From 9cd88251a3051dc1f3f9348a4395f0baae56f5b5 Mon Sep 17 00:00:00 2001 From: James Ide Date: Mon, 20 May 2019 07:13:42 -0700 Subject: [PATCH 0001/1084] ReactPrivate, an explicit interface between the renderer and RN (#24782) Summary: This introduces a new library named "ReactPrivate" that defines an explicit interface between the React renderers generated by the React repo and the code within RN. Previously, the React renderers would reach into RN internals via Haste wormholes. With this commit, there is now an explicit module (`ReactNativePrivateInterface`) that the renderers use to access RN internals. Motivation: The main goal is to move one step closer to turning off Haste for RN (https://github.com/facebook/react-native/issues/24316). Since the generated renderers currently use Haste, this commit sets the foundation for giving them a path-based interface to access RN internals. Additionally, this approach inverts abstraction control since RN needs to intentionally export its internals via the private interface instead of React reaching in via Haste. There will also need to be a corresponding commit to the React repo to make the renderers use this new interface. This RN commit needs to land before the React commit. ## Changelog [General] [Changed] - Add a private interface (do not use) between the renderer and RN Pull Request resolved: https://github.com/facebook/react-native/pull/24782 Differential Revision: D15413477 Pulled By: cpojer fbshipit-source-id: 3766ad4cf129fad0c82f0ddc7a485a4ba313b2c4 --- Libraries/Animated/release/.gitignore | 1 - {lib => Libraries/ReactPrivate}/README | 2 +- .../ReactNativePrivateInitializeCore.js | 6 +-- .../ReactNativePrivateInterface.js | 43 +++++++++++++++++++ lib/InitializeJavaScriptAppEngine.js | 15 ------- lib/RCTEventEmitter.js | 15 ------- lib/TextInputState.js | 15 ------- lib/UIManager.js | 15 ------- lib/UIManagerStatTracker.js | 15 ------- lib/deepDiffer.js | 15 ------- lib/deepFreezeAndThrowOnMutationInDev.js | 15 ------- lib/flattenStyle.js | 15 ------- 12 files changed, 45 insertions(+), 127 deletions(-) rename {lib => Libraries/ReactPrivate}/README (53%) rename lib/View.js => Libraries/ReactPrivate/ReactNativePrivateInitializeCore.js (59%) create mode 100644 Libraries/ReactPrivate/ReactNativePrivateInterface.js delete mode 100644 lib/InitializeJavaScriptAppEngine.js delete mode 100644 lib/RCTEventEmitter.js delete mode 100644 lib/TextInputState.js delete mode 100644 lib/UIManager.js delete mode 100644 lib/UIManagerStatTracker.js delete mode 100644 lib/deepDiffer.js delete mode 100644 lib/deepFreezeAndThrowOnMutationInDev.js delete mode 100644 lib/flattenStyle.js diff --git a/Libraries/Animated/release/.gitignore b/Libraries/Animated/release/.gitignore index 4c422f3bc92283..3d2bc62692c4b0 100644 --- a/Libraries/Animated/release/.gitignore +++ b/Libraries/Animated/release/.gitignore @@ -1,3 +1,2 @@ -/lib/ /dist/ /node_modules/ diff --git a/lib/README b/Libraries/ReactPrivate/README similarity index 53% rename from lib/README rename to Libraries/ReactPrivate/README index b5273d4970123e..afda34a704367d 100644 --- a/lib/README +++ b/Libraries/ReactPrivate/README @@ -1 +1 @@ -JS modules in this folder are forwarding modules to allow React to require React Native internals as node dependencies. +JS modules in this folder are forwarding modules to allow React to require React Native internals. diff --git a/lib/View.js b/Libraries/ReactPrivate/ReactNativePrivateInitializeCore.js similarity index 59% rename from lib/View.js rename to Libraries/ReactPrivate/ReactNativePrivateInitializeCore.js index 2eaddd857b6e8f..e34e6271f2f7fe 100644 --- a/lib/View.js +++ b/Libraries/ReactPrivate/ReactNativePrivateInitializeCore.js @@ -8,8 +8,4 @@ * @flow strict-local */ -'use strict'; - -// This is a forwarding module to allow React to require React Native internals -// as node dependency -module.exports = require('View'); +import '../Core/InitializeCore'; diff --git a/Libraries/ReactPrivate/ReactNativePrivateInterface.js b/Libraries/ReactPrivate/ReactNativePrivateInterface.js new file mode 100644 index 00000000000000..99e978864bf7a8 --- /dev/null +++ b/Libraries/ReactPrivate/ReactNativePrivateInterface.js @@ -0,0 +1,43 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow strict-local + */ + +// flowlint unsafe-getters-setters:off +module.exports = { + get BatchedBridge() { + return require('../BatchedBridge/BatchedBridge.js'); + }, + get ExceptionsManager() { + return require('../Core/ExceptionsManager'); + }, + get Platform() { + return require('../Utilities/Platform'); + }, + get RCTEventEmitter() { + return require('../EventEmitter/RCTEventEmitter'); + }, + get ReactNativeViewConfigRegistry() { + return require('../Renderer/shims/ReactNativeViewConfigRegistry'); + }, + get TextInputState() { + return require('../Components/TextInput/TextInputState'); + }, + get UIManager() { + return require('../ReactNative/UIManager'); + }, + get deepDiffer() { + return require('../Utilities/differ/deepDiffer'); + }, + get deepFreezeAndThrowOnMutationInDev() { + return require('../Utilities/deepFreezeAndThrowOnMutationInDev'); + }, + get flattenStyle() { + return require('../StyleSheet/flattenStyle'); + }, +}; diff --git a/lib/InitializeJavaScriptAppEngine.js b/lib/InitializeJavaScriptAppEngine.js deleted file mode 100644 index 3bfab280a03506..00000000000000 --- a/lib/InitializeJavaScriptAppEngine.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @flow strict-local - */ - -'use strict'; - -// This is a forwarding module to allow React to require React Native internals -// as node dependency -module.exports = require('InitializeCore'); diff --git a/lib/RCTEventEmitter.js b/lib/RCTEventEmitter.js deleted file mode 100644 index 85010174075aa4..00000000000000 --- a/lib/RCTEventEmitter.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @flow strict-local - */ - -'use strict'; - -// This is a forwarding module to allow React to require React Native internals -// as node dependency -module.exports = require('RCTEventEmitter'); diff --git a/lib/TextInputState.js b/lib/TextInputState.js deleted file mode 100644 index d016523f939b60..00000000000000 --- a/lib/TextInputState.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @flow strict-local - */ - -'use strict'; - -// This is a forwarding module to allow React to require React Native internals -// as node dependency -module.exports = require('TextInputState'); diff --git a/lib/UIManager.js b/lib/UIManager.js deleted file mode 100644 index a8140397c7bdbe..00000000000000 --- a/lib/UIManager.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @flow strict-local - */ - -'use strict'; - -// This is a forwarding module to allow React to require React Native internals -// as node dependency -module.exports = require('UIManager'); diff --git a/lib/UIManagerStatTracker.js b/lib/UIManagerStatTracker.js deleted file mode 100644 index 2579d1ea10c642..00000000000000 --- a/lib/UIManagerStatTracker.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @flow strict-local - */ - -'use strict'; - -// This is a forwarding module to allow React to require React Native internals -// as node dependency -module.exports = require('UIManagerStatTracker'); diff --git a/lib/deepDiffer.js b/lib/deepDiffer.js deleted file mode 100644 index 3d091331852afe..00000000000000 --- a/lib/deepDiffer.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @flow strict-local - */ - -'use strict'; - -// This is a forwarding module to allow React to require React Native internals -// as node dependency -module.exports = require('deepDiffer'); diff --git a/lib/deepFreezeAndThrowOnMutationInDev.js b/lib/deepFreezeAndThrowOnMutationInDev.js deleted file mode 100644 index 961a0e1b66615d..00000000000000 --- a/lib/deepFreezeAndThrowOnMutationInDev.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @flow strict-local - */ - -'use strict'; - -// This is a forwarding module to allow React to require React Native internals -// as node dependency -module.exports = require('deepFreezeAndThrowOnMutationInDev'); diff --git a/lib/flattenStyle.js b/lib/flattenStyle.js deleted file mode 100644 index 8c4d4ebee10335..00000000000000 --- a/lib/flattenStyle.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @flow strict-local - */ - -'use strict'; - -// This is a forwarding module to allow React to require React Native internals -// as node dependency -module.exports = require('flattenStyle'); From 57a1e7c000e0b035cdf5ac7cb256ded59ac2fcfb Mon Sep 17 00:00:00 2001 From: Alan Kenyon Date: Mon, 20 May 2019 07:42:49 -0700 Subject: [PATCH 0002/1084] VirtualizedList.RenderItem throws when using function component with hooks (#24832) Summary: `` will throw an error if the `renderItem` Prop component uses hooks. Function components without hooks and class components work without issue. Super contrived Example ```{js} function FlatListItem({ item }) { React.useEffect(() => console.log(item),[]) return ({item}); } ``` Example Error: ``` Invariant Violation: Hooks can only be called inside the body of a function component. (https://fb.me/react-invalid-hook-call) This error is located at: in CellRenderer (at VirtualizedList.js:688) in RCTScrollContentView (at ScrollView.js:976) in RCTScrollView (at ScrollView.js:1115) in ScrollView (at VirtualizedList.js:1081) in VirtualizedList (at FlatList.js:632) in FlatList (at WithoutScrollbars.js:21) ... ``` ## Changelog [General] [Added] - VirtualizedList ListItemComponent. An alternative to renderItem that accepts function components with hooks. [General][Added] - FlatList ListItemComponent. An alternative to renderItem that accepts function components with hooks. [General][Added] - VirtualizedList and FlatList tests and updated RNTester example Pull Request resolved: https://github.com/facebook/react-native/pull/24832 Reviewed By: sahrens Differential Revision: D15334020 Pulled By: cpojer fbshipit-source-id: 882db722fd6e22f07260b08091b3456d1c66c2c8 --- Libraries/Inspector/NetworkOverlay.js | 2 +- Libraries/Lists/FlatList.js | 143 +++++++---- Libraries/Lists/VirtualizedList.js | 72 +++++- Libraries/Lists/__tests__/FlatList-test.js | 35 +++ .../Lists/__tests__/VirtualizedList-test.js | 55 +++++ .../__snapshots__/FlatList-test.js.snap | 223 ++++++++++++++++++ .../VirtualizedList-test.js.snap | 108 +++++++++ RNTester/js/FlatListExample.js | 37 ++- 8 files changed, 602 insertions(+), 73 deletions(-) diff --git a/Libraries/Inspector/NetworkOverlay.js b/Libraries/Inspector/NetworkOverlay.js index 4e93151c13a080..a39370bcee8e65 100644 --- a/Libraries/Inspector/NetworkOverlay.js +++ b/Libraries/Inspector/NetworkOverlay.js @@ -325,7 +325,7 @@ class NetworkOverlay extends React.Component { WebSocketInterceptor.disableInterception(); } - _renderItem = ({item, index}): ?React.Element => { + _renderItem = ({item, index}): React.Element => { const tableRowViewStyle = [ styles.tableRow, index % 2 === 1 ? styles.tableRowOdd : styles.tableRowEven, diff --git a/Libraries/Lists/FlatList.js b/Libraries/Lists/FlatList.js index 5d17580c16365c..292c6e1cc63746 100644 --- a/Libraries/Lists/FlatList.js +++ b/Libraries/Lists/FlatList.js @@ -24,15 +24,20 @@ import type { ViewToken, ViewabilityConfigCallbackPair, } from './ViewabilityHelper'; -import type {Props as VirtualizedListProps} from './VirtualizedList'; - -export type SeparatorsObj = { - highlight: () => void, - unhighlight: () => void, - updateProps: (select: 'leading' | 'trailing', newProps: Object) => void, -}; +import type { + Props as VirtualizedListProps, + RenderItemType, + RenderItemProps, +} from './VirtualizedList'; type RequiredProps = { + /** + * For simplicity, data is just a plain array. If you want to use something else, like an + * immutable list, use the underlying `VirtualizedList` directly. + */ + data: ?$ReadOnlyArray, +}; +type OptionalProps = { /** * Takes an item from `data` and renders it into the list. Example usage: * @@ -59,18 +64,7 @@ type RequiredProps = { * `highlight` and `unhighlight` (which set the `highlighted: boolean` prop) are insufficient for * your use-case. */ - renderItem: (info: { - item: ItemT, - index: number, - separators: SeparatorsObj, - }) => ?React.Node, - /** - * For simplicity, data is just a plain array. If you want to use something else, like an - * immutable list, use the underlying `VirtualizedList` directly. - */ - data: ?$ReadOnlyArray, -}; -type OptionalProps = { + renderItem?: ?RenderItemType, /** * Rendered in between each item, but not at the top or bottom. By default, `highlighted` and * `leadingItem` props are provided. `renderItem` provides `separators.highlight`/`unhighlight` @@ -78,6 +72,33 @@ type OptionalProps = { * `separators.updateProps`. */ ItemSeparatorComponent?: ?React.ComponentType, + /** + * Takes an item from `data` and renders it into the list. Example usage: + * + * ( + * + * )} + * data={[{title: 'Title Text', key: 'item1'}]} + * ListItemComponent={({item, separators}) => ( + * this._onPress(item)} + * onShowUnderlay={separators.highlight} + * onHideUnderlay={separators.unhighlight}> + * + * {item.title} + * + * + * )} + * /> + * + * Provides additional metadata like `index` if you need it, as well as a more generic + * `separators.updateProps` function which let's you set whatever props you want to change the + * rendering of either the leading separator or trailing separator in case the more common + * `highlight` and `unhighlight` (which set the `highlighted: boolean` prop) are insufficient for + * your use-case. + */ + ListItemComponent?: ?React.ComponentType, /** * Rendered when the list is empty. Can be a React Component Class, a render function, or * a rendered element. @@ -598,47 +619,71 @@ class FlatList extends React.PureComponent, void> { }; } - _renderItem = (info: Object): ?React.Node => { - const {renderItem, numColumns, columnWrapperStyle} = this.props; - if (numColumns > 1) { - const {item, index} = info; - invariant( - Array.isArray(item), - 'Expected array of items with numColumns > 1', - ); - return ( - - {item.map((it, kk) => { - const element = renderItem({ - item: it, - index: index * numColumns + kk, - separators: info.separators, - }); - return element != null ? ( - {element} - ) : null; - })} - - ); - } else { - return renderItem(info); - } + _renderer = () => { + const { + ListItemComponent, + renderItem, + numColumns, + columnWrapperStyle, + } = this.props; + + let virtualizedListRenderKey = ListItemComponent + ? 'ListItemComponent' + : 'renderItem'; + + const renderer = props => { + if (ListItemComponent) { + return ; + } else if (renderItem) { + return renderItem(props); + } else { + return null; + } + }; + + return { + [virtualizedListRenderKey]: (info: RenderItemProps) => { + if (numColumns > 1) { + const {item, index} = info; + invariant( + Array.isArray(item), + 'Expected array of items with numColumns > 1', + ); + return ( + + {item.map((it, kk) => { + const element = renderer({ + item: it, + index: index * numColumns + kk, + separators: info.separators, + }); + return element != null ? ( + {element} + ) : null; + })} + + ); + } else { + return renderer(info); + } + }, + }; }; render() { return ( ); } diff --git a/Libraries/Lists/VirtualizedList.js b/Libraries/Lists/VirtualizedList.js index b896b3b5fb76b4..0281d87c8a3418 100644 --- a/Libraries/Lists/VirtualizedList.js +++ b/Libraries/Lists/VirtualizedList.js @@ -17,7 +17,6 @@ const ReactNative = require('../Renderer/shims/ReactNative'); const RefreshControl = require('../Components/RefreshControl/RefreshControl'); const ScrollView = require('../Components/ScrollView/ScrollView'); const StyleSheet = require('../StyleSheet/StyleSheet'); -const UIManager = require('../ReactNative/UIManager'); const View = require('../Components/View/View'); const ViewabilityHelper = require('./ViewabilityHelper'); @@ -37,7 +36,21 @@ import type { type Item = any; -export type renderItemType = (info: any) => ?React.Element; +export type Separators = { + highlight: () => void, + unhighlight: () => void, + updateProps: (select: 'leading' | 'trailing', newProps: Object) => void, +}; + +export type RenderItemProps = { + item: ItemT, + index: number, + separators: Separators, +}; + +export type RenderItemType = ( + info: RenderItemProps, +) => React.Node; type ViewabilityHelperCallbackTuple = { viewabilityHelper: ViewabilityHelper, @@ -48,9 +61,6 @@ type ViewabilityHelperCallbackTuple = { }; type RequiredProps = { - // TODO: Conflicts with the optional `renderItem` in - // `VirtualizedSectionList`'s props. - renderItem: $FlowFixMe, /** * The default accessor functions assume this is an Array<{key: string} | {id: string}> but you can override * getItem, getItemCount, and keyExtractor to handle any type of index-based data. @@ -66,6 +76,9 @@ type RequiredProps = { getItemCount: (data: any) => number, }; type OptionalProps = { + // TODO: Conflicts with the optional `renderItem` in + // `VirtualizedSectionList`'s props. + renderItem?: $FlowFixMe>, /** * `debug` will turn on extra logging and visual overlays to aid with debugging both usage and * implementation, but with a significant perf hit. @@ -111,6 +124,11 @@ type OptionalProps = { * or a render function. Defaults to using View. */ CellRendererComponent?: ?React.ComponentType, + /** + * Each data item is rendered using this element. Can be a React Component Class, + * or a render function. + */ + ListItemComponent?: ?React.ComponentType, /** * Rendered when the list is empty. Can be a React Component Class, a render function, or * a rendered element. @@ -1664,7 +1682,8 @@ class CellRenderer extends React.Component< onUpdateSeparators: (cellKeys: Array, props: Object) => void, parentProps: { getItemLayout?: ?Function, - renderItem: renderItemType, + renderItem?: ?RenderItemType, + ListItemComponent?: ?(React.ComponentType | React.Element), }, prevCellKey: ?string, }, @@ -1725,6 +1744,36 @@ class CellRenderer extends React.Component< this.props.onUnmount(this.props.cellKey); } + _renderElement(renderItem, ListItemComponent, item, index) { + if (renderItem && ListItemComponent) { + console.warn( + 'VirtualizedList: Both ListItemComponent and renderItem props are present. ListItemComponent will take' + + ' precedence over renderItem.', + ); + } + + if (ListItemComponent) { + return React.createElement(ListItemComponent, { + item, + index, + separators: this._separators, + }); + } + + if (renderItem) { + return renderItem({ + item, + index, + separators: this._separators, + }); + } + + invariant( + false, + 'VirtualizedList: Either ListItemComponent or renderItem props are required but none were found.', + ); + } + render() { const { CellRendererComponent, @@ -1736,13 +1785,14 @@ class CellRenderer extends React.Component< inversionStyle, parentProps, } = this.props; - const {renderItem, getItemLayout} = parentProps; - invariant(renderItem, 'no renderItem!'); - const element = renderItem({ + const {renderItem, getItemLayout, ListItemComponent} = parentProps; + const element = this._renderElement( + renderItem, + ListItemComponent, item, index, - separators: this._separators, - }); + ); + const onLayout = /* $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 diff --git a/Libraries/Lists/__tests__/FlatList-test.js b/Libraries/Lists/__tests__/FlatList-test.js index e1c605aae11039..1df7e484c76688 100644 --- a/Libraries/Lists/__tests__/FlatList-test.js +++ b/Libraries/Lists/__tests__/FlatList-test.js @@ -25,6 +25,41 @@ describe('FlatList', () => { ); expect(component).toMatchSnapshot(); }); + it('renders simple list (multiple columns)', () => { + const component = ReactTestRenderer.create( + } + numColumns={2} + />, + ); + expect(component).toMatchSnapshot(); + }); + it('renders simple list using ListItemComponent', () => { + function ListItemComponent({item}) { + return ; + } + const component = ReactTestRenderer.create( + , + ); + expect(component).toMatchSnapshot(); + }); + it('renders simple list using ListItemComponent (multiple columns)', () => { + function ListItemComponent({item}) { + return ; + } + const component = ReactTestRenderer.create( + , + ); + expect(component).toMatchSnapshot(); + }); it('renders empty list', () => { const component = ReactTestRenderer.create( } />, diff --git a/Libraries/Lists/__tests__/VirtualizedList-test.js b/Libraries/Lists/__tests__/VirtualizedList-test.js index d421d1b9a78591..c4873374e0ef54 100644 --- a/Libraries/Lists/__tests__/VirtualizedList-test.js +++ b/Libraries/Lists/__tests__/VirtualizedList-test.js @@ -28,6 +28,61 @@ describe('VirtualizedList', () => { expect(component).toMatchSnapshot(); }); + it('renders simple list using ListItemComponent', () => { + function ListItemComponent({item}) { + return ; + } + const component = ReactTestRenderer.create( + data[index]} + getItemCount={data => data.length} + />, + ); + expect(component).toMatchSnapshot(); + }); + + it('warns if both renderItem or ListItemComponent are specified. Uses ListItemComponent', () => { + jest.spyOn(global.console, 'warn'); + function ListItemComponent({item}) { + return ; + } + const component = ReactTestRenderer.create( + ( + + )} + getItem={(data, index) => data[index]} + getItemCount={data => data.length} + />, + ); + + expect(console.warn.mock.calls).toEqual([ + [ + 'VirtualizedList: Both ListItemComponent and renderItem props are present. ListItemComponent will take precedence over renderItem.', + ], + ]); + expect(component).toMatchSnapshot(); + console.warn.mockRestore(); + }); + + it('throws if no renderItem or ListItemComponent', () => { + const componentFactory = () => + ReactTestRenderer.create( + data[index]} + getItemCount={data => data.length} + />, + ); + expect(componentFactory).toThrow( + 'VirtualizedList: Either ListItemComponent or renderItem props are required but none were found.', + ); + }); + it('renders empty list', () => { const component = ReactTestRenderer.create( `; +exports[`FlatList renders simple list (multiple columns) 1`] = ` + + + + + + + + + + + + + + + +`; + exports[`FlatList renders simple list 1`] = ` `; + +exports[`FlatList renders simple list using ListItemComponent (multiple columns) 1`] = ` + + + + + + + + + + + + + + + +`; + +exports[`FlatList renders simple list using ListItemComponent 1`] = ` + + + + + + + + + + + + + +`; diff --git a/Libraries/Lists/__tests__/__snapshots__/VirtualizedList-test.js.snap b/Libraries/Lists/__tests__/__snapshots__/VirtualizedList-test.js.snap index 2ae233201f72ba..86faf0fa8aa0cb 100644 --- a/Libraries/Lists/__tests__/__snapshots__/VirtualizedList-test.js.snap +++ b/Libraries/Lists/__tests__/__snapshots__/VirtualizedList-test.js.snap @@ -811,6 +811,70 @@ exports[`VirtualizedList renders simple list 1`] = ` `; +exports[`VirtualizedList renders simple list using ListItemComponent 1`] = ` + + + + + + + + + + + + + +`; + exports[`VirtualizedList test getItem functionality where data is not an Array 1`] = ` `; + +exports[`VirtualizedList warns if both renderItem or ListItemComponent are specified. Uses ListItemComponent 1`] = ` + + + + + + + +`; diff --git a/RNTester/js/FlatListExample.js b/RNTester/js/FlatListExample.js index f85870405845d3..733f0737f0fe77 100644 --- a/RNTester/js/FlatListExample.js +++ b/RNTester/js/FlatListExample.js @@ -51,6 +51,7 @@ type State = {| logViewable: boolean, virtualized: boolean, empty: boolean, + useFlatListItemComponent: boolean, |}; class FlatListExample extends React.PureComponent { @@ -64,6 +65,7 @@ class FlatListExample extends React.PureComponent { logViewable: false, virtualized: true, empty: false, + useFlatListItemComponent: false, }; _onChangeFilterText = filterText => { @@ -95,6 +97,7 @@ class FlatListExample extends React.PureComponent { const filter = item => filterRegex.test(item.text) || filterRegex.test(item.title); const filteredData = this.state.data.filter(filter); + const flatListItemRendererProps = this._renderItemComponent(); return ( @@ -118,6 +121,7 @@ class FlatListExample extends React.PureComponent { {renderSmallSwitchOption(this, 'inverted')} {renderSmallSwitchOption(this, 'empty')} {renderSmallSwitchOption(this, 'debug')} + {renderSmallSwitchOption(this, 'useFlatListItemComponent')} @@ -150,9 +154,9 @@ class FlatListExample extends React.PureComponent { onViewableItemsChanged={this._onViewableItemsChanged} ref={this._captureRef} refreshing={false} - renderItem={this._renderItemComponent} contentContainerStyle={styles.list} viewabilityConfig={VIEWABILITY_CONFIG} + {...flatListItemRendererProps} /> @@ -173,17 +177,26 @@ class FlatListExample extends React.PureComponent { })); }; _onRefresh = () => Alert.alert('onRefresh: nothing to refresh :P'); - _renderItemComponent = ({item, separators}) => { - return ( - - ); + _renderItemComponent = () => { + const flatListPropKey = this.state.useFlatListItemComponent + ? 'ListItemComponent' + : 'renderItem'; + + return { + renderItem: undefined, + [flatListPropKey]: ({item, separators}) => { + return ( + + ); + }, + }; }; // This is called when items change viewability by scrolling into or out of // the viewable area. From c59da6eae88690c5cd0071d88f933b0e88e9c97b Mon Sep 17 00:00:00 2001 From: Shen Jin Date: Mon, 20 May 2019 07:47:37 -0700 Subject: [PATCH 0003/1084] Add textContentType to onboarding flow Summary: Allows iOS users to prefil from keyboard if they support safari autofill Differential Revision: D15385599 fbshipit-source-id: 35d8a7a04c44d23d2aa27dffa02035b68818db7a --- Libraries/Components/TextInput/TextInput.js | 61 +++++++++++---------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js index 44999222bf741e..61441eb5af2dee 100644 --- a/Libraries/Components/TextInput/TextInput.js +++ b/Libraries/Components/TextInput/TextInput.js @@ -178,6 +178,36 @@ export type ReturnKeyType = export type AutoCapitalize = 'none' | 'sentences' | 'words' | 'characters'; +export type TextContentType = + | 'none' + | 'URL' + | 'addressCity' + | 'addressCityAndState' + | 'addressState' + | 'countryName' + | 'creditCardNumber' + | 'emailAddress' + | 'familyName' + | 'fullStreetAddress' + | 'givenName' + | 'jobTitle' + | 'location' + | 'middleName' + | 'name' + | 'namePrefix' + | 'nameSuffix' + | 'nickname' + | 'organizationName' + | 'postalCode' + | 'streetAddressLine1' + | 'streetAddressLine2' + | 'sublocality' + | 'telephoneNumber' + | 'username' + | 'password' + | 'newPassword' + | 'oneTimeCode'; + type IOSProps = $ReadOnly<{| spellCheck?: ?boolean, keyboardAppearance?: ?('default' | 'light' | 'dark'), @@ -189,36 +219,7 @@ type IOSProps = $ReadOnly<{| | ?DataDetectorTypesType | $ReadOnlyArray, inputAccessoryViewID?: ?string, - textContentType?: ?( - | 'none' - | 'URL' - | 'addressCity' - | 'addressCityAndState' - | 'addressState' - | 'countryName' - | 'creditCardNumber' - | 'emailAddress' - | 'familyName' - | 'fullStreetAddress' - | 'givenName' - | 'jobTitle' - | 'location' - | 'middleName' - | 'name' - | 'namePrefix' - | 'nameSuffix' - | 'nickname' - | 'organizationName' - | 'postalCode' - | 'streetAddressLine1' - | 'streetAddressLine2' - | 'sublocality' - | 'telephoneNumber' - | 'username' - | 'password' - | 'newPassword' - | 'oneTimeCode' - ), + textContentType?: ?TextContentType, scrollEnabled?: ?boolean, |}>; From 6ec19aba4eb908b0005af7e577ce91432176ef6f Mon Sep 17 00:00:00 2001 From: Eric Lewis Date: Mon, 20 May 2019 09:46:23 -0700 Subject: [PATCH 0004/1084] use state in paragraph component (#24873) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Updates the paragraph component to use State instead of Local Data, part of the path to a Fabric TextInput 💯 ## Changelog [General] [Changed] - Fabric: Use State instead of Local Data for Paragraph Pull Request resolved: https://github.com/facebook/react-native/pull/24873 Differential Revision: D15410979 Pulled By: shergin fbshipit-source-id: 3c9517d2495a64c4dbd213b6efb5ff55287900e3 --- .../Text/RCTParagraphComponentView.mm | 28 ++++----- .../paragraph/ParagraphComponentDescriptor.h | 2 +- .../text/paragraph/ParagraphLocalData.cpp | 58 ------------------- .../text/paragraph/ParagraphLocalData.h | 58 ------------------- .../text/paragraph/ParagraphProps.cpp | 8 +-- .../text/paragraph/ParagraphProps.h | 6 +- .../text/paragraph/ParagraphShadowNode.cpp | 28 ++++----- .../text/paragraph/ParagraphShadowNode.h | 16 ++--- .../text/paragraph/ParagraphState.cpp | 23 ++++++++ .../text/paragraph/ParagraphState.h | 52 +++++++++++++++++ .../components/text/paragraph/conversions.h | 15 ++--- .../text/tests/ParagraphLocalDataTest.cpp | 10 ++-- 12 files changed, 129 insertions(+), 175 deletions(-) delete mode 100644 ReactCommon/fabric/components/text/paragraph/ParagraphLocalData.cpp delete mode 100644 ReactCommon/fabric/components/text/paragraph/ParagraphLocalData.h create mode 100644 ReactCommon/fabric/components/text/paragraph/ParagraphState.cpp create mode 100644 ReactCommon/fabric/components/text/paragraph/ParagraphState.h diff --git a/React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm b/React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm index 9a64f5c30dce93..9497b406f536a6 100644 --- a/React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm @@ -8,8 +8,8 @@ #import "RCTParagraphComponentView.h" #import -#import #import +#import #import #import #import @@ -21,7 +21,7 @@ using namespace facebook::react; @implementation RCTParagraphComponentView { - SharedParagraphLocalData _paragraphLocalData; + ParagraphShadowNode::ConcreteState::Shared _state; ParagraphAttributes _paragraphAttributes; } @@ -63,32 +63,32 @@ - (void)updateProps:(SharedProps)props oldProps:(SharedProps)oldProps _paragraphAttributes = paragraphProps->paragraphAttributes; } -- (void)updateLocalData:(SharedLocalData)localData oldLocalData:(SharedLocalData)oldLocalData +- (void)updateState:(State::Shared)state oldState:(State::Shared)oldState { - _paragraphLocalData = std::static_pointer_cast(localData); - assert(_paragraphLocalData); + _state = std::static_pointer_cast(state); + assert(_state); [self setNeedsDisplay]; } - (void)prepareForRecycle { [super prepareForRecycle]; - _paragraphLocalData.reset(); + _state.reset(); } - (void)drawRect:(CGRect)rect { - if (!_paragraphLocalData) { + if (!_state) { return; } - SharedTextLayoutManager textLayoutManager = _paragraphLocalData->getTextLayoutManager(); + SharedTextLayoutManager textLayoutManager = _state->getData().layoutManager; RCTTextLayoutManager *nativeTextLayoutManager = (__bridge RCTTextLayoutManager *)textLayoutManager->getNativeTextLayoutManager(); CGRect frame = RCTCGRectFromRect(_layoutMetrics.getContentFrame()); - [nativeTextLayoutManager drawAttributedString:_paragraphLocalData->getAttributedString() + [nativeTextLayoutManager drawAttributedString:_state->getData().attributedString paragraphAttributes:_paragraphAttributes frame:frame]; } @@ -102,26 +102,26 @@ - (NSString *)accessibilityLabel return superAccessibilityLabel; } - if (!_paragraphLocalData) { + if (!_state) { return nil; } - return RCTNSStringFromString(_paragraphLocalData->getAttributedString().getString()); + return RCTNSStringFromString(_state->getData().attributedString.getString()); } - (SharedTouchEventEmitter)touchEventEmitterAtPoint:(CGPoint)point { - if (!_paragraphLocalData) { + if (!_state) { return _eventEmitter; } - SharedTextLayoutManager textLayoutManager = _paragraphLocalData->getTextLayoutManager(); + SharedTextLayoutManager textLayoutManager = _state->getData().layoutManager; RCTTextLayoutManager *nativeTextLayoutManager = (__bridge RCTTextLayoutManager *)textLayoutManager->getNativeTextLayoutManager(); CGRect frame = RCTCGRectFromRect(_layoutMetrics.getContentFrame()); SharedEventEmitter eventEmitter = - [nativeTextLayoutManager getEventEmitterWithAttributeString:_paragraphLocalData->getAttributedString() + [nativeTextLayoutManager getEventEmitterWithAttributeString:_state->getData().attributedString paragraphAttributes:_paragraphAttributes frame:frame atPoint:point]; diff --git a/ReactCommon/fabric/components/text/paragraph/ParagraphComponentDescriptor.h b/ReactCommon/fabric/components/text/paragraph/ParagraphComponentDescriptor.h index 83a5292392f6c8..a0dd2abff798dc 100644 --- a/ReactCommon/fabric/components/text/paragraph/ParagraphComponentDescriptor.h +++ b/ReactCommon/fabric/components/text/paragraph/ParagraphComponentDescriptor.h @@ -64,7 +64,7 @@ class ParagraphComponentDescriptor final private: SharedTextLayoutManager textLayoutManager_; - std::unique_ptr measureCache_; + std::unique_ptr measureCache_; }; } // namespace react diff --git a/ReactCommon/fabric/components/text/paragraph/ParagraphLocalData.cpp b/ReactCommon/fabric/components/text/paragraph/ParagraphLocalData.cpp deleted file mode 100644 index fb9426da9975f6..00000000000000 --- a/ReactCommon/fabric/components/text/paragraph/ParagraphLocalData.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include "ParagraphLocalData.h" - -#include -#include - -namespace facebook { -namespace react { - -AttributedString ParagraphLocalData::getAttributedString() const { - return attributedString_; -} - -void ParagraphLocalData::setAttributedString( - AttributedString attributedString) { - ensureUnsealed(); - attributedString_ = attributedString; -} - -SharedTextLayoutManager ParagraphLocalData::getTextLayoutManager() const { - return textLayoutManager_; -} - -void ParagraphLocalData::setTextLayoutManager( - SharedTextLayoutManager textLayoutManager) { - ensureUnsealed(); - textLayoutManager_ = textLayoutManager; -} - -#ifdef ANDROID - -folly::dynamic ParagraphLocalData::getDynamic() const { - return toDynamic(*this); -} - -#endif - -#pragma mark - DebugStringConvertible - -#if RN_DEBUG_STRING_CONVERTIBLE -std::string ParagraphLocalData::getDebugName() const { - return "ParagraphLocalData"; -} - -SharedDebugStringConvertibleList ParagraphLocalData::getDebugProps() const { - return { - debugStringConvertibleItem("attributedString", attributedString_, "")}; -} -#endif - -} // namespace react -} // namespace facebook diff --git a/ReactCommon/fabric/components/text/paragraph/ParagraphLocalData.h b/ReactCommon/fabric/components/text/paragraph/ParagraphLocalData.h deleted file mode 100644 index 15e370573566ab..00000000000000 --- a/ReactCommon/fabric/components/text/paragraph/ParagraphLocalData.h +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include -#include -#include - -namespace facebook { -namespace react { - -class ParagraphLocalData; - -using SharedParagraphLocalData = std::shared_ptr; - -/* - * LocalData for component. - * Represents what to render and how to render. - */ -class ParagraphLocalData : public LocalData { - public: - /* - * All content of component represented as an `AttributedString`. - */ - AttributedString getAttributedString() const; - void setAttributedString(AttributedString attributedString); - - /* - * `TextLayoutManager` provides a connection to platform-specific - * text rendering infrastructure which is capable to render the - * `AttributedString`. - */ - SharedTextLayoutManager getTextLayoutManager() const; - void setTextLayoutManager(SharedTextLayoutManager textLayoutManager); - -#ifdef ANDROID - folly::dynamic getDynamic() const override; -#endif - -#pragma mark - DebugStringConvertible - -#if RN_DEBUG_STRING_CONVERTIBLE - std::string getDebugName() const override; - SharedDebugStringConvertibleList getDebugProps() const override; -#endif - - private: - AttributedString attributedString_; - SharedTextLayoutManager textLayoutManager_; -}; - -} // namespace react -} // namespace facebook diff --git a/ReactCommon/fabric/components/text/paragraph/ParagraphProps.cpp b/ReactCommon/fabric/components/text/paragraph/ParagraphProps.cpp index d8135cd845a2e7..da79a25a1aeb67 100644 --- a/ReactCommon/fabric/components/text/paragraph/ParagraphProps.cpp +++ b/ReactCommon/fabric/components/text/paragraph/ParagraphProps.cpp @@ -15,8 +15,8 @@ namespace facebook { namespace react { static ParagraphAttributes convertRawProp( - const RawProps &rawProps, - const ParagraphAttributes &defaultParagraphAttributes) { + RawProps const &rawProps, + ParagraphAttributes const &defaultParagraphAttributes) { auto paragraphAttributes = ParagraphAttributes{}; paragraphAttributes.maximumNumberOfLines = convertRawProp( @@ -44,8 +44,8 @@ static ParagraphAttributes convertRawProp( } ParagraphProps::ParagraphProps( - const ParagraphProps &sourceProps, - const RawProps &rawProps) + ParagraphProps const &sourceProps, + RawProps const &rawProps) : ViewProps(sourceProps, rawProps), BaseTextProps(sourceProps, rawProps), paragraphAttributes( diff --git a/ReactCommon/fabric/components/text/paragraph/ParagraphProps.h b/ReactCommon/fabric/components/text/paragraph/ParagraphProps.h index 1e1ca67e15b97f..c796eef638e58f 100644 --- a/ReactCommon/fabric/components/text/paragraph/ParagraphProps.h +++ b/ReactCommon/fabric/components/text/paragraph/ParagraphProps.h @@ -26,7 +26,7 @@ namespace react { class ParagraphProps : public ViewProps, public BaseTextProps { public: ParagraphProps() = default; - ParagraphProps(const ParagraphProps &sourceProps, const RawProps &rawProps); + ParagraphProps(ParagraphProps const &sourceProps, RawProps const &rawProps); #pragma mark - Props @@ -34,12 +34,12 @@ class ParagraphProps : public ViewProps, public BaseTextProps { * Contains all prop values that affect visual representation of the * paragraph. */ - const ParagraphAttributes paragraphAttributes{}; + ParagraphAttributes const paragraphAttributes{}; /* * Defines can the text be selected (and copied) or not. */ - const bool isSelectable{}; + bool const isSelectable{}; #pragma mark - DebugStringConvertible diff --git a/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.cpp b/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.cpp index 028652ca5cbcc7..ec7f4af6be426c 100644 --- a/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.cpp +++ b/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.cpp @@ -6,13 +6,13 @@ */ #include "ParagraphShadowNode.h" -#include "ParagraphLocalData.h" #include "ParagraphMeasurementCache.h" +#include "ParagraphState.h" namespace facebook { namespace react { -const char ParagraphComponentName[] = "Paragraph"; +char const ParagraphComponentName[] = "Paragraph"; AttributedString ParagraphShadowNode::getAttributedString() const { if (!cachedAttributedString_.has_value()) { @@ -33,26 +33,21 @@ void ParagraphShadowNode::setTextLayoutManager( } void ParagraphShadowNode::setMeasureCache( - const ParagraphMeasurementCache *cache) { + ParagraphMeasurementCache const *cache) { ensureUnsealed(); measureCache_ = cache; } -void ParagraphShadowNode::updateLocalDataIfNeeded() { +void ParagraphShadowNode::updateStateIfNeeded() { ensureUnsealed(); auto attributedString = getAttributedString(); - auto currentLocalData = - std::static_pointer_cast(getLocalData()); - if (currentLocalData && - currentLocalData->getAttributedString() == attributedString) { + auto const &state = getStateData(); + if (state.attributedString == attributedString) { return; } - auto localData = std::make_shared(); - localData->setAttributedString(std::move(attributedString)); - localData->setTextLayoutManager(textLayoutManager_); - setLocalData(localData); + setStateData(ParagraphState{attributedString, textLayoutManager_}); } #pragma mark - LayoutableShadowNode @@ -64,15 +59,16 @@ Size ParagraphShadowNode::measure(LayoutConstraints layoutConstraints) const { return {0, 0}; } - const ParagraphAttributes paragraphAttributes = + ParagraphAttributes const paragraphAttributes = getProps()->paragraphAttributes; // Cache results of this function so we don't need to call measure() // repeatedly. if (measureCache_) { return measureCache_->get( - ParagraphMeasurementCacheKey{attributedString, paragraphAttributes, layoutConstraints}, - [&](const ParagraphMeasurementCacheKey &key) { + ParagraphMeasurementCacheKey{ + attributedString, paragraphAttributes, layoutConstraints}, + [&](ParagraphMeasurementCacheKey const &key) { return textLayoutManager_->measure( attributedString, paragraphAttributes, layoutConstraints); }); @@ -83,7 +79,7 @@ Size ParagraphShadowNode::measure(LayoutConstraints layoutConstraints) const { } void ParagraphShadowNode::layout(LayoutContext layoutContext) { - updateLocalDataIfNeeded(); + updateStateIfNeeded(); ConcreteViewShadowNode::layout(layoutContext); } diff --git a/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.h b/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.h index 9d03af4a3a6006..dd738f169c4a59 100644 --- a/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.h +++ b/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -20,7 +21,7 @@ namespace facebook { namespace react { -extern const char ParagraphComponentName[]; +extern char const ParagraphComponentName[]; using ParagraphEventEmitter = ViewEventEmitter; @@ -32,7 +33,8 @@ using ParagraphEventEmitter = ViewEventEmitter; class ParagraphShadowNode : public ConcreteViewShadowNode< ParagraphComponentName, ParagraphProps, - ParagraphEventEmitter>, + ParagraphEventEmitter, + ParagraphState>, public BaseTextShadowNode { public: using ConcreteViewShadowNode::ConcreteViewShadowNode; @@ -45,7 +47,7 @@ class ParagraphShadowNode : public ConcreteViewShadowNode< /* * Associates a shared TextLayoutManager with the node. * `ParagraphShadowNode` uses the manager to measure text content - * and construct `ParagraphLocalData` objects. + * and construct `ParagraphState` objects. */ void setTextLayoutManager(SharedTextLayoutManager textLayoutManager); @@ -56,7 +58,7 @@ class ParagraphShadowNode : public ConcreteViewShadowNode< * By design, the ParagraphComponentDescriptor outlives all * shadow nodes, so it's safe for this to be a raw pointer. */ - void setMeasureCache(const ParagraphMeasurementCache *cache); + void setMeasureCache(ParagraphMeasurementCache const *cache); #pragma mark - LayoutableShadowNode @@ -65,13 +67,13 @@ class ParagraphShadowNode : public ConcreteViewShadowNode< private: /* - * Creates a `LocalData` object (with `AttributedText` and + * Creates a `State` object (with `AttributedText` and * `TextLayoutManager`) if needed. */ - void updateLocalDataIfNeeded(); + void updateStateIfNeeded(); SharedTextLayoutManager textLayoutManager_; - const ParagraphMeasurementCache *measureCache_; + ParagraphMeasurementCache const *measureCache_; /* * Cached attributed string that represents the content of the subtree started diff --git a/ReactCommon/fabric/components/text/paragraph/ParagraphState.cpp b/ReactCommon/fabric/components/text/paragraph/ParagraphState.cpp new file mode 100644 index 00000000000000..89a7c442c1cf95 --- /dev/null +++ b/ReactCommon/fabric/components/text/paragraph/ParagraphState.cpp @@ -0,0 +1,23 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "ParagraphState.h" + +#include +#include + +namespace facebook { +namespace react { + +#ifdef ANDROID +folly::dynamic ParagraphState::getDynamic() const { + return toDynamic(*this); +} +#endif + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/components/text/paragraph/ParagraphState.h b/ReactCommon/fabric/components/text/paragraph/ParagraphState.h new file mode 100644 index 00000000000000..e5ae4be7567961 --- /dev/null +++ b/ReactCommon/fabric/components/text/paragraph/ParagraphState.h @@ -0,0 +1,52 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include + +#ifdef ANDROID +#include +#endif + +namespace facebook { +namespace react { + +/* + * State for component. + * Represents what to render and how to render. + */ +class ParagraphState final { + public: + /* + * All content of component represented as an `AttributedString`. + */ + AttributedString attributedString; + + /* + * `TextLayoutManager` provides a connection to platform-specific + * text rendering infrastructure which is capable to render the + * `AttributedString`. + */ + SharedTextLayoutManager layoutManager; + +#ifdef ANDROID + ParagraphState( + AttributedString const &attributedString, + SharedTextLayoutManager const &layoutManager) + : attributedString(attributedString), layoutManager(layoutManager) {} + ParagraphState() = default; + ParagraphState(folly::dynamic const &data) { + assert(false && "Not supported"); + }; + folly::dynamic getDynamic() const; +#endif +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/components/text/paragraph/conversions.h b/ReactCommon/fabric/components/text/paragraph/conversions.h index dd507cefa0d7c3..12d53b1d540616 100644 --- a/ReactCommon/fabric/components/text/paragraph/conversions.h +++ b/ReactCommon/fabric/components/text/paragraph/conversions.h @@ -5,21 +5,18 @@ #include #include -#include +#include namespace facebook { namespace react { #ifdef ANDROID - -inline folly::dynamic toDynamic(const ParagraphLocalData ¶graphLocalData) { - folly::dynamic newLocalData = folly::dynamic::object(); - newLocalData["attributedString"] = - toDynamic(paragraphLocalData.getAttributedString()); - newLocalData["hash"] = newLocalData["attributedString"]["hash"]; - return newLocalData; +inline folly::dynamic toDynamic(ParagraphState const ¶graphState) { + folly::dynamic newState = folly::dynamic::object(); + newState["attributedString"] = toDynamic(paragraphState.attributedString); + newState["hash"] = newState["attributedString"]["hash"]; + return newState; } - #endif } // namespace react diff --git a/ReactCommon/fabric/components/text/tests/ParagraphLocalDataTest.cpp b/ReactCommon/fabric/components/text/tests/ParagraphLocalDataTest.cpp index accf32c0b79443..48b09cc6d334a8 100644 --- a/ReactCommon/fabric/components/text/tests/ParagraphLocalDataTest.cpp +++ b/ReactCommon/fabric/components/text/tests/ParagraphLocalDataTest.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include namespace facebook { @@ -21,7 +21,7 @@ namespace react { #ifdef ANDROID TEST(ParagraphLocalDataTest, testSomething) { - auto attString = AttributedString(); + auto attributedString = AttributedString(); auto fragment = AttributedString::Fragment(); fragment.string = "test"; @@ -35,10 +35,10 @@ TEST(ParagraphLocalDataTest, testSomething) { fragment.textAttributes = text; attString.prependFragment(fragment); - auto paragraphLocalData = ParagraphLocalData(); - paragraphLocalData.setAttributedString(attString); + auto paragraphState = ParagraphState{}; + paragraphLocalData.attributedString = attributedString; - auto result = toDynamic(paragraphLocalData)["attributedString"]; + auto result = toDynamic(paragraphState)["attributedString"]; assert(result["string"] == fragment.string); auto textAttribute = result["fragments"][0]["textAttributes"]; From adc0878703ecabc1e3460a119a1a5723bdb8ea54 Mon Sep 17 00:00:00 2001 From: nossbigg Date: Mon, 20 May 2019 10:12:33 -0700 Subject: [PATCH 0005/1084] Fix e2e detox build step (#24953) Summary: Fixes the e2e detox build step by manually overriding `PROJECT_ROOT` for the project's JS bundle build step. After seeing [quite](https://github.com/facebook/react-native/issues/18472#issuecomment-428996279) [a](https://github.com/facebook/react-native/issues/18472#issuecomment-450485004) [few](https://github.com/facebook/react-native/issues/15432#issuecomment-417310668) [comments](https://stackoverflow.com/a/49506072) suggesting running some variant of the `react-native bundle` manually on your own so as to build the jsbundle required as part of the build step for RNTester project... The main issue I found was that the working directory in which `react-native-xcode.sh` executed the CLI bundle step was not correct. The `PROJECT_ROOT` was not resolving to the root of the `react-native` project directory, but instead to something to the effect of `/Users/gibson.cheng/IdeaProjects/react-native/../..` - of which of course the build step would not be able to find the `react-native` project to run the build against. I'm not sure if new generated `react-native` projects require this manual override, so I only applied it to the RNTester project. Reviewers are welcome to correct my understanding and solutioning to this matter :) hramos, if this works, perhaps there would not be a need to push through with #24936. Also, this contributes to #23561. ## Changelog [Internal] [Fixed] - Fix build-ios-e2e build step Pull Request resolved: https://github.com/facebook/react-native/pull/24953 Differential Revision: D15415850 Pulled By: hramos fbshipit-source-id: baaff09f81f01be4da1608e0b2898d037db35c23 --- RNTester/RNTester.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/RNTester/RNTester.xcodeproj/project.pbxproj b/RNTester/RNTester.xcodeproj/project.pbxproj index ab4d141ff89073..9d56534720e7f8 100644 --- a/RNTester/RNTester.xcodeproj/project.pbxproj +++ b/RNTester/RNTester.xcodeproj/project.pbxproj @@ -1107,7 +1107,7 @@ 13B07F871A680F5B00A75B9A /* Sources */, 13B07F8C1A680F5B00A75B9A /* Frameworks */, 13B07F8E1A680F5B00A75B9A /* Resources */, - 68CD48B71D2BCB2C007E06A9 /* Run Script */, + 68CD48B71D2BCB2C007E06A9 /* Bundle React Native code and images */, EDEBC7DE214C68E400DD5AC8 /* Embed Frameworks */, ); buildRules = ( @@ -1707,19 +1707,19 @@ shellPath = /bin/sh; shellScript = "export NODE_BINARY=node\n$SRCROOT/../scripts/react-native-xcode.sh RNTester/js/RNTesterApp.ios.js"; }; - 68CD48B71D2BCB2C007E06A9 /* Run Script */ = { + 68CD48B71D2BCB2C007E06A9 /* Bundle React Native code and images */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "Run Script"; + name = "Bundle React Native code and images"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "export NODE_BINARY=node\n$SRCROOT/../scripts/react-native-xcode.sh RNTester/js/RNTesterApp.ios.js\n"; + shellScript = "export NODE_BINARY=node\nPROJECT_ROOT=$SRCROOT/.. $SRCROOT/../scripts/react-native-xcode.sh RNTester/js/RNTesterApp.ios.js\n"; }; /* End PBXShellScriptBuildPhase section */ From 9785a572eecdc6ea89f433a93c157979ca334b57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= Date: Mon, 20 May 2019 10:12:41 -0700 Subject: [PATCH 0006/1084] Disable iOS end-to-end tests (#24962) Summary: The iOS end-to-end tests are currently broken. I'm disabling them to bring the tests back to green and unblock other PRs, until they can be fixed. ## Changelog [Internal] [Removed] - Disable iOS e2e test Pull Request resolved: https://github.com/facebook/react-native/pull/24962 Differential Revision: D15415872 Pulled By: hramos fbshipit-source-id: 1a146a2eb36d5bf9b4e1f8cc9daf9b3e4d0cfab1 --- .circleci/config.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 30d1e1d781431b..7cf18599cbe96c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -507,15 +507,15 @@ jobs: node ./scripts/run-ci-e2e-tests.js --js --retries 3 when: always - - run: - name: Run iOS End-to-End Tests - command: | - # free up port 8081 for the packager before running tests - set +eo pipefail - lsof -i tcp:8081 | awk 'NR!=1 {print $2}' | xargs kill - set -eo pipefail - node ./scripts/run-ci-e2e-tests.js --ios --retries 3; - when: always + # - run: + # name: Run iOS End-to-End Tests + # command: | + # # free up port 8081 for the packager before running tests + # set +eo pipefail + # lsof -i tcp:8081 | awk 'NR!=1 {print $2}' | xargs kill + # set -eo pipefail + # node ./scripts/run-ci-e2e-tests.js --ios --retries 3; + # when: always # ------------------------- From 19a88d7f4addcd9f95fd4908d50db37b3604b5b1 Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Mon, 20 May 2019 10:37:59 -0700 Subject: [PATCH 0007/1084] `YGNode`: Field for web defaults Summary: In order to remove the config pointer from nodes, we have to keep track of whether the node is using web defaults. This information fits into one bit that we can place in padding (i.e. no extra memory needed). This allows us to get rid of config usage withing `YGNode` with some exceptions: - `iterChildrenAfterCloningIfNeeded` -- this function will simply receive the configuration, or the cloning callback. - `setAndPropogateUseLegacyFlag` -- will be removed in D15316863 - in `YGNode::reset` -- will go away utomatically once we remove the config pointer Reviewed By: SidharthGuglani Differential Revision: D15391536 fbshipit-source-id: 0fa0d0805c6862bd741fe4a7d9b637ed534f56a4 --- .../view/yoga/YogaLayoutableShadowNode.cpp | 17 ++++++------- .../view/yoga/YogaLayoutableShadowNode.h | 12 +++++----- ReactCommon/yoga/yoga/YGNode.cpp | 24 ++++++++++++------- ReactCommon/yoga/yoga/YGNode.h | 23 +++++++++++++++--- ReactCommon/yoga/yoga/Yoga.cpp | 7 +----- 5 files changed, 49 insertions(+), 34 deletions(-) diff --git a/ReactCommon/fabric/components/view/yoga/YogaLayoutableShadowNode.cpp b/ReactCommon/fabric/components/view/yoga/YogaLayoutableShadowNode.cpp index 89abffeb1bfc9b..52c70153215861 100644 --- a/ReactCommon/fabric/components/view/yoga/YogaLayoutableShadowNode.cpp +++ b/ReactCommon/fabric/components/view/yoga/YogaLayoutableShadowNode.cpp @@ -22,21 +22,17 @@ namespace facebook { namespace react { YogaLayoutableShadowNode::YogaLayoutableShadowNode() - : yogaNode_({}), yogaConfig_(nullptr) { - initializeYogaConfig(yogaConfig_); - - yogaNode_.setConfig(&yogaConfig_); + : yogaConfig_(nullptr), yogaNode_(&initializeYogaConfig(yogaConfig_)) { yogaNode_.setContext(this); } YogaLayoutableShadowNode::YogaLayoutableShadowNode( const YogaLayoutableShadowNode &layoutableShadowNode) : LayoutableShadowNode(layoutableShadowNode), - yogaNode_(layoutableShadowNode.yogaNode_), - yogaConfig_(nullptr) { - initializeYogaConfig(yogaConfig_); - - yogaNode_.setConfig(&yogaConfig_); + yogaConfig_(nullptr), + yogaNode_( + layoutableShadowNode.yogaNode_, + &initializeYogaConfig(yogaConfig_)) { yogaNode_.setContext(this); yogaNode_.setOwner(nullptr); @@ -286,10 +282,11 @@ YGSize YogaLayoutableShadowNode::yogaNodeMeasureCallbackConnector( yogaFloatFromFloat(size.height)}; } -void YogaLayoutableShadowNode::initializeYogaConfig(YGConfig &config) { +YGConfig &YogaLayoutableShadowNode::initializeYogaConfig(YGConfig &config) { config.setCloneNodeCallback( YogaLayoutableShadowNode::yogaNodeCloneCallbackConnector); config.useLegacyStretchBehaviour = true; + return config; } } // namespace react diff --git a/ReactCommon/fabric/components/view/yoga/YogaLayoutableShadowNode.h b/ReactCommon/fabric/components/view/yoga/YogaLayoutableShadowNode.h index 012f67091c38df..afb369e60fe67e 100644 --- a/ReactCommon/fabric/components/view/yoga/YogaLayoutableShadowNode.h +++ b/ReactCommon/fabric/components/view/yoga/YogaLayoutableShadowNode.h @@ -94,6 +94,11 @@ class YogaLayoutableShadowNode : public LayoutableShadowNode, LayoutableShadowNode::UnsharedList getLayoutableChildNodes() const override; protected: + /* + * Yoga config associated (only) with this particular node. + */ + YGConfig yogaConfig_; + /* * All Yoga functions only accept non-const arguments, so we have to mark * Yoga node as `mutable` here to avoid `static_cast`ing the pointer to this @@ -101,13 +106,8 @@ class YogaLayoutableShadowNode : public LayoutableShadowNode, */ mutable YGNode yogaNode_; - /* - * Yoga config associated (only) with this particular node. - */ - YGConfig yogaConfig_; - private: - static void initializeYogaConfig(YGConfig &config); + static YGConfig &initializeYogaConfig(YGConfig &config); static YGNode *yogaNodeCloneCallbackConnector( YGNode *oldYogaNode, YGNode *parentYogaNode, diff --git a/ReactCommon/yoga/yoga/YGNode.cpp b/ReactCommon/yoga/yoga/YGNode.cpp index 2c68d6077bcbea..172da8713d50c7 100644 --- a/ReactCommon/yoga/yoga/YGNode.cpp +++ b/ReactCommon/yoga/yoga/YGNode.cpp @@ -22,6 +22,7 @@ YGNode::YGNode(YGNode&& node) { measureUsesContext_ = node.measureUsesContext_; baselineUsesContext_ = node.baselineUsesContext_; printUsesContext_ = node.printUsesContext_; + useWebDefaults_ = node.useWebDefaults_; measure_ = node.measure_; baseline_ = node.baseline_; print_ = node.print_; @@ -38,6 +39,13 @@ YGNode::YGNode(YGNode&& node) { } } +YGNode::YGNode(const YGNode& node, YGConfigRef config) : YGNode{node} { + config_ = config; + if (config->useWebDefaults) { + useWebDefaults(); + } +} + void YGNode::print(void* printContext) { if (print_.noContext != nullptr) { if (printUsesContext_) { @@ -349,7 +357,7 @@ YGValue YGNode::resolveFlexBasisPtr() const { return flexBasis; } if (!style_.flex().isUndefined() && style_.flex().unwrap() > 0.0f) { - return config_->useWebDefaults ? YGValueAuto : YGValueZero; + return useWebDefaults_ ? YGValueAuto : YGValueZero; } return YGValueAuto; } @@ -425,11 +433,11 @@ float YGNode::resolveFlexShrink() const { if (!style_.flexShrink().isUndefined()) { return style_.flexShrink().unwrap(); } - if (!config_->useWebDefaults && !style_.flex().isUndefined() && + if (!useWebDefaults_ && !style_.flex().isUndefined() && style_.flex().unwrap() < 0.0f) { return -style_.flex().unwrap(); } - return config_->useWebDefaults ? kWebDefaultFlexShrink : kDefaultFlexShrink; + return useWebDefaults_ ? kWebDefaultFlexShrink : kDefaultFlexShrink; } bool YGNode::isNodeFlexible() { @@ -581,11 +589,9 @@ void YGNode::reset() { clearChildren(); - auto config = getConfig(); - *this = YGNode{}; - if (config->useWebDefaults) { - style_.flexDirection() = YGFlexDirectionRow; - style_.alignContent() = YGAlignStretch; + auto webDefaults = useWebDefaults_; + *this = YGNode{getConfig()}; + if (webDefaults) { + useWebDefaults(); } - setConfig(config); } diff --git a/ReactCommon/yoga/yoga/YGNode.h b/ReactCommon/yoga/yoga/YGNode.h index bbd1b7031c9fc1..d368bde0356318 100644 --- a/ReactCommon/yoga/yoga/YGNode.h +++ b/ReactCommon/yoga/yoga/YGNode.h @@ -13,6 +13,8 @@ #include "YGStyle.h" #include "Yoga-internal.h" +YGConfigRef YGConfigGetDefault(); + struct YGNode { using MeasureWithContextFn = YGSize (*)(YGNode*, float, YGMeasureMode, float, YGMeasureMode, void*); @@ -28,6 +30,7 @@ struct YGNode { bool measureUsesContext_ : 1; bool baselineUsesContext_ : 1; bool printUsesContext_ : 1; + bool useWebDefaults_ : 1; uint8_t reserved_ = 0; union { YGMeasureFunc noContext; @@ -58,6 +61,12 @@ struct YGNode { void setMeasureFunc(decltype(measure_)); void setBaselineFunc(decltype(baseline_)); + void useWebDefaults() { + useWebDefaults_ = true; + style_.flexDirection() = YGFlexDirectionRow; + style_.alignContent() = YGAlignStretch; + } + // DANGER DANGER DANGER! // If the the node assigned to has children, we'd either have to deallocate // them (potentially incorrect) or ignore them (danger of leaks). Only ever @@ -68,8 +77,8 @@ struct YGNode { using CompactValue = facebook::yoga::detail::CompactValue; public: - YGNode() : YGNode{nullptr} {} - explicit YGNode(const YGConfigRef newConfig) + YGNode() : YGNode{YGConfigGetDefault()} {} + explicit YGNode(const YGConfigRef config) : hasNewLayout_{true}, isReferenceBaseline_{false}, isDirty_{false}, @@ -77,7 +86,12 @@ struct YGNode { measureUsesContext_{false}, baselineUsesContext_{false}, printUsesContext_{false}, - config_{newConfig} {}; + useWebDefaults_{config->useWebDefaults}, + config_{config} { + if (useWebDefaults_) { + useWebDefaults(); + } + }; ~YGNode() = default; // cleanup of owner/children relationships in YGNodeFree YGNode(YGNode&&); @@ -86,6 +100,9 @@ struct YGNode { // Should we remove this? YGNode(const YGNode& node) = default; + // for RB fabric + YGNode(const YGNode& node, YGConfigRef config); + // assignment means potential leaks of existing children, or alternatively // freeing unowned memory, double free, or freeing stack memory. YGNode& operator=(const YGNode&) = delete; diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index f7322980fd3930..bcca97951bb051 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -210,18 +210,13 @@ void YGNodeMarkDirtyAndPropogateToDescendants(const YGNodeRef node) { int32_t gConfigInstanceCount = 0; WIN_EXPORT YGNodeRef YGNodeNewWithConfig(const YGConfigRef config) { - const YGNodeRef node = new YGNode(); + const YGNodeRef node = new YGNode{config}; YGAssertWithConfig( config, node != nullptr, "Could not allocate memory for node"); #ifdef YG_ENABLE_EVENTS Event::publish(node, {config}); #endif - if (config->useWebDefaults) { - node->getStyle().flexDirection() = YGFlexDirectionRow; - node->getStyle().alignContent() = YGAlignStretch; - } - node->setConfig(config); return node; } From 3c464782e02ef0cff265c1ace5a1c7c1410b2d24 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Mon, 20 May 2019 14:32:02 -0700 Subject: [PATCH 0008/1084] Revert D15410979: [react-native][PR] [Fabric] use state in paragraph component Differential Revision: D15410979 Original commit changeset: 3c9517d2495a fbshipit-source-id: 2e2fc860dd657b2b2159bd245896a4e8a25d5734 --- .../Text/RCTParagraphComponentView.mm | 28 ++++----- .../paragraph/ParagraphComponentDescriptor.h | 2 +- .../text/paragraph/ParagraphLocalData.cpp | 58 +++++++++++++++++++ .../text/paragraph/ParagraphLocalData.h | 58 +++++++++++++++++++ .../text/paragraph/ParagraphProps.cpp | 8 +-- .../text/paragraph/ParagraphProps.h | 6 +- .../text/paragraph/ParagraphShadowNode.cpp | 28 +++++---- .../text/paragraph/ParagraphShadowNode.h | 16 +++-- .../text/paragraph/ParagraphState.cpp | 23 -------- .../text/paragraph/ParagraphState.h | 52 ----------------- .../components/text/paragraph/conversions.h | 15 +++-- .../text/tests/ParagraphLocalDataTest.cpp | 10 ++-- 12 files changed, 175 insertions(+), 129 deletions(-) create mode 100644 ReactCommon/fabric/components/text/paragraph/ParagraphLocalData.cpp create mode 100644 ReactCommon/fabric/components/text/paragraph/ParagraphLocalData.h delete mode 100644 ReactCommon/fabric/components/text/paragraph/ParagraphState.cpp delete mode 100644 ReactCommon/fabric/components/text/paragraph/ParagraphState.h diff --git a/React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm b/React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm index 9497b406f536a6..9a64f5c30dce93 100644 --- a/React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm @@ -8,8 +8,8 @@ #import "RCTParagraphComponentView.h" #import +#import #import -#import #import #import #import @@ -21,7 +21,7 @@ using namespace facebook::react; @implementation RCTParagraphComponentView { - ParagraphShadowNode::ConcreteState::Shared _state; + SharedParagraphLocalData _paragraphLocalData; ParagraphAttributes _paragraphAttributes; } @@ -63,32 +63,32 @@ - (void)updateProps:(SharedProps)props oldProps:(SharedProps)oldProps _paragraphAttributes = paragraphProps->paragraphAttributes; } -- (void)updateState:(State::Shared)state oldState:(State::Shared)oldState +- (void)updateLocalData:(SharedLocalData)localData oldLocalData:(SharedLocalData)oldLocalData { - _state = std::static_pointer_cast(state); - assert(_state); + _paragraphLocalData = std::static_pointer_cast(localData); + assert(_paragraphLocalData); [self setNeedsDisplay]; } - (void)prepareForRecycle { [super prepareForRecycle]; - _state.reset(); + _paragraphLocalData.reset(); } - (void)drawRect:(CGRect)rect { - if (!_state) { + if (!_paragraphLocalData) { return; } - SharedTextLayoutManager textLayoutManager = _state->getData().layoutManager; + SharedTextLayoutManager textLayoutManager = _paragraphLocalData->getTextLayoutManager(); RCTTextLayoutManager *nativeTextLayoutManager = (__bridge RCTTextLayoutManager *)textLayoutManager->getNativeTextLayoutManager(); CGRect frame = RCTCGRectFromRect(_layoutMetrics.getContentFrame()); - [nativeTextLayoutManager drawAttributedString:_state->getData().attributedString + [nativeTextLayoutManager drawAttributedString:_paragraphLocalData->getAttributedString() paragraphAttributes:_paragraphAttributes frame:frame]; } @@ -102,26 +102,26 @@ - (NSString *)accessibilityLabel return superAccessibilityLabel; } - if (!_state) { + if (!_paragraphLocalData) { return nil; } - return RCTNSStringFromString(_state->getData().attributedString.getString()); + return RCTNSStringFromString(_paragraphLocalData->getAttributedString().getString()); } - (SharedTouchEventEmitter)touchEventEmitterAtPoint:(CGPoint)point { - if (!_state) { + if (!_paragraphLocalData) { return _eventEmitter; } - SharedTextLayoutManager textLayoutManager = _state->getData().layoutManager; + SharedTextLayoutManager textLayoutManager = _paragraphLocalData->getTextLayoutManager(); RCTTextLayoutManager *nativeTextLayoutManager = (__bridge RCTTextLayoutManager *)textLayoutManager->getNativeTextLayoutManager(); CGRect frame = RCTCGRectFromRect(_layoutMetrics.getContentFrame()); SharedEventEmitter eventEmitter = - [nativeTextLayoutManager getEventEmitterWithAttributeString:_state->getData().attributedString + [nativeTextLayoutManager getEventEmitterWithAttributeString:_paragraphLocalData->getAttributedString() paragraphAttributes:_paragraphAttributes frame:frame atPoint:point]; diff --git a/ReactCommon/fabric/components/text/paragraph/ParagraphComponentDescriptor.h b/ReactCommon/fabric/components/text/paragraph/ParagraphComponentDescriptor.h index a0dd2abff798dc..83a5292392f6c8 100644 --- a/ReactCommon/fabric/components/text/paragraph/ParagraphComponentDescriptor.h +++ b/ReactCommon/fabric/components/text/paragraph/ParagraphComponentDescriptor.h @@ -64,7 +64,7 @@ class ParagraphComponentDescriptor final private: SharedTextLayoutManager textLayoutManager_; - std::unique_ptr measureCache_; + std::unique_ptr measureCache_; }; } // namespace react diff --git a/ReactCommon/fabric/components/text/paragraph/ParagraphLocalData.cpp b/ReactCommon/fabric/components/text/paragraph/ParagraphLocalData.cpp new file mode 100644 index 00000000000000..fb9426da9975f6 --- /dev/null +++ b/ReactCommon/fabric/components/text/paragraph/ParagraphLocalData.cpp @@ -0,0 +1,58 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "ParagraphLocalData.h" + +#include +#include + +namespace facebook { +namespace react { + +AttributedString ParagraphLocalData::getAttributedString() const { + return attributedString_; +} + +void ParagraphLocalData::setAttributedString( + AttributedString attributedString) { + ensureUnsealed(); + attributedString_ = attributedString; +} + +SharedTextLayoutManager ParagraphLocalData::getTextLayoutManager() const { + return textLayoutManager_; +} + +void ParagraphLocalData::setTextLayoutManager( + SharedTextLayoutManager textLayoutManager) { + ensureUnsealed(); + textLayoutManager_ = textLayoutManager; +} + +#ifdef ANDROID + +folly::dynamic ParagraphLocalData::getDynamic() const { + return toDynamic(*this); +} + +#endif + +#pragma mark - DebugStringConvertible + +#if RN_DEBUG_STRING_CONVERTIBLE +std::string ParagraphLocalData::getDebugName() const { + return "ParagraphLocalData"; +} + +SharedDebugStringConvertibleList ParagraphLocalData::getDebugProps() const { + return { + debugStringConvertibleItem("attributedString", attributedString_, "")}; +} +#endif + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/components/text/paragraph/ParagraphLocalData.h b/ReactCommon/fabric/components/text/paragraph/ParagraphLocalData.h new file mode 100644 index 00000000000000..15e370573566ab --- /dev/null +++ b/ReactCommon/fabric/components/text/paragraph/ParagraphLocalData.h @@ -0,0 +1,58 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include +#include + +namespace facebook { +namespace react { + +class ParagraphLocalData; + +using SharedParagraphLocalData = std::shared_ptr; + +/* + * LocalData for component. + * Represents what to render and how to render. + */ +class ParagraphLocalData : public LocalData { + public: + /* + * All content of component represented as an `AttributedString`. + */ + AttributedString getAttributedString() const; + void setAttributedString(AttributedString attributedString); + + /* + * `TextLayoutManager` provides a connection to platform-specific + * text rendering infrastructure which is capable to render the + * `AttributedString`. + */ + SharedTextLayoutManager getTextLayoutManager() const; + void setTextLayoutManager(SharedTextLayoutManager textLayoutManager); + +#ifdef ANDROID + folly::dynamic getDynamic() const override; +#endif + +#pragma mark - DebugStringConvertible + +#if RN_DEBUG_STRING_CONVERTIBLE + std::string getDebugName() const override; + SharedDebugStringConvertibleList getDebugProps() const override; +#endif + + private: + AttributedString attributedString_; + SharedTextLayoutManager textLayoutManager_; +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/components/text/paragraph/ParagraphProps.cpp b/ReactCommon/fabric/components/text/paragraph/ParagraphProps.cpp index da79a25a1aeb67..d8135cd845a2e7 100644 --- a/ReactCommon/fabric/components/text/paragraph/ParagraphProps.cpp +++ b/ReactCommon/fabric/components/text/paragraph/ParagraphProps.cpp @@ -15,8 +15,8 @@ namespace facebook { namespace react { static ParagraphAttributes convertRawProp( - RawProps const &rawProps, - ParagraphAttributes const &defaultParagraphAttributes) { + const RawProps &rawProps, + const ParagraphAttributes &defaultParagraphAttributes) { auto paragraphAttributes = ParagraphAttributes{}; paragraphAttributes.maximumNumberOfLines = convertRawProp( @@ -44,8 +44,8 @@ static ParagraphAttributes convertRawProp( } ParagraphProps::ParagraphProps( - ParagraphProps const &sourceProps, - RawProps const &rawProps) + const ParagraphProps &sourceProps, + const RawProps &rawProps) : ViewProps(sourceProps, rawProps), BaseTextProps(sourceProps, rawProps), paragraphAttributes( diff --git a/ReactCommon/fabric/components/text/paragraph/ParagraphProps.h b/ReactCommon/fabric/components/text/paragraph/ParagraphProps.h index c796eef638e58f..1e1ca67e15b97f 100644 --- a/ReactCommon/fabric/components/text/paragraph/ParagraphProps.h +++ b/ReactCommon/fabric/components/text/paragraph/ParagraphProps.h @@ -26,7 +26,7 @@ namespace react { class ParagraphProps : public ViewProps, public BaseTextProps { public: ParagraphProps() = default; - ParagraphProps(ParagraphProps const &sourceProps, RawProps const &rawProps); + ParagraphProps(const ParagraphProps &sourceProps, const RawProps &rawProps); #pragma mark - Props @@ -34,12 +34,12 @@ class ParagraphProps : public ViewProps, public BaseTextProps { * Contains all prop values that affect visual representation of the * paragraph. */ - ParagraphAttributes const paragraphAttributes{}; + const ParagraphAttributes paragraphAttributes{}; /* * Defines can the text be selected (and copied) or not. */ - bool const isSelectable{}; + const bool isSelectable{}; #pragma mark - DebugStringConvertible diff --git a/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.cpp b/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.cpp index ec7f4af6be426c..028652ca5cbcc7 100644 --- a/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.cpp +++ b/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.cpp @@ -6,13 +6,13 @@ */ #include "ParagraphShadowNode.h" +#include "ParagraphLocalData.h" #include "ParagraphMeasurementCache.h" -#include "ParagraphState.h" namespace facebook { namespace react { -char const ParagraphComponentName[] = "Paragraph"; +const char ParagraphComponentName[] = "Paragraph"; AttributedString ParagraphShadowNode::getAttributedString() const { if (!cachedAttributedString_.has_value()) { @@ -33,21 +33,26 @@ void ParagraphShadowNode::setTextLayoutManager( } void ParagraphShadowNode::setMeasureCache( - ParagraphMeasurementCache const *cache) { + const ParagraphMeasurementCache *cache) { ensureUnsealed(); measureCache_ = cache; } -void ParagraphShadowNode::updateStateIfNeeded() { +void ParagraphShadowNode::updateLocalDataIfNeeded() { ensureUnsealed(); auto attributedString = getAttributedString(); - auto const &state = getStateData(); - if (state.attributedString == attributedString) { + auto currentLocalData = + std::static_pointer_cast(getLocalData()); + if (currentLocalData && + currentLocalData->getAttributedString() == attributedString) { return; } - setStateData(ParagraphState{attributedString, textLayoutManager_}); + auto localData = std::make_shared(); + localData->setAttributedString(std::move(attributedString)); + localData->setTextLayoutManager(textLayoutManager_); + setLocalData(localData); } #pragma mark - LayoutableShadowNode @@ -59,16 +64,15 @@ Size ParagraphShadowNode::measure(LayoutConstraints layoutConstraints) const { return {0, 0}; } - ParagraphAttributes const paragraphAttributes = + const ParagraphAttributes paragraphAttributes = getProps()->paragraphAttributes; // Cache results of this function so we don't need to call measure() // repeatedly. if (measureCache_) { return measureCache_->get( - ParagraphMeasurementCacheKey{ - attributedString, paragraphAttributes, layoutConstraints}, - [&](ParagraphMeasurementCacheKey const &key) { + ParagraphMeasurementCacheKey{attributedString, paragraphAttributes, layoutConstraints}, + [&](const ParagraphMeasurementCacheKey &key) { return textLayoutManager_->measure( attributedString, paragraphAttributes, layoutConstraints); }); @@ -79,7 +83,7 @@ Size ParagraphShadowNode::measure(LayoutConstraints layoutConstraints) const { } void ParagraphShadowNode::layout(LayoutContext layoutContext) { - updateStateIfNeeded(); + updateLocalDataIfNeeded(); ConcreteViewShadowNode::layout(layoutContext); } diff --git a/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.h b/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.h index dd738f169c4a59..9d03af4a3a6006 100644 --- a/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.h +++ b/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.h @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -21,7 +20,7 @@ namespace facebook { namespace react { -extern char const ParagraphComponentName[]; +extern const char ParagraphComponentName[]; using ParagraphEventEmitter = ViewEventEmitter; @@ -33,8 +32,7 @@ using ParagraphEventEmitter = ViewEventEmitter; class ParagraphShadowNode : public ConcreteViewShadowNode< ParagraphComponentName, ParagraphProps, - ParagraphEventEmitter, - ParagraphState>, + ParagraphEventEmitter>, public BaseTextShadowNode { public: using ConcreteViewShadowNode::ConcreteViewShadowNode; @@ -47,7 +45,7 @@ class ParagraphShadowNode : public ConcreteViewShadowNode< /* * Associates a shared TextLayoutManager with the node. * `ParagraphShadowNode` uses the manager to measure text content - * and construct `ParagraphState` objects. + * and construct `ParagraphLocalData` objects. */ void setTextLayoutManager(SharedTextLayoutManager textLayoutManager); @@ -58,7 +56,7 @@ class ParagraphShadowNode : public ConcreteViewShadowNode< * By design, the ParagraphComponentDescriptor outlives all * shadow nodes, so it's safe for this to be a raw pointer. */ - void setMeasureCache(ParagraphMeasurementCache const *cache); + void setMeasureCache(const ParagraphMeasurementCache *cache); #pragma mark - LayoutableShadowNode @@ -67,13 +65,13 @@ class ParagraphShadowNode : public ConcreteViewShadowNode< private: /* - * Creates a `State` object (with `AttributedText` and + * Creates a `LocalData` object (with `AttributedText` and * `TextLayoutManager`) if needed. */ - void updateStateIfNeeded(); + void updateLocalDataIfNeeded(); SharedTextLayoutManager textLayoutManager_; - ParagraphMeasurementCache const *measureCache_; + const ParagraphMeasurementCache *measureCache_; /* * Cached attributed string that represents the content of the subtree started diff --git a/ReactCommon/fabric/components/text/paragraph/ParagraphState.cpp b/ReactCommon/fabric/components/text/paragraph/ParagraphState.cpp deleted file mode 100644 index 89a7c442c1cf95..00000000000000 --- a/ReactCommon/fabric/components/text/paragraph/ParagraphState.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include "ParagraphState.h" - -#include -#include - -namespace facebook { -namespace react { - -#ifdef ANDROID -folly::dynamic ParagraphState::getDynamic() const { - return toDynamic(*this); -} -#endif - -} // namespace react -} // namespace facebook diff --git a/ReactCommon/fabric/components/text/paragraph/ParagraphState.h b/ReactCommon/fabric/components/text/paragraph/ParagraphState.h deleted file mode 100644 index e5ae4be7567961..00000000000000 --- a/ReactCommon/fabric/components/text/paragraph/ParagraphState.h +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include -#include - -#ifdef ANDROID -#include -#endif - -namespace facebook { -namespace react { - -/* - * State for component. - * Represents what to render and how to render. - */ -class ParagraphState final { - public: - /* - * All content of component represented as an `AttributedString`. - */ - AttributedString attributedString; - - /* - * `TextLayoutManager` provides a connection to platform-specific - * text rendering infrastructure which is capable to render the - * `AttributedString`. - */ - SharedTextLayoutManager layoutManager; - -#ifdef ANDROID - ParagraphState( - AttributedString const &attributedString, - SharedTextLayoutManager const &layoutManager) - : attributedString(attributedString), layoutManager(layoutManager) {} - ParagraphState() = default; - ParagraphState(folly::dynamic const &data) { - assert(false && "Not supported"); - }; - folly::dynamic getDynamic() const; -#endif -}; - -} // namespace react -} // namespace facebook diff --git a/ReactCommon/fabric/components/text/paragraph/conversions.h b/ReactCommon/fabric/components/text/paragraph/conversions.h index 12d53b1d540616..dd507cefa0d7c3 100644 --- a/ReactCommon/fabric/components/text/paragraph/conversions.h +++ b/ReactCommon/fabric/components/text/paragraph/conversions.h @@ -5,18 +5,21 @@ #include #include -#include +#include namespace facebook { namespace react { #ifdef ANDROID -inline folly::dynamic toDynamic(ParagraphState const ¶graphState) { - folly::dynamic newState = folly::dynamic::object(); - newState["attributedString"] = toDynamic(paragraphState.attributedString); - newState["hash"] = newState["attributedString"]["hash"]; - return newState; + +inline folly::dynamic toDynamic(const ParagraphLocalData ¶graphLocalData) { + folly::dynamic newLocalData = folly::dynamic::object(); + newLocalData["attributedString"] = + toDynamic(paragraphLocalData.getAttributedString()); + newLocalData["hash"] = newLocalData["attributedString"]["hash"]; + return newLocalData; } + #endif } // namespace react diff --git a/ReactCommon/fabric/components/text/tests/ParagraphLocalDataTest.cpp b/ReactCommon/fabric/components/text/tests/ParagraphLocalDataTest.cpp index 48b09cc6d334a8..accf32c0b79443 100644 --- a/ReactCommon/fabric/components/text/tests/ParagraphLocalDataTest.cpp +++ b/ReactCommon/fabric/components/text/tests/ParagraphLocalDataTest.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include namespace facebook { @@ -21,7 +21,7 @@ namespace react { #ifdef ANDROID TEST(ParagraphLocalDataTest, testSomething) { - auto attributedString = AttributedString(); + auto attString = AttributedString(); auto fragment = AttributedString::Fragment(); fragment.string = "test"; @@ -35,10 +35,10 @@ TEST(ParagraphLocalDataTest, testSomething) { fragment.textAttributes = text; attString.prependFragment(fragment); - auto paragraphState = ParagraphState{}; - paragraphLocalData.attributedString = attributedString; + auto paragraphLocalData = ParagraphLocalData(); + paragraphLocalData.setAttributedString(attString); - auto result = toDynamic(paragraphState)["attributedString"]; + auto result = toDynamic(paragraphLocalData)["attributedString"]; assert(result["string"] == fragment.string); auto textAttribute = result["fragments"][0]["textAttributes"]; From 651ca3bc9fc7710a79d1209334d4bd4dad452fbf Mon Sep 17 00:00:00 2001 From: David Vacca Date: Mon, 20 May 2019 15:36:56 -0700 Subject: [PATCH 0009/1084] Refactor RootTag -> surfaceId Summary: Quick diff to refactor RootTag for surfaceId in Binding.cpp class This is the first diff to start moving away from rootTag naming in Fabric Reviewed By: JoshuaGross Differential Revision: D15421770 fbshipit-source-id: 7bca7782f96be3d7148ee93f5d5a3a54e0d768dd --- .../main/java/com/facebook/react/fabric/jsi/Binding.java | 2 +- .../java/com/facebook/react/fabric/jsi/jni/Binding.cpp | 8 ++++---- .../main/java/com/facebook/react/fabric/jsi/jni/Binding.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/Binding.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/Binding.java index b3346ecf9b32dc..441e98091109ab 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/Binding.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/Binding.java @@ -49,7 +49,7 @@ private native void installFabricUIManager( public native void setPixelDensity(float pointScaleFactor); public native void setConstraints( - int rootTag, float minWidth, float maxWidth, float minHeight, float maxHeight); + int surfaceId, float minWidth, float maxWidth, float minHeight, float maxHeight); public void register( JavaScriptContextHolder jsContext, diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.cpp index 4bc1df5c249f5b..daf0fd20e478c1 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.cpp @@ -67,7 +67,7 @@ void Binding::stopSurface(jint surfaceId) { } void Binding::setConstraints( - jint rootTag, + jint surfaceId, jfloat minWidth, jfloat maxWidth, jfloat minHeight, @@ -84,7 +84,7 @@ void Binding::setConstraints( constraints.minimumSize = minimumSize; constraints.maximumSize = maximumSize; - scheduler_->constraintSurfaceLayout(rootTag, constraints, context); + scheduler_->constraintSurfaceLayout(surfaceId, constraints, context); } } @@ -329,7 +329,7 @@ local_ref createDeleteMountItem( local_ref createCreateMountItem( const jni::global_ref& javaUIManager, const ShadowViewMutation& mutation, - const Tag rootTag) { + const Tag surfaceId) { static auto createJavaInstruction = jni::findClassStatic(UIManagerJavaDescriptor) ->getMethod(jstring, jint, jint, jboolean)>( @@ -345,7 +345,7 @@ local_ref createCreateMountItem( return createJavaInstruction( javaUIManager, componentName.get(), - rootTag, + surfaceId, newChildShadowView.tag, isLayoutable); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.h b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.h index e61b5c1cebaef6..d082e78f285fb9 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.h +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.h @@ -34,7 +34,7 @@ class Binding : public jni::HybridClass, public SchedulerDelegate { private: void setConstraints( - jint rootTag, + jint surfaceId, jfloat minWidth, jfloat maxWidth, jfloat minHeight, From 3b8fc8b10a7f6bfe75ac5e9399a1a67720472077 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Mon, 20 May 2019 15:36:56 -0700 Subject: [PATCH 0010/1084] Remove warnings Summary: Easy diff to remove warnings in FabricUIManager Reviewed By: JoshuaGross Differential Revision: D15421771 fbshipit-source-id: 647391a0826272d0bc9320196fc8b3cb80eecfac --- .../main/java/com/facebook/react/fabric/FabricUIManager.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java index 1efadeea295582..912523c68b6993 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -157,6 +157,7 @@ public int addRootView( /** Method called when an event has been dispatched on the C++ side. */ @DoNotStrip + @SuppressWarnings("unused") public void onRequestEventBeat() { mEventDispatcher.dispatchAllEvents(); } @@ -183,6 +184,7 @@ public void onCatalystInstanceDestroy() { } @DoNotStrip + @SuppressWarnings("unused") private void preallocateView( int rootTag, int reactTag, From 563e0bce97e7aa8e25e2dfc0e0217b0beb26dc74 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Mon, 20 May 2019 15:36:56 -0700 Subject: [PATCH 0011/1084] Refactor sComponentNames Map out of FabricUIManager Summary: Easy diff to refactor the sComponentNames map out of the FabricUIManager class. This is a necessary clean-up to perform a slightly major refactor of the Fabric classes Reviewed By: JoshuaGross Differential Revision: D15421769 fbshipit-source-id: 3be73a6e20b338c8cea23ef0c88db417df7e3aa9 --- .../react/fabric/FabricComponents.java | 46 +++++++++++++++++++ .../react/fabric/FabricJSIModuleProvider.java | 1 + .../react/fabric/FabricUIManager.java | 29 ++---------- 3 files changed, 52 insertions(+), 24 deletions(-) create mode 100644 ReactAndroid/src/main/java/com/facebook/react/fabric/FabricComponents.java diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricComponents.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricComponents.java new file mode 100644 index 00000000000000..7d1cb572449789 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricComponents.java @@ -0,0 +1,46 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +package com.facebook.react.fabric; + +import java.util.HashMap; +import java.util.Map; + +/** + * Utility class for Fabric components, this will be removed + * + *

//TODO T31905686: remove this class when the component names are unified between JS - Android + * - iOS - C++ + */ +public class FabricComponents { + + private static final Map sComponentNames = new HashMap<>(); + + static { + // TODO T31905686: unify component names between JS - Android - iOS - C++ + sComponentNames.put("View", "RCTView"); + sComponentNames.put("Image", "RCTImageView"); + sComponentNames.put("ScrollView", "RCTScrollView"); + sComponentNames.put("Slider", "RCTSlider"); + sComponentNames.put("ModalHostView", "RCTModalHostView"); + sComponentNames.put("Paragraph", "RCTText"); + sComponentNames.put("Text", "RCText"); + sComponentNames.put("RawText", "RCTRawText"); + sComponentNames.put("ActivityIndicatorView", "AndroidProgressBar"); + sComponentNames.put("ShimmeringView", "RKShimmeringView"); + sComponentNames.put("TemplateView", "RCTTemplateView"); + sComponentNames.put("AxialGradientView", "RCTAxialGradientView"); + } + + /** + * @return the name of component in the Fabric environment + */ + static String getFabricComponentName(String componentName) { + String component = sComponentNames.get(componentName); + return component != null ? component : componentName; + } + +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricJSIModuleProvider.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricJSIModuleProvider.java index e126da4a0e9601..f83bbd4abd6467 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricJSIModuleProvider.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricJSIModuleProvider.java @@ -96,6 +96,7 @@ private FabricUIManager createUIManager(EventBeatManager eventBeatManager) { private static void loadClasses() { BatchEventDispatchedListener.class.getClass(); ReactNativeConfig.class.getClass(); + FabricComponents.class.getClass(); ViewManagerFactory.class.getClass(); StateWrapper.class.getClass(); ViewFactory.class.getClass(); diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java index 912523c68b6993..2f3c65843286a6 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -7,6 +7,7 @@ package com.facebook.react.fabric; import static com.facebook.infer.annotation.ThreadConfined.UI; +import static com.facebook.react.fabric.FabricComponents.getFabricComponentName; import static com.facebook.react.fabric.mounting.LayoutMetricsConversions.getMaxSize; import static com.facebook.react.fabric.mounting.LayoutMetricsConversions.getMinSize; import static com.facebook.react.fabric.mounting.LayoutMetricsConversions.getYogaMeasureMode; @@ -15,10 +16,10 @@ import android.annotation.SuppressLint; import android.os.SystemClock; +import android.view.View; import androidx.annotation.GuardedBy; import androidx.annotation.Nullable; import androidx.annotation.UiThread; -import android.view.View; import com.facebook.common.logging.FLog; import com.facebook.debug.holder.PrinterHolder; import com.facebook.debug.tags.ReactDebugOverlayTags; @@ -38,9 +39,9 @@ import com.facebook.react.fabric.jsi.EventBeatManager; import com.facebook.react.fabric.jsi.EventEmitterWrapper; import com.facebook.react.fabric.jsi.FabricSoLoader; -import com.facebook.react.fabric.mounting.mountitems.CreateMountItem; import com.facebook.react.fabric.mounting.MountingManager; import com.facebook.react.fabric.mounting.mountitems.BatchMountItem; +import com.facebook.react.fabric.mounting.mountitems.CreateMountItem; import com.facebook.react.fabric.mounting.mountitems.DeleteMountItem; import com.facebook.react.fabric.mounting.mountitems.DispatchCommandMountItem; import com.facebook.react.fabric.mounting.mountitems.InsertMountItem; @@ -73,27 +74,12 @@ public class FabricUIManager implements UIManager, LifecycleEventListener { public static final String TAG = FabricUIManager.class.getSimpleName(); public static final boolean DEBUG = PrinterHolder.getPrinter().shouldDisplayLogMessage(ReactDebugOverlayTags.FABRIC_UI_MANAGER); - private static final Map sComponentNames = new HashMap<>(); private static final int FRAME_TIME_MS = 16; private static final int MAX_TIME_IN_FRAME_FOR_NON_BATCHED_OPERATIONS_MS = 8; private static final int PRE_MOUNT_ITEMS_INITIAL_SIZE_ARRAY = 250; static { FabricSoLoader.staticInit(); - - // TODO T31905686: unify component names between JS - Android - iOS - C++ - sComponentNames.put("View", "RCTView"); - sComponentNames.put("Image", "RCTImageView"); - sComponentNames.put("ScrollView", "RCTScrollView"); - sComponentNames.put("Slider", "RCTSlider"); - sComponentNames.put("ModalHostView", "RCTModalHostView"); - sComponentNames.put("Paragraph", "RCTText"); - sComponentNames.put("Text", "RCText"); - sComponentNames.put("RawText", "RCTRawText"); - sComponentNames.put("ActivityIndicatorView", "AndroidProgressBar"); - sComponentNames.put("ShimmeringView", "RKShimmeringView"); - sComponentNames.put("TemplateView", "RCTTemplateView"); - sComponentNames.put("AxialGradientView", "RCTAxialGradientView"); } private Binding mBinding; @@ -192,7 +178,7 @@ private void preallocateView( @Nullable ReadableMap props, boolean isLayoutable) { ThemedReactContext context = mReactContextForRootTag.get(rootTag); - String component = getComponent(componentName); + String component = getFabricComponentName(componentName); synchronized (mPreMountItemsLock) { mPreMountItems.add( new PreAllocateViewMountItem( @@ -205,16 +191,11 @@ private void preallocateView( } } - private String getComponent(String componentName) { - String component = sComponentNames.get(componentName); - return component != null ? component : componentName; - } - @DoNotStrip @SuppressWarnings("unused") private MountItem createMountItem( String componentName, int reactRootTag, int reactTag, boolean isLayoutable) { - String component = getComponent(componentName); + String component = getFabricComponentName(componentName); ThemedReactContext reactContext = mReactContextForRootTag.get(reactRootTag); if (reactContext == null) { throw new IllegalArgumentException("Unable to find ReactContext for root: " + reactRootTag); From 6c573f71f122076882d0feb452a7996d45d411da Mon Sep 17 00:00:00 2001 From: Eric Lewis Date: Mon, 20 May 2019 18:00:34 -0700 Subject: [PATCH 0012/1084] spec for JSCSamplingProfiler (#24903) Summary: part of #24875. ## Changelog [General] [Added] - Add TM spec for JSCSamplingProfiler Pull Request resolved: https://github.com/facebook/react-native/pull/24903 Reviewed By: RSNara Differential Revision: D15421649 Pulled By: fkgozali fbshipit-source-id: 3d5a04a135aa7640495a0eb682b9c2300636db8e --- .../Performance/NativeJSCSamplingProfiler.js | 20 +++++++++++++++++++ Libraries/Performance/SamplingProfiler.js | 7 +++++-- 2 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 Libraries/Performance/NativeJSCSamplingProfiler.js diff --git a/Libraries/Performance/NativeJSCSamplingProfiler.js b/Libraries/Performance/NativeJSCSamplingProfiler.js new file mode 100644 index 00000000000000..9ac1fad140d8c1 --- /dev/null +++ b/Libraries/Performance/NativeJSCSamplingProfiler.js @@ -0,0 +1,20 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +operationComplete: (token: number, result: ?string, error: ?string) => void; +} + +export default TurboModuleRegistry.get('JSCSamplingProfiler'); diff --git a/Libraries/Performance/SamplingProfiler.js b/Libraries/Performance/SamplingProfiler.js index cce9cb9596b467..2808f83ebddaec 100644 --- a/Libraries/Performance/SamplingProfiler.js +++ b/Libraries/Performance/SamplingProfiler.js @@ -28,8 +28,11 @@ const SamplingProfiler = { error = e.toString(); } - const {JSCSamplingProfiler} = require('../BatchedBridge/NativeModules'); - JSCSamplingProfiler.operationComplete(token, result, error); + const NativeJSCSamplingProfiler = require('./NativeJSCSamplingProfiler') + .default; + if (NativeJSCSamplingProfiler) { + NativeJSCSamplingProfiler.operationComplete(token, result, error); + } }, }; From 580088c1994e29f25e5e6bd524808b821f57f5bf Mon Sep 17 00:00:00 2001 From: Uilque Messias Date: Mon, 20 May 2019 18:00:34 -0700 Subject: [PATCH 0013/1084] Add spec for NativeDeviceEventManager (#24914) Summary: Part of #24875. ## Changelog [General] [Added] - TM add spec for NativeDeviceEventManager Pull Request resolved: https://github.com/facebook/react-native/pull/24914 Reviewed By: RSNara Differential Revision: D15421462 Pulled By: fkgozali fbshipit-source-id: 78b90c615cd031ecd010a552751e506406ab739a --- .../specs/NativeDeviceEventManager.js | 20 +++++++++++++++++++ Libraries/Utilities/BackHandler.android.js | 11 ++++++---- 2 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 Libraries/NativeModules/specs/NativeDeviceEventManager.js diff --git a/Libraries/NativeModules/specs/NativeDeviceEventManager.js b/Libraries/NativeModules/specs/NativeDeviceEventManager.js new file mode 100644 index 00000000000000..8f32816d8d3e7a --- /dev/null +++ b/Libraries/NativeModules/specs/NativeDeviceEventManager.js @@ -0,0 +1,20 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +invokeDefaultBackPressHandler: () => void; +} + +export default TurboModuleRegistry.get('DeviceEventManager'); diff --git a/Libraries/Utilities/BackHandler.android.js b/Libraries/Utilities/BackHandler.android.js index a7e2e29dc9ae77..6ddc3eea0782c6 100644 --- a/Libraries/Utilities/BackHandler.android.js +++ b/Libraries/Utilities/BackHandler.android.js @@ -10,9 +10,8 @@ 'use strict'; -const DeviceEventManager = require('../BatchedBridge/NativeModules') - .DeviceEventManager; -const RCTDeviceEventEmitter = require('../EventEmitter/RCTDeviceEventEmitter'); +import NativeDeviceEventManager from '../../Libraries/NativeModules/specs/NativeDeviceEventManager'; +import RCTDeviceEventEmitter from '../EventEmitter/RCTDeviceEventEmitter'; const DEVICE_BACK_EVENT = 'hardwareBackPress'; @@ -73,7 +72,11 @@ type TBackHandler = {| |}; const BackHandler: TBackHandler = { exitApp: function(): void { - DeviceEventManager.invokeDefaultBackPressHandler(); + if (!NativeDeviceEventManager) { + return; + } + + NativeDeviceEventManager.invokeDefaultBackPressHandler(); }, /** From 00fe438003150c4716d107f0bcd5610e364e4ff9 Mon Sep 17 00:00:00 2001 From: Eric Lewis Date: Mon, 20 May 2019 18:00:34 -0700 Subject: [PATCH 0014/1084] Add spec for AnimationsDebugModule (#24915) Summary: Part of #24875. ## Changelog [General] [Added] - Add TM spec for AnimationsDebugModule Pull Request resolved: https://github.com/facebook/react-native/pull/24915 Reviewed By: RSNara Differential Revision: D15421499 Pulled By: fkgozali fbshipit-source-id: f52780773f5947097b75c4d776a0b80e0bc1d387 --- .../specs/NativeAnimationsDebugModule.js | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 Libraries/NativeModules/specs/NativeAnimationsDebugModule.js diff --git a/Libraries/NativeModules/specs/NativeAnimationsDebugModule.js b/Libraries/NativeModules/specs/NativeAnimationsDebugModule.js new file mode 100644 index 00000000000000..792a6d47d03a92 --- /dev/null +++ b/Libraries/NativeModules/specs/NativeAnimationsDebugModule.js @@ -0,0 +1,21 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +startRecordingFps: () => void; + +stopRecordingFps: (animationStopTimeMs: number) => void; +} + +export default TurboModuleRegistry.get('AnimationsDebugModule'); From 35cf427365b8f58f7fec65a18c7cf9727ff54876 Mon Sep 17 00:00:00 2001 From: Glenna Buford Date: Mon, 20 May 2019 18:00:34 -0700 Subject: [PATCH 0015/1084] Add spec for DevLoadingView (#24930) Summary: Part of #24875 ## Changelog [General] [Added] - add TM spec for DevLoadingView Pull Request resolved: https://github.com/facebook/react-native/pull/24930 Reviewed By: RSNara Differential Revision: D15423524 Pulled By: fkgozali fbshipit-source-id: 18ca65abcd4fb3c0ec0434ccba0c0e1d97c17995 --- Libraries/Utilities/HMRLoadingView.ios.js | 18 +++++++++------ Libraries/Utilities/NativeDevLoadingView.js | 25 +++++++++++++++++++++ 2 files changed, 36 insertions(+), 7 deletions(-) create mode 100644 Libraries/Utilities/NativeDevLoadingView.js diff --git a/Libraries/Utilities/HMRLoadingView.ios.js b/Libraries/Utilities/HMRLoadingView.ios.js index 77105bcc1f122d..76979539ecabb9 100644 --- a/Libraries/Utilities/HMRLoadingView.ios.js +++ b/Libraries/Utilities/HMRLoadingView.ios.js @@ -11,19 +11,23 @@ 'use strict'; const processColor = require('../StyleSheet/processColor'); -const {DevLoadingView} = require('../BatchedBridge/NativeModules'); +import NativeDevLoadingView from './NativeDevLoadingView'; class HMRLoadingView { static showMessage(message: string) { - DevLoadingView.showMessage( - message, - processColor('#000000'), - processColor('#aaaaaa'), - ); + if (NativeDevLoadingView != null) { + NativeDevLoadingView.showMessage( + message, + processColor('#000000'), + processColor('#aaaaaa'), + ); + } } static hide() { - DevLoadingView.hide(); + if (NativeDevLoadingView != null) { + NativeDevLoadingView.hide(); + } } } diff --git a/Libraries/Utilities/NativeDevLoadingView.js b/Libraries/Utilities/NativeDevLoadingView.js new file mode 100644 index 00000000000000..b22399bea278cd --- /dev/null +++ b/Libraries/Utilities/NativeDevLoadingView.js @@ -0,0 +1,25 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +showMessage: ( + message: string, + color: Object, + backgroundColor: Object, + ) => void; + +hide: () => void; +} + +export default TurboModuleRegistry.get('DevLoadingView'); From c44d4f9ef6adbc68ed9baefb6f1df5ea0c8276e9 Mon Sep 17 00:00:00 2001 From: Eric Lewis Date: Mon, 20 May 2019 18:00:34 -0700 Subject: [PATCH 0016/1084] add spec for RedBox (#24922) Summary: part of #24875. ## Changelog [General] [Added] - add TM spec for RedBox Pull Request resolved: https://github.com/facebook/react-native/pull/24922 Reviewed By: RSNara Differential Revision: D15423532 Pulled By: fkgozali fbshipit-source-id: 3c30e5b32a29628caf0bb9286c0628597ac64fb7 --- Libraries/BugReporting/BugReporting.js | 8 +++---- Libraries/NativeModules/specs/NativeRedBox.js | 21 +++++++++++++++++++ Libraries/Utilities/HMRClient.js | 11 +++++++--- 3 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 Libraries/NativeModules/specs/NativeRedBox.js diff --git a/Libraries/BugReporting/BugReporting.js b/Libraries/BugReporting/BugReporting.js index ed5bdfc61d6b4b..ff6cb920b5b109 100644 --- a/Libraries/BugReporting/BugReporting.js +++ b/Libraries/BugReporting/BugReporting.js @@ -14,6 +14,7 @@ const RCTDeviceEventEmitter = require('../EventEmitter/RCTDeviceEventEmitter'); const infoLog = require('../Utilities/infoLog'); import type EmitterSubscription from '../vendor/emitter/EmitterSubscription'; +import NativeRedBox from '../NativeModules/specs/NativeRedBox'; type ExtraData = {[key: string]: string}; type SourceCallback = () => string; @@ -127,10 +128,9 @@ class BugReporting { BugReportingNativeModule.setExtraData && BugReportingNativeModule.setExtraData(extraData, fileData); - const RedBoxNativeModule = require('../BatchedBridge/NativeModules').RedBox; - RedBoxNativeModule && - RedBoxNativeModule.setExtraData && - RedBoxNativeModule.setExtraData(extraData, 'From BugReporting.js'); + if (NativeRedBox != null && NativeRedBox.setExtraData != null) { + NativeRedBox.setExtraData(extraData, 'From BugReporting.js'); + } return {extras: extraData, files: fileData}; } diff --git a/Libraries/NativeModules/specs/NativeRedBox.js b/Libraries/NativeModules/specs/NativeRedBox.js new file mode 100644 index 00000000000000..55fa1ab932854b --- /dev/null +++ b/Libraries/NativeModules/specs/NativeRedBox.js @@ -0,0 +1,21 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +setExtraData: (extraData: Object, identifier: string) => void; + +dismiss: () => void; +} + +export default TurboModuleRegistry.get('RedBox'); diff --git a/Libraries/Utilities/HMRClient.js b/Libraries/Utilities/HMRClient.js index 0c192a7092d0e4..bb5b3ab69bcdd7 100644 --- a/Libraries/Utilities/HMRClient.js +++ b/Libraries/Utilities/HMRClient.js @@ -14,6 +14,8 @@ const invariant = require('invariant'); const MetroHMRClient = require('metro/src/lib/bundle-modules/HMRClient'); +import NativeRedBox from '../NativeModules/specs/NativeRedBox'; + /** * HMR Client that receives from the server HMR updates and propagates them * runtime to reflects those changes. @@ -72,9 +74,12 @@ Error: ${e.message}`; }); hmrClient.on('update', () => { - if (Platform.OS === 'ios') { - const RCTRedBox = require('../BatchedBridge/NativeModules').RedBox; - RCTRedBox && RCTRedBox.dismiss && RCTRedBox.dismiss(); + if ( + Platform.OS === 'ios' && + NativeRedBox != null && + NativeRedBox.dismiss != null + ) { + NativeRedBox.dismiss(); } else { const RCTExceptionsManager = require('../BatchedBridge/NativeModules') .ExceptionsManager; From 56c3852384fad2e5dfbb9bad316543af972e902c Mon Sep 17 00:00:00 2001 From: Eric Lewis Date: Mon, 20 May 2019 18:00:34 -0700 Subject: [PATCH 0017/1084] add spec for HeadlessJsTaskSupport (#24907) Summary: part of #24875 ## Changelog [General] [Added] - add TM spec for HeadlessJsTaskSupport Pull Request resolved: https://github.com/facebook/react-native/pull/24907 Reviewed By: RSNara Differential Revision: D15425720 Pulled By: fkgozali fbshipit-source-id: 2e904f265a68066918bae4f6f95494ad77654598 --- Libraries/ReactNative/AppRegistry.js | 19 ++++++++++++------ .../NativeHeadlessJsTaskSupport.js | 20 +++++++++++++++++++ 2 files changed, 33 insertions(+), 6 deletions(-) create mode 100644 Libraries/ReactNative/NativeHeadlessJsTaskSupport.js diff --git a/Libraries/ReactNative/AppRegistry.js b/Libraries/ReactNative/AppRegistry.js index 3fa755e3d98490..2d517ce6dd0f10 100644 --- a/Libraries/ReactNative/AppRegistry.js +++ b/Libraries/ReactNative/AppRegistry.js @@ -11,7 +11,6 @@ const BatchedBridge = require('../BatchedBridge/BatchedBridge'); const BugReporting = require('../BugReporting/BugReporting'); -const NativeModules = require('../BatchedBridge/NativeModules'); const ReactNative = require('../Renderer/shims/ReactNative'); const SceneTracker = require('../Utilities/SceneTracker'); @@ -21,6 +20,8 @@ const renderApplication = require('./renderApplication'); const createPerformanceLogger = require('../Utilities/createPerformanceLogger'); import type {IPerformanceLogger} from '../Utilities/createPerformanceLogger'; +import NativeHeadlessJsTaskSupport from './NativeHeadlessJsTaskSupport'; + type Task = (taskData: any) => Promise; type TaskProvider = () => Task; type TaskCanceller = () => void; @@ -261,16 +262,22 @@ const AppRegistry = { const taskProvider = taskProviders.get(taskKey); if (!taskProvider) { console.warn(`No task registered for key ${taskKey}`); - NativeModules.HeadlessJsTaskSupport.notifyTaskFinished(taskId); + if (NativeHeadlessJsTaskSupport) { + NativeHeadlessJsTaskSupport.notifyTaskFinished(taskId); + } return; } taskProvider()(data) - .then(() => - NativeModules.HeadlessJsTaskSupport.notifyTaskFinished(taskId), - ) + .then(() => { + if (NativeHeadlessJsTaskSupport) { + NativeHeadlessJsTaskSupport.notifyTaskFinished(taskId); + } + }) .catch(reason => { console.error(reason); - NativeModules.HeadlessJsTaskSupport.notifyTaskFinished(taskId); + if (NativeHeadlessJsTaskSupport) { + NativeHeadlessJsTaskSupport.notifyTaskFinished(taskId); + } }); }, diff --git a/Libraries/ReactNative/NativeHeadlessJsTaskSupport.js b/Libraries/ReactNative/NativeHeadlessJsTaskSupport.js new file mode 100644 index 00000000000000..4d1cf841486aab --- /dev/null +++ b/Libraries/ReactNative/NativeHeadlessJsTaskSupport.js @@ -0,0 +1,20 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +notifyTaskFinished: (taskId: number) => void; +} + +export default TurboModuleRegistry.get('HeadlessJsTaskSupport'); From 34d88bc5976870e0de93f217f1c29c83e4648213 Mon Sep 17 00:00:00 2001 From: Pedro Pessoa Date: Mon, 20 May 2019 18:00:34 -0700 Subject: [PATCH 0018/1084] Add Spec for DatePickerAndroid (#24916) Summary: This PR solves part of this issue: https://github.com/facebook/react-native/issues/24875 ## Changelog [General] [Added] - TM Spec for DatePickerAndroid Pull Request resolved: https://github.com/facebook/react-native/pull/24916 Reviewed By: RSNara Differential Revision: D15425864 Pulled By: fkgozali fbshipit-source-id: 964412d9d8daedfe265cf277f9fe5896856e47f8 --- .../DatePickerAndroid.android.js | 5 ++--- .../NativeDatePickerAndroid.js | 20 +++++++++++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 Libraries/Components/DatePickerAndroid/NativeDatePickerAndroid.js diff --git a/Libraries/Components/DatePickerAndroid/DatePickerAndroid.android.js b/Libraries/Components/DatePickerAndroid/DatePickerAndroid.android.js index 92a78b35dab6da..4f9358e21a88ef 100644 --- a/Libraries/Components/DatePickerAndroid/DatePickerAndroid.android.js +++ b/Libraries/Components/DatePickerAndroid/DatePickerAndroid.android.js @@ -10,9 +10,8 @@ 'use strict'; -const DatePickerModule = require('../../BatchedBridge/NativeModules') - .DatePickerAndroid; import type {Options, DatePickerOpenAction} from './DatePickerAndroidTypes'; +import NativeDatePickerAndroid from './NativeDatePickerAndroid'; /** * Convert a Date to a timestamp. @@ -74,7 +73,7 @@ class DatePickerAndroid { _toMillis(optionsMs, 'minDate'); _toMillis(optionsMs, 'maxDate'); } - return DatePickerModule.open(options); + return NativeDatePickerAndroid.open(options); } /** diff --git a/Libraries/Components/DatePickerAndroid/NativeDatePickerAndroid.js b/Libraries/Components/DatePickerAndroid/NativeDatePickerAndroid.js new file mode 100644 index 00000000000000..ccc7a33f68d355 --- /dev/null +++ b/Libraries/Components/DatePickerAndroid/NativeDatePickerAndroid.js @@ -0,0 +1,20 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +open: (options: Object) => Promise; +} + +export default TurboModuleRegistry.getEnforcing('DatePickerAndroid'); From c38f167019a3c481847d4abc80a458f7784f1336 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Mon, 20 May 2019 22:28:34 -0700 Subject: [PATCH 0019/1084] Resubmit #24714 and fixes kvo crash (#24840) Summary: Resubmit #24714. From the https://github.com/facebook/react-native/pull/24714#issuecomment-491962489, seems it would crash sometimes. JoshuaGross Hi :) I added a method to let `UITextField` call the cleanup explicitly. Please check again, thanks! ## Changelog [iOS] [Fixed] - Fixes selection of single line text input Pull Request resolved: https://github.com/facebook/react-native/pull/24840 Differential Revision: D15415793 Pulled By: JoshuaGross fbshipit-source-id: 2bb32aa8a1fd8fad116177aac760509649c4a423 --- Libraries/Text/TextInput/Singleline/RCTUITextField.m | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Libraries/Text/TextInput/Singleline/RCTUITextField.m b/Libraries/Text/TextInput/Singleline/RCTUITextField.m index 3d1af3d353970a..3346fd56c3d5ee 100644 --- a/Libraries/Text/TextInput/Singleline/RCTUITextField.m +++ b/Libraries/Text/TextInput/Singleline/RCTUITextField.m @@ -176,6 +176,16 @@ - (CGRect)editingRectForBounds:(CGRect)bounds #pragma mark - Overrides +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" +// Overrides selectedTextRange setter to get notify when selectedTextRange changed. +- (void)setSelectedTextRange:(UITextRange *)selectedTextRange +{ + [super setSelectedTextRange:selectedTextRange]; + [_textInputDelegateAdapter selectedTextRangeWasSet]; +} +#pragma clang diagnostic pop + - (void)setSelectedTextRange:(UITextRange *)selectedTextRange notifyDelegate:(BOOL)notifyDelegate { if (!notifyDelegate) { From 168a67e4b2972d26c1db3fc08b119232e22a29c7 Mon Sep 17 00:00:00 2001 From: nossbigg Date: Tue, 21 May 2019 03:42:17 -0700 Subject: [PATCH 0020/1084] Return endCoordinates for keyboardDidHide keyboard event (#24947) Summary: This pull request enhances the Keyboard API event emitter for Android upon `keyboardDidHide` by returning a `KeyboardEvent` with a meaningful `endCoordinates` property (instead of emitting a null as of current implementation). This change standardizes the `keyboardDidHide` keyboard event emission across both iOS and Android, which makes it easier for developers to use the API. In particular, the semantics of `endCoordinates` emitted during the `keyboardDidHide` event on Android will match nicely with semantics of the same event emitted on iOS: - `screenY` will be height of the screen, as that the keyboard has collapsed to the bottom of the screen - `screenX` will be 0, as the keyboard will always be flush to the sides of the screen - `height` will be 0, as the keyboard has fully collapsed - `width` will be the width of the screen, as the keyboard will always extend to the width of the screen Also, the flowtypes for `KeyboardEvent` have been further improved and are more explicit to better highlight the different object shapes (see `IOSKeyboardEvent` and `AndroidKeyboardEvent`) depending on the platform. ## Changelog [Android] [Added] - Return endCoordinates for keyboardDidHide keyboard event Pull Request resolved: https://github.com/facebook/react-native/pull/24947 Differential Revision: D15413441 Pulled By: cpojer fbshipit-source-id: aa3998542b7068e9852467038f57310355018379 --- Libraries/Components/Keyboard/Keyboard.js | 19 +++++-- RNTester/js/RNTesterList.android.js | 4 ++ .../com/facebook/react/ReactRootView.java | 52 ++++++++++++++----- 3 files changed, 58 insertions(+), 17 deletions(-) diff --git a/Libraries/Components/Keyboard/Keyboard.js b/Libraries/Components/Keyboard/Keyboard.js index 4e5674fb984c85..a7970fc8ed0aed 100644 --- a/Libraries/Components/Keyboard/Keyboard.js +++ b/Libraries/Components/Keyboard/Keyboard.js @@ -33,18 +33,29 @@ export type KeyboardEventEasing = | 'linear' | 'keyboard'; -type ScreenRect = $ReadOnly<{| +export type KeyboardEventCoordinates = $ReadOnly<{| screenX: number, screenY: number, width: number, height: number, |}>; -export type KeyboardEvent = $ReadOnly<{| +export type KeyboardEvent = AndroidKeyboardEvent | IOSKeyboardEvent; + +type BaseKeyboardEvent = {| duration: number, easing: KeyboardEventEasing, - endCoordinates: ScreenRect, - startCoordinates: ScreenRect, + endCoordinates: KeyboardEventCoordinates, +|}; + +export type AndroidKeyboardEvent = $ReadOnly<{| + ...BaseKeyboardEvent, + easing: 'keyboard', +|}>; + +export type IOSKeyboardEvent = $ReadOnly<{| + ...BaseKeyboardEvent, + startCoordinates: KeyboardEventCoordinates, isEventFromThisApp: boolean, |}>; diff --git a/RNTester/js/RNTesterList.android.js b/RNTester/js/RNTesterList.android.js index a721932ddff20d..7d2677f137acbf 100644 --- a/RNTester/js/RNTesterList.android.js +++ b/RNTester/js/RNTesterList.android.js @@ -33,6 +33,10 @@ const ComponentExamples: Array = [ key: 'ImageExample', module: require('./ImageExample'), }, + { + key: 'KeyboardAvoidingViewExample', + module: require('./KeyboardAvoidingViewExample'), + }, { key: 'ModalExample', module: require('./ModalExample'), diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java index 97b594049a3d23..42d2c757ef2960 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java @@ -648,21 +648,33 @@ private void checkForKeyboardEvents() { getRootView().getWindowVisibleDisplayFrame(mVisibleViewArea); final int heightDiff = DisplayMetricsHolder.getWindowDisplayMetrics().heightPixels - mVisibleViewArea.bottom; - if (mKeyboardHeight != heightDiff && heightDiff > mMinKeyboardHeightDetected) { - // keyboard is now showing, or the keyboard height has changed + + boolean isKeyboardShowingOrKeyboardHeightChanged = + mKeyboardHeight != heightDiff && heightDiff > mMinKeyboardHeightDetected; + if (isKeyboardShowingOrKeyboardHeightChanged) { mKeyboardHeight = heightDiff; - WritableMap params = Arguments.createMap(); - WritableMap coordinates = Arguments.createMap(); - coordinates.putDouble("screenY", PixelUtil.toDIPFromPixel(mVisibleViewArea.bottom)); - coordinates.putDouble("screenX", PixelUtil.toDIPFromPixel(mVisibleViewArea.left)); - coordinates.putDouble("width", PixelUtil.toDIPFromPixel(mVisibleViewArea.width())); - coordinates.putDouble("height", PixelUtil.toDIPFromPixel(mKeyboardHeight)); - params.putMap("endCoordinates", coordinates); - sendEvent("keyboardDidShow", params); - } else if (mKeyboardHeight != 0 && heightDiff <= mMinKeyboardHeightDetected) { - // keyboard is now hidden + sendEvent("keyboardDidShow", + createKeyboardEventPayload( + PixelUtil.toDIPFromPixel(mVisibleViewArea.bottom), + PixelUtil.toDIPFromPixel(mVisibleViewArea.left), + PixelUtil.toDIPFromPixel(mVisibleViewArea.width()), + PixelUtil.toDIPFromPixel(mKeyboardHeight)) + ); + return; + } + + boolean isKeyboardHidden = + mKeyboardHeight != 0 && heightDiff <= mMinKeyboardHeightDetected; + if (isKeyboardHidden) { mKeyboardHeight = 0; - sendEvent("keyboardDidHide", null); + sendEvent("keyboardDidHide", + createKeyboardEventPayload( + PixelUtil.toDIPFromPixel(mVisibleViewArea.height()), + 0, + PixelUtil.toDIPFromPixel(mVisibleViewArea.width()), + 0 + ) + ); } } @@ -746,5 +758,19 @@ private void emitUpdateDimensionsEvent() { .getNativeModule(DeviceInfoModule.class) .emitUpdateDimensionsEvent(); } + + private WritableMap createKeyboardEventPayload(double screenY, double screenX, double width, double height) { + WritableMap keyboardEventParams = Arguments.createMap(); + WritableMap endCoordinates = Arguments.createMap(); + + endCoordinates.putDouble("height", height); + endCoordinates.putDouble("screenX", screenX); + endCoordinates.putDouble("width", width); + endCoordinates.putDouble("screenY", screenY); + + keyboardEventParams.putMap("endCoordinates", endCoordinates); + keyboardEventParams.putString("easing", "keyboard"); + return keyboardEventParams; + } } } From 30a0a03b80cfcd67efdb821698b78e465d8af9b3 Mon Sep 17 00:00:00 2001 From: nossbigg Date: Tue, 21 May 2019 05:41:23 -0700 Subject: [PATCH 0021/1084] Fix ios/android e2e tests (#24974) Summary: Fixes broken ios/android e2e tests for CI. Changes: 1. Use `npm pack` instead of `yarn pack` during e2e test 2. Update test string assertions in ios/android e2e tests 3. Use `Step One` as candidate for source code replacement to test for page changes (since the "Welcome to React Native" string exists in the `Header` component instead of being on `App.js`) ## Changelog [Internal] [Fixed] - Fix ios/android e2e tests Pull Request resolved: https://github.com/facebook/react-native/pull/24974 Differential Revision: D15431539 Pulled By: cpojer fbshipit-source-id: 054af2c2fff6bbdb2263c15d7f5cd416aaa507fd --- .circleci/config.yml | 19 +++++++++---------- scripts/android-e2e-test.js | 11 ++++------- scripts/run-ci-e2e-tests.js | 2 +- .../ios/HelloWorldTests/HelloWorldTests.m | 2 +- 4 files changed, 15 insertions(+), 19 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 7cf18599cbe96c..563bc3e8a03284 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -507,16 +507,15 @@ jobs: node ./scripts/run-ci-e2e-tests.js --js --retries 3 when: always - # - run: - # name: Run iOS End-to-End Tests - # command: | - # # free up port 8081 for the packager before running tests - # set +eo pipefail - # lsof -i tcp:8081 | awk 'NR!=1 {print $2}' | xargs kill - # set -eo pipefail - # node ./scripts/run-ci-e2e-tests.js --ios --retries 3; - # when: always - + - run: + name: Run iOS End-to-End Tests + command: | + # free up port 8081 for the packager before running tests + set +eo pipefail + lsof -i tcp:8081 | awk 'NR!=1 {print $2}' | xargs kill + set -eo pipefail + node ./scripts/run-ci-e2e-tests.js --ios --retries 3; + when: always # ------------------------- # JOBS: Test Android diff --git a/scripts/android-e2e-test.js b/scripts/android-e2e-test.js index 404902cbfd0509..be4d076acc7b3b 100644 --- a/scripts/android-e2e-test.js +++ b/scripts/android-e2e-test.js @@ -110,15 +110,12 @@ describe('Android Test App', function() { return ( driver .waitForElementByXPath( - '//android.widget.TextView[starts-with(@text, "Welcome to React Native!")]', + '//android.widget.TextView[starts-with(@text, "Welcome to React")]', ) .then(() => { fs.writeFileSync( 'App.js', - androidAppCode.replace( - 'Welcome to React Native!', - 'Welcome to React Native! Reloaded', - ), + androidAppCode.replace('Step One', 'Step 1'), 'utf-8', ); }) @@ -128,7 +125,7 @@ describe('Android Test App', function() { .pressDeviceKey(46) .sleep(2000) .waitForElementByXPath( - '//android.widget.TextView[starts-with(@text, "Welcome to React Native! Reloaded")]', + '//android.widget.TextView[starts-with(@text, "Step 1")]', ) .finally(() => { clearInterval(intervalToUpdate); @@ -145,7 +142,7 @@ describe('Android Test App', function() { return ( driver .waitForElementByXPath( - '//android.widget.TextView[starts-with(@text, "Welcome to React Native!")]', + '//android.widget.TextView[starts-with(@text, "Welcome to React")]', ) // http://developer.android.com/reference/android/view/KeyEvent.html#KEYCODE_MENU .pressDeviceKey(82) diff --git a/scripts/run-ci-e2e-tests.js b/scripts/run-ci-e2e-tests.js index f46e92075a069d..95312e7998d57a 100644 --- a/scripts/run-ci-e2e-tests.js +++ b/scripts/run-ci-e2e-tests.js @@ -81,7 +81,7 @@ try { } } - if (exec('yarn pack').code) { + if (exec('npm pack').code) { echo('Failed to pack react-native'); exitCode = 1; throw Error(exitCode); diff --git a/template/ios/HelloWorldTests/HelloWorldTests.m b/template/ios/HelloWorldTests/HelloWorldTests.m index e9db2f118ab97e..3b45a1a9197b13 100644 --- a/template/ios/HelloWorldTests/HelloWorldTests.m +++ b/template/ios/HelloWorldTests/HelloWorldTests.m @@ -12,7 +12,7 @@ #import #define TIMEOUT_SECONDS 600 -#define TEXT_TO_LOOK_FOR @"Welcome to React Native!" +#define TEXT_TO_LOOK_FOR @"Welcome to React" @interface HelloWorldTests : XCTestCase From 80258b530d1b6334de3d4e35e361d356ca053cee Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Tue, 21 May 2019 06:02:19 -0700 Subject: [PATCH 0022/1084] Remove `YGNode::setAndPropogateUseLegacyFlag` Summary: `YGNode::setAndPropogateUseLegacyFlag` was only used for debugging purposes. Here, we replace it with a free function in `Yoga.cpp`. Now that we have events, the diffing functionality should go into a separate debugging package and be implemented in terms of an event listener. Let's do that as soon as we can support multiple listeners. Reviewed By: SidharthGuglani Differential Revision: D15316863 fbshipit-source-id: db929eba7c2de8aa1550e362dd2c175929c0070e --- ReactCommon/yoga/yoga/YGNode.cpp | 7 ------ ReactCommon/yoga/yoga/YGNode.h | 1 - ReactCommon/yoga/yoga/Yoga.cpp | 37 +++++++++++++++++++------------- 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/ReactCommon/yoga/yoga/YGNode.cpp b/ReactCommon/yoga/yoga/YGNode.cpp index 172da8713d50c7..81a4216eb6616a 100644 --- a/ReactCommon/yoga/yoga/YGNode.cpp +++ b/ReactCommon/yoga/yoga/YGNode.cpp @@ -539,13 +539,6 @@ bool YGNode::didUseLegacyFlag() { return didUseLegacyFlag; } -void YGNode::setAndPropogateUseLegacyFlag(bool useLegacyFlag) { - config_->useLegacyStretchBehaviour = useLegacyFlag; - for_each(children_.begin(), children_.end(), [=](YGNodeRef childNode) { - childNode->getConfig()->useLegacyStretchBehaviour = useLegacyFlag; - }); -} - void YGNode::setLayoutDoesLegacyFlagAffectsLayout( bool doesLegacyFlagAffectsLayout) { layout_.doesLegacyStretchFlagAffectsLayout = doesLegacyFlagAffectsLayout; diff --git a/ReactCommon/yoga/yoga/YGNode.h b/ReactCommon/yoga/yoga/YGNode.h index d368bde0356318..e5f1da3ca5ba78 100644 --- a/ReactCommon/yoga/yoga/YGNode.h +++ b/ReactCommon/yoga/yoga/YGNode.h @@ -292,7 +292,6 @@ struct YGNode { const float mainSize, const float crossSize, const float ownerWidth); - void setAndPropogateUseLegacyFlag(bool useLegacyFlag); void setLayoutDoesLegacyFlagAffectsLayout(bool doesLegacyFlagAffectsLayout); void setLayoutDidUseLegacyFlag(bool didUseLegacyFlag); void markDirtyAndPropogateDownwards(); diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index bcca97951bb051..c4544ed95a76a2 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -3992,6 +3992,13 @@ static void YGRoundToPixelGrid( } } +static void unsetUseLegacyFlagRecursively(YGNodeRef node) { + node->getConfig()->useLegacyStretchBehaviour = false; + for (auto child : node->getChildren()) { + unsetUseLegacyFlagRecursively(child); + } +} + void YGNodeCalculateLayoutWithContext( const YGNodeRef node, const float ownerWidth, @@ -4096,16 +4103,16 @@ void YGNodeCalculateLayoutWithContext( // run experiments. if (node->getConfig()->shouldDiffLayoutWithoutLegacyStretchBehaviour && node->didUseLegacyFlag()) { - const YGNodeRef originalNode = YGNodeDeepClone(node); - originalNode->resolveDimension(); + const YGNodeRef nodeWithoutLegacyFlag = YGNodeDeepClone(node); + nodeWithoutLegacyFlag->resolveDimension(); // Recursively mark nodes as dirty - originalNode->markDirtyAndPropogateDownwards(); + nodeWithoutLegacyFlag->markDirtyAndPropogateDownwards(); gCurrentGenerationCount++; // Rerun the layout, and calculate the diff - originalNode->setAndPropogateUseLegacyFlag(false); + unsetUseLegacyFlagRecursively(nodeWithoutLegacyFlag); YGMarkerLayoutData layoutMarkerData; if (YGLayoutNodeInternal( - originalNode, + nodeWithoutLegacyFlag, width, height, ownerDirection, @@ -4115,37 +4122,37 @@ void YGNodeCalculateLayoutWithContext( ownerHeight, true, "initial", - originalNode->getConfig(), + nodeWithoutLegacyFlag->getConfig(), layoutMarkerData, layoutContext)) { - originalNode->setPosition( - originalNode->getLayout().direction, + nodeWithoutLegacyFlag->setPosition( + nodeWithoutLegacyFlag->getLayout().direction, ownerWidth, ownerHeight, ownerWidth); YGRoundToPixelGrid( - originalNode, - originalNode->getConfig()->pointScaleFactor, + nodeWithoutLegacyFlag, + nodeWithoutLegacyFlag->getConfig()->pointScaleFactor, 0.0f, 0.0f); // Set whether the two layouts are different or not. auto neededLegacyStretchBehaviour = - !originalNode->isLayoutTreeEqualToNode(*node); + !nodeWithoutLegacyFlag->isLayoutTreeEqualToNode(*node); node->setLayoutDoesLegacyFlagAffectsLayout(neededLegacyStretchBehaviour); #ifdef DEBUG - if (originalNode->getConfig()->printTree) { + if (nodeWithoutLegacyFlag->getConfig()->printTree) { YGNodePrint( - originalNode, + nodeWithoutLegacyFlag, (YGPrintOptions)( YGPrintOptionsLayout | YGPrintOptionsChildren | YGPrintOptionsStyle)); } #endif } - YGConfigFreeRecursive(originalNode); - YGNodeFreeRecursive(originalNode); + YGConfigFreeRecursive(nodeWithoutLegacyFlag); + YGNodeFreeRecursive(nodeWithoutLegacyFlag); } } From c9df1db00a0b5ee5378135877b2d57724c309c63 Mon Sep 17 00:00:00 2001 From: Vojtech Novak Date: Tue, 21 May 2019 06:36:38 -0700 Subject: [PATCH 0023/1084] allow custom maybeSetText logic for ReactEditText subclasses (#24927) Summary: We're working on a custom EditText that supports some rich text editing, and one of the places where our logic has to be different from the textinput provided by RN is the text setting logic: https://github.com/facebook/react-native/blob/7abfd23b90db08b426c3c91b0cb6d01d161a9b9e/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java#L377 However, some of the important members are private and our subclass cannot access them (we work around this now with reflection). It would be nice if we could work with them directly, either using getters and setters or by changing the access. Let me know what you think about this. Thanks. ## Changelog [Android] [Added] - allow custom maybeSetText logic for ReactEditText subclasses Pull Request resolved: https://github.com/facebook/react-native/pull/24927 Differential Revision: D15431682 Pulled By: cpojer fbshipit-source-id: 91860cadac0798a101ff7df6f6b868f3980ba9b1 --- .../com/facebook/react/views/textinput/ReactEditText.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java index 1638d4925013ce..63a941a0c2ab2e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java @@ -58,18 +58,18 @@ public class ReactEditText extends EditText { // This flag is set to true when we set the text of the EditText explicitly. In that case, no // *TextChanged events should be triggered. This is less expensive than removing the text // listeners and adding them back again after the text change is completed. - private boolean mIsSettingTextFromJS; + protected boolean mIsSettingTextFromJS; // This component is controlled, so we want it to get focused only when JS ask it to do so. // Whenever android requests focus (which it does for random reasons), it will be ignored. private boolean mIsJSSettingFocus; private int mDefaultGravityHorizontal; private int mDefaultGravityVertical; - private int mNativeEventCount; - private int mMostRecentEventCount; + protected int mNativeEventCount; + protected int mMostRecentEventCount; private @Nullable ArrayList mListeners; private @Nullable TextWatcherDelegator mTextWatcherDelegator; private int mStagedInputType; - private boolean mContainsImages; + protected boolean mContainsImages; private @Nullable Boolean mBlurOnSubmit; private boolean mDisableFullscreen; private @Nullable String mReturnKeyType; From b05761f1bbd3827cebf1f05cc833690feeac7cb0 Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Tue, 21 May 2019 13:31:57 -0700 Subject: [PATCH 0024/1084] Pass State to `preallocateView` and `createView` methods whenever possible Summary: For some components, we will have state as soon as the ShadowNode is created that may be meaningful. In those cases, ViewManagers should be able to use State to create or preallocate views. FB: This will be used in following diffs for Litho support. Reviewed By: mdvacca Differential Revision: D15343702 fbshipit-source-id: 8fd672251cb88dea662b5cae5a9efc96877d28a9 --- .../react/fabric/FabricUIManager.java | 2 ++ .../facebook/react/fabric/jsi/jni/Binding.cpp | 27 ++++++++++++++----- .../fabric/mounting/ContextBasedViewPool.java | 7 ++--- .../fabric/mounting/MountingManager.java | 23 +++++++++------- .../react/fabric/mounting/ViewFactory.java | 4 ++- .../fabric/mounting/ViewManagerFactory.java | 6 +++-- .../react/fabric/mounting/ViewPool.java | 9 ++++--- .../mounting/mountitems/CreateMountItem.java | 2 +- .../mountitems/PreAllocateViewMountItem.java | 6 ++++- .../uimanager/NativeViewHierarchyManager.java | 4 +-- .../facebook/react/uimanager/ViewManager.java | 14 +++++----- .../uimanager/SimpleViewPropertyTest.java | 4 +-- 12 files changed, 67 insertions(+), 41 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java index 2f3c65843286a6..9b9c6f78107b38 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -176,6 +176,7 @@ private void preallocateView( int reactTag, final String componentName, @Nullable ReadableMap props, + Object stateWrapper, boolean isLayoutable) { ThemedReactContext context = mReactContextForRootTag.get(rootTag); String component = getFabricComponentName(componentName); @@ -187,6 +188,7 @@ private void preallocateView( reactTag, component, props, + (StateWrapper) stateWrapper, isLayoutable)); } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.cpp index daf0fd20e478c1..10e9551ecbb67a 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.cpp @@ -290,14 +290,17 @@ local_ref createUpdateStateMountItem( // Do not hold onto Java object from C // We DO want to hold onto C object from Java, since we don't know the // lifetime of the Java object - auto javaStateWrapper = StateWrapperImpl::newObjectJavaArgs(); - StateWrapperImpl* cStateWrapper = cthis(javaStateWrapper); - cStateWrapper->state_ = state; + local_ref javaStateWrapper = nullptr; + if (state != nullptr) { + javaStateWrapper = StateWrapperImpl::newObjectJavaArgs(); + StateWrapperImpl* cStateWrapper = cthis(javaStateWrapper); + cStateWrapper->state_ = state; + } return updateStateInstruction( javaUIManager, mutation.newChildShadowView.tag, - javaStateWrapper.get()); + (javaStateWrapper != nullptr ? javaStateWrapper.get() : nullptr)); } @@ -525,13 +528,23 @@ void Binding::schedulerDidRequestPreliminaryViewAllocation( static auto preallocateView = jni::findClassStatic(UIManagerJavaDescriptor) - ->getMethod("preallocateView"); + ->getMethod("preallocateView"); - local_ref readableMap = + // Do not hold onto Java object from C + // We DO want to hold onto C object from Java, since we don't know the + // lifetime of the Java object + local_ref javaStateWrapper = nullptr; + if (shadowView.state != nullptr) { + javaStateWrapper = StateWrapperImpl::newObjectJavaArgs(); + StateWrapperImpl* cStateWrapper = cthis(javaStateWrapper); + cStateWrapper->state_ = shadowView.state; + } + + local_ref props = castReadableMap(ReadableNativeMap::newObjectCxxArgs(shadowView.props->rawProps)); auto component = getPlatformComponentName(shadowView); preallocateView( - javaUIManager_, surfaceId, shadowView.tag, component.get(), readableMap.get(), isLayoutableShadowNode); + javaUIManager_, surfaceId, shadowView.tag, component.get(), props.get(), (javaStateWrapper != nullptr ? javaStateWrapper.get() : nullptr), isLayoutableShadowNode); } void Binding::registerNatives() { diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/ContextBasedViewPool.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/ContextBasedViewPool.java index 579e8b730059bd..3265d6e957769e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/ContextBasedViewPool.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/ContextBasedViewPool.java @@ -9,6 +9,7 @@ import android.view.View; import androidx.annotation.UiThread; import com.facebook.react.uimanager.ReactStylesDiffMap; +import com.facebook.react.uimanager.StateWrapper; import com.facebook.react.uimanager.ThemedReactContext; import com.facebook.react.uimanager.ViewManagerRegistry; import java.util.WeakHashMap; @@ -26,13 +27,13 @@ public final class ContextBasedViewPool implements ViewFactory { @UiThread void createView(ThemedReactContext context, ReactStylesDiffMap props, String componentName) { - getViewPool(context).createView(componentName, props, context); + getViewPool(context).createView(componentName, props, null, context); } @UiThread @Override - public View getOrCreateView(String componentName, ReactStylesDiffMap props, ThemedReactContext context) { - return getViewPool(context).getOrCreateView(componentName, props, context); + public View getOrCreateView(String componentName, ReactStylesDiffMap props, StateWrapper stateWrapper, ThemedReactContext context) { + return getViewPool(context).getOrCreateView(componentName, props, stateWrapper, context); } @UiThread diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java index 675c43c57caccd..730db1205391f0 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java @@ -170,11 +170,12 @@ public void removeViewAt(int parentTag, int index) { } @UiThread - public void createViewWithProps( + public void createView( ThemedReactContext themedReactContext, String componentName, int reactTag, @Nullable ReadableMap props, + @Nullable StateWrapper stateWrapper, boolean isLayoutable) { if (mTagToViewState.get(reactTag) != null) { return; @@ -183,19 +184,20 @@ public void createViewWithProps( View view = null; ViewManager viewManager = null; - ReactStylesDiffMap diffMap = null; + ReactStylesDiffMap propsDiffMap = null; if (props != null) { - diffMap = new ReactStylesDiffMap(props); + propsDiffMap = new ReactStylesDiffMap(props); } if (isLayoutable) { viewManager = mViewManagerRegistry.get(componentName); - view = mViewFactory.getOrCreateView(componentName, diffMap, themedReactContext); + view = mViewFactory.getOrCreateView(componentName, propsDiffMap, stateWrapper, themedReactContext); view.setId(reactTag); } ViewState viewState = new ViewState(reactTag, view, viewManager); - viewState.mCurrentProps = diffMap; + viewState.mCurrentProps = propsDiffMap; + viewState.mCurrentState = (stateWrapper != null ? stateWrapper.getState() : null); mTagToViewState.put(reactTag, viewState); } @@ -313,6 +315,7 @@ public void preallocateView( String componentName, int reactTag, @Nullable ReadableMap props, + @Nullable StateWrapper stateWrapper, boolean isLayoutable) { if (mTagToViewState.get(reactTag) != null) { @@ -320,7 +323,7 @@ public void preallocateView( "View for component " + componentName + " with tag " + reactTag + " already exists."); } - createViewWithProps(reactContext, componentName, reactTag, props, isLayoutable); + createView(reactContext, componentName, reactTag, props, stateWrapper, isLayoutable); } @UiThread @@ -362,10 +365,10 @@ private static class ViewState { final int mReactTag; final boolean mIsRoot; @Nullable final ViewManager mViewManager; - public ReactStylesDiffMap mCurrentProps; - public ReadableMap mCurrentLocalData; - public ReadableMap mCurrentState; - public EventEmitterWrapper mEventEmitter; + public ReactStylesDiffMap mCurrentProps = null; + public ReadableMap mCurrentLocalData = null; + public ReadableMap mCurrentState = null; + public EventEmitterWrapper mEventEmitter = null; private ViewState(int reactTag, @Nullable View view, @Nullable ViewManager viewManager) { this(reactTag, view, viewManager, false); diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/ViewFactory.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/ViewFactory.java index b92f576ebda4bf..086e143b16dceb 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/ViewFactory.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/ViewFactory.java @@ -8,11 +8,13 @@ import android.view.View; import com.facebook.react.uimanager.ReactStylesDiffMap; +import com.facebook.react.uimanager.StateWrapper; import com.facebook.react.uimanager.ThemedReactContext; +import javax.annotation.Nullable; public interface ViewFactory { - View getOrCreateView(String componentName, ReactStylesDiffMap props, ThemedReactContext context); + View getOrCreateView(String componentName, @Nullable ReactStylesDiffMap props, @Nullable StateWrapper stateWrapper, ThemedReactContext context); void recycle(ThemedReactContext context, String componentName, View view); diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/ViewManagerFactory.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/ViewManagerFactory.java index dffac26f5a69e9..3e9236263ec778 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/ViewManagerFactory.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/ViewManagerFactory.java @@ -9,8 +9,10 @@ import androidx.annotation.UiThread; import android.view.View; import com.facebook.react.uimanager.ReactStylesDiffMap; +import com.facebook.react.uimanager.StateWrapper; import com.facebook.react.uimanager.ThemedReactContext; import com.facebook.react.uimanager.ViewManagerRegistry; +import javax.annotation.Nullable; public class ViewManagerFactory implements ViewFactory { @@ -23,8 +25,8 @@ public class ViewManagerFactory implements ViewFactory { @UiThread @Override public View getOrCreateView( - String componentName, ReactStylesDiffMap props, ThemedReactContext context) { - return mViewManagerRegistry.get(componentName).createViewWithProps(context, props, null); + String componentName, @Nullable ReactStylesDiffMap props, @Nullable StateWrapper stateWrapper, ThemedReactContext context) { + return mViewManagerRegistry.get(componentName).createView(context, props, stateWrapper, null); } @UiThread diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/ViewPool.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/ViewPool.java index 69a2c911c8de0d..4fc769aec8325e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/ViewPool.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/ViewPool.java @@ -10,6 +10,7 @@ import android.view.View; import com.facebook.react.common.ClearableSynchronizedPool; import com.facebook.react.uimanager.ReactStylesDiffMap; +import com.facebook.react.uimanager.StateWrapper; import com.facebook.react.uimanager.ThemedReactContext; import com.facebook.react.uimanager.ViewManager; import com.facebook.react.uimanager.ViewManagerRegistry; @@ -26,20 +27,20 @@ public final class ViewPool { } @UiThread - void createView(String componentName, ReactStylesDiffMap props, ThemedReactContext context) { + void createView(String componentName, ReactStylesDiffMap props, StateWrapper stateWrapper, ThemedReactContext context) { ClearableSynchronizedPool viewPool = getViewPoolForComponent(componentName); ViewManager viewManager = mViewManagerRegistry.get(componentName); // TODO: T31905686 Integrate / re-implement jsResponder - View view = viewManager.createViewWithProps(context, props, null); + View view = viewManager.createView(context, props, stateWrapper, null); viewPool.release(view); } @UiThread - View getOrCreateView(String componentName, ReactStylesDiffMap props, ThemedReactContext context) { + View getOrCreateView(String componentName, ReactStylesDiffMap props, StateWrapper stateWrapper, ThemedReactContext context) { ClearableSynchronizedPool viewPool = getViewPoolForComponent(componentName); View view = viewPool.acquire(); if (view == null) { - createView(componentName, props, context); + createView(componentName, props, stateWrapper, context); view = viewPool.acquire(); } return view; diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/CreateMountItem.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/CreateMountItem.java index af518f1c47136c..980e7800cfe982 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/CreateMountItem.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/CreateMountItem.java @@ -32,7 +32,7 @@ public CreateMountItem( @Override public void execute(MountingManager mountingManager) { - mountingManager.createViewWithProps(mContext, mComponent, mReactTag, null, mIsLayoutable); + mountingManager.createView(mContext, mComponent, mReactTag, null, null, mIsLayoutable); } @Override diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/PreAllocateViewMountItem.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/PreAllocateViewMountItem.java index ca117d4587776c..00d0f65c0091e1 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/PreAllocateViewMountItem.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/PreAllocateViewMountItem.java @@ -13,6 +13,7 @@ import com.facebook.common.logging.FLog; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.fabric.mounting.MountingManager; +import com.facebook.react.uimanager.StateWrapper; import com.facebook.react.uimanager.ThemedReactContext; /** {@link MountItem} that is used to pre-allocate views for JS components. */ @@ -22,6 +23,7 @@ public class PreAllocateViewMountItem implements MountItem { private final int mRootTag; private final int mReactTag; private final @Nullable ReadableMap mProps; + private final @Nullable StateWrapper mStateWrapper; private final ThemedReactContext mContext; private final boolean mIsLayoutable; @@ -31,11 +33,13 @@ public PreAllocateViewMountItem( int reactTag, String component, @Nullable ReadableMap props, + StateWrapper stateWrapper, boolean isLayoutable) { mContext = context; mComponent = component; mRootTag = rootTag; mProps = props; + mStateWrapper = stateWrapper; mReactTag = reactTag; mIsLayoutable = isLayoutable; } @@ -45,7 +49,7 @@ public void execute(MountingManager mountingManager) { if (DEBUG) { FLog.d(TAG, "Executing pre-allocation of: " + toString()); } - mountingManager.preallocateView(mContext, mComponent, mReactTag, mProps, mIsLayoutable); + mountingManager.preallocateView(mContext, mComponent, mReactTag, mProps, mStateWrapper, mIsLayoutable); } @Override diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java index 724dd8e81d0e69..48d1daefd5f855 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java @@ -8,7 +8,6 @@ package com.facebook.react.uimanager; import android.content.res.Resources; -import android.os.Build; import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.SparseIntArray; @@ -19,7 +18,6 @@ import android.view.ViewParent; import android.widget.PopupMenu; import com.facebook.common.logging.FLog; -import com.facebook.infer.annotation.Assertions; import com.facebook.react.R; import com.facebook.react.bridge.Callback; import com.facebook.react.bridge.JSApplicationIllegalArgumentException; @@ -256,7 +254,7 @@ public synchronized void createView( try { ViewManager viewManager = mViewManagers.get(className); - View view = viewManager.createViewWithProps(themedContext, null, mJSResponderHandler); + View view = viewManager.createView(themedContext, null, null, mJSResponderHandler); mTagsToViews.put(tag, view); mTagsToViewManagers.put(tag, viewManager); diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java index 7100f699c40e02..a0f7c9ba51cdc7 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java @@ -11,10 +11,8 @@ import android.view.View; import com.facebook.react.bridge.BaseJavaModule; import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.uimanager.StateWrapper; import com.facebook.react.touch.JSResponderHandler; import com.facebook.react.touch.ReactInterceptingViewGroup; import com.facebook.react.uimanager.annotations.ReactProp; @@ -41,6 +39,7 @@ public abstract class ViewManager * * @param viewToUpdate * @param props + * @param stateWrapper */ public void updateProperties(@Nonnull T viewToUpdate, ReactStylesDiffMap props) { ViewManagerPropertyUpdater.updateProps(this, viewToUpdate, props); @@ -53,17 +52,18 @@ public void updateProperties(@Nonnull T viewToUpdate, ReactStylesDiffMap props) private final @Nonnull T createView( @Nonnull ThemedReactContext reactContext, JSResponderHandler jsResponderHandler) { - return this.createViewWithProps(reactContext, null, jsResponderHandler); + return createView(reactContext, null, null, jsResponderHandler); } /** * Creates a view with knowledge of props. */ - public @Nonnull T createViewWithProps( + public @Nonnull T createView( @Nonnull ThemedReactContext reactContext, - ReactStylesDiffMap props, + @Nullable ReactStylesDiffMap props, + @Nullable StateWrapper stateWrapper, JSResponderHandler jsResponderHandler) { - T view = createViewInstanceWithProps(reactContext, props); + T view = createViewInstance(reactContext, props, stateWrapper); addEventEmitters(reactContext, view); if (view instanceof ReactInterceptingViewGroup) { ((ReactInterceptingViewGroup) view).setOnInterceptTouchEventListener(jsResponderHandler); @@ -115,7 +115,7 @@ public C createShadowNodeInstance() { * Override it if you need props upon creation of the view. * @param reactContext */ - protected @Nonnull T createViewInstanceWithProps(@Nonnull ThemedReactContext reactContext, ReactStylesDiffMap initialProps) { + protected @Nonnull T createViewInstance(@Nonnull ThemedReactContext reactContext, @Nullable ReactStylesDiffMap initialProps, @Nullable StateWrapper stateWrapper) { T view = createViewInstance(reactContext); if (initialProps != null) { updateProperties(view, initialProps); diff --git a/ReactAndroid/src/test/java/com/facebook/react/uimanager/SimpleViewPropertyTest.java b/ReactAndroid/src/test/java/com/facebook/react/uimanager/SimpleViewPropertyTest.java index e054da2e8088aa..c66d9bf48df2c7 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/uimanager/SimpleViewPropertyTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/uimanager/SimpleViewPropertyTest.java @@ -83,7 +83,7 @@ public ReactStylesDiffMap buildStyles(Object... keysAndValues) { @Test public void testOpacity() { - View view = mManager.createViewWithProps(mThemedContext, buildStyles(), new JSResponderHandler()); + View view = mManager.createView(mThemedContext, buildStyles(), null, new JSResponderHandler()); mManager.updateProperties(view, buildStyles()); assertThat(view.getAlpha()).isEqualTo(1.0f); @@ -97,7 +97,7 @@ public void testOpacity() { @Test public void testBackgroundColor() { - View view = mManager.createViewWithProps(mThemedContext, buildStyles(), new JSResponderHandler()); + View view = mManager.createView(mThemedContext, buildStyles(), null, new JSResponderHandler()); mManager.updateProperties(view, buildStyles()); assertThat(view.getBackground()).isEqualTo(null); From 1c2c431f68f814147dc2f3148d5d44572d8943c4 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 21 May 2019 18:43:27 -0700 Subject: [PATCH 0025/1084] Fabric: Making `UIView+ComponentViewProtocol` to conform to the protocol Summary: UIView+ComponentViewProtocol is useless without it. Conformance to the protocol is only purpose of this category. We didn't run into this issue because we have never used that yet. Reviewed By: mdvacca Differential Revision: D15419953 fbshipit-source-id: 84a430397e886c941d35075d9754eae5748c3a3f --- React/Fabric/Mounting/UIView+ComponentViewProtocol.h | 2 +- React/Fabric/Mounting/UIView+ComponentViewProtocol.mm | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/React/Fabric/Mounting/UIView+ComponentViewProtocol.h b/React/Fabric/Mounting/UIView+ComponentViewProtocol.h index b0ff68685b2b48..35bb307da1ea5f 100644 --- a/React/Fabric/Mounting/UIView+ComponentViewProtocol.h +++ b/React/Fabric/Mounting/UIView+ComponentViewProtocol.h @@ -14,7 +14,7 @@ NS_ASSUME_NONNULL_BEGIN /** * Default implementation of RCTComponentViewProtocol. */ -@interface UIView (ComponentViewProtocol) +@interface UIView (ComponentViewProtocol) + (std::vector)supplementalComponentDescriptorProviders; diff --git a/React/Fabric/Mounting/UIView+ComponentViewProtocol.mm b/React/Fabric/Mounting/UIView+ComponentViewProtocol.mm index c5285a316a31bb..6d25817c091fc3 100644 --- a/React/Fabric/Mounting/UIView+ComponentViewProtocol.mm +++ b/React/Fabric/Mounting/UIView+ComponentViewProtocol.mm @@ -17,6 +17,12 @@ @implementation UIView (ComponentViewProtocol) ++ (ComponentDescriptorProvider)componentDescriptorProvider +{ + RCTAssert(NO, @"`-[RCTComponentViewProtocol componentDescriptorProvider]` must be implemented in a concrete class."); + return {}; +} + + (std::vector)supplementalComponentDescriptorProviders { return {}; From 9c3f4c021ed1a9ba6b9df467e76788a906c3547f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= Date: Tue, 21 May 2019 19:35:40 -0700 Subject: [PATCH 0026/1084] Bots cleanup, avoid leaving inline reviews when N>5 (#24923) Summary: This PR cleans up some of our GitHub bots. The overall goal is to make the contribution process just a tad nicer. ### analysis-bot * The bot will continue leaving GitHub Reviews when it finds lint issues, but will abstain from leaving inline comments if they would exceed 5 in number. * The review comment left by the bot has instructions on how to reproduce the lint issues locally. This will educate PR authors on how to run lint and fix the issues without unnecessarily spamming the PR with 50+ comments, while still providing useful reviews to authors when only a handful of lint issues slip by. * Code moved to `bots/` directory for ease of discovery and co-location with pull-bot. * Added `yarn lint-ci` command. This seems like the right choice: it's running `yarn lint` and other linters, and it is only intended to run on CI. * It's still possible to run `yarn lint-ci` locally, though the script will stop short of posting a review to GitHub unless the necessary envvars are provided. * Added `yarn shellcheck` command. This can be run locally, though it requires `shellcheck` to be installed. * Outside of this PR, I added instructions on using shellcheck to https://github.com/facebook/react-native/wiki/Development-Dependencies * Updated Circle CI config to use these new commands, and streamlined the `analyze_pr` step. * Documented analysis-bot in `bots/README.md`. ### pull-bot * Bumped `danger-js` dependency. No breaking changes found in this minor bump from what I can tell. * Documented pull-bot in `bots/README.md`. ### misc * PR template: don't use jargon. ## Changelog [Internal] [Changed] - GitHub Bots cleanup Pull Request resolved: https://github.com/facebook/react-native/pull/24923 Differential Revision: D15399744 Pulled By: hramos fbshipit-source-id: 32632e775f8554424072270e3f98542de84bfb8c --- .circleci/config.yml | 39 +- .github/PULL_REQUEST_TEMPLATE.md | 2 +- bots/IssueCommands.txt | 70 -- bots/README.md | 27 +- .../circleci => bots}/code-analysis-bot.js | 15 +- bots/dangerfile.js | 6 +- bots/package.json | 5 +- bots/yarn.lock | 657 +++++++++++++++++- package.json | 2 + scripts/circleci/analyze_code.sh | 8 +- scripts/circleci/analyze_scripts.sh | 38 +- 11 files changed, 731 insertions(+), 138 deletions(-) delete mode 100644 bots/IssueCommands.txt rename {scripts/circleci => bots}/code-analysis-bot.js (93%) diff --git a/.circleci/config.yml b/.circleci/config.yml index 563bc3e8a03284..d38432f3e37c65 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -215,44 +215,27 @@ jobs: - restore-cache: *restore-yarn-cache - run: *yarn - - run: - name: Analyze Shell Scripts + name: Install dependencies command: | - echo -e "\\x1B[36mInstalling additional dependencies\\x1B[0m" - apt update && apt install -y shellcheck jq - yarn add @octokit/rest@15.18.0 - echo -e "\\x1B[36mAnalyzing shell scripts\\x1B[0m"; \ - GITHUB_TOKEN="$PUBLIC_ANALYSISBOT_GITHUB_TOKEN_A""$PUBLIC_ANALYSISBOT_GITHUB_TOKEN_B" \ - GITHUB_OWNER="$CIRCLE_PROJECT_USERNAME" \ - GITHUB_REPO="$CIRCLE_PROJECT_REPONAME" \ - GITHUB_PR_NUMBER="$CIRCLE_PR_NUMBER" \ - ./scripts/circleci/analyze_scripts.sh - when: always + apt update + apt install -y shellcheck jq + cd bots + yarn install --non-interactive --cache-folder ~/.cache/yarn + - save-cache: *save-yarn-cache - run: - name: Analyze Code - command: | - echo -e "\\x1B[36mInstalling additional dependencies\\x1B[0m"; yarn add @octokit/rest@15.18.0 - echo -e "\\x1B[36mAnalyzing code\\x1B[0m"; \ - GITHUB_TOKEN="$PUBLIC_ANALYSISBOT_GITHUB_TOKEN_A""$PUBLIC_ANALYSISBOT_GITHUB_TOKEN_B" \ - GITHUB_OWNER="$CIRCLE_PROJECT_USERNAME" \ - GITHUB_REPO="$CIRCLE_PROJECT_REPONAME" \ - GITHUB_PR_NUMBER="$CIRCLE_PR_NUMBER" \ - ./scripts/circleci/analyze_code.sh + name: Run linters against modified files (analysis-bot) + command: GITHUB_TOKEN="$PUBLIC_ANALYSISBOT_GITHUB_TOKEN_A""$PUBLIC_ANALYSISBOT_GITHUB_TOKEN_B" yarn lint-ci when: always - run: - name: Analyze Pull Request + name: Analyze Pull Request (pull-bot) command: | - echo -e "\\x1B[36mInstalling additional dependencies\\x1B[0m" cd bots - yarn install --non-interactive --cache-folder ~/.cache/yarn - echo -e "\\x1B[36mAnalyzing pull request\\x1B[0m"; \ - DANGER_GITHUB_API_TOKEN="$PUBLIC_PULLBOT_GITHUB_TOKEN_A""$PUBLIC_PULLBOT_GITHUB_TOKEN_B" \ - yarn danger ci --use-github-checks + DANGER_GITHUB_API_TOKEN="$PUBLIC_PULLBOT_GITHUB_TOKEN_A""$PUBLIC_PULLBOT_GITHUB_TOKEN_B" yarn danger ci --use-github-checks when: always - - save-cache: *save-yarn-cache + # ------------------------- # JOBS: Analyze Code diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 990da2c1f6f4ec..d34a154fd4e4e1 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -12,4 +12,4 @@ ## Test Plan - + diff --git a/bots/IssueCommands.txt b/bots/IssueCommands.txt deleted file mode 100644 index 0c73a582e065c5..00000000000000 --- a/bots/IssueCommands.txt +++ /dev/null @@ -1,70 +0,0 @@ -React Native GitHub Issue Task Force: AndrewJack, astreet, bestander, brentvatne, browniefed, cancan101, charpeni, chirag04, christopherdro, corbt, cosmith, damusnet, DanielMSchmidt, davidaurelio, dmmiller, dsibiski, foghina, frantic, gantman, geirman, grabbou, gre, ide, janicduplessis, javache, jaygarcia, jsierles, kmagiera, knowbody, kmagiera, Kureev, lelandrichardson, lwinkyawmyat, martinbigio, melihmucuk, mkonicek, ncuillery, radko93, react-native-bot, rigdern, rmevans9, rt2zz, ryankask, satya164, skevy, tabrindle, timwangdev, vjeux - -@facebook-github-bot answered -comment Closing this issue as {author} says the question asked has been answered. -close - -@facebook-github-bot duplicate (#[0-9]+) -comment Duplicate of {match0} -close - -@facebook-github-bot expected -comment The comment above tells me this is expected behavior. If you'd like to change how this feature works, please submit a feature request on [Canny](https://react-native.canny.io/feature-requests) so that other people can vote on it.

[How to Contribute](https://facebook.github.io/react-native/docs/contributing.html#bugs) • [What to Expect from Maintainers](https://facebook.github.io/react-native/docs/maintainers.html#handling-issues) -close - -@facebook-github-bot stack-overflow -comment Hey {issue_author}, thanks for posting this! {author} tells me this issue looks like a question that would be best asked on [Stack Overflow](https://stackoverflow.com/questions/tagged/react-native). Stack Overflow is amazing for Q&A: it has a reputation system, voting, the ability to mark a question as answered. Because of the reputation system it is likely the community will see and answer your question there. This also helps us use the GitHub bug tracker for bugs only.

[How to Contribute](https://facebook.github.io/react-native/docs/contributing.html#bugs) • [What to Expect from Maintainers](https://facebook.github.io/react-native/docs/maintainers.html#handling-issues) -add-label ":no_entry_sign:For Stack Overflow" -close - -@facebook-github-bot label (.*) -add-label {match0} - -@facebook-github-bot no-reply -comment Closing this issue as more information is needed to debug this and we haven't heard back from the author. -add-label ":grey_question:Needs More Information" -close - -@facebook-github-bot no-template -comment Hey {issue_author}, thanks for posting this! It looks like your issue is missing some required information. Can you please add all the details specified in the [Issue Template](https://raw.githubusercontent.com/facebook/react-native/master/.github/ISSUE_TEMPLATE.md)? This is necessary for people to be able to understand and reproduce your issue. I am going to close this, but please feel free to open a new issue with the additional information provided. Thanks!

[How to Contribute](https://facebook.github.io/react-native/docs/contributing.html#bugs) • [What to Expect from Maintainers](https://facebook.github.io/react-native/docs/maintainers.html#handling-issues) -add-label ":grey_question:Needs More Information" -close - -@facebook-github-bot close -comment {author} has closed this issue. -close - -@facebook-github-bot large-pr -comment Thank you for your contribution. Unfortunately, this pull request seems relatively large.

In order to reduce the load on maintainers, it would be valuable if you could [split this into small, targeted PRs that changed one thing at a time](https://graysonkoonce.com/stacked-pull-requests-keeping-github-diffs-small/).

If doing this requires more than a few pull requests, please open (or update) an issue specifying your goal and the different steps you will take in your PRs. This will ensure maintainers have context on the relationship between the PRs.

If this is a codemod or other formatting change that is simple but inherently touches many files, please comment on this and let us know and we will reopen the PR. -add-label ":clipboard:Large PR :bangbang:" -close - -@facebook-github-bot bugfix -comment Hey {issue_author}, if you're sure this is a bug, can you send a pull request with a fix?

[How to Contribute](https://facebook.github.io/react-native/docs/contributing.html#bugs) • [What to Expect from Maintainers](https://facebook.github.io/react-native/docs/maintainers.html#handling-issues) -add-label "Help Wanted :octocat:" - -@facebook-github-bot needs-repro -comment Can you reproduce the issue using [Snack](https://snack.expo.io)? This step is necessary for people to be able to see and debug the issue being reported.

[How to Contribute](https://facebook.github.io/react-native/docs/contributing.html#bugs) • [What to Expect from Maintainers](https://facebook.github.io/react-native/docs/maintainers.html#handling-issues) -add-label ":grey_question:Needs More Information" - -@facebook-github-bot cannot-repro -comment Thanks for opening the issue! It does not appear like a community member will be able to reliably reproduce this issue. This may be for several reasons; perhaps it affects a particular app but a minimal repro has not been provided, or the issue may be sporadic. As it happens, we need a concrete set of steps that can demonstrably reproduce the issue as this will allow your fellow community members to validate a fix. We'll close the issue for now, but feel free to submit a new issue once you're able to reliably reproduce the issue locally. Thanks for your understanding!

[How to Contribute](https://facebook.github.io/react-native/docs/contributing.html#bugs) • [What to Expect from Maintainers](https://facebook.github.io/react-native/docs/maintainers.html#handling-issues) -close - -@facebook-github-bot reopen -comment Okay, reopening this issue. -reopen - -@facebook-github-bot feature -comment Hey {issue_author}! Thanks for opening the issue, however it looks like a feature request. As noted in the [Issue template](https://raw.githubusercontent.com/facebook/react-native/master/.github/ISSUE_TEMPLATE.md) we'd like to use the GitHub issues to track bugs only. Can you implement the feature as a standalone npm module? If not, consider sending a pull request or a creating an entry on [Canny](https://react-native.canny.io/feature-requests/). It has a voting system and if the feature gets upvoted enough it might get implemented. Closing this now, thanks for understanding!

[How to Contribute](https://facebook.github.io/react-native/docs/contributing.html#bugs) • [What to Expect from Maintainers](https://facebook.github.io/react-native/docs/maintainers.html#handling-issues) -add-label ":star2:Feature Request" -close - -@facebook-github-bot cla -comment Hey {issue_author}! Thanks for sending this pull request! We would love to review your changes however it looks like you haven't signed the CLA yet. You can do so at https://code.facebook.com/cla. See ["How to Contribute"](https://facebook.github.io/react-native/docs/contributing.html#pull-requests) to learn more. -add-label ":grey_question:Needs More Information" - -@facebook-github-bot icebox -comment {author} tells me to close this issue because it has been inactive for a while. Maybe the issue has been fixed in a recent release, or perhaps it is not affecting a lot of people. Either way, we're automatically closing issues after a period of inactivity. Please do not take it personally!

If you think this issue should definitely remain open, please let us know. The following information is helpful when it comes to determining if the issue should be re-opened:
  • Does the issue still reproduce on the latest release candidate? Post a comment with the version you tested.
  • If so, is there any information missing from the bug report? Post a comment with all the information required by the [issue template](https://github.com/facebook/react-native/blob/master/.github/ISSUE_TEMPLATE.md).
  • Is there a pull request that addresses this issue? Post a comment with the PR number so we can follow up.
If you would like to work on a patch to fix the issue, *contributions are very welcome*! Read through the [contribution guide](https://facebook.github.io/react-native/docs/contributing.html), and feel free to hop into [#react-native](https://discordapp.com/invite/0ZcbPKXt5bZjGY5n) if you need help planning your contribution.

[How to Contribute](https://facebook.github.io/react-native/docs/contributing.html#bugs) • [What to Expect from Maintainers](https://facebook.github.io/react-native/docs/maintainers.html#handling-issues) -add-label Stale -close diff --git a/bots/README.md b/bots/README.md index 985687f387b207..d108148033d413 100644 --- a/bots/README.md +++ b/bots/README.md @@ -1,18 +1,23 @@ -GitHub bots, such as the Danger bot, as well as messages used by the Facebook GitHub bot are all configured in this directory/ - ## Danger -We use [Danger JS](http://danger.systems/js/) to perform rudimentary maintenance on the React Native repository. +[Danger](http://danger.systems/js/) is a JavaScript runtime which helps you provide continuous feedback inside GitHub. It's used by @pull-bot to analyze the contents of a GitHub pull request. -If you'd like to make changes to the Dangerfile, find an existing PR on the React Native repo and make note of the URL. - -Then, run from the React Native root directory: +If you want to test changes to Danger, I'd recommend checking out an existing PR and then running the `danger pr` command. +You'll need a GitHub token. You can re-use this one: `a6edf8e8d40ce4e8b11a 150e1341f4dd9c944d2a` (just remove the space). +So, for example: ``` -cd bots -npm install -.. -node bots/node_modules/.bin/danger pr https://github.com/facebook/react-native/pull/1 +DANGER_GITHUB_API_TOKEN=[ENV_ABOVE] yarn danger pr https://github.com/facebook/react-native/pull/1234 ``` -And you will get the responses from parsing the Dangerfile. +## Code Analysis Bot + +The code analysis bot provides lint and other results as inline reviews on GitHub. It runs as part of the Circle CI analysis workflow. + +If you want to test changes to the Code Analysis Bot, I'd recommend checking out an existing PR and then running the `analyze pr` command. +You'll need a GitHub token. You can re-use this one: `78a72af35445ca3f8180` `b1a98e0bbd56ff1ccba1` (just remove the space). +So, for example: + +``` +GITHUB_TOKEN=[ENV_ABOVE] GITHUB_PR_NUMBER=1234 yarn lint-ci +``` diff --git a/scripts/circleci/code-analysis-bot.js b/bots/code-analysis-bot.js similarity index 93% rename from scripts/circleci/code-analysis-bot.js rename to bots/code-analysis-bot.js index 1a791933cd67ab..a44cec89ea69c2 100644 --- a/scripts/circleci/code-analysis-bot.js +++ b/bots/code-analysis-bot.js @@ -33,8 +33,10 @@ function push(arr, key, value) { const converterSummary = { eslint: '`eslint` found some issues. Run `yarn lint --fix` to automatically fix problems.', - flow: '`flow` found some issues.', - shellcheck: '`shellcheck` found some issues.', + flow: + '`flow` found some issues. Run `yarn flow check` to analyze your code and address any errors.', + shellcheck: + '`shellcheck` found some issues. Run `yarn shellcheck` to analyze shell scripts.', }; /** @@ -172,6 +174,9 @@ function sendReview(owner, repo, number, commit_id, body, comments) { if (comments.length === 0) { // Do not leave an empty review. return; + } else if (comments.length > 5) { + // Avoid noisy reviews and rely solely on the body of the review. + comments = []; } const event = 'REQUEST_CHANGES'; @@ -227,7 +232,7 @@ function main(messages, owner, repo, number) { }); } else { console.log( - 'Missing GITHUB_TOKEN. Example: 5fd88b964fa214c4be2b144dc5af5d486a2f8c1e. Review feedback with code analysis results will not be provided on GitHub.', + 'Missing GITHUB_TOKEN. Example: 5fd88b964fa214c4be2b144dc5af5d486a2f8c1e. Review feedback with code analysis results will not be provided on GitHub without a valid token.', ); } @@ -319,7 +324,9 @@ process.stdin.on('end', function() { const repo = process.env.GITHUB_REPO; if (!process.env.GITHUB_PR_NUMBER) { - console.error('Missing GITHUB_PR_NUMBER. Example: 4687'); + console.error( + 'Missing GITHUB_PR_NUMBER. Example: 4687. Review feedback with code analysis results cannot be provided on GitHub without a valid pull request number.', + ); // for master branch, don't throw an error process.exit(0); } diff --git a/bots/dangerfile.js b/bots/dangerfile.js index a1cbd9707fbed0..e9529acff3abb4 100644 --- a/bots/dangerfile.js +++ b/bots/dangerfile.js @@ -4,17 +4,13 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * To test Danger during development, run yarn in this directory, then run: - * $ yarn danger pr - * * @format */ 'use strict'; -const includes = require('lodash.includes'); - const {danger, fail, message, warn} = require('danger'); +const includes = require('lodash.includes'); // Provides advice if a summary section is missing, or body is too short const includesSummary = diff --git a/bots/package.json b/bots/package.json index a2c7533a4c5010..51cfe34eadeac1 100644 --- a/bots/package.json +++ b/bots/package.json @@ -4,8 +4,11 @@ "danger": "node ./node_modules/.bin/danger" }, "devDependencies": { - "danger": "^7.0.8", + "danger": "^7.1.4", "lodash.includes": "^4.3.0", "minimatch": "^3.0.4" + }, + "dependencies": { + "@octokit/rest": "15.18.0" } } diff --git a/bots/yarn.lock b/bots/yarn.lock index 8c779838b86c76..f7b51e9cfcce2b 100644 --- a/bots/yarn.lock +++ b/bots/yarn.lock @@ -30,6 +30,21 @@ node-fetch "^2.3.0" universal-user-agent "^2.0.1" +"@octokit/rest@15.18.0": + version "15.18.0" + resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-15.18.0.tgz#e6de702b57dec94c71e806f1cff0ecb9725b3054" + integrity sha512-D1dDJMbvT4dok9++vc8uwCr92ndadwfz6vHK+IklzBHKSsuLlhpv2/dzx97Y4aRlm0t74LeXKDp4j0b4M2vmQw== + dependencies: + before-after-hook "^1.1.0" + btoa-lite "^1.0.0" + debug "^3.1.0" + http-proxy-agent "^2.1.0" + https-proxy-agent "^2.2.0" + lodash "^4.17.4" + node-fetch "^2.1.1" + universal-user-agent "^2.0.0" + url-template "^2.0.8" + "@octokit/rest@^16.14.1": version "16.15.0" resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-16.15.0.tgz#648a88d5de055bcf38976709c5b2bdf1227b926f" @@ -69,11 +84,59 @@ ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= + +arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= + +atob@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +before-after-hook@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-1.4.0.tgz#2b6bf23dca4f32e628fd2747c10a37c74a4b484d" + integrity sha512-l5r9ir56nda3qu14nAXIlyq1MmUSs0meCIaFAh8HwkFwP1F8eToOuS3ah2VAHHcY04jaYD7FpJC5JTXHYRbkzg== + before-after-hook@^1.2.0: version "1.3.2" resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-1.3.2.tgz#7bfbf844ad670aa7a96b5a4e4e15bd74b08ed66b" @@ -87,6 +150,22 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +braces@^2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + btoa-lite@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/btoa-lite/-/btoa-lite-1.0.0.tgz#337766da15801210fdd956c22e9c6891ab9d0337" @@ -97,6 +176,21 @@ buffer-equal-constant-time@1.0.1: resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk= +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + camelcase@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" @@ -111,6 +205,16 @@ chalk@^2.3.0: escape-string-regexp "^1.0.5" supports-color "^5.3.0" +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + cliui@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" @@ -125,6 +229,14 @@ code-point-at@^1.0.0: resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -142,11 +254,21 @@ commander@^2.18.0: resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== +component-emitter@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= + core-js@^2.5.7: version "2.6.4" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.4.tgz#b8897c062c4d769dd30a0ac5c73976c47f92ea0d" @@ -172,10 +294,10 @@ cross-spawn@^6.0.0: shebang-command "^1.2.0" which "^1.2.9" -danger@^7.0.8: - version "7.0.9" - resolved "https://registry.yarnpkg.com/danger/-/danger-7.0.9.tgz#057ccf52868feb4416f6379199a813d001f8588e" - integrity sha512-HqsztujIEdbBL89Xcr0CF7n/qul5W7LRvER63Dc2dc+MHO3RBtc+4lB2AE1kiOXm5uTgLCA3E2dHdzMvcrYuhg== +danger@^7.1.4: + version "7.1.4" + resolved "https://registry.yarnpkg.com/danger/-/danger-7.1.4.tgz#de068b9277143505a7aaa698f27aac90c00303ae" + integrity sha512-Q6Qi7GZ58k2kyGbZkToGquM8ELtY9GR2CsfHeKGzIa77cRzaTMvn/x1W4FH3Vd0WPIASDV1yFp0xjvbK9sPcpg== dependencies: "@babel/polyfill" "^7.2.5" "@octokit/rest" "^16.14.1" @@ -194,7 +316,10 @@ danger@^7.0.8: lodash.includes "^4.3.0" lodash.isobject "^3.0.2" lodash.keys "^4.0.8" + lodash.mapvalues "^4.6.0" + lodash.memoize "^4.1.2" memfs-or-file-map-to-github-branch "^1.1.0" + micromatch "^3.1.10" node-cleanup "^2.1.2" node-fetch "^2.3.0" override-require "^1.1.1" @@ -216,6 +341,13 @@ debug@3.1.0: dependencies: ms "2.0.0" +debug@^2.2.0, debug@^2.3.3: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + debug@^3.1.0: version "3.2.6" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" @@ -235,11 +367,38 @@ decamelize@^1.1.1: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + deepmerge@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-3.1.0.tgz#a612626ce4803da410d77554bfd80361599c034d" integrity sha512-/TnecbwXEdycfbsM2++O3eGiatEFHjjNciHEwJclM+T5Kd94qD1AP+2elP/Mq0L5b9VZJao5znR01Mz6eX8Seg== +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + ecdsa-sig-formatter@1.0.10: version "1.0.10" resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.10.tgz#1c595000f04a8897dfb85000892a0f4c33af86c3" @@ -290,6 +449,19 @@ execa@^0.7.0: signal-exit "^3.0.0" strip-eof "^1.0.0" +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + expand-tilde@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" @@ -304,6 +476,38 @@ extend-shallow@^2.0.1: dependencies: is-extendable "^0.1.0" +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + find-up@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" @@ -311,6 +515,18 @@ find-up@^2.1.0: dependencies: locate-path "^2.0.0" +for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= + dependencies: + map-cache "^0.2.2" + fs-exists-sync@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" @@ -331,6 +547,11 @@ get-stream@^3.0.0: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= + git-config-path@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/git-config-path/-/git-config-path-1.0.1.tgz#6d33f7ed63db0d0e118131503bab3aca47d54664" @@ -350,6 +571,37 @@ has-flag@^3.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + homedir-polyfill@^1.0.0, homedir-polyfill@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" @@ -365,7 +617,7 @@ http-proxy-agent@^2.1.0: agent-base "4" debug "3.1.0" -https-proxy-agent@^2.2.1: +https-proxy-agent@^2.2.0, https-proxy-agent@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0" integrity sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ== @@ -388,11 +640,69 @@ invert-kv@^1.0.0: resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= -is-extendable@^0.1.0: +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== + dependencies: + kind-of "^6.0.0" + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== + dependencies: + kind-of "^6.0.0" + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== + dependencies: + is-plain-object "^2.0.4" + is-fullwidth-code-point@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" @@ -405,7 +715,14 @@ is-fullwidth-code-point@^2.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= -is-plain-object@^2.0.4: +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= + dependencies: + kind-of "^3.0.2" + +is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== @@ -417,12 +734,29 @@ is-stream@^1.1.0: resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + +isarray@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= -isobject@^3.0.1: +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= @@ -485,6 +819,30 @@ jws@^3.1.5: jwa "^1.2.0" safe-buffer "^5.0.1" +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== + lcid@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" @@ -550,6 +908,16 @@ lodash.keys@^4.0.8: resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-4.2.0.tgz#a08602ac12e4fb83f91fc1fb7a360a4d9ba35205" integrity sha1-oIYCrBLk+4P5H8H7ejYKTZujUgU= +lodash.mapvalues@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz#1bafa5005de9dd6f4f26668c30ca37230cc9689c" + integrity sha1-G6+lAF3p3W9PJmaMMMo3IwzJaJw= + +lodash.memoize@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= + lodash.once@^4.0.0: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" @@ -565,6 +933,11 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= +lodash@^4.17.4: + version "4.17.11" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" + integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== + lru-cache@^4.0.1: version "4.1.5" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" @@ -578,6 +951,18 @@ macos-release@^2.0.0: resolved "https://registry.yarnpkg.com/macos-release/-/macos-release-2.0.0.tgz#7dddf4caf79001a851eb4fba7fb6034f251276ab" integrity sha512-iCM3ZGeqIzlrH7KxYK+fphlJpCCczyHXc+HhRVbEu9uNTCrzYJjvvtefzeKTCVHd5AP/aD/fzC80JZ4ZP+dQ/A== +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= + dependencies: + object-visit "^1.0.0" + mem@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" @@ -590,6 +975,25 @@ memfs-or-file-map-to-github-branch@^1.1.0: resolved "https://registry.yarnpkg.com/memfs-or-file-map-to-github-branch/-/memfs-or-file-map-to-github-branch-1.1.2.tgz#9d46c02481b7eca8e5ee8a94f170b7e0138cad67" integrity sha512-D2JKK2DTuVYQqquBWco3K6UfSVyVwmd58dgNqh+TgxHOZdTmR8I130gjMbVCkemDl/EzqDA62417cJxKL3/FFA== +micromatch@^3.1.10: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + mimic-fn@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" @@ -607,6 +1011,14 @@ minimist@^1.2.0: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= +mixin-deep@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" + integrity sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ== + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -617,6 +1029,23 @@ ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" @@ -627,6 +1056,11 @@ node-cleanup@^2.1.2: resolved "https://registry.yarnpkg.com/node-cleanup/-/node-cleanup-2.1.2.tgz#7ac19abd297e09a7f72a71545d951b517e4dde2c" integrity sha1-esGavSl+Caf3KnFUXZUbUX5N3iw= +node-fetch@^2.1.1: + version "2.6.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" + integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== + node-fetch@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.3.0.tgz#1a1d940bbfb916a1d3e0219f037e89e71f8c5fa5" @@ -644,6 +1078,29 @@ number-is-nan@^1.0.0: resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= + dependencies: + isobject "^3.0.0" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= + dependencies: + isobject "^3.0.1" + octokit-pagination-methods@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/octokit-pagination-methods/-/octokit-pagination-methods-1.1.0.tgz#cf472edc9d551055f9ef73f6e42b4dbb4c80bea4" @@ -738,6 +1195,11 @@ parse-passwd@^1.0.0: resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY= +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= + path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" @@ -753,6 +1215,11 @@ pinpoint@^1.1.0: resolved "https://registry.yarnpkg.com/pinpoint/-/pinpoint-1.1.0.tgz#0cf7757a6977f1bf7f6a32207b709e377388e874" integrity sha1-DPd1eml38b9/ajIge3CeN3OI6HQ= +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= + pseudomap@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" @@ -768,6 +1235,24 @@ regenerator-runtime@^0.12.0: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de" integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg== +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +repeat-element@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" + integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== + +repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -783,6 +1268,16 @@ require-main-filename@^1.0.1: resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + rfc6902@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/rfc6902/-/rfc6902-3.0.1.tgz#03a3d38329dbc266fbc92aa7fc14546d7839e89f" @@ -793,6 +1288,13 @@ safe-buffer@^5.0.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= + dependencies: + ret "~0.1.10" + semver@^5.5.0: version "5.6.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" @@ -803,6 +1305,26 @@ set-blocking@^2.0.0: resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= +set-value@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" + integrity sha1-fbCPnT0i3H945Trzw79GZuzfzPE= + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.1" + to-object-path "^0.3.0" + +set-value@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" + integrity sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg== + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" @@ -820,6 +1342,72 @@ signal-exit@^3.0.0: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +source-map-resolve@^0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" + integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== + dependencies: + atob "^2.1.1" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= + +source-map@^0.5.6: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== + dependencies: + extend-shallow "^3.0.0" + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + string-width@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" @@ -871,6 +1459,41 @@ supports-hyperlinks@^1.0.1: has-flag "^2.0.0" supports-color "^5.0.0" +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +union-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" + integrity sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ= + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^0.4.3" + universal-user-agent@^2.0.0, universal-user-agent@^2.0.1: version "2.0.3" resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-2.0.3.tgz#9f6f09f9cc33de867bb720d84c08069b14937c6c" @@ -878,11 +1501,29 @@ universal-user-agent@^2.0.0, universal-user-agent@^2.0.1: dependencies: os-name "^3.0.0" +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= + url-template@^2.0.8: version "2.0.8" resolved "https://registry.yarnpkg.com/url-template/-/url-template-2.0.8.tgz#fc565a3cccbff7730c775f5641f9555791439f21" integrity sha1-/FZaPMy/93MMd19WQflVV5FDnyE= +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== + which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" diff --git a/package.json b/package.json index 34a6a9444ddfdf..3ea4fa788d51f8 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,8 @@ "flow-check-ios": "flow check", "flow-check-android": "flow check --flowconfig-name .flowconfig.android", "lint": "eslint .", + "lint-ci": "./scripts/circleci/analyze_code.sh && yarn shellcheck", + "shellcheck": "./scripts/circleci/analyze_scripts.sh", "clang-format": "clang-format -i --glob=*/**/*.{h,cpp,m,mm}", "format": "npm run prettier && npm run clang-format", "prettier": "prettier --write \"./**/*.{js,md,yml}\"", diff --git a/scripts/circleci/analyze_code.sh b/scripts/circleci/analyze_code.sh index ef55d484e91a46..fbf02e7668b2d8 100755 --- a/scripts/circleci/analyze_code.sh +++ b/scripts/circleci/analyze_code.sh @@ -4,9 +4,13 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -cat <(echo eslint; npm run lint --silent -- --format=json; echo flow; npm run flow --silent -- check --json) | node scripts/circleci/code-analysis-bot.js +GITHUB_OWNER=${CIRCLE_PROJECT_USERNAME:-facebook} +GITHUB_REPO=${CIRCLE_PROJECT_REPONAME:-react-native} +export GITHUB_OWNER +export GITHUB_REPO + +cat <(echo eslint; npm run lint --silent -- --format=json; echo flow; npm run flow-check-ios --silent --json; echo flow; npm run flow-check-android --silent --json) | GITHUB_PR_NUMBER="$CIRCLE_PR_NUMBER" node bots/code-analysis-bot.js -# check status STATUS=$? if [ $STATUS == 0 ]; then echo "Code analyzed successfully." diff --git a/scripts/circleci/analyze_scripts.sh b/scripts/circleci/analyze_scripts.sh index 052688cab9bafa..9fc17f61307530 100755 --- a/scripts/circleci/analyze_scripts.sh +++ b/scripts/circleci/analyze_scripts.sh @@ -4,16 +4,38 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -IFS=$'\n' +GITHUB_OWNER=${CIRCLE_PROJECT_USERNAME:-facebook} +GITHUB_REPO=${CIRCLE_PROJECT_REPONAME:-react-native} +export GITHUB_OWNER +export GITHUB_REPO -results=( "$(find . -type f -not -path "*node_modules*" -not -path "*third-party*" -name '*.sh' -exec sh -c 'shellcheck "$1" -f json' -- {} \;)" ) +if [ -x "$(command -v shellcheck)" ]; then + IFS=$'\n' -cat <(echo shellcheck; printf '%s\n' "${results[@]}" | jq .,[] | jq -s . | jq --compact-output --raw-output '[ (.[] | .[] | . ) ]') | node scripts/circleci/code-analysis-bot.js + if [ -n "$CIRCLE_CI" ]; then + results=( "$(find . -type f -not -path "*node_modules*" -not -path "*third-party*" -name '*.sh' -exec sh -c 'shellcheck "$1" -f json' -- {} \;)" ) + + cat <(echo shellcheck; printf '%s\n' "${results[@]}" | jq .,[] | jq -s . | jq --compact-output --raw-output '[ (.[] | .[] | . ) ]') | GITHUB_PR_NUMBER="$CIRCLE_PR_NUMBER" node scripts/circleci/code-analysis-bot.js + + # check status + STATUS=$? + if [ $STATUS == 0 ]; then + echo "Shell scripts analyzed successfully." + else + echo "Shell script analysis failed, error status $STATUS." + fi + + else + find . \ + -type f \ + -not -path "*node_modules*" \ + -not -path "*third-party*" \ + -name '*.sh' \ + -exec sh -c 'shellcheck "$1"' -- {} \; + fi -# check status -STATUS=$? -if [ $STATUS == 0 ]; then - echo "Shell scripts analyzed successfully." else - echo "Shell script analysis failed, error status $STATUS." + echo 'shellcheck is not installed. See https://github.com/facebook/react-native/wiki/Development-Dependencies#shellcheck for instructions.' + exit 1 fi + From 592e6c5e7de1c0df15d4773b1f86ad1a01946937 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 21 May 2019 23:09:12 -0700 Subject: [PATCH 0027/1084] Fabric: Restoring the original purpose of StateData class Summary: This diff restores the original role of StateData as a dummy class that has only one purpose - designate that there is no state associated with the node. I believe having an abstract StateData class for all data types is not necessary and actually slightly harmful. And here the reasons: * Having virtual dispatch enabled for classes introduces some overhead, and it should be used only if it is absolutely necessary. In this case, we don't need to have virtual dispatch enabled for Data classes because it's already enabled for State classes; therefore all virtual resolution is done there and that's sufficient. No need to pay for what we don't need. * Continuing the previous point, yes, we expect some API being exposed for Data classes (such as `getDynamic`), but introducing a base abstract class for that is *not* an idiomatic C++ solution; in C++ it's by design that most of the template contracts are actually duck-typed. This is a well-known design issue/concern that will be addressed with an effort called "Concepts" in C++20. Anyway, we should not use abstract classes as *only* indication of conformance to some interface. * StateData does not introduce any convenience. As it is clear from several subclass implementations, we don't really use base methods from it. * The previous issue actually happens especially because of the interface of StateData class. Consider constructor that accepts `folly::dynamic` and does nothing, it actually useless because it's impossible to use it unless it's called inside superclass's constructor. That's the case because C++ does not support virtual dispatch for constructors (for good). * Avoiding subclassing StateData counter-intuitively enforces the desired conformance to imaginary interface: it does not compile otherwise. Reviewed By: JoshuaGross Differential Revision: D15342338 fbshipit-source-id: 1f04f7fc5247499e7cfc09cd4b3cccffdc0b6b06 --- .../components/modal/ModalHostViewState.cpp | 7 +---- .../components/modal/ModalHostViewState.h | 10 ++++--- ReactCommon/fabric/core/state/StateData.cpp | 30 ------------------- ReactCommon/fabric/core/state/StateData.h | 19 ++++-------- 4 files changed, 13 insertions(+), 53 deletions(-) delete mode 100644 ReactCommon/fabric/core/state/StateData.cpp diff --git a/ReactCommon/fabric/components/modal/ModalHostViewState.cpp b/ReactCommon/fabric/components/modal/ModalHostViewState.cpp index be62de46a82710..ade5367cec9a68 100644 --- a/ReactCommon/fabric/components/modal/ModalHostViewState.cpp +++ b/ReactCommon/fabric/components/modal/ModalHostViewState.cpp @@ -6,17 +6,12 @@ */ #include "ModalHostViewState.h" -#include - -#ifdef ANDROID -#include -#endif namespace facebook { namespace react { #ifdef ANDROID -const folly::dynamic ModalHostViewState::getDynamic() const { +folly::dynamic ModalHostViewState::getDynamic() const { return folly::dynamic::object("screenWidth", screenSize.width)( "screenHeight", screenSize.height); } diff --git a/ReactCommon/fabric/components/modal/ModalHostViewState.h b/ReactCommon/fabric/components/modal/ModalHostViewState.h index 167ffa22d37231..102e52e01e9f29 100644 --- a/ReactCommon/fabric/components/modal/ModalHostViewState.h +++ b/ReactCommon/fabric/components/modal/ModalHostViewState.h @@ -7,24 +7,26 @@ #pragma once -#include #include #include #include +#ifdef ANDROID +#include +#endif + namespace facebook { namespace react { /* * State for component. */ -class ModalHostViewState : public StateData { +class ModalHostViewState final { public: using Shared = std::shared_ptr; ModalHostViewState(){}; ModalHostViewState(Size screenSize_) : screenSize(screenSize_){}; - virtual ~ModalHostViewState() = default; #ifdef ANDROID ModalHostViewState(folly::dynamic data) @@ -35,7 +37,7 @@ class ModalHostViewState : public StateData { const Size screenSize{}; #ifdef ANDROID - virtual const folly::dynamic getDynamic() const override; + folly::dynamic getDynamic() const; #endif #pragma mark - Getters diff --git a/ReactCommon/fabric/core/state/StateData.cpp b/ReactCommon/fabric/core/state/StateData.cpp deleted file mode 100644 index 44f2744e10d834..00000000000000 --- a/ReactCommon/fabric/core/state/StateData.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include "StateData.h" - -#ifdef ANDROID -#include -#endif - -namespace facebook { -namespace react { - -#ifdef ANDROID -StateData::~StateData() { - // This needs to be here or the linker will complain: - // https://gcc.gnu.org/wiki/VerboseDiagnostics#missing_vtable -} -const folly::dynamic StateData::getDynamic() const { - assert(false); // TODO: get rid of this? - return folly::dynamic::object(); -} - -#endif - -} // namespace react -} // namespace facebook diff --git a/ReactCommon/fabric/core/state/StateData.h b/ReactCommon/fabric/core/state/StateData.h index 32b026cfd18b34..e33ccb00d0ae58 100644 --- a/ReactCommon/fabric/core/state/StateData.h +++ b/ReactCommon/fabric/core/state/StateData.h @@ -17,23 +17,16 @@ namespace facebook { namespace react { /* - * Base class for state data. - * Must be used to provide getDynamic for Android. + * Dummy type that is used as a placeholder for state data for nodes that + * don't have a state. */ -class StateData { - public: +struct StateData final { using Shared = std::shared_ptr; - StateData() {} - #ifdef ANDROID - StateData(folly::dynamic data) {} - - // Destructor must either be virtual or protected if we have any - // virtual methods - virtual ~StateData(); - - virtual const folly::dynamic getDynamic() const; + StateData() = default; + StateData(folly::dynamic data){}; + folly::dynamic getDynamic() const; #endif }; From 6671165f69e37a49af8b709b4807f9049f7606c3 Mon Sep 17 00:00:00 2001 From: Tom Underhill Date: Tue, 21 May 2019 23:17:49 -0700 Subject: [PATCH 0028/1084] RNTesterIntegrationTests can fail due to the warning "Can't call setState (or forceUpdate) on an unmounted component." (#24984) Summary: When running the RNTesterIntegrationTests from the XCode IDE or xcodebuild command line, its possible for tests to intermittently fail due to the warning `'Warning: Can\'t call setState (or forceUpdate) on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.%s', '\n in RNTesterApp.` . A setState() call could happen in the AsyncStorage callback after the component had unmounted: presumably because the test ran and concluded before AsyncStorage returned. Changed RNTesterApp.ios.js to maintain a _mounted field that is set and cleared in componentDidMount() and componentWillUnmount() and refrain from calling setState() if the flag is false. ## Changelog [iOS] [Fixed] - Fixed RNTesterApp to not call setState() after the component has been unmounted. Pull Request resolved: https://github.com/facebook/react-native/pull/24984 Differential Revision: D15447898 Pulled By: hramos fbshipit-source-id: b01bc0a40a4f4d548aca0a4bb891ba3f4c8d0612 --- RNTester/js/RNTesterApp.ios.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/RNTester/js/RNTesterApp.ios.js b/RNTester/js/RNTesterApp.ios.js index e13178d024e797..411e352bd23d06 100644 --- a/RNTester/js/RNTesterApp.ios.js +++ b/RNTester/js/RNTesterApp.ios.js @@ -61,13 +61,19 @@ const Header = ({onBack, title}: {onBack?: () => mixed, title: string}) => ( ); class RNTesterApp extends React.Component { + _mounted: boolean; + UNSAFE_componentWillMount() { BackHandler.addEventListener('hardwareBackPress', this._handleBack); } componentDidMount() { + this._mounted = true; Linking.getInitialURL().then(url => { AsyncStorage.getItem(APP_STATE_KEY, (err, storedString) => { + if (!this._mounted) { + return; + } const exampleAction = URIActionMap( this.props.exampleFromAppetizeParams, ); @@ -83,6 +89,10 @@ class RNTesterApp extends React.Component { }); } + componentWillUnmount() { + this._mounted = false; + } + _handleBack = () => { this._handleAction(RNTesterActions.Back()); }; From 781c68cb43a5e4bb2a3a7e5053b673de6484a9d3 Mon Sep 17 00:00:00 2001 From: Jean Regisser Date: Wed, 22 May 2019 03:18:24 -0700 Subject: [PATCH 0029/1084] Add spec for TVNavigationEventEmitter (#24898) Summary: Part of #24875 ## Changelog [General] [Added] - Add TurboModule spec for TVNavigationEventEmitter Pull Request resolved: https://github.com/facebook/react-native/pull/24898 Reviewed By: fkgozali Differential Revision: D15391716 Pulled By: rickhanlonii fbshipit-source-id: 015120c755894a5c8f75a99c2670a6ac5545b454 --- .../AppleTV/NativeTVNavigationEventEmitter.js | 21 +++++++++++++++++++ .../Components/AppleTV/TVEventHandler.js | 8 +++---- 2 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 Libraries/Components/AppleTV/NativeTVNavigationEventEmitter.js diff --git a/Libraries/Components/AppleTV/NativeTVNavigationEventEmitter.js b/Libraries/Components/AppleTV/NativeTVNavigationEventEmitter.js new file mode 100644 index 00000000000000..4870931e0dc607 --- /dev/null +++ b/Libraries/Components/AppleTV/NativeTVNavigationEventEmitter.js @@ -0,0 +1,21 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +addListener: (eventName: string) => void; + +removeListeners: (count: number) => void; +} + +export default TurboModuleRegistry.get('TVNavigationEventEmitter'); diff --git a/Libraries/Components/AppleTV/TVEventHandler.js b/Libraries/Components/AppleTV/TVEventHandler.js index debaa0f3418a03..852038ba12f57a 100644 --- a/Libraries/Components/AppleTV/TVEventHandler.js +++ b/Libraries/Components/AppleTV/TVEventHandler.js @@ -11,10 +11,10 @@ 'use strict'; const Platform = require('../../Utilities/Platform'); -const TVNavigationEventEmitter = require('../../BatchedBridge/NativeModules') - .TVNavigationEventEmitter; const NativeEventEmitter = require('../../EventEmitter/NativeEventEmitter'); +import NativeTVNavigationEventEmitter from './NativeTVNavigationEventEmitter'; + function TVEventHandler() { this.__nativeTVNavigationEventListener = null; this.__nativeTVNavigationEventEmitter = null; @@ -24,12 +24,12 @@ TVEventHandler.prototype.enable = function( component: ?any, callback: Function, ) { - if (Platform.OS === 'ios' && !TVNavigationEventEmitter) { + if (Platform.OS === 'ios' && !NativeTVNavigationEventEmitter) { return; } this.__nativeTVNavigationEventEmitter = new NativeEventEmitter( - TVNavigationEventEmitter, + NativeTVNavigationEventEmitter, ); this.__nativeTVNavigationEventListener = this.__nativeTVNavigationEventEmitter.addListener( 'onHWKeyEvent', From 0e7a2ca54e623bcaed6999e973ca148e4b30d51c Mon Sep 17 00:00:00 2001 From: Eric Lewis Date: Wed, 22 May 2019 03:18:24 -0700 Subject: [PATCH 0030/1084] add spec for FileReaderModule (#24904) Summary: Part of #24875. ## Changelog [General] [Added] - add TM spec for FileReaderModule Pull Request resolved: https://github.com/facebook/react-native/pull/24904 Reviewed By: fkgozali Differential Revision: D15391738 Pulled By: rickhanlonii fbshipit-source-id: 69e6ff53aba2d2227607905e1f70310bdd01d224 --- Libraries/Blob/FileReader.js | 6 +++--- Libraries/Blob/NativeFileReaderModule.js | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 Libraries/Blob/NativeFileReaderModule.js diff --git a/Libraries/Blob/FileReader.js b/Libraries/Blob/FileReader.js index 7d8116fce9c37c..b9113966f1a9fb 100644 --- a/Libraries/Blob/FileReader.js +++ b/Libraries/Blob/FileReader.js @@ -12,7 +12,7 @@ const EventTarget = require('event-target-shim'); const Blob = require('./Blob'); -const {FileReaderModule} = require('../BatchedBridge/NativeModules'); +import NativeFileReaderModule from './NativeFileReaderModule'; type ReadyState = | 0 // EMPTY @@ -87,7 +87,7 @@ class FileReader extends EventTarget(...READER_EVENTS) { readAsDataURL(blob: Blob) { this._aborted = false; - FileReaderModule.readAsDataURL(blob.data).then( + NativeFileReaderModule.readAsDataURL(blob.data).then( (text: string) => { if (this._aborted) { return; @@ -108,7 +108,7 @@ class FileReader extends EventTarget(...READER_EVENTS) { readAsText(blob: Blob, encoding: string = 'UTF-8') { this._aborted = false; - FileReaderModule.readAsText(blob.data, encoding).then( + NativeFileReaderModule.readAsText(blob.data, encoding).then( (text: string) => { if (this._aborted) { return; diff --git a/Libraries/Blob/NativeFileReaderModule.js b/Libraries/Blob/NativeFileReaderModule.js new file mode 100644 index 00000000000000..b784d8c6f8253f --- /dev/null +++ b/Libraries/Blob/NativeFileReaderModule.js @@ -0,0 +1,21 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +readAsDataURL: (data: Object) => Promise; + +readAsText: (data: Object, encoding: string) => Promise; +} + +export default TurboModuleRegistry.getEnforcing('FileReaderModule'); From 163fb087921dd997145bb02d6999d8f94f82a3eb Mon Sep 17 00:00:00 2001 From: Jean Regisser Date: Wed, 22 May 2019 03:18:24 -0700 Subject: [PATCH 0031/1084] Add spec for SourceCode (#24901) Summary: Part of #24875 ## Changelog [General] [Added] - Add TurboModule spec for SourceCode Pull Request resolved: https://github.com/facebook/react-native/pull/24901 Reviewed By: fkgozali Differential Revision: D15391727 Pulled By: rickhanlonii fbshipit-source-id: 9d4622d809efdc3955d435c5a51b72c38cedccc5 --- Libraries/Core/Devtools/getDevServer.js | 9 +++--- .../Core/Devtools/symbolicateStackTrace.js | 7 ++-- .../__tests__/resolveAssetSource-test.js | 32 ++++++++++++------- Libraries/Image/resolveAssetSource.js | 5 ++- .../NativeModules/specs/NativeSourceCode.js | 22 +++++++++++++ jest/setup.js | 6 +++- 6 files changed, 57 insertions(+), 24 deletions(-) create mode 100644 Libraries/NativeModules/specs/NativeSourceCode.js diff --git a/Libraries/Core/Devtools/getDevServer.js b/Libraries/Core/Devtools/getDevServer.js index 1de83592dc3b43..845640847c8d29 100644 --- a/Libraries/Core/Devtools/getDevServer.js +++ b/Libraries/Core/Devtools/getDevServer.js @@ -10,7 +10,7 @@ 'use strict'; -const {SourceCode} = require('../../BatchedBridge/NativeModules'); +import NativeSourceCode from '../../NativeModules/specs/NativeSourceCode'; let _cachedDevServerURL: ?string; const FALLBACK = 'http://localhost:8081/'; @@ -26,10 +26,9 @@ type DevServerInfo = { */ function getDevServer(): DevServerInfo { if (_cachedDevServerURL === undefined) { - const match = - SourceCode && - SourceCode.scriptURL && - SourceCode.scriptURL.match(/^https?:\/\/.*?\//); + const match = NativeSourceCode.getConstants().scriptURL.match( + /^https?:\/\/.*?\//, + ); _cachedDevServerURL = match ? match[0] : null; } diff --git a/Libraries/Core/Devtools/symbolicateStackTrace.js b/Libraries/Core/Devtools/symbolicateStackTrace.js index f7cc031e300787..32e209ef78f59c 100644 --- a/Libraries/Core/Devtools/symbolicateStackTrace.js +++ b/Libraries/Core/Devtools/symbolicateStackTrace.js @@ -12,7 +12,7 @@ const getDevServer = require('./getDevServer'); -const {SourceCode} = require('../../BatchedBridge/NativeModules'); +import NativeSourceCode from '../../NativeModules/specs/NativeSourceCode'; // Avoid requiring fetch on load of this module; see symbolicateStackTrace let fetch; @@ -48,7 +48,8 @@ async function symbolicateStackTrace( let stackCopy = stack; - if (SourceCode.scriptURL) { + const {scriptURL} = NativeSourceCode.getConstants(); + if (scriptURL) { let foundInternalSource: boolean = false; stackCopy = stack.map((frame: StackFrame) => { // If the sources exist on disk rather than appearing to come from the packager, @@ -57,7 +58,7 @@ async function symbolicateStackTrace( // the application to a surrounding debugging environment. if (!foundInternalSource && isSourcedFromDisk(frame.file)) { // Copy frame into new object and replace 'file' property - return {...frame, file: SourceCode.scriptURL}; + return {...frame, file: scriptURL}; } foundInternalSource = true; diff --git a/Libraries/Image/__tests__/resolveAssetSource-test.js b/Libraries/Image/__tests__/resolveAssetSource-test.js index c5afbdf8705587..195a5be549eda2 100644 --- a/Libraries/Image/__tests__/resolveAssetSource-test.js +++ b/Libraries/Image/__tests__/resolveAssetSource-test.js @@ -12,9 +12,10 @@ const AssetRegistry = require('../AssetRegistry'); const Platform = require('../../Utilities/Platform'); -const NativeModules = require('../../BatchedBridge/NativeModules'); const resolveAssetSource = require('../resolveAssetSource'); +import NativeSourceCode from '../../NativeModules/specs/NativeSourceCode'; + function expectResolvesAsset(input, expectedSource) { const assetId = AssetRegistry.registerAsset(input); expect(resolveAssetSource(assetId)).toEqual(expectedSource); @@ -57,7 +58,9 @@ describe('resolveAssetSource', () => { describe('bundle was loaded from network (DEV)', () => { beforeEach(() => { - NativeModules.SourceCode.scriptURL = 'http://10.0.0.1:8081/main.bundle'; + NativeSourceCode.getConstants = () => ({ + scriptURL: 'http://10.0.0.1:8081/main.bundle', + }); Platform.OS = 'ios'; }); @@ -112,8 +115,9 @@ describe('resolveAssetSource', () => { describe('bundle was loaded from file on iOS', () => { beforeEach(() => { - NativeModules.SourceCode.scriptURL = - 'file:///Path/To/Sample.app/main.bundle'; + NativeSourceCode.getConstants = () => ({ + scriptURL: 'file:///Path/To/Sample.app/main.bundle', + }); Platform.OS = 'ios'; }); @@ -143,8 +147,9 @@ describe('resolveAssetSource', () => { describe('bundle was loaded from assets on Android', () => { beforeEach(() => { - NativeModules.SourceCode.scriptURL = - 'assets://Path/To/Simulator/main.bundle'; + NativeSourceCode.getConstants = () => ({ + scriptURL: 'assets://Path/To/Simulator/main.bundle', + }); Platform.OS = 'android'; }); @@ -174,8 +179,9 @@ describe('resolveAssetSource', () => { describe('bundle was loaded from file on Android', () => { beforeEach(() => { - NativeModules.SourceCode.scriptURL = - 'file:///sdcard/Path/To/Simulator/main.bundle'; + NativeSourceCode.getConstants = () => ({ + scriptURL: 'file:///sdcard/Path/To/Simulator/main.bundle', + }); Platform.OS = 'android'; }); @@ -206,8 +212,9 @@ describe('resolveAssetSource', () => { describe('bundle was loaded from raw file on Android', () => { beforeEach(() => { - NativeModules.SourceCode.scriptURL = - '/sdcard/Path/To/Simulator/main.bundle'; + NativeSourceCode.getConstants = () => ({ + scriptURL: '/sdcard/Path/To/Simulator/main.bundle', + }); Platform.OS = 'android'; }); @@ -238,8 +245,9 @@ describe('resolveAssetSource', () => { describe('source resolver can be customized', () => { beforeEach(() => { - NativeModules.SourceCode.scriptURL = - 'file:///sdcard/Path/To/Simulator/main.bundle'; + NativeSourceCode.getConstants = () => ({ + scriptURL: 'file:///sdcard/Path/To/Simulator/main.bundle', + }); Platform.OS = 'android'; }); diff --git a/Libraries/Image/resolveAssetSource.js b/Libraries/Image/resolveAssetSource.js index dd9167af53e086..7d256832fca144 100644 --- a/Libraries/Image/resolveAssetSource.js +++ b/Libraries/Image/resolveAssetSource.js @@ -29,10 +29,9 @@ function getSourceCodeScriptURL(): ?string { let sourceCode = global.nativeExtensions && global.nativeExtensions.SourceCode; if (!sourceCode) { - const NativeModules = require('../BatchedBridge/NativeModules'); - sourceCode = NativeModules && NativeModules.SourceCode; + sourceCode = require('../NativeModules/specs/NativeSourceCode').default; } - _sourceCodeScriptURL = sourceCode.scriptURL; + _sourceCodeScriptURL = sourceCode.getConstants().scriptURL; return _sourceCodeScriptURL; } diff --git a/Libraries/NativeModules/specs/NativeSourceCode.js b/Libraries/NativeModules/specs/NativeSourceCode.js new file mode 100644 index 00000000000000..3db328618ef2ca --- /dev/null +++ b/Libraries/NativeModules/specs/NativeSourceCode.js @@ -0,0 +1,22 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +getConstants: () => {| + scriptURL: string, + |}; +} + +export default TurboModuleRegistry.getEnforcing('SourceCode'); diff --git a/jest/setup.js b/jest/setup.js index 7328ed18dd622d..b59e3604efc7ec 100644 --- a/jest/setup.js +++ b/jest/setup.js @@ -259,7 +259,11 @@ const mockNativeModules = { removeListeners: jest.fn(), }, SourceCode: { - scriptURL: null, + getConstants() { + return { + scriptURL: null, + }; + }, }, StatusBarManager: { HEIGHT: 42, From d7a5e3e215eedb7377a86f172e0619403e20c2b8 Mon Sep 17 00:00:00 2001 From: Eric Lewis Date: Wed, 22 May 2019 03:18:24 -0700 Subject: [PATCH 0032/1084] add spec for JSDevSupport (#24905) Summary: Part of #24875. ## Changelog [General] [Added] - add TM spec for JSDevSupport Pull Request resolved: https://github.com/facebook/react-native/pull/24905 Reviewed By: fkgozali Differential Revision: D15391754 Pulled By: rickhanlonii fbshipit-source-id: afca6ce3d6bcfaaf097e13c148496cdd1f062465 --- Libraries/Utilities/JSDevSupportModule.js | 33 ++++++++++++----------- Libraries/Utilities/NativeJSDevSupport.js | 25 +++++++++++++++++ 2 files changed, 43 insertions(+), 15 deletions(-) create mode 100644 Libraries/Utilities/NativeJSDevSupport.js diff --git a/Libraries/Utilities/JSDevSupportModule.js b/Libraries/Utilities/JSDevSupportModule.js index c609faf91a766f..9e6d60dce01fa9 100644 --- a/Libraries/Utilities/JSDevSupportModule.js +++ b/Libraries/Utilities/JSDevSupportModule.js @@ -10,26 +10,29 @@ 'use strict'; -const JSDevSupport = require('../BatchedBridge/NativeModules').JSDevSupport; +import NativeJSDevSupport from './NativeJSDevSupport'; const ReactNative = require('../Renderer/shims/ReactNative'); const JSDevSupportModule = { getJSHierarchy: function(tag: number) { - try { - const { - computeComponentStackForErrorReporting, - } = ReactNative.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; - const componentStack = computeComponentStackForErrorReporting(tag); - if (!componentStack) { - JSDevSupport.onFailure( - JSDevSupport.ERROR_CODE_VIEW_NOT_FOUND, - "Component stack doesn't exist for tag " + tag, - ); - } else { - JSDevSupport.onSuccess(componentStack); + if (NativeJSDevSupport) { + const constants = NativeJSDevSupport.getConstants(); + try { + const { + computeComponentStackForErrorReporting, + } = ReactNative.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; + const componentStack = computeComponentStackForErrorReporting(tag); + if (!componentStack) { + NativeJSDevSupport.onFailure( + constants.ERROR_CODE_VIEW_NOT_FOUND, + "Component stack doesn't exist for tag " + tag, + ); + } else { + NativeJSDevSupport.onSuccess(componentStack); + } + } catch (e) { + NativeJSDevSupport.onFailure(constants.ERROR_CODE_EXCEPTION, e.message); } - } catch (e) { - JSDevSupport.onFailure(JSDevSupport.ERROR_CODE_EXCEPTION, e.message); } }, }; diff --git a/Libraries/Utilities/NativeJSDevSupport.js b/Libraries/Utilities/NativeJSDevSupport.js new file mode 100644 index 00000000000000..ae7217be760d97 --- /dev/null +++ b/Libraries/Utilities/NativeJSDevSupport.js @@ -0,0 +1,25 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +getConstants: () => {| + ERROR_CODE_EXCEPTION: number, + ERROR_CODE_VIEW_NOT_FOUND: number, + |}; + +onSuccess: (data: Object) => void; + +onFailure: (errorCode: number, error: string) => void; +} + +export default TurboModuleRegistry.get('JSDevSupport'); From de33b8a237f69511eee02246decb598b00ddf00f Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Wed, 22 May 2019 05:33:12 -0700 Subject: [PATCH 0033/1084] Generate events with no arguments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: This diff allows generating native events without any arguments with an event like: ``` { name: 'onEnd', optional: true, bubblingType: 'bubble', typeAnnotation: { type: 'EventTypeAnnotation', // note: no argument key }, }, ``` See the snapshot updates in the diff for the native code that will be generated � Reviewed By: shergin Differential Revision: D15403791 fbshipit-source-id: 925a49bb477eebb234e181df681f0d6b1d4e8cf1 --- .../react-native-codegen/src/CodegenSchema.js | 2 +- .../src/generators/GenerateEventEmitterCpp.js | 47 ++++++++++++------- .../src/generators/GenerateEventEmitterH.js | 22 +++++---- .../generators/__test_fixtures__/fixtures.js | 8 ++++ .../GenerateEventEmitterCpp-test.js.snap | 3 ++ .../GenerateEventEmitterH-test.js.snap | 2 + .../GenerateViewConfigJs-test.js.snap | 8 ++++ 7 files changed, 66 insertions(+), 26 deletions(-) diff --git a/packages/react-native-codegen/src/CodegenSchema.js b/packages/react-native-codegen/src/CodegenSchema.js index 1ab45de9789ea3..8d3aec5dc6bfc6 100644 --- a/packages/react-native-codegen/src/CodegenSchema.js +++ b/packages/react-native-codegen/src/CodegenSchema.js @@ -83,7 +83,7 @@ export type EventTypeShape = $ReadOnly<{| optional: boolean, typeAnnotation: $ReadOnly<{| type: 'EventTypeAnnotation', - argument: $ReadOnly<{| + argument?: $ReadOnly<{| type: 'ObjectTypeAnnotation', properties: $ReadOnlyArray, |}>, diff --git a/packages/react-native-codegen/src/generators/GenerateEventEmitterCpp.js b/packages/react-native-codegen/src/generators/GenerateEventEmitterCpp.js index ccd3a1f0c52663..c6820ddc502707 100644 --- a/packages/react-native-codegen/src/generators/GenerateEventEmitterCpp.js +++ b/packages/react-native-codegen/src/generators/GenerateEventEmitterCpp.js @@ -55,6 +55,12 @@ void ::_CLASSNAME_::EventEmitter::::_EVENT_NAME_::(::_STRUCT_NAME_:: event) cons } `.trim(); +const basicComponentTemplate = ` +void ::_CLASSNAME_::EventEmitter::::_EVENT_NAME_::() const { + dispatchEvent("::_DISPATCH_EVENT_NAME_::"); +} +`.trim(); + function generateSetter(variableName, propertyName, propertyParts) { const trailingPeriod = propertyParts.length === 0 ? '' : '.'; const eventChain = `event.${propertyParts.join( @@ -106,16 +112,6 @@ function generateSetters( } function generateEvent(componentName: string, event): string { - const implementation = ` - auto payload = jsi::Object(runtime); - ${generateSetters('payload', event.typeAnnotation.argument.properties, [])} - return payload; - `.trim(); - - if (!event.name.startsWith('on')) { - throw new Error('Expected the event name to start with `on`'); - } - // This is a gross hack necessary because native code is sending // events named things like topChange to JS which is then converted back to // call the onChange prop. We should be consistent throughout the system. @@ -126,15 +122,32 @@ function generateEvent(componentName: string, event): string { 3, )}`; - return componentTemplate + if (event.typeAnnotation.argument) { + const implementation = ` + auto payload = jsi::Object(runtime); + ${generateSetters('payload', event.typeAnnotation.argument.properties, [])} + return payload; + `.trim(); + + if (!event.name.startsWith('on')) { + throw new Error('Expected the event name to start with `on`'); + } + + return componentTemplate + .replace(/::_CLASSNAME_::/g, componentName) + .replace(/::_EVENT_NAME_::/g, event.name) + .replace(/::_DISPATCH_EVENT_NAME_::/g, dispatchEventName) + .replace( + '::_STRUCT_NAME_::', + generateStructName(componentName, [event.name]), + ) + .replace('::_IMPLEMENTATION_::', implementation); + } + + return basicComponentTemplate .replace(/::_CLASSNAME_::/g, componentName) .replace(/::_EVENT_NAME_::/g, event.name) - .replace(/::_DISPATCH_EVENT_NAME_::/g, dispatchEventName) - .replace( - '::_STRUCT_NAME_::', - generateStructName(componentName, [event.name]), - ) - .replace('::_IMPLEMENTATION_::', implementation); + .replace(/::_DISPATCH_EVENT_NAME_::/g, dispatchEventName); } module.exports = { diff --git a/packages/react-native-codegen/src/generators/GenerateEventEmitterH.js b/packages/react-native-codegen/src/generators/GenerateEventEmitterH.js index 2b4909837a9825..075f124c25e068 100644 --- a/packages/react-native-codegen/src/generators/GenerateEventEmitterH.js +++ b/packages/react-native-codegen/src/generators/GenerateEventEmitterH.js @@ -146,21 +146,27 @@ function generateStructs(componentName: string, component): string { const structs: StructsMap = new Map(); component.events.forEach(event => { - generateStruct( - structs, - componentName, - [event.name], - event.typeAnnotation.argument.properties, - ); + if (event.typeAnnotation.argument) { + generateStruct( + structs, + componentName, + [event.name], + event.typeAnnotation.argument.properties, + ); + } }); return Array.from(structs.values()).join('\n\n'); } function generateEvent(componentName: string, event: EventTypeShape): string { - const structName = generateStructName(componentName, [event.name]); + if (event.typeAnnotation.argument) { + const structName = generateStructName(componentName, [event.name]); + + return `void ${event.name}(${structName} value) const;`; + } - return `void ${event.name}(${structName} value) const;`; + return `void ${event.name}() const;`; } function generateEvents(componentName: string, component): string { return component.events diff --git a/packages/react-native-codegen/src/generators/__test_fixtures__/fixtures.js b/packages/react-native-codegen/src/generators/__test_fixtures__/fixtures.js index 4bb696833cfb58..8e95a41bede781 100644 --- a/packages/react-native-codegen/src/generators/__test_fixtures__/fixtures.js +++ b/packages/react-native-codegen/src/generators/__test_fixtures__/fixtures.js @@ -560,6 +560,14 @@ const EVENT_PROPS: SchemaType = { }, }, }, + { + name: 'onEnd', + optional: true, + bubblingType: 'bubble', + typeAnnotation: { + type: 'EventTypeAnnotation', + }, + }, ], props: [ { diff --git a/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateEventEmitterCpp-test.js.snap b/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateEventEmitterCpp-test.js.snap index 41ed47758c43aa..25846b02b5d46e 100644 --- a/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateEventEmitterCpp-test.js.snap +++ b/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateEventEmitterCpp-test.js.snap @@ -165,6 +165,9 @@ void EventsNativeComponentEventEmitter::onEventDirect(EventsNativeComponentOnEve return payload; }); } +void EventsNativeComponentEventEmitter::onEnd() const { + dispatchEvent(\\"end\\"); +} } // namespace react } // namespace facebook diff --git a/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateEventEmitterH-test.js.snap b/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateEventEmitterH-test.js.snap index bf3c4da2b95e17..bff692ada2630a 100644 --- a/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateEventEmitterH-test.js.snap +++ b/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateEventEmitterH-test.js.snap @@ -173,6 +173,8 @@ class EventsNativeComponentEventEmitter : public ViewEventEmitter { void onChange(EventsNativeComponentOnChangeStruct value) const; void onEventDirect(EventsNativeComponentOnEventDirectStruct value) const; + + void onEnd() const; }; } // namespace react diff --git a/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap b/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap index 86933768e59360..8e7ec6e5fb590e 100644 --- a/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap +++ b/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap @@ -285,6 +285,13 @@ const EventsNativeComponentViewConfig = { bubbled: 'onChange', }, }, + + topEnd: { + phasedRegistrationNames: { + captured: 'onEndCapture', + bubbled: 'onEnd', + }, + }, }, directEventTypes: { @@ -300,6 +307,7 @@ const EventsNativeComponentViewConfig = { disabled: true, onChange: true, onEventDirect: true, + onEnd: true, }, }; From cea0a2b61ae9bec5ceff697d8173d34cad438216 Mon Sep 17 00:00:00 2001 From: nossbigg Date: Wed, 22 May 2019 05:33:22 -0700 Subject: [PATCH 0034/1084] Set duration=0 for android keyboard events (#24994) Summary: Set duration=0 for android keyboard events. Brings actual implementation closer to existing flowtypes, and duration is set to 0 to minimize impact on existing keyboard event consumers. Follow up to #24947, upon cpojer's [input](https://github.com/facebook/react-native/pull/24947#issuecomment-494681618) :) ## Changelog [Android] [Added] - Set duration=0 for android keyboard events Pull Request resolved: https://github.com/facebook/react-native/pull/24994 Differential Revision: D15449394 Pulled By: cpojer fbshipit-source-id: d43096238bd38d189fbec54fc2d93f17010d9ddb --- Libraries/Components/Keyboard/Keyboard.js | 1 + ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java | 1 + 2 files changed, 2 insertions(+) diff --git a/Libraries/Components/Keyboard/Keyboard.js b/Libraries/Components/Keyboard/Keyboard.js index a7970fc8ed0aed..d4e99f51d8fafe 100644 --- a/Libraries/Components/Keyboard/Keyboard.js +++ b/Libraries/Components/Keyboard/Keyboard.js @@ -50,6 +50,7 @@ type BaseKeyboardEvent = {| export type AndroidKeyboardEvent = $ReadOnly<{| ...BaseKeyboardEvent, + duration: 0, easing: 'keyboard', |}>; diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java index 42d2c757ef2960..37341ca9242422 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java @@ -770,6 +770,7 @@ private WritableMap createKeyboardEventPayload(double screenY, double screenX, d keyboardEventParams.putMap("endCoordinates", endCoordinates); keyboardEventParams.putString("easing", "keyboard"); + keyboardEventParams.putDouble("duration", 0); return keyboardEventParams; } } From 9e97f71579238d10540a4ed1035ab5f9f9c19235 Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Wed, 22 May 2019 05:56:42 -0700 Subject: [PATCH 0035/1084] Organize files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: This diff reorganizes some of the code in react-native-codegen as requested in T44120025 There are two new dirs: `scr/cli` and `src/parsers` ``` buck_tests/ src/ cli/ generators/ parsers/ ``` We moved anything cli-ish from `buck_tests` to the `src/cli` directory: ``` src/ cli/ combine/ combine_js_to_schema.sh combine_js_to_schema-cli.js combine_js_to_schema.js viewconfigs/ generate-view-configs-cli.js generate-view-configs.js generate-view-configs.sh ``` And we created a new `src/parsers` directory that will contain the flow parser and the current schema parser: ``` src/ parsers/ flow/ index.js schema/ index.js ``` This should organize the code a little better and make it easier to contribute 👍 Reviewed By: cpojer Differential Revision: D15414264 fbshipit-source-id: 376af2e91def033855f6ed72a9a9cc4369c33c7d --- packages/react-native-codegen/BUCK | 8 +++---- .../{generate_tests.sh => generate-tests.sh} | 0 .../combine-js-to-schema-test.js.snap | 0 .../__tests__/combine-js-to-schema-test.js | 0 .../cli/combine}/combine-js-to-schema-cli.js | 0 .../cli/combine}/combine-js-to-schema.js | 6 +++--- .../cli/combine}/combine_js_to_schema.sh | 2 +- .../viewconfigs}/generate-view-configs-cli.js | 0 .../cli/viewconfigs}/generate-view-configs.js | 6 +++--- .../cli/viewconfigs}/generate-view-configs.sh | 2 +- .../src/parsers/flow/index.js | 21 +++++++++++++++++++ .../RNParser.js => parsers/schema/index.js} | 2 +- scripts/generate-rncore.sh | 2 +- 13 files changed, 35 insertions(+), 14 deletions(-) rename packages/react-native-codegen/buck_tests/{generate_tests.sh => generate-tests.sh} (100%) rename packages/react-native-codegen/{buck_tests => src/cli/combine}/__tests__/__snapshots__/combine-js-to-schema-test.js.snap (100%) rename packages/react-native-codegen/{buck_tests => src/cli/combine}/__tests__/combine-js-to-schema-test.js (100%) rename packages/react-native-codegen/{buck_tests => src/cli/combine}/combine-js-to-schema-cli.js (100%) rename packages/react-native-codegen/{buck_tests => src/cli/combine}/combine-js-to-schema.js (76%) rename packages/react-native-codegen/{buck_tests => src/cli/combine}/combine_js_to_schema.sh (79%) rename packages/react-native-codegen/{buck_tests => src/cli/viewconfigs}/generate-view-configs-cli.js (100%) rename packages/react-native-codegen/{buck_tests => src/cli/viewconfigs}/generate-view-configs.js (90%) rename packages/react-native-codegen/{buck_tests => src/cli/viewconfigs}/generate-view-configs.sh (84%) create mode 100644 packages/react-native-codegen/src/parsers/flow/index.js rename packages/react-native-codegen/src/{generators/RNParser.js => parsers/schema/index.js} (88%) diff --git a/packages/react-native-codegen/BUCK b/packages/react-native-codegen/BUCK index f305b43e744ba5..8cd540b1244cdb 100644 --- a/packages/react-native-codegen/BUCK +++ b/packages/react-native-codegen/BUCK @@ -17,18 +17,18 @@ fb_native.sh_binary( fb_native.sh_binary( name = "write_to_json", - main = "buck_tests/combine_js_to_schema.sh", + main = "src/cli/combine/combine_js_to_schema.sh", resources = [ - "buck_tests/combine-js-to-schema.js", - "buck_tests/combine_js_to_schema.sh", "fbsource//xplat/js:setup_env", + "src/cli/combine/combine-js-to-schema.js", + "src/cli/combine/combine_js_to_schema.sh", ], visibility = ["PUBLIC"], ) fb_native.sh_binary( name = "rn_codegen", - main = "buck_tests/generate_tests.sh", + main = "buck_tests/generate-tests.sh", resources = glob( [ "buck_tests/**/*.js", diff --git a/packages/react-native-codegen/buck_tests/generate_tests.sh b/packages/react-native-codegen/buck_tests/generate-tests.sh similarity index 100% rename from packages/react-native-codegen/buck_tests/generate_tests.sh rename to packages/react-native-codegen/buck_tests/generate-tests.sh diff --git a/packages/react-native-codegen/buck_tests/__tests__/__snapshots__/combine-js-to-schema-test.js.snap b/packages/react-native-codegen/src/cli/combine/__tests__/__snapshots__/combine-js-to-schema-test.js.snap similarity index 100% rename from packages/react-native-codegen/buck_tests/__tests__/__snapshots__/combine-js-to-schema-test.js.snap rename to packages/react-native-codegen/src/cli/combine/__tests__/__snapshots__/combine-js-to-schema-test.js.snap diff --git a/packages/react-native-codegen/buck_tests/__tests__/combine-js-to-schema-test.js b/packages/react-native-codegen/src/cli/combine/__tests__/combine-js-to-schema-test.js similarity index 100% rename from packages/react-native-codegen/buck_tests/__tests__/combine-js-to-schema-test.js rename to packages/react-native-codegen/src/cli/combine/__tests__/combine-js-to-schema-test.js diff --git a/packages/react-native-codegen/buck_tests/combine-js-to-schema-cli.js b/packages/react-native-codegen/src/cli/combine/combine-js-to-schema-cli.js similarity index 100% rename from packages/react-native-codegen/buck_tests/combine-js-to-schema-cli.js rename to packages/react-native-codegen/src/cli/combine/combine-js-to-schema-cli.js diff --git a/packages/react-native-codegen/buck_tests/combine-js-to-schema.js b/packages/react-native-codegen/src/cli/combine/combine-js-to-schema.js similarity index 76% rename from packages/react-native-codegen/buck_tests/combine-js-to-schema.js rename to packages/react-native-codegen/src/cli/combine/combine-js-to-schema.js index 5855fd520dead2..f1815bf727201e 100644 --- a/packages/react-native-codegen/buck_tests/combine-js-to-schema.js +++ b/packages/react-native-codegen/src/cli/combine/combine-js-to-schema.js @@ -9,14 +9,14 @@ */ 'use strict'; -import type {SchemaType} from '../src/CodegenSchema.js'; +import type {SchemaType} from '../../CodegenSchema.js'; -const RNParser = require('../src/generators/RNParser.js'); +const SchemaParser = require('../../parsers/schema'); function combineSchemas(files: Array): SchemaType { return files.reduce( (merged, filename) => { - const schema = RNParser.parse(filename); + const schema = SchemaParser.parse(filename); if (schema && schema.modules) { merged.modules = {...merged.modules, ...schema.modules}; } diff --git a/packages/react-native-codegen/buck_tests/combine_js_to_schema.sh b/packages/react-native-codegen/src/cli/combine/combine_js_to_schema.sh similarity index 79% rename from packages/react-native-codegen/buck_tests/combine_js_to_schema.sh rename to packages/react-native-codegen/src/cli/combine/combine_js_to_schema.sh index 5d2c74c6f44ac5..1cf35cba55a876 100755 --- a/packages/react-native-codegen/buck_tests/combine_js_to_schema.sh +++ b/packages/react-native-codegen/src/cli/combine/combine_js_to_schema.sh @@ -6,6 +6,6 @@ set -u THIS_DIR=$(cd -P "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo "${BASH_SOURCE[0]}")")" && pwd) # shellcheck source=xplat/js/env-utils/setup_env_vars.sh -source "$THIS_DIR/../../../../env-utils/setup_env_vars.sh" +source "$THIS_DIR/../../../../../../env-utils/setup_env_vars.sh" exec "$FLOW_NODE_BINARY" "$THIS_DIR/combine-js-to-schema-cli.js" "$@" diff --git a/packages/react-native-codegen/buck_tests/generate-view-configs-cli.js b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js similarity index 100% rename from packages/react-native-codegen/buck_tests/generate-view-configs-cli.js rename to packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js diff --git a/packages/react-native-codegen/buck_tests/generate-view-configs.js b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.js similarity index 90% rename from packages/react-native-codegen/buck_tests/generate-view-configs.js rename to packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.js index 68171c5b13f6dc..18d5670890ea05 100644 --- a/packages/react-native-codegen/buck_tests/generate-view-configs.js +++ b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.js @@ -10,8 +10,8 @@ 'use strict'; -const RNCodegen = require('../src/generators/RNCodegen.js'); -const RNParser = require('../src/generators/RNParser.js'); +const RNCodegen = require('../../generators/RNCodegen.js'); +const SchemaParser = require('../../parsers/schema'); const path = require('path'); @@ -25,7 +25,7 @@ function generateFilesWithResults( test: boolean, ): Array { return files.reduce((aggregated, filename) => { - const schema = RNParser.parse(filename); + const schema = SchemaParser.parse(filename); if (schema && schema.modules) { const libraryName = path.basename(filename).replace('Schema.js', ''); const success = RNCodegen.generate( diff --git a/packages/react-native-codegen/buck_tests/generate-view-configs.sh b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.sh similarity index 84% rename from packages/react-native-codegen/buck_tests/generate-view-configs.sh rename to packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.sh index 7b0809f5926dff..4da0153b7ef6ce 100755 --- a/packages/react-native-codegen/buck_tests/generate-view-configs.sh +++ b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.sh @@ -10,6 +10,6 @@ THIS_DIR=$(cd -P "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo "${BASH_SOUR FILES=$(find "$JS_DIR/" -name "*Schema.js" -print -type f) # shellcheck source=xplat/js/env-utils/setup_env_vars.sh -source "$THIS_DIR/../../../../env-utils/setup_env_vars.sh" +source "$THIS_DIR/../../../../../../env-utils/setup_env_vars.sh" exec "$FLOW_NODE_BINARY" "$THIS_DIR/generate-view-configs-cli.js" "$@" "$FILES" diff --git a/packages/react-native-codegen/src/parsers/flow/index.js b/packages/react-native-codegen/src/parsers/flow/index.js new file mode 100644 index 00000000000000..f8fe9459b89a88 --- /dev/null +++ b/packages/react-native-codegen/src/parsers/flow/index.js @@ -0,0 +1,21 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +'use strict'; + +import type {SchemaType} from '../../CodegenSchema.js'; + +function parse(filename: string): ?SchemaType { + throw new Error('Not implemented yet'); +} + +module.exports = { + parse, +}; diff --git a/packages/react-native-codegen/src/generators/RNParser.js b/packages/react-native-codegen/src/parsers/schema/index.js similarity index 88% rename from packages/react-native-codegen/src/generators/RNParser.js rename to packages/react-native-codegen/src/parsers/schema/index.js index 7d8cef5be3f301..663ffcb2f807e8 100644 --- a/packages/react-native-codegen/src/generators/RNParser.js +++ b/packages/react-native-codegen/src/parsers/schema/index.js @@ -10,7 +10,7 @@ 'use strict'; -import type {SchemaType} from '../CodegenSchema.js'; +import type {SchemaType} from '../../CodegenSchema.js'; function parse(filename: string): ?SchemaType { try { diff --git a/scripts/generate-rncore.sh b/scripts/generate-rncore.sh index 9392b35303d402..00d56ae97fe6fa 100644 --- a/scripts/generate-rncore.sh +++ b/scripts/generate-rncore.sh @@ -9,5 +9,5 @@ # to a location that the podspecs expect. # shellcheck disable=SC2038 -find "$PWD/../Libraries" -name "*Schema.js" -print | xargs yarn flow-node packages/react-native-codegen/buck_tests/combine-js-to-schema-cli.js schema-rncore.json +find "$PWD/../Libraries" -name "*Schema.js" -print | xargs yarn flow-node packages/react-native-codegen/src/cli/combine/combine-js-to-schema-cli.js schema-rncore.json yarn flow-node packages/react-native-codegen/buck_tests/generate-tests.js schema-rncore.json rncore ReactCommon/fabric/components/rncore From 45b5e5f141642896fa687b7c0f878ed6e34372d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= Date: Wed, 22 May 2019 06:53:20 -0700 Subject: [PATCH 0036/1084] Add test-ios command to package.json (#24985) Summary: There is currently no entry point for running the RNTester tests in package.json. This adds a test-ios command which leverages the existing objc-test-ios.sh script. With this change in place, our documentation for running tests locally can be simplified and made consistent with how JavaScript tests are run (yarn test). ## Changelog [General] [Added] - Add a test-ios command to run iOS RNTester tests locally Pull Request resolved: https://github.com/facebook/react-native/pull/24985 Differential Revision: D15449399 Pulled By: cpojer fbshipit-source-id: 63f7ad653d23c5601a11fc9d27a39b4987fccaad --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 3ea4fa788d51f8..38ae1245970930 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,8 @@ "test-android-unit": "yarn run docker-build-android && yarn run test-android-run-unit", "test-android-e2e": "yarn run docker-build-android && yarn run test-android-run-e2e", "build-ios-e2e": "detox build -c ios.sim.release", - "test-ios-e2e": "detox test -c ios.sim.release RNTester/e2e" + "test-ios-e2e": "detox test -c ios.sim.release RNTester/e2e", + "test-ios": "./scripts/objc-test-ios.sh test" }, "peerDependencies": { "react": "16.8.6" From 905e3fc5bd3e68a88167a9faa28bf604e6c3697c Mon Sep 17 00:00:00 2001 From: Eric Lewis Date: Wed, 22 May 2019 09:23:41 -0700 Subject: [PATCH 0037/1084] Add spec for KeyboardObserver (#24881) Summary: part of #24875. iOS only it appears, but not really used by RN itself. Should be fine? ## Changelog [General] [Added] - Add TM spec for KeyboardObserver Pull Request resolved: https://github.com/facebook/react-native/pull/24881 Reviewed By: fkgozali Differential Revision: D15391769 Pulled By: rickhanlonii fbshipit-source-id: 557507f6063b40d1c68ec8739e23b33bc22ade39 --- Libraries/Components/Keyboard/Keyboard.js | 6 +++--- .../Keyboard/NativeKeyboardObserver.js | 21 +++++++++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 Libraries/Components/Keyboard/NativeKeyboardObserver.js diff --git a/Libraries/Components/Keyboard/Keyboard.js b/Libraries/Components/Keyboard/Keyboard.js index d4e99f51d8fafe..976aab0aa7daaf 100644 --- a/Libraries/Components/Keyboard/Keyboard.js +++ b/Libraries/Components/Keyboard/Keyboard.js @@ -13,10 +13,10 @@ const LayoutAnimation = require('../../LayoutAnimation/LayoutAnimation'); const invariant = require('invariant'); const NativeEventEmitter = require('../../EventEmitter/NativeEventEmitter'); -const KeyboardObserver = require('../../BatchedBridge/NativeModules') - .KeyboardObserver; const dismissKeyboard = require('../../Utilities/dismissKeyboard'); -const KeyboardEventEmitter = new NativeEventEmitter(KeyboardObserver); + +import NativeKeyboardObserver from './NativeKeyboardObserver'; +const KeyboardEventEmitter = new NativeEventEmitter(NativeKeyboardObserver); export type KeyboardEventName = | 'keyboardWillShow' diff --git a/Libraries/Components/Keyboard/NativeKeyboardObserver.js b/Libraries/Components/Keyboard/NativeKeyboardObserver.js new file mode 100644 index 00000000000000..792cf7c075726b --- /dev/null +++ b/Libraries/Components/Keyboard/NativeKeyboardObserver.js @@ -0,0 +1,21 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +addListener: (eventName: string) => void; + +removeListeners: (count: number) => void; +} + +export default TurboModuleRegistry.get('KeyboardObserver'); From 07398592f28163616754b05e11a9d210b86bfbaa Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Wed, 22 May 2019 09:39:28 -0700 Subject: [PATCH 0038/1084] Remove comparison to `YGUndefined` *and* `0.0f` Summary: Removes a check introduced in D6969537, comparing `totalFlexGrowFactors` and `resolveFlexGrow` to both `0.0` *and* undefined. Reviewed By: SidharthGuglani Differential Revision: D15431425 fbshipit-source-id: 13c8f24e1bc8c49496097a6aa78e20ee5d3964a7 --- ReactCommon/yoga/yoga/Yoga.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index c4544ed95a76a2..93ad4148c79bdd 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -2859,11 +2859,8 @@ static void YGNodelayoutImpl( availableInnerMainDim = maxInnerMainDim; } else { if (!node->getConfig()->useLegacyStretchBehaviour && - ((YGFloatIsUndefined( - collectedFlexItemsValues.totalFlexGrowFactors) && - collectedFlexItemsValues.totalFlexGrowFactors == 0) || - (YGFloatIsUndefined(node->resolveFlexGrow()) && - node->resolveFlexGrow() == 0))) { + (collectedFlexItemsValues.totalFlexGrowFactors == 0 || + node->resolveFlexGrow() == 0)) { // If we don't have any children to flex or we can't flex the node // itself, space we've used is all space we need. Root node also // should be shrunk to minimum From 65b10b350e7a461f0a516a424cea6f625c6aadf3 Mon Sep 17 00:00:00 2001 From: Jean Regisser Date: Wed, 22 May 2019 13:04:35 -0700 Subject: [PATCH 0039/1084] Add spec for TimePickerAndroid (#24897) Summary: Part of #24875 ## Changelog [General] [Added] - Add TurboModule spec for TimePickerAndroid Pull Request resolved: https://github.com/facebook/react-native/pull/24897 Reviewed By: fkgozali Differential Revision: D15424335 Pulled By: RSNara fbshipit-source-id: a846de9353af58ad7d5e09678dd810ac33532105 --- ...oidTypes.js => NativeTimePickerAndroid.js} | 17 +++++++++--- .../TimePickerAndroid.ios.js | 26 ------------------- ...ndroid.android.js => TimePickerAndroid.js} | 23 +++++++++------- 3 files changed, 27 insertions(+), 39 deletions(-) rename Libraries/Components/TimePickerAndroid/{TimePickerAndroidTypes.js => NativeTimePickerAndroid.js} (51%) delete mode 100644 Libraries/Components/TimePickerAndroid/TimePickerAndroid.ios.js rename Libraries/Components/TimePickerAndroid/{TimePickerAndroid.android.js => TimePickerAndroid.js} (82%) diff --git a/Libraries/Components/TimePickerAndroid/TimePickerAndroidTypes.js b/Libraries/Components/TimePickerAndroid/NativeTimePickerAndroid.js similarity index 51% rename from Libraries/Components/TimePickerAndroid/TimePickerAndroidTypes.js rename to Libraries/Components/TimePickerAndroid/NativeTimePickerAndroid.js index aafa572be6c052..7d0d9a429dc2f0 100644 --- a/Libraries/Components/TimePickerAndroid/TimePickerAndroidTypes.js +++ b/Libraries/Components/TimePickerAndroid/NativeTimePickerAndroid.js @@ -4,21 +4,30 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * + * @flow * @format - * @flow strict-local */ 'use strict'; +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + export type TimePickerOptions = {| hour?: number, minute?: number, is24Hour?: boolean, - mode?: 'clock' | 'spinner' | 'default', + mode?: string, |}; -export type TimePickerResult = $ReadOnly<{| +export type TimePickerResult = {| action: string, hour: number, minute: number, -|}>; +|}; + +export interface Spec extends TurboModule { + +open: (options: TimePickerOptions) => Promise; +} + +export default TurboModuleRegistry.get('TimePickerAndroid'); diff --git a/Libraries/Components/TimePickerAndroid/TimePickerAndroid.ios.js b/Libraries/Components/TimePickerAndroid/TimePickerAndroid.ios.js deleted file mode 100644 index 3de6ca4aa06560..00000000000000 --- a/Libraries/Components/TimePickerAndroid/TimePickerAndroid.ios.js +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @flow strict-local - */ - -'use strict'; - -import type { - TimePickerOptions, - TimePickerResult, -} from './TimePickerAndroidTypes'; - -const TimePickerAndroid = { - async open(options: TimePickerOptions): Promise { - return Promise.reject({ - message: 'TimePickerAndroid is not supported on this platform.', - }); - }, -}; - -module.exports = TimePickerAndroid; diff --git a/Libraries/Components/TimePickerAndroid/TimePickerAndroid.android.js b/Libraries/Components/TimePickerAndroid/TimePickerAndroid.js similarity index 82% rename from Libraries/Components/TimePickerAndroid/TimePickerAndroid.android.js rename to Libraries/Components/TimePickerAndroid/TimePickerAndroid.js index 8b25e19868b2c0..5c2aab9cf52cc1 100644 --- a/Libraries/Components/TimePickerAndroid/TimePickerAndroid.android.js +++ b/Libraries/Components/TimePickerAndroid/TimePickerAndroid.js @@ -10,13 +10,10 @@ 'use strict'; -const TimePickerModule = require('../../BatchedBridge/NativeModules') - .TimePickerAndroid; - -import type { - TimePickerOptions, - TimePickerResult, -} from './TimePickerAndroidTypes'; +import NativeTimePickerAndroid, { + type TimePickerOptions, + type TimePickerResult, +} from './NativeTimePickerAndroid'; /** * Opens the standard Android time picker dialog. @@ -58,8 +55,16 @@ class TimePickerAndroid { * still be resolved with action being `TimePickerAndroid.dismissedAction` and all the other keys * being undefined. **Always** check whether the `action` before reading the values. */ - static async open(options: TimePickerOptions): Promise { - return TimePickerModule.open(options); + static async open( + options: TimePickerOptions, + ): Promise<$ReadOnly> { + if (NativeTimePickerAndroid) { + return NativeTimePickerAndroid.open(options); + } else { + return Promise.reject({ + message: 'TimePickerAndroid is not supported on this platform.', + }); + } } /** From 8ea749ad3e2cb8b73079fd7a3e409d723326c0aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Wed, 22 May 2019 13:04:35 -0700 Subject: [PATCH 0040/1084] Add spec for ExceptionsManager (#24900) Summary: Part of #24875, adds a spec for ExceptionsManager ## Changelog [General] [Added] - TM Add spec for ExceptionsManager Pull Request resolved: https://github.com/facebook/react-native/pull/24900 Reviewed By: fkgozali Differential Revision: D15434006 Pulled By: RSNara fbshipit-source-id: 1a505744a84c0c4ac3a9fac6c91a391fbd8a9f46 --- Libraries/Core/Devtools/parseErrorStack.js | 7 +-- .../Core/Devtools/symbolicateStackTrace.js | 2 +- Libraries/Core/ExceptionsManager.js | 19 +++++--- Libraries/Core/NativeExceptionsManager.js | 43 +++++++++++++++++++ Libraries/Utilities/HMRClient.js | 10 ++--- .../YellowBox/Data/YellowBoxSymbolication.js | 2 +- .../__tests__/YellowBoxSymbolication-test.js | 2 +- .../Data/__tests__/YellowBoxWarning-test.js | 2 +- .../UI/YellowBoxInspectorStackFrame.js | 2 +- 9 files changed, 66 insertions(+), 23 deletions(-) create mode 100644 Libraries/Core/NativeExceptionsManager.js diff --git a/Libraries/Core/Devtools/parseErrorStack.js b/Libraries/Core/Devtools/parseErrorStack.js index a826630355df32..441800dac8cf90 100644 --- a/Libraries/Core/Devtools/parseErrorStack.js +++ b/Libraries/Core/Devtools/parseErrorStack.js @@ -10,12 +10,7 @@ 'use strict'; -export type StackFrame = { - column: ?number, - file: string, - lineNumber: number, - methodName: string, -}; +import type {StackFrame} from '../NativeExceptionsManager'; export type ExtendedError = Error & { framesToPop?: number, diff --git a/Libraries/Core/Devtools/symbolicateStackTrace.js b/Libraries/Core/Devtools/symbolicateStackTrace.js index 32e209ef78f59c..1c6552a1591d7a 100644 --- a/Libraries/Core/Devtools/symbolicateStackTrace.js +++ b/Libraries/Core/Devtools/symbolicateStackTrace.js @@ -17,7 +17,7 @@ import NativeSourceCode from '../../NativeModules/specs/NativeSourceCode'; // Avoid requiring fetch on load of this module; see symbolicateStackTrace let fetch; -import type {StackFrame} from './parseErrorStack'; +import type {StackFrame} from '../NativeExceptionsManager'; function isSourcedFromDisk(sourcePath: string): boolean { return !/^http/.test(sourcePath) && /[\\/]/.test(sourcePath); diff --git a/Libraries/Core/ExceptionsManager.js b/Libraries/Core/ExceptionsManager.js index 24ca07b5891b9a..9ccd725d4294ca 100644 --- a/Libraries/Core/ExceptionsManager.js +++ b/Libraries/Core/ExceptionsManager.js @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. * * @format - * @flow + * @flow strict-local */ 'use strict'; @@ -24,21 +24,25 @@ const INTERNAL_CALLSITES_REGEX = new RegExp( */ let exceptionID = 0; function reportException(e: ExtendedError, isFatal: boolean) { - const {ExceptionsManager} = require('../BatchedBridge/NativeModules'); - if (ExceptionsManager) { + const NativeExceptionsManager = require('./NativeExceptionsManager').default; + if (NativeExceptionsManager) { const parseErrorStack = require('./Devtools/parseErrorStack'); const stack = parseErrorStack(e); const currentExceptionID = ++exceptionID; const message = e.jsEngine == null ? e.message : `${e.message}, js engine: ${e.jsEngine}`; if (isFatal) { - ExceptionsManager.reportFatalException( + NativeExceptionsManager.reportFatalException( message, stack, currentExceptionID, ); } else { - ExceptionsManager.reportSoftException(message, stack, currentExceptionID); + NativeExceptionsManager.reportSoftException( + message, + stack, + currentExceptionID, + ); } if (__DEV__) { const symbolicateStackTrace = require('./Devtools/symbolicateStackTrace'); @@ -50,7 +54,7 @@ function reportException(e: ExtendedError, isFatal: boolean) { frame.file && frame.file.match(INTERNAL_CALLSITES_REGEX) === null, ); - ExceptionsManager.updateExceptionMessage( + NativeExceptionsManager.updateExceptionMessage( message, stackWithoutInternalCallsites, currentExceptionID, @@ -67,7 +71,7 @@ function reportException(e: ExtendedError, isFatal: boolean) { } declare var console: typeof console & { - _errorOriginal: Function, + _errorOriginal: typeof console.error, reportErrorsAsExceptions: boolean, }; @@ -80,6 +84,7 @@ function handleException(e: Error, isFatal: boolean) { // case, so if you ended up here trying to trace an error, look for // `throw ''` somewhere in your codebase. if (!e.message) { + // $FlowFixMe - cannot reassign constant, explanation above e = new Error(e); } if (console._errorOriginal) { diff --git a/Libraries/Core/NativeExceptionsManager.js b/Libraries/Core/NativeExceptionsManager.js new file mode 100644 index 00000000000000..f9a82ec6389e06 --- /dev/null +++ b/Libraries/Core/NativeExceptionsManager.js @@ -0,0 +1,43 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +export type StackFrame = {| + column: ?number, + file: string, + lineNumber: number, + methodName: string, +|}; + +export interface Spec extends TurboModule { + +reportFatalException: ( + message: string, + stack: Array, + exceptionId: number, + ) => void; + +reportSoftException: ( + message: string, + stack: Array, + exceptionId: number, + ) => void; + +updateExceptionMessage: ( + message: string, + stack: Array, + exceptionId: number, + ) => void; + // Android only + +dismissRedbox: () => void; +} + +export default TurboModuleRegistry.getEnforcing('ExceptionsManager'); diff --git a/Libraries/Utilities/HMRClient.js b/Libraries/Utilities/HMRClient.js index bb5b3ab69bcdd7..eb34d2d83ecc8d 100644 --- a/Libraries/Utilities/HMRClient.js +++ b/Libraries/Utilities/HMRClient.js @@ -81,11 +81,11 @@ Error: ${e.message}`; ) { NativeRedBox.dismiss(); } else { - const RCTExceptionsManager = require('../BatchedBridge/NativeModules') - .ExceptionsManager; - RCTExceptionsManager && - RCTExceptionsManager.dismissRedbox && - RCTExceptionsManager.dismissRedbox(); + const NativeExceptionsManager = require('../Core/NativeExceptionsManager') + .default; + NativeExceptionsManager && + NativeExceptionsManager.dismissRedbox && + NativeExceptionsManager.dismissRedbox(); } }); diff --git a/Libraries/YellowBox/Data/YellowBoxSymbolication.js b/Libraries/YellowBox/Data/YellowBoxSymbolication.js index f8186daeeb9868..d31d6ef06b757c 100644 --- a/Libraries/YellowBox/Data/YellowBoxSymbolication.js +++ b/Libraries/YellowBox/Data/YellowBoxSymbolication.js @@ -12,7 +12,7 @@ const symbolicateStackTrace = require('../../Core/Devtools/symbolicateStackTrace'); -import type {StackFrame} from '../../Core/Devtools/parseErrorStack'; +import type {StackFrame} from '../../Core/NativeExceptionsManager'; type CacheKey = string; diff --git a/Libraries/YellowBox/Data/__tests__/YellowBoxSymbolication-test.js b/Libraries/YellowBox/Data/__tests__/YellowBoxSymbolication-test.js index b438ab1142e92d..f125ff380f040a 100644 --- a/Libraries/YellowBox/Data/__tests__/YellowBoxSymbolication-test.js +++ b/Libraries/YellowBox/Data/__tests__/YellowBoxSymbolication-test.js @@ -11,7 +11,7 @@ 'use strict'; -import type {StackFrame} from '../../../Core/Devtools/parseErrorStack'; +import type {StackFrame} from '../../../Core/NativeExceptionsManager'; jest.mock('../../../Core/Devtools/symbolicateStackTrace'); diff --git a/Libraries/YellowBox/Data/__tests__/YellowBoxWarning-test.js b/Libraries/YellowBox/Data/__tests__/YellowBoxWarning-test.js index 65369bf8e5e60f..3bbca34dd569e7 100644 --- a/Libraries/YellowBox/Data/__tests__/YellowBoxWarning-test.js +++ b/Libraries/YellowBox/Data/__tests__/YellowBoxWarning-test.js @@ -11,7 +11,7 @@ 'use strict'; -import type {StackFrame} from '../../../Core/Devtools/parseErrorStack'; +import type {StackFrame} from '../../../Core/NativeExceptionsManager'; jest.mock('../YellowBoxSymbolication'); diff --git a/Libraries/YellowBox/UI/YellowBoxInspectorStackFrame.js b/Libraries/YellowBox/UI/YellowBoxInspectorStackFrame.js index efac349d35ee3c..47985c8b117e20 100644 --- a/Libraries/YellowBox/UI/YellowBoxInspectorStackFrame.js +++ b/Libraries/YellowBox/UI/YellowBoxInspectorStackFrame.js @@ -17,7 +17,7 @@ const YellowBoxPressable = require('./YellowBoxPressable'); const YellowBoxStyle = require('./YellowBoxStyle'); import type {PressEvent} from '../../Types/CoreEventTypes'; -import type {StackFrame} from '../../Core/Devtools/parseErrorStack'; +import type {StackFrame} from '../../Core/NativeExceptionsManager'; type Props = $ReadOnly<{| frame: StackFrame, From 342c81d75448e760ae32d62ebd9004bf6eeeff46 Mon Sep 17 00:00:00 2001 From: Eric Lewis Date: Wed, 22 May 2019 13:04:35 -0700 Subject: [PATCH 0041/1084] Add spec for BlobModule (#24909) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Part of #24875. Not sure that the id’s types are necessarily correct here… ## Changelog [General] [Added] - Add TM spec for BlobModule Pull Request resolved: https://github.com/facebook/react-native/pull/24909 Reviewed By: fkgozali Differential Revision: D15433753 Pulled By: RSNara fbshipit-source-id: 68193d1a82fc7c66d6cc7ba4f22a0d3786987599 --- Libraries/Blob/BlobManager.js | 29 +++++++++++++++++++++-------- Libraries/Blob/NativeBlobModule.js | 26 ++++++++++++++++++++++++++ Libraries/Blob/URL.js | 14 +++++++++----- jest/setup.js | 3 +-- 4 files changed, 57 insertions(+), 15 deletions(-) create mode 100644 Libraries/Blob/NativeBlobModule.js diff --git a/Libraries/Blob/BlobManager.js b/Libraries/Blob/BlobManager.js index 20e81ee67a5fc0..9176218373ca67 100644 --- a/Libraries/Blob/BlobManager.js +++ b/Libraries/Blob/BlobManager.js @@ -12,7 +12,8 @@ const Blob = require('./Blob'); const BlobRegistry = require('./BlobRegistry'); -const {BlobModule} = require('../BatchedBridge/NativeModules'); +import NativeBlobModule from './NativeBlobModule'; +import invariant from 'invariant'; import type {BlobData, BlobOptions, BlobCollector} from './BlobTypes'; @@ -53,7 +54,7 @@ class BlobManager { /** * If the native blob module is available. */ - static isAvailable = !!BlobModule; + static isAvailable = !!NativeBlobModule; /** * Create blob from existing array of blobs. @@ -62,6 +63,8 @@ class BlobManager { parts: Array, options?: BlobOptions, ): Blob { + invariant(NativeBlobModule, 'NativeBlobModule is available.'); + const blobId = uuidv4(); const items = parts.map(part => { if ( @@ -92,7 +95,7 @@ class BlobManager { } }, 0); - BlobModule.createFromParts(items, blobId); + NativeBlobModule.createFromParts(items, blobId); return BlobManager.createFromOptions({ blobId, @@ -127,11 +130,13 @@ class BlobManager { * Deallocate resources for a blob. */ static release(blobId: string): void { + invariant(NativeBlobModule, 'NativeBlobModule is available.'); + BlobRegistry.unregister(blobId); if (BlobRegistry.has(blobId)) { return; } - BlobModule.release(blobId); + NativeBlobModule.release(blobId); } /** @@ -139,7 +144,9 @@ class BlobManager { * requests and responses. */ static addNetworkingHandler(): void { - BlobModule.addNetworkingHandler(); + invariant(NativeBlobModule, 'NativeBlobModule is available.'); + + NativeBlobModule.addNetworkingHandler(); } /** @@ -147,7 +154,9 @@ class BlobManager { * messages. */ static addWebSocketHandler(socketId: number): void { - BlobModule.addWebSocketHandler(socketId); + invariant(NativeBlobModule, 'NativeBlobModule is available.'); + + NativeBlobModule.addWebSocketHandler(socketId); } /** @@ -155,14 +164,18 @@ class BlobManager { * binary messages. */ static removeWebSocketHandler(socketId: number): void { - BlobModule.removeWebSocketHandler(socketId); + invariant(NativeBlobModule, 'NativeBlobModule is available.'); + + NativeBlobModule.removeWebSocketHandler(socketId); } /** * Send a blob message to a websocket. */ static sendOverSocket(blob: Blob, socketId: number): void { - BlobModule.sendOverSocket(blob.data, socketId); + invariant(NativeBlobModule, 'NativeBlobModule is available.'); + + NativeBlobModule.sendOverSocket(blob.data, socketId); } } diff --git a/Libraries/Blob/NativeBlobModule.js b/Libraries/Blob/NativeBlobModule.js new file mode 100644 index 00000000000000..e2f8450e236008 --- /dev/null +++ b/Libraries/Blob/NativeBlobModule.js @@ -0,0 +1,26 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +getConstants: () => {|BLOB_URI_SCHEME: string, BLOB_URI_HOST: ?string|}; + +addNetworkingHandler: () => void; + +addWebSocketHandler: (id: number) => void; + +removeWebSocketHandler: (id: number) => void; + +sendOverSocket: (blob: Object, id: number) => void; + +createFromParts: (parts: Array, blobId: string) => void; + +release: (blobId: string) => void; +} + +export default TurboModuleRegistry.get('BlobModule'); diff --git a/Libraries/Blob/URL.js b/Libraries/Blob/URL.js index 520b5fc63a0c94..692980c69ca1b8 100644 --- a/Libraries/Blob/URL.js +++ b/Libraries/Blob/URL.js @@ -11,14 +11,18 @@ const Blob = require('./Blob'); -const {BlobModule} = require('../BatchedBridge/NativeModules'); +import NativeBlobModule from './NativeBlobModule'; let BLOB_URL_PREFIX = null; -if (BlobModule && typeof BlobModule.BLOB_URI_SCHEME === 'string') { - BLOB_URL_PREFIX = BlobModule.BLOB_URI_SCHEME + ':'; - if (typeof BlobModule.BLOB_URI_HOST === 'string') { - BLOB_URL_PREFIX += `//${BlobModule.BLOB_URI_HOST}/`; +if ( + NativeBlobModule && + typeof NativeBlobModule.getConstants().BLOB_URI_SCHEME === 'string' +) { + const constants = NativeBlobModule.getConstants(); + BLOB_URL_PREFIX = constants.BLOB_URI_SCHEME + ':'; + if (typeof constants.BLOB_URI_HOST === 'string') { + BLOB_URL_PREFIX += `//${constants.BLOB_URI_HOST}/`; } } diff --git a/jest/setup.js b/jest/setup.js index b59e3604efc7ec..eb2358c3c83ffb 100644 --- a/jest/setup.js +++ b/jest/setup.js @@ -321,8 +321,7 @@ const mockNativeModules = { }, }, BlobModule: { - BLOB_URI_SCHEME: 'content', - BLOB_URI_HOST: null, + getConstants: () => ({BLOB_URI_SCHEME: 'content', BLOB_URI_HOST: null}), addNetworkingHandler: jest.fn(), enableBlobSupport: jest.fn(), disableBlobSupport: jest.fn(), From 67c3ed34ba75500098a16eced5f43b33039b0b14 Mon Sep 17 00:00:00 2001 From: michalchudziak Date: Wed, 22 May 2019 13:04:35 -0700 Subject: [PATCH 0042/1084] Add specs for AccessibilityInfo (#24891) Summary: Part of https://github.com/facebook/react-native/issues/24875 ## Changelog [General] [Added] - Add TurboModule spec for AccessibilityInfo Pull Request resolved: https://github.com/facebook/react-native/pull/24891 Reviewed By: fkgozali Differential Revision: D15394913 Pulled By: RSNara fbshipit-source-id: e66e7b7fc4451575b5022695f125c15f9f4b707e --- .../AccessibilityInfo.android.js | 21 ++++++++++----- .../NativeAccessibilityInfo.js | 27 +++++++++++++++++++ 2 files changed, 42 insertions(+), 6 deletions(-) create mode 100644 Libraries/Components/AccessibilityInfo/NativeAccessibilityInfo.js diff --git a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js index bd89906110480c..ff9a7329a56c87 100644 --- a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js +++ b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js @@ -10,12 +10,11 @@ 'use strict'; -const NativeModules = require('../../BatchedBridge/NativeModules'); +import NativeAccessibilityInfo from './NativeAccessibilityInfo'; + const RCTDeviceEventEmitter = require('../../EventEmitter/RCTDeviceEventEmitter'); const UIManager = require('../../ReactNative/UIManager'); -const RCTAccessibilityInfo = NativeModules.AccessibilityInfo; - const REDUCE_MOTION_EVENT = 'reduceMotionDidChange'; const TOUCH_EXPLORATION_EVENT = 'touchExplorationDidChange'; @@ -61,7 +60,11 @@ const AccessibilityInfo = { isReduceMotionEnabled: function(): Promise { return new Promise((resolve, reject) => { - RCTAccessibilityInfo.isReduceMotionEnabled(resolve); + if (NativeAccessibilityInfo) { + NativeAccessibilityInfo.isReduceMotionEnabled(resolve); + } else { + reject(false); + } }); }, @@ -74,7 +77,11 @@ const AccessibilityInfo = { isScreenReaderEnabled: function(): Promise { return new Promise((resolve, reject) => { - RCTAccessibilityInfo.isTouchExplorationEnabled(resolve); + if (NativeAccessibilityInfo) { + NativeAccessibilityInfo.isTouchExplorationEnabled(resolve); + } else { + reject(false); + } }); }, @@ -142,7 +149,9 @@ const AccessibilityInfo = { * See http://facebook.github.io/react-native/docs/accessibilityinfo.html#announceforaccessibility */ announceForAccessibility: function(announcement: string): void { - RCTAccessibilityInfo.announceForAccessibility(announcement); + if (NativeAccessibilityInfo) { + NativeAccessibilityInfo.announceForAccessibility(announcement); + } }, }; diff --git a/Libraries/Components/AccessibilityInfo/NativeAccessibilityInfo.js b/Libraries/Components/AccessibilityInfo/NativeAccessibilityInfo.js new file mode 100644 index 00000000000000..894a0804a9faef --- /dev/null +++ b/Libraries/Components/AccessibilityInfo/NativeAccessibilityInfo.js @@ -0,0 +1,27 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +isReduceMotionEnabled: ( + onSuccess: (isReduceMotionEnabled: boolean) => void, + ) => void; + +isTouchExplorationEnabled: ( + onSuccess: (isScreenReaderEnabled: boolean) => void, + ) => void; + +setAccessibilityFocus: (reactTag: number) => void; + +announceForAccessibility: (announcement: string) => void; +} + +export default TurboModuleRegistry.get('AccessibilityInfo'); From 94029eee546cc8f95cedbb1dd4be73a6a62e53a9 Mon Sep 17 00:00:00 2001 From: Wojteg1337 Date: Wed, 22 May 2019 13:04:35 -0700 Subject: [PATCH 0043/1084] Add spec for HeapCapture (#24899) Summary: Part of #24875, adds a spec for HeapCapture ## Changelog [General] [Added] - TM Spec for HeapCapture Pull Request resolved: https://github.com/facebook/react-native/pull/24899 Reviewed By: fkgozali Differential Revision: D15393464 Pulled By: RSNara fbshipit-source-id: d8778285753ce8dbc87204ecfbddfa7339acd264 --- Libraries/Core/setUpBatchedBridge.js | 2 +- .../{Utilities => HeapCapture}/HeapCapture.js | 9 +++---- Libraries/HeapCapture/NativeHeapCapture.js | 24 +++++++++++++++++++ 3 files changed, 30 insertions(+), 5 deletions(-) rename Libraries/{Utilities => HeapCapture}/HeapCapture.js (80%) create mode 100644 Libraries/HeapCapture/NativeHeapCapture.js diff --git a/Libraries/Core/setUpBatchedBridge.js b/Libraries/Core/setUpBatchedBridge.js index 680c1398e45b84..e9d33fe6ae3a25 100644 --- a/Libraries/Core/setUpBatchedBridge.js +++ b/Libraries/Core/setUpBatchedBridge.js @@ -22,7 +22,7 @@ BatchedBridge.registerLazyCallableModule('JSTimers', () => require('./Timers/JSTimers'), ); BatchedBridge.registerLazyCallableModule('HeapCapture', () => - require('../Utilities/HeapCapture'), + require('../HeapCapture/HeapCapture'), ); BatchedBridge.registerLazyCallableModule('SamplingProfiler', () => require('../Performance/SamplingProfiler'), diff --git a/Libraries/Utilities/HeapCapture.js b/Libraries/HeapCapture/HeapCapture.js similarity index 80% rename from Libraries/Utilities/HeapCapture.js rename to Libraries/HeapCapture/HeapCapture.js index 94ae18f1157606..9cbabc60417487 100644 --- a/Libraries/Utilities/HeapCapture.js +++ b/Libraries/HeapCapture/HeapCapture.js @@ -10,6 +10,8 @@ 'use strict'; +import NativeHeapCapture from './NativeHeapCapture'; + const HeapCapture = { captureHeap: function(path: string) { let error = null; @@ -20,10 +22,9 @@ const HeapCapture = { console.log('HeapCapture.captureHeap error: ' + e.toString()); error = e.toString(); } - require('../BatchedBridge/NativeModules').JSCHeapCapture.captureComplete( - path, - error, - ); + if (NativeHeapCapture) { + NativeHeapCapture.captureComplete(path, error); + } }, }; diff --git a/Libraries/HeapCapture/NativeHeapCapture.js b/Libraries/HeapCapture/NativeHeapCapture.js new file mode 100644 index 00000000000000..a68a967d4ab627 --- /dev/null +++ b/Libraries/HeapCapture/NativeHeapCapture.js @@ -0,0 +1,24 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +export interface Spec extends TurboModule { + // Common interface + +captureHeap: (path: string) => void; + + // Android only + +captureComplete: (path: string, error: ?string) => void; +} + +export default TurboModuleRegistry.get('HeapCapture'); From db0ec663413a44a569d18d3798a316d6ee1bd2e2 Mon Sep 17 00:00:00 2001 From: Jean Regisser Date: Wed, 22 May 2019 13:04:35 -0700 Subject: [PATCH 0044/1084] Add spec for Timing (#24889) Summary: Part of #24875 ## Changelog [General] [Added] - Add TurboModule spec for Timing Pull Request resolved: https://github.com/facebook/react-native/pull/24889 Reviewed By: fkgozali Differential Revision: D15379559 Pulled By: RSNara fbshipit-source-id: d254fb4d1cae3533bbd63bf7ec739cebc6ca14b0 --- Libraries/Core/Timers/JSTimers.js | 41 ++++++++++++++++++++------- Libraries/Core/Timers/NativeTiming.js | 27 ++++++++++++++++++ 2 files changed, 58 insertions(+), 10 deletions(-) create mode 100644 Libraries/Core/Timers/NativeTiming.js diff --git a/Libraries/Core/Timers/JSTimers.js b/Libraries/Core/Timers/JSTimers.js index 54d86d44f18197..c13732b2ce8671 100644 --- a/Libraries/Core/Timers/JSTimers.js +++ b/Libraries/Core/Timers/JSTimers.js @@ -13,9 +13,10 @@ const Platform = require('../../Utilities/Platform'); const Systrace = require('../../Performance/Systrace'); const invariant = require('invariant'); -const {Timing} = require('../../BatchedBridge/NativeModules'); const BatchedBridge = require('../../BatchedBridge/BatchedBridge'); +import NativeTiming from './NativeTiming'; + import type {ExtendedError} from '../Devtools/parseErrorStack'; let _performanceNow = null; @@ -221,7 +222,7 @@ function _freeCallback(timerID: number) { _clearIndex(index); const type = types[index]; if (type !== 'setImmediate' && type !== 'requestIdleCallback') { - Timing.deleteTimer(timerID); + deleteTimer(timerID); } } } @@ -250,7 +251,7 @@ const JSTimers = { () => func.apply(undefined, args), 'setTimeout', ); - Timing.createTimer(id, duration || 0, Date.now(), /* recurring */ false); + createTimer(id, duration || 0, Date.now(), /* recurring */ false); return id; }, @@ -276,7 +277,7 @@ const JSTimers = { () => func.apply(undefined, args), 'setInterval', ); - Timing.createTimer(id, duration || 0, Date.now(), /* recurring */ true); + createTimer(id, duration || 0, Date.now(), /* recurring */ true); return id; }, @@ -298,7 +299,7 @@ const JSTimers = { */ requestAnimationFrame: function(func: Function) { const id = _allocateCallback(func, 'requestAnimationFrame'); - Timing.createTimer(id, 1, Date.now(), /* recurring */ false); + createTimer(id, 1, Date.now(), /* recurring */ false); return id; }, @@ -309,7 +310,7 @@ const JSTimers = { */ requestIdleCallback: function(func: Function, options: ?Object) { if (requestIdleCallbacks.length === 0) { - Timing.setSendIdleEvents(true); + setSendIdleEvents(true); } const timeout = options && options.timeout; @@ -337,7 +338,7 @@ const JSTimers = { } delete requestIdleCallbackTimeouts[id]; if (requestIdleCallbacks.length === 0) { - Timing.setSendIdleEvents(false); + setSendIdleEvents(false); } }, timeout); requestIdleCallbackTimeouts[id] = timeoutId; @@ -359,7 +360,7 @@ const JSTimers = { } if (requestIdleCallbacks.length === 0) { - Timing.setSendIdleEvents(false); + setSendIdleEvents(false); } }, @@ -437,7 +438,7 @@ const JSTimers = { } if (requestIdleCallbacks.length === 0) { - Timing.setSendIdleEvents(false); + setSendIdleEvents(false); } if (errors) { @@ -477,8 +478,28 @@ const JSTimers = { }, }; +function createTimer( + callbackID: number, + duration: number, + jsSchedulingTime: number, + repeats: boolean, +): void { + invariant(NativeTiming, 'NativeTiming is available'); + NativeTiming.createTimer(callbackID, duration, jsSchedulingTime, repeats); +} + +function deleteTimer(timerID: number): void { + invariant(NativeTiming, 'NativeTiming is available'); + NativeTiming.deleteTimer(timerID); +} + +function setSendIdleEvents(sendIdleEvents: boolean): void { + invariant(NativeTiming, 'NativeTiming is available'); + NativeTiming.setSendIdleEvents(sendIdleEvents); +} + let ExportedJSTimers; -if (!Timing) { +if (!NativeTiming) { console.warn("Timing native module is not available, can't set timers."); // $FlowFixMe: we can assume timers are generally available ExportedJSTimers = ({ diff --git a/Libraries/Core/Timers/NativeTiming.js b/Libraries/Core/Timers/NativeTiming.js new file mode 100644 index 00000000000000..7f8f1d806ccc3f --- /dev/null +++ b/Libraries/Core/Timers/NativeTiming.js @@ -0,0 +1,27 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +createTimer: ( + callbackID: number, + duration: number, + jsSchedulingTime: number, + repeats: boolean, + ) => void; + +deleteTimer: (timerID: number) => void; + +setSendIdleEvents: (sendIdleEvents: boolean) => void; +} + +export default TurboModuleRegistry.get('Timing'); From 12c0ec85f7fd116b2840ecd4e2edbd57de7638ef Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Wed, 22 May 2019 13:11:53 -0700 Subject: [PATCH 0045/1084] Implement ReactContext.getNativeModule support Summary: `ReactContext.getNativeModule` can be used to access NativeModules. With these changes, it can also be used to instantiate (if necessary) and retrieve a TurboModule. Reviewed By: mdvacca Differential Revision: D15167631 fbshipit-source-id: 3cb0d9a4be16cbadebbf6648c3f1481ba26513c3 --- .../react/bridge/CatalystInstance.java | 9 +++++ .../react/bridge/CatalystInstanceImpl.java | 33 ++++++++++++--- .../com/facebook/react/turbomodule/core/BUCK | 4 +- .../turbomodule/core/TurboModuleManager.java | 40 ++++++++++++++----- .../react/turbomodule/core/interfaces/BUCK | 5 ++- .../core/interfaces/TurboModuleRegistry.java | 35 ++++++++++++++++ 6 files changed, 110 insertions(+), 16 deletions(-) create mode 100644 ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/interfaces/TurboModuleRegistry.java diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java index c7b6ced623def7..69751f22508638 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstance.java @@ -11,6 +11,7 @@ import com.facebook.react.bridge.queue.ReactQueueConfiguration; import com.facebook.react.common.annotations.VisibleForTesting; import com.facebook.react.turbomodule.core.interfaces.JSCallInvokerHolder; +import com.facebook.react.turbomodule.core.interfaces.TurboModuleRegistry; import java.util.Collection; import java.util.List; import javax.annotation.Nullable; @@ -110,4 +111,12 @@ void callFunction( * Required for TurboModuleManager initialization. */ JSCallInvokerHolder getJSCallInvokerHolder(); + + /** + * For the time being, we want code relying on the old infra to also + * work with TurboModules. Hence, we must provide the TurboModuleRegistry + * to CatalystInstance so that getNativeModule, hasNativeModule, and + * getNativeModules can also return TurboModules. + */ + void setTurboModuleRegistry(TurboModuleRegistry getter); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java index b2325fdcb863a3..1933f10ae70c07 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java @@ -25,10 +25,10 @@ import com.facebook.react.common.annotations.VisibleForTesting; import com.facebook.react.module.annotations.ReactModule; import com.facebook.react.turbomodule.core.JSCallInvokerHolderImpl; +import com.facebook.react.turbomodule.core.interfaces.TurboModule; +import com.facebook.react.turbomodule.core.interfaces.TurboModuleRegistry; import com.facebook.systrace.Systrace; import com.facebook.systrace.TraceListener; -import java.lang.annotation.Annotation; -import java.lang.annotation.Native; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collection; @@ -96,6 +96,7 @@ public String toString() { private @Nullable String mSourceURL; private JavaScriptContextHolder mJavaScriptContextHolder; + private @Nullable TurboModuleRegistry mTurboModuleRegistry = null; // C++ parts private final HybridData mHybridData; @@ -421,16 +422,25 @@ public T getJSModule(Class jsInterface) { @Override public boolean hasNativeModule(Class nativeModuleInterface) { - return mNativeModuleRegistry.hasModule(getNameFromAnnotation(nativeModuleInterface)); + String moduleName = getNameFromAnnotation(nativeModuleInterface); + return mTurboModuleRegistry != null && mTurboModuleRegistry.hasModule(moduleName) ? true : mNativeModuleRegistry.hasModule(moduleName); } @Override public T getNativeModule(Class nativeModuleInterface) { - return (T) mNativeModuleRegistry.getModule(getNameFromAnnotation(nativeModuleInterface)); + return (T) getNativeModule(getNameFromAnnotation(nativeModuleInterface)); } @Override public NativeModule getNativeModule(String moduleName) { + if (mTurboModuleRegistry != null) { + TurboModule turboModule = mTurboModuleRegistry.getModule(moduleName); + + if (turboModule != null) { + return (NativeModule)turboModule; + } + } + return mNativeModuleRegistry.getModule(moduleName); } @@ -445,7 +455,16 @@ private String getNameFromAnnotation(Class nativeMod // This is only used by com.facebook.react.modules.common.ModuleDataCleaner @Override public Collection getNativeModules() { - return mNativeModuleRegistry.getAllModules(); + Collection nativeModules = new ArrayList<>(); + nativeModules.addAll(mNativeModuleRegistry.getAllModules()); + + if (mTurboModuleRegistry != null) { + for (TurboModule turboModule : mTurboModuleRegistry.getModules()) { + nativeModules.add((NativeModule) turboModule); + } + } + + return nativeModules; } private native void jniHandleMemoryPressure(int level); @@ -517,6 +536,10 @@ public void run() { } } + public void setTurboModuleRegistry(TurboModuleRegistry getter) { + mTurboModuleRegistry = getter; + } + private void decrementPendingJSCalls() { int newPendingCalls = mPendingJSCalls.decrementAndGet(); // TODO(9604406): handle case of web workers injecting messages to main thread diff --git a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/BUCK b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/BUCK index aa8b05cf7542c7..c6ad15fff0d97c 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/BUCK @@ -13,7 +13,6 @@ rn_android_library( "PUBLIC", ], deps = [ - react_native_target("java/com/facebook/react/turbomodule/core/interfaces:interfaces"), react_native_dep("java/com/facebook/systrace:systrace"), react_native_dep("libraries/soloader/java/com/facebook/soloader:soloader"), react_native_dep("third-party/java/infer-annotations:infer-annotations"), @@ -24,6 +23,9 @@ rn_android_library( react_native_target("java/com/facebook/react/bridge:bridge"), ":jscallinvokerholder", ], + exported_deps = [ + react_native_target("java/com/facebook/react/turbomodule/core/interfaces:interfaces"), + ], ) rn_android_library( diff --git a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManager.java b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManager.java index 158ff5bd298519..511dd690f31a03 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManager.java @@ -9,20 +9,24 @@ import com.facebook.jni.HybridData; import com.facebook.proguard.annotations.DoNotStrip; +import com.facebook.react.bridge.CatalystInstance; import com.facebook.react.bridge.JSIModule; import com.facebook.react.bridge.JavaScriptContextHolder; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.queue.MessageQueueThread; import com.facebook.react.turbomodule.core.interfaces.JSCallInvokerHolder; import com.facebook.react.turbomodule.core.interfaces.TurboModule; +import com.facebook.react.turbomodule.core.interfaces.TurboModuleRegistry; import com.facebook.soloader.SoLoader; +import java.util.*; +import javax.annotation.Nullable; /** * This is the main class and entry point for TurboModules. * Note that this is a hybrid class, and has a C++ counterpart * This class installs the JSI bindings. It also implements the method to get a Java module, that the C++ counterpart calls. */ -public class TurboModuleManager implements JSIModule { +public class TurboModuleManager implements JSIModule, TurboModuleRegistry { static { SoLoader.loadLibrary("turbomodulejsijni"); } @@ -30,6 +34,8 @@ public class TurboModuleManager implements JSIModule { private final ReactApplicationContext mReactApplicationContext; private final TurboModuleManagerDelegate mTurbomoduleManagerDelegate; + private final Map mTurboModules = new HashMap<>(); + @DoNotStrip @SuppressWarnings("unused") private final HybridData mHybridData; @@ -41,9 +47,30 @@ public TurboModuleManager( mTurbomoduleManagerDelegate = tmmDelegate; } @DoNotStrip - @SuppressWarnings("unused") - private TurboModule getJavaModule(String name) { - return mTurbomoduleManagerDelegate.getModule(name); + @Nullable + protected TurboModule getJavaModule(String name) { + if (!mTurboModules.containsKey(name)) { + final TurboModule turboModule = mTurbomoduleManagerDelegate.getModule(name); + + if (turboModule != null) { + mTurboModules.put(name, turboModule); + } + } + + return mTurboModules.get(name); + } + + @Nullable + public TurboModule getModule(String name) { + return getJavaModule(name); + } + + public Collection getModules() { + return mTurboModules.values(); + } + + public boolean hasModule(String name) { + return mTurboModules.containsKey(name); } private native HybridData initHybrid(long jsContext, JSCallInvokerHolderImpl jsQueue, TurboModuleManagerDelegate tmmDelegate); @@ -59,9 +86,4 @@ public void initialize() {} @Override public void onCatalystInstanceDestroy() {} - - /** All applications must implement this interface, and provide the Java TurboModule class */ - public interface ModuleProvider { - TurboModule getModule(String name, ReactApplicationContext reactApplicationContext); - } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/interfaces/BUCK b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/interfaces/BUCK index d18e484bfb0111..fac8ba723f9a96 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/interfaces/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/interfaces/BUCK @@ -1,4 +1,4 @@ -load("//tools/build_defs/oss:rn_defs.bzl", "rn_android_library") +load("//tools/build_defs/oss:rn_defs.bzl", "react_native_dep", "rn_android_library") rn_android_library( name = "interfaces", @@ -9,4 +9,7 @@ rn_android_library( visibility = [ "PUBLIC", ], + deps = [ + react_native_dep("third-party/java/jsr-305:jsr-305"), + ], ) diff --git a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/interfaces/TurboModuleRegistry.java b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/interfaces/TurboModuleRegistry.java new file mode 100644 index 00000000000000..85794679bb4709 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/interfaces/TurboModuleRegistry.java @@ -0,0 +1,35 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.react.turbomodule.core.interfaces; + +import java.util.Collection; +import javax.annotation.Nullable; + +/** + * Interface to allow for creating and retrieving TurboModuels. + */ +public interface TurboModuleRegistry { + + /** + * Return the TurboModule instance that has that name `moduleName`. + * If the `moduleName` TurboModule hasn't been instantiated, instantiate it. + * If no TurboModule is registered under `moduleName`, return null. + */ + @Nullable + TurboModule getModule(String moduleName); + + /** + * Get all instantiated TurboModules. + */ + Collection getModules(); + + /** + * Has the TurboModule with name `moduleName` been instantiated? + */ + boolean hasModule(String moduleName); +} From 08d87cdacc7201822eee5abcd37cf343f4c54d13 Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Wed, 22 May 2019 13:11:53 -0700 Subject: [PATCH 0046/1084] Introduce ReactPackageTurboModuleManagerDelegate Summary: ## Summary People use `ReactPackage` instances to create NativeModules. To make the migration from NativeModule to TurboModule easy, I'm introducing a `TurboModuleManagerDelegate` that understands `ReactPackage`s, and uses them to lookup and create the Java TurboModule objects. This way, we don't have to change the way we declare NativeModules for the migration. ## TurboModule registration Each application should have its own subclass of `ReactPackageTurboModuleManagerDelegate`. This subclass is a hybrid class with a C++ and a Java part. The Java part can (and probably should) do nothing (for now). The C++ part has to implement the `moduleName -> jni::HostObject` and `moduleName, javaInstance -> jni::HostObject` functions for all TurboModules in the application. **Use Case: Migrating a NativeModule to TurboModule system** 1. Make the Java NativeModule extend `TurboModule`. (The reason why this doesn't happen automatically is probably because we haven't changed the Java codegen yet). 2. Modify the `moduleName -> jni::HostObject` or `moduleName, javaInstance -> jni::HostObject` functions to return the `TurboModule`. **Use Case: Adding a new TurboModule** 1. Add the TurboModule to a `ReactPackage` in the application. 2. Modify the `moduleName -> jni::HostObject` or `moduleName, javaInstance -> jni::HostObject` functions to return the TurboModule `jsi::HostObject`. **Note:** It's also possible to declare TurboModules by overriding the `getModule(String moduleName)` function of `ReactPackageTurboModuleManagerDelegate`. It's not a good idea, because it'll make switching between the NativeModule/TurboModule system difficult. Reviewed By: mdvacca Differential Revision: D15209129 fbshipit-source-id: 4b0a303595145be9b19d6f4934f956b91990f859 --- .../com/facebook/react/LazyReactPackage.java | 3 +- .../facebook/react/ReactInstanceManager.java | 4 + .../com/facebook/react/turbomodule/core/BUCK | 2 + ...eactPackageTurboModuleManagerDelegate.java | 104 ++++++++++++++++++ 4 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/ReactPackageTurboModuleManagerDelegate.java diff --git a/ReactAndroid/src/main/java/com/facebook/react/LazyReactPackage.java b/ReactAndroid/src/main/java/com/facebook/react/LazyReactPackage.java index 8c649f407f2ad8..5c8217b1b93814 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/LazyReactPackage.java +++ b/ReactAndroid/src/main/java/com/facebook/react/LazyReactPackage.java @@ -76,8 +76,7 @@ public Map getReactModuleInfos() { * @param reactContext * @return */ - /* package */ - Iterable getNativeModuleIterator(final ReactApplicationContext reactContext) { + public Iterable getNativeModuleIterator(final ReactApplicationContext reactContext) { final Map reactModuleInfoMap = getReactModuleInfoProvider().getReactModuleInfos(); final List nativeModules = getNativeModules(reactContext); diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java index 022eb1cf58b653..8c8bd4ceb6fa7b 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java @@ -307,6 +307,10 @@ public MemoryPressureRouter getMemoryPressureRouter() { return mMemoryPressureRouter; } + public List getPackages() { + return new ArrayList<>(mPackages); + } + private static void initializeSoLoaderIfNecessary(Context applicationContext) { // Call SoLoader.initialize here, this is required for apps that does not use exopackage and // does not use SoLoader for loading other native code except from the one used by React Native diff --git a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/BUCK b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/BUCK index c6ad15fff0d97c..90437ec640b389 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/BUCK @@ -21,6 +21,8 @@ rn_android_library( react_native_target("java/com/facebook/debug/holder:holder"), react_native_target("java/com/facebook/react/bridge:interfaces"), react_native_target("java/com/facebook/react/bridge:bridge"), + react_native_target("java/com/facebook/react/config:config"), + react_native_target("java/com/facebook/react:react"), ":jscallinvokerholder", ], exported_deps = [ diff --git a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/ReactPackageTurboModuleManagerDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/ReactPackageTurboModuleManagerDelegate.java new file mode 100644 index 00000000000000..fab21c9fca327e --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/ReactPackageTurboModuleManagerDelegate.java @@ -0,0 +1,104 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +package com.facebook.react.turbomodule.core; + +import com.facebook.react.ReactPackage; +import com.facebook.react.TurboReactPackage; +import com.facebook.react.bridge.CxxModuleWrapper; +import com.facebook.react.bridge.NativeModule; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.turbomodule.core.interfaces.TurboModule; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import javax.annotation.Nullable; +import java.util.List; + +public abstract class ReactPackageTurboModuleManagerDelegate extends TurboModuleManagerDelegate { + private final List mPackages = new ArrayList<>(); + private final Map mModules = new HashMap<>(); + private final ReactApplicationContext mReactApplicationContext; + + public ReactPackageTurboModuleManagerDelegate(ReactApplicationContext reactApplicationContext, List packages) { + super(reactApplicationContext); + mReactApplicationContext = reactApplicationContext; + for (ReactPackage reactPackage : packages) { + if (reactPackage instanceof TurboReactPackage) { + mPackages.add((TurboReactPackage)reactPackage); + } + } + } + + @Nullable + @Override + public TurboModule getModule(String moduleName) { + TurboModule module = resolveModule(moduleName); + if (module == null) { + return null; + } + + if (module instanceof CxxModuleWrapper) { + return null; + } + + + return module; + } + + @Nullable + @Override + public CxxModuleWrapper getLegacyCxxModule(String moduleName) { + TurboModule module = resolveModule(moduleName); + if (module == null) { + return null; + } + + if (!(module instanceof CxxModuleWrapper)) { + return null; + } + + + return (CxxModuleWrapper)module; + } + + private TurboModule resolveModule(String moduleName) { + if (mModules.containsKey(moduleName)) { + return mModules.get(moduleName); + } + + NativeModule resolvedModule = null; + + for (final TurboReactPackage pkg : mPackages) { + try { + NativeModule module = pkg.getModule(moduleName, mReactApplicationContext); + if (resolvedModule == null || module != null && module.canOverrideExistingModule()) { + resolvedModule = module; + } + } catch (IllegalArgumentException ex) { + /** + * TurboReactPackages can throw an IllegalArgumentException when a module + * isn't found. If this happens, it's safe to ignore the exception because + * a later TurboReactPackage could provide the module. + */ + } + } + + if (resolvedModule instanceof TurboModule) { + mModules.put(moduleName, (TurboModule)resolvedModule); + } else { + /** + * 1. The list of TurboReactPackages doesn't change. + * 2. TurboReactPackage.getModule is deterministic. Therefore, any two + * invocations of TurboReactPackage.getModule will return the same result + * given that they're provided the same arguments. + * + * Hence, if module lookup fails once, we know it'll fail every time. + * Therefore, we can write null to the mModules Map and avoid doing this + * extra work. + */ + mModules.put(moduleName, null); + } + + return mModules.get(moduleName); + } +} From e1102b43ff2f4757f48c71ade316c81c0b352345 Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Wed, 22 May 2019 13:11:53 -0700 Subject: [PATCH 0047/1084] Implement Android Cxx TurboModule support Summary: ## Summary This diff does a bunch of things: 1. The TurboModule resolution algorithm on Android now supports C++ TurboModules. 2. `SampleTurboCxxModule` is moved from `ReactCommon/turbomodule/samples/platform/ios/` to `ReactCommon/turbomodule/samples` so that both iOS and Android can share it. 3. `CatalystTurboModuleManagerDelegate::getTurboModule(std::string, JSCallInvoker)` now understands and returns `SampleTurboCxxModule`. Reviewed By: mdvacca Differential Revision: D15253477 fbshipit-source-id: 3def91911b091f8cf93be17decd245a0499ed718 --- .../RNTester/RNTesterTurboModuleProvider.mm | 2 +- .../core/jni/jsireact/TurboModuleManager.cpp | 5 + .../NativeSampleTurboCxxModuleSpecJSI.cpp | 0 .../NativeSampleTurboCxxModuleSpecJSI.h | 0 .../samples/SampleTurboCxxModule.cpp | 94 +++++++++++++++++++ .../samples/SampleTurboCxxModule.h | 44 +++++++++ .../platform/ios/RCTSampleTurboCxxModule.h | 30 ------ .../platform/ios/RCTSampleTurboCxxModule.mm | 69 +------------- 8 files changed, 145 insertions(+), 99 deletions(-) rename ReactCommon/turbomodule/samples/{platform/ios => }/NativeSampleTurboCxxModuleSpecJSI.cpp (100%) rename ReactCommon/turbomodule/samples/{platform/ios => }/NativeSampleTurboCxxModuleSpecJSI.h (100%) create mode 100644 ReactCommon/turbomodule/samples/SampleTurboCxxModule.cpp create mode 100644 ReactCommon/turbomodule/samples/SampleTurboCxxModule.h diff --git a/RNTester/RNTester/RNTesterTurboModuleProvider.mm b/RNTester/RNTester/RNTesterTurboModuleProvider.mm index b93d94878fef84..f25472b5689ebf 100644 --- a/RNTester/RNTester/RNTesterTurboModuleProvider.mm +++ b/RNTester/RNTester/RNTesterTurboModuleProvider.mm @@ -11,7 +11,7 @@ #import "RNTesterTurboModuleProvider.h" #import -#import +#import // NOTE: This entire file should be codegen'ed. diff --git a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/jsireact/TurboModuleManager.cpp b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/jsireact/TurboModuleManager.cpp index 8cfa6621a72075..34c30a5f00ba1b 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/jsireact/TurboModuleManager.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/jsireact/TurboModuleManager.cpp @@ -56,6 +56,11 @@ void TurboModuleManager::installJSIBindings() { } TurboModuleBinding::install(*runtime_, std::make_shared( [this](const std::string &name) { + auto cxxModule = turboModuleManagerDelegate_->cthis()->getTurboModule(name, jsCallInvoker_); + if (cxxModule) { + return cxxModule; + } + const auto moduleInstance = getJavaModule(name); return turboModuleManagerDelegate_->cthis()->getTurboModule(name, moduleInstance, jsCallInvoker_); }) diff --git a/ReactCommon/turbomodule/samples/platform/ios/NativeSampleTurboCxxModuleSpecJSI.cpp b/ReactCommon/turbomodule/samples/NativeSampleTurboCxxModuleSpecJSI.cpp similarity index 100% rename from ReactCommon/turbomodule/samples/platform/ios/NativeSampleTurboCxxModuleSpecJSI.cpp rename to ReactCommon/turbomodule/samples/NativeSampleTurboCxxModuleSpecJSI.cpp diff --git a/ReactCommon/turbomodule/samples/platform/ios/NativeSampleTurboCxxModuleSpecJSI.h b/ReactCommon/turbomodule/samples/NativeSampleTurboCxxModuleSpecJSI.h similarity index 100% rename from ReactCommon/turbomodule/samples/platform/ios/NativeSampleTurboCxxModuleSpecJSI.h rename to ReactCommon/turbomodule/samples/NativeSampleTurboCxxModuleSpecJSI.h diff --git a/ReactCommon/turbomodule/samples/SampleTurboCxxModule.cpp b/ReactCommon/turbomodule/samples/SampleTurboCxxModule.cpp new file mode 100644 index 00000000000000..4062e05ed7e65d --- /dev/null +++ b/ReactCommon/turbomodule/samples/SampleTurboCxxModule.cpp @@ -0,0 +1,94 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "SampleTurboCxxModule.h" + +#import + +using namespace facebook; + +namespace facebook { +namespace react { + +SampleTurboCxxModule::SampleTurboCxxModule( + std::shared_ptr jsInvoker) + : NativeSampleTurboCxxModuleSpecJSI(jsInvoker) {} + +void SampleTurboCxxModule::voidFunc(jsi::Runtime &rt) { + // Nothing to do +} + +bool SampleTurboCxxModule::getBool(jsi::Runtime &rt, bool arg) { + return arg; +} + +double SampleTurboCxxModule::getNumber(jsi::Runtime &rt, double arg) { + return arg; +} + +jsi::String SampleTurboCxxModule::getString( + jsi::Runtime &rt, + const jsi::String &arg) { + return jsi::String::createFromUtf8(rt, arg.utf8(rt)); +} + +jsi::Array SampleTurboCxxModule::getArray( + jsi::Runtime &rt, + const jsi::Array &arg) { + return deepCopyJSIArray(rt, arg); +} + +jsi::Object SampleTurboCxxModule::getObject( + jsi::Runtime &rt, + const jsi::Object &arg) { + return deepCopyJSIObject(rt, arg); +} + +jsi::Object SampleTurboCxxModule::getValue( + jsi::Runtime &rt, + double x, + const jsi::String &y, + const jsi::Object &z) { + // Note: return type isn't type-safe. + jsi::Object result(rt); + result.setProperty(rt, "x", jsi::Value(x)); + result.setProperty(rt, "y", jsi::String::createFromUtf8(rt, y.utf8(rt))); + result.setProperty(rt, "z", deepCopyJSIObject(rt, z)); + return result; +} + +void SampleTurboCxxModule::getValueWithCallback( + jsi::Runtime &rt, + const jsi::Function &callback) { + callback.call(rt, jsi::String::createFromUtf8(rt, "value from callback!")); +} + +jsi::Value SampleTurboCxxModule::getValueWithPromise( + jsi::Runtime &rt, + bool error) { + return createPromiseAsJSIValue( + rt, [error](jsi::Runtime &rt2, std::shared_ptr promise) { + if (error) { + promise->reject("intentional promise rejection"); + } else { + promise->resolve(jsi::String::createFromUtf8(rt2, "result!")); + } + }); +} + +jsi::Object SampleTurboCxxModule::getConstants(jsi::Runtime &rt) { + // Note: return type isn't type-safe. + jsi::Object result(rt); + result.setProperty(rt, "const1", jsi::Value(true)); + result.setProperty(rt, "const2", jsi::Value(375)); + result.setProperty( + rt, "const3", jsi::String::createFromUtf8(rt, "something")); + return result; +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/turbomodule/samples/SampleTurboCxxModule.h b/ReactCommon/turbomodule/samples/SampleTurboCxxModule.h new file mode 100644 index 00000000000000..6275b75e11d312 --- /dev/null +++ b/ReactCommon/turbomodule/samples/SampleTurboCxxModule.h @@ -0,0 +1,44 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#import + +#import "NativeSampleTurboCxxModuleSpecJSI.h" + +namespace facebook { +namespace react { + +/** + * A sample implementation of the C++ spec. In practice, this class can just + * extend jsi::HostObject directly, but using the spec provides build-time + * type-safety. + */ +class SampleTurboCxxModule : public NativeSampleTurboCxxModuleSpecJSI { + public: + SampleTurboCxxModule(std::shared_ptr jsInvoker); + + void voidFunc(jsi::Runtime &rt) override; + bool getBool(jsi::Runtime &rt, bool arg) override; + double getNumber(jsi::Runtime &rt, double arg) override; + jsi::String getString(jsi::Runtime &rt, const jsi::String &arg) override; + jsi::Array getArray(jsi::Runtime &rt, const jsi::Array &arg) override; + jsi::Object getObject(jsi::Runtime &rt, const jsi::Object &arg) override; + jsi::Object getValue( + jsi::Runtime &rt, + double x, + const jsi::String &y, + const jsi::Object &z) override; + void getValueWithCallback(jsi::Runtime &rt, const jsi::Function &callback) + override; + jsi::Value getValueWithPromise(jsi::Runtime &rt, bool error) override; + jsi::Object getConstants(jsi::Runtime &rt) override; +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/turbomodule/samples/platform/ios/RCTSampleTurboCxxModule.h b/ReactCommon/turbomodule/samples/platform/ios/RCTSampleTurboCxxModule.h index e4fc54f788f7b6..5987d53cd44c4c 100644 --- a/ReactCommon/turbomodule/samples/platform/ios/RCTSampleTurboCxxModule.h +++ b/ReactCommon/turbomodule/samples/platform/ios/RCTSampleTurboCxxModule.h @@ -7,39 +7,9 @@ #pragma once -#import - #import #import -#import "NativeSampleTurboCxxModuleSpecJSI.h" - -namespace facebook { -namespace react { - -/** - * A sample implementation of the C++ spec. In practice, this class can just extend jsi::HostObject - * directly, but using the spec provides build-time type-safety. - */ -class SampleTurboCxxModule : public NativeSampleTurboCxxModuleSpecJSI { -public: - SampleTurboCxxModule(std::shared_ptr jsInvoker); - - void voidFunc(jsi::Runtime &rt) override; - bool getBool(jsi::Runtime &rt, bool arg) override; - double getNumber(jsi::Runtime &rt, double arg) override; - jsi::String getString(jsi::Runtime &rt, const jsi::String &arg) override; - jsi::Array getArray(jsi::Runtime &rt, const jsi::Array &arg) override; - jsi::Object getObject(jsi::Runtime &rt, const jsi::Object &arg) override; - jsi::Object getValue(jsi::Runtime &rt, double x, const jsi::String &y, const jsi::Object &z) override; - void getValueWithCallback(jsi::Runtime &rt, const jsi::Function &callback) override; - jsi::Value getValueWithPromise(jsi::Runtime &rt, bool error) override; - jsi::Object getConstants(jsi::Runtime &rt) override; -}; - -} // namespace react -} // namespace facebook - /** * Sample backward-compatible RCTCxxModule-based module. * With jsi::HostObject, this class is no longer necessary, but the system supports it for diff --git a/ReactCommon/turbomodule/samples/platform/ios/RCTSampleTurboCxxModule.mm b/ReactCommon/turbomodule/samples/platform/ios/RCTSampleTurboCxxModule.mm index 4fa19f1e8baf6b..873661c9779ec9 100644 --- a/ReactCommon/turbomodule/samples/platform/ios/RCTSampleTurboCxxModule.mm +++ b/ReactCommon/turbomodule/samples/platform/ios/RCTSampleTurboCxxModule.mm @@ -8,78 +8,11 @@ #import "RCTSampleTurboCxxModule.h" #import -#import - +#import #import "SampleTurboCxxModuleLegacyImpl.h" using namespace facebook; -namespace facebook { -namespace react { - -SampleTurboCxxModule::SampleTurboCxxModule(std::shared_ptr jsInvoker) - : NativeSampleTurboCxxModuleSpecJSI(jsInvoker) {} - -void SampleTurboCxxModule::voidFunc(jsi::Runtime &rt) { - // Nothing to do -} - -bool SampleTurboCxxModule::getBool(jsi::Runtime &rt, bool arg) { - return arg; -} - -double SampleTurboCxxModule::getNumber(jsi::Runtime &rt, double arg) { - return arg; -} - -jsi::String SampleTurboCxxModule::getString(jsi::Runtime &rt, const jsi::String &arg) { - return jsi::String::createFromUtf8(rt, arg.utf8(rt)); -} - -jsi::Array SampleTurboCxxModule::getArray(jsi::Runtime &rt, const jsi::Array &arg) { - return deepCopyJSIArray(rt, arg); -} - -jsi::Object SampleTurboCxxModule::getObject(jsi::Runtime &rt, const jsi::Object &arg) { - return deepCopyJSIObject(rt, arg); -} - -jsi::Object SampleTurboCxxModule::getValue(jsi::Runtime &rt, double x, const jsi::String &y, const jsi::Object &z) { - // Note: return type isn't type-safe. - jsi::Object result(rt); - result.setProperty(rt, "x", jsi::Value(x)); - result.setProperty(rt, "y", jsi::String::createFromUtf8(rt, y.utf8(rt))); - result.setProperty(rt, "z", deepCopyJSIObject(rt, z)); - return result; -} - -void SampleTurboCxxModule::getValueWithCallback(jsi::Runtime &rt, const jsi::Function &callback) { - callback.call(rt, jsi::String::createFromUtf8(rt, "value from callback!")); -} - -jsi::Value SampleTurboCxxModule::getValueWithPromise(jsi::Runtime &rt, bool error) { - return createPromiseAsJSIValue(rt, [error](jsi::Runtime &rt2, std::shared_ptr promise) { - if (error) { - promise->reject("intentional promise rejection"); - } else { - promise->resolve(jsi::String::createFromUtf8(rt2, "result!")); - } - }); -} - -jsi::Object SampleTurboCxxModule::getConstants(jsi::Runtime &rt) { - // Note: return type isn't type-safe. - jsi::Object result(rt); - result.setProperty(rt, "const1", jsi::Value(true)); - result.setProperty(rt, "const2", jsi::Value(375)); - result.setProperty(rt, "const3", jsi::String::createFromUtf8(rt, "something")); - return result; -} - -} // namespace react -} // namespace facebook - - // ObjC++ wrapper. @implementation RCTSampleTurboCxxModule_v1 From 37583bd6e8c4c583363c937857ccd508e56fe34d Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Wed, 22 May 2019 13:11:53 -0700 Subject: [PATCH 0048/1084] Only create TurboModule jsi::HostObject if Java module is non-null Summary: ## Summary If the Java instance of a TurboModule is null, then the resultant JS object returned from `TurboModuleRegistry` should also be null. Reviewed By: mdvacca Differential Revision: D15253476 fbshipit-source-id: 83a6b9aa97b547aeecf9b285986ad0f5b9e413da --- .../turbomodule/core/jni/jsireact/TurboModuleManager.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/jsireact/TurboModuleManager.cpp b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/jsireact/TurboModuleManager.cpp index 34c30a5f00ba1b..995d274dda0fbe 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/jsireact/TurboModuleManager.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/jsireact/TurboModuleManager.cpp @@ -62,7 +62,12 @@ void TurboModuleManager::installJSIBindings() { } const auto moduleInstance = getJavaModule(name); - return turboModuleManagerDelegate_->cthis()->getTurboModule(name, moduleInstance, jsCallInvoker_); + + if (moduleInstance) { + return turboModuleManagerDelegate_->cthis()->getTurboModule(name, moduleInstance, jsCallInvoker_); + } + + return std::shared_ptr(nullptr); }) ); } From 5127ac5c2a95f2505b5688fa7c2f810db725ca0f Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Wed, 22 May 2019 13:11:53 -0700 Subject: [PATCH 0049/1084] Implement support for legacy CxxModules Summary: ## Background Legacy Cxx NativeModules are implemented as Hybrid classes. Essentially, when a Cxx NativeModule is requested, you instantiate its hybrid class, which then creates a C++ counterpart. Then, the bridge uses the C++ counterpart's `getModule()` method to obtain ownership of the Cxx NativeModule. ## Summary This diff implements backwards-compability for Cxx NativeModules. If a Cxx NativeModule implements the `TurboModule` interface, then when the module is requested by name, we: 1. Instantiate its Java hybrid class, createing a C++ counterpart. 3. Obtain the CxxModule from the C++ counterpart using `getModule()` and use it to create a `TurboCxxModule` instance (this forwards all JavaScript method calls to the CxxModule) inside `TurboModuleManager`. 5. Return this `TurboCxxModule` to JS. Reviewed By: mdvacca Differential Revision: D15252041 fbshipit-source-id: cdbb62632d7a8735f7687daf62de63df9e3ad2c5 --- .../core/jni/jsireact/TurboModuleManager.cpp | 17 ++++++++++++++--- .../core/jni/jsireact/TurboModuleManager.h | 2 ++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/jsireact/TurboModuleManager.cpp b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/jsireact/TurboModuleManager.cpp index 995d274dda0fbe..0a7854f93ab8a7 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/jsireact/TurboModuleManager.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/jsireact/TurboModuleManager.cpp @@ -12,7 +12,7 @@ #include #include - +#include #include #include "TurboModuleManager.h" @@ -55,13 +55,18 @@ void TurboModuleManager::installJSIBindings() { return; // Runtime doesn't exist when attached to Chrome debugger. } TurboModuleBinding::install(*runtime_, std::make_shared( - [this](const std::string &name) { + [this](const std::string &name) -> std::shared_ptr { auto cxxModule = turboModuleManagerDelegate_->cthis()->getTurboModule(name, jsCallInvoker_); if (cxxModule) { return cxxModule; } - const auto moduleInstance = getJavaModule(name); + auto legacyCxxModule = getLegacyCxxJavaModule(name); + if (legacyCxxModule) { + return std::make_shared(legacyCxxModule->cthis()->getModule(), jsCallInvoker_); + } + + auto moduleInstance = getJavaModule(name); if (moduleInstance) { return turboModuleManagerDelegate_->cthis()->getTurboModule(name, moduleInstance, jsCallInvoker_); @@ -80,5 +85,11 @@ jni::global_ref TurboModuleManager::getJavaModule(std::string name return module; } +jni::global_ref TurboModuleManager::getLegacyCxxJavaModule(std::string name) { + static auto method = turboModuleManagerDelegate_->getClass()->getMethod(const std::string&)>("getLegacyCxxModule"); + auto module = jni::make_global(method(turboModuleManagerDelegate_.get(), name)); + return module; +} + } // namespace react } // namespace facebook diff --git a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/jsireact/TurboModuleManager.h b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/jsireact/TurboModuleManager.h index 305b3b18594174..fbb29834e0cf4d 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/jsireact/TurboModuleManager.h +++ b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/jsireact/TurboModuleManager.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -37,6 +38,7 @@ class TurboModuleManager : public jni::HybridClass { jni::global_ref turboModuleManagerDelegate_; jni::global_ref getJavaModule(std::string name); + jni::global_ref getLegacyCxxJavaModule(std::string name); void installJSIBindings(); explicit TurboModuleManager( jni::alias_ref jThis, From 9fb31d15381647c7c7a28ebe28f8a8676d65eb19 Mon Sep 17 00:00:00 2001 From: Blair Vanderhoof Date: Wed, 22 May 2019 13:20:03 -0700 Subject: [PATCH 0050/1084] Fix layout animation crash Summary: As of D14529038, LayoutAnimations can sometimes throw an exception due to the view being null. This can happen when elements are removed/added and is not fixable in product code. This is a temporary fix - the root cause for this issue will be fixed soon. Reviewed By: lunaleaps Differential Revision: D15428791 fbshipit-source-id: 41200e572ed7d5d470754792c5576a0ea23fe946 --- .../react/uimanager/NativeViewHierarchyManager.java | 2 +- .../layoutanimation/LayoutAnimationController.java | 12 ++++++++---- .../facebook/react/views/view/ReactViewGroup.java | 4 +++- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java index 48d1daefd5f855..2aa8abf9794833 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java @@ -444,7 +444,7 @@ public synchronized void manageChildren( arrayContains(tagsToDelete, viewToRemove.getId())) { // The view will be removed and dropped by the 'delete' layout animation // instead, so do nothing - } else { + } else if (viewToManage != null) { viewManager.removeViewAt(viewToManage, normalizedIndexToRemove); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationController.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationController.java index 232cb01f9071e5..cad0a0cac29c06 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationController.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationController.java @@ -82,10 +82,14 @@ public void reset() { } public boolean shouldAnimateLayout(View viewToAnimate) { - // if view parent is null, skip animation: view have been clipped, we don't want animation to - // resume when view is re-attached to parent, which is the standard android animation behavior. - // If there's a layout handling animation going on, it should be animated nonetheless since the - // ongoing animation needs to be updated. + // if view is null or the view parent is null, skip animation: view have been clipped, + // we don't want animation to resume when view is re-attached to parent, which is the + // standard android animation behavior. If there's a layout handling animation going on, + // it should be animated nonetheless since the ongoing animation needs to be updated. + + if (viewToAnimate == null) { + return false; + } return (mShouldAnimateLayout && viewToAnimate.getParent() != null) || mLayoutHandlers.get(viewToAnimate.getId()) != null; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java index 4e89e9dbf59b9b..e1cec5d41a26ab 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java @@ -465,7 +465,9 @@ public void removeViewAt(int index) { mDrawingOrderHelper.handleRemoveView(getChildAt(index)); setChildrenDrawingOrderEnabled(mDrawingOrderHelper.shouldEnableCustomDrawingOrder()); - super.removeViewAt(index); + if (getChildAt(index) != null) { + super.removeViewAt(index); + } } @Override From f80a1c2146aaf7a5a898844deeb7d3dd2fd27945 Mon Sep 17 00:00:00 2001 From: Spencer Ahrens Date: Wed, 22 May 2019 16:48:25 -0700 Subject: [PATCH 0051/1084] Turn off no-inline-styles lint internally Summary: no-inline-styles is a false positive more often than not because it fires even when compositing dynamic styles which must be done inline. It's not that big a deal anyway so I'm just turning it off to reduce noise on diffs. Also removes all existing supressions. Reviewed By: yungsters Differential Revision: D15457771 fbshipit-source-id: 44fbd058834e70966b71fbe4eb7af40d6f3a0a57 --- RNTester/js/TextExample.android.js | 4 +--- RNTester/js/ViewExample.js | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/RNTester/js/TextExample.android.js b/RNTester/js/TextExample.android.js index efc53aa8d4a54b..ae21774375d034 100644 --- a/RNTester/js/TextExample.android.js +++ b/RNTester/js/TextExample.android.js @@ -8,12 +8,10 @@ * @flow */ -/* eslint-disable react-native/no-inline-styles */ - 'use strict'; const React = require('react'); -const {Image, StyleSheet, Text, View} = require('react-native'); +const {StyleSheet, Text, View} = require('react-native'); const RNTesterBlock = require('./RNTesterBlock'); const RNTesterPage = require('./RNTesterPage'); const TextInlineView = require('./Shared/TextInlineView'); diff --git a/RNTester/js/ViewExample.js b/RNTester/js/ViewExample.js index 25dc2641f72657..6c27499cce81ff 100644 --- a/RNTester/js/ViewExample.js +++ b/RNTester/js/ViewExample.js @@ -10,8 +10,6 @@ 'use strict'; -/* eslint-disable react-native/no-inline-styles */ - const React = require('react'); const { StyleSheet, From 116ac65feade4e4cfb7b91b6a90ecdfb8fd137f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Wed, 22 May 2019 17:09:00 -0700 Subject: [PATCH 0052/1084] Add spec for AnimatedModule (#24911) Summary: Part of #24875. Added `strict-local` to the NativeModuleHelper btw. ## Changelog [General] [Added] - TM add spec for AnimatedModule Pull Request resolved: https://github.com/facebook/react-native/pull/24911 Reviewed By: rickhanlonii Differential Revision: D15434114 Pulled By: fkgozali fbshipit-source-id: ea9215306ebf969795ce755270b8fdc14c52da9c --- .../Animated/src/NativeAnimatedHelper.js | 77 ++++++++++--------- .../Animated/src/NativeAnimatedModule.js | 70 +++++++++++++++++ .../Animated/src/__tests__/Animated-test.js | 4 + .../src/__tests__/AnimatedNative-test.js | 8 +- 4 files changed, 118 insertions(+), 41 deletions(-) create mode 100644 Libraries/Animated/src/NativeAnimatedModule.js diff --git a/Libraries/Animated/src/NativeAnimatedHelper.js b/Libraries/Animated/src/NativeAnimatedHelper.js index 05bd6e37a8a4d2..a5352046fbbf9f 100644 --- a/Libraries/Animated/src/NativeAnimatedHelper.js +++ b/Libraries/Animated/src/NativeAnimatedHelper.js @@ -4,30 +4,27 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @flow + * @flow strict-local * @format */ 'use strict'; -const NativeAnimatedModule = require('../../BatchedBridge/NativeModules') - .NativeAnimatedModule; -const NativeEventEmitter = require('../../EventEmitter/NativeEventEmitter'); +import NativeEventEmitter from '../../EventEmitter/NativeEventEmitter'; +import type { + EventMapping, + AnimatedNodeConfig, + AnimatingNodeConfig, +} from './NativeAnimatedModule'; +import NativeAnimatedModule from './NativeAnimatedModule'; +import invariant from 'invariant'; -const invariant = require('invariant'); - -import type {AnimationConfig} from './animations/Animation'; +import type {AnimationConfig, EndCallback} from './animations/Animation'; +import type {InterpolationConfigType} from './nodes/AnimatedInterpolation'; import type {EventConfig} from './AnimatedEvent'; let __nativeAnimatedNodeTagCount = 1; /* used for animated nodes */ let __nativeAnimationIdCount = 1; /* used for started animations */ -type EndResult = {finished: boolean}; -type EndCallback = (result: EndResult) => void; -type EventMapping = { - nativeEventPath: Array, - animatedValueTag: ?number, -}; - let nativeEventEmitter; /** @@ -35,36 +32,36 @@ let nativeEventEmitter; * the native module methods */ const API = { - createAnimatedNode: function(tag: ?number, config: Object): void { - assertNativeAnimatedModule(); + createAnimatedNode: function(tag: ?number, config: AnimatedNodeConfig): void { + invariant(NativeAnimatedModule, 'Native animated module is not available'); NativeAnimatedModule.createAnimatedNode(tag, config); }, startListeningToAnimatedNodeValue: function(tag: ?number) { - assertNativeAnimatedModule(); + invariant(NativeAnimatedModule, 'Native animated module is not available'); NativeAnimatedModule.startListeningToAnimatedNodeValue(tag); }, stopListeningToAnimatedNodeValue: function(tag: ?number) { - assertNativeAnimatedModule(); + invariant(NativeAnimatedModule, 'Native animated module is not available'); NativeAnimatedModule.stopListeningToAnimatedNodeValue(tag); }, connectAnimatedNodes: function(parentTag: ?number, childTag: ?number): void { - assertNativeAnimatedModule(); + invariant(NativeAnimatedModule, 'Native animated module is not available'); NativeAnimatedModule.connectAnimatedNodes(parentTag, childTag); }, disconnectAnimatedNodes: function( parentTag: ?number, childTag: ?number, ): void { - assertNativeAnimatedModule(); + invariant(NativeAnimatedModule, 'Native animated module is not available'); NativeAnimatedModule.disconnectAnimatedNodes(parentTag, childTag); }, startAnimatingNode: function( animationId: ?number, nodeTag: ?number, - config: Object, + config: AnimatingNodeConfig, endCallback: EndCallback, ): void { - assertNativeAnimatedModule(); + invariant(NativeAnimatedModule, 'Native animated module is not available'); NativeAnimatedModule.startAnimatingNode( animationId, nodeTag, @@ -73,41 +70,41 @@ const API = { ); }, stopAnimation: function(animationId: ?number) { - assertNativeAnimatedModule(); + invariant(NativeAnimatedModule, 'Native animated module is not available'); NativeAnimatedModule.stopAnimation(animationId); }, setAnimatedNodeValue: function(nodeTag: ?number, value: ?number): void { - assertNativeAnimatedModule(); + invariant(NativeAnimatedModule, 'Native animated module is not available'); NativeAnimatedModule.setAnimatedNodeValue(nodeTag, value); }, setAnimatedNodeOffset: function(nodeTag: ?number, offset: ?number): void { - assertNativeAnimatedModule(); + invariant(NativeAnimatedModule, 'Native animated module is not available'); NativeAnimatedModule.setAnimatedNodeOffset(nodeTag, offset); }, flattenAnimatedNodeOffset: function(nodeTag: ?number): void { - assertNativeAnimatedModule(); + invariant(NativeAnimatedModule, 'Native animated module is not available'); NativeAnimatedModule.flattenAnimatedNodeOffset(nodeTag); }, extractAnimatedNodeOffset: function(nodeTag: ?number): void { - assertNativeAnimatedModule(); + invariant(NativeAnimatedModule, 'Native animated module is not available'); NativeAnimatedModule.extractAnimatedNodeOffset(nodeTag); }, connectAnimatedNodeToView: function( nodeTag: ?number, viewTag: ?number, ): void { - assertNativeAnimatedModule(); + invariant(NativeAnimatedModule, 'Native animated module is not available'); NativeAnimatedModule.connectAnimatedNodeToView(nodeTag, viewTag); }, disconnectAnimatedNodeFromView: function( nodeTag: ?number, viewTag: ?number, ): void { - assertNativeAnimatedModule(); + invariant(NativeAnimatedModule, 'Native animated module is not available'); NativeAnimatedModule.disconnectAnimatedNodeFromView(nodeTag, viewTag); }, dropAnimatedNode: function(tag: ?number): void { - assertNativeAnimatedModule(); + invariant(NativeAnimatedModule, 'Native animated module is not available'); NativeAnimatedModule.dropAnimatedNode(tag); }, addAnimatedEventToView: function( @@ -115,7 +112,7 @@ const API = { eventName: string, eventMapping: EventMapping, ) { - assertNativeAnimatedModule(); + invariant(NativeAnimatedModule, 'Native animated module is not available'); NativeAnimatedModule.addAnimatedEventToView( viewTag, eventName, @@ -127,7 +124,7 @@ const API = { eventName: string, animatedNodeTag: ?number, ) { - assertNativeAnimatedModule(); + invariant(NativeAnimatedModule, 'Native animated module is not available'); NativeAnimatedModule.removeAnimatedEventFromView( viewTag, eventName, @@ -197,7 +194,12 @@ function addWhitelistedInterpolationParam(param: string): void { SUPPORTED_INTERPOLATION_PARAMS[param] = true; } -function validateTransform(configs: Array): void { +function validateTransform( + configs: Array< + | {type: 'animated', property: string, nodeTag: ?number} + | {type: 'static', property: string, value: number}, + >, +): void { configs.forEach(config => { if (!TRANSFORM_WHITELIST.hasOwnProperty(config.property)) { throw new Error( @@ -209,7 +211,7 @@ function validateTransform(configs: Array): void { }); } -function validateStyles(styles: Object): void { +function validateStyles(styles: {[key: string]: ?number}): void { for (const key in styles) { if (!STYLES_WHITELIST.hasOwnProperty(key)) { throw new Error( @@ -219,7 +221,7 @@ function validateStyles(styles: Object): void { } } -function validateInterpolation(config: Object): void { +function validateInterpolation(config: InterpolationConfigType): void { for (const key in config) { if (!SUPPORTED_INTERPOLATION_PARAMS.hasOwnProperty(key)) { throw new Error( @@ -244,7 +246,7 @@ function assertNativeAnimatedModule(): void { let _warnedMissingNativeAnimated = false; function shouldUseNativeDriver(config: AnimationConfig | EventConfig): boolean { - if (config.useNativeDriver && !NativeAnimatedModule) { + if (config.useNativeDriver === true && !NativeAnimatedModule) { if (!_warnedMissingNativeAnimated) { console.warn( 'Animated: `useNativeDriver` is not supported because the native ' + @@ -261,7 +263,7 @@ function shouldUseNativeDriver(config: AnimationConfig | EventConfig): boolean { return config.useNativeDriver || false; } -function transformDataType(value: any): number { +function transformDataType(value: number | string): number { // Change the string type to number type so we can reuse the same logic in // iOS and Android platform if (typeof value !== 'string') { @@ -290,6 +292,7 @@ module.exports = { assertNativeAnimatedModule, shouldUseNativeDriver, transformDataType, + // $FlowExpectedError - unsafe getter lint suppresion get nativeEventEmitter() { if (!nativeEventEmitter) { nativeEventEmitter = new NativeEventEmitter(NativeAnimatedModule); diff --git a/Libraries/Animated/src/NativeAnimatedModule.js b/Libraries/Animated/src/NativeAnimatedModule.js new file mode 100644 index 00000000000000..b13d6f33191bc4 --- /dev/null +++ b/Libraries/Animated/src/NativeAnimatedModule.js @@ -0,0 +1,70 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +type EndResult = {finished: boolean}; +type EndCallback = (result: EndResult) => void; + +export type EventMapping = {| + nativeEventPath: Array, + animatedValueTag: ?number, +|}; + +export type AnimatedNodeConfig = {| + // TODO: Type this with better enums. + type: string, +|}; + +export type AnimatingNodeConfig = {| + // TODO: Type this with better enums. + type: string, +|}; + +export interface Spec extends TurboModule { + +createAnimatedNode: (tag: ?number, config: AnimatedNodeConfig) => void; + +startListeningToAnimatedNodeValue: (tag: ?number) => void; + +stopListeningToAnimatedNodeValue: (tag: ?number) => void; + +connectAnimatedNodes: (parentTag: ?number, childTag: ?number) => void; + +disconnectAnimatedNodes: (parentTag: ?number, childTag: ?number) => void; + +startAnimatingNode: ( + animationId: ?number, + nodeTag: ?number, + config: AnimatingNodeConfig, + endCallback: EndCallback, + ) => void; + +stopAnimation: (animationId: ?number) => void; + +setAnimatedNodeValue: (nodeTag: ?number, value: ?number) => void; + +setAnimatedNodeOffset: (nodeTag: ?number, offset: ?number) => void; + +flattenAnimatedNodeOffset: (nodeTag: ?number) => void; + +extractAnimatedNodeOffset: (nodeTag: ?number) => void; + +connectAnimatedNodeToView: (nodeTag: ?number, viewTag: ?number) => void; + +disconnectAnimatedNodeFromView: (nodeTag: ?number, viewTag: ?number) => void; + +dropAnimatedNode: (tag: ?number) => void; + +addAnimatedEventToView: ( + viewTag: ?number, + eventName: string, + eventMapping: EventMapping, + ) => void; + +removeAnimatedEventFromView: ( + viewTag: ?number, + eventName: string, + animatedNodeTag: ?number, + ) => void; + + // Events + +addListener: (eventName: string) => void; + +removeListeners: (count: number) => void; +} + +export default TurboModuleRegistry.get('NativeAnimatedModule'); diff --git a/Libraries/Animated/src/__tests__/Animated-test.js b/Libraries/Animated/src/__tests__/Animated-test.js index 11c1ad922efede..fbfdc5dd73f3a1 100644 --- a/Libraries/Animated/src/__tests__/Animated-test.js +++ b/Libraries/Animated/src/__tests__/Animated-test.js @@ -10,6 +10,10 @@ 'use strict'; +jest.mock('../../../BatchedBridge/NativeModules', () => ({ + NativeAnimatedModule: {}, +})); + let Animated = require('../Animated'); describe('Animated tests', () => { beforeEach(() => { diff --git a/Libraries/Animated/src/__tests__/AnimatedNative-test.js b/Libraries/Animated/src/__tests__/AnimatedNative-test.js index e90f2341b7d90c..38e201928c2e5e 100644 --- a/Libraries/Animated/src/__tests__/AnimatedNative-test.js +++ b/Libraries/Animated/src/__tests__/AnimatedNative-test.js @@ -22,9 +22,10 @@ jest .setMock('../../../Lists/FlatList', ClassComponentMock) .setMock('../../../Lists/SectionList', ClassComponentMock) .setMock('react', {Component: class {}}) - .setMock('../../../BatchedBridge/NativeModules', { + .mock('../../../BatchedBridge/NativeModules', () => ({ NativeAnimatedModule: {}, - }) + })) + .mock('../NativeAnimatedModule') .mock('../../../EventEmitter/NativeEventEmitter') // findNodeHandle is imported from ReactNative so mock that whole module. .setMock('../../../Renderer/shims/ReactNative', {findNodeHandle: () => 1}); @@ -43,8 +44,7 @@ function createAndMountComponent(ComponentClass, props) { } describe('Native Animated', () => { - const nativeAnimatedModule = require('../../../BatchedBridge/NativeModules') - .NativeAnimatedModule; + const nativeAnimatedModule = require('../NativeAnimatedModule').default; beforeEach(() => { nativeAnimatedModule.addAnimatedEventToView = jest.fn(); From 32340d377bb1f9492a640ef543ffdb0440b17c16 Mon Sep 17 00:00:00 2001 From: Uilque Messias Date: Wed, 22 May 2019 18:19:10 -0700 Subject: [PATCH 0053/1084] Add spec for DialogManagerAndroid (#24912) Summary: Part of #24875. ## Changelog [General] [Added] - TM add spec for DialogManagerAndroid Pull Request resolved: https://github.com/facebook/react-native/pull/24912 Reviewed By: fkgozali Differential Revision: D15433854 Pulled By: RSNara fbshipit-source-id: e7234debe16de5afbc770f8feee2471f41b54427 --- Libraries/Alert/Alert.js | 63 ++++++++++--------- Libraries/Alert/RCTAlertManager.android.js | 8 ++- .../specs/NativeDialogManagerAndroid.js | 49 +++++++++++++++ .../PermissionsAndroid/PermissionsAndroid.js | 10 ++- 4 files changed, 95 insertions(+), 35 deletions(-) create mode 100644 Libraries/NativeModules/specs/NativeDialogManagerAndroid.js diff --git a/Libraries/Alert/Alert.js b/Libraries/Alert/Alert.js index 9d64acda4e63c4..1e03d1d136df3a 100644 --- a/Libraries/Alert/Alert.js +++ b/Libraries/Alert/Alert.js @@ -10,9 +10,13 @@ 'use strict'; -const NativeModules = require('../BatchedBridge/NativeModules'); +import NativeModules from '../BatchedBridge/NativeModules'; +import Platform from '../Utilities/Platform'; +import DialogManagerAndroid, { + type DialogOptions, +} from '../NativeModules/specs/NativeDialogManagerAndroid'; + const RCTAlertManager = NativeModules.AlertManager; -const Platform = require('../Utilities/Platform'); export type Buttons = Array<{ text?: string, @@ -53,14 +57,19 @@ class Alert { if (Platform.OS === 'ios') { Alert.prompt(title, message, buttons, 'default'); } else if (Platform.OS === 'android') { - let config = { + if (!DialogManagerAndroid) { + return; + } + const constants = DialogManagerAndroid.getConstants(); + + const config: DialogOptions = { title: title || '', message: message || '', cancelable: false, }; - if (options) { - config = {...config, cancelable: options.cancelable}; + if (options && options.cancelable) { + config.cancelable = options.cancelable; } // At most three buttons (neutral, negative, positive). Ignore rest. // The text 'OK' should be probably localized. iOS Alert does that in native. @@ -70,38 +79,32 @@ class Alert { const buttonPositive = validButtons.pop(); const buttonNegative = validButtons.pop(); const buttonNeutral = validButtons.pop(); + if (buttonNeutral) { - config = {...config, buttonNeutral: buttonNeutral.text || ''}; + config.buttonNeutral = buttonNeutral.text || ''; } if (buttonNegative) { - config = {...config, buttonNegative: buttonNegative.text || ''}; + config.buttonNegative = buttonNegative.text || ''; } if (buttonPositive) { - config = {...config, buttonPositive: buttonPositive.text || ''}; + config.buttonPositive = buttonPositive.text || ''; } - NativeModules.DialogManagerAndroid.showAlert( - config, - errorMessage => console.warn(errorMessage), - (action, buttonKey) => { - if (action === NativeModules.DialogManagerAndroid.buttonClicked) { - if ( - buttonKey === NativeModules.DialogManagerAndroid.buttonNeutral - ) { - buttonNeutral.onPress && buttonNeutral.onPress(); - } else if ( - buttonKey === NativeModules.DialogManagerAndroid.buttonNegative - ) { - buttonNegative.onPress && buttonNegative.onPress(); - } else if ( - buttonKey === NativeModules.DialogManagerAndroid.buttonPositive - ) { - buttonPositive.onPress && buttonPositive.onPress(); - } - } else if (action === NativeModules.DialogManagerAndroid.dismissed) { - options && options.onDismiss && options.onDismiss(); + + const onAction = (action, buttonKey) => { + if (action === constants.buttonClicked) { + if (buttonKey === constants.buttonNeutral) { + buttonNeutral.onPress && buttonNeutral.onPress(); + } else if (buttonKey === constants.buttonNegative) { + buttonNegative.onPress && buttonNegative.onPress(); + } else if (buttonKey === constants.buttonPositive) { + buttonPositive.onPress && buttonPositive.onPress(); } - }, - ); + } else if (action === constants.dismissed) { + options && options.onDismiss && options.onDismiss(); + } + }; + const onError = errorMessage => console.warn(errorMessage); + DialogManagerAndroid.showAlert(config, onError, onAction); } } diff --git a/Libraries/Alert/RCTAlertManager.android.js b/Libraries/Alert/RCTAlertManager.android.js index 843dec92fe47cb..43f49a94e50bb1 100644 --- a/Libraries/Alert/RCTAlertManager.android.js +++ b/Libraries/Alert/RCTAlertManager.android.js @@ -9,14 +9,18 @@ 'use strict'; -const NativeModules = require('../BatchedBridge/NativeModules'); +import NativeDialogManagerAndroid from '../NativeModules/specs/NativeDialogManagerAndroid'; function emptyCallback() {} module.exports = { alertWithArgs: function(args, callback) { // TODO(5998984): Polyfill it correctly with DialogManagerAndroid - NativeModules.DialogManagerAndroid.showAlert( + if (!NativeDialogManagerAndroid) { + return; + } + + NativeDialogManagerAndroid.showAlert( args, emptyCallback, callback || emptyCallback, diff --git a/Libraries/NativeModules/specs/NativeDialogManagerAndroid.js b/Libraries/NativeModules/specs/NativeDialogManagerAndroid.js new file mode 100644 index 00000000000000..ae8c121529fac3 --- /dev/null +++ b/Libraries/NativeModules/specs/NativeDialogManagerAndroid.js @@ -0,0 +1,49 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +/* 'buttonClicked' | 'dismissed' */ +type DialogAction = string; +/* + buttonPositive = -1, + buttonNegative = -2, + buttonNeutral = -3 +*/ +type DialogButtonKey = number; +export type DialogOptions = {| + title?: string, + message?: string, + buttonPositive?: string, + buttonNegative?: string, + buttonNeutral?: string, + items?: Array, + cancelable?: boolean, +|}; + +export interface Spec extends TurboModule { + +getConstants: () => {| + +buttonClicked: DialogAction, + +dismissed: DialogAction, + +buttonPositive: DialogButtonKey, + +buttonNegative: DialogButtonKey, + +buttonNeutral: DialogButtonKey, + |}; + +showAlert: ( + config: DialogOptions, + onError: (string) => void, + onAction: (action: DialogAction, buttonKey?: DialogButtonKey) => void, + ) => void; +} + +export default TurboModuleRegistry.get('DialogManagerAndroid'); diff --git a/Libraries/PermissionsAndroid/PermissionsAndroid.js b/Libraries/PermissionsAndroid/PermissionsAndroid.js index ae35e07cac6073..91522c89109012 100644 --- a/Libraries/PermissionsAndroid/PermissionsAndroid.js +++ b/Libraries/PermissionsAndroid/PermissionsAndroid.js @@ -10,6 +10,7 @@ 'use strict'; +import NativeDialogManagerAndroid from '../NativeModules/specs/NativeDialogManagerAndroid'; const NativeModules = require('../BatchedBridge/NativeModules'); export type Rationale = { @@ -134,10 +135,13 @@ class PermissionsAndroid { permission, ); - if (shouldShowRationale) { + if (shouldShowRationale && !!NativeDialogManagerAndroid) { return new Promise((resolve, reject) => { - NativeModules.DialogManagerAndroid.showAlert( - rationale, + const options = { + ...rationale, + }; + NativeDialogManagerAndroid.showAlert( + options, () => reject(new Error('Error showing rationale')), () => resolve( From b355ba56dbb88e8ba54114f4cbc0cb38bcaa1881 Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Wed, 22 May 2019 18:19:10 -0700 Subject: [PATCH 0054/1084] Fix flow errors Summary: This diff fixes the flow errors that surfaced from flow-typing DialogManagerAndorid and deleting NativeDialogManagerAndroid. I also migrated all imports of NativeDialogManagerAndorid to import the module from `react-native-implementation.js`. Reviewed By: fkgozali Differential Revision: D15440162 fbshipit-source-id: 2fdfb68104bc8ffb93c0c77fe15aacadc182f62f --- .../NativeModules/specs/NativeDialogManagerAndroid.js | 8 ++++---- Libraries/react-native/react-native-implementation.js | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Libraries/NativeModules/specs/NativeDialogManagerAndroid.js b/Libraries/NativeModules/specs/NativeDialogManagerAndroid.js index ae8c121529fac3..1ffb71c8ce8260 100644 --- a/Libraries/NativeModules/specs/NativeDialogManagerAndroid.js +++ b/Libraries/NativeModules/specs/NativeDialogManagerAndroid.js @@ -23,10 +23,10 @@ type DialogAction = string; type DialogButtonKey = number; export type DialogOptions = {| title?: string, - message?: string, - buttonPositive?: string, - buttonNegative?: string, - buttonNeutral?: string, + message?: Stringish, + buttonPositive?: Stringish, + buttonNegative?: Stringish, + buttonNeutral?: Stringish, items?: Array, cancelable?: boolean, |}; diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js index 8a4acfc1dfb280..32142a1823641b 100644 --- a/Libraries/react-native/react-native-implementation.js +++ b/Libraries/react-native/react-native-implementation.js @@ -247,6 +247,9 @@ module.exports = { get Linking() { return require('Linking'); }, + get NativeDialogManagerAndroid() { + return require('NativeDialogManagerAndroid').default; + }, get NativeEventEmitter() { return require('NativeEventEmitter'); }, From 3616941ef848c573f203925f23bdd7020dddd51b Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Wed, 22 May 2019 22:50:17 -0700 Subject: [PATCH 0055/1084] Add NAN check for text font sizeMultiplier (#24966) Summary: Set `sizeMultiplier` to `1.0` if default value is `NAN`, otherwise, text cannot show properly. ## Changelog [iOS] [Fixed] - Add NAN check for text font sizeMultiplier Pull Request resolved: https://github.com/facebook/react-native/pull/24966 Differential Revision: D15466559 Pulled By: shergin fbshipit-source-id: 6f8b47eb8e521cb120d7f351cba02dbf1c5411fd --- ReactCommon/fabric/attributedstring/TextAttributes.cpp | 1 + .../fabric/textlayoutmanager/platform/ios/RCTFontUtils.mm | 1 + 2 files changed, 2 insertions(+) diff --git a/ReactCommon/fabric/attributedstring/TextAttributes.cpp b/ReactCommon/fabric/attributedstring/TextAttributes.cpp index 5016c9ce0bca2f..3a25c1394821ee 100644 --- a/ReactCommon/fabric/attributedstring/TextAttributes.cpp +++ b/ReactCommon/fabric/attributedstring/TextAttributes.cpp @@ -154,6 +154,7 @@ TextAttributes TextAttributes::defaultTextAttributes() { textAttributes.foregroundColor = blackColor(); textAttributes.backgroundColor = clearColor(); textAttributes.fontSize = 14.0; + textAttributes.fontSizeMultiplier = 1.0; return textAttributes; }(); return textAttributes; diff --git a/ReactCommon/fabric/textlayoutmanager/platform/ios/RCTFontUtils.mm b/ReactCommon/fabric/textlayoutmanager/platform/ios/RCTFontUtils.mm index dfe13ff861ee31..70481596ba381b 100644 --- a/ReactCommon/fabric/textlayoutmanager/platform/ios/RCTFontUtils.mm +++ b/ReactCommon/fabric/textlayoutmanager/platform/ios/RCTFontUtils.mm @@ -137,6 +137,7 @@ static UIFontWeight RCTUIFontWeightFromFloat(CGFloat fontWeight) { RCTFontProperties defaultFontProperties = RCTDefaultFontProperties(); fontProperties = RCTResolveFontProperties(fontProperties); + assert(!isnan(fontProperties.sizeMultiplier)); CGFloat effectiveFontSize = fontProperties.sizeMultiplier * fontProperties.size; UIFont *font; From a7a7970e543959e9db5281914d5f132beb01db8d Mon Sep 17 00:00:00 2001 From: James Ide Date: Thu, 23 May 2019 00:48:22 -0700 Subject: [PATCH 0056/1084] Replace more Haste imports with path-based imports (#25001) Summary: This is another step in moving RN towards standard path-based requires, updating more code to use path-based requires. See the umbrella issue at https://github.com/facebook/react-native/issues/24316 for more detail. ## Changelog [General] [Changed] - Replace more Haste imports with path-based imports Pull Request resolved: https://github.com/facebook/react-native/pull/25001 Differential Revision: D15467829 Pulled By: cpojer fbshipit-source-id: 58c364bb4c1c757689907d5ed0d0f3fac0e22f3f --- Libraries/AppState/NativeAppState.js | 4 +- Libraries/Blob/NativeBlobModule.js | 4 +- Libraries/Blob/NativeFileReaderModule.js | 4 +- .../NativeAccessibilityInfo.js | 4 +- .../AppleTV/NativeTVNavigationEventEmitter.js | 4 +- .../NativeDatePickerAndroid.js | 4 +- .../Keyboard/NativeKeyboardObserver.js | 4 +- .../NativeTimePickerAndroid.js | 4 +- .../View/ReactNativeViewViewConfig.js | 56 +++++++++---------- .../Components/View/ViewAccessibility.js | 2 +- Libraries/Core/NativeExceptionsManager.js | 4 +- Libraries/Core/Timers/NativeTiming.js | 4 +- Libraries/HeapCapture/NativeHeapCapture.js | 4 +- Libraries/Linking/NativeLinking.js | 6 +- .../specs/NativeAnimationsDebugModule.js | 4 +- .../specs/NativeDeviceEventManager.js | 4 +- Libraries/NativeModules/specs/NativeRedBox.js | 4 +- .../NativeModules/specs/NativeSourceCode.js | 4 +- .../Performance/NativeJSCSamplingProfiler.js | 4 +- .../NativeHeadlessJsTaskSupport.js | 4 +- Libraries/Utilities/NativeDevLoadingView.js | 4 +- Libraries/Utilities/NativeJSDevSupport.js | 4 +- ...erifyComponentAttributeEquivalence-test.js | 6 +- .../verifyComponentAttributeEquivalence.js | 4 +- RNTester/js/TextExample.ios.js | 2 +- 25 files changed, 76 insertions(+), 76 deletions(-) diff --git a/Libraries/AppState/NativeAppState.js b/Libraries/AppState/NativeAppState.js index d5d13a392acb94..ffea188b92bcd0 100644 --- a/Libraries/AppState/NativeAppState.js +++ b/Libraries/AppState/NativeAppState.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { +getConstants: () => {| diff --git a/Libraries/Blob/NativeBlobModule.js b/Libraries/Blob/NativeBlobModule.js index e2f8450e236008..cb44600c642ae6 100644 --- a/Libraries/Blob/NativeBlobModule.js +++ b/Libraries/Blob/NativeBlobModule.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { +getConstants: () => {|BLOB_URI_SCHEME: string, BLOB_URI_HOST: ?string|}; diff --git a/Libraries/Blob/NativeFileReaderModule.js b/Libraries/Blob/NativeFileReaderModule.js index b784d8c6f8253f..2291c2e60ad21f 100644 --- a/Libraries/Blob/NativeFileReaderModule.js +++ b/Libraries/Blob/NativeFileReaderModule.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { +readAsDataURL: (data: Object) => Promise; diff --git a/Libraries/Components/AccessibilityInfo/NativeAccessibilityInfo.js b/Libraries/Components/AccessibilityInfo/NativeAccessibilityInfo.js index 894a0804a9faef..2f51c3c183de30 100644 --- a/Libraries/Components/AccessibilityInfo/NativeAccessibilityInfo.js +++ b/Libraries/Components/AccessibilityInfo/NativeAccessibilityInfo.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { +isReduceMotionEnabled: ( diff --git a/Libraries/Components/AppleTV/NativeTVNavigationEventEmitter.js b/Libraries/Components/AppleTV/NativeTVNavigationEventEmitter.js index 4870931e0dc607..27f33bd7270df2 100644 --- a/Libraries/Components/AppleTV/NativeTVNavigationEventEmitter.js +++ b/Libraries/Components/AppleTV/NativeTVNavigationEventEmitter.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { +addListener: (eventName: string) => void; diff --git a/Libraries/Components/DatePickerAndroid/NativeDatePickerAndroid.js b/Libraries/Components/DatePickerAndroid/NativeDatePickerAndroid.js index ccc7a33f68d355..a0676f033291b5 100644 --- a/Libraries/Components/DatePickerAndroid/NativeDatePickerAndroid.js +++ b/Libraries/Components/DatePickerAndroid/NativeDatePickerAndroid.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { +open: (options: Object) => Promise; diff --git a/Libraries/Components/Keyboard/NativeKeyboardObserver.js b/Libraries/Components/Keyboard/NativeKeyboardObserver.js index 792cf7c075726b..04d95a6b69b292 100644 --- a/Libraries/Components/Keyboard/NativeKeyboardObserver.js +++ b/Libraries/Components/Keyboard/NativeKeyboardObserver.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { +addListener: (eventName: string) => void; diff --git a/Libraries/Components/TimePickerAndroid/NativeTimePickerAndroid.js b/Libraries/Components/TimePickerAndroid/NativeTimePickerAndroid.js index 7d0d9a429dc2f0..a23de52629f100 100644 --- a/Libraries/Components/TimePickerAndroid/NativeTimePickerAndroid.js +++ b/Libraries/Components/TimePickerAndroid/NativeTimePickerAndroid.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../../TurboModule/TurboModuleRegistry'; export type TimePickerOptions = {| hour?: number, diff --git a/Libraries/Components/View/ReactNativeViewViewConfig.js b/Libraries/Components/View/ReactNativeViewViewConfig.js index 7a70e54eebedf1..0a65d0188203a3 100644 --- a/Libraries/Components/View/ReactNativeViewViewConfig.js +++ b/Libraries/Components/View/ReactNativeViewViewConfig.js @@ -117,25 +117,25 @@ const ReactNativeViewConfig = { alignSelf: true, aspectRatio: true, backfaceVisibility: true, - backgroundColor: {process: require('processColor')}, - borderBottomColor: {process: require('processColor')}, + backgroundColor: {process: require('../../StyleSheet/processColor')}, + borderBottomColor: {process: require('../../StyleSheet/processColor')}, borderBottomEndRadius: true, borderBottomLeftRadius: true, borderBottomRightRadius: true, borderBottomStartRadius: true, borderBottomWidth: true, - borderColor: {process: require('processColor')}, - borderEndColor: {process: require('processColor')}, + borderColor: {process: require('../../StyleSheet/processColor')}, + borderEndColor: {process: require('../../StyleSheet/processColor')}, borderEndWidth: true, - borderLeftColor: {process: require('processColor')}, + borderLeftColor: {process: require('../../StyleSheet/processColor')}, borderLeftWidth: true, borderRadius: true, - borderRightColor: {process: require('processColor')}, + borderRightColor: {process: require('../../StyleSheet/processColor')}, borderRightWidth: true, - borderStartColor: {process: require('processColor')}, + borderStartColor: {process: require('../../StyleSheet/processColor')}, borderStartWidth: true, borderStyle: true, - borderTopColor: {process: require('processColor')}, + borderTopColor: {process: require('../../StyleSheet/processColor')}, borderTopEndRadius: true, borderTopLeftRadius: true, borderTopRightRadius: true, @@ -156,7 +156,7 @@ const ReactNativeViewConfig = { flexShrink: true, flexWrap: true, height: true, - hitSlop: {diff: (require('insetsDiffer'): any)}, + hitSlop: {diff: (require('../../Utilities/differ/insetsDiffer'): any)}, importantForAccessibility: true, justifyContent: true, left: true, @@ -199,8 +199,8 @@ const ReactNativeViewConfig = { rotation: true, scaleX: true, scaleY: true, - shadowColor: {process: require('processColor')}, - shadowOffset: {diff: require('sizesDiffer')}, + shadowColor: {process: require('../../StyleSheet/processColor')}, + shadowOffset: {diff: require('../../Utilities/differ/sizesDiffer')}, shadowOpacity: true, shadowRadius: true, shouldRasterizeIOS: true, @@ -211,25 +211,25 @@ const ReactNativeViewConfig = { alignSelf: true, aspectRatio: true, backfaceVisibility: true, - backgroundColor: {process: require('processColor')}, - borderBottomColor: {process: require('processColor')}, + backgroundColor: {process: require('../../StyleSheet/processColor')}, + borderBottomColor: {process: require('../../StyleSheet/processColor')}, borderBottomEndRadius: true, borderBottomLeftRadius: true, borderBottomRightRadius: true, borderBottomStartRadius: true, borderBottomWidth: true, - borderColor: {process: require('processColor')}, - borderEndColor: {process: require('processColor')}, + borderColor: {process: require('../../StyleSheet/processColor')}, + borderEndColor: {process: require('../../StyleSheet/processColor')}, borderEndWidth: true, - borderLeftColor: {process: require('processColor')}, + borderLeftColor: {process: require('../../StyleSheet/processColor')}, borderLeftWidth: true, borderRadius: true, - borderRightColor: {process: require('processColor')}, + borderRightColor: {process: require('../../StyleSheet/processColor')}, borderRightWidth: true, - borderStartColor: {process: require('processColor')}, + borderStartColor: {process: require('../../StyleSheet/processColor')}, borderStartWidth: true, borderStyle: true, - borderTopColor: {process: require('processColor')}, + borderTopColor: {process: require('../../StyleSheet/processColor')}, borderTopEndRadius: true, borderTopLeftRadius: true, borderTopRightRadius: true, @@ -237,7 +237,7 @@ const ReactNativeViewConfig = { borderTopWidth: true, borderWidth: true, bottom: true, - color: {process: require('processColor')}, + color: {process: require('../../StyleSheet/processColor')}, decomposedMatrix: true, direction: true, display: true, @@ -275,7 +275,7 @@ const ReactNativeViewConfig = { minWidth: true, opacity: true, overflow: true, - overlayColor: {process: require('processColor')}, + overlayColor: {process: require('../../StyleSheet/processColor')}, padding: true, paddingBottom: true, paddingEnd: true, @@ -291,23 +291,23 @@ const ReactNativeViewConfig = { rotation: true, scaleX: true, scaleY: true, - shadowColor: {process: require('processColor')}, - shadowOffset: {diff: require('sizesDiffer')}, + shadowColor: {process: require('../../StyleSheet/processColor')}, + shadowOffset: {diff: require('../../Utilities/differ/sizesDiffer')}, shadowOpacity: true, shadowRadius: true, start: true, textAlign: true, textAlignVertical: true, - textDecorationColor: {process: require('processColor')}, + textDecorationColor: {process: require('../../StyleSheet/processColor')}, textDecorationLine: true, textDecorationStyle: true, - textShadowColor: {process: require('processColor')}, + textShadowColor: {process: require('../../StyleSheet/processColor')}, textShadowOffset: true, textShadowRadius: true, textTransform: true, - tintColor: {process: require('processColor')}, + tintColor: {process: require('../../StyleSheet/processColor')}, top: true, - transform: {diff: require('matricesDiffer')}, + transform: {diff: require('../../Utilities/differ/matricesDiffer')}, transformMatrix: true, translateX: true, translateY: true, @@ -317,7 +317,7 @@ const ReactNativeViewConfig = { }, testID: true, top: true, - transform: {diff: require('matricesDiffer')}, + transform: {diff: require('../../Utilities/differ/matricesDiffer')}, translateX: true, translateY: true, width: true, diff --git a/Libraries/Components/View/ViewAccessibility.js b/Libraries/Components/View/ViewAccessibility.js index ab23281eecea2a..6f40d3d3c78cf7 100644 --- a/Libraries/Components/View/ViewAccessibility.js +++ b/Libraries/Components/View/ViewAccessibility.js @@ -10,7 +10,7 @@ 'use strict'; -import type {SyntheticEvent} from 'CoreEventTypes'; +import type {SyntheticEvent} from '../../Types/CoreEventTypes'; // This must be kept in sync with the AccessibilityRolesMask in RCTViewManager.m export type AccessibilityRole = diff --git a/Libraries/Core/NativeExceptionsManager.js b/Libraries/Core/NativeExceptionsManager.js index f9a82ec6389e06..e2528fd7ec77c1 100644 --- a/Libraries/Core/NativeExceptionsManager.js +++ b/Libraries/Core/NativeExceptionsManager.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; export type StackFrame = {| column: ?number, diff --git a/Libraries/Core/Timers/NativeTiming.js b/Libraries/Core/Timers/NativeTiming.js index 7f8f1d806ccc3f..f02c71e6fca604 100644 --- a/Libraries/Core/Timers/NativeTiming.js +++ b/Libraries/Core/Timers/NativeTiming.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { +createTimer: ( diff --git a/Libraries/HeapCapture/NativeHeapCapture.js b/Libraries/HeapCapture/NativeHeapCapture.js index a68a967d4ab627..95c2f7f7cff75b 100644 --- a/Libraries/HeapCapture/NativeHeapCapture.js +++ b/Libraries/HeapCapture/NativeHeapCapture.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { // Common interface diff --git a/Libraries/Linking/NativeLinking.js b/Libraries/Linking/NativeLinking.js index 2fa0d78d349b33..d0d648553f55b0 100644 --- a/Libraries/Linking/NativeLinking.js +++ b/Libraries/Linking/NativeLinking.js @@ -10,9 +10,9 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; -import Platform from 'Platform'; +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; +import Platform from '../Utilities/Platform'; export interface Spec extends TurboModule { // Common interface diff --git a/Libraries/NativeModules/specs/NativeAnimationsDebugModule.js b/Libraries/NativeModules/specs/NativeAnimationsDebugModule.js index 792a6d47d03a92..cb653ffe9ad0b4 100644 --- a/Libraries/NativeModules/specs/NativeAnimationsDebugModule.js +++ b/Libraries/NativeModules/specs/NativeAnimationsDebugModule.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { +startRecordingFps: () => void; diff --git a/Libraries/NativeModules/specs/NativeDeviceEventManager.js b/Libraries/NativeModules/specs/NativeDeviceEventManager.js index 8f32816d8d3e7a..1755ba1fc403a8 100644 --- a/Libraries/NativeModules/specs/NativeDeviceEventManager.js +++ b/Libraries/NativeModules/specs/NativeDeviceEventManager.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { +invokeDefaultBackPressHandler: () => void; diff --git a/Libraries/NativeModules/specs/NativeRedBox.js b/Libraries/NativeModules/specs/NativeRedBox.js index 55fa1ab932854b..336caca5dcf5d0 100644 --- a/Libraries/NativeModules/specs/NativeRedBox.js +++ b/Libraries/NativeModules/specs/NativeRedBox.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { +setExtraData: (extraData: Object, identifier: string) => void; diff --git a/Libraries/NativeModules/specs/NativeSourceCode.js b/Libraries/NativeModules/specs/NativeSourceCode.js index 3db328618ef2ca..e0383ace4a87d3 100644 --- a/Libraries/NativeModules/specs/NativeSourceCode.js +++ b/Libraries/NativeModules/specs/NativeSourceCode.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { +getConstants: () => {| diff --git a/Libraries/Performance/NativeJSCSamplingProfiler.js b/Libraries/Performance/NativeJSCSamplingProfiler.js index 9ac1fad140d8c1..944d68383bcefa 100644 --- a/Libraries/Performance/NativeJSCSamplingProfiler.js +++ b/Libraries/Performance/NativeJSCSamplingProfiler.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { +operationComplete: (token: number, result: ?string, error: ?string) => void; diff --git a/Libraries/ReactNative/NativeHeadlessJsTaskSupport.js b/Libraries/ReactNative/NativeHeadlessJsTaskSupport.js index 4d1cf841486aab..686ababaa9ae4f 100644 --- a/Libraries/ReactNative/NativeHeadlessJsTaskSupport.js +++ b/Libraries/ReactNative/NativeHeadlessJsTaskSupport.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { +notifyTaskFinished: (taskId: number) => void; diff --git a/Libraries/Utilities/NativeDevLoadingView.js b/Libraries/Utilities/NativeDevLoadingView.js index b22399bea278cd..7141bb660c9a78 100644 --- a/Libraries/Utilities/NativeDevLoadingView.js +++ b/Libraries/Utilities/NativeDevLoadingView.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { +showMessage: ( diff --git a/Libraries/Utilities/NativeJSDevSupport.js b/Libraries/Utilities/NativeJSDevSupport.js index ae7217be760d97..ffbf9aa65595a6 100644 --- a/Libraries/Utilities/NativeJSDevSupport.js +++ b/Libraries/Utilities/NativeJSDevSupport.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { +getConstants: () => {| diff --git a/Libraries/Utilities/__tests__/verifyComponentAttributeEquivalence-test.js b/Libraries/Utilities/__tests__/verifyComponentAttributeEquivalence-test.js index fade9976f66095..57e0d00e8a1fa0 100644 --- a/Libraries/Utilities/__tests__/verifyComponentAttributeEquivalence-test.js +++ b/Libraries/Utilities/__tests__/verifyComponentAttributeEquivalence-test.js @@ -10,10 +10,10 @@ 'use strict'; -const getNativeComponentAttributes = require('getNativeComponentAttributes'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); +const getNativeComponentAttributes = require('../../ReactNative/getNativeComponentAttributes'); +const verifyComponentAttributeEquivalence = require('../verifyComponentAttributeEquivalence'); -jest.mock('getNativeComponentAttributes', () => () => ({ +jest.mock('../../ReactNative/getNativeComponentAttributes', () => () => ({ NativeProps: { value: 'BOOL', }, diff --git a/Libraries/Utilities/verifyComponentAttributeEquivalence.js b/Libraries/Utilities/verifyComponentAttributeEquivalence.js index f950b6cf13ee15..296b7837cbd7af 100644 --- a/Libraries/Utilities/verifyComponentAttributeEquivalence.js +++ b/Libraries/Utilities/verifyComponentAttributeEquivalence.js @@ -10,9 +10,9 @@ 'use strict'; -const getNativeComponentAttributes = require('getNativeComponentAttributes'); +const getNativeComponentAttributes = require('../ReactNative/getNativeComponentAttributes'); -import type {ReactNativeBaseComponentViewConfig} from 'ReactNativeTypes'; +import type {ReactNativeBaseComponentViewConfig} from '../Renderer/shims/ReactNativeTypes'; const IGNORED_KEYS = ['transform']; /** diff --git a/RNTester/js/TextExample.ios.js b/RNTester/js/TextExample.ios.js index b229b9bc2893bf..281403e2a49323 100644 --- a/RNTester/js/TextExample.ios.js +++ b/RNTester/js/TextExample.ios.js @@ -19,7 +19,7 @@ const { TextInput, View, } = require('react-native'); -const TextAncestor = require('TextAncestor'); +const TextAncestor = require('../../Libraries/Text/TextAncestor'); const TextInlineView = require('./Shared/TextInlineView'); const TextLegend = require('./Shared/TextLegend'); From 82771f4c62d63a8d367317d051bf7ebfe69b8a6d Mon Sep 17 00:00:00 2001 From: Eric Lewis Date: Thu, 23 May 2019 03:36:42 -0700 Subject: [PATCH 0057/1084] Remove ToolbarAndroid (#24999) Summary: This replaces ToolbarAndroid with a cleaner, but very similar design and paves the path for removing ToolbarAndroid from core. ## Changelog [Internal] [Removed] - ToolbarAndroid removed from RNTester Pull Request resolved: https://github.com/facebook/react-native/pull/24999 Differential Revision: D15468053 Pulled By: cpojer fbshipit-source-id: 21a58558b9ec371689bc994c2d888b81cff01126 --- RNTester/js/RNTesterApp.android.js | 61 ++++-- RNTester/js/RNTesterList.android.js | 6 - RNTester/js/ToolbarAndroidExample.android.js | 186 ------------------- RNTester/js/ToolbarAndroidExample.ios.js | 16 -- 4 files changed, 41 insertions(+), 228 deletions(-) delete mode 100644 RNTester/js/ToolbarAndroidExample.android.js delete mode 100644 RNTester/js/ToolbarAndroidExample.ios.js diff --git a/RNTester/js/RNTesterApp.android.js b/RNTester/js/RNTesterApp.android.js index d3b29152299ed0..e8085c2922d9c3 100644 --- a/RNTester/js/RNTesterApp.android.js +++ b/RNTester/js/RNTesterApp.android.js @@ -17,10 +17,12 @@ const { BackHandler, Dimensions, DrawerLayoutAndroid, + Image, Linking, StatusBar, StyleSheet, - ToolbarAndroid, + Text, + TouchableWithoutFeedback, UIManager, View, } = require('react-native'); @@ -47,18 +49,27 @@ type Props = { const APP_STATE_KEY = 'RNTesterAppState.v2'; -const HEADER_LOGO_ICON = nativeImageSource({ - android: 'launcher_icon', - width: 132, - height: 144, -}); - const HEADER_NAV_ICON = nativeImageSource({ android: 'ic_menu_black_24dp', width: 48, height: 48, }); +const Header = ({title, onPressDrawer}) => { + return ( + + + {title} + + + + + + + + ); +}; + class RNTesterApp extends React.Component { UNSAFE_componentWillMount() { BackHandler.addEventListener( @@ -155,14 +166,11 @@ class RNTesterApp extends React.Component { } else if (ExampleModule) { return ( - =0.78.0 site=react_native_android_fb) This issue * was found when making Flow check .android.js files. */ - onIconClicked={() => this.drawer.openDrawer()} - style={styles.toolbar} - title={ExampleModule.title} + onPressDrawer={() => this.drawer.openDrawer()} /> { return ( - =0.78.0 site=react_native_android_fb) This issue was - * found when making Flow check .android.js files. */ - onIconClicked={() => this.drawer.openDrawer()} - style={styles.toolbar} +
=0.78.0 site=react_native_android_fb) This issue + * was found when making Flow check .android.js files. */ + onPressDrawer={() => this.drawer.openDrawer()} /> = [ * when making Flow check .android.js files. */ module: require('./TextInputExample'), }, - { - key: 'ToolbarAndroidExample', - /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found - * when making Flow check .android.js files. */ - module: require('./ToolbarAndroidExample'), - }, { key: 'TouchableExample', module: require('./TouchableExample'), diff --git a/RNTester/js/ToolbarAndroidExample.android.js b/RNTester/js/ToolbarAndroidExample.android.js deleted file mode 100644 index 86d0e976c04cf6..00000000000000 --- a/RNTester/js/ToolbarAndroidExample.android.js +++ /dev/null @@ -1,186 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @flow - */ - -'use strict'; - -const React = require('react'); -const { - StyleSheet, - Switch, - Text, - ToolbarAndroid, - View, -} = require('react-native'); - -const nativeImageSource = require('../../Libraries/Image/nativeImageSource'); - -const RNTesterBlock = require('./RNTesterBlock'); -const RNTesterPage = require('./RNTesterPage'); - -class ToolbarAndroidExample extends React.Component<{}, $FlowFixMeState> { - state = { - actionText: 'Example app with toolbar component', - toolbarSwitch: false, - colorProps: { - titleColor: '#3b5998', - subtitleColor: '#6a7180', - }, - }; - - render() { - return ( - - - this.setState({actionText: 'Icon clicked'})} - style={styles.toolbar} - subtitle={this.state.actionText} - title="Toolbar" - /> - {this.state.actionText} - - - - - this.setState({toolbarSwitch: value})} - /> - {"'Tis but a switch"} - - - - - - - - - - - this.setState({colorProps: {}})} - title="Wow, such toolbar" - style={styles.toolbar} - subtitle="Much native" - {...this.state.colorProps} - /> - - Touch the icon to reset the custom colors to the default - (theme-provided) ones. - - - - - - - - - - ); - } - - _onActionSelected = position => { - this.setState({ - actionText: 'Selected ' + toolbarActions[position].title, - }); - }; -} - -const toolbarActions = [ - { - title: 'Create', - icon: nativeImageSource({ - android: 'ic_create_black_48dp', - width: 96, - height: 96, - }), - show: 'always', - }, - {title: 'Filter'}, - { - title: 'Settings', - icon: nativeImageSource({ - android: 'ic_settings_black_48dp', - width: 96, - height: 96, - }), - show: 'always', - }, -]; - -const styles = StyleSheet.create({ - toolbar: { - backgroundColor: '#e9eaed', - height: 56, - }, - switchWrapper: { - height: 56, - flexDirection: 'row', - alignItems: 'center', - }, -}); - -exports.title = ''; -exports.description = 'Examples of using the Android toolbar.'; -exports.examples = [ - { - title: 'Basic toolbar', - render: function(): React.Element { - return ; - }, - }, -]; diff --git a/RNTester/js/ToolbarAndroidExample.ios.js b/RNTester/js/ToolbarAndroidExample.ios.js deleted file mode 100644 index 6d1eff69dc8b28..00000000000000 --- a/RNTester/js/ToolbarAndroidExample.ios.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @flow strict-local - */ - -'use strict'; - -const {View} = require('react-native'); - -// Not applicable to iOS. -module.exports = View; From 04564a032285dd079b3525b4e35f713f3d9e3ad5 Mon Sep 17 00:00:00 2001 From: Vojtech Novak Date: Thu, 23 May 2019 05:24:14 -0700 Subject: [PATCH 0058/1084] allow overriding spannedFromShadowNode in ReactTextInputShadowNode (#24995) Summary: Motivation is the same as in https://github.com/facebook/react-native/pull/24927 - when building a custom textinput (eg with rich text editing), one needs custom text processing logic. `ReactTextInputShadowNode` contains https://github.com/facebook/react-native/blob/6671165f69e37a49af8b709b4807f9049f7606c3/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java#L211 where an instance of `ReactTextUpdate` is created. For the custom use case, we'd like to just change the usage of [`spannedFromShadowNode()`](https://github.com/facebook/react-native/blob/6671165f69e37a49af8b709b4807f9049f7606c3/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java#L217) to our own implementation. from there: It's easy to subclass `ReactTextInputShadowNode` and override `public void onCollectExtraUpdates()` but the problem is that the method accesses private members. It also means overriding more code than necessary as we only care for `spannedFromShadowNode()`. Solution might be changing the members to protected, but that seemed weird because there are already setters for them. Creating getters also seemed weird, as we'd end up having unused getters hanging around. So the second way which I find nicer is changing `protected static Spannable spannedFromShadowNode(ReactBaseTextShadowNode textShadowNode, String text)` to just `protected` since that will allow subclasses to override just this behavior. ## Changelog [Android] [Added] - allow custom spannedFromShadowNode in ReactTextInputShadowNode subclasses Pull Request resolved: https://github.com/facebook/react-native/pull/24995 Differential Revision: D15468066 Pulled By: cpojer fbshipit-source-id: 73d5f0b9e06f3e02a03bf9db5effac62cecc80c4 --- .../facebook/react/views/text/ReactBaseTextShadowNode.java | 2 +- .../react/views/textinput/ReactTextInputShadowNode.java | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java index b935576c5292b7..3649a944908af6 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java @@ -226,7 +226,7 @@ private static void buildSpannedFromShadowNode( } // `nativeViewHierarchyOptimizer` can be `null` as long as `supportsInlineViews` is `false`. - protected static Spannable spannedFromShadowNode( + protected Spannable spannedFromShadowNode( ReactBaseTextShadowNode textShadowNode, String text, boolean supportsInlineViews, diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java index 3f00b8718b3ad6..fe5845310b37fa 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java @@ -18,14 +18,9 @@ import com.facebook.react.bridge.JSApplicationIllegalArgumentException; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.common.annotations.VisibleForTesting; -import com.facebook.react.uimanager.LayoutShadowNode; -import com.facebook.react.uimanager.NativeViewHierarchyOptimizer; -import com.facebook.react.uimanager.PixelUtil; -import com.facebook.react.uimanager.ReactShadowNodeImpl; import com.facebook.react.uimanager.Spacing; import com.facebook.react.uimanager.ThemedReactContext; import com.facebook.react.uimanager.UIViewOperationQueue; -import com.facebook.react.uimanager.ViewDefaults; import com.facebook.react.uimanager.annotations.ReactProp; import com.facebook.react.views.text.ReactBaseTextShadowNode; import com.facebook.react.views.text.ReactTextUpdate; From 099be9b35634851b178e990c47358c2129c0dd7d Mon Sep 17 00:00:00 2001 From: Marc Mulcahy Date: Thu, 23 May 2019 05:27:39 -0700 Subject: [PATCH 0059/1084] New Accessibility states API. (#24608) Summary: As currently defined, accessibilityStates is an array of strings, which represents the state of an object. The array of strings notion doesn't well encapsulate how various states are related, nor enforce any level of correctness. This PR converts accessibilityStates to an object with a specific definition. So, rather than: We have: And specifically define the checked state to either take a boolean or the "mixed" string (to represent mixed checkboxes). We feel this API is easier to understand an implement, and provides better semantic definition of the states themselves, and how states are related to one another. ## Changelog [general] [change] - Convert accessibilityStates to an object instead of an array of strings. Pull Request resolved: https://github.com/facebook/react-native/pull/24608 Differential Revision: D15467980 Pulled By: cpojer fbshipit-source-id: f0414c0ef6add3f10f7f551d323d82d978754278 --- Libraries/Components/TextInput/TextInput.js | 3 + .../Components/Touchable/TouchableBounce.js | 1 + .../Touchable/TouchableHighlight.js | 1 + .../TouchableNativeFeedback.android.js | 1 + .../Components/Touchable/TouchableOpacity.js | 1 + .../Touchable/TouchableWithoutFeedback.js | 9 ++- .../View/ReactNativeViewAttributes.js | 1 + .../View/ReactNativeViewViewConfig.js | 1 + .../Components/View/ViewAccessibility.js | 8 ++ Libraries/Components/View/ViewPropTypes.js | 2 + .../DeprecatedViewPropTypes.js | 1 + Libraries/Text/TextProps.js | 2 + RNTester/js/AccessibilityExample.js | 52 +++++++------ React/Views/RCTView.m | 31 +++++++- React/Views/RCTViewManager.m | 32 ++++++++ React/Views/UIView+React.h | 1 + React/Views/UIView+React.m | 10 +++ .../react/uimanager/BaseViewManager.java | 73 +++++++++++++++++-- .../uimanager/ReactAccessibilityDelegate.java | 48 ++++++++++-- .../main/res/views/uimanager/values/ids.xml | 3 + .../uimanager/values/strings_unlocalized.xml | 4 + 21 files changed, 242 insertions(+), 43 deletions(-) diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js index 61441eb5af2dee..3caf05f6bacb88 100644 --- a/Libraries/Components/TextInput/TextInput.js +++ b/Libraries/Components/TextInput/TextInput.js @@ -1104,6 +1104,7 @@ const TextInput = createReactClass({ accessibilityLabel={props.accessibilityLabel} accessibilityRole={props.accessibilityRole} accessibilityStates={props.accessibilityStates} + accessibilityState={props.accessibilityState} nativeID={this.props.nativeID} testID={props.testID}> {textContainer} @@ -1156,6 +1157,7 @@ const TextInput = createReactClass({ accessibilityLabel={props.accessibilityLabel} accessibilityRole={props.accessibilityRole} accessibilityStates={props.accessibilityStates} + accessibilityState={props.accessibilityState} nativeID={this.props.nativeID} testID={props.testID}> {textContainer} @@ -1213,6 +1215,7 @@ const TextInput = createReactClass({ accessibilityLabel={this.props.accessibilityLabel} accessibilityRole={this.props.accessibilityRole} accessibilityStates={this.props.accessibilityStates} + accessibilityState={this.props.accessibilityState} nativeID={this.props.nativeID} testID={this.props.testID}> {textContainer} diff --git a/Libraries/Components/Touchable/TouchableBounce.js b/Libraries/Components/Touchable/TouchableBounce.js index 1010be60870a24..e9937dfd70a844 100644 --- a/Libraries/Components/Touchable/TouchableBounce.js +++ b/Libraries/Components/Touchable/TouchableBounce.js @@ -181,6 +181,7 @@ const TouchableBounce = ((createReactClass({ accessibilityHint={this.props.accessibilityHint} accessibilityRole={this.props.accessibilityRole} accessibilityStates={this.props.accessibilityStates} + accessibilityState={this.props.accessibilityState} nativeID={this.props.nativeID} testID={this.props.testID} hitSlop={this.props.hitSlop} diff --git a/Libraries/Components/Touchable/TouchableHighlight.js b/Libraries/Components/Touchable/TouchableHighlight.js index b9e552937b4949..5d733edb0a2c72 100644 --- a/Libraries/Components/Touchable/TouchableHighlight.js +++ b/Libraries/Components/Touchable/TouchableHighlight.js @@ -408,6 +408,7 @@ const TouchableHighlight = ((createReactClass({ accessibilityHint={this.props.accessibilityHint} accessibilityRole={this.props.accessibilityRole} accessibilityStates={this.props.accessibilityStates} + accessibilityState={this.props.accessibilityState} style={StyleSheet.compose( this.props.style, this.state.extraUnderlayStyle, diff --git a/Libraries/Components/Touchable/TouchableNativeFeedback.android.js b/Libraries/Components/Touchable/TouchableNativeFeedback.android.js index 1bd0d27cab21da..1f10ff412bd6e7 100644 --- a/Libraries/Components/Touchable/TouchableNativeFeedback.android.js +++ b/Libraries/Components/Touchable/TouchableNativeFeedback.android.js @@ -314,6 +314,7 @@ const TouchableNativeFeedback = createReactClass({ accessibilityLabel: this.props.accessibilityLabel, accessibilityRole: this.props.accessibilityRole, accessibilityStates: this.props.accessibilityStates, + accessibilityState: this.props.accessibilityState, children, testID: this.props.testID, onLayout: this.props.onLayout, diff --git a/Libraries/Components/Touchable/TouchableOpacity.js b/Libraries/Components/Touchable/TouchableOpacity.js index 235d47ff9af197..adc6439584aa33 100644 --- a/Libraries/Components/Touchable/TouchableOpacity.js +++ b/Libraries/Components/Touchable/TouchableOpacity.js @@ -311,6 +311,7 @@ const TouchableOpacity = ((createReactClass({ accessibilityHint={this.props.accessibilityHint} accessibilityRole={this.props.accessibilityRole} accessibilityStates={this.props.accessibilityStates} + accessibilityState={this.props.accessibilityState} style={[this.props.style, {opacity: this.state.anim}]} nativeID={this.props.nativeID} testID={this.props.testID} diff --git a/Libraries/Components/Touchable/TouchableWithoutFeedback.js b/Libraries/Components/Touchable/TouchableWithoutFeedback.js index 887a9805309f63..6323cee0ed977e 100755 --- a/Libraries/Components/Touchable/TouchableWithoutFeedback.js +++ b/Libraries/Components/Touchable/TouchableWithoutFeedback.js @@ -21,7 +21,6 @@ const ensurePositiveDelayProps = require('./ensurePositiveDelayProps'); const { DeprecatedAccessibilityRoles, - DeprecatedAccessibilityStates, } = require('../../DeprecatedPropTypes/DeprecatedViewAccessibility'); import type { @@ -33,6 +32,7 @@ import type {EdgeInsetsProp} from '../../StyleSheet/EdgeInsetsPropType'; import type { AccessibilityRole, AccessibilityStates, + AccessibilityState, } from '../View/ViewAccessibility'; type TargetEvent = SyntheticEvent< @@ -52,6 +52,7 @@ const OVERRIDE_PROPS = [ 'accessibilityIgnoresInvertColors', 'accessibilityRole', 'accessibilityStates', + 'accessibilityState', 'hitSlop', 'nativeID', 'onBlur', @@ -67,6 +68,7 @@ export type Props = $ReadOnly<{| accessibilityIgnoresInvertColors?: ?boolean, accessibilityRole?: ?AccessibilityRole, accessibilityStates?: ?AccessibilityStates, + accessibilityState?: ?AccessibilityState, children?: ?React.Node, delayLongPress?: ?number, delayPressIn?: ?number, @@ -104,9 +106,8 @@ const TouchableWithoutFeedback = ((createReactClass({ accessibilityHint: PropTypes.string, accessibilityIgnoresInvertColors: PropTypes.bool, accessibilityRole: PropTypes.oneOf(DeprecatedAccessibilityRoles), - accessibilityStates: PropTypes.arrayOf( - PropTypes.oneOf(DeprecatedAccessibilityStates), - ), + accessibilityStates: PropTypes.array, + accessibilityState: PropTypes.object, /** * When `accessible` is true (which is the default) this may be called when * the OS-specific concept of "focus" occurs. Some platforms may not have diff --git a/Libraries/Components/View/ReactNativeViewAttributes.js b/Libraries/Components/View/ReactNativeViewAttributes.js index b4a3b69040e311..92837b4bed1820 100644 --- a/Libraries/Components/View/ReactNativeViewAttributes.js +++ b/Libraries/Components/View/ReactNativeViewAttributes.js @@ -22,6 +22,7 @@ ReactNativeViewAttributes.UIView = { accessibilityLiveRegion: true, accessibilityRole: true, accessibilityStates: true, + accessibilityState: true, accessibilityHint: true, importantForAccessibility: true, nativeID: true, diff --git a/Libraries/Components/View/ReactNativeViewViewConfig.js b/Libraries/Components/View/ReactNativeViewViewConfig.js index 0a65d0188203a3..d723f2797e7de1 100644 --- a/Libraries/Components/View/ReactNativeViewViewConfig.js +++ b/Libraries/Components/View/ReactNativeViewViewConfig.js @@ -110,6 +110,7 @@ const ReactNativeViewConfig = { accessibilityLiveRegion: true, accessibilityRole: true, accessibilityStates: true, + accessibilityState: true, accessibilityViewIsModal: true, accessible: true, alignContent: true, diff --git a/Libraries/Components/View/ViewAccessibility.js b/Libraries/Components/View/ViewAccessibility.js index 6f40d3d3c78cf7..711b57a77d68a7 100644 --- a/Libraries/Components/View/ViewAccessibility.js +++ b/Libraries/Components/View/ViewAccessibility.js @@ -66,3 +66,11 @@ export type AccessibilityActionEvent = SyntheticEvent< actionName: string, }>, >; + +export type AccessibilityState = { + disabled?: boolean, + selected?: boolean, + checked?: ?boolean | 'mixed', + busy?: boolean, + expanded?: boolean, +}; diff --git a/Libraries/Components/View/ViewPropTypes.js b/Libraries/Components/View/ViewPropTypes.js index 861f105b455995..e3a53b8e84d79a 100644 --- a/Libraries/Components/View/ViewPropTypes.js +++ b/Libraries/Components/View/ViewPropTypes.js @@ -18,6 +18,7 @@ import type {TVViewProps} from '../AppleTV/TVViewPropTypes'; import type { AccessibilityRole, AccessibilityStates, + AccessibilityState, AccessibilityActionEvent, AccessibilityActionInfo, } from './ViewAccessibility'; @@ -413,6 +414,7 @@ export type ViewProps = $ReadOnly<{| * Indicates to accessibility services that UI Component is in a specific State. */ accessibilityStates?: ?AccessibilityStates, + accessibilityState?: ?AccessibilityState, /** * Provides an array of custom actions available for accessibility. diff --git a/Libraries/DeprecatedPropTypes/DeprecatedViewPropTypes.js b/Libraries/DeprecatedPropTypes/DeprecatedViewPropTypes.js index 01f035858cb607..343513b5cf3570 100644 --- a/Libraries/DeprecatedPropTypes/DeprecatedViewPropTypes.js +++ b/Libraries/DeprecatedPropTypes/DeprecatedViewPropTypes.js @@ -78,6 +78,7 @@ module.exports = { accessibilityStates: PropTypes.arrayOf( PropTypes.oneOf(DeprecatedAccessibilityStates), ), + accessibilityState: PropTypes.object, /** * Indicates to accessibility services whether the user should be notified * when this view changes. Works for Android API >= 19 only. diff --git a/Libraries/Text/TextProps.js b/Libraries/Text/TextProps.js index 2e55b7c4fa69d6..21951fe145c7f0 100644 --- a/Libraries/Text/TextProps.js +++ b/Libraries/Text/TextProps.js @@ -20,6 +20,7 @@ import type {TextStyleProp} from '../StyleSheet/StyleSheet'; import type { AccessibilityRole, AccessibilityStates, + AccessibilityState, } from '../Components/View/ViewAccessibility'; export type PressRetentionOffset = $ReadOnly<{| @@ -43,6 +44,7 @@ export type TextProps = $ReadOnly<{| accessibilityLabel?: ?Stringish, accessibilityRole?: ?AccessibilityRole, accessibilityStates?: ?AccessibilityStates, + accessibilityState?: ?AccessibilityState, /** * Whether font should be scaled down automatically. diff --git a/RNTester/js/AccessibilityExample.js b/RNTester/js/AccessibilityExample.js index c5ae027942e4d8..a12602c5291c59 100644 --- a/RNTester/js/AccessibilityExample.js +++ b/RNTester/js/AccessibilityExample.js @@ -109,7 +109,7 @@ class AccessibilityExample extends React.Component { Alert.alert('Button has been pressed!')} accessibilityRole="button" - accessibilityStates={['disabled']} + accessibilityState={{disabled: true}} disabled={true}> @@ -122,7 +122,7 @@ class AccessibilityExample extends React.Component { + accessibilityState={{selected: true, disabled: true}}> This view is selected and disabled. @@ -132,7 +132,7 @@ class AccessibilityExample extends React.Component { accessible={true} accessibilityLabel="Accessibility label." accessibilityRole="button" - accessibilityStates={['selected']} + accessibilityState={{selected: true}} accessibilityHint="Accessibility hint."> Accessible view with label, hint, role, and state @@ -144,12 +144,18 @@ class AccessibilityExample extends React.Component { class CheckboxExample extends React.Component { state = { - checkboxState: 'checked', + checkboxState: true, }; _onCheckboxPress = () => { - const checkboxState = - this.state.checkboxState === 'checked' ? 'unchecked' : 'checked'; + let checkboxState = false; + if (this.state.checkboxState === false) { + checkboxState = 'mixed'; + } else if (this.state.checkboxState === 'mixed') { + checkboxState = true; + } else { + checkboxState = false; + } this.setState({ checkboxState: checkboxState, @@ -169,7 +175,7 @@ class CheckboxExample extends React.Component { onPress={this._onCheckboxPress} accessibilityLabel="element 2" accessibilityRole="checkbox" - accessibilityStates={[this.state.checkboxState]} + accessibilityState={{checked: this.state.checkboxState}} accessibilityHint="click me to change state"> Checkbox example @@ -179,12 +185,11 @@ class CheckboxExample extends React.Component { class SwitchExample extends React.Component { state = { - switchState: 'checked', + switchState: true, }; _onSwitchToggle = () => { - const switchState = - this.state.switchState === 'checked' ? 'unchecked' : 'checked'; + const switchState = !this.state.switchState; this.setState({ switchState: switchState, @@ -204,7 +209,7 @@ class SwitchExample extends React.Component { onPress={this._onSwitchToggle} accessibilityLabel="element 12" accessibilityRole="switch" - accessibilityStates={[this.state.switchState]} + accessibilityState={{checked: this.state.switchState}} accessible={true}> Switch example @@ -224,14 +229,11 @@ class SelectionExample extends React.Component { }; render() { - let accessibilityStates = []; let accessibilityHint = 'click me to select'; if (this.state.isSelected) { - accessibilityStates.push('selected'); accessibilityHint = 'click me to unselect'; } if (!this.state.isEnabled) { - accessibilityStates.push('disabled'); accessibilityHint = 'use the button on the right to enable selection'; } let buttonTitle = this.state.isEnabled @@ -244,9 +246,11 @@ class SelectionExample extends React.Component { ref={this.selectableElement} accessible={true} onPress={() => { - this.setState({ - isSelected: !this.state.isSelected, - }); + if (this.state.isEnabled) { + this.setState({ + isSelected: !this.state.isSelected, + }); + } if (Platform.OS === 'android') { UIManager.sendAccessibilityEvent( @@ -256,7 +260,10 @@ class SelectionExample extends React.Component { } }} accessibilityLabel="element 19" - accessibilityStates={accessibilityStates} + accessibilityState={{ + selected: this.state.isSelected, + disabled: !this.state.isEnabled, + }} accessibilityHint={accessibilityHint}> Selectable element example @@ -275,12 +282,11 @@ class SelectionExample extends React.Component { class ExpandableElementExample extends React.Component { state = { - expandState: 'collapsed', + expandState: false, }; _onElementPress = () => { - const expandState = - this.state.expandState === 'collapsed' ? 'expanded' : 'collapsed'; + const expandState = !this.state.expandState; this.setState({ expandState: expandState, @@ -299,7 +305,7 @@ class ExpandableElementExample extends React.Component { Expandable element example @@ -399,7 +405,7 @@ class AccessibilityRoleAndStateExample extends React.Component<{}> { State busy example diff --git a/React/Views/RCTView.m b/React/Views/RCTView.m index 39cdcaa974ae94..8f550ab57cbdf3 100644 --- a/React/Views/RCTView.m +++ b/React/Views/RCTView.m @@ -222,6 +222,15 @@ - (NSString *)accessibilityValue return @"0"; } } + for (NSString *state in self.accessibilityState) { + id val = self.accessibilityState[state]; + if (!val) { + continue; + } + if ([state isEqualToString:@"checked"] && [val isKindOfClass:[NSNumber class]]) { + return [val boolValue] ? @"1" : @"0"; + } + } } NSMutableArray *valueComponents = [NSMutableArray new]; static NSDictionary *roleDescriptions = nil; @@ -255,6 +264,7 @@ - (NSString *)accessibilityValue @"busy" : @"busy", @"expanded" : @"expanded", @"collapsed" : @"collapsed", + @"mixed": @"mixed", }; }); NSString *roleDescription = self.accessibilityRole ? roleDescriptions[self.accessibilityRole]: nil; @@ -267,8 +277,27 @@ - (NSString *)accessibilityValue [valueComponents addObject:stateDescription]; } } + for (NSString *state in self.accessibilityState) { + id val = self.accessibilityState[state]; + if (!val) { + continue; + } + if ([state isEqualToString:@"checked"]) { + if ([val isKindOfClass:[NSNumber class]]) { + [valueComponents addObject:stateDescriptions[[val boolValue] ? @"checked" : @"unchecked"]]; + } else if ([val isKindOfClass:[NSString class]] && [val isEqualToString:@"mixed"]) { + [valueComponents addObject:stateDescriptions[@"mixed"]]; + } + } + if ([state isEqualToString:@"expanded"] && [val isKindOfClass:[NSNumber class]]) { + [valueComponents addObject:stateDescriptions[[val boolValue] ? @"expanded" : @"collapsed"]]; + } + if ([state isEqualToString:@"busy"] && [val isKindOfClass:[NSNumber class]] && [val boolValue]) { + [valueComponents addObject:stateDescriptions[@"busy"]]; + } + } if (valueComponents.count > 0) { - return [valueComponents componentsJoinedByString:@", "]; + return [valueComponents componentsJoinedByString:@", "]; } return nil; } diff --git a/React/Views/RCTViewManager.m b/React/Views/RCTViewManager.m index 7c538ed2e200bc..bdc9ecccd84b87 100644 --- a/React/Views/RCTViewManager.m +++ b/React/Views/RCTViewManager.m @@ -206,6 +206,38 @@ - (RCTShadowView *)shadowView } } +RCT_CUSTOM_VIEW_PROPERTY(accessibilityState, NSDictionary, RCTView) +{ + NSDictionary *state = json ? [RCTConvert NSDictionary:json] : nil; + NSMutableDictionary *newState = [[NSMutableDictionary alloc] init]; + + if (!state) { + return; + } + + const UIAccessibilityTraits AccessibilityStatesMask = UIAccessibilityTraitNotEnabled | UIAccessibilityTraitSelected; + view.reactAccessibilityElement.accessibilityTraits = view.reactAccessibilityElement.accessibilityTraits & ~AccessibilityStatesMask; + + for (NSString *s in state) { + id val = [state objectForKey:s]; + if (!val) { + continue; + } + if ([s isEqualToString:@"selected"] && [val isKindOfClass:[NSNumber class]] && [val boolValue]) { + view.reactAccessibilityElement.accessibilityTraits |= UIAccessibilityTraitSelected; + } else if ([s isEqualToString:@"disabled"] && [val isKindOfClass:[NSNumber class]] && [val boolValue]) { + view.reactAccessibilityElement.accessibilityTraits |= UIAccessibilityTraitNotEnabled; + } else { + newState[s] = val; + } + } + if (newState.count > 0) { + view.reactAccessibilityElement.accessibilityState = newState; + } else { + view.reactAccessibilityElement.accessibilityState = nil; + } +} + RCT_CUSTOM_VIEW_PROPERTY(nativeID, NSString *, RCTView) { view.nativeID = json ? [RCTConvert NSString:json] : defaultView.nativeID; diff --git a/React/Views/UIView+React.h b/React/Views/UIView+React.h index c4cab30b60a72f..6fbf47a0739299 100644 --- a/React/Views/UIView+React.h +++ b/React/Views/UIView+React.h @@ -118,6 +118,7 @@ */ @property (nonatomic, copy) NSString *accessibilityRole; @property (nonatomic, copy) NSArray *accessibilityStates; +@property (nonatomic, copy) NSDictionary *accessibilityState; /** * Used in debugging to get a description of the view hierarchy rooted at diff --git a/React/Views/UIView+React.m b/React/Views/UIView+React.m index 019eebcc120f7f..d9c4d4190ab226 100644 --- a/React/Views/UIView+React.m +++ b/React/Views/UIView+React.m @@ -327,6 +327,16 @@ - (void)setAccessibilityStates:(NSArray *)accessibilityStates objc_setAssociatedObject(self, @selector(accessibilityStates), accessibilityStates, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } +- (NSDictionary *)accessibilityState +{ + return objc_getAssociatedObject(self, _cmd); +} + +- (void)setAccessibilityState:(NSDictionary *)accessibilityState +{ + objc_setAssociatedObject(self, @selector(accessibilityState), accessibilityState, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + #pragma mark - Debug - (void)react_addRecursiveDescriptionToString:(NSMutableString *)string atLevel:(NSUInteger)level diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java index 0d63d86cb1f15b..94bfdbf91fc47b 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java @@ -6,14 +6,21 @@ package com.facebook.react.uimanager; import android.graphics.Color; +import android.text.TextUtils; import android.view.View; import android.view.ViewParent; + import androidx.core.view.ViewCompat; +import java.util.ArrayList; import java.util.HashMap; import com.facebook.react.R; +import com.facebook.react.bridge.Dynamic; import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.bridge.ReadableMapKeySetIterator; +import com.facebook.react.bridge.ReadableType; import com.facebook.react.common.MapBuilder; import com.facebook.react.uimanager.ReactAccessibilityDelegate; import com.facebook.react.uimanager.ReactAccessibilityDelegate.AccessibilityRole; @@ -21,6 +28,7 @@ import com.facebook.react.uimanager.util.ReactFindViewUtil; import javax.annotation.Nonnull; +import java.util.ArrayList; import java.util.Map; import javax.annotation.Nullable; @@ -41,6 +49,7 @@ public abstract class BaseViewManager sStateDescription= new HashMap(); + public static final HashMap sStateDescription = new HashMap(); static { sStateDescription.put("busy", R.string.state_busy_description); sStateDescription.put("expanded", R.string.state_expanded_description); sStateDescription.put("collapsed", R.string.state_collapsed_description); } + // State definition constants -- must match the definition in + // ViewAccessibility.js. These only include states for which there + // is no native support in android. + + private static final String STATE_CHECKED = "checked"; // Special case for mixed state checkboxes + private static final String STATE_BUSY = "busy"; + private static final String STATE_EXPANDED = "expanded"; + private static final String STATE_MIXED = "mixed"; + @ReactProp(name = PROP_BACKGROUND_COLOR, defaultInt = Color.TRANSPARENT, customType = "Color") public void setBackgroundColor(@Nonnull T view, int backgroundColor) { view.setBackgroundColor(backgroundColor); @@ -169,27 +187,66 @@ public void setViewStates(@Nonnull T view, @Nullable ReadableArray accessibility } } + @ReactProp(name = PROP_ACCESSIBILITY_STATE) + public void setViewState(@Nonnull T view, @Nullable ReadableMap accessibilityState) { + if (accessibilityState == null) { + return; + } + view.setTag(R.id.accessibility_state, accessibilityState); + view.setSelected(false); + view.setEnabled(true); + + // For states which don't have corresponding methods in + // AccessibilityNodeInfo, update the view's content description + // here + + final ReadableMapKeySetIterator i = accessibilityState.keySetIterator(); + while (i.hasNextKey()) { + final String state = i.nextKey(); + if (state.equals(STATE_BUSY) || state.equals(STATE_EXPANDED) || + (state.equals(STATE_CHECKED) && accessibilityState.getType(STATE_CHECKED) == ReadableType.String)) { + updateViewContentDescription(view); + break; + } + } + } + private void updateViewContentDescription(@Nonnull T view) { final String accessibilityLabel = (String) view.getTag(R.id.accessibility_label); final ReadableArray accessibilityStates = (ReadableArray) view.getTag(R.id.accessibility_states); + final ReadableMap accessibilityState = (ReadableMap) view.getTag(R.id.accessibility_state); final String accessibilityHint = (String) view.getTag(R.id.accessibility_hint); - StringBuilder contentDescription = new StringBuilder(); + final ArrayList contentDescription = new ArrayList(); if (accessibilityLabel != null) { - contentDescription.append(accessibilityLabel + ", "); + contentDescription.add(accessibilityLabel); } if (accessibilityStates != null) { for (int i = 0; i < accessibilityStates.size(); i++) { - String state = accessibilityStates.getString(i); + final String state = accessibilityStates.getString(i); if (sStateDescription.containsKey(state)) { - contentDescription.append(view.getContext().getString(sStateDescription.get(state)) + ", "); + contentDescription.add(view.getContext().getString(sStateDescription.get(state))); + } + } + } + if (accessibilityState != null) { + final ReadableMapKeySetIterator i = accessibilityState.keySetIterator(); + while (i.hasNextKey()) { + final String state = i.nextKey(); + final Dynamic value = accessibilityState.getDynamic(state); + if (state.equals(STATE_CHECKED) && value.getType() == ReadableType.String && value.asString().equals(STATE_MIXED)) { + contentDescription.add(view.getContext().getString(R.string.state_mixed_description)); + } else if (state.equals(STATE_BUSY) && value.getType() == ReadableType.Boolean && value.asBoolean()) { + contentDescription.add(view.getContext().getString(R.string.state_busy_description)); + } else if (state.equals(STATE_EXPANDED) && value.getType() == ReadableType.Boolean) { + contentDescription.add(view.getContext().getString(value.asBoolean() ? R.string.state_expanded_description : R.string.state_collapsed_description)); } } } if (accessibilityHint != null) { - contentDescription.append(accessibilityHint + ", "); + contentDescription.add(accessibilityHint); } - if (contentDescription.length() > 0) { - view.setContentDescription(contentDescription.toString()); + if (contentDescription.size() > 0) { + view.setContentDescription(TextUtils.join(", ", contentDescription)); } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java index 0924dacfc8e8cd..481f2e2821d669 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java @@ -18,12 +18,16 @@ import androidx.core.view.ViewCompat; import androidx.core.view.accessibility.AccessibilityNodeInfoCompat; import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat; +import android.util.Log; import android.view.View; import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.Dynamic; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.bridge.ReadableMapKeySetIterator; +import com.facebook.react.bridge.ReadableType; import com.facebook.react.bridge.WritableMap; import com.facebook.react.uimanager.events.RCTEventEmitter; import com.facebook.react.R; @@ -39,6 +43,7 @@ public class ReactAccessibilityDelegate extends AccessibilityDelegateCompat { + private static final String TAG = "ReactAccessibilityDelegate"; private static int sCounter = 0x3f000000; public static final HashMap sActionIdMap= new HashMap<>(); @@ -121,6 +126,12 @@ public static AccessibilityRole fromValue(@Nullable String value) { private final HashMap mAccessibilityActionsMap; + // State constants for states which have analogs in AccessibilityNodeInfo + + private static final String STATE_DISABLED = "disabled"; + private static final String STATE_SELECTED = "selected"; + private static final String STATE_CHECKED = "checked"; + public ReactAccessibilityDelegate() { super(); mAccessibilityActionsMap = new HashMap(); @@ -136,8 +147,12 @@ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCo // states are changable. final ReadableArray accessibilityStates = (ReadableArray) host.getTag(R.id.accessibility_states); + final ReadableMap accessibilityState = (ReadableMap) host.getTag(R.id.accessibility_state); if (accessibilityStates != null) { - setState(info, accessibilityStates, host.getContext()); + setStates(info, accessibilityStates, host.getContext()); + } + if (accessibilityState != null) { + setState(info, accessibilityState, host.getContext()); } final ReadableArray accessibilityActions = (ReadableArray) host.getTag(R.id.accessibility_actions); if (accessibilityActions != null) { @@ -175,7 +190,7 @@ public boolean performAccessibilityAction(View host, int action, Bundle args) { return super.performAccessibilityAction(host, action, args); } - public static void setState(AccessibilityNodeInfoCompat info, ReadableArray accessibilityStates, Context context) { + private static void setStates(AccessibilityNodeInfoCompat info, ReadableArray accessibilityStates, Context context) { for (int i = 0; i < accessibilityStates.size(); i++) { String state = accessibilityStates.getString(i); switch (state) { @@ -188,20 +203,38 @@ public static void setState(AccessibilityNodeInfoCompat info, ReadableArray acce case "checked": info.setCheckable(true); info.setChecked(true); - if (info.getClassName().equals("android.widget.Switch")) { + if (info.getClassName().equals(AccessibilityRole.getValue(AccessibilityRole.SWITCH))) { info.setText(context.getString(R.string.state_on_description)); } break; case "unchecked": info.setCheckable(true); info.setChecked(false); - if (info.getClassName().equals("android.widget.Switch")) { + if (info.getClassName().equals(AccessibilityRole.getValue(AccessibilityRole.SWITCH))) { info.setText(context.getString(R.string.state_off_description)); } break; - case "hasPopup": - info.setCanOpenPopup(true); - break; + } + } + } + + private static void setState(AccessibilityNodeInfoCompat info, ReadableMap accessibilityState, Context context) { + Log.d(TAG, "setState " + accessibilityState); + final ReadableMapKeySetIterator i = accessibilityState.keySetIterator(); + while (i.hasNextKey()) { + final String state = i.nextKey(); + final Dynamic value = accessibilityState.getDynamic(state); + if (state.equals(STATE_SELECTED) && value.getType() == ReadableType.Boolean) { + info.setSelected(value.asBoolean()); + } else if (state.equals(STATE_DISABLED) && value.getType() == ReadableType.Boolean) { + info.setEnabled(!value.asBoolean()); + } else if (state.equals(STATE_CHECKED) && value.getType() == ReadableType.Boolean) { + final boolean boolValue = value.asBoolean(); + info.setCheckable(true); + info.setChecked(boolValue); + if (info.getClassName().equals(AccessibilityRole.getValue(AccessibilityRole.SWITCH))) { + info.setText(context.getString(boolValue ? R.string.state_on_description : R.string.state_off_description)); + } } } } @@ -281,6 +314,7 @@ public static void setDelegate(final View view) { if (!ViewCompat.hasAccessibilityDelegate(view) && (view.getTag(R.id.accessibility_role) != null || view.getTag(R.id.accessibility_states) != null || + view.getTag(R.id.accessibility_state) != null || view.getTag(R.id.accessibility_actions) != null)) { ViewCompat.setAccessibilityDelegate(view, new ReactAccessibilityDelegate()); } diff --git a/ReactAndroid/src/main/res/views/uimanager/values/ids.xml b/ReactAndroid/src/main/res/views/uimanager/values/ids.xml index 0ae5d684021781..6dce677f736dca 100644 --- a/ReactAndroid/src/main/res/views/uimanager/values/ids.xml +++ b/ReactAndroid/src/main/res/views/uimanager/values/ids.xml @@ -18,6 +18,9 @@ + + + diff --git a/ReactAndroid/src/main/res/views/uimanager/values/strings_unlocalized.xml b/ReactAndroid/src/main/res/views/uimanager/values/strings_unlocalized.xml index 7950f24a6a7b07..cd3cc03e0d6236 100644 --- a/ReactAndroid/src/main/res/views/uimanager/values/strings_unlocalized.xml +++ b/ReactAndroid/src/main/res/views/uimanager/values/strings_unlocalized.xml @@ -96,4 +96,8 @@ name="state_off_description" translatable="false" >off + mixed From 3f04cfecda638c82d7d3b8f14474e57a9bb79576 Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Thu, 23 May 2019 07:02:23 -0700 Subject: [PATCH 0060/1084] Move CameraRoll JS to FB internal Summary: Moves relevant JS files to fb internal, removes stuff we don't need in the RN repo any more. Android and iOS will happen in a follow-up. Reviewed By: rickhanlonii Differential Revision: D15468419 fbshipit-source-id: 39fffc22f87534e557788e398bbae575043353b6 --- Libraries/CameraRoll/CameraRoll.js | 250 -------------- .../RCTCameraRoll.xcodeproj/project.pbxproj | 302 ----------------- .../CameraRoll/React-RCTCameraRoll.podspec | 36 -- Libraries/CameraRoll/__mocks__/CameraRoll.js | 14 - .../{CameraRoll => Image}/ImagePickerIOS.js | 0 .../react-native-implementation.js | 9 - RNTester/Podfile | 3 +- RNTester/Podfile.lock | 7 - RNTester/RNTester.xcodeproj/project.pbxproj | 30 -- .../RNTesterPods.xcodeproj/project.pbxproj | 2 - RNTester/js/AssetScaledImageExample.js | 23 +- RNTester/js/CameraRollExample.js | 162 --------- RNTester/js/CameraRollView.js | 264 --------------- RNTester/js/ImageEditingExample.js | 315 ------------------ RNTester/js/RNTesterList.android.js | 8 - RNTester/js/RNTesterList.ios.js | 10 - RNTester/js/XHRExample.js | 7 - RNTester/js/XHRExampleFormData.js | 242 -------------- 18 files changed, 23 insertions(+), 1661 deletions(-) delete mode 100644 Libraries/CameraRoll/CameraRoll.js delete mode 100644 Libraries/CameraRoll/RCTCameraRoll.xcodeproj/project.pbxproj delete mode 100644 Libraries/CameraRoll/React-RCTCameraRoll.podspec delete mode 100644 Libraries/CameraRoll/__mocks__/CameraRoll.js rename Libraries/{CameraRoll => Image}/ImagePickerIOS.js (100%) delete mode 100644 RNTester/js/CameraRollExample.js delete mode 100644 RNTester/js/CameraRollView.js delete mode 100644 RNTester/js/ImageEditingExample.js delete mode 100644 RNTester/js/XHRExampleFormData.js diff --git a/Libraries/CameraRoll/CameraRoll.js b/Libraries/CameraRoll/CameraRoll.js deleted file mode 100644 index bc791fde36f2b5..00000000000000 --- a/Libraries/CameraRoll/CameraRoll.js +++ /dev/null @@ -1,250 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - * @format - */ -'use strict'; - -const PropTypes = require('prop-types'); -const {checkPropTypes} = PropTypes; -const RCTCameraRollManager = require('../BatchedBridge/NativeModules') - .CameraRollManager; - -const deprecatedCreateStrictShapeTypeChecker = require('../DeprecatedPropTypes/deprecatedCreateStrictShapeTypeChecker'); -const invariant = require('invariant'); - -const GROUP_TYPES_OPTIONS = { - Album: 'Album', - All: 'All', - Event: 'Event', - Faces: 'Faces', - Library: 'Library', - PhotoStream: 'PhotoStream', - SavedPhotos: 'SavedPhotos', // default -}; - -const ASSET_TYPE_OPTIONS = { - All: 'All', - Videos: 'Videos', - Photos: 'Photos', -}; - -export type GroupTypes = $Keys; - -export type GetPhotosParams = { - first: number, - after?: string, - groupTypes?: GroupTypes, - groupName?: string, - assetType?: $Keys, - mimeTypes?: Array, -}; - -/** - * Shape of the param arg for the `getPhotos` function. - */ -const getPhotosParamChecker = deprecatedCreateStrictShapeTypeChecker({ - /** - * The number of photos wanted in reverse order of the photo application - * (i.e. most recent first for SavedPhotos). - */ - first: PropTypes.number.isRequired, - - /** - * A cursor that matches `page_info { end_cursor }` returned from a previous - * call to `getPhotos` - */ - after: PropTypes.string, - - /** - * Specifies which group types to filter the results to. - */ - groupTypes: PropTypes.oneOf(Object.keys(GROUP_TYPES_OPTIONS)), - - /** - * Specifies filter on group names, like 'Recent Photos' or custom album - * titles. - */ - groupName: PropTypes.string, - - /** - * Specifies filter on asset type - */ - assetType: PropTypes.oneOf(Object.keys(ASSET_TYPE_OPTIONS)), - - /** - * Filter by mimetype (e.g. image/jpeg). - */ - mimeTypes: PropTypes.arrayOf(PropTypes.string), -}); - -export type PhotoIdentifier = { - node: { - type: string, - group_name: string, - image: { - filename: string, - uri: string, - height: number, - width: number, - isStored?: boolean, - playableDuration: number, - }, - timestamp: number, - location?: { - latitude?: number, - longitude?: number, - altitude?: number, - heading?: number, - speed?: number, - }, - }, -}; - -export type PhotoIdentifiersPage = { - edges: Array, - page_info: { - has_next_page: boolean, - start_cursor?: string, - end_cursor?: string, - }, -}; - -/** - * Shape of the return value of the `getPhotos` function. - */ -const getPhotosReturnChecker = deprecatedCreateStrictShapeTypeChecker({ - edges: PropTypes.arrayOf( - /* $FlowFixMe(>=0.66.0 site=react_native_fb) This comment suppresses an - * error found when Flow v0.66 was deployed. To see the error delete this - * comment and run Flow. */ - deprecatedCreateStrictShapeTypeChecker({ - node: deprecatedCreateStrictShapeTypeChecker({ - type: PropTypes.string.isRequired, - group_name: PropTypes.string.isRequired, - image: deprecatedCreateStrictShapeTypeChecker({ - uri: PropTypes.string.isRequired, - height: PropTypes.number.isRequired, - width: PropTypes.number.isRequired, - isStored: PropTypes.bool, - playableDuration: PropTypes.number.isRequired, - }).isRequired, - timestamp: PropTypes.number.isRequired, - location: deprecatedCreateStrictShapeTypeChecker({ - latitude: PropTypes.number, - longitude: PropTypes.number, - altitude: PropTypes.number, - heading: PropTypes.number, - speed: PropTypes.number, - }), - }).isRequired, - }), - ).isRequired, - page_info: deprecatedCreateStrictShapeTypeChecker({ - has_next_page: PropTypes.bool.isRequired, - start_cursor: PropTypes.string, - end_cursor: PropTypes.string, - }).isRequired, -}); - -/** - * `CameraRoll` provides access to the local camera roll or photo library. - * - * See https://facebook.github.io/react-native/docs/cameraroll.html - */ -class CameraRoll { - static GroupTypesOptions = GROUP_TYPES_OPTIONS; - static AssetTypeOptions = ASSET_TYPE_OPTIONS; - - /** - * `CameraRoll.saveImageWithTag()` is deprecated. Use `CameraRoll.saveToCameraRoll()` instead. - */ - static saveImageWithTag(tag: string): Promise { - console.warn( - '`CameraRoll.saveImageWithTag()` is deprecated. Use `CameraRoll.saveToCameraRoll()` instead.', - ); - return this.saveToCameraRoll(tag, 'photo'); - } - - static deletePhotos(photos: Array) { - return RCTCameraRollManager.deletePhotos(photos); - } - - /** - * Saves the photo or video to the camera roll or photo library. - * - * See https://facebook.github.io/react-native/docs/cameraroll.html#savetocameraroll - */ - static saveToCameraRoll( - tag: string, - type?: 'photo' | 'video', - ): Promise { - invariant( - typeof tag === 'string', - 'CameraRoll.saveToCameraRoll must be a valid string.', - ); - - invariant( - type === 'photo' || type === 'video' || type === undefined, - `The second argument to saveToCameraRoll must be 'photo' or 'video'. You passed ${type || - 'unknown'}`, - ); - - let mediaType = 'photo'; - if (type) { - mediaType = type; - } else if (['mov', 'mp4'].indexOf(tag.split('.').slice(-1)[0]) >= 0) { - mediaType = 'video'; - } - - return RCTCameraRollManager.saveToCameraRoll(tag, mediaType); - } - - /** - * Returns a Promise with photo identifier objects from the local camera - * roll of the device matching shape defined by `getPhotosReturnChecker`. - * - * See https://facebook.github.io/react-native/docs/cameraroll.html#getphotos - */ - static getPhotos(params: GetPhotosParams): Promise { - if (__DEV__) { - checkPropTypes( - {params: getPhotosParamChecker}, - {params}, - 'params', - 'CameraRoll.getPhotos', - ); - } - if (arguments.length > 1) { - console.warn( - 'CameraRoll.getPhotos(tag, success, error) is deprecated. Use the returned Promise instead', - ); - let successCallback = arguments[1]; - if (__DEV__) { - const callback = arguments[1]; - successCallback = response => { - checkPropTypes( - {response: getPhotosReturnChecker}, - {response}, - 'response', - 'CameraRoll.getPhotos callback', - ); - callback(response); - }; - } - const errorCallback = arguments[2] || (() => {}); - RCTCameraRollManager.getPhotos(params).then( - successCallback, - errorCallback, - ); - } - // TODO: Add the __DEV__ check back in to verify the Promise result - return RCTCameraRollManager.getPhotos(params); - } -} - -module.exports = CameraRoll; diff --git a/Libraries/CameraRoll/RCTCameraRoll.xcodeproj/project.pbxproj b/Libraries/CameraRoll/RCTCameraRoll.xcodeproj/project.pbxproj deleted file mode 100644 index 618dbab44ae880..00000000000000 --- a/Libraries/CameraRoll/RCTCameraRoll.xcodeproj/project.pbxproj +++ /dev/null @@ -1,302 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 137620351B31C53500677FF0 /* RCTImagePickerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 137620341B31C53500677FF0 /* RCTImagePickerManager.m */; }; - 143879351AAD238D00F088A5 /* RCTCameraRollManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 143879341AAD238D00F088A5 /* RCTCameraRollManager.m */; }; - 8312EAEE1B85EB7C001867A2 /* RCTAssetsLibraryRequestHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 8312EAED1B85EB7C001867A2 /* RCTAssetsLibraryRequestHandler.m */; }; - 8312EAF11B85F071001867A2 /* RCTPhotoLibraryImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 8312EAF01B85F071001867A2 /* RCTPhotoLibraryImageLoader.m */; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 58B5115B1A9E6B3D00147676 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = "include/$(PRODUCT_NAME)"; - dstSubfolderSpec = 16; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 137620331B31C53500677FF0 /* RCTImagePickerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RCTImagePickerManager.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; - 137620341B31C53500677FF0 /* RCTImagePickerManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImagePickerManager.m; sourceTree = ""; }; - 143879331AAD238D00F088A5 /* RCTCameraRollManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RCTCameraRollManager.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; - 143879341AAD238D00F088A5 /* RCTCameraRollManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTCameraRollManager.m; sourceTree = ""; }; - 58B5115D1A9E6B3D00147676 /* libRCTCameraRoll.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTCameraRoll.a; sourceTree = BUILT_PRODUCTS_DIR; }; - 8312EAEC1B85EB7C001867A2 /* RCTAssetsLibraryRequestHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RCTAssetsLibraryRequestHandler.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; - 8312EAED1B85EB7C001867A2 /* RCTAssetsLibraryRequestHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAssetsLibraryRequestHandler.m; sourceTree = ""; }; - 8312EAEF1B85F071001867A2 /* RCTPhotoLibraryImageLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RCTPhotoLibraryImageLoader.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; - 8312EAF01B85F071001867A2 /* RCTPhotoLibraryImageLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTPhotoLibraryImageLoader.m; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 58B5115A1A9E6B3D00147676 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 58B511541A9E6B3D00147676 = { - isa = PBXGroup; - children = ( - 8312EAEC1B85EB7C001867A2 /* RCTAssetsLibraryRequestHandler.h */, - 8312EAED1B85EB7C001867A2 /* RCTAssetsLibraryRequestHandler.m */, - 143879331AAD238D00F088A5 /* RCTCameraRollManager.h */, - 143879341AAD238D00F088A5 /* RCTCameraRollManager.m */, - 137620331B31C53500677FF0 /* RCTImagePickerManager.h */, - 137620341B31C53500677FF0 /* RCTImagePickerManager.m */, - 8312EAEF1B85F071001867A2 /* RCTPhotoLibraryImageLoader.h */, - 8312EAF01B85F071001867A2 /* RCTPhotoLibraryImageLoader.m */, - 58B5115E1A9E6B3D00147676 /* Products */, - ); - indentWidth = 2; - sourceTree = ""; - tabWidth = 2; - usesTabs = 0; - }; - 58B5115E1A9E6B3D00147676 /* Products */ = { - isa = PBXGroup; - children = ( - 58B5115D1A9E6B3D00147676 /* libRCTCameraRoll.a */, - ); - name = Products; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 58B5115C1A9E6B3D00147676 /* RCTCameraRoll */ = { - isa = PBXNativeTarget; - buildConfigurationList = 58B511711A9E6B3D00147676 /* Build configuration list for PBXNativeTarget "RCTCameraRoll" */; - buildPhases = ( - 58B511591A9E6B3D00147676 /* Sources */, - 58B5115A1A9E6B3D00147676 /* Frameworks */, - 58B5115B1A9E6B3D00147676 /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = RCTCameraRoll; - productName = RCTNetworkImage; - productReference = 58B5115D1A9E6B3D00147676 /* libRCTCameraRoll.a */; - productType = "com.apple.product-type.library.static"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 58B511551A9E6B3D00147676 /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0940; - ORGANIZATIONNAME = Facebook; - TargetAttributes = { - 58B5115C1A9E6B3D00147676 = { - CreatedOnToolsVersion = 6.1.1; - }; - }; - }; - buildConfigurationList = 58B511581A9E6B3D00147676 /* Build configuration list for PBXProject "RCTCameraRoll" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - ); - mainGroup = 58B511541A9E6B3D00147676; - productRefGroup = 58B5115E1A9E6B3D00147676 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 58B5115C1A9E6B3D00147676 /* RCTCameraRoll */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXSourcesBuildPhase section */ - 58B511591A9E6B3D00147676 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 8312EAEE1B85EB7C001867A2 /* RCTAssetsLibraryRequestHandler.m in Sources */, - 8312EAF11B85F071001867A2 /* RCTPhotoLibraryImageLoader.m in Sources */, - 137620351B31C53500677FF0 /* RCTImagePickerManager.m in Sources */, - 143879351AAD238D00F088A5 /* RCTCameraRollManager.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - 58B5116F1A9E6B3D00147676 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; - GCC_WARN_SHADOW = YES; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SKIP_INSTALL = YES; - WARNING_CFLAGS = ( - "-Werror", - "-Wall", - "-Wno-deprecated-declarations", - ); - }; - name = Debug; - }; - 58B511701A9E6B3D00147676 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = YES; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; - GCC_WARN_SHADOW = YES; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SKIP_INSTALL = YES; - VALIDATE_PRODUCT = YES; - WARNING_CFLAGS = ( - "-Werror", - "-Wall", - "-Wno-deprecated-declarations", - ); - }; - name = Release; - }; - 58B511721A9E6B3D00147676 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_STATIC_ANALYZER_MODE = deep; - LIBRARY_SEARCH_PATHS = "$(inherited)"; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = RCTCameraRoll; - RUN_CLANG_STATIC_ANALYZER = YES; - }; - name = Debug; - }; - 58B511731A9E6B3D00147676 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_STATIC_ANALYZER_MODE = deep; - LIBRARY_SEARCH_PATHS = "$(inherited)"; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = RCTCameraRoll; - RUN_CLANG_STATIC_ANALYZER = NO; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 58B511581A9E6B3D00147676 /* Build configuration list for PBXProject "RCTCameraRoll" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 58B5116F1A9E6B3D00147676 /* Debug */, - 58B511701A9E6B3D00147676 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 58B511711A9E6B3D00147676 /* Build configuration list for PBXNativeTarget "RCTCameraRoll" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 58B511721A9E6B3D00147676 /* Debug */, - 58B511731A9E6B3D00147676 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 58B511551A9E6B3D00147676 /* Project object */; -} diff --git a/Libraries/CameraRoll/React-RCTCameraRoll.podspec b/Libraries/CameraRoll/React-RCTCameraRoll.podspec deleted file mode 100644 index 2e283cf6865915..00000000000000 --- a/Libraries/CameraRoll/React-RCTCameraRoll.podspec +++ /dev/null @@ -1,36 +0,0 @@ -# coding: utf-8 -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -require "json" - -package = JSON.parse(File.read(File.join(__dir__, "..", "..", "package.json"))) -version = package['version'] - -source = { :git => 'https://github.com/facebook/react-native.git' } -if version == '1000.0.0' - # This is an unpublished version, use the latest commit hash of the react-native repo, which we’re presumably in. - source[:commit] = `git rev-parse HEAD`.strip -else - source[:tag] = "v#{version}" -end - -Pod::Spec.new do |s| - s.name = "React-RCTCameraRoll" - s.version = version - s.summary = "An API that provides access to the local camera roll or photo library." - s.homepage = "http://facebook.github.io/react-native/" - s.documentation_url = "https://facebook.github.io/react-native/docs/cameraroll" - s.license = package["license"] - s.author = "Facebook, Inc. and its affiliates" - s.platforms = { :ios => "9.0", :tvos => "9.2" } - s.source = source - s.source_files = "*.{h,m}" - s.preserve_paths = "package.json", "LICENSE", "LICENSE-docs" - s.header_dir = "React" - - s.dependency "React-Core", version - s.dependency "React-RCTImage", version -end diff --git a/Libraries/CameraRoll/__mocks__/CameraRoll.js b/Libraries/CameraRoll/__mocks__/CameraRoll.js deleted file mode 100644 index 5094bdc7290099..00000000000000 --- a/Libraries/CameraRoll/__mocks__/CameraRoll.js +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - * @format - */ -'use strict'; - -const CameraRoll = {}; - -export default CameraRoll; diff --git a/Libraries/CameraRoll/ImagePickerIOS.js b/Libraries/Image/ImagePickerIOS.js similarity index 100% rename from Libraries/CameraRoll/ImagePickerIOS.js rename to Libraries/Image/ImagePickerIOS.js diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js index 32142a1823641b..c1bfca14181584 100644 --- a/Libraries/react-native/react-native-implementation.js +++ b/Libraries/react-native/react-native-implementation.js @@ -202,15 +202,6 @@ module.exports = { get BackHandler() { return require('BackHandler'); }, - get CameraRoll() { - warnOnce( - 'cameraroll-moved', - 'CameraRoll has been extracted from react-native core and will be removed in a future release. ' + - "It can now be installed and imported from '@react-native-community/cameraroll' instead of 'react-native'. " + - 'See https://github.com/react-native-community/react-native-cameraroll', - ); - return require('CameraRoll'); - }, get Clipboard() { return require('Clipboard'); }, diff --git a/RNTester/Podfile b/RNTester/Podfile index 6c403e44fdd416..01dc26ac2bb977 100644 --- a/RNTester/Podfile +++ b/RNTester/Podfile @@ -7,13 +7,12 @@ target 'RNTester' do # use_frameworks! project 'RNTesterPods.xcodeproj' - + # Enable TurboModule use_react_native!(path: "..", turbo_modules_enabled: true) pod 'React-turbomodule-samples', :path => '../ReactCommon/turbomodule/samples' # Additional Pods which aren't included in the default Podfile - pod 'React-RCTCameraRoll', :path => '../Libraries/CameraRoll' pod 'React-ART', :path => '../Libraries/ART' pod 'React-RCTPushNotification', :path => '../Libraries/PushNotificationIOS' diff --git a/RNTester/Podfile.lock b/RNTester/Podfile.lock index f9f5a2e4f64f57..bd1e44261aba16 100644 --- a/RNTester/Podfile.lock +++ b/RNTester/Podfile.lock @@ -67,9 +67,6 @@ PODS: - React-Core (= 1000.0.0) - React-RCTNetwork (= 1000.0.0) - React-RCTWebSocket (= 1000.0.0) - - React-RCTCameraRoll (1000.0.0): - - React-Core (= 1000.0.0) - - React-RCTImage (= 1000.0.0) - React-RCTImage (1000.0.0): - React-Core (= 1000.0.0) - React-RCTNetwork (= 1000.0.0) @@ -130,7 +127,6 @@ DEPENDENCIES: - React-RCTActionSheet (from `../Libraries/ActionSheetIOS`) - React-RCTAnimation (from `../Libraries/NativeAnimation`) - React-RCTBlob (from `../Libraries/Blob`) - - React-RCTCameraRoll (from `../Libraries/CameraRoll`) - React-RCTImage (from `../Libraries/Image`) - React-RCTLinking (from `../Libraries/LinkingIOS`) - React-RCTNetwork (from `../Libraries/Network`) @@ -178,8 +174,6 @@ EXTERNAL SOURCES: :path: "../Libraries/NativeAnimation" React-RCTBlob: :path: "../Libraries/Blob" - React-RCTCameraRoll: - :path: "../Libraries/CameraRoll" React-RCTImage: :path: "../Libraries/Image" React-RCTLinking: @@ -220,7 +214,6 @@ SPEC CHECKSUMS: React-RCTActionSheet: 4ad4bfac1ba9ec020edf278362855448d607cafd React-RCTAnimation: f050e9fbe85e5616f74cea7a2557bdfb6be73cee React-RCTBlob: 9f907aab3417a43bbda84aef76f88ee528e877d4 - React-RCTCameraRoll: 288b1007d8e540771b917f89d7d99118a3477ee1 React-RCTImage: 4234a754ebdb922416f5f77cff121c680fd3ccbe React-RCTLinking: 3a52500942cc73999df19f541b7bda5887c3c43d React-RCTNetwork: 2042d2648e1160770ac0e5068bb5b648c03296a5 diff --git a/RNTester/RNTester.xcodeproj/project.pbxproj b/RNTester/RNTester.xcodeproj/project.pbxproj index 9d56534720e7f8..52cacf2394b200 100644 --- a/RNTester/RNTester.xcodeproj/project.pbxproj +++ b/RNTester/RNTester.xcodeproj/project.pbxproj @@ -16,7 +16,6 @@ 1341802C1AA9178B003F314A /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1341802B1AA91779003F314A /* libRCTNetwork.a */; }; 134CB92A1C85A38800265FA6 /* RCTModuleInitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 134CB9291C85A38800265FA6 /* RCTModuleInitTests.m */; }; 138D6A181B53CD440074A87E /* RCTShadowViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 138D6A161B53CD440074A87E /* RCTShadowViewTests.m */; }; - 138DEE241B9EDFB6007F4EA5 /* libRCTCameraRoll.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 138DEE091B9EDDDB007F4EA5 /* libRCTCameraRoll.a */; }; 1393D0381B68CD1300E1B601 /* RCTModuleMethodTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1393D0371B68CD1300E1B601 /* RCTModuleMethodTests.mm */; }; 139FDEDB1B0651FB00C62182 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDED91B0651EA00C62182 /* libRCTWebSocket.a */; }; 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; }; @@ -161,13 +160,6 @@ remoteGlobalIDString = 58B511DB1A9E6C8500147676; remoteInfo = RCTNetwork; }; - 138DEE081B9EDDDB007F4EA5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 138DEE021B9EDDDB007F4EA5 /* RCTCameraRoll.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 58B5115D1A9E6B3D00147676; - remoteInfo = RCTImage; - }; 139FDED81B0651EA00C62182 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 139FDECA1B0651EA00C62182 /* RCTWebSocket.xcodeproj */; @@ -488,7 +480,6 @@ 134180261AA91779003F314A /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = ../Libraries/Network/RCTNetwork.xcodeproj; sourceTree = ""; }; 134CB9291C85A38800265FA6 /* RCTModuleInitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTModuleInitTests.m; sourceTree = ""; }; 138D6A161B53CD440074A87E /* RCTShadowViewTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTShadowViewTests.m; sourceTree = ""; }; - 138DEE021B9EDDDB007F4EA5 /* RCTCameraRoll.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTCameraRoll.xcodeproj; path = ../Libraries/CameraRoll/RCTCameraRoll.xcodeproj; sourceTree = ""; }; 1393D0371B68CD1300E1B601 /* RCTModuleMethodTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RCTModuleMethodTests.mm; sourceTree = ""; }; 139FDECA1B0651EA00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = ../Libraries/WebSocket/RCTWebSocket.xcodeproj; sourceTree = ""; }; 13B07F961A680F5B00A75B9A /* RNTester.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RNTester.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -606,7 +597,6 @@ 2D66FF8F1ECA406D00F0A767 /* libART.a in Frameworks */, 147CED4C1AB3532B00DA3E4C /* libRCTActionSheet.a in Frameworks */, 13E501F11D07A84A005F35D8 /* libRCTAnimation.a in Frameworks */, - 138DEE241B9EDFB6007F4EA5 /* libRCTCameraRoll.a in Frameworks */, 1341802C1AA9178B003F314A /* libRCTNetwork.a in Frameworks */, 13417FE91AA91432003F314A /* libRCTImage.a in Frameworks */, 3578590A1B28D2CF00341EDB /* libRCTLinking.a in Frameworks */, @@ -690,7 +680,6 @@ 14AADEFF1AC3DB95002390C9 /* React.xcodeproj */, 14E0EEC81AB118F7000DECC3 /* RCTActionSheet.xcodeproj */, 13E5019C1D07A502005F35D8 /* RCTAnimation.xcodeproj */, - 138DEE021B9EDDDB007F4EA5 /* RCTCameraRoll.xcodeproj */, 13417FE31AA91428003F314A /* RCTImage.xcodeproj */, 357858F81B28D2C400341EDB /* RCTLinking.xcodeproj */, 134180261AA91779003F314A /* RCTNetwork.xcodeproj */, @@ -740,14 +729,6 @@ name = Products; sourceTree = ""; }; - 138DEE031B9EDDDB007F4EA5 /* Products */ = { - isa = PBXGroup; - children = ( - 138DEE091B9EDDDB007F4EA5 /* libRCTCameraRoll.a */, - ); - name = Products; - sourceTree = ""; - }; 139FDECB1B0651EA00C62182 /* Products */ = { isa = PBXGroup; children = ( @@ -1270,10 +1251,6 @@ ProductGroup = 5281CA4C1EEAC9A700AC40CD /* Products */; ProjectRef = 5281CA4B1EEAC9A700AC40CD /* RCTBlob.xcodeproj */; }, - { - ProductGroup = 138DEE031B9EDDDB007F4EA5 /* Products */; - ProjectRef = 138DEE021B9EDDDB007F4EA5 /* RCTCameraRoll.xcodeproj */; - }, { ProductGroup = 13417FE41AA91428003F314A /* Products */; ProjectRef = 13417FE31AA91428003F314A /* RCTImage.xcodeproj */; @@ -1350,13 +1327,6 @@ remoteRef = 1341802A1AA91779003F314A /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 138DEE091B9EDDDB007F4EA5 /* libRCTCameraRoll.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTCameraRoll.a; - remoteRef = 138DEE081B9EDDDB007F4EA5 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; 139FDED91B0651EA00C62182 /* libRCTWebSocket.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; diff --git a/RNTester/RNTesterPods.xcodeproj/project.pbxproj b/RNTester/RNTesterPods.xcodeproj/project.pbxproj index 63e244730cb0b9..1d5629c85b9856 100644 --- a/RNTester/RNTesterPods.xcodeproj/project.pbxproj +++ b/RNTester/RNTesterPods.xcodeproj/project.pbxproj @@ -385,7 +385,6 @@ "\"${PODS_ROOT}/Headers/Public/React-RCTActionSheet\"", "\"${PODS_ROOT}/Headers/Public/React-RCTAnimation\"", "\"${PODS_ROOT}/Headers/Public/React-RCTBlob\"", - "\"${PODS_ROOT}/Headers/Public/React-RCTCameraRoll\"", "\"${PODS_ROOT}/Headers/Public/React-RCTFabric\"", "\"${PODS_ROOT}/Headers/Public/React-RCTGeolocation\"", "\"${PODS_ROOT}/Headers/Public/React-RCTImage\"", @@ -434,7 +433,6 @@ "\"${PODS_ROOT}/Headers/Public/React-RCTActionSheet\"", "\"${PODS_ROOT}/Headers/Public/React-RCTAnimation\"", "\"${PODS_ROOT}/Headers/Public/React-RCTBlob\"", - "\"${PODS_ROOT}/Headers/Public/React-RCTCameraRoll\"", "\"${PODS_ROOT}/Headers/Public/React-RCTFabric\"", "\"${PODS_ROOT}/Headers/Public/React-RCTGeolocation\"", "\"${PODS_ROOT}/Headers/Public/React-RCTImage\"", diff --git a/RNTester/js/AssetScaledImageExample.js b/RNTester/js/AssetScaledImageExample.js index 32620c05e35ce0..c066badad97a71 100644 --- a/RNTester/js/AssetScaledImageExample.js +++ b/RNTester/js/AssetScaledImageExample.js @@ -13,7 +13,28 @@ const React = require('react'); const {Image, StyleSheet, View, ScrollView} = require('react-native'); -import type {PhotoIdentifier} from '../../Libraries/CameraRoll/CameraRoll'; +type PhotoIdentifier = { + node: { + type: string, + group_name: string, + image: { + filename: string, + uri: string, + height: number, + width: number, + isStored?: boolean, + playableDuration: number, + }, + timestamp: number, + location?: { + latitude?: number, + longitude?: number, + altitude?: number, + heading?: number, + speed?: number, + }, + }, +}; type Props = $ReadOnly<{| asset: PhotoIdentifier, diff --git a/RNTester/js/CameraRollExample.js b/RNTester/js/CameraRollExample.js deleted file mode 100644 index 7f0660db8f29b7..00000000000000 --- a/RNTester/js/CameraRollExample.js +++ /dev/null @@ -1,162 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - * @format - */ -'use strict'; - -const React = require('react'); -const { - CameraRoll, - Image, - Slider, - StyleSheet, - Switch, - Text, - View, - TouchableOpacity, -} = require('react-native'); - -const invariant = require('invariant'); - -const CameraRollView = require('./CameraRollView'); - -const AssetScaledImageExampleView = require('./AssetScaledImageExample'); - -import type { - PhotoIdentifier, - GroupTypes, -} from '../../Libraries/CameraRoll/CameraRoll'; - -type Props = $ReadOnly<{| - navigator?: ?Array< - $ReadOnly<{| - title: string, - component: Class>, - backButtonTitle: string, - passProps: $ReadOnly<{|asset: PhotoIdentifier|}>, - |}>, - >, -|}>; - -type State = {| - groupTypes: GroupTypes, - sliderValue: number, - bigImages: boolean, -|}; - -class CameraRollExample extends React.Component { - state = { - groupTypes: 'SavedPhotos', - sliderValue: 1, - bigImages: true, - }; - _cameraRollView: ?React.ElementRef; - render() { - return ( - - - {(this.state.bigImages ? 'Big' : 'Small') + ' Images'} - - {'Group Type: ' + this.state.groupTypes} - { - this._cameraRollView = ref; - }} - batchSize={20} - groupTypes={this.state.groupTypes} - renderImage={this._renderImage} - bigImages={this.state.bigImages} - /> - - ); - } - - loadAsset(asset) { - if (this.props.navigator) { - this.props.navigator.push({ - title: 'Camera Roll Image', - component: AssetScaledImageExampleView, - backButtonTitle: 'Back', - passProps: {asset: asset}, - }); - } - } - - _renderImage = (asset: PhotoIdentifier) => { - const imageSize = this.state.bigImages ? 150 : 75; - const imageStyle = [styles.image, {width: imageSize, height: imageSize}]; - const {location} = asset.node; - const locationStr = location - ? JSON.stringify(location) - : 'Unknown location'; - return ( - - - - - {asset.node.image.uri} - {locationStr} - {asset.node.group_name} - {new Date(asset.node.timestamp).toString()} - - - - ); - }; - - _onSliderChange = value => { - const options = Object.keys(CameraRoll.GroupTypesOptions); - const index = Math.floor(value * options.length * 0.99); - const groupTypes = options[index]; - if (groupTypes !== this.state.groupTypes) { - this.setState({groupTypes: groupTypes}); - } - }; - - _onSwitchChange = value => { - invariant(this._cameraRollView, 'ref should be set'); - this.setState({bigImages: value}); - }; -} - -const styles = StyleSheet.create({ - row: { - flexDirection: 'row', - flex: 1, - }, - url: { - fontSize: 9, - marginBottom: 14, - }, - image: { - margin: 4, - }, - info: { - flex: 1, - }, -}); - -exports.title = 'Camera Roll'; -exports.description = - "Example component that uses CameraRoll to list user's photos"; -exports.examples = [ - { - title: 'Photos', - render(): React.Node { - return ; - }, - }, -]; diff --git a/RNTester/js/CameraRollView.js b/RNTester/js/CameraRollView.js deleted file mode 100644 index 8058f0aba3364b..00000000000000 --- a/RNTester/js/CameraRollView.js +++ /dev/null @@ -1,264 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @flow - */ - -'use strict'; - -const React = require('react'); -const { - ActivityIndicator, - Alert, - CameraRoll, - Image, - FlatList, - PermissionsAndroid, - Platform, - StyleSheet, - View, -} = require('react-native'); - -const groupByEveryN = require('../../Libraries/Utilities/groupByEveryN'); -const logError = require('../../Libraries/Utilities/logError'); - -import type { - PhotoIdentifier, - PhotoIdentifiersPage, - GetPhotosParams, -} from '../../Libraries/CameraRoll/CameraRoll'; - -type Props = $ReadOnly<{| - /** - * The group where the photos will be fetched from. Possible - * values are 'Album', 'All', 'Event', 'Faces', 'Library', 'PhotoStream' - * and SavedPhotos. - */ - groupTypes: - | 'Album' - | 'All' - | 'Event' - | 'Faces' - | 'Library' - | 'PhotoStream' - | 'SavedPhotos', - - /** - * Number of images that will be fetched in one page. - */ - batchSize: number, - - /** - * A function that takes a single image as a parameter and renders it. - */ - renderImage: PhotoIdentifier => React.Node, - - /** - * imagesPerRow: Number of images to be shown in each row. - */ - imagesPerRow: number, - - /** - * A boolean that indicates if we should render large or small images. - */ - bigImages?: boolean, - - /** - * The asset type, one of 'Photos', 'Videos' or 'All' - */ - assetType: 'Photos' | 'Videos' | 'All', -|}>; - -type State = {| - assets: Array, - data: Array>, - seen: Set, - lastCursor: ?string, - noMore: boolean, - loadingMore: boolean, -|}; - -type Row = { - item: Array, -}; - -class CameraRollView extends React.Component { - static defaultProps = { - groupTypes: 'SavedPhotos', - batchSize: 5, - imagesPerRow: 1, - assetType: 'Photos', - renderImage: function(asset: PhotoIdentifier) { - const imageSize = 150; - const imageStyle = [styles.image, {width: imageSize, height: imageSize}]; - return ; - }, - }; - - state = this.getInitialState(); - - getInitialState() { - return { - assets: [], - data: [], - seen: new Set(), - lastCursor: null, - noMore: false, - loadingMore: false, - }; - } - - componentDidMount() { - this.fetch(); - } - - UNSAFE_componentWillReceiveProps(nextProps: Props) { - if (this.props.groupTypes !== nextProps.groupTypes) { - this.fetch(true); - } - } - - async _fetch(clear?: boolean) { - if (clear) { - this.setState(this.getInitialState(), this.fetch); - return; - } - - if (Platform.OS === 'android') { - const result = await PermissionsAndroid.request( - PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE, - { - title: 'Permission Explanation', - message: 'RNTester would like to access your pictures.', - }, - ); - if (result !== 'granted') { - Alert.alert('Access to pictures was denied.'); - return; - } - } - - const fetchParams: GetPhotosParams = { - first: this.props.batchSize, - groupTypes: this.props.groupTypes, - assetType: this.props.assetType, - }; - if (Platform.OS === 'android') { - // not supported in android - delete fetchParams.groupTypes; - } - - if (this.state.lastCursor) { - fetchParams.after = this.state.lastCursor; - } - - try { - const data = await CameraRoll.getPhotos(fetchParams); - this._appendAssets(data); - } catch (e) { - logError(e); - } - } - - /** - * Fetches more images from the camera roll. If clear is set to true, it will - * set the component to its initial state and re-fetch the images. - */ - fetch = (clear?: boolean) => { - if (!this.state.loadingMore) { - this.setState({loadingMore: true}, () => { - this._fetch(clear); - }); - } - }; - - render() { - return ( - String(idx)} - renderItem={this._renderItem} - ListFooterComponent={this._renderFooterSpinner} - onEndReached={this._onEndReached} - onEndReachedThreshold={0.2} - style={styles.container} - data={this.state.data || []} - extraData={this.props.bigImages + this.state.noMore} - /> - ); - } - - _renderFooterSpinner = () => { - if (!this.state.noMore) { - return ; - } - return null; - }; - - _renderItem = (row: Row) => { - return ( - - {row.item.map(image => (image ? this.props.renderImage(image) : null))} - - ); - }; - - _appendAssets(data: PhotoIdentifiersPage) { - const assets = data.edges; - const newState: $Shape = {loadingMore: false}; - - if (!data.page_info.has_next_page) { - newState.noMore = true; - } - - if (assets.length > 0) { - newState.lastCursor = data.page_info.end_cursor; - newState.seen = new Set(this.state.seen); - - // Unique assets efficiently - // Checks new pages against seen objects - const uniqAssets = []; - for (let index = 0; index < assets.length; index++) { - const asset = assets[index]; - let value = asset.node.image.uri; - if (newState.seen.has(value)) { - continue; - } - newState.seen.add(value); - uniqAssets.push(asset); - } - - newState.assets = this.state.assets.concat(uniqAssets); - newState.data = groupByEveryN( - newState.assets, - this.props.imagesPerRow, - ); - } - - this.setState(newState); - } - - _onEndReached = () => { - if (!this.state.noMore) { - this.fetch(); - } - }; -} - -const styles = StyleSheet.create({ - row: { - flexDirection: 'row', - flex: 1, - }, - image: { - margin: 4, - }, - container: { - flex: 1, - }, -}); - -module.exports = CameraRollView; diff --git a/RNTester/js/ImageEditingExample.js b/RNTester/js/ImageEditingExample.js deleted file mode 100644 index fa6e124ef30b82..00000000000000 --- a/RNTester/js/ImageEditingExample.js +++ /dev/null @@ -1,315 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @flow - */ -'use strict'; - -const React = require('react'); -const { - CameraRoll, - Image, - ImageEditor, - Platform, - ScrollView, - StyleSheet, - Text, - TouchableHighlight, - View, -} = require('react-native'); - -const PAGE_SIZE = 20; - -type ImageOffset = {| - x: number, - y: number, -|}; - -type ImageSize = {| - width: number, - height: number, -|}; - -type ImageCropData = {| - offset: ImageOffset, - size: ImageSize, - displaySize?: ?ImageSize, - resizeMode?: ?any, -|}; - -class SquareImageCropper extends React.Component< - $FlowFixMeProps, - $FlowFixMeState, -> { - state: any; - _isMounted: boolean; - _transformData: ImageCropData; - - /* $FlowFixMe(>=0.85.0 site=react_native_fb) This comment suppresses an error - * found when Flow v0.85 was deployed. To see the error, delete this comment - * and run Flow. */ - constructor(props) { - super(props); - this._isMounted = true; - this.state = { - randomPhoto: null, - measuredSize: null, - croppedImageURI: null, - cropError: null, - }; - this._fetchRandomPhoto(); - } - - async _fetchRandomPhoto() { - try { - const data = await CameraRoll.getPhotos({first: PAGE_SIZE}); - if (!this._isMounted) { - return; - } - const edges = data.edges; - const edge = edges[Math.floor(Math.random() * edges.length)]; - const randomPhoto = edge && edge.node && edge.node.image; - if (randomPhoto) { - this.setState({randomPhoto}); - } - } catch (error) { - console.warn("Can't get a photo from camera roll", error); - } - } - - componentWillUnmount() { - this._isMounted = false; - } - - render() { - if (!this.state.measuredSize) { - return ( - { - const measuredWidth = event.nativeEvent.layout.width; - if (!measuredWidth) { - return; - } - this.setState({ - measuredSize: {width: measuredWidth, height: measuredWidth}, - }); - }} - /> - ); - } - - if (!this.state.croppedImageURI) { - return this._renderImageCropper(); - } - return this._renderCroppedImage(); - } - - _renderImageCropper() { - if (!this.state.randomPhoto) { - return ; - } - let error = null; - if (this.state.cropError) { - error = {this.state.cropError.message}; - } - return ( - - Drag the image within the square to crop: - (this._transformData = data)} - /> - - - Crop - - - {error} - - ); - } - - _renderCroppedImage() { - return ( - - Here is the cropped image: - - - - Try again - - - - ); - } - - _crop() { - ImageEditor.cropImage( - this.state.randomPhoto.uri, - this._transformData, - croppedImageURI => this.setState({croppedImageURI}), - cropError => this.setState({cropError}), - ); - } - - _reset() { - this.setState({ - randomPhoto: null, - croppedImageURI: null, - cropError: null, - }); - this._fetchRandomPhoto(); - } -} - -class ImageCropper extends React.Component<$FlowFixMeProps, $FlowFixMeState> { - _contentOffset: ImageOffset; - _maximumZoomScale: number; - _minimumZoomScale: number; - _scaledImageSize: ImageSize; - _horizontal: boolean; - - UNSAFE_componentWillMount() { - // Scale an image to the minimum size that is large enough to completely - // fill the crop box. - const widthRatio = this.props.image.width / this.props.size.width; - const heightRatio = this.props.image.height / this.props.size.height; - this._horizontal = widthRatio > heightRatio; - if (this._horizontal) { - this._scaledImageSize = { - width: this.props.image.width / heightRatio, - height: this.props.size.height, - }; - } else { - this._scaledImageSize = { - width: this.props.size.width, - height: this.props.image.height / widthRatio, - }; - if (Platform.OS === 'android') { - // hack to work around Android ScrollView a) not supporting zoom, and - // b) not supporting vertical scrolling when nested inside another - // vertical ScrollView (which it is, when displayed inside UIExplorer) - this._scaledImageSize.width *= 2; - this._scaledImageSize.height *= 2; - this._horizontal = true; - } - } - this._contentOffset = { - x: (this._scaledImageSize.width - this.props.size.width) / 2, - y: (this._scaledImageSize.height - this.props.size.height) / 2, - }; - this._maximumZoomScale = Math.min( - this.props.image.width / this._scaledImageSize.width, - this.props.image.height / this._scaledImageSize.height, - ); - this._minimumZoomScale = Math.max( - this.props.size.width / this._scaledImageSize.width, - this.props.size.height / this._scaledImageSize.height, - ); - this._updateTransformData( - this._contentOffset, - this._scaledImageSize, - this.props.size, - ); - } - - _onScroll(event) { - this._updateTransformData( - event.nativeEvent.contentOffset, - event.nativeEvent.contentSize, - event.nativeEvent.layoutMeasurement, - ); - } - - _updateTransformData(offset, scaledImageSize, croppedImageSize) { - const offsetRatioX = offset.x / scaledImageSize.width; - const offsetRatioY = offset.y / scaledImageSize.height; - const sizeRatioX = croppedImageSize.width / scaledImageSize.width; - const sizeRatioY = croppedImageSize.height / scaledImageSize.height; - - const cropData: ImageCropData = { - offset: { - x: this.props.image.width * offsetRatioX, - y: this.props.image.height * offsetRatioY, - }, - size: { - width: this.props.image.width * sizeRatioX, - height: this.props.image.height * sizeRatioY, - }, - }; - this.props.onTransformDataChange && - this.props.onTransformDataChange(cropData); - } - - render() { - return ( - - - - ); - } -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - alignSelf: 'stretch', - }, - imageCropper: { - alignSelf: 'center', - marginTop: 12, - }, - cropButtonTouchable: { - alignSelf: 'center', - marginTop: 12, - }, - cropButton: { - padding: 12, - backgroundColor: 'blue', - borderRadius: 4, - }, - cropButtonLabel: { - color: 'white', - fontSize: 16, - fontWeight: '500', - }, -}); - -exports.framework = 'React'; -exports.title = 'ImageEditor'; -exports.description = 'Cropping and scaling with ImageEditor'; -exports.examples = [ - { - title: 'Image Cropping', - render() { - return ; - }, - }, -]; diff --git a/RNTester/js/RNTesterList.android.js b/RNTester/js/RNTesterList.android.js index 2ff7ec9683313f..4506e2163f2d17 100644 --- a/RNTester/js/RNTesterList.android.js +++ b/RNTester/js/RNTesterList.android.js @@ -138,10 +138,6 @@ const APIExamples: Array = [ key: 'BorderExample', module: require('./BorderExample'), }, - { - key: 'CameraRollExample', - module: require('./CameraRollExample'), - }, { key: 'ClipboardExample', module: require('./ClipboardExample'), @@ -158,10 +154,6 @@ const APIExamples: Array = [ key: 'Dimensions', module: require('./DimensionsExample'), }, - { - key: 'ImageEditingExample', - module: require('./ImageEditingExample'), - }, { key: 'LayoutEventsExample', module: require('./LayoutEventsExample'), diff --git a/RNTester/js/RNTesterList.ios.js b/RNTester/js/RNTesterList.ios.js index c0ff9a2f5b2c1b..f8531648274665 100644 --- a/RNTester/js/RNTesterList.ios.js +++ b/RNTester/js/RNTesterList.ios.js @@ -216,11 +216,6 @@ const APIExamples: Array = [ module: require('./BoxShadowExample'), supportsTVOS: true, }, - { - key: 'CameraRollExample', - module: require('./CameraRollExample'), - supportsTVOS: false, - }, { key: 'ClipboardExample', module: require('./ClipboardExample'), @@ -236,11 +231,6 @@ const APIExamples: Array = [ module: require('./DimensionsExample'), supportsTVOS: true, }, - { - key: 'ImageEditingExample', - module: require('./ImageEditingExample'), - supportsTVOS: false, - }, { key: 'LayoutAnimationExample', module: require('./LayoutAnimationExample'), diff --git a/RNTester/js/XHRExample.js b/RNTester/js/XHRExample.js index a7df025303a4e8..b9e3ad37087bbe 100644 --- a/RNTester/js/XHRExample.js +++ b/RNTester/js/XHRExample.js @@ -14,7 +14,6 @@ const React = require('react'); const XHRExampleDownload = require('./XHRExampleDownload'); const XHRExampleBinaryUpload = require('./XHRExampleBinaryUpload'); -const XHRExampleFormData = require('./XHRExampleFormData'); const XHRExampleHeaders = require('./XHRExampleHeaders'); const XHRExampleFetch = require('./XHRExampleFetch'); const XHRExampleOnTimeOut = require('./XHRExampleOnTimeOut'); @@ -38,12 +37,6 @@ exports.examples = [ return ; }, }, - { - title: 'multipart/form-data Upload', - render() { - return ; - }, - }, { title: 'Fetch Test', render() { diff --git a/RNTester/js/XHRExampleFormData.js b/RNTester/js/XHRExampleFormData.js deleted file mode 100644 index 12fffc6432a557..00000000000000 --- a/RNTester/js/XHRExampleFormData.js +++ /dev/null @@ -1,242 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @flow - */ - -'use strict'; - -const React = require('react'); -const { - CameraRoll, - Image, - ImageEditor, - Platform, - StyleSheet, - Text, - TextInput, - TouchableHighlight, - View, -} = require('react-native'); - -const XHRExampleBinaryUpload = require('./XHRExampleBinaryUpload'); - -const PAGE_SIZE = 20; - -class XHRExampleFormData extends React.Component { - state: Object = { - isUploading: false, - uploadProgress: null, - randomPhoto: null, - textParams: [], - }; - - _isMounted: boolean = true; - - constructor(props: Object) { - super(props); - this._fetchRandomPhoto(); - } - - componentWillUnmount() { - this._isMounted = false; - } - - _fetchRandomPhoto = () => { - CameraRoll.getPhotos({ - first: PAGE_SIZE, - groupTypes: Platform.OS === 'ios' ? 'All' : undefined, - assetType: 'All', - }).then( - data => { - if (!this._isMounted) { - return; - } - const edges = data.edges; - const edge = edges[Math.floor(Math.random() * edges.length)]; - const randomPhoto = edge && edge.node && edge.node.image; - if (randomPhoto) { - let {width, height} = randomPhoto; - width *= 0.25; - height *= 0.25; - ImageEditor.cropImage( - randomPhoto.uri, - {offset: {x: 0, y: 0}, size: {width, height}}, - uri => this.setState({randomPhoto: {uri}}), - error => undefined, - ); - } - }, - error => undefined, - ); - }; - - _addTextParam = () => { - const textParams = this.state.textParams; - textParams.push({name: '', value: ''}); - this.setState({textParams}); - }; - - _onTextParamNameChange(index, text) { - const textParams = this.state.textParams; - textParams[index].name = text; - this.setState({textParams}); - } - - _onTextParamValueChange(index, text) { - const textParams = this.state.textParams; - textParams[index].value = text; - this.setState({textParams}); - } - - _upload = () => { - const xhr = new XMLHttpRequest(); - xhr.open('POST', 'http://posttestserver.com/post.php'); - xhr.onload = () => { - this.setState({isUploading: false}); - XHRExampleBinaryUpload.handlePostTestServerUpload(xhr); - }; - const formdata = new FormData(); - if (this.state.randomPhoto) { - formdata.append('image', { - ...this.state.randomPhoto, - type: 'image/jpg', - name: 'image.jpg', - }); - } - this.state.textParams.forEach(param => - formdata.append(param.name, param.value), - ); - xhr.upload.onprogress = event => { - if (event.lengthComputable) { - this.setState({uploadProgress: event.loaded / event.total}); - } - }; - - xhr.send(formdata); - this.setState({isUploading: true}); - }; - - render() { - let image = null; - if (this.state.randomPhoto) { - image = ( - - ); - } - const textItems = this.state.textParams.map((item, index) => ( - - - = - - - )); - let uploadButtonLabel = this.state.isUploading ? 'Uploading...' : 'Upload'; - const uploadProgress = this.state.uploadProgress; - if (uploadProgress !== null) { - uploadButtonLabel += ' ' + Math.round(uploadProgress * 100) + '%'; - } - let uploadButton = ( - - {uploadButtonLabel} - - ); - if (!this.state.isUploading) { - uploadButton = ( - - {uploadButton} - - ); - } - return ( - - - - Random photo from your library ( - - update - - ) - - {image} - - {textItems} - - - Add a text param - - - {uploadButton} - - ); - } -} - -const styles = StyleSheet.create({ - paramRow: { - flexDirection: 'row', - paddingVertical: 8, - alignItems: 'center', - borderBottomWidth: StyleSheet.hairlineWidth, - borderBottomColor: 'grey', - }, - photoLabel: { - flex: 1, - }, - randomPhoto: { - width: 50, - height: 50, - }, - textButton: { - color: 'blue', - }, - addTextParamButton: { - marginTop: 8, - }, - textInput: { - flex: 1, - borderRadius: 3, - borderColor: 'grey', - borderWidth: 1, - height: Platform.OS === 'android' ? 50 : 30, - paddingLeft: 8, - }, - equalSign: { - paddingHorizontal: 4, - }, - uploadButton: { - marginTop: 16, - }, - uploadButtonBox: { - flex: 1, - paddingVertical: 12, - alignItems: 'center', - backgroundColor: 'blue', - borderRadius: 4, - }, - uploadButtonLabel: { - color: 'white', - fontSize: 16, - fontWeight: '500', - }, -}); - -module.exports = XHRExampleFormData; From d742c7be360f0481ab1805af3961f1475ed2937e Mon Sep 17 00:00:00 2001 From: Emily Janzer Date: Thu, 23 May 2019 13:43:57 -0700 Subject: [PATCH 0061/1084] Auto-formatting for Binding Summary: I just learned about Nuclide's auto-formatting (cmd-shift-c) and started using it in another diff, but I didn't want to pollute the diff with a bunch of formatting changes, so here we are. I don't know if anyone else uses Nuclide's auto-formatting, or something else - happy to ditch this if that's not how we roll. Reviewed By: shergin Differential Revision: D15389601 fbshipit-source-id: e3b20acd073adf3cc7bab1f62d86c5b5dab8c4fc --- .../facebook/react/fabric/jsi/jni/Binding.cpp | 99 ++++++++++--------- .../facebook/react/fabric/jsi/jni/Binding.h | 10 +- 2 files changed, 60 insertions(+), 49 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.cpp index 10e9551ecbb67a..286392d5590b83 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.cpp @@ -12,14 +12,14 @@ #include #include #include -#include #include #include +#include #include -#include #include #include #include +#include #include using namespace facebook::jni; @@ -45,7 +45,7 @@ jni::local_ref Binding::initHybrid( return makeCxxInstance(); } -void Binding::startSurface(jint surfaceId, NativeMap* initialProps) { +void Binding::startSurface(jint surfaceId, NativeMap *initialProps) { if (scheduler_) { scheduler_->startSurface(surfaceId, "", initialProps->consume()); } @@ -54,7 +54,7 @@ void Binding::startSurface(jint surfaceId, NativeMap* initialProps) { void Binding::renderTemplateToSurface(jint surfaceId, jstring uiTemplate) { if (scheduler_) { auto env = Environment::current(); - const char* nativeString = env->GetStringUTFChars(uiTemplate, JNI_FALSE); + const char *nativeString = env->GetStringUTFChars(uiTemplate, JNI_FALSE); scheduler_->renderTemplateToSurface(surfaceId, nativeString); env->ReleaseStringUTFChars(uiTemplate, nativeString); } @@ -91,9 +91,9 @@ void Binding::setConstraints( void Binding::installFabricUIManager( jlong jsContextNativePointer, jni::alias_ref javaUIManager, - EventBeatManager* eventBeatManager, + EventBeatManager *eventBeatManager, jni::alias_ref jsMessageQueueThread, - ComponentFactoryDelegate* componentsRegistry, + ComponentFactoryDelegate *componentsRegistry, jni::alias_ref reactNativeConfig) { javaUIManager_ = make_global(javaUIManager); @@ -103,10 +103,10 @@ void Binding::installFabricUIManager( auto sharedJSMessageQueueThread = std::make_shared(jsMessageQueueThread); - Runtime* runtime = (Runtime*)jsContextNativePointer; + Runtime *runtime = (Runtime *)jsContextNativePointer; RuntimeExecutor runtimeExecutor = [runtime, sharedJSMessageQueueThread]( - std::function&& callback) { + std::function &&callback) { sharedJSMessageQueueThread->runOnQueue( [runtime, callback = std::move(callback)]() { callback(*runtime); @@ -129,7 +129,8 @@ void Binding::installFabricUIManager( eventBeatManager, runtimeExecutor, localJavaUIManager); }; - std::shared_ptr config = std::make_shared(reactNativeConfig); + std::shared_ptr config = + std::make_shared(reactNativeConfig); contextContainer->registerInstance(config, "ReactNativeConfig"); contextContainer->registerInstance( synchronousBeatFactory, "synchronous"); @@ -155,7 +156,7 @@ inline local_ref castReadableMap( } // TODO: this method will be removed when binding for components are code-gen -local_ref getPlatformComponentName(const ShadowView& shadowView) { +local_ref getPlatformComponentName(const ShadowView &shadowView) { local_ref componentName; auto newViewProps = std::dynamic_pointer_cast(shadowView.props); @@ -170,8 +171,8 @@ local_ref getPlatformComponentName(const ShadowView& shadowView) { } local_ref createUpdateEventEmitterMountItem( - const jni::global_ref& javaUIManager, - const ShadowViewMutation& mutation) { + const jni::global_ref &javaUIManager, + const ShadowViewMutation &mutation) { if (!mutation.newChildShadowView.eventEmitter) { return nullptr; } @@ -179,7 +180,7 @@ local_ref createUpdateEventEmitterMountItem( // Do not hold a reference to javaEventEmitter from the C++ side. auto javaEventEmitter = EventEmitterWrapper::newObjectJavaArgs(); - EventEmitterWrapper* cEventEmitter = cthis(javaEventEmitter); + EventEmitterWrapper *cEventEmitter = cthis(javaEventEmitter); cEventEmitter->eventEmitter = eventEmitter; static auto updateEventEmitterInstruction = @@ -192,8 +193,8 @@ local_ref createUpdateEventEmitterMountItem( } local_ref createUpdatePropsMountItem( - const jni::global_ref& javaUIManager, - const ShadowViewMutation& mutation) { + const jni::global_ref &javaUIManager, + const ShadowViewMutation &mutation) { auto shadowView = mutation.newChildShadowView; auto newViewProps = *std::dynamic_pointer_cast(shadowView.props); @@ -213,8 +214,8 @@ local_ref createUpdatePropsMountItem( } local_ref createUpdateLayoutMountItem( - const jni::global_ref& javaUIManager, - const ShadowViewMutation& mutation) { + const jni::global_ref &javaUIManager, + const ShadowViewMutation &mutation) { auto oldChildShadowView = mutation.oldChildShadowView; auto newChildShadowView = mutation.newChildShadowView; @@ -240,8 +241,8 @@ local_ref createUpdateLayoutMountItem( } local_ref createInsertMountItem( - const jni::global_ref& javaUIManager, - const ShadowViewMutation& mutation) { + const jni::global_ref &javaUIManager, + const ShadowViewMutation &mutation) { static auto insertInstruction = jni::findClassStatic(UIManagerJavaDescriptor) ->getMethod(jint, jint, jint)>( @@ -255,8 +256,8 @@ local_ref createInsertMountItem( } local_ref createUpdateLocalData( - const jni::global_ref& javaUIManager, - const ShadowViewMutation& mutation) { + const jni::global_ref &javaUIManager, + const ShadowViewMutation &mutation) { static auto updateLocalDataInstruction = jni::findClassStatic(UIManagerJavaDescriptor) ->getMethod(jint, ReadableMap::javaobject)>( @@ -278,8 +279,8 @@ local_ref createUpdateLocalData( } local_ref createUpdateStateMountItem( - const jni::global_ref& javaUIManager, - const ShadowViewMutation& mutation) { + const jni::global_ref &javaUIManager, + const ShadowViewMutation &mutation) { static auto updateStateInstruction = jni::findClassStatic(UIManagerJavaDescriptor) ->getMethod(jint, jobject)>( @@ -293,7 +294,7 @@ local_ref createUpdateStateMountItem( local_ref javaStateWrapper = nullptr; if (state != nullptr) { javaStateWrapper = StateWrapperImpl::newObjectJavaArgs(); - StateWrapperImpl* cStateWrapper = cthis(javaStateWrapper); + StateWrapperImpl *cStateWrapper = cthis(javaStateWrapper); cStateWrapper->state_ = state; } @@ -303,10 +304,9 @@ local_ref createUpdateStateMountItem( (javaStateWrapper != nullptr ? javaStateWrapper.get() : nullptr)); } - local_ref createRemoveMountItem( - const jni::global_ref& javaUIManager, - const ShadowViewMutation& mutation) { + const jni::global_ref &javaUIManager, + const ShadowViewMutation &mutation) { static auto removeInstruction = jni::findClassStatic(UIManagerJavaDescriptor) ->getMethod(jint, jint, jint)>( @@ -320,8 +320,8 @@ local_ref createRemoveMountItem( } local_ref createDeleteMountItem( - const jni::global_ref& javaUIManager, - const ShadowViewMutation& mutation) { + const jni::global_ref &javaUIManager, + const ShadowViewMutation &mutation) { static auto deleteInstruction = jni::findClassStatic(UIManagerJavaDescriptor) ->getMethod(jint)>("deleteMountItem"); @@ -330,8 +330,8 @@ local_ref createDeleteMountItem( } local_ref createCreateMountItem( - const jni::global_ref& javaUIManager, - const ShadowViewMutation& mutation, + const jni::global_ref &javaUIManager, + const ShadowViewMutation &mutation, const Tag surfaceId) { static auto createJavaInstruction = jni::findClassStatic(UIManagerJavaDescriptor) @@ -343,7 +343,8 @@ local_ref createCreateMountItem( local_ref componentName = getPlatformComponentName(newChildShadowView); - jboolean isLayoutable = newChildShadowView.layoutMetrics != EmptyLayoutMetrics; + jboolean isLayoutable = + newChildShadowView.layoutMetrics != EmptyLayoutMetrics; return createJavaInstruction( javaUIManager, @@ -380,7 +381,7 @@ void Binding::schedulerDidFinishTransaction( std::unordered_set deletedViewTags; int position = 0; - for (const auto& mutation : mutations) { + for (const auto &mutation : mutations) { auto oldChildShadowView = mutation.oldChildShadowView; auto newChildShadowView = mutation.newChildShadowView; @@ -389,12 +390,13 @@ void Binding::schedulerDidFinishTransaction( switch (mutation.type) { case ShadowViewMutation::Create: { - if (mutation.newChildShadowView.props->revision > 1 - || deletedViewTags.find(mutation.newChildShadowView.tag) != deletedViewTags.end()) { + if (mutation.newChildShadowView.props->revision > 1 || + deletedViewTags.find(mutation.newChildShadowView.tag) != + deletedViewTags.end()) { mountItems[position++] = createCreateMountItem(javaUIManager_, mutation, surfaceId); } - break; + break; } case ShadowViewMutation::Remove: { if (!isVirtual) { @@ -448,10 +450,12 @@ void Binding::schedulerDidFinishTransaction( case ShadowViewMutation::Insert: { if (!isVirtual) { // Insert item - mountItems[position++] = createInsertMountItem(javaUIManager_, mutation); + mountItems[position++] = + createInsertMountItem(javaUIManager_, mutation); if (mutation.newChildShadowView.props->revision > 1 || - deletedViewTags.find(mutation.newChildShadowView.tag) != deletedViewTags.end()) { + deletedViewTags.find(mutation.newChildShadowView.tag) != + deletedViewTags.end()) { mountItems[position++] = createUpdatePropsMountItem(javaUIManager_, mutation); } @@ -523,12 +527,13 @@ void Binding::setPixelDensity(float pointScaleFactor) { void Binding::schedulerDidRequestPreliminaryViewAllocation( const SurfaceId surfaceId, const ShadowView &shadowView) { - bool isLayoutableShadowNode = shadowView.layoutMetrics != EmptyLayoutMetrics; static auto preallocateView = jni::findClassStatic(UIManagerJavaDescriptor) - ->getMethod("preallocateView"); + ->getMethod( + "preallocateView"); // Do not hold onto Java object from C // We DO want to hold onto C object from Java, since we don't know the @@ -536,15 +541,21 @@ void Binding::schedulerDidRequestPreliminaryViewAllocation( local_ref javaStateWrapper = nullptr; if (shadowView.state != nullptr) { javaStateWrapper = StateWrapperImpl::newObjectJavaArgs(); - StateWrapperImpl* cStateWrapper = cthis(javaStateWrapper); + StateWrapperImpl *cStateWrapper = cthis(javaStateWrapper); cStateWrapper->state_ = shadowView.state; } - local_ref props = - castReadableMap(ReadableNativeMap::newObjectCxxArgs(shadowView.props->rawProps)); + local_ref props = castReadableMap( + ReadableNativeMap::newObjectCxxArgs(shadowView.props->rawProps)); auto component = getPlatformComponentName(shadowView); preallocateView( - javaUIManager_, surfaceId, shadowView.tag, component.get(), props.get(), (javaStateWrapper != nullptr ? javaStateWrapper.get() : nullptr), isLayoutableShadowNode); + javaUIManager_, + surfaceId, + shadowView.tag, + component.get(), + props.get(), + (javaStateWrapper != nullptr ? javaStateWrapper.get() : nullptr), + isLayoutableShadowNode); } void Binding::registerNatives() { diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.h b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.h index d082e78f285fb9..6486763e7eeca0 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.h +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.h @@ -21,7 +21,7 @@ class Instance; class Binding : public jni::HybridClass, public SchedulerDelegate { public: - constexpr static const char* const kJavaDescriptor = + constexpr static const char *const kJavaDescriptor = "Lcom/facebook/react/fabric/jsi/Binding;"; static void registerNatives(); @@ -45,19 +45,19 @@ class Binding : public jni::HybridClass, public SchedulerDelegate { void installFabricUIManager( jlong jsContextNativePointer, jni::alias_ref javaUIManager, - EventBeatManager* eventBeatManager, + EventBeatManager *eventBeatManager, jni::alias_ref jsMessageQueueThread, - ComponentFactoryDelegate* componentsRegistry, + ComponentFactoryDelegate *componentsRegistry, jni::alias_ref reactNativeConfig); - void startSurface(jint surfaceId, NativeMap* initialProps); + void startSurface(jint surfaceId, NativeMap *initialProps); void renderTemplateToSurface(jint surfaceId, jstring uiTemplate); void stopSurface(jint surfaceId); void schedulerDidFinishTransaction( - MountingCoordinator::Shared const &mountingCoordinator); + MountingCoordinator::Shared const &mountingCoordinator); void schedulerDidRequestPreliminaryViewAllocation( const SurfaceId surfaceId, From f23da3aeb0cd824f0b0816fd70f82456584606bd Mon Sep 17 00:00:00 2001 From: Emily Janzer Date: Thu, 23 May 2019 13:43:57 -0700 Subject: [PATCH 0062/1084] Use startSurface on Android Summary: Right now calling FabricUIManager.addRootView() doesn't actually start running the application on Android. This diff: 1. Removes the #ifndef so that we actually call UIManagerBinding.startSurface() on Android 2. Passes through the JS module name from addRootView so we can render the surface (falls back to an empty string if not provided, which is the current behavior) 3. Adds an option for starting the surface using `RN$SurfaceRegistry` instead of `AppRegistry`, if that global property has been defined in JS. This is used for Venice (bridgeless RN) Reviewed By: shergin Differential Revision: D15366200 fbshipit-source-id: 4a506a589108905d4852b9723aac6fb0fad2d86e --- .../react/fabric/FabricUIManager.java | 9 +++++-- .../facebook/react/fabric/jsi/Binding.java | 2 +- .../facebook/react/fabric/jsi/jni/Binding.cpp | 8 ++++-- .../facebook/react/fabric/jsi/jni/Binding.h | 5 +++- ReactCommon/fabric/uimanager/Scheduler.cpp | 4 --- .../fabric/uimanager/UIManagerBinding.cpp | 25 +++++++++++++------ 6 files changed, 36 insertions(+), 17 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java index 9b9c6f78107b38..3c2070910a0dce 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -128,13 +128,18 @@ public FabricUIManager( @Override public int addRootView( - final T rootView, final WritableMap initialProps, final @Nullable String initialUITemplate) { + final T rootView, final WritableMap initialProps, final @Nullable String initialUITemplate) { + return addRootView(rootView, null, initialProps, initialUITemplate); + } + + public int addRootView( + final T rootView, final @Nullable String moduleName, final WritableMap initialProps, final @Nullable String initialUITemplate) { final int rootTag = ReactRootViewTagGenerator.getNextRootViewTag(); ThemedReactContext reactContext = new ThemedReactContext(mReactApplicationContext, rootView.getContext()); mMountingManager.addRootView(rootTag, rootView); mReactContextForRootTag.put(rootTag, reactContext); - mBinding.startSurface(rootTag, (NativeMap) initialProps); + mBinding.startSurface(rootTag, moduleName == null ? "" : moduleName, (NativeMap) initialProps); if (initialUITemplate != null) { mBinding.renderTemplateToSurface(rootTag, initialUITemplate); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/Binding.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/Binding.java index 441e98091109ab..664cd6d94dac16 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/Binding.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/Binding.java @@ -40,7 +40,7 @@ private native void installFabricUIManager( ComponentFactoryDelegate componentsRegistry, Object reactNativeConfig); - public native void startSurface(int surfaceId, NativeMap initialProps); + public native void startSurface(int surfaceId, String moduleName, NativeMap initialProps); public native void renderTemplateToSurface(int surfaceId, String uiTemplate); diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.cpp index 286392d5590b83..171935a1aca939 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.cpp @@ -45,9 +45,13 @@ jni::local_ref Binding::initHybrid( return makeCxxInstance(); } -void Binding::startSurface(jint surfaceId, NativeMap *initialProps) { +void Binding::startSurface( + jint surfaceId, + jni::alias_ref moduleName, + NativeMap *initialProps) { if (scheduler_) { - scheduler_->startSurface(surfaceId, "", initialProps->consume()); + scheduler_->startSurface( + surfaceId, moduleName->toStdString(), initialProps->consume()); } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.h b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.h index 6486763e7eeca0..6981de4937a48d 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.h +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.h @@ -50,7 +50,10 @@ class Binding : public jni::HybridClass, public SchedulerDelegate { ComponentFactoryDelegate *componentsRegistry, jni::alias_ref reactNativeConfig); - void startSurface(jint surfaceId, NativeMap *initialProps); + void startSurface( + jint surfaceId, + jni::alias_ref moduleName, + NativeMap *initialProps); void renderTemplateToSurface(jint surfaceId, jstring uiTemplate); diff --git a/ReactCommon/fabric/uimanager/Scheduler.cpp b/ReactCommon/fabric/uimanager/Scheduler.cpp index c4637c1a3d5bed..aab1121d9341e8 100644 --- a/ReactCommon/fabric/uimanager/Scheduler.cpp +++ b/ReactCommon/fabric/uimanager/Scheduler.cpp @@ -96,12 +96,10 @@ void Scheduler::startSurface( shadowTreeRegistry_.add(std::move(shadowTree)); -#ifndef ANDROID runtimeExecutor_([=](jsi::Runtime &runtime) { uiManagerBinding_->startSurface( runtime, surfaceId, moduleName, initialProps); }); -#endif } void Scheduler::renderTemplateToSurface( @@ -171,11 +169,9 @@ void Scheduler::stopSurface(SurfaceId surfaceId) const { auto shadowTree = shadowTreeRegistry_.remove(surfaceId); shadowTree->setDelegate(nullptr); -#ifndef ANDROID runtimeExecutor_([=](jsi::Runtime &runtime) { uiManagerBinding_->stopSurface(runtime, surfaceId); }); -#endif } Size Scheduler::measureSurface( diff --git a/ReactCommon/fabric/uimanager/UIManagerBinding.cpp b/ReactCommon/fabric/uimanager/UIManagerBinding.cpp index afcb6aff7d45fb..ac72b2437bef0d 100644 --- a/ReactCommon/fabric/uimanager/UIManagerBinding.cpp +++ b/ReactCommon/fabric/uimanager/UIManagerBinding.cpp @@ -46,14 +46,25 @@ void UIManagerBinding::startSurface( parameters["initialProps"] = initalProps; parameters["fabric"] = true; - auto module = getModule(runtime, "AppRegistry"); - auto method = module.getPropertyAsFunction(runtime, "runApplication"); + if (runtime.global().hasProperty(runtime, "RN$SurfaceRegistry")) { + auto registry = + runtime.global().getPropertyAsObject(runtime, "RN$SurfaceRegistry"); + auto method = registry.getPropertyAsFunction(runtime, "renderSurface"); - method.callWithThis( - runtime, - module, - {jsi::String::createFromUtf8(runtime, moduleName), - jsi::valueFromDynamic(runtime, parameters)}); + method.call( + runtime, + {jsi::String::createFromUtf8(runtime, moduleName), + jsi::valueFromDynamic(runtime, parameters)}); + } else { + auto module = getModule(runtime, "AppRegistry"); + auto method = module.getPropertyAsFunction(runtime, "runApplication"); + + method.callWithThis( + runtime, + module, + {jsi::String::createFromUtf8(runtime, moduleName), + jsi::valueFromDynamic(runtime, parameters)}); + } } void UIManagerBinding::stopSurface(jsi::Runtime &runtime, SurfaceId surfaceId) From 01abcf0e83fe58757661dcf6cfc0c2843fed570d Mon Sep 17 00:00:00 2001 From: David Vacca Date: Thu, 23 May 2019 18:26:51 -0700 Subject: [PATCH 0063/1084] Fix update of accessibilityStates in Android Summary: This diff fixes a bug on the update of accessibiltyState prop in RN Android. In particular, this bug was reproducible when a view has an accessibiltyState = ['disabled'] and there was a state update to set the {accessibiltyState = {null}}. In this scenario, the BaseViewManager.setViewStates method did not update the view with the default values for accessibilityState Reviewed By: sahrens Differential Revision: D15446078 fbshipit-source-id: 75f160916e55f0ee469516db2fe9b0a7d4758cd8 --- .../react/uimanager/BaseViewManager.java | 75 ++++++++++--------- 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java index 94bfdbf91fc47b..524a4bf60c084e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java @@ -33,8 +33,8 @@ import javax.annotation.Nullable; /** - * Base class that should be suitable for the majority of subclasses of {@link ViewManager}. - * It provides support for base view properties such as backgroundColor, opacity, etc. + * Base class that should be suitable for the majority of subclasses of {@link ViewManager}. It + * provides support for base view properties such as backgroundColor, opacity, etc. */ public abstract class BaseViewManager extends ViewManager { @@ -61,12 +61,11 @@ public abstract class BaseViewManager sStateDescription = new HashMap(); + static { - sStateDescription.put("busy", R.string.state_busy_description); - sStateDescription.put("expanded", R.string.state_expanded_description); - sStateDescription.put("collapsed", R.string.state_collapsed_description); + sStateDescription.put("busy", R.string.state_busy_description); + sStateDescription.put("expanded", R.string.state_expanded_description); + sStateDescription.put("collapsed", R.string.state_collapsed_description); } // State definition constants -- must match the definition in @@ -164,22 +164,22 @@ public void setAccessibilityRole(@Nonnull T view, @Nullable String accessibility @ReactProp(name = PROP_ACCESSIBILITY_STATES) public void setViewStates(@Nonnull T view, @Nullable ReadableArray accessibilityStates) { - if (accessibilityStates == null) { - return; - } + boolean shouldUpdateContentDescription = + view.getTag(R.id.accessibility_states) != null && accessibilityStates == null; view.setTag(R.id.accessibility_states, accessibilityStates); view.setSelected(false); view.setEnabled(true); - boolean shouldUpdateContentDescription = false; - for (int i = 0; i < accessibilityStates.size(); i++) { - String state = accessibilityStates.getString(i); - if (sStateDescription.containsKey(state)) { - shouldUpdateContentDescription = true; - } - if (state.equals("selected")) { - view.setSelected(true); - } else if (state.equals("disabled")) { - view.setEnabled(false); + if (accessibilityStates != null) { + for (int i = 0; i < accessibilityStates.size(); i++) { + String state = accessibilityStates.getString(i); + if (sStateDescription.containsKey(state)) { + shouldUpdateContentDescription = true; + } + if (state.equals("selected")) { + view.setSelected(true); + } else if (state.equals("disabled")) { + view.setEnabled(false); + } } } if (shouldUpdateContentDescription) { @@ -260,7 +260,8 @@ public void setAccessibilityActions(T view, ReadableArray accessibilityActions) } @ReactProp(name = PROP_IMPORTANT_FOR_ACCESSIBILITY) - public void setImportantForAccessibility(@Nonnull T view, @Nullable String importantForAccessibility) { + public void setImportantForAccessibility( + @Nonnull T view, @Nullable String importantForAccessibility) { if (importantForAccessibility == null || importantForAccessibility.equals("auto")) { ViewCompat.setImportantForAccessibility(view, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO); } else if (importantForAccessibility.equals("yes")) { @@ -268,7 +269,8 @@ public void setImportantForAccessibility(@Nonnull T view, @Nullable String impor } else if (importantForAccessibility.equals("no")) { ViewCompat.setImportantForAccessibility(view, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO); } else if (importantForAccessibility.equals("no-hide-descendants")) { - ViewCompat.setImportantForAccessibility(view, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); + ViewCompat.setImportantForAccessibility( + view, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); } } @@ -304,13 +306,13 @@ public void setTranslateY(@Nonnull T view, float translateY) { @ReactProp(name = PROP_ACCESSIBILITY_LIVE_REGION) public void setAccessibilityLiveRegion(@Nonnull T view, @Nullable String liveRegion) { - if (liveRegion == null || liveRegion.equals("none")) { - ViewCompat.setAccessibilityLiveRegion(view, ViewCompat.ACCESSIBILITY_LIVE_REGION_NONE); - } else if (liveRegion.equals("polite")) { - ViewCompat.setAccessibilityLiveRegion(view, ViewCompat.ACCESSIBILITY_LIVE_REGION_POLITE); - } else if (liveRegion.equals("assertive")) { - ViewCompat.setAccessibilityLiveRegion(view, ViewCompat.ACCESSIBILITY_LIVE_REGION_ASSERTIVE); - } + if (liveRegion == null || liveRegion.equals("none")) { + ViewCompat.setAccessibilityLiveRegion(view, ViewCompat.ACCESSIBILITY_LIVE_REGION_NONE); + } else if (liveRegion.equals("polite")) { + ViewCompat.setAccessibilityLiveRegion(view, ViewCompat.ACCESSIBILITY_LIVE_REGION_POLITE); + } else if (liveRegion.equals("assertive")) { + ViewCompat.setAccessibilityLiveRegion(view, ViewCompat.ACCESSIBILITY_LIVE_REGION_ASSERTIVE); + } } private static void setTransformProperty(@Nonnull View view, ReadableArray transforms) { @@ -329,7 +331,8 @@ private static void setTransformProperty(@Nonnull View view, ReadableArray trans double[] perspectiveArray = sMatrixDecompositionContext.perspective; if (perspectiveArray.length > PERSPECTIVE_ARRAY_INVERTED_CAMERA_DISTANCE_INDEX) { - float invertedCameraDistance = (float) perspectiveArray[PERSPECTIVE_ARRAY_INVERTED_CAMERA_DISTANCE_INDEX]; + float invertedCameraDistance = + (float) perspectiveArray[PERSPECTIVE_ARRAY_INVERTED_CAMERA_DISTANCE_INDEX]; if (invertedCameraDistance == 0) { // Default camera distance, before scale multiplier (1280) invertedCameraDistance = 0.00078125f; @@ -343,9 +346,9 @@ private static void setTransformProperty(@Nonnull View view, ReadableArray trans // calculation, so squaring and a normalization value of // sqrt(5) produces an exact replica with iOS. // For more information, see https://github.com/facebook/react-native/pull/18302 - float normalizedCameraDistance = scale * scale * cameraDistance * CAMERA_DISTANCE_NORMALIZATION_MULTIPLIER; + float normalizedCameraDistance = + scale * scale * cameraDistance * CAMERA_DISTANCE_NORMALIZATION_MULTIPLIER; view.setCameraDistance(normalizedCameraDistance); - } } @@ -373,7 +376,7 @@ protected void onAfterUpdateTransaction(@Nonnull T view) { @Override public @Nullable Map getExportedCustomDirectEventTypeConstants() { return MapBuilder.builder() - .put("performAction", MapBuilder.of("registrationName", "onAccessibilityAction")) - .build(); + .put("performAction", MapBuilder.of("registrationName", "onAccessibilityAction")) + .build(); } } From fb6cf2552a0ab19d4e96d7d3a586de36c792c1a4 Mon Sep 17 00:00:00 2001 From: Oleksandr Melnykov Date: Fri, 24 May 2019 02:50:40 -0700 Subject: [PATCH 0064/1084] Fix backgroundColor top level prop of TextInput Summary: Changelog: [Android] [FIXED] - Fix backgroundColor top level prop of TextInput This diff fixes two issues with the `backgroundColor` top level property of TextInput on Android: * Now it is possible to set a **string** value for the top-level `backgroundColor` property of TextInput (crashed the app previously): ``` Hello, React Native ``` * Now it's possible to set an **integer** value for the top-level `backgroundColor` property of TextInput (had no effect previously): ``` Hello, React Native ``` A `customType = "Color"` annotation parameter must be provided for `ReactBaseTextShadowNode.setBackgroundColor(...)` since the color value must be previously processed in JS before sending it over the bridge to the native code. The JS code will parse the color value and return the proper ARGB color integer to the native platforms (https://fburl.com/uqup52tn). Without providing the custom type for the background color, if a string value is set for the top-level `backgroundColor` property in the JS code, the Android code will crash since it expects an integer value for the color in `ReactBaseTextShadowNode.setBackgroundColor(...)`, but a string will be passed from JS without any conversion and there will be a `ClassCastException` thrown. If an integer value without the alpha component (like `0xffccbb`) is set, the Android native view would get an integer color value with its alpha component set to `0x00`, which means a transparent color. On a side note: the alpha component of a color must always be set when using an integer value for `backgroundColor` since the JS code, while processing the color type, shifts the rightmost 8 bytes (alpha component) to the leftmost position. If those 8 bytes are not the alpha component, you will get the wrong color in the end. It doesn't seem to be a problem for string values of `backgroundColor` though. Reviewed By: mdvacca Differential Revision: D15453980 fbshipit-source-id: f3f5d9c9877cdbce79a67f2ed93ad4589576d166 --- .../facebook/react/views/text/ReactBaseTextShadowNode.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java index 3649a944908af6..7bfc0ae496ca63 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java @@ -459,8 +459,8 @@ public void setColor(@Nullable Integer color) { markUpdated(); } - @ReactProp(name = ViewProps.BACKGROUND_COLOR) - public void setBackgroundColor(Integer color) { + @ReactProp(name = ViewProps.BACKGROUND_COLOR, customType = "Color") + public void setBackgroundColor(@Nullable Integer color) { // Background color needs to be handled here for virtual nodes so it can be incorporated into // the span. However, it doesn't need to be applied to non-virtual nodes because non-virtual // nodes get mapped to native views and native views get their background colors get set via From 057ea6a5c7f1ad5de24a7a465ba36d5f33c1c393 Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Fri, 24 May 2019 09:15:10 -0700 Subject: [PATCH 0065/1084] Add flow parser Summary: This diff initializes the codegen flow parser using a proposal for some new syntaxes in flow file to handle missing information like: - Float vs Int32 - Bubbling Events vs Direct Events - Default props - Codegen options - Specifying the component name For a deep dive on the proposal see: https://fb.quip.com/kPYJAjCHxlgO Note: there are still some todos to follow up with: - Array props - Enum props - Object event arguments Note also: the parser code is a little rough, I didn't want spend too much time cleaning it up before we agreed on the format [General][Added] Add codegen flow parser Reviewed By: cpojer Differential Revision: D15417733 fbshipit-source-id: dd80887c0b2ac46fdc3da203214775facd204e28 --- .../Slider/RCTSliderNativeComponent.js | 53 +- Libraries/StyleSheet/StyleSheetTypes.js | 4 + Libraries/Types/CodegenTypes.js | 38 + .../react-native-codegen/src/CodegenSchema.js | 40 +- .../src/cli/parser/parser-cli.js | 18 + .../src/cli/parser/parser.js | 21 + .../src/cli/parser/parser.sh | 11 + .../flow/__test_fixtures__/fixtures.js | 559 +++ .../__snapshots__/parser-test.js.snap | 3826 +++++++++++++++++ .../src/parsers/flow/__tests__/parser-test.js | 28 + .../src/parsers/flow/events.js | 167 + .../src/parsers/flow/extends.js | 42 + .../src/parsers/flow/index.js | 86 +- .../src/parsers/flow/options.js | 36 + .../src/parsers/flow/props.js | 222 + .../src/parsers/flow/schema.js | 56 + 16 files changed, 5180 insertions(+), 27 deletions(-) create mode 100644 Libraries/Types/CodegenTypes.js create mode 100644 packages/react-native-codegen/src/cli/parser/parser-cli.js create mode 100644 packages/react-native-codegen/src/cli/parser/parser.js create mode 100755 packages/react-native-codegen/src/cli/parser/parser.sh create mode 100644 packages/react-native-codegen/src/parsers/flow/__test_fixtures__/fixtures.js create mode 100644 packages/react-native-codegen/src/parsers/flow/__tests__/__snapshots__/parser-test.js.snap create mode 100644 packages/react-native-codegen/src/parsers/flow/__tests__/parser-test.js create mode 100644 packages/react-native-codegen/src/parsers/flow/events.js create mode 100644 packages/react-native-codegen/src/parsers/flow/extends.js create mode 100644 packages/react-native-codegen/src/parsers/flow/options.js create mode 100644 packages/react-native-codegen/src/parsers/flow/props.js create mode 100644 packages/react-native-codegen/src/parsers/flow/schema.js diff --git a/Libraries/Components/Slider/RCTSliderNativeComponent.js b/Libraries/Components/Slider/RCTSliderNativeComponent.js index 71e20a3f8eaaee..f644fa41556326 100644 --- a/Libraries/Components/Slider/RCTSliderNativeComponent.js +++ b/Libraries/Components/Slider/RCTSliderNativeComponent.js @@ -12,40 +12,53 @@ const requireNativeComponent = require('../../ReactNative/requireNativeComponent'); +import type { + Float, + BubblingEvent, + DirectEvent, + WithDefault, + CodegenNativeComponent, +} from '../../Types/CodegenTypes'; + import type {ColorValue} from '../../StyleSheet/StyleSheetTypes'; import type {ImageSource} from '../../Image/ImageSource'; -import type {NativeComponent} from '../../Renderer/shims/ReactNative'; -import type {SyntheticEvent} from '../../Types/CoreEventTypes'; import type {ViewProps} from '../View/ViewPropTypes'; -type Event = SyntheticEvent< - $ReadOnly<{| - value: number, - fromUser?: boolean, - |}>, ->; +type Event = $ReadOnly<{| + value: Float, + fromUser?: boolean, +|}>; type NativeProps = $ReadOnly<{| ...ViewProps, - disabled?: ?boolean, - enabled?: ?boolean, + + // Props + disabled?: ?WithDefault, + enabled?: ?WithDefault, maximumTrackImage?: ?ImageSource, maximumTrackTintColor?: ?ColorValue, - maximumValue?: ?number, + maximumValue?: ?WithDefault, minimumTrackImage?: ?ImageSource, minimumTrackTintColor?: ?ColorValue, - minimumValue?: ?number, - onChange?: ?(event: Event) => void, - onSlidingComplete?: ?(event: Event) => void, - onValueChange?: ?(event: Event) => void, - step?: ?number, - testID?: ?string, + minimumValue?: ?WithDefault, + step?: ?WithDefault, + testID?: ?WithDefault, thumbImage?: ?ImageSource, thumbTintColor?: ?ColorValue, trackImage?: ?ImageSource, - value?: ?number, + value: ?WithDefault, + + // Events + onChange?: ?(event: BubblingEvent) => void, + onValueChange?: ?(event: BubblingEvent) => void, + onSlidingComplete?: ?(event: DirectEvent) => void, |}>; -type RCTSliderType = Class>; +type Options = { + interfaceOnly: true, + isDeprecatedPaperComponentNameRCT: true, +}; + +type SliderType = CodegenNativeComponent<'Slider', NativeProps, Options>; -module.exports = ((requireNativeComponent('RCTSlider'): any): RCTSliderType); +module.exports = ((requireNativeComponent('RCTSlider'): any): SliderType); diff --git a/Libraries/StyleSheet/StyleSheetTypes.js b/Libraries/StyleSheet/StyleSheetTypes.js index f307de6f06fb78..39819d5e6b4eb7 100644 --- a/Libraries/StyleSheet/StyleSheetTypes.js +++ b/Libraries/StyleSheet/StyleSheetTypes.js @@ -13,6 +13,10 @@ const AnimatedNode = require('../Animated/src/nodes/AnimatedNode'); export type ColorValue = null | string; +export type PointValue = {| + x: number, + y: number, +|}; export type DimensionValue = null | number | string | AnimatedNode; /** diff --git a/Libraries/Types/CodegenTypes.js b/Libraries/Types/CodegenTypes.js new file mode 100644 index 00000000000000..4ee7fadd651019 --- /dev/null +++ b/Libraries/Types/CodegenTypes.js @@ -0,0 +1,38 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow + */ + +'use strict'; + +import type {NativeComponent} from '../Renderer/shims/ReactNative'; +import type {SyntheticEvent} from './CoreEventTypes'; + +// Event types +export type BubblingEvent = SyntheticEvent; +export type DirectEvent = SyntheticEvent; + +// Prop types +export type Float = number; +export type Int32 = number; + +// Default handling, ignore the unused value +// we're only using it for type checking +// +// TODO: (rickhanlonii) T44881457 If a default is provided, it should always be optional +// but that is currently not supported in the codegen since we require a default +// eslint-disable-next-line no-unused-vars +export type WithDefault = Type; + +// We're not using ComponentName or Options in JS +// We only use these types to codegen native code +// +// eslint-disable-next-line no-unused-vars +export type CodegenNativeComponent = Class< + NativeComponent, +>; diff --git a/packages/react-native-codegen/src/CodegenSchema.js b/packages/react-native-codegen/src/CodegenSchema.js index 8d3aec5dc6bfc6..3ee4879818c808 100644 --- a/packages/react-native-codegen/src/CodegenSchema.js +++ b/packages/react-native-codegen/src/CodegenSchema.js @@ -68,7 +68,29 @@ type PropTypeTypeAnnotation = |}> | $ReadOnly<{| type: 'ArrayTypeAnnotation', - elementType: $ReadOnly, + elementType: + | $ReadOnly<{| + type: 'BooleanTypeAnnotation', + |}> + | $ReadOnly<{| + type: 'StringTypeAnnotation', + |}> + | $ReadOnly<{| + type: 'FloatTypeAnnotation', + |}> + | $ReadOnly<{| + type: 'Int32TypeAnnotation', + |}> + | $ReadOnly<{| + type: 'StringEnumTypeAnnotation', + options: $ReadOnlyArray<{| + name: string, + |}>, + |}> + | $ReadOnly<{| + type: 'NativePrimitiveTypeAnnotation', + name: 'ColorPrimitive' | 'ImageSourcePrimitive' | 'PointPrimitive', + |}>, |}>; export type PropTypeShape = $ReadOnly<{| @@ -90,13 +112,19 @@ export type EventTypeShape = $ReadOnly<{| |}>, |}>; -export type ComponentShape = $ReadOnly<{| +export type OptionsShape = $ReadOnly<{| interfaceOnly?: boolean, isDeprecatedPaperComponentNameRCT?: boolean, - extendsProps: $ReadOnlyArray<{| - type: 'ReactNativeBuiltInType', - knownTypeName: 'ReactNativeCoreViewProps', - |}>, +|}>; + +export type ExtendsPropsShape = $ReadOnly<{| + type: 'ReactNativeBuiltInType', + knownTypeName: 'ReactNativeCoreViewProps', +|}>; + +export type ComponentShape = $ReadOnly<{| + ...OptionsShape, + extendsProps: $ReadOnlyArray, events: $ReadOnlyArray, props: $ReadOnlyArray, |}>; diff --git a/packages/react-native-codegen/src/cli/parser/parser-cli.js b/packages/react-native-codegen/src/cli/parser/parser-cli.js new file mode 100644 index 00000000000000..2be7c4a03f6561 --- /dev/null +++ b/packages/react-native-codegen/src/cli/parser/parser-cli.js @@ -0,0 +1,18 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @emails oncall+react_native + * @flow + * @format + */ + +'use strict'; + +const parseFiles = require('./parser.js'); + +const [...fileList] = process.argv.slice(2); + +parseFiles(fileList); diff --git a/packages/react-native-codegen/src/cli/parser/parser.js b/packages/react-native-codegen/src/cli/parser/parser.js new file mode 100644 index 00000000000000..c1ec866f8a8ba1 --- /dev/null +++ b/packages/react-native-codegen/src/cli/parser/parser.js @@ -0,0 +1,21 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +const FlowParser = require('../../parsers/flow'); + +function parseFiles(files: Array) { + files.forEach(filename => { + console.log(filename, JSON.stringify(FlowParser.parse(filename), null, 2)); + }); +} + +module.exports = parseFiles; diff --git a/packages/react-native-codegen/src/cli/parser/parser.sh b/packages/react-native-codegen/src/cli/parser/parser.sh new file mode 100755 index 00000000000000..87155debab41c4 --- /dev/null +++ b/packages/react-native-codegen/src/cli/parser/parser.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +set -e +set -u + +THIS_DIR=$(cd -P "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo "${BASH_SOURCE[0]}")")" && pwd) + +# shellcheck source=xplat/js/env-utils/setup_env_vars.sh +source "$THIS_DIR/../../../../../../env-utils/setup_env_vars.sh" + +exec "$FLOW_NODE_BINARY" "$THIS_DIR/parser.js" "$@" diff --git a/packages/react-native-codegen/src/parsers/flow/__test_fixtures__/fixtures.js b/packages/react-native-codegen/src/parsers/flow/__test_fixtures__/fixtures.js new file mode 100644 index 00000000000000..5fbef12ed35c10 --- /dev/null +++ b/packages/react-native-codegen/src/parsers/flow/__test_fixtures__/fixtures.js @@ -0,0 +1,559 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; +const EVENT_DEFINITION = ` + boolean_required: boolean, + boolean_optional_key?: boolean, + boolean_optional_value: ?boolean, + boolean_optional_both?: ?boolean, + + string_required: string, + string_optional_key?: string, + string_optional_value: ?string, + string_optional_both?: ?string, + + float_required: Float, + float_optional_key?: Float, + float_optional_value: ?Float, + float_optional_both?: ?Float, + + int32_required: Int32, + int32_optional_key?: Int32, + int32_optional_value: ?Int32, + int32_optional_both?: ?Int32, + + object_required: { + boolean_required: boolean, + } + + object_optional_key?: { + string_optional_key?: string, + } + + object_optional_value: ?{ + float_optional_value: ?Float, + } + + object_optional_both?: ?{ + int32_optional_both?: ?Int32, + } + + object_required_nested_2_layers: { + object_optional_nested_1_layer?: ?{ + boolean_required: Int32, + string_optional_key?: string, + float_optional_value: ?Float, + int32_optional_both?: ?Int32, + } + } +`; +const ONE_OF_EACH_PROP_EVENT_DEFAULT_AND_OPTIONS = ` +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow + */ + +'use strict'; + +const requireNativeComponent = require('requireNativeComponent'); + +import type { + BubblingEvent, + DirectEvent, + WithDefault, + CodegenNativeComponent, +} from 'CodegenFlowtypes'; + +import type {ViewProps} from 'ViewPropTypes'; + +type ModuleProps = $ReadOnly<{| + ...ViewProps, + + // Props + boolean_default_true_optional_both?: ?WithDefault, + + // Events + onDirectEventDefinedInlineNull: (event: DirectEvent) => void, + onBubblingEventDefinedInlineNull: (event: BubblingEvent) => void, +|}>; + +type Options = { + interfaceOnly: true, + isDeprecatedPaperComponentNameRCT: true, +}; + +type ModuleType = CodegenNativeComponent<'Module', ModuleProps, Options>; + +module.exports = ((requireNativeComponent('RCTModule'): any): ModuleType); +`; + +const ALL_PROP_TYPES_NO_EVENTS = ` +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow + */ + +'use strict'; + +const requireNativeComponent = require('requireNativeComponent'); + +import type { + Int32, + Float, + WithDefault, + CodegenNativeComponent, +} from 'CodegenFlowtypes'; + +import type {ColorValue, PointValue} from 'StyleSheetTypes'; +import type {ImageSource} from 'ImageSource'; +import type {ViewProps} from 'ViewPropTypes'; + +type ModuleProps = $ReadOnly<{| + ...ViewProps, + + // Props + // Boolean props + boolean_required: WithDefault, + boolean_optional_key?: WithDefault, + boolean_optional_value: ?WithDefault, + boolean_optional_both?: ?WithDefault, + + // String props + string_required: WithDefault, + string_optional_key?: WithDefault, + string_optional_value: ?WithDefault, + string_optional_both?: ?WithDefault, + + // Float props + float_required: WithDefault, + float_optional_key?: WithDefault, + float_optional_value: ?WithDefault, + float_optional_both?: ?WithDefault, + + // Int32 props + int32_required: WithDefault, + int32_optional_key?: WithDefault, + int32_optional_value: ?WithDefault, + int32_optional_both?: ?WithDefault, + + // String enum props + enum_required: WithDefault<('small' | 'large'), 'small'>, + enum_optional_key?: WithDefault<('small' | 'large'), 'small'>, + enum_optional_value: ?WithDefault<('small' | 'large'), 'small'>, + enum_optional_both?: ?WithDefault<('small' | 'large'), 'small'>, + + // ImageSource props + image_required: ImageSource, + image_optional_value: ?ImageSource, + image_optional_both?: ?ImageSource, + + // ColorValue props + color_required: ColorValue, + color_optional_key?: ColorValue, + color_optional_value: ?ColorValue, + color_optional_both?: ?ColorValue, + + // PointValue props + point_required: PointValue, + point_optional_key?: PointValue, + point_optional_value: ?PointValue, + point_optional_both?: ?PointValue, +|}>; + +type ModuleType = CodegenNativeComponent<'Module', ModuleProps, Options>; + +module.exports = ((requireNativeComponent('RCTModule'): any): ModuleType); +`; + +const ARRAY_PROP_TYPES_NO_EVENTS = ` +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow + */ + +'use strict'; + +const requireNativeComponent = require('requireNativeComponent'); + +import type { + Int32, + Float, + WithDefault, + CodegenNativeComponent, +} from 'CodegenFlowtypes'; + +import type {ColorValue, PointValue} from 'StyleSheetTypes'; +import type {ImageSource} from 'ImageSource'; +import type {ViewProps} from 'ViewPropTypes'; + +type ModuleProps = $ReadOnly<{| + ...ViewProps, + + // Props + // Boolean props + array_boolean_required: $ReadOnlyArray, + array_boolean_optional_key?: $ReadOnlyArray, + array_boolean_optional_value: ?$ReadOnlyArray, + array_boolean_optional_both?: ?$ReadOnlyArray, + + // String props + array_string_required: $ReadOnlyArray, + array_string_optional_key?: $ReadOnlyArray, + array_string_optional_value: ?$ReadOnlyArray, + array_string_optional_both?: ?$ReadOnlyArray, + + // Float props + array_float_required: $ReadOnlyArray, + array_float_optional_key?: $ReadOnlyArray, + array_float_optional_value: ?$ReadOnlyArray, + array_float_optional_both?: ?$ReadOnlyArray, + + // Int32 props + array_int32_required: $ReadOnlyArray, + array_int32_optional_key?: $ReadOnlyArray, + array_int32_optional_value: ?$ReadOnlyArray, + array_int32_optional_both?: ?$ReadOnlyArray, + + // String enum props + array_enum_required: $ReadOnlyArray<('small' | 'large')>, + array_enum_optional_key?: $ReadOnlyArray<('small' | 'large')>, + array_enum_optional_value: ?$ReadOnlyArray<('small' | 'large')>, + array_enum_optional_both?: ?$ReadOnlyArray<('small' | 'large')>, + + // ImageSource props + array_image_required: $ReadOnlyArray, + array_image_optional_key?: $ReadOnlyArray, + array_image_optional_value: ?$ReadOnlyArray, + array_image_optional_both?: ?$ReadOnlyArray, + + // ColorValue props + array_color_required: $ReadOnlyArray, + array_color_optional_key?: $ReadOnlyArray, + array_color_optional_value: ?$ReadOnlyArray, + array_color_optional_both?: ?$ReadOnlyArray, + + // PointValue props + array_point_required: $ReadOnlyArray, + array_point_optional_key?: $ReadOnlyArray, + array_point_optional_value: ?$ReadOnlyArray, + array_point_optional_both?: ?$ReadOnlyArray, +|}>; + +type ModuleType = CodegenNativeComponent<'Module', ModuleProps, Options>; + +module.exports = ((requireNativeComponent('RCTModule'): any): ModuleType); +`; + +const EVENTS_DEFINED_INLINE_WITH_ALL_TYPES = ` +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow + */ + +'use strict'; + +const requireNativeComponent = require('requireNativeComponent'); + +import type { + Int32, + Float, + BubblingEvent, + DirectEvent, + CodegenNativeComponent, +} from 'CodegenFlowtypes'; + +import type {ViewProps} from 'ViewPropTypes'; + +type ModuleProps = $ReadOnly<{| + ...ViewProps, + // No Props + + // Events + onDirectEventDefinedInline: ( + event: DirectEvent< + $ReadOnly<{| + ${EVENT_DEFINITION} + |}>, + >, + ) => void, + + onDirectEventDefinedInlineOptionalKey?: ( + event: DirectEvent< + $ReadOnly<{| + ${EVENT_DEFINITION} + |}>, + >, + ) => void, + + onDirectEventDefinedInlineOptionalValue: ?( + event: DirectEvent< + $ReadOnly<{| + ${EVENT_DEFINITION} + |}>, + >, + ) => void, + + onDirectEventDefinedInlineOptionalBoth?: ?( + event: DirectEvent< + $ReadOnly<{| + ${EVENT_DEFINITION} + |}>, + >, + ) => void, + + onBubblingEventDefinedInline: ( + event: BubblingEvent< + $ReadOnly<{| + ${EVENT_DEFINITION} + |}>, + >, + ) => void, + + onBubblingEventDefinedInlineOptionalKey?: ( + event: BubblingEvent< + $ReadOnly<{| + ${EVENT_DEFINITION} + |}>, + >, + ) => void, + + onBubblingEventDefinedInlineOptionalValue: ?( + event: BubblingEvent< + $ReadOnly<{| + ${EVENT_DEFINITION} + |}>, + >, + ) => void, + + onBubblingEventDefinedInlineOptionalBoth?: ?( + event: BubblingEvent< + $ReadOnly<{| + ${EVENT_DEFINITION} + |}>, + >, + ) => void, +|}>; + +type ModuleType = CodegenNativeComponent<'Module', ModuleProps>; + +module.exports = ((requireNativeComponent('RCTModule'): any): ModuleType); +`; + +const EVENTS_DEFINED_IN_FILE_WITH_ALL_TYPES = ` +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow + */ + +'use strict'; + +const requireNativeComponent = require('requireNativeComponent'); + +import type { + Float, + Int32, + BubblingEvent, + DirectEvent, + CodegenNativeComponent, +} from 'CodegenFlowtypes'; + +import type {ViewProps} from 'ViewPropTypes'; + +type EventInFile = $ReadOnly<{| + ${EVENT_DEFINITION} +|}>; + +type DirectEventInFile = DirectEvent; +type BubblingEventInFile = BubblingEvent; + +type ModuleProps = $ReadOnly<{| + ...ViewProps, + + // No props + + // Events + // Events defined elsewhere in file + + onDirectEventDefinedInFile: (event: DirectEventInFile) => void, + onDirectEventDefinedInFileOptionalKey?: (event: DirectEventInFile) => void, + onDirectEventDefinedInFileOptionalValue: ?(event: DirectEventInFile) => void, + onDirectEventDefinedInFileOptionalBoth?: ?(event: DirectEventInFile) => void, + + onBubblingEventDefinedInFile: (event: BubblingEventInFile) => void, + onBubblingEventDefinedInFileOptionalKey?: ( + event: BubblingEventInFile, + ) => void, + onBubblingEventDefinedInFileOptionalValue: ?( + event: BubblingEventInFile, + ) => void, + onBubblingEventDefinedInFileOptionalBoth?: ?( + event: BubblingEventInFile, + ) => void, +|}>; + +type ModuleType = CodegenNativeComponent<'Module', ModuleProps>; + +module.exports = ((requireNativeComponent('RCTModule'): any): ModuleType); +`; + +const EVENTS_DEFINED_AS_NULL_IN_FILE = ` +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow + */ + +'use strict'; + +const requireNativeComponent = require('requireNativeComponent'); + +import type { + BubblingEvent, + DirectEvent, + CodegenNativeComponent, +} from 'CodegenFlowtypes'; + +import type {ViewProps} from 'ViewPropTypes'; + +type DirectEventDefinedInFileNull = DirectEvent; +type BubblingEventDefinedInFileNull = BubblingEvent; + +type ModuleProps = $ReadOnly<{| + ...ViewProps, + + // No props + + // Events defined elsewhere in file + onDirectEventDefinedInFileNull: (event: DirectEventDefinedInFileNull) => void, + onDirectEventDefinedInFileNullOptionalKey?: ( + event: DirectEventDefinedInFileNull, + ) => void, + onDirectEventDefinedInFileNullOptionalValue: ?( + event: DirectEventDefinedInFileNull, + ) => void, + onDirectEventDefinedInFileNullOptionalBoth?: ?( + event: DirectEventDefinedInFileNull, + ) => void, + + onBubblingEventDefinedInFileNull: ( + event: BubblingEventDefinedInFileNull, + ) => void, + onBubblingEventDefinedInFileNullOptionalKey?: ( + event: BubblingEventDefinedInFileNull, + ) => void, + onBubblingEventDefinedInFileNullOptionalValue: ?( + event: BubblingEventDefinedInFileNull, + ) => void, + onBubblingEventDefinedInFileNullOptionalBoth?: ?( + event: BubblingEventDefinedInFileNull, + ) => void, +|}>; + +type ModuleType = CodegenNativeComponent<'Module', ModuleProps>; + +module.exports = ((requireNativeComponent('RCTModule'): any): ModuleType); +`; + +const EVENTS_DEFINED_AS_NULL_INLINE = ` +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow + */ + +'use strict'; + +const requireNativeComponent = require('requireNativeComponent'); + +import type { + BubblingEvent, + DirectEvent, + CodegenNativeComponent, +} from 'CodegenFlowtypes'; + +import type {ViewProps} from 'ViewPropTypes'; + +type ModuleProps = $ReadOnly<{| + ...ViewProps, + + // No props + + // Events defined inline + onDirectEventDefinedInlineNull: (event: DirectEvent) => void, + onDirectEventDefinedInlineNullOptionalKey?: ( + event: DirectEvent, + ) => void, + onDirectEventDefinedInlineNullOptionalValue: ?( + event: DirectEvent, + ) => void, + onDirectEventDefinedInlineNullOptionalBoth?: ?( + event: DirectEvent, + ) => void, + + onBubblingEventDefinedInlineNull: (event: BubblingEvent) => void, + onBubblingEventDefinedInlineNullOptionalKey?: ( + event: BubblingEvent, + ) => void, + onBubblingEventDefinedInlineNullOptionalValue: ?( + event: BubblingEvent, + ) => void, + onBubblingEventDefinedInlineNullOptionalBoth?: ?( + event: BubblingEvent, + ) => void, +|}>; + +type ModuleType = CodegenNativeComponent<'Module', ModuleProps>; + +module.exports = ((requireNativeComponent('RCTModule'): any): ModuleType); +`; + +module.exports = { + ALL_PROP_TYPES_NO_EVENTS, + ARRAY_PROP_TYPES_NO_EVENTS, + ONE_OF_EACH_PROP_EVENT_DEFAULT_AND_OPTIONS, + EVENTS_DEFINED_INLINE_WITH_ALL_TYPES, + EVENTS_DEFINED_IN_FILE_WITH_ALL_TYPES, + EVENTS_DEFINED_AS_NULL_IN_FILE, + EVENTS_DEFINED_AS_NULL_INLINE, +}; diff --git a/packages/react-native-codegen/src/parsers/flow/__tests__/__snapshots__/parser-test.js.snap b/packages/react-native-codegen/src/parsers/flow/__tests__/__snapshots__/parser-test.js.snap new file mode 100644 index 00000000000000..527f9edd44c68a --- /dev/null +++ b/packages/react-native-codegen/src/parsers/flow/__tests__/__snapshots__/parser-test.js.snap @@ -0,0 +1,3826 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`RN Codegen Flow Parser can generate fixture ALL_PROP_TYPES_NO_EVENTS 1`] = ` +Object { + "modules": Object { + "Module": Object { + "components": Object { + "Module": Object { + "events": Array [], + "extendsProps": Array [ + Object { + "knownTypeName": "ReactNativeCoreViewProps", + "type": "ReactNativeBuiltInType", + }, + ], + "props": Array [ + Object { + "name": "boolean_required", + "optional": false, + "typeAnnotation": Object { + "default": true, + "type": "BooleanTypeAnnotation", + }, + }, + Object { + "name": "boolean_optional_key", + "optional": true, + "typeAnnotation": Object { + "default": true, + "type": "BooleanTypeAnnotation", + }, + }, + Object { + "name": "boolean_optional_value", + "optional": true, + "typeAnnotation": Object { + "default": true, + "type": "BooleanTypeAnnotation", + }, + }, + Object { + "name": "boolean_optional_both", + "optional": true, + "typeAnnotation": Object { + "default": true, + "type": "BooleanTypeAnnotation", + }, + }, + Object { + "name": "string_required", + "optional": false, + "typeAnnotation": Object { + "default": "", + "type": "StringTypeAnnotation", + }, + }, + Object { + "name": "string_optional_key", + "optional": true, + "typeAnnotation": Object { + "default": "", + "type": "StringTypeAnnotation", + }, + }, + Object { + "name": "string_optional_value", + "optional": true, + "typeAnnotation": Object { + "default": "", + "type": "StringTypeAnnotation", + }, + }, + Object { + "name": "string_optional_both", + "optional": true, + "typeAnnotation": Object { + "default": "", + "type": "StringTypeAnnotation", + }, + }, + Object { + "name": "float_required", + "optional": false, + "typeAnnotation": Object { + "default": 1.1, + "type": "FloatTypeAnnotation", + }, + }, + Object { + "name": "float_optional_key", + "optional": true, + "typeAnnotation": Object { + "default": 1.1, + "type": "FloatTypeAnnotation", + }, + }, + Object { + "name": "float_optional_value", + "optional": true, + "typeAnnotation": Object { + "default": 1.1, + "type": "FloatTypeAnnotation", + }, + }, + Object { + "name": "float_optional_both", + "optional": true, + "typeAnnotation": Object { + "default": 1.1, + "type": "FloatTypeAnnotation", + }, + }, + Object { + "name": "int32_required", + "optional": false, + "typeAnnotation": Object { + "default": 1, + "type": "Int32TypeAnnotation", + }, + }, + Object { + "name": "int32_optional_key", + "optional": true, + "typeAnnotation": Object { + "default": 1, + "type": "Int32TypeAnnotation", + }, + }, + Object { + "name": "int32_optional_value", + "optional": true, + "typeAnnotation": Object { + "default": 1, + "type": "Int32TypeAnnotation", + }, + }, + Object { + "name": "int32_optional_both", + "optional": true, + "typeAnnotation": Object { + "default": 1, + "type": "Int32TypeAnnotation", + }, + }, + Object { + "name": "enum_required", + "optional": false, + "typeAnnotation": Object { + "default": "small", + "options": Array [ + Object { + "name": "small", + }, + Object { + "name": "large", + }, + ], + "type": "StringEnumTypeAnnotation", + }, + }, + Object { + "name": "enum_optional_key", + "optional": true, + "typeAnnotation": Object { + "default": "small", + "options": Array [ + Object { + "name": "small", + }, + Object { + "name": "large", + }, + ], + "type": "StringEnumTypeAnnotation", + }, + }, + Object { + "name": "enum_optional_value", + "optional": true, + "typeAnnotation": Object { + "default": "small", + "options": Array [ + Object { + "name": "small", + }, + Object { + "name": "large", + }, + ], + "type": "StringEnumTypeAnnotation", + }, + }, + Object { + "name": "enum_optional_both", + "optional": true, + "typeAnnotation": Object { + "default": "small", + "options": Array [ + Object { + "name": "small", + }, + Object { + "name": "large", + }, + ], + "type": "StringEnumTypeAnnotation", + }, + }, + Object { + "name": "image_required", + "optional": false, + "typeAnnotation": Object { + "name": "ImageSourcePrimitive", + "type": "NativePrimitiveTypeAnnotation", + }, + }, + Object { + "name": "image_optional_value", + "optional": true, + "typeAnnotation": Object { + "name": "ImageSourcePrimitive", + "type": "NativePrimitiveTypeAnnotation", + }, + }, + Object { + "name": "image_optional_both", + "optional": true, + "typeAnnotation": Object { + "name": "ImageSourcePrimitive", + "type": "NativePrimitiveTypeAnnotation", + }, + }, + Object { + "name": "color_required", + "optional": false, + "typeAnnotation": Object { + "name": "ColorPrimitive", + "type": "NativePrimitiveTypeAnnotation", + }, + }, + Object { + "name": "color_optional_key", + "optional": true, + "typeAnnotation": Object { + "name": "ColorPrimitive", + "type": "NativePrimitiveTypeAnnotation", + }, + }, + Object { + "name": "color_optional_value", + "optional": true, + "typeAnnotation": Object { + "name": "ColorPrimitive", + "type": "NativePrimitiveTypeAnnotation", + }, + }, + Object { + "name": "color_optional_both", + "optional": true, + "typeAnnotation": Object { + "name": "ColorPrimitive", + "type": "NativePrimitiveTypeAnnotation", + }, + }, + Object { + "name": "point_required", + "optional": false, + "typeAnnotation": Object { + "name": "PointPrimitive", + "type": "NativePrimitiveTypeAnnotation", + }, + }, + Object { + "name": "point_optional_key", + "optional": true, + "typeAnnotation": Object { + "name": "PointPrimitive", + "type": "NativePrimitiveTypeAnnotation", + }, + }, + Object { + "name": "point_optional_value", + "optional": true, + "typeAnnotation": Object { + "name": "PointPrimitive", + "type": "NativePrimitiveTypeAnnotation", + }, + }, + Object { + "name": "point_optional_both", + "optional": true, + "typeAnnotation": Object { + "name": "PointPrimitive", + "type": "NativePrimitiveTypeAnnotation", + }, + }, + ], + }, + }, + }, + }, +} +`; + +exports[`RN Codegen Flow Parser can generate fixture ARRAY_PROP_TYPES_NO_EVENTS 1`] = ` +Object { + "modules": Object { + "Module": Object { + "components": Object { + "Module": Object { + "events": Array [], + "extendsProps": Array [ + Object { + "knownTypeName": "ReactNativeCoreViewProps", + "type": "ReactNativeBuiltInType", + }, + ], + "props": Array [ + Object { + "name": "array_boolean_required", + "optional": false, + "typeAnnotation": Object { + "elementType": Object { + "type": "BooleanTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "array_boolean_optional_key", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "type": "BooleanTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "array_boolean_optional_value", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "type": "BooleanTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "array_boolean_optional_both", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "type": "BooleanTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "array_string_required", + "optional": false, + "typeAnnotation": Object { + "elementType": Object { + "type": "StringTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "array_string_optional_key", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "type": "StringTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "array_string_optional_value", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "type": "StringTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "array_string_optional_both", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "type": "StringTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "array_float_required", + "optional": false, + "typeAnnotation": Object { + "elementType": Object { + "type": "FloatTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "array_float_optional_key", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "type": "FloatTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "array_float_optional_value", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "type": "FloatTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "array_float_optional_both", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "type": "FloatTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "array_int32_required", + "optional": false, + "typeAnnotation": Object { + "elementType": Object { + "type": "Int32TypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "array_int32_optional_key", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "type": "Int32TypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "array_int32_optional_value", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "type": "Int32TypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "array_int32_optional_both", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "type": "Int32TypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "array_enum_required", + "optional": false, + "typeAnnotation": Object { + "elementType": Object { + "options": Array [ + Object { + "name": "small", + }, + Object { + "name": "large", + }, + ], + "type": "StringEnumTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "array_enum_optional_key", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "options": Array [ + Object { + "name": "small", + }, + Object { + "name": "large", + }, + ], + "type": "StringEnumTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "array_enum_optional_value", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "options": Array [ + Object { + "name": "small", + }, + Object { + "name": "large", + }, + ], + "type": "StringEnumTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "array_enum_optional_both", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "options": Array [ + Object { + "name": "small", + }, + Object { + "name": "large", + }, + ], + "type": "StringEnumTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "array_image_required", + "optional": false, + "typeAnnotation": Object { + "elementType": Object { + "name": "ImageSourcePrimitive", + "type": "NativePrimitiveTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "array_image_optional_key", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "name": "ImageSourcePrimitive", + "type": "NativePrimitiveTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "array_image_optional_value", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "name": "ImageSourcePrimitive", + "type": "NativePrimitiveTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "array_image_optional_both", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "name": "ImageSourcePrimitive", + "type": "NativePrimitiveTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "array_color_required", + "optional": false, + "typeAnnotation": Object { + "elementType": Object { + "name": "ColorPrimitive", + "type": "NativePrimitiveTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "array_color_optional_key", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "name": "ColorPrimitive", + "type": "NativePrimitiveTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "array_color_optional_value", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "name": "ColorPrimitive", + "type": "NativePrimitiveTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "array_color_optional_both", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "name": "ColorPrimitive", + "type": "NativePrimitiveTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "array_point_required", + "optional": false, + "typeAnnotation": Object { + "elementType": Object { + "name": "PointPrimitive", + "type": "NativePrimitiveTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "array_point_optional_key", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "name": "PointPrimitive", + "type": "NativePrimitiveTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "array_point_optional_value", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "name": "PointPrimitive", + "type": "NativePrimitiveTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "array_point_optional_both", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "name": "PointPrimitive", + "type": "NativePrimitiveTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + ], + }, + }, + }, + }, +} +`; + +exports[`RN Codegen Flow Parser can generate fixture EVENTS_DEFINED_AS_NULL_IN_FILE 1`] = ` +Object { + "modules": Object { + "Module": Object { + "components": Object { + "Module": Object { + "events": Array [ + Object { + "bubblingType": "direct", + "name": "onDirectEventDefinedInFileNull", + "optional": false, + "typeAnnotation": Object { + "argument": Object { + "properties": Array [], + "type": "ObjectTypeAnnotation", + }, + "type": "EventTypeAnnotation", + }, + }, + Object { + "bubblingType": "direct", + "name": "onDirectEventDefinedInFileNullOptionalKey", + "optional": true, + "typeAnnotation": Object { + "argument": Object { + "properties": Array [], + "type": "ObjectTypeAnnotation", + }, + "type": "EventTypeAnnotation", + }, + }, + Object { + "bubblingType": "direct", + "name": "onDirectEventDefinedInFileNullOptionalValue", + "optional": true, + "typeAnnotation": Object { + "argument": Object { + "properties": Array [], + "type": "ObjectTypeAnnotation", + }, + "type": "EventTypeAnnotation", + }, + }, + Object { + "bubblingType": "direct", + "name": "onDirectEventDefinedInFileNullOptionalBoth", + "optional": true, + "typeAnnotation": Object { + "argument": Object { + "properties": Array [], + "type": "ObjectTypeAnnotation", + }, + "type": "EventTypeAnnotation", + }, + }, + Object { + "bubblingType": "bubble", + "name": "onBubblingEventDefinedInFileNull", + "optional": false, + "typeAnnotation": Object { + "argument": Object { + "properties": Array [], + "type": "ObjectTypeAnnotation", + }, + "type": "EventTypeAnnotation", + }, + }, + Object { + "bubblingType": "bubble", + "name": "onBubblingEventDefinedInFileNullOptionalKey", + "optional": true, + "typeAnnotation": Object { + "argument": Object { + "properties": Array [], + "type": "ObjectTypeAnnotation", + }, + "type": "EventTypeAnnotation", + }, + }, + Object { + "bubblingType": "bubble", + "name": "onBubblingEventDefinedInFileNullOptionalValue", + "optional": true, + "typeAnnotation": Object { + "argument": Object { + "properties": Array [], + "type": "ObjectTypeAnnotation", + }, + "type": "EventTypeAnnotation", + }, + }, + Object { + "bubblingType": "bubble", + "name": "onBubblingEventDefinedInFileNullOptionalBoth", + "optional": true, + "typeAnnotation": Object { + "argument": Object { + "properties": Array [], + "type": "ObjectTypeAnnotation", + }, + "type": "EventTypeAnnotation", + }, + }, + ], + "extendsProps": Array [ + Object { + "knownTypeName": "ReactNativeCoreViewProps", + "type": "ReactNativeBuiltInType", + }, + ], + "props": Array [], + }, + }, + }, + }, +} +`; + +exports[`RN Codegen Flow Parser can generate fixture EVENTS_DEFINED_AS_NULL_INLINE 1`] = ` +Object { + "modules": Object { + "Module": Object { + "components": Object { + "Module": Object { + "events": Array [ + Object { + "bubblingType": "direct", + "name": "onDirectEventDefinedInlineNull", + "optional": false, + "typeAnnotation": Object { + "argument": Object { + "properties": Array [], + "type": "ObjectTypeAnnotation", + }, + "type": "EventTypeAnnotation", + }, + }, + Object { + "bubblingType": "direct", + "name": "onDirectEventDefinedInlineNullOptionalKey", + "optional": true, + "typeAnnotation": Object { + "argument": Object { + "properties": Array [], + "type": "ObjectTypeAnnotation", + }, + "type": "EventTypeAnnotation", + }, + }, + Object { + "bubblingType": "direct", + "name": "onDirectEventDefinedInlineNullOptionalValue", + "optional": true, + "typeAnnotation": Object { + "argument": Object { + "properties": Array [], + "type": "ObjectTypeAnnotation", + }, + "type": "EventTypeAnnotation", + }, + }, + Object { + "bubblingType": "direct", + "name": "onDirectEventDefinedInlineNullOptionalBoth", + "optional": true, + "typeAnnotation": Object { + "argument": Object { + "properties": Array [], + "type": "ObjectTypeAnnotation", + }, + "type": "EventTypeAnnotation", + }, + }, + Object { + "bubblingType": "bubble", + "name": "onBubblingEventDefinedInlineNull", + "optional": false, + "typeAnnotation": Object { + "argument": Object { + "properties": Array [], + "type": "ObjectTypeAnnotation", + }, + "type": "EventTypeAnnotation", + }, + }, + Object { + "bubblingType": "bubble", + "name": "onBubblingEventDefinedInlineNullOptionalKey", + "optional": true, + "typeAnnotation": Object { + "argument": Object { + "properties": Array [], + "type": "ObjectTypeAnnotation", + }, + "type": "EventTypeAnnotation", + }, + }, + Object { + "bubblingType": "bubble", + "name": "onBubblingEventDefinedInlineNullOptionalValue", + "optional": true, + "typeAnnotation": Object { + "argument": Object { + "properties": Array [], + "type": "ObjectTypeAnnotation", + }, + "type": "EventTypeAnnotation", + }, + }, + Object { + "bubblingType": "bubble", + "name": "onBubblingEventDefinedInlineNullOptionalBoth", + "optional": true, + "typeAnnotation": Object { + "argument": Object { + "properties": Array [], + "type": "ObjectTypeAnnotation", + }, + "type": "EventTypeAnnotation", + }, + }, + ], + "extendsProps": Array [ + Object { + "knownTypeName": "ReactNativeCoreViewProps", + "type": "ReactNativeBuiltInType", + }, + ], + "props": Array [], + }, + }, + }, + }, +} +`; + +exports[`RN Codegen Flow Parser can generate fixture EVENTS_DEFINED_IN_FILE_WITH_ALL_TYPES 1`] = ` +Object { + "modules": Object { + "Module": Object { + "components": Object { + "Module": Object { + "events": Array [ + Object { + "bubblingType": "direct", + "name": "onDirectEventDefinedInFile", + "optional": false, + "typeAnnotation": Object { + "argument": Object { + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_key", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_value", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_both", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "string_required", + "optional": false, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_value", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_both", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "float_required", + "optional": false, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_key", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_both", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "int32_required", + "optional": false, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_key", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_value", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "object_required", + "optional": false, + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "BooleanTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_key", + "optional": true, + "properties": Array [ + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_value", + "optional": true, + "properties": Array [ + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_both", + "optional": true, + "properties": Array [ + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_required_nested_2_layers", + "optional": false, + "properties": Array [ + Object { + "name": "object_optional_nested_1_layer", + "optional": true, + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + "type": "EventTypeAnnotation", + }, + }, + Object { + "bubblingType": "direct", + "name": "onDirectEventDefinedInFileOptionalKey", + "optional": true, + "typeAnnotation": Object { + "argument": Object { + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_key", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_value", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_both", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "string_required", + "optional": false, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_value", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_both", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "float_required", + "optional": false, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_key", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_both", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "int32_required", + "optional": false, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_key", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_value", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "object_required", + "optional": false, + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "BooleanTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_key", + "optional": true, + "properties": Array [ + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_value", + "optional": true, + "properties": Array [ + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_both", + "optional": true, + "properties": Array [ + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_required_nested_2_layers", + "optional": false, + "properties": Array [ + Object { + "name": "object_optional_nested_1_layer", + "optional": true, + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + "type": "EventTypeAnnotation", + }, + }, + Object { + "bubblingType": "direct", + "name": "onDirectEventDefinedInFileOptionalValue", + "optional": true, + "typeAnnotation": Object { + "argument": Object { + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_key", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_value", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_both", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "string_required", + "optional": false, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_value", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_both", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "float_required", + "optional": false, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_key", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_both", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "int32_required", + "optional": false, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_key", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_value", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "object_required", + "optional": false, + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "BooleanTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_key", + "optional": true, + "properties": Array [ + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_value", + "optional": true, + "properties": Array [ + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_both", + "optional": true, + "properties": Array [ + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_required_nested_2_layers", + "optional": false, + "properties": Array [ + Object { + "name": "object_optional_nested_1_layer", + "optional": true, + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + "type": "EventTypeAnnotation", + }, + }, + Object { + "bubblingType": "direct", + "name": "onDirectEventDefinedInFileOptionalBoth", + "optional": true, + "typeAnnotation": Object { + "argument": Object { + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_key", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_value", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_both", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "string_required", + "optional": false, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_value", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_both", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "float_required", + "optional": false, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_key", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_both", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "int32_required", + "optional": false, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_key", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_value", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "object_required", + "optional": false, + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "BooleanTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_key", + "optional": true, + "properties": Array [ + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_value", + "optional": true, + "properties": Array [ + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_both", + "optional": true, + "properties": Array [ + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_required_nested_2_layers", + "optional": false, + "properties": Array [ + Object { + "name": "object_optional_nested_1_layer", + "optional": true, + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + "type": "EventTypeAnnotation", + }, + }, + Object { + "bubblingType": "bubble", + "name": "onBubblingEventDefinedInFile", + "optional": false, + "typeAnnotation": Object { + "argument": Object { + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_key", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_value", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_both", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "string_required", + "optional": false, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_value", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_both", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "float_required", + "optional": false, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_key", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_both", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "int32_required", + "optional": false, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_key", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_value", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "object_required", + "optional": false, + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "BooleanTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_key", + "optional": true, + "properties": Array [ + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_value", + "optional": true, + "properties": Array [ + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_both", + "optional": true, + "properties": Array [ + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_required_nested_2_layers", + "optional": false, + "properties": Array [ + Object { + "name": "object_optional_nested_1_layer", + "optional": true, + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + "type": "EventTypeAnnotation", + }, + }, + Object { + "bubblingType": "bubble", + "name": "onBubblingEventDefinedInFileOptionalKey", + "optional": true, + "typeAnnotation": Object { + "argument": Object { + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_key", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_value", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_both", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "string_required", + "optional": false, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_value", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_both", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "float_required", + "optional": false, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_key", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_both", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "int32_required", + "optional": false, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_key", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_value", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "object_required", + "optional": false, + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "BooleanTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_key", + "optional": true, + "properties": Array [ + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_value", + "optional": true, + "properties": Array [ + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_both", + "optional": true, + "properties": Array [ + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_required_nested_2_layers", + "optional": false, + "properties": Array [ + Object { + "name": "object_optional_nested_1_layer", + "optional": true, + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + "type": "EventTypeAnnotation", + }, + }, + Object { + "bubblingType": "bubble", + "name": "onBubblingEventDefinedInFileOptionalValue", + "optional": true, + "typeAnnotation": Object { + "argument": Object { + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_key", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_value", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_both", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "string_required", + "optional": false, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_value", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_both", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "float_required", + "optional": false, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_key", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_both", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "int32_required", + "optional": false, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_key", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_value", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "object_required", + "optional": false, + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "BooleanTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_key", + "optional": true, + "properties": Array [ + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_value", + "optional": true, + "properties": Array [ + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_both", + "optional": true, + "properties": Array [ + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_required_nested_2_layers", + "optional": false, + "properties": Array [ + Object { + "name": "object_optional_nested_1_layer", + "optional": true, + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + "type": "EventTypeAnnotation", + }, + }, + Object { + "bubblingType": "bubble", + "name": "onBubblingEventDefinedInFileOptionalBoth", + "optional": true, + "typeAnnotation": Object { + "argument": Object { + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_key", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_value", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_both", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "string_required", + "optional": false, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_value", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_both", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "float_required", + "optional": false, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_key", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_both", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "int32_required", + "optional": false, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_key", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_value", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "object_required", + "optional": false, + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "BooleanTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_key", + "optional": true, + "properties": Array [ + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_value", + "optional": true, + "properties": Array [ + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_both", + "optional": true, + "properties": Array [ + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_required_nested_2_layers", + "optional": false, + "properties": Array [ + Object { + "name": "object_optional_nested_1_layer", + "optional": true, + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + "type": "EventTypeAnnotation", + }, + }, + ], + "extendsProps": Array [ + Object { + "knownTypeName": "ReactNativeCoreViewProps", + "type": "ReactNativeBuiltInType", + }, + ], + "props": Array [], + }, + }, + }, + }, +} +`; + +exports[`RN Codegen Flow Parser can generate fixture EVENTS_DEFINED_INLINE_WITH_ALL_TYPES 1`] = ` +Object { + "modules": Object { + "Module": Object { + "components": Object { + "Module": Object { + "events": Array [ + Object { + "bubblingType": "direct", + "name": "onDirectEventDefinedInline", + "optional": false, + "typeAnnotation": Object { + "argument": Object { + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_key", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_value", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_both", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "string_required", + "optional": false, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_value", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_both", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "float_required", + "optional": false, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_key", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_both", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "int32_required", + "optional": false, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_key", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_value", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "object_required", + "optional": false, + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "BooleanTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_key", + "optional": true, + "properties": Array [ + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_value", + "optional": true, + "properties": Array [ + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_both", + "optional": true, + "properties": Array [ + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_required_nested_2_layers", + "optional": false, + "properties": Array [ + Object { + "name": "object_optional_nested_1_layer", + "optional": true, + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + "type": "EventTypeAnnotation", + }, + }, + Object { + "bubblingType": "direct", + "name": "onDirectEventDefinedInlineOptionalKey", + "optional": true, + "typeAnnotation": Object { + "argument": Object { + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_key", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_value", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_both", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "string_required", + "optional": false, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_value", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_both", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "float_required", + "optional": false, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_key", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_both", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "int32_required", + "optional": false, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_key", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_value", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "object_required", + "optional": false, + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "BooleanTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_key", + "optional": true, + "properties": Array [ + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_value", + "optional": true, + "properties": Array [ + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_both", + "optional": true, + "properties": Array [ + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_required_nested_2_layers", + "optional": false, + "properties": Array [ + Object { + "name": "object_optional_nested_1_layer", + "optional": true, + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + "type": "EventTypeAnnotation", + }, + }, + Object { + "bubblingType": "direct", + "name": "onDirectEventDefinedInlineOptionalValue", + "optional": true, + "typeAnnotation": Object { + "argument": Object { + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_key", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_value", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_both", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "string_required", + "optional": false, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_value", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_both", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "float_required", + "optional": false, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_key", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_both", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "int32_required", + "optional": false, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_key", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_value", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "object_required", + "optional": false, + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "BooleanTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_key", + "optional": true, + "properties": Array [ + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_value", + "optional": true, + "properties": Array [ + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_both", + "optional": true, + "properties": Array [ + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_required_nested_2_layers", + "optional": false, + "properties": Array [ + Object { + "name": "object_optional_nested_1_layer", + "optional": true, + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + "type": "EventTypeAnnotation", + }, + }, + Object { + "bubblingType": "direct", + "name": "onDirectEventDefinedInlineOptionalBoth", + "optional": true, + "typeAnnotation": Object { + "argument": Object { + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_key", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_value", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_both", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "string_required", + "optional": false, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_value", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_both", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "float_required", + "optional": false, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_key", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_both", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "int32_required", + "optional": false, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_key", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_value", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "object_required", + "optional": false, + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "BooleanTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_key", + "optional": true, + "properties": Array [ + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_value", + "optional": true, + "properties": Array [ + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_both", + "optional": true, + "properties": Array [ + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_required_nested_2_layers", + "optional": false, + "properties": Array [ + Object { + "name": "object_optional_nested_1_layer", + "optional": true, + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + "type": "EventTypeAnnotation", + }, + }, + Object { + "bubblingType": "bubble", + "name": "onBubblingEventDefinedInline", + "optional": false, + "typeAnnotation": Object { + "argument": Object { + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_key", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_value", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_both", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "string_required", + "optional": false, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_value", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_both", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "float_required", + "optional": false, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_key", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_both", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "int32_required", + "optional": false, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_key", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_value", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "object_required", + "optional": false, + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "BooleanTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_key", + "optional": true, + "properties": Array [ + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_value", + "optional": true, + "properties": Array [ + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_both", + "optional": true, + "properties": Array [ + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_required_nested_2_layers", + "optional": false, + "properties": Array [ + Object { + "name": "object_optional_nested_1_layer", + "optional": true, + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + "type": "EventTypeAnnotation", + }, + }, + Object { + "bubblingType": "bubble", + "name": "onBubblingEventDefinedInlineOptionalKey", + "optional": true, + "typeAnnotation": Object { + "argument": Object { + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_key", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_value", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_both", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "string_required", + "optional": false, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_value", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_both", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "float_required", + "optional": false, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_key", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_both", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "int32_required", + "optional": false, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_key", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_value", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "object_required", + "optional": false, + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "BooleanTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_key", + "optional": true, + "properties": Array [ + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_value", + "optional": true, + "properties": Array [ + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_both", + "optional": true, + "properties": Array [ + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_required_nested_2_layers", + "optional": false, + "properties": Array [ + Object { + "name": "object_optional_nested_1_layer", + "optional": true, + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + "type": "EventTypeAnnotation", + }, + }, + Object { + "bubblingType": "bubble", + "name": "onBubblingEventDefinedInlineOptionalValue", + "optional": true, + "typeAnnotation": Object { + "argument": Object { + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_key", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_value", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_both", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "string_required", + "optional": false, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_value", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_both", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "float_required", + "optional": false, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_key", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_both", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "int32_required", + "optional": false, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_key", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_value", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "object_required", + "optional": false, + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "BooleanTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_key", + "optional": true, + "properties": Array [ + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_value", + "optional": true, + "properties": Array [ + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_both", + "optional": true, + "properties": Array [ + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_required_nested_2_layers", + "optional": false, + "properties": Array [ + Object { + "name": "object_optional_nested_1_layer", + "optional": true, + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + "type": "EventTypeAnnotation", + }, + }, + Object { + "bubblingType": "bubble", + "name": "onBubblingEventDefinedInlineOptionalBoth", + "optional": true, + "typeAnnotation": Object { + "argument": Object { + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_key", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_value", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "boolean_optional_both", + "optional": true, + "type": "BooleanTypeAnnotation", + }, + Object { + "name": "string_required", + "optional": false, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_value", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "string_optional_both", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "float_required", + "optional": false, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_key", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "float_optional_both", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "int32_required", + "optional": false, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_key", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_value", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "object_required", + "optional": false, + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "BooleanTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_key", + "optional": true, + "properties": Array [ + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_value", + "optional": true, + "properties": Array [ + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_optional_both", + "optional": true, + "properties": Array [ + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + Object { + "name": "object_required_nested_2_layers", + "optional": false, + "properties": Array [ + Object { + "name": "object_optional_nested_1_layer", + "optional": true, + "properties": Array [ + Object { + "name": "boolean_required", + "optional": false, + "type": "Int32TypeAnnotation", + }, + Object { + "name": "string_optional_key", + "optional": true, + "type": "StringTypeAnnotation", + }, + Object { + "name": "float_optional_value", + "optional": true, + "type": "FloatTypeAnnotation", + }, + Object { + "name": "int32_optional_both", + "optional": true, + "type": "Int32TypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + ], + "type": "ObjectTypeAnnotation", + }, + "type": "EventTypeAnnotation", + }, + }, + ], + "extendsProps": Array [ + Object { + "knownTypeName": "ReactNativeCoreViewProps", + "type": "ReactNativeBuiltInType", + }, + ], + "props": Array [], + }, + }, + }, + }, +} +`; + +exports[`RN Codegen Flow Parser can generate fixture ONE_OF_EACH_PROP_EVENT_DEFAULT_AND_OPTIONS 1`] = ` +Object { + "modules": Object { + "Module": Object { + "components": Object { + "Module": Object { + "events": Array [ + Object { + "bubblingType": "direct", + "name": "onDirectEventDefinedInlineNull", + "optional": false, + "typeAnnotation": Object { + "argument": Object { + "properties": Array [], + "type": "ObjectTypeAnnotation", + }, + "type": "EventTypeAnnotation", + }, + }, + Object { + "bubblingType": "bubble", + "name": "onBubblingEventDefinedInlineNull", + "optional": false, + "typeAnnotation": Object { + "argument": Object { + "properties": Array [], + "type": "ObjectTypeAnnotation", + }, + "type": "EventTypeAnnotation", + }, + }, + ], + "extendsProps": Array [ + Object { + "knownTypeName": "ReactNativeCoreViewProps", + "type": "ReactNativeBuiltInType", + }, + ], + "interfaceOnly": true, + "isDeprecatedPaperComponentNameRCT": true, + "props": Array [ + Object { + "name": "boolean_default_true_optional_both", + "optional": true, + "typeAnnotation": Object { + "default": true, + "type": "BooleanTypeAnnotation", + }, + }, + ], + }, + }, + }, + }, +} +`; diff --git a/packages/react-native-codegen/src/parsers/flow/__tests__/parser-test.js b/packages/react-native-codegen/src/parsers/flow/__tests__/parser-test.js new file mode 100644 index 00000000000000..05c7374569a424 --- /dev/null +++ b/packages/react-native-codegen/src/parsers/flow/__tests__/parser-test.js @@ -0,0 +1,28 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @emails oncall+react_native + * @flow + * @format + */ + +'use strict'; + +const FlowParser = require('../index.js'); +const fixtures = require('../__test_fixtures__/fixtures.js'); +jest.mock('fs', () => ({ + readFileSync: filename => fixtures[filename], +})); + +describe('RN Codegen Flow Parser', () => { + Object.keys(fixtures) + .sort() + .forEach(fixtureName => { + it(`can generate fixture ${fixtureName}`, () => { + expect(FlowParser.parse(fixtureName)).toMatchSnapshot(); + }); + }); +}); diff --git a/packages/react-native-codegen/src/parsers/flow/events.js b/packages/react-native-codegen/src/parsers/flow/events.js new file mode 100644 index 00000000000000..263acf32e25809 --- /dev/null +++ b/packages/react-native-codegen/src/parsers/flow/events.js @@ -0,0 +1,167 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +'use strict'; + +import type {EventTypeShape, ObjectPropertyType} from '../../CodegenSchema.js'; + +function getPropertyType(name, optional, typeAnnotation) { + const type = + typeAnnotation.type === 'GenericTypeAnnotation' + ? typeAnnotation.id.name + : typeAnnotation.type; + + switch (type) { + case 'BooleanTypeAnnotation': + return { + type: 'BooleanTypeAnnotation', + name, + optional, + }; + case 'StringTypeAnnotation': + return { + type: 'StringTypeAnnotation', + name, + optional, + }; + case 'Int32': + return { + type: 'Int32TypeAnnotation', + name, + optional, + }; + case 'Float': + return { + type: 'FloatTypeAnnotation', + name, + optional, + }; + case 'ObjectTypeAnnotation': + return { + type: 'ObjectTypeAnnotation', + name, + optional, + properties: typeAnnotation.properties.map(buildPropertiesForEvent), + }; + default: + throw new Error(`Unable to determine type for "${name}"`); + } +} + +function findEventArgumentsAndType(typeAnnotation, types, bubblingType) { + const name = typeAnnotation.id.name; + if (name === '$ReadOnly') { + return { + argumentProps: typeAnnotation.typeParameters.params[0].properties, + bubblingType, + }; + } else if (name === 'BubblingEvent' || name === 'DirectEvent') { + const eventType = name === 'BubblingEvent' ? 'bubble' : 'direct'; + if ( + typeAnnotation.typeParameters.params[0].type === + 'NullLiteralTypeAnnotation' + ) { + return {argumentProps: [], bubblingType: eventType}; + } + return findEventArgumentsAndType( + typeAnnotation.typeParameters.params[0], + types, + eventType, + ); + } else if (types[name]) { + return findEventArgumentsAndType(types[name].right, types, bubblingType); + } else { + return {argumentProps: null, bubblingType: null}; + } +} + +function buildPropertiesForEvent(property): ObjectPropertyType { + const name = property.key.name; + const optional = + property.value.type === 'NullableTypeAnnotation' || property.optional; + let typeAnnotation = + property.value.type === 'NullableTypeAnnotation' + ? property.value.typeAnnotation + : property.value; + + return getPropertyType(name, optional, typeAnnotation); +} + +function getEventArgument(argumentProps, name) { + return { + type: 'ObjectTypeAnnotation', + properties: argumentProps.map(buildPropertiesForEvent), + }; +} + +function buildEventSchema( + types: TypeMap, + property: EventTypeAST, +): ?EventTypeShape { + const name = property.key.name; + const optional = + property.optional || property.value.type === 'NullableTypeAnnotation'; + + let typeAnnotation = + property.value.type === 'NullableTypeAnnotation' + ? property.value.typeAnnotation + : property.value; + + if (typeAnnotation.type !== 'FunctionTypeAnnotation') { + return null; + } + + const {argumentProps, bubblingType} = findEventArgumentsAndType( + typeAnnotation.params[0].typeAnnotation, + types, + ); + + if (bubblingType && argumentProps) { + return { + name, + optional, + bubblingType, + typeAnnotation: { + type: 'EventTypeAnnotation', + argument: getEventArgument(argumentProps, name), + }, + }; + } + + if (argumentProps === null) { + throw new Error(`Unabled to determine event arguments for "${name}"`); + } + + if (bubblingType === null) { + throw new Error(`Unabled to determine event arguments for "${name}"`); + } +} + +// $FlowFixMe there's no flowtype for ASTs +type EventTypeAST = Object; + +type TypeMap = { + // $FlowFixMe there's no flowtype for ASTs + [string]: Object, +}; + +function getEvents( + eventTypeAST: $ReadOnlyArray, + types: TypeMap, +): $ReadOnlyArray { + return eventTypeAST + .filter(property => property.type === 'ObjectTypeProperty') + .map(property => buildEventSchema(types, property)) + .filter(Boolean); +} + +module.exports = { + getEvents, +}; diff --git a/packages/react-native-codegen/src/parsers/flow/extends.js b/packages/react-native-codegen/src/parsers/flow/extends.js new file mode 100644 index 00000000000000..9d9a30b7317814 --- /dev/null +++ b/packages/react-native-codegen/src/parsers/flow/extends.js @@ -0,0 +1,42 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +'use strict'; + +import type {ExtendsPropsShape} from '../../CodegenSchema.js'; + +function extendsForProp(prop) { + const name = prop.argument.id.name; + switch (name) { + case 'ViewProps': + return { + type: 'ReactNativeBuiltInType', + knownTypeName: 'ReactNativeCoreViewProps', + }; + default: { + throw new Error(`Unable to handle prop spread: ${name}`); + } + } +} + +// $FlowFixMe there's no flowtype for ASTs +type PropsAST = Object; + +function getExtendsProps( + typeDefinition: $ReadOnlyArray, +): $ReadOnlyArray { + return typeDefinition + .filter(prop => prop.type === 'ObjectTypeSpreadProperty') + .map(extendsForProp); +} + +module.exports = { + getExtendsProps, +}; diff --git a/packages/react-native-codegen/src/parsers/flow/index.js b/packages/react-native-codegen/src/parsers/flow/index.js index f8fe9459b89a88..861b444412e86b 100644 --- a/packages/react-native-codegen/src/parsers/flow/index.js +++ b/packages/react-native-codegen/src/parsers/flow/index.js @@ -11,9 +11,93 @@ 'use strict'; import type {SchemaType} from '../../CodegenSchema.js'; +// $FlowFixMe there's no flowtype flow-parser +const flowParser = require('flow-parser'); +const fs = require('fs'); +const {buildSchema} = require('./schema'); +const {getEvents} = require('./events'); +const {getProps} = require('./props'); +const {getOptions} = require('./options'); +const {getExtendsProps} = require('./extends'); + +function findConfig(types) { + const foundConfigs = []; + + Object.keys(types).forEach(key => { + try { + const type = types[key]; + if (type.right.id.name === 'CodegenNativeComponent') { + const params = type.right.typeParameters.params; + const nativeComponentType = {}; + nativeComponentType.componentName = params[0].value; + nativeComponentType.propsTypeName = params[1].id.name; + if (params.length > 2) { + nativeComponentType.optionsTypeName = params[2].id.name; + } + foundConfigs.push(nativeComponentType); + } + } catch (e) { + // ignore + } + }); + + if (foundConfigs.length === 0) { + throw new Error('Could not find component config for native component'); + } + if (foundConfigs.length > 1) { + throw new Error('Only one component is supported per file'); + } + + return foundConfigs[0]; +} + +function getTypes(ast) { + return ast.body + .filter(node => node.type === 'TypeAlias') + .reduce((types, node) => { + types[node.id.name] = node; + return types; + }, {}); +} + +function getPropProperties(propsTypeName, types) { + const typeAlias = types[propsTypeName]; + try { + return typeAlias.right.typeParameters.params[0].properties; + } catch (e) { + throw new Error( + `Failed find type definition for "${propsTypeName}", please check that you have a valid codegen flow file`, + ); + } +} + +function parseFileAst(filename: string) { + const contents = fs.readFileSync(filename, 'utf8'); + const ast = flowParser.parse(contents); + + const types = getTypes(ast); + const {componentName, propsTypeName, optionsTypeName} = findConfig(types); + + const propProperties = getPropProperties(propsTypeName, types); + + const extendsProps = getExtendsProps(propProperties); + const options = getOptions(types[optionsTypeName]); + + const props = getProps(propProperties); + const events = getEvents(propProperties, types); + + return { + filename: componentName, + componentName, + options, + extendsProps, + events, + props, + }; +} function parse(filename: string): ?SchemaType { - throw new Error('Not implemented yet'); + return buildSchema(parseFileAst(filename)); } module.exports = { diff --git a/packages/react-native-codegen/src/parsers/flow/options.js b/packages/react-native-codegen/src/parsers/flow/options.js new file mode 100644 index 00000000000000..157de570179f37 --- /dev/null +++ b/packages/react-native-codegen/src/parsers/flow/options.js @@ -0,0 +1,36 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +'use strict'; + +import type {OptionsShape} from '../../CodegenSchema.js'; + +// $FlowFixMe there's no flowtype for ASTs +type OptionsAST = Object; + +function getOptions(optionsDefinition: OptionsAST): ?OptionsShape { + if (!optionsDefinition) { + return null; + } + try { + return optionsDefinition.right.properties.reduce((options, prop) => { + options[prop.key.name] = prop.value.value; + return options; + }, {}); + } catch (e) { + throw new Error( + 'Failed to parse codegen options, please check that they are defined correctly', + ); + } +} + +module.exports = { + getOptions, +}; diff --git a/packages/react-native-codegen/src/parsers/flow/props.js b/packages/react-native-codegen/src/parsers/flow/props.js new file mode 100644 index 00000000000000..e7d5e16d7daf7f --- /dev/null +++ b/packages/react-native-codegen/src/parsers/flow/props.js @@ -0,0 +1,222 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +'use strict'; + +import type {PropTypeShape} from '../../CodegenSchema.js'; + +function getTypeAnnotationForArray(name, typeAnnotation) { + if (typeAnnotation.type === 'NullableTypeAnnotation') { + throw new Error( + 'Nested optionals such as "$ReadOnlyArray" are not supported, please declare optionals at the top level of value definitions as in "?$ReadOnlyArray"', + ); + } + + if ( + typeAnnotation.type === 'GenericTypeAnnotation' && + typeAnnotation.id.name === 'WithDefault' + ) { + throw new Error( + 'Nested defaults such as "$ReadOnlyArray>" are not supported, please declare defaults at the top level of value definitions as in "WithDefault<$ReadOnlyArray, false>"', + ); + } + + const type = + typeAnnotation.type === 'GenericTypeAnnotation' + ? typeAnnotation.id.name + : typeAnnotation.type; + + switch (type) { + case 'ImageSource': + return { + type: 'NativePrimitiveTypeAnnotation', + name: 'ImageSourcePrimitive', + }; + case 'ColorValue': + return { + type: 'NativePrimitiveTypeAnnotation', + name: 'ColorPrimitive', + }; + case 'PointValue': + return { + type: 'NativePrimitiveTypeAnnotation', + name: 'PointPrimitive', + }; + case 'Int32': + return { + type: 'Int32TypeAnnotation', + }; + case 'Float': + return { + type: 'FloatTypeAnnotation', + }; + case 'BooleanTypeAnnotation': + return { + type: 'BooleanTypeAnnotation', + }; + case 'StringTypeAnnotation': + return { + type: 'StringTypeAnnotation', + }; + case 'UnionTypeAnnotation': + return { + type: 'StringEnumTypeAnnotation', + options: typeAnnotation.types.map(option => ({name: option.value})), + }; + default: + throw new Error(`Unknown prop type for "${name}"`); + } +} + +function getTypeAnnotation(name, typeAnnotation, defaultValue) { + if ( + typeAnnotation.type === 'GenericTypeAnnotation' && + typeAnnotation.id.name === '$ReadOnlyArray' + ) { + return { + type: 'ArrayTypeAnnotation', + elementType: getTypeAnnotationForArray( + name, + typeAnnotation.typeParameters.params[0], + ), + }; + } + + const type = + typeAnnotation.type === 'GenericTypeAnnotation' + ? typeAnnotation.id.name + : typeAnnotation.type; + + switch (type) { + case 'ImageSource': + return { + type: 'NativePrimitiveTypeAnnotation', + name: 'ImageSourcePrimitive', + }; + case 'ColorValue': + return { + type: 'NativePrimitiveTypeAnnotation', + name: 'ColorPrimitive', + }; + case 'PointValue': + return { + type: 'NativePrimitiveTypeAnnotation', + name: 'PointPrimitive', + }; + case 'Int32': + if (defaultValue !== null) { + return { + type: 'Int32TypeAnnotation', + default: (defaultValue: number), + }; + } + throw new Error(`A default int is required for "${name}"`); + case 'Float': + if (defaultValue !== null) { + return { + type: 'FloatTypeAnnotation', + default: (defaultValue: number), + }; + } + throw new Error(`A default float is required for "${name}"`); + case 'BooleanTypeAnnotation': + if (defaultValue !== null) { + return { + type: 'BooleanTypeAnnotation', + default: (defaultValue: boolean), + }; + } + throw new Error(`A default boolean is required for "${name}"`); + case 'StringTypeAnnotation': + if (defaultValue !== null) { + return { + type: 'StringTypeAnnotation', + default: (defaultValue: string), + }; + } + throw new Error(`A default string is required for "${name}"`); + case 'UnionTypeAnnotation': + if (defaultValue !== null) { + return { + type: 'StringEnumTypeAnnotation', + default: (defaultValue: string), + options: typeAnnotation.types.map(option => ({name: option.value})), + }; + } + throw new Error(`A default enum value is required for "${name}"`); + default: + throw new Error(`Unknown prop type for "${name}"`); + } +} + +function buildPropSchema(property): ?PropTypeShape { + const name = property.key.name; + const optional = + property.value.type === 'NullableTypeAnnotation' || property.optional; + + let typeAnnotation = + property.value.type === 'NullableTypeAnnotation' + ? property.value.typeAnnotation + : property.value; + + let type = typeAnnotation.type; + if (type === 'FunctionTypeAnnotation') { + return null; + } + + if ( + name === 'style' && + type === 'GenericTypeAnnotation' && + typeAnnotation.id.name === 'ViewStyleProp' + ) { + return null; + } + + let defaultValue = null; + if ( + type === 'GenericTypeAnnotation' && + typeAnnotation.id.name === 'WithDefault' + ) { + if (typeAnnotation.typeParameters.params.length === 1) { + throw new Error( + `WithDefault requires two parameters, did you forget to provide a default value for "${name}"?`, + ); + } + type = typeAnnotation.typeParameters.params[0].type; + defaultValue = typeAnnotation.typeParameters.params[1].value; + typeAnnotation = typeAnnotation.typeParameters.params[0]; + } + + if (type === 'GenericTypeAnnotation') { + type = typeAnnotation.id.name; + } + + return { + name, + optional, + typeAnnotation: getTypeAnnotation(name, typeAnnotation, defaultValue), + }; +} + +// $FlowFixMe there's no flowtype for ASTs +type PropAST = Object; + +function getProps( + typeDefinition: $ReadOnlyArray, +): $ReadOnlyArray { + return typeDefinition + .filter(property => property.type === 'ObjectTypeProperty') + .map(buildPropSchema) + .filter(Boolean); +} + +module.exports = { + getProps, +}; diff --git a/packages/react-native-codegen/src/parsers/flow/schema.js b/packages/react-native-codegen/src/parsers/flow/schema.js new file mode 100644 index 00000000000000..5f2c8f0da9fedb --- /dev/null +++ b/packages/react-native-codegen/src/parsers/flow/schema.js @@ -0,0 +1,56 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow + */ + +'use strict'; + +import type { + EventTypeShape, + PropTypeShape, + ExtendsPropsShape, + SchemaType, + OptionsShape, +} from '../../CodegenSchema.js'; + +type SchemaBuilderConfig = $ReadOnly<{| + filename: string, + componentName: string, + extendsProps: $ReadOnlyArray, + events: $ReadOnlyArray, + props: $ReadOnlyArray, + options?: ?OptionsShape, +|}>; + +function buildSchema({ + filename, + componentName, + extendsProps, + events, + props, + options, +}: SchemaBuilderConfig): SchemaType { + return { + modules: { + [filename]: { + components: { + [componentName]: { + ...(options || {}), + extendsProps, + events, + props, + }, + }, + }, + }, + }; +} + +module.exports = { + buildSchema, +}; From ca783414d66796fd714c6efd364b72d0b0c4a0a5 Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Fri, 24 May 2019 09:15:10 -0700 Subject: [PATCH 0066/1084] Integrate flow parser into view config generation Summary: This diff integrates the new flow parser into `js1 build viewconfig` so that we're generating the view config from actual source Note: see next diff for usage Reviewed By: mdvacca Differential Revision: D15452255 fbshipit-source-id: db04cb1c7adffaf3167a49c2260cae8fd365f50b --- .../viewconfigs/generate-view-configs-cli.js | 6 ++-- .../cli/viewconfigs/generate-view-configs.js | 31 +++++++++++++------ .../cli/viewconfigs/generate-view-configs.sh | 2 +- .../src/generators/GenerateViewConfigJs.js | 8 +++-- 4 files changed, 32 insertions(+), 15 deletions(-) diff --git a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js index cb861a4ba0e6f4..68fc84cb1f80eb 100644 --- a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js +++ b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js @@ -23,14 +23,14 @@ const yargv = yargs.strict().option('t', { const argv = yargv.argv; const fileList = argv._[0].split('\n'); -const CURRENT_VIEW_CONFIG_SCHEMAS = ['']; +const CURRENT_VIEW_CONFIG_FILES = []; generate( fileList.filter(fileName => - CURRENT_VIEW_CONFIG_SCHEMAS.find(supportedFileName => + CURRENT_VIEW_CONFIG_FILES.find(supportedFileName => fileName.endsWith(supportedFileName), ), ), // $FlowFixMe Type argv - argv.test, + {test: argv.test, parser: 'flow'}, ); diff --git a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.js b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.js index 18d5670890ea05..64abcb27935b87 100644 --- a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.js +++ b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.js @@ -12,6 +12,7 @@ const RNCodegen = require('../../generators/RNCodegen.js'); const SchemaParser = require('../../parsers/schema'); +const FlowParser = require('../../parsers/flow'); const path = require('path'); @@ -20,21 +21,31 @@ type Result = $ReadOnly<{| success: boolean, |}>; +type Config = $ReadOnly<{| + test?: boolean, + parser?: 'schema' | 'flow', +|}>; + function generateFilesWithResults( files: Array, - test: boolean, + config: Config, ): Array { return files.reduce((aggregated, filename) => { - const schema = SchemaParser.parse(filename); + const schema = + config.parser === 'flow' + ? FlowParser.parse(filename) + : SchemaParser.parse(filename); if (schema && schema.modules) { - const libraryName = path.basename(filename).replace('Schema.js', ''); + const libraryName = path + .basename(filename) + .replace(/NativeComponent\.js$/, ''); const success = RNCodegen.generate( { schema, libraryName, outputDirectory: path.dirname(filename), }, - {generators: ['view-configs'], test}, + {generators: ['view-configs'], test: config.test}, ); aggregated.push({ @@ -46,18 +57,20 @@ function generateFilesWithResults( }, []); } -function generate(files: Array, test: boolean): void { - console.log(`${test ? 'Testing' : 'Generating'} view configs`); +function generate(files: Array, config: Config): void { + console.log(`${config.test ? 'Testing' : 'Generating'} view configs`); - const results = generateFilesWithResults(files, test); + const results = generateFilesWithResults(files, config); const failed = results.filter(result => !result.success); const totalCount = results.length; - console.log(`\n${test ? 'Tested' : 'Generated'} ${totalCount} view configs`); + console.log( + `\n${config.test ? 'Tested' : 'Generated'} ${totalCount} view configs`, + ); if (failed.length) { - if (test === true) { + if (config.test === true) { console.error(`${failed.length} configs changed`); console.error("Please re-run 'js1 build viewconfigs'"); } diff --git a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.sh b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.sh index 4da0153b7ef6ce..355c9fe560b83a 100755 --- a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.sh +++ b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.sh @@ -7,7 +7,7 @@ set -u THIS_DIR=$(cd -P "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo "${BASH_SOURCE[0]}")")" && pwd) -FILES=$(find "$JS_DIR/" -name "*Schema.js" -print -type f) +FILES=$(find "$JS_DIR/" -name "*NativeComponent.js" -print -type f) # shellcheck source=xplat/js/env-utils/setup_env_vars.sh source "$THIS_DIR/../../../../../../env-utils/setup_env_vars.sh" diff --git a/packages/react-native-codegen/src/generators/GenerateViewConfigJs.js b/packages/react-native-codegen/src/generators/GenerateViewConfigJs.js index de818fd2bd1c75..3315d1a29d1349 100644 --- a/packages/react-native-codegen/src/generators/GenerateViewConfigJs.js +++ b/packages/react-native-codegen/src/generators/GenerateViewConfigJs.js @@ -56,11 +56,15 @@ function getReactDiffProcessValue(prop) { return j.template.expression`{ diff: require('pointsDiffer') }`; default: (typeAnnotation.name: empty); - throw new Error('Receieved unknown NativePrimitiveTypeAnnotation'); + throw new Error( + `Received unknown native typeAnnotation: "${typeAnnotation.name}"`, + ); } default: (typeAnnotation: empty); - throw new Error('Receieved invalid typeAnnotation'); + throw new Error( + `Received unknown typeAnnotation: "${typeAnnotation.type}"`, + ); } } From e52bc2aa73f8139ce4e7e197716aaeb110180df0 Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Fri, 24 May 2019 09:15:10 -0700 Subject: [PATCH 0067/1084] Use generated view config for Slider MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: This diff uses the generated view config for the slider component � Reviewed By: JoshuaGross, TheSavior, mdvacca Differential Revision: D15336089 fbshipit-source-id: 46c458805fd947e202e2084df65c8c83560cf106 --- Libraries/Components/Slider/Slider.js | 6 +- ...eComponent.js => SliderNativeComponent.js} | 4 +- .../Slider/SliderNativeViewConfig.js | 76 +++++++++++++++++++ Libraries/Components/Slider/SliderSchema.js | 1 + .../viewconfigs/generate-view-configs-cli.js | 2 +- 5 files changed, 82 insertions(+), 7 deletions(-) rename Libraries/Components/Slider/{RCTSliderNativeComponent.js => SliderNativeComponent.js} (90%) create mode 100644 Libraries/Components/Slider/SliderNativeViewConfig.js diff --git a/Libraries/Components/Slider/Slider.js b/Libraries/Components/Slider/Slider.js index e0e22b335c6e53..f7b47992e306bd 100644 --- a/Libraries/Components/Slider/Slider.js +++ b/Libraries/Components/Slider/Slider.js @@ -11,7 +11,7 @@ 'use strict'; const Platform = require('../../Utilities/Platform'); -const RCTSliderNativeComponent = require('./RCTSliderNativeComponent'); +const SliderNativeComponent = require('./SliderNativeComponent'); const React = require('react'); const ReactNative = require('../../Renderer/shims/ReactNative'); const StyleSheet = require('../../StyleSheet/StyleSheet'); @@ -197,7 +197,7 @@ type Props = $ReadOnly<{| */ const Slider = ( props: Props, - forwardedRef?: ?React.Ref, + forwardedRef?: ?React.Ref, ) => { const style = StyleSheet.compose( styles.slider, @@ -227,7 +227,7 @@ const Slider = ( : null; return ( - ; -module.exports = ((requireNativeComponent('RCTSlider'): any): SliderType); +module.exports = ((require('SliderNativeViewConfig'): any): SliderType); diff --git a/Libraries/Components/Slider/SliderNativeViewConfig.js b/Libraries/Components/Slider/SliderNativeViewConfig.js new file mode 100644 index 00000000000000..92abe056836b21 --- /dev/null +++ b/Libraries/Components/Slider/SliderNativeViewConfig.js @@ -0,0 +1,76 @@ + +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +'use strict'; + +const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); +const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); +const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); + +const SliderViewConfig = { + uiViewClassName: 'RCTSlider', + Commands: {}, + + bubblingEventTypes: { + ...ReactNativeViewViewConfig.bubblingEventTypes, + + topChange: { + phasedRegistrationNames: { + captured: 'onChangeCapture', + bubbled: 'onChange', + }, + }, + + topValueChange: { + phasedRegistrationNames: { + captured: 'onValueChangeCapture', + bubbled: 'onValueChange', + }, + }, + }, + + directEventTypes: { + ...ReactNativeViewViewConfig.directEventTypes, + + topSlidingComplete: { + registrationName: 'onSlidingComplete', + }, + }, + + validAttributes: { + ...ReactNativeViewViewConfig.validAttributes, + disabled: true, + enabled: true, + maximumTrackImage: { process: require('resolveAssetSource') }, + maximumTrackTintColor: { process: require('processColor') }, + maximumValue: true, + minimumTrackImage: { process: require('resolveAssetSource') }, + minimumTrackTintColor: { process: require('processColor') }, + minimumValue: true, + step: true, + testID: true, + thumbImage: { process: require('resolveAssetSource') }, + thumbTintColor: { process: require('processColor') }, + trackImage: { process: require('resolveAssetSource') }, + value: true, + onChange: true, + onValueChange: true, + onSlidingComplete: true, + }, +}; + +verifyComponentAttributeEquivalence('RCTSlider', SliderViewConfig); + +ReactNativeViewConfigRegistry.register( + 'RCTSlider', + () => SliderViewConfig, +); + +module.exports = 'RCTSlider'; // RCT prefix present for paper support diff --git a/Libraries/Components/Slider/SliderSchema.js b/Libraries/Components/Slider/SliderSchema.js index f3e75ad491abc8..32d954ca9ccdaf 100644 --- a/Libraries/Components/Slider/SliderSchema.js +++ b/Libraries/Components/Slider/SliderSchema.js @@ -18,6 +18,7 @@ const SliderSchema: SchemaType = { components: { Slider: { interfaceOnly: true, + isDeprecatedPaperComponentNameRCT: true, extendsProps: [ { type: 'ReactNativeBuiltInType', diff --git a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js index 68fc84cb1f80eb..eccf262a8d66a3 100644 --- a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js +++ b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js @@ -23,7 +23,7 @@ const yargv = yargs.strict().option('t', { const argv = yargv.argv; const fileList = argv._[0].split('\n'); -const CURRENT_VIEW_CONFIG_FILES = []; +const CURRENT_VIEW_CONFIG_FILES = ['SliderNativeComponent.js']; generate( fileList.filter(fileName => From ac62274e56ebe525def676ed8ad05b0a4e7b335d Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Fri, 24 May 2019 09:15:10 -0700 Subject: [PATCH 0068/1084] Use generated view config for ActivityIndicatorView Summary: This diff moves ActivityIndicatorView to the generated view config Reviewed By: shergin Differential Revision: D15392561 fbshipit-source-id: 67a2fa0dbbb884af9e9c02b9062d3a610a023240 --- .../ActivityIndicator/ActivityIndicator.js | 15 +++---- ...> ActivityIndicatorViewNativeComponent.js} | 34 +++++++------- .../ActivityIndicatorViewNativeViewConfig.js | 45 +++++++++++++++++++ ...hema.js => ActivityIndicatorViewSchema.js} | 17 +------ .../ActivityIndicator-test.js.snap | 2 - ...erifyComponentAttributeEquivalence-test.js | 1 + jest/setup.js | 5 +++ .../viewconfigs/generate-view-configs-cli.js | 5 ++- 8 files changed, 82 insertions(+), 42 deletions(-) rename Libraries/Components/ActivityIndicator/{RCTActivityIndicatorViewNativeComponent.js => ActivityIndicatorViewNativeComponent.js} (63%) create mode 100644 Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeViewConfig.js rename Libraries/Components/ActivityIndicator/{ActivityIndicatorSchema.js => ActivityIndicatorViewSchema.js} (80%) diff --git a/Libraries/Components/ActivityIndicator/ActivityIndicator.js b/Libraries/Components/ActivityIndicator/ActivityIndicator.js index 1c4a54c98ff1cf..f6ffe500edfc5d 100644 --- a/Libraries/Components/ActivityIndicator/ActivityIndicator.js +++ b/Libraries/Components/ActivityIndicator/ActivityIndicator.js @@ -15,15 +15,12 @@ const React = require('react'); const StyleSheet = require('../../StyleSheet/StyleSheet'); const View = require('../View/View'); -const RCTActivityIndicatorViewNativeComponent = require('./RCTActivityIndicatorViewNativeComponent'); +const ActivityIndicatorViewNativeComponent = require('./ActivityIndicatorViewNativeComponent'); import type {NativeComponent} from '../../Renderer/shims/ReactNative'; import type {ViewProps} from '../View/ViewPropTypes'; -const RCTActivityIndicator = - Platform.OS === 'android' - ? require('../ProgressBarAndroid/ProgressBarAndroid') - : RCTActivityIndicatorViewNativeComponent; +const ProgressBarAndroid = require('../ProgressBarAndroid/ProgressBarAndroid'); const GRAY = '#999999'; @@ -93,8 +90,6 @@ const ActivityIndicator = (props: Props, forwardedRef?: any) => { ref: forwardedRef, style: sizeStyle, size: sizeProp, - styleAttr: 'Normal', - indeterminate: true, }; return ( @@ -106,7 +101,11 @@ const ActivityIndicator = (props: Props, forwardedRef?: any) => { )}> {/* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was * found when making Flow check .android.js files. */} - + {Platform.OS === 'android' ? ( + + ) : ( + + )} ); }; diff --git a/Libraries/Components/ActivityIndicator/RCTActivityIndicatorViewNativeComponent.js b/Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeComponent.js similarity index 63% rename from Libraries/Components/ActivityIndicator/RCTActivityIndicatorViewNativeComponent.js rename to Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeComponent.js index e1d2be92935722..731b6f3fb27244 100644 --- a/Libraries/Components/ActivityIndicator/RCTActivityIndicatorViewNativeComponent.js +++ b/Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeComponent.js @@ -10,11 +10,13 @@ 'use strict'; -const requireNativeComponent = require('../../ReactNative/requireNativeComponent'); +import type { + WithDefault, + CodegenNativeComponent, +} from '../../Types/CodegenTypes'; +import type {ColorValue} from '../../StyleSheet/StyleSheetTypes'; import type {ViewProps} from '../View/ViewPropTypes'; -import type {ViewStyleProp} from '../../StyleSheet/StyleSheet'; -import type {NativeComponent} from '../../Renderer/shims/ReactNative'; type NativeProps = $ReadOnly<{| ...ViewProps, @@ -24,21 +26,21 @@ type NativeProps = $ReadOnly<{| * * See http://facebook.github.io/react-native/docs/activityindicator.html#hideswhenstopped */ - hidesWhenStopped?: ?boolean, + hidesWhenStopped?: ?WithDefault, /** * Whether to show the indicator (true, the default) or hide it (false). * * See http://facebook.github.io/react-native/docs/activityindicator.html#animating */ - animating?: ?boolean, + animating?: ?WithDefault, /** * The foreground color of the spinner (default is gray). * * See http://facebook.github.io/react-native/docs/activityindicator.html#color */ - color?: ?string, + color?: ?ColorValue, /** * Size of the indicator (default is 'small'). @@ -46,15 +48,17 @@ type NativeProps = $ReadOnly<{| * * See http://facebook.github.io/react-native/docs/activityindicator.html#size */ - size?: ?('small' | 'large'), - - style?: ?ViewStyleProp, - styleAttr?: ?string, - indeterminate?: ?boolean, + size?: ?WithDefault<'small' | 'large', 'small'>, |}>; -type ActivityIndicatorNativeType = Class>; +type Options = { + isDeprecatedPaperComponentNameRCT: true, +}; + +type ActivityIndicatorNativeType = CodegenNativeComponent< + 'ActivityIndicatorView', + NativeProps, + Options, +>; -module.exports = ((requireNativeComponent( - 'RCTActivityIndicatorView', -): any): ActivityIndicatorNativeType); +module.exports = ((require('./ActivityIndicatorViewNativeViewConfig'): any): ActivityIndicatorNativeType); diff --git a/Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeViewConfig.js b/Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeViewConfig.js new file mode 100644 index 00000000000000..0e448d1d21f24e --- /dev/null +++ b/Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeViewConfig.js @@ -0,0 +1,45 @@ + +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +'use strict'; + +const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); +const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); +const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); + +const ActivityIndicatorViewViewConfig = { + uiViewClassName: 'RCTActivityIndicatorView', + Commands: {}, + + bubblingEventTypes: { + ...ReactNativeViewViewConfig.bubblingEventTypes, + }, + + directEventTypes: { + ...ReactNativeViewViewConfig.directEventTypes, + }, + + validAttributes: { + ...ReactNativeViewViewConfig.validAttributes, + hidesWhenStopped: true, + animating: true, + color: { process: require('processColor') }, + size: true, + }, +}; + +verifyComponentAttributeEquivalence('RCTActivityIndicatorView', ActivityIndicatorViewViewConfig); + +ReactNativeViewConfigRegistry.register( + 'RCTActivityIndicatorView', + () => ActivityIndicatorViewViewConfig, +); + +module.exports = 'RCTActivityIndicatorView'; // RCT prefix present for paper support diff --git a/Libraries/Components/ActivityIndicator/ActivityIndicatorSchema.js b/Libraries/Components/ActivityIndicator/ActivityIndicatorViewSchema.js similarity index 80% rename from Libraries/Components/ActivityIndicator/ActivityIndicatorSchema.js rename to Libraries/Components/ActivityIndicator/ActivityIndicatorViewSchema.js index 7da1cbc1c27f0c..d45f7590721ec1 100644 --- a/Libraries/Components/ActivityIndicator/ActivityIndicatorSchema.js +++ b/Libraries/Components/ActivityIndicator/ActivityIndicatorViewSchema.js @@ -17,6 +17,7 @@ const SwitchSchema: SchemaType = { ActivityIndicatorSchema: { components: { ActivityIndicatorView: { + isDeprecatedPaperComponentNameRCT: true, extendsProps: [ { type: 'ReactNativeBuiltInType', @@ -41,14 +42,6 @@ const SwitchSchema: SchemaType = { default: false, }, }, - { - name: 'styleAttr', - optional: true, - typeAnnotation: { - type: 'StringTypeAnnotation', - default: '', - }, - }, { name: 'color', optional: true, @@ -73,14 +66,6 @@ const SwitchSchema: SchemaType = { ], }, }, - { - name: 'intermediate', - optional: true, - typeAnnotation: { - type: 'BooleanTypeAnnotation', - default: false, - }, - }, ], }, }, diff --git a/Libraries/Components/ActivityIndicator/__tests__/__snapshots__/ActivityIndicator-test.js.snap b/Libraries/Components/ActivityIndicator/__tests__/__snapshots__/ActivityIndicator-test.js.snap index 51f69150ab5916..fcd667d5670b89 100644 --- a/Libraries/Components/ActivityIndicator/__tests__/__snapshots__/ActivityIndicator-test.js.snap +++ b/Libraries/Components/ActivityIndicator/__tests__/__snapshots__/ActivityIndicator-test.js.snap @@ -22,7 +22,6 @@ exports[` should render as when not mocked 1`] = ` animating={true} color="#0000ff" hidesWhenStopped={true} - indeterminate={true} size="large" style={ Object { @@ -30,7 +29,6 @@ exports[` should render as when not mocked 1`] = ` "width": 36, } } - styleAttr="Normal" /> `; diff --git a/Libraries/Utilities/__tests__/verifyComponentAttributeEquivalence-test.js b/Libraries/Utilities/__tests__/verifyComponentAttributeEquivalence-test.js index 57e0d00e8a1fa0..13a1b3637d5d6f 100644 --- a/Libraries/Utilities/__tests__/verifyComponentAttributeEquivalence-test.js +++ b/Libraries/Utilities/__tests__/verifyComponentAttributeEquivalence-test.js @@ -13,6 +13,7 @@ const getNativeComponentAttributes = require('../../ReactNative/getNativeComponentAttributes'); const verifyComponentAttributeEquivalence = require('../verifyComponentAttributeEquivalence'); +jest.dontMock('../verifyComponentAttributeEquivalence'); jest.mock('../../ReactNative/getNativeComponentAttributes', () => () => ({ NativeProps: { value: 'BOOL', diff --git a/jest/setup.js b/jest/setup.js index eb2358c3c83ffb..3a2eb77bd2f05b 100644 --- a/jest/setup.js +++ b/jest/setup.js @@ -363,3 +363,8 @@ jest.doMock('../Libraries/ReactNative/requireNativeComponent', () => { } }; }); + +jest.doMock( + '../Libraries/Utilities/verifyComponentAttributeEquivalence', + () => function() {}, +); diff --git a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js index eccf262a8d66a3..421b569e952ac5 100644 --- a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js +++ b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js @@ -23,7 +23,10 @@ const yargv = yargs.strict().option('t', { const argv = yargv.argv; const fileList = argv._[0].split('\n'); -const CURRENT_VIEW_CONFIG_FILES = ['SliderNativeComponent.js']; +const CURRENT_VIEW_CONFIG_FILES = [ + 'SliderNativeComponent.js', + 'ActivityIndicatorViewNativeComponent.js', +]; generate( fileList.filter(fileName => From 9f8305a8375f7354f621c2feb7554ed7cd4b202d Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Fri, 24 May 2019 09:15:10 -0700 Subject: [PATCH 0069/1084] Add view config for PullToRefresh Summary: Adds the generated view config for PullToRefresh Note: we're not using this view config yet, the component is in the process of being renamed (see TODO) Reviewed By: rubennorte Differential Revision: D15485870 fbshipit-source-id: a163ac371181dcc990093e3cd995d7dd9058b26a --- ...js => PullToRefreshViewNativeComponent.js} | 24 ++++++--- .../PullToRefreshViewNativeViewConfig.js | 53 +++++++++++++++++++ .../RefreshControl/RefreshControl.js | 5 +- .../viewconfigs/generate-view-configs-cli.js | 1 + 4 files changed, 73 insertions(+), 10 deletions(-) rename Libraries/Components/RefreshControl/{RCTRefreshControlNativeComponent.js => PullToRefreshViewNativeComponent.js} (61%) create mode 100644 Libraries/Components/RefreshControl/PullToRefreshViewNativeViewConfig.js diff --git a/Libraries/Components/RefreshControl/RCTRefreshControlNativeComponent.js b/Libraries/Components/RefreshControl/PullToRefreshViewNativeComponent.js similarity index 61% rename from Libraries/Components/RefreshControl/RCTRefreshControlNativeComponent.js rename to Libraries/Components/RefreshControl/PullToRefreshViewNativeComponent.js index 1a20adadb2b7b2..5274896fb75e11 100644 --- a/Libraries/Components/RefreshControl/RCTRefreshControlNativeComponent.js +++ b/Libraries/Components/RefreshControl/PullToRefreshViewNativeComponent.js @@ -10,13 +10,18 @@ 'use strict'; +import type { + BubblingEvent, + WithDefault, + CodegenNativeComponent, +} from '../../Types/CodegenTypes'; + const requireNativeComponent = require('../../ReactNative/requireNativeComponent'); import type {ColorValue} from '../../StyleSheet/StyleSheetTypes'; import type {ViewProps} from '../View/ViewPropTypes'; -import type {NativeComponent} from '../../Renderer/shims/ReactNative'; -export type NativeProps = $ReadOnly<{| +type NativeProps = $ReadOnly<{| ...ViewProps, /** @@ -30,21 +35,26 @@ export type NativeProps = $ReadOnly<{| /** * The title displayed under the refresh indicator. */ - title?: ?string, + title?: ?WithDefault, /** * Called when the view starts refreshing. */ - onRefresh?: ?() => mixed, + onRefresh?: ?(event: BubblingEvent) => mixed, /** * Whether the view should be indicating an active refresh. */ - refreshing: boolean, + refreshing: WithDefault, |}>; -type PullToRefreshView = Class>; +type PullToRefreshViewType = CodegenNativeComponent< + 'PullToRefreshView', + NativeProps, +>; +// TODO: Switch this over to require('./PullToRefreshNativeViewConfig') +// once the native components are renamed in paper and fabric module.exports = ((requireNativeComponent( 'RCTRefreshControl', -): any): PullToRefreshView); +): any): PullToRefreshViewType); diff --git a/Libraries/Components/RefreshControl/PullToRefreshViewNativeViewConfig.js b/Libraries/Components/RefreshControl/PullToRefreshViewNativeViewConfig.js new file mode 100644 index 00000000000000..27a1071076e540 --- /dev/null +++ b/Libraries/Components/RefreshControl/PullToRefreshViewNativeViewConfig.js @@ -0,0 +1,53 @@ + +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +'use strict'; + +const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); +const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); +const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); + +const PullToRefreshViewViewConfig = { + uiViewClassName: 'PullToRefreshView', + Commands: {}, + + bubblingEventTypes: { + ...ReactNativeViewViewConfig.bubblingEventTypes, + + topRefresh: { + phasedRegistrationNames: { + captured: 'onRefreshCapture', + bubbled: 'onRefresh', + }, + }, + }, + + directEventTypes: { + ...ReactNativeViewViewConfig.directEventTypes, + }, + + validAttributes: { + ...ReactNativeViewViewConfig.validAttributes, + tintColor: { process: require('processColor') }, + titleColor: { process: require('processColor') }, + title: true, + refreshing: true, + onRefresh: true, + }, +}; + +verifyComponentAttributeEquivalence('PullToRefreshView', PullToRefreshViewViewConfig); + +ReactNativeViewConfigRegistry.register( + 'PullToRefreshView', + () => PullToRefreshViewViewConfig, +); + +module.exports = 'PullToRefreshView'; diff --git a/Libraries/Components/RefreshControl/RefreshControl.js b/Libraries/Components/RefreshControl/RefreshControl.js index cb432db07b6839..f6ed8d9e71c2c2 100644 --- a/Libraries/Components/RefreshControl/RefreshControl.js +++ b/Libraries/Components/RefreshControl/RefreshControl.js @@ -12,10 +12,9 @@ const Platform = require('../../Utilities/Platform'); const React = require('react'); -const {NativeComponent} = require('../../Renderer/shims/ReactNative'); const AndroidSwipeRefreshLayoutNativeComponent = require('./AndroidSwipeRefreshLayoutNativeComponent'); -const RCTRefreshControlNativeComponent = require('./RCTRefreshControlNativeComponent'); +const PullToRefreshViewNativeComponent = require('./PullToRefreshViewNativeComponent'); const nullthrows = require('nullthrows'); import type {ColorValue} from '../../StyleSheet/StyleSheetTypes'; @@ -175,7 +174,7 @@ class RefreshControl extends React.Component { ...props } = this.props; return ( - Date: Fri, 24 May 2019 11:22:09 -0700 Subject: [PATCH 0070/1084] Back out "[Venice][Fabric] Use startSurface on Android" Summary: Original commit changeset: 4a506a589108 Reviewed By: ejanzer Differential Revision: D15497094 fbshipit-source-id: 47e5d0c3c69cc56cc3dd56d28e23e1db5b562fa4 --- .../react/fabric/FabricUIManager.java | 9 ++----- .../facebook/react/fabric/jsi/Binding.java | 2 +- .../facebook/react/fabric/jsi/jni/Binding.cpp | 8 ++---- .../facebook/react/fabric/jsi/jni/Binding.h | 5 +--- ReactCommon/fabric/uimanager/Scheduler.cpp | 4 +++ .../fabric/uimanager/UIManagerBinding.cpp | 25 ++++++------------- 6 files changed, 17 insertions(+), 36 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java index 3c2070910a0dce..9b9c6f78107b38 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -128,18 +128,13 @@ public FabricUIManager( @Override public int addRootView( - final T rootView, final WritableMap initialProps, final @Nullable String initialUITemplate) { - return addRootView(rootView, null, initialProps, initialUITemplate); - } - - public int addRootView( - final T rootView, final @Nullable String moduleName, final WritableMap initialProps, final @Nullable String initialUITemplate) { + final T rootView, final WritableMap initialProps, final @Nullable String initialUITemplate) { final int rootTag = ReactRootViewTagGenerator.getNextRootViewTag(); ThemedReactContext reactContext = new ThemedReactContext(mReactApplicationContext, rootView.getContext()); mMountingManager.addRootView(rootTag, rootView); mReactContextForRootTag.put(rootTag, reactContext); - mBinding.startSurface(rootTag, moduleName == null ? "" : moduleName, (NativeMap) initialProps); + mBinding.startSurface(rootTag, (NativeMap) initialProps); if (initialUITemplate != null) { mBinding.renderTemplateToSurface(rootTag, initialUITemplate); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/Binding.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/Binding.java index 664cd6d94dac16..441e98091109ab 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/Binding.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/Binding.java @@ -40,7 +40,7 @@ private native void installFabricUIManager( ComponentFactoryDelegate componentsRegistry, Object reactNativeConfig); - public native void startSurface(int surfaceId, String moduleName, NativeMap initialProps); + public native void startSurface(int surfaceId, NativeMap initialProps); public native void renderTemplateToSurface(int surfaceId, String uiTemplate); diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.cpp index 171935a1aca939..286392d5590b83 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.cpp @@ -45,13 +45,9 @@ jni::local_ref Binding::initHybrid( return makeCxxInstance(); } -void Binding::startSurface( - jint surfaceId, - jni::alias_ref moduleName, - NativeMap *initialProps) { +void Binding::startSurface(jint surfaceId, NativeMap *initialProps) { if (scheduler_) { - scheduler_->startSurface( - surfaceId, moduleName->toStdString(), initialProps->consume()); + scheduler_->startSurface(surfaceId, "", initialProps->consume()); } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.h b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.h index 6981de4937a48d..6486763e7eeca0 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.h +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.h @@ -50,10 +50,7 @@ class Binding : public jni::HybridClass, public SchedulerDelegate { ComponentFactoryDelegate *componentsRegistry, jni::alias_ref reactNativeConfig); - void startSurface( - jint surfaceId, - jni::alias_ref moduleName, - NativeMap *initialProps); + void startSurface(jint surfaceId, NativeMap *initialProps); void renderTemplateToSurface(jint surfaceId, jstring uiTemplate); diff --git a/ReactCommon/fabric/uimanager/Scheduler.cpp b/ReactCommon/fabric/uimanager/Scheduler.cpp index aab1121d9341e8..c4637c1a3d5bed 100644 --- a/ReactCommon/fabric/uimanager/Scheduler.cpp +++ b/ReactCommon/fabric/uimanager/Scheduler.cpp @@ -96,10 +96,12 @@ void Scheduler::startSurface( shadowTreeRegistry_.add(std::move(shadowTree)); +#ifndef ANDROID runtimeExecutor_([=](jsi::Runtime &runtime) { uiManagerBinding_->startSurface( runtime, surfaceId, moduleName, initialProps); }); +#endif } void Scheduler::renderTemplateToSurface( @@ -169,9 +171,11 @@ void Scheduler::stopSurface(SurfaceId surfaceId) const { auto shadowTree = shadowTreeRegistry_.remove(surfaceId); shadowTree->setDelegate(nullptr); +#ifndef ANDROID runtimeExecutor_([=](jsi::Runtime &runtime) { uiManagerBinding_->stopSurface(runtime, surfaceId); }); +#endif } Size Scheduler::measureSurface( diff --git a/ReactCommon/fabric/uimanager/UIManagerBinding.cpp b/ReactCommon/fabric/uimanager/UIManagerBinding.cpp index ac72b2437bef0d..afcb6aff7d45fb 100644 --- a/ReactCommon/fabric/uimanager/UIManagerBinding.cpp +++ b/ReactCommon/fabric/uimanager/UIManagerBinding.cpp @@ -46,25 +46,14 @@ void UIManagerBinding::startSurface( parameters["initialProps"] = initalProps; parameters["fabric"] = true; - if (runtime.global().hasProperty(runtime, "RN$SurfaceRegistry")) { - auto registry = - runtime.global().getPropertyAsObject(runtime, "RN$SurfaceRegistry"); - auto method = registry.getPropertyAsFunction(runtime, "renderSurface"); + auto module = getModule(runtime, "AppRegistry"); + auto method = module.getPropertyAsFunction(runtime, "runApplication"); - method.call( - runtime, - {jsi::String::createFromUtf8(runtime, moduleName), - jsi::valueFromDynamic(runtime, parameters)}); - } else { - auto module = getModule(runtime, "AppRegistry"); - auto method = module.getPropertyAsFunction(runtime, "runApplication"); - - method.callWithThis( - runtime, - module, - {jsi::String::createFromUtf8(runtime, moduleName), - jsi::valueFromDynamic(runtime, parameters)}); - } + method.callWithThis( + runtime, + module, + {jsi::String::createFromUtf8(runtime, moduleName), + jsi::valueFromDynamic(runtime, parameters)}); } void UIManagerBinding::stopSurface(jsi::Runtime &runtime, SurfaceId surfaceId) From cb1a28c859eab0f5c25ecfeee26c4570145c0430 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Fri, 24 May 2019 11:22:09 -0700 Subject: [PATCH 0071/1084] Remove jsi package from fabric android Summary: Refactor of packages of RN Android Reviewed By: JoshuaGross Differential Revision: D15457141 fbshipit-source-id: a291f7e1ca8e0be3e93daf9c34161c8f1fdbafac --- .../src/main/java/com/facebook/react/fabric/BUCK | 3 ++- .../com/facebook/react/fabric/{jsi => }/Binding.java | 5 ++--- .../fabric/{jsi => }/ComponentFactoryDelegate.java | 3 +-- .../react/fabric/{jsi => }/ComponentRegistry.java | 2 +- .../facebook/react/fabric/FabricJSIModuleProvider.java | 10 +++------- .../react/fabric/{jsi => }/FabricSoLoader.java | 2 +- .../com/facebook/react/fabric/FabricUIManager.java | 7 +++---- .../react/fabric/{jsi => }/StateWrapperImpl.java | 2 +- .../react/fabric/{jsi => events}/EventBeatManager.java | 5 ++--- .../fabric/{jsi => events}/EventEmitterWrapper.java | 4 ++-- .../react/fabric/{ => events}/FabricEventEmitter.java | 3 ++- .../react/fabric/{jsi => }/jni/AsyncEventBeat.h | 0 .../java/com/facebook/react/fabric/{jsi => }/jni/BUCK | 0 .../facebook/react/fabric/{jsi => }/jni/Binding.cpp | 0 .../com/facebook/react/fabric/{jsi => }/jni/Binding.h | 4 ++-- .../fabric/{jsi => }/jni/ComponentFactoryDelegate.cpp | 0 .../fabric/{jsi => }/jni/ComponentFactoryDelegate.h | 2 +- .../react/fabric/{jsi => }/jni/EventBeatManager.cpp | 0 .../react/fabric/{jsi => }/jni/EventBeatManager.h | 2 +- .../react/fabric/{jsi => }/jni/EventEmitterWrapper.cpp | 0 .../react/fabric/{jsi => }/jni/EventEmitterWrapper.h | 2 +- .../react/fabric/{jsi => }/jni/NodeStateWrapper.cpp | 0 .../react/fabric/{jsi => }/jni/NodeStateWrapper.h | 0 .../com/facebook/react/fabric/{jsi => }/jni/OnLoad.cpp | 0 .../fabric/{jsi => }/jni/ReactNativeConfigHolder.cpp | 0 .../fabric/{jsi => }/jni/ReactNativeConfigHolder.h | 0 .../react/fabric/{jsi => }/jni/StateWrapperImpl.cpp | 0 .../react/fabric/{jsi => }/jni/StateWrapperImpl.h | 2 +- .../react/fabric/mounting/MountingManager.java | 2 +- .../mountitems/UpdateEventEmitterMountItem.java | 2 +- 30 files changed, 28 insertions(+), 34 deletions(-) rename ReactAndroid/src/main/java/com/facebook/react/fabric/{jsi => }/Binding.java (93%) rename ReactAndroid/src/main/java/com/facebook/react/fabric/{jsi => }/ComponentFactoryDelegate.java (84%) rename ReactAndroid/src/main/java/com/facebook/react/fabric/{jsi => }/ComponentRegistry.java (92%) rename ReactAndroid/src/main/java/com/facebook/react/fabric/{jsi => }/FabricSoLoader.java (96%) rename ReactAndroid/src/main/java/com/facebook/react/fabric/{jsi => }/StateWrapperImpl.java (96%) rename ReactAndroid/src/main/java/com/facebook/react/fabric/{jsi => events}/EventBeatManager.java (91%) rename ReactAndroid/src/main/java/com/facebook/react/fabric/{jsi => events}/EventEmitterWrapper.java (94%) rename ReactAndroid/src/main/java/com/facebook/react/fabric/{ => events}/FabricEventEmitter.java (98%) rename ReactAndroid/src/main/java/com/facebook/react/fabric/{jsi => }/jni/AsyncEventBeat.h (100%) rename ReactAndroid/src/main/java/com/facebook/react/fabric/{jsi => }/jni/BUCK (100%) rename ReactAndroid/src/main/java/com/facebook/react/fabric/{jsi => }/jni/Binding.cpp (100%) rename ReactAndroid/src/main/java/com/facebook/react/fabric/{jsi => }/jni/Binding.h (94%) rename ReactAndroid/src/main/java/com/facebook/react/fabric/{jsi => }/jni/ComponentFactoryDelegate.cpp (100%) rename ReactAndroid/src/main/java/com/facebook/react/fabric/{jsi => }/jni/ComponentFactoryDelegate.h (93%) rename ReactAndroid/src/main/java/com/facebook/react/fabric/{jsi => }/jni/EventBeatManager.cpp (100%) rename ReactAndroid/src/main/java/com/facebook/react/fabric/{jsi => }/jni/EventBeatManager.h (95%) rename ReactAndroid/src/main/java/com/facebook/react/fabric/{jsi => }/jni/EventEmitterWrapper.cpp (100%) rename ReactAndroid/src/main/java/com/facebook/react/fabric/{jsi => }/jni/EventEmitterWrapper.h (92%) rename ReactAndroid/src/main/java/com/facebook/react/fabric/{jsi => }/jni/NodeStateWrapper.cpp (100%) rename ReactAndroid/src/main/java/com/facebook/react/fabric/{jsi => }/jni/NodeStateWrapper.h (100%) rename ReactAndroid/src/main/java/com/facebook/react/fabric/{jsi => }/jni/OnLoad.cpp (100%) rename ReactAndroid/src/main/java/com/facebook/react/fabric/{jsi => }/jni/ReactNativeConfigHolder.cpp (100%) rename ReactAndroid/src/main/java/com/facebook/react/fabric/{jsi => }/jni/ReactNativeConfigHolder.h (100%) rename ReactAndroid/src/main/java/com/facebook/react/fabric/{jsi => }/jni/StateWrapperImpl.cpp (100%) rename ReactAndroid/src/main/java/com/facebook/react/fabric/{jsi => }/jni/StateWrapperImpl.h (93%) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/BUCK b/ReactAndroid/src/main/java/com/facebook/react/fabric/BUCK index 80e09b6a0e713c..a1b3e467e75f36 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/BUCK @@ -4,6 +4,7 @@ rn_android_library( name = "fabric", srcs = glob([ "*.java", + "events/**/*.java", "jsi/*.java", "mounting/**/*.java", ]), @@ -28,7 +29,7 @@ rn_android_library( react_native_target("java/com/facebook/debug/tags:tags"), react_native_target("java/com/facebook/debug/holder:holder"), react_native_target("java/com/facebook/react/bridge:bridge"), - react_native_target("java/com/facebook/react/fabric/jsi/jni:jni"), + react_native_target("java/com/facebook/react/fabric/jni:jni"), react_native_target("java/com/facebook/react:react"), react_native_target("java/com/facebook/react/module/annotations:annotations"), react_native_target("java/com/facebook/react/modules/core:core"), diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/Binding.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/Binding.java similarity index 93% rename from ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/Binding.java rename to ReactAndroid/src/main/java/com/facebook/react/fabric/Binding.java index 441e98091109ab..cd2557a4357af4 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/Binding.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/Binding.java @@ -4,7 +4,7 @@ *

This source code is licensed under the MIT license found in the LICENSE file in the root * directory of this source tree. */ -package com.facebook.react.fabric.jsi; +package com.facebook.react.fabric; import android.annotation.SuppressLint; import com.facebook.jni.HybridData; @@ -12,8 +12,7 @@ import com.facebook.react.bridge.JavaScriptContextHolder; import com.facebook.react.bridge.NativeMap; import com.facebook.react.bridge.queue.MessageQueueThread; -import com.facebook.react.fabric.ReactNativeConfig; -import com.facebook.react.fabric.FabricUIManager; +import com.facebook.react.fabric.events.EventBeatManager; import com.facebook.react.uimanager.PixelUtil; @DoNotStrip diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/ComponentFactoryDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/ComponentFactoryDelegate.java similarity index 84% rename from ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/ComponentFactoryDelegate.java rename to ReactAndroid/src/main/java/com/facebook/react/fabric/ComponentFactoryDelegate.java index b16d2038e5f27c..412cec466fb3f2 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/ComponentFactoryDelegate.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/ComponentFactoryDelegate.java @@ -1,11 +1,10 @@ // Copyright 2004-present Facebook. All Rights Reserved. -package com.facebook.react.fabric.jsi; +package com.facebook.react.fabric; import com.facebook.jni.HybridData; import com.facebook.proguard.annotations.DoNotStrip; import com.facebook.soloader.SoLoader; -import com.facebook.react.fabric.jsi.FabricSoLoader; @DoNotStrip public class ComponentFactoryDelegate { diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/ComponentRegistry.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/ComponentRegistry.java similarity index 92% rename from ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/ComponentRegistry.java rename to ReactAndroid/src/main/java/com/facebook/react/fabric/ComponentRegistry.java index b942af8dc100cd..1f656aefeb96fd 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/ComponentRegistry.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/ComponentRegistry.java @@ -1,6 +1,6 @@ // Copyright 2004-present Facebook. All Rights Reserved. -package com.facebook.react.fabric.jsi; +package com.facebook.react.fabric; import com.facebook.jni.HybridData; import com.facebook.proguard.annotations.DoNotStrip; diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricJSIModuleProvider.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricJSIModuleProvider.java index f83bbd4abd6467..1116f3874307c6 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricJSIModuleProvider.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricJSIModuleProvider.java @@ -6,13 +6,9 @@ import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.UIManager; import com.facebook.react.bridge.queue.MessageQueueThread; -import com.facebook.react.fabric.jsi.Binding; -import com.facebook.react.fabric.jsi.ComponentFactoryDelegate; -import com.facebook.react.fabric.jsi.ComponentRegistry; -import com.facebook.react.fabric.jsi.EventBeatManager; -import com.facebook.react.fabric.jsi.EventEmitterWrapper; -import com.facebook.react.fabric.jsi.FabricSoLoader; -import com.facebook.react.fabric.jsi.StateWrapperImpl; +import com.facebook.react.fabric.events.EventBeatManager; +import com.facebook.react.fabric.events.EventEmitterWrapper; +import com.facebook.react.fabric.events.FabricEventEmitter; import com.facebook.react.fabric.mounting.ContextBasedViewPool; import com.facebook.react.fabric.mounting.LayoutMetricsConversions; import com.facebook.react.fabric.mounting.MountingManager; diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/FabricSoLoader.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricSoLoader.java similarity index 96% rename from ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/FabricSoLoader.java rename to ReactAndroid/src/main/java/com/facebook/react/fabric/FabricSoLoader.java index f84a2ac837572e..f49eb476d3da00 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/FabricSoLoader.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricSoLoader.java @@ -4,7 +4,7 @@ *

This source code is licensed under the MIT license found in the LICENSE file in the root * directory of this source tree. */ -package com.facebook.react.fabric.jsi; +package com.facebook.react.fabric; import static com.facebook.systrace.Systrace.TRACE_TAG_REACT_JAVA_BRIDGE; diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java index 9b9c6f78107b38..880f9a827c92bd 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -35,10 +35,9 @@ import com.facebook.react.bridge.UiThreadUtil; import com.facebook.react.bridge.WritableMap; import com.facebook.react.common.ReactConstants; -import com.facebook.react.fabric.jsi.Binding; -import com.facebook.react.fabric.jsi.EventBeatManager; -import com.facebook.react.fabric.jsi.EventEmitterWrapper; -import com.facebook.react.fabric.jsi.FabricSoLoader; +import com.facebook.react.fabric.events.EventBeatManager; +import com.facebook.react.fabric.events.EventEmitterWrapper; +import com.facebook.react.fabric.events.FabricEventEmitter; import com.facebook.react.fabric.mounting.MountingManager; import com.facebook.react.fabric.mounting.mountitems.BatchMountItem; import com.facebook.react.fabric.mounting.mountitems.CreateMountItem; diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/StateWrapperImpl.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/StateWrapperImpl.java similarity index 96% rename from ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/StateWrapperImpl.java rename to ReactAndroid/src/main/java/com/facebook/react/fabric/StateWrapperImpl.java index b5f459f797da65..a938af35e97935 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/StateWrapperImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/StateWrapperImpl.java @@ -4,7 +4,7 @@ *

This source code is licensed under the MIT license found in the LICENSE file in the root * directory of this source tree. */ -package com.facebook.react.fabric.jsi; +package com.facebook.react.fabric; import android.annotation.SuppressLint; import com.facebook.jni.HybridData; diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/EventBeatManager.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/events/EventBeatManager.java similarity index 91% rename from ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/EventBeatManager.java rename to ReactAndroid/src/main/java/com/facebook/react/fabric/events/EventBeatManager.java index 285a24f8946ffe..f3e6cd4f8e869c 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/EventBeatManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/events/EventBeatManager.java @@ -4,15 +4,14 @@ *

This source code is licensed under the MIT license found in the LICENSE file in the root * directory of this source tree. */ -package com.facebook.react.fabric.jsi; +package com.facebook.react.fabric.events; import android.annotation.SuppressLint; import com.facebook.jni.HybridData; import com.facebook.proguard.annotations.DoNotStrip; -import com.facebook.react.bridge.JavaScriptContextHolder; import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.fabric.FabricSoLoader; import com.facebook.react.uimanager.events.BatchEventDispatchedListener; -import com.facebook.react.fabric.jsi.FabricSoLoader; /** * Class that acts as a proxy between the list of EventBeats registered in C++ and the Android side. diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/EventEmitterWrapper.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/events/EventEmitterWrapper.java similarity index 94% rename from ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/EventEmitterWrapper.java rename to ReactAndroid/src/main/java/com/facebook/react/fabric/events/EventEmitterWrapper.java index 4d5e621ffc1ef0..00d6a1f1205784 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/EventEmitterWrapper.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/events/EventEmitterWrapper.java @@ -4,7 +4,7 @@ *

This source code is licensed under the MIT license found in the LICENSE file in the root * directory of this source tree. */ -package com.facebook.react.fabric.jsi; +package com.facebook.react.fabric.events; import android.annotation.SuppressLint; import androidx.annotation.Nullable; @@ -13,7 +13,7 @@ import com.facebook.react.bridge.NativeMap; import com.facebook.react.bridge.WritableMap; import com.facebook.react.bridge.WritableNativeMap; -import com.facebook.react.fabric.jsi.FabricSoLoader; +import com.facebook.react.fabric.FabricSoLoader; /** * This class holds reference to the C++ EventEmitter object. Instances of this class are created on diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricEventEmitter.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/events/FabricEventEmitter.java similarity index 98% rename from ReactAndroid/src/main/java/com/facebook/react/fabric/FabricEventEmitter.java rename to ReactAndroid/src/main/java/com/facebook/react/fabric/events/FabricEventEmitter.java index c399ac12cda587..f9fa3de0fa8750 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricEventEmitter.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/events/FabricEventEmitter.java @@ -4,7 +4,7 @@ *

This source code is licensed under the MIT license found in the LICENSE file in the root * directory of this source tree. */ -package com.facebook.react.fabric; +package com.facebook.react.fabric.events; import static com.facebook.react.uimanager.events.TouchesHelper.CHANGED_TOUCHES_KEY; import static com.facebook.react.uimanager.events.TouchesHelper.TARGET_KEY; @@ -19,6 +19,7 @@ import com.facebook.react.bridge.WritableMap; import com.facebook.react.bridge.WritableNativeArray; import com.facebook.react.bridge.WritableNativeMap; +import com.facebook.react.fabric.FabricUIManager; import com.facebook.react.uimanager.events.RCTEventEmitter; import com.facebook.systrace.Systrace; import java.util.HashSet; diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/AsyncEventBeat.h b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/AsyncEventBeat.h similarity index 100% rename from ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/AsyncEventBeat.h rename to ReactAndroid/src/main/java/com/facebook/react/fabric/jni/AsyncEventBeat.h diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/BUCK b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/BUCK similarity index 100% rename from ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/BUCK rename to ReactAndroid/src/main/java/com/facebook/react/fabric/jni/BUCK diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp similarity index 100% rename from ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.cpp rename to ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.h b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.h similarity index 94% rename from ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.h rename to ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.h index 6486763e7eeca0..588e94740f8a91 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.h +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.h @@ -21,8 +21,8 @@ class Instance; class Binding : public jni::HybridClass, public SchedulerDelegate { public: - constexpr static const char *const kJavaDescriptor = - "Lcom/facebook/react/fabric/jsi/Binding;"; + constexpr static const char* const kJavaDescriptor = + "Lcom/facebook/react/fabric/Binding;"; static void registerNatives(); diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/ComponentFactoryDelegate.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/ComponentFactoryDelegate.cpp similarity index 100% rename from ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/ComponentFactoryDelegate.cpp rename to ReactAndroid/src/main/java/com/facebook/react/fabric/jni/ComponentFactoryDelegate.cpp diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/ComponentFactoryDelegate.h b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/ComponentFactoryDelegate.h similarity index 93% rename from ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/ComponentFactoryDelegate.h rename to ReactAndroid/src/main/java/com/facebook/react/fabric/jni/ComponentFactoryDelegate.h index a215eac89dd606..c3abdc210ac776 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/ComponentFactoryDelegate.h +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/ComponentFactoryDelegate.h @@ -23,7 +23,7 @@ class ComponentFactoryDelegate : public jni::HybridClass { public: constexpr static const char* const kJavaDescriptor = - "Lcom/facebook/react/fabric/jsi/ComponentFactoryDelegate;"; + "Lcom/facebook/react/fabric/ComponentFactoryDelegate;"; static void registerNatives(); diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/EventBeatManager.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/EventBeatManager.cpp similarity index 100% rename from ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/EventBeatManager.cpp rename to ReactAndroid/src/main/java/com/facebook/react/fabric/jni/EventBeatManager.cpp diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/EventBeatManager.h b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/EventBeatManager.h similarity index 95% rename from ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/EventBeatManager.h rename to ReactAndroid/src/main/java/com/facebook/react/fabric/jni/EventBeatManager.h index 4425bc386f60d9..4fa39139a4db12 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/EventBeatManager.h +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/EventBeatManager.h @@ -21,7 +21,7 @@ class Instance; class EventBeatManager : public jni::HybridClass { public: constexpr static const char* const kJavaDescriptor = - "Lcom/facebook/react/fabric/jsi/EventBeatManager;"; + "Lcom/facebook/react/fabric/events/EventBeatManager;"; static void registerNatives(); diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/EventEmitterWrapper.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/EventEmitterWrapper.cpp similarity index 100% rename from ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/EventEmitterWrapper.cpp rename to ReactAndroid/src/main/java/com/facebook/react/fabric/jni/EventEmitterWrapper.cpp diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/EventEmitterWrapper.h b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/EventEmitterWrapper.h similarity index 92% rename from ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/EventEmitterWrapper.h rename to ReactAndroid/src/main/java/com/facebook/react/fabric/jni/EventEmitterWrapper.h index ce43653eac95f6..cd612ac4d460ab 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/EventEmitterWrapper.h +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/EventEmitterWrapper.h @@ -16,7 +16,7 @@ class Instance; class EventEmitterWrapper : public jni::HybridClass { public: constexpr static const char* const kJavaDescriptor = - "Lcom/facebook/react/fabric/jsi/EventEmitterWrapper;"; + "Lcom/facebook/react/fabric/events/EventEmitterWrapper;"; static void registerNatives(); diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/NodeStateWrapper.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/NodeStateWrapper.cpp similarity index 100% rename from ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/NodeStateWrapper.cpp rename to ReactAndroid/src/main/java/com/facebook/react/fabric/jni/NodeStateWrapper.cpp diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/NodeStateWrapper.h b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/NodeStateWrapper.h similarity index 100% rename from ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/NodeStateWrapper.h rename to ReactAndroid/src/main/java/com/facebook/react/fabric/jni/NodeStateWrapper.h diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/OnLoad.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/OnLoad.cpp similarity index 100% rename from ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/OnLoad.cpp rename to ReactAndroid/src/main/java/com/facebook/react/fabric/jni/OnLoad.cpp diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/ReactNativeConfigHolder.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/ReactNativeConfigHolder.cpp similarity index 100% rename from ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/ReactNativeConfigHolder.cpp rename to ReactAndroid/src/main/java/com/facebook/react/fabric/jni/ReactNativeConfigHolder.cpp diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/ReactNativeConfigHolder.h b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/ReactNativeConfigHolder.h similarity index 100% rename from ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/ReactNativeConfigHolder.h rename to ReactAndroid/src/main/java/com/facebook/react/fabric/jni/ReactNativeConfigHolder.h diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/StateWrapperImpl.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/StateWrapperImpl.cpp similarity index 100% rename from ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/StateWrapperImpl.cpp rename to ReactAndroid/src/main/java/com/facebook/react/fabric/jni/StateWrapperImpl.cpp diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/StateWrapperImpl.h b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/StateWrapperImpl.h similarity index 93% rename from ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/StateWrapperImpl.h rename to ReactAndroid/src/main/java/com/facebook/react/fabric/jni/StateWrapperImpl.h index 82239ef06358da..17fe04e25ef696 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/StateWrapperImpl.h +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/StateWrapperImpl.h @@ -16,7 +16,7 @@ class Instance; class StateWrapperImpl : public jni::HybridClass { public: constexpr static const char* const kJavaDescriptor = - "Lcom/facebook/react/fabric/jsi/StateWrapperImpl;"; + "Lcom/facebook/react/fabric/StateWrapperImpl;"; static void registerNatives(); diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java index 730db1205391f0..5a2bb4924e04a9 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java @@ -20,7 +20,7 @@ import com.facebook.react.bridge.SoftAssertions; import com.facebook.react.bridge.UiThreadUtil; import com.facebook.react.fabric.FabricUIManager; -import com.facebook.react.fabric.jsi.EventEmitterWrapper; +import com.facebook.react.fabric.events.EventEmitterWrapper; import com.facebook.react.fabric.mounting.mountitems.MountItem; import com.facebook.react.uimanager.IllegalViewOperationException; import com.facebook.react.uimanager.ReactStylesDiffMap; diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdateEventEmitterMountItem.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdateEventEmitterMountItem.java index 24dd1b64fe6fa7..9d5f0dc6b85d83 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdateEventEmitterMountItem.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdateEventEmitterMountItem.java @@ -6,7 +6,7 @@ */ package com.facebook.react.fabric.mounting.mountitems; -import com.facebook.react.fabric.jsi.EventEmitterWrapper; +import com.facebook.react.fabric.events.EventEmitterWrapper; import com.facebook.react.fabric.mounting.MountingManager; public class UpdateEventEmitterMountItem implements MountItem { From c629cdc39a2d64b65e40ba550b7b6c8d22bc7065 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Fri, 24 May 2019 11:22:09 -0700 Subject: [PATCH 0072/1084] Remove ComponentRegistry class Summary: This class is not necessary anymore, this diff deletes it from the repo Reviewed By: JoshuaGross Differential Revision: D15457346 fbshipit-source-id: c7293d93b50271efe3b3d2121c128ba6e13c7627 --- .../react/fabric/ComponentRegistry.java | 25 ------------------- .../react/fabric/FabricJSIModuleProvider.java | 1 - 2 files changed, 26 deletions(-) delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/fabric/ComponentRegistry.java diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/ComponentRegistry.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/ComponentRegistry.java deleted file mode 100644 index 1f656aefeb96fd..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/ComponentRegistry.java +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -package com.facebook.react.fabric; - -import com.facebook.jni.HybridData; -import com.facebook.proguard.annotations.DoNotStrip; -import com.facebook.soloader.SoLoader; - -@DoNotStrip -public class ComponentRegistry { - - static { - FabricSoLoader.staticInit(); - } - - private final HybridData mHybridData; - - @DoNotStrip - private static native HybridData initHybrid(); - - public ComponentRegistry() { - mHybridData = initHybrid(); - } - -} diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricJSIModuleProvider.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricJSIModuleProvider.java index 1116f3874307c6..1fde5b7c35c5b1 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricJSIModuleProvider.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricJSIModuleProvider.java @@ -115,7 +115,6 @@ private static void loadClasses() { ViewPool.class.getClass(); Binding.class.getClass(); ComponentFactoryDelegate.class.getClass(); - ComponentRegistry.class.getClass(); EventBeatManager.class.getClass(); EventEmitterWrapper.class.getClass(); StateWrapperImpl.class.getClass(); From cd5fe06abe1b5f00f3e6edda453342266da6d36e Mon Sep 17 00:00:00 2001 From: David Vacca Date: Fri, 24 May 2019 11:22:09 -0700 Subject: [PATCH 0073/1084] Fix bottom sheet in Fabric Android Summary: This diff fixes the rendering of Bottom Sheet in Fabric Android. In D15343702 we added state as part of the "preallocateView" method but we forgot to call viewManager.updateState(), this prevents the state to be updated during the first render. Reviewed By: shergin Differential Revision: D15476042 fbshipit-source-id: cd6fc9bdd178589d2e04f85723425b5e5c3e5a04 --- .../com/facebook/react/fabric/mounting/MountingManager.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java index 5a2bb4924e04a9..43caf8fcfabbf9 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java @@ -193,6 +193,9 @@ public void createView( viewManager = mViewManagerRegistry.get(componentName); view = mViewFactory.getOrCreateView(componentName, propsDiffMap, stateWrapper, themedReactContext); view.setId(reactTag); + if (stateWrapper != null) { + viewManager.updateState(view, stateWrapper); + } } ViewState viewState = new ViewState(reactTag, view, viewManager); From 92f8fd22e2c45f6b8e714a8c50819fc1c7f8568b Mon Sep 17 00:00:00 2001 From: David Vacca Date: Fri, 24 May 2019 11:22:09 -0700 Subject: [PATCH 0074/1084] Optimize the update of state during first render of a View Summary: This is an optimization to avoid transfering updateState instructions twice during the frist render of a view (same a props) Reviewed By: shergin Differential Revision: D15476041 fbshipit-source-id: 8a62035dbbb63c93f86a2f8d217986a325cb1805 --- .../java/com/facebook/react/fabric/jni/Binding.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp index 286392d5590b83..4effb64e1a0fe0 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp @@ -458,6 +458,12 @@ void Binding::schedulerDidFinishTransaction( deletedViewTags.end()) { mountItems[position++] = createUpdatePropsMountItem(javaUIManager_, mutation); + + // State + if (mutation.newChildShadowView.state) { + mountItems[position++] = + createUpdateStateMountItem(javaUIManager_, mutation); + } } // LocalData @@ -472,12 +478,6 @@ void Binding::schedulerDidFinishTransaction( if (updateLayoutMountItem) { mountItems[position++] = updateLayoutMountItem; } - - // State - if (mutation.newChildShadowView.state) { - mountItems[position++] = - createUpdateStateMountItem(javaUIManager_, mutation); - } } // EventEmitter From 6f63b054b604a676df7d6500c4cf84f4d91df95b Mon Sep 17 00:00:00 2001 From: David Vacca Date: Fri, 24 May 2019 11:22:09 -0700 Subject: [PATCH 0075/1084] Add Nullable annotation into Mounting Manager Summary: trivial diff to remove warnings because of the lack of Nullable annotations in MountingManager.ViewState Reviewed By: shergin Differential Revision: D15476040 fbshipit-source-id: 2b9a4efa1be1d5aa29d4e32cf32c8ff502f7c60c --- .../facebook/react/fabric/mounting/MountingManager.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java index 43caf8fcfabbf9..c4e19f27717f7e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java @@ -368,10 +368,10 @@ private static class ViewState { final int mReactTag; final boolean mIsRoot; @Nullable final ViewManager mViewManager; - public ReactStylesDiffMap mCurrentProps = null; - public ReadableMap mCurrentLocalData = null; - public ReadableMap mCurrentState = null; - public EventEmitterWrapper mEventEmitter = null; + @Nullable public ReactStylesDiffMap mCurrentProps = null; + @Nullable public ReadableMap mCurrentLocalData = null; + @Nullable public ReadableMap mCurrentState = null; + @Nullable public EventEmitterWrapper mEventEmitter = null; private ViewState(int reactTag, @Nullable View view, @Nullable ViewManager viewManager) { this(reactTag, view, viewManager, false); From fbc6d8caff3f40996ec8b8918625ef2ed864a824 Mon Sep 17 00:00:00 2001 From: Dulmandakh Date: Fri, 24 May 2019 11:49:03 -0700 Subject: [PATCH 0076/1084] bump android gradle plugin to 3.4.1 (#24883) Summary: bump android gradle plugin to 3.4.1, includes many fixes and improvements. ## Changelog [Android] [Changed] - bump android gradle plugin to 3.4.1 Pull Request resolved: https://github.com/facebook/react-native/pull/24883 Differential Revision: D15474556 Pulled By: hramos fbshipit-source-id: 8d1eb91855b9f416ed3380c61f34672deded26c1 --- build.gradle.kts | 2 +- template/android/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 053621ac4917d2..703d1cc4e794bd 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -10,7 +10,7 @@ buildscript { jcenter() } dependencies { - classpath("com.android.tools.build:gradle:3.4.0") + classpath("com.android.tools.build:gradle:3.4.1") classpath("de.undercouch:gradle-download-task:3.4.3") // NOTE: Do not place your application dependencies here; they belong diff --git a/template/android/build.gradle b/template/android/build.gradle index 99f4104700f2f1..e7732fe0d7232b 100644 --- a/template/android/build.gradle +++ b/template/android/build.gradle @@ -13,7 +13,7 @@ buildscript { jcenter() } dependencies { - classpath("com.android.tools.build:gradle:3.4.0") + classpath("com.android.tools.build:gradle:3.4.1") // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files From e4240da5609f4c8e67ee9ada5572ba86898929e4 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Fri, 24 May 2019 12:10:48 -0700 Subject: [PATCH 0077/1084] Break retain cycle between view component and observer (#25019) Summary: Fixes potential memory leaks. ## Changelog [iOS] [Fixed] - [Fabric] Break retain cycle between view component and observer Pull Request resolved: https://github.com/facebook/react-native/pull/25019 Differential Revision: D15499209 Pulled By: shergin fbshipit-source-id: de53bea5cd5758b9890f3941c39a27d2747bf35b --- React/Fabric/RCTImageResponseObserverProxy.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/React/Fabric/RCTImageResponseObserverProxy.h b/React/Fabric/RCTImageResponseObserverProxy.h index 72a1aa6bf7d482..584dfefaec8915 100644 --- a/React/Fabric/RCTImageResponseObserverProxy.h +++ b/React/Fabric/RCTImageResponseObserverProxy.h @@ -24,7 +24,7 @@ namespace facebook { void didReceiveFailure() override; private: - id delegate_; + __weak id delegate_; }; } } From 0e9c764e28f38442b2aab3942d3fd7b77ee05ea5 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Fri, 24 May 2019 12:20:21 -0700 Subject: [PATCH 0078/1084] Fabric: Passing props as `const &` in RCTComponentViewProtocol Summary: Passing shared pointers as references can save us a couple of milliseconds at scale. Originally, I didn't expect that Objective-C supports passing values by references, but apparently it does. Reviewed By: mdvacca Differential Revision: D15473218 fbshipit-source-id: 15eb3770cc0889654647a8e91607d8aa78010121 --- .../RCTActivityIndicatorViewComponentView.mm | 2 +- .../ComponentViews/Image/RCTImageComponentView.mm | 2 +- .../ScrollView/RCTScrollViewComponentView.mm | 2 +- .../ScrollView/RNPullToRefreshViewComponentView.mm | 11 +++++++---- .../ComponentViews/Slider/RCTSliderComponentView.mm | 2 +- .../ComponentViews/Switch/RCTSwitchComponentView.mm | 2 +- .../ComponentViews/Text/RCTParagraphComponentView.mm | 2 +- .../RCTUnimplementedNativeComponentView.mm | 2 +- .../ComponentViews/View/RCTViewComponentView.h | 4 ++-- .../ComponentViews/View/RCTViewComponentView.mm | 12 +++++------- React/Fabric/Mounting/RCTComponentViewProtocol.h | 3 ++- React/Fabric/Mounting/UIView+ComponentViewProtocol.h | 3 ++- .../Fabric/Mounting/UIView+ComponentViewProtocol.mm | 2 +- 13 files changed, 26 insertions(+), 23 deletions(-) diff --git a/React/Fabric/Mounting/ComponentViews/ActivityIndicator/RCTActivityIndicatorViewComponentView.mm b/React/Fabric/Mounting/ComponentViews/ActivityIndicator/RCTActivityIndicatorViewComponentView.mm index 9f103e93ced184..c1ac244f05fb45 100644 --- a/React/Fabric/Mounting/ComponentViews/ActivityIndicator/RCTActivityIndicatorViewComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/ActivityIndicator/RCTActivityIndicatorViewComponentView.mm @@ -58,7 +58,7 @@ - (instancetype)initWithFrame:(CGRect)frame return self; } -- (void)updateProps:(SharedProps)props oldProps:(SharedProps)oldProps +- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto &oldViewProps = *std::static_pointer_cast(oldProps ?: _props); const auto &newViewProps = *std::static_pointer_cast(props); diff --git a/React/Fabric/Mounting/ComponentViews/Image/RCTImageComponentView.mm b/React/Fabric/Mounting/ComponentViews/Image/RCTImageComponentView.mm index ad8231d4fa06c5..c85e0a8837f4a2 100644 --- a/React/Fabric/Mounting/ComponentViews/Image/RCTImageComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/Image/RCTImageComponentView.mm @@ -50,7 +50,7 @@ + (ComponentDescriptorProvider)componentDescriptorProvider return concreteComponentDescriptorProvider(); } -- (void)updateProps:(SharedProps)props oldProps:(SharedProps)oldProps +- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto &oldImageProps = *std::static_pointer_cast(oldProps ?: _props); const auto &newImageProps = *std::static_pointer_cast(props); diff --git a/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm b/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm index aaeda9b75447c1..bcdeadac928882 100644 --- a/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm @@ -69,7 +69,7 @@ + (ComponentDescriptorProvider)componentDescriptorProvider return concreteComponentDescriptorProvider(); } -- (void)updateProps:(SharedProps)props oldProps:(SharedProps)oldProps +- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto &oldScrollViewProps = *std::static_pointer_cast(oldProps ?: _props); const auto &newScrollViewProps = *std::static_pointer_cast(props); diff --git a/React/Fabric/Mounting/ComponentViews/ScrollView/RNPullToRefreshViewComponentView.mm b/React/Fabric/Mounting/ComponentViews/ScrollView/RNPullToRefreshViewComponentView.mm index c43b2f150f4a7c..44705d83fb2ca6 100644 --- a/React/Fabric/Mounting/ComponentViews/ScrollView/RNPullToRefreshViewComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/ScrollView/RNPullToRefreshViewComponentView.mm @@ -11,8 +11,8 @@ #import #import -#import #import +#import using namespace facebook::react; @@ -33,7 +33,9 @@ - (instancetype)initWithFrame:(CGRect)frame _props = defaultProps; _refreshControl = [[UIRefreshControl alloc] init]; - [_refreshControl addTarget:self action:@selector(handleUIControlEventValueChanged) forControlEvents:UIControlEventValueChanged]; + [_refreshControl addTarget:self + action:@selector(handleUIControlEventValueChanged) + forControlEvents:UIControlEventValueChanged]; } return self; @@ -46,7 +48,7 @@ + (ComponentDescriptorProvider)componentDescriptorProvider return concreteComponentDescriptorProvider(); } -- (void)updateProps:(SharedProps)props oldProps:(SharedProps)oldProps +- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { auto const &oldConcreteProps = *std::static_pointer_cast(oldProps ?: _props); auto const &newConcreteProps = *std::static_pointer_cast(props); @@ -97,7 +99,8 @@ - (void)_updateTitle attributes[NSForegroundColorAttributeName] = RCTUIColorFromSharedColor(concreteProps.titleColor); } - _refreshControl.attributedTitle = [[NSAttributedString alloc] initWithString:RCTNSStringFromString(concreteProps.title) attributes:attributes]; + _refreshControl.attributedTitle = + [[NSAttributedString alloc] initWithString:RCTNSStringFromString(concreteProps.title) attributes:attributes]; } #pragma mark - Attaching & Detaching diff --git a/React/Fabric/Mounting/ComponentViews/Slider/RCTSliderComponentView.mm b/React/Fabric/Mounting/ComponentViews/Slider/RCTSliderComponentView.mm index f71ab528394717..30dcb94563840d 100644 --- a/React/Fabric/Mounting/ComponentViews/Slider/RCTSliderComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/Slider/RCTSliderComponentView.mm @@ -107,7 +107,7 @@ + (ComponentDescriptorProvider)componentDescriptorProvider return concreteComponentDescriptorProvider(); } -- (void)updateProps:(SharedProps)props oldProps:(SharedProps)oldProps +- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto &oldSliderProps = *std::static_pointer_cast(oldProps ?: _props); const auto &newSliderProps = *std::static_pointer_cast(props); diff --git a/React/Fabric/Mounting/ComponentViews/Switch/RCTSwitchComponentView.mm b/React/Fabric/Mounting/ComponentViews/Switch/RCTSwitchComponentView.mm index 2857748dab8a36..24a84a5dfda965 100644 --- a/React/Fabric/Mounting/ComponentViews/Switch/RCTSwitchComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/Switch/RCTSwitchComponentView.mm @@ -43,7 +43,7 @@ + (ComponentDescriptorProvider)componentDescriptorProvider return concreteComponentDescriptorProvider(); } -- (void)updateProps:(SharedProps)props oldProps:(SharedProps)oldProps +- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto &oldSwitchProps = *std::static_pointer_cast(oldProps ?: _props); const auto &newSwitchProps = *std::static_pointer_cast(props); diff --git a/React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm b/React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm index 9a64f5c30dce93..1da31b99f15f8f 100644 --- a/React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm @@ -53,7 +53,7 @@ + (ComponentDescriptorProvider)componentDescriptorProvider concreteComponentDescriptorProvider()}; } -- (void)updateProps:(SharedProps)props oldProps:(SharedProps)oldProps +- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto ¶graphProps = std::static_pointer_cast(props); diff --git a/React/Fabric/Mounting/ComponentViews/UnimplementedComponent/RCTUnimplementedNativeComponentView.mm b/React/Fabric/Mounting/ComponentViews/UnimplementedComponent/RCTUnimplementedNativeComponentView.mm index bf5fdd1e70950c..f231a2d2eae7b2 100644 --- a/React/Fabric/Mounting/ComponentViews/UnimplementedComponent/RCTUnimplementedNativeComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/UnimplementedComponent/RCTUnimplementedNativeComponentView.mm @@ -45,7 +45,7 @@ + (ComponentDescriptorProvider)componentDescriptorProvider return concreteComponentDescriptorProvider(); } -- (void)updateProps:(SharedProps)props oldProps:(SharedProps)oldProps +- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { const auto &oldViewProps = *std::static_pointer_cast(oldProps ?: _props); const auto &newViewProps = *std::static_pointer_cast(props); diff --git a/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.h b/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.h index 9cd1cbf3a63ccb..d8593c0c362b3a 100644 --- a/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.h +++ b/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.h @@ -71,8 +71,8 @@ NS_ASSUME_NONNULL_BEGIN /** * Enforcing `call super` semantic for overridden methods from `RCTComponentViewProtocol`. */ -- (void)updateProps:(facebook::react::SharedProps)props - oldProps:(facebook::react::SharedProps)oldProps NS_REQUIRES_SUPER; +- (void)updateProps:(facebook::react::Props::Shared const &)props + oldProps:(facebook::react::Props::Shared const &)oldProps NS_REQUIRES_SUPER; - (void)updateEventEmitter:(facebook::react::SharedEventEmitter)eventEmitter NS_REQUIRES_SUPER; - (void)updateLayoutMetrics:(facebook::react::LayoutMetrics)layoutMetrics oldLayoutMetrics:(facebook::react::LayoutMetrics)oldLayoutMetrics NS_REQUIRES_SUPER; diff --git a/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm b/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm index 39425793a0fc01..c723fdd63a77cf 100644 --- a/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm @@ -94,7 +94,7 @@ + (ComponentDescriptorProvider)componentDescriptorProvider return concreteComponentDescriptorProvider(); } -- (void)updateProps:(SharedProps)props oldProps:(SharedProps)oldProps +- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { #ifndef NS_BLOCK_ASSERTIONS auto propsRawPtr = _props.get(); @@ -332,12 +332,10 @@ static RCTCornerRadii RCTCornerRadiiFromBorderRadii(BorderRadii borderRadii) static RCTBorderColors RCTBorderColorsFromBorderColors(BorderColors borderColors) { - return RCTBorderColors{ - .left = RCTCGColorRefUnretainedFromSharedColor(borderColors.left), - .top = RCTCGColorRefUnretainedFromSharedColor(borderColors.top), - .bottom = RCTCGColorRefUnretainedFromSharedColor(borderColors.bottom), - .right = RCTCGColorRefUnretainedFromSharedColor(borderColors.right) - }; + return RCTBorderColors{.left = RCTCGColorRefUnretainedFromSharedColor(borderColors.left), + .top = RCTCGColorRefUnretainedFromSharedColor(borderColors.top), + .bottom = RCTCGColorRefUnretainedFromSharedColor(borderColors.bottom), + .right = RCTCGColorRefUnretainedFromSharedColor(borderColors.right)}; } static UIEdgeInsets UIEdgeInsetsFromBorderInsets(EdgeInsets edgeInsets) diff --git a/React/Fabric/Mounting/RCTComponentViewProtocol.h b/React/Fabric/Mounting/RCTComponentViewProtocol.h index e5e1c6a5c06a45..0269217bdafb22 100644 --- a/React/Fabric/Mounting/RCTComponentViewProtocol.h +++ b/React/Fabric/Mounting/RCTComponentViewProtocol.h @@ -70,7 +70,8 @@ typedef NS_OPTIONS(NSInteger, RNComponentViewUpdateMask) { * Called for updating component's props. * Receiver must update native view props accordingly changed props. */ -- (void)updateProps:(facebook::react::SharedProps)props oldProps:(facebook::react::SharedProps)oldProps; +- (void)updateProps:(facebook::react::Props::Shared const &)props + oldProps:(facebook::react::Props::Shared const &)oldProps; /* * Called for updating component's local data. diff --git a/React/Fabric/Mounting/UIView+ComponentViewProtocol.h b/React/Fabric/Mounting/UIView+ComponentViewProtocol.h index 35bb307da1ea5f..831708f2f49969 100644 --- a/React/Fabric/Mounting/UIView+ComponentViewProtocol.h +++ b/React/Fabric/Mounting/UIView+ComponentViewProtocol.h @@ -22,7 +22,8 @@ NS_ASSUME_NONNULL_BEGIN - (void)unmountChildComponentView:(UIView *)childComponentView index:(NSInteger)index; -- (void)updateProps:(facebook::react::SharedProps)props oldProps:(facebook::react::SharedProps)oldProps; +- (void)updateProps:(facebook::react::Props::Shared const &)props + oldProps:(facebook::react::Props::Shared const &)oldProps; - (void)updateEventEmitter:(facebook::react::SharedEventEmitter)eventEmitter; diff --git a/React/Fabric/Mounting/UIView+ComponentViewProtocol.mm b/React/Fabric/Mounting/UIView+ComponentViewProtocol.mm index 6d25817c091fc3..db23fecf50bf1d 100644 --- a/React/Fabric/Mounting/UIView+ComponentViewProtocol.mm +++ b/React/Fabric/Mounting/UIView+ComponentViewProtocol.mm @@ -39,7 +39,7 @@ - (void)unmountChildComponentView:(UIView *)childCompo [childComponentView removeFromSuperview]; } -- (void)updateProps:(SharedProps)props oldProps:(SharedProps)oldProps +- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps { // Default implementation does nothing. } From f4a01026425e26af09db36192cd72e9f3b22fd61 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Fri, 24 May 2019 12:20:21 -0700 Subject: [PATCH 0079/1084] Fabric: Using `const &` in all other appropriate parts of RCTComponentViewProtocol Summary: Same as previous one but for the rest (minority) of methods. I didn't change `updateLocalData:` because it's going away soon anyway. Reviewed By: mdvacca Differential Revision: D15473217 fbshipit-source-id: 6a6bd66c5343211a973fc34ad11e86efe031d07d --- .../ScrollView/RCTScrollViewComponentView.mm | 2 +- .../Mounting/ComponentViews/View/RCTViewComponentView.h | 6 +++--- .../Mounting/ComponentViews/View/RCTViewComponentView.mm | 5 +++-- React/Fabric/Mounting/RCTComponentViewProtocol.h | 9 +++++---- React/Fabric/Mounting/UIView+ComponentViewProtocol.h | 9 +++++---- React/Fabric/Mounting/UIView+ComponentViewProtocol.mm | 8 +++++--- 6 files changed, 22 insertions(+), 17 deletions(-) diff --git a/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm b/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm index bcdeadac928882..87350b07b8e301 100644 --- a/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm @@ -115,7 +115,7 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const & // MAP_SCROLL_VIEW_PROP(snapToAlignment); } -- (void)updateState:(State::Shared)state oldState:(State::Shared)oldState +- (void)updateState:(State::Shared const &)state oldState:(State::Shared const &)oldState { assert(std::dynamic_pointer_cast(state)); _state = std::static_pointer_cast(state); diff --git a/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.h b/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.h index d8593c0c362b3a..9d91ebb73df315 100644 --- a/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.h +++ b/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.h @@ -73,9 +73,9 @@ NS_ASSUME_NONNULL_BEGIN */ - (void)updateProps:(facebook::react::Props::Shared const &)props oldProps:(facebook::react::Props::Shared const &)oldProps NS_REQUIRES_SUPER; -- (void)updateEventEmitter:(facebook::react::SharedEventEmitter)eventEmitter NS_REQUIRES_SUPER; -- (void)updateLayoutMetrics:(facebook::react::LayoutMetrics)layoutMetrics - oldLayoutMetrics:(facebook::react::LayoutMetrics)oldLayoutMetrics NS_REQUIRES_SUPER; +- (void)updateEventEmitter:(facebook::react::EventEmitter::Shared const &)eventEmitter NS_REQUIRES_SUPER; +- (void)updateLayoutMetrics:(facebook::react::LayoutMetrics const &)layoutMetrics + oldLayoutMetrics:(facebook::react::LayoutMetrics const &)oldLayoutMetrics NS_REQUIRES_SUPER; - (void)finalizeUpdates:(RNComponentViewUpdateMask)updateMask NS_REQUIRES_SUPER; - (void)prepareForRecycle NS_REQUIRES_SUPER; diff --git a/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm b/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm index c723fdd63a77cf..22921328b0288c 100644 --- a/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm @@ -243,13 +243,14 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const & _needsInvalidateLayer = _needsInvalidateLayer || needsInvalidateLayer; } -- (void)updateEventEmitter:(SharedEventEmitter)eventEmitter +- (void)updateEventEmitter:(EventEmitter::Shared const &)eventEmitter { assert(std::dynamic_pointer_cast(eventEmitter)); _eventEmitter = std::static_pointer_cast(eventEmitter); } -- (void)updateLayoutMetrics:(LayoutMetrics)layoutMetrics oldLayoutMetrics:(LayoutMetrics)oldLayoutMetrics +- (void)updateLayoutMetrics:(LayoutMetrics const &)layoutMetrics + oldLayoutMetrics:(LayoutMetrics const &)oldLayoutMetrics { [super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:oldLayoutMetrics]; diff --git a/React/Fabric/Mounting/RCTComponentViewProtocol.h b/React/Fabric/Mounting/RCTComponentViewProtocol.h index 0269217bdafb22..e2301348dc4ce2 100644 --- a/React/Fabric/Mounting/RCTComponentViewProtocol.h +++ b/React/Fabric/Mounting/RCTComponentViewProtocol.h @@ -84,22 +84,23 @@ typedef NS_OPTIONS(NSInteger, RNComponentViewUpdateMask) { * Called for updating component's state. * Receiver must update native view according to changed state. */ -- (void)updateState:(facebook::react::State::Shared)state oldState:(facebook::react::State::Shared)oldState; +- (void)updateState:(facebook::react::State::Shared const &)state + oldState:(facebook::react::State::Shared const &)oldState; /* * Called for updating component's event handlers set. * Receiver must cache `eventEmitter` object inside and use it for emitting * events when needed. */ -- (void)updateEventEmitter:(facebook::react::SharedEventEmitter)eventEmitter; +- (void)updateEventEmitter:(facebook::react::EventEmitter::Shared const &)eventEmitter; /* * Called for updating component's layout metrics. * Receiver must update `UIView` layout-related fields (such as `frame`, * `bounds`, `layer.zPosition`, and so on) accordingly. */ -- (void)updateLayoutMetrics:(facebook::react::LayoutMetrics)layoutMetrics - oldLayoutMetrics:(facebook::react::LayoutMetrics)oldLayoutMetrics; +- (void)updateLayoutMetrics:(facebook::react::LayoutMetrics const &)layoutMetrics + oldLayoutMetrics:(facebook::react::LayoutMetrics const &)oldLayoutMetrics; /* * Called right after all update methods were called for a particular component view. diff --git a/React/Fabric/Mounting/UIView+ComponentViewProtocol.h b/React/Fabric/Mounting/UIView+ComponentViewProtocol.h index 831708f2f49969..ac46d801c6c54f 100644 --- a/React/Fabric/Mounting/UIView+ComponentViewProtocol.h +++ b/React/Fabric/Mounting/UIView+ComponentViewProtocol.h @@ -25,15 +25,16 @@ NS_ASSUME_NONNULL_BEGIN - (void)updateProps:(facebook::react::Props::Shared const &)props oldProps:(facebook::react::Props::Shared const &)oldProps; -- (void)updateEventEmitter:(facebook::react::SharedEventEmitter)eventEmitter; +- (void)updateEventEmitter:(facebook::react::EventEmitter::Shared const &)eventEmitter; - (void)updateLocalData:(facebook::react::SharedLocalData)localData oldLocalData:(facebook::react::SharedLocalData)oldLocalData; -- (void)updateState:(facebook::react::State::Shared)state oldState:(facebook::react::State::Shared)oldState; +- (void)updateState:(facebook::react::State::Shared const &)state + oldState:(facebook::react::State::Shared const &)oldState; -- (void)updateLayoutMetrics:(facebook::react::LayoutMetrics)layoutMetrics - oldLayoutMetrics:(facebook::react::LayoutMetrics)oldLayoutMetrics; +- (void)updateLayoutMetrics:(facebook::react::LayoutMetrics const &)layoutMetrics + oldLayoutMetrics:(facebook::react::LayoutMetrics const &)oldLayoutMetrics; - (void)finalizeUpdates:(RNComponentViewUpdateMask)updateMask; diff --git a/React/Fabric/Mounting/UIView+ComponentViewProtocol.mm b/React/Fabric/Mounting/UIView+ComponentViewProtocol.mm index db23fecf50bf1d..a6f5f240e437c8 100644 --- a/React/Fabric/Mounting/UIView+ComponentViewProtocol.mm +++ b/React/Fabric/Mounting/UIView+ComponentViewProtocol.mm @@ -44,7 +44,7 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const & // Default implementation does nothing. } -- (void)updateEventEmitter:(SharedEventEmitter)eventEmitter +- (void)updateEventEmitter:(EventEmitter::Shared const &)eventEmitter { // Default implementation does nothing. } @@ -54,12 +54,14 @@ - (void)updateLocalData:(SharedLocalData)localData oldLocalData:(SharedLocalData // Default implementation does nothing. } -- (void)updateState:(facebook::react::State::Shared)state oldState:(facebook::react::State::Shared)oldState +- (void)updateState:(facebook::react::State::Shared const &)state + oldState:(facebook::react::State::Shared const &)oldState { // Default implementation does nothing. } -- (void)updateLayoutMetrics:(LayoutMetrics)layoutMetrics oldLayoutMetrics:(LayoutMetrics)oldLayoutMetrics +- (void)updateLayoutMetrics:(LayoutMetrics const &)layoutMetrics + oldLayoutMetrics:(LayoutMetrics const &)oldLayoutMetrics { if (layoutMetrics.frame != oldLayoutMetrics.frame) { CGRect frame = RCTCGRectFromRect(layoutMetrics.frame); From 6dbd809df5b3b26bd504797084336c279b724a39 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Fri, 24 May 2019 12:20:21 -0700 Subject: [PATCH 0080/1084] Fabric: Support for debug printing `std::unordered_set<>` Summary: Quite trivial. Reviewed By: mdvacca Differential Revision: D15498190 fbshipit-source-id: 512c121c6629e65bef7dd0c86898506e0fe861a9 --- .../fabric/debug/DebugStringConvertible.h | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/ReactCommon/fabric/debug/DebugStringConvertible.h b/ReactCommon/fabric/debug/DebugStringConvertible.h index 2767f92d2e9e88..d3e96a3ea88142 100644 --- a/ReactCommon/fabric/debug/DebugStringConvertible.h +++ b/ReactCommon/fabric/debug/DebugStringConvertible.h @@ -11,6 +11,7 @@ #include #include #include +#include namespace facebook { namespace react { @@ -285,13 +286,26 @@ inline std::string getDebugDescription( } // `std::vector` -template -std::string getDebugName(std::vector const &vector) { +template +std::string getDebugName(std::vector const &vector) { return "List"; } -template -std::vector getDebugChildren(std::vector const &vector) { +template +std::vector getDebugChildren(std::vector const &vector) { + return vector; +} + +// `std::unordered_set` +template +std::string getDebugName(std::unordered_set const &set) { + return "Set"; +} + +template +std::vector getDebugChildren(std::unordered_set const &set) { + auto vector = std::vector{}; + vector.insert(vector.end(), set.begin(), set.end()); return vector; } From 83f23982ca165338af814785f94598a63cd69f43 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Fri, 24 May 2019 12:20:21 -0700 Subject: [PATCH 0081/1084] Fabric: Touch and TouchEvent got own files and support for debug printing Summary: That's essential for debugging touch events. Reviewed By: mdvacca Differential Revision: D15498192 fbshipit-source-id: 4a8e0a2b84a1935722518fdce03c10ba277f5702 --- ReactCommon/fabric/components/view/Touch.cpp | 36 ++++++ ReactCommon/fabric/components/view/Touch.h | 88 +++++++++++++++ .../fabric/components/view/TouchEvent.cpp | 33 ++++++ .../fabric/components/view/TouchEvent.h | 54 +++++++++ .../components/view/TouchEventEmitter.cpp | 22 ++-- .../components/view/TouchEventEmitter.h | 105 ++---------------- .../fabric/components/view/ViewEventEmitter.h | 1 + 7 files changed, 234 insertions(+), 105 deletions(-) create mode 100644 ReactCommon/fabric/components/view/Touch.cpp create mode 100644 ReactCommon/fabric/components/view/Touch.h create mode 100644 ReactCommon/fabric/components/view/TouchEvent.cpp create mode 100644 ReactCommon/fabric/components/view/TouchEvent.h diff --git a/ReactCommon/fabric/components/view/Touch.cpp b/ReactCommon/fabric/components/view/Touch.cpp new file mode 100644 index 00000000000000..c5f54821a7c101 --- /dev/null +++ b/ReactCommon/fabric/components/view/Touch.cpp @@ -0,0 +1,36 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "Touch.h" + +namespace facebook { +namespace react { + +#if RN_DEBUG_STRING_CONVERTIBLE + +std::string getDebugName(Touch const &touch) { + return "Touch"; +} + +std::vector getDebugProps( + Touch const &touch, + DebugStringConvertibleOptions options) { + return { + {"pagePoint", getDebugDescription(touch.pagePoint, options)}, + {"offsetPoint", getDebugDescription(touch.offsetPoint, options)}, + {"screenPoint", getDebugDescription(touch.screenPoint, options)}, + {"identifier", getDebugDescription(touch.identifier, options)}, + {"target", getDebugDescription(touch.target, options)}, + {"force", getDebugDescription(touch.force, options)}, + {"timestamp", getDebugDescription(touch.timestamp, options)}, + }; +} + +#endif + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/components/view/Touch.h b/ReactCommon/fabric/components/view/Touch.h new file mode 100644 index 00000000000000..fa3d3bc4708cfd --- /dev/null +++ b/ReactCommon/fabric/components/view/Touch.h @@ -0,0 +1,88 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +#pragma once + +#include +#include +#include + +namespace facebook { +namespace react { + +/* + * Describes an individual touch point for a touch event. + * See https://www.w3.org/TR/touch-events/ for more details. + */ +struct Touch { + /* + * The coordinate of point relative to the root component in points. + */ + Point pagePoint; + + /* + * The coordinate of point relative to the target component in points. + */ + Point offsetPoint; + + /* + * The coordinate of point relative to the screen component in points. + */ + Point screenPoint; + + /* + * An identification number for each touch point. + */ + int identifier; + + /* + * The tag of a component on which the touch point started when it was first + * placed on the surface, even if the touch point has since moved outside the + * interactive area of that element. + */ + Tag target; + + /* + * The force of the touch. + */ + Float force; + + /* + * The time in seconds when the touch occurred or when it was last mutated. + */ + Float timestamp; + + /* + * The particular implementation of `Hasher` and (especially) `Comparator` + * make sense only when `Touch` object is used as a *key* in indexed + * collections. Because of that they are expressed as separate classes. + */ + struct Hasher { + size_t operator()(Touch const &touch) const { + return std::hash()(touch.identifier); + } + }; + + struct Comparator { + bool operator()(Touch const &lhs, Touch const &rhs) const { + return lhs.identifier == rhs.identifier; + } + }; +}; + +using Touches = std::unordered_set; + +#if RN_DEBUG_STRING_CONVERTIBLE + +std::string getDebugName(Touch const &touch); +std::vector getDebugProps( + Touch const &object, + DebugStringConvertibleOptions options = {}); + +#endif + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/components/view/TouchEvent.cpp b/ReactCommon/fabric/components/view/TouchEvent.cpp new file mode 100644 index 00000000000000..f32fd058a4f964 --- /dev/null +++ b/ReactCommon/fabric/components/view/TouchEvent.cpp @@ -0,0 +1,33 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "TouchEvent.h" + +namespace facebook { +namespace react { + +#if RN_DEBUG_STRING_CONVERTIBLE + +std::string getDebugName(TouchEvent const &touchEvent) { + return "TouchEvent"; +} + +std::vector getDebugProps( + TouchEvent const &touchEvent, + DebugStringConvertibleOptions options) { + + return { + {"touches", getDebugDescription(touchEvent.touches, options)}, + {"changedTouches", getDebugDescription(touchEvent.changedTouches, options)}, + {"targetTouches", getDebugDescription(touchEvent.targetTouches, options)}, + }; +} + +#endif + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/components/view/TouchEvent.h b/ReactCommon/fabric/components/view/TouchEvent.h new file mode 100644 index 00000000000000..dc11bbb0a91c27 --- /dev/null +++ b/ReactCommon/fabric/components/view/TouchEvent.h @@ -0,0 +1,54 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +#pragma once + +#include + +#include + +#include + +namespace facebook { +namespace react { + +using Touches = std::unordered_set; + +/* + * Defines the `touchstart`, `touchend`, `touchmove`, and `touchcancel` event + * types. + */ +struct TouchEvent { + /* + * A list of Touches for every point of contact currently touching the + * surface. + */ + Touches touches; + + /* + * A list of Touches for every point of contact which contributed to the + * event. + */ + Touches changedTouches; + + /* + * A list of Touches for every point of contact that is touching the surface + * and started on the element that is the target of the current event. + */ + Touches targetTouches; +}; + +#if RN_DEBUG_STRING_CONVERTIBLE + +std::string getDebugName(TouchEvent const &touchEvent); +std::vector getDebugProps( + TouchEvent const &touchEvent, + DebugStringConvertibleOptions options = {}); + +#endif + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/components/view/TouchEventEmitter.cpp b/ReactCommon/fabric/components/view/TouchEventEmitter.cpp index ded95e1ff91ea0..dcfb1bd0ea0b30 100644 --- a/ReactCommon/fabric/components/view/TouchEventEmitter.cpp +++ b/ReactCommon/fabric/components/view/TouchEventEmitter.cpp @@ -12,7 +12,7 @@ namespace react { #pragma mark - Touches -static jsi::Value touchPayload(jsi::Runtime &runtime, const Touch &touch) { +static jsi::Value touchPayload(jsi::Runtime &runtime, Touch const &touch) { auto object = jsi::Object(runtime); object.setProperty(runtime, "locationX", touch.offsetPoint.x); object.setProperty(runtime, "locationY", touch.offsetPoint.y); @@ -29,10 +29,10 @@ static jsi::Value touchPayload(jsi::Runtime &runtime, const Touch &touch) { static jsi::Value touchesPayload( jsi::Runtime &runtime, - const Touches &touches) { + Touches const &touches) { auto array = jsi::Array(runtime, touches.size()); int i = 0; - for (const auto &touch : touches) { + for (auto const &touch : touches) { array.setValueAtIndex(runtime, i++, touchPayload(runtime, touch)); } return array; @@ -40,7 +40,7 @@ static jsi::Value touchesPayload( static jsi::Value touchEventPayload( jsi::Runtime &runtime, - const TouchEvent &event) { + TouchEvent const &event) { auto object = jsi::Object(runtime); object.setProperty( runtime, "touches", touchesPayload(runtime, event.touches)); @@ -52,9 +52,9 @@ static jsi::Value touchEventPayload( } void TouchEventEmitter::dispatchTouchEvent( - const std::string &type, - const TouchEvent &event, - const EventPriority &priority) const { + std::string const &type, + TouchEvent const &event, + EventPriority const &priority) const { dispatchEvent( type, [event](jsi::Runtime &runtime) { @@ -63,19 +63,19 @@ void TouchEventEmitter::dispatchTouchEvent( priority); } -void TouchEventEmitter::onTouchStart(const TouchEvent &event) const { +void TouchEventEmitter::onTouchStart(TouchEvent const &event) const { dispatchTouchEvent("touchStart", event, EventPriority::SynchronousUnbatched); } -void TouchEventEmitter::onTouchMove(const TouchEvent &event) const { +void TouchEventEmitter::onTouchMove(TouchEvent const &event) const { dispatchTouchEvent("touchMove", event, EventPriority::SynchronousBatched); } -void TouchEventEmitter::onTouchEnd(const TouchEvent &event) const { +void TouchEventEmitter::onTouchEnd(TouchEvent const &event) const { dispatchTouchEvent("touchEnd", event, EventPriority::SynchronousBatched); } -void TouchEventEmitter::onTouchCancel(const TouchEvent &event) const { +void TouchEventEmitter::onTouchCancel(TouchEvent const &event) const { dispatchTouchEvent("touchCancel", event, EventPriority::SynchronousBatched); } diff --git a/ReactCommon/fabric/components/view/TouchEventEmitter.h b/ReactCommon/fabric/components/view/TouchEventEmitter.h index 9edfd51c76e4dc..3192a31e85da0b 100644 --- a/ReactCommon/fabric/components/view/TouchEventEmitter.h +++ b/ReactCommon/fabric/components/view/TouchEventEmitter.h @@ -9,113 +9,30 @@ #include #include #include +#include +#include namespace facebook { namespace react { -/* - * Describes an individual touch point for a touch event. - * See https://www.w3.org/TR/touch-events/ for more details. - */ -struct Touch { - /* - * The coordinate of point relative to the root component in points. - */ - Point pagePoint; - - /* - * The coordinate of point relative to the target component in points. - */ - Point offsetPoint; - - /* - * The coordinate of point relative to the screen component in points. - */ - Point screenPoint; - - /* - * An identification number for each touch point. - */ - int identifier; - - /* - * The tag of a component on which the touch point started when it was first - * placed on the surface, even if the touch point has since moved outside the - * interactive area of that element. - */ - Tag target; - - /* - * The force of the touch. - */ - Float force; - - /* - * The time in seconds when the touch occurred or when it was last mutated. - */ - Float timestamp; - - /* - * The particular implementation of `Hasher` and (especially) `Comparator` - * make sense only when `Touch` object is used as a *key* in indexed - * collections. Because of that they are expressed as separate classes. - */ - struct Hasher { - size_t operator()(const Touch &touch) const { - return std::hash()(touch.identifier); - } - }; - - struct Comparator { - bool operator()(const Touch &lhs, const Touch &rhs) const { - return lhs.identifier == rhs.identifier; - } - }; -}; - -using Touches = std::unordered_set; - -/* - * Defines the `touchstart`, `touchend`, `touchmove`, and `touchcancel` event - * types. - */ -struct TouchEvent { - /* - * A list of Touches for every point of contact currently touching the - * surface. - */ - Touches touches; - - /* - * A list of Touches for every point of contact which contributed to the - * event. - */ - Touches changedTouches; - - /* - * A list of Touches for every point of contact that is touching the surface - * and started on the element that is the target of the current event. - */ - Touches targetTouches; -}; - class TouchEventEmitter; -using SharedTouchEventEmitter = std::shared_ptr; + +using SharedTouchEventEmitter = std::shared_ptr; class TouchEventEmitter : public EventEmitter { public: using EventEmitter::EventEmitter; - void onTouchStart(const TouchEvent &event) const; - void onTouchMove(const TouchEvent &event) const; - void onTouchEnd(const TouchEvent &event) const; - void onTouchCancel(const TouchEvent &event) const; + void onTouchStart(TouchEvent const &event) const; + void onTouchMove(TouchEvent const &event) const; + void onTouchEnd(TouchEvent const &event) const; + void onTouchCancel(TouchEvent const &event) const; private: void dispatchTouchEvent( - const std::string &type, - const TouchEvent &event, - const EventPriority &priority) const; + std::string const &type, + TouchEvent const &event, + EventPriority const &priority) const; }; } // namespace react diff --git a/ReactCommon/fabric/components/view/ViewEventEmitter.h b/ReactCommon/fabric/components/view/ViewEventEmitter.h index e16b4f98cbbe71..4ccd2735b62c14 100644 --- a/ReactCommon/fabric/components/view/ViewEventEmitter.h +++ b/ReactCommon/fabric/components/view/ViewEventEmitter.h @@ -10,6 +10,7 @@ #include #include + #include "TouchEventEmitter.h" namespace facebook { From 9990010b2c5eefa8e9b8fca22b4b387f4aa90ad5 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Fri, 24 May 2019 12:20:21 -0700 Subject: [PATCH 0082/1084] Fabric: Disabling sync and unbatched event queues Summary: We are not sure yet how exactly this should work semantically (e.g. should unbatched events flash previously dispatched batched or not). So, let's disable that until we have all answers. Reviewed By: mdvacca Differential Revision: D15498191 fbshipit-source-id: 77f07c5e86bfbfd212505df8cc6530e39531b5ef --- ReactCommon/fabric/core/events/EventDispatcher.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/ReactCommon/fabric/core/events/EventDispatcher.cpp b/ReactCommon/fabric/core/events/EventDispatcher.cpp index ea08e6d8bb7ecb..00c7dbd5a3214b 100644 --- a/ReactCommon/fabric/core/events/EventDispatcher.cpp +++ b/ReactCommon/fabric/core/events/EventDispatcher.cpp @@ -58,15 +58,7 @@ void EventDispatcher::dispatchStateUpdate( const EventQueue &EventDispatcher::getEventQueue(EventPriority priority) const { #ifdef REACT_FABRIC_SYNC_EVENT_DISPATCHING_DISABLED - // Synchronous dispatch works, but JavaScript interop layer does not have - // proper synchonization yet and it crashes. - if (priority == EventPriority::SynchronousUnbatched) { - priority = EventPriority::AsynchronousUnbatched; - } - - if (priority == EventPriority::SynchronousBatched) { - priority = EventPriority::AsynchronousBatched; - } + priority = EventPriority::AsynchronousBatched; #endif return *eventQueues_[(int)priority]; From 141a3041e0dab68c538375e398ac6a3cfb488256 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Fri, 24 May 2019 14:03:07 -0700 Subject: [PATCH 0083/1084] Fixes wrong headers import (#25002) Summary: Issue imported from https://github.com/facebook/react-native/commit/e1102b43ff2f4757f48c71ade316c81c0b352345 for Android TM support. Fixes wrong headers import in iOS. ## Changelog [iOS] [Fixed] - [TM] Fixes wrong headers import Pull Request resolved: https://github.com/facebook/react-native/pull/25002 Differential Revision: D15501594 Pulled By: cpojer fbshipit-source-id: 45ea2986963ff4937c473464f0befc1f5bcfe115 --- RNTester/RNTester/RNTesterTurboModuleProvider.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/RNTester/RNTester/RNTesterTurboModuleProvider.mm b/RNTester/RNTester/RNTesterTurboModuleProvider.mm index f25472b5689ebf..fd4b7726f05b5f 100644 --- a/RNTester/RNTester/RNTesterTurboModuleProvider.mm +++ b/RNTester/RNTester/RNTesterTurboModuleProvider.mm @@ -10,8 +10,8 @@ #import "RNTesterTurboModuleProvider.h" -#import -#import +#import +#import // NOTE: This entire file should be codegen'ed. From 7d1c827cb2231e4091698a3d33addd067f40af7d Mon Sep 17 00:00:00 2001 From: Shen Jin Date: Fri, 24 May 2019 14:37:17 -0700 Subject: [PATCH 0084/1084] Fix spinner mode Summary: Okay, I think this is the best I can do David, I don't think there's an obvious/easy way for me to try to get `getIdentifier()` to return a non zero value. Setting it to what Spencer suggested works for my use case. ## Changelog [Android] [Changed] - Update spinner mode to render spinner instead of calendar Reviewed By: sahrens Differential Revision: D15427793 fbshipit-source-id: b04f024a9a1f052f69f3bda47d77821782dc2c0e --- .../react/modules/datepicker/DatePickerDialogFragment.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/datepicker/DatePickerDialogFragment.java b/ReactAndroid/src/main/java/com/facebook/react/modules/datepicker/DatePickerDialogFragment.java index fdaa97fe3b7719..70d4466ad003e8 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/datepicker/DatePickerDialogFragment.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/datepicker/DatePickerDialogFragment.java @@ -19,6 +19,7 @@ import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnDismissListener; +import android.graphics.drawable.ColorDrawable; import android.os.Build; import android.os.Bundle; import androidx.fragment.app.DialogFragment; @@ -69,8 +70,9 @@ public Dialog onCreateDialog(Bundle savedInstanceState) { break; case SPINNER: dialog = new DismissableDatePickerDialog(activityContext, - activityContext.getResources().getIdentifier("SpinnerDatePickerDialog", "style", activityContext.getPackageName()), + android.R.style.Theme_Holo_Light_Dialog, onDateSetListener, year, month, day); + dialog.getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT)); break; case DEFAULT: dialog = new DismissableDatePickerDialog(activityContext, onDateSetListener, year, month, day); From fa97b2383ceaab339bc2f45b60a7b7cf510ecf0d Mon Sep 17 00:00:00 2001 From: Malcolm Scruggs Date: Fri, 24 May 2019 14:53:46 -0700 Subject: [PATCH 0085/1084] Use default OK on buttonPositive to prevent showing an alert without any buttons (#25033) Summary: Solve #25016 Use `OK` as default text for the affirmative button if no text is specified. When setting an alert on android with button configuration, and no `text` field specified no button is shown on the alert. This makes it impossible to dismiss. An example of how this can happen is creating a simple button where a `onPress` callback is used but no text is specified: ``` Alert.alert( 'title', 'message', [ { onPress: () => console.log('onPress') } ], ) ``` Does not change the current behavior of no text button configurations on iOS. On iOS at least one button is always shown, and buttons with no text can be displayed. Behavior on setting multiple buttons is a little wonky, but this PR does not aim to solve it. I did test these cases and included some examples below. ## Changelog [Android] [Fixed] - Use OK as default text on Android Alert if button configuration specified without text Pull Request resolved: https://github.com/facebook/react-native/pull/25033 Differential Revision: D15502780 Pulled By: cpojer fbshipit-source-id: 505a9940f4588f4c10e25b67bfed8b8a1e610c69 --- Libraries/Alert/Alert.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Libraries/Alert/Alert.js b/Libraries/Alert/Alert.js index 1e03d1d136df3a..125a488e0b2e66 100644 --- a/Libraries/Alert/Alert.js +++ b/Libraries/Alert/Alert.js @@ -73,9 +73,10 @@ class Alert { } // At most three buttons (neutral, negative, positive). Ignore rest. // The text 'OK' should be probably localized. iOS Alert does that in native. + const defaultPositiveText = 'OK'; const validButtons: Buttons = buttons ? buttons.slice(0, 3) - : [{text: 'OK'}]; + : [{text: defaultPositiveText}]; const buttonPositive = validButtons.pop(); const buttonNegative = validButtons.pop(); const buttonNeutral = validButtons.pop(); @@ -87,7 +88,7 @@ class Alert { config.buttonNegative = buttonNegative.text || ''; } if (buttonPositive) { - config.buttonPositive = buttonPositive.text || ''; + config.buttonPositive = buttonPositive.text || defaultPositiveText; } const onAction = (action, buttonKey) => { From b9b9137604f28736dd88a2438d1c89f4cc212e77 Mon Sep 17 00:00:00 2001 From: Hermanyo Date: Fri, 24 May 2019 15:10:22 -0700 Subject: [PATCH 0086/1084] if-else refactoring (#25025) Summary: ## Summary ## Changelog [Internal] [Changed] - Code review ## Test Plan N/A Pull Request resolved: https://github.com/facebook/react-native/pull/25025 Differential Revision: D15502838 Pulled By: cpojer fbshipit-source-id: 9b8d2525411dea35e746638146b9af90832733f6 --- .../com/facebook/react/modules/clipboard/ClipboardModule.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/clipboard/ClipboardModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/clipboard/ClipboardModule.java index 2ba6aaec6c606c..3ac75048af76ed 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/clipboard/ClipboardModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/clipboard/ClipboardModule.java @@ -42,9 +42,7 @@ public void getString(Promise promise) { try { ClipboardManager clipboard = getClipboardService(); ClipData clipData = clipboard.getPrimaryClip(); - if (clipData == null) { - promise.resolve(""); - } else if (clipData.getItemCount() >= 1) { + if (clipData != null && clipData.getItemCount() >= 1) { ClipData.Item firstItem = clipboard.getPrimaryClip().getItemAt(0); promise.resolve("" + firstItem.getText()); } else { From 651cc2613fc0080fe8f9374c95c5ce27dbdfe785 Mon Sep 17 00:00:00 2001 From: Sharon Gong Date: Fri, 24 May 2019 15:25:18 -0700 Subject: [PATCH 0087/1084] Move accessibilityActions property to UIView+React (#25015) Summary: As PR [#24743](https://github.com/facebook/react-native/pull/24743) suggested, accessibility properties are better to set on UIView+React instead of RCTView so they can be used safely on any UIView. ## Changelog [General] [Fixed] - Move accessibilityActions props to UIView+React Pull Request resolved: https://github.com/facebook/react-native/pull/25015 Differential Revision: D15503131 Pulled By: cpojer fbshipit-source-id: dedf9afbd0a1d35a5abbd13ace95ee620f718f39 --- React/Views/RCTView.h | 1 - React/Views/RCTView.m | 24 ++++++------------------ React/Views/UIView+React.h | 1 + 3 files changed, 7 insertions(+), 19 deletions(-) diff --git a/React/Views/RCTView.h b/React/Views/RCTView.h index b6d6f776682362..a63ef765bee82d 100644 --- a/React/Views/RCTView.h +++ b/React/Views/RCTView.h @@ -23,7 +23,6 @@ extern const UIAccessibilityTraits SwitchAccessibilityTrait; /** * Accessibility event handlers */ -@property (nonatomic, copy) NSArray *accessibilityActions; @property (nonatomic, copy) RCTDirectEventBlock onAccessibilityAction; @property (nonatomic, copy) RCTDirectEventBlock onAccessibilityTap; @property (nonatomic, copy) RCTDirectEventBlock onMagicTap; diff --git a/React/Views/RCTView.m b/React/Views/RCTView.m index 8f550ab57cbdf3..35854f652fc52c 100644 --- a/React/Views/RCTView.m +++ b/React/Views/RCTView.m @@ -158,33 +158,21 @@ - (NSString *)accessibilityLabel return RCTRecursiveAccessibilityLabel(self); } --(void)setAccessibilityActions:(NSArray *)actions -{ - if (!actions) { - return; - } - accessibilityActionsNameMap = [[NSMutableDictionary alloc] init]; - accessibilityActionsLabelMap = [[NSMutableDictionary alloc] init]; - for (NSDictionary *action in actions) { - if (action[@"name"]) { - accessibilityActionsNameMap[action[@"name"]] = action; - } - if (action[@"label"]) { - accessibilityActionsLabelMap[action[@"label"]] = action; - } - } - _accessibilityActions = [actions copy]; -} - - (NSArray *)accessibilityCustomActions { if (!self.accessibilityActions.count) { return nil; } + accessibilityActionsNameMap = [[NSMutableDictionary alloc] init]; + accessibilityActionsLabelMap = [[NSMutableDictionary alloc] init]; NSMutableArray *actions = [NSMutableArray array]; for (NSDictionary *action in self.accessibilityActions) { + if (action[@"name"]) { + accessibilityActionsNameMap[action[@"name"]] = action; + } if (action[@"label"]) { + accessibilityActionsLabelMap[action[@"label"]] = action; [actions addObject:[[UIAccessibilityCustomAction alloc] initWithName:action[@"label"] target:self selector:@selector(didActivateAccessibilityCustomAction:)]]; diff --git a/React/Views/UIView+React.h b/React/Views/UIView+React.h index 6fbf47a0739299..d79a46f7ccc519 100644 --- a/React/Views/UIView+React.h +++ b/React/Views/UIView+React.h @@ -119,6 +119,7 @@ @property (nonatomic, copy) NSString *accessibilityRole; @property (nonatomic, copy) NSArray *accessibilityStates; @property (nonatomic, copy) NSDictionary *accessibilityState; +@property (nonatomic, copy) NSArray *accessibilityActions; /** * Used in debugging to get a description of the view hierarchy rooted at From 206bb6d3b94888051ef70505aa86affe8e33acf2 Mon Sep 17 00:00:00 2001 From: rkang Date: Fri, 24 May 2019 15:30:03 -0700 Subject: [PATCH 0088/1084] Update the "nativeStackAndroid" (#25014) Summary: Update the "nativeStackAndroid" frame limit to 50 and include the class name on the "nativeStackAndroid". nativeStackAndroid only contains up to 10 lines of stack traces. This is due to the "ERROR_STACK_FRAME_LIMIT" set to 10 on https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/bridge/PromiseImpl.java. ![2019-05-22_10-33-23](https://user-images.githubusercontent.com/14658357/58291337-eba8de80-7d71-11e9-9524-5bd6814c9f4a.png) nativeStackAndroid should contain a more reasonable number of the native stack traces. (nativeStackIOS includes all of them). another improvement could be adding the "declaringClass" on top of the "methodName", "LineNumber", and "file" on the stack trace frameMap. ![2019-05-22_13-38-43](https://user-images.githubusercontent.com/14658357/58290869-1b56e700-7d70-11e9-9e63-2149fd1486c7.png) ## Changelog [Android] [Added] - Update the "nativeStackAndroid" frame limit to 50 and include class name Pull Request resolved: https://github.com/facebook/react-native/pull/25014 Differential Revision: D15503022 Pulled By: cpojer fbshipit-source-id: 6f1bc25ea739715d0e7589d430bf9cf72da305b2 --- .../src/main/java/com/facebook/react/bridge/PromiseImpl.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/PromiseImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/PromiseImpl.java index 4c67957eda7e33..fb3cceaa6443f7 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/PromiseImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/PromiseImpl.java @@ -20,7 +20,7 @@ public class PromiseImpl implements Promise { // Number of stack frames to parse and return to mReject.invoke // for ERROR_MAP_KEY_NATIVE_STACK - private static final int ERROR_STACK_FRAME_LIMIT = 10; + private static final int ERROR_STACK_FRAME_LIMIT = 50; private static final String ERROR_DEFAULT_CODE = "EUNSPECIFIED"; private static final String ERROR_DEFAULT_MESSAGE = "Error not specified."; @@ -32,6 +32,7 @@ public class PromiseImpl implements Promise { private static final String ERROR_MAP_KEY_NATIVE_STACK = "nativeStackAndroid"; // Keys for ERROR_MAP_KEY_NATIVE_STACK's StackFrame maps + private static final String STACK_FRAME_KEY_CLASS = "class"; private static final String STACK_FRAME_KEY_FILE = "file"; private static final String STACK_FRAME_KEY_LINE_NUMBER = "lineNumber"; private static final String STACK_FRAME_KEY_METHOD_NAME = "methodName"; @@ -218,6 +219,7 @@ public void reject( StackTraceElement frame = stackTrace[i]; WritableMap frameMap = new WritableNativeMap(); // NOTE: no column number exists StackTraceElement + frameMap.putString(STACK_FRAME_KEY_CLASS, frame.getClassName()); frameMap.putString(STACK_FRAME_KEY_FILE, frame.getFileName()); frameMap.putInt(STACK_FRAME_KEY_LINE_NUMBER, frame.getLineNumber()); frameMap.putString(STACK_FRAME_KEY_METHOD_NAME, frame.getMethodName()); From d88e4701fc46b028861ddcfa3e6ffb141b3ede3d Mon Sep 17 00:00:00 2001 From: "valerio.ponte" Date: Fri, 24 May 2019 15:34:55 -0700 Subject: [PATCH 0089/1084] Add showSoftInputOnFocus to TextInput (#25028) Summary: Add prop showSoftInputOnFocus to TextInput. This fixes #14045. This prop can be used to prevent the system keyboard from displaying at all when focusing an input text, for example if a custom keyboard component needs to be displayed instead. On Android, currently TextInput always open the soft keyboard when focused. This is because `requestFocus` calls `showSoftKeyboard`, which in turn instructs `InputMethodManager` to show the soft keyboard. Unfortunately even if we were to define a new input type that extends ReactEditText, there is no way to overcome this issue. This is because `showSoftKeyboard` is a private method so it can't be overriden. And at the same time `requestFocus` needs to invoke `super.requestFocus` to properly instruct Android that the field has gained focused, so overriding `requestFocus` in a subclass of ReactEditText is also not an option, as when invoking `super.requestFocus` we would end up calling again the one defined in ReactEditText. So currently the only way of doing this is to basically add a listener on the focus event that will close the soft keyboard immediately after. But for a split second it will still be displayed. The code in the PR changes `requestFocus` to honor showSoftInputOnFocus as defined in Android TextView, displaying the soft keyboard unless instructed otherwise. ## Changelog [Android] [Added] - Add showSoftInputOnFocus to TextInput Pull Request resolved: https://github.com/facebook/react-native/pull/25028 Differential Revision: D15503070 Pulled By: mdvacca fbshipit-source-id: db4616fa165643d6ef2b3185008c4d279ae08092 --- Libraries/Components/TextInput/TextInput.js | 7 +++++++ .../com/facebook/react/views/textinput/ReactEditText.java | 4 +++- .../react/views/textinput/ReactTextInputManager.java | 6 ++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js index 3caf05f6bacb88..9e4f29c94c9c74 100644 --- a/Libraries/Components/TextInput/TextInput.js +++ b/Libraries/Components/TextInput/TextInput.js @@ -253,6 +253,7 @@ type AndroidProps = $ReadOnly<{| | 'yes' | 'yesExcludeDescendants' ), + showSoftInputOnFocus?: ?boolean, |}>; type Props = $ReadOnly<{| @@ -926,6 +927,12 @@ const TextInput = createReactClass({ 'newPassword', 'oneTimeCode', ]), + /** + * When `false`, it will prevent the soft keyboard from showing when the field is focused. + * Defaults to `true`. + * @platform android + */ + showSoftInputOnFocus: PropTypes.bool, }, getDefaultProps() { return { diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java index 63a941a0c2ab2e..7f8137c9c4af97 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java @@ -213,7 +213,9 @@ public boolean requestFocus(int direction, Rect previouslyFocusedRect) { } setFocusableInTouchMode(true); boolean focused = super.requestFocus(direction, previouslyFocusedRect); - showSoftKeyboard(); + if (getShowSoftInputOnFocus()) { + showSoftKeyboard(); + } return focused; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java index 2927ab9c705404..e0e286ead83e1f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java @@ -715,6 +715,12 @@ public void setBorderStyle(ReactEditText view, @Nullable String borderStyle) { view.setBorderStyle(borderStyle); } + @ReactProp(name = "showSoftInputOnFocus", defaultBoolean = true) + public void showKeyboardOnFocus(ReactEditText view, boolean showKeyboardOnFocus) { + view.setShowSoftInputOnFocus(showKeyboardOnFocus); + } + + @ReactPropGroup(names = { ViewProps.BORDER_WIDTH, ViewProps.BORDER_LEFT_WIDTH, From 94dfc153a4776e3d018b3ca53dcd849e2f01d905 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Fri, 24 May 2019 19:11:45 -0700 Subject: [PATCH 0090/1084] Fabric: Temporary workaround to enable commands in Fabric Summary: This is a temporary workaround that we need only temporary and will get rid of soon. Reviewed By: mdvacca Differential Revision: D15501203 fbshipit-source-id: cec4891b6a185ea9e39f50bfedf9e1dae8993b66 --- .../View/RCTViewComponentView.h | 5 +++++ .../View/RCTViewComponentView.mm | 5 +++++ React/Modules/RCTUIManager.m | 19 +++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.h b/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.h index 9d91ebb73df315..c4803845ad7470 100644 --- a/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.h +++ b/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.h @@ -79,6 +79,11 @@ NS_ASSUME_NONNULL_BEGIN - (void)finalizeUpdates:(RNComponentViewUpdateMask)updateMask NS_REQUIRES_SUPER; - (void)prepareForRecycle NS_REQUIRES_SUPER; +/* + * This is a fragment of temporary workaround that we need only temporary and will get rid of soon. + */ +- (NSString *)componentViewName_DO_NOT_USE_THIS_IS_BROKEN; + @end NS_ASSUME_NONNULL_END diff --git a/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm b/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm index 22921328b0288c..48fed7a72018d6 100644 --- a/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm @@ -564,4 +564,9 @@ - (SharedTouchEventEmitter)touchEventEmitterAtPoint:(CGPoint)point return _eventEmitter; } +- (NSString *)componentViewName_DO_NOT_USE_THIS_IS_BROKEN +{ + return RCTNSStringFromString([[self class] componentDescriptorProvider].name); +} + @end diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m index 7aeefbb57ba1d6..d40995bc30ca18 100644 --- a/React/Modules/RCTUIManager.m +++ b/React/Modules/RCTUIManager.m @@ -1065,6 +1065,25 @@ - (void)synchronouslyUpdateViewOnUIThread:(NSNumber *)reactTag { RCTShadowView *shadowView = _shadowViewRegistry[reactTag]; RCTComponentData *componentData = _componentDataByName[shadowView.viewName]; + + // Achtung! Achtung! + // This is a remarkably hacky and ugly workaround. + // We need this only temporary for some testing. We need this hack until Fabric fully implements command-execution pipeline. + // This does not affect non-Fabric apps. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wundeclared-selector" + if (!componentData) { + __block UIView *view; + RCTUnsafeExecuteOnMainQueueSync(^{ + view = self->_viewRegistry[reactTag]; + }); + if ([view respondsToSelector:@selector(componentViewName_DO_NOT_USE_THIS_IS_BROKEN)]) { + NSString *name = [view performSelector:@selector(componentViewName_DO_NOT_USE_THIS_IS_BROKEN)]; + componentData = _componentDataByName[[NSString stringWithFormat:@"RCT%@", name]]; + } + } +#pragma clang diagnostic pop + Class managerClass = componentData.managerClass; RCTModuleData *moduleData = [_bridge moduleDataForName:RCTBridgeModuleNameForClass(managerClass)]; id method = moduleData.methods[commandID]; From ba627f4970ea558a064689df3ebfdb34467a1c39 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Fri, 24 May 2019 19:11:45 -0700 Subject: [PATCH 0091/1084] Fabric: Implementaion of RCTScrollableProtocol for RCTScrollViewComponentView Summary: We need this only until Fabric has own command-execution pipeline. Reviewed By: mdvacca Differential Revision: D15501202 fbshipit-source-id: aad77660ada43e429722b13d1da2f998a1726c73 --- .../ScrollView/RCTScrollViewComponentView.h | 10 +++++ .../ScrollView/RCTScrollViewComponentView.mm | 39 +++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.h b/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.h index b476ead428902c..ace64fe6f02c27 100644 --- a/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.h +++ b/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.h @@ -7,6 +7,7 @@ #import +#import #import #import @@ -46,4 +47,13 @@ NS_ASSUME_NONNULL_BEGIN @end +/* + * RCTScrollableProtocol is a protocol which RCTScrollViewManager uses to communicate with all kinds of `UIScrollView`s. + * Until Fabric has own command-execution pipeline we have to support that to some extent. The implementation shouldn't + * be perfect though because very soon we will migrate that to the new commands infra and get rid of this. + */ +@interface RCTScrollViewComponentView (ScrollableProtocol) + +@end + NS_ASSUME_NONNULL_END diff --git a/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm b/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm index 87350b07b8e301..5ed4ed9e218014 100644 --- a/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm @@ -218,3 +218,42 @@ - (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(nullable UI } @end + +@implementation RCTScrollViewComponentView (ScrollableProtocol) + +- (CGSize)contentSize +{ + return _contentSize; +} + +- (void)scrollToOffset:(CGPoint)offset +{ + [self scrollToOffset:offset animated:YES]; +} + +- (void)scrollToOffset:(CGPoint)offset animated:(BOOL)animated +{ + [self.scrollView setContentOffset:offset animated:animated]; +} + +- (void)scrollToEnd:(BOOL)animated +{ + // Not implemented. +} + +- (void)zoomToRect:(CGRect)rect animated:(BOOL)animated +{ + // Not implemented. +} + +- (void)addScrollListener:(NSObject *)scrollListener +{ + [self.scrollViewDelegateSplitter addDelegate:scrollListener]; +} + +- (void)removeScrollListener:(NSObject *)scrollListener +{ + [self.scrollViewDelegateSplitter removeDelegate:scrollListener]; +} + +@end From a0f2bfa120ea8f4e5ce72436a96104a1b096dc49 Mon Sep 17 00:00:00 2001 From: Michal Sienkiewicz Date: Sun, 26 May 2019 01:33:19 -0700 Subject: [PATCH 0092/1084] Sync worker requirement mismatches Summary: Syncing worker requirement mismatches to improve remote build time. Created actions: MEDIUM: 5 Differential Revision: D15510246 fbshipit-source-id: b8454b4acf2810251d2a4a4515fc0ce2c1a2b327 --- ReactCommon/cxxreact/re_worker_requirements | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 ReactCommon/cxxreact/re_worker_requirements diff --git a/ReactCommon/cxxreact/re_worker_requirements b/ReactCommon/cxxreact/re_worker_requirements new file mode 100644 index 00000000000000..3b5fff6d2e136a --- /dev/null +++ b/ReactCommon/cxxreact/re_worker_requirements @@ -0,0 +1,6 @@ +{ + "bridgeAndroid#android-x86,merge_structure_97d5739e": { + "workerSize": "MEDIUM", + "platformType": "LINUX" + } +} \ No newline at end of file From 956077675efc3c24651e7a0409c25e759347df4e Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Mon, 27 May 2019 11:47:05 -0700 Subject: [PATCH 0093/1084] Fix for ActivityIndicator on Android Summary: Fixes an issue that was including the view config native component verification function even when the native component wasn't included (e.g. on android) Reviewed By: mdvacca Differential Revision: D15513535 fbshipit-source-id: 9b615689c0d64757eeb3d66862e5b1902ea79b20 --- .../ActivityIndicator/ActivityIndicator.js | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/Libraries/Components/ActivityIndicator/ActivityIndicator.js b/Libraries/Components/ActivityIndicator/ActivityIndicator.js index f6ffe500edfc5d..70f73db0ce0cdd 100644 --- a/Libraries/Components/ActivityIndicator/ActivityIndicator.js +++ b/Libraries/Components/ActivityIndicator/ActivityIndicator.js @@ -15,12 +15,13 @@ const React = require('react'); const StyleSheet = require('../../StyleSheet/StyleSheet'); const View = require('../View/View'); -const ActivityIndicatorViewNativeComponent = require('./ActivityIndicatorViewNativeComponent'); - import type {NativeComponent} from '../../Renderer/shims/ReactNative'; import type {ViewProps} from '../View/ViewPropTypes'; -const ProgressBarAndroid = require('../ProgressBarAndroid/ProgressBarAndroid'); +const PlatformActivityIndicator = + Platform.OS === 'android' + ? require('../ProgressBarAndroid/ProgressBarAndroid') + : require('./ActivityIndicatorViewNativeComponent'); const GRAY = '#999999'; @@ -92,6 +93,11 @@ const ActivityIndicator = (props: Props, forwardedRef?: any) => { size: sizeProp, }; + const androidProps = { + styleAttr: 'Normal', + indeterminate: true, + }; + return ( { styles.container, style, )}> - {/* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was - * found when making Flow check .android.js files. */} {Platform.OS === 'android' ? ( - + // $FlowFixMe Flow doesn't know when this is the android component + ) : ( - + )} ); From 122cc8ba8ab7c5bbcc042f5221f5c0c53ec99c19 Mon Sep 17 00:00:00 2001 From: Daiki Ihara Date: Mon, 27 May 2019 22:09:41 -0700 Subject: [PATCH 0094/1084] Add spec for AlertManager (#24906) Summary: Part of #24875 ## Changelog [General] [Added] - Add TurboModule spec for AlertManager Pull Request resolved: https://github.com/facebook/react-native/pull/24906 Reviewed By: lunaleaps Differential Revision: D15471065 Pulled By: fkgozali fbshipit-source-id: bb22e6454b1f748987f3a8cd957bfd4e027493a5 --- Libraries/Alert/Alert.js | 40 ++++---------------- Libraries/Alert/NativeAlertManager.js | 51 ++++++++++++++++++++++++++ Libraries/Alert/RCTAlertManager.ios.js | 15 +++++++- 3 files changed, 72 insertions(+), 34 deletions(-) create mode 100644 Libraries/Alert/NativeAlertManager.js diff --git a/Libraries/Alert/Alert.js b/Libraries/Alert/Alert.js index 125a488e0b2e66..63f5b31d4fe30c 100644 --- a/Libraries/Alert/Alert.js +++ b/Libraries/Alert/Alert.js @@ -10,37 +10,12 @@ 'use strict'; -import NativeModules from '../BatchedBridge/NativeModules'; import Platform from '../Utilities/Platform'; -import DialogManagerAndroid, { +import NativeDialogManagerAndroid, { type DialogOptions, } from '../NativeModules/specs/NativeDialogManagerAndroid'; - -const RCTAlertManager = NativeModules.AlertManager; - -export type Buttons = Array<{ - text?: string, - onPress?: ?Function, - style?: AlertButtonStyle, -}>; - -type Options = { - cancelable?: ?boolean, - onDismiss?: ?Function, -}; - -type AlertType = $Keys<{ - default: string, - 'plain-text': string, - 'secure-text': string, - 'login-password': string, -}>; - -export type AlertButtonStyle = $Keys<{ - default: string, - cancel: string, - destructive: string, -}>; +import RCTAlertManager from './RCTAlertManager'; +import {type Buttons, type Options, type AlertType} from './NativeAlertManager'; /** * Launches an alert dialog with the specified title and message. @@ -57,10 +32,10 @@ class Alert { if (Platform.OS === 'ios') { Alert.prompt(title, message, buttons, 'default'); } else if (Platform.OS === 'android') { - if (!DialogManagerAndroid) { + if (!NativeDialogManagerAndroid) { return; } - const constants = DialogManagerAndroid.getConstants(); + const constants = NativeDialogManagerAndroid.getConstants(); const config: DialogOptions = { title: title || '', @@ -105,7 +80,7 @@ class Alert { } }; const onError = errorMessage => console.warn(errorMessage); - DialogManagerAndroid.showAlert(config, onError, onAction); + NativeDialogManagerAndroid.showAlert(config, onError, onAction); } } @@ -131,7 +106,7 @@ class Alert { { title: title || '', type: 'plain-text', - defaultValue: message, + defaultValue: message || '', }, (id, value) => { callback(value); @@ -175,6 +150,7 @@ class Alert { }, (id, value) => { const cb = callbacks[id]; + // $FlowFixMe cb && cb(value); }, ); diff --git a/Libraries/Alert/NativeAlertManager.js b/Libraries/Alert/NativeAlertManager.js new file mode 100644 index 00000000000000..0a540cac72770f --- /dev/null +++ b/Libraries/Alert/NativeAlertManager.js @@ -0,0 +1,51 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +export type Buttons = Array<{ + text?: string, + onPress?: ?Function, + style?: AlertButtonStyle, +}>; + +export type Options = { + cancelable?: ?boolean, + onDismiss?: ?() => void, +}; + +/* 'default' | plain-text' | 'secure-text' | 'login-password' */ +export type AlertType = string; + +/* 'default' | 'cancel' | 'destructive' */ +export type AlertButtonStyle = string; + +export type Args = {| + title?: string, + message?: string, + buttons?: Buttons, + type?: string, + defaultValue?: string, + cancelButtonKey?: string, + destructiveButtonKey?: string, + keyboardType?: string, +|}; + +export interface Spec extends TurboModule { + +alertWithArgs: ( + args: Args, + callback: (id: number, value: string) => void, + ) => void; +} + +export default TurboModuleRegistry.get('AlertManager'); diff --git a/Libraries/Alert/RCTAlertManager.ios.js b/Libraries/Alert/RCTAlertManager.ios.js index 246967358982b9..8ededddf4b463c 100644 --- a/Libraries/Alert/RCTAlertManager.ios.js +++ b/Libraries/Alert/RCTAlertManager.ios.js @@ -10,6 +10,17 @@ 'use strict'; -const RCTAlertManager = require('../BatchedBridge/NativeModules').AlertManager; +import NativeAlertManager from './NativeAlertManager'; +import type {Args} from './NativeAlertManager'; -module.exports = RCTAlertManager; +module.exports = { + alertWithArgs( + args: Args, + callback: (id: number, value: string) => void, + ): void { + if (NativeAlertManager == null) { + return; + } + NativeAlertManager.alertWithArgs(args, callback); + }, +}; From d2ef1145382b63d95f1f3374384e55487adee130 Mon Sep 17 00:00:00 2001 From: Youssouf El Azizi Date: Mon, 27 May 2019 22:09:41 -0700 Subject: [PATCH 0095/1084] Add Spec for ImageEditor (#24921) Summary: This PR solves part of this issue: #24875 ## Changelog [General] [Added] - TM Spec for ImageEditor Pull Request resolved: https://github.com/facebook/react-native/pull/24921 Reviewed By: rickhanlonii Differential Revision: D15471058 Pulled By: fkgozali fbshipit-source-id: f01539fc8acea95fca27ce7bb4b4169ffe138d93 --- Libraries/Image/ImageEditor.js | 6 ++---- Libraries/Image/NativeImageEditor.js | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 Libraries/Image/NativeImageEditor.js diff --git a/Libraries/Image/ImageEditor.js b/Libraries/Image/ImageEditor.js index 75621c7bb3e50e..69a7a9121e0783 100644 --- a/Libraries/Image/ImageEditor.js +++ b/Libraries/Image/ImageEditor.js @@ -8,9 +8,7 @@ * @format */ 'use strict'; - -const RCTImageEditingManager = require('../BatchedBridge/NativeModules') - .ImageEditingManager; +import NativeImageEditor from './NativeImageEditor'; type ImageCropData = { /** @@ -66,7 +64,7 @@ class ImageEditor { success: (uri: string) => void, failure: (error: Object) => void, ) { - RCTImageEditingManager.cropImage(uri, cropData, success, failure); + NativeImageEditor.cropImage(uri, cropData, success, failure); } } diff --git a/Libraries/Image/NativeImageEditor.js b/Libraries/Image/NativeImageEditor.js new file mode 100644 index 00000000000000..4f4da0b5388b67 --- /dev/null +++ b/Libraries/Image/NativeImageEditor.js @@ -0,0 +1,25 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +cropImage: ( + uri: string, + options: Object, // TODO: type this better + success: (uri: string) => void, + error: (error: string) => void, + ) => void; +} + +export default TurboModuleRegistry.getEnforcing('ImageEditingManager'); From 31ab94770311f56182734b57c48ffcd765096dc5 Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Tue, 28 May 2019 04:17:17 -0700 Subject: [PATCH 0096/1084] Remove ToolbarAndroid, move to FB Internal Summary: This removes the JS for ToolbarAndroid from RN and moves it to Ads manager, which has two remaining uses of it. In a follow-up, I will also move the native code. Reviewed By: rickhanlonii Differential Revision: D15469117 fbshipit-source-id: 68c3f89b85cc589a48f2dced183267daa791b53b --- .../ToolbarAndroid/ToolbarAndroid.android.js | 251 ------------------ .../ToolbarAndroid/ToolbarAndroid.ios.js | 12 - .../ToolbarAndroidNativeComponent.js | 133 ---------- .../react-native-implementation.js | 3 - 4 files changed, 399 deletions(-) delete mode 100644 Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js delete mode 100644 Libraries/Components/ToolbarAndroid/ToolbarAndroid.ios.js delete mode 100644 Libraries/Components/ToolbarAndroid/ToolbarAndroidNativeComponent.js diff --git a/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js b/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js deleted file mode 100644 index fdfbde63567274..00000000000000 --- a/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js +++ /dev/null @@ -1,251 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @flow - */ - -'use strict'; - -const React = require('react'); -const UIManager = require('../../ReactNative/UIManager'); - -const ToolbarAndroidNativeComponent = require('./ToolbarAndroidNativeComponent'); -const resolveAssetSource = require('../../Image/resolveAssetSource'); - -import type {SyntheticEvent} from '../../Types/CoreEventTypes'; -import type {ImageSource} from '../../Image/ImageSource'; -import type {ColorValue} from '../../StyleSheet/StyleSheetTypes'; -import type {ViewProps} from '../View/ViewPropTypes'; -import type {NativeComponent} from '../../Renderer/shims/ReactNative'; - -/** - * React component that wraps the Android-only [`Toolbar` widget][0]. A Toolbar can display a logo, - * navigation icon (e.g. hamburger menu), a title & subtitle and a list of actions. The title and - * subtitle are expanded so the logo and navigation icons are displayed on the left, title and - * subtitle in the middle and the actions on the right. - * - * If the toolbar has an only child, it will be displayed between the title and actions. - * - * Although the Toolbar supports remote images for the logo, navigation and action icons, this - * should only be used in DEV mode where `require('./some_icon.png')` translates into a packager - * URL. In release mode you should always use a drawable resource for these icons. Using - * `require('./some_icon.png')` will do this automatically for you, so as long as you don't - * explicitly use e.g. `{uri: 'http://...'}`, you will be good. - * - * Example: - * - * ``` - * render: function() { - * return ( - * - * ) - * }, - * onActionSelected: function(position) { - * if (position === 0) { // index of 'Settings' - * showSettings(); - * } - * } - * ``` - * - * [0]: https://developer.android.com/reference/android/support/v7/widget/Toolbar.html - */ - -type Action = $ReadOnly<{| - title: string, - icon?: ?ImageSource, - show?: 'always' | 'ifRoom' | 'never', - showWithText?: boolean, -|}>; - -type ToolbarAndroidChangeEvent = SyntheticEvent< - $ReadOnly<{| - position: number, - |}>, ->; - -type ToolbarAndroidProps = $ReadOnly<{| - ...ViewProps, - /** - * or text on the right side of the widget. If they don't fit they are placed in an 'overflow' - * Sets possible actions on the toolbar as part of the action menu. These are displayed as icons - * menu. - * - * This property takes an array of objects, where each object has the following keys: - * - * * `title`: **required**, the title of this action - * * `icon`: the icon for this action, e.g. `require('./some_icon.png')` - * * `show`: when to show this action as an icon or hide it in the overflow menu: `always`, - * `ifRoom` or `never` - * * `showWithText`: boolean, whether to show text alongside the icon or not - */ - actions?: ?Array, - /** - * Sets the toolbar logo. - */ - logo?: ?ImageSource, - /** - * Sets the navigation icon. - */ - navIcon?: ?ImageSource, - /** - * Callback that is called when an action is selected. The only argument that is passed to the - * callback is the position of the action in the actions array. - */ - onActionSelected?: ?(position: number) => void, - /** - * Callback called when the icon is selected. - */ - onIconClicked?: ?() => void, - /** - * Sets the overflow icon. - */ - overflowIcon?: ?ImageSource, - /** - * Sets the toolbar subtitle. - */ - subtitle?: ?string, - /** - * Sets the toolbar subtitle color. - */ - subtitleColor?: ?ColorValue, - /** - * Sets the toolbar title. - */ - title?: ?Stringish, - /** - * Sets the toolbar title color. - */ - titleColor?: ?ColorValue, - /** - * Sets the content inset for the toolbar starting edge. - * - * The content inset affects the valid area for Toolbar content other than - * the navigation button and menu. Insets define the minimum margin for - * these components and can be used to effectively align Toolbar content - * along well-known gridlines. - */ - contentInsetStart?: ?number, - /** - * Sets the content inset for the toolbar ending edge. - * - * The content inset affects the valid area for Toolbar content other than - * the navigation button and menu. Insets define the minimum margin for - * these components and can be used to effectively align Toolbar content - * along well-known gridlines. - */ - contentInsetEnd?: ?number, - /** - * Used to set the toolbar direction to RTL. - * In addition to this property you need to add - * - * android:supportsRtl="true" - * - * to your application AndroidManifest.xml and then call - * `setLayoutDirection(LayoutDirection.RTL)` in your MainActivity - * `onCreate` method. - */ - rtl?: ?boolean, - /** - * Used to locate this view in end-to-end tests. - */ - testID?: ?string, -|}>; - -type Props = $ReadOnly<{| - ...ToolbarAndroidProps, - forwardedRef: ?React.Ref, -|}>; - -class ToolbarAndroid extends React.Component { - _onSelect = (event: ToolbarAndroidChangeEvent) => { - const position = event.nativeEvent.position; - if (position === -1) { - this.props.onIconClicked && this.props.onIconClicked(); - } else { - this.props.onActionSelected && this.props.onActionSelected(position); - } - }; - - render() { - const { - onIconClicked, - onActionSelected, - forwardedRef, - ...otherProps - } = this.props; - - const nativeProps: {...typeof otherProps, nativeActions?: Array} = { - ...otherProps, - }; - - if (this.props.logo) { - nativeProps.logo = resolveAssetSource(this.props.logo); - } - - if (this.props.navIcon) { - nativeProps.navIcon = resolveAssetSource(this.props.navIcon); - } - - if (this.props.overflowIcon) { - nativeProps.overflowIcon = resolveAssetSource(this.props.overflowIcon); - } - - if (this.props.actions) { - const nativeActions = []; - for (let i = 0; i < this.props.actions.length; i++) { - const action = { - icon: this.props.actions[i].icon, - show: this.props.actions[i].show, - }; - - if (action.icon) { - action.icon = resolveAssetSource(action.icon); - } - if (action.show) { - action.show = UIManager.getViewManagerConfig( - 'ToolbarAndroid', - ).Constants.ShowAsAction[action.show]; - } - - nativeActions.push({ - ...this.props.actions[i], - ...action, - }); - } - - nativeProps.nativeActions = nativeActions; - } - - return ( - - ); - } -} - -const ToolbarAndroidToExport = React.forwardRef( - ( - props: ToolbarAndroidProps, - forwardedRef: ?React.Ref, - ) => { - return ; - }, -); - -/* $FlowFixMe(>=0.89.0 site=react_native_android_fb) This comment suppresses an - * error found when Flow v0.89 was deployed. To see the error, delete this - * comment and run Flow. */ -module.exports = (ToolbarAndroidToExport: Class< - NativeComponent, ->); diff --git a/Libraries/Components/ToolbarAndroid/ToolbarAndroid.ios.js b/Libraries/Components/ToolbarAndroid/ToolbarAndroid.ios.js deleted file mode 100644 index d5fd5cf83f7560..00000000000000 --- a/Libraries/Components/ToolbarAndroid/ToolbarAndroid.ios.js +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -'use strict'; - -module.exports = require('../UnimplementedViews/UnimplementedView'); diff --git a/Libraries/Components/ToolbarAndroid/ToolbarAndroidNativeComponent.js b/Libraries/Components/ToolbarAndroid/ToolbarAndroidNativeComponent.js deleted file mode 100644 index e65b4eabeeb368..00000000000000 --- a/Libraries/Components/ToolbarAndroid/ToolbarAndroidNativeComponent.js +++ /dev/null @@ -1,133 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @flow - */ - -'use strict'; - -const requireNativeComponent = require('../../ReactNative/requireNativeComponent'); - -import type {SyntheticEvent} from '../../Types/CoreEventTypes'; -import type {ImageSource} from '../../Image/ImageSource'; -import type {ViewProps} from '../View/ViewPropTypes'; -import type {NativeComponent} from '../../Renderer/shims/ReactNative'; - -type Action = $ReadOnly<{| - title: string, - icon?: ?ImageSource, - show?: 'always' | 'ifRoom' | 'never', - showWithText?: boolean, -|}>; - -type ToolbarAndroidChangeEvent = SyntheticEvent< - $ReadOnly<{| - position: number, - |}>, ->; - -type NativeProps = $ReadOnly<{| - onSelect: (event: ToolbarAndroidChangeEvent) => mixed, - nativeActions?: Array, -|}>; - -type ColorValue = null | string; - -type ToolbarAndroidProps = $ReadOnly<{| - ...ViewProps, - ...NativeProps, - /** - * or text on the right side of the widget. If they don't fit they are placed in an 'overflow' - * Sets possible actions on the toolbar as part of the action menu. These are displayed as icons - * menu. - * - * This property takes an array of objects, where each object has the following keys: - * - * * `title`: **required**, the title of this action - * * `icon`: the icon for this action, e.g. `require('./some_icon.png')` - * * `show`: when to show this action as an icon or hide it in the overflow menu: `always`, - * `ifRoom` or `never` - * * `showWithText`: boolean, whether to show text alongside the icon or not - */ - actions?: ?Array, - /** - * Sets the toolbar logo. - */ - logo?: ?ImageSource, - /** - * Sets the navigation icon. - */ - navIcon?: ?ImageSource, - /** - * Callback that is called when an action is selected. The only argument that is passed to the - * callback is the position of the action in the actions array. - */ - onActionSelected?: ?(position: number) => void, - /** - * Callback called when the icon is selected. - */ - onIconClicked?: ?() => void, - /** - * Sets the overflow icon. - */ - overflowIcon?: ?ImageSource, - /** - * Sets the toolbar subtitle. - */ - subtitle?: ?string, - /** - * Sets the toolbar subtitle color. - */ - subtitleColor?: ?ColorValue, - /** - * Sets the toolbar title. - */ - title?: ?Stringish, - /** - * Sets the toolbar title color. - */ - titleColor?: ?ColorValue, - /** - * Sets the content inset for the toolbar starting edge. - * - * The content inset affects the valid area for Toolbar content other than - * the navigation button and menu. Insets define the minimum margin for - * these components and can be used to effectively align Toolbar content - * along well-known gridlines. - */ - contentInsetStart?: ?number, - /** - * Sets the content inset for the toolbar ending edge. - * - * The content inset affects the valid area for Toolbar content other than - * the navigation button and menu. Insets define the minimum margin for - * these components and can be used to effectively align Toolbar content - * along well-known gridlines. - */ - contentInsetEnd?: ?number, - /** - * Used to set the toolbar direction to RTL. - * In addition to this property you need to add - * - * android:supportsRtl="true" - * - * to your application AndroidManifest.xml and then call - * `setLayoutDirection(LayoutDirection.RTL)` in your MainActivity - * `onCreate` method. - */ - rtl?: ?boolean, - /** - * Used to locate this view in end-to-end tests. - */ - testID?: ?string, -|}>; - -type NativeToolbarAndroidProps = Class>; - -module.exports = ((requireNativeComponent( - 'ToolbarAndroid', -): any): NativeToolbarAndroidProps); diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js index c1bfca14181584..1f4ab0051f9d58 100644 --- a/Libraries/react-native/react-native-implementation.js +++ b/Libraries/react-native/react-native-implementation.js @@ -137,9 +137,6 @@ module.exports = { get TextInput() { return require('TextInput'); }, - get ToolbarAndroid() { - return require('ToolbarAndroid'); - }, get Touchable() { return require('Touchable'); }, From 0b14b6007d448d674ce0bd5f733413dd20a4e8cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= Date: Tue, 28 May 2019 06:49:54 -0700 Subject: [PATCH 0097/1084] (CONTRIBUTING.md) Link to Issues wiki (#25035) Summary: Link to https://github.com/facebook/react-native/wiki/Issues ## Changelog [Internal] [Changed] - Link to Issues wiki Pull Request resolved: https://github.com/facebook/react-native/pull/25035 Differential Revision: D15516862 Pulled By: cpojer fbshipit-source-id: 2f70a28685852293f946c0b1128184226d56aaa7 --- CONTRIBUTING.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 42cb49e62135ee..56e1eea52dce36 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -18,7 +18,7 @@ If you are eager to start contributing code right away, we have a list of [good There are other ways you can contribute without writing a single line of code. Here are a few things you can do to help out: -1. **Replying and handling open issues.** We get a lot of issues every day, and some of them may lack necessary information. You can help out by guiding people through the process of filling out the issue template, asking for clarifying information, or pointing them to existing issues that match their description of the problem. We'll cover more about this process later, in [Handling Issues](http://github.com/facebook/react-native/wiki/Handling-Issues). +1. **Replying and handling open issues.** We get a lot of issues every day, and some of them may lack necessary information. You can help out by guiding people through the process of filling out the issue template, asking for clarifying information, or pointing them to existing issues that match their description of the problem. We cover more about this process in the [Issue Triage wiki](https://github.com/facebook/react-native/wiki/Issues#triage). 2. **Reviewing pull requests for the docs.** Reviewing [documentation updates](https://github.com/facebook/react-native-website/pulls) can be as simple as checking for spelling and grammar. If you encounter situations that can be explained better in the docs, click **Edit** at the top of most docs pages to get started with your own contribution. 3. **Help people write test plans.** Some pull requests sent to the main repository may lack a proper test plan. These help reviewers understand how the change was tested, and can speed up the time it takes for a contribution to be accepted. @@ -30,6 +30,7 @@ We use GitHub issues and pull requests to keep track of bug reports and contribu You can learn more about the contribution process in the following documents: +* [Issues](https://github.com/facebook/react-native/wiki/Issues) * [Pull Requests](https://github.com/facebook/react-native/wiki/Pull-Requests) We also have a thriving community of contributors who would be happy to help you get set up. You can reach out to us through [@ReactNative](http://twitter.com/reactnative) (the React Native team) and [@ReactNativeComm](http://twitter.com/reactnativecomm) (the React Native Community organization). @@ -47,9 +48,9 @@ There are a few other repositories you might want to familiarize yourself with: Browsing through these repositories should provide some insight into how the React Native open source project is managed. -## Handling Issues +## GitHub Issues -We use GitHub issues to track bugs exclusively. You can report an issue by filing a [Bug Report](https://github.com/facebook/react-native/issues/new/choose). Watch this space for more details on how to get involved and triage issues. +We use GitHub issues to track bugs exclusively. We have documented our issue handling processes in the [Issues wiki](https://github.com/facebook/react-native/wiki/Issues). ### Security Bugs From 54abe1f5990b8f5f57da3231d1bb1fd83966f064 Mon Sep 17 00:00:00 2001 From: Andrea Cimitan Date: Tue, 28 May 2019 07:30:00 -0700 Subject: [PATCH 0098/1084] Linking.getInitialURL() to work with NFC tags on Android (#25055) Summary: This PR solves bug https://github.com/facebook/react-native/issues/24393 for Android. Allows an app to be opened with an NFC tag and getting the url trough Linking.getInitialURL() ## Changelog [Android] [Fixed] - This branch checks also for `ACTION_NDEF_DISCOVERED` intent matches to set the initialURL Pull Request resolved: https://github.com/facebook/react-native/pull/25055 Differential Revision: D15516873 Pulled By: cpojer fbshipit-source-id: e8803738d857a69e1063e926fc3858a416a0b25e --- .../java/com/facebook/react/modules/intent/IntentModule.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.java index 50c6d405809556..9cf2a7e94732a6 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.java @@ -12,6 +12,7 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; +import android.nfc.NfcAdapter; import android.provider.Settings; import com.facebook.react.bridge.JSApplicationIllegalArgumentException; @@ -59,7 +60,7 @@ public void getInitialURL(Promise promise) { String action = intent.getAction(); Uri uri = intent.getData(); - if (Intent.ACTION_VIEW.equals(action) && uri != null) { + if (uri != null && (Intent.ACTION_VIEW.equals(action) || NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action))) { initialURL = uri.toString(); } } From 3945f10561622a3e361190919d0a6d397f67ef8b Mon Sep 17 00:00:00 2001 From: AndreiCalazans Date: Tue, 28 May 2019 08:34:59 -0700 Subject: [PATCH 0099/1084] - Update folder structure of RNTester's JS directory. (#25013) Summary: Changes RNTester, first attempt in the direction of improving the RNTester overall. Related ticket: #24647 Changed the `js` directory of the RNTester to have the following structure: ``` - js - assets - components - examples - types - utils ``` * **assets** _Any images, gifs, and media content_ * **components** _All shared components_ * **examples** _Example View/Components to be rendered by the App_ * **types** _Shared flow types_ * **utils** _Shared utilities_ ## Changelog [General] [Changed] - Update folder structure of RNTester's JS directory. Pull Request resolved: https://github.com/facebook/react-native/pull/25013 Differential Revision: D15515773 Pulled By: cpojer fbshipit-source-id: 0e4b6386127f338dca0ffe8c237073be53a9e221 --- .gitignore | 1 + RNTester/js/AssetScaledImageExample.js | 113 ---------------- RNTester/js/RNTesterApp.android.js | 14 +- RNTester/js/RNTesterApp.ios.js | 26 ++-- .../js/{Thumbnails => assets}/bandaged.png | Bin RNTester/js/{ => assets}/bunny.png | Bin RNTester/js/{Thumbnails => assets}/call.png | Bin .../js/{Thumbnails => assets}/dislike.png | Bin RNTester/js/{Thumbnails => assets}/fist.png | Bin .../js/{Thumbnails => assets}/flowers.png | Bin RNTester/js/{ => assets}/flux@3x.png | Bin RNTester/js/{ => assets}/hawk.png | Bin RNTester/js/{Thumbnails => assets}/heart.png | Bin RNTester/js/{ => assets}/helloworld.html | 0 RNTester/js/{ => assets}/imageMask.png | Bin RNTester/js/{Thumbnails => assets}/like.png | Bin RNTester/js/{Thumbnails => assets}/liking.png | Bin RNTester/js/{ => assets}/messagingtest.html | 0 RNTester/js/{Thumbnails => assets}/party.png | Bin RNTester/js/{Thumbnails => assets}/poke.png | Bin RNTester/js/{ => assets}/relay@3x.png | Bin RNTester/js/{ => assets}/slider-left.png | Bin RNTester/js/{ => assets}/slider-left@2x.png | Bin RNTester/js/{ => assets}/slider-right.png | Bin RNTester/js/{ => assets}/slider-right@2x.png | Bin RNTester/js/{ => assets}/slider.png | Bin RNTester/js/{ => assets}/slider@2x.png | Bin .../js/{Thumbnails => assets}/superlike.png | Bin .../trees.jpg | Bin .../tumblr_mfqekpMktw1rn90umo1_500.gif | Bin .../uie_comment_highlighted@2x.png | Bin .../js/{ => assets}/uie_comment_normal@2x.png | Bin RNTester/js/{ => assets}/uie_thumb_big.png | Bin .../js/{ => assets}/uie_thumb_normal@2x.png | Bin .../js/{ => assets}/uie_thumb_selected@2x.png | Bin .../js/{Thumbnails => assets}/victory.png | Bin .../js/{ => components}/ListExampleShared.js | 24 ++-- RNTester/js/{ => components}/RNTesterBlock.js | 0 .../js/{ => components}/RNTesterButton.js | 2 +- .../RNTesterExampleContainer.js | 0 .../{ => components}/RNTesterExampleFilter.js | 0 .../{ => components}/RNTesterExampleList.js | 6 +- RNTester/js/{ => components}/RNTesterPage.js | 0 .../RNTesterSettingSwitchRow.js | 2 +- RNTester/js/{ => components}/RNTesterTitle.js | 0 .../{Shared => components}/TextInlineView.js | 3 +- .../js/{Shared => components}/TextLegend.js | 0 .../js/{ => components}/createExamplePage.js | 2 +- RNTester/js/{ => examples/ART}/ARTExample.js | 0 .../AccessibilityAndroidExample.android.js | 4 +- .../Accessibility}/AccessibilityExample.js | 2 +- .../Accessibility}/AccessibilityIOSExample.js | 2 +- .../ActionSheetIOS}/ActionSheetIOSExample.js | 0 .../ActivityIndicatorExample.js | 0 .../js/{ => examples/Alert}/AlertExample.js | 2 +- .../{ => examples/Alert}/AlertIOSExample.js | 0 .../Animated}/AnimatedExample.js | 4 +- .../AnimatedGratuitousApp/AnExApp.js | 0 .../AnimatedGratuitousApp/AnExBobble.js | 0 .../AnimatedGratuitousApp/AnExChained.js | 10 +- .../AnimatedGratuitousApp/AnExScroll.js | 0 .../AnimatedGratuitousApp/AnExSet.js | 0 .../AnimatedGratuitousApp/AnExSlides.md | 0 .../AnimatedGratuitousApp/AnExTilt.js | 2 +- .../AppState}/AppStateExample.js | 0 .../AsyncStorage}/AsyncStorageExample.js | 0 .../js/{ => examples/Border}/BorderExample.js | 0 .../BoxShadow}/BoxShadowExample.js | 2 +- .../js/{ => examples/Button}/ButtonExample.js | 0 .../CheckBox}/CheckBoxExample.js | 0 .../Clipboard}/ClipboardExample.js | 0 .../js/{ => examples/Crash}/CrashExample.js | 0 .../DatePicker}/DatePickerAndroidExample.js | 4 +- .../DatePicker}/DatePickerIOSExample.js | 0 .../Dimensions}/DimensionsExample.js | 0 .../FlatList}/FlatListExample.js | 8 +- .../Image}/ImageCapInsetsExample.js | 2 +- .../js/{ => examples/Image}/ImageExample.js | 24 ++-- .../InputAccessoryViewExample.js | 0 .../KeyboardAvoidingViewExample.js | 4 +- .../Layout}/LayoutAnimationExample.js | 0 .../Layout}/LayoutEventsExample.js | 2 +- .../js/{ => examples/Layout}/LayoutExample.js | 4 +- .../{ => examples/Linking}/LinkingExample.js | 2 +- .../MaskedView}/MaskedViewExample.js | 2 +- .../js/{ => examples/Modal}/ModalExample.js | 0 .../MultiColumn}/MultiColumnExample.js | 6 +- .../NativeAnimationsExample.js | 12 +- .../NewAppScreen}/NewAppScreenExample.js | 2 +- .../OrientationChangeExample.js | 2 +- .../PanResponder}/PanResponderExample.js | 4 +- .../PermissionsAndroid/PermissionsExample.js} | 0 .../js/{ => examples/Picker}/PickerExample.js | 0 .../{ => examples/Picker}/PickerIOSExample.js | 0 .../PointerEvents}/PointerEventsExample.js | 0 .../ProgressBarAndroidExample.android.js | 6 +- .../ProgressViewIOSExample.js | 0 .../PushNotificationIOSExample.js | 0 .../RCTRootView}/RCTRootViewIOSExample.js | 0 RNTester/js/{ => examples/RTL}/RTLExample.js | 10 +- .../RefreshControl}/RefreshControlExample.js | 0 .../RootViewSizeFlexibilityExampleApp.js | 0 .../SafeAreaView}/SafeAreaViewExample.js | 0 .../ScrollView}/ScrollViewExample.js | 2 +- .../ScrollView}/ScrollViewSimpleExample.js | 0 .../SectionList}/SectionListExample.js | 6 +- .../SegmentedControlIOSExample.js | 0 .../SetPropertiesExampleApp.js | 0 .../js/{ => examples/Share}/ShareExample.js | 0 .../js/{ => examples/Slider}/SliderExample.js | 10 +- .../Snapshot}/SnapshotExample.js | 0 .../Snapshot}/SnapshotViewIOS.android.js | 2 +- .../Snapshot}/SnapshotViewIOS.ios.js | 6 +- .../StatusBar}/StatusBarExample.js | 0 .../js/{ => examples/Switch}/SwitchExample.js | 0 .../TVEventHandler}/TVEventHandlerExample.js | 0 .../Text}/TextExample.android.js | 8 +- .../js/{ => examples/Text}/TextExample.ios.js | 6 +- .../TextInput}/TextInputExample.android.js | 0 .../TextInput}/TextInputExample.ios.js | 0 .../TimePicker}/TimePickerAndroidExample.js | 4 +- .../js/{ => examples/Timer}/TimerExample.js | 2 +- .../ToastAndroidExample.android.js | 4 +- .../Touchable}/TouchableExample.js | 0 .../Transform}/TransformExample.js | 0 .../TransparentHitTestExample.js | 0 .../TurboModule}/SampleTurboModuleExample.js | 2 +- .../TurboModule}/TurboModuleExample.js | 0 .../Vibration}/VibrationExample.js | 0 .../js/{ => examples/View}/ViewExample.js | 0 .../ViewPagerAndroidExample.android.js | 2 +- .../WebSocket}/WebSocketExample.js | 4 +- .../WebSocket}/http_test_server.js | 0 .../WebSocket}/websocket_test_server.js | 0 RNTester/js/{ => examples/XHR}/XHRExample.js | 0 .../XHR}/XHRExampleAbortController.js | 0 .../XHR}/XHRExampleBinaryUpload.js | 0 .../{ => examples/XHR}/XHRExampleDownload.js | 0 .../js/{ => examples/XHR}/XHRExampleFetch.js | 0 .../{ => examples/XHR}/XHRExampleHeaders.js | 0 .../{ => examples/XHR}/XHRExampleOnTimeOut.js | 0 .../js/{Shared => types}/RNTesterTypes.js | 0 RNTester/js/{ => utils}/RNTesterActions.js | 0 .../js/{ => utils}/RNTesterList.android.js | 102 +++++++------- RNTester/js/{ => utils}/RNTesterList.ios.js | 126 +++++++++--------- .../{ => utils}/RNTesterNavigationReducer.js | 0 .../js/{ => utils}/RNTesterStatePersister.js | 0 RNTester/js/{ => utils}/URIActionMap.js | 0 148 files changed, 247 insertions(+), 354 deletions(-) delete mode 100644 RNTester/js/AssetScaledImageExample.js rename RNTester/js/{Thumbnails => assets}/bandaged.png (100%) rename RNTester/js/{ => assets}/bunny.png (100%) rename RNTester/js/{Thumbnails => assets}/call.png (100%) rename RNTester/js/{Thumbnails => assets}/dislike.png (100%) rename RNTester/js/{Thumbnails => assets}/fist.png (100%) rename RNTester/js/{Thumbnails => assets}/flowers.png (100%) rename RNTester/js/{ => assets}/flux@3x.png (100%) rename RNTester/js/{ => assets}/hawk.png (100%) rename RNTester/js/{Thumbnails => assets}/heart.png (100%) rename RNTester/js/{ => assets}/helloworld.html (100%) rename RNTester/js/{ => assets}/imageMask.png (100%) rename RNTester/js/{Thumbnails => assets}/like.png (100%) rename RNTester/js/{Thumbnails => assets}/liking.png (100%) rename RNTester/js/{ => assets}/messagingtest.html (100%) rename RNTester/js/{Thumbnails => assets}/party.png (100%) rename RNTester/js/{Thumbnails => assets}/poke.png (100%) rename RNTester/js/{ => assets}/relay@3x.png (100%) rename RNTester/js/{ => assets}/slider-left.png (100%) rename RNTester/js/{ => assets}/slider-left@2x.png (100%) rename RNTester/js/{ => assets}/slider-right.png (100%) rename RNTester/js/{ => assets}/slider-right@2x.png (100%) rename RNTester/js/{ => assets}/slider.png (100%) rename RNTester/js/{ => assets}/slider@2x.png (100%) rename RNTester/js/{Thumbnails => assets}/superlike.png (100%) rename RNTester/js/{AnimatedGratuitousApp => assets}/trees.jpg (100%) rename RNTester/js/{ => assets}/tumblr_mfqekpMktw1rn90umo1_500.gif (100%) rename RNTester/js/{ => assets}/uie_comment_highlighted@2x.png (100%) rename RNTester/js/{ => assets}/uie_comment_normal@2x.png (100%) rename RNTester/js/{ => assets}/uie_thumb_big.png (100%) rename RNTester/js/{ => assets}/uie_thumb_normal@2x.png (100%) rename RNTester/js/{ => assets}/uie_thumb_selected@2x.png (100%) rename RNTester/js/{Thumbnails => assets}/victory.png (100%) rename RNTester/js/{ => components}/ListExampleShared.js (94%) rename RNTester/js/{ => components}/RNTesterBlock.js (100%) rename RNTester/js/{ => components}/RNTesterButton.js (93%) rename RNTester/js/{ => components}/RNTesterExampleContainer.js (100%) rename RNTester/js/{ => components}/RNTesterExampleFilter.js (100%) rename RNTester/js/{ => components}/RNTesterExampleList.js (96%) rename RNTester/js/{ => components}/RNTesterPage.js (100%) rename RNTester/js/{ => components}/RNTesterSettingSwitchRow.js (95%) rename RNTester/js/{ => components}/RNTesterTitle.js (100%) rename RNTester/js/{Shared => components}/TextInlineView.js (98%) rename RNTester/js/{Shared => components}/TextLegend.js (100%) rename RNTester/js/{ => components}/createExamplePage.js (91%) rename RNTester/js/{ => examples/ART}/ARTExample.js (100%) rename RNTester/js/{ => examples/Accessibility}/AccessibilityAndroidExample.android.js (97%) rename RNTester/js/{ => examples/Accessibility}/AccessibilityExample.js (99%) rename RNTester/js/{ => examples/Accessibility}/AccessibilityIOSExample.js (96%) rename RNTester/js/{ => examples/ActionSheetIOS}/ActionSheetIOSExample.js (100%) rename RNTester/js/{ => examples/ActivityIndicator}/ActivityIndicatorExample.js (100%) rename RNTester/js/{ => examples/Alert}/AlertExample.js (98%) rename RNTester/js/{ => examples/Alert}/AlertIOSExample.js (100%) rename RNTester/js/{ => examples/Animated}/AnimatedExample.js (98%) rename RNTester/js/{ => examples/Animated}/AnimatedGratuitousApp/AnExApp.js (100%) rename RNTester/js/{ => examples/Animated}/AnimatedGratuitousApp/AnExBobble.js (100%) rename RNTester/js/{ => examples/Animated}/AnimatedGratuitousApp/AnExChained.js (93%) rename RNTester/js/{ => examples/Animated}/AnimatedGratuitousApp/AnExScroll.js (100%) rename RNTester/js/{ => examples/Animated}/AnimatedGratuitousApp/AnExSet.js (100%) rename RNTester/js/{ => examples/Animated}/AnimatedGratuitousApp/AnExSlides.md (100%) rename RNTester/js/{ => examples/Animated}/AnimatedGratuitousApp/AnExTilt.js (98%) rename RNTester/js/{ => examples/AppState}/AppStateExample.js (100%) rename RNTester/js/{ => examples/AsyncStorage}/AsyncStorageExample.js (100%) rename RNTester/js/{ => examples/Border}/BorderExample.js (100%) rename RNTester/js/{ => examples/BoxShadow}/BoxShadowExample.js (97%) rename RNTester/js/{ => examples/Button}/ButtonExample.js (100%) rename RNTester/js/{ => examples/CheckBox}/CheckBoxExample.js (100%) rename RNTester/js/{ => examples/Clipboard}/ClipboardExample.js (100%) rename RNTester/js/{ => examples/Crash}/CrashExample.js (100%) rename RNTester/js/{ => examples/DatePicker}/DatePickerAndroidExample.js (97%) rename RNTester/js/{ => examples/DatePicker}/DatePickerIOSExample.js (100%) rename RNTester/js/{ => examples/Dimensions}/DimensionsExample.js (100%) rename RNTester/js/{ => examples/FlatList}/FlatListExample.js (96%) rename RNTester/js/{ => examples/Image}/ImageCapInsetsExample.js (95%) rename RNTester/js/{ => examples/Image}/ImageExample.js (96%) rename RNTester/js/{ => examples/InputAccessoryView}/InputAccessoryViewExample.js (100%) rename RNTester/js/{ => examples/KeyboardAvoidingView}/KeyboardAvoidingViewExample.js (95%) rename RNTester/js/{ => examples/Layout}/LayoutAnimationExample.js (100%) rename RNTester/js/{ => examples/Layout}/LayoutEventsExample.js (98%) rename RNTester/js/{ => examples/Layout}/LayoutExample.js (97%) rename RNTester/js/{ => examples/Linking}/LinkingExample.js (97%) rename RNTester/js/{ => examples/MaskedView}/MaskedViewExample.js (98%) rename RNTester/js/{ => examples/Modal}/ModalExample.js (100%) rename RNTester/js/{ => examples/MultiColumn}/MultiColumnExample.js (96%) rename RNTester/js/{ => examples/NativeAnimation}/NativeAnimationsExample.js (98%) rename RNTester/js/{ => examples/NewAppScreen}/NewAppScreenExample.js (97%) rename RNTester/js/{ => examples/OrientationChange}/OrientationChangeExample.js (93%) rename RNTester/js/{ => examples/PanResponder}/PanResponderExample.js (96%) rename RNTester/js/{PermissionsExampleAndroid.android.js => examples/PermissionsAndroid/PermissionsExample.js} (100%) rename RNTester/js/{ => examples/Picker}/PickerExample.js (100%) rename RNTester/js/{ => examples/Picker}/PickerIOSExample.js (100%) rename RNTester/js/{ => examples/PointerEvents}/PointerEventsExample.js (100%) rename RNTester/js/{ => examples/ProgressBarAndroid}/ProgressBarAndroidExample.android.js (91%) rename RNTester/js/{ => examples/ProgressViewIOS}/ProgressViewIOSExample.js (100%) rename RNTester/js/{ => examples/PushNotificationIOS}/PushNotificationIOSExample.js (100%) rename RNTester/js/{ => examples/RCTRootView}/RCTRootViewIOSExample.js (100%) rename RNTester/js/{ => examples/RTL}/RTLExample.js (98%) rename RNTester/js/{ => examples/RefreshControl}/RefreshControlExample.js (100%) rename RNTester/js/{ => examples/RootViewSizeFlexibilityExample}/RootViewSizeFlexibilityExampleApp.js (100%) rename RNTester/js/{ => examples/SafeAreaView}/SafeAreaViewExample.js (100%) rename RNTester/js/{ => examples/ScrollView}/ScrollViewExample.js (99%) rename RNTester/js/{ => examples/ScrollView}/ScrollViewSimpleExample.js (100%) rename RNTester/js/{ => examples/SectionList}/SectionListExample.js (97%) rename RNTester/js/{ => examples/SegmentedControlIOS}/SegmentedControlIOSExample.js (100%) rename RNTester/js/{ => examples/SetPropertiesExample}/SetPropertiesExampleApp.js (100%) rename RNTester/js/{ => examples/Share}/ShareExample.js (100%) rename RNTester/js/{ => examples/Slider}/SliderExample.js (90%) rename RNTester/js/{ => examples/Snapshot}/SnapshotExample.js (100%) rename RNTester/js/{ => examples/Snapshot}/SnapshotViewIOS.android.js (68%) rename RNTester/js/{ => examples/Snapshot}/SnapshotViewIOS.ios.js (87%) rename RNTester/js/{ => examples/StatusBar}/StatusBarExample.js (100%) rename RNTester/js/{ => examples/Switch}/SwitchExample.js (100%) rename RNTester/js/{ => examples/TVEventHandler}/TVEventHandlerExample.js (100%) rename RNTester/js/{ => examples/Text}/TextExample.android.js (98%) rename RNTester/js/{ => examples/Text}/TextExample.ios.js (99%) rename RNTester/js/{ => examples/TextInput}/TextInputExample.android.js (100%) rename RNTester/js/{ => examples/TextInput}/TextInputExample.ios.js (100%) rename RNTester/js/{ => examples/TimePicker}/TimePickerAndroidExample.js (96%) rename RNTester/js/{ => examples/Timer}/TimerExample.js (99%) rename RNTester/js/{ => examples/ToastAndroid}/ToastAndroidExample.android.js (96%) rename RNTester/js/{ => examples/Touchable}/TouchableExample.js (100%) rename RNTester/js/{ => examples/Transform}/TransformExample.js (100%) rename RNTester/js/{ => examples/TransparentHitTest}/TransparentHitTestExample.js (100%) rename RNTester/js/{ => examples/TurboModule}/SampleTurboModuleExample.js (97%) rename RNTester/js/{ => examples/TurboModule}/TurboModuleExample.js (100%) rename RNTester/js/{ => examples/Vibration}/VibrationExample.js (100%) rename RNTester/js/{ => examples/View}/ViewExample.js (100%) rename RNTester/js/{ => examples/ViewPagerAndroid}/ViewPagerAndroidExample.android.js (98%) rename RNTester/js/{ => examples/WebSocket}/WebSocketExample.js (98%) rename RNTester/js/{ => examples/WebSocket}/http_test_server.js (100%) rename RNTester/js/{ => examples/WebSocket}/websocket_test_server.js (100%) rename RNTester/js/{ => examples/XHR}/XHRExample.js (100%) rename RNTester/js/{ => examples/XHR}/XHRExampleAbortController.js (100%) rename RNTester/js/{ => examples/XHR}/XHRExampleBinaryUpload.js (100%) rename RNTester/js/{ => examples/XHR}/XHRExampleDownload.js (100%) rename RNTester/js/{ => examples/XHR}/XHRExampleFetch.js (100%) rename RNTester/js/{ => examples/XHR}/XHRExampleHeaders.js (100%) rename RNTester/js/{ => examples/XHR}/XHRExampleOnTimeOut.js (100%) rename RNTester/js/{Shared => types}/RNTesterTypes.js (100%) rename RNTester/js/{ => utils}/RNTesterActions.js (100%) rename RNTester/js/{ => utils}/RNTesterList.android.js (51%) rename RNTester/js/{ => utils}/RNTesterList.ios.js (52%) rename RNTester/js/{ => utils}/RNTesterNavigationReducer.js (100%) rename RNTester/js/{ => utils}/RNTesterStatePersister.js (100%) rename RNTester/js/{ => utils}/URIActionMap.js (100%) diff --git a/.gitignore b/.gitignore index a70af1fa1efd11..361ac1a7a0120f 100644 --- a/.gitignore +++ b/.gitignore @@ -73,3 +73,4 @@ RNTester/build # CocoaPods /template/ios/Pods/ /template/ios/Podfile.lock +RNTester/RNTesterPods.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/RNTester/js/AssetScaledImageExample.js b/RNTester/js/AssetScaledImageExample.js deleted file mode 100644 index c066badad97a71..00000000000000 --- a/RNTester/js/AssetScaledImageExample.js +++ /dev/null @@ -1,113 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @flow strict-local - */ - -'use strict'; - -const React = require('react'); -const {Image, StyleSheet, View, ScrollView} = require('react-native'); - -type PhotoIdentifier = { - node: { - type: string, - group_name: string, - image: { - filename: string, - uri: string, - height: number, - width: number, - isStored?: boolean, - playableDuration: number, - }, - timestamp: number, - location?: { - latitude?: number, - longitude?: number, - altitude?: number, - heading?: number, - speed?: number, - }, - }, -}; - -type Props = $ReadOnly<{| - asset: PhotoIdentifier, -|}>; - -type State = {| - asset: PhotoIdentifier, -|}; - -class AssetScaledImageExample extends React.Component { - state = { - asset: this.props.asset, - }; - - render() { - const image = this.state.asset.node.image; - return ( - - - - - - - - - - - - - - - ); - } -} - -const styles = StyleSheet.create({ - row: { - padding: 5, - flex: 1, - flexDirection: 'row', - alignSelf: 'center', - }, - imageWide: { - borderWidth: 1, - borderColor: 'black', - width: 320, - height: 240, - margin: 5, - }, - imageThumb: { - borderWidth: 1, - borderColor: 'black', - width: 100, - height: 100, - margin: 5, - }, - imageT1: { - borderWidth: 1, - borderColor: 'black', - width: 212, - height: 320, - margin: 5, - }, - imageT2: { - borderWidth: 1, - borderColor: 'black', - width: 100, - height: 320, - margin: 5, - }, -}); - -exports.title = ''; -exports.description = - 'Example component that displays the automatic scaling capabilities of the tag'; -module.exports = AssetScaledImageExample; diff --git a/RNTester/js/RNTesterApp.android.js b/RNTester/js/RNTesterApp.android.js index e8085c2922d9c3..b87a9198b27430 100644 --- a/RNTester/js/RNTesterApp.android.js +++ b/RNTester/js/RNTesterApp.android.js @@ -26,18 +26,18 @@ const { UIManager, View, } = require('react-native'); -const RNTesterActions = require('./RNTesterActions'); -const RNTesterExampleContainer = require('./RNTesterExampleContainer'); -const RNTesterExampleList = require('./RNTesterExampleList'); +const RNTesterActions = require('./utils/RNTesterActions'); +const RNTesterExampleContainer = require('./components/RNTesterExampleContainer'); +const RNTesterExampleList = require('./components/RNTesterExampleList'); /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found when * making Flow check .android.js files. */ -const RNTesterList = require('./RNTesterList'); -const RNTesterNavigationReducer = require('./RNTesterNavigationReducer'); -const URIActionMap = require('./URIActionMap'); +const RNTesterList = require('./utils/RNTesterList'); +const RNTesterNavigationReducer = require('./utils/RNTesterNavigationReducer'); +const URIActionMap = require('./utils/URIActionMap'); const nativeImageSource = require('../../Libraries/Image/nativeImageSource'); -import type {RNTesterNavigationState} from './RNTesterNavigationReducer'; +import type {RNTesterNavigationState} from './utils/RNTesterNavigationReducer'; UIManager.setLayoutAnimationEnabledExperimental(true); diff --git a/RNTester/js/RNTesterApp.ios.js b/RNTester/js/RNTesterApp.ios.js index 411e352bd23d06..9645166d7b10ea 100644 --- a/RNTester/js/RNTesterApp.ios.js +++ b/RNTester/js/RNTesterApp.ios.js @@ -23,17 +23,17 @@ const { View, YellowBox, } = require('react-native'); -const RNTesterActions = require('./RNTesterActions'); -const RNTesterExampleContainer = require('./RNTesterExampleContainer'); -const RNTesterExampleList = require('./RNTesterExampleList'); -const RNTesterList = require('./RNTesterList.ios'); -const RNTesterNavigationReducer = require('./RNTesterNavigationReducer'); -const SnapshotViewIOS = require('./SnapshotViewIOS.ios'); -const URIActionMap = require('./URIActionMap'); - -import type {RNTesterExample} from './Shared/RNTesterTypes'; -import type {RNTesterAction} from './RNTesterActions'; -import type {RNTesterNavigationState} from './RNTesterNavigationReducer'; +const RNTesterActions = require('./utils/RNTesterActions'); +const RNTesterExampleContainer = require('./components/RNTesterExampleContainer'); +const RNTesterExampleList = require('./components/RNTesterExampleList'); +const RNTesterList = require('./utils/RNTesterList.ios'); +const RNTesterNavigationReducer = require('./utils/RNTesterNavigationReducer'); +const SnapshotViewIOS = require('./examples/Snapshot/SnapshotViewIOS.ios'); +const URIActionMap = require('./utils/URIActionMap'); + +import type {RNTesterExample} from './types/RNTesterTypes'; +import type {RNTesterAction} from './utils/RNTesterActions'; +import type {RNTesterNavigationState} from './utils/RNTesterNavigationReducer'; type Props = { exampleFromAppetizeParams: string, @@ -168,10 +168,10 @@ const styles = StyleSheet.create({ }); AppRegistry.registerComponent('SetPropertiesExampleApp', () => - require('./SetPropertiesExampleApp'), + require('./examples/SetPropertiesExample/SetPropertiesExampleApp'), ); AppRegistry.registerComponent('RootViewSizeFlexibilityExampleApp', () => - require('./RootViewSizeFlexibilityExampleApp'), + require('./examples/RootViewSizeFlexibilityExample/RootViewSizeFlexibilityExampleApp'), ); AppRegistry.registerComponent('RNTesterApp', () => RNTesterApp); diff --git a/RNTester/js/Thumbnails/bandaged.png b/RNTester/js/assets/bandaged.png similarity index 100% rename from RNTester/js/Thumbnails/bandaged.png rename to RNTester/js/assets/bandaged.png diff --git a/RNTester/js/bunny.png b/RNTester/js/assets/bunny.png similarity index 100% rename from RNTester/js/bunny.png rename to RNTester/js/assets/bunny.png diff --git a/RNTester/js/Thumbnails/call.png b/RNTester/js/assets/call.png similarity index 100% rename from RNTester/js/Thumbnails/call.png rename to RNTester/js/assets/call.png diff --git a/RNTester/js/Thumbnails/dislike.png b/RNTester/js/assets/dislike.png similarity index 100% rename from RNTester/js/Thumbnails/dislike.png rename to RNTester/js/assets/dislike.png diff --git a/RNTester/js/Thumbnails/fist.png b/RNTester/js/assets/fist.png similarity index 100% rename from RNTester/js/Thumbnails/fist.png rename to RNTester/js/assets/fist.png diff --git a/RNTester/js/Thumbnails/flowers.png b/RNTester/js/assets/flowers.png similarity index 100% rename from RNTester/js/Thumbnails/flowers.png rename to RNTester/js/assets/flowers.png diff --git a/RNTester/js/flux@3x.png b/RNTester/js/assets/flux@3x.png similarity index 100% rename from RNTester/js/flux@3x.png rename to RNTester/js/assets/flux@3x.png diff --git a/RNTester/js/hawk.png b/RNTester/js/assets/hawk.png similarity index 100% rename from RNTester/js/hawk.png rename to RNTester/js/assets/hawk.png diff --git a/RNTester/js/Thumbnails/heart.png b/RNTester/js/assets/heart.png similarity index 100% rename from RNTester/js/Thumbnails/heart.png rename to RNTester/js/assets/heart.png diff --git a/RNTester/js/helloworld.html b/RNTester/js/assets/helloworld.html similarity index 100% rename from RNTester/js/helloworld.html rename to RNTester/js/assets/helloworld.html diff --git a/RNTester/js/imageMask.png b/RNTester/js/assets/imageMask.png similarity index 100% rename from RNTester/js/imageMask.png rename to RNTester/js/assets/imageMask.png diff --git a/RNTester/js/Thumbnails/like.png b/RNTester/js/assets/like.png similarity index 100% rename from RNTester/js/Thumbnails/like.png rename to RNTester/js/assets/like.png diff --git a/RNTester/js/Thumbnails/liking.png b/RNTester/js/assets/liking.png similarity index 100% rename from RNTester/js/Thumbnails/liking.png rename to RNTester/js/assets/liking.png diff --git a/RNTester/js/messagingtest.html b/RNTester/js/assets/messagingtest.html similarity index 100% rename from RNTester/js/messagingtest.html rename to RNTester/js/assets/messagingtest.html diff --git a/RNTester/js/Thumbnails/party.png b/RNTester/js/assets/party.png similarity index 100% rename from RNTester/js/Thumbnails/party.png rename to RNTester/js/assets/party.png diff --git a/RNTester/js/Thumbnails/poke.png b/RNTester/js/assets/poke.png similarity index 100% rename from RNTester/js/Thumbnails/poke.png rename to RNTester/js/assets/poke.png diff --git a/RNTester/js/relay@3x.png b/RNTester/js/assets/relay@3x.png similarity index 100% rename from RNTester/js/relay@3x.png rename to RNTester/js/assets/relay@3x.png diff --git a/RNTester/js/slider-left.png b/RNTester/js/assets/slider-left.png similarity index 100% rename from RNTester/js/slider-left.png rename to RNTester/js/assets/slider-left.png diff --git a/RNTester/js/slider-left@2x.png b/RNTester/js/assets/slider-left@2x.png similarity index 100% rename from RNTester/js/slider-left@2x.png rename to RNTester/js/assets/slider-left@2x.png diff --git a/RNTester/js/slider-right.png b/RNTester/js/assets/slider-right.png similarity index 100% rename from RNTester/js/slider-right.png rename to RNTester/js/assets/slider-right.png diff --git a/RNTester/js/slider-right@2x.png b/RNTester/js/assets/slider-right@2x.png similarity index 100% rename from RNTester/js/slider-right@2x.png rename to RNTester/js/assets/slider-right@2x.png diff --git a/RNTester/js/slider.png b/RNTester/js/assets/slider.png similarity index 100% rename from RNTester/js/slider.png rename to RNTester/js/assets/slider.png diff --git a/RNTester/js/slider@2x.png b/RNTester/js/assets/slider@2x.png similarity index 100% rename from RNTester/js/slider@2x.png rename to RNTester/js/assets/slider@2x.png diff --git a/RNTester/js/Thumbnails/superlike.png b/RNTester/js/assets/superlike.png similarity index 100% rename from RNTester/js/Thumbnails/superlike.png rename to RNTester/js/assets/superlike.png diff --git a/RNTester/js/AnimatedGratuitousApp/trees.jpg b/RNTester/js/assets/trees.jpg similarity index 100% rename from RNTester/js/AnimatedGratuitousApp/trees.jpg rename to RNTester/js/assets/trees.jpg diff --git a/RNTester/js/tumblr_mfqekpMktw1rn90umo1_500.gif b/RNTester/js/assets/tumblr_mfqekpMktw1rn90umo1_500.gif similarity index 100% rename from RNTester/js/tumblr_mfqekpMktw1rn90umo1_500.gif rename to RNTester/js/assets/tumblr_mfqekpMktw1rn90umo1_500.gif diff --git a/RNTester/js/uie_comment_highlighted@2x.png b/RNTester/js/assets/uie_comment_highlighted@2x.png similarity index 100% rename from RNTester/js/uie_comment_highlighted@2x.png rename to RNTester/js/assets/uie_comment_highlighted@2x.png diff --git a/RNTester/js/uie_comment_normal@2x.png b/RNTester/js/assets/uie_comment_normal@2x.png similarity index 100% rename from RNTester/js/uie_comment_normal@2x.png rename to RNTester/js/assets/uie_comment_normal@2x.png diff --git a/RNTester/js/uie_thumb_big.png b/RNTester/js/assets/uie_thumb_big.png similarity index 100% rename from RNTester/js/uie_thumb_big.png rename to RNTester/js/assets/uie_thumb_big.png diff --git a/RNTester/js/uie_thumb_normal@2x.png b/RNTester/js/assets/uie_thumb_normal@2x.png similarity index 100% rename from RNTester/js/uie_thumb_normal@2x.png rename to RNTester/js/assets/uie_thumb_normal@2x.png diff --git a/RNTester/js/uie_thumb_selected@2x.png b/RNTester/js/assets/uie_thumb_selected@2x.png similarity index 100% rename from RNTester/js/uie_thumb_selected@2x.png rename to RNTester/js/assets/uie_thumb_selected@2x.png diff --git a/RNTester/js/Thumbnails/victory.png b/RNTester/js/assets/victory.png similarity index 100% rename from RNTester/js/Thumbnails/victory.png rename to RNTester/js/assets/victory.png diff --git a/RNTester/js/ListExampleShared.js b/RNTester/js/components/ListExampleShared.js similarity index 94% rename from RNTester/js/ListExampleShared.js rename to RNTester/js/components/ListExampleShared.js index 03d2f822276d85..43e4f9424d9011 100644 --- a/RNTester/js/ListExampleShared.js +++ b/RNTester/js/components/ListExampleShared.js @@ -181,18 +181,18 @@ class Spindicator extends React.PureComponent<$FlowFixMeProps> { } const THUMB_URLS = [ - require('./Thumbnails/like.png'), - require('./Thumbnails/dislike.png'), - require('./Thumbnails/call.png'), - require('./Thumbnails/fist.png'), - require('./Thumbnails/bandaged.png'), - require('./Thumbnails/flowers.png'), - require('./Thumbnails/heart.png'), - require('./Thumbnails/liking.png'), - require('./Thumbnails/party.png'), - require('./Thumbnails/poke.png'), - require('./Thumbnails/superlike.png'), - require('./Thumbnails/victory.png'), + require('../assets/like.png'), + require('../assets/dislike.png'), + require('../assets/call.png'), + require('../assets/fist.png'), + require('../assets/bandaged.png'), + require('../assets/flowers.png'), + require('../assets/heart.png'), + require('../assets/liking.png'), + require('../assets/party.png'), + require('../assets/poke.png'), + require('../assets/superlike.png'), + require('../assets/victory.png'), ]; const LOREM_IPSUM = diff --git a/RNTester/js/RNTesterBlock.js b/RNTester/js/components/RNTesterBlock.js similarity index 100% rename from RNTester/js/RNTesterBlock.js rename to RNTester/js/components/RNTesterBlock.js diff --git a/RNTester/js/RNTesterButton.js b/RNTester/js/components/RNTesterButton.js similarity index 93% rename from RNTester/js/RNTesterButton.js rename to RNTester/js/components/RNTesterButton.js index 398861a0be0339..543d52c6e0ae36 100644 --- a/RNTester/js/RNTesterButton.js +++ b/RNTester/js/components/RNTesterButton.js @@ -13,7 +13,7 @@ const React = require('react'); const {StyleSheet, Text, TouchableHighlight} = require('react-native'); -import type {PressEvent} from '../../Libraries/Types/CoreEventTypes'; +import type {PressEvent} from '../../../Libraries/Types/CoreEventTypes'; type Props = $ReadOnly<{| children?: React.Node, diff --git a/RNTester/js/RNTesterExampleContainer.js b/RNTester/js/components/RNTesterExampleContainer.js similarity index 100% rename from RNTester/js/RNTesterExampleContainer.js rename to RNTester/js/components/RNTesterExampleContainer.js diff --git a/RNTester/js/RNTesterExampleFilter.js b/RNTester/js/components/RNTesterExampleFilter.js similarity index 100% rename from RNTester/js/RNTesterExampleFilter.js rename to RNTester/js/components/RNTesterExampleFilter.js diff --git a/RNTester/js/RNTesterExampleList.js b/RNTester/js/components/RNTesterExampleList.js similarity index 96% rename from RNTester/js/RNTesterExampleList.js rename to RNTester/js/components/RNTesterExampleList.js index 9082b7a05c64ae..c3fe40a708678e 100644 --- a/RNTester/js/RNTesterExampleList.js +++ b/RNTester/js/components/RNTesterExampleList.js @@ -19,11 +19,11 @@ const { TouchableHighlight, View, } = require('react-native'); -const RNTesterActions = require('./RNTesterActions'); +const RNTesterActions = require('../utils/RNTesterActions'); const RNTesterExampleFilter = require('./RNTesterExampleFilter'); -import type {RNTesterExample} from './Shared/RNTesterTypes'; -import type {ViewStyleProp} from '../../Libraries/StyleSheet/StyleSheet'; +import type {RNTesterExample} from '../types/RNTesterTypes'; +import type {ViewStyleProp} from '../../../Libraries/StyleSheet/StyleSheet'; type Props = { onNavigate: Function, diff --git a/RNTester/js/RNTesterPage.js b/RNTester/js/components/RNTesterPage.js similarity index 100% rename from RNTester/js/RNTesterPage.js rename to RNTester/js/components/RNTesterPage.js diff --git a/RNTester/js/RNTesterSettingSwitchRow.js b/RNTester/js/components/RNTesterSettingSwitchRow.js similarity index 95% rename from RNTester/js/RNTesterSettingSwitchRow.js rename to RNTester/js/components/RNTesterSettingSwitchRow.js index 4667ed18081e8c..983ff5f4fe0d69 100644 --- a/RNTester/js/RNTesterSettingSwitchRow.js +++ b/RNTester/js/components/RNTesterSettingSwitchRow.js @@ -12,7 +12,7 @@ const React = require('react'); const {StyleSheet, Switch, Text, View} = require('react-native'); -const RNTesterStatePersister = require('./RNTesterStatePersister'); +const RNTesterStatePersister = require('../utils/RNTesterStatePersister'); class RNTesterSettingSwitchRow extends React.Component< $FlowFixMeProps, diff --git a/RNTester/js/RNTesterTitle.js b/RNTester/js/components/RNTesterTitle.js similarity index 100% rename from RNTester/js/RNTesterTitle.js rename to RNTester/js/components/RNTesterTitle.js diff --git a/RNTester/js/Shared/TextInlineView.js b/RNTester/js/components/TextInlineView.js similarity index 98% rename from RNTester/js/Shared/TextInlineView.js rename to RNTester/js/components/TextInlineView.js index 9cb8e13aded1ff..d69f5b10507833 100644 --- a/RNTester/js/Shared/TextInlineView.js +++ b/RNTester/js/components/TextInlineView.js @@ -18,7 +18,8 @@ function Basic() { This text contains an inline blue view{' '} and - an inline image . Neat, huh? + an inline image . Neat, + huh? ); } diff --git a/RNTester/js/Shared/TextLegend.js b/RNTester/js/components/TextLegend.js similarity index 100% rename from RNTester/js/Shared/TextLegend.js rename to RNTester/js/components/TextLegend.js diff --git a/RNTester/js/createExamplePage.js b/RNTester/js/components/createExamplePage.js similarity index 91% rename from RNTester/js/createExamplePage.js rename to RNTester/js/components/createExamplePage.js index 1b70fe5a91e9be..05db48f0ad9718 100644 --- a/RNTester/js/createExamplePage.js +++ b/RNTester/js/components/createExamplePage.js @@ -13,7 +13,7 @@ const React = require('react'); const RNTesterExampleContainer = require('./RNTesterExampleContainer'); -import type {RNTesterExample} from './Shared/RNTesterTypes'; +import type {RNTesterExample} from '../types/RNTesterTypes'; const createExamplePage = function( title: ?string, diff --git a/RNTester/js/ARTExample.js b/RNTester/js/examples/ART/ARTExample.js similarity index 100% rename from RNTester/js/ARTExample.js rename to RNTester/js/examples/ART/ARTExample.js diff --git a/RNTester/js/AccessibilityAndroidExample.android.js b/RNTester/js/examples/Accessibility/AccessibilityAndroidExample.android.js similarity index 97% rename from RNTester/js/AccessibilityAndroidExample.android.js rename to RNTester/js/examples/Accessibility/AccessibilityAndroidExample.android.js index a2a0a6cd6a1ab0..d09389478b9311 100644 --- a/RNTester/js/AccessibilityAndroidExample.android.js +++ b/RNTester/js/examples/Accessibility/AccessibilityAndroidExample.android.js @@ -17,8 +17,8 @@ const { TouchableWithoutFeedback, } = require('react-native'); -const RNTesterBlock = require('./RNTesterBlock'); -const RNTesterPage = require('./RNTesterPage'); +const RNTesterBlock = require('../../components/RNTesterBlock'); +const RNTesterPage = require('../../components/RNTesterPage'); const importantForAccessibilityValues = [ 'auto', diff --git a/RNTester/js/AccessibilityExample.js b/RNTester/js/examples/Accessibility/AccessibilityExample.js similarity index 99% rename from RNTester/js/AccessibilityExample.js rename to RNTester/js/examples/Accessibility/AccessibilityExample.js index a12602c5291c59..649279f0be9f6d 100644 --- a/RNTester/js/AccessibilityExample.js +++ b/RNTester/js/examples/Accessibility/AccessibilityExample.js @@ -22,7 +22,7 @@ const { Platform, } = require('react-native'); -const RNTesterBlock = require('./RNTesterBlock'); +const RNTesterBlock = require('../../components/RNTesterBlock'); class AccessibilityExample extends React.Component { render() { diff --git a/RNTester/js/AccessibilityIOSExample.js b/RNTester/js/examples/Accessibility/AccessibilityIOSExample.js similarity index 96% rename from RNTester/js/AccessibilityIOSExample.js rename to RNTester/js/examples/Accessibility/AccessibilityIOSExample.js index 0bcabc91c1c2a7..1ca8e44f54f679 100644 --- a/RNTester/js/AccessibilityIOSExample.js +++ b/RNTester/js/examples/Accessibility/AccessibilityIOSExample.js @@ -13,7 +13,7 @@ const React = require('react'); const {Text, View, Alert} = require('react-native'); -const RNTesterBlock = require('./RNTesterBlock'); +const RNTesterBlock = require('../../components/RNTesterBlock'); type Props = $ReadOnly<{||}>; class AccessibilityIOSExample extends React.Component { diff --git a/RNTester/js/ActionSheetIOSExample.js b/RNTester/js/examples/ActionSheetIOS/ActionSheetIOSExample.js similarity index 100% rename from RNTester/js/ActionSheetIOSExample.js rename to RNTester/js/examples/ActionSheetIOS/ActionSheetIOSExample.js diff --git a/RNTester/js/ActivityIndicatorExample.js b/RNTester/js/examples/ActivityIndicator/ActivityIndicatorExample.js similarity index 100% rename from RNTester/js/ActivityIndicatorExample.js rename to RNTester/js/examples/ActivityIndicator/ActivityIndicatorExample.js diff --git a/RNTester/js/AlertExample.js b/RNTester/js/examples/Alert/AlertExample.js similarity index 98% rename from RNTester/js/AlertExample.js rename to RNTester/js/examples/Alert/AlertExample.js index 123dac52ed1b6e..4e362a525f91f9 100644 --- a/RNTester/js/AlertExample.js +++ b/RNTester/js/examples/Alert/AlertExample.js @@ -18,7 +18,7 @@ const { View, } = require('react-native'); -const RNTesterBlock = require('./RNTesterBlock'); +const RNTesterBlock = require('../../components/RNTesterBlock'); // corporate ipsum > lorem ipsum const alertMessage = diff --git a/RNTester/js/AlertIOSExample.js b/RNTester/js/examples/Alert/AlertIOSExample.js similarity index 100% rename from RNTester/js/AlertIOSExample.js rename to RNTester/js/examples/Alert/AlertIOSExample.js diff --git a/RNTester/js/AnimatedExample.js b/RNTester/js/examples/Animated/AnimatedExample.js similarity index 98% rename from RNTester/js/AnimatedExample.js rename to RNTester/js/examples/Animated/AnimatedExample.js index 6513a346e535fb..409c4f00b08dcf 100644 --- a/RNTester/js/AnimatedExample.js +++ b/RNTester/js/examples/Animated/AnimatedExample.js @@ -12,7 +12,7 @@ const React = require('react'); const {Animated, Easing, StyleSheet, Text, View} = require('react-native'); -const RNTesterButton = require('./RNTesterButton'); +const RNTesterButton = require('../../components/RNTesterButton'); const styles = StyleSheet.create({ content: { @@ -259,7 +259,7 @@ exports.examples = [ Press to Spin it! { }, ], }} - source={require('./trees.jpg')} + source={require('../../../assets/trees.jpg')} /> ); diff --git a/RNTester/js/AppStateExample.js b/RNTester/js/examples/AppState/AppStateExample.js similarity index 100% rename from RNTester/js/AppStateExample.js rename to RNTester/js/examples/AppState/AppStateExample.js diff --git a/RNTester/js/AsyncStorageExample.js b/RNTester/js/examples/AsyncStorage/AsyncStorageExample.js similarity index 100% rename from RNTester/js/AsyncStorageExample.js rename to RNTester/js/examples/AsyncStorage/AsyncStorageExample.js diff --git a/RNTester/js/BorderExample.js b/RNTester/js/examples/Border/BorderExample.js similarity index 100% rename from RNTester/js/BorderExample.js rename to RNTester/js/examples/Border/BorderExample.js diff --git a/RNTester/js/BoxShadowExample.js b/RNTester/js/examples/BoxShadow/BoxShadowExample.js similarity index 97% rename from RNTester/js/BoxShadowExample.js rename to RNTester/js/examples/BoxShadow/BoxShadowExample.js index b383da6a97673a..5801cf3f5ad4ae 100644 --- a/RNTester/js/BoxShadowExample.js +++ b/RNTester/js/examples/BoxShadow/BoxShadowExample.js @@ -79,7 +79,7 @@ exports.examples = [ render() { return ( ); diff --git a/RNTester/js/ButtonExample.js b/RNTester/js/examples/Button/ButtonExample.js similarity index 100% rename from RNTester/js/ButtonExample.js rename to RNTester/js/examples/Button/ButtonExample.js diff --git a/RNTester/js/CheckBoxExample.js b/RNTester/js/examples/CheckBox/CheckBoxExample.js similarity index 100% rename from RNTester/js/CheckBoxExample.js rename to RNTester/js/examples/CheckBox/CheckBoxExample.js diff --git a/RNTester/js/ClipboardExample.js b/RNTester/js/examples/Clipboard/ClipboardExample.js similarity index 100% rename from RNTester/js/ClipboardExample.js rename to RNTester/js/examples/Clipboard/ClipboardExample.js diff --git a/RNTester/js/CrashExample.js b/RNTester/js/examples/Crash/CrashExample.js similarity index 100% rename from RNTester/js/CrashExample.js rename to RNTester/js/examples/Crash/CrashExample.js diff --git a/RNTester/js/DatePickerAndroidExample.js b/RNTester/js/examples/DatePicker/DatePickerAndroidExample.js similarity index 97% rename from RNTester/js/DatePickerAndroidExample.js rename to RNTester/js/examples/DatePicker/DatePickerAndroidExample.js index 23f16cb91be7f8..e52037f5aebcfa 100644 --- a/RNTester/js/DatePickerAndroidExample.js +++ b/RNTester/js/examples/DatePicker/DatePickerAndroidExample.js @@ -17,8 +17,8 @@ const { TouchableWithoutFeedback, } = require('react-native'); -const RNTesterBlock = require('./RNTesterBlock'); -const RNTesterPage = require('./RNTesterPage'); +const RNTesterBlock = require('../../components/RNTesterBlock'); +const RNTesterPage = require('../../components/RNTesterPage'); type Props = $ReadOnly<{||}>; type State = {| diff --git a/RNTester/js/DatePickerIOSExample.js b/RNTester/js/examples/DatePicker/DatePickerIOSExample.js similarity index 100% rename from RNTester/js/DatePickerIOSExample.js rename to RNTester/js/examples/DatePicker/DatePickerIOSExample.js diff --git a/RNTester/js/DimensionsExample.js b/RNTester/js/examples/Dimensions/DimensionsExample.js similarity index 100% rename from RNTester/js/DimensionsExample.js rename to RNTester/js/examples/Dimensions/DimensionsExample.js diff --git a/RNTester/js/FlatListExample.js b/RNTester/js/examples/FlatList/FlatListExample.js similarity index 96% rename from RNTester/js/FlatListExample.js rename to RNTester/js/examples/FlatList/FlatListExample.js index 733f0737f0fe77..e62bce5c6e42cf 100644 --- a/RNTester/js/FlatListExample.js +++ b/RNTester/js/examples/FlatList/FlatListExample.js @@ -10,14 +10,14 @@ 'use strict'; -import type {Item} from './ListExampleShared'; +import type {Item} from '../../components/ListExampleShared'; const React = require('react'); const {Alert, Animated, StyleSheet, View} = require('react-native'); -const RNTesterPage = require('./RNTesterPage'); +const RNTesterPage = require('../../components/RNTesterPage'); -const infoLog = require('../../Libraries/Utilities/infoLog'); +const infoLog = require('../../../../Libraries/Utilities/infoLog'); const { FooterComponent, @@ -32,7 +32,7 @@ const { getItemLayout, pressItem, renderSmallSwitchOption, -} = require('./ListExampleShared'); +} = require('../../components/ListExampleShared'); const VIEWABILITY_CONFIG = { minimumViewTime: 3000, diff --git a/RNTester/js/ImageCapInsetsExample.js b/RNTester/js/examples/Image/ImageCapInsetsExample.js similarity index 95% rename from RNTester/js/ImageCapInsetsExample.js rename to RNTester/js/examples/Image/ImageCapInsetsExample.js index ca95d454e0e369..4524e99c5e8c96 100644 --- a/RNTester/js/ImageCapInsetsExample.js +++ b/RNTester/js/examples/Image/ImageCapInsetsExample.js @@ -13,7 +13,7 @@ const React = require('react'); const ReactNative = require('react-native'); -const nativeImageSource = require('../../Libraries/Image/nativeImageSource'); +const nativeImageSource = require('../../../../Libraries/Image/nativeImageSource'); const {Image, StyleSheet, Text, View} = ReactNative; type Props = $ReadOnly<{||}>; diff --git a/RNTester/js/ImageExample.js b/RNTester/js/examples/Image/ImageExample.js similarity index 96% rename from RNTester/js/ImageExample.js rename to RNTester/js/examples/Image/ImageExample.js index 82cfc8b5c21582..c3aaa8418ffb7e 100644 --- a/RNTester/js/ImageExample.js +++ b/RNTester/js/examples/Image/ImageExample.js @@ -424,19 +424,19 @@ exports.examples = [ return ( @@ -490,7 +490,7 @@ exports.examples = [ render: function() { return ( ); }, diff --git a/RNTester/js/InputAccessoryViewExample.js b/RNTester/js/examples/InputAccessoryView/InputAccessoryViewExample.js similarity index 100% rename from RNTester/js/InputAccessoryViewExample.js rename to RNTester/js/examples/InputAccessoryView/InputAccessoryViewExample.js diff --git a/RNTester/js/KeyboardAvoidingViewExample.js b/RNTester/js/examples/KeyboardAvoidingView/KeyboardAvoidingViewExample.js similarity index 95% rename from RNTester/js/KeyboardAvoidingViewExample.js rename to RNTester/js/examples/KeyboardAvoidingView/KeyboardAvoidingViewExample.js index caa5401dc3e1e5..0e07f955b149c9 100644 --- a/RNTester/js/KeyboardAvoidingViewExample.js +++ b/RNTester/js/examples/KeyboardAvoidingView/KeyboardAvoidingViewExample.js @@ -21,8 +21,8 @@ const { View, } = require('react-native'); -const RNTesterBlock = require('./RNTesterBlock'); -const RNTesterPage = require('./RNTesterPage'); +const RNTesterBlock = require('../../components/RNTesterBlock'); +const RNTesterPage = require('../../components/RNTesterPage'); type Props = $ReadOnly<{||}>; type State = {| diff --git a/RNTester/js/LayoutAnimationExample.js b/RNTester/js/examples/Layout/LayoutAnimationExample.js similarity index 100% rename from RNTester/js/LayoutAnimationExample.js rename to RNTester/js/examples/Layout/LayoutAnimationExample.js diff --git a/RNTester/js/LayoutEventsExample.js b/RNTester/js/examples/Layout/LayoutEventsExample.js similarity index 98% rename from RNTester/js/LayoutEventsExample.js rename to RNTester/js/examples/Layout/LayoutEventsExample.js index 74a285e25d9a13..b556c272d17f51 100644 --- a/RNTester/js/LayoutEventsExample.js +++ b/RNTester/js/examples/Layout/LayoutEventsExample.js @@ -22,7 +22,7 @@ const { import type { ViewLayout, ViewLayoutEvent, -} from '../../Libraries/Components/View/ViewPropTypes'; +} from '../../../../Libraries/Components/View/ViewPropTypes'; type Props = $ReadOnly<{||}>; type State = { diff --git a/RNTester/js/LayoutExample.js b/RNTester/js/examples/Layout/LayoutExample.js similarity index 97% rename from RNTester/js/LayoutExample.js rename to RNTester/js/examples/Layout/LayoutExample.js index 4d5f085207bda9..1d2050effcbe6c 100644 --- a/RNTester/js/LayoutExample.js +++ b/RNTester/js/examples/Layout/LayoutExample.js @@ -13,8 +13,8 @@ const React = require('react'); const {StyleSheet, Text, View} = require('react-native'); -const RNTesterBlock = require('./RNTesterBlock'); -const RNTesterPage = require('./RNTesterPage'); +const RNTesterBlock = require('../../components/RNTesterBlock'); +const RNTesterPage = require('../../components/RNTesterPage'); class Circle extends React.Component<$FlowFixMeProps> { render() { diff --git a/RNTester/js/LinkingExample.js b/RNTester/js/examples/Linking/LinkingExample.js similarity index 97% rename from RNTester/js/LinkingExample.js rename to RNTester/js/examples/Linking/LinkingExample.js index 32ae2bc990e836..df63aadce14ca7 100644 --- a/RNTester/js/LinkingExample.js +++ b/RNTester/js/examples/Linking/LinkingExample.js @@ -20,7 +20,7 @@ const { View, } = require('react-native'); -const RNTesterBlock = require('./RNTesterBlock'); +const RNTesterBlock = require('../../components/RNTesterBlock'); type Props = $ReadOnly<{| url?: ?string, diff --git a/RNTester/js/MaskedViewExample.js b/RNTester/js/examples/MaskedView/MaskedViewExample.js similarity index 98% rename from RNTester/js/MaskedViewExample.js rename to RNTester/js/examples/MaskedView/MaskedViewExample.js index 238a22c7d9a605..22dd6e1aaa5802 100644 --- a/RNTester/js/MaskedViewExample.js +++ b/RNTester/js/examples/MaskedView/MaskedViewExample.js @@ -198,7 +198,7 @@ exports.examples = [ }> diff --git a/RNTester/js/ModalExample.js b/RNTester/js/examples/Modal/ModalExample.js similarity index 100% rename from RNTester/js/ModalExample.js rename to RNTester/js/examples/Modal/ModalExample.js diff --git a/RNTester/js/MultiColumnExample.js b/RNTester/js/examples/MultiColumn/MultiColumnExample.js similarity index 96% rename from RNTester/js/MultiColumnExample.js rename to RNTester/js/examples/MultiColumn/MultiColumnExample.js index 435e2d465a925b..f79ea22a0697ae 100644 --- a/RNTester/js/MultiColumnExample.js +++ b/RNTester/js/examples/MultiColumn/MultiColumnExample.js @@ -13,9 +13,9 @@ const React = require('react'); const {FlatList, StyleSheet, Text, View, Alert} = require('react-native'); -const RNTesterPage = require('./RNTesterPage'); +const RNTesterPage = require('../../components/RNTesterPage'); -const infoLog = require('../../Libraries/Utilities/infoLog'); +const infoLog = require('../../../../Libraries/Utilities/infoLog'); const { FooterComponent, @@ -27,7 +27,7 @@ const { getItemLayout, pressItem, renderSmallSwitchOption, -} = require('./ListExampleShared'); +} = require('../../components/ListExampleShared'); class MultiColumnExample extends React.PureComponent< $FlowFixMeProps, diff --git a/RNTester/js/NativeAnimationsExample.js b/RNTester/js/examples/NativeAnimation/NativeAnimationsExample.js similarity index 98% rename from RNTester/js/NativeAnimationsExample.js rename to RNTester/js/examples/NativeAnimation/NativeAnimationsExample.js index 41c229c15e0168..2e1fcd22b78c29 100644 --- a/RNTester/js/NativeAnimationsExample.js +++ b/RNTester/js/examples/NativeAnimation/NativeAnimationsExample.js @@ -154,7 +154,7 @@ class LoopExample extends React.Component<{}, $FlowFixMeState> { } } -const RNTesterSettingSwitchRow = require('./RNTesterSettingSwitchRow'); +const RNTesterSettingSwitchRow = require('../../components/RNTesterSettingSwitchRow'); class InternalSettings extends React.Component< {}, {busyTime: number | string, filteredStall: number}, @@ -187,11 +187,13 @@ class InternalSettings extends React.Component< initialValue={false} label="Track JS Stalls" onEnable={() => { - require('../../Libraries/Interaction/JSEventLoopWatchdog').install({ - thresholdMS: 25, - }); + require('../../../../Libraries/Interaction/JSEventLoopWatchdog').install( + { + thresholdMS: 25, + }, + ); this.setState({busyTime: ''}); - require('../../Libraries/Interaction/JSEventLoopWatchdog').addHandler( + require('../../../../Libraries/Interaction/JSEventLoopWatchdog').addHandler( { onStall: ({busyTime}) => this.setState(state => ({ diff --git a/RNTester/js/NewAppScreenExample.js b/RNTester/js/examples/NewAppScreen/NewAppScreenExample.js similarity index 97% rename from RNTester/js/NewAppScreenExample.js rename to RNTester/js/examples/NewAppScreen/NewAppScreenExample.js index 0b75f826f43eb7..8136f601f4a693 100644 --- a/RNTester/js/NewAppScreenExample.js +++ b/RNTester/js/examples/NewAppScreen/NewAppScreenExample.js @@ -18,7 +18,7 @@ const { Colors, DebugInstructions, ReloadInstructions, -} = require('../../Libraries/NewAppScreen'); +} = require('../../../../Libraries/NewAppScreen'); exports.title = 'New App Screen'; exports.description = 'Displays the content of the new app screen'; diff --git a/RNTester/js/OrientationChangeExample.js b/RNTester/js/examples/OrientationChange/OrientationChangeExample.js similarity index 93% rename from RNTester/js/OrientationChangeExample.js rename to RNTester/js/examples/OrientationChange/OrientationChangeExample.js index ceb4fdc436a2ec..509ab84b0dc598 100644 --- a/RNTester/js/OrientationChangeExample.js +++ b/RNTester/js/examples/OrientationChange/OrientationChangeExample.js @@ -13,7 +13,7 @@ const React = require('react'); const {DeviceEventEmitter, Text, View} = require('react-native'); -import type EmitterSubscription from '../../Libraries/vendor/emitter/EmitterSubscription'; +import type EmitterSubscription from '../../../../Libraries/vendor/emitter/EmitterSubscription'; class OrientationChangeExample extends React.Component<{}, $FlowFixMeState> { _orientationSubscription: EmitterSubscription; diff --git a/RNTester/js/PanResponderExample.js b/RNTester/js/examples/PanResponder/PanResponderExample.js similarity index 96% rename from RNTester/js/PanResponderExample.js rename to RNTester/js/examples/PanResponder/PanResponderExample.js index fddb5631e9e8f5..3526dbb8cf6b49 100644 --- a/RNTester/js/PanResponderExample.js +++ b/RNTester/js/examples/PanResponder/PanResponderExample.js @@ -16,8 +16,8 @@ const {PanResponder, StyleSheet, View} = require('react-native'); import type { PanResponderInstance, GestureState, -} from '../../Libraries/Interaction/PanResponder'; -import type {PressEvent} from '../../Libraries/Types/CoreEventTypes'; +} from '../../../../Libraries/Interaction/PanResponder'; +import type {PressEvent} from '../../../../Libraries/Types/CoreEventTypes'; type CircleStyles = { backgroundColor?: string, diff --git a/RNTester/js/PermissionsExampleAndroid.android.js b/RNTester/js/examples/PermissionsAndroid/PermissionsExample.js similarity index 100% rename from RNTester/js/PermissionsExampleAndroid.android.js rename to RNTester/js/examples/PermissionsAndroid/PermissionsExample.js diff --git a/RNTester/js/PickerExample.js b/RNTester/js/examples/Picker/PickerExample.js similarity index 100% rename from RNTester/js/PickerExample.js rename to RNTester/js/examples/Picker/PickerExample.js diff --git a/RNTester/js/PickerIOSExample.js b/RNTester/js/examples/Picker/PickerIOSExample.js similarity index 100% rename from RNTester/js/PickerIOSExample.js rename to RNTester/js/examples/Picker/PickerIOSExample.js diff --git a/RNTester/js/PointerEventsExample.js b/RNTester/js/examples/PointerEvents/PointerEventsExample.js similarity index 100% rename from RNTester/js/PointerEventsExample.js rename to RNTester/js/examples/PointerEvents/PointerEventsExample.js diff --git a/RNTester/js/ProgressBarAndroidExample.android.js b/RNTester/js/examples/ProgressBarAndroid/ProgressBarAndroidExample.android.js similarity index 91% rename from RNTester/js/ProgressBarAndroidExample.android.js rename to RNTester/js/examples/ProgressBarAndroid/ProgressBarAndroidExample.android.js index 29050e9f010507..86a6bd662c5515 100644 --- a/RNTester/js/ProgressBarAndroidExample.android.js +++ b/RNTester/js/examples/ProgressBarAndroid/ProgressBarAndroidExample.android.js @@ -12,10 +12,10 @@ const React = require('react'); const {ProgressBarAndroid: ProgressBar} = require('react-native'); -const RNTesterBlock = require('./RNTesterBlock'); -const RNTesterPage = require('./RNTesterPage'); +const RNTesterBlock = require('../../components/RNTesterBlock'); +const RNTesterPage = require('../../components/RNTesterPage'); -import type {ProgressBarAndroidProps} from '../../Libraries/Components/ProgressBarAndroid/ProgressBarAndroid'; +import type {ProgressBarAndroidProps} from '../../../../Libraries/Components/ProgressBarAndroid/ProgressBarAndroid'; type MovingBarProps = $ReadOnly<{| ...$Diff< diff --git a/RNTester/js/ProgressViewIOSExample.js b/RNTester/js/examples/ProgressViewIOS/ProgressViewIOSExample.js similarity index 100% rename from RNTester/js/ProgressViewIOSExample.js rename to RNTester/js/examples/ProgressViewIOS/ProgressViewIOSExample.js diff --git a/RNTester/js/PushNotificationIOSExample.js b/RNTester/js/examples/PushNotificationIOS/PushNotificationIOSExample.js similarity index 100% rename from RNTester/js/PushNotificationIOSExample.js rename to RNTester/js/examples/PushNotificationIOS/PushNotificationIOSExample.js diff --git a/RNTester/js/RCTRootViewIOSExample.js b/RNTester/js/examples/RCTRootView/RCTRootViewIOSExample.js similarity index 100% rename from RNTester/js/RCTRootViewIOSExample.js rename to RNTester/js/examples/RCTRootView/RCTRootViewIOSExample.js diff --git a/RNTester/js/RTLExample.js b/RNTester/js/examples/RTL/RTLExample.js similarity index 98% rename from RNTester/js/RTLExample.js rename to RNTester/js/examples/RTL/RTLExample.js index 38462ee5bfabe7..fe26776e526642 100644 --- a/RNTester/js/RTLExample.js +++ b/RNTester/js/examples/RTL/RTLExample.js @@ -99,7 +99,7 @@ const IconsExample = withRTLState(({isRTL, setRTL}) => { @@ -108,7 +108,7 @@ const IconsExample = withRTLState(({isRTL, setRTL}) => { @@ -126,7 +126,7 @@ function AnimationBlock(props) { @@ -219,8 +219,8 @@ const SimpleListItemExample = withRTLState(({isRTL, setRTL}) => { - - + + ); diff --git a/RNTester/js/RefreshControlExample.js b/RNTester/js/examples/RefreshControl/RefreshControlExample.js similarity index 100% rename from RNTester/js/RefreshControlExample.js rename to RNTester/js/examples/RefreshControl/RefreshControlExample.js diff --git a/RNTester/js/RootViewSizeFlexibilityExampleApp.js b/RNTester/js/examples/RootViewSizeFlexibilityExample/RootViewSizeFlexibilityExampleApp.js similarity index 100% rename from RNTester/js/RootViewSizeFlexibilityExampleApp.js rename to RNTester/js/examples/RootViewSizeFlexibilityExample/RootViewSizeFlexibilityExampleApp.js diff --git a/RNTester/js/SafeAreaViewExample.js b/RNTester/js/examples/SafeAreaView/SafeAreaViewExample.js similarity index 100% rename from RNTester/js/SafeAreaViewExample.js rename to RNTester/js/examples/SafeAreaView/SafeAreaViewExample.js diff --git a/RNTester/js/ScrollViewExample.js b/RNTester/js/examples/ScrollView/ScrollViewExample.js similarity index 99% rename from RNTester/js/ScrollViewExample.js rename to RNTester/js/examples/ScrollView/ScrollViewExample.js index c6c28afb1e2b47..8b975df5172211 100644 --- a/RNTester/js/ScrollViewExample.js +++ b/RNTester/js/examples/ScrollView/ScrollViewExample.js @@ -19,7 +19,7 @@ const { View, } = require('react-native'); -import type {ViewStyleProp} from '../../Libraries/StyleSheet/StyleSheet'; +import type {ViewStyleProp} from '../../../../Libraries/StyleSheet/StyleSheet'; exports.displayName = 'ScrollViewExample'; exports.title = ''; diff --git a/RNTester/js/ScrollViewSimpleExample.js b/RNTester/js/examples/ScrollView/ScrollViewSimpleExample.js similarity index 100% rename from RNTester/js/ScrollViewSimpleExample.js rename to RNTester/js/examples/ScrollView/ScrollViewSimpleExample.js diff --git a/RNTester/js/SectionListExample.js b/RNTester/js/examples/SectionList/SectionListExample.js similarity index 97% rename from RNTester/js/SectionListExample.js rename to RNTester/js/examples/SectionList/SectionListExample.js index 11c49aa8e4f0aa..76e131f5c97640 100644 --- a/RNTester/js/SectionListExample.js +++ b/RNTester/js/examples/SectionList/SectionListExample.js @@ -20,9 +20,9 @@ const { View, } = require('react-native'); -const RNTesterPage = require('./RNTesterPage'); +const RNTesterPage = require('../../components/RNTesterPage'); -const infoLog = require('../../Libraries/Utilities/infoLog'); +const infoLog = require('../../../../Libraries/Utilities/infoLog'); const { HeaderComponent, @@ -35,7 +35,7 @@ const { pressItem, renderSmallSwitchOption, renderStackedItem, -} = require('./ListExampleShared'); +} = require('../../components/ListExampleShared'); const VIEWABILITY_CONFIG = { minimumViewTime: 3000, diff --git a/RNTester/js/SegmentedControlIOSExample.js b/RNTester/js/examples/SegmentedControlIOS/SegmentedControlIOSExample.js similarity index 100% rename from RNTester/js/SegmentedControlIOSExample.js rename to RNTester/js/examples/SegmentedControlIOS/SegmentedControlIOSExample.js diff --git a/RNTester/js/SetPropertiesExampleApp.js b/RNTester/js/examples/SetPropertiesExample/SetPropertiesExampleApp.js similarity index 100% rename from RNTester/js/SetPropertiesExampleApp.js rename to RNTester/js/examples/SetPropertiesExample/SetPropertiesExampleApp.js diff --git a/RNTester/js/ShareExample.js b/RNTester/js/examples/Share/ShareExample.js similarity index 100% rename from RNTester/js/ShareExample.js rename to RNTester/js/examples/Share/ShareExample.js diff --git a/RNTester/js/SliderExample.js b/RNTester/js/examples/Slider/SliderExample.js similarity index 90% rename from RNTester/js/SliderExample.js rename to RNTester/js/examples/Slider/SliderExample.js index 5ca17c2baff4a4..95613c5808391c 100644 --- a/RNTester/js/SliderExample.js +++ b/RNTester/js/examples/Slider/SliderExample.js @@ -132,14 +132,16 @@ exports.examples = [ title: 'Custom thumb image', platform: 'ios', render(): React.Element { - return ; + return ( + + ); }, }, { title: 'Custom track image', platform: 'ios', render(): React.Element { - return ; + return ; }, }, { @@ -148,8 +150,8 @@ exports.examples = [ render(): React.Element { return ( ); }, diff --git a/RNTester/js/SnapshotExample.js b/RNTester/js/examples/Snapshot/SnapshotExample.js similarity index 100% rename from RNTester/js/SnapshotExample.js rename to RNTester/js/examples/Snapshot/SnapshotExample.js diff --git a/RNTester/js/SnapshotViewIOS.android.js b/RNTester/js/examples/Snapshot/SnapshotViewIOS.android.js similarity index 68% rename from RNTester/js/SnapshotViewIOS.android.js rename to RNTester/js/examples/Snapshot/SnapshotViewIOS.android.js index bbcaacae4db100..b2af871929ae52 100644 --- a/RNTester/js/SnapshotViewIOS.android.js +++ b/RNTester/js/examples/Snapshot/SnapshotViewIOS.android.js @@ -9,4 +9,4 @@ 'use strict'; -module.exports = require('../../Libraries/Components/UnimplementedViews/UnimplementedView'); +module.exports = require('../../../../Libraries/Components/UnimplementedViews/UnimplementedView'); diff --git a/RNTester/js/SnapshotViewIOS.ios.js b/RNTester/js/examples/Snapshot/SnapshotViewIOS.ios.js similarity index 87% rename from RNTester/js/SnapshotViewIOS.ios.js rename to RNTester/js/examples/Snapshot/SnapshotViewIOS.ios.js index 330cb4bb755061..0f8334b7759db7 100644 --- a/RNTester/js/SnapshotViewIOS.ios.js +++ b/RNTester/js/examples/Snapshot/SnapshotViewIOS.ios.js @@ -15,14 +15,14 @@ const {NativeModules, StyleSheet, UIManager, View} = require('react-native'); const {TestModule} = NativeModules; -import type {SyntheticEvent} from '../../Libraries/Types/CoreEventTypes'; -import type {ViewProps} from '../../Libraries/Components/View/ViewPropTypes'; +import type {SyntheticEvent} from '../../../../Libraries/Types/CoreEventTypes'; +import type {ViewProps} from '../../../../Libraries/Components/View/ViewPropTypes'; // Verify that RCTSnapshot is part of the UIManager since it is only loaded // if you have linked against RCTTest like in tests, otherwise we will have // a warning printed out const RCTSnapshot = UIManager.getViewManagerConfig('RCTSnapshot') - ? require('../RCTTest/RCTSnapshotNativeComponent') + ? require('../../../RCTTest/RCTSnapshotNativeComponent') : View; type SnapshotReadyEvent = SyntheticEvent< diff --git a/RNTester/js/StatusBarExample.js b/RNTester/js/examples/StatusBar/StatusBarExample.js similarity index 100% rename from RNTester/js/StatusBarExample.js rename to RNTester/js/examples/StatusBar/StatusBarExample.js diff --git a/RNTester/js/SwitchExample.js b/RNTester/js/examples/Switch/SwitchExample.js similarity index 100% rename from RNTester/js/SwitchExample.js rename to RNTester/js/examples/Switch/SwitchExample.js diff --git a/RNTester/js/TVEventHandlerExample.js b/RNTester/js/examples/TVEventHandler/TVEventHandlerExample.js similarity index 100% rename from RNTester/js/TVEventHandlerExample.js rename to RNTester/js/examples/TVEventHandler/TVEventHandlerExample.js diff --git a/RNTester/js/TextExample.android.js b/RNTester/js/examples/Text/TextExample.android.js similarity index 98% rename from RNTester/js/TextExample.android.js rename to RNTester/js/examples/Text/TextExample.android.js index ae21774375d034..85fb52c96e9fa1 100644 --- a/RNTester/js/TextExample.android.js +++ b/RNTester/js/examples/Text/TextExample.android.js @@ -12,10 +12,10 @@ const React = require('react'); const {StyleSheet, Text, View} = require('react-native'); -const RNTesterBlock = require('./RNTesterBlock'); -const RNTesterPage = require('./RNTesterPage'); -const TextInlineView = require('./Shared/TextInlineView'); -const TextLegend = require('./Shared/TextLegend'); +const RNTesterBlock = require('../../components/RNTesterBlock'); +const RNTesterPage = require('../../components/RNTesterPage'); +const TextInlineView = require('../../components/TextInlineView'); +const TextLegend = require('../../components/TextLegend'); class Entity extends React.Component<{|children: React.Node|}> { render() { diff --git a/RNTester/js/TextExample.ios.js b/RNTester/js/examples/Text/TextExample.ios.js similarity index 99% rename from RNTester/js/TextExample.ios.js rename to RNTester/js/examples/Text/TextExample.ios.js index 281403e2a49323..5835161d1fa83c 100644 --- a/RNTester/js/TextExample.ios.js +++ b/RNTester/js/examples/Text/TextExample.ios.js @@ -19,9 +19,9 @@ const { TextInput, View, } = require('react-native'); -const TextAncestor = require('../../Libraries/Text/TextAncestor'); -const TextInlineView = require('./Shared/TextInlineView'); -const TextLegend = require('./Shared/TextLegend'); +const TextAncestor = require('../../../../Libraries/Text/TextAncestor'); +const TextInlineView = require('../../components/TextInlineView'); +const TextLegend = require('../../components/TextLegend'); // TODO: Is there a cleaner way to flip the TextAncestor value to false? I // suspect apps won't even be able to leverage this workaround because diff --git a/RNTester/js/TextInputExample.android.js b/RNTester/js/examples/TextInput/TextInputExample.android.js similarity index 100% rename from RNTester/js/TextInputExample.android.js rename to RNTester/js/examples/TextInput/TextInputExample.android.js diff --git a/RNTester/js/TextInputExample.ios.js b/RNTester/js/examples/TextInput/TextInputExample.ios.js similarity index 100% rename from RNTester/js/TextInputExample.ios.js rename to RNTester/js/examples/TextInput/TextInputExample.ios.js diff --git a/RNTester/js/TimePickerAndroidExample.js b/RNTester/js/examples/TimePicker/TimePickerAndroidExample.js similarity index 96% rename from RNTester/js/TimePickerAndroidExample.js rename to RNTester/js/examples/TimePicker/TimePickerAndroidExample.js index 28c25582b046dd..ced8a74ff73a41 100644 --- a/RNTester/js/TimePickerAndroidExample.js +++ b/RNTester/js/examples/TimePicker/TimePickerAndroidExample.js @@ -17,8 +17,8 @@ const { TouchableWithoutFeedback, } = require('react-native'); -const RNTesterBlock = require('./RNTesterBlock'); -const RNTesterPage = require('./RNTesterPage'); +const RNTesterBlock = require('../../components/RNTesterBlock'); +const RNTesterPage = require('../../components/RNTesterPage'); class TimePickerAndroidExample extends React.Component { state = { diff --git a/RNTester/js/TimerExample.js b/RNTester/js/examples/Timer/TimerExample.js similarity index 99% rename from RNTester/js/TimerExample.js rename to RNTester/js/examples/Timer/TimerExample.js index a67397771a06af..59a792b6b46d7b 100644 --- a/RNTester/js/TimerExample.js +++ b/RNTester/js/examples/Timer/TimerExample.js @@ -12,7 +12,7 @@ const React = require('react'); const {Alert, Platform, ToastAndroid, Text, View} = require('react-native'); -const RNTesterButton = require('./RNTesterButton'); +const RNTesterButton = require('../../components/RNTesterButton'); const performanceNow = require('fbjs/lib/performanceNow'); function burnCPU(milliseconds) { diff --git a/RNTester/js/ToastAndroidExample.android.js b/RNTester/js/examples/ToastAndroid/ToastAndroidExample.android.js similarity index 96% rename from RNTester/js/ToastAndroidExample.android.js rename to RNTester/js/examples/ToastAndroid/ToastAndroidExample.android.js index e2e2208da205b7..2b2ad5fa1291f6 100644 --- a/RNTester/js/ToastAndroidExample.android.js +++ b/RNTester/js/examples/ToastAndroid/ToastAndroidExample.android.js @@ -18,8 +18,8 @@ const { TouchableWithoutFeedback, } = require('react-native'); -const RNTesterBlock = require('./RNTesterBlock'); -const RNTesterPage = require('./RNTesterPage'); +const RNTesterBlock = require('../../components/RNTesterBlock'); +const RNTesterPage = require('../../components/RNTesterPage'); type Props = $ReadOnly<{||}>; class ToastExample extends React.Component { diff --git a/RNTester/js/TouchableExample.js b/RNTester/js/examples/Touchable/TouchableExample.js similarity index 100% rename from RNTester/js/TouchableExample.js rename to RNTester/js/examples/Touchable/TouchableExample.js diff --git a/RNTester/js/TransformExample.js b/RNTester/js/examples/Transform/TransformExample.js similarity index 100% rename from RNTester/js/TransformExample.js rename to RNTester/js/examples/Transform/TransformExample.js diff --git a/RNTester/js/TransparentHitTestExample.js b/RNTester/js/examples/TransparentHitTest/TransparentHitTestExample.js similarity index 100% rename from RNTester/js/TransparentHitTestExample.js rename to RNTester/js/examples/TransparentHitTest/TransparentHitTestExample.js diff --git a/RNTester/js/SampleTurboModuleExample.js b/RNTester/js/examples/TurboModule/SampleTurboModuleExample.js similarity index 97% rename from RNTester/js/SampleTurboModuleExample.js rename to RNTester/js/examples/TurboModule/SampleTurboModuleExample.js index a3c89c5e826710..a3417f3a255ed5 100644 --- a/RNTester/js/SampleTurboModuleExample.js +++ b/RNTester/js/examples/TurboModule/SampleTurboModuleExample.js @@ -10,7 +10,7 @@ 'use strict'; -import NativeSampleTurboModule from 'react-native/Libraries/TurboModule/samples/NativeSampleTurboModule'; +import NativeSampleTurboModule from '../../../../Libraries/TurboModule/samples/NativeSampleTurboModule'; import { StyleSheet, Text, diff --git a/RNTester/js/TurboModuleExample.js b/RNTester/js/examples/TurboModule/TurboModuleExample.js similarity index 100% rename from RNTester/js/TurboModuleExample.js rename to RNTester/js/examples/TurboModule/TurboModuleExample.js diff --git a/RNTester/js/VibrationExample.js b/RNTester/js/examples/Vibration/VibrationExample.js similarity index 100% rename from RNTester/js/VibrationExample.js rename to RNTester/js/examples/Vibration/VibrationExample.js diff --git a/RNTester/js/ViewExample.js b/RNTester/js/examples/View/ViewExample.js similarity index 100% rename from RNTester/js/ViewExample.js rename to RNTester/js/examples/View/ViewExample.js diff --git a/RNTester/js/ViewPagerAndroidExample.android.js b/RNTester/js/examples/ViewPagerAndroid/ViewPagerAndroidExample.android.js similarity index 98% rename from RNTester/js/ViewPagerAndroidExample.android.js rename to RNTester/js/examples/ViewPagerAndroid/ViewPagerAndroidExample.android.js index 0be94e6a6719a3..579d6f76495379 100644 --- a/RNTester/js/ViewPagerAndroidExample.android.js +++ b/RNTester/js/examples/ViewPagerAndroid/ViewPagerAndroidExample.android.js @@ -20,7 +20,7 @@ const { ViewPagerAndroid, } = require('react-native'); -import type {ViewPagerScrollState} from '../../Libraries/Components/ViewPager/ViewPagerAndroid'; +import type {ViewPagerScrollState} from '../../../../Libraries/Components/ViewPager/ViewPagerAndroid'; const PAGES = 5; const BGCOLOR = ['#fdc08e', '#fff6b9', '#99d1b7', '#dde5fe', '#f79273']; diff --git a/RNTester/js/WebSocketExample.js b/RNTester/js/examples/WebSocket/WebSocketExample.js similarity index 98% rename from RNTester/js/WebSocketExample.js rename to RNTester/js/examples/WebSocket/WebSocketExample.js index bd42e595e3534e..755669a5e4d4d3 100644 --- a/RNTester/js/WebSocketExample.js +++ b/RNTester/js/examples/WebSocket/WebSocketExample.js @@ -210,7 +210,7 @@ class WebSocketExample extends React.Component { To start the WS test server: - ./RNTester/js/websocket_test_server.js + ./RNTester/js/examples/WebSocket/websocket_test_server.js @@ -266,7 +266,7 @@ class WebSocketExample extends React.Component { To start the HTTP test server: - ./RNTester/js/http_test_server.js + ./RNTester/js/examples/WebSocket/http_test_server.js = [ { key: 'ActivityIndicatorExample', - module: require('./ActivityIndicatorExample'), + module: require('../examples/ActivityIndicator/ActivityIndicatorExample'), }, { key: 'ButtonExample', - module: require('./ButtonExample'), + module: require('../examples/Button/ButtonExample'), }, { key: 'CheckBoxExample', - module: require('./CheckBoxExample'), + module: require('../examples/CheckBox/CheckBoxExample'), }, { key: 'FlatListExample', - module: require('./FlatListExample'), + module: require('../examples/FlatList/FlatListExample'), }, { key: 'ImageExample', - module: require('./ImageExample'), + module: require('../examples/Image/ImageExample'), }, { key: 'KeyboardAvoidingViewExample', - module: require('./KeyboardAvoidingViewExample'), + module: require('../examples/KeyboardAvoidingView/KeyboardAvoidingViewExample'), }, { key: 'ModalExample', - module: require('./ModalExample'), + module: require('../examples/Modal/ModalExample'), }, { key: 'MultiColumnExample', - module: require('./MultiColumnExample'), + module: require('../examples/MultiColumn/MultiColumnExample'), }, { key: 'NewAppScreenExample', - module: require('./NewAppScreenExample'), + module: require('../examples/NewAppScreen/NewAppScreenExample'), }, { key: 'PickerExample', - module: require('./PickerExample'), + module: require('../examples/Picker/PickerExample'), }, { key: 'ProgressBarAndroidExample', /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found * when making Flow check .android.js files. */ - module: require('./ProgressBarAndroidExample'), + module: require('../examples/ProgressBarAndroid/ProgressBarAndroidExample'), }, { key: 'RefreshControlExample', - module: require('./RefreshControlExample'), + module: require('../examples/RefreshControl/RefreshControlExample'), }, { key: 'ScrollViewSimpleExample', - module: require('./ScrollViewSimpleExample'), + module: require('../examples/ScrollView/ScrollViewSimpleExample'), }, { key: 'SectionListExample', - module: require('./SectionListExample'), + module: require('../examples/SectionList/SectionListExample'), }, { key: 'SliderExample', - module: require('./SliderExample'), + module: require('../examples/Slider/SliderExample'), }, { key: 'StatusBarExample', - module: require('./StatusBarExample'), + module: require('../examples/StatusBar/StatusBarExample'), }, { key: 'SwitchExample', - module: require('./SwitchExample'), + module: require('../examples/Switch/SwitchExample'), }, { key: 'TextExample', /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found * when making Flow check .android.js files. */ - module: require('./TextExample'), + module: require('../examples/Text/TextExample'), }, { key: 'TextInputExample', /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found * when making Flow check .android.js files. */ - module: require('./TextInputExample'), + module: require('../examples/TextInput/TextInputExample'), }, { key: 'TouchableExample', - module: require('./TouchableExample'), + module: require('../examples/Touchable/TouchableExample'), }, { key: 'ViewExample', - module: require('./ViewExample'), + module: require('../examples/View/ViewExample'), }, { key: 'ViewPagerAndroidExample', /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found * when making Flow check .android.js files. */ - module: require('./ViewPagerAndroidExample'), + module: require('../examples/ViewPagerAndroid/ViewPagerAndroidExample'), }, ]; const APIExamples: Array = [ { key: 'AccessibilityExample', - module: require('./AccessibilityExample'), + module: require('../examples/Accessibility/AccessibilityExample'), }, { key: 'AccessibilityAndroidExample', /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found * when making Flow check .android.js files. */ - module: require('./AccessibilityAndroidExample'), + module: require('../examples/Accessibility/AccessibilityAndroidExample'), }, { key: 'AlertExample', - module: require('./AlertExample').AlertExample, + module: require('../examples/Alert/AlertExample').AlertExample, }, { key: 'AnimatedExample', - module: require('./AnimatedExample'), + module: require('../examples/Animated/AnimatedExample'), }, { key: 'AppStateExample', - module: require('./AppStateExample'), + module: require('../examples/AppState/AppStateExample'), }, { key: 'BorderExample', - module: require('./BorderExample'), + module: require('../examples/Border/BorderExample'), }, { key: 'ClipboardExample', - module: require('./ClipboardExample'), + module: require('../examples/Clipboard/ClipboardExample'), }, { key: 'CrashExample', - module: require('./CrashExample'), + module: require('../examples/Crash/CrashExample'), }, { key: 'DatePickerAndroidExample', - module: require('./DatePickerAndroidExample'), + module: require('../examples/DatePicker/DatePickerAndroidExample'), }, { key: 'Dimensions', - module: require('./DimensionsExample'), + module: require('../examples/Dimensions/DimensionsExample'), }, { key: 'LayoutEventsExample', - module: require('./LayoutEventsExample'), + module: require('../examples/Layout/LayoutEventsExample'), }, { key: 'LinkingExample', - module: require('./LinkingExample'), + module: require('../examples/Linking/LinkingExample'), }, { key: 'LayoutAnimationExample', - module: require('./LayoutAnimationExample'), + module: require('../examples/Layout/LayoutAnimationExample'), }, { key: 'LayoutExample', - module: require('./LayoutExample'), + module: require('../examples/Layout/LayoutExample'), }, { key: 'NativeAnimationsExample', - module: require('./NativeAnimationsExample'), + module: require('../examples/NativeAnimation/NativeAnimationsExample'), }, { key: 'OrientationChangeExample', - module: require('./OrientationChangeExample'), + module: require('../examples/OrientationChange/OrientationChangeExample'), }, { key: 'PanResponderExample', - module: require('./PanResponderExample'), + module: require('../examples/PanResponder/PanResponderExample'), }, { key: 'PermissionsExampleAndroid', /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found * when making Flow check .android.js files. */ - module: require('./PermissionsExampleAndroid'), + module: require('../examples/PermissionsAndroid/PermissionsExample'), }, { key: 'PointerEventsExample', - module: require('./PointerEventsExample'), + module: require('../examples/PointerEvents/PointerEventsExample'), }, { key: 'RTLExample', - module: require('./RTLExample'), + module: require('../examples/RTL/RTLExample'), }, { key: 'ShareExample', - module: require('./ShareExample'), + module: require('../examples/Share/ShareExample'), }, { key: 'TimePickerAndroidExample', - module: require('./TimePickerAndroidExample'), + module: require('../examples/TimePicker/TimePickerAndroidExample'), }, { key: 'TimerExample', - module: require('./TimerExample'), + module: require('../examples/Timer/TimerExample'), }, { key: 'ToastAndroidExample', /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found * when making Flow check .android.js files. */ - module: require('./ToastAndroidExample'), + module: require('../examples/ToastAndroid/ToastAndroidExample'), }, { key: 'TransformExample', - module: require('./TransformExample'), + module: require('../examples/Transform/TransformExample'), }, { key: 'VibrationExample', - module: require('./VibrationExample'), + module: require('../examples/Vibration/VibrationExample'), }, { key: 'WebSocketExample', - module: require('./WebSocketExample'), + module: require('../examples/WebSocket/WebSocketExample'), }, { key: 'XHRExample', - module: require('./XHRExample'), + module: require('../examples/XHR/XHRExample'), }, ]; diff --git a/RNTester/js/RNTesterList.ios.js b/RNTester/js/utils/RNTesterList.ios.js similarity index 52% rename from RNTester/js/RNTesterList.ios.js rename to RNTester/js/utils/RNTesterList.ios.js index f8531648274665..e5e4de716b544e 100644 --- a/RNTester/js/RNTesterList.ios.js +++ b/RNTester/js/utils/RNTesterList.ios.js @@ -10,157 +10,157 @@ 'use strict'; -import type {RNTesterExample} from './Shared/RNTesterTypes'; +import type {RNTesterExample} from '../types/RNTesterTypes'; const ComponentExamples: Array = [ { key: 'ActivityIndicatorExample', - module: require('./ActivityIndicatorExample'), + module: require('../examples/ActivityIndicator/ActivityIndicatorExample'), supportsTVOS: true, }, { key: 'ARTExample', - module: require('./ARTExample'), + module: require('../examples/ART/ARTExample'), supportsTVOS: true, }, { key: 'ButtonExample', - module: require('./ButtonExample'), + module: require('../examples/Button/ButtonExample'), supportsTVOS: true, }, { key: 'DatePickerIOSExample', - module: require('./DatePickerIOSExample'), + module: require('../examples/DatePicker/DatePickerIOSExample'), supportsTVOS: false, }, { key: 'FlatListExample', - module: require('./FlatListExample'), + module: require('../examples/FlatList/FlatListExample'), supportsTVOS: true, }, { key: 'ImageExample', - module: require('./ImageExample'), + module: require('../examples/Image/ImageExample'), supportsTVOS: true, }, { key: 'InputAccessoryViewExample', - module: require('./InputAccessoryViewExample'), + module: require('../examples/InputAccessoryView/InputAccessoryViewExample'), supportsTVOS: true, }, { key: 'KeyboardAvoidingViewExample', - module: require('./KeyboardAvoidingViewExample'), + module: require('../examples/KeyboardAvoidingView/KeyboardAvoidingViewExample'), supportsTVOS: false, }, { key: 'LayoutEventsExample', - module: require('./LayoutEventsExample'), + module: require('../examples/Layout/LayoutEventsExample'), supportsTVOS: true, }, { key: 'MaskedViewExample', - module: require('./MaskedViewExample'), + module: require('../examples/MaskedView/MaskedViewExample'), supportsTVOS: true, }, { key: 'ModalExample', - module: require('./ModalExample'), + module: require('../examples/Modal/ModalExample'), supportsTVOS: true, }, { key: 'MultiColumnExample', - module: require('./MultiColumnExample'), + module: require('../examples/MultiColumn/MultiColumnExample'), supportsTVOS: true, }, { key: 'NewAppScreenExample', - module: require('./NewAppScreenExample'), + module: require('../examples/NewAppScreen/NewAppScreenExample'), supportsTVOS: false, }, { key: 'PickerExample', - module: require('./PickerExample'), + module: require('../examples/Picker/PickerExample'), supportsTVOS: false, }, { key: 'PickerIOSExample', - module: require('./PickerIOSExample'), + module: require('../examples/Picker/PickerIOSExample'), supportsTVOS: false, }, { key: 'ProgressViewIOSExample', - module: require('./ProgressViewIOSExample'), + module: require('../examples/ProgressViewIOS/ProgressViewIOSExample'), supportsTVOS: true, }, { key: 'RefreshControlExample', - module: require('./RefreshControlExample'), + module: require('../examples/RefreshControl/RefreshControlExample'), supportsTVOS: false, }, { key: 'ScrollViewSimpleExample', - module: require('./ScrollViewSimpleExample'), + module: require('../examples/ScrollView/ScrollViewSimpleExample'), supportsTVOS: true, }, { key: 'SafeAreaViewExample', - module: require('./SafeAreaViewExample'), + module: require('../examples/SafeAreaView/SafeAreaViewExample'), supportsTVOS: true, }, { key: 'ScrollViewExample', - module: require('./ScrollViewExample'), + module: require('../examples/ScrollView/ScrollViewExample'), supportsTVOS: true, }, { key: 'SectionListExample', - module: require('./SectionListExample'), + module: require('../examples/SectionList/SectionListExample'), supportsTVOS: true, }, { key: 'SegmentedControlIOSExample', - module: require('./SegmentedControlIOSExample'), + module: require('../examples/SegmentedControlIOS/SegmentedControlIOSExample'), supportsTVOS: false, }, { key: 'SliderExample', - module: require('./SliderExample'), + module: require('../examples/Slider/SliderExample'), supportsTVOS: false, }, { key: 'StatusBarExample', - module: require('./StatusBarExample'), + module: require('../examples/StatusBar/StatusBarExample'), supportsTVOS: false, }, { key: 'SwitchExample', - module: require('./SwitchExample'), + module: require('../examples/Switch/SwitchExample'), supportsTVOS: false, }, { key: 'TextExample', - module: require('./TextExample.ios'), + module: require('../examples/Text/TextExample.ios'), supportsTVOS: true, }, { key: 'TextInputExample', - module: require('./TextInputExample.ios'), + module: require('../examples/TextInput/TextInputExample.ios'), supportsTVOS: true, }, { key: 'TouchableExample', - module: require('./TouchableExample'), + module: require('../examples/Touchable/TouchableExample'), supportsTVOS: true, }, { key: 'TransparentHitTestExample', - module: require('./TransparentHitTestExample'), + module: require('../examples/TransparentHitTest/TransparentHitTestExample'), supportsTVOS: false, }, { key: 'ViewExample', - module: require('./ViewExample'), + module: require('../examples/View/ViewExample'), supportsTVOS: true, }, ]; @@ -168,162 +168,162 @@ const ComponentExamples: Array = [ const APIExamples: Array = [ { key: 'AccessibilityExample', - module: require('./AccessibilityExample'), + module: require('../examples/Accessibility/AccessibilityExample'), supportsTVOS: false, }, { key: 'AccessibilityIOSExample', - module: require('./AccessibilityIOSExample'), + module: require('../examples/Accessibility/AccessibilityIOSExample'), supportsTVOS: false, }, { key: 'ActionSheetIOSExample', - module: require('./ActionSheetIOSExample'), + module: require('../examples/ActionSheetIOS/ActionSheetIOSExample'), supportsTVOS: true, }, { key: 'AlertIOSExample', - module: require('./AlertIOSExample'), + module: require('../examples/Alert/AlertIOSExample'), supportsTVOS: true, }, { key: 'AnimatedExample', - module: require('./AnimatedExample'), + module: require('../examples/Animated/AnimatedExample'), supportsTVOS: true, }, { key: 'AnExApp', - module: require('./AnimatedGratuitousApp/AnExApp'), + module: require('../examples/Animated/AnimatedGratuitousApp/AnExApp'), supportsTVOS: true, }, { key: 'AppStateExample', - module: require('./AppStateExample'), + module: require('../examples/AppState/AppStateExample'), supportsTVOS: true, }, { key: 'AsyncStorageExample', - module: require('./AsyncStorageExample'), + module: require('../examples/AsyncStorage/AsyncStorageExample'), supportsTVOS: true, }, { key: 'BorderExample', - module: require('./BorderExample'), + module: require('../examples/Border/BorderExample'), supportsTVOS: true, }, { key: 'BoxShadowExample', - module: require('./BoxShadowExample'), + module: require('../examples/BoxShadow/BoxShadowExample'), supportsTVOS: true, }, { key: 'ClipboardExample', - module: require('./ClipboardExample'), + module: require('../examples/Clipboard/ClipboardExample'), supportsTVOS: false, }, { key: 'CrashExample', - module: require('./CrashExample'), + module: require('../examples/Crash/CrashExample'), supportsTVOS: false, }, { key: 'Dimensions', - module: require('./DimensionsExample'), + module: require('../examples/Dimensions/DimensionsExample'), supportsTVOS: true, }, { key: 'LayoutAnimationExample', - module: require('./LayoutAnimationExample'), + module: require('../examples/Layout/LayoutAnimationExample'), supportsTVOS: true, }, { key: 'LayoutExample', - module: require('./LayoutExample'), + module: require('../examples/Layout/LayoutExample'), supportsTVOS: true, }, { key: 'LinkingExample', - module: require('./LinkingExample'), + module: require('../examples/Linking/LinkingExample'), supportsTVOS: true, }, { key: 'NativeAnimationsExample', - module: require('./NativeAnimationsExample'), + module: require('../examples/NativeAnimation/NativeAnimationsExample'), supportsTVOS: true, }, { key: 'OrientationChangeExample', - module: require('./OrientationChangeExample'), + module: require('../examples/OrientationChange/OrientationChangeExample'), supportsTVOS: false, }, { key: 'PanResponderExample', - module: require('./PanResponderExample'), + module: require('../examples/PanResponder/PanResponderExample'), supportsTVOS: false, }, { key: 'PointerEventsExample', - module: require('./PointerEventsExample'), + module: require('../examples/PointerEvents/PointerEventsExample'), supportsTVOS: false, }, { key: 'PushNotificationIOSExample', - module: require('./PushNotificationIOSExample'), + module: require('../examples/PushNotificationIOS/PushNotificationIOSExample'), supportsTVOS: false, }, { key: 'RCTRootViewIOSExample', - module: require('./RCTRootViewIOSExample'), + module: require('../examples/RCTRootView/RCTRootViewIOSExample'), supportsTVOS: true, }, { key: 'RTLExample', - module: require('./RTLExample'), + module: require('../examples/RTL/RTLExample'), supportsTVOS: true, }, { key: 'ShareExample', - module: require('./ShareExample'), + module: require('../examples/Share/ShareExample'), supportsTVOS: true, }, { key: 'SnapshotExample', - module: require('./SnapshotExample'), + module: require('../examples/Snapshot/SnapshotExample'), supportsTVOS: true, }, { key: 'TimerExample', - module: require('./TimerExample'), + module: require('../examples/Timer/TimerExample'), supportsTVOS: true, }, { key: 'TransformExample', - module: require('./TransformExample'), + module: require('../examples/Transform/TransformExample'), supportsTVOS: true, }, { key: 'TurboModuleExample', - module: require('./TurboModuleExample'), + module: require('../examples/TurboModule/TurboModuleExample'), supportsTVOS: false, }, { key: 'TVEventHandlerExample', - module: require('./TVEventHandlerExample'), + module: require('../examples/TVEventHandler/TVEventHandlerExample'), supportsTVOS: true, }, { key: 'VibrationExample', - module: require('./VibrationExample'), + module: require('../examples/Vibration/VibrationExample'), supportsTVOS: false, }, { key: 'WebSocketExample', - module: require('./WebSocketExample'), + module: require('../examples/WebSocket/WebSocketExample'), supportsTVOS: true, }, { key: 'XHRExample', - module: require('./XHRExample'), + module: require('../examples/XHR/XHRExample'), supportsTVOS: true, }, ]; diff --git a/RNTester/js/RNTesterNavigationReducer.js b/RNTester/js/utils/RNTesterNavigationReducer.js similarity index 100% rename from RNTester/js/RNTesterNavigationReducer.js rename to RNTester/js/utils/RNTesterNavigationReducer.js diff --git a/RNTester/js/RNTesterStatePersister.js b/RNTester/js/utils/RNTesterStatePersister.js similarity index 100% rename from RNTester/js/RNTesterStatePersister.js rename to RNTester/js/utils/RNTesterStatePersister.js diff --git a/RNTester/js/URIActionMap.js b/RNTester/js/utils/URIActionMap.js similarity index 100% rename from RNTester/js/URIActionMap.js rename to RNTester/js/utils/URIActionMap.js From 5979eafb1653cec975741c0e9ec9236f19ee8ce5 Mon Sep 17 00:00:00 2001 From: Luna Wei Date: Tue, 28 May 2019 09:05:57 -0700 Subject: [PATCH 0100/1084] Back out "[RN] Fix layout animation crash" Summary: Original commit changeset: 41200e572ed7 Reviewed By: mdvacca Differential Revision: D15485156 fbshipit-source-id: d0868a03b7186bb33998afc2c99dd85f31c8fef9 --- .../react/uimanager/NativeViewHierarchyManager.java | 2 +- .../layoutanimation/LayoutAnimationController.java | 12 ++++-------- .../facebook/react/views/view/ReactViewGroup.java | 4 +--- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java index 2aa8abf9794833..48d1daefd5f855 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java @@ -444,7 +444,7 @@ public synchronized void manageChildren( arrayContains(tagsToDelete, viewToRemove.getId())) { // The view will be removed and dropped by the 'delete' layout animation // instead, so do nothing - } else if (viewToManage != null) { + } else { viewManager.removeViewAt(viewToManage, normalizedIndexToRemove); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationController.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationController.java index cad0a0cac29c06..232cb01f9071e5 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationController.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/layoutanimation/LayoutAnimationController.java @@ -82,14 +82,10 @@ public void reset() { } public boolean shouldAnimateLayout(View viewToAnimate) { - // if view is null or the view parent is null, skip animation: view have been clipped, - // we don't want animation to resume when view is re-attached to parent, which is the - // standard android animation behavior. If there's a layout handling animation going on, - // it should be animated nonetheless since the ongoing animation needs to be updated. - - if (viewToAnimate == null) { - return false; - } + // if view parent is null, skip animation: view have been clipped, we don't want animation to + // resume when view is re-attached to parent, which is the standard android animation behavior. + // If there's a layout handling animation going on, it should be animated nonetheless since the + // ongoing animation needs to be updated. return (mShouldAnimateLayout && viewToAnimate.getParent() != null) || mLayoutHandlers.get(viewToAnimate.getId()) != null; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java index e1cec5d41a26ab..4e89e9dbf59b9b 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java @@ -465,9 +465,7 @@ public void removeViewAt(int index) { mDrawingOrderHelper.handleRemoveView(getChildAt(index)); setChildrenDrawingOrderEnabled(mDrawingOrderHelper.shouldEnableCustomDrawingOrder()); - if (getChildAt(index) != null) { - super.removeViewAt(index); - } + super.removeViewAt(index); } @Override From bd3023abeadf9b6dfbe18cbac649961e0efe73f0 Mon Sep 17 00:00:00 2001 From: Luna Wei Date: Tue, 28 May 2019 09:05:57 -0700 Subject: [PATCH 0101/1084] Layout Animation fix for normalized indices Summary: [Android][Fix] - Fix how we normalize indices Before, we were incorrectly normalizing indices given pending view deletion in the view hierarchy (namely, using LayoutAnimations) What we had before (that was wrong): * Maintained a pendingIndices sparse array for each tag * For each pendingIndices sparse array we'd keep track of how many views we deleted at each abstract index * Given an abstract index to delete a view at, we'd consult `pendingIndices` array to sum how many pending deletes we had for indices equal or smaller than and add to abstract index ^ Above algorithm is wrong and you can follow along with the following example to see how. ## The correct approach Given these operations in this order: 1. {tagsToDelete: [123], indicesToDelete [2]} 2. {tagsToDelete: [124], indicesToDelete [1]} 3. {tagsToDelete: [125], indicesToDelete [2]} 4. {tagsToDelete: [126], indicesToDelete [1]} The approach we want to be using to calculate normalized indices: ### Step 1: Delete tag 124 at index 2 |Views:|122|123|124|125|126|127| |Actual Indices:|0|1|2|3|4|5| |Abstract Indices:|0|1|2|3|4|5| => simple, we just mark the view at 2 ### Step 2: Delete tag 123 at index 1 View tags and indices: |Views|122|123|~~124~~|125|126|127| |Actual indices|0|1|~~2~~|3|4|5| |Abstract Indices|0|1||2|3|4| => again, simple, we can just use the normalized index 1 because no pending deletes affect this operation ### Step 3: Delete tag 126 at index 2 View tags and indices: |Views|122|~~123~~|~~124~~|125|126|127| |Actual Indices|0|~~1~~|~~2~~|3|4|5| |Abstract Indices|0|||1|2|3| => Here we want to normalize this index to 4 because we need to account the 2 views that should be skipped ### Step 4: Delete tag 125 at index 1 View tags and indices: |Views|122|~~123~~|~~124~~|125|~~126~~|127| |Actual Indices|0|~~1~~|~~2~~|3|~~4~~|5| |Abstract Indices|0|||1||2| => The normalized index should be 3. This diff updates the function `normalizeIndex` to do the above algorithm by repurposing `pendingIndicesToDelete` to instead be a sparse int array that holds [normalizedIndex]=[tag] pairs It's required that `pendingIndicesToDelete` is ordered by the normalizedIndex. Reviewed By: mdvacca Differential Revision: D15485132 fbshipit-source-id: 43e57dffa807e8ea50fa1650c5dec13a6fded624 --- .../uimanager/NativeViewHierarchyManager.java | 54 +++++++++++++++---- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java index 48d1daefd5f855..4c6c626d6e81f1 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java @@ -338,17 +338,52 @@ private static String constructManageChildrenErrorMessage( } /** - * Given an index to action on under synchronous deletes, return an updated index factoring in - * asynchronous deletes (where the async delete operations have not yet been performed) + * Given an index, normalize against pending view deletion indices in the native view hierarchy + * @param index the index in the view operation under the assumption all view operations are synchronous + * @param pendingIndicesToDelete sparse array of view tags at normalized indices */ - private int normalizeIndex(int index, SparseIntArray pendingIndices) { - int normalizedIndex = index; - for (int i = 0; i <= index; i++) { - normalizedIndex += pendingIndices.get(i); + private int normalizeIndex(int index, SparseIntArray pendingIndicesToDelete) { + int normalizedIndex = -1; + while (index >= 0) { + normalizedIndex += 1; + if (pendingIndicesToDelete.get(normalizedIndex, -1) == -1) { // assuming we never have negative tag + index--; + } } return normalizedIndex; } + /** + * Add view tag to pendingIndicesToDelete. Views in pendingIndicesToDelete are marked for deletion but have not been deleted yet + * @param index the index in the view to be deleted as provided by the view operation + * @param tag the view tag + * @param pendingIndicesToDelete sparse array of normalizedIndices to view tags marked for deletion + */ + private void addPendingIndex(int index, int tag, SparseIntArray pendingIndicesToDelete) { + int normalizedIndex = normalizeIndex(index, pendingIndicesToDelete); + if (pendingIndicesToDelete.get(normalizedIndex) > 0) { + throw new IllegalViewOperationException("Invalid!!"); + } + pendingIndicesToDelete.put(normalizedIndex, tag); + } + + /** + * When delete is completed, remove view from pendingIndicesToDelete + * @param tag tag of the view to be removed + * @param pendingIndicesToDelete sparse array of normalizedIndices to view tags marked for deletion + */ + private void removePendingIndex(int tag, SparseIntArray pendingIndicesToDelete) { + // indexAt refers to index within pendingIndicesToDelete sparse array, not the normalized index + int indexAt = pendingIndicesToDelete.indexOfValue(tag); + pendingIndicesToDelete.removeAt(indexAt); + for (indexAt = indexAt + 1; indexAt < pendingIndicesToDelete.size(); indexAt ++) { + int nextTag = pendingIndicesToDelete.valueAt(indexAt); + int nextKey = pendingIndicesToDelete.keyAt(indexAt); + pendingIndicesToDelete.removeAt(indexAt); + pendingIndicesToDelete.put(nextKey - 1, nextTag); + } + } + /** * Given React tag, return sparse array of direct child indices that are pending deletion (due to * async view deletion) @@ -471,8 +506,8 @@ public synchronized void manageChildren( if (mLayoutAnimationEnabled && mLayoutAnimator.shouldAnimateLayout(viewToDestroy)) { - int updatedCount = pendingIndicesToDelete.get(indexToDelete, 0) + 1; - pendingIndicesToDelete.put(indexToDelete, updatedCount); + + addPendingIndex(indexToDelete, tagToDelete, pendingIndicesToDelete); mLayoutAnimator.deleteView( viewToDestroy, new LayoutAnimationListener() { @@ -481,8 +516,7 @@ public void onAnimationEnd() { viewManager.removeView(viewToManage, viewToDestroy); dropView(viewToDestroy); - int count = pendingIndicesToDelete.get(indexToDelete, 0); - pendingIndicesToDelete.put(indexToDelete, Math.max(0, count - 1)); + removePendingIndex(viewToDestroy.getId(), pendingIndicesToDelete); } }); } else { From 77a6617a39896ef4f6793b369d304444b8cf63bb Mon Sep 17 00:00:00 2001 From: Emily Janzer Date: Tue, 28 May 2019 10:17:26 -0700 Subject: [PATCH 0102/1084] Use JS ViewConfig for View Summary: Rick manually created view config in JS for View; adding some missing attributes/events and using this instead of `requireNativeComponent` Reviewed By: rickhanlonii Differential Revision: D15488008 fbshipit-source-id: 48e925ec0ca2aeba9e6cc66edef0b70ee1c94d27 --- .../View/ReactNativeViewViewConfig.js | 63 ++++++++++++++++++- .../Components/View/ViewNativeComponent.js | 6 +- .../verifyComponentAttributeEquivalence.js | 2 +- 3 files changed, 63 insertions(+), 8 deletions(-) diff --git a/Libraries/Components/View/ReactNativeViewViewConfig.js b/Libraries/Components/View/ReactNativeViewViewConfig.js index d723f2797e7de1..942a269790f1f5 100644 --- a/Libraries/Components/View/ReactNativeViewViewConfig.js +++ b/Libraries/Components/View/ReactNativeViewViewConfig.js @@ -10,12 +10,12 @@ 'use strict'; +const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); +const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); + const ReactNativeViewConfig = { uiViewClassName: 'RCTView', - baseModuleName: null, - Manager: 'ViewManager', Commands: {}, - Constants: {}, bubblingEventTypes: { topBlur: { phasedRegistrationNames: { @@ -53,6 +53,12 @@ const ReactNativeViewConfig = { captured: 'onPressCapture', }, }, + topSelect: { + phasedRegistrationNames: { + bubbled: 'onSelect', + captured: 'onSelectCapture', + }, + }, topSubmitEditing: { phasedRegistrationNames: { bubbled: 'onSubmitEditing', @@ -85,6 +91,9 @@ const ReactNativeViewConfig = { }, }, directEventTypes: { + performAction: { + registrationName: 'onAccessibilityAction', + }, topAccessibilityAction: { registrationName: 'onAccessibilityAction', }, @@ -94,12 +103,48 @@ const ReactNativeViewConfig = { topAccessibilityTap: { registrationName: 'onAccessibilityTap', }, + topClick: { + registrationName: 'onClick', + }, + topContentSizeChange: { + registrationName: 'onContentSizeChange', + }, topLayout: { registrationName: 'onLayout', }, + topLoadingError: { + registrationName: 'onLoadingError', + }, + topLoadingFinish: { + registrationName: 'onLoadingFinish', + }, + topLoadingStart: { + registrationName: 'onLoadingStart', + }, topMagicTap: { registrationName: 'onMagicTap', }, + topMessage: { + registrationName: 'onMessage', + }, + topMomentumScrollBegin: { + registrationName: 'onMomentumScrollBegin', + }, + topMomentumScrollEnd: { + registrationName: 'onMomentumScrollEnd', + }, + topScroll: { + registrationName: 'onScroll', + }, + topScrollBeginDrag: { + registrationName: 'onScrollBeginDrag', + }, + topScrollEndDrag: { + registrationName: 'onScrollEndDrag', + }, + topSelectionChange: { + registrationName: 'onSelectionChange', + }, }, validAttributes: { accessibilityActions: true, @@ -156,6 +201,7 @@ const ReactNativeViewConfig = { flexGrow: true, flexShrink: true, flexWrap: true, + hasTVPreferredFocus: true, height: true, hitSlop: {diff: (require('../../Utilities/differ/insetsDiffer'): any)}, importantForAccessibility: true, @@ -174,8 +220,15 @@ const ReactNativeViewConfig = { maxWidth: true, minHeight: true, minWidth: true, + nativeBackgroundAndroid: true, + nativeForegroundAndroid: true, nativeID: true, needsOffscreenAlphaCompositing: true, + nextFocusDown: true, + nextFocusForward: true, + nextFocusLeft: true, + nextFocusRight: true, + nextFocusUp: true, onAccessibilityAction: true, onAccessibilityEscape: true, onAccessibilityTap: true, @@ -326,4 +379,8 @@ const ReactNativeViewConfig = { }, }; +verifyComponentAttributeEquivalence('RCTView', ReactNativeViewConfig); + +ReactNativeViewConfigRegistry.register('RCTView', () => ReactNativeViewConfig); + module.exports = ReactNativeViewConfig; diff --git a/Libraries/Components/View/ViewNativeComponent.js b/Libraries/Components/View/ViewNativeComponent.js index 21e57c8a437ab5..aa7ea2b502141d 100644 --- a/Libraries/Components/View/ViewNativeComponent.js +++ b/Libraries/Components/View/ViewNativeComponent.js @@ -12,12 +12,10 @@ const ReactNative = require('../../Renderer/shims/ReactNative'); -const requireNativeComponent = require('../../ReactNative/requireNativeComponent'); - import type {ViewProps} from './ViewPropTypes'; type ViewNativeComponentType = Class>; -const NativeViewComponent = requireNativeComponent('RCTView'); +require('ReactNativeViewViewConfig'); -module.exports = ((NativeViewComponent: any): ViewNativeComponentType); +module.exports = (('RCTView': any): ViewNativeComponentType); diff --git a/Libraries/Utilities/verifyComponentAttributeEquivalence.js b/Libraries/Utilities/verifyComponentAttributeEquivalence.js index 296b7837cbd7af..63c66445a159c3 100644 --- a/Libraries/Utilities/verifyComponentAttributeEquivalence.js +++ b/Libraries/Utilities/verifyComponentAttributeEquivalence.js @@ -14,7 +14,7 @@ const getNativeComponentAttributes = require('../ReactNative/getNativeComponentA import type {ReactNativeBaseComponentViewConfig} from '../Renderer/shims/ReactNativeTypes'; -const IGNORED_KEYS = ['transform']; +const IGNORED_KEYS = ['transform', 'hitSlop']; /** * The purpose of this function is to validate that the view config that * native exposes for a given view manager is the same as the view config From ab1a42762c1f7a8b0e99d70f2c1916d907e3868b Mon Sep 17 00:00:00 2001 From: Sam Goldman Date: Tue, 28 May 2019 12:07:34 -0700 Subject: [PATCH 0103/1084] Make RelayObservable Source return type disjoint Summary: In Flow v0.99 we are changing function type annotations to be strict about their static properties. This causes a small issue with the union of a Subcription and `() => mixed` function type, where the latter is now understood to possibly have an `unsubscribe` property with a mixed type. This causes the following refinement check, which appears lower in this file, to cause an error in the next version of Flow: ``` if (cleanup) { if (cleanup.unsubscribe) { cleanup.unsubscribe(); // <-- error here } // ... } ``` In Flow v0.99, because `() => mixed` statics are now checked, Flow sees that `cleanup.unsubscribe` might be `mixed`, which passes the conditional but could cause an exception when called. I also needed to change JestMockFn to have exact statics, because tests sometimes use a value with that type in place of the cleanup function. That runs into the `{} <: {+p?: void}` rule, which is an error. `{||} <: {+p?:void}` is not an error. Reviewed By: josephsavona Differential Revision: D15522655 fbshipit-source-id: 2ae3c9016e2b07abaac79827082d2f8743623eb5 --- flow/jest.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flow/jest.js b/flow/jest.js index 799978ca43bd27..252c05bea445c7 100644 --- a/flow/jest.js +++ b/flow/jest.js @@ -11,7 +11,7 @@ /* eslint-disable lint/no-unclear-flowtypes */ -type JestMockFn, TReturn> = { +type JestMockFn, TReturn> = {| (...args: TArguments): TReturn, /** * An object for introspecting mock calls @@ -105,7 +105,7 @@ type JestMockFn, TReturn> = { * Sugar for jest.fn().mockImplementationOnce(() => Promise.reject(value)) */ mockRejectedValueOnce(value: TReturn): JestMockFn>, -}; +|}; type JestAsymmetricEqualityType = { /** @@ -794,7 +794,7 @@ type JestObjectType = { * Returns a new, unused mock function. Optionally takes a mock * implementation. */ - fn, TReturn>( + fn, TReturn>( implementation?: (...args: TArguments) => TReturn, ): JestMockFn, /** From 298f59c5d38424836381faae93a2a782450e2ad4 Mon Sep 17 00:00:00 2001 From: Emily Janzer Date: Tue, 28 May 2019 12:14:36 -0700 Subject: [PATCH 0104/1084] Use startSurface on Android Summary: We currently have two different codepaths for actually rendering a surface with Fabric on iOS and Android: on iOS we use Fabric's `UIManagerBinding.startSurface` to call `AppRegistry.runApplication`, but on Android we don't; instead we use the same codepath as paper, calling `ReactRootView.runApplication`. This diff does a few different things: 1. Unify iOS and Android by removing the `#ifndef` for Android so that we call `startSurface` for both 2. Pass through the JS module name on Android so that this actually works (it currently passes in an empty string) 3. Remove the call to `ReactRootView.runApplication` for Fabric so that we don't end up doing this twice 4. Copy over some logic that we need from `ReactRootView.runApplication` (make sure that root layout specs get updated, and that content appeared gets logged) Reviewed By: mdvacca Differential Revision: D15501666 fbshipit-source-id: 5c96c8cf036261cb99729b1dbdff0f7c09a32d76 --- .../facebook/react/ReactInstanceManager.java | 18 +++++++++---- .../com/facebook/react/ReactRootView.java | 27 ++++++++++++------- .../com/facebook/react/fabric/Binding.java | 2 +- .../react/fabric/FabricUIManager.java | 10 +++++-- .../com/facebook/react/fabric/jni/Binding.cpp | 8 ++++-- .../com/facebook/react/fabric/jni/Binding.h | 5 +++- .../facebook/react/uimanager/ReactRoot.java | 12 +++++++++ ReactCommon/fabric/uimanager/Scheduler.cpp | 4 --- 8 files changed, 62 insertions(+), 24 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java index 8c8bd4ceb6fa7b..e9513a059352bc 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java @@ -1050,16 +1050,24 @@ public void run() { private void attachRootViewToInstance(final ReactRoot reactRoot) { Log.d(ReactConstants.TAG, "ReactInstanceManager.attachRootViewToInstance()"); Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "attachRootViewToInstance"); - UIManager uiManagerModule = UIManagerHelper.getUIManager(mCurrentReactContext, reactRoot.getUIManagerType()); + UIManager uiManager = UIManagerHelper.getUIManager(mCurrentReactContext, reactRoot.getUIManagerType()); @Nullable Bundle initialProperties = reactRoot.getAppProperties(); - final int rootTag = uiManagerModule.addRootView( - reactRoot.getRootViewGroup(), - initialProperties == null ? + + final int rootTag = uiManager.addRootView( + reactRoot.getRootViewGroup(), + initialProperties == null ? new WritableNativeMap() : Arguments.fromBundle(initialProperties), reactRoot.getInitialUITemplate()); reactRoot.setRootViewTag(rootTag); - reactRoot.runApplication(); + if (reactRoot.getUIManagerType() == FABRIC) { + // Fabric requires to call updateRootLayoutSpecs before starting JS Application, + // this ensures the root will hace the correct pointScaleFactor. + uiManager.updateRootLayoutSpecs(rootTag, reactRoot.getWidthMeasureSpec(), reactRoot.getHeightMeasureSpec()); + reactRoot.setShouldLogContentAppeared(true); + } else { + reactRoot.runApplication(); + } Systrace.beginAsyncSection( TRACE_TAG_REACT_JAVA_BRIDGE, "pre_rootView.onAttachedToReactInstance", diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java index 37341ca9242422..3cf5a45d3a85fb 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java @@ -405,6 +405,21 @@ public void startReactApplication( } } + @Override + public int getWidthMeasureSpec() { + return mWidthMeasureSpec; + } + + @Override + public int getHeightMeasureSpec() { + return mHeightMeasureSpec; + } + + @Override + public void setShouldLogContentAppeared(boolean shouldLogContentAppeared) { + mShouldLogContentAppeared = shouldLogContentAppeared; + } + private void updateRootLayoutSpecs(final int widthMeasureSpec, final int heightMeasureSpec) { if (mReactInstanceManager == null) { FLog.w( @@ -461,7 +476,8 @@ public void setEventListener(ReactRootViewEventListener eventListener) { mRootViewEventListener = eventListener; } - /* package */ String getJSModuleName() { + @Override + public String getJSModuleName() { return Assertions.assertNotNull(mJSModuleName); } @@ -506,11 +522,7 @@ public void runApplication() { if (mUseSurface) { // TODO call surface's runApplication } else { - - boolean isFabric = getUIManagerType() == FABRIC; - // Fabric requires to call updateRootLayoutSpecs before starting JS Application, - // this ensures the root will hace the correct pointScaleFactor. - if (mWasMeasured || isFabric) { + if (mWasMeasured) { updateRootLayoutSpecs(mWidthMeasureSpec, mHeightMeasureSpec); } @@ -520,9 +532,6 @@ public void runApplication() { if (appProperties != null) { appParams.putMap("initialProps", Arguments.fromBundle(appProperties)); } - if (isFabric) { - appParams.putBoolean("fabric", true); - } mShouldLogContentAppeared = true; diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/Binding.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/Binding.java index cd2557a4357af4..c41b5bcbe46a75 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/Binding.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/Binding.java @@ -39,7 +39,7 @@ private native void installFabricUIManager( ComponentFactoryDelegate componentsRegistry, Object reactNativeConfig); - public native void startSurface(int surfaceId, NativeMap initialProps); + public native void startSurface(int surfaceId, String moduleName, NativeMap initialProps); public native void renderTemplateToSurface(int surfaceId, String uiTemplate); diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java index 880f9a827c92bd..2741bb08f92630 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -53,6 +53,7 @@ import com.facebook.react.fabric.mounting.mountitems.UpdatePropsMountItem; import com.facebook.react.fabric.mounting.mountitems.UpdateStateMountItem; import com.facebook.react.modules.core.ReactChoreographer; +import com.facebook.react.uimanager.ReactRoot; import com.facebook.react.uimanager.ReactRootViewTagGenerator; import com.facebook.react.uimanager.StateWrapper; import com.facebook.react.uimanager.ThemedReactContext; @@ -127,13 +128,18 @@ public FabricUIManager( @Override public int addRootView( - final T rootView, final WritableMap initialProps, final @Nullable String initialUITemplate) { + final T rootView, final WritableMap initialProps, final @Nullable String initialUITemplate) { + return addRootView(rootView, ((ReactRoot) rootView).getJSModuleName(), initialProps, initialUITemplate); + } + + public int addRootView( + final T rootView, final String moduleName, final WritableMap initialProps, final @Nullable String initialUITemplate) { final int rootTag = ReactRootViewTagGenerator.getNextRootViewTag(); ThemedReactContext reactContext = new ThemedReactContext(mReactApplicationContext, rootView.getContext()); mMountingManager.addRootView(rootTag, rootView); mReactContextForRootTag.put(rootTag, reactContext); - mBinding.startSurface(rootTag, (NativeMap) initialProps); + mBinding.startSurface(rootTag, moduleName, (NativeMap) initialProps); if (initialUITemplate != null) { mBinding.renderTemplateToSurface(rootTag, initialUITemplate); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp index 4effb64e1a0fe0..e38edd549d76bf 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp @@ -45,9 +45,13 @@ jni::local_ref Binding::initHybrid( return makeCxxInstance(); } -void Binding::startSurface(jint surfaceId, NativeMap *initialProps) { +void Binding::startSurface( + jint surfaceId, + jni::alias_ref moduleName, + NativeMap *initialProps) { if (scheduler_) { - scheduler_->startSurface(surfaceId, "", initialProps->consume()); + scheduler_->startSurface( + surfaceId, moduleName->toStdString(), initialProps->consume()); } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.h b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.h index 588e94740f8a91..2a880bc2d8bac4 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.h +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.h @@ -50,7 +50,10 @@ class Binding : public jni::HybridClass, public SchedulerDelegate { ComponentFactoryDelegate *componentsRegistry, jni::alias_ref reactNativeConfig); - void startSurface(jint surfaceId, NativeMap *initialProps); + void startSurface( + jint surfaceId, + jni::alias_ref moduleName, + NativeMap *initialProps); void renderTemplateToSurface(jint surfaceId, jstring uiTemplate); diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactRoot.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactRoot.java index c56216ded0dec9..67db02992660d6 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactRoot.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactRoot.java @@ -23,6 +23,7 @@ public interface ReactRoot { */ @Nullable Bundle getAppProperties(); @Nullable String getInitialUITemplate(); + String getJSModuleName(); /** * Fabric or Default UI Manager, see {@link UIManagerType} @@ -47,4 +48,15 @@ public interface ReactRoot { * Return native view for root */ ViewGroup getRootViewGroup(); + + /** + * @return Cached values for widthMeasureSpec and heightMeasureSpec + */ + int getWidthMeasureSpec(); + int getHeightMeasureSpec(); + + /** + * Sets a flag that determines whether to log that content appeared on next view added. + */ + void setShouldLogContentAppeared(boolean shouldLogContentAppeared); } diff --git a/ReactCommon/fabric/uimanager/Scheduler.cpp b/ReactCommon/fabric/uimanager/Scheduler.cpp index c4637c1a3d5bed..aab1121d9341e8 100644 --- a/ReactCommon/fabric/uimanager/Scheduler.cpp +++ b/ReactCommon/fabric/uimanager/Scheduler.cpp @@ -96,12 +96,10 @@ void Scheduler::startSurface( shadowTreeRegistry_.add(std::move(shadowTree)); -#ifndef ANDROID runtimeExecutor_([=](jsi::Runtime &runtime) { uiManagerBinding_->startSurface( runtime, surfaceId, moduleName, initialProps); }); -#endif } void Scheduler::renderTemplateToSurface( @@ -171,11 +169,9 @@ void Scheduler::stopSurface(SurfaceId surfaceId) const { auto shadowTree = shadowTreeRegistry_.remove(surfaceId); shadowTree->setDelegate(nullptr); -#ifndef ANDROID runtimeExecutor_([=](jsi::Runtime &runtime) { uiManagerBinding_->stopSurface(runtime, surfaceId); }); -#endif } Size Scheduler::measureSurface( From d83ba5ad51abb110819f2a65a69ac3cd865bffdd Mon Sep 17 00:00:00 2001 From: Emily Janzer Date: Tue, 28 May 2019 16:31:56 -0700 Subject: [PATCH 0105/1084] Revert D15488008: Use JS ViewConfig for View Differential Revision: D15488008 Original commit changeset: 48e925ec0ca2 fbshipit-source-id: 4ffa223e636116777c178386b6e966a4f253c30a --- .../View/ReactNativeViewViewConfig.js | 63 +------------------ .../Components/View/ViewNativeComponent.js | 6 +- .../verifyComponentAttributeEquivalence.js | 2 +- 3 files changed, 8 insertions(+), 63 deletions(-) diff --git a/Libraries/Components/View/ReactNativeViewViewConfig.js b/Libraries/Components/View/ReactNativeViewViewConfig.js index 942a269790f1f5..d723f2797e7de1 100644 --- a/Libraries/Components/View/ReactNativeViewViewConfig.js +++ b/Libraries/Components/View/ReactNativeViewViewConfig.js @@ -10,12 +10,12 @@ 'use strict'; -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); - const ReactNativeViewConfig = { uiViewClassName: 'RCTView', + baseModuleName: null, + Manager: 'ViewManager', Commands: {}, + Constants: {}, bubblingEventTypes: { topBlur: { phasedRegistrationNames: { @@ -53,12 +53,6 @@ const ReactNativeViewConfig = { captured: 'onPressCapture', }, }, - topSelect: { - phasedRegistrationNames: { - bubbled: 'onSelect', - captured: 'onSelectCapture', - }, - }, topSubmitEditing: { phasedRegistrationNames: { bubbled: 'onSubmitEditing', @@ -91,9 +85,6 @@ const ReactNativeViewConfig = { }, }, directEventTypes: { - performAction: { - registrationName: 'onAccessibilityAction', - }, topAccessibilityAction: { registrationName: 'onAccessibilityAction', }, @@ -103,48 +94,12 @@ const ReactNativeViewConfig = { topAccessibilityTap: { registrationName: 'onAccessibilityTap', }, - topClick: { - registrationName: 'onClick', - }, - topContentSizeChange: { - registrationName: 'onContentSizeChange', - }, topLayout: { registrationName: 'onLayout', }, - topLoadingError: { - registrationName: 'onLoadingError', - }, - topLoadingFinish: { - registrationName: 'onLoadingFinish', - }, - topLoadingStart: { - registrationName: 'onLoadingStart', - }, topMagicTap: { registrationName: 'onMagicTap', }, - topMessage: { - registrationName: 'onMessage', - }, - topMomentumScrollBegin: { - registrationName: 'onMomentumScrollBegin', - }, - topMomentumScrollEnd: { - registrationName: 'onMomentumScrollEnd', - }, - topScroll: { - registrationName: 'onScroll', - }, - topScrollBeginDrag: { - registrationName: 'onScrollBeginDrag', - }, - topScrollEndDrag: { - registrationName: 'onScrollEndDrag', - }, - topSelectionChange: { - registrationName: 'onSelectionChange', - }, }, validAttributes: { accessibilityActions: true, @@ -201,7 +156,6 @@ const ReactNativeViewConfig = { flexGrow: true, flexShrink: true, flexWrap: true, - hasTVPreferredFocus: true, height: true, hitSlop: {diff: (require('../../Utilities/differ/insetsDiffer'): any)}, importantForAccessibility: true, @@ -220,15 +174,8 @@ const ReactNativeViewConfig = { maxWidth: true, minHeight: true, minWidth: true, - nativeBackgroundAndroid: true, - nativeForegroundAndroid: true, nativeID: true, needsOffscreenAlphaCompositing: true, - nextFocusDown: true, - nextFocusForward: true, - nextFocusLeft: true, - nextFocusRight: true, - nextFocusUp: true, onAccessibilityAction: true, onAccessibilityEscape: true, onAccessibilityTap: true, @@ -379,8 +326,4 @@ const ReactNativeViewConfig = { }, }; -verifyComponentAttributeEquivalence('RCTView', ReactNativeViewConfig); - -ReactNativeViewConfigRegistry.register('RCTView', () => ReactNativeViewConfig); - module.exports = ReactNativeViewConfig; diff --git a/Libraries/Components/View/ViewNativeComponent.js b/Libraries/Components/View/ViewNativeComponent.js index aa7ea2b502141d..21e57c8a437ab5 100644 --- a/Libraries/Components/View/ViewNativeComponent.js +++ b/Libraries/Components/View/ViewNativeComponent.js @@ -12,10 +12,12 @@ const ReactNative = require('../../Renderer/shims/ReactNative'); +const requireNativeComponent = require('../../ReactNative/requireNativeComponent'); + import type {ViewProps} from './ViewPropTypes'; type ViewNativeComponentType = Class>; -require('ReactNativeViewViewConfig'); +const NativeViewComponent = requireNativeComponent('RCTView'); -module.exports = (('RCTView': any): ViewNativeComponentType); +module.exports = ((NativeViewComponent: any): ViewNativeComponentType); diff --git a/Libraries/Utilities/verifyComponentAttributeEquivalence.js b/Libraries/Utilities/verifyComponentAttributeEquivalence.js index 63c66445a159c3..296b7837cbd7af 100644 --- a/Libraries/Utilities/verifyComponentAttributeEquivalence.js +++ b/Libraries/Utilities/verifyComponentAttributeEquivalence.js @@ -14,7 +14,7 @@ const getNativeComponentAttributes = require('../ReactNative/getNativeComponentA import type {ReactNativeBaseComponentViewConfig} from '../Renderer/shims/ReactNativeTypes'; -const IGNORED_KEYS = ['transform', 'hitSlop']; +const IGNORED_KEYS = ['transform']; /** * The purpose of this function is to validate that the view config that * native exposes for a given view manager is the same as the view config From 12b735a378fe8b09905c4b5ec498fcd1356fd06d Mon Sep 17 00:00:00 2001 From: David Vacca Date: Tue, 28 May 2019 17:23:16 -0700 Subject: [PATCH 0106/1084] Create structure of mapbuffer project Summary: Create structure of C++ side of mapbuffer project Reviewed By: shergin Differential Revision: D15529650 fbshipit-source-id: b563d3fbcfddcf46802ccb202e372233baad123d --- ReactCommon/fabric/mapbuffer/BUCK | 66 +++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 ReactCommon/fabric/mapbuffer/BUCK diff --git a/ReactCommon/fabric/mapbuffer/BUCK b/ReactCommon/fabric/mapbuffer/BUCK new file mode 100644 index 00000000000000..c7029191c58da0 --- /dev/null +++ b/ReactCommon/fabric/mapbuffer/BUCK @@ -0,0 +1,66 @@ +load( + "//tools/build_defs/oss:rn_defs.bzl", + "ANDROID", + "fb_xplat_cxx_test", + "react_native_xplat_target", + "rn_xplat_cxx_library", + "subdir_glob", +) + +rn_xplat_cxx_library( + name = "mapbuffer", + srcs = glob( + ["**/*.cpp"], + exclude = glob(["tests/**/*.cpp"]), + ), + headers = glob( + ["**/*.h"], + exclude = glob(["tests/**/*.h"]), + ), + header_namespace = "", + exported_headers = subdir_glob( + [ + ("", "*.h"), + ], + prefix = "react", + ), + compiler_flags = [ + "-fexceptions", + "-frtti", + "-std=c++14", + "-Wall", + ], + force_static = True, + macosx_tests_override = [], + platforms = (ANDROID), + preprocessor_flags = [ + "-DLOG_TAG=\"ReactNative\"", + ], + tests = [":tests"], + visibility = ["PUBLIC"], + deps = [ + "fbsource//xplat/fbsystrace:fbsystrace", + "fbsource//xplat/folly:headers_only", + "fbsource//xplat/folly:memory", + "fbsource//xplat/third-party/glog:glog", + react_native_xplat_target("utils:utils"), + ], +) + +fb_xplat_cxx_test( + name = "tests", + srcs = glob(["tests/**/*.cpp"]), + headers = glob(["tests/**/*.h"]), + compiler_flags = [ + "-fexceptions", + "-frtti", + "-std=c++14", + "-Wall", + ], + contacts = ["oncall+react_native@xmail.facebook.com"], + platforms = (ANDROID), + deps = [ + "fbsource//xplat/folly:molly", + "fbsource//xplat/third-party/gmock:gtest", + ], +) From 382cb05ae6ccf96355d297bcf54055305c2a7bac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= Date: Tue, 28 May 2019 19:06:14 -0700 Subject: [PATCH 0107/1084] Disable Android tests on Appveyor (#25066) Summary: Android is failing on Appveyor. Removing to regain signal on Windows. See https://ci.appveyor.com/project/Facebook/react-native/builds/24869333/job/tnif7yt4x0lfisju for an example. Pull Request resolved: https://github.com/facebook/react-native/pull/25066 Differential Revision: D15532362 Pulled By: hramos fbshipit-source-id: afb55297b385d8b7e497d9cf4d26420f9502df44 --- .appveyor/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor/config.yml b/.appveyor/config.yml index 545f955abeeaa2..a30baf7582a396 100644 --- a/.appveyor/config.yml +++ b/.appveyor/config.yml @@ -38,7 +38,7 @@ build_script: - yarn run flow-check-android - yarn run flow-check-ios - yarn run test - - gradlew.bat RNTester:android:app:assembleRelease + # - gradlew.bat RNTester:android:app:assembleRelease cache: - node_modules From 6677f405a2de0833286671bc308230ea1d574f82 Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Wed, 29 May 2019 07:38:12 -0700 Subject: [PATCH 0108/1084] Deprecate `YGNode::setConfig` Summary: We want to phase out usage of config pointers on nodes. Setting configs is no longer needed, as a config is unly used during construction. Here we deprecate the setter, as it is no longer working as it used to (e.g. changing `useWebDefaults` after a node is constructed). Reviewed By: SidharthGuglani Differential Revision: D15416474 fbshipit-source-id: a2cc06cad0c5148cecce056ece5f141b3defe9a9 --- ReactCommon/yoga/yoga/YGMacros.h | 12 ++++++++++++ ReactCommon/yoga/yoga/YGNode.h | 3 ++- ReactCommon/yoga/yoga/Yoga.cpp | 12 +++++++----- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/ReactCommon/yoga/yoga/YGMacros.h b/ReactCommon/yoga/yoga/YGMacros.h index 9c2989acb97670..badea8c3c3e489 100644 --- a/ReactCommon/yoga/yoga/YGMacros.h +++ b/ReactCommon/yoga/yoga/YGMacros.h @@ -30,3 +30,15 @@ #define YG_ENUM_BEGIN(name) enum name #define YG_ENUM_END(name) name #endif + +#ifdef __GNUC__ +#define YG_DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) +#define YG_DEPRECATED __declspec(deprecated) +#elif __cplusplus >= 201402L +#if defined(__has_cpp_attribute) +#if __has_cpp_attribute(deprecated) +#define YG_DEPRECATED [[deprecated]] +#endif +#endif +#endif diff --git a/ReactCommon/yoga/yoga/YGNode.h b/ReactCommon/yoga/yoga/YGNode.h index e5f1da3ca5ba78..1ef8014214b8e0 100644 --- a/ReactCommon/yoga/yoga/YGNode.h +++ b/ReactCommon/yoga/yoga/YGNode.h @@ -11,6 +11,7 @@ #include "YGConfig.h" #include "YGLayout.h" #include "YGStyle.h" +#include "YGMacros.h" #include "Yoga-internal.h" YGConfigRef YGConfigGetDefault(); @@ -272,7 +273,7 @@ struct YGNode { // TODO: rvalue override for setChildren - void setConfig(YGConfigRef config) { config_ = config; } + YG_DEPRECATED void setConfig(YGConfigRef config) { config_ = config; } void setDirty(bool isDirty); void setLayoutLastOwnerDirection(YGDirection direction); diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index 93ad4148c79bdd..da24a549fd5247 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -253,7 +253,13 @@ static YGConfigRef YGConfigClone(const YGConfig& oldConfig) { } static YGNodeRef YGNodeDeepClone(YGNodeRef oldNode) { - YGNodeRef node = YGNodeClone(oldNode); + auto config = YGConfigClone(*oldNode->getConfig()); + auto node = new YGNode{*oldNode, config}; + node->setOwner(nullptr); +#ifdef YG_ENABLE_EVENTS + Event::publish(node, {node->getConfig()}); +#endif + YGVector vec = YGVector(); vec.reserve(oldNode->getChildren().size()); YGNodeRef childNode = nullptr; @@ -264,10 +270,6 @@ static YGNodeRef YGNodeDeepClone(YGNodeRef oldNode) { } node->setChildren(vec); - if (oldNode->getConfig() != nullptr) { - node->setConfig(YGConfigClone(*(oldNode->getConfig()))); - } - return node; } From 5a5c28a2cf6d4a2c6619041d9ab6cb7c72f8e1f2 Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Wed, 29 May 2019 08:31:04 -0700 Subject: [PATCH 0109/1084] Temporarily bring back the "ToolbarAndroid" export for RN Summary: This unbreaks an issue at FB. Reviewed By: rickhanlonii Differential Revision: D15536623 fbshipit-source-id: 2d59542330d2b951908adf8b6c5c41ca4232bb07 --- Libraries/react-native/react-native-implementation.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js index 1f4ab0051f9d58..66f1ce260e372e 100644 --- a/Libraries/react-native/react-native-implementation.js +++ b/Libraries/react-native/react-native-implementation.js @@ -335,6 +335,10 @@ module.exports = { get ViewPropTypes() { return require('DeprecatedViewPropTypes'); }, + // TODO(cpojer): Temporary fix for missing Toolbar + get ToolbarAndroid() { + return require('UnimplementedView'); + }, }; if (__DEV__) { From a3479c212a935468396872bf448777196784c880 Mon Sep 17 00:00:00 2001 From: Abhinandan Ramaprasath Date: Wed, 29 May 2019 13:01:45 -0700 Subject: [PATCH 0110/1084] Add specs for ModalManager (#24896) Summary: Part of #24875 ## Changelog [General] [Added] - Add TurboModule spec for ModalManager Pull Request resolved: https://github.com/facebook/react-native/pull/24896 Reviewed By: rickhanlonii Differential Revision: D15471097 Pulled By: fkgozali fbshipit-source-id: 99671583ddc2a6fc32fd1bcf9a6e340ad93a27c2 --- Libraries/Modal/Modal.js | 7 +++---- Libraries/Modal/NativeModalManager.js | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 Libraries/Modal/NativeModalManager.js diff --git a/Libraries/Modal/Modal.js b/Libraries/Modal/Modal.js index e364ec0af7f74c..40c03122bb2c14 100644 --- a/Libraries/Modal/Modal.js +++ b/Libraries/Modal/Modal.js @@ -13,7 +13,7 @@ const AppContainer = require('../ReactNative/AppContainer'); const I18nManager = require('../ReactNative/I18nManager'); const NativeEventEmitter = require('../EventEmitter/NativeEventEmitter'); -const NativeModules = require('../BatchedBridge/NativeModules'); +import NativeModalManager from './NativeModalManager'; const Platform = require('../Utilities/Platform'); const React = require('react'); const PropTypes = require('prop-types'); @@ -21,10 +21,9 @@ const StyleSheet = require('../StyleSheet/StyleSheet'); const View = require('../Components/View/View'); const RCTModalHostView = require('./RCTModalHostViewNativeComponent'); - const ModalEventEmitter = - Platform.OS === 'ios' && NativeModules.ModalManager - ? new NativeEventEmitter(NativeModules.ModalManager) + Platform.OS === 'ios' && NativeModalManager != null + ? new NativeEventEmitter(NativeModalManager) : null; import type EmitterSubscription from '../vendor/emitter/EmitterSubscription'; diff --git a/Libraries/Modal/NativeModalManager.js b/Libraries/Modal/NativeModalManager.js new file mode 100644 index 00000000000000..28bf3d9a548d89 --- /dev/null +++ b/Libraries/Modal/NativeModalManager.js @@ -0,0 +1,22 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +export interface Spec extends TurboModule { + // RCTEventEmitter + +addListener: (eventName: string) => void; + +removeListeners: (count: number) => void; +} + +export default TurboModuleRegistry.get('ModalManager'); From 71461cb3dd4ad40dbe4de656bfec4b1a614ffa95 Mon Sep 17 00:00:00 2001 From: michalchudziak Date: Wed, 29 May 2019 13:01:45 -0700 Subject: [PATCH 0111/1084] Add spec for AccessibilityManager (#24894) Summary: Part of https://github.com/facebook/react-native/issues/24875 ## Changelog [General] [Added] - Add TurboModule spec for AccessibilityManager Pull Request resolved: https://github.com/facebook/react-native/pull/24894 Reviewed By: rickhanlonii Differential Revision: D15471243 Pulled By: fkgozali fbshipit-source-id: 33f39d41d70da9380f29f2eb47e8c7682b323030 --- .../AccessibilityInfo.ios.js | 52 +++++++++++++++---- .../NativeAccessibilityManager.js | 45 ++++++++++++++++ 2 files changed, 86 insertions(+), 11 deletions(-) create mode 100644 Libraries/Components/AccessibilityInfo/NativeAccessibilityManager.js diff --git a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.ios.js b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.ios.js index c759491c62ea51..a804af6fd68dd0 100644 --- a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.ios.js +++ b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.ios.js @@ -10,12 +10,11 @@ 'use strict'; -const NativeModules = require('../../BatchedBridge/NativeModules'); +import NativeAccessibilityManager from './NativeAccessibilityManager'; + const Promise = require('../../Promise'); const RCTDeviceEventEmitter = require('../../EventEmitter/RCTDeviceEventEmitter'); -const AccessibilityManager = NativeModules.AccessibilityManager; - const CHANGE_EVENT_NAME = { announcementFinished: 'announcementFinished', boldTextChanged: 'boldTextChanged', @@ -59,7 +58,11 @@ const AccessibilityInfo = { */ isBoldTextEnabled: function(): Promise { return new Promise((resolve, reject) => { - AccessibilityManager.getCurrentBoldTextState(resolve, reject); + if (NativeAccessibilityManager) { + NativeAccessibilityManager.getCurrentBoldTextState(resolve, reject); + } else { + reject(reject); + } }); }, @@ -73,7 +76,11 @@ const AccessibilityInfo = { */ isGrayscaleEnabled: function(): Promise { return new Promise((resolve, reject) => { - AccessibilityManager.getCurrentGrayscaleState(resolve, reject); + if (NativeAccessibilityManager) { + NativeAccessibilityManager.getCurrentGrayscaleState(resolve, reject); + } else { + reject(reject); + } }); }, @@ -87,7 +94,11 @@ const AccessibilityInfo = { */ isInvertColorsEnabled: function(): Promise { return new Promise((resolve, reject) => { - AccessibilityManager.getCurrentInvertColorsState(resolve, reject); + if (NativeAccessibilityManager) { + NativeAccessibilityManager.getCurrentInvertColorsState(resolve, reject); + } else { + reject(reject); + } }); }, @@ -101,7 +112,11 @@ const AccessibilityInfo = { */ isReduceMotionEnabled: function(): Promise { return new Promise((resolve, reject) => { - AccessibilityManager.getCurrentReduceMotionState(resolve, reject); + if (NativeAccessibilityManager) { + NativeAccessibilityManager.getCurrentReduceMotionState(resolve, reject); + } else { + reject(reject); + } }); }, @@ -115,7 +130,14 @@ const AccessibilityInfo = { */ isReduceTransparencyEnabled: function(): Promise { return new Promise((resolve, reject) => { - AccessibilityManager.getCurrentReduceTransparencyState(resolve, reject); + if (NativeAccessibilityManager) { + NativeAccessibilityManager.getCurrentReduceTransparencyState( + resolve, + reject, + ); + } else { + reject(reject); + } }); }, @@ -129,7 +151,11 @@ const AccessibilityInfo = { */ isScreenReaderEnabled: function(): Promise { return new Promise((resolve, reject) => { - AccessibilityManager.getCurrentVoiceOverState(resolve, reject); + if (NativeAccessibilityManager) { + NativeAccessibilityManager.getCurrentVoiceOverState(resolve, reject); + } else { + reject(reject); + } }); }, @@ -204,7 +230,9 @@ const AccessibilityInfo = { * See http://facebook.github.io/react-native/docs/accessibilityinfo.html#setaccessibilityfocus */ setAccessibilityFocus: function(reactTag: number): void { - AccessibilityManager.setAccessibilityFocus(reactTag); + if (NativeAccessibilityManager) { + NativeAccessibilityManager.setAccessibilityFocus(reactTag); + } }, /** @@ -213,7 +241,9 @@ const AccessibilityInfo = { * See http://facebook.github.io/react-native/docs/accessibilityinfo.html#announceforaccessibility */ announceForAccessibility: function(announcement: string): void { - AccessibilityManager.announceForAccessibility(announcement); + if (NativeAccessibilityManager) { + NativeAccessibilityManager.announceForAccessibility(announcement); + } }, /** diff --git a/Libraries/Components/AccessibilityInfo/NativeAccessibilityManager.js b/Libraries/Components/AccessibilityInfo/NativeAccessibilityManager.js new file mode 100644 index 00000000000000..2e90cdf4f8c63b --- /dev/null +++ b/Libraries/Components/AccessibilityInfo/NativeAccessibilityManager.js @@ -0,0 +1,45 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +getCurrentBoldTextState: ( + onSuccess: (isBoldTextEnabled: boolean) => void, + onError: (error: Object) => void, + ) => void; + +getCurrentGrayscaleState: ( + onSuccess: (isGrayscaleEnabled: boolean) => void, + onError: (error: Object) => void, + ) => void; + +getCurrentInvertColorsState: ( + onSuccess: (isInvertColorsEnabled: boolean) => void, + onError: (error: Object) => void, + ) => void; + +getCurrentReduceMotionState: ( + onSuccess: (isReduceMotionEnabled: boolean) => void, + onError: (error: Object) => void, + ) => void; + +getCurrentReduceTransparencyState: ( + onSuccess: (isReduceTransparencyEnabled: boolean) => void, + onError: (error: Object) => void, + ) => void; + +getCurrentVoiceOverState: ( + onSuccess: (isScreenReaderEnabled: boolean) => void, + onError: (error: Object) => void, + ) => void; + +setAccessibilityFocus: (reactTag: number) => void; + +announceForAccessibility: (announcement: string) => void; +} + +export default TurboModuleRegistry.get('AccessibilityManager'); From 40625ceabf8ced0497f7bdeb4c2ed6b659e3e05a Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Wed, 29 May 2019 13:23:04 -0700 Subject: [PATCH 0112/1084] Revert Slider and Activity indicator view configs Summary: Reverting the generated view configs due to a potential issue Reviewed By: mdvacca Differential Revision: D15539319 fbshipit-source-id: bddf923dcfda18bd074196f06610fea8bb4561b4 --- .../ActivityIndicatorViewNativeComponent.js | 6 +- .../ActivityIndicatorViewNativeViewConfig.js | 45 ----------- .../Slider/SliderNativeComponent.js | 4 +- .../Slider/SliderNativeViewConfig.js | 76 ------------------- .../viewconfigs/generate-view-configs-cli.js | 6 +- 5 files changed, 9 insertions(+), 128 deletions(-) delete mode 100644 Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeViewConfig.js delete mode 100644 Libraries/Components/Slider/SliderNativeViewConfig.js diff --git a/Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeComponent.js b/Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeComponent.js index 731b6f3fb27244..213f1d0e796a24 100644 --- a/Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeComponent.js +++ b/Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeComponent.js @@ -18,6 +18,8 @@ import type { import type {ColorValue} from '../../StyleSheet/StyleSheetTypes'; import type {ViewProps} from '../View/ViewPropTypes'; +const requireNativeComponent = require('../../ReactNative/requireNativeComponent'); + type NativeProps = $ReadOnly<{| ...ViewProps, @@ -61,4 +63,6 @@ type ActivityIndicatorNativeType = CodegenNativeComponent< Options, >; -module.exports = ((require('./ActivityIndicatorViewNativeViewConfig'): any): ActivityIndicatorNativeType); +module.exports = ((requireNativeComponent( + 'RCTActivityIndicatorView', +): any): ActivityIndicatorNativeType); diff --git a/Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeViewConfig.js b/Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeViewConfig.js deleted file mode 100644 index 0e448d1d21f24e..00000000000000 --- a/Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeViewConfig.js +++ /dev/null @@ -1,45 +0,0 @@ - -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - */ - -'use strict'; - -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); - -const ActivityIndicatorViewViewConfig = { - uiViewClassName: 'RCTActivityIndicatorView', - Commands: {}, - - bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - }, - - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, - - validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, - hidesWhenStopped: true, - animating: true, - color: { process: require('processColor') }, - size: true, - }, -}; - -verifyComponentAttributeEquivalence('RCTActivityIndicatorView', ActivityIndicatorViewViewConfig); - -ReactNativeViewConfigRegistry.register( - 'RCTActivityIndicatorView', - () => ActivityIndicatorViewViewConfig, -); - -module.exports = 'RCTActivityIndicatorView'; // RCT prefix present for paper support diff --git a/Libraries/Components/Slider/SliderNativeComponent.js b/Libraries/Components/Slider/SliderNativeComponent.js index a100656c2702c3..d7d90e0cdab608 100644 --- a/Libraries/Components/Slider/SliderNativeComponent.js +++ b/Libraries/Components/Slider/SliderNativeComponent.js @@ -22,6 +22,8 @@ import type {ColorValue} from '../../StyleSheet/StyleSheetTypes'; import type {ImageSource} from '../../Image/ImageSource'; import type {ViewProps} from '../View/ViewPropTypes'; +const requireNativeComponent = require('../../ReactNative/requireNativeComponent'); + type Event = $ReadOnly<{| value: Float, fromUser?: boolean, @@ -59,4 +61,4 @@ type Options = { type SliderType = CodegenNativeComponent<'Slider', NativeProps, Options>; -module.exports = ((require('SliderNativeViewConfig'): any): SliderType); +module.exports = ((requireNativeComponent('RCTSlider'): any): SliderType); diff --git a/Libraries/Components/Slider/SliderNativeViewConfig.js b/Libraries/Components/Slider/SliderNativeViewConfig.js deleted file mode 100644 index 92abe056836b21..00000000000000 --- a/Libraries/Components/Slider/SliderNativeViewConfig.js +++ /dev/null @@ -1,76 +0,0 @@ - -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - */ - -'use strict'; - -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); - -const SliderViewConfig = { - uiViewClassName: 'RCTSlider', - Commands: {}, - - bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - - topChange: { - phasedRegistrationNames: { - captured: 'onChangeCapture', - bubbled: 'onChange', - }, - }, - - topValueChange: { - phasedRegistrationNames: { - captured: 'onValueChangeCapture', - bubbled: 'onValueChange', - }, - }, - }, - - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - - topSlidingComplete: { - registrationName: 'onSlidingComplete', - }, - }, - - validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, - disabled: true, - enabled: true, - maximumTrackImage: { process: require('resolveAssetSource') }, - maximumTrackTintColor: { process: require('processColor') }, - maximumValue: true, - minimumTrackImage: { process: require('resolveAssetSource') }, - minimumTrackTintColor: { process: require('processColor') }, - minimumValue: true, - step: true, - testID: true, - thumbImage: { process: require('resolveAssetSource') }, - thumbTintColor: { process: require('processColor') }, - trackImage: { process: require('resolveAssetSource') }, - value: true, - onChange: true, - onValueChange: true, - onSlidingComplete: true, - }, -}; - -verifyComponentAttributeEquivalence('RCTSlider', SliderViewConfig); - -ReactNativeViewConfigRegistry.register( - 'RCTSlider', - () => SliderViewConfig, -); - -module.exports = 'RCTSlider'; // RCT prefix present for paper support diff --git a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js index 8e73febfc260c6..68fc84cb1f80eb 100644 --- a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js +++ b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js @@ -23,11 +23,7 @@ const yargv = yargs.strict().option('t', { const argv = yargv.argv; const fileList = argv._[0].split('\n'); -const CURRENT_VIEW_CONFIG_FILES = [ - 'SliderNativeComponent.js', - 'ActivityIndicatorViewNativeComponent.js', - 'PullToRefreshViewNativeComponent.js', -]; +const CURRENT_VIEW_CONFIG_FILES = []; generate( fileList.filter(fileName => From 96a50010242cc1b33644aaa98ebddaaacd486cb5 Mon Sep 17 00:00:00 2001 From: Emily Janzer Date: Wed, 29 May 2019 16:30:40 -0700 Subject: [PATCH 0113/1084] Add spec for DeviceInfo module Summary: Adding flow types for DeviceInfo module and migrating our codebase over to using `DeviceInfo.getConstants()` Reviewed By: fkgozali Differential Revision: D14645744 fbshipit-source-id: e30a060c6dc92938cd1420ba11a1d837c79d1e32 --- Libraries/Utilities/DeviceInfo.js | 8 +--- Libraries/Utilities/Dimensions.js | 5 +- Libraries/Utilities/NativeDeviceInfo.js | 47 +++++++++++++++++++ .../Utilities/__tests__/DeviceInfo-test.js | 2 +- .../react-native-implementation.js | 2 +- .../SafeAreaView/SafeAreaViewExample.js | 2 +- jest/setup.js | 30 +++++++----- 7 files changed, 72 insertions(+), 24 deletions(-) create mode 100644 Libraries/Utilities/NativeDeviceInfo.js diff --git a/Libraries/Utilities/DeviceInfo.js b/Libraries/Utilities/DeviceInfo.js index 9757f2686e5a70..c3f59c5e88bced 100644 --- a/Libraries/Utilities/DeviceInfo.js +++ b/Libraries/Utilities/DeviceInfo.js @@ -10,10 +10,6 @@ 'use strict'; -const DeviceInfo = require('../BatchedBridge/NativeModules').DeviceInfo; +import NativeDeviceInfo from './NativeDeviceInfo'; -const invariant = require('invariant'); - -invariant(DeviceInfo, 'DeviceInfo native module is not installed correctly'); - -module.exports = DeviceInfo; +module.exports = NativeDeviceInfo; diff --git a/Libraries/Utilities/Dimensions.js b/Libraries/Utilities/Dimensions.js index 383dcc44c8ac5c..508f6b0403dae5 100644 --- a/Libraries/Utilities/Dimensions.js +++ b/Libraries/Utilities/Dimensions.js @@ -14,6 +14,8 @@ const EventEmitter = require('../vendor/emitter/EventEmitter'); const Platform = require('./Platform'); const RCTDeviceEventEmitter = require('../EventEmitter/RCTDeviceEventEmitter'); +import NativeDeviceInfo from './NativeDeviceInfo'; + const invariant = require('invariant'); const eventEmitter = new EventEmitter(); @@ -128,8 +130,7 @@ let dims: ?{[key: string]: any} = global.nativeExtensions.DeviceInfo.Dimensions; let nativeExtensionsEnabled = true; if (!dims) { - const DeviceInfo = require('./DeviceInfo'); - dims = DeviceInfo.Dimensions; + dims = NativeDeviceInfo.getConstants().Dimensions; nativeExtensionsEnabled = false; } diff --git a/Libraries/Utilities/NativeDeviceInfo.js b/Libraries/Utilities/NativeDeviceInfo.js new file mode 100644 index 00000000000000..dd905806547bff --- /dev/null +++ b/Libraries/Utilities/NativeDeviceInfo.js @@ -0,0 +1,47 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +type DisplayMetricsAndroid = {| + width: number, + height: number, + scale: number, + fontScale: number, + densityDpi: number, +|}; + +type DisplayMetricsIOS = {| + width: number, + height: number, + scale: number, + fontScale: number, +|}; + +export interface Spec extends TurboModule { + +getConstants: () => {| + +Dimensions: { + window?: DisplayMetricsIOS, + screen?: DisplayMetricsIOS, + windowPhysicalPixels?: DisplayMetricsAndroid, + screenPhysicalPixels?: DisplayMetricsAndroid, + }, + +isIPhoneX_deprecated?: boolean, + |}; +} + +const NativeModule = TurboModuleRegistry.getEnforcing('DeviceInfo'); + +const NativeDeviceInfo = NativeModule; + +export default NativeDeviceInfo; diff --git a/Libraries/Utilities/__tests__/DeviceInfo-test.js b/Libraries/Utilities/__tests__/DeviceInfo-test.js index 049feb571d7549..8cc9c224461aeb 100644 --- a/Libraries/Utilities/__tests__/DeviceInfo-test.js +++ b/Libraries/Utilities/__tests__/DeviceInfo-test.js @@ -14,6 +14,6 @@ describe('DeviceInfo', () => { const DeviceInfo = require('../DeviceInfo'); it('should give device info', () => { - expect(DeviceInfo).toHaveProperty('Dimensions'); + expect(DeviceInfo.getConstants()).toHaveProperty('Dimensions'); }); }); diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js index 66f1ce260e372e..0b9f07b6aa9ec2 100644 --- a/Libraries/react-native/react-native-implementation.js +++ b/Libraries/react-native/react-native-implementation.js @@ -206,7 +206,7 @@ module.exports = { return require('DatePickerAndroid'); }, get DeviceInfo() { - return require('DeviceInfo'); + return require('NativeDeviceInfo').default; }, get Dimensions() { return require('Dimensions'); diff --git a/RNTester/js/examples/SafeAreaView/SafeAreaViewExample.js b/RNTester/js/examples/SafeAreaView/SafeAreaViewExample.js index 287c19bbfdf604..d92acd76f19c03 100644 --- a/RNTester/js/examples/SafeAreaView/SafeAreaViewExample.js +++ b/RNTester/js/examples/SafeAreaView/SafeAreaViewExample.js @@ -87,7 +87,7 @@ class IsIPhoneXExample extends React.Component<{}> { Is this an iPhone X:{' '} - {DeviceInfo.isIPhoneX_deprecated + {DeviceInfo.getConstants().isIPhoneX_deprecated ? 'Yeah!' : 'Nope. (Or `isIPhoneX_deprecated` was already removed.)'} diff --git a/jest/setup.js b/jest/setup.js index 3a2eb77bd2f05b..e03244ed5d982b 100644 --- a/jest/setup.js +++ b/jest/setup.js @@ -153,19 +153,23 @@ const mockNativeModules = { queryData: jest.fn(), }, DeviceInfo: { - Dimensions: { - window: { - fontScale: 2, - height: 1334, - scale: 2, - width: 750, - }, - screen: { - fontScale: 2, - height: 1334, - scale: 2, - width: 750, - }, + getConstants() { + return { + Dimensions: { + window: { + fontScale: 2, + height: 1334, + scale: 2, + width: 750, + }, + screen: { + fontScale: 2, + height: 1334, + scale: 2, + width: 750, + }, + }, + }; }, }, FacebookSDK: { From e923a2fa684b136bf7c0c54f3fa2acacb88d31a4 Mon Sep 17 00:00:00 2001 From: Sam Goldman Date: Wed, 29 May 2019 18:07:56 -0700 Subject: [PATCH 0114/1084] Use libdefs for fbjs instead of types from node_modules Summary: When code depends on a module from fbjs, its types come from the node_modules directory. This is problematic when Flow is deployed, since we can't codemod the parts that come from node_modules. Reviewed By: dsainati1 Differential Revision: D15547035 fbshipit-source-id: 8794a32e0f5786bcdd80eab98344d4bc623fb674 --- Libraries/Sample/Sample.android.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Libraries/Sample/Sample.android.js b/Libraries/Sample/Sample.android.js index 2b30b41d7defa4..3924e178310770 100644 --- a/Libraries/Sample/Sample.android.js +++ b/Libraries/Sample/Sample.android.js @@ -16,6 +16,7 @@ const warning = require('fbjs/lib/warning'); const Sample = { test: function() { + // $FlowFixMe warning expects a condition warning('Not yet implemented for Android.'); }, }; From 87b31bccdf23246339e6377f0c9e80ac827534ab Mon Sep 17 00:00:00 2001 From: Sam Goldman Date: Wed, 29 May 2019 18:07:56 -0700 Subject: [PATCH 0115/1084] @allow-large-files Deploy Flow v0.99.0 to xplat/js Reviewed By: dsainati1 Differential Revision: D15541620 fbshipit-source-id: e19795e13d47dca58c5603b308b7cd60ba67ef86 --- .flowconfig | 2 +- .flowconfig.android | 2 +- Libraries/Alert/Alert.js | 1 - .../DrawerAndroid/__tests__/DrawerAndroid-test.js | 4 +++- .../Components/Picker/PickerAndroid.android.js | 2 -- .../__tests__/ProgressBarAndroid-test.js | 4 +++- Libraries/Image/ImageSource.js | 1 - Libraries/Lists/SectionList.js | 6 +++--- Libraries/Sample/Sample.android.js | 4 +++- RNTester/js/RNTesterApp.android.js | 2 -- RNTester/js/examples/Picker/PickerExample.js | 3 +++ RNTester/js/utils/RNTesterList.android.js | 14 -------------- RNTester/js/utils/RNTesterNavigationReducer.js | 1 - RNTester/js/utils/URIActionMap.js | 1 - package.json | 2 +- .../cli/viewconfigs/generate-view-configs-cli.js | 4 +++- template/_flowconfig | 2 +- yarn.lock | 8 ++++---- 18 files changed, 26 insertions(+), 37 deletions(-) diff --git a/.flowconfig b/.flowconfig index 16440a06e5521e..69e9a5aef1cdf7 100644 --- a/.flowconfig +++ b/.flowconfig @@ -103,4 +103,4 @@ untyped-import untyped-type-import [version] -^0.98.0 +^0.99.0 diff --git a/.flowconfig.android b/.flowconfig.android index 743e61c8437073..dce8cc3e8bda53 100644 --- a/.flowconfig.android +++ b/.flowconfig.android @@ -103,4 +103,4 @@ untyped-import untyped-type-import [version] -^0.98.0 +^0.99.0 diff --git a/Libraries/Alert/Alert.js b/Libraries/Alert/Alert.js index 63f5b31d4fe30c..c0afc6573bb73f 100644 --- a/Libraries/Alert/Alert.js +++ b/Libraries/Alert/Alert.js @@ -150,7 +150,6 @@ class Alert { }, (id, value) => { const cb = callbacks[id]; - // $FlowFixMe cb && cb(value); }, ); diff --git a/Libraries/Components/DrawerAndroid/__tests__/DrawerAndroid-test.js b/Libraries/Components/DrawerAndroid/__tests__/DrawerAndroid-test.js index e9747a088b26fe..514edf85cc4489 100644 --- a/Libraries/Components/DrawerAndroid/__tests__/DrawerAndroid-test.js +++ b/Libraries/Components/DrawerAndroid/__tests__/DrawerAndroid-test.js @@ -12,7 +12,9 @@ 'use strict'; const React = require('react'); -// $FlowFixMe +/* $FlowFixMe(>=0.99.0 site=react_native_ios_fb) This comment suppresses an + * error found when Flow v0.99 was deployed. To see the error, delete this + * comment and run Flow. */ const DrawerLayoutAndroid = require('../DrawerLayoutAndroid.android'); const View = require('../../View/View'); diff --git a/Libraries/Components/Picker/PickerAndroid.android.js b/Libraries/Components/Picker/PickerAndroid.android.js index d6aafd918add3d..744559b2807584 100644 --- a/Libraries/Components/Picker/PickerAndroid.android.js +++ b/Libraries/Components/Picker/PickerAndroid.android.js @@ -117,8 +117,6 @@ class PickerAndroid extends React.Component< item => item != null, ); const value = children[position].props.value; - /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was - * found when making Flow check .android.js files. */ if (this.props.selectedValue !== value) { this.props.onValueChange(value, position); } diff --git a/Libraries/Components/ProgressBarAndroid/__tests__/ProgressBarAndroid-test.js b/Libraries/Components/ProgressBarAndroid/__tests__/ProgressBarAndroid-test.js index 9f479341b0658f..ccce645eb49aa5 100644 --- a/Libraries/Components/ProgressBarAndroid/__tests__/ProgressBarAndroid-test.js +++ b/Libraries/Components/ProgressBarAndroid/__tests__/ProgressBarAndroid-test.js @@ -12,7 +12,9 @@ 'use strict'; const React = require('react'); -// $FlowFixMe +/* $FlowFixMe(>=0.99.0 site=react_native_ios_fb) This comment suppresses an + * error found when Flow v0.99 was deployed. To see the error, delete this + * comment and run Flow. */ const ProgressBarAndroid = require('../ProgressBarAndroid.android'); const render = require('../../../../jest/renderer'); diff --git a/Libraries/Image/ImageSource.js b/Libraries/Image/ImageSource.js index 0e03dc78c0f5d1..4607ef14223357 100644 --- a/Libraries/Image/ImageSource.js +++ b/Libraries/Image/ImageSource.js @@ -87,5 +87,4 @@ export type ImageURISource = $ReadOnly<{ // We have to export any because of an issue in Flow with objects that come from Relay: // https://fburl.com/8ljo5tmr // https://fb.facebook.com/groups/flow/permalink/1824103160971624/ -// $FlowFixMe T26861415 export type ImageSource = ImageURISource | number | Array; diff --git a/Libraries/Lists/SectionList.js b/Libraries/Lists/SectionList.js index 076fb0e29f66b9..f1bbe26bd4a808 100644 --- a/Libraries/Lists/SectionList.js +++ b/Libraries/Lists/SectionList.js @@ -303,9 +303,6 @@ class SectionList> extends React.PureComponent< render() { return ( - /* $FlowFixMe(>=0.66.0 site=react_native_fb) This comment suppresses an - * error found when Flow v0.66 was deployed. To see the error delete this - * comment and run Flow. */ > extends React.PureComponent< _wrapperListRef: ?React.ElementRef; _captureRef = ref => { + /* $FlowFixMe(>=0.99.0 site=react_native_fb) This comment suppresses an + * error found when Flow v0.99 was deployed. To see the error, delete this + * comment and run Flow. */ this._wrapperListRef = ref; }; } diff --git a/Libraries/Sample/Sample.android.js b/Libraries/Sample/Sample.android.js index 3924e178310770..3a7a25b51155c9 100644 --- a/Libraries/Sample/Sample.android.js +++ b/Libraries/Sample/Sample.android.js @@ -16,7 +16,9 @@ const warning = require('fbjs/lib/warning'); const Sample = { test: function() { - // $FlowFixMe warning expects a condition + /* $FlowFixMe(>=0.99.0 site=react_native_android_fb) This comment + * suppresses an error found when Flow v0.99 was deployed. To see the + * error, delete this comment and run Flow. */ warning('Not yet implemented for Android.'); }, }; diff --git a/RNTester/js/RNTesterApp.android.js b/RNTester/js/RNTesterApp.android.js index b87a9198b27430..a7c79047de9664 100644 --- a/RNTester/js/RNTesterApp.android.js +++ b/RNTester/js/RNTesterApp.android.js @@ -29,8 +29,6 @@ const { const RNTesterActions = require('./utils/RNTesterActions'); const RNTesterExampleContainer = require('./components/RNTesterExampleContainer'); const RNTesterExampleList = require('./components/RNTesterExampleList'); -/* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found when - * making Flow check .android.js files. */ const RNTesterList = require('./utils/RNTesterList'); const RNTesterNavigationReducer = require('./utils/RNTesterNavigationReducer'); const URIActionMap = require('./utils/URIActionMap'); diff --git a/RNTester/js/examples/Picker/PickerExample.js b/RNTester/js/examples/Picker/PickerExample.js index 417f9387cffc68..b9af4bb67e2f3a 100644 --- a/RNTester/js/examples/Picker/PickerExample.js +++ b/RNTester/js/examples/Picker/PickerExample.js @@ -167,6 +167,9 @@ exports.examples = [ title: 'Picker with no listener', render: function(): React.Element { return ( + /* $FlowFixMe(>=0.99.0 site=react_native_fb) This comment suppresses an + * error found when Flow v0.99 was deployed. To see the error, delete + * this comment and run Flow. */ <> diff --git a/RNTester/js/utils/RNTesterList.android.js b/RNTester/js/utils/RNTesterList.android.js index cf9f10f78e7a91..929d0b78cea949 100644 --- a/RNTester/js/utils/RNTesterList.android.js +++ b/RNTester/js/utils/RNTesterList.android.js @@ -55,8 +55,6 @@ const ComponentExamples: Array = [ }, { key: 'ProgressBarAndroidExample', - /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found - * when making Flow check .android.js files. */ module: require('../examples/ProgressBarAndroid/ProgressBarAndroidExample'), }, { @@ -85,14 +83,10 @@ const ComponentExamples: Array = [ }, { key: 'TextExample', - /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found - * when making Flow check .android.js files. */ module: require('../examples/Text/TextExample'), }, { key: 'TextInputExample', - /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found - * when making Flow check .android.js files. */ module: require('../examples/TextInput/TextInputExample'), }, { @@ -105,8 +99,6 @@ const ComponentExamples: Array = [ }, { key: 'ViewPagerAndroidExample', - /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found - * when making Flow check .android.js files. */ module: require('../examples/ViewPagerAndroid/ViewPagerAndroidExample'), }, ]; @@ -118,8 +110,6 @@ const APIExamples: Array = [ }, { key: 'AccessibilityAndroidExample', - /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found - * when making Flow check .android.js files. */ module: require('../examples/Accessibility/AccessibilityAndroidExample'), }, { @@ -184,8 +174,6 @@ const APIExamples: Array = [ }, { key: 'PermissionsExampleAndroid', - /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found - * when making Flow check .android.js files. */ module: require('../examples/PermissionsAndroid/PermissionsExample'), }, { @@ -210,8 +198,6 @@ const APIExamples: Array = [ }, { key: 'ToastAndroidExample', - /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found - * when making Flow check .android.js files. */ module: require('../examples/ToastAndroid/ToastAndroidExample'), }, { diff --git a/RNTester/js/utils/RNTesterNavigationReducer.js b/RNTester/js/utils/RNTesterNavigationReducer.js index a7b68d6bc9b68d..b406eabcf3a660 100644 --- a/RNTester/js/utils/RNTesterNavigationReducer.js +++ b/RNTester/js/utils/RNTesterNavigationReducer.js @@ -10,7 +10,6 @@ 'use strict'; -// $FlowFixMe : This is a platform-forked component, and flow seems to only run on iOS? const RNTesterList = require('./RNTesterList'); export type RNTesterNavigationState = { diff --git a/RNTester/js/utils/URIActionMap.js b/RNTester/js/utils/URIActionMap.js index 3dba73d27bf8ca..d03f40572a092a 100644 --- a/RNTester/js/utils/URIActionMap.js +++ b/RNTester/js/utils/URIActionMap.js @@ -12,7 +12,6 @@ const ReactNative = require('react-native'); const RNTesterActions = require('./RNTesterActions'); -// $FlowFixMe : This is a platform-forked component, and flow seems to only run on iOS? const RNTesterList = require('./RNTesterList'); const {Alert} = ReactNative; diff --git a/package.json b/package.json index 38ae1245970930..ec40027e2ddc36 100644 --- a/package.json +++ b/package.json @@ -128,7 +128,7 @@ "eslint-plugin-react-hooks": "^1.5.1", "eslint-plugin-react-native": "3.6.0", "eslint-plugin-relay": "1.3.0", - "flow-bin": "^0.98.0", + "flow-bin": "^0.99.0", "flow-remove-types": "1.2.3", "jest": "^24.7.1", "jest-junit": "^6.3.0", diff --git a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js index 68fc84cb1f80eb..6603717369500f 100644 --- a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js +++ b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js @@ -31,6 +31,8 @@ generate( fileName.endsWith(supportedFileName), ), ), - // $FlowFixMe Type argv + /* $FlowFixMe(>=0.99.0 site=react_native_fb) This comment suppresses an error + * found when Flow v0.99 was deployed. To see the error, delete this comment + * and run Flow. */ {test: argv.test, parser: 'flow'}, ); diff --git a/template/_flowconfig b/template/_flowconfig index 1319ea127818c3..2047ef0464540a 100644 --- a/template/_flowconfig +++ b/template/_flowconfig @@ -96,4 +96,4 @@ untyped-import untyped-type-import [version] -^0.98.0 +^0.99.0 diff --git a/yarn.lock b/yarn.lock index 000f16ca52c9c9..1db6f52c69c42d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3198,10 +3198,10 @@ flat-cache@^1.2.1: rimraf "~2.6.2" write "^0.2.1" -flow-bin@^0.98.0: - version "0.98.0" - resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.98.0.tgz#3361a03682326a83a5f0a864749f4f7f0d826bce" - integrity sha512-vuiYjBVt82eYF+dEk9Zqa8hTSDvbhl/czxzFRLZm9/XHbJnYNMTwFoNFYAQT9IQ6ACNBIbwSTIfxroieuKja7g== +flow-bin@^0.99.0: + version "0.99.1" + resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.99.1.tgz#0d4f413ca84a3a95d0aa64214178684dd7c6a4c5" + integrity sha512-dipNwJlb4MsVt3IuDgPTymCNL4GFoq3pG+GbY6DmBbl0dJPWFSA383rCTmgbfFhoeJ1XCfYBan0BPryToSxiiQ== flow-parser@0.*: version "0.89.0" From 82fe1b05210fd703381c0a053bd3310bf12a4f1a Mon Sep 17 00:00:00 2001 From: Krzysztof Borowy Date: Wed, 29 May 2019 18:23:47 -0700 Subject: [PATCH 0116/1084] add spec for PermissionsAndroid (#24886) Summary: Part of #24875 ## Changelog [General] [Added] - Add TurboModule spec for PermissionsAndroid Pull Request resolved: https://github.com/facebook/react-native/pull/24886 Reviewed By: RSNara Differential Revision: D15542996 Pulled By: fkgozali fbshipit-source-id: cab02d97e70d65347f63e891cff98c17adc1fdba --- .../NativePermissionsAndroid.js | 59 +++++++ .../PermissionsAndroid/PermissionsAndroid.js | 145 +++++++++++------- 2 files changed, 147 insertions(+), 57 deletions(-) create mode 100644 Libraries/PermissionsAndroid/NativePermissionsAndroid.js diff --git a/Libraries/PermissionsAndroid/NativePermissionsAndroid.js b/Libraries/PermissionsAndroid/NativePermissionsAndroid.js new file mode 100644 index 00000000000000..fbac01fc8de583 --- /dev/null +++ b/Libraries/PermissionsAndroid/NativePermissionsAndroid.js @@ -0,0 +1,59 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow strict-local + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +// TODO: Use proper enum types. +export type PermissionStatus = string; +export type PermissionType = string; +/* +export type PermissionStatus = 'granted' | 'denied' | 'never_ask_again'; +export type PermissionType = + | 'android.permission.READ_CALENDAR' + | 'android.permission.WRITE_CALENDAR' + | 'android.permission.CAMERA' + | 'android.permission.READ_CONTACTS' + | 'android.permission.WRITE_CONTACTS' + | 'android.permission.GET_ACCOUNTS' + | 'android.permission.ACCESS_FINE_LOCATION' + | 'android.permission.ACCESS_COARSE_LOCATION' + | 'android.permission.RECORD_AUDIO' + | 'android.permission.READ_PHONE_STATE' + | 'android.permission.CALL_PHONE' + | 'android.permission.READ_CALL_LOG' + | 'android.permission.WRITE_CALL_LOG' + | 'com.android.voicemail.permission.ADD_VOICEMAIL' + | 'android.permission.USE_SIP' + | 'android.permission.PROCESS_OUTGOING_CALLS' + | 'android.permission.BODY_SENSORS' + | 'android.permission.SEND_SMS' + | 'android.permission.RECEIVE_SMS' + | 'android.permission.READ_SMS' + | 'android.permission.RECEIVE_WAP_PUSH' + | 'android.permission.RECEIVE_MMS' + | 'android.permission.READ_EXTERNAL_STORAGE' + | 'android.permission.WRITE_EXTERNAL_STORAGE'; +*/ + +export interface Spec extends TurboModule { + +checkPermission: (permission: PermissionType) => Promise; + +requestPermission: (permission: PermissionType) => Promise; + +shouldShowRequestPermissionRationale: ( + permission: string, + ) => Promise; + +requestMultiplePermissions: ( + permissions: Array, + ) => Promise<{[permission: PermissionType]: PermissionStatus}>; +} + +export default TurboModuleRegistry.getEnforcing('PermissionsAndroid'); diff --git a/Libraries/PermissionsAndroid/PermissionsAndroid.js b/Libraries/PermissionsAndroid/PermissionsAndroid.js index 91522c89109012..1b414e71165a29 100644 --- a/Libraries/PermissionsAndroid/PermissionsAndroid.js +++ b/Libraries/PermissionsAndroid/PermissionsAndroid.js @@ -12,6 +12,13 @@ import NativeDialogManagerAndroid from '../NativeModules/specs/NativeDialogManagerAndroid'; const NativeModules = require('../BatchedBridge/NativeModules'); +const Platform = require('../Utilities/Platform'); +import NativePermissionsAndroid from './NativePermissionsAndroid'; + +import type { + PermissionStatus, + PermissionType, +} from './NativePermissionsAndroid'; export type Rationale = { title: string, @@ -21,7 +28,39 @@ export type Rationale = { buttonNeutral?: string, }; -type PermissionStatus = 'granted' | 'denied' | 'never_ask_again'; +const PERMISSION_REQUEST_RESULT = Object.freeze({ + GRANTED: 'granted', + DENIED: 'denied', + NEVER_ASK_AGAIN: 'never_ask_again', +}); + +const PERMISSIONS = Object.freeze({ + READ_CALENDAR: 'android.permission.READ_CALENDAR', + WRITE_CALENDAR: 'android.permission.WRITE_CALENDAR', + CAMERA: 'android.permission.CAMERA', + READ_CONTACTS: 'android.permission.READ_CONTACTS', + WRITE_CONTACTS: 'android.permission.WRITE_CONTACTS', + GET_ACCOUNTS: 'android.permission.GET_ACCOUNTS', + ACCESS_FINE_LOCATION: 'android.permission.ACCESS_FINE_LOCATION', + ACCESS_COARSE_LOCATION: 'android.permission.ACCESS_COARSE_LOCATION', + RECORD_AUDIO: 'android.permission.RECORD_AUDIO', + READ_PHONE_STATE: 'android.permission.READ_PHONE_STATE', + CALL_PHONE: 'android.permission.CALL_PHONE', + READ_CALL_LOG: 'android.permission.READ_CALL_LOG', + WRITE_CALL_LOG: 'android.permission.WRITE_CALL_LOG', + ADD_VOICEMAIL: 'com.android.voicemail.permission.ADD_VOICEMAIL', + USE_SIP: 'android.permission.USE_SIP', + PROCESS_OUTGOING_CALLS: 'android.permission.PROCESS_OUTGOING_CALLS', + BODY_SENSORS: 'android.permission.BODY_SENSORS', + SEND_SMS: 'android.permission.SEND_SMS', + RECEIVE_SMS: 'android.permission.RECEIVE_SMS', + READ_SMS: 'android.permission.READ_SMS', + RECEIVE_WAP_PUSH: 'android.permission.RECEIVE_WAP_PUSH', + RECEIVE_MMS: 'android.permission.RECEIVE_MMS', + READ_EXTERNAL_STORAGE: 'android.permission.READ_EXTERNAL_STORAGE', + WRITE_EXTERNAL_STORAGE: 'android.permission.WRITE_EXTERNAL_STORAGE', +}); + /** * `PermissionsAndroid` provides access to Android M's new permissions model. * @@ -29,46 +68,8 @@ type PermissionStatus = 'granted' | 'denied' | 'never_ask_again'; */ class PermissionsAndroid { - PERMISSIONS: Object; - RESULTS: Object; - - constructor() { - /** - * A list of specified "dangerous" permissions that require prompting the user - */ - this.PERMISSIONS = { - READ_CALENDAR: 'android.permission.READ_CALENDAR', - WRITE_CALENDAR: 'android.permission.WRITE_CALENDAR', - CAMERA: 'android.permission.CAMERA', - READ_CONTACTS: 'android.permission.READ_CONTACTS', - WRITE_CONTACTS: 'android.permission.WRITE_CONTACTS', - GET_ACCOUNTS: 'android.permission.GET_ACCOUNTS', - ACCESS_FINE_LOCATION: 'android.permission.ACCESS_FINE_LOCATION', - ACCESS_COARSE_LOCATION: 'android.permission.ACCESS_COARSE_LOCATION', - RECORD_AUDIO: 'android.permission.RECORD_AUDIO', - READ_PHONE_STATE: 'android.permission.READ_PHONE_STATE', - CALL_PHONE: 'android.permission.CALL_PHONE', - READ_CALL_LOG: 'android.permission.READ_CALL_LOG', - WRITE_CALL_LOG: 'android.permission.WRITE_CALL_LOG', - ADD_VOICEMAIL: 'com.android.voicemail.permission.ADD_VOICEMAIL', - USE_SIP: 'android.permission.USE_SIP', - PROCESS_OUTGOING_CALLS: 'android.permission.PROCESS_OUTGOING_CALLS', - BODY_SENSORS: 'android.permission.BODY_SENSORS', - SEND_SMS: 'android.permission.SEND_SMS', - RECEIVE_SMS: 'android.permission.RECEIVE_SMS', - READ_SMS: 'android.permission.READ_SMS', - RECEIVE_WAP_PUSH: 'android.permission.RECEIVE_WAP_PUSH', - RECEIVE_MMS: 'android.permission.RECEIVE_MMS', - READ_EXTERNAL_STORAGE: 'android.permission.READ_EXTERNAL_STORAGE', - WRITE_EXTERNAL_STORAGE: 'android.permission.WRITE_EXTERNAL_STORAGE', - }; - - this.RESULTS = { - GRANTED: 'granted', - DENIED: 'denied', - NEVER_ASK_AGAIN: 'never_ask_again', - }; - } + PERMISSIONS = PERMISSIONS; + RESULTS = PERMISSION_REQUEST_RESULT; /** * DEPRECATED - use check @@ -78,11 +79,18 @@ class PermissionsAndroid { * * @deprecated */ - checkPermission(permission: string): Promise { + checkPermission(permission: PermissionType): Promise { console.warn( '"PermissionsAndroid.checkPermission" is deprecated. Use "PermissionsAndroid.check" instead', ); - return NativeModules.PermissionsAndroid.checkPermission(permission); + if (Platform.OS !== 'android') { + console.warn( + '"PermissionsAndroid" module works only for Android platform.', + ); + return Promise.resolve(false); + } + + return NativePermissionsAndroid.checkPermission(permission); } /** @@ -91,8 +99,14 @@ class PermissionsAndroid { * * See https://facebook.github.io/react-native/docs/permissionsandroid.html#check */ - check(permission: string): Promise { - return NativeModules.PermissionsAndroid.checkPermission(permission); + check(permission: PermissionType): Promise { + if (Platform.OS !== 'android') { + console.warn( + '"PermissionsAndroid" module works only for Android platform.', + ); + return Promise.resolve(false); + } + return NativePermissionsAndroid.checkPermission(permission); } /** @@ -110,12 +124,19 @@ class PermissionsAndroid { * @deprecated */ async requestPermission( - permission: string, + permission: PermissionType, rationale?: Rationale, ): Promise { console.warn( '"PermissionsAndroid.requestPermission" is deprecated. Use "PermissionsAndroid.request" instead', ); + if (Platform.OS !== 'android') { + console.warn( + '"PermissionsAndroid" module works only for Android platform.', + ); + return Promise.resolve(false); + } + const response = await this.request(permission, rationale); return response === this.RESULTS.GRANTED; } @@ -127,11 +148,18 @@ class PermissionsAndroid { * See https://facebook.github.io/react-native/docs/permissionsandroid.html#request */ async request( - permission: string, + permission: PermissionType, rationale?: Rationale, ): Promise { + if (Platform.OS !== 'android') { + console.warn( + '"PermissionsAndroid" module works only for Android platform.', + ); + return Promise.resolve(this.RESULTS.DENIED); + } + if (rationale) { - const shouldShowRationale = await NativeModules.PermissionsAndroid.shouldShowRequestPermissionRationale( + const shouldShowRationale = await NativePermissionsAndroid.shouldShowRequestPermissionRationale( permission, ); @@ -144,14 +172,12 @@ class PermissionsAndroid { options, () => reject(new Error('Error showing rationale')), () => - resolve( - NativeModules.PermissionsAndroid.requestPermission(permission), - ), + resolve(NativePermissionsAndroid.requestPermission(permission)), ); }); } } - return NativeModules.PermissionsAndroid.requestPermission(permission); + return NativePermissionsAndroid.requestPermission(permission); } /** @@ -162,11 +188,16 @@ class PermissionsAndroid { * See https://facebook.github.io/react-native/docs/permissionsandroid.html#requestmultiple */ requestMultiple( - permissions: Array, - ): Promise<{[permission: string]: PermissionStatus}> { - return NativeModules.PermissionsAndroid.requestMultiplePermissions( - permissions, - ); + permissions: Array, + ): Promise<{[permission: PermissionType]: PermissionStatus}> { + if (Platform.OS !== 'android') { + console.warn( + '"PermissionsAndroid" module works only for Android platform.', + ); + return Promise.resolve({}); + } + + return NativePermissionsAndroid.requestMultiplePermissions(permissions); } } From aaa4127332ae858ae5d3ea40d1fcfbbe9c3ef5b0 Mon Sep 17 00:00:00 2001 From: Eric Lewis Date: Wed, 29 May 2019 18:23:47 -0700 Subject: [PATCH 0117/1084] Add spec for Settings (#24879) Summary: part of #24875. I again, am not completely sure how the call site here works- appears settings can be directly accessed? ## Changelog [General] [Added] - Add TM spec for Settings Pull Request resolved: https://github.com/facebook/react-native/pull/24879 Reviewed By: RSNara Differential Revision: D15543012 Pulled By: fkgozali fbshipit-source-id: a1df3096a2fc5fe8e65d0ed2398912530bd3911a --- Libraries/Settings/NativeSettingsManager.js | 24 +++++++++++++++++++++ Libraries/Settings/Settings.ios.js | 8 +++---- 2 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 Libraries/Settings/NativeSettingsManager.js diff --git a/Libraries/Settings/NativeSettingsManager.js b/Libraries/Settings/NativeSettingsManager.js new file mode 100644 index 00000000000000..fd050c996b7cf4 --- /dev/null +++ b/Libraries/Settings/NativeSettingsManager.js @@ -0,0 +1,24 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +getConstants: () => {| + settings: Object, + |}; + +setValues: (values: Object) => void; + +deleteValues: (values: Array) => void; +} + +export default TurboModuleRegistry.getEnforcing('SettingsManager'); diff --git a/Libraries/Settings/Settings.ios.js b/Libraries/Settings/Settings.ios.js index 4084364721ec3e..c802759f764d1b 100644 --- a/Libraries/Settings/Settings.ios.js +++ b/Libraries/Settings/Settings.ios.js @@ -11,15 +11,15 @@ 'use strict'; const RCTDeviceEventEmitter = require('../EventEmitter/RCTDeviceEventEmitter'); -const RCTSettingsManager = require('../BatchedBridge/NativeModules') - .SettingsManager; +import NativeSettingsManager from './NativeSettingsManager'; const invariant = require('invariant'); const subscriptions: Array<{keys: Array, callback: ?Function}> = []; const Settings = { - _settings: RCTSettingsManager && RCTSettingsManager.settings, + _settings: + NativeSettingsManager && NativeSettingsManager.getConstants().settings, get(key: string): mixed { return this._settings[key]; @@ -27,7 +27,7 @@ const Settings = { set(settings: Object) { this._settings = Object.assign(this._settings, settings); - RCTSettingsManager.setValues(settings); + NativeSettingsManager.setValues(settings); }, watchKeys(keys: string | Array, callback: Function): number { From 08efb1d73b73073cb8509bd5fe0189189d31392c Mon Sep 17 00:00:00 2001 From: Wojteg1337 Date: Wed, 29 May 2019 18:23:47 -0700 Subject: [PATCH 0118/1084] Add spec for AndroidToast (#24888) Summary: part of #24875 ## Changelog [General] [Added] - Add TM spec for AndroidToast Pull Request resolved: https://github.com/facebook/react-native/pull/24888 Reviewed By: RSNara Differential Revision: D15543043 Pulled By: fkgozali fbshipit-source-id: 6636dd913f7c006704ead1aa92d37e42a4edf70e --- .../ToastAndroid/NativeToastAndroid.js | 39 +++++++++++++++++++ .../ToastAndroid/ToastAndroid.android.js | 21 +++++----- .../ToastAndroid/ToastAndroid.ios.js | 18 +++++++++ 3 files changed, 66 insertions(+), 12 deletions(-) create mode 100644 Libraries/Components/ToastAndroid/NativeToastAndroid.js diff --git a/Libraries/Components/ToastAndroid/NativeToastAndroid.js b/Libraries/Components/ToastAndroid/NativeToastAndroid.js new file mode 100644 index 00000000000000..89e74438740986 --- /dev/null +++ b/Libraries/Components/ToastAndroid/NativeToastAndroid.js @@ -0,0 +1,39 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +getConstants: () => {| + SHORT: number, + LONG: number, + TOP: number, + BOTTOM: number, + CENTER: number, + |}; + +show: (message: string, duration: number) => void; + +showWithGravity: ( + message: string, + duration: number, + gravity: number, + ) => void; + +showWithGravityAndOffset: ( + message: string, + duration: number, + gravity: number, + xOffset: number, + yOffset: number, + ) => void; +} + +export default TurboModuleRegistry.getEnforcing('ToastAndroid'); diff --git a/Libraries/Components/ToastAndroid/ToastAndroid.android.js b/Libraries/Components/ToastAndroid/ToastAndroid.android.js index 30207d30a9ce71..ff1db3cf90bf88 100644 --- a/Libraries/Components/ToastAndroid/ToastAndroid.android.js +++ b/Libraries/Components/ToastAndroid/ToastAndroid.android.js @@ -9,9 +9,7 @@ */ 'use strict'; - -const RCTToastAndroid = require('../../BatchedBridge/NativeModules') - .ToastAndroid; +import NativeToastAndroid from './NativeToastAndroid'; /** * This exposes the native ToastAndroid module as a JS module. This has a function 'show' @@ -36,16 +34,15 @@ const RCTToastAndroid = require('../../BatchedBridge/NativeModules') const ToastAndroid = { // Toast duration constants - SHORT: RCTToastAndroid.SHORT, - LONG: RCTToastAndroid.LONG, - + SHORT: NativeToastAndroid.getConstants().SHORT, + LONG: NativeToastAndroid.getConstants().LONG, // Toast gravity constants - TOP: RCTToastAndroid.TOP, - BOTTOM: RCTToastAndroid.BOTTOM, - CENTER: RCTToastAndroid.CENTER, + TOP: NativeToastAndroid.getConstants().TOP, + BOTTOM: NativeToastAndroid.getConstants().BOTTOM, + CENTER: NativeToastAndroid.getConstants().CENTER, show: function(message: string, duration: number): void { - RCTToastAndroid.show(message, duration); + NativeToastAndroid.show(message, duration); }, showWithGravity: function( @@ -53,7 +50,7 @@ const ToastAndroid = { duration: number, gravity: number, ): void { - RCTToastAndroid.showWithGravity(message, duration, gravity); + NativeToastAndroid.showWithGravity(message, duration, gravity); }, showWithGravityAndOffset: function( @@ -63,7 +60,7 @@ const ToastAndroid = { xOffset: number, yOffset: number, ): void { - RCTToastAndroid.showWithGravityAndOffset( + NativeToastAndroid.showWithGravityAndOffset( message, duration, gravity, diff --git a/Libraries/Components/ToastAndroid/ToastAndroid.ios.js b/Libraries/Components/ToastAndroid/ToastAndroid.ios.js index ed5fcf02f40116..d0528ff65dc35e 100644 --- a/Libraries/Components/ToastAndroid/ToastAndroid.ios.js +++ b/Libraries/Components/ToastAndroid/ToastAndroid.ios.js @@ -16,6 +16,24 @@ const ToastAndroid = { show: function(message: string, duration: number): void { warning(false, 'ToastAndroid is not supported on this platform.'); }, + + showWithGravity: function( + message: string, + duration: number, + gravity: number, + ): void { + warning(false, 'ToastAndroid is not supported on this platform.'); + }, + + showWithGravityAndOffset: function( + message: string, + duration: number, + gravity: number, + xOffset: number, + yOffset: number, + ): void { + warning(false, 'ToastAndroid is not supported on this platform.'); + }, }; module.exports = ToastAndroid; From e8037cb942bf7dab13cc7e18baee53db720411f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Wed, 29 May 2019 18:23:47 -0700 Subject: [PATCH 0119/1084] Add spec for Networking (#24892) Summary: Part of #24875, adds a spec for Networking. Since `sendRequest` methods are different for both platforms, I had to create 2 spec files as Flow would merge their definitions even when I added `Platform.OS` check ## Changelog [General] [Added] - TM spec for Networking Pull Request resolved: https://github.com/facebook/react-native/pull/24892 Reviewed By: RSNara Differential Revision: D15543067 Pulled By: fkgozali fbshipit-source-id: 2b91114dfa45e7899bbb139656a30a6fd52e31db --- Libraries/Network/NativeNetworkingAndroid.js | 38 ++++++++++++++++++++ Libraries/Network/NativeNetworkingIOS.js | 38 ++++++++++++++++++++ Libraries/Network/RCTNetworking.android.js | 13 ++++--- Libraries/Network/RCTNetworking.ios.js | 15 ++++---- 4 files changed, 89 insertions(+), 15 deletions(-) create mode 100644 Libraries/Network/NativeNetworkingAndroid.js create mode 100644 Libraries/Network/NativeNetworkingIOS.js diff --git a/Libraries/Network/NativeNetworkingAndroid.js b/Libraries/Network/NativeNetworkingAndroid.js new file mode 100644 index 00000000000000..6db46cef70f5e9 --- /dev/null +++ b/Libraries/Network/NativeNetworkingAndroid.js @@ -0,0 +1,38 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +type Header = [string, string]; + +export interface Spec extends TurboModule { + +sendRequest: ( + method: string, + url: string, + requestId: number, + headers: Array

, + data: Object, + responseType: Object, // TODO: Use stricter type. + useIncrementalUpdates: boolean, + timeout: number, + withCredentials: boolean, + ) => void; + +abortRequest: (requestId: number) => void; + +clearCookies: (callback: (result: boolean) => mixed) => void; + + // RCTEventEmitter + +addListener: (eventName: string) => void; + +removeListeners: (count: number) => void; +} + +export default TurboModuleRegistry.getEnforcing('Networking'); diff --git a/Libraries/Network/NativeNetworkingIOS.js b/Libraries/Network/NativeNetworkingIOS.js new file mode 100644 index 00000000000000..f61b3520a0ea67 --- /dev/null +++ b/Libraries/Network/NativeNetworkingIOS.js @@ -0,0 +1,38 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +sendRequest: ( + query: {| + method: string, + url: string, + data: Object, + headers: Object, + responseType: Object, // TODO: Use stricter type. + incrementalUpdates: boolean, + timeout: number, + withCredentials: boolean, + |}, + callback: (requestId: number) => mixed, + ) => void; + +abortRequest: (requestId: number) => void; + +clearCookies: (callback: (result: boolean) => mixed) => void; + + // RCTEventEmitter + +addListener: (eventName: string) => void; + +removeListeners: (count: number) => void; +} + +export default TurboModuleRegistry.getEnforcing('Networking'); diff --git a/Libraries/Network/RCTNetworking.android.js b/Libraries/Network/RCTNetworking.android.js index 89435e2714cf9a..c809b8dcdd3a18 100644 --- a/Libraries/Network/RCTNetworking.android.js +++ b/Libraries/Network/RCTNetworking.android.js @@ -13,8 +13,7 @@ // Do not require the native RCTNetworking module directly! Use this wrapper module instead. // It will add the necessary requestId, so that you don't have to generate it yourself. const NativeEventEmitter = require('../EventEmitter/NativeEventEmitter'); -const RCTNetworkingNative = require('../BatchedBridge/NativeModules') - .Networking; +import NativeNetworkingAndroid from './NativeNetworkingAndroid'; const convertRequestBody = require('./convertRequestBody'); import type {RequestBody} from './convertRequestBody'; @@ -42,7 +41,7 @@ function generateRequestId(): number { */ class RCTNetworking extends NativeEventEmitter { constructor() { - super(RCTNetworkingNative); + super(NativeNetworkingAndroid); } sendRequest( @@ -54,7 +53,7 @@ class RCTNetworking extends NativeEventEmitter { responseType: 'text' | 'base64', incrementalUpdates: boolean, timeout: number, - callback: (requestId: number) => any, + callback: (requestId: number) => mixed, withCredentials: boolean, ) { const body = convertRequestBody(data); @@ -65,7 +64,7 @@ class RCTNetworking extends NativeEventEmitter { })); } const requestId = generateRequestId(); - RCTNetworkingNative.sendRequest( + NativeNetworkingAndroid.sendRequest( method, url, requestId, @@ -80,11 +79,11 @@ class RCTNetworking extends NativeEventEmitter { } abortRequest(requestId: number) { - RCTNetworkingNative.abortRequest(requestId); + NativeNetworkingAndroid.abortRequest(requestId); } clearCookies(callback: (result: boolean) => any) { - RCTNetworkingNative.clearCookies(callback); + NativeNetworkingAndroid.clearCookies(callback); } } diff --git a/Libraries/Network/RCTNetworking.ios.js b/Libraries/Network/RCTNetworking.ios.js index 6905142cbff471..62f4f26b7894b6 100644 --- a/Libraries/Network/RCTNetworking.ios.js +++ b/Libraries/Network/RCTNetworking.ios.js @@ -11,8 +11,7 @@ 'use strict'; const NativeEventEmitter = require('../EventEmitter/NativeEventEmitter'); -const RCTNetworkingNative = require('../BatchedBridge/NativeModules') - .Networking; +import NativeNetworkingIOS from './NativeNetworkingIOS'; const convertRequestBody = require('./convertRequestBody'); import type {RequestBody} from './convertRequestBody'; @@ -21,7 +20,7 @@ import type {NativeResponseType} from './XMLHttpRequest'; class RCTNetworking extends NativeEventEmitter { constructor() { - super(RCTNetworkingNative); + super(NativeNetworkingIOS); } sendRequest( @@ -33,11 +32,11 @@ class RCTNetworking extends NativeEventEmitter { responseType: NativeResponseType, incrementalUpdates: boolean, timeout: number, - callback: (requestId: number) => any, + callback: (requestId: number) => mixed, withCredentials: boolean, ) { const body = convertRequestBody(data); - RCTNetworkingNative.sendRequest( + NativeNetworkingIOS.sendRequest( { method, url, @@ -53,11 +52,11 @@ class RCTNetworking extends NativeEventEmitter { } abortRequest(requestId: number) { - RCTNetworkingNative.abortRequest(requestId); + NativeNetworkingIOS.abortRequest(requestId); } - clearCookies(callback: (result: boolean) => any) { - RCTNetworkingNative.clearCookies(callback); + clearCookies(callback: (result: boolean) => mixed) { + NativeNetworkingIOS.clearCookies(callback); } } From 338298417f8077dee177057c57b38671b4ec8c75 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Thu, 30 May 2019 02:00:03 -0700 Subject: [PATCH 0120/1084] Timing: Fixes timer when app get into background (#24649) Summary: Related #23674, in that PR, we imported background timer support, but it's not sufficient, I think the reason that works is because it enable the `Background Modes` and do some background tasks, for the users who don't enable it, timer would pause immediately before goes into background. To fix it, we can mark a background task when goes into background, it can keep app active for minutes, try best to support timing when in background. cc. cpojer . ## Changelog [iOS] [Fixed] - Timing: Fixes timer when app get into background Pull Request resolved: https://github.com/facebook/react-native/pull/24649 Differential Revision: D15554451 Pulled By: cpojer fbshipit-source-id: a33f7afe6b63d1a4fefcb7098459aee0c09145da --- React/Modules/RCTTiming.m | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/React/Modules/RCTTiming.m b/React/Modules/RCTTiming.m index ef4ec94819e3eb..7568dff8a58a8f 100644 --- a/React/Modules/RCTTiming.m +++ b/React/Modules/RCTTiming.m @@ -97,6 +97,7 @@ @implementation RCTTiming NSTimer *_sleepTimer; BOOL _sendIdleEvents; BOOL _inBackground; + UIBackgroundTaskIdentifier _backgroundTaskIdentifier; } @synthesize bridge = _bridge; @@ -112,6 +113,7 @@ - (void)setBridge:(RCTBridge *)bridge _paused = YES; _timers = [NSMutableDictionary new]; _inBackground = NO; + _backgroundTaskIdentifier = UIBackgroundTaskInvalid; for (NSString *name in @[UIApplicationWillResignActiveNotification, UIApplicationDidEnterBackgroundNotification, @@ -135,10 +137,35 @@ - (void)setBridge:(RCTBridge *)bridge - (void)dealloc { + [self markEndOfBackgroundTaskIfNeeded]; [_sleepTimer invalidate]; [[NSNotificationCenter defaultCenter] removeObserver:self]; } +- (void)markStartOfBackgroundTaskIfNeeded +{ + if (_backgroundTaskIdentifier == UIBackgroundTaskInvalid) { + __weak typeof(self) weakSelf = self; + // Marks the beginning of a new long-running background task. We can run the timer in the background. + _backgroundTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ + typeof(self) strongSelf = weakSelf; + if (!strongSelf) { + return; + } + // Mark the end of background task + [strongSelf markEndOfBackgroundTaskIfNeeded]; + }]; + } +} + +- (void)markEndOfBackgroundTaskIfNeeded +{ + if (_backgroundTaskIdentifier != UIBackgroundTaskInvalid) { + [[UIApplication sharedApplication] endBackgroundTask:_backgroundTaskIdentifier]; + _backgroundTaskIdentifier = UIBackgroundTaskInvalid; + } +} + - (dispatch_queue_t)methodQueue { return RCTJSThread; @@ -163,6 +190,7 @@ - (void)appDidMoveToBackground - (void)appDidMoveToForeground { + [self markEndOfBackgroundTaskIfNeeded]; _inBackground = NO; [self startTimers]; } @@ -260,6 +288,7 @@ - (void)didUpdateFrame:(RCTFrameUpdate *)update } if (_inBackground) { if (timerCount) { + [self markStartOfBackgroundTaskIfNeeded]; [self scheduleSleepTimer:nextScheduledTarget]; } } else if (!_sendIdleEvents && timersToCall.count == 0) { @@ -338,6 +367,7 @@ - (void)timerDidFire } if (_inBackground) { + [self markStartOfBackgroundTaskIfNeeded]; [self scheduleSleepTimer:timer.target]; } else if (_paused) { if ([timer.target timeIntervalSinceNow] > kMinimumSleepInterval) { From 6d54423b788ba2f0ec5c7eda9b2ab3d66a5bd529 Mon Sep 17 00:00:00 2001 From: Johan-dutoit Date: Thu, 30 May 2019 02:51:49 -0700 Subject: [PATCH 0121/1084] Add a deprecation warning when importing ImagePickerIOS (#25074) Summary: Added a deprecation warning for the ImagePickerIOS, module as part of #23313. ## Changelog [General] [Deprecated] - ImagePickerIOS [was moved to community repo](https://github.com/react-native-community/react-native-image-picker-ios) Pull Request resolved: https://github.com/facebook/react-native/pull/25074 Differential Revision: D15554728 Pulled By: cpojer fbshipit-source-id: 867f4c1db64064fef7511d8ff3dc0a621281eb7b --- Libraries/react-native/react-native-implementation.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js index 0b9f07b6aa9ec2..727d8f3415cce5 100644 --- a/Libraries/react-native/react-native-implementation.js +++ b/Libraries/react-native/react-native-implementation.js @@ -221,6 +221,13 @@ module.exports = { return require('I18nManager'); }, get ImagePickerIOS() { + warnOnce( + 'imagePickerIOS-moved', + 'ImagePickerIOS has been extracted from react-native core and will be removed in a future release. ' + + "Please upgrade to use either '@react-native-community/react-native-image-picker' or 'expo-image-picker'. " + + "If you cannot upgrade to a different library, please install the deprecated '@react-native-community/image-picker-ios' package. " + + 'See https://github.com/react-native-community/react-native-image-picker-ios', + ); return require('ImagePickerIOS'); }, get InteractionManager() { From c83a89daa6a2a562f46a1805d48a17c18e7f3cb4 Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Thu, 30 May 2019 04:49:00 -0700 Subject: [PATCH 0122/1084] Upgrade RN gesture handler to 1.1.1 Summary: React Native Gesture Handler used to eagerly initialize all of its exports and therefore required a bunch of things from React Native eagerly. When we remove things from RN via the Lean Core project, this leads to failures. I asked Krzysztof to make a patch release that lazily loads them instead: https://github.com/kmagiera/react-native-gesture-handler/commit/da658c2de2e7135871e27284d9c8c6d323c5d803 Reviewed By: rickhanlonii Differential Revision: D15554658 fbshipit-source-id: aa4b82e5a3c2c837d160da914f41756d26cd6c07 --- Libraries/react-native/react-native-implementation.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js index 727d8f3415cce5..dbe17f81de8d51 100644 --- a/Libraries/react-native/react-native-implementation.js +++ b/Libraries/react-native/react-native-implementation.js @@ -342,10 +342,6 @@ module.exports = { get ViewPropTypes() { return require('DeprecatedViewPropTypes'); }, - // TODO(cpojer): Temporary fix for missing Toolbar - get ToolbarAndroid() { - return require('UnimplementedView'); - }, }; if (__DEV__) { From d31e90648e03911f54abc2874d388df124d99c21 Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Thu, 30 May 2019 06:48:11 -0700 Subject: [PATCH 0123/1084] Add deprecation messages for NetInfo and CameraRoll Summary: I simply removed them from RN but we should give an actionable error message for people who upgrade from older versions of RN and who may be using these old modules, at least in `__DEV__`. Reviewed By: rickhanlonii Differential Revision: D15554863 fbshipit-source-id: 1975d4773581258776d2586ae820677bb14488f6 --- .../react-native-implementation.js | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js index dbe17f81de8d51..94aeecb53941e9 100644 --- a/Libraries/react-native/react-native-implementation.js +++ b/Libraries/react-native/react-native-implementation.js @@ -383,4 +383,30 @@ if (__DEV__) { ); }, }); + + // $FlowFixMe This is intentional: Flow will error when attempting to access NetInfo. + Object.defineProperty(module.exports, 'NetInfo', { + configurable: true, + get() { + invariant( + false, + 'NetInfo has been removed from React Native. ' + + "It can now be installed and imported from 'react-native-netinfo' instead of 'react-native'. " + + 'See https://github.com/react-native-community/react-native-netinfo', + ); + }, + }); + + // $FlowFixMe This is intentional: Flow will error when attempting to access CameraRoll. + Object.defineProperty(module.exports, 'CameraRoll', { + configurable: true, + get() { + invariant( + false, + 'CameraRoll has been removed from React Native. ' + + "It can now be installed and imported from 'react-native-cameraroll' instead of 'react-native'. " + + 'See https://github.com/react-native-community/react-native-cameraroll', + ); + }, + }); } From 33ee6f8b99d423dbe8e604852232a63d5abe94d4 Mon Sep 17 00:00:00 2001 From: James Ide Date: Thu, 30 May 2019 07:41:37 -0700 Subject: [PATCH 0124/1084] Add a lint rule to disallow Haste imports (#25058) Summary: This is an ESLint plugin that infers whether an import looks like a Haste module name. To keep the linter fast and simple, it does not look in the Haste map. Instead, it looks for uppercase characters in single-name import paths, since npm has disallowed uppercase letters in package names for a long time. There are some false negatives (e.g. "merge" is a Haste module and this linter rule would not pick it up) but those are about 1.1% of the module names in the RN repo, and unit tests and integration tests will fail anyway once Haste is turned off. You can disable the lint rule on varying granular levels with ESLint's normal disabling/enabling mechanisms. Also rewrote more Haste imports so that the linter passes (i.e. fixed lint errors as part of this PR). ## Changelog [General] [Changed] - Add a lint rule to disallow Haste imports Pull Request resolved: https://github.com/facebook/react-native/pull/25058 Differential Revision: D15515826 Pulled By: cpojer fbshipit-source-id: d58a3c30dfe0887f8a530e3393af4af5a1ec1cac --- .eslintrc | 8 ++ Libraries/Alert/NativeAlertManager.js | 4 +- .../Animated/src/NativeAnimatedModule.js | 4 +- .../__tests__/MessageQueue-test.js | 2 +- .../__tests__/NativeModules-test.js | 2 +- .../NativeAccessibilityManager.js | 4 +- .../PullToRefreshViewNativeViewConfig.js | 10 +-- .../ToastAndroid/NativeToastAndroid.js | 4 +- Libraries/Image/NativeImageEditor.js | 4 +- Libraries/Modal/NativeModalManager.js | 4 +- .../specs/NativeDialogManagerAndroid.js | 4 +- Libraries/Network/NativeNetworkingAndroid.js | 4 +- Libraries/Network/NativeNetworkingIOS.js | 4 +- .../NativePermissionsAndroid.js | 4 +- Libraries/Settings/NativeSettingsManager.js | 4 +- Libraries/Utilities/NativeDeviceInfo.js | 4 +- .../react-native-implementation.js | 4 +- .../androidTest/js/ScrollViewTestModule.js | 2 +- package.json | 1 + .../index.js | 1 + .../README.md | 21 ++++++ .../index.js | 12 +++ .../no-haste-imports.js | 73 +++++++++++++++++++ .../package.json | 11 +++ yarn.lock | 5 ++ 25 files changed, 167 insertions(+), 33 deletions(-) create mode 100644 packages/eslint-plugin-react-native-community/README.md create mode 100644 packages/eslint-plugin-react-native-community/index.js create mode 100644 packages/eslint-plugin-react-native-community/no-haste-imports.js create mode 100644 packages/eslint-plugin-react-native-community/package.json diff --git a/.eslintrc b/.eslintrc index d18f7eb8286127..9c36dc1804f899 100644 --- a/.eslintrc +++ b/.eslintrc @@ -6,6 +6,14 @@ ], "overrides": [ + { + "files": [ + "Libraries/**/*.js", + ], + rules: { + '@react-native-community/no-haste-imports': 2 + } + }, { "files": [ "**/__fixtures__/**/*.js", diff --git a/Libraries/Alert/NativeAlertManager.js b/Libraries/Alert/NativeAlertManager.js index 0a540cac72770f..16191e7e4721e9 100644 --- a/Libraries/Alert/NativeAlertManager.js +++ b/Libraries/Alert/NativeAlertManager.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; export type Buttons = Array<{ text?: string, diff --git a/Libraries/Animated/src/NativeAnimatedModule.js b/Libraries/Animated/src/NativeAnimatedModule.js index b13d6f33191bc4..80ece9d69d04cf 100644 --- a/Libraries/Animated/src/NativeAnimatedModule.js +++ b/Libraries/Animated/src/NativeAnimatedModule.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../../TurboModule/TurboModuleRegistry'; type EndResult = {finished: boolean}; type EndCallback = (result: EndResult) => void; diff --git a/Libraries/BatchedBridge/__tests__/MessageQueue-test.js b/Libraries/BatchedBridge/__tests__/MessageQueue-test.js index f8568cae72d172..0c2db74b5266e5 100644 --- a/Libraries/BatchedBridge/__tests__/MessageQueue-test.js +++ b/Libraries/BatchedBridge/__tests__/MessageQueue-test.js @@ -33,7 +33,7 @@ describe('MessageQueue', function() { beforeEach(function() { jest.resetModules(); MessageQueue = require('../MessageQueue'); - MessageQueueTestModule = require('MessageQueueTestModule'); + MessageQueueTestModule = require('../__mocks__/MessageQueueTestModule'); queue = new MessageQueue(); queue.registerCallableModule( 'MessageQueueTestModule', diff --git a/Libraries/BatchedBridge/__tests__/NativeModules-test.js b/Libraries/BatchedBridge/__tests__/NativeModules-test.js index 6457385f233acb..3bc364694ed2ac 100644 --- a/Libraries/BatchedBridge/__tests__/NativeModules-test.js +++ b/Libraries/BatchedBridge/__tests__/NativeModules-test.js @@ -40,7 +40,7 @@ describe('MessageQueue', function() { beforeEach(function() { jest.resetModules(); - global.__fbBatchedBridgeConfig = require('MessageQueueTestConfig'); + global.__fbBatchedBridgeConfig = require('../__mocks__/MessageQueueTestConfig'); BatchedBridge = require('../BatchedBridge'); NativeModules = require('../NativeModules'); }); diff --git a/Libraries/Components/AccessibilityInfo/NativeAccessibilityManager.js b/Libraries/Components/AccessibilityInfo/NativeAccessibilityManager.js index 2e90cdf4f8c63b..b0fe8dd1d7ed70 100644 --- a/Libraries/Components/AccessibilityInfo/NativeAccessibilityManager.js +++ b/Libraries/Components/AccessibilityInfo/NativeAccessibilityManager.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { +getCurrentBoldTextState: ( diff --git a/Libraries/Components/RefreshControl/PullToRefreshViewNativeViewConfig.js b/Libraries/Components/RefreshControl/PullToRefreshViewNativeViewConfig.js index 27a1071076e540..f76c8e02dd2140 100644 --- a/Libraries/Components/RefreshControl/PullToRefreshViewNativeViewConfig.js +++ b/Libraries/Components/RefreshControl/PullToRefreshViewNativeViewConfig.js @@ -10,9 +10,9 @@ 'use strict'; -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); +const ReactNativeViewConfigRegistry = require('../../Renderer/shims/ReactNativeViewConfigRegistry'); +const ReactNativeViewViewConfig = require('../View/ReactNativeViewViewConfig'); +const verifyComponentAttributeEquivalence = require('../../Utilities/verifyComponentAttributeEquivalence'); const PullToRefreshViewViewConfig = { uiViewClassName: 'PullToRefreshView', @@ -35,8 +35,8 @@ const PullToRefreshViewViewConfig = { validAttributes: { ...ReactNativeViewViewConfig.validAttributes, - tintColor: { process: require('processColor') }, - titleColor: { process: require('processColor') }, + tintColor: { process: require('../../StyleSheet/processColor') }, + titleColor: { process: require('../../StyleSheet/processColor') }, title: true, refreshing: true, onRefresh: true, diff --git a/Libraries/Components/ToastAndroid/NativeToastAndroid.js b/Libraries/Components/ToastAndroid/NativeToastAndroid.js index 89e74438740986..079a7d0112bcfd 100644 --- a/Libraries/Components/ToastAndroid/NativeToastAndroid.js +++ b/Libraries/Components/ToastAndroid/NativeToastAndroid.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { +getConstants: () => {| diff --git a/Libraries/Image/NativeImageEditor.js b/Libraries/Image/NativeImageEditor.js index 4f4da0b5388b67..e208cb47b6df1c 100644 --- a/Libraries/Image/NativeImageEditor.js +++ b/Libraries/Image/NativeImageEditor.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { +cropImage: ( diff --git a/Libraries/Modal/NativeModalManager.js b/Libraries/Modal/NativeModalManager.js index 28bf3d9a548d89..d293caf68f45c3 100644 --- a/Libraries/Modal/NativeModalManager.js +++ b/Libraries/Modal/NativeModalManager.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { // RCTEventEmitter diff --git a/Libraries/NativeModules/specs/NativeDialogManagerAndroid.js b/Libraries/NativeModules/specs/NativeDialogManagerAndroid.js index 1ffb71c8ce8260..d1e1f9a7c83962 100644 --- a/Libraries/NativeModules/specs/NativeDialogManagerAndroid.js +++ b/Libraries/NativeModules/specs/NativeDialogManagerAndroid.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../../TurboModule/TurboModuleRegistry'; /* 'buttonClicked' | 'dismissed' */ type DialogAction = string; diff --git a/Libraries/Network/NativeNetworkingAndroid.js b/Libraries/Network/NativeNetworkingAndroid.js index 6db46cef70f5e9..06ccdf29fa154e 100644 --- a/Libraries/Network/NativeNetworkingAndroid.js +++ b/Libraries/Network/NativeNetworkingAndroid.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; type Header = [string, string]; diff --git a/Libraries/Network/NativeNetworkingIOS.js b/Libraries/Network/NativeNetworkingIOS.js index f61b3520a0ea67..5c685de7845743 100644 --- a/Libraries/Network/NativeNetworkingIOS.js +++ b/Libraries/Network/NativeNetworkingIOS.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { +sendRequest: ( diff --git a/Libraries/PermissionsAndroid/NativePermissionsAndroid.js b/Libraries/PermissionsAndroid/NativePermissionsAndroid.js index fbac01fc8de583..025f9af18419b1 100644 --- a/Libraries/PermissionsAndroid/NativePermissionsAndroid.js +++ b/Libraries/PermissionsAndroid/NativePermissionsAndroid.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; // TODO: Use proper enum types. export type PermissionStatus = string; diff --git a/Libraries/Settings/NativeSettingsManager.js b/Libraries/Settings/NativeSettingsManager.js index fd050c996b7cf4..19de825248cdb9 100644 --- a/Libraries/Settings/NativeSettingsManager.js +++ b/Libraries/Settings/NativeSettingsManager.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { +getConstants: () => {| diff --git a/Libraries/Utilities/NativeDeviceInfo.js b/Libraries/Utilities/NativeDeviceInfo.js index dd905806547bff..8e0b785a6fbc4f 100644 --- a/Libraries/Utilities/NativeDeviceInfo.js +++ b/Libraries/Utilities/NativeDeviceInfo.js @@ -10,8 +10,8 @@ 'use strict'; -import type {TurboModule} from 'RCTExport'; -import * as TurboModuleRegistry from 'TurboModuleRegistry'; +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; type DisplayMetricsAndroid = {| width: number, diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js index 94aeecb53941e9..8e0a72c5ce0858 100644 --- a/Libraries/react-native/react-native-implementation.js +++ b/Libraries/react-native/react-native-implementation.js @@ -10,8 +10,10 @@ 'use strict'; +/* eslint-disable @react-native-community/no-haste-imports */ + const invariant = require('invariant'); -const warnOnce = require('warnOnce'); +const warnOnce = require('../Utilities/warnOnce'); // Export React, plus some native additions. module.exports = { diff --git a/ReactAndroid/src/androidTest/js/ScrollViewTestModule.js b/ReactAndroid/src/androidTest/js/ScrollViewTestModule.js index 5da2b7686caa9c..3e097245800083 100644 --- a/ReactAndroid/src/androidTest/js/ScrollViewTestModule.js +++ b/ReactAndroid/src/androidTest/js/ScrollViewTestModule.js @@ -25,7 +25,7 @@ const {ScrollListener} = NativeModules; const NUM_ITEMS = 100; -import type {PressEvent} from 'CoreEventTypes'; +import type {PressEvent} from 'react-native/Libraries/Types/CoreEventTypes'; // Shared by integration tests for ScrollView and HorizontalScrollView diff --git a/package.json b/package.json index ec40027e2ddc36..d9bbd3257e2a31 100644 --- a/package.json +++ b/package.json @@ -109,6 +109,7 @@ "devDependencies": { "@babel/core": "^7.0.0", "@babel/generator": "^7.0.0", + "@react-native-community/eslint-plugin": "1.0.0", "@reactions/component": "^2.0.2", "async": "^2.4.0", "babel-eslint": "10.0.1", diff --git a/packages/eslint-config-react-native-community/index.js b/packages/eslint-config-react-native-community/index.js index d1cfc6948713e2..8691452b8fab27 100644 --- a/packages/eslint-config-react-native-community/index.js +++ b/packages/eslint-config-react-native-community/index.js @@ -22,6 +22,7 @@ module.exports = { 'react', 'react-hooks', 'react-native', + '@react-native-community', 'jest', ], diff --git a/packages/eslint-plugin-react-native-community/README.md b/packages/eslint-plugin-react-native-community/README.md new file mode 100644 index 00000000000000..262c7e92171884 --- /dev/null +++ b/packages/eslint-plugin-react-native-community/README.md @@ -0,0 +1,21 @@ +# eslint-plugin-react-native-community + +This plugin is intended to be used in `@react-native-community/eslint-plugin`. You probably want to install that package instead. + +## Installation + +``` +yarn add --dev eslint @react-native-community/eslint-plugin +``` + +*Note: We're using `yarn` to install deps. Feel free to change commands to use `npm` 3+ and `npx` if you like* + +## Usage + +Add to your eslint config (`.eslintrc`, or `eslintConfig` field in `package.json`): + +```json +{ + "plugins": ["@react-native-community"] +} +``` diff --git a/packages/eslint-plugin-react-native-community/index.js b/packages/eslint-plugin-react-native-community/index.js new file mode 100644 index 00000000000000..f0165057500822 --- /dev/null +++ b/packages/eslint-plugin-react-native-community/index.js @@ -0,0 +1,12 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +exports.rules = { + 'no-haste-imports': require('./no-haste-imports'), +}; diff --git a/packages/eslint-plugin-react-native-community/no-haste-imports.js b/packages/eslint-plugin-react-native-community/no-haste-imports.js new file mode 100644 index 00000000000000..5282c6950ec2d6 --- /dev/null +++ b/packages/eslint-plugin-react-native-community/no-haste-imports.js @@ -0,0 +1,73 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +module.exports = { + meta: { + type: 'problem', + docs: { + description: + 'disallow Haste module names in import statements and require calls', + }, + schema: [], + }, + + create(context) { + return { + ImportDeclaration(node) { + checkImportForHaste(context, node.source.value, node.source); + }, + CallExpression(node) { + if (isStaticRequireCall(node)) { + const [firstArgument] = node.arguments; + checkImportForHaste(context, firstArgument.value, firstArgument); + } + }, + }; + }, +}; + +function checkImportForHaste(context, importPath, node) { + if (isLikelyHasteModuleName(importPath)) { + context.report({ + node, + message: `"${importPath}" appears to be a Haste module name. Use path-based imports instead.`, + }); + } +} + +function isLikelyHasteModuleName(importPath) { + // Our heuristic assumes an import path is a Haste module name if it is not a + // path and doesn't appear to be an npm package. For several years, npm has + // disallowed uppercase characters in package names. + // + // This heuristic has a ~1% false negative rate for the filenames in React + // Native, which is acceptable since the linter will not complain wrongly and + // the rate is so low. False negatives that slip through will be caught by + // tests with Haste disabled. + return ( + // Exclude relative paths + !importPath.startsWith('.') && + // Exclude package-internal paths and scoped packages + !importPath.includes('/') && + // Include camelCase and UpperCamelCase + /[A-Z]/.test(importPath) + ); +} + +function isStaticRequireCall(node) { + return ( + node && + node.callee && + node.callee.type === 'Identifier' && + node.callee.name === 'require' && + node.arguments.length === 1 && + node.arguments[0].type === 'Literal' && + typeof node.arguments[0].value === 'string' + ); +} diff --git a/packages/eslint-plugin-react-native-community/package.json b/packages/eslint-plugin-react-native-community/package.json new file mode 100644 index 00000000000000..5a6c28f26d0281 --- /dev/null +++ b/packages/eslint-plugin-react-native-community/package.json @@ -0,0 +1,11 @@ +{ + "name": "@react-native-community/eslint-plugin", + "version": "1.0.0", + "description": "ESLint rules for @react-native-community/eslint-config", + "main": "index.js", + "repository": { + "type": "git", + "url": "git@github.com:facebook/react-native.git" + }, + "license": "MIT" +} diff --git a/yarn.lock b/yarn.lock index 1db6f52c69c42d..37f37f1218e584 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1160,6 +1160,11 @@ shell-quote "1.6.1" ws "^1.1.0" +"@react-native-community/eslint-plugin@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@react-native-community/eslint-plugin/-/eslint-plugin-1.0.0.tgz#ae9a430f2c5795debca491f15a989fce86ea75a0" + integrity sha512-GLhSN8dRt4lpixPQh+8prSCy6PYk/MT/mvji/ojAd5yshowDo6HFsimCSTD/uWAdjpUq91XK9tVdTNWfGRlKQA== + "@reactions/component@^2.0.2": version "2.0.2" resolved "https://registry.yarnpkg.com/@reactions/component/-/component-2.0.2.tgz#40f8c1c2c37baabe57a0c944edb9310dc1ec6642" From aac95b409b38200c3e2a357c5faf77cf8273cb32 Mon Sep 17 00:00:00 2001 From: Oleksandr Melnykov Date: Thu, 30 May 2019 10:32:51 -0700 Subject: [PATCH 0125/1084] Fix switch being stuck in intermidiate state on Android Summary: This diff fixes the bug of the switch component on Android being stuck in the middle when a user releases their finger whily dragging the thumb. When a user releases their finger while dragging the thumb, `setChecked` will be called and if `mAllowChange` is set to false, `super.setChecked` is never called. The supper method will actually make sure the thumb will be animated to the correct edge. Without calling the super method, the thumb might stay in the middle of the switch where a user released their finger. The fix had to be applied both to ReactSwitch and FbReactSwitchCompat. One more fix had to be made to FbReactSwitchCompat since D5884661 was applied to ReactSwitch, but not to FbReactSwitchCompat: if (mAllowChange && **isChecked() != checked**) { ... } Reviewed By: mdvacca Differential Revision: D15535611 fbshipit-source-id: 22ca1fe3fa993ae65cbd677bfae2208a02c368d4 --- .../com/facebook/react/views/switchview/ReactSwitch.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitch.java b/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitch.java index fc716387770c11..dbbffb4bd78607 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitch.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/switchview/ReactSwitch.java @@ -37,6 +37,11 @@ public void setChecked(boolean checked) { mAllowChange = false; super.setChecked(checked); setTrackColor(checked); + } else { + // Even if mAllowChange is set to false or the checked value hasn't changed, we still must + // call the super method, since it will make sure the thumb is moved back to the correct edge. + // Without calling the super method, the thumb might stuck in the middle of the switch. + super.setChecked(isChecked()); } } From 2aca234dee6a4c1e710b93dce341528279797c34 Mon Sep 17 00:00:00 2001 From: Petter Hesselberg Date: Thu, 30 May 2019 11:05:56 -0700 Subject: [PATCH 0126/1084] Don't reference null android.ndkDirectory in build.gradle (#25088) Summary: If you (try to) build React Native for Android without having the NDK properly installed and referenced, you get the following error: >A problem occurred evaluating project ':ReactAndroid'. \> Cannot get property 'absolutePath' on null object This is not an overly helpful diagnostic. This PR results in this message instead: >ndk-build binary cannot be found, check if you've set $ANDROID_NDK environment variable correctly or if ndk.dir is setup in local.properties Fixes #25087 ## Changelog [Android] [Fixed] - Show proper error message instead of throwing a NullReferenceException if Gradle cannot find the NDK Pull Request resolved: https://github.com/facebook/react-native/pull/25088 Differential Revision: D15559271 Pulled By: cpojer fbshipit-source-id: 35c9a9321af4e4a34bf519144ada48884b48352d --- ReactAndroid/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactAndroid/build.gradle b/ReactAndroid/build.gradle index 8ac94f45161c29..6e44769892cbbc 100644 --- a/ReactAndroid/build.gradle +++ b/ReactAndroid/build.gradle @@ -193,7 +193,7 @@ def findNdkBuildFullPath() { def ndkDir = android.hasProperty("plugin") ? android.plugin.ndkFolder : plugins.getPlugin("com.android.library").hasProperty("sdkHandler") ? plugins.getPlugin("com.android.library").sdkHandler.getNdkFolder() : - android.ndkDirectory.absolutePath + android.ndkDirectory ? android.ndkDirectory.absolutePath : null if (ndkDir) { return new File(ndkDir, getNdkBuildName()).getAbsolutePath() } From 49f7e31ea36d35eb9197a130c3163cc5c49cce3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Thu, 30 May 2019 12:28:44 -0700 Subject: [PATCH 0127/1084] - Upgrade CLI to latest alpha (#25094) Summary: Updates the CLI version to the latest alpha to fix some issues around init and autolinking. Please port this PR back to `0.60-stable` branch as it fixes an issue with `npx react-native init`. cc grabbou hramos ## Changelog [General] [Fix] - Upgrade CLI to latest alpha Pull Request resolved: https://github.com/facebook/react-native/pull/25094 Differential Revision: D15558082 Pulled By: cpojer fbshipit-source-id: 60be64fbed996b6667eddc08346b07475dbb5089 --- package.json | 6 +++--- yarn.lock | 59 ++++++++++++++++++++++++++++++---------------------- 2 files changed, 37 insertions(+), 28 deletions(-) diff --git a/package.json b/package.json index d9bbd3257e2a31..fb864871321e10 100644 --- a/package.json +++ b/package.json @@ -82,9 +82,9 @@ }, "dependencies": { "@babel/runtime": "^7.0.0", - "@react-native-community/cli": "2.0.0-alpha.20", - "@react-native-community/cli-platform-android": "2.0.0-alpha.20", - "@react-native-community/cli-platform-ios": "2.0.0-alpha.20", + "@react-native-community/cli": "2.0.0-alpha.23", + "@react-native-community/cli-platform-android": "2.0.0-alpha.23", + "@react-native-community/cli-platform-ios": "2.0.0-alpha.23", "abort-controller": "^3.0.0", "art": "^0.10.0", "base64-js": "^1.1.2", diff --git a/yarn.lock b/yarn.lock index 37f37f1218e584..702e94ae62fb01 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1090,44 +1090,44 @@ "@types/istanbul-lib-coverage" "^2.0.0" "@types/yargs" "^12.0.9" -"@react-native-community/cli-platform-android@2.0.0-alpha.20", "@react-native-community/cli-platform-android@^2.0.0-alpha.20": - version "2.0.0-alpha.20" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-android/-/cli-platform-android-2.0.0-alpha.20.tgz#a3b5aceae38bd3c930f0801b721d44551fe98dc2" - integrity sha512-Z1eWiK4/oZlKvZTPYnORW6uAZ4rgBFMvswldwdy6r9CnjLTZsgw3aGN6r5TUNSCwbZy4p2l5J1pTELl2Ors24g== +"@react-native-community/cli-platform-android@2.0.0-alpha.23", "@react-native-community/cli-platform-android@^2.0.0-alpha.23": + version "2.0.0-alpha.23" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-android/-/cli-platform-android-2.0.0-alpha.23.tgz#f4941cca17eedef694bf420027b816ecd2e1f1c3" + integrity sha512-V57NWTyi20VQA2EPL1xmiibIQD0bUVe0ecVQxSb903f4M3ml0x4TEqWOToE2wgda/c4Z3pEKJuRCzyZHfuEYPA== dependencies: - "@react-native-community/cli-tools" "^2.0.0-alpha.20" + "@react-native-community/cli-tools" "^2.0.0-alpha.23" logkitty "^0.4.0" - node-fetch "^2.2.0" slash "^2.0.0" xmldoc "^0.4.0" -"@react-native-community/cli-platform-ios@2.0.0-alpha.20", "@react-native-community/cli-platform-ios@^2.0.0-alpha.20": - version "2.0.0-alpha.20" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-ios/-/cli-platform-ios-2.0.0-alpha.20.tgz#66eda705b0522b44818806910bbf2b7d47d41b56" - integrity sha512-ZDvx2YU/1cFp5/ADbPUwnlvs5D0RIeEZK4Ddskd2Sx7KIq5jLnQbXW+JDOqie5wQgQQ+eCmebCHnCFBWIGXdMQ== +"@react-native-community/cli-platform-ios@2.0.0-alpha.23", "@react-native-community/cli-platform-ios@^2.0.0-alpha.23": + version "2.0.0-alpha.23" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-ios/-/cli-platform-ios-2.0.0-alpha.23.tgz#3ef22cc5d5ce32b85f9f9604056ca3cea652a59a" + integrity sha512-jAffpJNw9zrlI5rwM/BfaTNtKjrx+Rvuei1YqfjLaQKUiXgrbJYbIu9+6Lc+sAn1qFGwL2+CShpywwbvN2ehGQ== dependencies: - "@react-native-community/cli-tools" "^2.0.0-alpha.20" + "@react-native-community/cli-tools" "^2.0.0-alpha.23" chalk "^1.1.1" xcode "^2.0.0" -"@react-native-community/cli-tools@^2.0.0-alpha.20": - version "2.0.0-alpha.20" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-tools/-/cli-tools-2.0.0-alpha.20.tgz#7762205a701ffabe6aa0b08d9202dd3d101297d7" - integrity sha512-G2VcBUuG/WmtbgHA4wTPkYqhuRhzE9EH8+4/WnCQmxSi7bfIYAzyVxgpBLCGzFv4liPmtoVuhcsapVeAMOdSlQ== +"@react-native-community/cli-tools@^2.0.0-alpha.23": + version "2.0.0-alpha.23" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-tools/-/cli-tools-2.0.0-alpha.23.tgz#001a6ef134e1488bf8ef41dd203fda67f7aed8d6" + integrity sha512-+a+IByj0EXQg6M3Q0aT1hsGSmmqWPPkrx+LeY4Gi2pnmOR+DB9A/dDEDOvwxd/OPBsXqzNmdO+iUcg3HNm/twg== dependencies: chalk "^1.1.1" lodash "^4.17.5" - mime "^1.3.4" + mime "^2.4.1" + node-fetch "^2.5.0" -"@react-native-community/cli@2.0.0-alpha.20": - version "2.0.0-alpha.20" - resolved "https://registry.yarnpkg.com/@react-native-community/cli/-/cli-2.0.0-alpha.20.tgz#611fe4ad483755ae10d3f7f915e1ed527f4a9bf8" - integrity sha512-H71a8gYhhI/7F6UzN3vrzQMtl9dmV/iDf55QeRqWEIU1i+SOpXXk5cmcL7hFY4FBUAkjn4o7GAd089RstGIOeA== +"@react-native-community/cli@2.0.0-alpha.23": + version "2.0.0-alpha.23" + resolved "https://registry.yarnpkg.com/@react-native-community/cli/-/cli-2.0.0-alpha.23.tgz#321ea633ffdf1160170e4428b5886f4d731ff373" + integrity sha512-NIIRgdqA1IA3+K1l1jcXEtS0qL0aos75GXVwGBOmEkC4TfNoOpVQZl2Ffy+/j+IPGpzl2xecOMMmIvlzQRGDtQ== dependencies: "@hapi/joi" "^15.0.3" - "@react-native-community/cli-platform-android" "^2.0.0-alpha.20" - "@react-native-community/cli-platform-ios" "^2.0.0-alpha.20" - "@react-native-community/cli-tools" "^2.0.0-alpha.20" + "@react-native-community/cli-platform-android" "^2.0.0-alpha.23" + "@react-native-community/cli-platform-ios" "^2.0.0-alpha.23" + "@react-native-community/cli-tools" "^2.0.0-alpha.23" chalk "^1.1.1" command-exists "^1.2.8" commander "^2.19.0" @@ -1150,7 +1150,6 @@ minimist "^1.2.0" mkdirp "^0.5.1" morgan "^1.9.0" - node-fetch "^2.2.0" node-notifier "^5.2.1" open "^6.2.0" ora "^3.4.0" @@ -5184,11 +5183,16 @@ mime-types@^2.1.12, mime-types@~2.1.18, mime-types@~2.1.19: dependencies: mime-db "~1.36.0" -mime@1.4.1, mime@^1.3.4: +mime@1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ== +mime@^2.4.1: + version "2.4.3" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.3.tgz#229687331e86f68924e6cb59e1cdd937f18275fe" + integrity sha512-QgrPRJfE+riq5TPZMcHZOtm8c6K/yYrMbKIoRfapfiGLxS8OTeIfRhUGW5LU7MlRa52KOAGCfUNruqLrIBvWZw== + mimic-fn@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" @@ -5369,6 +5373,11 @@ node-fetch@^2.2.0: resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.2.0.tgz#4ee79bde909262f9775f731e3656d0db55ced5b5" integrity sha512-OayFWziIxiHY8bCUyLX6sTpDH8Jsbp4FfYd1j1f7vZyfgkcOnAyM4oQR16f8a0s7Gl/viMGRey8eScYk4V4EZA== +node-fetch@^2.5.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" + integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== + node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" From 00c0fe7d5b1048c987fb3d684a855f78115fdf00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Norte?= Date: Thu, 30 May 2019 14:19:41 -0700 Subject: [PATCH 0128/1084] Add method to get a segment path without injecting it in the VM Reviewed By: cpojer Differential Revision: D15495065 fbshipit-source-id: 6537100d8b6dbab68603b7333705d7082c88e3f0 --- .../SegmentFetcher/NativeSegmentFetcher.js | 5 ++ Libraries/Core/setUpSegmentFetcher.js | 47 +++++++++++++++++-- 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/Libraries/Core/SegmentFetcher/NativeSegmentFetcher.js b/Libraries/Core/SegmentFetcher/NativeSegmentFetcher.js index 38319e03456d68..765b8ef0e07ef3 100644 --- a/Libraries/Core/SegmentFetcher/NativeSegmentFetcher.js +++ b/Libraries/Core/SegmentFetcher/NativeSegmentFetcher.js @@ -18,6 +18,11 @@ export interface Spec extends TurboModule { options: Object, // flowlint-line unclear-type: off callback: (error: ?Object) => void, // flowlint-line unclear-type: off ) => void; + +getSegment?: ( + segmentId: number, + options: Object, // flowlint-line unclear-type: off + callback: (error: ?Object, path: ?string) => void, // flowlint-line unclear-type: off + ) => void; } export default TurboModuleRegistry.getEnforcing('SegmentFetcher'); diff --git a/Libraries/Core/setUpSegmentFetcher.js b/Libraries/Core/setUpSegmentFetcher.js index dd182a69c91bb7..3d811535ce38ee 100644 --- a/Libraries/Core/setUpSegmentFetcher.js +++ b/Libraries/Core/setUpSegmentFetcher.js @@ -9,13 +9,20 @@ */ 'use strict'; +export type FetchSegmentFunction = typeof __fetchSegment; +export type GetSegmentFunction = typeof __getSegment; + /** * Set up SegmentFetcher. * You can use this module directly, or just require InitializeCore. */ -global.__fetchSegment = function( + +function __fetchSegment( segmentId: number, - options: {|+otaBuildNumber: ?string|}, + options: {| + +otaBuildNumber: ?string, + +requestedModuleName?: ?string, + |}, callback: (?Error) => void, ) { const SegmentFetcher = require('./SegmentFetcher/NativeSegmentFetcher') @@ -33,4 +40,38 @@ global.__fetchSegment = function( callback(null); }, ); -}; +} + +global.__fetchSegment = __fetchSegment; + +function __getSegment( + segmentId: number, + options: {| + +otaBuildNumber: ?string, + +requestedModuleName?: ?string, + |}, + callback: (?Error, ?string) => void, +) { + const SegmentFetcher = require('./SegmentFetcher/NativeSegmentFetcher') + .default; + + if (!SegmentFetcher.getSegment) { + throw new Error('SegmentFetcher.getSegment must be defined'); + } + + SegmentFetcher.getSegment( + segmentId, + options, + (errorObject: ?{message: string, code: string}, path: ?string) => { + if (errorObject) { + const error = new Error(errorObject.message); + (error: any).code = errorObject.code; // flowlint-line unclear-type: off + callback(error); + } + + callback(null, path); + }, + ); +} + +global.__getSegment = __getSegment; From 5705ea1752b8f2fd3941b457a30a95ac9069aab3 Mon Sep 17 00:00:00 2001 From: Jean Regisser Date: Thu, 30 May 2019 14:23:39 -0700 Subject: [PATCH 0129/1084] Add spec for WebSocketModule (#24893) Summary: Part of #24875 ## Changelog [General] [Added] - Add TurboModule spec for WebSocketModule Pull Request resolved: https://github.com/facebook/react-native/pull/24893 Reviewed By: RSNara Differential Revision: D15551329 Pulled By: fkgozali fbshipit-source-id: 59a921c50cc162528b2181fdd4cb1e41e3f1f6eb --- Libraries/WebSocket/NativeWebSocketModule.js | 33 ++++++++++++++++++ Libraries/WebSocket/WebSocket.js | 15 ++++----- Libraries/WebSocket/WebSocketInterceptor.js | 35 +++++++++++--------- 3 files changed, 60 insertions(+), 23 deletions(-) create mode 100644 Libraries/WebSocket/NativeWebSocketModule.js diff --git a/Libraries/WebSocket/NativeWebSocketModule.js b/Libraries/WebSocket/NativeWebSocketModule.js new file mode 100644 index 00000000000000..0b595b51b02861 --- /dev/null +++ b/Libraries/WebSocket/NativeWebSocketModule.js @@ -0,0 +1,33 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +'use strict'; + +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +connect: ( + url: string, + protocols: ?Array, + options: ?{headers?: {origin?: string}}, + socketID: number, + ) => void; + +send: (message: string, socketID: number) => void; + +sendBinary: (base64String: string, socketID: number) => void; + +ping: (socketID: number) => void; + +close: (code: number, reason: string, socketID: number) => void; + + // RCTEventEmitter + +addListener: (eventName: string) => void; + +removeListeners: (count: number) => void; +} + +export default TurboModuleRegistry.getEnforcing('WebSocketModule'); diff --git a/Libraries/WebSocket/WebSocket.js b/Libraries/WebSocket/WebSocket.js index 472fd833e63096..47d56c7eecd7d7 100644 --- a/Libraries/WebSocket/WebSocket.js +++ b/Libraries/WebSocket/WebSocket.js @@ -14,7 +14,6 @@ const Blob = require('../Blob/Blob'); const EventTarget = require('event-target-shim'); const NativeEventEmitter = require('../EventEmitter/NativeEventEmitter'); const BlobManager = require('../Blob/BlobManager'); -const NativeModules = require('../BatchedBridge/NativeModules'); const Platform = require('../Utilities/Platform'); const WebSocketEvent = require('./WebSocketEvent'); @@ -22,7 +21,7 @@ const base64 = require('base64-js'); const binaryToBase64 = require('../Utilities/binaryToBase64'); const invariant = require('invariant'); -const {WebSocketModule} = NativeModules; +import NativeWebSocketModule from './NativeWebSocketModule'; import type EventSubscription from '../vendor/emitter/EventSubscription'; @@ -128,10 +127,10 @@ class WebSocket extends EventTarget(...WEBSOCKET_EVENTS) { protocols = null; } - this._eventEmitter = new NativeEventEmitter(WebSocketModule); + this._eventEmitter = new NativeEventEmitter(NativeWebSocketModule); this._socketId = nextWebSocketId++; this._registerEvents(); - WebSocketModule.connect(url, protocols, {headers}, this._socketId); + NativeWebSocketModule.connect(url, protocols, {headers}, this._socketId); } get binaryType(): ?BinaryType { @@ -180,12 +179,12 @@ class WebSocket extends EventTarget(...WEBSOCKET_EVENTS) { } if (typeof data === 'string') { - WebSocketModule.send(data, this._socketId); + NativeWebSocketModule.send(data, this._socketId); return; } if (data instanceof ArrayBuffer || ArrayBuffer.isView(data)) { - WebSocketModule.sendBinary(binaryToBase64(data), this._socketId); + NativeWebSocketModule.sendBinary(binaryToBase64(data), this._socketId); return; } @@ -197,14 +196,14 @@ class WebSocket extends EventTarget(...WEBSOCKET_EVENTS) { throw new Error('INVALID_STATE_ERR'); } - WebSocketModule.ping(this._socketId); + NativeWebSocketModule.ping(this._socketId); } _close(code?: number, reason?: string): void { // See https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent const statusCode = typeof code === 'number' ? code : CLOSE_NORMAL; const closeReason = typeof reason === 'string' ? reason : ''; - WebSocketModule.close(statusCode, closeReason, this._socketId); + NativeWebSocketModule.close(statusCode, closeReason, this._socketId); if (BlobManager.isAvailable && this._binaryType === 'blob') { BlobManager.removeWebSocketHandler(this._socketId); diff --git a/Libraries/WebSocket/WebSocketInterceptor.js b/Libraries/WebSocket/WebSocketInterceptor.js index 58cd3da3a3b7d7..6c371c1028c485 100644 --- a/Libraries/WebSocket/WebSocketInterceptor.js +++ b/Libraries/WebSocket/WebSocketInterceptor.js @@ -9,16 +9,16 @@ 'use strict'; -const RCTWebSocketModule = require('../BatchedBridge/NativeModules') - .WebSocketModule; const NativeEventEmitter = require('../EventEmitter/NativeEventEmitter'); +import NativeWebSocketModule from './NativeWebSocketModule'; + const base64 = require('base64-js'); -const originalRCTWebSocketConnect = RCTWebSocketModule.connect; -const originalRCTWebSocketSend = RCTWebSocketModule.send; -const originalRCTWebSocketSendBinary = RCTWebSocketModule.sendBinary; -const originalRCTWebSocketClose = RCTWebSocketModule.close; +const originalRCTWebSocketConnect = NativeWebSocketModule.connect; +const originalRCTWebSocketSend = NativeWebSocketModule.send; +const originalRCTWebSocketSendBinary = NativeWebSocketModule.sendBinary; +const originalRCTWebSocketClose = NativeWebSocketModule.close; let eventEmitter: NativeEventEmitter; let subscriptions: Array; @@ -135,13 +135,18 @@ const WebSocketInterceptor = { if (isInterceptorEnabled) { return; } - eventEmitter = new NativeEventEmitter(RCTWebSocketModule); + eventEmitter = new NativeEventEmitter(NativeWebSocketModule); WebSocketInterceptor._registerEvents(); // Override `connect` method for all RCTWebSocketModule requests // to intercept the request url, protocols, options and socketId, // then pass them through the `connectCallback`. - RCTWebSocketModule.connect = function(url, protocols, options, socketId) { + NativeWebSocketModule.connect = function( + url, + protocols, + options, + socketId, + ) { if (connectCallback) { connectCallback(url, protocols, options, socketId); } @@ -150,7 +155,7 @@ const WebSocketInterceptor = { // Override `send` method for all RCTWebSocketModule requests to intercept // the data sent, then pass them through the `sendCallback`. - RCTWebSocketModule.send = function(data, socketId) { + NativeWebSocketModule.send = function(data, socketId) { if (sendCallback) { sendCallback(data, socketId); } @@ -159,7 +164,7 @@ const WebSocketInterceptor = { // Override `sendBinary` method for all RCTWebSocketModule requests to // intercept the data sent, then pass them through the `sendCallback`. - RCTWebSocketModule.sendBinary = function(data, socketId) { + NativeWebSocketModule.sendBinary = function(data, socketId) { if (sendCallback) { sendCallback(WebSocketInterceptor._arrayBufferToString(data), socketId); } @@ -168,7 +173,7 @@ const WebSocketInterceptor = { // Override `close` method for all RCTWebSocketModule requests to intercept // the close information, then pass them through the `closeCallback`. - RCTWebSocketModule.close = function() { + NativeWebSocketModule.close = function() { if (closeCallback) { if (arguments.length === 3) { closeCallback(arguments[0], arguments[1], arguments[2]); @@ -203,10 +208,10 @@ const WebSocketInterceptor = { return; } isInterceptorEnabled = false; - RCTWebSocketModule.send = originalRCTWebSocketSend; - RCTWebSocketModule.sendBinary = originalRCTWebSocketSendBinary; - RCTWebSocketModule.close = originalRCTWebSocketClose; - RCTWebSocketModule.connect = originalRCTWebSocketConnect; + NativeWebSocketModule.send = originalRCTWebSocketSend; + NativeWebSocketModule.sendBinary = originalRCTWebSocketSendBinary; + NativeWebSocketModule.close = originalRCTWebSocketClose; + NativeWebSocketModule.connect = originalRCTWebSocketConnect; connectCallback = null; closeCallback = null; From 7fd08e146184432731ec5d5ba210e352690dc569 Mon Sep 17 00:00:00 2001 From: Tom Sanderson Date: Thu, 30 May 2019 14:23:39 -0700 Subject: [PATCH 0130/1084] add spec for PlatformConstants (#24928) Summary: part of #24875. ## Changelog [General] [Added] - add TM spec for PlatformConstants Pull Request resolved: https://github.com/facebook/react-native/pull/24928 Reviewed By: RSNara Differential Revision: D15551340 Pulled By: fkgozali fbshipit-source-id: 9de15ff4cfe717f963332868bd873d5147a37506 --- .../Animated/src/__tests__/Animated-test.js | 5 +++ .../src/__tests__/AnimatedNative-test.js | 5 +++ Libraries/Core/ReactNativeVersionCheck.js | 11 +++--- .../__tests__/ReactNativeVersionCheck-test.js | 11 ++++-- .../Network/__tests__/XMLHttpRequest-test.js | 5 +++ .../NativePlatformConstantsAndroid.js | 36 +++++++++++++++++++ .../Utilities/NativePlatformConstantsIOS.js | 32 +++++++++++++++++ Libraries/Utilities/Platform.android.js | 14 ++++---- Libraries/Utilities/Platform.ios.js | 17 +++++---- .../js/examples/Touchable/TouchableExample.js | 5 +-- jest/setup.js | 5 +++ 11 files changed, 116 insertions(+), 30 deletions(-) create mode 100644 Libraries/Utilities/NativePlatformConstantsAndroid.js create mode 100644 Libraries/Utilities/NativePlatformConstantsIOS.js diff --git a/Libraries/Animated/src/__tests__/Animated-test.js b/Libraries/Animated/src/__tests__/Animated-test.js index fbfdc5dd73f3a1..4e74cb6200e3c0 100644 --- a/Libraries/Animated/src/__tests__/Animated-test.js +++ b/Libraries/Animated/src/__tests__/Animated-test.js @@ -12,6 +12,11 @@ jest.mock('../../../BatchedBridge/NativeModules', () => ({ NativeAnimatedModule: {}, + PlatformConstants: { + getConstants() { + return {}; + }, + }, })); let Animated = require('../Animated'); diff --git a/Libraries/Animated/src/__tests__/AnimatedNative-test.js b/Libraries/Animated/src/__tests__/AnimatedNative-test.js index 38e201928c2e5e..09b087ce5d5be0 100644 --- a/Libraries/Animated/src/__tests__/AnimatedNative-test.js +++ b/Libraries/Animated/src/__tests__/AnimatedNative-test.js @@ -24,6 +24,11 @@ jest .setMock('react', {Component: class {}}) .mock('../../../BatchedBridge/NativeModules', () => ({ NativeAnimatedModule: {}, + PlatformConstants: { + getConstants() { + return {}; + }, + }, })) .mock('../NativeAnimatedModule') .mock('../../../EventEmitter/NativeEventEmitter') diff --git a/Libraries/Core/ReactNativeVersionCheck.js b/Libraries/Core/ReactNativeVersionCheck.js index 30264918c79221..a2eb4d050fc90c 100644 --- a/Libraries/Core/ReactNativeVersionCheck.js +++ b/Libraries/Core/ReactNativeVersionCheck.js @@ -9,7 +9,7 @@ */ 'use strict'; -const {PlatformConstants} = require('../BatchedBridge/NativeModules'); +import Platform from '../Utilities/Platform'; const ReactNativeVersion = require('./ReactNativeVersion'); /** @@ -22,11 +22,7 @@ const ReactNativeVersion = require('./ReactNativeVersion'); * and rely on its existence as a separate module. */ exports.checkVersions = function checkVersions(): void { - if (!PlatformConstants) { - return; - } - - const nativeVersion = PlatformConstants.reactNativeVersion; + const nativeVersion = Platform.constants.reactNativeVersion; if ( ReactNativeVersion.version.major !== nativeVersion.major || ReactNativeVersion.version.minor !== nativeVersion.minor @@ -46,6 +42,7 @@ exports.checkVersions = function checkVersions(): void { function _formatVersion(version): string { return ( `${version.major}.${version.minor}.${version.patch}` + - (version.prerelease !== null ? `-${version.prerelease}` : '') + // eslint-disable-next-line eqeqeq + (version.prerelease != undefined ? `-${version.prerelease}` : '') ); } diff --git a/Libraries/Core/__tests__/ReactNativeVersionCheck-test.js b/Libraries/Core/__tests__/ReactNativeVersionCheck-test.js index 471a6f00308c3a..70c8abd88e2f24 100644 --- a/Libraries/Core/__tests__/ReactNativeVersionCheck-test.js +++ b/Libraries/Core/__tests__/ReactNativeVersionCheck-test.js @@ -127,9 +127,14 @@ function _mockNativeVersion( patch = 0, prerelease = null, ) { - jest.doMock('../../BatchedBridge/NativeModules', () => ({ - PlatformConstants: { + jest.doMock('../../Utilities/NativePlatformConstantsAndroid', () => ({ + getConstants: () => ({ reactNativeVersion: {major, minor, patch, prerelease}, - }, + }), + })); + jest.doMock('../../Utilities/NativePlatformConstantsIOS', () => ({ + getConstants: () => ({ + reactNativeVersion: {major, minor, patch, prerelease}, + }), })); } diff --git a/Libraries/Network/__tests__/XMLHttpRequest-test.js b/Libraries/Network/__tests__/XMLHttpRequest-test.js index e69e91b55d6b1c..0520348f380646 100644 --- a/Libraries/Network/__tests__/XMLHttpRequest-test.js +++ b/Libraries/Network/__tests__/XMLHttpRequest-test.js @@ -34,6 +34,11 @@ jest }, abortRequest: function() {}, }, + PlatformConstants: { + getConstants() { + return {}; + }, + }, }); const XMLHttpRequest = require('../XMLHttpRequest'); diff --git a/Libraries/Utilities/NativePlatformConstantsAndroid.js b/Libraries/Utilities/NativePlatformConstantsAndroid.js new file mode 100644 index 00000000000000..ba952618b95600 --- /dev/null +++ b/Libraries/Utilities/NativePlatformConstantsAndroid.js @@ -0,0 +1,36 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +'use strict'; + +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +getConstants: () => {| + isTesting: boolean, + reactNativeVersion: {| + major: number, + minor: number, + patch: number, + prerelease: ?number, + |}, + Version: number, + Release: string, + Serial: string, + Fingerprint: string, + Model: string, + ServerHost: string, + uiMode: string, + |}; + +getAndroidID: () => string; +} + +export default TurboModuleRegistry.getEnforcing('PlatformConstants'); diff --git a/Libraries/Utilities/NativePlatformConstantsIOS.js b/Libraries/Utilities/NativePlatformConstantsIOS.js new file mode 100644 index 00000000000000..b350a6ee477b67 --- /dev/null +++ b/Libraries/Utilities/NativePlatformConstantsIOS.js @@ -0,0 +1,32 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +'use strict'; + +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +getConstants: () => {| + isTesting: boolean, + reactNativeVersion: {| + major: number, + minor: number, + patch: number, + prerelease: ?number, + |}, + forceTouchAvailable: boolean, + osVersion: string, + systemName: string, + interfaceIdiom: string, + |}; +} + +export default TurboModuleRegistry.getEnforcing('PlatformConstants'); diff --git a/Libraries/Utilities/Platform.android.js b/Libraries/Utilities/Platform.android.js index 40b7a83034efbc..d7e672b33b863b 100644 --- a/Libraries/Utilities/Platform.android.js +++ b/Libraries/Utilities/Platform.android.js @@ -10,7 +10,7 @@ 'use strict'; -const NativeModules = require('../BatchedBridge/NativeModules'); +import NativePlatformConstantsAndroid from './NativePlatformConstantsAndroid'; export type PlatformSelectSpec = { android?: A, @@ -20,19 +20,19 @@ export type PlatformSelectSpec = { const Platform = { OS: 'android', get Version() { - const constants = NativeModules.PlatformConstants; - return constants && constants.Version; + return NativePlatformConstantsAndroid.getConstants().Version; + }, + get constants() { + return NativePlatformConstantsAndroid.getConstants(); }, get isTesting(): boolean { if (__DEV__) { - const constants = NativeModules.PlatformConstants; - return constants && constants.isTesting; + return NativePlatformConstantsAndroid.getConstants().isTesting; } return false; }, get isTV(): boolean { - const constants = NativeModules.PlatformConstants; - return constants && constants.uiMode === 'tv'; + return NativePlatformConstantsAndroid.getConstants().uiMode === 'tv'; }, select: (spec: PlatformSelectSpec): A | D => 'android' in spec ? spec.android : spec.default, diff --git a/Libraries/Utilities/Platform.ios.js b/Libraries/Utilities/Platform.ios.js index 2ac52e3005a061..f558755c6f0b02 100644 --- a/Libraries/Utilities/Platform.ios.js +++ b/Libraries/Utilities/Platform.ios.js @@ -10,7 +10,7 @@ 'use strict'; -const NativeModules = require('../BatchedBridge/NativeModules'); +import NativePlatformConstantsIOS from './NativePlatformConstantsIOS'; export type PlatformSelectSpec = { default?: D, @@ -20,12 +20,13 @@ export type PlatformSelectSpec = { const Platform = { OS: 'ios', get Version() { - const constants = NativeModules.PlatformConstants; - return constants && constants.osVersion; + return NativePlatformConstantsIOS.getConstants().osVersion; + }, + get constants() { + return NativePlatformConstantsIOS.getConstants(); }, get isPad() { - const constants = NativeModules.PlatformConstants; - return constants ? constants.interfaceIdiom === 'pad' : false; + return NativePlatformConstantsIOS.getConstants().interfaceIdiom === 'pad'; }, /** * Deprecated, use `isTV` instead. @@ -34,13 +35,11 @@ const Platform = { return Platform.isTV; }, get isTV() { - const constants = NativeModules.PlatformConstants; - return constants ? constants.interfaceIdiom === 'tv' : false; + return NativePlatformConstantsIOS.getConstants().interfaceIdiom === 'tv'; }, get isTesting(): boolean { if (__DEV__) { - const constants = NativeModules.PlatformConstants; - return constants && constants.isTesting; + return NativePlatformConstantsIOS.getConstants().isTesting; } return false; }, diff --git a/RNTester/js/examples/Touchable/TouchableExample.js b/RNTester/js/examples/Touchable/TouchableExample.js index 7e4e348cb3a2b8..f77b7db9a548d0 100644 --- a/RNTester/js/examples/Touchable/TouchableExample.js +++ b/RNTester/js/examples/Touchable/TouchableExample.js @@ -18,7 +18,6 @@ const { Text, TouchableHighlight, TouchableOpacity, - NativeModules, Platform, TouchableNativeFeedback, TouchableWithoutFeedback, @@ -26,9 +25,7 @@ const { } = require('react-native'); const forceTouchAvailable = - (NativeModules.PlatformConstants && - NativeModules.PlatformConstants.forceTouchAvailable) || - false; + (Platform.OS === 'ios' && Platform.constants.forceTouchAvailable) || false; class TouchableHighlightBox extends React.Component<{}, $FlowFixMeState> { state = { diff --git a/jest/setup.js b/jest/setup.js index e03244ed5d982b..38cef7befbf12f 100644 --- a/jest/setup.js +++ b/jest/setup.js @@ -236,6 +236,11 @@ const mockNativeModules = { addListener: jest.fn(), removeListeners: jest.fn(), }, + PlatformConstants: { + getConstants() { + return {}; + }, + }, PushNotificationManager: { presentLocalNotification: jest.fn(), scheduleLocalNotification: jest.fn(), From 171cc0edb703e8e502d423b3eed9eb914c74e021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= Date: Thu, 30 May 2019 15:07:45 -0700 Subject: [PATCH 0131/1084] Migrate to Circle CI 2.1 (#25036) Summary: Migrate the Circle CI configuration to the 2.1 schema and take advantage of new config reuse features. I've enabled pipelines in the facebook/react-native Circle CI project, a requirement for Circle CI 2.1 features. ### Overview * Use executors to provide a common set of execution environments. * Use commands to provide reusable steps (running yarn with cache, installing Android dependencies, ...) * Use parametrized commands/jobs to reuse job definitions for `test_js` and `test_js_lts` where the only difference is the version of node provided by the environment. * Reduce total execution time by [storing the git repo in a cache as opposed to using workspaces](https://circleci.com/blog/persisting-data-in-workflows-when-to-use-caching-artifacts-and-workspaces/) * Fix various flaky end-to-end test failures related to CocoaPods and the CLI. * Move `analyze` job to `analysis` workflow and rename to `analyze_pr` * Rename `test_javascript` as `test_js`. * Split up end-to-end test job into `test_ios_e2e` and `test_js_e2e`. ## Changelog [Internal] [Changed] - Migrate to Circle CI 2.1 and fix e2e tests Pull Request resolved: https://github.com/facebook/react-native/pull/25036 Differential Revision: D15565515 Pulled By: hramos fbshipit-source-id: cfba2154a9fdc96400cbf778bd5d13e9411ee3f8 --- .circleci/config.yml | 698 ++++++++++++++++++------------------ scripts/run-ci-e2e-tests.js | 49 ++- 2 files changed, 374 insertions(+), 373 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index d38432f3e37c65..64630eaf6c5753 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,143 +1,4 @@ -# ------------------------- -# ALIASES -# ------------------------- -aliases: - # ------------------------- - # ALIASES: Caches - # ------------------------- - - &restore-yarn-cache - keys: - - v1-yarn-cache-{{ arch }}-{{ checksum "package.json" }}{{ checksum "bots/package.json" }} - - v1-yarn-cache-{{ arch }} - - - &save-yarn-cache - paths: - - ~/.cache/yarn - key: v1-yarn-cache-{{ arch }}-{{ checksum "package.json" }}{{ checksum "bots/package.json" }} - - - &restore-brew-cache - keys: - - v1-brew - - - &save-brew-cache - paths: - - /usr/local/Homebrew - - ~/Library/Caches/Homebrew - key: v1-brew - - # Android - - &restore-buck-downloads-cache - keys: - - v3-buck-v2019.01.10.01-{{ checksum "scripts/circleci/buck_fetch.sh" }}} - - v3-buck-v2019.01.10.01- - - &save-buck-downloads-cache - paths: - - ~/buck - - ~/okbuck - key: v3-buck-v2019.01.10.01-{{ checksum "scripts/circleci/buck_fetch.sh" }} - - - &restore-gradle-downloads-cache - keys: - - v1-gradle-{{ checksum "ReactAndroid/build.gradle" }}-{{ checksum "scripts/circleci/gradle_download_deps.sh" }} - - v1-gradle- - - - &save-gradle-downloads-cache - paths: - - ~/.gradle - - ReactAndroid/build/downloads - - ReactAndroid/build/third-party-ndk - key: v1-gradle-{{ checksum "ReactAndroid/build.gradle" }}-{{ checksum "scripts/circleci/gradle_download_deps.sh" }} - - # ------------------------- - # ALIASES: Shared Commands - # ------------------------- - - &yarn - name: Run Yarn - command: | - # Skip yarn install on metro bump commits as the package is not yet - # available on npm - if [[ $(echo "$GIT_COMMIT_DESC" | grep -c "Bump metro@") -eq 0 ]]; then - yarn install --non-interactive --cache-folder ~/.cache/yarn - fi - - - &setup-artifacts - name: Initial Setup - command: | - mkdir -p ~/react-native/reports/buck/ - mkdir -p ~/react-native/reports/build/ - mkdir -p ~/react-native/reports/junit/ - mkdir -p ~/react-native/reports/outputs/ - - # Android - - &download-dependencies-buck - name: Download Dependencies Using Buck - command: ./scripts/circleci/buck_fetch.sh - - - &download-dependencies-gradle - name: Download Dependencies Using Gradle - command: ./scripts/circleci/gradle_download_deps.sh - - # JavaScript - - &run-js-tests - name: JavaScript Test Suite - command: yarn test-ci - - # ------------------------- - # ALIASES: Disabled Tests - # ------------------------- - - &run-podspec-tests - name: Test CocoaPods - command: ./scripts/process-podspecs.sh - - &run-e2e-tests - name: End-to-End Test Suite - command: ./scripts/run-ci-e2e-tests.js --android --ios --js --retries 3; - - &run-android-e2e-tests - name: Android End-to-End Test Suite - command: node ./scripts/run-ci-e2e-tests.js --android --retries 3; - - - # ------------------------- - # ALIASES: Branch Filters - # ------------------------- - - &filter-only-master - branches: - only: master - - - &filter-only-master-stable - branches: - only: - - /.*-stable/ - - master - - - &filter-only-stable - branches: - only: - - /.*-stable/ - - - &filter-ignore-gh-pages - branches: - ignore: gh-pages - - - &filter-only-version-tags - # Both of the following conditions must be included! - # Ignore any commit on any branch by default. - branches: - ignore: /.*/ - # Only act on version tags. - tags: - only: /v[0-9]+(\.[0-9]+)*(\-rc(\.[0-9]+)?)?/ - - - &filter-only-forked-pull-requests - branches: - only: /^pull\/.*$/ - - # ------------------------- - # ALIASES: Workflows - # ------------------------- - - &run-after-checkout - filters: *filter-ignore-gh-pages - requires: - - checkout_code +version: 2.1 # ------------------------- # DEFAULTS @@ -147,50 +8,175 @@ defaults: &defaults environment: - GIT_COMMIT_DESC: git log --format=oneline -n 1 $CIRCLE_SHA1 -# JavaScript -js_defaults: &js_defaults - <<: *defaults - docker: - - image: node:8 - -# Android -android_defaults: &android_defaults - <<: *defaults - docker: - - image: reactnativecommunity/react-native-android:2019-5-7 - resource_class: "large" - environment: - - TERM: "dumb" - - ADB_INSTALL_TIMEOUT: 10 - - _JAVA_OPTIONS: "-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap" - - GRADLE_OPTS: '-Dorg.gradle.daemon=false -Dorg.gradle.jvmargs="-XX:+HeapDumpOnOutOfMemoryError"' - - BUILD_THREADS: 2 - -# iOS -macos_defaults: &macos_defaults - <<: *defaults - macos: - xcode: "10.2.0" +# ------------------------- +# EXECUTORS +# ------------------------- +executors: + node8: + <<: *defaults + docker: + - image: circleci/node:8 + nodelts: + <<: *defaults + docker: + - image: circleci/node:lts + reactnativeandroid: + <<: *defaults + docker: + - image: reactnativecommunity/react-native-android:2019-5-29 + resource_class: "large" + environment: + - TERM: "dumb" + - ADB_INSTALL_TIMEOUT: 10 + - _JAVA_OPTIONS: "-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap" + - GRADLE_OPTS: '-Dorg.gradle.daemon=false -Dorg.gradle.jvmargs="-XX:+HeapDumpOnOutOfMemoryError"' + - BUILD_THREADS: 2 + reactnativeios: + <<: *defaults + macos: + xcode: "10.2.0" + +# ------------------------- +# COMMANDS +# ------------------------- +commands: + restore_cache_checkout: + parameters: + checkout_type: + type: string + default: node + steps: + - restore_cache: + key: v1-repo-{{ .Environment.CIRCLE_SHA1 }}-<< parameters.checkout_type >> + + setup_artifacts: + steps: + - run: + name: Initial Setup + command: mkdir -p ~/reports/{buck,build,junit,outputs} + + run_yarn: + steps: + - restore_cache: + keys: + - v2-yarn-cache-{{ arch }}-{{ checksum "package.json" }} + - v2-yarn-cache-{{ arch }} + - run: + name: Run Yarn + command: | + # Skip yarn install on metro bump commits as the package is not yet + # available on npm + if [[ $(echo "$GIT_COMMIT_DESC" | grep -c "Bump metro@") -eq 0 ]]; then + yarn install --non-interactive --cache-folder ~/.cache/yarn + fi + - save_cache: + paths: + - ~/.cache/yarn + key: v2-yarn-cache-{{ arch }}-{{ checksum "package.json" }} + + install_buck_tooling: + steps: + - restore_cache: + keys: + - v3-buck-v2019.01.10.01-{{ checksum "scripts/circleci/buck_fetch.sh" }}} + - v3-buck-v2019.01.10.01- + - run: + name: Install BUCK + command: | + buck --version + # Install related tooling + if [[ ! -e ~/okbuck ]]; then + git clone https://github.com/uber/okbuck.git ~/okbuck --depth=1 + fi + - save_cache: + paths: + - ~/buck + - ~/okbuck + key: v3-buck-v2019.01.10.01-{{ checksum "scripts/circleci/buck_fetch.sh" }} + + brew_install: + parameters: + package: + description: Homebrew package to install + type: string + steps: + - run: HOMEBREW_NO_AUTO_UPDATE=1 brew install << parameters.package >> >/dev/null + + with_brew_cache_span: + parameters: + steps: + type: steps + steps: + - restore_cache: + keys: + - v1-brew + - steps: << parameters.steps >> + - save_cache: + paths: + - /usr/local/Homebrew + - ~/Library/Caches/Homebrew + key: v1-brew + + download_gradle_dependencies: + steps: + - restore_cache: + keys: + - v1-gradle-{{ checksum "ReactAndroid/build.gradle" }}-{{ checksum "scripts/circleci/gradle_download_deps.sh" }} + - v1-gradle- + - run: + name: Download Dependencies Using Gradle + command: ./scripts/circleci/gradle_download_deps.sh + - save_cache: + paths: + - ~/.gradle + - ReactAndroid/build/downloads + - ReactAndroid/build/third-party-ndk + key: v1-gradle-{{ checksum "ReactAndroid/build.gradle" }}-{{ checksum "scripts/circleci/gradle_download_deps.sh" }} + + download_buck_dependencies: + steps: + - run: + name: Download Dependencies Using Buck + command: ./scripts/circleci/buck_fetch.sh + + # ------------------------- + # COMMANDS: Disabled Tests + # ------------------------- + run_podspec_tests: + steps: + - run: + name: Test CocoaPods + command: ./scripts/process-podspecs.sh + run_e2e_tests: + steps: + - run: + name: Full End-to-End Test Suite + command: node ./scripts/run-ci-e2e-tests.js --android --ios --js --retries 3; + run_android_e2e_tests: + steps: + - run: + name: Android End-to-End Test Suite + command: node ./scripts/run-ci-e2e-tests.js --android --retries 3; # ------------------------- # JOBS # ------------------------- -version: 2 jobs: - # Set up a Node environment for downstream jobs - checkout_code: - <<: *js_defaults + setup: + parameters: + executor: + type: executor + default: node8 + checkout_type: + type: string + default: node + executor: << parameters.executor >> steps: - checkout - - run: *setup-artifacts - - - restore-cache: *restore-yarn-cache - - run: *yarn - - save-cache: *save-yarn-cache - - - persist_to_workspace: - root: . - paths: . + - save_cache: + key: v1-repo-{{ .Environment.CIRCLE_SHA1 }}-<< parameters.checkout_type >> + paths: + - ~/react-native # ------------------------- # JOBS: Analyze PR @@ -199,9 +185,7 @@ jobs: # Issues will be posted to the PR itself via GitHub bots. # This workflow should only fail if the bots fail to run. analyze_pr: - <<: *defaults - docker: - - image: node:lts + executor: nodelts # The public github tokens are publicly visible by design environment: - PUBLIC_PULLBOT_GITHUB_TOKEN_A: "a6edf8e8d40ce4e8b11a" @@ -210,19 +194,15 @@ jobs: - PUBLIC_ANALYSISBOT_GITHUB_TOKEN_B: "b1a98e0bbd56ff1ccba1" steps: - - checkout - - run: *setup-artifacts + - restore_cache_checkout: + checkout_type: node + - run_yarn - - restore-cache: *restore-yarn-cache - - run: *yarn - run: name: Install dependencies command: | - apt update - apt install -y shellcheck jq - cd bots - yarn install --non-interactive --cache-folder ~/.cache/yarn - - save-cache: *save-yarn-cache + sudo apt update && sudo apt install -y shellcheck jq + cd bots && yarn install --non-interactive --cache-folder ~/.cache/yarn - run: name: Run linters against modified files (analysis-bot) @@ -240,15 +220,17 @@ jobs: # ------------------------- # JOBS: Analyze Code # ------------------------- - analyze: - <<: *js_defaults + analyze_code: + executor: node8 steps: - - attach_workspace: - at: ~/react-native + - restore_cache_checkout: + checkout_type: node + - setup_artifacts + - run_yarn - run: name: Lint code - command: scripts/circleci/exec_swallow_error.sh yarn lint --format junit -o ~/react-native/reports/junit/eslint/results.xml + command: scripts/circleci/exec_swallow_error.sh yarn lint --format junit -o ~/reports/junit/eslint/results.xml when: always - run: @@ -274,56 +256,43 @@ jobs: when: always - store_test_results: - path: ~/react-native/reports/junit - - store_artifacts: - path: ~/react-native/yarn.lock + path: ~/reports/junit # ------------------------- # JOBS: Test JavaScript # ------------------------- - # Runs JavaScript tests on Node 8 - test_javascript: - <<: *js_defaults + # Runs JavaScript tests + test_js: + parameters: + executor: + type: executor + default: node8 + executor: << parameters.executor >> steps: - - attach_workspace: - at: ~/react-native - - - run: - name: JavaScript Test Suite - command: node ./scripts/run-ci-javascript-tests.js --maxWorkers 2 - - - store_test_results: - path: ~/react-native/reports/junit - - # Run JavaScript tests on Node LTS - test_node_lts: - <<: *defaults - docker: - - image: node:lts - steps: - - checkout - - run: *setup-artifacts - - - run: *yarn + - restore_cache_checkout: + checkout_type: node + - setup_artifacts + - run_yarn - run: name: JavaScript Test Suite command: node ./scripts/run-ci-javascript-tests.js --maxWorkers 2 - store_test_results: - path: ~/react-native/reports/junit - + path: ~/reports/junit # ------------------------- # JOBS: Test iOS # ------------------------- # Runs unit tests on iOS devices test_ios: - <<: *macos_defaults + executor: reactnativeios environment: - REPORTS_DIR: "./reports" steps: - - attach_workspace: - at: ~/react-native + - restore_cache_checkout: + checkout_type: ios + - setup_artifacts + - run_yarn - run: name: Print Xcode environment @@ -337,13 +306,11 @@ jobs: name: Boot iOS Simulator command: source scripts/.tests.env && xcrun simctl boot "$IOS_DEVICE" || true - - restore-cache: *restore-brew-cache - - run: - name: Install Watchman - command: | - HOMEBREW_NO_AUTO_UPDATE=1 brew install watchman >/dev/null - touch .watchmanconfig - - save-cache: *save-brew-cache + - with_brew_cache_span: + steps: + - brew_install: + package: watchman + - run: touch .watchmanconfig - run: name: Start Metro packager @@ -433,14 +400,16 @@ jobs: lsof -i tcp:5555 | awk 'NR!=1 {print $2}' | xargs kill - store_test_results: - path: ~/react-native/reports/junit + path: ~/reports/junit - # Runs end-to-end tests - test_end_to_end: - <<: *macos_defaults + # Runs iOS end-to-end tests + test_ios_e2e: + executor: reactnativeios steps: - - attach_workspace: - at: ~/react-native + - restore_cache_checkout: + checkout_type: ios + - setup_artifacts + - run_yarn - run: name: Boot iPhone Simulator @@ -453,41 +422,20 @@ jobs: source $BASH_ENV # Brew - - restore-cache: *restore-brew-cache - - run: - name: Configure Detox Environment - command: | - HOMEBREW_NO_AUTO_UPDATE=1 brew install node@8 >/dev/null - HOMEBREW_NO_AUTO_UPDATE=1 brew tap wix/brew >/dev/null - HOMEBREW_NO_AUTO_UPDATE=1 brew install applesimutils >/dev/null - touch .watchmanconfig - node -v - - save-cache: *save-brew-cache + - with_brew_cache_span: + steps: + - brew_install: + package: node@8 + - run: HOMEBREW_NO_AUTO_UPDATE=1 brew tap wix/brew >/dev/null + - brew_install: + package: applesimutils - # Yarn install - - restore-cache: *restore-yarn-cache - - run: *yarn - - save-cache: *save-yarn-cache + # Configure Watchman + - run: touch .watchmanconfig - # Xcode build - - run: - name: Build app for Detox iOS End-to-End Tests - command: yarn run build-ios-e2e - - # Test - run: name: Run Detox iOS End-to-End Tests - command: yarn run test-ios-e2e - when: always - - - run: - name: Run JavaScript End-to-End Tests - command: | - # free up port 8081 for the packager before running tests - set +eo pipefail - lsof -i tcp:8081 | awk 'NR!=1 {print $2}' | xargs kill - set -eo pipefail - node ./scripts/run-ci-e2e-tests.js --js --retries 3 + command: yarn run build-ios-e2e && yarn run test-ios-e2e when: always - run: @@ -500,15 +448,32 @@ jobs: node ./scripts/run-ci-e2e-tests.js --ios --retries 3; when: always + test_js_e2e: + executor: node8 + steps: + - restore_cache_checkout: + checkout_type: node + - setup_artifacts + - run_yarn + + - run: + name: Run JavaScript End-to-End Tests + command: node ./scripts/run-ci-e2e-tests.js --js --retries 3 + + - store_test_results: + path: ~/reports/junit + # ------------------------- # JOBS: Test Android # ------------------------- # Run Android tests test_android: - <<: *android_defaults + executor: reactnativeandroid steps: - - attach_workspace: - at: ~/react-native + - restore_cache_checkout: + checkout_type: android + - setup_artifacts + - run_yarn # Validate Android SDK installation and packages - run: @@ -527,31 +492,15 @@ jobs: # Keep configuring Android dependencies while AVD boots up # Install Buck - - restore-cache: *restore-buck-downloads-cache - - run: - name: Install BUCK - command: | - buck --version - # Install related tooling - if [[ ! -e ~/okbuck ]]; then - git clone https://github.com/uber/okbuck.git ~/okbuck --depth=1 - fi - mkdir -p ~/react-native/tooling/junit - cp -R ~/okbuck/tooling/junit/* ~/react-native/tooling/junit/. - - save-cache: *save-buck-downloads-cache + - install_buck_tooling # Validate Android test environment (including Buck) - run: name: Validate Android Test Environment command: ./scripts/validate-android-test-env.sh - # Download dependencies using Buck - - run: *download-dependencies-buck - - # Download dependencies using Gradle - - restore-cache: *restore-gradle-downloads-cache - - run: *download-dependencies-gradle - - save-cache: *save-gradle-downloads-cache + - download_buck_dependencies + - download_gradle_dependencies # Build and compile - run: @@ -577,7 +526,7 @@ jobs: # Test Suite - run: name: Run Unit Tests - command: buck test ReactAndroid/src/test/... --config build.threads=$BUILD_THREADS --xml ~/react-native/reports/buck/all-results-raw.xml + command: buck test ReactAndroid/src/test/... --config build.threads=$BUILD_THREADS --xml ~/reports/buck/all-results-raw.xml - run: name: Run Instrumentation Tests @@ -595,19 +544,19 @@ jobs: - run: name: Collect Test Results command: | - find . -type f -regex ".*/build/test-results/debug/.*xml" -exec cp {} ~/react-native/reports/build/ \; - find . -type f -regex ".*/outputs/androidTest-results/connected/.*xml" -exec cp {} ~/react-native/reports/outputs/ \; - find . -type f -regex ".*/buck-out/gen/ReactAndroid/src/test/.*/.*xml" -exec cp {} ~/react-native/reports/buck/ \; - ./tooling/junit/buck_to_junit.sh ~/react-native/reports/buck/all-results-raw.xml ~/react-native/reports/junit/all-results-junit.xml + find . -type f -regex ".*/build/test-results/debug/.*xml" -exec cp {} ~/reports/build/ \; + find . -type f -regex ".*/outputs/androidTest-results/connected/.*xml" -exec cp {} ~/reports/outputs/ \; + find . -type f -regex ".*/buck-out/gen/ReactAndroid/src/test/.*/.*xml" -exec cp {} ~/reports/buck/ \; + ~/okbuck/tooling/junit/buck_to_junit.sh ~/reports/buck/all-results-raw.xml ~/reports/junit/all-results-junit.xml when: always - store_test_results: - path: ~/react-native/reports/junit + path: ~/reports/junit # ------------------------- - # JOBS: Test Docker Build + # JOBS: Test Docker # ------------------------- - test_docker_build: + test_docker: machine: true steps: - checkout @@ -626,16 +575,17 @@ jobs: # ------------------------- # Collect JavaScript test coverage js_coverage: - <<: *js_defaults + executor: node8 environment: - CI_BRANCH: $CIRCLE_BRANCH - CI_PULL_REQUEST: $CIRCLE_PULL_REQUEST - CI_BUILD_NUMBER: $CIRCLE_BUILD_NUM - CI_BUILD_URL: $CIRCLE_BUILD_URL steps: - - checkout - - restore-cache: *restore-yarn-cache - - run: *yarn + - restore_cache_checkout: + checkout_type: node + - setup_artifacts + - run_yarn - run: name: Test coverage command: | @@ -651,73 +601,113 @@ jobs: # Publishes new version onto npm # Only works on stable branches when a properly tagged commit is pushed publish_npm_package: - <<: *android_defaults + executor: reactnativeandroid steps: - - checkout - - - restore-cache: *restore-yarn-cache - - run: *yarn - - # Fetch dependencies using Buck - - restore-cache: *restore-buck-downloads-cache - - run: *download-dependencies-buck - - # Fetch dependencies using Gradle - - restore-cache: *restore-gradle-downloads-cache - - run: *download-dependencies-gradle - - - restore-cache: *restore-yarn-cache - - run: *yarn - - - run: - name: Authenticate with npm - command: echo "//registry.npmjs.org/:_authToken=${CIRCLE_NPM_TOKEN}" > ~/.npmrc - - - run: - name: Authenticate git user - command: | - git config --global user.email "react-native-bot@users.noreply.github.com" - git config --global user.name "npm Deployment Script" - echo "machine github.com login react-native-bot password $GITHUB_TOKEN" > ~/.netrc - - # Build and publish release. Requires an Android environment. - - run: - name: Publish React Native Package - command: node ./scripts/publish-npm.js + - restore_cache_checkout: + checkout_type: android + - run_yarn + - install_buck_tooling + - download_buck_dependencies + - download_gradle_dependencies + - run: echo "//registry.npmjs.org/:_authToken=${CIRCLE_NPM_TOKEN}" > ~/.npmrc + - run: | + git config --global user.email "react-native-bot@users.noreply.github.com" + git config --global user.name "npm Deployment Script" + echo "machine github.com login react-native-bot password $GITHUB_TOKEN" > ~/.netrc + - run: node ./scripts/publish-npm.js # ------------------------- # WORK FLOWS # ------------------------- workflows: - version: 2 - tests: jobs: - - test_node_lts: - filters: *filter-ignore-gh-pages - - - checkout_code: - filters: *filter-ignore-gh-pages - - - analyze: *run-after-checkout - - test_javascript: *run-after-checkout - - test_android: *run-after-checkout - - test_ios: *run-after-checkout - - test_end_to_end: *run-after-checkout - - test_docker_build: - filters: *filter-ignore-gh-pages - + - setup: + name: setup_js + filters: + branches: + ignore: gh-pages + - setup: + name: setup_ios + checkout_type: ios + executor: reactnativeios + filters: + branches: + ignore: gh-pages + - setup: + name: setup_android + checkout_type: android + executor: reactnativeandroid + filters: + branches: + ignore: gh-pages + - test_js: + requires: + - setup_js + - test_js_e2e: + requires: + - setup_js + - test_js + - test_android: + requires: + - setup_android + - test_ios: + requires: + - setup_ios + - test_ios_e2e: + requires: + - setup_ios + - test_js + - test_js: + name: test_js_lts + executor: nodelts + requires: + - setup_js + - test_docker: + filters: + branches: + ignore: gh-pages releases: jobs: + - setup: + name: setup_android + checkout_type: android + executor: reactnativeandroid + filters: + # Both of the following conditions must be included! + # Ignore any commit on any branch by default. + branches: + ignore: /.*/ + # Only act on version tags. + tags: + only: /v[0-9]+(\.[0-9]+)*(\-rc(\.[0-9]+)?)?/ - publish_npm_package: - filters: *filter-only-version-tags + requires: + - setup_android analysis: jobs: + - setup + # Run lints on every commit other than those to the gh-pages branch + - analyze_code: + requires: + - setup + filters: + branches: + ignore: gh-pages + # Run code checks on PRs from forks - analyze_pr: - filters: *filter-only-forked-pull-requests + requires: + - setup + filters: + branches: + only: /^pull\/.*$/ # Gather coverage on master - js_coverage: - filters: *filter-only-master + requires: + - setup + filters: + branches: + only: master diff --git a/scripts/run-ci-e2e-tests.js b/scripts/run-ci-e2e-tests.js index 95312e7998d57a..b5db0c4816802e 100644 --- a/scripts/run-ci-e2e-tests.js +++ b/scripts/run-ci-e2e-tests.js @@ -44,6 +44,7 @@ try { // install CLI const CLI_PACKAGE = 'react-native-cli'; if (!argv['skip-cli-install']) { + describe('Instal react-native-cli'); if (exec(`yarn global add ${CLI_PACKAGE}`).code) { echo('Could not install react-native-cli globally.'); echo('Run with --skip-cli-install to skip this step'); @@ -53,6 +54,7 @@ try { } if (argv.android) { + describe('Compile Android binaries'); if ( exec( './gradlew :ReactAndroid:installArchives -Pjobs=1 -Dorg.gradle.jvmargs="-Xmx512m -XX:+HeapDumpOnOutOfMemoryError"', @@ -65,6 +67,7 @@ try { } if (argv.js) { + describe('Install Flow'); if ( tryExecNTimes( () => { @@ -81,6 +84,7 @@ try { } } + describe('Create react-native package'); if (exec('npm pack').code) { echo('Failed to pack react-native'); exitCode = 1; @@ -90,12 +94,16 @@ try { const PACKAGE = path.join(ROOT, 'react-native-*.tgz'); cd(TEMP); - echo('Creating EndToEndTest React Native app'); + describe('Create EndToEndTest React Native app'); if ( tryExecNTimes( () => { - return exec(`react-native init EndToEndTest --version ${PACKAGE} --npm`) - .code; + return exec( + `${path.join( + ROOT, + '/node_modules/.bin/react-native', + )} init EndToEndTest --version ${PACKAGE} --npm`, + ).code; }, numberOfRetries, () => { @@ -116,9 +124,10 @@ try { cp(RN_POLYFILLS, 'EndToEndTest/.'); cd('EndToEndTest'); - echo('Installing React Native package'); + describe('Install React Native package'); exec(`npm install ${PACKAGE}`); - echo('Installing node_modules'); + + describe('Install node_modules'); if ( tryExecNTimes( () => { @@ -135,8 +144,7 @@ try { } if (argv.android) { - describe('Executing Android end-to-end tests'); - echo('Installing end-to-end framework'); + describe('Install end-to-end framework'); if ( tryExecNTimes( () => @@ -154,10 +162,11 @@ try { } cp(`${SCRIPTS}/android-e2e-test.js`, 'android-e2e-test.js'); cd('android'); - echo('Downloading Maven deps'); + describe('Download Maven deps'); exec('./gradlew :app:copyDownloadableDepsToLibs'); cd('..'); + describe('Generate key'); exec('rm android/app/debug.keystore'); if ( exec( @@ -169,18 +178,18 @@ try { throw Error(exitCode); } - echo(`Starting appium server, ${APPIUM_PID}`); + describe(`Start appium server, ${APPIUM_PID}`); const appiumProcess = spawn('node', ['./node_modules/.bin/appium']); APPIUM_PID = appiumProcess.pid; - echo('Building the app'); - if (exec('react-native run-android').code) { + describe('Build the app'); + if (exec('./node_modules/.bin/react-native run-android').code) { echo('could not execute react-native run-android'); exitCode = 1; throw Error(exitCode); } - echo(`Starting packager server, ${SERVER_PID}`); + describe(`Start packager server, ${SERVER_PID}`); // shelljs exec('', {async: true}) does not emit stdout events, so we rely on good old spawn const packagerProcess = spawn('yarn', ['start', '--max-workers 1'], { env: process.env, @@ -207,11 +216,11 @@ try { if (argv.ios || argv.tvos) { var iosTestType = argv.tvos ? 'tvOS' : 'iOS'; - describe('Executing ' + iosTestType + ' end-to-end tests'); cd('ios'); // shelljs exec('', {async: true}) does not emit stdout events, so we rely on good old spawn const packagerEnv = Object.create(process.env); packagerEnv.REACT_NATIVE_MAX_WORKERS = 1; + describe('Start packager server'); const packagerProcess = spawn('yarn', ['start'], { stdio: 'inherit', env: packagerEnv, @@ -222,9 +231,11 @@ try { exec( 'response=$(curl --write-out %{http_code} --silent --output /dev/null localhost:8081/index.bundle?platform=ios&dev=true)', ); - echo(`Starting packager server, ${SERVER_PID}`); - echo('Running pod install'); + echo(`Packager server up and running, ${SERVER_PID}`); + + describe('Install CocoaPod dependencies'); exec('pod install'); + describe('Test: ' + iosTestType + ' end-to-end test'); if ( tryExecNTimes( @@ -259,7 +270,7 @@ try { '--report', 'junit', '--output', - `"~/react-native/reports/junit/${iosTestType}-e2e/results.xml"`, + `"~/reports/junit/${iosTestType}-e2e/results.xml"`, ].join(' ') + ' && exit ${PIPESTATUS[0]}', ).code; @@ -277,12 +288,11 @@ try { } if (argv.js) { - describe('Executing JavaScript end-to-end tests'); // Check the packager produces a bundle (doesn't throw an error) describe('Test: Verify packager can generate an Android bundle'); if ( exec( - 'react-native bundle --max-workers 1 --platform android --dev true --entry-file index.js --bundle-output android-bundle.js', + './node_modules/.bin/react-native bundle --max-workers 1 --dev true --entry-file index.js --bundle-output android-bundle.js --platform android', ).code ) { echo('Could not build Android bundle'); @@ -292,7 +302,7 @@ try { describe('Test: Verify packager can generate an iOS bundle'); if ( exec( - 'react-native --max-workers 1 bundle --platform ios --dev true --entry-file index.js --bundle-output ios-bundle.js', + './node_modules/.bin/react-native bundle --max-workers 1 --dev true --entry-file index.js --bundle-output ios-bundle.js --platform ios', ).code ) { echo('Could not build iOS bundle'); @@ -308,6 +318,7 @@ try { } exitCode = 0; } finally { + describe('Clean up'); if (SERVER_PID) { echo(`Killing packager ${SERVER_PID}`); exec(`kill -9 ${SERVER_PID}`); From 99bb710617ed6c0e076e6283e3cf4e107a4ea05e Mon Sep 17 00:00:00 2001 From: Dan Nguyen Date: Thu, 30 May 2019 15:16:14 -0700 Subject: [PATCH 0132/1084] Revert D15495065: Add method to get a segment path without injecting it in the VM Differential Revision: D15495065 Original commit changeset: 6537100d8b6d fbshipit-source-id: fee8319eaa5461f11ee4ea8d3b9d25e211beb2a8 --- .../SegmentFetcher/NativeSegmentFetcher.js | 5 -- Libraries/Core/setUpSegmentFetcher.js | 47 ++----------------- 2 files changed, 3 insertions(+), 49 deletions(-) diff --git a/Libraries/Core/SegmentFetcher/NativeSegmentFetcher.js b/Libraries/Core/SegmentFetcher/NativeSegmentFetcher.js index 765b8ef0e07ef3..38319e03456d68 100644 --- a/Libraries/Core/SegmentFetcher/NativeSegmentFetcher.js +++ b/Libraries/Core/SegmentFetcher/NativeSegmentFetcher.js @@ -18,11 +18,6 @@ export interface Spec extends TurboModule { options: Object, // flowlint-line unclear-type: off callback: (error: ?Object) => void, // flowlint-line unclear-type: off ) => void; - +getSegment?: ( - segmentId: number, - options: Object, // flowlint-line unclear-type: off - callback: (error: ?Object, path: ?string) => void, // flowlint-line unclear-type: off - ) => void; } export default TurboModuleRegistry.getEnforcing('SegmentFetcher'); diff --git a/Libraries/Core/setUpSegmentFetcher.js b/Libraries/Core/setUpSegmentFetcher.js index 3d811535ce38ee..dd182a69c91bb7 100644 --- a/Libraries/Core/setUpSegmentFetcher.js +++ b/Libraries/Core/setUpSegmentFetcher.js @@ -9,20 +9,13 @@ */ 'use strict'; -export type FetchSegmentFunction = typeof __fetchSegment; -export type GetSegmentFunction = typeof __getSegment; - /** * Set up SegmentFetcher. * You can use this module directly, or just require InitializeCore. */ - -function __fetchSegment( +global.__fetchSegment = function( segmentId: number, - options: {| - +otaBuildNumber: ?string, - +requestedModuleName?: ?string, - |}, + options: {|+otaBuildNumber: ?string|}, callback: (?Error) => void, ) { const SegmentFetcher = require('./SegmentFetcher/NativeSegmentFetcher') @@ -40,38 +33,4 @@ function __fetchSegment( callback(null); }, ); -} - -global.__fetchSegment = __fetchSegment; - -function __getSegment( - segmentId: number, - options: {| - +otaBuildNumber: ?string, - +requestedModuleName?: ?string, - |}, - callback: (?Error, ?string) => void, -) { - const SegmentFetcher = require('./SegmentFetcher/NativeSegmentFetcher') - .default; - - if (!SegmentFetcher.getSegment) { - throw new Error('SegmentFetcher.getSegment must be defined'); - } - - SegmentFetcher.getSegment( - segmentId, - options, - (errorObject: ?{message: string, code: string}, path: ?string) => { - if (errorObject) { - const error = new Error(errorObject.message); - (error: any).code = errorObject.code; // flowlint-line unclear-type: off - callback(error); - } - - callback(null, path); - }, - ); -} - -global.__getSegment = __getSegment; +}; From 7fb02bd90884f0a717e8151d4d30767fe38392c1 Mon Sep 17 00:00:00 2001 From: Emily Janzer Date: Thu, 30 May 2019 15:56:55 -0700 Subject: [PATCH 0133/1084] Rename onAccessibilityAction event on Android Summary: D15391408 (https://github.com/facebook/react-native/pull/24695) added a new event type with the registration name 'onAccessibilityAction' on Android, using the key 'performAction'. On iOS the same event uses the key 'topAccessibilityAction', which caused a runtime error after I started registering both using the unified JS view config in D15488008. This diff changes Android to use the same name as iOS since the convention is to start with 'top'. Reviewed By: cpojer Differential Revision: D15542623 fbshipit-source-id: c339621d2b4d3e1700feb5419ae3e3af8b185ca8 --- .../main/java/com/facebook/react/uimanager/BaseViewManager.java | 2 +- .../facebook/react/uimanager/ReactAccessibilityDelegate.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java index 524a4bf60c084e..0e68825e67ed16 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java @@ -376,7 +376,7 @@ protected void onAfterUpdateTransaction(@Nonnull T view) { @Override public @Nullable Map getExportedCustomDirectEventTypeConstants() { return MapBuilder.builder() - .put("performAction", MapBuilder.of("registrationName", "onAccessibilityAction")) + .put("topAccessibilityAction", MapBuilder.of("registrationName", "onAccessibilityAction")) .build(); } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java index 481f2e2821d669..332114fca6a14d 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java @@ -183,7 +183,7 @@ public boolean performAccessibilityAction(View host, int action, Bundle args) { ReactContext reactContext = (ReactContext)host.getContext(); reactContext.getJSModule(RCTEventEmitter.class).receiveEvent( host.getId(), - "performAction", + "topAccessibilityAction", event); return true; } From 060a3ea3bf7bb1f77dbb29a6fe23e2e823fbc52b Mon Sep 17 00:00:00 2001 From: Ram N Date: Thu, 30 May 2019 17:24:27 -0700 Subject: [PATCH 0134/1084] Delete Start/Stop Profiler from Dev Menu in Android Reviewed By: mdvacca Differential Revision: D10473627 fbshipit-source-id: eec61903f0a7abd0757aed0750d4bd828e4887bc --- .../com/facebook/react/DebugCorePackage.java | 13 +- .../devsupport/DevSupportManagerImpl.java | 67 +------- .../react/devsupport/JSCSamplingProfiler.java | 148 ------------------ .../main/res/devsupport/values/strings.xml | 1 - 4 files changed, 2 insertions(+), 227 deletions(-) delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/devsupport/JSCSamplingProfiler.java diff --git a/ReactAndroid/src/main/java/com/facebook/react/DebugCorePackage.java b/ReactAndroid/src/main/java/com/facebook/react/DebugCorePackage.java index 1ecb2d5557d39f..e40b61a93c698c 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/DebugCorePackage.java +++ b/ReactAndroid/src/main/java/com/facebook/react/DebugCorePackage.java @@ -10,9 +10,8 @@ import com.facebook.react.bridge.ModuleSpec; import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.devsupport.JSCSamplingProfiler; -import com.facebook.react.devsupport.JSDevSupport; import com.facebook.react.devsupport.JSCHeapCapture; +import com.facebook.react.devsupport.JSDevSupport; import com.facebook.react.module.annotations.ReactModuleList; import com.facebook.react.module.model.ReactModuleInfoProvider; import java.util.ArrayList; @@ -27,7 +26,6 @@ @ReactModuleList( nativeModules = { JSCHeapCapture.class, - JSCSamplingProfiler.class, JSDevSupport.class, } ) @@ -48,15 +46,6 @@ public NativeModule get() { return new JSCHeapCapture(reactContext); } })); - moduleSpecList.add( - ModuleSpec.nativeModuleSpec( - JSCSamplingProfiler.class, - new Provider() { - @Override - public NativeModule get() { - return new JSCSamplingProfiler(reactContext); - } - })); return moduleSpecList; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java index 7443b4e3d2bb7e..5938ce067ec761 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java @@ -150,39 +150,6 @@ private enum ErrorType { private @Nullable Map mCustomPackagerCommandHandlers; - private static class JscProfileTask extends AsyncTask { - private static final MediaType JSON = - MediaType.parse("application/json; charset=utf-8"); - - private final String mSourceUrl; - - private JscProfileTask(String sourceUrl) { - mSourceUrl = sourceUrl; - } - - @Override - protected Void doInBackground(String... jsonData) { - try { - String jscProfileUrl = - Uri.parse(mSourceUrl).buildUpon() - .path("/jsc-profile") - .query(null) - .build() - .toString(); - OkHttpClient client = new OkHttpClient(); - for (String json: jsonData) { - RequestBody body = RequestBody.create(JSON, json); - Request request = - new Request.Builder().url(jscProfileUrl).post(body).build(); - client.newCall(request).execute(); - } - } catch (IOException e) { - FLog.e(ReactConstants.TAG, "Failed not talk to server", e); - } - return null; - } - } - public DevSupportManagerImpl( Context applicationContext, ReactInstanceManagerDevHelper reactInstanceManagerHelper, @@ -467,10 +434,8 @@ public void onOptionSelected() { } }); if (mDevSettings.isNuclideJSDebugEnabled()) { - // The concatenation is applied directly here because XML isn't emoji-friendly String nuclideJsDebugMenuItemTitle = - mApplicationContext.getString(R.string.catalyst_debugjs_nuclide) - + EMOJI_HUNDRED_POINTS_SYMBOL; + mApplicationContext.getString(R.string.catalyst_debugjs_nuclide); options.put( nuclideJsDebugMenuItemTitle, new DevOptionHandler() { @@ -484,9 +449,6 @@ public void onOptionSelected() { mDevSettings.isRemoteJSDebugEnabled() ? mApplicationContext.getString(R.string.catalyst_debugjs_off) : mApplicationContext.getString(R.string.catalyst_debugjs); - if (mDevSettings.isNuclideJSDebugEnabled()) { - remoteJsDebugMenuItemTitle += EMOJI_FACE_WITH_NO_GOOD_GESTURE; - } options.put( remoteJsDebugMenuItemTitle, new DevOptionHandler() { @@ -549,14 +511,6 @@ public void onOptionSelected() { mDevSettings.setFpsDebugEnabled(!mDevSettings.isFpsDebugEnabled()); } }); - options.put( - mApplicationContext.getString(R.string.catalyst_poke_sampling_profiler), - new DevOptionHandler() { - @Override - public void onOptionSelected() { - handlePokeSamplingProfiler(); - } - }); options.put( mApplicationContext.getString(R.string.catalyst_settings), new DevOptionHandler() { @Override @@ -878,25 +832,6 @@ public void onFailure(JSCHeapCapture.CaptureException error) { }); } - private void handlePokeSamplingProfiler() { - try { - List pokeResults = JSCSamplingProfiler.poke(60000); - for (String result : pokeResults) { - Toast.makeText( - mCurrentContext, - result == null - ? "Started JSC Sampling Profiler" - : "Stopped JSC Sampling Profiler", - Toast.LENGTH_LONG).show(); - new JscProfileTask(getSourceUrl()).executeOnExecutor( - AsyncTask.THREAD_POOL_EXECUTOR, - result); - } - } catch (JSCSamplingProfiler.ProfilerException e) { - showNewJavaError(e.getMessage(), e); - } - } - private void updateLastErrorInfo( @Nullable final String message, final StackFrame[] stack, diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/JSCSamplingProfiler.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/JSCSamplingProfiler.java deleted file mode 100644 index 59c05dcf4f2234..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/JSCSamplingProfiler.java +++ /dev/null @@ -1,148 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react.devsupport; - -import javax.annotation.Nullable; - -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; - -import com.facebook.react.bridge.JavaScriptModule; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.ReactContextBaseJavaModule; -import com.facebook.react.bridge.ReactMethod; -import com.facebook.react.module.annotations.ReactModule; - -// This module is being called only by Java via the static method "poke" that -// requires it to alreay be initialized, thus we eagerly initialize this module -@ReactModule(name = "JSCSamplingProfiler", needsEagerInit = true) -public class JSCSamplingProfiler extends ReactContextBaseJavaModule { - public interface SamplingProfiler extends JavaScriptModule { - void poke(int token); - } - - public static class ProfilerException extends Exception { - ProfilerException(String message) { - super(message); - } - } - - private @Nullable SamplingProfiler mSamplingProfiler; - private boolean mOperationInProgress; - private int mOperationToken; - private @Nullable String mOperationError; - private @Nullable String mSamplingProfilerResult; - - private static final HashSet sRegisteredDumpers = - new HashSet<>(); - - private static synchronized void registerSamplingProfiler( - JSCSamplingProfiler dumper) { - if (sRegisteredDumpers.contains(dumper)) { - throw new RuntimeException( - "a JSCSamplingProfiler registered more than once"); - } - sRegisteredDumpers.add(dumper); - } - - private static synchronized void unregisterSamplingProfiler( - JSCSamplingProfiler dumper) { - sRegisteredDumpers.remove(dumper); - } - - public static synchronized List poke(long timeout) - throws ProfilerException { - LinkedList results = new LinkedList<>(); - if (sRegisteredDumpers.isEmpty()) { - throw new ProfilerException("No JSC registered"); - } - - for (JSCSamplingProfiler dumper : sRegisteredDumpers) { - dumper.pokeHelper(timeout); - results.add(dumper.mSamplingProfilerResult); - } - return results; - } - - public JSCSamplingProfiler(ReactApplicationContext reactContext) { - super(reactContext); - mSamplingProfiler = null; - mOperationInProgress = false; - mOperationToken = 0; - mOperationError = null; - mSamplingProfilerResult = null; - } - - private synchronized void pokeHelper(long timeout) throws ProfilerException { - if (mSamplingProfiler == null) { - throw new ProfilerException("SamplingProfiler.js module not connected"); - } - mSamplingProfiler.poke(getOperationToken()); - waitForOperation(timeout); - } - - private int getOperationToken() throws ProfilerException { - if (mOperationInProgress) { - throw new ProfilerException("Another operation already in progress."); - } - mOperationInProgress = true; - return ++mOperationToken; - } - - private void waitForOperation(long timeout) throws ProfilerException { - try { - wait(timeout); - } catch (InterruptedException e) { - throw new ProfilerException( - "Waiting for heap capture failed: " + e.getMessage()); - } - - if (mOperationInProgress) { - mOperationInProgress = false; - throw new ProfilerException("heap capture timed out."); - } - - if (mOperationError != null) { - throw new ProfilerException(mOperationError); - } - } - - @ReactMethod - public synchronized void operationComplete( - int token, String result, String error) { - if (token == mOperationToken) { - mOperationInProgress = false; - mSamplingProfilerResult = result; - mOperationError = error; - this.notify(); - } else { - throw new RuntimeException("Completed operation is not in progress."); - } - } - - @Override - public String getName() { - return "JSCSamplingProfiler"; - } - - @Override - public void initialize() { - super.initialize(); - mSamplingProfiler = - getReactApplicationContext().getJSModule(SamplingProfiler.class); - registerSamplingProfiler(this); - } - - @Override - public void onCatalystInstanceDestroy() { - super.onCatalystInstanceDestroy(); - unregisterSamplingProfiler(this); - mSamplingProfiler = null; - } -} diff --git a/ReactAndroid/src/main/res/devsupport/values/strings.xml b/ReactAndroid/src/main/res/devsupport/values/strings.xml index 29411de6e7aa8f..125f48d6195af7 100644 --- a/ReactAndroid/src/main/res/devsupport/values/strings.xml +++ b/ReactAndroid/src/main/res/devsupport/values/strings.xml @@ -20,7 +20,6 @@ Capture Heap Dismiss\n(ESC) Reload\n(R,\u00A0R) - Start/Stop Sampling Profiler Copy\n Report Loading from %1$s… From 739651afa1c0b90bf0fb75d9c09047645ff55388 Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Thu, 30 May 2019 18:47:10 -0700 Subject: [PATCH 0135/1084] RN: Simplify Context Creation (Android) Summary: Every call site is either already using `createReactContextInBackground` correctly or guarding the invocation using `hasStartedCreatingInitialContext`. This is an unnecessary and overly complex dance that can be simplified. This revision simplifies the use of `createReactContextInBackground` by integrating the check. This is not a breaking change. Reviewed By: zackargyle, mdvacca Differential Revision: D15566632 fbshipit-source-id: 7b50285c9ac6776d1297d2c9c53dff208851b722 --- .../facebook/react/HeadlessJsTaskService.java | 4 +--- .../com/facebook/react/ReactInstanceManager.java | 16 +++++----------- .../java/com/facebook/react/ReactRootView.java | 4 +--- 3 files changed, 7 insertions(+), 17 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/HeadlessJsTaskService.java b/ReactAndroid/src/main/java/com/facebook/react/HeadlessJsTaskService.java index cf809e9eb17435..c527167cf3db92 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/HeadlessJsTaskService.java +++ b/ReactAndroid/src/main/java/com/facebook/react/HeadlessJsTaskService.java @@ -108,9 +108,7 @@ public void onReactContextInitialized(ReactContext reactContext) { reactInstanceManager.removeReactInstanceEventListener(this); } }); - if (!reactInstanceManager.hasStartedCreatingInitialContext()) { - reactInstanceManager.createReactContextInBackground(); - } + reactInstanceManager.createReactContextInBackground(); } else { invokeStartTask(reactContext, taskConfig); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java index e9513a059352bc..0926cf7efb37ce 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java @@ -325,23 +325,17 @@ private static void initializeSoLoaderIfNecessary(Context applicationContext) { /** * Trigger react context initialization asynchronously in a background async task. This enables * applications to pre-load the application JS, and execute global code before - * {@link ReactRootView} is available and measured. This should only be called the first time the - * application is set up, which is enforced to keep developers from accidentally creating their - * application multiple times without realizing it. + * {@link ReactRootView} is available and measured. * * Called from UI thread. */ @ThreadConfined(UI) public void createReactContextInBackground() { Log.d(ReactConstants.TAG, "ReactInstanceManager.createReactContextInBackground()"); - Assertions.assertCondition( - !mHasStartedCreatingInitialContext, - "createReactContextInBackground should only be called when creating the react " + - "application for the first time. When reloading JS, e.g. from a new file, explicitly" + - "use recreateReactContextInBackground"); - - mHasStartedCreatingInitialContext = true; - recreateReactContextInBackgroundInner(); + if (!mHasStartedCreatingInitialContext) { + mHasStartedCreatingInitialContext = true; + recreateReactContextInBackgroundInner(); + } } /** diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java index 3cf5a45d3a85fb..1a98fd22479e14 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java @@ -394,9 +394,7 @@ public void startReactApplication( // TODO initialize surface here } - if (!mReactInstanceManager.hasStartedCreatingInitialContext()) { - mReactInstanceManager.createReactContextInBackground(); - } + mReactInstanceManager.createReactContextInBackground(); attachToReactInstanceManager(); From a0879ce49f11812e478d0cda2827f36f325cf972 Mon Sep 17 00:00:00 2001 From: Eric Lewis Date: Thu, 30 May 2019 21:01:55 -0700 Subject: [PATCH 0136/1084] Add spec for UIManager (#24902) Summary: part of #24875. Because some of the methods are rewriteable, I dropped the `+` from the signature, this doesn't feel right to me, but I am not sure if the codegen requires that. If it does, it will probably be better to extend the spec and allow those specific methods to be overriden in a UIManager.js interface. Thoughts on that fkgozali or RSNara? ## Changelog [General] [Added] - Add TM spec for UIManager Pull Request resolved: https://github.com/facebook/react-native/pull/24902 Reviewed By: hramos Differential Revision: D15551356 Pulled By: fkgozali fbshipit-source-id: 076c4ce635aa7ea41e21cbd67c47ecd562fc320d --- .../AccessibilityInfo.android.js | 2 +- Libraries/ReactNative/NativeUIManager.js | 122 ++++++++++++++++ Libraries/ReactNative/UIManager.js | 131 +++++++++++------- Libraries/ReactNative/UIManagerStatTracker.js | 4 +- .../getNativeComponentAttributes.js | 7 +- 5 files changed, 213 insertions(+), 53 deletions(-) create mode 100644 Libraries/ReactNative/NativeUIManager.js diff --git a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js index ff9a7329a56c87..5c9ab848d2ecff 100644 --- a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js +++ b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js @@ -139,7 +139,7 @@ const AccessibilityInfo = { setAccessibilityFocus: function(reactTag: number): void { UIManager.sendAccessibilityEvent( reactTag, - UIManager.AccessibilityEventTypes.typeViewFocused, + UIManager.getConstants().AccessibilityEventTypes.typeViewFocused, ); }, diff --git a/Libraries/ReactNative/NativeUIManager.js b/Libraries/ReactNative/NativeUIManager.js new file mode 100644 index 00000000000000..9eb60e68194b81 --- /dev/null +++ b/Libraries/ReactNative/NativeUIManager.js @@ -0,0 +1,122 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +getConstants: () => Object; + +getConstantsForViewManager: (viewManagerName: string) => Object; + +getDefaultEventTypes: () => Array; + +playTouchSound: () => void; + +lazilyLoadView: (name: string) => Object; // revisit return + +createView: ( + reactTag: ?number, + viewName: string, + rootTag: number, + props: Object, + ) => void; + +updateView: (reactTag: number, viewName: string, props: Object) => void; + +focus: (reactTag: ?number) => void; + +blur: (reactTag: ?number) => void; + +findSubviewIn: ( + reactTag: ?number, + point: [number, number], + callback: ( + nativeViewTag: number, + left: number, + top: number, + width: number, + height: number, + ) => void, + ) => void; + +dispatchViewManagerCommand: ( + reactTag: ?number, + commandID: number, + commandArgs: ?Array, // is this best? + ) => void; + +measure: ( + reactTag: ?number, + callback: ( + left: number, + top: number, + width: number, + height: number, + pageX: number, + pageY: number, + ) => void, + ) => void; + +measureInWindow: ( + reactTag: ?number, + callback: (x: number, y: number, width: number, height: number) => void, + ) => void; + +viewIsDescendantOf: ( + reactTag: ?number, + ancestorReactTag: ?number, + callback: (result: Array) => void, + ) => void; + +measureLayout: ( + reactTag: ?number, + ancestorReactTag: ?number, + errorCallback: (error: Object) => void, + callback: ( + left: number, + top: number, + width: number, + height: number, + ) => void, + ) => void; + +measureLayoutRelativeToParent: ( + reactTag: ?number, + errorCallback: (error: Object) => void, + callback: ( + left: number, + top: number, + width: number, + height: number, + ) => void, + ) => void; + +setJSResponder: (reactTag: ?number, blockNativeResponder: boolean) => void; + +clearJSResponder: () => void; + +configureNextLayoutAnimation: ( + config: Object, + callback: () => void, // check what is returned here + errorCallback: (error: Object) => void, + ) => void; + +removeSubviewsFromContainerWithID: (containerID: number) => void; + +replaceExistingNonRootView: ( + reactTag: ?number, + newReactTag: ?number, + ) => void; + +setChildren: (containerTag: ?number, reactTags: Array) => void; + +manageChildren: ( + containerTag: ?number, + moveFromIndices: Array, + moveToIndices: Array, + addChildReactTags: Array, + addAtIndices: Array, + removeAtIndices: Array, + ) => void; + + // Android only + +setLayoutAnimationEnabledExperimental: (enabled: boolean) => void; + +sendAccessibilityEvent: (reactTag: ?number, eventType: number) => void; + +showPopupMenu: ( + reactTag: ?number, + items: Array, + error: (error: Object) => void, + success: (event: string, selected?: number) => void, + ) => void; + +dismissPopupMenu: () => void; +} + +export default TurboModuleRegistry.getEnforcing('UIManager'); diff --git a/Libraries/ReactNative/UIManager.js b/Libraries/ReactNative/UIManager.js index cf7f8edbdbb839..234732bfe1db2c 100644 --- a/Libraries/ReactNative/UIManager.js +++ b/Libraries/ReactNative/UIManager.js @@ -4,7 +4,7 @@ * 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 + * @flow * @format */ 'use strict'; @@ -14,58 +14,94 @@ const Platform = require('../Utilities/Platform'); const UIManagerProperties = require('./UIManagerProperties'); const defineLazyObjectProperty = require('../Utilities/defineLazyObjectProperty'); -const invariant = require('invariant'); -const {UIManager} = NativeModules; +import NativeUIManager from './NativeUIManager'; +import type {Spec} from './NativeUIManager'; + const viewManagerConfigs = {}; -invariant( - UIManager, - 'UIManager is undefined. The native module config is probably incorrect.', -); +interface UIManagerJSInterface extends Spec { + +getViewManagerConfig: (viewManagerName: string) => Object; + // The following are not marked read-only due to logic in UIManagerStatTracker. + createView: ( + reactTag: ?number, + viewName: string, + rootTag: number, + props: Object, + ) => void; + updateView: (reactTag: number, viewName: string, props: Object) => void; + manageChildren: ( + containerTag: ?number, + moveFromIndices: Array, + moveToIndices: Array, + addChildReactTags: Array, + addAtIndices: Array, + removeAtIndices: Array, + ) => void; +} const triedLoadingConfig = new Set(); -UIManager.getViewManagerConfig = function(viewManagerName: string) { - if ( - viewManagerConfigs[viewManagerName] === undefined && - UIManager.getConstantsForViewManager - ) { - try { - viewManagerConfigs[ - viewManagerName - ] = UIManager.getConstantsForViewManager(viewManagerName); - } catch (e) { - viewManagerConfigs[viewManagerName] = null; - } - } - const config = viewManagerConfigs[viewManagerName]; - if (config) { - return config; +let NativeUIManagerConstants = {}; +let isNativeUIManagerConstantsSet = false; +function getConstants(): Object { + if (!isNativeUIManagerConstantsSet) { + NativeUIManagerConstants = NativeUIManager.getConstants(); + isNativeUIManagerConstantsSet = true; } + return NativeUIManagerConstants; +} + +const UIManagerJS: UIManagerJSInterface = { + ...NativeUIManager, + getConstants(): Object { + return getConstants(); + }, + getViewManagerConfig: function(viewManagerName: string) { + if ( + viewManagerConfigs[viewManagerName] === undefined && + NativeUIManager.getConstantsForViewManager + ) { + try { + viewManagerConfigs[ + viewManagerName + ] = NativeUIManager.getConstantsForViewManager(viewManagerName); + } catch (e) { + viewManagerConfigs[viewManagerName] = null; + } + } - // If we're in the Chrome Debugger, let's not even try calling the sync - // method. - if (__DEV__) { - if (!global.nativeCallSyncHook) { + const config = viewManagerConfigs[viewManagerName]; + if (config) { return config; } - } - if (UIManager.lazilyLoadView && !triedLoadingConfig.has(viewManagerName)) { - const result = UIManager.lazilyLoadView(viewManagerName); - triedLoadingConfig.add(viewManagerName); - if (result.viewConfig) { - UIManager[viewManagerName] = result.viewConfig; - lazifyViewManagerConfig(viewManagerName); + // If we're in the Chrome Debugger, let's not even try calling the sync + // method. + if (__DEV__) { + if (!global.nativeCallSyncHook) { + return config; + } } - } - return viewManagerConfigs[viewManagerName]; + if ( + NativeUIManager.lazilyLoadView && + !triedLoadingConfig.has(viewManagerName) + ) { + const result = NativeUIManager.lazilyLoadView(viewManagerName); + triedLoadingConfig.add(viewManagerName); + if (result.viewConfig) { + getConstants()[viewManagerName] = result.viewConfig; + lazifyViewManagerConfig(viewManagerName); + } + } + + return viewManagerConfigs[viewManagerName]; + }, }; function lazifyViewManagerConfig(viewName) { - const viewConfig = UIManager[viewName]; + const viewConfig = getConstants()[viewName]; if (viewConfig.Manager) { viewManagerConfigs[viewName] = viewConfig; defineLazyObjectProperty(viewConfig, 'Constants', { @@ -106,10 +142,10 @@ function lazifyViewManagerConfig(viewName) { * namespace instead of UIManager, unlike Android. */ if (Platform.OS === 'ios') { - Object.keys(UIManager).forEach(viewName => { + Object.keys(getConstants()).forEach(viewName => { lazifyViewManagerConfig(viewName); }); -} else if (UIManager.ViewManagerNames) { +} else if (getConstants().ViewManagerNames) { // We want to add all the view managers to the UIManager. // However, the way things are set up, the list of view managers is not known at compile time. // As Prepack runs at compile it, it cannot process this loop. @@ -120,13 +156,13 @@ if (Platform.OS === 'ios') { residual( 'void', (UIManager, defineLazyObjectProperty) => { - UIManager.ViewManagerNames.forEach(viewManagerName => { + UIManager.getConstants().ViewManagerNames.forEach(viewManagerName => { defineLazyObjectProperty(UIManager, viewManagerName, { get: () => UIManager.getConstantsForViewManager(viewManagerName), }); }); }, - UIManager, + NativeUIManager, defineLazyObjectProperty, ); @@ -135,27 +171,28 @@ if (Platform.OS === 'ios') { // so that any accesses to unknown properties along the global code will fail // when Prepack encounters them. if (global.__makePartial) { - global.__makePartial(UIManager); + global.__makePartial(NativeUIManager); } } if (__DEV__) { - Object.keys(UIManager).forEach(viewManagerName => { + Object.keys(getConstants()).forEach(viewManagerName => { if (!UIManagerProperties.includes(viewManagerName)) { if (!viewManagerConfigs[viewManagerName]) { - viewManagerConfigs[viewManagerName] = UIManager[viewManagerName]; + viewManagerConfigs[viewManagerName] = getConstants()[viewManagerName]; } - defineLazyObjectProperty(UIManager, viewManagerName, { + defineLazyObjectProperty(NativeUIManager, viewManagerName, { get: () => { console.warn( `Accessing view manager configs directly off UIManager via UIManager['${viewManagerName}'] ` + `is no longer supported. Use UIManager.getViewManagerConfig('${viewManagerName}') instead.`, ); - return UIManager.getViewManagerConfig(viewManagerName); + + return UIManagerJS.getViewManagerConfig(viewManagerName); }, }); } }); } -module.exports = UIManager; +module.exports = UIManagerJS; diff --git a/Libraries/ReactNative/UIManagerStatTracker.js b/Libraries/ReactNative/UIManagerStatTracker.js index ec1494c53b4390..85aaa6ba7707a7 100644 --- a/Libraries/ReactNative/UIManagerStatTracker.js +++ b/Libraries/ReactNative/UIManagerStatTracker.js @@ -52,8 +52,8 @@ const UIManagerStatTracker = { remove, ) { incStat('manageChildren', 1); - incStat('move', Object.keys(moveFrom || []).length); - incStat('remove', Object.keys(remove || []).length); + incStat('move', moveFrom.length); + incStat('remove', remove.length); manageChildrenOrig(tag, moveFrom, moveTo, addTags, addIndices, remove); }; }, diff --git a/Libraries/ReactNative/getNativeComponentAttributes.js b/Libraries/ReactNative/getNativeComponentAttributes.js index bf08c389eb8753..85a347bea1f358 100644 --- a/Libraries/ReactNative/getNativeComponentAttributes.js +++ b/Libraries/ReactNative/getNativeComponentAttributes.js @@ -96,17 +96,18 @@ function attachDefaultEventTypes(viewConfig: any) { // This is supported on UIManager platforms (ex: Android), // as lazy view managers are not implemented for all platforms. // See [UIManager] for details on constants and implementations. - if (UIManager.ViewManagerNames || UIManager.LazyViewManagersEnabled) { + const constants = UIManager.getConstants(); + if (constants.ViewManagerNames || constants.LazyViewManagersEnabled) { // Lazy view managers enabled. viewConfig = merge(viewConfig, UIManager.getDefaultEventTypes()); } else { viewConfig.bubblingEventTypes = merge( viewConfig.bubblingEventTypes, - UIManager.genericBubblingEventTypes, + constants.genericBubblingEventTypes, ); viewConfig.directEventTypes = merge( viewConfig.directEventTypes, - UIManager.genericDirectEventTypes, + constants.genericDirectEventTypes, ); } } From 85252a6cac044872e80f35fb3ab1c198d92cbf21 Mon Sep 17 00:00:00 2001 From: Jarvis Luong Date: Thu, 30 May 2019 21:01:55 -0700 Subject: [PATCH 0137/1084] Add spec for DevSettings (#25084) Summary: Part of #24875, adds a spec for DevSettings. ## Changelog [General] [Added] - TM spec for DevSettings Pull Request resolved: https://github.com/facebook/react-native/pull/25084 Reviewed By: hramos Differential Revision: D15558093 Pulled By: fkgozali fbshipit-source-id: 3adcb640a6ad80c84c831905bda114e27177f1fe --- .../NativeModules/specs/NativeDevSettings.js | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 Libraries/NativeModules/specs/NativeDevSettings.js diff --git a/Libraries/NativeModules/specs/NativeDevSettings.js b/Libraries/NativeModules/specs/NativeDevSettings.js new file mode 100644 index 00000000000000..9a53a0db7905e0 --- /dev/null +++ b/Libraries/NativeModules/specs/NativeDevSettings.js @@ -0,0 +1,28 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +'use strict'; + +import type {TurboModule} from '../../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../../TurboModule/TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +reload: () => void; + +setHotLoadingEnabled: (isHotLoadingEnabled: boolean) => void; + +setIsDebuggingRemotely: (isDebuggingRemotelyEnabled: boolean) => void; + +setLiveReloadEnabled: (isLiveReloadEnabled: boolean) => void; + +setProfilingEnabled: (isProfilingEnabled: boolean) => void; + +toggleElementInspector: () => void; + + // iOS only. + +setIsShakeToShowDevMenuEnabled: (enabled: boolean) => void; +} + +export default TurboModuleRegistry.getEnforcing('DevSettings'); From 8db4de41e41f1983ac71f618fa29ce70e3d09eb5 Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Thu, 30 May 2019 21:39:30 -0700 Subject: [PATCH 0138/1084] TM Spec: relax PermissionsAndroid enforcement Summary: Some modules accessed PermissionsAndroid even in iOS, causing redbox. Let's relax the enforcement, then invariant() on the callsites instead. Reviewed By: yungsters Differential Revision: D15572716 fbshipit-source-id: 4a2edea608ab27727e88f0f246ecb9cdcf5a5329 --- .../NativePermissionsAndroid.js | 2 +- .../PermissionsAndroid/PermissionsAndroid.js | 24 ++++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/Libraries/PermissionsAndroid/NativePermissionsAndroid.js b/Libraries/PermissionsAndroid/NativePermissionsAndroid.js index 025f9af18419b1..4212164d8baf83 100644 --- a/Libraries/PermissionsAndroid/NativePermissionsAndroid.js +++ b/Libraries/PermissionsAndroid/NativePermissionsAndroid.js @@ -56,4 +56,4 @@ export interface Spec extends TurboModule { ) => Promise<{[permission: PermissionType]: PermissionStatus}>; } -export default TurboModuleRegistry.getEnforcing('PermissionsAndroid'); +export default TurboModuleRegistry.get('PermissionsAndroid'); diff --git a/Libraries/PermissionsAndroid/PermissionsAndroid.js b/Libraries/PermissionsAndroid/PermissionsAndroid.js index 1b414e71165a29..427fb21c8a1f88 100644 --- a/Libraries/PermissionsAndroid/PermissionsAndroid.js +++ b/Libraries/PermissionsAndroid/PermissionsAndroid.js @@ -11,10 +11,11 @@ 'use strict'; import NativeDialogManagerAndroid from '../NativeModules/specs/NativeDialogManagerAndroid'; -const NativeModules = require('../BatchedBridge/NativeModules'); const Platform = require('../Utilities/Platform'); import NativePermissionsAndroid from './NativePermissionsAndroid'; +import invariant from 'invariant'; + import type { PermissionStatus, PermissionType, @@ -90,6 +91,11 @@ class PermissionsAndroid { return Promise.resolve(false); } + invariant( + NativePermissionsAndroid, + 'PermissionsAndroid is not installed correctly.', + ); + return NativePermissionsAndroid.checkPermission(permission); } @@ -106,6 +112,12 @@ class PermissionsAndroid { ); return Promise.resolve(false); } + + invariant( + NativePermissionsAndroid, + 'PermissionsAndroid is not installed correctly.', + ); + return NativePermissionsAndroid.checkPermission(permission); } @@ -158,6 +170,11 @@ class PermissionsAndroid { return Promise.resolve(this.RESULTS.DENIED); } + invariant( + NativePermissionsAndroid, + 'PermissionsAndroid is not installed correctly.', + ); + if (rationale) { const shouldShowRationale = await NativePermissionsAndroid.shouldShowRequestPermissionRationale( permission, @@ -197,6 +214,11 @@ class PermissionsAndroid { return Promise.resolve({}); } + invariant( + NativePermissionsAndroid, + 'PermissionsAndroid is not installed correctly.', + ); + return NativePermissionsAndroid.requestMultiplePermissions(permissions); } } From 796e9b0e3746ec8e58dcae19750bc1672ca93605 Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Thu, 30 May 2019 22:38:59 -0700 Subject: [PATCH 0139/1084] RN: Debug Menu Cleanup (iOS) Summary: Addresses a number of pieces of feedback regarding the debug menu. - Simplify labels for the debugger actions (e.g. no "remote", no emoji). - Reorder actions so that modal items are generally lower. - Changed "Toggle Inspector" to "Show/Hide Inspector". - Renamed "Live Reloading" to "Reload-on-Save". - Hide disabled debug items when profiling is enabled. - Changed "Start Systrace" to "Systrace Unavailable" when debugging. - Renamed "Change packager location" to "Configure Bundler". - Revised nomenclature in "Configure Bundler" menu to be clearer. - Removed extraneous debug menu title. - Consistently refer to HMR as "Hot Reloading". Changelog: [iOS] [Changed] - Cleaned up debug menu. Reviewed By: axe-fb Differential Revision: D15548628 fbshipit-source-id: 26b2ddca8280d1f6f8ff904439b403600e98a3b3 --- Libraries/Utilities/HMRClient.js | 4 +- React/DevSupport/RCTDevMenu.m | 125 ++++++++++++++++--------------- 2 files changed, 65 insertions(+), 64 deletions(-) diff --git a/Libraries/Utilities/HMRClient.js b/Libraries/Utilities/HMRClient.js index eb34d2d83ecc8d..f901778b659a39 100644 --- a/Libraries/Utilities/HMRClient.js +++ b/Libraries/Utilities/HMRClient.js @@ -45,7 +45,7 @@ const HMRClient = { const hmrClient = new MetroHMRClient(wsUrl); hmrClient.on('connection-error', e => { - let error = `Hot loading isn't working because it cannot connect to the development server. + let error = `Hot reloading isn't working because it cannot connect to the development server. Try the following to fix the issue: - Ensure that the packager server is running and available on the same network`; @@ -70,7 +70,7 @@ Error: ${e.message}`; }); hmrClient.on('update-start', () => { - HMRLoadingView.showMessage('Hot Loading...'); + HMRLoadingView.showMessage('Hot Reloading...'); }); hmrClient.on('update', () => { diff --git a/React/DevSupport/RCTDevMenu.m b/React/DevSupport/RCTDevMenu.m index 140be91dd98fa5..a57c4222cfdde0 100644 --- a/React/DevSupport/RCTDevMenu.m +++ b/React/DevSupport/RCTDevMenu.m @@ -210,56 +210,62 @@ - (void)setDefaultJSBundle { [bridge reload]; }]]; - if (devSettings.isNuclideDebuggingAvailable) { - [items addObject:[RCTDevMenuItem buttonItemWithTitle:[NSString stringWithFormat:@"Debug JS in Nuclide %@", @"\U0001F4AF"] handler:^{ -#if RCT_ENABLE_INSPECTOR - [RCTInspectorDevServerHelper attachDebugger:@"ReactNative" withBundleURL:bridge.bundleURL withView: RCTPresentedViewController()]; -#endif - }]]; - } + if (!devSettings.isProfilingEnabled) { + if (!devSettings.isRemoteDebuggingAvailable) { + [items addObject:[RCTDevMenuItem buttonItemWithTitle:@"Debugger Unavailable" handler:^{ + NSString *message = RCTTurboModuleEnabled() ? + @"Debugging is not currently supported when TurboModule is enabled." : + @"Include the RCTWebSocket library to enable JavaScript debugging."; + UIAlertController *alertController = [UIAlertController + alertControllerWithTitle:@"Debugger Unavailable" + message:message + preferredStyle:UIAlertControllerStyleAlert]; + __weak typeof(alertController) weakAlertController = alertController; + [alertController addAction: + [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(__unused UIAlertAction *action){ + [weakAlertController dismissViewControllerAnimated:YES completion:nil]; + }]]; + [RCTPresentedViewController() presentViewController:alertController animated:YES completion:NULL]; + }]]; + } else { + [items addObject:[RCTDevMenuItem buttonItemWithTitleBlock:^NSString *{ + if (devSettings.isNuclideDebuggingAvailable) { + return devSettings.isDebuggingRemotely ? @"Stop Chrome Debugger" : @"Debug with Chrome"; + } else { + return devSettings.isDebuggingRemotely ? @"Stop Debugging" : @"Debug"; + } + } handler:^{ + devSettings.isDebuggingRemotely = !devSettings.isDebuggingRemotely; + }]]; + } - if (!devSettings.isRemoteDebuggingAvailable) { - [items addObject:[RCTDevMenuItem buttonItemWithTitle:@"Remote JS Debugger Unavailable" handler:^{ - NSString *message = RCTTurboModuleEnabled() ? - @"You cannot use remote JS debugging when TurboModule system is enabled" : - @"You need to include the RCTWebSocket library to enable remote JS debugging"; - UIAlertController *alertController = [UIAlertController - alertControllerWithTitle:@"Remote JS Debugger Unavailable" - message:message - preferredStyle:UIAlertControllerStyleAlert]; - __weak typeof(alertController) weakAlertController = alertController; - [alertController addAction: - [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(__unused UIAlertAction *action){ - [weakAlertController dismissViewControllerAnimated:YES completion:nil]; + if (devSettings.isNuclideDebuggingAvailable && !devSettings.isDebuggingRemotely) { + [items addObject:[RCTDevMenuItem buttonItemWithTitle:@"Debug with Nuclide" handler:^{ + #if RCT_ENABLE_INSPECTOR + [RCTInspectorDevServerHelper attachDebugger:@"ReactNative" withBundleURL:bridge.bundleURL withView: RCTPresentedViewController()]; + #endif }]]; - [RCTPresentedViewController() presentViewController:alertController animated:YES completion:NULL]; - }]]; - } else { - [items addObject:[RCTDevMenuItem buttonItemWithTitleBlock:^NSString *{ - NSString *title = devSettings.isDebuggingRemotely ? @"Stop Remote JS Debugging" : @"Debug JS Remotely"; - if (devSettings.isNuclideDebuggingAvailable) { - return [NSString stringWithFormat:@"%@ %@", title, @"\U0001F645"]; - } else { - return title; - } - } handler:^{ - devSettings.isDebuggingRemotely = !devSettings.isDebuggingRemotely; - }]]; + } } + [items addObject:[RCTDevMenuItem buttonItemWithTitleBlock:^NSString *{ + return devSettings.isElementInspectorShown ? @"Disable Inspector" : @"Enable Inspector"; + } handler:^{ + [devSettings toggleElementInspector]; + }]]; + if (devSettings.isLiveReloadAvailable) { [items addObject:[RCTDevMenuItem buttonItemWithTitleBlock:^NSString *{ - return devSettings.isLiveReloadEnabled ? @"Disable Live Reload" : @"Enable Live Reload"; - } handler:^{ - devSettings.isLiveReloadEnabled = !devSettings.isLiveReloadEnabled; - }]]; - [items addObject:[RCTDevMenuItem buttonItemWithTitleBlock:^NSString *{ - return devSettings.isProfilingEnabled ? @"Stop Systrace" : @"Start Systrace"; + return devSettings.isDebuggingRemotely + ? @"Systrace Unavailable" + : devSettings.isProfilingEnabled + ? @"Stop Systrace" + : @"Start Systrace"; } handler:^{ if (devSettings.isDebuggingRemotely) { UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Systrace Unavailable" - message:@"You need to stop remote JS debugging to enable Systrace" + message:@"Stop debugging to enable Systrace." preferredStyle:UIAlertControllerStyleAlert]; __weak typeof(alertController) weakAlertController = alertController; [alertController addAction: @@ -271,9 +277,15 @@ - (void)setDefaultJSBundle { devSettings.isProfilingEnabled = !devSettings.isProfilingEnabled; } }]]; + + [items addObject:[RCTDevMenuItem buttonItemWithTitleBlock:^NSString *{ + return devSettings.isLiveReloadEnabled ? @"Disable Reload-on-Save" : @"Enable Reload-on-Save"; + } handler:^{ + devSettings.isLiveReloadEnabled = !devSettings.isLiveReloadEnabled; + }]]; } - if (_bridge.devSettings.isHotLoadingAvailable) { + if (devSettings.isHotLoadingAvailable) { [items addObject:[RCTDevMenuItem buttonItemWithTitleBlock:^NSString *{ return devSettings.isHotLoadingEnabled ? @"Disable Hot Reloading" : @"Enable Hot Reloading"; } handler:^{ @@ -282,10 +294,10 @@ - (void)setDefaultJSBundle { } [items addObject:[RCTDevMenuItem buttonItemWithTitleBlock:^NSString *{ - return @"Change packager location"; + return @"Configure Bundler"; } handler:^{ - UIAlertController * alertController = [UIAlertController alertControllerWithTitle: @"Change packager location" - message: @"Input packager IP, port and entrypoint" + UIAlertController * alertController = [UIAlertController alertControllerWithTitle: @"Configure Bundler" + message: @"Provide a custom bundler address, port, and entrypoint." preferredStyle:UIAlertControllerStyleAlert]; [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) { textField.placeholder = @"0.0.0.0"; @@ -296,16 +308,13 @@ - (void)setDefaultJSBundle { [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) { textField.placeholder = @"index"; }]; - [alertController addAction:[UIAlertAction actionWithTitle:@"Use bundled JS" style:UIAlertActionStyleDefault handler:^(__unused UIAlertAction *action) { - [weakSelf setDefaultJSBundle]; - }]]; - [alertController addAction:[UIAlertAction actionWithTitle:@"Use packager location" style:UIAlertActionStyleDefault handler:^(__unused UIAlertAction *action) { + [alertController addAction:[UIAlertAction actionWithTitle:@"Apply Changes" style:UIAlertActionStyleDefault handler:^(__unused UIAlertAction *action) { NSArray * textfields = alertController.textFields; UITextField * ipTextField = textfields[0]; UITextField * portTextField = textfields[1]; UITextField * bundleRootTextField = textfields[2]; NSString * bundleRoot = bundleRootTextField.text; - if(bundleRoot.length==0){ + if(bundleRoot.length == 0){ bundleRoot = @"index"; } if(ipTextField.text.length == 0 && portTextField.text.length == 0) { @@ -326,18 +335,15 @@ - (void)setDefaultJSBundle { [strongBridge reload]; } }]]; + [alertController addAction:[UIAlertAction actionWithTitle:@"Reset to Default" style:UIAlertActionStyleDefault handler:^(__unused UIAlertAction *action) { + [weakSelf setDefaultJSBundle]; + }]]; [alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(__unused UIAlertAction *action) { return; }]]; [RCTPresentedViewController() presentViewController:alertController animated:YES completion:NULL]; }]]; - [items addObject:[RCTDevMenuItem buttonItemWithTitleBlock:^NSString *{ - return @"Toggle Inspector"; - } handler:^{ - [devSettings toggleElementInspector]; - }]]; - [items addObjectsFromArray:_extraMenuItems]; return items; } @@ -348,15 +354,10 @@ - (void)setDefaultJSBundle { return; } - NSString *desc = _bridge.bridgeDescription; - if (desc.length == 0) { - desc = NSStringFromClass([_bridge class]); - } - NSString *title = [NSString stringWithFormat:@"React Native: Development (%@)", desc]; // On larger devices we don't have an anchor point for the action sheet UIAlertControllerStyle style = [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone ? UIAlertControllerStyleActionSheet : UIAlertControllerStyleAlert; - _actionSheet = [UIAlertController alertControllerWithTitle:title - message:@"" + _actionSheet = [UIAlertController alertControllerWithTitle:nil + message:nil preferredStyle:style]; NSArray *items = [self _menuItemsToPresent]; From dac037d371f77963cfff3fc3acfcb8a8c955a3d2 Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Thu, 30 May 2019 22:38:59 -0700 Subject: [PATCH 0140/1084] RN: Debug Menu Cleanup (Android) Summary: Addresses a number of pieces of feedback regarding the debug menu. - Simplify labels for the debugger actions (e.g. no "remote", no emoji). - Reorder actions so that modal items are generally lower. - Renamed "Live Reloading" to "Reload-on-Save". - Renamed "Dev Settings" to "Settings". Changelog: [Android] [Changed] - Cleaned up debug menu. Reviewed By: cpojer Differential Revision: D15553883 fbshipit-source-id: d30e8cd0804e010985c0cf40d443defc7c0710ac --- .../devsupport/DevLoadingViewController.java | 2 +- .../react/devsupport/DevServerHelper.java | 2 +- .../devsupport/DevSupportManagerImpl.java | 113 ++++++++++-------- .../main/res/devsupport/values/strings.xml | 36 +++--- 4 files changed, 82 insertions(+), 71 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevLoadingViewController.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevLoadingViewController.java index d8f4f319aabe90..36b6eb07ec8af2 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevLoadingViewController.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevLoadingViewController.java @@ -81,7 +81,7 @@ public void showForRemoteJSEnabled() { return; } - showMessage(context.getString(R.string.catalyst_remotedbg_message)); + showMessage(context.getString(R.string.catalyst_debug_connecting)); } public void updateProgress(final @Nullable String status, final @Nullable Integer done, final @Nullable Integer total) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java index f7d9748c967d3e..2f70a32292ece7 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java @@ -275,7 +275,7 @@ public boolean doSync() { @Override protected void onPostExecute(Boolean result) { if (!result) { - String message = context.getString(R.string.catalyst_debugjs_nuclide_failure); + String message = context.getString(R.string.catalyst_debug_nuclide_error); Toast.makeText(context, message, Toast.LENGTH_LONG).show(); } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java index 5938ce067ec761..dfc241c51091fc 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java @@ -422,46 +422,59 @@ public void showDevOptionsDialog() { LinkedHashMap options = new LinkedHashMap<>(); /* register standard options */ options.put( - mApplicationContext.getString(R.string.catalyst_reloadjs), + mApplicationContext.getString(R.string.catalyst_reload), + new DevOptionHandler() { + @Override + public void onOptionSelected() { + if (!mDevSettings.isJSDevModeEnabled() && mDevSettings.isHotModuleReplacementEnabled()) { + Toast.makeText( + mApplicationContext, + mApplicationContext.getString(R.string.catalyst_hot_reloading_auto_disable), + Toast.LENGTH_LONG).show(); + mDevSettings.setHotModuleReplacementEnabled(false); + } + handleReloadJS(); + } + }); + options.put( + mDevSettings.isNuclideJSDebugEnabled() + ? mDevSettings.isRemoteJSDebugEnabled() + ? mApplicationContext.getString(R.string.catalyst_debug_chrome_stop) + : mApplicationContext.getString(R.string.catalyst_debug_chrome) + : mDevSettings.isRemoteJSDebugEnabled() + ? mApplicationContext.getString(R.string.catalyst_debug_stop) + : mApplicationContext.getString(R.string.catalyst_debug), + new DevOptionHandler() { + @Override + public void onOptionSelected() { + mDevSettings.setRemoteJSDebugEnabled(!mDevSettings.isRemoteJSDebugEnabled()); + handleReloadJS(); + } + }); + if (mDevSettings.isNuclideJSDebugEnabled()) { + options.put( + mApplicationContext.getString(R.string.catalyst_debug_nuclide), new DevOptionHandler() { @Override public void onOptionSelected() { - if (!mDevSettings.isJSDevModeEnabled() && mDevSettings.isHotModuleReplacementEnabled()) { - Toast.makeText(mApplicationContext, "HMR cannot be enabled when Dev mode is off. Disabling HMR...", Toast.LENGTH_LONG).show(); - mDevSettings.setHotModuleReplacementEnabled(false); - } - handleReloadJS(); + mDevServerHelper.attachDebugger(mApplicationContext, "ReactNative"); } }); - if (mDevSettings.isNuclideJSDebugEnabled()) { - String nuclideJsDebugMenuItemTitle = - mApplicationContext.getString(R.string.catalyst_debugjs_nuclide); - options.put( - nuclideJsDebugMenuItemTitle, - new DevOptionHandler() { - @Override - public void onOptionSelected() { - mDevServerHelper.attachDebugger(mApplicationContext, "ReactNative"); - } - }); } - String remoteJsDebugMenuItemTitle = - mDevSettings.isRemoteJSDebugEnabled() - ? mApplicationContext.getString(R.string.catalyst_debugjs_off) - : mApplicationContext.getString(R.string.catalyst_debugjs); options.put( - remoteJsDebugMenuItemTitle, + // NOTE: `isElementInspectorEnabled` is not guaranteed to be accurate. + mApplicationContext.getString(R.string.catalyst_inspector), new DevOptionHandler() { @Override public void onOptionSelected() { - mDevSettings.setRemoteJSDebugEnabled(!mDevSettings.isRemoteJSDebugEnabled()); - handleReloadJS(); + mDevSettings.setElementInspectorEnabled(!mDevSettings.isElementInspectorEnabled()); + mReactInstanceManagerHelper.toggleElementInspector(); } }); options.put( mDevSettings.isReloadOnJSChangeEnabled() - ? mApplicationContext.getString(R.string.catalyst_live_reload_off) - : mApplicationContext.getString(R.string.catalyst_live_reload), + ? mApplicationContext.getString(R.string.catalyst_reload_on_save_stop) + : mApplicationContext.getString(R.string.catalyst_reload_on_save), new DevOptionHandler() { @Override public void onOptionSelected() { @@ -469,32 +482,26 @@ public void onOptionSelected() { } }); options.put( - mDevSettings.isHotModuleReplacementEnabled() - ? mApplicationContext.getString(R.string.catalyst_hot_module_replacement_off) - : mApplicationContext.getString(R.string.catalyst_hot_module_replacement), - new DevOptionHandler() { - @Override - public void onOptionSelected() { - if (!mDevSettings.isHotModuleReplacementEnabled() && !mDevSettings.isJSDevModeEnabled()) { - Toast.makeText(mApplicationContext, "You're trying to enable HMR while Dev mode is off. Turning both HMR and the Dev mode on...", Toast.LENGTH_LONG).show(); - mDevSettings.setJSDevModeEnabled(true); - } - mDevSettings.setHotModuleReplacementEnabled(!mDevSettings.isHotModuleReplacementEnabled()); - handleReloadJS(); - } - }); - options.put( - mApplicationContext.getString(R.string.catalyst_element_inspector), - new DevOptionHandler() { - @Override - public void onOptionSelected() { - mDevSettings.setElementInspectorEnabled(!mDevSettings.isElementInspectorEnabled()); - mReactInstanceManagerHelper.toggleElementInspector(); - } - }); + mDevSettings.isHotModuleReplacementEnabled() + ? mApplicationContext.getString(R.string.catalyst_hot_reloading_stop) + : mApplicationContext.getString(R.string.catalyst_hot_reloading), + new DevOptionHandler() { + @Override + public void onOptionSelected() { + if (!mDevSettings.isHotModuleReplacementEnabled() && !mDevSettings.isJSDevModeEnabled()) { + Toast.makeText( + mApplicationContext, + mApplicationContext.getString(R.string.catalyst_hot_reloading_auto_enable), + Toast.LENGTH_LONG).show(); + mDevSettings.setJSDevModeEnabled(true); + } + mDevSettings.setHotModuleReplacementEnabled(!mDevSettings.isHotModuleReplacementEnabled()); + handleReloadJS(); + } + }); options.put( mDevSettings.isFpsDebugEnabled() - ? mApplicationContext.getString(R.string.catalyst_perf_monitor_off) + ? mApplicationContext.getString(R.string.catalyst_perf_monitor_stop) : mApplicationContext.getString(R.string.catalyst_perf_monitor), new DevOptionHandler() { @Override @@ -884,10 +891,10 @@ public void onSuccess() { public void onFailure(final Throwable cause) { mDevLoadingViewController.hide(); mDevLoadingViewVisible = false; - FLog.e(ReactConstants.TAG, "Unable to connect to remote debugger", cause); + FLog.e(ReactConstants.TAG, "Failed to connect to debugger!", cause); future.setException( new IOException( - mApplicationContext.getString(R.string.catalyst_remotedbg_error), cause)); + mApplicationContext.getString(R.string.catalyst_debug_error), cause)); } }; } @@ -951,7 +958,7 @@ public void run() { showNewJavaError(debugServerException.getMessage(), cause); } else { showNewJavaError( - mApplicationContext.getString(R.string.catalyst_jsload_error), + mApplicationContext.getString(R.string.catalyst_reload_error), cause); } } diff --git a/ReactAndroid/src/main/res/devsupport/values/strings.xml b/ReactAndroid/src/main/res/devsupport/values/strings.xml index 125f48d6195af7..4b04fddbbc7d48 100644 --- a/ReactAndroid/src/main/res/devsupport/values/strings.xml +++ b/ReactAndroid/src/main/res/devsupport/values/strings.xml @@ -1,22 +1,26 @@ - Reload - Debug JS in Nuclide - The request to attach Nuclide could not reach Metro Bundler! - Debug JS Remotely - Stop Remote JS Debugging - Enable Hot Reloading - Disable Hot Reloading - Enable Live Reload - Disable Live Reload + Reload + Failed to load bundle. Try restarting the bundler or reconnecting your device. + Debug + Stop Debugging + Connecting to debugger... + Failed to connect to debugger! + Debug with Chrome + Stop Chrome Debugging + Debug with Nuclide + Failed to communicate with the bundler to enabling debugging with Nuclide. + Enable Reload-on-Save + Disable Reload-on-Save + Enable Hot Reloading + Disable Hot Reloading + Disabling hot reloading because it requires a development bundle. + Switching to development bundle in order to enable hot reloading. + Toggle Inspector Show Perf Monitor - Hide Perf Monitor - Dev Settings - Catalyst Dev Settings - Unable to download JS bundle. Did you forget to start the development server or connect your device? - Connecting to remote debugger - Unable to connect with remote debugger - Toggle Inspector + Hide Perf Monitor + Settings + Debug Settings Capture Heap Dismiss\n(ESC) Reload\n(R,\u00A0R) From db9fc388932370f39aee412dc1d181a217f60226 Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Fri, 31 May 2019 00:41:48 -0700 Subject: [PATCH 0141/1084] Log `console.log` invocations to the Metro terminal. Summary: People ask "How do you use `console.log` with React Native?" and there is no good answer. This diff aims to stop people from asking this question. See https://fb.workplace.com/groups/rn.core/permalink/2372327062999018/ for context. This logging relies on network requests which can cause logs to show up out-of-order. To reduce the likelihood I queue every log message on the server for a maximum of 200ms. There could be other methods, like using websocket, but that seems more complex than is necessary at least in the beginning. I considered various throttling strategies because this could be quite chatty and possibly problematic, however I think we can just ship this and iterate based on feedback. On my very underpowered laptop I logged a random number every 10 milliseconds and it didn't cause any issues or slowdown. Reviewed By: gaearon Differential Revision: D15559151 fbshipit-source-id: 552001622af0937ae3a37d2bd8c1b96e7ca52020 --- Libraries/Core/Devtools/logToConsole.js | 33 +++++++++++++++++++++++++ Libraries/Core/setUpDeveloperTools.js | 10 ++++++++ 2 files changed, 43 insertions(+) create mode 100644 Libraries/Core/Devtools/logToConsole.js diff --git a/Libraries/Core/Devtools/logToConsole.js b/Libraries/Core/Devtools/logToConsole.js new file mode 100644 index 00000000000000..ecad232cb98a63 --- /dev/null +++ b/Libraries/Core/Devtools/logToConsole.js @@ -0,0 +1,33 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow strict-local + */ + +'use strict'; + +const getDevServer = require('./getDevServer'); + +let ID = 0; + +function logToConsole( + level: 'trace' | 'info' | 'warn' | 'log', + data: Array, +) { + let body; + try { + body = JSON.stringify({id: ID++, level, data}); + } catch (error) { + body = JSON.stringify({id: ID++, level, data: [error.message]}); + } + fetch(getDevServer().url + 'log-to-console', { + method: 'POST', + body, + }); +} + +module.exports = logToConsole; diff --git a/Libraries/Core/setUpDeveloperTools.js b/Libraries/Core/setUpDeveloperTools.js index e18b5be9740199..da9aa45c50e457 100644 --- a/Libraries/Core/setUpDeveloperTools.js +++ b/Libraries/Core/setUpDeveloperTools.js @@ -25,4 +25,14 @@ if (__DEV__) { const JSInspector = require('../JSInspector/JSInspector'); JSInspector.registerAgent(require('../JSInspector/NetworkAgent')); } + + const logToConsole = require('./Devtools/logToConsole'); + ['log', 'warn', 'info', 'trace'].forEach(level => { + const originalFunction = console[level]; + // $FlowFixMe Overwrite console methods + console[level] = function(...args) { + logToConsole(level, args); + originalFunction.apply(console, args); + }; + }); } From 5b7edb59a5198f6c00ece5c97c3c6b917a56313b Mon Sep 17 00:00:00 2001 From: Vojtech Novak Date: Fri, 31 May 2019 00:43:59 -0700 Subject: [PATCH 0142/1084] fix shouldComponentUpdate in YellowBox (#25097) Summary: The previous comparison does not make sense (accessing props by index) - and always returns true. I'm going to assume there was a reason for implementing `shouldComponentUpdate` - although personally I'd just go for PureComponent (even if it may not be 100% accurate). Let me know if PureComponent sounds better. ## Changelog not needed Pull Request resolved: https://github.com/facebook/react-native/pull/25097 Differential Revision: D15575079 Pulled By: cpojer fbshipit-source-id: 49aeb9d2997d3c613fe7a1af4534dff1607d53b4 --- Libraries/YellowBox/UI/YellowBoxListRow.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libraries/YellowBox/UI/YellowBoxListRow.js b/Libraries/YellowBox/UI/YellowBoxListRow.js index d10f11b9034709..f388c5083b117d 100644 --- a/Libraries/YellowBox/UI/YellowBoxListRow.js +++ b/Libraries/YellowBox/UI/YellowBoxListRow.js @@ -38,7 +38,7 @@ class YellowBoxListRow extends React.Component { prevProps.onPress !== nextProps.onPress || prevProps.warnings.length !== nextProps.warnings.length || prevProps.warnings.some( - (prevWarning, index) => prevWarning !== nextProps[index], + (prevWarning, index) => prevWarning !== nextProps.warnings[index], ) ); } From a1bfb284ee6fcd8832b7f2939fb2ea97117d5075 Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Fri, 31 May 2019 01:21:25 -0700 Subject: [PATCH 0143/1084] Use atomic list for event subscribers Summary: Replace the *copy on write* vector with an atomic pointer to a linked list. This allows to publish without locking a mutex, at the cost of the slower traversal of a linked list (a vector has better locality). At the moment, the typical use case is to have one subscriber, meaning that the afforementioned slower traversal is not a problem. Adding subscribers is implemented as atomic *compare and swap.* Reviewed By: SidharthGuglani Differential Revision: D15546964 fbshipit-source-id: 41bfa41f1ac6be5c9b6bf4288ea3271ee995877e --- ReactCommon/yoga/yoga/event/event.cpp | 56 +++++++++++++++------------ 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/ReactCommon/yoga/yoga/event/event.cpp b/ReactCommon/yoga/yoga/event/event.cpp index e2fe3588f1f96d..02e70dce02eb33 100644 --- a/ReactCommon/yoga/yoga/event/event.cpp +++ b/ReactCommon/yoga/yoga/event/event.cpp @@ -5,51 +5,57 @@ * file in the root directory of this source tree. */ #include "event.h" +#include #include #include -#include - -#include namespace facebook { namespace yoga { namespace { -std::mutex& eventSubscribersMutex() { - static std::mutex subscribersMutex; - return subscribersMutex; -} +struct Node { + std::function subscriber = nullptr; + Node* next = nullptr; + + Node(std::function&& subscriber) + : subscriber{std::move(subscriber)} {} +}; -std::shared_ptr& eventSubscribers() { - static auto subscribers = std::make_shared(); - return subscribers; +std::atomic subscribers{nullptr}; + +Node* push(Node* newHead) { + Node* oldHead; + do { + oldHead = subscribers.load(std::memory_order_relaxed); + if (newHead != nullptr) { + newHead->next = oldHead; + } + } while (!subscribers.compare_exchange_weak( + oldHead, newHead, std::memory_order_release, std::memory_order_relaxed)); + return oldHead; } } // namespace void Event::reset() { - eventSubscribers() = std::make_shared(); + auto head = push(nullptr); + while (head != nullptr) { + auto current = head; + head = head->next; + delete current; + } } void Event::subscribe(std::function&& subscriber) { - std::lock_guard guard(eventSubscribersMutex()); - eventSubscribers() = - std::make_shared(*eventSubscribers()); - eventSubscribers()->push_back(subscriber); + push(new Node{std::move(subscriber)}); } void Event::publish(const YGNode& node, Type eventType, const Data& eventData) { - std::shared_ptr subscribers; - { - std::lock_guard guard(eventSubscribersMutex()); - subscribers = eventSubscribers(); - } - - for (auto& subscriber : *subscribers) { - if (subscriber) { - subscriber(node, eventType, eventData); - } + for (auto subscriber = subscribers.load(std::memory_order_relaxed); + subscriber != nullptr; + subscriber = subscriber->next) { + subscriber->subscriber(node, eventType, eventData); } } From bccc92dfdd2d85933f2a9cb5c8d1773affb7acba Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Fri, 31 May 2019 01:32:13 -0700 Subject: [PATCH 0144/1084] Remove vendored fetch polyfill, update to whatwg-fetch@3.0 (#24418) Summary: The original reason for vendoring the fetch polyfill was to remove the default blob response type but this was reverted. Here's a little history around the fetch polyfill and the blob issue: - Original commit introducing the vendored polyfill: #19333, the goal was to fix a memory leak because our blob implementation doesn't release resources automatically. Not an ideal fix but since the issue was pretty severe and the infra for a proper fix was not in place. - This introduced an issue when downloading images using `fetch` which was fixed by #22063 which re-added the default blob content type. However that re-introduced the original fetch memory leak. - We have better infra now with jsi and I was able to get blob deallocation working, see #24405 Currently the vendored fetch polyfill is useless since it was changed back to the original version. We can just use the npm version again. I also updated to 3.0 which brings better spec compliance and support for cancellation via `AbortController`, https://github.com/github/fetch/releases/tag/v3.0.0. ## Changelog [General] [Changed] - Remove vendored fetch polyfill, update to whatwg-fetch@3.0 Pull Request resolved: https://github.com/facebook/react-native/pull/24418 Differential Revision: D14932683 Pulled By: cpojer fbshipit-source-id: 915e3d25978e8b9d7507ed807e7fba45aa88385a --- Libraries/Core/setUpGlobals.js | 4 + Libraries/Network/fetch.js | 2 +- Libraries/vendor/core/whatwg-fetch.js | 533 -------------------------- package.json | 3 +- yarn.lock | 2 +- 5 files changed, 8 insertions(+), 536 deletions(-) delete mode 100644 Libraries/vendor/core/whatwg-fetch.js diff --git a/Libraries/Core/setUpGlobals.js b/Libraries/Core/setUpGlobals.js index 0310f3c2bcf047..b4cdf775eb6e54 100644 --- a/Libraries/Core/setUpGlobals.js +++ b/Libraries/Core/setUpGlobals.js @@ -21,6 +21,10 @@ if (global.window === undefined) { global.window = global; } +if (global.self === undefined) { + global.self = global; +} + // Set up process global.process = global.process || {}; global.process.env = global.process.env || {}; diff --git a/Libraries/Network/fetch.js b/Libraries/Network/fetch.js index ec9c28f1860a93..66687e70de2035 100644 --- a/Libraries/Network/fetch.js +++ b/Libraries/Network/fetch.js @@ -11,7 +11,7 @@ 'use strict'; -const whatwg = require('../vendor/core/whatwg-fetch'); +const whatwg = require('whatwg-fetch'); if (whatwg && whatwg.fetch) { module.exports = whatwg; diff --git a/Libraries/vendor/core/whatwg-fetch.js b/Libraries/vendor/core/whatwg-fetch.js deleted file mode 100644 index 3f1767afda813e..00000000000000 --- a/Libraries/vendor/core/whatwg-fetch.js +++ /dev/null @@ -1,533 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -// Fork of https://github.com/github/fetch/blob/master/fetch.js that does not -// use reponseType: 'blob' by default. RN already has specific native implementations -// for different response types so there is no need to add the extra blob overhead. - -// Copyright (c) 2014-2016 GitHub, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -(function(self) { - 'use strict'; - - if (self.fetch) { - return; - } - - var support = { - searchParams: 'URLSearchParams' in self, - iterable: 'Symbol' in self && 'iterator' in Symbol, - blob: - 'FileReader' in self && - 'Blob' in self && - (function() { - try { - new Blob(); - return true; - } catch (e) { - return false; - } - })(), - formData: 'FormData' in self, - arrayBuffer: 'ArrayBuffer' in self, - }; - - if (support.arrayBuffer) { - var viewClasses = [ - '[object Int8Array]', - '[object Uint8Array]', - '[object Uint8ClampedArray]', - '[object Int16Array]', - '[object Uint16Array]', - '[object Int32Array]', - '[object Uint32Array]', - '[object Float32Array]', - '[object Float64Array]', - ]; - - var isDataView = function(obj) { - return obj && DataView.prototype.isPrototypeOf(obj); - }; - - var isArrayBufferView = - ArrayBuffer.isView || - function(obj) { - return ( - obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1 - ); - }; - } - - function normalizeName(name) { - if (typeof name !== 'string') { - name = String(name); - } - if (/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(name)) { - throw new TypeError('Invalid character in header field name'); - } - return name.toLowerCase(); - } - - function normalizeValue(value) { - if (typeof value !== 'string') { - value = String(value); - } - return value; - } - - // Build a destructive iterator for the value list - function iteratorFor(items) { - var iterator = { - next: function() { - var value = items.shift(); - return {done: value === undefined, value: value}; - }, - }; - - if (support.iterable) { - iterator[Symbol.iterator] = function() { - return iterator; - }; - } - - return iterator; - } - - function Headers(headers) { - this.map = {}; - - if (headers instanceof Headers) { - headers.forEach(function(value, name) { - this.append(name, value); - }, this); - } else if (Array.isArray(headers)) { - headers.forEach(function(header) { - this.append(header[0], header[1]); - }, this); - } else if (headers) { - Object.getOwnPropertyNames(headers).forEach(function(name) { - this.append(name, headers[name]); - }, this); - } - } - - Headers.prototype.append = function(name, value) { - name = normalizeName(name); - value = normalizeValue(value); - var oldValue = this.map[name]; - this.map[name] = oldValue ? oldValue + ',' + value : value; - }; - - Headers.prototype['delete'] = function(name) { - delete this.map[normalizeName(name)]; - }; - - Headers.prototype.get = function(name) { - name = normalizeName(name); - return this.has(name) ? this.map[name] : null; - }; - - Headers.prototype.has = function(name) { - return this.map.hasOwnProperty(normalizeName(name)); - }; - - Headers.prototype.set = function(name, value) { - this.map[normalizeName(name)] = normalizeValue(value); - }; - - Headers.prototype.forEach = function(callback, thisArg) { - for (var name in this.map) { - if (this.map.hasOwnProperty(name)) { - callback.call(thisArg, this.map[name], name, this); - } - } - }; - - Headers.prototype.keys = function() { - var items = []; - this.forEach(function(value, name) { - items.push(name); - }); - return iteratorFor(items); - }; - - Headers.prototype.values = function() { - var items = []; - this.forEach(function(value) { - items.push(value); - }); - return iteratorFor(items); - }; - - Headers.prototype.entries = function() { - var items = []; - this.forEach(function(value, name) { - items.push([name, value]); - }); - return iteratorFor(items); - }; - - if (support.iterable) { - Headers.prototype[Symbol.iterator] = Headers.prototype.entries; - } - - function consumed(body) { - if (body.bodyUsed) { - return Promise.reject(new TypeError('Already read')); - } - body.bodyUsed = true; - } - - function fileReaderReady(reader) { - return new Promise(function(resolve, reject) { - reader.onload = function() { - resolve(reader.result); - }; - reader.onerror = function() { - reject(reader.error); - }; - }); - } - - function readBlobAsArrayBuffer(blob) { - var reader = new FileReader(); - var promise = fileReaderReady(reader); - reader.readAsArrayBuffer(blob); - return promise; - } - - function readBlobAsText(blob) { - var reader = new FileReader(); - var promise = fileReaderReady(reader); - reader.readAsText(blob); - return promise; - } - - function readArrayBufferAsText(buf) { - var view = new Uint8Array(buf); - var chars = new Array(view.length); - - for (var i = 0; i < view.length; i++) { - chars[i] = String.fromCharCode(view[i]); - } - return chars.join(''); - } - - function bufferClone(buf) { - if (buf.slice) { - return buf.slice(0); - } else { - var view = new Uint8Array(buf.byteLength); - view.set(new Uint8Array(buf)); - return view.buffer; - } - } - - function Body() { - this.bodyUsed = false; - - this._initBody = function(body) { - this._bodyInit = body; - if (!body) { - this._bodyText = ''; - } else if (typeof body === 'string') { - this._bodyText = body; - } else if (support.blob && Blob.prototype.isPrototypeOf(body)) { - this._bodyBlob = body; - } else if (support.formData && FormData.prototype.isPrototypeOf(body)) { - this._bodyFormData = body; - } else if ( - support.searchParams && - URLSearchParams.prototype.isPrototypeOf(body) - ) { - this._bodyText = body.toString(); - } else if (support.arrayBuffer && support.blob && isDataView(body)) { - this._bodyArrayBuffer = bufferClone(body.buffer); - // IE 10-11 can't handle a DataView body. - this._bodyInit = new Blob([this._bodyArrayBuffer]); - } else if ( - support.arrayBuffer && - (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body)) - ) { - this._bodyArrayBuffer = bufferClone(body); - } else { - throw new Error('unsupported BodyInit type'); - } - - if (!this.headers.get('content-type')) { - if (typeof body === 'string') { - this.headers.set('content-type', 'text/plain;charset=UTF-8'); - } else if (this._bodyBlob && this._bodyBlob.type) { - this.headers.set('content-type', this._bodyBlob.type); - } else if ( - support.searchParams && - URLSearchParams.prototype.isPrototypeOf(body) - ) { - this.headers.set( - 'content-type', - 'application/x-www-form-urlencoded;charset=UTF-8', - ); - } - } - }; - - if (support.blob) { - this.blob = function() { - var rejected = consumed(this); - if (rejected) { - return rejected; - } - - if (this._bodyBlob) { - return Promise.resolve(this._bodyBlob); - } else if (this._bodyArrayBuffer) { - return Promise.resolve(new Blob([this._bodyArrayBuffer])); - } else if (this._bodyFormData) { - throw new Error('could not read FormData body as blob'); - } else { - return Promise.resolve(new Blob([this._bodyText])); - } - }; - - this.arrayBuffer = function() { - if (this._bodyArrayBuffer) { - return consumed(this) || Promise.resolve(this._bodyArrayBuffer); - } else { - return this.blob().then(readBlobAsArrayBuffer); - } - }; - } - - this.text = function() { - var rejected = consumed(this); - if (rejected) { - return rejected; - } - - if (this._bodyBlob) { - return readBlobAsText(this._bodyBlob); - } else if (this._bodyArrayBuffer) { - return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer)); - } else if (this._bodyFormData) { - throw new Error('could not read FormData body as text'); - } else { - return Promise.resolve(this._bodyText); - } - }; - - if (support.formData) { - this.formData = function() { - return this.text().then(decode); - }; - } - - this.json = function() { - return this.text().then(JSON.parse); - }; - - return this; - } - - // HTTP methods whose capitalization should be normalized - var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT']; - - function normalizeMethod(method) { - var upcased = method.toUpperCase(); - return methods.indexOf(upcased) > -1 ? upcased : method; - } - - function Request(input, options) { - options = options || {}; - var body = options.body; - - if (input instanceof Request) { - if (input.bodyUsed) { - throw new TypeError('Already read'); - } - this.url = input.url; - this.credentials = input.credentials; - if (!options.headers) { - this.headers = new Headers(input.headers); - } - this.method = input.method; - this.mode = input.mode; - if (!body && input._bodyInit != null) { - body = input._bodyInit; - input.bodyUsed = true; - } - } else { - this.url = String(input); - } - - this.credentials = options.credentials || this.credentials || 'omit'; - if (options.headers || !this.headers) { - this.headers = new Headers(options.headers); - } - this.method = normalizeMethod(options.method || this.method || 'GET'); - this.mode = options.mode || this.mode || null; - this.referrer = null; - - if ((this.method === 'GET' || this.method === 'HEAD') && body) { - throw new TypeError('Body not allowed for GET or HEAD requests'); - } - this._initBody(body); - } - - Request.prototype.clone = function() { - return new Request(this, {body: this._bodyInit}); - }; - - function decode(body) { - var form = new FormData(); - body - .trim() - .split('&') - .forEach(function(bytes) { - if (bytes) { - var split = bytes.split('='); - var name = split.shift().replace(/\+/g, ' '); - var value = split.join('=').replace(/\+/g, ' '); - form.append(decodeURIComponent(name), decodeURIComponent(value)); - } - }); - return form; - } - - function parseHeaders(rawHeaders) { - var headers = new Headers(); - // Replace instances of \r\n and \n followed by at least one space or horizontal tab with a space - // https://tools.ietf.org/html/rfc7230#section-3.2 - var preProcessedHeaders = rawHeaders.replace(/\r?\n[\t ]+/g, ' '); - preProcessedHeaders.split(/\r?\n/).forEach(function(line) { - var parts = line.split(':'); - var key = parts.shift().trim(); - if (key) { - var value = parts.join(':').trim(); - headers.append(key, value); - } - }); - return headers; - } - - Body.call(Request.prototype); - - function Response(bodyInit, options) { - if (!options) { - options = {}; - } - - this.type = 'default'; - this.status = options.status === undefined ? 200 : options.status; - this.ok = this.status >= 200 && this.status < 300; - this.statusText = 'statusText' in options ? options.statusText : 'OK'; - this.headers = new Headers(options.headers); - this.url = options.url || ''; - this._initBody(bodyInit); - } - - Body.call(Response.prototype); - - Response.prototype.clone = function() { - return new Response(this._bodyInit, { - status: this.status, - statusText: this.statusText, - headers: new Headers(this.headers), - url: this.url, - }); - }; - - Response.error = function() { - var response = new Response(null, {status: 0, statusText: ''}); - response.type = 'error'; - return response; - }; - - var redirectStatuses = [301, 302, 303, 307, 308]; - - Response.redirect = function(url, status) { - if (redirectStatuses.indexOf(status) === -1) { - throw new RangeError('Invalid status code'); - } - - return new Response(null, {status: status, headers: {location: url}}); - }; - - self.Headers = Headers; - self.Request = Request; - self.Response = Response; - - self.fetch = function(input, init) { - return new Promise(function(resolve, reject) { - var request = new Request(input, init); - var xhr = new XMLHttpRequest(); - - xhr.onload = function() { - var options = { - status: xhr.status, - statusText: xhr.statusText, - headers: parseHeaders(xhr.getAllResponseHeaders() || ''), - }; - options.url = - 'responseURL' in xhr - ? xhr.responseURL - : options.headers.get('X-Request-URL'); - var body = 'response' in xhr ? xhr.response : xhr.responseText; - resolve(new Response(body, options)); - }; - - xhr.onerror = function() { - reject(new TypeError('Network request failed')); - }; - - xhr.ontimeout = function() { - reject(new TypeError('Network request failed')); - }; - - xhr.open(request.method, request.url, true); - - if (request.credentials === 'include') { - xhr.withCredentials = true; - } else if (request.credentials === 'omit') { - xhr.withCredentials = false; - } - - if ('responseType' in xhr && support.blob) { - xhr.responseType = 'blob'; - } - - request.headers.forEach(function(value, name) { - xhr.setRequestHeader(name, value); - }); - - xhr.send( - typeof request._bodyInit === 'undefined' ? null : request._bodyInit, - ); - }); - }; - self.fetch.polyfill = true; -})(typeof self !== 'undefined' ? self : this); diff --git a/package.json b/package.json index fb864871321e10..47fbc2b66db8ca 100644 --- a/package.json +++ b/package.json @@ -104,7 +104,8 @@ "prop-types": "^15.7.2", "react-devtools-core": "^3.6.0", "regenerator-runtime": "^0.13.2", - "stacktrace-parser": "^0.1.3" + "stacktrace-parser": "^0.1.3", + "whatwg-fetch": "^3.0.0" }, "devDependencies": { "@babel/core": "^7.0.0", diff --git a/yarn.lock b/yarn.lock index 702e94ae62fb01..0eda165a2609d7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7356,7 +7356,7 @@ whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3: dependencies: iconv-lite "0.4.24" -whatwg-fetch@>=0.10.0: +whatwg-fetch@>=0.10.0, whatwg-fetch@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb" integrity sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q== From 90938d60535c256981c80dae79309b7fa2638e84 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Fri, 31 May 2019 02:14:57 -0700 Subject: [PATCH 0145/1084] Fixes text style lost when enable maxLength (#24989) Summary: To fix https://github.com/facebook/react-native/issues/24983, we lost text style when `maxLength` enabled. ## Changelog [iOS] [Fixed] - Fixes text style lost when enable maxLength Pull Request resolved: https://github.com/facebook/react-native/pull/24989 Differential Revision: D15575493 Pulled By: cpojer fbshipit-source-id: 60129d2c24f7985ea0da38354078dfeea28157bc --- Libraries/Text/TextInput/RCTBaseTextInputView.m | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Libraries/Text/TextInput/RCTBaseTextInputView.m b/Libraries/Text/TextInput/RCTBaseTextInputView.m index d9b0d7310d818f..5ffce4cd49e8ec 100644 --- a/Libraries/Text/TextInput/RCTBaseTextInputView.m +++ b/Libraries/Text/TextInput/RCTBaseTextInputView.m @@ -381,7 +381,12 @@ - (BOOL)textInputShouldChangeTextInRange:(NSRange)range replacementText:(NSStrin // Truncate the input string so the result is exactly maxLength NSString *limitedString = [text substringToIndex:allowedLength]; NSMutableAttributedString *newAttributedText = [backedTextInputView.attributedText mutableCopy]; - [newAttributedText replaceCharactersInRange:range withString:limitedString]; + // Apply text attributes if original input view doesn't have text. + if (backedTextInputView.attributedText.length == 0) { + newAttributedText = [[NSMutableAttributedString alloc] initWithString:[self.textAttributes applyTextAttributesToText:limitedString] attributes:self.textAttributes.effectiveTextAttributes]; + } else { + [newAttributedText replaceCharactersInRange:range withString:limitedString]; + } backedTextInputView.attributedText = newAttributedText; _predictedText = newAttributedText.string; From 74f56bd55793d49d84b1068eb3ed9042aeb341e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Norte?= Date: Fri, 31 May 2019 02:26:37 -0700 Subject: [PATCH 0146/1084] Add method to get a segment path without injecting it in the VM Reviewed By: cpojer Differential Revision: D15575463 fbshipit-source-id: 0b481c48f02353e0d15e0dec6162850a0e2140e9 --- .../SegmentFetcher/NativeSegmentFetcher.js | 5 ++ Libraries/Core/setUpSegmentFetcher.js | 47 +++++++++++++++++-- 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/Libraries/Core/SegmentFetcher/NativeSegmentFetcher.js b/Libraries/Core/SegmentFetcher/NativeSegmentFetcher.js index 38319e03456d68..765b8ef0e07ef3 100644 --- a/Libraries/Core/SegmentFetcher/NativeSegmentFetcher.js +++ b/Libraries/Core/SegmentFetcher/NativeSegmentFetcher.js @@ -18,6 +18,11 @@ export interface Spec extends TurboModule { options: Object, // flowlint-line unclear-type: off callback: (error: ?Object) => void, // flowlint-line unclear-type: off ) => void; + +getSegment?: ( + segmentId: number, + options: Object, // flowlint-line unclear-type: off + callback: (error: ?Object, path: ?string) => void, // flowlint-line unclear-type: off + ) => void; } export default TurboModuleRegistry.getEnforcing('SegmentFetcher'); diff --git a/Libraries/Core/setUpSegmentFetcher.js b/Libraries/Core/setUpSegmentFetcher.js index dd182a69c91bb7..3d811535ce38ee 100644 --- a/Libraries/Core/setUpSegmentFetcher.js +++ b/Libraries/Core/setUpSegmentFetcher.js @@ -9,13 +9,20 @@ */ 'use strict'; +export type FetchSegmentFunction = typeof __fetchSegment; +export type GetSegmentFunction = typeof __getSegment; + /** * Set up SegmentFetcher. * You can use this module directly, or just require InitializeCore. */ -global.__fetchSegment = function( + +function __fetchSegment( segmentId: number, - options: {|+otaBuildNumber: ?string|}, + options: {| + +otaBuildNumber: ?string, + +requestedModuleName?: ?string, + |}, callback: (?Error) => void, ) { const SegmentFetcher = require('./SegmentFetcher/NativeSegmentFetcher') @@ -33,4 +40,38 @@ global.__fetchSegment = function( callback(null); }, ); -}; +} + +global.__fetchSegment = __fetchSegment; + +function __getSegment( + segmentId: number, + options: {| + +otaBuildNumber: ?string, + +requestedModuleName?: ?string, + |}, + callback: (?Error, ?string) => void, +) { + const SegmentFetcher = require('./SegmentFetcher/NativeSegmentFetcher') + .default; + + if (!SegmentFetcher.getSegment) { + throw new Error('SegmentFetcher.getSegment must be defined'); + } + + SegmentFetcher.getSegment( + segmentId, + options, + (errorObject: ?{message: string, code: string}, path: ?string) => { + if (errorObject) { + const error = new Error(errorObject.message); + (error: any).code = errorObject.code; // flowlint-line unclear-type: off + callback(error); + } + + callback(null, path); + }, + ); +} + +global.__getSegment = __getSegment; From 284c5f0ad023204458124167789f43321f12776d Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Fri, 31 May 2019 02:56:49 -0700 Subject: [PATCH 0147/1084] Using presentingViewController to dismiss Modal (#24959) Summary: Fixes https://github.com/facebook/react-native/issues/23463. Using `presentingViewController` to dismiss Modal VC directly, don't let Modal VC to find `presentingViewController`, then dismiss. ## Changelog [iOS] [Fixed] - Using presentingViewController to dismiss Modal Pull Request resolved: https://github.com/facebook/react-native/pull/24959 Differential Revision: D15575571 Pulled By: cpojer fbshipit-source-id: e275e7c7fef644c06cc8e64dba5b5a5af4129192 --- React/Views/RCTModalHostViewManager.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/React/Views/RCTModalHostViewManager.m b/React/Views/RCTModalHostViewManager.m index 6377683d2dc748..495b90d2dddd7e 100644 --- a/React/Views/RCTModalHostViewManager.m +++ b/React/Views/RCTModalHostViewManager.m @@ -89,7 +89,7 @@ - (void)dismissModalHostView:(RCTModalHostView *)modalHostView withViewControlle if (_dismissalBlock) { _dismissalBlock([modalHostView reactViewController], viewController, animated, completionBlock); } else { - [viewController dismissViewControllerAnimated:animated completion:completionBlock]; + [viewController.presentingViewController dismissViewControllerAnimated:animated completion:completionBlock]; } } From 9d0d7b61b69a0395ebbcb0ddbfb324e38dbe070a Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Fri, 31 May 2019 02:58:00 -0700 Subject: [PATCH 0148/1084] Add ultrabold pairs for font weight (#24948) Summary: Add `ultrabold` map of font weight, if not, `ultrabold` would map to `bold`. Fixes https://github.com/facebook/react-native/issues/23512. ## Changelog [iOS] [Fixed] - Add ultrabold pairs for font weight Pull Request resolved: https://github.com/facebook/react-native/pull/24948 Differential Revision: D15575568 Pulled By: cpojer fbshipit-source-id: 5d1d6a033c166d91a330526ba8996ac0416f3887 --- React/Views/RCTFont.mm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/React/Views/RCTFont.mm b/React/Views/RCTFont.mm index e686637953a751..8c0e6d88c81d0b 100644 --- a/React/Views/RCTFont.mm +++ b/React/Views/RCTFont.mm @@ -32,6 +32,7 @@ static RCTFontWeight weightOfFont(UIFont *font) @"semibold", @"demibold", @"extrabold", + @"ultrabold", @"bold", @"heavy", @"black" @@ -46,6 +47,7 @@ static RCTFontWeight weightOfFont(UIFont *font) @(UIFontWeightSemibold), @(UIFontWeightSemibold), @(UIFontWeightHeavy), + @(UIFontWeightHeavy), @(UIFontWeightBold), @(UIFontWeightHeavy), @(UIFontWeightBlack) From 1ed352517ad387b4b7e48ce2b0ba3b9f7a8508e8 Mon Sep 17 00:00:00 2001 From: James Ide Date: Fri, 31 May 2019 03:12:46 -0700 Subject: [PATCH 0149/1084] Explicitly separate mocked native modules from mocked JS modules (#24809) Summary: This commit more clearly defines the mocks RN sets up and uses paths instead of Haste names to define the mocks. The Jest setup script defined mocks for native modules (Obj-C, Java) and mocks for JS modules in the same data structure. This meant that some non-native modules (that is, JS modules) were in the `mockNativeModules` map -- this commit splits them out and mocks them in typical `jest.mock` fashion. Additionally, the setup script used to mock the modules using the Haste names. As one of the steps toward migrating to standard path-based imports, the setup script now mocks JS modules using paths (native modules don't need a Haste name nor path since they are just entries in `NativeModules`). This gets us closer to being able to remove `hasteImpl`. (Tracking in https://github.com/facebook/react-native/issues/24772.) Also, this commit removes mocks that are not referenced anywhere in the RN and React repositories (grepped for the names and found no entries outside of the Jest setup scripts). ## Changelog [General] [Changed] - Explicitly separate mocked native modules from mocked JS modules Pull Request resolved: https://github.com/facebook/react-native/pull/24809 Differential Revision: D15316882 Pulled By: cpojer fbshipit-source-id: 039e4e320121bea9580196fe0a091b8b1e8b41bf --- .../__tests__/resolveAssetSource-test.js | 29 +- jest/setup.js | 480 ++++++++---------- 2 files changed, 233 insertions(+), 276 deletions(-) diff --git a/Libraries/Image/__tests__/resolveAssetSource-test.js b/Libraries/Image/__tests__/resolveAssetSource-test.js index 195a5be549eda2..287e0657beb5ac 100644 --- a/Libraries/Image/__tests__/resolveAssetSource-test.js +++ b/Libraries/Image/__tests__/resolveAssetSource-test.js @@ -10,20 +10,20 @@ 'use strict'; -const AssetRegistry = require('../AssetRegistry'); -const Platform = require('../../Utilities/Platform'); -const resolveAssetSource = require('../resolveAssetSource'); - -import NativeSourceCode from '../../NativeModules/specs/NativeSourceCode'; - -function expectResolvesAsset(input, expectedSource) { - const assetId = AssetRegistry.registerAsset(input); - expect(resolveAssetSource(assetId)).toEqual(expectedSource); -} - describe('resolveAssetSource', () => { + let AssetRegistry; + let resolveAssetSource; + let NativeSourceCode; + let Platform; + beforeEach(() => { jest.resetModules(); + + AssetRegistry = require('../AssetRegistry'); + resolveAssetSource = require('../resolveAssetSource'); + NativeSourceCode = require('../../NativeModules/specs/NativeSourceCode') + .default; + Platform = require('../../Utilities/Platform'); }); it('returns same source for simple static and network images', () => { @@ -303,9 +303,16 @@ describe('resolveAssetSource', () => { ); }); }); + + function expectResolvesAsset(input, expectedSource) { + const assetId = AssetRegistry.registerAsset(input); + expect(resolveAssetSource(assetId)).toEqual(expectedSource); + } }); describe('resolveAssetSource.pickScale', () => { + const resolveAssetSource = require('../resolveAssetSource'); + it('picks matching scale', () => { expect(resolveAssetSource.pickScale([1], 2)).toBe(1); expect(resolveAssetSource.pickScale([1, 2, 3], 2)).toBe(2); diff --git a/jest/setup.js b/jest/setup.js index 38cef7befbf12f..d85849066c2d82 100644 --- a/jest/setup.js +++ b/jest/setup.js @@ -37,6 +37,53 @@ jest.setMock( jest .mock('../Libraries/Core/InitializeCore', () => {}) + .mock('../Libraries/ReactNative/UIManager', () => ({ + AndroidViewPager: { + Commands: { + setPage: jest.fn(), + setPageWithoutAnimation: jest.fn(), + }, + }, + blur: jest.fn(), + createView: jest.fn(), + customBubblingEventTypes: {}, + customDirectEventTypes: {}, + dispatchViewManagerCommand: jest.fn(), + focus: jest.fn(), + getViewManagerConfig: jest.fn(name => { + if (name === 'AndroidDrawerLayout') { + return { + Constants: { + DrawerPosition: { + Left: 10, + }, + }, + }; + } + }), + measure: jest.fn(), + manageChildren: jest.fn(), + removeSubviewsFromContainerWithID: jest.fn(), + replaceExistingNonRootView: jest.fn(), + setChildren: jest.fn(), + updateView: jest.fn(), + AndroidDrawerLayout: { + Constants: { + DrawerPosition: { + Left: 10, + }, + }, + }, + AndroidTextInput: { + Commands: {}, + }, + ScrollView: { + Constants: {}, + }, + View: { + Constants: {}, + }, + })) .mock('../Libraries/Image/Image', () => mockComponent('../Libraries/Image/Image'), ) @@ -52,6 +99,19 @@ jest .mock('../Libraries/Components/View/View', () => mockComponent('../Libraries/Components/View/View', MockNativeMethods), ) + .mock('../Libraries/Components/AccessibilityInfo/AccessibilityInfo', () => ({ + addEventListener: jest.fn(), + announceForAccessibility: jest.fn(), + fetch: jest.fn(), + isBoldTextEnabled: jest.fn(), + isGrayscaleEnabled: jest.fn(), + isInvertColorsEnabled: jest.fn(), + isReduceMotionEnabled: jest.fn(), + isReduceTransparencyEnabled: jest.fn(), + isScreenReaderEnabled: jest.fn(), + removeEventListener: jest.fn(), + setAccessibilityFocus: jest.fn(), + })) .mock('../Libraries/Components/RefreshControl/RefreshControl', () => jest.requireActual( '../Libraries/Components/RefreshControl/__mocks__/RefreshControlMock', @@ -82,6 +142,19 @@ jest }; return AnimatedImplementation; }) + .mock('../Libraries/AppState/AppState', () => ({ + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + })) + .mock('../Libraries/Linking/Linking', () => ({ + openURL: jest.fn(), + canOpenURL: jest.fn(() => Promise.resolve(true)), + openSettings: jest.fn(), + addEventListener: jest.fn(), + getInitialURL: jest.fn(() => Promise.resolve()), + removeEventListener: jest.fn(), + sendIntent: jest.fn(), + })) .mock('../Libraries/Renderer/shims/ReactNative', () => { const ReactNative = jest.requireActual( '../Libraries/Renderer/shims/ReactNative', @@ -97,283 +170,160 @@ jest }) .mock('../Libraries/Components/Touchable/ensureComponentIsNative', () => () => true, - ); - -const mockNativeModules = { - AccessibilityInfo: { - addEventListener: jest.fn(), - announceForAccessibility: jest.fn(), - fetch: jest.fn(), - isBoldTextEnabled: jest.fn(), - isGrayscaleEnabled: jest.fn(), - isInvertColorsEnabled: jest.fn(), - isReduceMotionEnabled: jest.fn(), - isReduceTransparencyEnabled: jest.fn(), - isScreenReaderEnabled: jest.fn(), - removeEventListener: jest.fn(), - setAccessibilityFocus: jest.fn(), - }, - AlertManager: { - alertWithArgs: jest.fn(), - }, - AppState: { - addEventListener: jest.fn(), - removeEventListener: jest.fn(), - }, - AsyncLocalStorage: { - multiGet: jest.fn((keys, callback) => - process.nextTick(() => callback(null, [])), - ), - multiSet: jest.fn((entries, callback) => - process.nextTick(() => callback(null)), - ), - multiRemove: jest.fn((keys, callback) => - process.nextTick(() => callback(null)), - ), - multiMerge: jest.fn((entries, callback) => - process.nextTick(() => callback(null)), - ), - clear: jest.fn(callback => process.nextTick(() => callback(null))), - getAllKeys: jest.fn(callback => process.nextTick(() => callback(null, []))), - }, - BuildInfo: { - appVersion: '0', - buildVersion: '0', - getConstants() { - return { - appVersion: '0', - buildVersion: '0', - }; + ) + // Mock modules defined by the native layer (ex: Objective-C, Java) + .mock('../Libraries/BatchedBridge/NativeModules', () => ({ + AlertManager: { + alertWithArgs: jest.fn(), }, - }, - Clipboard: { - setString: jest.fn(), - }, - DataManager: { - queryData: jest.fn(), - }, - DeviceInfo: { - getConstants() { - return { - Dimensions: { - window: { - fontScale: 2, - height: 1334, - scale: 2, - width: 750, - }, - screen: { - fontScale: 2, - height: 1334, - scale: 2, - width: 750, + AsyncLocalStorage: { + multiGet: jest.fn((keys, callback) => + process.nextTick(() => callback(null, [])), + ), + multiSet: jest.fn((entries, callback) => + process.nextTick(() => callback(null)), + ), + multiRemove: jest.fn((keys, callback) => + process.nextTick(() => callback(null)), + ), + multiMerge: jest.fn((entries, callback) => + process.nextTick(() => callback(null)), + ), + clear: jest.fn(callback => process.nextTick(() => callback(null))), + getAllKeys: jest.fn(callback => + process.nextTick(() => callback(null, [])), + ), + }, + Clipboard: { + getString: jest.fn(() => ''), + setString: jest.fn(), + }, + DeviceInfo: { + getConstants() { + return { + Dimensions: { + window: { + fontScale: 2, + height: 1334, + scale: 2, + width: 750, + }, + screen: { + fontScale: 2, + height: 1334, + scale: 2, + width: 750, + }, }, - }, - }; + }; + }, }, - }, - FacebookSDK: { - login: jest.fn(), - logout: jest.fn(), - queryGraphPath: jest.fn((path, method, params, callback) => callback()), - }, - GraphPhotoUpload: { - upload: jest.fn(), - }, - I18n: { - translationsDictionary: JSON.stringify({ - 'Good bye, {name}!|Bye message': '\u{00A1}Adi\u{00F3}s {name}!', - }), - }, - ImageLoader: { - getSize: jest.fn(url => Promise.resolve({width: 320, height: 240})), - prefetchImage: jest.fn(), - }, - ImageViewManager: { - getSize: jest.fn((uri, success) => - process.nextTick(() => success(320, 240)), - ), - prefetchImage: jest.fn(), - }, - KeyboardObserver: { - addListener: jest.fn(), - removeListeners: jest.fn(), - }, - Linking: { - openURL: jest.fn(), - canOpenURL: jest.fn(() => Promise.resolve(true)), - openSettings: jest.fn(), - addEventListener: jest.fn(), - getInitialURL: jest.fn(() => Promise.resolve()), - removeEventListener: jest.fn(), - sendIntent: jest.fn(), - }, - LocationObserver: { - addListener: jest.fn(), - getCurrentPosition: jest.fn(), - removeListeners: jest.fn(), - requestAuthorization: jest.fn(), - setConfiguration: jest.fn(), - startObserving: jest.fn(), - stopObserving: jest.fn(), - }, - ModalFullscreenViewManager: {}, - NetInfo: { - fetch: jest.fn(() => Promise.resolve()), - getConnectionInfo: jest.fn(() => Promise.resolve()), - addEventListener: jest.fn(), - removeEventListener: jest.fn(), - isConnected: { - fetch: jest.fn(() => Promise.resolve()), - addEventListener: jest.fn(), - removeEventListener: jest.fn(), + ImageLoader: { + getSize: jest.fn(url => Promise.resolve({width: 320, height: 240})), + prefetchImage: jest.fn(), }, - isConnectionExpensive: jest.fn(() => Promise.resolve()), - }, - Networking: { - sendRequest: jest.fn(), - abortRequest: jest.fn(), - addListener: jest.fn(), - removeListeners: jest.fn(), - }, - PlatformConstants: { - getConstants() { - return {}; + ImageViewManager: { + getSize: jest.fn((uri, success) => + process.nextTick(() => success(320, 240)), + ), + prefetchImage: jest.fn(), }, - }, - PushNotificationManager: { - presentLocalNotification: jest.fn(), - scheduleLocalNotification: jest.fn(), - cancelAllLocalNotifications: jest.fn(), - removeAllDeliveredNotifications: jest.fn(), - getDeliveredNotifications: jest.fn(callback => process.nextTick(() => [])), - removeDeliveredNotifications: jest.fn(), - setApplicationIconBadgeNumber: jest.fn(), - getApplicationIconBadgeNumber: jest.fn(callback => - process.nextTick(() => callback(0)), - ), - cancelLocalNotifications: jest.fn(), - getScheduledLocalNotifications: jest.fn(callback => - process.nextTick(() => callback()), - ), - requestPermissions: jest.fn(() => - Promise.resolve({alert: true, badge: true, sound: true}), - ), - abandonPermissions: jest.fn(), - checkPermissions: jest.fn(callback => - process.nextTick(() => callback({alert: true, badge: true, sound: true})), - ), - getInitialNotification: jest.fn(() => Promise.resolve(null)), - addListener: jest.fn(), - removeListeners: jest.fn(), - }, - SourceCode: { - getConstants() { - return { - scriptURL: null, - }; + KeyboardObserver: { + addListener: jest.fn(), + removeListeners: jest.fn(), }, - }, - StatusBarManager: { - HEIGHT: 42, - setColor: jest.fn(), - setStyle: jest.fn(), - setHidden: jest.fn(), - setNetworkActivityIndicatorVisible: jest.fn(), - setBackgroundColor: jest.fn(), - setTranslucent: jest.fn(), - }, - Timing: { - createTimer: jest.fn(), - deleteTimer: jest.fn(), - }, - UIManager: { - AndroidViewPager: { - Commands: { - setPage: jest.fn(), - setPageWithoutAnimation: jest.fn(), + Networking: { + sendRequest: jest.fn(), + abortRequest: jest.fn(), + addListener: jest.fn(), + removeListeners: jest.fn(), + }, + PlatformConstants: { + getConstants() { + return {}; }, }, - blur: jest.fn(), - createView: jest.fn(), - dispatchViewManagerCommand: jest.fn(), - focus: jest.fn(), - getViewManagerConfig: jest.fn(name => { - if (name === 'AndroidDrawerLayout') { + PushNotificationManager: { + presentLocalNotification: jest.fn(), + scheduleLocalNotification: jest.fn(), + cancelAllLocalNotifications: jest.fn(), + removeAllDeliveredNotifications: jest.fn(), + getDeliveredNotifications: jest.fn(callback => + process.nextTick(() => []), + ), + removeDeliveredNotifications: jest.fn(), + setApplicationIconBadgeNumber: jest.fn(), + getApplicationIconBadgeNumber: jest.fn(callback => + process.nextTick(() => callback(0)), + ), + cancelLocalNotifications: jest.fn(), + getScheduledLocalNotifications: jest.fn(callback => + process.nextTick(() => callback()), + ), + requestPermissions: jest.fn(() => + Promise.resolve({alert: true, badge: true, sound: true}), + ), + abandonPermissions: jest.fn(), + checkPermissions: jest.fn(callback => + process.nextTick(() => + callback({alert: true, badge: true, sound: true}), + ), + ), + getInitialNotification: jest.fn(() => Promise.resolve(null)), + addListener: jest.fn(), + removeListeners: jest.fn(), + }, + SourceCode: { + getConstants() { return { - Constants: { - DrawerPosition: { - Left: 10, - }, - }, + scriptURL: null, }; - } - }), - setChildren: jest.fn(), - manageChildren: jest.fn(), - updateView: jest.fn(), - removeSubviewsFromContainerWithID: jest.fn(), - replaceExistingNonRootView: jest.fn(), - customBubblingEventTypes: {}, - customDirectEventTypes: {}, - AndroidTextInput: { - Commands: {}, + }, }, - ModalFullscreenView: { - Constants: {}, + StatusBarManager: { + HEIGHT: 42, + setColor: jest.fn(), + setStyle: jest.fn(), + setHidden: jest.fn(), + setNetworkActivityIndicatorVisible: jest.fn(), + setBackgroundColor: jest.fn(), + setTranslucent: jest.fn(), }, - ScrollView: { - Constants: {}, + Timing: { + createTimer: jest.fn(), + deleteTimer: jest.fn(), }, - View: { - Constants: {}, + UIManager: {}, + BlobModule: { + getConstants: () => ({BLOB_URI_SCHEME: 'content', BLOB_URI_HOST: null}), + addNetworkingHandler: jest.fn(), + enableBlobSupport: jest.fn(), + disableBlobSupport: jest.fn(), + createFromParts: jest.fn(), + sendBlob: jest.fn(), + release: jest.fn(), }, - }, - BlobModule: { - getConstants: () => ({BLOB_URI_SCHEME: 'content', BLOB_URI_HOST: null}), - addNetworkingHandler: jest.fn(), - enableBlobSupport: jest.fn(), - disableBlobSupport: jest.fn(), - createFromParts: jest.fn(), - sendBlob: jest.fn(), - release: jest.fn(), - }, - WebSocketModule: { - connect: jest.fn(), - send: jest.fn(), - sendBinary: jest.fn(), - ping: jest.fn(), - close: jest.fn(), - addListener: jest.fn(), - removeListeners: jest.fn(), - }, -}; - -Object.keys(mockNativeModules).forEach(module => { - try { - jest.doMock(module, () => mockNativeModules[module]); // needed by FacebookSDK-test - } catch (e) { - jest.doMock(module, () => mockNativeModules[module], {virtual: true}); - } -}); - -jest.doMock( - '../Libraries/BatchedBridge/NativeModules', - () => mockNativeModules, -); - -jest.doMock('../Libraries/ReactNative/requireNativeComponent', () => { - const React = require('react'); - - return viewName => - class extends React.Component { - render() { - return React.createElement(viewName, this.props, this.props.children); - } - }; -}); + WebSocketModule: { + connect: jest.fn(), + send: jest.fn(), + sendBinary: jest.fn(), + ping: jest.fn(), + close: jest.fn(), + addListener: jest.fn(), + removeListeners: jest.fn(), + }, + })) + .mock('../Libraries/ReactNative/requireNativeComponent', () => { + const React = require('react'); -jest.doMock( - '../Libraries/Utilities/verifyComponentAttributeEquivalence', - () => function() {}, -); + return viewName => + class extends React.Component { + render() { + return React.createElement(viewName, this.props, this.props.children); + } + }; + }) + .mock( + '../Libraries/Utilities/verifyComponentAttributeEquivalence', + () => function() {}, + ); From a4f7e17a4f06ee713fecbfa1fbb1e632a9d3bf89 Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Fri, 31 May 2019 03:51:56 -0700 Subject: [PATCH 0150/1084] Release underlying resources when JS instance is GC'ed on Android (#24767) Summary: Android followup for #24745. This adds a jsi object that removes blobs when it is gc'ed. We don't have many modules with native code on Android so I've added the native code directly in the blob package as a separate .so. I used a similar structure as the turbomodule package. ## Changelog [Android] [Fixed] - [Blob] Release underlying resources when JS instance is GC'ed on Android Pull Request resolved: https://github.com/facebook/react-native/pull/24767 Differential Revision: D15279651 Pulled By: cpojer fbshipit-source-id: 2bbdc4bbcbeae8945588ac5e3e895c49e6ac9e1a --- RNTester/android/app/BUCK | 1 + ReactAndroid/build.gradle | 1 + .../java/com/facebook/react/modules/blob/BUCK | 2 + .../react/modules/blob/BlobCollector.java | 25 ++++++++ .../react/modules/blob/BlobModule.java | 39 +++++++----- .../react/modules/blob/jni/Android.mk | 21 +++++++ .../com/facebook/react/modules/blob/jni/BUCK | 22 +++++++ .../react/modules/blob/jni/BlobCollector.cpp | 61 +++++++++++++++++++ .../react/modules/blob/jni/BlobCollector.h | 39 ++++++++++++ .../react/modules/blob/jni/OnLoad.cpp | 13 ++++ .../src/main/jni/react/jni/Android.mk | 2 + 11 files changed, 211 insertions(+), 15 deletions(-) create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobCollector.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/Android.mk create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BUCK create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BlobCollector.cpp create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BlobCollector.h create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/OnLoad.cpp diff --git a/RNTester/android/app/BUCK b/RNTester/android/app/BUCK index ceb05c3e109291..5e839d5e9153ca 100644 --- a/RNTester/android/app/BUCK +++ b/RNTester/android/app/BUCK @@ -25,6 +25,7 @@ rn_android_library( react_native_target("java/com/facebook/react:react"), react_native_target("java/com/facebook/react/common:build_config"), react_native_target("java/com/facebook/react/modules/core:core"), + react_native_target("java/com/facebook/react/views/text:text"), react_native_target("java/com/facebook/react/shell:shell"), react_native_target("jni/prebuilt:android-jsc"), # .so files are prebuilt by Gradle with `./gradlew :ReactAndroid:packageReactNdkLibsForBuck` diff --git a/ReactAndroid/build.gradle b/ReactAndroid/build.gradle index 6e44769892cbbc..84207fb50578dc 100644 --- a/ReactAndroid/build.gradle +++ b/ReactAndroid/build.gradle @@ -222,6 +222,7 @@ def getNdkBuildFullPath() { task buildReactNdkLib(dependsOn: [prepareJSC, prepareBoost, prepareDoubleConversion, prepareFolly, prepareGlog], type: Exec) { inputs.dir("$projectDir/../ReactCommon") inputs.dir("src/main/jni") + inputs.dir("src/main/java/com/facebook/react/modules/blob") outputs.dir("$buildDir/react-ndk/all") commandLine(getNdkBuildFullPath(), "NDK_PROJECT_PATH=null", diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK index ac8fbcbc9f87ec..72c927348f08e4 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK @@ -16,6 +16,7 @@ rn_android_library( ], deps = [ react_native_dep("libraries/fbcore/src/main/java/com/facebook/common/logging:logging"), + react_native_dep("libraries/soloader/java/com/facebook/soloader:soloader"), react_native_dep("third-party/java/infer-annotations:infer-annotations"), react_native_dep("third-party/java/jsr-305:jsr-305"), react_native_dep("third-party/java/okhttp:okhttp3"), @@ -24,6 +25,7 @@ rn_android_library( react_native_target("java/com/facebook/react/bridge:bridge"), react_native_target("java/com/facebook/react/common:common"), react_native_target("java/com/facebook/react/module/annotations:annotations"), + react_native_target("java/com/facebook/react/modules/blob/jni:jni"), react_native_target("java/com/facebook/react/modules/network:network"), react_native_target("java/com/facebook/react/modules/websocket:websocket"), ], diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobCollector.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobCollector.java new file mode 100644 index 00000000000000..715f3dd38f6300 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobCollector.java @@ -0,0 +1,25 @@ +package com.facebook.react.modules.blob; + +import com.facebook.react.bridge.JavaScriptContextHolder; +import com.facebook.react.bridge.ReactContext; +import com.facebook.soloader.SoLoader; + +/* package */ class BlobCollector { + static { + SoLoader.loadLibrary("reactnativeblob"); + } + + static void install(final ReactContext reactContext, final BlobModule blobModule) { + reactContext.runOnJSQueueThread(new Runnable() { + @Override + public void run() { + JavaScriptContextHolder jsContext = reactContext.getJavaScriptContextHolder(); + synchronized (jsContext) { + nativeInstall(blobModule, jsContext.get()); + } + } + }); + } + + private native static void nativeInstall(Object blobModule, long jsContext); +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java index 830180c6ffc308..7bb5f281e49118 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java @@ -6,13 +6,10 @@ */ package com.facebook.react.modules.blob; -import android.content.ContentResolver; -import android.content.Context; import android.content.res.Resources; import android.database.Cursor; import android.net.Uri; import android.provider.MediaStore; -import androidx.annotation.Nullable; import android.webkit.MimeTypeMap; import com.facebook.react.bridge.Arguments; @@ -40,6 +37,7 @@ import java.util.Map; import java.util.UUID; +import androidx.annotation.Nullable; import okhttp3.MediaType; import okhttp3.RequestBody; import okhttp3.ResponseBody; @@ -151,6 +149,11 @@ public BlobModule(ReactApplicationContext reactContext) { super(reactContext); } + @Override + public void initialize() { + BlobCollector.install(getReactApplicationContext(), this); + } + @Override public String getName() { return NAME; @@ -178,11 +181,15 @@ public String store(byte[] data) { } public void store(byte[] data, String blobId) { - mBlobs.put(blobId, data); + synchronized (mBlobs) { + mBlobs.put(blobId, data); + } } public void remove(String blobId) { - mBlobs.remove(blobId); + synchronized (mBlobs) { + mBlobs.remove(blobId); + } } public @Nullable byte[] resolve(Uri uri) { @@ -201,17 +208,19 @@ public void remove(String blobId) { } public @Nullable byte[] resolve(String blobId, int offset, int size) { - byte[] data = mBlobs.get(blobId); - if (data == null) { - return null; - } - if (size == -1) { - size = data.length - offset; - } - if (offset > 0 || size != data.length) { - data = Arrays.copyOfRange(data, offset, offset + size); + synchronized (mBlobs) { + byte[] data = mBlobs.get(blobId); + if (data == null) { + return null; + } + if (size == -1) { + size = data.length - offset; + } + if (offset > 0 || size != data.length) { + data = Arrays.copyOfRange(data, offset, offset + size); + } + return data; } - return data; } public @Nullable byte[] resolve(ReadableMap blob) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/Android.mk b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/Android.mk new file mode 100644 index 00000000000000..b0ef370c574413 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/Android.mk @@ -0,0 +1,21 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := reactnativeblob + +LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp) + +LOCAL_C_INCLUDES := $(LOCAL_PATH) + +LOCAL_CFLAGS += -fvisibility=hidden -fexceptions -frtti + +LOCAL_STATIC_LIBRARIES := libjsi libjsireact jscruntime +LOCAL_SHARED_LIBRARIES := libfolly_json libfb libreactnativejni + +include $(BUILD_SHARED_LIBRARY) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BUCK new file mode 100644 index 00000000000000..c02646779b63f8 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BUCK @@ -0,0 +1,22 @@ +load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "FBJNI_TARGET", "react_native_target", "react_native_xplat_target", "rn_xplat_cxx_library") + +rn_xplat_cxx_library( + name = "jni", + srcs = glob(["*.cpp"]), + headers = glob(["*.h"]), + header_namespace = "", + compiler_flags = ["-fexceptions"], + fbandroid_allow_jni_merging = True, + platforms = ANDROID, + soname = "libreactnativeblob.$(ext)", + visibility = [ + "PUBLIC", + ], + deps = [ + "fbsource//xplat/folly:molly", + FBJNI_TARGET, + react_native_target("jni/react/jni:jni"), + react_native_xplat_target("jsi:JSCRuntime"), + react_native_xplat_target("jsiexecutor:jsiexecutor"), + ], +) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BlobCollector.cpp b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BlobCollector.cpp new file mode 100644 index 00000000000000..d14d3885253b9d --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BlobCollector.cpp @@ -0,0 +1,61 @@ +// Copyright 2004-present Facebook. All Rights Reserved. +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + +#include "BlobCollector.h" + +#include +#include +#include + +using namespace facebook; + +namespace facebook { +namespace react { + +static constexpr auto kBlobModuleJavaDescriptor = + "com/facebook/react/modules/blob/BlobModule"; + +BlobCollector::BlobCollector( + jni::global_ref blobModule, + const std::string &blobId) + : blobModule_(blobModule), blobId_(blobId) {} + +BlobCollector::~BlobCollector() { + auto removeMethod = jni::findClassStatic(kBlobModuleJavaDescriptor) + ->getMethod("remove"); + removeMethod(blobModule_, jni::make_jstring(blobId_).get()); +} + +void BlobCollector::nativeInstall( + jni::alias_ref jThis, + jni::alias_ref blobModule, + jlong jsContextNativePointer) { + auto &runtime = *((jsi::Runtime *)jsContextNativePointer); + auto blobModuleRef = jni::make_global(blobModule); + runtime.global().setProperty( + runtime, + "__blobCollectorProvider", + jsi::Function::createFromHostFunction( + runtime, + jsi::PropNameID::forAscii(runtime, "__blobCollectorProvider"), + 1, + [blobModuleRef]( + jsi::Runtime &rt, + const jsi::Value &thisVal, + const jsi::Value *args, + size_t count) { + auto blobId = args[0].asString(rt).utf8(rt); + auto blobCollector = + std::make_shared(blobModuleRef, blobId); + return jsi::Object::createFromHostObject(rt, blobCollector); + })); +} + +void BlobCollector::registerNatives() { + registerHybrid( + {makeNativeMethod("nativeInstall", BlobCollector::nativeInstall)}); +} + +} // namespace react +} // namespace facebook diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BlobCollector.h b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BlobCollector.h new file mode 100644 index 00000000000000..b013cf8bf665c7 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BlobCollector.h @@ -0,0 +1,39 @@ +// Copyright 2004-present Facebook. All Rights Reserved. +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + +#pragma once + +#include +#include + +namespace facebook { +namespace react { + +class BlobCollector : public jni::HybridClass, + public jsi::HostObject { + public: + BlobCollector( + jni::global_ref blobManager, + const std::string &blobId); + ~BlobCollector(); + + static constexpr auto kJavaDescriptor = + "Lcom/facebook/react/modules/blob/BlobCollector;"; + + static void nativeInstall( + jni::alias_ref jThis, + jni::alias_ref blobModule, + jlong jsContextNativePointer); + + static void registerNatives(); + + private: + friend HybridBase; + + jni::global_ref blobModule_; + const std::string blobId_; +}; + +} // namespace react +} // namespace facebook diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/OnLoad.cpp b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/OnLoad.cpp new file mode 100644 index 00000000000000..3707d02665e44a --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/OnLoad.cpp @@ -0,0 +1,13 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + +#include + +#include "BlobCollector.h" + +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { + return facebook::jni::initialize( + vm, [] { facebook::react::BlobCollector::registerNatives(); }); +} diff --git a/ReactAndroid/src/main/jni/react/jni/Android.mk b/ReactAndroid/src/main/jni/react/jni/Android.mk index 7d410f44c1078b..1cf03a78a5ea19 100644 --- a/ReactAndroid/src/main/jni/react/jni/Android.mk +++ b/ReactAndroid/src/main/jni/react/jni/Android.mk @@ -68,3 +68,5 @@ include $(REACT_SRC_DIR)/turbomodule/core/jni/Android.mk # $(call import-module,jscexecutor) include $(REACT_SRC_DIR)/jscexecutor/Android.mk + +include $(REACT_SRC_DIR)/modules/blob/jni/Android.mk From f6e1c164c2021fdaa8a8b0659dd341343594bd61 Mon Sep 17 00:00:00 2001 From: Petr Nikolaev Date: Fri, 31 May 2019 06:32:39 -0700 Subject: [PATCH 0151/1084] Revert D15572716: [RN] TM Spec: relax PermissionsAndroid enforcement Differential Revision: D15572716 Original commit changeset: 4a2edea608ab fbshipit-source-id: cb5ce87685dca9362d0c3df6f874d1a5470b05ac --- .../NativePermissionsAndroid.js | 2 +- .../PermissionsAndroid/PermissionsAndroid.js | 24 +------------------ 2 files changed, 2 insertions(+), 24 deletions(-) diff --git a/Libraries/PermissionsAndroid/NativePermissionsAndroid.js b/Libraries/PermissionsAndroid/NativePermissionsAndroid.js index 4212164d8baf83..025f9af18419b1 100644 --- a/Libraries/PermissionsAndroid/NativePermissionsAndroid.js +++ b/Libraries/PermissionsAndroid/NativePermissionsAndroid.js @@ -56,4 +56,4 @@ export interface Spec extends TurboModule { ) => Promise<{[permission: PermissionType]: PermissionStatus}>; } -export default TurboModuleRegistry.get('PermissionsAndroid'); +export default TurboModuleRegistry.getEnforcing('PermissionsAndroid'); diff --git a/Libraries/PermissionsAndroid/PermissionsAndroid.js b/Libraries/PermissionsAndroid/PermissionsAndroid.js index 427fb21c8a1f88..1b414e71165a29 100644 --- a/Libraries/PermissionsAndroid/PermissionsAndroid.js +++ b/Libraries/PermissionsAndroid/PermissionsAndroid.js @@ -11,11 +11,10 @@ 'use strict'; import NativeDialogManagerAndroid from '../NativeModules/specs/NativeDialogManagerAndroid'; +const NativeModules = require('../BatchedBridge/NativeModules'); const Platform = require('../Utilities/Platform'); import NativePermissionsAndroid from './NativePermissionsAndroid'; -import invariant from 'invariant'; - import type { PermissionStatus, PermissionType, @@ -91,11 +90,6 @@ class PermissionsAndroid { return Promise.resolve(false); } - invariant( - NativePermissionsAndroid, - 'PermissionsAndroid is not installed correctly.', - ); - return NativePermissionsAndroid.checkPermission(permission); } @@ -112,12 +106,6 @@ class PermissionsAndroid { ); return Promise.resolve(false); } - - invariant( - NativePermissionsAndroid, - 'PermissionsAndroid is not installed correctly.', - ); - return NativePermissionsAndroid.checkPermission(permission); } @@ -170,11 +158,6 @@ class PermissionsAndroid { return Promise.resolve(this.RESULTS.DENIED); } - invariant( - NativePermissionsAndroid, - 'PermissionsAndroid is not installed correctly.', - ); - if (rationale) { const shouldShowRationale = await NativePermissionsAndroid.shouldShowRequestPermissionRationale( permission, @@ -214,11 +197,6 @@ class PermissionsAndroid { return Promise.resolve({}); } - invariant( - NativePermissionsAndroid, - 'PermissionsAndroid is not installed correctly.', - ); - return NativePermissionsAndroid.requestMultiplePermissions(permissions); } } From a944ebd7da505cab8e5e1059d1844415e36ba434 Mon Sep 17 00:00:00 2001 From: Petr Nikolaev Date: Fri, 31 May 2019 06:32:39 -0700 Subject: [PATCH 0152/1084] Revert D15558093: [react-native][PR] [TM] Add spec for DevSettings Differential Revision: D15558093 Original commit changeset: 3adcb640a6ad fbshipit-source-id: 70b4842f5cdef878b18786c6a13e76694ffb1581 --- .../NativeModules/specs/NativeDevSettings.js | 28 ------------------- 1 file changed, 28 deletions(-) delete mode 100644 Libraries/NativeModules/specs/NativeDevSettings.js diff --git a/Libraries/NativeModules/specs/NativeDevSettings.js b/Libraries/NativeModules/specs/NativeDevSettings.js deleted file mode 100644 index 9a53a0db7905e0..00000000000000 --- a/Libraries/NativeModules/specs/NativeDevSettings.js +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow strict-local - * @format - */ - -'use strict'; - -import type {TurboModule} from '../../TurboModule/RCTExport'; -import * as TurboModuleRegistry from '../../TurboModule/TurboModuleRegistry'; - -export interface Spec extends TurboModule { - +reload: () => void; - +setHotLoadingEnabled: (isHotLoadingEnabled: boolean) => void; - +setIsDebuggingRemotely: (isDebuggingRemotelyEnabled: boolean) => void; - +setLiveReloadEnabled: (isLiveReloadEnabled: boolean) => void; - +setProfilingEnabled: (isProfilingEnabled: boolean) => void; - +toggleElementInspector: () => void; - - // iOS only. - +setIsShakeToShowDevMenuEnabled: (enabled: boolean) => void; -} - -export default TurboModuleRegistry.getEnforcing('DevSettings'); From b0254e8d3cedac28cb58846af1a7ebc2e4a10575 Mon Sep 17 00:00:00 2001 From: Petr Nikolaev Date: Fri, 31 May 2019 06:32:39 -0700 Subject: [PATCH 0153/1084] Revert D15551356: [react-native][PR] [TM] Add spec for UIManager Differential Revision: D15551356 Original commit changeset: 076c4ce635aa fbshipit-source-id: dff59dc9c98bc579851091855611ee5d973931d0 --- .../AccessibilityInfo.android.js | 2 +- Libraries/ReactNative/NativeUIManager.js | 122 ---------------- Libraries/ReactNative/UIManager.js | 131 +++++++----------- Libraries/ReactNative/UIManagerStatTracker.js | 4 +- .../getNativeComponentAttributes.js | 7 +- 5 files changed, 53 insertions(+), 213 deletions(-) delete mode 100644 Libraries/ReactNative/NativeUIManager.js diff --git a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js index 5c9ab848d2ecff..ff9a7329a56c87 100644 --- a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js +++ b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js @@ -139,7 +139,7 @@ const AccessibilityInfo = { setAccessibilityFocus: function(reactTag: number): void { UIManager.sendAccessibilityEvent( reactTag, - UIManager.getConstants().AccessibilityEventTypes.typeViewFocused, + UIManager.AccessibilityEventTypes.typeViewFocused, ); }, diff --git a/Libraries/ReactNative/NativeUIManager.js b/Libraries/ReactNative/NativeUIManager.js deleted file mode 100644 index 9eb60e68194b81..00000000000000 --- a/Libraries/ReactNative/NativeUIManager.js +++ /dev/null @@ -1,122 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - * @format - */ - -'use strict'; - -import type {TurboModule} from '../TurboModule/RCTExport'; -import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; - -export interface Spec extends TurboModule { - +getConstants: () => Object; - +getConstantsForViewManager: (viewManagerName: string) => Object; - +getDefaultEventTypes: () => Array; - +playTouchSound: () => void; - +lazilyLoadView: (name: string) => Object; // revisit return - +createView: ( - reactTag: ?number, - viewName: string, - rootTag: number, - props: Object, - ) => void; - +updateView: (reactTag: number, viewName: string, props: Object) => void; - +focus: (reactTag: ?number) => void; - +blur: (reactTag: ?number) => void; - +findSubviewIn: ( - reactTag: ?number, - point: [number, number], - callback: ( - nativeViewTag: number, - left: number, - top: number, - width: number, - height: number, - ) => void, - ) => void; - +dispatchViewManagerCommand: ( - reactTag: ?number, - commandID: number, - commandArgs: ?Array, // is this best? - ) => void; - +measure: ( - reactTag: ?number, - callback: ( - left: number, - top: number, - width: number, - height: number, - pageX: number, - pageY: number, - ) => void, - ) => void; - +measureInWindow: ( - reactTag: ?number, - callback: (x: number, y: number, width: number, height: number) => void, - ) => void; - +viewIsDescendantOf: ( - reactTag: ?number, - ancestorReactTag: ?number, - callback: (result: Array) => void, - ) => void; - +measureLayout: ( - reactTag: ?number, - ancestorReactTag: ?number, - errorCallback: (error: Object) => void, - callback: ( - left: number, - top: number, - width: number, - height: number, - ) => void, - ) => void; - +measureLayoutRelativeToParent: ( - reactTag: ?number, - errorCallback: (error: Object) => void, - callback: ( - left: number, - top: number, - width: number, - height: number, - ) => void, - ) => void; - +setJSResponder: (reactTag: ?number, blockNativeResponder: boolean) => void; - +clearJSResponder: () => void; - +configureNextLayoutAnimation: ( - config: Object, - callback: () => void, // check what is returned here - errorCallback: (error: Object) => void, - ) => void; - +removeSubviewsFromContainerWithID: (containerID: number) => void; - +replaceExistingNonRootView: ( - reactTag: ?number, - newReactTag: ?number, - ) => void; - +setChildren: (containerTag: ?number, reactTags: Array) => void; - +manageChildren: ( - containerTag: ?number, - moveFromIndices: Array, - moveToIndices: Array, - addChildReactTags: Array, - addAtIndices: Array, - removeAtIndices: Array, - ) => void; - - // Android only - +setLayoutAnimationEnabledExperimental: (enabled: boolean) => void; - +sendAccessibilityEvent: (reactTag: ?number, eventType: number) => void; - +showPopupMenu: ( - reactTag: ?number, - items: Array, - error: (error: Object) => void, - success: (event: string, selected?: number) => void, - ) => void; - +dismissPopupMenu: () => void; -} - -export default TurboModuleRegistry.getEnforcing('UIManager'); diff --git a/Libraries/ReactNative/UIManager.js b/Libraries/ReactNative/UIManager.js index 234732bfe1db2c..cf7f8edbdbb839 100644 --- a/Libraries/ReactNative/UIManager.js +++ b/Libraries/ReactNative/UIManager.js @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @flow + * @flow strict-local * @format */ 'use strict'; @@ -14,94 +14,58 @@ const Platform = require('../Utilities/Platform'); const UIManagerProperties = require('./UIManagerProperties'); const defineLazyObjectProperty = require('../Utilities/defineLazyObjectProperty'); +const invariant = require('invariant'); -import NativeUIManager from './NativeUIManager'; -import type {Spec} from './NativeUIManager'; - +const {UIManager} = NativeModules; const viewManagerConfigs = {}; -interface UIManagerJSInterface extends Spec { - +getViewManagerConfig: (viewManagerName: string) => Object; - // The following are not marked read-only due to logic in UIManagerStatTracker. - createView: ( - reactTag: ?number, - viewName: string, - rootTag: number, - props: Object, - ) => void; - updateView: (reactTag: number, viewName: string, props: Object) => void; - manageChildren: ( - containerTag: ?number, - moveFromIndices: Array, - moveToIndices: Array, - addChildReactTags: Array, - addAtIndices: Array, - removeAtIndices: Array, - ) => void; -} +invariant( + UIManager, + 'UIManager is undefined. The native module config is probably incorrect.', +); const triedLoadingConfig = new Set(); - -let NativeUIManagerConstants = {}; -let isNativeUIManagerConstantsSet = false; -function getConstants(): Object { - if (!isNativeUIManagerConstantsSet) { - NativeUIManagerConstants = NativeUIManager.getConstants(); - isNativeUIManagerConstantsSet = true; +UIManager.getViewManagerConfig = function(viewManagerName: string) { + if ( + viewManagerConfigs[viewManagerName] === undefined && + UIManager.getConstantsForViewManager + ) { + try { + viewManagerConfigs[ + viewManagerName + ] = UIManager.getConstantsForViewManager(viewManagerName); + } catch (e) { + viewManagerConfigs[viewManagerName] = null; + } } - return NativeUIManagerConstants; -} -const UIManagerJS: UIManagerJSInterface = { - ...NativeUIManager, - getConstants(): Object { - return getConstants(); - }, - getViewManagerConfig: function(viewManagerName: string) { - if ( - viewManagerConfigs[viewManagerName] === undefined && - NativeUIManager.getConstantsForViewManager - ) { - try { - viewManagerConfigs[ - viewManagerName - ] = NativeUIManager.getConstantsForViewManager(viewManagerName); - } catch (e) { - viewManagerConfigs[viewManagerName] = null; - } - } + const config = viewManagerConfigs[viewManagerName]; + if (config) { + return config; + } - const config = viewManagerConfigs[viewManagerName]; - if (config) { + // If we're in the Chrome Debugger, let's not even try calling the sync + // method. + if (__DEV__) { + if (!global.nativeCallSyncHook) { return config; } + } - // If we're in the Chrome Debugger, let's not even try calling the sync - // method. - if (__DEV__) { - if (!global.nativeCallSyncHook) { - return config; - } - } - - if ( - NativeUIManager.lazilyLoadView && - !triedLoadingConfig.has(viewManagerName) - ) { - const result = NativeUIManager.lazilyLoadView(viewManagerName); - triedLoadingConfig.add(viewManagerName); - if (result.viewConfig) { - getConstants()[viewManagerName] = result.viewConfig; - lazifyViewManagerConfig(viewManagerName); - } + if (UIManager.lazilyLoadView && !triedLoadingConfig.has(viewManagerName)) { + const result = UIManager.lazilyLoadView(viewManagerName); + triedLoadingConfig.add(viewManagerName); + if (result.viewConfig) { + UIManager[viewManagerName] = result.viewConfig; + lazifyViewManagerConfig(viewManagerName); } + } - return viewManagerConfigs[viewManagerName]; - }, + return viewManagerConfigs[viewManagerName]; }; function lazifyViewManagerConfig(viewName) { - const viewConfig = getConstants()[viewName]; + const viewConfig = UIManager[viewName]; if (viewConfig.Manager) { viewManagerConfigs[viewName] = viewConfig; defineLazyObjectProperty(viewConfig, 'Constants', { @@ -142,10 +106,10 @@ function lazifyViewManagerConfig(viewName) { * namespace instead of UIManager, unlike Android. */ if (Platform.OS === 'ios') { - Object.keys(getConstants()).forEach(viewName => { + Object.keys(UIManager).forEach(viewName => { lazifyViewManagerConfig(viewName); }); -} else if (getConstants().ViewManagerNames) { +} else if (UIManager.ViewManagerNames) { // We want to add all the view managers to the UIManager. // However, the way things are set up, the list of view managers is not known at compile time. // As Prepack runs at compile it, it cannot process this loop. @@ -156,13 +120,13 @@ if (Platform.OS === 'ios') { residual( 'void', (UIManager, defineLazyObjectProperty) => { - UIManager.getConstants().ViewManagerNames.forEach(viewManagerName => { + UIManager.ViewManagerNames.forEach(viewManagerName => { defineLazyObjectProperty(UIManager, viewManagerName, { get: () => UIManager.getConstantsForViewManager(viewManagerName), }); }); }, - NativeUIManager, + UIManager, defineLazyObjectProperty, ); @@ -171,28 +135,27 @@ if (Platform.OS === 'ios') { // so that any accesses to unknown properties along the global code will fail // when Prepack encounters them. if (global.__makePartial) { - global.__makePartial(NativeUIManager); + global.__makePartial(UIManager); } } if (__DEV__) { - Object.keys(getConstants()).forEach(viewManagerName => { + Object.keys(UIManager).forEach(viewManagerName => { if (!UIManagerProperties.includes(viewManagerName)) { if (!viewManagerConfigs[viewManagerName]) { - viewManagerConfigs[viewManagerName] = getConstants()[viewManagerName]; + viewManagerConfigs[viewManagerName] = UIManager[viewManagerName]; } - defineLazyObjectProperty(NativeUIManager, viewManagerName, { + defineLazyObjectProperty(UIManager, viewManagerName, { get: () => { console.warn( `Accessing view manager configs directly off UIManager via UIManager['${viewManagerName}'] ` + `is no longer supported. Use UIManager.getViewManagerConfig('${viewManagerName}') instead.`, ); - - return UIManagerJS.getViewManagerConfig(viewManagerName); + return UIManager.getViewManagerConfig(viewManagerName); }, }); } }); } -module.exports = UIManagerJS; +module.exports = UIManager; diff --git a/Libraries/ReactNative/UIManagerStatTracker.js b/Libraries/ReactNative/UIManagerStatTracker.js index 85aaa6ba7707a7..ec1494c53b4390 100644 --- a/Libraries/ReactNative/UIManagerStatTracker.js +++ b/Libraries/ReactNative/UIManagerStatTracker.js @@ -52,8 +52,8 @@ const UIManagerStatTracker = { remove, ) { incStat('manageChildren', 1); - incStat('move', moveFrom.length); - incStat('remove', remove.length); + incStat('move', Object.keys(moveFrom || []).length); + incStat('remove', Object.keys(remove || []).length); manageChildrenOrig(tag, moveFrom, moveTo, addTags, addIndices, remove); }; }, diff --git a/Libraries/ReactNative/getNativeComponentAttributes.js b/Libraries/ReactNative/getNativeComponentAttributes.js index 85a347bea1f358..bf08c389eb8753 100644 --- a/Libraries/ReactNative/getNativeComponentAttributes.js +++ b/Libraries/ReactNative/getNativeComponentAttributes.js @@ -96,18 +96,17 @@ function attachDefaultEventTypes(viewConfig: any) { // This is supported on UIManager platforms (ex: Android), // as lazy view managers are not implemented for all platforms. // See [UIManager] for details on constants and implementations. - const constants = UIManager.getConstants(); - if (constants.ViewManagerNames || constants.LazyViewManagersEnabled) { + if (UIManager.ViewManagerNames || UIManager.LazyViewManagersEnabled) { // Lazy view managers enabled. viewConfig = merge(viewConfig, UIManager.getDefaultEventTypes()); } else { viewConfig.bubblingEventTypes = merge( viewConfig.bubblingEventTypes, - constants.genericBubblingEventTypes, + UIManager.genericBubblingEventTypes, ); viewConfig.directEventTypes = merge( viewConfig.directEventTypes, - constants.genericDirectEventTypes, + UIManager.genericDirectEventTypes, ); } } From db7e00250c98f0d7b7b9fae5241d0ba08701e6a7 Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Fri, 31 May 2019 10:53:03 -0700 Subject: [PATCH 0154/1084] Reland "[react-native][PR] [TM] Add spec for DevSettings" Summary: Original commit changeset: 70b4842f5cde Reviewed By: cpojer Differential Revision: D15578852 fbshipit-source-id: 6389a6f5ed2115182d88dcc777e6457c376750f6 --- .../NativeModules/specs/NativeDevSettings.js | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 Libraries/NativeModules/specs/NativeDevSettings.js diff --git a/Libraries/NativeModules/specs/NativeDevSettings.js b/Libraries/NativeModules/specs/NativeDevSettings.js new file mode 100644 index 00000000000000..9a53a0db7905e0 --- /dev/null +++ b/Libraries/NativeModules/specs/NativeDevSettings.js @@ -0,0 +1,28 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +'use strict'; + +import type {TurboModule} from '../../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../../TurboModule/TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +reload: () => void; + +setHotLoadingEnabled: (isHotLoadingEnabled: boolean) => void; + +setIsDebuggingRemotely: (isDebuggingRemotelyEnabled: boolean) => void; + +setLiveReloadEnabled: (isLiveReloadEnabled: boolean) => void; + +setProfilingEnabled: (isProfilingEnabled: boolean) => void; + +toggleElementInspector: () => void; + + // iOS only. + +setIsShakeToShowDevMenuEnabled: (enabled: boolean) => void; +} + +export default TurboModuleRegistry.getEnforcing('DevSettings'); From 3b65d2c2c8ce92693abc92bd0b3ff8342ab80f3c Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Fri, 31 May 2019 10:53:03 -0700 Subject: [PATCH 0155/1084] Reland "[RN] TM Spec: relax PermissionsAndroid enforcement" Summary: Original commit changeset: cb5ce87685dc Reviewed By: cpojer Differential Revision: D15578851 fbshipit-source-id: ab8cb9a14f94bbf4e850d9af91133612060e1401 --- .../NativePermissionsAndroid.js | 2 +- .../PermissionsAndroid/PermissionsAndroid.js | 24 ++++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/Libraries/PermissionsAndroid/NativePermissionsAndroid.js b/Libraries/PermissionsAndroid/NativePermissionsAndroid.js index 025f9af18419b1..4212164d8baf83 100644 --- a/Libraries/PermissionsAndroid/NativePermissionsAndroid.js +++ b/Libraries/PermissionsAndroid/NativePermissionsAndroid.js @@ -56,4 +56,4 @@ export interface Spec extends TurboModule { ) => Promise<{[permission: PermissionType]: PermissionStatus}>; } -export default TurboModuleRegistry.getEnforcing('PermissionsAndroid'); +export default TurboModuleRegistry.get('PermissionsAndroid'); diff --git a/Libraries/PermissionsAndroid/PermissionsAndroid.js b/Libraries/PermissionsAndroid/PermissionsAndroid.js index 1b414e71165a29..427fb21c8a1f88 100644 --- a/Libraries/PermissionsAndroid/PermissionsAndroid.js +++ b/Libraries/PermissionsAndroid/PermissionsAndroid.js @@ -11,10 +11,11 @@ 'use strict'; import NativeDialogManagerAndroid from '../NativeModules/specs/NativeDialogManagerAndroid'; -const NativeModules = require('../BatchedBridge/NativeModules'); const Platform = require('../Utilities/Platform'); import NativePermissionsAndroid from './NativePermissionsAndroid'; +import invariant from 'invariant'; + import type { PermissionStatus, PermissionType, @@ -90,6 +91,11 @@ class PermissionsAndroid { return Promise.resolve(false); } + invariant( + NativePermissionsAndroid, + 'PermissionsAndroid is not installed correctly.', + ); + return NativePermissionsAndroid.checkPermission(permission); } @@ -106,6 +112,12 @@ class PermissionsAndroid { ); return Promise.resolve(false); } + + invariant( + NativePermissionsAndroid, + 'PermissionsAndroid is not installed correctly.', + ); + return NativePermissionsAndroid.checkPermission(permission); } @@ -158,6 +170,11 @@ class PermissionsAndroid { return Promise.resolve(this.RESULTS.DENIED); } + invariant( + NativePermissionsAndroid, + 'PermissionsAndroid is not installed correctly.', + ); + if (rationale) { const shouldShowRationale = await NativePermissionsAndroid.shouldShowRequestPermissionRationale( permission, @@ -197,6 +214,11 @@ class PermissionsAndroid { return Promise.resolve({}); } + invariant( + NativePermissionsAndroid, + 'PermissionsAndroid is not installed correctly.', + ); + return NativePermissionsAndroid.requestMultiplePermissions(permissions); } } From dc0106e4f4ace66e54673a3550432a519d582fcf Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Fri, 31 May 2019 11:08:38 -0700 Subject: [PATCH 0156/1084] Do not send log messages to Metro when `Platform.isTesting` is set Summary: Ideally this should fix `//Libraries/FBReactKit:HiPriServerSnapshotTestsFacebookRedbox`. Reviewed By: PeteTheHeat Differential Revision: D15578792 fbshipit-source-id: 83dd227122170721c0f33c54e0f0e23e810569ae --- Libraries/Core/setUpDeveloperTools.js | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/Libraries/Core/setUpDeveloperTools.js b/Libraries/Core/setUpDeveloperTools.js index da9aa45c50e457..43213cb94bb78d 100644 --- a/Libraries/Core/setUpDeveloperTools.js +++ b/Libraries/Core/setUpDeveloperTools.js @@ -9,6 +9,8 @@ */ 'use strict'; +import Platform from '../Utilities/Platform'; + /** * Sets up developer tools for React Native. * You can use this module directly, or just require InitializeCore. @@ -26,13 +28,15 @@ if (__DEV__) { JSInspector.registerAgent(require('../JSInspector/NetworkAgent')); } - const logToConsole = require('./Devtools/logToConsole'); - ['log', 'warn', 'info', 'trace'].forEach(level => { - const originalFunction = console[level]; - // $FlowFixMe Overwrite console methods - console[level] = function(...args) { - logToConsole(level, args); - originalFunction.apply(console, args); - }; - }); + if (!Platform.isTesting) { + const logToConsole = require('./Devtools/logToConsole'); + ['log', 'warn', 'info', 'trace'].forEach(level => { + const originalFunction = console[level]; + // $FlowFixMe Overwrite console methods + console[level] = function(...args) { + logToConsole(level, args); + originalFunction.apply(console, args); + }; + }); + } } From 62c605efe1a23923292f8ec4740bba8349cbcca2 Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Fri, 31 May 2019 12:13:01 -0700 Subject: [PATCH 0157/1084] Use relative requires for most modules in react-native-implementation Summary: This continues the migration off of haste for react-native-github by changing `react-native-implementation` not to use haste. Reviewed By: JoshuaGross Differential Revision: D15575896 fbshipit-source-id: 0de7314b7d038a6d603d09ca910f84d580c5cc33 --- .../react-native-implementation.js | 178 +++++++++--------- 1 file changed, 88 insertions(+), 90 deletions(-) diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js index 8e0a72c5ce0858..af54b7a6dfe017 100644 --- a/Libraries/react-native/react-native-implementation.js +++ b/Libraries/react-native/react-native-implementation.js @@ -10,8 +10,6 @@ 'use strict'; -/* eslint-disable @react-native-community/no-haste-imports */ - const invariant = require('invariant'); const warnOnce = require('../Utilities/warnOnce'); @@ -19,16 +17,16 @@ const warnOnce = require('../Utilities/warnOnce'); module.exports = { // Components get AccessibilityInfo() { - return require('AccessibilityInfo'); + return require('../Components/AccessibilityInfo/AccessibilityInfo'); }, get ActivityIndicator() { - return require('ActivityIndicator'); + return require('../Components/ActivityIndicator/ActivityIndicator'); }, get ART() { - return require('ReactNativeART'); + return require('../ART/ReactNativeART'); }, get Button() { - return require('Button'); + return require('../Components/Button'); }, get CheckBox() { warnOnce( @@ -37,22 +35,22 @@ module.exports = { "It can now be installed and imported from '@react-native-community/checkbox' instead of 'react-native'. " + 'See https://github.com/react-native-community/react-native-checkbox', ); - return require('CheckBox'); + return require('../Components/CheckBox/CheckBox'); }, get DatePickerIOS() { - return require('DatePickerIOS'); + return require('../Components/DatePicker/DatePickerIOS'); }, get DrawerLayoutAndroid() { - return require('DrawerLayoutAndroid'); + return require('../Components/DrawerAndroid/DrawerLayoutAndroid'); }, get FlatList() { - return require('FlatList'); + return require('../Lists/FlatList'); }, get Image() { - return require('Image'); + return require('../Image/Image'); }, get ImageBackground() { - return require('ImageBackground'); + return require('../Image/ImageBackground'); }, get ImageEditor() { warnOnce( @@ -61,7 +59,7 @@ module.exports = { "It can now be installed and imported from '@react-native-community/image-editor' instead of 'react-native'. " + 'See https://github.com/react-native-community/react-native-image-editor', ); - return require('ImageEditor'); + return require('../Image/ImageEditor'); }, get ImageStore() { warnOnce( @@ -71,13 +69,13 @@ module.exports = { "* expo-file-system: `readAsStringAsync(filepath, 'base64')`" + "* react-native-fs: `readFile(filepath, 'base64')`", ); - return require('ImageStore'); + return require('../Image/ImageStore'); }, get InputAccessoryView() { - return require('InputAccessoryView'); + return require('../Components/TextInput/InputAccessoryView'); }, get KeyboardAvoidingView() { - return require('KeyboardAvoidingView'); + return require('../Components/Keyboard/KeyboardAvoidingView'); }, get MaskedViewIOS() { warnOnce( @@ -86,34 +84,34 @@ module.exports = { "It can now be installed and imported from '@react-native-community/masked-view' instead of 'react-native'. " + 'See https://github.com/react-native-community/react-native-masked-view', ); - return require('MaskedViewIOS'); + return require('../Components/MaskedView/MaskedViewIOS'); }, get Modal() { - return require('Modal'); + return require('../Modal/Modal'); }, get Picker() { - return require('Picker'); + return require('../Components/Picker/Picker'); }, get PickerIOS() { - return require('PickerIOS'); + return require('../Components/Picker/PickerIOS'); }, get ProgressBarAndroid() { - return require('ProgressBarAndroid'); + return require('../Components/ProgressBarAndroid/ProgressBarAndroid'); }, get ProgressViewIOS() { - return require('ProgressViewIOS'); + return require('../Components/ProgressViewIOS/ProgressViewIOS'); }, get SafeAreaView() { - return require('SafeAreaView'); + return require('../Components/SafeAreaView/SafeAreaView'); }, get ScrollView() { - return require('ScrollView'); + return require('../Components/ScrollView/ScrollView'); }, get SectionList() { - return require('SectionList'); + return require('../Lists/SectionList'); }, get SegmentedControlIOS() { - return require('SegmentedControlIOS'); + return require('../Components/SegmentedControlIOS/SegmentedControlIOS'); }, get Slider() { warnOnce( @@ -122,40 +120,40 @@ module.exports = { "It can now be installed and imported from '@react-native-community/slider' instead of 'react-native'. " + 'See https://github.com/react-native-community/react-native-slider', ); - return require('Slider'); + return require('../Components/Slider/Slider'); }, get Switch() { - return require('Switch'); + return require('../Components/Switch/Switch'); }, get RefreshControl() { - return require('RefreshControl'); + return require('../Components/RefreshControl/RefreshControl'); }, get StatusBar() { - return require('StatusBar'); + return require('../Components/StatusBar/StatusBar'); }, get Text() { - return require('Text'); + return require('../Text/Text'); }, get TextInput() { - return require('TextInput'); + return require('../Components/TextInput/TextInput'); }, get Touchable() { - return require('Touchable'); + return require('../Components/Touchable/Touchable'); }, get TouchableHighlight() { - return require('TouchableHighlight'); + return require('../Components/Touchable/TouchableHighlight'); }, get TouchableNativeFeedback() { - return require('TouchableNativeFeedback'); + return require('../Components/Touchable/TouchableNativeFeedback'); }, get TouchableOpacity() { - return require('TouchableOpacity'); + return require('../Components/Touchable/TouchableOpacity'); }, get TouchableWithoutFeedback() { - return require('TouchableWithoutFeedback'); + return require('../Components/Touchable/TouchableWithoutFeedback'); }, get View() { - return require('View'); + return require('../Components/View/View'); }, get ViewPagerAndroid() { warnOnce( @@ -164,30 +162,30 @@ module.exports = { "It can now be installed and imported from '@react-native-community/viewpager' instead of 'react-native'. " + 'See https://github.com/react-native-community/react-native-viewpager', ); - return require('ViewPagerAndroid'); + return require('../Components/ViewPager/ViewPagerAndroid'); }, get VirtualizedList() { - return require('VirtualizedList'); + return require('../Lists/VirtualizedList'); }, get VirtualizedSectionList() { - return require('VirtualizedSectionList'); + return require('../Lists/VirtualizedSectionList'); }, // APIs get ActionSheetIOS() { - return require('ActionSheetIOS'); + return require('../ActionSheetIOS/ActionSheetIOS'); }, get Alert() { - return require('Alert'); + return require('../Alert/Alert'); }, get Animated() { - return require('Animated'); + return require('../Animated/src/Animated'); }, get AppRegistry() { - return require('AppRegistry'); + return require('../ReactNative/AppRegistry'); }, get AppState() { - return require('AppState'); + return require('../AppState/AppState'); }, get AsyncStorage() { warnOnce( @@ -196,31 +194,31 @@ module.exports = { "It can now be installed and imported from '@react-native-community/async-storage' instead of 'react-native'. " + 'See https://github.com/react-native-community/react-native-async-storage', ); - return require('AsyncStorage'); + return require('../Storage/AsyncStorage'); }, get BackHandler() { - return require('BackHandler'); + return require('../Utilities/BackHandler'); }, get Clipboard() { - return require('Clipboard'); + return require('../Components/Clipboard/Clipboard'); }, get DatePickerAndroid() { - return require('DatePickerAndroid'); + return require('../Components/DatePickerAndroid/DatePickerAndroid'); }, get DeviceInfo() { - return require('NativeDeviceInfo').default; + return require('../Utilities/DeviceInfo'); }, get Dimensions() { - return require('Dimensions'); + return require('../Utilities/Dimensions'); }, get Easing() { - return require('Easing'); + return require('../Animated/src/Easing'); }, get findNodeHandle() { - return require('ReactNative').findNodeHandle; + return require('../Renderer/shims/ReactNative').findNodeHandle; }, get I18nManager() { - return require('I18nManager'); + return require('../ReactNative/I18nManager'); }, get ImagePickerIOS() { warnOnce( @@ -230,34 +228,34 @@ module.exports = { "If you cannot upgrade to a different library, please install the deprecated '@react-native-community/image-picker-ios' package. " + 'See https://github.com/react-native-community/react-native-image-picker-ios', ); - return require('ImagePickerIOS'); + return require('../Image/ImagePickerIOS'); }, get InteractionManager() { - return require('InteractionManager'); + return require('../Interaction/InteractionManager'); }, get Keyboard() { - return require('Keyboard'); + return require('../Components/Keyboard/Keyboard'); }, get LayoutAnimation() { - return require('LayoutAnimation'); + return require('../LayoutAnimation/LayoutAnimation'); }, get Linking() { - return require('Linking'); + return require('../Linking/Linking'); }, get NativeDialogManagerAndroid() { - return require('NativeDialogManagerAndroid').default; + return require('../NativeModules/specs/NativeDialogManagerAndroid').default; }, get NativeEventEmitter() { - return require('NativeEventEmitter'); + return require('../EventEmitter/NativeEventEmitter'); }, get PanResponder() { - return require('PanResponder'); + return require('../Interaction/PanResponder'); }, get PermissionsAndroid() { - return require('PermissionsAndroid'); + return require('../PermissionsAndroid/PermissionsAndroid'); }, get PixelRatio() { - return require('PixelRatio'); + return require('../Utilities/PixelRatio'); }, get PushNotificationIOS() { warnOnce( @@ -266,83 +264,83 @@ module.exports = { "It can now be installed and imported from '@react-native-community/push-notification-ios' instead of 'react-native'. " + 'See https://github.com/react-native-community/react-native-push-notification-ios', ); - return require('PushNotificationIOS'); + return require('../PushNotificationIOS/PushNotificationIOS'); }, get Settings() { - return require('Settings'); + return require('../Settings/Settings'); }, get Share() { - return require('Share'); + return require('../Share/Share'); }, get StatusBarIOS() { - return require('StatusBarIOS'); + return require('../Components/StatusBar/StatusBarIOS'); }, get StyleSheet() { - return require('StyleSheet'); + return require('../StyleSheet/StyleSheet'); }, get Systrace() { - return require('Systrace'); + return require('../Performance/Systrace'); }, get TimePickerAndroid() { - return require('TimePickerAndroid'); + return require('../Components/TimePickerAndroid/TimePickerAndroid'); }, get ToastAndroid() { - return require('ToastAndroid'); + return require('../Components/ToastAndroid/ToastAndroid'); }, get TurboModuleRegistry() { - return require('TurboModuleRegistry'); + return require('../TurboModule/TurboModuleRegistry'); }, get TVEventHandler() { - return require('TVEventHandler'); + return require('../Components/AppleTV/TVEventHandler'); }, get UIManager() { - return require('UIManager'); + return require('../ReactNative/UIManager'); }, get unstable_batchedUpdates() { - return require('ReactNative').unstable_batchedUpdates; + return require('../Renderer/shims/ReactNative').unstable_batchedUpdates; }, get UTFSequence() { - return require('UTFSequence'); + return require('../UTFSequence'); }, get Vibration() { - return require('Vibration'); + return require('../Vibration/Vibration'); }, get YellowBox() { - return require('YellowBox'); + return require('../YellowBox/YellowBox'); }, // Plugins get DeviceEventEmitter() { - return require('RCTDeviceEventEmitter'); + return require('../EventEmitter/RCTDeviceEventEmitter'); }, get NativeAppEventEmitter() { - return require('RCTNativeAppEventEmitter'); + return require('../EventEmitter/RCTNativeAppEventEmitter'); }, get NativeModules() { - return require('NativeModules'); + return require('../BatchedBridge/NativeModules'); }, get Platform() { - return require('Platform'); + return require('../Utilities/Platform'); }, get processColor() { - return require('processColor'); + return require('../StyleSheet/processColor'); }, get requireNativeComponent() { - return require('requireNativeComponent'); + return require('../ReactNative/requireNativeComponent'); }, // Prop Types get ColorPropType() { - return require('DeprecatedColorPropType'); + return require('../DeprecatedPropTypes/DeprecatedColorPropType'); }, get EdgeInsetsPropType() { - return require('DeprecatedEdgeInsetsPropType'); + return require('../DeprecatedPropTypes/DeprecatedEdgeInsetsPropType'); }, get PointPropType() { - return require('DeprecatedPointPropType'); + return require('../DeprecatedPropTypes/DeprecatedPointPropType'); }, get ViewPropTypes() { - return require('DeprecatedViewPropTypes'); + return require('../DeprecatedPropTypes/DeprecatedViewPropTypes'); }, }; From 23f578779b48040760f47bbd97ca0e970c75041b Mon Sep 17 00:00:00 2001 From: Leo Natan Date: Fri, 31 May 2019 12:44:01 -0700 Subject: [PATCH 0158/1084] Fix incorrect unhooking for UI manager views in RCTProfileUnhookModules (#25042) Summary: This PR fixes incorrect unhooking for UI manager views in `RCTProfileUnhookModules`. `view` is actually a key, not the view itself; instead, use `viewForReactTag:` to obtain the view itself. This fixes issue #24952. ## Changelog [iOS] [Fixed] - Fix incorrect unhooking for UI manager views in `RCTProfileUnhookModules`, causing an infinite `RCTProfileTrampoline ` recursion (#24952) Pull Request resolved: https://github.com/facebook/react-native/pull/25042 Differential Revision: D15580978 Pulled By: PeteTheHeat fbshipit-source-id: 3483a7f6380b6fb1db4249374d86f692348c9aa2 --- React/Profiler/RCTProfile.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/React/Profiler/RCTProfile.m b/React/Profiler/RCTProfile.m index 98ba2e84333354..4d7460268fa4a0 100644 --- a/React/Profiler/RCTProfile.m +++ b/React/Profiler/RCTProfile.m @@ -350,7 +350,7 @@ void RCTProfileUnhookModules(RCTBridge *bridge) if ([bridge moduleIsInitialized:[RCTUIManager class]]) { dispatch_async(dispatch_get_main_queue(), ^{ for (id view in [bridge.uiManager valueForKey:@"viewRegistry"]) { - RCTProfileUnhookInstance(view); + RCTProfileUnhookInstance([bridge.uiManager viewForReactTag:view]); } dispatch_group_leave(RCTProfileGetUnhookGroup()); From 723adad4395f0eb3848dce4e56b21d81418e9a9d Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Fri, 31 May 2019 12:53:56 -0700 Subject: [PATCH 0159/1084] Reland "[react-native][PR] [TM] Add spec for UIManager" Summary: Original commit changeset: dff59dc9c98b Reviewed By: JoshuaGross Differential Revision: D15579147 fbshipit-source-id: 77a58d2ab3324e243610c1a4d4ab794a7095b3ee --- .../AccessibilityInfo.android.js | 2 +- Libraries/ReactNative/NativeUIManager.js | 122 ++++++++++++++++ Libraries/ReactNative/UIManager.js | 131 +++++++++++------- Libraries/ReactNative/UIManagerStatTracker.js | 4 +- .../getNativeComponentAttributes.js | 7 +- 5 files changed, 213 insertions(+), 53 deletions(-) create mode 100644 Libraries/ReactNative/NativeUIManager.js diff --git a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js index ff9a7329a56c87..5c9ab848d2ecff 100644 --- a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js +++ b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js @@ -139,7 +139,7 @@ const AccessibilityInfo = { setAccessibilityFocus: function(reactTag: number): void { UIManager.sendAccessibilityEvent( reactTag, - UIManager.AccessibilityEventTypes.typeViewFocused, + UIManager.getConstants().AccessibilityEventTypes.typeViewFocused, ); }, diff --git a/Libraries/ReactNative/NativeUIManager.js b/Libraries/ReactNative/NativeUIManager.js new file mode 100644 index 00000000000000..9eb60e68194b81 --- /dev/null +++ b/Libraries/ReactNative/NativeUIManager.js @@ -0,0 +1,122 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +getConstants: () => Object; + +getConstantsForViewManager: (viewManagerName: string) => Object; + +getDefaultEventTypes: () => Array; + +playTouchSound: () => void; + +lazilyLoadView: (name: string) => Object; // revisit return + +createView: ( + reactTag: ?number, + viewName: string, + rootTag: number, + props: Object, + ) => void; + +updateView: (reactTag: number, viewName: string, props: Object) => void; + +focus: (reactTag: ?number) => void; + +blur: (reactTag: ?number) => void; + +findSubviewIn: ( + reactTag: ?number, + point: [number, number], + callback: ( + nativeViewTag: number, + left: number, + top: number, + width: number, + height: number, + ) => void, + ) => void; + +dispatchViewManagerCommand: ( + reactTag: ?number, + commandID: number, + commandArgs: ?Array, // is this best? + ) => void; + +measure: ( + reactTag: ?number, + callback: ( + left: number, + top: number, + width: number, + height: number, + pageX: number, + pageY: number, + ) => void, + ) => void; + +measureInWindow: ( + reactTag: ?number, + callback: (x: number, y: number, width: number, height: number) => void, + ) => void; + +viewIsDescendantOf: ( + reactTag: ?number, + ancestorReactTag: ?number, + callback: (result: Array) => void, + ) => void; + +measureLayout: ( + reactTag: ?number, + ancestorReactTag: ?number, + errorCallback: (error: Object) => void, + callback: ( + left: number, + top: number, + width: number, + height: number, + ) => void, + ) => void; + +measureLayoutRelativeToParent: ( + reactTag: ?number, + errorCallback: (error: Object) => void, + callback: ( + left: number, + top: number, + width: number, + height: number, + ) => void, + ) => void; + +setJSResponder: (reactTag: ?number, blockNativeResponder: boolean) => void; + +clearJSResponder: () => void; + +configureNextLayoutAnimation: ( + config: Object, + callback: () => void, // check what is returned here + errorCallback: (error: Object) => void, + ) => void; + +removeSubviewsFromContainerWithID: (containerID: number) => void; + +replaceExistingNonRootView: ( + reactTag: ?number, + newReactTag: ?number, + ) => void; + +setChildren: (containerTag: ?number, reactTags: Array) => void; + +manageChildren: ( + containerTag: ?number, + moveFromIndices: Array, + moveToIndices: Array, + addChildReactTags: Array, + addAtIndices: Array, + removeAtIndices: Array, + ) => void; + + // Android only + +setLayoutAnimationEnabledExperimental: (enabled: boolean) => void; + +sendAccessibilityEvent: (reactTag: ?number, eventType: number) => void; + +showPopupMenu: ( + reactTag: ?number, + items: Array, + error: (error: Object) => void, + success: (event: string, selected?: number) => void, + ) => void; + +dismissPopupMenu: () => void; +} + +export default TurboModuleRegistry.getEnforcing('UIManager'); diff --git a/Libraries/ReactNative/UIManager.js b/Libraries/ReactNative/UIManager.js index cf7f8edbdbb839..234732bfe1db2c 100644 --- a/Libraries/ReactNative/UIManager.js +++ b/Libraries/ReactNative/UIManager.js @@ -4,7 +4,7 @@ * 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 + * @flow * @format */ 'use strict'; @@ -14,58 +14,94 @@ const Platform = require('../Utilities/Platform'); const UIManagerProperties = require('./UIManagerProperties'); const defineLazyObjectProperty = require('../Utilities/defineLazyObjectProperty'); -const invariant = require('invariant'); -const {UIManager} = NativeModules; +import NativeUIManager from './NativeUIManager'; +import type {Spec} from './NativeUIManager'; + const viewManagerConfigs = {}; -invariant( - UIManager, - 'UIManager is undefined. The native module config is probably incorrect.', -); +interface UIManagerJSInterface extends Spec { + +getViewManagerConfig: (viewManagerName: string) => Object; + // The following are not marked read-only due to logic in UIManagerStatTracker. + createView: ( + reactTag: ?number, + viewName: string, + rootTag: number, + props: Object, + ) => void; + updateView: (reactTag: number, viewName: string, props: Object) => void; + manageChildren: ( + containerTag: ?number, + moveFromIndices: Array, + moveToIndices: Array, + addChildReactTags: Array, + addAtIndices: Array, + removeAtIndices: Array, + ) => void; +} const triedLoadingConfig = new Set(); -UIManager.getViewManagerConfig = function(viewManagerName: string) { - if ( - viewManagerConfigs[viewManagerName] === undefined && - UIManager.getConstantsForViewManager - ) { - try { - viewManagerConfigs[ - viewManagerName - ] = UIManager.getConstantsForViewManager(viewManagerName); - } catch (e) { - viewManagerConfigs[viewManagerName] = null; - } - } - const config = viewManagerConfigs[viewManagerName]; - if (config) { - return config; +let NativeUIManagerConstants = {}; +let isNativeUIManagerConstantsSet = false; +function getConstants(): Object { + if (!isNativeUIManagerConstantsSet) { + NativeUIManagerConstants = NativeUIManager.getConstants(); + isNativeUIManagerConstantsSet = true; } + return NativeUIManagerConstants; +} + +const UIManagerJS: UIManagerJSInterface = { + ...NativeUIManager, + getConstants(): Object { + return getConstants(); + }, + getViewManagerConfig: function(viewManagerName: string) { + if ( + viewManagerConfigs[viewManagerName] === undefined && + NativeUIManager.getConstantsForViewManager + ) { + try { + viewManagerConfigs[ + viewManagerName + ] = NativeUIManager.getConstantsForViewManager(viewManagerName); + } catch (e) { + viewManagerConfigs[viewManagerName] = null; + } + } - // If we're in the Chrome Debugger, let's not even try calling the sync - // method. - if (__DEV__) { - if (!global.nativeCallSyncHook) { + const config = viewManagerConfigs[viewManagerName]; + if (config) { return config; } - } - if (UIManager.lazilyLoadView && !triedLoadingConfig.has(viewManagerName)) { - const result = UIManager.lazilyLoadView(viewManagerName); - triedLoadingConfig.add(viewManagerName); - if (result.viewConfig) { - UIManager[viewManagerName] = result.viewConfig; - lazifyViewManagerConfig(viewManagerName); + // If we're in the Chrome Debugger, let's not even try calling the sync + // method. + if (__DEV__) { + if (!global.nativeCallSyncHook) { + return config; + } } - } - return viewManagerConfigs[viewManagerName]; + if ( + NativeUIManager.lazilyLoadView && + !triedLoadingConfig.has(viewManagerName) + ) { + const result = NativeUIManager.lazilyLoadView(viewManagerName); + triedLoadingConfig.add(viewManagerName); + if (result.viewConfig) { + getConstants()[viewManagerName] = result.viewConfig; + lazifyViewManagerConfig(viewManagerName); + } + } + + return viewManagerConfigs[viewManagerName]; + }, }; function lazifyViewManagerConfig(viewName) { - const viewConfig = UIManager[viewName]; + const viewConfig = getConstants()[viewName]; if (viewConfig.Manager) { viewManagerConfigs[viewName] = viewConfig; defineLazyObjectProperty(viewConfig, 'Constants', { @@ -106,10 +142,10 @@ function lazifyViewManagerConfig(viewName) { * namespace instead of UIManager, unlike Android. */ if (Platform.OS === 'ios') { - Object.keys(UIManager).forEach(viewName => { + Object.keys(getConstants()).forEach(viewName => { lazifyViewManagerConfig(viewName); }); -} else if (UIManager.ViewManagerNames) { +} else if (getConstants().ViewManagerNames) { // We want to add all the view managers to the UIManager. // However, the way things are set up, the list of view managers is not known at compile time. // As Prepack runs at compile it, it cannot process this loop. @@ -120,13 +156,13 @@ if (Platform.OS === 'ios') { residual( 'void', (UIManager, defineLazyObjectProperty) => { - UIManager.ViewManagerNames.forEach(viewManagerName => { + UIManager.getConstants().ViewManagerNames.forEach(viewManagerName => { defineLazyObjectProperty(UIManager, viewManagerName, { get: () => UIManager.getConstantsForViewManager(viewManagerName), }); }); }, - UIManager, + NativeUIManager, defineLazyObjectProperty, ); @@ -135,27 +171,28 @@ if (Platform.OS === 'ios') { // so that any accesses to unknown properties along the global code will fail // when Prepack encounters them. if (global.__makePartial) { - global.__makePartial(UIManager); + global.__makePartial(NativeUIManager); } } if (__DEV__) { - Object.keys(UIManager).forEach(viewManagerName => { + Object.keys(getConstants()).forEach(viewManagerName => { if (!UIManagerProperties.includes(viewManagerName)) { if (!viewManagerConfigs[viewManagerName]) { - viewManagerConfigs[viewManagerName] = UIManager[viewManagerName]; + viewManagerConfigs[viewManagerName] = getConstants()[viewManagerName]; } - defineLazyObjectProperty(UIManager, viewManagerName, { + defineLazyObjectProperty(NativeUIManager, viewManagerName, { get: () => { console.warn( `Accessing view manager configs directly off UIManager via UIManager['${viewManagerName}'] ` + `is no longer supported. Use UIManager.getViewManagerConfig('${viewManagerName}') instead.`, ); - return UIManager.getViewManagerConfig(viewManagerName); + + return UIManagerJS.getViewManagerConfig(viewManagerName); }, }); } }); } -module.exports = UIManager; +module.exports = UIManagerJS; diff --git a/Libraries/ReactNative/UIManagerStatTracker.js b/Libraries/ReactNative/UIManagerStatTracker.js index ec1494c53b4390..85aaa6ba7707a7 100644 --- a/Libraries/ReactNative/UIManagerStatTracker.js +++ b/Libraries/ReactNative/UIManagerStatTracker.js @@ -52,8 +52,8 @@ const UIManagerStatTracker = { remove, ) { incStat('manageChildren', 1); - incStat('move', Object.keys(moveFrom || []).length); - incStat('remove', Object.keys(remove || []).length); + incStat('move', moveFrom.length); + incStat('remove', remove.length); manageChildrenOrig(tag, moveFrom, moveTo, addTags, addIndices, remove); }; }, diff --git a/Libraries/ReactNative/getNativeComponentAttributes.js b/Libraries/ReactNative/getNativeComponentAttributes.js index bf08c389eb8753..85a347bea1f358 100644 --- a/Libraries/ReactNative/getNativeComponentAttributes.js +++ b/Libraries/ReactNative/getNativeComponentAttributes.js @@ -96,17 +96,18 @@ function attachDefaultEventTypes(viewConfig: any) { // This is supported on UIManager platforms (ex: Android), // as lazy view managers are not implemented for all platforms. // See [UIManager] for details on constants and implementations. - if (UIManager.ViewManagerNames || UIManager.LazyViewManagersEnabled) { + const constants = UIManager.getConstants(); + if (constants.ViewManagerNames || constants.LazyViewManagersEnabled) { // Lazy view managers enabled. viewConfig = merge(viewConfig, UIManager.getDefaultEventTypes()); } else { viewConfig.bubblingEventTypes = merge( viewConfig.bubblingEventTypes, - UIManager.genericBubblingEventTypes, + constants.genericBubblingEventTypes, ); viewConfig.directEventTypes = merge( viewConfig.directEventTypes, - UIManager.genericDirectEventTypes, + constants.genericDirectEventTypes, ); } } From fd607b13048952eeaffc646b17adcaaf1cea8b4a Mon Sep 17 00:00:00 2001 From: David Aurelio Date: Fri, 31 May 2019 15:52:40 -0700 Subject: [PATCH 0160/1084] Back out "[Yoga] Remove comparison to `YGUndefined` *and* `0.0f`" Summary: Original commit changeset: 13c8f24e1bc8 Reviewed By: fabiomassimo Differential Revision: D15583502 fbshipit-source-id: efc6175f6c4925a383fea723195c073f49e2eff1 --- ReactCommon/yoga/yoga/Yoga.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index da24a549fd5247..d41a12013cd75d 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -2861,8 +2861,11 @@ static void YGNodelayoutImpl( availableInnerMainDim = maxInnerMainDim; } else { if (!node->getConfig()->useLegacyStretchBehaviour && - (collectedFlexItemsValues.totalFlexGrowFactors == 0 || - node->resolveFlexGrow() == 0)) { + ((YGFloatIsUndefined( + collectedFlexItemsValues.totalFlexGrowFactors) && + collectedFlexItemsValues.totalFlexGrowFactors == 0) || + (YGFloatIsUndefined(node->resolveFlexGrow()) && + node->resolveFlexGrow() == 0))) { // If we don't have any children to flex or we can't flex the node // itself, space we've used is all space we need. Root node also // should be shrunk to minimum From 83a37b4ffa95c86486e506f0bd10c64a2377fa4c Mon Sep 17 00:00:00 2001 From: Oleg Lokhvitsky Date: Fri, 31 May 2019 16:29:13 -0700 Subject: [PATCH 0161/1084] Backout D15554658 Summary: It's breaking Mobile Home. We're about to have our branch cut so need master to be in a stable place. https://fb.prod.workplace.com/groups/549677545222488/permalink/1123279851195585/ Reviewed By: alsun2001 Differential Revision: D15578479 fbshipit-source-id: a7e04f03630f4950f7505d35fc74119052d23178 --- Libraries/react-native/react-native-implementation.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js index af54b7a6dfe017..b9b76263c375e4 100644 --- a/Libraries/react-native/react-native-implementation.js +++ b/Libraries/react-native/react-native-implementation.js @@ -342,6 +342,10 @@ module.exports = { get ViewPropTypes() { return require('../DeprecatedPropTypes/DeprecatedViewPropTypes'); }, + // TODO(cpojer): Temporary fix for missing Toolbar + get ToolbarAndroid() { + return require('UnimplementedView'); + }, }; if (__DEV__) { From 4a6676dc18f2781e752c2055a4206a2005940bcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= Date: Fri, 31 May 2019 16:42:18 -0700 Subject: [PATCH 0162/1084] Cache CocoaPods specs-repo (#25095) Summary: The `test_end_to_end` job has been timing out due CocoaPods taking too long to check out the Specs repo. This repo is stored at `~/.cocoapods`, therefore by caching this folder we can keep the individual e2e test run from exceeding 10 minutes w/o output. ## Changelog [Internal] [Added] - Cache CocoaPods Pull Request resolved: https://github.com/facebook/react-native/pull/25095 Differential Revision: D15587702 Pulled By: hramos fbshipit-source-id: 6669ff09a5021f012ac8a829db70442d8f7f07e8 --- .circleci/config.yml | 24 +++++++++---- scripts/run-ci-e2e-tests.js | 70 +++++++++++-------------------------- 2 files changed, 38 insertions(+), 56 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 64630eaf6c5753..439abd9e050dd2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -59,8 +59,8 @@ commands: steps: - restore_cache: keys: - - v2-yarn-cache-{{ arch }}-{{ checksum "package.json" }} - - v2-yarn-cache-{{ arch }} + - v3-yarn-cache-{{ arch }}-{{ checksum "yarn.lock" }} + - v3-yarn-cache-{{ arch }} - run: name: Run Yarn command: | @@ -72,7 +72,7 @@ commands: - save_cache: paths: - ~/.cache/yarn - key: v2-yarn-cache-{{ arch }}-{{ checksum "package.json" }} + key: v3-yarn-cache-{{ arch }}-{{ checksum "yarn.lock" }} install_buck_tooling: steps: @@ -433,6 +433,13 @@ jobs: # Configure Watchman - run: touch .watchmanconfig + - restore_cache: + keys: + - v1-cocoapods-{{ checksum "template/ios/Podfile" }} + - v1-cocoapods- + + - run: pod setup + - run: name: Run Detox iOS End-to-End Tests command: yarn run build-ios-e2e && yarn run test-ios-e2e @@ -448,6 +455,11 @@ jobs: node ./scripts/run-ci-e2e-tests.js --ios --retries 3; when: always + - save_cache: + paths: + - ~/.cocoapods/repos + key: v1-cocoapods-{{ checksum "template/ios/Podfile" }} + test_js_e2e: executor: node8 steps: @@ -455,6 +467,7 @@ jobs: checkout_type: node - setup_artifacts - run_yarn + - run: sudo apt-get install rsync - run: name: Run JavaScript End-to-End Tests @@ -704,10 +717,7 @@ workflows: branches: only: /^pull\/.*$/ - # Gather coverage on master + # Gather coverage - js_coverage: requires: - setup - filters: - branches: - only: master diff --git a/scripts/run-ci-e2e-tests.js b/scripts/run-ci-e2e-tests.js index b5db0c4816802e..56b4bdc644eb88 100644 --- a/scripts/run-ci-e2e-tests.js +++ b/scripts/run-ci-e2e-tests.js @@ -30,7 +30,10 @@ const SCRIPTS = __dirname; const ROOT = path.normalize(path.join(__dirname, '..')); const tryExecNTimes = require('./try-n-times'); -const TEMP = exec('mktemp -d /tmp/react-native-XXXXXXXX').stdout.trim(); +const REACT_NATIVE_TEMP_DIR = exec( + 'mktemp -d /tmp/react-native-XXXXXXXX', +).stdout.trim(); +const REACT_NATIVE_APP_DIR = `${REACT_NATIVE_TEMP_DIR}/template`; const numberOfRetries = argv.retries || 1; let SERVER_PID; let APPIUM_PID; @@ -41,18 +44,6 @@ function describe(message) { } try { - // install CLI - const CLI_PACKAGE = 'react-native-cli'; - if (!argv['skip-cli-install']) { - describe('Instal react-native-cli'); - if (exec(`yarn global add ${CLI_PACKAGE}`).code) { - echo('Could not install react-native-cli globally.'); - echo('Run with --skip-cli-install to skip this step'); - exitCode = 1; - throw Error(exitCode); - } - } - if (argv.android) { describe('Compile Android binaries'); if ( @@ -91,41 +82,21 @@ try { throw Error(exitCode); } - const PACKAGE = path.join(ROOT, 'react-native-*.tgz'); - cd(TEMP); + const REACT_NATIVE_PACKAGE = path.join(ROOT, 'react-native-*.tgz'); - describe('Create EndToEndTest React Native app'); - if ( - tryExecNTimes( - () => { - return exec( - `${path.join( - ROOT, - '/node_modules/.bin/react-native', - )} init EndToEndTest --version ${PACKAGE} --npm`, - ).code; - }, - numberOfRetries, - () => { - rm('-rf', 'EndToEndTest'); - exec('sleep 10s'); - }, - ) - ) { - echo('Failed to execute react-native init'); - echo('Most common reason is npm registry connectivity, try again'); - exitCode = 1; - throw Error(exitCode); - } + describe('Scaffold a basic React Native app from template'); + exec(`rsync -a ${ROOT}/template ${REACT_NATIVE_TEMP_DIR}`); + cd(REACT_NATIVE_APP_DIR); const METRO_CONFIG = path.join(ROOT, 'metro.config.js'); const RN_POLYFILLS = path.join(ROOT, 'rn-get-polyfills.js'); - cp(METRO_CONFIG, 'EndToEndTest/.'); - cp(RN_POLYFILLS, 'EndToEndTest/.'); + cp(METRO_CONFIG, '.'); + cp(RN_POLYFILLS, '.'); + mv('_flowconfig', '.flowconfig'); + mv('_watchmanconfig', '.watchmanconfig'); - cd('EndToEndTest'); describe('Install React Native package'); - exec(`npm install ${PACKAGE}`); + exec(`npm install ${REACT_NATIVE_PACKAGE}`); describe('Install node_modules'); if ( @@ -142,6 +113,7 @@ try { exitCode = 1; throw Error(exitCode); } + exec('rm -rf ./node_modules/react-native/template'); if (argv.android) { describe('Install end-to-end framework'); @@ -183,7 +155,7 @@ try { APPIUM_PID = appiumProcess.pid; describe('Build the app'); - if (exec('./node_modules/.bin/react-native run-android').code) { + if (exec('react-native run-android').code) { echo('could not execute react-native run-android'); exitCode = 1; throw Error(exitCode); @@ -242,19 +214,19 @@ try { () => { let destination = 'platform=iOS Simulator,name=iPhone 6s,OS=12.2'; let sdk = 'iphonesimulator'; - let scheme = 'EndToEndTest'; + let scheme = 'HelloWorld'; if (argv.tvos) { destination = 'platform=tvOS Simulator,name=Apple TV,OS=11.4'; sdk = 'appletvsimulator'; - scheme = 'EndToEndTest-tvOS'; + scheme = 'HelloWorld-tvOS'; } return exec( [ 'xcodebuild', '-workspace', - '"EndToEndTest.xcworkspace"', + '"HelloWorld.xcworkspace"', '-destination', `"${destination}"`, '-scheme', @@ -292,7 +264,7 @@ try { describe('Test: Verify packager can generate an Android bundle'); if ( exec( - './node_modules/.bin/react-native bundle --max-workers 1 --dev true --entry-file index.js --bundle-output android-bundle.js --platform android', + 'yarn react-native bundle --entry-file index.js --platform android --dev true --bundle-output android-bundle.js --max-workers 1', ).code ) { echo('Could not build Android bundle'); @@ -302,7 +274,7 @@ try { describe('Test: Verify packager can generate an iOS bundle'); if ( exec( - './node_modules/.bin/react-native bundle --max-workers 1 --dev true --entry-file index.js --bundle-output ios-bundle.js --platform ios', + 'yarn react-native bundle --entry-file index.js --platform ios --dev true --bundle-output ios-bundle.js --max-workers 1', ).code ) { echo('Could not build iOS bundle'); @@ -310,7 +282,7 @@ try { throw Error(exitCode); } describe('Test: Flow check'); - if (exec(path.join(ROOT, '/node_modules/.bin/flow') + ' check').code) { + if (exec(`${ROOT}/node_modules/.bin/flow check`).code) { echo('Flow check failed.'); exitCode = 1; throw Error(exitCode); From 1dfe82d588a73280e315b6d743acdb9a71f96f52 Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Fri, 31 May 2019 16:58:54 -0700 Subject: [PATCH 0163/1084] UIManager: fill in getViewManagerConfig() on the NativeUIManager object Summary: Some callsites access `UIManager` from `NativeModules.UIManager` instead of importing directly from `UIManager.js`. Post TurboModule spec flow typing, we don't install `getViewManagerConfig()` on the NativeUIManager object anymore, only on the JS wrapper. So callsites not importing from `UIManager.js` will break. Example: https://github.com/react-native-community/react-native-maps/blob/dbf746d66ca1b42f2beb790bfbf4c0e3a74f3279/lib/components/decorateMapComponent.js#L32-L40 Reviewed By: JoshuaGross, mdvacca Differential Revision: D15588353 fbshipit-source-id: 2c2b497dae0660abf15acb2f944546fe03e9bb0a --- Libraries/ReactNative/UIManager.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Libraries/ReactNative/UIManager.js b/Libraries/ReactNative/UIManager.js index 234732bfe1db2c..e7dd0691724881 100644 --- a/Libraries/ReactNative/UIManager.js +++ b/Libraries/ReactNative/UIManager.js @@ -100,6 +100,13 @@ const UIManagerJS: UIManagerJSInterface = { }, }; +// TODO (T45220498): Remove this. +// 3rd party libs may be calling `NativeModules.UIManager.getViewManagerConfig()` +// instead of `UIManager.getViewManagerConfig()` off UIManager.js. +// This is a workaround for now. +// $FlowFixMe +NativeUIManager.getViewManagerConfig = UIManagerJS.getViewManagerConfig; + function lazifyViewManagerConfig(viewName) { const viewConfig = getConstants()[viewName]; if (viewConfig.Manager) { From 308d63fe938e473b6eba2cc7668f5834d96078fd Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Fri, 31 May 2019 17:01:42 -0700 Subject: [PATCH 0164/1084] console.log shouldn't throw warning if metro isn't running Summary: When metro is not running, D15559151 caused infinite exceptions (fetch threw an error if it couldn't connect to localhost:8081) which affected UI. Swallow those errors and everything works well, with or without metro. Reviewed By: yungsters Differential Revision: D15588623 fbshipit-source-id: d170ea82478545836a7a22a228196c9778e93ef0 --- Libraries/Core/Devtools/logToConsole.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Libraries/Core/Devtools/logToConsole.js b/Libraries/Core/Devtools/logToConsole.js index ecad232cb98a63..93806e76cba53f 100644 --- a/Libraries/Core/Devtools/logToConsole.js +++ b/Libraries/Core/Devtools/logToConsole.js @@ -27,6 +27,13 @@ function logToConsole( fetch(getDevServer().url + 'log-to-console', { method: 'POST', body, + }).catch(e => { + // ...Oh well! + // If metro is running, logs should be sent to metro. + // If metro is NOT running, this will throw an exception every time... and + // those exceptions will be caught and logged, which will throw another + // exception, etc, causing infinite exception loop which affects UI perf. + // If we swallow silently here, that won't happen. }); } From 489e83d977f8c1eac55e29eb5c8d88582e1608ee Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Fri, 31 May 2019 17:45:18 -0700 Subject: [PATCH 0165/1084] fix import path to not use haste (UnimplementedView) Summary: We shouldn't use Haste module import anymore... Reviewed By: yungsters Differential Revision: D15589880 fbshipit-source-id: d4598a256b6af81382427cf442099b95e69b4004 --- Libraries/react-native/react-native-implementation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js index b9b76263c375e4..d3602050e7f760 100644 --- a/Libraries/react-native/react-native-implementation.js +++ b/Libraries/react-native/react-native-implementation.js @@ -344,7 +344,7 @@ module.exports = { }, // TODO(cpojer): Temporary fix for missing Toolbar get ToolbarAndroid() { - return require('UnimplementedView'); + return require('../Components/UnimplementedViews/UnimplementedView'); }, }; From 5e6cebe50bb38ac257094227f5db9c5defd4c0f8 Mon Sep 17 00:00:00 2001 From: mitulsavani Date: Fri, 31 May 2019 19:28:00 -0700 Subject: [PATCH 0166/1084] add spec for ImageStore (#25101) Summary: This PR solves part of this issue: #24875 ## Changelog [General] [Added] - add TM spec for ImageStore Pull Request resolved: https://github.com/facebook/react-native/pull/25101 Reviewed By: hramos Differential Revision: D15583463 Pulled By: fkgozali fbshipit-source-id: 17e87e8fecb35d42a981b1fb348e40d2b1e91cc6 --- Libraries/Image/ImageStore.js | 23 ++++++++----------- Libraries/Image/NativeImageStore.js | 34 +++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 14 deletions(-) create mode 100644 Libraries/Image/NativeImageStore.js diff --git a/Libraries/Image/ImageStore.js b/Libraries/Image/ImageStore.js index e011ffc8022585..7d6e7be5d6faac 100644 --- a/Libraries/Image/ImageStore.js +++ b/Libraries/Image/ImageStore.js @@ -9,8 +9,7 @@ */ 'use strict'; -const RCTImageStoreManager = require('../BatchedBridge/NativeModules') - .ImageStoreManager; +import NativeImageStore from './NativeImageStore'; const Platform = require('../Utilities/Platform'); @@ -31,8 +30,8 @@ class ImageStore { * @platform ios */ static hasImageForTag(uri: string, callback: (hasImage: boolean) => void) { - if (RCTImageStoreManager.hasImageForTag) { - RCTImageStoreManager.hasImageForTag(uri, callback); + if (NativeImageStore.hasImageForTag) { + NativeImageStore.hasImageForTag(uri, callback); } else { warnUnimplementedMethod('hasImageForTag'); } @@ -47,8 +46,8 @@ class ImageStore { * @platform ios */ static removeImageForTag(uri: string) { - if (RCTImageStoreManager.removeImageForTag) { - RCTImageStoreManager.removeImageForTag(uri); + if (NativeImageStore.removeImageForTag) { + NativeImageStore.removeImageForTag(uri); } else { warnUnimplementedMethod('removeImageForTag'); } @@ -70,12 +69,8 @@ class ImageStore { success: (uri: string) => void, failure: (error: any) => void, ) { - if (RCTImageStoreManager.addImageFromBase64) { - RCTImageStoreManager.addImageFromBase64( - base64ImageData, - success, - failure, - ); + if (NativeImageStore.addImageFromBase64) { + NativeImageStore.addImageFromBase64(base64ImageData, success, failure); } else { warnUnimplementedMethod('addImageFromBase64'); } @@ -97,8 +92,8 @@ class ImageStore { success: (base64ImageData: string) => void, failure: (error: any) => void, ) { - if (RCTImageStoreManager.getBase64ForTag) { - RCTImageStoreManager.getBase64ForTag(uri, success, failure); + if (NativeImageStore.getBase64ForTag) { + NativeImageStore.getBase64ForTag(uri, success, failure); } else { warnUnimplementedMethod('getBase64ForTag'); } diff --git a/Libraries/Image/NativeImageStore.js b/Libraries/Image/NativeImageStore.js new file mode 100644 index 00000000000000..4add169d31abec --- /dev/null +++ b/Libraries/Image/NativeImageStore.js @@ -0,0 +1,34 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; + +export interface Spec extends TurboModule { + // Common + +getBase64ForTag: ( + uri: string, + success: (base64ImageData: string) => void, + failure: (error: Object) => void, + ) => void; + + // iOS-only + +hasImageForTag: (uri: string, callback: (hasImage: boolean) => void) => void; + +removeImageForTag: (uri: string) => void; + +addImageFromBase64: ( + base64ImageData: string, + success: (uri: string) => void, + failure: (error: Object) => void, + ) => void; +} + +export default TurboModuleRegistry.getEnforcing('ImageStoringManager'); From 18fededae085b53b01e54a7ed27e32c2318e7cae Mon Sep 17 00:00:00 2001 From: Eric Lewis Date: Fri, 31 May 2019 19:53:21 -0700 Subject: [PATCH 0167/1084] add spec for I18nManager (#24908) Summary: Part of #24875. ## Changelog [General] [Added] - add TM spec for I18nManager Pull Request resolved: https://github.com/facebook/react-native/pull/24908 Reviewed By: fkgozali Differential Revision: D15395163 Pulled By: RSNara fbshipit-source-id: 8fd3a5a8ce5d0f74132efff4fae7224eab03405b --- Libraries/Inspector/resolveBoxStyle.js | 6 ++-- Libraries/Modal/Modal.js | 2 +- Libraries/ReactNative/I18nManager.js | 37 ++++++++++++---------- Libraries/ReactNative/NativeI18nManager.js | 26 +++++++++++++++ jest/setup.js | 9 ++++++ 5 files changed, 61 insertions(+), 19 deletions(-) create mode 100644 Libraries/ReactNative/NativeI18nManager.js diff --git a/Libraries/Inspector/resolveBoxStyle.js b/Libraries/Inspector/resolveBoxStyle.js index 15dfaf3061d810..1f013ed064ba3c 100644 --- a/Libraries/Inspector/resolveBoxStyle.js +++ b/Libraries/Inspector/resolveBoxStyle.js @@ -69,7 +69,8 @@ function resolveBoxStyle( const styleForEnd = style[prefix + 'End']; if (styleForEnd != null) { - if (I18nManager.isRTL && I18nManager.doLeftAndRightSwapInRTL) { + const constants = I18nManager.getConstants(); + if (constants.isRTL && constants.doLeftAndRightSwapInRTL) { result.left = styleForEnd; } else { result.right = styleForEnd; @@ -78,7 +79,8 @@ function resolveBoxStyle( } const styleForStart = style[prefix + 'Start']; if (styleForStart != null) { - if (I18nManager.isRTL && I18nManager.doLeftAndRightSwapInRTL) { + const constants = I18nManager.getConstants(); + if (constants.isRTL && constants.doLeftAndRightSwapInRTL) { result.right = styleForStart; } else { result.left = styleForStart; diff --git a/Libraries/Modal/Modal.js b/Libraries/Modal/Modal.js index 40c03122bb2c14..314647a843646d 100644 --- a/Libraries/Modal/Modal.js +++ b/Libraries/Modal/Modal.js @@ -271,7 +271,7 @@ class Modal extends React.Component { } } -const side = I18nManager.isRTL ? 'right' : 'left'; +const side = I18nManager.getConstants().isRTL ? 'right' : 'left'; const styles = StyleSheet.create({ modal: { position: 'absolute', diff --git a/Libraries/ReactNative/I18nManager.js b/Libraries/ReactNative/I18nManager.js index da2767a842068f..e5fd02e7c13dab 100644 --- a/Libraries/ReactNative/I18nManager.js +++ b/Libraries/ReactNative/I18nManager.js @@ -9,21 +9,26 @@ */ 'use strict'; -type I18nManagerStatus = { - isRTL: boolean, - doLeftAndRightSwapInRTL: boolean, - allowRTL: (allowRTL: boolean) => {}, - forceRTL: (forceRTL: boolean) => {}, - swapLeftAndRightInRTL: (flipStyles: boolean) => {}, -}; +import NativeI18nManager from './NativeI18nManager'; -const I18nManager: I18nManagerStatus = require('../BatchedBridge/NativeModules') - .I18nManager || { - isRTL: false, - doLeftAndRightSwapInRTL: true, - allowRTL: () => {}, - forceRTL: () => {}, - swapLeftAndRightInRTL: () => {}, -}; +module.exports = { + getConstants: () => { + return NativeI18nManager.getConstants(); + }, + + allowRTL: (shouldAllow: boolean) => { + NativeI18nManager.allowRTL(shouldAllow); + }, -module.exports = I18nManager; + forceRTL: (shouldForce: boolean) => { + NativeI18nManager.forceRTL(shouldForce); + }, + + swapLeftAndRightInRTL: (flipStyles: boolean) => { + NativeI18nManager.swapLeftAndRightInRTL(flipStyles); + }, + + isRTL: NativeI18nManager.getConstants().isRTL, + doLeftAndRightSwapInRTL: NativeI18nManager.getConstants() + .doLeftAndRightSwapInRTL, +}; diff --git a/Libraries/ReactNative/NativeI18nManager.js b/Libraries/ReactNative/NativeI18nManager.js new file mode 100644 index 00000000000000..0220b2471ba486 --- /dev/null +++ b/Libraries/ReactNative/NativeI18nManager.js @@ -0,0 +1,26 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +getConstants: () => {| + isRTL: boolean, + doLeftAndRightSwapInRTL: boolean, + |}; + allowRTL: (allowRTL: boolean) => void; + forceRTL: (forceRTL: boolean) => void; + swapLeftAndRightInRTL: (flipStyles: boolean) => void; +} + +export default TurboModuleRegistry.getEnforcing('I18nManager'); diff --git a/jest/setup.js b/jest/setup.js index d85849066c2d82..cdd146462fe7c0 100644 --- a/jest/setup.js +++ b/jest/setup.js @@ -312,6 +312,15 @@ jest addListener: jest.fn(), removeListeners: jest.fn(), }, + I18nManager: { + allowRTL: jest.fn(), + forceRTL: jest.fn(), + swapLeftAndRightInRTL: jest.fn(), + getConstants: () => ({ + isRTL: false, + doLeftAndRightSwapInRTL: true, + }), + }, })) .mock('../Libraries/ReactNative/requireNativeComponent', () => { const React = require('react'); From 5a8cdb4bb7736f984051a2ed346bb3a5d11f7228 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Sat, 1 Jun 2019 12:44:26 -0700 Subject: [PATCH 0168/1084] Fabric: Additional temporary checks in prop parsing infra Summary: While ViewConfig infra isn't perfect we need to check that for correcness. See the task for more details. Reviewed By: JoshuaGross Differential Revision: D15578675 fbshipit-source-id: c99c2be9c215e6b9d7ee8e6e50d85e822c1f007e --- ReactCommon/fabric/components/image/conversions.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/ReactCommon/fabric/components/image/conversions.h b/ReactCommon/fabric/components/image/conversions.h index 27b4960fa97a62..e1d8593b5c3080 100644 --- a/ReactCommon/fabric/components/image/conversions.h +++ b/ReactCommon/fabric/components/image/conversions.h @@ -35,11 +35,18 @@ inline void fromRawValue(const RawValue &value, ImageSource &result) { } if (items.find("width") != items.end() && - items.find("height") != items.end()) { + items.find("height") != items.end() && + // The following checks have to be removed after codegen is shipped. + // See T45151459. + items.at("width").hasType() && + items.at("height").hasType()) { result.size = {(Float)items.at("width"), (Float)items.at("height")}; } - if (items.find("scale") != items.end()) { + if (items.find("scale") != items.end() && + // The following checks have to be removed after codegen is shipped. + // See T45151459. + items.at("scale").hasType()) { result.scale = (Float)items.at("scale"); } else { result.scale = items.find("deprecated") != items.end() ? 0.0 : 1.0; From a2913d33a66dc1d179ced170d6c73c8ddf91960e Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Sat, 1 Jun 2019 20:04:27 -0700 Subject: [PATCH 0169/1084] Fabric: The second attempt to fix a thread-safety issue in RCTNativeAnimatedModule Summary: Previously we tried to fix that with RCTUnsafeExecuteOnUIManagerQueueSync but that caused a deadlock (yeah, it's actually unsafe). Besides that, I tried to solve that with introducing a mutex that covers access to `_operations` and `_preOperations` but failed miserably. It solved threading issue but that didn't fix data-races and inconsistency of the collections. Reviewed By: sahrens Differential Revision: D15587564 fbshipit-source-id: d1953036b09354d1663a9b191440f8b4a4e6be9d --- .../NativeAnimation/RCTNativeAnimatedModule.m | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/Libraries/NativeAnimation/RCTNativeAnimatedModule.m b/Libraries/NativeAnimation/RCTNativeAnimatedModule.m index 69bf078f804a6a..0bbc9c78711625 100644 --- a/Libraries/NativeAnimation/RCTNativeAnimatedModule.m +++ b/Libraries/NativeAnimation/RCTNativeAnimatedModule.m @@ -232,27 +232,31 @@ - (void)flushOperationQueues - (void)willMountComponentsWithRootTag:(NSInteger)rootTag { RCTAssertMainQueue(); - __block NSArray *preOperations; - RCTUnsafeExecuteOnUIManagerQueueSync(^{ - preOperations = self->_preOperations; + RCTExecuteOnUIManagerQueue(^{ + NSArray *preOperations = self->_preOperations; self->_preOperations = [NSMutableArray new]; + + RCTExecuteOnMainQueue(^{ + for (AnimatedOperation preOperation in preOperations) { + preOperation(self->_nodesManager); + } + }); }); - for (AnimatedOperation operation in preOperations) { - operation(self->_nodesManager); - } } - (void)didMountComponentsWithRootTag:(NSInteger)rootTag { RCTAssertMainQueue(); - __block NSArray *operations; - RCTUnsafeExecuteOnUIManagerQueueSync(^{ - operations = self->_operations; + RCTExecuteOnUIManagerQueue(^{ + NSArray *operations = self->_operations; self->_operations = [NSMutableArray new]; + + RCTExecuteOnMainQueue(^{ + for (AnimatedOperation operation in operations) { + operation(self->_nodesManager); + } + }); }); - for (AnimatedOperation operation in operations) { - operation(self->_nodesManager); - } } #pragma mark - RCTUIManagerObserver From bc6dd6b48a51abec0784dce7dc59e51d643d9604 Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Sat, 1 Jun 2019 23:22:53 -0700 Subject: [PATCH 0170/1084] TM Spec: fixed ImageStoreManager name Summary: It used a wrong name, so this fixed the module lookup. Reviewed By: yungsters Differential Revision: D15595099 fbshipit-source-id: f5a711f595d9630541ae08339aa1532ed1d4d5f2 --- Libraries/Image/NativeImageStore.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libraries/Image/NativeImageStore.js b/Libraries/Image/NativeImageStore.js index 4add169d31abec..0bc4948f1fb0a8 100644 --- a/Libraries/Image/NativeImageStore.js +++ b/Libraries/Image/NativeImageStore.js @@ -31,4 +31,4 @@ export interface Spec extends TurboModule { ) => void; } -export default TurboModuleRegistry.getEnforcing('ImageStoringManager'); +export default TurboModuleRegistry.getEnforcing('ImageStoreManager'); From 9a053fc4db1d926824cf579cbfcabcd664618f9b Mon Sep 17 00:00:00 2001 From: David Vacca Date: Sun, 2 Jun 2019 16:00:54 -0700 Subject: [PATCH 0171/1084] Create base MapBuffer class and tests Summary: This diff creates the base classes for MapBuffer and its tests Reviewed By: shergin Differential Revision: D15550730 fbshipit-source-id: a5a47edebd7c3e1b8b2c3ad2006aee0f8bdb7866 --- ReactCommon/fabric/mapbuffer/MapBuffer.cpp | 18 +++++++++ ReactCommon/fabric/mapbuffer/MapBuffer.h | 37 +++++++++++++++++++ .../fabric/mapbuffer/tests/MapBufferTest.cpp | 14 +++++++ 3 files changed, 69 insertions(+) create mode 100644 ReactCommon/fabric/mapbuffer/MapBuffer.cpp create mode 100644 ReactCommon/fabric/mapbuffer/MapBuffer.h create mode 100644 ReactCommon/fabric/mapbuffer/tests/MapBufferTest.cpp diff --git a/ReactCommon/fabric/mapbuffer/MapBuffer.cpp b/ReactCommon/fabric/mapbuffer/MapBuffer.cpp new file mode 100644 index 00000000000000..330890f8832d55 --- /dev/null +++ b/ReactCommon/fabric/mapbuffer/MapBuffer.cpp @@ -0,0 +1,18 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "MapBuffer.h" + +namespace facebook { +namespace react { + +MapBuffer::MapBuffer() {} + +MapBuffer::~MapBuffer() {} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/mapbuffer/MapBuffer.h b/ReactCommon/fabric/mapbuffer/MapBuffer.h new file mode 100644 index 00000000000000..e92a6f40635ac8 --- /dev/null +++ b/ReactCommon/fabric/mapbuffer/MapBuffer.h @@ -0,0 +1,37 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include + +namespace facebook { +namespace react { + +/** + * MapBuffer is an optimized map format for transferring data like props between + * C++ and other platforms The implemenation of this map is optimized to: + * - be compact to optimize space when sparse (sparse is the common case). + * - be accessible through JNI with zero/minimal copying via ByteBuffer. + * - be Have excellent C++ single-write and many-read performance by maximizing + * CPU cache performance through compactness, data locality, and fixed offsets + * where possible. + * - be optimized for iteration and intersection against other maps, but with + * reasonably good random access as well. + * - Work recursively for nested maps/arrays. + * - Supports dynamic types that map to JSON. + * - Don't require mutability - single-write on creation. + * - have minimal APK size and build time impact. + */ +class MapBuffer { + public: + MapBuffer(); + virtual ~MapBuffer(); +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/mapbuffer/tests/MapBufferTest.cpp b/ReactCommon/fabric/mapbuffer/tests/MapBufferTest.cpp new file mode 100644 index 00000000000000..591f24f22cf813 --- /dev/null +++ b/ReactCommon/fabric/mapbuffer/tests/MapBufferTest.cpp @@ -0,0 +1,14 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include + +TEST(MapBufferTest, testSomething) { + // TODO +} From 1148c03f6f51329710e23fba99a6916fff3ba42c Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Mon, 3 Jun 2019 01:49:51 -0700 Subject: [PATCH 0172/1084] Fixes wrong time unit of scroll event throttle (#25098) Summary: We need to use second for calculation, so change 17ms to 0.017s instead. ## Changelog [iOS] [Fixed] - Fixes wrong time unit of scroll event throttle Pull Request resolved: https://github.com/facebook/react-native/pull/25098 Reviewed By: sahrens, cpojer Differential Revision: D15576526 Pulled By: sammy-SC fbshipit-source-id: ddd8dd9098cbe582c6923ce8466892c363c090fc --- React/Views/ScrollView/RCTScrollView.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/React/Views/ScrollView/RCTScrollView.m b/React/Views/ScrollView/RCTScrollView.m index 7e73924379f80b..0e0b882a02c826 100644 --- a/React/Views/ScrollView/RCTScrollView.m +++ b/React/Views/ScrollView/RCTScrollView.m @@ -706,10 +706,10 @@ - (void)scrollViewDidScroll:(UIScrollView *)scrollView * warnings, and behave strangely (ListView works fine however), so don't fix it unless you fix that too! * * We limit the delta to 17ms so that small throttles intended to enable 60fps updates will not - * inadvertantly filter out any scroll events. + * inadvertently filter out any scroll events. */ if (_allowNextScrollNoMatterWhat || - (_scrollEventThrottle > 0 && _scrollEventThrottle < MAX(17, now - _lastScrollDispatchTime))) { + (_scrollEventThrottle > 0 && _scrollEventThrottle < MAX(0.017, now - _lastScrollDispatchTime))) { if (_DEPRECATED_sendUpdatedChildFrames) { // Calculate changed frames From b45d3b8697c6ed2ce5c6e4eac7bfd14553c79ed8 Mon Sep 17 00:00:00 2001 From: Michael Mason Date: Mon, 3 Jun 2019 06:46:45 -0700 Subject: [PATCH 0173/1084] - Fix missing whitespace in debug instructions (#25122) Summary: Fixes minor whitespace issue with the new new-app template. ## Changelog [Android] [Fixed] - Fix missing whitespace in debug instructions Pull Request resolved: https://github.com/facebook/react-native/pull/25122 Differential Revision: D15602100 Pulled By: cpojer fbshipit-source-id: 07c51c6359e37826941de659bcedea692ff3315a --- Libraries/NewAppScreen/components/DebugInstructions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libraries/NewAppScreen/components/DebugInstructions.js b/Libraries/NewAppScreen/components/DebugInstructions.js index 821f7cbde710f3..3953b442d1bd57 100644 --- a/Libraries/NewAppScreen/components/DebugInstructions.js +++ b/Libraries/NewAppScreen/components/DebugInstructions.js @@ -27,7 +27,7 @@ const DebugInstructions = Platform.select({ ), default: () => ( - Press menu button or + Press menu button or{' '} Shake your device to open the React Native debug menu. From d8fa1206c3fecd494b0f6abb63c66488e6ced5e0 Mon Sep 17 00:00:00 2001 From: Dratwas Date: Mon, 3 Jun 2019 07:08:42 -0700 Subject: [PATCH 0174/1084] fix indexed RAM bundle (#24967) Summary: Co-Authored: zamotany With React Native 0.59.8 the app keeps crashing with indexed RAM bundle on Android with the following error: ``` 2019-05-09 11:58:06.684 2793-2856/? E/AndroidRuntime: FATAL EXCEPTION: mqt_js Process: com.ramtestapp, PID: 2793 com.facebook.jni.CppException: getPropertyAsObject: property '__fbRequireBatchedBridge' is not an Object no stack at com.facebook.react.bridge.queue.NativeRunnable.run(Native Method) at android.os.Handler.handleCallback(Handler.java:873) at android.os.Handler.dispatchMessage(Handler.java:99) at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:29) at android.os.Looper.loop(Looper.java:193) at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:232) at java.lang.Thread.run(Thread.java:764) ``` After investigation we found that when using any bundle, let it be non-ram, FIle RAM bundle or Index RAM bundle, the `CatalystInstanceImpl.java` is always using `loadScriptsFromAsset`, which is calling `CatalystInstanceImpl::jniLoadScriptFromAssets` in C++. This method when checking if bundle is a RAM bundle, uses `JniJSModulesUnbundle::isUnbundle` which only check for js-modules/UNBUNDLE - file generated when building File RAM bundle. There is no other logic to handle Indexed RAM bundle, so it figures that the bundle is not RAM, cause there is no js-modules/UNBUNDLE file and tries to load as regular bundle and fails. In this PR we added check if it is indexed RAM bundle in `jniLoadScriptFromAssets` and handle it if it is. ## Changelog [Android] [Fixed] fix indexed RAM bundle Solves https://github.com/facebook/react-native/issues/21282 Pull Request resolved: https://github.com/facebook/react-native/pull/24967 Differential Revision: D15575924 Pulled By: cpojer fbshipit-source-id: 5ea428e0b793edd8242243f39f933d1092b35260 --- .../jni/react/jni/CatalystInstanceImpl.cpp | 2 ++ ReactCommon/cxxreact/Instance.cpp | 18 ++++++++++ ReactCommon/cxxreact/Instance.h | 2 ++ ReactCommon/cxxreact/JSIndexedRAMBundle.cpp | 35 ++++++++++++++----- ReactCommon/cxxreact/JSIndexedRAMBundle.h | 8 +++-- 5 files changed, 53 insertions(+), 12 deletions(-) diff --git a/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp b/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp index 06a224f457ab50..28de85f7ba2f22 100644 --- a/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp +++ b/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp @@ -199,6 +199,8 @@ void CatalystInstanceImpl::jniLoadScriptFromAssets( sourceURL, loadSynchronously); return; + } else if (Instance::isIndexedRAMBundle(&script)) { + instance_->loadRAMBundleFromString(std::move(script), sourceURL); } else { instance_->loadScriptFromString(std::move(script), sourceURL, loadSynchronously); } diff --git a/ReactCommon/cxxreact/Instance.cpp b/ReactCommon/cxxreact/Instance.cpp index ad5069238d6e32..81996813893b92 100644 --- a/ReactCommon/cxxreact/Instance.cpp +++ b/ReactCommon/cxxreact/Instance.cpp @@ -108,6 +108,24 @@ bool Instance::isIndexedRAMBundle(const char *sourcePath) { return parseTypeFromHeader(header) == ScriptTag::RAMBundle; } +bool Instance::isIndexedRAMBundle(std::unique_ptr* script) { + BundleHeader header; + strncpy(reinterpret_cast(&header), script->get()->c_str(), sizeof(header)); + + return parseTypeFromHeader(header) == ScriptTag::RAMBundle; +} + +void Instance::loadRAMBundleFromString(std::unique_ptr script, const std::string& sourceURL) { + auto bundle = folly::make_unique(std::move(script)); + auto startupScript = bundle->getStartupCode(); + auto registry = RAMBundleRegistry::singleBundleRegistry(std::move(bundle)); + loadRAMBundle( + std::move(registry), + std::move(startupScript), + sourceURL, + true); +} + void Instance::loadRAMBundleFromFile(const std::string& sourcePath, const std::string& sourceURL, bool loadSynchronously) { diff --git a/ReactCommon/cxxreact/Instance.h b/ReactCommon/cxxreact/Instance.h index b72729660ff601..b129ee7e633287 100644 --- a/ReactCommon/cxxreact/Instance.h +++ b/ReactCommon/cxxreact/Instance.h @@ -47,6 +47,8 @@ class RN_EXPORT Instance { void loadScriptFromString(std::unique_ptr string, std::string sourceURL, bool loadSynchronously); static bool isIndexedRAMBundle(const char *sourcePath); + static bool isIndexedRAMBundle(std::unique_ptr* string); + void loadRAMBundleFromString(std::unique_ptr script, const std::string& sourceURL); void loadRAMBundleFromFile(const std::string& sourcePath, const std::string& sourceURL, bool loadSynchronously); diff --git a/ReactCommon/cxxreact/JSIndexedRAMBundle.cpp b/ReactCommon/cxxreact/JSIndexedRAMBundle.cpp index 6c2e7e87c7eb26..65c73a11aef7c5 100644 --- a/ReactCommon/cxxreact/JSIndexedRAMBundle.cpp +++ b/ReactCommon/cxxreact/JSIndexedRAMBundle.cpp @@ -6,7 +6,8 @@ #include "JSIndexedRAMBundle.h" #include - +#include +#include #include namespace facebook { @@ -18,14 +19,30 @@ std::function(std::string)> JSIndexedRAMBundl }; } -JSIndexedRAMBundle::JSIndexedRAMBundle(const char *sourcePath) : - m_bundle (sourcePath, std::ios_base::in) { +JSIndexedRAMBundle::JSIndexedRAMBundle(const char *sourcePath) { + m_bundle = std::make_unique(sourcePath, std::ifstream::binary); if (!m_bundle) { throw std::ios_base::failure( folly::to("Bundle ", sourcePath, - "cannot be opened: ", m_bundle.rdstate())); + "cannot be opened: ", m_bundle->rdstate())); } + init(); +} + +JSIndexedRAMBundle::JSIndexedRAMBundle(std::unique_ptr script) { + // tmpStream is needed because m_bundle is std::istream type + // which has no member 'write' + std::unique_ptr tmpStream = std::make_unique(); + tmpStream->write(script->c_str(), script->size()); + m_bundle = std::move(tmpStream); + if (!m_bundle) { + throw std::ios_base::failure( + folly::to("Bundle from string cannot be opened: ", m_bundle->rdstate())); + } + init(); +} +void JSIndexedRAMBundle::init() { // read in magic header, number of entries, and length of the startup section uint32_t header[3]; static_assert( @@ -78,12 +95,12 @@ std::string JSIndexedRAMBundle::getModuleCode(const uint32_t id) const { } void JSIndexedRAMBundle::readBundle(char *buffer, const std::streamsize bytes) const { - if (!m_bundle.read(buffer, bytes)) { - if (m_bundle.rdstate() & std::ios::eofbit) { + if (!m_bundle->read(buffer, bytes)) { + if (m_bundle->rdstate() & std::ios::eofbit) { throw std::ios_base::failure("Unexpected end of RAM Bundle file"); } throw std::ios_base::failure( - folly::to("Error reading RAM Bundle: ", m_bundle.rdstate())); + folly::to("Error reading RAM Bundle: ", m_bundle->rdstate())); } } @@ -92,9 +109,9 @@ void JSIndexedRAMBundle::readBundle( const std::streamsize bytes, const std::ifstream::pos_type position) const { - if (!m_bundle.seekg(position)) { + if (!m_bundle->seekg(position)) { throw std::ios_base::failure( - folly::to("Error reading RAM Bundle: ", m_bundle.rdstate())); + folly::to("Error reading RAM Bundle: ", m_bundle->rdstate())); } readBundle(buffer, bytes); } diff --git a/ReactCommon/cxxreact/JSIndexedRAMBundle.h b/ReactCommon/cxxreact/JSIndexedRAMBundle.h index be6b27f7a84576..2f2db3b708fc26 100644 --- a/ReactCommon/cxxreact/JSIndexedRAMBundle.h +++ b/ReactCommon/cxxreact/JSIndexedRAMBundle.h @@ -5,7 +5,7 @@ #pragma once -#include +#include #include #include @@ -24,6 +24,7 @@ class RN_EXPORT JSIndexedRAMBundle : public JSModulesUnbundle { // Throws std::runtime_error on failure. JSIndexedRAMBundle(const char *sourceURL); + JSIndexedRAMBundle(std::unique_ptr script); // Throws std::runtime_error on failure. std::unique_ptr getStartupCode(); @@ -51,14 +52,15 @@ class RN_EXPORT JSIndexedRAMBundle : public JSModulesUnbundle { } }; + void init(); std::string getModuleCode(const uint32_t id) const; void readBundle(char *buffer, const std::streamsize bytes) const; void readBundle( char *buffer, const std::streamsize bytes, - const std::ifstream::pos_type position) const; + const std::istream::pos_type position) const; - mutable std::ifstream m_bundle; + mutable std::unique_ptr m_bundle; ModuleTable m_table; size_t m_baseOffset; std::unique_ptr m_startupCode; From ebb8caa4df2b6559ae9ed7cc532c7ff5a6c17e8d Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Mon, 3 Jun 2019 07:15:13 -0700 Subject: [PATCH 0175/1084] Add handling for ColorArray Summary: This diff adds support for ColorArrayValue in the flow parser Reviewed By: cpojer Differential Revision: D15502923 fbshipit-source-id: 6a906b6d609168378fabeb49d0080de011a34d78 --- .../getNativeComponentAttributes.js | 5 +- Libraries/StyleSheet/StyleSheetTypes.js | 1 + Libraries/StyleSheet/processColorArray.js | 19 ++ .../src/generators/GenerateViewConfigJs.js | 168 ++++++++++-------- .../GenerateViewConfigJs-test.js.snap | 2 +- .../flow/__test_fixtures__/fixtures.js | 8 +- .../__snapshots__/parser-test.js.snap | 44 +++++ .../src/parsers/flow/props.js | 8 + 8 files changed, 176 insertions(+), 79 deletions(-) create mode 100644 Libraries/StyleSheet/processColorArray.js diff --git a/Libraries/ReactNative/getNativeComponentAttributes.js b/Libraries/ReactNative/getNativeComponentAttributes.js index 85a347bea1f358..9dba82c47507e4 100644 --- a/Libraries/ReactNative/getNativeComponentAttributes.js +++ b/Libraries/ReactNative/getNativeComponentAttributes.js @@ -17,6 +17,7 @@ const insetsDiffer = require('../Utilities/differ/insetsDiffer'); const matricesDiffer = require('../Utilities/differ/matricesDiffer'); const pointsDiffer = require('../Utilities/differ/pointsDiffer'); const processColor = require('../StyleSheet/processColor'); +const processColorArray = require('../StyleSheet/processColorArray'); const resolveAssetSource = require('../Image/resolveAssetSource'); const sizesDiffer = require('../Utilities/differ/sizesDiffer'); const invariant = require('invariant'); @@ -182,8 +183,4 @@ function getProcessorForType(typeName: string): ?(nextProp: any) => any { return null; } -function processColorArray(colors: ?Array): ?Array { - return colors == null ? null : colors.map(processColor); -} - module.exports = getNativeComponentAttributes; diff --git a/Libraries/StyleSheet/StyleSheetTypes.js b/Libraries/StyleSheet/StyleSheetTypes.js index 39819d5e6b4eb7..9da10526c2363e 100644 --- a/Libraries/StyleSheet/StyleSheetTypes.js +++ b/Libraries/StyleSheet/StyleSheetTypes.js @@ -13,6 +13,7 @@ const AnimatedNode = require('../Animated/src/nodes/AnimatedNode'); export type ColorValue = null | string; +export type ColorArrayValue = null | $ReadOnlyArray; export type PointValue = {| x: number, y: number, diff --git a/Libraries/StyleSheet/processColorArray.js b/Libraries/StyleSheet/processColorArray.js new file mode 100644 index 00000000000000..711dc32aee5413 --- /dev/null +++ b/Libraries/StyleSheet/processColorArray.js @@ -0,0 +1,19 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow strict-local + */ + +'use strict'; + +const processColor = require('./processColor'); + +function processColorArray(colors: ?Array): ?Array { + return colors == null ? null : colors.map(processColor); +} + +module.exports = processColorArray; diff --git a/packages/react-native-codegen/src/generators/GenerateViewConfigJs.js b/packages/react-native-codegen/src/generators/GenerateViewConfigJs.js index 3315d1a29d1349..d5e1583ea2bccc 100644 --- a/packages/react-native-codegen/src/generators/GenerateViewConfigJs.js +++ b/packages/react-native-codegen/src/generators/GenerateViewConfigJs.js @@ -34,15 +34,12 @@ const template = ` ::_COMPONENT_CONFIG_:: `; -function getReactDiffProcessValue(prop) { - const typeAnnotation = prop.typeAnnotation; - +function getReactDiffProcessValue(typeAnnotation) { switch (typeAnnotation.type) { case 'BooleanTypeAnnotation': case 'StringTypeAnnotation': case 'Int32TypeAnnotation': case 'FloatTypeAnnotation': - case 'ArrayTypeAnnotation': case 'StringEnumTypeAnnotation': return j.literal(true); case 'NativePrimitiveTypeAnnotation': @@ -60,6 +57,25 @@ function getReactDiffProcessValue(prop) { `Received unknown native typeAnnotation: "${typeAnnotation.name}"`, ); } + case 'ArrayTypeAnnotation': + if (typeAnnotation.elementType.type === 'NativePrimitiveTypeAnnotation') { + switch (typeAnnotation.elementType.name) { + case 'ColorPrimitive': + return j.template + .expression`{ process: require('processColorArray') }`; + case 'ImageSourcePrimitive': + return j.literal(true); + case 'PointPrimitive': + return j.literal(true); + default: + throw new Error( + `Received unknown array native typeAnnotation: "${ + typeAnnotation.elementType.name + }"`, + ); + } + } + return j.literal(true); default: (typeAnnotation: empty); throw new Error( @@ -194,7 +210,7 @@ function buildViewConfig( return j.property( 'init', j.identifier(schemaProp.name), - getReactDiffProcessValue(schemaProp), + getReactDiffProcessValue(schemaProp.typeAnnotation), ); }), ...getValidAttributesForEvents(componentEvents), @@ -253,76 +269,82 @@ function buildViewConfig( module.exports = { generate(libraryName: string, schema: SchemaType): FilesOutput { - const fileName = `${libraryName}NativeViewConfig.js`; - const imports: Set = new Set(); - - imports.add( - "const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry');", - ); - imports.add( - "const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence');", - ); - - const moduleResults = Object.keys(schema.modules) - .map(moduleName => { - const components = schema.modules[moduleName].components; - // No components in this module - if (components == null) { - return null; - } + try { + const fileName = `${libraryName}NativeViewConfig.js`; + const imports: Set = new Set(); - return Object.keys(components) - .map(componentName => { - const component = components[componentName]; - - const compatabilityComponentName = `${ - component.isDeprecatedPaperComponentNameRCT ? 'RCT' : '' - }${componentName}`; - - const replacedTemplate = componentTemplate - .replace(/::_COMPONENT_NAME_::/g, componentName) - .replace( - /::_COMPONENT_NAME_WITH_COMPAT_SUPPORT_::/g, - compatabilityComponentName, - ) - .replace( - /::_COMPAT_COMMENT_::/g, - component.isDeprecatedPaperComponentNameRCT - ? ' // RCT prefix present for paper support' - : '', - ); - - const replacedSource: string = j - .withParser('flow')(replacedTemplate) - .find(j.Identifier, { - name: 'VIEW_CONFIG', - }) - .replaceWith( - buildViewConfig( - schema, - compatabilityComponentName, - component, - imports, - ), - ) - .toSource({quote: 'single', trailingComma: true}); - - return replacedSource; - }) - .join('\n\n'); - }) - .filter(Boolean) - .join('\n\n'); - - const replacedTemplate = template - .replace(/::_COMPONENT_CONFIG_::/g, moduleResults) - .replace( - '::_IMPORTS_::', - Array.from(imports) - .sort() - .join('\n'), + imports.add( + "const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry');", + ); + imports.add( + "const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence');", ); - return new Map([[fileName, replacedTemplate]]); + const moduleResults = Object.keys(schema.modules) + .map(moduleName => { + const components = schema.modules[moduleName].components; + // No components in this module + if (components == null) { + return null; + } + + return Object.keys(components) + .map(componentName => { + const component = components[componentName]; + + const compatabilityComponentName = `${ + component.isDeprecatedPaperComponentNameRCT ? 'RCT' : '' + }${componentName}`; + + const replacedTemplate = componentTemplate + .replace(/::_COMPONENT_NAME_::/g, componentName) + .replace( + /::_COMPONENT_NAME_WITH_COMPAT_SUPPORT_::/g, + compatabilityComponentName, + ) + .replace( + /::_COMPAT_COMMENT_::/g, + component.isDeprecatedPaperComponentNameRCT + ? ' // RCT prefix present for paper support' + : '', + ); + + const replacedSource: string = j + .withParser('flow')(replacedTemplate) + .find(j.Identifier, { + name: 'VIEW_CONFIG', + }) + .replaceWith( + buildViewConfig( + schema, + compatabilityComponentName, + component, + imports, + ), + ) + .toSource({quote: 'single', trailingComma: true}); + + return replacedSource; + }) + .join('\n\n'); + }) + .filter(Boolean) + .join('\n\n'); + + const replacedTemplate = template + .replace(/::_COMPONENT_CONFIG_::/g, moduleResults) + .replace( + '::_IMPORTS_::', + Array.from(imports) + .sort() + .join('\n'), + ); + + return new Map([[fileName, replacedTemplate]]); + } catch (error) { + console.error(`\nError parsing schema for ${libraryName}\n`); + console.error(JSON.stringify(schema)); + throw error; + } }, }; diff --git a/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap b/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap index 8e7ec6e5fb590e..729bfac1050bf9 100644 --- a/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap +++ b/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap @@ -36,7 +36,7 @@ const ArrayPropsNativeComponentViewConfig = { disableds: true, progress: true, radii: true, - colors: true, + colors: { process: require('processColorArray') }, srcs: true, points: true, }, diff --git a/packages/react-native-codegen/src/parsers/flow/__test_fixtures__/fixtures.js b/packages/react-native-codegen/src/parsers/flow/__test_fixtures__/fixtures.js index 5fbef12ed35c10..d971d6dba4e5dc 100644 --- a/packages/react-native-codegen/src/parsers/flow/__test_fixtures__/fixtures.js +++ b/packages/react-native-codegen/src/parsers/flow/__test_fixtures__/fixtures.js @@ -122,7 +122,7 @@ import type { CodegenNativeComponent, } from 'CodegenFlowtypes'; -import type {ColorValue, PointValue} from 'StyleSheetTypes'; +import type {ColorValue, ColorArrayValue, PointValue} from 'StyleSheetTypes'; import type {ImageSource} from 'ImageSource'; import type {ViewProps} from 'ViewPropTypes'; @@ -171,6 +171,12 @@ type ModuleProps = $ReadOnly<{| color_optional_value: ?ColorValue, color_optional_both?: ?ColorValue, + // ColorArrayValue props + color_array_required: ColorArrayValue, + color_array_optional_key?: ColorArrayValue, + color_array_optional_value: ?ColorArrayValue, + color_array_optional_both?: ?ColorArrayValue, + // PointValue props point_required: PointValue, point_optional_key?: PointValue, diff --git a/packages/react-native-codegen/src/parsers/flow/__tests__/__snapshots__/parser-test.js.snap b/packages/react-native-codegen/src/parsers/flow/__tests__/__snapshots__/parser-test.js.snap index 527f9edd44c68a..8feeb11c71c60e 100644 --- a/packages/react-native-codegen/src/parsers/flow/__tests__/__snapshots__/parser-test.js.snap +++ b/packages/react-native-codegen/src/parsers/flow/__tests__/__snapshots__/parser-test.js.snap @@ -262,6 +262,50 @@ Object { "type": "NativePrimitiveTypeAnnotation", }, }, + Object { + "name": "color_array_required", + "optional": false, + "typeAnnotation": Object { + "elementType": Object { + "name": "ColorPrimitive", + "type": "NativePrimitiveTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "color_array_optional_key", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "name": "ColorPrimitive", + "type": "NativePrimitiveTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "color_array_optional_value", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "name": "ColorPrimitive", + "type": "NativePrimitiveTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "color_array_optional_both", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "name": "ColorPrimitive", + "type": "NativePrimitiveTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, Object { "name": "point_required", "optional": false, diff --git a/packages/react-native-codegen/src/parsers/flow/props.js b/packages/react-native-codegen/src/parsers/flow/props.js index e7d5e16d7daf7f..222b2ca014b12c 100644 --- a/packages/react-native-codegen/src/parsers/flow/props.js +++ b/packages/react-native-codegen/src/parsers/flow/props.js @@ -105,6 +105,14 @@ function getTypeAnnotation(name, typeAnnotation, defaultValue) { type: 'NativePrimitiveTypeAnnotation', name: 'ColorPrimitive', }; + case 'ColorArrayValue': + return { + type: 'ArrayTypeAnnotation', + elementType: { + type: 'NativePrimitiveTypeAnnotation', + name: 'ColorPrimitive', + }, + }; case 'PointValue': return { type: 'NativePrimitiveTypeAnnotation', From 93dc403e1bf2bcfb24a4ba10e760f88f19eaf96c Mon Sep 17 00:00:00 2001 From: spdr admin Date: Mon, 3 Jun 2019 07:25:55 -0700 Subject: [PATCH 0176/1084] Fix RNTest TVOS target (#25110) Summary: I noticed that the RNTester-tvOS target is not compilable when I wanted to test the TVOS capacity of React Native. More specifically, the changes included in this PR are: ### RNTester-tvOS target 1. Add `AppDelegate.mm` to the target. 2. Add `.m` files under `turbomodule` to the target. 3. Add the following directories to **header search path**. ``` $(SRCROOT)/../third-party/boost_1_63_0 $(SRCROOT)/../third-party/folly-2018.10.22.00 $(SRCROOT)/../third-party/glog-0.3.5/src ``` 4. Add `RN_BUNDLE_PREFIX` to the scheme argument. 5. Add `RN_BUNDLE_PREFIX` entry to the plist file. ### React-tvOS target 1. Add `RCTCxxBridgeDelegate.h` and `JSCExecutorFactory.h` to the **Copy headers**. ## Changelog [iOS] [Fixed] - Fixed the issue that the RNTester-tvOS is not compilable. Pull Request resolved: https://github.com/facebook/react-native/pull/25110 Differential Revision: D15602450 Pulled By: cpojer fbshipit-source-id: e7eda18c8193b7d88355feafa69043ffef4a8edb --- RNTester/RNTester-tvOS/Info.plist | 2 ++ RNTester/RNTester.xcodeproj/project.pbxproj | 16 ++++++++++++++++ .../xcschemes/RNTester-tvOS.xcscheme | 4 ++++ React/React.xcodeproj/project.pbxproj | 4 ++++ 4 files changed, 26 insertions(+) diff --git a/RNTester/RNTester-tvOS/Info.plist b/RNTester/RNTester-tvOS/Info.plist index 0afedbb816c675..1f05733996acbd 100644 --- a/RNTester/RNTester-tvOS/Info.plist +++ b/RNTester/RNTester-tvOS/Info.plist @@ -31,5 +31,7 @@ UIUserInterfaceStyle Automatic + RN_BUNDLE_PREFIX + $(RN_BUNDLE_PREFIX) diff --git a/RNTester/RNTester.xcodeproj/project.pbxproj b/RNTester/RNTester.xcodeproj/project.pbxproj index 52cacf2394b200..173e82ed750f47 100644 --- a/RNTester/RNTester.xcodeproj/project.pbxproj +++ b/RNTester/RNTester.xcodeproj/project.pbxproj @@ -111,6 +111,9 @@ 3D56F9F11D6F6E9B00F53A06 /* RNTesterBundle.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 3D13F83E1D6F6AE000E69E0E /* RNTesterBundle.bundle */; }; 3DB99D0C1BA0340600302749 /* RNTesterIntegrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DB99D0B1BA0340600302749 /* RNTesterIntegrationTests.m */; }; 3DD981D61D33C6FB007DC7BE /* RNTesterUnitTestsBundle.js in Resources */ = {isa = PBXBuildFile; fileRef = 3DD981D51D33C6FB007DC7BE /* RNTesterUnitTestsBundle.js */; }; + 3FCC247D22A2333F0013B22F /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5C60EB582264416A0018C04F /* AppDelegate.mm */; }; + 3FCC24AA22A25DF80013B22F /* RCTNativeSampleTurboModuleSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5C2B71152267DB1A0066069E /* RCTNativeSampleTurboModuleSpec.mm */; }; + 3FCC24AB22A25DFF0013B22F /* RCTSampleTurboModule.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5C2B711A2267DB1A0066069E /* RCTSampleTurboModule.mm */; }; 52C11BBB1EEACA7100C1A058 /* libRCTBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5281CA511EEAC9A700AC40CD /* libRCTBlob.a */; }; 52C11BE11EEACA7800C1A058 /* libRCTBlob-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5281CA531EEAC9A700AC40CD /* libRCTBlob-tvOS.a */; }; 5C2B71672267DB1A0066069E /* RCTNativeSampleTurboModuleSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5C2B71152267DB1A0066069E /* RCTNativeSampleTurboModuleSpec.mm */; }; @@ -1772,8 +1775,11 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 3FCC24AB22A25DFF0013B22F /* RCTSampleTurboModule.mm in Sources */, 2DD323DC1DA2DDBF000FE1B8 /* FlexibleSizeExampleView.m in Sources */, 2DD323DD1DA2DDBF000FE1B8 /* UpdatePropertiesExampleView.m in Sources */, + 3FCC247D22A2333F0013B22F /* AppDelegate.mm in Sources */, + 3FCC24AA22A25DF80013B22F /* RCTNativeSampleTurboModuleSpec.mm in Sources */, 2DD323E01DA2DDBF000FE1B8 /* main.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2025,6 +2031,11 @@ CLANG_WARN_SUSPICIOUS_MOVES = YES; DEBUG_INFORMATION_FORMAT = dwarf; GCC_NO_COMMON_BLOCKS = YES; + HEADER_SEARCH_PATHS = ( + "$(SRCROOT)/../third-party/boost_1_63_0", + "$(SRCROOT)/../third-party/folly-2018.10.22.00", + "$(SRCROOT)/../third-party/glog-0.3.5/src", + ); INFOPLIST_FILE = "RNTester-tvOS/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.RNTester-tvOS"; @@ -2045,6 +2056,11 @@ COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_NO_COMMON_BLOCKS = YES; + HEADER_SEARCH_PATHS = ( + "$(SRCROOT)/../third-party/boost_1_63_0", + "$(SRCROOT)/../third-party/folly-2018.10.22.00", + "$(SRCROOT)/../third-party/glog-0.3.5/src", + ); INFOPLIST_FILE = "RNTester-tvOS/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.RNTester-tvOS"; diff --git a/RNTester/RNTester.xcodeproj/xcshareddata/xcschemes/RNTester-tvOS.xcscheme b/RNTester/RNTester.xcodeproj/xcshareddata/xcschemes/RNTester-tvOS.xcscheme index 0c3555d5cfc2c5..a2fbdcf6be9aed 100644 --- a/RNTester/RNTester.xcodeproj/xcshareddata/xcschemes/RNTester-tvOS.xcscheme +++ b/RNTester/RNTester.xcodeproj/xcshareddata/xcschemes/RNTester-tvOS.xcscheme @@ -101,6 +101,10 @@ value = "1" isEnabled = "YES"> + + diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj index c04e4dd50c16c1..45439f6e31f41f 100644 --- a/React/React.xcodeproj/project.pbxproj +++ b/React/React.xcodeproj/project.pbxproj @@ -793,6 +793,8 @@ 3DFE0D1B1DF8575800459392 /* YGMacros.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 130A77041DF767AF001F9587 /* YGMacros.h */; }; 3DFE0D1C1DF8575800459392 /* Yoga.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 130A77081DF767AF001F9587 /* Yoga.h */; }; 3EDCA8A51D3591E700450C31 /* RCTErrorInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 3EDCA8A41D3591E700450C31 /* RCTErrorInfo.m */; }; + 3FCC24A822A24FCC0013B22F /* JSCExecutorFactory.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 8507BBBD21EDACC200AEAFCA /* JSCExecutorFactory.h */; }; + 3FCC24A922A24FD90013B22F /* RCTCxxBridgeDelegate.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 134D63C21F1FEC4B008872B5 /* RCTCxxBridgeDelegate.h */; }; 4F56C93822167A4800DB9F3F /* jsi/jsilib.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F56C93722167A4800DB9F3F /* jsi/jsilib.h */; }; 4F56C93922167A4D00DB9F3F /* jsi/jsilib.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 4F56C93722167A4800DB9F3F /* jsi/jsilib.h */; }; 4F56C93A2216A3B700DB9F3F /* jsi/jsilib.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 4F56C93722167A4800DB9F3F /* jsi/jsilib.h */; }; @@ -1344,6 +1346,8 @@ dstPath = include/React; dstSubfolderSpec = 16; files = ( + 3FCC24A922A24FD90013B22F /* RCTCxxBridgeDelegate.h in Copy Headers */, + 3FCC24A822A24FCC0013B22F /* JSCExecutorFactory.h in Copy Headers */, 0EA924D02237686F004AB895 /* RCTSurfacePresenterStub.h in Copy Headers */, 591F78DF202ADB97004A668C /* RCTLayout.h in Copy Headers */, 59EDBCC31FDF4E55003573DE /* RCTScrollableProtocol.h in Copy Headers */, From 1e428093e2d959d415e228b1c0e12ddd569aff89 Mon Sep 17 00:00:00 2001 From: Bruno Lemos Date: Mon, 3 Jun 2019 07:30:56 -0700 Subject: [PATCH 0177/1084] Fix ItemSeparatorComponent's leadingItem prop not being updated (#25114) Summary: Fix https://github.com/facebook/react-native/issues/24592 Just added a `getDerivedStateFromProps`, similar to what `VirtualizedSectionList` already does: https://github.com/facebook/react-native/blob/18fededae085b53b01e54a7ed27e32c2318e7cae/Libraries/Lists/VirtualizedSectionList.js#L470-L492 ## Changelog [General] [Fixed] - Fix ItemSeparatorComponent's leadingItem prop not being updated Pull Request resolved: https://github.com/facebook/react-native/pull/25114 Differential Revision: D15602460 Pulled By: cpojer fbshipit-source-id: b16a82912fd746a956f6aa360d18ade53357f634 --- Libraries/Lists/VirtualizedList.js | 61 ++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/Libraries/Lists/VirtualizedList.js b/Libraries/Lists/VirtualizedList.js index 0281d87c8a3418..d060dbf9fa6d28 100644 --- a/Libraries/Lists/VirtualizedList.js +++ b/Libraries/Lists/VirtualizedList.js @@ -1667,27 +1667,36 @@ class VirtualizedList extends React.PureComponent { } } -class CellRenderer extends React.Component< - { - CellRendererComponent?: ?React.ComponentType, - ItemSeparatorComponent: ?React.ComponentType<*>, - cellKey: string, - fillRateHelper: FillRateHelper, - horizontal: ?boolean, - index: number, - inversionStyle: ViewStyleProp, - item: Item, - onLayout: (event: Object) => void, // This is extracted by ScrollViewStickyHeader - onUnmount: (cellKey: string) => void, - onUpdateSeparators: (cellKeys: Array, props: Object) => void, - parentProps: { - getItemLayout?: ?Function, - renderItem?: ?RenderItemType, - ListItemComponent?: ?(React.ComponentType | React.Element), - }, - prevCellKey: ?string, +type CellRendererProps = { + CellRendererComponent?: ?React.ComponentType, + ItemSeparatorComponent: ?React.ComponentType<*>, + cellKey: string, + fillRateHelper: FillRateHelper, + horizontal: ?boolean, + index: number, + inversionStyle: ViewStyleProp, + item: Item, + onLayout: (event: Object) => void, // This is extracted by ScrollViewStickyHeader + onUnmount: (cellKey: string) => void, + onUpdateSeparators: (cellKeys: Array, props: Object) => void, + parentProps: { + getItemLayout?: ?Function, + renderItem?: ?RenderItemType, + ListItemComponent?: ?(React.ComponentType | React.Element), }, - $FlowFixMeState, + prevCellKey: ?string, +}; + +type CellRendererState = { + separatorProps: $ReadOnly<{| + highlighted: boolean, + leadingItem: ?Item, + |}>, +}; + +class CellRenderer extends React.Component< + CellRendererProps, + CellRendererState, > { state = { separatorProps: { @@ -1702,6 +1711,18 @@ class CellRenderer extends React.Component< }), }; + static getDerivedStateFromProps( + props: CellRendererProps, + prevState: CellRendererState, + ): ?CellRendererState { + return { + separatorProps: { + ...prevState.separatorProps, + leadingItem: props.item, + }, + }; + } + getChildContext() { return { virtualizedCell: { From a98772e94c07e08074cf5a2c102fcb2055a72153 Mon Sep 17 00:00:00 2001 From: Hermanyo Date: Mon, 3 Jun 2019 07:54:53 -0700 Subject: [PATCH 0178/1084] more code review (#25109) Summary: ## Changelog [Internal] [Changed] - Code review Pull Request resolved: https://github.com/facebook/react-native/pull/25109 Differential Revision: D15602426 Pulled By: cpojer fbshipit-source-id: a47e3d6e0b264b24cc1106a34a7cfdafdadca799 --- .../modules/camera/CameraRollManager.java | 38 ++++++++++--------- .../modules/vibration/VibrationModule.java | 9 ++--- .../modules/websocket/WebSocketModule.java | 19 +++++++--- 3 files changed, 38 insertions(+), 28 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/camera/CameraRollManager.java b/ReactAndroid/src/main/java/com/facebook/react/modules/camera/CameraRollManager.java index 7356b048c19525..257802675493c2 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/camera/CameraRollManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/camera/CameraRollManager.java @@ -293,23 +293,27 @@ protected void doInBackgroundGuarded(Void... params) { selectionArgs.add(mGroupName); } - if (mAssetType.equals(ASSET_TYPE_PHOTOS)) { - selection.append(" AND " + MediaStore.Files.FileColumns.MEDIA_TYPE + " = " - + MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE); - } else if (mAssetType.equals(ASSET_TYPE_VIDEOS)) { - selection.append(" AND " + MediaStore.Files.FileColumns.MEDIA_TYPE + " = " - + MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO); - } else if (mAssetType.equals(ASSET_TYPE_ALL)) { - selection.append(" AND " + MediaStore.Files.FileColumns.MEDIA_TYPE + " IN (" - + MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO + "," - + MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE + ")"); - } else { - mPromise.reject( - ERROR_UNABLE_TO_FILTER, - "Invalid filter option: '" + mAssetType + "'. Expected one of '" - + ASSET_TYPE_PHOTOS + "', '" + ASSET_TYPE_VIDEOS + "' or '" + ASSET_TYPE_ALL + "'." - ); - return; + switch (mAssetType) { + case ASSET_TYPE_PHOTOS: + selection.append(" AND " + MediaStore.Files.FileColumns.MEDIA_TYPE + " = " + + MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE); + break; + case ASSET_TYPE_VIDEOS: + selection.append(" AND " + MediaStore.Files.FileColumns.MEDIA_TYPE + " = " + + MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO); + break; + case ASSET_TYPE_ALL: + selection.append(" AND " + MediaStore.Files.FileColumns.MEDIA_TYPE + " IN (" + + MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO + "," + + MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE + ")"); + break; + default: + mPromise.reject( + ERROR_UNABLE_TO_FILTER, + "Invalid filter option: '" + mAssetType + "'. Expected one of '" + + ASSET_TYPE_PHOTOS + "', '" + ASSET_TYPE_VIDEOS + "' or '" + ASSET_TYPE_ALL + "'." + ); + return; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/vibration/VibrationModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/vibration/VibrationModule.java index 153f800f775f2e..161a7cc19cc574 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/vibration/VibrationModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/vibration/VibrationModule.java @@ -42,13 +42,12 @@ public void vibrate(int duration) { @ReactMethod public void vibrateByPattern(ReadableArray pattern, int repeat) { - long[] patternLong = new long[pattern.size()]; - for (int i = 0; i < pattern.size(); i++) { - patternLong[i] = pattern.getInt(i); - } - Vibrator v = (Vibrator) getReactApplicationContext().getSystemService(Context.VIBRATOR_SERVICE); if (v != null) { + long[] patternLong = new long[pattern.size()]; + for (int i = 0; i < pattern.size(); i++) { + patternLong[i] = pattern.getInt(i); + } v.vibrate(patternLong, repeat); } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java index f28f271f7f043a..c2c4021ed3c243 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java @@ -342,12 +342,19 @@ private static String getDefaultOrigin(String uri) { String scheme = ""; URI requestURI = new URI(uri); - if (requestURI.getScheme().equals("wss")) { - scheme += "https"; - } else if (requestURI.getScheme().equals("ws")) { - scheme += "http"; - } else if (requestURI.getScheme().equals("http") || requestURI.getScheme().equals("https")) { - scheme += requestURI.getScheme(); + switch (requestURI.getScheme()) { + case "wss": + scheme += "https"; + break; + case "ws": + scheme += "http"; + break; + case "http": + case "https": + scheme += requestURI.getScheme(); + break; + default: + break; } if (requestURI.getPort() != -1) { From 7f489b63f201f65158d58ad5fe33f460938d0c74 Mon Sep 17 00:00:00 2001 From: "REDMOND\\acoates" Date: Mon, 3 Jun 2019 08:41:57 -0700 Subject: [PATCH 0179/1084] Move unistd.h include to cpp where its used (#25107) Summary: unistd.h isn't a header available in the windows SDK, so we can't include it from react-native-windows. I moved the usage of dup, to JSBigString.cpp in a previous PR, so this header should only be needed in the cpp file, not the header. (And react-native-windows doesn't use the cpp file) ## Changelog [Internal] [Fixed] - Header cleanup Pull Request resolved: https://github.com/facebook/react-native/pull/25107 Differential Revision: D15602265 Pulled By: cpojer fbshipit-source-id: 6a62bf8fe6758e400810f37834e8646485120d71 --- ReactCommon/cxxreact/JSBigString.cpp | 1 + ReactCommon/cxxreact/JSBigString.h | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactCommon/cxxreact/JSBigString.cpp b/ReactCommon/cxxreact/JSBigString.cpp index dc997d1cd5b728..d841295e323d1c 100644 --- a/ReactCommon/cxxreact/JSBigString.cpp +++ b/ReactCommon/cxxreact/JSBigString.cpp @@ -7,6 +7,7 @@ #include #include +#include #include diff --git a/ReactCommon/cxxreact/JSBigString.h b/ReactCommon/cxxreact/JSBigString.h index c4bf86fd71990e..3d07f1fda4da2f 100644 --- a/ReactCommon/cxxreact/JSBigString.h +++ b/ReactCommon/cxxreact/JSBigString.h @@ -6,7 +6,6 @@ #pragma once #include -#include #include #include From 5c2459996e3932f5fd10e8aa86e406f6ffab0d07 Mon Sep 17 00:00:00 2001 From: Alex Cohen Date: Mon, 3 Jun 2019 10:55:22 -0700 Subject: [PATCH 0180/1084] name background tasks Summary: [iOS] [Changed] - background tasks need names in order to track them. Reviewed By: aditya7fb Differential Revision: D15604435 fbshipit-source-id: 098e28620b75860c0e39166639399bbbcd42ff2b --- React/Modules/RCTTiming.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/React/Modules/RCTTiming.m b/React/Modules/RCTTiming.m index 7568dff8a58a8f..bfc31c63f78dfc 100644 --- a/React/Modules/RCTTiming.m +++ b/React/Modules/RCTTiming.m @@ -147,7 +147,7 @@ - (void)markStartOfBackgroundTaskIfNeeded if (_backgroundTaskIdentifier == UIBackgroundTaskInvalid) { __weak typeof(self) weakSelf = self; // Marks the beginning of a new long-running background task. We can run the timer in the background. - _backgroundTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ + _backgroundTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithName:@"rct.timing.gb.task" expirationHandler:^{ typeof(self) strongSelf = weakSelf; if (!strongSelf) { return; @@ -365,7 +365,7 @@ - (void)timerDidFire @synchronized (_timers) { _timers[callbackID] = timer; } - + if (_inBackground) { [self markStartOfBackgroundTaskIfNeeded]; [self scheduleSleepTimer:timer.target]; From d3cf756613b2c047400476678debb3706b8682f0 Mon Sep 17 00:00:00 2001 From: Sidharth Guglani Date: Mon, 3 Jun 2019 15:57:59 -0700 Subject: [PATCH 0181/1084] moved PtrJNode map to YGJtypes.h and passing layout context as data in LayoutPassEnd Event Summary: Move PtrJNodeMap to header file so that it can be accessed in events subscribers outside yoga Reviewed By: davidaurelio Differential Revision: D15602627 fbshipit-source-id: bb5bd5bbf8dcb279f5f87a4fd7287909d4e895d8 --- .../jni/first-party/yogajni/jni/YGJNI.cpp | 28 ---------------- .../jni/first-party/yogajni/jni/YGJTypes.h | 33 +++++++++++++++++++ ReactCommon/yoga/yoga/Yoga.cpp | 2 +- ReactCommon/yoga/yoga/event/event.h | 5 +++ 4 files changed, 39 insertions(+), 29 deletions(-) diff --git a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp index 28011661441036..c0b1a99b27d680 100644 --- a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp +++ b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp @@ -75,34 +75,6 @@ const short int LAYOUT_BORDER_START_INDEX = 14; bool useBatchingForLayoutOutputs; -class PtrJNodeMap { - using JNodeArray = JArrayClass; - std::map ptrsToIdxs_; - alias_ref javaNodes_; - -public: - PtrJNodeMap() : ptrsToIdxs_{}, javaNodes_{} {} - PtrJNodeMap( - alias_ref nativePointers, - alias_ref javaNodes) - : javaNodes_{javaNodes} { - auto pin = nativePointers->pinCritical(); - auto ptrs = pin.get(); - for (size_t i = 0, n = pin.size(); i < n; ++i) { - ptrsToIdxs_[(YGNodeRef) ptrs[i]] = i; - } - } - - local_ref ref(YGNodeRef node) { - auto idx = ptrsToIdxs_.find(node); - if (idx == ptrsToIdxs_.end()) { - return local_ref{}; - } else { - return javaNodes_->getElement(idx->second); - } - } -}; - namespace { union YGNodeContext { diff --git a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.h b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.h index c2c5fc518e3070..e93d74db2dc1ee 100644 --- a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.h +++ b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.h @@ -6,6 +6,11 @@ */ #include #include +#include +#include + +using namespace facebook::jni; +using namespace std; struct JYogaNode : public facebook::jni::JavaClass { static constexpr auto kJavaDescriptor = "Lcom/facebook/yoga/YogaNodeJNIBase;"; @@ -28,3 +33,31 @@ struct JYogaLogger : public facebook::jni::JavaClass { facebook::jni::alias_ref, jstring); }; + +class PtrJNodeMap { + using JNodeArray = JArrayClass; + std::map ptrsToIdxs_; + alias_ref javaNodes_; + +public: + PtrJNodeMap() : ptrsToIdxs_{}, javaNodes_{} {} + PtrJNodeMap( + alias_ref nativePointers, + alias_ref javaNodes) + : javaNodes_{javaNodes} { + auto pin = nativePointers->pinCritical(); + auto ptrs = pin.get(); + for (size_t i = 0, n = pin.size(); i < n; ++i) { + ptrsToIdxs_[(YGNodeRef) ptrs[i]] = i; + } + } + + local_ref ref(YGNodeRef node) { + auto idx = ptrsToIdxs_.find(node); + if (idx == ptrsToIdxs_.end()) { + return local_ref{}; + } else { + return javaNodes_->getElement(idx->second); + } + } +}; diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index d41a12013cd75d..7baab631e2e4be 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -4093,7 +4093,7 @@ void YGNodeCalculateLayoutWithContext( marker = nullptr; #ifdef YG_ENABLE_EVENTS - Event::publish(node); + Event::publish(node, {layoutContext}); #endif // We want to get rid off `useLegacyStretchBehaviour` from YGConfig. But we diff --git a/ReactCommon/yoga/yoga/event/event.h b/ReactCommon/yoga/yoga/event/event.h index 578d2f3a66a5e8..1a7c881f233199 100644 --- a/ReactCommon/yoga/yoga/event/event.h +++ b/ReactCommon/yoga/yoga/event/event.h @@ -71,5 +71,10 @@ struct Event::TypedData { YGConfig* config; }; +template <> +struct Event::TypedData { + void* layoutContext; +}; + } // namespace yoga } // namespace facebook From a44ab2957c6994fa44bd9644ab10da142109bab8 Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Mon, 3 Jun 2019 16:11:20 -0700 Subject: [PATCH 0182/1084] Protect access to RCTTurboModuleCache Summary: The `_rctTurboModuleCache` `std::unordered_map` can be accessed by multiple threads at the same time via the `provideRCTTurboModule` method. Since `provideRCTTurboModule` both reads and writes to `_rctTurboModuleCache`, this is really bad because we could end up reading from `_rctTurboModuleCache` while it's in an invalid state. Therefore, in this diff, I'm making it so that only one thread at a time can enter `provideRCTTurboModule`. Reviewed By: fkgozali Differential Revision: D15609987 fbshipit-source-id: e24e1f5cc2351d8cbb820b7a97074aacd06eec9d --- .../core/platform/ios/RCTTurboModuleManager.mm | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm b/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm index 0da68b3f3db64e..93f91f00ef7769 100644 --- a/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm +++ b/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm @@ -8,6 +8,7 @@ #import "RCTTurboModuleManager.h" #import +#import #import #import @@ -45,6 +46,18 @@ @implementation RCTTurboModuleManager { */ std::unordered_map> _rctTurboModuleCache; std::unordered_map> _turboModuleCache; + + /** + * _rctTurboModuleCache can be accessed by muitiple threads at once via + * the provideRCTTurboModule method. This can lead to races. Therefore, we + * need to protect access to this unordered_map. + * + * Note: + * There's no need to protect access to _turboModuleCache because that cache + * is only accessed within provideTurboModule, which is only invoked by the + * JS thread. + */ + std::mutex _rctTurboModuleCacheLock; } - (instancetype)initWithBridge:(RCTBridge *)bridge delegate:(id)delegate @@ -198,6 +211,8 @@ - (void)notifyAboutTurboModuleSetup:(const char *)name */ - (id)provideRCTTurboModule:(const char *)moduleName { + std::lock_guard guard{_rctTurboModuleCacheLock}; + auto rctTurboModuleCacheLookup = _rctTurboModuleCache.find(moduleName); if (rctTurboModuleCacheLookup != _rctTurboModuleCache.end()) { return rctTurboModuleCacheLookup->second; From 738dd65967c3426e259885f7f060b349654b1abd Mon Sep 17 00:00:00 2001 From: Emily Janzer Date: Mon, 3 Jun 2019 19:17:54 -0700 Subject: [PATCH 0183/1084] Use SurfaceRegistry instead of AppRegistry Summary: Right now we render a surface by calling `AppRegistry.runApplication`, but the way we do this relies on the batched bridge. For Venice (bridgeless RN) I created a new module for registering a surface called SurfaceRegistry, which uses a global variable instead of registering itself as a callable module on the bridge. If that global variable exists, we can use that to start the surface instead of calling AppRegistry. Reviewed By: sahrens Differential Revision: D15502241 fbshipit-source-id: 0b8d4677f1df41f46d84444567a30e40e21fed3d --- .../fabric/uimanager/UIManagerBinding.cpp | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/ReactCommon/fabric/uimanager/UIManagerBinding.cpp b/ReactCommon/fabric/uimanager/UIManagerBinding.cpp index afcb6aff7d45fb..ac72b2437bef0d 100644 --- a/ReactCommon/fabric/uimanager/UIManagerBinding.cpp +++ b/ReactCommon/fabric/uimanager/UIManagerBinding.cpp @@ -46,14 +46,25 @@ void UIManagerBinding::startSurface( parameters["initialProps"] = initalProps; parameters["fabric"] = true; - auto module = getModule(runtime, "AppRegistry"); - auto method = module.getPropertyAsFunction(runtime, "runApplication"); + if (runtime.global().hasProperty(runtime, "RN$SurfaceRegistry")) { + auto registry = + runtime.global().getPropertyAsObject(runtime, "RN$SurfaceRegistry"); + auto method = registry.getPropertyAsFunction(runtime, "renderSurface"); - method.callWithThis( - runtime, - module, - {jsi::String::createFromUtf8(runtime, moduleName), - jsi::valueFromDynamic(runtime, parameters)}); + method.call( + runtime, + {jsi::String::createFromUtf8(runtime, moduleName), + jsi::valueFromDynamic(runtime, parameters)}); + } else { + auto module = getModule(runtime, "AppRegistry"); + auto method = module.getPropertyAsFunction(runtime, "runApplication"); + + method.callWithThis( + runtime, + module, + {jsi::String::createFromUtf8(runtime, moduleName), + jsi::valueFromDynamic(runtime, parameters)}); + } } void UIManagerBinding::stopSurface(jsi::Runtime &runtime, SurfaceId surfaceId) From 43d7664308f7521f39b5aea7d5452ef9028cc345 Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Mon, 3 Jun 2019 19:53:49 -0700 Subject: [PATCH 0184/1084] Revert D15602627: [yoga] moved PtrJNode map to YGJtypes.h and passing layout context as data in LayoutPassEnd Event Differential Revision: D15602627 Original commit changeset: bb5bd5bbf8dc fbshipit-source-id: 5ae08826eb706c3794c36738cb9625f82b58641e --- .../jni/first-party/yogajni/jni/YGJNI.cpp | 28 ++++++++++++++++ .../jni/first-party/yogajni/jni/YGJTypes.h | 33 ------------------- ReactCommon/yoga/yoga/Yoga.cpp | 2 +- ReactCommon/yoga/yoga/event/event.h | 5 --- 4 files changed, 29 insertions(+), 39 deletions(-) diff --git a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp index c0b1a99b27d680..28011661441036 100644 --- a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp +++ b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp @@ -75,6 +75,34 @@ const short int LAYOUT_BORDER_START_INDEX = 14; bool useBatchingForLayoutOutputs; +class PtrJNodeMap { + using JNodeArray = JArrayClass; + std::map ptrsToIdxs_; + alias_ref javaNodes_; + +public: + PtrJNodeMap() : ptrsToIdxs_{}, javaNodes_{} {} + PtrJNodeMap( + alias_ref nativePointers, + alias_ref javaNodes) + : javaNodes_{javaNodes} { + auto pin = nativePointers->pinCritical(); + auto ptrs = pin.get(); + for (size_t i = 0, n = pin.size(); i < n; ++i) { + ptrsToIdxs_[(YGNodeRef) ptrs[i]] = i; + } + } + + local_ref ref(YGNodeRef node) { + auto idx = ptrsToIdxs_.find(node); + if (idx == ptrsToIdxs_.end()) { + return local_ref{}; + } else { + return javaNodes_->getElement(idx->second); + } + } +}; + namespace { union YGNodeContext { diff --git a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.h b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.h index e93d74db2dc1ee..c2c5fc518e3070 100644 --- a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.h +++ b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.h @@ -6,11 +6,6 @@ */ #include #include -#include -#include - -using namespace facebook::jni; -using namespace std; struct JYogaNode : public facebook::jni::JavaClass { static constexpr auto kJavaDescriptor = "Lcom/facebook/yoga/YogaNodeJNIBase;"; @@ -33,31 +28,3 @@ struct JYogaLogger : public facebook::jni::JavaClass { facebook::jni::alias_ref, jstring); }; - -class PtrJNodeMap { - using JNodeArray = JArrayClass; - std::map ptrsToIdxs_; - alias_ref javaNodes_; - -public: - PtrJNodeMap() : ptrsToIdxs_{}, javaNodes_{} {} - PtrJNodeMap( - alias_ref nativePointers, - alias_ref javaNodes) - : javaNodes_{javaNodes} { - auto pin = nativePointers->pinCritical(); - auto ptrs = pin.get(); - for (size_t i = 0, n = pin.size(); i < n; ++i) { - ptrsToIdxs_[(YGNodeRef) ptrs[i]] = i; - } - } - - local_ref ref(YGNodeRef node) { - auto idx = ptrsToIdxs_.find(node); - if (idx == ptrsToIdxs_.end()) { - return local_ref{}; - } else { - return javaNodes_->getElement(idx->second); - } - } -}; diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index 7baab631e2e4be..d41a12013cd75d 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -4093,7 +4093,7 @@ void YGNodeCalculateLayoutWithContext( marker = nullptr; #ifdef YG_ENABLE_EVENTS - Event::publish(node, {layoutContext}); + Event::publish(node); #endif // We want to get rid off `useLegacyStretchBehaviour` from YGConfig. But we diff --git a/ReactCommon/yoga/yoga/event/event.h b/ReactCommon/yoga/yoga/event/event.h index 1a7c881f233199..578d2f3a66a5e8 100644 --- a/ReactCommon/yoga/yoga/event/event.h +++ b/ReactCommon/yoga/yoga/event/event.h @@ -71,10 +71,5 @@ struct Event::TypedData { YGConfig* config; }; -template <> -struct Event::TypedData { - void* layoutContext; -}; - } // namespace yoga } // namespace facebook From 22475ed38d181754d64a69f3d2143fa7d4b22a35 Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Mon, 3 Jun 2019 20:51:10 -0700 Subject: [PATCH 0185/1084] Ensure app doesn't crash when module is absent Summary: Before we flow-typed NativeI18nManager, we defaulted the implementation of I18nManager to something safe when it wasn't available. After the flow-type, it became a requirement that NativeI18nManager be present in the app. This is leading to crashes: T45287329. This diff re-enables the defaults for I18nManager. Reviewed By: fkgozali Differential Revision: D15617660 fbshipit-source-id: c3a1c737663a1a4ceae484d0ad6cbf2bd86ffe5f --- Libraries/ReactNative/I18nManager.js | 26 ++++++++++++++++++---- Libraries/ReactNative/NativeI18nManager.js | 2 +- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/Libraries/ReactNative/I18nManager.js b/Libraries/ReactNative/I18nManager.js index e5fd02e7c13dab..f5616c807ae57e 100644 --- a/Libraries/ReactNative/I18nManager.js +++ b/Libraries/ReactNative/I18nManager.js @@ -11,24 +11,42 @@ import NativeI18nManager from './NativeI18nManager'; +const i18nConstants = NativeI18nManager + ? NativeI18nManager.getConstants() + : { + isRTL: false, + doLeftAndRightSwapInRTL: true, + }; + module.exports = { getConstants: () => { - return NativeI18nManager.getConstants(); + return i18nConstants; }, allowRTL: (shouldAllow: boolean) => { + if (!NativeI18nManager) { + return; + } + NativeI18nManager.allowRTL(shouldAllow); }, forceRTL: (shouldForce: boolean) => { + if (!NativeI18nManager) { + return; + } + NativeI18nManager.forceRTL(shouldForce); }, swapLeftAndRightInRTL: (flipStyles: boolean) => { + if (!NativeI18nManager) { + return; + } + NativeI18nManager.swapLeftAndRightInRTL(flipStyles); }, - isRTL: NativeI18nManager.getConstants().isRTL, - doLeftAndRightSwapInRTL: NativeI18nManager.getConstants() - .doLeftAndRightSwapInRTL, + isRTL: i18nConstants.isRTL, + doLeftAndRightSwapInRTL: i18nConstants.doLeftAndRightSwapInRTL, }; diff --git a/Libraries/ReactNative/NativeI18nManager.js b/Libraries/ReactNative/NativeI18nManager.js index 0220b2471ba486..9da9a6ade2b960 100644 --- a/Libraries/ReactNative/NativeI18nManager.js +++ b/Libraries/ReactNative/NativeI18nManager.js @@ -23,4 +23,4 @@ export interface Spec extends TurboModule { swapLeftAndRightInRTL: (flipStyles: boolean) => void; } -export default TurboModuleRegistry.getEnforcing('I18nManager'); +export default TurboModuleRegistry.get('I18nManager'); From b3a50ec0de1065c9fdc6bc8453b8534a4498058a Mon Sep 17 00:00:00 2001 From: Sam Goldman Date: Mon, 3 Jun 2019 22:58:49 -0700 Subject: [PATCH 0186/1084] Deploy Flow v0.100 to xplat/js Reviewed By: dsainati1 Differential Revision: D15617077 fbshipit-source-id: b88325dd80d167473d3c4cc7bb93c27ea71e654b --- .flowconfig | 2 +- .flowconfig.android | 2 +- Libraries/Lists/FlatList.js | 3 --- package.json | 2 +- .../src/cli/viewconfigs/generate-view-configs-cli.js | 6 +++--- template/_flowconfig | 2 +- yarn.lock | 8 ++++---- 7 files changed, 11 insertions(+), 14 deletions(-) diff --git a/.flowconfig b/.flowconfig index 69e9a5aef1cdf7..2df42b89ca436c 100644 --- a/.flowconfig +++ b/.flowconfig @@ -103,4 +103,4 @@ untyped-import untyped-type-import [version] -^0.99.0 +^0.100.0 diff --git a/.flowconfig.android b/.flowconfig.android index dce8cc3e8bda53..1d47c484efc3ca 100644 --- a/.flowconfig.android +++ b/.flowconfig.android @@ -103,4 +103,4 @@ untyped-import untyped-type-import [version] -^0.99.0 +^0.100.0 diff --git a/Libraries/Lists/FlatList.js b/Libraries/Lists/FlatList.js index 292c6e1cc63746..3722bc1a273557 100644 --- a/Libraries/Lists/FlatList.js +++ b/Libraries/Lists/FlatList.js @@ -576,9 +576,6 @@ class FlatList extends React.PureComponent, void> { .map((it, kk) => keyExtractor(it, index * numColumns + kk)) .join(':'); } else { - /* $FlowFixMe(>=0.63.0 site=react_native_fb) This comment suppresses an - * error found when Flow v0.63 was deployed. To see the error delete this - * comment and run Flow. */ return keyExtractor(items, index); } }; diff --git a/package.json b/package.json index 47fbc2b66db8ca..0be5ffb403a123 100644 --- a/package.json +++ b/package.json @@ -130,7 +130,7 @@ "eslint-plugin-react-hooks": "^1.5.1", "eslint-plugin-react-native": "3.6.0", "eslint-plugin-relay": "1.3.0", - "flow-bin": "^0.99.0", + "flow-bin": "^0.100.0", "flow-remove-types": "1.2.3", "jest": "^24.7.1", "jest-junit": "^6.3.0", diff --git a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js index 6603717369500f..2ce923a97a16ac 100644 --- a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js +++ b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js @@ -31,8 +31,8 @@ generate( fileName.endsWith(supportedFileName), ), ), - /* $FlowFixMe(>=0.99.0 site=react_native_fb) This comment suppresses an error - * found when Flow v0.99 was deployed. To see the error, delete this comment - * and run Flow. */ + /* $FlowFixMe(>=0.99.0 site=react_native_fb) This comment suppresses an + * error found when Flow v0.99 was deployed. To see the error, delete this + * comment and run Flow. */ {test: argv.test, parser: 'flow'}, ); diff --git a/template/_flowconfig b/template/_flowconfig index 2047ef0464540a..80fa55fc38a41d 100644 --- a/template/_flowconfig +++ b/template/_flowconfig @@ -96,4 +96,4 @@ untyped-import untyped-type-import [version] -^0.99.0 +^0.100.0 diff --git a/yarn.lock b/yarn.lock index 0eda165a2609d7..9c5859f6db42db 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3202,10 +3202,10 @@ flat-cache@^1.2.1: rimraf "~2.6.2" write "^0.2.1" -flow-bin@^0.99.0: - version "0.99.1" - resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.99.1.tgz#0d4f413ca84a3a95d0aa64214178684dd7c6a4c5" - integrity sha512-dipNwJlb4MsVt3IuDgPTymCNL4GFoq3pG+GbY6DmBbl0dJPWFSA383rCTmgbfFhoeJ1XCfYBan0BPryToSxiiQ== +flow-bin@^0.100.0: + version "0.100.0" + resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.100.0.tgz#729902726658cfa0a81425d6401f9625cf9f5534" + integrity sha512-jcethhgrslBJukH7Z7883ohFFpzLrdsOEwHxvn5NwuTWbNaE71GAl55/PEBRJwYpDvYkRlqgcNkANTv0x5XjqA== flow-parser@0.*: version "0.89.0" From fc6bbe62b531c99dd83e6af939ad2c0a481df02e Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Tue, 4 Jun 2019 02:04:40 -0700 Subject: [PATCH 0187/1084] TurboModules: ES Module Cleanup Summary: Minor cleanup of module conventions in `TurboModuleRegistry`. Reviewed By: cpojer Differential Revision: D15619210 fbshipit-source-id: 90a926f992333260eb8806b5708594c4a12e68fb --- Libraries/TurboModule/TurboModuleRegistry.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/Libraries/TurboModule/TurboModuleRegistry.js b/Libraries/TurboModule/TurboModuleRegistry.js index ca64f774deceea..fcec0d8ada5eda 100644 --- a/Libraries/TurboModule/TurboModuleRegistry.js +++ b/Libraries/TurboModule/TurboModuleRegistry.js @@ -10,14 +10,13 @@ 'use strict'; -const NativeModules = require('../BatchedBridge/NativeModules'); - +import NativeModules from '../BatchedBridge/NativeModules'; import type {TurboModule} from './RCTExport'; import invariant from 'invariant'; const turboModuleProxy = global.__turboModuleProxy; -function get(name: string): ?T { +export function get(name: string): ?T { // Backward compatibility layer during migration. const legacyModule = NativeModules[name]; if (legacyModule != null) { @@ -32,11 +31,8 @@ function get(name: string): ?T { return null; } -function getEnforcing(name: string): T { +export function getEnforcing(name: string): T { const module = get(name); invariant(module != null, `${name} is not available in this app.`); return module; } - -export {get}; -export {getEnforcing}; From afc142bc76d5cfddcacf55a1f3770e6b6ea15996 Mon Sep 17 00:00:00 2001 From: Sharon Gong Date: Tue, 4 Jun 2019 07:02:14 -0700 Subject: [PATCH 0188/1084] Fix accessibilityActions accessors (#25134) Summary: The accessibilityActions accessors in UIView+React.m are not aligned with the property declaration in the header file. ## Changelog [General] [Fixed] - Fix accessibilityActions accessors Pull Request resolved: https://github.com/facebook/react-native/pull/25134 Differential Revision: D15621848 Pulled By: cpojer fbshipit-source-id: f344689292ae7988e46d0d4263980306d364366b --- React/Views/UIView+React.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/React/Views/UIView+React.m b/React/Views/UIView+React.m index d9c4d4190ab226..a14707137cf153 100644 --- a/React/Views/UIView+React.m +++ b/React/Views/UIView+React.m @@ -297,12 +297,12 @@ - (UIView *)reactAccessibilityElement return self; } -- (NSArray *)accessibilityActions +- (NSArray *)accessibilityActions { return objc_getAssociatedObject(self, _cmd); } -- (void)setAccessibilityActions:(NSArray *)accessibilityActions +- (void)setAccessibilityActions:(NSArray *)accessibilityActions { objc_setAssociatedObject(self, @selector(accessibilityActions), accessibilityActions, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } From fd7f5bb76868dced03747a8c128600993378c2ce Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Tue, 4 Jun 2019 07:06:06 -0700 Subject: [PATCH 0189/1084] Keep the order of Modals that we can dismiss in sequence (#24961) Summary: Fixes https://github.com/facebook/react-native/issues/16037. We need to keep the order of Modals, if we dismiss Modal randomly(before we use hash table), some Modals may not dismiss successfully. This PR should based on https://github.com/facebook/react-native/pull/24959. ## Changelog [iOS] [Fixed] - Keep the order of Modals that we can dismiss in sequence Pull Request resolved: https://github.com/facebook/react-native/pull/24961 Differential Revision: D15621858 Pulled By: cpojer fbshipit-source-id: 964729f8f4584995f4e1dd527af4b61534d369ba --- React/Views/RCTModalHostViewManager.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/React/Views/RCTModalHostViewManager.m b/React/Views/RCTModalHostViewManager.m index 495b90d2dddd7e..28c1c5e9423060 100644 --- a/React/Views/RCTModalHostViewManager.m +++ b/React/Views/RCTModalHostViewManager.m @@ -49,7 +49,7 @@ @interface RCTModalHostViewManager () @implementation RCTModalHostViewManager { - NSHashTable *_hostViews; + NSPointerArray *_hostViews; } RCT_EXPORT_MODULE() @@ -59,9 +59,9 @@ - (UIView *)view RCTModalHostView *view = [[RCTModalHostView alloc] initWithBridge:self.bridge]; view.delegate = self; if (!_hostViews) { - _hostViews = [NSHashTable weakObjectsHashTable]; + _hostViews = [NSPointerArray weakObjectsPointerArray]; } - [_hostViews addObject:view]; + [_hostViews addPointer:(__bridge void *)view]; return view; } @@ -104,7 +104,7 @@ - (void)invalidate for (RCTModalHostView *hostView in _hostViews) { [hostView invalidate]; } - [_hostViews removeAllObjects]; + _hostViews = nil; } RCT_EXPORT_VIEW_PROPERTY(animationType, NSString) From dbad0fd607890317614a60ba5a7fcf82c9e5ece1 Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Tue, 4 Jun 2019 08:25:00 -0700 Subject: [PATCH 0190/1084] Remove TMMDelegate's dependency on ReactApplicationContext Summary: `TurboModuleManagerDelegate` is an interface used to query/create TurboModules. It doesn't need to know anything about `ReactApplicationContext`. So, I'm removing all references of `ReactApplicationContext` from this class. Reviewed By: mdvacca Differential Revision: D15590552 fbshipit-source-id: 761d3ed71f124955f9c6b997e68a7a8338182126 --- .../core/ReactPackageTurboModuleManagerDelegate.java | 2 +- .../turbomodule/core/TurboModuleManagerDelegate.java | 8 +------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/ReactPackageTurboModuleManagerDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/ReactPackageTurboModuleManagerDelegate.java index fab21c9fca327e..839ada2cf080bc 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/ReactPackageTurboModuleManagerDelegate.java +++ b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/ReactPackageTurboModuleManagerDelegate.java @@ -20,7 +20,7 @@ public abstract class ReactPackageTurboModuleManagerDelegate extends TurboModule private final ReactApplicationContext mReactApplicationContext; public ReactPackageTurboModuleManagerDelegate(ReactApplicationContext reactApplicationContext, List packages) { - super(reactApplicationContext); + super(); mReactApplicationContext = reactApplicationContext; for (ReactPackage reactPackage : packages) { if (reactPackage instanceof TurboReactPackage) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManagerDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManagerDelegate.java index eabeae27640b35..fda66b65a36ab4 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManagerDelegate.java +++ b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManagerDelegate.java @@ -20,17 +20,11 @@ public abstract class TurboModuleManagerDelegate { } private final HybridData mHybridData; - private final ReactApplicationContext mReactApplicationContext; protected abstract HybridData initHybrid(); - protected TurboModuleManagerDelegate(ReactApplicationContext rac) { + protected TurboModuleManagerDelegate() { mHybridData = initHybrid(); - mReactApplicationContext = rac; - } - - protected ReactApplicationContext getReactApplicationContext() { - return mReactApplicationContext; } /** From 6b4e526b2da109a367aa0a6142feb6e4e3c2532c Mon Sep 17 00:00:00 2001 From: Kudo Chien Date: Tue, 4 Jun 2019 12:39:41 -0700 Subject: [PATCH 0191/1084] Add debug build support for Android native code (#25147) Summary: With JSI based architecture, there will be more and more C++ native code involved. Original NDK builder in RN only supports release build and that's not reasonable for native debugging. This change introduces a way to build native code in debuggable version. Simply add `NATIVE_BUILD_TYPE=Debug` environment variable during gradle build, e.g. `NATIVE_BUILD_TYPE=Debug ./gradlew clean :ReactAndroid:assembleDebug` ## Changelog [Android] [Added] - Add native debug build support to improve debugging DX Pull Request resolved: https://github.com/facebook/react-native/pull/25147 Differential Revision: D15628533 Pulled By: cpojer fbshipit-source-id: 8f5b54c4580824452d2a1236a7bd641889b001ec --- ReactAndroid/build.gradle | 4 ++++ ReactAndroid/src/main/jni/react/jni/Android.mk | 8 ++++++++ ReactAndroid/src/main/jni/third-party/folly/Android.mk | 8 ++++++++ 3 files changed, 20 insertions(+) diff --git a/ReactAndroid/build.gradle b/ReactAndroid/build.gradle index 84207fb50578dc..343543143431bc 100644 --- a/ReactAndroid/build.gradle +++ b/ReactAndroid/build.gradle @@ -33,6 +33,9 @@ def dependenciesPath = System.getenv("REACT_NATIVE_DEPENDENCIES") // and the build will use that. def boostPath = dependenciesPath ?: System.getenv("REACT_NATIVE_BOOST_PATH") +// Setup build type for NDK, supported values: {debug, release} +def nativeBuildType = System.getenv("NATIVE_BUILD_TYPE") ?: "release" + task createNativeDepsDirectories { downloadsDir.mkdirs() thirdPartyNdkDir.mkdirs() @@ -225,6 +228,7 @@ task buildReactNdkLib(dependsOn: [prepareJSC, prepareBoost, prepareDoubleConvers inputs.dir("src/main/java/com/facebook/react/modules/blob") outputs.dir("$buildDir/react-ndk/all") commandLine(getNdkBuildFullPath(), + "NDK_DEBUG=" + (nativeBuildType.equalsIgnoreCase("debug") ? "1" : "0"), "NDK_PROJECT_PATH=null", "NDK_APPLICATION_MK=$projectDir/src/main/jni/Application.mk", "NDK_OUT=" + temporaryDir, diff --git a/ReactAndroid/src/main/jni/react/jni/Android.mk b/ReactAndroid/src/main/jni/react/jni/Android.mk index 1cf03a78a5ea19..28c1fae096e7bf 100644 --- a/ReactAndroid/src/main/jni/react/jni/Android.mk +++ b/ReactAndroid/src/main/jni/react/jni/Android.mk @@ -36,6 +36,14 @@ LOCAL_MODULE := reactnativejni # Compile all local c++ files. LOCAL_SRC_FILES := $(wildcard *.cpp) +ifeq ($(APP_OPTIM),debug) + # Keep symbols by overriding the strip command invoked by ndk-build. + # Note that this will apply to all shared libraries, + # i.e. shared libraries will NOT be stripped + # even though we override it in this Android.mk + cmd-strip := +endif + # Build the files in this directory as a shared library include $(BUILD_SHARED_LIBRARY) diff --git a/ReactAndroid/src/main/jni/third-party/folly/Android.mk b/ReactAndroid/src/main/jni/third-party/folly/Android.mk index c84f2d9330b419..7da39f37737875 100644 --- a/ReactAndroid/src/main/jni/third-party/folly/Android.mk +++ b/ReactAndroid/src/main/jni/third-party/folly/Android.mk @@ -17,6 +17,14 @@ LOCAL_SRC_FILES:= \ folly/container/detail/F14Table.cpp \ folly/ScopeGuard.cpp \ +ifeq ($(APP_OPTIM),debug) + LOCAL_SRC_FILES += \ + folly/lang/Assume.cpp \ + folly/lang/SafeAssert.cpp \ + folly/FileUtil.cpp \ + folly/portability/SysUio.cpp +endif + LOCAL_C_INCLUDES := $(LOCAL_PATH) LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH) From 46c7ada535f8d87f325ccbd96c24993dd522165d Mon Sep 17 00:00:00 2001 From: Eric Lewis Date: Tue, 4 Jun 2019 12:54:59 -0700 Subject: [PATCH 0192/1084] Fix Xcode 11 build (#25146) Summary: Fixes build in Xcode 11 beta, the signature for `__unused` was changed. This adds a new check for the new style. ## Changelog [iOS] [Fixed] - Xcode 11 beta build Pull Request resolved: https://github.com/facebook/react-native/pull/25146 Differential Revision: D15628404 Pulled By: cpojer fbshipit-source-id: 781a188a0e1562a3316fbe62920b12b03a44e4a7 --- React/Base/RCTModuleMethod.mm | 1 + 1 file changed, 1 insertion(+) diff --git a/React/Base/RCTModuleMethod.mm b/React/Base/RCTModuleMethod.mm index 14963b19a639a6..12a5b197ce2bf3 100644 --- a/React/Base/RCTModuleMethod.mm +++ b/React/Base/RCTModuleMethod.mm @@ -91,6 +91,7 @@ static BOOL RCTParseSelectorPart(const char **input, NSMutableString *selector) static BOOL RCTParseUnused(const char **input) { return RCTReadString(input, "__attribute__((unused))") || + RCTReadString(input, "__attribute__((__unused__))") || RCTReadString(input, "__unused"); } From f5aa52399bb8dc0f0cbc3555b298837c5616d451 Mon Sep 17 00:00:00 2001 From: Jim Berlage Date: Tue, 4 Jun 2019 13:23:31 -0700 Subject: [PATCH 0193/1084] Ensure that iOS uses RCT_METRO_PORT instead of hardcoded 8081 when appropriate (#25144) Summary: In environments with McAfee EPro software, port 8081 is used and cannot be unbound. (See [#20466](https://github.com/facebook/react-native/issues/20466) for a recent example issue.) Most issues can be worked around by passing a `--port` option or setting `RCT_METRO_PORT`, but there are a couple places where 8081 is hardcoded that block adoption. Right now the workaround I've seen pushed on Stack Overflow and elsewhere is to modify node_modules after a `yarn install`, so I'd like to fix it at the source. This PR changes the react "Start Packager" build step and some code in the iOS DevSupport library to read from the `RCT_METRO_PORT` variable. ## Changelog [General] [Changed] - Removed hardcoded references to port 8081 and replaced them by reading from RCT_METRO_PORT (w/ fallback to 8081) Pull Request resolved: https://github.com/facebook/react-native/pull/25144 Differential Revision: D15630119 Pulled By: cpojer fbshipit-source-id: aff5d24691e0e9892a035cfbd25330fed6441199 --- React/DevSupport/RCTInspectorDevServerHelper.mm | 8 ++++++++ React/React.xcodeproj/project.pbxproj | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/React/DevSupport/RCTInspectorDevServerHelper.mm b/React/DevSupport/RCTInspectorDevServerHelper.mm index 0f1ada9347ad60..f813fe11bba7f0 100644 --- a/React/DevSupport/RCTInspectorDevServerHelper.mm +++ b/React/DevSupport/RCTInspectorDevServerHelper.mm @@ -33,6 +33,10 @@ static NSURL *getInspectorDeviceUrl(NSURL *bundleURL) { NSNumber *inspectorProxyPort = @8081; + NSString *inspectorProxyPortStr = [[[NSProcessInfo processInfo] environment] objectForKey:@"RCT_METRO_PORT"]; + if (inspectorProxyPortStr && [inspectorProxyPortStr length] > 0) { + inspectorProxyPort = [NSNumber numberWithInt:[inspectorProxyPortStr intValue]]; + } NSString *escapedDeviceName = [[[UIDevice currentDevice] name] stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet]; NSString *escapedAppName = [[[NSBundle mainBundle] bundleIdentifier] stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet]; return [NSURL URLWithString:[NSString stringWithFormat:@"http://%@/inspector/device?name=%@&app=%@", @@ -44,6 +48,10 @@ static NSURL *getAttachDeviceUrl(NSURL *bundleURL, NSString *title) { NSNumber *metroBundlerPort = @8081; + NSString *metroBundlerPortStr = [[[NSProcessInfo processInfo] environment] objectForKey:@"RCT_METRO_PORT"]; + if (metroBundlerPortStr && [metroBundlerPortStr length] > 0) { + metroBundlerPort = [NSNumber numberWithInt:[metroBundlerPortStr intValue]]; + } NSString *escapedDeviceName = [[[UIDevice currentDevice] name] stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLHostAllowedCharacterSet]; NSString *escapedAppName = [[[NSBundle mainBundle] bundleIdentifier] stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLHostAllowedCharacterSet]; return [NSURL URLWithString:[NSString stringWithFormat:@"http://%@/attach-debugger-nuclide?title=%@&device=%@&app=%@", diff --git a/React/React.xcodeproj/project.pbxproj b/React/React.xcodeproj/project.pbxproj index 45439f6e31f41f..cbb4825a0630b0 100644 --- a/React/React.xcodeproj/project.pbxproj +++ b/React/React.xcodeproj/project.pbxproj @@ -3979,7 +3979,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "terminal=\"${RCT_TERMINAL-${REACT_TERMINAL-$TERM_PROGRAM}}\"\n\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] && [ \"$CONFIGURATION\" == \"Debug\" ] ; then\n if nc -w 5 -z localhost 8081 ; then\n if ! curl -s \"http://localhost:8081/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port 8081 already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n elif [ -z \"$terminal\" ]; then\n open \"$SRCROOT/../scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n else\n open -a $terminal \"$SRCROOT/../scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi\n"; + shellScript = "terminal=\"${RCT_TERMINAL-${REACT_TERMINAL-$TERM_PROGRAM}}\"\nport=\"${RCT_METRO_PORT:-8081}\"\n\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] && [ \"$CONFIGURATION\" == \"Debug\" ] ; then\n if nc -w 5 -z localhost \"${port}\" ; then\n if ! curl -s \"http://localhost:${port}/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port ${port} already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n elif [ -z \"$terminal\" ]; then\n open \"$SRCROOT/../scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n else\n open -a $terminal \"$SRCROOT/../scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi\n"; showEnvVarsInLog = 0; }; 142C4F7F1B582EA6001F0B58 /* Include RCTJSCProfiler */ = { @@ -4099,7 +4099,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "terminal=\"${RCT_TERMINAL-${REACT_TERMINAL-$TERM_PROGRAM}}\"\n\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] && [ \"$CONFIGURATION\" == \"Debug\" ] ; then\n if nc -w 5 -z localhost 8081 ; then\n if ! curl -s \"http://localhost:8081/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port 8081 already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n elif [ -z \"$terminal\" ]; then\n open \"$SRCROOT/../scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n else\n open -a $terminal \"$SRCROOT/../scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi\n"; + shellScript = "terminal=\"${RCT_TERMINAL-${REACT_TERMINAL-$TERM_PROGRAM}}\"\nport=\"${RCT_METRO_PORT:-8081}\"\n\n\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] && [ \"$CONFIGURATION\" == \"Debug\" ] ; then\n if nc -w 5 -z localhost \"${port}\" ; then\n if ! curl -s \"http://localhost:${port}/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port ${port} already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n elif [ -z \"$terminal\" ]; then\n open \"$SRCROOT/../scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n else\n open -a $terminal \"$SRCROOT/../scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi\n"; showEnvVarsInLog = 0; }; 3D383D3E1EBD27B9005632C8 /* Install Third Party */ = { From 146d1f7578c3fcb4f4a4c49599a78ee437cf41d2 Mon Sep 17 00:00:00 2001 From: Dulmandakh Date: Tue, 4 Jun 2019 13:55:02 -0700 Subject: [PATCH 0194/1084] Bump Android NDK to r19c (#25140) Summary: In 2019-6-4 version of Docker Android image, we've added Android NDK r19c. So this PR will change CI to use NDK r19c. I'll create a PR to website once this merged. Note: I tried to build RN with NDK 19 while I was setting up my laptop after format, and it worked. ## Changelog [Android] [Changed] - Bump Android NDK to r19c Pull Request resolved: https://github.com/facebook/react-native/pull/25140 Differential Revision: D15631301 Pulled By: cpojer fbshipit-source-id: b9a5600df1dadeba328932b694493960b242c2f7 --- .appveyor/config.yml | 4 ++-- .circleci/config.yml | 2 +- scripts/android-setup.sh | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.appveyor/config.yml b/.appveyor/config.yml index a30baf7582a396..ed8162cf135899 100644 --- a/.appveyor/config.yml +++ b/.appveyor/config.yml @@ -1,13 +1,13 @@ environment: ANDROID_HOME: "C:\\android-sdk-windows" - ANDROID_NDK: "C:\\android-sdk-windows\\android-ndk-r17c" + ANDROID_NDK: "C:\\android-sdk-windows\\android-ndk-r19c" ANDROID_BUILD_VERSION: 28 ANDROID_TOOLS_VERSION: 28.0.3 GRADLE_OPTS: -Dorg.gradle.daemon=false SDK_TOOLS_URL: https://dl.google.com/android/repository/sdk-tools-windows-3859397.zip - NDK_TOOLS_URL: https://dl.google.com/android/repository/android-ndk-r17c-windows-x86_64.zip + NDK_TOOLS_URL: https://dl.google.com/android/repository/android-ndk-r19c-windows-x86_64.zip matrix: - nodejs_version: 8 diff --git a/.circleci/config.yml b/.circleci/config.yml index 439abd9e050dd2..88bb91c0a3cfe9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -23,7 +23,7 @@ executors: reactnativeandroid: <<: *defaults docker: - - image: reactnativecommunity/react-native-android:2019-5-29 + - image: reactnativecommunity/react-native-android:2019-6-4 resource_class: "large" environment: - TERM: "dumb" diff --git a/scripts/android-setup.sh b/scripts/android-setup.sh index c76f520b931854..3032d0c69f2543 100755 --- a/scripts/android-setup.sh +++ b/scripts/android-setup.sh @@ -40,7 +40,7 @@ function getAndroidNDK { if [ ! -e $DEPS ]; then cd $NDK_HOME || exit echo "Downloading NDK..." - curl -o ndk.zip https://dl.google.com/android/repository/android-ndk-r17c-linux-x86_64.zip + curl -o ndk.zip https://dl.google.com/android/repository/android-ndk-r19c-linux-x86_64.zip unzip -o -q ndk.zip echo "Installed Android NDK at $NDK_HOME" touch $DEPS From 608b1b5ea2d9861816aaf3c4289e4316d9304b87 Mon Sep 17 00:00:00 2001 From: Will Holen Date: Tue, 4 Jun 2019 14:35:01 -0700 Subject: [PATCH 0195/1084] Include testlib files in JSI Summary: This adds the testlib.cpp/h files to external JSI. They're in a `test/` subdirectory so that build scripts using globs like `*.cpp` won't include them. Reviewed By: mhorowitz Differential Revision: D15582281 fbshipit-source-id: 1785ee5071fcf98e92fbf3a11eddb21fe84b3799 --- ReactCommon/jsi/jsi/test/testlib.cpp | 1198 ++++++++++++++++++++++++++ ReactCommon/jsi/jsi/test/testlib.h | 48 ++ 2 files changed, 1246 insertions(+) create mode 100644 ReactCommon/jsi/jsi/test/testlib.cpp create mode 100644 ReactCommon/jsi/jsi/test/testlib.h diff --git a/ReactCommon/jsi/jsi/test/testlib.cpp b/ReactCommon/jsi/jsi/test/testlib.cpp new file mode 100644 index 00000000000000..640fb133570395 --- /dev/null +++ b/ReactCommon/jsi/jsi/test/testlib.cpp @@ -0,0 +1,1198 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the LICENSE + * file in the root directory of this source tree. + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace facebook::jsi; + +class JSITest : public JSITestBase {}; + +TEST_P(JSITest, RuntimeTest) { + auto v = rt.evaluateJavaScript(std::make_unique("1"), ""); + EXPECT_EQ(v.getNumber(), 1); + + rt.evaluateJavaScript(std::make_unique("x = 1"), ""); + EXPECT_EQ(rt.global().getProperty(rt, "x").getNumber(), 1); +} + +TEST_P(JSITest, PropNameIDTest) { + // This is a little weird to test, because it doesn't really exist + // in JS yet. All I can do is create them, compare them, and + // receive one as an argument to a HostObject. + + PropNameID quux = PropNameID::forAscii(rt, "quux1", 4); + PropNameID movedQuux = std::move(quux); + EXPECT_EQ(movedQuux.utf8(rt), "quux"); + movedQuux = PropNameID::forAscii(rt, "quux2"); + EXPECT_EQ(movedQuux.utf8(rt), "quux2"); + PropNameID copiedQuux = PropNameID(rt, movedQuux); + EXPECT_TRUE(PropNameID::compare(rt, movedQuux, copiedQuux)); + + EXPECT_TRUE(PropNameID::compare(rt, movedQuux, movedQuux)); + EXPECT_TRUE(PropNameID::compare( + rt, movedQuux, PropNameID::forAscii(rt, std::string("quux2")))); + EXPECT_FALSE(PropNameID::compare( + rt, movedQuux, PropNameID::forAscii(rt, std::string("foo")))); + uint8_t utf8[] = {0xF0, 0x9F, 0x86, 0x97}; + PropNameID utf8PropNameID = PropNameID::forUtf8(rt, utf8, sizeof(utf8)); + EXPECT_EQ(utf8PropNameID.utf8(rt), u8"\U0001F197"); + EXPECT_TRUE(PropNameID::compare( + rt, utf8PropNameID, PropNameID::forUtf8(rt, utf8, sizeof(utf8)))); + PropNameID nonUtf8PropNameID = PropNameID::forUtf8(rt, "meow"); + EXPECT_TRUE(PropNameID::compare( + rt, nonUtf8PropNameID, PropNameID::forAscii(rt, "meow"))); + EXPECT_EQ(nonUtf8PropNameID.utf8(rt), "meow"); + PropNameID strPropNameID = + PropNameID::forString(rt, String::createFromAscii(rt, "meow")); + EXPECT_TRUE(PropNameID::compare(rt, nonUtf8PropNameID, strPropNameID)); + + auto names = PropNameID::names( + rt, "Ala", std::string("ma"), PropNameID::forAscii(rt, "kota")); + EXPECT_EQ(names.size(), 3); + EXPECT_TRUE( + PropNameID::compare(rt, names[0], PropNameID::forAscii(rt, "Ala"))); + EXPECT_TRUE( + PropNameID::compare(rt, names[1], PropNameID::forAscii(rt, "ma"))); + EXPECT_TRUE( + PropNameID::compare(rt, names[2], PropNameID::forAscii(rt, "kota"))); +} + +TEST_P(JSITest, StringTest) { + EXPECT_TRUE(checkValue(String::createFromAscii(rt, "foobar", 3), "'foo'")); + EXPECT_TRUE(checkValue(String::createFromAscii(rt, "foobar"), "'foobar'")); + + std::string baz = "baz"; + EXPECT_TRUE(checkValue(String::createFromAscii(rt, baz), "'baz'")); + + uint8_t utf8[] = {0xF0, 0x9F, 0x86, 0x97}; + EXPECT_TRUE(checkValue( + String::createFromUtf8(rt, utf8, sizeof(utf8)), "'\\uD83C\\uDD97'")); + + EXPECT_EQ(eval("'quux'").getString(rt).utf8(rt), "quux"); + EXPECT_EQ(eval("'\\u20AC'").getString(rt).utf8(rt), "\xe2\x82\xac"); + + String quux = String::createFromAscii(rt, "quux"); + String movedQuux = std::move(quux); + EXPECT_EQ(movedQuux.utf8(rt), "quux"); + movedQuux = String::createFromAscii(rt, "quux2"); + EXPECT_EQ(movedQuux.utf8(rt), "quux2"); +} + +TEST_P(JSITest, ObjectTest) { + eval("x = {1:2, '3':4, 5:'six', 'seven':['eight', 'nine']}"); + Object x = rt.global().getPropertyAsObject(rt, "x"); + EXPECT_EQ(x.getPropertyNames(rt).size(rt), 4); + EXPECT_TRUE(x.hasProperty(rt, "1")); + EXPECT_TRUE(x.hasProperty(rt, PropNameID::forAscii(rt, "1"))); + EXPECT_FALSE(x.hasProperty(rt, "2")); + EXPECT_FALSE(x.hasProperty(rt, PropNameID::forAscii(rt, "2"))); + EXPECT_TRUE(x.hasProperty(rt, "3")); + EXPECT_TRUE(x.hasProperty(rt, PropNameID::forAscii(rt, "3"))); + EXPECT_TRUE(x.hasProperty(rt, "seven")); + EXPECT_TRUE(x.hasProperty(rt, PropNameID::forAscii(rt, "seven"))); + EXPECT_EQ(x.getProperty(rt, "1").getNumber(), 2); + EXPECT_EQ(x.getProperty(rt, PropNameID::forAscii(rt, "1")).getNumber(), 2); + EXPECT_EQ(x.getProperty(rt, "3").getNumber(), 4); + Value five = 5; + EXPECT_EQ( + x.getProperty(rt, PropNameID::forString(rt, five.toString(rt))) + .getString(rt) + .utf8(rt), + "six"); + + x.setProperty(rt, "ten", 11); + EXPECT_EQ(x.getPropertyNames(rt).size(rt), 5); + EXPECT_TRUE(eval("x.ten == 11").getBool()); + + x.setProperty(rt, "e_as_float", 2.71f); + EXPECT_TRUE(eval("Math.abs(x.e_as_float - 2.71) < 0.001").getBool()); + + x.setProperty(rt, "e_as_double", 2.71); + EXPECT_TRUE(eval("x.e_as_double == 2.71").getBool()); + + uint8_t utf8[] = {0xF0, 0x9F, 0x86, 0x97}; + String nonAsciiName = String::createFromUtf8(rt, utf8, sizeof(utf8)); + x.setProperty(rt, PropNameID::forString(rt, nonAsciiName), "emoji"); + EXPECT_EQ(x.getPropertyNames(rt).size(rt), 8); + EXPECT_TRUE(eval("x['\\uD83C\\uDD97'] == 'emoji'").getBool()); + + Object seven = x.getPropertyAsObject(rt, "seven"); + EXPECT_TRUE(seven.isArray(rt)); + Object evalf = rt.global().getPropertyAsObject(rt, "eval"); + EXPECT_TRUE(evalf.isFunction(rt)); + + Object movedX = Object(rt); + movedX = std::move(x); + EXPECT_EQ(movedX.getPropertyNames(rt).size(rt), 8); + EXPECT_EQ(movedX.getProperty(rt, "1").getNumber(), 2); + + Object obj = Object(rt); + obj.setProperty(rt, "roses", "red"); + obj.setProperty(rt, "violets", "blue"); + Object oprop = Object(rt); + obj.setProperty(rt, "oprop", oprop); + obj.setProperty(rt, "aprop", Array(rt, 1)); + + EXPECT_TRUE(function("function (obj) { return " + "obj.roses == 'red' && " + "obj['violets'] == 'blue' && " + "typeof obj.oprop == 'object' && " + "Array.isArray(obj.aprop); }") + .call(rt, obj) + .getBool()); + + // Check that getPropertyNames doesn't return non-enumerable + // properties. + obj = function( + "function () {" + " obj = {};" + " obj.a = 1;" + " Object.defineProperty(obj, 'b', {" + " enumerable: false," + " value: 2" + " });" + " return obj;" + "}") + .call(rt) + .getObject(rt); + EXPECT_EQ(obj.getProperty(rt, "a").getNumber(), 1); + EXPECT_EQ(obj.getProperty(rt, "b").getNumber(), 2); + Array names = obj.getPropertyNames(rt); + EXPECT_EQ(names.size(rt), 1); + EXPECT_EQ(names.getValueAtIndex(rt, 0).getString(rt).utf8(rt), "a"); +} + +TEST_P(JSITest, HostObjectTest) { + class ConstantHostObject : public HostObject { + Value get(Runtime&, const PropNameID& sym) override { + return 9000; + } + + void set(Runtime&, const PropNameID&, const Value&) override {} + }; + + Object cho = + Object::createFromHostObject(rt, std::make_shared()); + EXPECT_TRUE(function("function (obj) { return obj.someRandomProp == 9000; }") + .call(rt, cho) + .getBool()); + EXPECT_TRUE(cho.isHostObject(rt)); + EXPECT_TRUE(cho.getHostObject(rt).get() != nullptr); + + struct SameRuntimeHostObject : HostObject { + SameRuntimeHostObject(Runtime& rt) : rt_(rt){}; + + Value get(Runtime& rt, const PropNameID& sym) override { + EXPECT_EQ(&rt, &rt_); + return Value(); + } + + void set(Runtime& rt, const PropNameID& name, const Value& value) override { + EXPECT_EQ(&rt, &rt_); + } + + std::vector getPropertyNames(Runtime& rt) override { + EXPECT_EQ(&rt, &rt_); + return {}; + } + + Runtime& rt_; + }; + + Object srho = Object::createFromHostObject( + rt, std::make_shared(rt)); + // Test get's Runtime is as expected + function("function (obj) { return obj.isSame; }").call(rt, srho); + // ... and set + function("function (obj) { obj['k'] = 'v'; }").call(rt, srho); + // ... and getPropertyNames + function("function (obj) { for (k in obj) {} }").call(rt, srho); + + class TwiceHostObject : public HostObject { + Value get(Runtime& rt, const PropNameID& sym) override { + return String::createFromUtf8(rt, sym.utf8(rt) + sym.utf8(rt)); + } + + void set(Runtime&, const PropNameID&, const Value&) override {} + }; + + Object tho = + Object::createFromHostObject(rt, std::make_shared()); + EXPECT_TRUE(function("function (obj) { return obj.abc == 'abcabc'; }") + .call(rt, tho) + .getBool()); + EXPECT_TRUE(function("function (obj) { return obj['def'] == 'defdef'; }") + .call(rt, tho) + .getBool()); + EXPECT_TRUE(function("function (obj) { return obj[12] === '1212'; }") + .call(rt, tho) + .getBool()); + EXPECT_TRUE(tho.isHostObject(rt)); + EXPECT_TRUE( + std::dynamic_pointer_cast(tho.getHostObject(rt)) == + nullptr); + EXPECT_TRUE(tho.getHostObject(rt).get() != nullptr); + + class PropNameIDHostObject : public HostObject { + Value get(Runtime& rt, const PropNameID& sym) override { + if (PropNameID::compare(rt, sym, PropNameID::forAscii(rt, "undef"))) { + return Value::undefined(); + } else { + return PropNameID::compare( + rt, sym, PropNameID::forAscii(rt, "somesymbol")); + } + } + + void set(Runtime&, const PropNameID&, const Value&) override {} + }; + + Object sho = Object::createFromHostObject( + rt, std::make_shared()); + EXPECT_TRUE(sho.isHostObject(rt)); + EXPECT_TRUE(function("function (obj) { return obj.undef; }") + .call(rt, sho) + .isUndefined()); + EXPECT_TRUE(function("function (obj) { return obj.somesymbol; }") + .call(rt, sho) + .getBool()); + EXPECT_FALSE(function("function (obj) { return obj.notsomuch; }") + .call(rt, sho) + .getBool()); + + class BagHostObject : public HostObject { + public: + const std::string& getThing() { + return bag_["thing"]; + } + + private: + Value get(Runtime& rt, const PropNameID& sym) override { + if (sym.utf8(rt) == "thing") { + return String::createFromUtf8(rt, bag_[sym.utf8(rt)]); + } + return Value::undefined(); + } + + void set(Runtime& rt, const PropNameID& sym, const Value& val) override { + std::string key(sym.utf8(rt)); + if (key == "thing") { + bag_[key] = val.toString(rt).utf8(rt); + } + } + + std::unordered_map bag_; + }; + + std::shared_ptr shbho = std::make_shared(); + Object bho = Object::createFromHostObject(rt, shbho); + EXPECT_TRUE(bho.isHostObject(rt)); + EXPECT_TRUE(function("function (obj) { return obj.undef; }") + .call(rt, bho) + .isUndefined()); + EXPECT_EQ( + function("function (obj) { obj.thing = 'hello'; return obj.thing; }") + .call(rt, bho) + .toString(rt) + .utf8(rt), + "hello"); + EXPECT_EQ(shbho->getThing(), "hello"); + + class ThrowingHostObject : public HostObject { + Value get(Runtime& rt, const PropNameID& sym) override { + throw std::runtime_error("Cannot get"); + } + + void set(Runtime& rt, const PropNameID& sym, const Value& val) override { + throw std::runtime_error("Cannot set"); + } + }; + + Object thro = + Object::createFromHostObject(rt, std::make_shared()); + EXPECT_TRUE(thro.isHostObject(rt)); + std::string exc; + try { + function("function (obj) { return obj.thing; }").call(rt, thro); + } catch (const JSError& ex) { + exc = ex.what(); + } + EXPECT_NE(exc.find("Cannot get"), std::string::npos); + exc = ""; + try { + function("function (obj) { obj.thing = 'hello'; }").call(rt, thro); + } catch (const JSError& ex) { + exc = ex.what(); + } + EXPECT_NE(exc.find("Cannot set"), std::string::npos); + + class NopHostObject : public HostObject {}; + Object nopHo = + Object::createFromHostObject(rt, std::make_shared()); + EXPECT_TRUE(nopHo.isHostObject(rt)); + EXPECT_TRUE(function("function (obj) { return obj.thing; }") + .call(rt, nopHo) + .isUndefined()); + + std::string nopExc; + try { + function("function (obj) { obj.thing = 'pika'; }").call(rt, nopHo); + } catch (const JSError& ex) { + nopExc = ex.what(); + } + EXPECT_NE(nopExc.find("TypeError: "), std::string::npos); + + class HostObjectWithPropertyNames : public HostObject { + std::vector getPropertyNames(Runtime& rt) override { + return PropNameID::names( + rt, "a_prop", "1", "false", "a_prop", "3", "c_prop"); + } + }; + + Object howpn = Object::createFromHostObject( + rt, std::make_shared()); + EXPECT_TRUE( + function( + "function (o) { return Object.getOwnPropertyNames(o).length == 5 }") + .call(rt, howpn) + .getBool()); + + auto hasOwnPropertyName = function( + "function (o, p) {" + " return Object.getOwnPropertyNames(o).indexOf(p) >= 0" + "}"); + EXPECT_TRUE( + hasOwnPropertyName.call(rt, howpn, String::createFromAscii(rt, "a_prop")) + .getBool()); + EXPECT_TRUE( + hasOwnPropertyName.call(rt, howpn, String::createFromAscii(rt, "1")) + .getBool()); + EXPECT_TRUE( + hasOwnPropertyName.call(rt, howpn, String::createFromAscii(rt, "false")) + .getBool()); + EXPECT_TRUE( + hasOwnPropertyName.call(rt, howpn, String::createFromAscii(rt, "3")) + .getBool()); + EXPECT_TRUE( + hasOwnPropertyName.call(rt, howpn, String::createFromAscii(rt, "c_prop")) + .getBool()); + EXPECT_FALSE(hasOwnPropertyName + .call(rt, howpn, String::createFromAscii(rt, "not_existing")) + .getBool()); +} + +TEST_P(JSITest, ArrayTest) { + eval("x = {1:2, '3':4, 5:'six', 'seven':['eight', 'nine']}"); + + Object x = rt.global().getPropertyAsObject(rt, "x"); + Array names = x.getPropertyNames(rt); + EXPECT_EQ(names.size(rt), 4); + std::unordered_set strNames; + for (size_t i = 0; i < names.size(rt); ++i) { + Value n = names.getValueAtIndex(rt, i); + EXPECT_TRUE(n.isString()); + strNames.insert(n.getString(rt).utf8(rt)); + } + + EXPECT_EQ(strNames.size(), 4); + EXPECT_EQ(strNames.count("1"), 1); + EXPECT_EQ(strNames.count("3"), 1); + EXPECT_EQ(strNames.count("5"), 1); + EXPECT_EQ(strNames.count("seven"), 1); + + Object seven = x.getPropertyAsObject(rt, "seven"); + Array arr = seven.getArray(rt); + + EXPECT_EQ(arr.size(rt), 2); + EXPECT_EQ(arr.getValueAtIndex(rt, 0).getString(rt).utf8(rt), "eight"); + EXPECT_EQ(arr.getValueAtIndex(rt, 1).getString(rt).utf8(rt), "nine"); + // TODO: test out of range + + EXPECT_EQ(x.getPropertyAsObject(rt, "seven").getArray(rt).size(rt), 2); + + // Check that property access with both symbols and strings can access + // array values. + EXPECT_EQ(seven.getProperty(rt, "0").getString(rt).utf8(rt), "eight"); + EXPECT_EQ(seven.getProperty(rt, "1").getString(rt).utf8(rt), "nine"); + seven.setProperty(rt, "1", "modified"); + EXPECT_EQ(seven.getProperty(rt, "1").getString(rt).utf8(rt), "modified"); + EXPECT_EQ(arr.getValueAtIndex(rt, 1).getString(rt).utf8(rt), "modified"); + EXPECT_EQ( + seven.getProperty(rt, PropNameID::forAscii(rt, "0")) + .getString(rt) + .utf8(rt), + "eight"); + seven.setProperty(rt, PropNameID::forAscii(rt, "0"), "modified2"); + EXPECT_EQ(arr.getValueAtIndex(rt, 0).getString(rt).utf8(rt), "modified2"); + + Array alpha = Array(rt, 4); + EXPECT_TRUE(alpha.getValueAtIndex(rt, 0).isUndefined()); + EXPECT_TRUE(alpha.getValueAtIndex(rt, 3).isUndefined()); + EXPECT_EQ(alpha.size(rt), 4); + alpha.setValueAtIndex(rt, 0, "a"); + alpha.setValueAtIndex(rt, 1, "b"); + EXPECT_EQ(alpha.length(rt), 4); + alpha.setValueAtIndex(rt, 2, "c"); + alpha.setValueAtIndex(rt, 3, "d"); + EXPECT_EQ(alpha.size(rt), 4); + + EXPECT_TRUE( + function( + "function (arr) { return " + "arr.length == 4 && " + "['a','b','c','d'].every(function(v,i) { return v === arr[i]}); }") + .call(rt, alpha) + .getBool()); + + Array alpha2 = Array(rt, 1); + alpha2 = std::move(alpha); + EXPECT_EQ(alpha2.size(rt), 4); +} + +TEST_P(JSITest, FunctionTest) { + // test move ctor + Function fmove = function("function() { return 1 }"); + { + Function g = function("function() { return 2 }"); + fmove = std::move(g); + } + EXPECT_EQ(fmove.call(rt).getNumber(), 2); + + // This tests all the function argument converters, and all the + // non-lvalue overloads of call(). + Function f = function( + "function(n, b, d, df, i, s1, s2, s3, o, a, f, v) { return " + "n === null && " + "b === true && " + "d === 3.14 && " + "Math.abs(df - 2.71) < 0.001 && " + "i === 17 && " + "s1 == 's1' && " + "s2 == 's2' && " + "s3 == 's3' && " + "typeof o == 'object' && " + "Array.isArray(a) && " + "typeof f == 'function' && " + "v == 42 }"); + std::string s3 = "s3"; + EXPECT_TRUE(f.call( + rt, + nullptr, + true, + 3.14, + 2.71f, + 17, + "s1", + String::createFromAscii(rt, "s2"), + s3, + Object(rt), + Array(rt, 1), + function("function(){}"), + Value(42)) + .getBool()); + + // lvalue overloads of call() + Function flv = function( + "function(s, o, a, f, v) { return " + "s == 's' && " + "typeof o == 'object' && " + "Array.isArray(a) && " + "typeof f == 'function' && " + "v == 42 }"); + + String s = String::createFromAscii(rt, "s"); + Object o = Object(rt); + Array a = Array(rt, 1); + Value v = 42; + EXPECT_TRUE(flv.call(rt, s, o, a, f, v).getBool()); + + Function f1 = function("function() { return 1; }"); + Function f2 = function("function() { return 2; }"); + f2 = std::move(f1); + EXPECT_EQ(f2.call(rt).getNumber(), 1); +} + +TEST_P(JSITest, FunctionThisTest) { + Function checkPropertyFunction = + function("function() { return this.a === 'a_property' }"); + + Object jsObject = Object(rt); + jsObject.setProperty(rt, "a", String::createFromUtf8(rt, "a_property")); + + class APropertyHostObject : public HostObject { + Value get(Runtime& rt, const PropNameID& sym) override { + return String::createFromUtf8(rt, "a_property"); + } + + void set(Runtime&, const PropNameID&, const Value&) override {} + }; + Object hostObject = + Object::createFromHostObject(rt, std::make_shared()); + + EXPECT_TRUE(checkPropertyFunction.callWithThis(rt, jsObject).getBool()); + EXPECT_TRUE(checkPropertyFunction.callWithThis(rt, hostObject).getBool()); + EXPECT_FALSE(checkPropertyFunction.callWithThis(rt, Array(rt, 5)).getBool()); + EXPECT_FALSE(checkPropertyFunction.call(rt).getBool()); +} + +TEST_P(JSITest, FunctionConstructorTest) { + Function ctor = function( + "function (a) {" + " if (typeof a !== 'undefined') {" + " this.pika = a;" + " }" + "}"); + ctor.getProperty(rt, "prototype") + .getObject(rt) + .setProperty(rt, "pika", "chu"); + auto empty = ctor.callAsConstructor(rt); + ASSERT_TRUE(empty.isObject()); + auto emptyObj = std::move(empty).getObject(rt); + EXPECT_EQ(emptyObj.getProperty(rt, "pika").getString(rt).utf8(rt), "chu"); + auto who = ctor.callAsConstructor(rt, "who"); + ASSERT_TRUE(who.isObject()); + auto whoObj = std::move(who).getObject(rt); + EXPECT_EQ(whoObj.getProperty(rt, "pika").getString(rt).utf8(rt), "who"); + + auto instanceof = function("function (o, b) { return o instanceof b; }"); + EXPECT_TRUE(instanceof.call(rt, emptyObj, ctor).getBool()); + EXPECT_TRUE(instanceof.call(rt, whoObj, ctor).getBool()); + + auto dateCtor = rt.global().getPropertyAsFunction(rt, "Date"); + auto date = dateCtor.callAsConstructor(rt); + EXPECT_TRUE(date.isObject()); + EXPECT_TRUE(instanceof.call(rt, date, dateCtor).getBool()); + // Sleep for 50 milliseconds + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + EXPECT_GE( + function("function (d) { return (new Date()).getTime() - d.getTime(); }") + .call(rt, date) + .getNumber(), + 50); +} + +TEST_P(JSITest, InstanceOfTest) { + auto ctor = function("function Rick() { this.say = 'wubalubadubdub'; }"); + auto newObj = function("function (ctor) { return new ctor(); }"); + auto instance = newObj.call(rt, ctor).getObject(rt); + EXPECT_TRUE(instance.instanceOf(rt, ctor)); + EXPECT_EQ( + instance.getProperty(rt, "say").getString(rt).utf8(rt), "wubalubadubdub"); + EXPECT_FALSE(Object(rt).instanceOf(rt, ctor)); + EXPECT_TRUE(ctor.callAsConstructor(rt, nullptr, 0) + .getObject(rt) + .instanceOf(rt, ctor)); +} + +TEST_P(JSITest, HostFunctionTest) { + auto one = std::make_shared(1); + Function plusOne = Function::createFromHostFunction( + rt, + PropNameID::forAscii(rt, "plusOne"), + 2, + [one, savedRt = &rt]( + Runtime& rt, const Value& thisVal, const Value* args, size_t count) { + EXPECT_EQ(savedRt, &rt); + // We don't know if we're in strict mode or not, so it's either global + // or undefined. + EXPECT_TRUE( + Value::strictEquals(rt, thisVal, rt.global()) || + thisVal.isUndefined()); + return *one + args[0].getNumber() + args[1].getNumber(); + }); + + EXPECT_EQ(plusOne.call(rt, 1, 2).getNumber(), 4); + EXPECT_TRUE(checkValue(plusOne.call(rt, 3, 5), "9")); + rt.global().setProperty(rt, "plusOne", plusOne); + EXPECT_TRUE(eval("plusOne(20, 300) == 321").getBool()); + + Function dot = Function::createFromHostFunction( + rt, + PropNameID::forAscii(rt, "dot"), + 2, + [](Runtime& rt, const Value& thisVal, const Value* args, size_t count) { + EXPECT_TRUE( + Value::strictEquals(rt, thisVal, rt.global()) || + thisVal.isUndefined()); + if (count != 2) { + throw std::runtime_error("expected 2 args"); + } + std::string ret = args[0].getString(rt).utf8(rt) + "." + + args[1].getString(rt).utf8(rt); + return String::createFromUtf8( + rt, reinterpret_cast(ret.data()), ret.size()); + }); + + rt.global().setProperty(rt, "cons", dot); + EXPECT_TRUE(eval("cons('left', 'right') == 'left.right'").getBool()); + EXPECT_TRUE(eval("cons.name == 'dot'").getBool()); + EXPECT_TRUE(eval("cons.length == 2").getBool()); + EXPECT_TRUE(eval("cons instanceof Function").getBool()); + + EXPECT_TRUE(eval("(function() {" + " try {" + " cons('fail'); return false;" + " } catch (e) {" + " return ((e instanceof Error) &&" + " (e.message == 'Exception in HostFunction: ' +" + " 'expected 2 args'));" + " }})()") + .getBool()); + + Function coolify = Function::createFromHostFunction( + rt, + PropNameID::forAscii(rt, "coolify"), + 0, + [](Runtime& rt, const Value& thisVal, const Value* args, size_t count) { + EXPECT_EQ(count, 0); + std::string ret = thisVal.toString(rt).utf8(rt) + " is cool"; + return String::createFromUtf8( + rt, reinterpret_cast(ret.data()), ret.size()); + }); + rt.global().setProperty(rt, "coolify", coolify); + EXPECT_TRUE(eval("coolify.name == 'coolify'").getBool()); + EXPECT_TRUE(eval("coolify.length == 0").getBool()); + EXPECT_TRUE(eval("coolify.bind('R&M')() == 'R&M is cool'").getBool()); + EXPECT_TRUE(eval("(function() {" + " var s = coolify.bind(function(){})();" + " return s.lastIndexOf(' is cool') == (s.length - 8);" + "})()") + .getBool()); + + Function lookAtMe = Function::createFromHostFunction( + rt, + PropNameID::forAscii(rt, "lookAtMe"), + 0, + [](Runtime& rt, const Value& thisVal, const Value* args, size_t count) + -> Value { + EXPECT_TRUE(thisVal.isObject()); + EXPECT_EQ( + thisVal.getObject(rt) + .getProperty(rt, "name") + .getString(rt) + .utf8(rt), + "mr.meeseeks"); + return Value(); + }); + rt.global().setProperty(rt, "lookAtMe", lookAtMe); + EXPECT_TRUE(eval("lookAtMe.bind({'name': 'mr.meeseeks'})()").isUndefined()); + + struct Callable { + Callable(std::string s) : str(s) {} + + Value + operator()(Runtime& rt, const Value&, const Value* args, size_t count) { + if (count != 1) { + return Value(); + } + return String::createFromUtf8( + rt, args[0].toString(rt).utf8(rt) + " was called with " + str); + } + + std::string str; + }; + + Function callable = Function::createFromHostFunction( + rt, + PropNameID::forAscii(rt, "callable"), + 1, + Callable("std::function::target")); + EXPECT_EQ( + function("function (f) { return f('A cat'); }") + .call(rt, callable) + .getString(rt) + .utf8(rt), + "A cat was called with std::function::target"); + EXPECT_TRUE(callable.isHostFunction(rt)); + EXPECT_NE(callable.getHostFunction(rt).target(), nullptr); + + std::string strval = "strval1"; + auto getter = Object(rt); + getter.setProperty( + rt, + "get", + Function::createFromHostFunction( + rt, + PropNameID::forAscii(rt, "getter"), + 1, + [&strval]( + Runtime& rt, + const Value& thisVal, + const Value* args, + size_t count) -> Value { + return String::createFromUtf8(rt, strval); + })); + auto obj = Object(rt); + rt.global() + .getPropertyAsObject(rt, "Object") + .getPropertyAsFunction(rt, "defineProperty") + .call(rt, obj, "prop", getter); + EXPECT_TRUE(function("function(value) { return value.prop == 'strval1'; }") + .call(rt, obj) + .getBool()); + strval = "strval2"; + EXPECT_TRUE(function("function(value) { return value.prop == 'strval2'; }") + .call(rt, obj) + .getBool()); +} + +TEST_P(JSITest, ValueTest) { + EXPECT_TRUE(checkValue(Value::undefined(), "undefined")); + EXPECT_TRUE(checkValue(Value(), "undefined")); + EXPECT_TRUE(checkValue(Value::null(), "null")); + EXPECT_TRUE(checkValue(nullptr, "null")); + + EXPECT_TRUE(checkValue(Value(false), "false")); + EXPECT_TRUE(checkValue(false, "false")); + EXPECT_TRUE(checkValue(true, "true")); + + EXPECT_TRUE(checkValue(Value(1.5), "1.5")); + EXPECT_TRUE(checkValue(2.5, "2.5")); + + EXPECT_TRUE(checkValue(Value(10), "10")); + EXPECT_TRUE(checkValue(20, "20")); + EXPECT_TRUE(checkValue(30, "30")); + + // rvalue implicit conversion + EXPECT_TRUE(checkValue(String::createFromAscii(rt, "one"), "'one'")); + // lvalue explicit copy + String s = String::createFromAscii(rt, "two"); + EXPECT_TRUE(checkValue(Value(rt, s), "'two'")); + + { + // rvalue assignment of trivial value + Value v1 = 100; + Value v2 = String::createFromAscii(rt, "hundred"); + v2 = std::move(v1); + EXPECT_TRUE(v2.isNumber()); + EXPECT_EQ(v2.getNumber(), 100); + } + + { + // rvalue assignment of js heap value + Value v1 = String::createFromAscii(rt, "hundred"); + Value v2 = 100; + v2 = std::move(v1); + EXPECT_TRUE(v2.isString()); + EXPECT_EQ(v2.getString(rt).utf8(rt), "hundred"); + } + + Object o = Object(rt); + EXPECT_TRUE(function("function(value) { return typeof(value) == 'object'; }") + .call(rt, Value(rt, o)) + .getBool()); + + uint8_t utf8[] = "[null, 2, \"c\", \"emoji: \xf0\x9f\x86\x97\", {}]"; + + EXPECT_TRUE( + function("function (arr) { return " + "Array.isArray(arr) && " + "arr.length == 5 && " + "arr[0] === null && " + "arr[1] == 2 && " + "arr[2] == 'c' && " + "arr[3] == 'emoji: \\uD83C\\uDD97' && " + "typeof arr[4] == 'object'; }") + .call(rt, Value::createFromJsonUtf8(rt, utf8, sizeof(utf8) - 1)) + .getBool()); + + EXPECT_TRUE(eval("undefined").isUndefined()); + EXPECT_TRUE(eval("null").isNull()); + EXPECT_TRUE(eval("true").isBool()); + EXPECT_TRUE(eval("false").isBool()); + EXPECT_TRUE(eval("123").isNumber()); + EXPECT_TRUE(eval("123.4").isNumber()); + EXPECT_TRUE(eval("'str'").isString()); + // "{}" returns undefined. empty code block? + EXPECT_TRUE(eval("({})").isObject()); + EXPECT_TRUE(eval("[]").isObject()); + EXPECT_TRUE(eval("(function(){})").isObject()); + + EXPECT_EQ(eval("123").getNumber(), 123); + EXPECT_EQ(eval("123.4").getNumber(), 123.4); + EXPECT_EQ(eval("'str'").getString(rt).utf8(rt), "str"); + EXPECT_TRUE(eval("[]").getObject(rt).isArray(rt)); + + EXPECT_EQ(eval("456").asNumber(), 456); + EXPECT_THROW(eval("'word'").asNumber(), JSIException); + EXPECT_EQ( + eval("({1:2, 3:4})").asObject(rt).getProperty(rt, "1").getNumber(), 2); + EXPECT_THROW(eval("'oops'").asObject(rt), JSIException); + + EXPECT_EQ(eval("['zero',1,2,3]").toString(rt).utf8(rt), "zero,1,2,3"); +} + +TEST_P(JSITest, EqualsTest) { + EXPECT_TRUE(Object::strictEquals(rt, rt.global(), rt.global())); + EXPECT_TRUE(Value::strictEquals(rt, 1, 1)); + EXPECT_FALSE(Value::strictEquals(rt, true, 1)); + EXPECT_FALSE(Value::strictEquals(rt, true, false)); + EXPECT_TRUE(Value::strictEquals(rt, false, false)); + EXPECT_FALSE(Value::strictEquals(rt, nullptr, 1)); + EXPECT_TRUE(Value::strictEquals(rt, nullptr, nullptr)); + EXPECT_TRUE(Value::strictEquals(rt, Value::undefined(), Value())); + EXPECT_TRUE(Value::strictEquals(rt, rt.global(), Value(rt.global()))); + EXPECT_FALSE(Value::strictEquals( + rt, + std::numeric_limits::quiet_NaN(), + std::numeric_limits::quiet_NaN())); + EXPECT_FALSE(Value::strictEquals( + rt, + std::numeric_limits::signaling_NaN(), + std::numeric_limits::signaling_NaN())); + EXPECT_TRUE(Value::strictEquals(rt, +0.0, -0.0)); + EXPECT_TRUE(Value::strictEquals(rt, -0.0, +0.0)); + + Function noop = Function::createFromHostFunction( + rt, + PropNameID::forAscii(rt, "noop"), + 0, + [](const Runtime&, const Value&, const Value*, size_t) { + return Value(); + }); + auto noopDup = Value(rt, noop).getObject(rt); + EXPECT_TRUE(Object::strictEquals(rt, noop, noopDup)); + EXPECT_TRUE(Object::strictEquals(rt, noopDup, noop)); + EXPECT_FALSE(Object::strictEquals(rt, noop, rt.global())); + EXPECT_TRUE(Object::strictEquals(rt, noop, noop)); + EXPECT_TRUE(Value::strictEquals(rt, Value(rt, noop), Value(rt, noop))); + + String str = String::createFromAscii(rt, "rick"); + String strDup = String::createFromAscii(rt, "rick"); + String otherStr = String::createFromAscii(rt, "morty"); + EXPECT_TRUE(String::strictEquals(rt, str, str)); + EXPECT_TRUE(String::strictEquals(rt, str, strDup)); + EXPECT_TRUE(String::strictEquals(rt, strDup, str)); + EXPECT_FALSE(String::strictEquals(rt, str, otherStr)); + EXPECT_TRUE(Value::strictEquals(rt, Value(rt, str), Value(rt, str))); + EXPECT_FALSE(Value::strictEquals(rt, Value(rt, str), Value(rt, noop))); + EXPECT_FALSE(Value::strictEquals(rt, Value(rt, str), 1.0)); +} + +TEST_P(JSITest, ExceptionStackTraceTest) { + static const char invokeUndefinedScript[] = + "function hello() {" + " var a = {}; a.log(); }" + "function world() { hello(); }" + "world()"; + std::string stack; + try { + rt.evaluateJavaScript( + std::make_unique(invokeUndefinedScript), ""); + } catch (JSError& e) { + stack = e.getStack(); + } + EXPECT_NE(stack.find("world"), std::string::npos); +} + +TEST_P(JSITest, PreparedJavaScriptSourceTest) { + rt.evaluateJavaScript(std::make_unique("var q = 0;"), ""); + auto prep = rt.prepareJavaScript(std::make_unique("q++;"), ""); + EXPECT_EQ(rt.global().getProperty(rt, "q").getNumber(), 0); + rt.evaluatePreparedJavaScript(prep); + EXPECT_EQ(rt.global().getProperty(rt, "q").getNumber(), 1); + rt.evaluatePreparedJavaScript(prep); + EXPECT_EQ(rt.global().getProperty(rt, "q").getNumber(), 2); +} + +TEST_P(JSITest, PreparedJavaScriptURLInBacktrace) { + std::string sourceURL = "//PreparedJavaScriptURLInBacktrace/Test/URL"; + std::string throwingSource = + "function thrower() { throw new Error('oops')}" + "thrower();"; + auto prep = rt.prepareJavaScript( + std::make_unique(throwingSource), sourceURL); + try { + rt.evaluatePreparedJavaScript(prep); + FAIL() << "prepareJavaScript should have thrown an exception"; + } catch (facebook::jsi::JSError err) { + EXPECT_NE(std::string::npos, err.getStack().find(sourceURL)) + << "Backtrace should contain source URL"; + } +} + +namespace { + +unsigned countOccurences(const std::string& of, const std::string& in) { + unsigned occurences = 0; + std::string::size_type lastOccurence = -1; + while ((lastOccurence = in.find(of, lastOccurence + 1)) != + std::string::npos) { + occurences++; + } + return occurences; +} + +} // namespace + +TEST_P(JSITest, JSErrorsArePropagatedNicely) { + unsigned callsBeoreError = 5; + + Function sometimesThrows = function( + "function sometimesThrows(shouldThrow, callback) {" + " if (shouldThrow) {" + " throw Error('Omg, what a nasty exception')" + " }" + " callback(callback);" + "}"); + + Function callback = Function::createFromHostFunction( + rt, + PropNameID::forAscii(rt, "callback"), + 0, + [&sometimesThrows, &callsBeoreError]( + Runtime& rt, const Value& thisVal, const Value* args, size_t count) { + return sometimesThrows.call(rt, --callsBeoreError == 0, args[0]); + }); + + try { + sometimesThrows.call(rt, false, callback); + } catch (JSError& error) { + EXPECT_EQ(error.getMessage(), "Omg, what a nasty exception"); + EXPECT_EQ(countOccurences("sometimesThrows", error.getStack()), 6); + + // system JSC JSI does not implement host function names + // EXPECT_EQ(countOccurences("callback", error.getStack(rt)), 5); + } +} + +TEST_P(JSITest, JSErrorsCanBeConstructedWithStack) { + auto err = JSError(rt, "message", "stack"); + EXPECT_EQ(err.getMessage(), "message"); + EXPECT_EQ(err.getStack(), "stack"); +} + +TEST_P(JSITest, ScopeDoesNotCrashTest) { + Scope scope(rt); + Object o(rt); +} + +TEST_P(JSITest, ScopeDoesNotCrashWhenValueEscapes) { + Value v; + Scope::callInNewScope(rt, [&]() { + Object o(rt); + o.setProperty(rt, "a", 5); + v = std::move(o); + }); + EXPECT_EQ(v.getObject(rt).getProperty(rt, "a").getNumber(), 5); +} + +// Verifies you can have a host object that emulates a normal object +TEST_P(JSITest, HostObjectWithValueMembers) { + class Bag : public HostObject { + public: + Bag() = default; + + const Value& operator[](const std::string& name) const { + auto iter = data_.find(name); + if (iter == data_.end()) { + return undef_; + } + return iter->second; + } + + protected: + Value get(Runtime& rt, const PropNameID& name) override { + return Value(rt, (*this)[name.utf8(rt)]); + } + + void set(Runtime& rt, const PropNameID& name, const Value& val) override { + data_.emplace(name.utf8(rt), Value(rt, val)); + } + + Value undef_; + std::map data_; + }; + + auto sharedBag = std::make_shared(); + auto& bag = *sharedBag; + Object jsbag = Object::createFromHostObject(rt, std::move(sharedBag)); + auto set = function( + "function (o) {" + " o.foo = 'bar';" + " o.count = 37;" + " o.nul = null;" + " o.iscool = true;" + " o.obj = { 'foo': 'bar' };" + "}"); + set.call(rt, jsbag); + auto checkFoo = function("function (o) { return o.foo === 'bar'; }"); + auto checkCount = function("function (o) { return o.count === 37; }"); + auto checkNul = function("function (o) { return o.nul === null; }"); + auto checkIsCool = function("function (o) { return o.iscool === true; }"); + auto checkObj = function( + "function (o) {" + " return (typeof o.obj) === 'object' && o.obj.foo === 'bar';" + "}"); + // Check this looks good from js + EXPECT_TRUE(checkFoo.call(rt, jsbag).getBool()); + EXPECT_TRUE(checkCount.call(rt, jsbag).getBool()); + EXPECT_TRUE(checkNul.call(rt, jsbag).getBool()); + EXPECT_TRUE(checkIsCool.call(rt, jsbag).getBool()); + EXPECT_TRUE(checkObj.call(rt, jsbag).getBool()); + + // Check this looks good from c++ + EXPECT_EQ(bag["foo"].getString(rt).utf8(rt), "bar"); + EXPECT_EQ(bag["count"].getNumber(), 37); + EXPECT_TRUE(bag["nul"].isNull()); + EXPECT_TRUE(bag["iscool"].getBool()); + EXPECT_EQ( + bag["obj"].getObject(rt).getProperty(rt, "foo").getString(rt).utf8(rt), + "bar"); +} + +TEST_P(JSITest, DecoratorTest) { + struct Count { + // init here is just to show that a With type does not need to be + // default constructible. + explicit Count(int init) : count(init) {} + + // Test optional before method. + + void after() { + ++count; + } + + int count; + }; + + static constexpr int kInit = 17; + + class CountRuntime final : public WithRuntimeDecorator { + public: + explicit CountRuntime(std::unique_ptr rt) + : WithRuntimeDecorator(*rt, count_), + rt_(std::move(rt)), + count_(kInit) {} + + int count() { + return count_.count; + } + + private: + std::unique_ptr rt_; + Count count_; + }; + + CountRuntime crt(factory()); + + crt.description(); + EXPECT_EQ(crt.count(), kInit + 1); + + crt.global().setProperty(crt, "o", Object(crt)); + EXPECT_EQ(crt.count(), kInit + 6); +} + +TEST_P(JSITest, MultiDecoratorTest) { + struct Inc { + void before() { + ++count; + } + + // Test optional after method. + + int count = 0; + }; + + struct Nest { + void before() { + ++nest; + } + + void after() { + --nest; + } + + int nest = 0; + }; + + class MultiRuntime final : public WithRuntimeDecorator> { + public: + explicit MultiRuntime(std::unique_ptr rt) + : WithRuntimeDecorator>(*rt, tuple_), + rt_(std::move(rt)) {} + + int count() { + return std::get<0>(tuple_).count; + } + int nest() { + return std::get<1>(tuple_).nest; + } + + private: + std::unique_ptr rt_; + WithTuple tuple_; + }; + + MultiRuntime mrt(factory()); + + Function expectNestOne = Function::createFromHostFunction( + mrt, + PropNameID::forAscii(mrt, "expectNestOne"), + 0, + [](Runtime& rt, const Value& thisVal, const Value* args, size_t count) { + MultiRuntime* funcmrt = dynamic_cast(&rt); + EXPECT_NE(funcmrt, nullptr); + EXPECT_EQ(funcmrt->count(), 3); + EXPECT_EQ(funcmrt->nest(), 1); + return Value::undefined(); + }); + + expectNestOne.call(mrt); + + EXPECT_EQ(mrt.count(), 3); + EXPECT_EQ(mrt.nest(), 0); +} + +TEST_P(JSITest, SymbolTest) { + if (!rt.global().hasProperty(rt, "Symbol")) { + // Symbol is an es6 feature which doesn't exist in older VMs. So + // the tests which might be elsewhere are all here so they can be + // skipped. + return; + } + + // ObjectTest + eval("x = {1:2, 'three':Symbol('four')}"); + Object x = rt.global().getPropertyAsObject(rt, "x"); + EXPECT_EQ(x.getPropertyNames(rt).size(rt), 2); + EXPECT_TRUE(x.hasProperty(rt, "three")); + EXPECT_EQ( + x.getProperty(rt, "three").getSymbol(rt).toString(rt), "Symbol(four)"); + + // ValueTest + EXPECT_TRUE(eval("Symbol('sym')").isSymbol()); + EXPECT_EQ(eval("Symbol('sym')").getSymbol(rt).toString(rt), "Symbol(sym)"); + + // EqualsTest + EXPECT_FALSE(Symbol::strictEquals( + rt, + eval("Symbol('a')").getSymbol(rt), + eval("Symbol('a')").getSymbol(rt))); + EXPECT_TRUE(Symbol::strictEquals( + rt, + eval("Symbol.for('a')").getSymbol(rt), + eval("Symbol.for('a')").getSymbol(rt))); + EXPECT_FALSE( + Value::strictEquals(rt, eval("Symbol('a')"), eval("Symbol('a')"))); + EXPECT_TRUE(Value::strictEquals( + rt, eval("Symbol.for('a')"), eval("Symbol.for('a')"))); + EXPECT_FALSE(Value::strictEquals(rt, eval("Symbol('a')"), eval("'a'"))); +} + +INSTANTIATE_TEST_CASE_P( + Runtimes, + JSITest, + ::testing::ValuesIn(runtimeGenerators())); diff --git a/ReactCommon/jsi/jsi/test/testlib.h b/ReactCommon/jsi/jsi/test/testlib.h new file mode 100644 index 00000000000000..604fc044d6f773 --- /dev/null +++ b/ReactCommon/jsi/jsi/test/testlib.h @@ -0,0 +1,48 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the LICENSE + * file in the root directory of this source tree. + */ +#pragma once + +#include +#include +#include + +#include +#include + +namespace facebook { +namespace jsi { + +class Runtime; + +using RuntimeFactory = std::function()>; + +std::vector runtimeGenerators(); + +class JSITestBase : public ::testing::TestWithParam { + public: + JSITestBase() : factory(GetParam()), runtime(factory()), rt(*runtime) {} + + Value eval(const char* code) { + return rt.global().getPropertyAsFunction(rt, "eval").call(rt, code); + } + + Function function(const std::string& code) { + return eval(("(" + code + ")").c_str()).getObject(rt).getFunction(rt); + } + + bool checkValue(const Value& value, const std::string& jsValue) { + return function("function(value) { return value == " + jsValue + "; }") + .call(rt, std::move(value)) + .getBool(); + } + + RuntimeFactory factory; + std::unique_ptr runtime; + Runtime& rt; +}; +} // namespace jsi +} // namespace facebook From 15302284cc4d1840e9003ab781626c156d3691aa Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 4 Jun 2019 15:28:24 -0700 Subject: [PATCH 0196/1084] Fabric: Enable CXX (aka Default) platfrom fravour for all C++ Fabric targets Summary: First of all, seems it's the right thing to do. Fabric C++ code is cross-platfrom and should run on *all* platforms including Windows, Linux, and Mac. While we don't have a real *production* use cases where we need compilation for desktops, having CXX target is really handy for two reasons: * It simplifies local test running process. Instead of going to `/fbandroid/` and executing something like `buck test fbsource//xplat/js/react-native-github/ReactCommon/fabric/core:coreAndroid` (note the suffix). We can just do `buck test fbsource//xplat/js/react-native-github/ReactCommon/fabric/core:core` everywhere and it works now out of the box. Running tests with "Apple" flavor never worked for me. * It allows creating synthetic benchmark tests (using Google Benchmark) that can be used as a rough approximation of code micro-optimizations. Reviewed By: JoshuaGross Differential Revision: D15608678 fbshipit-source-id: d2449035685dbca6ab983480f5334ec4ac11cd35 --- ReactCommon/better/BUCK | 3 +- ReactCommon/config/BUCK | 4 +- ReactCommon/fabric/attributedstring/BUCK | 5 +- .../fabric/components/activityindicator/BUCK | 17 ++++-- ReactCommon/fabric/components/image/BUCK | 5 +- ReactCommon/fabric/components/modal/BUCK | 9 ++-- ReactCommon/fabric/components/root/BUCK | 5 +- ReactCommon/fabric/components/scrollview/BUCK | 5 +- ReactCommon/fabric/components/slider/BUCK | 13 +++-- ReactCommon/fabric/components/text/BUCK | 15 ++++-- ReactCommon/fabric/components/view/BUCK | 5 +- ReactCommon/fabric/core/BUCK | 17 ++++-- ReactCommon/fabric/debug/BUCK | 5 +- ReactCommon/fabric/graphics/BUCK | 20 +++++-- .../platform/{android => cxx}/Color.cpp | 0 .../platform/{android => cxx}/Color.h | 0 .../platform/{android => cxx}/Float.h | 0 ReactCommon/fabric/imagemanager/BUCK | 10 ++-- .../{android => cxx}/ImageManager.cpp | 0 .../{android => cxx}/ImageRequest.cpp | 0 ReactCommon/fabric/mounting/BUCK | 5 +- ReactCommon/fabric/textlayoutmanager/BUCK | 42 ++++++++++----- .../platform/cxx/TextLayoutManager.cpp | 27 ++++++++++ .../platform/cxx/TextLayoutManager.h | 54 +++++++++++++++++++ ReactCommon/fabric/uimanager/BUCK | 5 +- ReactCommon/utils/BUCK | 4 +- packages/react-native-codegen/DEFS.bzl | 5 +- 27 files changed, 216 insertions(+), 64 deletions(-) rename ReactCommon/fabric/graphics/platform/{android => cxx}/Color.cpp (100%) rename ReactCommon/fabric/graphics/platform/{android => cxx}/Color.h (100%) rename ReactCommon/fabric/graphics/platform/{android => cxx}/Float.h (100%) rename ReactCommon/fabric/imagemanager/platform/{android => cxx}/ImageManager.cpp (100%) rename ReactCommon/fabric/imagemanager/platform/{android => cxx}/ImageRequest.cpp (100%) create mode 100644 ReactCommon/fabric/textlayoutmanager/platform/cxx/TextLayoutManager.cpp create mode 100644 ReactCommon/fabric/textlayoutmanager/platform/cxx/TextLayoutManager.h diff --git a/ReactCommon/better/BUCK b/ReactCommon/better/BUCK index d59c2672394a93..8708525242bdbe 100644 --- a/ReactCommon/better/BUCK +++ b/ReactCommon/better/BUCK @@ -3,6 +3,7 @@ load( "//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", + "CXX", "get_apple_compiler_flags", "get_apple_inspector_flags", "rn_xplat_cxx_library", @@ -38,7 +39,7 @@ rn_xplat_cxx_library( fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), force_static = True, macosx_tests_override = [], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", diff --git a/ReactCommon/config/BUCK b/ReactCommon/config/BUCK index 85ad4e3edae348..2e74ef11533ec5 100644 --- a/ReactCommon/config/BUCK +++ b/ReactCommon/config/BUCK @@ -1,4 +1,4 @@ -load("@fbsource//tools/build_defs:default_platform_defs.bzl", "ANDROID", "APPLE") +load("@fbsource//tools/build_defs:default_platform_defs.bzl", "ANDROID", "APPLE", "CXX") load("@fbsource//tools/build_defs:glob_defs.bzl", "subdir_glob") load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "flags", "get_debug_preprocessor_flags", "get_static_library_ios_flags") load("@fbsource//tools/build_defs/oss:rn_defs.bzl", "get_apple_inspector_flags", "rn_xplat_cxx_library") @@ -27,7 +27,7 @@ rn_xplat_cxx_library( fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), force_static = True, - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", diff --git a/ReactCommon/fabric/attributedstring/BUCK b/ReactCommon/fabric/attributedstring/BUCK index a0f0b3bfb08075..58b66dd2f0fc27 100644 --- a/ReactCommon/fabric/attributedstring/BUCK +++ b/ReactCommon/fabric/attributedstring/BUCK @@ -3,6 +3,7 @@ load( "//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", + "CXX", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", @@ -40,7 +41,7 @@ rn_xplat_cxx_library( fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), force_static = True, macosx_tests_override = [], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", @@ -72,7 +73,7 @@ fb_xplat_cxx_test( "-Wall", ], contacts = ["oncall+react_native@xmail.facebook.com"], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), deps = [ "fbsource//xplat/folly:molly", "fbsource//xplat/third-party/gmock:gtest", diff --git a/ReactCommon/fabric/components/activityindicator/BUCK b/ReactCommon/fabric/components/activityindicator/BUCK index a1440b1a49846f..17866577999176 100644 --- a/ReactCommon/fabric/components/activityindicator/BUCK +++ b/ReactCommon/fabric/components/activityindicator/BUCK @@ -1,5 +1,16 @@ load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_debug_preprocessor_flags") -load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", "react_native_xplat_target", "rn_xplat_cxx_library", "subdir_glob") +load( + "//tools/build_defs/oss:rn_defs.bzl", + "ANDROID", + "APPLE", + "CXX", + "fb_xplat_cxx_test", + "get_apple_compiler_flags", + "get_apple_inspector_flags", + "react_native_xplat_target", + "rn_xplat_cxx_library", + "subdir_glob", +) APPLE_COMPILER_FLAGS = get_apple_compiler_flags() @@ -26,7 +37,7 @@ rn_xplat_cxx_library( fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), macosx_tests_override = [], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", @@ -57,7 +68,7 @@ fb_xplat_cxx_test( "-std=c++14", "-Wall", ], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), deps = [ "fbsource//xplat/folly:molly", "fbsource//xplat/third-party/gmock:gtest", diff --git a/ReactCommon/fabric/components/image/BUCK b/ReactCommon/fabric/components/image/BUCK index 8416205ae70fae..539fde772bf316 100644 --- a/ReactCommon/fabric/components/image/BUCK +++ b/ReactCommon/fabric/components/image/BUCK @@ -3,6 +3,7 @@ load( "//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", + "CXX", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", @@ -36,7 +37,7 @@ rn_xplat_cxx_library( fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), macosx_tests_override = [], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", @@ -69,7 +70,7 @@ fb_xplat_cxx_test( "-Wall", ], contacts = ["oncall+react_native@xmail.facebook.com"], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), deps = [ "fbsource//xplat/folly:molly", "fbsource//xplat/third-party/gmock:gtest", diff --git a/ReactCommon/fabric/components/modal/BUCK b/ReactCommon/fabric/components/modal/BUCK index 94272fdfecb815..a8c0314f87c62c 100644 --- a/ReactCommon/fabric/components/modal/BUCK +++ b/ReactCommon/fabric/components/modal/BUCK @@ -3,10 +3,10 @@ load( "//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", + "CXX", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", - "react_native_target", "react_native_xplat_target", "rn_xplat_cxx_library", "subdir_glob", @@ -37,9 +37,6 @@ rn_xplat_cxx_library( "-std=c++14", "-Wall", ], - fbandroid_deps = [ - react_native_target("jni/react/jni:jni"), - ], fbandroid_exported_headers = subdir_glob( [ ("", "*.h"), @@ -64,7 +61,7 @@ rn_xplat_cxx_library( prefix = "react/components/modal", ), macosx_tests_override = [], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", @@ -100,7 +97,7 @@ fb_xplat_cxx_test( "-Wall", ], contacts = ["oncall+react_native@xmail.facebook.com"], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), deps = [ "fbsource//xplat/folly:molly", "fbsource//xplat/third-party/gmock:gtest", diff --git a/ReactCommon/fabric/components/root/BUCK b/ReactCommon/fabric/components/root/BUCK index 54cd52e105a233..2992818afbe5f9 100644 --- a/ReactCommon/fabric/components/root/BUCK +++ b/ReactCommon/fabric/components/root/BUCK @@ -3,6 +3,7 @@ load( "//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", + "CXX", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", @@ -36,7 +37,7 @@ rn_xplat_cxx_library( fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), macosx_tests_override = [], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", # Systraces are temporary disabled. @@ -69,7 +70,7 @@ fb_xplat_cxx_test( "-Wall", ], contacts = ["oncall+react_native@xmail.facebook.com"], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), deps = [ "fbsource//xplat/folly:molly", "fbsource//xplat/third-party/gmock:gtest", diff --git a/ReactCommon/fabric/components/scrollview/BUCK b/ReactCommon/fabric/components/scrollview/BUCK index 8337ba6299a974..6346d835303759 100644 --- a/ReactCommon/fabric/components/scrollview/BUCK +++ b/ReactCommon/fabric/components/scrollview/BUCK @@ -3,6 +3,7 @@ load( "//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", + "CXX", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", @@ -40,7 +41,7 @@ rn_xplat_cxx_library( fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), force_static = True, macosx_tests_override = [], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", @@ -72,7 +73,7 @@ fb_xplat_cxx_test( "-Wall", ], contacts = ["oncall+react_native@xmail.facebook.com"], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), deps = [ "fbsource//xplat/folly:molly", "fbsource//xplat/third-party/gmock:gtest", diff --git a/ReactCommon/fabric/components/slider/BUCK b/ReactCommon/fabric/components/slider/BUCK index 4209dd66678bf3..a22ccb5f29d121 100644 --- a/ReactCommon/fabric/components/slider/BUCK +++ b/ReactCommon/fabric/components/slider/BUCK @@ -3,6 +3,7 @@ load( "//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", + "CXX", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", @@ -37,6 +38,7 @@ rn_xplat_cxx_library( "-std=c++14", "-Wall", ], + cxx_tests = [":tests"], fbandroid_deps = [ react_native_target("jni/react/jni:jni"), ], @@ -69,13 +71,11 @@ rn_xplat_cxx_library( ios_srcs = glob( ["platform/ios/*.cpp"], ), - macosx_tests_override = [], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", ], - tests = [":tests"], visibility = ["PUBLIC"], deps = [ "fbsource//xplat/fbsystrace:fbsystrace", @@ -106,7 +106,12 @@ fb_xplat_cxx_test( "-Wall", ], contacts = ["oncall+react_native@xmail.facebook.com"], - platforms = (ANDROID, APPLE), + platforms = ( + # `Apple` and `Android` flavors are disabled because the module (built with those flavors) requires Emulator/Simulator (which is expensive and slow). At the same time, we don't really have tests here. + # ANDROID, + # APPLE, + CXX, + ), deps = [ "fbsource//xplat/folly:molly", "fbsource//xplat/third-party/gmock:gtest", diff --git a/ReactCommon/fabric/components/text/BUCK b/ReactCommon/fabric/components/text/BUCK index b47afbb67b6461..a74a1e3dda3fe7 100644 --- a/ReactCommon/fabric/components/text/BUCK +++ b/ReactCommon/fabric/components/text/BUCK @@ -3,6 +3,7 @@ load( "//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", + "CXX", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", @@ -40,16 +41,15 @@ rn_xplat_cxx_library( "-std=c++14", "-Wall", ], + cxx_tests = [":tests"], fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), force_static = True, - macosx_tests_override = [], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", ], - tests = [":tests"], visibility = ["PUBLIC"], deps = [ "fbsource//xplat/fbsystrace:fbsystrace", @@ -81,7 +81,14 @@ fb_xplat_cxx_test( "-Wall", ], contacts = ["oncall+react_native@xmail.facebook.com"], - platforms = (ANDROID, APPLE), + platforms = ( + # `Apple` and `Android` flavors are disabled because the module depends on `textlayoutmanager` which requires real an Emulator/Simulator to run. + # At the same time, the code of tests does not rely on the simulator capabilities and it would be wasteful to add `fbandroid_use_instrumentation_test = True`. + # (Beware of this option though.) + # ANDROID, + # APPLE, + CXX + ), deps = [ "fbsource//xplat/folly:molly", "fbsource//xplat/third-party/gmock:gtest", diff --git a/ReactCommon/fabric/components/view/BUCK b/ReactCommon/fabric/components/view/BUCK index f7edaa58ea33ca..998866eacc8b97 100644 --- a/ReactCommon/fabric/components/view/BUCK +++ b/ReactCommon/fabric/components/view/BUCK @@ -3,6 +3,7 @@ load( "//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", + "CXX", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", @@ -43,7 +44,7 @@ rn_xplat_cxx_library( fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), force_static = True, macosx_tests_override = [], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", # Systraces are temporary disabled. @@ -75,7 +76,7 @@ fb_xplat_cxx_test( "-Wall", ], contacts = ["oncall+react_native@xmail.facebook.com"], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), deps = [ "fbsource//xplat/folly:molly", "fbsource//xplat/third-party/gmock:gtest", diff --git a/ReactCommon/fabric/core/BUCK b/ReactCommon/fabric/core/BUCK index 27456f16061242..e10813059a83a9 100644 --- a/ReactCommon/fabric/core/BUCK +++ b/ReactCommon/fabric/core/BUCK @@ -1,5 +1,16 @@ load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_debug_preprocessor_flags") -load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", "react_native_xplat_target", "rn_xplat_cxx_library", "subdir_glob") +load( + "//tools/build_defs/oss:rn_defs.bzl", + "ANDROID", + "APPLE", + "CXX", + "fb_xplat_cxx_test", + "get_apple_compiler_flags", + "get_apple_inspector_flags", + "react_native_xplat_target", + "rn_xplat_cxx_library", + "subdir_glob", +) APPLE_COMPILER_FLAGS = get_apple_compiler_flags() @@ -36,7 +47,7 @@ rn_xplat_cxx_library( fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), force_static = True, macosx_tests_override = [], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", @@ -68,7 +79,7 @@ fb_xplat_cxx_test( "-Wall", ], contacts = ["oncall+react_native@xmail.facebook.com"], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), deps = [ "fbsource//xplat/folly:molly", "fbsource//xplat/third-party/gmock:gtest", diff --git a/ReactCommon/fabric/debug/BUCK b/ReactCommon/fabric/debug/BUCK index 3a368828e6ce0a..31330eb81db722 100644 --- a/ReactCommon/fabric/debug/BUCK +++ b/ReactCommon/fabric/debug/BUCK @@ -1,3 +1,4 @@ +load("@fbsource//tools/build_defs:default_platform_defs.bzl", "CXX") load( "@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_debug_preprocessor_flags", @@ -42,7 +43,7 @@ rn_xplat_cxx_library( fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), force_static = True, macosx_tests_override = [], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", @@ -68,7 +69,7 @@ fb_xplat_cxx_test( "-Wall", ], contacts = ["oncall+react_native@xmail.facebook.com"], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), deps = [ "fbsource//xplat/folly:molly", "fbsource//xplat/third-party/gmock:gtest", diff --git a/ReactCommon/fabric/graphics/BUCK b/ReactCommon/fabric/graphics/BUCK index 2a884519a33f80..611056a1bbdeb0 100644 --- a/ReactCommon/fabric/graphics/BUCK +++ b/ReactCommon/fabric/graphics/BUCK @@ -3,6 +3,7 @@ load( "//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", + "CXX", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", @@ -38,15 +39,26 @@ rn_xplat_cxx_library( "-std=c++14", "-Wall", ], + cxx_exported_headers = subdir_glob( + [ + ("platform/cxx", "**/*.h"), + ], + prefix = "react/graphics", + ), + cxx_srcs = glob( + [ + "platform/cxx/**/*.cpp", + ], + ), fbandroid_exported_headers = subdir_glob( [ - ("platform/android", "**/*.h"), + ("platform/cxx", "**/*.h"), ], prefix = "react/graphics", ), fbandroid_srcs = glob( [ - "platform/android/**/*.cpp", + "platform/cxx/**/*.cpp", ], ), fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, @@ -74,7 +86,7 @@ rn_xplat_cxx_library( ], ), macosx_tests_override = [], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", @@ -101,7 +113,7 @@ fb_xplat_cxx_test( "-Wall", ], contacts = ["oncall+react_native@xmail.facebook.com"], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), deps = [ "fbsource//xplat/folly:molly", "fbsource//xplat/third-party/gmock:gtest", diff --git a/ReactCommon/fabric/graphics/platform/android/Color.cpp b/ReactCommon/fabric/graphics/platform/cxx/Color.cpp similarity index 100% rename from ReactCommon/fabric/graphics/platform/android/Color.cpp rename to ReactCommon/fabric/graphics/platform/cxx/Color.cpp diff --git a/ReactCommon/fabric/graphics/platform/android/Color.h b/ReactCommon/fabric/graphics/platform/cxx/Color.h similarity index 100% rename from ReactCommon/fabric/graphics/platform/android/Color.h rename to ReactCommon/fabric/graphics/platform/cxx/Color.h diff --git a/ReactCommon/fabric/graphics/platform/android/Float.h b/ReactCommon/fabric/graphics/platform/cxx/Float.h similarity index 100% rename from ReactCommon/fabric/graphics/platform/android/Float.h rename to ReactCommon/fabric/graphics/platform/cxx/Float.h diff --git a/ReactCommon/fabric/imagemanager/BUCK b/ReactCommon/fabric/imagemanager/BUCK index d1014ecbc74f9c..c8de61999d844c 100644 --- a/ReactCommon/fabric/imagemanager/BUCK +++ b/ReactCommon/fabric/imagemanager/BUCK @@ -3,6 +3,7 @@ load( "//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", + "CXX", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", @@ -31,19 +32,20 @@ rn_xplat_cxx_library( fbandroid_exported_headers = subdir_glob( [ ("", "*.h"), + ("platform/cxx", "**/*.h"), ], prefix = "react/imagemanager", ), fbandroid_headers = subdir_glob( [ ("", "*.h"), - ("platform/android", "**/*.h"), + ("platform/cxx", "**/*.h"), ], prefix = "", ), fbandroid_srcs = glob( [ - "platform/android/**/*.cpp", + "platform/cxx/**/*.cpp", ], ), fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, @@ -82,7 +84,7 @@ rn_xplat_cxx_library( ], ), macosx_tests_override = [], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", @@ -114,7 +116,7 @@ fb_xplat_cxx_test( "-Wall", ], contacts = ["oncall+react_native@xmail.facebook.com"], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), deps = [ "fbsource//xplat/folly:molly", "fbsource//xplat/third-party/gmock:gtest", diff --git a/ReactCommon/fabric/imagemanager/platform/android/ImageManager.cpp b/ReactCommon/fabric/imagemanager/platform/cxx/ImageManager.cpp similarity index 100% rename from ReactCommon/fabric/imagemanager/platform/android/ImageManager.cpp rename to ReactCommon/fabric/imagemanager/platform/cxx/ImageManager.cpp diff --git a/ReactCommon/fabric/imagemanager/platform/android/ImageRequest.cpp b/ReactCommon/fabric/imagemanager/platform/cxx/ImageRequest.cpp similarity index 100% rename from ReactCommon/fabric/imagemanager/platform/android/ImageRequest.cpp rename to ReactCommon/fabric/imagemanager/platform/cxx/ImageRequest.cpp diff --git a/ReactCommon/fabric/mounting/BUCK b/ReactCommon/fabric/mounting/BUCK index 268c698fb424bc..c4c9ec908705af 100644 --- a/ReactCommon/fabric/mounting/BUCK +++ b/ReactCommon/fabric/mounting/BUCK @@ -3,6 +3,7 @@ load( "//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", + "CXX", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", @@ -41,7 +42,7 @@ rn_xplat_cxx_library( fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), force_static = True, macosx_tests_override = [], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", # Systraces are temporary disabled. @@ -75,7 +76,7 @@ fb_xplat_cxx_test( "-Wall", ], contacts = ["oncall+react_native@xmail.facebook.com"], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), deps = [ "fbsource//xplat/folly:molly", "fbsource//xplat/third-party/gmock:gtest", diff --git a/ReactCommon/fabric/textlayoutmanager/BUCK b/ReactCommon/fabric/textlayoutmanager/BUCK index f5dbeffe240ca9..8ecdacd51f0051 100644 --- a/ReactCommon/fabric/textlayoutmanager/BUCK +++ b/ReactCommon/fabric/textlayoutmanager/BUCK @@ -3,6 +3,7 @@ load( "//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", + "CXX", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", @@ -17,21 +18,15 @@ APPLE_COMPILER_FLAGS = get_apple_compiler_flags() rn_xplat_cxx_library( name = "textlayoutmanager", srcs = glob( - [ - "*.cpp", - ], + [], ), headers = subdir_glob( - [ - ("", "*.h"), - ], + [], prefix = "", ), header_namespace = "", exported_headers = subdir_glob( - [ - ("", "*.h"), - ], + [], prefix = "react/textlayoutmanager", ), compiler_flags = [ @@ -40,12 +35,29 @@ rn_xplat_cxx_library( "-std=c++14", "-Wall", ], + cxx_exported_headers = subdir_glob( + [ + ("platform/cxx", "*.h"), + ], + prefix = "react/textlayoutmanager", + ), + cxx_headers = subdir_glob( + [ + ("platform/cxx", "**/*.h"), + ], + prefix = "", + ), + cxx_srcs = glob( + [ + "platform/cxx/**/*.cpp", + ], + ), + cxx_tests = [":tests"], fbandroid_deps = [ react_native_target("jni/react/jni:jni"), ], fbandroid_exported_headers = subdir_glob( [ - ("", "*.h"), ("platform/android", "*.h"), ], prefix = "react/textlayoutmanager", @@ -90,12 +102,11 @@ rn_xplat_cxx_library( ], ), macosx_tests_override = [], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", ], - tests = [":tests"], visibility = ["PUBLIC"], deps = [ "fbsource//xplat/fbsystrace:fbsystrace", @@ -123,7 +134,12 @@ fb_xplat_cxx_test( "-Wall", ], contacts = ["oncall+react_native@xmail.facebook.com"], - platforms = (ANDROID, APPLE), + platforms = ( + # `Apple` and `Android` flavors are disabled because the module (built with those flavors) requires Emulator/Simulator (which is expensive and slow). At the same time, we don't really have tests here. + # ANDROID, + # APPLE, + CXX, + ), deps = [ "fbsource//xplat/folly:molly", "fbsource//xplat/third-party/gmock:gtest", diff --git a/ReactCommon/fabric/textlayoutmanager/platform/cxx/TextLayoutManager.cpp b/ReactCommon/fabric/textlayoutmanager/platform/cxx/TextLayoutManager.cpp new file mode 100644 index 00000000000000..a3e9cb1eb9666a --- /dev/null +++ b/ReactCommon/fabric/textlayoutmanager/platform/cxx/TextLayoutManager.cpp @@ -0,0 +1,27 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "TextLayoutManager.h" + +namespace facebook { +namespace react { + +TextLayoutManager::~TextLayoutManager() {} + +void *TextLayoutManager::getNativeTextLayoutManager() const { + return self_; +} + +Size TextLayoutManager::measure( + AttributedString attributedString, + ParagraphAttributes paragraphAttributes, + LayoutConstraints layoutConstraints) const { + return Size{0, 0}; +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/textlayoutmanager/platform/cxx/TextLayoutManager.h b/ReactCommon/fabric/textlayoutmanager/platform/cxx/TextLayoutManager.h new file mode 100644 index 00000000000000..6bc496ba2044c8 --- /dev/null +++ b/ReactCommon/fabric/textlayoutmanager/platform/cxx/TextLayoutManager.h @@ -0,0 +1,54 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include + +#include +#include +#include +#include + +namespace facebook { +namespace react { + +class TextLayoutManager; + +using SharedTextLayoutManager = std::shared_ptr; + +/* + * Cross platform facade for Android-specific TextLayoutManager. + */ +class TextLayoutManager { + public: + TextLayoutManager(const ContextContainer::Shared &contextContainer) + : contextContainer_(contextContainer){}; + ~TextLayoutManager(); + + /* + * Measures `attributedString` using native text rendering infrastructure. + */ + Size measure( + AttributedString attributedString, + ParagraphAttributes paragraphAttributes, + LayoutConstraints layoutConstraints) const; + + /* + * Returns an opaque pointer to platform-specific TextLayoutManager. + * Is used on a native views layer to delegate text rendering to the manager. + */ + void *getNativeTextLayoutManager() const; + + private: + void *self_; + + ContextContainer::Shared contextContainer_; +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/uimanager/BUCK b/ReactCommon/fabric/uimanager/BUCK index a04c71a6923e25..4a4cabbedc1689 100644 --- a/ReactCommon/fabric/uimanager/BUCK +++ b/ReactCommon/fabric/uimanager/BUCK @@ -3,6 +3,7 @@ load( "//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", + "CXX", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", @@ -40,7 +41,7 @@ rn_xplat_cxx_library( fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), force_static = True, macosx_tests_override = [], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", # Systraces are temporary disabled. @@ -76,7 +77,7 @@ fb_xplat_cxx_test( "-Wall", ], contacts = ["oncall+react_native@xmail.facebook.com"], - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), deps = [ "fbsource//xplat/folly:molly", "fbsource//xplat/third-party/gmock:gtest", diff --git a/ReactCommon/utils/BUCK b/ReactCommon/utils/BUCK index dd317a18e7026e..c582782dfa18a3 100644 --- a/ReactCommon/utils/BUCK +++ b/ReactCommon/utils/BUCK @@ -1,5 +1,5 @@ load("@fbsource//tools/build_defs:glob_defs.bzl", "subdir_glob") -load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", "get_apple_compiler_flags", "react_native_xplat_target", "rn_xplat_cxx_library") +load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", "CXX", "get_apple_compiler_flags", "react_native_xplat_target", "rn_xplat_cxx_library") CXX_LIBRARY_COMPILER_FLAGS = [ "-std=c++14", @@ -21,7 +21,7 @@ rn_xplat_cxx_library( ], fbobjc_compiler_flags = get_apple_compiler_flags(), force_static = True, - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), visibility = [ "PUBLIC", ], diff --git a/packages/react-native-codegen/DEFS.bzl b/packages/react-native-codegen/DEFS.bzl index 31fdfbdc091d25..308aabe71518e7 100644 --- a/packages/react-native-codegen/DEFS.bzl +++ b/packages/react-native-codegen/DEFS.bzl @@ -5,6 +5,7 @@ load( "//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", + "CXX", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", @@ -123,7 +124,7 @@ def rn_codegen( ], fbobjc_compiler_flags = get_apple_compiler_flags(), fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", @@ -159,7 +160,7 @@ def rn_codegen( ], contacts = ["oncall+react_native@xmail.facebook.com"], apple_sdks = (IOS, MACOSX), - platforms = (ANDROID, APPLE), + platforms = (ANDROID, APPLE, CXX), deps = [ "fbsource//xplat/third-party/gmock:gtest", ":generated_components-{}".format(name), From a4cc519a52882a6b08825ecdb15e1c9411c0197d Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Tue, 4 Jun 2019 15:28:24 -0700 Subject: [PATCH 0197/1084] Fabric: Synthetic benchmarks for prop parsing infra Summary: And, btw, the tests show that performance of that is not so great: ``` Running /Users/shergin/fbsource/fbobjc/buck-out/cells/fbsource/gen/xplat/js/react-native-github/ReactCommon/fabric/core/benchmarks Run on (12 X 2900 MHz CPU s) CPU Caches: L1 Data 32K (x6) L1 Instruction 32K (x6) L2 Unified 262K (x6) L3 Unified 12582K (x1) -------------------------------------------------------------------------------------------- Benchmark Time CPU Iterations -------------------------------------------------------------------------------------------- propParsingUsingComponentDescriptor 79630 ns 77991 ns 8864 propParsingUsingComponentDescriptorWithNoSourceProps 70200 ns 69099 ns 8362 ``` Which means 70ms per 1000 prop parsing processes. Reviewed By: JoshuaGross, mdvacca Differential Revision: D15608677 fbshipit-source-id: ed4feca489e1243adc73de4741c287256c3aaec3 --- ReactCommon/fabric/core/BUCK | 28 ++++++- .../tests/benchmarks/RawPropsBenchmark.cpp | 80 +++++++++++++++++++ 2 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 ReactCommon/fabric/core/tests/benchmarks/RawPropsBenchmark.cpp diff --git a/ReactCommon/fabric/core/BUCK b/ReactCommon/fabric/core/BUCK index e10813059a83a9..5d744cfc674eae 100644 --- a/ReactCommon/fabric/core/BUCK +++ b/ReactCommon/fabric/core/BUCK @@ -1,3 +1,4 @@ +load("@fbsource//tools/build_defs:fb_xplat_cxx_binary.bzl", "fb_xplat_cxx_binary") load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_debug_preprocessor_flags") load( "//tools/build_defs/oss:rn_defs.bzl", @@ -70,8 +71,8 @@ rn_xplat_cxx_library( fb_xplat_cxx_test( name = "tests", - srcs = glob(["tests/**/*.cpp"]), - headers = glob(["tests/**/*.h"]), + srcs = glob(["tests/*.cpp"]), + headers = glob(["tests/*.h"]), compiler_flags = [ "-fexceptions", "-frtti", @@ -86,3 +87,26 @@ fb_xplat_cxx_test( ":core", ], ) + +fb_xplat_cxx_binary( + name = "benchmarks", + srcs = glob(["tests/benchmarks/*.cpp"]), + compiler_flags = [ + "-fexceptions", + "-frtti", + "-std=c++14", + "-Wall", + "-Wno-unused-variable", + ], + contacts = ["oncall+react_native@xmail.facebook.com"], + fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, + fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), + platforms = (ANDROID, APPLE, CXX), + visibility = ["PUBLIC"], + deps = [ + "fbsource//xplat/third-party/benchmark:benchmark", + react_native_xplat_target("utils:utils"), + react_native_xplat_target("fabric/components/view:view"), + ":core", + ], +) diff --git a/ReactCommon/fabric/core/tests/benchmarks/RawPropsBenchmark.cpp b/ReactCommon/fabric/core/tests/benchmarks/RawPropsBenchmark.cpp new file mode 100644 index 00000000000000..5772849a6600c7 --- /dev/null +++ b/ReactCommon/fabric/core/tests/benchmarks/RawPropsBenchmark.cpp @@ -0,0 +1,80 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace facebook { +namespace react { + +auto contextContainer = std::make_shared(); +auto eventDispatcher = std::shared_ptr{nullptr}; +auto viewComponentDescriptor = + ViewComponentDescriptor(eventDispatcher, contextContainer); + +auto emptyPropsDynamic = folly::parseJson("{}"); +auto propsString = std::string{ + "{\"flex\": 1, \"padding\": 10, \"position\": \"absolute\", \"display\": \"none\", \"nativeID\": \"some-id\", \"direction\": \"rtl\"}"}; +auto propsDynamic = folly::parseJson(propsString); +auto propsStringWithSomeUnsupportedProps = std::string{ + "{\"someName1\": 1, \"someName2\": 10, \"someName3\": \"absolute\", \"someName4\": \"none\", \"someName5\": \"some-id\", \"someName6\": \"rtl\"}"}; +auto unsupportedPropsDynamic = + folly::parseJson(propsStringWithSomeUnsupportedProps); + +auto sourceProps = ViewProps{}; +auto sharedSourceProps = ViewShadowNode::defaultSharedProps(); + +static void emptyPropCreation(benchmark::State &state) { + for (auto _ : state) { + ViewProps{}; + } +} +BENCHMARK(emptyPropCreation); + +static void propParsingEmptyRawProps(benchmark::State &state) { + for (auto _ : state) { + viewComponentDescriptor.cloneProps( + sharedSourceProps, RawProps{emptyPropsDynamic}); + } +} +BENCHMARK(propParsingEmptyRawProps); + +static void propParsingRegularRawProps(benchmark::State &state) { + for (auto _ : state) { + viewComponentDescriptor.cloneProps( + sharedSourceProps, RawProps{propsDynamic}); + } +} +BENCHMARK(propParsingRegularRawProps); + +static void propParsingUnsupportedRawProps(benchmark::State &state) { + for (auto _ : state) { + viewComponentDescriptor.cloneProps( + sharedSourceProps, RawProps{unsupportedPropsDynamic}); + } +} +BENCHMARK(propParsingUnsupportedRawProps); + +static void propParsingRegularRawPropsWithNoSourceProps( + benchmark::State &state) { + for (auto _ : state) { + viewComponentDescriptor.cloneProps(nullptr, RawProps{propsDynamic}); + } +} +BENCHMARK(propParsingRegularRawPropsWithNoSourceProps); + +} // namespace react +} // namespace facebook + +BENCHMARK_MAIN(); From 920d9dea21f217ca647e69d4f941f99c60c36143 Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Tue, 4 Jun 2019 19:18:05 -0700 Subject: [PATCH 0198/1084] Fix typo in layout time Summary: Fix typo. Reviewed By: shergin Differential Revision: D15639194 fbshipit-source-id: 1e1d029aab2a7016c630c7429815531e63f71333 --- ReactCommon/fabric/mounting/MountingTelemetry.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactCommon/fabric/mounting/MountingTelemetry.cpp b/ReactCommon/fabric/mounting/MountingTelemetry.cpp index a6964bd6b7165f..5f5bdf30ab7a2d 100644 --- a/ReactCommon/fabric/mounting/MountingTelemetry.cpp +++ b/ReactCommon/fabric/mounting/MountingTelemetry.cpp @@ -35,7 +35,7 @@ void MountingTelemetry::willLayout() { void MountingTelemetry::didLayout() { assert(layoutStartTime_ != kUndefinedTime); assert(layoutEndTime_ == kUndefinedTime); - layoutEndTime_ -= getTime(); + layoutEndTime_ = getTime(); } int64_t MountingTelemetry::getCommitTime() const { From 7cf939b0ad1ffb2a2dd87a4d4f5cf3f0c0c2dacf Mon Sep 17 00:00:00 2001 From: Kody Greenbaum Date: Wed, 5 Jun 2019 01:46:44 -0700 Subject: [PATCH 0199/1084] Back out "[react-native][PR] [Blob] Release underlying resources when JS instance is GC'ed on Android" Summary: Testing if reverting this fixes the android instacrash. Original commit changeset: 2bbdc4bbcbea Reviewed By: cpojer Differential Revision: D15611385 fbshipit-source-id: 396fc0698e1056c93dbb154f95c8cc13924d5495 --- RNTester/android/app/BUCK | 1 - ReactAndroid/build.gradle | 1 - .../java/com/facebook/react/modules/blob/BUCK | 2 - .../react/modules/blob/BlobCollector.java | 25 -------- .../react/modules/blob/BlobModule.java | 39 +++++------- .../react/modules/blob/jni/Android.mk | 21 ------- .../com/facebook/react/modules/blob/jni/BUCK | 22 ------- .../react/modules/blob/jni/BlobCollector.cpp | 61 ------------------- .../react/modules/blob/jni/BlobCollector.h | 39 ------------ .../react/modules/blob/jni/OnLoad.cpp | 13 ---- .../src/main/jni/react/jni/Android.mk | 2 - 11 files changed, 15 insertions(+), 211 deletions(-) delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobCollector.java delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/Android.mk delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BUCK delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BlobCollector.cpp delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BlobCollector.h delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/OnLoad.cpp diff --git a/RNTester/android/app/BUCK b/RNTester/android/app/BUCK index 5e839d5e9153ca..ceb05c3e109291 100644 --- a/RNTester/android/app/BUCK +++ b/RNTester/android/app/BUCK @@ -25,7 +25,6 @@ rn_android_library( react_native_target("java/com/facebook/react:react"), react_native_target("java/com/facebook/react/common:build_config"), react_native_target("java/com/facebook/react/modules/core:core"), - react_native_target("java/com/facebook/react/views/text:text"), react_native_target("java/com/facebook/react/shell:shell"), react_native_target("jni/prebuilt:android-jsc"), # .so files are prebuilt by Gradle with `./gradlew :ReactAndroid:packageReactNdkLibsForBuck` diff --git a/ReactAndroid/build.gradle b/ReactAndroid/build.gradle index 343543143431bc..81e2d74ac759cd 100644 --- a/ReactAndroid/build.gradle +++ b/ReactAndroid/build.gradle @@ -225,7 +225,6 @@ def getNdkBuildFullPath() { task buildReactNdkLib(dependsOn: [prepareJSC, prepareBoost, prepareDoubleConversion, prepareFolly, prepareGlog], type: Exec) { inputs.dir("$projectDir/../ReactCommon") inputs.dir("src/main/jni") - inputs.dir("src/main/java/com/facebook/react/modules/blob") outputs.dir("$buildDir/react-ndk/all") commandLine(getNdkBuildFullPath(), "NDK_DEBUG=" + (nativeBuildType.equalsIgnoreCase("debug") ? "1" : "0"), diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK index 72c927348f08e4..ac8fbcbc9f87ec 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK @@ -16,7 +16,6 @@ rn_android_library( ], deps = [ react_native_dep("libraries/fbcore/src/main/java/com/facebook/common/logging:logging"), - react_native_dep("libraries/soloader/java/com/facebook/soloader:soloader"), react_native_dep("third-party/java/infer-annotations:infer-annotations"), react_native_dep("third-party/java/jsr-305:jsr-305"), react_native_dep("third-party/java/okhttp:okhttp3"), @@ -25,7 +24,6 @@ rn_android_library( react_native_target("java/com/facebook/react/bridge:bridge"), react_native_target("java/com/facebook/react/common:common"), react_native_target("java/com/facebook/react/module/annotations:annotations"), - react_native_target("java/com/facebook/react/modules/blob/jni:jni"), react_native_target("java/com/facebook/react/modules/network:network"), react_native_target("java/com/facebook/react/modules/websocket:websocket"), ], diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobCollector.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobCollector.java deleted file mode 100644 index 715f3dd38f6300..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobCollector.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.facebook.react.modules.blob; - -import com.facebook.react.bridge.JavaScriptContextHolder; -import com.facebook.react.bridge.ReactContext; -import com.facebook.soloader.SoLoader; - -/* package */ class BlobCollector { - static { - SoLoader.loadLibrary("reactnativeblob"); - } - - static void install(final ReactContext reactContext, final BlobModule blobModule) { - reactContext.runOnJSQueueThread(new Runnable() { - @Override - public void run() { - JavaScriptContextHolder jsContext = reactContext.getJavaScriptContextHolder(); - synchronized (jsContext) { - nativeInstall(blobModule, jsContext.get()); - } - } - }); - } - - private native static void nativeInstall(Object blobModule, long jsContext); -} diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java index 7bb5f281e49118..830180c6ffc308 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java @@ -6,10 +6,13 @@ */ package com.facebook.react.modules.blob; +import android.content.ContentResolver; +import android.content.Context; import android.content.res.Resources; import android.database.Cursor; import android.net.Uri; import android.provider.MediaStore; +import androidx.annotation.Nullable; import android.webkit.MimeTypeMap; import com.facebook.react.bridge.Arguments; @@ -37,7 +40,6 @@ import java.util.Map; import java.util.UUID; -import androidx.annotation.Nullable; import okhttp3.MediaType; import okhttp3.RequestBody; import okhttp3.ResponseBody; @@ -149,11 +151,6 @@ public BlobModule(ReactApplicationContext reactContext) { super(reactContext); } - @Override - public void initialize() { - BlobCollector.install(getReactApplicationContext(), this); - } - @Override public String getName() { return NAME; @@ -181,15 +178,11 @@ public String store(byte[] data) { } public void store(byte[] data, String blobId) { - synchronized (mBlobs) { - mBlobs.put(blobId, data); - } + mBlobs.put(blobId, data); } public void remove(String blobId) { - synchronized (mBlobs) { - mBlobs.remove(blobId); - } + mBlobs.remove(blobId); } public @Nullable byte[] resolve(Uri uri) { @@ -208,19 +201,17 @@ public void remove(String blobId) { } public @Nullable byte[] resolve(String blobId, int offset, int size) { - synchronized (mBlobs) { - byte[] data = mBlobs.get(blobId); - if (data == null) { - return null; - } - if (size == -1) { - size = data.length - offset; - } - if (offset > 0 || size != data.length) { - data = Arrays.copyOfRange(data, offset, offset + size); - } - return data; + byte[] data = mBlobs.get(blobId); + if (data == null) { + return null; + } + if (size == -1) { + size = data.length - offset; + } + if (offset > 0 || size != data.length) { + data = Arrays.copyOfRange(data, offset, offset + size); } + return data; } public @Nullable byte[] resolve(ReadableMap blob) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/Android.mk b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/Android.mk deleted file mode 100644 index b0ef370c574413..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/Android.mk +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_MODULE := reactnativeblob - -LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp) - -LOCAL_C_INCLUDES := $(LOCAL_PATH) - -LOCAL_CFLAGS += -fvisibility=hidden -fexceptions -frtti - -LOCAL_STATIC_LIBRARIES := libjsi libjsireact jscruntime -LOCAL_SHARED_LIBRARIES := libfolly_json libfb libreactnativejni - -include $(BUILD_SHARED_LIBRARY) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BUCK deleted file mode 100644 index c02646779b63f8..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BUCK +++ /dev/null @@ -1,22 +0,0 @@ -load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "FBJNI_TARGET", "react_native_target", "react_native_xplat_target", "rn_xplat_cxx_library") - -rn_xplat_cxx_library( - name = "jni", - srcs = glob(["*.cpp"]), - headers = glob(["*.h"]), - header_namespace = "", - compiler_flags = ["-fexceptions"], - fbandroid_allow_jni_merging = True, - platforms = ANDROID, - soname = "libreactnativeblob.$(ext)", - visibility = [ - "PUBLIC", - ], - deps = [ - "fbsource//xplat/folly:molly", - FBJNI_TARGET, - react_native_target("jni/react/jni:jni"), - react_native_xplat_target("jsi:JSCRuntime"), - react_native_xplat_target("jsiexecutor:jsiexecutor"), - ], -) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BlobCollector.cpp b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BlobCollector.cpp deleted file mode 100644 index d14d3885253b9d..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BlobCollector.cpp +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -#include "BlobCollector.h" - -#include -#include -#include - -using namespace facebook; - -namespace facebook { -namespace react { - -static constexpr auto kBlobModuleJavaDescriptor = - "com/facebook/react/modules/blob/BlobModule"; - -BlobCollector::BlobCollector( - jni::global_ref blobModule, - const std::string &blobId) - : blobModule_(blobModule), blobId_(blobId) {} - -BlobCollector::~BlobCollector() { - auto removeMethod = jni::findClassStatic(kBlobModuleJavaDescriptor) - ->getMethod("remove"); - removeMethod(blobModule_, jni::make_jstring(blobId_).get()); -} - -void BlobCollector::nativeInstall( - jni::alias_ref jThis, - jni::alias_ref blobModule, - jlong jsContextNativePointer) { - auto &runtime = *((jsi::Runtime *)jsContextNativePointer); - auto blobModuleRef = jni::make_global(blobModule); - runtime.global().setProperty( - runtime, - "__blobCollectorProvider", - jsi::Function::createFromHostFunction( - runtime, - jsi::PropNameID::forAscii(runtime, "__blobCollectorProvider"), - 1, - [blobModuleRef]( - jsi::Runtime &rt, - const jsi::Value &thisVal, - const jsi::Value *args, - size_t count) { - auto blobId = args[0].asString(rt).utf8(rt); - auto blobCollector = - std::make_shared(blobModuleRef, blobId); - return jsi::Object::createFromHostObject(rt, blobCollector); - })); -} - -void BlobCollector::registerNatives() { - registerHybrid( - {makeNativeMethod("nativeInstall", BlobCollector::nativeInstall)}); -} - -} // namespace react -} // namespace facebook diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BlobCollector.h b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BlobCollector.h deleted file mode 100644 index b013cf8bf665c7..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/BlobCollector.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -#pragma once - -#include -#include - -namespace facebook { -namespace react { - -class BlobCollector : public jni::HybridClass, - public jsi::HostObject { - public: - BlobCollector( - jni::global_ref blobManager, - const std::string &blobId); - ~BlobCollector(); - - static constexpr auto kJavaDescriptor = - "Lcom/facebook/react/modules/blob/BlobCollector;"; - - static void nativeInstall( - jni::alias_ref jThis, - jni::alias_ref blobModule, - jlong jsContextNativePointer); - - static void registerNatives(); - - private: - friend HybridBase; - - jni::global_ref blobModule_; - const std::string blobId_; -}; - -} // namespace react -} // namespace facebook diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/OnLoad.cpp b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/OnLoad.cpp deleted file mode 100644 index 3707d02665e44a..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/jni/OnLoad.cpp +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -#include - -#include "BlobCollector.h" - -JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { - return facebook::jni::initialize( - vm, [] { facebook::react::BlobCollector::registerNatives(); }); -} diff --git a/ReactAndroid/src/main/jni/react/jni/Android.mk b/ReactAndroid/src/main/jni/react/jni/Android.mk index 28c1fae096e7bf..b2422db96598f0 100644 --- a/ReactAndroid/src/main/jni/react/jni/Android.mk +++ b/ReactAndroid/src/main/jni/react/jni/Android.mk @@ -76,5 +76,3 @@ include $(REACT_SRC_DIR)/turbomodule/core/jni/Android.mk # $(call import-module,jscexecutor) include $(REACT_SRC_DIR)/jscexecutor/Android.mk - -include $(REACT_SRC_DIR)/modules/blob/jni/Android.mk From 69d1ed731bf52c8b99f8b6319398b3920dcec109 Mon Sep 17 00:00:00 2001 From: James Ide Date: Wed, 5 Jun 2019 04:14:52 -0700 Subject: [PATCH 0200/1084] Sync React with Haste-style imports rewritten to use path-based imports instead (#25100) Summary: **This is a manual React sync to replace Haste names with paths so that the removal of Haste is not blocked on a normal React sync. This is a one-time special case; in the future, React will generate renderers that use paths instead of Haste.** This commit uses the same base commit of React that's currently in RN (React ec6691a68716bc59291746fc62f374a56fb435c9) plus a commit in the React repo that removes Haste-style imports from the renderer (61f62246c8cfb76a4a19d1661eeaa5822ec37b36) and a commit to make the shims import from `implementations` (https://github.com/facebook/react/pull/15786). I built React in the React repo with `yarn build` and copied over the `oss` directory into one called `implementations` and removed the `*.fb.js` files. ## Changelog [General] [Changed] - Sync React with Haste-style imports rewritten to use path-based imports instead Pull Request resolved: https://github.com/facebook/react-native/pull/25100 Reviewed By: yungsters Differential Revision: D15575646 Pulled By: cpojer fbshipit-source-id: adf25f9826b71729043b65ba1afd20d14d8c19c4 --- Libraries/Renderer/REVISION | 2 +- .../implementations/ReactFabric-dev.fb.js | 19816 +++++++++++++++ .../ReactFabric-dev.js | 211 +- .../implementations/ReactFabric-prod.fb.js | 6974 ++++++ .../ReactFabric-prod.js | 171 +- .../ReactFabric-profiling.fb.js | 7211 ++++++ .../ReactFabric-profiling.js | 173 +- .../ReactNativeRenderer-dev.fb.js | 20167 ++++++++++++++++ .../ReactNativeRenderer-dev.js | 185 +- .../ReactNativeRenderer-prod.fb.js | 7205 ++++++ .../ReactNativeRenderer-prod.js | 186 +- .../ReactNativeRenderer-profiling.fb.js | 7445 ++++++ .../ReactNativeRenderer-profiling.js | 188 +- Libraries/Renderer/shims/ReactFabric.js | 6 +- Libraries/Renderer/shims/ReactFeatureFlags.js | 17 + Libraries/Renderer/shims/ReactNative.js | 4 +- .../shims/createReactNativeComponentClass.js | 4 +- 17 files changed, 69476 insertions(+), 489 deletions(-) create mode 100644 Libraries/Renderer/implementations/ReactFabric-dev.fb.js rename Libraries/Renderer/{oss => implementations}/ReactFabric-dev.js (99%) create mode 100644 Libraries/Renderer/implementations/ReactFabric-prod.fb.js rename Libraries/Renderer/{oss => implementations}/ReactFabric-prod.js (97%) create mode 100644 Libraries/Renderer/implementations/ReactFabric-profiling.fb.js rename Libraries/Renderer/{oss => implementations}/ReactFabric-profiling.js (98%) create mode 100644 Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js rename Libraries/Renderer/{oss => implementations}/ReactNativeRenderer-dev.js (99%) create mode 100644 Libraries/Renderer/implementations/ReactNativeRenderer-prod.fb.js rename Libraries/Renderer/{oss => implementations}/ReactNativeRenderer-prod.js (97%) create mode 100644 Libraries/Renderer/implementations/ReactNativeRenderer-profiling.fb.js rename Libraries/Renderer/{oss => implementations}/ReactNativeRenderer-profiling.js (98%) create mode 100644 Libraries/Renderer/shims/ReactFeatureFlags.js diff --git a/Libraries/Renderer/REVISION b/Libraries/Renderer/REVISION index 7a8c0a1ac2f570..ca2ac7272eb294 100644 --- a/Libraries/Renderer/REVISION +++ b/Libraries/Renderer/REVISION @@ -1 +1 @@ -ec6691a68716bc59291746fc62f374a56fb435c9 \ No newline at end of file +87d375afd0d9394646a4bcddcebb7b15ffaa7e9e \ No newline at end of file diff --git a/Libraries/Renderer/implementations/ReactFabric-dev.fb.js b/Libraries/Renderer/implementations/ReactFabric-dev.fb.js new file mode 100644 index 00000000000000..01a54327173ccf --- /dev/null +++ b/Libraries/Renderer/implementations/ReactFabric-dev.fb.js @@ -0,0 +1,19816 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @noflow + * @preventMunge + * @generated + */ + +'use strict'; + +if (__DEV__) { + (function() { +"use strict"; + +require("react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore"); +var ReactNativePrivateInterface = require("react-native/Libraries/ReactPrivate/ReactNativePrivateInterface"); +var React = require("react"); +var checkPropTypes = require("prop-types/checkPropTypes"); +var Scheduler = require("scheduler"); +var tracing = require("scheduler/tracing"); + +// Do not require this module directly! Use a normal error constructor with +// template literal strings. The messages will be converted to ReactError during +// build, and in production they will be minified. + +function ReactError(message) { + var error = new Error(message); + error.name = "Invariant Violation"; + return error; +} + +/** + * Use invariant() to assert state which your program assumes to be true. + * + * Provide sprintf-style format (only %s is supported) and arguments + * to provide information about what broke and what you were + * expecting. + * + * The invariant message will be stripped in production, but the invariant + * will remain to ensure logic does not differ in production. + */ + +/** + * Injectable ordering of event plugins. + */ +var eventPluginOrder = null; + +/** + * Injectable mapping from names to event plugin modules. + */ +var namesToPlugins = {}; + +/** + * Recomputes the plugin list using the injected plugins and plugin ordering. + * + * @private + */ +function recomputePluginOrdering() { + if (!eventPluginOrder) { + // Wait until an `eventPluginOrder` is injected. + return; + } + for (var pluginName in namesToPlugins) { + var pluginModule = namesToPlugins[pluginName]; + var pluginIndex = eventPluginOrder.indexOf(pluginName); + (function() { + if (!(pluginIndex > -1)) { + throw ReactError( + "EventPluginRegistry: Cannot inject event plugins that do not exist in the plugin ordering, `" + + pluginName + + "`." + ); + } + })(); + if (plugins[pluginIndex]) { + continue; + } + (function() { + if (!pluginModule.extractEvents) { + throw ReactError( + "EventPluginRegistry: Event plugins must implement an `extractEvents` method, but `" + + pluginName + + "` does not." + ); + } + })(); + plugins[pluginIndex] = pluginModule; + var publishedEvents = pluginModule.eventTypes; + for (var eventName in publishedEvents) { + (function() { + if ( + !publishEventForPlugin( + publishedEvents[eventName], + pluginModule, + eventName + ) + ) { + throw ReactError( + "EventPluginRegistry: Failed to publish event `" + + eventName + + "` for plugin `" + + pluginName + + "`." + ); + } + })(); + } + } +} + +/** + * Publishes an event so that it can be dispatched by the supplied plugin. + * + * @param {object} dispatchConfig Dispatch configuration for the event. + * @param {object} PluginModule Plugin publishing the event. + * @return {boolean} True if the event was successfully published. + * @private + */ +function publishEventForPlugin(dispatchConfig, pluginModule, eventName) { + (function() { + if (!!eventNameDispatchConfigs.hasOwnProperty(eventName)) { + throw ReactError( + "EventPluginHub: More than one plugin attempted to publish the same event name, `" + + eventName + + "`." + ); + } + })(); + eventNameDispatchConfigs[eventName] = dispatchConfig; + + var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames; + if (phasedRegistrationNames) { + for (var phaseName in phasedRegistrationNames) { + if (phasedRegistrationNames.hasOwnProperty(phaseName)) { + var phasedRegistrationName = phasedRegistrationNames[phaseName]; + publishRegistrationName( + phasedRegistrationName, + pluginModule, + eventName + ); + } + } + return true; + } else if (dispatchConfig.registrationName) { + publishRegistrationName( + dispatchConfig.registrationName, + pluginModule, + eventName + ); + return true; + } + return false; +} + +/** + * Publishes a registration name that is used to identify dispatched events. + * + * @param {string} registrationName Registration name to add. + * @param {object} PluginModule Plugin publishing the event. + * @private + */ +function publishRegistrationName(registrationName, pluginModule, eventName) { + (function() { + if (!!registrationNameModules[registrationName]) { + throw ReactError( + "EventPluginHub: More than one plugin attempted to publish the same registration name, `" + + registrationName + + "`." + ); + } + })(); + registrationNameModules[registrationName] = pluginModule; + registrationNameDependencies[registrationName] = + pluginModule.eventTypes[eventName].dependencies; + + { + var lowerCasedName = registrationName.toLowerCase(); + } +} + +/** + * Registers plugins so that they can extract and dispatch events. + * + * @see {EventPluginHub} + */ + +/** + * Ordered list of injected plugins. + */ +var plugins = []; + +/** + * Mapping from event name to dispatch config + */ +var eventNameDispatchConfigs = {}; + +/** + * Mapping from registration name to plugin module + */ +var registrationNameModules = {}; + +/** + * Mapping from registration name to event name + */ +var registrationNameDependencies = {}; + +/** + * Mapping from lowercase registration names to the properly cased version, + * used to warn in the case of missing event handlers. Available + * only in true. + * @type {Object} + */ + +// Trust the developer to only use possibleRegistrationNames in true + +/** + * Injects an ordering of plugins (by plugin name). This allows the ordering + * to be decoupled from injection of the actual plugins so that ordering is + * always deterministic regardless of packaging, on-the-fly injection, etc. + * + * @param {array} InjectedEventPluginOrder + * @internal + * @see {EventPluginHub.injection.injectEventPluginOrder} + */ +function injectEventPluginOrder(injectedEventPluginOrder) { + (function() { + if (!!eventPluginOrder) { + throw ReactError( + "EventPluginRegistry: Cannot inject event plugin ordering more than once. You are likely trying to load more than one copy of React." + ); + } + })(); + // Clone the ordering so it cannot be dynamically mutated. + eventPluginOrder = Array.prototype.slice.call(injectedEventPluginOrder); + recomputePluginOrdering(); +} + +/** + * Injects plugins to be used by `EventPluginHub`. The plugin names must be + * in the ordering injected by `injectEventPluginOrder`. + * + * Plugins can be injected as part of page initialization or on-the-fly. + * + * @param {object} injectedNamesToPlugins Map from names to plugin modules. + * @internal + * @see {EventPluginHub.injection.injectEventPluginsByName} + */ +function injectEventPluginsByName(injectedNamesToPlugins) { + var isOrderingDirty = false; + for (var pluginName in injectedNamesToPlugins) { + if (!injectedNamesToPlugins.hasOwnProperty(pluginName)) { + continue; + } + var pluginModule = injectedNamesToPlugins[pluginName]; + if ( + !namesToPlugins.hasOwnProperty(pluginName) || + namesToPlugins[pluginName] !== pluginModule + ) { + (function() { + if (!!namesToPlugins[pluginName]) { + throw ReactError( + "EventPluginRegistry: Cannot inject two different event plugins using the same name, `" + + pluginName + + "`." + ); + } + })(); + namesToPlugins[pluginName] = pluginModule; + isOrderingDirty = true; + } + } + if (isOrderingDirty) { + recomputePluginOrdering(); + } +} + +var invokeGuardedCallbackImpl = function( + name, + func, + context, + a, + b, + c, + d, + e, + f +) { + var funcArgs = Array.prototype.slice.call(arguments, 3); + try { + func.apply(context, funcArgs); + } catch (error) { + this.onError(error); + } +}; + +{ + // In DEV mode, we swap out invokeGuardedCallback for a special version + // that plays more nicely with the browser's DevTools. The idea is to preserve + // "Pause on exceptions" behavior. Because React wraps all user-provided + // functions in invokeGuardedCallback, and the production version of + // invokeGuardedCallback uses a try-catch, all user exceptions are treated + // like caught exceptions, and the DevTools won't pause unless the developer + // takes the extra step of enabling pause on caught exceptions. This is + // unintuitive, though, because even though React has caught the error, from + // the developer's perspective, the error is uncaught. + // + // To preserve the expected "Pause on exceptions" behavior, we don't use a + // try-catch in DEV. Instead, we synchronously dispatch a fake event to a fake + // DOM node, and call the user-provided callback from inside an event handler + // for that fake event. If the callback throws, the error is "captured" using + // a global event handler. But because the error happens in a different + // event loop context, it does not interrupt the normal program flow. + // Effectively, this gives us try-catch behavior without actually using + // try-catch. Neat! + + // Check that the browser supports the APIs we need to implement our special + // DEV version of invokeGuardedCallback + if ( + typeof window !== "undefined" && + typeof window.dispatchEvent === "function" && + typeof document !== "undefined" && + typeof document.createEvent === "function" + ) { + var fakeNode = document.createElement("react"); + + var invokeGuardedCallbackDev = function( + name, + func, + context, + a, + b, + c, + d, + e, + f + ) { + // If document doesn't exist we know for sure we will crash in this method + // when we call document.createEvent(). However this can cause confusing + // errors: https://github.com/facebookincubator/create-react-app/issues/3482 + // So we preemptively throw with a better message instead. + (function() { + if (!(typeof document !== "undefined")) { + throw ReactError( + "The `document` global was defined when React was initialized, but is not defined anymore. This can happen in a test environment if a component schedules an update from an asynchronous callback, but the test has already finished running. To solve this, you can either unmount the component at the end of your test (and ensure that any asynchronous operations get canceled in `componentWillUnmount`), or you can change the test itself to be asynchronous." + ); + } + })(); + var evt = document.createEvent("Event"); + + // Keeps track of whether the user-provided callback threw an error. We + // set this to true at the beginning, then set it to false right after + // calling the function. If the function errors, `didError` will never be + // set to false. This strategy works even if the browser is flaky and + // fails to call our global error handler, because it doesn't rely on + // the error event at all. + var didError = true; + + // Keeps track of the value of window.event so that we can reset it + // during the callback to let user code access window.event in the + // browsers that support it. + var windowEvent = window.event; + + // Keeps track of the descriptor of window.event to restore it after event + // dispatching: https://github.com/facebook/react/issues/13688 + var windowEventDescriptor = Object.getOwnPropertyDescriptor( + window, + "event" + ); + + // Create an event handler for our fake event. We will synchronously + // dispatch our fake event using `dispatchEvent`. Inside the handler, we + // call the user-provided callback. + var funcArgs = Array.prototype.slice.call(arguments, 3); + function callCallback() { + // We immediately remove the callback from event listeners so that + // nested `invokeGuardedCallback` calls do not clash. Otherwise, a + // nested call would trigger the fake event handlers of any call higher + // in the stack. + fakeNode.removeEventListener(evtType, callCallback, false); + + // We check for window.hasOwnProperty('event') to prevent the + // window.event assignment in both IE <= 10 as they throw an error + // "Member not found" in strict mode, and in Firefox which does not + // support window.event. + if ( + typeof window.event !== "undefined" && + window.hasOwnProperty("event") + ) { + window.event = windowEvent; + } + + func.apply(context, funcArgs); + didError = false; + } + + // Create a global error event handler. We use this to capture the value + // that was thrown. It's possible that this error handler will fire more + // than once; for example, if non-React code also calls `dispatchEvent` + // and a handler for that event throws. We should be resilient to most of + // those cases. Even if our error event handler fires more than once, the + // last error event is always used. If the callback actually does error, + // we know that the last error event is the correct one, because it's not + // possible for anything else to have happened in between our callback + // erroring and the code that follows the `dispatchEvent` call below. If + // the callback doesn't error, but the error event was fired, we know to + // ignore it because `didError` will be false, as described above. + var error = void 0; + // Use this to track whether the error event is ever called. + var didSetError = false; + var isCrossOriginError = false; + + function handleWindowError(event) { + error = event.error; + didSetError = true; + if (error === null && event.colno === 0 && event.lineno === 0) { + isCrossOriginError = true; + } + if (event.defaultPrevented) { + // Some other error handler has prevented default. + // Browsers silence the error report if this happens. + // We'll remember this to later decide whether to log it or not. + if (error != null && typeof error === "object") { + try { + error._suppressLogging = true; + } catch (inner) { + // Ignore. + } + } + } + } + + // Create a fake event type. + var evtType = "react-" + (name ? name : "invokeguardedcallback"); + + // Attach our event handlers + window.addEventListener("error", handleWindowError); + fakeNode.addEventListener(evtType, callCallback, false); + + // Synchronously dispatch our fake event. If the user-provided function + // errors, it will trigger our global error handler. + evt.initEvent(evtType, false, false); + fakeNode.dispatchEvent(evt); + + if (windowEventDescriptor) { + Object.defineProperty(window, "event", windowEventDescriptor); + } + + if (didError) { + if (!didSetError) { + // The callback errored, but the error event never fired. + error = new Error( + "An error was thrown inside one of your components, but React " + + "doesn't know what it was. This is likely due to browser " + + 'flakiness. React does its best to preserve the "Pause on ' + + 'exceptions" behavior of the DevTools, which requires some ' + + "DEV-mode only tricks. It's possible that these don't work in " + + "your browser. Try triggering the error in production mode, " + + "or switching to a modern browser. If you suspect that this is " + + "actually an issue with React, please file an issue." + ); + } else if (isCrossOriginError) { + error = new Error( + "A cross-origin error was thrown. React doesn't have access to " + + "the actual error object in development. " + + "See https://fb.me/react-crossorigin-error for more information." + ); + } + this.onError(error); + } + + // Remove our event listeners + window.removeEventListener("error", handleWindowError); + }; + + invokeGuardedCallbackImpl = invokeGuardedCallbackDev; + } +} + +var invokeGuardedCallbackImpl$1 = invokeGuardedCallbackImpl; + +// Used by Fiber to simulate a try-catch. +var hasError = false; +var caughtError = null; + +// Used by event system to capture/rethrow the first error. +var hasRethrowError = false; +var rethrowError = null; + +var reporter = { + onError: function(error) { + hasError = true; + caughtError = error; + } +}; + +/** + * Call a function while guarding against errors that happens within it. + * Returns an error if it throws, otherwise null. + * + * In production, this is implemented using a try-catch. The reason we don't + * use a try-catch directly is so that we can swap out a different + * implementation in DEV mode. + * + * @param {String} name of the guard to use for logging or debugging + * @param {Function} func The function to invoke + * @param {*} context The context to use when calling the function + * @param {...*} args Arguments for function + */ +function invokeGuardedCallback(name, func, context, a, b, c, d, e, f) { + hasError = false; + caughtError = null; + invokeGuardedCallbackImpl$1.apply(reporter, arguments); +} + +/** + * Same as invokeGuardedCallback, but instead of returning an error, it stores + * it in a global so it can be rethrown by `rethrowCaughtError` later. + * TODO: See if caughtError and rethrowError can be unified. + * + * @param {String} name of the guard to use for logging or debugging + * @param {Function} func The function to invoke + * @param {*} context The context to use when calling the function + * @param {...*} args Arguments for function + */ +function invokeGuardedCallbackAndCatchFirstError( + name, + func, + context, + a, + b, + c, + d, + e, + f +) { + invokeGuardedCallback.apply(this, arguments); + if (hasError) { + var error = clearCaughtError(); + if (!hasRethrowError) { + hasRethrowError = true; + rethrowError = error; + } + } +} + +/** + * During execution of guarded functions we will capture the first error which + * we will rethrow to be handled by the top level error handler. + */ +function rethrowCaughtError() { + if (hasRethrowError) { + var error = rethrowError; + hasRethrowError = false; + rethrowError = null; + throw error; + } +} + +function hasCaughtError() { + return hasError; +} + +function clearCaughtError() { + if (hasError) { + var error = caughtError; + hasError = false; + caughtError = null; + return error; + } else { + (function() { + { + throw ReactError( + "clearCaughtError was called but no error was captured. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } +} + +/** + * Similar to invariant but only logs a warning if the condition is not met. + * This can be used to log issues in development environments in critical + * paths. Removing the logging code for production environments will keep the + * same logic and follow the same code paths. + */ + +var warningWithoutStack = function() {}; + +{ + warningWithoutStack = function(condition, format) { + for ( + var _len = arguments.length, + args = Array(_len > 2 ? _len - 2 : 0), + _key = 2; + _key < _len; + _key++ + ) { + args[_key - 2] = arguments[_key]; + } + + if (format === undefined) { + throw new Error( + "`warningWithoutStack(condition, format, ...args)` requires a warning " + + "message argument" + ); + } + if (args.length > 8) { + // Check before the condition to catch violations early. + throw new Error( + "warningWithoutStack() currently supports at most 8 arguments." + ); + } + if (condition) { + return; + } + if (typeof console !== "undefined") { + var argsWithFormat = args.map(function(item) { + return "" + item; + }); + argsWithFormat.unshift("Warning: " + format); + + // We intentionally don't use spread (or .apply) directly because it + // breaks IE9: https://github.com/facebook/react/issues/13610 + Function.prototype.apply.call(console.error, console, argsWithFormat); + } + try { + // --- Welcome to debugging React --- + // This error was thrown as a convenience so that you can use this stack + // to find the callsite that caused this warning to fire. + var argIndex = 0; + var message = + "Warning: " + + format.replace(/%s/g, function() { + return args[argIndex++]; + }); + throw new Error(message); + } catch (x) {} + }; +} + +var warningWithoutStack$1 = warningWithoutStack; + +var getFiberCurrentPropsFromNode = null; +var getInstanceFromNode = null; +var getNodeFromInstance = null; + +function setComponentTree( + getFiberCurrentPropsFromNodeImpl, + getInstanceFromNodeImpl, + getNodeFromInstanceImpl +) { + getFiberCurrentPropsFromNode = getFiberCurrentPropsFromNodeImpl; + getInstanceFromNode = getInstanceFromNodeImpl; + getNodeFromInstance = getNodeFromInstanceImpl; + { + !(getNodeFromInstance && getInstanceFromNode) + ? warningWithoutStack$1( + false, + "EventPluginUtils.setComponentTree(...): Injected " + + "module is missing getNodeFromInstance or getInstanceFromNode." + ) + : void 0; + } +} + +var validateEventDispatches = void 0; +{ + validateEventDispatches = function(event) { + var dispatchListeners = event._dispatchListeners; + var dispatchInstances = event._dispatchInstances; + + var listenersIsArr = Array.isArray(dispatchListeners); + var listenersLen = listenersIsArr + ? dispatchListeners.length + : dispatchListeners + ? 1 + : 0; + + var instancesIsArr = Array.isArray(dispatchInstances); + var instancesLen = instancesIsArr + ? dispatchInstances.length + : dispatchInstances + ? 1 + : 0; + + !(instancesIsArr === listenersIsArr && instancesLen === listenersLen) + ? warningWithoutStack$1(false, "EventPluginUtils: Invalid `event`.") + : void 0; + }; +} + +/** + * Dispatch the event to the listener. + * @param {SyntheticEvent} event SyntheticEvent to handle + * @param {function} listener Application-level callback + * @param {*} inst Internal component instance + */ +function executeDispatch(event, listener, inst) { + var type = event.type || "unknown-event"; + event.currentTarget = getNodeFromInstance(inst); + invokeGuardedCallbackAndCatchFirstError(type, listener, undefined, event); + event.currentTarget = null; +} + +/** + * Standard/simple iteration through an event's collected dispatches. + */ +function executeDispatchesInOrder(event) { + var dispatchListeners = event._dispatchListeners; + var dispatchInstances = event._dispatchInstances; + { + validateEventDispatches(event); + } + if (Array.isArray(dispatchListeners)) { + for (var i = 0; i < dispatchListeners.length; i++) { + if (event.isPropagationStopped()) { + break; + } + // Listeners and Instances are two parallel arrays that are always in sync. + executeDispatch(event, dispatchListeners[i], dispatchInstances[i]); + } + } else if (dispatchListeners) { + executeDispatch(event, dispatchListeners, dispatchInstances); + } + event._dispatchListeners = null; + event._dispatchInstances = null; +} + +/** + * Standard/simple iteration through an event's collected dispatches, but stops + * at the first dispatch execution returning true, and returns that id. + * + * @return {?string} id of the first dispatch execution who's listener returns + * true, or null if no listener returned true. + */ +function executeDispatchesInOrderStopAtTrueImpl(event) { + var dispatchListeners = event._dispatchListeners; + var dispatchInstances = event._dispatchInstances; + { + validateEventDispatches(event); + } + if (Array.isArray(dispatchListeners)) { + for (var i = 0; i < dispatchListeners.length; i++) { + if (event.isPropagationStopped()) { + break; + } + // Listeners and Instances are two parallel arrays that are always in sync. + if (dispatchListeners[i](event, dispatchInstances[i])) { + return dispatchInstances[i]; + } + } + } else if (dispatchListeners) { + if (dispatchListeners(event, dispatchInstances)) { + return dispatchInstances; + } + } + return null; +} + +/** + * @see executeDispatchesInOrderStopAtTrueImpl + */ +function executeDispatchesInOrderStopAtTrue(event) { + var ret = executeDispatchesInOrderStopAtTrueImpl(event); + event._dispatchInstances = null; + event._dispatchListeners = null; + return ret; +} + +/** + * Execution of a "direct" dispatch - there must be at most one dispatch + * accumulated on the event or it is considered an error. It doesn't really make + * sense for an event with multiple dispatches (bubbled) to keep track of the + * return values at each dispatch execution, but it does tend to make sense when + * dealing with "direct" dispatches. + * + * @return {*} The return value of executing the single dispatch. + */ +function executeDirectDispatch(event) { + { + validateEventDispatches(event); + } + var dispatchListener = event._dispatchListeners; + var dispatchInstance = event._dispatchInstances; + (function() { + if (!!Array.isArray(dispatchListener)) { + throw ReactError("executeDirectDispatch(...): Invalid `event`."); + } + })(); + event.currentTarget = dispatchListener + ? getNodeFromInstance(dispatchInstance) + : null; + var res = dispatchListener ? dispatchListener(event) : null; + event.currentTarget = null; + event._dispatchListeners = null; + event._dispatchInstances = null; + return res; +} + +/** + * @param {SyntheticEvent} event + * @return {boolean} True iff number of dispatches accumulated is greater than 0. + */ +function hasDispatches(event) { + return !!event._dispatchListeners; +} + +/** + * Accumulates items that must not be null or undefined into the first one. This + * is used to conserve memory by avoiding array allocations, and thus sacrifices + * API cleanness. Since `current` can be null before being passed in and not + * null after this function, make sure to assign it back to `current`: + * + * `a = accumulateInto(a, b);` + * + * This API should be sparingly used. Try `accumulate` for something cleaner. + * + * @return {*|array<*>} An accumulation of items. + */ + +function accumulateInto(current, next) { + (function() { + if (!(next != null)) { + throw ReactError( + "accumulateInto(...): Accumulated items must not be null or undefined." + ); + } + })(); + + if (current == null) { + return next; + } + + // Both are not empty. Warning: Never call x.concat(y) when you are not + // certain that x is an Array (x could be a string with concat method). + if (Array.isArray(current)) { + if (Array.isArray(next)) { + current.push.apply(current, next); + return current; + } + current.push(next); + return current; + } + + if (Array.isArray(next)) { + // A bit too dangerous to mutate `next`. + return [current].concat(next); + } + + return [current, next]; +} + +/** + * @param {array} arr an "accumulation" of items which is either an Array or + * a single item. Useful when paired with the `accumulate` module. This is a + * simple utility that allows us to reason about a collection of items, but + * handling the case when there is exactly one item (and we do not need to + * allocate an array). + * @param {function} cb Callback invoked with each element or a collection. + * @param {?} [scope] Scope used as `this` in a callback. + */ +function forEachAccumulated(arr, cb, scope) { + if (Array.isArray(arr)) { + arr.forEach(cb, scope); + } else if (arr) { + cb.call(scope, arr); + } +} + +/** + * Internal queue of events that have accumulated their dispatches and are + * waiting to have their dispatches executed. + */ +var eventQueue = null; + +/** + * Dispatches an event and releases it back into the pool, unless persistent. + * + * @param {?object} event Synthetic event to be dispatched. + * @private + */ +var executeDispatchesAndRelease = function(event) { + if (event) { + executeDispatchesInOrder(event); + + if (!event.isPersistent()) { + event.constructor.release(event); + } + } +}; +var executeDispatchesAndReleaseTopLevel = function(e) { + return executeDispatchesAndRelease(e); +}; + +function runEventsInBatch(events) { + if (events !== null) { + eventQueue = accumulateInto(eventQueue, events); + } + + // Set `eventQueue` to null before processing it so that we can tell if more + // events get enqueued while processing. + var processingEventQueue = eventQueue; + eventQueue = null; + + if (!processingEventQueue) { + return; + } + + forEachAccumulated(processingEventQueue, executeDispatchesAndReleaseTopLevel); + (function() { + if (!!eventQueue) { + throw ReactError( + "processEventQueue(): Additional events were enqueued while processing an event queue. Support for this has not yet been implemented." + ); + } + })(); + // This would be a good time to rethrow if any of the event handlers threw. + rethrowCaughtError(); +} + +function isInteractive(tag) { + return ( + tag === "button" || + tag === "input" || + tag === "select" || + tag === "textarea" + ); +} + +function shouldPreventMouseEvent(name, type, props) { + switch (name) { + case "onClick": + case "onClickCapture": + case "onDoubleClick": + case "onDoubleClickCapture": + case "onMouseDown": + case "onMouseDownCapture": + case "onMouseMove": + case "onMouseMoveCapture": + case "onMouseUp": + case "onMouseUpCapture": + return !!(props.disabled && isInteractive(type)); + default: + return false; + } +} + +/** + * This is a unified interface for event plugins to be installed and configured. + * + * Event plugins can implement the following properties: + * + * `extractEvents` {function(string, DOMEventTarget, string, object): *} + * Required. When a top-level event is fired, this method is expected to + * extract synthetic events that will in turn be queued and dispatched. + * + * `eventTypes` {object} + * Optional, plugins that fire events must publish a mapping of registration + * names that are used to register listeners. Values of this mapping must + * be objects that contain `registrationName` or `phasedRegistrationNames`. + * + * `executeDispatch` {function(object, function, string)} + * Optional, allows plugins to override how an event gets dispatched. By + * default, the listener is simply invoked. + * + * Each plugin that is injected into `EventsPluginHub` is immediately operable. + * + * @public + */ + +/** + * Methods for injecting dependencies. + */ +var injection = { + /** + * @param {array} InjectedEventPluginOrder + * @public + */ + injectEventPluginOrder: injectEventPluginOrder, + + /** + * @param {object} injectedNamesToPlugins Map from names to plugin modules. + */ + injectEventPluginsByName: injectEventPluginsByName +}; + +/** + * @param {object} inst The instance, which is the source of events. + * @param {string} registrationName Name of listener (e.g. `onClick`). + * @return {?function} The stored callback. + */ +function getListener(inst, registrationName) { + var listener = void 0; + + // TODO: shouldPreventMouseEvent is DOM-specific and definitely should not + // live here; needs to be moved to a better place soon + var stateNode = inst.stateNode; + if (!stateNode) { + // Work in progress (ex: onload events in incremental mode). + return null; + } + var props = getFiberCurrentPropsFromNode(stateNode); + if (!props) { + // Work in progress. + return null; + } + listener = props[registrationName]; + if (shouldPreventMouseEvent(registrationName, inst.type, props)) { + return null; + } + (function() { + if (!(!listener || typeof listener === "function")) { + throw ReactError( + "Expected `" + + registrationName + + "` listener to be a function, instead got a value of `" + + typeof listener + + "` type." + ); + } + })(); + return listener; +} + +/** + * Allows registered plugins an opportunity to extract events from top-level + * native browser events. + * + * @return {*} An accumulation of synthetic events. + * @internal + */ +function extractPluginEvents( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget +) { + var events = null; + for (var i = 0; i < plugins.length; i++) { + // Not every plugin in the ordering may be loaded at runtime. + var possiblePlugin = plugins[i]; + if (possiblePlugin) { + var extractedEvents = possiblePlugin.extractEvents( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ); + if (extractedEvents) { + events = accumulateInto(events, extractedEvents); + } + } + } + return events; +} + +function runExtractedPluginEventsInBatch( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget +) { + var events = extractPluginEvents( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ); + runEventsInBatch(events); +} + +var FunctionComponent = 0; +var ClassComponent = 1; +var IndeterminateComponent = 2; // Before we know whether it is function or class +var HostRoot = 3; // Root of a host tree. Could be nested inside another node. +var HostPortal = 4; // A subtree. Could be an entry point to a different renderer. +var HostComponent = 5; +var HostText = 6; +var Fragment = 7; +var Mode = 8; +var ContextConsumer = 9; +var ContextProvider = 10; +var ForwardRef = 11; +var Profiler = 12; +var SuspenseComponent = 13; +var MemoComponent = 14; +var SimpleMemoComponent = 15; +var LazyComponent = 16; +var IncompleteClassComponent = 17; +var DehydratedSuspenseComponent = 18; +var EventComponent = 19; +var EventTarget = 20; + +function getParent(inst) { + do { + inst = inst.return; + // TODO: If this is a HostRoot we might want to bail out. + // That is depending on if we want nested subtrees (layers) to bubble + // events to their parent. We could also go through parentNode on the + // host node but that wouldn't work for React Native and doesn't let us + // do the portal feature. + } while (inst && inst.tag !== HostComponent); + if (inst) { + return inst; + } + return null; +} + +/** + * Return the lowest common ancestor of A and B, or null if they are in + * different trees. + */ +function getLowestCommonAncestor(instA, instB) { + var depthA = 0; + for (var tempA = instA; tempA; tempA = getParent(tempA)) { + depthA++; + } + var depthB = 0; + for (var tempB = instB; tempB; tempB = getParent(tempB)) { + depthB++; + } + + // If A is deeper, crawl up. + while (depthA - depthB > 0) { + instA = getParent(instA); + depthA--; + } + + // If B is deeper, crawl up. + while (depthB - depthA > 0) { + instB = getParent(instB); + depthB--; + } + + // Walk in lockstep until we find a match. + var depth = depthA; + while (depth--) { + if (instA === instB || instA === instB.alternate) { + return instA; + } + instA = getParent(instA); + instB = getParent(instB); + } + return null; +} + +/** + * Return if A is an ancestor of B. + */ +function isAncestor(instA, instB) { + while (instB) { + if (instA === instB || instA === instB.alternate) { + return true; + } + instB = getParent(instB); + } + return false; +} + +/** + * Return the parent instance of the passed-in instance. + */ +function getParentInstance(inst) { + return getParent(inst); +} + +/** + * Simulates the traversal of a two-phase, capture/bubble event dispatch. + */ +function traverseTwoPhase(inst, fn, arg) { + var path = []; + while (inst) { + path.push(inst); + inst = getParent(inst); + } + var i = void 0; + for (i = path.length; i-- > 0; ) { + fn(path[i], "captured", arg); + } + for (i = 0; i < path.length; i++) { + fn(path[i], "bubbled", arg); + } +} + +/** + * Traverses the ID hierarchy and invokes the supplied `cb` on any IDs that + * should would receive a `mouseEnter` or `mouseLeave` event. + * + * Does not invoke the callback on the nearest common ancestor because nothing + * "entered" or "left" that element. + */ + +/** + * Some event types have a notion of different registration names for different + * "phases" of propagation. This finds listeners by a given phase. + */ +function listenerAtPhase(inst, event, propagationPhase) { + var registrationName = + event.dispatchConfig.phasedRegistrationNames[propagationPhase]; + return getListener(inst, registrationName); +} + +/** + * A small set of propagation patterns, each of which will accept a small amount + * of information, and generate a set of "dispatch ready event objects" - which + * are sets of events that have already been annotated with a set of dispatched + * listener functions/ids. The API is designed this way to discourage these + * propagation strategies from actually executing the dispatches, since we + * always want to collect the entire set of dispatches before executing even a + * single one. + */ + +/** + * Tags a `SyntheticEvent` with dispatched listeners. Creating this function + * here, allows us to not have to bind or create functions for each event. + * Mutating the event's members allows us to not have to create a wrapping + * "dispatch" object that pairs the event with the listener. + */ +function accumulateDirectionalDispatches(inst, phase, event) { + { + !inst + ? warningWithoutStack$1(false, "Dispatching inst must not be null") + : void 0; + } + var listener = listenerAtPhase(inst, event, phase); + if (listener) { + event._dispatchListeners = accumulateInto( + event._dispatchListeners, + listener + ); + event._dispatchInstances = accumulateInto(event._dispatchInstances, inst); + } +} + +/** + * Collect dispatches (must be entirely collected before dispatching - see unit + * tests). Lazily allocate the array to conserve memory. We must loop through + * each event and perform the traversal for each one. We cannot perform a + * single traversal for the entire collection of events because each event may + * have a different target. + */ +function accumulateTwoPhaseDispatchesSingle(event) { + if (event && event.dispatchConfig.phasedRegistrationNames) { + traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event); + } +} + +/** + * Same as `accumulateTwoPhaseDispatchesSingle`, but skips over the targetID. + */ +function accumulateTwoPhaseDispatchesSingleSkipTarget(event) { + if (event && event.dispatchConfig.phasedRegistrationNames) { + var targetInst = event._targetInst; + var parentInst = targetInst ? getParentInstance(targetInst) : null; + traverseTwoPhase(parentInst, accumulateDirectionalDispatches, event); + } +} + +/** + * Accumulates without regard to direction, does not look for phased + * registration names. Same as `accumulateDirectDispatchesSingle` but without + * requiring that the `dispatchMarker` be the same as the dispatched ID. + */ +function accumulateDispatches(inst, ignoredDirection, event) { + if (inst && event && event.dispatchConfig.registrationName) { + var registrationName = event.dispatchConfig.registrationName; + var listener = getListener(inst, registrationName); + if (listener) { + event._dispatchListeners = accumulateInto( + event._dispatchListeners, + listener + ); + event._dispatchInstances = accumulateInto(event._dispatchInstances, inst); + } + } +} + +/** + * Accumulates dispatches on an `SyntheticEvent`, but only for the + * `dispatchMarker`. + * @param {SyntheticEvent} event + */ +function accumulateDirectDispatchesSingle(event) { + if (event && event.dispatchConfig.registrationName) { + accumulateDispatches(event._targetInst, null, event); + } +} + +function accumulateTwoPhaseDispatches(events) { + forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle); +} + +function accumulateTwoPhaseDispatchesSkipTarget(events) { + forEachAccumulated(events, accumulateTwoPhaseDispatchesSingleSkipTarget); +} + +function accumulateDirectDispatches(events) { + forEachAccumulated(events, accumulateDirectDispatchesSingle); +} + +/* eslint valid-typeof: 0 */ + +var EVENT_POOL_SIZE = 10; + +/** + * @interface Event + * @see http://www.w3.org/TR/DOM-Level-3-Events/ + */ +var EventInterface = { + type: null, + target: null, + // currentTarget is set when dispatching; no use in copying it here + currentTarget: function() { + return null; + }, + eventPhase: null, + bubbles: null, + cancelable: null, + timeStamp: function(event) { + return event.timeStamp || Date.now(); + }, + defaultPrevented: null, + isTrusted: null +}; + +function functionThatReturnsTrue() { + return true; +} + +function functionThatReturnsFalse() { + return false; +} + +/** + * Synthetic events are dispatched by event plugins, typically in response to a + * top-level event delegation handler. + * + * These systems should generally use pooling to reduce the frequency of garbage + * collection. The system should check `isPersistent` to determine whether the + * event should be released into the pool after being dispatched. Users that + * need a persisted event should invoke `persist`. + * + * Synthetic events (and subclasses) implement the DOM Level 3 Events API by + * normalizing browser quirks. Subclasses do not necessarily have to implement a + * DOM interface; custom application-specific events can also subclass this. + * + * @param {object} dispatchConfig Configuration used to dispatch this event. + * @param {*} targetInst Marker identifying the event target. + * @param {object} nativeEvent Native browser event. + * @param {DOMEventTarget} nativeEventTarget Target node. + */ +function SyntheticEvent( + dispatchConfig, + targetInst, + nativeEvent, + nativeEventTarget +) { + { + // these have a getter/setter for warnings + delete this.nativeEvent; + delete this.preventDefault; + delete this.stopPropagation; + delete this.isDefaultPrevented; + delete this.isPropagationStopped; + } + + this.dispatchConfig = dispatchConfig; + this._targetInst = targetInst; + this.nativeEvent = nativeEvent; + + var Interface = this.constructor.Interface; + for (var propName in Interface) { + if (!Interface.hasOwnProperty(propName)) { + continue; + } + { + delete this[propName]; // this has a getter/setter for warnings + } + var normalize = Interface[propName]; + if (normalize) { + this[propName] = normalize(nativeEvent); + } else { + if (propName === "target") { + this.target = nativeEventTarget; + } else { + this[propName] = nativeEvent[propName]; + } + } + } + + var defaultPrevented = + nativeEvent.defaultPrevented != null + ? nativeEvent.defaultPrevented + : nativeEvent.returnValue === false; + if (defaultPrevented) { + this.isDefaultPrevented = functionThatReturnsTrue; + } else { + this.isDefaultPrevented = functionThatReturnsFalse; + } + this.isPropagationStopped = functionThatReturnsFalse; + return this; +} + +Object.assign(SyntheticEvent.prototype, { + preventDefault: function() { + this.defaultPrevented = true; + var event = this.nativeEvent; + if (!event) { + return; + } + + if (event.preventDefault) { + event.preventDefault(); + } else if (typeof event.returnValue !== "unknown") { + event.returnValue = false; + } + this.isDefaultPrevented = functionThatReturnsTrue; + }, + + stopPropagation: function() { + var event = this.nativeEvent; + if (!event) { + return; + } + + if (event.stopPropagation) { + event.stopPropagation(); + } else if (typeof event.cancelBubble !== "unknown") { + // The ChangeEventPlugin registers a "propertychange" event for + // IE. This event does not support bubbling or cancelling, and + // any references to cancelBubble throw "Member not found". A + // typeof check of "unknown" circumvents this issue (and is also + // IE specific). + event.cancelBubble = true; + } + + this.isPropagationStopped = functionThatReturnsTrue; + }, + + /** + * We release all dispatched `SyntheticEvent`s after each event loop, adding + * them back into the pool. This allows a way to hold onto a reference that + * won't be added back into the pool. + */ + persist: function() { + this.isPersistent = functionThatReturnsTrue; + }, + + /** + * Checks if this event should be released back into the pool. + * + * @return {boolean} True if this should not be released, false otherwise. + */ + isPersistent: functionThatReturnsFalse, + + /** + * `PooledClass` looks for `destructor` on each instance it releases. + */ + destructor: function() { + var Interface = this.constructor.Interface; + for (var propName in Interface) { + { + Object.defineProperty( + this, + propName, + getPooledWarningPropertyDefinition(propName, Interface[propName]) + ); + } + } + this.dispatchConfig = null; + this._targetInst = null; + this.nativeEvent = null; + this.isDefaultPrevented = functionThatReturnsFalse; + this.isPropagationStopped = functionThatReturnsFalse; + this._dispatchListeners = null; + this._dispatchInstances = null; + { + Object.defineProperty( + this, + "nativeEvent", + getPooledWarningPropertyDefinition("nativeEvent", null) + ); + Object.defineProperty( + this, + "isDefaultPrevented", + getPooledWarningPropertyDefinition( + "isDefaultPrevented", + functionThatReturnsFalse + ) + ); + Object.defineProperty( + this, + "isPropagationStopped", + getPooledWarningPropertyDefinition( + "isPropagationStopped", + functionThatReturnsFalse + ) + ); + Object.defineProperty( + this, + "preventDefault", + getPooledWarningPropertyDefinition("preventDefault", function() {}) + ); + Object.defineProperty( + this, + "stopPropagation", + getPooledWarningPropertyDefinition("stopPropagation", function() {}) + ); + } + } +}); + +SyntheticEvent.Interface = EventInterface; + +/** + * Helper to reduce boilerplate when creating subclasses. + */ +SyntheticEvent.extend = function(Interface) { + var Super = this; + + var E = function() {}; + E.prototype = Super.prototype; + var prototype = new E(); + + function Class() { + return Super.apply(this, arguments); + } + Object.assign(prototype, Class.prototype); + Class.prototype = prototype; + Class.prototype.constructor = Class; + + Class.Interface = Object.assign({}, Super.Interface, Interface); + Class.extend = Super.extend; + addEventPoolingTo(Class); + + return Class; +}; + +addEventPoolingTo(SyntheticEvent); + +/** + * Helper to nullify syntheticEvent instance properties when destructing + * + * @param {String} propName + * @param {?object} getVal + * @return {object} defineProperty object + */ +function getPooledWarningPropertyDefinition(propName, getVal) { + var isFunction = typeof getVal === "function"; + return { + configurable: true, + set: set, + get: get + }; + + function set(val) { + var action = isFunction ? "setting the method" : "setting the property"; + warn(action, "This is effectively a no-op"); + return val; + } + + function get() { + var action = isFunction ? "accessing the method" : "accessing the property"; + var result = isFunction + ? "This is a no-op function" + : "This is set to null"; + warn(action, result); + return getVal; + } + + function warn(action, result) { + var warningCondition = false; + !warningCondition + ? warningWithoutStack$1( + false, + "This synthetic event is reused for performance reasons. If you're seeing this, " + + "you're %s `%s` on a released/nullified synthetic event. %s. " + + "If you must keep the original synthetic event around, use event.persist(). " + + "See https://fb.me/react-event-pooling for more information.", + action, + propName, + result + ) + : void 0; + } +} + +function getPooledEvent(dispatchConfig, targetInst, nativeEvent, nativeInst) { + var EventConstructor = this; + if (EventConstructor.eventPool.length) { + var instance = EventConstructor.eventPool.pop(); + EventConstructor.call( + instance, + dispatchConfig, + targetInst, + nativeEvent, + nativeInst + ); + return instance; + } + return new EventConstructor( + dispatchConfig, + targetInst, + nativeEvent, + nativeInst + ); +} + +function releasePooledEvent(event) { + var EventConstructor = this; + (function() { + if (!(event instanceof EventConstructor)) { + throw ReactError( + "Trying to release an event instance into a pool of a different type." + ); + } + })(); + event.destructor(); + if (EventConstructor.eventPool.length < EVENT_POOL_SIZE) { + EventConstructor.eventPool.push(event); + } +} + +function addEventPoolingTo(EventConstructor) { + EventConstructor.eventPool = []; + EventConstructor.getPooled = getPooledEvent; + EventConstructor.release = releasePooledEvent; +} + +/** + * `touchHistory` isn't actually on the native event, but putting it in the + * interface will ensure that it is cleaned up when pooled/destroyed. The + * `ResponderEventPlugin` will populate it appropriately. + */ +var ResponderSyntheticEvent = SyntheticEvent.extend({ + touchHistory: function(nativeEvent) { + return null; // Actually doesn't even look at the native event. + } +}); + +var TOP_TOUCH_START = "topTouchStart"; +var TOP_TOUCH_MOVE = "topTouchMove"; +var TOP_TOUCH_END = "topTouchEnd"; +var TOP_TOUCH_CANCEL = "topTouchCancel"; +var TOP_SCROLL = "topScroll"; +var TOP_SELECTION_CHANGE = "topSelectionChange"; + +function isStartish(topLevelType) { + return topLevelType === TOP_TOUCH_START; +} + +function isMoveish(topLevelType) { + return topLevelType === TOP_TOUCH_MOVE; +} + +function isEndish(topLevelType) { + return topLevelType === TOP_TOUCH_END || topLevelType === TOP_TOUCH_CANCEL; +} + +var startDependencies = [TOP_TOUCH_START]; +var moveDependencies = [TOP_TOUCH_MOVE]; +var endDependencies = [TOP_TOUCH_CANCEL, TOP_TOUCH_END]; + +/** + * Tracks the position and time of each active touch by `touch.identifier`. We + * should typically only see IDs in the range of 1-20 because IDs get recycled + * when touches end and start again. + */ + +var MAX_TOUCH_BANK = 20; +var touchBank = []; +var touchHistory = { + touchBank: touchBank, + numberActiveTouches: 0, + // If there is only one active touch, we remember its location. This prevents + // us having to loop through all of the touches all the time in the most + // common case. + indexOfSingleActiveTouch: -1, + mostRecentTimeStamp: 0 +}; + +function timestampForTouch(touch) { + // The legacy internal implementation provides "timeStamp", which has been + // renamed to "timestamp". Let both work for now while we iron it out + // TODO (evv): rename timeStamp to timestamp in internal code + return touch.timeStamp || touch.timestamp; +} + +/** + * TODO: Instead of making gestures recompute filtered velocity, we could + * include a built in velocity computation that can be reused globally. + */ +function createTouchRecord(touch) { + return { + touchActive: true, + startPageX: touch.pageX, + startPageY: touch.pageY, + startTimeStamp: timestampForTouch(touch), + currentPageX: touch.pageX, + currentPageY: touch.pageY, + currentTimeStamp: timestampForTouch(touch), + previousPageX: touch.pageX, + previousPageY: touch.pageY, + previousTimeStamp: timestampForTouch(touch) + }; +} + +function resetTouchRecord(touchRecord, touch) { + touchRecord.touchActive = true; + touchRecord.startPageX = touch.pageX; + touchRecord.startPageY = touch.pageY; + touchRecord.startTimeStamp = timestampForTouch(touch); + touchRecord.currentPageX = touch.pageX; + touchRecord.currentPageY = touch.pageY; + touchRecord.currentTimeStamp = timestampForTouch(touch); + touchRecord.previousPageX = touch.pageX; + touchRecord.previousPageY = touch.pageY; + touchRecord.previousTimeStamp = timestampForTouch(touch); +} + +function getTouchIdentifier(_ref) { + var identifier = _ref.identifier; + + (function() { + if (!(identifier != null)) { + throw ReactError("Touch object is missing identifier."); + } + })(); + { + !(identifier <= MAX_TOUCH_BANK) + ? warningWithoutStack$1( + false, + "Touch identifier %s is greater than maximum supported %s which causes " + + "performance issues backfilling array locations for all of the indices.", + identifier, + MAX_TOUCH_BANK + ) + : void 0; + } + return identifier; +} + +function recordTouchStart(touch) { + var identifier = getTouchIdentifier(touch); + var touchRecord = touchBank[identifier]; + if (touchRecord) { + resetTouchRecord(touchRecord, touch); + } else { + touchBank[identifier] = createTouchRecord(touch); + } + touchHistory.mostRecentTimeStamp = timestampForTouch(touch); +} + +function recordTouchMove(touch) { + var touchRecord = touchBank[getTouchIdentifier(touch)]; + if (touchRecord) { + touchRecord.touchActive = true; + touchRecord.previousPageX = touchRecord.currentPageX; + touchRecord.previousPageY = touchRecord.currentPageY; + touchRecord.previousTimeStamp = touchRecord.currentTimeStamp; + touchRecord.currentPageX = touch.pageX; + touchRecord.currentPageY = touch.pageY; + touchRecord.currentTimeStamp = timestampForTouch(touch); + touchHistory.mostRecentTimeStamp = timestampForTouch(touch); + } else { + console.error( + "Cannot record touch move without a touch start.\n" + "Touch Move: %s\n", + "Touch Bank: %s", + printTouch(touch), + printTouchBank() + ); + } +} + +function recordTouchEnd(touch) { + var touchRecord = touchBank[getTouchIdentifier(touch)]; + if (touchRecord) { + touchRecord.touchActive = false; + touchRecord.previousPageX = touchRecord.currentPageX; + touchRecord.previousPageY = touchRecord.currentPageY; + touchRecord.previousTimeStamp = touchRecord.currentTimeStamp; + touchRecord.currentPageX = touch.pageX; + touchRecord.currentPageY = touch.pageY; + touchRecord.currentTimeStamp = timestampForTouch(touch); + touchHistory.mostRecentTimeStamp = timestampForTouch(touch); + } else { + console.error( + "Cannot record touch end without a touch start.\n" + "Touch End: %s\n", + "Touch Bank: %s", + printTouch(touch), + printTouchBank() + ); + } +} + +function printTouch(touch) { + return JSON.stringify({ + identifier: touch.identifier, + pageX: touch.pageX, + pageY: touch.pageY, + timestamp: timestampForTouch(touch) + }); +} + +function printTouchBank() { + var printed = JSON.stringify(touchBank.slice(0, MAX_TOUCH_BANK)); + if (touchBank.length > MAX_TOUCH_BANK) { + printed += " (original size: " + touchBank.length + ")"; + } + return printed; +} + +var ResponderTouchHistoryStore = { + recordTouchTrack: function(topLevelType, nativeEvent) { + if (isMoveish(topLevelType)) { + nativeEvent.changedTouches.forEach(recordTouchMove); + } else if (isStartish(topLevelType)) { + nativeEvent.changedTouches.forEach(recordTouchStart); + touchHistory.numberActiveTouches = nativeEvent.touches.length; + if (touchHistory.numberActiveTouches === 1) { + touchHistory.indexOfSingleActiveTouch = + nativeEvent.touches[0].identifier; + } + } else if (isEndish(topLevelType)) { + nativeEvent.changedTouches.forEach(recordTouchEnd); + touchHistory.numberActiveTouches = nativeEvent.touches.length; + if (touchHistory.numberActiveTouches === 1) { + for (var i = 0; i < touchBank.length; i++) { + var touchTrackToCheck = touchBank[i]; + if (touchTrackToCheck != null && touchTrackToCheck.touchActive) { + touchHistory.indexOfSingleActiveTouch = i; + break; + } + } + { + var activeRecord = touchBank[touchHistory.indexOfSingleActiveTouch]; + !(activeRecord != null && activeRecord.touchActive) + ? warningWithoutStack$1(false, "Cannot find single active touch.") + : void 0; + } + } + } + }, + + touchHistory: touchHistory +}; + +/** + * Accumulates items that must not be null or undefined. + * + * This is used to conserve memory by avoiding array allocations. + * + * @return {*|array<*>} An accumulation of items. + */ +function accumulate(current, next) { + (function() { + if (!(next != null)) { + throw ReactError( + "accumulate(...): Accumulated items must not be null or undefined." + ); + } + })(); + + if (current == null) { + return next; + } + + // Both are not empty. Warning: Never call x.concat(y) when you are not + // certain that x is an Array (x could be a string with concat method). + if (Array.isArray(current)) { + return current.concat(next); + } + + if (Array.isArray(next)) { + return [current].concat(next); + } + + return [current, next]; +} + +/** + * Instance of element that should respond to touch/move types of interactions, + * as indicated explicitly by relevant callbacks. + */ +var responderInst = null; + +/** + * Count of current touches. A textInput should become responder iff the + * selection changes while there is a touch on the screen. + */ +var trackedTouchCount = 0; + +var changeResponder = function(nextResponderInst, blockHostResponder) { + var oldResponderInst = responderInst; + responderInst = nextResponderInst; + if (ResponderEventPlugin.GlobalResponderHandler !== null) { + ResponderEventPlugin.GlobalResponderHandler.onChange( + oldResponderInst, + nextResponderInst, + blockHostResponder + ); + } +}; + +var eventTypes = { + /** + * On a `touchStart`/`mouseDown`, is it desired that this element become the + * responder? + */ + startShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onStartShouldSetResponder", + captured: "onStartShouldSetResponderCapture" + }, + dependencies: startDependencies + }, + + /** + * On a `scroll`, is it desired that this element become the responder? This + * is usually not needed, but should be used to retroactively infer that a + * `touchStart` had occurred during momentum scroll. During a momentum scroll, + * a touch start will be immediately followed by a scroll event if the view is + * currently scrolling. + * + * TODO: This shouldn't bubble. + */ + scrollShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onScrollShouldSetResponder", + captured: "onScrollShouldSetResponderCapture" + }, + dependencies: [TOP_SCROLL] + }, + + /** + * On text selection change, should this element become the responder? This + * is needed for text inputs or other views with native selection, so the + * JS view can claim the responder. + * + * TODO: This shouldn't bubble. + */ + selectionChangeShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onSelectionChangeShouldSetResponder", + captured: "onSelectionChangeShouldSetResponderCapture" + }, + dependencies: [TOP_SELECTION_CHANGE] + }, + + /** + * On a `touchMove`/`mouseMove`, is it desired that this element become the + * responder? + */ + moveShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onMoveShouldSetResponder", + captured: "onMoveShouldSetResponderCapture" + }, + dependencies: moveDependencies + }, + + /** + * Direct responder events dispatched directly to responder. Do not bubble. + */ + responderStart: { + registrationName: "onResponderStart", + dependencies: startDependencies + }, + responderMove: { + registrationName: "onResponderMove", + dependencies: moveDependencies + }, + responderEnd: { + registrationName: "onResponderEnd", + dependencies: endDependencies + }, + responderRelease: { + registrationName: "onResponderRelease", + dependencies: endDependencies + }, + responderTerminationRequest: { + registrationName: "onResponderTerminationRequest", + dependencies: [] + }, + responderGrant: { + registrationName: "onResponderGrant", + dependencies: [] + }, + responderReject: { + registrationName: "onResponderReject", + dependencies: [] + }, + responderTerminate: { + registrationName: "onResponderTerminate", + dependencies: [] + } +}; + +/** + * + * Responder System: + * ---------------- + * + * - A global, solitary "interaction lock" on a view. + * - If a node becomes the responder, it should convey visual feedback + * immediately to indicate so, either by highlighting or moving accordingly. + * - To be the responder means, that touches are exclusively important to that + * responder view, and no other view. + * - While touches are still occurring, the responder lock can be transferred to + * a new view, but only to increasingly "higher" views (meaning ancestors of + * the current responder). + * + * Responder being granted: + * ------------------------ + * + * - Touch starts, moves, and scrolls can cause an ID to become the responder. + * - We capture/bubble `startShouldSetResponder`/`moveShouldSetResponder` to + * the "appropriate place". + * - If nothing is currently the responder, the "appropriate place" is the + * initiating event's `targetID`. + * - If something *is* already the responder, the "appropriate place" is the + * first common ancestor of the event target and the current `responderInst`. + * - Some negotiation happens: See the timing diagram below. + * - Scrolled views automatically become responder. The reasoning is that a + * platform scroll view that isn't built on top of the responder system has + * began scrolling, and the active responder must now be notified that the + * interaction is no longer locked to it - the system has taken over. + * + * - Responder being released: + * As soon as no more touches that *started* inside of descendants of the + * *current* responderInst, an `onResponderRelease` event is dispatched to the + * current responder, and the responder lock is released. + * + * TODO: + * - on "end", a callback hook for `onResponderEndShouldRemainResponder` that + * determines if the responder lock should remain. + * - If a view shouldn't "remain" the responder, any active touches should by + * default be considered "dead" and do not influence future negotiations or + * bubble paths. It should be as if those touches do not exist. + * -- For multitouch: Usually a translate-z will choose to "remain" responder + * after one out of many touches ended. For translate-y, usually the view + * doesn't wish to "remain" responder after one of many touches end. + * - Consider building this on top of a `stopPropagation` model similar to + * `W3C` events. + * - Ensure that `onResponderTerminate` is called on touch cancels, whether or + * not `onResponderTerminationRequest` returns `true` or `false`. + * + */ + +/* Negotiation Performed + +-----------------------+ + / \ +Process low level events to + Current Responder + wantsResponderID +determine who to perform negot-| (if any exists at all) | +iation/transition | Otherwise just pass through| +-------------------------------+----------------------------+------------------+ +Bubble to find first ID | | +to return true:wantsResponderID| | + | | + +-------------+ | | + | onTouchStart| | | + +------+------+ none | | + | return| | ++-----------v-------------+true| +------------------------+ | +|onStartShouldSetResponder|----->|onResponderStart (cur) |<-----------+ ++-----------+-------------+ | +------------------------+ | | + | | | +--------+-------+ + | returned true for| false:REJECT +-------->|onResponderReject + | wantsResponderID | | | +----------------+ + | (now attempt | +------------------+-----+ | + | handoff) | | onResponder | | + +------------------->| TerminationRequest| | + | +------------------+-----+ | + | | | +----------------+ + | true:GRANT +-------->|onResponderGrant| + | | +--------+-------+ + | +------------------------+ | | + | | onResponderTerminate |<-----------+ + | +------------------+-----+ | + | | | +----------------+ + | +-------->|onResponderStart| + | | +----------------+ +Bubble to find first ID | | +to return true:wantsResponderID| | + | | + +-------------+ | | + | onTouchMove | | | + +------+------+ none | | + | return| | ++-----------v-------------+true| +------------------------+ | +|onMoveShouldSetResponder |----->|onResponderMove (cur) |<-----------+ ++-----------+-------------+ | +------------------------+ | | + | | | +--------+-------+ + | returned true for| false:REJECT +-------->|onResponderRejec| + | wantsResponderID | | | +----------------+ + | (now attempt | +------------------+-----+ | + | handoff) | | onResponder | | + +------------------->| TerminationRequest| | + | +------------------+-----+ | + | | | +----------------+ + | true:GRANT +-------->|onResponderGrant| + | | +--------+-------+ + | +------------------------+ | | + | | onResponderTerminate |<-----------+ + | +------------------+-----+ | + | | | +----------------+ + | +-------->|onResponderMove | + | | +----------------+ + | | + | | + Some active touch started| | + inside current responder | +------------------------+ | + +------------------------->| onResponderEnd | | + | | +------------------------+ | + +---+---------+ | | + | onTouchEnd | | | + +---+---------+ | | + | | +------------------------+ | + +------------------------->| onResponderEnd | | + No active touches started| +-----------+------------+ | + inside current responder | | | + | v | + | +------------------------+ | + | | onResponderRelease | | + | +------------------------+ | + | | + + + */ + +/** + * A note about event ordering in the `EventPluginHub`. + * + * Suppose plugins are injected in the following order: + * + * `[R, S, C]` + * + * To help illustrate the example, assume `S` is `SimpleEventPlugin` (for + * `onClick` etc) and `R` is `ResponderEventPlugin`. + * + * "Deferred-Dispatched Events": + * + * - The current event plugin system will traverse the list of injected plugins, + * in order, and extract events by collecting the plugin's return value of + * `extractEvents()`. + * - These events that are returned from `extractEvents` are "deferred + * dispatched events". + * - When returned from `extractEvents`, deferred-dispatched events contain an + * "accumulation" of deferred dispatches. + * - These deferred dispatches are accumulated/collected before they are + * returned, but processed at a later time by the `EventPluginHub` (hence the + * name deferred). + * + * In the process of returning their deferred-dispatched events, event plugins + * themselves can dispatch events on-demand without returning them from + * `extractEvents`. Plugins might want to do this, so that they can use event + * dispatching as a tool that helps them decide which events should be extracted + * in the first place. + * + * "On-Demand-Dispatched Events": + * + * - On-demand-dispatched events are not returned from `extractEvents`. + * - On-demand-dispatched events are dispatched during the process of returning + * the deferred-dispatched events. + * - They should not have side effects. + * - They should be avoided, and/or eventually be replaced with another + * abstraction that allows event plugins to perform multiple "rounds" of event + * extraction. + * + * Therefore, the sequence of event dispatches becomes: + * + * - `R`s on-demand events (if any) (dispatched by `R` on-demand) + * - `S`s on-demand events (if any) (dispatched by `S` on-demand) + * - `C`s on-demand events (if any) (dispatched by `C` on-demand) + * - `R`s extracted events (if any) (dispatched by `EventPluginHub`) + * - `S`s extracted events (if any) (dispatched by `EventPluginHub`) + * - `C`s extracted events (if any) (dispatched by `EventPluginHub`) + * + * In the case of `ResponderEventPlugin`: If the `startShouldSetResponder` + * on-demand dispatch returns `true` (and some other details are satisfied) the + * `onResponderGrant` deferred dispatched event is returned from + * `extractEvents`. The sequence of dispatch executions in this case + * will appear as follows: + * + * - `startShouldSetResponder` (`ResponderEventPlugin` dispatches on-demand) + * - `touchStartCapture` (`EventPluginHub` dispatches as usual) + * - `touchStart` (`EventPluginHub` dispatches as usual) + * - `responderGrant/Reject` (`EventPluginHub` dispatches as usual) + */ + +function setResponderAndExtractTransfer( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget +) { + var shouldSetEventType = isStartish(topLevelType) + ? eventTypes.startShouldSetResponder + : isMoveish(topLevelType) + ? eventTypes.moveShouldSetResponder + : topLevelType === TOP_SELECTION_CHANGE + ? eventTypes.selectionChangeShouldSetResponder + : eventTypes.scrollShouldSetResponder; + + // TODO: stop one short of the current responder. + var bubbleShouldSetFrom = !responderInst + ? targetInst + : getLowestCommonAncestor(responderInst, targetInst); + + // When capturing/bubbling the "shouldSet" event, we want to skip the target + // (deepest ID) if it happens to be the current responder. The reasoning: + // It's strange to get an `onMoveShouldSetResponder` when you're *already* + // the responder. + var skipOverBubbleShouldSetFrom = bubbleShouldSetFrom === responderInst; + var shouldSetEvent = ResponderSyntheticEvent.getPooled( + shouldSetEventType, + bubbleShouldSetFrom, + nativeEvent, + nativeEventTarget + ); + shouldSetEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + if (skipOverBubbleShouldSetFrom) { + accumulateTwoPhaseDispatchesSkipTarget(shouldSetEvent); + } else { + accumulateTwoPhaseDispatches(shouldSetEvent); + } + var wantsResponderInst = executeDispatchesInOrderStopAtTrue(shouldSetEvent); + if (!shouldSetEvent.isPersistent()) { + shouldSetEvent.constructor.release(shouldSetEvent); + } + + if (!wantsResponderInst || wantsResponderInst === responderInst) { + return null; + } + var extracted = void 0; + var grantEvent = ResponderSyntheticEvent.getPooled( + eventTypes.responderGrant, + wantsResponderInst, + nativeEvent, + nativeEventTarget + ); + grantEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + + accumulateDirectDispatches(grantEvent); + var blockHostResponder = executeDirectDispatch(grantEvent) === true; + if (responderInst) { + var terminationRequestEvent = ResponderSyntheticEvent.getPooled( + eventTypes.responderTerminationRequest, + responderInst, + nativeEvent, + nativeEventTarget + ); + terminationRequestEvent.touchHistory = + ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches(terminationRequestEvent); + var shouldSwitch = + !hasDispatches(terminationRequestEvent) || + executeDirectDispatch(terminationRequestEvent); + if (!terminationRequestEvent.isPersistent()) { + terminationRequestEvent.constructor.release(terminationRequestEvent); + } + + if (shouldSwitch) { + var terminateEvent = ResponderSyntheticEvent.getPooled( + eventTypes.responderTerminate, + responderInst, + nativeEvent, + nativeEventTarget + ); + terminateEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches(terminateEvent); + extracted = accumulate(extracted, [grantEvent, terminateEvent]); + changeResponder(wantsResponderInst, blockHostResponder); + } else { + var rejectEvent = ResponderSyntheticEvent.getPooled( + eventTypes.responderReject, + wantsResponderInst, + nativeEvent, + nativeEventTarget + ); + rejectEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches(rejectEvent); + extracted = accumulate(extracted, rejectEvent); + } + } else { + extracted = accumulate(extracted, grantEvent); + changeResponder(wantsResponderInst, blockHostResponder); + } + return extracted; +} + +/** + * A transfer is a negotiation between a currently set responder and the next + * element to claim responder status. Any start event could trigger a transfer + * of responderInst. Any move event could trigger a transfer. + * + * @param {string} topLevelType Record from `BrowserEventConstants`. + * @return {boolean} True if a transfer of responder could possibly occur. + */ +function canTriggerTransfer(topLevelType, topLevelInst, nativeEvent) { + return ( + topLevelInst && + // responderIgnoreScroll: We are trying to migrate away from specifically + // tracking native scroll events here and responderIgnoreScroll indicates we + // will send topTouchCancel to handle canceling touch events instead + ((topLevelType === TOP_SCROLL && !nativeEvent.responderIgnoreScroll) || + (trackedTouchCount > 0 && topLevelType === TOP_SELECTION_CHANGE) || + isStartish(topLevelType) || + isMoveish(topLevelType)) + ); +} + +/** + * Returns whether or not this touch end event makes it such that there are no + * longer any touches that started inside of the current `responderInst`. + * + * @param {NativeEvent} nativeEvent Native touch end event. + * @return {boolean} Whether or not this touch end event ends the responder. + */ +function noResponderTouches(nativeEvent) { + var touches = nativeEvent.touches; + if (!touches || touches.length === 0) { + return true; + } + for (var i = 0; i < touches.length; i++) { + var activeTouch = touches[i]; + var target = activeTouch.target; + if (target !== null && target !== undefined && target !== 0) { + // Is the original touch location inside of the current responder? + var targetInst = getInstanceFromNode(target); + if (isAncestor(responderInst, targetInst)) { + return false; + } + } + } + return true; +} + +var ResponderEventPlugin = { + /* For unit testing only */ + _getResponder: function() { + return responderInst; + }, + + eventTypes: eventTypes, + + /** + * We must be resilient to `targetInst` being `null` on `touchMove` or + * `touchEnd`. On certain platforms, this means that a native scroll has + * assumed control and the original touch targets are destroyed. + */ + extractEvents: function( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ) { + if (isStartish(topLevelType)) { + trackedTouchCount += 1; + } else if (isEndish(topLevelType)) { + if (trackedTouchCount >= 0) { + trackedTouchCount -= 1; + } else { + console.error( + "Ended a touch event which was not counted in `trackedTouchCount`." + ); + return null; + } + } + + ResponderTouchHistoryStore.recordTouchTrack(topLevelType, nativeEvent); + + var extracted = canTriggerTransfer(topLevelType, targetInst, nativeEvent) + ? setResponderAndExtractTransfer( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ) + : null; + // Responder may or may not have transferred on a new touch start/move. + // Regardless, whoever is the responder after any potential transfer, we + // direct all touch start/move/ends to them in the form of + // `onResponderMove/Start/End`. These will be called for *every* additional + // finger that move/start/end, dispatched directly to whoever is the + // current responder at that moment, until the responder is "released". + // + // These multiple individual change touch events are are always bookended + // by `onResponderGrant`, and one of + // (`onResponderRelease/onResponderTerminate`). + var isResponderTouchStart = responderInst && isStartish(topLevelType); + var isResponderTouchMove = responderInst && isMoveish(topLevelType); + var isResponderTouchEnd = responderInst && isEndish(topLevelType); + var incrementalTouch = isResponderTouchStart + ? eventTypes.responderStart + : isResponderTouchMove + ? eventTypes.responderMove + : isResponderTouchEnd + ? eventTypes.responderEnd + : null; + + if (incrementalTouch) { + var gesture = ResponderSyntheticEvent.getPooled( + incrementalTouch, + responderInst, + nativeEvent, + nativeEventTarget + ); + gesture.touchHistory = ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches(gesture); + extracted = accumulate(extracted, gesture); + } + + var isResponderTerminate = + responderInst && topLevelType === TOP_TOUCH_CANCEL; + var isResponderRelease = + responderInst && + !isResponderTerminate && + isEndish(topLevelType) && + noResponderTouches(nativeEvent); + var finalTouch = isResponderTerminate + ? eventTypes.responderTerminate + : isResponderRelease + ? eventTypes.responderRelease + : null; + if (finalTouch) { + var finalEvent = ResponderSyntheticEvent.getPooled( + finalTouch, + responderInst, + nativeEvent, + nativeEventTarget + ); + finalEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches(finalEvent); + extracted = accumulate(extracted, finalEvent); + changeResponder(null); + } + + return extracted; + }, + + GlobalResponderHandler: null, + + injection: { + /** + * @param {{onChange: (ReactID, ReactID) => void} GlobalResponderHandler + * Object that handles any change in responder. Use this to inject + * integration with an existing touch handling system etc. + */ + injectGlobalResponderHandler: function(GlobalResponderHandler) { + ResponderEventPlugin.GlobalResponderHandler = GlobalResponderHandler; + } + } +}; + +// Module provided by RN: +var customBubblingEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customBubblingEventTypes; +var customDirectEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customDirectEventTypes; +var eventTypes$1 = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes; + +var ReactNativeBridgeEventPlugin = { + eventTypes: eventTypes$1, + + /** + * @see {EventPluginHub.extractEvents} + */ + extractEvents: function( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ) { + if (targetInst == null) { + // Probably a node belonging to another renderer's tree. + return null; + } + var bubbleDispatchConfig = customBubblingEventTypes[topLevelType]; + var directDispatchConfig = customDirectEventTypes[topLevelType]; + (function() { + if (!(bubbleDispatchConfig || directDispatchConfig)) { + throw ReactError( + 'Unsupported top level event type "' + topLevelType + '" dispatched' + ); + } + })(); + var event = SyntheticEvent.getPooled( + bubbleDispatchConfig || directDispatchConfig, + targetInst, + nativeEvent, + nativeEventTarget + ); + if (bubbleDispatchConfig) { + accumulateTwoPhaseDispatches(event); + } else if (directDispatchConfig) { + accumulateDirectDispatches(event); + } else { + return null; + } + return event; + } +}; + +var ReactNativeEventPluginOrder = [ + "ResponderEventPlugin", + "ReactNativeBridgeEventPlugin" +]; + +/** + * Make sure essential globals are available and are patched correctly. Please don't remove this + * line. Bundles created by react-packager `require` it before executing any application code. This + * ensures it exists in the dependency graph and can be `require`d. + * TODO: require this in packager, not in React #10932517 + */ +// Module provided by RN: +/** + * Inject module for resolving DOM hierarchy and plugin ordering. + */ +injection.injectEventPluginOrder(ReactNativeEventPluginOrder); + +/** + * Some important event plugins included by default (without having to require + * them). + */ +injection.injectEventPluginsByName({ + ResponderEventPlugin: ResponderEventPlugin, + ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin +}); + +function getInstanceFromInstance(instanceHandle) { + return instanceHandle; +} + +function getTagFromInstance(inst) { + var tag = inst.stateNode.canonical._nativeTag; + (function() { + if (!tag) { + throw ReactError("All native instances should have a tag."); + } + })(); + return tag; +} + +function getFiberCurrentPropsFromNode$1(inst) { + return inst.canonical.currentProps; +} + +// Module provided by RN: +var ReactFabricGlobalResponderHandler = { + onChange: function(from, to, blockNativeResponder) { + if (to !== null) { + var tag = to.stateNode.canonical._nativeTag; + ReactNativePrivateInterface.UIManager.setJSResponder( + tag, + blockNativeResponder + ); + } else { + ReactNativePrivateInterface.UIManager.clearJSResponder(); + } + } +}; + +setComponentTree( + getFiberCurrentPropsFromNode$1, + getInstanceFromInstance, + getTagFromInstance +); + +ResponderEventPlugin.injection.injectGlobalResponderHandler( + ReactFabricGlobalResponderHandler +); + +/** + * `ReactInstanceMap` maintains a mapping from a public facing stateful + * instance (key) and the internal representation (value). This allows public + * methods to accept the user facing instance as an argument and map them back + * to internal methods. + * + * Note that this module is currently shared and assumed to be stateless. + * If this becomes an actual Map, that will break. + */ + +/** + * This API should be called `delete` but we'd have to make sure to always + * transform these to strings for IE support. When this transform is fully + * supported we can rename it. + */ + +function get(key) { + return key._reactInternalFiber; +} + +function set(key, value) { + key._reactInternalFiber = value; +} + +var ReactSharedInternals = + React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; + +// Prevent newer renderers from RTE when used with older react package versions. +// Current owner and dispatcher used to share the same ref, +// but PR #14548 split them out to better support the react-debug-tools package. +if (!ReactSharedInternals.hasOwnProperty("ReactCurrentDispatcher")) { + ReactSharedInternals.ReactCurrentDispatcher = { + current: null + }; +} + +// The Symbol used to tag the ReactElement-like types. If there is no native Symbol +// nor polyfill, then a plain number is used for performance. +var hasSymbol = typeof Symbol === "function" && Symbol.for; + +var REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for("react.element") : 0xeac7; +var REACT_PORTAL_TYPE = hasSymbol ? Symbol.for("react.portal") : 0xeaca; +var REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for("react.fragment") : 0xeacb; +var REACT_STRICT_MODE_TYPE = hasSymbol + ? Symbol.for("react.strict_mode") + : 0xeacc; +var REACT_PROFILER_TYPE = hasSymbol ? Symbol.for("react.profiler") : 0xead2; +var REACT_PROVIDER_TYPE = hasSymbol ? Symbol.for("react.provider") : 0xeacd; +var REACT_CONTEXT_TYPE = hasSymbol ? Symbol.for("react.context") : 0xeace; + +var REACT_CONCURRENT_MODE_TYPE = hasSymbol + ? Symbol.for("react.concurrent_mode") + : 0xeacf; +var REACT_FORWARD_REF_TYPE = hasSymbol + ? Symbol.for("react.forward_ref") + : 0xead0; +var REACT_SUSPENSE_TYPE = hasSymbol ? Symbol.for("react.suspense") : 0xead1; +var REACT_MEMO_TYPE = hasSymbol ? Symbol.for("react.memo") : 0xead3; +var REACT_LAZY_TYPE = hasSymbol ? Symbol.for("react.lazy") : 0xead4; +var REACT_EVENT_COMPONENT_TYPE = hasSymbol + ? Symbol.for("react.event_component") + : 0xead5; +var REACT_EVENT_TARGET_TYPE = hasSymbol + ? Symbol.for("react.event_target") + : 0xead6; + +// React event targets +var REACT_EVENT_TARGET_TOUCH_HIT = hasSymbol + ? Symbol.for("react.event_target.touch_hit") + : 0xead7; + +var MAYBE_ITERATOR_SYMBOL = typeof Symbol === "function" && Symbol.iterator; +var FAUX_ITERATOR_SYMBOL = "@@iterator"; + +function getIteratorFn(maybeIterable) { + if (maybeIterable === null || typeof maybeIterable !== "object") { + return null; + } + var maybeIterator = + (MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL]) || + maybeIterable[FAUX_ITERATOR_SYMBOL]; + if (typeof maybeIterator === "function") { + return maybeIterator; + } + return null; +} + +var Pending = 0; +var Resolved = 1; +var Rejected = 2; + +function refineResolvedLazyComponent(lazyComponent) { + return lazyComponent._status === Resolved ? lazyComponent._result : null; +} + +// Re-export dynamic flags from the fbsource version. +var _require = require("../shims/ReactFeatureFlags"); + +var debugRenderPhaseSideEffects = _require.debugRenderPhaseSideEffects; + +var enableUserTimingAPI = true; +var enableProfilerTimer = true; +var enableSchedulerTracing = true; +var enableSuspenseServerRenderer = false; + +var debugRenderPhaseSideEffectsForStrictMode = true; + +var disableYielding = false; + +var replayFailedUnitOfWorkWithInvokeGuardedCallback = true; +var warnAboutDeprecatedLifecycles = true; +var warnAboutDeprecatedSetNativeProps = true; +var enableEventAPI = false; + +// Only used in www builds. + +function getWrappedName(outerType, innerType, wrapperName) { + var functionName = innerType.displayName || innerType.name || ""; + return ( + outerType.displayName || + (functionName !== "" ? wrapperName + "(" + functionName + ")" : wrapperName) + ); +} + +function getComponentName(type) { + if (type == null) { + // Host root, text node or just invalid type. + return null; + } + { + if (typeof type.tag === "number") { + warningWithoutStack$1( + false, + "Received an unexpected object in getComponentName(). " + + "This is likely a bug in React. Please file an issue." + ); + } + } + if (typeof type === "function") { + return type.displayName || type.name || null; + } + if (typeof type === "string") { + return type; + } + switch (type) { + case REACT_CONCURRENT_MODE_TYPE: + return "ConcurrentMode"; + case REACT_FRAGMENT_TYPE: + return "Fragment"; + case REACT_PORTAL_TYPE: + return "Portal"; + case REACT_PROFILER_TYPE: + return "Profiler"; + case REACT_STRICT_MODE_TYPE: + return "StrictMode"; + case REACT_SUSPENSE_TYPE: + return "Suspense"; + } + if (typeof type === "object") { + switch (type.$$typeof) { + case REACT_CONTEXT_TYPE: + return "Context.Consumer"; + case REACT_PROVIDER_TYPE: + return "Context.Provider"; + case REACT_FORWARD_REF_TYPE: + return getWrappedName(type, type.render, "ForwardRef"); + case REACT_MEMO_TYPE: + return getComponentName(type.type); + case REACT_LAZY_TYPE: { + var thenable = type; + var resolvedThenable = refineResolvedLazyComponent(thenable); + if (resolvedThenable) { + return getComponentName(resolvedThenable); + } + break; + } + case REACT_EVENT_COMPONENT_TYPE: { + if (enableEventAPI) { + var eventComponent = type; + var displayName = eventComponent.displayName; + if (displayName !== undefined) { + return displayName; + } + } + break; + } + case REACT_EVENT_TARGET_TYPE: { + if (enableEventAPI) { + var eventTarget = type; + if (eventTarget.type === REACT_EVENT_TARGET_TOUCH_HIT) { + return "TouchHitTarget"; + } + var _displayName = eventTarget.displayName; + if (_displayName !== undefined) { + return _displayName; + } + } + } + } + } + return null; +} + +// Don't change these two values. They're used by React Dev Tools. +var NoEffect = /* */ 0; +var PerformedWork = /* */ 1; + +// You can change the rest (and add more). +var Placement = /* */ 2; +var Update = /* */ 4; +var PlacementAndUpdate = /* */ 6; +var Deletion = /* */ 8; +var ContentReset = /* */ 16; +var Callback = /* */ 32; +var DidCapture = /* */ 64; +var Ref = /* */ 128; +var Snapshot = /* */ 256; +var Passive = /* */ 512; + +// Passive & Update & Callback & Ref & Snapshot +var LifecycleEffectMask = /* */ 932; + +// Union of all host effects +var HostEffectMask = /* */ 1023; + +var Incomplete = /* */ 1024; +var ShouldCapture = /* */ 2048; + +var ReactCurrentOwner$1 = ReactSharedInternals.ReactCurrentOwner; + +var MOUNTING = 1; +var MOUNTED = 2; +var UNMOUNTED = 3; + +function isFiberMountedImpl(fiber) { + var node = fiber; + if (!fiber.alternate) { + // If there is no alternate, this might be a new tree that isn't inserted + // yet. If it is, then it will have a pending insertion effect on it. + if ((node.effectTag & Placement) !== NoEffect) { + return MOUNTING; + } + while (node.return) { + node = node.return; + if ((node.effectTag & Placement) !== NoEffect) { + return MOUNTING; + } + } + } else { + while (node.return) { + node = node.return; + } + } + if (node.tag === HostRoot) { + // TODO: Check if this was a nested HostRoot when used with + // renderContainerIntoSubtree. + return MOUNTED; + } + // If we didn't hit the root, that means that we're in an disconnected tree + // that has been unmounted. + return UNMOUNTED; +} + +function isFiberMounted(fiber) { + return isFiberMountedImpl(fiber) === MOUNTED; +} + +function isMounted(component) { + { + var owner = ReactCurrentOwner$1.current; + if (owner !== null && owner.tag === ClassComponent) { + var ownerFiber = owner; + var instance = ownerFiber.stateNode; + !instance._warnedAboutRefsInRender + ? warningWithoutStack$1( + false, + "%s is accessing isMounted inside its render() function. " + + "render() should be a pure function of props and state. It should " + + "never access something that requires stale data from the previous " + + "render, such as refs. Move this logic to componentDidMount and " + + "componentDidUpdate instead.", + getComponentName(ownerFiber.type) || "A component" + ) + : void 0; + instance._warnedAboutRefsInRender = true; + } + } + + var fiber = get(component); + if (!fiber) { + return false; + } + return isFiberMountedImpl(fiber) === MOUNTED; +} + +function assertIsMounted(fiber) { + (function() { + if (!(isFiberMountedImpl(fiber) === MOUNTED)) { + throw ReactError("Unable to find node on an unmounted component."); + } + })(); +} + +function findCurrentFiberUsingSlowPath(fiber) { + var alternate = fiber.alternate; + if (!alternate) { + // If there is no alternate, then we only need to check if it is mounted. + var state = isFiberMountedImpl(fiber); + (function() { + if (!(state !== UNMOUNTED)) { + throw ReactError("Unable to find node on an unmounted component."); + } + })(); + if (state === MOUNTING) { + return null; + } + return fiber; + } + // If we have two possible branches, we'll walk backwards up to the root + // to see what path the root points to. On the way we may hit one of the + // special cases and we'll deal with them. + var a = fiber; + var b = alternate; + while (true) { + var parentA = a.return; + if (parentA === null) { + // We're at the root. + break; + } + var parentB = parentA.alternate; + if (parentB === null) { + // There is no alternate. This is an unusual case. Currently, it only + // happens when a Suspense component is hidden. An extra fragment fiber + // is inserted in between the Suspense fiber and its children. Skip + // over this extra fragment fiber and proceed to the next parent. + var nextParent = parentA.return; + if (nextParent !== null) { + a = b = nextParent; + continue; + } + // If there's no parent, we're at the root. + break; + } + + // If both copies of the parent fiber point to the same child, we can + // assume that the child is current. This happens when we bailout on low + // priority: the bailed out fiber's child reuses the current child. + if (parentA.child === parentB.child) { + var child = parentA.child; + while (child) { + if (child === a) { + // We've determined that A is the current branch. + assertIsMounted(parentA); + return fiber; + } + if (child === b) { + // We've determined that B is the current branch. + assertIsMounted(parentA); + return alternate; + } + child = child.sibling; + } + // We should never have an alternate for any mounting node. So the only + // way this could possibly happen is if this was unmounted, if at all. + (function() { + { + throw ReactError("Unable to find node on an unmounted component."); + } + })(); + } + + if (a.return !== b.return) { + // The return pointer of A and the return pointer of B point to different + // fibers. We assume that return pointers never criss-cross, so A must + // belong to the child set of A.return, and B must belong to the child + // set of B.return. + a = parentA; + b = parentB; + } else { + // The return pointers point to the same fiber. We'll have to use the + // default, slow path: scan the child sets of each parent alternate to see + // which child belongs to which set. + // + // Search parent A's child set + var didFindChild = false; + var _child = parentA.child; + while (_child) { + if (_child === a) { + didFindChild = true; + a = parentA; + b = parentB; + break; + } + if (_child === b) { + didFindChild = true; + b = parentA; + a = parentB; + break; + } + _child = _child.sibling; + } + if (!didFindChild) { + // Search parent B's child set + _child = parentB.child; + while (_child) { + if (_child === a) { + didFindChild = true; + a = parentB; + b = parentA; + break; + } + if (_child === b) { + didFindChild = true; + b = parentB; + a = parentA; + break; + } + _child = _child.sibling; + } + (function() { + if (!didFindChild) { + throw ReactError( + "Child was not found in either parent set. This indicates a bug in React related to the return pointer. Please file an issue." + ); + } + })(); + } + } + + (function() { + if (!(a.alternate === b)) { + throw ReactError( + "Return fibers should always be each others' alternates. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + // If the root is not a host container, we're in a disconnected tree. I.e. + // unmounted. + (function() { + if (!(a.tag === HostRoot)) { + throw ReactError("Unable to find node on an unmounted component."); + } + })(); + if (a.stateNode.current === a) { + // We've determined that A is the current branch. + return fiber; + } + // Otherwise B has to be current branch. + return alternate; +} + +function findCurrentHostFiber(parent) { + var currentParent = findCurrentFiberUsingSlowPath(parent); + if (!currentParent) { + return null; + } + + // Next we'll drill down this component to find the first HostComponent/Text. + var node = currentParent; + while (true) { + if (node.tag === HostComponent || node.tag === HostText) { + return node; + } else if (node.child) { + node.child.return = node; + node = node.child; + continue; + } + if (node === currentParent) { + return null; + } + while (!node.sibling) { + if (!node.return || node.return === currentParent) { + return null; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + // Flow needs the return null here, but ESLint complains about it. + // eslint-disable-next-line no-unreachable + return null; +} + +/** + * In the future, we should cleanup callbacks by cancelling them instead of + * using this. + */ +function mountSafeCallback_NOT_REALLY_SAFE(context, callback) { + return function() { + if (!callback) { + return undefined; + } + // This protects against createClass() components. + // We don't know if there is code depending on it. + // We intentionally don't use isMounted() because even accessing + // isMounted property on a React ES6 class will trigger a warning. + if (typeof context.__isMounted === "boolean") { + if (!context.__isMounted) { + return undefined; + } + } + + // FIXME: there used to be other branches that protected + // against unmounted host components. But RN host components don't + // define isMounted() anymore, so those checks didn't do anything. + + // They caused false positive warning noise so we removed them: + // https://github.com/facebook/react-native/issues/18868#issuecomment-413579095 + + // However, this means that the callback is NOT guaranteed to be safe + // for host components. The solution we should implement is to make + // UIManager.measure() and similar calls truly cancelable. Then we + // can change our own code calling them to cancel when something unmounts. + + return callback.apply(context, arguments); + }; +} + +function throwOnStylesProp(component, props) { + if (props.styles !== undefined) { + var owner = component._owner || null; + var name = component.constructor.displayName; + var msg = + "`styles` is not a supported property of `" + + name + + "`, did " + + "you mean `style` (singular)?"; + if (owner && owner.constructor && owner.constructor.displayName) { + msg += + "\n\nCheck the `" + + owner.constructor.displayName + + "` parent " + + " component."; + } + throw new Error(msg); + } +} + +function warnForStyleProps(props, validAttributes) { + for (var key in validAttributes.style) { + if (!(validAttributes[key] || props[key] === undefined)) { + console.error( + "You are setting the style `{ " + + key + + ": ... }` as a prop. You " + + "should nest it in a style object. " + + "E.g. `{ style: { " + + key + + ": ... } }`" + ); + } + } +} + +// Modules provided by RN: +var emptyObject = {}; + +/** + * Create a payload that contains all the updates between two sets of props. + * + * These helpers are all encapsulated into a single module, because they use + * mutation as a performance optimization which leads to subtle shared + * dependencies between the code paths. To avoid this mutable state leaking + * across modules, I've kept them isolated to this module. + */ + +// Tracks removed keys +var removedKeys = null; +var removedKeyCount = 0; + +function defaultDiffer(prevProp, nextProp) { + if (typeof nextProp !== "object" || nextProp === null) { + // Scalars have already been checked for equality + return true; + } else { + // For objects and arrays, the default diffing algorithm is a deep compare + return ReactNativePrivateInterface.deepDiffer(prevProp, nextProp); + } +} + +function restoreDeletedValuesInNestedArray( + updatePayload, + node, + validAttributes +) { + if (Array.isArray(node)) { + var i = node.length; + while (i-- && removedKeyCount > 0) { + restoreDeletedValuesInNestedArray( + updatePayload, + node[i], + validAttributes + ); + } + } else if (node && removedKeyCount > 0) { + var obj = node; + for (var propKey in removedKeys) { + if (!removedKeys[propKey]) { + continue; + } + var nextProp = obj[propKey]; + if (nextProp === undefined) { + continue; + } + + var attributeConfig = validAttributes[propKey]; + if (!attributeConfig) { + continue; // not a valid native prop + } + + if (typeof nextProp === "function") { + nextProp = true; + } + if (typeof nextProp === "undefined") { + nextProp = null; + } + + if (typeof attributeConfig !== "object") { + // case: !Object is the default case + updatePayload[propKey] = nextProp; + } else if ( + typeof attributeConfig.diff === "function" || + typeof attributeConfig.process === "function" + ) { + // case: CustomAttributeConfiguration + var nextValue = + typeof attributeConfig.process === "function" + ? attributeConfig.process(nextProp) + : nextProp; + updatePayload[propKey] = nextValue; + } + removedKeys[propKey] = false; + removedKeyCount--; + } + } +} + +function diffNestedArrayProperty( + updatePayload, + prevArray, + nextArray, + validAttributes +) { + var minLength = + prevArray.length < nextArray.length ? prevArray.length : nextArray.length; + var i = void 0; + for (i = 0; i < minLength; i++) { + // Diff any items in the array in the forward direction. Repeated keys + // will be overwritten by later values. + updatePayload = diffNestedProperty( + updatePayload, + prevArray[i], + nextArray[i], + validAttributes + ); + } + for (; i < prevArray.length; i++) { + // Clear out all remaining properties. + updatePayload = clearNestedProperty( + updatePayload, + prevArray[i], + validAttributes + ); + } + for (; i < nextArray.length; i++) { + // Add all remaining properties. + updatePayload = addNestedProperty( + updatePayload, + nextArray[i], + validAttributes + ); + } + return updatePayload; +} + +function diffNestedProperty( + updatePayload, + prevProp, + nextProp, + validAttributes +) { + if (!updatePayload && prevProp === nextProp) { + // If no properties have been added, then we can bail out quickly on object + // equality. + return updatePayload; + } + + if (!prevProp || !nextProp) { + if (nextProp) { + return addNestedProperty(updatePayload, nextProp, validAttributes); + } + if (prevProp) { + return clearNestedProperty(updatePayload, prevProp, validAttributes); + } + return updatePayload; + } + + if (!Array.isArray(prevProp) && !Array.isArray(nextProp)) { + // Both are leaves, we can diff the leaves. + return diffProperties(updatePayload, prevProp, nextProp, validAttributes); + } + + if (Array.isArray(prevProp) && Array.isArray(nextProp)) { + // Both are arrays, we can diff the arrays. + return diffNestedArrayProperty( + updatePayload, + prevProp, + nextProp, + validAttributes + ); + } + + if (Array.isArray(prevProp)) { + return diffProperties( + updatePayload, + // $FlowFixMe - We know that this is always an object when the input is. + ReactNativePrivateInterface.flattenStyle(prevProp), + // $FlowFixMe - We know that this isn't an array because of above flow. + nextProp, + validAttributes + ); + } + + return diffProperties( + updatePayload, + prevProp, + // $FlowFixMe - We know that this is always an object when the input is. + ReactNativePrivateInterface.flattenStyle(nextProp), + validAttributes + ); +} + +/** + * addNestedProperty takes a single set of props and valid attribute + * attribute configurations. It processes each prop and adds it to the + * updatePayload. + */ +function addNestedProperty(updatePayload, nextProp, validAttributes) { + if (!nextProp) { + return updatePayload; + } + + if (!Array.isArray(nextProp)) { + // Add each property of the leaf. + return addProperties(updatePayload, nextProp, validAttributes); + } + + for (var i = 0; i < nextProp.length; i++) { + // Add all the properties of the array. + updatePayload = addNestedProperty( + updatePayload, + nextProp[i], + validAttributes + ); + } + + return updatePayload; +} + +/** + * clearNestedProperty takes a single set of props and valid attributes. It + * adds a null sentinel to the updatePayload, for each prop key. + */ +function clearNestedProperty(updatePayload, prevProp, validAttributes) { + if (!prevProp) { + return updatePayload; + } + + if (!Array.isArray(prevProp)) { + // Add each property of the leaf. + return clearProperties(updatePayload, prevProp, validAttributes); + } + + for (var i = 0; i < prevProp.length; i++) { + // Add all the properties of the array. + updatePayload = clearNestedProperty( + updatePayload, + prevProp[i], + validAttributes + ); + } + return updatePayload; +} + +/** + * diffProperties takes two sets of props and a set of valid attributes + * and write to updatePayload the values that changed or were deleted. + * If no updatePayload is provided, a new one is created and returned if + * anything changed. + */ +function diffProperties(updatePayload, prevProps, nextProps, validAttributes) { + var attributeConfig = void 0; + var nextProp = void 0; + var prevProp = void 0; + + for (var propKey in nextProps) { + attributeConfig = validAttributes[propKey]; + if (!attributeConfig) { + continue; // not a valid native prop + } + + prevProp = prevProps[propKey]; + nextProp = nextProps[propKey]; + + // functions are converted to booleans as markers that the associated + // events should be sent from native. + if (typeof nextProp === "function") { + nextProp = true; + // If nextProp is not a function, then don't bother changing prevProp + // since nextProp will win and go into the updatePayload regardless. + if (typeof prevProp === "function") { + prevProp = true; + } + } + + // An explicit value of undefined is treated as a null because it overrides + // any other preceding value. + if (typeof nextProp === "undefined") { + nextProp = null; + if (typeof prevProp === "undefined") { + prevProp = null; + } + } + + if (removedKeys) { + removedKeys[propKey] = false; + } + + if (updatePayload && updatePayload[propKey] !== undefined) { + // Something else already triggered an update to this key because another + // value diffed. Since we're now later in the nested arrays our value is + // more important so we need to calculate it and override the existing + // value. It doesn't matter if nothing changed, we'll set it anyway. + + // Pattern match on: attributeConfig + if (typeof attributeConfig !== "object") { + // case: !Object is the default case + updatePayload[propKey] = nextProp; + } else if ( + typeof attributeConfig.diff === "function" || + typeof attributeConfig.process === "function" + ) { + // case: CustomAttributeConfiguration + var nextValue = + typeof attributeConfig.process === "function" + ? attributeConfig.process(nextProp) + : nextProp; + updatePayload[propKey] = nextValue; + } + continue; + } + + if (prevProp === nextProp) { + continue; // nothing changed + } + + // Pattern match on: attributeConfig + if (typeof attributeConfig !== "object") { + // case: !Object is the default case + if (defaultDiffer(prevProp, nextProp)) { + // a normal leaf has changed + (updatePayload || (updatePayload = {}))[propKey] = nextProp; + } + } else if ( + typeof attributeConfig.diff === "function" || + typeof attributeConfig.process === "function" + ) { + // case: CustomAttributeConfiguration + var shouldUpdate = + prevProp === undefined || + (typeof attributeConfig.diff === "function" + ? attributeConfig.diff(prevProp, nextProp) + : defaultDiffer(prevProp, nextProp)); + if (shouldUpdate) { + var _nextValue = + typeof attributeConfig.process === "function" + ? attributeConfig.process(nextProp) + : nextProp; + (updatePayload || (updatePayload = {}))[propKey] = _nextValue; + } + } else { + // default: fallthrough case when nested properties are defined + removedKeys = null; + removedKeyCount = 0; + // We think that attributeConfig is not CustomAttributeConfiguration at + // this point so we assume it must be AttributeConfiguration. + updatePayload = diffNestedProperty( + updatePayload, + prevProp, + nextProp, + attributeConfig + ); + if (removedKeyCount > 0 && updatePayload) { + restoreDeletedValuesInNestedArray( + updatePayload, + nextProp, + attributeConfig + ); + removedKeys = null; + } + } + } + + // Also iterate through all the previous props to catch any that have been + // removed and make sure native gets the signal so it can reset them to the + // default. + for (var _propKey in prevProps) { + if (nextProps[_propKey] !== undefined) { + continue; // we've already covered this key in the previous pass + } + attributeConfig = validAttributes[_propKey]; + if (!attributeConfig) { + continue; // not a valid native prop + } + + if (updatePayload && updatePayload[_propKey] !== undefined) { + // This was already updated to a diff result earlier. + continue; + } + + prevProp = prevProps[_propKey]; + if (prevProp === undefined) { + continue; // was already empty anyway + } + // Pattern match on: attributeConfig + if ( + typeof attributeConfig !== "object" || + typeof attributeConfig.diff === "function" || + typeof attributeConfig.process === "function" + ) { + // case: CustomAttributeConfiguration | !Object + // Flag the leaf property for removal by sending a sentinel. + (updatePayload || (updatePayload = {}))[_propKey] = null; + if (!removedKeys) { + removedKeys = {}; + } + if (!removedKeys[_propKey]) { + removedKeys[_propKey] = true; + removedKeyCount++; + } + } else { + // default: + // This is a nested attribute configuration where all the properties + // were removed so we need to go through and clear out all of them. + updatePayload = clearNestedProperty( + updatePayload, + prevProp, + attributeConfig + ); + } + } + return updatePayload; +} + +/** + * addProperties adds all the valid props to the payload after being processed. + */ +function addProperties(updatePayload, props, validAttributes) { + // TODO: Fast path + return diffProperties(updatePayload, emptyObject, props, validAttributes); +} + +/** + * clearProperties clears all the previous props by adding a null sentinel + * to the payload for each valid key. + */ +function clearProperties(updatePayload, prevProps, validAttributes) { + // TODO: Fast path + return diffProperties(updatePayload, prevProps, emptyObject, validAttributes); +} + +function create(props, validAttributes) { + return addProperties( + null, // updatePayload + props, + validAttributes + ); +} + +function diff(prevProps, nextProps, validAttributes) { + return diffProperties( + null, // updatePayload + prevProps, + nextProps, + validAttributes + ); +} + +// Use to restore controlled state after a change event has fired. + +var restoreImpl = null; +var restoreTarget = null; +var restoreQueue = null; + +function restoreStateOfTarget(target) { + // We perform this translation at the end of the event loop so that we + // always receive the correct fiber here + var internalInstance = getInstanceFromNode(target); + if (!internalInstance) { + // Unmounted + return; + } + (function() { + if (!(typeof restoreImpl === "function")) { + throw ReactError( + "setRestoreImplementation() needs to be called to handle a target for controlled events. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + var props = getFiberCurrentPropsFromNode(internalInstance.stateNode); + restoreImpl(internalInstance.stateNode, internalInstance.type, props); +} + +function needsStateRestore() { + return restoreTarget !== null || restoreQueue !== null; +} + +function restoreStateIfNeeded() { + if (!restoreTarget) { + return; + } + var target = restoreTarget; + var queuedTargets = restoreQueue; + restoreTarget = null; + restoreQueue = null; + + restoreStateOfTarget(target); + if (queuedTargets) { + for (var i = 0; i < queuedTargets.length; i++) { + restoreStateOfTarget(queuedTargets[i]); + } + } +} + +// Used as a way to call batchedUpdates when we don't have a reference to +// the renderer. Such as when we're dispatching events or if third party +// libraries need to call batchedUpdates. Eventually, this API will go away when +// everything is batched by default. We'll then have a similar API to opt-out of +// scheduled work and instead do synchronous work. + +// Defaults +var _batchedUpdatesImpl = function(fn, bookkeeping) { + return fn(bookkeeping); +}; +var _flushInteractiveUpdatesImpl = function() {}; + +var isBatching = false; +function batchedUpdates(fn, bookkeeping) { + if (isBatching) { + // If we are currently inside another batch, we need to wait until it + // fully completes before restoring state. + return fn(bookkeeping); + } + isBatching = true; + try { + return _batchedUpdatesImpl(fn, bookkeeping); + } finally { + // Here we wait until all updates have propagated, which is important + // when using controlled components within layers: + // https://github.com/facebook/react/issues/1698 + // Then we restore state of any controlled component. + isBatching = false; + var controlledComponentsHavePendingUpdates = needsStateRestore(); + if (controlledComponentsHavePendingUpdates) { + // If a controlled event was fired, we may need to restore the state of + // the DOM node back to the controlled value. This is necessary when React + // bails out of the update without touching the DOM. + _flushInteractiveUpdatesImpl(); + restoreStateIfNeeded(); + } + } +} + +function setBatchingImplementation( + batchedUpdatesImpl, + interactiveUpdatesImpl, + flushInteractiveUpdatesImpl +) { + _batchedUpdatesImpl = batchedUpdatesImpl; + _flushInteractiveUpdatesImpl = flushInteractiveUpdatesImpl; +} + +function dispatchEvent(target, topLevelType, nativeEvent) { + var targetFiber = target; + batchedUpdates(function() { + runExtractedPluginEventsInBatch( + topLevelType, + targetFiber, + nativeEvent, + nativeEvent.target + ); + }); + // React Native doesn't use ReactControlledComponent but if it did, here's + // where it would do it. +} + +// Renderers that don't support mutation +// can re-export everything from this module. + +function shim() { + (function() { + { + throw ReactError( + "The current renderer does not support mutation. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); +} + +// Mutation (when unsupported) +var supportsMutation = false; +var appendChild = shim; +var appendChildToContainer = shim; +var commitTextUpdate = shim; +var commitMount = shim; +var commitUpdate = shim; +var insertBefore = shim; +var insertInContainerBefore = shim; +var removeChild = shim; +var removeChildFromContainer = shim; +var resetTextContent = shim; +var hideInstance = shim; +var hideTextInstance = shim; +var unhideInstance = shim; +var unhideTextInstance = shim; + +// Renderers that don't support hydration +// can re-export everything from this module. + +function shim$1() { + (function() { + { + throw ReactError( + "The current renderer does not support hydration. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); +} + +// Hydration (when unsupported) + +var supportsHydration = false; +var canHydrateInstance = shim$1; +var canHydrateTextInstance = shim$1; +var canHydrateSuspenseInstance = shim$1; +var isSuspenseInstancePending = shim$1; +var isSuspenseInstanceFallback = shim$1; +var registerSuspenseInstanceRetry = shim$1; +var getNextHydratableSibling = shim$1; +var getFirstHydratableChild = shim$1; +var hydrateInstance = shim$1; +var hydrateTextInstance = shim$1; +var getNextHydratableInstanceAfterSuspenseInstance = shim$1; +var clearSuspenseBoundary = shim$1; +var clearSuspenseBoundaryFromContainer = shim$1; +var didNotMatchHydratedContainerTextInstance = shim$1; +var didNotMatchHydratedTextInstance = shim$1; +var didNotHydrateContainerInstance = shim$1; +var didNotHydrateInstance = shim$1; +var didNotFindHydratableContainerInstance = shim$1; +var didNotFindHydratableContainerTextInstance = shim$1; +var didNotFindHydratableContainerSuspenseInstance = shim$1; +var didNotFindHydratableInstance = shim$1; +var didNotFindHydratableTextInstance = shim$1; +var didNotFindHydratableSuspenseInstance = shim$1; + +function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } +} + +// Modules provided by RN: +var _nativeFabricUIManage = nativeFabricUIManager; +var createNode = _nativeFabricUIManage.createNode; +var cloneNode = _nativeFabricUIManage.cloneNode; +var cloneNodeWithNewChildren = _nativeFabricUIManage.cloneNodeWithNewChildren; +var cloneNodeWithNewChildrenAndProps = + _nativeFabricUIManage.cloneNodeWithNewChildrenAndProps; +var cloneNodeWithNewProps = _nativeFabricUIManage.cloneNodeWithNewProps; +var createChildNodeSet = _nativeFabricUIManage.createChildSet; +var appendChildNode = _nativeFabricUIManage.appendChild; +var appendChildNodeToSet = _nativeFabricUIManage.appendChildToSet; +var completeRoot = _nativeFabricUIManage.completeRoot; +var registerEventHandler = _nativeFabricUIManage.registerEventHandler; +var fabricMeasure = _nativeFabricUIManage.measure; +var fabricMeasureInWindow = _nativeFabricUIManage.measureInWindow; +var fabricMeasureLayout = _nativeFabricUIManage.measureLayout; +var getViewConfigForType = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.get; + +// Counter for uniquely identifying views. +// % 10 === 1 means it is a rootTag. +// % 2 === 0 means it is a Fabric tag. +// This means that they never overlap. + +var nextReactTag = 2; + +// TODO: Remove this conditional once all changes have propagated. +if (registerEventHandler) { + /** + * Register the event emitter with the native bridge + */ + registerEventHandler(dispatchEvent); +} + +/** + * This is used for refs on host components. + */ + +var ReactFabricHostComponent = (function() { + function ReactFabricHostComponent( + tag, + viewConfig, + props, + internalInstanceHandle + ) { + _classCallCheck(this, ReactFabricHostComponent); + + this._nativeTag = tag; + this.viewConfig = viewConfig; + this.currentProps = props; + this._internalInstanceHandle = internalInstanceHandle; + } + + ReactFabricHostComponent.prototype.blur = function blur() { + ReactNativePrivateInterface.TextInputState.blurTextInput(this._nativeTag); + }; + + ReactFabricHostComponent.prototype.focus = function focus() { + ReactNativePrivateInterface.TextInputState.focusTextInput(this._nativeTag); + }; + + ReactFabricHostComponent.prototype.measure = function measure(callback) { + fabricMeasure( + this._internalInstanceHandle.stateNode.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + }; + + ReactFabricHostComponent.prototype.measureInWindow = function measureInWindow( + callback + ) { + fabricMeasureInWindow( + this._internalInstanceHandle.stateNode.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + }; + + ReactFabricHostComponent.prototype.measureLayout = function measureLayout( + relativeToNativeNode, + onSuccess, + onFail /* currently unused */ + ) { + if ( + typeof relativeToNativeNode === "number" || + !(relativeToNativeNode instanceof ReactFabricHostComponent) + ) { + warningWithoutStack$1( + false, + "Warning: ref.measureLayout must be called with a ref to a native component." + ); + + return; + } + + fabricMeasureLayout( + this._internalInstanceHandle.stateNode.node, + relativeToNativeNode._internalInstanceHandle.stateNode.node, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + ); + }; + + ReactFabricHostComponent.prototype.setNativeProps = function setNativeProps( + nativeProps + ) { + warningWithoutStack$1( + false, + "Warning: setNativeProps is not currently supported in Fabric" + ); + + return; + }; + + return ReactFabricHostComponent; +})(); + +function appendInitialChild(parentInstance, child) { + appendChildNode(parentInstance.node, child.node); +} + +function createInstance( + type, + props, + rootContainerInstance, + hostContext, + internalInstanceHandle +) { + var tag = nextReactTag; + nextReactTag += 2; + + var viewConfig = getViewConfigForType(type); + + { + for (var key in viewConfig.validAttributes) { + if (props.hasOwnProperty(key)) { + ReactNativePrivateInterface.deepFreezeAndThrowOnMutationInDev( + props[key] + ); + } + } + } + + var updatePayload = create(props, viewConfig.validAttributes); + + var node = createNode( + tag, // reactTag + viewConfig.uiViewClassName, // viewName + rootContainerInstance, // rootTag + updatePayload, // props + internalInstanceHandle // internalInstanceHandle + ); + + var component = new ReactFabricHostComponent( + tag, + viewConfig, + props, + internalInstanceHandle + ); + + return { + node: node, + canonical: component + }; +} + +function createTextInstance( + text, + rootContainerInstance, + hostContext, + internalInstanceHandle +) { + (function() { + if (!hostContext.isInAParentText) { + throw ReactError( + "Text strings must be rendered within a component." + ); + } + })(); + + var tag = nextReactTag; + nextReactTag += 2; + + var node = createNode( + tag, // reactTag + "RCTRawText", // viewName + rootContainerInstance, // rootTag + { text: text }, // props + internalInstanceHandle // instance handle + ); + + return { + node: node + }; +} + +function finalizeInitialChildren( + parentInstance, + type, + props, + rootContainerInstance, + hostContext +) { + return false; +} + +function getRootHostContext(rootContainerInstance) { + return { isInAParentText: false }; +} + +function getChildHostContext(parentHostContext, type, rootContainerInstance) { + var prevIsInAParentText = parentHostContext.isInAParentText; + var isInAParentText = + type === "AndroidTextInput" || // Android + type === "RCTMultilineTextInputView" || // iOS + type === "RCTSinglelineTextInputView" || // iOS + type === "RCTText" || + type === "RCTVirtualText"; + + if (prevIsInAParentText !== isInAParentText) { + return { isInAParentText: isInAParentText }; + } else { + return parentHostContext; + } +} + +function getChildHostContextForEventComponent(parentHostContext) { + // TODO: add getChildHostContextForEventComponent implementation + return parentHostContext; +} + +function getChildHostContextForEventTarget(parentHostContext, type) { + // TODO: add getChildHostContextForEventTarget implementation + return parentHostContext; +} + +function getPublicInstance(instance) { + return instance.canonical; +} + +function prepareForCommit(containerInfo) { + // Noop +} + +function prepareUpdate( + instance, + type, + oldProps, + newProps, + rootContainerInstance, + hostContext +) { + var viewConfig = instance.canonical.viewConfig; + var updatePayload = diff(oldProps, newProps, viewConfig.validAttributes); + // TODO: If the event handlers have changed, we need to update the current props + // in the commit phase but there is no host config hook to do it yet. + // So instead we hack it by updating it in the render phase. + instance.canonical.currentProps = newProps; + return updatePayload; +} + +function resetAfterCommit(containerInfo) { + // Noop +} + +function shouldDeprioritizeSubtree(type, props) { + return false; +} + +function shouldSetTextContent(type, props) { + // TODO (bvaughn) Revisit this decision. + // Always returning false simplifies the createInstance() implementation, + // But creates an additional child Fiber for raw text children. + // No additional native views are created though. + // It's not clear to me which is better so I'm deferring for now. + // More context @ github.com/facebook/react/pull/8560#discussion_r92111303 + return false; +} + +// The Fabric renderer is secondary to the existing React Native renderer. +var isPrimaryRenderer = false; + +var scheduleTimeout = setTimeout; +var cancelTimeout = clearTimeout; +var noTimeout = -1; + +// ------------------- +// Persistence +// ------------------- + +var supportsPersistence = true; + +function cloneInstance( + instance, + updatePayload, + type, + oldProps, + newProps, + internalInstanceHandle, + keepChildren, + recyclableInstance +) { + var node = instance.node; + var clone = void 0; + if (keepChildren) { + if (updatePayload !== null) { + clone = cloneNodeWithNewProps(node, updatePayload); + } else { + clone = cloneNode(node); + } + } else { + if (updatePayload !== null) { + clone = cloneNodeWithNewChildrenAndProps(node, updatePayload); + } else { + clone = cloneNodeWithNewChildren(node); + } + } + return { + node: clone, + canonical: instance.canonical + }; +} + +function cloneHiddenInstance(instance, type, props, internalInstanceHandle) { + var viewConfig = instance.canonical.viewConfig; + var node = instance.node; + var updatePayload = create( + { style: { display: "none" } }, + viewConfig.validAttributes + ); + return { + node: cloneNodeWithNewProps(node, updatePayload), + canonical: instance.canonical + }; +} + +function cloneHiddenTextInstance(instance, text, internalInstanceHandle) { + throw new Error("Not yet implemented."); +} + +function createContainerChildSet(container) { + return createChildNodeSet(container); +} + +function appendChildToContainerChildSet(childSet, child) { + appendChildNodeToSet(childSet, child.node); +} + +function finalizeContainerChildren(container, newChildren) { + completeRoot(container, newChildren); +} + +function mountEventComponent(eventComponentInstance) { + throw new Error("Not yet implemented."); +} + +function updateEventComponent(eventComponentInstance) { + throw new Error("Not yet implemented."); +} + +function unmountEventComponent(eventComponentInstance) { + throw new Error("Not yet implemented."); +} + +function getEventTargetChildElement(type, props) { + throw new Error("Not yet implemented."); +} + +function handleEventTarget( + type, + props, + rootContainerInstance, + internalInstanceHandle +) { + throw new Error("Not yet implemented."); +} + +function commitEventTarget(type, props, instance, parentInstance) { + throw new Error("Not yet implemented."); +} + +var BEFORE_SLASH_RE = /^(.*)[\\\/]/; + +var describeComponentFrame = function(name, source, ownerName) { + var sourceInfo = ""; + if (source) { + var path = source.fileName; + var fileName = path.replace(BEFORE_SLASH_RE, ""); + { + // In DEV, include code for a common special case: + // prefer "folder/index.js" instead of just "index.js". + if (/^index\./.test(fileName)) { + var match = path.match(BEFORE_SLASH_RE); + if (match) { + var pathBeforeSlash = match[1]; + if (pathBeforeSlash) { + var folderName = pathBeforeSlash.replace(BEFORE_SLASH_RE, ""); + fileName = folderName + "/" + fileName; + } + } + } + } + sourceInfo = " (at " + fileName + ":" + source.lineNumber + ")"; + } else if (ownerName) { + sourceInfo = " (created by " + ownerName + ")"; + } + return "\n in " + (name || "Unknown") + sourceInfo; +}; + +var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; + +function describeFiber(fiber) { + switch (fiber.tag) { + case HostRoot: + case HostPortal: + case HostText: + case Fragment: + case ContextProvider: + case ContextConsumer: + return ""; + default: + var owner = fiber._debugOwner; + var source = fiber._debugSource; + var name = getComponentName(fiber.type); + var ownerName = null; + if (owner) { + ownerName = getComponentName(owner.type); + } + return describeComponentFrame(name, source, ownerName); + } +} + +function getStackByFiberInDevAndProd(workInProgress) { + var info = ""; + var node = workInProgress; + do { + info += describeFiber(node); + node = node.return; + } while (node); + return info; +} + +var current = null; +var phase = null; + +function getCurrentFiberOwnerNameInDevOrNull() { + { + if (current === null) { + return null; + } + var owner = current._debugOwner; + if (owner !== null && typeof owner !== "undefined") { + return getComponentName(owner.type); + } + } + return null; +} + +function getCurrentFiberStackInDev() { + { + if (current === null) { + return ""; + } + // Safe because if current fiber exists, we are reconciling, + // and it is guaranteed to be the work-in-progress version. + return getStackByFiberInDevAndProd(current); + } + return ""; +} + +function resetCurrentFiber() { + { + ReactDebugCurrentFrame.getCurrentStack = null; + current = null; + phase = null; + } +} + +function setCurrentFiber(fiber) { + { + ReactDebugCurrentFrame.getCurrentStack = getCurrentFiberStackInDev; + current = fiber; + phase = null; + } +} + +function setCurrentPhase(lifeCyclePhase) { + { + phase = lifeCyclePhase; + } +} + +// Prefix measurements so that it's possible to filter them. +// Longer prefixes are hard to read in DevTools. +var reactEmoji = "\u269B"; +var warningEmoji = "\u26D4"; +var supportsUserTiming = + typeof performance !== "undefined" && + typeof performance.mark === "function" && + typeof performance.clearMarks === "function" && + typeof performance.measure === "function" && + typeof performance.clearMeasures === "function"; + +// Keep track of current fiber so that we know the path to unwind on pause. +// TODO: this looks the same as nextUnitOfWork in scheduler. Can we unify them? +var currentFiber = null; +// If we're in the middle of user code, which fiber and method is it? +// Reusing `currentFiber` would be confusing for this because user code fiber +// can change during commit phase too, but we don't need to unwind it (since +// lifecycles in the commit phase don't resemble a tree). +var currentPhase = null; +var currentPhaseFiber = null; +// Did lifecycle hook schedule an update? This is often a performance problem, +// so we will keep track of it, and include it in the report. +// Track commits caused by cascading updates. +var isCommitting = false; +var hasScheduledUpdateInCurrentCommit = false; +var hasScheduledUpdateInCurrentPhase = false; +var commitCountInCurrentWorkLoop = 0; +var effectCountInCurrentCommit = 0; +var isWaitingForCallback = false; +// During commits, we only show a measurement once per method name +// to avoid stretch the commit phase with measurement overhead. +var labelsInCurrentCommit = new Set(); + +var formatMarkName = function(markName) { + return reactEmoji + " " + markName; +}; + +var formatLabel = function(label, warning) { + var prefix = warning ? warningEmoji + " " : reactEmoji + " "; + var suffix = warning ? " Warning: " + warning : ""; + return "" + prefix + label + suffix; +}; + +var beginMark = function(markName) { + performance.mark(formatMarkName(markName)); +}; + +var clearMark = function(markName) { + performance.clearMarks(formatMarkName(markName)); +}; + +var endMark = function(label, markName, warning) { + var formattedMarkName = formatMarkName(markName); + var formattedLabel = formatLabel(label, warning); + try { + performance.measure(formattedLabel, formattedMarkName); + } catch (err) {} + // If previous mark was missing for some reason, this will throw. + // This could only happen if React crashed in an unexpected place earlier. + // Don't pile on with more errors. + + // Clear marks immediately to avoid growing buffer. + performance.clearMarks(formattedMarkName); + performance.clearMeasures(formattedLabel); +}; + +var getFiberMarkName = function(label, debugID) { + return label + " (#" + debugID + ")"; +}; + +var getFiberLabel = function(componentName, isMounted, phase) { + if (phase === null) { + // These are composite component total time measurements. + return componentName + " [" + (isMounted ? "update" : "mount") + "]"; + } else { + // Composite component methods. + return componentName + "." + phase; + } +}; + +var beginFiberMark = function(fiber, phase) { + var componentName = getComponentName(fiber.type) || "Unknown"; + var debugID = fiber._debugID; + var isMounted = fiber.alternate !== null; + var label = getFiberLabel(componentName, isMounted, phase); + + if (isCommitting && labelsInCurrentCommit.has(label)) { + // During the commit phase, we don't show duplicate labels because + // there is a fixed overhead for every measurement, and we don't + // want to stretch the commit phase beyond necessary. + return false; + } + labelsInCurrentCommit.add(label); + + var markName = getFiberMarkName(label, debugID); + beginMark(markName); + return true; +}; + +var clearFiberMark = function(fiber, phase) { + var componentName = getComponentName(fiber.type) || "Unknown"; + var debugID = fiber._debugID; + var isMounted = fiber.alternate !== null; + var label = getFiberLabel(componentName, isMounted, phase); + var markName = getFiberMarkName(label, debugID); + clearMark(markName); +}; + +var endFiberMark = function(fiber, phase, warning) { + var componentName = getComponentName(fiber.type) || "Unknown"; + var debugID = fiber._debugID; + var isMounted = fiber.alternate !== null; + var label = getFiberLabel(componentName, isMounted, phase); + var markName = getFiberMarkName(label, debugID); + endMark(label, markName, warning); +}; + +var shouldIgnoreFiber = function(fiber) { + // Host components should be skipped in the timeline. + // We could check typeof fiber.type, but does this work with RN? + switch (fiber.tag) { + case HostRoot: + case HostComponent: + case HostText: + case HostPortal: + case Fragment: + case ContextProvider: + case ContextConsumer: + case Mode: + return true; + default: + return false; + } +}; + +var clearPendingPhaseMeasurement = function() { + if (currentPhase !== null && currentPhaseFiber !== null) { + clearFiberMark(currentPhaseFiber, currentPhase); + } + currentPhaseFiber = null; + currentPhase = null; + hasScheduledUpdateInCurrentPhase = false; +}; + +var pauseTimers = function() { + // Stops all currently active measurements so that they can be resumed + // if we continue in a later deferred loop from the same unit of work. + var fiber = currentFiber; + while (fiber) { + if (fiber._debugIsCurrentlyTiming) { + endFiberMark(fiber, null, null); + } + fiber = fiber.return; + } +}; + +var resumeTimersRecursively = function(fiber) { + if (fiber.return !== null) { + resumeTimersRecursively(fiber.return); + } + if (fiber._debugIsCurrentlyTiming) { + beginFiberMark(fiber, null); + } +}; + +var resumeTimers = function() { + // Resumes all measurements that were active during the last deferred loop. + if (currentFiber !== null) { + resumeTimersRecursively(currentFiber); + } +}; + +function recordEffect() { + if (enableUserTimingAPI) { + effectCountInCurrentCommit++; + } +} + +function recordScheduleUpdate() { + if (enableUserTimingAPI) { + if (isCommitting) { + hasScheduledUpdateInCurrentCommit = true; + } + if ( + currentPhase !== null && + currentPhase !== "componentWillMount" && + currentPhase !== "componentWillReceiveProps" + ) { + hasScheduledUpdateInCurrentPhase = true; + } + } +} + +function startRequestCallbackTimer() { + if (enableUserTimingAPI) { + if (supportsUserTiming && !isWaitingForCallback) { + isWaitingForCallback = true; + beginMark("(Waiting for async callback...)"); + } + } +} + +function stopRequestCallbackTimer(didExpire) { + if (enableUserTimingAPI) { + if (supportsUserTiming) { + isWaitingForCallback = false; + var warning = didExpire + ? "Update expired; will flush synchronously" + : null; + endMark( + "(Waiting for async callback...)", + "(Waiting for async callback...)", + warning + ); + } + } +} + +function startWorkTimer(fiber) { + if (enableUserTimingAPI) { + if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { + return; + } + // If we pause, this is the fiber to unwind from. + currentFiber = fiber; + if (!beginFiberMark(fiber, null)) { + return; + } + fiber._debugIsCurrentlyTiming = true; + } +} + +function cancelWorkTimer(fiber) { + if (enableUserTimingAPI) { + if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { + return; + } + // Remember we shouldn't complete measurement for this fiber. + // Otherwise flamechart will be deep even for small updates. + fiber._debugIsCurrentlyTiming = false; + clearFiberMark(fiber, null); + } +} + +function stopWorkTimer(fiber) { + if (enableUserTimingAPI) { + if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { + return; + } + // If we pause, its parent is the fiber to unwind from. + currentFiber = fiber.return; + if (!fiber._debugIsCurrentlyTiming) { + return; + } + fiber._debugIsCurrentlyTiming = false; + endFiberMark(fiber, null, null); + } +} + +function stopFailedWorkTimer(fiber) { + if (enableUserTimingAPI) { + if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { + return; + } + // If we pause, its parent is the fiber to unwind from. + currentFiber = fiber.return; + if (!fiber._debugIsCurrentlyTiming) { + return; + } + fiber._debugIsCurrentlyTiming = false; + var warning = + fiber.tag === SuspenseComponent || + fiber.tag === DehydratedSuspenseComponent + ? "Rendering was suspended" + : "An error was thrown inside this error boundary"; + endFiberMark(fiber, null, warning); + } +} + +function startPhaseTimer(fiber, phase) { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + clearPendingPhaseMeasurement(); + if (!beginFiberMark(fiber, phase)) { + return; + } + currentPhaseFiber = fiber; + currentPhase = phase; + } +} + +function stopPhaseTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + if (currentPhase !== null && currentPhaseFiber !== null) { + var warning = hasScheduledUpdateInCurrentPhase + ? "Scheduled a cascading update" + : null; + endFiberMark(currentPhaseFiber, currentPhase, warning); + } + currentPhase = null; + currentPhaseFiber = null; + } +} + +function startWorkLoopTimer(nextUnitOfWork) { + if (enableUserTimingAPI) { + currentFiber = nextUnitOfWork; + if (!supportsUserTiming) { + return; + } + commitCountInCurrentWorkLoop = 0; + // This is top level call. + // Any other measurements are performed within. + beginMark("(React Tree Reconciliation)"); + // Resume any measurements that were in progress during the last loop. + resumeTimers(); + } +} + +function stopWorkLoopTimer(interruptedBy, didCompleteRoot) { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + var warning = null; + if (interruptedBy !== null) { + if (interruptedBy.tag === HostRoot) { + warning = "A top-level update interrupted the previous render"; + } else { + var componentName = getComponentName(interruptedBy.type) || "Unknown"; + warning = + "An update to " + componentName + " interrupted the previous render"; + } + } else if (commitCountInCurrentWorkLoop > 1) { + warning = "There were cascading updates"; + } + commitCountInCurrentWorkLoop = 0; + var label = didCompleteRoot + ? "(React Tree Reconciliation: Completed Root)" + : "(React Tree Reconciliation: Yielded)"; + // Pause any measurements until the next loop. + pauseTimers(); + endMark(label, "(React Tree Reconciliation)", warning); + } +} + +function startCommitTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + isCommitting = true; + hasScheduledUpdateInCurrentCommit = false; + labelsInCurrentCommit.clear(); + beginMark("(Committing Changes)"); + } +} + +function stopCommitTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + + var warning = null; + if (hasScheduledUpdateInCurrentCommit) { + warning = "Lifecycle hook scheduled a cascading update"; + } else if (commitCountInCurrentWorkLoop > 0) { + warning = "Caused by a cascading update in earlier commit"; + } + hasScheduledUpdateInCurrentCommit = false; + commitCountInCurrentWorkLoop++; + isCommitting = false; + labelsInCurrentCommit.clear(); + + endMark("(Committing Changes)", "(Committing Changes)", warning); + } +} + +function startCommitSnapshotEffectsTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + effectCountInCurrentCommit = 0; + beginMark("(Committing Snapshot Effects)"); + } +} + +function stopCommitSnapshotEffectsTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + var count = effectCountInCurrentCommit; + effectCountInCurrentCommit = 0; + endMark( + "(Committing Snapshot Effects: " + count + " Total)", + "(Committing Snapshot Effects)", + null + ); + } +} + +function startCommitHostEffectsTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + effectCountInCurrentCommit = 0; + beginMark("(Committing Host Effects)"); + } +} + +function stopCommitHostEffectsTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + var count = effectCountInCurrentCommit; + effectCountInCurrentCommit = 0; + endMark( + "(Committing Host Effects: " + count + " Total)", + "(Committing Host Effects)", + null + ); + } +} + +function startCommitLifeCyclesTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + effectCountInCurrentCommit = 0; + beginMark("(Calling Lifecycle Methods)"); + } +} + +function stopCommitLifeCyclesTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + var count = effectCountInCurrentCommit; + effectCountInCurrentCommit = 0; + endMark( + "(Calling Lifecycle Methods: " + count + " Total)", + "(Calling Lifecycle Methods)", + null + ); + } +} + +var valueStack = []; + +var fiberStack = void 0; + +{ + fiberStack = []; +} + +var index = -1; + +function createCursor(defaultValue) { + return { + current: defaultValue + }; +} + +function pop(cursor, fiber) { + if (index < 0) { + { + warningWithoutStack$1(false, "Unexpected pop."); + } + return; + } + + { + if (fiber !== fiberStack[index]) { + warningWithoutStack$1(false, "Unexpected Fiber popped."); + } + } + + cursor.current = valueStack[index]; + + valueStack[index] = null; + + { + fiberStack[index] = null; + } + + index--; +} + +function push(cursor, value, fiber) { + index++; + + valueStack[index] = cursor.current; + + { + fiberStack[index] = fiber; + } + + cursor.current = value; +} + +var warnedAboutMissingGetChildContext = void 0; + +{ + warnedAboutMissingGetChildContext = {}; +} + +var emptyContextObject = {}; +{ + Object.freeze(emptyContextObject); +} + +// A cursor to the current merged context object on the stack. +var contextStackCursor = createCursor(emptyContextObject); +// A cursor to a boolean indicating whether the context has changed. +var didPerformWorkStackCursor = createCursor(false); +// Keep track of the previous context object that was on the stack. +// We use this to get access to the parent context after we have already +// pushed the next context provider, and now need to merge their contexts. +var previousContext = emptyContextObject; + +function getUnmaskedContext( + workInProgress, + Component, + didPushOwnContextIfProvider +) { + if (didPushOwnContextIfProvider && isContextProvider(Component)) { + // If the fiber is a context provider itself, when we read its context + // we may have already pushed its own child context on the stack. A context + // provider should not "see" its own child context. Therefore we read the + // previous (parent) context instead for a context provider. + return previousContext; + } + return contextStackCursor.current; +} + +function cacheContext(workInProgress, unmaskedContext, maskedContext) { + var instance = workInProgress.stateNode; + instance.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext; + instance.__reactInternalMemoizedMaskedChildContext = maskedContext; +} + +function getMaskedContext(workInProgress, unmaskedContext) { + var type = workInProgress.type; + var contextTypes = type.contextTypes; + if (!contextTypes) { + return emptyContextObject; + } + + // Avoid recreating masked context unless unmasked context has changed. + // Failing to do this will result in unnecessary calls to componentWillReceiveProps. + // This may trigger infinite loops if componentWillReceiveProps calls setState. + var instance = workInProgress.stateNode; + if ( + instance && + instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext + ) { + return instance.__reactInternalMemoizedMaskedChildContext; + } + + var context = {}; + for (var key in contextTypes) { + context[key] = unmaskedContext[key]; + } + + { + var name = getComponentName(type) || "Unknown"; + checkPropTypes( + contextTypes, + context, + "context", + name, + getCurrentFiberStackInDev + ); + } + + // Cache unmasked context so we can avoid recreating masked context unless necessary. + // Context is created before the class component is instantiated so check for instance. + if (instance) { + cacheContext(workInProgress, unmaskedContext, context); + } + + return context; +} + +function hasContextChanged() { + return didPerformWorkStackCursor.current; +} + +function isContextProvider(type) { + var childContextTypes = type.childContextTypes; + return childContextTypes !== null && childContextTypes !== undefined; +} + +function popContext(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); +} + +function popTopLevelContextObject(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); +} + +function pushTopLevelContextObject(fiber, context, didChange) { + (function() { + if (!(contextStackCursor.current === emptyContextObject)) { + throw ReactError( + "Unexpected context found on stack. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + + push(contextStackCursor, context, fiber); + push(didPerformWorkStackCursor, didChange, fiber); +} + +function processChildContext(fiber, type, parentContext) { + var instance = fiber.stateNode; + var childContextTypes = type.childContextTypes; + + // TODO (bvaughn) Replace this behavior with an invariant() in the future. + // It has only been added in Fiber to match the (unintentional) behavior in Stack. + if (typeof instance.getChildContext !== "function") { + { + var componentName = getComponentName(type) || "Unknown"; + + if (!warnedAboutMissingGetChildContext[componentName]) { + warnedAboutMissingGetChildContext[componentName] = true; + warningWithoutStack$1( + false, + "%s.childContextTypes is specified but there is no getChildContext() method " + + "on the instance. You can either define getChildContext() on %s or remove " + + "childContextTypes from it.", + componentName, + componentName + ); + } + } + return parentContext; + } + + var childContext = void 0; + { + setCurrentPhase("getChildContext"); + } + startPhaseTimer(fiber, "getChildContext"); + childContext = instance.getChildContext(); + stopPhaseTimer(); + { + setCurrentPhase(null); + } + for (var contextKey in childContext) { + (function() { + if (!(contextKey in childContextTypes)) { + throw ReactError( + (getComponentName(type) || "Unknown") + + '.getChildContext(): key "' + + contextKey + + '" is not defined in childContextTypes.' + ); + } + })(); + } + { + var name = getComponentName(type) || "Unknown"; + checkPropTypes( + childContextTypes, + childContext, + "child context", + name, + // In practice, there is one case in which we won't get a stack. It's when + // somebody calls unstable_renderSubtreeIntoContainer() and we process + // context from the parent component instance. The stack will be missing + // because it's outside of the reconciliation, and so the pointer has not + // been set. This is rare and doesn't matter. We'll also remove that API. + getCurrentFiberStackInDev + ); + } + + return Object.assign({}, parentContext, childContext); +} + +function pushContextProvider(workInProgress) { + var instance = workInProgress.stateNode; + // We push the context as early as possible to ensure stack integrity. + // If the instance does not exist yet, we will push null at first, + // and replace it on the stack later when invalidating the context. + var memoizedMergedChildContext = + (instance && instance.__reactInternalMemoizedMergedChildContext) || + emptyContextObject; + + // Remember the parent context so we can merge with it later. + // Inherit the parent's did-perform-work value to avoid inadvertently blocking updates. + previousContext = contextStackCursor.current; + push(contextStackCursor, memoizedMergedChildContext, workInProgress); + push( + didPerformWorkStackCursor, + didPerformWorkStackCursor.current, + workInProgress + ); + + return true; +} + +function invalidateContextProvider(workInProgress, type, didChange) { + var instance = workInProgress.stateNode; + (function() { + if (!instance) { + throw ReactError( + "Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + + if (didChange) { + // Merge parent and own context. + // Skip this if we're not updating due to sCU. + // This avoids unnecessarily recomputing memoized values. + var mergedContext = processChildContext( + workInProgress, + type, + previousContext + ); + instance.__reactInternalMemoizedMergedChildContext = mergedContext; + + // Replace the old (or empty) context with the new one. + // It is important to unwind the context in the reverse order. + pop(didPerformWorkStackCursor, workInProgress); + pop(contextStackCursor, workInProgress); + // Now push the new context and mark that it has changed. + push(contextStackCursor, mergedContext, workInProgress); + push(didPerformWorkStackCursor, didChange, workInProgress); + } else { + pop(didPerformWorkStackCursor, workInProgress); + push(didPerformWorkStackCursor, didChange, workInProgress); + } +} + +function findCurrentUnmaskedContext(fiber) { + // Currently this is only used with renderSubtreeIntoContainer; not sure if it + // makes sense elsewhere + (function() { + if (!(isFiberMounted(fiber) && fiber.tag === ClassComponent)) { + throw ReactError( + "Expected subtree parent to be a mounted class component. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + + var node = fiber; + do { + switch (node.tag) { + case HostRoot: + return node.stateNode.context; + case ClassComponent: { + var Component = node.type; + if (isContextProvider(Component)) { + return node.stateNode.__reactInternalMemoizedMergedChildContext; + } + break; + } + } + node = node.return; + } while (node !== null); + (function() { + { + throw ReactError( + "Found unexpected detached subtree parent. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); +} + +var onCommitFiberRoot = null; +var onCommitFiberUnmount = null; +var hasLoggedError = false; + +function catchErrors(fn) { + return function(arg) { + try { + return fn(arg); + } catch (err) { + if (true && !hasLoggedError) { + hasLoggedError = true; + warningWithoutStack$1( + false, + "React DevTools encountered an error: %s", + err + ); + } + } + }; +} + +var isDevToolsPresent = typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== "undefined"; + +function injectInternals(internals) { + if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === "undefined") { + // No DevTools + return false; + } + var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__; + if (hook.isDisabled) { + // This isn't a real property on the hook, but it can be set to opt out + // of DevTools integration and associated warnings and logs. + // https://github.com/facebook/react/issues/3877 + return true; + } + if (!hook.supportsFiber) { + { + warningWithoutStack$1( + false, + "The installed version of React DevTools is too old and will not work " + + "with the current version of React. Please update React DevTools. " + + "https://fb.me/react-devtools" + ); + } + // DevTools exists, even though it doesn't support Fiber. + return true; + } + try { + var rendererID = hook.inject(internals); + // We have successfully injected, so now it is safe to set up hooks. + onCommitFiberRoot = catchErrors(function(root) { + return hook.onCommitFiberRoot(rendererID, root); + }); + onCommitFiberUnmount = catchErrors(function(fiber) { + return hook.onCommitFiberUnmount(rendererID, fiber); + }); + } catch (err) { + // Catch all errors because it is unsafe to throw during initialization. + { + warningWithoutStack$1( + false, + "React DevTools encountered an error: %s.", + err + ); + } + } + // DevTools exists + return true; +} + +function onCommitRoot(root) { + if (typeof onCommitFiberRoot === "function") { + onCommitFiberRoot(root); + } +} + +function onCommitUnmount(fiber) { + if (typeof onCommitFiberUnmount === "function") { + onCommitFiberUnmount(fiber); + } +} + +// Max 31 bit integer. The max integer size in V8 for 32-bit systems. +// Math.pow(2, 30) - 1 +// 0b111111111111111111111111111111 +var MAX_SIGNED_31_BIT_INT = 1073741823; + +// Intentionally not named imports because Rollup would use dynamic dispatch for +// CommonJS interop named imports. +var Scheduler_runWithPriority = Scheduler.unstable_runWithPriority; +var Scheduler_scheduleCallback = Scheduler.unstable_scheduleCallback; +var Scheduler_cancelCallback = Scheduler.unstable_cancelCallback; +var Scheduler_shouldYield = Scheduler.unstable_shouldYield; +var Scheduler_now = Scheduler.unstable_now; +var Scheduler_getCurrentPriorityLevel = + Scheduler.unstable_getCurrentPriorityLevel; +var Scheduler_ImmediatePriority = Scheduler.unstable_ImmediatePriority; +var Scheduler_UserBlockingPriority = Scheduler.unstable_UserBlockingPriority; +var Scheduler_NormalPriority = Scheduler.unstable_NormalPriority; +var Scheduler_LowPriority = Scheduler.unstable_LowPriority; +var Scheduler_IdlePriority = Scheduler.unstable_IdlePriority; + +if (enableSchedulerTracing) { + // Provide explicit error message when production+profiling bundle of e.g. + // react-dom is used with production (non-profiling) bundle of + // scheduler/tracing + (function() { + if ( + !( + tracing.__interactionsRef != null && + tracing.__interactionsRef.current != null + ) + ) { + throw ReactError( + "It is not supported to run the profiling version of a renderer (for example, `react-dom/profiling`) without also replacing the `scheduler/tracing` module with `scheduler/tracing-profiling`. Your bundler might have a setting for aliasing both modules. Learn more at http://fb.me/react-profiling" + ); + } + })(); +} + +var fakeCallbackNode = {}; + +// Except for NoPriority, these correspond to Scheduler priorities. We use +// ascending numbers so we can compare them like numbers. They start at 90 to +// avoid clashing with Scheduler's priorities. +var ImmediatePriority = 99; +var UserBlockingPriority = 98; +var NormalPriority = 97; +var LowPriority = 96; +var IdlePriority = 95; +// NoPriority is the absence of priority. Also React-only. + +var shouldYield = disableYielding + ? function() { + return false; + } // Never yield when `disableYielding` is on + : Scheduler_shouldYield; + +var immediateQueue = null; +var immediateQueueCallbackNode = null; +var isFlushingImmediate = false; +var initialTimeMs = Scheduler_now(); + +// If the initial timestamp is reasonably small, use Scheduler's `now` directly. +// This will be the case for modern browsers that support `performance.now`. In +// older browsers, Scheduler falls back to `Date.now`, which returns a Unix +// timestamp. In that case, subtract the module initialization time to simulate +// the behavior of performance.now and keep our times small enough to fit +// within 32 bits. +// TODO: Consider lifting this into Scheduler. +var now = + initialTimeMs < 10000 + ? Scheduler_now + : function() { + return Scheduler_now() - initialTimeMs; + }; + +function getCurrentPriorityLevel() { + switch (Scheduler_getCurrentPriorityLevel()) { + case Scheduler_ImmediatePriority: + return ImmediatePriority; + case Scheduler_UserBlockingPriority: + return UserBlockingPriority; + case Scheduler_NormalPriority: + return NormalPriority; + case Scheduler_LowPriority: + return LowPriority; + case Scheduler_IdlePriority: + return IdlePriority; + default: + (function() { + { + throw ReactError("Unknown priority level."); + } + })(); + } +} + +function reactPriorityToSchedulerPriority(reactPriorityLevel) { + switch (reactPriorityLevel) { + case ImmediatePriority: + return Scheduler_ImmediatePriority; + case UserBlockingPriority: + return Scheduler_UserBlockingPriority; + case NormalPriority: + return Scheduler_NormalPriority; + case LowPriority: + return Scheduler_LowPriority; + case IdlePriority: + return Scheduler_IdlePriority; + default: + (function() { + { + throw ReactError("Unknown priority level."); + } + })(); + } +} + +function runWithPriority(reactPriorityLevel, fn) { + var priorityLevel = reactPriorityToSchedulerPriority(reactPriorityLevel); + return Scheduler_runWithPriority(priorityLevel, fn); +} + +function scheduleCallback(reactPriorityLevel, callback, options) { + if (reactPriorityLevel === ImmediatePriority) { + // Push this callback into an internal queue. We'll flush these either in + // the next tick, or earlier if something calls `flushImmediateQueue`. + if (immediateQueue === null) { + immediateQueue = [callback]; + // Flush the queue in the next tick, at the earliest. + immediateQueueCallbackNode = Scheduler_scheduleCallback( + Scheduler_ImmediatePriority, + flushImmediateQueueImpl + ); + } else { + // Push onto existing queue. Don't need to schedule a callback because + // we already scheduled one when we created the queue. + immediateQueue.push(callback); + } + return fakeCallbackNode; + } + // Otherwise pass through to Scheduler. + var priorityLevel = reactPriorityToSchedulerPriority(reactPriorityLevel); + return Scheduler_scheduleCallback(priorityLevel, callback, options); +} + +function cancelCallback(callbackNode) { + if (callbackNode !== fakeCallbackNode) { + Scheduler_cancelCallback(callbackNode); + } +} + +function flushImmediateQueue() { + if (immediateQueueCallbackNode !== null) { + Scheduler_cancelCallback(immediateQueueCallbackNode); + } + flushImmediateQueueImpl(); +} + +function flushImmediateQueueImpl() { + if (!isFlushingImmediate && immediateQueue !== null) { + // Prevent re-entrancy. + isFlushingImmediate = true; + var i = 0; + try { + var _isSync = true; + for (; i < immediateQueue.length; i++) { + var callback = immediateQueue[i]; + do { + callback = callback(_isSync); + } while (callback !== null); + } + immediateQueue = null; + } catch (error) { + // If something throws, leave the remaining callbacks on the queue. + if (immediateQueue !== null) { + immediateQueue = immediateQueue.slice(i + 1); + } + // Resume flushing in the next tick + Scheduler_scheduleCallback( + Scheduler_ImmediatePriority, + flushImmediateQueue + ); + throw error; + } finally { + isFlushingImmediate = false; + } + } +} + +var NoWork = 0; +var Never = 1; +var Sync = MAX_SIGNED_31_BIT_INT; + +var UNIT_SIZE = 10; +var MAGIC_NUMBER_OFFSET = MAX_SIGNED_31_BIT_INT - 1; + +// 1 unit of expiration time represents 10ms. +function msToExpirationTime(ms) { + // Always add an offset so that we don't clash with the magic number for NoWork. + return MAGIC_NUMBER_OFFSET - ((ms / UNIT_SIZE) | 0); +} + +function expirationTimeToMs(expirationTime) { + return (MAGIC_NUMBER_OFFSET - expirationTime) * UNIT_SIZE; +} + +function ceiling(num, precision) { + return (((num / precision) | 0) + 1) * precision; +} + +function computeExpirationBucket(currentTime, expirationInMs, bucketSizeMs) { + return ( + MAGIC_NUMBER_OFFSET - + ceiling( + MAGIC_NUMBER_OFFSET - currentTime + expirationInMs / UNIT_SIZE, + bucketSizeMs / UNIT_SIZE + ) + ); +} + +// TODO: This corresponds to Scheduler's NormalPriority, not LowPriority. Update +// the names to reflect. +var LOW_PRIORITY_EXPIRATION = 5000; +var LOW_PRIORITY_BATCH_SIZE = 250; + +function computeAsyncExpiration(currentTime) { + return computeExpirationBucket( + currentTime, + LOW_PRIORITY_EXPIRATION, + LOW_PRIORITY_BATCH_SIZE + ); +} + +// Same as computeAsyncExpiration but without the bucketing logic. This is +// used to compute timestamps instead of actual expiration times. +function computeAsyncExpirationNoBucket(currentTime) { + return currentTime - LOW_PRIORITY_EXPIRATION / UNIT_SIZE; +} + +// We intentionally set a higher expiration time for interactive updates in +// dev than in production. +// +// If the main thread is being blocked so long that you hit the expiration, +// it's a problem that could be solved with better scheduling. +// +// People will be more likely to notice this and fix it with the long +// expiration time in development. +// +// In production we opt for better UX at the risk of masking scheduling +// problems, by expiring fast. +var HIGH_PRIORITY_EXPIRATION = 500; +var HIGH_PRIORITY_BATCH_SIZE = 100; + +function computeInteractiveExpiration(currentTime) { + return computeExpirationBucket( + currentTime, + HIGH_PRIORITY_EXPIRATION, + HIGH_PRIORITY_BATCH_SIZE + ); +} + +function inferPriorityFromExpirationTime(currentTime, expirationTime) { + if (expirationTime === Sync) { + return ImmediatePriority; + } + if (expirationTime === Never) { + return IdlePriority; + } + var msUntil = + expirationTimeToMs(expirationTime) - expirationTimeToMs(currentTime); + if (msUntil <= 0) { + return ImmediatePriority; + } + if (msUntil <= HIGH_PRIORITY_EXPIRATION + HIGH_PRIORITY_BATCH_SIZE) { + return UserBlockingPriority; + } + if (msUntil <= LOW_PRIORITY_EXPIRATION + LOW_PRIORITY_BATCH_SIZE) { + return NormalPriority; + } + + // TODO: Handle LowPriority + + // Assume anything lower has idle priority + return IdlePriority; +} + +var NoContext = 0; +var ConcurrentMode = 1; +var StrictMode = 2; +var ProfileMode = 4; + +var hasBadMapPolyfill = void 0; + +{ + hasBadMapPolyfill = false; + try { + var nonExtensibleObject = Object.preventExtensions({}); + var testMap = new Map([[nonExtensibleObject, null]]); + var testSet = new Set([nonExtensibleObject]); + // This is necessary for Rollup to not consider these unused. + // https://github.com/rollup/rollup/issues/1771 + // TODO: we can remove these if Rollup fixes the bug. + testMap.set(0, 0); + testSet.add(0); + } catch (e) { + // TODO: Consider warning about bad polyfills + hasBadMapPolyfill = true; + } +} + +// A Fiber is work on a Component that needs to be done or was done. There can +// be more than one per component. + +var debugCounter = void 0; + +{ + debugCounter = 1; +} + +function FiberNode(tag, pendingProps, key, mode) { + // Instance + this.tag = tag; + this.key = key; + this.elementType = null; + this.type = null; + this.stateNode = null; + + // Fiber + this.return = null; + this.child = null; + this.sibling = null; + this.index = 0; + + this.ref = null; + + this.pendingProps = pendingProps; + this.memoizedProps = null; + this.updateQueue = null; + this.memoizedState = null; + this.contextDependencies = null; + + this.mode = mode; + + // Effects + this.effectTag = NoEffect; + this.nextEffect = null; + + this.firstEffect = null; + this.lastEffect = null; + + this.expirationTime = NoWork; + this.childExpirationTime = NoWork; + + this.alternate = null; + + if (enableProfilerTimer) { + // Note: The following is done to avoid a v8 performance cliff. + // + // Initializing the fields below to smis and later updating them with + // double values will cause Fibers to end up having separate shapes. + // This behavior/bug has something to do with Object.preventExtension(). + // Fortunately this only impacts DEV builds. + // Unfortunately it makes React unusably slow for some applications. + // To work around this, initialize the fields below with doubles. + // + // Learn more about this here: + // https://github.com/facebook/react/issues/14365 + // https://bugs.chromium.org/p/v8/issues/detail?id=8538 + this.actualDuration = Number.NaN; + this.actualStartTime = Number.NaN; + this.selfBaseDuration = Number.NaN; + this.treeBaseDuration = Number.NaN; + + // It's okay to replace the initial doubles with smis after initialization. + // This won't trigger the performance cliff mentioned above, + // and it simplifies other profiler code (including DevTools). + this.actualDuration = 0; + this.actualStartTime = -1; + this.selfBaseDuration = 0; + this.treeBaseDuration = 0; + } + + { + this._debugID = debugCounter++; + this._debugSource = null; + this._debugOwner = null; + this._debugIsCurrentlyTiming = false; + this._debugHookTypes = null; + if (!hasBadMapPolyfill && typeof Object.preventExtensions === "function") { + Object.preventExtensions(this); + } + } +} + +// This is a constructor function, rather than a POJO constructor, still +// please ensure we do the following: +// 1) Nobody should add any instance methods on this. Instance methods can be +// more difficult to predict when they get optimized and they are almost +// never inlined properly in static compilers. +// 2) Nobody should rely on `instanceof Fiber` for type testing. We should +// always know when it is a fiber. +// 3) We might want to experiment with using numeric keys since they are easier +// to optimize in a non-JIT environment. +// 4) We can easily go from a constructor to a createFiber object literal if that +// is faster. +// 5) It should be easy to port this to a C struct and keep a C implementation +// compatible. +var createFiber = function(tag, pendingProps, key, mode) { + // $FlowFixMe: the shapes are exact here but Flow doesn't like constructors + return new FiberNode(tag, pendingProps, key, mode); +}; + +function shouldConstruct(Component) { + var prototype = Component.prototype; + return !!(prototype && prototype.isReactComponent); +} + +function isSimpleFunctionComponent(type) { + return ( + typeof type === "function" && + !shouldConstruct(type) && + type.defaultProps === undefined + ); +} + +function resolveLazyComponentTag(Component) { + if (typeof Component === "function") { + return shouldConstruct(Component) ? ClassComponent : FunctionComponent; + } else if (Component !== undefined && Component !== null) { + var $$typeof = Component.$$typeof; + if ($$typeof === REACT_FORWARD_REF_TYPE) { + return ForwardRef; + } + if ($$typeof === REACT_MEMO_TYPE) { + return MemoComponent; + } + } + return IndeterminateComponent; +} + +// This is used to create an alternate fiber to do work on. +function createWorkInProgress(current, pendingProps, expirationTime) { + var workInProgress = current.alternate; + if (workInProgress === null) { + // We use a double buffering pooling technique because we know that we'll + // only ever need at most two versions of a tree. We pool the "other" unused + // node that we're free to reuse. This is lazily created to avoid allocating + // extra objects for things that are never updated. It also allow us to + // reclaim the extra memory if needed. + workInProgress = createFiber( + current.tag, + pendingProps, + current.key, + current.mode + ); + workInProgress.elementType = current.elementType; + workInProgress.type = current.type; + workInProgress.stateNode = current.stateNode; + + { + // DEV-only fields + workInProgress._debugID = current._debugID; + workInProgress._debugSource = current._debugSource; + workInProgress._debugOwner = current._debugOwner; + workInProgress._debugHookTypes = current._debugHookTypes; + } + + workInProgress.alternate = current; + current.alternate = workInProgress; + } else { + workInProgress.pendingProps = pendingProps; + + // We already have an alternate. + // Reset the effect tag. + workInProgress.effectTag = NoEffect; + + // The effect list is no longer valid. + workInProgress.nextEffect = null; + workInProgress.firstEffect = null; + workInProgress.lastEffect = null; + + if (enableProfilerTimer) { + // We intentionally reset, rather than copy, actualDuration & actualStartTime. + // This prevents time from endlessly accumulating in new commits. + // This has the downside of resetting values for different priority renders, + // But works for yielding (the common case) and should support resuming. + workInProgress.actualDuration = 0; + workInProgress.actualStartTime = -1; + } + } + + workInProgress.childExpirationTime = current.childExpirationTime; + workInProgress.expirationTime = current.expirationTime; + + workInProgress.child = current.child; + workInProgress.memoizedProps = current.memoizedProps; + workInProgress.memoizedState = current.memoizedState; + workInProgress.updateQueue = current.updateQueue; + workInProgress.contextDependencies = current.contextDependencies; + + // These will be overridden during the parent's reconciliation + workInProgress.sibling = current.sibling; + workInProgress.index = current.index; + workInProgress.ref = current.ref; + + if (enableProfilerTimer) { + workInProgress.selfBaseDuration = current.selfBaseDuration; + workInProgress.treeBaseDuration = current.treeBaseDuration; + } + + return workInProgress; +} + +function createHostRootFiber(isConcurrent) { + var mode = isConcurrent ? ConcurrentMode | StrictMode : NoContext; + + if (enableProfilerTimer && isDevToolsPresent) { + // Always collect profile timings when DevTools are present. + // This enables DevTools to start capturing timing at any point– + // Without some nodes in the tree having empty base times. + mode |= ProfileMode; + } + + return createFiber(HostRoot, null, null, mode); +} + +function createFiberFromTypeAndProps( + type, // React$ElementType + key, + pendingProps, + owner, + mode, + expirationTime +) { + var fiber = void 0; + + var fiberTag = IndeterminateComponent; + // The resolved type is set if we know what the final type will be. I.e. it's not lazy. + var resolvedType = type; + if (typeof type === "function") { + if (shouldConstruct(type)) { + fiberTag = ClassComponent; + } + } else if (typeof type === "string") { + fiberTag = HostComponent; + } else { + getTag: switch (type) { + case REACT_FRAGMENT_TYPE: + return createFiberFromFragment( + pendingProps.children, + mode, + expirationTime, + key + ); + case REACT_CONCURRENT_MODE_TYPE: + return createFiberFromMode( + pendingProps, + mode | ConcurrentMode | StrictMode, + expirationTime, + key + ); + case REACT_STRICT_MODE_TYPE: + return createFiberFromMode( + pendingProps, + mode | StrictMode, + expirationTime, + key + ); + case REACT_PROFILER_TYPE: + return createFiberFromProfiler(pendingProps, mode, expirationTime, key); + case REACT_SUSPENSE_TYPE: + return createFiberFromSuspense(pendingProps, mode, expirationTime, key); + default: { + if (typeof type === "object" && type !== null) { + switch (type.$$typeof) { + case REACT_PROVIDER_TYPE: + fiberTag = ContextProvider; + break getTag; + case REACT_CONTEXT_TYPE: + // This is a consumer + fiberTag = ContextConsumer; + break getTag; + case REACT_FORWARD_REF_TYPE: + fiberTag = ForwardRef; + break getTag; + case REACT_MEMO_TYPE: + fiberTag = MemoComponent; + break getTag; + case REACT_LAZY_TYPE: + fiberTag = LazyComponent; + resolvedType = null; + break getTag; + case REACT_EVENT_COMPONENT_TYPE: + if (enableEventAPI) { + return createFiberFromEventComponent( + type, + pendingProps, + mode, + expirationTime, + key + ); + } + break; + case REACT_EVENT_TARGET_TYPE: + if (enableEventAPI) { + return createFiberFromEventTarget( + type, + pendingProps, + mode, + expirationTime, + key + ); + } + break; + } + } + var info = ""; + { + if ( + type === undefined || + (typeof type === "object" && + type !== null && + Object.keys(type).length === 0) + ) { + info += + " You likely forgot to export your component from the file " + + "it's defined in, or you might have mixed up default and " + + "named imports."; + } + var ownerName = owner ? getComponentName(owner.type) : null; + if (ownerName) { + info += "\n\nCheck the render method of `" + ownerName + "`."; + } + } + (function() { + { + throw ReactError( + "Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: " + + (type == null ? type : typeof type) + + "." + + info + ); + } + })(); + } + } + } + + fiber = createFiber(fiberTag, pendingProps, key, mode); + fiber.elementType = type; + fiber.type = resolvedType; + fiber.expirationTime = expirationTime; + + return fiber; +} + +function createFiberFromElement(element, mode, expirationTime) { + var owner = null; + { + owner = element._owner; + } + var type = element.type; + var key = element.key; + var pendingProps = element.props; + var fiber = createFiberFromTypeAndProps( + type, + key, + pendingProps, + owner, + mode, + expirationTime + ); + { + fiber._debugSource = element._source; + fiber._debugOwner = element._owner; + } + return fiber; +} + +function createFiberFromFragment(elements, mode, expirationTime, key) { + var fiber = createFiber(Fragment, elements, key, mode); + fiber.expirationTime = expirationTime; + return fiber; +} + +function createFiberFromEventComponent( + eventComponent, + pendingProps, + mode, + expirationTime, + key +) { + var fiber = createFiber(EventComponent, pendingProps, key, mode); + fiber.elementType = eventComponent; + fiber.type = eventComponent; + fiber.expirationTime = expirationTime; + return fiber; +} + +function createFiberFromEventTarget( + eventTarget, + pendingProps, + mode, + expirationTime, + key +) { + var fiber = createFiber(EventTarget, pendingProps, key, mode); + fiber.elementType = eventTarget; + fiber.type = eventTarget; + fiber.expirationTime = expirationTime; + // Store latest props + fiber.stateNode = { + props: pendingProps + }; + return fiber; +} + +function createFiberFromProfiler(pendingProps, mode, expirationTime, key) { + { + if ( + typeof pendingProps.id !== "string" || + typeof pendingProps.onRender !== "function" + ) { + warningWithoutStack$1( + false, + 'Profiler must specify an "id" string and "onRender" function as props' + ); + } + } + + var fiber = createFiber(Profiler, pendingProps, key, mode | ProfileMode); + // TODO: The Profiler fiber shouldn't have a type. It has a tag. + fiber.elementType = REACT_PROFILER_TYPE; + fiber.type = REACT_PROFILER_TYPE; + fiber.expirationTime = expirationTime; + + return fiber; +} + +function createFiberFromMode(pendingProps, mode, expirationTime, key) { + var fiber = createFiber(Mode, pendingProps, key, mode); + + // TODO: The Mode fiber shouldn't have a type. It has a tag. + var type = + (mode & ConcurrentMode) === NoContext + ? REACT_STRICT_MODE_TYPE + : REACT_CONCURRENT_MODE_TYPE; + fiber.elementType = type; + fiber.type = type; + + fiber.expirationTime = expirationTime; + return fiber; +} + +function createFiberFromSuspense(pendingProps, mode, expirationTime, key) { + var fiber = createFiber(SuspenseComponent, pendingProps, key, mode); + + // TODO: The SuspenseComponent fiber shouldn't have a type. It has a tag. + var type = REACT_SUSPENSE_TYPE; + fiber.elementType = type; + fiber.type = type; + + fiber.expirationTime = expirationTime; + return fiber; +} + +function createFiberFromText(content, mode, expirationTime) { + var fiber = createFiber(HostText, content, null, mode); + fiber.expirationTime = expirationTime; + return fiber; +} + +function createFiberFromHostInstanceForDeletion() { + var fiber = createFiber(HostComponent, null, null, NoContext); + // TODO: These should not need a type. + fiber.elementType = "DELETED"; + fiber.type = "DELETED"; + return fiber; +} + +function createFiberFromPortal(portal, mode, expirationTime) { + var pendingProps = portal.children !== null ? portal.children : []; + var fiber = createFiber(HostPortal, pendingProps, portal.key, mode); + fiber.expirationTime = expirationTime; + fiber.stateNode = { + containerInfo: portal.containerInfo, + pendingChildren: null, // Used by persistent updates + implementation: portal.implementation + }; + return fiber; +} + +// Used for stashing WIP properties to replay failed work in DEV. +function assignFiberPropertiesInDEV(target, source) { + if (target === null) { + // This Fiber's initial properties will always be overwritten. + // We only use a Fiber to ensure the same hidden class so DEV isn't slow. + target = createFiber(IndeterminateComponent, null, null, NoContext); + } + + // This is intentionally written as a list of all properties. + // We tried to use Object.assign() instead but this is called in + // the hottest path, and Object.assign() was too slow: + // https://github.com/facebook/react/issues/12502 + // This code is DEV-only so size is not a concern. + + target.tag = source.tag; + target.key = source.key; + target.elementType = source.elementType; + target.type = source.type; + target.stateNode = source.stateNode; + target.return = source.return; + target.child = source.child; + target.sibling = source.sibling; + target.index = source.index; + target.ref = source.ref; + target.pendingProps = source.pendingProps; + target.memoizedProps = source.memoizedProps; + target.updateQueue = source.updateQueue; + target.memoizedState = source.memoizedState; + target.contextDependencies = source.contextDependencies; + target.mode = source.mode; + target.effectTag = source.effectTag; + target.nextEffect = source.nextEffect; + target.firstEffect = source.firstEffect; + target.lastEffect = source.lastEffect; + target.expirationTime = source.expirationTime; + target.childExpirationTime = source.childExpirationTime; + target.alternate = source.alternate; + if (enableProfilerTimer) { + target.actualDuration = source.actualDuration; + target.actualStartTime = source.actualStartTime; + target.selfBaseDuration = source.selfBaseDuration; + target.treeBaseDuration = source.treeBaseDuration; + } + target._debugID = source._debugID; + target._debugSource = source._debugSource; + target._debugOwner = source._debugOwner; + target._debugIsCurrentlyTiming = source._debugIsCurrentlyTiming; + target._debugHookTypes = source._debugHookTypes; + return target; +} + +// TODO: This should be lifted into the renderer. + +// The following attributes are only used by interaction tracing builds. +// They enable interactions to be associated with their async work, +// And expose interaction metadata to the React DevTools Profiler plugin. +// Note that these attributes are only defined when the enableSchedulerTracing flag is enabled. + +// Exported FiberRoot type includes all properties, +// To avoid requiring potentially error-prone :any casts throughout the project. +// Profiling properties are only safe to access in profiling builds (when enableSchedulerTracing is true). +// The types are defined separately within this file to ensure they stay in sync. +// (We don't have to use an inline :any cast when enableSchedulerTracing is disabled.) + +function FiberRootNode(containerInfo, hydrate) { + this.current = null; + this.containerInfo = containerInfo; + this.pendingChildren = null; + this.pingCache = null; + this.pendingCommitExpirationTime = NoWork; + this.finishedWork = null; + this.timeoutHandle = noTimeout; + this.context = null; + this.pendingContext = null; + this.hydrate = hydrate; + this.firstBatch = null; + this.callbackNode = null; + this.callbackExpirationTime = NoWork; + this.firstPendingTime = NoWork; + this.lastPendingTime = NoWork; + this.pingTime = NoWork; + + if (enableSchedulerTracing) { + this.interactionThreadID = tracing.unstable_getThreadID(); + this.memoizedInteractions = new Set(); + this.pendingInteractionMap = new Map(); + } +} + +function createFiberRoot(containerInfo, isConcurrent, hydrate) { + var root = new FiberRootNode(containerInfo, hydrate); + + // Cyclic construction. This cheats the type system right now because + // stateNode is any. + var uninitializedFiber = createHostRootFiber(isConcurrent); + root.current = uninitializedFiber; + uninitializedFiber.stateNode = root; + + return root; +} + +/** + * Similar to invariant but only logs a warning if the condition is not met. + * This can be used to log issues in development environments in critical + * paths. Removing the logging code for production environments will keep the + * same logic and follow the same code paths. + */ + +var warning = warningWithoutStack$1; + +{ + warning = function(condition, format) { + if (condition) { + return; + } + var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; + var stack = ReactDebugCurrentFrame.getStackAddendum(); + // eslint-disable-next-line react-internal/warning-and-invariant-args + + for ( + var _len = arguments.length, + args = Array(_len > 2 ? _len - 2 : 0), + _key = 2; + _key < _len; + _key++ + ) { + args[_key - 2] = arguments[_key]; + } + + warningWithoutStack$1.apply( + undefined, + [false, format + "%s"].concat(args, [stack]) + ); + }; +} + +var warning$1 = warning; + +/** + * inlined Object.is polyfill to avoid requiring consumers ship their own + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is + */ +function is(x, y) { + return ( + (x === y && (x !== 0 || 1 / x === 1 / y)) || (x !== x && y !== y) // eslint-disable-line no-self-compare + ); +} + +var hasOwnProperty = Object.prototype.hasOwnProperty; + +/** + * Performs equality by iterating through keys on an object and returning false + * when any key has values which are not strictly equal between the arguments. + * Returns true when the values of all keys are strictly equal. + */ +function shallowEqual(objA, objB) { + if (is(objA, objB)) { + return true; + } + + if ( + typeof objA !== "object" || + objA === null || + typeof objB !== "object" || + objB === null + ) { + return false; + } + + var keysA = Object.keys(objA); + var keysB = Object.keys(objB); + + if (keysA.length !== keysB.length) { + return false; + } + + // Test for A's keys different from B. + for (var i = 0; i < keysA.length; i++) { + if ( + !hasOwnProperty.call(objB, keysA[i]) || + !is(objA[keysA[i]], objB[keysA[i]]) + ) { + return false; + } + } + + return true; +} + +/** + * Forked from fbjs/warning: + * https://github.com/facebook/fbjs/blob/e66ba20ad5be433eb54423f2b097d829324d9de6/packages/fbjs/src/__forks__/warning.js + * + * Only change is we use console.warn instead of console.error, + * and do nothing when 'console' is not supported. + * This really simplifies the code. + * --- + * Similar to invariant but only logs a warning if the condition is not met. + * This can be used to log issues in development environments in critical + * paths. Removing the logging code for production environments will keep the + * same logic and follow the same code paths. + */ + +var lowPriorityWarning = function() {}; + +{ + var printWarning = function(format) { + for ( + var _len = arguments.length, + args = Array(_len > 1 ? _len - 1 : 0), + _key = 1; + _key < _len; + _key++ + ) { + args[_key - 1] = arguments[_key]; + } + + var argIndex = 0; + var message = + "Warning: " + + format.replace(/%s/g, function() { + return args[argIndex++]; + }); + if (typeof console !== "undefined") { + console.warn(message); + } + try { + // --- Welcome to debugging React --- + // This error was thrown as a convenience so that you can use this stack + // to find the callsite that caused this warning to fire. + throw new Error(message); + } catch (x) {} + }; + + lowPriorityWarning = function(condition, format) { + if (format === undefined) { + throw new Error( + "`lowPriorityWarning(condition, format, ...args)` requires a warning " + + "message argument" + ); + } + if (!condition) { + for ( + var _len2 = arguments.length, + args = Array(_len2 > 2 ? _len2 - 2 : 0), + _key2 = 2; + _key2 < _len2; + _key2++ + ) { + args[_key2 - 2] = arguments[_key2]; + } + + printWarning.apply(undefined, [format].concat(args)); + } + }; +} + +var lowPriorityWarning$1 = lowPriorityWarning; + +var ReactStrictModeWarnings = { + discardPendingWarnings: function() {}, + flushPendingDeprecationWarnings: function() {}, + flushPendingUnsafeLifecycleWarnings: function() {}, + recordDeprecationWarnings: function(fiber, instance) {}, + recordUnsafeLifecycleWarnings: function(fiber, instance) {}, + recordLegacyContextWarning: function(fiber, instance) {}, + flushLegacyContextWarning: function() {} +}; + +{ + var LIFECYCLE_SUGGESTIONS = { + UNSAFE_componentWillMount: "componentDidMount", + UNSAFE_componentWillReceiveProps: "static getDerivedStateFromProps", + UNSAFE_componentWillUpdate: "componentDidUpdate" + }; + + var pendingComponentWillMountWarnings = []; + var pendingComponentWillReceivePropsWarnings = []; + var pendingComponentWillUpdateWarnings = []; + var pendingUnsafeLifecycleWarnings = new Map(); + var pendingLegacyContextWarning = new Map(); + + // Tracks components we have already warned about. + var didWarnAboutDeprecatedLifecycles = new Set(); + var didWarnAboutUnsafeLifecycles = new Set(); + var didWarnAboutLegacyContext = new Set(); + + var setToSortedString = function(set) { + var array = []; + set.forEach(function(value) { + array.push(value); + }); + return array.sort().join(", "); + }; + + ReactStrictModeWarnings.discardPendingWarnings = function() { + pendingComponentWillMountWarnings = []; + pendingComponentWillReceivePropsWarnings = []; + pendingComponentWillUpdateWarnings = []; + pendingUnsafeLifecycleWarnings = new Map(); + pendingLegacyContextWarning = new Map(); + }; + + ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = function() { + pendingUnsafeLifecycleWarnings.forEach(function( + lifecycleWarningsMap, + strictRoot + ) { + var lifecyclesWarningMessages = []; + + Object.keys(lifecycleWarningsMap).forEach(function(lifecycle) { + var lifecycleWarnings = lifecycleWarningsMap[lifecycle]; + if (lifecycleWarnings.length > 0) { + var componentNames = new Set(); + lifecycleWarnings.forEach(function(fiber) { + componentNames.add(getComponentName(fiber.type) || "Component"); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + + var formatted = lifecycle.replace("UNSAFE_", ""); + var suggestion = LIFECYCLE_SUGGESTIONS[lifecycle]; + var sortedComponentNames = setToSortedString(componentNames); + + lifecyclesWarningMessages.push( + formatted + + ": Please update the following components to use " + + (suggestion + " instead: " + sortedComponentNames) + ); + } + }); + + if (lifecyclesWarningMessages.length > 0) { + var strictRootComponentStack = getStackByFiberInDevAndProd(strictRoot); + + warningWithoutStack$1( + false, + "Unsafe lifecycle methods were found within a strict-mode tree:%s" + + "\n\n%s" + + "\n\nLearn more about this warning here:" + + "\nhttps://fb.me/react-strict-mode-warnings", + strictRootComponentStack, + lifecyclesWarningMessages.join("\n\n") + ); + } + }); + + pendingUnsafeLifecycleWarnings = new Map(); + }; + + var findStrictRoot = function(fiber) { + var maybeStrictRoot = null; + + var node = fiber; + while (node !== null) { + if (node.mode & StrictMode) { + maybeStrictRoot = node; + } + node = node.return; + } + + return maybeStrictRoot; + }; + + ReactStrictModeWarnings.flushPendingDeprecationWarnings = function() { + if (pendingComponentWillMountWarnings.length > 0) { + var uniqueNames = new Set(); + pendingComponentWillMountWarnings.forEach(function(fiber) { + uniqueNames.add(getComponentName(fiber.type) || "Component"); + didWarnAboutDeprecatedLifecycles.add(fiber.type); + }); + + var sortedNames = setToSortedString(uniqueNames); + + lowPriorityWarning$1( + false, + "componentWillMount is deprecated and will be removed in the next major version. " + + "Use componentDidMount instead. As a temporary workaround, " + + "you can rename to UNSAFE_componentWillMount." + + "\n\nPlease update the following components: %s" + + "\n\nLearn more about this warning here:" + + "\nhttps://fb.me/react-async-component-lifecycle-hooks", + sortedNames + ); + + pendingComponentWillMountWarnings = []; + } + + if (pendingComponentWillReceivePropsWarnings.length > 0) { + var _uniqueNames = new Set(); + pendingComponentWillReceivePropsWarnings.forEach(function(fiber) { + _uniqueNames.add(getComponentName(fiber.type) || "Component"); + didWarnAboutDeprecatedLifecycles.add(fiber.type); + }); + + var _sortedNames = setToSortedString(_uniqueNames); + + lowPriorityWarning$1( + false, + "componentWillReceiveProps is deprecated and will be removed in the next major version. " + + "Use static getDerivedStateFromProps instead." + + "\n\nPlease update the following components: %s" + + "\n\nLearn more about this warning here:" + + "\nhttps://fb.me/react-async-component-lifecycle-hooks", + _sortedNames + ); + + pendingComponentWillReceivePropsWarnings = []; + } + + if (pendingComponentWillUpdateWarnings.length > 0) { + var _uniqueNames2 = new Set(); + pendingComponentWillUpdateWarnings.forEach(function(fiber) { + _uniqueNames2.add(getComponentName(fiber.type) || "Component"); + didWarnAboutDeprecatedLifecycles.add(fiber.type); + }); + + var _sortedNames2 = setToSortedString(_uniqueNames2); + + lowPriorityWarning$1( + false, + "componentWillUpdate is deprecated and will be removed in the next major version. " + + "Use componentDidUpdate instead. As a temporary workaround, " + + "you can rename to UNSAFE_componentWillUpdate." + + "\n\nPlease update the following components: %s" + + "\n\nLearn more about this warning here:" + + "\nhttps://fb.me/react-async-component-lifecycle-hooks", + _sortedNames2 + ); + + pendingComponentWillUpdateWarnings = []; + } + }; + + ReactStrictModeWarnings.recordDeprecationWarnings = function( + fiber, + instance + ) { + // Dedup strategy: Warn once per component. + if (didWarnAboutDeprecatedLifecycles.has(fiber.type)) { + return; + } + + // Don't warn about react-lifecycles-compat polyfilled components. + if ( + typeof instance.componentWillMount === "function" && + instance.componentWillMount.__suppressDeprecationWarning !== true + ) { + pendingComponentWillMountWarnings.push(fiber); + } + if ( + typeof instance.componentWillReceiveProps === "function" && + instance.componentWillReceiveProps.__suppressDeprecationWarning !== true + ) { + pendingComponentWillReceivePropsWarnings.push(fiber); + } + if ( + typeof instance.componentWillUpdate === "function" && + instance.componentWillUpdate.__suppressDeprecationWarning !== true + ) { + pendingComponentWillUpdateWarnings.push(fiber); + } + }; + + ReactStrictModeWarnings.recordUnsafeLifecycleWarnings = function( + fiber, + instance + ) { + var strictRoot = findStrictRoot(fiber); + if (strictRoot === null) { + warningWithoutStack$1( + false, + "Expected to find a StrictMode component in a strict mode tree. " + + "This error is likely caused by a bug in React. Please file an issue." + ); + return; + } + + // Dedup strategy: Warn once per component. + // This is difficult to track any other way since component names + // are often vague and are likely to collide between 3rd party libraries. + // An expand property is probably okay to use here since it's DEV-only, + // and will only be set in the event of serious warnings. + if (didWarnAboutUnsafeLifecycles.has(fiber.type)) { + return; + } + + var warningsForRoot = void 0; + if (!pendingUnsafeLifecycleWarnings.has(strictRoot)) { + warningsForRoot = { + UNSAFE_componentWillMount: [], + UNSAFE_componentWillReceiveProps: [], + UNSAFE_componentWillUpdate: [] + }; + + pendingUnsafeLifecycleWarnings.set(strictRoot, warningsForRoot); + } else { + warningsForRoot = pendingUnsafeLifecycleWarnings.get(strictRoot); + } + + var unsafeLifecycles = []; + if ( + (typeof instance.componentWillMount === "function" && + instance.componentWillMount.__suppressDeprecationWarning !== true) || + typeof instance.UNSAFE_componentWillMount === "function" + ) { + unsafeLifecycles.push("UNSAFE_componentWillMount"); + } + if ( + (typeof instance.componentWillReceiveProps === "function" && + instance.componentWillReceiveProps.__suppressDeprecationWarning !== + true) || + typeof instance.UNSAFE_componentWillReceiveProps === "function" + ) { + unsafeLifecycles.push("UNSAFE_componentWillReceiveProps"); + } + if ( + (typeof instance.componentWillUpdate === "function" && + instance.componentWillUpdate.__suppressDeprecationWarning !== true) || + typeof instance.UNSAFE_componentWillUpdate === "function" + ) { + unsafeLifecycles.push("UNSAFE_componentWillUpdate"); + } + + if (unsafeLifecycles.length > 0) { + unsafeLifecycles.forEach(function(lifecycle) { + warningsForRoot[lifecycle].push(fiber); + }); + } + }; + + ReactStrictModeWarnings.recordLegacyContextWarning = function( + fiber, + instance + ) { + var strictRoot = findStrictRoot(fiber); + if (strictRoot === null) { + warningWithoutStack$1( + false, + "Expected to find a StrictMode component in a strict mode tree. " + + "This error is likely caused by a bug in React. Please file an issue." + ); + return; + } + + // Dedup strategy: Warn once per component. + if (didWarnAboutLegacyContext.has(fiber.type)) { + return; + } + + var warningsForRoot = pendingLegacyContextWarning.get(strictRoot); + + if ( + fiber.type.contextTypes != null || + fiber.type.childContextTypes != null || + (instance !== null && typeof instance.getChildContext === "function") + ) { + if (warningsForRoot === undefined) { + warningsForRoot = []; + pendingLegacyContextWarning.set(strictRoot, warningsForRoot); + } + warningsForRoot.push(fiber); + } + }; + + ReactStrictModeWarnings.flushLegacyContextWarning = function() { + pendingLegacyContextWarning.forEach(function(fiberArray, strictRoot) { + var uniqueNames = new Set(); + fiberArray.forEach(function(fiber) { + uniqueNames.add(getComponentName(fiber.type) || "Component"); + didWarnAboutLegacyContext.add(fiber.type); + }); + + var sortedNames = setToSortedString(uniqueNames); + var strictRootComponentStack = getStackByFiberInDevAndProd(strictRoot); + + warningWithoutStack$1( + false, + "Legacy context API has been detected within a strict-mode tree: %s" + + "\n\nPlease update the following components: %s" + + "\n\nLearn more about this warning here:" + + "\nhttps://fb.me/react-strict-mode-warnings", + strictRootComponentStack, + sortedNames + ); + }); + }; +} + +function resolveDefaultProps(Component, baseProps) { + if (Component && Component.defaultProps) { + // Resolve default props. Taken from ReactElement + var props = Object.assign({}, baseProps); + var defaultProps = Component.defaultProps; + for (var propName in defaultProps) { + if (props[propName] === undefined) { + props[propName] = defaultProps[propName]; + } + } + return props; + } + return baseProps; +} + +function readLazyComponentType(lazyComponent) { + var status = lazyComponent._status; + var result = lazyComponent._result; + switch (status) { + case Resolved: { + var Component = result; + return Component; + } + case Rejected: { + var error = result; + throw error; + } + case Pending: { + var thenable = result; + throw thenable; + } + default: { + lazyComponent._status = Pending; + var ctor = lazyComponent._ctor; + var _thenable = ctor(); + _thenable.then( + function(moduleObject) { + if (lazyComponent._status === Pending) { + var defaultExport = moduleObject.default; + { + if (defaultExport === undefined) { + warning$1( + false, + "lazy: Expected the result of a dynamic import() call. " + + "Instead received: %s\n\nYour code should look like: \n " + + "const MyComponent = lazy(() => import('./MyComponent'))", + moduleObject + ); + } + } + lazyComponent._status = Resolved; + lazyComponent._result = defaultExport; + } + }, + function(error) { + if (lazyComponent._status === Pending) { + lazyComponent._status = Rejected; + lazyComponent._result = error; + } + } + ); + // Handle synchronous thenables. + switch (lazyComponent._status) { + case Resolved: + return lazyComponent._result; + case Rejected: + throw lazyComponent._result; + } + lazyComponent._result = _thenable; + throw _thenable; + } + } +} + +var valueCursor = createCursor(null); + +var rendererSigil = void 0; +{ + // Use this to detect multiple renderers using the same context + rendererSigil = {}; +} + +var currentlyRenderingFiber = null; +var lastContextDependency = null; +var lastContextWithAllBitsObserved = null; + +var isDisallowedContextReadInDEV = false; + +function resetContextDependences() { + // This is called right before React yields execution, to ensure `readContext` + // cannot be called outside the render phase. + currentlyRenderingFiber = null; + lastContextDependency = null; + lastContextWithAllBitsObserved = null; + { + isDisallowedContextReadInDEV = false; + } +} + +function enterDisallowedContextReadInDEV() { + { + isDisallowedContextReadInDEV = true; + } +} + +function exitDisallowedContextReadInDEV() { + { + isDisallowedContextReadInDEV = false; + } +} + +function pushProvider(providerFiber, nextValue) { + var context = providerFiber.type._context; + + if (isPrimaryRenderer) { + push(valueCursor, context._currentValue, providerFiber); + + context._currentValue = nextValue; + { + !( + context._currentRenderer === undefined || + context._currentRenderer === null || + context._currentRenderer === rendererSigil + ) + ? warningWithoutStack$1( + false, + "Detected multiple renderers concurrently rendering the " + + "same context provider. This is currently unsupported." + ) + : void 0; + context._currentRenderer = rendererSigil; + } + } else { + push(valueCursor, context._currentValue2, providerFiber); + + context._currentValue2 = nextValue; + { + !( + context._currentRenderer2 === undefined || + context._currentRenderer2 === null || + context._currentRenderer2 === rendererSigil + ) + ? warningWithoutStack$1( + false, + "Detected multiple renderers concurrently rendering the " + + "same context provider. This is currently unsupported." + ) + : void 0; + context._currentRenderer2 = rendererSigil; + } + } +} + +function popProvider(providerFiber) { + var currentValue = valueCursor.current; + + pop(valueCursor, providerFiber); + + var context = providerFiber.type._context; + if (isPrimaryRenderer) { + context._currentValue = currentValue; + } else { + context._currentValue2 = currentValue; + } +} + +function calculateChangedBits(context, newValue, oldValue) { + if (is(oldValue, newValue)) { + // No change + return 0; + } else { + var changedBits = + typeof context._calculateChangedBits === "function" + ? context._calculateChangedBits(oldValue, newValue) + : MAX_SIGNED_31_BIT_INT; + + { + !((changedBits & MAX_SIGNED_31_BIT_INT) === changedBits) + ? warning$1( + false, + "calculateChangedBits: Expected the return value to be a " + + "31-bit integer. Instead received: %s", + changedBits + ) + : void 0; + } + return changedBits | 0; + } +} + +function scheduleWorkOnParentPath(parent, renderExpirationTime) { + // Update the child expiration time of all the ancestors, including + // the alternates. + var node = parent; + while (node !== null) { + var alternate = node.alternate; + if (node.childExpirationTime < renderExpirationTime) { + node.childExpirationTime = renderExpirationTime; + if ( + alternate !== null && + alternate.childExpirationTime < renderExpirationTime + ) { + alternate.childExpirationTime = renderExpirationTime; + } + } else if ( + alternate !== null && + alternate.childExpirationTime < renderExpirationTime + ) { + alternate.childExpirationTime = renderExpirationTime; + } else { + // Neither alternate was updated, which means the rest of the + // ancestor path already has sufficient priority. + break; + } + node = node.return; + } +} + +function propagateContextChange( + workInProgress, + context, + changedBits, + renderExpirationTime +) { + var fiber = workInProgress.child; + if (fiber !== null) { + // Set the return pointer of the child to the work-in-progress fiber. + fiber.return = workInProgress; + } + while (fiber !== null) { + var nextFiber = void 0; + + // Visit this fiber. + var list = fiber.contextDependencies; + if (list !== null) { + nextFiber = fiber.child; + + var dependency = list.first; + while (dependency !== null) { + // Check if the context matches. + if ( + dependency.context === context && + (dependency.observedBits & changedBits) !== 0 + ) { + // Match! Schedule an update on this fiber. + + if (fiber.tag === ClassComponent) { + // Schedule a force update on the work-in-progress. + var update = createUpdate(renderExpirationTime); + update.tag = ForceUpdate; + // TODO: Because we don't have a work-in-progress, this will add the + // update to the current fiber, too, which means it will persist even if + // this render is thrown away. Since it's a race condition, not sure it's + // worth fixing. + enqueueUpdate(fiber, update); + } + + if (fiber.expirationTime < renderExpirationTime) { + fiber.expirationTime = renderExpirationTime; + } + var alternate = fiber.alternate; + if ( + alternate !== null && + alternate.expirationTime < renderExpirationTime + ) { + alternate.expirationTime = renderExpirationTime; + } + + scheduleWorkOnParentPath(fiber.return, renderExpirationTime); + + // Mark the expiration time on the list, too. + if (list.expirationTime < renderExpirationTime) { + list.expirationTime = renderExpirationTime; + } + + // Since we already found a match, we can stop traversing the + // dependency list. + break; + } + dependency = dependency.next; + } + } else if (fiber.tag === ContextProvider) { + // Don't scan deeper if this is a matching provider + nextFiber = fiber.type === workInProgress.type ? null : fiber.child; + } else if ( + enableSuspenseServerRenderer && + fiber.tag === DehydratedSuspenseComponent + ) { + // If a dehydrated suspense component is in this subtree, we don't know + // if it will have any context consumers in it. The best we can do is + // mark it as having updates on its children. + if (fiber.expirationTime < renderExpirationTime) { + fiber.expirationTime = renderExpirationTime; + } + var _alternate = fiber.alternate; + if ( + _alternate !== null && + _alternate.expirationTime < renderExpirationTime + ) { + _alternate.expirationTime = renderExpirationTime; + } + // This is intentionally passing this fiber as the parent + // because we want to schedule this fiber as having work + // on its children. We'll use the childExpirationTime on + // this fiber to indicate that a context has changed. + scheduleWorkOnParentPath(fiber, renderExpirationTime); + nextFiber = fiber.sibling; + } else { + // Traverse down. + nextFiber = fiber.child; + } + + if (nextFiber !== null) { + // Set the return pointer of the child to the work-in-progress fiber. + nextFiber.return = fiber; + } else { + // No child. Traverse to next sibling. + nextFiber = fiber; + while (nextFiber !== null) { + if (nextFiber === workInProgress) { + // We're back to the root of this subtree. Exit. + nextFiber = null; + break; + } + var sibling = nextFiber.sibling; + if (sibling !== null) { + // Set the return pointer of the sibling to the work-in-progress fiber. + sibling.return = nextFiber.return; + nextFiber = sibling; + break; + } + // No more siblings. Traverse up. + nextFiber = nextFiber.return; + } + } + fiber = nextFiber; + } +} + +function prepareToReadContext(workInProgress, renderExpirationTime) { + currentlyRenderingFiber = workInProgress; + lastContextDependency = null; + lastContextWithAllBitsObserved = null; + + var currentDependencies = workInProgress.contextDependencies; + if ( + currentDependencies !== null && + currentDependencies.expirationTime >= renderExpirationTime + ) { + // Context list has a pending update. Mark that this fiber performed work. + markWorkInProgressReceivedUpdate(); + } + + // Reset the work-in-progress list + workInProgress.contextDependencies = null; +} + +function readContext(context, observedBits) { + { + // This warning would fire if you read context inside a Hook like useMemo. + // Unlike the class check below, it's not enforced in production for perf. + !!isDisallowedContextReadInDEV + ? warning$1( + false, + "Context can only be read while React is rendering. " + + "In classes, you can read it in the render method or getDerivedStateFromProps. " + + "In function components, you can read it directly in the function body, but not " + + "inside Hooks like useReducer() or useMemo()." + ) + : void 0; + } + + if (lastContextWithAllBitsObserved === context) { + // Nothing to do. We already observe everything in this context. + } else if (observedBits === false || observedBits === 0) { + // Do not observe any updates. + } else { + var resolvedObservedBits = void 0; // Avoid deopting on observable arguments or heterogeneous types. + if ( + typeof observedBits !== "number" || + observedBits === MAX_SIGNED_31_BIT_INT + ) { + // Observe all updates. + lastContextWithAllBitsObserved = context; + resolvedObservedBits = MAX_SIGNED_31_BIT_INT; + } else { + resolvedObservedBits = observedBits; + } + + var contextItem = { + context: context, + observedBits: resolvedObservedBits, + next: null + }; + + if (lastContextDependency === null) { + (function() { + if (!(currentlyRenderingFiber !== null)) { + throw ReactError( + "Context can only be read while React is rendering. In classes, you can read it in the render method or getDerivedStateFromProps. In function components, you can read it directly in the function body, but not inside Hooks like useReducer() or useMemo()." + ); + } + })(); + + // This is the first dependency for this component. Create a new list. + lastContextDependency = contextItem; + currentlyRenderingFiber.contextDependencies = { + first: contextItem, + expirationTime: NoWork + }; + } else { + // Append a new context item. + lastContextDependency = lastContextDependency.next = contextItem; + } + } + return isPrimaryRenderer ? context._currentValue : context._currentValue2; +} + +// UpdateQueue is a linked list of prioritized updates. +// +// Like fibers, update queues come in pairs: a current queue, which represents +// the visible state of the screen, and a work-in-progress queue, which can be +// mutated and processed asynchronously before it is committed — a form of +// double buffering. If a work-in-progress render is discarded before finishing, +// we create a new work-in-progress by cloning the current queue. +// +// Both queues share a persistent, singly-linked list structure. To schedule an +// update, we append it to the end of both queues. Each queue maintains a +// pointer to first update in the persistent list that hasn't been processed. +// The work-in-progress pointer always has a position equal to or greater than +// the current queue, since we always work on that one. The current queue's +// pointer is only updated during the commit phase, when we swap in the +// work-in-progress. +// +// For example: +// +// Current pointer: A - B - C - D - E - F +// Work-in-progress pointer: D - E - F +// ^ +// The work-in-progress queue has +// processed more updates than current. +// +// The reason we append to both queues is because otherwise we might drop +// updates without ever processing them. For example, if we only add updates to +// the work-in-progress queue, some updates could be lost whenever a work-in +// -progress render restarts by cloning from current. Similarly, if we only add +// updates to the current queue, the updates will be lost whenever an already +// in-progress queue commits and swaps with the current queue. However, by +// adding to both queues, we guarantee that the update will be part of the next +// work-in-progress. (And because the work-in-progress queue becomes the +// current queue once it commits, there's no danger of applying the same +// update twice.) +// +// Prioritization +// -------------- +// +// Updates are not sorted by priority, but by insertion; new updates are always +// appended to the end of the list. +// +// The priority is still important, though. When processing the update queue +// during the render phase, only the updates with sufficient priority are +// included in the result. If we skip an update because it has insufficient +// priority, it remains in the queue to be processed later, during a lower +// priority render. Crucially, all updates subsequent to a skipped update also +// remain in the queue *regardless of their priority*. That means high priority +// updates are sometimes processed twice, at two separate priorities. We also +// keep track of a base state, that represents the state before the first +// update in the queue is applied. +// +// For example: +// +// Given a base state of '', and the following queue of updates +// +// A1 - B2 - C1 - D2 +// +// where the number indicates the priority, and the update is applied to the +// previous state by appending a letter, React will process these updates as +// two separate renders, one per distinct priority level: +// +// First render, at priority 1: +// Base state: '' +// Updates: [A1, C1] +// Result state: 'AC' +// +// Second render, at priority 2: +// Base state: 'A' <- The base state does not include C1, +// because B2 was skipped. +// Updates: [B2, C1, D2] <- C1 was rebased on top of B2 +// Result state: 'ABCD' +// +// Because we process updates in insertion order, and rebase high priority +// updates when preceding updates are skipped, the final result is deterministic +// regardless of priority. Intermediate state may vary according to system +// resources, but the final state is always the same. + +var UpdateState = 0; +var ReplaceState = 1; +var ForceUpdate = 2; +var CaptureUpdate = 3; + +// Global state that is reset at the beginning of calling `processUpdateQueue`. +// It should only be read right after calling `processUpdateQueue`, via +// `checkHasForceUpdateAfterProcessing`. +var hasForceUpdate = false; + +var didWarnUpdateInsideUpdate = void 0; +var currentlyProcessingQueue = void 0; + +{ + didWarnUpdateInsideUpdate = false; + currentlyProcessingQueue = null; +} + +function createUpdateQueue(baseState) { + var queue = { + baseState: baseState, + firstUpdate: null, + lastUpdate: null, + firstCapturedUpdate: null, + lastCapturedUpdate: null, + firstEffect: null, + lastEffect: null, + firstCapturedEffect: null, + lastCapturedEffect: null + }; + return queue; +} + +function cloneUpdateQueue(currentQueue) { + var queue = { + baseState: currentQueue.baseState, + firstUpdate: currentQueue.firstUpdate, + lastUpdate: currentQueue.lastUpdate, + + // TODO: With resuming, if we bail out and resuse the child tree, we should + // keep these effects. + firstCapturedUpdate: null, + lastCapturedUpdate: null, + + firstEffect: null, + lastEffect: null, + + firstCapturedEffect: null, + lastCapturedEffect: null + }; + return queue; +} + +function createUpdate(expirationTime) { + return { + expirationTime: expirationTime, + + tag: UpdateState, + payload: null, + callback: null, + + next: null, + nextEffect: null + }; +} + +function appendUpdateToQueue(queue, update) { + // Append the update to the end of the list. + if (queue.lastUpdate === null) { + // Queue is empty + queue.firstUpdate = queue.lastUpdate = update; + } else { + queue.lastUpdate.next = update; + queue.lastUpdate = update; + } +} + +function enqueueUpdate(fiber, update) { + // Update queues are created lazily. + var alternate = fiber.alternate; + var queue1 = void 0; + var queue2 = void 0; + if (alternate === null) { + // There's only one fiber. + queue1 = fiber.updateQueue; + queue2 = null; + if (queue1 === null) { + queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState); + } + } else { + // There are two owners. + queue1 = fiber.updateQueue; + queue2 = alternate.updateQueue; + if (queue1 === null) { + if (queue2 === null) { + // Neither fiber has an update queue. Create new ones. + queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState); + queue2 = alternate.updateQueue = createUpdateQueue( + alternate.memoizedState + ); + } else { + // Only one fiber has an update queue. Clone to create a new one. + queue1 = fiber.updateQueue = cloneUpdateQueue(queue2); + } + } else { + if (queue2 === null) { + // Only one fiber has an update queue. Clone to create a new one. + queue2 = alternate.updateQueue = cloneUpdateQueue(queue1); + } else { + // Both owners have an update queue. + } + } + } + if (queue2 === null || queue1 === queue2) { + // There's only a single queue. + appendUpdateToQueue(queue1, update); + } else { + // There are two queues. We need to append the update to both queues, + // while accounting for the persistent structure of the list — we don't + // want the same update to be added multiple times. + if (queue1.lastUpdate === null || queue2.lastUpdate === null) { + // One of the queues is not empty. We must add the update to both queues. + appendUpdateToQueue(queue1, update); + appendUpdateToQueue(queue2, update); + } else { + // Both queues are non-empty. The last update is the same in both lists, + // because of structural sharing. So, only append to one of the lists. + appendUpdateToQueue(queue1, update); + // But we still need to update the `lastUpdate` pointer of queue2. + queue2.lastUpdate = update; + } + } + + { + if ( + fiber.tag === ClassComponent && + (currentlyProcessingQueue === queue1 || + (queue2 !== null && currentlyProcessingQueue === queue2)) && + !didWarnUpdateInsideUpdate + ) { + warningWithoutStack$1( + false, + "An update (setState, replaceState, or forceUpdate) was scheduled " + + "from inside an update function. Update functions should be pure, " + + "with zero side-effects. Consider using componentDidUpdate or a " + + "callback." + ); + didWarnUpdateInsideUpdate = true; + } + } +} + +function enqueueCapturedUpdate(workInProgress, update) { + // Captured updates go into a separate list, and only on the work-in- + // progress queue. + var workInProgressQueue = workInProgress.updateQueue; + if (workInProgressQueue === null) { + workInProgressQueue = workInProgress.updateQueue = createUpdateQueue( + workInProgress.memoizedState + ); + } else { + // TODO: I put this here rather than createWorkInProgress so that we don't + // clone the queue unnecessarily. There's probably a better way to + // structure this. + workInProgressQueue = ensureWorkInProgressQueueIsAClone( + workInProgress, + workInProgressQueue + ); + } + + // Append the update to the end of the list. + if (workInProgressQueue.lastCapturedUpdate === null) { + // This is the first render phase update + workInProgressQueue.firstCapturedUpdate = workInProgressQueue.lastCapturedUpdate = update; + } else { + workInProgressQueue.lastCapturedUpdate.next = update; + workInProgressQueue.lastCapturedUpdate = update; + } +} + +function ensureWorkInProgressQueueIsAClone(workInProgress, queue) { + var current = workInProgress.alternate; + if (current !== null) { + // If the work-in-progress queue is equal to the current queue, + // we need to clone it first. + if (queue === current.updateQueue) { + queue = workInProgress.updateQueue = cloneUpdateQueue(queue); + } + } + return queue; +} + +function getStateFromUpdate( + workInProgress, + queue, + update, + prevState, + nextProps, + instance +) { + switch (update.tag) { + case ReplaceState: { + var _payload = update.payload; + if (typeof _payload === "function") { + // Updater function + { + enterDisallowedContextReadInDEV(); + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + _payload.call(instance, prevState, nextProps); + } + } + var nextState = _payload.call(instance, prevState, nextProps); + { + exitDisallowedContextReadInDEV(); + } + return nextState; + } + // State object + return _payload; + } + case CaptureUpdate: { + workInProgress.effectTag = + (workInProgress.effectTag & ~ShouldCapture) | DidCapture; + } + // Intentional fallthrough + case UpdateState: { + var _payload2 = update.payload; + var partialState = void 0; + if (typeof _payload2 === "function") { + // Updater function + { + enterDisallowedContextReadInDEV(); + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + _payload2.call(instance, prevState, nextProps); + } + } + partialState = _payload2.call(instance, prevState, nextProps); + { + exitDisallowedContextReadInDEV(); + } + } else { + // Partial state object + partialState = _payload2; + } + if (partialState === null || partialState === undefined) { + // Null and undefined are treated as no-ops. + return prevState; + } + // Merge the partial state and the previous state. + return Object.assign({}, prevState, partialState); + } + case ForceUpdate: { + hasForceUpdate = true; + return prevState; + } + } + return prevState; +} + +function processUpdateQueue( + workInProgress, + queue, + props, + instance, + renderExpirationTime +) { + hasForceUpdate = false; + + queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue); + + { + currentlyProcessingQueue = queue; + } + + // These values may change as we process the queue. + var newBaseState = queue.baseState; + var newFirstUpdate = null; + var newExpirationTime = NoWork; + + // Iterate through the list of updates to compute the result. + var update = queue.firstUpdate; + var resultState = newBaseState; + while (update !== null) { + var updateExpirationTime = update.expirationTime; + if (updateExpirationTime < renderExpirationTime) { + // This update does not have sufficient priority. Skip it. + if (newFirstUpdate === null) { + // This is the first skipped update. It will be the first update in + // the new list. + newFirstUpdate = update; + // Since this is the first update that was skipped, the current result + // is the new base state. + newBaseState = resultState; + } + // Since this update will remain in the list, update the remaining + // expiration time. + if (newExpirationTime < updateExpirationTime) { + newExpirationTime = updateExpirationTime; + } + } else { + // This update does have sufficient priority. + + // Mark the event time of this update as relevant to this render pass. + // TODO: This should ideally use the true event time of this update rather than + // its priority which is a derived and not reverseable value. + // TODO: We should skip this update if it was already committed but currently + // we have no way of detecting the difference between a committed and suspended + // update here. + markRenderEventTime(updateExpirationTime); + + // Process it and compute a new result. + resultState = getStateFromUpdate( + workInProgress, + queue, + update, + resultState, + props, + instance + ); + var _callback = update.callback; + if (_callback !== null) { + workInProgress.effectTag |= Callback; + // Set this to null, in case it was mutated during an aborted render. + update.nextEffect = null; + if (queue.lastEffect === null) { + queue.firstEffect = queue.lastEffect = update; + } else { + queue.lastEffect.nextEffect = update; + queue.lastEffect = update; + } + } + } + // Continue to the next update. + update = update.next; + } + + // Separately, iterate though the list of captured updates. + var newFirstCapturedUpdate = null; + update = queue.firstCapturedUpdate; + while (update !== null) { + var _updateExpirationTime = update.expirationTime; + if (_updateExpirationTime < renderExpirationTime) { + // This update does not have sufficient priority. Skip it. + if (newFirstCapturedUpdate === null) { + // This is the first skipped captured update. It will be the first + // update in the new list. + newFirstCapturedUpdate = update; + // If this is the first update that was skipped, the current result is + // the new base state. + if (newFirstUpdate === null) { + newBaseState = resultState; + } + } + // Since this update will remain in the list, update the remaining + // expiration time. + if (newExpirationTime < _updateExpirationTime) { + newExpirationTime = _updateExpirationTime; + } + } else { + // This update does have sufficient priority. Process it and compute + // a new result. + resultState = getStateFromUpdate( + workInProgress, + queue, + update, + resultState, + props, + instance + ); + var _callback2 = update.callback; + if (_callback2 !== null) { + workInProgress.effectTag |= Callback; + // Set this to null, in case it was mutated during an aborted render. + update.nextEffect = null; + if (queue.lastCapturedEffect === null) { + queue.firstCapturedEffect = queue.lastCapturedEffect = update; + } else { + queue.lastCapturedEffect.nextEffect = update; + queue.lastCapturedEffect = update; + } + } + } + update = update.next; + } + + if (newFirstUpdate === null) { + queue.lastUpdate = null; + } + if (newFirstCapturedUpdate === null) { + queue.lastCapturedUpdate = null; + } else { + workInProgress.effectTag |= Callback; + } + if (newFirstUpdate === null && newFirstCapturedUpdate === null) { + // We processed every update, without skipping. That means the new base + // state is the same as the result state. + newBaseState = resultState; + } + + queue.baseState = newBaseState; + queue.firstUpdate = newFirstUpdate; + queue.firstCapturedUpdate = newFirstCapturedUpdate; + + // Set the remaining expiration time to be whatever is remaining in the queue. + // This should be fine because the only two other things that contribute to + // expiration time are props and context. We're already in the middle of the + // begin phase by the time we start processing the queue, so we've already + // dealt with the props. Context in components that specify + // shouldComponentUpdate is tricky; but we'll have to account for + // that regardless. + workInProgress.expirationTime = newExpirationTime; + workInProgress.memoizedState = resultState; + + { + currentlyProcessingQueue = null; + } +} + +function callCallback(callback, context) { + (function() { + if (!(typeof callback === "function")) { + throw ReactError( + "Invalid argument passed as callback. Expected a function. Instead received: " + + callback + ); + } + })(); + callback.call(context); +} + +function resetHasForceUpdateBeforeProcessing() { + hasForceUpdate = false; +} + +function checkHasForceUpdateAfterProcessing() { + return hasForceUpdate; +} + +function commitUpdateQueue( + finishedWork, + finishedQueue, + instance, + renderExpirationTime +) { + // If the finished render included captured updates, and there are still + // lower priority updates left over, we need to keep the captured updates + // in the queue so that they are rebased and not dropped once we process the + // queue again at the lower priority. + if (finishedQueue.firstCapturedUpdate !== null) { + // Join the captured update list to the end of the normal list. + if (finishedQueue.lastUpdate !== null) { + finishedQueue.lastUpdate.next = finishedQueue.firstCapturedUpdate; + finishedQueue.lastUpdate = finishedQueue.lastCapturedUpdate; + } + // Clear the list of captured updates. + finishedQueue.firstCapturedUpdate = finishedQueue.lastCapturedUpdate = null; + } + + // Commit the effects + commitUpdateEffects(finishedQueue.firstEffect, instance); + finishedQueue.firstEffect = finishedQueue.lastEffect = null; + + commitUpdateEffects(finishedQueue.firstCapturedEffect, instance); + finishedQueue.firstCapturedEffect = finishedQueue.lastCapturedEffect = null; +} + +function commitUpdateEffects(effect, instance) { + while (effect !== null) { + var _callback3 = effect.callback; + if (_callback3 !== null) { + effect.callback = null; + callCallback(_callback3, instance); + } + effect = effect.nextEffect; + } +} + +var fakeInternalInstance = {}; +var isArray$1 = Array.isArray; + +// React.Component uses a shared frozen object by default. +// We'll use it to determine whether we need to initialize legacy refs. +var emptyRefsObject = new React.Component().refs; + +var didWarnAboutStateAssignmentForComponent = void 0; +var didWarnAboutUninitializedState = void 0; +var didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate = void 0; +var didWarnAboutLegacyLifecyclesAndDerivedState = void 0; +var didWarnAboutUndefinedDerivedState = void 0; +var warnOnUndefinedDerivedState = void 0; +var warnOnInvalidCallback = void 0; +var didWarnAboutDirectlyAssigningPropsToState = void 0; +var didWarnAboutContextTypeAndContextTypes = void 0; +var didWarnAboutInvalidateContextType = void 0; + +{ + didWarnAboutStateAssignmentForComponent = new Set(); + didWarnAboutUninitializedState = new Set(); + didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate = new Set(); + didWarnAboutLegacyLifecyclesAndDerivedState = new Set(); + didWarnAboutDirectlyAssigningPropsToState = new Set(); + didWarnAboutUndefinedDerivedState = new Set(); + didWarnAboutContextTypeAndContextTypes = new Set(); + didWarnAboutInvalidateContextType = new Set(); + + var didWarnOnInvalidCallback = new Set(); + + warnOnInvalidCallback = function(callback, callerName) { + if (callback === null || typeof callback === "function") { + return; + } + var key = callerName + "_" + callback; + if (!didWarnOnInvalidCallback.has(key)) { + didWarnOnInvalidCallback.add(key); + warningWithoutStack$1( + false, + "%s(...): Expected the last optional `callback` argument to be a " + + "function. Instead received: %s.", + callerName, + callback + ); + } + }; + + warnOnUndefinedDerivedState = function(type, partialState) { + if (partialState === undefined) { + var componentName = getComponentName(type) || "Component"; + if (!didWarnAboutUndefinedDerivedState.has(componentName)) { + didWarnAboutUndefinedDerivedState.add(componentName); + warningWithoutStack$1( + false, + "%s.getDerivedStateFromProps(): A valid state object (or null) must be returned. " + + "You have returned undefined.", + componentName + ); + } + } + }; + + // This is so gross but it's at least non-critical and can be removed if + // it causes problems. This is meant to give a nicer error message for + // ReactDOM15.unstable_renderSubtreeIntoContainer(reactDOM16Component, + // ...)) which otherwise throws a "_processChildContext is not a function" + // exception. + Object.defineProperty(fakeInternalInstance, "_processChildContext", { + enumerable: false, + value: function() { + (function() { + { + throw ReactError( + "_processChildContext is not available in React 16+. This likely means you have multiple copies of React and are attempting to nest a React 15 tree inside a React 16 tree using unstable_renderSubtreeIntoContainer, which isn't supported. Try to make sure you have only one copy of React (and ideally, switch to ReactDOM.createPortal)." + ); + } + })(); + } + }); + Object.freeze(fakeInternalInstance); +} + +function applyDerivedStateFromProps( + workInProgress, + ctor, + getDerivedStateFromProps, + nextProps +) { + var prevState = workInProgress.memoizedState; + + { + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + // Invoke the function an extra time to help detect side-effects. + getDerivedStateFromProps(nextProps, prevState); + } + } + + var partialState = getDerivedStateFromProps(nextProps, prevState); + + { + warnOnUndefinedDerivedState(ctor, partialState); + } + // Merge the partial state and the previous state. + var memoizedState = + partialState === null || partialState === undefined + ? prevState + : Object.assign({}, prevState, partialState); + workInProgress.memoizedState = memoizedState; + + // Once the update queue is empty, persist the derived state onto the + // base state. + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null && workInProgress.expirationTime === NoWork) { + updateQueue.baseState = memoizedState; + } +} + +var classComponentUpdater = { + isMounted: isMounted, + enqueueSetState: function(inst, payload, callback) { + var fiber = get(inst); + var currentTime = requestCurrentTime(); + var expirationTime = computeExpirationForFiber(currentTime, fiber); + + var update = createUpdate(expirationTime); + update.payload = payload; + if (callback !== undefined && callback !== null) { + { + warnOnInvalidCallback(callback, "setState"); + } + update.callback = callback; + } + + flushPassiveEffects(); + enqueueUpdate(fiber, update); + scheduleWork(fiber, expirationTime); + }, + enqueueReplaceState: function(inst, payload, callback) { + var fiber = get(inst); + var currentTime = requestCurrentTime(); + var expirationTime = computeExpirationForFiber(currentTime, fiber); + + var update = createUpdate(expirationTime); + update.tag = ReplaceState; + update.payload = payload; + + if (callback !== undefined && callback !== null) { + { + warnOnInvalidCallback(callback, "replaceState"); + } + update.callback = callback; + } + + flushPassiveEffects(); + enqueueUpdate(fiber, update); + scheduleWork(fiber, expirationTime); + }, + enqueueForceUpdate: function(inst, callback) { + var fiber = get(inst); + var currentTime = requestCurrentTime(); + var expirationTime = computeExpirationForFiber(currentTime, fiber); + + var update = createUpdate(expirationTime); + update.tag = ForceUpdate; + + if (callback !== undefined && callback !== null) { + { + warnOnInvalidCallback(callback, "forceUpdate"); + } + update.callback = callback; + } + + flushPassiveEffects(); + enqueueUpdate(fiber, update); + scheduleWork(fiber, expirationTime); + } +}; + +function checkShouldComponentUpdate( + workInProgress, + ctor, + oldProps, + newProps, + oldState, + newState, + nextContext +) { + var instance = workInProgress.stateNode; + if (typeof instance.shouldComponentUpdate === "function") { + startPhaseTimer(workInProgress, "shouldComponentUpdate"); + var shouldUpdate = instance.shouldComponentUpdate( + newProps, + newState, + nextContext + ); + stopPhaseTimer(); + + { + !(shouldUpdate !== undefined) + ? warningWithoutStack$1( + false, + "%s.shouldComponentUpdate(): Returned undefined instead of a " + + "boolean value. Make sure to return true or false.", + getComponentName(ctor) || "Component" + ) + : void 0; + } + + return shouldUpdate; + } + + if (ctor.prototype && ctor.prototype.isPureReactComponent) { + return ( + !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState) + ); + } + + return true; +} + +function checkClassInstance(workInProgress, ctor, newProps) { + var instance = workInProgress.stateNode; + { + var name = getComponentName(ctor) || "Component"; + var renderPresent = instance.render; + + if (!renderPresent) { + if (ctor.prototype && typeof ctor.prototype.render === "function") { + warningWithoutStack$1( + false, + "%s(...): No `render` method found on the returned component " + + "instance: did you accidentally return an object from the constructor?", + name + ); + } else { + warningWithoutStack$1( + false, + "%s(...): No `render` method found on the returned component " + + "instance: you may have forgotten to define `render`.", + name + ); + } + } + + var noGetInitialStateOnES6 = + !instance.getInitialState || + instance.getInitialState.isReactClassApproved || + instance.state; + !noGetInitialStateOnES6 + ? warningWithoutStack$1( + false, + "getInitialState was defined on %s, a plain JavaScript class. " + + "This is only supported for classes created using React.createClass. " + + "Did you mean to define a state property instead?", + name + ) + : void 0; + var noGetDefaultPropsOnES6 = + !instance.getDefaultProps || + instance.getDefaultProps.isReactClassApproved; + !noGetDefaultPropsOnES6 + ? warningWithoutStack$1( + false, + "getDefaultProps was defined on %s, a plain JavaScript class. " + + "This is only supported for classes created using React.createClass. " + + "Use a static property to define defaultProps instead.", + name + ) + : void 0; + var noInstancePropTypes = !instance.propTypes; + !noInstancePropTypes + ? warningWithoutStack$1( + false, + "propTypes was defined as an instance property on %s. Use a static " + + "property to define propTypes instead.", + name + ) + : void 0; + var noInstanceContextType = !instance.contextType; + !noInstanceContextType + ? warningWithoutStack$1( + false, + "contextType was defined as an instance property on %s. Use a static " + + "property to define contextType instead.", + name + ) + : void 0; + var noInstanceContextTypes = !instance.contextTypes; + !noInstanceContextTypes + ? warningWithoutStack$1( + false, + "contextTypes was defined as an instance property on %s. Use a static " + + "property to define contextTypes instead.", + name + ) + : void 0; + + if ( + ctor.contextType && + ctor.contextTypes && + !didWarnAboutContextTypeAndContextTypes.has(ctor) + ) { + didWarnAboutContextTypeAndContextTypes.add(ctor); + warningWithoutStack$1( + false, + "%s declares both contextTypes and contextType static properties. " + + "The legacy contextTypes property will be ignored.", + name + ); + } + + var noComponentShouldUpdate = + typeof instance.componentShouldUpdate !== "function"; + !noComponentShouldUpdate + ? warningWithoutStack$1( + false, + "%s has a method called " + + "componentShouldUpdate(). Did you mean shouldComponentUpdate()? " + + "The name is phrased as a question because the function is " + + "expected to return a value.", + name + ) + : void 0; + if ( + ctor.prototype && + ctor.prototype.isPureReactComponent && + typeof instance.shouldComponentUpdate !== "undefined" + ) { + warningWithoutStack$1( + false, + "%s has a method called shouldComponentUpdate(). " + + "shouldComponentUpdate should not be used when extending React.PureComponent. " + + "Please extend React.Component if shouldComponentUpdate is used.", + getComponentName(ctor) || "A pure component" + ); + } + var noComponentDidUnmount = + typeof instance.componentDidUnmount !== "function"; + !noComponentDidUnmount + ? warningWithoutStack$1( + false, + "%s has a method called " + + "componentDidUnmount(). But there is no such lifecycle method. " + + "Did you mean componentWillUnmount()?", + name + ) + : void 0; + var noComponentDidReceiveProps = + typeof instance.componentDidReceiveProps !== "function"; + !noComponentDidReceiveProps + ? warningWithoutStack$1( + false, + "%s has a method called " + + "componentDidReceiveProps(). But there is no such lifecycle method. " + + "If you meant to update the state in response to changing props, " + + "use componentWillReceiveProps(). If you meant to fetch data or " + + "run side-effects or mutations after React has updated the UI, use componentDidUpdate().", + name + ) + : void 0; + var noComponentWillRecieveProps = + typeof instance.componentWillRecieveProps !== "function"; + !noComponentWillRecieveProps + ? warningWithoutStack$1( + false, + "%s has a method called " + + "componentWillRecieveProps(). Did you mean componentWillReceiveProps()?", + name + ) + : void 0; + var noUnsafeComponentWillRecieveProps = + typeof instance.UNSAFE_componentWillRecieveProps !== "function"; + !noUnsafeComponentWillRecieveProps + ? warningWithoutStack$1( + false, + "%s has a method called " + + "UNSAFE_componentWillRecieveProps(). Did you mean UNSAFE_componentWillReceiveProps()?", + name + ) + : void 0; + var hasMutatedProps = instance.props !== newProps; + !(instance.props === undefined || !hasMutatedProps) + ? warningWithoutStack$1( + false, + "%s(...): When calling super() in `%s`, make sure to pass " + + "up the same props that your component's constructor was passed.", + name, + name + ) + : void 0; + var noInstanceDefaultProps = !instance.defaultProps; + !noInstanceDefaultProps + ? warningWithoutStack$1( + false, + "Setting defaultProps as an instance property on %s is not supported and will be ignored." + + " Instead, define defaultProps as a static property on %s.", + name, + name + ) + : void 0; + + if ( + typeof instance.getSnapshotBeforeUpdate === "function" && + typeof instance.componentDidUpdate !== "function" && + !didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.has(ctor) + ) { + didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.add(ctor); + warningWithoutStack$1( + false, + "%s: getSnapshotBeforeUpdate() should be used with componentDidUpdate(). " + + "This component defines getSnapshotBeforeUpdate() only.", + getComponentName(ctor) + ); + } + + var noInstanceGetDerivedStateFromProps = + typeof instance.getDerivedStateFromProps !== "function"; + !noInstanceGetDerivedStateFromProps + ? warningWithoutStack$1( + false, + "%s: getDerivedStateFromProps() is defined as an instance method " + + "and will be ignored. Instead, declare it as a static method.", + name + ) + : void 0; + var noInstanceGetDerivedStateFromCatch = + typeof instance.getDerivedStateFromError !== "function"; + !noInstanceGetDerivedStateFromCatch + ? warningWithoutStack$1( + false, + "%s: getDerivedStateFromError() is defined as an instance method " + + "and will be ignored. Instead, declare it as a static method.", + name + ) + : void 0; + var noStaticGetSnapshotBeforeUpdate = + typeof ctor.getSnapshotBeforeUpdate !== "function"; + !noStaticGetSnapshotBeforeUpdate + ? warningWithoutStack$1( + false, + "%s: getSnapshotBeforeUpdate() is defined as a static method " + + "and will be ignored. Instead, declare it as an instance method.", + name + ) + : void 0; + var _state = instance.state; + if (_state && (typeof _state !== "object" || isArray$1(_state))) { + warningWithoutStack$1( + false, + "%s.state: must be set to an object or null", + name + ); + } + if (typeof instance.getChildContext === "function") { + !(typeof ctor.childContextTypes === "object") + ? warningWithoutStack$1( + false, + "%s.getChildContext(): childContextTypes must be defined in order to " + + "use getChildContext().", + name + ) + : void 0; + } + } +} + +function adoptClassInstance(workInProgress, instance) { + instance.updater = classComponentUpdater; + workInProgress.stateNode = instance; + // The instance needs access to the fiber so that it can schedule updates + set(instance, workInProgress); + { + instance._reactInternalInstance = fakeInternalInstance; + } +} + +function constructClassInstance( + workInProgress, + ctor, + props, + renderExpirationTime +) { + var isLegacyContextConsumer = false; + var unmaskedContext = emptyContextObject; + var context = null; + var contextType = ctor.contextType; + + { + if ("contextType" in ctor) { + var isValid = + // Allow null for conditional declaration + contextType === null || + (contextType !== undefined && + contextType.$$typeof === REACT_CONTEXT_TYPE && + contextType._context === undefined); // Not a + + if (!isValid && !didWarnAboutInvalidateContextType.has(ctor)) { + didWarnAboutInvalidateContextType.add(ctor); + + var addendum = ""; + if (contextType === undefined) { + addendum = + " However, it is set to undefined. " + + "This can be caused by a typo or by mixing up named and default imports. " + + "This can also happen due to a circular dependency, so " + + "try moving the createContext() call to a separate file."; + } else if (typeof contextType !== "object") { + addendum = " However, it is set to a " + typeof contextType + "."; + } else if (contextType.$$typeof === REACT_PROVIDER_TYPE) { + addendum = " Did you accidentally pass the Context.Provider instead?"; + } else if (contextType._context !== undefined) { + // + addendum = " Did you accidentally pass the Context.Consumer instead?"; + } else { + addendum = + " However, it is set to an object with keys {" + + Object.keys(contextType).join(", ") + + "}."; + } + warningWithoutStack$1( + false, + "%s defines an invalid contextType. " + + "contextType should point to the Context object returned by React.createContext().%s", + getComponentName(ctor) || "Component", + addendum + ); + } + } + } + + if (typeof contextType === "object" && contextType !== null) { + context = readContext(contextType); + } else { + unmaskedContext = getUnmaskedContext(workInProgress, ctor, true); + var contextTypes = ctor.contextTypes; + isLegacyContextConsumer = + contextTypes !== null && contextTypes !== undefined; + context = isLegacyContextConsumer + ? getMaskedContext(workInProgress, unmaskedContext) + : emptyContextObject; + } + + // Instantiate twice to help detect side-effects. + { + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + new ctor(props, context); // eslint-disable-line no-new + } + } + + var instance = new ctor(props, context); + var state = (workInProgress.memoizedState = + instance.state !== null && instance.state !== undefined + ? instance.state + : null); + adoptClassInstance(workInProgress, instance); + + { + if (typeof ctor.getDerivedStateFromProps === "function" && state === null) { + var componentName = getComponentName(ctor) || "Component"; + if (!didWarnAboutUninitializedState.has(componentName)) { + didWarnAboutUninitializedState.add(componentName); + warningWithoutStack$1( + false, + "`%s` uses `getDerivedStateFromProps` but its initial state is " + + "%s. This is not recommended. Instead, define the initial state by " + + "assigning an object to `this.state` in the constructor of `%s`. " + + "This ensures that `getDerivedStateFromProps` arguments have a consistent shape.", + componentName, + instance.state === null ? "null" : "undefined", + componentName + ); + } + } + + // If new component APIs are defined, "unsafe" lifecycles won't be called. + // Warn about these lifecycles if they are present. + // Don't warn about react-lifecycles-compat polyfilled methods though. + if ( + typeof ctor.getDerivedStateFromProps === "function" || + typeof instance.getSnapshotBeforeUpdate === "function" + ) { + var foundWillMountName = null; + var foundWillReceivePropsName = null; + var foundWillUpdateName = null; + if ( + typeof instance.componentWillMount === "function" && + instance.componentWillMount.__suppressDeprecationWarning !== true + ) { + foundWillMountName = "componentWillMount"; + } else if (typeof instance.UNSAFE_componentWillMount === "function") { + foundWillMountName = "UNSAFE_componentWillMount"; + } + if ( + typeof instance.componentWillReceiveProps === "function" && + instance.componentWillReceiveProps.__suppressDeprecationWarning !== true + ) { + foundWillReceivePropsName = "componentWillReceiveProps"; + } else if ( + typeof instance.UNSAFE_componentWillReceiveProps === "function" + ) { + foundWillReceivePropsName = "UNSAFE_componentWillReceiveProps"; + } + if ( + typeof instance.componentWillUpdate === "function" && + instance.componentWillUpdate.__suppressDeprecationWarning !== true + ) { + foundWillUpdateName = "componentWillUpdate"; + } else if (typeof instance.UNSAFE_componentWillUpdate === "function") { + foundWillUpdateName = "UNSAFE_componentWillUpdate"; + } + if ( + foundWillMountName !== null || + foundWillReceivePropsName !== null || + foundWillUpdateName !== null + ) { + var _componentName = getComponentName(ctor) || "Component"; + var newApiName = + typeof ctor.getDerivedStateFromProps === "function" + ? "getDerivedStateFromProps()" + : "getSnapshotBeforeUpdate()"; + if (!didWarnAboutLegacyLifecyclesAndDerivedState.has(_componentName)) { + didWarnAboutLegacyLifecyclesAndDerivedState.add(_componentName); + warningWithoutStack$1( + false, + "Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n" + + "%s uses %s but also contains the following legacy lifecycles:%s%s%s\n\n" + + "The above lifecycles should be removed. Learn more about this warning here:\n" + + "https://fb.me/react-async-component-lifecycle-hooks", + _componentName, + newApiName, + foundWillMountName !== null ? "\n " + foundWillMountName : "", + foundWillReceivePropsName !== null + ? "\n " + foundWillReceivePropsName + : "", + foundWillUpdateName !== null ? "\n " + foundWillUpdateName : "" + ); + } + } + } + } + + // Cache unmasked context so we can avoid recreating masked context unless necessary. + // ReactFiberContext usually updates this cache but can't for newly-created instances. + if (isLegacyContextConsumer) { + cacheContext(workInProgress, unmaskedContext, context); + } + + return instance; +} + +function callComponentWillMount(workInProgress, instance) { + startPhaseTimer(workInProgress, "componentWillMount"); + var oldState = instance.state; + + if (typeof instance.componentWillMount === "function") { + instance.componentWillMount(); + } + if (typeof instance.UNSAFE_componentWillMount === "function") { + instance.UNSAFE_componentWillMount(); + } + + stopPhaseTimer(); + + if (oldState !== instance.state) { + { + warningWithoutStack$1( + false, + "%s.componentWillMount(): Assigning directly to this.state is " + + "deprecated (except inside a component's " + + "constructor). Use setState instead.", + getComponentName(workInProgress.type) || "Component" + ); + } + classComponentUpdater.enqueueReplaceState(instance, instance.state, null); + } +} + +function callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + nextContext +) { + var oldState = instance.state; + startPhaseTimer(workInProgress, "componentWillReceiveProps"); + if (typeof instance.componentWillReceiveProps === "function") { + instance.componentWillReceiveProps(newProps, nextContext); + } + if (typeof instance.UNSAFE_componentWillReceiveProps === "function") { + instance.UNSAFE_componentWillReceiveProps(newProps, nextContext); + } + stopPhaseTimer(); + + if (instance.state !== oldState) { + { + var componentName = getComponentName(workInProgress.type) || "Component"; + if (!didWarnAboutStateAssignmentForComponent.has(componentName)) { + didWarnAboutStateAssignmentForComponent.add(componentName); + warningWithoutStack$1( + false, + "%s.componentWillReceiveProps(): Assigning directly to " + + "this.state is deprecated (except inside a component's " + + "constructor). Use setState instead.", + componentName + ); + } + } + classComponentUpdater.enqueueReplaceState(instance, instance.state, null); + } +} + +// Invokes the mount life-cycles on a previously never rendered instance. +function mountClassInstance( + workInProgress, + ctor, + newProps, + renderExpirationTime +) { + { + checkClassInstance(workInProgress, ctor, newProps); + } + + var instance = workInProgress.stateNode; + instance.props = newProps; + instance.state = workInProgress.memoizedState; + instance.refs = emptyRefsObject; + + var contextType = ctor.contextType; + if (typeof contextType === "object" && contextType !== null) { + instance.context = readContext(contextType); + } else { + var unmaskedContext = getUnmaskedContext(workInProgress, ctor, true); + instance.context = getMaskedContext(workInProgress, unmaskedContext); + } + + { + if (instance.state === newProps) { + var componentName = getComponentName(ctor) || "Component"; + if (!didWarnAboutDirectlyAssigningPropsToState.has(componentName)) { + didWarnAboutDirectlyAssigningPropsToState.add(componentName); + warningWithoutStack$1( + false, + "%s: It is not recommended to assign props directly to state " + + "because updates to props won't be reflected in state. " + + "In most cases, it is better to use props directly.", + componentName + ); + } + } + + if (workInProgress.mode & StrictMode) { + ReactStrictModeWarnings.recordUnsafeLifecycleWarnings( + workInProgress, + instance + ); + + ReactStrictModeWarnings.recordLegacyContextWarning( + workInProgress, + instance + ); + } + + if (warnAboutDeprecatedLifecycles) { + ReactStrictModeWarnings.recordDeprecationWarnings( + workInProgress, + instance + ); + } + } + + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null) { + processUpdateQueue( + workInProgress, + updateQueue, + newProps, + instance, + renderExpirationTime + ); + instance.state = workInProgress.memoizedState; + } + + var getDerivedStateFromProps = ctor.getDerivedStateFromProps; + if (typeof getDerivedStateFromProps === "function") { + applyDerivedStateFromProps( + workInProgress, + ctor, + getDerivedStateFromProps, + newProps + ); + instance.state = workInProgress.memoizedState; + } + + // In order to support react-lifecycles-compat polyfilled components, + // Unsafe lifecycles should not be invoked for components using the new APIs. + if ( + typeof ctor.getDerivedStateFromProps !== "function" && + typeof instance.getSnapshotBeforeUpdate !== "function" && + (typeof instance.UNSAFE_componentWillMount === "function" || + typeof instance.componentWillMount === "function") + ) { + callComponentWillMount(workInProgress, instance); + // If we had additional state updates during this life-cycle, let's + // process them now. + updateQueue = workInProgress.updateQueue; + if (updateQueue !== null) { + processUpdateQueue( + workInProgress, + updateQueue, + newProps, + instance, + renderExpirationTime + ); + instance.state = workInProgress.memoizedState; + } + } + + if (typeof instance.componentDidMount === "function") { + workInProgress.effectTag |= Update; + } +} + +function resumeMountClassInstance( + workInProgress, + ctor, + newProps, + renderExpirationTime +) { + var instance = workInProgress.stateNode; + + var oldProps = workInProgress.memoizedProps; + instance.props = oldProps; + + var oldContext = instance.context; + var contextType = ctor.contextType; + var nextContext = void 0; + if (typeof contextType === "object" && contextType !== null) { + nextContext = readContext(contextType); + } else { + var nextLegacyUnmaskedContext = getUnmaskedContext( + workInProgress, + ctor, + true + ); + nextContext = getMaskedContext(workInProgress, nextLegacyUnmaskedContext); + } + + var getDerivedStateFromProps = ctor.getDerivedStateFromProps; + var hasNewLifecycles = + typeof getDerivedStateFromProps === "function" || + typeof instance.getSnapshotBeforeUpdate === "function"; + + // Note: During these life-cycles, instance.props/instance.state are what + // ever the previously attempted to render - not the "current". However, + // during componentDidUpdate we pass the "current" props. + + // In order to support react-lifecycles-compat polyfilled components, + // Unsafe lifecycles should not be invoked for components using the new APIs. + if ( + !hasNewLifecycles && + (typeof instance.UNSAFE_componentWillReceiveProps === "function" || + typeof instance.componentWillReceiveProps === "function") + ) { + if (oldProps !== newProps || oldContext !== nextContext) { + callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + nextContext + ); + } + } + + resetHasForceUpdateBeforeProcessing(); + + var oldState = workInProgress.memoizedState; + var newState = (instance.state = oldState); + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null) { + processUpdateQueue( + workInProgress, + updateQueue, + newProps, + instance, + renderExpirationTime + ); + newState = workInProgress.memoizedState; + } + if ( + oldProps === newProps && + oldState === newState && + !hasContextChanged() && + !checkHasForceUpdateAfterProcessing() + ) { + // If an update was already in progress, we should schedule an Update + // effect even though we're bailing out, so that cWU/cDU are called. + if (typeof instance.componentDidMount === "function") { + workInProgress.effectTag |= Update; + } + return false; + } + + if (typeof getDerivedStateFromProps === "function") { + applyDerivedStateFromProps( + workInProgress, + ctor, + getDerivedStateFromProps, + newProps + ); + newState = workInProgress.memoizedState; + } + + var shouldUpdate = + checkHasForceUpdateAfterProcessing() || + checkShouldComponentUpdate( + workInProgress, + ctor, + oldProps, + newProps, + oldState, + newState, + nextContext + ); + + if (shouldUpdate) { + // In order to support react-lifecycles-compat polyfilled components, + // Unsafe lifecycles should not be invoked for components using the new APIs. + if ( + !hasNewLifecycles && + (typeof instance.UNSAFE_componentWillMount === "function" || + typeof instance.componentWillMount === "function") + ) { + startPhaseTimer(workInProgress, "componentWillMount"); + if (typeof instance.componentWillMount === "function") { + instance.componentWillMount(); + } + if (typeof instance.UNSAFE_componentWillMount === "function") { + instance.UNSAFE_componentWillMount(); + } + stopPhaseTimer(); + } + if (typeof instance.componentDidMount === "function") { + workInProgress.effectTag |= Update; + } + } else { + // If an update was already in progress, we should schedule an Update + // effect even though we're bailing out, so that cWU/cDU are called. + if (typeof instance.componentDidMount === "function") { + workInProgress.effectTag |= Update; + } + + // If shouldComponentUpdate returned false, we should still update the + // memoized state to indicate that this work can be reused. + workInProgress.memoizedProps = newProps; + workInProgress.memoizedState = newState; + } + + // Update the existing instance's state, props, and context pointers even + // if shouldComponentUpdate returns false. + instance.props = newProps; + instance.state = newState; + instance.context = nextContext; + + return shouldUpdate; +} + +// Invokes the update life-cycles and returns false if it shouldn't rerender. +function updateClassInstance( + current, + workInProgress, + ctor, + newProps, + renderExpirationTime +) { + var instance = workInProgress.stateNode; + + var oldProps = workInProgress.memoizedProps; + instance.props = + workInProgress.type === workInProgress.elementType + ? oldProps + : resolveDefaultProps(workInProgress.type, oldProps); + + var oldContext = instance.context; + var contextType = ctor.contextType; + var nextContext = void 0; + if (typeof contextType === "object" && contextType !== null) { + nextContext = readContext(contextType); + } else { + var nextUnmaskedContext = getUnmaskedContext(workInProgress, ctor, true); + nextContext = getMaskedContext(workInProgress, nextUnmaskedContext); + } + + var getDerivedStateFromProps = ctor.getDerivedStateFromProps; + var hasNewLifecycles = + typeof getDerivedStateFromProps === "function" || + typeof instance.getSnapshotBeforeUpdate === "function"; + + // Note: During these life-cycles, instance.props/instance.state are what + // ever the previously attempted to render - not the "current". However, + // during componentDidUpdate we pass the "current" props. + + // In order to support react-lifecycles-compat polyfilled components, + // Unsafe lifecycles should not be invoked for components using the new APIs. + if ( + !hasNewLifecycles && + (typeof instance.UNSAFE_componentWillReceiveProps === "function" || + typeof instance.componentWillReceiveProps === "function") + ) { + if (oldProps !== newProps || oldContext !== nextContext) { + callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + nextContext + ); + } + } + + resetHasForceUpdateBeforeProcessing(); + + var oldState = workInProgress.memoizedState; + var newState = (instance.state = oldState); + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null) { + processUpdateQueue( + workInProgress, + updateQueue, + newProps, + instance, + renderExpirationTime + ); + newState = workInProgress.memoizedState; + } + + if ( + oldProps === newProps && + oldState === newState && + !hasContextChanged() && + !checkHasForceUpdateAfterProcessing() + ) { + // If an update was already in progress, we should schedule an Update + // effect even though we're bailing out, so that cWU/cDU are called. + if (typeof instance.componentDidUpdate === "function") { + if ( + oldProps !== current.memoizedProps || + oldState !== current.memoizedState + ) { + workInProgress.effectTag |= Update; + } + } + if (typeof instance.getSnapshotBeforeUpdate === "function") { + if ( + oldProps !== current.memoizedProps || + oldState !== current.memoizedState + ) { + workInProgress.effectTag |= Snapshot; + } + } + return false; + } + + if (typeof getDerivedStateFromProps === "function") { + applyDerivedStateFromProps( + workInProgress, + ctor, + getDerivedStateFromProps, + newProps + ); + newState = workInProgress.memoizedState; + } + + var shouldUpdate = + checkHasForceUpdateAfterProcessing() || + checkShouldComponentUpdate( + workInProgress, + ctor, + oldProps, + newProps, + oldState, + newState, + nextContext + ); + + if (shouldUpdate) { + // In order to support react-lifecycles-compat polyfilled components, + // Unsafe lifecycles should not be invoked for components using the new APIs. + if ( + !hasNewLifecycles && + (typeof instance.UNSAFE_componentWillUpdate === "function" || + typeof instance.componentWillUpdate === "function") + ) { + startPhaseTimer(workInProgress, "componentWillUpdate"); + if (typeof instance.componentWillUpdate === "function") { + instance.componentWillUpdate(newProps, newState, nextContext); + } + if (typeof instance.UNSAFE_componentWillUpdate === "function") { + instance.UNSAFE_componentWillUpdate(newProps, newState, nextContext); + } + stopPhaseTimer(); + } + if (typeof instance.componentDidUpdate === "function") { + workInProgress.effectTag |= Update; + } + if (typeof instance.getSnapshotBeforeUpdate === "function") { + workInProgress.effectTag |= Snapshot; + } + } else { + // If an update was already in progress, we should schedule an Update + // effect even though we're bailing out, so that cWU/cDU are called. + if (typeof instance.componentDidUpdate === "function") { + if ( + oldProps !== current.memoizedProps || + oldState !== current.memoizedState + ) { + workInProgress.effectTag |= Update; + } + } + if (typeof instance.getSnapshotBeforeUpdate === "function") { + if ( + oldProps !== current.memoizedProps || + oldState !== current.memoizedState + ) { + workInProgress.effectTag |= Snapshot; + } + } + + // If shouldComponentUpdate returned false, we should still update the + // memoized props/state to indicate that this work can be reused. + workInProgress.memoizedProps = newProps; + workInProgress.memoizedState = newState; + } + + // Update the existing instance's state, props, and context pointers even + // if shouldComponentUpdate returns false. + instance.props = newProps; + instance.state = newState; + instance.context = nextContext; + + return shouldUpdate; +} + +var didWarnAboutMaps = void 0; +var didWarnAboutGenerators = void 0; +var didWarnAboutStringRefInStrictMode = void 0; +var ownerHasKeyUseWarning = void 0; +var ownerHasFunctionTypeWarning = void 0; +var warnForMissingKey = function(child) {}; + +{ + didWarnAboutMaps = false; + didWarnAboutGenerators = false; + didWarnAboutStringRefInStrictMode = {}; + + /** + * Warn if there's no key explicitly set on dynamic arrays of children or + * object keys are not valid. This allows us to keep track of children between + * updates. + */ + ownerHasKeyUseWarning = {}; + ownerHasFunctionTypeWarning = {}; + + warnForMissingKey = function(child) { + if (child === null || typeof child !== "object") { + return; + } + if (!child._store || child._store.validated || child.key != null) { + return; + } + (function() { + if (!(typeof child._store === "object")) { + throw ReactError( + "React Component in warnForMissingKey should have a _store. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + child._store.validated = true; + + var currentComponentErrorInfo = + "Each child in a list should have a unique " + + '"key" prop. See https://fb.me/react-warning-keys for ' + + "more information." + + getCurrentFiberStackInDev(); + if (ownerHasKeyUseWarning[currentComponentErrorInfo]) { + return; + } + ownerHasKeyUseWarning[currentComponentErrorInfo] = true; + + warning$1( + false, + "Each child in a list should have a unique " + + '"key" prop. See https://fb.me/react-warning-keys for ' + + "more information." + ); + }; +} + +var isArray = Array.isArray; + +function coerceRef(returnFiber, current$$1, element) { + var mixedRef = element.ref; + if ( + mixedRef !== null && + typeof mixedRef !== "function" && + typeof mixedRef !== "object" + ) { + { + if (returnFiber.mode & StrictMode) { + var componentName = getComponentName(returnFiber.type) || "Component"; + if (!didWarnAboutStringRefInStrictMode[componentName]) { + warningWithoutStack$1( + false, + 'A string ref, "%s", has been found within a strict mode tree. ' + + "String refs are a source of potential bugs and should be avoided. " + + "We recommend using createRef() instead." + + "\n%s" + + "\n\nLearn more about using refs safely here:" + + "\nhttps://fb.me/react-strict-mode-string-ref", + mixedRef, + getStackByFiberInDevAndProd(returnFiber) + ); + didWarnAboutStringRefInStrictMode[componentName] = true; + } + } + } + + if (element._owner) { + var owner = element._owner; + var inst = void 0; + if (owner) { + var ownerFiber = owner; + (function() { + if (!(ownerFiber.tag === ClassComponent)) { + throw ReactError( + "Function components cannot have refs. Did you mean to use React.forwardRef()?" + ); + } + })(); + inst = ownerFiber.stateNode; + } + (function() { + if (!inst) { + throw ReactError( + "Missing owner for string ref " + + mixedRef + + ". This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + var stringRef = "" + mixedRef; + // Check if previous string ref matches new string ref + if ( + current$$1 !== null && + current$$1.ref !== null && + typeof current$$1.ref === "function" && + current$$1.ref._stringRef === stringRef + ) { + return current$$1.ref; + } + var ref = function(value) { + var refs = inst.refs; + if (refs === emptyRefsObject) { + // This is a lazy pooled frozen object, so we need to initialize. + refs = inst.refs = {}; + } + if (value === null) { + delete refs[stringRef]; + } else { + refs[stringRef] = value; + } + }; + ref._stringRef = stringRef; + return ref; + } else { + (function() { + if (!(typeof mixedRef === "string")) { + throw ReactError( + "Expected ref to be a function, a string, an object returned by React.createRef(), or null." + ); + } + })(); + (function() { + if (!element._owner) { + throw ReactError( + "Element ref was specified as a string (" + + mixedRef + + ") but no owner was set. This could happen for one of the following reasons:\n1. You may be adding a ref to a function component\n2. You may be adding a ref to a component that was not created inside a component's render method\n3. You have multiple copies of React loaded\nSee https://fb.me/react-refs-must-have-owner for more information." + ); + } + })(); + } + } + return mixedRef; +} + +function throwOnInvalidObjectType(returnFiber, newChild) { + if (returnFiber.type !== "textarea") { + var addendum = ""; + { + addendum = + " If you meant to render a collection of children, use an array " + + "instead." + + getCurrentFiberStackInDev(); + } + (function() { + { + throw ReactError( + "Objects are not valid as a React child (found: " + + (Object.prototype.toString.call(newChild) === "[object Object]" + ? "object with keys {" + Object.keys(newChild).join(", ") + "}" + : newChild) + + ")." + + addendum + ); + } + })(); + } +} + +function warnOnFunctionType() { + var currentComponentErrorInfo = + "Functions are not valid as a React child. This may happen if " + + "you return a Component instead of from render. " + + "Or maybe you meant to call this function rather than return it." + + getCurrentFiberStackInDev(); + + if (ownerHasFunctionTypeWarning[currentComponentErrorInfo]) { + return; + } + ownerHasFunctionTypeWarning[currentComponentErrorInfo] = true; + + warning$1( + false, + "Functions are not valid as a React child. This may happen if " + + "you return a Component instead of from render. " + + "Or maybe you meant to call this function rather than return it." + ); +} + +// This wrapper function exists because I expect to clone the code in each path +// to be able to optimize each path individually by branching early. This needs +// a compiler or we can do it manually. Helpers that don't need this branching +// live outside of this function. +function ChildReconciler(shouldTrackSideEffects) { + function deleteChild(returnFiber, childToDelete) { + if (!shouldTrackSideEffects) { + // Noop. + return; + } + // Deletions are added in reversed order so we add it to the front. + // At this point, the return fiber's effect list is empty except for + // deletions, so we can just append the deletion to the list. The remaining + // effects aren't added until the complete phase. Once we implement + // resuming, this may not be true. + var last = returnFiber.lastEffect; + if (last !== null) { + last.nextEffect = childToDelete; + returnFiber.lastEffect = childToDelete; + } else { + returnFiber.firstEffect = returnFiber.lastEffect = childToDelete; + } + childToDelete.nextEffect = null; + childToDelete.effectTag = Deletion; + } + + function deleteRemainingChildren(returnFiber, currentFirstChild) { + if (!shouldTrackSideEffects) { + // Noop. + return null; + } + + // TODO: For the shouldClone case, this could be micro-optimized a bit by + // assuming that after the first child we've already added everything. + var childToDelete = currentFirstChild; + while (childToDelete !== null) { + deleteChild(returnFiber, childToDelete); + childToDelete = childToDelete.sibling; + } + return null; + } + + function mapRemainingChildren(returnFiber, currentFirstChild) { + // Add the remaining children to a temporary map so that we can find them by + // keys quickly. Implicit (null) keys get added to this set with their index + var existingChildren = new Map(); + + var existingChild = currentFirstChild; + while (existingChild !== null) { + if (existingChild.key !== null) { + existingChildren.set(existingChild.key, existingChild); + } else { + existingChildren.set(existingChild.index, existingChild); + } + existingChild = existingChild.sibling; + } + return existingChildren; + } + + function useFiber(fiber, pendingProps, expirationTime) { + // We currently set sibling to null and index to 0 here because it is easy + // to forget to do before returning it. E.g. for the single child case. + var clone = createWorkInProgress(fiber, pendingProps, expirationTime); + clone.index = 0; + clone.sibling = null; + return clone; + } + + function placeChild(newFiber, lastPlacedIndex, newIndex) { + newFiber.index = newIndex; + if (!shouldTrackSideEffects) { + // Noop. + return lastPlacedIndex; + } + var current$$1 = newFiber.alternate; + if (current$$1 !== null) { + var oldIndex = current$$1.index; + if (oldIndex < lastPlacedIndex) { + // This is a move. + newFiber.effectTag = Placement; + return lastPlacedIndex; + } else { + // This item can stay in place. + return oldIndex; + } + } else { + // This is an insertion. + newFiber.effectTag = Placement; + return lastPlacedIndex; + } + } + + function placeSingleChild(newFiber) { + // This is simpler for the single child case. We only need to do a + // placement for inserting new children. + if (shouldTrackSideEffects && newFiber.alternate === null) { + newFiber.effectTag = Placement; + } + return newFiber; + } + + function updateTextNode( + returnFiber, + current$$1, + textContent, + expirationTime + ) { + if (current$$1 === null || current$$1.tag !== HostText) { + // Insert + var created = createFiberFromText( + textContent, + returnFiber.mode, + expirationTime + ); + created.return = returnFiber; + return created; + } else { + // Update + var existing = useFiber(current$$1, textContent, expirationTime); + existing.return = returnFiber; + return existing; + } + } + + function updateElement(returnFiber, current$$1, element, expirationTime) { + if (current$$1 !== null && current$$1.elementType === element.type) { + // Move based on index + var existing = useFiber(current$$1, element.props, expirationTime); + existing.ref = coerceRef(returnFiber, current$$1, element); + existing.return = returnFiber; + { + existing._debugSource = element._source; + existing._debugOwner = element._owner; + } + return existing; + } else { + // Insert + var created = createFiberFromElement( + element, + returnFiber.mode, + expirationTime + ); + created.ref = coerceRef(returnFiber, current$$1, element); + created.return = returnFiber; + return created; + } + } + + function updatePortal(returnFiber, current$$1, portal, expirationTime) { + if ( + current$$1 === null || + current$$1.tag !== HostPortal || + current$$1.stateNode.containerInfo !== portal.containerInfo || + current$$1.stateNode.implementation !== portal.implementation + ) { + // Insert + var created = createFiberFromPortal( + portal, + returnFiber.mode, + expirationTime + ); + created.return = returnFiber; + return created; + } else { + // Update + var existing = useFiber( + current$$1, + portal.children || [], + expirationTime + ); + existing.return = returnFiber; + return existing; + } + } + + function updateFragment( + returnFiber, + current$$1, + fragment, + expirationTime, + key + ) { + if (current$$1 === null || current$$1.tag !== Fragment) { + // Insert + var created = createFiberFromFragment( + fragment, + returnFiber.mode, + expirationTime, + key + ); + created.return = returnFiber; + return created; + } else { + // Update + var existing = useFiber(current$$1, fragment, expirationTime); + existing.return = returnFiber; + return existing; + } + } + + function createChild(returnFiber, newChild, expirationTime) { + if (typeof newChild === "string" || typeof newChild === "number") { + // Text nodes don't have keys. If the previous node is implicitly keyed + // we can continue to replace it without aborting even if it is not a text + // node. + var created = createFiberFromText( + "" + newChild, + returnFiber.mode, + expirationTime + ); + created.return = returnFiber; + return created; + } + + if (typeof newChild === "object" && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: { + var _created = createFiberFromElement( + newChild, + returnFiber.mode, + expirationTime + ); + _created.ref = coerceRef(returnFiber, null, newChild); + _created.return = returnFiber; + return _created; + } + case REACT_PORTAL_TYPE: { + var _created2 = createFiberFromPortal( + newChild, + returnFiber.mode, + expirationTime + ); + _created2.return = returnFiber; + return _created2; + } + } + + if (isArray(newChild) || getIteratorFn(newChild)) { + var _created3 = createFiberFromFragment( + newChild, + returnFiber.mode, + expirationTime, + null + ); + _created3.return = returnFiber; + return _created3; + } + + throwOnInvalidObjectType(returnFiber, newChild); + } + + { + if (typeof newChild === "function") { + warnOnFunctionType(); + } + } + + return null; + } + + function updateSlot(returnFiber, oldFiber, newChild, expirationTime) { + // Update the fiber if the keys match, otherwise return null. + + var key = oldFiber !== null ? oldFiber.key : null; + + if (typeof newChild === "string" || typeof newChild === "number") { + // Text nodes don't have keys. If the previous node is implicitly keyed + // we can continue to replace it without aborting even if it is not a text + // node. + if (key !== null) { + return null; + } + return updateTextNode( + returnFiber, + oldFiber, + "" + newChild, + expirationTime + ); + } + + if (typeof newChild === "object" && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: { + if (newChild.key === key) { + if (newChild.type === REACT_FRAGMENT_TYPE) { + return updateFragment( + returnFiber, + oldFiber, + newChild.props.children, + expirationTime, + key + ); + } + return updateElement( + returnFiber, + oldFiber, + newChild, + expirationTime + ); + } else { + return null; + } + } + case REACT_PORTAL_TYPE: { + if (newChild.key === key) { + return updatePortal( + returnFiber, + oldFiber, + newChild, + expirationTime + ); + } else { + return null; + } + } + } + + if (isArray(newChild) || getIteratorFn(newChild)) { + if (key !== null) { + return null; + } + + return updateFragment( + returnFiber, + oldFiber, + newChild, + expirationTime, + null + ); + } + + throwOnInvalidObjectType(returnFiber, newChild); + } + + { + if (typeof newChild === "function") { + warnOnFunctionType(); + } + } + + return null; + } + + function updateFromMap( + existingChildren, + returnFiber, + newIdx, + newChild, + expirationTime + ) { + if (typeof newChild === "string" || typeof newChild === "number") { + // Text nodes don't have keys, so we neither have to check the old nor + // new node for the key. If both are text nodes, they match. + var matchedFiber = existingChildren.get(newIdx) || null; + return updateTextNode( + returnFiber, + matchedFiber, + "" + newChild, + expirationTime + ); + } + + if (typeof newChild === "object" && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: { + var _matchedFiber = + existingChildren.get( + newChild.key === null ? newIdx : newChild.key + ) || null; + if (newChild.type === REACT_FRAGMENT_TYPE) { + return updateFragment( + returnFiber, + _matchedFiber, + newChild.props.children, + expirationTime, + newChild.key + ); + } + return updateElement( + returnFiber, + _matchedFiber, + newChild, + expirationTime + ); + } + case REACT_PORTAL_TYPE: { + var _matchedFiber2 = + existingChildren.get( + newChild.key === null ? newIdx : newChild.key + ) || null; + return updatePortal( + returnFiber, + _matchedFiber2, + newChild, + expirationTime + ); + } + } + + if (isArray(newChild) || getIteratorFn(newChild)) { + var _matchedFiber3 = existingChildren.get(newIdx) || null; + return updateFragment( + returnFiber, + _matchedFiber3, + newChild, + expirationTime, + null + ); + } + + throwOnInvalidObjectType(returnFiber, newChild); + } + + { + if (typeof newChild === "function") { + warnOnFunctionType(); + } + } + + return null; + } + + /** + * Warns if there is a duplicate or missing key + */ + function warnOnInvalidKey(child, knownKeys) { + { + if (typeof child !== "object" || child === null) { + return knownKeys; + } + switch (child.$$typeof) { + case REACT_ELEMENT_TYPE: + case REACT_PORTAL_TYPE: + warnForMissingKey(child); + var key = child.key; + if (typeof key !== "string") { + break; + } + if (knownKeys === null) { + knownKeys = new Set(); + knownKeys.add(key); + break; + } + if (!knownKeys.has(key)) { + knownKeys.add(key); + break; + } + warning$1( + false, + "Encountered two children with the same key, `%s`. " + + "Keys should be unique so that components maintain their identity " + + "across updates. Non-unique keys may cause children to be " + + "duplicated and/or omitted — the behavior is unsupported and " + + "could change in a future version.", + key + ); + break; + default: + break; + } + } + return knownKeys; + } + + function reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChildren, + expirationTime + ) { + // This algorithm can't optimize by searching from both ends since we + // don't have backpointers on fibers. I'm trying to see how far we can get + // with that model. If it ends up not being worth the tradeoffs, we can + // add it later. + + // Even with a two ended optimization, we'd want to optimize for the case + // where there are few changes and brute force the comparison instead of + // going for the Map. It'd like to explore hitting that path first in + // forward-only mode and only go for the Map once we notice that we need + // lots of look ahead. This doesn't handle reversal as well as two ended + // search but that's unusual. Besides, for the two ended optimization to + // work on Iterables, we'd need to copy the whole set. + + // In this first iteration, we'll just live with hitting the bad case + // (adding everything to a Map) in for every insert/move. + + // If you change this code, also update reconcileChildrenIterator() which + // uses the same algorithm. + + { + // First, validate keys. + var knownKeys = null; + for (var i = 0; i < newChildren.length; i++) { + var child = newChildren[i]; + knownKeys = warnOnInvalidKey(child, knownKeys); + } + } + + var resultingFirstChild = null; + var previousNewFiber = null; + + var oldFiber = currentFirstChild; + var lastPlacedIndex = 0; + var newIdx = 0; + var nextOldFiber = null; + for (; oldFiber !== null && newIdx < newChildren.length; newIdx++) { + if (oldFiber.index > newIdx) { + nextOldFiber = oldFiber; + oldFiber = null; + } else { + nextOldFiber = oldFiber.sibling; + } + var newFiber = updateSlot( + returnFiber, + oldFiber, + newChildren[newIdx], + expirationTime + ); + if (newFiber === null) { + // TODO: This breaks on empty slots like null children. That's + // unfortunate because it triggers the slow path all the time. We need + // a better way to communicate whether this was a miss or null, + // boolean, undefined, etc. + if (oldFiber === null) { + oldFiber = nextOldFiber; + } + break; + } + if (shouldTrackSideEffects) { + if (oldFiber && newFiber.alternate === null) { + // We matched the slot, but we didn't reuse the existing fiber, so we + // need to delete the existing child. + deleteChild(returnFiber, oldFiber); + } + } + lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = newFiber; + } else { + // TODO: Defer siblings if we're not at the right index for this slot. + // I.e. if we had null values before, then we want to defer this + // for each null value. However, we also don't want to call updateSlot + // with the previous one. + previousNewFiber.sibling = newFiber; + } + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } + + if (newIdx === newChildren.length) { + // We've reached the end of the new children. We can delete the rest. + deleteRemainingChildren(returnFiber, oldFiber); + return resultingFirstChild; + } + + if (oldFiber === null) { + // If we don't have any more existing children we can choose a fast path + // since the rest will all be insertions. + for (; newIdx < newChildren.length; newIdx++) { + var _newFiber = createChild( + returnFiber, + newChildren[newIdx], + expirationTime + ); + if (_newFiber === null) { + continue; + } + lastPlacedIndex = placeChild(_newFiber, lastPlacedIndex, newIdx); + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = _newFiber; + } else { + previousNewFiber.sibling = _newFiber; + } + previousNewFiber = _newFiber; + } + return resultingFirstChild; + } + + // Add all children to a key map for quick lookups. + var existingChildren = mapRemainingChildren(returnFiber, oldFiber); + + // Keep scanning and use the map to restore deleted items as moves. + for (; newIdx < newChildren.length; newIdx++) { + var _newFiber2 = updateFromMap( + existingChildren, + returnFiber, + newIdx, + newChildren[newIdx], + expirationTime + ); + if (_newFiber2 !== null) { + if (shouldTrackSideEffects) { + if (_newFiber2.alternate !== null) { + // The new fiber is a work in progress, but if there exists a + // current, that means that we reused the fiber. We need to delete + // it from the child list so that we don't add it to the deletion + // list. + existingChildren.delete( + _newFiber2.key === null ? newIdx : _newFiber2.key + ); + } + } + lastPlacedIndex = placeChild(_newFiber2, lastPlacedIndex, newIdx); + if (previousNewFiber === null) { + resultingFirstChild = _newFiber2; + } else { + previousNewFiber.sibling = _newFiber2; + } + previousNewFiber = _newFiber2; + } + } + + if (shouldTrackSideEffects) { + // Any existing children that weren't consumed above were deleted. We need + // to add them to the deletion list. + existingChildren.forEach(function(child) { + return deleteChild(returnFiber, child); + }); + } + + return resultingFirstChild; + } + + function reconcileChildrenIterator( + returnFiber, + currentFirstChild, + newChildrenIterable, + expirationTime + ) { + // This is the same implementation as reconcileChildrenArray(), + // but using the iterator instead. + + var iteratorFn = getIteratorFn(newChildrenIterable); + (function() { + if (!(typeof iteratorFn === "function")) { + throw ReactError( + "An object is not an iterable. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + + { + // We don't support rendering Generators because it's a mutation. + // See https://github.com/facebook/react/issues/12995 + if ( + typeof Symbol === "function" && + // $FlowFixMe Flow doesn't know about toStringTag + newChildrenIterable[Symbol.toStringTag] === "Generator" + ) { + !didWarnAboutGenerators + ? warning$1( + false, + "Using Generators as children is unsupported and will likely yield " + + "unexpected results because enumerating a generator mutates it. " + + "You may convert it to an array with `Array.from()` or the " + + "`[...spread]` operator before rendering. Keep in mind " + + "you might need to polyfill these features for older browsers." + ) + : void 0; + didWarnAboutGenerators = true; + } + + // Warn about using Maps as children + if (newChildrenIterable.entries === iteratorFn) { + !didWarnAboutMaps + ? warning$1( + false, + "Using Maps as children is unsupported and will likely yield " + + "unexpected results. Convert it to a sequence/iterable of keyed " + + "ReactElements instead." + ) + : void 0; + didWarnAboutMaps = true; + } + + // First, validate keys. + // We'll get a different iterator later for the main pass. + var _newChildren = iteratorFn.call(newChildrenIterable); + if (_newChildren) { + var knownKeys = null; + var _step = _newChildren.next(); + for (; !_step.done; _step = _newChildren.next()) { + var child = _step.value; + knownKeys = warnOnInvalidKey(child, knownKeys); + } + } + } + + var newChildren = iteratorFn.call(newChildrenIterable); + (function() { + if (!(newChildren != null)) { + throw ReactError("An iterable object provided no iterator."); + } + })(); + + var resultingFirstChild = null; + var previousNewFiber = null; + + var oldFiber = currentFirstChild; + var lastPlacedIndex = 0; + var newIdx = 0; + var nextOldFiber = null; + + var step = newChildren.next(); + for ( + ; + oldFiber !== null && !step.done; + newIdx++, step = newChildren.next() + ) { + if (oldFiber.index > newIdx) { + nextOldFiber = oldFiber; + oldFiber = null; + } else { + nextOldFiber = oldFiber.sibling; + } + var newFiber = updateSlot( + returnFiber, + oldFiber, + step.value, + expirationTime + ); + if (newFiber === null) { + // TODO: This breaks on empty slots like null children. That's + // unfortunate because it triggers the slow path all the time. We need + // a better way to communicate whether this was a miss or null, + // boolean, undefined, etc. + if (oldFiber === null) { + oldFiber = nextOldFiber; + } + break; + } + if (shouldTrackSideEffects) { + if (oldFiber && newFiber.alternate === null) { + // We matched the slot, but we didn't reuse the existing fiber, so we + // need to delete the existing child. + deleteChild(returnFiber, oldFiber); + } + } + lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = newFiber; + } else { + // TODO: Defer siblings if we're not at the right index for this slot. + // I.e. if we had null values before, then we want to defer this + // for each null value. However, we also don't want to call updateSlot + // with the previous one. + previousNewFiber.sibling = newFiber; + } + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } + + if (step.done) { + // We've reached the end of the new children. We can delete the rest. + deleteRemainingChildren(returnFiber, oldFiber); + return resultingFirstChild; + } + + if (oldFiber === null) { + // If we don't have any more existing children we can choose a fast path + // since the rest will all be insertions. + for (; !step.done; newIdx++, step = newChildren.next()) { + var _newFiber3 = createChild(returnFiber, step.value, expirationTime); + if (_newFiber3 === null) { + continue; + } + lastPlacedIndex = placeChild(_newFiber3, lastPlacedIndex, newIdx); + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = _newFiber3; + } else { + previousNewFiber.sibling = _newFiber3; + } + previousNewFiber = _newFiber3; + } + return resultingFirstChild; + } + + // Add all children to a key map for quick lookups. + var existingChildren = mapRemainingChildren(returnFiber, oldFiber); + + // Keep scanning and use the map to restore deleted items as moves. + for (; !step.done; newIdx++, step = newChildren.next()) { + var _newFiber4 = updateFromMap( + existingChildren, + returnFiber, + newIdx, + step.value, + expirationTime + ); + if (_newFiber4 !== null) { + if (shouldTrackSideEffects) { + if (_newFiber4.alternate !== null) { + // The new fiber is a work in progress, but if there exists a + // current, that means that we reused the fiber. We need to delete + // it from the child list so that we don't add it to the deletion + // list. + existingChildren.delete( + _newFiber4.key === null ? newIdx : _newFiber4.key + ); + } + } + lastPlacedIndex = placeChild(_newFiber4, lastPlacedIndex, newIdx); + if (previousNewFiber === null) { + resultingFirstChild = _newFiber4; + } else { + previousNewFiber.sibling = _newFiber4; + } + previousNewFiber = _newFiber4; + } + } + + if (shouldTrackSideEffects) { + // Any existing children that weren't consumed above were deleted. We need + // to add them to the deletion list. + existingChildren.forEach(function(child) { + return deleteChild(returnFiber, child); + }); + } + + return resultingFirstChild; + } + + function reconcileSingleTextNode( + returnFiber, + currentFirstChild, + textContent, + expirationTime + ) { + // There's no need to check for keys on text nodes since we don't have a + // way to define them. + if (currentFirstChild !== null && currentFirstChild.tag === HostText) { + // We already have an existing node so let's just update it and delete + // the rest. + deleteRemainingChildren(returnFiber, currentFirstChild.sibling); + var existing = useFiber(currentFirstChild, textContent, expirationTime); + existing.return = returnFiber; + return existing; + } + // The existing first child is not a text node so we need to create one + // and delete the existing ones. + deleteRemainingChildren(returnFiber, currentFirstChild); + var created = createFiberFromText( + textContent, + returnFiber.mode, + expirationTime + ); + created.return = returnFiber; + return created; + } + + function reconcileSingleElement( + returnFiber, + currentFirstChild, + element, + expirationTime + ) { + var key = element.key; + var child = currentFirstChild; + while (child !== null) { + // TODO: If key === null and child.key === null, then this only applies to + // the first item in the list. + if (child.key === key) { + if ( + child.tag === Fragment + ? element.type === REACT_FRAGMENT_TYPE + : child.elementType === element.type + ) { + deleteRemainingChildren(returnFiber, child.sibling); + var existing = useFiber( + child, + element.type === REACT_FRAGMENT_TYPE + ? element.props.children + : element.props, + expirationTime + ); + existing.ref = coerceRef(returnFiber, child, element); + existing.return = returnFiber; + { + existing._debugSource = element._source; + existing._debugOwner = element._owner; + } + return existing; + } else { + deleteRemainingChildren(returnFiber, child); + break; + } + } else { + deleteChild(returnFiber, child); + } + child = child.sibling; + } + + if (element.type === REACT_FRAGMENT_TYPE) { + var created = createFiberFromFragment( + element.props.children, + returnFiber.mode, + expirationTime, + element.key + ); + created.return = returnFiber; + return created; + } else { + var _created4 = createFiberFromElement( + element, + returnFiber.mode, + expirationTime + ); + _created4.ref = coerceRef(returnFiber, currentFirstChild, element); + _created4.return = returnFiber; + return _created4; + } + } + + function reconcileSinglePortal( + returnFiber, + currentFirstChild, + portal, + expirationTime + ) { + var key = portal.key; + var child = currentFirstChild; + while (child !== null) { + // TODO: If key === null and child.key === null, then this only applies to + // the first item in the list. + if (child.key === key) { + if ( + child.tag === HostPortal && + child.stateNode.containerInfo === portal.containerInfo && + child.stateNode.implementation === portal.implementation + ) { + deleteRemainingChildren(returnFiber, child.sibling); + var existing = useFiber(child, portal.children || [], expirationTime); + existing.return = returnFiber; + return existing; + } else { + deleteRemainingChildren(returnFiber, child); + break; + } + } else { + deleteChild(returnFiber, child); + } + child = child.sibling; + } + + var created = createFiberFromPortal( + portal, + returnFiber.mode, + expirationTime + ); + created.return = returnFiber; + return created; + } + + // This API will tag the children with the side-effect of the reconciliation + // itself. They will be added to the side-effect list as we pass through the + // children and the parent. + function reconcileChildFibers( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ) { + // This function is not recursive. + // If the top level item is an array, we treat it as a set of children, + // not as a fragment. Nested arrays on the other hand will be treated as + // fragment nodes. Recursion happens at the normal flow. + + // Handle top level unkeyed fragments as if they were arrays. + // This leads to an ambiguity between <>{[...]} and <>.... + // We treat the ambiguous cases above the same. + var isUnkeyedTopLevelFragment = + typeof newChild === "object" && + newChild !== null && + newChild.type === REACT_FRAGMENT_TYPE && + newChild.key === null; + if (isUnkeyedTopLevelFragment) { + newChild = newChild.props.children; + } + + // Handle object types + var isObject = typeof newChild === "object" && newChild !== null; + + if (isObject) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return placeSingleChild( + reconcileSingleElement( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ) + ); + case REACT_PORTAL_TYPE: + return placeSingleChild( + reconcileSinglePortal( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ) + ); + } + } + + if (typeof newChild === "string" || typeof newChild === "number") { + return placeSingleChild( + reconcileSingleTextNode( + returnFiber, + currentFirstChild, + "" + newChild, + expirationTime + ) + ); + } + + if (isArray(newChild)) { + return reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ); + } + + if (getIteratorFn(newChild)) { + return reconcileChildrenIterator( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ); + } + + if (isObject) { + throwOnInvalidObjectType(returnFiber, newChild); + } + + { + if (typeof newChild === "function") { + warnOnFunctionType(); + } + } + if (typeof newChild === "undefined" && !isUnkeyedTopLevelFragment) { + // If the new child is undefined, and the return fiber is a composite + // component, throw an error. If Fiber return types are disabled, + // we already threw above. + switch (returnFiber.tag) { + case ClassComponent: { + { + var instance = returnFiber.stateNode; + if (instance.render._isMockFunction) { + // We allow auto-mocks to proceed as if they're returning null. + break; + } + } + } + // Intentionally fall through to the next case, which handles both + // functions and classes + // eslint-disable-next-lined no-fallthrough + case FunctionComponent: { + var Component = returnFiber.type; + (function() { + { + throw ReactError( + (Component.displayName || Component.name || "Component") + + "(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null." + ); + } + })(); + } + } + } + + // Remaining cases are all treated as empty. + return deleteRemainingChildren(returnFiber, currentFirstChild); + } + + return reconcileChildFibers; +} + +var reconcileChildFibers = ChildReconciler(true); +var mountChildFibers = ChildReconciler(false); + +function cloneChildFibers(current$$1, workInProgress) { + (function() { + if (!(current$$1 === null || workInProgress.child === current$$1.child)) { + throw ReactError("Resuming work not yet implemented."); + } + })(); + + if (workInProgress.child === null) { + return; + } + + var currentChild = workInProgress.child; + var newChild = createWorkInProgress( + currentChild, + currentChild.pendingProps, + currentChild.expirationTime + ); + workInProgress.child = newChild; + + newChild.return = workInProgress; + while (currentChild.sibling !== null) { + currentChild = currentChild.sibling; + newChild = newChild.sibling = createWorkInProgress( + currentChild, + currentChild.pendingProps, + currentChild.expirationTime + ); + newChild.return = workInProgress; + } + newChild.sibling = null; +} + +var NO_CONTEXT = {}; + +var contextStackCursor$1 = createCursor(NO_CONTEXT); +var contextFiberStackCursor = createCursor(NO_CONTEXT); +var rootInstanceStackCursor = createCursor(NO_CONTEXT); + +function requiredContext(c) { + (function() { + if (!(c !== NO_CONTEXT)) { + throw ReactError( + "Expected host context to exist. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + return c; +} + +function getRootHostContainer() { + var rootInstance = requiredContext(rootInstanceStackCursor.current); + return rootInstance; +} + +function pushHostContainer(fiber, nextRootInstance) { + // Push current root instance onto the stack; + // This allows us to reset root when portals are popped. + push(rootInstanceStackCursor, nextRootInstance, fiber); + // Track the context and the Fiber that provided it. + // This enables us to pop only Fibers that provide unique contexts. + push(contextFiberStackCursor, fiber, fiber); + + // Finally, we need to push the host context to the stack. + // However, we can't just call getRootHostContext() and push it because + // we'd have a different number of entries on the stack depending on + // whether getRootHostContext() throws somewhere in renderer code or not. + // So we push an empty value first. This lets us safely unwind on errors. + push(contextStackCursor$1, NO_CONTEXT, fiber); + var nextRootContext = getRootHostContext(nextRootInstance); + // Now that we know this function doesn't throw, replace it. + pop(contextStackCursor$1, fiber); + push(contextStackCursor$1, nextRootContext, fiber); +} + +function popHostContainer(fiber) { + pop(contextStackCursor$1, fiber); + pop(contextFiberStackCursor, fiber); + pop(rootInstanceStackCursor, fiber); +} + +function getHostContext() { + var context = requiredContext(contextStackCursor$1.current); + return context; +} + +function pushHostContext(fiber) { + var rootInstance = requiredContext(rootInstanceStackCursor.current); + var context = requiredContext(contextStackCursor$1.current); + var nextContext = getChildHostContext(context, fiber.type, rootInstance); + + // Don't push this Fiber's context unless it's unique. + if (context === nextContext) { + return; + } + + // Track the context and the Fiber that provided it. + // This enables us to pop only Fibers that provide unique contexts. + push(contextFiberStackCursor, fiber, fiber); + push(contextStackCursor$1, nextContext, fiber); +} + +function pushHostContextForEventComponent(fiber) { + var context = requiredContext(contextStackCursor$1.current); + var nextContext = getChildHostContextForEventComponent(context); + + // Don't push this Fiber's context unless it's unique. + if (context === nextContext) { + return; + } + + // Track the context and the Fiber that provided it. + // This enables us to pop only Fibers that provide unique contexts. + push(contextFiberStackCursor, fiber, fiber); + push(contextStackCursor$1, nextContext, fiber); +} + +function pushHostContextForEventTarget(fiber) { + var context = requiredContext(contextStackCursor$1.current); + var eventTargetType = fiber.type.type; + var nextContext = getChildHostContextForEventTarget(context, eventTargetType); + + // Don't push this Fiber's context unless it's unique. + if (context === nextContext) { + return; + } + + // Track the context and the Fiber that provided it. + // This enables us to pop only Fibers that provide unique contexts. + push(contextFiberStackCursor, fiber, fiber); + push(contextStackCursor$1, nextContext, fiber); +} + +function popHostContext(fiber) { + // Do not pop unless this Fiber provided the current context. + // pushHostContext() only pushes Fibers that provide unique contexts. + if (contextFiberStackCursor.current !== fiber) { + return; + } + + pop(contextStackCursor$1, fiber); + pop(contextFiberStackCursor, fiber); +} + +var NoEffect$1 = /* */ 0; +var UnmountSnapshot = /* */ 2; +var UnmountMutation = /* */ 4; +var MountMutation = /* */ 8; +var UnmountLayout = /* */ 16; +var MountLayout = /* */ 32; +var MountPassive = /* */ 64; +var UnmountPassive = /* */ 128; + +var ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher; + +var didWarnAboutMismatchedHooksForComponent = void 0; +{ + didWarnAboutMismatchedHooksForComponent = new Set(); +} + +// These are set right before calling the component. +var renderExpirationTime$1 = NoWork; +// The work-in-progress fiber. I've named it differently to distinguish it from +// the work-in-progress hook. +var currentlyRenderingFiber$1 = null; + +// Hooks are stored as a linked list on the fiber's memoizedState field. The +// current hook list is the list that belongs to the current fiber. The +// work-in-progress hook list is a new list that will be added to the +// work-in-progress fiber. +var currentHook = null; +var nextCurrentHook = null; +var firstWorkInProgressHook = null; +var workInProgressHook = null; +var nextWorkInProgressHook = null; + +var remainingExpirationTime = NoWork; +var componentUpdateQueue = null; +var sideEffectTag = 0; + +// Updates scheduled during render will trigger an immediate re-render at the +// end of the current pass. We can't store these updates on the normal queue, +// because if the work is aborted, they should be discarded. Because this is +// a relatively rare case, we also don't want to add an additional field to +// either the hook or queue object types. So we store them in a lazily create +// map of queue -> render-phase updates, which are discarded once the component +// completes without re-rendering. + +// Whether an update was scheduled during the currently executing render pass. +var didScheduleRenderPhaseUpdate = false; +// Lazily created map of render-phase updates +var renderPhaseUpdates = null; +// Counter to prevent infinite loops. +var numberOfReRenders = 0; +var RE_RENDER_LIMIT = 25; + +// In DEV, this is the name of the currently executing primitive hook +var currentHookNameInDev = null; + +// In DEV, this list ensures that hooks are called in the same order between renders. +// The list stores the order of hooks used during the initial render (mount). +// Subsequent renders (updates) reference this list. +var hookTypesDev = null; +var hookTypesUpdateIndexDev = -1; + +function mountHookTypesDev() { + { + var hookName = currentHookNameInDev; + + if (hookTypesDev === null) { + hookTypesDev = [hookName]; + } else { + hookTypesDev.push(hookName); + } + } +} + +function updateHookTypesDev() { + { + var hookName = currentHookNameInDev; + + if (hookTypesDev !== null) { + hookTypesUpdateIndexDev++; + if (hookTypesDev[hookTypesUpdateIndexDev] !== hookName) { + warnOnHookMismatchInDev(hookName); + } + } + } +} + +function checkDepsAreArrayDev(deps) { + { + if (deps !== undefined && deps !== null && !Array.isArray(deps)) { + // Verify deps, but only on mount to avoid extra checks. + // It's unlikely their type would change as usually you define them inline. + warning$1( + false, + "%s received a final argument that is not an array (instead, received `%s`). When " + + "specified, the final argument must be an array.", + currentHookNameInDev, + typeof deps + ); + } + } +} + +function warnOnHookMismatchInDev(currentHookName) { + { + var componentName = getComponentName(currentlyRenderingFiber$1.type); + if (!didWarnAboutMismatchedHooksForComponent.has(componentName)) { + didWarnAboutMismatchedHooksForComponent.add(componentName); + + if (hookTypesDev !== null) { + var table = ""; + + var secondColumnStart = 30; + + for (var i = 0; i <= hookTypesUpdateIndexDev; i++) { + var oldHookName = hookTypesDev[i]; + var newHookName = + i === hookTypesUpdateIndexDev ? currentHookName : oldHookName; + + var row = i + 1 + ". " + oldHookName; + + // Extra space so second column lines up + // lol @ IE not supporting String#repeat + while (row.length < secondColumnStart) { + row += " "; + } + + row += newHookName + "\n"; + + table += row; + } + + warning$1( + false, + "React has detected a change in the order of Hooks called by %s. " + + "This will lead to bugs and errors if not fixed. " + + "For more information, read the Rules of Hooks: https://fb.me/rules-of-hooks\n\n" + + " Previous render Next render\n" + + " ------------------------------------------------------\n" + + "%s" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + componentName, + table + ); + } + } + } +} + +function throwInvalidHookError() { + (function() { + { + throw ReactError( + "Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:\n1. You might have mismatching versions of React and the renderer (such as React DOM)\n2. You might be breaking the Rules of Hooks\n3. You might have more than one copy of React in the same app\nSee https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem." + ); + } + })(); +} + +function areHookInputsEqual(nextDeps, prevDeps) { + if (prevDeps === null) { + { + warning$1( + false, + "%s received a final argument during this render, but not during " + + "the previous render. Even though the final argument is optional, " + + "its type cannot change between renders.", + currentHookNameInDev + ); + } + return false; + } + + { + // Don't bother comparing lengths in prod because these arrays should be + // passed inline. + if (nextDeps.length !== prevDeps.length) { + warning$1( + false, + "The final argument passed to %s changed size between renders. The " + + "order and size of this array must remain constant.\n\n" + + "Previous: %s\n" + + "Incoming: %s", + currentHookNameInDev, + "[" + prevDeps.join(", ") + "]", + "[" + nextDeps.join(", ") + "]" + ); + } + } + for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++) { + if (is(nextDeps[i], prevDeps[i])) { + continue; + } + return false; + } + return true; +} + +function renderWithHooks( + current, + workInProgress, + Component, + props, + refOrContext, + nextRenderExpirationTime +) { + renderExpirationTime$1 = nextRenderExpirationTime; + currentlyRenderingFiber$1 = workInProgress; + nextCurrentHook = current !== null ? current.memoizedState : null; + + { + hookTypesDev = current !== null ? current._debugHookTypes : null; + hookTypesUpdateIndexDev = -1; + } + + // The following should have already been reset + // currentHook = null; + // workInProgressHook = null; + + // remainingExpirationTime = NoWork; + // componentUpdateQueue = null; + + // didScheduleRenderPhaseUpdate = false; + // renderPhaseUpdates = null; + // numberOfReRenders = 0; + // sideEffectTag = 0; + + // TODO Warn if no hooks are used at all during mount, then some are used during update. + // Currently we will identify the update render as a mount because nextCurrentHook === null. + // This is tricky because it's valid for certain types of components (e.g. React.lazy) + + // Using nextCurrentHook to differentiate between mount/update only works if at least one stateful hook is used. + // Non-stateful hooks (e.g. context) don't get added to memoizedState, + // so nextCurrentHook would be null during updates and mounts. + { + if (nextCurrentHook !== null) { + ReactCurrentDispatcher$1.current = HooksDispatcherOnUpdateInDEV; + } else if (hookTypesDev !== null) { + // This dispatcher handles an edge case where a component is updating, + // but no stateful hooks have been used. + // We want to match the production code behavior (which will use HooksDispatcherOnMount), + // but with the extra DEV validation to ensure hooks ordering hasn't changed. + // This dispatcher does that. + ReactCurrentDispatcher$1.current = HooksDispatcherOnMountWithHookTypesInDEV; + } else { + ReactCurrentDispatcher$1.current = HooksDispatcherOnMountInDEV; + } + } + + var children = Component(props, refOrContext); + + if (didScheduleRenderPhaseUpdate) { + do { + didScheduleRenderPhaseUpdate = false; + numberOfReRenders += 1; + + // Start over from the beginning of the list + nextCurrentHook = current !== null ? current.memoizedState : null; + nextWorkInProgressHook = firstWorkInProgressHook; + + currentHook = null; + workInProgressHook = null; + componentUpdateQueue = null; + + { + // Also validate hook order for cascading updates. + hookTypesUpdateIndexDev = -1; + } + + ReactCurrentDispatcher$1.current = HooksDispatcherOnUpdateInDEV; + + children = Component(props, refOrContext); + } while (didScheduleRenderPhaseUpdate); + + renderPhaseUpdates = null; + numberOfReRenders = 0; + } + + // We can assume the previous dispatcher is always this one, since we set it + // at the beginning of the render phase and there's no re-entrancy. + ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; + + var renderedWork = currentlyRenderingFiber$1; + + renderedWork.memoizedState = firstWorkInProgressHook; + renderedWork.expirationTime = remainingExpirationTime; + renderedWork.updateQueue = componentUpdateQueue; + renderedWork.effectTag |= sideEffectTag; + + { + renderedWork._debugHookTypes = hookTypesDev; + } + + // This check uses currentHook so that it works the same in DEV and prod bundles. + // hookTypesDev could catch more cases (e.g. context) but only in DEV bundles. + var didRenderTooFewHooks = currentHook !== null && currentHook.next !== null; + + renderExpirationTime$1 = NoWork; + currentlyRenderingFiber$1 = null; + + currentHook = null; + nextCurrentHook = null; + firstWorkInProgressHook = null; + workInProgressHook = null; + nextWorkInProgressHook = null; + + { + currentHookNameInDev = null; + hookTypesDev = null; + hookTypesUpdateIndexDev = -1; + } + + remainingExpirationTime = NoWork; + componentUpdateQueue = null; + sideEffectTag = 0; + + // These were reset above + // didScheduleRenderPhaseUpdate = false; + // renderPhaseUpdates = null; + // numberOfReRenders = 0; + + (function() { + if (!!didRenderTooFewHooks) { + throw ReactError( + "Rendered fewer hooks than expected. This may be caused by an accidental early return statement." + ); + } + })(); + + return children; +} + +function bailoutHooks(current, workInProgress, expirationTime) { + workInProgress.updateQueue = current.updateQueue; + workInProgress.effectTag &= ~(Passive | Update); + if (current.expirationTime <= expirationTime) { + current.expirationTime = NoWork; + } +} + +function resetHooks() { + // We can assume the previous dispatcher is always this one, since we set it + // at the beginning of the render phase and there's no re-entrancy. + ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; + + // This is used to reset the state of this module when a component throws. + // It's also called inside mountIndeterminateComponent if we determine the + // component is a module-style component. + renderExpirationTime$1 = NoWork; + currentlyRenderingFiber$1 = null; + + currentHook = null; + nextCurrentHook = null; + firstWorkInProgressHook = null; + workInProgressHook = null; + nextWorkInProgressHook = null; + + { + hookTypesDev = null; + hookTypesUpdateIndexDev = -1; + + currentHookNameInDev = null; + } + + remainingExpirationTime = NoWork; + componentUpdateQueue = null; + sideEffectTag = 0; + + didScheduleRenderPhaseUpdate = false; + renderPhaseUpdates = null; + numberOfReRenders = 0; +} + +function mountWorkInProgressHook() { + var hook = { + memoizedState: null, + + baseState: null, + queue: null, + baseUpdate: null, + + next: null + }; + + if (workInProgressHook === null) { + // This is the first hook in the list + firstWorkInProgressHook = workInProgressHook = hook; + } else { + // Append to the end of the list + workInProgressHook = workInProgressHook.next = hook; + } + return workInProgressHook; +} + +function updateWorkInProgressHook() { + // This function is used both for updates and for re-renders triggered by a + // render phase update. It assumes there is either a current hook we can + // clone, or a work-in-progress hook from a previous render pass that we can + // use as a base. When we reach the end of the base list, we must switch to + // the dispatcher used for mounts. + if (nextWorkInProgressHook !== null) { + // There's already a work-in-progress. Reuse it. + workInProgressHook = nextWorkInProgressHook; + nextWorkInProgressHook = workInProgressHook.next; + + currentHook = nextCurrentHook; + nextCurrentHook = currentHook !== null ? currentHook.next : null; + } else { + // Clone from the current hook. + (function() { + if (!(nextCurrentHook !== null)) { + throw ReactError( + "Rendered more hooks than during the previous render." + ); + } + })(); + currentHook = nextCurrentHook; + + var newHook = { + memoizedState: currentHook.memoizedState, + + baseState: currentHook.baseState, + queue: currentHook.queue, + baseUpdate: currentHook.baseUpdate, + + next: null + }; + + if (workInProgressHook === null) { + // This is the first hook in the list. + workInProgressHook = firstWorkInProgressHook = newHook; + } else { + // Append to the end of the list. + workInProgressHook = workInProgressHook.next = newHook; + } + nextCurrentHook = currentHook.next; + } + return workInProgressHook; +} + +function createFunctionComponentUpdateQueue() { + return { + lastEffect: null + }; +} + +function basicStateReducer(state, action) { + return typeof action === "function" ? action(state) : action; +} + +function mountReducer(reducer, initialArg, init) { + var hook = mountWorkInProgressHook(); + var initialState = void 0; + if (init !== undefined) { + initialState = init(initialArg); + } else { + initialState = initialArg; + } + hook.memoizedState = hook.baseState = initialState; + var queue = (hook.queue = { + last: null, + dispatch: null, + lastRenderedReducer: reducer, + lastRenderedState: initialState + }); + var dispatch = (queue.dispatch = dispatchAction.bind( + null, + // Flow doesn't know this is non-null, but we do. + currentlyRenderingFiber$1, + queue + )); + return [hook.memoizedState, dispatch]; +} + +function updateReducer(reducer, initialArg, init) { + var hook = updateWorkInProgressHook(); + var queue = hook.queue; + (function() { + if (!(queue !== null)) { + throw ReactError( + "Should have a queue. This is likely a bug in React. Please file an issue." + ); + } + })(); + + queue.lastRenderedReducer = reducer; + + if (numberOfReRenders > 0) { + // This is a re-render. Apply the new render phase updates to the previous + var _dispatch = queue.dispatch; + if (renderPhaseUpdates !== null) { + // Render phase updates are stored in a map of queue -> linked list + var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue); + if (firstRenderPhaseUpdate !== undefined) { + renderPhaseUpdates.delete(queue); + var newState = hook.memoizedState; + var update = firstRenderPhaseUpdate; + do { + // Process this render phase update. We don't have to check the + // priority because it will always be the same as the current + // render's. + var _action = update.action; + newState = reducer(newState, _action); + update = update.next; + } while (update !== null); + + // Mark that the fiber performed work, but only if the new state is + // different from the current state. + if (!is(newState, hook.memoizedState)) { + markWorkInProgressReceivedUpdate(); + } + + hook.memoizedState = newState; + // Don't persist the state accumlated from the render phase updates to + // the base state unless the queue is empty. + // TODO: Not sure if this is the desired semantics, but it's what we + // do for gDSFP. I can't remember why. + if (hook.baseUpdate === queue.last) { + hook.baseState = newState; + } + + queue.lastRenderedState = newState; + + return [newState, _dispatch]; + } + } + return [hook.memoizedState, _dispatch]; + } + + // The last update in the entire queue + var last = queue.last; + // The last update that is part of the base state. + var baseUpdate = hook.baseUpdate; + var baseState = hook.baseState; + + // Find the first unprocessed update. + var first = void 0; + if (baseUpdate !== null) { + if (last !== null) { + // For the first update, the queue is a circular linked list where + // `queue.last.next = queue.first`. Once the first update commits, and + // the `baseUpdate` is no longer empty, we can unravel the list. + last.next = null; + } + first = baseUpdate.next; + } else { + first = last !== null ? last.next : null; + } + if (first !== null) { + var _newState = baseState; + var newBaseState = null; + var newBaseUpdate = null; + var prevUpdate = baseUpdate; + var _update = first; + var didSkip = false; + do { + var updateExpirationTime = _update.expirationTime; + if (updateExpirationTime < renderExpirationTime$1) { + // Priority is insufficient. Skip this update. If this is the first + // skipped update, the previous update/state is the new base + // update/state. + if (!didSkip) { + didSkip = true; + newBaseUpdate = prevUpdate; + newBaseState = _newState; + } + // Update the remaining priority in the queue. + if (updateExpirationTime > remainingExpirationTime) { + remainingExpirationTime = updateExpirationTime; + } + } else { + // This update does have sufficient priority. + + // Mark the event time of this update as relevant to this render pass. + // TODO: This should ideally use the true event time of this update rather than + // its priority which is a derived and not reverseable value. + // TODO: We should skip this update if it was already committed but currently + // we have no way of detecting the difference between a committed and suspended + // update here. + markRenderEventTime(updateExpirationTime); + + // Process this update. + if (_update.eagerReducer === reducer) { + // If this update was processed eagerly, and its reducer matches the + // current reducer, we can use the eagerly computed state. + _newState = _update.eagerState; + } else { + var _action2 = _update.action; + _newState = reducer(_newState, _action2); + } + } + prevUpdate = _update; + _update = _update.next; + } while (_update !== null && _update !== first); + + if (!didSkip) { + newBaseUpdate = prevUpdate; + newBaseState = _newState; + } + + // Mark that the fiber performed work, but only if the new state is + // different from the current state. + if (!is(_newState, hook.memoizedState)) { + markWorkInProgressReceivedUpdate(); + } + + hook.memoizedState = _newState; + hook.baseUpdate = newBaseUpdate; + hook.baseState = newBaseState; + + queue.lastRenderedState = _newState; + } + + var dispatch = queue.dispatch; + return [hook.memoizedState, dispatch]; +} + +function mountState(initialState) { + var hook = mountWorkInProgressHook(); + if (typeof initialState === "function") { + initialState = initialState(); + } + hook.memoizedState = hook.baseState = initialState; + var queue = (hook.queue = { + last: null, + dispatch: null, + lastRenderedReducer: basicStateReducer, + lastRenderedState: initialState + }); + var dispatch = (queue.dispatch = dispatchAction.bind( + null, + // Flow doesn't know this is non-null, but we do. + currentlyRenderingFiber$1, + queue + )); + return [hook.memoizedState, dispatch]; +} + +function updateState(initialState) { + return updateReducer(basicStateReducer, initialState); +} + +function pushEffect(tag, create, destroy, deps) { + var effect = { + tag: tag, + create: create, + destroy: destroy, + deps: deps, + // Circular + next: null + }; + if (componentUpdateQueue === null) { + componentUpdateQueue = createFunctionComponentUpdateQueue(); + componentUpdateQueue.lastEffect = effect.next = effect; + } else { + var _lastEffect = componentUpdateQueue.lastEffect; + if (_lastEffect === null) { + componentUpdateQueue.lastEffect = effect.next = effect; + } else { + var firstEffect = _lastEffect.next; + _lastEffect.next = effect; + effect.next = firstEffect; + componentUpdateQueue.lastEffect = effect; + } + } + return effect; +} + +function mountRef(initialValue) { + var hook = mountWorkInProgressHook(); + var ref = { current: initialValue }; + { + Object.seal(ref); + } + hook.memoizedState = ref; + return ref; +} + +function updateRef(initialValue) { + var hook = updateWorkInProgressHook(); + return hook.memoizedState; +} + +function mountEffectImpl(fiberEffectTag, hookEffectTag, create, deps) { + var hook = mountWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + sideEffectTag |= fiberEffectTag; + hook.memoizedState = pushEffect(hookEffectTag, create, undefined, nextDeps); +} + +function updateEffectImpl(fiberEffectTag, hookEffectTag, create, deps) { + var hook = updateWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + var destroy = undefined; + + if (currentHook !== null) { + var prevEffect = currentHook.memoizedState; + destroy = prevEffect.destroy; + if (nextDeps !== null) { + var prevDeps = prevEffect.deps; + if (areHookInputsEqual(nextDeps, prevDeps)) { + pushEffect(NoEffect$1, create, destroy, nextDeps); + return; + } + } + } + + sideEffectTag |= fiberEffectTag; + hook.memoizedState = pushEffect(hookEffectTag, create, destroy, nextDeps); +} + +function mountEffect(create, deps) { + return mountEffectImpl( + Update | Passive, + UnmountPassive | MountPassive, + create, + deps + ); +} + +function updateEffect(create, deps) { + return updateEffectImpl( + Update | Passive, + UnmountPassive | MountPassive, + create, + deps + ); +} + +function mountLayoutEffect(create, deps) { + return mountEffectImpl(Update, UnmountMutation | MountLayout, create, deps); +} + +function updateLayoutEffect(create, deps) { + return updateEffectImpl(Update, UnmountMutation | MountLayout, create, deps); +} + +function imperativeHandleEffect(create, ref) { + if (typeof ref === "function") { + var refCallback = ref; + var _inst = create(); + refCallback(_inst); + return function() { + refCallback(null); + }; + } else if (ref !== null && ref !== undefined) { + var refObject = ref; + { + !refObject.hasOwnProperty("current") + ? warning$1( + false, + "Expected useImperativeHandle() first argument to either be a " + + "ref callback or React.createRef() object. Instead received: %s.", + "an object with keys {" + Object.keys(refObject).join(", ") + "}" + ) + : void 0; + } + var _inst2 = create(); + refObject.current = _inst2; + return function() { + refObject.current = null; + }; + } +} + +function mountImperativeHandle(ref, create, deps) { + { + !(typeof create === "function") + ? warning$1( + false, + "Expected useImperativeHandle() second argument to be a function " + + "that creates a handle. Instead received: %s.", + create !== null ? typeof create : "null" + ) + : void 0; + } + + // TODO: If deps are provided, should we skip comparing the ref itself? + var effectDeps = + deps !== null && deps !== undefined ? deps.concat([ref]) : null; + + return mountEffectImpl( + Update, + UnmountMutation | MountLayout, + imperativeHandleEffect.bind(null, create, ref), + effectDeps + ); +} + +function updateImperativeHandle(ref, create, deps) { + { + !(typeof create === "function") + ? warning$1( + false, + "Expected useImperativeHandle() second argument to be a function " + + "that creates a handle. Instead received: %s.", + create !== null ? typeof create : "null" + ) + : void 0; + } + + // TODO: If deps are provided, should we skip comparing the ref itself? + var effectDeps = + deps !== null && deps !== undefined ? deps.concat([ref]) : null; + + return updateEffectImpl( + Update, + UnmountMutation | MountLayout, + imperativeHandleEffect.bind(null, create, ref), + effectDeps + ); +} + +function mountDebugValue(value, formatterFn) { + // This hook is normally a no-op. + // The react-debug-hooks package injects its own implementation + // so that e.g. DevTools can display custom hook values. +} + +var updateDebugValue = mountDebugValue; + +function mountCallback(callback, deps) { + var hook = mountWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + hook.memoizedState = [callback, nextDeps]; + return callback; +} + +function updateCallback(callback, deps) { + var hook = updateWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + var prevState = hook.memoizedState; + if (prevState !== null) { + if (nextDeps !== null) { + var prevDeps = prevState[1]; + if (areHookInputsEqual(nextDeps, prevDeps)) { + return prevState[0]; + } + } + } + hook.memoizedState = [callback, nextDeps]; + return callback; +} + +function mountMemo(nextCreate, deps) { + var hook = mountWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + var nextValue = nextCreate(); + hook.memoizedState = [nextValue, nextDeps]; + return nextValue; +} + +function updateMemo(nextCreate, deps) { + var hook = updateWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + var prevState = hook.memoizedState; + if (prevState !== null) { + // Assume these are defined. If they're not, areHookInputsEqual will warn. + if (nextDeps !== null) { + var prevDeps = prevState[1]; + if (areHookInputsEqual(nextDeps, prevDeps)) { + return prevState[0]; + } + } + } + var nextValue = nextCreate(); + hook.memoizedState = [nextValue, nextDeps]; + return nextValue; +} + +function dispatchAction(fiber, queue, action) { + (function() { + if (!(numberOfReRenders < RE_RENDER_LIMIT)) { + throw ReactError( + "Too many re-renders. React limits the number of renders to prevent an infinite loop." + ); + } + })(); + + { + !(arguments.length <= 3) + ? warning$1( + false, + "State updates from the useState() and useReducer() Hooks don't support the " + + "second callback argument. To execute a side effect after " + + "rendering, declare it in the component body with useEffect()." + ) + : void 0; + } + + var alternate = fiber.alternate; + if ( + fiber === currentlyRenderingFiber$1 || + (alternate !== null && alternate === currentlyRenderingFiber$1) + ) { + // This is a render phase update. Stash it in a lazily-created map of + // queue -> linked list of updates. After this render pass, we'll restart + // and apply the stashed updates on top of the work-in-progress hook. + didScheduleRenderPhaseUpdate = true; + var update = { + expirationTime: renderExpirationTime$1, + action: action, + eagerReducer: null, + eagerState: null, + next: null + }; + if (renderPhaseUpdates === null) { + renderPhaseUpdates = new Map(); + } + var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue); + if (firstRenderPhaseUpdate === undefined) { + renderPhaseUpdates.set(queue, update); + } else { + // Append the update to the end of the list. + var lastRenderPhaseUpdate = firstRenderPhaseUpdate; + while (lastRenderPhaseUpdate.next !== null) { + lastRenderPhaseUpdate = lastRenderPhaseUpdate.next; + } + lastRenderPhaseUpdate.next = update; + } + } else { + flushPassiveEffects(); + + var currentTime = requestCurrentTime(); + var _expirationTime = computeExpirationForFiber(currentTime, fiber); + + var _update2 = { + expirationTime: _expirationTime, + action: action, + eagerReducer: null, + eagerState: null, + next: null + }; + + // Append the update to the end of the list. + var _last = queue.last; + if (_last === null) { + // This is the first update. Create a circular list. + _update2.next = _update2; + } else { + var first = _last.next; + if (first !== null) { + // Still circular. + _update2.next = first; + } + _last.next = _update2; + } + queue.last = _update2; + + if ( + fiber.expirationTime === NoWork && + (alternate === null || alternate.expirationTime === NoWork) + ) { + // The queue is currently empty, which means we can eagerly compute the + // next state before entering the render phase. If the new state is the + // same as the current state, we may be able to bail out entirely. + var _lastRenderedReducer = queue.lastRenderedReducer; + if (_lastRenderedReducer !== null) { + var prevDispatcher = void 0; + { + prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV; + } + try { + var currentState = queue.lastRenderedState; + var _eagerState = _lastRenderedReducer(currentState, action); + // Stash the eagerly computed state, and the reducer used to compute + // it, on the update object. If the reducer hasn't changed by the + // time we enter the render phase, then the eager state can be used + // without calling the reducer again. + _update2.eagerReducer = _lastRenderedReducer; + _update2.eagerState = _eagerState; + if (is(_eagerState, currentState)) { + // Fast path. We can bail out without scheduling React to re-render. + // It's still possible that we'll need to rebase this update later, + // if the component re-renders for a different reason and by that + // time the reducer has changed. + return; + } + } catch (error) { + // Suppress the error. It will throw again in the render phase. + } finally { + { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + } + } + } + { + // jest isn't a 'global', it's just exposed to tests via a wrapped function + // further, this isn't a test file, so flow doesn't recognize the symbol. So... + // $FlowExpectedError - because requirements don't give a damn about your type sigs. + if ("undefined" !== typeof jest) { + warnIfNotCurrentlyActingUpdatesInDev(fiber); + } + } + scheduleWork(fiber, _expirationTime); + } +} + +var ContextOnlyDispatcher = { + readContext: readContext, + + useCallback: throwInvalidHookError, + useContext: throwInvalidHookError, + useEffect: throwInvalidHookError, + useImperativeHandle: throwInvalidHookError, + useLayoutEffect: throwInvalidHookError, + useMemo: throwInvalidHookError, + useReducer: throwInvalidHookError, + useRef: throwInvalidHookError, + useState: throwInvalidHookError, + useDebugValue: throwInvalidHookError +}; + +var HooksDispatcherOnMountInDEV = null; +var HooksDispatcherOnMountWithHookTypesInDEV = null; +var HooksDispatcherOnUpdateInDEV = null; +var InvalidNestedHooksDispatcherOnMountInDEV = null; +var InvalidNestedHooksDispatcherOnUpdateInDEV = null; + +{ + var warnInvalidContextAccess = function() { + warning$1( + false, + "Context can only be read while React is rendering. " + + "In classes, you can read it in the render method or getDerivedStateFromProps. " + + "In function components, you can read it directly in the function body, but not " + + "inside Hooks like useReducer() or useMemo()." + ); + }; + + var warnInvalidHookAccess = function() { + warning$1( + false, + "Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. " + + "You can only call Hooks at the top level of your React function. " + + "For more information, see " + + "https://fb.me/rules-of-hooks" + ); + }; + + HooksDispatcherOnMountInDEV = { + readContext: function(context, observedBits) { + return readContext(context, observedBits); + }, + useCallback: function(callback, deps) { + currentHookNameInDev = "useCallback"; + mountHookTypesDev(); + checkDepsAreArrayDev(deps); + return mountCallback(callback, deps); + }, + useContext: function(context, observedBits) { + currentHookNameInDev = "useContext"; + mountHookTypesDev(); + return readContext(context, observedBits); + }, + useEffect: function(create, deps) { + currentHookNameInDev = "useEffect"; + mountHookTypesDev(); + checkDepsAreArrayDev(deps); + return mountEffect(create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + currentHookNameInDev = "useImperativeHandle"; + mountHookTypesDev(); + checkDepsAreArrayDev(deps); + return mountImperativeHandle(ref, create, deps); + }, + useLayoutEffect: function(create, deps) { + currentHookNameInDev = "useLayoutEffect"; + mountHookTypesDev(); + checkDepsAreArrayDev(deps); + return mountLayoutEffect(create, deps); + }, + useMemo: function(create, deps) { + currentHookNameInDev = "useMemo"; + mountHookTypesDev(); + checkDepsAreArrayDev(deps); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountMemo(create, deps); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useReducer: function(reducer, initialArg, init) { + currentHookNameInDev = "useReducer"; + mountHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountReducer(reducer, initialArg, init); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useRef: function(initialValue) { + currentHookNameInDev = "useRef"; + mountHookTypesDev(); + return mountRef(initialValue); + }, + useState: function(initialState) { + currentHookNameInDev = "useState"; + mountHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountState(initialState); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useDebugValue: function(value, formatterFn) { + currentHookNameInDev = "useDebugValue"; + mountHookTypesDev(); + return mountDebugValue(value, formatterFn); + } + }; + + HooksDispatcherOnMountWithHookTypesInDEV = { + readContext: function(context, observedBits) { + return readContext(context, observedBits); + }, + useCallback: function(callback, deps) { + currentHookNameInDev = "useCallback"; + updateHookTypesDev(); + return mountCallback(callback, deps); + }, + useContext: function(context, observedBits) { + currentHookNameInDev = "useContext"; + updateHookTypesDev(); + return readContext(context, observedBits); + }, + useEffect: function(create, deps) { + currentHookNameInDev = "useEffect"; + updateHookTypesDev(); + return mountEffect(create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + currentHookNameInDev = "useImperativeHandle"; + updateHookTypesDev(); + return mountImperativeHandle(ref, create, deps); + }, + useLayoutEffect: function(create, deps) { + currentHookNameInDev = "useLayoutEffect"; + updateHookTypesDev(); + return mountLayoutEffect(create, deps); + }, + useMemo: function(create, deps) { + currentHookNameInDev = "useMemo"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountMemo(create, deps); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useReducer: function(reducer, initialArg, init) { + currentHookNameInDev = "useReducer"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountReducer(reducer, initialArg, init); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useRef: function(initialValue) { + currentHookNameInDev = "useRef"; + updateHookTypesDev(); + return mountRef(initialValue); + }, + useState: function(initialState) { + currentHookNameInDev = "useState"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountState(initialState); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useDebugValue: function(value, formatterFn) { + currentHookNameInDev = "useDebugValue"; + updateHookTypesDev(); + return mountDebugValue(value, formatterFn); + } + }; + + HooksDispatcherOnUpdateInDEV = { + readContext: function(context, observedBits) { + return readContext(context, observedBits); + }, + useCallback: function(callback, deps) { + currentHookNameInDev = "useCallback"; + updateHookTypesDev(); + return updateCallback(callback, deps); + }, + useContext: function(context, observedBits) { + currentHookNameInDev = "useContext"; + updateHookTypesDev(); + return readContext(context, observedBits); + }, + useEffect: function(create, deps) { + currentHookNameInDev = "useEffect"; + updateHookTypesDev(); + return updateEffect(create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + currentHookNameInDev = "useImperativeHandle"; + updateHookTypesDev(); + return updateImperativeHandle(ref, create, deps); + }, + useLayoutEffect: function(create, deps) { + currentHookNameInDev = "useLayoutEffect"; + updateHookTypesDev(); + return updateLayoutEffect(create, deps); + }, + useMemo: function(create, deps) { + currentHookNameInDev = "useMemo"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV; + try { + return updateMemo(create, deps); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useReducer: function(reducer, initialArg, init) { + currentHookNameInDev = "useReducer"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV; + try { + return updateReducer(reducer, initialArg, init); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useRef: function(initialValue) { + currentHookNameInDev = "useRef"; + updateHookTypesDev(); + return updateRef(initialValue); + }, + useState: function(initialState) { + currentHookNameInDev = "useState"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV; + try { + return updateState(initialState); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useDebugValue: function(value, formatterFn) { + currentHookNameInDev = "useDebugValue"; + updateHookTypesDev(); + return updateDebugValue(value, formatterFn); + } + }; + + InvalidNestedHooksDispatcherOnMountInDEV = { + readContext: function(context, observedBits) { + warnInvalidContextAccess(); + return readContext(context, observedBits); + }, + useCallback: function(callback, deps) { + currentHookNameInDev = "useCallback"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountCallback(callback, deps); + }, + useContext: function(context, observedBits) { + currentHookNameInDev = "useContext"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return readContext(context, observedBits); + }, + useEffect: function(create, deps) { + currentHookNameInDev = "useEffect"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountEffect(create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + currentHookNameInDev = "useImperativeHandle"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountImperativeHandle(ref, create, deps); + }, + useLayoutEffect: function(create, deps) { + currentHookNameInDev = "useLayoutEffect"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountLayoutEffect(create, deps); + }, + useMemo: function(create, deps) { + currentHookNameInDev = "useMemo"; + warnInvalidHookAccess(); + mountHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountMemo(create, deps); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useReducer: function(reducer, initialArg, init) { + currentHookNameInDev = "useReducer"; + warnInvalidHookAccess(); + mountHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountReducer(reducer, initialArg, init); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useRef: function(initialValue) { + currentHookNameInDev = "useRef"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountRef(initialValue); + }, + useState: function(initialState) { + currentHookNameInDev = "useState"; + warnInvalidHookAccess(); + mountHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountState(initialState); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useDebugValue: function(value, formatterFn) { + currentHookNameInDev = "useDebugValue"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountDebugValue(value, formatterFn); + } + }; + + InvalidNestedHooksDispatcherOnUpdateInDEV = { + readContext: function(context, observedBits) { + warnInvalidContextAccess(); + return readContext(context, observedBits); + }, + useCallback: function(callback, deps) { + currentHookNameInDev = "useCallback"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateCallback(callback, deps); + }, + useContext: function(context, observedBits) { + currentHookNameInDev = "useContext"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return readContext(context, observedBits); + }, + useEffect: function(create, deps) { + currentHookNameInDev = "useEffect"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateEffect(create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + currentHookNameInDev = "useImperativeHandle"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateImperativeHandle(ref, create, deps); + }, + useLayoutEffect: function(create, deps) { + currentHookNameInDev = "useLayoutEffect"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateLayoutEffect(create, deps); + }, + useMemo: function(create, deps) { + currentHookNameInDev = "useMemo"; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV; + try { + return updateMemo(create, deps); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useReducer: function(reducer, initialArg, init) { + currentHookNameInDev = "useReducer"; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV; + try { + return updateReducer(reducer, initialArg, init); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useRef: function(initialValue) { + currentHookNameInDev = "useRef"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateRef(initialValue); + }, + useState: function(initialState) { + currentHookNameInDev = "useState"; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV; + try { + return updateState(initialState); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useDebugValue: function(value, formatterFn) { + currentHookNameInDev = "useDebugValue"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateDebugValue(value, formatterFn); + } + }; +} + +// Intentionally not named imports because Rollup would use dynamic dispatch for +// CommonJS interop named imports. +var now$1 = Scheduler.unstable_now; + +var commitTime = 0; +var profilerStartTime = -1; + +function getCommitTime() { + return commitTime; +} + +function recordCommitTime() { + if (!enableProfilerTimer) { + return; + } + commitTime = now$1(); +} + +function startProfilerTimer(fiber) { + if (!enableProfilerTimer) { + return; + } + + profilerStartTime = now$1(); + + if (fiber.actualStartTime < 0) { + fiber.actualStartTime = now$1(); + } +} + +function stopProfilerTimerIfRunning(fiber) { + if (!enableProfilerTimer) { + return; + } + profilerStartTime = -1; +} + +function stopProfilerTimerIfRunningAndRecordDelta(fiber, overrideBaseTime) { + if (!enableProfilerTimer) { + return; + } + + if (profilerStartTime >= 0) { + var elapsedTime = now$1() - profilerStartTime; + fiber.actualDuration += elapsedTime; + if (overrideBaseTime) { + fiber.selfBaseDuration = elapsedTime; + } + profilerStartTime = -1; + } +} + +// The deepest Fiber on the stack involved in a hydration context. +// This may have been an insertion or a hydration. +var hydrationParentFiber = null; +var nextHydratableInstance = null; +var isHydrating = false; + +function enterHydrationState(fiber) { + if (!supportsHydration) { + return false; + } + + var parentInstance = fiber.stateNode.containerInfo; + nextHydratableInstance = getFirstHydratableChild(parentInstance); + hydrationParentFiber = fiber; + isHydrating = true; + return true; +} + +function reenterHydrationStateFromDehydratedSuspenseInstance(fiber) { + if (!supportsHydration) { + return false; + } + + var suspenseInstance = fiber.stateNode; + nextHydratableInstance = getNextHydratableSibling(suspenseInstance); + popToNextHostParent(fiber); + isHydrating = true; + return true; +} + +function deleteHydratableInstance(returnFiber, instance) { + { + switch (returnFiber.tag) { + case HostRoot: + didNotHydrateContainerInstance( + returnFiber.stateNode.containerInfo, + instance + ); + break; + case HostComponent: + didNotHydrateInstance( + returnFiber.type, + returnFiber.memoizedProps, + returnFiber.stateNode, + instance + ); + break; + } + } + + var childToDelete = createFiberFromHostInstanceForDeletion(); + childToDelete.stateNode = instance; + childToDelete.return = returnFiber; + childToDelete.effectTag = Deletion; + + // This might seem like it belongs on progressedFirstDeletion. However, + // these children are not part of the reconciliation list of children. + // Even if we abort and rereconcile the children, that will try to hydrate + // again and the nodes are still in the host tree so these will be + // recreated. + if (returnFiber.lastEffect !== null) { + returnFiber.lastEffect.nextEffect = childToDelete; + returnFiber.lastEffect = childToDelete; + } else { + returnFiber.firstEffect = returnFiber.lastEffect = childToDelete; + } +} + +function insertNonHydratedInstance(returnFiber, fiber) { + fiber.effectTag |= Placement; + { + switch (returnFiber.tag) { + case HostRoot: { + var parentContainer = returnFiber.stateNode.containerInfo; + switch (fiber.tag) { + case HostComponent: + var type = fiber.type; + var props = fiber.pendingProps; + didNotFindHydratableContainerInstance(parentContainer, type, props); + break; + case HostText: + var text = fiber.pendingProps; + didNotFindHydratableContainerTextInstance(parentContainer, text); + break; + case SuspenseComponent: + didNotFindHydratableContainerSuspenseInstance(parentContainer); + break; + } + break; + } + case HostComponent: { + var parentType = returnFiber.type; + var parentProps = returnFiber.memoizedProps; + var parentInstance = returnFiber.stateNode; + switch (fiber.tag) { + case HostComponent: + var _type = fiber.type; + var _props = fiber.pendingProps; + didNotFindHydratableInstance( + parentType, + parentProps, + parentInstance, + _type, + _props + ); + break; + case HostText: + var _text = fiber.pendingProps; + didNotFindHydratableTextInstance( + parentType, + parentProps, + parentInstance, + _text + ); + break; + case SuspenseComponent: + didNotFindHydratableSuspenseInstance( + parentType, + parentProps, + parentInstance + ); + break; + } + break; + } + default: + return; + } + } +} + +function tryHydrate(fiber, nextInstance) { + switch (fiber.tag) { + case HostComponent: { + var type = fiber.type; + var props = fiber.pendingProps; + var instance = canHydrateInstance(nextInstance, type, props); + if (instance !== null) { + fiber.stateNode = instance; + return true; + } + return false; + } + case HostText: { + var text = fiber.pendingProps; + var textInstance = canHydrateTextInstance(nextInstance, text); + if (textInstance !== null) { + fiber.stateNode = textInstance; + return true; + } + return false; + } + case SuspenseComponent: { + if (enableSuspenseServerRenderer) { + var suspenseInstance = canHydrateSuspenseInstance(nextInstance); + if (suspenseInstance !== null) { + // Downgrade the tag to a dehydrated component until we've hydrated it. + fiber.tag = DehydratedSuspenseComponent; + fiber.stateNode = suspenseInstance; + return true; + } + } + return false; + } + default: + return false; + } +} + +function tryToClaimNextHydratableInstance(fiber) { + if (!isHydrating) { + return; + } + var nextInstance = nextHydratableInstance; + if (!nextInstance) { + // Nothing to hydrate. Make it an insertion. + insertNonHydratedInstance(hydrationParentFiber, fiber); + isHydrating = false; + hydrationParentFiber = fiber; + return; + } + var firstAttemptedInstance = nextInstance; + if (!tryHydrate(fiber, nextInstance)) { + // If we can't hydrate this instance let's try the next one. + // We use this as a heuristic. It's based on intuition and not data so it + // might be flawed or unnecessary. + nextInstance = getNextHydratableSibling(firstAttemptedInstance); + if (!nextInstance || !tryHydrate(fiber, nextInstance)) { + // Nothing to hydrate. Make it an insertion. + insertNonHydratedInstance(hydrationParentFiber, fiber); + isHydrating = false; + hydrationParentFiber = fiber; + return; + } + // We matched the next one, we'll now assume that the first one was + // superfluous and we'll delete it. Since we can't eagerly delete it + // we'll have to schedule a deletion. To do that, this node needs a dummy + // fiber associated with it. + deleteHydratableInstance(hydrationParentFiber, firstAttemptedInstance); + } + hydrationParentFiber = fiber; + nextHydratableInstance = getFirstHydratableChild(nextInstance); +} + +function prepareToHydrateHostInstance( + fiber, + rootContainerInstance, + hostContext +) { + if (!supportsHydration) { + (function() { + { + throw ReactError( + "Expected prepareToHydrateHostInstance() to never be called. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + + var instance = fiber.stateNode; + var updatePayload = hydrateInstance( + instance, + fiber.type, + fiber.memoizedProps, + rootContainerInstance, + hostContext, + fiber + ); + // TODO: Type this specific to this type of component. + fiber.updateQueue = updatePayload; + // If the update payload indicates that there is a change or if there + // is a new ref we mark this as an update. + if (updatePayload !== null) { + return true; + } + return false; +} + +function prepareToHydrateHostTextInstance(fiber) { + if (!supportsHydration) { + (function() { + { + throw ReactError( + "Expected prepareToHydrateHostTextInstance() to never be called. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + + var textInstance = fiber.stateNode; + var textContent = fiber.memoizedProps; + var shouldUpdate = hydrateTextInstance(textInstance, textContent, fiber); + { + if (shouldUpdate) { + // We assume that prepareToHydrateHostTextInstance is called in a context where the + // hydration parent is the parent host component of this host text. + var returnFiber = hydrationParentFiber; + if (returnFiber !== null) { + switch (returnFiber.tag) { + case HostRoot: { + var parentContainer = returnFiber.stateNode.containerInfo; + didNotMatchHydratedContainerTextInstance( + parentContainer, + textInstance, + textContent + ); + break; + } + case HostComponent: { + var parentType = returnFiber.type; + var parentProps = returnFiber.memoizedProps; + var parentInstance = returnFiber.stateNode; + didNotMatchHydratedTextInstance( + parentType, + parentProps, + parentInstance, + textInstance, + textContent + ); + break; + } + } + } + } + } + return shouldUpdate; +} + +function skipPastDehydratedSuspenseInstance(fiber) { + if (!supportsHydration) { + (function() { + { + throw ReactError( + "Expected skipPastDehydratedSuspenseInstance() to never be called. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + var suspenseInstance = fiber.stateNode; + (function() { + if (!suspenseInstance) { + throw ReactError( + "Expected to have a hydrated suspense instance. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + nextHydratableInstance = getNextHydratableInstanceAfterSuspenseInstance( + suspenseInstance + ); +} + +function popToNextHostParent(fiber) { + var parent = fiber.return; + while ( + parent !== null && + parent.tag !== HostComponent && + parent.tag !== HostRoot && + parent.tag !== DehydratedSuspenseComponent + ) { + parent = parent.return; + } + hydrationParentFiber = parent; +} + +function popHydrationState(fiber) { + if (!supportsHydration) { + return false; + } + if (fiber !== hydrationParentFiber) { + // We're deeper than the current hydration context, inside an inserted + // tree. + return false; + } + if (!isHydrating) { + // If we're not currently hydrating but we're in a hydration context, then + // we were an insertion and now need to pop up reenter hydration of our + // siblings. + popToNextHostParent(fiber); + isHydrating = true; + return false; + } + + var type = fiber.type; + + // If we have any remaining hydratable nodes, we need to delete them now. + // We only do this deeper than head and body since they tend to have random + // other nodes in them. We also ignore components with pure text content in + // side of them. + // TODO: Better heuristic. + if ( + fiber.tag !== HostComponent || + (type !== "head" && + type !== "body" && + !shouldSetTextContent(type, fiber.memoizedProps)) + ) { + var nextInstance = nextHydratableInstance; + while (nextInstance) { + deleteHydratableInstance(fiber, nextInstance); + nextInstance = getNextHydratableSibling(nextInstance); + } + } + + popToNextHostParent(fiber); + nextHydratableInstance = hydrationParentFiber + ? getNextHydratableSibling(fiber.stateNode) + : null; + return true; +} + +function resetHydrationState() { + if (!supportsHydration) { + return; + } + + hydrationParentFiber = null; + nextHydratableInstance = null; + isHydrating = false; +} + +var ReactCurrentOwner$3 = ReactSharedInternals.ReactCurrentOwner; + +var didReceiveUpdate = false; + +var didWarnAboutBadClass = void 0; +var didWarnAboutModulePatternComponent = void 0; +var didWarnAboutContextTypeOnFunctionComponent = void 0; +var didWarnAboutGetDerivedStateOnFunctionComponent = void 0; +var didWarnAboutFunctionRefs = void 0; +var didWarnAboutReassigningProps = void 0; +var didWarnAboutMaxDuration = void 0; + +{ + didWarnAboutBadClass = {}; + didWarnAboutModulePatternComponent = {}; + didWarnAboutContextTypeOnFunctionComponent = {}; + didWarnAboutGetDerivedStateOnFunctionComponent = {}; + didWarnAboutFunctionRefs = {}; + didWarnAboutReassigningProps = false; + didWarnAboutMaxDuration = false; +} + +function reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime +) { + if (current$$1 === null) { + // If this is a fresh new component that hasn't been rendered yet, we + // won't update its child set by applying minimal side-effects. Instead, + // we will add them all to the child before it gets rendered. That means + // we can optimize this reconciliation pass by not tracking side-effects. + workInProgress.child = mountChildFibers( + workInProgress, + null, + nextChildren, + renderExpirationTime + ); + } else { + // If the current child is the same as the work in progress, it means that + // we haven't yet started any work on these children. Therefore, we use + // the clone algorithm to create a copy of all the current children. + + // If we had any progressed work already, that is invalid at this point so + // let's throw it out. + workInProgress.child = reconcileChildFibers( + workInProgress, + current$$1.child, + nextChildren, + renderExpirationTime + ); + } +} + +function forceUnmountCurrentAndReconcile( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime +) { + // This function is fork of reconcileChildren. It's used in cases where we + // want to reconcile without matching against the existing set. This has the + // effect of all current children being unmounted; even if the type and key + // are the same, the old child is unmounted and a new child is created. + // + // To do this, we're going to go through the reconcile algorithm twice. In + // the first pass, we schedule a deletion for all the current children by + // passing null. + workInProgress.child = reconcileChildFibers( + workInProgress, + current$$1.child, + null, + renderExpirationTime + ); + // In the second pass, we mount the new children. The trick here is that we + // pass null in place of where we usually pass the current child set. This has + // the effect of remounting all children regardless of whether their their + // identity matches. + workInProgress.child = reconcileChildFibers( + workInProgress, + null, + nextChildren, + renderExpirationTime + ); +} + +function updateForwardRef( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + // TODO: current can be non-null here even if the component + // hasn't yet mounted. This happens after the first render suspends. + // We'll need to figure out if this is fine or can cause issues. + + { + if (workInProgress.type !== workInProgress.elementType) { + // Lazy component props can't be validated in createElement + // because they're only guaranteed to be resolved here. + var innerPropTypes = Component.propTypes; + if (innerPropTypes) { + checkPropTypes( + innerPropTypes, + nextProps, // Resolved props + "prop", + getComponentName(Component), + getCurrentFiberStackInDev + ); + } + } + } + + var render = Component.render; + var ref = workInProgress.ref; + + // The rest is a fork of updateFunctionComponent + var nextChildren = void 0; + prepareToReadContext(workInProgress, renderExpirationTime); + { + ReactCurrentOwner$3.current = workInProgress; + setCurrentPhase("render"); + nextChildren = renderWithHooks( + current$$1, + workInProgress, + render, + nextProps, + ref, + renderExpirationTime + ); + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + // Only double-render components with Hooks + if (workInProgress.memoizedState !== null) { + nextChildren = renderWithHooks( + current$$1, + workInProgress, + render, + nextProps, + ref, + renderExpirationTime + ); + } + } + setCurrentPhase(null); + } + + if (current$$1 !== null && !didReceiveUpdate) { + bailoutHooks(current$$1, workInProgress, renderExpirationTime); + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + return workInProgress.child; +} + +function updateMemoComponent( + current$$1, + workInProgress, + Component, + nextProps, + updateExpirationTime, + renderExpirationTime +) { + if (current$$1 === null) { + var type = Component.type; + if ( + isSimpleFunctionComponent(type) && + Component.compare === null && + // SimpleMemoComponent codepath doesn't resolve outer props either. + Component.defaultProps === undefined + ) { + // If this is a plain function component without default props, + // and with only the default shallow comparison, we upgrade it + // to a SimpleMemoComponent to allow fast path updates. + workInProgress.tag = SimpleMemoComponent; + workInProgress.type = type; + { + validateFunctionComponentInDev(workInProgress, type); + } + return updateSimpleMemoComponent( + current$$1, + workInProgress, + type, + nextProps, + updateExpirationTime, + renderExpirationTime + ); + } + { + var innerPropTypes = type.propTypes; + if (innerPropTypes) { + // Inner memo component props aren't currently validated in createElement. + // We could move it there, but we'd still need this for lazy code path. + checkPropTypes( + innerPropTypes, + nextProps, // Resolved props + "prop", + getComponentName(type), + getCurrentFiberStackInDev + ); + } + } + var child = createFiberFromTypeAndProps( + Component.type, + null, + nextProps, + null, + workInProgress.mode, + renderExpirationTime + ); + child.ref = workInProgress.ref; + child.return = workInProgress; + workInProgress.child = child; + return child; + } + { + var _type = Component.type; + var _innerPropTypes = _type.propTypes; + if (_innerPropTypes) { + // Inner memo component props aren't currently validated in createElement. + // We could move it there, but we'd still need this for lazy code path. + checkPropTypes( + _innerPropTypes, + nextProps, // Resolved props + "prop", + getComponentName(_type), + getCurrentFiberStackInDev + ); + } + } + var currentChild = current$$1.child; // This is always exactly one child + if (updateExpirationTime < renderExpirationTime) { + // This will be the props with resolved defaultProps, + // unlike current.memoizedProps which will be the unresolved ones. + var prevProps = currentChild.memoizedProps; + // Default to shallow comparison + var compare = Component.compare; + compare = compare !== null ? compare : shallowEqual; + if ( + compare(prevProps, nextProps) && + current$$1.ref === workInProgress.ref + ) { + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + } + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + var newChild = createWorkInProgress( + currentChild, + nextProps, + renderExpirationTime + ); + newChild.ref = workInProgress.ref; + newChild.return = workInProgress; + workInProgress.child = newChild; + return newChild; +} + +function updateSimpleMemoComponent( + current$$1, + workInProgress, + Component, + nextProps, + updateExpirationTime, + renderExpirationTime +) { + // TODO: current can be non-null here even if the component + // hasn't yet mounted. This happens when the inner render suspends. + // We'll need to figure out if this is fine or can cause issues. + + { + if (workInProgress.type !== workInProgress.elementType) { + // Lazy component props can't be validated in createElement + // because they're only guaranteed to be resolved here. + var outerMemoType = workInProgress.elementType; + if (outerMemoType.$$typeof === REACT_LAZY_TYPE) { + // We warn when you define propTypes on lazy() + // so let's just skip over it to find memo() outer wrapper. + // Inner props for memo are validated later. + outerMemoType = refineResolvedLazyComponent(outerMemoType); + } + var outerPropTypes = outerMemoType && outerMemoType.propTypes; + if (outerPropTypes) { + checkPropTypes( + outerPropTypes, + nextProps, // Resolved (SimpleMemoComponent has no defaultProps) + "prop", + getComponentName(outerMemoType), + getCurrentFiberStackInDev + ); + } + // Inner propTypes will be validated in the function component path. + } + } + if (current$$1 !== null) { + var prevProps = current$$1.memoizedProps; + if ( + shallowEqual(prevProps, nextProps) && + current$$1.ref === workInProgress.ref + ) { + didReceiveUpdate = false; + if (updateExpirationTime < renderExpirationTime) { + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + } + } + return updateFunctionComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime + ); +} + +function updateFragment(current$$1, workInProgress, renderExpirationTime) { + var nextChildren = workInProgress.pendingProps; + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + return workInProgress.child; +} + +function updateMode(current$$1, workInProgress, renderExpirationTime) { + var nextChildren = workInProgress.pendingProps.children; + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + return workInProgress.child; +} + +function updateProfiler(current$$1, workInProgress, renderExpirationTime) { + if (enableProfilerTimer) { + workInProgress.effectTag |= Update; + } + var nextProps = workInProgress.pendingProps; + var nextChildren = nextProps.children; + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + return workInProgress.child; +} + +function markRef(current$$1, workInProgress) { + var ref = workInProgress.ref; + if ( + (current$$1 === null && ref !== null) || + (current$$1 !== null && current$$1.ref !== ref) + ) { + // Schedule a Ref effect + workInProgress.effectTag |= Ref; + } +} + +function updateFunctionComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + { + if (workInProgress.type !== workInProgress.elementType) { + // Lazy component props can't be validated in createElement + // because they're only guaranteed to be resolved here. + var innerPropTypes = Component.propTypes; + if (innerPropTypes) { + checkPropTypes( + innerPropTypes, + nextProps, // Resolved props + "prop", + getComponentName(Component), + getCurrentFiberStackInDev + ); + } + } + } + + var unmaskedContext = getUnmaskedContext(workInProgress, Component, true); + var context = getMaskedContext(workInProgress, unmaskedContext); + + var nextChildren = void 0; + prepareToReadContext(workInProgress, renderExpirationTime); + { + ReactCurrentOwner$3.current = workInProgress; + setCurrentPhase("render"); + nextChildren = renderWithHooks( + current$$1, + workInProgress, + Component, + nextProps, + context, + renderExpirationTime + ); + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + // Only double-render components with Hooks + if (workInProgress.memoizedState !== null) { + nextChildren = renderWithHooks( + current$$1, + workInProgress, + Component, + nextProps, + context, + renderExpirationTime + ); + } + } + setCurrentPhase(null); + } + + if (current$$1 !== null && !didReceiveUpdate) { + bailoutHooks(current$$1, workInProgress, renderExpirationTime); + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + return workInProgress.child; +} + +function updateClassComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + { + if (workInProgress.type !== workInProgress.elementType) { + // Lazy component props can't be validated in createElement + // because they're only guaranteed to be resolved here. + var innerPropTypes = Component.propTypes; + if (innerPropTypes) { + checkPropTypes( + innerPropTypes, + nextProps, // Resolved props + "prop", + getComponentName(Component), + getCurrentFiberStackInDev + ); + } + } + } + + // Push context providers early to prevent context stack mismatches. + // During mounting we don't know the child context yet as the instance doesn't exist. + // We will invalidate the child context in finishClassComponent() right after rendering. + var hasContext = void 0; + if (isContextProvider(Component)) { + hasContext = true; + pushContextProvider(workInProgress); + } else { + hasContext = false; + } + prepareToReadContext(workInProgress, renderExpirationTime); + + var instance = workInProgress.stateNode; + var shouldUpdate = void 0; + if (instance === null) { + if (current$$1 !== null) { + // An class component without an instance only mounts if it suspended + // inside a non- concurrent tree, in an inconsistent state. We want to + // tree it like a new mount, even though an empty version of it already + // committed. Disconnect the alternate pointers. + current$$1.alternate = null; + workInProgress.alternate = null; + // Since this is conceptually a new fiber, schedule a Placement effect + workInProgress.effectTag |= Placement; + } + // In the initial pass we might need to construct the instance. + constructClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ); + mountClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ); + shouldUpdate = true; + } else if (current$$1 === null) { + // In a resume, we'll already have an instance we can reuse. + shouldUpdate = resumeMountClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ); + } else { + shouldUpdate = updateClassInstance( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime + ); + } + var nextUnitOfWork = finishClassComponent( + current$$1, + workInProgress, + Component, + shouldUpdate, + hasContext, + renderExpirationTime + ); + { + var inst = workInProgress.stateNode; + if (inst.props !== nextProps) { + !didWarnAboutReassigningProps + ? warning$1( + false, + "It looks like %s is reassigning its own `this.props` while rendering. " + + "This is not supported and can lead to confusing bugs.", + getComponentName(workInProgress.type) || "a component" + ) + : void 0; + didWarnAboutReassigningProps = true; + } + } + return nextUnitOfWork; +} + +function finishClassComponent( + current$$1, + workInProgress, + Component, + shouldUpdate, + hasContext, + renderExpirationTime +) { + // Refs should update even if shouldComponentUpdate returns false + markRef(current$$1, workInProgress); + + var didCaptureError = (workInProgress.effectTag & DidCapture) !== NoEffect; + + if (!shouldUpdate && !didCaptureError) { + // Context providers should defer to sCU for rendering + if (hasContext) { + invalidateContextProvider(workInProgress, Component, false); + } + + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + + var instance = workInProgress.stateNode; + + // Rerender + ReactCurrentOwner$3.current = workInProgress; + var nextChildren = void 0; + if ( + didCaptureError && + typeof Component.getDerivedStateFromError !== "function" + ) { + // If we captured an error, but getDerivedStateFrom catch is not defined, + // unmount all the children. componentDidCatch will schedule an update to + // re-render a fallback. This is temporary until we migrate everyone to + // the new API. + // TODO: Warn in a future release. + nextChildren = null; + + if (enableProfilerTimer) { + stopProfilerTimerIfRunning(workInProgress); + } + } else { + { + setCurrentPhase("render"); + nextChildren = instance.render(); + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + instance.render(); + } + setCurrentPhase(null); + } + } + + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + if (current$$1 !== null && didCaptureError) { + // If we're recovering from an error, reconcile without reusing any of + // the existing children. Conceptually, the normal children and the children + // that are shown on error are two different sets, so we shouldn't reuse + // normal children even if their identities match. + forceUnmountCurrentAndReconcile( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + } else { + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + } + + // Memoize state using the values we just used to render. + // TODO: Restructure so we never read values from the instance. + workInProgress.memoizedState = instance.state; + + // The context might have changed so we need to recalculate it. + if (hasContext) { + invalidateContextProvider(workInProgress, Component, true); + } + + return workInProgress.child; +} + +function pushHostRootContext(workInProgress) { + var root = workInProgress.stateNode; + if (root.pendingContext) { + pushTopLevelContextObject( + workInProgress, + root.pendingContext, + root.pendingContext !== root.context + ); + } else if (root.context) { + // Should always be set + pushTopLevelContextObject(workInProgress, root.context, false); + } + pushHostContainer(workInProgress, root.containerInfo); +} + +function updateHostRoot(current$$1, workInProgress, renderExpirationTime) { + pushHostRootContext(workInProgress); + var updateQueue = workInProgress.updateQueue; + (function() { + if (!(updateQueue !== null)) { + throw ReactError( + "If the root does not have an updateQueue, we should have already bailed out. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + var nextProps = workInProgress.pendingProps; + var prevState = workInProgress.memoizedState; + var prevChildren = prevState !== null ? prevState.element : null; + processUpdateQueue( + workInProgress, + updateQueue, + nextProps, + null, + renderExpirationTime + ); + var nextState = workInProgress.memoizedState; + // Caution: React DevTools currently depends on this property + // being called "element". + var nextChildren = nextState.element; + if (nextChildren === prevChildren) { + // If the state is the same as before, that's a bailout because we had + // no work that expires at this time. + resetHydrationState(); + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + var root = workInProgress.stateNode; + if ( + (current$$1 === null || current$$1.child === null) && + root.hydrate && + enterHydrationState(workInProgress) + ) { + // If we don't have any current children this might be the first pass. + // We always try to hydrate. If this isn't a hydration pass there won't + // be any children to hydrate which is effectively the same thing as + // not hydrating. + + // This is a bit of a hack. We track the host root as a placement to + // know that we're currently in a mounting state. That way isMounted + // works as expected. We must reset this before committing. + // TODO: Delete this when we delete isMounted and findDOMNode. + workInProgress.effectTag |= Placement; + + // Ensure that children mount into this root without tracking + // side-effects. This ensures that we don't store Placement effects on + // nodes that will be hydrated. + workInProgress.child = mountChildFibers( + workInProgress, + null, + nextChildren, + renderExpirationTime + ); + } else { + // Otherwise reset hydration state in case we aborted and resumed another + // root. + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + resetHydrationState(); + } + return workInProgress.child; +} + +function updateHostComponent(current$$1, workInProgress, renderExpirationTime) { + pushHostContext(workInProgress); + + if (current$$1 === null) { + tryToClaimNextHydratableInstance(workInProgress); + } + + var type = workInProgress.type; + var nextProps = workInProgress.pendingProps; + var prevProps = current$$1 !== null ? current$$1.memoizedProps : null; + + var nextChildren = nextProps.children; + var isDirectTextChild = shouldSetTextContent(type, nextProps); + + if (isDirectTextChild) { + // We special case a direct text child of a host node. This is a common + // case. We won't handle it as a reified child. We will instead handle + // this in the host environment that also have access to this prop. That + // avoids allocating another HostText fiber and traversing it. + nextChildren = null; + } else if (prevProps !== null && shouldSetTextContent(type, prevProps)) { + // If we're switching from a direct text child to a normal child, or to + // empty, we need to schedule the text content to be reset. + workInProgress.effectTag |= ContentReset; + } + + markRef(current$$1, workInProgress); + + // Check the host config to see if the children are offscreen/hidden. + if ( + renderExpirationTime !== Never && + workInProgress.mode & ConcurrentMode && + shouldDeprioritizeSubtree(type, nextProps) + ) { + // Schedule this fiber to re-render at offscreen priority. Then bailout. + workInProgress.expirationTime = workInProgress.childExpirationTime = Never; + return null; + } + + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + return workInProgress.child; +} + +function updateHostText(current$$1, workInProgress) { + if (current$$1 === null) { + tryToClaimNextHydratableInstance(workInProgress); + } + // Nothing to do here. This is terminal. We'll do the completion step + // immediately after. + return null; +} + +function mountLazyComponent( + _current, + workInProgress, + elementType, + updateExpirationTime, + renderExpirationTime +) { + if (_current !== null) { + // An lazy component only mounts if it suspended inside a non- + // concurrent tree, in an inconsistent state. We want to treat it like + // a new mount, even though an empty version of it already committed. + // Disconnect the alternate pointers. + _current.alternate = null; + workInProgress.alternate = null; + // Since this is conceptually a new fiber, schedule a Placement effect + workInProgress.effectTag |= Placement; + } + + var props = workInProgress.pendingProps; + // We can't start a User Timing measurement with correct label yet. + // Cancel and resume right after we know the tag. + cancelWorkTimer(workInProgress); + var Component = readLazyComponentType(elementType); + // Store the unwrapped component in the type. + workInProgress.type = Component; + var resolvedTag = (workInProgress.tag = resolveLazyComponentTag(Component)); + startWorkTimer(workInProgress); + var resolvedProps = resolveDefaultProps(Component, props); + var child = void 0; + switch (resolvedTag) { + case FunctionComponent: { + { + validateFunctionComponentInDev(workInProgress, Component); + } + child = updateFunctionComponent( + null, + workInProgress, + Component, + resolvedProps, + renderExpirationTime + ); + break; + } + case ClassComponent: { + child = updateClassComponent( + null, + workInProgress, + Component, + resolvedProps, + renderExpirationTime + ); + break; + } + case ForwardRef: { + child = updateForwardRef( + null, + workInProgress, + Component, + resolvedProps, + renderExpirationTime + ); + break; + } + case MemoComponent: { + { + if (workInProgress.type !== workInProgress.elementType) { + var outerPropTypes = Component.propTypes; + if (outerPropTypes) { + checkPropTypes( + outerPropTypes, + resolvedProps, // Resolved for outer only + "prop", + getComponentName(Component), + getCurrentFiberStackInDev + ); + } + } + } + child = updateMemoComponent( + null, + workInProgress, + Component, + resolveDefaultProps(Component.type, resolvedProps), // The inner type can have defaults too + updateExpirationTime, + renderExpirationTime + ); + break; + } + default: { + var hint = ""; + { + if ( + Component !== null && + typeof Component === "object" && + Component.$$typeof === REACT_LAZY_TYPE + ) { + hint = " Did you wrap a component in React.lazy() more than once?"; + } + } + // This message intentionally doesn't mention ForwardRef or MemoComponent + // because the fact that it's a separate type of work is an + // implementation detail. + (function() { + { + throw ReactError( + "Element type is invalid. Received a promise that resolves to: " + + Component + + ". Lazy element type must resolve to a class or function." + + hint + ); + } + })(); + } + } + return child; +} + +function mountIncompleteClassComponent( + _current, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + if (_current !== null) { + // An incomplete component only mounts if it suspended inside a non- + // concurrent tree, in an inconsistent state. We want to treat it like + // a new mount, even though an empty version of it already committed. + // Disconnect the alternate pointers. + _current.alternate = null; + workInProgress.alternate = null; + // Since this is conceptually a new fiber, schedule a Placement effect + workInProgress.effectTag |= Placement; + } + + // Promote the fiber to a class and try rendering again. + workInProgress.tag = ClassComponent; + + // The rest of this function is a fork of `updateClassComponent` + + // Push context providers early to prevent context stack mismatches. + // During mounting we don't know the child context yet as the instance doesn't exist. + // We will invalidate the child context in finishClassComponent() right after rendering. + var hasContext = void 0; + if (isContextProvider(Component)) { + hasContext = true; + pushContextProvider(workInProgress); + } else { + hasContext = false; + } + prepareToReadContext(workInProgress, renderExpirationTime); + + constructClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ); + mountClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ); + + return finishClassComponent( + null, + workInProgress, + Component, + true, + hasContext, + renderExpirationTime + ); +} + +function mountIndeterminateComponent( + _current, + workInProgress, + Component, + renderExpirationTime +) { + if (_current !== null) { + // An indeterminate component only mounts if it suspended inside a non- + // concurrent tree, in an inconsistent state. We want to treat it like + // a new mount, even though an empty version of it already committed. + // Disconnect the alternate pointers. + _current.alternate = null; + workInProgress.alternate = null; + // Since this is conceptually a new fiber, schedule a Placement effect + workInProgress.effectTag |= Placement; + } + + var props = workInProgress.pendingProps; + var unmaskedContext = getUnmaskedContext(workInProgress, Component, false); + var context = getMaskedContext(workInProgress, unmaskedContext); + + prepareToReadContext(workInProgress, renderExpirationTime); + + var value = void 0; + + { + if ( + Component.prototype && + typeof Component.prototype.render === "function" + ) { + var componentName = getComponentName(Component) || "Unknown"; + + if (!didWarnAboutBadClass[componentName]) { + warningWithoutStack$1( + false, + "The <%s /> component appears to have a render method, but doesn't extend React.Component. " + + "This is likely to cause errors. Change %s to extend React.Component instead.", + componentName, + componentName + ); + didWarnAboutBadClass[componentName] = true; + } + } + + if (workInProgress.mode & StrictMode) { + ReactStrictModeWarnings.recordLegacyContextWarning(workInProgress, null); + } + + ReactCurrentOwner$3.current = workInProgress; + value = renderWithHooks( + null, + workInProgress, + Component, + props, + context, + renderExpirationTime + ); + } + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + + if ( + typeof value === "object" && + value !== null && + typeof value.render === "function" && + value.$$typeof === undefined + ) { + { + var _componentName = getComponentName(Component) || "Unknown"; + if (!didWarnAboutModulePatternComponent[_componentName]) { + warningWithoutStack$1( + false, + "The <%s /> component appears to be a function component that returns a class instance. " + + "Change %s to a class that extends React.Component instead. " + + "If you can't use a class try assigning the prototype on the function as a workaround. " + + "`%s.prototype = React.Component.prototype`. Don't use an arrow function since it " + + "cannot be called with `new` by React.", + _componentName, + _componentName, + _componentName + ); + didWarnAboutModulePatternComponent[_componentName] = true; + } + } + + // Proceed under the assumption that this is a class instance + workInProgress.tag = ClassComponent; + + // Throw out any hooks that were used. + resetHooks(); + + // Push context providers early to prevent context stack mismatches. + // During mounting we don't know the child context yet as the instance doesn't exist. + // We will invalidate the child context in finishClassComponent() right after rendering. + var hasContext = false; + if (isContextProvider(Component)) { + hasContext = true; + pushContextProvider(workInProgress); + } else { + hasContext = false; + } + + workInProgress.memoizedState = + value.state !== null && value.state !== undefined ? value.state : null; + + var getDerivedStateFromProps = Component.getDerivedStateFromProps; + if (typeof getDerivedStateFromProps === "function") { + applyDerivedStateFromProps( + workInProgress, + Component, + getDerivedStateFromProps, + props + ); + } + + adoptClassInstance(workInProgress, value); + mountClassInstance(workInProgress, Component, props, renderExpirationTime); + return finishClassComponent( + null, + workInProgress, + Component, + true, + hasContext, + renderExpirationTime + ); + } else { + // Proceed under the assumption that this is a function component + workInProgress.tag = FunctionComponent; + { + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + // Only double-render components with Hooks + if (workInProgress.memoizedState !== null) { + value = renderWithHooks( + null, + workInProgress, + Component, + props, + context, + renderExpirationTime + ); + } + } + } + reconcileChildren(null, workInProgress, value, renderExpirationTime); + { + validateFunctionComponentInDev(workInProgress, Component); + } + return workInProgress.child; + } +} + +function validateFunctionComponentInDev(workInProgress, Component) { + if (Component) { + !!Component.childContextTypes + ? warningWithoutStack$1( + false, + "%s(...): childContextTypes cannot be defined on a function component.", + Component.displayName || Component.name || "Component" + ) + : void 0; + } + if (workInProgress.ref !== null) { + var info = ""; + var ownerName = getCurrentFiberOwnerNameInDevOrNull(); + if (ownerName) { + info += "\n\nCheck the render method of `" + ownerName + "`."; + } + + var warningKey = ownerName || workInProgress._debugID || ""; + var debugSource = workInProgress._debugSource; + if (debugSource) { + warningKey = debugSource.fileName + ":" + debugSource.lineNumber; + } + if (!didWarnAboutFunctionRefs[warningKey]) { + didWarnAboutFunctionRefs[warningKey] = true; + warning$1( + false, + "Function components cannot be given refs. " + + "Attempts to access this ref will fail. " + + "Did you mean to use React.forwardRef()?%s", + info + ); + } + } + + if (typeof Component.getDerivedStateFromProps === "function") { + var componentName = getComponentName(Component) || "Unknown"; + + if (!didWarnAboutGetDerivedStateOnFunctionComponent[componentName]) { + warningWithoutStack$1( + false, + "%s: Function components do not support getDerivedStateFromProps.", + componentName + ); + didWarnAboutGetDerivedStateOnFunctionComponent[componentName] = true; + } + } + + if ( + typeof Component.contextType === "object" && + Component.contextType !== null + ) { + var _componentName2 = getComponentName(Component) || "Unknown"; + + if (!didWarnAboutContextTypeOnFunctionComponent[_componentName2]) { + warningWithoutStack$1( + false, + "%s: Function components do not support contextType.", + _componentName2 + ); + didWarnAboutContextTypeOnFunctionComponent[_componentName2] = true; + } + } +} + +function updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime +) { + var mode = workInProgress.mode; + var nextProps = workInProgress.pendingProps; + + { + if (shouldSuspend(workInProgress)) { + workInProgress.effectTag |= DidCapture; + } + } + + // We should attempt to render the primary children unless this boundary + // already suspended during this render (`alreadyCaptured` is true). + var nextState = workInProgress.memoizedState; + + var nextDidTimeout = void 0; + if ((workInProgress.effectTag & DidCapture) === NoEffect) { + // This is the first attempt. + nextState = null; + nextDidTimeout = false; + } else { + // Something in this boundary's subtree already suspended. Switch to + // rendering the fallback children. + nextState = { + fallbackExpirationTime: + nextState !== null ? nextState.fallbackExpirationTime : NoWork + }; + nextDidTimeout = true; + workInProgress.effectTag &= ~DidCapture; + } + + { + if ("maxDuration" in nextProps) { + if (!didWarnAboutMaxDuration) { + didWarnAboutMaxDuration = true; + warning$1( + false, + "maxDuration has been removed from React. " + + "Remove the maxDuration prop." + ); + } + } + } + + // This next part is a bit confusing. If the children timeout, we switch to + // showing the fallback children in place of the "primary" children. + // However, we don't want to delete the primary children because then their + // state will be lost (both the React state and the host state, e.g. + // uncontrolled form inputs). Instead we keep them mounted and hide them. + // Both the fallback children AND the primary children are rendered at the + // same time. Once the primary children are un-suspended, we can delete + // the fallback children — don't need to preserve their state. + // + // The two sets of children are siblings in the host environment, but + // semantically, for purposes of reconciliation, they are two separate sets. + // So we store them using two fragment fibers. + // + // However, we want to avoid allocating extra fibers for every placeholder. + // They're only necessary when the children time out, because that's the + // only time when both sets are mounted. + // + // So, the extra fragment fibers are only used if the children time out. + // Otherwise, we render the primary children directly. This requires some + // custom reconciliation logic to preserve the state of the primary + // children. It's essentially a very basic form of re-parenting. + + // `child` points to the child fiber. In the normal case, this is the first + // fiber of the primary children set. In the timed-out case, it's a + // a fragment fiber containing the primary children. + var child = void 0; + // `next` points to the next fiber React should render. In the normal case, + // it's the same as `child`: the first fiber of the primary children set. + // In the timed-out case, it's a fragment fiber containing the *fallback* + // children -- we skip over the primary children entirely. + var next = void 0; + if (current$$1 === null) { + if (enableSuspenseServerRenderer) { + // If we're currently hydrating, try to hydrate this boundary. + // But only if this has a fallback. + if (nextProps.fallback !== undefined) { + tryToClaimNextHydratableInstance(workInProgress); + // This could've changed the tag if this was a dehydrated suspense component. + if (workInProgress.tag === DehydratedSuspenseComponent) { + return updateDehydratedSuspenseComponent( + null, + workInProgress, + renderExpirationTime + ); + } + } + } + + // This is the initial mount. This branch is pretty simple because there's + // no previous state that needs to be preserved. + if (nextDidTimeout) { + // Mount separate fragments for primary and fallback children. + var nextFallbackChildren = nextProps.fallback; + var primaryChildFragment = createFiberFromFragment( + null, + mode, + NoWork, + null + ); + + if ((workInProgress.mode & ConcurrentMode) === NoContext) { + // Outside of concurrent mode, we commit the effects from the + var progressedState = workInProgress.memoizedState; + var progressedPrimaryChild = + progressedState !== null + ? workInProgress.child.child + : workInProgress.child; + primaryChildFragment.child = progressedPrimaryChild; + } + + var fallbackChildFragment = createFiberFromFragment( + nextFallbackChildren, + mode, + renderExpirationTime, + null + ); + primaryChildFragment.sibling = fallbackChildFragment; + child = primaryChildFragment; + // Skip the primary children, and continue working on the + // fallback children. + next = fallbackChildFragment; + child.return = next.return = workInProgress; + } else { + // Mount the primary children without an intermediate fragment fiber. + var nextPrimaryChildren = nextProps.children; + child = next = mountChildFibers( + workInProgress, + null, + nextPrimaryChildren, + renderExpirationTime + ); + } + } else { + // This is an update. This branch is more complicated because we need to + // ensure the state of the primary children is preserved. + var prevState = current$$1.memoizedState; + var prevDidTimeout = prevState !== null; + if (prevDidTimeout) { + // The current tree already timed out. That means each child set is + var currentPrimaryChildFragment = current$$1.child; + var currentFallbackChildFragment = currentPrimaryChildFragment.sibling; + if (nextDidTimeout) { + // Still timed out. Reuse the current primary children by cloning + // its fragment. We're going to skip over these entirely. + var _nextFallbackChildren = nextProps.fallback; + var _primaryChildFragment = createWorkInProgress( + currentPrimaryChildFragment, + currentPrimaryChildFragment.pendingProps, + NoWork + ); + + if ((workInProgress.mode & ConcurrentMode) === NoContext) { + // Outside of concurrent mode, we commit the effects from the + var _progressedState = workInProgress.memoizedState; + var _progressedPrimaryChild = + _progressedState !== null + ? workInProgress.child.child + : workInProgress.child; + if (_progressedPrimaryChild !== currentPrimaryChildFragment.child) { + _primaryChildFragment.child = _progressedPrimaryChild; + } + } + + // Because primaryChildFragment is a new fiber that we're inserting as the + // parent of a new tree, we need to set its treeBaseDuration. + if (enableProfilerTimer && workInProgress.mode & ProfileMode) { + // treeBaseDuration is the sum of all the child tree base durations. + var treeBaseDuration = 0; + var hiddenChild = _primaryChildFragment.child; + while (hiddenChild !== null) { + treeBaseDuration += hiddenChild.treeBaseDuration; + hiddenChild = hiddenChild.sibling; + } + _primaryChildFragment.treeBaseDuration = treeBaseDuration; + } + + // Clone the fallback child fragment, too. These we'll continue + // working on. + var _fallbackChildFragment = (_primaryChildFragment.sibling = createWorkInProgress( + currentFallbackChildFragment, + _nextFallbackChildren, + currentFallbackChildFragment.expirationTime + )); + child = _primaryChildFragment; + _primaryChildFragment.childExpirationTime = NoWork; + // Skip the primary children, and continue working on the + // fallback children. + next = _fallbackChildFragment; + child.return = next.return = workInProgress; + } else { + // No longer suspended. Switch back to showing the primary children, + // and remove the intermediate fragment fiber. + var _nextPrimaryChildren = nextProps.children; + var currentPrimaryChild = currentPrimaryChildFragment.child; + var primaryChild = reconcileChildFibers( + workInProgress, + currentPrimaryChild, + _nextPrimaryChildren, + renderExpirationTime + ); + + // If this render doesn't suspend, we need to delete the fallback + // children. Wait until the complete phase, after we've confirmed the + // fallback is no longer needed. + // TODO: Would it be better to store the fallback fragment on + // the stateNode? + + // Continue rendering the children, like we normally do. + child = next = primaryChild; + } + } else { + // The current tree has not already timed out. That means the primary + // children are not wrapped in a fragment fiber. + var _currentPrimaryChild = current$$1.child; + if (nextDidTimeout) { + // Timed out. Wrap the children in a fragment fiber to keep them + // separate from the fallback children. + var _nextFallbackChildren2 = nextProps.fallback; + var _primaryChildFragment2 = createFiberFromFragment( + // It shouldn't matter what the pending props are because we aren't + // going to render this fragment. + null, + mode, + NoWork, + null + ); + _primaryChildFragment2.child = _currentPrimaryChild; + + // Even though we're creating a new fiber, there are no new children, + // because we're reusing an already mounted tree. So we don't need to + // schedule a placement. + // primaryChildFragment.effectTag |= Placement; + + if ((workInProgress.mode & ConcurrentMode) === NoContext) { + // Outside of concurrent mode, we commit the effects from the + var _progressedState2 = workInProgress.memoizedState; + var _progressedPrimaryChild2 = + _progressedState2 !== null + ? workInProgress.child.child + : workInProgress.child; + _primaryChildFragment2.child = _progressedPrimaryChild2; + } + + // Because primaryChildFragment is a new fiber that we're inserting as the + // parent of a new tree, we need to set its treeBaseDuration. + if (enableProfilerTimer && workInProgress.mode & ProfileMode) { + // treeBaseDuration is the sum of all the child tree base durations. + var _treeBaseDuration = 0; + var _hiddenChild = _primaryChildFragment2.child; + while (_hiddenChild !== null) { + _treeBaseDuration += _hiddenChild.treeBaseDuration; + _hiddenChild = _hiddenChild.sibling; + } + _primaryChildFragment2.treeBaseDuration = _treeBaseDuration; + } + + // Create a fragment from the fallback children, too. + var _fallbackChildFragment2 = (_primaryChildFragment2.sibling = createFiberFromFragment( + _nextFallbackChildren2, + mode, + renderExpirationTime, + null + )); + _fallbackChildFragment2.effectTag |= Placement; + child = _primaryChildFragment2; + _primaryChildFragment2.childExpirationTime = NoWork; + // Skip the primary children, and continue working on the + // fallback children. + next = _fallbackChildFragment2; + child.return = next.return = workInProgress; + } else { + // Still haven't timed out. Continue rendering the children, like we + // normally do. + var _nextPrimaryChildren2 = nextProps.children; + next = child = reconcileChildFibers( + workInProgress, + _currentPrimaryChild, + _nextPrimaryChildren2, + renderExpirationTime + ); + } + } + workInProgress.stateNode = current$$1.stateNode; + } + + workInProgress.memoizedState = nextState; + workInProgress.child = child; + return next; +} + +function retrySuspenseComponentWithoutHydrating( + current$$1, + workInProgress, + renderExpirationTime +) { + // Detach from the current dehydrated boundary. + current$$1.alternate = null; + workInProgress.alternate = null; + + // Insert a deletion in the effect list. + var returnFiber = workInProgress.return; + (function() { + if (!(returnFiber !== null)) { + throw ReactError( + "Suspense boundaries are never on the root. This is probably a bug in React." + ); + } + })(); + var last = returnFiber.lastEffect; + if (last !== null) { + last.nextEffect = current$$1; + returnFiber.lastEffect = current$$1; + } else { + returnFiber.firstEffect = returnFiber.lastEffect = current$$1; + } + current$$1.nextEffect = null; + current$$1.effectTag = Deletion; + + // Upgrade this work in progress to a real Suspense component. + workInProgress.tag = SuspenseComponent; + workInProgress.stateNode = null; + workInProgress.memoizedState = null; + // This is now an insertion. + workInProgress.effectTag |= Placement; + // Retry as a real Suspense component. + return updateSuspenseComponent(null, workInProgress, renderExpirationTime); +} + +function updateDehydratedSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime +) { + var suspenseInstance = workInProgress.stateNode; + if (current$$1 === null) { + // During the first pass, we'll bail out and not drill into the children. + // Instead, we'll leave the content in place and try to hydrate it later. + if (isSuspenseInstanceFallback(suspenseInstance)) { + // This is a client-only boundary. Since we won't get any content from the server + // for this, we need to schedule that at a higher priority based on when it would + // have timed out. In theory we could render it in this pass but it would have the + // wrong priority associated with it and will prevent hydration of parent path. + // Instead, we'll leave work left on it to render it in a separate commit. + + // TODO This time should be the time at which the server rendered response that is + // a parent to this boundary was displayed. However, since we currently don't have + // a protocol to transfer that time, we'll just estimate it by using the current + // time. This will mean that Suspense timeouts are slightly shifted to later than + // they should be. + var serverDisplayTime = requestCurrentTime(); + // Schedule a normal pri update to render this content. + workInProgress.expirationTime = computeAsyncExpiration(serverDisplayTime); + } else { + // We'll continue hydrating the rest at offscreen priority since we'll already + // be showing the right content coming from the server, it is no rush. + workInProgress.expirationTime = Never; + } + return null; + } + if ((workInProgress.effectTag & DidCapture) !== NoEffect) { + // Something suspended. Leave the existing children in place. + // TODO: In non-concurrent mode, should we commit the nodes we have hydrated so far? + workInProgress.child = null; + return null; + } + if (isSuspenseInstanceFallback(suspenseInstance)) { + // This boundary is in a permanent fallback state. In this case, we'll never + // get an update and we'll never be able to hydrate the final content. Let's just try the + // client side render instead. + return retrySuspenseComponentWithoutHydrating( + current$$1, + workInProgress, + renderExpirationTime + ); + } + // We use childExpirationTime to indicate that a child might depend on context, so if + // any context has changed, we need to treat is as if the input might have changed. + var hasContextChanged$$1 = + current$$1.childExpirationTime >= renderExpirationTime; + if (didReceiveUpdate || hasContextChanged$$1) { + // This boundary has changed since the first render. This means that we are now unable to + // hydrate it. We might still be able to hydrate it using an earlier expiration time but + // during this render we can't. Instead, we're going to delete the whole subtree and + // instead inject a new real Suspense boundary to take its place, which may render content + // or fallback. The real Suspense boundary will suspend for a while so we have some time + // to ensure it can produce real content, but all state and pending events will be lost. + return retrySuspenseComponentWithoutHydrating( + current$$1, + workInProgress, + renderExpirationTime + ); + } else if (isSuspenseInstancePending(suspenseInstance)) { + // This component is still pending more data from the server, so we can't hydrate its + // content. We treat it as if this component suspended itself. It might seem as if + // we could just try to render it client-side instead. However, this will perform a + // lot of unnecessary work and is unlikely to complete since it often will suspend + // on missing data anyway. Additionally, the server might be able to render more + // than we can on the client yet. In that case we'd end up with more fallback states + // on the client than if we just leave it alone. If the server times out or errors + // these should update this boundary to the permanent Fallback state instead. + // Mark it as having captured (i.e. suspended). + workInProgress.effectTag |= DidCapture; + // Leave the children in place. I.e. empty. + workInProgress.child = null; + // Register a callback to retry this boundary once the server has sent the result. + registerSuspenseInstanceRetry( + suspenseInstance, + retryTimedOutBoundary.bind(null, current$$1) + ); + return null; + } else { + // This is the first attempt. + reenterHydrationStateFromDehydratedSuspenseInstance(workInProgress); + var nextProps = workInProgress.pendingProps; + var nextChildren = nextProps.children; + workInProgress.child = mountChildFibers( + workInProgress, + null, + nextChildren, + renderExpirationTime + ); + return workInProgress.child; + } +} + +function updatePortalComponent( + current$$1, + workInProgress, + renderExpirationTime +) { + pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); + var nextChildren = workInProgress.pendingProps; + if (current$$1 === null) { + // Portals are special because we don't append the children during mount + // but at commit. Therefore we need to track insertions which the normal + // flow doesn't do during mount. This doesn't happen at the root because + // the root always starts with a "current" with a null child. + // TODO: Consider unifying this with how the root works. + workInProgress.child = reconcileChildFibers( + workInProgress, + null, + nextChildren, + renderExpirationTime + ); + } else { + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + } + return workInProgress.child; +} + +function updateContextProvider( + current$$1, + workInProgress, + renderExpirationTime +) { + var providerType = workInProgress.type; + var context = providerType._context; + + var newProps = workInProgress.pendingProps; + var oldProps = workInProgress.memoizedProps; + + var newValue = newProps.value; + + { + var providerPropTypes = workInProgress.type.propTypes; + + if (providerPropTypes) { + checkPropTypes( + providerPropTypes, + newProps, + "prop", + "Context.Provider", + getCurrentFiberStackInDev + ); + } + } + + pushProvider(workInProgress, newValue); + + if (oldProps !== null) { + var oldValue = oldProps.value; + var changedBits = calculateChangedBits(context, newValue, oldValue); + if (changedBits === 0) { + // No change. Bailout early if children are the same. + if (oldProps.children === newProps.children && !hasContextChanged()) { + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + } else { + // The context value changed. Search for matching consumers and schedule + // them to update. + propagateContextChange( + workInProgress, + context, + changedBits, + renderExpirationTime + ); + } + } + + var newChildren = newProps.children; + reconcileChildren( + current$$1, + workInProgress, + newChildren, + renderExpirationTime + ); + return workInProgress.child; +} + +var hasWarnedAboutUsingContextAsConsumer = false; + +function updateContextConsumer( + current$$1, + workInProgress, + renderExpirationTime +) { + var context = workInProgress.type; + // The logic below for Context differs depending on PROD or DEV mode. In + // DEV mode, we create a separate object for Context.Consumer that acts + // like a proxy to Context. This proxy object adds unnecessary code in PROD + // so we use the old behaviour (Context.Consumer references Context) to + // reduce size and overhead. The separate object references context via + // a property called "_context", which also gives us the ability to check + // in DEV mode if this property exists or not and warn if it does not. + { + if (context._context === undefined) { + // This may be because it's a Context (rather than a Consumer). + // Or it may be because it's older React where they're the same thing. + // We only want to warn if we're sure it's a new React. + if (context !== context.Consumer) { + if (!hasWarnedAboutUsingContextAsConsumer) { + hasWarnedAboutUsingContextAsConsumer = true; + warning$1( + false, + "Rendering directly is not supported and will be removed in " + + "a future major release. Did you mean to render instead?" + ); + } + } + } else { + context = context._context; + } + } + var newProps = workInProgress.pendingProps; + var render = newProps.children; + + { + !(typeof render === "function") + ? warningWithoutStack$1( + false, + "A context consumer was rendered with multiple children, or a child " + + "that isn't a function. A context consumer expects a single child " + + "that is a function. If you did pass a function, make sure there " + + "is no trailing or leading whitespace around it." + ) + : void 0; + } + + prepareToReadContext(workInProgress, renderExpirationTime); + var newValue = readContext(context, newProps.unstable_observedBits); + var newChildren = void 0; + { + ReactCurrentOwner$3.current = workInProgress; + setCurrentPhase("render"); + newChildren = render(newValue); + setCurrentPhase(null); + } + + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + reconcileChildren( + current$$1, + workInProgress, + newChildren, + renderExpirationTime + ); + return workInProgress.child; +} + +function updateEventComponent$1( + current$$1, + workInProgress, + renderExpirationTime +) { + var nextProps = workInProgress.pendingProps; + var nextChildren = nextProps.children; + + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + pushHostContextForEventComponent(workInProgress); + return workInProgress.child; +} + +function updateEventTarget(current$$1, workInProgress, renderExpirationTime) { + var type = workInProgress.type.type; + var nextProps = workInProgress.pendingProps; + var eventTargetChild = getEventTargetChildElement(type, nextProps); + + { + !(nextProps.children == null) + ? warning$1(false, "Event targets should not have children.") + : void 0; + } + if (eventTargetChild !== null) { + var child = (workInProgress.child = createFiberFromTypeAndProps( + eventTargetChild.type, + null, + eventTargetChild.props, + null, + workInProgress.mode, + renderExpirationTime + )); + child.return = workInProgress; + + if (current$$1 === null || current$$1.child === null) { + child.effectTag = Placement; + } + } else { + reconcileChildren(current$$1, workInProgress, null, renderExpirationTime); + } + pushHostContextForEventTarget(workInProgress); + return workInProgress.child; +} + +function markWorkInProgressReceivedUpdate() { + didReceiveUpdate = true; +} + +function bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime +) { + cancelWorkTimer(workInProgress); + + if (current$$1 !== null) { + // Reuse previous context list + workInProgress.contextDependencies = current$$1.contextDependencies; + } + + if (enableProfilerTimer) { + // Don't update "base" render times for bailouts. + stopProfilerTimerIfRunning(workInProgress); + } + + // Check if the children have any pending work. + var childExpirationTime = workInProgress.childExpirationTime; + if (childExpirationTime < renderExpirationTime) { + // The children don't have any work either. We can skip them. + // TODO: Once we add back resuming, we should check if the children are + // a work-in-progress set. If so, we need to transfer their effects. + return null; + } else { + // This fiber doesn't have work, but its subtree does. Clone the child + // fibers and continue. + cloneChildFibers(current$$1, workInProgress); + return workInProgress.child; + } +} + +function beginWork$1(current$$1, workInProgress, renderExpirationTime) { + var updateExpirationTime = workInProgress.expirationTime; + + if (current$$1 !== null) { + var oldProps = current$$1.memoizedProps; + var newProps = workInProgress.pendingProps; + + if (oldProps !== newProps || hasContextChanged()) { + // If props or context changed, mark the fiber as having performed work. + // This may be unset if the props are determined to be equal later (memo). + didReceiveUpdate = true; + } else if (updateExpirationTime < renderExpirationTime) { + didReceiveUpdate = false; + // This fiber does not have any pending work. Bailout without entering + // the begin phase. There's still some bookkeeping we that needs to be done + // in this optimized path, mostly pushing stuff onto the stack. + switch (workInProgress.tag) { + case HostRoot: + pushHostRootContext(workInProgress); + resetHydrationState(); + break; + case HostComponent: + pushHostContext(workInProgress); + break; + case ClassComponent: { + var Component = workInProgress.type; + if (isContextProvider(Component)) { + pushContextProvider(workInProgress); + } + break; + } + case HostPortal: + pushHostContainer( + workInProgress, + workInProgress.stateNode.containerInfo + ); + break; + case ContextProvider: { + var newValue = workInProgress.memoizedProps.value; + pushProvider(workInProgress, newValue); + break; + } + case Profiler: + if (enableProfilerTimer) { + workInProgress.effectTag |= Update; + } + break; + case SuspenseComponent: { + var state = workInProgress.memoizedState; + var didTimeout = state !== null; + if (didTimeout) { + // If this boundary is currently timed out, we need to decide + // whether to retry the primary children, or to skip over it and + // go straight to the fallback. Check the priority of the primary + var primaryChildFragment = workInProgress.child; + var primaryChildExpirationTime = + primaryChildFragment.childExpirationTime; + if ( + primaryChildExpirationTime !== NoWork && + primaryChildExpirationTime >= renderExpirationTime + ) { + // The primary children have pending work. Use the normal path + // to attempt to render the primary children again. + return updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + } else { + // The primary children do not have pending work with sufficient + // priority. Bailout. + var child = bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + if (child !== null) { + // The fallback children have pending work. Skip over the + // primary children and work on the fallback. + return child.sibling; + } else { + return null; + } + } + } + break; + } + case DehydratedSuspenseComponent: { + if (enableSuspenseServerRenderer) { + // We know that this component will suspend again because if it has + // been unsuspended it has committed as a regular Suspense component. + // If it needs to be retried, it should have work scheduled on it. + workInProgress.effectTag |= DidCapture; + } + break; + } + case EventComponent: + if (enableEventAPI) { + pushHostContextForEventComponent(workInProgress); + } + break; + case EventTarget: { + if (enableEventAPI) { + pushHostContextForEventTarget(workInProgress); + } + break; + } + } + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + } else { + didReceiveUpdate = false; + } + + // Before entering the begin phase, clear the expiration time. + workInProgress.expirationTime = NoWork; + + switch (workInProgress.tag) { + case IndeterminateComponent: { + var elementType = workInProgress.elementType; + return mountIndeterminateComponent( + current$$1, + workInProgress, + elementType, + renderExpirationTime + ); + } + case LazyComponent: { + var _elementType = workInProgress.elementType; + return mountLazyComponent( + current$$1, + workInProgress, + _elementType, + updateExpirationTime, + renderExpirationTime + ); + } + case FunctionComponent: { + var _Component = workInProgress.type; + var unresolvedProps = workInProgress.pendingProps; + var resolvedProps = + workInProgress.elementType === _Component + ? unresolvedProps + : resolveDefaultProps(_Component, unresolvedProps); + return updateFunctionComponent( + current$$1, + workInProgress, + _Component, + resolvedProps, + renderExpirationTime + ); + } + case ClassComponent: { + var _Component2 = workInProgress.type; + var _unresolvedProps = workInProgress.pendingProps; + var _resolvedProps = + workInProgress.elementType === _Component2 + ? _unresolvedProps + : resolveDefaultProps(_Component2, _unresolvedProps); + return updateClassComponent( + current$$1, + workInProgress, + _Component2, + _resolvedProps, + renderExpirationTime + ); + } + case HostRoot: + return updateHostRoot(current$$1, workInProgress, renderExpirationTime); + case HostComponent: + return updateHostComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + case HostText: + return updateHostText(current$$1, workInProgress); + case SuspenseComponent: + return updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + case HostPortal: + return updatePortalComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + case ForwardRef: { + var type = workInProgress.type; + var _unresolvedProps2 = workInProgress.pendingProps; + var _resolvedProps2 = + workInProgress.elementType === type + ? _unresolvedProps2 + : resolveDefaultProps(type, _unresolvedProps2); + return updateForwardRef( + current$$1, + workInProgress, + type, + _resolvedProps2, + renderExpirationTime + ); + } + case Fragment: + return updateFragment(current$$1, workInProgress, renderExpirationTime); + case Mode: + return updateMode(current$$1, workInProgress, renderExpirationTime); + case Profiler: + return updateProfiler(current$$1, workInProgress, renderExpirationTime); + case ContextProvider: + return updateContextProvider( + current$$1, + workInProgress, + renderExpirationTime + ); + case ContextConsumer: + return updateContextConsumer( + current$$1, + workInProgress, + renderExpirationTime + ); + case MemoComponent: { + var _type2 = workInProgress.type; + var _unresolvedProps3 = workInProgress.pendingProps; + // Resolve outer props first, then resolve inner props. + var _resolvedProps3 = resolveDefaultProps(_type2, _unresolvedProps3); + { + if (workInProgress.type !== workInProgress.elementType) { + var outerPropTypes = _type2.propTypes; + if (outerPropTypes) { + checkPropTypes( + outerPropTypes, + _resolvedProps3, // Resolved for outer only + "prop", + getComponentName(_type2), + getCurrentFiberStackInDev + ); + } + } + } + _resolvedProps3 = resolveDefaultProps(_type2.type, _resolvedProps3); + return updateMemoComponent( + current$$1, + workInProgress, + _type2, + _resolvedProps3, + updateExpirationTime, + renderExpirationTime + ); + } + case SimpleMemoComponent: { + return updateSimpleMemoComponent( + current$$1, + workInProgress, + workInProgress.type, + workInProgress.pendingProps, + updateExpirationTime, + renderExpirationTime + ); + } + case IncompleteClassComponent: { + var _Component3 = workInProgress.type; + var _unresolvedProps4 = workInProgress.pendingProps; + var _resolvedProps4 = + workInProgress.elementType === _Component3 + ? _unresolvedProps4 + : resolveDefaultProps(_Component3, _unresolvedProps4); + return mountIncompleteClassComponent( + current$$1, + workInProgress, + _Component3, + _resolvedProps4, + renderExpirationTime + ); + } + case DehydratedSuspenseComponent: { + if (enableSuspenseServerRenderer) { + return updateDehydratedSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + } + break; + } + case EventComponent: { + if (enableEventAPI) { + return updateEventComponent$1( + current$$1, + workInProgress, + renderExpirationTime + ); + } + break; + } + case EventTarget: { + if (enableEventAPI) { + return updateEventTarget( + current$$1, + workInProgress, + renderExpirationTime + ); + } + break; + } + } + (function() { + { + throw ReactError( + "Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); +} + +function markUpdate(workInProgress) { + // Tag the fiber with an update effect. This turns a Placement into + // a PlacementAndUpdate. + workInProgress.effectTag |= Update; +} + +function markRef$1(workInProgress) { + workInProgress.effectTag |= Ref; +} + +var appendAllChildren = void 0; +var updateHostContainer = void 0; +var updateHostComponent$1 = void 0; +var updateHostText$1 = void 0; +if (supportsMutation) { + // Mutation mode + + appendAllChildren = function( + parent, + workInProgress, + needsVisibilityToggle, + isHidden + ) { + // We only have the top Fiber that was created but we need recurse down its + // children to find all the terminal nodes. + var node = workInProgress.child; + while (node !== null) { + if (node.tag === HostComponent || node.tag === HostText) { + appendInitialChild(parent, node.stateNode); + } else if (node.tag === HostPortal) { + // If we have a portal child, then we don't want to traverse + // down its children. Instead, we'll get insertions from each child in + // the portal directly. + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } + if (node === workInProgress) { + return; + } + while (node.sibling === null) { + if (node.return === null || node.return === workInProgress) { + return; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + }; + + updateHostContainer = function(workInProgress) { + // Noop + }; + updateHostComponent$1 = function( + current, + workInProgress, + type, + newProps, + rootContainerInstance + ) { + // If we have an alternate, that means this is an update and we need to + // schedule a side-effect to do the updates. + var oldProps = current.memoizedProps; + if (oldProps === newProps) { + // In mutation mode, this is sufficient for a bailout because + // we won't touch this node even if children changed. + return; + } + + // If we get updated because one of our children updated, we don't + // have newProps so we'll have to reuse them. + // TODO: Split the update API as separate for the props vs. children. + // Even better would be if children weren't special cased at all tho. + var instance = workInProgress.stateNode; + var currentHostContext = getHostContext(); + // TODO: Experiencing an error where oldProps is null. Suggests a host + // component is hitting the resume path. Figure out why. Possibly + // related to `hidden`. + var updatePayload = prepareUpdate( + instance, + type, + oldProps, + newProps, + rootContainerInstance, + currentHostContext + ); + // TODO: Type this specific to this type of component. + workInProgress.updateQueue = updatePayload; + // If the update payload indicates that there is a change or if there + // is a new ref we mark this as an update. All the work is done in commitWork. + if (updatePayload) { + markUpdate(workInProgress); + } + }; + updateHostText$1 = function(current, workInProgress, oldText, newText) { + // If the text differs, mark it as an update. All the work in done in commitWork. + if (oldText !== newText) { + markUpdate(workInProgress); + } + }; +} else if (supportsPersistence) { + // Persistent host tree mode + + appendAllChildren = function( + parent, + workInProgress, + needsVisibilityToggle, + isHidden + ) { + // We only have the top Fiber that was created but we need recurse down its + // children to find all the terminal nodes. + var node = workInProgress.child; + while (node !== null) { + // eslint-disable-next-line no-labels + branches: if (node.tag === HostComponent) { + var instance = node.stateNode; + if (needsVisibilityToggle && isHidden) { + // This child is inside a timed out tree. Hide it. + var props = node.memoizedProps; + var type = node.type; + instance = cloneHiddenInstance(instance, type, props, node); + } + appendInitialChild(parent, instance); + } else if (node.tag === HostText) { + var _instance = node.stateNode; + if (needsVisibilityToggle && isHidden) { + // This child is inside a timed out tree. Hide it. + var text = node.memoizedProps; + _instance = cloneHiddenTextInstance(_instance, text, node); + } + appendInitialChild(parent, _instance); + } else if (node.tag === HostPortal) { + // If we have a portal child, then we don't want to traverse + // down its children. Instead, we'll get insertions from each child in + // the portal directly. + } else if (node.tag === SuspenseComponent) { + if ((node.effectTag & Update) !== NoEffect) { + // Need to toggle the visibility of the primary children. + var newIsHidden = node.memoizedState !== null; + if (newIsHidden) { + var primaryChildParent = node.child; + if (primaryChildParent !== null) { + if (primaryChildParent.child !== null) { + primaryChildParent.child.return = primaryChildParent; + appendAllChildren( + parent, + primaryChildParent, + true, + newIsHidden + ); + } + var fallbackChildParent = primaryChildParent.sibling; + if (fallbackChildParent !== null) { + fallbackChildParent.return = node; + node = fallbackChildParent; + continue; + } + } + } + } + if (node.child !== null) { + // Continue traversing like normal + node.child.return = node; + node = node.child; + continue; + } + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } + // $FlowFixMe This is correct but Flow is confused by the labeled break. + node = node; + if (node === workInProgress) { + return; + } + while (node.sibling === null) { + if (node.return === null || node.return === workInProgress) { + return; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + }; + + // An unfortunate fork of appendAllChildren because we have two different parent types. + var appendAllChildrenToContainer = function( + containerChildSet, + workInProgress, + needsVisibilityToggle, + isHidden + ) { + // We only have the top Fiber that was created but we need recurse down its + // children to find all the terminal nodes. + var node = workInProgress.child; + while (node !== null) { + // eslint-disable-next-line no-labels + branches: if (node.tag === HostComponent) { + var instance = node.stateNode; + if (needsVisibilityToggle && isHidden) { + // This child is inside a timed out tree. Hide it. + var props = node.memoizedProps; + var type = node.type; + instance = cloneHiddenInstance(instance, type, props, node); + } + appendChildToContainerChildSet(containerChildSet, instance); + } else if (node.tag === HostText) { + var _instance2 = node.stateNode; + if (needsVisibilityToggle && isHidden) { + // This child is inside a timed out tree. Hide it. + var text = node.memoizedProps; + _instance2 = cloneHiddenTextInstance(_instance2, text, node); + } + appendChildToContainerChildSet(containerChildSet, _instance2); + } else if (node.tag === HostPortal) { + // If we have a portal child, then we don't want to traverse + // down its children. Instead, we'll get insertions from each child in + // the portal directly. + } else if (node.tag === SuspenseComponent) { + if ((node.effectTag & Update) !== NoEffect) { + // Need to toggle the visibility of the primary children. + var newIsHidden = node.memoizedState !== null; + if (newIsHidden) { + var primaryChildParent = node.child; + if (primaryChildParent !== null) { + if (primaryChildParent.child !== null) { + primaryChildParent.child.return = primaryChildParent; + appendAllChildrenToContainer( + containerChildSet, + primaryChildParent, + true, + newIsHidden + ); + } + var fallbackChildParent = primaryChildParent.sibling; + if (fallbackChildParent !== null) { + fallbackChildParent.return = node; + node = fallbackChildParent; + continue; + } + } + } + } + if (node.child !== null) { + // Continue traversing like normal + node.child.return = node; + node = node.child; + continue; + } + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } + // $FlowFixMe This is correct but Flow is confused by the labeled break. + node = node; + if (node === workInProgress) { + return; + } + while (node.sibling === null) { + if (node.return === null || node.return === workInProgress) { + return; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + }; + updateHostContainer = function(workInProgress) { + var portalOrRoot = workInProgress.stateNode; + var childrenUnchanged = workInProgress.firstEffect === null; + if (childrenUnchanged) { + // No changes, just reuse the existing instance. + } else { + var container = portalOrRoot.containerInfo; + var newChildSet = createContainerChildSet(container); + // If children might have changed, we have to add them all to the set. + appendAllChildrenToContainer(newChildSet, workInProgress, false, false); + portalOrRoot.pendingChildren = newChildSet; + // Schedule an update on the container to swap out the container. + markUpdate(workInProgress); + finalizeContainerChildren(container, newChildSet); + } + }; + updateHostComponent$1 = function( + current, + workInProgress, + type, + newProps, + rootContainerInstance + ) { + var currentInstance = current.stateNode; + var oldProps = current.memoizedProps; + // If there are no effects associated with this node, then none of our children had any updates. + // This guarantees that we can reuse all of them. + var childrenUnchanged = workInProgress.firstEffect === null; + if (childrenUnchanged && oldProps === newProps) { + // No changes, just reuse the existing instance. + // Note that this might release a previous clone. + workInProgress.stateNode = currentInstance; + return; + } + var recyclableInstance = workInProgress.stateNode; + var currentHostContext = getHostContext(); + var updatePayload = null; + if (oldProps !== newProps) { + updatePayload = prepareUpdate( + recyclableInstance, + type, + oldProps, + newProps, + rootContainerInstance, + currentHostContext + ); + } + if (childrenUnchanged && updatePayload === null) { + // No changes, just reuse the existing instance. + // Note that this might release a previous clone. + workInProgress.stateNode = currentInstance; + return; + } + var newInstance = cloneInstance( + currentInstance, + updatePayload, + type, + oldProps, + newProps, + workInProgress, + childrenUnchanged, + recyclableInstance + ); + if ( + finalizeInitialChildren( + newInstance, + type, + newProps, + rootContainerInstance, + currentHostContext + ) + ) { + markUpdate(workInProgress); + } + workInProgress.stateNode = newInstance; + if (childrenUnchanged) { + // If there are no other effects in this tree, we need to flag this node as having one. + // Even though we're not going to use it for anything. + // Otherwise parents won't know that there are new children to propagate upwards. + markUpdate(workInProgress); + } else { + // If children might have changed, we have to add them all to the set. + appendAllChildren(newInstance, workInProgress, false, false); + } + }; + updateHostText$1 = function(current, workInProgress, oldText, newText) { + if (oldText !== newText) { + // If the text content differs, we'll create a new text instance for it. + var rootContainerInstance = getRootHostContainer(); + var currentHostContext = getHostContext(); + workInProgress.stateNode = createTextInstance( + newText, + rootContainerInstance, + currentHostContext, + workInProgress + ); + // We'll have to mark it as having an effect, even though we won't use the effect for anything. + // This lets the parents know that at least one of their children has changed. + markUpdate(workInProgress); + } + }; +} else { + // No host operations + updateHostContainer = function(workInProgress) { + // Noop + }; + updateHostComponent$1 = function( + current, + workInProgress, + type, + newProps, + rootContainerInstance + ) { + // Noop + }; + updateHostText$1 = function(current, workInProgress, oldText, newText) { + // Noop + }; +} + +function completeWork(current, workInProgress, renderExpirationTime) { + var newProps = workInProgress.pendingProps; + + switch (workInProgress.tag) { + case IndeterminateComponent: + break; + case LazyComponent: + break; + case SimpleMemoComponent: + case FunctionComponent: + break; + case ClassComponent: { + var Component = workInProgress.type; + if (isContextProvider(Component)) { + popContext(workInProgress); + } + break; + } + case HostRoot: { + popHostContainer(workInProgress); + popTopLevelContextObject(workInProgress); + var fiberRoot = workInProgress.stateNode; + if (fiberRoot.pendingContext) { + fiberRoot.context = fiberRoot.pendingContext; + fiberRoot.pendingContext = null; + } + if (current === null || current.child === null) { + // If we hydrated, pop so that we can delete any remaining children + // that weren't hydrated. + popHydrationState(workInProgress); + // This resets the hacky state to fix isMounted before committing. + // TODO: Delete this when we delete isMounted and findDOMNode. + workInProgress.effectTag &= ~Placement; + } + updateHostContainer(workInProgress); + break; + } + case HostComponent: { + popHostContext(workInProgress); + var rootContainerInstance = getRootHostContainer(); + var type = workInProgress.type; + if (current !== null && workInProgress.stateNode != null) { + updateHostComponent$1( + current, + workInProgress, + type, + newProps, + rootContainerInstance + ); + + if (current.ref !== workInProgress.ref) { + markRef$1(workInProgress); + } + } else { + if (!newProps) { + (function() { + if (!(workInProgress.stateNode !== null)) { + throw ReactError( + "We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + // This can happen when we abort work. + break; + } + + var currentHostContext = getHostContext(); + // TODO: Move createInstance to beginWork and keep it on a context + // "stack" as the parent. Then append children as we go in beginWork + // or completeWork depending on we want to add then top->down or + // bottom->up. Top->down is faster in IE11. + var wasHydrated = popHydrationState(workInProgress); + if (wasHydrated) { + // TODO: Move this and createInstance step into the beginPhase + // to consolidate. + if ( + prepareToHydrateHostInstance( + workInProgress, + rootContainerInstance, + currentHostContext + ) + ) { + // If changes to the hydrated node needs to be applied at the + // commit-phase we mark this as such. + markUpdate(workInProgress); + } + } else { + var instance = createInstance( + type, + newProps, + rootContainerInstance, + currentHostContext, + workInProgress + ); + + appendAllChildren(instance, workInProgress, false, false); + + // Certain renderers require commit-time effects for initial mount. + // (eg DOM renderer supports auto-focus for certain elements). + // Make sure such renderers get scheduled for later work. + if ( + finalizeInitialChildren( + instance, + type, + newProps, + rootContainerInstance, + currentHostContext + ) + ) { + markUpdate(workInProgress); + } + workInProgress.stateNode = instance; + } + + if (workInProgress.ref !== null) { + // If there is a ref on a host node we need to schedule a callback + markRef$1(workInProgress); + } + } + break; + } + case HostText: { + var newText = newProps; + if (current && workInProgress.stateNode != null) { + var oldText = current.memoizedProps; + // If we have an alternate, that means this is an update and we need + // to schedule a side-effect to do the updates. + updateHostText$1(current, workInProgress, oldText, newText); + } else { + if (typeof newText !== "string") { + (function() { + if (!(workInProgress.stateNode !== null)) { + throw ReactError( + "We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + // This can happen when we abort work. + } + var _rootContainerInstance = getRootHostContainer(); + var _currentHostContext = getHostContext(); + var _wasHydrated = popHydrationState(workInProgress); + if (_wasHydrated) { + if (prepareToHydrateHostTextInstance(workInProgress)) { + markUpdate(workInProgress); + } + } else { + workInProgress.stateNode = createTextInstance( + newText, + _rootContainerInstance, + _currentHostContext, + workInProgress + ); + } + } + break; + } + case ForwardRef: + break; + case SuspenseComponent: { + var nextState = workInProgress.memoizedState; + if ((workInProgress.effectTag & DidCapture) !== NoEffect) { + // Something suspended. Re-render with the fallback children. + workInProgress.expirationTime = renderExpirationTime; + // Do not reset the effect list. + return workInProgress; + } + + var nextDidTimeout = nextState !== null; + var prevDidTimeout = false; + if (current === null) { + // In cases where we didn't find a suitable hydration boundary we never + // downgraded this to a DehydratedSuspenseComponent, but we still need to + // pop the hydration state since we might be inside the insertion tree. + popHydrationState(workInProgress); + } else { + var prevState = current.memoizedState; + prevDidTimeout = prevState !== null; + if (!nextDidTimeout && prevState !== null) { + // We just switched from the fallback to the normal children. + + // Mark the event time of the switching from fallback to normal children, + // based on the start of when we first showed the fallback. This time + var fallbackExpirationTime = prevState.fallbackExpirationTime; + markRenderEventTime(fallbackExpirationTime); + + // Delete the fallback. + // TODO: Would it be better to store the fallback fragment on + // the stateNode during the begin phase? + var currentFallbackChild = current.child.sibling; + if (currentFallbackChild !== null) { + // Deletions go at the beginning of the return fiber's effect list + var first = workInProgress.firstEffect; + if (first !== null) { + workInProgress.firstEffect = currentFallbackChild; + currentFallbackChild.nextEffect = first; + } else { + workInProgress.firstEffect = workInProgress.lastEffect = currentFallbackChild; + currentFallbackChild.nextEffect = null; + } + currentFallbackChild.effectTag = Deletion; + } + } + } + + if (nextDidTimeout && !prevDidTimeout) { + // If this subtreee is running in concurrent mode we can suspend, + // otherwise we won't suspend. + // TODO: This will still suspend a synchronous tree if anything + // in the concurrent tree already suspended during this render. + // This is a known bug. + if ((workInProgress.mode & ConcurrentMode) !== NoContext) { + renderDidSuspend(); + } + } + + if (supportsPersistence) { + // TODO: Only schedule updates if not prevDidTimeout. + if (nextDidTimeout) { + // If this boundary just timed out, schedule an effect to attach a + // retry listener to the proimse. This flag is also used to hide the + // primary children. + workInProgress.effectTag |= Update; + } + } + if (supportsMutation) { + // TODO: Only schedule updates if these values are non equal, i.e. it changed. + if (nextDidTimeout || prevDidTimeout) { + // If this boundary just timed out, schedule an effect to attach a + // retry listener to the proimse. This flag is also used to hide the + // primary children. In mutation mode, we also need the flag to + // *unhide* children that were previously hidden, so check if the + // is currently timed out, too. + workInProgress.effectTag |= Update; + } + } + break; + } + case Fragment: + break; + case Mode: + break; + case Profiler: + break; + case HostPortal: + popHostContainer(workInProgress); + updateHostContainer(workInProgress); + break; + case ContextProvider: + // Pop provider fiber + popProvider(workInProgress); + break; + case ContextConsumer: + break; + case MemoComponent: + break; + case IncompleteClassComponent: { + // Same as class component case. I put it down here so that the tags are + // sequential to ensure this switch is compiled to a jump table. + var _Component = workInProgress.type; + if (isContextProvider(_Component)) { + popContext(workInProgress); + } + break; + } + case DehydratedSuspenseComponent: { + if (enableSuspenseServerRenderer) { + if (current === null) { + var _wasHydrated2 = popHydrationState(workInProgress); + (function() { + if (!_wasHydrated2) { + throw ReactError( + "A dehydrated suspense component was completed without a hydrated node. This is probably a bug in React." + ); + } + })(); + skipPastDehydratedSuspenseInstance(workInProgress); + } else if ((workInProgress.effectTag & DidCapture) === NoEffect) { + // This boundary did not suspend so it's now hydrated. + // To handle any future suspense cases, we're going to now upgrade it + // to a Suspense component. We detach it from the existing current fiber. + current.alternate = null; + workInProgress.alternate = null; + workInProgress.tag = SuspenseComponent; + workInProgress.memoizedState = null; + workInProgress.stateNode = null; + } + } + break; + } + case EventComponent: { + if (enableEventAPI) { + popHostContext(workInProgress); + var _rootContainerInstance2 = getRootHostContainer(); + var responder = workInProgress.type.responder; + var eventComponentInstance = workInProgress.stateNode; + + if (eventComponentInstance === null) { + var responderState = null; + if (responder.createInitialState !== undefined) { + responderState = responder.createInitialState(newProps); + } + eventComponentInstance = workInProgress.stateNode = { + currentFiber: workInProgress, + props: newProps, + responder: responder, + rootEventTypes: null, + rootInstance: _rootContainerInstance2, + state: responderState + }; + markUpdate(workInProgress); + } else { + // Update the props on the event component state node + eventComponentInstance.props = newProps; + // Update the root container, so we can properly unmount events at some point + eventComponentInstance.rootInstance = _rootContainerInstance2; + // Update the current fiber + eventComponentInstance.currentFiber = workInProgress; + updateEventComponent(eventComponentInstance); + } + } + break; + } + case EventTarget: { + if (enableEventAPI) { + popHostContext(workInProgress); + var _type = workInProgress.type.type; + var _rootContainerInstance3 = getRootHostContainer(); + var shouldUpdate = handleEventTarget( + _type, + newProps, + _rootContainerInstance3, + workInProgress + ); + // Update the latest props on the stateNode. This is used + // during the event phase to find the most current props. + workInProgress.stateNode.props = newProps; + if (shouldUpdate) { + markUpdate(workInProgress); + } + } + break; + } + default: + (function() { + { + throw ReactError( + "Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + + return null; +} + +function shouldCaptureSuspense(workInProgress) { + // In order to capture, the Suspense component must have a fallback prop. + if (workInProgress.memoizedProps.fallback === undefined) { + return false; + } + // If it was the primary children that just suspended, capture and render the + // fallback. Otherwise, don't capture and bubble to the next boundary. + var nextState = workInProgress.memoizedState; + return nextState === null; +} + +function createCapturedValue(value, source) { + // If the value is an error, call this function immediately after it is thrown + // so the stack is accurate. + return { + value: value, + source: source, + stack: getStackByFiberInDevAndProd(source) + }; +} + +// Module provided by RN: +/** + * Intercept lifecycle errors and ensure they are shown with the correct stack + * trace within the native redbox component. + */ +function showErrorDialog(capturedError) { + var componentStack = capturedError.componentStack, + error = capturedError.error; + + var errorToHandle = void 0; + + // Typically Errors are thrown but eg strings or null can be thrown as well. + if (error instanceof Error) { + var message = error.message, + name = error.name; + + var summary = message ? name + ": " + message : name; + + errorToHandle = error; + + try { + errorToHandle.message = + summary + "\n\nThis error is located at:" + componentStack; + } catch (e) {} + } else if (typeof error === "string") { + errorToHandle = new Error( + error + "\n\nThis error is located at:" + componentStack + ); + } else { + errorToHandle = new Error("Unspecified error at:" + componentStack); + } + + ReactNativePrivateInterface.ExceptionsManager.handleException( + errorToHandle, + false + ); + + // Return false here to prevent ReactFiberErrorLogger default behavior of + // logging error details to console.error. Calls to console.error are + // automatically routed to the native redbox controller, which we've already + // done above by calling ExceptionsManager. + return false; +} + +function logCapturedError(capturedError) { + var logError = showErrorDialog(capturedError); + + // Allow injected showErrorDialog() to prevent default console.error logging. + // This enables renderers like ReactNative to better manage redbox behavior. + if (logError === false) { + return; + } + + var error = capturedError.error; + { + var componentName = capturedError.componentName, + componentStack = capturedError.componentStack, + errorBoundaryName = capturedError.errorBoundaryName, + errorBoundaryFound = capturedError.errorBoundaryFound, + willRetry = capturedError.willRetry; + + // Browsers support silencing uncaught errors by calling + // `preventDefault()` in window `error` handler. + // We record this information as an expando on the error. + + if (error != null && error._suppressLogging) { + if (errorBoundaryFound && willRetry) { + // The error is recoverable and was silenced. + // Ignore it and don't print the stack addendum. + // This is handy for testing error boundaries without noise. + return; + } + // The error is fatal. Since the silencing might have + // been accidental, we'll surface it anyway. + // However, the browser would have silenced the original error + // so we'll print it first, and then print the stack addendum. + console.error(error); + // For a more detailed description of this block, see: + // https://github.com/facebook/react/pull/13384 + } + + var componentNameMessage = componentName + ? "The above error occurred in the <" + componentName + "> component:" + : "The above error occurred in one of your React components:"; + + var errorBoundaryMessage = void 0; + // errorBoundaryFound check is sufficient; errorBoundaryName check is to satisfy Flow. + if (errorBoundaryFound && errorBoundaryName) { + if (willRetry) { + errorBoundaryMessage = + "React will try to recreate this component tree from scratch " + + ("using the error boundary you provided, " + errorBoundaryName + "."); + } else { + errorBoundaryMessage = + "This error was initially handled by the error boundary " + + errorBoundaryName + + ".\n" + + "Recreating the tree from scratch failed so React will unmount the tree."; + } + } else { + errorBoundaryMessage = + "Consider adding an error boundary to your tree to customize error handling behavior.\n" + + "Visit https://fb.me/react-error-boundaries to learn more about error boundaries."; + } + var combinedMessage = + "" + + componentNameMessage + + componentStack + + "\n\n" + + ("" + errorBoundaryMessage); + + // In development, we provide our own message with just the component stack. + // We don't include the original error message and JS stack because the browser + // has already printed it. Even if the application swallows the error, it is still + // displayed by the browser thanks to the DEV-only fake event trick in ReactErrorUtils. + console.error(combinedMessage); + } +} + +var didWarnAboutUndefinedSnapshotBeforeUpdate = null; +{ + didWarnAboutUndefinedSnapshotBeforeUpdate = new Set(); +} + +var PossiblyWeakSet$1 = typeof WeakSet === "function" ? WeakSet : Set; + +function logError(boundary, errorInfo) { + var source = errorInfo.source; + var stack = errorInfo.stack; + if (stack === null && source !== null) { + stack = getStackByFiberInDevAndProd(source); + } + + var capturedError = { + componentName: source !== null ? getComponentName(source.type) : null, + componentStack: stack !== null ? stack : "", + error: errorInfo.value, + errorBoundary: null, + errorBoundaryName: null, + errorBoundaryFound: false, + willRetry: false + }; + + if (boundary !== null && boundary.tag === ClassComponent) { + capturedError.errorBoundary = boundary.stateNode; + capturedError.errorBoundaryName = getComponentName(boundary.type); + capturedError.errorBoundaryFound = true; + capturedError.willRetry = true; + } + + try { + logCapturedError(capturedError); + } catch (e) { + // This method must not throw, or React internal state will get messed up. + // If console.error is overridden, or logCapturedError() shows a dialog that throws, + // we want to report this error outside of the normal stack as a last resort. + // https://github.com/facebook/react/issues/13188 + setTimeout(function() { + throw e; + }); + } +} + +var callComponentWillUnmountWithTimer = function(current$$1, instance) { + startPhaseTimer(current$$1, "componentWillUnmount"); + instance.props = current$$1.memoizedProps; + instance.state = current$$1.memoizedState; + instance.componentWillUnmount(); + stopPhaseTimer(); +}; + +// Capture errors so they don't interrupt unmounting. +function safelyCallComponentWillUnmount(current$$1, instance) { + { + invokeGuardedCallback( + null, + callComponentWillUnmountWithTimer, + null, + current$$1, + instance + ); + if (hasCaughtError()) { + var unmountError = clearCaughtError(); + captureCommitPhaseError(current$$1, unmountError); + } + } +} + +function safelyDetachRef(current$$1) { + var ref = current$$1.ref; + if (ref !== null) { + if (typeof ref === "function") { + { + invokeGuardedCallback(null, ref, null, null); + if (hasCaughtError()) { + var refError = clearCaughtError(); + captureCommitPhaseError(current$$1, refError); + } + } + } else { + ref.current = null; + } + } +} + +function safelyCallDestroy(current$$1, destroy) { + { + invokeGuardedCallback(null, destroy, null); + if (hasCaughtError()) { + var error = clearCaughtError(); + captureCommitPhaseError(current$$1, error); + } + } +} + +function commitBeforeMutationLifeCycles(current$$1, finishedWork) { + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: { + commitHookEffectList(UnmountSnapshot, NoEffect$1, finishedWork); + return; + } + case ClassComponent: { + if (finishedWork.effectTag & Snapshot) { + if (current$$1 !== null) { + var prevProps = current$$1.memoizedProps; + var prevState = current$$1.memoizedState; + startPhaseTimer(finishedWork, "getSnapshotBeforeUpdate"); + var instance = finishedWork.stateNode; + // We could update instance props and state here, + // but instead we rely on them being set during last render. + // TODO: revisit this when we implement resuming. + { + if ( + finishedWork.type === finishedWork.elementType && + !didWarnAboutReassigningProps + ) { + !(instance.props === finishedWork.memoizedProps) + ? warning$1( + false, + "Expected %s props to match memoized props before " + + "getSnapshotBeforeUpdate. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentName(finishedWork.type) || "instance" + ) + : void 0; + !(instance.state === finishedWork.memoizedState) + ? warning$1( + false, + "Expected %s state to match memoized state before " + + "getSnapshotBeforeUpdate. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentName(finishedWork.type) || "instance" + ) + : void 0; + } + } + var snapshot = instance.getSnapshotBeforeUpdate( + finishedWork.elementType === finishedWork.type + ? prevProps + : resolveDefaultProps(finishedWork.type, prevProps), + prevState + ); + { + var didWarnSet = didWarnAboutUndefinedSnapshotBeforeUpdate; + if (snapshot === undefined && !didWarnSet.has(finishedWork.type)) { + didWarnSet.add(finishedWork.type); + warningWithoutStack$1( + false, + "%s.getSnapshotBeforeUpdate(): A snapshot value (or null) " + + "must be returned. You have returned undefined.", + getComponentName(finishedWork.type) + ); + } + } + instance.__reactInternalSnapshotBeforeUpdate = snapshot; + stopPhaseTimer(); + } + } + return; + } + case HostRoot: + case HostComponent: + case HostText: + case HostPortal: + case IncompleteClassComponent: + case EventTarget: + // Nothing to do for these component types + return; + default: { + (function() { + { + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + } +} + +function commitHookEffectList(unmountTag, mountTag, finishedWork) { + var updateQueue = finishedWork.updateQueue; + var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null; + if (lastEffect !== null) { + var firstEffect = lastEffect.next; + var effect = firstEffect; + do { + if ((effect.tag & unmountTag) !== NoEffect$1) { + // Unmount + var destroy = effect.destroy; + effect.destroy = undefined; + if (destroy !== undefined) { + destroy(); + } + } + if ((effect.tag & mountTag) !== NoEffect$1) { + // Mount + var create = effect.create; + effect.destroy = create(); + + { + var _destroy = effect.destroy; + if (_destroy !== undefined && typeof _destroy !== "function") { + var addendum = void 0; + if (_destroy === null) { + addendum = + " You returned null. If your effect does not require clean " + + "up, return undefined (or nothing)."; + } else if (typeof _destroy.then === "function") { + addendum = + "\n\nIt looks like you wrote useEffect(async () => ...) or returned a Promise. " + + "Instead, write the async function inside your effect " + + "and call it immediately:\n\n" + + "useEffect(() => {\n" + + " async function fetchData() {\n" + + " // You can await here\n" + + " const response = await MyAPI.getData(someId);\n" + + " // ...\n" + + " }\n" + + " fetchData();\n" + + "}, [someId]); // Or [] if effect doesn't need props or state\n\n" + + "Learn more about data fetching with Hooks: https://fb.me/react-hooks-data-fetching"; + } else { + addendum = " You returned: " + _destroy; + } + warningWithoutStack$1( + false, + "An effect function must not return anything besides a function, " + + "which is used for clean-up.%s%s", + addendum, + getStackByFiberInDevAndProd(finishedWork) + ); + } + } + } + effect = effect.next; + } while (effect !== firstEffect); + } +} + +function commitPassiveHookEffects(finishedWork) { + commitHookEffectList(UnmountPassive, NoEffect$1, finishedWork); + commitHookEffectList(NoEffect$1, MountPassive, finishedWork); +} + +function commitLifeCycles( + finishedRoot, + current$$1, + finishedWork, + committedExpirationTime +) { + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: { + commitHookEffectList(UnmountLayout, MountLayout, finishedWork); + break; + } + case ClassComponent: { + var instance = finishedWork.stateNode; + if (finishedWork.effectTag & Update) { + if (current$$1 === null) { + startPhaseTimer(finishedWork, "componentDidMount"); + // We could update instance props and state here, + // but instead we rely on them being set during last render. + // TODO: revisit this when we implement resuming. + { + if ( + finishedWork.type === finishedWork.elementType && + !didWarnAboutReassigningProps + ) { + !(instance.props === finishedWork.memoizedProps) + ? warning$1( + false, + "Expected %s props to match memoized props before " + + "componentDidMount. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentName(finishedWork.type) || "instance" + ) + : void 0; + !(instance.state === finishedWork.memoizedState) + ? warning$1( + false, + "Expected %s state to match memoized state before " + + "componentDidMount. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentName(finishedWork.type) || "instance" + ) + : void 0; + } + } + instance.componentDidMount(); + stopPhaseTimer(); + } else { + var prevProps = + finishedWork.elementType === finishedWork.type + ? current$$1.memoizedProps + : resolveDefaultProps( + finishedWork.type, + current$$1.memoizedProps + ); + var prevState = current$$1.memoizedState; + startPhaseTimer(finishedWork, "componentDidUpdate"); + // We could update instance props and state here, + // but instead we rely on them being set during last render. + // TODO: revisit this when we implement resuming. + { + if ( + finishedWork.type === finishedWork.elementType && + !didWarnAboutReassigningProps + ) { + !(instance.props === finishedWork.memoizedProps) + ? warning$1( + false, + "Expected %s props to match memoized props before " + + "componentDidUpdate. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentName(finishedWork.type) || "instance" + ) + : void 0; + !(instance.state === finishedWork.memoizedState) + ? warning$1( + false, + "Expected %s state to match memoized state before " + + "componentDidUpdate. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentName(finishedWork.type) || "instance" + ) + : void 0; + } + } + instance.componentDidUpdate( + prevProps, + prevState, + instance.__reactInternalSnapshotBeforeUpdate + ); + stopPhaseTimer(); + } + } + var updateQueue = finishedWork.updateQueue; + if (updateQueue !== null) { + { + if ( + finishedWork.type === finishedWork.elementType && + !didWarnAboutReassigningProps + ) { + !(instance.props === finishedWork.memoizedProps) + ? warning$1( + false, + "Expected %s props to match memoized props before " + + "processing the update queue. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentName(finishedWork.type) || "instance" + ) + : void 0; + !(instance.state === finishedWork.memoizedState) + ? warning$1( + false, + "Expected %s state to match memoized state before " + + "processing the update queue. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentName(finishedWork.type) || "instance" + ) + : void 0; + } + } + // We could update instance props and state here, + // but instead we rely on them being set during last render. + // TODO: revisit this when we implement resuming. + commitUpdateQueue( + finishedWork, + updateQueue, + instance, + committedExpirationTime + ); + } + return; + } + case HostRoot: { + var _updateQueue = finishedWork.updateQueue; + if (_updateQueue !== null) { + var _instance = null; + if (finishedWork.child !== null) { + switch (finishedWork.child.tag) { + case HostComponent: + _instance = getPublicInstance(finishedWork.child.stateNode); + break; + case ClassComponent: + _instance = finishedWork.child.stateNode; + break; + } + } + commitUpdateQueue( + finishedWork, + _updateQueue, + _instance, + committedExpirationTime + ); + } + return; + } + case HostComponent: { + var _instance2 = finishedWork.stateNode; + + // Renderers may schedule work to be done after host components are mounted + // (eg DOM renderer may schedule auto-focus for inputs and form controls). + // These effects should only be committed when components are first mounted, + // aka when there is no current/alternate. + if (current$$1 === null && finishedWork.effectTag & Update) { + var type = finishedWork.type; + var props = finishedWork.memoizedProps; + commitMount(_instance2, type, props, finishedWork); + } + + return; + } + case HostText: { + // We have no life-cycles associated with text. + return; + } + case HostPortal: { + // We have no life-cycles associated with portals. + return; + } + case Profiler: { + if (enableProfilerTimer) { + var onRender = finishedWork.memoizedProps.onRender; + + if (enableSchedulerTracing) { + onRender( + finishedWork.memoizedProps.id, + current$$1 === null ? "mount" : "update", + finishedWork.actualDuration, + finishedWork.treeBaseDuration, + finishedWork.actualStartTime, + getCommitTime(), + finishedRoot.memoizedInteractions + ); + } else { + onRender( + finishedWork.memoizedProps.id, + current$$1 === null ? "mount" : "update", + finishedWork.actualDuration, + finishedWork.treeBaseDuration, + finishedWork.actualStartTime, + getCommitTime() + ); + } + } + return; + } + case SuspenseComponent: + case IncompleteClassComponent: + return; + case EventTarget: { + if (enableEventAPI) { + var _type = finishedWork.type.type; + var _props = finishedWork.memoizedProps; + var _instance3 = finishedWork.stateNode; + var parentInstance = null; + + var node = finishedWork.return; + // Traverse up the fiber tree until we find the parent host node. + while (node !== null) { + if (node.tag === HostComponent) { + parentInstance = node.stateNode; + break; + } else if (node.tag === HostRoot) { + parentInstance = node.stateNode.containerInfo; + break; + } + node = node.return; + } + (function() { + if (!(parentInstance !== null)) { + throw ReactError( + "This should have a parent host component initialized. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + commitEventTarget(_type, _props, _instance3, parentInstance); + } + return; + } + case EventComponent: { + if (enableEventAPI) { + mountEventComponent(finishedWork.stateNode); + } + return; + } + default: { + (function() { + { + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + } +} + +function hideOrUnhideAllChildren(finishedWork, isHidden) { + if (supportsMutation) { + // We only have the top Fiber that was inserted but we need to recurse down its + var node = finishedWork; + while (true) { + if (node.tag === HostComponent) { + var instance = node.stateNode; + if (isHidden) { + hideInstance(instance); + } else { + unhideInstance(node.stateNode, node.memoizedProps); + } + } else if (node.tag === HostText) { + var _instance4 = node.stateNode; + if (isHidden) { + hideTextInstance(_instance4); + } else { + unhideTextInstance(_instance4, node.memoizedProps); + } + } else if ( + node.tag === SuspenseComponent && + node.memoizedState !== null + ) { + // Found a nested Suspense component that timed out. Skip over the + var fallbackChildFragment = node.child.sibling; + fallbackChildFragment.return = node; + node = fallbackChildFragment; + continue; + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } + if (node === finishedWork) { + return; + } + while (node.sibling === null) { + if (node.return === null || node.return === finishedWork) { + return; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + } +} + +function commitAttachRef(finishedWork) { + var ref = finishedWork.ref; + if (ref !== null) { + var instance = finishedWork.stateNode; + var instanceToUse = void 0; + switch (finishedWork.tag) { + case HostComponent: + instanceToUse = getPublicInstance(instance); + break; + default: + instanceToUse = instance; + } + if (typeof ref === "function") { + ref(instanceToUse); + } else { + { + if (!ref.hasOwnProperty("current")) { + warningWithoutStack$1( + false, + "Unexpected ref object provided for %s. " + + "Use either a ref-setter function or React.createRef().%s", + getComponentName(finishedWork.type), + getStackByFiberInDevAndProd(finishedWork) + ); + } + } + + ref.current = instanceToUse; + } + } +} + +function commitDetachRef(current$$1) { + var currentRef = current$$1.ref; + if (currentRef !== null) { + if (typeof currentRef === "function") { + currentRef(null); + } else { + currentRef.current = null; + } + } +} + +// User-originating errors (lifecycles and refs) should not interrupt +// deletion, so don't let them throw. Host-originating errors should +// interrupt deletion, so it's okay +function commitUnmount(current$$1) { + onCommitUnmount(current$$1); + + switch (current$$1.tag) { + case FunctionComponent: + case ForwardRef: + case MemoComponent: + case SimpleMemoComponent: { + var updateQueue = current$$1.updateQueue; + if (updateQueue !== null) { + var lastEffect = updateQueue.lastEffect; + if (lastEffect !== null) { + var firstEffect = lastEffect.next; + var effect = firstEffect; + do { + var destroy = effect.destroy; + if (destroy !== undefined) { + safelyCallDestroy(current$$1, destroy); + } + effect = effect.next; + } while (effect !== firstEffect); + } + } + break; + } + case ClassComponent: { + safelyDetachRef(current$$1); + var instance = current$$1.stateNode; + if (typeof instance.componentWillUnmount === "function") { + safelyCallComponentWillUnmount(current$$1, instance); + } + return; + } + case HostComponent: { + safelyDetachRef(current$$1); + return; + } + case HostPortal: { + // TODO: this is recursive. + // We are also not using this parent because + // the portal will get pushed immediately. + if (supportsMutation) { + unmountHostComponents(current$$1); + } else if (supportsPersistence) { + emptyPortalContainer(current$$1); + } + return; + } + case EventComponent: { + if (enableEventAPI) { + var eventComponentInstance = current$$1.stateNode; + unmountEventComponent(eventComponentInstance); + current$$1.stateNode = null; + } + } + } +} + +function commitNestedUnmounts(root) { + // While we're inside a removed host node we don't want to call + // removeChild on the inner nodes because they're removed by the top + // call anyway. We also want to call componentWillUnmount on all + // composites before this host node is removed from the tree. Therefore + var node = root; + while (true) { + commitUnmount(node); + // Visit children because they may contain more composite or host nodes. + // Skip portals because commitUnmount() currently visits them recursively. + if ( + node.child !== null && + // If we use mutation we drill down into portals using commitUnmount above. + // If we don't use mutation we drill down into portals here instead. + (!supportsMutation || node.tag !== HostPortal) + ) { + node.child.return = node; + node = node.child; + continue; + } + if (node === root) { + return; + } + while (node.sibling === null) { + if (node.return === null || node.return === root) { + return; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } +} + +function detachFiber(current$$1) { + // Cut off the return pointers to disconnect it from the tree. Ideally, we + // should clear the child pointer of the parent alternate to let this + // get GC:ed but we don't know which for sure which parent is the current + // one so we'll settle for GC:ing the subtree of this child. This child + // itself will be GC:ed when the parent updates the next time. + current$$1.return = null; + current$$1.child = null; + current$$1.memoizedState = null; + current$$1.updateQueue = null; + var alternate = current$$1.alternate; + if (alternate !== null) { + alternate.return = null; + alternate.child = null; + alternate.memoizedState = null; + alternate.updateQueue = null; + } +} + +function emptyPortalContainer(current$$1) { + if (!supportsPersistence) { + return; + } + + var portal = current$$1.stateNode; + var containerInfo = portal.containerInfo; + + var emptyChildSet = createContainerChildSet(containerInfo); +} + +function commitContainer(finishedWork) { + if (!supportsPersistence) { + return; + } + + switch (finishedWork.tag) { + case ClassComponent: + case HostComponent: + case HostText: + case EventTarget: + case EventComponent: { + return; + } + case HostRoot: + case HostPortal: { + var portalOrRoot = finishedWork.stateNode; + var containerInfo = portalOrRoot.containerInfo, + _pendingChildren = portalOrRoot.pendingChildren; + + return; + } + default: { + (function() { + { + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + } +} + +function getHostParentFiber(fiber) { + var parent = fiber.return; + while (parent !== null) { + if (isHostParent(parent)) { + return parent; + } + parent = parent.return; + } + (function() { + { + throw ReactError( + "Expected to find a host parent. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); +} + +function isHostParent(fiber) { + return ( + fiber.tag === HostComponent || + fiber.tag === HostRoot || + fiber.tag === HostPortal + ); +} + +function getHostSibling(fiber) { + // We're going to search forward into the tree until we find a sibling host + // node. Unfortunately, if multiple insertions are done in a row we have to + // search past them. This leads to exponential search for the next sibling. + var node = fiber; + siblings: while (true) { + // If we didn't find anything, let's try the next sibling. + while (node.sibling === null) { + if (node.return === null || isHostParent(node.return)) { + // If we pop out of the root or hit the parent the fiber we are the + // last sibling. + return null; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + while ( + node.tag !== HostComponent && + node.tag !== HostText && + node.tag !== DehydratedSuspenseComponent + ) { + // If it is not host node and, we might have a host node inside it. + // Try to search down until we find one. + if (node.effectTag & Placement) { + // If we don't have a child, try the siblings instead. + continue siblings; + } + // If we don't have a child, try the siblings instead. + // We also skip portals because they are not part of this host tree. + if (node.child === null || node.tag === HostPortal) { + continue siblings; + } else { + node.child.return = node; + node = node.child; + } + } + // Check if this host node is stable or about to be placed. + if (!(node.effectTag & Placement)) { + // Found it! + return node.stateNode; + } + } +} + +function commitPlacement(finishedWork) { + if (!supportsMutation) { + return; + } + + // Recursively insert all host nodes into the parent. + var parentFiber = getHostParentFiber(finishedWork); + + // Note: these two variables *must* always be updated together. + var parent = void 0; + var isContainer = void 0; + + switch (parentFiber.tag) { + case HostComponent: + parent = parentFiber.stateNode; + isContainer = false; + break; + case HostRoot: + parent = parentFiber.stateNode.containerInfo; + isContainer = true; + break; + case HostPortal: + parent = parentFiber.stateNode.containerInfo; + isContainer = true; + break; + default: + (function() { + { + throw ReactError( + "Invalid host parent fiber. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + if (parentFiber.effectTag & ContentReset) { + // Reset the text content of the parent before doing any insertions + resetTextContent(parent); + // Clear ContentReset from the effect tag + parentFiber.effectTag &= ~ContentReset; + } + + var before = getHostSibling(finishedWork); + // We only have the top Fiber that was inserted but we need to recurse down its + // children to find all the terminal nodes. + var node = finishedWork; + while (true) { + if (node.tag === HostComponent || node.tag === HostText) { + var stateNode = node.stateNode; + if (before) { + if (isContainer) { + insertInContainerBefore(parent, stateNode, before); + } else { + insertBefore(parent, stateNode, before); + } + } else { + if (isContainer) { + appendChildToContainer(parent, stateNode); + } else { + appendChild(parent, stateNode); + } + } + } else if (node.tag === HostPortal) { + // If the insertion itself is a portal, then we don't want to traverse + // down its children. Instead, we'll get insertions from each child in + // the portal directly. + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } + if (node === finishedWork) { + return; + } + while (node.sibling === null) { + if (node.return === null || node.return === finishedWork) { + return; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } +} + +function unmountHostComponents(current$$1) { + // We only have the top Fiber that was deleted but we need to recurse down its + var node = current$$1; + + // Each iteration, currentParent is populated with node's host parent if not + // currentParentIsValid. + var currentParentIsValid = false; + + // Note: these two variables *must* always be updated together. + var currentParent = void 0; + var currentParentIsContainer = void 0; + + while (true) { + if (!currentParentIsValid) { + var parent = node.return; + findParent: while (true) { + (function() { + if (!(parent !== null)) { + throw ReactError( + "Expected to find a host parent. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + switch (parent.tag) { + case HostComponent: + currentParent = parent.stateNode; + currentParentIsContainer = false; + break findParent; + case HostRoot: + currentParent = parent.stateNode.containerInfo; + currentParentIsContainer = true; + break findParent; + case HostPortal: + currentParent = parent.stateNode.containerInfo; + currentParentIsContainer = true; + break findParent; + } + parent = parent.return; + } + currentParentIsValid = true; + } + + if (node.tag === HostComponent || node.tag === HostText) { + commitNestedUnmounts(node); + // After all the children have unmounted, it is now safe to remove the + // node from the tree. + if (currentParentIsContainer) { + removeChildFromContainer(currentParent, node.stateNode); + } else { + removeChild(currentParent, node.stateNode); + } + // Don't visit children because we already visited them. + } else if ( + enableSuspenseServerRenderer && + node.tag === DehydratedSuspenseComponent + ) { + // Delete the dehydrated suspense boundary and all of its content. + if (currentParentIsContainer) { + clearSuspenseBoundaryFromContainer(currentParent, node.stateNode); + } else { + clearSuspenseBoundary(currentParent, node.stateNode); + } + } else if (node.tag === HostPortal) { + if (node.child !== null) { + // When we go into a portal, it becomes the parent to remove from. + // We will reassign it back when we pop the portal on the way up. + currentParent = node.stateNode.containerInfo; + currentParentIsContainer = true; + // Visit children because portals might contain host components. + node.child.return = node; + node = node.child; + continue; + } + } else { + commitUnmount(node); + // Visit children because we may find more host components below. + if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } + } + if (node === current$$1) { + return; + } + while (node.sibling === null) { + if (node.return === null || node.return === current$$1) { + return; + } + node = node.return; + if (node.tag === HostPortal) { + // When we go out of the portal, we need to restore the parent. + // Since we don't keep a stack of them, we will search for it. + currentParentIsValid = false; + } + } + node.sibling.return = node.return; + node = node.sibling; + } +} + +function commitDeletion(current$$1) { + if (supportsMutation) { + // Recursively delete all host nodes from the parent. + // Detach refs and call componentWillUnmount() on the whole subtree. + unmountHostComponents(current$$1); + } else { + // Detach refs and call componentWillUnmount() on the whole subtree. + commitNestedUnmounts(current$$1); + } + detachFiber(current$$1); +} + +function commitWork(current$$1, finishedWork) { + if (!supportsMutation) { + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case MemoComponent: + case SimpleMemoComponent: { + // Note: We currently never use MountMutation, but useLayout uses + // UnmountMutation. + commitHookEffectList(UnmountMutation, MountMutation, finishedWork); + return; + } + case Profiler: { + return; + } + case SuspenseComponent: { + commitSuspenseComponent(finishedWork); + return; + } + } + + commitContainer(finishedWork); + return; + } + + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case MemoComponent: + case SimpleMemoComponent: { + // Note: We currently never use MountMutation, but useLayout uses + // UnmountMutation. + commitHookEffectList(UnmountMutation, MountMutation, finishedWork); + return; + } + case ClassComponent: { + return; + } + case HostComponent: { + var instance = finishedWork.stateNode; + if (instance != null) { + // Commit the work prepared earlier. + var newProps = finishedWork.memoizedProps; + // For hydration we reuse the update path but we treat the oldProps + // as the newProps. The updatePayload will contain the real change in + // this case. + var oldProps = + current$$1 !== null ? current$$1.memoizedProps : newProps; + var type = finishedWork.type; + // TODO: Type the updateQueue to be specific to host components. + var updatePayload = finishedWork.updateQueue; + finishedWork.updateQueue = null; + if (updatePayload !== null) { + commitUpdate( + instance, + updatePayload, + type, + oldProps, + newProps, + finishedWork + ); + } + } + return; + } + case HostText: { + (function() { + if (!(finishedWork.stateNode !== null)) { + throw ReactError( + "This should have a text node initialized. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + var textInstance = finishedWork.stateNode; + var newText = finishedWork.memoizedProps; + // For hydration we reuse the update path but we treat the oldProps + // as the newProps. The updatePayload will contain the real change in + // this case. + var oldText = current$$1 !== null ? current$$1.memoizedProps : newText; + commitTextUpdate(textInstance, oldText, newText); + return; + } + case EventTarget: { + return; + } + case HostRoot: { + return; + } + case Profiler: { + return; + } + case SuspenseComponent: { + commitSuspenseComponent(finishedWork); + return; + } + case IncompleteClassComponent: { + return; + } + case EventComponent: { + return; + } + default: { + (function() { + { + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + } +} + +function commitSuspenseComponent(finishedWork) { + var newState = finishedWork.memoizedState; + + var newDidTimeout = void 0; + var primaryChildParent = finishedWork; + if (newState === null) { + newDidTimeout = false; + } else { + newDidTimeout = true; + primaryChildParent = finishedWork.child; + if (newState.fallbackExpirationTime === NoWork) { + // If the children had not already timed out, record the time. + // This is used to compute the elapsed time during subsequent + // attempts to render the children. + // We model this as a normal pri expiration time since that's + // how we infer start time for updates. + newState.fallbackExpirationTime = computeAsyncExpirationNoBucket( + requestCurrentTime() + ); + } + } + + if (supportsMutation && primaryChildParent !== null) { + hideOrUnhideAllChildren(primaryChildParent, newDidTimeout); + } + + // If this boundary just timed out, then it will have a set of thenables. + // For each thenable, attach a listener so that when it resolves, React + // attempts to re-render the boundary in the primary (pre-timeout) state. + var thenables = finishedWork.updateQueue; + if (thenables !== null) { + finishedWork.updateQueue = null; + var retryCache = finishedWork.stateNode; + if (retryCache === null) { + retryCache = finishedWork.stateNode = new PossiblyWeakSet$1(); + } + thenables.forEach(function(thenable) { + // Memoize using the boundary fiber to prevent redundant listeners. + var retry = resolveRetryThenable.bind(null, finishedWork, thenable); + if (!retryCache.has(thenable)) { + if (enableSchedulerTracing) { + retry = tracing.unstable_wrap(retry); + } + retryCache.add(thenable); + thenable.then(retry, retry); + } + }); + } +} + +function commitResetTextContent(current$$1) { + if (!supportsMutation) { + return; + } + resetTextContent(current$$1.stateNode); +} + +var PossiblyWeakSet = typeof WeakSet === "function" ? WeakSet : Set; +var PossiblyWeakMap = typeof WeakMap === "function" ? WeakMap : Map; + +function createRootErrorUpdate(fiber, errorInfo, expirationTime) { + var update = createUpdate(expirationTime); + // Unmount the root by rendering null. + update.tag = CaptureUpdate; + // Caution: React DevTools currently depends on this property + // being called "element". + update.payload = { element: null }; + var error = errorInfo.value; + update.callback = function() { + onUncaughtError(error); + logError(fiber, errorInfo); + }; + return update; +} + +function createClassErrorUpdate(fiber, errorInfo, expirationTime) { + var update = createUpdate(expirationTime); + update.tag = CaptureUpdate; + var getDerivedStateFromError = fiber.type.getDerivedStateFromError; + if (typeof getDerivedStateFromError === "function") { + var error = errorInfo.value; + update.payload = function() { + return getDerivedStateFromError(error); + }; + } + + var inst = fiber.stateNode; + if (inst !== null && typeof inst.componentDidCatch === "function") { + update.callback = function callback() { + if (typeof getDerivedStateFromError !== "function") { + // To preserve the preexisting retry behavior of error boundaries, + // we keep track of which ones already failed during this batch. + // This gets reset before we yield back to the browser. + // TODO: Warn in strict mode if getDerivedStateFromError is + // not defined. + markLegacyErrorBoundaryAsFailed(this); + } + var error = errorInfo.value; + var stack = errorInfo.stack; + logError(fiber, errorInfo); + this.componentDidCatch(error, { + componentStack: stack !== null ? stack : "" + }); + { + if (typeof getDerivedStateFromError !== "function") { + // If componentDidCatch is the only error boundary method defined, + // then it needs to call setState to recover from errors. + // If no state update is scheduled then the boundary will swallow the error. + !(fiber.expirationTime === Sync) + ? warningWithoutStack$1( + false, + "%s: Error boundaries should implement getDerivedStateFromError(). " + + "In that method, return a state update to display an error message or fallback UI.", + getComponentName(fiber.type) || "Unknown" + ) + : void 0; + } + } + }; + } + return update; +} + +function attachPingListener(root, renderExpirationTime, thenable) { + // Attach a listener to the promise to "ping" the root and retry. But + // only if one does not already exist for the current render expiration + // time (which acts like a "thread ID" here). + var pingCache = root.pingCache; + var threadIDs = void 0; + if (pingCache === null) { + pingCache = root.pingCache = new PossiblyWeakMap(); + threadIDs = new Set(); + pingCache.set(thenable, threadIDs); + } else { + threadIDs = pingCache.get(thenable); + if (threadIDs === undefined) { + threadIDs = new Set(); + pingCache.set(thenable, threadIDs); + } + } + if (!threadIDs.has(renderExpirationTime)) { + // Memoize using the thread ID to prevent redundant listeners. + threadIDs.add(renderExpirationTime); + var ping = pingSuspendedRoot.bind( + null, + root, + thenable, + renderExpirationTime + ); + if (enableSchedulerTracing) { + ping = tracing.unstable_wrap(ping); + } + thenable.then(ping, ping); + } +} + +function throwException( + root, + returnFiber, + sourceFiber, + value, + renderExpirationTime +) { + // The source fiber did not complete. + sourceFiber.effectTag |= Incomplete; + // Its effect list is no longer valid. + sourceFiber.firstEffect = sourceFiber.lastEffect = null; + + if ( + value !== null && + typeof value === "object" && + typeof value.then === "function" + ) { + // This is a thenable. + var thenable = value; + + // Schedule the nearest Suspense to re-render the timed out view. + var _workInProgress = returnFiber; + do { + if ( + _workInProgress.tag === SuspenseComponent && + shouldCaptureSuspense(_workInProgress) + ) { + // Found the nearest boundary. + + // Stash the promise on the boundary fiber. If the boundary times out, we'll + var thenables = _workInProgress.updateQueue; + if (thenables === null) { + var updateQueue = new Set(); + updateQueue.add(thenable); + _workInProgress.updateQueue = updateQueue; + } else { + thenables.add(thenable); + } + + // If the boundary is outside of concurrent mode, we should *not* + // suspend the commit. Pretend as if the suspended component rendered + // null and keep rendering. In the commit phase, we'll schedule a + // subsequent synchronous update to re-render the Suspense. + // + // Note: It doesn't matter whether the component that suspended was + // inside a concurrent mode tree. If the Suspense is outside of it, we + // should *not* suspend the commit. + if ((_workInProgress.mode & ConcurrentMode) === NoContext) { + _workInProgress.effectTag |= DidCapture; + + // We're going to commit this fiber even though it didn't complete. + // But we shouldn't call any lifecycle methods or callbacks. Remove + // all lifecycle effect tags. + sourceFiber.effectTag &= ~(LifecycleEffectMask | Incomplete); + + if (sourceFiber.tag === ClassComponent) { + var currentSourceFiber = sourceFiber.alternate; + if (currentSourceFiber === null) { + // This is a new mount. Change the tag so it's not mistaken for a + // completed class component. For example, we should not call + // componentWillUnmount if it is deleted. + sourceFiber.tag = IncompleteClassComponent; + } else { + // When we try rendering again, we should not reuse the current fiber, + // since it's known to be in an inconsistent state. Use a force updte to + // prevent a bail out. + var update = createUpdate(Sync); + update.tag = ForceUpdate; + enqueueUpdate(sourceFiber, update); + } + } + + // The source fiber did not complete. Mark it with Sync priority to + // indicate that it still has pending work. + sourceFiber.expirationTime = Sync; + + // Exit without suspending. + return; + } + + // Confirmed that the boundary is in a concurrent mode tree. Continue + // with the normal suspend path. + + attachPingListener(root, renderExpirationTime, thenable); + + _workInProgress.effectTag |= ShouldCapture; + _workInProgress.expirationTime = renderExpirationTime; + return; + } else if ( + enableSuspenseServerRenderer && + _workInProgress.tag === DehydratedSuspenseComponent + ) { + attachPingListener(root, renderExpirationTime, thenable); + + // Since we already have a current fiber, we can eagerly add a retry listener. + var retryCache = _workInProgress.memoizedState; + if (retryCache === null) { + retryCache = _workInProgress.memoizedState = new PossiblyWeakSet(); + var current$$1 = _workInProgress.alternate; + (function() { + if (!current$$1) { + throw ReactError( + "A dehydrated suspense boundary must commit before trying to render. This is probably a bug in React." + ); + } + })(); + current$$1.memoizedState = retryCache; + } + // Memoize using the boundary fiber to prevent redundant listeners. + if (!retryCache.has(thenable)) { + retryCache.add(thenable); + var retry = resolveRetryThenable.bind( + null, + _workInProgress, + thenable + ); + if (enableSchedulerTracing) { + retry = tracing.unstable_wrap(retry); + } + thenable.then(retry, retry); + } + _workInProgress.effectTag |= ShouldCapture; + _workInProgress.expirationTime = renderExpirationTime; + return; + } + // This boundary already captured during this render. Continue to the next + // boundary. + _workInProgress = _workInProgress.return; + } while (_workInProgress !== null); + // No boundary was found. Fallthrough to error mode. + // TODO: Use invariant so the message is stripped in prod? + value = new Error( + (getComponentName(sourceFiber.type) || "A React component") + + " suspended while rendering, but no fallback UI was specified.\n" + + "\n" + + "Add a component higher in the tree to " + + "provide a loading indicator or placeholder to display." + + getStackByFiberInDevAndProd(sourceFiber) + ); + } + + // We didn't find a boundary that could handle this type of exception. Start + // over and traverse parent path again, this time treating the exception + // as an error. + renderDidError(); + value = createCapturedValue(value, sourceFiber); + var workInProgress = returnFiber; + do { + switch (workInProgress.tag) { + case HostRoot: { + var _errorInfo = value; + workInProgress.effectTag |= ShouldCapture; + workInProgress.expirationTime = renderExpirationTime; + var _update = createRootErrorUpdate( + workInProgress, + _errorInfo, + renderExpirationTime + ); + enqueueCapturedUpdate(workInProgress, _update); + return; + } + case ClassComponent: + // Capture and retry + var errorInfo = value; + var ctor = workInProgress.type; + var instance = workInProgress.stateNode; + if ( + (workInProgress.effectTag & DidCapture) === NoEffect && + (typeof ctor.getDerivedStateFromError === "function" || + (instance !== null && + typeof instance.componentDidCatch === "function" && + !isAlreadyFailedLegacyErrorBoundary(instance))) + ) { + workInProgress.effectTag |= ShouldCapture; + workInProgress.expirationTime = renderExpirationTime; + // Schedule the error boundary to re-render using updated state + var _update2 = createClassErrorUpdate( + workInProgress, + errorInfo, + renderExpirationTime + ); + enqueueCapturedUpdate(workInProgress, _update2); + return; + } + break; + default: + break; + } + workInProgress = workInProgress.return; + } while (workInProgress !== null); +} + +function unwindWork(workInProgress, renderExpirationTime) { + switch (workInProgress.tag) { + case ClassComponent: { + var Component = workInProgress.type; + if (isContextProvider(Component)) { + popContext(workInProgress); + } + var effectTag = workInProgress.effectTag; + if (effectTag & ShouldCapture) { + workInProgress.effectTag = (effectTag & ~ShouldCapture) | DidCapture; + return workInProgress; + } + return null; + } + case HostRoot: { + popHostContainer(workInProgress); + popTopLevelContextObject(workInProgress); + var _effectTag = workInProgress.effectTag; + (function() { + if (!((_effectTag & DidCapture) === NoEffect)) { + throw ReactError( + "The root failed to unmount after an error. This is likely a bug in React. Please file an issue." + ); + } + })(); + workInProgress.effectTag = (_effectTag & ~ShouldCapture) | DidCapture; + return workInProgress; + } + case HostComponent: { + // TODO: popHydrationState + popHostContext(workInProgress); + return null; + } + case SuspenseComponent: { + var _effectTag2 = workInProgress.effectTag; + if (_effectTag2 & ShouldCapture) { + workInProgress.effectTag = (_effectTag2 & ~ShouldCapture) | DidCapture; + // Captured a suspense effect. Re-render the boundary. + return workInProgress; + } + return null; + } + case DehydratedSuspenseComponent: { + if (enableSuspenseServerRenderer) { + // TODO: popHydrationState + var _effectTag3 = workInProgress.effectTag; + if (_effectTag3 & ShouldCapture) { + workInProgress.effectTag = + (_effectTag3 & ~ShouldCapture) | DidCapture; + // Captured a suspense effect. Re-render the boundary. + return workInProgress; + } + } + return null; + } + case HostPortal: + popHostContainer(workInProgress); + return null; + case ContextProvider: + popProvider(workInProgress); + return null; + case EventComponent: + case EventTarget: + if (enableEventAPI) { + popHostContext(workInProgress); + } + return null; + default: + return null; + } +} + +function unwindInterruptedWork(interruptedWork) { + switch (interruptedWork.tag) { + case ClassComponent: { + var childContextTypes = interruptedWork.type.childContextTypes; + if (childContextTypes !== null && childContextTypes !== undefined) { + popContext(interruptedWork); + } + break; + } + case HostRoot: { + popHostContainer(interruptedWork); + popTopLevelContextObject(interruptedWork); + break; + } + case HostComponent: { + popHostContext(interruptedWork); + break; + } + case HostPortal: + popHostContainer(interruptedWork); + break; + case ContextProvider: + popProvider(interruptedWork); + break; + default: + break; + } +} + +// TODO: Ahaha Andrew is bad at spellling +// DEV stuff +var ceil = Math.ceil; + +var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher; +var ReactCurrentOwner$2 = ReactSharedInternals.ReactCurrentOwner; +var ReactShouldWarnActingUpdates = + ReactSharedInternals.ReactShouldWarnActingUpdates; + +var NotWorking = 0; +var BatchedPhase = 1; +var LegacyUnbatchedPhase = 2; +var RenderPhase = 4; +var CommitPhase = 5; + +var RootIncomplete = 0; +var RootErrored = 1; +var RootSuspended = 2; +var RootCompleted = 3; + +// The phase of work we're currently in +var workPhase = NotWorking; +// The root we're working on +var workInProgressRoot = null; +// The fiber we're working on +var workInProgress = null; +// The expiration time we're rendering +var renderExpirationTime = NoWork; +// Whether to root completed, errored, suspended, etc. +var workInProgressRootExitStatus = RootIncomplete; +// Most recent event time among processed updates during this render. +// This is conceptually a time stamp but expressed in terms of an ExpirationTime +// because we deal mostly with expiration times in the hot path, so this avoids +// the conversion happening in the hot path. +var workInProgressRootMostRecentEventTime = Sync; + +var nextEffect = null; +var hasUncaughtError = false; +var firstUncaughtError = null; +var legacyErrorBoundariesThatAlreadyFailed = null; + +var rootDoesHavePassiveEffects = false; +var rootWithPendingPassiveEffects = null; +var pendingPassiveEffectsExpirationTime = NoWork; + +var rootsWithPendingDiscreteUpdates = null; + +// Use these to prevent an infinite loop of nested updates +var NESTED_UPDATE_LIMIT = 50; +var nestedUpdateCount = 0; +var rootWithNestedUpdates = null; + +var NESTED_PASSIVE_UPDATE_LIMIT = 50; +var nestedPassiveUpdateCount = 0; + +var interruptedBy = null; + +// Expiration times are computed by adding to the current time (the start +// time). However, if two updates are scheduled within the same event, we +// should treat their start times as simultaneous, even if the actual clock +// time has advanced between the first and second call. + +// In other words, because expiration times determine how updates are batched, +// we want all updates of like priority that occur within the same event to +// receive the same expiration time. Otherwise we get tearing. +var currentEventTime = NoWork; + +function requestCurrentTime() { + if (workPhase === RenderPhase || workPhase === CommitPhase) { + // We're inside React, so it's fine to read the actual time. + return msToExpirationTime(now()); + } + // We're not inside React, so we may be in the middle of a browser event. + if (currentEventTime !== NoWork) { + // Use the same start time for all updates until we enter React again. + return currentEventTime; + } + // This is the first update since React yielded. Compute a new start time. + currentEventTime = msToExpirationTime(now()); + return currentEventTime; +} + +function computeExpirationForFiber(currentTime, fiber) { + if ((fiber.mode & ConcurrentMode) === NoContext) { + return Sync; + } + + if (workPhase === RenderPhase) { + // Use whatever time we're already rendering + return renderExpirationTime; + } + + // Compute an expiration time based on the Scheduler priority. + var expirationTime = void 0; + var priorityLevel = getCurrentPriorityLevel(); + switch (priorityLevel) { + case ImmediatePriority: + expirationTime = Sync; + break; + case UserBlockingPriority: + // TODO: Rename this to computeUserBlockingExpiration + expirationTime = computeInteractiveExpiration(currentTime); + break; + case NormalPriority: + case LowPriority: + // TODO: Handle LowPriority + // TODO: Rename this to... something better. + expirationTime = computeAsyncExpiration(currentTime); + break; + case IdlePriority: + expirationTime = Never; + break; + default: + (function() { + { + throw ReactError("Expected a valid priority level"); + } + })(); + } + + // If we're in the middle of rendering a tree, do not update at the same + // expiration time that is already rendering. + if (workInProgressRoot !== null && expirationTime === renderExpirationTime) { + // This is a trick to move this update into a separate batch + expirationTime -= 1; + } + + return expirationTime; +} + +function scheduleUpdateOnFiber(fiber, expirationTime) { + checkForNestedUpdates(); + warnAboutInvalidUpdatesOnClassComponentsInDEV(fiber); + + var root = markUpdateTimeFromFiberToRoot(fiber, expirationTime); + if (root === null) { + warnAboutUpdateOnUnmountedFiberInDEV(fiber); + return; + } + + root.pingTime = NoWork; + + checkForInterruption(fiber, expirationTime); + recordScheduleUpdate(); + + if (expirationTime === Sync) { + if (workPhase === LegacyUnbatchedPhase) { + // This is a legacy edge case. The initial mount of a ReactDOM.render-ed + // root inside of batchedUpdates should be synchronous, but layout updates + // should be deferred until the end of the batch. + var callback = renderRoot(root, Sync, true); + while (callback !== null) { + callback = callback(true); + } + } else { + scheduleCallbackForRoot(root, ImmediatePriority, Sync); + if (workPhase === NotWorking) { + // Flush the synchronous work now, wnless we're already working or inside + // a batch. This is intentionally inside scheduleUpdateOnFiber instead of + // scheduleCallbackForFiber to preserve the ability to schedule a callback + // without immediately flushing it. We only do this for user-initated + // updates, to preserve historical behavior of sync mode. + flushImmediateQueue(); + } + } + } else { + // TODO: computeExpirationForFiber also reads the priority. Pass the + // priority as an argument to that function and this one. + var priorityLevel = getCurrentPriorityLevel(); + if (priorityLevel === UserBlockingPriority) { + // This is the result of a discrete event. Track the lowest priority + // discrete update per root so we can flush them early, if needed. + if (rootsWithPendingDiscreteUpdates === null) { + rootsWithPendingDiscreteUpdates = new Map([[root, expirationTime]]); + } else { + var lastDiscreteTime = rootsWithPendingDiscreteUpdates.get(root); + if ( + lastDiscreteTime === undefined || + lastDiscreteTime > expirationTime + ) { + rootsWithPendingDiscreteUpdates.set(root, expirationTime); + } + } + } + scheduleCallbackForRoot(root, priorityLevel, expirationTime); + } +} +var scheduleWork = scheduleUpdateOnFiber; + +// This is split into a separate function so we can mark a fiber with pending +// work without treating it as a typical update that originates from an event; +// e.g. retrying a Suspense boundary isn't an update, but it does schedule work +// on a fiber. +function markUpdateTimeFromFiberToRoot(fiber, expirationTime) { + // Update the source fiber's expiration time + if (fiber.expirationTime < expirationTime) { + fiber.expirationTime = expirationTime; + } + var alternate = fiber.alternate; + if (alternate !== null && alternate.expirationTime < expirationTime) { + alternate.expirationTime = expirationTime; + } + // Walk the parent path to the root and update the child expiration time. + var node = fiber.return; + var root = null; + if (node === null && fiber.tag === HostRoot) { + root = fiber.stateNode; + } else { + while (node !== null) { + alternate = node.alternate; + if (node.childExpirationTime < expirationTime) { + node.childExpirationTime = expirationTime; + if ( + alternate !== null && + alternate.childExpirationTime < expirationTime + ) { + alternate.childExpirationTime = expirationTime; + } + } else if ( + alternate !== null && + alternate.childExpirationTime < expirationTime + ) { + alternate.childExpirationTime = expirationTime; + } + if (node.return === null && node.tag === HostRoot) { + root = node.stateNode; + break; + } + node = node.return; + } + } + + if (root !== null) { + // Update the first and last pending expiration times in this root + var firstPendingTime = root.firstPendingTime; + if (expirationTime > firstPendingTime) { + root.firstPendingTime = expirationTime; + } + var lastPendingTime = root.lastPendingTime; + if (lastPendingTime === NoWork || expirationTime < lastPendingTime) { + root.lastPendingTime = expirationTime; + } + } + + return root; +} + +// Use this function, along with runRootCallback, to ensure that only a single +// callback per root is scheduled. It's still possible to call renderRoot +// directly, but scheduling via this function helps avoid excessive callbacks. +// It works by storing the callback node and expiration time on the root. When a +// new callback comes in, it compares the expiration time to determine if it +// should cancel the previous one. It also relies on commitRoot scheduling a +// callback to render the next level, because that means we don't need a +// separate callback per expiration time. +function scheduleCallbackForRoot(root, priorityLevel, expirationTime) { + var existingCallbackExpirationTime = root.callbackExpirationTime; + if (existingCallbackExpirationTime < expirationTime) { + // New callback has higher priority than the existing one. + var existingCallbackNode = root.callbackNode; + if (existingCallbackNode !== null) { + cancelCallback(existingCallbackNode); + } + root.callbackExpirationTime = expirationTime; + + var options = null; + if (expirationTime !== Sync && expirationTime !== Never) { + var timeout = expirationTimeToMs(expirationTime) - now(); + if (timeout > 5000) { + // Sanity check. Should never take longer than 5 seconds. + // TODO: Add internal warning? + timeout = 5000; + } + options = { timeout: timeout }; + } + + root.callbackNode = scheduleCallback( + priorityLevel, + runRootCallback.bind( + null, + root, + renderRoot.bind(null, root, expirationTime) + ), + options + ); + if ( + enableUserTimingAPI && + expirationTime !== Sync && + workPhase !== RenderPhase && + workPhase !== CommitPhase + ) { + // Scheduled an async callback, and we're not already working. Add an + // entry to the flamegraph that shows we're waiting for a callback + // to fire. + startRequestCallbackTimer(); + } + } + + // Add the current set of interactions to the pending set associated with + // this root. + schedulePendingInteraction(root, expirationTime); +} + +function runRootCallback(root, callback, isSync) { + var prevCallbackNode = root.callbackNode; + var continuation = null; + try { + continuation = callback(isSync); + if (continuation !== null) { + return runRootCallback.bind(null, root, continuation); + } else { + return null; + } + } finally { + // If the callback exits without returning a continuation, remove the + // corresponding callback node from the root. Unless the callback node + // has changed, which implies that it was already cancelled by a high + // priority update. + if (continuation === null && prevCallbackNode === root.callbackNode) { + root.callbackNode = null; + root.callbackExpirationTime = NoWork; + } + } +} + +function flushInteractiveUpdates$1() { + if (workPhase === RenderPhase || workPhase === CommitPhase) { + // Can't synchronously flush interactive updates if React is already + // working. This is currently a no-op. + // TODO: Should we fire a warning? This happens if you synchronously invoke + // an input event inside an effect, like with `element.click()`. + return; + } + flushPendingDiscreteUpdates(); +} + +function resolveLocksOnRoot(root, expirationTime) { + var firstBatch = root.firstBatch; + if ( + firstBatch !== null && + firstBatch._defer && + firstBatch._expirationTime >= expirationTime + ) { + root.finishedWork = root.current.alternate; + root.pendingCommitExpirationTime = expirationTime; + scheduleCallback(NormalPriority, function() { + firstBatch._onComplete(); + return null; + }); + return true; + } else { + return false; + } +} + +function interactiveUpdates$1(fn, a, b, c) { + if (workPhase === NotWorking) { + // TODO: Remove this call. Instead of doing this automatically, the caller + // should explicitly call flushInteractiveUpdates. + flushPendingDiscreteUpdates(); + } + return runWithPriority(UserBlockingPriority, fn.bind(null, a, b, c)); +} + +function flushPendingDiscreteUpdates() { + if (rootsWithPendingDiscreteUpdates !== null) { + // For each root with pending discrete updates, schedule a callback to + // immediately flush them. + var roots = rootsWithPendingDiscreteUpdates; + rootsWithPendingDiscreteUpdates = null; + roots.forEach(function(expirationTime, root) { + scheduleCallback( + ImmediatePriority, + renderRoot.bind(null, root, expirationTime) + ); + }); + // Now flush the immediate queue. + flushImmediateQueue(); + } +} + +function batchedUpdates$1(fn, a) { + if (workPhase !== NotWorking) { + // We're already working, or inside a batch, so batchedUpdates is a no-op. + return fn(a); + } + workPhase = BatchedPhase; + try { + return fn(a); + } finally { + workPhase = NotWorking; + // Flush the immediate callbacks that were scheduled during this batch + flushImmediateQueue(); + } +} + +function prepareFreshStack(root, expirationTime) { + root.pendingCommitExpirationTime = NoWork; + + var timeoutHandle = root.timeoutHandle; + if (timeoutHandle !== noTimeout) { + // The root previous suspended and scheduled a timeout to commit a fallback + // state. Now that we have additional work, cancel the timeout. + root.timeoutHandle = noTimeout; + // $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above + cancelTimeout(timeoutHandle); + } + + if (workInProgress !== null) { + var interruptedWork = workInProgress.return; + while (interruptedWork !== null) { + unwindInterruptedWork(interruptedWork); + interruptedWork = interruptedWork.return; + } + } + workInProgressRoot = root; + workInProgress = createWorkInProgress(root.current, null, expirationTime); + renderExpirationTime = expirationTime; + workInProgressRootExitStatus = RootIncomplete; + workInProgressRootMostRecentEventTime = Sync; + + { + ReactStrictModeWarnings.discardPendingWarnings(); + } +} + +function renderRoot(root, expirationTime, isSync) { + (function() { + if (!(workPhase !== RenderPhase && workPhase !== CommitPhase)) { + throw ReactError("Should not already be working."); + } + })(); + + if (enableUserTimingAPI && expirationTime !== Sync) { + var didExpire = isSync; + stopRequestCallbackTimer(didExpire); + } + + if (root.firstPendingTime < expirationTime) { + // If there's no work left at this expiration time, exit immediately. This + // happens when multiple callbacks are scheduled for a single root, but an + // earlier callback flushes the work of a later one. + return null; + } + + if (root.pendingCommitExpirationTime === expirationTime) { + // There's already a pending commit at this expiration time. + root.pendingCommitExpirationTime = NoWork; + return commitRoot.bind(null, root, expirationTime); + } + + flushPassiveEffects(); + + // If the root or expiration time have changed, throw out the existing stack + // and prepare a fresh one. Otherwise we'll continue where we left off. + if (root !== workInProgressRoot || expirationTime !== renderExpirationTime) { + prepareFreshStack(root, expirationTime); + startWorkOnPendingInteraction(root, expirationTime); + } + + // If we have a work-in-progress fiber, it means there's still work to do + // in this root. + if (workInProgress !== null) { + var prevWorkPhase = workPhase; + workPhase = RenderPhase; + var prevDispatcher = ReactCurrentDispatcher.current; + if (prevDispatcher === null) { + // The React isomorphic package does not include a default dispatcher. + // Instead the first renderer will lazily attach one, in order to give + // nicer error messages. + prevDispatcher = ContextOnlyDispatcher; + } + ReactCurrentDispatcher.current = ContextOnlyDispatcher; + var prevInteractions = null; + if (enableSchedulerTracing) { + prevInteractions = tracing.__interactionsRef.current; + tracing.__interactionsRef.current = root.memoizedInteractions; + } + + startWorkLoopTimer(workInProgress); + + // TODO: Fork renderRoot into renderRootSync and renderRootAsync + if (isSync) { + if (expirationTime !== Sync) { + // An async update expired. There may be other expired updates on + // this root. We should render all the expired work in a + // single batch. + var currentTime = requestCurrentTime(); + if (currentTime < expirationTime) { + // Restart at the current time. + workPhase = prevWorkPhase; + resetContextDependences(); + ReactCurrentDispatcher.current = prevDispatcher; + if (enableSchedulerTracing) { + tracing.__interactionsRef.current = prevInteractions; + } + return renderRoot.bind(null, root, currentTime); + } + } + } else { + // Since we know we're in a React event, we can clear the current + // event time. The next update will compute a new event time. + currentEventTime = NoWork; + } + + do { + try { + if (isSync) { + workLoopSync(); + } else { + workLoop(); + } + break; + } catch (thrownValue) { + // Reset module-level state that was set during the render phase. + resetContextDependences(); + resetHooks(); + + var sourceFiber = workInProgress; + if (sourceFiber === null || sourceFiber.return === null) { + // Expected to be working on a non-root fiber. This is a fatal error + // because there's no ancestor that can handle it; the root is + // supposed to capture all errors that weren't caught by an error + // boundary. + prepareFreshStack(root, expirationTime); + workPhase = prevWorkPhase; + throw thrownValue; + } + + if (enableProfilerTimer && sourceFiber.mode & ProfileMode) { + // Record the time spent rendering before an error was thrown. This + // avoids inaccurate Profiler durations in the case of a + // suspended render. + stopProfilerTimerIfRunningAndRecordDelta(sourceFiber, true); + } + + var returnFiber = sourceFiber.return; + throwException( + root, + returnFiber, + sourceFiber, + thrownValue, + renderExpirationTime + ); + workInProgress = completeUnitOfWork(sourceFiber); + } + } while (true); + + workPhase = prevWorkPhase; + resetContextDependences(); + ReactCurrentDispatcher.current = prevDispatcher; + if (enableSchedulerTracing) { + tracing.__interactionsRef.current = prevInteractions; + } + + if (workInProgress !== null) { + // There's still work left over. Return a continuation. + stopInterruptedWorkLoopTimer(); + if (expirationTime !== Sync) { + startRequestCallbackTimer(); + } + return renderRoot.bind(null, root, expirationTime); + } + } + + // We now have a consistent tree. The next step is either to commit it, or, if + // something suspended, wait to commit it after a timeout. + stopFinishedWorkLoopTimer(); + + var isLocked = resolveLocksOnRoot(root, expirationTime); + if (isLocked) { + // This root has a lock that prevents it from committing. Exit. If we begin + // work on the root again, without any intervening updates, it will finish + // without doing additional work. + return null; + } + + // Set this to null to indicate there's no in-progress render. + workInProgressRoot = null; + + switch (workInProgressRootExitStatus) { + case RootIncomplete: { + (function() { + { + throw ReactError("Should have a work-in-progress."); + } + })(); + } + // Flow knows about invariant, so it compains if I add a break statement, + // but eslint doesn't know about invariant, so it complains if I do. + // eslint-disable-next-line no-fallthrough + case RootErrored: { + // An error was thrown. First check if there is lower priority work + // scheduled on this root. + var lastPendingTime = root.lastPendingTime; + if (root.lastPendingTime < expirationTime) { + // There's lower priority work. Before raising the error, try rendering + // at the lower priority to see if it fixes it. Use a continuation to + // maintain the existing priority and position in the queue. + return renderRoot.bind(null, root, lastPendingTime); + } + if (!isSync) { + // If we're rendering asynchronously, it's possible the error was + // caused by tearing due to a mutation during an event. Try rendering + // one more time without yiedling to events. + prepareFreshStack(root, expirationTime); + scheduleCallback( + ImmediatePriority, + renderRoot.bind(null, root, expirationTime) + ); + return null; + } + // If we're already rendering synchronously, commit the root in its + // errored state. + return commitRoot.bind(null, root, expirationTime); + } + case RootSuspended: { + if (!isSync) { + var _lastPendingTime = root.lastPendingTime; + if (root.lastPendingTime < expirationTime) { + // There's lower priority work. It might be unsuspended. Try rendering + // at that level. + return renderRoot.bind(null, root, _lastPendingTime); + } + // If workInProgressRootMostRecentEventTime is Sync, that means we didn't + // track any event times. That can happen if we retried but nothing switched + // from fallback to content. There's no reason to delay doing no work. + if (workInProgressRootMostRecentEventTime !== Sync) { + var msUntilTimeout = computeMsUntilTimeout( + workInProgressRootMostRecentEventTime, + expirationTime + ); + // Don't bother with a very short suspense time. + if (msUntilTimeout > 10) { + // The render is suspended, it hasn't timed out, and there's no lower + // priority work to do. Instead of committing the fallback + // immediately, wait for more data to arrive. + root.timeoutHandle = scheduleTimeout( + commitRoot.bind(null, root, expirationTime), + msUntilTimeout + ); + return null; + } + } + } + // The work expired. Commit immediately. + return commitRoot.bind(null, root, expirationTime); + } + case RootCompleted: { + // The work completed. Ready to commit. + return commitRoot.bind(null, root, expirationTime); + } + default: { + (function() { + { + throw ReactError("Unknown root exit status."); + } + })(); + } + } +} + +function markRenderEventTime(expirationTime) { + if (expirationTime < workInProgressRootMostRecentEventTime) { + workInProgressRootMostRecentEventTime = expirationTime; + } +} + +function renderDidSuspend() { + if (workInProgressRootExitStatus === RootIncomplete) { + workInProgressRootExitStatus = RootSuspended; + } +} + +function renderDidError() { + if ( + workInProgressRootExitStatus === RootIncomplete || + workInProgressRootExitStatus === RootSuspended + ) { + workInProgressRootExitStatus = RootErrored; + } +} + +function inferTimeFromExpirationTime(expirationTime) { + // We don't know exactly when the update was scheduled, but we can infer an + // approximate start time from the expiration time. + var earliestExpirationTimeMs = expirationTimeToMs(expirationTime); + return earliestExpirationTimeMs - LOW_PRIORITY_EXPIRATION; +} + +function workLoopSync() { + // Already timed out, so perform work without checking if we need to yield. + while (workInProgress !== null) { + workInProgress = performUnitOfWork(workInProgress); + } +} + +function workLoop() { + // Perform work until Scheduler asks us to yield + while (workInProgress !== null && !shouldYield()) { + workInProgress = performUnitOfWork(workInProgress); + } +} + +function performUnitOfWork(unitOfWork) { + // The current, flushed, state of this fiber is the alternate. Ideally + // nothing should rely on this, but relying on it here means that we don't + // need an additional field on the work in progress. + var current$$1 = unitOfWork.alternate; + + startWorkTimer(unitOfWork); + setCurrentFiber(unitOfWork); + + var next = void 0; + if (enableProfilerTimer && (unitOfWork.mode & ProfileMode) !== NoContext) { + startProfilerTimer(unitOfWork); + next = beginWork$$1(current$$1, unitOfWork, renderExpirationTime); + stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true); + } else { + next = beginWork$$1(current$$1, unitOfWork, renderExpirationTime); + } + + resetCurrentFiber(); + unitOfWork.memoizedProps = unitOfWork.pendingProps; + if (next === null) { + // If this doesn't spawn new work, complete the current work. + next = completeUnitOfWork(unitOfWork); + } + + ReactCurrentOwner$2.current = null; + return next; +} + +function completeUnitOfWork(unitOfWork) { + // Attempt to complete the current unit of work, then move to the next + // sibling. If there are no more siblings, return to the parent fiber. + workInProgress = unitOfWork; + do { + // The current, flushed, state of this fiber is the alternate. Ideally + // nothing should rely on this, but relying on it here means that we don't + // need an additional field on the work in progress. + var current$$1 = workInProgress.alternate; + var returnFiber = workInProgress.return; + + // Check if the work completed or if something threw. + if ((workInProgress.effectTag & Incomplete) === NoEffect) { + setCurrentFiber(workInProgress); + var next = void 0; + if ( + !enableProfilerTimer || + (workInProgress.mode & ProfileMode) === NoContext + ) { + next = completeWork(current$$1, workInProgress, renderExpirationTime); + } else { + startProfilerTimer(workInProgress); + next = completeWork(current$$1, workInProgress, renderExpirationTime); + // Update render duration assuming we didn't error. + stopProfilerTimerIfRunningAndRecordDelta(workInProgress, false); + } + stopWorkTimer(workInProgress); + resetCurrentFiber(); + resetChildExpirationTime(workInProgress); + + if (next !== null) { + // Completing this fiber spawned new work. Work on that next. + return next; + } + + if ( + returnFiber !== null && + // Do not append effects to parents if a sibling failed to complete + (returnFiber.effectTag & Incomplete) === NoEffect + ) { + // Append all the effects of the subtree and this fiber onto the effect + // list of the parent. The completion order of the children affects the + // side-effect order. + if (returnFiber.firstEffect === null) { + returnFiber.firstEffect = workInProgress.firstEffect; + } + if (workInProgress.lastEffect !== null) { + if (returnFiber.lastEffect !== null) { + returnFiber.lastEffect.nextEffect = workInProgress.firstEffect; + } + returnFiber.lastEffect = workInProgress.lastEffect; + } + + // If this fiber had side-effects, we append it AFTER the children's + // side-effects. We can perform certain side-effects earlier if needed, + // by doing multiple passes over the effect list. We don't want to + // schedule our own side-effect on our own list because if end up + // reusing children we'll schedule this effect onto itself since we're + // at the end. + var effectTag = workInProgress.effectTag; + + // Skip both NoWork and PerformedWork tags when creating the effect + // list. PerformedWork effect is read by React DevTools but shouldn't be + // committed. + if (effectTag > PerformedWork) { + if (returnFiber.lastEffect !== null) { + returnFiber.lastEffect.nextEffect = workInProgress; + } else { + returnFiber.firstEffect = workInProgress; + } + returnFiber.lastEffect = workInProgress; + } + } + } else { + // This fiber did not complete because something threw. Pop values off + // the stack without entering the complete phase. If this is a boundary, + // capture values if possible. + var _next = unwindWork(workInProgress, renderExpirationTime); + + // Because this fiber did not complete, don't reset its expiration time. + + if ( + enableProfilerTimer && + (workInProgress.mode & ProfileMode) !== NoContext + ) { + // Record the render duration for the fiber that errored. + stopProfilerTimerIfRunningAndRecordDelta(workInProgress, false); + + // Include the time spent working on failed children before continuing. + var actualDuration = workInProgress.actualDuration; + var child = workInProgress.child; + while (child !== null) { + actualDuration += child.actualDuration; + child = child.sibling; + } + workInProgress.actualDuration = actualDuration; + } + + if (_next !== null) { + // If completing this work spawned new work, do that next. We'll come + // back here again. + // Since we're restarting, remove anything that is not a host effect + // from the effect tag. + // TODO: The name stopFailedWorkTimer is misleading because Suspense + // also captures and restarts. + stopFailedWorkTimer(workInProgress); + _next.effectTag &= HostEffectMask; + return _next; + } + stopWorkTimer(workInProgress); + + if (returnFiber !== null) { + // Mark the parent fiber as incomplete and clear its effect list. + returnFiber.firstEffect = returnFiber.lastEffect = null; + returnFiber.effectTag |= Incomplete; + } + } + + var siblingFiber = workInProgress.sibling; + if (siblingFiber !== null) { + // If there is more work to do in this returnFiber, do that next. + return siblingFiber; + } + // Otherwise, return to the parent + workInProgress = returnFiber; + } while (workInProgress !== null); + + // We've reached the root. + if (workInProgressRootExitStatus === RootIncomplete) { + workInProgressRootExitStatus = RootCompleted; + } + return null; +} + +function resetChildExpirationTime(completedWork) { + if ( + renderExpirationTime !== Never && + completedWork.childExpirationTime === Never + ) { + // The children of this component are hidden. Don't bubble their + // expiration times. + return; + } + + var newChildExpirationTime = NoWork; + + // Bubble up the earliest expiration time. + if (enableProfilerTimer && (completedWork.mode & ProfileMode) !== NoContext) { + // In profiling mode, resetChildExpirationTime is also used to reset + // profiler durations. + var actualDuration = completedWork.actualDuration; + var treeBaseDuration = completedWork.selfBaseDuration; + + // When a fiber is cloned, its actualDuration is reset to 0. This value will + // only be updated if work is done on the fiber (i.e. it doesn't bailout). + // When work is done, it should bubble to the parent's actualDuration. If + // the fiber has not been cloned though, (meaning no work was done), then + // this value will reflect the amount of time spent working on a previous + // render. In that case it should not bubble. We determine whether it was + // cloned by comparing the child pointer. + var shouldBubbleActualDurations = + completedWork.alternate === null || + completedWork.child !== completedWork.alternate.child; + + var child = completedWork.child; + while (child !== null) { + var childUpdateExpirationTime = child.expirationTime; + var childChildExpirationTime = child.childExpirationTime; + if (childUpdateExpirationTime > newChildExpirationTime) { + newChildExpirationTime = childUpdateExpirationTime; + } + if (childChildExpirationTime > newChildExpirationTime) { + newChildExpirationTime = childChildExpirationTime; + } + if (shouldBubbleActualDurations) { + actualDuration += child.actualDuration; + } + treeBaseDuration += child.treeBaseDuration; + child = child.sibling; + } + completedWork.actualDuration = actualDuration; + completedWork.treeBaseDuration = treeBaseDuration; + } else { + var _child = completedWork.child; + while (_child !== null) { + var _childUpdateExpirationTime = _child.expirationTime; + var _childChildExpirationTime = _child.childExpirationTime; + if (_childUpdateExpirationTime > newChildExpirationTime) { + newChildExpirationTime = _childUpdateExpirationTime; + } + if (_childChildExpirationTime > newChildExpirationTime) { + newChildExpirationTime = _childChildExpirationTime; + } + _child = _child.sibling; + } + } + + completedWork.childExpirationTime = newChildExpirationTime; +} + +function commitRoot(root, expirationTime) { + runWithPriority( + ImmediatePriority, + commitRootImpl.bind(null, root, expirationTime) + ); + // If there are passive effects, schedule a callback to flush them. This goes + // outside commitRootImpl so that it inherits the priority of the render. + if (rootWithPendingPassiveEffects !== null) { + var priorityLevel = getCurrentPriorityLevel(); + scheduleCallback(priorityLevel, function() { + flushPassiveEffects(); + return null; + }); + } + return null; +} + +function commitRootImpl(root, expirationTime) { + flushPassiveEffects(); + flushRenderPhaseStrictModeWarningsInDEV(); + + (function() { + if (!(workPhase !== RenderPhase && workPhase !== CommitPhase)) { + throw ReactError("Should not already be working."); + } + })(); + var finishedWork = root.current.alternate; + (function() { + if (!(finishedWork !== null)) { + throw ReactError("Should have a work-in-progress root."); + } + })(); + + // commitRoot never returns a continuation; it always finishes synchronously. + // So we can clear these now to allow a new callback to be scheduled. + root.callbackNode = null; + root.callbackExpirationTime = NoWork; + + startCommitTimer(); + + // Update the first and last pending times on this root. The new first + // pending time is whatever is left on the root fiber. + var updateExpirationTimeBeforeCommit = finishedWork.expirationTime; + var childExpirationTimeBeforeCommit = finishedWork.childExpirationTime; + var firstPendingTimeBeforeCommit = + childExpirationTimeBeforeCommit > updateExpirationTimeBeforeCommit + ? childExpirationTimeBeforeCommit + : updateExpirationTimeBeforeCommit; + root.firstPendingTime = firstPendingTimeBeforeCommit; + if (firstPendingTimeBeforeCommit < root.lastPendingTime) { + // This usually means we've finished all the work, but it can also happen + // when something gets downprioritized during render, like a hidden tree. + root.lastPendingTime = firstPendingTimeBeforeCommit; + } + + if (root === workInProgressRoot) { + // We can reset these now that they are finished. + workInProgressRoot = null; + workInProgress = null; + renderExpirationTime = NoWork; + } else { + } + // This indicates that the last root we worked on is not the same one that + // we're committing now. This most commonly happens when a suspended root + // times out. + + // Get the list of effects. + var firstEffect = void 0; + if (finishedWork.effectTag > PerformedWork) { + // A fiber's effect list consists only of its children, not itself. So if + // the root has an effect, we need to add it to the end of the list. The + // resulting list is the set that would belong to the root's parent, if it + // had one; that is, all the effects in the tree including the root. + if (finishedWork.lastEffect !== null) { + finishedWork.lastEffect.nextEffect = finishedWork; + firstEffect = finishedWork.firstEffect; + } else { + firstEffect = finishedWork; + } + } else { + // There is no effect on the root. + firstEffect = finishedWork.firstEffect; + } + + if (firstEffect !== null) { + var prevWorkPhase = workPhase; + workPhase = CommitPhase; + var prevInteractions = null; + if (enableSchedulerTracing) { + prevInteractions = tracing.__interactionsRef.current; + tracing.__interactionsRef.current = root.memoizedInteractions; + } + + // Reset this to null before calling lifecycles + ReactCurrentOwner$2.current = null; + + // The commit phase is broken into several sub-phases. We do a separate pass + // of the effect list for each phase: all mutation effects come before all + // layout effects, and so on. + + // The first phase a "before mutation" phase. We use this phase to read the + // state of the host tree right before we mutate it. This is where + // getSnapshotBeforeUpdate is called. + startCommitSnapshotEffectsTimer(); + prepareForCommit(root.containerInfo); + nextEffect = firstEffect; + do { + { + invokeGuardedCallback(null, commitBeforeMutationEffects, null); + if (hasCaughtError()) { + (function() { + if (!(nextEffect !== null)) { + throw ReactError("Should be working on an effect."); + } + })(); + var error = clearCaughtError(); + captureCommitPhaseError(nextEffect, error); + nextEffect = nextEffect.nextEffect; + } + } + } while (nextEffect !== null); + stopCommitSnapshotEffectsTimer(); + + if (enableProfilerTimer) { + // Mark the current commit time to be shared by all Profilers in this + // batch. This enables them to be grouped later. + recordCommitTime(); + } + + // The next phase is the mutation phase, where we mutate the host tree. + startCommitHostEffectsTimer(); + nextEffect = firstEffect; + do { + { + invokeGuardedCallback(null, commitMutationEffects, null); + if (hasCaughtError()) { + (function() { + if (!(nextEffect !== null)) { + throw ReactError("Should be working on an effect."); + } + })(); + var _error = clearCaughtError(); + captureCommitPhaseError(nextEffect, _error); + nextEffect = nextEffect.nextEffect; + } + } + } while (nextEffect !== null); + stopCommitHostEffectsTimer(); + resetAfterCommit(root.containerInfo); + + // The work-in-progress tree is now the current tree. This must come after + // the mutation phase, so that the previous tree is still current during + // componentWillUnmount, but before the layout phase, so that the finished + // work is current during componentDidMount/Update. + root.current = finishedWork; + + // The next phase is the layout phase, where we call effects that read + // the host tree after it's been mutated. The idiomatic use case for this is + // layout, but class component lifecycles also fire here for legacy reasons. + startCommitLifeCyclesTimer(); + nextEffect = firstEffect; + do { + { + invokeGuardedCallback( + null, + commitLayoutEffects, + null, + root, + expirationTime + ); + if (hasCaughtError()) { + (function() { + if (!(nextEffect !== null)) { + throw ReactError("Should be working on an effect."); + } + })(); + var _error2 = clearCaughtError(); + captureCommitPhaseError(nextEffect, _error2); + nextEffect = nextEffect.nextEffect; + } + } + } while (nextEffect !== null); + stopCommitLifeCyclesTimer(); + + nextEffect = null; + + if (enableSchedulerTracing) { + tracing.__interactionsRef.current = prevInteractions; + } + workPhase = prevWorkPhase; + } else { + // No effects. + root.current = finishedWork; + // Measure these anyway so the flamegraph explicitly shows that there were + // no effects. + // TODO: Maybe there's a better way to report this. + startCommitSnapshotEffectsTimer(); + stopCommitSnapshotEffectsTimer(); + if (enableProfilerTimer) { + recordCommitTime(); + } + startCommitHostEffectsTimer(); + stopCommitHostEffectsTimer(); + startCommitLifeCyclesTimer(); + stopCommitLifeCyclesTimer(); + } + + stopCommitTimer(); + + if (rootDoesHavePassiveEffects) { + // This commit has passive effects. Stash a reference to them. But don't + // schedule a callback until after flushing layout work. + rootDoesHavePassiveEffects = false; + rootWithPendingPassiveEffects = root; + pendingPassiveEffectsExpirationTime = expirationTime; + } else { + if (enableSchedulerTracing) { + // If there are no passive effects, then we can complete the pending + // interactions. Otherwise, we'll wait until after the passive effects + // are flushed. + finishPendingInteractions(root, expirationTime); + } + } + + // Check if there's remaining work on this root + var remainingExpirationTime = root.firstPendingTime; + if (remainingExpirationTime !== NoWork) { + var currentTime = requestCurrentTime(); + var priorityLevel = inferPriorityFromExpirationTime( + currentTime, + remainingExpirationTime + ); + scheduleCallbackForRoot(root, priorityLevel, remainingExpirationTime); + } else { + // If there's no remaining work, we can clear the set of already failed + // error boundaries. + legacyErrorBoundariesThatAlreadyFailed = null; + } + + onCommitRoot(finishedWork.stateNode); + + if (remainingExpirationTime === Sync) { + // Count the number of times the root synchronously re-renders without + // finishing. If there are too many, it indicates an infinite update loop. + if (root === rootWithNestedUpdates) { + nestedUpdateCount++; + } else { + nestedUpdateCount = 0; + rootWithNestedUpdates = root; + } + } else { + nestedUpdateCount = 0; + } + + if (hasUncaughtError) { + hasUncaughtError = false; + var _error3 = firstUncaughtError; + firstUncaughtError = null; + throw _error3; + } + + if (workPhase === LegacyUnbatchedPhase) { + // This is a legacy edge case. We just committed the initial mount of + // a ReactDOM.render-ed root inside of batchedUpdates. The commit fired + // synchronously, but layout updates should be deferred until the end + // of the batch. + return null; + } + + // If layout work was scheduled, flush it now. + flushImmediateQueue(); + return null; +} + +function commitBeforeMutationEffects() { + while (nextEffect !== null) { + if ((nextEffect.effectTag & Snapshot) !== NoEffect) { + setCurrentFiber(nextEffect); + recordEffect(); + + var current$$1 = nextEffect.alternate; + commitBeforeMutationLifeCycles(current$$1, nextEffect); + + resetCurrentFiber(); + } + nextEffect = nextEffect.nextEffect; + } +} + +function commitMutationEffects() { + // TODO: Should probably move the bulk of this function to commitWork. + while (nextEffect !== null) { + setCurrentFiber(nextEffect); + + var effectTag = nextEffect.effectTag; + + if (effectTag & ContentReset) { + commitResetTextContent(nextEffect); + } + + if (effectTag & Ref) { + var current$$1 = nextEffect.alternate; + if (current$$1 !== null) { + commitDetachRef(current$$1); + } + } + + // The following switch statement is only concerned about placement, + // updates, and deletions. To avoid needing to add a case for every possible + // bitmap value, we remove the secondary effects from the effect tag and + // switch on that value. + var primaryEffectTag = effectTag & (Placement | Update | Deletion); + switch (primaryEffectTag) { + case Placement: { + commitPlacement(nextEffect); + // Clear the "placement" from effect tag so that we know that this is + // inserted, before any life-cycles like componentDidMount gets called. + // TODO: findDOMNode doesn't rely on this any more but isMounted does + // and isMounted is deprecated anyway so we should be able to kill this. + nextEffect.effectTag &= ~Placement; + break; + } + case PlacementAndUpdate: { + // Placement + commitPlacement(nextEffect); + // Clear the "placement" from effect tag so that we know that this is + // inserted, before any life-cycles like componentDidMount gets called. + nextEffect.effectTag &= ~Placement; + + // Update + var _current = nextEffect.alternate; + commitWork(_current, nextEffect); + break; + } + case Update: { + var _current2 = nextEffect.alternate; + commitWork(_current2, nextEffect); + break; + } + case Deletion: { + commitDeletion(nextEffect); + break; + } + } + + // TODO: Only record a mutation effect if primaryEffectTag is non-zero. + recordEffect(); + + resetCurrentFiber(); + nextEffect = nextEffect.nextEffect; + } +} + +function commitLayoutEffects(root, committedExpirationTime) { + // TODO: Should probably move the bulk of this function to commitWork. + while (nextEffect !== null) { + setCurrentFiber(nextEffect); + + var effectTag = nextEffect.effectTag; + + if (effectTag & (Update | Callback)) { + recordEffect(); + var current$$1 = nextEffect.alternate; + commitLifeCycles(root, current$$1, nextEffect, committedExpirationTime); + } + + if (effectTag & Ref) { + recordEffect(); + commitAttachRef(nextEffect); + } + + if (effectTag & Passive) { + rootDoesHavePassiveEffects = true; + } + + resetCurrentFiber(); + nextEffect = nextEffect.nextEffect; + } +} + +function flushPassiveEffects() { + if (rootWithPendingPassiveEffects === null) { + return false; + } + var root = rootWithPendingPassiveEffects; + var expirationTime = pendingPassiveEffectsExpirationTime; + rootWithPendingPassiveEffects = null; + pendingPassiveEffectsExpirationTime = NoWork; + + var prevInteractions = null; + if (enableSchedulerTracing) { + prevInteractions = tracing.__interactionsRef.current; + tracing.__interactionsRef.current = root.memoizedInteractions; + } + + (function() { + if (!(workPhase !== RenderPhase && workPhase !== CommitPhase)) { + throw ReactError("Cannot flush passive effects while already rendering."); + } + })(); + var prevWorkPhase = workPhase; + workPhase = CommitPhase; + + // Note: This currently assumes there are no passive effects on the root + // fiber, because the root is not part of its own effect list. This could + // change in the future. + var effect = root.current.firstEffect; + while (effect !== null) { + { + setCurrentFiber(effect); + invokeGuardedCallback(null, commitPassiveHookEffects, null, effect); + if (hasCaughtError()) { + (function() { + if (!(effect !== null)) { + throw ReactError("Should be working on an effect."); + } + })(); + var error = clearCaughtError(); + captureCommitPhaseError(effect, error); + } + resetCurrentFiber(); + } + effect = effect.nextEffect; + } + + if (enableSchedulerTracing) { + tracing.__interactionsRef.current = prevInteractions; + finishPendingInteractions(root, expirationTime); + } + + workPhase = prevWorkPhase; + flushImmediateQueue(); + + // If additional passive effects were scheduled, increment a counter. If this + // exceeds the limit, we'll fire a warning. + nestedPassiveUpdateCount = + rootWithPendingPassiveEffects === null ? 0 : nestedPassiveUpdateCount + 1; + + return true; +} + +function isAlreadyFailedLegacyErrorBoundary(instance) { + return ( + legacyErrorBoundariesThatAlreadyFailed !== null && + legacyErrorBoundariesThatAlreadyFailed.has(instance) + ); +} + +function markLegacyErrorBoundaryAsFailed(instance) { + if (legacyErrorBoundariesThatAlreadyFailed === null) { + legacyErrorBoundariesThatAlreadyFailed = new Set([instance]); + } else { + legacyErrorBoundariesThatAlreadyFailed.add(instance); + } +} + +function prepareToThrowUncaughtError(error) { + if (!hasUncaughtError) { + hasUncaughtError = true; + firstUncaughtError = error; + } +} +var onUncaughtError = prepareToThrowUncaughtError; + +function captureCommitPhaseErrorOnRoot(rootFiber, sourceFiber, error) { + var errorInfo = createCapturedValue(error, sourceFiber); + var update = createRootErrorUpdate(rootFiber, errorInfo, Sync); + enqueueUpdate(rootFiber, update); + var root = markUpdateTimeFromFiberToRoot(rootFiber, Sync); + if (root !== null) { + scheduleCallbackForRoot(root, ImmediatePriority, Sync); + } +} + +function captureCommitPhaseError(sourceFiber, error) { + if (sourceFiber.tag === HostRoot) { + // Error was thrown at the root. There is no parent, so the root + // itself should capture it. + captureCommitPhaseErrorOnRoot(sourceFiber, sourceFiber, error); + return; + } + + var fiber = sourceFiber.return; + while (fiber !== null) { + if (fiber.tag === HostRoot) { + captureCommitPhaseErrorOnRoot(fiber, sourceFiber, error); + return; + } else if (fiber.tag === ClassComponent) { + var ctor = fiber.type; + var instance = fiber.stateNode; + if ( + typeof ctor.getDerivedStateFromError === "function" || + (typeof instance.componentDidCatch === "function" && + !isAlreadyFailedLegacyErrorBoundary(instance)) + ) { + var errorInfo = createCapturedValue(error, sourceFiber); + var update = createClassErrorUpdate( + fiber, + errorInfo, + // TODO: This is always sync + Sync + ); + enqueueUpdate(fiber, update); + var root = markUpdateTimeFromFiberToRoot(fiber, Sync); + if (root !== null) { + scheduleCallbackForRoot(root, ImmediatePriority, Sync); + } + return; + } + } + fiber = fiber.return; + } +} + +function pingSuspendedRoot(root, thenable, suspendedTime) { + var pingCache = root.pingCache; + if (pingCache !== null) { + // The thenable resolved, so we no longer need to memoize, because it will + // never be thrown again. + pingCache.delete(thenable); + } + + if (workInProgressRoot === root && renderExpirationTime === suspendedTime) { + // Received a ping at the same priority level at which we're currently + // rendering. Restart from the root. Don't need to schedule a ping because + // we're already working on this tree. + prepareFreshStack(root, renderExpirationTime); + return; + } + + var lastPendingTime = root.lastPendingTime; + if (lastPendingTime < suspendedTime) { + // The root is no longer suspended at this time. + return; + } + + var pingTime = root.pingTime; + if (pingTime !== NoWork && pingTime < suspendedTime) { + // There's already a lower priority ping scheduled. + return; + } + + // Mark the time at which this ping was scheduled. + root.pingTime = suspendedTime; + + var currentTime = requestCurrentTime(); + var priorityLevel = inferPriorityFromExpirationTime( + currentTime, + suspendedTime + ); + scheduleCallbackForRoot(root, priorityLevel, suspendedTime); +} + +function retryTimedOutBoundary(boundaryFiber) { + // The boundary fiber (a Suspense component) previously timed out and was + // rendered in its fallback state. One of the promises that suspended it has + // resolved, which means at least part of the tree was likely unblocked. Try + // rendering again, at a new expiration time. + var currentTime = requestCurrentTime(); + var retryTime = computeExpirationForFiber(currentTime, boundaryFiber); + // TODO: Special case idle priority? + var priorityLevel = inferPriorityFromExpirationTime(currentTime, retryTime); + var root = markUpdateTimeFromFiberToRoot(boundaryFiber, retryTime); + if (root !== null) { + scheduleCallbackForRoot(root, priorityLevel, retryTime); + } +} + +function resolveRetryThenable(boundaryFiber, thenable) { + var retryCache = void 0; + if (enableSuspenseServerRenderer) { + switch (boundaryFiber.tag) { + case SuspenseComponent: + retryCache = boundaryFiber.stateNode; + break; + case DehydratedSuspenseComponent: + retryCache = boundaryFiber.memoizedState; + break; + default: + (function() { + { + throw ReactError( + "Pinged unknown suspense boundary type. This is probably a bug in React." + ); + } + })(); + } + } else { + retryCache = boundaryFiber.stateNode; + } + + if (retryCache !== null) { + // The thenable resolved, so we no longer need to memoize, because it will + // never be thrown again. + retryCache.delete(thenable); + } + + retryTimedOutBoundary(boundaryFiber); +} + +// Computes the next Just Noticeable Difference (JND) boundary. +// The theory is that a person can't tell the difference between small differences in time. +// Therefore, if we wait a bit longer than necessary that won't translate to a noticeable +// difference in the experience. However, waiting for longer might mean that we can avoid +// showing an intermediate loading state. The longer we have already waited, the harder it +// is to tell small differences in time. Therefore, the longer we've already waited, +// the longer we can wait additionally. At some point we have to give up though. +// We pick a train model where the next boundary commits at a consistent schedule. +// These particular numbers are vague estimates. We expect to adjust them based on research. +function jnd(timeElapsed) { + return timeElapsed < 120 + ? 120 + : timeElapsed < 480 + ? 480 + : timeElapsed < 1080 + ? 1080 + : timeElapsed < 1920 + ? 1920 + : timeElapsed < 3000 + ? 3000 + : timeElapsed < 4320 + ? 4320 + : ceil(timeElapsed / 1960) * 1960; +} + +function computeMsUntilTimeout(mostRecentEventTime, committedExpirationTime) { + if (disableYielding) { + // Timeout immediately when yielding is disabled. + return 0; + } + + var eventTimeMs = inferTimeFromExpirationTime(mostRecentEventTime); + var currentTimeMs = now(); + var timeElapsed = currentTimeMs - eventTimeMs; + + var msUntilTimeout = jnd(timeElapsed) - timeElapsed; + + // Compute the time until this render pass would expire. + var timeUntilExpirationMs = + expirationTimeToMs(committedExpirationTime) - currentTimeMs; + + // Clamp the timeout to the expiration time. + // TODO: Once the event time is exact instead of inferred from expiration time + // we don't need this. + if (timeUntilExpirationMs < msUntilTimeout) { + msUntilTimeout = timeUntilExpirationMs; + } + + // This is the value that is passed to `setTimeout`. + return msUntilTimeout; +} + +function checkForNestedUpdates() { + if (nestedUpdateCount > NESTED_UPDATE_LIMIT) { + nestedUpdateCount = 0; + rootWithNestedUpdates = null; + (function() { + { + throw ReactError( + "Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops." + ); + } + })(); + } + + { + if (nestedPassiveUpdateCount > NESTED_PASSIVE_UPDATE_LIMIT) { + nestedPassiveUpdateCount = 0; + warning$1( + false, + "Maximum update depth exceeded. This can happen when a component " + + "calls setState inside useEffect, but useEffect either doesn't " + + "have a dependency array, or one of the dependencies changes on " + + "every render." + ); + } + } +} + +function flushRenderPhaseStrictModeWarningsInDEV() { + { + ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings(); + ReactStrictModeWarnings.flushLegacyContextWarning(); + + if (warnAboutDeprecatedLifecycles) { + ReactStrictModeWarnings.flushPendingDeprecationWarnings(); + } + } +} + +function stopFinishedWorkLoopTimer() { + var didCompleteRoot = true; + stopWorkLoopTimer(interruptedBy, didCompleteRoot); + interruptedBy = null; +} + +function stopInterruptedWorkLoopTimer() { + // TODO: Track which fiber caused the interruption. + var didCompleteRoot = false; + stopWorkLoopTimer(interruptedBy, didCompleteRoot); + interruptedBy = null; +} + +function checkForInterruption(fiberThatReceivedUpdate, updateExpirationTime) { + if ( + enableUserTimingAPI && + workInProgressRoot !== null && + updateExpirationTime > renderExpirationTime + ) { + interruptedBy = fiberThatReceivedUpdate; + } +} + +var didWarnStateUpdateForUnmountedComponent = null; +function warnAboutUpdateOnUnmountedFiberInDEV(fiber) { + { + var tag = fiber.tag; + if ( + tag !== HostRoot && + tag !== ClassComponent && + tag !== FunctionComponent && + tag !== ForwardRef && + tag !== MemoComponent && + tag !== SimpleMemoComponent + ) { + // Only warn for user-defined components, not internal ones like Suspense. + return; + } + // We show the whole stack but dedupe on the top component's name because + // the problematic code almost always lies inside that component. + var componentName = getComponentName(fiber.type) || "ReactComponent"; + if (didWarnStateUpdateForUnmountedComponent !== null) { + if (didWarnStateUpdateForUnmountedComponent.has(componentName)) { + return; + } + didWarnStateUpdateForUnmountedComponent.add(componentName); + } else { + didWarnStateUpdateForUnmountedComponent = new Set([componentName]); + } + warningWithoutStack$1( + false, + "Can't perform a React state update on an unmounted component. This " + + "is a no-op, but it indicates a memory leak in your application. To " + + "fix, cancel all subscriptions and asynchronous tasks in %s.%s", + tag === ClassComponent + ? "the componentWillUnmount method" + : "a useEffect cleanup function", + getStackByFiberInDevAndProd(fiber) + ); + } +} + +var beginWork$$1 = void 0; +if (true && replayFailedUnitOfWorkWithInvokeGuardedCallback) { + var dummyFiber = null; + beginWork$$1 = function(current$$1, unitOfWork, expirationTime) { + // If a component throws an error, we replay it again in a synchronously + // dispatched event, so that the debugger will treat it as an uncaught + // error See ReactErrorUtils for more information. + + // Before entering the begin phase, copy the work-in-progress onto a dummy + // fiber. If beginWork throws, we'll use this to reset the state. + var originalWorkInProgressCopy = assignFiberPropertiesInDEV( + dummyFiber, + unitOfWork + ); + try { + return beginWork$1(current$$1, unitOfWork, expirationTime); + } catch (originalError) { + if ( + originalError !== null && + typeof originalError === "object" && + typeof originalError.then === "function" + ) { + // Don't replay promises. Treat everything else like an error. + throw originalError; + } + + // Keep this code in sync with renderRoot; any changes here must have + // corresponding changes there. + resetContextDependences(); + resetHooks(); + + // Unwind the failed stack frame + unwindInterruptedWork(unitOfWork); + + // Restore the original properties of the fiber. + assignFiberPropertiesInDEV(unitOfWork, originalWorkInProgressCopy); + + if (enableProfilerTimer && unitOfWork.mode & ProfileMode) { + // Reset the profiler timer. + startProfilerTimer(unitOfWork); + } + + // Run beginWork again. + invokeGuardedCallback( + null, + beginWork$1, + null, + current$$1, + unitOfWork, + expirationTime + ); + + if (hasCaughtError()) { + var replayError = clearCaughtError(); + // `invokeGuardedCallback` sometimes sets an expando `_suppressLogging`. + // Rethrow this error instead of the original one. + throw replayError; + } else { + // This branch is reachable if the render phase is impure. + throw originalError; + } + } + }; +} else { + beginWork$$1 = beginWork$1; +} + +var didWarnAboutUpdateInRender = false; +var didWarnAboutUpdateInGetChildContext = false; +function warnAboutInvalidUpdatesOnClassComponentsInDEV(fiber) { + { + if (fiber.tag === ClassComponent) { + switch (phase) { + case "getChildContext": + if (didWarnAboutUpdateInGetChildContext) { + return; + } + warningWithoutStack$1( + false, + "setState(...): Cannot call setState() inside getChildContext()" + ); + didWarnAboutUpdateInGetChildContext = true; + break; + case "render": + if (didWarnAboutUpdateInRender) { + return; + } + warningWithoutStack$1( + false, + "Cannot update during an existing state transition (such as " + + "within `render`). Render methods should be a pure function of " + + "props and state." + ); + didWarnAboutUpdateInRender = true; + break; + } + } + } +} + +function warnIfNotCurrentlyActingUpdatesInDEV(fiber) { + { + if ( + workPhase === NotWorking && + ReactShouldWarnActingUpdates.current === false + ) { + warningWithoutStack$1( + false, + "An update to %s inside a test was not wrapped in act(...).\n\n" + + "When testing, code that causes React state updates should be " + + "wrapped into act(...):\n\n" + + "act(() => {\n" + + " /* fire events that update state */\n" + + "});\n" + + "/* assert on the output */\n\n" + + "This ensures that you're testing the behavior the user would see " + + "in the browser." + + " Learn more at https://fb.me/react-wrap-tests-with-act" + + "%s", + getComponentName(fiber.type), + getStackByFiberInDevAndProd(fiber) + ); + } + } +} + +var warnIfNotCurrentlyActingUpdatesInDev = warnIfNotCurrentlyActingUpdatesInDEV; + +function computeThreadID(root, expirationTime) { + // Interaction threads are unique per root and expiration time. + return expirationTime * 1000 + root.interactionThreadID; +} + +function schedulePendingInteraction(root, expirationTime) { + // This is called when work is scheduled on a root. It sets up a pending + // interaction, which is completed once the work commits. + if (!enableSchedulerTracing) { + return; + } + + var interactions = tracing.__interactionsRef.current; + if (interactions.size > 0) { + var pendingInteractionMap = root.pendingInteractionMap; + var pendingInteractions = pendingInteractionMap.get(expirationTime); + if (pendingInteractions != null) { + interactions.forEach(function(interaction) { + if (!pendingInteractions.has(interaction)) { + // Update the pending async work count for previously unscheduled interaction. + interaction.__count++; + } + + pendingInteractions.add(interaction); + }); + } else { + pendingInteractionMap.set(expirationTime, new Set(interactions)); + + // Update the pending async work count for the current interactions. + interactions.forEach(function(interaction) { + interaction.__count++; + }); + } + + var subscriber = tracing.__subscriberRef.current; + if (subscriber !== null) { + var threadID = computeThreadID(root, expirationTime); + subscriber.onWorkScheduled(interactions, threadID); + } + } +} + +function startWorkOnPendingInteraction(root, expirationTime) { + // This is called when new work is started on a root. + if (!enableSchedulerTracing) { + return; + } + + // Determine which interactions this batch of work currently includes, So that + // we can accurately attribute time spent working on it, And so that cascading + // work triggered during the render phase will be associated with it. + var interactions = new Set(); + root.pendingInteractionMap.forEach(function( + scheduledInteractions, + scheduledExpirationTime + ) { + if (scheduledExpirationTime >= expirationTime) { + scheduledInteractions.forEach(function(interaction) { + return interactions.add(interaction); + }); + } + }); + + // Store the current set of interactions on the FiberRoot for a few reasons: + // We can re-use it in hot functions like renderRoot() without having to + // recalculate it. We will also use it in commitWork() to pass to any Profiler + // onRender() hooks. This also provides DevTools with a way to access it when + // the onCommitRoot() hook is called. + root.memoizedInteractions = interactions; + + if (interactions.size > 0) { + var subscriber = tracing.__subscriberRef.current; + if (subscriber !== null) { + var threadID = computeThreadID(root, expirationTime); + try { + subscriber.onWorkStarted(interactions, threadID); + } catch (error) { + // If the subscriber throws, rethrow it in a separate task + scheduleCallback(ImmediatePriority, function() { + throw error; + }); + } + } + } +} + +function finishPendingInteractions(root, committedExpirationTime) { + if (!enableSchedulerTracing) { + return; + } + + var earliestRemainingTimeAfterCommit = root.firstPendingTime; + + var subscriber = void 0; + + try { + subscriber = tracing.__subscriberRef.current; + if (subscriber !== null && root.memoizedInteractions.size > 0) { + var threadID = computeThreadID(root, committedExpirationTime); + subscriber.onWorkStopped(root.memoizedInteractions, threadID); + } + } catch (error) { + // If the subscriber throws, rethrow it in a separate task + scheduleCallback(ImmediatePriority, function() { + throw error; + }); + } finally { + // Clear completed interactions from the pending Map. + // Unless the render was suspended or cascading work was scheduled, + // In which case– leave pending interactions until the subsequent render. + var pendingInteractionMap = root.pendingInteractionMap; + pendingInteractionMap.forEach(function( + scheduledInteractions, + scheduledExpirationTime + ) { + // Only decrement the pending interaction count if we're done. + // If there's still work at the current priority, + // That indicates that we are waiting for suspense data. + if (scheduledExpirationTime > earliestRemainingTimeAfterCommit) { + pendingInteractionMap.delete(scheduledExpirationTime); + + scheduledInteractions.forEach(function(interaction) { + interaction.__count--; + + if (subscriber !== null && interaction.__count === 0) { + try { + subscriber.onInteractionScheduledWorkCompleted(interaction); + } catch (error) { + // If the subscriber throws, rethrow it in a separate task + scheduleCallback(ImmediatePriority, function() { + throw error; + }); + } + } + }); + } + }); + } +} + +// This lets us hook into Fiber to debug what it's doing. +// See https://github.com/facebook/react/pull/8033. +// This is not part of the public API, not even for React DevTools. +// You may only inject a debugTool if you work on React Fiber itself. +var ReactFiberInstrumentation = { + debugTool: null +}; + +var ReactFiberInstrumentation_1 = ReactFiberInstrumentation; + +// 0 is PROD, 1 is DEV. +// Might add PROFILE later. + +var didWarnAboutNestedUpdates = void 0; +var didWarnAboutFindNodeInStrictMode = void 0; + +{ + didWarnAboutNestedUpdates = false; + didWarnAboutFindNodeInStrictMode = {}; +} + +function getContextForSubtree(parentComponent) { + if (!parentComponent) { + return emptyContextObject; + } + + var fiber = get(parentComponent); + var parentContext = findCurrentUnmaskedContext(fiber); + + if (fiber.tag === ClassComponent) { + var Component = fiber.type; + if (isContextProvider(Component)) { + return processChildContext(fiber, Component, parentContext); + } + } + + return parentContext; +} + +function scheduleRootUpdate(current$$1, element, expirationTime, callback) { + { + if (phase === "render" && current !== null && !didWarnAboutNestedUpdates) { + didWarnAboutNestedUpdates = true; + warningWithoutStack$1( + false, + "Render methods should be a pure function of props and state; " + + "triggering nested component updates from render is not allowed. " + + "If necessary, trigger nested updates in componentDidUpdate.\n\n" + + "Check the render method of %s.", + getComponentName(current.type) || "Unknown" + ); + } + } + + var update = createUpdate(expirationTime); + // Caution: React DevTools currently depends on this property + // being called "element". + update.payload = { element: element }; + + callback = callback === undefined ? null : callback; + if (callback !== null) { + !(typeof callback === "function") + ? warningWithoutStack$1( + false, + "render(...): Expected the last optional `callback` argument to be a " + + "function. Instead received: %s.", + callback + ) + : void 0; + update.callback = callback; + } + + flushPassiveEffects(); + enqueueUpdate(current$$1, update); + scheduleWork(current$$1, expirationTime); + + return expirationTime; +} + +function updateContainerAtExpirationTime( + element, + container, + parentComponent, + expirationTime, + callback +) { + // TODO: If this is a nested container, this won't be the root. + var current$$1 = container.current; + + { + if (ReactFiberInstrumentation_1.debugTool) { + if (current$$1.alternate === null) { + ReactFiberInstrumentation_1.debugTool.onMountContainer(container); + } else if (element === null) { + ReactFiberInstrumentation_1.debugTool.onUnmountContainer(container); + } else { + ReactFiberInstrumentation_1.debugTool.onUpdateContainer(container); + } + } + } + + var context = getContextForSubtree(parentComponent); + if (container.context === null) { + container.context = context; + } else { + container.pendingContext = context; + } + + return scheduleRootUpdate(current$$1, element, expirationTime, callback); +} + +function findHostInstance(component) { + var fiber = get(component); + if (fiber === undefined) { + if (typeof component.render === "function") { + (function() { + { + throw ReactError("Unable to find node on an unmounted component."); + } + })(); + } else { + (function() { + { + throw ReactError( + "Argument appears to not be a ReactComponent. Keys: " + + Object.keys(component) + ); + } + })(); + } + } + var hostFiber = findCurrentHostFiber(fiber); + if (hostFiber === null) { + return null; + } + return hostFiber.stateNode; +} + +function findHostInstanceWithWarning(component, methodName) { + { + var fiber = get(component); + if (fiber === undefined) { + if (typeof component.render === "function") { + (function() { + { + throw ReactError("Unable to find node on an unmounted component."); + } + })(); + } else { + (function() { + { + throw ReactError( + "Argument appears to not be a ReactComponent. Keys: " + + Object.keys(component) + ); + } + })(); + } + } + var hostFiber = findCurrentHostFiber(fiber); + if (hostFiber === null) { + return null; + } + if (hostFiber.mode & StrictMode) { + var componentName = getComponentName(fiber.type) || "Component"; + if (!didWarnAboutFindNodeInStrictMode[componentName]) { + didWarnAboutFindNodeInStrictMode[componentName] = true; + if (fiber.mode & StrictMode) { + warningWithoutStack$1( + false, + "%s is deprecated in StrictMode. " + + "%s was passed an instance of %s which is inside StrictMode. " + + "Instead, add a ref directly to the element you want to reference." + + "\n%s" + + "\n\nLearn more about using refs safely here:" + + "\nhttps://fb.me/react-strict-mode-find-node", + methodName, + methodName, + componentName, + getStackByFiberInDevAndProd(hostFiber) + ); + } else { + warningWithoutStack$1( + false, + "%s is deprecated in StrictMode. " + + "%s was passed an instance of %s which renders StrictMode children. " + + "Instead, add a ref directly to the element you want to reference." + + "\n%s" + + "\n\nLearn more about using refs safely here:" + + "\nhttps://fb.me/react-strict-mode-find-node", + methodName, + methodName, + componentName, + getStackByFiberInDevAndProd(hostFiber) + ); + } + } + } + return hostFiber.stateNode; + } + return findHostInstance(component); +} + +function createContainer(containerInfo, isConcurrent, hydrate) { + return createFiberRoot(containerInfo, isConcurrent, hydrate); +} + +function updateContainer(element, container, parentComponent, callback) { + var current$$1 = container.current; + var currentTime = requestCurrentTime(); + var expirationTime = computeExpirationForFiber(currentTime, current$$1); + return updateContainerAtExpirationTime( + element, + container, + parentComponent, + expirationTime, + callback + ); +} + +function getPublicRootInstance(container) { + var containerFiber = container.current; + if (!containerFiber.child) { + return null; + } + switch (containerFiber.child.tag) { + case HostComponent: + return getPublicInstance(containerFiber.child.stateNode); + default: + return containerFiber.child.stateNode; + } +} + +var shouldSuspendImpl = function(fiber) { + return false; +}; + +function shouldSuspend(fiber) { + return shouldSuspendImpl(fiber); +} + +var overrideHookState = null; +var overrideProps = null; +var scheduleUpdate = null; +var setSuspenseHandler = null; + +{ + var copyWithSetImpl = function(obj, path, idx, value) { + if (idx >= path.length) { + return value; + } + var key = path[idx]; + var updated = Array.isArray(obj) ? obj.slice() : Object.assign({}, obj); + // $FlowFixMe number or string is fine here + updated[key] = copyWithSetImpl(obj[key], path, idx + 1, value); + return updated; + }; + + var copyWithSet = function(obj, path, value) { + return copyWithSetImpl(obj, path, 0, value); + }; + + // Support DevTools editable values for useState and useReducer. + overrideHookState = function(fiber, id, path, value) { + // For now, the "id" of stateful hooks is just the stateful hook index. + // This may change in the future with e.g. nested hooks. + var currentHook = fiber.memoizedState; + while (currentHook !== null && id > 0) { + currentHook = currentHook.next; + id--; + } + if (currentHook !== null) { + flushPassiveEffects(); + + var newState = copyWithSet(currentHook.memoizedState, path, value); + currentHook.memoizedState = newState; + currentHook.baseState = newState; + + // We aren't actually adding an update to the queue, + // because there is no update we can add for useReducer hooks that won't trigger an error. + // (There's no appropriate action type for DevTools overrides.) + // As a result though, React will see the scheduled update as a noop and bailout. + // Shallow cloning props works as a workaround for now to bypass the bailout check. + fiber.memoizedProps = Object.assign({}, fiber.memoizedProps); + + scheduleWork(fiber, Sync); + } + }; + + // Support DevTools props for function components, forwardRef, memo, host components, etc. + overrideProps = function(fiber, path, value) { + flushPassiveEffects(); + fiber.pendingProps = copyWithSet(fiber.memoizedProps, path, value); + if (fiber.alternate) { + fiber.alternate.pendingProps = fiber.pendingProps; + } + scheduleWork(fiber, Sync); + }; + + scheduleUpdate = function(fiber) { + flushPassiveEffects(); + scheduleWork(fiber, Sync); + }; + + setSuspenseHandler = function(newShouldSuspendImpl) { + shouldSuspendImpl = newShouldSuspendImpl; + }; +} + +function injectIntoDevTools(devToolsConfig) { + var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; + var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher; + + return injectInternals( + Object.assign({}, devToolsConfig, { + overrideHookState: overrideHookState, + overrideProps: overrideProps, + setSuspenseHandler: setSuspenseHandler, + scheduleUpdate: scheduleUpdate, + currentDispatcherRef: ReactCurrentDispatcher, + findHostInstanceByFiber: function(fiber) { + var hostFiber = findCurrentHostFiber(fiber); + if (hostFiber === null) { + return null; + } + return hostFiber.stateNode; + }, + findFiberByHostInstance: function(instance) { + if (!findFiberByHostInstance) { + // Might not be implemented by the renderer. + return null; + } + return findFiberByHostInstance(instance); + } + }) + ); +} + +// This file intentionally does *not* have the Flow annotation. +// Don't add it. See `./inline-typed.js` for an explanation. + +function createPortal( + children, + containerInfo, + // TODO: figure out the API for cross-renderer implementation. + implementation +) { + var key = + arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; + + return { + // This tag allow us to uniquely identify this as a React Portal + $$typeof: REACT_PORTAL_TYPE, + key: key == null ? null : "" + key, + children: children, + containerInfo: containerInfo, + implementation: implementation + }; +} + +// TODO: this is special because it gets imported during build. + +var ReactVersion = "16.8.6"; + +// Modules provided by RN: +var NativeMethodsMixin = function(findNodeHandle, findHostInstance) { + /** + * `NativeMethodsMixin` provides methods to access the underlying native + * component directly. This can be useful in cases when you want to focus + * a view or measure its on-screen dimensions, for example. + * + * The methods described here are available on most of the default components + * provided by React Native. Note, however, that they are *not* available on + * composite components that aren't directly backed by a native view. This will + * generally include most components that you define in your own app. For more + * information, see [Direct + * Manipulation](docs/direct-manipulation.html). + * + * Note the Flow $Exact<> syntax is required to support mixins. + * React createClass mixins can only be used with exact types. + */ + var NativeMethodsMixin = { + /** + * Determines the location on screen, width, and height of the given view and + * returns the values via an async callback. If successful, the callback will + * be called with the following arguments: + * + * - x + * - y + * - width + * - height + * - pageX + * - pageY + * + * Note that these measurements are not available until after the rendering + * has been completed in native. If you need the measurements as soon as + * possible, consider using the [`onLayout` + * prop](docs/view.html#onlayout) instead. + */ + measure: function(callback) { + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + if (maybeInstance.canonical) { + // We can't call FabricUIManager here because it won't be loaded in paper + // at initialization time. See https://github.com/facebook/react/pull/15490 + // for more info. + nativeFabricUIManager.measure( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + } else { + ReactNativePrivateInterface.UIManager.measure( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + } + }, + + /** + * Determines the location of the given view in the window and returns the + * values via an async callback. If the React root view is embedded in + * another native view, this will give you the absolute coordinates. If + * successful, the callback will be called with the following + * arguments: + * + * - x + * - y + * - width + * - height + * + * Note that these measurements are not available until after the rendering + * has been completed in native. + */ + measureInWindow: function(callback) { + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + if (maybeInstance.canonical) { + // We can't call FabricUIManager here because it won't be loaded in paper + // at initialization time. See https://github.com/facebook/react/pull/15490 + // for more info. + nativeFabricUIManager.measureInWindow( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + } else { + ReactNativePrivateInterface.UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + } + }, + + /** + * Like [`measure()`](#measure), but measures the view relative an ancestor, + * specified as `relativeToNativeNode`. This means that the returned x, y + * are relative to the origin x, y of the ancestor view. + * + * As always, to obtain a native node handle for a component, you can use + * `findNodeHandle(component)`. + */ + measureLayout: function( + relativeToNativeNode, + onSuccess, + onFail /* currently unused */ + ) { + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + if (maybeInstance.canonical) { + warningWithoutStack$1( + false, + "Warning: measureLayout on components using NativeMethodsMixin " + + "or ReactNative.NativeComponent is not currently supported in Fabric. " + + "measureLayout must be called on a native ref. Consider using forwardRef." + ); + return; + } else { + var relativeNode = void 0; + + if (typeof relativeToNativeNode === "number") { + // Already a node handle + relativeNode = relativeToNativeNode; + } else if (relativeToNativeNode._nativeTag) { + relativeNode = relativeToNativeNode._nativeTag; + } + + if (relativeNode == null) { + warningWithoutStack$1( + false, + "Warning: ref.measureLayout must be called with a node handle or a ref to a native component." + ); + + return; + } + + ReactNativePrivateInterface.UIManager.measureLayout( + findNodeHandle(this), + relativeNode, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + ); + } + }, + + /** + * This function sends props straight to native. They will not participate in + * future diff process - this means that if you do not include them in the + * next render, they will remain active (see [Direct + * Manipulation](docs/direct-manipulation.html)). + */ + setNativeProps: function(nativeProps) { + // Class components don't have viewConfig -> validateAttributes. + // Nor does it make sense to set native props on a non-native component. + // Instead, find the nearest host component and set props on it. + // Use findNodeHandle() rather than findNodeHandle() because + // We want the instance/wrapper (not the native tag). + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + if (maybeInstance.canonical) { + warningWithoutStack$1( + false, + "Warning: setNativeProps is not currently supported in Fabric" + ); + return; + } + + { + if (warnAboutDeprecatedSetNativeProps) { + warningWithoutStack$1( + false, + "Warning: Calling ref.setNativeProps(nativeProps) " + + "is deprecated and will be removed in a future release. " + + "Use the setNativeProps export from the react-native package instead." + + "\n\timport {setNativeProps} from 'react-native';\n\tsetNativeProps(ref, nativeProps);\n" + ); + } + } + + var nativeTag = + maybeInstance._nativeTag || maybeInstance.canonical._nativeTag; + var viewConfig = + maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; + + { + warnForStyleProps(nativeProps, viewConfig.validAttributes); + } + + var updatePayload = create(nativeProps, viewConfig.validAttributes); + + // Avoid the overhead of bridge calls if there's no update. + // This is an expensive no-op for Android, and causes an unnecessary + // view invalidation for certain components (eg RCTTextInput) on iOS. + if (updatePayload != null) { + ReactNativePrivateInterface.UIManager.updateView( + nativeTag, + viewConfig.uiViewClassName, + updatePayload + ); + } + }, + + /** + * Requests focus for the given input or view. The exact behavior triggered + * will depend on the platform and type of view. + */ + focus: function() { + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); + }, + + /** + * Removes focus from an input or view. This is the opposite of `focus()`. + */ + blur: function() { + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); + } + }; + + { + // hide this from Flow since we can't define these properties outside of + // true without actually implementing them (setting them to undefined + // isn't allowed by ReactClass) + var NativeMethodsMixin_DEV = NativeMethodsMixin; + (function() { + if ( + !( + !NativeMethodsMixin_DEV.componentWillMount && + !NativeMethodsMixin_DEV.componentWillReceiveProps && + !NativeMethodsMixin_DEV.UNSAFE_componentWillMount && + !NativeMethodsMixin_DEV.UNSAFE_componentWillReceiveProps + ) + ) { + throw ReactError("Do not override existing functions."); + } + })(); + // TODO (bvaughn) Remove cWM and cWRP in a future version of React Native, + // Once these lifecycles have been remove from the reconciler. + NativeMethodsMixin_DEV.componentWillMount = function() { + throwOnStylesProp(this, this.props); + }; + NativeMethodsMixin_DEV.componentWillReceiveProps = function(newProps) { + throwOnStylesProp(this, newProps); + }; + NativeMethodsMixin_DEV.UNSAFE_componentWillMount = function() { + throwOnStylesProp(this, this.props); + }; + NativeMethodsMixin_DEV.UNSAFE_componentWillReceiveProps = function( + newProps + ) { + throwOnStylesProp(this, newProps); + }; + + // React may warn about cWM/cWRP/cWU methods being deprecated. + // Add a flag to suppress these warnings for this special case. + // TODO (bvaughn) Remove this flag once the above methods have been removed. + NativeMethodsMixin_DEV.componentWillMount.__suppressDeprecationWarning = true; + NativeMethodsMixin_DEV.componentWillReceiveProps.__suppressDeprecationWarning = true; + } + + return NativeMethodsMixin; +}; + +function _classCallCheck$1(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } +} + +function _possibleConstructorReturn(self, call) { + if (!self) { + throw new ReferenceError( + "this hasn't been initialised - super() hasn't been called" + ); + } + return call && (typeof call === "object" || typeof call === "function") + ? call + : self; +} + +function _inherits(subClass, superClass) { + if (typeof superClass !== "function" && superClass !== null) { + throw new TypeError( + "Super expression must either be null or a function, not " + + typeof superClass + ); + } + subClass.prototype = Object.create(superClass && superClass.prototype, { + constructor: { + value: subClass, + enumerable: false, + writable: true, + configurable: true + } + }); + if (superClass) + Object.setPrototypeOf + ? Object.setPrototypeOf(subClass, superClass) + : (subClass.__proto__ = superClass); +} + +// Modules provided by RN: +var ReactNativeComponent = function(findNodeHandle, findHostInstance) { + /** + * Superclass that provides methods to access the underlying native component. + * This can be useful when you want to focus a view or measure its dimensions. + * + * Methods implemented by this class are available on most default components + * provided by React Native. However, they are *not* available on composite + * components that are not directly backed by a native view. For more + * information, see [Direct Manipulation](docs/direct-manipulation.html). + * + * @abstract + */ + var ReactNativeComponent = (function(_React$Component) { + _inherits(ReactNativeComponent, _React$Component); + + function ReactNativeComponent() { + _classCallCheck$1(this, ReactNativeComponent); + + return _possibleConstructorReturn( + this, + _React$Component.apply(this, arguments) + ); + } + + /** + * Removes focus. This is the opposite of `focus()`. + */ + + /** + * Due to bugs in Flow's handling of React.createClass, some fields already + * declared in the base class need to be redeclared below. + */ + ReactNativeComponent.prototype.blur = function blur() { + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); + }; + + /** + * Requests focus. The exact behavior depends on the platform and view. + */ + + ReactNativeComponent.prototype.focus = function focus() { + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); + }; + + /** + * Measures the on-screen location and dimensions. If successful, the callback + * will be called asynchronously with the following arguments: + * + * - x + * - y + * - width + * - height + * - pageX + * - pageY + * + * These values are not available until after natives rendering completes. If + * you need the measurements as soon as possible, consider using the + * [`onLayout` prop](docs/view.html#onlayout) instead. + */ + + ReactNativeComponent.prototype.measure = function measure(callback) { + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + if (maybeInstance.canonical) { + // We can't call FabricUIManager here because it won't be loaded in paper + // at initialization time. See https://github.com/facebook/react/pull/15490 + // for more info. + nativeFabricUIManager.measure( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + } else { + ReactNativePrivateInterface.UIManager.measure( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + } + }; + + /** + * Measures the on-screen location and dimensions. Even if the React Native + * root view is embedded within another native view, this method will give you + * the absolute coordinates measured from the window. If successful, the + * callback will be called asynchronously with the following arguments: + * + * - x + * - y + * - width + * - height + * + * These values are not available until after natives rendering completes. + */ + + ReactNativeComponent.prototype.measureInWindow = function measureInWindow( + callback + ) { + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + if (maybeInstance.canonical) { + // We can't call FabricUIManager here because it won't be loaded in paper + // at initialization time. See https://github.com/facebook/react/pull/15490 + // for more info. + nativeFabricUIManager.measureInWindow( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + } else { + ReactNativePrivateInterface.UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + } + }; + + /** + * Similar to [`measure()`](#measure), but the resulting location will be + * relative to the supplied ancestor's location. + * + * Obtain a native node handle with `ReactNative.findNodeHandle(component)`. + */ + + ReactNativeComponent.prototype.measureLayout = function measureLayout( + relativeToNativeNode, + onSuccess, + onFail /* currently unused */ + ) { + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + if (maybeInstance.canonical) { + warningWithoutStack$1( + false, + "Warning: measureLayout on components using NativeMethodsMixin " + + "or ReactNative.NativeComponent is not currently supported in Fabric. " + + "measureLayout must be called on a native ref. Consider using forwardRef." + ); + return; + } else { + var relativeNode = void 0; + + if (typeof relativeToNativeNode === "number") { + // Already a node handle + relativeNode = relativeToNativeNode; + } else if (relativeToNativeNode._nativeTag) { + relativeNode = relativeToNativeNode._nativeTag; + } + + if (relativeNode == null) { + warningWithoutStack$1( + false, + "Warning: ref.measureLayout must be called with a node handle or a ref to a native component." + ); + + return; + } + + ReactNativePrivateInterface.UIManager.measureLayout( + findNodeHandle(this), + relativeNode, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + ); + } + }; + + /** + * This function sends props straight to native. They will not participate in + * future diff process - this means that if you do not include them in the + * next render, they will remain active (see [Direct + * Manipulation](docs/direct-manipulation.html)). + */ + + ReactNativeComponent.prototype.setNativeProps = function setNativeProps( + nativeProps + ) { + // Class components don't have viewConfig -> validateAttributes. + // Nor does it make sense to set native props on a non-native component. + // Instead, find the nearest host component and set props on it. + // Use findNodeHandle() rather than ReactNative.findNodeHandle() because + // We want the instance/wrapper (not the native tag). + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + if (maybeInstance.canonical) { + warningWithoutStack$1( + false, + "Warning: setNativeProps is not currently supported in Fabric" + ); + return; + } + + { + if (warnAboutDeprecatedSetNativeProps) { + warningWithoutStack$1( + false, + "Warning: Calling ref.setNativeProps(nativeProps) " + + "is deprecated and will be removed in a future release. " + + "Use the setNativeProps export from the react-native package instead." + + "\n\timport {setNativeProps} from 'react-native';\n\tsetNativeProps(ref, nativeProps);\n" + ); + } + } + + var nativeTag = + maybeInstance._nativeTag || maybeInstance.canonical._nativeTag; + var viewConfig = + maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; + + var updatePayload = create(nativeProps, viewConfig.validAttributes); + + // Avoid the overhead of bridge calls if there's no update. + // This is an expensive no-op for Android, and causes an unnecessary + // view invalidation for certain components (eg RCTTextInput) on iOS. + if (updatePayload != null) { + ReactNativePrivateInterface.UIManager.updateView( + nativeTag, + viewConfig.uiViewClassName, + updatePayload + ); + } + }; + + return ReactNativeComponent; + })(React.Component); + + // eslint-disable-next-line no-unused-expressions + + return ReactNativeComponent; +}; + +var instanceCache = {}; + +function getInstanceFromTag(tag) { + return instanceCache[tag] || null; +} + +// Module provided by RN: +var emptyObject$1 = {}; +{ + Object.freeze(emptyObject$1); +} + +var getInspectorDataForViewTag = void 0; + +{ + var traverseOwnerTreeUp = function(hierarchy, instance) { + if (instance) { + hierarchy.unshift(instance); + traverseOwnerTreeUp(hierarchy, instance._debugOwner); + } + }; + + var getOwnerHierarchy = function(instance) { + var hierarchy = []; + traverseOwnerTreeUp(hierarchy, instance); + return hierarchy; + }; + + var lastNonHostInstance = function(hierarchy) { + for (var i = hierarchy.length - 1; i > 1; i--) { + var instance = hierarchy[i]; + + if (instance.tag !== HostComponent) { + return instance; + } + } + return hierarchy[0]; + }; + + var getHostProps = function(fiber) { + var host = findCurrentHostFiber(fiber); + if (host) { + return host.memoizedProps || emptyObject$1; + } + return emptyObject$1; + }; + + var getHostNode = function(fiber, findNodeHandle) { + var hostNode = void 0; + // look for children first for the hostNode + // as composite fibers do not have a hostNode + while (fiber) { + if (fiber.stateNode !== null && fiber.tag === HostComponent) { + hostNode = findNodeHandle(fiber.stateNode); + } + if (hostNode) { + return hostNode; + } + fiber = fiber.child; + } + return null; + }; + + var createHierarchy = function(fiberHierarchy) { + return fiberHierarchy.map(function(fiber) { + return { + name: getComponentName(fiber.type), + getInspectorData: function(findNodeHandle) { + return { + measure: function(callback) { + return ReactNativePrivateInterface.UIManager.measure( + getHostNode(fiber, findNodeHandle), + callback + ); + }, + props: getHostProps(fiber), + source: fiber._debugSource + }; + } + }; + }); + }; + + getInspectorDataForViewTag = function(viewTag) { + var closestInstance = getInstanceFromTag(viewTag); + + // Handle case where user clicks outside of ReactNative + if (!closestInstance) { + return { + hierarchy: [], + props: emptyObject$1, + selection: null, + source: null + }; + } + + var fiber = findCurrentFiberUsingSlowPath(closestInstance); + var fiberHierarchy = getOwnerHierarchy(fiber); + var instance = lastNonHostInstance(fiberHierarchy); + var hierarchy = createHierarchy(fiberHierarchy); + var props = getHostProps(instance); + var source = instance._debugSource; + var selection = fiberHierarchy.indexOf(instance); + + return { + hierarchy: hierarchy, + props: props, + selection: selection, + source: source + }; + }; +} + +var ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner; + +function findNodeHandle(componentOrHandle) { + { + var owner = ReactCurrentOwner.current; + if (owner !== null && owner.stateNode !== null) { + !owner.stateNode._warnedAboutRefsInRender + ? warningWithoutStack$1( + false, + "%s is accessing findNodeHandle inside its render(). " + + "render() should be a pure function of props and state. It should " + + "never access something that requires stale data from the previous " + + "render, such as refs. Move this logic to componentDidMount and " + + "componentDidUpdate instead.", + getComponentName(owner.type) || "A component" + ) + : void 0; + + owner.stateNode._warnedAboutRefsInRender = true; + } + } + if (componentOrHandle == null) { + return null; + } + if (typeof componentOrHandle === "number") { + // Already a node handle + return componentOrHandle; + } + if (componentOrHandle._nativeTag) { + return componentOrHandle._nativeTag; + } + if (componentOrHandle.canonical && componentOrHandle.canonical._nativeTag) { + return componentOrHandle.canonical._nativeTag; + } + var hostInstance = void 0; + { + hostInstance = findHostInstanceWithWarning( + componentOrHandle, + "findNodeHandle" + ); + } + + if (hostInstance == null) { + return hostInstance; + } + // TODO: the code is right but the types here are wrong. + // https://github.com/facebook/react/pull/12863 + if (hostInstance.canonical) { + // Fabric + return hostInstance.canonical._nativeTag; + } + return hostInstance._nativeTag; +} + +setBatchingImplementation( + batchedUpdates$1, + interactiveUpdates$1, + flushInteractiveUpdates$1 +); + +var roots = new Map(); + +var ReactFabric = { + NativeComponent: ReactNativeComponent(findNodeHandle, findHostInstance), + + findNodeHandle: findNodeHandle, + + setNativeProps: function(handle, nativeProps) { + warningWithoutStack$1( + false, + "Warning: setNativeProps is not currently supported in Fabric" + ); + + return; + }, + render: function(element, containerTag, callback) { + var root = roots.get(containerTag); + + if (!root) { + // TODO (bvaughn): If we decide to keep the wrapper component, + // We could create a wrapper for containerTag as well to reduce special casing. + root = createContainer(containerTag, false, false); + roots.set(containerTag, root); + } + updateContainer(element, root, null, callback); + + return getPublicRootInstance(root); + }, + unmountComponentAtNode: function(containerTag) { + var root = roots.get(containerTag); + if (root) { + // TODO: Is it safe to reset this now or should I wait since this unmount could be deferred? + updateContainer(null, root, null, function() { + roots.delete(containerTag); + }); + } + }, + createPortal: function(children, containerTag) { + var key = + arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; + + return createPortal(children, containerTag, null, key); + }, + + __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { + // Used as a mixin in many createClass-based components + NativeMethodsMixin: NativeMethodsMixin(findNodeHandle, findHostInstance) + } +}; + +injectIntoDevTools({ + findFiberByHostInstance: getInstanceFromInstance, + getInspectorDataForViewTag: getInspectorDataForViewTag, + bundleType: 1, + version: ReactVersion, + rendererPackageName: "react-native-renderer" +}); + +var ReactFabric$2 = Object.freeze({ + default: ReactFabric +}); + +var ReactFabric$3 = (ReactFabric$2 && ReactFabric) || ReactFabric$2; + +// TODO: decide on the top-level export form. +// This is hacky but makes it work with both Rollup and Jest. +var fabric = ReactFabric$3.default || ReactFabric$3; + +module.exports = fabric; + + })(); +} diff --git a/Libraries/Renderer/oss/ReactFabric-dev.js b/Libraries/Renderer/implementations/ReactFabric-dev.js similarity index 99% rename from Libraries/Renderer/oss/ReactFabric-dev.js rename to Libraries/Renderer/implementations/ReactFabric-dev.js index 5ea69a29fba41a..f1676471c4da4e 100644 --- a/Libraries/Renderer/oss/ReactFabric-dev.js +++ b/Libraries/Renderer/implementations/ReactFabric-dev.js @@ -16,19 +16,12 @@ if (__DEV__) { (function() { "use strict"; -require("InitializeCore"); -var ReactNativeViewConfigRegistry = require("ReactNativeViewConfigRegistry"); -var UIManager = require("UIManager"); +require("react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore"); +var ReactNativePrivateInterface = require("react-native/Libraries/ReactPrivate/ReactNativePrivateInterface"); var React = require("react"); -var deepDiffer = require("deepDiffer"); -var flattenStyle = require("flattenStyle"); -var deepFreezeAndThrowOnMutationInDev = require("deepFreezeAndThrowOnMutationInDev"); -var TextInputState = require("TextInputState"); -var FabricUIManager = require("FabricUIManager"); var checkPropTypes = require("prop-types/checkPropTypes"); var Scheduler = require("scheduler"); var tracing = require("scheduler/tracing"); -var ExceptionsManager = require("ExceptionsManager"); // Do not require this module directly! Use a normal error constructor with // template literal strings. The messages will be converted to ReactError during @@ -1561,7 +1554,7 @@ function getPooledWarningPropertyDefinition(propName, getVal) { return { configurable: true, set: set, - get: get$$1 + get: get }; function set(val) { @@ -1570,7 +1563,7 @@ function getPooledWarningPropertyDefinition(propName, getVal) { return val; } - function get$$1() { + function get() { var action = isFunction ? "accessing the method" : "accessing the property"; var result = isFunction ? "This is a no-op function" @@ -1913,7 +1906,7 @@ var changeResponder = function(nextResponderInst, blockHostResponder) { } }; -var eventTypes$1 = { +var eventTypes = { /** * On a `touchStart`/`mouseDown`, is it desired that this element become the * responder? @@ -2204,12 +2197,12 @@ function setResponderAndExtractTransfer( nativeEventTarget ) { var shouldSetEventType = isStartish(topLevelType) - ? eventTypes$1.startShouldSetResponder + ? eventTypes.startShouldSetResponder : isMoveish(topLevelType) - ? eventTypes$1.moveShouldSetResponder + ? eventTypes.moveShouldSetResponder : topLevelType === TOP_SELECTION_CHANGE - ? eventTypes$1.selectionChangeShouldSetResponder - : eventTypes$1.scrollShouldSetResponder; + ? eventTypes.selectionChangeShouldSetResponder + : eventTypes.scrollShouldSetResponder; // TODO: stop one short of the current responder. var bubbleShouldSetFrom = !responderInst @@ -2243,7 +2236,7 @@ function setResponderAndExtractTransfer( } var extracted = void 0; var grantEvent = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderGrant, + eventTypes.responderGrant, wantsResponderInst, nativeEvent, nativeEventTarget @@ -2254,7 +2247,7 @@ function setResponderAndExtractTransfer( var blockHostResponder = executeDirectDispatch(grantEvent) === true; if (responderInst) { var terminationRequestEvent = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderTerminationRequest, + eventTypes.responderTerminationRequest, responderInst, nativeEvent, nativeEventTarget @@ -2271,7 +2264,7 @@ function setResponderAndExtractTransfer( if (shouldSwitch) { var terminateEvent = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderTerminate, + eventTypes.responderTerminate, responderInst, nativeEvent, nativeEventTarget @@ -2282,7 +2275,7 @@ function setResponderAndExtractTransfer( changeResponder(wantsResponderInst, blockHostResponder); } else { var rejectEvent = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderReject, + eventTypes.responderReject, wantsResponderInst, nativeEvent, nativeEventTarget @@ -2351,7 +2344,7 @@ var ResponderEventPlugin = { return responderInst; }, - eventTypes: eventTypes$1, + eventTypes: eventTypes, /** * We must be resilient to `targetInst` being `null` on `touchMove` or @@ -2401,11 +2394,11 @@ var ResponderEventPlugin = { var isResponderTouchMove = responderInst && isMoveish(topLevelType); var isResponderTouchEnd = responderInst && isEndish(topLevelType); var incrementalTouch = isResponderTouchStart - ? eventTypes$1.responderStart + ? eventTypes.responderStart : isResponderTouchMove - ? eventTypes$1.responderMove + ? eventTypes.responderMove : isResponderTouchEnd - ? eventTypes$1.responderEnd + ? eventTypes.responderEnd : null; if (incrementalTouch) { @@ -2428,9 +2421,9 @@ var ResponderEventPlugin = { isEndish(topLevelType) && noResponderTouches(nativeEvent); var finalTouch = isResponderTerminate - ? eventTypes$1.responderTerminate + ? eventTypes.responderTerminate : isResponderRelease - ? eventTypes$1.responderRelease + ? eventTypes.responderRelease : null; if (finalTouch) { var finalEvent = ResponderSyntheticEvent.getPooled( @@ -2462,8 +2455,18 @@ var ResponderEventPlugin = { } }; +// Module provided by RN: +var customBubblingEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customBubblingEventTypes; +var customDirectEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customDirectEventTypes; +var eventTypes$1 = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes; + var ReactNativeBridgeEventPlugin = { - eventTypes: ReactNativeViewConfigRegistry.eventTypes, + eventTypes: eventTypes$1, /** * @see {EventPluginHub.extractEvents} @@ -2478,10 +2481,8 @@ var ReactNativeBridgeEventPlugin = { // Probably a node belonging to another renderer's tree. return null; } - var bubbleDispatchConfig = - ReactNativeViewConfigRegistry.customBubblingEventTypes[topLevelType]; - var directDispatchConfig = - ReactNativeViewConfigRegistry.customDirectEventTypes[topLevelType]; + var bubbleDispatchConfig = customBubblingEventTypes[topLevelType]; + var directDispatchConfig = customDirectEventTypes[topLevelType]; (function() { if (!(bubbleDispatchConfig || directDispatchConfig)) { throw ReactError( @@ -2555,9 +2556,12 @@ var ReactFabricGlobalResponderHandler = { onChange: function(from, to, blockNativeResponder) { if (to !== null) { var tag = to.stateNode.canonical._nativeTag; - UIManager.setJSResponder(tag, blockNativeResponder); + ReactNativePrivateInterface.UIManager.setJSResponder( + tag, + blockNativeResponder + ); } else { - UIManager.clearJSResponder(); + ReactNativePrivateInterface.UIManager.clearJSResponder(); } } }; @@ -2588,7 +2592,7 @@ ResponderEventPlugin.injection.injectGlobalResponderHandler( * supported we can rename it. */ -function get$1(key) { +function get(key) { return key._reactInternalFiber; } @@ -2855,7 +2859,7 @@ function isMounted(component) { } } - var fiber = get$1(component); + var fiber = get(component); if (!fiber) { return false; } @@ -3145,7 +3149,7 @@ function defaultDiffer(prevProp, nextProp) { return true; } else { // For objects and arrays, the default diffing algorithm is a deep compare - return deepDiffer(prevProp, nextProp); + return ReactNativePrivateInterface.deepDiffer(prevProp, nextProp); } } @@ -3285,7 +3289,7 @@ function diffNestedProperty( return diffProperties( updatePayload, // $FlowFixMe - We know that this is always an object when the input is. - flattenStyle(prevProp), + ReactNativePrivateInterface.flattenStyle(prevProp), // $FlowFixMe - We know that this isn't an array because of above flow. nextProp, validAttributes @@ -3296,7 +3300,7 @@ function diffNestedProperty( updatePayload, prevProp, // $FlowFixMe - We know that this is always an object when the input is. - flattenStyle(nextProp), + ReactNativePrivateInterface.flattenStyle(nextProp), validAttributes ); } @@ -3680,7 +3684,7 @@ function shim() { // Mutation (when unsupported) var supportsMutation = false; -var appendChild$1 = shim; +var appendChild = shim; var appendChildToContainer = shim; var commitTextUpdate = shim; var commitMount = shim; @@ -3742,18 +3746,37 @@ function _classCallCheck(instance, Constructor) { } // Modules provided by RN: +var _nativeFabricUIManage = nativeFabricUIManager; +var createNode = _nativeFabricUIManage.createNode; +var cloneNode = _nativeFabricUIManage.cloneNode; +var cloneNodeWithNewChildren = _nativeFabricUIManage.cloneNodeWithNewChildren; +var cloneNodeWithNewChildrenAndProps = + _nativeFabricUIManage.cloneNodeWithNewChildrenAndProps; +var cloneNodeWithNewProps = _nativeFabricUIManage.cloneNodeWithNewProps; +var createChildNodeSet = _nativeFabricUIManage.createChildSet; +var appendChildNode = _nativeFabricUIManage.appendChild; +var appendChildNodeToSet = _nativeFabricUIManage.appendChildToSet; +var completeRoot = _nativeFabricUIManage.completeRoot; +var registerEventHandler = _nativeFabricUIManage.registerEventHandler; +var fabricMeasure = _nativeFabricUIManage.measure; +var fabricMeasureInWindow = _nativeFabricUIManage.measureInWindow; +var fabricMeasureLayout = _nativeFabricUIManage.measureLayout; +var getViewConfigForType = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.get; + // Counter for uniquely identifying views. // % 10 === 1 means it is a rootTag. // % 2 === 0 means it is a Fabric tag. // This means that they never overlap. + var nextReactTag = 2; // TODO: Remove this conditional once all changes have propagated. -if (FabricUIManager.registerEventHandler) { +if (registerEventHandler) { /** * Register the event emitter with the native bridge */ - FabricUIManager.registerEventHandler(dispatchEvent); + registerEventHandler(dispatchEvent); } /** @@ -3776,30 +3799,30 @@ var ReactFabricHostComponent = (function() { } ReactFabricHostComponent.prototype.blur = function blur() { - TextInputState.blurTextInput(this._nativeTag); + ReactNativePrivateInterface.TextInputState.blurTextInput(this._nativeTag); }; ReactFabricHostComponent.prototype.focus = function focus() { - TextInputState.focusTextInput(this._nativeTag); + ReactNativePrivateInterface.TextInputState.focusTextInput(this._nativeTag); }; - ReactFabricHostComponent.prototype.measure = function measure$$1(callback) { - FabricUIManager.measure( + ReactFabricHostComponent.prototype.measure = function measure(callback) { + fabricMeasure( this._internalInstanceHandle.stateNode.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); }; - ReactFabricHostComponent.prototype.measureInWindow = function measureInWindow$$1( + ReactFabricHostComponent.prototype.measureInWindow = function measureInWindow( callback ) { - FabricUIManager.measureInWindow( + fabricMeasureInWindow( this._internalInstanceHandle.stateNode.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); }; - ReactFabricHostComponent.prototype.measureLayout = function measureLayout$$1( + ReactFabricHostComponent.prototype.measureLayout = function measureLayout( relativeToNativeNode, onSuccess, onFail /* currently unused */ @@ -3816,7 +3839,7 @@ var ReactFabricHostComponent = (function() { return; } - FabricUIManager.measureLayout( + fabricMeasureLayout( this._internalInstanceHandle.stateNode.node, relativeToNativeNode._internalInstanceHandle.stateNode.node, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -3839,7 +3862,7 @@ var ReactFabricHostComponent = (function() { })(); function appendInitialChild(parentInstance, child) { - FabricUIManager.appendChild(parentInstance.node, child.node); + appendChildNode(parentInstance.node, child.node); } function createInstance( @@ -3852,19 +3875,21 @@ function createInstance( var tag = nextReactTag; nextReactTag += 2; - var viewConfig = ReactNativeViewConfigRegistry.get(type); + var viewConfig = getViewConfigForType(type); { for (var key in viewConfig.validAttributes) { if (props.hasOwnProperty(key)) { - deepFreezeAndThrowOnMutationInDev(props[key]); + ReactNativePrivateInterface.deepFreezeAndThrowOnMutationInDev( + props[key] + ); } } } var updatePayload = create(props, viewConfig.validAttributes); - var node = FabricUIManager.createNode( + var node = createNode( tag, // reactTag viewConfig.uiViewClassName, // viewName rootContainerInstance, // rootTag @@ -3902,7 +3927,7 @@ function createTextInstance( var tag = nextReactTag; nextReactTag += 2; - var node = FabricUIManager.createNode( + var node = createNode( tag, // reactTag "RCTRawText", // viewName rootContainerInstance, // rootTag @@ -4025,18 +4050,15 @@ function cloneInstance( var clone = void 0; if (keepChildren) { if (updatePayload !== null) { - clone = FabricUIManager.cloneNodeWithNewProps(node, updatePayload); + clone = cloneNodeWithNewProps(node, updatePayload); } else { - clone = FabricUIManager.cloneNode(node); + clone = cloneNode(node); } } else { if (updatePayload !== null) { - clone = FabricUIManager.cloneNodeWithNewChildrenAndProps( - node, - updatePayload - ); + clone = cloneNodeWithNewChildrenAndProps(node, updatePayload); } else { - clone = FabricUIManager.cloneNodeWithNewChildren(node); + clone = cloneNodeWithNewChildren(node); } } return { @@ -4053,7 +4075,7 @@ function cloneHiddenInstance(instance, type, props, internalInstanceHandle) { viewConfig.validAttributes ); return { - node: FabricUIManager.cloneNodeWithNewProps(node, updatePayload), + node: cloneNodeWithNewProps(node, updatePayload), canonical: instance.canonical }; } @@ -4063,15 +4085,15 @@ function cloneHiddenTextInstance(instance, text, internalInstanceHandle) { } function createContainerChildSet(container) { - return FabricUIManager.createChildSet(container); + return createChildNodeSet(container); } function appendChildToContainerChildSet(childSet, child) { - FabricUIManager.appendChildToSet(childSet, child.node); + appendChildNodeToSet(childSet, child.node); } function finalizeContainerChildren(container, newChildren) { - FabricUIManager.completeRoot(container, newChildren); + completeRoot(container, newChildren); } function mountEventComponent(eventComponentInstance) { @@ -7565,7 +7587,7 @@ function applyDerivedStateFromProps( var classComponentUpdater = { isMounted: isMounted, enqueueSetState: function(inst, payload, callback) { - var fiber = get$1(inst); + var fiber = get(inst); var currentTime = requestCurrentTime(); var expirationTime = computeExpirationForFiber(currentTime, fiber); @@ -7583,7 +7605,7 @@ var classComponentUpdater = { scheduleWork(fiber, expirationTime); }, enqueueReplaceState: function(inst, payload, callback) { - var fiber = get$1(inst); + var fiber = get(inst); var currentTime = requestCurrentTime(); var expirationTime = computeExpirationForFiber(currentTime, fiber); @@ -7603,7 +7625,7 @@ var classComponentUpdater = { scheduleWork(fiber, expirationTime); }, enqueueForceUpdate: function(inst, callback) { - var fiber = get$1(inst); + var fiber = get(inst); var currentTime = requestCurrentTime(); var expirationTime = computeExpirationForFiber(currentTime, fiber); @@ -14897,7 +14919,10 @@ function showErrorDialog(capturedError) { errorToHandle = new Error("Unspecified error at:" + componentStack); } - ExceptionsManager.handleException(errorToHandle, false); + ReactNativePrivateInterface.ExceptionsManager.handleException( + errorToHandle, + false + ); // Return false here to prevent ReactFiberErrorLogger default behavior of // logging error details to console.error. Calls to console.error are @@ -15879,7 +15904,7 @@ function commitPlacement(finishedWork) { if (isContainer) { appendChildToContainer(parent, stateNode); } else { - appendChild$1(parent, stateNode); + appendChild(parent, stateNode); } } } else if (node.tag === HostPortal) { @@ -18559,7 +18584,7 @@ function getContextForSubtree(parentComponent) { return emptyContextObject; } - var fiber = get$1(parentComponent); + var fiber = get(parentComponent); var parentContext = findCurrentUnmaskedContext(fiber); if (fiber.tag === ClassComponent) { @@ -18645,7 +18670,7 @@ function updateContainerAtExpirationTime( } function findHostInstance(component) { - var fiber = get$1(component); + var fiber = get(component); if (fiber === undefined) { if (typeof component.render === "function") { (function() { @@ -18673,7 +18698,7 @@ function findHostInstance(component) { function findHostInstanceWithWarning(component, methodName) { { - var fiber = get$1(component); + var fiber = get(component); if (fiber === undefined) { if (typeof component.render === "function") { (function() { @@ -18958,7 +18983,7 @@ var NativeMethodsMixin = function(findNodeHandle, findHostInstance) { mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); } else { - UIManager.measure( + ReactNativePrivateInterface.UIManager.measure( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); @@ -19006,7 +19031,7 @@ var NativeMethodsMixin = function(findNodeHandle, findHostInstance) { mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); } else { - UIManager.measureInWindow( + ReactNativePrivateInterface.UIManager.measureInWindow( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); @@ -19069,7 +19094,7 @@ var NativeMethodsMixin = function(findNodeHandle, findHostInstance) { return; } - UIManager.measureLayout( + ReactNativePrivateInterface.UIManager.measureLayout( findNodeHandle(this), relativeNode, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -19141,7 +19166,7 @@ var NativeMethodsMixin = function(findNodeHandle, findHostInstance) { // This is an expensive no-op for Android, and causes an unnecessary // view invalidation for certain components (eg RCTTextInput) on iOS. if (updatePayload != null) { - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( nativeTag, viewConfig.uiViewClassName, updatePayload @@ -19154,14 +19179,18 @@ var NativeMethodsMixin = function(findNodeHandle, findHostInstance) { * will depend on the platform and type of view. */ focus: function() { - TextInputState.focusTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); }, /** * Removes focus from an input or view. This is the opposite of `focus()`. */ blur: function() { - TextInputState.blurTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); } }; @@ -19281,7 +19310,9 @@ var ReactNativeComponent = function(findNodeHandle, findHostInstance) { * declared in the base class need to be redeclared below. */ ReactNativeComponent.prototype.blur = function blur() { - TextInputState.blurTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); }; /** @@ -19289,7 +19320,9 @@ var ReactNativeComponent = function(findNodeHandle, findHostInstance) { */ ReactNativeComponent.prototype.focus = function focus() { - TextInputState.focusTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); }; /** @@ -19308,7 +19341,7 @@ var ReactNativeComponent = function(findNodeHandle, findHostInstance) { * [`onLayout` prop](docs/view.html#onlayout) instead. */ - ReactNativeComponent.prototype.measure = function measure$$1(callback) { + ReactNativeComponent.prototype.measure = function measure(callback) { var maybeInstance = void 0; // Fiber errors if findNodeHandle is called for an umounted component. @@ -19334,7 +19367,7 @@ var ReactNativeComponent = function(findNodeHandle, findHostInstance) { mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); } else { - UIManager.measure( + ReactNativePrivateInterface.UIManager.measure( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); @@ -19355,7 +19388,7 @@ var ReactNativeComponent = function(findNodeHandle, findHostInstance) { * These values are not available until after natives rendering completes. */ - ReactNativeComponent.prototype.measureInWindow = function measureInWindow$$1( + ReactNativeComponent.prototype.measureInWindow = function measureInWindow( callback ) { var maybeInstance = void 0; @@ -19383,7 +19416,7 @@ var ReactNativeComponent = function(findNodeHandle, findHostInstance) { mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); } else { - UIManager.measureInWindow( + ReactNativePrivateInterface.UIManager.measureInWindow( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); @@ -19397,7 +19430,7 @@ var ReactNativeComponent = function(findNodeHandle, findHostInstance) { * Obtain a native node handle with `ReactNative.findNodeHandle(component)`. */ - ReactNativeComponent.prototype.measureLayout = function measureLayout$$1( + ReactNativeComponent.prototype.measureLayout = function measureLayout( relativeToNativeNode, onSuccess, onFail /* currently unused */ @@ -19445,7 +19478,7 @@ var ReactNativeComponent = function(findNodeHandle, findHostInstance) { return; } - UIManager.measureLayout( + ReactNativePrivateInterface.UIManager.measureLayout( findNodeHandle(this), relativeNode, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -19516,7 +19549,7 @@ var ReactNativeComponent = function(findNodeHandle, findHostInstance) { // This is an expensive no-op for Android, and causes an unnecessary // view invalidation for certain components (eg RCTTextInput) on iOS. if (updatePayload != null) { - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( nativeTag, viewConfig.uiViewClassName, updatePayload @@ -19602,7 +19635,7 @@ var getInspectorDataForViewTag = void 0; getInspectorData: function(findNodeHandle) { return { measure: function(callback) { - return UIManager.measure( + return ReactNativePrivateInterface.UIManager.measure( getHostNode(fiber, findNodeHandle), callback ); diff --git a/Libraries/Renderer/implementations/ReactFabric-prod.fb.js b/Libraries/Renderer/implementations/ReactFabric-prod.fb.js new file mode 100644 index 00000000000000..414151d1168e47 --- /dev/null +++ b/Libraries/Renderer/implementations/ReactFabric-prod.fb.js @@ -0,0 +1,6974 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @noflow + * @preventMunge + * @generated + */ + +"use strict"; +require("react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore"); +var ReactNativePrivateInterface = require("react-native/Libraries/ReactPrivate/ReactNativePrivateInterface"), + React = require("react"), + Scheduler = require("scheduler"); +function ReactError(message) { + message = Error(message); + message.name = "Invariant Violation"; + return message; +} +var eventPluginOrder = null, + namesToPlugins = {}; +function recomputePluginOrdering() { + if (eventPluginOrder) + for (var pluginName in namesToPlugins) { + var pluginModule = namesToPlugins[pluginName], + pluginIndex = eventPluginOrder.indexOf(pluginName); + if (!(-1 < pluginIndex)) + throw ReactError( + "EventPluginRegistry: Cannot inject event plugins that do not exist in the plugin ordering, `" + + pluginName + + "`." + ); + if (!plugins[pluginIndex]) { + if (!pluginModule.extractEvents) + throw ReactError( + "EventPluginRegistry: Event plugins must implement an `extractEvents` method, but `" + + pluginName + + "` does not." + ); + plugins[pluginIndex] = pluginModule; + pluginIndex = pluginModule.eventTypes; + for (var eventName in pluginIndex) { + var JSCompiler_inline_result = void 0; + var dispatchConfig = pluginIndex[eventName], + pluginModule$jscomp$0 = pluginModule, + eventName$jscomp$0 = eventName; + if (eventNameDispatchConfigs.hasOwnProperty(eventName$jscomp$0)) + throw ReactError( + "EventPluginHub: More than one plugin attempted to publish the same event name, `" + + eventName$jscomp$0 + + "`." + ); + eventNameDispatchConfigs[eventName$jscomp$0] = dispatchConfig; + var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames; + if (phasedRegistrationNames) { + for (JSCompiler_inline_result in phasedRegistrationNames) + phasedRegistrationNames.hasOwnProperty( + JSCompiler_inline_result + ) && + publishRegistrationName( + phasedRegistrationNames[JSCompiler_inline_result], + pluginModule$jscomp$0, + eventName$jscomp$0 + ); + JSCompiler_inline_result = !0; + } else + dispatchConfig.registrationName + ? (publishRegistrationName( + dispatchConfig.registrationName, + pluginModule$jscomp$0, + eventName$jscomp$0 + ), + (JSCompiler_inline_result = !0)) + : (JSCompiler_inline_result = !1); + if (!JSCompiler_inline_result) + throw ReactError( + "EventPluginRegistry: Failed to publish event `" + + eventName + + "` for plugin `" + + pluginName + + "`." + ); + } + } + } +} +function publishRegistrationName(registrationName, pluginModule) { + if (registrationNameModules[registrationName]) + throw ReactError( + "EventPluginHub: More than one plugin attempted to publish the same registration name, `" + + registrationName + + "`." + ); + registrationNameModules[registrationName] = pluginModule; +} +var plugins = [], + eventNameDispatchConfigs = {}, + registrationNameModules = {}; +function invokeGuardedCallbackImpl(name, func, context, a, b, c, d, e, f) { + var funcArgs = Array.prototype.slice.call(arguments, 3); + try { + func.apply(context, funcArgs); + } catch (error) { + this.onError(error); + } +} +var hasError = !1, + caughtError = null, + hasRethrowError = !1, + rethrowError = null, + reporter = { + onError: function(error) { + hasError = !0; + caughtError = error; + } + }; +function invokeGuardedCallback(name, func, context, a, b, c, d, e, f) { + hasError = !1; + caughtError = null; + invokeGuardedCallbackImpl.apply(reporter, arguments); +} +function invokeGuardedCallbackAndCatchFirstError( + name, + func, + context, + a, + b, + c, + d, + e, + f +) { + invokeGuardedCallback.apply(this, arguments); + if (hasError) { + if (hasError) { + var error = caughtError; + hasError = !1; + caughtError = null; + } else + throw ReactError( + "clearCaughtError was called but no error was captured. This error is likely caused by a bug in React. Please file an issue." + ); + hasRethrowError || ((hasRethrowError = !0), (rethrowError = error)); + } +} +var getFiberCurrentPropsFromNode = null, + getInstanceFromNode = null, + getNodeFromInstance = null; +function executeDispatch(event, listener, inst) { + var type = event.type || "unknown-event"; + event.currentTarget = getNodeFromInstance(inst); + invokeGuardedCallbackAndCatchFirstError(type, listener, void 0, event); + event.currentTarget = null; +} +function executeDirectDispatch(event) { + var dispatchListener = event._dispatchListeners, + dispatchInstance = event._dispatchInstances; + if (Array.isArray(dispatchListener)) + throw ReactError("executeDirectDispatch(...): Invalid `event`."); + event.currentTarget = dispatchListener + ? getNodeFromInstance(dispatchInstance) + : null; + dispatchListener = dispatchListener ? dispatchListener(event) : null; + event.currentTarget = null; + event._dispatchListeners = null; + event._dispatchInstances = null; + return dispatchListener; +} +function accumulateInto(current, next) { + if (null == next) + throw ReactError( + "accumulateInto(...): Accumulated items must not be null or undefined." + ); + if (null == current) return next; + if (Array.isArray(current)) { + if (Array.isArray(next)) return current.push.apply(current, next), current; + current.push(next); + return current; + } + return Array.isArray(next) ? [current].concat(next) : [current, next]; +} +function forEachAccumulated(arr, cb, scope) { + Array.isArray(arr) ? arr.forEach(cb, scope) : arr && cb.call(scope, arr); +} +var eventQueue = null; +function executeDispatchesAndReleaseTopLevel(e) { + if (e) { + var dispatchListeners = e._dispatchListeners, + dispatchInstances = e._dispatchInstances; + if (Array.isArray(dispatchListeners)) + for ( + var i = 0; + i < dispatchListeners.length && !e.isPropagationStopped(); + i++ + ) + executeDispatch(e, dispatchListeners[i], dispatchInstances[i]); + else + dispatchListeners && + executeDispatch(e, dispatchListeners, dispatchInstances); + e._dispatchListeners = null; + e._dispatchInstances = null; + e.isPersistent() || e.constructor.release(e); + } +} +var injection = { + injectEventPluginOrder: function(injectedEventPluginOrder) { + if (eventPluginOrder) + throw ReactError( + "EventPluginRegistry: Cannot inject event plugin ordering more than once. You are likely trying to load more than one copy of React." + ); + eventPluginOrder = Array.prototype.slice.call(injectedEventPluginOrder); + recomputePluginOrdering(); + }, + injectEventPluginsByName: function(injectedNamesToPlugins) { + var isOrderingDirty = !1, + pluginName; + for (pluginName in injectedNamesToPlugins) + if (injectedNamesToPlugins.hasOwnProperty(pluginName)) { + var pluginModule = injectedNamesToPlugins[pluginName]; + if ( + !namesToPlugins.hasOwnProperty(pluginName) || + namesToPlugins[pluginName] !== pluginModule + ) { + if (namesToPlugins[pluginName]) + throw ReactError( + "EventPluginRegistry: Cannot inject two different event plugins using the same name, `" + + pluginName + + "`." + ); + namesToPlugins[pluginName] = pluginModule; + isOrderingDirty = !0; + } + } + isOrderingDirty && recomputePluginOrdering(); + } +}; +function getListener(inst, registrationName) { + var listener = inst.stateNode; + if (!listener) return null; + var props = getFiberCurrentPropsFromNode(listener); + if (!props) return null; + listener = props[registrationName]; + a: switch (registrationName) { + case "onClick": + case "onClickCapture": + case "onDoubleClick": + case "onDoubleClickCapture": + case "onMouseDown": + case "onMouseDownCapture": + case "onMouseMove": + case "onMouseMoveCapture": + case "onMouseUp": + case "onMouseUpCapture": + (props = !props.disabled) || + ((inst = inst.type), + (props = !( + "button" === inst || + "input" === inst || + "select" === inst || + "textarea" === inst + ))); + inst = !props; + break a; + default: + inst = !1; + } + if (inst) return null; + if (listener && "function" !== typeof listener) + throw ReactError( + "Expected `" + + registrationName + + "` listener to be a function, instead got a value of `" + + typeof listener + + "` type." + ); + return listener; +} +function getParent(inst) { + do inst = inst.return; + while (inst && 5 !== inst.tag); + return inst ? inst : null; +} +function traverseTwoPhase(inst, fn, arg) { + for (var path = []; inst; ) path.push(inst), (inst = getParent(inst)); + for (inst = path.length; 0 < inst--; ) fn(path[inst], "captured", arg); + for (inst = 0; inst < path.length; inst++) fn(path[inst], "bubbled", arg); +} +function accumulateDirectionalDispatches(inst, phase, event) { + if ( + (phase = getListener( + inst, + event.dispatchConfig.phasedRegistrationNames[phase] + )) + ) + (event._dispatchListeners = accumulateInto( + event._dispatchListeners, + phase + )), + (event._dispatchInstances = accumulateInto( + event._dispatchInstances, + inst + )); +} +function accumulateTwoPhaseDispatchesSingle(event) { + event && + event.dispatchConfig.phasedRegistrationNames && + traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event); +} +function accumulateTwoPhaseDispatchesSingleSkipTarget(event) { + if (event && event.dispatchConfig.phasedRegistrationNames) { + var targetInst = event._targetInst; + targetInst = targetInst ? getParent(targetInst) : null; + traverseTwoPhase(targetInst, accumulateDirectionalDispatches, event); + } +} +function accumulateDirectDispatchesSingle(event) { + if (event && event.dispatchConfig.registrationName) { + var inst = event._targetInst; + if (inst && event && event.dispatchConfig.registrationName) { + var listener = getListener(inst, event.dispatchConfig.registrationName); + listener && + ((event._dispatchListeners = accumulateInto( + event._dispatchListeners, + listener + )), + (event._dispatchInstances = accumulateInto( + event._dispatchInstances, + inst + ))); + } + } +} +function functionThatReturnsTrue() { + return !0; +} +function functionThatReturnsFalse() { + return !1; +} +function SyntheticEvent( + dispatchConfig, + targetInst, + nativeEvent, + nativeEventTarget +) { + this.dispatchConfig = dispatchConfig; + this._targetInst = targetInst; + this.nativeEvent = nativeEvent; + dispatchConfig = this.constructor.Interface; + for (var propName in dispatchConfig) + dispatchConfig.hasOwnProperty(propName) && + ((targetInst = dispatchConfig[propName]) + ? (this[propName] = targetInst(nativeEvent)) + : "target" === propName + ? (this.target = nativeEventTarget) + : (this[propName] = nativeEvent[propName])); + this.isDefaultPrevented = (null != nativeEvent.defaultPrevented + ? nativeEvent.defaultPrevented + : !1 === nativeEvent.returnValue) + ? functionThatReturnsTrue + : functionThatReturnsFalse; + this.isPropagationStopped = functionThatReturnsFalse; + return this; +} +Object.assign(SyntheticEvent.prototype, { + preventDefault: function() { + this.defaultPrevented = !0; + var event = this.nativeEvent; + event && + (event.preventDefault + ? event.preventDefault() + : "unknown" !== typeof event.returnValue && (event.returnValue = !1), + (this.isDefaultPrevented = functionThatReturnsTrue)); + }, + stopPropagation: function() { + var event = this.nativeEvent; + event && + (event.stopPropagation + ? event.stopPropagation() + : "unknown" !== typeof event.cancelBubble && (event.cancelBubble = !0), + (this.isPropagationStopped = functionThatReturnsTrue)); + }, + persist: function() { + this.isPersistent = functionThatReturnsTrue; + }, + isPersistent: functionThatReturnsFalse, + destructor: function() { + var Interface = this.constructor.Interface, + propName; + for (propName in Interface) this[propName] = null; + this.nativeEvent = this._targetInst = this.dispatchConfig = null; + this.isPropagationStopped = this.isDefaultPrevented = functionThatReturnsFalse; + this._dispatchInstances = this._dispatchListeners = null; + } +}); +SyntheticEvent.Interface = { + type: null, + target: null, + currentTarget: function() { + return null; + }, + eventPhase: null, + bubbles: null, + cancelable: null, + timeStamp: function(event) { + return event.timeStamp || Date.now(); + }, + defaultPrevented: null, + isTrusted: null +}; +SyntheticEvent.extend = function(Interface) { + function E() {} + function Class() { + return Super.apply(this, arguments); + } + var Super = this; + E.prototype = Super.prototype; + var prototype = new E(); + Object.assign(prototype, Class.prototype); + Class.prototype = prototype; + Class.prototype.constructor = Class; + Class.Interface = Object.assign({}, Super.Interface, Interface); + Class.extend = Super.extend; + addEventPoolingTo(Class); + return Class; +}; +addEventPoolingTo(SyntheticEvent); +function getPooledEvent(dispatchConfig, targetInst, nativeEvent, nativeInst) { + if (this.eventPool.length) { + var instance = this.eventPool.pop(); + this.call(instance, dispatchConfig, targetInst, nativeEvent, nativeInst); + return instance; + } + return new this(dispatchConfig, targetInst, nativeEvent, nativeInst); +} +function releasePooledEvent(event) { + if (!(event instanceof this)) + throw ReactError( + "Trying to release an event instance into a pool of a different type." + ); + event.destructor(); + 10 > this.eventPool.length && this.eventPool.push(event); +} +function addEventPoolingTo(EventConstructor) { + EventConstructor.eventPool = []; + EventConstructor.getPooled = getPooledEvent; + EventConstructor.release = releasePooledEvent; +} +var ResponderSyntheticEvent = SyntheticEvent.extend({ + touchHistory: function() { + return null; + } +}); +function isStartish(topLevelType) { + return "topTouchStart" === topLevelType; +} +function isMoveish(topLevelType) { + return "topTouchMove" === topLevelType; +} +var startDependencies = ["topTouchStart"], + moveDependencies = ["topTouchMove"], + endDependencies = ["topTouchCancel", "topTouchEnd"], + touchBank = [], + touchHistory = { + touchBank: touchBank, + numberActiveTouches: 0, + indexOfSingleActiveTouch: -1, + mostRecentTimeStamp: 0 + }; +function timestampForTouch(touch) { + return touch.timeStamp || touch.timestamp; +} +function getTouchIdentifier(_ref) { + _ref = _ref.identifier; + if (null == _ref) throw ReactError("Touch object is missing identifier."); + return _ref; +} +function recordTouchStart(touch) { + var identifier = getTouchIdentifier(touch), + touchRecord = touchBank[identifier]; + touchRecord + ? ((touchRecord.touchActive = !0), + (touchRecord.startPageX = touch.pageX), + (touchRecord.startPageY = touch.pageY), + (touchRecord.startTimeStamp = timestampForTouch(touch)), + (touchRecord.currentPageX = touch.pageX), + (touchRecord.currentPageY = touch.pageY), + (touchRecord.currentTimeStamp = timestampForTouch(touch)), + (touchRecord.previousPageX = touch.pageX), + (touchRecord.previousPageY = touch.pageY), + (touchRecord.previousTimeStamp = timestampForTouch(touch))) + : ((touchRecord = { + touchActive: !0, + startPageX: touch.pageX, + startPageY: touch.pageY, + startTimeStamp: timestampForTouch(touch), + currentPageX: touch.pageX, + currentPageY: touch.pageY, + currentTimeStamp: timestampForTouch(touch), + previousPageX: touch.pageX, + previousPageY: touch.pageY, + previousTimeStamp: timestampForTouch(touch) + }), + (touchBank[identifier] = touchRecord)); + touchHistory.mostRecentTimeStamp = timestampForTouch(touch); +} +function recordTouchMove(touch) { + var touchRecord = touchBank[getTouchIdentifier(touch)]; + touchRecord + ? ((touchRecord.touchActive = !0), + (touchRecord.previousPageX = touchRecord.currentPageX), + (touchRecord.previousPageY = touchRecord.currentPageY), + (touchRecord.previousTimeStamp = touchRecord.currentTimeStamp), + (touchRecord.currentPageX = touch.pageX), + (touchRecord.currentPageY = touch.pageY), + (touchRecord.currentTimeStamp = timestampForTouch(touch)), + (touchHistory.mostRecentTimeStamp = timestampForTouch(touch))) + : console.error( + "Cannot record touch move without a touch start.\nTouch Move: %s\n", + "Touch Bank: %s", + printTouch(touch), + printTouchBank() + ); +} +function recordTouchEnd(touch) { + var touchRecord = touchBank[getTouchIdentifier(touch)]; + touchRecord + ? ((touchRecord.touchActive = !1), + (touchRecord.previousPageX = touchRecord.currentPageX), + (touchRecord.previousPageY = touchRecord.currentPageY), + (touchRecord.previousTimeStamp = touchRecord.currentTimeStamp), + (touchRecord.currentPageX = touch.pageX), + (touchRecord.currentPageY = touch.pageY), + (touchRecord.currentTimeStamp = timestampForTouch(touch)), + (touchHistory.mostRecentTimeStamp = timestampForTouch(touch))) + : console.error( + "Cannot record touch end without a touch start.\nTouch End: %s\n", + "Touch Bank: %s", + printTouch(touch), + printTouchBank() + ); +} +function printTouch(touch) { + return JSON.stringify({ + identifier: touch.identifier, + pageX: touch.pageX, + pageY: touch.pageY, + timestamp: timestampForTouch(touch) + }); +} +function printTouchBank() { + var printed = JSON.stringify(touchBank.slice(0, 20)); + 20 < touchBank.length && + (printed += " (original size: " + touchBank.length + ")"); + return printed; +} +var ResponderTouchHistoryStore = { + recordTouchTrack: function(topLevelType, nativeEvent) { + if (isMoveish(topLevelType)) + nativeEvent.changedTouches.forEach(recordTouchMove); + else if (isStartish(topLevelType)) + nativeEvent.changedTouches.forEach(recordTouchStart), + (touchHistory.numberActiveTouches = nativeEvent.touches.length), + 1 === touchHistory.numberActiveTouches && + (touchHistory.indexOfSingleActiveTouch = + nativeEvent.touches[0].identifier); + else if ( + "topTouchEnd" === topLevelType || + "topTouchCancel" === topLevelType + ) + if ( + (nativeEvent.changedTouches.forEach(recordTouchEnd), + (touchHistory.numberActiveTouches = nativeEvent.touches.length), + 1 === touchHistory.numberActiveTouches) + ) + for (topLevelType = 0; topLevelType < touchBank.length; topLevelType++) + if ( + ((nativeEvent = touchBank[topLevelType]), + null != nativeEvent && nativeEvent.touchActive) + ) { + touchHistory.indexOfSingleActiveTouch = topLevelType; + break; + } + }, + touchHistory: touchHistory +}; +function accumulate(current, next) { + if (null == next) + throw ReactError( + "accumulate(...): Accumulated items must not be null or undefined." + ); + return null == current + ? next + : Array.isArray(current) + ? current.concat(next) + : Array.isArray(next) + ? [current].concat(next) + : [current, next]; +} +var responderInst = null, + trackedTouchCount = 0; +function changeResponder(nextResponderInst, blockHostResponder) { + var oldResponderInst = responderInst; + responderInst = nextResponderInst; + if (null !== ResponderEventPlugin.GlobalResponderHandler) + ResponderEventPlugin.GlobalResponderHandler.onChange( + oldResponderInst, + nextResponderInst, + blockHostResponder + ); +} +var eventTypes = { + startShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onStartShouldSetResponder", + captured: "onStartShouldSetResponderCapture" + }, + dependencies: startDependencies + }, + scrollShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onScrollShouldSetResponder", + captured: "onScrollShouldSetResponderCapture" + }, + dependencies: ["topScroll"] + }, + selectionChangeShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onSelectionChangeShouldSetResponder", + captured: "onSelectionChangeShouldSetResponderCapture" + }, + dependencies: ["topSelectionChange"] + }, + moveShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onMoveShouldSetResponder", + captured: "onMoveShouldSetResponderCapture" + }, + dependencies: moveDependencies + }, + responderStart: { + registrationName: "onResponderStart", + dependencies: startDependencies + }, + responderMove: { + registrationName: "onResponderMove", + dependencies: moveDependencies + }, + responderEnd: { + registrationName: "onResponderEnd", + dependencies: endDependencies + }, + responderRelease: { + registrationName: "onResponderRelease", + dependencies: endDependencies + }, + responderTerminationRequest: { + registrationName: "onResponderTerminationRequest", + dependencies: [] + }, + responderGrant: { registrationName: "onResponderGrant", dependencies: [] }, + responderReject: { + registrationName: "onResponderReject", + dependencies: [] + }, + responderTerminate: { + registrationName: "onResponderTerminate", + dependencies: [] + } + }, + ResponderEventPlugin = { + _getResponder: function() { + return responderInst; + }, + eventTypes: eventTypes, + extractEvents: function( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ) { + if (isStartish(topLevelType)) trackedTouchCount += 1; + else if ( + "topTouchEnd" === topLevelType || + "topTouchCancel" === topLevelType + ) + if (0 <= trackedTouchCount) --trackedTouchCount; + else + return ( + console.error( + "Ended a touch event which was not counted in `trackedTouchCount`." + ), + null + ); + ResponderTouchHistoryStore.recordTouchTrack(topLevelType, nativeEvent); + if ( + targetInst && + (("topScroll" === topLevelType && !nativeEvent.responderIgnoreScroll) || + (0 < trackedTouchCount && "topSelectionChange" === topLevelType) || + isStartish(topLevelType) || + isMoveish(topLevelType)) + ) { + var JSCompiler_temp = isStartish(topLevelType) + ? eventTypes.startShouldSetResponder + : isMoveish(topLevelType) + ? eventTypes.moveShouldSetResponder + : "topSelectionChange" === topLevelType + ? eventTypes.selectionChangeShouldSetResponder + : eventTypes.scrollShouldSetResponder; + if (responderInst) + b: { + var JSCompiler_temp$jscomp$0 = responderInst; + for ( + var depthA = 0, tempA = JSCompiler_temp$jscomp$0; + tempA; + tempA = getParent(tempA) + ) + depthA++; + tempA = 0; + for (var tempB = targetInst; tempB; tempB = getParent(tempB)) + tempA++; + for (; 0 < depthA - tempA; ) + (JSCompiler_temp$jscomp$0 = getParent(JSCompiler_temp$jscomp$0)), + depthA--; + for (; 0 < tempA - depthA; ) + (targetInst = getParent(targetInst)), tempA--; + for (; depthA--; ) { + if ( + JSCompiler_temp$jscomp$0 === targetInst || + JSCompiler_temp$jscomp$0 === targetInst.alternate + ) + break b; + JSCompiler_temp$jscomp$0 = getParent(JSCompiler_temp$jscomp$0); + targetInst = getParent(targetInst); + } + JSCompiler_temp$jscomp$0 = null; + } + else JSCompiler_temp$jscomp$0 = targetInst; + targetInst = JSCompiler_temp$jscomp$0 === responderInst; + JSCompiler_temp$jscomp$0 = ResponderSyntheticEvent.getPooled( + JSCompiler_temp, + JSCompiler_temp$jscomp$0, + nativeEvent, + nativeEventTarget + ); + JSCompiler_temp$jscomp$0.touchHistory = + ResponderTouchHistoryStore.touchHistory; + targetInst + ? forEachAccumulated( + JSCompiler_temp$jscomp$0, + accumulateTwoPhaseDispatchesSingleSkipTarget + ) + : forEachAccumulated( + JSCompiler_temp$jscomp$0, + accumulateTwoPhaseDispatchesSingle + ); + b: { + JSCompiler_temp = JSCompiler_temp$jscomp$0._dispatchListeners; + targetInst = JSCompiler_temp$jscomp$0._dispatchInstances; + if (Array.isArray(JSCompiler_temp)) + for ( + depthA = 0; + depthA < JSCompiler_temp.length && + !JSCompiler_temp$jscomp$0.isPropagationStopped(); + depthA++ + ) { + if ( + JSCompiler_temp[depthA]( + JSCompiler_temp$jscomp$0, + targetInst[depthA] + ) + ) { + JSCompiler_temp = targetInst[depthA]; + break b; + } + } + else if ( + JSCompiler_temp && + JSCompiler_temp(JSCompiler_temp$jscomp$0, targetInst) + ) { + JSCompiler_temp = targetInst; + break b; + } + JSCompiler_temp = null; + } + JSCompiler_temp$jscomp$0._dispatchInstances = null; + JSCompiler_temp$jscomp$0._dispatchListeners = null; + JSCompiler_temp$jscomp$0.isPersistent() || + JSCompiler_temp$jscomp$0.constructor.release( + JSCompiler_temp$jscomp$0 + ); + JSCompiler_temp && JSCompiler_temp !== responderInst + ? ((JSCompiler_temp$jscomp$0 = void 0), + (targetInst = ResponderSyntheticEvent.getPooled( + eventTypes.responderGrant, + JSCompiler_temp, + nativeEvent, + nativeEventTarget + )), + (targetInst.touchHistory = ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(targetInst, accumulateDirectDispatchesSingle), + (depthA = !0 === executeDirectDispatch(targetInst)), + responderInst + ? ((tempA = ResponderSyntheticEvent.getPooled( + eventTypes.responderTerminationRequest, + responderInst, + nativeEvent, + nativeEventTarget + )), + (tempA.touchHistory = ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(tempA, accumulateDirectDispatchesSingle), + (tempB = + !tempA._dispatchListeners || executeDirectDispatch(tempA)), + tempA.isPersistent() || tempA.constructor.release(tempA), + tempB + ? ((tempA = ResponderSyntheticEvent.getPooled( + eventTypes.responderTerminate, + responderInst, + nativeEvent, + nativeEventTarget + )), + (tempA.touchHistory = + ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(tempA, accumulateDirectDispatchesSingle), + (JSCompiler_temp$jscomp$0 = accumulate( + JSCompiler_temp$jscomp$0, + [targetInst, tempA] + )), + changeResponder(JSCompiler_temp, depthA)) + : ((JSCompiler_temp = ResponderSyntheticEvent.getPooled( + eventTypes.responderReject, + JSCompiler_temp, + nativeEvent, + nativeEventTarget + )), + (JSCompiler_temp.touchHistory = + ResponderTouchHistoryStore.touchHistory), + forEachAccumulated( + JSCompiler_temp, + accumulateDirectDispatchesSingle + ), + (JSCompiler_temp$jscomp$0 = accumulate( + JSCompiler_temp$jscomp$0, + JSCompiler_temp + )))) + : ((JSCompiler_temp$jscomp$0 = accumulate( + JSCompiler_temp$jscomp$0, + targetInst + )), + changeResponder(JSCompiler_temp, depthA)), + (JSCompiler_temp = JSCompiler_temp$jscomp$0)) + : (JSCompiler_temp = null); + } else JSCompiler_temp = null; + JSCompiler_temp$jscomp$0 = responderInst && isStartish(topLevelType); + targetInst = responderInst && isMoveish(topLevelType); + depthA = + responderInst && + ("topTouchEnd" === topLevelType || "topTouchCancel" === topLevelType); + if ( + (JSCompiler_temp$jscomp$0 = JSCompiler_temp$jscomp$0 + ? eventTypes.responderStart + : targetInst + ? eventTypes.responderMove + : depthA + ? eventTypes.responderEnd + : null) + ) + (JSCompiler_temp$jscomp$0 = ResponderSyntheticEvent.getPooled( + JSCompiler_temp$jscomp$0, + responderInst, + nativeEvent, + nativeEventTarget + )), + (JSCompiler_temp$jscomp$0.touchHistory = + ResponderTouchHistoryStore.touchHistory), + forEachAccumulated( + JSCompiler_temp$jscomp$0, + accumulateDirectDispatchesSingle + ), + (JSCompiler_temp = accumulate( + JSCompiler_temp, + JSCompiler_temp$jscomp$0 + )); + JSCompiler_temp$jscomp$0 = + responderInst && "topTouchCancel" === topLevelType; + if ( + (topLevelType = + responderInst && + !JSCompiler_temp$jscomp$0 && + ("topTouchEnd" === topLevelType || "topTouchCancel" === topLevelType)) + ) + a: { + if ((topLevelType = nativeEvent.touches) && 0 !== topLevelType.length) + for (targetInst = 0; targetInst < topLevelType.length; targetInst++) + if ( + ((depthA = topLevelType[targetInst].target), + null !== depthA && void 0 !== depthA && 0 !== depthA) + ) { + tempA = getInstanceFromNode(depthA); + b: { + for (depthA = responderInst; tempA; ) { + if (depthA === tempA || depthA === tempA.alternate) { + depthA = !0; + break b; + } + tempA = getParent(tempA); + } + depthA = !1; + } + if (depthA) { + topLevelType = !1; + break a; + } + } + topLevelType = !0; + } + if ( + (topLevelType = JSCompiler_temp$jscomp$0 + ? eventTypes.responderTerminate + : topLevelType + ? eventTypes.responderRelease + : null) + ) + (nativeEvent = ResponderSyntheticEvent.getPooled( + topLevelType, + responderInst, + nativeEvent, + nativeEventTarget + )), + (nativeEvent.touchHistory = ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(nativeEvent, accumulateDirectDispatchesSingle), + (JSCompiler_temp = accumulate(JSCompiler_temp, nativeEvent)), + changeResponder(null); + return JSCompiler_temp; + }, + GlobalResponderHandler: null, + injection: { + injectGlobalResponderHandler: function(GlobalResponderHandler) { + ResponderEventPlugin.GlobalResponderHandler = GlobalResponderHandler; + } + } + }, + customBubblingEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customBubblingEventTypes, + customDirectEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customDirectEventTypes, + ReactNativeBridgeEventPlugin = { + eventTypes: + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes, + extractEvents: function( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ) { + if (null == targetInst) return null; + var bubbleDispatchConfig = customBubblingEventTypes[topLevelType], + directDispatchConfig = customDirectEventTypes[topLevelType]; + if (!bubbleDispatchConfig && !directDispatchConfig) + throw ReactError( + 'Unsupported top level event type "' + topLevelType + '" dispatched' + ); + topLevelType = SyntheticEvent.getPooled( + bubbleDispatchConfig || directDispatchConfig, + targetInst, + nativeEvent, + nativeEventTarget + ); + if (bubbleDispatchConfig) + forEachAccumulated(topLevelType, accumulateTwoPhaseDispatchesSingle); + else if (directDispatchConfig) + forEachAccumulated(topLevelType, accumulateDirectDispatchesSingle); + else return null; + return topLevelType; + } + }; +injection.injectEventPluginOrder([ + "ResponderEventPlugin", + "ReactNativeBridgeEventPlugin" +]); +injection.injectEventPluginsByName({ + ResponderEventPlugin: ResponderEventPlugin, + ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin +}); +function getInstanceFromInstance(instanceHandle) { + return instanceHandle; +} +getFiberCurrentPropsFromNode = function(inst) { + return inst.canonical.currentProps; +}; +getInstanceFromNode = getInstanceFromInstance; +getNodeFromInstance = function(inst) { + inst = inst.stateNode.canonical._nativeTag; + if (!inst) throw ReactError("All native instances should have a tag."); + return inst; +}; +ResponderEventPlugin.injection.injectGlobalResponderHandler({ + onChange: function(from, to, blockNativeResponder) { + null !== to + ? ReactNativePrivateInterface.UIManager.setJSResponder( + to.stateNode.canonical._nativeTag, + blockNativeResponder + ) + : ReactNativePrivateInterface.UIManager.clearJSResponder(); + } +}); +var ReactSharedInternals = + React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; +ReactSharedInternals.hasOwnProperty("ReactCurrentDispatcher") || + (ReactSharedInternals.ReactCurrentDispatcher = { current: null }); +var hasSymbol = "function" === typeof Symbol && Symbol.for, + REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for("react.element") : 60103, + REACT_PORTAL_TYPE = hasSymbol ? Symbol.for("react.portal") : 60106, + REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for("react.fragment") : 60107, + REACT_STRICT_MODE_TYPE = hasSymbol ? Symbol.for("react.strict_mode") : 60108, + REACT_PROFILER_TYPE = hasSymbol ? Symbol.for("react.profiler") : 60114, + REACT_PROVIDER_TYPE = hasSymbol ? Symbol.for("react.provider") : 60109, + REACT_CONTEXT_TYPE = hasSymbol ? Symbol.for("react.context") : 60110, + REACT_CONCURRENT_MODE_TYPE = hasSymbol + ? Symbol.for("react.concurrent_mode") + : 60111, + REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for("react.forward_ref") : 60112, + REACT_SUSPENSE_TYPE = hasSymbol ? Symbol.for("react.suspense") : 60113, + REACT_MEMO_TYPE = hasSymbol ? Symbol.for("react.memo") : 60115, + REACT_LAZY_TYPE = hasSymbol ? Symbol.for("react.lazy") : 60116; +hasSymbol && Symbol.for("react.event_component"); +hasSymbol && Symbol.for("react.event_target"); +hasSymbol && Symbol.for("react.event_target.touch_hit"); +var MAYBE_ITERATOR_SYMBOL = "function" === typeof Symbol && Symbol.iterator; +function getIteratorFn(maybeIterable) { + if (null === maybeIterable || "object" !== typeof maybeIterable) return null; + maybeIterable = + (MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL]) || + maybeIterable["@@iterator"]; + return "function" === typeof maybeIterable ? maybeIterable : null; +} +require("../shims/ReactFeatureFlags"); +function getComponentName(type) { + if (null == type) return null; + if ("function" === typeof type) return type.displayName || type.name || null; + if ("string" === typeof type) return type; + switch (type) { + case REACT_CONCURRENT_MODE_TYPE: + return "ConcurrentMode"; + case REACT_FRAGMENT_TYPE: + return "Fragment"; + case REACT_PORTAL_TYPE: + return "Portal"; + case REACT_PROFILER_TYPE: + return "Profiler"; + case REACT_STRICT_MODE_TYPE: + return "StrictMode"; + case REACT_SUSPENSE_TYPE: + return "Suspense"; + } + if ("object" === typeof type) + switch (type.$$typeof) { + case REACT_CONTEXT_TYPE: + return "Context.Consumer"; + case REACT_PROVIDER_TYPE: + return "Context.Provider"; + case REACT_FORWARD_REF_TYPE: + var innerType = type.render; + innerType = innerType.displayName || innerType.name || ""; + return ( + type.displayName || + ("" !== innerType ? "ForwardRef(" + innerType + ")" : "ForwardRef") + ); + case REACT_MEMO_TYPE: + return getComponentName(type.type); + case REACT_LAZY_TYPE: + if ((type = 1 === type._status ? type._result : null)) + return getComponentName(type); + } + return null; +} +function isFiberMountedImpl(fiber) { + var node = fiber; + if (fiber.alternate) for (; node.return; ) node = node.return; + else { + if (0 !== (node.effectTag & 2)) return 1; + for (; node.return; ) + if (((node = node.return), 0 !== (node.effectTag & 2))) return 1; + } + return 3 === node.tag ? 2 : 3; +} +function assertIsMounted(fiber) { + if (2 !== isFiberMountedImpl(fiber)) + throw ReactError("Unable to find node on an unmounted component."); +} +function findCurrentFiberUsingSlowPath(fiber) { + var alternate = fiber.alternate; + if (!alternate) { + alternate = isFiberMountedImpl(fiber); + if (3 === alternate) + throw ReactError("Unable to find node on an unmounted component."); + return 1 === alternate ? null : fiber; + } + for (var a = fiber, b = alternate; ; ) { + var parentA = a.return; + if (null === parentA) break; + var parentB = parentA.alternate; + if (null === parentB) { + b = parentA.return; + if (null !== b) { + a = b; + continue; + } + break; + } + if (parentA.child === parentB.child) { + for (parentB = parentA.child; parentB; ) { + if (parentB === a) return assertIsMounted(parentA), fiber; + if (parentB === b) return assertIsMounted(parentA), alternate; + parentB = parentB.sibling; + } + throw ReactError("Unable to find node on an unmounted component."); + } + if (a.return !== b.return) (a = parentA), (b = parentB); + else { + for (var didFindChild = !1, _child = parentA.child; _child; ) { + if (_child === a) { + didFindChild = !0; + a = parentA; + b = parentB; + break; + } + if (_child === b) { + didFindChild = !0; + b = parentA; + a = parentB; + break; + } + _child = _child.sibling; + } + if (!didFindChild) { + for (_child = parentB.child; _child; ) { + if (_child === a) { + didFindChild = !0; + a = parentB; + b = parentA; + break; + } + if (_child === b) { + didFindChild = !0; + b = parentB; + a = parentA; + break; + } + _child = _child.sibling; + } + if (!didFindChild) + throw ReactError( + "Child was not found in either parent set. This indicates a bug in React related to the return pointer. Please file an issue." + ); + } + } + if (a.alternate !== b) + throw ReactError( + "Return fibers should always be each others' alternates. This error is likely caused by a bug in React. Please file an issue." + ); + } + if (3 !== a.tag) + throw ReactError("Unable to find node on an unmounted component."); + return a.stateNode.current === a ? fiber : alternate; +} +function findCurrentHostFiber(parent) { + parent = findCurrentFiberUsingSlowPath(parent); + if (!parent) return null; + for (var node = parent; ; ) { + if (5 === node.tag || 6 === node.tag) return node; + if (node.child) (node.child.return = node), (node = node.child); + else { + if (node === parent) break; + for (; !node.sibling; ) { + if (!node.return || node.return === parent) return null; + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + } + return null; +} +function mountSafeCallback_NOT_REALLY_SAFE(context, callback) { + return function() { + if ( + callback && + ("boolean" !== typeof context.__isMounted || context.__isMounted) + ) + return callback.apply(context, arguments); + }; +} +var emptyObject = {}, + removedKeys = null, + removedKeyCount = 0; +function restoreDeletedValuesInNestedArray( + updatePayload, + node, + validAttributes +) { + if (Array.isArray(node)) + for (var i = node.length; i-- && 0 < removedKeyCount; ) + restoreDeletedValuesInNestedArray( + updatePayload, + node[i], + validAttributes + ); + else if (node && 0 < removedKeyCount) + for (i in removedKeys) + if (removedKeys[i]) { + var nextProp = node[i]; + if (void 0 !== nextProp) { + var attributeConfig = validAttributes[i]; + if (attributeConfig) { + "function" === typeof nextProp && (nextProp = !0); + "undefined" === typeof nextProp && (nextProp = null); + if ("object" !== typeof attributeConfig) + updatePayload[i] = nextProp; + else if ( + "function" === typeof attributeConfig.diff || + "function" === typeof attributeConfig.process + ) + (nextProp = + "function" === typeof attributeConfig.process + ? attributeConfig.process(nextProp) + : nextProp), + (updatePayload[i] = nextProp); + removedKeys[i] = !1; + removedKeyCount--; + } + } + } +} +function diffNestedProperty( + updatePayload, + prevProp, + nextProp, + validAttributes +) { + if (!updatePayload && prevProp === nextProp) return updatePayload; + if (!prevProp || !nextProp) + return nextProp + ? addNestedProperty(updatePayload, nextProp, validAttributes) + : prevProp + ? clearNestedProperty(updatePayload, prevProp, validAttributes) + : updatePayload; + if (!Array.isArray(prevProp) && !Array.isArray(nextProp)) + return diffProperties(updatePayload, prevProp, nextProp, validAttributes); + if (Array.isArray(prevProp) && Array.isArray(nextProp)) { + var minLength = + prevProp.length < nextProp.length ? prevProp.length : nextProp.length, + i; + for (i = 0; i < minLength; i++) + updatePayload = diffNestedProperty( + updatePayload, + prevProp[i], + nextProp[i], + validAttributes + ); + for (; i < prevProp.length; i++) + updatePayload = clearNestedProperty( + updatePayload, + prevProp[i], + validAttributes + ); + for (; i < nextProp.length; i++) + updatePayload = addNestedProperty( + updatePayload, + nextProp[i], + validAttributes + ); + return updatePayload; + } + return Array.isArray(prevProp) + ? diffProperties( + updatePayload, + ReactNativePrivateInterface.flattenStyle(prevProp), + nextProp, + validAttributes + ) + : diffProperties( + updatePayload, + prevProp, + ReactNativePrivateInterface.flattenStyle(nextProp), + validAttributes + ); +} +function addNestedProperty(updatePayload, nextProp, validAttributes) { + if (!nextProp) return updatePayload; + if (!Array.isArray(nextProp)) + return diffProperties( + updatePayload, + emptyObject, + nextProp, + validAttributes + ); + for (var i = 0; i < nextProp.length; i++) + updatePayload = addNestedProperty( + updatePayload, + nextProp[i], + validAttributes + ); + return updatePayload; +} +function clearNestedProperty(updatePayload, prevProp, validAttributes) { + if (!prevProp) return updatePayload; + if (!Array.isArray(prevProp)) + return diffProperties( + updatePayload, + prevProp, + emptyObject, + validAttributes + ); + for (var i = 0; i < prevProp.length; i++) + updatePayload = clearNestedProperty( + updatePayload, + prevProp[i], + validAttributes + ); + return updatePayload; +} +function diffProperties(updatePayload, prevProps, nextProps, validAttributes) { + var attributeConfig, propKey; + for (propKey in nextProps) + if ((attributeConfig = validAttributes[propKey])) { + var prevProp = prevProps[propKey]; + var nextProp = nextProps[propKey]; + "function" === typeof nextProp && + ((nextProp = !0), "function" === typeof prevProp && (prevProp = !0)); + "undefined" === typeof nextProp && + ((nextProp = null), + "undefined" === typeof prevProp && (prevProp = null)); + removedKeys && (removedKeys[propKey] = !1); + if (updatePayload && void 0 !== updatePayload[propKey]) + if ("object" !== typeof attributeConfig) + updatePayload[propKey] = nextProp; + else { + if ( + "function" === typeof attributeConfig.diff || + "function" === typeof attributeConfig.process + ) + (attributeConfig = + "function" === typeof attributeConfig.process + ? attributeConfig.process(nextProp) + : nextProp), + (updatePayload[propKey] = attributeConfig); + } + else if (prevProp !== nextProp) + if ("object" !== typeof attributeConfig) + ("object" !== typeof nextProp || + null === nextProp || + ReactNativePrivateInterface.deepDiffer(prevProp, nextProp)) && + ((updatePayload || (updatePayload = {}))[propKey] = nextProp); + else if ( + "function" === typeof attributeConfig.diff || + "function" === typeof attributeConfig.process + ) { + if ( + void 0 === prevProp || + ("function" === typeof attributeConfig.diff + ? attributeConfig.diff(prevProp, nextProp) + : "object" !== typeof nextProp || + null === nextProp || + ReactNativePrivateInterface.deepDiffer(prevProp, nextProp)) + ) + (attributeConfig = + "function" === typeof attributeConfig.process + ? attributeConfig.process(nextProp) + : nextProp), + ((updatePayload || (updatePayload = {}))[ + propKey + ] = attributeConfig); + } else + (removedKeys = null), + (removedKeyCount = 0), + (updatePayload = diffNestedProperty( + updatePayload, + prevProp, + nextProp, + attributeConfig + )), + 0 < removedKeyCount && + updatePayload && + (restoreDeletedValuesInNestedArray( + updatePayload, + nextProp, + attributeConfig + ), + (removedKeys = null)); + } + for (var _propKey in prevProps) + void 0 === nextProps[_propKey] && + (!(attributeConfig = validAttributes[_propKey]) || + (updatePayload && void 0 !== updatePayload[_propKey]) || + ((prevProp = prevProps[_propKey]), + void 0 !== prevProp && + ("object" !== typeof attributeConfig || + "function" === typeof attributeConfig.diff || + "function" === typeof attributeConfig.process + ? (((updatePayload || (updatePayload = {}))[_propKey] = null), + removedKeys || (removedKeys = {}), + removedKeys[_propKey] || + ((removedKeys[_propKey] = !0), removedKeyCount++)) + : (updatePayload = clearNestedProperty( + updatePayload, + prevProp, + attributeConfig + ))))); + return updatePayload; +} +var restoreTarget = null, + restoreQueue = null; +function restoreStateOfTarget(target) { + if (getInstanceFromNode(target)) + throw ReactError( + "setRestoreImplementation() needs to be called to handle a target for controlled events. This error is likely caused by a bug in React. Please file an issue." + ); +} +function _batchedUpdatesImpl(fn, bookkeeping) { + return fn(bookkeeping); +} +function _flushInteractiveUpdatesImpl() {} +var isBatching = !1; +function batchedUpdates(fn, bookkeeping) { + if (isBatching) return fn(bookkeeping); + isBatching = !0; + try { + return _batchedUpdatesImpl(fn, bookkeeping); + } finally { + if (((isBatching = !1), null !== restoreTarget || null !== restoreQueue)) + if ( + (_flushInteractiveUpdatesImpl(), + restoreTarget && + ((bookkeeping = restoreTarget), + (fn = restoreQueue), + (restoreQueue = restoreTarget = null), + restoreStateOfTarget(bookkeeping), + fn)) + ) + for (bookkeeping = 0; bookkeeping < fn.length; bookkeeping++) + restoreStateOfTarget(fn[bookkeeping]); + } +} +function dispatchEvent(target, topLevelType, nativeEvent) { + batchedUpdates(function() { + var events = nativeEvent.target; + for (var events$jscomp$0 = null, i = 0; i < plugins.length; i++) { + var possiblePlugin = plugins[i]; + possiblePlugin && + (possiblePlugin = possiblePlugin.extractEvents( + topLevelType, + target, + nativeEvent, + events + )) && + (events$jscomp$0 = accumulateInto(events$jscomp$0, possiblePlugin)); + } + events = events$jscomp$0; + null !== events && (eventQueue = accumulateInto(eventQueue, events)); + events = eventQueue; + eventQueue = null; + if (events) { + forEachAccumulated(events, executeDispatchesAndReleaseTopLevel); + if (eventQueue) + throw ReactError( + "processEventQueue(): Additional events were enqueued while processing an event queue. Support for this has not yet been implemented." + ); + if (hasRethrowError) + throw ((events = rethrowError), + (hasRethrowError = !1), + (rethrowError = null), + events); + } + }); +} +function shim$1() { + throw ReactError( + "The current renderer does not support hydration. This error is likely caused by a bug in React. Please file an issue." + ); +} +var _nativeFabricUIManage = nativeFabricUIManager, + createNode = _nativeFabricUIManage.createNode, + cloneNode = _nativeFabricUIManage.cloneNode, + cloneNodeWithNewChildren = _nativeFabricUIManage.cloneNodeWithNewChildren, + cloneNodeWithNewChildrenAndProps = + _nativeFabricUIManage.cloneNodeWithNewChildrenAndProps, + cloneNodeWithNewProps = _nativeFabricUIManage.cloneNodeWithNewProps, + createChildNodeSet = _nativeFabricUIManage.createChildSet, + appendChildNode = _nativeFabricUIManage.appendChild, + appendChildNodeToSet = _nativeFabricUIManage.appendChildToSet, + completeRoot = _nativeFabricUIManage.completeRoot, + registerEventHandler = _nativeFabricUIManage.registerEventHandler, + fabricMeasure = _nativeFabricUIManage.measure, + fabricMeasureInWindow = _nativeFabricUIManage.measureInWindow, + fabricMeasureLayout = _nativeFabricUIManage.measureLayout, + getViewConfigForType = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.get, + nextReactTag = 2; +registerEventHandler && registerEventHandler(dispatchEvent); +var ReactFabricHostComponent = (function() { + function ReactFabricHostComponent( + tag, + viewConfig, + props, + internalInstanceHandle + ) { + if (!(this instanceof ReactFabricHostComponent)) + throw new TypeError("Cannot call a class as a function"); + this._nativeTag = tag; + this.viewConfig = viewConfig; + this.currentProps = props; + this._internalInstanceHandle = internalInstanceHandle; + } + ReactFabricHostComponent.prototype.blur = function() { + ReactNativePrivateInterface.TextInputState.blurTextInput(this._nativeTag); + }; + ReactFabricHostComponent.prototype.focus = function() { + ReactNativePrivateInterface.TextInputState.focusTextInput(this._nativeTag); + }; + ReactFabricHostComponent.prototype.measure = function(callback) { + fabricMeasure( + this._internalInstanceHandle.stateNode.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + }; + ReactFabricHostComponent.prototype.measureInWindow = function(callback) { + fabricMeasureInWindow( + this._internalInstanceHandle.stateNode.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + }; + ReactFabricHostComponent.prototype.measureLayout = function( + relativeToNativeNode, + onSuccess, + onFail + ) { + "number" !== typeof relativeToNativeNode && + relativeToNativeNode instanceof ReactFabricHostComponent && + fabricMeasureLayout( + this._internalInstanceHandle.stateNode.node, + relativeToNativeNode._internalInstanceHandle.stateNode.node, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + ); + }; + ReactFabricHostComponent.prototype.setNativeProps = function() {}; + return ReactFabricHostComponent; +})(); +function createTextInstance( + text, + rootContainerInstance, + hostContext, + internalInstanceHandle +) { + if (!hostContext.isInAParentText) + throw ReactError( + "Text strings must be rendered within a component." + ); + hostContext = nextReactTag; + nextReactTag += 2; + return { + node: createNode( + hostContext, + "RCTRawText", + rootContainerInstance, + { text: text }, + internalInstanceHandle + ) + }; +} +var scheduleTimeout = setTimeout, + cancelTimeout = clearTimeout; +function cloneHiddenInstance(instance) { + var node = instance.node; + var updatePayload = diffProperties( + null, + emptyObject, + { style: { display: "none" } }, + instance.canonical.viewConfig.validAttributes + ); + return { + node: cloneNodeWithNewProps(node, updatePayload), + canonical: instance.canonical + }; +} +var BEFORE_SLASH_RE = /^(.*)[\\\/]/; +function getStackByFiberInDevAndProd(workInProgress) { + var info = ""; + do { + a: switch (workInProgress.tag) { + case 3: + case 4: + case 6: + case 7: + case 10: + case 9: + var JSCompiler_inline_result = ""; + break a; + default: + var owner = workInProgress._debugOwner, + source = workInProgress._debugSource, + name = getComponentName(workInProgress.type); + JSCompiler_inline_result = null; + owner && (JSCompiler_inline_result = getComponentName(owner.type)); + owner = name; + name = ""; + source + ? (name = + " (at " + + source.fileName.replace(BEFORE_SLASH_RE, "") + + ":" + + source.lineNumber + + ")") + : JSCompiler_inline_result && + (name = " (created by " + JSCompiler_inline_result + ")"); + JSCompiler_inline_result = "\n in " + (owner || "Unknown") + name; + } + info += JSCompiler_inline_result; + workInProgress = workInProgress.return; + } while (workInProgress); + return info; +} +new Set(); +var valueStack = [], + index = -1; +function pop(cursor) { + 0 > index || + ((cursor.current = valueStack[index]), (valueStack[index] = null), index--); +} +function push(cursor, value) { + index++; + valueStack[index] = cursor.current; + cursor.current = value; +} +var emptyContextObject = {}, + contextStackCursor = { current: emptyContextObject }, + didPerformWorkStackCursor = { current: !1 }, + previousContext = emptyContextObject; +function getMaskedContext(workInProgress, unmaskedContext) { + var contextTypes = workInProgress.type.contextTypes; + if (!contextTypes) return emptyContextObject; + var instance = workInProgress.stateNode; + if ( + instance && + instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext + ) + return instance.__reactInternalMemoizedMaskedChildContext; + var context = {}, + key; + for (key in contextTypes) context[key] = unmaskedContext[key]; + instance && + ((workInProgress = workInProgress.stateNode), + (workInProgress.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext), + (workInProgress.__reactInternalMemoizedMaskedChildContext = context)); + return context; +} +function isContextProvider(type) { + type = type.childContextTypes; + return null !== type && void 0 !== type; +} +function popContext(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); +} +function popTopLevelContextObject(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); +} +function pushTopLevelContextObject(fiber, context, didChange) { + if (contextStackCursor.current !== emptyContextObject) + throw ReactError( + "Unexpected context found on stack. This error is likely caused by a bug in React. Please file an issue." + ); + push(contextStackCursor, context, fiber); + push(didPerformWorkStackCursor, didChange, fiber); +} +function processChildContext(fiber, type, parentContext) { + var instance = fiber.stateNode; + fiber = type.childContextTypes; + if ("function" !== typeof instance.getChildContext) return parentContext; + instance = instance.getChildContext(); + for (var contextKey in instance) + if (!(contextKey in fiber)) + throw ReactError( + (getComponentName(type) || "Unknown") + + '.getChildContext(): key "' + + contextKey + + '" is not defined in childContextTypes.' + ); + return Object.assign({}, parentContext, instance); +} +function pushContextProvider(workInProgress) { + var instance = workInProgress.stateNode; + instance = + (instance && instance.__reactInternalMemoizedMergedChildContext) || + emptyContextObject; + previousContext = contextStackCursor.current; + push(contextStackCursor, instance, workInProgress); + push( + didPerformWorkStackCursor, + didPerformWorkStackCursor.current, + workInProgress + ); + return !0; +} +function invalidateContextProvider(workInProgress, type, didChange) { + var instance = workInProgress.stateNode; + if (!instance) + throw ReactError( + "Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue." + ); + didChange + ? ((type = processChildContext(workInProgress, type, previousContext)), + (instance.__reactInternalMemoizedMergedChildContext = type), + pop(didPerformWorkStackCursor, workInProgress), + pop(contextStackCursor, workInProgress), + push(contextStackCursor, type, workInProgress)) + : pop(didPerformWorkStackCursor, workInProgress); + push(didPerformWorkStackCursor, didChange, workInProgress); +} +var onCommitFiberRoot = null, + onCommitFiberUnmount = null; +function catchErrors(fn) { + return function(arg) { + try { + return fn(arg); + } catch (err) {} + }; +} +function injectInternals(internals) { + if ("undefined" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) return !1; + var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__; + if (hook.isDisabled || !hook.supportsFiber) return !0; + try { + var rendererID = hook.inject(internals); + onCommitFiberRoot = catchErrors(function(root) { + return hook.onCommitFiberRoot(rendererID, root); + }); + onCommitFiberUnmount = catchErrors(function(fiber) { + return hook.onCommitFiberUnmount(rendererID, fiber); + }); + } catch (err) {} + return !0; +} +var Scheduler_runWithPriority = Scheduler.unstable_runWithPriority, + Scheduler_scheduleCallback = Scheduler.unstable_scheduleCallback, + Scheduler_cancelCallback = Scheduler.unstable_cancelCallback, + Scheduler_now = Scheduler.unstable_now, + Scheduler_getCurrentPriorityLevel = + Scheduler.unstable_getCurrentPriorityLevel, + Scheduler_ImmediatePriority = Scheduler.unstable_ImmediatePriority, + Scheduler_UserBlockingPriority = Scheduler.unstable_UserBlockingPriority, + Scheduler_NormalPriority = Scheduler.unstable_NormalPriority, + Scheduler_LowPriority = Scheduler.unstable_LowPriority, + Scheduler_IdlePriority = Scheduler.unstable_IdlePriority, + fakeCallbackNode = {}, + shouldYield = Scheduler.unstable_shouldYield, + immediateQueue = null, + immediateQueueCallbackNode = null, + isFlushingImmediate = !1, + initialTimeMs = Scheduler_now(), + now = + 1e4 > initialTimeMs + ? Scheduler_now + : function() { + return Scheduler_now() - initialTimeMs; + }; +function getCurrentPriorityLevel() { + switch (Scheduler_getCurrentPriorityLevel()) { + case Scheduler_ImmediatePriority: + return 99; + case Scheduler_UserBlockingPriority: + return 98; + case Scheduler_NormalPriority: + return 97; + case Scheduler_LowPriority: + return 96; + case Scheduler_IdlePriority: + return 95; + default: + throw ReactError("Unknown priority level."); + } +} +function reactPriorityToSchedulerPriority(reactPriorityLevel) { + switch (reactPriorityLevel) { + case 99: + return Scheduler_ImmediatePriority; + case 98: + return Scheduler_UserBlockingPriority; + case 97: + return Scheduler_NormalPriority; + case 96: + return Scheduler_LowPriority; + case 95: + return Scheduler_IdlePriority; + default: + throw ReactError("Unknown priority level."); + } +} +function runWithPriority(reactPriorityLevel, fn) { + reactPriorityLevel = reactPriorityToSchedulerPriority(reactPriorityLevel); + return Scheduler_runWithPriority(reactPriorityLevel, fn); +} +function scheduleCallback(reactPriorityLevel, callback, options) { + if (99 === reactPriorityLevel) + return ( + null === immediateQueue + ? ((immediateQueue = [callback]), + (immediateQueueCallbackNode = Scheduler_scheduleCallback( + Scheduler_ImmediatePriority, + flushImmediateQueueImpl + ))) + : immediateQueue.push(callback), + fakeCallbackNode + ); + reactPriorityLevel = reactPriorityToSchedulerPriority(reactPriorityLevel); + return Scheduler_scheduleCallback(reactPriorityLevel, callback, options); +} +function flushImmediateQueue() { + null !== immediateQueueCallbackNode && + Scheduler_cancelCallback(immediateQueueCallbackNode); + flushImmediateQueueImpl(); +} +function flushImmediateQueueImpl() { + if (!isFlushingImmediate && null !== immediateQueue) { + isFlushingImmediate = !0; + var i = 0; + try { + for (; i < immediateQueue.length; i++) { + var callback = immediateQueue[i]; + do callback = callback(!0); + while (null !== callback); + } + immediateQueue = null; + } catch (error) { + throw (null !== immediateQueue && + (immediateQueue = immediateQueue.slice(i + 1)), + Scheduler_scheduleCallback( + Scheduler_ImmediatePriority, + flushImmediateQueue + ), + error); + } finally { + isFlushingImmediate = !1; + } + } +} +function inferPriorityFromExpirationTime(currentTime, expirationTime) { + if (1073741823 === expirationTime) return 99; + if (1 === expirationTime) return 95; + currentTime = + 10 * (1073741822 - expirationTime) - 10 * (1073741822 - currentTime); + return 0 >= currentTime + ? 99 + : 250 >= currentTime + ? 98 + : 5250 >= currentTime + ? 97 + : 95; +} +function FiberNode(tag, pendingProps, key, mode) { + this.tag = tag; + this.key = key; + this.sibling = this.child = this.return = this.stateNode = this.type = this.elementType = null; + this.index = 0; + this.ref = null; + this.pendingProps = pendingProps; + this.contextDependencies = this.memoizedState = this.updateQueue = this.memoizedProps = null; + this.mode = mode; + this.effectTag = 0; + this.lastEffect = this.firstEffect = this.nextEffect = null; + this.childExpirationTime = this.expirationTime = 0; + this.alternate = null; +} +function createFiber(tag, pendingProps, key, mode) { + return new FiberNode(tag, pendingProps, key, mode); +} +function shouldConstruct(Component) { + Component = Component.prototype; + return !(!Component || !Component.isReactComponent); +} +function resolveLazyComponentTag(Component) { + if ("function" === typeof Component) + return shouldConstruct(Component) ? 1 : 0; + if (void 0 !== Component && null !== Component) { + Component = Component.$$typeof; + if (Component === REACT_FORWARD_REF_TYPE) return 11; + if (Component === REACT_MEMO_TYPE) return 14; + } + return 2; +} +function createWorkInProgress(current, pendingProps) { + var workInProgress = current.alternate; + null === workInProgress + ? ((workInProgress = createFiber( + current.tag, + pendingProps, + current.key, + current.mode + )), + (workInProgress.elementType = current.elementType), + (workInProgress.type = current.type), + (workInProgress.stateNode = current.stateNode), + (workInProgress.alternate = current), + (current.alternate = workInProgress)) + : ((workInProgress.pendingProps = pendingProps), + (workInProgress.effectTag = 0), + (workInProgress.nextEffect = null), + (workInProgress.firstEffect = null), + (workInProgress.lastEffect = null)); + workInProgress.childExpirationTime = current.childExpirationTime; + workInProgress.expirationTime = current.expirationTime; + workInProgress.child = current.child; + workInProgress.memoizedProps = current.memoizedProps; + workInProgress.memoizedState = current.memoizedState; + workInProgress.updateQueue = current.updateQueue; + workInProgress.contextDependencies = current.contextDependencies; + workInProgress.sibling = current.sibling; + workInProgress.index = current.index; + workInProgress.ref = current.ref; + return workInProgress; +} +function createFiberFromTypeAndProps( + type, + key, + pendingProps, + owner, + mode, + expirationTime +) { + var fiberTag = 2; + owner = type; + if ("function" === typeof type) shouldConstruct(type) && (fiberTag = 1); + else if ("string" === typeof type) fiberTag = 5; + else + a: switch (type) { + case REACT_FRAGMENT_TYPE: + return createFiberFromFragment( + pendingProps.children, + mode, + expirationTime, + key + ); + case REACT_CONCURRENT_MODE_TYPE: + return createFiberFromMode(pendingProps, mode | 3, expirationTime, key); + case REACT_STRICT_MODE_TYPE: + return createFiberFromMode(pendingProps, mode | 2, expirationTime, key); + case REACT_PROFILER_TYPE: + return ( + (type = createFiber(12, pendingProps, key, mode | 4)), + (type.elementType = REACT_PROFILER_TYPE), + (type.type = REACT_PROFILER_TYPE), + (type.expirationTime = expirationTime), + type + ); + case REACT_SUSPENSE_TYPE: + return ( + (type = createFiber(13, pendingProps, key, mode)), + (type.elementType = REACT_SUSPENSE_TYPE), + (type.type = REACT_SUSPENSE_TYPE), + (type.expirationTime = expirationTime), + type + ); + default: + if ("object" === typeof type && null !== type) + switch (type.$$typeof) { + case REACT_PROVIDER_TYPE: + fiberTag = 10; + break a; + case REACT_CONTEXT_TYPE: + fiberTag = 9; + break a; + case REACT_FORWARD_REF_TYPE: + fiberTag = 11; + break a; + case REACT_MEMO_TYPE: + fiberTag = 14; + break a; + case REACT_LAZY_TYPE: + fiberTag = 16; + owner = null; + break a; + } + throw ReactError( + "Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: " + + (null == type ? type : typeof type) + + "." + ); + } + key = createFiber(fiberTag, pendingProps, key, mode); + key.elementType = type; + key.type = owner; + key.expirationTime = expirationTime; + return key; +} +function createFiberFromFragment(elements, mode, expirationTime, key) { + elements = createFiber(7, elements, key, mode); + elements.expirationTime = expirationTime; + return elements; +} +function createFiberFromMode(pendingProps, mode, expirationTime, key) { + pendingProps = createFiber(8, pendingProps, key, mode); + mode = 0 === (mode & 1) ? REACT_STRICT_MODE_TYPE : REACT_CONCURRENT_MODE_TYPE; + pendingProps.elementType = mode; + pendingProps.type = mode; + pendingProps.expirationTime = expirationTime; + return pendingProps; +} +function createFiberFromText(content, mode, expirationTime) { + content = createFiber(6, content, null, mode); + content.expirationTime = expirationTime; + return content; +} +function createFiberFromPortal(portal, mode, expirationTime) { + mode = createFiber( + 4, + null !== portal.children ? portal.children : [], + portal.key, + mode + ); + mode.expirationTime = expirationTime; + mode.stateNode = { + containerInfo: portal.containerInfo, + pendingChildren: null, + implementation: portal.implementation + }; + return mode; +} +function FiberRootNode(containerInfo, hydrate) { + this.current = null; + this.containerInfo = containerInfo; + this.pingCache = this.pendingChildren = null; + this.pendingCommitExpirationTime = 0; + this.finishedWork = null; + this.timeoutHandle = -1; + this.pendingContext = this.context = null; + this.hydrate = hydrate; + this.callbackNode = this.firstBatch = null; + this.pingTime = this.lastPendingTime = this.firstPendingTime = this.callbackExpirationTime = 0; +} +function is(x, y) { + return (x === y && (0 !== x || 1 / x === 1 / y)) || (x !== x && y !== y); +} +var hasOwnProperty = Object.prototype.hasOwnProperty; +function shallowEqual(objA, objB) { + if (is(objA, objB)) return !0; + if ( + "object" !== typeof objA || + null === objA || + "object" !== typeof objB || + null === objB + ) + return !1; + var keysA = Object.keys(objA), + keysB = Object.keys(objB); + if (keysA.length !== keysB.length) return !1; + for (keysB = 0; keysB < keysA.length; keysB++) + if ( + !hasOwnProperty.call(objB, keysA[keysB]) || + !is(objA[keysA[keysB]], objB[keysA[keysB]]) + ) + return !1; + return !0; +} +function resolveDefaultProps(Component, baseProps) { + if (Component && Component.defaultProps) { + baseProps = Object.assign({}, baseProps); + Component = Component.defaultProps; + for (var propName in Component) + void 0 === baseProps[propName] && + (baseProps[propName] = Component[propName]); + } + return baseProps; +} +function readLazyComponentType(lazyComponent) { + var result = lazyComponent._result; + switch (lazyComponent._status) { + case 1: + return result; + case 2: + throw result; + case 0: + throw result; + default: + lazyComponent._status = 0; + result = lazyComponent._ctor; + result = result(); + result.then( + function(moduleObject) { + 0 === lazyComponent._status && + ((moduleObject = moduleObject.default), + (lazyComponent._status = 1), + (lazyComponent._result = moduleObject)); + }, + function(error) { + 0 === lazyComponent._status && + ((lazyComponent._status = 2), (lazyComponent._result = error)); + } + ); + switch (lazyComponent._status) { + case 1: + return lazyComponent._result; + case 2: + throw lazyComponent._result; + } + lazyComponent._result = result; + throw result; + } +} +var valueCursor = { current: null }, + currentlyRenderingFiber = null, + lastContextDependency = null, + lastContextWithAllBitsObserved = null; +function resetContextDependences() { + lastContextWithAllBitsObserved = lastContextDependency = currentlyRenderingFiber = null; +} +function pushProvider(providerFiber, nextValue) { + var context = providerFiber.type._context; + push(valueCursor, context._currentValue2, providerFiber); + context._currentValue2 = nextValue; +} +function popProvider(providerFiber) { + var currentValue = valueCursor.current; + pop(valueCursor, providerFiber); + providerFiber.type._context._currentValue2 = currentValue; +} +function prepareToReadContext(workInProgress, renderExpirationTime) { + currentlyRenderingFiber = workInProgress; + lastContextWithAllBitsObserved = lastContextDependency = null; + var currentDependencies = workInProgress.contextDependencies; + null !== currentDependencies && + currentDependencies.expirationTime >= renderExpirationTime && + (didReceiveUpdate = !0); + workInProgress.contextDependencies = null; +} +function readContext(context, observedBits) { + if ( + lastContextWithAllBitsObserved !== context && + !1 !== observedBits && + 0 !== observedBits + ) { + if ("number" !== typeof observedBits || 1073741823 === observedBits) + (lastContextWithAllBitsObserved = context), (observedBits = 1073741823); + observedBits = { context: context, observedBits: observedBits, next: null }; + if (null === lastContextDependency) { + if (null === currentlyRenderingFiber) + throw ReactError( + "Context can only be read while React is rendering. In classes, you can read it in the render method or getDerivedStateFromProps. In function components, you can read it directly in the function body, but not inside Hooks like useReducer() or useMemo()." + ); + lastContextDependency = observedBits; + currentlyRenderingFiber.contextDependencies = { + first: observedBits, + expirationTime: 0 + }; + } else lastContextDependency = lastContextDependency.next = observedBits; + } + return context._currentValue2; +} +var hasForceUpdate = !1; +function createUpdateQueue(baseState) { + return { + baseState: baseState, + firstUpdate: null, + lastUpdate: null, + firstCapturedUpdate: null, + lastCapturedUpdate: null, + firstEffect: null, + lastEffect: null, + firstCapturedEffect: null, + lastCapturedEffect: null + }; +} +function cloneUpdateQueue(currentQueue) { + return { + baseState: currentQueue.baseState, + firstUpdate: currentQueue.firstUpdate, + lastUpdate: currentQueue.lastUpdate, + firstCapturedUpdate: null, + lastCapturedUpdate: null, + firstEffect: null, + lastEffect: null, + firstCapturedEffect: null, + lastCapturedEffect: null + }; +} +function createUpdate(expirationTime) { + return { + expirationTime: expirationTime, + tag: 0, + payload: null, + callback: null, + next: null, + nextEffect: null + }; +} +function appendUpdateToQueue(queue, update) { + null === queue.lastUpdate + ? (queue.firstUpdate = queue.lastUpdate = update) + : ((queue.lastUpdate.next = update), (queue.lastUpdate = update)); +} +function enqueueUpdate(fiber, update) { + var alternate = fiber.alternate; + if (null === alternate) { + var queue1 = fiber.updateQueue; + var queue2 = null; + null === queue1 && + (queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState)); + } else + (queue1 = fiber.updateQueue), + (queue2 = alternate.updateQueue), + null === queue1 + ? null === queue2 + ? ((queue1 = fiber.updateQueue = createUpdateQueue( + fiber.memoizedState + )), + (queue2 = alternate.updateQueue = createUpdateQueue( + alternate.memoizedState + ))) + : (queue1 = fiber.updateQueue = cloneUpdateQueue(queue2)) + : null === queue2 && + (queue2 = alternate.updateQueue = cloneUpdateQueue(queue1)); + null === queue2 || queue1 === queue2 + ? appendUpdateToQueue(queue1, update) + : null === queue1.lastUpdate || null === queue2.lastUpdate + ? (appendUpdateToQueue(queue1, update), + appendUpdateToQueue(queue2, update)) + : (appendUpdateToQueue(queue1, update), (queue2.lastUpdate = update)); +} +function enqueueCapturedUpdate(workInProgress, update) { + var workInProgressQueue = workInProgress.updateQueue; + workInProgressQueue = + null === workInProgressQueue + ? (workInProgress.updateQueue = createUpdateQueue( + workInProgress.memoizedState + )) + : ensureWorkInProgressQueueIsAClone(workInProgress, workInProgressQueue); + null === workInProgressQueue.lastCapturedUpdate + ? (workInProgressQueue.firstCapturedUpdate = workInProgressQueue.lastCapturedUpdate = update) + : ((workInProgressQueue.lastCapturedUpdate.next = update), + (workInProgressQueue.lastCapturedUpdate = update)); +} +function ensureWorkInProgressQueueIsAClone(workInProgress, queue) { + var current = workInProgress.alternate; + null !== current && + queue === current.updateQueue && + (queue = workInProgress.updateQueue = cloneUpdateQueue(queue)); + return queue; +} +function getStateFromUpdate( + workInProgress, + queue, + update, + prevState, + nextProps, + instance +) { + switch (update.tag) { + case 1: + return ( + (workInProgress = update.payload), + "function" === typeof workInProgress + ? workInProgress.call(instance, prevState, nextProps) + : workInProgress + ); + case 3: + workInProgress.effectTag = (workInProgress.effectTag & -2049) | 64; + case 0: + workInProgress = update.payload; + nextProps = + "function" === typeof workInProgress + ? workInProgress.call(instance, prevState, nextProps) + : workInProgress; + if (null === nextProps || void 0 === nextProps) break; + return Object.assign({}, prevState, nextProps); + case 2: + hasForceUpdate = !0; + } + return prevState; +} +function processUpdateQueue( + workInProgress, + queue, + props, + instance, + renderExpirationTime +) { + hasForceUpdate = !1; + queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue); + for ( + var newBaseState = queue.baseState, + newFirstUpdate = null, + newExpirationTime = 0, + update = queue.firstUpdate, + resultState = newBaseState; + null !== update; + + ) { + var updateExpirationTime = update.expirationTime; + updateExpirationTime < renderExpirationTime + ? (null === newFirstUpdate && + ((newFirstUpdate = update), (newBaseState = resultState)), + newExpirationTime < updateExpirationTime && + (newExpirationTime = updateExpirationTime)) + : (updateExpirationTime < workInProgressRootMostRecentEventTime && + (workInProgressRootMostRecentEventTime = updateExpirationTime), + (resultState = getStateFromUpdate( + workInProgress, + queue, + update, + resultState, + props, + instance + )), + null !== update.callback && + ((workInProgress.effectTag |= 32), + (update.nextEffect = null), + null === queue.lastEffect + ? (queue.firstEffect = queue.lastEffect = update) + : ((queue.lastEffect.nextEffect = update), + (queue.lastEffect = update)))); + update = update.next; + } + updateExpirationTime = null; + for (update = queue.firstCapturedUpdate; null !== update; ) { + var _updateExpirationTime = update.expirationTime; + _updateExpirationTime < renderExpirationTime + ? (null === updateExpirationTime && + ((updateExpirationTime = update), + null === newFirstUpdate && (newBaseState = resultState)), + newExpirationTime < _updateExpirationTime && + (newExpirationTime = _updateExpirationTime)) + : ((resultState = getStateFromUpdate( + workInProgress, + queue, + update, + resultState, + props, + instance + )), + null !== update.callback && + ((workInProgress.effectTag |= 32), + (update.nextEffect = null), + null === queue.lastCapturedEffect + ? (queue.firstCapturedEffect = queue.lastCapturedEffect = update) + : ((queue.lastCapturedEffect.nextEffect = update), + (queue.lastCapturedEffect = update)))); + update = update.next; + } + null === newFirstUpdate && (queue.lastUpdate = null); + null === updateExpirationTime + ? (queue.lastCapturedUpdate = null) + : (workInProgress.effectTag |= 32); + null === newFirstUpdate && + null === updateExpirationTime && + (newBaseState = resultState); + queue.baseState = newBaseState; + queue.firstUpdate = newFirstUpdate; + queue.firstCapturedUpdate = updateExpirationTime; + workInProgress.expirationTime = newExpirationTime; + workInProgress.memoizedState = resultState; +} +function commitUpdateQueue(finishedWork, finishedQueue, instance) { + null !== finishedQueue.firstCapturedUpdate && + (null !== finishedQueue.lastUpdate && + ((finishedQueue.lastUpdate.next = finishedQueue.firstCapturedUpdate), + (finishedQueue.lastUpdate = finishedQueue.lastCapturedUpdate)), + (finishedQueue.firstCapturedUpdate = finishedQueue.lastCapturedUpdate = null)); + commitUpdateEffects(finishedQueue.firstEffect, instance); + finishedQueue.firstEffect = finishedQueue.lastEffect = null; + commitUpdateEffects(finishedQueue.firstCapturedEffect, instance); + finishedQueue.firstCapturedEffect = finishedQueue.lastCapturedEffect = null; +} +function commitUpdateEffects(effect, instance) { + for (; null !== effect; ) { + var _callback3 = effect.callback; + if (null !== _callback3) { + effect.callback = null; + var context = instance; + if ("function" !== typeof _callback3) + throw ReactError( + "Invalid argument passed as callback. Expected a function. Instead received: " + + _callback3 + ); + _callback3.call(context); + } + effect = effect.nextEffect; + } +} +var emptyRefsObject = new React.Component().refs; +function applyDerivedStateFromProps( + workInProgress, + ctor, + getDerivedStateFromProps, + nextProps +) { + ctor = workInProgress.memoizedState; + getDerivedStateFromProps = getDerivedStateFromProps(nextProps, ctor); + getDerivedStateFromProps = + null === getDerivedStateFromProps || void 0 === getDerivedStateFromProps + ? ctor + : Object.assign({}, ctor, getDerivedStateFromProps); + workInProgress.memoizedState = getDerivedStateFromProps; + nextProps = workInProgress.updateQueue; + null !== nextProps && + 0 === workInProgress.expirationTime && + (nextProps.baseState = getDerivedStateFromProps); +} +var classComponentUpdater = { + isMounted: function(component) { + return (component = component._reactInternalFiber) + ? 2 === isFiberMountedImpl(component) + : !1; + }, + enqueueSetState: function(inst, payload, callback) { + inst = inst._reactInternalFiber; + var currentTime = requestCurrentTime(); + currentTime = computeExpirationForFiber(currentTime, inst); + var update = createUpdate(currentTime); + update.payload = payload; + void 0 !== callback && null !== callback && (update.callback = callback); + flushPassiveEffects(); + enqueueUpdate(inst, update); + scheduleUpdateOnFiber(inst, currentTime); + }, + enqueueReplaceState: function(inst, payload, callback) { + inst = inst._reactInternalFiber; + var currentTime = requestCurrentTime(); + currentTime = computeExpirationForFiber(currentTime, inst); + var update = createUpdate(currentTime); + update.tag = 1; + update.payload = payload; + void 0 !== callback && null !== callback && (update.callback = callback); + flushPassiveEffects(); + enqueueUpdate(inst, update); + scheduleUpdateOnFiber(inst, currentTime); + }, + enqueueForceUpdate: function(inst, callback) { + inst = inst._reactInternalFiber; + var currentTime = requestCurrentTime(); + currentTime = computeExpirationForFiber(currentTime, inst); + var update = createUpdate(currentTime); + update.tag = 2; + void 0 !== callback && null !== callback && (update.callback = callback); + flushPassiveEffects(); + enqueueUpdate(inst, update); + scheduleUpdateOnFiber(inst, currentTime); + } +}; +function checkShouldComponentUpdate( + workInProgress, + ctor, + oldProps, + newProps, + oldState, + newState, + nextContext +) { + workInProgress = workInProgress.stateNode; + return "function" === typeof workInProgress.shouldComponentUpdate + ? workInProgress.shouldComponentUpdate(newProps, newState, nextContext) + : ctor.prototype && ctor.prototype.isPureReactComponent + ? !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState) + : !0; +} +function constructClassInstance(workInProgress, ctor, props) { + var isLegacyContextConsumer = !1, + unmaskedContext = emptyContextObject; + var context = ctor.contextType; + "object" === typeof context && null !== context + ? (context = readContext(context)) + : ((unmaskedContext = isContextProvider(ctor) + ? previousContext + : contextStackCursor.current), + (isLegacyContextConsumer = ctor.contextTypes), + (context = (isLegacyContextConsumer = + null !== isLegacyContextConsumer && void 0 !== isLegacyContextConsumer) + ? getMaskedContext(workInProgress, unmaskedContext) + : emptyContextObject)); + ctor = new ctor(props, context); + workInProgress.memoizedState = + null !== ctor.state && void 0 !== ctor.state ? ctor.state : null; + ctor.updater = classComponentUpdater; + workInProgress.stateNode = ctor; + ctor._reactInternalFiber = workInProgress; + isLegacyContextConsumer && + ((workInProgress = workInProgress.stateNode), + (workInProgress.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext), + (workInProgress.__reactInternalMemoizedMaskedChildContext = context)); + return ctor; +} +function callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + nextContext +) { + workInProgress = instance.state; + "function" === typeof instance.componentWillReceiveProps && + instance.componentWillReceiveProps(newProps, nextContext); + "function" === typeof instance.UNSAFE_componentWillReceiveProps && + instance.UNSAFE_componentWillReceiveProps(newProps, nextContext); + instance.state !== workInProgress && + classComponentUpdater.enqueueReplaceState(instance, instance.state, null); +} +function mountClassInstance( + workInProgress, + ctor, + newProps, + renderExpirationTime +) { + var instance = workInProgress.stateNode; + instance.props = newProps; + instance.state = workInProgress.memoizedState; + instance.refs = emptyRefsObject; + var contextType = ctor.contextType; + "object" === typeof contextType && null !== contextType + ? (instance.context = readContext(contextType)) + : ((contextType = isContextProvider(ctor) + ? previousContext + : contextStackCursor.current), + (instance.context = getMaskedContext(workInProgress, contextType))); + contextType = workInProgress.updateQueue; + null !== contextType && + (processUpdateQueue( + workInProgress, + contextType, + newProps, + instance, + renderExpirationTime + ), + (instance.state = workInProgress.memoizedState)); + contextType = ctor.getDerivedStateFromProps; + "function" === typeof contextType && + (applyDerivedStateFromProps(workInProgress, ctor, contextType, newProps), + (instance.state = workInProgress.memoizedState)); + "function" === typeof ctor.getDerivedStateFromProps || + "function" === typeof instance.getSnapshotBeforeUpdate || + ("function" !== typeof instance.UNSAFE_componentWillMount && + "function" !== typeof instance.componentWillMount) || + ((ctor = instance.state), + "function" === typeof instance.componentWillMount && + instance.componentWillMount(), + "function" === typeof instance.UNSAFE_componentWillMount && + instance.UNSAFE_componentWillMount(), + ctor !== instance.state && + classComponentUpdater.enqueueReplaceState(instance, instance.state, null), + (contextType = workInProgress.updateQueue), + null !== contextType && + (processUpdateQueue( + workInProgress, + contextType, + newProps, + instance, + renderExpirationTime + ), + (instance.state = workInProgress.memoizedState))); + "function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4); +} +var isArray = Array.isArray; +function coerceRef(returnFiber, current$$1, element) { + returnFiber = element.ref; + if ( + null !== returnFiber && + "function" !== typeof returnFiber && + "object" !== typeof returnFiber + ) { + if (element._owner) { + element = element._owner; + var inst = void 0; + if (element) { + if (1 !== element.tag) + throw ReactError( + "Function components cannot have refs. Did you mean to use React.forwardRef()?" + ); + inst = element.stateNode; + } + if (!inst) + throw ReactError( + "Missing owner for string ref " + + returnFiber + + ". This error is likely caused by a bug in React. Please file an issue." + ); + var stringRef = "" + returnFiber; + if ( + null !== current$$1 && + null !== current$$1.ref && + "function" === typeof current$$1.ref && + current$$1.ref._stringRef === stringRef + ) + return current$$1.ref; + current$$1 = function(value) { + var refs = inst.refs; + refs === emptyRefsObject && (refs = inst.refs = {}); + null === value ? delete refs[stringRef] : (refs[stringRef] = value); + }; + current$$1._stringRef = stringRef; + return current$$1; + } + if ("string" !== typeof returnFiber) + throw ReactError( + "Expected ref to be a function, a string, an object returned by React.createRef(), or null." + ); + if (!element._owner) + throw ReactError( + "Element ref was specified as a string (" + + returnFiber + + ") but no owner was set. This could happen for one of the following reasons:\n1. You may be adding a ref to a function component\n2. You may be adding a ref to a component that was not created inside a component's render method\n3. You have multiple copies of React loaded\nSee https://fb.me/react-refs-must-have-owner for more information." + ); + } + return returnFiber; +} +function throwOnInvalidObjectType(returnFiber, newChild) { + if ("textarea" !== returnFiber.type) + throw ReactError( + "Objects are not valid as a React child (found: " + + ("[object Object]" === Object.prototype.toString.call(newChild) + ? "object with keys {" + Object.keys(newChild).join(", ") + "}" + : newChild) + + ")." + ); +} +function ChildReconciler(shouldTrackSideEffects) { + function deleteChild(returnFiber, childToDelete) { + if (shouldTrackSideEffects) { + var last = returnFiber.lastEffect; + null !== last + ? ((last.nextEffect = childToDelete), + (returnFiber.lastEffect = childToDelete)) + : (returnFiber.firstEffect = returnFiber.lastEffect = childToDelete); + childToDelete.nextEffect = null; + childToDelete.effectTag = 8; + } + } + function deleteRemainingChildren(returnFiber, currentFirstChild) { + if (!shouldTrackSideEffects) return null; + for (; null !== currentFirstChild; ) + deleteChild(returnFiber, currentFirstChild), + (currentFirstChild = currentFirstChild.sibling); + return null; + } + function mapRemainingChildren(returnFiber, currentFirstChild) { + for (returnFiber = new Map(); null !== currentFirstChild; ) + null !== currentFirstChild.key + ? returnFiber.set(currentFirstChild.key, currentFirstChild) + : returnFiber.set(currentFirstChild.index, currentFirstChild), + (currentFirstChild = currentFirstChild.sibling); + return returnFiber; + } + function useFiber(fiber, pendingProps, expirationTime) { + fiber = createWorkInProgress(fiber, pendingProps, expirationTime); + fiber.index = 0; + fiber.sibling = null; + return fiber; + } + function placeChild(newFiber, lastPlacedIndex, newIndex) { + newFiber.index = newIndex; + if (!shouldTrackSideEffects) return lastPlacedIndex; + newIndex = newFiber.alternate; + if (null !== newIndex) + return ( + (newIndex = newIndex.index), + newIndex < lastPlacedIndex + ? ((newFiber.effectTag = 2), lastPlacedIndex) + : newIndex + ); + newFiber.effectTag = 2; + return lastPlacedIndex; + } + function placeSingleChild(newFiber) { + shouldTrackSideEffects && + null === newFiber.alternate && + (newFiber.effectTag = 2); + return newFiber; + } + function updateTextNode( + returnFiber, + current$$1, + textContent, + expirationTime + ) { + if (null === current$$1 || 6 !== current$$1.tag) + return ( + (current$$1 = createFiberFromText( + textContent, + returnFiber.mode, + expirationTime + )), + (current$$1.return = returnFiber), + current$$1 + ); + current$$1 = useFiber(current$$1, textContent, expirationTime); + current$$1.return = returnFiber; + return current$$1; + } + function updateElement(returnFiber, current$$1, element, expirationTime) { + if (null !== current$$1 && current$$1.elementType === element.type) + return ( + (expirationTime = useFiber(current$$1, element.props, expirationTime)), + (expirationTime.ref = coerceRef(returnFiber, current$$1, element)), + (expirationTime.return = returnFiber), + expirationTime + ); + expirationTime = createFiberFromTypeAndProps( + element.type, + element.key, + element.props, + null, + returnFiber.mode, + expirationTime + ); + expirationTime.ref = coerceRef(returnFiber, current$$1, element); + expirationTime.return = returnFiber; + return expirationTime; + } + function updatePortal(returnFiber, current$$1, portal, expirationTime) { + if ( + null === current$$1 || + 4 !== current$$1.tag || + current$$1.stateNode.containerInfo !== portal.containerInfo || + current$$1.stateNode.implementation !== portal.implementation + ) + return ( + (current$$1 = createFiberFromPortal( + portal, + returnFiber.mode, + expirationTime + )), + (current$$1.return = returnFiber), + current$$1 + ); + current$$1 = useFiber(current$$1, portal.children || [], expirationTime); + current$$1.return = returnFiber; + return current$$1; + } + function updateFragment( + returnFiber, + current$$1, + fragment, + expirationTime, + key + ) { + if (null === current$$1 || 7 !== current$$1.tag) + return ( + (current$$1 = createFiberFromFragment( + fragment, + returnFiber.mode, + expirationTime, + key + )), + (current$$1.return = returnFiber), + current$$1 + ); + current$$1 = useFiber(current$$1, fragment, expirationTime); + current$$1.return = returnFiber; + return current$$1; + } + function createChild(returnFiber, newChild, expirationTime) { + if ("string" === typeof newChild || "number" === typeof newChild) + return ( + (newChild = createFiberFromText( + "" + newChild, + returnFiber.mode, + expirationTime + )), + (newChild.return = returnFiber), + newChild + ); + if ("object" === typeof newChild && null !== newChild) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return ( + (expirationTime = createFiberFromTypeAndProps( + newChild.type, + newChild.key, + newChild.props, + null, + returnFiber.mode, + expirationTime + )), + (expirationTime.ref = coerceRef(returnFiber, null, newChild)), + (expirationTime.return = returnFiber), + expirationTime + ); + case REACT_PORTAL_TYPE: + return ( + (newChild = createFiberFromPortal( + newChild, + returnFiber.mode, + expirationTime + )), + (newChild.return = returnFiber), + newChild + ); + } + if (isArray(newChild) || getIteratorFn(newChild)) + return ( + (newChild = createFiberFromFragment( + newChild, + returnFiber.mode, + expirationTime, + null + )), + (newChild.return = returnFiber), + newChild + ); + throwOnInvalidObjectType(returnFiber, newChild); + } + return null; + } + function updateSlot(returnFiber, oldFiber, newChild, expirationTime) { + var key = null !== oldFiber ? oldFiber.key : null; + if ("string" === typeof newChild || "number" === typeof newChild) + return null !== key + ? null + : updateTextNode(returnFiber, oldFiber, "" + newChild, expirationTime); + if ("object" === typeof newChild && null !== newChild) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return newChild.key === key + ? newChild.type === REACT_FRAGMENT_TYPE + ? updateFragment( + returnFiber, + oldFiber, + newChild.props.children, + expirationTime, + key + ) + : updateElement(returnFiber, oldFiber, newChild, expirationTime) + : null; + case REACT_PORTAL_TYPE: + return newChild.key === key + ? updatePortal(returnFiber, oldFiber, newChild, expirationTime) + : null; + } + if (isArray(newChild) || getIteratorFn(newChild)) + return null !== key + ? null + : updateFragment( + returnFiber, + oldFiber, + newChild, + expirationTime, + null + ); + throwOnInvalidObjectType(returnFiber, newChild); + } + return null; + } + function updateFromMap( + existingChildren, + returnFiber, + newIdx, + newChild, + expirationTime + ) { + if ("string" === typeof newChild || "number" === typeof newChild) + return ( + (existingChildren = existingChildren.get(newIdx) || null), + updateTextNode( + returnFiber, + existingChildren, + "" + newChild, + expirationTime + ) + ); + if ("object" === typeof newChild && null !== newChild) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return ( + (existingChildren = + existingChildren.get( + null === newChild.key ? newIdx : newChild.key + ) || null), + newChild.type === REACT_FRAGMENT_TYPE + ? updateFragment( + returnFiber, + existingChildren, + newChild.props.children, + expirationTime, + newChild.key + ) + : updateElement( + returnFiber, + existingChildren, + newChild, + expirationTime + ) + ); + case REACT_PORTAL_TYPE: + return ( + (existingChildren = + existingChildren.get( + null === newChild.key ? newIdx : newChild.key + ) || null), + updatePortal( + returnFiber, + existingChildren, + newChild, + expirationTime + ) + ); + } + if (isArray(newChild) || getIteratorFn(newChild)) + return ( + (existingChildren = existingChildren.get(newIdx) || null), + updateFragment( + returnFiber, + existingChildren, + newChild, + expirationTime, + null + ) + ); + throwOnInvalidObjectType(returnFiber, newChild); + } + return null; + } + function reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChildren, + expirationTime + ) { + for ( + var resultingFirstChild = null, + previousNewFiber = null, + oldFiber = currentFirstChild, + newIdx = (currentFirstChild = 0), + nextOldFiber = null; + null !== oldFiber && newIdx < newChildren.length; + newIdx++ + ) { + oldFiber.index > newIdx + ? ((nextOldFiber = oldFiber), (oldFiber = null)) + : (nextOldFiber = oldFiber.sibling); + var newFiber = updateSlot( + returnFiber, + oldFiber, + newChildren[newIdx], + expirationTime + ); + if (null === newFiber) { + null === oldFiber && (oldFiber = nextOldFiber); + break; + } + shouldTrackSideEffects && + oldFiber && + null === newFiber.alternate && + deleteChild(returnFiber, oldFiber); + currentFirstChild = placeChild(newFiber, currentFirstChild, newIdx); + null === previousNewFiber + ? (resultingFirstChild = newFiber) + : (previousNewFiber.sibling = newFiber); + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } + if (newIdx === newChildren.length) + return ( + deleteRemainingChildren(returnFiber, oldFiber), resultingFirstChild + ); + if (null === oldFiber) { + for (; newIdx < newChildren.length; newIdx++) + (oldFiber = createChild( + returnFiber, + newChildren[newIdx], + expirationTime + )), + null !== oldFiber && + ((currentFirstChild = placeChild( + oldFiber, + currentFirstChild, + newIdx + )), + null === previousNewFiber + ? (resultingFirstChild = oldFiber) + : (previousNewFiber.sibling = oldFiber), + (previousNewFiber = oldFiber)); + return resultingFirstChild; + } + for ( + oldFiber = mapRemainingChildren(returnFiber, oldFiber); + newIdx < newChildren.length; + newIdx++ + ) + (nextOldFiber = updateFromMap( + oldFiber, + returnFiber, + newIdx, + newChildren[newIdx], + expirationTime + )), + null !== nextOldFiber && + (shouldTrackSideEffects && + null !== nextOldFiber.alternate && + oldFiber.delete( + null === nextOldFiber.key ? newIdx : nextOldFiber.key + ), + (currentFirstChild = placeChild( + nextOldFiber, + currentFirstChild, + newIdx + )), + null === previousNewFiber + ? (resultingFirstChild = nextOldFiber) + : (previousNewFiber.sibling = nextOldFiber), + (previousNewFiber = nextOldFiber)); + shouldTrackSideEffects && + oldFiber.forEach(function(child) { + return deleteChild(returnFiber, child); + }); + return resultingFirstChild; + } + function reconcileChildrenIterator( + returnFiber, + currentFirstChild, + newChildrenIterable, + expirationTime + ) { + var iteratorFn = getIteratorFn(newChildrenIterable); + if ("function" !== typeof iteratorFn) + throw ReactError( + "An object is not an iterable. This error is likely caused by a bug in React. Please file an issue." + ); + newChildrenIterable = iteratorFn.call(newChildrenIterable); + if (null == newChildrenIterable) + throw ReactError("An iterable object provided no iterator."); + for ( + var previousNewFiber = (iteratorFn = null), + oldFiber = currentFirstChild, + newIdx = (currentFirstChild = 0), + nextOldFiber = null, + step = newChildrenIterable.next(); + null !== oldFiber && !step.done; + newIdx++, step = newChildrenIterable.next() + ) { + oldFiber.index > newIdx + ? ((nextOldFiber = oldFiber), (oldFiber = null)) + : (nextOldFiber = oldFiber.sibling); + var newFiber = updateSlot( + returnFiber, + oldFiber, + step.value, + expirationTime + ); + if (null === newFiber) { + null === oldFiber && (oldFiber = nextOldFiber); + break; + } + shouldTrackSideEffects && + oldFiber && + null === newFiber.alternate && + deleteChild(returnFiber, oldFiber); + currentFirstChild = placeChild(newFiber, currentFirstChild, newIdx); + null === previousNewFiber + ? (iteratorFn = newFiber) + : (previousNewFiber.sibling = newFiber); + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } + if (step.done) + return deleteRemainingChildren(returnFiber, oldFiber), iteratorFn; + if (null === oldFiber) { + for (; !step.done; newIdx++, step = newChildrenIterable.next()) + (step = createChild(returnFiber, step.value, expirationTime)), + null !== step && + ((currentFirstChild = placeChild(step, currentFirstChild, newIdx)), + null === previousNewFiber + ? (iteratorFn = step) + : (previousNewFiber.sibling = step), + (previousNewFiber = step)); + return iteratorFn; + } + for ( + oldFiber = mapRemainingChildren(returnFiber, oldFiber); + !step.done; + newIdx++, step = newChildrenIterable.next() + ) + (step = updateFromMap( + oldFiber, + returnFiber, + newIdx, + step.value, + expirationTime + )), + null !== step && + (shouldTrackSideEffects && + null !== step.alternate && + oldFiber.delete(null === step.key ? newIdx : step.key), + (currentFirstChild = placeChild(step, currentFirstChild, newIdx)), + null === previousNewFiber + ? (iteratorFn = step) + : (previousNewFiber.sibling = step), + (previousNewFiber = step)); + shouldTrackSideEffects && + oldFiber.forEach(function(child) { + return deleteChild(returnFiber, child); + }); + return iteratorFn; + } + return function(returnFiber, currentFirstChild, newChild, expirationTime) { + var isUnkeyedTopLevelFragment = + "object" === typeof newChild && + null !== newChild && + newChild.type === REACT_FRAGMENT_TYPE && + null === newChild.key; + isUnkeyedTopLevelFragment && (newChild = newChild.props.children); + var isObject = "object" === typeof newChild && null !== newChild; + if (isObject) + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + a: { + isObject = newChild.key; + for ( + isUnkeyedTopLevelFragment = currentFirstChild; + null !== isUnkeyedTopLevelFragment; + + ) { + if (isUnkeyedTopLevelFragment.key === isObject) { + if ( + 7 === isUnkeyedTopLevelFragment.tag + ? newChild.type === REACT_FRAGMENT_TYPE + : isUnkeyedTopLevelFragment.elementType === newChild.type + ) { + deleteRemainingChildren( + returnFiber, + isUnkeyedTopLevelFragment.sibling + ); + currentFirstChild = useFiber( + isUnkeyedTopLevelFragment, + newChild.type === REACT_FRAGMENT_TYPE + ? newChild.props.children + : newChild.props, + expirationTime + ); + currentFirstChild.ref = coerceRef( + returnFiber, + isUnkeyedTopLevelFragment, + newChild + ); + currentFirstChild.return = returnFiber; + returnFiber = currentFirstChild; + break a; + } + deleteRemainingChildren(returnFiber, isUnkeyedTopLevelFragment); + break; + } else deleteChild(returnFiber, isUnkeyedTopLevelFragment); + isUnkeyedTopLevelFragment = isUnkeyedTopLevelFragment.sibling; + } + newChild.type === REACT_FRAGMENT_TYPE + ? ((currentFirstChild = createFiberFromFragment( + newChild.props.children, + returnFiber.mode, + expirationTime, + newChild.key + )), + (currentFirstChild.return = returnFiber), + (returnFiber = currentFirstChild)) + : ((expirationTime = createFiberFromTypeAndProps( + newChild.type, + newChild.key, + newChild.props, + null, + returnFiber.mode, + expirationTime + )), + (expirationTime.ref = coerceRef( + returnFiber, + currentFirstChild, + newChild + )), + (expirationTime.return = returnFiber), + (returnFiber = expirationTime)); + } + return placeSingleChild(returnFiber); + case REACT_PORTAL_TYPE: + a: { + for ( + isUnkeyedTopLevelFragment = newChild.key; + null !== currentFirstChild; + + ) { + if (currentFirstChild.key === isUnkeyedTopLevelFragment) { + if ( + 4 === currentFirstChild.tag && + currentFirstChild.stateNode.containerInfo === + newChild.containerInfo && + currentFirstChild.stateNode.implementation === + newChild.implementation + ) { + deleteRemainingChildren( + returnFiber, + currentFirstChild.sibling + ); + currentFirstChild = useFiber( + currentFirstChild, + newChild.children || [], + expirationTime + ); + currentFirstChild.return = returnFiber; + returnFiber = currentFirstChild; + break a; + } + deleteRemainingChildren(returnFiber, currentFirstChild); + break; + } else deleteChild(returnFiber, currentFirstChild); + currentFirstChild = currentFirstChild.sibling; + } + currentFirstChild = createFiberFromPortal( + newChild, + returnFiber.mode, + expirationTime + ); + currentFirstChild.return = returnFiber; + returnFiber = currentFirstChild; + } + return placeSingleChild(returnFiber); + } + if ("string" === typeof newChild || "number" === typeof newChild) + return ( + (newChild = "" + newChild), + null !== currentFirstChild && 6 === currentFirstChild.tag + ? (deleteRemainingChildren(returnFiber, currentFirstChild.sibling), + (currentFirstChild = useFiber( + currentFirstChild, + newChild, + expirationTime + )), + (currentFirstChild.return = returnFiber), + (returnFiber = currentFirstChild)) + : (deleteRemainingChildren(returnFiber, currentFirstChild), + (currentFirstChild = createFiberFromText( + newChild, + returnFiber.mode, + expirationTime + )), + (currentFirstChild.return = returnFiber), + (returnFiber = currentFirstChild)), + placeSingleChild(returnFiber) + ); + if (isArray(newChild)) + return reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ); + if (getIteratorFn(newChild)) + return reconcileChildrenIterator( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ); + isObject && throwOnInvalidObjectType(returnFiber, newChild); + if ("undefined" === typeof newChild && !isUnkeyedTopLevelFragment) + switch (returnFiber.tag) { + case 1: + case 0: + throw ((returnFiber = returnFiber.type), + ReactError( + (returnFiber.displayName || returnFiber.name || "Component") + + "(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null." + )); + } + return deleteRemainingChildren(returnFiber, currentFirstChild); + }; +} +var reconcileChildFibers = ChildReconciler(!0), + mountChildFibers = ChildReconciler(!1), + NO_CONTEXT = {}, + contextStackCursor$1 = { current: NO_CONTEXT }, + contextFiberStackCursor = { current: NO_CONTEXT }, + rootInstanceStackCursor = { current: NO_CONTEXT }; +function requiredContext(c) { + if (c === NO_CONTEXT) + throw ReactError( + "Expected host context to exist. This error is likely caused by a bug in React. Please file an issue." + ); + return c; +} +function pushHostContainer(fiber, nextRootInstance) { + push(rootInstanceStackCursor, nextRootInstance, fiber); + push(contextFiberStackCursor, fiber, fiber); + push(contextStackCursor$1, NO_CONTEXT, fiber); + pop(contextStackCursor$1, fiber); + push(contextStackCursor$1, { isInAParentText: !1 }, fiber); +} +function popHostContainer(fiber) { + pop(contextStackCursor$1, fiber); + pop(contextFiberStackCursor, fiber); + pop(rootInstanceStackCursor, fiber); +} +function pushHostContext(fiber) { + requiredContext(rootInstanceStackCursor.current); + var context = requiredContext(contextStackCursor$1.current); + var nextContext = fiber.type; + nextContext = + "AndroidTextInput" === nextContext || + "RCTMultilineTextInputView" === nextContext || + "RCTSinglelineTextInputView" === nextContext || + "RCTText" === nextContext || + "RCTVirtualText" === nextContext; + nextContext = + context.isInAParentText !== nextContext + ? { isInAParentText: nextContext } + : context; + context !== nextContext && + (push(contextFiberStackCursor, fiber, fiber), + push(contextStackCursor$1, nextContext, fiber)); +} +function popHostContext(fiber) { + contextFiberStackCursor.current === fiber && + (pop(contextStackCursor$1, fiber), pop(contextFiberStackCursor, fiber)); +} +var NoEffect$1 = 0, + UnmountSnapshot = 2, + UnmountMutation = 4, + MountMutation = 8, + UnmountLayout = 16, + MountLayout = 32, + MountPassive = 64, + UnmountPassive = 128, + ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher, + renderExpirationTime$1 = 0, + currentlyRenderingFiber$1 = null, + currentHook = null, + nextCurrentHook = null, + firstWorkInProgressHook = null, + workInProgressHook = null, + nextWorkInProgressHook = null, + remainingExpirationTime = 0, + componentUpdateQueue = null, + sideEffectTag = 0, + didScheduleRenderPhaseUpdate = !1, + renderPhaseUpdates = null, + numberOfReRenders = 0; +function throwInvalidHookError() { + throw ReactError( + "Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:\n1. You might have mismatching versions of React and the renderer (such as React DOM)\n2. You might be breaking the Rules of Hooks\n3. You might have more than one copy of React in the same app\nSee https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem." + ); +} +function areHookInputsEqual(nextDeps, prevDeps) { + if (null === prevDeps) return !1; + for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++) + if (!is(nextDeps[i], prevDeps[i])) return !1; + return !0; +} +function renderWithHooks( + current, + workInProgress, + Component, + props, + refOrContext, + nextRenderExpirationTime +) { + renderExpirationTime$1 = nextRenderExpirationTime; + currentlyRenderingFiber$1 = workInProgress; + nextCurrentHook = null !== current ? current.memoizedState : null; + ReactCurrentDispatcher$1.current = + null === nextCurrentHook ? HooksDispatcherOnMount : HooksDispatcherOnUpdate; + workInProgress = Component(props, refOrContext); + if (didScheduleRenderPhaseUpdate) { + do + (didScheduleRenderPhaseUpdate = !1), + (numberOfReRenders += 1), + (nextCurrentHook = null !== current ? current.memoizedState : null), + (nextWorkInProgressHook = firstWorkInProgressHook), + (componentUpdateQueue = workInProgressHook = currentHook = null), + (ReactCurrentDispatcher$1.current = HooksDispatcherOnUpdate), + (workInProgress = Component(props, refOrContext)); + while (didScheduleRenderPhaseUpdate); + renderPhaseUpdates = null; + numberOfReRenders = 0; + } + ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; + current = currentlyRenderingFiber$1; + current.memoizedState = firstWorkInProgressHook; + current.expirationTime = remainingExpirationTime; + current.updateQueue = componentUpdateQueue; + current.effectTag |= sideEffectTag; + current = null !== currentHook && null !== currentHook.next; + renderExpirationTime$1 = 0; + nextWorkInProgressHook = workInProgressHook = firstWorkInProgressHook = nextCurrentHook = currentHook = currentlyRenderingFiber$1 = null; + remainingExpirationTime = 0; + componentUpdateQueue = null; + sideEffectTag = 0; + if (current) + throw ReactError( + "Rendered fewer hooks than expected. This may be caused by an accidental early return statement." + ); + return workInProgress; +} +function resetHooks() { + ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; + renderExpirationTime$1 = 0; + nextWorkInProgressHook = workInProgressHook = firstWorkInProgressHook = nextCurrentHook = currentHook = currentlyRenderingFiber$1 = null; + remainingExpirationTime = 0; + componentUpdateQueue = null; + sideEffectTag = 0; + didScheduleRenderPhaseUpdate = !1; + renderPhaseUpdates = null; + numberOfReRenders = 0; +} +function mountWorkInProgressHook() { + var hook = { + memoizedState: null, + baseState: null, + queue: null, + baseUpdate: null, + next: null + }; + null === workInProgressHook + ? (firstWorkInProgressHook = workInProgressHook = hook) + : (workInProgressHook = workInProgressHook.next = hook); + return workInProgressHook; +} +function updateWorkInProgressHook() { + if (null !== nextWorkInProgressHook) + (workInProgressHook = nextWorkInProgressHook), + (nextWorkInProgressHook = workInProgressHook.next), + (currentHook = nextCurrentHook), + (nextCurrentHook = null !== currentHook ? currentHook.next : null); + else { + if (null === nextCurrentHook) + throw ReactError("Rendered more hooks than during the previous render."); + currentHook = nextCurrentHook; + var newHook = { + memoizedState: currentHook.memoizedState, + baseState: currentHook.baseState, + queue: currentHook.queue, + baseUpdate: currentHook.baseUpdate, + next: null + }; + workInProgressHook = + null === workInProgressHook + ? (firstWorkInProgressHook = newHook) + : (workInProgressHook.next = newHook); + nextCurrentHook = currentHook.next; + } + return workInProgressHook; +} +function basicStateReducer(state, action) { + return "function" === typeof action ? action(state) : action; +} +function updateReducer(reducer) { + var hook = updateWorkInProgressHook(), + queue = hook.queue; + if (null === queue) + throw ReactError( + "Should have a queue. This is likely a bug in React. Please file an issue." + ); + queue.lastRenderedReducer = reducer; + if (0 < numberOfReRenders) { + var _dispatch = queue.dispatch; + if (null !== renderPhaseUpdates) { + var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue); + if (void 0 !== firstRenderPhaseUpdate) { + renderPhaseUpdates.delete(queue); + var newState = hook.memoizedState; + do + (newState = reducer(newState, firstRenderPhaseUpdate.action)), + (firstRenderPhaseUpdate = firstRenderPhaseUpdate.next); + while (null !== firstRenderPhaseUpdate); + is(newState, hook.memoizedState) || (didReceiveUpdate = !0); + hook.memoizedState = newState; + hook.baseUpdate === queue.last && (hook.baseState = newState); + queue.lastRenderedState = newState; + return [newState, _dispatch]; + } + } + return [hook.memoizedState, _dispatch]; + } + _dispatch = queue.last; + var baseUpdate = hook.baseUpdate; + newState = hook.baseState; + null !== baseUpdate + ? (null !== _dispatch && (_dispatch.next = null), + (_dispatch = baseUpdate.next)) + : (_dispatch = null !== _dispatch ? _dispatch.next : null); + if (null !== _dispatch) { + var newBaseUpdate = (firstRenderPhaseUpdate = null), + _update = _dispatch, + didSkip = !1; + do { + var updateExpirationTime = _update.expirationTime; + updateExpirationTime < renderExpirationTime$1 + ? (didSkip || + ((didSkip = !0), + (newBaseUpdate = baseUpdate), + (firstRenderPhaseUpdate = newState)), + updateExpirationTime > remainingExpirationTime && + (remainingExpirationTime = updateExpirationTime)) + : (updateExpirationTime < workInProgressRootMostRecentEventTime && + (workInProgressRootMostRecentEventTime = updateExpirationTime), + (newState = + _update.eagerReducer === reducer + ? _update.eagerState + : reducer(newState, _update.action))); + baseUpdate = _update; + _update = _update.next; + } while (null !== _update && _update !== _dispatch); + didSkip || + ((newBaseUpdate = baseUpdate), (firstRenderPhaseUpdate = newState)); + is(newState, hook.memoizedState) || (didReceiveUpdate = !0); + hook.memoizedState = newState; + hook.baseUpdate = newBaseUpdate; + hook.baseState = firstRenderPhaseUpdate; + queue.lastRenderedState = newState; + } + return [hook.memoizedState, queue.dispatch]; +} +function pushEffect(tag, create, destroy, deps) { + tag = { tag: tag, create: create, destroy: destroy, deps: deps, next: null }; + null === componentUpdateQueue + ? ((componentUpdateQueue = { lastEffect: null }), + (componentUpdateQueue.lastEffect = tag.next = tag)) + : ((create = componentUpdateQueue.lastEffect), + null === create + ? (componentUpdateQueue.lastEffect = tag.next = tag) + : ((destroy = create.next), + (create.next = tag), + (tag.next = destroy), + (componentUpdateQueue.lastEffect = tag))); + return tag; +} +function mountEffectImpl(fiberEffectTag, hookEffectTag, create, deps) { + var hook = mountWorkInProgressHook(); + sideEffectTag |= fiberEffectTag; + hook.memoizedState = pushEffect( + hookEffectTag, + create, + void 0, + void 0 === deps ? null : deps + ); +} +function updateEffectImpl(fiberEffectTag, hookEffectTag, create, deps) { + var hook = updateWorkInProgressHook(); + deps = void 0 === deps ? null : deps; + var destroy = void 0; + if (null !== currentHook) { + var prevEffect = currentHook.memoizedState; + destroy = prevEffect.destroy; + if (null !== deps && areHookInputsEqual(deps, prevEffect.deps)) { + pushEffect(NoEffect$1, create, destroy, deps); + return; + } + } + sideEffectTag |= fiberEffectTag; + hook.memoizedState = pushEffect(hookEffectTag, create, destroy, deps); +} +function imperativeHandleEffect(create, ref) { + if ("function" === typeof ref) + return ( + (create = create()), + ref(create), + function() { + ref(null); + } + ); + if (null !== ref && void 0 !== ref) + return ( + (create = create()), + (ref.current = create), + function() { + ref.current = null; + } + ); +} +function mountDebugValue() {} +function dispatchAction(fiber, queue, action) { + if (!(25 > numberOfReRenders)) + throw ReactError( + "Too many re-renders. React limits the number of renders to prevent an infinite loop." + ); + var alternate = fiber.alternate; + if ( + fiber === currentlyRenderingFiber$1 || + (null !== alternate && alternate === currentlyRenderingFiber$1) + ) + if ( + ((didScheduleRenderPhaseUpdate = !0), + (fiber = { + expirationTime: renderExpirationTime$1, + action: action, + eagerReducer: null, + eagerState: null, + next: null + }), + null === renderPhaseUpdates && (renderPhaseUpdates = new Map()), + (action = renderPhaseUpdates.get(queue)), + void 0 === action) + ) + renderPhaseUpdates.set(queue, fiber); + else { + for (queue = action; null !== queue.next; ) queue = queue.next; + queue.next = fiber; + } + else { + flushPassiveEffects(); + var currentTime = requestCurrentTime(); + currentTime = computeExpirationForFiber(currentTime, fiber); + var _update2 = { + expirationTime: currentTime, + action: action, + eagerReducer: null, + eagerState: null, + next: null + }, + _last = queue.last; + if (null === _last) _update2.next = _update2; + else { + var first = _last.next; + null !== first && (_update2.next = first); + _last.next = _update2; + } + queue.last = _update2; + if ( + 0 === fiber.expirationTime && + (null === alternate || 0 === alternate.expirationTime) && + ((alternate = queue.lastRenderedReducer), null !== alternate) + ) + try { + var currentState = queue.lastRenderedState, + _eagerState = alternate(currentState, action); + _update2.eagerReducer = alternate; + _update2.eagerState = _eagerState; + if (is(_eagerState, currentState)) return; + } catch (error) { + } finally { + } + scheduleUpdateOnFiber(fiber, currentTime); + } +} +var ContextOnlyDispatcher = { + readContext: readContext, + useCallback: throwInvalidHookError, + useContext: throwInvalidHookError, + useEffect: throwInvalidHookError, + useImperativeHandle: throwInvalidHookError, + useLayoutEffect: throwInvalidHookError, + useMemo: throwInvalidHookError, + useReducer: throwInvalidHookError, + useRef: throwInvalidHookError, + useState: throwInvalidHookError, + useDebugValue: throwInvalidHookError + }, + HooksDispatcherOnMount = { + readContext: readContext, + useCallback: function(callback, deps) { + mountWorkInProgressHook().memoizedState = [ + callback, + void 0 === deps ? null : deps + ]; + return callback; + }, + useContext: readContext, + useEffect: function(create, deps) { + return mountEffectImpl(516, UnmountPassive | MountPassive, create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + deps = null !== deps && void 0 !== deps ? deps.concat([ref]) : null; + return mountEffectImpl( + 4, + UnmountMutation | MountLayout, + imperativeHandleEffect.bind(null, create, ref), + deps + ); + }, + useLayoutEffect: function(create, deps) { + return mountEffectImpl(4, UnmountMutation | MountLayout, create, deps); + }, + useMemo: function(nextCreate, deps) { + var hook = mountWorkInProgressHook(); + deps = void 0 === deps ? null : deps; + nextCreate = nextCreate(); + hook.memoizedState = [nextCreate, deps]; + return nextCreate; + }, + useReducer: function(reducer, initialArg, init) { + var hook = mountWorkInProgressHook(); + initialArg = void 0 !== init ? init(initialArg) : initialArg; + hook.memoizedState = hook.baseState = initialArg; + reducer = hook.queue = { + last: null, + dispatch: null, + lastRenderedReducer: reducer, + lastRenderedState: initialArg + }; + reducer = reducer.dispatch = dispatchAction.bind( + null, + currentlyRenderingFiber$1, + reducer + ); + return [hook.memoizedState, reducer]; + }, + useRef: function(initialValue) { + var hook = mountWorkInProgressHook(); + initialValue = { current: initialValue }; + return (hook.memoizedState = initialValue); + }, + useState: function(initialState) { + var hook = mountWorkInProgressHook(); + "function" === typeof initialState && (initialState = initialState()); + hook.memoizedState = hook.baseState = initialState; + initialState = hook.queue = { + last: null, + dispatch: null, + lastRenderedReducer: basicStateReducer, + lastRenderedState: initialState + }; + initialState = initialState.dispatch = dispatchAction.bind( + null, + currentlyRenderingFiber$1, + initialState + ); + return [hook.memoizedState, initialState]; + }, + useDebugValue: mountDebugValue + }, + HooksDispatcherOnUpdate = { + readContext: readContext, + useCallback: function(callback, deps) { + var hook = updateWorkInProgressHook(); + deps = void 0 === deps ? null : deps; + var prevState = hook.memoizedState; + if ( + null !== prevState && + null !== deps && + areHookInputsEqual(deps, prevState[1]) + ) + return prevState[0]; + hook.memoizedState = [callback, deps]; + return callback; + }, + useContext: readContext, + useEffect: function(create, deps) { + return updateEffectImpl(516, UnmountPassive | MountPassive, create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + deps = null !== deps && void 0 !== deps ? deps.concat([ref]) : null; + return updateEffectImpl( + 4, + UnmountMutation | MountLayout, + imperativeHandleEffect.bind(null, create, ref), + deps + ); + }, + useLayoutEffect: function(create, deps) { + return updateEffectImpl(4, UnmountMutation | MountLayout, create, deps); + }, + useMemo: function(nextCreate, deps) { + var hook = updateWorkInProgressHook(); + deps = void 0 === deps ? null : deps; + var prevState = hook.memoizedState; + if ( + null !== prevState && + null !== deps && + areHookInputsEqual(deps, prevState[1]) + ) + return prevState[0]; + nextCreate = nextCreate(); + hook.memoizedState = [nextCreate, deps]; + return nextCreate; + }, + useReducer: updateReducer, + useRef: function() { + return updateWorkInProgressHook().memoizedState; + }, + useState: function(initialState) { + return updateReducer(basicStateReducer, initialState); + }, + useDebugValue: mountDebugValue + }, + hydrationParentFiber = null, + nextHydratableInstance = null, + isHydrating = !1; +function tryHydrate(fiber, nextInstance) { + switch (fiber.tag) { + case 5: + return ( + (nextInstance = shim$1(nextInstance, fiber.type, fiber.pendingProps)), + null !== nextInstance ? ((fiber.stateNode = nextInstance), !0) : !1 + ); + case 6: + return ( + (nextInstance = shim$1(nextInstance, fiber.pendingProps)), + null !== nextInstance ? ((fiber.stateNode = nextInstance), !0) : !1 + ); + case 13: + return !1; + default: + return !1; + } +} +function tryToClaimNextHydratableInstance(fiber$jscomp$0) { + if (isHydrating) { + var nextInstance = nextHydratableInstance; + if (nextInstance) { + var firstAttemptedInstance = nextInstance; + if (!tryHydrate(fiber$jscomp$0, nextInstance)) { + nextInstance = shim$1(firstAttemptedInstance); + if (!nextInstance || !tryHydrate(fiber$jscomp$0, nextInstance)) { + fiber$jscomp$0.effectTag |= 2; + isHydrating = !1; + hydrationParentFiber = fiber$jscomp$0; + return; + } + var returnFiber = hydrationParentFiber, + fiber = createFiber(5, null, null, 0); + fiber.elementType = "DELETED"; + fiber.type = "DELETED"; + fiber.stateNode = firstAttemptedInstance; + fiber.return = returnFiber; + fiber.effectTag = 8; + null !== returnFiber.lastEffect + ? ((returnFiber.lastEffect.nextEffect = fiber), + (returnFiber.lastEffect = fiber)) + : (returnFiber.firstEffect = returnFiber.lastEffect = fiber); + } + hydrationParentFiber = fiber$jscomp$0; + nextHydratableInstance = shim$1(nextInstance); + } else + (fiber$jscomp$0.effectTag |= 2), + (isHydrating = !1), + (hydrationParentFiber = fiber$jscomp$0); + } +} +var ReactCurrentOwner$3 = ReactSharedInternals.ReactCurrentOwner, + didReceiveUpdate = !1; +function reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime +) { + workInProgress.child = + null === current$$1 + ? mountChildFibers( + workInProgress, + null, + nextChildren, + renderExpirationTime + ) + : reconcileChildFibers( + workInProgress, + current$$1.child, + nextChildren, + renderExpirationTime + ); +} +function updateForwardRef( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + Component = Component.render; + var ref = workInProgress.ref; + prepareToReadContext(workInProgress, renderExpirationTime); + nextProps = renderWithHooks( + current$$1, + workInProgress, + Component, + nextProps, + ref, + renderExpirationTime + ); + if (null !== current$$1 && !didReceiveUpdate) + return ( + (workInProgress.updateQueue = current$$1.updateQueue), + (workInProgress.effectTag &= -517), + current$$1.expirationTime <= renderExpirationTime && + (current$$1.expirationTime = 0), + bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ) + ); + workInProgress.effectTag |= 1; + reconcileChildren( + current$$1, + workInProgress, + nextProps, + renderExpirationTime + ); + return workInProgress.child; +} +function updateMemoComponent( + current$$1, + workInProgress, + Component, + nextProps, + updateExpirationTime, + renderExpirationTime +) { + if (null === current$$1) { + var type = Component.type; + if ( + "function" === typeof type && + !shouldConstruct(type) && + void 0 === type.defaultProps && + null === Component.compare && + void 0 === Component.defaultProps + ) + return ( + (workInProgress.tag = 15), + (workInProgress.type = type), + updateSimpleMemoComponent( + current$$1, + workInProgress, + type, + nextProps, + updateExpirationTime, + renderExpirationTime + ) + ); + current$$1 = createFiberFromTypeAndProps( + Component.type, + null, + nextProps, + null, + workInProgress.mode, + renderExpirationTime + ); + current$$1.ref = workInProgress.ref; + current$$1.return = workInProgress; + return (workInProgress.child = current$$1); + } + type = current$$1.child; + if ( + updateExpirationTime < renderExpirationTime && + ((updateExpirationTime = type.memoizedProps), + (Component = Component.compare), + (Component = null !== Component ? Component : shallowEqual), + Component(updateExpirationTime, nextProps) && + current$$1.ref === workInProgress.ref) + ) + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + workInProgress.effectTag |= 1; + current$$1 = createWorkInProgress(type, nextProps, renderExpirationTime); + current$$1.ref = workInProgress.ref; + current$$1.return = workInProgress; + return (workInProgress.child = current$$1); +} +function updateSimpleMemoComponent( + current$$1, + workInProgress, + Component, + nextProps, + updateExpirationTime, + renderExpirationTime +) { + return null !== current$$1 && + shallowEqual(current$$1.memoizedProps, nextProps) && + current$$1.ref === workInProgress.ref && + ((didReceiveUpdate = !1), updateExpirationTime < renderExpirationTime) + ? bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ) + : updateFunctionComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime + ); +} +function markRef(current$$1, workInProgress) { + var ref = workInProgress.ref; + if ( + (null === current$$1 && null !== ref) || + (null !== current$$1 && current$$1.ref !== ref) + ) + workInProgress.effectTag |= 128; +} +function updateFunctionComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + var unmaskedContext = isContextProvider(Component) + ? previousContext + : contextStackCursor.current; + unmaskedContext = getMaskedContext(workInProgress, unmaskedContext); + prepareToReadContext(workInProgress, renderExpirationTime); + Component = renderWithHooks( + current$$1, + workInProgress, + Component, + nextProps, + unmaskedContext, + renderExpirationTime + ); + if (null !== current$$1 && !didReceiveUpdate) + return ( + (workInProgress.updateQueue = current$$1.updateQueue), + (workInProgress.effectTag &= -517), + current$$1.expirationTime <= renderExpirationTime && + (current$$1.expirationTime = 0), + bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ) + ); + workInProgress.effectTag |= 1; + reconcileChildren( + current$$1, + workInProgress, + Component, + renderExpirationTime + ); + return workInProgress.child; +} +function updateClassComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + if (isContextProvider(Component)) { + var hasContext = !0; + pushContextProvider(workInProgress); + } else hasContext = !1; + prepareToReadContext(workInProgress, renderExpirationTime); + if (null === workInProgress.stateNode) + null !== current$$1 && + ((current$$1.alternate = null), + (workInProgress.alternate = null), + (workInProgress.effectTag |= 2)), + constructClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ), + mountClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ), + (nextProps = !0); + else if (null === current$$1) { + var instance = workInProgress.stateNode, + oldProps = workInProgress.memoizedProps; + instance.props = oldProps; + var oldContext = instance.context, + contextType = Component.contextType; + "object" === typeof contextType && null !== contextType + ? (contextType = readContext(contextType)) + : ((contextType = isContextProvider(Component) + ? previousContext + : contextStackCursor.current), + (contextType = getMaskedContext(workInProgress, contextType))); + var getDerivedStateFromProps = Component.getDerivedStateFromProps, + hasNewLifecycles = + "function" === typeof getDerivedStateFromProps || + "function" === typeof instance.getSnapshotBeforeUpdate; + hasNewLifecycles || + ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && + "function" !== typeof instance.componentWillReceiveProps) || + ((oldProps !== nextProps || oldContext !== contextType) && + callComponentWillReceiveProps( + workInProgress, + instance, + nextProps, + contextType + )); + hasForceUpdate = !1; + var oldState = workInProgress.memoizedState; + oldContext = instance.state = oldState; + var updateQueue = workInProgress.updateQueue; + null !== updateQueue && + (processUpdateQueue( + workInProgress, + updateQueue, + nextProps, + instance, + renderExpirationTime + ), + (oldContext = workInProgress.memoizedState)); + oldProps !== nextProps || + oldState !== oldContext || + didPerformWorkStackCursor.current || + hasForceUpdate + ? ("function" === typeof getDerivedStateFromProps && + (applyDerivedStateFromProps( + workInProgress, + Component, + getDerivedStateFromProps, + nextProps + ), + (oldContext = workInProgress.memoizedState)), + (oldProps = + hasForceUpdate || + checkShouldComponentUpdate( + workInProgress, + Component, + oldProps, + nextProps, + oldState, + oldContext, + contextType + )) + ? (hasNewLifecycles || + ("function" !== typeof instance.UNSAFE_componentWillMount && + "function" !== typeof instance.componentWillMount) || + ("function" === typeof instance.componentWillMount && + instance.componentWillMount(), + "function" === typeof instance.UNSAFE_componentWillMount && + instance.UNSAFE_componentWillMount()), + "function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4)) + : ("function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4), + (workInProgress.memoizedProps = nextProps), + (workInProgress.memoizedState = oldContext)), + (instance.props = nextProps), + (instance.state = oldContext), + (instance.context = contextType), + (nextProps = oldProps)) + : ("function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4), + (nextProps = !1)); + } else + (instance = workInProgress.stateNode), + (oldProps = workInProgress.memoizedProps), + (instance.props = + workInProgress.type === workInProgress.elementType + ? oldProps + : resolveDefaultProps(workInProgress.type, oldProps)), + (oldContext = instance.context), + (contextType = Component.contextType), + "object" === typeof contextType && null !== contextType + ? (contextType = readContext(contextType)) + : ((contextType = isContextProvider(Component) + ? previousContext + : contextStackCursor.current), + (contextType = getMaskedContext(workInProgress, contextType))), + (getDerivedStateFromProps = Component.getDerivedStateFromProps), + (hasNewLifecycles = + "function" === typeof getDerivedStateFromProps || + "function" === typeof instance.getSnapshotBeforeUpdate) || + ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && + "function" !== typeof instance.componentWillReceiveProps) || + ((oldProps !== nextProps || oldContext !== contextType) && + callComponentWillReceiveProps( + workInProgress, + instance, + nextProps, + contextType + )), + (hasForceUpdate = !1), + (oldContext = workInProgress.memoizedState), + (oldState = instance.state = oldContext), + (updateQueue = workInProgress.updateQueue), + null !== updateQueue && + (processUpdateQueue( + workInProgress, + updateQueue, + nextProps, + instance, + renderExpirationTime + ), + (oldState = workInProgress.memoizedState)), + oldProps !== nextProps || + oldContext !== oldState || + didPerformWorkStackCursor.current || + hasForceUpdate + ? ("function" === typeof getDerivedStateFromProps && + (applyDerivedStateFromProps( + workInProgress, + Component, + getDerivedStateFromProps, + nextProps + ), + (oldState = workInProgress.memoizedState)), + (getDerivedStateFromProps = + hasForceUpdate || + checkShouldComponentUpdate( + workInProgress, + Component, + oldProps, + nextProps, + oldContext, + oldState, + contextType + )) + ? (hasNewLifecycles || + ("function" !== typeof instance.UNSAFE_componentWillUpdate && + "function" !== typeof instance.componentWillUpdate) || + ("function" === typeof instance.componentWillUpdate && + instance.componentWillUpdate( + nextProps, + oldState, + contextType + ), + "function" === typeof instance.UNSAFE_componentWillUpdate && + instance.UNSAFE_componentWillUpdate( + nextProps, + oldState, + contextType + )), + "function" === typeof instance.componentDidUpdate && + (workInProgress.effectTag |= 4), + "function" === typeof instance.getSnapshotBeforeUpdate && + (workInProgress.effectTag |= 256)) + : ("function" !== typeof instance.componentDidUpdate || + (oldProps === current$$1.memoizedProps && + oldContext === current$$1.memoizedState) || + (workInProgress.effectTag |= 4), + "function" !== typeof instance.getSnapshotBeforeUpdate || + (oldProps === current$$1.memoizedProps && + oldContext === current$$1.memoizedState) || + (workInProgress.effectTag |= 256), + (workInProgress.memoizedProps = nextProps), + (workInProgress.memoizedState = oldState)), + (instance.props = nextProps), + (instance.state = oldState), + (instance.context = contextType), + (nextProps = getDerivedStateFromProps)) + : ("function" !== typeof instance.componentDidUpdate || + (oldProps === current$$1.memoizedProps && + oldContext === current$$1.memoizedState) || + (workInProgress.effectTag |= 4), + "function" !== typeof instance.getSnapshotBeforeUpdate || + (oldProps === current$$1.memoizedProps && + oldContext === current$$1.memoizedState) || + (workInProgress.effectTag |= 256), + (nextProps = !1)); + return finishClassComponent( + current$$1, + workInProgress, + Component, + nextProps, + hasContext, + renderExpirationTime + ); +} +function finishClassComponent( + current$$1, + workInProgress, + Component, + shouldUpdate, + hasContext, + renderExpirationTime +) { + markRef(current$$1, workInProgress); + var didCaptureError = 0 !== (workInProgress.effectTag & 64); + if (!shouldUpdate && !didCaptureError) + return ( + hasContext && invalidateContextProvider(workInProgress, Component, !1), + bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ) + ); + shouldUpdate = workInProgress.stateNode; + ReactCurrentOwner$3.current = workInProgress; + var nextChildren = + didCaptureError && "function" !== typeof Component.getDerivedStateFromError + ? null + : shouldUpdate.render(); + workInProgress.effectTag |= 1; + null !== current$$1 && didCaptureError + ? ((workInProgress.child = reconcileChildFibers( + workInProgress, + current$$1.child, + null, + renderExpirationTime + )), + (workInProgress.child = reconcileChildFibers( + workInProgress, + null, + nextChildren, + renderExpirationTime + ))) + : reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + workInProgress.memoizedState = shouldUpdate.state; + hasContext && invalidateContextProvider(workInProgress, Component, !0); + return workInProgress.child; +} +function pushHostRootContext(workInProgress) { + var root = workInProgress.stateNode; + root.pendingContext + ? pushTopLevelContextObject( + workInProgress, + root.pendingContext, + root.pendingContext !== root.context + ) + : root.context && + pushTopLevelContextObject(workInProgress, root.context, !1); + pushHostContainer(workInProgress, root.containerInfo); +} +function updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime +) { + var mode = workInProgress.mode, + nextProps = workInProgress.pendingProps, + nextState = workInProgress.memoizedState; + if (0 === (workInProgress.effectTag & 64)) { + nextState = null; + var nextDidTimeout = !1; + } else + (nextState = { + fallbackExpirationTime: + null !== nextState ? nextState.fallbackExpirationTime : 0 + }), + (nextDidTimeout = !0), + (workInProgress.effectTag &= -65); + if (null === current$$1) + if (nextDidTimeout) { + var nextFallbackChildren = nextProps.fallback; + current$$1 = createFiberFromFragment(null, mode, 0, null); + 0 === (workInProgress.mode & 1) && + (current$$1.child = + null !== workInProgress.memoizedState + ? workInProgress.child.child + : workInProgress.child); + mode = createFiberFromFragment( + nextFallbackChildren, + mode, + renderExpirationTime, + null + ); + current$$1.sibling = mode; + renderExpirationTime = current$$1; + renderExpirationTime.return = mode.return = workInProgress; + } else + renderExpirationTime = mode = mountChildFibers( + workInProgress, + null, + nextProps.children, + renderExpirationTime + ); + else + null !== current$$1.memoizedState + ? ((mode = current$$1.child), + (nextFallbackChildren = mode.sibling), + nextDidTimeout + ? ((renderExpirationTime = nextProps.fallback), + (nextProps = createWorkInProgress(mode, mode.pendingProps, 0)), + 0 === (workInProgress.mode & 1) && + ((nextDidTimeout = + null !== workInProgress.memoizedState + ? workInProgress.child.child + : workInProgress.child), + nextDidTimeout !== mode.child && + (nextProps.child = nextDidTimeout)), + (mode = nextProps.sibling = createWorkInProgress( + nextFallbackChildren, + renderExpirationTime, + nextFallbackChildren.expirationTime + )), + (renderExpirationTime = nextProps), + (nextProps.childExpirationTime = 0), + (renderExpirationTime.return = mode.return = workInProgress)) + : (renderExpirationTime = mode = reconcileChildFibers( + workInProgress, + mode.child, + nextProps.children, + renderExpirationTime + ))) + : ((nextFallbackChildren = current$$1.child), + nextDidTimeout + ? ((nextDidTimeout = nextProps.fallback), + (nextProps = createFiberFromFragment(null, mode, 0, null)), + (nextProps.child = nextFallbackChildren), + 0 === (workInProgress.mode & 1) && + (nextProps.child = + null !== workInProgress.memoizedState + ? workInProgress.child.child + : workInProgress.child), + (mode = nextProps.sibling = createFiberFromFragment( + nextDidTimeout, + mode, + renderExpirationTime, + null + )), + (mode.effectTag |= 2), + (renderExpirationTime = nextProps), + (nextProps.childExpirationTime = 0), + (renderExpirationTime.return = mode.return = workInProgress)) + : (mode = renderExpirationTime = reconcileChildFibers( + workInProgress, + nextFallbackChildren, + nextProps.children, + renderExpirationTime + ))), + (workInProgress.stateNode = current$$1.stateNode); + workInProgress.memoizedState = nextState; + workInProgress.child = renderExpirationTime; + return mode; +} +function bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime +) { + null !== current$$1 && + (workInProgress.contextDependencies = current$$1.contextDependencies); + if (workInProgress.childExpirationTime < renderExpirationTime) return null; + if (null !== current$$1 && workInProgress.child !== current$$1.child) + throw ReactError("Resuming work not yet implemented."); + if (null !== workInProgress.child) { + current$$1 = workInProgress.child; + renderExpirationTime = createWorkInProgress( + current$$1, + current$$1.pendingProps, + current$$1.expirationTime + ); + workInProgress.child = renderExpirationTime; + for ( + renderExpirationTime.return = workInProgress; + null !== current$$1.sibling; + + ) + (current$$1 = current$$1.sibling), + (renderExpirationTime = renderExpirationTime.sibling = createWorkInProgress( + current$$1, + current$$1.pendingProps, + current$$1.expirationTime + )), + (renderExpirationTime.return = workInProgress); + renderExpirationTime.sibling = null; + } + return workInProgress.child; +} +var appendAllChildren = void 0, + updateHostContainer = void 0, + updateHostComponent$1 = void 0, + updateHostText$1 = void 0; +appendAllChildren = function( + parent, + workInProgress, + needsVisibilityToggle, + isHidden +) { + for (var node = workInProgress.child; null !== node; ) { + if (5 === node.tag) { + var instance = node.stateNode; + needsVisibilityToggle && + isHidden && + (instance = cloneHiddenInstance( + instance, + node.type, + node.memoizedProps, + node + )); + appendChildNode(parent.node, instance.node); + } else if (6 === node.tag) { + instance = node.stateNode; + if (needsVisibilityToggle && isHidden) + throw Error("Not yet implemented."); + appendChildNode(parent.node, instance.node); + } else if (4 !== node.tag) { + if ( + 13 === node.tag && + 0 !== (node.effectTag & 4) && + (instance = null !== node.memoizedState) + ) { + var primaryChildParent = node.child; + if ( + null !== primaryChildParent && + (null !== primaryChildParent.child && + ((primaryChildParent.child.return = primaryChildParent), + appendAllChildren(parent, primaryChildParent, !0, instance)), + (instance = primaryChildParent.sibling), + null !== instance) + ) { + instance.return = node; + node = instance; + continue; + } + } + if (null !== node.child) { + node.child.return = node; + node = node.child; + continue; + } + } + if (node === workInProgress) break; + for (; null === node.sibling; ) { + if (null === node.return || node.return === workInProgress) return; + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } +}; +function appendAllChildrenToContainer( + containerChildSet, + workInProgress, + needsVisibilityToggle, + isHidden +) { + for (var node = workInProgress.child; null !== node; ) { + if (5 === node.tag) { + var instance = node.stateNode; + needsVisibilityToggle && + isHidden && + (instance = cloneHiddenInstance( + instance, + node.type, + node.memoizedProps, + node + )); + appendChildNodeToSet(containerChildSet, instance.node); + } else if (6 === node.tag) { + instance = node.stateNode; + if (needsVisibilityToggle && isHidden) + throw Error("Not yet implemented."); + appendChildNodeToSet(containerChildSet, instance.node); + } else if (4 !== node.tag) { + if ( + 13 === node.tag && + 0 !== (node.effectTag & 4) && + (instance = null !== node.memoizedState) + ) { + var primaryChildParent = node.child; + if ( + null !== primaryChildParent && + (null !== primaryChildParent.child && + ((primaryChildParent.child.return = primaryChildParent), + appendAllChildrenToContainer( + containerChildSet, + primaryChildParent, + !0, + instance + )), + (instance = primaryChildParent.sibling), + null !== instance) + ) { + instance.return = node; + node = instance; + continue; + } + } + if (null !== node.child) { + node.child.return = node; + node = node.child; + continue; + } + } + if (node === workInProgress) break; + for (; null === node.sibling; ) { + if (null === node.return || node.return === workInProgress) return; + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } +} +updateHostContainer = function(workInProgress) { + var portalOrRoot = workInProgress.stateNode; + if (null !== workInProgress.firstEffect) { + var container = portalOrRoot.containerInfo, + newChildSet = createChildNodeSet(container); + appendAllChildrenToContainer(newChildSet, workInProgress, !1, !1); + portalOrRoot.pendingChildren = newChildSet; + workInProgress.effectTag |= 4; + completeRoot(container, newChildSet); + } +}; +updateHostComponent$1 = function(current, workInProgress, type, newProps) { + type = current.stateNode; + var oldProps = current.memoizedProps; + if ((current = null === workInProgress.firstEffect) && oldProps === newProps) + workInProgress.stateNode = type; + else { + var recyclableInstance = workInProgress.stateNode; + requiredContext(contextStackCursor$1.current); + var updatePayload = null; + oldProps !== newProps && + ((oldProps = diffProperties( + null, + oldProps, + newProps, + recyclableInstance.canonical.viewConfig.validAttributes + )), + (recyclableInstance.canonical.currentProps = newProps), + (updatePayload = oldProps)); + current && null === updatePayload + ? (workInProgress.stateNode = type) + : ((newProps = updatePayload), + (recyclableInstance = type.node), + (type = { + node: current + ? null !== newProps + ? cloneNodeWithNewProps(recyclableInstance, newProps) + : cloneNode(recyclableInstance) + : null !== newProps + ? cloneNodeWithNewChildrenAndProps(recyclableInstance, newProps) + : cloneNodeWithNewChildren(recyclableInstance), + canonical: type.canonical + }), + (workInProgress.stateNode = type), + current + ? (workInProgress.effectTag |= 4) + : appendAllChildren(type, workInProgress, !1, !1)); + } +}; +updateHostText$1 = function(current, workInProgress, oldText, newText) { + oldText !== newText && + ((current = requiredContext(rootInstanceStackCursor.current)), + (oldText = requiredContext(contextStackCursor$1.current)), + (workInProgress.stateNode = createTextInstance( + newText, + current, + oldText, + workInProgress + )), + (workInProgress.effectTag |= 4)); +}; +function createCapturedValue(value, source) { + return { + value: value, + source: source, + stack: getStackByFiberInDevAndProd(source) + }; +} +function logCapturedError(capturedError) { + var componentStack = capturedError.componentStack, + error = capturedError.error; + if (error instanceof Error) { + capturedError = error.message; + var name = error.name; + try { + error.message = + (capturedError ? name + ": " + capturedError : name) + + "\n\nThis error is located at:" + + componentStack; + } catch (e) {} + } else + error = + "string" === typeof error + ? Error(error + "\n\nThis error is located at:" + componentStack) + : Error("Unspecified error at:" + componentStack); + ReactNativePrivateInterface.ExceptionsManager.handleException(error, !1); +} +var PossiblyWeakSet$1 = "function" === typeof WeakSet ? WeakSet : Set; +function logError(boundary, errorInfo) { + var source = errorInfo.source, + stack = errorInfo.stack; + null === stack && + null !== source && + (stack = getStackByFiberInDevAndProd(source)); + errorInfo = { + componentName: null !== source ? getComponentName(source.type) : null, + componentStack: null !== stack ? stack : "", + error: errorInfo.value, + errorBoundary: null, + errorBoundaryName: null, + errorBoundaryFound: !1, + willRetry: !1 + }; + null !== boundary && + 1 === boundary.tag && + ((errorInfo.errorBoundary = boundary.stateNode), + (errorInfo.errorBoundaryName = getComponentName(boundary.type)), + (errorInfo.errorBoundaryFound = !0), + (errorInfo.willRetry = !0)); + try { + logCapturedError(errorInfo); + } catch (e) { + setTimeout(function() { + throw e; + }); + } +} +function safelyDetachRef(current$$1) { + var ref = current$$1.ref; + if (null !== ref) + if ("function" === typeof ref) + try { + ref(null); + } catch (refError) { + captureCommitPhaseError(current$$1, refError); + } + else ref.current = null; +} +function commitHookEffectList(unmountTag, mountTag, finishedWork) { + finishedWork = finishedWork.updateQueue; + finishedWork = null !== finishedWork ? finishedWork.lastEffect : null; + if (null !== finishedWork) { + var effect = (finishedWork = finishedWork.next); + do { + if ((effect.tag & unmountTag) !== NoEffect$1) { + var destroy = effect.destroy; + effect.destroy = void 0; + void 0 !== destroy && destroy(); + } + (effect.tag & mountTag) !== NoEffect$1 && + ((destroy = effect.create), (effect.destroy = destroy())); + effect = effect.next; + } while (effect !== finishedWork); + } +} +function commitWork(current$$1, finishedWork) { + switch (finishedWork.tag) { + case 0: + case 11: + case 14: + case 15: + commitHookEffectList(UnmountMutation, MountMutation, finishedWork); + return; + case 12: + return; + case 13: + commitSuspenseComponent(finishedWork); + return; + } + switch (finishedWork.tag) { + case 1: + case 5: + case 6: + case 20: + case 19: + break; + case 3: + case 4: + break; + default: + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } +} +function commitSuspenseComponent(finishedWork) { + var newState = finishedWork.memoizedState; + null !== newState && + 0 === newState.fallbackExpirationTime && + (newState.fallbackExpirationTime = requestCurrentTime() - 500); + newState = finishedWork.updateQueue; + if (null !== newState) { + finishedWork.updateQueue = null; + var retryCache = finishedWork.stateNode; + null === retryCache && + (retryCache = finishedWork.stateNode = new PossiblyWeakSet$1()); + newState.forEach(function(thenable) { + var retry = resolveRetryThenable.bind(null, finishedWork, thenable); + retryCache.has(thenable) || + (retryCache.add(thenable), thenable.then(retry, retry)); + }); + } +} +var PossiblyWeakMap = "function" === typeof WeakMap ? WeakMap : Map; +function createRootErrorUpdate(fiber, errorInfo, expirationTime) { + expirationTime = createUpdate(expirationTime); + expirationTime.tag = 3; + expirationTime.payload = { element: null }; + var error = errorInfo.value; + expirationTime.callback = function() { + hasUncaughtError || ((hasUncaughtError = !0), (firstUncaughtError = error)); + logError(fiber, errorInfo); + }; + return expirationTime; +} +function createClassErrorUpdate(fiber, errorInfo, expirationTime) { + expirationTime = createUpdate(expirationTime); + expirationTime.tag = 3; + var getDerivedStateFromError = fiber.type.getDerivedStateFromError; + if ("function" === typeof getDerivedStateFromError) { + var error$jscomp$0 = errorInfo.value; + expirationTime.payload = function() { + return getDerivedStateFromError(error$jscomp$0); + }; + } + var inst = fiber.stateNode; + null !== inst && + "function" === typeof inst.componentDidCatch && + (expirationTime.callback = function() { + "function" !== typeof getDerivedStateFromError && + (null === legacyErrorBoundariesThatAlreadyFailed + ? (legacyErrorBoundariesThatAlreadyFailed = new Set([this])) + : legacyErrorBoundariesThatAlreadyFailed.add(this)); + var error = errorInfo.value, + stack = errorInfo.stack; + logError(fiber, errorInfo); + this.componentDidCatch(error, { + componentStack: null !== stack ? stack : "" + }); + }); + return expirationTime; +} +function unwindWork(workInProgress) { + switch (workInProgress.tag) { + case 1: + isContextProvider(workInProgress.type) && popContext(workInProgress); + var effectTag = workInProgress.effectTag; + return effectTag & 2048 + ? ((workInProgress.effectTag = (effectTag & -2049) | 64), + workInProgress) + : null; + case 3: + popHostContainer(workInProgress); + popTopLevelContextObject(workInProgress); + effectTag = workInProgress.effectTag; + if (0 !== (effectTag & 64)) + throw ReactError( + "The root failed to unmount after an error. This is likely a bug in React. Please file an issue." + ); + workInProgress.effectTag = (effectTag & -2049) | 64; + return workInProgress; + case 5: + return popHostContext(workInProgress), null; + case 13: + return ( + (effectTag = workInProgress.effectTag), + effectTag & 2048 + ? ((workInProgress.effectTag = (effectTag & -2049) | 64), + workInProgress) + : null + ); + case 18: + return null; + case 4: + return popHostContainer(workInProgress), null; + case 10: + return popProvider(workInProgress), null; + case 19: + case 20: + return null; + default: + return null; + } +} +var ceil = Math.ceil, + ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher, + ReactCurrentOwner$2 = ReactSharedInternals.ReactCurrentOwner, + LegacyUnbatchedPhase = 2, + RenderPhase = 4, + CommitPhase = 5, + RootIncomplete = 0, + RootErrored = 1, + RootSuspended = 2, + RootCompleted = 3, + workPhase = 0, + workInProgressRoot = null, + workInProgress = null, + renderExpirationTime = 0, + workInProgressRootExitStatus = RootIncomplete, + workInProgressRootMostRecentEventTime = 1073741823, + nextEffect = null, + hasUncaughtError = !1, + firstUncaughtError = null, + legacyErrorBoundariesThatAlreadyFailed = null, + rootDoesHavePassiveEffects = !1, + rootWithPendingPassiveEffects = null, + rootsWithPendingDiscreteUpdates = null, + nestedUpdateCount = 0, + rootWithNestedUpdates = null, + currentEventTime = 0; +function requestCurrentTime() { + return workPhase === RenderPhase || workPhase === CommitPhase + ? 1073741822 - ((now() / 10) | 0) + : 0 !== currentEventTime + ? currentEventTime + : (currentEventTime = 1073741822 - ((now() / 10) | 0)); +} +function computeExpirationForFiber(currentTime, fiber) { + if (0 === (fiber.mode & 1)) return 1073741823; + if (workPhase === RenderPhase) return renderExpirationTime; + switch (getCurrentPriorityLevel()) { + case 99: + currentTime = 1073741823; + break; + case 98: + currentTime = + 1073741822 - 10 * ((((1073741822 - currentTime + 15) / 10) | 0) + 1); + break; + case 97: + case 96: + currentTime = + 1073741822 - 25 * ((((1073741822 - currentTime + 500) / 25) | 0) + 1); + break; + case 95: + currentTime = 1; + break; + default: + throw ReactError("Expected a valid priority level"); + } + null !== workInProgressRoot && + currentTime === renderExpirationTime && + --currentTime; + return currentTime; +} +function scheduleUpdateOnFiber(fiber, expirationTime) { + if (50 < nestedUpdateCount) + throw ((nestedUpdateCount = 0), + (rootWithNestedUpdates = null), + ReactError( + "Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops." + )); + fiber = markUpdateTimeFromFiberToRoot(fiber, expirationTime); + if (null !== fiber) + if (((fiber.pingTime = 0), 1073741823 === expirationTime)) + if (workPhase === LegacyUnbatchedPhase) + for ( + expirationTime = renderRoot(fiber, 1073741823, !0); + null !== expirationTime; + + ) + expirationTime = expirationTime(!0); + else + scheduleCallbackForRoot(fiber, 99, 1073741823), + 0 === workPhase && flushImmediateQueue(); + else { + var priorityLevel = getCurrentPriorityLevel(); + if (98 === priorityLevel) + if (null === rootsWithPendingDiscreteUpdates) + rootsWithPendingDiscreteUpdates = new Map([[fiber, expirationTime]]); + else { + var lastDiscreteTime = rootsWithPendingDiscreteUpdates.get(fiber); + (void 0 === lastDiscreteTime || lastDiscreteTime > expirationTime) && + rootsWithPendingDiscreteUpdates.set(fiber, expirationTime); + } + scheduleCallbackForRoot(fiber, priorityLevel, expirationTime); + } +} +function markUpdateTimeFromFiberToRoot(fiber, expirationTime) { + fiber.expirationTime < expirationTime && + (fiber.expirationTime = expirationTime); + var alternate = fiber.alternate; + null !== alternate && + alternate.expirationTime < expirationTime && + (alternate.expirationTime = expirationTime); + var node = fiber.return, + root = null; + if (null === node && 3 === fiber.tag) root = fiber.stateNode; + else + for (; null !== node; ) { + alternate = node.alternate; + node.childExpirationTime < expirationTime && + (node.childExpirationTime = expirationTime); + null !== alternate && + alternate.childExpirationTime < expirationTime && + (alternate.childExpirationTime = expirationTime); + if (null === node.return && 3 === node.tag) { + root = node.stateNode; + break; + } + node = node.return; + } + null !== root && + (expirationTime > root.firstPendingTime && + (root.firstPendingTime = expirationTime), + (fiber = root.lastPendingTime), + 0 === fiber || expirationTime < fiber) && + (root.lastPendingTime = expirationTime); + return root; +} +function scheduleCallbackForRoot(root, priorityLevel, expirationTime) { + if (root.callbackExpirationTime < expirationTime) { + var existingCallbackNode = root.callbackNode; + null !== existingCallbackNode && + existingCallbackNode !== fakeCallbackNode && + Scheduler_cancelCallback(existingCallbackNode); + root.callbackExpirationTime = expirationTime; + existingCallbackNode = null; + 1073741823 !== expirationTime && + 1 !== expirationTime && + ((existingCallbackNode = 10 * (1073741822 - expirationTime) - now()), + 5e3 < existingCallbackNode && (existingCallbackNode = 5e3), + (existingCallbackNode = { timeout: existingCallbackNode })); + root.callbackNode = scheduleCallback( + priorityLevel, + runRootCallback.bind( + null, + root, + renderRoot.bind(null, root, expirationTime) + ), + existingCallbackNode + ); + } +} +function runRootCallback(root, callback, isSync) { + var prevCallbackNode = root.callbackNode, + continuation = null; + try { + return ( + (continuation = callback(isSync)), + null !== continuation + ? runRootCallback.bind(null, root, continuation) + : null + ); + } finally { + null === continuation && + prevCallbackNode === root.callbackNode && + ((root.callbackNode = null), (root.callbackExpirationTime = 0)); + } +} +function resolveLocksOnRoot(root, expirationTime) { + var firstBatch = root.firstBatch; + return null !== firstBatch && + firstBatch._defer && + firstBatch._expirationTime >= expirationTime + ? ((root.finishedWork = root.current.alternate), + (root.pendingCommitExpirationTime = expirationTime), + scheduleCallback(97, function() { + firstBatch._onComplete(); + return null; + }), + !0) + : !1; +} +function flushPendingDiscreteUpdates() { + if (null !== rootsWithPendingDiscreteUpdates) { + var roots = rootsWithPendingDiscreteUpdates; + rootsWithPendingDiscreteUpdates = null; + roots.forEach(function(expirationTime, root) { + scheduleCallback(99, renderRoot.bind(null, root, expirationTime)); + }); + flushImmediateQueue(); + } +} +function prepareFreshStack(root, expirationTime) { + root.pendingCommitExpirationTime = 0; + var timeoutHandle = root.timeoutHandle; + -1 !== timeoutHandle && + ((root.timeoutHandle = -1), cancelTimeout(timeoutHandle)); + if (null !== workInProgress) + for (timeoutHandle = workInProgress.return; null !== timeoutHandle; ) { + var interruptedWork = timeoutHandle; + switch (interruptedWork.tag) { + case 1: + var childContextTypes = interruptedWork.type.childContextTypes; + null !== childContextTypes && + void 0 !== childContextTypes && + popContext(interruptedWork); + break; + case 3: + popHostContainer(interruptedWork); + popTopLevelContextObject(interruptedWork); + break; + case 5: + popHostContext(interruptedWork); + break; + case 4: + popHostContainer(interruptedWork); + break; + case 10: + popProvider(interruptedWork); + } + timeoutHandle = timeoutHandle.return; + } + workInProgressRoot = root; + workInProgress = createWorkInProgress(root.current, null, expirationTime); + renderExpirationTime = expirationTime; + workInProgressRootExitStatus = RootIncomplete; + workInProgressRootMostRecentEventTime = 1073741823; +} +function renderRoot(root$jscomp$0, expirationTime, isSync) { + if (workPhase === RenderPhase || workPhase === CommitPhase) + throw ReactError("Should not already be working."); + if (root$jscomp$0.firstPendingTime < expirationTime) return null; + if (root$jscomp$0.pendingCommitExpirationTime === expirationTime) + return ( + (root$jscomp$0.pendingCommitExpirationTime = 0), + commitRoot.bind(null, root$jscomp$0, expirationTime) + ); + flushPassiveEffects(); + (root$jscomp$0 === workInProgressRoot && + expirationTime === renderExpirationTime) || + prepareFreshStack(root$jscomp$0, expirationTime); + if (null !== workInProgress) { + var prevWorkPhase = workPhase; + workPhase = RenderPhase; + var prevDispatcher = ReactCurrentDispatcher.current; + null === prevDispatcher && (prevDispatcher = ContextOnlyDispatcher); + ReactCurrentDispatcher.current = ContextOnlyDispatcher; + if (isSync) { + if (1073741823 !== expirationTime) { + var currentTime = requestCurrentTime(); + if (currentTime < expirationTime) + return ( + (workPhase = prevWorkPhase), + resetContextDependences(), + (ReactCurrentDispatcher.current = prevDispatcher), + renderRoot.bind(null, root$jscomp$0, currentTime) + ); + } + } else currentEventTime = 0; + do + try { + if (isSync) + for (; null !== workInProgress; ) + workInProgress = performUnitOfWork(workInProgress); + else + for (; null !== workInProgress && !shouldYield(); ) + workInProgress = performUnitOfWork(workInProgress); + break; + } catch (thrownValue) { + resetContextDependences(); + resetHooks(); + currentTime = workInProgress; + if (null === currentTime || null === currentTime.return) + throw (prepareFreshStack(root$jscomp$0, expirationTime), + (workPhase = prevWorkPhase), + thrownValue); + a: { + var root = root$jscomp$0, + returnFiber = currentTime.return, + sourceFiber = currentTime, + value = thrownValue, + renderExpirationTime$jscomp$0 = renderExpirationTime; + sourceFiber.effectTag |= 1024; + sourceFiber.firstEffect = sourceFiber.lastEffect = null; + if ( + null !== value && + "object" === typeof value && + "function" === typeof value.then + ) { + var thenable = value; + value = returnFiber; + do { + if ( + 13 === value.tag && + (void 0 === value.memoizedProps.fallback + ? 0 + : null === value.memoizedState) + ) { + returnFiber = value.updateQueue; + null === returnFiber + ? ((returnFiber = new Set()), + returnFiber.add(thenable), + (value.updateQueue = returnFiber)) + : returnFiber.add(thenable); + if (0 === (value.mode & 1)) { + value.effectTag |= 64; + sourceFiber.effectTag &= -1957; + 1 === sourceFiber.tag && + (null === sourceFiber.alternate + ? (sourceFiber.tag = 17) + : ((renderExpirationTime$jscomp$0 = createUpdate( + 1073741823 + )), + (renderExpirationTime$jscomp$0.tag = 2), + enqueueUpdate( + sourceFiber, + renderExpirationTime$jscomp$0 + ))); + sourceFiber.expirationTime = 1073741823; + break a; + } + sourceFiber = root; + root = renderExpirationTime$jscomp$0; + var pingCache = sourceFiber.pingCache; + null === pingCache + ? ((pingCache = sourceFiber.pingCache = new PossiblyWeakMap()), + (returnFiber = new Set()), + pingCache.set(thenable, returnFiber)) + : ((returnFiber = pingCache.get(thenable)), + void 0 === returnFiber && + ((returnFiber = new Set()), + pingCache.set(thenable, returnFiber))); + returnFiber.has(root) || + (returnFiber.add(root), + (sourceFiber = pingSuspendedRoot.bind( + null, + sourceFiber, + thenable, + root + )), + thenable.then(sourceFiber, sourceFiber)); + value.effectTag |= 2048; + value.expirationTime = renderExpirationTime$jscomp$0; + break a; + } + value = value.return; + } while (null !== value); + value = Error( + (getComponentName(sourceFiber.type) || "A React component") + + " suspended while rendering, but no fallback UI was specified.\n\nAdd a component higher in the tree to provide a loading indicator or placeholder to display." + + getStackByFiberInDevAndProd(sourceFiber) + ); + } + if ( + workInProgressRootExitStatus === RootIncomplete || + workInProgressRootExitStatus === RootSuspended + ) + workInProgressRootExitStatus = RootErrored; + value = createCapturedValue(value, sourceFiber); + sourceFiber = returnFiber; + do { + switch (sourceFiber.tag) { + case 3: + sourceFiber.effectTag |= 2048; + sourceFiber.expirationTime = renderExpirationTime$jscomp$0; + renderExpirationTime$jscomp$0 = createRootErrorUpdate( + sourceFiber, + value, + renderExpirationTime$jscomp$0 + ); + enqueueCapturedUpdate( + sourceFiber, + renderExpirationTime$jscomp$0 + ); + break a; + case 1: + if ( + ((thenable = value), + (root = sourceFiber.type), + (returnFiber = sourceFiber.stateNode), + 0 === (sourceFiber.effectTag & 64) && + ("function" === typeof root.getDerivedStateFromError || + (null !== returnFiber && + "function" === typeof returnFiber.componentDidCatch && + (null === legacyErrorBoundariesThatAlreadyFailed || + !legacyErrorBoundariesThatAlreadyFailed.has( + returnFiber + ))))) + ) { + sourceFiber.effectTag |= 2048; + sourceFiber.expirationTime = renderExpirationTime$jscomp$0; + renderExpirationTime$jscomp$0 = createClassErrorUpdate( + sourceFiber, + thenable, + renderExpirationTime$jscomp$0 + ); + enqueueCapturedUpdate( + sourceFiber, + renderExpirationTime$jscomp$0 + ); + break a; + } + } + sourceFiber = sourceFiber.return; + } while (null !== sourceFiber); + } + workInProgress = completeUnitOfWork(currentTime); + } + while (1); + workPhase = prevWorkPhase; + resetContextDependences(); + ReactCurrentDispatcher.current = prevDispatcher; + if (null !== workInProgress) + return renderRoot.bind(null, root$jscomp$0, expirationTime); + } + if (resolveLocksOnRoot(root$jscomp$0, expirationTime)) return null; + workInProgressRoot = null; + switch (workInProgressRootExitStatus) { + case RootIncomplete: + throw ReactError("Should have a work-in-progress."); + case RootErrored: + return ( + (prevWorkPhase = root$jscomp$0.lastPendingTime), + root$jscomp$0.lastPendingTime < expirationTime + ? renderRoot.bind(null, root$jscomp$0, prevWorkPhase) + : isSync + ? commitRoot.bind(null, root$jscomp$0, expirationTime) + : (prepareFreshStack(root$jscomp$0, expirationTime), + scheduleCallback( + 99, + renderRoot.bind(null, root$jscomp$0, expirationTime) + ), + null) + ); + case RootSuspended: + if (!isSync) { + isSync = root$jscomp$0.lastPendingTime; + if (root$jscomp$0.lastPendingTime < expirationTime) + return renderRoot.bind(null, root$jscomp$0, isSync); + if ( + 1073741823 !== workInProgressRootMostRecentEventTime && + ((prevWorkPhase = + 10 * (1073741822 - workInProgressRootMostRecentEventTime) - 5e3), + (isSync = now()), + (prevWorkPhase = isSync - prevWorkPhase), + (prevWorkPhase = + (120 > prevWorkPhase + ? 120 + : 480 > prevWorkPhase + ? 480 + : 1080 > prevWorkPhase + ? 1080 + : 1920 > prevWorkPhase + ? 1920 + : 3e3 > prevWorkPhase + ? 3e3 + : 4320 > prevWorkPhase + ? 4320 + : 1960 * ceil(prevWorkPhase / 1960)) - prevWorkPhase), + (isSync = 10 * (1073741822 - expirationTime) - isSync), + isSync < prevWorkPhase && (prevWorkPhase = isSync), + (isSync = prevWorkPhase), + 10 < isSync) + ) + return ( + (root$jscomp$0.timeoutHandle = scheduleTimeout( + commitRoot.bind(null, root$jscomp$0, expirationTime), + isSync + )), + null + ); + } + return commitRoot.bind(null, root$jscomp$0, expirationTime); + case RootCompleted: + return commitRoot.bind(null, root$jscomp$0, expirationTime); + default: + throw ReactError("Unknown root exit status."); + } +} +function performUnitOfWork(unitOfWork) { + var next = beginWork$$1( + unitOfWork.alternate, + unitOfWork, + renderExpirationTime + ); + unitOfWork.memoizedProps = unitOfWork.pendingProps; + null === next && (next = completeUnitOfWork(unitOfWork)); + ReactCurrentOwner$2.current = null; + return next; +} +function completeUnitOfWork(unitOfWork) { + workInProgress = unitOfWork; + do { + var current$$1 = workInProgress.alternate; + unitOfWork = workInProgress.return; + if (0 === (workInProgress.effectTag & 1024)) { + a: { + var current = current$$1; + current$$1 = workInProgress; + var renderExpirationTime$jscomp$0 = renderExpirationTime, + newProps = current$$1.pendingProps; + switch (current$$1.tag) { + case 2: + break; + case 16: + break; + case 15: + case 0: + break; + case 1: + isContextProvider(current$$1.type) && popContext(current$$1); + break; + case 3: + popHostContainer(current$$1); + popTopLevelContextObject(current$$1); + newProps = current$$1.stateNode; + newProps.pendingContext && + ((newProps.context = newProps.pendingContext), + (newProps.pendingContext = null)); + if (null === current || null === current.child) + current$$1.effectTag &= -3; + updateHostContainer(current$$1); + break; + case 5: + popHostContext(current$$1); + renderExpirationTime$jscomp$0 = requiredContext( + rootInstanceStackCursor.current + ); + var type = current$$1.type; + if (null !== current && null != current$$1.stateNode) + updateHostComponent$1( + current, + current$$1, + type, + newProps, + renderExpirationTime$jscomp$0 + ), + current.ref !== current$$1.ref && (current$$1.effectTag |= 128); + else if (newProps) { + requiredContext(contextStackCursor$1.current); + current = newProps; + var rootContainerInstance = renderExpirationTime$jscomp$0; + newProps = current$$1; + renderExpirationTime$jscomp$0 = nextReactTag; + nextReactTag += 2; + type = getViewConfigForType(type); + var updatePayload = diffProperties( + null, + emptyObject, + current, + type.validAttributes + ); + rootContainerInstance = createNode( + renderExpirationTime$jscomp$0, + type.uiViewClassName, + rootContainerInstance, + updatePayload, + newProps + ); + current = new ReactFabricHostComponent( + renderExpirationTime$jscomp$0, + type, + current, + newProps + ); + current = { node: rootContainerInstance, canonical: current }; + appendAllChildren(current, current$$1, !1, !1); + current$$1.stateNode = current; + null !== current$$1.ref && (current$$1.effectTag |= 128); + } else if (null === current$$1.stateNode) + throw ReactError( + "We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue." + ); + break; + case 6: + if (current && null != current$$1.stateNode) + updateHostText$1( + current, + current$$1, + current.memoizedProps, + newProps + ); + else { + if ("string" !== typeof newProps && null === current$$1.stateNode) + throw ReactError( + "We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue." + ); + current = requiredContext(rootInstanceStackCursor.current); + renderExpirationTime$jscomp$0 = requiredContext( + contextStackCursor$1.current + ); + current$$1.stateNode = createTextInstance( + newProps, + current, + renderExpirationTime$jscomp$0, + current$$1 + ); + } + break; + case 11: + break; + case 13: + newProps = current$$1.memoizedState; + if (0 !== (current$$1.effectTag & 64)) { + current$$1.expirationTime = renderExpirationTime$jscomp$0; + break a; + } + newProps = null !== newProps; + renderExpirationTime$jscomp$0 = !1; + null !== current && + ((type = current.memoizedState), + (renderExpirationTime$jscomp$0 = null !== type), + newProps || + null === type || + ((type = type.fallbackExpirationTime), + type < workInProgressRootMostRecentEventTime && + (workInProgressRootMostRecentEventTime = type), + (current = current.child.sibling), + null !== current && + ((type = current$$1.firstEffect), + null !== type + ? ((current$$1.firstEffect = current), + (current.nextEffect = type)) + : ((current$$1.firstEffect = current$$1.lastEffect = current), + (current.nextEffect = null)), + (current.effectTag = 8)))); + newProps && + !renderExpirationTime$jscomp$0 && + 0 !== (current$$1.mode & 1) && + workInProgressRootExitStatus === RootIncomplete && + (workInProgressRootExitStatus = RootSuspended); + newProps && (current$$1.effectTag |= 4); + break; + case 7: + break; + case 8: + break; + case 12: + break; + case 4: + popHostContainer(current$$1); + updateHostContainer(current$$1); + break; + case 10: + popProvider(current$$1); + break; + case 9: + break; + case 14: + break; + case 17: + isContextProvider(current$$1.type) && popContext(current$$1); + break; + case 18: + break; + case 19: + break; + case 20: + break; + default: + throw ReactError( + "Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue." + ); + } + current$$1 = null; + } + current = workInProgress; + if (1 === renderExpirationTime || 1 !== current.childExpirationTime) { + newProps = 0; + for ( + renderExpirationTime$jscomp$0 = current.child; + null !== renderExpirationTime$jscomp$0; + + ) + (type = renderExpirationTime$jscomp$0.expirationTime), + (rootContainerInstance = + renderExpirationTime$jscomp$0.childExpirationTime), + type > newProps && (newProps = type), + rootContainerInstance > newProps && + (newProps = rootContainerInstance), + (renderExpirationTime$jscomp$0 = + renderExpirationTime$jscomp$0.sibling); + current.childExpirationTime = newProps; + } + if (null !== current$$1) return current$$1; + null !== unitOfWork && + 0 === (unitOfWork.effectTag & 1024) && + (null === unitOfWork.firstEffect && + (unitOfWork.firstEffect = workInProgress.firstEffect), + null !== workInProgress.lastEffect && + (null !== unitOfWork.lastEffect && + (unitOfWork.lastEffect.nextEffect = workInProgress.firstEffect), + (unitOfWork.lastEffect = workInProgress.lastEffect)), + 1 < workInProgress.effectTag && + (null !== unitOfWork.lastEffect + ? (unitOfWork.lastEffect.nextEffect = workInProgress) + : (unitOfWork.firstEffect = workInProgress), + (unitOfWork.lastEffect = workInProgress))); + } else { + current$$1 = unwindWork(workInProgress, renderExpirationTime); + if (null !== current$$1) + return (current$$1.effectTag &= 1023), current$$1; + null !== unitOfWork && + ((unitOfWork.firstEffect = unitOfWork.lastEffect = null), + (unitOfWork.effectTag |= 1024)); + } + current$$1 = workInProgress.sibling; + if (null !== current$$1) return current$$1; + workInProgress = unitOfWork; + } while (null !== workInProgress); + workInProgressRootExitStatus === RootIncomplete && + (workInProgressRootExitStatus = RootCompleted); + return null; +} +function commitRoot(root, expirationTime) { + runWithPriority(99, commitRootImpl.bind(null, root, expirationTime)); + null !== rootWithPendingPassiveEffects && + ((root = getCurrentPriorityLevel()), + scheduleCallback(root, function() { + flushPassiveEffects(); + return null; + })); + return null; +} +function commitRootImpl(root, expirationTime) { + flushPassiveEffects(); + if (workPhase === RenderPhase || workPhase === CommitPhase) + throw ReactError("Should not already be working."); + var finishedWork = root.current.alternate; + if (null === finishedWork) + throw ReactError("Should have a work-in-progress root."); + root.callbackNode = null; + root.callbackExpirationTime = 0; + var updateExpirationTimeBeforeCommit = finishedWork.expirationTime, + childExpirationTimeBeforeCommit = finishedWork.childExpirationTime; + updateExpirationTimeBeforeCommit = + childExpirationTimeBeforeCommit > updateExpirationTimeBeforeCommit + ? childExpirationTimeBeforeCommit + : updateExpirationTimeBeforeCommit; + root.firstPendingTime = updateExpirationTimeBeforeCommit; + updateExpirationTimeBeforeCommit < root.lastPendingTime && + (root.lastPendingTime = updateExpirationTimeBeforeCommit); + root === workInProgressRoot && + ((workInProgress = workInProgressRoot = null), (renderExpirationTime = 0)); + 1 < finishedWork.effectTag + ? null !== finishedWork.lastEffect + ? ((finishedWork.lastEffect.nextEffect = finishedWork), + (childExpirationTimeBeforeCommit = finishedWork.firstEffect)) + : (childExpirationTimeBeforeCommit = finishedWork) + : (childExpirationTimeBeforeCommit = finishedWork.firstEffect); + if (null !== childExpirationTimeBeforeCommit) { + updateExpirationTimeBeforeCommit = workPhase; + workPhase = CommitPhase; + ReactCurrentOwner$2.current = null; + nextEffect = childExpirationTimeBeforeCommit; + do + try { + for (; null !== nextEffect; ) { + if (0 !== (nextEffect.effectTag & 256)) { + var current$$1 = nextEffect.alternate, + finishedWork$jscomp$0 = nextEffect; + switch (finishedWork$jscomp$0.tag) { + case 0: + case 11: + case 15: + commitHookEffectList( + UnmountSnapshot, + NoEffect$1, + finishedWork$jscomp$0 + ); + break; + case 1: + if ( + finishedWork$jscomp$0.effectTag & 256 && + null !== current$$1 + ) { + var prevProps = current$$1.memoizedProps, + prevState = current$$1.memoizedState, + instance = finishedWork$jscomp$0.stateNode, + snapshot = instance.getSnapshotBeforeUpdate( + finishedWork$jscomp$0.elementType === + finishedWork$jscomp$0.type + ? prevProps + : resolveDefaultProps( + finishedWork$jscomp$0.type, + prevProps + ), + prevState + ); + instance.__reactInternalSnapshotBeforeUpdate = snapshot; + } + break; + case 3: + case 5: + case 6: + case 4: + case 17: + case 20: + break; + default: + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + } + nextEffect = nextEffect.nextEffect; + } + } catch (error) { + if (null === nextEffect) + throw ReactError("Should be working on an effect."); + captureCommitPhaseError(nextEffect, error); + nextEffect = nextEffect.nextEffect; + } + while (null !== nextEffect); + nextEffect = childExpirationTimeBeforeCommit; + do + try { + for (; null !== nextEffect; ) { + var effectTag = nextEffect.effectTag; + if (effectTag & 128) { + var current$$1$jscomp$0 = nextEffect.alternate; + if (null !== current$$1$jscomp$0) { + var currentRef = current$$1$jscomp$0.ref; + null !== currentRef && + ("function" === typeof currentRef + ? currentRef(null) + : (currentRef.current = null)); + } + } + switch (effectTag & 14) { + case 2: + nextEffect.effectTag &= -3; + break; + case 6: + nextEffect.effectTag &= -3; + commitWork(nextEffect.alternate, nextEffect); + break; + case 4: + commitWork(nextEffect.alternate, nextEffect); + break; + case 8: + current$$1 = nextEffect; + a: for (prevState = prevProps = current$$1; ; ) { + instance = prevState; + "function" === typeof onCommitFiberUnmount && + onCommitFiberUnmount(instance); + switch (instance.tag) { + case 0: + case 11: + case 14: + case 15: + var updateQueue = instance.updateQueue; + if (null !== updateQueue) { + var lastEffect = updateQueue.lastEffect; + if (null !== lastEffect) { + var firstEffect = lastEffect.next; + snapshot = firstEffect; + do { + var destroy = snapshot.destroy; + if (void 0 !== destroy) { + finishedWork$jscomp$0 = instance; + try { + destroy(); + } catch (error) { + captureCommitPhaseError( + finishedWork$jscomp$0, + error + ); + } + } + snapshot = snapshot.next; + } while (snapshot !== firstEffect); + } + } + break; + case 1: + safelyDetachRef(instance); + var instance$jscomp$0 = instance.stateNode; + if ( + "function" === + typeof instance$jscomp$0.componentWillUnmount + ) + try { + (instance$jscomp$0.props = instance.memoizedProps), + (instance$jscomp$0.state = instance.memoizedState), + instance$jscomp$0.componentWillUnmount(); + } catch (unmountError) { + captureCommitPhaseError(instance, unmountError); + } + break; + case 5: + safelyDetachRef(instance); + break; + case 4: + createChildNodeSet(instance.stateNode.containerInfo); + } + if (null !== prevState.child) + (prevState.child.return = prevState), + (prevState = prevState.child); + else { + if (prevState === prevProps) break; + for (; null === prevState.sibling; ) { + if ( + null === prevState.return || + prevState.return === prevProps + ) + break a; + prevState = prevState.return; + } + prevState.sibling.return = prevState.return; + prevState = prevState.sibling; + } + } + current$$1.return = null; + current$$1.child = null; + current$$1.memoizedState = null; + current$$1.updateQueue = null; + var alternate = current$$1.alternate; + null !== alternate && + ((alternate.return = null), + (alternate.child = null), + (alternate.memoizedState = null), + (alternate.updateQueue = null)); + } + nextEffect = nextEffect.nextEffect; + } + } catch (error) { + if (null === nextEffect) + throw ReactError("Should be working on an effect."); + captureCommitPhaseError(nextEffect, error); + nextEffect = nextEffect.nextEffect; + } + while (null !== nextEffect); + root.current = finishedWork; + nextEffect = childExpirationTimeBeforeCommit; + do + try { + for (effectTag = expirationTime; null !== nextEffect; ) { + var effectTag$jscomp$0 = nextEffect.effectTag; + if (effectTag$jscomp$0 & 36) { + var current$$1$jscomp$1 = nextEffect.alternate; + current$$1$jscomp$0 = nextEffect; + currentRef = effectTag; + switch (current$$1$jscomp$0.tag) { + case 0: + case 11: + case 15: + commitHookEffectList( + UnmountLayout, + MountLayout, + current$$1$jscomp$0 + ); + break; + case 1: + var instance$jscomp$1 = current$$1$jscomp$0.stateNode; + if (current$$1$jscomp$0.effectTag & 4) + if (null === current$$1$jscomp$1) + instance$jscomp$1.componentDidMount(); + else { + var prevProps$jscomp$0 = + current$$1$jscomp$0.elementType === + current$$1$jscomp$0.type + ? current$$1$jscomp$1.memoizedProps + : resolveDefaultProps( + current$$1$jscomp$0.type, + current$$1$jscomp$1.memoizedProps + ); + instance$jscomp$1.componentDidUpdate( + prevProps$jscomp$0, + current$$1$jscomp$1.memoizedState, + instance$jscomp$1.__reactInternalSnapshotBeforeUpdate + ); + } + var updateQueue$jscomp$0 = current$$1$jscomp$0.updateQueue; + null !== updateQueue$jscomp$0 && + commitUpdateQueue( + current$$1$jscomp$0, + updateQueue$jscomp$0, + instance$jscomp$1, + currentRef + ); + break; + case 3: + var _updateQueue = current$$1$jscomp$0.updateQueue; + if (null !== _updateQueue) { + updateQueue = null; + if (null !== current$$1$jscomp$0.child) + switch (current$$1$jscomp$0.child.tag) { + case 5: + updateQueue = + current$$1$jscomp$0.child.stateNode.canonical; + break; + case 1: + updateQueue = current$$1$jscomp$0.child.stateNode; + } + commitUpdateQueue( + current$$1$jscomp$0, + _updateQueue, + updateQueue, + currentRef + ); + } + break; + case 5: + if ( + null === current$$1$jscomp$1 && + current$$1$jscomp$0.effectTag & 4 + ) + throw ReactError( + "The current renderer does not support mutation. This error is likely caused by a bug in React. Please file an issue." + ); + break; + case 6: + break; + case 4: + break; + case 12: + break; + case 13: + case 17: + break; + case 20: + break; + case 19: + break; + default: + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + } + if (effectTag$jscomp$0 & 128) { + var ref = nextEffect.ref; + if (null !== ref) { + var instance$jscomp$2 = nextEffect.stateNode; + switch (nextEffect.tag) { + case 5: + var instanceToUse = instance$jscomp$2.canonical; + break; + default: + instanceToUse = instance$jscomp$2; + } + "function" === typeof ref + ? ref(instanceToUse) + : (ref.current = instanceToUse); + } + } + effectTag$jscomp$0 & 512 && (rootDoesHavePassiveEffects = !0); + nextEffect = nextEffect.nextEffect; + } + } catch (error) { + if (null === nextEffect) + throw ReactError("Should be working on an effect."); + captureCommitPhaseError(nextEffect, error); + nextEffect = nextEffect.nextEffect; + } + while (null !== nextEffect); + nextEffect = null; + workPhase = updateExpirationTimeBeforeCommit; + } else root.current = finishedWork; + rootDoesHavePassiveEffects && + ((rootDoesHavePassiveEffects = !1), (rootWithPendingPassiveEffects = root)); + expirationTime = root.firstPendingTime; + 0 !== expirationTime + ? ((effectTag$jscomp$0 = requestCurrentTime()), + (effectTag$jscomp$0 = inferPriorityFromExpirationTime( + effectTag$jscomp$0, + expirationTime + )), + scheduleCallbackForRoot(root, effectTag$jscomp$0, expirationTime)) + : (legacyErrorBoundariesThatAlreadyFailed = null); + "function" === typeof onCommitFiberRoot && + onCommitFiberRoot(finishedWork.stateNode); + 1073741823 === expirationTime + ? root === rootWithNestedUpdates + ? nestedUpdateCount++ + : ((nestedUpdateCount = 0), (rootWithNestedUpdates = root)) + : (nestedUpdateCount = 0); + if (hasUncaughtError) + throw ((hasUncaughtError = !1), + (root = firstUncaughtError), + (firstUncaughtError = null), + root); + if (workPhase === LegacyUnbatchedPhase) return null; + flushImmediateQueue(); + return null; +} +function flushPassiveEffects() { + if (null === rootWithPendingPassiveEffects) return !1; + var root = rootWithPendingPassiveEffects; + rootWithPendingPassiveEffects = null; + if (workPhase === RenderPhase || workPhase === CommitPhase) + throw ReactError("Cannot flush passive effects while already rendering."); + var prevWorkPhase = workPhase; + workPhase = CommitPhase; + for (root = root.current.firstEffect; null !== root; ) { + try { + var finishedWork = root; + commitHookEffectList(UnmountPassive, NoEffect$1, finishedWork); + commitHookEffectList(NoEffect$1, MountPassive, finishedWork); + } catch (error) { + if (null === root) throw ReactError("Should be working on an effect."); + captureCommitPhaseError(root, error); + } + root = root.nextEffect; + } + workPhase = prevWorkPhase; + flushImmediateQueue(); + return !0; +} +function captureCommitPhaseErrorOnRoot(rootFiber, sourceFiber, error) { + sourceFiber = createCapturedValue(error, sourceFiber); + sourceFiber = createRootErrorUpdate(rootFiber, sourceFiber, 1073741823); + enqueueUpdate(rootFiber, sourceFiber); + rootFiber = markUpdateTimeFromFiberToRoot(rootFiber, 1073741823); + null !== rootFiber && scheduleCallbackForRoot(rootFiber, 99, 1073741823); +} +function captureCommitPhaseError(sourceFiber, error) { + if (3 === sourceFiber.tag) + captureCommitPhaseErrorOnRoot(sourceFiber, sourceFiber, error); + else + for (var fiber = sourceFiber.return; null !== fiber; ) { + if (3 === fiber.tag) { + captureCommitPhaseErrorOnRoot(fiber, sourceFiber, error); + break; + } else if (1 === fiber.tag) { + var instance = fiber.stateNode; + if ( + "function" === typeof fiber.type.getDerivedStateFromError || + ("function" === typeof instance.componentDidCatch && + (null === legacyErrorBoundariesThatAlreadyFailed || + !legacyErrorBoundariesThatAlreadyFailed.has(instance))) + ) { + sourceFiber = createCapturedValue(error, sourceFiber); + sourceFiber = createClassErrorUpdate(fiber, sourceFiber, 1073741823); + enqueueUpdate(fiber, sourceFiber); + fiber = markUpdateTimeFromFiberToRoot(fiber, 1073741823); + null !== fiber && scheduleCallbackForRoot(fiber, 99, 1073741823); + break; + } + } + fiber = fiber.return; + } +} +function pingSuspendedRoot(root, thenable, suspendedTime) { + var pingCache = root.pingCache; + null !== pingCache && pingCache.delete(thenable); + workInProgressRoot === root && renderExpirationTime === suspendedTime + ? prepareFreshStack(root, renderExpirationTime) + : root.lastPendingTime < suspendedTime || + ((thenable = root.pingTime), + (0 !== thenable && thenable < suspendedTime) || + ((root.pingTime = suspendedTime), + (thenable = requestCurrentTime()), + (thenable = inferPriorityFromExpirationTime(thenable, suspendedTime)), + scheduleCallbackForRoot(root, thenable, suspendedTime))); +} +function resolveRetryThenable(boundaryFiber, thenable) { + var retryCache = boundaryFiber.stateNode; + null !== retryCache && retryCache.delete(thenable); + retryCache = requestCurrentTime(); + thenable = computeExpirationForFiber(retryCache, boundaryFiber); + retryCache = inferPriorityFromExpirationTime(retryCache, thenable); + boundaryFiber = markUpdateTimeFromFiberToRoot(boundaryFiber, thenable); + null !== boundaryFiber && + scheduleCallbackForRoot(boundaryFiber, retryCache, thenable); +} +var beginWork$$1 = void 0; +beginWork$$1 = function(current$$1, workInProgress, renderExpirationTime) { + var updateExpirationTime = workInProgress.expirationTime; + if (null !== current$$1) + if ( + current$$1.memoizedProps !== workInProgress.pendingProps || + didPerformWorkStackCursor.current + ) + didReceiveUpdate = !0; + else { + if (updateExpirationTime < renderExpirationTime) { + didReceiveUpdate = !1; + switch (workInProgress.tag) { + case 3: + pushHostRootContext(workInProgress); + break; + case 5: + pushHostContext(workInProgress); + break; + case 1: + isContextProvider(workInProgress.type) && + pushContextProvider(workInProgress); + break; + case 4: + pushHostContainer( + workInProgress, + workInProgress.stateNode.containerInfo + ); + break; + case 10: + pushProvider(workInProgress, workInProgress.memoizedProps.value); + break; + case 13: + if (null !== workInProgress.memoizedState) { + updateExpirationTime = workInProgress.child.childExpirationTime; + if ( + 0 !== updateExpirationTime && + updateExpirationTime >= renderExpirationTime + ) + return updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + workInProgress = bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + return null !== workInProgress ? workInProgress.sibling : null; + } + } + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + } + else didReceiveUpdate = !1; + workInProgress.expirationTime = 0; + switch (workInProgress.tag) { + case 2: + updateExpirationTime = workInProgress.elementType; + null !== current$$1 && + ((current$$1.alternate = null), + (workInProgress.alternate = null), + (workInProgress.effectTag |= 2)); + current$$1 = workInProgress.pendingProps; + var context = getMaskedContext( + workInProgress, + contextStackCursor.current + ); + prepareToReadContext(workInProgress, renderExpirationTime); + context = renderWithHooks( + null, + workInProgress, + updateExpirationTime, + current$$1, + context, + renderExpirationTime + ); + workInProgress.effectTag |= 1; + if ( + "object" === typeof context && + null !== context && + "function" === typeof context.render && + void 0 === context.$$typeof + ) { + workInProgress.tag = 1; + resetHooks(); + if (isContextProvider(updateExpirationTime)) { + var hasContext = !0; + pushContextProvider(workInProgress); + } else hasContext = !1; + workInProgress.memoizedState = + null !== context.state && void 0 !== context.state + ? context.state + : null; + var getDerivedStateFromProps = + updateExpirationTime.getDerivedStateFromProps; + "function" === typeof getDerivedStateFromProps && + applyDerivedStateFromProps( + workInProgress, + updateExpirationTime, + getDerivedStateFromProps, + current$$1 + ); + context.updater = classComponentUpdater; + workInProgress.stateNode = context; + context._reactInternalFiber = workInProgress; + mountClassInstance( + workInProgress, + updateExpirationTime, + current$$1, + renderExpirationTime + ); + workInProgress = finishClassComponent( + null, + workInProgress, + updateExpirationTime, + !0, + hasContext, + renderExpirationTime + ); + } else + (workInProgress.tag = 0), + reconcileChildren( + null, + workInProgress, + context, + renderExpirationTime + ), + (workInProgress = workInProgress.child); + return workInProgress; + case 16: + context = workInProgress.elementType; + null !== current$$1 && + ((current$$1.alternate = null), + (workInProgress.alternate = null), + (workInProgress.effectTag |= 2)); + current$$1 = workInProgress.pendingProps; + context = readLazyComponentType(context); + workInProgress.type = context; + hasContext = workInProgress.tag = resolveLazyComponentTag(context); + current$$1 = resolveDefaultProps(context, current$$1); + switch (hasContext) { + case 0: + workInProgress = updateFunctionComponent( + null, + workInProgress, + context, + current$$1, + renderExpirationTime + ); + break; + case 1: + workInProgress = updateClassComponent( + null, + workInProgress, + context, + current$$1, + renderExpirationTime + ); + break; + case 11: + workInProgress = updateForwardRef( + null, + workInProgress, + context, + current$$1, + renderExpirationTime + ); + break; + case 14: + workInProgress = updateMemoComponent( + null, + workInProgress, + context, + resolveDefaultProps(context.type, current$$1), + updateExpirationTime, + renderExpirationTime + ); + break; + default: + throw ReactError( + "Element type is invalid. Received a promise that resolves to: " + + context + + ". Lazy element type must resolve to a class or function." + ); + } + return workInProgress; + case 0: + return ( + (updateExpirationTime = workInProgress.type), + (context = workInProgress.pendingProps), + (context = + workInProgress.elementType === updateExpirationTime + ? context + : resolveDefaultProps(updateExpirationTime, context)), + updateFunctionComponent( + current$$1, + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ) + ); + case 1: + return ( + (updateExpirationTime = workInProgress.type), + (context = workInProgress.pendingProps), + (context = + workInProgress.elementType === updateExpirationTime + ? context + : resolveDefaultProps(updateExpirationTime, context)), + updateClassComponent( + current$$1, + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ) + ); + case 3: + pushHostRootContext(workInProgress); + updateExpirationTime = workInProgress.updateQueue; + if (null === updateExpirationTime) + throw ReactError( + "If the root does not have an updateQueue, we should have already bailed out. This error is likely caused by a bug in React. Please file an issue." + ); + context = workInProgress.memoizedState; + context = null !== context ? context.element : null; + processUpdateQueue( + workInProgress, + updateExpirationTime, + workInProgress.pendingProps, + null, + renderExpirationTime + ); + updateExpirationTime = workInProgress.memoizedState.element; + updateExpirationTime === context + ? (workInProgress = bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + )) + : (reconcileChildren( + current$$1, + workInProgress, + updateExpirationTime, + renderExpirationTime + ), + (workInProgress = workInProgress.child)); + return workInProgress; + case 5: + return ( + pushHostContext(workInProgress), + null === current$$1 && tryToClaimNextHydratableInstance(workInProgress), + (updateExpirationTime = workInProgress.pendingProps.children), + markRef(current$$1, workInProgress), + reconcileChildren( + current$$1, + workInProgress, + updateExpirationTime, + renderExpirationTime + ), + workInProgress.child + ); + case 6: + return ( + null === current$$1 && tryToClaimNextHydratableInstance(workInProgress), + null + ); + case 13: + return updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + case 4: + return ( + pushHostContainer( + workInProgress, + workInProgress.stateNode.containerInfo + ), + (updateExpirationTime = workInProgress.pendingProps), + null === current$$1 + ? (workInProgress.child = reconcileChildFibers( + workInProgress, + null, + updateExpirationTime, + renderExpirationTime + )) + : reconcileChildren( + current$$1, + workInProgress, + updateExpirationTime, + renderExpirationTime + ), + workInProgress.child + ); + case 11: + return ( + (updateExpirationTime = workInProgress.type), + (context = workInProgress.pendingProps), + (context = + workInProgress.elementType === updateExpirationTime + ? context + : resolveDefaultProps(updateExpirationTime, context)), + updateForwardRef( + current$$1, + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ) + ); + case 7: + return ( + reconcileChildren( + current$$1, + workInProgress, + workInProgress.pendingProps, + renderExpirationTime + ), + workInProgress.child + ); + case 8: + return ( + reconcileChildren( + current$$1, + workInProgress, + workInProgress.pendingProps.children, + renderExpirationTime + ), + workInProgress.child + ); + case 12: + return ( + reconcileChildren( + current$$1, + workInProgress, + workInProgress.pendingProps.children, + renderExpirationTime + ), + workInProgress.child + ); + case 10: + a: { + updateExpirationTime = workInProgress.type._context; + context = workInProgress.pendingProps; + getDerivedStateFromProps = workInProgress.memoizedProps; + hasContext = context.value; + pushProvider(workInProgress, hasContext); + if (null !== getDerivedStateFromProps) { + var oldValue = getDerivedStateFromProps.value; + hasContext = is(oldValue, hasContext) + ? 0 + : ("function" === typeof updateExpirationTime._calculateChangedBits + ? updateExpirationTime._calculateChangedBits( + oldValue, + hasContext + ) + : 1073741823) | 0; + if (0 === hasContext) { + if ( + getDerivedStateFromProps.children === context.children && + !didPerformWorkStackCursor.current + ) { + workInProgress = bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + break a; + } + } else + for ( + oldValue = workInProgress.child, + null !== oldValue && (oldValue.return = workInProgress); + null !== oldValue; + + ) { + var list = oldValue.contextDependencies; + if (null !== list) { + getDerivedStateFromProps = oldValue.child; + for (var dependency = list.first; null !== dependency; ) { + if ( + dependency.context === updateExpirationTime && + 0 !== (dependency.observedBits & hasContext) + ) { + 1 === oldValue.tag && + ((dependency = createUpdate(renderExpirationTime)), + (dependency.tag = 2), + enqueueUpdate(oldValue, dependency)); + oldValue.expirationTime < renderExpirationTime && + (oldValue.expirationTime = renderExpirationTime); + dependency = oldValue.alternate; + null !== dependency && + dependency.expirationTime < renderExpirationTime && + (dependency.expirationTime = renderExpirationTime); + dependency = renderExpirationTime; + for (var node = oldValue.return; null !== node; ) { + var alternate = node.alternate; + if (node.childExpirationTime < dependency) + (node.childExpirationTime = dependency), + null !== alternate && + alternate.childExpirationTime < dependency && + (alternate.childExpirationTime = dependency); + else if ( + null !== alternate && + alternate.childExpirationTime < dependency + ) + alternate.childExpirationTime = dependency; + else break; + node = node.return; + } + list.expirationTime < renderExpirationTime && + (list.expirationTime = renderExpirationTime); + break; + } + dependency = dependency.next; + } + } else + getDerivedStateFromProps = + 10 === oldValue.tag + ? oldValue.type === workInProgress.type + ? null + : oldValue.child + : oldValue.child; + if (null !== getDerivedStateFromProps) + getDerivedStateFromProps.return = oldValue; + else + for ( + getDerivedStateFromProps = oldValue; + null !== getDerivedStateFromProps; + + ) { + if (getDerivedStateFromProps === workInProgress) { + getDerivedStateFromProps = null; + break; + } + oldValue = getDerivedStateFromProps.sibling; + if (null !== oldValue) { + oldValue.return = getDerivedStateFromProps.return; + getDerivedStateFromProps = oldValue; + break; + } + getDerivedStateFromProps = getDerivedStateFromProps.return; + } + oldValue = getDerivedStateFromProps; + } + } + reconcileChildren( + current$$1, + workInProgress, + context.children, + renderExpirationTime + ); + workInProgress = workInProgress.child; + } + return workInProgress; + case 9: + return ( + (context = workInProgress.type), + (hasContext = workInProgress.pendingProps), + (updateExpirationTime = hasContext.children), + prepareToReadContext(workInProgress, renderExpirationTime), + (context = readContext(context, hasContext.unstable_observedBits)), + (updateExpirationTime = updateExpirationTime(context)), + (workInProgress.effectTag |= 1), + reconcileChildren( + current$$1, + workInProgress, + updateExpirationTime, + renderExpirationTime + ), + workInProgress.child + ); + case 14: + return ( + (context = workInProgress.type), + (hasContext = resolveDefaultProps( + context, + workInProgress.pendingProps + )), + (hasContext = resolveDefaultProps(context.type, hasContext)), + updateMemoComponent( + current$$1, + workInProgress, + context, + hasContext, + updateExpirationTime, + renderExpirationTime + ) + ); + case 15: + return updateSimpleMemoComponent( + current$$1, + workInProgress, + workInProgress.type, + workInProgress.pendingProps, + updateExpirationTime, + renderExpirationTime + ); + case 17: + return ( + (updateExpirationTime = workInProgress.type), + (context = workInProgress.pendingProps), + (context = + workInProgress.elementType === updateExpirationTime + ? context + : resolveDefaultProps(updateExpirationTime, context)), + null !== current$$1 && + ((current$$1.alternate = null), + (workInProgress.alternate = null), + (workInProgress.effectTag |= 2)), + (workInProgress.tag = 1), + isContextProvider(updateExpirationTime) + ? ((current$$1 = !0), pushContextProvider(workInProgress)) + : (current$$1 = !1), + prepareToReadContext(workInProgress, renderExpirationTime), + constructClassInstance( + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ), + mountClassInstance( + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ), + finishClassComponent( + null, + workInProgress, + updateExpirationTime, + !0, + current$$1, + renderExpirationTime + ) + ); + } + throw ReactError( + "Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue." + ); +}; +function findHostInstance(component) { + var fiber = component._reactInternalFiber; + if (void 0 === fiber) { + if ("function" === typeof component.render) + throw ReactError("Unable to find node on an unmounted component."); + throw ReactError( + "Argument appears to not be a ReactComponent. Keys: " + + Object.keys(component) + ); + } + component = findCurrentHostFiber(fiber); + return null === component ? null : component.stateNode; +} +function updateContainer(element, container, parentComponent, callback) { + var current$$1 = container.current, + currentTime = requestCurrentTime(); + current$$1 = computeExpirationForFiber(currentTime, current$$1); + currentTime = container.current; + a: if (parentComponent) { + parentComponent = parentComponent._reactInternalFiber; + b: { + if ( + 2 !== isFiberMountedImpl(parentComponent) || + 1 !== parentComponent.tag + ) + throw ReactError( + "Expected subtree parent to be a mounted class component. This error is likely caused by a bug in React. Please file an issue." + ); + var parentContext = parentComponent; + do { + switch (parentContext.tag) { + case 3: + parentContext = parentContext.stateNode.context; + break b; + case 1: + if (isContextProvider(parentContext.type)) { + parentContext = + parentContext.stateNode + .__reactInternalMemoizedMergedChildContext; + break b; + } + } + parentContext = parentContext.return; + } while (null !== parentContext); + throw ReactError( + "Found unexpected detached subtree parent. This error is likely caused by a bug in React. Please file an issue." + ); + } + if (1 === parentComponent.tag) { + var Component = parentComponent.type; + if (isContextProvider(Component)) { + parentComponent = processChildContext( + parentComponent, + Component, + parentContext + ); + break a; + } + } + parentComponent = parentContext; + } else parentComponent = emptyContextObject; + null === container.context + ? (container.context = parentComponent) + : (container.pendingContext = parentComponent); + container = callback; + callback = createUpdate(current$$1); + callback.payload = { element: element }; + container = void 0 === container ? null : container; + null !== container && (callback.callback = container); + flushPassiveEffects(); + enqueueUpdate(currentTime, callback); + scheduleUpdateOnFiber(currentTime, current$$1); + return current$$1; +} +function createPortal(children, containerInfo, implementation) { + var key = + 3 < arguments.length && void 0 !== arguments[3] ? arguments[3] : null; + return { + $$typeof: REACT_PORTAL_TYPE, + key: null == key ? null : "" + key, + children: children, + containerInfo: containerInfo, + implementation: implementation + }; +} +function _inherits(subClass, superClass) { + if ("function" !== typeof superClass && null !== superClass) + throw new TypeError( + "Super expression must either be null or a function, not " + + typeof superClass + ); + subClass.prototype = Object.create(superClass && superClass.prototype, { + constructor: { + value: subClass, + enumerable: !1, + writable: !0, + configurable: !0 + } + }); + superClass && + (Object.setPrototypeOf + ? Object.setPrototypeOf(subClass, superClass) + : (subClass.__proto__ = superClass)); +} +var getInspectorDataForViewTag = void 0; +getInspectorDataForViewTag = function() { + throw ReactError( + "getInspectorDataForViewTag() is not available in production" + ); +}; +function findNodeHandle(componentOrHandle) { + if (null == componentOrHandle) return null; + if ("number" === typeof componentOrHandle) return componentOrHandle; + if (componentOrHandle._nativeTag) return componentOrHandle._nativeTag; + if (componentOrHandle.canonical && componentOrHandle.canonical._nativeTag) + return componentOrHandle.canonical._nativeTag; + componentOrHandle = findHostInstance(componentOrHandle); + return null == componentOrHandle + ? componentOrHandle + : componentOrHandle.canonical + ? componentOrHandle.canonical._nativeTag + : componentOrHandle._nativeTag; +} +_batchedUpdatesImpl = function(fn, a) { + if (0 !== workPhase) return fn(a); + workPhase = 1; + try { + return fn(a); + } finally { + (workPhase = 0), flushImmediateQueue(); + } +}; +_flushInteractiveUpdatesImpl = function() { + workPhase !== RenderPhase && + workPhase !== CommitPhase && + flushPendingDiscreteUpdates(); +}; +var roots = new Map(), + ReactFabric = { + NativeComponent: (function(findNodeHandle, findHostInstance) { + return (function(_React$Component) { + function ReactNativeComponent() { + if (!(this instanceof ReactNativeComponent)) + throw new TypeError("Cannot call a class as a function"); + var call = _React$Component.apply(this, arguments); + if (!this) + throw new ReferenceError( + "this hasn't been initialised - super() hasn't been called" + ); + return !call || + ("object" !== typeof call && "function" !== typeof call) + ? this + : call; + } + _inherits(ReactNativeComponent, _React$Component); + ReactNativeComponent.prototype.blur = function() { + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); + }; + ReactNativeComponent.prototype.focus = function() { + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); + }; + ReactNativeComponent.prototype.measure = function(callback) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null != maybeInstance && + (maybeInstance.canonical + ? nativeFabricUIManager.measure( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ) + : ReactNativePrivateInterface.UIManager.measure( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + )); + }; + ReactNativeComponent.prototype.measureInWindow = function(callback) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null != maybeInstance && + (maybeInstance.canonical + ? nativeFabricUIManager.measureInWindow( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ) + : ReactNativePrivateInterface.UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + )); + }; + ReactNativeComponent.prototype.measureLayout = function( + relativeToNativeNode, + onSuccess, + onFail + ) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null == maybeInstance || + maybeInstance.canonical || + ((maybeInstance = void 0), + "number" === typeof relativeToNativeNode + ? (maybeInstance = relativeToNativeNode) + : relativeToNativeNode._nativeTag && + (maybeInstance = relativeToNativeNode._nativeTag), + null != maybeInstance && + ReactNativePrivateInterface.UIManager.measureLayout( + findNodeHandle(this), + maybeInstance, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + )); + }; + ReactNativeComponent.prototype.setNativeProps = function(nativeProps) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + if (null != maybeInstance && !maybeInstance.canonical) { + var nativeTag = + maybeInstance._nativeTag || maybeInstance.canonical._nativeTag; + maybeInstance = + maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; + nativeProps = diffProperties( + null, + emptyObject, + nativeProps, + maybeInstance.validAttributes + ); + null != nativeProps && + ReactNativePrivateInterface.UIManager.updateView( + nativeTag, + maybeInstance.uiViewClassName, + nativeProps + ); + } + }; + return ReactNativeComponent; + })(React.Component); + })(findNodeHandle, findHostInstance), + findNodeHandle: findNodeHandle, + setNativeProps: function() {}, + render: function(element, containerTag, callback) { + var root = roots.get(containerTag); + if (!root) { + root = new FiberRootNode(containerTag, !1); + var uninitializedFiber = createFiber(3, null, null, 0); + root.current = uninitializedFiber; + uninitializedFiber.stateNode = root; + roots.set(containerTag, root); + } + updateContainer(element, root, null, callback); + a: if (((element = root.current), element.child)) + switch (element.child.tag) { + case 5: + element = element.child.stateNode.canonical; + break a; + default: + element = element.child.stateNode; + } + else element = null; + return element; + }, + unmountComponentAtNode: function(containerTag) { + var root = roots.get(containerTag); + root && + updateContainer(null, root, null, function() { + roots.delete(containerTag); + }); + }, + createPortal: function(children, containerTag) { + return createPortal( + children, + containerTag, + null, + 2 < arguments.length && void 0 !== arguments[2] ? arguments[2] : null + ); + }, + __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { + NativeMethodsMixin: (function(findNodeHandle, findHostInstance) { + return { + measure: function(callback) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null != maybeInstance && + (maybeInstance.canonical + ? nativeFabricUIManager.measure( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ) + : ReactNativePrivateInterface.UIManager.measure( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + )); + }, + measureInWindow: function(callback) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null != maybeInstance && + (maybeInstance.canonical + ? nativeFabricUIManager.measureInWindow( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ) + : ReactNativePrivateInterface.UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + )); + }, + measureLayout: function(relativeToNativeNode, onSuccess, onFail) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null == maybeInstance || + maybeInstance.canonical || + ((maybeInstance = void 0), + "number" === typeof relativeToNativeNode + ? (maybeInstance = relativeToNativeNode) + : relativeToNativeNode._nativeTag && + (maybeInstance = relativeToNativeNode._nativeTag), + null != maybeInstance && + ReactNativePrivateInterface.UIManager.measureLayout( + findNodeHandle(this), + maybeInstance, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + )); + }, + setNativeProps: function(nativeProps) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + if (null != maybeInstance && !maybeInstance.canonical) { + var nativeTag = + maybeInstance._nativeTag || maybeInstance.canonical._nativeTag; + maybeInstance = + maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; + nativeProps = diffProperties( + null, + emptyObject, + nativeProps, + maybeInstance.validAttributes + ); + null != nativeProps && + ReactNativePrivateInterface.UIManager.updateView( + nativeTag, + maybeInstance.uiViewClassName, + nativeProps + ); + } + }, + focus: function() { + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); + }, + blur: function() { + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); + } + }; + })(findNodeHandle, findHostInstance) + } + }; +(function(devToolsConfig) { + var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; + return injectInternals( + Object.assign({}, devToolsConfig, { + overrideHookState: null, + overrideProps: null, + setSuspenseHandler: null, + scheduleUpdate: null, + currentDispatcherRef: ReactSharedInternals.ReactCurrentDispatcher, + findHostInstanceByFiber: function(fiber) { + fiber = findCurrentHostFiber(fiber); + return null === fiber ? null : fiber.stateNode; + }, + findFiberByHostInstance: function(instance) { + return findFiberByHostInstance + ? findFiberByHostInstance(instance) + : null; + } + }) + ); +})({ + findFiberByHostInstance: getInstanceFromInstance, + getInspectorDataForViewTag: getInspectorDataForViewTag, + bundleType: 0, + version: "16.8.6", + rendererPackageName: "react-native-renderer" +}); +var ReactFabric$2 = { default: ReactFabric }, + ReactFabric$3 = (ReactFabric$2 && ReactFabric) || ReactFabric$2; +module.exports = ReactFabric$3.default || ReactFabric$3; diff --git a/Libraries/Renderer/oss/ReactFabric-prod.js b/Libraries/Renderer/implementations/ReactFabric-prod.js similarity index 97% rename from Libraries/Renderer/oss/ReactFabric-prod.js rename to Libraries/Renderer/implementations/ReactFabric-prod.js index afbbd4ce6b1b9f..50abb2ccc511cd 100644 --- a/Libraries/Renderer/oss/ReactFabric-prod.js +++ b/Libraries/Renderer/implementations/ReactFabric-prod.js @@ -11,16 +11,10 @@ */ "use strict"; -require("InitializeCore"); -var ReactNativeViewConfigRegistry = require("ReactNativeViewConfigRegistry"), - UIManager = require("UIManager"), +require("react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore"); +var ReactNativePrivateInterface = require("react-native/Libraries/ReactPrivate/ReactNativePrivateInterface"), React = require("react"), - deepDiffer = require("deepDiffer"), - flattenStyle = require("flattenStyle"), - TextInputState = require("TextInputState"), - FabricUIManager = require("FabricUIManager"), Scheduler = require("scheduler"); -var ExceptionsManager = require("ExceptionsManager"); function ReactError(message) { message = Error(message); message.name = "Invariant Violation"; @@ -617,7 +611,7 @@ function changeResponder(nextResponderInst, blockHostResponder) { blockHostResponder ); } -var eventTypes$1 = { +var eventTypes = { startShouldSetResponder: { phasedRegistrationNames: { bubbled: "onStartShouldSetResponder", @@ -680,7 +674,7 @@ var eventTypes$1 = { _getResponder: function() { return responderInst; }, - eventTypes: eventTypes$1, + eventTypes: eventTypes, extractEvents: function( topLevelType, targetInst, @@ -709,12 +703,12 @@ var eventTypes$1 = { isMoveish(topLevelType)) ) { var JSCompiler_temp = isStartish(topLevelType) - ? eventTypes$1.startShouldSetResponder + ? eventTypes.startShouldSetResponder : isMoveish(topLevelType) - ? eventTypes$1.moveShouldSetResponder + ? eventTypes.moveShouldSetResponder : "topSelectionChange" === topLevelType - ? eventTypes$1.selectionChangeShouldSetResponder - : eventTypes$1.scrollShouldSetResponder; + ? eventTypes.selectionChangeShouldSetResponder + : eventTypes.scrollShouldSetResponder; if (responderInst) b: { var JSCompiler_temp$jscomp$0 = responderInst; @@ -800,7 +794,7 @@ var eventTypes$1 = { JSCompiler_temp && JSCompiler_temp !== responderInst ? ((JSCompiler_temp$jscomp$0 = void 0), (targetInst = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderGrant, + eventTypes.responderGrant, JSCompiler_temp, nativeEvent, nativeEventTarget @@ -810,7 +804,7 @@ var eventTypes$1 = { (depthA = !0 === executeDirectDispatch(targetInst)), responderInst ? ((tempA = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderTerminationRequest, + eventTypes.responderTerminationRequest, responderInst, nativeEvent, nativeEventTarget @@ -822,7 +816,7 @@ var eventTypes$1 = { tempA.isPersistent() || tempA.constructor.release(tempA), tempB ? ((tempA = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderTerminate, + eventTypes.responderTerminate, responderInst, nativeEvent, nativeEventTarget @@ -836,7 +830,7 @@ var eventTypes$1 = { )), changeResponder(JSCompiler_temp, depthA)) : ((JSCompiler_temp = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderReject, + eventTypes.responderReject, JSCompiler_temp, nativeEvent, nativeEventTarget @@ -866,11 +860,11 @@ var eventTypes$1 = { ("topTouchEnd" === topLevelType || "topTouchCancel" === topLevelType); if ( (JSCompiler_temp$jscomp$0 = JSCompiler_temp$jscomp$0 - ? eventTypes$1.responderStart + ? eventTypes.responderStart : targetInst - ? eventTypes$1.responderMove + ? eventTypes.responderMove : depthA - ? eventTypes$1.responderEnd + ? eventTypes.responderEnd : null) ) (JSCompiler_temp$jscomp$0 = ResponderSyntheticEvent.getPooled( @@ -924,9 +918,9 @@ var eventTypes$1 = { } if ( (topLevelType = JSCompiler_temp$jscomp$0 - ? eventTypes$1.responderTerminate + ? eventTypes.responderTerminate : topLevelType - ? eventTypes$1.responderRelease + ? eventTypes.responderRelease : null) ) (nativeEvent = ResponderSyntheticEvent.getPooled( @@ -948,8 +942,15 @@ var eventTypes$1 = { } } }, + customBubblingEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customBubblingEventTypes, + customDirectEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customDirectEventTypes, ReactNativeBridgeEventPlugin = { - eventTypes: ReactNativeViewConfigRegistry.eventTypes, + eventTypes: + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes, extractEvents: function( topLevelType, targetInst, @@ -957,10 +958,8 @@ var eventTypes$1 = { nativeEventTarget ) { if (null == targetInst) return null; - var bubbleDispatchConfig = - ReactNativeViewConfigRegistry.customBubblingEventTypes[topLevelType], - directDispatchConfig = - ReactNativeViewConfigRegistry.customDirectEventTypes[topLevelType]; + var bubbleDispatchConfig = customBubblingEventTypes[topLevelType], + directDispatchConfig = customDirectEventTypes[topLevelType]; if (!bubbleDispatchConfig && !directDispatchConfig) throw ReactError( 'Unsupported top level event type "' + topLevelType + '" dispatched' @@ -1002,11 +1001,11 @@ getNodeFromInstance = function(inst) { ResponderEventPlugin.injection.injectGlobalResponderHandler({ onChange: function(from, to, blockNativeResponder) { null !== to - ? UIManager.setJSResponder( + ? ReactNativePrivateInterface.UIManager.setJSResponder( to.stateNode.canonical._nativeTag, blockNativeResponder ) - : UIManager.clearJSResponder(); + : ReactNativePrivateInterface.UIManager.clearJSResponder(); } }); var ReactSharedInternals = @@ -1279,14 +1278,14 @@ function diffNestedProperty( return Array.isArray(prevProp) ? diffProperties( updatePayload, - flattenStyle(prevProp), + ReactNativePrivateInterface.flattenStyle(prevProp), nextProp, validAttributes ) : diffProperties( updatePayload, prevProp, - flattenStyle(nextProp), + ReactNativePrivateInterface.flattenStyle(nextProp), validAttributes ); } @@ -1354,7 +1353,7 @@ function diffProperties(updatePayload, prevProps, nextProps, validAttributes) { if ("object" !== typeof attributeConfig) ("object" !== typeof nextProp || null === nextProp || - deepDiffer(prevProp, nextProp)) && + ReactNativePrivateInterface.deepDiffer(prevProp, nextProp)) && ((updatePayload || (updatePayload = {}))[propKey] = nextProp); else if ( "function" === typeof attributeConfig.diff || @@ -1366,7 +1365,7 @@ function diffProperties(updatePayload, prevProps, nextProps, validAttributes) { ? attributeConfig.diff(prevProp, nextProp) : "object" !== typeof nextProp || null === nextProp || - deepDiffer(prevProp, nextProp)) + ReactNativePrivateInterface.deepDiffer(prevProp, nextProp)) ) (attributeConfig = "function" === typeof attributeConfig.process @@ -1483,9 +1482,25 @@ function shim$1() { "The current renderer does not support hydration. This error is likely caused by a bug in React. Please file an issue." ); } -var nextReactTag = 2; -FabricUIManager.registerEventHandler && - FabricUIManager.registerEventHandler(dispatchEvent); +var _nativeFabricUIManage = nativeFabricUIManager, + createNode = _nativeFabricUIManage.createNode, + cloneNode = _nativeFabricUIManage.cloneNode, + cloneNodeWithNewChildren = _nativeFabricUIManage.cloneNodeWithNewChildren, + cloneNodeWithNewChildrenAndProps = + _nativeFabricUIManage.cloneNodeWithNewChildrenAndProps, + cloneNodeWithNewProps = _nativeFabricUIManage.cloneNodeWithNewProps, + createChildNodeSet = _nativeFabricUIManage.createChildSet, + appendChildNode = _nativeFabricUIManage.appendChild, + appendChildNodeToSet = _nativeFabricUIManage.appendChildToSet, + completeRoot = _nativeFabricUIManage.completeRoot, + registerEventHandler = _nativeFabricUIManage.registerEventHandler, + fabricMeasure = _nativeFabricUIManage.measure, + fabricMeasureInWindow = _nativeFabricUIManage.measureInWindow, + fabricMeasureLayout = _nativeFabricUIManage.measureLayout, + getViewConfigForType = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.get, + nextReactTag = 2; +registerEventHandler && registerEventHandler(dispatchEvent); var ReactFabricHostComponent = (function() { function ReactFabricHostComponent( tag, @@ -1501,19 +1516,19 @@ var ReactFabricHostComponent = (function() { this._internalInstanceHandle = internalInstanceHandle; } ReactFabricHostComponent.prototype.blur = function() { - TextInputState.blurTextInput(this._nativeTag); + ReactNativePrivateInterface.TextInputState.blurTextInput(this._nativeTag); }; ReactFabricHostComponent.prototype.focus = function() { - TextInputState.focusTextInput(this._nativeTag); + ReactNativePrivateInterface.TextInputState.focusTextInput(this._nativeTag); }; ReactFabricHostComponent.prototype.measure = function(callback) { - FabricUIManager.measure( + fabricMeasure( this._internalInstanceHandle.stateNode.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); }; ReactFabricHostComponent.prototype.measureInWindow = function(callback) { - FabricUIManager.measureInWindow( + fabricMeasureInWindow( this._internalInstanceHandle.stateNode.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); @@ -1525,7 +1540,7 @@ var ReactFabricHostComponent = (function() { ) { "number" !== typeof relativeToNativeNode && relativeToNativeNode instanceof ReactFabricHostComponent && - FabricUIManager.measureLayout( + fabricMeasureLayout( this._internalInstanceHandle.stateNode.node, relativeToNativeNode._internalInstanceHandle.stateNode.node, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -1548,7 +1563,7 @@ function createTextInstance( hostContext = nextReactTag; nextReactTag += 2; return { - node: FabricUIManager.createNode( + node: createNode( hostContext, "RCTRawText", rootContainerInstance, @@ -1568,7 +1583,7 @@ function cloneHiddenInstance(instance) { instance.canonical.viewConfig.validAttributes ); return { - node: FabricUIManager.cloneNodeWithNewProps(node, updatePayload), + node: cloneNodeWithNewProps(node, updatePayload), canonical: instance.canonical }; } @@ -4457,12 +4472,12 @@ appendAllChildren = function( node.memoizedProps, node )); - FabricUIManager.appendChild(parent.node, instance.node); + appendChildNode(parent.node, instance.node); } else if (6 === node.tag) { instance = node.stateNode; if (needsVisibilityToggle && isHidden) throw Error("Not yet implemented."); - FabricUIManager.appendChild(parent.node, instance.node); + appendChildNode(parent.node, instance.node); } else if (4 !== node.tag) { if ( 13 === node.tag && @@ -4515,12 +4530,12 @@ function appendAllChildrenToContainer( node.memoizedProps, node )); - FabricUIManager.appendChildToSet(containerChildSet, instance.node); + appendChildNodeToSet(containerChildSet, instance.node); } else if (6 === node.tag) { instance = node.stateNode; if (needsVisibilityToggle && isHidden) throw Error("Not yet implemented."); - FabricUIManager.appendChildToSet(containerChildSet, instance.node); + appendChildNodeToSet(containerChildSet, instance.node); } else if (4 !== node.tag) { if ( 13 === node.tag && @@ -4565,11 +4580,11 @@ updateHostContainer = function(workInProgress) { var portalOrRoot = workInProgress.stateNode; if (null !== workInProgress.firstEffect) { var container = portalOrRoot.containerInfo, - newChildSet = FabricUIManager.createChildSet(container); + newChildSet = createChildNodeSet(container); appendAllChildrenToContainer(newChildSet, workInProgress, !1, !1); portalOrRoot.pendingChildren = newChildSet; workInProgress.effectTag |= 4; - FabricUIManager.completeRoot(container, newChildSet); + completeRoot(container, newChildSet); } }; updateHostComponent$1 = function(current, workInProgress, type, newProps) { @@ -4597,17 +4612,11 @@ updateHostComponent$1 = function(current, workInProgress, type, newProps) { (type = { node: current ? null !== newProps - ? FabricUIManager.cloneNodeWithNewProps( - recyclableInstance, - newProps - ) - : FabricUIManager.cloneNode(recyclableInstance) + ? cloneNodeWithNewProps(recyclableInstance, newProps) + : cloneNode(recyclableInstance) : null !== newProps - ? FabricUIManager.cloneNodeWithNewChildrenAndProps( - recyclableInstance, - newProps - ) - : FabricUIManager.cloneNodeWithNewChildren(recyclableInstance), + ? cloneNodeWithNewChildrenAndProps(recyclableInstance, newProps) + : cloneNodeWithNewChildren(recyclableInstance), canonical: type.canonical }), (workInProgress.stateNode = type), @@ -4652,7 +4661,7 @@ function logCapturedError(capturedError) { "string" === typeof error ? Error(error + "\n\nThis error is located at:" + componentStack) : Error("Unspecified error at:" + componentStack); - ExceptionsManager.handleException(error, !1); + ReactNativePrivateInterface.ExceptionsManager.handleException(error, !1); } var PossiblyWeakSet$1 = "function" === typeof WeakSet ? WeakSet : Set; function logError(boundary, errorInfo) { @@ -5383,14 +5392,14 @@ function completeUnitOfWork(unitOfWork) { newProps = current$$1; renderExpirationTime$jscomp$0 = nextReactTag; nextReactTag += 2; - type = ReactNativeViewConfigRegistry.get(type); + type = getViewConfigForType(type); var updatePayload = diffProperties( null, emptyObject, current, type.validAttributes ); - rootContainerInstance = FabricUIManager.createNode( + rootContainerInstance = createNode( renderExpirationTime$jscomp$0, type.uiViewClassName, rootContainerInstance, @@ -5732,9 +5741,7 @@ function commitRootImpl(root, expirationTime) { safelyDetachRef(instance); break; case 4: - FabricUIManager.createChildSet( - instance.stateNode.containerInfo - ); + createChildNodeSet(instance.stateNode.containerInfo); } if (null !== prevState.child) (prevState.child.return = prevState), @@ -6712,10 +6719,14 @@ var roots = new Map(), } _inherits(ReactNativeComponent, _React$Component); ReactNativeComponent.prototype.blur = function() { - TextInputState.blurTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); }; ReactNativeComponent.prototype.focus = function() { - TextInputState.focusTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); }; ReactNativeComponent.prototype.measure = function(callback) { var maybeInstance = void 0; @@ -6728,7 +6739,7 @@ var roots = new Map(), maybeInstance.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ) - : UIManager.measure( + : ReactNativePrivateInterface.UIManager.measure( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) )); @@ -6744,7 +6755,7 @@ var roots = new Map(), maybeInstance.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ) - : UIManager.measureInWindow( + : ReactNativePrivateInterface.UIManager.measureInWindow( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) )); @@ -6766,7 +6777,7 @@ var roots = new Map(), : relativeToNativeNode._nativeTag && (maybeInstance = relativeToNativeNode._nativeTag), null != maybeInstance && - UIManager.measureLayout( + ReactNativePrivateInterface.UIManager.measureLayout( findNodeHandle(this), maybeInstance, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -6790,7 +6801,7 @@ var roots = new Map(), maybeInstance.validAttributes ); null != nativeProps && - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( nativeTag, maybeInstance.uiViewClassName, nativeProps @@ -6852,7 +6863,7 @@ var roots = new Map(), maybeInstance.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ) - : UIManager.measure( + : ReactNativePrivateInterface.UIManager.measure( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) )); @@ -6868,7 +6879,7 @@ var roots = new Map(), maybeInstance.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ) - : UIManager.measureInWindow( + : ReactNativePrivateInterface.UIManager.measureInWindow( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) )); @@ -6886,7 +6897,7 @@ var roots = new Map(), : relativeToNativeNode._nativeTag && (maybeInstance = relativeToNativeNode._nativeTag), null != maybeInstance && - UIManager.measureLayout( + ReactNativePrivateInterface.UIManager.measureLayout( findNodeHandle(this), maybeInstance, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -6910,7 +6921,7 @@ var roots = new Map(), maybeInstance.validAttributes ); null != nativeProps && - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( nativeTag, maybeInstance.uiViewClassName, nativeProps @@ -6918,10 +6929,14 @@ var roots = new Map(), } }, focus: function() { - TextInputState.focusTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); }, blur: function() { - TextInputState.blurTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); } }; })(findNodeHandle, findHostInstance) diff --git a/Libraries/Renderer/implementations/ReactFabric-profiling.fb.js b/Libraries/Renderer/implementations/ReactFabric-profiling.fb.js new file mode 100644 index 00000000000000..722fac68035257 --- /dev/null +++ b/Libraries/Renderer/implementations/ReactFabric-profiling.fb.js @@ -0,0 +1,7211 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @noflow + * @preventMunge + * @generated + */ + +"use strict"; +require("react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore"); +var ReactNativePrivateInterface = require("react-native/Libraries/ReactPrivate/ReactNativePrivateInterface"), + React = require("react"), + Scheduler = require("scheduler"), + tracing = require("scheduler/tracing"); +function ReactError(message) { + message = Error(message); + message.name = "Invariant Violation"; + return message; +} +var eventPluginOrder = null, + namesToPlugins = {}; +function recomputePluginOrdering() { + if (eventPluginOrder) + for (var pluginName in namesToPlugins) { + var pluginModule = namesToPlugins[pluginName], + pluginIndex = eventPluginOrder.indexOf(pluginName); + if (!(-1 < pluginIndex)) + throw ReactError( + "EventPluginRegistry: Cannot inject event plugins that do not exist in the plugin ordering, `" + + pluginName + + "`." + ); + if (!plugins[pluginIndex]) { + if (!pluginModule.extractEvents) + throw ReactError( + "EventPluginRegistry: Event plugins must implement an `extractEvents` method, but `" + + pluginName + + "` does not." + ); + plugins[pluginIndex] = pluginModule; + pluginIndex = pluginModule.eventTypes; + for (var eventName in pluginIndex) { + var JSCompiler_inline_result = void 0; + var dispatchConfig = pluginIndex[eventName], + pluginModule$jscomp$0 = pluginModule, + eventName$jscomp$0 = eventName; + if (eventNameDispatchConfigs.hasOwnProperty(eventName$jscomp$0)) + throw ReactError( + "EventPluginHub: More than one plugin attempted to publish the same event name, `" + + eventName$jscomp$0 + + "`." + ); + eventNameDispatchConfigs[eventName$jscomp$0] = dispatchConfig; + var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames; + if (phasedRegistrationNames) { + for (JSCompiler_inline_result in phasedRegistrationNames) + phasedRegistrationNames.hasOwnProperty( + JSCompiler_inline_result + ) && + publishRegistrationName( + phasedRegistrationNames[JSCompiler_inline_result], + pluginModule$jscomp$0, + eventName$jscomp$0 + ); + JSCompiler_inline_result = !0; + } else + dispatchConfig.registrationName + ? (publishRegistrationName( + dispatchConfig.registrationName, + pluginModule$jscomp$0, + eventName$jscomp$0 + ), + (JSCompiler_inline_result = !0)) + : (JSCompiler_inline_result = !1); + if (!JSCompiler_inline_result) + throw ReactError( + "EventPluginRegistry: Failed to publish event `" + + eventName + + "` for plugin `" + + pluginName + + "`." + ); + } + } + } +} +function publishRegistrationName(registrationName, pluginModule) { + if (registrationNameModules[registrationName]) + throw ReactError( + "EventPluginHub: More than one plugin attempted to publish the same registration name, `" + + registrationName + + "`." + ); + registrationNameModules[registrationName] = pluginModule; +} +var plugins = [], + eventNameDispatchConfigs = {}, + registrationNameModules = {}; +function invokeGuardedCallbackImpl(name, func, context, a, b, c, d, e, f) { + var funcArgs = Array.prototype.slice.call(arguments, 3); + try { + func.apply(context, funcArgs); + } catch (error) { + this.onError(error); + } +} +var hasError = !1, + caughtError = null, + hasRethrowError = !1, + rethrowError = null, + reporter = { + onError: function(error) { + hasError = !0; + caughtError = error; + } + }; +function invokeGuardedCallback(name, func, context, a, b, c, d, e, f) { + hasError = !1; + caughtError = null; + invokeGuardedCallbackImpl.apply(reporter, arguments); +} +function invokeGuardedCallbackAndCatchFirstError( + name, + func, + context, + a, + b, + c, + d, + e, + f +) { + invokeGuardedCallback.apply(this, arguments); + if (hasError) { + if (hasError) { + var error = caughtError; + hasError = !1; + caughtError = null; + } else + throw ReactError( + "clearCaughtError was called but no error was captured. This error is likely caused by a bug in React. Please file an issue." + ); + hasRethrowError || ((hasRethrowError = !0), (rethrowError = error)); + } +} +var getFiberCurrentPropsFromNode = null, + getInstanceFromNode = null, + getNodeFromInstance = null; +function executeDispatch(event, listener, inst) { + var type = event.type || "unknown-event"; + event.currentTarget = getNodeFromInstance(inst); + invokeGuardedCallbackAndCatchFirstError(type, listener, void 0, event); + event.currentTarget = null; +} +function executeDirectDispatch(event) { + var dispatchListener = event._dispatchListeners, + dispatchInstance = event._dispatchInstances; + if (Array.isArray(dispatchListener)) + throw ReactError("executeDirectDispatch(...): Invalid `event`."); + event.currentTarget = dispatchListener + ? getNodeFromInstance(dispatchInstance) + : null; + dispatchListener = dispatchListener ? dispatchListener(event) : null; + event.currentTarget = null; + event._dispatchListeners = null; + event._dispatchInstances = null; + return dispatchListener; +} +function accumulateInto(current, next) { + if (null == next) + throw ReactError( + "accumulateInto(...): Accumulated items must not be null or undefined." + ); + if (null == current) return next; + if (Array.isArray(current)) { + if (Array.isArray(next)) return current.push.apply(current, next), current; + current.push(next); + return current; + } + return Array.isArray(next) ? [current].concat(next) : [current, next]; +} +function forEachAccumulated(arr, cb, scope) { + Array.isArray(arr) ? arr.forEach(cb, scope) : arr && cb.call(scope, arr); +} +var eventQueue = null; +function executeDispatchesAndReleaseTopLevel(e) { + if (e) { + var dispatchListeners = e._dispatchListeners, + dispatchInstances = e._dispatchInstances; + if (Array.isArray(dispatchListeners)) + for ( + var i = 0; + i < dispatchListeners.length && !e.isPropagationStopped(); + i++ + ) + executeDispatch(e, dispatchListeners[i], dispatchInstances[i]); + else + dispatchListeners && + executeDispatch(e, dispatchListeners, dispatchInstances); + e._dispatchListeners = null; + e._dispatchInstances = null; + e.isPersistent() || e.constructor.release(e); + } +} +var injection = { + injectEventPluginOrder: function(injectedEventPluginOrder) { + if (eventPluginOrder) + throw ReactError( + "EventPluginRegistry: Cannot inject event plugin ordering more than once. You are likely trying to load more than one copy of React." + ); + eventPluginOrder = Array.prototype.slice.call(injectedEventPluginOrder); + recomputePluginOrdering(); + }, + injectEventPluginsByName: function(injectedNamesToPlugins) { + var isOrderingDirty = !1, + pluginName; + for (pluginName in injectedNamesToPlugins) + if (injectedNamesToPlugins.hasOwnProperty(pluginName)) { + var pluginModule = injectedNamesToPlugins[pluginName]; + if ( + !namesToPlugins.hasOwnProperty(pluginName) || + namesToPlugins[pluginName] !== pluginModule + ) { + if (namesToPlugins[pluginName]) + throw ReactError( + "EventPluginRegistry: Cannot inject two different event plugins using the same name, `" + + pluginName + + "`." + ); + namesToPlugins[pluginName] = pluginModule; + isOrderingDirty = !0; + } + } + isOrderingDirty && recomputePluginOrdering(); + } +}; +function getListener(inst, registrationName) { + var listener = inst.stateNode; + if (!listener) return null; + var props = getFiberCurrentPropsFromNode(listener); + if (!props) return null; + listener = props[registrationName]; + a: switch (registrationName) { + case "onClick": + case "onClickCapture": + case "onDoubleClick": + case "onDoubleClickCapture": + case "onMouseDown": + case "onMouseDownCapture": + case "onMouseMove": + case "onMouseMoveCapture": + case "onMouseUp": + case "onMouseUpCapture": + (props = !props.disabled) || + ((inst = inst.type), + (props = !( + "button" === inst || + "input" === inst || + "select" === inst || + "textarea" === inst + ))); + inst = !props; + break a; + default: + inst = !1; + } + if (inst) return null; + if (listener && "function" !== typeof listener) + throw ReactError( + "Expected `" + + registrationName + + "` listener to be a function, instead got a value of `" + + typeof listener + + "` type." + ); + return listener; +} +function getParent(inst) { + do inst = inst.return; + while (inst && 5 !== inst.tag); + return inst ? inst : null; +} +function traverseTwoPhase(inst, fn, arg) { + for (var path = []; inst; ) path.push(inst), (inst = getParent(inst)); + for (inst = path.length; 0 < inst--; ) fn(path[inst], "captured", arg); + for (inst = 0; inst < path.length; inst++) fn(path[inst], "bubbled", arg); +} +function accumulateDirectionalDispatches(inst, phase, event) { + if ( + (phase = getListener( + inst, + event.dispatchConfig.phasedRegistrationNames[phase] + )) + ) + (event._dispatchListeners = accumulateInto( + event._dispatchListeners, + phase + )), + (event._dispatchInstances = accumulateInto( + event._dispatchInstances, + inst + )); +} +function accumulateTwoPhaseDispatchesSingle(event) { + event && + event.dispatchConfig.phasedRegistrationNames && + traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event); +} +function accumulateTwoPhaseDispatchesSingleSkipTarget(event) { + if (event && event.dispatchConfig.phasedRegistrationNames) { + var targetInst = event._targetInst; + targetInst = targetInst ? getParent(targetInst) : null; + traverseTwoPhase(targetInst, accumulateDirectionalDispatches, event); + } +} +function accumulateDirectDispatchesSingle(event) { + if (event && event.dispatchConfig.registrationName) { + var inst = event._targetInst; + if (inst && event && event.dispatchConfig.registrationName) { + var listener = getListener(inst, event.dispatchConfig.registrationName); + listener && + ((event._dispatchListeners = accumulateInto( + event._dispatchListeners, + listener + )), + (event._dispatchInstances = accumulateInto( + event._dispatchInstances, + inst + ))); + } + } +} +function functionThatReturnsTrue() { + return !0; +} +function functionThatReturnsFalse() { + return !1; +} +function SyntheticEvent( + dispatchConfig, + targetInst, + nativeEvent, + nativeEventTarget +) { + this.dispatchConfig = dispatchConfig; + this._targetInst = targetInst; + this.nativeEvent = nativeEvent; + dispatchConfig = this.constructor.Interface; + for (var propName in dispatchConfig) + dispatchConfig.hasOwnProperty(propName) && + ((targetInst = dispatchConfig[propName]) + ? (this[propName] = targetInst(nativeEvent)) + : "target" === propName + ? (this.target = nativeEventTarget) + : (this[propName] = nativeEvent[propName])); + this.isDefaultPrevented = (null != nativeEvent.defaultPrevented + ? nativeEvent.defaultPrevented + : !1 === nativeEvent.returnValue) + ? functionThatReturnsTrue + : functionThatReturnsFalse; + this.isPropagationStopped = functionThatReturnsFalse; + return this; +} +Object.assign(SyntheticEvent.prototype, { + preventDefault: function() { + this.defaultPrevented = !0; + var event = this.nativeEvent; + event && + (event.preventDefault + ? event.preventDefault() + : "unknown" !== typeof event.returnValue && (event.returnValue = !1), + (this.isDefaultPrevented = functionThatReturnsTrue)); + }, + stopPropagation: function() { + var event = this.nativeEvent; + event && + (event.stopPropagation + ? event.stopPropagation() + : "unknown" !== typeof event.cancelBubble && (event.cancelBubble = !0), + (this.isPropagationStopped = functionThatReturnsTrue)); + }, + persist: function() { + this.isPersistent = functionThatReturnsTrue; + }, + isPersistent: functionThatReturnsFalse, + destructor: function() { + var Interface = this.constructor.Interface, + propName; + for (propName in Interface) this[propName] = null; + this.nativeEvent = this._targetInst = this.dispatchConfig = null; + this.isPropagationStopped = this.isDefaultPrevented = functionThatReturnsFalse; + this._dispatchInstances = this._dispatchListeners = null; + } +}); +SyntheticEvent.Interface = { + type: null, + target: null, + currentTarget: function() { + return null; + }, + eventPhase: null, + bubbles: null, + cancelable: null, + timeStamp: function(event) { + return event.timeStamp || Date.now(); + }, + defaultPrevented: null, + isTrusted: null +}; +SyntheticEvent.extend = function(Interface) { + function E() {} + function Class() { + return Super.apply(this, arguments); + } + var Super = this; + E.prototype = Super.prototype; + var prototype = new E(); + Object.assign(prototype, Class.prototype); + Class.prototype = prototype; + Class.prototype.constructor = Class; + Class.Interface = Object.assign({}, Super.Interface, Interface); + Class.extend = Super.extend; + addEventPoolingTo(Class); + return Class; +}; +addEventPoolingTo(SyntheticEvent); +function getPooledEvent(dispatchConfig, targetInst, nativeEvent, nativeInst) { + if (this.eventPool.length) { + var instance = this.eventPool.pop(); + this.call(instance, dispatchConfig, targetInst, nativeEvent, nativeInst); + return instance; + } + return new this(dispatchConfig, targetInst, nativeEvent, nativeInst); +} +function releasePooledEvent(event) { + if (!(event instanceof this)) + throw ReactError( + "Trying to release an event instance into a pool of a different type." + ); + event.destructor(); + 10 > this.eventPool.length && this.eventPool.push(event); +} +function addEventPoolingTo(EventConstructor) { + EventConstructor.eventPool = []; + EventConstructor.getPooled = getPooledEvent; + EventConstructor.release = releasePooledEvent; +} +var ResponderSyntheticEvent = SyntheticEvent.extend({ + touchHistory: function() { + return null; + } +}); +function isStartish(topLevelType) { + return "topTouchStart" === topLevelType; +} +function isMoveish(topLevelType) { + return "topTouchMove" === topLevelType; +} +var startDependencies = ["topTouchStart"], + moveDependencies = ["topTouchMove"], + endDependencies = ["topTouchCancel", "topTouchEnd"], + touchBank = [], + touchHistory = { + touchBank: touchBank, + numberActiveTouches: 0, + indexOfSingleActiveTouch: -1, + mostRecentTimeStamp: 0 + }; +function timestampForTouch(touch) { + return touch.timeStamp || touch.timestamp; +} +function getTouchIdentifier(_ref) { + _ref = _ref.identifier; + if (null == _ref) throw ReactError("Touch object is missing identifier."); + return _ref; +} +function recordTouchStart(touch) { + var identifier = getTouchIdentifier(touch), + touchRecord = touchBank[identifier]; + touchRecord + ? ((touchRecord.touchActive = !0), + (touchRecord.startPageX = touch.pageX), + (touchRecord.startPageY = touch.pageY), + (touchRecord.startTimeStamp = timestampForTouch(touch)), + (touchRecord.currentPageX = touch.pageX), + (touchRecord.currentPageY = touch.pageY), + (touchRecord.currentTimeStamp = timestampForTouch(touch)), + (touchRecord.previousPageX = touch.pageX), + (touchRecord.previousPageY = touch.pageY), + (touchRecord.previousTimeStamp = timestampForTouch(touch))) + : ((touchRecord = { + touchActive: !0, + startPageX: touch.pageX, + startPageY: touch.pageY, + startTimeStamp: timestampForTouch(touch), + currentPageX: touch.pageX, + currentPageY: touch.pageY, + currentTimeStamp: timestampForTouch(touch), + previousPageX: touch.pageX, + previousPageY: touch.pageY, + previousTimeStamp: timestampForTouch(touch) + }), + (touchBank[identifier] = touchRecord)); + touchHistory.mostRecentTimeStamp = timestampForTouch(touch); +} +function recordTouchMove(touch) { + var touchRecord = touchBank[getTouchIdentifier(touch)]; + touchRecord + ? ((touchRecord.touchActive = !0), + (touchRecord.previousPageX = touchRecord.currentPageX), + (touchRecord.previousPageY = touchRecord.currentPageY), + (touchRecord.previousTimeStamp = touchRecord.currentTimeStamp), + (touchRecord.currentPageX = touch.pageX), + (touchRecord.currentPageY = touch.pageY), + (touchRecord.currentTimeStamp = timestampForTouch(touch)), + (touchHistory.mostRecentTimeStamp = timestampForTouch(touch))) + : console.error( + "Cannot record touch move without a touch start.\nTouch Move: %s\n", + "Touch Bank: %s", + printTouch(touch), + printTouchBank() + ); +} +function recordTouchEnd(touch) { + var touchRecord = touchBank[getTouchIdentifier(touch)]; + touchRecord + ? ((touchRecord.touchActive = !1), + (touchRecord.previousPageX = touchRecord.currentPageX), + (touchRecord.previousPageY = touchRecord.currentPageY), + (touchRecord.previousTimeStamp = touchRecord.currentTimeStamp), + (touchRecord.currentPageX = touch.pageX), + (touchRecord.currentPageY = touch.pageY), + (touchRecord.currentTimeStamp = timestampForTouch(touch)), + (touchHistory.mostRecentTimeStamp = timestampForTouch(touch))) + : console.error( + "Cannot record touch end without a touch start.\nTouch End: %s\n", + "Touch Bank: %s", + printTouch(touch), + printTouchBank() + ); +} +function printTouch(touch) { + return JSON.stringify({ + identifier: touch.identifier, + pageX: touch.pageX, + pageY: touch.pageY, + timestamp: timestampForTouch(touch) + }); +} +function printTouchBank() { + var printed = JSON.stringify(touchBank.slice(0, 20)); + 20 < touchBank.length && + (printed += " (original size: " + touchBank.length + ")"); + return printed; +} +var ResponderTouchHistoryStore = { + recordTouchTrack: function(topLevelType, nativeEvent) { + if (isMoveish(topLevelType)) + nativeEvent.changedTouches.forEach(recordTouchMove); + else if (isStartish(topLevelType)) + nativeEvent.changedTouches.forEach(recordTouchStart), + (touchHistory.numberActiveTouches = nativeEvent.touches.length), + 1 === touchHistory.numberActiveTouches && + (touchHistory.indexOfSingleActiveTouch = + nativeEvent.touches[0].identifier); + else if ( + "topTouchEnd" === topLevelType || + "topTouchCancel" === topLevelType + ) + if ( + (nativeEvent.changedTouches.forEach(recordTouchEnd), + (touchHistory.numberActiveTouches = nativeEvent.touches.length), + 1 === touchHistory.numberActiveTouches) + ) + for (topLevelType = 0; topLevelType < touchBank.length; topLevelType++) + if ( + ((nativeEvent = touchBank[topLevelType]), + null != nativeEvent && nativeEvent.touchActive) + ) { + touchHistory.indexOfSingleActiveTouch = topLevelType; + break; + } + }, + touchHistory: touchHistory +}; +function accumulate(current, next) { + if (null == next) + throw ReactError( + "accumulate(...): Accumulated items must not be null or undefined." + ); + return null == current + ? next + : Array.isArray(current) + ? current.concat(next) + : Array.isArray(next) + ? [current].concat(next) + : [current, next]; +} +var responderInst = null, + trackedTouchCount = 0; +function changeResponder(nextResponderInst, blockHostResponder) { + var oldResponderInst = responderInst; + responderInst = nextResponderInst; + if (null !== ResponderEventPlugin.GlobalResponderHandler) + ResponderEventPlugin.GlobalResponderHandler.onChange( + oldResponderInst, + nextResponderInst, + blockHostResponder + ); +} +var eventTypes = { + startShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onStartShouldSetResponder", + captured: "onStartShouldSetResponderCapture" + }, + dependencies: startDependencies + }, + scrollShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onScrollShouldSetResponder", + captured: "onScrollShouldSetResponderCapture" + }, + dependencies: ["topScroll"] + }, + selectionChangeShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onSelectionChangeShouldSetResponder", + captured: "onSelectionChangeShouldSetResponderCapture" + }, + dependencies: ["topSelectionChange"] + }, + moveShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onMoveShouldSetResponder", + captured: "onMoveShouldSetResponderCapture" + }, + dependencies: moveDependencies + }, + responderStart: { + registrationName: "onResponderStart", + dependencies: startDependencies + }, + responderMove: { + registrationName: "onResponderMove", + dependencies: moveDependencies + }, + responderEnd: { + registrationName: "onResponderEnd", + dependencies: endDependencies + }, + responderRelease: { + registrationName: "onResponderRelease", + dependencies: endDependencies + }, + responderTerminationRequest: { + registrationName: "onResponderTerminationRequest", + dependencies: [] + }, + responderGrant: { registrationName: "onResponderGrant", dependencies: [] }, + responderReject: { + registrationName: "onResponderReject", + dependencies: [] + }, + responderTerminate: { + registrationName: "onResponderTerminate", + dependencies: [] + } + }, + ResponderEventPlugin = { + _getResponder: function() { + return responderInst; + }, + eventTypes: eventTypes, + extractEvents: function( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ) { + if (isStartish(topLevelType)) trackedTouchCount += 1; + else if ( + "topTouchEnd" === topLevelType || + "topTouchCancel" === topLevelType + ) + if (0 <= trackedTouchCount) --trackedTouchCount; + else + return ( + console.error( + "Ended a touch event which was not counted in `trackedTouchCount`." + ), + null + ); + ResponderTouchHistoryStore.recordTouchTrack(topLevelType, nativeEvent); + if ( + targetInst && + (("topScroll" === topLevelType && !nativeEvent.responderIgnoreScroll) || + (0 < trackedTouchCount && "topSelectionChange" === topLevelType) || + isStartish(topLevelType) || + isMoveish(topLevelType)) + ) { + var JSCompiler_temp = isStartish(topLevelType) + ? eventTypes.startShouldSetResponder + : isMoveish(topLevelType) + ? eventTypes.moveShouldSetResponder + : "topSelectionChange" === topLevelType + ? eventTypes.selectionChangeShouldSetResponder + : eventTypes.scrollShouldSetResponder; + if (responderInst) + b: { + var JSCompiler_temp$jscomp$0 = responderInst; + for ( + var depthA = 0, tempA = JSCompiler_temp$jscomp$0; + tempA; + tempA = getParent(tempA) + ) + depthA++; + tempA = 0; + for (var tempB = targetInst; tempB; tempB = getParent(tempB)) + tempA++; + for (; 0 < depthA - tempA; ) + (JSCompiler_temp$jscomp$0 = getParent(JSCompiler_temp$jscomp$0)), + depthA--; + for (; 0 < tempA - depthA; ) + (targetInst = getParent(targetInst)), tempA--; + for (; depthA--; ) { + if ( + JSCompiler_temp$jscomp$0 === targetInst || + JSCompiler_temp$jscomp$0 === targetInst.alternate + ) + break b; + JSCompiler_temp$jscomp$0 = getParent(JSCompiler_temp$jscomp$0); + targetInst = getParent(targetInst); + } + JSCompiler_temp$jscomp$0 = null; + } + else JSCompiler_temp$jscomp$0 = targetInst; + targetInst = JSCompiler_temp$jscomp$0 === responderInst; + JSCompiler_temp$jscomp$0 = ResponderSyntheticEvent.getPooled( + JSCompiler_temp, + JSCompiler_temp$jscomp$0, + nativeEvent, + nativeEventTarget + ); + JSCompiler_temp$jscomp$0.touchHistory = + ResponderTouchHistoryStore.touchHistory; + targetInst + ? forEachAccumulated( + JSCompiler_temp$jscomp$0, + accumulateTwoPhaseDispatchesSingleSkipTarget + ) + : forEachAccumulated( + JSCompiler_temp$jscomp$0, + accumulateTwoPhaseDispatchesSingle + ); + b: { + JSCompiler_temp = JSCompiler_temp$jscomp$0._dispatchListeners; + targetInst = JSCompiler_temp$jscomp$0._dispatchInstances; + if (Array.isArray(JSCompiler_temp)) + for ( + depthA = 0; + depthA < JSCompiler_temp.length && + !JSCompiler_temp$jscomp$0.isPropagationStopped(); + depthA++ + ) { + if ( + JSCompiler_temp[depthA]( + JSCompiler_temp$jscomp$0, + targetInst[depthA] + ) + ) { + JSCompiler_temp = targetInst[depthA]; + break b; + } + } + else if ( + JSCompiler_temp && + JSCompiler_temp(JSCompiler_temp$jscomp$0, targetInst) + ) { + JSCompiler_temp = targetInst; + break b; + } + JSCompiler_temp = null; + } + JSCompiler_temp$jscomp$0._dispatchInstances = null; + JSCompiler_temp$jscomp$0._dispatchListeners = null; + JSCompiler_temp$jscomp$0.isPersistent() || + JSCompiler_temp$jscomp$0.constructor.release( + JSCompiler_temp$jscomp$0 + ); + JSCompiler_temp && JSCompiler_temp !== responderInst + ? ((JSCompiler_temp$jscomp$0 = void 0), + (targetInst = ResponderSyntheticEvent.getPooled( + eventTypes.responderGrant, + JSCompiler_temp, + nativeEvent, + nativeEventTarget + )), + (targetInst.touchHistory = ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(targetInst, accumulateDirectDispatchesSingle), + (depthA = !0 === executeDirectDispatch(targetInst)), + responderInst + ? ((tempA = ResponderSyntheticEvent.getPooled( + eventTypes.responderTerminationRequest, + responderInst, + nativeEvent, + nativeEventTarget + )), + (tempA.touchHistory = ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(tempA, accumulateDirectDispatchesSingle), + (tempB = + !tempA._dispatchListeners || executeDirectDispatch(tempA)), + tempA.isPersistent() || tempA.constructor.release(tempA), + tempB + ? ((tempA = ResponderSyntheticEvent.getPooled( + eventTypes.responderTerminate, + responderInst, + nativeEvent, + nativeEventTarget + )), + (tempA.touchHistory = + ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(tempA, accumulateDirectDispatchesSingle), + (JSCompiler_temp$jscomp$0 = accumulate( + JSCompiler_temp$jscomp$0, + [targetInst, tempA] + )), + changeResponder(JSCompiler_temp, depthA)) + : ((JSCompiler_temp = ResponderSyntheticEvent.getPooled( + eventTypes.responderReject, + JSCompiler_temp, + nativeEvent, + nativeEventTarget + )), + (JSCompiler_temp.touchHistory = + ResponderTouchHistoryStore.touchHistory), + forEachAccumulated( + JSCompiler_temp, + accumulateDirectDispatchesSingle + ), + (JSCompiler_temp$jscomp$0 = accumulate( + JSCompiler_temp$jscomp$0, + JSCompiler_temp + )))) + : ((JSCompiler_temp$jscomp$0 = accumulate( + JSCompiler_temp$jscomp$0, + targetInst + )), + changeResponder(JSCompiler_temp, depthA)), + (JSCompiler_temp = JSCompiler_temp$jscomp$0)) + : (JSCompiler_temp = null); + } else JSCompiler_temp = null; + JSCompiler_temp$jscomp$0 = responderInst && isStartish(topLevelType); + targetInst = responderInst && isMoveish(topLevelType); + depthA = + responderInst && + ("topTouchEnd" === topLevelType || "topTouchCancel" === topLevelType); + if ( + (JSCompiler_temp$jscomp$0 = JSCompiler_temp$jscomp$0 + ? eventTypes.responderStart + : targetInst + ? eventTypes.responderMove + : depthA + ? eventTypes.responderEnd + : null) + ) + (JSCompiler_temp$jscomp$0 = ResponderSyntheticEvent.getPooled( + JSCompiler_temp$jscomp$0, + responderInst, + nativeEvent, + nativeEventTarget + )), + (JSCompiler_temp$jscomp$0.touchHistory = + ResponderTouchHistoryStore.touchHistory), + forEachAccumulated( + JSCompiler_temp$jscomp$0, + accumulateDirectDispatchesSingle + ), + (JSCompiler_temp = accumulate( + JSCompiler_temp, + JSCompiler_temp$jscomp$0 + )); + JSCompiler_temp$jscomp$0 = + responderInst && "topTouchCancel" === topLevelType; + if ( + (topLevelType = + responderInst && + !JSCompiler_temp$jscomp$0 && + ("topTouchEnd" === topLevelType || "topTouchCancel" === topLevelType)) + ) + a: { + if ((topLevelType = nativeEvent.touches) && 0 !== topLevelType.length) + for (targetInst = 0; targetInst < topLevelType.length; targetInst++) + if ( + ((depthA = topLevelType[targetInst].target), + null !== depthA && void 0 !== depthA && 0 !== depthA) + ) { + tempA = getInstanceFromNode(depthA); + b: { + for (depthA = responderInst; tempA; ) { + if (depthA === tempA || depthA === tempA.alternate) { + depthA = !0; + break b; + } + tempA = getParent(tempA); + } + depthA = !1; + } + if (depthA) { + topLevelType = !1; + break a; + } + } + topLevelType = !0; + } + if ( + (topLevelType = JSCompiler_temp$jscomp$0 + ? eventTypes.responderTerminate + : topLevelType + ? eventTypes.responderRelease + : null) + ) + (nativeEvent = ResponderSyntheticEvent.getPooled( + topLevelType, + responderInst, + nativeEvent, + nativeEventTarget + )), + (nativeEvent.touchHistory = ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(nativeEvent, accumulateDirectDispatchesSingle), + (JSCompiler_temp = accumulate(JSCompiler_temp, nativeEvent)), + changeResponder(null); + return JSCompiler_temp; + }, + GlobalResponderHandler: null, + injection: { + injectGlobalResponderHandler: function(GlobalResponderHandler) { + ResponderEventPlugin.GlobalResponderHandler = GlobalResponderHandler; + } + } + }, + customBubblingEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customBubblingEventTypes, + customDirectEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customDirectEventTypes, + ReactNativeBridgeEventPlugin = { + eventTypes: + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes, + extractEvents: function( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ) { + if (null == targetInst) return null; + var bubbleDispatchConfig = customBubblingEventTypes[topLevelType], + directDispatchConfig = customDirectEventTypes[topLevelType]; + if (!bubbleDispatchConfig && !directDispatchConfig) + throw ReactError( + 'Unsupported top level event type "' + topLevelType + '" dispatched' + ); + topLevelType = SyntheticEvent.getPooled( + bubbleDispatchConfig || directDispatchConfig, + targetInst, + nativeEvent, + nativeEventTarget + ); + if (bubbleDispatchConfig) + forEachAccumulated(topLevelType, accumulateTwoPhaseDispatchesSingle); + else if (directDispatchConfig) + forEachAccumulated(topLevelType, accumulateDirectDispatchesSingle); + else return null; + return topLevelType; + } + }; +injection.injectEventPluginOrder([ + "ResponderEventPlugin", + "ReactNativeBridgeEventPlugin" +]); +injection.injectEventPluginsByName({ + ResponderEventPlugin: ResponderEventPlugin, + ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin +}); +function getInstanceFromInstance(instanceHandle) { + return instanceHandle; +} +getFiberCurrentPropsFromNode = function(inst) { + return inst.canonical.currentProps; +}; +getInstanceFromNode = getInstanceFromInstance; +getNodeFromInstance = function(inst) { + inst = inst.stateNode.canonical._nativeTag; + if (!inst) throw ReactError("All native instances should have a tag."); + return inst; +}; +ResponderEventPlugin.injection.injectGlobalResponderHandler({ + onChange: function(from, to, blockNativeResponder) { + null !== to + ? ReactNativePrivateInterface.UIManager.setJSResponder( + to.stateNode.canonical._nativeTag, + blockNativeResponder + ) + : ReactNativePrivateInterface.UIManager.clearJSResponder(); + } +}); +var ReactSharedInternals = + React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; +ReactSharedInternals.hasOwnProperty("ReactCurrentDispatcher") || + (ReactSharedInternals.ReactCurrentDispatcher = { current: null }); +var hasSymbol = "function" === typeof Symbol && Symbol.for, + REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for("react.element") : 60103, + REACT_PORTAL_TYPE = hasSymbol ? Symbol.for("react.portal") : 60106, + REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for("react.fragment") : 60107, + REACT_STRICT_MODE_TYPE = hasSymbol ? Symbol.for("react.strict_mode") : 60108, + REACT_PROFILER_TYPE = hasSymbol ? Symbol.for("react.profiler") : 60114, + REACT_PROVIDER_TYPE = hasSymbol ? Symbol.for("react.provider") : 60109, + REACT_CONTEXT_TYPE = hasSymbol ? Symbol.for("react.context") : 60110, + REACT_CONCURRENT_MODE_TYPE = hasSymbol + ? Symbol.for("react.concurrent_mode") + : 60111, + REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for("react.forward_ref") : 60112, + REACT_SUSPENSE_TYPE = hasSymbol ? Symbol.for("react.suspense") : 60113, + REACT_MEMO_TYPE = hasSymbol ? Symbol.for("react.memo") : 60115, + REACT_LAZY_TYPE = hasSymbol ? Symbol.for("react.lazy") : 60116; +hasSymbol && Symbol.for("react.event_component"); +hasSymbol && Symbol.for("react.event_target"); +hasSymbol && Symbol.for("react.event_target.touch_hit"); +var MAYBE_ITERATOR_SYMBOL = "function" === typeof Symbol && Symbol.iterator; +function getIteratorFn(maybeIterable) { + if (null === maybeIterable || "object" !== typeof maybeIterable) return null; + maybeIterable = + (MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL]) || + maybeIterable["@@iterator"]; + return "function" === typeof maybeIterable ? maybeIterable : null; +} +require("../shims/ReactFeatureFlags"); +function getComponentName(type) { + if (null == type) return null; + if ("function" === typeof type) return type.displayName || type.name || null; + if ("string" === typeof type) return type; + switch (type) { + case REACT_CONCURRENT_MODE_TYPE: + return "ConcurrentMode"; + case REACT_FRAGMENT_TYPE: + return "Fragment"; + case REACT_PORTAL_TYPE: + return "Portal"; + case REACT_PROFILER_TYPE: + return "Profiler"; + case REACT_STRICT_MODE_TYPE: + return "StrictMode"; + case REACT_SUSPENSE_TYPE: + return "Suspense"; + } + if ("object" === typeof type) + switch (type.$$typeof) { + case REACT_CONTEXT_TYPE: + return "Context.Consumer"; + case REACT_PROVIDER_TYPE: + return "Context.Provider"; + case REACT_FORWARD_REF_TYPE: + var innerType = type.render; + innerType = innerType.displayName || innerType.name || ""; + return ( + type.displayName || + ("" !== innerType ? "ForwardRef(" + innerType + ")" : "ForwardRef") + ); + case REACT_MEMO_TYPE: + return getComponentName(type.type); + case REACT_LAZY_TYPE: + if ((type = 1 === type._status ? type._result : null)) + return getComponentName(type); + } + return null; +} +function isFiberMountedImpl(fiber) { + var node = fiber; + if (fiber.alternate) for (; node.return; ) node = node.return; + else { + if (0 !== (node.effectTag & 2)) return 1; + for (; node.return; ) + if (((node = node.return), 0 !== (node.effectTag & 2))) return 1; + } + return 3 === node.tag ? 2 : 3; +} +function assertIsMounted(fiber) { + if (2 !== isFiberMountedImpl(fiber)) + throw ReactError("Unable to find node on an unmounted component."); +} +function findCurrentFiberUsingSlowPath(fiber) { + var alternate = fiber.alternate; + if (!alternate) { + alternate = isFiberMountedImpl(fiber); + if (3 === alternate) + throw ReactError("Unable to find node on an unmounted component."); + return 1 === alternate ? null : fiber; + } + for (var a = fiber, b = alternate; ; ) { + var parentA = a.return; + if (null === parentA) break; + var parentB = parentA.alternate; + if (null === parentB) { + b = parentA.return; + if (null !== b) { + a = b; + continue; + } + break; + } + if (parentA.child === parentB.child) { + for (parentB = parentA.child; parentB; ) { + if (parentB === a) return assertIsMounted(parentA), fiber; + if (parentB === b) return assertIsMounted(parentA), alternate; + parentB = parentB.sibling; + } + throw ReactError("Unable to find node on an unmounted component."); + } + if (a.return !== b.return) (a = parentA), (b = parentB); + else { + for (var didFindChild = !1, _child = parentA.child; _child; ) { + if (_child === a) { + didFindChild = !0; + a = parentA; + b = parentB; + break; + } + if (_child === b) { + didFindChild = !0; + b = parentA; + a = parentB; + break; + } + _child = _child.sibling; + } + if (!didFindChild) { + for (_child = parentB.child; _child; ) { + if (_child === a) { + didFindChild = !0; + a = parentB; + b = parentA; + break; + } + if (_child === b) { + didFindChild = !0; + b = parentB; + a = parentA; + break; + } + _child = _child.sibling; + } + if (!didFindChild) + throw ReactError( + "Child was not found in either parent set. This indicates a bug in React related to the return pointer. Please file an issue." + ); + } + } + if (a.alternate !== b) + throw ReactError( + "Return fibers should always be each others' alternates. This error is likely caused by a bug in React. Please file an issue." + ); + } + if (3 !== a.tag) + throw ReactError("Unable to find node on an unmounted component."); + return a.stateNode.current === a ? fiber : alternate; +} +function findCurrentHostFiber(parent) { + parent = findCurrentFiberUsingSlowPath(parent); + if (!parent) return null; + for (var node = parent; ; ) { + if (5 === node.tag || 6 === node.tag) return node; + if (node.child) (node.child.return = node), (node = node.child); + else { + if (node === parent) break; + for (; !node.sibling; ) { + if (!node.return || node.return === parent) return null; + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + } + return null; +} +function mountSafeCallback_NOT_REALLY_SAFE(context, callback) { + return function() { + if ( + callback && + ("boolean" !== typeof context.__isMounted || context.__isMounted) + ) + return callback.apply(context, arguments); + }; +} +var emptyObject = {}, + removedKeys = null, + removedKeyCount = 0; +function restoreDeletedValuesInNestedArray( + updatePayload, + node, + validAttributes +) { + if (Array.isArray(node)) + for (var i = node.length; i-- && 0 < removedKeyCount; ) + restoreDeletedValuesInNestedArray( + updatePayload, + node[i], + validAttributes + ); + else if (node && 0 < removedKeyCount) + for (i in removedKeys) + if (removedKeys[i]) { + var nextProp = node[i]; + if (void 0 !== nextProp) { + var attributeConfig = validAttributes[i]; + if (attributeConfig) { + "function" === typeof nextProp && (nextProp = !0); + "undefined" === typeof nextProp && (nextProp = null); + if ("object" !== typeof attributeConfig) + updatePayload[i] = nextProp; + else if ( + "function" === typeof attributeConfig.diff || + "function" === typeof attributeConfig.process + ) + (nextProp = + "function" === typeof attributeConfig.process + ? attributeConfig.process(nextProp) + : nextProp), + (updatePayload[i] = nextProp); + removedKeys[i] = !1; + removedKeyCount--; + } + } + } +} +function diffNestedProperty( + updatePayload, + prevProp, + nextProp, + validAttributes +) { + if (!updatePayload && prevProp === nextProp) return updatePayload; + if (!prevProp || !nextProp) + return nextProp + ? addNestedProperty(updatePayload, nextProp, validAttributes) + : prevProp + ? clearNestedProperty(updatePayload, prevProp, validAttributes) + : updatePayload; + if (!Array.isArray(prevProp) && !Array.isArray(nextProp)) + return diffProperties(updatePayload, prevProp, nextProp, validAttributes); + if (Array.isArray(prevProp) && Array.isArray(nextProp)) { + var minLength = + prevProp.length < nextProp.length ? prevProp.length : nextProp.length, + i; + for (i = 0; i < minLength; i++) + updatePayload = diffNestedProperty( + updatePayload, + prevProp[i], + nextProp[i], + validAttributes + ); + for (; i < prevProp.length; i++) + updatePayload = clearNestedProperty( + updatePayload, + prevProp[i], + validAttributes + ); + for (; i < nextProp.length; i++) + updatePayload = addNestedProperty( + updatePayload, + nextProp[i], + validAttributes + ); + return updatePayload; + } + return Array.isArray(prevProp) + ? diffProperties( + updatePayload, + ReactNativePrivateInterface.flattenStyle(prevProp), + nextProp, + validAttributes + ) + : diffProperties( + updatePayload, + prevProp, + ReactNativePrivateInterface.flattenStyle(nextProp), + validAttributes + ); +} +function addNestedProperty(updatePayload, nextProp, validAttributes) { + if (!nextProp) return updatePayload; + if (!Array.isArray(nextProp)) + return diffProperties( + updatePayload, + emptyObject, + nextProp, + validAttributes + ); + for (var i = 0; i < nextProp.length; i++) + updatePayload = addNestedProperty( + updatePayload, + nextProp[i], + validAttributes + ); + return updatePayload; +} +function clearNestedProperty(updatePayload, prevProp, validAttributes) { + if (!prevProp) return updatePayload; + if (!Array.isArray(prevProp)) + return diffProperties( + updatePayload, + prevProp, + emptyObject, + validAttributes + ); + for (var i = 0; i < prevProp.length; i++) + updatePayload = clearNestedProperty( + updatePayload, + prevProp[i], + validAttributes + ); + return updatePayload; +} +function diffProperties(updatePayload, prevProps, nextProps, validAttributes) { + var attributeConfig, propKey; + for (propKey in nextProps) + if ((attributeConfig = validAttributes[propKey])) { + var prevProp = prevProps[propKey]; + var nextProp = nextProps[propKey]; + "function" === typeof nextProp && + ((nextProp = !0), "function" === typeof prevProp && (prevProp = !0)); + "undefined" === typeof nextProp && + ((nextProp = null), + "undefined" === typeof prevProp && (prevProp = null)); + removedKeys && (removedKeys[propKey] = !1); + if (updatePayload && void 0 !== updatePayload[propKey]) + if ("object" !== typeof attributeConfig) + updatePayload[propKey] = nextProp; + else { + if ( + "function" === typeof attributeConfig.diff || + "function" === typeof attributeConfig.process + ) + (attributeConfig = + "function" === typeof attributeConfig.process + ? attributeConfig.process(nextProp) + : nextProp), + (updatePayload[propKey] = attributeConfig); + } + else if (prevProp !== nextProp) + if ("object" !== typeof attributeConfig) + ("object" !== typeof nextProp || + null === nextProp || + ReactNativePrivateInterface.deepDiffer(prevProp, nextProp)) && + ((updatePayload || (updatePayload = {}))[propKey] = nextProp); + else if ( + "function" === typeof attributeConfig.diff || + "function" === typeof attributeConfig.process + ) { + if ( + void 0 === prevProp || + ("function" === typeof attributeConfig.diff + ? attributeConfig.diff(prevProp, nextProp) + : "object" !== typeof nextProp || + null === nextProp || + ReactNativePrivateInterface.deepDiffer(prevProp, nextProp)) + ) + (attributeConfig = + "function" === typeof attributeConfig.process + ? attributeConfig.process(nextProp) + : nextProp), + ((updatePayload || (updatePayload = {}))[ + propKey + ] = attributeConfig); + } else + (removedKeys = null), + (removedKeyCount = 0), + (updatePayload = diffNestedProperty( + updatePayload, + prevProp, + nextProp, + attributeConfig + )), + 0 < removedKeyCount && + updatePayload && + (restoreDeletedValuesInNestedArray( + updatePayload, + nextProp, + attributeConfig + ), + (removedKeys = null)); + } + for (var _propKey in prevProps) + void 0 === nextProps[_propKey] && + (!(attributeConfig = validAttributes[_propKey]) || + (updatePayload && void 0 !== updatePayload[_propKey]) || + ((prevProp = prevProps[_propKey]), + void 0 !== prevProp && + ("object" !== typeof attributeConfig || + "function" === typeof attributeConfig.diff || + "function" === typeof attributeConfig.process + ? (((updatePayload || (updatePayload = {}))[_propKey] = null), + removedKeys || (removedKeys = {}), + removedKeys[_propKey] || + ((removedKeys[_propKey] = !0), removedKeyCount++)) + : (updatePayload = clearNestedProperty( + updatePayload, + prevProp, + attributeConfig + ))))); + return updatePayload; +} +var restoreTarget = null, + restoreQueue = null; +function restoreStateOfTarget(target) { + if (getInstanceFromNode(target)) + throw ReactError( + "setRestoreImplementation() needs to be called to handle a target for controlled events. This error is likely caused by a bug in React. Please file an issue." + ); +} +function _batchedUpdatesImpl(fn, bookkeeping) { + return fn(bookkeeping); +} +function _flushInteractiveUpdatesImpl() {} +var isBatching = !1; +function batchedUpdates(fn, bookkeeping) { + if (isBatching) return fn(bookkeeping); + isBatching = !0; + try { + return _batchedUpdatesImpl(fn, bookkeeping); + } finally { + if (((isBatching = !1), null !== restoreTarget || null !== restoreQueue)) + if ( + (_flushInteractiveUpdatesImpl(), + restoreTarget && + ((bookkeeping = restoreTarget), + (fn = restoreQueue), + (restoreQueue = restoreTarget = null), + restoreStateOfTarget(bookkeeping), + fn)) + ) + for (bookkeeping = 0; bookkeeping < fn.length; bookkeeping++) + restoreStateOfTarget(fn[bookkeeping]); + } +} +function dispatchEvent(target, topLevelType, nativeEvent) { + batchedUpdates(function() { + var events = nativeEvent.target; + for (var events$jscomp$0 = null, i = 0; i < plugins.length; i++) { + var possiblePlugin = plugins[i]; + possiblePlugin && + (possiblePlugin = possiblePlugin.extractEvents( + topLevelType, + target, + nativeEvent, + events + )) && + (events$jscomp$0 = accumulateInto(events$jscomp$0, possiblePlugin)); + } + events = events$jscomp$0; + null !== events && (eventQueue = accumulateInto(eventQueue, events)); + events = eventQueue; + eventQueue = null; + if (events) { + forEachAccumulated(events, executeDispatchesAndReleaseTopLevel); + if (eventQueue) + throw ReactError( + "processEventQueue(): Additional events were enqueued while processing an event queue. Support for this has not yet been implemented." + ); + if (hasRethrowError) + throw ((events = rethrowError), + (hasRethrowError = !1), + (rethrowError = null), + events); + } + }); +} +function shim$1() { + throw ReactError( + "The current renderer does not support hydration. This error is likely caused by a bug in React. Please file an issue." + ); +} +var _nativeFabricUIManage = nativeFabricUIManager, + createNode = _nativeFabricUIManage.createNode, + cloneNode = _nativeFabricUIManage.cloneNode, + cloneNodeWithNewChildren = _nativeFabricUIManage.cloneNodeWithNewChildren, + cloneNodeWithNewChildrenAndProps = + _nativeFabricUIManage.cloneNodeWithNewChildrenAndProps, + cloneNodeWithNewProps = _nativeFabricUIManage.cloneNodeWithNewProps, + createChildNodeSet = _nativeFabricUIManage.createChildSet, + appendChildNode = _nativeFabricUIManage.appendChild, + appendChildNodeToSet = _nativeFabricUIManage.appendChildToSet, + completeRoot = _nativeFabricUIManage.completeRoot, + registerEventHandler = _nativeFabricUIManage.registerEventHandler, + fabricMeasure = _nativeFabricUIManage.measure, + fabricMeasureInWindow = _nativeFabricUIManage.measureInWindow, + fabricMeasureLayout = _nativeFabricUIManage.measureLayout, + getViewConfigForType = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.get, + nextReactTag = 2; +registerEventHandler && registerEventHandler(dispatchEvent); +var ReactFabricHostComponent = (function() { + function ReactFabricHostComponent( + tag, + viewConfig, + props, + internalInstanceHandle + ) { + if (!(this instanceof ReactFabricHostComponent)) + throw new TypeError("Cannot call a class as a function"); + this._nativeTag = tag; + this.viewConfig = viewConfig; + this.currentProps = props; + this._internalInstanceHandle = internalInstanceHandle; + } + ReactFabricHostComponent.prototype.blur = function() { + ReactNativePrivateInterface.TextInputState.blurTextInput(this._nativeTag); + }; + ReactFabricHostComponent.prototype.focus = function() { + ReactNativePrivateInterface.TextInputState.focusTextInput(this._nativeTag); + }; + ReactFabricHostComponent.prototype.measure = function(callback) { + fabricMeasure( + this._internalInstanceHandle.stateNode.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + }; + ReactFabricHostComponent.prototype.measureInWindow = function(callback) { + fabricMeasureInWindow( + this._internalInstanceHandle.stateNode.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + }; + ReactFabricHostComponent.prototype.measureLayout = function( + relativeToNativeNode, + onSuccess, + onFail + ) { + "number" !== typeof relativeToNativeNode && + relativeToNativeNode instanceof ReactFabricHostComponent && + fabricMeasureLayout( + this._internalInstanceHandle.stateNode.node, + relativeToNativeNode._internalInstanceHandle.stateNode.node, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + ); + }; + ReactFabricHostComponent.prototype.setNativeProps = function() {}; + return ReactFabricHostComponent; +})(); +function createTextInstance( + text, + rootContainerInstance, + hostContext, + internalInstanceHandle +) { + if (!hostContext.isInAParentText) + throw ReactError( + "Text strings must be rendered within a component." + ); + hostContext = nextReactTag; + nextReactTag += 2; + return { + node: createNode( + hostContext, + "RCTRawText", + rootContainerInstance, + { text: text }, + internalInstanceHandle + ) + }; +} +var scheduleTimeout = setTimeout, + cancelTimeout = clearTimeout; +function cloneHiddenInstance(instance) { + var node = instance.node; + var updatePayload = diffProperties( + null, + emptyObject, + { style: { display: "none" } }, + instance.canonical.viewConfig.validAttributes + ); + return { + node: cloneNodeWithNewProps(node, updatePayload), + canonical: instance.canonical + }; +} +var BEFORE_SLASH_RE = /^(.*)[\\\/]/; +function getStackByFiberInDevAndProd(workInProgress) { + var info = ""; + do { + a: switch (workInProgress.tag) { + case 3: + case 4: + case 6: + case 7: + case 10: + case 9: + var JSCompiler_inline_result = ""; + break a; + default: + var owner = workInProgress._debugOwner, + source = workInProgress._debugSource, + name = getComponentName(workInProgress.type); + JSCompiler_inline_result = null; + owner && (JSCompiler_inline_result = getComponentName(owner.type)); + owner = name; + name = ""; + source + ? (name = + " (at " + + source.fileName.replace(BEFORE_SLASH_RE, "") + + ":" + + source.lineNumber + + ")") + : JSCompiler_inline_result && + (name = " (created by " + JSCompiler_inline_result + ")"); + JSCompiler_inline_result = "\n in " + (owner || "Unknown") + name; + } + info += JSCompiler_inline_result; + workInProgress = workInProgress.return; + } while (workInProgress); + return info; +} +new Set(); +var valueStack = [], + index = -1; +function pop(cursor) { + 0 > index || + ((cursor.current = valueStack[index]), (valueStack[index] = null), index--); +} +function push(cursor, value) { + index++; + valueStack[index] = cursor.current; + cursor.current = value; +} +var emptyContextObject = {}, + contextStackCursor = { current: emptyContextObject }, + didPerformWorkStackCursor = { current: !1 }, + previousContext = emptyContextObject; +function getMaskedContext(workInProgress, unmaskedContext) { + var contextTypes = workInProgress.type.contextTypes; + if (!contextTypes) return emptyContextObject; + var instance = workInProgress.stateNode; + if ( + instance && + instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext + ) + return instance.__reactInternalMemoizedMaskedChildContext; + var context = {}, + key; + for (key in contextTypes) context[key] = unmaskedContext[key]; + instance && + ((workInProgress = workInProgress.stateNode), + (workInProgress.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext), + (workInProgress.__reactInternalMemoizedMaskedChildContext = context)); + return context; +} +function isContextProvider(type) { + type = type.childContextTypes; + return null !== type && void 0 !== type; +} +function popContext(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); +} +function popTopLevelContextObject(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); +} +function pushTopLevelContextObject(fiber, context, didChange) { + if (contextStackCursor.current !== emptyContextObject) + throw ReactError( + "Unexpected context found on stack. This error is likely caused by a bug in React. Please file an issue." + ); + push(contextStackCursor, context, fiber); + push(didPerformWorkStackCursor, didChange, fiber); +} +function processChildContext(fiber, type, parentContext) { + var instance = fiber.stateNode; + fiber = type.childContextTypes; + if ("function" !== typeof instance.getChildContext) return parentContext; + instance = instance.getChildContext(); + for (var contextKey in instance) + if (!(contextKey in fiber)) + throw ReactError( + (getComponentName(type) || "Unknown") + + '.getChildContext(): key "' + + contextKey + + '" is not defined in childContextTypes.' + ); + return Object.assign({}, parentContext, instance); +} +function pushContextProvider(workInProgress) { + var instance = workInProgress.stateNode; + instance = + (instance && instance.__reactInternalMemoizedMergedChildContext) || + emptyContextObject; + previousContext = contextStackCursor.current; + push(contextStackCursor, instance, workInProgress); + push( + didPerformWorkStackCursor, + didPerformWorkStackCursor.current, + workInProgress + ); + return !0; +} +function invalidateContextProvider(workInProgress, type, didChange) { + var instance = workInProgress.stateNode; + if (!instance) + throw ReactError( + "Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue." + ); + didChange + ? ((type = processChildContext(workInProgress, type, previousContext)), + (instance.__reactInternalMemoizedMergedChildContext = type), + pop(didPerformWorkStackCursor, workInProgress), + pop(contextStackCursor, workInProgress), + push(contextStackCursor, type, workInProgress)) + : pop(didPerformWorkStackCursor, workInProgress); + push(didPerformWorkStackCursor, didChange, workInProgress); +} +var onCommitFiberRoot = null, + onCommitFiberUnmount = null; +function catchErrors(fn) { + return function(arg) { + try { + return fn(arg); + } catch (err) {} + }; +} +var isDevToolsPresent = "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__; +function injectInternals(internals) { + if ("undefined" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) return !1; + var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__; + if (hook.isDisabled || !hook.supportsFiber) return !0; + try { + var rendererID = hook.inject(internals); + onCommitFiberRoot = catchErrors(function(root) { + return hook.onCommitFiberRoot(rendererID, root); + }); + onCommitFiberUnmount = catchErrors(function(fiber) { + return hook.onCommitFiberUnmount(rendererID, fiber); + }); + } catch (err) {} + return !0; +} +var Scheduler_runWithPriority = Scheduler.unstable_runWithPriority, + Scheduler_scheduleCallback = Scheduler.unstable_scheduleCallback, + Scheduler_cancelCallback = Scheduler.unstable_cancelCallback, + Scheduler_shouldYield = Scheduler.unstable_shouldYield, + Scheduler_now = Scheduler.unstable_now, + Scheduler_getCurrentPriorityLevel = + Scheduler.unstable_getCurrentPriorityLevel, + Scheduler_ImmediatePriority = Scheduler.unstable_ImmediatePriority, + Scheduler_UserBlockingPriority = Scheduler.unstable_UserBlockingPriority, + Scheduler_NormalPriority = Scheduler.unstable_NormalPriority, + Scheduler_LowPriority = Scheduler.unstable_LowPriority, + Scheduler_IdlePriority = Scheduler.unstable_IdlePriority; +if ( + null == tracing.__interactionsRef || + null == tracing.__interactionsRef.current +) + throw ReactError( + "It is not supported to run the profiling version of a renderer (for example, `react-dom/profiling`) without also replacing the `scheduler/tracing` module with `scheduler/tracing-profiling`. Your bundler might have a setting for aliasing both modules. Learn more at http://fb.me/react-profiling" + ); +var fakeCallbackNode = {}, + immediateQueue = null, + immediateQueueCallbackNode = null, + isFlushingImmediate = !1, + initialTimeMs = Scheduler_now(), + now = + 1e4 > initialTimeMs + ? Scheduler_now + : function() { + return Scheduler_now() - initialTimeMs; + }; +function getCurrentPriorityLevel() { + switch (Scheduler_getCurrentPriorityLevel()) { + case Scheduler_ImmediatePriority: + return 99; + case Scheduler_UserBlockingPriority: + return 98; + case Scheduler_NormalPriority: + return 97; + case Scheduler_LowPriority: + return 96; + case Scheduler_IdlePriority: + return 95; + default: + throw ReactError("Unknown priority level."); + } +} +function reactPriorityToSchedulerPriority(reactPriorityLevel) { + switch (reactPriorityLevel) { + case 99: + return Scheduler_ImmediatePriority; + case 98: + return Scheduler_UserBlockingPriority; + case 97: + return Scheduler_NormalPriority; + case 96: + return Scheduler_LowPriority; + case 95: + return Scheduler_IdlePriority; + default: + throw ReactError("Unknown priority level."); + } +} +function runWithPriority(reactPriorityLevel, fn) { + reactPriorityLevel = reactPriorityToSchedulerPriority(reactPriorityLevel); + return Scheduler_runWithPriority(reactPriorityLevel, fn); +} +function scheduleCallback(reactPriorityLevel, callback, options) { + if (99 === reactPriorityLevel) + return ( + null === immediateQueue + ? ((immediateQueue = [callback]), + (immediateQueueCallbackNode = Scheduler_scheduleCallback( + Scheduler_ImmediatePriority, + flushImmediateQueueImpl + ))) + : immediateQueue.push(callback), + fakeCallbackNode + ); + reactPriorityLevel = reactPriorityToSchedulerPriority(reactPriorityLevel); + return Scheduler_scheduleCallback(reactPriorityLevel, callback, options); +} +function flushImmediateQueue() { + null !== immediateQueueCallbackNode && + Scheduler_cancelCallback(immediateQueueCallbackNode); + flushImmediateQueueImpl(); +} +function flushImmediateQueueImpl() { + if (!isFlushingImmediate && null !== immediateQueue) { + isFlushingImmediate = !0; + var i = 0; + try { + for (; i < immediateQueue.length; i++) { + var callback = immediateQueue[i]; + do callback = callback(!0); + while (null !== callback); + } + immediateQueue = null; + } catch (error) { + throw (null !== immediateQueue && + (immediateQueue = immediateQueue.slice(i + 1)), + Scheduler_scheduleCallback( + Scheduler_ImmediatePriority, + flushImmediateQueue + ), + error); + } finally { + isFlushingImmediate = !1; + } + } +} +function inferPriorityFromExpirationTime(currentTime, expirationTime) { + if (1073741823 === expirationTime) return 99; + if (1 === expirationTime) return 95; + currentTime = + 10 * (1073741822 - expirationTime) - 10 * (1073741822 - currentTime); + return 0 >= currentTime + ? 99 + : 250 >= currentTime + ? 98 + : 5250 >= currentTime + ? 97 + : 95; +} +function FiberNode(tag, pendingProps, key, mode) { + this.tag = tag; + this.key = key; + this.sibling = this.child = this.return = this.stateNode = this.type = this.elementType = null; + this.index = 0; + this.ref = null; + this.pendingProps = pendingProps; + this.contextDependencies = this.memoizedState = this.updateQueue = this.memoizedProps = null; + this.mode = mode; + this.effectTag = 0; + this.lastEffect = this.firstEffect = this.nextEffect = null; + this.childExpirationTime = this.expirationTime = 0; + this.alternate = null; + this.actualDuration = 0; + this.actualStartTime = -1; + this.treeBaseDuration = this.selfBaseDuration = 0; +} +function createFiber(tag, pendingProps, key, mode) { + return new FiberNode(tag, pendingProps, key, mode); +} +function shouldConstruct(Component) { + Component = Component.prototype; + return !(!Component || !Component.isReactComponent); +} +function resolveLazyComponentTag(Component) { + if ("function" === typeof Component) + return shouldConstruct(Component) ? 1 : 0; + if (void 0 !== Component && null !== Component) { + Component = Component.$$typeof; + if (Component === REACT_FORWARD_REF_TYPE) return 11; + if (Component === REACT_MEMO_TYPE) return 14; + } + return 2; +} +function createWorkInProgress(current, pendingProps) { + var workInProgress = current.alternate; + null === workInProgress + ? ((workInProgress = createFiber( + current.tag, + pendingProps, + current.key, + current.mode + )), + (workInProgress.elementType = current.elementType), + (workInProgress.type = current.type), + (workInProgress.stateNode = current.stateNode), + (workInProgress.alternate = current), + (current.alternate = workInProgress)) + : ((workInProgress.pendingProps = pendingProps), + (workInProgress.effectTag = 0), + (workInProgress.nextEffect = null), + (workInProgress.firstEffect = null), + (workInProgress.lastEffect = null), + (workInProgress.actualDuration = 0), + (workInProgress.actualStartTime = -1)); + workInProgress.childExpirationTime = current.childExpirationTime; + workInProgress.expirationTime = current.expirationTime; + workInProgress.child = current.child; + workInProgress.memoizedProps = current.memoizedProps; + workInProgress.memoizedState = current.memoizedState; + workInProgress.updateQueue = current.updateQueue; + workInProgress.contextDependencies = current.contextDependencies; + workInProgress.sibling = current.sibling; + workInProgress.index = current.index; + workInProgress.ref = current.ref; + workInProgress.selfBaseDuration = current.selfBaseDuration; + workInProgress.treeBaseDuration = current.treeBaseDuration; + return workInProgress; +} +function createFiberFromTypeAndProps( + type, + key, + pendingProps, + owner, + mode, + expirationTime +) { + var fiberTag = 2; + owner = type; + if ("function" === typeof type) shouldConstruct(type) && (fiberTag = 1); + else if ("string" === typeof type) fiberTag = 5; + else + a: switch (type) { + case REACT_FRAGMENT_TYPE: + return createFiberFromFragment( + pendingProps.children, + mode, + expirationTime, + key + ); + case REACT_CONCURRENT_MODE_TYPE: + return createFiberFromMode(pendingProps, mode | 3, expirationTime, key); + case REACT_STRICT_MODE_TYPE: + return createFiberFromMode(pendingProps, mode | 2, expirationTime, key); + case REACT_PROFILER_TYPE: + return ( + (type = createFiber(12, pendingProps, key, mode | 4)), + (type.elementType = REACT_PROFILER_TYPE), + (type.type = REACT_PROFILER_TYPE), + (type.expirationTime = expirationTime), + type + ); + case REACT_SUSPENSE_TYPE: + return ( + (type = createFiber(13, pendingProps, key, mode)), + (type.elementType = REACT_SUSPENSE_TYPE), + (type.type = REACT_SUSPENSE_TYPE), + (type.expirationTime = expirationTime), + type + ); + default: + if ("object" === typeof type && null !== type) + switch (type.$$typeof) { + case REACT_PROVIDER_TYPE: + fiberTag = 10; + break a; + case REACT_CONTEXT_TYPE: + fiberTag = 9; + break a; + case REACT_FORWARD_REF_TYPE: + fiberTag = 11; + break a; + case REACT_MEMO_TYPE: + fiberTag = 14; + break a; + case REACT_LAZY_TYPE: + fiberTag = 16; + owner = null; + break a; + } + throw ReactError( + "Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: " + + (null == type ? type : typeof type) + + "." + ); + } + key = createFiber(fiberTag, pendingProps, key, mode); + key.elementType = type; + key.type = owner; + key.expirationTime = expirationTime; + return key; +} +function createFiberFromFragment(elements, mode, expirationTime, key) { + elements = createFiber(7, elements, key, mode); + elements.expirationTime = expirationTime; + return elements; +} +function createFiberFromMode(pendingProps, mode, expirationTime, key) { + pendingProps = createFiber(8, pendingProps, key, mode); + mode = 0 === (mode & 1) ? REACT_STRICT_MODE_TYPE : REACT_CONCURRENT_MODE_TYPE; + pendingProps.elementType = mode; + pendingProps.type = mode; + pendingProps.expirationTime = expirationTime; + return pendingProps; +} +function createFiberFromText(content, mode, expirationTime) { + content = createFiber(6, content, null, mode); + content.expirationTime = expirationTime; + return content; +} +function createFiberFromPortal(portal, mode, expirationTime) { + mode = createFiber( + 4, + null !== portal.children ? portal.children : [], + portal.key, + mode + ); + mode.expirationTime = expirationTime; + mode.stateNode = { + containerInfo: portal.containerInfo, + pendingChildren: null, + implementation: portal.implementation + }; + return mode; +} +function FiberRootNode(containerInfo, hydrate) { + this.current = null; + this.containerInfo = containerInfo; + this.pingCache = this.pendingChildren = null; + this.pendingCommitExpirationTime = 0; + this.finishedWork = null; + this.timeoutHandle = -1; + this.pendingContext = this.context = null; + this.hydrate = hydrate; + this.callbackNode = this.firstBatch = null; + this.pingTime = this.lastPendingTime = this.firstPendingTime = this.callbackExpirationTime = 0; + this.interactionThreadID = tracing.unstable_getThreadID(); + this.memoizedInteractions = new Set(); + this.pendingInteractionMap = new Map(); +} +function is(x, y) { + return (x === y && (0 !== x || 1 / x === 1 / y)) || (x !== x && y !== y); +} +var hasOwnProperty = Object.prototype.hasOwnProperty; +function shallowEqual(objA, objB) { + if (is(objA, objB)) return !0; + if ( + "object" !== typeof objA || + null === objA || + "object" !== typeof objB || + null === objB + ) + return !1; + var keysA = Object.keys(objA), + keysB = Object.keys(objB); + if (keysA.length !== keysB.length) return !1; + for (keysB = 0; keysB < keysA.length; keysB++) + if ( + !hasOwnProperty.call(objB, keysA[keysB]) || + !is(objA[keysA[keysB]], objB[keysA[keysB]]) + ) + return !1; + return !0; +} +function resolveDefaultProps(Component, baseProps) { + if (Component && Component.defaultProps) { + baseProps = Object.assign({}, baseProps); + Component = Component.defaultProps; + for (var propName in Component) + void 0 === baseProps[propName] && + (baseProps[propName] = Component[propName]); + } + return baseProps; +} +function readLazyComponentType(lazyComponent) { + var result = lazyComponent._result; + switch (lazyComponent._status) { + case 1: + return result; + case 2: + throw result; + case 0: + throw result; + default: + lazyComponent._status = 0; + result = lazyComponent._ctor; + result = result(); + result.then( + function(moduleObject) { + 0 === lazyComponent._status && + ((moduleObject = moduleObject.default), + (lazyComponent._status = 1), + (lazyComponent._result = moduleObject)); + }, + function(error) { + 0 === lazyComponent._status && + ((lazyComponent._status = 2), (lazyComponent._result = error)); + } + ); + switch (lazyComponent._status) { + case 1: + return lazyComponent._result; + case 2: + throw lazyComponent._result; + } + lazyComponent._result = result; + throw result; + } +} +var valueCursor = { current: null }, + currentlyRenderingFiber = null, + lastContextDependency = null, + lastContextWithAllBitsObserved = null; +function resetContextDependences() { + lastContextWithAllBitsObserved = lastContextDependency = currentlyRenderingFiber = null; +} +function pushProvider(providerFiber, nextValue) { + var context = providerFiber.type._context; + push(valueCursor, context._currentValue2, providerFiber); + context._currentValue2 = nextValue; +} +function popProvider(providerFiber) { + var currentValue = valueCursor.current; + pop(valueCursor, providerFiber); + providerFiber.type._context._currentValue2 = currentValue; +} +function prepareToReadContext(workInProgress, renderExpirationTime) { + currentlyRenderingFiber = workInProgress; + lastContextWithAllBitsObserved = lastContextDependency = null; + var currentDependencies = workInProgress.contextDependencies; + null !== currentDependencies && + currentDependencies.expirationTime >= renderExpirationTime && + (didReceiveUpdate = !0); + workInProgress.contextDependencies = null; +} +function readContext(context, observedBits) { + if ( + lastContextWithAllBitsObserved !== context && + !1 !== observedBits && + 0 !== observedBits + ) { + if ("number" !== typeof observedBits || 1073741823 === observedBits) + (lastContextWithAllBitsObserved = context), (observedBits = 1073741823); + observedBits = { context: context, observedBits: observedBits, next: null }; + if (null === lastContextDependency) { + if (null === currentlyRenderingFiber) + throw ReactError( + "Context can only be read while React is rendering. In classes, you can read it in the render method or getDerivedStateFromProps. In function components, you can read it directly in the function body, but not inside Hooks like useReducer() or useMemo()." + ); + lastContextDependency = observedBits; + currentlyRenderingFiber.contextDependencies = { + first: observedBits, + expirationTime: 0 + }; + } else lastContextDependency = lastContextDependency.next = observedBits; + } + return context._currentValue2; +} +var hasForceUpdate = !1; +function createUpdateQueue(baseState) { + return { + baseState: baseState, + firstUpdate: null, + lastUpdate: null, + firstCapturedUpdate: null, + lastCapturedUpdate: null, + firstEffect: null, + lastEffect: null, + firstCapturedEffect: null, + lastCapturedEffect: null + }; +} +function cloneUpdateQueue(currentQueue) { + return { + baseState: currentQueue.baseState, + firstUpdate: currentQueue.firstUpdate, + lastUpdate: currentQueue.lastUpdate, + firstCapturedUpdate: null, + lastCapturedUpdate: null, + firstEffect: null, + lastEffect: null, + firstCapturedEffect: null, + lastCapturedEffect: null + }; +} +function createUpdate(expirationTime) { + return { + expirationTime: expirationTime, + tag: 0, + payload: null, + callback: null, + next: null, + nextEffect: null + }; +} +function appendUpdateToQueue(queue, update) { + null === queue.lastUpdate + ? (queue.firstUpdate = queue.lastUpdate = update) + : ((queue.lastUpdate.next = update), (queue.lastUpdate = update)); +} +function enqueueUpdate(fiber, update) { + var alternate = fiber.alternate; + if (null === alternate) { + var queue1 = fiber.updateQueue; + var queue2 = null; + null === queue1 && + (queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState)); + } else + (queue1 = fiber.updateQueue), + (queue2 = alternate.updateQueue), + null === queue1 + ? null === queue2 + ? ((queue1 = fiber.updateQueue = createUpdateQueue( + fiber.memoizedState + )), + (queue2 = alternate.updateQueue = createUpdateQueue( + alternate.memoizedState + ))) + : (queue1 = fiber.updateQueue = cloneUpdateQueue(queue2)) + : null === queue2 && + (queue2 = alternate.updateQueue = cloneUpdateQueue(queue1)); + null === queue2 || queue1 === queue2 + ? appendUpdateToQueue(queue1, update) + : null === queue1.lastUpdate || null === queue2.lastUpdate + ? (appendUpdateToQueue(queue1, update), + appendUpdateToQueue(queue2, update)) + : (appendUpdateToQueue(queue1, update), (queue2.lastUpdate = update)); +} +function enqueueCapturedUpdate(workInProgress, update) { + var workInProgressQueue = workInProgress.updateQueue; + workInProgressQueue = + null === workInProgressQueue + ? (workInProgress.updateQueue = createUpdateQueue( + workInProgress.memoizedState + )) + : ensureWorkInProgressQueueIsAClone(workInProgress, workInProgressQueue); + null === workInProgressQueue.lastCapturedUpdate + ? (workInProgressQueue.firstCapturedUpdate = workInProgressQueue.lastCapturedUpdate = update) + : ((workInProgressQueue.lastCapturedUpdate.next = update), + (workInProgressQueue.lastCapturedUpdate = update)); +} +function ensureWorkInProgressQueueIsAClone(workInProgress, queue) { + var current = workInProgress.alternate; + null !== current && + queue === current.updateQueue && + (queue = workInProgress.updateQueue = cloneUpdateQueue(queue)); + return queue; +} +function getStateFromUpdate( + workInProgress, + queue, + update, + prevState, + nextProps, + instance +) { + switch (update.tag) { + case 1: + return ( + (workInProgress = update.payload), + "function" === typeof workInProgress + ? workInProgress.call(instance, prevState, nextProps) + : workInProgress + ); + case 3: + workInProgress.effectTag = (workInProgress.effectTag & -2049) | 64; + case 0: + workInProgress = update.payload; + nextProps = + "function" === typeof workInProgress + ? workInProgress.call(instance, prevState, nextProps) + : workInProgress; + if (null === nextProps || void 0 === nextProps) break; + return Object.assign({}, prevState, nextProps); + case 2: + hasForceUpdate = !0; + } + return prevState; +} +function processUpdateQueue( + workInProgress, + queue, + props, + instance, + renderExpirationTime +) { + hasForceUpdate = !1; + queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue); + for ( + var newBaseState = queue.baseState, + newFirstUpdate = null, + newExpirationTime = 0, + update = queue.firstUpdate, + resultState = newBaseState; + null !== update; + + ) { + var updateExpirationTime = update.expirationTime; + updateExpirationTime < renderExpirationTime + ? (null === newFirstUpdate && + ((newFirstUpdate = update), (newBaseState = resultState)), + newExpirationTime < updateExpirationTime && + (newExpirationTime = updateExpirationTime)) + : (updateExpirationTime < workInProgressRootMostRecentEventTime && + (workInProgressRootMostRecentEventTime = updateExpirationTime), + (resultState = getStateFromUpdate( + workInProgress, + queue, + update, + resultState, + props, + instance + )), + null !== update.callback && + ((workInProgress.effectTag |= 32), + (update.nextEffect = null), + null === queue.lastEffect + ? (queue.firstEffect = queue.lastEffect = update) + : ((queue.lastEffect.nextEffect = update), + (queue.lastEffect = update)))); + update = update.next; + } + updateExpirationTime = null; + for (update = queue.firstCapturedUpdate; null !== update; ) { + var _updateExpirationTime = update.expirationTime; + _updateExpirationTime < renderExpirationTime + ? (null === updateExpirationTime && + ((updateExpirationTime = update), + null === newFirstUpdate && (newBaseState = resultState)), + newExpirationTime < _updateExpirationTime && + (newExpirationTime = _updateExpirationTime)) + : ((resultState = getStateFromUpdate( + workInProgress, + queue, + update, + resultState, + props, + instance + )), + null !== update.callback && + ((workInProgress.effectTag |= 32), + (update.nextEffect = null), + null === queue.lastCapturedEffect + ? (queue.firstCapturedEffect = queue.lastCapturedEffect = update) + : ((queue.lastCapturedEffect.nextEffect = update), + (queue.lastCapturedEffect = update)))); + update = update.next; + } + null === newFirstUpdate && (queue.lastUpdate = null); + null === updateExpirationTime + ? (queue.lastCapturedUpdate = null) + : (workInProgress.effectTag |= 32); + null === newFirstUpdate && + null === updateExpirationTime && + (newBaseState = resultState); + queue.baseState = newBaseState; + queue.firstUpdate = newFirstUpdate; + queue.firstCapturedUpdate = updateExpirationTime; + workInProgress.expirationTime = newExpirationTime; + workInProgress.memoizedState = resultState; +} +function commitUpdateQueue(finishedWork, finishedQueue, instance) { + null !== finishedQueue.firstCapturedUpdate && + (null !== finishedQueue.lastUpdate && + ((finishedQueue.lastUpdate.next = finishedQueue.firstCapturedUpdate), + (finishedQueue.lastUpdate = finishedQueue.lastCapturedUpdate)), + (finishedQueue.firstCapturedUpdate = finishedQueue.lastCapturedUpdate = null)); + commitUpdateEffects(finishedQueue.firstEffect, instance); + finishedQueue.firstEffect = finishedQueue.lastEffect = null; + commitUpdateEffects(finishedQueue.firstCapturedEffect, instance); + finishedQueue.firstCapturedEffect = finishedQueue.lastCapturedEffect = null; +} +function commitUpdateEffects(effect, instance) { + for (; null !== effect; ) { + var _callback3 = effect.callback; + if (null !== _callback3) { + effect.callback = null; + var context = instance; + if ("function" !== typeof _callback3) + throw ReactError( + "Invalid argument passed as callback. Expected a function. Instead received: " + + _callback3 + ); + _callback3.call(context); + } + effect = effect.nextEffect; + } +} +var emptyRefsObject = new React.Component().refs; +function applyDerivedStateFromProps( + workInProgress, + ctor, + getDerivedStateFromProps, + nextProps +) { + ctor = workInProgress.memoizedState; + getDerivedStateFromProps = getDerivedStateFromProps(nextProps, ctor); + getDerivedStateFromProps = + null === getDerivedStateFromProps || void 0 === getDerivedStateFromProps + ? ctor + : Object.assign({}, ctor, getDerivedStateFromProps); + workInProgress.memoizedState = getDerivedStateFromProps; + nextProps = workInProgress.updateQueue; + null !== nextProps && + 0 === workInProgress.expirationTime && + (nextProps.baseState = getDerivedStateFromProps); +} +var classComponentUpdater = { + isMounted: function(component) { + return (component = component._reactInternalFiber) + ? 2 === isFiberMountedImpl(component) + : !1; + }, + enqueueSetState: function(inst, payload, callback) { + inst = inst._reactInternalFiber; + var currentTime = requestCurrentTime(); + currentTime = computeExpirationForFiber(currentTime, inst); + var update = createUpdate(currentTime); + update.payload = payload; + void 0 !== callback && null !== callback && (update.callback = callback); + flushPassiveEffects(); + enqueueUpdate(inst, update); + scheduleUpdateOnFiber(inst, currentTime); + }, + enqueueReplaceState: function(inst, payload, callback) { + inst = inst._reactInternalFiber; + var currentTime = requestCurrentTime(); + currentTime = computeExpirationForFiber(currentTime, inst); + var update = createUpdate(currentTime); + update.tag = 1; + update.payload = payload; + void 0 !== callback && null !== callback && (update.callback = callback); + flushPassiveEffects(); + enqueueUpdate(inst, update); + scheduleUpdateOnFiber(inst, currentTime); + }, + enqueueForceUpdate: function(inst, callback) { + inst = inst._reactInternalFiber; + var currentTime = requestCurrentTime(); + currentTime = computeExpirationForFiber(currentTime, inst); + var update = createUpdate(currentTime); + update.tag = 2; + void 0 !== callback && null !== callback && (update.callback = callback); + flushPassiveEffects(); + enqueueUpdate(inst, update); + scheduleUpdateOnFiber(inst, currentTime); + } +}; +function checkShouldComponentUpdate( + workInProgress, + ctor, + oldProps, + newProps, + oldState, + newState, + nextContext +) { + workInProgress = workInProgress.stateNode; + return "function" === typeof workInProgress.shouldComponentUpdate + ? workInProgress.shouldComponentUpdate(newProps, newState, nextContext) + : ctor.prototype && ctor.prototype.isPureReactComponent + ? !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState) + : !0; +} +function constructClassInstance(workInProgress, ctor, props) { + var isLegacyContextConsumer = !1, + unmaskedContext = emptyContextObject; + var context = ctor.contextType; + "object" === typeof context && null !== context + ? (context = readContext(context)) + : ((unmaskedContext = isContextProvider(ctor) + ? previousContext + : contextStackCursor.current), + (isLegacyContextConsumer = ctor.contextTypes), + (context = (isLegacyContextConsumer = + null !== isLegacyContextConsumer && void 0 !== isLegacyContextConsumer) + ? getMaskedContext(workInProgress, unmaskedContext) + : emptyContextObject)); + ctor = new ctor(props, context); + workInProgress.memoizedState = + null !== ctor.state && void 0 !== ctor.state ? ctor.state : null; + ctor.updater = classComponentUpdater; + workInProgress.stateNode = ctor; + ctor._reactInternalFiber = workInProgress; + isLegacyContextConsumer && + ((workInProgress = workInProgress.stateNode), + (workInProgress.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext), + (workInProgress.__reactInternalMemoizedMaskedChildContext = context)); + return ctor; +} +function callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + nextContext +) { + workInProgress = instance.state; + "function" === typeof instance.componentWillReceiveProps && + instance.componentWillReceiveProps(newProps, nextContext); + "function" === typeof instance.UNSAFE_componentWillReceiveProps && + instance.UNSAFE_componentWillReceiveProps(newProps, nextContext); + instance.state !== workInProgress && + classComponentUpdater.enqueueReplaceState(instance, instance.state, null); +} +function mountClassInstance( + workInProgress, + ctor, + newProps, + renderExpirationTime +) { + var instance = workInProgress.stateNode; + instance.props = newProps; + instance.state = workInProgress.memoizedState; + instance.refs = emptyRefsObject; + var contextType = ctor.contextType; + "object" === typeof contextType && null !== contextType + ? (instance.context = readContext(contextType)) + : ((contextType = isContextProvider(ctor) + ? previousContext + : contextStackCursor.current), + (instance.context = getMaskedContext(workInProgress, contextType))); + contextType = workInProgress.updateQueue; + null !== contextType && + (processUpdateQueue( + workInProgress, + contextType, + newProps, + instance, + renderExpirationTime + ), + (instance.state = workInProgress.memoizedState)); + contextType = ctor.getDerivedStateFromProps; + "function" === typeof contextType && + (applyDerivedStateFromProps(workInProgress, ctor, contextType, newProps), + (instance.state = workInProgress.memoizedState)); + "function" === typeof ctor.getDerivedStateFromProps || + "function" === typeof instance.getSnapshotBeforeUpdate || + ("function" !== typeof instance.UNSAFE_componentWillMount && + "function" !== typeof instance.componentWillMount) || + ((ctor = instance.state), + "function" === typeof instance.componentWillMount && + instance.componentWillMount(), + "function" === typeof instance.UNSAFE_componentWillMount && + instance.UNSAFE_componentWillMount(), + ctor !== instance.state && + classComponentUpdater.enqueueReplaceState(instance, instance.state, null), + (contextType = workInProgress.updateQueue), + null !== contextType && + (processUpdateQueue( + workInProgress, + contextType, + newProps, + instance, + renderExpirationTime + ), + (instance.state = workInProgress.memoizedState))); + "function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4); +} +var isArray = Array.isArray; +function coerceRef(returnFiber, current$$1, element) { + returnFiber = element.ref; + if ( + null !== returnFiber && + "function" !== typeof returnFiber && + "object" !== typeof returnFiber + ) { + if (element._owner) { + element = element._owner; + var inst = void 0; + if (element) { + if (1 !== element.tag) + throw ReactError( + "Function components cannot have refs. Did you mean to use React.forwardRef()?" + ); + inst = element.stateNode; + } + if (!inst) + throw ReactError( + "Missing owner for string ref " + + returnFiber + + ". This error is likely caused by a bug in React. Please file an issue." + ); + var stringRef = "" + returnFiber; + if ( + null !== current$$1 && + null !== current$$1.ref && + "function" === typeof current$$1.ref && + current$$1.ref._stringRef === stringRef + ) + return current$$1.ref; + current$$1 = function(value) { + var refs = inst.refs; + refs === emptyRefsObject && (refs = inst.refs = {}); + null === value ? delete refs[stringRef] : (refs[stringRef] = value); + }; + current$$1._stringRef = stringRef; + return current$$1; + } + if ("string" !== typeof returnFiber) + throw ReactError( + "Expected ref to be a function, a string, an object returned by React.createRef(), or null." + ); + if (!element._owner) + throw ReactError( + "Element ref was specified as a string (" + + returnFiber + + ") but no owner was set. This could happen for one of the following reasons:\n1. You may be adding a ref to a function component\n2. You may be adding a ref to a component that was not created inside a component's render method\n3. You have multiple copies of React loaded\nSee https://fb.me/react-refs-must-have-owner for more information." + ); + } + return returnFiber; +} +function throwOnInvalidObjectType(returnFiber, newChild) { + if ("textarea" !== returnFiber.type) + throw ReactError( + "Objects are not valid as a React child (found: " + + ("[object Object]" === Object.prototype.toString.call(newChild) + ? "object with keys {" + Object.keys(newChild).join(", ") + "}" + : newChild) + + ")." + ); +} +function ChildReconciler(shouldTrackSideEffects) { + function deleteChild(returnFiber, childToDelete) { + if (shouldTrackSideEffects) { + var last = returnFiber.lastEffect; + null !== last + ? ((last.nextEffect = childToDelete), + (returnFiber.lastEffect = childToDelete)) + : (returnFiber.firstEffect = returnFiber.lastEffect = childToDelete); + childToDelete.nextEffect = null; + childToDelete.effectTag = 8; + } + } + function deleteRemainingChildren(returnFiber, currentFirstChild) { + if (!shouldTrackSideEffects) return null; + for (; null !== currentFirstChild; ) + deleteChild(returnFiber, currentFirstChild), + (currentFirstChild = currentFirstChild.sibling); + return null; + } + function mapRemainingChildren(returnFiber, currentFirstChild) { + for (returnFiber = new Map(); null !== currentFirstChild; ) + null !== currentFirstChild.key + ? returnFiber.set(currentFirstChild.key, currentFirstChild) + : returnFiber.set(currentFirstChild.index, currentFirstChild), + (currentFirstChild = currentFirstChild.sibling); + return returnFiber; + } + function useFiber(fiber, pendingProps, expirationTime) { + fiber = createWorkInProgress(fiber, pendingProps, expirationTime); + fiber.index = 0; + fiber.sibling = null; + return fiber; + } + function placeChild(newFiber, lastPlacedIndex, newIndex) { + newFiber.index = newIndex; + if (!shouldTrackSideEffects) return lastPlacedIndex; + newIndex = newFiber.alternate; + if (null !== newIndex) + return ( + (newIndex = newIndex.index), + newIndex < lastPlacedIndex + ? ((newFiber.effectTag = 2), lastPlacedIndex) + : newIndex + ); + newFiber.effectTag = 2; + return lastPlacedIndex; + } + function placeSingleChild(newFiber) { + shouldTrackSideEffects && + null === newFiber.alternate && + (newFiber.effectTag = 2); + return newFiber; + } + function updateTextNode( + returnFiber, + current$$1, + textContent, + expirationTime + ) { + if (null === current$$1 || 6 !== current$$1.tag) + return ( + (current$$1 = createFiberFromText( + textContent, + returnFiber.mode, + expirationTime + )), + (current$$1.return = returnFiber), + current$$1 + ); + current$$1 = useFiber(current$$1, textContent, expirationTime); + current$$1.return = returnFiber; + return current$$1; + } + function updateElement(returnFiber, current$$1, element, expirationTime) { + if (null !== current$$1 && current$$1.elementType === element.type) + return ( + (expirationTime = useFiber(current$$1, element.props, expirationTime)), + (expirationTime.ref = coerceRef(returnFiber, current$$1, element)), + (expirationTime.return = returnFiber), + expirationTime + ); + expirationTime = createFiberFromTypeAndProps( + element.type, + element.key, + element.props, + null, + returnFiber.mode, + expirationTime + ); + expirationTime.ref = coerceRef(returnFiber, current$$1, element); + expirationTime.return = returnFiber; + return expirationTime; + } + function updatePortal(returnFiber, current$$1, portal, expirationTime) { + if ( + null === current$$1 || + 4 !== current$$1.tag || + current$$1.stateNode.containerInfo !== portal.containerInfo || + current$$1.stateNode.implementation !== portal.implementation + ) + return ( + (current$$1 = createFiberFromPortal( + portal, + returnFiber.mode, + expirationTime + )), + (current$$1.return = returnFiber), + current$$1 + ); + current$$1 = useFiber(current$$1, portal.children || [], expirationTime); + current$$1.return = returnFiber; + return current$$1; + } + function updateFragment( + returnFiber, + current$$1, + fragment, + expirationTime, + key + ) { + if (null === current$$1 || 7 !== current$$1.tag) + return ( + (current$$1 = createFiberFromFragment( + fragment, + returnFiber.mode, + expirationTime, + key + )), + (current$$1.return = returnFiber), + current$$1 + ); + current$$1 = useFiber(current$$1, fragment, expirationTime); + current$$1.return = returnFiber; + return current$$1; + } + function createChild(returnFiber, newChild, expirationTime) { + if ("string" === typeof newChild || "number" === typeof newChild) + return ( + (newChild = createFiberFromText( + "" + newChild, + returnFiber.mode, + expirationTime + )), + (newChild.return = returnFiber), + newChild + ); + if ("object" === typeof newChild && null !== newChild) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return ( + (expirationTime = createFiberFromTypeAndProps( + newChild.type, + newChild.key, + newChild.props, + null, + returnFiber.mode, + expirationTime + )), + (expirationTime.ref = coerceRef(returnFiber, null, newChild)), + (expirationTime.return = returnFiber), + expirationTime + ); + case REACT_PORTAL_TYPE: + return ( + (newChild = createFiberFromPortal( + newChild, + returnFiber.mode, + expirationTime + )), + (newChild.return = returnFiber), + newChild + ); + } + if (isArray(newChild) || getIteratorFn(newChild)) + return ( + (newChild = createFiberFromFragment( + newChild, + returnFiber.mode, + expirationTime, + null + )), + (newChild.return = returnFiber), + newChild + ); + throwOnInvalidObjectType(returnFiber, newChild); + } + return null; + } + function updateSlot(returnFiber, oldFiber, newChild, expirationTime) { + var key = null !== oldFiber ? oldFiber.key : null; + if ("string" === typeof newChild || "number" === typeof newChild) + return null !== key + ? null + : updateTextNode(returnFiber, oldFiber, "" + newChild, expirationTime); + if ("object" === typeof newChild && null !== newChild) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return newChild.key === key + ? newChild.type === REACT_FRAGMENT_TYPE + ? updateFragment( + returnFiber, + oldFiber, + newChild.props.children, + expirationTime, + key + ) + : updateElement(returnFiber, oldFiber, newChild, expirationTime) + : null; + case REACT_PORTAL_TYPE: + return newChild.key === key + ? updatePortal(returnFiber, oldFiber, newChild, expirationTime) + : null; + } + if (isArray(newChild) || getIteratorFn(newChild)) + return null !== key + ? null + : updateFragment( + returnFiber, + oldFiber, + newChild, + expirationTime, + null + ); + throwOnInvalidObjectType(returnFiber, newChild); + } + return null; + } + function updateFromMap( + existingChildren, + returnFiber, + newIdx, + newChild, + expirationTime + ) { + if ("string" === typeof newChild || "number" === typeof newChild) + return ( + (existingChildren = existingChildren.get(newIdx) || null), + updateTextNode( + returnFiber, + existingChildren, + "" + newChild, + expirationTime + ) + ); + if ("object" === typeof newChild && null !== newChild) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return ( + (existingChildren = + existingChildren.get( + null === newChild.key ? newIdx : newChild.key + ) || null), + newChild.type === REACT_FRAGMENT_TYPE + ? updateFragment( + returnFiber, + existingChildren, + newChild.props.children, + expirationTime, + newChild.key + ) + : updateElement( + returnFiber, + existingChildren, + newChild, + expirationTime + ) + ); + case REACT_PORTAL_TYPE: + return ( + (existingChildren = + existingChildren.get( + null === newChild.key ? newIdx : newChild.key + ) || null), + updatePortal( + returnFiber, + existingChildren, + newChild, + expirationTime + ) + ); + } + if (isArray(newChild) || getIteratorFn(newChild)) + return ( + (existingChildren = existingChildren.get(newIdx) || null), + updateFragment( + returnFiber, + existingChildren, + newChild, + expirationTime, + null + ) + ); + throwOnInvalidObjectType(returnFiber, newChild); + } + return null; + } + function reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChildren, + expirationTime + ) { + for ( + var resultingFirstChild = null, + previousNewFiber = null, + oldFiber = currentFirstChild, + newIdx = (currentFirstChild = 0), + nextOldFiber = null; + null !== oldFiber && newIdx < newChildren.length; + newIdx++ + ) { + oldFiber.index > newIdx + ? ((nextOldFiber = oldFiber), (oldFiber = null)) + : (nextOldFiber = oldFiber.sibling); + var newFiber = updateSlot( + returnFiber, + oldFiber, + newChildren[newIdx], + expirationTime + ); + if (null === newFiber) { + null === oldFiber && (oldFiber = nextOldFiber); + break; + } + shouldTrackSideEffects && + oldFiber && + null === newFiber.alternate && + deleteChild(returnFiber, oldFiber); + currentFirstChild = placeChild(newFiber, currentFirstChild, newIdx); + null === previousNewFiber + ? (resultingFirstChild = newFiber) + : (previousNewFiber.sibling = newFiber); + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } + if (newIdx === newChildren.length) + return ( + deleteRemainingChildren(returnFiber, oldFiber), resultingFirstChild + ); + if (null === oldFiber) { + for (; newIdx < newChildren.length; newIdx++) + (oldFiber = createChild( + returnFiber, + newChildren[newIdx], + expirationTime + )), + null !== oldFiber && + ((currentFirstChild = placeChild( + oldFiber, + currentFirstChild, + newIdx + )), + null === previousNewFiber + ? (resultingFirstChild = oldFiber) + : (previousNewFiber.sibling = oldFiber), + (previousNewFiber = oldFiber)); + return resultingFirstChild; + } + for ( + oldFiber = mapRemainingChildren(returnFiber, oldFiber); + newIdx < newChildren.length; + newIdx++ + ) + (nextOldFiber = updateFromMap( + oldFiber, + returnFiber, + newIdx, + newChildren[newIdx], + expirationTime + )), + null !== nextOldFiber && + (shouldTrackSideEffects && + null !== nextOldFiber.alternate && + oldFiber.delete( + null === nextOldFiber.key ? newIdx : nextOldFiber.key + ), + (currentFirstChild = placeChild( + nextOldFiber, + currentFirstChild, + newIdx + )), + null === previousNewFiber + ? (resultingFirstChild = nextOldFiber) + : (previousNewFiber.sibling = nextOldFiber), + (previousNewFiber = nextOldFiber)); + shouldTrackSideEffects && + oldFiber.forEach(function(child) { + return deleteChild(returnFiber, child); + }); + return resultingFirstChild; + } + function reconcileChildrenIterator( + returnFiber, + currentFirstChild, + newChildrenIterable, + expirationTime + ) { + var iteratorFn = getIteratorFn(newChildrenIterable); + if ("function" !== typeof iteratorFn) + throw ReactError( + "An object is not an iterable. This error is likely caused by a bug in React. Please file an issue." + ); + newChildrenIterable = iteratorFn.call(newChildrenIterable); + if (null == newChildrenIterable) + throw ReactError("An iterable object provided no iterator."); + for ( + var previousNewFiber = (iteratorFn = null), + oldFiber = currentFirstChild, + newIdx = (currentFirstChild = 0), + nextOldFiber = null, + step = newChildrenIterable.next(); + null !== oldFiber && !step.done; + newIdx++, step = newChildrenIterable.next() + ) { + oldFiber.index > newIdx + ? ((nextOldFiber = oldFiber), (oldFiber = null)) + : (nextOldFiber = oldFiber.sibling); + var newFiber = updateSlot( + returnFiber, + oldFiber, + step.value, + expirationTime + ); + if (null === newFiber) { + null === oldFiber && (oldFiber = nextOldFiber); + break; + } + shouldTrackSideEffects && + oldFiber && + null === newFiber.alternate && + deleteChild(returnFiber, oldFiber); + currentFirstChild = placeChild(newFiber, currentFirstChild, newIdx); + null === previousNewFiber + ? (iteratorFn = newFiber) + : (previousNewFiber.sibling = newFiber); + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } + if (step.done) + return deleteRemainingChildren(returnFiber, oldFiber), iteratorFn; + if (null === oldFiber) { + for (; !step.done; newIdx++, step = newChildrenIterable.next()) + (step = createChild(returnFiber, step.value, expirationTime)), + null !== step && + ((currentFirstChild = placeChild(step, currentFirstChild, newIdx)), + null === previousNewFiber + ? (iteratorFn = step) + : (previousNewFiber.sibling = step), + (previousNewFiber = step)); + return iteratorFn; + } + for ( + oldFiber = mapRemainingChildren(returnFiber, oldFiber); + !step.done; + newIdx++, step = newChildrenIterable.next() + ) + (step = updateFromMap( + oldFiber, + returnFiber, + newIdx, + step.value, + expirationTime + )), + null !== step && + (shouldTrackSideEffects && + null !== step.alternate && + oldFiber.delete(null === step.key ? newIdx : step.key), + (currentFirstChild = placeChild(step, currentFirstChild, newIdx)), + null === previousNewFiber + ? (iteratorFn = step) + : (previousNewFiber.sibling = step), + (previousNewFiber = step)); + shouldTrackSideEffects && + oldFiber.forEach(function(child) { + return deleteChild(returnFiber, child); + }); + return iteratorFn; + } + return function(returnFiber, currentFirstChild, newChild, expirationTime) { + var isUnkeyedTopLevelFragment = + "object" === typeof newChild && + null !== newChild && + newChild.type === REACT_FRAGMENT_TYPE && + null === newChild.key; + isUnkeyedTopLevelFragment && (newChild = newChild.props.children); + var isObject = "object" === typeof newChild && null !== newChild; + if (isObject) + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + a: { + isObject = newChild.key; + for ( + isUnkeyedTopLevelFragment = currentFirstChild; + null !== isUnkeyedTopLevelFragment; + + ) { + if (isUnkeyedTopLevelFragment.key === isObject) { + if ( + 7 === isUnkeyedTopLevelFragment.tag + ? newChild.type === REACT_FRAGMENT_TYPE + : isUnkeyedTopLevelFragment.elementType === newChild.type + ) { + deleteRemainingChildren( + returnFiber, + isUnkeyedTopLevelFragment.sibling + ); + currentFirstChild = useFiber( + isUnkeyedTopLevelFragment, + newChild.type === REACT_FRAGMENT_TYPE + ? newChild.props.children + : newChild.props, + expirationTime + ); + currentFirstChild.ref = coerceRef( + returnFiber, + isUnkeyedTopLevelFragment, + newChild + ); + currentFirstChild.return = returnFiber; + returnFiber = currentFirstChild; + break a; + } + deleteRemainingChildren(returnFiber, isUnkeyedTopLevelFragment); + break; + } else deleteChild(returnFiber, isUnkeyedTopLevelFragment); + isUnkeyedTopLevelFragment = isUnkeyedTopLevelFragment.sibling; + } + newChild.type === REACT_FRAGMENT_TYPE + ? ((currentFirstChild = createFiberFromFragment( + newChild.props.children, + returnFiber.mode, + expirationTime, + newChild.key + )), + (currentFirstChild.return = returnFiber), + (returnFiber = currentFirstChild)) + : ((expirationTime = createFiberFromTypeAndProps( + newChild.type, + newChild.key, + newChild.props, + null, + returnFiber.mode, + expirationTime + )), + (expirationTime.ref = coerceRef( + returnFiber, + currentFirstChild, + newChild + )), + (expirationTime.return = returnFiber), + (returnFiber = expirationTime)); + } + return placeSingleChild(returnFiber); + case REACT_PORTAL_TYPE: + a: { + for ( + isUnkeyedTopLevelFragment = newChild.key; + null !== currentFirstChild; + + ) { + if (currentFirstChild.key === isUnkeyedTopLevelFragment) { + if ( + 4 === currentFirstChild.tag && + currentFirstChild.stateNode.containerInfo === + newChild.containerInfo && + currentFirstChild.stateNode.implementation === + newChild.implementation + ) { + deleteRemainingChildren( + returnFiber, + currentFirstChild.sibling + ); + currentFirstChild = useFiber( + currentFirstChild, + newChild.children || [], + expirationTime + ); + currentFirstChild.return = returnFiber; + returnFiber = currentFirstChild; + break a; + } + deleteRemainingChildren(returnFiber, currentFirstChild); + break; + } else deleteChild(returnFiber, currentFirstChild); + currentFirstChild = currentFirstChild.sibling; + } + currentFirstChild = createFiberFromPortal( + newChild, + returnFiber.mode, + expirationTime + ); + currentFirstChild.return = returnFiber; + returnFiber = currentFirstChild; + } + return placeSingleChild(returnFiber); + } + if ("string" === typeof newChild || "number" === typeof newChild) + return ( + (newChild = "" + newChild), + null !== currentFirstChild && 6 === currentFirstChild.tag + ? (deleteRemainingChildren(returnFiber, currentFirstChild.sibling), + (currentFirstChild = useFiber( + currentFirstChild, + newChild, + expirationTime + )), + (currentFirstChild.return = returnFiber), + (returnFiber = currentFirstChild)) + : (deleteRemainingChildren(returnFiber, currentFirstChild), + (currentFirstChild = createFiberFromText( + newChild, + returnFiber.mode, + expirationTime + )), + (currentFirstChild.return = returnFiber), + (returnFiber = currentFirstChild)), + placeSingleChild(returnFiber) + ); + if (isArray(newChild)) + return reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ); + if (getIteratorFn(newChild)) + return reconcileChildrenIterator( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ); + isObject && throwOnInvalidObjectType(returnFiber, newChild); + if ("undefined" === typeof newChild && !isUnkeyedTopLevelFragment) + switch (returnFiber.tag) { + case 1: + case 0: + throw ((returnFiber = returnFiber.type), + ReactError( + (returnFiber.displayName || returnFiber.name || "Component") + + "(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null." + )); + } + return deleteRemainingChildren(returnFiber, currentFirstChild); + }; +} +var reconcileChildFibers = ChildReconciler(!0), + mountChildFibers = ChildReconciler(!1), + NO_CONTEXT = {}, + contextStackCursor$1 = { current: NO_CONTEXT }, + contextFiberStackCursor = { current: NO_CONTEXT }, + rootInstanceStackCursor = { current: NO_CONTEXT }; +function requiredContext(c) { + if (c === NO_CONTEXT) + throw ReactError( + "Expected host context to exist. This error is likely caused by a bug in React. Please file an issue." + ); + return c; +} +function pushHostContainer(fiber, nextRootInstance) { + push(rootInstanceStackCursor, nextRootInstance, fiber); + push(contextFiberStackCursor, fiber, fiber); + push(contextStackCursor$1, NO_CONTEXT, fiber); + pop(contextStackCursor$1, fiber); + push(contextStackCursor$1, { isInAParentText: !1 }, fiber); +} +function popHostContainer(fiber) { + pop(contextStackCursor$1, fiber); + pop(contextFiberStackCursor, fiber); + pop(rootInstanceStackCursor, fiber); +} +function pushHostContext(fiber) { + requiredContext(rootInstanceStackCursor.current); + var context = requiredContext(contextStackCursor$1.current); + var nextContext = fiber.type; + nextContext = + "AndroidTextInput" === nextContext || + "RCTMultilineTextInputView" === nextContext || + "RCTSinglelineTextInputView" === nextContext || + "RCTText" === nextContext || + "RCTVirtualText" === nextContext; + nextContext = + context.isInAParentText !== nextContext + ? { isInAParentText: nextContext } + : context; + context !== nextContext && + (push(contextFiberStackCursor, fiber, fiber), + push(contextStackCursor$1, nextContext, fiber)); +} +function popHostContext(fiber) { + contextFiberStackCursor.current === fiber && + (pop(contextStackCursor$1, fiber), pop(contextFiberStackCursor, fiber)); +} +var NoEffect$1 = 0, + UnmountSnapshot = 2, + UnmountMutation = 4, + MountMutation = 8, + UnmountLayout = 16, + MountLayout = 32, + MountPassive = 64, + UnmountPassive = 128, + ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher, + renderExpirationTime$1 = 0, + currentlyRenderingFiber$1 = null, + currentHook = null, + nextCurrentHook = null, + firstWorkInProgressHook = null, + workInProgressHook = null, + nextWorkInProgressHook = null, + remainingExpirationTime = 0, + componentUpdateQueue = null, + sideEffectTag = 0, + didScheduleRenderPhaseUpdate = !1, + renderPhaseUpdates = null, + numberOfReRenders = 0; +function throwInvalidHookError() { + throw ReactError( + "Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:\n1. You might have mismatching versions of React and the renderer (such as React DOM)\n2. You might be breaking the Rules of Hooks\n3. You might have more than one copy of React in the same app\nSee https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem." + ); +} +function areHookInputsEqual(nextDeps, prevDeps) { + if (null === prevDeps) return !1; + for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++) + if (!is(nextDeps[i], prevDeps[i])) return !1; + return !0; +} +function renderWithHooks( + current, + workInProgress, + Component, + props, + refOrContext, + nextRenderExpirationTime +) { + renderExpirationTime$1 = nextRenderExpirationTime; + currentlyRenderingFiber$1 = workInProgress; + nextCurrentHook = null !== current ? current.memoizedState : null; + ReactCurrentDispatcher$1.current = + null === nextCurrentHook ? HooksDispatcherOnMount : HooksDispatcherOnUpdate; + workInProgress = Component(props, refOrContext); + if (didScheduleRenderPhaseUpdate) { + do + (didScheduleRenderPhaseUpdate = !1), + (numberOfReRenders += 1), + (nextCurrentHook = null !== current ? current.memoizedState : null), + (nextWorkInProgressHook = firstWorkInProgressHook), + (componentUpdateQueue = workInProgressHook = currentHook = null), + (ReactCurrentDispatcher$1.current = HooksDispatcherOnUpdate), + (workInProgress = Component(props, refOrContext)); + while (didScheduleRenderPhaseUpdate); + renderPhaseUpdates = null; + numberOfReRenders = 0; + } + ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; + current = currentlyRenderingFiber$1; + current.memoizedState = firstWorkInProgressHook; + current.expirationTime = remainingExpirationTime; + current.updateQueue = componentUpdateQueue; + current.effectTag |= sideEffectTag; + current = null !== currentHook && null !== currentHook.next; + renderExpirationTime$1 = 0; + nextWorkInProgressHook = workInProgressHook = firstWorkInProgressHook = nextCurrentHook = currentHook = currentlyRenderingFiber$1 = null; + remainingExpirationTime = 0; + componentUpdateQueue = null; + sideEffectTag = 0; + if (current) + throw ReactError( + "Rendered fewer hooks than expected. This may be caused by an accidental early return statement." + ); + return workInProgress; +} +function resetHooks() { + ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; + renderExpirationTime$1 = 0; + nextWorkInProgressHook = workInProgressHook = firstWorkInProgressHook = nextCurrentHook = currentHook = currentlyRenderingFiber$1 = null; + remainingExpirationTime = 0; + componentUpdateQueue = null; + sideEffectTag = 0; + didScheduleRenderPhaseUpdate = !1; + renderPhaseUpdates = null; + numberOfReRenders = 0; +} +function mountWorkInProgressHook() { + var hook = { + memoizedState: null, + baseState: null, + queue: null, + baseUpdate: null, + next: null + }; + null === workInProgressHook + ? (firstWorkInProgressHook = workInProgressHook = hook) + : (workInProgressHook = workInProgressHook.next = hook); + return workInProgressHook; +} +function updateWorkInProgressHook() { + if (null !== nextWorkInProgressHook) + (workInProgressHook = nextWorkInProgressHook), + (nextWorkInProgressHook = workInProgressHook.next), + (currentHook = nextCurrentHook), + (nextCurrentHook = null !== currentHook ? currentHook.next : null); + else { + if (null === nextCurrentHook) + throw ReactError("Rendered more hooks than during the previous render."); + currentHook = nextCurrentHook; + var newHook = { + memoizedState: currentHook.memoizedState, + baseState: currentHook.baseState, + queue: currentHook.queue, + baseUpdate: currentHook.baseUpdate, + next: null + }; + workInProgressHook = + null === workInProgressHook + ? (firstWorkInProgressHook = newHook) + : (workInProgressHook.next = newHook); + nextCurrentHook = currentHook.next; + } + return workInProgressHook; +} +function basicStateReducer(state, action) { + return "function" === typeof action ? action(state) : action; +} +function updateReducer(reducer) { + var hook = updateWorkInProgressHook(), + queue = hook.queue; + if (null === queue) + throw ReactError( + "Should have a queue. This is likely a bug in React. Please file an issue." + ); + queue.lastRenderedReducer = reducer; + if (0 < numberOfReRenders) { + var _dispatch = queue.dispatch; + if (null !== renderPhaseUpdates) { + var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue); + if (void 0 !== firstRenderPhaseUpdate) { + renderPhaseUpdates.delete(queue); + var newState = hook.memoizedState; + do + (newState = reducer(newState, firstRenderPhaseUpdate.action)), + (firstRenderPhaseUpdate = firstRenderPhaseUpdate.next); + while (null !== firstRenderPhaseUpdate); + is(newState, hook.memoizedState) || (didReceiveUpdate = !0); + hook.memoizedState = newState; + hook.baseUpdate === queue.last && (hook.baseState = newState); + queue.lastRenderedState = newState; + return [newState, _dispatch]; + } + } + return [hook.memoizedState, _dispatch]; + } + _dispatch = queue.last; + var baseUpdate = hook.baseUpdate; + newState = hook.baseState; + null !== baseUpdate + ? (null !== _dispatch && (_dispatch.next = null), + (_dispatch = baseUpdate.next)) + : (_dispatch = null !== _dispatch ? _dispatch.next : null); + if (null !== _dispatch) { + var newBaseUpdate = (firstRenderPhaseUpdate = null), + _update = _dispatch, + didSkip = !1; + do { + var updateExpirationTime = _update.expirationTime; + updateExpirationTime < renderExpirationTime$1 + ? (didSkip || + ((didSkip = !0), + (newBaseUpdate = baseUpdate), + (firstRenderPhaseUpdate = newState)), + updateExpirationTime > remainingExpirationTime && + (remainingExpirationTime = updateExpirationTime)) + : (updateExpirationTime < workInProgressRootMostRecentEventTime && + (workInProgressRootMostRecentEventTime = updateExpirationTime), + (newState = + _update.eagerReducer === reducer + ? _update.eagerState + : reducer(newState, _update.action))); + baseUpdate = _update; + _update = _update.next; + } while (null !== _update && _update !== _dispatch); + didSkip || + ((newBaseUpdate = baseUpdate), (firstRenderPhaseUpdate = newState)); + is(newState, hook.memoizedState) || (didReceiveUpdate = !0); + hook.memoizedState = newState; + hook.baseUpdate = newBaseUpdate; + hook.baseState = firstRenderPhaseUpdate; + queue.lastRenderedState = newState; + } + return [hook.memoizedState, queue.dispatch]; +} +function pushEffect(tag, create, destroy, deps) { + tag = { tag: tag, create: create, destroy: destroy, deps: deps, next: null }; + null === componentUpdateQueue + ? ((componentUpdateQueue = { lastEffect: null }), + (componentUpdateQueue.lastEffect = tag.next = tag)) + : ((create = componentUpdateQueue.lastEffect), + null === create + ? (componentUpdateQueue.lastEffect = tag.next = tag) + : ((destroy = create.next), + (create.next = tag), + (tag.next = destroy), + (componentUpdateQueue.lastEffect = tag))); + return tag; +} +function mountEffectImpl(fiberEffectTag, hookEffectTag, create, deps) { + var hook = mountWorkInProgressHook(); + sideEffectTag |= fiberEffectTag; + hook.memoizedState = pushEffect( + hookEffectTag, + create, + void 0, + void 0 === deps ? null : deps + ); +} +function updateEffectImpl(fiberEffectTag, hookEffectTag, create, deps) { + var hook = updateWorkInProgressHook(); + deps = void 0 === deps ? null : deps; + var destroy = void 0; + if (null !== currentHook) { + var prevEffect = currentHook.memoizedState; + destroy = prevEffect.destroy; + if (null !== deps && areHookInputsEqual(deps, prevEffect.deps)) { + pushEffect(NoEffect$1, create, destroy, deps); + return; + } + } + sideEffectTag |= fiberEffectTag; + hook.memoizedState = pushEffect(hookEffectTag, create, destroy, deps); +} +function imperativeHandleEffect(create, ref) { + if ("function" === typeof ref) + return ( + (create = create()), + ref(create), + function() { + ref(null); + } + ); + if (null !== ref && void 0 !== ref) + return ( + (create = create()), + (ref.current = create), + function() { + ref.current = null; + } + ); +} +function mountDebugValue() {} +function dispatchAction(fiber, queue, action) { + if (!(25 > numberOfReRenders)) + throw ReactError( + "Too many re-renders. React limits the number of renders to prevent an infinite loop." + ); + var alternate = fiber.alternate; + if ( + fiber === currentlyRenderingFiber$1 || + (null !== alternate && alternate === currentlyRenderingFiber$1) + ) + if ( + ((didScheduleRenderPhaseUpdate = !0), + (fiber = { + expirationTime: renderExpirationTime$1, + action: action, + eagerReducer: null, + eagerState: null, + next: null + }), + null === renderPhaseUpdates && (renderPhaseUpdates = new Map()), + (action = renderPhaseUpdates.get(queue)), + void 0 === action) + ) + renderPhaseUpdates.set(queue, fiber); + else { + for (queue = action; null !== queue.next; ) queue = queue.next; + queue.next = fiber; + } + else { + flushPassiveEffects(); + var currentTime = requestCurrentTime(); + currentTime = computeExpirationForFiber(currentTime, fiber); + var _update2 = { + expirationTime: currentTime, + action: action, + eagerReducer: null, + eagerState: null, + next: null + }, + _last = queue.last; + if (null === _last) _update2.next = _update2; + else { + var first = _last.next; + null !== first && (_update2.next = first); + _last.next = _update2; + } + queue.last = _update2; + if ( + 0 === fiber.expirationTime && + (null === alternate || 0 === alternate.expirationTime) && + ((alternate = queue.lastRenderedReducer), null !== alternate) + ) + try { + var currentState = queue.lastRenderedState, + _eagerState = alternate(currentState, action); + _update2.eagerReducer = alternate; + _update2.eagerState = _eagerState; + if (is(_eagerState, currentState)) return; + } catch (error) { + } finally { + } + scheduleUpdateOnFiber(fiber, currentTime); + } +} +var ContextOnlyDispatcher = { + readContext: readContext, + useCallback: throwInvalidHookError, + useContext: throwInvalidHookError, + useEffect: throwInvalidHookError, + useImperativeHandle: throwInvalidHookError, + useLayoutEffect: throwInvalidHookError, + useMemo: throwInvalidHookError, + useReducer: throwInvalidHookError, + useRef: throwInvalidHookError, + useState: throwInvalidHookError, + useDebugValue: throwInvalidHookError + }, + HooksDispatcherOnMount = { + readContext: readContext, + useCallback: function(callback, deps) { + mountWorkInProgressHook().memoizedState = [ + callback, + void 0 === deps ? null : deps + ]; + return callback; + }, + useContext: readContext, + useEffect: function(create, deps) { + return mountEffectImpl(516, UnmountPassive | MountPassive, create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + deps = null !== deps && void 0 !== deps ? deps.concat([ref]) : null; + return mountEffectImpl( + 4, + UnmountMutation | MountLayout, + imperativeHandleEffect.bind(null, create, ref), + deps + ); + }, + useLayoutEffect: function(create, deps) { + return mountEffectImpl(4, UnmountMutation | MountLayout, create, deps); + }, + useMemo: function(nextCreate, deps) { + var hook = mountWorkInProgressHook(); + deps = void 0 === deps ? null : deps; + nextCreate = nextCreate(); + hook.memoizedState = [nextCreate, deps]; + return nextCreate; + }, + useReducer: function(reducer, initialArg, init) { + var hook = mountWorkInProgressHook(); + initialArg = void 0 !== init ? init(initialArg) : initialArg; + hook.memoizedState = hook.baseState = initialArg; + reducer = hook.queue = { + last: null, + dispatch: null, + lastRenderedReducer: reducer, + lastRenderedState: initialArg + }; + reducer = reducer.dispatch = dispatchAction.bind( + null, + currentlyRenderingFiber$1, + reducer + ); + return [hook.memoizedState, reducer]; + }, + useRef: function(initialValue) { + var hook = mountWorkInProgressHook(); + initialValue = { current: initialValue }; + return (hook.memoizedState = initialValue); + }, + useState: function(initialState) { + var hook = mountWorkInProgressHook(); + "function" === typeof initialState && (initialState = initialState()); + hook.memoizedState = hook.baseState = initialState; + initialState = hook.queue = { + last: null, + dispatch: null, + lastRenderedReducer: basicStateReducer, + lastRenderedState: initialState + }; + initialState = initialState.dispatch = dispatchAction.bind( + null, + currentlyRenderingFiber$1, + initialState + ); + return [hook.memoizedState, initialState]; + }, + useDebugValue: mountDebugValue + }, + HooksDispatcherOnUpdate = { + readContext: readContext, + useCallback: function(callback, deps) { + var hook = updateWorkInProgressHook(); + deps = void 0 === deps ? null : deps; + var prevState = hook.memoizedState; + if ( + null !== prevState && + null !== deps && + areHookInputsEqual(deps, prevState[1]) + ) + return prevState[0]; + hook.memoizedState = [callback, deps]; + return callback; + }, + useContext: readContext, + useEffect: function(create, deps) { + return updateEffectImpl(516, UnmountPassive | MountPassive, create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + deps = null !== deps && void 0 !== deps ? deps.concat([ref]) : null; + return updateEffectImpl( + 4, + UnmountMutation | MountLayout, + imperativeHandleEffect.bind(null, create, ref), + deps + ); + }, + useLayoutEffect: function(create, deps) { + return updateEffectImpl(4, UnmountMutation | MountLayout, create, deps); + }, + useMemo: function(nextCreate, deps) { + var hook = updateWorkInProgressHook(); + deps = void 0 === deps ? null : deps; + var prevState = hook.memoizedState; + if ( + null !== prevState && + null !== deps && + areHookInputsEqual(deps, prevState[1]) + ) + return prevState[0]; + nextCreate = nextCreate(); + hook.memoizedState = [nextCreate, deps]; + return nextCreate; + }, + useReducer: updateReducer, + useRef: function() { + return updateWorkInProgressHook().memoizedState; + }, + useState: function(initialState) { + return updateReducer(basicStateReducer, initialState); + }, + useDebugValue: mountDebugValue + }, + now$1 = Scheduler.unstable_now, + commitTime = 0, + profilerStartTime = -1; +function stopProfilerTimerIfRunningAndRecordDelta(fiber, overrideBaseTime) { + if (0 <= profilerStartTime) { + var elapsedTime = now$1() - profilerStartTime; + fiber.actualDuration += elapsedTime; + overrideBaseTime && (fiber.selfBaseDuration = elapsedTime); + profilerStartTime = -1; + } +} +var hydrationParentFiber = null, + nextHydratableInstance = null, + isHydrating = !1; +function tryHydrate(fiber, nextInstance) { + switch (fiber.tag) { + case 5: + return ( + (nextInstance = shim$1(nextInstance, fiber.type, fiber.pendingProps)), + null !== nextInstance ? ((fiber.stateNode = nextInstance), !0) : !1 + ); + case 6: + return ( + (nextInstance = shim$1(nextInstance, fiber.pendingProps)), + null !== nextInstance ? ((fiber.stateNode = nextInstance), !0) : !1 + ); + case 13: + return !1; + default: + return !1; + } +} +function tryToClaimNextHydratableInstance(fiber$jscomp$0) { + if (isHydrating) { + var nextInstance = nextHydratableInstance; + if (nextInstance) { + var firstAttemptedInstance = nextInstance; + if (!tryHydrate(fiber$jscomp$0, nextInstance)) { + nextInstance = shim$1(firstAttemptedInstance); + if (!nextInstance || !tryHydrate(fiber$jscomp$0, nextInstance)) { + fiber$jscomp$0.effectTag |= 2; + isHydrating = !1; + hydrationParentFiber = fiber$jscomp$0; + return; + } + var returnFiber = hydrationParentFiber, + fiber = createFiber(5, null, null, 0); + fiber.elementType = "DELETED"; + fiber.type = "DELETED"; + fiber.stateNode = firstAttemptedInstance; + fiber.return = returnFiber; + fiber.effectTag = 8; + null !== returnFiber.lastEffect + ? ((returnFiber.lastEffect.nextEffect = fiber), + (returnFiber.lastEffect = fiber)) + : (returnFiber.firstEffect = returnFiber.lastEffect = fiber); + } + hydrationParentFiber = fiber$jscomp$0; + nextHydratableInstance = shim$1(nextInstance); + } else + (fiber$jscomp$0.effectTag |= 2), + (isHydrating = !1), + (hydrationParentFiber = fiber$jscomp$0); + } +} +var ReactCurrentOwner$3 = ReactSharedInternals.ReactCurrentOwner, + didReceiveUpdate = !1; +function reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime +) { + workInProgress.child = + null === current$$1 + ? mountChildFibers( + workInProgress, + null, + nextChildren, + renderExpirationTime + ) + : reconcileChildFibers( + workInProgress, + current$$1.child, + nextChildren, + renderExpirationTime + ); +} +function updateForwardRef( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + Component = Component.render; + var ref = workInProgress.ref; + prepareToReadContext(workInProgress, renderExpirationTime); + nextProps = renderWithHooks( + current$$1, + workInProgress, + Component, + nextProps, + ref, + renderExpirationTime + ); + if (null !== current$$1 && !didReceiveUpdate) + return ( + (workInProgress.updateQueue = current$$1.updateQueue), + (workInProgress.effectTag &= -517), + current$$1.expirationTime <= renderExpirationTime && + (current$$1.expirationTime = 0), + bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ) + ); + workInProgress.effectTag |= 1; + reconcileChildren( + current$$1, + workInProgress, + nextProps, + renderExpirationTime + ); + return workInProgress.child; +} +function updateMemoComponent( + current$$1, + workInProgress, + Component, + nextProps, + updateExpirationTime, + renderExpirationTime +) { + if (null === current$$1) { + var type = Component.type; + if ( + "function" === typeof type && + !shouldConstruct(type) && + void 0 === type.defaultProps && + null === Component.compare && + void 0 === Component.defaultProps + ) + return ( + (workInProgress.tag = 15), + (workInProgress.type = type), + updateSimpleMemoComponent( + current$$1, + workInProgress, + type, + nextProps, + updateExpirationTime, + renderExpirationTime + ) + ); + current$$1 = createFiberFromTypeAndProps( + Component.type, + null, + nextProps, + null, + workInProgress.mode, + renderExpirationTime + ); + current$$1.ref = workInProgress.ref; + current$$1.return = workInProgress; + return (workInProgress.child = current$$1); + } + type = current$$1.child; + if ( + updateExpirationTime < renderExpirationTime && + ((updateExpirationTime = type.memoizedProps), + (Component = Component.compare), + (Component = null !== Component ? Component : shallowEqual), + Component(updateExpirationTime, nextProps) && + current$$1.ref === workInProgress.ref) + ) + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + workInProgress.effectTag |= 1; + current$$1 = createWorkInProgress(type, nextProps, renderExpirationTime); + current$$1.ref = workInProgress.ref; + current$$1.return = workInProgress; + return (workInProgress.child = current$$1); +} +function updateSimpleMemoComponent( + current$$1, + workInProgress, + Component, + nextProps, + updateExpirationTime, + renderExpirationTime +) { + return null !== current$$1 && + shallowEqual(current$$1.memoizedProps, nextProps) && + current$$1.ref === workInProgress.ref && + ((didReceiveUpdate = !1), updateExpirationTime < renderExpirationTime) + ? bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ) + : updateFunctionComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime + ); +} +function markRef(current$$1, workInProgress) { + var ref = workInProgress.ref; + if ( + (null === current$$1 && null !== ref) || + (null !== current$$1 && current$$1.ref !== ref) + ) + workInProgress.effectTag |= 128; +} +function updateFunctionComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + var unmaskedContext = isContextProvider(Component) + ? previousContext + : contextStackCursor.current; + unmaskedContext = getMaskedContext(workInProgress, unmaskedContext); + prepareToReadContext(workInProgress, renderExpirationTime); + Component = renderWithHooks( + current$$1, + workInProgress, + Component, + nextProps, + unmaskedContext, + renderExpirationTime + ); + if (null !== current$$1 && !didReceiveUpdate) + return ( + (workInProgress.updateQueue = current$$1.updateQueue), + (workInProgress.effectTag &= -517), + current$$1.expirationTime <= renderExpirationTime && + (current$$1.expirationTime = 0), + bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ) + ); + workInProgress.effectTag |= 1; + reconcileChildren( + current$$1, + workInProgress, + Component, + renderExpirationTime + ); + return workInProgress.child; +} +function updateClassComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + if (isContextProvider(Component)) { + var hasContext = !0; + pushContextProvider(workInProgress); + } else hasContext = !1; + prepareToReadContext(workInProgress, renderExpirationTime); + if (null === workInProgress.stateNode) + null !== current$$1 && + ((current$$1.alternate = null), + (workInProgress.alternate = null), + (workInProgress.effectTag |= 2)), + constructClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ), + mountClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ), + (nextProps = !0); + else if (null === current$$1) { + var instance = workInProgress.stateNode, + oldProps = workInProgress.memoizedProps; + instance.props = oldProps; + var oldContext = instance.context, + contextType = Component.contextType; + "object" === typeof contextType && null !== contextType + ? (contextType = readContext(contextType)) + : ((contextType = isContextProvider(Component) + ? previousContext + : contextStackCursor.current), + (contextType = getMaskedContext(workInProgress, contextType))); + var getDerivedStateFromProps = Component.getDerivedStateFromProps, + hasNewLifecycles = + "function" === typeof getDerivedStateFromProps || + "function" === typeof instance.getSnapshotBeforeUpdate; + hasNewLifecycles || + ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && + "function" !== typeof instance.componentWillReceiveProps) || + ((oldProps !== nextProps || oldContext !== contextType) && + callComponentWillReceiveProps( + workInProgress, + instance, + nextProps, + contextType + )); + hasForceUpdate = !1; + var oldState = workInProgress.memoizedState; + oldContext = instance.state = oldState; + var updateQueue = workInProgress.updateQueue; + null !== updateQueue && + (processUpdateQueue( + workInProgress, + updateQueue, + nextProps, + instance, + renderExpirationTime + ), + (oldContext = workInProgress.memoizedState)); + oldProps !== nextProps || + oldState !== oldContext || + didPerformWorkStackCursor.current || + hasForceUpdate + ? ("function" === typeof getDerivedStateFromProps && + (applyDerivedStateFromProps( + workInProgress, + Component, + getDerivedStateFromProps, + nextProps + ), + (oldContext = workInProgress.memoizedState)), + (oldProps = + hasForceUpdate || + checkShouldComponentUpdate( + workInProgress, + Component, + oldProps, + nextProps, + oldState, + oldContext, + contextType + )) + ? (hasNewLifecycles || + ("function" !== typeof instance.UNSAFE_componentWillMount && + "function" !== typeof instance.componentWillMount) || + ("function" === typeof instance.componentWillMount && + instance.componentWillMount(), + "function" === typeof instance.UNSAFE_componentWillMount && + instance.UNSAFE_componentWillMount()), + "function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4)) + : ("function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4), + (workInProgress.memoizedProps = nextProps), + (workInProgress.memoizedState = oldContext)), + (instance.props = nextProps), + (instance.state = oldContext), + (instance.context = contextType), + (nextProps = oldProps)) + : ("function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4), + (nextProps = !1)); + } else + (instance = workInProgress.stateNode), + (oldProps = workInProgress.memoizedProps), + (instance.props = + workInProgress.type === workInProgress.elementType + ? oldProps + : resolveDefaultProps(workInProgress.type, oldProps)), + (oldContext = instance.context), + (contextType = Component.contextType), + "object" === typeof contextType && null !== contextType + ? (contextType = readContext(contextType)) + : ((contextType = isContextProvider(Component) + ? previousContext + : contextStackCursor.current), + (contextType = getMaskedContext(workInProgress, contextType))), + (getDerivedStateFromProps = Component.getDerivedStateFromProps), + (hasNewLifecycles = + "function" === typeof getDerivedStateFromProps || + "function" === typeof instance.getSnapshotBeforeUpdate) || + ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && + "function" !== typeof instance.componentWillReceiveProps) || + ((oldProps !== nextProps || oldContext !== contextType) && + callComponentWillReceiveProps( + workInProgress, + instance, + nextProps, + contextType + )), + (hasForceUpdate = !1), + (oldContext = workInProgress.memoizedState), + (oldState = instance.state = oldContext), + (updateQueue = workInProgress.updateQueue), + null !== updateQueue && + (processUpdateQueue( + workInProgress, + updateQueue, + nextProps, + instance, + renderExpirationTime + ), + (oldState = workInProgress.memoizedState)), + oldProps !== nextProps || + oldContext !== oldState || + didPerformWorkStackCursor.current || + hasForceUpdate + ? ("function" === typeof getDerivedStateFromProps && + (applyDerivedStateFromProps( + workInProgress, + Component, + getDerivedStateFromProps, + nextProps + ), + (oldState = workInProgress.memoizedState)), + (getDerivedStateFromProps = + hasForceUpdate || + checkShouldComponentUpdate( + workInProgress, + Component, + oldProps, + nextProps, + oldContext, + oldState, + contextType + )) + ? (hasNewLifecycles || + ("function" !== typeof instance.UNSAFE_componentWillUpdate && + "function" !== typeof instance.componentWillUpdate) || + ("function" === typeof instance.componentWillUpdate && + instance.componentWillUpdate( + nextProps, + oldState, + contextType + ), + "function" === typeof instance.UNSAFE_componentWillUpdate && + instance.UNSAFE_componentWillUpdate( + nextProps, + oldState, + contextType + )), + "function" === typeof instance.componentDidUpdate && + (workInProgress.effectTag |= 4), + "function" === typeof instance.getSnapshotBeforeUpdate && + (workInProgress.effectTag |= 256)) + : ("function" !== typeof instance.componentDidUpdate || + (oldProps === current$$1.memoizedProps && + oldContext === current$$1.memoizedState) || + (workInProgress.effectTag |= 4), + "function" !== typeof instance.getSnapshotBeforeUpdate || + (oldProps === current$$1.memoizedProps && + oldContext === current$$1.memoizedState) || + (workInProgress.effectTag |= 256), + (workInProgress.memoizedProps = nextProps), + (workInProgress.memoizedState = oldState)), + (instance.props = nextProps), + (instance.state = oldState), + (instance.context = contextType), + (nextProps = getDerivedStateFromProps)) + : ("function" !== typeof instance.componentDidUpdate || + (oldProps === current$$1.memoizedProps && + oldContext === current$$1.memoizedState) || + (workInProgress.effectTag |= 4), + "function" !== typeof instance.getSnapshotBeforeUpdate || + (oldProps === current$$1.memoizedProps && + oldContext === current$$1.memoizedState) || + (workInProgress.effectTag |= 256), + (nextProps = !1)); + return finishClassComponent( + current$$1, + workInProgress, + Component, + nextProps, + hasContext, + renderExpirationTime + ); +} +function finishClassComponent( + current$$1, + workInProgress, + Component, + shouldUpdate, + hasContext, + renderExpirationTime +) { + markRef(current$$1, workInProgress); + var didCaptureError = 0 !== (workInProgress.effectTag & 64); + if (!shouldUpdate && !didCaptureError) + return ( + hasContext && invalidateContextProvider(workInProgress, Component, !1), + bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ) + ); + shouldUpdate = workInProgress.stateNode; + ReactCurrentOwner$3.current = workInProgress; + if ( + didCaptureError && + "function" !== typeof Component.getDerivedStateFromError + ) { + var nextChildren = null; + profilerStartTime = -1; + } else nextChildren = shouldUpdate.render(); + workInProgress.effectTag |= 1; + null !== current$$1 && didCaptureError + ? ((didCaptureError = nextChildren), + (workInProgress.child = reconcileChildFibers( + workInProgress, + current$$1.child, + null, + renderExpirationTime + )), + (workInProgress.child = reconcileChildFibers( + workInProgress, + null, + didCaptureError, + renderExpirationTime + ))) + : reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + workInProgress.memoizedState = shouldUpdate.state; + hasContext && invalidateContextProvider(workInProgress, Component, !0); + return workInProgress.child; +} +function pushHostRootContext(workInProgress) { + var root = workInProgress.stateNode; + root.pendingContext + ? pushTopLevelContextObject( + workInProgress, + root.pendingContext, + root.pendingContext !== root.context + ) + : root.context && + pushTopLevelContextObject(workInProgress, root.context, !1); + pushHostContainer(workInProgress, root.containerInfo); +} +function updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime +) { + var mode = workInProgress.mode, + nextProps = workInProgress.pendingProps, + nextState = workInProgress.memoizedState; + if (0 === (workInProgress.effectTag & 64)) { + nextState = null; + var nextDidTimeout = !1; + } else + (nextState = { + fallbackExpirationTime: + null !== nextState ? nextState.fallbackExpirationTime : 0 + }), + (nextDidTimeout = !0), + (workInProgress.effectTag &= -65); + if (null === current$$1) + if (nextDidTimeout) { + var nextFallbackChildren = nextProps.fallback; + current$$1 = createFiberFromFragment(null, mode, 0, null); + 0 === (workInProgress.mode & 1) && + (current$$1.child = + null !== workInProgress.memoizedState + ? workInProgress.child.child + : workInProgress.child); + renderExpirationTime = createFiberFromFragment( + nextFallbackChildren, + mode, + renderExpirationTime, + null + ); + current$$1.sibling = renderExpirationTime; + mode = current$$1; + mode.return = renderExpirationTime.return = workInProgress; + } else + mode = renderExpirationTime = mountChildFibers( + workInProgress, + null, + nextProps.children, + renderExpirationTime + ); + else { + if (null !== current$$1.memoizedState) + if ( + ((nextFallbackChildren = current$$1.child), + (mode = nextFallbackChildren.sibling), + nextDidTimeout) + ) { + nextProps = nextProps.fallback; + renderExpirationTime = createWorkInProgress( + nextFallbackChildren, + nextFallbackChildren.pendingProps, + 0 + ); + 0 === (workInProgress.mode & 1) && + ((nextDidTimeout = + null !== workInProgress.memoizedState + ? workInProgress.child.child + : workInProgress.child), + nextDidTimeout !== nextFallbackChildren.child && + (renderExpirationTime.child = nextDidTimeout)); + if (workInProgress.mode & 4) { + nextFallbackChildren = 0; + for ( + nextDidTimeout = renderExpirationTime.child; + null !== nextDidTimeout; + + ) + (nextFallbackChildren += nextDidTimeout.treeBaseDuration), + (nextDidTimeout = nextDidTimeout.sibling); + renderExpirationTime.treeBaseDuration = nextFallbackChildren; + } + nextFallbackChildren = renderExpirationTime.sibling = createWorkInProgress( + mode, + nextProps, + mode.expirationTime + ); + mode = renderExpirationTime; + renderExpirationTime.childExpirationTime = 0; + renderExpirationTime = nextFallbackChildren; + mode.return = renderExpirationTime.return = workInProgress; + } else + mode = renderExpirationTime = reconcileChildFibers( + workInProgress, + nextFallbackChildren.child, + nextProps.children, + renderExpirationTime + ); + else { + var _currentPrimaryChild = current$$1.child; + if (nextDidTimeout) { + nextProps = nextProps.fallback; + nextFallbackChildren = createFiberFromFragment(null, mode, 0, null); + nextFallbackChildren.child = _currentPrimaryChild; + 0 === (workInProgress.mode & 1) && + (nextFallbackChildren.child = + null !== workInProgress.memoizedState + ? workInProgress.child.child + : workInProgress.child); + if (workInProgress.mode & 4) { + nextDidTimeout = 0; + for ( + _currentPrimaryChild = nextFallbackChildren.child; + null !== _currentPrimaryChild; + + ) + (nextDidTimeout += _currentPrimaryChild.treeBaseDuration), + (_currentPrimaryChild = _currentPrimaryChild.sibling); + nextFallbackChildren.treeBaseDuration = nextDidTimeout; + } + renderExpirationTime = nextFallbackChildren.sibling = createFiberFromFragment( + nextProps, + mode, + renderExpirationTime, + null + ); + renderExpirationTime.effectTag |= 2; + mode = nextFallbackChildren; + nextFallbackChildren.childExpirationTime = 0; + mode.return = renderExpirationTime.return = workInProgress; + } else + renderExpirationTime = mode = reconcileChildFibers( + workInProgress, + _currentPrimaryChild, + nextProps.children, + renderExpirationTime + ); + } + workInProgress.stateNode = current$$1.stateNode; + } + workInProgress.memoizedState = nextState; + workInProgress.child = mode; + return renderExpirationTime; +} +function bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime +) { + null !== current$$1 && + (workInProgress.contextDependencies = current$$1.contextDependencies); + profilerStartTime = -1; + if (workInProgress.childExpirationTime < renderExpirationTime) return null; + if (null !== current$$1 && workInProgress.child !== current$$1.child) + throw ReactError("Resuming work not yet implemented."); + if (null !== workInProgress.child) { + current$$1 = workInProgress.child; + renderExpirationTime = createWorkInProgress( + current$$1, + current$$1.pendingProps, + current$$1.expirationTime + ); + workInProgress.child = renderExpirationTime; + for ( + renderExpirationTime.return = workInProgress; + null !== current$$1.sibling; + + ) + (current$$1 = current$$1.sibling), + (renderExpirationTime = renderExpirationTime.sibling = createWorkInProgress( + current$$1, + current$$1.pendingProps, + current$$1.expirationTime + )), + (renderExpirationTime.return = workInProgress); + renderExpirationTime.sibling = null; + } + return workInProgress.child; +} +var appendAllChildren = void 0, + updateHostContainer = void 0, + updateHostComponent$1 = void 0, + updateHostText$1 = void 0; +appendAllChildren = function( + parent, + workInProgress, + needsVisibilityToggle, + isHidden +) { + for (var node = workInProgress.child; null !== node; ) { + if (5 === node.tag) { + var instance = node.stateNode; + needsVisibilityToggle && + isHidden && + (instance = cloneHiddenInstance( + instance, + node.type, + node.memoizedProps, + node + )); + appendChildNode(parent.node, instance.node); + } else if (6 === node.tag) { + instance = node.stateNode; + if (needsVisibilityToggle && isHidden) + throw Error("Not yet implemented."); + appendChildNode(parent.node, instance.node); + } else if (4 !== node.tag) { + if ( + 13 === node.tag && + 0 !== (node.effectTag & 4) && + (instance = null !== node.memoizedState) + ) { + var primaryChildParent = node.child; + if ( + null !== primaryChildParent && + (null !== primaryChildParent.child && + ((primaryChildParent.child.return = primaryChildParent), + appendAllChildren(parent, primaryChildParent, !0, instance)), + (instance = primaryChildParent.sibling), + null !== instance) + ) { + instance.return = node; + node = instance; + continue; + } + } + if (null !== node.child) { + node.child.return = node; + node = node.child; + continue; + } + } + if (node === workInProgress) break; + for (; null === node.sibling; ) { + if (null === node.return || node.return === workInProgress) return; + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } +}; +function appendAllChildrenToContainer( + containerChildSet, + workInProgress, + needsVisibilityToggle, + isHidden +) { + for (var node = workInProgress.child; null !== node; ) { + if (5 === node.tag) { + var instance = node.stateNode; + needsVisibilityToggle && + isHidden && + (instance = cloneHiddenInstance( + instance, + node.type, + node.memoizedProps, + node + )); + appendChildNodeToSet(containerChildSet, instance.node); + } else if (6 === node.tag) { + instance = node.stateNode; + if (needsVisibilityToggle && isHidden) + throw Error("Not yet implemented."); + appendChildNodeToSet(containerChildSet, instance.node); + } else if (4 !== node.tag) { + if ( + 13 === node.tag && + 0 !== (node.effectTag & 4) && + (instance = null !== node.memoizedState) + ) { + var primaryChildParent = node.child; + if ( + null !== primaryChildParent && + (null !== primaryChildParent.child && + ((primaryChildParent.child.return = primaryChildParent), + appendAllChildrenToContainer( + containerChildSet, + primaryChildParent, + !0, + instance + )), + (instance = primaryChildParent.sibling), + null !== instance) + ) { + instance.return = node; + node = instance; + continue; + } + } + if (null !== node.child) { + node.child.return = node; + node = node.child; + continue; + } + } + if (node === workInProgress) break; + for (; null === node.sibling; ) { + if (null === node.return || node.return === workInProgress) return; + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } +} +updateHostContainer = function(workInProgress) { + var portalOrRoot = workInProgress.stateNode; + if (null !== workInProgress.firstEffect) { + var container = portalOrRoot.containerInfo, + newChildSet = createChildNodeSet(container); + appendAllChildrenToContainer(newChildSet, workInProgress, !1, !1); + portalOrRoot.pendingChildren = newChildSet; + workInProgress.effectTag |= 4; + completeRoot(container, newChildSet); + } +}; +updateHostComponent$1 = function(current, workInProgress, type, newProps) { + type = current.stateNode; + var oldProps = current.memoizedProps; + if ((current = null === workInProgress.firstEffect) && oldProps === newProps) + workInProgress.stateNode = type; + else { + var recyclableInstance = workInProgress.stateNode; + requiredContext(contextStackCursor$1.current); + var updatePayload = null; + oldProps !== newProps && + ((oldProps = diffProperties( + null, + oldProps, + newProps, + recyclableInstance.canonical.viewConfig.validAttributes + )), + (recyclableInstance.canonical.currentProps = newProps), + (updatePayload = oldProps)); + current && null === updatePayload + ? (workInProgress.stateNode = type) + : ((newProps = updatePayload), + (recyclableInstance = type.node), + (type = { + node: current + ? null !== newProps + ? cloneNodeWithNewProps(recyclableInstance, newProps) + : cloneNode(recyclableInstance) + : null !== newProps + ? cloneNodeWithNewChildrenAndProps(recyclableInstance, newProps) + : cloneNodeWithNewChildren(recyclableInstance), + canonical: type.canonical + }), + (workInProgress.stateNode = type), + current + ? (workInProgress.effectTag |= 4) + : appendAllChildren(type, workInProgress, !1, !1)); + } +}; +updateHostText$1 = function(current, workInProgress, oldText, newText) { + oldText !== newText && + ((current = requiredContext(rootInstanceStackCursor.current)), + (oldText = requiredContext(contextStackCursor$1.current)), + (workInProgress.stateNode = createTextInstance( + newText, + current, + oldText, + workInProgress + )), + (workInProgress.effectTag |= 4)); +}; +function completeWork(current, workInProgress, renderExpirationTime) { + var newProps = workInProgress.pendingProps; + switch (workInProgress.tag) { + case 2: + break; + case 16: + break; + case 15: + case 0: + break; + case 1: + isContextProvider(workInProgress.type) && popContext(workInProgress); + break; + case 3: + popHostContainer(workInProgress); + popTopLevelContextObject(workInProgress); + newProps = workInProgress.stateNode; + newProps.pendingContext && + ((newProps.context = newProps.pendingContext), + (newProps.pendingContext = null)); + if (null === current || null === current.child) + workInProgress.effectTag &= -3; + updateHostContainer(workInProgress); + break; + case 5: + popHostContext(workInProgress); + renderExpirationTime = requiredContext(rootInstanceStackCursor.current); + var type = workInProgress.type; + if (null !== current && null != workInProgress.stateNode) + updateHostComponent$1( + current, + workInProgress, + type, + newProps, + renderExpirationTime + ), + current.ref !== workInProgress.ref && + (workInProgress.effectTag |= 128); + else if (newProps) { + requiredContext(contextStackCursor$1.current); + current = nextReactTag; + nextReactTag += 2; + type = getViewConfigForType(type); + var updatePayload = diffProperties( + null, + emptyObject, + newProps, + type.validAttributes + ); + renderExpirationTime = createNode( + current, + type.uiViewClassName, + renderExpirationTime, + updatePayload, + workInProgress + ); + current = new ReactFabricHostComponent( + current, + type, + newProps, + workInProgress + ); + current = { node: renderExpirationTime, canonical: current }; + appendAllChildren(current, workInProgress, !1, !1); + workInProgress.stateNode = current; + null !== workInProgress.ref && (workInProgress.effectTag |= 128); + } else if (null === workInProgress.stateNode) + throw ReactError( + "We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue." + ); + break; + case 6: + if (current && null != workInProgress.stateNode) + updateHostText$1( + current, + workInProgress, + current.memoizedProps, + newProps + ); + else { + if ("string" !== typeof newProps && null === workInProgress.stateNode) + throw ReactError( + "We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue." + ); + current = requiredContext(rootInstanceStackCursor.current); + renderExpirationTime = requiredContext(contextStackCursor$1.current); + workInProgress.stateNode = createTextInstance( + newProps, + current, + renderExpirationTime, + workInProgress + ); + } + break; + case 11: + break; + case 13: + newProps = workInProgress.memoizedState; + if (0 !== (workInProgress.effectTag & 64)) + return ( + (workInProgress.expirationTime = renderExpirationTime), workInProgress + ); + newProps = null !== newProps; + renderExpirationTime = !1; + null !== current && + ((type = current.memoizedState), + (renderExpirationTime = null !== type), + newProps || + null === type || + ((type = type.fallbackExpirationTime), + type < workInProgressRootMostRecentEventTime && + (workInProgressRootMostRecentEventTime = type), + (current = current.child.sibling), + null !== current && + ((type = workInProgress.firstEffect), + null !== type + ? ((workInProgress.firstEffect = current), + (current.nextEffect = type)) + : ((workInProgress.firstEffect = workInProgress.lastEffect = current), + (current.nextEffect = null)), + (current.effectTag = 8)))); + newProps && + !renderExpirationTime && + 0 !== (workInProgress.mode & 1) && + workInProgressRootExitStatus === RootIncomplete && + (workInProgressRootExitStatus = RootSuspended); + newProps && (workInProgress.effectTag |= 4); + break; + case 7: + break; + case 8: + break; + case 12: + break; + case 4: + popHostContainer(workInProgress); + updateHostContainer(workInProgress); + break; + case 10: + popProvider(workInProgress); + break; + case 9: + break; + case 14: + break; + case 17: + isContextProvider(workInProgress.type) && popContext(workInProgress); + break; + case 18: + break; + case 19: + break; + case 20: + break; + default: + throw ReactError( + "Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue." + ); + } + return null; +} +function createCapturedValue(value, source) { + return { + value: value, + source: source, + stack: getStackByFiberInDevAndProd(source) + }; +} +function logCapturedError(capturedError) { + var componentStack = capturedError.componentStack, + error = capturedError.error; + if (error instanceof Error) { + capturedError = error.message; + var name = error.name; + try { + error.message = + (capturedError ? name + ": " + capturedError : name) + + "\n\nThis error is located at:" + + componentStack; + } catch (e) {} + } else + error = + "string" === typeof error + ? Error(error + "\n\nThis error is located at:" + componentStack) + : Error("Unspecified error at:" + componentStack); + ReactNativePrivateInterface.ExceptionsManager.handleException(error, !1); +} +var PossiblyWeakSet$1 = "function" === typeof WeakSet ? WeakSet : Set; +function logError(boundary, errorInfo) { + var source = errorInfo.source, + stack = errorInfo.stack; + null === stack && + null !== source && + (stack = getStackByFiberInDevAndProd(source)); + errorInfo = { + componentName: null !== source ? getComponentName(source.type) : null, + componentStack: null !== stack ? stack : "", + error: errorInfo.value, + errorBoundary: null, + errorBoundaryName: null, + errorBoundaryFound: !1, + willRetry: !1 + }; + null !== boundary && + 1 === boundary.tag && + ((errorInfo.errorBoundary = boundary.stateNode), + (errorInfo.errorBoundaryName = getComponentName(boundary.type)), + (errorInfo.errorBoundaryFound = !0), + (errorInfo.willRetry = !0)); + try { + logCapturedError(errorInfo); + } catch (e) { + setTimeout(function() { + throw e; + }); + } +} +function safelyDetachRef(current$$1) { + var ref = current$$1.ref; + if (null !== ref) + if ("function" === typeof ref) + try { + ref(null); + } catch (refError) { + captureCommitPhaseError(current$$1, refError); + } + else ref.current = null; +} +function commitHookEffectList(unmountTag, mountTag, finishedWork) { + finishedWork = finishedWork.updateQueue; + finishedWork = null !== finishedWork ? finishedWork.lastEffect : null; + if (null !== finishedWork) { + var effect = (finishedWork = finishedWork.next); + do { + if ((effect.tag & unmountTag) !== NoEffect$1) { + var destroy = effect.destroy; + effect.destroy = void 0; + void 0 !== destroy && destroy(); + } + (effect.tag & mountTag) !== NoEffect$1 && + ((destroy = effect.create), (effect.destroy = destroy())); + effect = effect.next; + } while (effect !== finishedWork); + } +} +function commitWork(current$$1, finishedWork) { + switch (finishedWork.tag) { + case 0: + case 11: + case 14: + case 15: + commitHookEffectList(UnmountMutation, MountMutation, finishedWork); + return; + case 12: + return; + case 13: + commitSuspenseComponent(finishedWork); + return; + } + switch (finishedWork.tag) { + case 1: + case 5: + case 6: + case 20: + case 19: + break; + case 3: + case 4: + break; + default: + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } +} +function commitSuspenseComponent(finishedWork) { + var newState = finishedWork.memoizedState; + null !== newState && + 0 === newState.fallbackExpirationTime && + (newState.fallbackExpirationTime = requestCurrentTime() - 500); + newState = finishedWork.updateQueue; + if (null !== newState) { + finishedWork.updateQueue = null; + var retryCache = finishedWork.stateNode; + null === retryCache && + (retryCache = finishedWork.stateNode = new PossiblyWeakSet$1()); + newState.forEach(function(thenable) { + var retry = resolveRetryThenable.bind(null, finishedWork, thenable); + retryCache.has(thenable) || + ((retry = tracing.unstable_wrap(retry)), + retryCache.add(thenable), + thenable.then(retry, retry)); + }); + } +} +var PossiblyWeakMap = "function" === typeof WeakMap ? WeakMap : Map; +function createRootErrorUpdate(fiber, errorInfo, expirationTime) { + expirationTime = createUpdate(expirationTime); + expirationTime.tag = 3; + expirationTime.payload = { element: null }; + var error = errorInfo.value; + expirationTime.callback = function() { + hasUncaughtError || ((hasUncaughtError = !0), (firstUncaughtError = error)); + logError(fiber, errorInfo); + }; + return expirationTime; +} +function createClassErrorUpdate(fiber, errorInfo, expirationTime) { + expirationTime = createUpdate(expirationTime); + expirationTime.tag = 3; + var getDerivedStateFromError = fiber.type.getDerivedStateFromError; + if ("function" === typeof getDerivedStateFromError) { + var error$jscomp$0 = errorInfo.value; + expirationTime.payload = function() { + return getDerivedStateFromError(error$jscomp$0); + }; + } + var inst = fiber.stateNode; + null !== inst && + "function" === typeof inst.componentDidCatch && + (expirationTime.callback = function() { + "function" !== typeof getDerivedStateFromError && + (null === legacyErrorBoundariesThatAlreadyFailed + ? (legacyErrorBoundariesThatAlreadyFailed = new Set([this])) + : legacyErrorBoundariesThatAlreadyFailed.add(this)); + var error = errorInfo.value, + stack = errorInfo.stack; + logError(fiber, errorInfo); + this.componentDidCatch(error, { + componentStack: null !== stack ? stack : "" + }); + }); + return expirationTime; +} +function unwindWork(workInProgress) { + switch (workInProgress.tag) { + case 1: + isContextProvider(workInProgress.type) && popContext(workInProgress); + var effectTag = workInProgress.effectTag; + return effectTag & 2048 + ? ((workInProgress.effectTag = (effectTag & -2049) | 64), + workInProgress) + : null; + case 3: + popHostContainer(workInProgress); + popTopLevelContextObject(workInProgress); + effectTag = workInProgress.effectTag; + if (0 !== (effectTag & 64)) + throw ReactError( + "The root failed to unmount after an error. This is likely a bug in React. Please file an issue." + ); + workInProgress.effectTag = (effectTag & -2049) | 64; + return workInProgress; + case 5: + return popHostContext(workInProgress), null; + case 13: + return ( + (effectTag = workInProgress.effectTag), + effectTag & 2048 + ? ((workInProgress.effectTag = (effectTag & -2049) | 64), + workInProgress) + : null + ); + case 18: + return null; + case 4: + return popHostContainer(workInProgress), null; + case 10: + return popProvider(workInProgress), null; + case 19: + case 20: + return null; + default: + return null; + } +} +var ceil = Math.ceil, + ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher, + ReactCurrentOwner$2 = ReactSharedInternals.ReactCurrentOwner, + LegacyUnbatchedPhase = 2, + RenderPhase = 4, + CommitPhase = 5, + RootIncomplete = 0, + RootErrored = 1, + RootSuspended = 2, + RootCompleted = 3, + workPhase = 0, + workInProgressRoot = null, + workInProgress = null, + renderExpirationTime = 0, + workInProgressRootExitStatus = RootIncomplete, + workInProgressRootMostRecentEventTime = 1073741823, + nextEffect = null, + hasUncaughtError = !1, + firstUncaughtError = null, + legacyErrorBoundariesThatAlreadyFailed = null, + rootDoesHavePassiveEffects = !1, + rootWithPendingPassiveEffects = null, + pendingPassiveEffectsExpirationTime = 0, + rootsWithPendingDiscreteUpdates = null, + nestedUpdateCount = 0, + rootWithNestedUpdates = null, + currentEventTime = 0; +function requestCurrentTime() { + return workPhase === RenderPhase || workPhase === CommitPhase + ? 1073741822 - ((now() / 10) | 0) + : 0 !== currentEventTime + ? currentEventTime + : (currentEventTime = 1073741822 - ((now() / 10) | 0)); +} +function computeExpirationForFiber(currentTime, fiber) { + if (0 === (fiber.mode & 1)) return 1073741823; + if (workPhase === RenderPhase) return renderExpirationTime; + switch (getCurrentPriorityLevel()) { + case 99: + currentTime = 1073741823; + break; + case 98: + currentTime = + 1073741822 - 10 * ((((1073741822 - currentTime + 15) / 10) | 0) + 1); + break; + case 97: + case 96: + currentTime = + 1073741822 - 25 * ((((1073741822 - currentTime + 500) / 25) | 0) + 1); + break; + case 95: + currentTime = 1; + break; + default: + throw ReactError("Expected a valid priority level"); + } + null !== workInProgressRoot && + currentTime === renderExpirationTime && + --currentTime; + return currentTime; +} +function scheduleUpdateOnFiber(fiber, expirationTime) { + if (50 < nestedUpdateCount) + throw ((nestedUpdateCount = 0), + (rootWithNestedUpdates = null), + ReactError( + "Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops." + )); + fiber = markUpdateTimeFromFiberToRoot(fiber, expirationTime); + if (null !== fiber) + if (((fiber.pingTime = 0), 1073741823 === expirationTime)) + if (workPhase === LegacyUnbatchedPhase) + for ( + expirationTime = renderRoot(fiber, 1073741823, !0); + null !== expirationTime; + + ) + expirationTime = expirationTime(!0); + else + scheduleCallbackForRoot(fiber, 99, 1073741823), + 0 === workPhase && flushImmediateQueue(); + else { + var priorityLevel = getCurrentPriorityLevel(); + if (98 === priorityLevel) + if (null === rootsWithPendingDiscreteUpdates) + rootsWithPendingDiscreteUpdates = new Map([[fiber, expirationTime]]); + else { + var lastDiscreteTime = rootsWithPendingDiscreteUpdates.get(fiber); + (void 0 === lastDiscreteTime || lastDiscreteTime > expirationTime) && + rootsWithPendingDiscreteUpdates.set(fiber, expirationTime); + } + scheduleCallbackForRoot(fiber, priorityLevel, expirationTime); + } +} +function markUpdateTimeFromFiberToRoot(fiber, expirationTime) { + fiber.expirationTime < expirationTime && + (fiber.expirationTime = expirationTime); + var alternate = fiber.alternate; + null !== alternate && + alternate.expirationTime < expirationTime && + (alternate.expirationTime = expirationTime); + var node = fiber.return, + root = null; + if (null === node && 3 === fiber.tag) root = fiber.stateNode; + else + for (; null !== node; ) { + alternate = node.alternate; + node.childExpirationTime < expirationTime && + (node.childExpirationTime = expirationTime); + null !== alternate && + alternate.childExpirationTime < expirationTime && + (alternate.childExpirationTime = expirationTime); + if (null === node.return && 3 === node.tag) { + root = node.stateNode; + break; + } + node = node.return; + } + null !== root && + (expirationTime > root.firstPendingTime && + (root.firstPendingTime = expirationTime), + (fiber = root.lastPendingTime), + 0 === fiber || expirationTime < fiber) && + (root.lastPendingTime = expirationTime); + return root; +} +function scheduleCallbackForRoot(root, priorityLevel, expirationTime) { + if (root.callbackExpirationTime < expirationTime) { + var existingCallbackNode = root.callbackNode; + null !== existingCallbackNode && + existingCallbackNode !== fakeCallbackNode && + Scheduler_cancelCallback(existingCallbackNode); + root.callbackExpirationTime = expirationTime; + existingCallbackNode = null; + 1073741823 !== expirationTime && + 1 !== expirationTime && + ((existingCallbackNode = 10 * (1073741822 - expirationTime) - now()), + 5e3 < existingCallbackNode && (existingCallbackNode = 5e3), + (existingCallbackNode = { timeout: existingCallbackNode })); + root.callbackNode = scheduleCallback( + priorityLevel, + runRootCallback.bind( + null, + root, + renderRoot.bind(null, root, expirationTime) + ), + existingCallbackNode + ); + } + schedulePendingInteraction(root, expirationTime); +} +function runRootCallback(root, callback, isSync) { + var prevCallbackNode = root.callbackNode, + continuation = null; + try { + return ( + (continuation = callback(isSync)), + null !== continuation + ? runRootCallback.bind(null, root, continuation) + : null + ); + } finally { + null === continuation && + prevCallbackNode === root.callbackNode && + ((root.callbackNode = null), (root.callbackExpirationTime = 0)); + } +} +function resolveLocksOnRoot(root, expirationTime) { + var firstBatch = root.firstBatch; + return null !== firstBatch && + firstBatch._defer && + firstBatch._expirationTime >= expirationTime + ? ((root.finishedWork = root.current.alternate), + (root.pendingCommitExpirationTime = expirationTime), + scheduleCallback(97, function() { + firstBatch._onComplete(); + return null; + }), + !0) + : !1; +} +function flushPendingDiscreteUpdates() { + if (null !== rootsWithPendingDiscreteUpdates) { + var roots = rootsWithPendingDiscreteUpdates; + rootsWithPendingDiscreteUpdates = null; + roots.forEach(function(expirationTime, root) { + scheduleCallback(99, renderRoot.bind(null, root, expirationTime)); + }); + flushImmediateQueue(); + } +} +function prepareFreshStack(root, expirationTime) { + root.pendingCommitExpirationTime = 0; + var timeoutHandle = root.timeoutHandle; + -1 !== timeoutHandle && + ((root.timeoutHandle = -1), cancelTimeout(timeoutHandle)); + if (null !== workInProgress) + for (timeoutHandle = workInProgress.return; null !== timeoutHandle; ) { + var interruptedWork = timeoutHandle; + switch (interruptedWork.tag) { + case 1: + var childContextTypes = interruptedWork.type.childContextTypes; + null !== childContextTypes && + void 0 !== childContextTypes && + popContext(interruptedWork); + break; + case 3: + popHostContainer(interruptedWork); + popTopLevelContextObject(interruptedWork); + break; + case 5: + popHostContext(interruptedWork); + break; + case 4: + popHostContainer(interruptedWork); + break; + case 10: + popProvider(interruptedWork); + } + timeoutHandle = timeoutHandle.return; + } + workInProgressRoot = root; + workInProgress = createWorkInProgress(root.current, null, expirationTime); + renderExpirationTime = expirationTime; + workInProgressRootExitStatus = RootIncomplete; + workInProgressRootMostRecentEventTime = 1073741823; +} +function renderRoot(root$jscomp$0, expirationTime, isSync) { + if (workPhase === RenderPhase || workPhase === CommitPhase) + throw ReactError("Should not already be working."); + if (root$jscomp$0.firstPendingTime < expirationTime) return null; + if (root$jscomp$0.pendingCommitExpirationTime === expirationTime) + return ( + (root$jscomp$0.pendingCommitExpirationTime = 0), + commitRoot.bind(null, root$jscomp$0, expirationTime) + ); + flushPassiveEffects(); + if ( + root$jscomp$0 !== workInProgressRoot || + expirationTime !== renderExpirationTime + ) + prepareFreshStack(root$jscomp$0, expirationTime), + startWorkOnPendingInteraction(root$jscomp$0, expirationTime); + if (null !== workInProgress) { + var prevWorkPhase = workPhase; + workPhase = RenderPhase; + var prevDispatcher = ReactCurrentDispatcher.current; + null === prevDispatcher && (prevDispatcher = ContextOnlyDispatcher); + ReactCurrentDispatcher.current = ContextOnlyDispatcher; + var prevInteractions = tracing.__interactionsRef.current; + tracing.__interactionsRef.current = root$jscomp$0.memoizedInteractions; + if (isSync) { + if (1073741823 !== expirationTime) { + var currentTime = requestCurrentTime(); + if (currentTime < expirationTime) + return ( + (workPhase = prevWorkPhase), + resetContextDependences(), + (ReactCurrentDispatcher.current = prevDispatcher), + (tracing.__interactionsRef.current = prevInteractions), + renderRoot.bind(null, root$jscomp$0, currentTime) + ); + } + } else currentEventTime = 0; + do + try { + if (isSync) + for (; null !== workInProgress; ) + workInProgress = performUnitOfWork(workInProgress); + else + for (; null !== workInProgress && !Scheduler_shouldYield(); ) + workInProgress = performUnitOfWork(workInProgress); + break; + } catch (thrownValue) { + resetContextDependences(); + resetHooks(); + currentTime = workInProgress; + if (null === currentTime || null === currentTime.return) + throw (prepareFreshStack(root$jscomp$0, expirationTime), + (workPhase = prevWorkPhase), + thrownValue); + currentTime.mode & 4 && + stopProfilerTimerIfRunningAndRecordDelta(currentTime, !0); + a: { + var root = root$jscomp$0, + returnFiber = currentTime.return, + sourceFiber = currentTime, + value = thrownValue, + renderExpirationTime$jscomp$0 = renderExpirationTime; + sourceFiber.effectTag |= 1024; + sourceFiber.firstEffect = sourceFiber.lastEffect = null; + if ( + null !== value && + "object" === typeof value && + "function" === typeof value.then + ) { + var thenable = value; + value = returnFiber; + do { + if ( + 13 === value.tag && + (void 0 === value.memoizedProps.fallback + ? 0 + : null === value.memoizedState) + ) { + returnFiber = value.updateQueue; + null === returnFiber + ? ((returnFiber = new Set()), + returnFiber.add(thenable), + (value.updateQueue = returnFiber)) + : returnFiber.add(thenable); + if (0 === (value.mode & 1)) { + value.effectTag |= 64; + sourceFiber.effectTag &= -1957; + 1 === sourceFiber.tag && + (null === sourceFiber.alternate + ? (sourceFiber.tag = 17) + : ((renderExpirationTime$jscomp$0 = createUpdate( + 1073741823 + )), + (renderExpirationTime$jscomp$0.tag = 2), + enqueueUpdate( + sourceFiber, + renderExpirationTime$jscomp$0 + ))); + sourceFiber.expirationTime = 1073741823; + break a; + } + sourceFiber = root; + root = renderExpirationTime$jscomp$0; + var pingCache = sourceFiber.pingCache; + null === pingCache + ? ((pingCache = sourceFiber.pingCache = new PossiblyWeakMap()), + (returnFiber = new Set()), + pingCache.set(thenable, returnFiber)) + : ((returnFiber = pingCache.get(thenable)), + void 0 === returnFiber && + ((returnFiber = new Set()), + pingCache.set(thenable, returnFiber))); + returnFiber.has(root) || + (returnFiber.add(root), + (sourceFiber = pingSuspendedRoot.bind( + null, + sourceFiber, + thenable, + root + )), + (sourceFiber = tracing.unstable_wrap(sourceFiber)), + thenable.then(sourceFiber, sourceFiber)); + value.effectTag |= 2048; + value.expirationTime = renderExpirationTime$jscomp$0; + break a; + } + value = value.return; + } while (null !== value); + value = Error( + (getComponentName(sourceFiber.type) || "A React component") + + " suspended while rendering, but no fallback UI was specified.\n\nAdd a component higher in the tree to provide a loading indicator or placeholder to display." + + getStackByFiberInDevAndProd(sourceFiber) + ); + } + if ( + workInProgressRootExitStatus === RootIncomplete || + workInProgressRootExitStatus === RootSuspended + ) + workInProgressRootExitStatus = RootErrored; + value = createCapturedValue(value, sourceFiber); + sourceFiber = returnFiber; + do { + switch (sourceFiber.tag) { + case 3: + sourceFiber.effectTag |= 2048; + sourceFiber.expirationTime = renderExpirationTime$jscomp$0; + renderExpirationTime$jscomp$0 = createRootErrorUpdate( + sourceFiber, + value, + renderExpirationTime$jscomp$0 + ); + enqueueCapturedUpdate( + sourceFiber, + renderExpirationTime$jscomp$0 + ); + break a; + case 1: + if ( + ((thenable = value), + (root = sourceFiber.type), + (returnFiber = sourceFiber.stateNode), + 0 === (sourceFiber.effectTag & 64) && + ("function" === typeof root.getDerivedStateFromError || + (null !== returnFiber && + "function" === typeof returnFiber.componentDidCatch && + (null === legacyErrorBoundariesThatAlreadyFailed || + !legacyErrorBoundariesThatAlreadyFailed.has( + returnFiber + ))))) + ) { + sourceFiber.effectTag |= 2048; + sourceFiber.expirationTime = renderExpirationTime$jscomp$0; + renderExpirationTime$jscomp$0 = createClassErrorUpdate( + sourceFiber, + thenable, + renderExpirationTime$jscomp$0 + ); + enqueueCapturedUpdate( + sourceFiber, + renderExpirationTime$jscomp$0 + ); + break a; + } + } + sourceFiber = sourceFiber.return; + } while (null !== sourceFiber); + } + workInProgress = completeUnitOfWork(currentTime); + } + while (1); + workPhase = prevWorkPhase; + resetContextDependences(); + ReactCurrentDispatcher.current = prevDispatcher; + tracing.__interactionsRef.current = prevInteractions; + if (null !== workInProgress) + return renderRoot.bind(null, root$jscomp$0, expirationTime); + } + if (resolveLocksOnRoot(root$jscomp$0, expirationTime)) return null; + workInProgressRoot = null; + switch (workInProgressRootExitStatus) { + case RootIncomplete: + throw ReactError("Should have a work-in-progress."); + case RootErrored: + return ( + (prevWorkPhase = root$jscomp$0.lastPendingTime), + root$jscomp$0.lastPendingTime < expirationTime + ? renderRoot.bind(null, root$jscomp$0, prevWorkPhase) + : isSync + ? commitRoot.bind(null, root$jscomp$0, expirationTime) + : (prepareFreshStack(root$jscomp$0, expirationTime), + scheduleCallback( + 99, + renderRoot.bind(null, root$jscomp$0, expirationTime) + ), + null) + ); + case RootSuspended: + if (!isSync) { + isSync = root$jscomp$0.lastPendingTime; + if (root$jscomp$0.lastPendingTime < expirationTime) + return renderRoot.bind(null, root$jscomp$0, isSync); + if ( + 1073741823 !== workInProgressRootMostRecentEventTime && + ((prevWorkPhase = + 10 * (1073741822 - workInProgressRootMostRecentEventTime) - 5e3), + (isSync = now()), + (prevWorkPhase = isSync - prevWorkPhase), + (prevWorkPhase = + (120 > prevWorkPhase + ? 120 + : 480 > prevWorkPhase + ? 480 + : 1080 > prevWorkPhase + ? 1080 + : 1920 > prevWorkPhase + ? 1920 + : 3e3 > prevWorkPhase + ? 3e3 + : 4320 > prevWorkPhase + ? 4320 + : 1960 * ceil(prevWorkPhase / 1960)) - prevWorkPhase), + (isSync = 10 * (1073741822 - expirationTime) - isSync), + isSync < prevWorkPhase && (prevWorkPhase = isSync), + (isSync = prevWorkPhase), + 10 < isSync) + ) + return ( + (root$jscomp$0.timeoutHandle = scheduleTimeout( + commitRoot.bind(null, root$jscomp$0, expirationTime), + isSync + )), + null + ); + } + return commitRoot.bind(null, root$jscomp$0, expirationTime); + case RootCompleted: + return commitRoot.bind(null, root$jscomp$0, expirationTime); + default: + throw ReactError("Unknown root exit status."); + } +} +function performUnitOfWork(unitOfWork) { + var current$$1 = unitOfWork.alternate; + 0 !== (unitOfWork.mode & 4) + ? ((profilerStartTime = now$1()), + 0 > unitOfWork.actualStartTime && (unitOfWork.actualStartTime = now$1()), + (current$$1 = beginWork$$1(current$$1, unitOfWork, renderExpirationTime)), + stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, !0)) + : (current$$1 = beginWork$$1(current$$1, unitOfWork, renderExpirationTime)); + unitOfWork.memoizedProps = unitOfWork.pendingProps; + null === current$$1 && (current$$1 = completeUnitOfWork(unitOfWork)); + ReactCurrentOwner$2.current = null; + return current$$1; +} +function completeUnitOfWork(unitOfWork) { + workInProgress = unitOfWork; + do { + var current$$1 = workInProgress.alternate; + unitOfWork = workInProgress.return; + if (0 === (workInProgress.effectTag & 1024)) { + if (0 === (workInProgress.mode & 4)) + current$$1 = completeWork( + current$$1, + workInProgress, + renderExpirationTime + ); + else { + var fiber = workInProgress; + profilerStartTime = now$1(); + 0 > fiber.actualStartTime && (fiber.actualStartTime = now$1()); + current$$1 = completeWork( + current$$1, + workInProgress, + renderExpirationTime + ); + stopProfilerTimerIfRunningAndRecordDelta(workInProgress, !1); + } + fiber = workInProgress; + if (1 === renderExpirationTime || 1 !== fiber.childExpirationTime) { + var newChildExpirationTime = 0; + if (0 !== (fiber.mode & 4)) { + for ( + var actualDuration = fiber.actualDuration, + treeBaseDuration = fiber.selfBaseDuration, + shouldBubbleActualDurations = + null === fiber.alternate || + fiber.child !== fiber.alternate.child, + child = fiber.child; + null !== child; + + ) { + var childUpdateExpirationTime = child.expirationTime, + childChildExpirationTime = child.childExpirationTime; + childUpdateExpirationTime > newChildExpirationTime && + (newChildExpirationTime = childUpdateExpirationTime); + childChildExpirationTime > newChildExpirationTime && + (newChildExpirationTime = childChildExpirationTime); + shouldBubbleActualDurations && + (actualDuration += child.actualDuration); + treeBaseDuration += child.treeBaseDuration; + child = child.sibling; + } + fiber.actualDuration = actualDuration; + fiber.treeBaseDuration = treeBaseDuration; + } else + for (actualDuration = fiber.child; null !== actualDuration; ) + (treeBaseDuration = actualDuration.expirationTime), + (shouldBubbleActualDurations = + actualDuration.childExpirationTime), + treeBaseDuration > newChildExpirationTime && + (newChildExpirationTime = treeBaseDuration), + shouldBubbleActualDurations > newChildExpirationTime && + (newChildExpirationTime = shouldBubbleActualDurations), + (actualDuration = actualDuration.sibling); + fiber.childExpirationTime = newChildExpirationTime; + } + if (null !== current$$1) return current$$1; + null !== unitOfWork && + 0 === (unitOfWork.effectTag & 1024) && + (null === unitOfWork.firstEffect && + (unitOfWork.firstEffect = workInProgress.firstEffect), + null !== workInProgress.lastEffect && + (null !== unitOfWork.lastEffect && + (unitOfWork.lastEffect.nextEffect = workInProgress.firstEffect), + (unitOfWork.lastEffect = workInProgress.lastEffect)), + 1 < workInProgress.effectTag && + (null !== unitOfWork.lastEffect + ? (unitOfWork.lastEffect.nextEffect = workInProgress) + : (unitOfWork.firstEffect = workInProgress), + (unitOfWork.lastEffect = workInProgress))); + } else { + current$$1 = unwindWork(workInProgress, renderExpirationTime); + if (0 !== (workInProgress.mode & 4)) { + stopProfilerTimerIfRunningAndRecordDelta(workInProgress, !1); + fiber = workInProgress.actualDuration; + for ( + newChildExpirationTime = workInProgress.child; + null !== newChildExpirationTime; + + ) + (fiber += newChildExpirationTime.actualDuration), + (newChildExpirationTime = newChildExpirationTime.sibling); + workInProgress.actualDuration = fiber; + } + if (null !== current$$1) + return (current$$1.effectTag &= 1023), current$$1; + null !== unitOfWork && + ((unitOfWork.firstEffect = unitOfWork.lastEffect = null), + (unitOfWork.effectTag |= 1024)); + } + current$$1 = workInProgress.sibling; + if (null !== current$$1) return current$$1; + workInProgress = unitOfWork; + } while (null !== workInProgress); + workInProgressRootExitStatus === RootIncomplete && + (workInProgressRootExitStatus = RootCompleted); + return null; +} +function commitRoot(root, expirationTime) { + runWithPriority(99, commitRootImpl.bind(null, root, expirationTime)); + null !== rootWithPendingPassiveEffects && + ((root = getCurrentPriorityLevel()), + scheduleCallback(root, function() { + flushPassiveEffects(); + return null; + })); + return null; +} +function commitRootImpl(root, expirationTime) { + flushPassiveEffects(); + if (workPhase === RenderPhase || workPhase === CommitPhase) + throw ReactError("Should not already be working."); + var finishedWork = root.current.alternate; + if (null === finishedWork) + throw ReactError("Should have a work-in-progress root."); + root.callbackNode = null; + root.callbackExpirationTime = 0; + var updateExpirationTimeBeforeCommit = finishedWork.expirationTime, + childExpirationTimeBeforeCommit = finishedWork.childExpirationTime; + updateExpirationTimeBeforeCommit = + childExpirationTimeBeforeCommit > updateExpirationTimeBeforeCommit + ? childExpirationTimeBeforeCommit + : updateExpirationTimeBeforeCommit; + root.firstPendingTime = updateExpirationTimeBeforeCommit; + updateExpirationTimeBeforeCommit < root.lastPendingTime && + (root.lastPendingTime = updateExpirationTimeBeforeCommit); + root === workInProgressRoot && + ((workInProgress = workInProgressRoot = null), (renderExpirationTime = 0)); + if (1 < finishedWork.effectTag) + if (null !== finishedWork.lastEffect) { + finishedWork.lastEffect.nextEffect = finishedWork; + var firstEffect = finishedWork.firstEffect; + } else firstEffect = finishedWork; + else firstEffect = finishedWork.firstEffect; + if (null !== firstEffect) { + updateExpirationTimeBeforeCommit = workPhase; + workPhase = CommitPhase; + childExpirationTimeBeforeCommit = tracing.__interactionsRef.current; + tracing.__interactionsRef.current = root.memoizedInteractions; + ReactCurrentOwner$2.current = null; + nextEffect = firstEffect; + do + try { + for (; null !== nextEffect; ) { + if (0 !== (nextEffect.effectTag & 256)) { + var current$$1 = nextEffect.alternate, + finishedWork$jscomp$0 = nextEffect; + switch (finishedWork$jscomp$0.tag) { + case 0: + case 11: + case 15: + commitHookEffectList( + UnmountSnapshot, + NoEffect$1, + finishedWork$jscomp$0 + ); + break; + case 1: + if ( + finishedWork$jscomp$0.effectTag & 256 && + null !== current$$1 + ) { + var prevProps = current$$1.memoizedProps, + prevState = current$$1.memoizedState, + instance = finishedWork$jscomp$0.stateNode, + snapshot = instance.getSnapshotBeforeUpdate( + finishedWork$jscomp$0.elementType === + finishedWork$jscomp$0.type + ? prevProps + : resolveDefaultProps( + finishedWork$jscomp$0.type, + prevProps + ), + prevState + ); + instance.__reactInternalSnapshotBeforeUpdate = snapshot; + } + break; + case 3: + case 5: + case 6: + case 4: + case 17: + case 20: + break; + default: + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + } + nextEffect = nextEffect.nextEffect; + } + } catch (error) { + if (null === nextEffect) + throw ReactError("Should be working on an effect."); + captureCommitPhaseError(nextEffect, error); + nextEffect = nextEffect.nextEffect; + } + while (null !== nextEffect); + commitTime = now$1(); + nextEffect = firstEffect; + do + try { + for (; null !== nextEffect; ) { + var effectTag = nextEffect.effectTag; + if (effectTag & 128) { + var current$$1$jscomp$0 = nextEffect.alternate; + if (null !== current$$1$jscomp$0) { + var currentRef = current$$1$jscomp$0.ref; + null !== currentRef && + ("function" === typeof currentRef + ? currentRef(null) + : (currentRef.current = null)); + } + } + switch (effectTag & 14) { + case 2: + nextEffect.effectTag &= -3; + break; + case 6: + nextEffect.effectTag &= -3; + commitWork(nextEffect.alternate, nextEffect); + break; + case 4: + commitWork(nextEffect.alternate, nextEffect); + break; + case 8: + current$$1 = nextEffect; + a: for (prevState = prevProps = current$$1; ; ) { + instance = prevState; + "function" === typeof onCommitFiberUnmount && + onCommitFiberUnmount(instance); + switch (instance.tag) { + case 0: + case 11: + case 14: + case 15: + var updateQueue = instance.updateQueue; + if (null !== updateQueue) { + var lastEffect = updateQueue.lastEffect; + if (null !== lastEffect) { + var firstEffect$jscomp$0 = lastEffect.next; + snapshot = firstEffect$jscomp$0; + do { + var destroy = snapshot.destroy; + if (void 0 !== destroy) { + finishedWork$jscomp$0 = instance; + try { + destroy(); + } catch (error) { + captureCommitPhaseError( + finishedWork$jscomp$0, + error + ); + } + } + snapshot = snapshot.next; + } while (snapshot !== firstEffect$jscomp$0); + } + } + break; + case 1: + safelyDetachRef(instance); + var instance$jscomp$0 = instance.stateNode; + if ( + "function" === + typeof instance$jscomp$0.componentWillUnmount + ) + try { + (instance$jscomp$0.props = instance.memoizedProps), + (instance$jscomp$0.state = instance.memoizedState), + instance$jscomp$0.componentWillUnmount(); + } catch (unmountError) { + captureCommitPhaseError(instance, unmountError); + } + break; + case 5: + safelyDetachRef(instance); + break; + case 4: + createChildNodeSet(instance.stateNode.containerInfo); + } + if (null !== prevState.child) + (prevState.child.return = prevState), + (prevState = prevState.child); + else { + if (prevState === prevProps) break; + for (; null === prevState.sibling; ) { + if ( + null === prevState.return || + prevState.return === prevProps + ) + break a; + prevState = prevState.return; + } + prevState.sibling.return = prevState.return; + prevState = prevState.sibling; + } + } + current$$1.return = null; + current$$1.child = null; + current$$1.memoizedState = null; + current$$1.updateQueue = null; + var alternate = current$$1.alternate; + null !== alternate && + ((alternate.return = null), + (alternate.child = null), + (alternate.memoizedState = null), + (alternate.updateQueue = null)); + } + nextEffect = nextEffect.nextEffect; + } + } catch (error) { + if (null === nextEffect) + throw ReactError("Should be working on an effect."); + captureCommitPhaseError(nextEffect, error); + nextEffect = nextEffect.nextEffect; + } + while (null !== nextEffect); + root.current = finishedWork; + nextEffect = firstEffect; + do + try { + for ( + effectTag = root, current$$1$jscomp$0 = expirationTime; + null !== nextEffect; + + ) { + var effectTag$jscomp$0 = nextEffect.effectTag; + if (effectTag$jscomp$0 & 36) { + lastEffect = effectTag; + var current$$1$jscomp$1 = nextEffect.alternate; + currentRef = nextEffect; + updateQueue = current$$1$jscomp$0; + switch (currentRef.tag) { + case 0: + case 11: + case 15: + commitHookEffectList(UnmountLayout, MountLayout, currentRef); + break; + case 1: + var instance$jscomp$1 = currentRef.stateNode; + if (currentRef.effectTag & 4) + if (null === current$$1$jscomp$1) + instance$jscomp$1.componentDidMount(); + else { + var prevProps$jscomp$0 = + currentRef.elementType === currentRef.type + ? current$$1$jscomp$1.memoizedProps + : resolveDefaultProps( + currentRef.type, + current$$1$jscomp$1.memoizedProps + ); + instance$jscomp$1.componentDidUpdate( + prevProps$jscomp$0, + current$$1$jscomp$1.memoizedState, + instance$jscomp$1.__reactInternalSnapshotBeforeUpdate + ); + } + var updateQueue$jscomp$0 = currentRef.updateQueue; + null !== updateQueue$jscomp$0 && + commitUpdateQueue( + currentRef, + updateQueue$jscomp$0, + instance$jscomp$1, + updateQueue + ); + break; + case 3: + var _updateQueue = currentRef.updateQueue; + if (null !== _updateQueue) { + lastEffect = null; + if (null !== currentRef.child) + switch (currentRef.child.tag) { + case 5: + lastEffect = currentRef.child.stateNode.canonical; + break; + case 1: + lastEffect = currentRef.child.stateNode; + } + commitUpdateQueue( + currentRef, + _updateQueue, + lastEffect, + updateQueue + ); + } + break; + case 5: + if (null === current$$1$jscomp$1 && currentRef.effectTag & 4) + throw ReactError( + "The current renderer does not support mutation. This error is likely caused by a bug in React. Please file an issue." + ); + break; + case 6: + break; + case 4: + break; + case 12: + var onRender = currentRef.memoizedProps.onRender; + onRender( + currentRef.memoizedProps.id, + null === current$$1$jscomp$1 ? "mount" : "update", + currentRef.actualDuration, + currentRef.treeBaseDuration, + currentRef.actualStartTime, + commitTime, + lastEffect.memoizedInteractions + ); + break; + case 13: + case 17: + break; + case 20: + break; + case 19: + break; + default: + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + } + if (effectTag$jscomp$0 & 128) { + var ref = nextEffect.ref; + if (null !== ref) { + var instance$jscomp$2 = nextEffect.stateNode; + switch (nextEffect.tag) { + case 5: + var instanceToUse = instance$jscomp$2.canonical; + break; + default: + instanceToUse = instance$jscomp$2; + } + "function" === typeof ref + ? ref(instanceToUse) + : (ref.current = instanceToUse); + } + } + effectTag$jscomp$0 & 512 && (rootDoesHavePassiveEffects = !0); + nextEffect = nextEffect.nextEffect; + } + } catch (error) { + if (null === nextEffect) + throw ReactError("Should be working on an effect."); + captureCommitPhaseError(nextEffect, error); + nextEffect = nextEffect.nextEffect; + } + while (null !== nextEffect); + nextEffect = null; + tracing.__interactionsRef.current = childExpirationTimeBeforeCommit; + workPhase = updateExpirationTimeBeforeCommit; + } else (root.current = finishedWork), (commitTime = now$1()); + rootDoesHavePassiveEffects + ? ((rootDoesHavePassiveEffects = !1), + (rootWithPendingPassiveEffects = root), + (pendingPassiveEffectsExpirationTime = expirationTime)) + : finishPendingInteractions(root, expirationTime); + expirationTime = root.firstPendingTime; + 0 !== expirationTime + ? ((effectTag$jscomp$0 = requestCurrentTime()), + (effectTag$jscomp$0 = inferPriorityFromExpirationTime( + effectTag$jscomp$0, + expirationTime + )), + scheduleCallbackForRoot(root, effectTag$jscomp$0, expirationTime)) + : (legacyErrorBoundariesThatAlreadyFailed = null); + "function" === typeof onCommitFiberRoot && + onCommitFiberRoot(finishedWork.stateNode); + 1073741823 === expirationTime + ? root === rootWithNestedUpdates + ? nestedUpdateCount++ + : ((nestedUpdateCount = 0), (rootWithNestedUpdates = root)) + : (nestedUpdateCount = 0); + if (hasUncaughtError) + throw ((hasUncaughtError = !1), + (root = firstUncaughtError), + (firstUncaughtError = null), + root); + if (workPhase === LegacyUnbatchedPhase) return null; + flushImmediateQueue(); + return null; +} +function flushPassiveEffects() { + if (null === rootWithPendingPassiveEffects) return !1; + var root = rootWithPendingPassiveEffects, + expirationTime = pendingPassiveEffectsExpirationTime; + rootWithPendingPassiveEffects = null; + pendingPassiveEffectsExpirationTime = 0; + var prevInteractions = tracing.__interactionsRef.current; + tracing.__interactionsRef.current = root.memoizedInteractions; + if (workPhase === RenderPhase || workPhase === CommitPhase) + throw ReactError("Cannot flush passive effects while already rendering."); + var prevWorkPhase = workPhase; + workPhase = CommitPhase; + for (var effect = root.current.firstEffect; null !== effect; ) { + try { + var finishedWork = effect; + commitHookEffectList(UnmountPassive, NoEffect$1, finishedWork); + commitHookEffectList(NoEffect$1, MountPassive, finishedWork); + } catch (error) { + if (null === effect) throw ReactError("Should be working on an effect."); + captureCommitPhaseError(effect, error); + } + effect = effect.nextEffect; + } + tracing.__interactionsRef.current = prevInteractions; + finishPendingInteractions(root, expirationTime); + workPhase = prevWorkPhase; + flushImmediateQueue(); + return !0; +} +function captureCommitPhaseErrorOnRoot(rootFiber, sourceFiber, error) { + sourceFiber = createCapturedValue(error, sourceFiber); + sourceFiber = createRootErrorUpdate(rootFiber, sourceFiber, 1073741823); + enqueueUpdate(rootFiber, sourceFiber); + rootFiber = markUpdateTimeFromFiberToRoot(rootFiber, 1073741823); + null !== rootFiber && scheduleCallbackForRoot(rootFiber, 99, 1073741823); +} +function captureCommitPhaseError(sourceFiber, error) { + if (3 === sourceFiber.tag) + captureCommitPhaseErrorOnRoot(sourceFiber, sourceFiber, error); + else + for (var fiber = sourceFiber.return; null !== fiber; ) { + if (3 === fiber.tag) { + captureCommitPhaseErrorOnRoot(fiber, sourceFiber, error); + break; + } else if (1 === fiber.tag) { + var instance = fiber.stateNode; + if ( + "function" === typeof fiber.type.getDerivedStateFromError || + ("function" === typeof instance.componentDidCatch && + (null === legacyErrorBoundariesThatAlreadyFailed || + !legacyErrorBoundariesThatAlreadyFailed.has(instance))) + ) { + sourceFiber = createCapturedValue(error, sourceFiber); + sourceFiber = createClassErrorUpdate(fiber, sourceFiber, 1073741823); + enqueueUpdate(fiber, sourceFiber); + fiber = markUpdateTimeFromFiberToRoot(fiber, 1073741823); + null !== fiber && scheduleCallbackForRoot(fiber, 99, 1073741823); + break; + } + } + fiber = fiber.return; + } +} +function pingSuspendedRoot(root, thenable, suspendedTime) { + var pingCache = root.pingCache; + null !== pingCache && pingCache.delete(thenable); + workInProgressRoot === root && renderExpirationTime === suspendedTime + ? prepareFreshStack(root, renderExpirationTime) + : root.lastPendingTime < suspendedTime || + ((thenable = root.pingTime), + (0 !== thenable && thenable < suspendedTime) || + ((root.pingTime = suspendedTime), + (thenable = requestCurrentTime()), + (thenable = inferPriorityFromExpirationTime(thenable, suspendedTime)), + scheduleCallbackForRoot(root, thenable, suspendedTime))); +} +function resolveRetryThenable(boundaryFiber, thenable) { + var retryCache = boundaryFiber.stateNode; + null !== retryCache && retryCache.delete(thenable); + retryCache = requestCurrentTime(); + thenable = computeExpirationForFiber(retryCache, boundaryFiber); + retryCache = inferPriorityFromExpirationTime(retryCache, thenable); + boundaryFiber = markUpdateTimeFromFiberToRoot(boundaryFiber, thenable); + null !== boundaryFiber && + scheduleCallbackForRoot(boundaryFiber, retryCache, thenable); +} +var beginWork$$1 = void 0; +beginWork$$1 = function(current$$1, workInProgress, renderExpirationTime) { + var updateExpirationTime = workInProgress.expirationTime; + if (null !== current$$1) + if ( + current$$1.memoizedProps !== workInProgress.pendingProps || + didPerformWorkStackCursor.current + ) + didReceiveUpdate = !0; + else { + if (updateExpirationTime < renderExpirationTime) { + didReceiveUpdate = !1; + switch (workInProgress.tag) { + case 3: + pushHostRootContext(workInProgress); + break; + case 5: + pushHostContext(workInProgress); + break; + case 1: + isContextProvider(workInProgress.type) && + pushContextProvider(workInProgress); + break; + case 4: + pushHostContainer( + workInProgress, + workInProgress.stateNode.containerInfo + ); + break; + case 10: + pushProvider(workInProgress, workInProgress.memoizedProps.value); + break; + case 12: + workInProgress.effectTag |= 4; + break; + case 13: + if (null !== workInProgress.memoizedState) { + updateExpirationTime = workInProgress.child.childExpirationTime; + if ( + 0 !== updateExpirationTime && + updateExpirationTime >= renderExpirationTime + ) + return updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + workInProgress = bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + return null !== workInProgress ? workInProgress.sibling : null; + } + } + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + } + else didReceiveUpdate = !1; + workInProgress.expirationTime = 0; + switch (workInProgress.tag) { + case 2: + updateExpirationTime = workInProgress.elementType; + null !== current$$1 && + ((current$$1.alternate = null), + (workInProgress.alternate = null), + (workInProgress.effectTag |= 2)); + current$$1 = workInProgress.pendingProps; + var context = getMaskedContext( + workInProgress, + contextStackCursor.current + ); + prepareToReadContext(workInProgress, renderExpirationTime); + context = renderWithHooks( + null, + workInProgress, + updateExpirationTime, + current$$1, + context, + renderExpirationTime + ); + workInProgress.effectTag |= 1; + if ( + "object" === typeof context && + null !== context && + "function" === typeof context.render && + void 0 === context.$$typeof + ) { + workInProgress.tag = 1; + resetHooks(); + if (isContextProvider(updateExpirationTime)) { + var hasContext = !0; + pushContextProvider(workInProgress); + } else hasContext = !1; + workInProgress.memoizedState = + null !== context.state && void 0 !== context.state + ? context.state + : null; + var getDerivedStateFromProps = + updateExpirationTime.getDerivedStateFromProps; + "function" === typeof getDerivedStateFromProps && + applyDerivedStateFromProps( + workInProgress, + updateExpirationTime, + getDerivedStateFromProps, + current$$1 + ); + context.updater = classComponentUpdater; + workInProgress.stateNode = context; + context._reactInternalFiber = workInProgress; + mountClassInstance( + workInProgress, + updateExpirationTime, + current$$1, + renderExpirationTime + ); + workInProgress = finishClassComponent( + null, + workInProgress, + updateExpirationTime, + !0, + hasContext, + renderExpirationTime + ); + } else + (workInProgress.tag = 0), + reconcileChildren( + null, + workInProgress, + context, + renderExpirationTime + ), + (workInProgress = workInProgress.child); + return workInProgress; + case 16: + context = workInProgress.elementType; + null !== current$$1 && + ((current$$1.alternate = null), + (workInProgress.alternate = null), + (workInProgress.effectTag |= 2)); + current$$1 = workInProgress.pendingProps; + context = readLazyComponentType(context); + workInProgress.type = context; + hasContext = workInProgress.tag = resolveLazyComponentTag(context); + current$$1 = resolveDefaultProps(context, current$$1); + switch (hasContext) { + case 0: + workInProgress = updateFunctionComponent( + null, + workInProgress, + context, + current$$1, + renderExpirationTime + ); + break; + case 1: + workInProgress = updateClassComponent( + null, + workInProgress, + context, + current$$1, + renderExpirationTime + ); + break; + case 11: + workInProgress = updateForwardRef( + null, + workInProgress, + context, + current$$1, + renderExpirationTime + ); + break; + case 14: + workInProgress = updateMemoComponent( + null, + workInProgress, + context, + resolveDefaultProps(context.type, current$$1), + updateExpirationTime, + renderExpirationTime + ); + break; + default: + throw ReactError( + "Element type is invalid. Received a promise that resolves to: " + + context + + ". Lazy element type must resolve to a class or function." + ); + } + return workInProgress; + case 0: + return ( + (updateExpirationTime = workInProgress.type), + (context = workInProgress.pendingProps), + (context = + workInProgress.elementType === updateExpirationTime + ? context + : resolveDefaultProps(updateExpirationTime, context)), + updateFunctionComponent( + current$$1, + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ) + ); + case 1: + return ( + (updateExpirationTime = workInProgress.type), + (context = workInProgress.pendingProps), + (context = + workInProgress.elementType === updateExpirationTime + ? context + : resolveDefaultProps(updateExpirationTime, context)), + updateClassComponent( + current$$1, + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ) + ); + case 3: + pushHostRootContext(workInProgress); + updateExpirationTime = workInProgress.updateQueue; + if (null === updateExpirationTime) + throw ReactError( + "If the root does not have an updateQueue, we should have already bailed out. This error is likely caused by a bug in React. Please file an issue." + ); + context = workInProgress.memoizedState; + context = null !== context ? context.element : null; + processUpdateQueue( + workInProgress, + updateExpirationTime, + workInProgress.pendingProps, + null, + renderExpirationTime + ); + updateExpirationTime = workInProgress.memoizedState.element; + updateExpirationTime === context + ? (workInProgress = bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + )) + : (reconcileChildren( + current$$1, + workInProgress, + updateExpirationTime, + renderExpirationTime + ), + (workInProgress = workInProgress.child)); + return workInProgress; + case 5: + return ( + pushHostContext(workInProgress), + null === current$$1 && tryToClaimNextHydratableInstance(workInProgress), + (updateExpirationTime = workInProgress.pendingProps.children), + markRef(current$$1, workInProgress), + reconcileChildren( + current$$1, + workInProgress, + updateExpirationTime, + renderExpirationTime + ), + workInProgress.child + ); + case 6: + return ( + null === current$$1 && tryToClaimNextHydratableInstance(workInProgress), + null + ); + case 13: + return updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + case 4: + return ( + pushHostContainer( + workInProgress, + workInProgress.stateNode.containerInfo + ), + (updateExpirationTime = workInProgress.pendingProps), + null === current$$1 + ? (workInProgress.child = reconcileChildFibers( + workInProgress, + null, + updateExpirationTime, + renderExpirationTime + )) + : reconcileChildren( + current$$1, + workInProgress, + updateExpirationTime, + renderExpirationTime + ), + workInProgress.child + ); + case 11: + return ( + (updateExpirationTime = workInProgress.type), + (context = workInProgress.pendingProps), + (context = + workInProgress.elementType === updateExpirationTime + ? context + : resolveDefaultProps(updateExpirationTime, context)), + updateForwardRef( + current$$1, + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ) + ); + case 7: + return ( + reconcileChildren( + current$$1, + workInProgress, + workInProgress.pendingProps, + renderExpirationTime + ), + workInProgress.child + ); + case 8: + return ( + reconcileChildren( + current$$1, + workInProgress, + workInProgress.pendingProps.children, + renderExpirationTime + ), + workInProgress.child + ); + case 12: + return ( + (workInProgress.effectTag |= 4), + reconcileChildren( + current$$1, + workInProgress, + workInProgress.pendingProps.children, + renderExpirationTime + ), + workInProgress.child + ); + case 10: + a: { + updateExpirationTime = workInProgress.type._context; + context = workInProgress.pendingProps; + getDerivedStateFromProps = workInProgress.memoizedProps; + hasContext = context.value; + pushProvider(workInProgress, hasContext); + if (null !== getDerivedStateFromProps) { + var oldValue = getDerivedStateFromProps.value; + hasContext = is(oldValue, hasContext) + ? 0 + : ("function" === typeof updateExpirationTime._calculateChangedBits + ? updateExpirationTime._calculateChangedBits( + oldValue, + hasContext + ) + : 1073741823) | 0; + if (0 === hasContext) { + if ( + getDerivedStateFromProps.children === context.children && + !didPerformWorkStackCursor.current + ) { + workInProgress = bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + break a; + } + } else + for ( + oldValue = workInProgress.child, + null !== oldValue && (oldValue.return = workInProgress); + null !== oldValue; + + ) { + var list = oldValue.contextDependencies; + if (null !== list) { + getDerivedStateFromProps = oldValue.child; + for (var dependency = list.first; null !== dependency; ) { + if ( + dependency.context === updateExpirationTime && + 0 !== (dependency.observedBits & hasContext) + ) { + 1 === oldValue.tag && + ((dependency = createUpdate(renderExpirationTime)), + (dependency.tag = 2), + enqueueUpdate(oldValue, dependency)); + oldValue.expirationTime < renderExpirationTime && + (oldValue.expirationTime = renderExpirationTime); + dependency = oldValue.alternate; + null !== dependency && + dependency.expirationTime < renderExpirationTime && + (dependency.expirationTime = renderExpirationTime); + dependency = renderExpirationTime; + for (var node = oldValue.return; null !== node; ) { + var alternate = node.alternate; + if (node.childExpirationTime < dependency) + (node.childExpirationTime = dependency), + null !== alternate && + alternate.childExpirationTime < dependency && + (alternate.childExpirationTime = dependency); + else if ( + null !== alternate && + alternate.childExpirationTime < dependency + ) + alternate.childExpirationTime = dependency; + else break; + node = node.return; + } + list.expirationTime < renderExpirationTime && + (list.expirationTime = renderExpirationTime); + break; + } + dependency = dependency.next; + } + } else + getDerivedStateFromProps = + 10 === oldValue.tag + ? oldValue.type === workInProgress.type + ? null + : oldValue.child + : oldValue.child; + if (null !== getDerivedStateFromProps) + getDerivedStateFromProps.return = oldValue; + else + for ( + getDerivedStateFromProps = oldValue; + null !== getDerivedStateFromProps; + + ) { + if (getDerivedStateFromProps === workInProgress) { + getDerivedStateFromProps = null; + break; + } + oldValue = getDerivedStateFromProps.sibling; + if (null !== oldValue) { + oldValue.return = getDerivedStateFromProps.return; + getDerivedStateFromProps = oldValue; + break; + } + getDerivedStateFromProps = getDerivedStateFromProps.return; + } + oldValue = getDerivedStateFromProps; + } + } + reconcileChildren( + current$$1, + workInProgress, + context.children, + renderExpirationTime + ); + workInProgress = workInProgress.child; + } + return workInProgress; + case 9: + return ( + (context = workInProgress.type), + (hasContext = workInProgress.pendingProps), + (updateExpirationTime = hasContext.children), + prepareToReadContext(workInProgress, renderExpirationTime), + (context = readContext(context, hasContext.unstable_observedBits)), + (updateExpirationTime = updateExpirationTime(context)), + (workInProgress.effectTag |= 1), + reconcileChildren( + current$$1, + workInProgress, + updateExpirationTime, + renderExpirationTime + ), + workInProgress.child + ); + case 14: + return ( + (context = workInProgress.type), + (hasContext = resolveDefaultProps( + context, + workInProgress.pendingProps + )), + (hasContext = resolveDefaultProps(context.type, hasContext)), + updateMemoComponent( + current$$1, + workInProgress, + context, + hasContext, + updateExpirationTime, + renderExpirationTime + ) + ); + case 15: + return updateSimpleMemoComponent( + current$$1, + workInProgress, + workInProgress.type, + workInProgress.pendingProps, + updateExpirationTime, + renderExpirationTime + ); + case 17: + return ( + (updateExpirationTime = workInProgress.type), + (context = workInProgress.pendingProps), + (context = + workInProgress.elementType === updateExpirationTime + ? context + : resolveDefaultProps(updateExpirationTime, context)), + null !== current$$1 && + ((current$$1.alternate = null), + (workInProgress.alternate = null), + (workInProgress.effectTag |= 2)), + (workInProgress.tag = 1), + isContextProvider(updateExpirationTime) + ? ((current$$1 = !0), pushContextProvider(workInProgress)) + : (current$$1 = !1), + prepareToReadContext(workInProgress, renderExpirationTime), + constructClassInstance( + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ), + mountClassInstance( + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ), + finishClassComponent( + null, + workInProgress, + updateExpirationTime, + !0, + current$$1, + renderExpirationTime + ) + ); + } + throw ReactError( + "Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue." + ); +}; +function schedulePendingInteraction(root, expirationTime) { + var interactions = tracing.__interactionsRef.current; + if (0 < interactions.size) { + var pendingInteractionMap = root.pendingInteractionMap, + pendingInteractions = pendingInteractionMap.get(expirationTime); + null != pendingInteractions + ? interactions.forEach(function(interaction) { + pendingInteractions.has(interaction) || interaction.__count++; + pendingInteractions.add(interaction); + }) + : (pendingInteractionMap.set(expirationTime, new Set(interactions)), + interactions.forEach(function(interaction) { + interaction.__count++; + })); + pendingInteractionMap = tracing.__subscriberRef.current; + if (null !== pendingInteractionMap) + pendingInteractionMap.onWorkScheduled( + interactions, + 1e3 * expirationTime + root.interactionThreadID + ); + } +} +function startWorkOnPendingInteraction(root, expirationTime) { + var interactions = new Set(); + root.pendingInteractionMap.forEach(function( + scheduledInteractions, + scheduledExpirationTime + ) { + scheduledExpirationTime >= expirationTime && + scheduledInteractions.forEach(function(interaction) { + return interactions.add(interaction); + }); + }); + root.memoizedInteractions = interactions; + if (0 < interactions.size) { + var subscriber = tracing.__subscriberRef.current; + if (null !== subscriber) { + root = 1e3 * expirationTime + root.interactionThreadID; + try { + subscriber.onWorkStarted(interactions, root); + } catch (error) { + scheduleCallback(99, function() { + throw error; + }); + } + } + } +} +function finishPendingInteractions(root, committedExpirationTime) { + var earliestRemainingTimeAfterCommit = root.firstPendingTime, + subscriber = void 0; + try { + if ( + ((subscriber = tracing.__subscriberRef.current), + null !== subscriber && 0 < root.memoizedInteractions.size) + ) + subscriber.onWorkStopped( + root.memoizedInteractions, + 1e3 * committedExpirationTime + root.interactionThreadID + ); + } catch (error) { + scheduleCallback(99, function() { + throw error; + }); + } finally { + var pendingInteractionMap = root.pendingInteractionMap; + pendingInteractionMap.forEach(function( + scheduledInteractions, + scheduledExpirationTime + ) { + scheduledExpirationTime > earliestRemainingTimeAfterCommit && + (pendingInteractionMap.delete(scheduledExpirationTime), + scheduledInteractions.forEach(function(interaction) { + interaction.__count--; + if (null !== subscriber && 0 === interaction.__count) + try { + subscriber.onInteractionScheduledWorkCompleted(interaction); + } catch (error) { + scheduleCallback(99, function() { + throw error; + }); + } + })); + }); + } +} +function findHostInstance(component) { + var fiber = component._reactInternalFiber; + if (void 0 === fiber) { + if ("function" === typeof component.render) + throw ReactError("Unable to find node on an unmounted component."); + throw ReactError( + "Argument appears to not be a ReactComponent. Keys: " + + Object.keys(component) + ); + } + component = findCurrentHostFiber(fiber); + return null === component ? null : component.stateNode; +} +function updateContainer(element, container, parentComponent, callback) { + var current$$1 = container.current, + currentTime = requestCurrentTime(); + current$$1 = computeExpirationForFiber(currentTime, current$$1); + currentTime = container.current; + a: if (parentComponent) { + parentComponent = parentComponent._reactInternalFiber; + b: { + if ( + 2 !== isFiberMountedImpl(parentComponent) || + 1 !== parentComponent.tag + ) + throw ReactError( + "Expected subtree parent to be a mounted class component. This error is likely caused by a bug in React. Please file an issue." + ); + var parentContext = parentComponent; + do { + switch (parentContext.tag) { + case 3: + parentContext = parentContext.stateNode.context; + break b; + case 1: + if (isContextProvider(parentContext.type)) { + parentContext = + parentContext.stateNode + .__reactInternalMemoizedMergedChildContext; + break b; + } + } + parentContext = parentContext.return; + } while (null !== parentContext); + throw ReactError( + "Found unexpected detached subtree parent. This error is likely caused by a bug in React. Please file an issue." + ); + } + if (1 === parentComponent.tag) { + var Component = parentComponent.type; + if (isContextProvider(Component)) { + parentComponent = processChildContext( + parentComponent, + Component, + parentContext + ); + break a; + } + } + parentComponent = parentContext; + } else parentComponent = emptyContextObject; + null === container.context + ? (container.context = parentComponent) + : (container.pendingContext = parentComponent); + container = callback; + callback = createUpdate(current$$1); + callback.payload = { element: element }; + container = void 0 === container ? null : container; + null !== container && (callback.callback = container); + flushPassiveEffects(); + enqueueUpdate(currentTime, callback); + scheduleUpdateOnFiber(currentTime, current$$1); + return current$$1; +} +function createPortal(children, containerInfo, implementation) { + var key = + 3 < arguments.length && void 0 !== arguments[3] ? arguments[3] : null; + return { + $$typeof: REACT_PORTAL_TYPE, + key: null == key ? null : "" + key, + children: children, + containerInfo: containerInfo, + implementation: implementation + }; +} +function _inherits(subClass, superClass) { + if ("function" !== typeof superClass && null !== superClass) + throw new TypeError( + "Super expression must either be null or a function, not " + + typeof superClass + ); + subClass.prototype = Object.create(superClass && superClass.prototype, { + constructor: { + value: subClass, + enumerable: !1, + writable: !0, + configurable: !0 + } + }); + superClass && + (Object.setPrototypeOf + ? Object.setPrototypeOf(subClass, superClass) + : (subClass.__proto__ = superClass)); +} +var getInspectorDataForViewTag = void 0; +getInspectorDataForViewTag = function() { + throw ReactError( + "getInspectorDataForViewTag() is not available in production" + ); +}; +function findNodeHandle(componentOrHandle) { + if (null == componentOrHandle) return null; + if ("number" === typeof componentOrHandle) return componentOrHandle; + if (componentOrHandle._nativeTag) return componentOrHandle._nativeTag; + if (componentOrHandle.canonical && componentOrHandle.canonical._nativeTag) + return componentOrHandle.canonical._nativeTag; + componentOrHandle = findHostInstance(componentOrHandle); + return null == componentOrHandle + ? componentOrHandle + : componentOrHandle.canonical + ? componentOrHandle.canonical._nativeTag + : componentOrHandle._nativeTag; +} +_batchedUpdatesImpl = function(fn, a) { + if (0 !== workPhase) return fn(a); + workPhase = 1; + try { + return fn(a); + } finally { + (workPhase = 0), flushImmediateQueue(); + } +}; +_flushInteractiveUpdatesImpl = function() { + workPhase !== RenderPhase && + workPhase !== CommitPhase && + flushPendingDiscreteUpdates(); +}; +var roots = new Map(), + ReactFabric = { + NativeComponent: (function(findNodeHandle, findHostInstance) { + return (function(_React$Component) { + function ReactNativeComponent() { + if (!(this instanceof ReactNativeComponent)) + throw new TypeError("Cannot call a class as a function"); + var call = _React$Component.apply(this, arguments); + if (!this) + throw new ReferenceError( + "this hasn't been initialised - super() hasn't been called" + ); + return !call || + ("object" !== typeof call && "function" !== typeof call) + ? this + : call; + } + _inherits(ReactNativeComponent, _React$Component); + ReactNativeComponent.prototype.blur = function() { + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); + }; + ReactNativeComponent.prototype.focus = function() { + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); + }; + ReactNativeComponent.prototype.measure = function(callback) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null != maybeInstance && + (maybeInstance.canonical + ? nativeFabricUIManager.measure( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ) + : ReactNativePrivateInterface.UIManager.measure( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + )); + }; + ReactNativeComponent.prototype.measureInWindow = function(callback) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null != maybeInstance && + (maybeInstance.canonical + ? nativeFabricUIManager.measureInWindow( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ) + : ReactNativePrivateInterface.UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + )); + }; + ReactNativeComponent.prototype.measureLayout = function( + relativeToNativeNode, + onSuccess, + onFail + ) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null == maybeInstance || + maybeInstance.canonical || + ((maybeInstance = void 0), + "number" === typeof relativeToNativeNode + ? (maybeInstance = relativeToNativeNode) + : relativeToNativeNode._nativeTag && + (maybeInstance = relativeToNativeNode._nativeTag), + null != maybeInstance && + ReactNativePrivateInterface.UIManager.measureLayout( + findNodeHandle(this), + maybeInstance, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + )); + }; + ReactNativeComponent.prototype.setNativeProps = function(nativeProps) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + if (null != maybeInstance && !maybeInstance.canonical) { + var nativeTag = + maybeInstance._nativeTag || maybeInstance.canonical._nativeTag; + maybeInstance = + maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; + nativeProps = diffProperties( + null, + emptyObject, + nativeProps, + maybeInstance.validAttributes + ); + null != nativeProps && + ReactNativePrivateInterface.UIManager.updateView( + nativeTag, + maybeInstance.uiViewClassName, + nativeProps + ); + } + }; + return ReactNativeComponent; + })(React.Component); + })(findNodeHandle, findHostInstance), + findNodeHandle: findNodeHandle, + setNativeProps: function() {}, + render: function(element, containerTag, callback) { + var root = roots.get(containerTag); + if (!root) { + root = new FiberRootNode(containerTag, !1); + var uninitializedFiber = 0; + isDevToolsPresent && (uninitializedFiber |= 4); + uninitializedFiber = createFiber(3, null, null, uninitializedFiber); + root.current = uninitializedFiber; + uninitializedFiber.stateNode = root; + roots.set(containerTag, root); + } + updateContainer(element, root, null, callback); + a: if (((element = root.current), element.child)) + switch (element.child.tag) { + case 5: + element = element.child.stateNode.canonical; + break a; + default: + element = element.child.stateNode; + } + else element = null; + return element; + }, + unmountComponentAtNode: function(containerTag) { + var root = roots.get(containerTag); + root && + updateContainer(null, root, null, function() { + roots.delete(containerTag); + }); + }, + createPortal: function(children, containerTag) { + return createPortal( + children, + containerTag, + null, + 2 < arguments.length && void 0 !== arguments[2] ? arguments[2] : null + ); + }, + __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { + NativeMethodsMixin: (function(findNodeHandle, findHostInstance) { + return { + measure: function(callback) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null != maybeInstance && + (maybeInstance.canonical + ? nativeFabricUIManager.measure( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ) + : ReactNativePrivateInterface.UIManager.measure( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + )); + }, + measureInWindow: function(callback) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null != maybeInstance && + (maybeInstance.canonical + ? nativeFabricUIManager.measureInWindow( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ) + : ReactNativePrivateInterface.UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + )); + }, + measureLayout: function(relativeToNativeNode, onSuccess, onFail) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null == maybeInstance || + maybeInstance.canonical || + ((maybeInstance = void 0), + "number" === typeof relativeToNativeNode + ? (maybeInstance = relativeToNativeNode) + : relativeToNativeNode._nativeTag && + (maybeInstance = relativeToNativeNode._nativeTag), + null != maybeInstance && + ReactNativePrivateInterface.UIManager.measureLayout( + findNodeHandle(this), + maybeInstance, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + )); + }, + setNativeProps: function(nativeProps) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + if (null != maybeInstance && !maybeInstance.canonical) { + var nativeTag = + maybeInstance._nativeTag || maybeInstance.canonical._nativeTag; + maybeInstance = + maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; + nativeProps = diffProperties( + null, + emptyObject, + nativeProps, + maybeInstance.validAttributes + ); + null != nativeProps && + ReactNativePrivateInterface.UIManager.updateView( + nativeTag, + maybeInstance.uiViewClassName, + nativeProps + ); + } + }, + focus: function() { + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); + }, + blur: function() { + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); + } + }; + })(findNodeHandle, findHostInstance) + } + }; +(function(devToolsConfig) { + var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; + return injectInternals( + Object.assign({}, devToolsConfig, { + overrideHookState: null, + overrideProps: null, + setSuspenseHandler: null, + scheduleUpdate: null, + currentDispatcherRef: ReactSharedInternals.ReactCurrentDispatcher, + findHostInstanceByFiber: function(fiber) { + fiber = findCurrentHostFiber(fiber); + return null === fiber ? null : fiber.stateNode; + }, + findFiberByHostInstance: function(instance) { + return findFiberByHostInstance + ? findFiberByHostInstance(instance) + : null; + } + }) + ); +})({ + findFiberByHostInstance: getInstanceFromInstance, + getInspectorDataForViewTag: getInspectorDataForViewTag, + bundleType: 0, + version: "16.8.6", + rendererPackageName: "react-native-renderer" +}); +var ReactFabric$2 = { default: ReactFabric }, + ReactFabric$3 = (ReactFabric$2 && ReactFabric) || ReactFabric$2; +module.exports = ReactFabric$3.default || ReactFabric$3; diff --git a/Libraries/Renderer/oss/ReactFabric-profiling.js b/Libraries/Renderer/implementations/ReactFabric-profiling.js similarity index 98% rename from Libraries/Renderer/oss/ReactFabric-profiling.js rename to Libraries/Renderer/implementations/ReactFabric-profiling.js index 74761df873a15f..9cd8fe74bcf731 100644 --- a/Libraries/Renderer/oss/ReactFabric-profiling.js +++ b/Libraries/Renderer/implementations/ReactFabric-profiling.js @@ -11,17 +11,11 @@ */ "use strict"; -require("InitializeCore"); -var ReactNativeViewConfigRegistry = require("ReactNativeViewConfigRegistry"), - UIManager = require("UIManager"), +require("react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore"); +var ReactNativePrivateInterface = require("react-native/Libraries/ReactPrivate/ReactNativePrivateInterface"), React = require("react"), - deepDiffer = require("deepDiffer"), - flattenStyle = require("flattenStyle"), - TextInputState = require("TextInputState"), - FabricUIManager = require("FabricUIManager"), Scheduler = require("scheduler"), - tracing = require("scheduler/tracing"), - ExceptionsManager = require("ExceptionsManager"); + tracing = require("scheduler/tracing"); function ReactError(message) { message = Error(message); message.name = "Invariant Violation"; @@ -618,7 +612,7 @@ function changeResponder(nextResponderInst, blockHostResponder) { blockHostResponder ); } -var eventTypes$1 = { +var eventTypes = { startShouldSetResponder: { phasedRegistrationNames: { bubbled: "onStartShouldSetResponder", @@ -681,7 +675,7 @@ var eventTypes$1 = { _getResponder: function() { return responderInst; }, - eventTypes: eventTypes$1, + eventTypes: eventTypes, extractEvents: function( topLevelType, targetInst, @@ -710,12 +704,12 @@ var eventTypes$1 = { isMoveish(topLevelType)) ) { var JSCompiler_temp = isStartish(topLevelType) - ? eventTypes$1.startShouldSetResponder + ? eventTypes.startShouldSetResponder : isMoveish(topLevelType) - ? eventTypes$1.moveShouldSetResponder + ? eventTypes.moveShouldSetResponder : "topSelectionChange" === topLevelType - ? eventTypes$1.selectionChangeShouldSetResponder - : eventTypes$1.scrollShouldSetResponder; + ? eventTypes.selectionChangeShouldSetResponder + : eventTypes.scrollShouldSetResponder; if (responderInst) b: { var JSCompiler_temp$jscomp$0 = responderInst; @@ -801,7 +795,7 @@ var eventTypes$1 = { JSCompiler_temp && JSCompiler_temp !== responderInst ? ((JSCompiler_temp$jscomp$0 = void 0), (targetInst = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderGrant, + eventTypes.responderGrant, JSCompiler_temp, nativeEvent, nativeEventTarget @@ -811,7 +805,7 @@ var eventTypes$1 = { (depthA = !0 === executeDirectDispatch(targetInst)), responderInst ? ((tempA = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderTerminationRequest, + eventTypes.responderTerminationRequest, responderInst, nativeEvent, nativeEventTarget @@ -823,7 +817,7 @@ var eventTypes$1 = { tempA.isPersistent() || tempA.constructor.release(tempA), tempB ? ((tempA = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderTerminate, + eventTypes.responderTerminate, responderInst, nativeEvent, nativeEventTarget @@ -837,7 +831,7 @@ var eventTypes$1 = { )), changeResponder(JSCompiler_temp, depthA)) : ((JSCompiler_temp = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderReject, + eventTypes.responderReject, JSCompiler_temp, nativeEvent, nativeEventTarget @@ -867,11 +861,11 @@ var eventTypes$1 = { ("topTouchEnd" === topLevelType || "topTouchCancel" === topLevelType); if ( (JSCompiler_temp$jscomp$0 = JSCompiler_temp$jscomp$0 - ? eventTypes$1.responderStart + ? eventTypes.responderStart : targetInst - ? eventTypes$1.responderMove + ? eventTypes.responderMove : depthA - ? eventTypes$1.responderEnd + ? eventTypes.responderEnd : null) ) (JSCompiler_temp$jscomp$0 = ResponderSyntheticEvent.getPooled( @@ -925,9 +919,9 @@ var eventTypes$1 = { } if ( (topLevelType = JSCompiler_temp$jscomp$0 - ? eventTypes$1.responderTerminate + ? eventTypes.responderTerminate : topLevelType - ? eventTypes$1.responderRelease + ? eventTypes.responderRelease : null) ) (nativeEvent = ResponderSyntheticEvent.getPooled( @@ -949,8 +943,15 @@ var eventTypes$1 = { } } }, + customBubblingEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customBubblingEventTypes, + customDirectEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customDirectEventTypes, ReactNativeBridgeEventPlugin = { - eventTypes: ReactNativeViewConfigRegistry.eventTypes, + eventTypes: + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes, extractEvents: function( topLevelType, targetInst, @@ -958,10 +959,8 @@ var eventTypes$1 = { nativeEventTarget ) { if (null == targetInst) return null; - var bubbleDispatchConfig = - ReactNativeViewConfigRegistry.customBubblingEventTypes[topLevelType], - directDispatchConfig = - ReactNativeViewConfigRegistry.customDirectEventTypes[topLevelType]; + var bubbleDispatchConfig = customBubblingEventTypes[topLevelType], + directDispatchConfig = customDirectEventTypes[topLevelType]; if (!bubbleDispatchConfig && !directDispatchConfig) throw ReactError( 'Unsupported top level event type "' + topLevelType + '" dispatched' @@ -1003,11 +1002,11 @@ getNodeFromInstance = function(inst) { ResponderEventPlugin.injection.injectGlobalResponderHandler({ onChange: function(from, to, blockNativeResponder) { null !== to - ? UIManager.setJSResponder( + ? ReactNativePrivateInterface.UIManager.setJSResponder( to.stateNode.canonical._nativeTag, blockNativeResponder ) - : UIManager.clearJSResponder(); + : ReactNativePrivateInterface.UIManager.clearJSResponder(); } }); var ReactSharedInternals = @@ -1280,14 +1279,14 @@ function diffNestedProperty( return Array.isArray(prevProp) ? diffProperties( updatePayload, - flattenStyle(prevProp), + ReactNativePrivateInterface.flattenStyle(prevProp), nextProp, validAttributes ) : diffProperties( updatePayload, prevProp, - flattenStyle(nextProp), + ReactNativePrivateInterface.flattenStyle(nextProp), validAttributes ); } @@ -1355,7 +1354,7 @@ function diffProperties(updatePayload, prevProps, nextProps, validAttributes) { if ("object" !== typeof attributeConfig) ("object" !== typeof nextProp || null === nextProp || - deepDiffer(prevProp, nextProp)) && + ReactNativePrivateInterface.deepDiffer(prevProp, nextProp)) && ((updatePayload || (updatePayload = {}))[propKey] = nextProp); else if ( "function" === typeof attributeConfig.diff || @@ -1367,7 +1366,7 @@ function diffProperties(updatePayload, prevProps, nextProps, validAttributes) { ? attributeConfig.diff(prevProp, nextProp) : "object" !== typeof nextProp || null === nextProp || - deepDiffer(prevProp, nextProp)) + ReactNativePrivateInterface.deepDiffer(prevProp, nextProp)) ) (attributeConfig = "function" === typeof attributeConfig.process @@ -1484,9 +1483,25 @@ function shim$1() { "The current renderer does not support hydration. This error is likely caused by a bug in React. Please file an issue." ); } -var nextReactTag = 2; -FabricUIManager.registerEventHandler && - FabricUIManager.registerEventHandler(dispatchEvent); +var _nativeFabricUIManage = nativeFabricUIManager, + createNode = _nativeFabricUIManage.createNode, + cloneNode = _nativeFabricUIManage.cloneNode, + cloneNodeWithNewChildren = _nativeFabricUIManage.cloneNodeWithNewChildren, + cloneNodeWithNewChildrenAndProps = + _nativeFabricUIManage.cloneNodeWithNewChildrenAndProps, + cloneNodeWithNewProps = _nativeFabricUIManage.cloneNodeWithNewProps, + createChildNodeSet = _nativeFabricUIManage.createChildSet, + appendChildNode = _nativeFabricUIManage.appendChild, + appendChildNodeToSet = _nativeFabricUIManage.appendChildToSet, + completeRoot = _nativeFabricUIManage.completeRoot, + registerEventHandler = _nativeFabricUIManage.registerEventHandler, + fabricMeasure = _nativeFabricUIManage.measure, + fabricMeasureInWindow = _nativeFabricUIManage.measureInWindow, + fabricMeasureLayout = _nativeFabricUIManage.measureLayout, + getViewConfigForType = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.get, + nextReactTag = 2; +registerEventHandler && registerEventHandler(dispatchEvent); var ReactFabricHostComponent = (function() { function ReactFabricHostComponent( tag, @@ -1502,19 +1517,19 @@ var ReactFabricHostComponent = (function() { this._internalInstanceHandle = internalInstanceHandle; } ReactFabricHostComponent.prototype.blur = function() { - TextInputState.blurTextInput(this._nativeTag); + ReactNativePrivateInterface.TextInputState.blurTextInput(this._nativeTag); }; ReactFabricHostComponent.prototype.focus = function() { - TextInputState.focusTextInput(this._nativeTag); + ReactNativePrivateInterface.TextInputState.focusTextInput(this._nativeTag); }; ReactFabricHostComponent.prototype.measure = function(callback) { - FabricUIManager.measure( + fabricMeasure( this._internalInstanceHandle.stateNode.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); }; ReactFabricHostComponent.prototype.measureInWindow = function(callback) { - FabricUIManager.measureInWindow( + fabricMeasureInWindow( this._internalInstanceHandle.stateNode.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); @@ -1526,7 +1541,7 @@ var ReactFabricHostComponent = (function() { ) { "number" !== typeof relativeToNativeNode && relativeToNativeNode instanceof ReactFabricHostComponent && - FabricUIManager.measureLayout( + fabricMeasureLayout( this._internalInstanceHandle.stateNode.node, relativeToNativeNode._internalInstanceHandle.stateNode.node, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -1549,7 +1564,7 @@ function createTextInstance( hostContext = nextReactTag; nextReactTag += 2; return { - node: FabricUIManager.createNode( + node: createNode( hostContext, "RCTRawText", rootContainerInstance, @@ -1569,7 +1584,7 @@ function cloneHiddenInstance(instance) { instance.canonical.viewConfig.validAttributes ); return { - node: FabricUIManager.cloneNodeWithNewProps(node, updatePayload), + node: cloneNodeWithNewProps(node, updatePayload), canonical: instance.canonical }; } @@ -4526,12 +4541,12 @@ appendAllChildren = function( node.memoizedProps, node )); - FabricUIManager.appendChild(parent.node, instance.node); + appendChildNode(parent.node, instance.node); } else if (6 === node.tag) { instance = node.stateNode; if (needsVisibilityToggle && isHidden) throw Error("Not yet implemented."); - FabricUIManager.appendChild(parent.node, instance.node); + appendChildNode(parent.node, instance.node); } else if (4 !== node.tag) { if ( 13 === node.tag && @@ -4584,12 +4599,12 @@ function appendAllChildrenToContainer( node.memoizedProps, node )); - FabricUIManager.appendChildToSet(containerChildSet, instance.node); + appendChildNodeToSet(containerChildSet, instance.node); } else if (6 === node.tag) { instance = node.stateNode; if (needsVisibilityToggle && isHidden) throw Error("Not yet implemented."); - FabricUIManager.appendChildToSet(containerChildSet, instance.node); + appendChildNodeToSet(containerChildSet, instance.node); } else if (4 !== node.tag) { if ( 13 === node.tag && @@ -4634,11 +4649,11 @@ updateHostContainer = function(workInProgress) { var portalOrRoot = workInProgress.stateNode; if (null !== workInProgress.firstEffect) { var container = portalOrRoot.containerInfo, - newChildSet = FabricUIManager.createChildSet(container); + newChildSet = createChildNodeSet(container); appendAllChildrenToContainer(newChildSet, workInProgress, !1, !1); portalOrRoot.pendingChildren = newChildSet; workInProgress.effectTag |= 4; - FabricUIManager.completeRoot(container, newChildSet); + completeRoot(container, newChildSet); } }; updateHostComponent$1 = function(current, workInProgress, type, newProps) { @@ -4666,17 +4681,11 @@ updateHostComponent$1 = function(current, workInProgress, type, newProps) { (type = { node: current ? null !== newProps - ? FabricUIManager.cloneNodeWithNewProps( - recyclableInstance, - newProps - ) - : FabricUIManager.cloneNode(recyclableInstance) + ? cloneNodeWithNewProps(recyclableInstance, newProps) + : cloneNode(recyclableInstance) : null !== newProps - ? FabricUIManager.cloneNodeWithNewChildrenAndProps( - recyclableInstance, - newProps - ) - : FabricUIManager.cloneNodeWithNewChildren(recyclableInstance), + ? cloneNodeWithNewChildrenAndProps(recyclableInstance, newProps) + : cloneNodeWithNewChildren(recyclableInstance), canonical: type.canonical }), (workInProgress.stateNode = type), @@ -4739,14 +4748,14 @@ function completeWork(current, workInProgress, renderExpirationTime) { requiredContext(contextStackCursor$1.current); current = nextReactTag; nextReactTag += 2; - type = ReactNativeViewConfigRegistry.get(type); + type = getViewConfigForType(type); var updatePayload = diffProperties( null, emptyObject, newProps, type.validAttributes ); - renderExpirationTime = FabricUIManager.createNode( + renderExpirationTime = createNode( current, type.uiViewClassName, renderExpirationTime, @@ -4882,7 +4891,7 @@ function logCapturedError(capturedError) { "string" === typeof error ? Error(error + "\n\nThis error is located at:" + componentStack) : Error("Unspecified error at:" + componentStack); - ExceptionsManager.handleException(error, !1); + ReactNativePrivateInterface.ExceptionsManager.handleException(error, !1); } var PossiblyWeakSet$1 = "function" === typeof WeakSet ? WeakSet : Set; function logError(boundary, errorInfo) { @@ -5861,9 +5870,7 @@ function commitRootImpl(root, expirationTime) { safelyDetachRef(instance); break; case 4: - FabricUIManager.createChildSet( - instance.stateNode.containerInfo - ); + createChildNodeSet(instance.stateNode.containerInfo); } if (null !== prevState.child) (prevState.child.return = prevState), @@ -6947,10 +6954,14 @@ var roots = new Map(), } _inherits(ReactNativeComponent, _React$Component); ReactNativeComponent.prototype.blur = function() { - TextInputState.blurTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); }; ReactNativeComponent.prototype.focus = function() { - TextInputState.focusTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); }; ReactNativeComponent.prototype.measure = function(callback) { var maybeInstance = void 0; @@ -6963,7 +6974,7 @@ var roots = new Map(), maybeInstance.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ) - : UIManager.measure( + : ReactNativePrivateInterface.UIManager.measure( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) )); @@ -6979,7 +6990,7 @@ var roots = new Map(), maybeInstance.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ) - : UIManager.measureInWindow( + : ReactNativePrivateInterface.UIManager.measureInWindow( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) )); @@ -7001,7 +7012,7 @@ var roots = new Map(), : relativeToNativeNode._nativeTag && (maybeInstance = relativeToNativeNode._nativeTag), null != maybeInstance && - UIManager.measureLayout( + ReactNativePrivateInterface.UIManager.measureLayout( findNodeHandle(this), maybeInstance, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -7025,7 +7036,7 @@ var roots = new Map(), maybeInstance.validAttributes ); null != nativeProps && - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( nativeTag, maybeInstance.uiViewClassName, nativeProps @@ -7089,7 +7100,7 @@ var roots = new Map(), maybeInstance.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ) - : UIManager.measure( + : ReactNativePrivateInterface.UIManager.measure( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) )); @@ -7105,7 +7116,7 @@ var roots = new Map(), maybeInstance.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ) - : UIManager.measureInWindow( + : ReactNativePrivateInterface.UIManager.measureInWindow( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) )); @@ -7123,7 +7134,7 @@ var roots = new Map(), : relativeToNativeNode._nativeTag && (maybeInstance = relativeToNativeNode._nativeTag), null != maybeInstance && - UIManager.measureLayout( + ReactNativePrivateInterface.UIManager.measureLayout( findNodeHandle(this), maybeInstance, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -7147,7 +7158,7 @@ var roots = new Map(), maybeInstance.validAttributes ); null != nativeProps && - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( nativeTag, maybeInstance.uiViewClassName, nativeProps @@ -7155,10 +7166,14 @@ var roots = new Map(), } }, focus: function() { - TextInputState.focusTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); }, blur: function() { - TextInputState.blurTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); } }; })(findNodeHandle, findHostInstance) diff --git a/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js b/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js new file mode 100644 index 00000000000000..d6da48c340b9b9 --- /dev/null +++ b/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js @@ -0,0 +1,20167 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @noflow + * @preventMunge + * @generated + */ + +'use strict'; + +if (__DEV__) { + (function() { +"use strict"; + +require("react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore"); +var ReactNativePrivateInterface = require("react-native/Libraries/ReactPrivate/ReactNativePrivateInterface"); +var React = require("react"); +var checkPropTypes = require("prop-types/checkPropTypes"); +var Scheduler = require("scheduler"); +var tracing = require("scheduler/tracing"); + +// Do not require this module directly! Use a normal error constructor with +// template literal strings. The messages will be converted to ReactError during +// build, and in production they will be minified. + +function ReactError(message) { + var error = new Error(message); + error.name = "Invariant Violation"; + return error; +} + +/** + * Use invariant() to assert state which your program assumes to be true. + * + * Provide sprintf-style format (only %s is supported) and arguments + * to provide information about what broke and what you were + * expecting. + * + * The invariant message will be stripped in production, but the invariant + * will remain to ensure logic does not differ in production. + */ + +/** + * Injectable ordering of event plugins. + */ +var eventPluginOrder = null; + +/** + * Injectable mapping from names to event plugin modules. + */ +var namesToPlugins = {}; + +/** + * Recomputes the plugin list using the injected plugins and plugin ordering. + * + * @private + */ +function recomputePluginOrdering() { + if (!eventPluginOrder) { + // Wait until an `eventPluginOrder` is injected. + return; + } + for (var pluginName in namesToPlugins) { + var pluginModule = namesToPlugins[pluginName]; + var pluginIndex = eventPluginOrder.indexOf(pluginName); + (function() { + if (!(pluginIndex > -1)) { + throw ReactError( + "EventPluginRegistry: Cannot inject event plugins that do not exist in the plugin ordering, `" + + pluginName + + "`." + ); + } + })(); + if (plugins[pluginIndex]) { + continue; + } + (function() { + if (!pluginModule.extractEvents) { + throw ReactError( + "EventPluginRegistry: Event plugins must implement an `extractEvents` method, but `" + + pluginName + + "` does not." + ); + } + })(); + plugins[pluginIndex] = pluginModule; + var publishedEvents = pluginModule.eventTypes; + for (var eventName in publishedEvents) { + (function() { + if ( + !publishEventForPlugin( + publishedEvents[eventName], + pluginModule, + eventName + ) + ) { + throw ReactError( + "EventPluginRegistry: Failed to publish event `" + + eventName + + "` for plugin `" + + pluginName + + "`." + ); + } + })(); + } + } +} + +/** + * Publishes an event so that it can be dispatched by the supplied plugin. + * + * @param {object} dispatchConfig Dispatch configuration for the event. + * @param {object} PluginModule Plugin publishing the event. + * @return {boolean} True if the event was successfully published. + * @private + */ +function publishEventForPlugin(dispatchConfig, pluginModule, eventName) { + (function() { + if (!!eventNameDispatchConfigs.hasOwnProperty(eventName)) { + throw ReactError( + "EventPluginHub: More than one plugin attempted to publish the same event name, `" + + eventName + + "`." + ); + } + })(); + eventNameDispatchConfigs[eventName] = dispatchConfig; + + var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames; + if (phasedRegistrationNames) { + for (var phaseName in phasedRegistrationNames) { + if (phasedRegistrationNames.hasOwnProperty(phaseName)) { + var phasedRegistrationName = phasedRegistrationNames[phaseName]; + publishRegistrationName( + phasedRegistrationName, + pluginModule, + eventName + ); + } + } + return true; + } else if (dispatchConfig.registrationName) { + publishRegistrationName( + dispatchConfig.registrationName, + pluginModule, + eventName + ); + return true; + } + return false; +} + +/** + * Publishes a registration name that is used to identify dispatched events. + * + * @param {string} registrationName Registration name to add. + * @param {object} PluginModule Plugin publishing the event. + * @private + */ +function publishRegistrationName(registrationName, pluginModule, eventName) { + (function() { + if (!!registrationNameModules[registrationName]) { + throw ReactError( + "EventPluginHub: More than one plugin attempted to publish the same registration name, `" + + registrationName + + "`." + ); + } + })(); + registrationNameModules[registrationName] = pluginModule; + registrationNameDependencies[registrationName] = + pluginModule.eventTypes[eventName].dependencies; + + { + var lowerCasedName = registrationName.toLowerCase(); + } +} + +/** + * Registers plugins so that they can extract and dispatch events. + * + * @see {EventPluginHub} + */ + +/** + * Ordered list of injected plugins. + */ +var plugins = []; + +/** + * Mapping from event name to dispatch config + */ +var eventNameDispatchConfigs = {}; + +/** + * Mapping from registration name to plugin module + */ +var registrationNameModules = {}; + +/** + * Mapping from registration name to event name + */ +var registrationNameDependencies = {}; + +/** + * Mapping from lowercase registration names to the properly cased version, + * used to warn in the case of missing event handlers. Available + * only in true. + * @type {Object} + */ + +// Trust the developer to only use possibleRegistrationNames in true + +/** + * Injects an ordering of plugins (by plugin name). This allows the ordering + * to be decoupled from injection of the actual plugins so that ordering is + * always deterministic regardless of packaging, on-the-fly injection, etc. + * + * @param {array} InjectedEventPluginOrder + * @internal + * @see {EventPluginHub.injection.injectEventPluginOrder} + */ +function injectEventPluginOrder(injectedEventPluginOrder) { + (function() { + if (!!eventPluginOrder) { + throw ReactError( + "EventPluginRegistry: Cannot inject event plugin ordering more than once. You are likely trying to load more than one copy of React." + ); + } + })(); + // Clone the ordering so it cannot be dynamically mutated. + eventPluginOrder = Array.prototype.slice.call(injectedEventPluginOrder); + recomputePluginOrdering(); +} + +/** + * Injects plugins to be used by `EventPluginHub`. The plugin names must be + * in the ordering injected by `injectEventPluginOrder`. + * + * Plugins can be injected as part of page initialization or on-the-fly. + * + * @param {object} injectedNamesToPlugins Map from names to plugin modules. + * @internal + * @see {EventPluginHub.injection.injectEventPluginsByName} + */ +function injectEventPluginsByName(injectedNamesToPlugins) { + var isOrderingDirty = false; + for (var pluginName in injectedNamesToPlugins) { + if (!injectedNamesToPlugins.hasOwnProperty(pluginName)) { + continue; + } + var pluginModule = injectedNamesToPlugins[pluginName]; + if ( + !namesToPlugins.hasOwnProperty(pluginName) || + namesToPlugins[pluginName] !== pluginModule + ) { + (function() { + if (!!namesToPlugins[pluginName]) { + throw ReactError( + "EventPluginRegistry: Cannot inject two different event plugins using the same name, `" + + pluginName + + "`." + ); + } + })(); + namesToPlugins[pluginName] = pluginModule; + isOrderingDirty = true; + } + } + if (isOrderingDirty) { + recomputePluginOrdering(); + } +} + +var invokeGuardedCallbackImpl = function( + name, + func, + context, + a, + b, + c, + d, + e, + f +) { + var funcArgs = Array.prototype.slice.call(arguments, 3); + try { + func.apply(context, funcArgs); + } catch (error) { + this.onError(error); + } +}; + +{ + // In DEV mode, we swap out invokeGuardedCallback for a special version + // that plays more nicely with the browser's DevTools. The idea is to preserve + // "Pause on exceptions" behavior. Because React wraps all user-provided + // functions in invokeGuardedCallback, and the production version of + // invokeGuardedCallback uses a try-catch, all user exceptions are treated + // like caught exceptions, and the DevTools won't pause unless the developer + // takes the extra step of enabling pause on caught exceptions. This is + // unintuitive, though, because even though React has caught the error, from + // the developer's perspective, the error is uncaught. + // + // To preserve the expected "Pause on exceptions" behavior, we don't use a + // try-catch in DEV. Instead, we synchronously dispatch a fake event to a fake + // DOM node, and call the user-provided callback from inside an event handler + // for that fake event. If the callback throws, the error is "captured" using + // a global event handler. But because the error happens in a different + // event loop context, it does not interrupt the normal program flow. + // Effectively, this gives us try-catch behavior without actually using + // try-catch. Neat! + + // Check that the browser supports the APIs we need to implement our special + // DEV version of invokeGuardedCallback + if ( + typeof window !== "undefined" && + typeof window.dispatchEvent === "function" && + typeof document !== "undefined" && + typeof document.createEvent === "function" + ) { + var fakeNode = document.createElement("react"); + + var invokeGuardedCallbackDev = function( + name, + func, + context, + a, + b, + c, + d, + e, + f + ) { + // If document doesn't exist we know for sure we will crash in this method + // when we call document.createEvent(). However this can cause confusing + // errors: https://github.com/facebookincubator/create-react-app/issues/3482 + // So we preemptively throw with a better message instead. + (function() { + if (!(typeof document !== "undefined")) { + throw ReactError( + "The `document` global was defined when React was initialized, but is not defined anymore. This can happen in a test environment if a component schedules an update from an asynchronous callback, but the test has already finished running. To solve this, you can either unmount the component at the end of your test (and ensure that any asynchronous operations get canceled in `componentWillUnmount`), or you can change the test itself to be asynchronous." + ); + } + })(); + var evt = document.createEvent("Event"); + + // Keeps track of whether the user-provided callback threw an error. We + // set this to true at the beginning, then set it to false right after + // calling the function. If the function errors, `didError` will never be + // set to false. This strategy works even if the browser is flaky and + // fails to call our global error handler, because it doesn't rely on + // the error event at all. + var didError = true; + + // Keeps track of the value of window.event so that we can reset it + // during the callback to let user code access window.event in the + // browsers that support it. + var windowEvent = window.event; + + // Keeps track of the descriptor of window.event to restore it after event + // dispatching: https://github.com/facebook/react/issues/13688 + var windowEventDescriptor = Object.getOwnPropertyDescriptor( + window, + "event" + ); + + // Create an event handler for our fake event. We will synchronously + // dispatch our fake event using `dispatchEvent`. Inside the handler, we + // call the user-provided callback. + var funcArgs = Array.prototype.slice.call(arguments, 3); + function callCallback() { + // We immediately remove the callback from event listeners so that + // nested `invokeGuardedCallback` calls do not clash. Otherwise, a + // nested call would trigger the fake event handlers of any call higher + // in the stack. + fakeNode.removeEventListener(evtType, callCallback, false); + + // We check for window.hasOwnProperty('event') to prevent the + // window.event assignment in both IE <= 10 as they throw an error + // "Member not found" in strict mode, and in Firefox which does not + // support window.event. + if ( + typeof window.event !== "undefined" && + window.hasOwnProperty("event") + ) { + window.event = windowEvent; + } + + func.apply(context, funcArgs); + didError = false; + } + + // Create a global error event handler. We use this to capture the value + // that was thrown. It's possible that this error handler will fire more + // than once; for example, if non-React code also calls `dispatchEvent` + // and a handler for that event throws. We should be resilient to most of + // those cases. Even if our error event handler fires more than once, the + // last error event is always used. If the callback actually does error, + // we know that the last error event is the correct one, because it's not + // possible for anything else to have happened in between our callback + // erroring and the code that follows the `dispatchEvent` call below. If + // the callback doesn't error, but the error event was fired, we know to + // ignore it because `didError` will be false, as described above. + var error = void 0; + // Use this to track whether the error event is ever called. + var didSetError = false; + var isCrossOriginError = false; + + function handleWindowError(event) { + error = event.error; + didSetError = true; + if (error === null && event.colno === 0 && event.lineno === 0) { + isCrossOriginError = true; + } + if (event.defaultPrevented) { + // Some other error handler has prevented default. + // Browsers silence the error report if this happens. + // We'll remember this to later decide whether to log it or not. + if (error != null && typeof error === "object") { + try { + error._suppressLogging = true; + } catch (inner) { + // Ignore. + } + } + } + } + + // Create a fake event type. + var evtType = "react-" + (name ? name : "invokeguardedcallback"); + + // Attach our event handlers + window.addEventListener("error", handleWindowError); + fakeNode.addEventListener(evtType, callCallback, false); + + // Synchronously dispatch our fake event. If the user-provided function + // errors, it will trigger our global error handler. + evt.initEvent(evtType, false, false); + fakeNode.dispatchEvent(evt); + + if (windowEventDescriptor) { + Object.defineProperty(window, "event", windowEventDescriptor); + } + + if (didError) { + if (!didSetError) { + // The callback errored, but the error event never fired. + error = new Error( + "An error was thrown inside one of your components, but React " + + "doesn't know what it was. This is likely due to browser " + + 'flakiness. React does its best to preserve the "Pause on ' + + 'exceptions" behavior of the DevTools, which requires some ' + + "DEV-mode only tricks. It's possible that these don't work in " + + "your browser. Try triggering the error in production mode, " + + "or switching to a modern browser. If you suspect that this is " + + "actually an issue with React, please file an issue." + ); + } else if (isCrossOriginError) { + error = new Error( + "A cross-origin error was thrown. React doesn't have access to " + + "the actual error object in development. " + + "See https://fb.me/react-crossorigin-error for more information." + ); + } + this.onError(error); + } + + // Remove our event listeners + window.removeEventListener("error", handleWindowError); + }; + + invokeGuardedCallbackImpl = invokeGuardedCallbackDev; + } +} + +var invokeGuardedCallbackImpl$1 = invokeGuardedCallbackImpl; + +// Used by Fiber to simulate a try-catch. +var hasError = false; +var caughtError = null; + +// Used by event system to capture/rethrow the first error. +var hasRethrowError = false; +var rethrowError = null; + +var reporter = { + onError: function(error) { + hasError = true; + caughtError = error; + } +}; + +/** + * Call a function while guarding against errors that happens within it. + * Returns an error if it throws, otherwise null. + * + * In production, this is implemented using a try-catch. The reason we don't + * use a try-catch directly is so that we can swap out a different + * implementation in DEV mode. + * + * @param {String} name of the guard to use for logging or debugging + * @param {Function} func The function to invoke + * @param {*} context The context to use when calling the function + * @param {...*} args Arguments for function + */ +function invokeGuardedCallback(name, func, context, a, b, c, d, e, f) { + hasError = false; + caughtError = null; + invokeGuardedCallbackImpl$1.apply(reporter, arguments); +} + +/** + * Same as invokeGuardedCallback, but instead of returning an error, it stores + * it in a global so it can be rethrown by `rethrowCaughtError` later. + * TODO: See if caughtError and rethrowError can be unified. + * + * @param {String} name of the guard to use for logging or debugging + * @param {Function} func The function to invoke + * @param {*} context The context to use when calling the function + * @param {...*} args Arguments for function + */ +function invokeGuardedCallbackAndCatchFirstError( + name, + func, + context, + a, + b, + c, + d, + e, + f +) { + invokeGuardedCallback.apply(this, arguments); + if (hasError) { + var error = clearCaughtError(); + if (!hasRethrowError) { + hasRethrowError = true; + rethrowError = error; + } + } +} + +/** + * During execution of guarded functions we will capture the first error which + * we will rethrow to be handled by the top level error handler. + */ +function rethrowCaughtError() { + if (hasRethrowError) { + var error = rethrowError; + hasRethrowError = false; + rethrowError = null; + throw error; + } +} + +function hasCaughtError() { + return hasError; +} + +function clearCaughtError() { + if (hasError) { + var error = caughtError; + hasError = false; + caughtError = null; + return error; + } else { + (function() { + { + throw ReactError( + "clearCaughtError was called but no error was captured. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } +} + +/** + * Similar to invariant but only logs a warning if the condition is not met. + * This can be used to log issues in development environments in critical + * paths. Removing the logging code for production environments will keep the + * same logic and follow the same code paths. + */ + +var warningWithoutStack = function() {}; + +{ + warningWithoutStack = function(condition, format) { + for ( + var _len = arguments.length, + args = Array(_len > 2 ? _len - 2 : 0), + _key = 2; + _key < _len; + _key++ + ) { + args[_key - 2] = arguments[_key]; + } + + if (format === undefined) { + throw new Error( + "`warningWithoutStack(condition, format, ...args)` requires a warning " + + "message argument" + ); + } + if (args.length > 8) { + // Check before the condition to catch violations early. + throw new Error( + "warningWithoutStack() currently supports at most 8 arguments." + ); + } + if (condition) { + return; + } + if (typeof console !== "undefined") { + var argsWithFormat = args.map(function(item) { + return "" + item; + }); + argsWithFormat.unshift("Warning: " + format); + + // We intentionally don't use spread (or .apply) directly because it + // breaks IE9: https://github.com/facebook/react/issues/13610 + Function.prototype.apply.call(console.error, console, argsWithFormat); + } + try { + // --- Welcome to debugging React --- + // This error was thrown as a convenience so that you can use this stack + // to find the callsite that caused this warning to fire. + var argIndex = 0; + var message = + "Warning: " + + format.replace(/%s/g, function() { + return args[argIndex++]; + }); + throw new Error(message); + } catch (x) {} + }; +} + +var warningWithoutStack$1 = warningWithoutStack; + +var getFiberCurrentPropsFromNode = null; +var getInstanceFromNode = null; +var getNodeFromInstance = null; + +function setComponentTree( + getFiberCurrentPropsFromNodeImpl, + getInstanceFromNodeImpl, + getNodeFromInstanceImpl +) { + getFiberCurrentPropsFromNode = getFiberCurrentPropsFromNodeImpl; + getInstanceFromNode = getInstanceFromNodeImpl; + getNodeFromInstance = getNodeFromInstanceImpl; + { + !(getNodeFromInstance && getInstanceFromNode) + ? warningWithoutStack$1( + false, + "EventPluginUtils.setComponentTree(...): Injected " + + "module is missing getNodeFromInstance or getInstanceFromNode." + ) + : void 0; + } +} + +var validateEventDispatches = void 0; +{ + validateEventDispatches = function(event) { + var dispatchListeners = event._dispatchListeners; + var dispatchInstances = event._dispatchInstances; + + var listenersIsArr = Array.isArray(dispatchListeners); + var listenersLen = listenersIsArr + ? dispatchListeners.length + : dispatchListeners + ? 1 + : 0; + + var instancesIsArr = Array.isArray(dispatchInstances); + var instancesLen = instancesIsArr + ? dispatchInstances.length + : dispatchInstances + ? 1 + : 0; + + !(instancesIsArr === listenersIsArr && instancesLen === listenersLen) + ? warningWithoutStack$1(false, "EventPluginUtils: Invalid `event`.") + : void 0; + }; +} + +/** + * Dispatch the event to the listener. + * @param {SyntheticEvent} event SyntheticEvent to handle + * @param {function} listener Application-level callback + * @param {*} inst Internal component instance + */ +function executeDispatch(event, listener, inst) { + var type = event.type || "unknown-event"; + event.currentTarget = getNodeFromInstance(inst); + invokeGuardedCallbackAndCatchFirstError(type, listener, undefined, event); + event.currentTarget = null; +} + +/** + * Standard/simple iteration through an event's collected dispatches. + */ +function executeDispatchesInOrder(event) { + var dispatchListeners = event._dispatchListeners; + var dispatchInstances = event._dispatchInstances; + { + validateEventDispatches(event); + } + if (Array.isArray(dispatchListeners)) { + for (var i = 0; i < dispatchListeners.length; i++) { + if (event.isPropagationStopped()) { + break; + } + // Listeners and Instances are two parallel arrays that are always in sync. + executeDispatch(event, dispatchListeners[i], dispatchInstances[i]); + } + } else if (dispatchListeners) { + executeDispatch(event, dispatchListeners, dispatchInstances); + } + event._dispatchListeners = null; + event._dispatchInstances = null; +} + +/** + * Standard/simple iteration through an event's collected dispatches, but stops + * at the first dispatch execution returning true, and returns that id. + * + * @return {?string} id of the first dispatch execution who's listener returns + * true, or null if no listener returned true. + */ +function executeDispatchesInOrderStopAtTrueImpl(event) { + var dispatchListeners = event._dispatchListeners; + var dispatchInstances = event._dispatchInstances; + { + validateEventDispatches(event); + } + if (Array.isArray(dispatchListeners)) { + for (var i = 0; i < dispatchListeners.length; i++) { + if (event.isPropagationStopped()) { + break; + } + // Listeners and Instances are two parallel arrays that are always in sync. + if (dispatchListeners[i](event, dispatchInstances[i])) { + return dispatchInstances[i]; + } + } + } else if (dispatchListeners) { + if (dispatchListeners(event, dispatchInstances)) { + return dispatchInstances; + } + } + return null; +} + +/** + * @see executeDispatchesInOrderStopAtTrueImpl + */ +function executeDispatchesInOrderStopAtTrue(event) { + var ret = executeDispatchesInOrderStopAtTrueImpl(event); + event._dispatchInstances = null; + event._dispatchListeners = null; + return ret; +} + +/** + * Execution of a "direct" dispatch - there must be at most one dispatch + * accumulated on the event or it is considered an error. It doesn't really make + * sense for an event with multiple dispatches (bubbled) to keep track of the + * return values at each dispatch execution, but it does tend to make sense when + * dealing with "direct" dispatches. + * + * @return {*} The return value of executing the single dispatch. + */ +function executeDirectDispatch(event) { + { + validateEventDispatches(event); + } + var dispatchListener = event._dispatchListeners; + var dispatchInstance = event._dispatchInstances; + (function() { + if (!!Array.isArray(dispatchListener)) { + throw ReactError("executeDirectDispatch(...): Invalid `event`."); + } + })(); + event.currentTarget = dispatchListener + ? getNodeFromInstance(dispatchInstance) + : null; + var res = dispatchListener ? dispatchListener(event) : null; + event.currentTarget = null; + event._dispatchListeners = null; + event._dispatchInstances = null; + return res; +} + +/** + * @param {SyntheticEvent} event + * @return {boolean} True iff number of dispatches accumulated is greater than 0. + */ +function hasDispatches(event) { + return !!event._dispatchListeners; +} + +/** + * Accumulates items that must not be null or undefined into the first one. This + * is used to conserve memory by avoiding array allocations, and thus sacrifices + * API cleanness. Since `current` can be null before being passed in and not + * null after this function, make sure to assign it back to `current`: + * + * `a = accumulateInto(a, b);` + * + * This API should be sparingly used. Try `accumulate` for something cleaner. + * + * @return {*|array<*>} An accumulation of items. + */ + +function accumulateInto(current, next) { + (function() { + if (!(next != null)) { + throw ReactError( + "accumulateInto(...): Accumulated items must not be null or undefined." + ); + } + })(); + + if (current == null) { + return next; + } + + // Both are not empty. Warning: Never call x.concat(y) when you are not + // certain that x is an Array (x could be a string with concat method). + if (Array.isArray(current)) { + if (Array.isArray(next)) { + current.push.apply(current, next); + return current; + } + current.push(next); + return current; + } + + if (Array.isArray(next)) { + // A bit too dangerous to mutate `next`. + return [current].concat(next); + } + + return [current, next]; +} + +/** + * @param {array} arr an "accumulation" of items which is either an Array or + * a single item. Useful when paired with the `accumulate` module. This is a + * simple utility that allows us to reason about a collection of items, but + * handling the case when there is exactly one item (and we do not need to + * allocate an array). + * @param {function} cb Callback invoked with each element or a collection. + * @param {?} [scope] Scope used as `this` in a callback. + */ +function forEachAccumulated(arr, cb, scope) { + if (Array.isArray(arr)) { + arr.forEach(cb, scope); + } else if (arr) { + cb.call(scope, arr); + } +} + +/** + * Internal queue of events that have accumulated their dispatches and are + * waiting to have their dispatches executed. + */ +var eventQueue = null; + +/** + * Dispatches an event and releases it back into the pool, unless persistent. + * + * @param {?object} event Synthetic event to be dispatched. + * @private + */ +var executeDispatchesAndRelease = function(event) { + if (event) { + executeDispatchesInOrder(event); + + if (!event.isPersistent()) { + event.constructor.release(event); + } + } +}; +var executeDispatchesAndReleaseTopLevel = function(e) { + return executeDispatchesAndRelease(e); +}; + +function runEventsInBatch(events) { + if (events !== null) { + eventQueue = accumulateInto(eventQueue, events); + } + + // Set `eventQueue` to null before processing it so that we can tell if more + // events get enqueued while processing. + var processingEventQueue = eventQueue; + eventQueue = null; + + if (!processingEventQueue) { + return; + } + + forEachAccumulated(processingEventQueue, executeDispatchesAndReleaseTopLevel); + (function() { + if (!!eventQueue) { + throw ReactError( + "processEventQueue(): Additional events were enqueued while processing an event queue. Support for this has not yet been implemented." + ); + } + })(); + // This would be a good time to rethrow if any of the event handlers threw. + rethrowCaughtError(); +} + +function isInteractive(tag) { + return ( + tag === "button" || + tag === "input" || + tag === "select" || + tag === "textarea" + ); +} + +function shouldPreventMouseEvent(name, type, props) { + switch (name) { + case "onClick": + case "onClickCapture": + case "onDoubleClick": + case "onDoubleClickCapture": + case "onMouseDown": + case "onMouseDownCapture": + case "onMouseMove": + case "onMouseMoveCapture": + case "onMouseUp": + case "onMouseUpCapture": + return !!(props.disabled && isInteractive(type)); + default: + return false; + } +} + +/** + * This is a unified interface for event plugins to be installed and configured. + * + * Event plugins can implement the following properties: + * + * `extractEvents` {function(string, DOMEventTarget, string, object): *} + * Required. When a top-level event is fired, this method is expected to + * extract synthetic events that will in turn be queued and dispatched. + * + * `eventTypes` {object} + * Optional, plugins that fire events must publish a mapping of registration + * names that are used to register listeners. Values of this mapping must + * be objects that contain `registrationName` or `phasedRegistrationNames`. + * + * `executeDispatch` {function(object, function, string)} + * Optional, allows plugins to override how an event gets dispatched. By + * default, the listener is simply invoked. + * + * Each plugin that is injected into `EventsPluginHub` is immediately operable. + * + * @public + */ + +/** + * Methods for injecting dependencies. + */ +var injection = { + /** + * @param {array} InjectedEventPluginOrder + * @public + */ + injectEventPluginOrder: injectEventPluginOrder, + + /** + * @param {object} injectedNamesToPlugins Map from names to plugin modules. + */ + injectEventPluginsByName: injectEventPluginsByName +}; + +/** + * @param {object} inst The instance, which is the source of events. + * @param {string} registrationName Name of listener (e.g. `onClick`). + * @return {?function} The stored callback. + */ +function getListener(inst, registrationName) { + var listener = void 0; + + // TODO: shouldPreventMouseEvent is DOM-specific and definitely should not + // live here; needs to be moved to a better place soon + var stateNode = inst.stateNode; + if (!stateNode) { + // Work in progress (ex: onload events in incremental mode). + return null; + } + var props = getFiberCurrentPropsFromNode(stateNode); + if (!props) { + // Work in progress. + return null; + } + listener = props[registrationName]; + if (shouldPreventMouseEvent(registrationName, inst.type, props)) { + return null; + } + (function() { + if (!(!listener || typeof listener === "function")) { + throw ReactError( + "Expected `" + + registrationName + + "` listener to be a function, instead got a value of `" + + typeof listener + + "` type." + ); + } + })(); + return listener; +} + +/** + * Allows registered plugins an opportunity to extract events from top-level + * native browser events. + * + * @return {*} An accumulation of synthetic events. + * @internal + */ +function extractPluginEvents( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget +) { + var events = null; + for (var i = 0; i < plugins.length; i++) { + // Not every plugin in the ordering may be loaded at runtime. + var possiblePlugin = plugins[i]; + if (possiblePlugin) { + var extractedEvents = possiblePlugin.extractEvents( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ); + if (extractedEvents) { + events = accumulateInto(events, extractedEvents); + } + } + } + return events; +} + +function runExtractedPluginEventsInBatch( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget +) { + var events = extractPluginEvents( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ); + runEventsInBatch(events); +} + +var FunctionComponent = 0; +var ClassComponent = 1; +var IndeterminateComponent = 2; // Before we know whether it is function or class +var HostRoot = 3; // Root of a host tree. Could be nested inside another node. +var HostPortal = 4; // A subtree. Could be an entry point to a different renderer. +var HostComponent = 5; +var HostText = 6; +var Fragment = 7; +var Mode = 8; +var ContextConsumer = 9; +var ContextProvider = 10; +var ForwardRef = 11; +var Profiler = 12; +var SuspenseComponent = 13; +var MemoComponent = 14; +var SimpleMemoComponent = 15; +var LazyComponent = 16; +var IncompleteClassComponent = 17; +var DehydratedSuspenseComponent = 18; +var EventComponent = 19; +var EventTarget = 20; + +function getParent(inst) { + do { + inst = inst.return; + // TODO: If this is a HostRoot we might want to bail out. + // That is depending on if we want nested subtrees (layers) to bubble + // events to their parent. We could also go through parentNode on the + // host node but that wouldn't work for React Native and doesn't let us + // do the portal feature. + } while (inst && inst.tag !== HostComponent); + if (inst) { + return inst; + } + return null; +} + +/** + * Return the lowest common ancestor of A and B, or null if they are in + * different trees. + */ +function getLowestCommonAncestor(instA, instB) { + var depthA = 0; + for (var tempA = instA; tempA; tempA = getParent(tempA)) { + depthA++; + } + var depthB = 0; + for (var tempB = instB; tempB; tempB = getParent(tempB)) { + depthB++; + } + + // If A is deeper, crawl up. + while (depthA - depthB > 0) { + instA = getParent(instA); + depthA--; + } + + // If B is deeper, crawl up. + while (depthB - depthA > 0) { + instB = getParent(instB); + depthB--; + } + + // Walk in lockstep until we find a match. + var depth = depthA; + while (depth--) { + if (instA === instB || instA === instB.alternate) { + return instA; + } + instA = getParent(instA); + instB = getParent(instB); + } + return null; +} + +/** + * Return if A is an ancestor of B. + */ +function isAncestor(instA, instB) { + while (instB) { + if (instA === instB || instA === instB.alternate) { + return true; + } + instB = getParent(instB); + } + return false; +} + +/** + * Return the parent instance of the passed-in instance. + */ +function getParentInstance(inst) { + return getParent(inst); +} + +/** + * Simulates the traversal of a two-phase, capture/bubble event dispatch. + */ +function traverseTwoPhase(inst, fn, arg) { + var path = []; + while (inst) { + path.push(inst); + inst = getParent(inst); + } + var i = void 0; + for (i = path.length; i-- > 0; ) { + fn(path[i], "captured", arg); + } + for (i = 0; i < path.length; i++) { + fn(path[i], "bubbled", arg); + } +} + +/** + * Traverses the ID hierarchy and invokes the supplied `cb` on any IDs that + * should would receive a `mouseEnter` or `mouseLeave` event. + * + * Does not invoke the callback on the nearest common ancestor because nothing + * "entered" or "left" that element. + */ + +/** + * Some event types have a notion of different registration names for different + * "phases" of propagation. This finds listeners by a given phase. + */ +function listenerAtPhase(inst, event, propagationPhase) { + var registrationName = + event.dispatchConfig.phasedRegistrationNames[propagationPhase]; + return getListener(inst, registrationName); +} + +/** + * A small set of propagation patterns, each of which will accept a small amount + * of information, and generate a set of "dispatch ready event objects" - which + * are sets of events that have already been annotated with a set of dispatched + * listener functions/ids. The API is designed this way to discourage these + * propagation strategies from actually executing the dispatches, since we + * always want to collect the entire set of dispatches before executing even a + * single one. + */ + +/** + * Tags a `SyntheticEvent` with dispatched listeners. Creating this function + * here, allows us to not have to bind or create functions for each event. + * Mutating the event's members allows us to not have to create a wrapping + * "dispatch" object that pairs the event with the listener. + */ +function accumulateDirectionalDispatches(inst, phase, event) { + { + !inst + ? warningWithoutStack$1(false, "Dispatching inst must not be null") + : void 0; + } + var listener = listenerAtPhase(inst, event, phase); + if (listener) { + event._dispatchListeners = accumulateInto( + event._dispatchListeners, + listener + ); + event._dispatchInstances = accumulateInto(event._dispatchInstances, inst); + } +} + +/** + * Collect dispatches (must be entirely collected before dispatching - see unit + * tests). Lazily allocate the array to conserve memory. We must loop through + * each event and perform the traversal for each one. We cannot perform a + * single traversal for the entire collection of events because each event may + * have a different target. + */ +function accumulateTwoPhaseDispatchesSingle(event) { + if (event && event.dispatchConfig.phasedRegistrationNames) { + traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event); + } +} + +/** + * Same as `accumulateTwoPhaseDispatchesSingle`, but skips over the targetID. + */ +function accumulateTwoPhaseDispatchesSingleSkipTarget(event) { + if (event && event.dispatchConfig.phasedRegistrationNames) { + var targetInst = event._targetInst; + var parentInst = targetInst ? getParentInstance(targetInst) : null; + traverseTwoPhase(parentInst, accumulateDirectionalDispatches, event); + } +} + +/** + * Accumulates without regard to direction, does not look for phased + * registration names. Same as `accumulateDirectDispatchesSingle` but without + * requiring that the `dispatchMarker` be the same as the dispatched ID. + */ +function accumulateDispatches(inst, ignoredDirection, event) { + if (inst && event && event.dispatchConfig.registrationName) { + var registrationName = event.dispatchConfig.registrationName; + var listener = getListener(inst, registrationName); + if (listener) { + event._dispatchListeners = accumulateInto( + event._dispatchListeners, + listener + ); + event._dispatchInstances = accumulateInto(event._dispatchInstances, inst); + } + } +} + +/** + * Accumulates dispatches on an `SyntheticEvent`, but only for the + * `dispatchMarker`. + * @param {SyntheticEvent} event + */ +function accumulateDirectDispatchesSingle(event) { + if (event && event.dispatchConfig.registrationName) { + accumulateDispatches(event._targetInst, null, event); + } +} + +function accumulateTwoPhaseDispatches(events) { + forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle); +} + +function accumulateTwoPhaseDispatchesSkipTarget(events) { + forEachAccumulated(events, accumulateTwoPhaseDispatchesSingleSkipTarget); +} + +function accumulateDirectDispatches(events) { + forEachAccumulated(events, accumulateDirectDispatchesSingle); +} + +/* eslint valid-typeof: 0 */ + +var EVENT_POOL_SIZE = 10; + +/** + * @interface Event + * @see http://www.w3.org/TR/DOM-Level-3-Events/ + */ +var EventInterface = { + type: null, + target: null, + // currentTarget is set when dispatching; no use in copying it here + currentTarget: function() { + return null; + }, + eventPhase: null, + bubbles: null, + cancelable: null, + timeStamp: function(event) { + return event.timeStamp || Date.now(); + }, + defaultPrevented: null, + isTrusted: null +}; + +function functionThatReturnsTrue() { + return true; +} + +function functionThatReturnsFalse() { + return false; +} + +/** + * Synthetic events are dispatched by event plugins, typically in response to a + * top-level event delegation handler. + * + * These systems should generally use pooling to reduce the frequency of garbage + * collection. The system should check `isPersistent` to determine whether the + * event should be released into the pool after being dispatched. Users that + * need a persisted event should invoke `persist`. + * + * Synthetic events (and subclasses) implement the DOM Level 3 Events API by + * normalizing browser quirks. Subclasses do not necessarily have to implement a + * DOM interface; custom application-specific events can also subclass this. + * + * @param {object} dispatchConfig Configuration used to dispatch this event. + * @param {*} targetInst Marker identifying the event target. + * @param {object} nativeEvent Native browser event. + * @param {DOMEventTarget} nativeEventTarget Target node. + */ +function SyntheticEvent( + dispatchConfig, + targetInst, + nativeEvent, + nativeEventTarget +) { + { + // these have a getter/setter for warnings + delete this.nativeEvent; + delete this.preventDefault; + delete this.stopPropagation; + delete this.isDefaultPrevented; + delete this.isPropagationStopped; + } + + this.dispatchConfig = dispatchConfig; + this._targetInst = targetInst; + this.nativeEvent = nativeEvent; + + var Interface = this.constructor.Interface; + for (var propName in Interface) { + if (!Interface.hasOwnProperty(propName)) { + continue; + } + { + delete this[propName]; // this has a getter/setter for warnings + } + var normalize = Interface[propName]; + if (normalize) { + this[propName] = normalize(nativeEvent); + } else { + if (propName === "target") { + this.target = nativeEventTarget; + } else { + this[propName] = nativeEvent[propName]; + } + } + } + + var defaultPrevented = + nativeEvent.defaultPrevented != null + ? nativeEvent.defaultPrevented + : nativeEvent.returnValue === false; + if (defaultPrevented) { + this.isDefaultPrevented = functionThatReturnsTrue; + } else { + this.isDefaultPrevented = functionThatReturnsFalse; + } + this.isPropagationStopped = functionThatReturnsFalse; + return this; +} + +Object.assign(SyntheticEvent.prototype, { + preventDefault: function() { + this.defaultPrevented = true; + var event = this.nativeEvent; + if (!event) { + return; + } + + if (event.preventDefault) { + event.preventDefault(); + } else if (typeof event.returnValue !== "unknown") { + event.returnValue = false; + } + this.isDefaultPrevented = functionThatReturnsTrue; + }, + + stopPropagation: function() { + var event = this.nativeEvent; + if (!event) { + return; + } + + if (event.stopPropagation) { + event.stopPropagation(); + } else if (typeof event.cancelBubble !== "unknown") { + // The ChangeEventPlugin registers a "propertychange" event for + // IE. This event does not support bubbling or cancelling, and + // any references to cancelBubble throw "Member not found". A + // typeof check of "unknown" circumvents this issue (and is also + // IE specific). + event.cancelBubble = true; + } + + this.isPropagationStopped = functionThatReturnsTrue; + }, + + /** + * We release all dispatched `SyntheticEvent`s after each event loop, adding + * them back into the pool. This allows a way to hold onto a reference that + * won't be added back into the pool. + */ + persist: function() { + this.isPersistent = functionThatReturnsTrue; + }, + + /** + * Checks if this event should be released back into the pool. + * + * @return {boolean} True if this should not be released, false otherwise. + */ + isPersistent: functionThatReturnsFalse, + + /** + * `PooledClass` looks for `destructor` on each instance it releases. + */ + destructor: function() { + var Interface = this.constructor.Interface; + for (var propName in Interface) { + { + Object.defineProperty( + this, + propName, + getPooledWarningPropertyDefinition(propName, Interface[propName]) + ); + } + } + this.dispatchConfig = null; + this._targetInst = null; + this.nativeEvent = null; + this.isDefaultPrevented = functionThatReturnsFalse; + this.isPropagationStopped = functionThatReturnsFalse; + this._dispatchListeners = null; + this._dispatchInstances = null; + { + Object.defineProperty( + this, + "nativeEvent", + getPooledWarningPropertyDefinition("nativeEvent", null) + ); + Object.defineProperty( + this, + "isDefaultPrevented", + getPooledWarningPropertyDefinition( + "isDefaultPrevented", + functionThatReturnsFalse + ) + ); + Object.defineProperty( + this, + "isPropagationStopped", + getPooledWarningPropertyDefinition( + "isPropagationStopped", + functionThatReturnsFalse + ) + ); + Object.defineProperty( + this, + "preventDefault", + getPooledWarningPropertyDefinition("preventDefault", function() {}) + ); + Object.defineProperty( + this, + "stopPropagation", + getPooledWarningPropertyDefinition("stopPropagation", function() {}) + ); + } + } +}); + +SyntheticEvent.Interface = EventInterface; + +/** + * Helper to reduce boilerplate when creating subclasses. + */ +SyntheticEvent.extend = function(Interface) { + var Super = this; + + var E = function() {}; + E.prototype = Super.prototype; + var prototype = new E(); + + function Class() { + return Super.apply(this, arguments); + } + Object.assign(prototype, Class.prototype); + Class.prototype = prototype; + Class.prototype.constructor = Class; + + Class.Interface = Object.assign({}, Super.Interface, Interface); + Class.extend = Super.extend; + addEventPoolingTo(Class); + + return Class; +}; + +addEventPoolingTo(SyntheticEvent); + +/** + * Helper to nullify syntheticEvent instance properties when destructing + * + * @param {String} propName + * @param {?object} getVal + * @return {object} defineProperty object + */ +function getPooledWarningPropertyDefinition(propName, getVal) { + var isFunction = typeof getVal === "function"; + return { + configurable: true, + set: set, + get: get + }; + + function set(val) { + var action = isFunction ? "setting the method" : "setting the property"; + warn(action, "This is effectively a no-op"); + return val; + } + + function get() { + var action = isFunction ? "accessing the method" : "accessing the property"; + var result = isFunction + ? "This is a no-op function" + : "This is set to null"; + warn(action, result); + return getVal; + } + + function warn(action, result) { + var warningCondition = false; + !warningCondition + ? warningWithoutStack$1( + false, + "This synthetic event is reused for performance reasons. If you're seeing this, " + + "you're %s `%s` on a released/nullified synthetic event. %s. " + + "If you must keep the original synthetic event around, use event.persist(). " + + "See https://fb.me/react-event-pooling for more information.", + action, + propName, + result + ) + : void 0; + } +} + +function getPooledEvent(dispatchConfig, targetInst, nativeEvent, nativeInst) { + var EventConstructor = this; + if (EventConstructor.eventPool.length) { + var instance = EventConstructor.eventPool.pop(); + EventConstructor.call( + instance, + dispatchConfig, + targetInst, + nativeEvent, + nativeInst + ); + return instance; + } + return new EventConstructor( + dispatchConfig, + targetInst, + nativeEvent, + nativeInst + ); +} + +function releasePooledEvent(event) { + var EventConstructor = this; + (function() { + if (!(event instanceof EventConstructor)) { + throw ReactError( + "Trying to release an event instance into a pool of a different type." + ); + } + })(); + event.destructor(); + if (EventConstructor.eventPool.length < EVENT_POOL_SIZE) { + EventConstructor.eventPool.push(event); + } +} + +function addEventPoolingTo(EventConstructor) { + EventConstructor.eventPool = []; + EventConstructor.getPooled = getPooledEvent; + EventConstructor.release = releasePooledEvent; +} + +/** + * `touchHistory` isn't actually on the native event, but putting it in the + * interface will ensure that it is cleaned up when pooled/destroyed. The + * `ResponderEventPlugin` will populate it appropriately. + */ +var ResponderSyntheticEvent = SyntheticEvent.extend({ + touchHistory: function(nativeEvent) { + return null; // Actually doesn't even look at the native event. + } +}); + +var TOP_TOUCH_START = "topTouchStart"; +var TOP_TOUCH_MOVE = "topTouchMove"; +var TOP_TOUCH_END = "topTouchEnd"; +var TOP_TOUCH_CANCEL = "topTouchCancel"; +var TOP_SCROLL = "topScroll"; +var TOP_SELECTION_CHANGE = "topSelectionChange"; + +function isStartish(topLevelType) { + return topLevelType === TOP_TOUCH_START; +} + +function isMoveish(topLevelType) { + return topLevelType === TOP_TOUCH_MOVE; +} + +function isEndish(topLevelType) { + return topLevelType === TOP_TOUCH_END || topLevelType === TOP_TOUCH_CANCEL; +} + +var startDependencies = [TOP_TOUCH_START]; +var moveDependencies = [TOP_TOUCH_MOVE]; +var endDependencies = [TOP_TOUCH_CANCEL, TOP_TOUCH_END]; + +/** + * Tracks the position and time of each active touch by `touch.identifier`. We + * should typically only see IDs in the range of 1-20 because IDs get recycled + * when touches end and start again. + */ + +var MAX_TOUCH_BANK = 20; +var touchBank = []; +var touchHistory = { + touchBank: touchBank, + numberActiveTouches: 0, + // If there is only one active touch, we remember its location. This prevents + // us having to loop through all of the touches all the time in the most + // common case. + indexOfSingleActiveTouch: -1, + mostRecentTimeStamp: 0 +}; + +function timestampForTouch(touch) { + // The legacy internal implementation provides "timeStamp", which has been + // renamed to "timestamp". Let both work for now while we iron it out + // TODO (evv): rename timeStamp to timestamp in internal code + return touch.timeStamp || touch.timestamp; +} + +/** + * TODO: Instead of making gestures recompute filtered velocity, we could + * include a built in velocity computation that can be reused globally. + */ +function createTouchRecord(touch) { + return { + touchActive: true, + startPageX: touch.pageX, + startPageY: touch.pageY, + startTimeStamp: timestampForTouch(touch), + currentPageX: touch.pageX, + currentPageY: touch.pageY, + currentTimeStamp: timestampForTouch(touch), + previousPageX: touch.pageX, + previousPageY: touch.pageY, + previousTimeStamp: timestampForTouch(touch) + }; +} + +function resetTouchRecord(touchRecord, touch) { + touchRecord.touchActive = true; + touchRecord.startPageX = touch.pageX; + touchRecord.startPageY = touch.pageY; + touchRecord.startTimeStamp = timestampForTouch(touch); + touchRecord.currentPageX = touch.pageX; + touchRecord.currentPageY = touch.pageY; + touchRecord.currentTimeStamp = timestampForTouch(touch); + touchRecord.previousPageX = touch.pageX; + touchRecord.previousPageY = touch.pageY; + touchRecord.previousTimeStamp = timestampForTouch(touch); +} + +function getTouchIdentifier(_ref) { + var identifier = _ref.identifier; + + (function() { + if (!(identifier != null)) { + throw ReactError("Touch object is missing identifier."); + } + })(); + { + !(identifier <= MAX_TOUCH_BANK) + ? warningWithoutStack$1( + false, + "Touch identifier %s is greater than maximum supported %s which causes " + + "performance issues backfilling array locations for all of the indices.", + identifier, + MAX_TOUCH_BANK + ) + : void 0; + } + return identifier; +} + +function recordTouchStart(touch) { + var identifier = getTouchIdentifier(touch); + var touchRecord = touchBank[identifier]; + if (touchRecord) { + resetTouchRecord(touchRecord, touch); + } else { + touchBank[identifier] = createTouchRecord(touch); + } + touchHistory.mostRecentTimeStamp = timestampForTouch(touch); +} + +function recordTouchMove(touch) { + var touchRecord = touchBank[getTouchIdentifier(touch)]; + if (touchRecord) { + touchRecord.touchActive = true; + touchRecord.previousPageX = touchRecord.currentPageX; + touchRecord.previousPageY = touchRecord.currentPageY; + touchRecord.previousTimeStamp = touchRecord.currentTimeStamp; + touchRecord.currentPageX = touch.pageX; + touchRecord.currentPageY = touch.pageY; + touchRecord.currentTimeStamp = timestampForTouch(touch); + touchHistory.mostRecentTimeStamp = timestampForTouch(touch); + } else { + console.error( + "Cannot record touch move without a touch start.\n" + "Touch Move: %s\n", + "Touch Bank: %s", + printTouch(touch), + printTouchBank() + ); + } +} + +function recordTouchEnd(touch) { + var touchRecord = touchBank[getTouchIdentifier(touch)]; + if (touchRecord) { + touchRecord.touchActive = false; + touchRecord.previousPageX = touchRecord.currentPageX; + touchRecord.previousPageY = touchRecord.currentPageY; + touchRecord.previousTimeStamp = touchRecord.currentTimeStamp; + touchRecord.currentPageX = touch.pageX; + touchRecord.currentPageY = touch.pageY; + touchRecord.currentTimeStamp = timestampForTouch(touch); + touchHistory.mostRecentTimeStamp = timestampForTouch(touch); + } else { + console.error( + "Cannot record touch end without a touch start.\n" + "Touch End: %s\n", + "Touch Bank: %s", + printTouch(touch), + printTouchBank() + ); + } +} + +function printTouch(touch) { + return JSON.stringify({ + identifier: touch.identifier, + pageX: touch.pageX, + pageY: touch.pageY, + timestamp: timestampForTouch(touch) + }); +} + +function printTouchBank() { + var printed = JSON.stringify(touchBank.slice(0, MAX_TOUCH_BANK)); + if (touchBank.length > MAX_TOUCH_BANK) { + printed += " (original size: " + touchBank.length + ")"; + } + return printed; +} + +var ResponderTouchHistoryStore = { + recordTouchTrack: function(topLevelType, nativeEvent) { + if (isMoveish(topLevelType)) { + nativeEvent.changedTouches.forEach(recordTouchMove); + } else if (isStartish(topLevelType)) { + nativeEvent.changedTouches.forEach(recordTouchStart); + touchHistory.numberActiveTouches = nativeEvent.touches.length; + if (touchHistory.numberActiveTouches === 1) { + touchHistory.indexOfSingleActiveTouch = + nativeEvent.touches[0].identifier; + } + } else if (isEndish(topLevelType)) { + nativeEvent.changedTouches.forEach(recordTouchEnd); + touchHistory.numberActiveTouches = nativeEvent.touches.length; + if (touchHistory.numberActiveTouches === 1) { + for (var i = 0; i < touchBank.length; i++) { + var touchTrackToCheck = touchBank[i]; + if (touchTrackToCheck != null && touchTrackToCheck.touchActive) { + touchHistory.indexOfSingleActiveTouch = i; + break; + } + } + { + var activeRecord = touchBank[touchHistory.indexOfSingleActiveTouch]; + !(activeRecord != null && activeRecord.touchActive) + ? warningWithoutStack$1(false, "Cannot find single active touch.") + : void 0; + } + } + } + }, + + touchHistory: touchHistory +}; + +/** + * Accumulates items that must not be null or undefined. + * + * This is used to conserve memory by avoiding array allocations. + * + * @return {*|array<*>} An accumulation of items. + */ +function accumulate(current, next) { + (function() { + if (!(next != null)) { + throw ReactError( + "accumulate(...): Accumulated items must not be null or undefined." + ); + } + })(); + + if (current == null) { + return next; + } + + // Both are not empty. Warning: Never call x.concat(y) when you are not + // certain that x is an Array (x could be a string with concat method). + if (Array.isArray(current)) { + return current.concat(next); + } + + if (Array.isArray(next)) { + return [current].concat(next); + } + + return [current, next]; +} + +/** + * Instance of element that should respond to touch/move types of interactions, + * as indicated explicitly by relevant callbacks. + */ +var responderInst = null; + +/** + * Count of current touches. A textInput should become responder iff the + * selection changes while there is a touch on the screen. + */ +var trackedTouchCount = 0; + +var changeResponder = function(nextResponderInst, blockHostResponder) { + var oldResponderInst = responderInst; + responderInst = nextResponderInst; + if (ResponderEventPlugin.GlobalResponderHandler !== null) { + ResponderEventPlugin.GlobalResponderHandler.onChange( + oldResponderInst, + nextResponderInst, + blockHostResponder + ); + } +}; + +var eventTypes = { + /** + * On a `touchStart`/`mouseDown`, is it desired that this element become the + * responder? + */ + startShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onStartShouldSetResponder", + captured: "onStartShouldSetResponderCapture" + }, + dependencies: startDependencies + }, + + /** + * On a `scroll`, is it desired that this element become the responder? This + * is usually not needed, but should be used to retroactively infer that a + * `touchStart` had occurred during momentum scroll. During a momentum scroll, + * a touch start will be immediately followed by a scroll event if the view is + * currently scrolling. + * + * TODO: This shouldn't bubble. + */ + scrollShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onScrollShouldSetResponder", + captured: "onScrollShouldSetResponderCapture" + }, + dependencies: [TOP_SCROLL] + }, + + /** + * On text selection change, should this element become the responder? This + * is needed for text inputs or other views with native selection, so the + * JS view can claim the responder. + * + * TODO: This shouldn't bubble. + */ + selectionChangeShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onSelectionChangeShouldSetResponder", + captured: "onSelectionChangeShouldSetResponderCapture" + }, + dependencies: [TOP_SELECTION_CHANGE] + }, + + /** + * On a `touchMove`/`mouseMove`, is it desired that this element become the + * responder? + */ + moveShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onMoveShouldSetResponder", + captured: "onMoveShouldSetResponderCapture" + }, + dependencies: moveDependencies + }, + + /** + * Direct responder events dispatched directly to responder. Do not bubble. + */ + responderStart: { + registrationName: "onResponderStart", + dependencies: startDependencies + }, + responderMove: { + registrationName: "onResponderMove", + dependencies: moveDependencies + }, + responderEnd: { + registrationName: "onResponderEnd", + dependencies: endDependencies + }, + responderRelease: { + registrationName: "onResponderRelease", + dependencies: endDependencies + }, + responderTerminationRequest: { + registrationName: "onResponderTerminationRequest", + dependencies: [] + }, + responderGrant: { + registrationName: "onResponderGrant", + dependencies: [] + }, + responderReject: { + registrationName: "onResponderReject", + dependencies: [] + }, + responderTerminate: { + registrationName: "onResponderTerminate", + dependencies: [] + } +}; + +/** + * + * Responder System: + * ---------------- + * + * - A global, solitary "interaction lock" on a view. + * - If a node becomes the responder, it should convey visual feedback + * immediately to indicate so, either by highlighting or moving accordingly. + * - To be the responder means, that touches are exclusively important to that + * responder view, and no other view. + * - While touches are still occurring, the responder lock can be transferred to + * a new view, but only to increasingly "higher" views (meaning ancestors of + * the current responder). + * + * Responder being granted: + * ------------------------ + * + * - Touch starts, moves, and scrolls can cause an ID to become the responder. + * - We capture/bubble `startShouldSetResponder`/`moveShouldSetResponder` to + * the "appropriate place". + * - If nothing is currently the responder, the "appropriate place" is the + * initiating event's `targetID`. + * - If something *is* already the responder, the "appropriate place" is the + * first common ancestor of the event target and the current `responderInst`. + * - Some negotiation happens: See the timing diagram below. + * - Scrolled views automatically become responder. The reasoning is that a + * platform scroll view that isn't built on top of the responder system has + * began scrolling, and the active responder must now be notified that the + * interaction is no longer locked to it - the system has taken over. + * + * - Responder being released: + * As soon as no more touches that *started* inside of descendants of the + * *current* responderInst, an `onResponderRelease` event is dispatched to the + * current responder, and the responder lock is released. + * + * TODO: + * - on "end", a callback hook for `onResponderEndShouldRemainResponder` that + * determines if the responder lock should remain. + * - If a view shouldn't "remain" the responder, any active touches should by + * default be considered "dead" and do not influence future negotiations or + * bubble paths. It should be as if those touches do not exist. + * -- For multitouch: Usually a translate-z will choose to "remain" responder + * after one out of many touches ended. For translate-y, usually the view + * doesn't wish to "remain" responder after one of many touches end. + * - Consider building this on top of a `stopPropagation` model similar to + * `W3C` events. + * - Ensure that `onResponderTerminate` is called on touch cancels, whether or + * not `onResponderTerminationRequest` returns `true` or `false`. + * + */ + +/* Negotiation Performed + +-----------------------+ + / \ +Process low level events to + Current Responder + wantsResponderID +determine who to perform negot-| (if any exists at all) | +iation/transition | Otherwise just pass through| +-------------------------------+----------------------------+------------------+ +Bubble to find first ID | | +to return true:wantsResponderID| | + | | + +-------------+ | | + | onTouchStart| | | + +------+------+ none | | + | return| | ++-----------v-------------+true| +------------------------+ | +|onStartShouldSetResponder|----->|onResponderStart (cur) |<-----------+ ++-----------+-------------+ | +------------------------+ | | + | | | +--------+-------+ + | returned true for| false:REJECT +-------->|onResponderReject + | wantsResponderID | | | +----------------+ + | (now attempt | +------------------+-----+ | + | handoff) | | onResponder | | + +------------------->| TerminationRequest| | + | +------------------+-----+ | + | | | +----------------+ + | true:GRANT +-------->|onResponderGrant| + | | +--------+-------+ + | +------------------------+ | | + | | onResponderTerminate |<-----------+ + | +------------------+-----+ | + | | | +----------------+ + | +-------->|onResponderStart| + | | +----------------+ +Bubble to find first ID | | +to return true:wantsResponderID| | + | | + +-------------+ | | + | onTouchMove | | | + +------+------+ none | | + | return| | ++-----------v-------------+true| +------------------------+ | +|onMoveShouldSetResponder |----->|onResponderMove (cur) |<-----------+ ++-----------+-------------+ | +------------------------+ | | + | | | +--------+-------+ + | returned true for| false:REJECT +-------->|onResponderRejec| + | wantsResponderID | | | +----------------+ + | (now attempt | +------------------+-----+ | + | handoff) | | onResponder | | + +------------------->| TerminationRequest| | + | +------------------+-----+ | + | | | +----------------+ + | true:GRANT +-------->|onResponderGrant| + | | +--------+-------+ + | +------------------------+ | | + | | onResponderTerminate |<-----------+ + | +------------------+-----+ | + | | | +----------------+ + | +-------->|onResponderMove | + | | +----------------+ + | | + | | + Some active touch started| | + inside current responder | +------------------------+ | + +------------------------->| onResponderEnd | | + | | +------------------------+ | + +---+---------+ | | + | onTouchEnd | | | + +---+---------+ | | + | | +------------------------+ | + +------------------------->| onResponderEnd | | + No active touches started| +-----------+------------+ | + inside current responder | | | + | v | + | +------------------------+ | + | | onResponderRelease | | + | +------------------------+ | + | | + + + */ + +/** + * A note about event ordering in the `EventPluginHub`. + * + * Suppose plugins are injected in the following order: + * + * `[R, S, C]` + * + * To help illustrate the example, assume `S` is `SimpleEventPlugin` (for + * `onClick` etc) and `R` is `ResponderEventPlugin`. + * + * "Deferred-Dispatched Events": + * + * - The current event plugin system will traverse the list of injected plugins, + * in order, and extract events by collecting the plugin's return value of + * `extractEvents()`. + * - These events that are returned from `extractEvents` are "deferred + * dispatched events". + * - When returned from `extractEvents`, deferred-dispatched events contain an + * "accumulation" of deferred dispatches. + * - These deferred dispatches are accumulated/collected before they are + * returned, but processed at a later time by the `EventPluginHub` (hence the + * name deferred). + * + * In the process of returning their deferred-dispatched events, event plugins + * themselves can dispatch events on-demand without returning them from + * `extractEvents`. Plugins might want to do this, so that they can use event + * dispatching as a tool that helps them decide which events should be extracted + * in the first place. + * + * "On-Demand-Dispatched Events": + * + * - On-demand-dispatched events are not returned from `extractEvents`. + * - On-demand-dispatched events are dispatched during the process of returning + * the deferred-dispatched events. + * - They should not have side effects. + * - They should be avoided, and/or eventually be replaced with another + * abstraction that allows event plugins to perform multiple "rounds" of event + * extraction. + * + * Therefore, the sequence of event dispatches becomes: + * + * - `R`s on-demand events (if any) (dispatched by `R` on-demand) + * - `S`s on-demand events (if any) (dispatched by `S` on-demand) + * - `C`s on-demand events (if any) (dispatched by `C` on-demand) + * - `R`s extracted events (if any) (dispatched by `EventPluginHub`) + * - `S`s extracted events (if any) (dispatched by `EventPluginHub`) + * - `C`s extracted events (if any) (dispatched by `EventPluginHub`) + * + * In the case of `ResponderEventPlugin`: If the `startShouldSetResponder` + * on-demand dispatch returns `true` (and some other details are satisfied) the + * `onResponderGrant` deferred dispatched event is returned from + * `extractEvents`. The sequence of dispatch executions in this case + * will appear as follows: + * + * - `startShouldSetResponder` (`ResponderEventPlugin` dispatches on-demand) + * - `touchStartCapture` (`EventPluginHub` dispatches as usual) + * - `touchStart` (`EventPluginHub` dispatches as usual) + * - `responderGrant/Reject` (`EventPluginHub` dispatches as usual) + */ + +function setResponderAndExtractTransfer( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget +) { + var shouldSetEventType = isStartish(topLevelType) + ? eventTypes.startShouldSetResponder + : isMoveish(topLevelType) + ? eventTypes.moveShouldSetResponder + : topLevelType === TOP_SELECTION_CHANGE + ? eventTypes.selectionChangeShouldSetResponder + : eventTypes.scrollShouldSetResponder; + + // TODO: stop one short of the current responder. + var bubbleShouldSetFrom = !responderInst + ? targetInst + : getLowestCommonAncestor(responderInst, targetInst); + + // When capturing/bubbling the "shouldSet" event, we want to skip the target + // (deepest ID) if it happens to be the current responder. The reasoning: + // It's strange to get an `onMoveShouldSetResponder` when you're *already* + // the responder. + var skipOverBubbleShouldSetFrom = bubbleShouldSetFrom === responderInst; + var shouldSetEvent = ResponderSyntheticEvent.getPooled( + shouldSetEventType, + bubbleShouldSetFrom, + nativeEvent, + nativeEventTarget + ); + shouldSetEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + if (skipOverBubbleShouldSetFrom) { + accumulateTwoPhaseDispatchesSkipTarget(shouldSetEvent); + } else { + accumulateTwoPhaseDispatches(shouldSetEvent); + } + var wantsResponderInst = executeDispatchesInOrderStopAtTrue(shouldSetEvent); + if (!shouldSetEvent.isPersistent()) { + shouldSetEvent.constructor.release(shouldSetEvent); + } + + if (!wantsResponderInst || wantsResponderInst === responderInst) { + return null; + } + var extracted = void 0; + var grantEvent = ResponderSyntheticEvent.getPooled( + eventTypes.responderGrant, + wantsResponderInst, + nativeEvent, + nativeEventTarget + ); + grantEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + + accumulateDirectDispatches(grantEvent); + var blockHostResponder = executeDirectDispatch(grantEvent) === true; + if (responderInst) { + var terminationRequestEvent = ResponderSyntheticEvent.getPooled( + eventTypes.responderTerminationRequest, + responderInst, + nativeEvent, + nativeEventTarget + ); + terminationRequestEvent.touchHistory = + ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches(terminationRequestEvent); + var shouldSwitch = + !hasDispatches(terminationRequestEvent) || + executeDirectDispatch(terminationRequestEvent); + if (!terminationRequestEvent.isPersistent()) { + terminationRequestEvent.constructor.release(terminationRequestEvent); + } + + if (shouldSwitch) { + var terminateEvent = ResponderSyntheticEvent.getPooled( + eventTypes.responderTerminate, + responderInst, + nativeEvent, + nativeEventTarget + ); + terminateEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches(terminateEvent); + extracted = accumulate(extracted, [grantEvent, terminateEvent]); + changeResponder(wantsResponderInst, blockHostResponder); + } else { + var rejectEvent = ResponderSyntheticEvent.getPooled( + eventTypes.responderReject, + wantsResponderInst, + nativeEvent, + nativeEventTarget + ); + rejectEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches(rejectEvent); + extracted = accumulate(extracted, rejectEvent); + } + } else { + extracted = accumulate(extracted, grantEvent); + changeResponder(wantsResponderInst, blockHostResponder); + } + return extracted; +} + +/** + * A transfer is a negotiation between a currently set responder and the next + * element to claim responder status. Any start event could trigger a transfer + * of responderInst. Any move event could trigger a transfer. + * + * @param {string} topLevelType Record from `BrowserEventConstants`. + * @return {boolean} True if a transfer of responder could possibly occur. + */ +function canTriggerTransfer(topLevelType, topLevelInst, nativeEvent) { + return ( + topLevelInst && + // responderIgnoreScroll: We are trying to migrate away from specifically + // tracking native scroll events here and responderIgnoreScroll indicates we + // will send topTouchCancel to handle canceling touch events instead + ((topLevelType === TOP_SCROLL && !nativeEvent.responderIgnoreScroll) || + (trackedTouchCount > 0 && topLevelType === TOP_SELECTION_CHANGE) || + isStartish(topLevelType) || + isMoveish(topLevelType)) + ); +} + +/** + * Returns whether or not this touch end event makes it such that there are no + * longer any touches that started inside of the current `responderInst`. + * + * @param {NativeEvent} nativeEvent Native touch end event. + * @return {boolean} Whether or not this touch end event ends the responder. + */ +function noResponderTouches(nativeEvent) { + var touches = nativeEvent.touches; + if (!touches || touches.length === 0) { + return true; + } + for (var i = 0; i < touches.length; i++) { + var activeTouch = touches[i]; + var target = activeTouch.target; + if (target !== null && target !== undefined && target !== 0) { + // Is the original touch location inside of the current responder? + var targetInst = getInstanceFromNode(target); + if (isAncestor(responderInst, targetInst)) { + return false; + } + } + } + return true; +} + +var ResponderEventPlugin = { + /* For unit testing only */ + _getResponder: function() { + return responderInst; + }, + + eventTypes: eventTypes, + + /** + * We must be resilient to `targetInst` being `null` on `touchMove` or + * `touchEnd`. On certain platforms, this means that a native scroll has + * assumed control and the original touch targets are destroyed. + */ + extractEvents: function( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ) { + if (isStartish(topLevelType)) { + trackedTouchCount += 1; + } else if (isEndish(topLevelType)) { + if (trackedTouchCount >= 0) { + trackedTouchCount -= 1; + } else { + console.error( + "Ended a touch event which was not counted in `trackedTouchCount`." + ); + return null; + } + } + + ResponderTouchHistoryStore.recordTouchTrack(topLevelType, nativeEvent); + + var extracted = canTriggerTransfer(topLevelType, targetInst, nativeEvent) + ? setResponderAndExtractTransfer( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ) + : null; + // Responder may or may not have transferred on a new touch start/move. + // Regardless, whoever is the responder after any potential transfer, we + // direct all touch start/move/ends to them in the form of + // `onResponderMove/Start/End`. These will be called for *every* additional + // finger that move/start/end, dispatched directly to whoever is the + // current responder at that moment, until the responder is "released". + // + // These multiple individual change touch events are are always bookended + // by `onResponderGrant`, and one of + // (`onResponderRelease/onResponderTerminate`). + var isResponderTouchStart = responderInst && isStartish(topLevelType); + var isResponderTouchMove = responderInst && isMoveish(topLevelType); + var isResponderTouchEnd = responderInst && isEndish(topLevelType); + var incrementalTouch = isResponderTouchStart + ? eventTypes.responderStart + : isResponderTouchMove + ? eventTypes.responderMove + : isResponderTouchEnd + ? eventTypes.responderEnd + : null; + + if (incrementalTouch) { + var gesture = ResponderSyntheticEvent.getPooled( + incrementalTouch, + responderInst, + nativeEvent, + nativeEventTarget + ); + gesture.touchHistory = ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches(gesture); + extracted = accumulate(extracted, gesture); + } + + var isResponderTerminate = + responderInst && topLevelType === TOP_TOUCH_CANCEL; + var isResponderRelease = + responderInst && + !isResponderTerminate && + isEndish(topLevelType) && + noResponderTouches(nativeEvent); + var finalTouch = isResponderTerminate + ? eventTypes.responderTerminate + : isResponderRelease + ? eventTypes.responderRelease + : null; + if (finalTouch) { + var finalEvent = ResponderSyntheticEvent.getPooled( + finalTouch, + responderInst, + nativeEvent, + nativeEventTarget + ); + finalEvent.touchHistory = ResponderTouchHistoryStore.touchHistory; + accumulateDirectDispatches(finalEvent); + extracted = accumulate(extracted, finalEvent); + changeResponder(null); + } + + return extracted; + }, + + GlobalResponderHandler: null, + + injection: { + /** + * @param {{onChange: (ReactID, ReactID) => void} GlobalResponderHandler + * Object that handles any change in responder. Use this to inject + * integration with an existing touch handling system etc. + */ + injectGlobalResponderHandler: function(GlobalResponderHandler) { + ResponderEventPlugin.GlobalResponderHandler = GlobalResponderHandler; + } + } +}; + +// Module provided by RN: +var customBubblingEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customBubblingEventTypes; +var customDirectEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customDirectEventTypes; +var eventTypes$1 = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes; + +var ReactNativeBridgeEventPlugin = { + eventTypes: eventTypes$1, + + /** + * @see {EventPluginHub.extractEvents} + */ + extractEvents: function( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ) { + if (targetInst == null) { + // Probably a node belonging to another renderer's tree. + return null; + } + var bubbleDispatchConfig = customBubblingEventTypes[topLevelType]; + var directDispatchConfig = customDirectEventTypes[topLevelType]; + (function() { + if (!(bubbleDispatchConfig || directDispatchConfig)) { + throw ReactError( + 'Unsupported top level event type "' + topLevelType + '" dispatched' + ); + } + })(); + var event = SyntheticEvent.getPooled( + bubbleDispatchConfig || directDispatchConfig, + targetInst, + nativeEvent, + nativeEventTarget + ); + if (bubbleDispatchConfig) { + accumulateTwoPhaseDispatches(event); + } else if (directDispatchConfig) { + accumulateDirectDispatches(event); + } else { + return null; + } + return event; + } +}; + +var ReactNativeEventPluginOrder = [ + "ResponderEventPlugin", + "ReactNativeBridgeEventPlugin" +]; + +/** + * Make sure essential globals are available and are patched correctly. Please don't remove this + * line. Bundles created by react-packager `require` it before executing any application code. This + * ensures it exists in the dependency graph and can be `require`d. + * TODO: require this in packager, not in React #10932517 + */ +// Module provided by RN: +/** + * Inject module for resolving DOM hierarchy and plugin ordering. + */ +injection.injectEventPluginOrder(ReactNativeEventPluginOrder); + +/** + * Some important event plugins included by default (without having to require + * them). + */ +injection.injectEventPluginsByName({ + ResponderEventPlugin: ResponderEventPlugin, + ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin +}); + +var instanceCache = {}; +var instanceProps = {}; + +function precacheFiberNode(hostInst, tag) { + instanceCache[tag] = hostInst; +} + +function uncacheFiberNode(tag) { + delete instanceCache[tag]; + delete instanceProps[tag]; +} + +function getInstanceFromTag(tag) { + return instanceCache[tag] || null; +} + +function getTagFromInstance(inst) { + var tag = inst.stateNode._nativeTag; + if (tag === undefined) { + tag = inst.stateNode.canonical._nativeTag; + } + (function() { + if (!tag) { + throw ReactError("All native instances should have a tag."); + } + })(); + return tag; +} + +function getFiberCurrentPropsFromNode$1(stateNode) { + return instanceProps[stateNode._nativeTag] || null; +} + +function updateFiberProps(tag, props) { + instanceProps[tag] = props; +} + +// Use to restore controlled state after a change event has fired. + +var restoreImpl = null; +var restoreTarget = null; +var restoreQueue = null; + +function restoreStateOfTarget(target) { + // We perform this translation at the end of the event loop so that we + // always receive the correct fiber here + var internalInstance = getInstanceFromNode(target); + if (!internalInstance) { + // Unmounted + return; + } + (function() { + if (!(typeof restoreImpl === "function")) { + throw ReactError( + "setRestoreImplementation() needs to be called to handle a target for controlled events. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + var props = getFiberCurrentPropsFromNode(internalInstance.stateNode); + restoreImpl(internalInstance.stateNode, internalInstance.type, props); +} + +function needsStateRestore() { + return restoreTarget !== null || restoreQueue !== null; +} + +function restoreStateIfNeeded() { + if (!restoreTarget) { + return; + } + var target = restoreTarget; + var queuedTargets = restoreQueue; + restoreTarget = null; + restoreQueue = null; + + restoreStateOfTarget(target); + if (queuedTargets) { + for (var i = 0; i < queuedTargets.length; i++) { + restoreStateOfTarget(queuedTargets[i]); + } + } +} + +// Used as a way to call batchedUpdates when we don't have a reference to +// the renderer. Such as when we're dispatching events or if third party +// libraries need to call batchedUpdates. Eventually, this API will go away when +// everything is batched by default. We'll then have a similar API to opt-out of +// scheduled work and instead do synchronous work. + +// Defaults +var _batchedUpdatesImpl = function(fn, bookkeeping) { + return fn(bookkeeping); +}; +var _flushInteractiveUpdatesImpl = function() {}; + +var isBatching = false; +function batchedUpdates(fn, bookkeeping) { + if (isBatching) { + // If we are currently inside another batch, we need to wait until it + // fully completes before restoring state. + return fn(bookkeeping); + } + isBatching = true; + try { + return _batchedUpdatesImpl(fn, bookkeeping); + } finally { + // Here we wait until all updates have propagated, which is important + // when using controlled components within layers: + // https://github.com/facebook/react/issues/1698 + // Then we restore state of any controlled component. + isBatching = false; + var controlledComponentsHavePendingUpdates = needsStateRestore(); + if (controlledComponentsHavePendingUpdates) { + // If a controlled event was fired, we may need to restore the state of + // the DOM node back to the controlled value. This is necessary when React + // bails out of the update without touching the DOM. + _flushInteractiveUpdatesImpl(); + restoreStateIfNeeded(); + } + } +} + +function setBatchingImplementation( + batchedUpdatesImpl, + interactiveUpdatesImpl, + flushInteractiveUpdatesImpl +) { + _batchedUpdatesImpl = batchedUpdatesImpl; + _flushInteractiveUpdatesImpl = flushInteractiveUpdatesImpl; +} + +/** + * Version of `ReactBrowserEventEmitter` that works on the receiving side of a + * serialized worker boundary. + */ + +// Shared default empty native event - conserve memory. +var EMPTY_NATIVE_EVENT = {}; + +/** + * Selects a subsequence of `Touch`es, without destroying `touches`. + * + * @param {Array} touches Deserialized touch objects. + * @param {Array} indices Indices by which to pull subsequence. + * @return {Array} Subsequence of touch objects. + */ +var touchSubsequence = function(touches, indices) { + var ret = []; + for (var i = 0; i < indices.length; i++) { + ret.push(touches[indices[i]]); + } + return ret; +}; + +/** + * TODO: Pool all of this. + * + * Destroys `touches` by removing touch objects at indices `indices`. This is + * to maintain compatibility with W3C touch "end" events, where the active + * touches don't include the set that has just been "ended". + * + * @param {Array} touches Deserialized touch objects. + * @param {Array} indices Indices to remove from `touches`. + * @return {Array} Subsequence of removed touch objects. + */ +var removeTouchesAtIndices = function(touches, indices) { + var rippedOut = []; + // use an unsafe downcast to alias to nullable elements, + // so we can delete and then compact. + var temp = touches; + for (var i = 0; i < indices.length; i++) { + var index = indices[i]; + rippedOut.push(touches[index]); + temp[index] = null; + } + var fillAt = 0; + for (var j = 0; j < temp.length; j++) { + var cur = temp[j]; + if (cur !== null) { + temp[fillAt++] = cur; + } + } + temp.length = fillAt; + return rippedOut; +}; + +/** + * Internal version of `receiveEvent` in terms of normalized (non-tag) + * `rootNodeID`. + * + * @see receiveEvent. + * + * @param {rootNodeID} rootNodeID React root node ID that event occurred on. + * @param {TopLevelType} topLevelType Top level type of event. + * @param {?object} nativeEventParam Object passed from native. + */ +function _receiveRootNodeIDEvent(rootNodeID, topLevelType, nativeEventParam) { + var nativeEvent = nativeEventParam || EMPTY_NATIVE_EVENT; + var inst = getInstanceFromTag(rootNodeID); + batchedUpdates(function() { + runExtractedPluginEventsInBatch( + topLevelType, + inst, + nativeEvent, + nativeEvent.target + ); + }); + // React Native doesn't use ReactControlledComponent but if it did, here's + // where it would do it. +} + +/** + * Publicly exposed method on module for native objc to invoke when a top + * level event is extracted. + * @param {rootNodeID} rootNodeID React root node ID that event occurred on. + * @param {TopLevelType} topLevelType Top level type of event. + * @param {object} nativeEventParam Object passed from native. + */ +function receiveEvent(rootNodeID, topLevelType, nativeEventParam) { + _receiveRootNodeIDEvent(rootNodeID, topLevelType, nativeEventParam); +} + +/** + * Simple multi-wrapper around `receiveEvent` that is intended to receive an + * efficient representation of `Touch` objects, and other information that + * can be used to construct W3C compliant `Event` and `Touch` lists. + * + * This may create dispatch behavior that differs than web touch handling. We + * loop through each of the changed touches and receive it as a single event. + * So two `touchStart`/`touchMove`s that occur simultaneously are received as + * two separate touch event dispatches - when they arguably should be one. + * + * This implementation reuses the `Touch` objects themselves as the `Event`s + * since we dispatch an event for each touch (though that might not be spec + * compliant). The main purpose of reusing them is to save allocations. + * + * TODO: Dispatch multiple changed touches in one event. The bubble path + * could be the first common ancestor of all the `changedTouches`. + * + * One difference between this behavior and W3C spec: cancelled touches will + * not appear in `.touches`, or in any future `.touches`, though they may + * still be "actively touching the surface". + * + * Web desktop polyfills only need to construct a fake touch event with + * identifier 0, also abandoning traditional click handlers. + */ +function receiveTouches(eventTopLevelType, touches, changedIndices) { + var changedTouches = + eventTopLevelType === "topTouchEnd" || + eventTopLevelType === "topTouchCancel" + ? removeTouchesAtIndices(touches, changedIndices) + : touchSubsequence(touches, changedIndices); + + for (var jj = 0; jj < changedTouches.length; jj++) { + var touch = changedTouches[jj]; + // Touch objects can fulfill the role of `DOM` `Event` objects if we set + // the `changedTouches`/`touches`. This saves allocations. + touch.changedTouches = changedTouches; + touch.touches = touches; + var nativeEvent = touch; + var rootNodeID = null; + var target = nativeEvent.target; + if (target !== null && target !== undefined) { + if (target < 1) { + { + warningWithoutStack$1( + false, + "A view is reporting that a touch occurred on tag zero." + ); + } + } else { + rootNodeID = target; + } + } + // $FlowFixMe Shouldn't we *not* call it if rootNodeID is null? + _receiveRootNodeIDEvent(rootNodeID, eventTopLevelType, nativeEvent); + } +} + +// Module provided by RN: +var ReactNativeGlobalResponderHandler = { + onChange: function(from, to, blockNativeResponder) { + if (to !== null) { + var tag = to.stateNode._nativeTag; + ReactNativePrivateInterface.UIManager.setJSResponder( + tag, + blockNativeResponder + ); + } else { + ReactNativePrivateInterface.UIManager.clearJSResponder(); + } + } +}; + +// Module provided by RN: +/** + * Register the event emitter with the native bridge + */ +ReactNativePrivateInterface.RCTEventEmitter.register({ + receiveEvent: receiveEvent, + receiveTouches: receiveTouches +}); + +setComponentTree( + getFiberCurrentPropsFromNode$1, + getInstanceFromTag, + getTagFromInstance +); + +ResponderEventPlugin.injection.injectGlobalResponderHandler( + ReactNativeGlobalResponderHandler +); + +/** + * `ReactInstanceMap` maintains a mapping from a public facing stateful + * instance (key) and the internal representation (value). This allows public + * methods to accept the user facing instance as an argument and map them back + * to internal methods. + * + * Note that this module is currently shared and assumed to be stateless. + * If this becomes an actual Map, that will break. + */ + +/** + * This API should be called `delete` but we'd have to make sure to always + * transform these to strings for IE support. When this transform is fully + * supported we can rename it. + */ + +function get(key) { + return key._reactInternalFiber; +} + +function set(key, value) { + key._reactInternalFiber = value; +} + +var ReactSharedInternals = + React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; + +// Prevent newer renderers from RTE when used with older react package versions. +// Current owner and dispatcher used to share the same ref, +// but PR #14548 split them out to better support the react-debug-tools package. +if (!ReactSharedInternals.hasOwnProperty("ReactCurrentDispatcher")) { + ReactSharedInternals.ReactCurrentDispatcher = { + current: null + }; +} + +// The Symbol used to tag the ReactElement-like types. If there is no native Symbol +// nor polyfill, then a plain number is used for performance. +var hasSymbol = typeof Symbol === "function" && Symbol.for; + +var REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for("react.element") : 0xeac7; +var REACT_PORTAL_TYPE = hasSymbol ? Symbol.for("react.portal") : 0xeaca; +var REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for("react.fragment") : 0xeacb; +var REACT_STRICT_MODE_TYPE = hasSymbol + ? Symbol.for("react.strict_mode") + : 0xeacc; +var REACT_PROFILER_TYPE = hasSymbol ? Symbol.for("react.profiler") : 0xead2; +var REACT_PROVIDER_TYPE = hasSymbol ? Symbol.for("react.provider") : 0xeacd; +var REACT_CONTEXT_TYPE = hasSymbol ? Symbol.for("react.context") : 0xeace; + +var REACT_CONCURRENT_MODE_TYPE = hasSymbol + ? Symbol.for("react.concurrent_mode") + : 0xeacf; +var REACT_FORWARD_REF_TYPE = hasSymbol + ? Symbol.for("react.forward_ref") + : 0xead0; +var REACT_SUSPENSE_TYPE = hasSymbol ? Symbol.for("react.suspense") : 0xead1; +var REACT_MEMO_TYPE = hasSymbol ? Symbol.for("react.memo") : 0xead3; +var REACT_LAZY_TYPE = hasSymbol ? Symbol.for("react.lazy") : 0xead4; +var REACT_EVENT_COMPONENT_TYPE = hasSymbol + ? Symbol.for("react.event_component") + : 0xead5; +var REACT_EVENT_TARGET_TYPE = hasSymbol + ? Symbol.for("react.event_target") + : 0xead6; + +// React event targets +var REACT_EVENT_TARGET_TOUCH_HIT = hasSymbol + ? Symbol.for("react.event_target.touch_hit") + : 0xead7; + +var MAYBE_ITERATOR_SYMBOL = typeof Symbol === "function" && Symbol.iterator; +var FAUX_ITERATOR_SYMBOL = "@@iterator"; + +function getIteratorFn(maybeIterable) { + if (maybeIterable === null || typeof maybeIterable !== "object") { + return null; + } + var maybeIterator = + (MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL]) || + maybeIterable[FAUX_ITERATOR_SYMBOL]; + if (typeof maybeIterator === "function") { + return maybeIterator; + } + return null; +} + +var Pending = 0; +var Resolved = 1; +var Rejected = 2; + +function refineResolvedLazyComponent(lazyComponent) { + return lazyComponent._status === Resolved ? lazyComponent._result : null; +} + +// Re-export dynamic flags from the fbsource version. +var _require = require("../shims/ReactFeatureFlags"); + +var debugRenderPhaseSideEffects = _require.debugRenderPhaseSideEffects; + +var enableUserTimingAPI = true; +var enableProfilerTimer = true; +var enableSchedulerTracing = true; +var enableSuspenseServerRenderer = false; + +var debugRenderPhaseSideEffectsForStrictMode = true; + +var disableYielding = false; + +var replayFailedUnitOfWorkWithInvokeGuardedCallback = true; +var warnAboutDeprecatedLifecycles = true; +var warnAboutDeprecatedSetNativeProps = true; +var enableEventAPI = false; + +// Only used in www builds. + +function getWrappedName(outerType, innerType, wrapperName) { + var functionName = innerType.displayName || innerType.name || ""; + return ( + outerType.displayName || + (functionName !== "" ? wrapperName + "(" + functionName + ")" : wrapperName) + ); +} + +function getComponentName(type) { + if (type == null) { + // Host root, text node or just invalid type. + return null; + } + { + if (typeof type.tag === "number") { + warningWithoutStack$1( + false, + "Received an unexpected object in getComponentName(). " + + "This is likely a bug in React. Please file an issue." + ); + } + } + if (typeof type === "function") { + return type.displayName || type.name || null; + } + if (typeof type === "string") { + return type; + } + switch (type) { + case REACT_CONCURRENT_MODE_TYPE: + return "ConcurrentMode"; + case REACT_FRAGMENT_TYPE: + return "Fragment"; + case REACT_PORTAL_TYPE: + return "Portal"; + case REACT_PROFILER_TYPE: + return "Profiler"; + case REACT_STRICT_MODE_TYPE: + return "StrictMode"; + case REACT_SUSPENSE_TYPE: + return "Suspense"; + } + if (typeof type === "object") { + switch (type.$$typeof) { + case REACT_CONTEXT_TYPE: + return "Context.Consumer"; + case REACT_PROVIDER_TYPE: + return "Context.Provider"; + case REACT_FORWARD_REF_TYPE: + return getWrappedName(type, type.render, "ForwardRef"); + case REACT_MEMO_TYPE: + return getComponentName(type.type); + case REACT_LAZY_TYPE: { + var thenable = type; + var resolvedThenable = refineResolvedLazyComponent(thenable); + if (resolvedThenable) { + return getComponentName(resolvedThenable); + } + break; + } + case REACT_EVENT_COMPONENT_TYPE: { + if (enableEventAPI) { + var eventComponent = type; + var displayName = eventComponent.displayName; + if (displayName !== undefined) { + return displayName; + } + } + break; + } + case REACT_EVENT_TARGET_TYPE: { + if (enableEventAPI) { + var eventTarget = type; + if (eventTarget.type === REACT_EVENT_TARGET_TOUCH_HIT) { + return "TouchHitTarget"; + } + var _displayName = eventTarget.displayName; + if (_displayName !== undefined) { + return _displayName; + } + } + } + } + } + return null; +} + +// Don't change these two values. They're used by React Dev Tools. +var NoEffect = /* */ 0; +var PerformedWork = /* */ 1; + +// You can change the rest (and add more). +var Placement = /* */ 2; +var Update = /* */ 4; +var PlacementAndUpdate = /* */ 6; +var Deletion = /* */ 8; +var ContentReset = /* */ 16; +var Callback = /* */ 32; +var DidCapture = /* */ 64; +var Ref = /* */ 128; +var Snapshot = /* */ 256; +var Passive = /* */ 512; + +// Passive & Update & Callback & Ref & Snapshot +var LifecycleEffectMask = /* */ 932; + +// Union of all host effects +var HostEffectMask = /* */ 1023; + +var Incomplete = /* */ 1024; +var ShouldCapture = /* */ 2048; + +var ReactCurrentOwner$1 = ReactSharedInternals.ReactCurrentOwner; + +var MOUNTING = 1; +var MOUNTED = 2; +var UNMOUNTED = 3; + +function isFiberMountedImpl(fiber) { + var node = fiber; + if (!fiber.alternate) { + // If there is no alternate, this might be a new tree that isn't inserted + // yet. If it is, then it will have a pending insertion effect on it. + if ((node.effectTag & Placement) !== NoEffect) { + return MOUNTING; + } + while (node.return) { + node = node.return; + if ((node.effectTag & Placement) !== NoEffect) { + return MOUNTING; + } + } + } else { + while (node.return) { + node = node.return; + } + } + if (node.tag === HostRoot) { + // TODO: Check if this was a nested HostRoot when used with + // renderContainerIntoSubtree. + return MOUNTED; + } + // If we didn't hit the root, that means that we're in an disconnected tree + // that has been unmounted. + return UNMOUNTED; +} + +function isFiberMounted(fiber) { + return isFiberMountedImpl(fiber) === MOUNTED; +} + +function isMounted(component) { + { + var owner = ReactCurrentOwner$1.current; + if (owner !== null && owner.tag === ClassComponent) { + var ownerFiber = owner; + var instance = ownerFiber.stateNode; + !instance._warnedAboutRefsInRender + ? warningWithoutStack$1( + false, + "%s is accessing isMounted inside its render() function. " + + "render() should be a pure function of props and state. It should " + + "never access something that requires stale data from the previous " + + "render, such as refs. Move this logic to componentDidMount and " + + "componentDidUpdate instead.", + getComponentName(ownerFiber.type) || "A component" + ) + : void 0; + instance._warnedAboutRefsInRender = true; + } + } + + var fiber = get(component); + if (!fiber) { + return false; + } + return isFiberMountedImpl(fiber) === MOUNTED; +} + +function assertIsMounted(fiber) { + (function() { + if (!(isFiberMountedImpl(fiber) === MOUNTED)) { + throw ReactError("Unable to find node on an unmounted component."); + } + })(); +} + +function findCurrentFiberUsingSlowPath(fiber) { + var alternate = fiber.alternate; + if (!alternate) { + // If there is no alternate, then we only need to check if it is mounted. + var state = isFiberMountedImpl(fiber); + (function() { + if (!(state !== UNMOUNTED)) { + throw ReactError("Unable to find node on an unmounted component."); + } + })(); + if (state === MOUNTING) { + return null; + } + return fiber; + } + // If we have two possible branches, we'll walk backwards up to the root + // to see what path the root points to. On the way we may hit one of the + // special cases and we'll deal with them. + var a = fiber; + var b = alternate; + while (true) { + var parentA = a.return; + if (parentA === null) { + // We're at the root. + break; + } + var parentB = parentA.alternate; + if (parentB === null) { + // There is no alternate. This is an unusual case. Currently, it only + // happens when a Suspense component is hidden. An extra fragment fiber + // is inserted in between the Suspense fiber and its children. Skip + // over this extra fragment fiber and proceed to the next parent. + var nextParent = parentA.return; + if (nextParent !== null) { + a = b = nextParent; + continue; + } + // If there's no parent, we're at the root. + break; + } + + // If both copies of the parent fiber point to the same child, we can + // assume that the child is current. This happens when we bailout on low + // priority: the bailed out fiber's child reuses the current child. + if (parentA.child === parentB.child) { + var child = parentA.child; + while (child) { + if (child === a) { + // We've determined that A is the current branch. + assertIsMounted(parentA); + return fiber; + } + if (child === b) { + // We've determined that B is the current branch. + assertIsMounted(parentA); + return alternate; + } + child = child.sibling; + } + // We should never have an alternate for any mounting node. So the only + // way this could possibly happen is if this was unmounted, if at all. + (function() { + { + throw ReactError("Unable to find node on an unmounted component."); + } + })(); + } + + if (a.return !== b.return) { + // The return pointer of A and the return pointer of B point to different + // fibers. We assume that return pointers never criss-cross, so A must + // belong to the child set of A.return, and B must belong to the child + // set of B.return. + a = parentA; + b = parentB; + } else { + // The return pointers point to the same fiber. We'll have to use the + // default, slow path: scan the child sets of each parent alternate to see + // which child belongs to which set. + // + // Search parent A's child set + var didFindChild = false; + var _child = parentA.child; + while (_child) { + if (_child === a) { + didFindChild = true; + a = parentA; + b = parentB; + break; + } + if (_child === b) { + didFindChild = true; + b = parentA; + a = parentB; + break; + } + _child = _child.sibling; + } + if (!didFindChild) { + // Search parent B's child set + _child = parentB.child; + while (_child) { + if (_child === a) { + didFindChild = true; + a = parentB; + b = parentA; + break; + } + if (_child === b) { + didFindChild = true; + b = parentB; + a = parentA; + break; + } + _child = _child.sibling; + } + (function() { + if (!didFindChild) { + throw ReactError( + "Child was not found in either parent set. This indicates a bug in React related to the return pointer. Please file an issue." + ); + } + })(); + } + } + + (function() { + if (!(a.alternate === b)) { + throw ReactError( + "Return fibers should always be each others' alternates. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + // If the root is not a host container, we're in a disconnected tree. I.e. + // unmounted. + (function() { + if (!(a.tag === HostRoot)) { + throw ReactError("Unable to find node on an unmounted component."); + } + })(); + if (a.stateNode.current === a) { + // We've determined that A is the current branch. + return fiber; + } + // Otherwise B has to be current branch. + return alternate; +} + +function findCurrentHostFiber(parent) { + var currentParent = findCurrentFiberUsingSlowPath(parent); + if (!currentParent) { + return null; + } + + // Next we'll drill down this component to find the first HostComponent/Text. + var node = currentParent; + while (true) { + if (node.tag === HostComponent || node.tag === HostText) { + return node; + } else if (node.child) { + node.child.return = node; + node = node.child; + continue; + } + if (node === currentParent) { + return null; + } + while (!node.sibling) { + if (!node.return || node.return === currentParent) { + return null; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + // Flow needs the return null here, but ESLint complains about it. + // eslint-disable-next-line no-unreachable + return null; +} + +// Modules provided by RN: +var emptyObject = {}; + +/** + * Create a payload that contains all the updates between two sets of props. + * + * These helpers are all encapsulated into a single module, because they use + * mutation as a performance optimization which leads to subtle shared + * dependencies between the code paths. To avoid this mutable state leaking + * across modules, I've kept them isolated to this module. + */ + +// Tracks removed keys +var removedKeys = null; +var removedKeyCount = 0; + +function defaultDiffer(prevProp, nextProp) { + if (typeof nextProp !== "object" || nextProp === null) { + // Scalars have already been checked for equality + return true; + } else { + // For objects and arrays, the default diffing algorithm is a deep compare + return ReactNativePrivateInterface.deepDiffer(prevProp, nextProp); + } +} + +function restoreDeletedValuesInNestedArray( + updatePayload, + node, + validAttributes +) { + if (Array.isArray(node)) { + var i = node.length; + while (i-- && removedKeyCount > 0) { + restoreDeletedValuesInNestedArray( + updatePayload, + node[i], + validAttributes + ); + } + } else if (node && removedKeyCount > 0) { + var obj = node; + for (var propKey in removedKeys) { + if (!removedKeys[propKey]) { + continue; + } + var nextProp = obj[propKey]; + if (nextProp === undefined) { + continue; + } + + var attributeConfig = validAttributes[propKey]; + if (!attributeConfig) { + continue; // not a valid native prop + } + + if (typeof nextProp === "function") { + nextProp = true; + } + if (typeof nextProp === "undefined") { + nextProp = null; + } + + if (typeof attributeConfig !== "object") { + // case: !Object is the default case + updatePayload[propKey] = nextProp; + } else if ( + typeof attributeConfig.diff === "function" || + typeof attributeConfig.process === "function" + ) { + // case: CustomAttributeConfiguration + var nextValue = + typeof attributeConfig.process === "function" + ? attributeConfig.process(nextProp) + : nextProp; + updatePayload[propKey] = nextValue; + } + removedKeys[propKey] = false; + removedKeyCount--; + } + } +} + +function diffNestedArrayProperty( + updatePayload, + prevArray, + nextArray, + validAttributes +) { + var minLength = + prevArray.length < nextArray.length ? prevArray.length : nextArray.length; + var i = void 0; + for (i = 0; i < minLength; i++) { + // Diff any items in the array in the forward direction. Repeated keys + // will be overwritten by later values. + updatePayload = diffNestedProperty( + updatePayload, + prevArray[i], + nextArray[i], + validAttributes + ); + } + for (; i < prevArray.length; i++) { + // Clear out all remaining properties. + updatePayload = clearNestedProperty( + updatePayload, + prevArray[i], + validAttributes + ); + } + for (; i < nextArray.length; i++) { + // Add all remaining properties. + updatePayload = addNestedProperty( + updatePayload, + nextArray[i], + validAttributes + ); + } + return updatePayload; +} + +function diffNestedProperty( + updatePayload, + prevProp, + nextProp, + validAttributes +) { + if (!updatePayload && prevProp === nextProp) { + // If no properties have been added, then we can bail out quickly on object + // equality. + return updatePayload; + } + + if (!prevProp || !nextProp) { + if (nextProp) { + return addNestedProperty(updatePayload, nextProp, validAttributes); + } + if (prevProp) { + return clearNestedProperty(updatePayload, prevProp, validAttributes); + } + return updatePayload; + } + + if (!Array.isArray(prevProp) && !Array.isArray(nextProp)) { + // Both are leaves, we can diff the leaves. + return diffProperties(updatePayload, prevProp, nextProp, validAttributes); + } + + if (Array.isArray(prevProp) && Array.isArray(nextProp)) { + // Both are arrays, we can diff the arrays. + return diffNestedArrayProperty( + updatePayload, + prevProp, + nextProp, + validAttributes + ); + } + + if (Array.isArray(prevProp)) { + return diffProperties( + updatePayload, + // $FlowFixMe - We know that this is always an object when the input is. + ReactNativePrivateInterface.flattenStyle(prevProp), + // $FlowFixMe - We know that this isn't an array because of above flow. + nextProp, + validAttributes + ); + } + + return diffProperties( + updatePayload, + prevProp, + // $FlowFixMe - We know that this is always an object when the input is. + ReactNativePrivateInterface.flattenStyle(nextProp), + validAttributes + ); +} + +/** + * addNestedProperty takes a single set of props and valid attribute + * attribute configurations. It processes each prop and adds it to the + * updatePayload. + */ +function addNestedProperty(updatePayload, nextProp, validAttributes) { + if (!nextProp) { + return updatePayload; + } + + if (!Array.isArray(nextProp)) { + // Add each property of the leaf. + return addProperties(updatePayload, nextProp, validAttributes); + } + + for (var i = 0; i < nextProp.length; i++) { + // Add all the properties of the array. + updatePayload = addNestedProperty( + updatePayload, + nextProp[i], + validAttributes + ); + } + + return updatePayload; +} + +/** + * clearNestedProperty takes a single set of props and valid attributes. It + * adds a null sentinel to the updatePayload, for each prop key. + */ +function clearNestedProperty(updatePayload, prevProp, validAttributes) { + if (!prevProp) { + return updatePayload; + } + + if (!Array.isArray(prevProp)) { + // Add each property of the leaf. + return clearProperties(updatePayload, prevProp, validAttributes); + } + + for (var i = 0; i < prevProp.length; i++) { + // Add all the properties of the array. + updatePayload = clearNestedProperty( + updatePayload, + prevProp[i], + validAttributes + ); + } + return updatePayload; +} + +/** + * diffProperties takes two sets of props and a set of valid attributes + * and write to updatePayload the values that changed or were deleted. + * If no updatePayload is provided, a new one is created and returned if + * anything changed. + */ +function diffProperties(updatePayload, prevProps, nextProps, validAttributes) { + var attributeConfig = void 0; + var nextProp = void 0; + var prevProp = void 0; + + for (var propKey in nextProps) { + attributeConfig = validAttributes[propKey]; + if (!attributeConfig) { + continue; // not a valid native prop + } + + prevProp = prevProps[propKey]; + nextProp = nextProps[propKey]; + + // functions are converted to booleans as markers that the associated + // events should be sent from native. + if (typeof nextProp === "function") { + nextProp = true; + // If nextProp is not a function, then don't bother changing prevProp + // since nextProp will win and go into the updatePayload regardless. + if (typeof prevProp === "function") { + prevProp = true; + } + } + + // An explicit value of undefined is treated as a null because it overrides + // any other preceding value. + if (typeof nextProp === "undefined") { + nextProp = null; + if (typeof prevProp === "undefined") { + prevProp = null; + } + } + + if (removedKeys) { + removedKeys[propKey] = false; + } + + if (updatePayload && updatePayload[propKey] !== undefined) { + // Something else already triggered an update to this key because another + // value diffed. Since we're now later in the nested arrays our value is + // more important so we need to calculate it and override the existing + // value. It doesn't matter if nothing changed, we'll set it anyway. + + // Pattern match on: attributeConfig + if (typeof attributeConfig !== "object") { + // case: !Object is the default case + updatePayload[propKey] = nextProp; + } else if ( + typeof attributeConfig.diff === "function" || + typeof attributeConfig.process === "function" + ) { + // case: CustomAttributeConfiguration + var nextValue = + typeof attributeConfig.process === "function" + ? attributeConfig.process(nextProp) + : nextProp; + updatePayload[propKey] = nextValue; + } + continue; + } + + if (prevProp === nextProp) { + continue; // nothing changed + } + + // Pattern match on: attributeConfig + if (typeof attributeConfig !== "object") { + // case: !Object is the default case + if (defaultDiffer(prevProp, nextProp)) { + // a normal leaf has changed + (updatePayload || (updatePayload = {}))[propKey] = nextProp; + } + } else if ( + typeof attributeConfig.diff === "function" || + typeof attributeConfig.process === "function" + ) { + // case: CustomAttributeConfiguration + var shouldUpdate = + prevProp === undefined || + (typeof attributeConfig.diff === "function" + ? attributeConfig.diff(prevProp, nextProp) + : defaultDiffer(prevProp, nextProp)); + if (shouldUpdate) { + var _nextValue = + typeof attributeConfig.process === "function" + ? attributeConfig.process(nextProp) + : nextProp; + (updatePayload || (updatePayload = {}))[propKey] = _nextValue; + } + } else { + // default: fallthrough case when nested properties are defined + removedKeys = null; + removedKeyCount = 0; + // We think that attributeConfig is not CustomAttributeConfiguration at + // this point so we assume it must be AttributeConfiguration. + updatePayload = diffNestedProperty( + updatePayload, + prevProp, + nextProp, + attributeConfig + ); + if (removedKeyCount > 0 && updatePayload) { + restoreDeletedValuesInNestedArray( + updatePayload, + nextProp, + attributeConfig + ); + removedKeys = null; + } + } + } + + // Also iterate through all the previous props to catch any that have been + // removed and make sure native gets the signal so it can reset them to the + // default. + for (var _propKey in prevProps) { + if (nextProps[_propKey] !== undefined) { + continue; // we've already covered this key in the previous pass + } + attributeConfig = validAttributes[_propKey]; + if (!attributeConfig) { + continue; // not a valid native prop + } + + if (updatePayload && updatePayload[_propKey] !== undefined) { + // This was already updated to a diff result earlier. + continue; + } + + prevProp = prevProps[_propKey]; + if (prevProp === undefined) { + continue; // was already empty anyway + } + // Pattern match on: attributeConfig + if ( + typeof attributeConfig !== "object" || + typeof attributeConfig.diff === "function" || + typeof attributeConfig.process === "function" + ) { + // case: CustomAttributeConfiguration | !Object + // Flag the leaf property for removal by sending a sentinel. + (updatePayload || (updatePayload = {}))[_propKey] = null; + if (!removedKeys) { + removedKeys = {}; + } + if (!removedKeys[_propKey]) { + removedKeys[_propKey] = true; + removedKeyCount++; + } + } else { + // default: + // This is a nested attribute configuration where all the properties + // were removed so we need to go through and clear out all of them. + updatePayload = clearNestedProperty( + updatePayload, + prevProp, + attributeConfig + ); + } + } + return updatePayload; +} + +/** + * addProperties adds all the valid props to the payload after being processed. + */ +function addProperties(updatePayload, props, validAttributes) { + // TODO: Fast path + return diffProperties(updatePayload, emptyObject, props, validAttributes); +} + +/** + * clearProperties clears all the previous props by adding a null sentinel + * to the payload for each valid key. + */ +function clearProperties(updatePayload, prevProps, validAttributes) { + // TODO: Fast path + return diffProperties(updatePayload, prevProps, emptyObject, validAttributes); +} + +function create(props, validAttributes) { + return addProperties( + null, // updatePayload + props, + validAttributes + ); +} + +function diff(prevProps, nextProps, validAttributes) { + return diffProperties( + null, // updatePayload + prevProps, + nextProps, + validAttributes + ); +} + +/** + * In the future, we should cleanup callbacks by cancelling them instead of + * using this. + */ +function mountSafeCallback_NOT_REALLY_SAFE(context, callback) { + return function() { + if (!callback) { + return undefined; + } + // This protects against createClass() components. + // We don't know if there is code depending on it. + // We intentionally don't use isMounted() because even accessing + // isMounted property on a React ES6 class will trigger a warning. + if (typeof context.__isMounted === "boolean") { + if (!context.__isMounted) { + return undefined; + } + } + + // FIXME: there used to be other branches that protected + // against unmounted host components. But RN host components don't + // define isMounted() anymore, so those checks didn't do anything. + + // They caused false positive warning noise so we removed them: + // https://github.com/facebook/react-native/issues/18868#issuecomment-413579095 + + // However, this means that the callback is NOT guaranteed to be safe + // for host components. The solution we should implement is to make + // UIManager.measure() and similar calls truly cancelable. Then we + // can change our own code calling them to cancel when something unmounts. + + return callback.apply(context, arguments); + }; +} + +function throwOnStylesProp(component, props) { + if (props.styles !== undefined) { + var owner = component._owner || null; + var name = component.constructor.displayName; + var msg = + "`styles` is not a supported property of `" + + name + + "`, did " + + "you mean `style` (singular)?"; + if (owner && owner.constructor && owner.constructor.displayName) { + msg += + "\n\nCheck the `" + + owner.constructor.displayName + + "` parent " + + " component."; + } + throw new Error(msg); + } +} + +function warnForStyleProps(props, validAttributes) { + for (var key in validAttributes.style) { + if (!(validAttributes[key] || props[key] === undefined)) { + console.error( + "You are setting the style `{ " + + key + + ": ... }` as a prop. You " + + "should nest it in a style object. " + + "E.g. `{ style: { " + + key + + ": ... } }`" + ); + } + } +} + +function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } +} + +// Modules provided by RN: +/** + * This component defines the same methods as NativeMethodsMixin but without the + * findNodeHandle wrapper. This wrapper is unnecessary for HostComponent views + * and would also result in a circular require.js dependency (since + * ReactNativeFiber depends on this component and NativeMethodsMixin depends on + * ReactNativeFiber). + */ + +var ReactNativeFiberHostComponent = (function() { + function ReactNativeFiberHostComponent(tag, viewConfig) { + _classCallCheck(this, ReactNativeFiberHostComponent); + + this._nativeTag = tag; + this._children = []; + this.viewConfig = viewConfig; + } + + ReactNativeFiberHostComponent.prototype.blur = function blur() { + ReactNativePrivateInterface.TextInputState.blurTextInput(this._nativeTag); + }; + + ReactNativeFiberHostComponent.prototype.focus = function focus() { + ReactNativePrivateInterface.TextInputState.focusTextInput(this._nativeTag); + }; + + ReactNativeFiberHostComponent.prototype.measure = function measure(callback) { + ReactNativePrivateInterface.UIManager.measure( + this._nativeTag, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + }; + + ReactNativeFiberHostComponent.prototype.measureInWindow = function measureInWindow( + callback + ) { + ReactNativePrivateInterface.UIManager.measureInWindow( + this._nativeTag, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + }; + + ReactNativeFiberHostComponent.prototype.measureLayout = function measureLayout( + relativeToNativeNode, + onSuccess, + onFail /* currently unused */ + ) { + var relativeNode = void 0; + + if (typeof relativeToNativeNode === "number") { + // Already a node handle + relativeNode = relativeToNativeNode; + } else if (relativeToNativeNode._nativeTag) { + relativeNode = relativeToNativeNode._nativeTag; + } else if ( + relativeToNativeNode.canonical && + relativeToNativeNode.canonical._nativeTag + ) { + relativeNode = relativeToNativeNode.canonical._nativeTag; + } + + if (relativeNode == null) { + warningWithoutStack$1( + false, + "Warning: ref.measureLayout must be called with a node handle or a ref to a native component." + ); + + return; + } + + ReactNativePrivateInterface.UIManager.measureLayout( + this._nativeTag, + relativeNode, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + ); + }; + + ReactNativeFiberHostComponent.prototype.setNativeProps = function setNativeProps( + nativeProps + ) { + { + if (warnAboutDeprecatedSetNativeProps) { + warningWithoutStack$1( + false, + "Warning: Calling ref.setNativeProps(nativeProps) " + + "is deprecated and will be removed in a future release. " + + "Use the setNativeProps export from the react-native package instead." + + "\n\timport {setNativeProps} from 'react-native';\n\tsetNativeProps(ref, nativeProps);\n" + ); + } + warnForStyleProps(nativeProps, this.viewConfig.validAttributes); + } + + var updatePayload = create(nativeProps, this.viewConfig.validAttributes); + + // Avoid the overhead of bridge calls if there's no update. + // This is an expensive no-op for Android, and causes an unnecessary + // view invalidation for certain components (eg RCTTextInput) on iOS. + if (updatePayload != null) { + ReactNativePrivateInterface.UIManager.updateView( + this._nativeTag, + this.viewConfig.uiViewClassName, + updatePayload + ); + } + }; + + return ReactNativeFiberHostComponent; +})(); + +// Renderers that don't support persistence +// can re-export everything from this module. + +function shim() { + (function() { + { + throw ReactError( + "The current renderer does not support persistence. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); +} + +// Persistence (when unsupported) +var supportsPersistence = false; +var cloneInstance = shim; +var createContainerChildSet = shim; +var appendChildToContainerChildSet = shim; +var finalizeContainerChildren = shim; +var replaceContainerChildren = shim; +var cloneHiddenInstance = shim; +var cloneHiddenTextInstance = shim; + +// Renderers that don't support hydration +// can re-export everything from this module. + +function shim$1() { + (function() { + { + throw ReactError( + "The current renderer does not support hydration. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); +} + +// Hydration (when unsupported) + +var supportsHydration = false; +var canHydrateInstance = shim$1; +var canHydrateTextInstance = shim$1; +var canHydrateSuspenseInstance = shim$1; +var isSuspenseInstancePending = shim$1; +var isSuspenseInstanceFallback = shim$1; +var registerSuspenseInstanceRetry = shim$1; +var getNextHydratableSibling = shim$1; +var getFirstHydratableChild = shim$1; +var hydrateInstance = shim$1; +var hydrateTextInstance = shim$1; +var getNextHydratableInstanceAfterSuspenseInstance = shim$1; +var clearSuspenseBoundary = shim$1; +var clearSuspenseBoundaryFromContainer = shim$1; +var didNotMatchHydratedContainerTextInstance = shim$1; +var didNotMatchHydratedTextInstance = shim$1; +var didNotHydrateContainerInstance = shim$1; +var didNotHydrateInstance = shim$1; +var didNotFindHydratableContainerInstance = shim$1; +var didNotFindHydratableContainerTextInstance = shim$1; +var didNotFindHydratableContainerSuspenseInstance = shim$1; +var didNotFindHydratableInstance = shim$1; +var didNotFindHydratableTextInstance = shim$1; +var didNotFindHydratableSuspenseInstance = shim$1; + +// Modules provided by RN: +var getViewConfigForType = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.get; // Unused +// Unused + +var UPDATE_SIGNAL = {}; +{ + Object.freeze(UPDATE_SIGNAL); +} + +// Counter for uniquely identifying views. +// % 10 === 1 means it is a rootTag. +// % 2 === 0 means it is a Fabric tag. +var nextReactTag = 3; +function allocateTag() { + var tag = nextReactTag; + if (tag % 10 === 1) { + tag += 2; + } + nextReactTag = tag + 2; + return tag; +} + +function recursivelyUncacheFiberNode(node) { + if (typeof node === "number") { + // Leaf node (eg text) + uncacheFiberNode(node); + } else { + uncacheFiberNode(node._nativeTag); + + node._children.forEach(recursivelyUncacheFiberNode); + } +} + +function appendInitialChild(parentInstance, child) { + parentInstance._children.push(child); +} + +function createInstance( + type, + props, + rootContainerInstance, + hostContext, + internalInstanceHandle +) { + var tag = allocateTag(); + var viewConfig = getViewConfigForType(type); + + { + for (var key in viewConfig.validAttributes) { + if (props.hasOwnProperty(key)) { + ReactNativePrivateInterface.deepFreezeAndThrowOnMutationInDev( + props[key] + ); + } + } + } + + var updatePayload = create(props, viewConfig.validAttributes); + + ReactNativePrivateInterface.UIManager.createView( + tag, // reactTag + viewConfig.uiViewClassName, // viewName + rootContainerInstance, // rootTag + updatePayload // props + ); + + var component = new ReactNativeFiberHostComponent(tag, viewConfig); + + precacheFiberNode(internalInstanceHandle, tag); + updateFiberProps(tag, props); + + // Not sure how to avoid this cast. Flow is okay if the component is defined + // in the same file but if it's external it can't see the types. + return component; +} + +function createTextInstance( + text, + rootContainerInstance, + hostContext, + internalInstanceHandle +) { + (function() { + if (!hostContext.isInAParentText) { + throw ReactError( + "Text strings must be rendered within a component." + ); + } + })(); + + var tag = allocateTag(); + + ReactNativePrivateInterface.UIManager.createView( + tag, // reactTag + "RCTRawText", // viewName + rootContainerInstance, // rootTag + { text: text } // props + ); + + precacheFiberNode(internalInstanceHandle, tag); + + return tag; +} + +function finalizeInitialChildren( + parentInstance, + type, + props, + rootContainerInstance, + hostContext +) { + // Don't send a no-op message over the bridge. + if (parentInstance._children.length === 0) { + return false; + } + + // Map from child objects to native tags. + // Either way we need to pass a copy of the Array to prevent it from being frozen. + var nativeTags = parentInstance._children.map(function(child) { + return typeof child === "number" + ? child // Leaf node (eg text) + : child._nativeTag; + }); + + ReactNativePrivateInterface.UIManager.setChildren( + parentInstance._nativeTag, // containerTag + nativeTags // reactTags + ); + + return false; +} + +function getRootHostContext(rootContainerInstance) { + return { isInAParentText: false }; +} + +function getChildHostContext(parentHostContext, type, rootContainerInstance) { + var prevIsInAParentText = parentHostContext.isInAParentText; + var isInAParentText = + type === "AndroidTextInput" || // Android + type === "RCTMultilineTextInputView" || // iOS + type === "RCTSinglelineTextInputView" || // iOS + type === "RCTText" || + type === "RCTVirtualText"; + + if (prevIsInAParentText !== isInAParentText) { + return { isInAParentText: isInAParentText }; + } else { + return parentHostContext; + } +} + +function getChildHostContextForEventComponent(parentHostContext) { + // TODO: add getChildHostContextForEventComponent implementation + return parentHostContext; +} + +function getChildHostContextForEventTarget(parentHostContext, type) { + // TODO: add getChildHostContextForEventTarget implementation + return parentHostContext; +} + +function getPublicInstance(instance) { + return instance; +} + +function prepareForCommit(containerInfo) { + // Noop +} + +function prepareUpdate( + instance, + type, + oldProps, + newProps, + rootContainerInstance, + hostContext +) { + return UPDATE_SIGNAL; +} + +function resetAfterCommit(containerInfo) { + // Noop +} + +var isPrimaryRenderer = true; + +var scheduleTimeout = setTimeout; +var cancelTimeout = clearTimeout; +var noTimeout = -1; + +function shouldDeprioritizeSubtree(type, props) { + return false; +} + +function shouldSetTextContent(type, props) { + // TODO (bvaughn) Revisit this decision. + // Always returning false simplifies the createInstance() implementation, + // But creates an additional child Fiber for raw text children. + // No additional native views are created though. + // It's not clear to me which is better so I'm deferring for now. + // More context @ github.com/facebook/react/pull/8560#discussion_r92111303 + return false; +} + +// ------------------- +// Mutation +// ------------------- + +var supportsMutation = true; + +function appendChild(parentInstance, child) { + var childTag = typeof child === "number" ? child : child._nativeTag; + var children = parentInstance._children; + var index = children.indexOf(child); + + if (index >= 0) { + children.splice(index, 1); + children.push(child); + + ReactNativePrivateInterface.UIManager.manageChildren( + parentInstance._nativeTag, // containerTag + [index], // moveFromIndices + [children.length - 1], // moveToIndices + [], // addChildReactTags + [], // addAtIndices + [] // removeAtIndices + ); + } else { + children.push(child); + + ReactNativePrivateInterface.UIManager.manageChildren( + parentInstance._nativeTag, // containerTag + [], // moveFromIndices + [], // moveToIndices + [childTag], // addChildReactTags + [children.length - 1], // addAtIndices + [] // removeAtIndices + ); + } +} + +function appendChildToContainer(parentInstance, child) { + var childTag = typeof child === "number" ? child : child._nativeTag; + ReactNativePrivateInterface.UIManager.setChildren( + parentInstance, // containerTag + [childTag] // reactTags + ); +} + +function commitTextUpdate(textInstance, oldText, newText) { + ReactNativePrivateInterface.UIManager.updateView( + textInstance, // reactTag + "RCTRawText", // viewName + { text: newText } // props + ); +} + +function commitUpdate( + instance, + updatePayloadTODO, + type, + oldProps, + newProps, + internalInstanceHandle +) { + var viewConfig = instance.viewConfig; + + updateFiberProps(instance._nativeTag, newProps); + + var updatePayload = diff(oldProps, newProps, viewConfig.validAttributes); + + // Avoid the overhead of bridge calls if there's no update. + // This is an expensive no-op for Android, and causes an unnecessary + // view invalidation for certain components (eg RCTTextInput) on iOS. + if (updatePayload != null) { + ReactNativePrivateInterface.UIManager.updateView( + instance._nativeTag, // reactTag + viewConfig.uiViewClassName, // viewName + updatePayload // props + ); + } +} + +function insertBefore(parentInstance, child, beforeChild) { + var children = parentInstance._children; + var index = children.indexOf(child); + + // Move existing child or add new child? + if (index >= 0) { + children.splice(index, 1); + var beforeChildIndex = children.indexOf(beforeChild); + children.splice(beforeChildIndex, 0, child); + + ReactNativePrivateInterface.UIManager.manageChildren( + parentInstance._nativeTag, // containerID + [index], // moveFromIndices + [beforeChildIndex], // moveToIndices + [], // addChildReactTags + [], // addAtIndices + [] // removeAtIndices + ); + } else { + var _beforeChildIndex = children.indexOf(beforeChild); + children.splice(_beforeChildIndex, 0, child); + + var childTag = typeof child === "number" ? child : child._nativeTag; + + ReactNativePrivateInterface.UIManager.manageChildren( + parentInstance._nativeTag, // containerID + [], // moveFromIndices + [], // moveToIndices + [childTag], // addChildReactTags + [_beforeChildIndex], // addAtIndices + [] // removeAtIndices + ); + } +} + +function insertInContainerBefore(parentInstance, child, beforeChild) { + // TODO (bvaughn): Remove this check when... + // We create a wrapper object for the container in ReactNative render() + // Or we refactor to remove wrapper objects entirely. + // For more info on pros/cons see PR #8560 description. + (function() { + if (!(typeof parentInstance !== "number")) { + throw ReactError("Container does not support insertBefore operation"); + } + })(); +} + +function removeChild(parentInstance, child) { + recursivelyUncacheFiberNode(child); + var children = parentInstance._children; + var index = children.indexOf(child); + + children.splice(index, 1); + + ReactNativePrivateInterface.UIManager.manageChildren( + parentInstance._nativeTag, // containerID + [], // moveFromIndices + [], // moveToIndices + [], // addChildReactTags + [], // addAtIndices + [index] // removeAtIndices + ); +} + +function removeChildFromContainer(parentInstance, child) { + recursivelyUncacheFiberNode(child); + ReactNativePrivateInterface.UIManager.manageChildren( + parentInstance, // containerID + [], // moveFromIndices + [], // moveToIndices + [], // addChildReactTags + [], // addAtIndices + [0] // removeAtIndices + ); +} + +function resetTextContent(instance) { + // Noop +} + +function hideInstance(instance) { + var viewConfig = instance.viewConfig; + var updatePayload = create( + { style: { display: "none" } }, + viewConfig.validAttributes + ); + ReactNativePrivateInterface.UIManager.updateView( + instance._nativeTag, + viewConfig.uiViewClassName, + updatePayload + ); +} + +function hideTextInstance(textInstance) { + throw new Error("Not yet implemented."); +} + +function unhideInstance(instance, props) { + var viewConfig = instance.viewConfig; + var updatePayload = diff( + Object.assign({}, props, { style: [props.style, { display: "none" }] }), + props, + viewConfig.validAttributes + ); + ReactNativePrivateInterface.UIManager.updateView( + instance._nativeTag, + viewConfig.uiViewClassName, + updatePayload + ); +} + +function unhideTextInstance(textInstance, text) { + throw new Error("Not yet implemented."); +} + +function mountEventComponent(eventComponentInstance) { + throw new Error("Not yet implemented."); +} + +function updateEventComponent(eventComponentInstance) { + throw new Error("Not yet implemented."); +} + +function unmountEventComponent(eventComponentInstance) { + throw new Error("Not yet implemented."); +} + +function getEventTargetChildElement(type, props) { + throw new Error("Not yet implemented."); +} + +function handleEventTarget( + type, + props, + rootContainerInstance, + internalInstanceHandle +) { + throw new Error("Not yet implemented."); +} + +function commitEventTarget(type, props, instance, parentInstance) { + throw new Error("Not yet implemented."); +} + +var BEFORE_SLASH_RE = /^(.*)[\\\/]/; + +var describeComponentFrame = function(name, source, ownerName) { + var sourceInfo = ""; + if (source) { + var path = source.fileName; + var fileName = path.replace(BEFORE_SLASH_RE, ""); + { + // In DEV, include code for a common special case: + // prefer "folder/index.js" instead of just "index.js". + if (/^index\./.test(fileName)) { + var match = path.match(BEFORE_SLASH_RE); + if (match) { + var pathBeforeSlash = match[1]; + if (pathBeforeSlash) { + var folderName = pathBeforeSlash.replace(BEFORE_SLASH_RE, ""); + fileName = folderName + "/" + fileName; + } + } + } + } + sourceInfo = " (at " + fileName + ":" + source.lineNumber + ")"; + } else if (ownerName) { + sourceInfo = " (created by " + ownerName + ")"; + } + return "\n in " + (name || "Unknown") + sourceInfo; +}; + +var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; + +function describeFiber(fiber) { + switch (fiber.tag) { + case HostRoot: + case HostPortal: + case HostText: + case Fragment: + case ContextProvider: + case ContextConsumer: + return ""; + default: + var owner = fiber._debugOwner; + var source = fiber._debugSource; + var name = getComponentName(fiber.type); + var ownerName = null; + if (owner) { + ownerName = getComponentName(owner.type); + } + return describeComponentFrame(name, source, ownerName); + } +} + +function getStackByFiberInDevAndProd(workInProgress) { + var info = ""; + var node = workInProgress; + do { + info += describeFiber(node); + node = node.return; + } while (node); + return info; +} + +var current = null; +var phase = null; + +function getCurrentFiberOwnerNameInDevOrNull() { + { + if (current === null) { + return null; + } + var owner = current._debugOwner; + if (owner !== null && typeof owner !== "undefined") { + return getComponentName(owner.type); + } + } + return null; +} + +function getCurrentFiberStackInDev() { + { + if (current === null) { + return ""; + } + // Safe because if current fiber exists, we are reconciling, + // and it is guaranteed to be the work-in-progress version. + return getStackByFiberInDevAndProd(current); + } + return ""; +} + +function resetCurrentFiber() { + { + ReactDebugCurrentFrame.getCurrentStack = null; + current = null; + phase = null; + } +} + +function setCurrentFiber(fiber) { + { + ReactDebugCurrentFrame.getCurrentStack = getCurrentFiberStackInDev; + current = fiber; + phase = null; + } +} + +function setCurrentPhase(lifeCyclePhase) { + { + phase = lifeCyclePhase; + } +} + +// Prefix measurements so that it's possible to filter them. +// Longer prefixes are hard to read in DevTools. +var reactEmoji = "\u269B"; +var warningEmoji = "\u26D4"; +var supportsUserTiming = + typeof performance !== "undefined" && + typeof performance.mark === "function" && + typeof performance.clearMarks === "function" && + typeof performance.measure === "function" && + typeof performance.clearMeasures === "function"; + +// Keep track of current fiber so that we know the path to unwind on pause. +// TODO: this looks the same as nextUnitOfWork in scheduler. Can we unify them? +var currentFiber = null; +// If we're in the middle of user code, which fiber and method is it? +// Reusing `currentFiber` would be confusing for this because user code fiber +// can change during commit phase too, but we don't need to unwind it (since +// lifecycles in the commit phase don't resemble a tree). +var currentPhase = null; +var currentPhaseFiber = null; +// Did lifecycle hook schedule an update? This is often a performance problem, +// so we will keep track of it, and include it in the report. +// Track commits caused by cascading updates. +var isCommitting = false; +var hasScheduledUpdateInCurrentCommit = false; +var hasScheduledUpdateInCurrentPhase = false; +var commitCountInCurrentWorkLoop = 0; +var effectCountInCurrentCommit = 0; +var isWaitingForCallback = false; +// During commits, we only show a measurement once per method name +// to avoid stretch the commit phase with measurement overhead. +var labelsInCurrentCommit = new Set(); + +var formatMarkName = function(markName) { + return reactEmoji + " " + markName; +}; + +var formatLabel = function(label, warning) { + var prefix = warning ? warningEmoji + " " : reactEmoji + " "; + var suffix = warning ? " Warning: " + warning : ""; + return "" + prefix + label + suffix; +}; + +var beginMark = function(markName) { + performance.mark(formatMarkName(markName)); +}; + +var clearMark = function(markName) { + performance.clearMarks(formatMarkName(markName)); +}; + +var endMark = function(label, markName, warning) { + var formattedMarkName = formatMarkName(markName); + var formattedLabel = formatLabel(label, warning); + try { + performance.measure(formattedLabel, formattedMarkName); + } catch (err) {} + // If previous mark was missing for some reason, this will throw. + // This could only happen if React crashed in an unexpected place earlier. + // Don't pile on with more errors. + + // Clear marks immediately to avoid growing buffer. + performance.clearMarks(formattedMarkName); + performance.clearMeasures(formattedLabel); +}; + +var getFiberMarkName = function(label, debugID) { + return label + " (#" + debugID + ")"; +}; + +var getFiberLabel = function(componentName, isMounted, phase) { + if (phase === null) { + // These are composite component total time measurements. + return componentName + " [" + (isMounted ? "update" : "mount") + "]"; + } else { + // Composite component methods. + return componentName + "." + phase; + } +}; + +var beginFiberMark = function(fiber, phase) { + var componentName = getComponentName(fiber.type) || "Unknown"; + var debugID = fiber._debugID; + var isMounted = fiber.alternate !== null; + var label = getFiberLabel(componentName, isMounted, phase); + + if (isCommitting && labelsInCurrentCommit.has(label)) { + // During the commit phase, we don't show duplicate labels because + // there is a fixed overhead for every measurement, and we don't + // want to stretch the commit phase beyond necessary. + return false; + } + labelsInCurrentCommit.add(label); + + var markName = getFiberMarkName(label, debugID); + beginMark(markName); + return true; +}; + +var clearFiberMark = function(fiber, phase) { + var componentName = getComponentName(fiber.type) || "Unknown"; + var debugID = fiber._debugID; + var isMounted = fiber.alternate !== null; + var label = getFiberLabel(componentName, isMounted, phase); + var markName = getFiberMarkName(label, debugID); + clearMark(markName); +}; + +var endFiberMark = function(fiber, phase, warning) { + var componentName = getComponentName(fiber.type) || "Unknown"; + var debugID = fiber._debugID; + var isMounted = fiber.alternate !== null; + var label = getFiberLabel(componentName, isMounted, phase); + var markName = getFiberMarkName(label, debugID); + endMark(label, markName, warning); +}; + +var shouldIgnoreFiber = function(fiber) { + // Host components should be skipped in the timeline. + // We could check typeof fiber.type, but does this work with RN? + switch (fiber.tag) { + case HostRoot: + case HostComponent: + case HostText: + case HostPortal: + case Fragment: + case ContextProvider: + case ContextConsumer: + case Mode: + return true; + default: + return false; + } +}; + +var clearPendingPhaseMeasurement = function() { + if (currentPhase !== null && currentPhaseFiber !== null) { + clearFiberMark(currentPhaseFiber, currentPhase); + } + currentPhaseFiber = null; + currentPhase = null; + hasScheduledUpdateInCurrentPhase = false; +}; + +var pauseTimers = function() { + // Stops all currently active measurements so that they can be resumed + // if we continue in a later deferred loop from the same unit of work. + var fiber = currentFiber; + while (fiber) { + if (fiber._debugIsCurrentlyTiming) { + endFiberMark(fiber, null, null); + } + fiber = fiber.return; + } +}; + +var resumeTimersRecursively = function(fiber) { + if (fiber.return !== null) { + resumeTimersRecursively(fiber.return); + } + if (fiber._debugIsCurrentlyTiming) { + beginFiberMark(fiber, null); + } +}; + +var resumeTimers = function() { + // Resumes all measurements that were active during the last deferred loop. + if (currentFiber !== null) { + resumeTimersRecursively(currentFiber); + } +}; + +function recordEffect() { + if (enableUserTimingAPI) { + effectCountInCurrentCommit++; + } +} + +function recordScheduleUpdate() { + if (enableUserTimingAPI) { + if (isCommitting) { + hasScheduledUpdateInCurrentCommit = true; + } + if ( + currentPhase !== null && + currentPhase !== "componentWillMount" && + currentPhase !== "componentWillReceiveProps" + ) { + hasScheduledUpdateInCurrentPhase = true; + } + } +} + +function startRequestCallbackTimer() { + if (enableUserTimingAPI) { + if (supportsUserTiming && !isWaitingForCallback) { + isWaitingForCallback = true; + beginMark("(Waiting for async callback...)"); + } + } +} + +function stopRequestCallbackTimer(didExpire) { + if (enableUserTimingAPI) { + if (supportsUserTiming) { + isWaitingForCallback = false; + var warning = didExpire + ? "Update expired; will flush synchronously" + : null; + endMark( + "(Waiting for async callback...)", + "(Waiting for async callback...)", + warning + ); + } + } +} + +function startWorkTimer(fiber) { + if (enableUserTimingAPI) { + if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { + return; + } + // If we pause, this is the fiber to unwind from. + currentFiber = fiber; + if (!beginFiberMark(fiber, null)) { + return; + } + fiber._debugIsCurrentlyTiming = true; + } +} + +function cancelWorkTimer(fiber) { + if (enableUserTimingAPI) { + if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { + return; + } + // Remember we shouldn't complete measurement for this fiber. + // Otherwise flamechart will be deep even for small updates. + fiber._debugIsCurrentlyTiming = false; + clearFiberMark(fiber, null); + } +} + +function stopWorkTimer(fiber) { + if (enableUserTimingAPI) { + if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { + return; + } + // If we pause, its parent is the fiber to unwind from. + currentFiber = fiber.return; + if (!fiber._debugIsCurrentlyTiming) { + return; + } + fiber._debugIsCurrentlyTiming = false; + endFiberMark(fiber, null, null); + } +} + +function stopFailedWorkTimer(fiber) { + if (enableUserTimingAPI) { + if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { + return; + } + // If we pause, its parent is the fiber to unwind from. + currentFiber = fiber.return; + if (!fiber._debugIsCurrentlyTiming) { + return; + } + fiber._debugIsCurrentlyTiming = false; + var warning = + fiber.tag === SuspenseComponent || + fiber.tag === DehydratedSuspenseComponent + ? "Rendering was suspended" + : "An error was thrown inside this error boundary"; + endFiberMark(fiber, null, warning); + } +} + +function startPhaseTimer(fiber, phase) { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + clearPendingPhaseMeasurement(); + if (!beginFiberMark(fiber, phase)) { + return; + } + currentPhaseFiber = fiber; + currentPhase = phase; + } +} + +function stopPhaseTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + if (currentPhase !== null && currentPhaseFiber !== null) { + var warning = hasScheduledUpdateInCurrentPhase + ? "Scheduled a cascading update" + : null; + endFiberMark(currentPhaseFiber, currentPhase, warning); + } + currentPhase = null; + currentPhaseFiber = null; + } +} + +function startWorkLoopTimer(nextUnitOfWork) { + if (enableUserTimingAPI) { + currentFiber = nextUnitOfWork; + if (!supportsUserTiming) { + return; + } + commitCountInCurrentWorkLoop = 0; + // This is top level call. + // Any other measurements are performed within. + beginMark("(React Tree Reconciliation)"); + // Resume any measurements that were in progress during the last loop. + resumeTimers(); + } +} + +function stopWorkLoopTimer(interruptedBy, didCompleteRoot) { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + var warning = null; + if (interruptedBy !== null) { + if (interruptedBy.tag === HostRoot) { + warning = "A top-level update interrupted the previous render"; + } else { + var componentName = getComponentName(interruptedBy.type) || "Unknown"; + warning = + "An update to " + componentName + " interrupted the previous render"; + } + } else if (commitCountInCurrentWorkLoop > 1) { + warning = "There were cascading updates"; + } + commitCountInCurrentWorkLoop = 0; + var label = didCompleteRoot + ? "(React Tree Reconciliation: Completed Root)" + : "(React Tree Reconciliation: Yielded)"; + // Pause any measurements until the next loop. + pauseTimers(); + endMark(label, "(React Tree Reconciliation)", warning); + } +} + +function startCommitTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + isCommitting = true; + hasScheduledUpdateInCurrentCommit = false; + labelsInCurrentCommit.clear(); + beginMark("(Committing Changes)"); + } +} + +function stopCommitTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + + var warning = null; + if (hasScheduledUpdateInCurrentCommit) { + warning = "Lifecycle hook scheduled a cascading update"; + } else if (commitCountInCurrentWorkLoop > 0) { + warning = "Caused by a cascading update in earlier commit"; + } + hasScheduledUpdateInCurrentCommit = false; + commitCountInCurrentWorkLoop++; + isCommitting = false; + labelsInCurrentCommit.clear(); + + endMark("(Committing Changes)", "(Committing Changes)", warning); + } +} + +function startCommitSnapshotEffectsTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + effectCountInCurrentCommit = 0; + beginMark("(Committing Snapshot Effects)"); + } +} + +function stopCommitSnapshotEffectsTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + var count = effectCountInCurrentCommit; + effectCountInCurrentCommit = 0; + endMark( + "(Committing Snapshot Effects: " + count + " Total)", + "(Committing Snapshot Effects)", + null + ); + } +} + +function startCommitHostEffectsTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + effectCountInCurrentCommit = 0; + beginMark("(Committing Host Effects)"); + } +} + +function stopCommitHostEffectsTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + var count = effectCountInCurrentCommit; + effectCountInCurrentCommit = 0; + endMark( + "(Committing Host Effects: " + count + " Total)", + "(Committing Host Effects)", + null + ); + } +} + +function startCommitLifeCyclesTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + effectCountInCurrentCommit = 0; + beginMark("(Calling Lifecycle Methods)"); + } +} + +function stopCommitLifeCyclesTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + var count = effectCountInCurrentCommit; + effectCountInCurrentCommit = 0; + endMark( + "(Calling Lifecycle Methods: " + count + " Total)", + "(Calling Lifecycle Methods)", + null + ); + } +} + +var valueStack = []; + +var fiberStack = void 0; + +{ + fiberStack = []; +} + +var index = -1; + +function createCursor(defaultValue) { + return { + current: defaultValue + }; +} + +function pop(cursor, fiber) { + if (index < 0) { + { + warningWithoutStack$1(false, "Unexpected pop."); + } + return; + } + + { + if (fiber !== fiberStack[index]) { + warningWithoutStack$1(false, "Unexpected Fiber popped."); + } + } + + cursor.current = valueStack[index]; + + valueStack[index] = null; + + { + fiberStack[index] = null; + } + + index--; +} + +function push(cursor, value, fiber) { + index++; + + valueStack[index] = cursor.current; + + { + fiberStack[index] = fiber; + } + + cursor.current = value; +} + +var warnedAboutMissingGetChildContext = void 0; + +{ + warnedAboutMissingGetChildContext = {}; +} + +var emptyContextObject = {}; +{ + Object.freeze(emptyContextObject); +} + +// A cursor to the current merged context object on the stack. +var contextStackCursor = createCursor(emptyContextObject); +// A cursor to a boolean indicating whether the context has changed. +var didPerformWorkStackCursor = createCursor(false); +// Keep track of the previous context object that was on the stack. +// We use this to get access to the parent context after we have already +// pushed the next context provider, and now need to merge their contexts. +var previousContext = emptyContextObject; + +function getUnmaskedContext( + workInProgress, + Component, + didPushOwnContextIfProvider +) { + if (didPushOwnContextIfProvider && isContextProvider(Component)) { + // If the fiber is a context provider itself, when we read its context + // we may have already pushed its own child context on the stack. A context + // provider should not "see" its own child context. Therefore we read the + // previous (parent) context instead for a context provider. + return previousContext; + } + return contextStackCursor.current; +} + +function cacheContext(workInProgress, unmaskedContext, maskedContext) { + var instance = workInProgress.stateNode; + instance.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext; + instance.__reactInternalMemoizedMaskedChildContext = maskedContext; +} + +function getMaskedContext(workInProgress, unmaskedContext) { + var type = workInProgress.type; + var contextTypes = type.contextTypes; + if (!contextTypes) { + return emptyContextObject; + } + + // Avoid recreating masked context unless unmasked context has changed. + // Failing to do this will result in unnecessary calls to componentWillReceiveProps. + // This may trigger infinite loops if componentWillReceiveProps calls setState. + var instance = workInProgress.stateNode; + if ( + instance && + instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext + ) { + return instance.__reactInternalMemoizedMaskedChildContext; + } + + var context = {}; + for (var key in contextTypes) { + context[key] = unmaskedContext[key]; + } + + { + var name = getComponentName(type) || "Unknown"; + checkPropTypes( + contextTypes, + context, + "context", + name, + getCurrentFiberStackInDev + ); + } + + // Cache unmasked context so we can avoid recreating masked context unless necessary. + // Context is created before the class component is instantiated so check for instance. + if (instance) { + cacheContext(workInProgress, unmaskedContext, context); + } + + return context; +} + +function hasContextChanged() { + return didPerformWorkStackCursor.current; +} + +function isContextProvider(type) { + var childContextTypes = type.childContextTypes; + return childContextTypes !== null && childContextTypes !== undefined; +} + +function popContext(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); +} + +function popTopLevelContextObject(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); +} + +function pushTopLevelContextObject(fiber, context, didChange) { + (function() { + if (!(contextStackCursor.current === emptyContextObject)) { + throw ReactError( + "Unexpected context found on stack. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + + push(contextStackCursor, context, fiber); + push(didPerformWorkStackCursor, didChange, fiber); +} + +function processChildContext(fiber, type, parentContext) { + var instance = fiber.stateNode; + var childContextTypes = type.childContextTypes; + + // TODO (bvaughn) Replace this behavior with an invariant() in the future. + // It has only been added in Fiber to match the (unintentional) behavior in Stack. + if (typeof instance.getChildContext !== "function") { + { + var componentName = getComponentName(type) || "Unknown"; + + if (!warnedAboutMissingGetChildContext[componentName]) { + warnedAboutMissingGetChildContext[componentName] = true; + warningWithoutStack$1( + false, + "%s.childContextTypes is specified but there is no getChildContext() method " + + "on the instance. You can either define getChildContext() on %s or remove " + + "childContextTypes from it.", + componentName, + componentName + ); + } + } + return parentContext; + } + + var childContext = void 0; + { + setCurrentPhase("getChildContext"); + } + startPhaseTimer(fiber, "getChildContext"); + childContext = instance.getChildContext(); + stopPhaseTimer(); + { + setCurrentPhase(null); + } + for (var contextKey in childContext) { + (function() { + if (!(contextKey in childContextTypes)) { + throw ReactError( + (getComponentName(type) || "Unknown") + + '.getChildContext(): key "' + + contextKey + + '" is not defined in childContextTypes.' + ); + } + })(); + } + { + var name = getComponentName(type) || "Unknown"; + checkPropTypes( + childContextTypes, + childContext, + "child context", + name, + // In practice, there is one case in which we won't get a stack. It's when + // somebody calls unstable_renderSubtreeIntoContainer() and we process + // context from the parent component instance. The stack will be missing + // because it's outside of the reconciliation, and so the pointer has not + // been set. This is rare and doesn't matter. We'll also remove that API. + getCurrentFiberStackInDev + ); + } + + return Object.assign({}, parentContext, childContext); +} + +function pushContextProvider(workInProgress) { + var instance = workInProgress.stateNode; + // We push the context as early as possible to ensure stack integrity. + // If the instance does not exist yet, we will push null at first, + // and replace it on the stack later when invalidating the context. + var memoizedMergedChildContext = + (instance && instance.__reactInternalMemoizedMergedChildContext) || + emptyContextObject; + + // Remember the parent context so we can merge with it later. + // Inherit the parent's did-perform-work value to avoid inadvertently blocking updates. + previousContext = contextStackCursor.current; + push(contextStackCursor, memoizedMergedChildContext, workInProgress); + push( + didPerformWorkStackCursor, + didPerformWorkStackCursor.current, + workInProgress + ); + + return true; +} + +function invalidateContextProvider(workInProgress, type, didChange) { + var instance = workInProgress.stateNode; + (function() { + if (!instance) { + throw ReactError( + "Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + + if (didChange) { + // Merge parent and own context. + // Skip this if we're not updating due to sCU. + // This avoids unnecessarily recomputing memoized values. + var mergedContext = processChildContext( + workInProgress, + type, + previousContext + ); + instance.__reactInternalMemoizedMergedChildContext = mergedContext; + + // Replace the old (or empty) context with the new one. + // It is important to unwind the context in the reverse order. + pop(didPerformWorkStackCursor, workInProgress); + pop(contextStackCursor, workInProgress); + // Now push the new context and mark that it has changed. + push(contextStackCursor, mergedContext, workInProgress); + push(didPerformWorkStackCursor, didChange, workInProgress); + } else { + pop(didPerformWorkStackCursor, workInProgress); + push(didPerformWorkStackCursor, didChange, workInProgress); + } +} + +function findCurrentUnmaskedContext(fiber) { + // Currently this is only used with renderSubtreeIntoContainer; not sure if it + // makes sense elsewhere + (function() { + if (!(isFiberMounted(fiber) && fiber.tag === ClassComponent)) { + throw ReactError( + "Expected subtree parent to be a mounted class component. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + + var node = fiber; + do { + switch (node.tag) { + case HostRoot: + return node.stateNode.context; + case ClassComponent: { + var Component = node.type; + if (isContextProvider(Component)) { + return node.stateNode.__reactInternalMemoizedMergedChildContext; + } + break; + } + } + node = node.return; + } while (node !== null); + (function() { + { + throw ReactError( + "Found unexpected detached subtree parent. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); +} + +var onCommitFiberRoot = null; +var onCommitFiberUnmount = null; +var hasLoggedError = false; + +function catchErrors(fn) { + return function(arg) { + try { + return fn(arg); + } catch (err) { + if (true && !hasLoggedError) { + hasLoggedError = true; + warningWithoutStack$1( + false, + "React DevTools encountered an error: %s", + err + ); + } + } + }; +} + +var isDevToolsPresent = typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== "undefined"; + +function injectInternals(internals) { + if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === "undefined") { + // No DevTools + return false; + } + var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__; + if (hook.isDisabled) { + // This isn't a real property on the hook, but it can be set to opt out + // of DevTools integration and associated warnings and logs. + // https://github.com/facebook/react/issues/3877 + return true; + } + if (!hook.supportsFiber) { + { + warningWithoutStack$1( + false, + "The installed version of React DevTools is too old and will not work " + + "with the current version of React. Please update React DevTools. " + + "https://fb.me/react-devtools" + ); + } + // DevTools exists, even though it doesn't support Fiber. + return true; + } + try { + var rendererID = hook.inject(internals); + // We have successfully injected, so now it is safe to set up hooks. + onCommitFiberRoot = catchErrors(function(root) { + return hook.onCommitFiberRoot(rendererID, root); + }); + onCommitFiberUnmount = catchErrors(function(fiber) { + return hook.onCommitFiberUnmount(rendererID, fiber); + }); + } catch (err) { + // Catch all errors because it is unsafe to throw during initialization. + { + warningWithoutStack$1( + false, + "React DevTools encountered an error: %s.", + err + ); + } + } + // DevTools exists + return true; +} + +function onCommitRoot(root) { + if (typeof onCommitFiberRoot === "function") { + onCommitFiberRoot(root); + } +} + +function onCommitUnmount(fiber) { + if (typeof onCommitFiberUnmount === "function") { + onCommitFiberUnmount(fiber); + } +} + +// Max 31 bit integer. The max integer size in V8 for 32-bit systems. +// Math.pow(2, 30) - 1 +// 0b111111111111111111111111111111 +var MAX_SIGNED_31_BIT_INT = 1073741823; + +// Intentionally not named imports because Rollup would use dynamic dispatch for +// CommonJS interop named imports. +var Scheduler_runWithPriority = Scheduler.unstable_runWithPriority; +var Scheduler_scheduleCallback = Scheduler.unstable_scheduleCallback; +var Scheduler_cancelCallback = Scheduler.unstable_cancelCallback; +var Scheduler_shouldYield = Scheduler.unstable_shouldYield; +var Scheduler_now = Scheduler.unstable_now; +var Scheduler_getCurrentPriorityLevel = + Scheduler.unstable_getCurrentPriorityLevel; +var Scheduler_ImmediatePriority = Scheduler.unstable_ImmediatePriority; +var Scheduler_UserBlockingPriority = Scheduler.unstable_UserBlockingPriority; +var Scheduler_NormalPriority = Scheduler.unstable_NormalPriority; +var Scheduler_LowPriority = Scheduler.unstable_LowPriority; +var Scheduler_IdlePriority = Scheduler.unstable_IdlePriority; + +if (enableSchedulerTracing) { + // Provide explicit error message when production+profiling bundle of e.g. + // react-dom is used with production (non-profiling) bundle of + // scheduler/tracing + (function() { + if ( + !( + tracing.__interactionsRef != null && + tracing.__interactionsRef.current != null + ) + ) { + throw ReactError( + "It is not supported to run the profiling version of a renderer (for example, `react-dom/profiling`) without also replacing the `scheduler/tracing` module with `scheduler/tracing-profiling`. Your bundler might have a setting for aliasing both modules. Learn more at http://fb.me/react-profiling" + ); + } + })(); +} + +var fakeCallbackNode = {}; + +// Except for NoPriority, these correspond to Scheduler priorities. We use +// ascending numbers so we can compare them like numbers. They start at 90 to +// avoid clashing with Scheduler's priorities. +var ImmediatePriority = 99; +var UserBlockingPriority = 98; +var NormalPriority = 97; +var LowPriority = 96; +var IdlePriority = 95; +// NoPriority is the absence of priority. Also React-only. + +var shouldYield = disableYielding + ? function() { + return false; + } // Never yield when `disableYielding` is on + : Scheduler_shouldYield; + +var immediateQueue = null; +var immediateQueueCallbackNode = null; +var isFlushingImmediate = false; +var initialTimeMs = Scheduler_now(); + +// If the initial timestamp is reasonably small, use Scheduler's `now` directly. +// This will be the case for modern browsers that support `performance.now`. In +// older browsers, Scheduler falls back to `Date.now`, which returns a Unix +// timestamp. In that case, subtract the module initialization time to simulate +// the behavior of performance.now and keep our times small enough to fit +// within 32 bits. +// TODO: Consider lifting this into Scheduler. +var now = + initialTimeMs < 10000 + ? Scheduler_now + : function() { + return Scheduler_now() - initialTimeMs; + }; + +function getCurrentPriorityLevel() { + switch (Scheduler_getCurrentPriorityLevel()) { + case Scheduler_ImmediatePriority: + return ImmediatePriority; + case Scheduler_UserBlockingPriority: + return UserBlockingPriority; + case Scheduler_NormalPriority: + return NormalPriority; + case Scheduler_LowPriority: + return LowPriority; + case Scheduler_IdlePriority: + return IdlePriority; + default: + (function() { + { + throw ReactError("Unknown priority level."); + } + })(); + } +} + +function reactPriorityToSchedulerPriority(reactPriorityLevel) { + switch (reactPriorityLevel) { + case ImmediatePriority: + return Scheduler_ImmediatePriority; + case UserBlockingPriority: + return Scheduler_UserBlockingPriority; + case NormalPriority: + return Scheduler_NormalPriority; + case LowPriority: + return Scheduler_LowPriority; + case IdlePriority: + return Scheduler_IdlePriority; + default: + (function() { + { + throw ReactError("Unknown priority level."); + } + })(); + } +} + +function runWithPriority(reactPriorityLevel, fn) { + var priorityLevel = reactPriorityToSchedulerPriority(reactPriorityLevel); + return Scheduler_runWithPriority(priorityLevel, fn); +} + +function scheduleCallback(reactPriorityLevel, callback, options) { + if (reactPriorityLevel === ImmediatePriority) { + // Push this callback into an internal queue. We'll flush these either in + // the next tick, or earlier if something calls `flushImmediateQueue`. + if (immediateQueue === null) { + immediateQueue = [callback]; + // Flush the queue in the next tick, at the earliest. + immediateQueueCallbackNode = Scheduler_scheduleCallback( + Scheduler_ImmediatePriority, + flushImmediateQueueImpl + ); + } else { + // Push onto existing queue. Don't need to schedule a callback because + // we already scheduled one when we created the queue. + immediateQueue.push(callback); + } + return fakeCallbackNode; + } + // Otherwise pass through to Scheduler. + var priorityLevel = reactPriorityToSchedulerPriority(reactPriorityLevel); + return Scheduler_scheduleCallback(priorityLevel, callback, options); +} + +function cancelCallback(callbackNode) { + if (callbackNode !== fakeCallbackNode) { + Scheduler_cancelCallback(callbackNode); + } +} + +function flushImmediateQueue() { + if (immediateQueueCallbackNode !== null) { + Scheduler_cancelCallback(immediateQueueCallbackNode); + } + flushImmediateQueueImpl(); +} + +function flushImmediateQueueImpl() { + if (!isFlushingImmediate && immediateQueue !== null) { + // Prevent re-entrancy. + isFlushingImmediate = true; + var i = 0; + try { + var _isSync = true; + for (; i < immediateQueue.length; i++) { + var callback = immediateQueue[i]; + do { + callback = callback(_isSync); + } while (callback !== null); + } + immediateQueue = null; + } catch (error) { + // If something throws, leave the remaining callbacks on the queue. + if (immediateQueue !== null) { + immediateQueue = immediateQueue.slice(i + 1); + } + // Resume flushing in the next tick + Scheduler_scheduleCallback( + Scheduler_ImmediatePriority, + flushImmediateQueue + ); + throw error; + } finally { + isFlushingImmediate = false; + } + } +} + +var NoWork = 0; +var Never = 1; +var Sync = MAX_SIGNED_31_BIT_INT; + +var UNIT_SIZE = 10; +var MAGIC_NUMBER_OFFSET = MAX_SIGNED_31_BIT_INT - 1; + +// 1 unit of expiration time represents 10ms. +function msToExpirationTime(ms) { + // Always add an offset so that we don't clash with the magic number for NoWork. + return MAGIC_NUMBER_OFFSET - ((ms / UNIT_SIZE) | 0); +} + +function expirationTimeToMs(expirationTime) { + return (MAGIC_NUMBER_OFFSET - expirationTime) * UNIT_SIZE; +} + +function ceiling(num, precision) { + return (((num / precision) | 0) + 1) * precision; +} + +function computeExpirationBucket(currentTime, expirationInMs, bucketSizeMs) { + return ( + MAGIC_NUMBER_OFFSET - + ceiling( + MAGIC_NUMBER_OFFSET - currentTime + expirationInMs / UNIT_SIZE, + bucketSizeMs / UNIT_SIZE + ) + ); +} + +// TODO: This corresponds to Scheduler's NormalPriority, not LowPriority. Update +// the names to reflect. +var LOW_PRIORITY_EXPIRATION = 5000; +var LOW_PRIORITY_BATCH_SIZE = 250; + +function computeAsyncExpiration(currentTime) { + return computeExpirationBucket( + currentTime, + LOW_PRIORITY_EXPIRATION, + LOW_PRIORITY_BATCH_SIZE + ); +} + +// Same as computeAsyncExpiration but without the bucketing logic. This is +// used to compute timestamps instead of actual expiration times. +function computeAsyncExpirationNoBucket(currentTime) { + return currentTime - LOW_PRIORITY_EXPIRATION / UNIT_SIZE; +} + +// We intentionally set a higher expiration time for interactive updates in +// dev than in production. +// +// If the main thread is being blocked so long that you hit the expiration, +// it's a problem that could be solved with better scheduling. +// +// People will be more likely to notice this and fix it with the long +// expiration time in development. +// +// In production we opt for better UX at the risk of masking scheduling +// problems, by expiring fast. +var HIGH_PRIORITY_EXPIRATION = 500; +var HIGH_PRIORITY_BATCH_SIZE = 100; + +function computeInteractiveExpiration(currentTime) { + return computeExpirationBucket( + currentTime, + HIGH_PRIORITY_EXPIRATION, + HIGH_PRIORITY_BATCH_SIZE + ); +} + +function inferPriorityFromExpirationTime(currentTime, expirationTime) { + if (expirationTime === Sync) { + return ImmediatePriority; + } + if (expirationTime === Never) { + return IdlePriority; + } + var msUntil = + expirationTimeToMs(expirationTime) - expirationTimeToMs(currentTime); + if (msUntil <= 0) { + return ImmediatePriority; + } + if (msUntil <= HIGH_PRIORITY_EXPIRATION + HIGH_PRIORITY_BATCH_SIZE) { + return UserBlockingPriority; + } + if (msUntil <= LOW_PRIORITY_EXPIRATION + LOW_PRIORITY_BATCH_SIZE) { + return NormalPriority; + } + + // TODO: Handle LowPriority + + // Assume anything lower has idle priority + return IdlePriority; +} + +var NoContext = 0; +var ConcurrentMode = 1; +var StrictMode = 2; +var ProfileMode = 4; + +var hasBadMapPolyfill = void 0; + +{ + hasBadMapPolyfill = false; + try { + var nonExtensibleObject = Object.preventExtensions({}); + var testMap = new Map([[nonExtensibleObject, null]]); + var testSet = new Set([nonExtensibleObject]); + // This is necessary for Rollup to not consider these unused. + // https://github.com/rollup/rollup/issues/1771 + // TODO: we can remove these if Rollup fixes the bug. + testMap.set(0, 0); + testSet.add(0); + } catch (e) { + // TODO: Consider warning about bad polyfills + hasBadMapPolyfill = true; + } +} + +// A Fiber is work on a Component that needs to be done or was done. There can +// be more than one per component. + +var debugCounter = void 0; + +{ + debugCounter = 1; +} + +function FiberNode(tag, pendingProps, key, mode) { + // Instance + this.tag = tag; + this.key = key; + this.elementType = null; + this.type = null; + this.stateNode = null; + + // Fiber + this.return = null; + this.child = null; + this.sibling = null; + this.index = 0; + + this.ref = null; + + this.pendingProps = pendingProps; + this.memoizedProps = null; + this.updateQueue = null; + this.memoizedState = null; + this.contextDependencies = null; + + this.mode = mode; + + // Effects + this.effectTag = NoEffect; + this.nextEffect = null; + + this.firstEffect = null; + this.lastEffect = null; + + this.expirationTime = NoWork; + this.childExpirationTime = NoWork; + + this.alternate = null; + + if (enableProfilerTimer) { + // Note: The following is done to avoid a v8 performance cliff. + // + // Initializing the fields below to smis and later updating them with + // double values will cause Fibers to end up having separate shapes. + // This behavior/bug has something to do with Object.preventExtension(). + // Fortunately this only impacts DEV builds. + // Unfortunately it makes React unusably slow for some applications. + // To work around this, initialize the fields below with doubles. + // + // Learn more about this here: + // https://github.com/facebook/react/issues/14365 + // https://bugs.chromium.org/p/v8/issues/detail?id=8538 + this.actualDuration = Number.NaN; + this.actualStartTime = Number.NaN; + this.selfBaseDuration = Number.NaN; + this.treeBaseDuration = Number.NaN; + + // It's okay to replace the initial doubles with smis after initialization. + // This won't trigger the performance cliff mentioned above, + // and it simplifies other profiler code (including DevTools). + this.actualDuration = 0; + this.actualStartTime = -1; + this.selfBaseDuration = 0; + this.treeBaseDuration = 0; + } + + { + this._debugID = debugCounter++; + this._debugSource = null; + this._debugOwner = null; + this._debugIsCurrentlyTiming = false; + this._debugHookTypes = null; + if (!hasBadMapPolyfill && typeof Object.preventExtensions === "function") { + Object.preventExtensions(this); + } + } +} + +// This is a constructor function, rather than a POJO constructor, still +// please ensure we do the following: +// 1) Nobody should add any instance methods on this. Instance methods can be +// more difficult to predict when they get optimized and they are almost +// never inlined properly in static compilers. +// 2) Nobody should rely on `instanceof Fiber` for type testing. We should +// always know when it is a fiber. +// 3) We might want to experiment with using numeric keys since they are easier +// to optimize in a non-JIT environment. +// 4) We can easily go from a constructor to a createFiber object literal if that +// is faster. +// 5) It should be easy to port this to a C struct and keep a C implementation +// compatible. +var createFiber = function(tag, pendingProps, key, mode) { + // $FlowFixMe: the shapes are exact here but Flow doesn't like constructors + return new FiberNode(tag, pendingProps, key, mode); +}; + +function shouldConstruct(Component) { + var prototype = Component.prototype; + return !!(prototype && prototype.isReactComponent); +} + +function isSimpleFunctionComponent(type) { + return ( + typeof type === "function" && + !shouldConstruct(type) && + type.defaultProps === undefined + ); +} + +function resolveLazyComponentTag(Component) { + if (typeof Component === "function") { + return shouldConstruct(Component) ? ClassComponent : FunctionComponent; + } else if (Component !== undefined && Component !== null) { + var $$typeof = Component.$$typeof; + if ($$typeof === REACT_FORWARD_REF_TYPE) { + return ForwardRef; + } + if ($$typeof === REACT_MEMO_TYPE) { + return MemoComponent; + } + } + return IndeterminateComponent; +} + +// This is used to create an alternate fiber to do work on. +function createWorkInProgress(current, pendingProps, expirationTime) { + var workInProgress = current.alternate; + if (workInProgress === null) { + // We use a double buffering pooling technique because we know that we'll + // only ever need at most two versions of a tree. We pool the "other" unused + // node that we're free to reuse. This is lazily created to avoid allocating + // extra objects for things that are never updated. It also allow us to + // reclaim the extra memory if needed. + workInProgress = createFiber( + current.tag, + pendingProps, + current.key, + current.mode + ); + workInProgress.elementType = current.elementType; + workInProgress.type = current.type; + workInProgress.stateNode = current.stateNode; + + { + // DEV-only fields + workInProgress._debugID = current._debugID; + workInProgress._debugSource = current._debugSource; + workInProgress._debugOwner = current._debugOwner; + workInProgress._debugHookTypes = current._debugHookTypes; + } + + workInProgress.alternate = current; + current.alternate = workInProgress; + } else { + workInProgress.pendingProps = pendingProps; + + // We already have an alternate. + // Reset the effect tag. + workInProgress.effectTag = NoEffect; + + // The effect list is no longer valid. + workInProgress.nextEffect = null; + workInProgress.firstEffect = null; + workInProgress.lastEffect = null; + + if (enableProfilerTimer) { + // We intentionally reset, rather than copy, actualDuration & actualStartTime. + // This prevents time from endlessly accumulating in new commits. + // This has the downside of resetting values for different priority renders, + // But works for yielding (the common case) and should support resuming. + workInProgress.actualDuration = 0; + workInProgress.actualStartTime = -1; + } + } + + workInProgress.childExpirationTime = current.childExpirationTime; + workInProgress.expirationTime = current.expirationTime; + + workInProgress.child = current.child; + workInProgress.memoizedProps = current.memoizedProps; + workInProgress.memoizedState = current.memoizedState; + workInProgress.updateQueue = current.updateQueue; + workInProgress.contextDependencies = current.contextDependencies; + + // These will be overridden during the parent's reconciliation + workInProgress.sibling = current.sibling; + workInProgress.index = current.index; + workInProgress.ref = current.ref; + + if (enableProfilerTimer) { + workInProgress.selfBaseDuration = current.selfBaseDuration; + workInProgress.treeBaseDuration = current.treeBaseDuration; + } + + return workInProgress; +} + +function createHostRootFiber(isConcurrent) { + var mode = isConcurrent ? ConcurrentMode | StrictMode : NoContext; + + if (enableProfilerTimer && isDevToolsPresent) { + // Always collect profile timings when DevTools are present. + // This enables DevTools to start capturing timing at any point– + // Without some nodes in the tree having empty base times. + mode |= ProfileMode; + } + + return createFiber(HostRoot, null, null, mode); +} + +function createFiberFromTypeAndProps( + type, // React$ElementType + key, + pendingProps, + owner, + mode, + expirationTime +) { + var fiber = void 0; + + var fiberTag = IndeterminateComponent; + // The resolved type is set if we know what the final type will be. I.e. it's not lazy. + var resolvedType = type; + if (typeof type === "function") { + if (shouldConstruct(type)) { + fiberTag = ClassComponent; + } + } else if (typeof type === "string") { + fiberTag = HostComponent; + } else { + getTag: switch (type) { + case REACT_FRAGMENT_TYPE: + return createFiberFromFragment( + pendingProps.children, + mode, + expirationTime, + key + ); + case REACT_CONCURRENT_MODE_TYPE: + return createFiberFromMode( + pendingProps, + mode | ConcurrentMode | StrictMode, + expirationTime, + key + ); + case REACT_STRICT_MODE_TYPE: + return createFiberFromMode( + pendingProps, + mode | StrictMode, + expirationTime, + key + ); + case REACT_PROFILER_TYPE: + return createFiberFromProfiler(pendingProps, mode, expirationTime, key); + case REACT_SUSPENSE_TYPE: + return createFiberFromSuspense(pendingProps, mode, expirationTime, key); + default: { + if (typeof type === "object" && type !== null) { + switch (type.$$typeof) { + case REACT_PROVIDER_TYPE: + fiberTag = ContextProvider; + break getTag; + case REACT_CONTEXT_TYPE: + // This is a consumer + fiberTag = ContextConsumer; + break getTag; + case REACT_FORWARD_REF_TYPE: + fiberTag = ForwardRef; + break getTag; + case REACT_MEMO_TYPE: + fiberTag = MemoComponent; + break getTag; + case REACT_LAZY_TYPE: + fiberTag = LazyComponent; + resolvedType = null; + break getTag; + case REACT_EVENT_COMPONENT_TYPE: + if (enableEventAPI) { + return createFiberFromEventComponent( + type, + pendingProps, + mode, + expirationTime, + key + ); + } + break; + case REACT_EVENT_TARGET_TYPE: + if (enableEventAPI) { + return createFiberFromEventTarget( + type, + pendingProps, + mode, + expirationTime, + key + ); + } + break; + } + } + var info = ""; + { + if ( + type === undefined || + (typeof type === "object" && + type !== null && + Object.keys(type).length === 0) + ) { + info += + " You likely forgot to export your component from the file " + + "it's defined in, or you might have mixed up default and " + + "named imports."; + } + var ownerName = owner ? getComponentName(owner.type) : null; + if (ownerName) { + info += "\n\nCheck the render method of `" + ownerName + "`."; + } + } + (function() { + { + throw ReactError( + "Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: " + + (type == null ? type : typeof type) + + "." + + info + ); + } + })(); + } + } + } + + fiber = createFiber(fiberTag, pendingProps, key, mode); + fiber.elementType = type; + fiber.type = resolvedType; + fiber.expirationTime = expirationTime; + + return fiber; +} + +function createFiberFromElement(element, mode, expirationTime) { + var owner = null; + { + owner = element._owner; + } + var type = element.type; + var key = element.key; + var pendingProps = element.props; + var fiber = createFiberFromTypeAndProps( + type, + key, + pendingProps, + owner, + mode, + expirationTime + ); + { + fiber._debugSource = element._source; + fiber._debugOwner = element._owner; + } + return fiber; +} + +function createFiberFromFragment(elements, mode, expirationTime, key) { + var fiber = createFiber(Fragment, elements, key, mode); + fiber.expirationTime = expirationTime; + return fiber; +} + +function createFiberFromEventComponent( + eventComponent, + pendingProps, + mode, + expirationTime, + key +) { + var fiber = createFiber(EventComponent, pendingProps, key, mode); + fiber.elementType = eventComponent; + fiber.type = eventComponent; + fiber.expirationTime = expirationTime; + return fiber; +} + +function createFiberFromEventTarget( + eventTarget, + pendingProps, + mode, + expirationTime, + key +) { + var fiber = createFiber(EventTarget, pendingProps, key, mode); + fiber.elementType = eventTarget; + fiber.type = eventTarget; + fiber.expirationTime = expirationTime; + // Store latest props + fiber.stateNode = { + props: pendingProps + }; + return fiber; +} + +function createFiberFromProfiler(pendingProps, mode, expirationTime, key) { + { + if ( + typeof pendingProps.id !== "string" || + typeof pendingProps.onRender !== "function" + ) { + warningWithoutStack$1( + false, + 'Profiler must specify an "id" string and "onRender" function as props' + ); + } + } + + var fiber = createFiber(Profiler, pendingProps, key, mode | ProfileMode); + // TODO: The Profiler fiber shouldn't have a type. It has a tag. + fiber.elementType = REACT_PROFILER_TYPE; + fiber.type = REACT_PROFILER_TYPE; + fiber.expirationTime = expirationTime; + + return fiber; +} + +function createFiberFromMode(pendingProps, mode, expirationTime, key) { + var fiber = createFiber(Mode, pendingProps, key, mode); + + // TODO: The Mode fiber shouldn't have a type. It has a tag. + var type = + (mode & ConcurrentMode) === NoContext + ? REACT_STRICT_MODE_TYPE + : REACT_CONCURRENT_MODE_TYPE; + fiber.elementType = type; + fiber.type = type; + + fiber.expirationTime = expirationTime; + return fiber; +} + +function createFiberFromSuspense(pendingProps, mode, expirationTime, key) { + var fiber = createFiber(SuspenseComponent, pendingProps, key, mode); + + // TODO: The SuspenseComponent fiber shouldn't have a type. It has a tag. + var type = REACT_SUSPENSE_TYPE; + fiber.elementType = type; + fiber.type = type; + + fiber.expirationTime = expirationTime; + return fiber; +} + +function createFiberFromText(content, mode, expirationTime) { + var fiber = createFiber(HostText, content, null, mode); + fiber.expirationTime = expirationTime; + return fiber; +} + +function createFiberFromHostInstanceForDeletion() { + var fiber = createFiber(HostComponent, null, null, NoContext); + // TODO: These should not need a type. + fiber.elementType = "DELETED"; + fiber.type = "DELETED"; + return fiber; +} + +function createFiberFromPortal(portal, mode, expirationTime) { + var pendingProps = portal.children !== null ? portal.children : []; + var fiber = createFiber(HostPortal, pendingProps, portal.key, mode); + fiber.expirationTime = expirationTime; + fiber.stateNode = { + containerInfo: portal.containerInfo, + pendingChildren: null, // Used by persistent updates + implementation: portal.implementation + }; + return fiber; +} + +// Used for stashing WIP properties to replay failed work in DEV. +function assignFiberPropertiesInDEV(target, source) { + if (target === null) { + // This Fiber's initial properties will always be overwritten. + // We only use a Fiber to ensure the same hidden class so DEV isn't slow. + target = createFiber(IndeterminateComponent, null, null, NoContext); + } + + // This is intentionally written as a list of all properties. + // We tried to use Object.assign() instead but this is called in + // the hottest path, and Object.assign() was too slow: + // https://github.com/facebook/react/issues/12502 + // This code is DEV-only so size is not a concern. + + target.tag = source.tag; + target.key = source.key; + target.elementType = source.elementType; + target.type = source.type; + target.stateNode = source.stateNode; + target.return = source.return; + target.child = source.child; + target.sibling = source.sibling; + target.index = source.index; + target.ref = source.ref; + target.pendingProps = source.pendingProps; + target.memoizedProps = source.memoizedProps; + target.updateQueue = source.updateQueue; + target.memoizedState = source.memoizedState; + target.contextDependencies = source.contextDependencies; + target.mode = source.mode; + target.effectTag = source.effectTag; + target.nextEffect = source.nextEffect; + target.firstEffect = source.firstEffect; + target.lastEffect = source.lastEffect; + target.expirationTime = source.expirationTime; + target.childExpirationTime = source.childExpirationTime; + target.alternate = source.alternate; + if (enableProfilerTimer) { + target.actualDuration = source.actualDuration; + target.actualStartTime = source.actualStartTime; + target.selfBaseDuration = source.selfBaseDuration; + target.treeBaseDuration = source.treeBaseDuration; + } + target._debugID = source._debugID; + target._debugSource = source._debugSource; + target._debugOwner = source._debugOwner; + target._debugIsCurrentlyTiming = source._debugIsCurrentlyTiming; + target._debugHookTypes = source._debugHookTypes; + return target; +} + +// TODO: This should be lifted into the renderer. + +// The following attributes are only used by interaction tracing builds. +// They enable interactions to be associated with their async work, +// And expose interaction metadata to the React DevTools Profiler plugin. +// Note that these attributes are only defined when the enableSchedulerTracing flag is enabled. + +// Exported FiberRoot type includes all properties, +// To avoid requiring potentially error-prone :any casts throughout the project. +// Profiling properties are only safe to access in profiling builds (when enableSchedulerTracing is true). +// The types are defined separately within this file to ensure they stay in sync. +// (We don't have to use an inline :any cast when enableSchedulerTracing is disabled.) + +function FiberRootNode(containerInfo, hydrate) { + this.current = null; + this.containerInfo = containerInfo; + this.pendingChildren = null; + this.pingCache = null; + this.pendingCommitExpirationTime = NoWork; + this.finishedWork = null; + this.timeoutHandle = noTimeout; + this.context = null; + this.pendingContext = null; + this.hydrate = hydrate; + this.firstBatch = null; + this.callbackNode = null; + this.callbackExpirationTime = NoWork; + this.firstPendingTime = NoWork; + this.lastPendingTime = NoWork; + this.pingTime = NoWork; + + if (enableSchedulerTracing) { + this.interactionThreadID = tracing.unstable_getThreadID(); + this.memoizedInteractions = new Set(); + this.pendingInteractionMap = new Map(); + } +} + +function createFiberRoot(containerInfo, isConcurrent, hydrate) { + var root = new FiberRootNode(containerInfo, hydrate); + + // Cyclic construction. This cheats the type system right now because + // stateNode is any. + var uninitializedFiber = createHostRootFiber(isConcurrent); + root.current = uninitializedFiber; + uninitializedFiber.stateNode = root; + + return root; +} + +/** + * Similar to invariant but only logs a warning if the condition is not met. + * This can be used to log issues in development environments in critical + * paths. Removing the logging code for production environments will keep the + * same logic and follow the same code paths. + */ + +var warning = warningWithoutStack$1; + +{ + warning = function(condition, format) { + if (condition) { + return; + } + var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; + var stack = ReactDebugCurrentFrame.getStackAddendum(); + // eslint-disable-next-line react-internal/warning-and-invariant-args + + for ( + var _len = arguments.length, + args = Array(_len > 2 ? _len - 2 : 0), + _key = 2; + _key < _len; + _key++ + ) { + args[_key - 2] = arguments[_key]; + } + + warningWithoutStack$1.apply( + undefined, + [false, format + "%s"].concat(args, [stack]) + ); + }; +} + +var warning$1 = warning; + +/** + * inlined Object.is polyfill to avoid requiring consumers ship their own + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is + */ +function is(x, y) { + return ( + (x === y && (x !== 0 || 1 / x === 1 / y)) || (x !== x && y !== y) // eslint-disable-line no-self-compare + ); +} + +var hasOwnProperty = Object.prototype.hasOwnProperty; + +/** + * Performs equality by iterating through keys on an object and returning false + * when any key has values which are not strictly equal between the arguments. + * Returns true when the values of all keys are strictly equal. + */ +function shallowEqual(objA, objB) { + if (is(objA, objB)) { + return true; + } + + if ( + typeof objA !== "object" || + objA === null || + typeof objB !== "object" || + objB === null + ) { + return false; + } + + var keysA = Object.keys(objA); + var keysB = Object.keys(objB); + + if (keysA.length !== keysB.length) { + return false; + } + + // Test for A's keys different from B. + for (var i = 0; i < keysA.length; i++) { + if ( + !hasOwnProperty.call(objB, keysA[i]) || + !is(objA[keysA[i]], objB[keysA[i]]) + ) { + return false; + } + } + + return true; +} + +/** + * Forked from fbjs/warning: + * https://github.com/facebook/fbjs/blob/e66ba20ad5be433eb54423f2b097d829324d9de6/packages/fbjs/src/__forks__/warning.js + * + * Only change is we use console.warn instead of console.error, + * and do nothing when 'console' is not supported. + * This really simplifies the code. + * --- + * Similar to invariant but only logs a warning if the condition is not met. + * This can be used to log issues in development environments in critical + * paths. Removing the logging code for production environments will keep the + * same logic and follow the same code paths. + */ + +var lowPriorityWarning = function() {}; + +{ + var printWarning = function(format) { + for ( + var _len = arguments.length, + args = Array(_len > 1 ? _len - 1 : 0), + _key = 1; + _key < _len; + _key++ + ) { + args[_key - 1] = arguments[_key]; + } + + var argIndex = 0; + var message = + "Warning: " + + format.replace(/%s/g, function() { + return args[argIndex++]; + }); + if (typeof console !== "undefined") { + console.warn(message); + } + try { + // --- Welcome to debugging React --- + // This error was thrown as a convenience so that you can use this stack + // to find the callsite that caused this warning to fire. + throw new Error(message); + } catch (x) {} + }; + + lowPriorityWarning = function(condition, format) { + if (format === undefined) { + throw new Error( + "`lowPriorityWarning(condition, format, ...args)` requires a warning " + + "message argument" + ); + } + if (!condition) { + for ( + var _len2 = arguments.length, + args = Array(_len2 > 2 ? _len2 - 2 : 0), + _key2 = 2; + _key2 < _len2; + _key2++ + ) { + args[_key2 - 2] = arguments[_key2]; + } + + printWarning.apply(undefined, [format].concat(args)); + } + }; +} + +var lowPriorityWarning$1 = lowPriorityWarning; + +var ReactStrictModeWarnings = { + discardPendingWarnings: function() {}, + flushPendingDeprecationWarnings: function() {}, + flushPendingUnsafeLifecycleWarnings: function() {}, + recordDeprecationWarnings: function(fiber, instance) {}, + recordUnsafeLifecycleWarnings: function(fiber, instance) {}, + recordLegacyContextWarning: function(fiber, instance) {}, + flushLegacyContextWarning: function() {} +}; + +{ + var LIFECYCLE_SUGGESTIONS = { + UNSAFE_componentWillMount: "componentDidMount", + UNSAFE_componentWillReceiveProps: "static getDerivedStateFromProps", + UNSAFE_componentWillUpdate: "componentDidUpdate" + }; + + var pendingComponentWillMountWarnings = []; + var pendingComponentWillReceivePropsWarnings = []; + var pendingComponentWillUpdateWarnings = []; + var pendingUnsafeLifecycleWarnings = new Map(); + var pendingLegacyContextWarning = new Map(); + + // Tracks components we have already warned about. + var didWarnAboutDeprecatedLifecycles = new Set(); + var didWarnAboutUnsafeLifecycles = new Set(); + var didWarnAboutLegacyContext = new Set(); + + var setToSortedString = function(set) { + var array = []; + set.forEach(function(value) { + array.push(value); + }); + return array.sort().join(", "); + }; + + ReactStrictModeWarnings.discardPendingWarnings = function() { + pendingComponentWillMountWarnings = []; + pendingComponentWillReceivePropsWarnings = []; + pendingComponentWillUpdateWarnings = []; + pendingUnsafeLifecycleWarnings = new Map(); + pendingLegacyContextWarning = new Map(); + }; + + ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = function() { + pendingUnsafeLifecycleWarnings.forEach(function( + lifecycleWarningsMap, + strictRoot + ) { + var lifecyclesWarningMessages = []; + + Object.keys(lifecycleWarningsMap).forEach(function(lifecycle) { + var lifecycleWarnings = lifecycleWarningsMap[lifecycle]; + if (lifecycleWarnings.length > 0) { + var componentNames = new Set(); + lifecycleWarnings.forEach(function(fiber) { + componentNames.add(getComponentName(fiber.type) || "Component"); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + + var formatted = lifecycle.replace("UNSAFE_", ""); + var suggestion = LIFECYCLE_SUGGESTIONS[lifecycle]; + var sortedComponentNames = setToSortedString(componentNames); + + lifecyclesWarningMessages.push( + formatted + + ": Please update the following components to use " + + (suggestion + " instead: " + sortedComponentNames) + ); + } + }); + + if (lifecyclesWarningMessages.length > 0) { + var strictRootComponentStack = getStackByFiberInDevAndProd(strictRoot); + + warningWithoutStack$1( + false, + "Unsafe lifecycle methods were found within a strict-mode tree:%s" + + "\n\n%s" + + "\n\nLearn more about this warning here:" + + "\nhttps://fb.me/react-strict-mode-warnings", + strictRootComponentStack, + lifecyclesWarningMessages.join("\n\n") + ); + } + }); + + pendingUnsafeLifecycleWarnings = new Map(); + }; + + var findStrictRoot = function(fiber) { + var maybeStrictRoot = null; + + var node = fiber; + while (node !== null) { + if (node.mode & StrictMode) { + maybeStrictRoot = node; + } + node = node.return; + } + + return maybeStrictRoot; + }; + + ReactStrictModeWarnings.flushPendingDeprecationWarnings = function() { + if (pendingComponentWillMountWarnings.length > 0) { + var uniqueNames = new Set(); + pendingComponentWillMountWarnings.forEach(function(fiber) { + uniqueNames.add(getComponentName(fiber.type) || "Component"); + didWarnAboutDeprecatedLifecycles.add(fiber.type); + }); + + var sortedNames = setToSortedString(uniqueNames); + + lowPriorityWarning$1( + false, + "componentWillMount is deprecated and will be removed in the next major version. " + + "Use componentDidMount instead. As a temporary workaround, " + + "you can rename to UNSAFE_componentWillMount." + + "\n\nPlease update the following components: %s" + + "\n\nLearn more about this warning here:" + + "\nhttps://fb.me/react-async-component-lifecycle-hooks", + sortedNames + ); + + pendingComponentWillMountWarnings = []; + } + + if (pendingComponentWillReceivePropsWarnings.length > 0) { + var _uniqueNames = new Set(); + pendingComponentWillReceivePropsWarnings.forEach(function(fiber) { + _uniqueNames.add(getComponentName(fiber.type) || "Component"); + didWarnAboutDeprecatedLifecycles.add(fiber.type); + }); + + var _sortedNames = setToSortedString(_uniqueNames); + + lowPriorityWarning$1( + false, + "componentWillReceiveProps is deprecated and will be removed in the next major version. " + + "Use static getDerivedStateFromProps instead." + + "\n\nPlease update the following components: %s" + + "\n\nLearn more about this warning here:" + + "\nhttps://fb.me/react-async-component-lifecycle-hooks", + _sortedNames + ); + + pendingComponentWillReceivePropsWarnings = []; + } + + if (pendingComponentWillUpdateWarnings.length > 0) { + var _uniqueNames2 = new Set(); + pendingComponentWillUpdateWarnings.forEach(function(fiber) { + _uniqueNames2.add(getComponentName(fiber.type) || "Component"); + didWarnAboutDeprecatedLifecycles.add(fiber.type); + }); + + var _sortedNames2 = setToSortedString(_uniqueNames2); + + lowPriorityWarning$1( + false, + "componentWillUpdate is deprecated and will be removed in the next major version. " + + "Use componentDidUpdate instead. As a temporary workaround, " + + "you can rename to UNSAFE_componentWillUpdate." + + "\n\nPlease update the following components: %s" + + "\n\nLearn more about this warning here:" + + "\nhttps://fb.me/react-async-component-lifecycle-hooks", + _sortedNames2 + ); + + pendingComponentWillUpdateWarnings = []; + } + }; + + ReactStrictModeWarnings.recordDeprecationWarnings = function( + fiber, + instance + ) { + // Dedup strategy: Warn once per component. + if (didWarnAboutDeprecatedLifecycles.has(fiber.type)) { + return; + } + + // Don't warn about react-lifecycles-compat polyfilled components. + if ( + typeof instance.componentWillMount === "function" && + instance.componentWillMount.__suppressDeprecationWarning !== true + ) { + pendingComponentWillMountWarnings.push(fiber); + } + if ( + typeof instance.componentWillReceiveProps === "function" && + instance.componentWillReceiveProps.__suppressDeprecationWarning !== true + ) { + pendingComponentWillReceivePropsWarnings.push(fiber); + } + if ( + typeof instance.componentWillUpdate === "function" && + instance.componentWillUpdate.__suppressDeprecationWarning !== true + ) { + pendingComponentWillUpdateWarnings.push(fiber); + } + }; + + ReactStrictModeWarnings.recordUnsafeLifecycleWarnings = function( + fiber, + instance + ) { + var strictRoot = findStrictRoot(fiber); + if (strictRoot === null) { + warningWithoutStack$1( + false, + "Expected to find a StrictMode component in a strict mode tree. " + + "This error is likely caused by a bug in React. Please file an issue." + ); + return; + } + + // Dedup strategy: Warn once per component. + // This is difficult to track any other way since component names + // are often vague and are likely to collide between 3rd party libraries. + // An expand property is probably okay to use here since it's DEV-only, + // and will only be set in the event of serious warnings. + if (didWarnAboutUnsafeLifecycles.has(fiber.type)) { + return; + } + + var warningsForRoot = void 0; + if (!pendingUnsafeLifecycleWarnings.has(strictRoot)) { + warningsForRoot = { + UNSAFE_componentWillMount: [], + UNSAFE_componentWillReceiveProps: [], + UNSAFE_componentWillUpdate: [] + }; + + pendingUnsafeLifecycleWarnings.set(strictRoot, warningsForRoot); + } else { + warningsForRoot = pendingUnsafeLifecycleWarnings.get(strictRoot); + } + + var unsafeLifecycles = []; + if ( + (typeof instance.componentWillMount === "function" && + instance.componentWillMount.__suppressDeprecationWarning !== true) || + typeof instance.UNSAFE_componentWillMount === "function" + ) { + unsafeLifecycles.push("UNSAFE_componentWillMount"); + } + if ( + (typeof instance.componentWillReceiveProps === "function" && + instance.componentWillReceiveProps.__suppressDeprecationWarning !== + true) || + typeof instance.UNSAFE_componentWillReceiveProps === "function" + ) { + unsafeLifecycles.push("UNSAFE_componentWillReceiveProps"); + } + if ( + (typeof instance.componentWillUpdate === "function" && + instance.componentWillUpdate.__suppressDeprecationWarning !== true) || + typeof instance.UNSAFE_componentWillUpdate === "function" + ) { + unsafeLifecycles.push("UNSAFE_componentWillUpdate"); + } + + if (unsafeLifecycles.length > 0) { + unsafeLifecycles.forEach(function(lifecycle) { + warningsForRoot[lifecycle].push(fiber); + }); + } + }; + + ReactStrictModeWarnings.recordLegacyContextWarning = function( + fiber, + instance + ) { + var strictRoot = findStrictRoot(fiber); + if (strictRoot === null) { + warningWithoutStack$1( + false, + "Expected to find a StrictMode component in a strict mode tree. " + + "This error is likely caused by a bug in React. Please file an issue." + ); + return; + } + + // Dedup strategy: Warn once per component. + if (didWarnAboutLegacyContext.has(fiber.type)) { + return; + } + + var warningsForRoot = pendingLegacyContextWarning.get(strictRoot); + + if ( + fiber.type.contextTypes != null || + fiber.type.childContextTypes != null || + (instance !== null && typeof instance.getChildContext === "function") + ) { + if (warningsForRoot === undefined) { + warningsForRoot = []; + pendingLegacyContextWarning.set(strictRoot, warningsForRoot); + } + warningsForRoot.push(fiber); + } + }; + + ReactStrictModeWarnings.flushLegacyContextWarning = function() { + pendingLegacyContextWarning.forEach(function(fiberArray, strictRoot) { + var uniqueNames = new Set(); + fiberArray.forEach(function(fiber) { + uniqueNames.add(getComponentName(fiber.type) || "Component"); + didWarnAboutLegacyContext.add(fiber.type); + }); + + var sortedNames = setToSortedString(uniqueNames); + var strictRootComponentStack = getStackByFiberInDevAndProd(strictRoot); + + warningWithoutStack$1( + false, + "Legacy context API has been detected within a strict-mode tree: %s" + + "\n\nPlease update the following components: %s" + + "\n\nLearn more about this warning here:" + + "\nhttps://fb.me/react-strict-mode-warnings", + strictRootComponentStack, + sortedNames + ); + }); + }; +} + +function resolveDefaultProps(Component, baseProps) { + if (Component && Component.defaultProps) { + // Resolve default props. Taken from ReactElement + var props = Object.assign({}, baseProps); + var defaultProps = Component.defaultProps; + for (var propName in defaultProps) { + if (props[propName] === undefined) { + props[propName] = defaultProps[propName]; + } + } + return props; + } + return baseProps; +} + +function readLazyComponentType(lazyComponent) { + var status = lazyComponent._status; + var result = lazyComponent._result; + switch (status) { + case Resolved: { + var Component = result; + return Component; + } + case Rejected: { + var error = result; + throw error; + } + case Pending: { + var thenable = result; + throw thenable; + } + default: { + lazyComponent._status = Pending; + var ctor = lazyComponent._ctor; + var _thenable = ctor(); + _thenable.then( + function(moduleObject) { + if (lazyComponent._status === Pending) { + var defaultExport = moduleObject.default; + { + if (defaultExport === undefined) { + warning$1( + false, + "lazy: Expected the result of a dynamic import() call. " + + "Instead received: %s\n\nYour code should look like: \n " + + "const MyComponent = lazy(() => import('./MyComponent'))", + moduleObject + ); + } + } + lazyComponent._status = Resolved; + lazyComponent._result = defaultExport; + } + }, + function(error) { + if (lazyComponent._status === Pending) { + lazyComponent._status = Rejected; + lazyComponent._result = error; + } + } + ); + // Handle synchronous thenables. + switch (lazyComponent._status) { + case Resolved: + return lazyComponent._result; + case Rejected: + throw lazyComponent._result; + } + lazyComponent._result = _thenable; + throw _thenable; + } + } +} + +var valueCursor = createCursor(null); + +var rendererSigil = void 0; +{ + // Use this to detect multiple renderers using the same context + rendererSigil = {}; +} + +var currentlyRenderingFiber = null; +var lastContextDependency = null; +var lastContextWithAllBitsObserved = null; + +var isDisallowedContextReadInDEV = false; + +function resetContextDependences() { + // This is called right before React yields execution, to ensure `readContext` + // cannot be called outside the render phase. + currentlyRenderingFiber = null; + lastContextDependency = null; + lastContextWithAllBitsObserved = null; + { + isDisallowedContextReadInDEV = false; + } +} + +function enterDisallowedContextReadInDEV() { + { + isDisallowedContextReadInDEV = true; + } +} + +function exitDisallowedContextReadInDEV() { + { + isDisallowedContextReadInDEV = false; + } +} + +function pushProvider(providerFiber, nextValue) { + var context = providerFiber.type._context; + + if (isPrimaryRenderer) { + push(valueCursor, context._currentValue, providerFiber); + + context._currentValue = nextValue; + { + !( + context._currentRenderer === undefined || + context._currentRenderer === null || + context._currentRenderer === rendererSigil + ) + ? warningWithoutStack$1( + false, + "Detected multiple renderers concurrently rendering the " + + "same context provider. This is currently unsupported." + ) + : void 0; + context._currentRenderer = rendererSigil; + } + } else { + push(valueCursor, context._currentValue2, providerFiber); + + context._currentValue2 = nextValue; + { + !( + context._currentRenderer2 === undefined || + context._currentRenderer2 === null || + context._currentRenderer2 === rendererSigil + ) + ? warningWithoutStack$1( + false, + "Detected multiple renderers concurrently rendering the " + + "same context provider. This is currently unsupported." + ) + : void 0; + context._currentRenderer2 = rendererSigil; + } + } +} + +function popProvider(providerFiber) { + var currentValue = valueCursor.current; + + pop(valueCursor, providerFiber); + + var context = providerFiber.type._context; + if (isPrimaryRenderer) { + context._currentValue = currentValue; + } else { + context._currentValue2 = currentValue; + } +} + +function calculateChangedBits(context, newValue, oldValue) { + if (is(oldValue, newValue)) { + // No change + return 0; + } else { + var changedBits = + typeof context._calculateChangedBits === "function" + ? context._calculateChangedBits(oldValue, newValue) + : MAX_SIGNED_31_BIT_INT; + + { + !((changedBits & MAX_SIGNED_31_BIT_INT) === changedBits) + ? warning$1( + false, + "calculateChangedBits: Expected the return value to be a " + + "31-bit integer. Instead received: %s", + changedBits + ) + : void 0; + } + return changedBits | 0; + } +} + +function scheduleWorkOnParentPath(parent, renderExpirationTime) { + // Update the child expiration time of all the ancestors, including + // the alternates. + var node = parent; + while (node !== null) { + var alternate = node.alternate; + if (node.childExpirationTime < renderExpirationTime) { + node.childExpirationTime = renderExpirationTime; + if ( + alternate !== null && + alternate.childExpirationTime < renderExpirationTime + ) { + alternate.childExpirationTime = renderExpirationTime; + } + } else if ( + alternate !== null && + alternate.childExpirationTime < renderExpirationTime + ) { + alternate.childExpirationTime = renderExpirationTime; + } else { + // Neither alternate was updated, which means the rest of the + // ancestor path already has sufficient priority. + break; + } + node = node.return; + } +} + +function propagateContextChange( + workInProgress, + context, + changedBits, + renderExpirationTime +) { + var fiber = workInProgress.child; + if (fiber !== null) { + // Set the return pointer of the child to the work-in-progress fiber. + fiber.return = workInProgress; + } + while (fiber !== null) { + var nextFiber = void 0; + + // Visit this fiber. + var list = fiber.contextDependencies; + if (list !== null) { + nextFiber = fiber.child; + + var dependency = list.first; + while (dependency !== null) { + // Check if the context matches. + if ( + dependency.context === context && + (dependency.observedBits & changedBits) !== 0 + ) { + // Match! Schedule an update on this fiber. + + if (fiber.tag === ClassComponent) { + // Schedule a force update on the work-in-progress. + var update = createUpdate(renderExpirationTime); + update.tag = ForceUpdate; + // TODO: Because we don't have a work-in-progress, this will add the + // update to the current fiber, too, which means it will persist even if + // this render is thrown away. Since it's a race condition, not sure it's + // worth fixing. + enqueueUpdate(fiber, update); + } + + if (fiber.expirationTime < renderExpirationTime) { + fiber.expirationTime = renderExpirationTime; + } + var alternate = fiber.alternate; + if ( + alternate !== null && + alternate.expirationTime < renderExpirationTime + ) { + alternate.expirationTime = renderExpirationTime; + } + + scheduleWorkOnParentPath(fiber.return, renderExpirationTime); + + // Mark the expiration time on the list, too. + if (list.expirationTime < renderExpirationTime) { + list.expirationTime = renderExpirationTime; + } + + // Since we already found a match, we can stop traversing the + // dependency list. + break; + } + dependency = dependency.next; + } + } else if (fiber.tag === ContextProvider) { + // Don't scan deeper if this is a matching provider + nextFiber = fiber.type === workInProgress.type ? null : fiber.child; + } else if ( + enableSuspenseServerRenderer && + fiber.tag === DehydratedSuspenseComponent + ) { + // If a dehydrated suspense component is in this subtree, we don't know + // if it will have any context consumers in it. The best we can do is + // mark it as having updates on its children. + if (fiber.expirationTime < renderExpirationTime) { + fiber.expirationTime = renderExpirationTime; + } + var _alternate = fiber.alternate; + if ( + _alternate !== null && + _alternate.expirationTime < renderExpirationTime + ) { + _alternate.expirationTime = renderExpirationTime; + } + // This is intentionally passing this fiber as the parent + // because we want to schedule this fiber as having work + // on its children. We'll use the childExpirationTime on + // this fiber to indicate that a context has changed. + scheduleWorkOnParentPath(fiber, renderExpirationTime); + nextFiber = fiber.sibling; + } else { + // Traverse down. + nextFiber = fiber.child; + } + + if (nextFiber !== null) { + // Set the return pointer of the child to the work-in-progress fiber. + nextFiber.return = fiber; + } else { + // No child. Traverse to next sibling. + nextFiber = fiber; + while (nextFiber !== null) { + if (nextFiber === workInProgress) { + // We're back to the root of this subtree. Exit. + nextFiber = null; + break; + } + var sibling = nextFiber.sibling; + if (sibling !== null) { + // Set the return pointer of the sibling to the work-in-progress fiber. + sibling.return = nextFiber.return; + nextFiber = sibling; + break; + } + // No more siblings. Traverse up. + nextFiber = nextFiber.return; + } + } + fiber = nextFiber; + } +} + +function prepareToReadContext(workInProgress, renderExpirationTime) { + currentlyRenderingFiber = workInProgress; + lastContextDependency = null; + lastContextWithAllBitsObserved = null; + + var currentDependencies = workInProgress.contextDependencies; + if ( + currentDependencies !== null && + currentDependencies.expirationTime >= renderExpirationTime + ) { + // Context list has a pending update. Mark that this fiber performed work. + markWorkInProgressReceivedUpdate(); + } + + // Reset the work-in-progress list + workInProgress.contextDependencies = null; +} + +function readContext(context, observedBits) { + { + // This warning would fire if you read context inside a Hook like useMemo. + // Unlike the class check below, it's not enforced in production for perf. + !!isDisallowedContextReadInDEV + ? warning$1( + false, + "Context can only be read while React is rendering. " + + "In classes, you can read it in the render method or getDerivedStateFromProps. " + + "In function components, you can read it directly in the function body, but not " + + "inside Hooks like useReducer() or useMemo()." + ) + : void 0; + } + + if (lastContextWithAllBitsObserved === context) { + // Nothing to do. We already observe everything in this context. + } else if (observedBits === false || observedBits === 0) { + // Do not observe any updates. + } else { + var resolvedObservedBits = void 0; // Avoid deopting on observable arguments or heterogeneous types. + if ( + typeof observedBits !== "number" || + observedBits === MAX_SIGNED_31_BIT_INT + ) { + // Observe all updates. + lastContextWithAllBitsObserved = context; + resolvedObservedBits = MAX_SIGNED_31_BIT_INT; + } else { + resolvedObservedBits = observedBits; + } + + var contextItem = { + context: context, + observedBits: resolvedObservedBits, + next: null + }; + + if (lastContextDependency === null) { + (function() { + if (!(currentlyRenderingFiber !== null)) { + throw ReactError( + "Context can only be read while React is rendering. In classes, you can read it in the render method or getDerivedStateFromProps. In function components, you can read it directly in the function body, but not inside Hooks like useReducer() or useMemo()." + ); + } + })(); + + // This is the first dependency for this component. Create a new list. + lastContextDependency = contextItem; + currentlyRenderingFiber.contextDependencies = { + first: contextItem, + expirationTime: NoWork + }; + } else { + // Append a new context item. + lastContextDependency = lastContextDependency.next = contextItem; + } + } + return isPrimaryRenderer ? context._currentValue : context._currentValue2; +} + +// UpdateQueue is a linked list of prioritized updates. +// +// Like fibers, update queues come in pairs: a current queue, which represents +// the visible state of the screen, and a work-in-progress queue, which can be +// mutated and processed asynchronously before it is committed — a form of +// double buffering. If a work-in-progress render is discarded before finishing, +// we create a new work-in-progress by cloning the current queue. +// +// Both queues share a persistent, singly-linked list structure. To schedule an +// update, we append it to the end of both queues. Each queue maintains a +// pointer to first update in the persistent list that hasn't been processed. +// The work-in-progress pointer always has a position equal to or greater than +// the current queue, since we always work on that one. The current queue's +// pointer is only updated during the commit phase, when we swap in the +// work-in-progress. +// +// For example: +// +// Current pointer: A - B - C - D - E - F +// Work-in-progress pointer: D - E - F +// ^ +// The work-in-progress queue has +// processed more updates than current. +// +// The reason we append to both queues is because otherwise we might drop +// updates without ever processing them. For example, if we only add updates to +// the work-in-progress queue, some updates could be lost whenever a work-in +// -progress render restarts by cloning from current. Similarly, if we only add +// updates to the current queue, the updates will be lost whenever an already +// in-progress queue commits and swaps with the current queue. However, by +// adding to both queues, we guarantee that the update will be part of the next +// work-in-progress. (And because the work-in-progress queue becomes the +// current queue once it commits, there's no danger of applying the same +// update twice.) +// +// Prioritization +// -------------- +// +// Updates are not sorted by priority, but by insertion; new updates are always +// appended to the end of the list. +// +// The priority is still important, though. When processing the update queue +// during the render phase, only the updates with sufficient priority are +// included in the result. If we skip an update because it has insufficient +// priority, it remains in the queue to be processed later, during a lower +// priority render. Crucially, all updates subsequent to a skipped update also +// remain in the queue *regardless of their priority*. That means high priority +// updates are sometimes processed twice, at two separate priorities. We also +// keep track of a base state, that represents the state before the first +// update in the queue is applied. +// +// For example: +// +// Given a base state of '', and the following queue of updates +// +// A1 - B2 - C1 - D2 +// +// where the number indicates the priority, and the update is applied to the +// previous state by appending a letter, React will process these updates as +// two separate renders, one per distinct priority level: +// +// First render, at priority 1: +// Base state: '' +// Updates: [A1, C1] +// Result state: 'AC' +// +// Second render, at priority 2: +// Base state: 'A' <- The base state does not include C1, +// because B2 was skipped. +// Updates: [B2, C1, D2] <- C1 was rebased on top of B2 +// Result state: 'ABCD' +// +// Because we process updates in insertion order, and rebase high priority +// updates when preceding updates are skipped, the final result is deterministic +// regardless of priority. Intermediate state may vary according to system +// resources, but the final state is always the same. + +var UpdateState = 0; +var ReplaceState = 1; +var ForceUpdate = 2; +var CaptureUpdate = 3; + +// Global state that is reset at the beginning of calling `processUpdateQueue`. +// It should only be read right after calling `processUpdateQueue`, via +// `checkHasForceUpdateAfterProcessing`. +var hasForceUpdate = false; + +var didWarnUpdateInsideUpdate = void 0; +var currentlyProcessingQueue = void 0; + +{ + didWarnUpdateInsideUpdate = false; + currentlyProcessingQueue = null; +} + +function createUpdateQueue(baseState) { + var queue = { + baseState: baseState, + firstUpdate: null, + lastUpdate: null, + firstCapturedUpdate: null, + lastCapturedUpdate: null, + firstEffect: null, + lastEffect: null, + firstCapturedEffect: null, + lastCapturedEffect: null + }; + return queue; +} + +function cloneUpdateQueue(currentQueue) { + var queue = { + baseState: currentQueue.baseState, + firstUpdate: currentQueue.firstUpdate, + lastUpdate: currentQueue.lastUpdate, + + // TODO: With resuming, if we bail out and resuse the child tree, we should + // keep these effects. + firstCapturedUpdate: null, + lastCapturedUpdate: null, + + firstEffect: null, + lastEffect: null, + + firstCapturedEffect: null, + lastCapturedEffect: null + }; + return queue; +} + +function createUpdate(expirationTime) { + return { + expirationTime: expirationTime, + + tag: UpdateState, + payload: null, + callback: null, + + next: null, + nextEffect: null + }; +} + +function appendUpdateToQueue(queue, update) { + // Append the update to the end of the list. + if (queue.lastUpdate === null) { + // Queue is empty + queue.firstUpdate = queue.lastUpdate = update; + } else { + queue.lastUpdate.next = update; + queue.lastUpdate = update; + } +} + +function enqueueUpdate(fiber, update) { + // Update queues are created lazily. + var alternate = fiber.alternate; + var queue1 = void 0; + var queue2 = void 0; + if (alternate === null) { + // There's only one fiber. + queue1 = fiber.updateQueue; + queue2 = null; + if (queue1 === null) { + queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState); + } + } else { + // There are two owners. + queue1 = fiber.updateQueue; + queue2 = alternate.updateQueue; + if (queue1 === null) { + if (queue2 === null) { + // Neither fiber has an update queue. Create new ones. + queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState); + queue2 = alternate.updateQueue = createUpdateQueue( + alternate.memoizedState + ); + } else { + // Only one fiber has an update queue. Clone to create a new one. + queue1 = fiber.updateQueue = cloneUpdateQueue(queue2); + } + } else { + if (queue2 === null) { + // Only one fiber has an update queue. Clone to create a new one. + queue2 = alternate.updateQueue = cloneUpdateQueue(queue1); + } else { + // Both owners have an update queue. + } + } + } + if (queue2 === null || queue1 === queue2) { + // There's only a single queue. + appendUpdateToQueue(queue1, update); + } else { + // There are two queues. We need to append the update to both queues, + // while accounting for the persistent structure of the list — we don't + // want the same update to be added multiple times. + if (queue1.lastUpdate === null || queue2.lastUpdate === null) { + // One of the queues is not empty. We must add the update to both queues. + appendUpdateToQueue(queue1, update); + appendUpdateToQueue(queue2, update); + } else { + // Both queues are non-empty. The last update is the same in both lists, + // because of structural sharing. So, only append to one of the lists. + appendUpdateToQueue(queue1, update); + // But we still need to update the `lastUpdate` pointer of queue2. + queue2.lastUpdate = update; + } + } + + { + if ( + fiber.tag === ClassComponent && + (currentlyProcessingQueue === queue1 || + (queue2 !== null && currentlyProcessingQueue === queue2)) && + !didWarnUpdateInsideUpdate + ) { + warningWithoutStack$1( + false, + "An update (setState, replaceState, or forceUpdate) was scheduled " + + "from inside an update function. Update functions should be pure, " + + "with zero side-effects. Consider using componentDidUpdate or a " + + "callback." + ); + didWarnUpdateInsideUpdate = true; + } + } +} + +function enqueueCapturedUpdate(workInProgress, update) { + // Captured updates go into a separate list, and only on the work-in- + // progress queue. + var workInProgressQueue = workInProgress.updateQueue; + if (workInProgressQueue === null) { + workInProgressQueue = workInProgress.updateQueue = createUpdateQueue( + workInProgress.memoizedState + ); + } else { + // TODO: I put this here rather than createWorkInProgress so that we don't + // clone the queue unnecessarily. There's probably a better way to + // structure this. + workInProgressQueue = ensureWorkInProgressQueueIsAClone( + workInProgress, + workInProgressQueue + ); + } + + // Append the update to the end of the list. + if (workInProgressQueue.lastCapturedUpdate === null) { + // This is the first render phase update + workInProgressQueue.firstCapturedUpdate = workInProgressQueue.lastCapturedUpdate = update; + } else { + workInProgressQueue.lastCapturedUpdate.next = update; + workInProgressQueue.lastCapturedUpdate = update; + } +} + +function ensureWorkInProgressQueueIsAClone(workInProgress, queue) { + var current = workInProgress.alternate; + if (current !== null) { + // If the work-in-progress queue is equal to the current queue, + // we need to clone it first. + if (queue === current.updateQueue) { + queue = workInProgress.updateQueue = cloneUpdateQueue(queue); + } + } + return queue; +} + +function getStateFromUpdate( + workInProgress, + queue, + update, + prevState, + nextProps, + instance +) { + switch (update.tag) { + case ReplaceState: { + var _payload = update.payload; + if (typeof _payload === "function") { + // Updater function + { + enterDisallowedContextReadInDEV(); + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + _payload.call(instance, prevState, nextProps); + } + } + var nextState = _payload.call(instance, prevState, nextProps); + { + exitDisallowedContextReadInDEV(); + } + return nextState; + } + // State object + return _payload; + } + case CaptureUpdate: { + workInProgress.effectTag = + (workInProgress.effectTag & ~ShouldCapture) | DidCapture; + } + // Intentional fallthrough + case UpdateState: { + var _payload2 = update.payload; + var partialState = void 0; + if (typeof _payload2 === "function") { + // Updater function + { + enterDisallowedContextReadInDEV(); + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + _payload2.call(instance, prevState, nextProps); + } + } + partialState = _payload2.call(instance, prevState, nextProps); + { + exitDisallowedContextReadInDEV(); + } + } else { + // Partial state object + partialState = _payload2; + } + if (partialState === null || partialState === undefined) { + // Null and undefined are treated as no-ops. + return prevState; + } + // Merge the partial state and the previous state. + return Object.assign({}, prevState, partialState); + } + case ForceUpdate: { + hasForceUpdate = true; + return prevState; + } + } + return prevState; +} + +function processUpdateQueue( + workInProgress, + queue, + props, + instance, + renderExpirationTime +) { + hasForceUpdate = false; + + queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue); + + { + currentlyProcessingQueue = queue; + } + + // These values may change as we process the queue. + var newBaseState = queue.baseState; + var newFirstUpdate = null; + var newExpirationTime = NoWork; + + // Iterate through the list of updates to compute the result. + var update = queue.firstUpdate; + var resultState = newBaseState; + while (update !== null) { + var updateExpirationTime = update.expirationTime; + if (updateExpirationTime < renderExpirationTime) { + // This update does not have sufficient priority. Skip it. + if (newFirstUpdate === null) { + // This is the first skipped update. It will be the first update in + // the new list. + newFirstUpdate = update; + // Since this is the first update that was skipped, the current result + // is the new base state. + newBaseState = resultState; + } + // Since this update will remain in the list, update the remaining + // expiration time. + if (newExpirationTime < updateExpirationTime) { + newExpirationTime = updateExpirationTime; + } + } else { + // This update does have sufficient priority. + + // Mark the event time of this update as relevant to this render pass. + // TODO: This should ideally use the true event time of this update rather than + // its priority which is a derived and not reverseable value. + // TODO: We should skip this update if it was already committed but currently + // we have no way of detecting the difference between a committed and suspended + // update here. + markRenderEventTime(updateExpirationTime); + + // Process it and compute a new result. + resultState = getStateFromUpdate( + workInProgress, + queue, + update, + resultState, + props, + instance + ); + var _callback = update.callback; + if (_callback !== null) { + workInProgress.effectTag |= Callback; + // Set this to null, in case it was mutated during an aborted render. + update.nextEffect = null; + if (queue.lastEffect === null) { + queue.firstEffect = queue.lastEffect = update; + } else { + queue.lastEffect.nextEffect = update; + queue.lastEffect = update; + } + } + } + // Continue to the next update. + update = update.next; + } + + // Separately, iterate though the list of captured updates. + var newFirstCapturedUpdate = null; + update = queue.firstCapturedUpdate; + while (update !== null) { + var _updateExpirationTime = update.expirationTime; + if (_updateExpirationTime < renderExpirationTime) { + // This update does not have sufficient priority. Skip it. + if (newFirstCapturedUpdate === null) { + // This is the first skipped captured update. It will be the first + // update in the new list. + newFirstCapturedUpdate = update; + // If this is the first update that was skipped, the current result is + // the new base state. + if (newFirstUpdate === null) { + newBaseState = resultState; + } + } + // Since this update will remain in the list, update the remaining + // expiration time. + if (newExpirationTime < _updateExpirationTime) { + newExpirationTime = _updateExpirationTime; + } + } else { + // This update does have sufficient priority. Process it and compute + // a new result. + resultState = getStateFromUpdate( + workInProgress, + queue, + update, + resultState, + props, + instance + ); + var _callback2 = update.callback; + if (_callback2 !== null) { + workInProgress.effectTag |= Callback; + // Set this to null, in case it was mutated during an aborted render. + update.nextEffect = null; + if (queue.lastCapturedEffect === null) { + queue.firstCapturedEffect = queue.lastCapturedEffect = update; + } else { + queue.lastCapturedEffect.nextEffect = update; + queue.lastCapturedEffect = update; + } + } + } + update = update.next; + } + + if (newFirstUpdate === null) { + queue.lastUpdate = null; + } + if (newFirstCapturedUpdate === null) { + queue.lastCapturedUpdate = null; + } else { + workInProgress.effectTag |= Callback; + } + if (newFirstUpdate === null && newFirstCapturedUpdate === null) { + // We processed every update, without skipping. That means the new base + // state is the same as the result state. + newBaseState = resultState; + } + + queue.baseState = newBaseState; + queue.firstUpdate = newFirstUpdate; + queue.firstCapturedUpdate = newFirstCapturedUpdate; + + // Set the remaining expiration time to be whatever is remaining in the queue. + // This should be fine because the only two other things that contribute to + // expiration time are props and context. We're already in the middle of the + // begin phase by the time we start processing the queue, so we've already + // dealt with the props. Context in components that specify + // shouldComponentUpdate is tricky; but we'll have to account for + // that regardless. + workInProgress.expirationTime = newExpirationTime; + workInProgress.memoizedState = resultState; + + { + currentlyProcessingQueue = null; + } +} + +function callCallback(callback, context) { + (function() { + if (!(typeof callback === "function")) { + throw ReactError( + "Invalid argument passed as callback. Expected a function. Instead received: " + + callback + ); + } + })(); + callback.call(context); +} + +function resetHasForceUpdateBeforeProcessing() { + hasForceUpdate = false; +} + +function checkHasForceUpdateAfterProcessing() { + return hasForceUpdate; +} + +function commitUpdateQueue( + finishedWork, + finishedQueue, + instance, + renderExpirationTime +) { + // If the finished render included captured updates, and there are still + // lower priority updates left over, we need to keep the captured updates + // in the queue so that they are rebased and not dropped once we process the + // queue again at the lower priority. + if (finishedQueue.firstCapturedUpdate !== null) { + // Join the captured update list to the end of the normal list. + if (finishedQueue.lastUpdate !== null) { + finishedQueue.lastUpdate.next = finishedQueue.firstCapturedUpdate; + finishedQueue.lastUpdate = finishedQueue.lastCapturedUpdate; + } + // Clear the list of captured updates. + finishedQueue.firstCapturedUpdate = finishedQueue.lastCapturedUpdate = null; + } + + // Commit the effects + commitUpdateEffects(finishedQueue.firstEffect, instance); + finishedQueue.firstEffect = finishedQueue.lastEffect = null; + + commitUpdateEffects(finishedQueue.firstCapturedEffect, instance); + finishedQueue.firstCapturedEffect = finishedQueue.lastCapturedEffect = null; +} + +function commitUpdateEffects(effect, instance) { + while (effect !== null) { + var _callback3 = effect.callback; + if (_callback3 !== null) { + effect.callback = null; + callCallback(_callback3, instance); + } + effect = effect.nextEffect; + } +} + +var fakeInternalInstance = {}; +var isArray$1 = Array.isArray; + +// React.Component uses a shared frozen object by default. +// We'll use it to determine whether we need to initialize legacy refs. +var emptyRefsObject = new React.Component().refs; + +var didWarnAboutStateAssignmentForComponent = void 0; +var didWarnAboutUninitializedState = void 0; +var didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate = void 0; +var didWarnAboutLegacyLifecyclesAndDerivedState = void 0; +var didWarnAboutUndefinedDerivedState = void 0; +var warnOnUndefinedDerivedState = void 0; +var warnOnInvalidCallback = void 0; +var didWarnAboutDirectlyAssigningPropsToState = void 0; +var didWarnAboutContextTypeAndContextTypes = void 0; +var didWarnAboutInvalidateContextType = void 0; + +{ + didWarnAboutStateAssignmentForComponent = new Set(); + didWarnAboutUninitializedState = new Set(); + didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate = new Set(); + didWarnAboutLegacyLifecyclesAndDerivedState = new Set(); + didWarnAboutDirectlyAssigningPropsToState = new Set(); + didWarnAboutUndefinedDerivedState = new Set(); + didWarnAboutContextTypeAndContextTypes = new Set(); + didWarnAboutInvalidateContextType = new Set(); + + var didWarnOnInvalidCallback = new Set(); + + warnOnInvalidCallback = function(callback, callerName) { + if (callback === null || typeof callback === "function") { + return; + } + var key = callerName + "_" + callback; + if (!didWarnOnInvalidCallback.has(key)) { + didWarnOnInvalidCallback.add(key); + warningWithoutStack$1( + false, + "%s(...): Expected the last optional `callback` argument to be a " + + "function. Instead received: %s.", + callerName, + callback + ); + } + }; + + warnOnUndefinedDerivedState = function(type, partialState) { + if (partialState === undefined) { + var componentName = getComponentName(type) || "Component"; + if (!didWarnAboutUndefinedDerivedState.has(componentName)) { + didWarnAboutUndefinedDerivedState.add(componentName); + warningWithoutStack$1( + false, + "%s.getDerivedStateFromProps(): A valid state object (or null) must be returned. " + + "You have returned undefined.", + componentName + ); + } + } + }; + + // This is so gross but it's at least non-critical and can be removed if + // it causes problems. This is meant to give a nicer error message for + // ReactDOM15.unstable_renderSubtreeIntoContainer(reactDOM16Component, + // ...)) which otherwise throws a "_processChildContext is not a function" + // exception. + Object.defineProperty(fakeInternalInstance, "_processChildContext", { + enumerable: false, + value: function() { + (function() { + { + throw ReactError( + "_processChildContext is not available in React 16+. This likely means you have multiple copies of React and are attempting to nest a React 15 tree inside a React 16 tree using unstable_renderSubtreeIntoContainer, which isn't supported. Try to make sure you have only one copy of React (and ideally, switch to ReactDOM.createPortal)." + ); + } + })(); + } + }); + Object.freeze(fakeInternalInstance); +} + +function applyDerivedStateFromProps( + workInProgress, + ctor, + getDerivedStateFromProps, + nextProps +) { + var prevState = workInProgress.memoizedState; + + { + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + // Invoke the function an extra time to help detect side-effects. + getDerivedStateFromProps(nextProps, prevState); + } + } + + var partialState = getDerivedStateFromProps(nextProps, prevState); + + { + warnOnUndefinedDerivedState(ctor, partialState); + } + // Merge the partial state and the previous state. + var memoizedState = + partialState === null || partialState === undefined + ? prevState + : Object.assign({}, prevState, partialState); + workInProgress.memoizedState = memoizedState; + + // Once the update queue is empty, persist the derived state onto the + // base state. + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null && workInProgress.expirationTime === NoWork) { + updateQueue.baseState = memoizedState; + } +} + +var classComponentUpdater = { + isMounted: isMounted, + enqueueSetState: function(inst, payload, callback) { + var fiber = get(inst); + var currentTime = requestCurrentTime(); + var expirationTime = computeExpirationForFiber(currentTime, fiber); + + var update = createUpdate(expirationTime); + update.payload = payload; + if (callback !== undefined && callback !== null) { + { + warnOnInvalidCallback(callback, "setState"); + } + update.callback = callback; + } + + flushPassiveEffects(); + enqueueUpdate(fiber, update); + scheduleWork(fiber, expirationTime); + }, + enqueueReplaceState: function(inst, payload, callback) { + var fiber = get(inst); + var currentTime = requestCurrentTime(); + var expirationTime = computeExpirationForFiber(currentTime, fiber); + + var update = createUpdate(expirationTime); + update.tag = ReplaceState; + update.payload = payload; + + if (callback !== undefined && callback !== null) { + { + warnOnInvalidCallback(callback, "replaceState"); + } + update.callback = callback; + } + + flushPassiveEffects(); + enqueueUpdate(fiber, update); + scheduleWork(fiber, expirationTime); + }, + enqueueForceUpdate: function(inst, callback) { + var fiber = get(inst); + var currentTime = requestCurrentTime(); + var expirationTime = computeExpirationForFiber(currentTime, fiber); + + var update = createUpdate(expirationTime); + update.tag = ForceUpdate; + + if (callback !== undefined && callback !== null) { + { + warnOnInvalidCallback(callback, "forceUpdate"); + } + update.callback = callback; + } + + flushPassiveEffects(); + enqueueUpdate(fiber, update); + scheduleWork(fiber, expirationTime); + } +}; + +function checkShouldComponentUpdate( + workInProgress, + ctor, + oldProps, + newProps, + oldState, + newState, + nextContext +) { + var instance = workInProgress.stateNode; + if (typeof instance.shouldComponentUpdate === "function") { + startPhaseTimer(workInProgress, "shouldComponentUpdate"); + var shouldUpdate = instance.shouldComponentUpdate( + newProps, + newState, + nextContext + ); + stopPhaseTimer(); + + { + !(shouldUpdate !== undefined) + ? warningWithoutStack$1( + false, + "%s.shouldComponentUpdate(): Returned undefined instead of a " + + "boolean value. Make sure to return true or false.", + getComponentName(ctor) || "Component" + ) + : void 0; + } + + return shouldUpdate; + } + + if (ctor.prototype && ctor.prototype.isPureReactComponent) { + return ( + !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState) + ); + } + + return true; +} + +function checkClassInstance(workInProgress, ctor, newProps) { + var instance = workInProgress.stateNode; + { + var name = getComponentName(ctor) || "Component"; + var renderPresent = instance.render; + + if (!renderPresent) { + if (ctor.prototype && typeof ctor.prototype.render === "function") { + warningWithoutStack$1( + false, + "%s(...): No `render` method found on the returned component " + + "instance: did you accidentally return an object from the constructor?", + name + ); + } else { + warningWithoutStack$1( + false, + "%s(...): No `render` method found on the returned component " + + "instance: you may have forgotten to define `render`.", + name + ); + } + } + + var noGetInitialStateOnES6 = + !instance.getInitialState || + instance.getInitialState.isReactClassApproved || + instance.state; + !noGetInitialStateOnES6 + ? warningWithoutStack$1( + false, + "getInitialState was defined on %s, a plain JavaScript class. " + + "This is only supported for classes created using React.createClass. " + + "Did you mean to define a state property instead?", + name + ) + : void 0; + var noGetDefaultPropsOnES6 = + !instance.getDefaultProps || + instance.getDefaultProps.isReactClassApproved; + !noGetDefaultPropsOnES6 + ? warningWithoutStack$1( + false, + "getDefaultProps was defined on %s, a plain JavaScript class. " + + "This is only supported for classes created using React.createClass. " + + "Use a static property to define defaultProps instead.", + name + ) + : void 0; + var noInstancePropTypes = !instance.propTypes; + !noInstancePropTypes + ? warningWithoutStack$1( + false, + "propTypes was defined as an instance property on %s. Use a static " + + "property to define propTypes instead.", + name + ) + : void 0; + var noInstanceContextType = !instance.contextType; + !noInstanceContextType + ? warningWithoutStack$1( + false, + "contextType was defined as an instance property on %s. Use a static " + + "property to define contextType instead.", + name + ) + : void 0; + var noInstanceContextTypes = !instance.contextTypes; + !noInstanceContextTypes + ? warningWithoutStack$1( + false, + "contextTypes was defined as an instance property on %s. Use a static " + + "property to define contextTypes instead.", + name + ) + : void 0; + + if ( + ctor.contextType && + ctor.contextTypes && + !didWarnAboutContextTypeAndContextTypes.has(ctor) + ) { + didWarnAboutContextTypeAndContextTypes.add(ctor); + warningWithoutStack$1( + false, + "%s declares both contextTypes and contextType static properties. " + + "The legacy contextTypes property will be ignored.", + name + ); + } + + var noComponentShouldUpdate = + typeof instance.componentShouldUpdate !== "function"; + !noComponentShouldUpdate + ? warningWithoutStack$1( + false, + "%s has a method called " + + "componentShouldUpdate(). Did you mean shouldComponentUpdate()? " + + "The name is phrased as a question because the function is " + + "expected to return a value.", + name + ) + : void 0; + if ( + ctor.prototype && + ctor.prototype.isPureReactComponent && + typeof instance.shouldComponentUpdate !== "undefined" + ) { + warningWithoutStack$1( + false, + "%s has a method called shouldComponentUpdate(). " + + "shouldComponentUpdate should not be used when extending React.PureComponent. " + + "Please extend React.Component if shouldComponentUpdate is used.", + getComponentName(ctor) || "A pure component" + ); + } + var noComponentDidUnmount = + typeof instance.componentDidUnmount !== "function"; + !noComponentDidUnmount + ? warningWithoutStack$1( + false, + "%s has a method called " + + "componentDidUnmount(). But there is no such lifecycle method. " + + "Did you mean componentWillUnmount()?", + name + ) + : void 0; + var noComponentDidReceiveProps = + typeof instance.componentDidReceiveProps !== "function"; + !noComponentDidReceiveProps + ? warningWithoutStack$1( + false, + "%s has a method called " + + "componentDidReceiveProps(). But there is no such lifecycle method. " + + "If you meant to update the state in response to changing props, " + + "use componentWillReceiveProps(). If you meant to fetch data or " + + "run side-effects or mutations after React has updated the UI, use componentDidUpdate().", + name + ) + : void 0; + var noComponentWillRecieveProps = + typeof instance.componentWillRecieveProps !== "function"; + !noComponentWillRecieveProps + ? warningWithoutStack$1( + false, + "%s has a method called " + + "componentWillRecieveProps(). Did you mean componentWillReceiveProps()?", + name + ) + : void 0; + var noUnsafeComponentWillRecieveProps = + typeof instance.UNSAFE_componentWillRecieveProps !== "function"; + !noUnsafeComponentWillRecieveProps + ? warningWithoutStack$1( + false, + "%s has a method called " + + "UNSAFE_componentWillRecieveProps(). Did you mean UNSAFE_componentWillReceiveProps()?", + name + ) + : void 0; + var hasMutatedProps = instance.props !== newProps; + !(instance.props === undefined || !hasMutatedProps) + ? warningWithoutStack$1( + false, + "%s(...): When calling super() in `%s`, make sure to pass " + + "up the same props that your component's constructor was passed.", + name, + name + ) + : void 0; + var noInstanceDefaultProps = !instance.defaultProps; + !noInstanceDefaultProps + ? warningWithoutStack$1( + false, + "Setting defaultProps as an instance property on %s is not supported and will be ignored." + + " Instead, define defaultProps as a static property on %s.", + name, + name + ) + : void 0; + + if ( + typeof instance.getSnapshotBeforeUpdate === "function" && + typeof instance.componentDidUpdate !== "function" && + !didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.has(ctor) + ) { + didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.add(ctor); + warningWithoutStack$1( + false, + "%s: getSnapshotBeforeUpdate() should be used with componentDidUpdate(). " + + "This component defines getSnapshotBeforeUpdate() only.", + getComponentName(ctor) + ); + } + + var noInstanceGetDerivedStateFromProps = + typeof instance.getDerivedStateFromProps !== "function"; + !noInstanceGetDerivedStateFromProps + ? warningWithoutStack$1( + false, + "%s: getDerivedStateFromProps() is defined as an instance method " + + "and will be ignored. Instead, declare it as a static method.", + name + ) + : void 0; + var noInstanceGetDerivedStateFromCatch = + typeof instance.getDerivedStateFromError !== "function"; + !noInstanceGetDerivedStateFromCatch + ? warningWithoutStack$1( + false, + "%s: getDerivedStateFromError() is defined as an instance method " + + "and will be ignored. Instead, declare it as a static method.", + name + ) + : void 0; + var noStaticGetSnapshotBeforeUpdate = + typeof ctor.getSnapshotBeforeUpdate !== "function"; + !noStaticGetSnapshotBeforeUpdate + ? warningWithoutStack$1( + false, + "%s: getSnapshotBeforeUpdate() is defined as a static method " + + "and will be ignored. Instead, declare it as an instance method.", + name + ) + : void 0; + var _state = instance.state; + if (_state && (typeof _state !== "object" || isArray$1(_state))) { + warningWithoutStack$1( + false, + "%s.state: must be set to an object or null", + name + ); + } + if (typeof instance.getChildContext === "function") { + !(typeof ctor.childContextTypes === "object") + ? warningWithoutStack$1( + false, + "%s.getChildContext(): childContextTypes must be defined in order to " + + "use getChildContext().", + name + ) + : void 0; + } + } +} + +function adoptClassInstance(workInProgress, instance) { + instance.updater = classComponentUpdater; + workInProgress.stateNode = instance; + // The instance needs access to the fiber so that it can schedule updates + set(instance, workInProgress); + { + instance._reactInternalInstance = fakeInternalInstance; + } +} + +function constructClassInstance( + workInProgress, + ctor, + props, + renderExpirationTime +) { + var isLegacyContextConsumer = false; + var unmaskedContext = emptyContextObject; + var context = null; + var contextType = ctor.contextType; + + { + if ("contextType" in ctor) { + var isValid = + // Allow null for conditional declaration + contextType === null || + (contextType !== undefined && + contextType.$$typeof === REACT_CONTEXT_TYPE && + contextType._context === undefined); // Not a + + if (!isValid && !didWarnAboutInvalidateContextType.has(ctor)) { + didWarnAboutInvalidateContextType.add(ctor); + + var addendum = ""; + if (contextType === undefined) { + addendum = + " However, it is set to undefined. " + + "This can be caused by a typo or by mixing up named and default imports. " + + "This can also happen due to a circular dependency, so " + + "try moving the createContext() call to a separate file."; + } else if (typeof contextType !== "object") { + addendum = " However, it is set to a " + typeof contextType + "."; + } else if (contextType.$$typeof === REACT_PROVIDER_TYPE) { + addendum = " Did you accidentally pass the Context.Provider instead?"; + } else if (contextType._context !== undefined) { + // + addendum = " Did you accidentally pass the Context.Consumer instead?"; + } else { + addendum = + " However, it is set to an object with keys {" + + Object.keys(contextType).join(", ") + + "}."; + } + warningWithoutStack$1( + false, + "%s defines an invalid contextType. " + + "contextType should point to the Context object returned by React.createContext().%s", + getComponentName(ctor) || "Component", + addendum + ); + } + } + } + + if (typeof contextType === "object" && contextType !== null) { + context = readContext(contextType); + } else { + unmaskedContext = getUnmaskedContext(workInProgress, ctor, true); + var contextTypes = ctor.contextTypes; + isLegacyContextConsumer = + contextTypes !== null && contextTypes !== undefined; + context = isLegacyContextConsumer + ? getMaskedContext(workInProgress, unmaskedContext) + : emptyContextObject; + } + + // Instantiate twice to help detect side-effects. + { + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + new ctor(props, context); // eslint-disable-line no-new + } + } + + var instance = new ctor(props, context); + var state = (workInProgress.memoizedState = + instance.state !== null && instance.state !== undefined + ? instance.state + : null); + adoptClassInstance(workInProgress, instance); + + { + if (typeof ctor.getDerivedStateFromProps === "function" && state === null) { + var componentName = getComponentName(ctor) || "Component"; + if (!didWarnAboutUninitializedState.has(componentName)) { + didWarnAboutUninitializedState.add(componentName); + warningWithoutStack$1( + false, + "`%s` uses `getDerivedStateFromProps` but its initial state is " + + "%s. This is not recommended. Instead, define the initial state by " + + "assigning an object to `this.state` in the constructor of `%s`. " + + "This ensures that `getDerivedStateFromProps` arguments have a consistent shape.", + componentName, + instance.state === null ? "null" : "undefined", + componentName + ); + } + } + + // If new component APIs are defined, "unsafe" lifecycles won't be called. + // Warn about these lifecycles if they are present. + // Don't warn about react-lifecycles-compat polyfilled methods though. + if ( + typeof ctor.getDerivedStateFromProps === "function" || + typeof instance.getSnapshotBeforeUpdate === "function" + ) { + var foundWillMountName = null; + var foundWillReceivePropsName = null; + var foundWillUpdateName = null; + if ( + typeof instance.componentWillMount === "function" && + instance.componentWillMount.__suppressDeprecationWarning !== true + ) { + foundWillMountName = "componentWillMount"; + } else if (typeof instance.UNSAFE_componentWillMount === "function") { + foundWillMountName = "UNSAFE_componentWillMount"; + } + if ( + typeof instance.componentWillReceiveProps === "function" && + instance.componentWillReceiveProps.__suppressDeprecationWarning !== true + ) { + foundWillReceivePropsName = "componentWillReceiveProps"; + } else if ( + typeof instance.UNSAFE_componentWillReceiveProps === "function" + ) { + foundWillReceivePropsName = "UNSAFE_componentWillReceiveProps"; + } + if ( + typeof instance.componentWillUpdate === "function" && + instance.componentWillUpdate.__suppressDeprecationWarning !== true + ) { + foundWillUpdateName = "componentWillUpdate"; + } else if (typeof instance.UNSAFE_componentWillUpdate === "function") { + foundWillUpdateName = "UNSAFE_componentWillUpdate"; + } + if ( + foundWillMountName !== null || + foundWillReceivePropsName !== null || + foundWillUpdateName !== null + ) { + var _componentName = getComponentName(ctor) || "Component"; + var newApiName = + typeof ctor.getDerivedStateFromProps === "function" + ? "getDerivedStateFromProps()" + : "getSnapshotBeforeUpdate()"; + if (!didWarnAboutLegacyLifecyclesAndDerivedState.has(_componentName)) { + didWarnAboutLegacyLifecyclesAndDerivedState.add(_componentName); + warningWithoutStack$1( + false, + "Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n" + + "%s uses %s but also contains the following legacy lifecycles:%s%s%s\n\n" + + "The above lifecycles should be removed. Learn more about this warning here:\n" + + "https://fb.me/react-async-component-lifecycle-hooks", + _componentName, + newApiName, + foundWillMountName !== null ? "\n " + foundWillMountName : "", + foundWillReceivePropsName !== null + ? "\n " + foundWillReceivePropsName + : "", + foundWillUpdateName !== null ? "\n " + foundWillUpdateName : "" + ); + } + } + } + } + + // Cache unmasked context so we can avoid recreating masked context unless necessary. + // ReactFiberContext usually updates this cache but can't for newly-created instances. + if (isLegacyContextConsumer) { + cacheContext(workInProgress, unmaskedContext, context); + } + + return instance; +} + +function callComponentWillMount(workInProgress, instance) { + startPhaseTimer(workInProgress, "componentWillMount"); + var oldState = instance.state; + + if (typeof instance.componentWillMount === "function") { + instance.componentWillMount(); + } + if (typeof instance.UNSAFE_componentWillMount === "function") { + instance.UNSAFE_componentWillMount(); + } + + stopPhaseTimer(); + + if (oldState !== instance.state) { + { + warningWithoutStack$1( + false, + "%s.componentWillMount(): Assigning directly to this.state is " + + "deprecated (except inside a component's " + + "constructor). Use setState instead.", + getComponentName(workInProgress.type) || "Component" + ); + } + classComponentUpdater.enqueueReplaceState(instance, instance.state, null); + } +} + +function callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + nextContext +) { + var oldState = instance.state; + startPhaseTimer(workInProgress, "componentWillReceiveProps"); + if (typeof instance.componentWillReceiveProps === "function") { + instance.componentWillReceiveProps(newProps, nextContext); + } + if (typeof instance.UNSAFE_componentWillReceiveProps === "function") { + instance.UNSAFE_componentWillReceiveProps(newProps, nextContext); + } + stopPhaseTimer(); + + if (instance.state !== oldState) { + { + var componentName = getComponentName(workInProgress.type) || "Component"; + if (!didWarnAboutStateAssignmentForComponent.has(componentName)) { + didWarnAboutStateAssignmentForComponent.add(componentName); + warningWithoutStack$1( + false, + "%s.componentWillReceiveProps(): Assigning directly to " + + "this.state is deprecated (except inside a component's " + + "constructor). Use setState instead.", + componentName + ); + } + } + classComponentUpdater.enqueueReplaceState(instance, instance.state, null); + } +} + +// Invokes the mount life-cycles on a previously never rendered instance. +function mountClassInstance( + workInProgress, + ctor, + newProps, + renderExpirationTime +) { + { + checkClassInstance(workInProgress, ctor, newProps); + } + + var instance = workInProgress.stateNode; + instance.props = newProps; + instance.state = workInProgress.memoizedState; + instance.refs = emptyRefsObject; + + var contextType = ctor.contextType; + if (typeof contextType === "object" && contextType !== null) { + instance.context = readContext(contextType); + } else { + var unmaskedContext = getUnmaskedContext(workInProgress, ctor, true); + instance.context = getMaskedContext(workInProgress, unmaskedContext); + } + + { + if (instance.state === newProps) { + var componentName = getComponentName(ctor) || "Component"; + if (!didWarnAboutDirectlyAssigningPropsToState.has(componentName)) { + didWarnAboutDirectlyAssigningPropsToState.add(componentName); + warningWithoutStack$1( + false, + "%s: It is not recommended to assign props directly to state " + + "because updates to props won't be reflected in state. " + + "In most cases, it is better to use props directly.", + componentName + ); + } + } + + if (workInProgress.mode & StrictMode) { + ReactStrictModeWarnings.recordUnsafeLifecycleWarnings( + workInProgress, + instance + ); + + ReactStrictModeWarnings.recordLegacyContextWarning( + workInProgress, + instance + ); + } + + if (warnAboutDeprecatedLifecycles) { + ReactStrictModeWarnings.recordDeprecationWarnings( + workInProgress, + instance + ); + } + } + + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null) { + processUpdateQueue( + workInProgress, + updateQueue, + newProps, + instance, + renderExpirationTime + ); + instance.state = workInProgress.memoizedState; + } + + var getDerivedStateFromProps = ctor.getDerivedStateFromProps; + if (typeof getDerivedStateFromProps === "function") { + applyDerivedStateFromProps( + workInProgress, + ctor, + getDerivedStateFromProps, + newProps + ); + instance.state = workInProgress.memoizedState; + } + + // In order to support react-lifecycles-compat polyfilled components, + // Unsafe lifecycles should not be invoked for components using the new APIs. + if ( + typeof ctor.getDerivedStateFromProps !== "function" && + typeof instance.getSnapshotBeforeUpdate !== "function" && + (typeof instance.UNSAFE_componentWillMount === "function" || + typeof instance.componentWillMount === "function") + ) { + callComponentWillMount(workInProgress, instance); + // If we had additional state updates during this life-cycle, let's + // process them now. + updateQueue = workInProgress.updateQueue; + if (updateQueue !== null) { + processUpdateQueue( + workInProgress, + updateQueue, + newProps, + instance, + renderExpirationTime + ); + instance.state = workInProgress.memoizedState; + } + } + + if (typeof instance.componentDidMount === "function") { + workInProgress.effectTag |= Update; + } +} + +function resumeMountClassInstance( + workInProgress, + ctor, + newProps, + renderExpirationTime +) { + var instance = workInProgress.stateNode; + + var oldProps = workInProgress.memoizedProps; + instance.props = oldProps; + + var oldContext = instance.context; + var contextType = ctor.contextType; + var nextContext = void 0; + if (typeof contextType === "object" && contextType !== null) { + nextContext = readContext(contextType); + } else { + var nextLegacyUnmaskedContext = getUnmaskedContext( + workInProgress, + ctor, + true + ); + nextContext = getMaskedContext(workInProgress, nextLegacyUnmaskedContext); + } + + var getDerivedStateFromProps = ctor.getDerivedStateFromProps; + var hasNewLifecycles = + typeof getDerivedStateFromProps === "function" || + typeof instance.getSnapshotBeforeUpdate === "function"; + + // Note: During these life-cycles, instance.props/instance.state are what + // ever the previously attempted to render - not the "current". However, + // during componentDidUpdate we pass the "current" props. + + // In order to support react-lifecycles-compat polyfilled components, + // Unsafe lifecycles should not be invoked for components using the new APIs. + if ( + !hasNewLifecycles && + (typeof instance.UNSAFE_componentWillReceiveProps === "function" || + typeof instance.componentWillReceiveProps === "function") + ) { + if (oldProps !== newProps || oldContext !== nextContext) { + callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + nextContext + ); + } + } + + resetHasForceUpdateBeforeProcessing(); + + var oldState = workInProgress.memoizedState; + var newState = (instance.state = oldState); + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null) { + processUpdateQueue( + workInProgress, + updateQueue, + newProps, + instance, + renderExpirationTime + ); + newState = workInProgress.memoizedState; + } + if ( + oldProps === newProps && + oldState === newState && + !hasContextChanged() && + !checkHasForceUpdateAfterProcessing() + ) { + // If an update was already in progress, we should schedule an Update + // effect even though we're bailing out, so that cWU/cDU are called. + if (typeof instance.componentDidMount === "function") { + workInProgress.effectTag |= Update; + } + return false; + } + + if (typeof getDerivedStateFromProps === "function") { + applyDerivedStateFromProps( + workInProgress, + ctor, + getDerivedStateFromProps, + newProps + ); + newState = workInProgress.memoizedState; + } + + var shouldUpdate = + checkHasForceUpdateAfterProcessing() || + checkShouldComponentUpdate( + workInProgress, + ctor, + oldProps, + newProps, + oldState, + newState, + nextContext + ); + + if (shouldUpdate) { + // In order to support react-lifecycles-compat polyfilled components, + // Unsafe lifecycles should not be invoked for components using the new APIs. + if ( + !hasNewLifecycles && + (typeof instance.UNSAFE_componentWillMount === "function" || + typeof instance.componentWillMount === "function") + ) { + startPhaseTimer(workInProgress, "componentWillMount"); + if (typeof instance.componentWillMount === "function") { + instance.componentWillMount(); + } + if (typeof instance.UNSAFE_componentWillMount === "function") { + instance.UNSAFE_componentWillMount(); + } + stopPhaseTimer(); + } + if (typeof instance.componentDidMount === "function") { + workInProgress.effectTag |= Update; + } + } else { + // If an update was already in progress, we should schedule an Update + // effect even though we're bailing out, so that cWU/cDU are called. + if (typeof instance.componentDidMount === "function") { + workInProgress.effectTag |= Update; + } + + // If shouldComponentUpdate returned false, we should still update the + // memoized state to indicate that this work can be reused. + workInProgress.memoizedProps = newProps; + workInProgress.memoizedState = newState; + } + + // Update the existing instance's state, props, and context pointers even + // if shouldComponentUpdate returns false. + instance.props = newProps; + instance.state = newState; + instance.context = nextContext; + + return shouldUpdate; +} + +// Invokes the update life-cycles and returns false if it shouldn't rerender. +function updateClassInstance( + current, + workInProgress, + ctor, + newProps, + renderExpirationTime +) { + var instance = workInProgress.stateNode; + + var oldProps = workInProgress.memoizedProps; + instance.props = + workInProgress.type === workInProgress.elementType + ? oldProps + : resolveDefaultProps(workInProgress.type, oldProps); + + var oldContext = instance.context; + var contextType = ctor.contextType; + var nextContext = void 0; + if (typeof contextType === "object" && contextType !== null) { + nextContext = readContext(contextType); + } else { + var nextUnmaskedContext = getUnmaskedContext(workInProgress, ctor, true); + nextContext = getMaskedContext(workInProgress, nextUnmaskedContext); + } + + var getDerivedStateFromProps = ctor.getDerivedStateFromProps; + var hasNewLifecycles = + typeof getDerivedStateFromProps === "function" || + typeof instance.getSnapshotBeforeUpdate === "function"; + + // Note: During these life-cycles, instance.props/instance.state are what + // ever the previously attempted to render - not the "current". However, + // during componentDidUpdate we pass the "current" props. + + // In order to support react-lifecycles-compat polyfilled components, + // Unsafe lifecycles should not be invoked for components using the new APIs. + if ( + !hasNewLifecycles && + (typeof instance.UNSAFE_componentWillReceiveProps === "function" || + typeof instance.componentWillReceiveProps === "function") + ) { + if (oldProps !== newProps || oldContext !== nextContext) { + callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + nextContext + ); + } + } + + resetHasForceUpdateBeforeProcessing(); + + var oldState = workInProgress.memoizedState; + var newState = (instance.state = oldState); + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null) { + processUpdateQueue( + workInProgress, + updateQueue, + newProps, + instance, + renderExpirationTime + ); + newState = workInProgress.memoizedState; + } + + if ( + oldProps === newProps && + oldState === newState && + !hasContextChanged() && + !checkHasForceUpdateAfterProcessing() + ) { + // If an update was already in progress, we should schedule an Update + // effect even though we're bailing out, so that cWU/cDU are called. + if (typeof instance.componentDidUpdate === "function") { + if ( + oldProps !== current.memoizedProps || + oldState !== current.memoizedState + ) { + workInProgress.effectTag |= Update; + } + } + if (typeof instance.getSnapshotBeforeUpdate === "function") { + if ( + oldProps !== current.memoizedProps || + oldState !== current.memoizedState + ) { + workInProgress.effectTag |= Snapshot; + } + } + return false; + } + + if (typeof getDerivedStateFromProps === "function") { + applyDerivedStateFromProps( + workInProgress, + ctor, + getDerivedStateFromProps, + newProps + ); + newState = workInProgress.memoizedState; + } + + var shouldUpdate = + checkHasForceUpdateAfterProcessing() || + checkShouldComponentUpdate( + workInProgress, + ctor, + oldProps, + newProps, + oldState, + newState, + nextContext + ); + + if (shouldUpdate) { + // In order to support react-lifecycles-compat polyfilled components, + // Unsafe lifecycles should not be invoked for components using the new APIs. + if ( + !hasNewLifecycles && + (typeof instance.UNSAFE_componentWillUpdate === "function" || + typeof instance.componentWillUpdate === "function") + ) { + startPhaseTimer(workInProgress, "componentWillUpdate"); + if (typeof instance.componentWillUpdate === "function") { + instance.componentWillUpdate(newProps, newState, nextContext); + } + if (typeof instance.UNSAFE_componentWillUpdate === "function") { + instance.UNSAFE_componentWillUpdate(newProps, newState, nextContext); + } + stopPhaseTimer(); + } + if (typeof instance.componentDidUpdate === "function") { + workInProgress.effectTag |= Update; + } + if (typeof instance.getSnapshotBeforeUpdate === "function") { + workInProgress.effectTag |= Snapshot; + } + } else { + // If an update was already in progress, we should schedule an Update + // effect even though we're bailing out, so that cWU/cDU are called. + if (typeof instance.componentDidUpdate === "function") { + if ( + oldProps !== current.memoizedProps || + oldState !== current.memoizedState + ) { + workInProgress.effectTag |= Update; + } + } + if (typeof instance.getSnapshotBeforeUpdate === "function") { + if ( + oldProps !== current.memoizedProps || + oldState !== current.memoizedState + ) { + workInProgress.effectTag |= Snapshot; + } + } + + // If shouldComponentUpdate returned false, we should still update the + // memoized props/state to indicate that this work can be reused. + workInProgress.memoizedProps = newProps; + workInProgress.memoizedState = newState; + } + + // Update the existing instance's state, props, and context pointers even + // if shouldComponentUpdate returns false. + instance.props = newProps; + instance.state = newState; + instance.context = nextContext; + + return shouldUpdate; +} + +var didWarnAboutMaps = void 0; +var didWarnAboutGenerators = void 0; +var didWarnAboutStringRefInStrictMode = void 0; +var ownerHasKeyUseWarning = void 0; +var ownerHasFunctionTypeWarning = void 0; +var warnForMissingKey = function(child) {}; + +{ + didWarnAboutMaps = false; + didWarnAboutGenerators = false; + didWarnAboutStringRefInStrictMode = {}; + + /** + * Warn if there's no key explicitly set on dynamic arrays of children or + * object keys are not valid. This allows us to keep track of children between + * updates. + */ + ownerHasKeyUseWarning = {}; + ownerHasFunctionTypeWarning = {}; + + warnForMissingKey = function(child) { + if (child === null || typeof child !== "object") { + return; + } + if (!child._store || child._store.validated || child.key != null) { + return; + } + (function() { + if (!(typeof child._store === "object")) { + throw ReactError( + "React Component in warnForMissingKey should have a _store. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + child._store.validated = true; + + var currentComponentErrorInfo = + "Each child in a list should have a unique " + + '"key" prop. See https://fb.me/react-warning-keys for ' + + "more information." + + getCurrentFiberStackInDev(); + if (ownerHasKeyUseWarning[currentComponentErrorInfo]) { + return; + } + ownerHasKeyUseWarning[currentComponentErrorInfo] = true; + + warning$1( + false, + "Each child in a list should have a unique " + + '"key" prop. See https://fb.me/react-warning-keys for ' + + "more information." + ); + }; +} + +var isArray = Array.isArray; + +function coerceRef(returnFiber, current$$1, element) { + var mixedRef = element.ref; + if ( + mixedRef !== null && + typeof mixedRef !== "function" && + typeof mixedRef !== "object" + ) { + { + if (returnFiber.mode & StrictMode) { + var componentName = getComponentName(returnFiber.type) || "Component"; + if (!didWarnAboutStringRefInStrictMode[componentName]) { + warningWithoutStack$1( + false, + 'A string ref, "%s", has been found within a strict mode tree. ' + + "String refs are a source of potential bugs and should be avoided. " + + "We recommend using createRef() instead." + + "\n%s" + + "\n\nLearn more about using refs safely here:" + + "\nhttps://fb.me/react-strict-mode-string-ref", + mixedRef, + getStackByFiberInDevAndProd(returnFiber) + ); + didWarnAboutStringRefInStrictMode[componentName] = true; + } + } + } + + if (element._owner) { + var owner = element._owner; + var inst = void 0; + if (owner) { + var ownerFiber = owner; + (function() { + if (!(ownerFiber.tag === ClassComponent)) { + throw ReactError( + "Function components cannot have refs. Did you mean to use React.forwardRef()?" + ); + } + })(); + inst = ownerFiber.stateNode; + } + (function() { + if (!inst) { + throw ReactError( + "Missing owner for string ref " + + mixedRef + + ". This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + var stringRef = "" + mixedRef; + // Check if previous string ref matches new string ref + if ( + current$$1 !== null && + current$$1.ref !== null && + typeof current$$1.ref === "function" && + current$$1.ref._stringRef === stringRef + ) { + return current$$1.ref; + } + var ref = function(value) { + var refs = inst.refs; + if (refs === emptyRefsObject) { + // This is a lazy pooled frozen object, so we need to initialize. + refs = inst.refs = {}; + } + if (value === null) { + delete refs[stringRef]; + } else { + refs[stringRef] = value; + } + }; + ref._stringRef = stringRef; + return ref; + } else { + (function() { + if (!(typeof mixedRef === "string")) { + throw ReactError( + "Expected ref to be a function, a string, an object returned by React.createRef(), or null." + ); + } + })(); + (function() { + if (!element._owner) { + throw ReactError( + "Element ref was specified as a string (" + + mixedRef + + ") but no owner was set. This could happen for one of the following reasons:\n1. You may be adding a ref to a function component\n2. You may be adding a ref to a component that was not created inside a component's render method\n3. You have multiple copies of React loaded\nSee https://fb.me/react-refs-must-have-owner for more information." + ); + } + })(); + } + } + return mixedRef; +} + +function throwOnInvalidObjectType(returnFiber, newChild) { + if (returnFiber.type !== "textarea") { + var addendum = ""; + { + addendum = + " If you meant to render a collection of children, use an array " + + "instead." + + getCurrentFiberStackInDev(); + } + (function() { + { + throw ReactError( + "Objects are not valid as a React child (found: " + + (Object.prototype.toString.call(newChild) === "[object Object]" + ? "object with keys {" + Object.keys(newChild).join(", ") + "}" + : newChild) + + ")." + + addendum + ); + } + })(); + } +} + +function warnOnFunctionType() { + var currentComponentErrorInfo = + "Functions are not valid as a React child. This may happen if " + + "you return a Component instead of from render. " + + "Or maybe you meant to call this function rather than return it." + + getCurrentFiberStackInDev(); + + if (ownerHasFunctionTypeWarning[currentComponentErrorInfo]) { + return; + } + ownerHasFunctionTypeWarning[currentComponentErrorInfo] = true; + + warning$1( + false, + "Functions are not valid as a React child. This may happen if " + + "you return a Component instead of from render. " + + "Or maybe you meant to call this function rather than return it." + ); +} + +// This wrapper function exists because I expect to clone the code in each path +// to be able to optimize each path individually by branching early. This needs +// a compiler or we can do it manually. Helpers that don't need this branching +// live outside of this function. +function ChildReconciler(shouldTrackSideEffects) { + function deleteChild(returnFiber, childToDelete) { + if (!shouldTrackSideEffects) { + // Noop. + return; + } + // Deletions are added in reversed order so we add it to the front. + // At this point, the return fiber's effect list is empty except for + // deletions, so we can just append the deletion to the list. The remaining + // effects aren't added until the complete phase. Once we implement + // resuming, this may not be true. + var last = returnFiber.lastEffect; + if (last !== null) { + last.nextEffect = childToDelete; + returnFiber.lastEffect = childToDelete; + } else { + returnFiber.firstEffect = returnFiber.lastEffect = childToDelete; + } + childToDelete.nextEffect = null; + childToDelete.effectTag = Deletion; + } + + function deleteRemainingChildren(returnFiber, currentFirstChild) { + if (!shouldTrackSideEffects) { + // Noop. + return null; + } + + // TODO: For the shouldClone case, this could be micro-optimized a bit by + // assuming that after the first child we've already added everything. + var childToDelete = currentFirstChild; + while (childToDelete !== null) { + deleteChild(returnFiber, childToDelete); + childToDelete = childToDelete.sibling; + } + return null; + } + + function mapRemainingChildren(returnFiber, currentFirstChild) { + // Add the remaining children to a temporary map so that we can find them by + // keys quickly. Implicit (null) keys get added to this set with their index + var existingChildren = new Map(); + + var existingChild = currentFirstChild; + while (existingChild !== null) { + if (existingChild.key !== null) { + existingChildren.set(existingChild.key, existingChild); + } else { + existingChildren.set(existingChild.index, existingChild); + } + existingChild = existingChild.sibling; + } + return existingChildren; + } + + function useFiber(fiber, pendingProps, expirationTime) { + // We currently set sibling to null and index to 0 here because it is easy + // to forget to do before returning it. E.g. for the single child case. + var clone = createWorkInProgress(fiber, pendingProps, expirationTime); + clone.index = 0; + clone.sibling = null; + return clone; + } + + function placeChild(newFiber, lastPlacedIndex, newIndex) { + newFiber.index = newIndex; + if (!shouldTrackSideEffects) { + // Noop. + return lastPlacedIndex; + } + var current$$1 = newFiber.alternate; + if (current$$1 !== null) { + var oldIndex = current$$1.index; + if (oldIndex < lastPlacedIndex) { + // This is a move. + newFiber.effectTag = Placement; + return lastPlacedIndex; + } else { + // This item can stay in place. + return oldIndex; + } + } else { + // This is an insertion. + newFiber.effectTag = Placement; + return lastPlacedIndex; + } + } + + function placeSingleChild(newFiber) { + // This is simpler for the single child case. We only need to do a + // placement for inserting new children. + if (shouldTrackSideEffects && newFiber.alternate === null) { + newFiber.effectTag = Placement; + } + return newFiber; + } + + function updateTextNode( + returnFiber, + current$$1, + textContent, + expirationTime + ) { + if (current$$1 === null || current$$1.tag !== HostText) { + // Insert + var created = createFiberFromText( + textContent, + returnFiber.mode, + expirationTime + ); + created.return = returnFiber; + return created; + } else { + // Update + var existing = useFiber(current$$1, textContent, expirationTime); + existing.return = returnFiber; + return existing; + } + } + + function updateElement(returnFiber, current$$1, element, expirationTime) { + if (current$$1 !== null && current$$1.elementType === element.type) { + // Move based on index + var existing = useFiber(current$$1, element.props, expirationTime); + existing.ref = coerceRef(returnFiber, current$$1, element); + existing.return = returnFiber; + { + existing._debugSource = element._source; + existing._debugOwner = element._owner; + } + return existing; + } else { + // Insert + var created = createFiberFromElement( + element, + returnFiber.mode, + expirationTime + ); + created.ref = coerceRef(returnFiber, current$$1, element); + created.return = returnFiber; + return created; + } + } + + function updatePortal(returnFiber, current$$1, portal, expirationTime) { + if ( + current$$1 === null || + current$$1.tag !== HostPortal || + current$$1.stateNode.containerInfo !== portal.containerInfo || + current$$1.stateNode.implementation !== portal.implementation + ) { + // Insert + var created = createFiberFromPortal( + portal, + returnFiber.mode, + expirationTime + ); + created.return = returnFiber; + return created; + } else { + // Update + var existing = useFiber( + current$$1, + portal.children || [], + expirationTime + ); + existing.return = returnFiber; + return existing; + } + } + + function updateFragment( + returnFiber, + current$$1, + fragment, + expirationTime, + key + ) { + if (current$$1 === null || current$$1.tag !== Fragment) { + // Insert + var created = createFiberFromFragment( + fragment, + returnFiber.mode, + expirationTime, + key + ); + created.return = returnFiber; + return created; + } else { + // Update + var existing = useFiber(current$$1, fragment, expirationTime); + existing.return = returnFiber; + return existing; + } + } + + function createChild(returnFiber, newChild, expirationTime) { + if (typeof newChild === "string" || typeof newChild === "number") { + // Text nodes don't have keys. If the previous node is implicitly keyed + // we can continue to replace it without aborting even if it is not a text + // node. + var created = createFiberFromText( + "" + newChild, + returnFiber.mode, + expirationTime + ); + created.return = returnFiber; + return created; + } + + if (typeof newChild === "object" && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: { + var _created = createFiberFromElement( + newChild, + returnFiber.mode, + expirationTime + ); + _created.ref = coerceRef(returnFiber, null, newChild); + _created.return = returnFiber; + return _created; + } + case REACT_PORTAL_TYPE: { + var _created2 = createFiberFromPortal( + newChild, + returnFiber.mode, + expirationTime + ); + _created2.return = returnFiber; + return _created2; + } + } + + if (isArray(newChild) || getIteratorFn(newChild)) { + var _created3 = createFiberFromFragment( + newChild, + returnFiber.mode, + expirationTime, + null + ); + _created3.return = returnFiber; + return _created3; + } + + throwOnInvalidObjectType(returnFiber, newChild); + } + + { + if (typeof newChild === "function") { + warnOnFunctionType(); + } + } + + return null; + } + + function updateSlot(returnFiber, oldFiber, newChild, expirationTime) { + // Update the fiber if the keys match, otherwise return null. + + var key = oldFiber !== null ? oldFiber.key : null; + + if (typeof newChild === "string" || typeof newChild === "number") { + // Text nodes don't have keys. If the previous node is implicitly keyed + // we can continue to replace it without aborting even if it is not a text + // node. + if (key !== null) { + return null; + } + return updateTextNode( + returnFiber, + oldFiber, + "" + newChild, + expirationTime + ); + } + + if (typeof newChild === "object" && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: { + if (newChild.key === key) { + if (newChild.type === REACT_FRAGMENT_TYPE) { + return updateFragment( + returnFiber, + oldFiber, + newChild.props.children, + expirationTime, + key + ); + } + return updateElement( + returnFiber, + oldFiber, + newChild, + expirationTime + ); + } else { + return null; + } + } + case REACT_PORTAL_TYPE: { + if (newChild.key === key) { + return updatePortal( + returnFiber, + oldFiber, + newChild, + expirationTime + ); + } else { + return null; + } + } + } + + if (isArray(newChild) || getIteratorFn(newChild)) { + if (key !== null) { + return null; + } + + return updateFragment( + returnFiber, + oldFiber, + newChild, + expirationTime, + null + ); + } + + throwOnInvalidObjectType(returnFiber, newChild); + } + + { + if (typeof newChild === "function") { + warnOnFunctionType(); + } + } + + return null; + } + + function updateFromMap( + existingChildren, + returnFiber, + newIdx, + newChild, + expirationTime + ) { + if (typeof newChild === "string" || typeof newChild === "number") { + // Text nodes don't have keys, so we neither have to check the old nor + // new node for the key. If both are text nodes, they match. + var matchedFiber = existingChildren.get(newIdx) || null; + return updateTextNode( + returnFiber, + matchedFiber, + "" + newChild, + expirationTime + ); + } + + if (typeof newChild === "object" && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: { + var _matchedFiber = + existingChildren.get( + newChild.key === null ? newIdx : newChild.key + ) || null; + if (newChild.type === REACT_FRAGMENT_TYPE) { + return updateFragment( + returnFiber, + _matchedFiber, + newChild.props.children, + expirationTime, + newChild.key + ); + } + return updateElement( + returnFiber, + _matchedFiber, + newChild, + expirationTime + ); + } + case REACT_PORTAL_TYPE: { + var _matchedFiber2 = + existingChildren.get( + newChild.key === null ? newIdx : newChild.key + ) || null; + return updatePortal( + returnFiber, + _matchedFiber2, + newChild, + expirationTime + ); + } + } + + if (isArray(newChild) || getIteratorFn(newChild)) { + var _matchedFiber3 = existingChildren.get(newIdx) || null; + return updateFragment( + returnFiber, + _matchedFiber3, + newChild, + expirationTime, + null + ); + } + + throwOnInvalidObjectType(returnFiber, newChild); + } + + { + if (typeof newChild === "function") { + warnOnFunctionType(); + } + } + + return null; + } + + /** + * Warns if there is a duplicate or missing key + */ + function warnOnInvalidKey(child, knownKeys) { + { + if (typeof child !== "object" || child === null) { + return knownKeys; + } + switch (child.$$typeof) { + case REACT_ELEMENT_TYPE: + case REACT_PORTAL_TYPE: + warnForMissingKey(child); + var key = child.key; + if (typeof key !== "string") { + break; + } + if (knownKeys === null) { + knownKeys = new Set(); + knownKeys.add(key); + break; + } + if (!knownKeys.has(key)) { + knownKeys.add(key); + break; + } + warning$1( + false, + "Encountered two children with the same key, `%s`. " + + "Keys should be unique so that components maintain their identity " + + "across updates. Non-unique keys may cause children to be " + + "duplicated and/or omitted — the behavior is unsupported and " + + "could change in a future version.", + key + ); + break; + default: + break; + } + } + return knownKeys; + } + + function reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChildren, + expirationTime + ) { + // This algorithm can't optimize by searching from both ends since we + // don't have backpointers on fibers. I'm trying to see how far we can get + // with that model. If it ends up not being worth the tradeoffs, we can + // add it later. + + // Even with a two ended optimization, we'd want to optimize for the case + // where there are few changes and brute force the comparison instead of + // going for the Map. It'd like to explore hitting that path first in + // forward-only mode and only go for the Map once we notice that we need + // lots of look ahead. This doesn't handle reversal as well as two ended + // search but that's unusual. Besides, for the two ended optimization to + // work on Iterables, we'd need to copy the whole set. + + // In this first iteration, we'll just live with hitting the bad case + // (adding everything to a Map) in for every insert/move. + + // If you change this code, also update reconcileChildrenIterator() which + // uses the same algorithm. + + { + // First, validate keys. + var knownKeys = null; + for (var i = 0; i < newChildren.length; i++) { + var child = newChildren[i]; + knownKeys = warnOnInvalidKey(child, knownKeys); + } + } + + var resultingFirstChild = null; + var previousNewFiber = null; + + var oldFiber = currentFirstChild; + var lastPlacedIndex = 0; + var newIdx = 0; + var nextOldFiber = null; + for (; oldFiber !== null && newIdx < newChildren.length; newIdx++) { + if (oldFiber.index > newIdx) { + nextOldFiber = oldFiber; + oldFiber = null; + } else { + nextOldFiber = oldFiber.sibling; + } + var newFiber = updateSlot( + returnFiber, + oldFiber, + newChildren[newIdx], + expirationTime + ); + if (newFiber === null) { + // TODO: This breaks on empty slots like null children. That's + // unfortunate because it triggers the slow path all the time. We need + // a better way to communicate whether this was a miss or null, + // boolean, undefined, etc. + if (oldFiber === null) { + oldFiber = nextOldFiber; + } + break; + } + if (shouldTrackSideEffects) { + if (oldFiber && newFiber.alternate === null) { + // We matched the slot, but we didn't reuse the existing fiber, so we + // need to delete the existing child. + deleteChild(returnFiber, oldFiber); + } + } + lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = newFiber; + } else { + // TODO: Defer siblings if we're not at the right index for this slot. + // I.e. if we had null values before, then we want to defer this + // for each null value. However, we also don't want to call updateSlot + // with the previous one. + previousNewFiber.sibling = newFiber; + } + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } + + if (newIdx === newChildren.length) { + // We've reached the end of the new children. We can delete the rest. + deleteRemainingChildren(returnFiber, oldFiber); + return resultingFirstChild; + } + + if (oldFiber === null) { + // If we don't have any more existing children we can choose a fast path + // since the rest will all be insertions. + for (; newIdx < newChildren.length; newIdx++) { + var _newFiber = createChild( + returnFiber, + newChildren[newIdx], + expirationTime + ); + if (_newFiber === null) { + continue; + } + lastPlacedIndex = placeChild(_newFiber, lastPlacedIndex, newIdx); + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = _newFiber; + } else { + previousNewFiber.sibling = _newFiber; + } + previousNewFiber = _newFiber; + } + return resultingFirstChild; + } + + // Add all children to a key map for quick lookups. + var existingChildren = mapRemainingChildren(returnFiber, oldFiber); + + // Keep scanning and use the map to restore deleted items as moves. + for (; newIdx < newChildren.length; newIdx++) { + var _newFiber2 = updateFromMap( + existingChildren, + returnFiber, + newIdx, + newChildren[newIdx], + expirationTime + ); + if (_newFiber2 !== null) { + if (shouldTrackSideEffects) { + if (_newFiber2.alternate !== null) { + // The new fiber is a work in progress, but if there exists a + // current, that means that we reused the fiber. We need to delete + // it from the child list so that we don't add it to the deletion + // list. + existingChildren.delete( + _newFiber2.key === null ? newIdx : _newFiber2.key + ); + } + } + lastPlacedIndex = placeChild(_newFiber2, lastPlacedIndex, newIdx); + if (previousNewFiber === null) { + resultingFirstChild = _newFiber2; + } else { + previousNewFiber.sibling = _newFiber2; + } + previousNewFiber = _newFiber2; + } + } + + if (shouldTrackSideEffects) { + // Any existing children that weren't consumed above were deleted. We need + // to add them to the deletion list. + existingChildren.forEach(function(child) { + return deleteChild(returnFiber, child); + }); + } + + return resultingFirstChild; + } + + function reconcileChildrenIterator( + returnFiber, + currentFirstChild, + newChildrenIterable, + expirationTime + ) { + // This is the same implementation as reconcileChildrenArray(), + // but using the iterator instead. + + var iteratorFn = getIteratorFn(newChildrenIterable); + (function() { + if (!(typeof iteratorFn === "function")) { + throw ReactError( + "An object is not an iterable. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + + { + // We don't support rendering Generators because it's a mutation. + // See https://github.com/facebook/react/issues/12995 + if ( + typeof Symbol === "function" && + // $FlowFixMe Flow doesn't know about toStringTag + newChildrenIterable[Symbol.toStringTag] === "Generator" + ) { + !didWarnAboutGenerators + ? warning$1( + false, + "Using Generators as children is unsupported and will likely yield " + + "unexpected results because enumerating a generator mutates it. " + + "You may convert it to an array with `Array.from()` or the " + + "`[...spread]` operator before rendering. Keep in mind " + + "you might need to polyfill these features for older browsers." + ) + : void 0; + didWarnAboutGenerators = true; + } + + // Warn about using Maps as children + if (newChildrenIterable.entries === iteratorFn) { + !didWarnAboutMaps + ? warning$1( + false, + "Using Maps as children is unsupported and will likely yield " + + "unexpected results. Convert it to a sequence/iterable of keyed " + + "ReactElements instead." + ) + : void 0; + didWarnAboutMaps = true; + } + + // First, validate keys. + // We'll get a different iterator later for the main pass. + var _newChildren = iteratorFn.call(newChildrenIterable); + if (_newChildren) { + var knownKeys = null; + var _step = _newChildren.next(); + for (; !_step.done; _step = _newChildren.next()) { + var child = _step.value; + knownKeys = warnOnInvalidKey(child, knownKeys); + } + } + } + + var newChildren = iteratorFn.call(newChildrenIterable); + (function() { + if (!(newChildren != null)) { + throw ReactError("An iterable object provided no iterator."); + } + })(); + + var resultingFirstChild = null; + var previousNewFiber = null; + + var oldFiber = currentFirstChild; + var lastPlacedIndex = 0; + var newIdx = 0; + var nextOldFiber = null; + + var step = newChildren.next(); + for ( + ; + oldFiber !== null && !step.done; + newIdx++, step = newChildren.next() + ) { + if (oldFiber.index > newIdx) { + nextOldFiber = oldFiber; + oldFiber = null; + } else { + nextOldFiber = oldFiber.sibling; + } + var newFiber = updateSlot( + returnFiber, + oldFiber, + step.value, + expirationTime + ); + if (newFiber === null) { + // TODO: This breaks on empty slots like null children. That's + // unfortunate because it triggers the slow path all the time. We need + // a better way to communicate whether this was a miss or null, + // boolean, undefined, etc. + if (oldFiber === null) { + oldFiber = nextOldFiber; + } + break; + } + if (shouldTrackSideEffects) { + if (oldFiber && newFiber.alternate === null) { + // We matched the slot, but we didn't reuse the existing fiber, so we + // need to delete the existing child. + deleteChild(returnFiber, oldFiber); + } + } + lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = newFiber; + } else { + // TODO: Defer siblings if we're not at the right index for this slot. + // I.e. if we had null values before, then we want to defer this + // for each null value. However, we also don't want to call updateSlot + // with the previous one. + previousNewFiber.sibling = newFiber; + } + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } + + if (step.done) { + // We've reached the end of the new children. We can delete the rest. + deleteRemainingChildren(returnFiber, oldFiber); + return resultingFirstChild; + } + + if (oldFiber === null) { + // If we don't have any more existing children we can choose a fast path + // since the rest will all be insertions. + for (; !step.done; newIdx++, step = newChildren.next()) { + var _newFiber3 = createChild(returnFiber, step.value, expirationTime); + if (_newFiber3 === null) { + continue; + } + lastPlacedIndex = placeChild(_newFiber3, lastPlacedIndex, newIdx); + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = _newFiber3; + } else { + previousNewFiber.sibling = _newFiber3; + } + previousNewFiber = _newFiber3; + } + return resultingFirstChild; + } + + // Add all children to a key map for quick lookups. + var existingChildren = mapRemainingChildren(returnFiber, oldFiber); + + // Keep scanning and use the map to restore deleted items as moves. + for (; !step.done; newIdx++, step = newChildren.next()) { + var _newFiber4 = updateFromMap( + existingChildren, + returnFiber, + newIdx, + step.value, + expirationTime + ); + if (_newFiber4 !== null) { + if (shouldTrackSideEffects) { + if (_newFiber4.alternate !== null) { + // The new fiber is a work in progress, but if there exists a + // current, that means that we reused the fiber. We need to delete + // it from the child list so that we don't add it to the deletion + // list. + existingChildren.delete( + _newFiber4.key === null ? newIdx : _newFiber4.key + ); + } + } + lastPlacedIndex = placeChild(_newFiber4, lastPlacedIndex, newIdx); + if (previousNewFiber === null) { + resultingFirstChild = _newFiber4; + } else { + previousNewFiber.sibling = _newFiber4; + } + previousNewFiber = _newFiber4; + } + } + + if (shouldTrackSideEffects) { + // Any existing children that weren't consumed above were deleted. We need + // to add them to the deletion list. + existingChildren.forEach(function(child) { + return deleteChild(returnFiber, child); + }); + } + + return resultingFirstChild; + } + + function reconcileSingleTextNode( + returnFiber, + currentFirstChild, + textContent, + expirationTime + ) { + // There's no need to check for keys on text nodes since we don't have a + // way to define them. + if (currentFirstChild !== null && currentFirstChild.tag === HostText) { + // We already have an existing node so let's just update it and delete + // the rest. + deleteRemainingChildren(returnFiber, currentFirstChild.sibling); + var existing = useFiber(currentFirstChild, textContent, expirationTime); + existing.return = returnFiber; + return existing; + } + // The existing first child is not a text node so we need to create one + // and delete the existing ones. + deleteRemainingChildren(returnFiber, currentFirstChild); + var created = createFiberFromText( + textContent, + returnFiber.mode, + expirationTime + ); + created.return = returnFiber; + return created; + } + + function reconcileSingleElement( + returnFiber, + currentFirstChild, + element, + expirationTime + ) { + var key = element.key; + var child = currentFirstChild; + while (child !== null) { + // TODO: If key === null and child.key === null, then this only applies to + // the first item in the list. + if (child.key === key) { + if ( + child.tag === Fragment + ? element.type === REACT_FRAGMENT_TYPE + : child.elementType === element.type + ) { + deleteRemainingChildren(returnFiber, child.sibling); + var existing = useFiber( + child, + element.type === REACT_FRAGMENT_TYPE + ? element.props.children + : element.props, + expirationTime + ); + existing.ref = coerceRef(returnFiber, child, element); + existing.return = returnFiber; + { + existing._debugSource = element._source; + existing._debugOwner = element._owner; + } + return existing; + } else { + deleteRemainingChildren(returnFiber, child); + break; + } + } else { + deleteChild(returnFiber, child); + } + child = child.sibling; + } + + if (element.type === REACT_FRAGMENT_TYPE) { + var created = createFiberFromFragment( + element.props.children, + returnFiber.mode, + expirationTime, + element.key + ); + created.return = returnFiber; + return created; + } else { + var _created4 = createFiberFromElement( + element, + returnFiber.mode, + expirationTime + ); + _created4.ref = coerceRef(returnFiber, currentFirstChild, element); + _created4.return = returnFiber; + return _created4; + } + } + + function reconcileSinglePortal( + returnFiber, + currentFirstChild, + portal, + expirationTime + ) { + var key = portal.key; + var child = currentFirstChild; + while (child !== null) { + // TODO: If key === null and child.key === null, then this only applies to + // the first item in the list. + if (child.key === key) { + if ( + child.tag === HostPortal && + child.stateNode.containerInfo === portal.containerInfo && + child.stateNode.implementation === portal.implementation + ) { + deleteRemainingChildren(returnFiber, child.sibling); + var existing = useFiber(child, portal.children || [], expirationTime); + existing.return = returnFiber; + return existing; + } else { + deleteRemainingChildren(returnFiber, child); + break; + } + } else { + deleteChild(returnFiber, child); + } + child = child.sibling; + } + + var created = createFiberFromPortal( + portal, + returnFiber.mode, + expirationTime + ); + created.return = returnFiber; + return created; + } + + // This API will tag the children with the side-effect of the reconciliation + // itself. They will be added to the side-effect list as we pass through the + // children and the parent. + function reconcileChildFibers( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ) { + // This function is not recursive. + // If the top level item is an array, we treat it as a set of children, + // not as a fragment. Nested arrays on the other hand will be treated as + // fragment nodes. Recursion happens at the normal flow. + + // Handle top level unkeyed fragments as if they were arrays. + // This leads to an ambiguity between <>{[...]} and <>.... + // We treat the ambiguous cases above the same. + var isUnkeyedTopLevelFragment = + typeof newChild === "object" && + newChild !== null && + newChild.type === REACT_FRAGMENT_TYPE && + newChild.key === null; + if (isUnkeyedTopLevelFragment) { + newChild = newChild.props.children; + } + + // Handle object types + var isObject = typeof newChild === "object" && newChild !== null; + + if (isObject) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return placeSingleChild( + reconcileSingleElement( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ) + ); + case REACT_PORTAL_TYPE: + return placeSingleChild( + reconcileSinglePortal( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ) + ); + } + } + + if (typeof newChild === "string" || typeof newChild === "number") { + return placeSingleChild( + reconcileSingleTextNode( + returnFiber, + currentFirstChild, + "" + newChild, + expirationTime + ) + ); + } + + if (isArray(newChild)) { + return reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ); + } + + if (getIteratorFn(newChild)) { + return reconcileChildrenIterator( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ); + } + + if (isObject) { + throwOnInvalidObjectType(returnFiber, newChild); + } + + { + if (typeof newChild === "function") { + warnOnFunctionType(); + } + } + if (typeof newChild === "undefined" && !isUnkeyedTopLevelFragment) { + // If the new child is undefined, and the return fiber is a composite + // component, throw an error. If Fiber return types are disabled, + // we already threw above. + switch (returnFiber.tag) { + case ClassComponent: { + { + var instance = returnFiber.stateNode; + if (instance.render._isMockFunction) { + // We allow auto-mocks to proceed as if they're returning null. + break; + } + } + } + // Intentionally fall through to the next case, which handles both + // functions and classes + // eslint-disable-next-lined no-fallthrough + case FunctionComponent: { + var Component = returnFiber.type; + (function() { + { + throw ReactError( + (Component.displayName || Component.name || "Component") + + "(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null." + ); + } + })(); + } + } + } + + // Remaining cases are all treated as empty. + return deleteRemainingChildren(returnFiber, currentFirstChild); + } + + return reconcileChildFibers; +} + +var reconcileChildFibers = ChildReconciler(true); +var mountChildFibers = ChildReconciler(false); + +function cloneChildFibers(current$$1, workInProgress) { + (function() { + if (!(current$$1 === null || workInProgress.child === current$$1.child)) { + throw ReactError("Resuming work not yet implemented."); + } + })(); + + if (workInProgress.child === null) { + return; + } + + var currentChild = workInProgress.child; + var newChild = createWorkInProgress( + currentChild, + currentChild.pendingProps, + currentChild.expirationTime + ); + workInProgress.child = newChild; + + newChild.return = workInProgress; + while (currentChild.sibling !== null) { + currentChild = currentChild.sibling; + newChild = newChild.sibling = createWorkInProgress( + currentChild, + currentChild.pendingProps, + currentChild.expirationTime + ); + newChild.return = workInProgress; + } + newChild.sibling = null; +} + +var NO_CONTEXT = {}; + +var contextStackCursor$1 = createCursor(NO_CONTEXT); +var contextFiberStackCursor = createCursor(NO_CONTEXT); +var rootInstanceStackCursor = createCursor(NO_CONTEXT); + +function requiredContext(c) { + (function() { + if (!(c !== NO_CONTEXT)) { + throw ReactError( + "Expected host context to exist. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + return c; +} + +function getRootHostContainer() { + var rootInstance = requiredContext(rootInstanceStackCursor.current); + return rootInstance; +} + +function pushHostContainer(fiber, nextRootInstance) { + // Push current root instance onto the stack; + // This allows us to reset root when portals are popped. + push(rootInstanceStackCursor, nextRootInstance, fiber); + // Track the context and the Fiber that provided it. + // This enables us to pop only Fibers that provide unique contexts. + push(contextFiberStackCursor, fiber, fiber); + + // Finally, we need to push the host context to the stack. + // However, we can't just call getRootHostContext() and push it because + // we'd have a different number of entries on the stack depending on + // whether getRootHostContext() throws somewhere in renderer code or not. + // So we push an empty value first. This lets us safely unwind on errors. + push(contextStackCursor$1, NO_CONTEXT, fiber); + var nextRootContext = getRootHostContext(nextRootInstance); + // Now that we know this function doesn't throw, replace it. + pop(contextStackCursor$1, fiber); + push(contextStackCursor$1, nextRootContext, fiber); +} + +function popHostContainer(fiber) { + pop(contextStackCursor$1, fiber); + pop(contextFiberStackCursor, fiber); + pop(rootInstanceStackCursor, fiber); +} + +function getHostContext() { + var context = requiredContext(contextStackCursor$1.current); + return context; +} + +function pushHostContext(fiber) { + var rootInstance = requiredContext(rootInstanceStackCursor.current); + var context = requiredContext(contextStackCursor$1.current); + var nextContext = getChildHostContext(context, fiber.type, rootInstance); + + // Don't push this Fiber's context unless it's unique. + if (context === nextContext) { + return; + } + + // Track the context and the Fiber that provided it. + // This enables us to pop only Fibers that provide unique contexts. + push(contextFiberStackCursor, fiber, fiber); + push(contextStackCursor$1, nextContext, fiber); +} + +function pushHostContextForEventComponent(fiber) { + var context = requiredContext(contextStackCursor$1.current); + var nextContext = getChildHostContextForEventComponent(context); + + // Don't push this Fiber's context unless it's unique. + if (context === nextContext) { + return; + } + + // Track the context and the Fiber that provided it. + // This enables us to pop only Fibers that provide unique contexts. + push(contextFiberStackCursor, fiber, fiber); + push(contextStackCursor$1, nextContext, fiber); +} + +function pushHostContextForEventTarget(fiber) { + var context = requiredContext(contextStackCursor$1.current); + var eventTargetType = fiber.type.type; + var nextContext = getChildHostContextForEventTarget(context, eventTargetType); + + // Don't push this Fiber's context unless it's unique. + if (context === nextContext) { + return; + } + + // Track the context and the Fiber that provided it. + // This enables us to pop only Fibers that provide unique contexts. + push(contextFiberStackCursor, fiber, fiber); + push(contextStackCursor$1, nextContext, fiber); +} + +function popHostContext(fiber) { + // Do not pop unless this Fiber provided the current context. + // pushHostContext() only pushes Fibers that provide unique contexts. + if (contextFiberStackCursor.current !== fiber) { + return; + } + + pop(contextStackCursor$1, fiber); + pop(contextFiberStackCursor, fiber); +} + +var NoEffect$1 = /* */ 0; +var UnmountSnapshot = /* */ 2; +var UnmountMutation = /* */ 4; +var MountMutation = /* */ 8; +var UnmountLayout = /* */ 16; +var MountLayout = /* */ 32; +var MountPassive = /* */ 64; +var UnmountPassive = /* */ 128; + +var ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher; + +var didWarnAboutMismatchedHooksForComponent = void 0; +{ + didWarnAboutMismatchedHooksForComponent = new Set(); +} + +// These are set right before calling the component. +var renderExpirationTime$1 = NoWork; +// The work-in-progress fiber. I've named it differently to distinguish it from +// the work-in-progress hook. +var currentlyRenderingFiber$1 = null; + +// Hooks are stored as a linked list on the fiber's memoizedState field. The +// current hook list is the list that belongs to the current fiber. The +// work-in-progress hook list is a new list that will be added to the +// work-in-progress fiber. +var currentHook = null; +var nextCurrentHook = null; +var firstWorkInProgressHook = null; +var workInProgressHook = null; +var nextWorkInProgressHook = null; + +var remainingExpirationTime = NoWork; +var componentUpdateQueue = null; +var sideEffectTag = 0; + +// Updates scheduled during render will trigger an immediate re-render at the +// end of the current pass. We can't store these updates on the normal queue, +// because if the work is aborted, they should be discarded. Because this is +// a relatively rare case, we also don't want to add an additional field to +// either the hook or queue object types. So we store them in a lazily create +// map of queue -> render-phase updates, which are discarded once the component +// completes without re-rendering. + +// Whether an update was scheduled during the currently executing render pass. +var didScheduleRenderPhaseUpdate = false; +// Lazily created map of render-phase updates +var renderPhaseUpdates = null; +// Counter to prevent infinite loops. +var numberOfReRenders = 0; +var RE_RENDER_LIMIT = 25; + +// In DEV, this is the name of the currently executing primitive hook +var currentHookNameInDev = null; + +// In DEV, this list ensures that hooks are called in the same order between renders. +// The list stores the order of hooks used during the initial render (mount). +// Subsequent renders (updates) reference this list. +var hookTypesDev = null; +var hookTypesUpdateIndexDev = -1; + +function mountHookTypesDev() { + { + var hookName = currentHookNameInDev; + + if (hookTypesDev === null) { + hookTypesDev = [hookName]; + } else { + hookTypesDev.push(hookName); + } + } +} + +function updateHookTypesDev() { + { + var hookName = currentHookNameInDev; + + if (hookTypesDev !== null) { + hookTypesUpdateIndexDev++; + if (hookTypesDev[hookTypesUpdateIndexDev] !== hookName) { + warnOnHookMismatchInDev(hookName); + } + } + } +} + +function checkDepsAreArrayDev(deps) { + { + if (deps !== undefined && deps !== null && !Array.isArray(deps)) { + // Verify deps, but only on mount to avoid extra checks. + // It's unlikely their type would change as usually you define them inline. + warning$1( + false, + "%s received a final argument that is not an array (instead, received `%s`). When " + + "specified, the final argument must be an array.", + currentHookNameInDev, + typeof deps + ); + } + } +} + +function warnOnHookMismatchInDev(currentHookName) { + { + var componentName = getComponentName(currentlyRenderingFiber$1.type); + if (!didWarnAboutMismatchedHooksForComponent.has(componentName)) { + didWarnAboutMismatchedHooksForComponent.add(componentName); + + if (hookTypesDev !== null) { + var table = ""; + + var secondColumnStart = 30; + + for (var i = 0; i <= hookTypesUpdateIndexDev; i++) { + var oldHookName = hookTypesDev[i]; + var newHookName = + i === hookTypesUpdateIndexDev ? currentHookName : oldHookName; + + var row = i + 1 + ". " + oldHookName; + + // Extra space so second column lines up + // lol @ IE not supporting String#repeat + while (row.length < secondColumnStart) { + row += " "; + } + + row += newHookName + "\n"; + + table += row; + } + + warning$1( + false, + "React has detected a change in the order of Hooks called by %s. " + + "This will lead to bugs and errors if not fixed. " + + "For more information, read the Rules of Hooks: https://fb.me/rules-of-hooks\n\n" + + " Previous render Next render\n" + + " ------------------------------------------------------\n" + + "%s" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + componentName, + table + ); + } + } + } +} + +function throwInvalidHookError() { + (function() { + { + throw ReactError( + "Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:\n1. You might have mismatching versions of React and the renderer (such as React DOM)\n2. You might be breaking the Rules of Hooks\n3. You might have more than one copy of React in the same app\nSee https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem." + ); + } + })(); +} + +function areHookInputsEqual(nextDeps, prevDeps) { + if (prevDeps === null) { + { + warning$1( + false, + "%s received a final argument during this render, but not during " + + "the previous render. Even though the final argument is optional, " + + "its type cannot change between renders.", + currentHookNameInDev + ); + } + return false; + } + + { + // Don't bother comparing lengths in prod because these arrays should be + // passed inline. + if (nextDeps.length !== prevDeps.length) { + warning$1( + false, + "The final argument passed to %s changed size between renders. The " + + "order and size of this array must remain constant.\n\n" + + "Previous: %s\n" + + "Incoming: %s", + currentHookNameInDev, + "[" + prevDeps.join(", ") + "]", + "[" + nextDeps.join(", ") + "]" + ); + } + } + for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++) { + if (is(nextDeps[i], prevDeps[i])) { + continue; + } + return false; + } + return true; +} + +function renderWithHooks( + current, + workInProgress, + Component, + props, + refOrContext, + nextRenderExpirationTime +) { + renderExpirationTime$1 = nextRenderExpirationTime; + currentlyRenderingFiber$1 = workInProgress; + nextCurrentHook = current !== null ? current.memoizedState : null; + + { + hookTypesDev = current !== null ? current._debugHookTypes : null; + hookTypesUpdateIndexDev = -1; + } + + // The following should have already been reset + // currentHook = null; + // workInProgressHook = null; + + // remainingExpirationTime = NoWork; + // componentUpdateQueue = null; + + // didScheduleRenderPhaseUpdate = false; + // renderPhaseUpdates = null; + // numberOfReRenders = 0; + // sideEffectTag = 0; + + // TODO Warn if no hooks are used at all during mount, then some are used during update. + // Currently we will identify the update render as a mount because nextCurrentHook === null. + // This is tricky because it's valid for certain types of components (e.g. React.lazy) + + // Using nextCurrentHook to differentiate between mount/update only works if at least one stateful hook is used. + // Non-stateful hooks (e.g. context) don't get added to memoizedState, + // so nextCurrentHook would be null during updates and mounts. + { + if (nextCurrentHook !== null) { + ReactCurrentDispatcher$1.current = HooksDispatcherOnUpdateInDEV; + } else if (hookTypesDev !== null) { + // This dispatcher handles an edge case where a component is updating, + // but no stateful hooks have been used. + // We want to match the production code behavior (which will use HooksDispatcherOnMount), + // but with the extra DEV validation to ensure hooks ordering hasn't changed. + // This dispatcher does that. + ReactCurrentDispatcher$1.current = HooksDispatcherOnMountWithHookTypesInDEV; + } else { + ReactCurrentDispatcher$1.current = HooksDispatcherOnMountInDEV; + } + } + + var children = Component(props, refOrContext); + + if (didScheduleRenderPhaseUpdate) { + do { + didScheduleRenderPhaseUpdate = false; + numberOfReRenders += 1; + + // Start over from the beginning of the list + nextCurrentHook = current !== null ? current.memoizedState : null; + nextWorkInProgressHook = firstWorkInProgressHook; + + currentHook = null; + workInProgressHook = null; + componentUpdateQueue = null; + + { + // Also validate hook order for cascading updates. + hookTypesUpdateIndexDev = -1; + } + + ReactCurrentDispatcher$1.current = HooksDispatcherOnUpdateInDEV; + + children = Component(props, refOrContext); + } while (didScheduleRenderPhaseUpdate); + + renderPhaseUpdates = null; + numberOfReRenders = 0; + } + + // We can assume the previous dispatcher is always this one, since we set it + // at the beginning of the render phase and there's no re-entrancy. + ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; + + var renderedWork = currentlyRenderingFiber$1; + + renderedWork.memoizedState = firstWorkInProgressHook; + renderedWork.expirationTime = remainingExpirationTime; + renderedWork.updateQueue = componentUpdateQueue; + renderedWork.effectTag |= sideEffectTag; + + { + renderedWork._debugHookTypes = hookTypesDev; + } + + // This check uses currentHook so that it works the same in DEV and prod bundles. + // hookTypesDev could catch more cases (e.g. context) but only in DEV bundles. + var didRenderTooFewHooks = currentHook !== null && currentHook.next !== null; + + renderExpirationTime$1 = NoWork; + currentlyRenderingFiber$1 = null; + + currentHook = null; + nextCurrentHook = null; + firstWorkInProgressHook = null; + workInProgressHook = null; + nextWorkInProgressHook = null; + + { + currentHookNameInDev = null; + hookTypesDev = null; + hookTypesUpdateIndexDev = -1; + } + + remainingExpirationTime = NoWork; + componentUpdateQueue = null; + sideEffectTag = 0; + + // These were reset above + // didScheduleRenderPhaseUpdate = false; + // renderPhaseUpdates = null; + // numberOfReRenders = 0; + + (function() { + if (!!didRenderTooFewHooks) { + throw ReactError( + "Rendered fewer hooks than expected. This may be caused by an accidental early return statement." + ); + } + })(); + + return children; +} + +function bailoutHooks(current, workInProgress, expirationTime) { + workInProgress.updateQueue = current.updateQueue; + workInProgress.effectTag &= ~(Passive | Update); + if (current.expirationTime <= expirationTime) { + current.expirationTime = NoWork; + } +} + +function resetHooks() { + // We can assume the previous dispatcher is always this one, since we set it + // at the beginning of the render phase and there's no re-entrancy. + ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; + + // This is used to reset the state of this module when a component throws. + // It's also called inside mountIndeterminateComponent if we determine the + // component is a module-style component. + renderExpirationTime$1 = NoWork; + currentlyRenderingFiber$1 = null; + + currentHook = null; + nextCurrentHook = null; + firstWorkInProgressHook = null; + workInProgressHook = null; + nextWorkInProgressHook = null; + + { + hookTypesDev = null; + hookTypesUpdateIndexDev = -1; + + currentHookNameInDev = null; + } + + remainingExpirationTime = NoWork; + componentUpdateQueue = null; + sideEffectTag = 0; + + didScheduleRenderPhaseUpdate = false; + renderPhaseUpdates = null; + numberOfReRenders = 0; +} + +function mountWorkInProgressHook() { + var hook = { + memoizedState: null, + + baseState: null, + queue: null, + baseUpdate: null, + + next: null + }; + + if (workInProgressHook === null) { + // This is the first hook in the list + firstWorkInProgressHook = workInProgressHook = hook; + } else { + // Append to the end of the list + workInProgressHook = workInProgressHook.next = hook; + } + return workInProgressHook; +} + +function updateWorkInProgressHook() { + // This function is used both for updates and for re-renders triggered by a + // render phase update. It assumes there is either a current hook we can + // clone, or a work-in-progress hook from a previous render pass that we can + // use as a base. When we reach the end of the base list, we must switch to + // the dispatcher used for mounts. + if (nextWorkInProgressHook !== null) { + // There's already a work-in-progress. Reuse it. + workInProgressHook = nextWorkInProgressHook; + nextWorkInProgressHook = workInProgressHook.next; + + currentHook = nextCurrentHook; + nextCurrentHook = currentHook !== null ? currentHook.next : null; + } else { + // Clone from the current hook. + (function() { + if (!(nextCurrentHook !== null)) { + throw ReactError( + "Rendered more hooks than during the previous render." + ); + } + })(); + currentHook = nextCurrentHook; + + var newHook = { + memoizedState: currentHook.memoizedState, + + baseState: currentHook.baseState, + queue: currentHook.queue, + baseUpdate: currentHook.baseUpdate, + + next: null + }; + + if (workInProgressHook === null) { + // This is the first hook in the list. + workInProgressHook = firstWorkInProgressHook = newHook; + } else { + // Append to the end of the list. + workInProgressHook = workInProgressHook.next = newHook; + } + nextCurrentHook = currentHook.next; + } + return workInProgressHook; +} + +function createFunctionComponentUpdateQueue() { + return { + lastEffect: null + }; +} + +function basicStateReducer(state, action) { + return typeof action === "function" ? action(state) : action; +} + +function mountReducer(reducer, initialArg, init) { + var hook = mountWorkInProgressHook(); + var initialState = void 0; + if (init !== undefined) { + initialState = init(initialArg); + } else { + initialState = initialArg; + } + hook.memoizedState = hook.baseState = initialState; + var queue = (hook.queue = { + last: null, + dispatch: null, + lastRenderedReducer: reducer, + lastRenderedState: initialState + }); + var dispatch = (queue.dispatch = dispatchAction.bind( + null, + // Flow doesn't know this is non-null, but we do. + currentlyRenderingFiber$1, + queue + )); + return [hook.memoizedState, dispatch]; +} + +function updateReducer(reducer, initialArg, init) { + var hook = updateWorkInProgressHook(); + var queue = hook.queue; + (function() { + if (!(queue !== null)) { + throw ReactError( + "Should have a queue. This is likely a bug in React. Please file an issue." + ); + } + })(); + + queue.lastRenderedReducer = reducer; + + if (numberOfReRenders > 0) { + // This is a re-render. Apply the new render phase updates to the previous + var _dispatch = queue.dispatch; + if (renderPhaseUpdates !== null) { + // Render phase updates are stored in a map of queue -> linked list + var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue); + if (firstRenderPhaseUpdate !== undefined) { + renderPhaseUpdates.delete(queue); + var newState = hook.memoizedState; + var update = firstRenderPhaseUpdate; + do { + // Process this render phase update. We don't have to check the + // priority because it will always be the same as the current + // render's. + var _action = update.action; + newState = reducer(newState, _action); + update = update.next; + } while (update !== null); + + // Mark that the fiber performed work, but only if the new state is + // different from the current state. + if (!is(newState, hook.memoizedState)) { + markWorkInProgressReceivedUpdate(); + } + + hook.memoizedState = newState; + // Don't persist the state accumlated from the render phase updates to + // the base state unless the queue is empty. + // TODO: Not sure if this is the desired semantics, but it's what we + // do for gDSFP. I can't remember why. + if (hook.baseUpdate === queue.last) { + hook.baseState = newState; + } + + queue.lastRenderedState = newState; + + return [newState, _dispatch]; + } + } + return [hook.memoizedState, _dispatch]; + } + + // The last update in the entire queue + var last = queue.last; + // The last update that is part of the base state. + var baseUpdate = hook.baseUpdate; + var baseState = hook.baseState; + + // Find the first unprocessed update. + var first = void 0; + if (baseUpdate !== null) { + if (last !== null) { + // For the first update, the queue is a circular linked list where + // `queue.last.next = queue.first`. Once the first update commits, and + // the `baseUpdate` is no longer empty, we can unravel the list. + last.next = null; + } + first = baseUpdate.next; + } else { + first = last !== null ? last.next : null; + } + if (first !== null) { + var _newState = baseState; + var newBaseState = null; + var newBaseUpdate = null; + var prevUpdate = baseUpdate; + var _update = first; + var didSkip = false; + do { + var updateExpirationTime = _update.expirationTime; + if (updateExpirationTime < renderExpirationTime$1) { + // Priority is insufficient. Skip this update. If this is the first + // skipped update, the previous update/state is the new base + // update/state. + if (!didSkip) { + didSkip = true; + newBaseUpdate = prevUpdate; + newBaseState = _newState; + } + // Update the remaining priority in the queue. + if (updateExpirationTime > remainingExpirationTime) { + remainingExpirationTime = updateExpirationTime; + } + } else { + // This update does have sufficient priority. + + // Mark the event time of this update as relevant to this render pass. + // TODO: This should ideally use the true event time of this update rather than + // its priority which is a derived and not reverseable value. + // TODO: We should skip this update if it was already committed but currently + // we have no way of detecting the difference between a committed and suspended + // update here. + markRenderEventTime(updateExpirationTime); + + // Process this update. + if (_update.eagerReducer === reducer) { + // If this update was processed eagerly, and its reducer matches the + // current reducer, we can use the eagerly computed state. + _newState = _update.eagerState; + } else { + var _action2 = _update.action; + _newState = reducer(_newState, _action2); + } + } + prevUpdate = _update; + _update = _update.next; + } while (_update !== null && _update !== first); + + if (!didSkip) { + newBaseUpdate = prevUpdate; + newBaseState = _newState; + } + + // Mark that the fiber performed work, but only if the new state is + // different from the current state. + if (!is(_newState, hook.memoizedState)) { + markWorkInProgressReceivedUpdate(); + } + + hook.memoizedState = _newState; + hook.baseUpdate = newBaseUpdate; + hook.baseState = newBaseState; + + queue.lastRenderedState = _newState; + } + + var dispatch = queue.dispatch; + return [hook.memoizedState, dispatch]; +} + +function mountState(initialState) { + var hook = mountWorkInProgressHook(); + if (typeof initialState === "function") { + initialState = initialState(); + } + hook.memoizedState = hook.baseState = initialState; + var queue = (hook.queue = { + last: null, + dispatch: null, + lastRenderedReducer: basicStateReducer, + lastRenderedState: initialState + }); + var dispatch = (queue.dispatch = dispatchAction.bind( + null, + // Flow doesn't know this is non-null, but we do. + currentlyRenderingFiber$1, + queue + )); + return [hook.memoizedState, dispatch]; +} + +function updateState(initialState) { + return updateReducer(basicStateReducer, initialState); +} + +function pushEffect(tag, create, destroy, deps) { + var effect = { + tag: tag, + create: create, + destroy: destroy, + deps: deps, + // Circular + next: null + }; + if (componentUpdateQueue === null) { + componentUpdateQueue = createFunctionComponentUpdateQueue(); + componentUpdateQueue.lastEffect = effect.next = effect; + } else { + var _lastEffect = componentUpdateQueue.lastEffect; + if (_lastEffect === null) { + componentUpdateQueue.lastEffect = effect.next = effect; + } else { + var firstEffect = _lastEffect.next; + _lastEffect.next = effect; + effect.next = firstEffect; + componentUpdateQueue.lastEffect = effect; + } + } + return effect; +} + +function mountRef(initialValue) { + var hook = mountWorkInProgressHook(); + var ref = { current: initialValue }; + { + Object.seal(ref); + } + hook.memoizedState = ref; + return ref; +} + +function updateRef(initialValue) { + var hook = updateWorkInProgressHook(); + return hook.memoizedState; +} + +function mountEffectImpl(fiberEffectTag, hookEffectTag, create, deps) { + var hook = mountWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + sideEffectTag |= fiberEffectTag; + hook.memoizedState = pushEffect(hookEffectTag, create, undefined, nextDeps); +} + +function updateEffectImpl(fiberEffectTag, hookEffectTag, create, deps) { + var hook = updateWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + var destroy = undefined; + + if (currentHook !== null) { + var prevEffect = currentHook.memoizedState; + destroy = prevEffect.destroy; + if (nextDeps !== null) { + var prevDeps = prevEffect.deps; + if (areHookInputsEqual(nextDeps, prevDeps)) { + pushEffect(NoEffect$1, create, destroy, nextDeps); + return; + } + } + } + + sideEffectTag |= fiberEffectTag; + hook.memoizedState = pushEffect(hookEffectTag, create, destroy, nextDeps); +} + +function mountEffect(create, deps) { + return mountEffectImpl( + Update | Passive, + UnmountPassive | MountPassive, + create, + deps + ); +} + +function updateEffect(create, deps) { + return updateEffectImpl( + Update | Passive, + UnmountPassive | MountPassive, + create, + deps + ); +} + +function mountLayoutEffect(create, deps) { + return mountEffectImpl(Update, UnmountMutation | MountLayout, create, deps); +} + +function updateLayoutEffect(create, deps) { + return updateEffectImpl(Update, UnmountMutation | MountLayout, create, deps); +} + +function imperativeHandleEffect(create, ref) { + if (typeof ref === "function") { + var refCallback = ref; + var _inst = create(); + refCallback(_inst); + return function() { + refCallback(null); + }; + } else if (ref !== null && ref !== undefined) { + var refObject = ref; + { + !refObject.hasOwnProperty("current") + ? warning$1( + false, + "Expected useImperativeHandle() first argument to either be a " + + "ref callback or React.createRef() object. Instead received: %s.", + "an object with keys {" + Object.keys(refObject).join(", ") + "}" + ) + : void 0; + } + var _inst2 = create(); + refObject.current = _inst2; + return function() { + refObject.current = null; + }; + } +} + +function mountImperativeHandle(ref, create, deps) { + { + !(typeof create === "function") + ? warning$1( + false, + "Expected useImperativeHandle() second argument to be a function " + + "that creates a handle. Instead received: %s.", + create !== null ? typeof create : "null" + ) + : void 0; + } + + // TODO: If deps are provided, should we skip comparing the ref itself? + var effectDeps = + deps !== null && deps !== undefined ? deps.concat([ref]) : null; + + return mountEffectImpl( + Update, + UnmountMutation | MountLayout, + imperativeHandleEffect.bind(null, create, ref), + effectDeps + ); +} + +function updateImperativeHandle(ref, create, deps) { + { + !(typeof create === "function") + ? warning$1( + false, + "Expected useImperativeHandle() second argument to be a function " + + "that creates a handle. Instead received: %s.", + create !== null ? typeof create : "null" + ) + : void 0; + } + + // TODO: If deps are provided, should we skip comparing the ref itself? + var effectDeps = + deps !== null && deps !== undefined ? deps.concat([ref]) : null; + + return updateEffectImpl( + Update, + UnmountMutation | MountLayout, + imperativeHandleEffect.bind(null, create, ref), + effectDeps + ); +} + +function mountDebugValue(value, formatterFn) { + // This hook is normally a no-op. + // The react-debug-hooks package injects its own implementation + // so that e.g. DevTools can display custom hook values. +} + +var updateDebugValue = mountDebugValue; + +function mountCallback(callback, deps) { + var hook = mountWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + hook.memoizedState = [callback, nextDeps]; + return callback; +} + +function updateCallback(callback, deps) { + var hook = updateWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + var prevState = hook.memoizedState; + if (prevState !== null) { + if (nextDeps !== null) { + var prevDeps = prevState[1]; + if (areHookInputsEqual(nextDeps, prevDeps)) { + return prevState[0]; + } + } + } + hook.memoizedState = [callback, nextDeps]; + return callback; +} + +function mountMemo(nextCreate, deps) { + var hook = mountWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + var nextValue = nextCreate(); + hook.memoizedState = [nextValue, nextDeps]; + return nextValue; +} + +function updateMemo(nextCreate, deps) { + var hook = updateWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + var prevState = hook.memoizedState; + if (prevState !== null) { + // Assume these are defined. If they're not, areHookInputsEqual will warn. + if (nextDeps !== null) { + var prevDeps = prevState[1]; + if (areHookInputsEqual(nextDeps, prevDeps)) { + return prevState[0]; + } + } + } + var nextValue = nextCreate(); + hook.memoizedState = [nextValue, nextDeps]; + return nextValue; +} + +function dispatchAction(fiber, queue, action) { + (function() { + if (!(numberOfReRenders < RE_RENDER_LIMIT)) { + throw ReactError( + "Too many re-renders. React limits the number of renders to prevent an infinite loop." + ); + } + })(); + + { + !(arguments.length <= 3) + ? warning$1( + false, + "State updates from the useState() and useReducer() Hooks don't support the " + + "second callback argument. To execute a side effect after " + + "rendering, declare it in the component body with useEffect()." + ) + : void 0; + } + + var alternate = fiber.alternate; + if ( + fiber === currentlyRenderingFiber$1 || + (alternate !== null && alternate === currentlyRenderingFiber$1) + ) { + // This is a render phase update. Stash it in a lazily-created map of + // queue -> linked list of updates. After this render pass, we'll restart + // and apply the stashed updates on top of the work-in-progress hook. + didScheduleRenderPhaseUpdate = true; + var update = { + expirationTime: renderExpirationTime$1, + action: action, + eagerReducer: null, + eagerState: null, + next: null + }; + if (renderPhaseUpdates === null) { + renderPhaseUpdates = new Map(); + } + var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue); + if (firstRenderPhaseUpdate === undefined) { + renderPhaseUpdates.set(queue, update); + } else { + // Append the update to the end of the list. + var lastRenderPhaseUpdate = firstRenderPhaseUpdate; + while (lastRenderPhaseUpdate.next !== null) { + lastRenderPhaseUpdate = lastRenderPhaseUpdate.next; + } + lastRenderPhaseUpdate.next = update; + } + } else { + flushPassiveEffects(); + + var currentTime = requestCurrentTime(); + var _expirationTime = computeExpirationForFiber(currentTime, fiber); + + var _update2 = { + expirationTime: _expirationTime, + action: action, + eagerReducer: null, + eagerState: null, + next: null + }; + + // Append the update to the end of the list. + var _last = queue.last; + if (_last === null) { + // This is the first update. Create a circular list. + _update2.next = _update2; + } else { + var first = _last.next; + if (first !== null) { + // Still circular. + _update2.next = first; + } + _last.next = _update2; + } + queue.last = _update2; + + if ( + fiber.expirationTime === NoWork && + (alternate === null || alternate.expirationTime === NoWork) + ) { + // The queue is currently empty, which means we can eagerly compute the + // next state before entering the render phase. If the new state is the + // same as the current state, we may be able to bail out entirely. + var _lastRenderedReducer = queue.lastRenderedReducer; + if (_lastRenderedReducer !== null) { + var prevDispatcher = void 0; + { + prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV; + } + try { + var currentState = queue.lastRenderedState; + var _eagerState = _lastRenderedReducer(currentState, action); + // Stash the eagerly computed state, and the reducer used to compute + // it, on the update object. If the reducer hasn't changed by the + // time we enter the render phase, then the eager state can be used + // without calling the reducer again. + _update2.eagerReducer = _lastRenderedReducer; + _update2.eagerState = _eagerState; + if (is(_eagerState, currentState)) { + // Fast path. We can bail out without scheduling React to re-render. + // It's still possible that we'll need to rebase this update later, + // if the component re-renders for a different reason and by that + // time the reducer has changed. + return; + } + } catch (error) { + // Suppress the error. It will throw again in the render phase. + } finally { + { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + } + } + } + { + // jest isn't a 'global', it's just exposed to tests via a wrapped function + // further, this isn't a test file, so flow doesn't recognize the symbol. So... + // $FlowExpectedError - because requirements don't give a damn about your type sigs. + if ("undefined" !== typeof jest) { + warnIfNotCurrentlyActingUpdatesInDev(fiber); + } + } + scheduleWork(fiber, _expirationTime); + } +} + +var ContextOnlyDispatcher = { + readContext: readContext, + + useCallback: throwInvalidHookError, + useContext: throwInvalidHookError, + useEffect: throwInvalidHookError, + useImperativeHandle: throwInvalidHookError, + useLayoutEffect: throwInvalidHookError, + useMemo: throwInvalidHookError, + useReducer: throwInvalidHookError, + useRef: throwInvalidHookError, + useState: throwInvalidHookError, + useDebugValue: throwInvalidHookError +}; + +var HooksDispatcherOnMountInDEV = null; +var HooksDispatcherOnMountWithHookTypesInDEV = null; +var HooksDispatcherOnUpdateInDEV = null; +var InvalidNestedHooksDispatcherOnMountInDEV = null; +var InvalidNestedHooksDispatcherOnUpdateInDEV = null; + +{ + var warnInvalidContextAccess = function() { + warning$1( + false, + "Context can only be read while React is rendering. " + + "In classes, you can read it in the render method or getDerivedStateFromProps. " + + "In function components, you can read it directly in the function body, but not " + + "inside Hooks like useReducer() or useMemo()." + ); + }; + + var warnInvalidHookAccess = function() { + warning$1( + false, + "Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. " + + "You can only call Hooks at the top level of your React function. " + + "For more information, see " + + "https://fb.me/rules-of-hooks" + ); + }; + + HooksDispatcherOnMountInDEV = { + readContext: function(context, observedBits) { + return readContext(context, observedBits); + }, + useCallback: function(callback, deps) { + currentHookNameInDev = "useCallback"; + mountHookTypesDev(); + checkDepsAreArrayDev(deps); + return mountCallback(callback, deps); + }, + useContext: function(context, observedBits) { + currentHookNameInDev = "useContext"; + mountHookTypesDev(); + return readContext(context, observedBits); + }, + useEffect: function(create, deps) { + currentHookNameInDev = "useEffect"; + mountHookTypesDev(); + checkDepsAreArrayDev(deps); + return mountEffect(create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + currentHookNameInDev = "useImperativeHandle"; + mountHookTypesDev(); + checkDepsAreArrayDev(deps); + return mountImperativeHandle(ref, create, deps); + }, + useLayoutEffect: function(create, deps) { + currentHookNameInDev = "useLayoutEffect"; + mountHookTypesDev(); + checkDepsAreArrayDev(deps); + return mountLayoutEffect(create, deps); + }, + useMemo: function(create, deps) { + currentHookNameInDev = "useMemo"; + mountHookTypesDev(); + checkDepsAreArrayDev(deps); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountMemo(create, deps); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useReducer: function(reducer, initialArg, init) { + currentHookNameInDev = "useReducer"; + mountHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountReducer(reducer, initialArg, init); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useRef: function(initialValue) { + currentHookNameInDev = "useRef"; + mountHookTypesDev(); + return mountRef(initialValue); + }, + useState: function(initialState) { + currentHookNameInDev = "useState"; + mountHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountState(initialState); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useDebugValue: function(value, formatterFn) { + currentHookNameInDev = "useDebugValue"; + mountHookTypesDev(); + return mountDebugValue(value, formatterFn); + } + }; + + HooksDispatcherOnMountWithHookTypesInDEV = { + readContext: function(context, observedBits) { + return readContext(context, observedBits); + }, + useCallback: function(callback, deps) { + currentHookNameInDev = "useCallback"; + updateHookTypesDev(); + return mountCallback(callback, deps); + }, + useContext: function(context, observedBits) { + currentHookNameInDev = "useContext"; + updateHookTypesDev(); + return readContext(context, observedBits); + }, + useEffect: function(create, deps) { + currentHookNameInDev = "useEffect"; + updateHookTypesDev(); + return mountEffect(create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + currentHookNameInDev = "useImperativeHandle"; + updateHookTypesDev(); + return mountImperativeHandle(ref, create, deps); + }, + useLayoutEffect: function(create, deps) { + currentHookNameInDev = "useLayoutEffect"; + updateHookTypesDev(); + return mountLayoutEffect(create, deps); + }, + useMemo: function(create, deps) { + currentHookNameInDev = "useMemo"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountMemo(create, deps); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useReducer: function(reducer, initialArg, init) { + currentHookNameInDev = "useReducer"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountReducer(reducer, initialArg, init); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useRef: function(initialValue) { + currentHookNameInDev = "useRef"; + updateHookTypesDev(); + return mountRef(initialValue); + }, + useState: function(initialState) { + currentHookNameInDev = "useState"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountState(initialState); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useDebugValue: function(value, formatterFn) { + currentHookNameInDev = "useDebugValue"; + updateHookTypesDev(); + return mountDebugValue(value, formatterFn); + } + }; + + HooksDispatcherOnUpdateInDEV = { + readContext: function(context, observedBits) { + return readContext(context, observedBits); + }, + useCallback: function(callback, deps) { + currentHookNameInDev = "useCallback"; + updateHookTypesDev(); + return updateCallback(callback, deps); + }, + useContext: function(context, observedBits) { + currentHookNameInDev = "useContext"; + updateHookTypesDev(); + return readContext(context, observedBits); + }, + useEffect: function(create, deps) { + currentHookNameInDev = "useEffect"; + updateHookTypesDev(); + return updateEffect(create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + currentHookNameInDev = "useImperativeHandle"; + updateHookTypesDev(); + return updateImperativeHandle(ref, create, deps); + }, + useLayoutEffect: function(create, deps) { + currentHookNameInDev = "useLayoutEffect"; + updateHookTypesDev(); + return updateLayoutEffect(create, deps); + }, + useMemo: function(create, deps) { + currentHookNameInDev = "useMemo"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV; + try { + return updateMemo(create, deps); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useReducer: function(reducer, initialArg, init) { + currentHookNameInDev = "useReducer"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV; + try { + return updateReducer(reducer, initialArg, init); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useRef: function(initialValue) { + currentHookNameInDev = "useRef"; + updateHookTypesDev(); + return updateRef(initialValue); + }, + useState: function(initialState) { + currentHookNameInDev = "useState"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV; + try { + return updateState(initialState); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useDebugValue: function(value, formatterFn) { + currentHookNameInDev = "useDebugValue"; + updateHookTypesDev(); + return updateDebugValue(value, formatterFn); + } + }; + + InvalidNestedHooksDispatcherOnMountInDEV = { + readContext: function(context, observedBits) { + warnInvalidContextAccess(); + return readContext(context, observedBits); + }, + useCallback: function(callback, deps) { + currentHookNameInDev = "useCallback"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountCallback(callback, deps); + }, + useContext: function(context, observedBits) { + currentHookNameInDev = "useContext"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return readContext(context, observedBits); + }, + useEffect: function(create, deps) { + currentHookNameInDev = "useEffect"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountEffect(create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + currentHookNameInDev = "useImperativeHandle"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountImperativeHandle(ref, create, deps); + }, + useLayoutEffect: function(create, deps) { + currentHookNameInDev = "useLayoutEffect"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountLayoutEffect(create, deps); + }, + useMemo: function(create, deps) { + currentHookNameInDev = "useMemo"; + warnInvalidHookAccess(); + mountHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountMemo(create, deps); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useReducer: function(reducer, initialArg, init) { + currentHookNameInDev = "useReducer"; + warnInvalidHookAccess(); + mountHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountReducer(reducer, initialArg, init); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useRef: function(initialValue) { + currentHookNameInDev = "useRef"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountRef(initialValue); + }, + useState: function(initialState) { + currentHookNameInDev = "useState"; + warnInvalidHookAccess(); + mountHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV; + try { + return mountState(initialState); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useDebugValue: function(value, formatterFn) { + currentHookNameInDev = "useDebugValue"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountDebugValue(value, formatterFn); + } + }; + + InvalidNestedHooksDispatcherOnUpdateInDEV = { + readContext: function(context, observedBits) { + warnInvalidContextAccess(); + return readContext(context, observedBits); + }, + useCallback: function(callback, deps) { + currentHookNameInDev = "useCallback"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateCallback(callback, deps); + }, + useContext: function(context, observedBits) { + currentHookNameInDev = "useContext"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return readContext(context, observedBits); + }, + useEffect: function(create, deps) { + currentHookNameInDev = "useEffect"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateEffect(create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + currentHookNameInDev = "useImperativeHandle"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateImperativeHandle(ref, create, deps); + }, + useLayoutEffect: function(create, deps) { + currentHookNameInDev = "useLayoutEffect"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateLayoutEffect(create, deps); + }, + useMemo: function(create, deps) { + currentHookNameInDev = "useMemo"; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV; + try { + return updateMemo(create, deps); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useReducer: function(reducer, initialArg, init) { + currentHookNameInDev = "useReducer"; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV; + try { + return updateReducer(reducer, initialArg, init); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useRef: function(initialValue) { + currentHookNameInDev = "useRef"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateRef(initialValue); + }, + useState: function(initialState) { + currentHookNameInDev = "useState"; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV; + try { + return updateState(initialState); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useDebugValue: function(value, formatterFn) { + currentHookNameInDev = "useDebugValue"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateDebugValue(value, formatterFn); + } + }; +} + +// Intentionally not named imports because Rollup would use dynamic dispatch for +// CommonJS interop named imports. +var now$1 = Scheduler.unstable_now; + +var commitTime = 0; +var profilerStartTime = -1; + +function getCommitTime() { + return commitTime; +} + +function recordCommitTime() { + if (!enableProfilerTimer) { + return; + } + commitTime = now$1(); +} + +function startProfilerTimer(fiber) { + if (!enableProfilerTimer) { + return; + } + + profilerStartTime = now$1(); + + if (fiber.actualStartTime < 0) { + fiber.actualStartTime = now$1(); + } +} + +function stopProfilerTimerIfRunning(fiber) { + if (!enableProfilerTimer) { + return; + } + profilerStartTime = -1; +} + +function stopProfilerTimerIfRunningAndRecordDelta(fiber, overrideBaseTime) { + if (!enableProfilerTimer) { + return; + } + + if (profilerStartTime >= 0) { + var elapsedTime = now$1() - profilerStartTime; + fiber.actualDuration += elapsedTime; + if (overrideBaseTime) { + fiber.selfBaseDuration = elapsedTime; + } + profilerStartTime = -1; + } +} + +// The deepest Fiber on the stack involved in a hydration context. +// This may have been an insertion or a hydration. +var hydrationParentFiber = null; +var nextHydratableInstance = null; +var isHydrating = false; + +function enterHydrationState(fiber) { + if (!supportsHydration) { + return false; + } + + var parentInstance = fiber.stateNode.containerInfo; + nextHydratableInstance = getFirstHydratableChild(parentInstance); + hydrationParentFiber = fiber; + isHydrating = true; + return true; +} + +function reenterHydrationStateFromDehydratedSuspenseInstance(fiber) { + if (!supportsHydration) { + return false; + } + + var suspenseInstance = fiber.stateNode; + nextHydratableInstance = getNextHydratableSibling(suspenseInstance); + popToNextHostParent(fiber); + isHydrating = true; + return true; +} + +function deleteHydratableInstance(returnFiber, instance) { + { + switch (returnFiber.tag) { + case HostRoot: + didNotHydrateContainerInstance( + returnFiber.stateNode.containerInfo, + instance + ); + break; + case HostComponent: + didNotHydrateInstance( + returnFiber.type, + returnFiber.memoizedProps, + returnFiber.stateNode, + instance + ); + break; + } + } + + var childToDelete = createFiberFromHostInstanceForDeletion(); + childToDelete.stateNode = instance; + childToDelete.return = returnFiber; + childToDelete.effectTag = Deletion; + + // This might seem like it belongs on progressedFirstDeletion. However, + // these children are not part of the reconciliation list of children. + // Even if we abort and rereconcile the children, that will try to hydrate + // again and the nodes are still in the host tree so these will be + // recreated. + if (returnFiber.lastEffect !== null) { + returnFiber.lastEffect.nextEffect = childToDelete; + returnFiber.lastEffect = childToDelete; + } else { + returnFiber.firstEffect = returnFiber.lastEffect = childToDelete; + } +} + +function insertNonHydratedInstance(returnFiber, fiber) { + fiber.effectTag |= Placement; + { + switch (returnFiber.tag) { + case HostRoot: { + var parentContainer = returnFiber.stateNode.containerInfo; + switch (fiber.tag) { + case HostComponent: + var type = fiber.type; + var props = fiber.pendingProps; + didNotFindHydratableContainerInstance(parentContainer, type, props); + break; + case HostText: + var text = fiber.pendingProps; + didNotFindHydratableContainerTextInstance(parentContainer, text); + break; + case SuspenseComponent: + didNotFindHydratableContainerSuspenseInstance(parentContainer); + break; + } + break; + } + case HostComponent: { + var parentType = returnFiber.type; + var parentProps = returnFiber.memoizedProps; + var parentInstance = returnFiber.stateNode; + switch (fiber.tag) { + case HostComponent: + var _type = fiber.type; + var _props = fiber.pendingProps; + didNotFindHydratableInstance( + parentType, + parentProps, + parentInstance, + _type, + _props + ); + break; + case HostText: + var _text = fiber.pendingProps; + didNotFindHydratableTextInstance( + parentType, + parentProps, + parentInstance, + _text + ); + break; + case SuspenseComponent: + didNotFindHydratableSuspenseInstance( + parentType, + parentProps, + parentInstance + ); + break; + } + break; + } + default: + return; + } + } +} + +function tryHydrate(fiber, nextInstance) { + switch (fiber.tag) { + case HostComponent: { + var type = fiber.type; + var props = fiber.pendingProps; + var instance = canHydrateInstance(nextInstance, type, props); + if (instance !== null) { + fiber.stateNode = instance; + return true; + } + return false; + } + case HostText: { + var text = fiber.pendingProps; + var textInstance = canHydrateTextInstance(nextInstance, text); + if (textInstance !== null) { + fiber.stateNode = textInstance; + return true; + } + return false; + } + case SuspenseComponent: { + if (enableSuspenseServerRenderer) { + var suspenseInstance = canHydrateSuspenseInstance(nextInstance); + if (suspenseInstance !== null) { + // Downgrade the tag to a dehydrated component until we've hydrated it. + fiber.tag = DehydratedSuspenseComponent; + fiber.stateNode = suspenseInstance; + return true; + } + } + return false; + } + default: + return false; + } +} + +function tryToClaimNextHydratableInstance(fiber) { + if (!isHydrating) { + return; + } + var nextInstance = nextHydratableInstance; + if (!nextInstance) { + // Nothing to hydrate. Make it an insertion. + insertNonHydratedInstance(hydrationParentFiber, fiber); + isHydrating = false; + hydrationParentFiber = fiber; + return; + } + var firstAttemptedInstance = nextInstance; + if (!tryHydrate(fiber, nextInstance)) { + // If we can't hydrate this instance let's try the next one. + // We use this as a heuristic. It's based on intuition and not data so it + // might be flawed or unnecessary. + nextInstance = getNextHydratableSibling(firstAttemptedInstance); + if (!nextInstance || !tryHydrate(fiber, nextInstance)) { + // Nothing to hydrate. Make it an insertion. + insertNonHydratedInstance(hydrationParentFiber, fiber); + isHydrating = false; + hydrationParentFiber = fiber; + return; + } + // We matched the next one, we'll now assume that the first one was + // superfluous and we'll delete it. Since we can't eagerly delete it + // we'll have to schedule a deletion. To do that, this node needs a dummy + // fiber associated with it. + deleteHydratableInstance(hydrationParentFiber, firstAttemptedInstance); + } + hydrationParentFiber = fiber; + nextHydratableInstance = getFirstHydratableChild(nextInstance); +} + +function prepareToHydrateHostInstance( + fiber, + rootContainerInstance, + hostContext +) { + if (!supportsHydration) { + (function() { + { + throw ReactError( + "Expected prepareToHydrateHostInstance() to never be called. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + + var instance = fiber.stateNode; + var updatePayload = hydrateInstance( + instance, + fiber.type, + fiber.memoizedProps, + rootContainerInstance, + hostContext, + fiber + ); + // TODO: Type this specific to this type of component. + fiber.updateQueue = updatePayload; + // If the update payload indicates that there is a change or if there + // is a new ref we mark this as an update. + if (updatePayload !== null) { + return true; + } + return false; +} + +function prepareToHydrateHostTextInstance(fiber) { + if (!supportsHydration) { + (function() { + { + throw ReactError( + "Expected prepareToHydrateHostTextInstance() to never be called. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + + var textInstance = fiber.stateNode; + var textContent = fiber.memoizedProps; + var shouldUpdate = hydrateTextInstance(textInstance, textContent, fiber); + { + if (shouldUpdate) { + // We assume that prepareToHydrateHostTextInstance is called in a context where the + // hydration parent is the parent host component of this host text. + var returnFiber = hydrationParentFiber; + if (returnFiber !== null) { + switch (returnFiber.tag) { + case HostRoot: { + var parentContainer = returnFiber.stateNode.containerInfo; + didNotMatchHydratedContainerTextInstance( + parentContainer, + textInstance, + textContent + ); + break; + } + case HostComponent: { + var parentType = returnFiber.type; + var parentProps = returnFiber.memoizedProps; + var parentInstance = returnFiber.stateNode; + didNotMatchHydratedTextInstance( + parentType, + parentProps, + parentInstance, + textInstance, + textContent + ); + break; + } + } + } + } + } + return shouldUpdate; +} + +function skipPastDehydratedSuspenseInstance(fiber) { + if (!supportsHydration) { + (function() { + { + throw ReactError( + "Expected skipPastDehydratedSuspenseInstance() to never be called. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + var suspenseInstance = fiber.stateNode; + (function() { + if (!suspenseInstance) { + throw ReactError( + "Expected to have a hydrated suspense instance. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + nextHydratableInstance = getNextHydratableInstanceAfterSuspenseInstance( + suspenseInstance + ); +} + +function popToNextHostParent(fiber) { + var parent = fiber.return; + while ( + parent !== null && + parent.tag !== HostComponent && + parent.tag !== HostRoot && + parent.tag !== DehydratedSuspenseComponent + ) { + parent = parent.return; + } + hydrationParentFiber = parent; +} + +function popHydrationState(fiber) { + if (!supportsHydration) { + return false; + } + if (fiber !== hydrationParentFiber) { + // We're deeper than the current hydration context, inside an inserted + // tree. + return false; + } + if (!isHydrating) { + // If we're not currently hydrating but we're in a hydration context, then + // we were an insertion and now need to pop up reenter hydration of our + // siblings. + popToNextHostParent(fiber); + isHydrating = true; + return false; + } + + var type = fiber.type; + + // If we have any remaining hydratable nodes, we need to delete them now. + // We only do this deeper than head and body since they tend to have random + // other nodes in them. We also ignore components with pure text content in + // side of them. + // TODO: Better heuristic. + if ( + fiber.tag !== HostComponent || + (type !== "head" && + type !== "body" && + !shouldSetTextContent(type, fiber.memoizedProps)) + ) { + var nextInstance = nextHydratableInstance; + while (nextInstance) { + deleteHydratableInstance(fiber, nextInstance); + nextInstance = getNextHydratableSibling(nextInstance); + } + } + + popToNextHostParent(fiber); + nextHydratableInstance = hydrationParentFiber + ? getNextHydratableSibling(fiber.stateNode) + : null; + return true; +} + +function resetHydrationState() { + if (!supportsHydration) { + return; + } + + hydrationParentFiber = null; + nextHydratableInstance = null; + isHydrating = false; +} + +var ReactCurrentOwner$3 = ReactSharedInternals.ReactCurrentOwner; + +var didReceiveUpdate = false; + +var didWarnAboutBadClass = void 0; +var didWarnAboutModulePatternComponent = void 0; +var didWarnAboutContextTypeOnFunctionComponent = void 0; +var didWarnAboutGetDerivedStateOnFunctionComponent = void 0; +var didWarnAboutFunctionRefs = void 0; +var didWarnAboutReassigningProps = void 0; +var didWarnAboutMaxDuration = void 0; + +{ + didWarnAboutBadClass = {}; + didWarnAboutModulePatternComponent = {}; + didWarnAboutContextTypeOnFunctionComponent = {}; + didWarnAboutGetDerivedStateOnFunctionComponent = {}; + didWarnAboutFunctionRefs = {}; + didWarnAboutReassigningProps = false; + didWarnAboutMaxDuration = false; +} + +function reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime +) { + if (current$$1 === null) { + // If this is a fresh new component that hasn't been rendered yet, we + // won't update its child set by applying minimal side-effects. Instead, + // we will add them all to the child before it gets rendered. That means + // we can optimize this reconciliation pass by not tracking side-effects. + workInProgress.child = mountChildFibers( + workInProgress, + null, + nextChildren, + renderExpirationTime + ); + } else { + // If the current child is the same as the work in progress, it means that + // we haven't yet started any work on these children. Therefore, we use + // the clone algorithm to create a copy of all the current children. + + // If we had any progressed work already, that is invalid at this point so + // let's throw it out. + workInProgress.child = reconcileChildFibers( + workInProgress, + current$$1.child, + nextChildren, + renderExpirationTime + ); + } +} + +function forceUnmountCurrentAndReconcile( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime +) { + // This function is fork of reconcileChildren. It's used in cases where we + // want to reconcile without matching against the existing set. This has the + // effect of all current children being unmounted; even if the type and key + // are the same, the old child is unmounted and a new child is created. + // + // To do this, we're going to go through the reconcile algorithm twice. In + // the first pass, we schedule a deletion for all the current children by + // passing null. + workInProgress.child = reconcileChildFibers( + workInProgress, + current$$1.child, + null, + renderExpirationTime + ); + // In the second pass, we mount the new children. The trick here is that we + // pass null in place of where we usually pass the current child set. This has + // the effect of remounting all children regardless of whether their their + // identity matches. + workInProgress.child = reconcileChildFibers( + workInProgress, + null, + nextChildren, + renderExpirationTime + ); +} + +function updateForwardRef( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + // TODO: current can be non-null here even if the component + // hasn't yet mounted. This happens after the first render suspends. + // We'll need to figure out if this is fine or can cause issues. + + { + if (workInProgress.type !== workInProgress.elementType) { + // Lazy component props can't be validated in createElement + // because they're only guaranteed to be resolved here. + var innerPropTypes = Component.propTypes; + if (innerPropTypes) { + checkPropTypes( + innerPropTypes, + nextProps, // Resolved props + "prop", + getComponentName(Component), + getCurrentFiberStackInDev + ); + } + } + } + + var render = Component.render; + var ref = workInProgress.ref; + + // The rest is a fork of updateFunctionComponent + var nextChildren = void 0; + prepareToReadContext(workInProgress, renderExpirationTime); + { + ReactCurrentOwner$3.current = workInProgress; + setCurrentPhase("render"); + nextChildren = renderWithHooks( + current$$1, + workInProgress, + render, + nextProps, + ref, + renderExpirationTime + ); + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + // Only double-render components with Hooks + if (workInProgress.memoizedState !== null) { + nextChildren = renderWithHooks( + current$$1, + workInProgress, + render, + nextProps, + ref, + renderExpirationTime + ); + } + } + setCurrentPhase(null); + } + + if (current$$1 !== null && !didReceiveUpdate) { + bailoutHooks(current$$1, workInProgress, renderExpirationTime); + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + return workInProgress.child; +} + +function updateMemoComponent( + current$$1, + workInProgress, + Component, + nextProps, + updateExpirationTime, + renderExpirationTime +) { + if (current$$1 === null) { + var type = Component.type; + if ( + isSimpleFunctionComponent(type) && + Component.compare === null && + // SimpleMemoComponent codepath doesn't resolve outer props either. + Component.defaultProps === undefined + ) { + // If this is a plain function component without default props, + // and with only the default shallow comparison, we upgrade it + // to a SimpleMemoComponent to allow fast path updates. + workInProgress.tag = SimpleMemoComponent; + workInProgress.type = type; + { + validateFunctionComponentInDev(workInProgress, type); + } + return updateSimpleMemoComponent( + current$$1, + workInProgress, + type, + nextProps, + updateExpirationTime, + renderExpirationTime + ); + } + { + var innerPropTypes = type.propTypes; + if (innerPropTypes) { + // Inner memo component props aren't currently validated in createElement. + // We could move it there, but we'd still need this for lazy code path. + checkPropTypes( + innerPropTypes, + nextProps, // Resolved props + "prop", + getComponentName(type), + getCurrentFiberStackInDev + ); + } + } + var child = createFiberFromTypeAndProps( + Component.type, + null, + nextProps, + null, + workInProgress.mode, + renderExpirationTime + ); + child.ref = workInProgress.ref; + child.return = workInProgress; + workInProgress.child = child; + return child; + } + { + var _type = Component.type; + var _innerPropTypes = _type.propTypes; + if (_innerPropTypes) { + // Inner memo component props aren't currently validated in createElement. + // We could move it there, but we'd still need this for lazy code path. + checkPropTypes( + _innerPropTypes, + nextProps, // Resolved props + "prop", + getComponentName(_type), + getCurrentFiberStackInDev + ); + } + } + var currentChild = current$$1.child; // This is always exactly one child + if (updateExpirationTime < renderExpirationTime) { + // This will be the props with resolved defaultProps, + // unlike current.memoizedProps which will be the unresolved ones. + var prevProps = currentChild.memoizedProps; + // Default to shallow comparison + var compare = Component.compare; + compare = compare !== null ? compare : shallowEqual; + if ( + compare(prevProps, nextProps) && + current$$1.ref === workInProgress.ref + ) { + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + } + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + var newChild = createWorkInProgress( + currentChild, + nextProps, + renderExpirationTime + ); + newChild.ref = workInProgress.ref; + newChild.return = workInProgress; + workInProgress.child = newChild; + return newChild; +} + +function updateSimpleMemoComponent( + current$$1, + workInProgress, + Component, + nextProps, + updateExpirationTime, + renderExpirationTime +) { + // TODO: current can be non-null here even if the component + // hasn't yet mounted. This happens when the inner render suspends. + // We'll need to figure out if this is fine or can cause issues. + + { + if (workInProgress.type !== workInProgress.elementType) { + // Lazy component props can't be validated in createElement + // because they're only guaranteed to be resolved here. + var outerMemoType = workInProgress.elementType; + if (outerMemoType.$$typeof === REACT_LAZY_TYPE) { + // We warn when you define propTypes on lazy() + // so let's just skip over it to find memo() outer wrapper. + // Inner props for memo are validated later. + outerMemoType = refineResolvedLazyComponent(outerMemoType); + } + var outerPropTypes = outerMemoType && outerMemoType.propTypes; + if (outerPropTypes) { + checkPropTypes( + outerPropTypes, + nextProps, // Resolved (SimpleMemoComponent has no defaultProps) + "prop", + getComponentName(outerMemoType), + getCurrentFiberStackInDev + ); + } + // Inner propTypes will be validated in the function component path. + } + } + if (current$$1 !== null) { + var prevProps = current$$1.memoizedProps; + if ( + shallowEqual(prevProps, nextProps) && + current$$1.ref === workInProgress.ref + ) { + didReceiveUpdate = false; + if (updateExpirationTime < renderExpirationTime) { + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + } + } + return updateFunctionComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime + ); +} + +function updateFragment(current$$1, workInProgress, renderExpirationTime) { + var nextChildren = workInProgress.pendingProps; + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + return workInProgress.child; +} + +function updateMode(current$$1, workInProgress, renderExpirationTime) { + var nextChildren = workInProgress.pendingProps.children; + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + return workInProgress.child; +} + +function updateProfiler(current$$1, workInProgress, renderExpirationTime) { + if (enableProfilerTimer) { + workInProgress.effectTag |= Update; + } + var nextProps = workInProgress.pendingProps; + var nextChildren = nextProps.children; + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + return workInProgress.child; +} + +function markRef(current$$1, workInProgress) { + var ref = workInProgress.ref; + if ( + (current$$1 === null && ref !== null) || + (current$$1 !== null && current$$1.ref !== ref) + ) { + // Schedule a Ref effect + workInProgress.effectTag |= Ref; + } +} + +function updateFunctionComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + { + if (workInProgress.type !== workInProgress.elementType) { + // Lazy component props can't be validated in createElement + // because they're only guaranteed to be resolved here. + var innerPropTypes = Component.propTypes; + if (innerPropTypes) { + checkPropTypes( + innerPropTypes, + nextProps, // Resolved props + "prop", + getComponentName(Component), + getCurrentFiberStackInDev + ); + } + } + } + + var unmaskedContext = getUnmaskedContext(workInProgress, Component, true); + var context = getMaskedContext(workInProgress, unmaskedContext); + + var nextChildren = void 0; + prepareToReadContext(workInProgress, renderExpirationTime); + { + ReactCurrentOwner$3.current = workInProgress; + setCurrentPhase("render"); + nextChildren = renderWithHooks( + current$$1, + workInProgress, + Component, + nextProps, + context, + renderExpirationTime + ); + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + // Only double-render components with Hooks + if (workInProgress.memoizedState !== null) { + nextChildren = renderWithHooks( + current$$1, + workInProgress, + Component, + nextProps, + context, + renderExpirationTime + ); + } + } + setCurrentPhase(null); + } + + if (current$$1 !== null && !didReceiveUpdate) { + bailoutHooks(current$$1, workInProgress, renderExpirationTime); + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + return workInProgress.child; +} + +function updateClassComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + { + if (workInProgress.type !== workInProgress.elementType) { + // Lazy component props can't be validated in createElement + // because they're only guaranteed to be resolved here. + var innerPropTypes = Component.propTypes; + if (innerPropTypes) { + checkPropTypes( + innerPropTypes, + nextProps, // Resolved props + "prop", + getComponentName(Component), + getCurrentFiberStackInDev + ); + } + } + } + + // Push context providers early to prevent context stack mismatches. + // During mounting we don't know the child context yet as the instance doesn't exist. + // We will invalidate the child context in finishClassComponent() right after rendering. + var hasContext = void 0; + if (isContextProvider(Component)) { + hasContext = true; + pushContextProvider(workInProgress); + } else { + hasContext = false; + } + prepareToReadContext(workInProgress, renderExpirationTime); + + var instance = workInProgress.stateNode; + var shouldUpdate = void 0; + if (instance === null) { + if (current$$1 !== null) { + // An class component without an instance only mounts if it suspended + // inside a non- concurrent tree, in an inconsistent state. We want to + // tree it like a new mount, even though an empty version of it already + // committed. Disconnect the alternate pointers. + current$$1.alternate = null; + workInProgress.alternate = null; + // Since this is conceptually a new fiber, schedule a Placement effect + workInProgress.effectTag |= Placement; + } + // In the initial pass we might need to construct the instance. + constructClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ); + mountClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ); + shouldUpdate = true; + } else if (current$$1 === null) { + // In a resume, we'll already have an instance we can reuse. + shouldUpdate = resumeMountClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ); + } else { + shouldUpdate = updateClassInstance( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime + ); + } + var nextUnitOfWork = finishClassComponent( + current$$1, + workInProgress, + Component, + shouldUpdate, + hasContext, + renderExpirationTime + ); + { + var inst = workInProgress.stateNode; + if (inst.props !== nextProps) { + !didWarnAboutReassigningProps + ? warning$1( + false, + "It looks like %s is reassigning its own `this.props` while rendering. " + + "This is not supported and can lead to confusing bugs.", + getComponentName(workInProgress.type) || "a component" + ) + : void 0; + didWarnAboutReassigningProps = true; + } + } + return nextUnitOfWork; +} + +function finishClassComponent( + current$$1, + workInProgress, + Component, + shouldUpdate, + hasContext, + renderExpirationTime +) { + // Refs should update even if shouldComponentUpdate returns false + markRef(current$$1, workInProgress); + + var didCaptureError = (workInProgress.effectTag & DidCapture) !== NoEffect; + + if (!shouldUpdate && !didCaptureError) { + // Context providers should defer to sCU for rendering + if (hasContext) { + invalidateContextProvider(workInProgress, Component, false); + } + + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + + var instance = workInProgress.stateNode; + + // Rerender + ReactCurrentOwner$3.current = workInProgress; + var nextChildren = void 0; + if ( + didCaptureError && + typeof Component.getDerivedStateFromError !== "function" + ) { + // If we captured an error, but getDerivedStateFrom catch is not defined, + // unmount all the children. componentDidCatch will schedule an update to + // re-render a fallback. This is temporary until we migrate everyone to + // the new API. + // TODO: Warn in a future release. + nextChildren = null; + + if (enableProfilerTimer) { + stopProfilerTimerIfRunning(workInProgress); + } + } else { + { + setCurrentPhase("render"); + nextChildren = instance.render(); + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + instance.render(); + } + setCurrentPhase(null); + } + } + + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + if (current$$1 !== null && didCaptureError) { + // If we're recovering from an error, reconcile without reusing any of + // the existing children. Conceptually, the normal children and the children + // that are shown on error are two different sets, so we shouldn't reuse + // normal children even if their identities match. + forceUnmountCurrentAndReconcile( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + } else { + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + } + + // Memoize state using the values we just used to render. + // TODO: Restructure so we never read values from the instance. + workInProgress.memoizedState = instance.state; + + // The context might have changed so we need to recalculate it. + if (hasContext) { + invalidateContextProvider(workInProgress, Component, true); + } + + return workInProgress.child; +} + +function pushHostRootContext(workInProgress) { + var root = workInProgress.stateNode; + if (root.pendingContext) { + pushTopLevelContextObject( + workInProgress, + root.pendingContext, + root.pendingContext !== root.context + ); + } else if (root.context) { + // Should always be set + pushTopLevelContextObject(workInProgress, root.context, false); + } + pushHostContainer(workInProgress, root.containerInfo); +} + +function updateHostRoot(current$$1, workInProgress, renderExpirationTime) { + pushHostRootContext(workInProgress); + var updateQueue = workInProgress.updateQueue; + (function() { + if (!(updateQueue !== null)) { + throw ReactError( + "If the root does not have an updateQueue, we should have already bailed out. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + var nextProps = workInProgress.pendingProps; + var prevState = workInProgress.memoizedState; + var prevChildren = prevState !== null ? prevState.element : null; + processUpdateQueue( + workInProgress, + updateQueue, + nextProps, + null, + renderExpirationTime + ); + var nextState = workInProgress.memoizedState; + // Caution: React DevTools currently depends on this property + // being called "element". + var nextChildren = nextState.element; + if (nextChildren === prevChildren) { + // If the state is the same as before, that's a bailout because we had + // no work that expires at this time. + resetHydrationState(); + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + var root = workInProgress.stateNode; + if ( + (current$$1 === null || current$$1.child === null) && + root.hydrate && + enterHydrationState(workInProgress) + ) { + // If we don't have any current children this might be the first pass. + // We always try to hydrate. If this isn't a hydration pass there won't + // be any children to hydrate which is effectively the same thing as + // not hydrating. + + // This is a bit of a hack. We track the host root as a placement to + // know that we're currently in a mounting state. That way isMounted + // works as expected. We must reset this before committing. + // TODO: Delete this when we delete isMounted and findDOMNode. + workInProgress.effectTag |= Placement; + + // Ensure that children mount into this root without tracking + // side-effects. This ensures that we don't store Placement effects on + // nodes that will be hydrated. + workInProgress.child = mountChildFibers( + workInProgress, + null, + nextChildren, + renderExpirationTime + ); + } else { + // Otherwise reset hydration state in case we aborted and resumed another + // root. + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + resetHydrationState(); + } + return workInProgress.child; +} + +function updateHostComponent(current$$1, workInProgress, renderExpirationTime) { + pushHostContext(workInProgress); + + if (current$$1 === null) { + tryToClaimNextHydratableInstance(workInProgress); + } + + var type = workInProgress.type; + var nextProps = workInProgress.pendingProps; + var prevProps = current$$1 !== null ? current$$1.memoizedProps : null; + + var nextChildren = nextProps.children; + var isDirectTextChild = shouldSetTextContent(type, nextProps); + + if (isDirectTextChild) { + // We special case a direct text child of a host node. This is a common + // case. We won't handle it as a reified child. We will instead handle + // this in the host environment that also have access to this prop. That + // avoids allocating another HostText fiber and traversing it. + nextChildren = null; + } else if (prevProps !== null && shouldSetTextContent(type, prevProps)) { + // If we're switching from a direct text child to a normal child, or to + // empty, we need to schedule the text content to be reset. + workInProgress.effectTag |= ContentReset; + } + + markRef(current$$1, workInProgress); + + // Check the host config to see if the children are offscreen/hidden. + if ( + renderExpirationTime !== Never && + workInProgress.mode & ConcurrentMode && + shouldDeprioritizeSubtree(type, nextProps) + ) { + // Schedule this fiber to re-render at offscreen priority. Then bailout. + workInProgress.expirationTime = workInProgress.childExpirationTime = Never; + return null; + } + + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + return workInProgress.child; +} + +function updateHostText(current$$1, workInProgress) { + if (current$$1 === null) { + tryToClaimNextHydratableInstance(workInProgress); + } + // Nothing to do here. This is terminal. We'll do the completion step + // immediately after. + return null; +} + +function mountLazyComponent( + _current, + workInProgress, + elementType, + updateExpirationTime, + renderExpirationTime +) { + if (_current !== null) { + // An lazy component only mounts if it suspended inside a non- + // concurrent tree, in an inconsistent state. We want to treat it like + // a new mount, even though an empty version of it already committed. + // Disconnect the alternate pointers. + _current.alternate = null; + workInProgress.alternate = null; + // Since this is conceptually a new fiber, schedule a Placement effect + workInProgress.effectTag |= Placement; + } + + var props = workInProgress.pendingProps; + // We can't start a User Timing measurement with correct label yet. + // Cancel and resume right after we know the tag. + cancelWorkTimer(workInProgress); + var Component = readLazyComponentType(elementType); + // Store the unwrapped component in the type. + workInProgress.type = Component; + var resolvedTag = (workInProgress.tag = resolveLazyComponentTag(Component)); + startWorkTimer(workInProgress); + var resolvedProps = resolveDefaultProps(Component, props); + var child = void 0; + switch (resolvedTag) { + case FunctionComponent: { + { + validateFunctionComponentInDev(workInProgress, Component); + } + child = updateFunctionComponent( + null, + workInProgress, + Component, + resolvedProps, + renderExpirationTime + ); + break; + } + case ClassComponent: { + child = updateClassComponent( + null, + workInProgress, + Component, + resolvedProps, + renderExpirationTime + ); + break; + } + case ForwardRef: { + child = updateForwardRef( + null, + workInProgress, + Component, + resolvedProps, + renderExpirationTime + ); + break; + } + case MemoComponent: { + { + if (workInProgress.type !== workInProgress.elementType) { + var outerPropTypes = Component.propTypes; + if (outerPropTypes) { + checkPropTypes( + outerPropTypes, + resolvedProps, // Resolved for outer only + "prop", + getComponentName(Component), + getCurrentFiberStackInDev + ); + } + } + } + child = updateMemoComponent( + null, + workInProgress, + Component, + resolveDefaultProps(Component.type, resolvedProps), // The inner type can have defaults too + updateExpirationTime, + renderExpirationTime + ); + break; + } + default: { + var hint = ""; + { + if ( + Component !== null && + typeof Component === "object" && + Component.$$typeof === REACT_LAZY_TYPE + ) { + hint = " Did you wrap a component in React.lazy() more than once?"; + } + } + // This message intentionally doesn't mention ForwardRef or MemoComponent + // because the fact that it's a separate type of work is an + // implementation detail. + (function() { + { + throw ReactError( + "Element type is invalid. Received a promise that resolves to: " + + Component + + ". Lazy element type must resolve to a class or function." + + hint + ); + } + })(); + } + } + return child; +} + +function mountIncompleteClassComponent( + _current, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + if (_current !== null) { + // An incomplete component only mounts if it suspended inside a non- + // concurrent tree, in an inconsistent state. We want to treat it like + // a new mount, even though an empty version of it already committed. + // Disconnect the alternate pointers. + _current.alternate = null; + workInProgress.alternate = null; + // Since this is conceptually a new fiber, schedule a Placement effect + workInProgress.effectTag |= Placement; + } + + // Promote the fiber to a class and try rendering again. + workInProgress.tag = ClassComponent; + + // The rest of this function is a fork of `updateClassComponent` + + // Push context providers early to prevent context stack mismatches. + // During mounting we don't know the child context yet as the instance doesn't exist. + // We will invalidate the child context in finishClassComponent() right after rendering. + var hasContext = void 0; + if (isContextProvider(Component)) { + hasContext = true; + pushContextProvider(workInProgress); + } else { + hasContext = false; + } + prepareToReadContext(workInProgress, renderExpirationTime); + + constructClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ); + mountClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ); + + return finishClassComponent( + null, + workInProgress, + Component, + true, + hasContext, + renderExpirationTime + ); +} + +function mountIndeterminateComponent( + _current, + workInProgress, + Component, + renderExpirationTime +) { + if (_current !== null) { + // An indeterminate component only mounts if it suspended inside a non- + // concurrent tree, in an inconsistent state. We want to treat it like + // a new mount, even though an empty version of it already committed. + // Disconnect the alternate pointers. + _current.alternate = null; + workInProgress.alternate = null; + // Since this is conceptually a new fiber, schedule a Placement effect + workInProgress.effectTag |= Placement; + } + + var props = workInProgress.pendingProps; + var unmaskedContext = getUnmaskedContext(workInProgress, Component, false); + var context = getMaskedContext(workInProgress, unmaskedContext); + + prepareToReadContext(workInProgress, renderExpirationTime); + + var value = void 0; + + { + if ( + Component.prototype && + typeof Component.prototype.render === "function" + ) { + var componentName = getComponentName(Component) || "Unknown"; + + if (!didWarnAboutBadClass[componentName]) { + warningWithoutStack$1( + false, + "The <%s /> component appears to have a render method, but doesn't extend React.Component. " + + "This is likely to cause errors. Change %s to extend React.Component instead.", + componentName, + componentName + ); + didWarnAboutBadClass[componentName] = true; + } + } + + if (workInProgress.mode & StrictMode) { + ReactStrictModeWarnings.recordLegacyContextWarning(workInProgress, null); + } + + ReactCurrentOwner$3.current = workInProgress; + value = renderWithHooks( + null, + workInProgress, + Component, + props, + context, + renderExpirationTime + ); + } + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + + if ( + typeof value === "object" && + value !== null && + typeof value.render === "function" && + value.$$typeof === undefined + ) { + { + var _componentName = getComponentName(Component) || "Unknown"; + if (!didWarnAboutModulePatternComponent[_componentName]) { + warningWithoutStack$1( + false, + "The <%s /> component appears to be a function component that returns a class instance. " + + "Change %s to a class that extends React.Component instead. " + + "If you can't use a class try assigning the prototype on the function as a workaround. " + + "`%s.prototype = React.Component.prototype`. Don't use an arrow function since it " + + "cannot be called with `new` by React.", + _componentName, + _componentName, + _componentName + ); + didWarnAboutModulePatternComponent[_componentName] = true; + } + } + + // Proceed under the assumption that this is a class instance + workInProgress.tag = ClassComponent; + + // Throw out any hooks that were used. + resetHooks(); + + // Push context providers early to prevent context stack mismatches. + // During mounting we don't know the child context yet as the instance doesn't exist. + // We will invalidate the child context in finishClassComponent() right after rendering. + var hasContext = false; + if (isContextProvider(Component)) { + hasContext = true; + pushContextProvider(workInProgress); + } else { + hasContext = false; + } + + workInProgress.memoizedState = + value.state !== null && value.state !== undefined ? value.state : null; + + var getDerivedStateFromProps = Component.getDerivedStateFromProps; + if (typeof getDerivedStateFromProps === "function") { + applyDerivedStateFromProps( + workInProgress, + Component, + getDerivedStateFromProps, + props + ); + } + + adoptClassInstance(workInProgress, value); + mountClassInstance(workInProgress, Component, props, renderExpirationTime); + return finishClassComponent( + null, + workInProgress, + Component, + true, + hasContext, + renderExpirationTime + ); + } else { + // Proceed under the assumption that this is a function component + workInProgress.tag = FunctionComponent; + { + if ( + debugRenderPhaseSideEffects || + (debugRenderPhaseSideEffectsForStrictMode && + workInProgress.mode & StrictMode) + ) { + // Only double-render components with Hooks + if (workInProgress.memoizedState !== null) { + value = renderWithHooks( + null, + workInProgress, + Component, + props, + context, + renderExpirationTime + ); + } + } + } + reconcileChildren(null, workInProgress, value, renderExpirationTime); + { + validateFunctionComponentInDev(workInProgress, Component); + } + return workInProgress.child; + } +} + +function validateFunctionComponentInDev(workInProgress, Component) { + if (Component) { + !!Component.childContextTypes + ? warningWithoutStack$1( + false, + "%s(...): childContextTypes cannot be defined on a function component.", + Component.displayName || Component.name || "Component" + ) + : void 0; + } + if (workInProgress.ref !== null) { + var info = ""; + var ownerName = getCurrentFiberOwnerNameInDevOrNull(); + if (ownerName) { + info += "\n\nCheck the render method of `" + ownerName + "`."; + } + + var warningKey = ownerName || workInProgress._debugID || ""; + var debugSource = workInProgress._debugSource; + if (debugSource) { + warningKey = debugSource.fileName + ":" + debugSource.lineNumber; + } + if (!didWarnAboutFunctionRefs[warningKey]) { + didWarnAboutFunctionRefs[warningKey] = true; + warning$1( + false, + "Function components cannot be given refs. " + + "Attempts to access this ref will fail. " + + "Did you mean to use React.forwardRef()?%s", + info + ); + } + } + + if (typeof Component.getDerivedStateFromProps === "function") { + var componentName = getComponentName(Component) || "Unknown"; + + if (!didWarnAboutGetDerivedStateOnFunctionComponent[componentName]) { + warningWithoutStack$1( + false, + "%s: Function components do not support getDerivedStateFromProps.", + componentName + ); + didWarnAboutGetDerivedStateOnFunctionComponent[componentName] = true; + } + } + + if ( + typeof Component.contextType === "object" && + Component.contextType !== null + ) { + var _componentName2 = getComponentName(Component) || "Unknown"; + + if (!didWarnAboutContextTypeOnFunctionComponent[_componentName2]) { + warningWithoutStack$1( + false, + "%s: Function components do not support contextType.", + _componentName2 + ); + didWarnAboutContextTypeOnFunctionComponent[_componentName2] = true; + } + } +} + +function updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime +) { + var mode = workInProgress.mode; + var nextProps = workInProgress.pendingProps; + + { + if (shouldSuspend(workInProgress)) { + workInProgress.effectTag |= DidCapture; + } + } + + // We should attempt to render the primary children unless this boundary + // already suspended during this render (`alreadyCaptured` is true). + var nextState = workInProgress.memoizedState; + + var nextDidTimeout = void 0; + if ((workInProgress.effectTag & DidCapture) === NoEffect) { + // This is the first attempt. + nextState = null; + nextDidTimeout = false; + } else { + // Something in this boundary's subtree already suspended. Switch to + // rendering the fallback children. + nextState = { + fallbackExpirationTime: + nextState !== null ? nextState.fallbackExpirationTime : NoWork + }; + nextDidTimeout = true; + workInProgress.effectTag &= ~DidCapture; + } + + { + if ("maxDuration" in nextProps) { + if (!didWarnAboutMaxDuration) { + didWarnAboutMaxDuration = true; + warning$1( + false, + "maxDuration has been removed from React. " + + "Remove the maxDuration prop." + ); + } + } + } + + // This next part is a bit confusing. If the children timeout, we switch to + // showing the fallback children in place of the "primary" children. + // However, we don't want to delete the primary children because then their + // state will be lost (both the React state and the host state, e.g. + // uncontrolled form inputs). Instead we keep them mounted and hide them. + // Both the fallback children AND the primary children are rendered at the + // same time. Once the primary children are un-suspended, we can delete + // the fallback children — don't need to preserve their state. + // + // The two sets of children are siblings in the host environment, but + // semantically, for purposes of reconciliation, they are two separate sets. + // So we store them using two fragment fibers. + // + // However, we want to avoid allocating extra fibers for every placeholder. + // They're only necessary when the children time out, because that's the + // only time when both sets are mounted. + // + // So, the extra fragment fibers are only used if the children time out. + // Otherwise, we render the primary children directly. This requires some + // custom reconciliation logic to preserve the state of the primary + // children. It's essentially a very basic form of re-parenting. + + // `child` points to the child fiber. In the normal case, this is the first + // fiber of the primary children set. In the timed-out case, it's a + // a fragment fiber containing the primary children. + var child = void 0; + // `next` points to the next fiber React should render. In the normal case, + // it's the same as `child`: the first fiber of the primary children set. + // In the timed-out case, it's a fragment fiber containing the *fallback* + // children -- we skip over the primary children entirely. + var next = void 0; + if (current$$1 === null) { + if (enableSuspenseServerRenderer) { + // If we're currently hydrating, try to hydrate this boundary. + // But only if this has a fallback. + if (nextProps.fallback !== undefined) { + tryToClaimNextHydratableInstance(workInProgress); + // This could've changed the tag if this was a dehydrated suspense component. + if (workInProgress.tag === DehydratedSuspenseComponent) { + return updateDehydratedSuspenseComponent( + null, + workInProgress, + renderExpirationTime + ); + } + } + } + + // This is the initial mount. This branch is pretty simple because there's + // no previous state that needs to be preserved. + if (nextDidTimeout) { + // Mount separate fragments for primary and fallback children. + var nextFallbackChildren = nextProps.fallback; + var primaryChildFragment = createFiberFromFragment( + null, + mode, + NoWork, + null + ); + + if ((workInProgress.mode & ConcurrentMode) === NoContext) { + // Outside of concurrent mode, we commit the effects from the + var progressedState = workInProgress.memoizedState; + var progressedPrimaryChild = + progressedState !== null + ? workInProgress.child.child + : workInProgress.child; + primaryChildFragment.child = progressedPrimaryChild; + } + + var fallbackChildFragment = createFiberFromFragment( + nextFallbackChildren, + mode, + renderExpirationTime, + null + ); + primaryChildFragment.sibling = fallbackChildFragment; + child = primaryChildFragment; + // Skip the primary children, and continue working on the + // fallback children. + next = fallbackChildFragment; + child.return = next.return = workInProgress; + } else { + // Mount the primary children without an intermediate fragment fiber. + var nextPrimaryChildren = nextProps.children; + child = next = mountChildFibers( + workInProgress, + null, + nextPrimaryChildren, + renderExpirationTime + ); + } + } else { + // This is an update. This branch is more complicated because we need to + // ensure the state of the primary children is preserved. + var prevState = current$$1.memoizedState; + var prevDidTimeout = prevState !== null; + if (prevDidTimeout) { + // The current tree already timed out. That means each child set is + var currentPrimaryChildFragment = current$$1.child; + var currentFallbackChildFragment = currentPrimaryChildFragment.sibling; + if (nextDidTimeout) { + // Still timed out. Reuse the current primary children by cloning + // its fragment. We're going to skip over these entirely. + var _nextFallbackChildren = nextProps.fallback; + var _primaryChildFragment = createWorkInProgress( + currentPrimaryChildFragment, + currentPrimaryChildFragment.pendingProps, + NoWork + ); + + if ((workInProgress.mode & ConcurrentMode) === NoContext) { + // Outside of concurrent mode, we commit the effects from the + var _progressedState = workInProgress.memoizedState; + var _progressedPrimaryChild = + _progressedState !== null + ? workInProgress.child.child + : workInProgress.child; + if (_progressedPrimaryChild !== currentPrimaryChildFragment.child) { + _primaryChildFragment.child = _progressedPrimaryChild; + } + } + + // Because primaryChildFragment is a new fiber that we're inserting as the + // parent of a new tree, we need to set its treeBaseDuration. + if (enableProfilerTimer && workInProgress.mode & ProfileMode) { + // treeBaseDuration is the sum of all the child tree base durations. + var treeBaseDuration = 0; + var hiddenChild = _primaryChildFragment.child; + while (hiddenChild !== null) { + treeBaseDuration += hiddenChild.treeBaseDuration; + hiddenChild = hiddenChild.sibling; + } + _primaryChildFragment.treeBaseDuration = treeBaseDuration; + } + + // Clone the fallback child fragment, too. These we'll continue + // working on. + var _fallbackChildFragment = (_primaryChildFragment.sibling = createWorkInProgress( + currentFallbackChildFragment, + _nextFallbackChildren, + currentFallbackChildFragment.expirationTime + )); + child = _primaryChildFragment; + _primaryChildFragment.childExpirationTime = NoWork; + // Skip the primary children, and continue working on the + // fallback children. + next = _fallbackChildFragment; + child.return = next.return = workInProgress; + } else { + // No longer suspended. Switch back to showing the primary children, + // and remove the intermediate fragment fiber. + var _nextPrimaryChildren = nextProps.children; + var currentPrimaryChild = currentPrimaryChildFragment.child; + var primaryChild = reconcileChildFibers( + workInProgress, + currentPrimaryChild, + _nextPrimaryChildren, + renderExpirationTime + ); + + // If this render doesn't suspend, we need to delete the fallback + // children. Wait until the complete phase, after we've confirmed the + // fallback is no longer needed. + // TODO: Would it be better to store the fallback fragment on + // the stateNode? + + // Continue rendering the children, like we normally do. + child = next = primaryChild; + } + } else { + // The current tree has not already timed out. That means the primary + // children are not wrapped in a fragment fiber. + var _currentPrimaryChild = current$$1.child; + if (nextDidTimeout) { + // Timed out. Wrap the children in a fragment fiber to keep them + // separate from the fallback children. + var _nextFallbackChildren2 = nextProps.fallback; + var _primaryChildFragment2 = createFiberFromFragment( + // It shouldn't matter what the pending props are because we aren't + // going to render this fragment. + null, + mode, + NoWork, + null + ); + _primaryChildFragment2.child = _currentPrimaryChild; + + // Even though we're creating a new fiber, there are no new children, + // because we're reusing an already mounted tree. So we don't need to + // schedule a placement. + // primaryChildFragment.effectTag |= Placement; + + if ((workInProgress.mode & ConcurrentMode) === NoContext) { + // Outside of concurrent mode, we commit the effects from the + var _progressedState2 = workInProgress.memoizedState; + var _progressedPrimaryChild2 = + _progressedState2 !== null + ? workInProgress.child.child + : workInProgress.child; + _primaryChildFragment2.child = _progressedPrimaryChild2; + } + + // Because primaryChildFragment is a new fiber that we're inserting as the + // parent of a new tree, we need to set its treeBaseDuration. + if (enableProfilerTimer && workInProgress.mode & ProfileMode) { + // treeBaseDuration is the sum of all the child tree base durations. + var _treeBaseDuration = 0; + var _hiddenChild = _primaryChildFragment2.child; + while (_hiddenChild !== null) { + _treeBaseDuration += _hiddenChild.treeBaseDuration; + _hiddenChild = _hiddenChild.sibling; + } + _primaryChildFragment2.treeBaseDuration = _treeBaseDuration; + } + + // Create a fragment from the fallback children, too. + var _fallbackChildFragment2 = (_primaryChildFragment2.sibling = createFiberFromFragment( + _nextFallbackChildren2, + mode, + renderExpirationTime, + null + )); + _fallbackChildFragment2.effectTag |= Placement; + child = _primaryChildFragment2; + _primaryChildFragment2.childExpirationTime = NoWork; + // Skip the primary children, and continue working on the + // fallback children. + next = _fallbackChildFragment2; + child.return = next.return = workInProgress; + } else { + // Still haven't timed out. Continue rendering the children, like we + // normally do. + var _nextPrimaryChildren2 = nextProps.children; + next = child = reconcileChildFibers( + workInProgress, + _currentPrimaryChild, + _nextPrimaryChildren2, + renderExpirationTime + ); + } + } + workInProgress.stateNode = current$$1.stateNode; + } + + workInProgress.memoizedState = nextState; + workInProgress.child = child; + return next; +} + +function retrySuspenseComponentWithoutHydrating( + current$$1, + workInProgress, + renderExpirationTime +) { + // Detach from the current dehydrated boundary. + current$$1.alternate = null; + workInProgress.alternate = null; + + // Insert a deletion in the effect list. + var returnFiber = workInProgress.return; + (function() { + if (!(returnFiber !== null)) { + throw ReactError( + "Suspense boundaries are never on the root. This is probably a bug in React." + ); + } + })(); + var last = returnFiber.lastEffect; + if (last !== null) { + last.nextEffect = current$$1; + returnFiber.lastEffect = current$$1; + } else { + returnFiber.firstEffect = returnFiber.lastEffect = current$$1; + } + current$$1.nextEffect = null; + current$$1.effectTag = Deletion; + + // Upgrade this work in progress to a real Suspense component. + workInProgress.tag = SuspenseComponent; + workInProgress.stateNode = null; + workInProgress.memoizedState = null; + // This is now an insertion. + workInProgress.effectTag |= Placement; + // Retry as a real Suspense component. + return updateSuspenseComponent(null, workInProgress, renderExpirationTime); +} + +function updateDehydratedSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime +) { + var suspenseInstance = workInProgress.stateNode; + if (current$$1 === null) { + // During the first pass, we'll bail out and not drill into the children. + // Instead, we'll leave the content in place and try to hydrate it later. + if (isSuspenseInstanceFallback(suspenseInstance)) { + // This is a client-only boundary. Since we won't get any content from the server + // for this, we need to schedule that at a higher priority based on when it would + // have timed out. In theory we could render it in this pass but it would have the + // wrong priority associated with it and will prevent hydration of parent path. + // Instead, we'll leave work left on it to render it in a separate commit. + + // TODO This time should be the time at which the server rendered response that is + // a parent to this boundary was displayed. However, since we currently don't have + // a protocol to transfer that time, we'll just estimate it by using the current + // time. This will mean that Suspense timeouts are slightly shifted to later than + // they should be. + var serverDisplayTime = requestCurrentTime(); + // Schedule a normal pri update to render this content. + workInProgress.expirationTime = computeAsyncExpiration(serverDisplayTime); + } else { + // We'll continue hydrating the rest at offscreen priority since we'll already + // be showing the right content coming from the server, it is no rush. + workInProgress.expirationTime = Never; + } + return null; + } + if ((workInProgress.effectTag & DidCapture) !== NoEffect) { + // Something suspended. Leave the existing children in place. + // TODO: In non-concurrent mode, should we commit the nodes we have hydrated so far? + workInProgress.child = null; + return null; + } + if (isSuspenseInstanceFallback(suspenseInstance)) { + // This boundary is in a permanent fallback state. In this case, we'll never + // get an update and we'll never be able to hydrate the final content. Let's just try the + // client side render instead. + return retrySuspenseComponentWithoutHydrating( + current$$1, + workInProgress, + renderExpirationTime + ); + } + // We use childExpirationTime to indicate that a child might depend on context, so if + // any context has changed, we need to treat is as if the input might have changed. + var hasContextChanged$$1 = + current$$1.childExpirationTime >= renderExpirationTime; + if (didReceiveUpdate || hasContextChanged$$1) { + // This boundary has changed since the first render. This means that we are now unable to + // hydrate it. We might still be able to hydrate it using an earlier expiration time but + // during this render we can't. Instead, we're going to delete the whole subtree and + // instead inject a new real Suspense boundary to take its place, which may render content + // or fallback. The real Suspense boundary will suspend for a while so we have some time + // to ensure it can produce real content, but all state and pending events will be lost. + return retrySuspenseComponentWithoutHydrating( + current$$1, + workInProgress, + renderExpirationTime + ); + } else if (isSuspenseInstancePending(suspenseInstance)) { + // This component is still pending more data from the server, so we can't hydrate its + // content. We treat it as if this component suspended itself. It might seem as if + // we could just try to render it client-side instead. However, this will perform a + // lot of unnecessary work and is unlikely to complete since it often will suspend + // on missing data anyway. Additionally, the server might be able to render more + // than we can on the client yet. In that case we'd end up with more fallback states + // on the client than if we just leave it alone. If the server times out or errors + // these should update this boundary to the permanent Fallback state instead. + // Mark it as having captured (i.e. suspended). + workInProgress.effectTag |= DidCapture; + // Leave the children in place. I.e. empty. + workInProgress.child = null; + // Register a callback to retry this boundary once the server has sent the result. + registerSuspenseInstanceRetry( + suspenseInstance, + retryTimedOutBoundary.bind(null, current$$1) + ); + return null; + } else { + // This is the first attempt. + reenterHydrationStateFromDehydratedSuspenseInstance(workInProgress); + var nextProps = workInProgress.pendingProps; + var nextChildren = nextProps.children; + workInProgress.child = mountChildFibers( + workInProgress, + null, + nextChildren, + renderExpirationTime + ); + return workInProgress.child; + } +} + +function updatePortalComponent( + current$$1, + workInProgress, + renderExpirationTime +) { + pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); + var nextChildren = workInProgress.pendingProps; + if (current$$1 === null) { + // Portals are special because we don't append the children during mount + // but at commit. Therefore we need to track insertions which the normal + // flow doesn't do during mount. This doesn't happen at the root because + // the root always starts with a "current" with a null child. + // TODO: Consider unifying this with how the root works. + workInProgress.child = reconcileChildFibers( + workInProgress, + null, + nextChildren, + renderExpirationTime + ); + } else { + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + } + return workInProgress.child; +} + +function updateContextProvider( + current$$1, + workInProgress, + renderExpirationTime +) { + var providerType = workInProgress.type; + var context = providerType._context; + + var newProps = workInProgress.pendingProps; + var oldProps = workInProgress.memoizedProps; + + var newValue = newProps.value; + + { + var providerPropTypes = workInProgress.type.propTypes; + + if (providerPropTypes) { + checkPropTypes( + providerPropTypes, + newProps, + "prop", + "Context.Provider", + getCurrentFiberStackInDev + ); + } + } + + pushProvider(workInProgress, newValue); + + if (oldProps !== null) { + var oldValue = oldProps.value; + var changedBits = calculateChangedBits(context, newValue, oldValue); + if (changedBits === 0) { + // No change. Bailout early if children are the same. + if (oldProps.children === newProps.children && !hasContextChanged()) { + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + } else { + // The context value changed. Search for matching consumers and schedule + // them to update. + propagateContextChange( + workInProgress, + context, + changedBits, + renderExpirationTime + ); + } + } + + var newChildren = newProps.children; + reconcileChildren( + current$$1, + workInProgress, + newChildren, + renderExpirationTime + ); + return workInProgress.child; +} + +var hasWarnedAboutUsingContextAsConsumer = false; + +function updateContextConsumer( + current$$1, + workInProgress, + renderExpirationTime +) { + var context = workInProgress.type; + // The logic below for Context differs depending on PROD or DEV mode. In + // DEV mode, we create a separate object for Context.Consumer that acts + // like a proxy to Context. This proxy object adds unnecessary code in PROD + // so we use the old behaviour (Context.Consumer references Context) to + // reduce size and overhead. The separate object references context via + // a property called "_context", which also gives us the ability to check + // in DEV mode if this property exists or not and warn if it does not. + { + if (context._context === undefined) { + // This may be because it's a Context (rather than a Consumer). + // Or it may be because it's older React where they're the same thing. + // We only want to warn if we're sure it's a new React. + if (context !== context.Consumer) { + if (!hasWarnedAboutUsingContextAsConsumer) { + hasWarnedAboutUsingContextAsConsumer = true; + warning$1( + false, + "Rendering directly is not supported and will be removed in " + + "a future major release. Did you mean to render instead?" + ); + } + } + } else { + context = context._context; + } + } + var newProps = workInProgress.pendingProps; + var render = newProps.children; + + { + !(typeof render === "function") + ? warningWithoutStack$1( + false, + "A context consumer was rendered with multiple children, or a child " + + "that isn't a function. A context consumer expects a single child " + + "that is a function. If you did pass a function, make sure there " + + "is no trailing or leading whitespace around it." + ) + : void 0; + } + + prepareToReadContext(workInProgress, renderExpirationTime); + var newValue = readContext(context, newProps.unstable_observedBits); + var newChildren = void 0; + { + ReactCurrentOwner$3.current = workInProgress; + setCurrentPhase("render"); + newChildren = render(newValue); + setCurrentPhase(null); + } + + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + reconcileChildren( + current$$1, + workInProgress, + newChildren, + renderExpirationTime + ); + return workInProgress.child; +} + +function updateEventComponent$1( + current$$1, + workInProgress, + renderExpirationTime +) { + var nextProps = workInProgress.pendingProps; + var nextChildren = nextProps.children; + + reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + pushHostContextForEventComponent(workInProgress); + return workInProgress.child; +} + +function updateEventTarget(current$$1, workInProgress, renderExpirationTime) { + var type = workInProgress.type.type; + var nextProps = workInProgress.pendingProps; + var eventTargetChild = getEventTargetChildElement(type, nextProps); + + { + !(nextProps.children == null) + ? warning$1(false, "Event targets should not have children.") + : void 0; + } + if (eventTargetChild !== null) { + var child = (workInProgress.child = createFiberFromTypeAndProps( + eventTargetChild.type, + null, + eventTargetChild.props, + null, + workInProgress.mode, + renderExpirationTime + )); + child.return = workInProgress; + + if (current$$1 === null || current$$1.child === null) { + child.effectTag = Placement; + } + } else { + reconcileChildren(current$$1, workInProgress, null, renderExpirationTime); + } + pushHostContextForEventTarget(workInProgress); + return workInProgress.child; +} + +function markWorkInProgressReceivedUpdate() { + didReceiveUpdate = true; +} + +function bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime +) { + cancelWorkTimer(workInProgress); + + if (current$$1 !== null) { + // Reuse previous context list + workInProgress.contextDependencies = current$$1.contextDependencies; + } + + if (enableProfilerTimer) { + // Don't update "base" render times for bailouts. + stopProfilerTimerIfRunning(workInProgress); + } + + // Check if the children have any pending work. + var childExpirationTime = workInProgress.childExpirationTime; + if (childExpirationTime < renderExpirationTime) { + // The children don't have any work either. We can skip them. + // TODO: Once we add back resuming, we should check if the children are + // a work-in-progress set. If so, we need to transfer their effects. + return null; + } else { + // This fiber doesn't have work, but its subtree does. Clone the child + // fibers and continue. + cloneChildFibers(current$$1, workInProgress); + return workInProgress.child; + } +} + +function beginWork$1(current$$1, workInProgress, renderExpirationTime) { + var updateExpirationTime = workInProgress.expirationTime; + + if (current$$1 !== null) { + var oldProps = current$$1.memoizedProps; + var newProps = workInProgress.pendingProps; + + if (oldProps !== newProps || hasContextChanged()) { + // If props or context changed, mark the fiber as having performed work. + // This may be unset if the props are determined to be equal later (memo). + didReceiveUpdate = true; + } else if (updateExpirationTime < renderExpirationTime) { + didReceiveUpdate = false; + // This fiber does not have any pending work. Bailout without entering + // the begin phase. There's still some bookkeeping we that needs to be done + // in this optimized path, mostly pushing stuff onto the stack. + switch (workInProgress.tag) { + case HostRoot: + pushHostRootContext(workInProgress); + resetHydrationState(); + break; + case HostComponent: + pushHostContext(workInProgress); + break; + case ClassComponent: { + var Component = workInProgress.type; + if (isContextProvider(Component)) { + pushContextProvider(workInProgress); + } + break; + } + case HostPortal: + pushHostContainer( + workInProgress, + workInProgress.stateNode.containerInfo + ); + break; + case ContextProvider: { + var newValue = workInProgress.memoizedProps.value; + pushProvider(workInProgress, newValue); + break; + } + case Profiler: + if (enableProfilerTimer) { + workInProgress.effectTag |= Update; + } + break; + case SuspenseComponent: { + var state = workInProgress.memoizedState; + var didTimeout = state !== null; + if (didTimeout) { + // If this boundary is currently timed out, we need to decide + // whether to retry the primary children, or to skip over it and + // go straight to the fallback. Check the priority of the primary + var primaryChildFragment = workInProgress.child; + var primaryChildExpirationTime = + primaryChildFragment.childExpirationTime; + if ( + primaryChildExpirationTime !== NoWork && + primaryChildExpirationTime >= renderExpirationTime + ) { + // The primary children have pending work. Use the normal path + // to attempt to render the primary children again. + return updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + } else { + // The primary children do not have pending work with sufficient + // priority. Bailout. + var child = bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + if (child !== null) { + // The fallback children have pending work. Skip over the + // primary children and work on the fallback. + return child.sibling; + } else { + return null; + } + } + } + break; + } + case DehydratedSuspenseComponent: { + if (enableSuspenseServerRenderer) { + // We know that this component will suspend again because if it has + // been unsuspended it has committed as a regular Suspense component. + // If it needs to be retried, it should have work scheduled on it. + workInProgress.effectTag |= DidCapture; + } + break; + } + case EventComponent: + if (enableEventAPI) { + pushHostContextForEventComponent(workInProgress); + } + break; + case EventTarget: { + if (enableEventAPI) { + pushHostContextForEventTarget(workInProgress); + } + break; + } + } + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + } else { + didReceiveUpdate = false; + } + + // Before entering the begin phase, clear the expiration time. + workInProgress.expirationTime = NoWork; + + switch (workInProgress.tag) { + case IndeterminateComponent: { + var elementType = workInProgress.elementType; + return mountIndeterminateComponent( + current$$1, + workInProgress, + elementType, + renderExpirationTime + ); + } + case LazyComponent: { + var _elementType = workInProgress.elementType; + return mountLazyComponent( + current$$1, + workInProgress, + _elementType, + updateExpirationTime, + renderExpirationTime + ); + } + case FunctionComponent: { + var _Component = workInProgress.type; + var unresolvedProps = workInProgress.pendingProps; + var resolvedProps = + workInProgress.elementType === _Component + ? unresolvedProps + : resolveDefaultProps(_Component, unresolvedProps); + return updateFunctionComponent( + current$$1, + workInProgress, + _Component, + resolvedProps, + renderExpirationTime + ); + } + case ClassComponent: { + var _Component2 = workInProgress.type; + var _unresolvedProps = workInProgress.pendingProps; + var _resolvedProps = + workInProgress.elementType === _Component2 + ? _unresolvedProps + : resolveDefaultProps(_Component2, _unresolvedProps); + return updateClassComponent( + current$$1, + workInProgress, + _Component2, + _resolvedProps, + renderExpirationTime + ); + } + case HostRoot: + return updateHostRoot(current$$1, workInProgress, renderExpirationTime); + case HostComponent: + return updateHostComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + case HostText: + return updateHostText(current$$1, workInProgress); + case SuspenseComponent: + return updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + case HostPortal: + return updatePortalComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + case ForwardRef: { + var type = workInProgress.type; + var _unresolvedProps2 = workInProgress.pendingProps; + var _resolvedProps2 = + workInProgress.elementType === type + ? _unresolvedProps2 + : resolveDefaultProps(type, _unresolvedProps2); + return updateForwardRef( + current$$1, + workInProgress, + type, + _resolvedProps2, + renderExpirationTime + ); + } + case Fragment: + return updateFragment(current$$1, workInProgress, renderExpirationTime); + case Mode: + return updateMode(current$$1, workInProgress, renderExpirationTime); + case Profiler: + return updateProfiler(current$$1, workInProgress, renderExpirationTime); + case ContextProvider: + return updateContextProvider( + current$$1, + workInProgress, + renderExpirationTime + ); + case ContextConsumer: + return updateContextConsumer( + current$$1, + workInProgress, + renderExpirationTime + ); + case MemoComponent: { + var _type2 = workInProgress.type; + var _unresolvedProps3 = workInProgress.pendingProps; + // Resolve outer props first, then resolve inner props. + var _resolvedProps3 = resolveDefaultProps(_type2, _unresolvedProps3); + { + if (workInProgress.type !== workInProgress.elementType) { + var outerPropTypes = _type2.propTypes; + if (outerPropTypes) { + checkPropTypes( + outerPropTypes, + _resolvedProps3, // Resolved for outer only + "prop", + getComponentName(_type2), + getCurrentFiberStackInDev + ); + } + } + } + _resolvedProps3 = resolveDefaultProps(_type2.type, _resolvedProps3); + return updateMemoComponent( + current$$1, + workInProgress, + _type2, + _resolvedProps3, + updateExpirationTime, + renderExpirationTime + ); + } + case SimpleMemoComponent: { + return updateSimpleMemoComponent( + current$$1, + workInProgress, + workInProgress.type, + workInProgress.pendingProps, + updateExpirationTime, + renderExpirationTime + ); + } + case IncompleteClassComponent: { + var _Component3 = workInProgress.type; + var _unresolvedProps4 = workInProgress.pendingProps; + var _resolvedProps4 = + workInProgress.elementType === _Component3 + ? _unresolvedProps4 + : resolveDefaultProps(_Component3, _unresolvedProps4); + return mountIncompleteClassComponent( + current$$1, + workInProgress, + _Component3, + _resolvedProps4, + renderExpirationTime + ); + } + case DehydratedSuspenseComponent: { + if (enableSuspenseServerRenderer) { + return updateDehydratedSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + } + break; + } + case EventComponent: { + if (enableEventAPI) { + return updateEventComponent$1( + current$$1, + workInProgress, + renderExpirationTime + ); + } + break; + } + case EventTarget: { + if (enableEventAPI) { + return updateEventTarget( + current$$1, + workInProgress, + renderExpirationTime + ); + } + break; + } + } + (function() { + { + throw ReactError( + "Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); +} + +function markUpdate(workInProgress) { + // Tag the fiber with an update effect. This turns a Placement into + // a PlacementAndUpdate. + workInProgress.effectTag |= Update; +} + +function markRef$1(workInProgress) { + workInProgress.effectTag |= Ref; +} + +var appendAllChildren = void 0; +var updateHostContainer = void 0; +var updateHostComponent$1 = void 0; +var updateHostText$1 = void 0; +if (supportsMutation) { + // Mutation mode + + appendAllChildren = function( + parent, + workInProgress, + needsVisibilityToggle, + isHidden + ) { + // We only have the top Fiber that was created but we need recurse down its + // children to find all the terminal nodes. + var node = workInProgress.child; + while (node !== null) { + if (node.tag === HostComponent || node.tag === HostText) { + appendInitialChild(parent, node.stateNode); + } else if (node.tag === HostPortal) { + // If we have a portal child, then we don't want to traverse + // down its children. Instead, we'll get insertions from each child in + // the portal directly. + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } + if (node === workInProgress) { + return; + } + while (node.sibling === null) { + if (node.return === null || node.return === workInProgress) { + return; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + }; + + updateHostContainer = function(workInProgress) { + // Noop + }; + updateHostComponent$1 = function( + current, + workInProgress, + type, + newProps, + rootContainerInstance + ) { + // If we have an alternate, that means this is an update and we need to + // schedule a side-effect to do the updates. + var oldProps = current.memoizedProps; + if (oldProps === newProps) { + // In mutation mode, this is sufficient for a bailout because + // we won't touch this node even if children changed. + return; + } + + // If we get updated because one of our children updated, we don't + // have newProps so we'll have to reuse them. + // TODO: Split the update API as separate for the props vs. children. + // Even better would be if children weren't special cased at all tho. + var instance = workInProgress.stateNode; + var currentHostContext = getHostContext(); + // TODO: Experiencing an error where oldProps is null. Suggests a host + // component is hitting the resume path. Figure out why. Possibly + // related to `hidden`. + var updatePayload = prepareUpdate( + instance, + type, + oldProps, + newProps, + rootContainerInstance, + currentHostContext + ); + // TODO: Type this specific to this type of component. + workInProgress.updateQueue = updatePayload; + // If the update payload indicates that there is a change or if there + // is a new ref we mark this as an update. All the work is done in commitWork. + if (updatePayload) { + markUpdate(workInProgress); + } + }; + updateHostText$1 = function(current, workInProgress, oldText, newText) { + // If the text differs, mark it as an update. All the work in done in commitWork. + if (oldText !== newText) { + markUpdate(workInProgress); + } + }; +} else if (supportsPersistence) { + // Persistent host tree mode + + appendAllChildren = function( + parent, + workInProgress, + needsVisibilityToggle, + isHidden + ) { + // We only have the top Fiber that was created but we need recurse down its + // children to find all the terminal nodes. + var node = workInProgress.child; + while (node !== null) { + // eslint-disable-next-line no-labels + branches: if (node.tag === HostComponent) { + var instance = node.stateNode; + if (needsVisibilityToggle && isHidden) { + // This child is inside a timed out tree. Hide it. + var props = node.memoizedProps; + var type = node.type; + instance = cloneHiddenInstance(instance, type, props, node); + } + appendInitialChild(parent, instance); + } else if (node.tag === HostText) { + var _instance = node.stateNode; + if (needsVisibilityToggle && isHidden) { + // This child is inside a timed out tree. Hide it. + var text = node.memoizedProps; + _instance = cloneHiddenTextInstance(_instance, text, node); + } + appendInitialChild(parent, _instance); + } else if (node.tag === HostPortal) { + // If we have a portal child, then we don't want to traverse + // down its children. Instead, we'll get insertions from each child in + // the portal directly. + } else if (node.tag === SuspenseComponent) { + if ((node.effectTag & Update) !== NoEffect) { + // Need to toggle the visibility of the primary children. + var newIsHidden = node.memoizedState !== null; + if (newIsHidden) { + var primaryChildParent = node.child; + if (primaryChildParent !== null) { + if (primaryChildParent.child !== null) { + primaryChildParent.child.return = primaryChildParent; + appendAllChildren( + parent, + primaryChildParent, + true, + newIsHidden + ); + } + var fallbackChildParent = primaryChildParent.sibling; + if (fallbackChildParent !== null) { + fallbackChildParent.return = node; + node = fallbackChildParent; + continue; + } + } + } + } + if (node.child !== null) { + // Continue traversing like normal + node.child.return = node; + node = node.child; + continue; + } + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } + // $FlowFixMe This is correct but Flow is confused by the labeled break. + node = node; + if (node === workInProgress) { + return; + } + while (node.sibling === null) { + if (node.return === null || node.return === workInProgress) { + return; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + }; + + // An unfortunate fork of appendAllChildren because we have two different parent types. + var appendAllChildrenToContainer = function( + containerChildSet, + workInProgress, + needsVisibilityToggle, + isHidden + ) { + // We only have the top Fiber that was created but we need recurse down its + // children to find all the terminal nodes. + var node = workInProgress.child; + while (node !== null) { + // eslint-disable-next-line no-labels + branches: if (node.tag === HostComponent) { + var instance = node.stateNode; + if (needsVisibilityToggle && isHidden) { + // This child is inside a timed out tree. Hide it. + var props = node.memoizedProps; + var type = node.type; + instance = cloneHiddenInstance(instance, type, props, node); + } + appendChildToContainerChildSet(containerChildSet, instance); + } else if (node.tag === HostText) { + var _instance2 = node.stateNode; + if (needsVisibilityToggle && isHidden) { + // This child is inside a timed out tree. Hide it. + var text = node.memoizedProps; + _instance2 = cloneHiddenTextInstance(_instance2, text, node); + } + appendChildToContainerChildSet(containerChildSet, _instance2); + } else if (node.tag === HostPortal) { + // If we have a portal child, then we don't want to traverse + // down its children. Instead, we'll get insertions from each child in + // the portal directly. + } else if (node.tag === SuspenseComponent) { + if ((node.effectTag & Update) !== NoEffect) { + // Need to toggle the visibility of the primary children. + var newIsHidden = node.memoizedState !== null; + if (newIsHidden) { + var primaryChildParent = node.child; + if (primaryChildParent !== null) { + if (primaryChildParent.child !== null) { + primaryChildParent.child.return = primaryChildParent; + appendAllChildrenToContainer( + containerChildSet, + primaryChildParent, + true, + newIsHidden + ); + } + var fallbackChildParent = primaryChildParent.sibling; + if (fallbackChildParent !== null) { + fallbackChildParent.return = node; + node = fallbackChildParent; + continue; + } + } + } + } + if (node.child !== null) { + // Continue traversing like normal + node.child.return = node; + node = node.child; + continue; + } + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } + // $FlowFixMe This is correct but Flow is confused by the labeled break. + node = node; + if (node === workInProgress) { + return; + } + while (node.sibling === null) { + if (node.return === null || node.return === workInProgress) { + return; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + }; + updateHostContainer = function(workInProgress) { + var portalOrRoot = workInProgress.stateNode; + var childrenUnchanged = workInProgress.firstEffect === null; + if (childrenUnchanged) { + // No changes, just reuse the existing instance. + } else { + var container = portalOrRoot.containerInfo; + var newChildSet = createContainerChildSet(container); + // If children might have changed, we have to add them all to the set. + appendAllChildrenToContainer(newChildSet, workInProgress, false, false); + portalOrRoot.pendingChildren = newChildSet; + // Schedule an update on the container to swap out the container. + markUpdate(workInProgress); + finalizeContainerChildren(container, newChildSet); + } + }; + updateHostComponent$1 = function( + current, + workInProgress, + type, + newProps, + rootContainerInstance + ) { + var currentInstance = current.stateNode; + var oldProps = current.memoizedProps; + // If there are no effects associated with this node, then none of our children had any updates. + // This guarantees that we can reuse all of them. + var childrenUnchanged = workInProgress.firstEffect === null; + if (childrenUnchanged && oldProps === newProps) { + // No changes, just reuse the existing instance. + // Note that this might release a previous clone. + workInProgress.stateNode = currentInstance; + return; + } + var recyclableInstance = workInProgress.stateNode; + var currentHostContext = getHostContext(); + var updatePayload = null; + if (oldProps !== newProps) { + updatePayload = prepareUpdate( + recyclableInstance, + type, + oldProps, + newProps, + rootContainerInstance, + currentHostContext + ); + } + if (childrenUnchanged && updatePayload === null) { + // No changes, just reuse the existing instance. + // Note that this might release a previous clone. + workInProgress.stateNode = currentInstance; + return; + } + var newInstance = cloneInstance( + currentInstance, + updatePayload, + type, + oldProps, + newProps, + workInProgress, + childrenUnchanged, + recyclableInstance + ); + if ( + finalizeInitialChildren( + newInstance, + type, + newProps, + rootContainerInstance, + currentHostContext + ) + ) { + markUpdate(workInProgress); + } + workInProgress.stateNode = newInstance; + if (childrenUnchanged) { + // If there are no other effects in this tree, we need to flag this node as having one. + // Even though we're not going to use it for anything. + // Otherwise parents won't know that there are new children to propagate upwards. + markUpdate(workInProgress); + } else { + // If children might have changed, we have to add them all to the set. + appendAllChildren(newInstance, workInProgress, false, false); + } + }; + updateHostText$1 = function(current, workInProgress, oldText, newText) { + if (oldText !== newText) { + // If the text content differs, we'll create a new text instance for it. + var rootContainerInstance = getRootHostContainer(); + var currentHostContext = getHostContext(); + workInProgress.stateNode = createTextInstance( + newText, + rootContainerInstance, + currentHostContext, + workInProgress + ); + // We'll have to mark it as having an effect, even though we won't use the effect for anything. + // This lets the parents know that at least one of their children has changed. + markUpdate(workInProgress); + } + }; +} else { + // No host operations + updateHostContainer = function(workInProgress) { + // Noop + }; + updateHostComponent$1 = function( + current, + workInProgress, + type, + newProps, + rootContainerInstance + ) { + // Noop + }; + updateHostText$1 = function(current, workInProgress, oldText, newText) { + // Noop + }; +} + +function completeWork(current, workInProgress, renderExpirationTime) { + var newProps = workInProgress.pendingProps; + + switch (workInProgress.tag) { + case IndeterminateComponent: + break; + case LazyComponent: + break; + case SimpleMemoComponent: + case FunctionComponent: + break; + case ClassComponent: { + var Component = workInProgress.type; + if (isContextProvider(Component)) { + popContext(workInProgress); + } + break; + } + case HostRoot: { + popHostContainer(workInProgress); + popTopLevelContextObject(workInProgress); + var fiberRoot = workInProgress.stateNode; + if (fiberRoot.pendingContext) { + fiberRoot.context = fiberRoot.pendingContext; + fiberRoot.pendingContext = null; + } + if (current === null || current.child === null) { + // If we hydrated, pop so that we can delete any remaining children + // that weren't hydrated. + popHydrationState(workInProgress); + // This resets the hacky state to fix isMounted before committing. + // TODO: Delete this when we delete isMounted and findDOMNode. + workInProgress.effectTag &= ~Placement; + } + updateHostContainer(workInProgress); + break; + } + case HostComponent: { + popHostContext(workInProgress); + var rootContainerInstance = getRootHostContainer(); + var type = workInProgress.type; + if (current !== null && workInProgress.stateNode != null) { + updateHostComponent$1( + current, + workInProgress, + type, + newProps, + rootContainerInstance + ); + + if (current.ref !== workInProgress.ref) { + markRef$1(workInProgress); + } + } else { + if (!newProps) { + (function() { + if (!(workInProgress.stateNode !== null)) { + throw ReactError( + "We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + // This can happen when we abort work. + break; + } + + var currentHostContext = getHostContext(); + // TODO: Move createInstance to beginWork and keep it on a context + // "stack" as the parent. Then append children as we go in beginWork + // or completeWork depending on we want to add then top->down or + // bottom->up. Top->down is faster in IE11. + var wasHydrated = popHydrationState(workInProgress); + if (wasHydrated) { + // TODO: Move this and createInstance step into the beginPhase + // to consolidate. + if ( + prepareToHydrateHostInstance( + workInProgress, + rootContainerInstance, + currentHostContext + ) + ) { + // If changes to the hydrated node needs to be applied at the + // commit-phase we mark this as such. + markUpdate(workInProgress); + } + } else { + var instance = createInstance( + type, + newProps, + rootContainerInstance, + currentHostContext, + workInProgress + ); + + appendAllChildren(instance, workInProgress, false, false); + + // Certain renderers require commit-time effects for initial mount. + // (eg DOM renderer supports auto-focus for certain elements). + // Make sure such renderers get scheduled for later work. + if ( + finalizeInitialChildren( + instance, + type, + newProps, + rootContainerInstance, + currentHostContext + ) + ) { + markUpdate(workInProgress); + } + workInProgress.stateNode = instance; + } + + if (workInProgress.ref !== null) { + // If there is a ref on a host node we need to schedule a callback + markRef$1(workInProgress); + } + } + break; + } + case HostText: { + var newText = newProps; + if (current && workInProgress.stateNode != null) { + var oldText = current.memoizedProps; + // If we have an alternate, that means this is an update and we need + // to schedule a side-effect to do the updates. + updateHostText$1(current, workInProgress, oldText, newText); + } else { + if (typeof newText !== "string") { + (function() { + if (!(workInProgress.stateNode !== null)) { + throw ReactError( + "We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + // This can happen when we abort work. + } + var _rootContainerInstance = getRootHostContainer(); + var _currentHostContext = getHostContext(); + var _wasHydrated = popHydrationState(workInProgress); + if (_wasHydrated) { + if (prepareToHydrateHostTextInstance(workInProgress)) { + markUpdate(workInProgress); + } + } else { + workInProgress.stateNode = createTextInstance( + newText, + _rootContainerInstance, + _currentHostContext, + workInProgress + ); + } + } + break; + } + case ForwardRef: + break; + case SuspenseComponent: { + var nextState = workInProgress.memoizedState; + if ((workInProgress.effectTag & DidCapture) !== NoEffect) { + // Something suspended. Re-render with the fallback children. + workInProgress.expirationTime = renderExpirationTime; + // Do not reset the effect list. + return workInProgress; + } + + var nextDidTimeout = nextState !== null; + var prevDidTimeout = false; + if (current === null) { + // In cases where we didn't find a suitable hydration boundary we never + // downgraded this to a DehydratedSuspenseComponent, but we still need to + // pop the hydration state since we might be inside the insertion tree. + popHydrationState(workInProgress); + } else { + var prevState = current.memoizedState; + prevDidTimeout = prevState !== null; + if (!nextDidTimeout && prevState !== null) { + // We just switched from the fallback to the normal children. + + // Mark the event time of the switching from fallback to normal children, + // based on the start of when we first showed the fallback. This time + var fallbackExpirationTime = prevState.fallbackExpirationTime; + markRenderEventTime(fallbackExpirationTime); + + // Delete the fallback. + // TODO: Would it be better to store the fallback fragment on + // the stateNode during the begin phase? + var currentFallbackChild = current.child.sibling; + if (currentFallbackChild !== null) { + // Deletions go at the beginning of the return fiber's effect list + var first = workInProgress.firstEffect; + if (first !== null) { + workInProgress.firstEffect = currentFallbackChild; + currentFallbackChild.nextEffect = first; + } else { + workInProgress.firstEffect = workInProgress.lastEffect = currentFallbackChild; + currentFallbackChild.nextEffect = null; + } + currentFallbackChild.effectTag = Deletion; + } + } + } + + if (nextDidTimeout && !prevDidTimeout) { + // If this subtreee is running in concurrent mode we can suspend, + // otherwise we won't suspend. + // TODO: This will still suspend a synchronous tree if anything + // in the concurrent tree already suspended during this render. + // This is a known bug. + if ((workInProgress.mode & ConcurrentMode) !== NoContext) { + renderDidSuspend(); + } + } + + if (supportsPersistence) { + // TODO: Only schedule updates if not prevDidTimeout. + if (nextDidTimeout) { + // If this boundary just timed out, schedule an effect to attach a + // retry listener to the proimse. This flag is also used to hide the + // primary children. + workInProgress.effectTag |= Update; + } + } + if (supportsMutation) { + // TODO: Only schedule updates if these values are non equal, i.e. it changed. + if (nextDidTimeout || prevDidTimeout) { + // If this boundary just timed out, schedule an effect to attach a + // retry listener to the proimse. This flag is also used to hide the + // primary children. In mutation mode, we also need the flag to + // *unhide* children that were previously hidden, so check if the + // is currently timed out, too. + workInProgress.effectTag |= Update; + } + } + break; + } + case Fragment: + break; + case Mode: + break; + case Profiler: + break; + case HostPortal: + popHostContainer(workInProgress); + updateHostContainer(workInProgress); + break; + case ContextProvider: + // Pop provider fiber + popProvider(workInProgress); + break; + case ContextConsumer: + break; + case MemoComponent: + break; + case IncompleteClassComponent: { + // Same as class component case. I put it down here so that the tags are + // sequential to ensure this switch is compiled to a jump table. + var _Component = workInProgress.type; + if (isContextProvider(_Component)) { + popContext(workInProgress); + } + break; + } + case DehydratedSuspenseComponent: { + if (enableSuspenseServerRenderer) { + if (current === null) { + var _wasHydrated2 = popHydrationState(workInProgress); + (function() { + if (!_wasHydrated2) { + throw ReactError( + "A dehydrated suspense component was completed without a hydrated node. This is probably a bug in React." + ); + } + })(); + skipPastDehydratedSuspenseInstance(workInProgress); + } else if ((workInProgress.effectTag & DidCapture) === NoEffect) { + // This boundary did not suspend so it's now hydrated. + // To handle any future suspense cases, we're going to now upgrade it + // to a Suspense component. We detach it from the existing current fiber. + current.alternate = null; + workInProgress.alternate = null; + workInProgress.tag = SuspenseComponent; + workInProgress.memoizedState = null; + workInProgress.stateNode = null; + } + } + break; + } + case EventComponent: { + if (enableEventAPI) { + popHostContext(workInProgress); + var _rootContainerInstance2 = getRootHostContainer(); + var responder = workInProgress.type.responder; + var eventComponentInstance = workInProgress.stateNode; + + if (eventComponentInstance === null) { + var responderState = null; + if (responder.createInitialState !== undefined) { + responderState = responder.createInitialState(newProps); + } + eventComponentInstance = workInProgress.stateNode = { + currentFiber: workInProgress, + props: newProps, + responder: responder, + rootEventTypes: null, + rootInstance: _rootContainerInstance2, + state: responderState + }; + markUpdate(workInProgress); + } else { + // Update the props on the event component state node + eventComponentInstance.props = newProps; + // Update the root container, so we can properly unmount events at some point + eventComponentInstance.rootInstance = _rootContainerInstance2; + // Update the current fiber + eventComponentInstance.currentFiber = workInProgress; + updateEventComponent(eventComponentInstance); + } + } + break; + } + case EventTarget: { + if (enableEventAPI) { + popHostContext(workInProgress); + var _type = workInProgress.type.type; + var _rootContainerInstance3 = getRootHostContainer(); + var shouldUpdate = handleEventTarget( + _type, + newProps, + _rootContainerInstance3, + workInProgress + ); + // Update the latest props on the stateNode. This is used + // during the event phase to find the most current props. + workInProgress.stateNode.props = newProps; + if (shouldUpdate) { + markUpdate(workInProgress); + } + } + break; + } + default: + (function() { + { + throw ReactError( + "Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + + return null; +} + +function shouldCaptureSuspense(workInProgress) { + // In order to capture, the Suspense component must have a fallback prop. + if (workInProgress.memoizedProps.fallback === undefined) { + return false; + } + // If it was the primary children that just suspended, capture and render the + // fallback. Otherwise, don't capture and bubble to the next boundary. + var nextState = workInProgress.memoizedState; + return nextState === null; +} + +function createCapturedValue(value, source) { + // If the value is an error, call this function immediately after it is thrown + // so the stack is accurate. + return { + value: value, + source: source, + stack: getStackByFiberInDevAndProd(source) + }; +} + +// Module provided by RN: +/** + * Intercept lifecycle errors and ensure they are shown with the correct stack + * trace within the native redbox component. + */ +function showErrorDialog(capturedError) { + var componentStack = capturedError.componentStack, + error = capturedError.error; + + var errorToHandle = void 0; + + // Typically Errors are thrown but eg strings or null can be thrown as well. + if (error instanceof Error) { + var message = error.message, + name = error.name; + + var summary = message ? name + ": " + message : name; + + errorToHandle = error; + + try { + errorToHandle.message = + summary + "\n\nThis error is located at:" + componentStack; + } catch (e) {} + } else if (typeof error === "string") { + errorToHandle = new Error( + error + "\n\nThis error is located at:" + componentStack + ); + } else { + errorToHandle = new Error("Unspecified error at:" + componentStack); + } + + ReactNativePrivateInterface.ExceptionsManager.handleException( + errorToHandle, + false + ); + + // Return false here to prevent ReactFiberErrorLogger default behavior of + // logging error details to console.error. Calls to console.error are + // automatically routed to the native redbox controller, which we've already + // done above by calling ExceptionsManager. + return false; +} + +function logCapturedError(capturedError) { + var logError = showErrorDialog(capturedError); + + // Allow injected showErrorDialog() to prevent default console.error logging. + // This enables renderers like ReactNative to better manage redbox behavior. + if (logError === false) { + return; + } + + var error = capturedError.error; + { + var componentName = capturedError.componentName, + componentStack = capturedError.componentStack, + errorBoundaryName = capturedError.errorBoundaryName, + errorBoundaryFound = capturedError.errorBoundaryFound, + willRetry = capturedError.willRetry; + + // Browsers support silencing uncaught errors by calling + // `preventDefault()` in window `error` handler. + // We record this information as an expando on the error. + + if (error != null && error._suppressLogging) { + if (errorBoundaryFound && willRetry) { + // The error is recoverable and was silenced. + // Ignore it and don't print the stack addendum. + // This is handy for testing error boundaries without noise. + return; + } + // The error is fatal. Since the silencing might have + // been accidental, we'll surface it anyway. + // However, the browser would have silenced the original error + // so we'll print it first, and then print the stack addendum. + console.error(error); + // For a more detailed description of this block, see: + // https://github.com/facebook/react/pull/13384 + } + + var componentNameMessage = componentName + ? "The above error occurred in the <" + componentName + "> component:" + : "The above error occurred in one of your React components:"; + + var errorBoundaryMessage = void 0; + // errorBoundaryFound check is sufficient; errorBoundaryName check is to satisfy Flow. + if (errorBoundaryFound && errorBoundaryName) { + if (willRetry) { + errorBoundaryMessage = + "React will try to recreate this component tree from scratch " + + ("using the error boundary you provided, " + errorBoundaryName + "."); + } else { + errorBoundaryMessage = + "This error was initially handled by the error boundary " + + errorBoundaryName + + ".\n" + + "Recreating the tree from scratch failed so React will unmount the tree."; + } + } else { + errorBoundaryMessage = + "Consider adding an error boundary to your tree to customize error handling behavior.\n" + + "Visit https://fb.me/react-error-boundaries to learn more about error boundaries."; + } + var combinedMessage = + "" + + componentNameMessage + + componentStack + + "\n\n" + + ("" + errorBoundaryMessage); + + // In development, we provide our own message with just the component stack. + // We don't include the original error message and JS stack because the browser + // has already printed it. Even if the application swallows the error, it is still + // displayed by the browser thanks to the DEV-only fake event trick in ReactErrorUtils. + console.error(combinedMessage); + } +} + +var didWarnAboutUndefinedSnapshotBeforeUpdate = null; +{ + didWarnAboutUndefinedSnapshotBeforeUpdate = new Set(); +} + +var PossiblyWeakSet$1 = typeof WeakSet === "function" ? WeakSet : Set; + +function logError(boundary, errorInfo) { + var source = errorInfo.source; + var stack = errorInfo.stack; + if (stack === null && source !== null) { + stack = getStackByFiberInDevAndProd(source); + } + + var capturedError = { + componentName: source !== null ? getComponentName(source.type) : null, + componentStack: stack !== null ? stack : "", + error: errorInfo.value, + errorBoundary: null, + errorBoundaryName: null, + errorBoundaryFound: false, + willRetry: false + }; + + if (boundary !== null && boundary.tag === ClassComponent) { + capturedError.errorBoundary = boundary.stateNode; + capturedError.errorBoundaryName = getComponentName(boundary.type); + capturedError.errorBoundaryFound = true; + capturedError.willRetry = true; + } + + try { + logCapturedError(capturedError); + } catch (e) { + // This method must not throw, or React internal state will get messed up. + // If console.error is overridden, or logCapturedError() shows a dialog that throws, + // we want to report this error outside of the normal stack as a last resort. + // https://github.com/facebook/react/issues/13188 + setTimeout(function() { + throw e; + }); + } +} + +var callComponentWillUnmountWithTimer = function(current$$1, instance) { + startPhaseTimer(current$$1, "componentWillUnmount"); + instance.props = current$$1.memoizedProps; + instance.state = current$$1.memoizedState; + instance.componentWillUnmount(); + stopPhaseTimer(); +}; + +// Capture errors so they don't interrupt unmounting. +function safelyCallComponentWillUnmount(current$$1, instance) { + { + invokeGuardedCallback( + null, + callComponentWillUnmountWithTimer, + null, + current$$1, + instance + ); + if (hasCaughtError()) { + var unmountError = clearCaughtError(); + captureCommitPhaseError(current$$1, unmountError); + } + } +} + +function safelyDetachRef(current$$1) { + var ref = current$$1.ref; + if (ref !== null) { + if (typeof ref === "function") { + { + invokeGuardedCallback(null, ref, null, null); + if (hasCaughtError()) { + var refError = clearCaughtError(); + captureCommitPhaseError(current$$1, refError); + } + } + } else { + ref.current = null; + } + } +} + +function safelyCallDestroy(current$$1, destroy) { + { + invokeGuardedCallback(null, destroy, null); + if (hasCaughtError()) { + var error = clearCaughtError(); + captureCommitPhaseError(current$$1, error); + } + } +} + +function commitBeforeMutationLifeCycles(current$$1, finishedWork) { + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: { + commitHookEffectList(UnmountSnapshot, NoEffect$1, finishedWork); + return; + } + case ClassComponent: { + if (finishedWork.effectTag & Snapshot) { + if (current$$1 !== null) { + var prevProps = current$$1.memoizedProps; + var prevState = current$$1.memoizedState; + startPhaseTimer(finishedWork, "getSnapshotBeforeUpdate"); + var instance = finishedWork.stateNode; + // We could update instance props and state here, + // but instead we rely on them being set during last render. + // TODO: revisit this when we implement resuming. + { + if ( + finishedWork.type === finishedWork.elementType && + !didWarnAboutReassigningProps + ) { + !(instance.props === finishedWork.memoizedProps) + ? warning$1( + false, + "Expected %s props to match memoized props before " + + "getSnapshotBeforeUpdate. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentName(finishedWork.type) || "instance" + ) + : void 0; + !(instance.state === finishedWork.memoizedState) + ? warning$1( + false, + "Expected %s state to match memoized state before " + + "getSnapshotBeforeUpdate. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentName(finishedWork.type) || "instance" + ) + : void 0; + } + } + var snapshot = instance.getSnapshotBeforeUpdate( + finishedWork.elementType === finishedWork.type + ? prevProps + : resolveDefaultProps(finishedWork.type, prevProps), + prevState + ); + { + var didWarnSet = didWarnAboutUndefinedSnapshotBeforeUpdate; + if (snapshot === undefined && !didWarnSet.has(finishedWork.type)) { + didWarnSet.add(finishedWork.type); + warningWithoutStack$1( + false, + "%s.getSnapshotBeforeUpdate(): A snapshot value (or null) " + + "must be returned. You have returned undefined.", + getComponentName(finishedWork.type) + ); + } + } + instance.__reactInternalSnapshotBeforeUpdate = snapshot; + stopPhaseTimer(); + } + } + return; + } + case HostRoot: + case HostComponent: + case HostText: + case HostPortal: + case IncompleteClassComponent: + case EventTarget: + // Nothing to do for these component types + return; + default: { + (function() { + { + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + } +} + +function commitHookEffectList(unmountTag, mountTag, finishedWork) { + var updateQueue = finishedWork.updateQueue; + var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null; + if (lastEffect !== null) { + var firstEffect = lastEffect.next; + var effect = firstEffect; + do { + if ((effect.tag & unmountTag) !== NoEffect$1) { + // Unmount + var destroy = effect.destroy; + effect.destroy = undefined; + if (destroy !== undefined) { + destroy(); + } + } + if ((effect.tag & mountTag) !== NoEffect$1) { + // Mount + var create = effect.create; + effect.destroy = create(); + + { + var _destroy = effect.destroy; + if (_destroy !== undefined && typeof _destroy !== "function") { + var addendum = void 0; + if (_destroy === null) { + addendum = + " You returned null. If your effect does not require clean " + + "up, return undefined (or nothing)."; + } else if (typeof _destroy.then === "function") { + addendum = + "\n\nIt looks like you wrote useEffect(async () => ...) or returned a Promise. " + + "Instead, write the async function inside your effect " + + "and call it immediately:\n\n" + + "useEffect(() => {\n" + + " async function fetchData() {\n" + + " // You can await here\n" + + " const response = await MyAPI.getData(someId);\n" + + " // ...\n" + + " }\n" + + " fetchData();\n" + + "}, [someId]); // Or [] if effect doesn't need props or state\n\n" + + "Learn more about data fetching with Hooks: https://fb.me/react-hooks-data-fetching"; + } else { + addendum = " You returned: " + _destroy; + } + warningWithoutStack$1( + false, + "An effect function must not return anything besides a function, " + + "which is used for clean-up.%s%s", + addendum, + getStackByFiberInDevAndProd(finishedWork) + ); + } + } + } + effect = effect.next; + } while (effect !== firstEffect); + } +} + +function commitPassiveHookEffects(finishedWork) { + commitHookEffectList(UnmountPassive, NoEffect$1, finishedWork); + commitHookEffectList(NoEffect$1, MountPassive, finishedWork); +} + +function commitLifeCycles( + finishedRoot, + current$$1, + finishedWork, + committedExpirationTime +) { + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: { + commitHookEffectList(UnmountLayout, MountLayout, finishedWork); + break; + } + case ClassComponent: { + var instance = finishedWork.stateNode; + if (finishedWork.effectTag & Update) { + if (current$$1 === null) { + startPhaseTimer(finishedWork, "componentDidMount"); + // We could update instance props and state here, + // but instead we rely on them being set during last render. + // TODO: revisit this when we implement resuming. + { + if ( + finishedWork.type === finishedWork.elementType && + !didWarnAboutReassigningProps + ) { + !(instance.props === finishedWork.memoizedProps) + ? warning$1( + false, + "Expected %s props to match memoized props before " + + "componentDidMount. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentName(finishedWork.type) || "instance" + ) + : void 0; + !(instance.state === finishedWork.memoizedState) + ? warning$1( + false, + "Expected %s state to match memoized state before " + + "componentDidMount. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentName(finishedWork.type) || "instance" + ) + : void 0; + } + } + instance.componentDidMount(); + stopPhaseTimer(); + } else { + var prevProps = + finishedWork.elementType === finishedWork.type + ? current$$1.memoizedProps + : resolveDefaultProps( + finishedWork.type, + current$$1.memoizedProps + ); + var prevState = current$$1.memoizedState; + startPhaseTimer(finishedWork, "componentDidUpdate"); + // We could update instance props and state here, + // but instead we rely on them being set during last render. + // TODO: revisit this when we implement resuming. + { + if ( + finishedWork.type === finishedWork.elementType && + !didWarnAboutReassigningProps + ) { + !(instance.props === finishedWork.memoizedProps) + ? warning$1( + false, + "Expected %s props to match memoized props before " + + "componentDidUpdate. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentName(finishedWork.type) || "instance" + ) + : void 0; + !(instance.state === finishedWork.memoizedState) + ? warning$1( + false, + "Expected %s state to match memoized state before " + + "componentDidUpdate. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentName(finishedWork.type) || "instance" + ) + : void 0; + } + } + instance.componentDidUpdate( + prevProps, + prevState, + instance.__reactInternalSnapshotBeforeUpdate + ); + stopPhaseTimer(); + } + } + var updateQueue = finishedWork.updateQueue; + if (updateQueue !== null) { + { + if ( + finishedWork.type === finishedWork.elementType && + !didWarnAboutReassigningProps + ) { + !(instance.props === finishedWork.memoizedProps) + ? warning$1( + false, + "Expected %s props to match memoized props before " + + "processing the update queue. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentName(finishedWork.type) || "instance" + ) + : void 0; + !(instance.state === finishedWork.memoizedState) + ? warning$1( + false, + "Expected %s state to match memoized state before " + + "processing the update queue. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentName(finishedWork.type) || "instance" + ) + : void 0; + } + } + // We could update instance props and state here, + // but instead we rely on them being set during last render. + // TODO: revisit this when we implement resuming. + commitUpdateQueue( + finishedWork, + updateQueue, + instance, + committedExpirationTime + ); + } + return; + } + case HostRoot: { + var _updateQueue = finishedWork.updateQueue; + if (_updateQueue !== null) { + var _instance = null; + if (finishedWork.child !== null) { + switch (finishedWork.child.tag) { + case HostComponent: + _instance = getPublicInstance(finishedWork.child.stateNode); + break; + case ClassComponent: + _instance = finishedWork.child.stateNode; + break; + } + } + commitUpdateQueue( + finishedWork, + _updateQueue, + _instance, + committedExpirationTime + ); + } + return; + } + case HostComponent: { + var _instance2 = finishedWork.stateNode; + + // Renderers may schedule work to be done after host components are mounted + // (eg DOM renderer may schedule auto-focus for inputs and form controls). + // These effects should only be committed when components are first mounted, + // aka when there is no current/alternate. + if (current$$1 === null && finishedWork.effectTag & Update) { + var type = finishedWork.type; + var props = finishedWork.memoizedProps; + } + + return; + } + case HostText: { + // We have no life-cycles associated with text. + return; + } + case HostPortal: { + // We have no life-cycles associated with portals. + return; + } + case Profiler: { + if (enableProfilerTimer) { + var onRender = finishedWork.memoizedProps.onRender; + + if (enableSchedulerTracing) { + onRender( + finishedWork.memoizedProps.id, + current$$1 === null ? "mount" : "update", + finishedWork.actualDuration, + finishedWork.treeBaseDuration, + finishedWork.actualStartTime, + getCommitTime(), + finishedRoot.memoizedInteractions + ); + } else { + onRender( + finishedWork.memoizedProps.id, + current$$1 === null ? "mount" : "update", + finishedWork.actualDuration, + finishedWork.treeBaseDuration, + finishedWork.actualStartTime, + getCommitTime() + ); + } + } + return; + } + case SuspenseComponent: + case IncompleteClassComponent: + return; + case EventTarget: { + if (enableEventAPI) { + var _type = finishedWork.type.type; + var _props = finishedWork.memoizedProps; + var _instance3 = finishedWork.stateNode; + var parentInstance = null; + + var node = finishedWork.return; + // Traverse up the fiber tree until we find the parent host node. + while (node !== null) { + if (node.tag === HostComponent) { + parentInstance = node.stateNode; + break; + } else if (node.tag === HostRoot) { + parentInstance = node.stateNode.containerInfo; + break; + } + node = node.return; + } + (function() { + if (!(parentInstance !== null)) { + throw ReactError( + "This should have a parent host component initialized. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + commitEventTarget(_type, _props, _instance3, parentInstance); + } + return; + } + case EventComponent: { + if (enableEventAPI) { + mountEventComponent(finishedWork.stateNode); + } + return; + } + default: { + (function() { + { + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + } +} + +function hideOrUnhideAllChildren(finishedWork, isHidden) { + if (supportsMutation) { + // We only have the top Fiber that was inserted but we need to recurse down its + var node = finishedWork; + while (true) { + if (node.tag === HostComponent) { + var instance = node.stateNode; + if (isHidden) { + hideInstance(instance); + } else { + unhideInstance(node.stateNode, node.memoizedProps); + } + } else if (node.tag === HostText) { + var _instance4 = node.stateNode; + if (isHidden) { + hideTextInstance(_instance4); + } else { + unhideTextInstance(_instance4, node.memoizedProps); + } + } else if ( + node.tag === SuspenseComponent && + node.memoizedState !== null + ) { + // Found a nested Suspense component that timed out. Skip over the + var fallbackChildFragment = node.child.sibling; + fallbackChildFragment.return = node; + node = fallbackChildFragment; + continue; + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } + if (node === finishedWork) { + return; + } + while (node.sibling === null) { + if (node.return === null || node.return === finishedWork) { + return; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + } +} + +function commitAttachRef(finishedWork) { + var ref = finishedWork.ref; + if (ref !== null) { + var instance = finishedWork.stateNode; + var instanceToUse = void 0; + switch (finishedWork.tag) { + case HostComponent: + instanceToUse = getPublicInstance(instance); + break; + default: + instanceToUse = instance; + } + if (typeof ref === "function") { + ref(instanceToUse); + } else { + { + if (!ref.hasOwnProperty("current")) { + warningWithoutStack$1( + false, + "Unexpected ref object provided for %s. " + + "Use either a ref-setter function or React.createRef().%s", + getComponentName(finishedWork.type), + getStackByFiberInDevAndProd(finishedWork) + ); + } + } + + ref.current = instanceToUse; + } + } +} + +function commitDetachRef(current$$1) { + var currentRef = current$$1.ref; + if (currentRef !== null) { + if (typeof currentRef === "function") { + currentRef(null); + } else { + currentRef.current = null; + } + } +} + +// User-originating errors (lifecycles and refs) should not interrupt +// deletion, so don't let them throw. Host-originating errors should +// interrupt deletion, so it's okay +function commitUnmount(current$$1) { + onCommitUnmount(current$$1); + + switch (current$$1.tag) { + case FunctionComponent: + case ForwardRef: + case MemoComponent: + case SimpleMemoComponent: { + var updateQueue = current$$1.updateQueue; + if (updateQueue !== null) { + var lastEffect = updateQueue.lastEffect; + if (lastEffect !== null) { + var firstEffect = lastEffect.next; + var effect = firstEffect; + do { + var destroy = effect.destroy; + if (destroy !== undefined) { + safelyCallDestroy(current$$1, destroy); + } + effect = effect.next; + } while (effect !== firstEffect); + } + } + break; + } + case ClassComponent: { + safelyDetachRef(current$$1); + var instance = current$$1.stateNode; + if (typeof instance.componentWillUnmount === "function") { + safelyCallComponentWillUnmount(current$$1, instance); + } + return; + } + case HostComponent: { + safelyDetachRef(current$$1); + return; + } + case HostPortal: { + // TODO: this is recursive. + // We are also not using this parent because + // the portal will get pushed immediately. + if (supportsMutation) { + unmountHostComponents(current$$1); + } else if (supportsPersistence) { + emptyPortalContainer(current$$1); + } + return; + } + case EventComponent: { + if (enableEventAPI) { + var eventComponentInstance = current$$1.stateNode; + unmountEventComponent(eventComponentInstance); + current$$1.stateNode = null; + } + } + } +} + +function commitNestedUnmounts(root) { + // While we're inside a removed host node we don't want to call + // removeChild on the inner nodes because they're removed by the top + // call anyway. We also want to call componentWillUnmount on all + // composites before this host node is removed from the tree. Therefore + var node = root; + while (true) { + commitUnmount(node); + // Visit children because they may contain more composite or host nodes. + // Skip portals because commitUnmount() currently visits them recursively. + if ( + node.child !== null && + // If we use mutation we drill down into portals using commitUnmount above. + // If we don't use mutation we drill down into portals here instead. + (!supportsMutation || node.tag !== HostPortal) + ) { + node.child.return = node; + node = node.child; + continue; + } + if (node === root) { + return; + } + while (node.sibling === null) { + if (node.return === null || node.return === root) { + return; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } +} + +function detachFiber(current$$1) { + // Cut off the return pointers to disconnect it from the tree. Ideally, we + // should clear the child pointer of the parent alternate to let this + // get GC:ed but we don't know which for sure which parent is the current + // one so we'll settle for GC:ing the subtree of this child. This child + // itself will be GC:ed when the parent updates the next time. + current$$1.return = null; + current$$1.child = null; + current$$1.memoizedState = null; + current$$1.updateQueue = null; + var alternate = current$$1.alternate; + if (alternate !== null) { + alternate.return = null; + alternate.child = null; + alternate.memoizedState = null; + alternate.updateQueue = null; + } +} + +function emptyPortalContainer(current$$1) { + if (!supportsPersistence) { + return; + } + + var portal = current$$1.stateNode; + var containerInfo = portal.containerInfo; + + var emptyChildSet = createContainerChildSet(containerInfo); + replaceContainerChildren(containerInfo, emptyChildSet); +} + +function commitContainer(finishedWork) { + if (!supportsPersistence) { + return; + } + + switch (finishedWork.tag) { + case ClassComponent: + case HostComponent: + case HostText: + case EventTarget: + case EventComponent: { + return; + } + case HostRoot: + case HostPortal: { + var portalOrRoot = finishedWork.stateNode; + var containerInfo = portalOrRoot.containerInfo, + _pendingChildren = portalOrRoot.pendingChildren; + + replaceContainerChildren(containerInfo, _pendingChildren); + return; + } + default: { + (function() { + { + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + } +} + +function getHostParentFiber(fiber) { + var parent = fiber.return; + while (parent !== null) { + if (isHostParent(parent)) { + return parent; + } + parent = parent.return; + } + (function() { + { + throw ReactError( + "Expected to find a host parent. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); +} + +function isHostParent(fiber) { + return ( + fiber.tag === HostComponent || + fiber.tag === HostRoot || + fiber.tag === HostPortal + ); +} + +function getHostSibling(fiber) { + // We're going to search forward into the tree until we find a sibling host + // node. Unfortunately, if multiple insertions are done in a row we have to + // search past them. This leads to exponential search for the next sibling. + var node = fiber; + siblings: while (true) { + // If we didn't find anything, let's try the next sibling. + while (node.sibling === null) { + if (node.return === null || isHostParent(node.return)) { + // If we pop out of the root or hit the parent the fiber we are the + // last sibling. + return null; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + while ( + node.tag !== HostComponent && + node.tag !== HostText && + node.tag !== DehydratedSuspenseComponent + ) { + // If it is not host node and, we might have a host node inside it. + // Try to search down until we find one. + if (node.effectTag & Placement) { + // If we don't have a child, try the siblings instead. + continue siblings; + } + // If we don't have a child, try the siblings instead. + // We also skip portals because they are not part of this host tree. + if (node.child === null || node.tag === HostPortal) { + continue siblings; + } else { + node.child.return = node; + node = node.child; + } + } + // Check if this host node is stable or about to be placed. + if (!(node.effectTag & Placement)) { + // Found it! + return node.stateNode; + } + } +} + +function commitPlacement(finishedWork) { + if (!supportsMutation) { + return; + } + + // Recursively insert all host nodes into the parent. + var parentFiber = getHostParentFiber(finishedWork); + + // Note: these two variables *must* always be updated together. + var parent = void 0; + var isContainer = void 0; + + switch (parentFiber.tag) { + case HostComponent: + parent = parentFiber.stateNode; + isContainer = false; + break; + case HostRoot: + parent = parentFiber.stateNode.containerInfo; + isContainer = true; + break; + case HostPortal: + parent = parentFiber.stateNode.containerInfo; + isContainer = true; + break; + default: + (function() { + { + throw ReactError( + "Invalid host parent fiber. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + if (parentFiber.effectTag & ContentReset) { + // Reset the text content of the parent before doing any insertions + parentFiber.effectTag &= ~ContentReset; + } + + var before = getHostSibling(finishedWork); + // We only have the top Fiber that was inserted but we need to recurse down its + // children to find all the terminal nodes. + var node = finishedWork; + while (true) { + if (node.tag === HostComponent || node.tag === HostText) { + var stateNode = node.stateNode; + if (before) { + if (isContainer) { + insertInContainerBefore(parent, stateNode, before); + } else { + insertBefore(parent, stateNode, before); + } + } else { + if (isContainer) { + appendChildToContainer(parent, stateNode); + } else { + appendChild(parent, stateNode); + } + } + } else if (node.tag === HostPortal) { + // If the insertion itself is a portal, then we don't want to traverse + // down its children. Instead, we'll get insertions from each child in + // the portal directly. + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } + if (node === finishedWork) { + return; + } + while (node.sibling === null) { + if (node.return === null || node.return === finishedWork) { + return; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } +} + +function unmountHostComponents(current$$1) { + // We only have the top Fiber that was deleted but we need to recurse down its + var node = current$$1; + + // Each iteration, currentParent is populated with node's host parent if not + // currentParentIsValid. + var currentParentIsValid = false; + + // Note: these two variables *must* always be updated together. + var currentParent = void 0; + var currentParentIsContainer = void 0; + + while (true) { + if (!currentParentIsValid) { + var parent = node.return; + findParent: while (true) { + (function() { + if (!(parent !== null)) { + throw ReactError( + "Expected to find a host parent. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + switch (parent.tag) { + case HostComponent: + currentParent = parent.stateNode; + currentParentIsContainer = false; + break findParent; + case HostRoot: + currentParent = parent.stateNode.containerInfo; + currentParentIsContainer = true; + break findParent; + case HostPortal: + currentParent = parent.stateNode.containerInfo; + currentParentIsContainer = true; + break findParent; + } + parent = parent.return; + } + currentParentIsValid = true; + } + + if (node.tag === HostComponent || node.tag === HostText) { + commitNestedUnmounts(node); + // After all the children have unmounted, it is now safe to remove the + // node from the tree. + if (currentParentIsContainer) { + removeChildFromContainer(currentParent, node.stateNode); + } else { + removeChild(currentParent, node.stateNode); + } + // Don't visit children because we already visited them. + } else if ( + enableSuspenseServerRenderer && + node.tag === DehydratedSuspenseComponent + ) { + // Delete the dehydrated suspense boundary and all of its content. + if (currentParentIsContainer) { + clearSuspenseBoundaryFromContainer(currentParent, node.stateNode); + } else { + clearSuspenseBoundary(currentParent, node.stateNode); + } + } else if (node.tag === HostPortal) { + if (node.child !== null) { + // When we go into a portal, it becomes the parent to remove from. + // We will reassign it back when we pop the portal on the way up. + currentParent = node.stateNode.containerInfo; + currentParentIsContainer = true; + // Visit children because portals might contain host components. + node.child.return = node; + node = node.child; + continue; + } + } else { + commitUnmount(node); + // Visit children because we may find more host components below. + if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } + } + if (node === current$$1) { + return; + } + while (node.sibling === null) { + if (node.return === null || node.return === current$$1) { + return; + } + node = node.return; + if (node.tag === HostPortal) { + // When we go out of the portal, we need to restore the parent. + // Since we don't keep a stack of them, we will search for it. + currentParentIsValid = false; + } + } + node.sibling.return = node.return; + node = node.sibling; + } +} + +function commitDeletion(current$$1) { + if (supportsMutation) { + // Recursively delete all host nodes from the parent. + // Detach refs and call componentWillUnmount() on the whole subtree. + unmountHostComponents(current$$1); + } else { + // Detach refs and call componentWillUnmount() on the whole subtree. + commitNestedUnmounts(current$$1); + } + detachFiber(current$$1); +} + +function commitWork(current$$1, finishedWork) { + if (!supportsMutation) { + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case MemoComponent: + case SimpleMemoComponent: { + // Note: We currently never use MountMutation, but useLayout uses + // UnmountMutation. + commitHookEffectList(UnmountMutation, MountMutation, finishedWork); + return; + } + case Profiler: { + return; + } + case SuspenseComponent: { + commitSuspenseComponent(finishedWork); + return; + } + } + + commitContainer(finishedWork); + return; + } + + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case MemoComponent: + case SimpleMemoComponent: { + // Note: We currently never use MountMutation, but useLayout uses + // UnmountMutation. + commitHookEffectList(UnmountMutation, MountMutation, finishedWork); + return; + } + case ClassComponent: { + return; + } + case HostComponent: { + var instance = finishedWork.stateNode; + if (instance != null) { + // Commit the work prepared earlier. + var newProps = finishedWork.memoizedProps; + // For hydration we reuse the update path but we treat the oldProps + // as the newProps. The updatePayload will contain the real change in + // this case. + var oldProps = + current$$1 !== null ? current$$1.memoizedProps : newProps; + var type = finishedWork.type; + // TODO: Type the updateQueue to be specific to host components. + var updatePayload = finishedWork.updateQueue; + finishedWork.updateQueue = null; + if (updatePayload !== null) { + commitUpdate( + instance, + updatePayload, + type, + oldProps, + newProps, + finishedWork + ); + } + } + return; + } + case HostText: { + (function() { + if (!(finishedWork.stateNode !== null)) { + throw ReactError( + "This should have a text node initialized. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + var textInstance = finishedWork.stateNode; + var newText = finishedWork.memoizedProps; + // For hydration we reuse the update path but we treat the oldProps + // as the newProps. The updatePayload will contain the real change in + // this case. + var oldText = current$$1 !== null ? current$$1.memoizedProps : newText; + commitTextUpdate(textInstance, oldText, newText); + return; + } + case EventTarget: { + return; + } + case HostRoot: { + return; + } + case Profiler: { + return; + } + case SuspenseComponent: { + commitSuspenseComponent(finishedWork); + return; + } + case IncompleteClassComponent: { + return; + } + case EventComponent: { + return; + } + default: { + (function() { + { + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + })(); + } + } +} + +function commitSuspenseComponent(finishedWork) { + var newState = finishedWork.memoizedState; + + var newDidTimeout = void 0; + var primaryChildParent = finishedWork; + if (newState === null) { + newDidTimeout = false; + } else { + newDidTimeout = true; + primaryChildParent = finishedWork.child; + if (newState.fallbackExpirationTime === NoWork) { + // If the children had not already timed out, record the time. + // This is used to compute the elapsed time during subsequent + // attempts to render the children. + // We model this as a normal pri expiration time since that's + // how we infer start time for updates. + newState.fallbackExpirationTime = computeAsyncExpirationNoBucket( + requestCurrentTime() + ); + } + } + + if (supportsMutation && primaryChildParent !== null) { + hideOrUnhideAllChildren(primaryChildParent, newDidTimeout); + } + + // If this boundary just timed out, then it will have a set of thenables. + // For each thenable, attach a listener so that when it resolves, React + // attempts to re-render the boundary in the primary (pre-timeout) state. + var thenables = finishedWork.updateQueue; + if (thenables !== null) { + finishedWork.updateQueue = null; + var retryCache = finishedWork.stateNode; + if (retryCache === null) { + retryCache = finishedWork.stateNode = new PossiblyWeakSet$1(); + } + thenables.forEach(function(thenable) { + // Memoize using the boundary fiber to prevent redundant listeners. + var retry = resolveRetryThenable.bind(null, finishedWork, thenable); + if (!retryCache.has(thenable)) { + if (enableSchedulerTracing) { + retry = tracing.unstable_wrap(retry); + } + retryCache.add(thenable); + thenable.then(retry, retry); + } + }); + } +} + +function commitResetTextContent(current$$1) { + if (!supportsMutation) { + return; + } + resetTextContent(current$$1.stateNode); +} + +var PossiblyWeakSet = typeof WeakSet === "function" ? WeakSet : Set; +var PossiblyWeakMap = typeof WeakMap === "function" ? WeakMap : Map; + +function createRootErrorUpdate(fiber, errorInfo, expirationTime) { + var update = createUpdate(expirationTime); + // Unmount the root by rendering null. + update.tag = CaptureUpdate; + // Caution: React DevTools currently depends on this property + // being called "element". + update.payload = { element: null }; + var error = errorInfo.value; + update.callback = function() { + onUncaughtError(error); + logError(fiber, errorInfo); + }; + return update; +} + +function createClassErrorUpdate(fiber, errorInfo, expirationTime) { + var update = createUpdate(expirationTime); + update.tag = CaptureUpdate; + var getDerivedStateFromError = fiber.type.getDerivedStateFromError; + if (typeof getDerivedStateFromError === "function") { + var error = errorInfo.value; + update.payload = function() { + return getDerivedStateFromError(error); + }; + } + + var inst = fiber.stateNode; + if (inst !== null && typeof inst.componentDidCatch === "function") { + update.callback = function callback() { + if (typeof getDerivedStateFromError !== "function") { + // To preserve the preexisting retry behavior of error boundaries, + // we keep track of which ones already failed during this batch. + // This gets reset before we yield back to the browser. + // TODO: Warn in strict mode if getDerivedStateFromError is + // not defined. + markLegacyErrorBoundaryAsFailed(this); + } + var error = errorInfo.value; + var stack = errorInfo.stack; + logError(fiber, errorInfo); + this.componentDidCatch(error, { + componentStack: stack !== null ? stack : "" + }); + { + if (typeof getDerivedStateFromError !== "function") { + // If componentDidCatch is the only error boundary method defined, + // then it needs to call setState to recover from errors. + // If no state update is scheduled then the boundary will swallow the error. + !(fiber.expirationTime === Sync) + ? warningWithoutStack$1( + false, + "%s: Error boundaries should implement getDerivedStateFromError(). " + + "In that method, return a state update to display an error message or fallback UI.", + getComponentName(fiber.type) || "Unknown" + ) + : void 0; + } + } + }; + } + return update; +} + +function attachPingListener(root, renderExpirationTime, thenable) { + // Attach a listener to the promise to "ping" the root and retry. But + // only if one does not already exist for the current render expiration + // time (which acts like a "thread ID" here). + var pingCache = root.pingCache; + var threadIDs = void 0; + if (pingCache === null) { + pingCache = root.pingCache = new PossiblyWeakMap(); + threadIDs = new Set(); + pingCache.set(thenable, threadIDs); + } else { + threadIDs = pingCache.get(thenable); + if (threadIDs === undefined) { + threadIDs = new Set(); + pingCache.set(thenable, threadIDs); + } + } + if (!threadIDs.has(renderExpirationTime)) { + // Memoize using the thread ID to prevent redundant listeners. + threadIDs.add(renderExpirationTime); + var ping = pingSuspendedRoot.bind( + null, + root, + thenable, + renderExpirationTime + ); + if (enableSchedulerTracing) { + ping = tracing.unstable_wrap(ping); + } + thenable.then(ping, ping); + } +} + +function throwException( + root, + returnFiber, + sourceFiber, + value, + renderExpirationTime +) { + // The source fiber did not complete. + sourceFiber.effectTag |= Incomplete; + // Its effect list is no longer valid. + sourceFiber.firstEffect = sourceFiber.lastEffect = null; + + if ( + value !== null && + typeof value === "object" && + typeof value.then === "function" + ) { + // This is a thenable. + var thenable = value; + + // Schedule the nearest Suspense to re-render the timed out view. + var _workInProgress = returnFiber; + do { + if ( + _workInProgress.tag === SuspenseComponent && + shouldCaptureSuspense(_workInProgress) + ) { + // Found the nearest boundary. + + // Stash the promise on the boundary fiber. If the boundary times out, we'll + var thenables = _workInProgress.updateQueue; + if (thenables === null) { + var updateQueue = new Set(); + updateQueue.add(thenable); + _workInProgress.updateQueue = updateQueue; + } else { + thenables.add(thenable); + } + + // If the boundary is outside of concurrent mode, we should *not* + // suspend the commit. Pretend as if the suspended component rendered + // null and keep rendering. In the commit phase, we'll schedule a + // subsequent synchronous update to re-render the Suspense. + // + // Note: It doesn't matter whether the component that suspended was + // inside a concurrent mode tree. If the Suspense is outside of it, we + // should *not* suspend the commit. + if ((_workInProgress.mode & ConcurrentMode) === NoContext) { + _workInProgress.effectTag |= DidCapture; + + // We're going to commit this fiber even though it didn't complete. + // But we shouldn't call any lifecycle methods or callbacks. Remove + // all lifecycle effect tags. + sourceFiber.effectTag &= ~(LifecycleEffectMask | Incomplete); + + if (sourceFiber.tag === ClassComponent) { + var currentSourceFiber = sourceFiber.alternate; + if (currentSourceFiber === null) { + // This is a new mount. Change the tag so it's not mistaken for a + // completed class component. For example, we should not call + // componentWillUnmount if it is deleted. + sourceFiber.tag = IncompleteClassComponent; + } else { + // When we try rendering again, we should not reuse the current fiber, + // since it's known to be in an inconsistent state. Use a force updte to + // prevent a bail out. + var update = createUpdate(Sync); + update.tag = ForceUpdate; + enqueueUpdate(sourceFiber, update); + } + } + + // The source fiber did not complete. Mark it with Sync priority to + // indicate that it still has pending work. + sourceFiber.expirationTime = Sync; + + // Exit without suspending. + return; + } + + // Confirmed that the boundary is in a concurrent mode tree. Continue + // with the normal suspend path. + + attachPingListener(root, renderExpirationTime, thenable); + + _workInProgress.effectTag |= ShouldCapture; + _workInProgress.expirationTime = renderExpirationTime; + return; + } else if ( + enableSuspenseServerRenderer && + _workInProgress.tag === DehydratedSuspenseComponent + ) { + attachPingListener(root, renderExpirationTime, thenable); + + // Since we already have a current fiber, we can eagerly add a retry listener. + var retryCache = _workInProgress.memoizedState; + if (retryCache === null) { + retryCache = _workInProgress.memoizedState = new PossiblyWeakSet(); + var current$$1 = _workInProgress.alternate; + (function() { + if (!current$$1) { + throw ReactError( + "A dehydrated suspense boundary must commit before trying to render. This is probably a bug in React." + ); + } + })(); + current$$1.memoizedState = retryCache; + } + // Memoize using the boundary fiber to prevent redundant listeners. + if (!retryCache.has(thenable)) { + retryCache.add(thenable); + var retry = resolveRetryThenable.bind( + null, + _workInProgress, + thenable + ); + if (enableSchedulerTracing) { + retry = tracing.unstable_wrap(retry); + } + thenable.then(retry, retry); + } + _workInProgress.effectTag |= ShouldCapture; + _workInProgress.expirationTime = renderExpirationTime; + return; + } + // This boundary already captured during this render. Continue to the next + // boundary. + _workInProgress = _workInProgress.return; + } while (_workInProgress !== null); + // No boundary was found. Fallthrough to error mode. + // TODO: Use invariant so the message is stripped in prod? + value = new Error( + (getComponentName(sourceFiber.type) || "A React component") + + " suspended while rendering, but no fallback UI was specified.\n" + + "\n" + + "Add a component higher in the tree to " + + "provide a loading indicator or placeholder to display." + + getStackByFiberInDevAndProd(sourceFiber) + ); + } + + // We didn't find a boundary that could handle this type of exception. Start + // over and traverse parent path again, this time treating the exception + // as an error. + renderDidError(); + value = createCapturedValue(value, sourceFiber); + var workInProgress = returnFiber; + do { + switch (workInProgress.tag) { + case HostRoot: { + var _errorInfo = value; + workInProgress.effectTag |= ShouldCapture; + workInProgress.expirationTime = renderExpirationTime; + var _update = createRootErrorUpdate( + workInProgress, + _errorInfo, + renderExpirationTime + ); + enqueueCapturedUpdate(workInProgress, _update); + return; + } + case ClassComponent: + // Capture and retry + var errorInfo = value; + var ctor = workInProgress.type; + var instance = workInProgress.stateNode; + if ( + (workInProgress.effectTag & DidCapture) === NoEffect && + (typeof ctor.getDerivedStateFromError === "function" || + (instance !== null && + typeof instance.componentDidCatch === "function" && + !isAlreadyFailedLegacyErrorBoundary(instance))) + ) { + workInProgress.effectTag |= ShouldCapture; + workInProgress.expirationTime = renderExpirationTime; + // Schedule the error boundary to re-render using updated state + var _update2 = createClassErrorUpdate( + workInProgress, + errorInfo, + renderExpirationTime + ); + enqueueCapturedUpdate(workInProgress, _update2); + return; + } + break; + default: + break; + } + workInProgress = workInProgress.return; + } while (workInProgress !== null); +} + +function unwindWork(workInProgress, renderExpirationTime) { + switch (workInProgress.tag) { + case ClassComponent: { + var Component = workInProgress.type; + if (isContextProvider(Component)) { + popContext(workInProgress); + } + var effectTag = workInProgress.effectTag; + if (effectTag & ShouldCapture) { + workInProgress.effectTag = (effectTag & ~ShouldCapture) | DidCapture; + return workInProgress; + } + return null; + } + case HostRoot: { + popHostContainer(workInProgress); + popTopLevelContextObject(workInProgress); + var _effectTag = workInProgress.effectTag; + (function() { + if (!((_effectTag & DidCapture) === NoEffect)) { + throw ReactError( + "The root failed to unmount after an error. This is likely a bug in React. Please file an issue." + ); + } + })(); + workInProgress.effectTag = (_effectTag & ~ShouldCapture) | DidCapture; + return workInProgress; + } + case HostComponent: { + // TODO: popHydrationState + popHostContext(workInProgress); + return null; + } + case SuspenseComponent: { + var _effectTag2 = workInProgress.effectTag; + if (_effectTag2 & ShouldCapture) { + workInProgress.effectTag = (_effectTag2 & ~ShouldCapture) | DidCapture; + // Captured a suspense effect. Re-render the boundary. + return workInProgress; + } + return null; + } + case DehydratedSuspenseComponent: { + if (enableSuspenseServerRenderer) { + // TODO: popHydrationState + var _effectTag3 = workInProgress.effectTag; + if (_effectTag3 & ShouldCapture) { + workInProgress.effectTag = + (_effectTag3 & ~ShouldCapture) | DidCapture; + // Captured a suspense effect. Re-render the boundary. + return workInProgress; + } + } + return null; + } + case HostPortal: + popHostContainer(workInProgress); + return null; + case ContextProvider: + popProvider(workInProgress); + return null; + case EventComponent: + case EventTarget: + if (enableEventAPI) { + popHostContext(workInProgress); + } + return null; + default: + return null; + } +} + +function unwindInterruptedWork(interruptedWork) { + switch (interruptedWork.tag) { + case ClassComponent: { + var childContextTypes = interruptedWork.type.childContextTypes; + if (childContextTypes !== null && childContextTypes !== undefined) { + popContext(interruptedWork); + } + break; + } + case HostRoot: { + popHostContainer(interruptedWork); + popTopLevelContextObject(interruptedWork); + break; + } + case HostComponent: { + popHostContext(interruptedWork); + break; + } + case HostPortal: + popHostContainer(interruptedWork); + break; + case ContextProvider: + popProvider(interruptedWork); + break; + default: + break; + } +} + +// TODO: Ahaha Andrew is bad at spellling +// DEV stuff +var ceil = Math.ceil; + +var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher; +var ReactCurrentOwner$2 = ReactSharedInternals.ReactCurrentOwner; +var ReactShouldWarnActingUpdates = + ReactSharedInternals.ReactShouldWarnActingUpdates; + +var NotWorking = 0; +var BatchedPhase = 1; +var LegacyUnbatchedPhase = 2; +var RenderPhase = 4; +var CommitPhase = 5; + +var RootIncomplete = 0; +var RootErrored = 1; +var RootSuspended = 2; +var RootCompleted = 3; + +// The phase of work we're currently in +var workPhase = NotWorking; +// The root we're working on +var workInProgressRoot = null; +// The fiber we're working on +var workInProgress = null; +// The expiration time we're rendering +var renderExpirationTime = NoWork; +// Whether to root completed, errored, suspended, etc. +var workInProgressRootExitStatus = RootIncomplete; +// Most recent event time among processed updates during this render. +// This is conceptually a time stamp but expressed in terms of an ExpirationTime +// because we deal mostly with expiration times in the hot path, so this avoids +// the conversion happening in the hot path. +var workInProgressRootMostRecentEventTime = Sync; + +var nextEffect = null; +var hasUncaughtError = false; +var firstUncaughtError = null; +var legacyErrorBoundariesThatAlreadyFailed = null; + +var rootDoesHavePassiveEffects = false; +var rootWithPendingPassiveEffects = null; +var pendingPassiveEffectsExpirationTime = NoWork; + +var rootsWithPendingDiscreteUpdates = null; + +// Use these to prevent an infinite loop of nested updates +var NESTED_UPDATE_LIMIT = 50; +var nestedUpdateCount = 0; +var rootWithNestedUpdates = null; + +var NESTED_PASSIVE_UPDATE_LIMIT = 50; +var nestedPassiveUpdateCount = 0; + +var interruptedBy = null; + +// Expiration times are computed by adding to the current time (the start +// time). However, if two updates are scheduled within the same event, we +// should treat their start times as simultaneous, even if the actual clock +// time has advanced between the first and second call. + +// In other words, because expiration times determine how updates are batched, +// we want all updates of like priority that occur within the same event to +// receive the same expiration time. Otherwise we get tearing. +var currentEventTime = NoWork; + +function requestCurrentTime() { + if (workPhase === RenderPhase || workPhase === CommitPhase) { + // We're inside React, so it's fine to read the actual time. + return msToExpirationTime(now()); + } + // We're not inside React, so we may be in the middle of a browser event. + if (currentEventTime !== NoWork) { + // Use the same start time for all updates until we enter React again. + return currentEventTime; + } + // This is the first update since React yielded. Compute a new start time. + currentEventTime = msToExpirationTime(now()); + return currentEventTime; +} + +function computeExpirationForFiber(currentTime, fiber) { + if ((fiber.mode & ConcurrentMode) === NoContext) { + return Sync; + } + + if (workPhase === RenderPhase) { + // Use whatever time we're already rendering + return renderExpirationTime; + } + + // Compute an expiration time based on the Scheduler priority. + var expirationTime = void 0; + var priorityLevel = getCurrentPriorityLevel(); + switch (priorityLevel) { + case ImmediatePriority: + expirationTime = Sync; + break; + case UserBlockingPriority: + // TODO: Rename this to computeUserBlockingExpiration + expirationTime = computeInteractiveExpiration(currentTime); + break; + case NormalPriority: + case LowPriority: + // TODO: Handle LowPriority + // TODO: Rename this to... something better. + expirationTime = computeAsyncExpiration(currentTime); + break; + case IdlePriority: + expirationTime = Never; + break; + default: + (function() { + { + throw ReactError("Expected a valid priority level"); + } + })(); + } + + // If we're in the middle of rendering a tree, do not update at the same + // expiration time that is already rendering. + if (workInProgressRoot !== null && expirationTime === renderExpirationTime) { + // This is a trick to move this update into a separate batch + expirationTime -= 1; + } + + return expirationTime; +} + +function scheduleUpdateOnFiber(fiber, expirationTime) { + checkForNestedUpdates(); + warnAboutInvalidUpdatesOnClassComponentsInDEV(fiber); + + var root = markUpdateTimeFromFiberToRoot(fiber, expirationTime); + if (root === null) { + warnAboutUpdateOnUnmountedFiberInDEV(fiber); + return; + } + + root.pingTime = NoWork; + + checkForInterruption(fiber, expirationTime); + recordScheduleUpdate(); + + if (expirationTime === Sync) { + if (workPhase === LegacyUnbatchedPhase) { + // This is a legacy edge case. The initial mount of a ReactDOM.render-ed + // root inside of batchedUpdates should be synchronous, but layout updates + // should be deferred until the end of the batch. + var callback = renderRoot(root, Sync, true); + while (callback !== null) { + callback = callback(true); + } + } else { + scheduleCallbackForRoot(root, ImmediatePriority, Sync); + if (workPhase === NotWorking) { + // Flush the synchronous work now, wnless we're already working or inside + // a batch. This is intentionally inside scheduleUpdateOnFiber instead of + // scheduleCallbackForFiber to preserve the ability to schedule a callback + // without immediately flushing it. We only do this for user-initated + // updates, to preserve historical behavior of sync mode. + flushImmediateQueue(); + } + } + } else { + // TODO: computeExpirationForFiber also reads the priority. Pass the + // priority as an argument to that function and this one. + var priorityLevel = getCurrentPriorityLevel(); + if (priorityLevel === UserBlockingPriority) { + // This is the result of a discrete event. Track the lowest priority + // discrete update per root so we can flush them early, if needed. + if (rootsWithPendingDiscreteUpdates === null) { + rootsWithPendingDiscreteUpdates = new Map([[root, expirationTime]]); + } else { + var lastDiscreteTime = rootsWithPendingDiscreteUpdates.get(root); + if ( + lastDiscreteTime === undefined || + lastDiscreteTime > expirationTime + ) { + rootsWithPendingDiscreteUpdates.set(root, expirationTime); + } + } + } + scheduleCallbackForRoot(root, priorityLevel, expirationTime); + } +} +var scheduleWork = scheduleUpdateOnFiber; + +// This is split into a separate function so we can mark a fiber with pending +// work without treating it as a typical update that originates from an event; +// e.g. retrying a Suspense boundary isn't an update, but it does schedule work +// on a fiber. +function markUpdateTimeFromFiberToRoot(fiber, expirationTime) { + // Update the source fiber's expiration time + if (fiber.expirationTime < expirationTime) { + fiber.expirationTime = expirationTime; + } + var alternate = fiber.alternate; + if (alternate !== null && alternate.expirationTime < expirationTime) { + alternate.expirationTime = expirationTime; + } + // Walk the parent path to the root and update the child expiration time. + var node = fiber.return; + var root = null; + if (node === null && fiber.tag === HostRoot) { + root = fiber.stateNode; + } else { + while (node !== null) { + alternate = node.alternate; + if (node.childExpirationTime < expirationTime) { + node.childExpirationTime = expirationTime; + if ( + alternate !== null && + alternate.childExpirationTime < expirationTime + ) { + alternate.childExpirationTime = expirationTime; + } + } else if ( + alternate !== null && + alternate.childExpirationTime < expirationTime + ) { + alternate.childExpirationTime = expirationTime; + } + if (node.return === null && node.tag === HostRoot) { + root = node.stateNode; + break; + } + node = node.return; + } + } + + if (root !== null) { + // Update the first and last pending expiration times in this root + var firstPendingTime = root.firstPendingTime; + if (expirationTime > firstPendingTime) { + root.firstPendingTime = expirationTime; + } + var lastPendingTime = root.lastPendingTime; + if (lastPendingTime === NoWork || expirationTime < lastPendingTime) { + root.lastPendingTime = expirationTime; + } + } + + return root; +} + +// Use this function, along with runRootCallback, to ensure that only a single +// callback per root is scheduled. It's still possible to call renderRoot +// directly, but scheduling via this function helps avoid excessive callbacks. +// It works by storing the callback node and expiration time on the root. When a +// new callback comes in, it compares the expiration time to determine if it +// should cancel the previous one. It also relies on commitRoot scheduling a +// callback to render the next level, because that means we don't need a +// separate callback per expiration time. +function scheduleCallbackForRoot(root, priorityLevel, expirationTime) { + var existingCallbackExpirationTime = root.callbackExpirationTime; + if (existingCallbackExpirationTime < expirationTime) { + // New callback has higher priority than the existing one. + var existingCallbackNode = root.callbackNode; + if (existingCallbackNode !== null) { + cancelCallback(existingCallbackNode); + } + root.callbackExpirationTime = expirationTime; + + var options = null; + if (expirationTime !== Sync && expirationTime !== Never) { + var timeout = expirationTimeToMs(expirationTime) - now(); + if (timeout > 5000) { + // Sanity check. Should never take longer than 5 seconds. + // TODO: Add internal warning? + timeout = 5000; + } + options = { timeout: timeout }; + } + + root.callbackNode = scheduleCallback( + priorityLevel, + runRootCallback.bind( + null, + root, + renderRoot.bind(null, root, expirationTime) + ), + options + ); + if ( + enableUserTimingAPI && + expirationTime !== Sync && + workPhase !== RenderPhase && + workPhase !== CommitPhase + ) { + // Scheduled an async callback, and we're not already working. Add an + // entry to the flamegraph that shows we're waiting for a callback + // to fire. + startRequestCallbackTimer(); + } + } + + // Add the current set of interactions to the pending set associated with + // this root. + schedulePendingInteraction(root, expirationTime); +} + +function runRootCallback(root, callback, isSync) { + var prevCallbackNode = root.callbackNode; + var continuation = null; + try { + continuation = callback(isSync); + if (continuation !== null) { + return runRootCallback.bind(null, root, continuation); + } else { + return null; + } + } finally { + // If the callback exits without returning a continuation, remove the + // corresponding callback node from the root. Unless the callback node + // has changed, which implies that it was already cancelled by a high + // priority update. + if (continuation === null && prevCallbackNode === root.callbackNode) { + root.callbackNode = null; + root.callbackExpirationTime = NoWork; + } + } +} + +function flushInteractiveUpdates$1() { + if (workPhase === RenderPhase || workPhase === CommitPhase) { + // Can't synchronously flush interactive updates if React is already + // working. This is currently a no-op. + // TODO: Should we fire a warning? This happens if you synchronously invoke + // an input event inside an effect, like with `element.click()`. + return; + } + flushPendingDiscreteUpdates(); +} + +function resolveLocksOnRoot(root, expirationTime) { + var firstBatch = root.firstBatch; + if ( + firstBatch !== null && + firstBatch._defer && + firstBatch._expirationTime >= expirationTime + ) { + root.finishedWork = root.current.alternate; + root.pendingCommitExpirationTime = expirationTime; + scheduleCallback(NormalPriority, function() { + firstBatch._onComplete(); + return null; + }); + return true; + } else { + return false; + } +} + +function interactiveUpdates$1(fn, a, b, c) { + if (workPhase === NotWorking) { + // TODO: Remove this call. Instead of doing this automatically, the caller + // should explicitly call flushInteractiveUpdates. + flushPendingDiscreteUpdates(); + } + return runWithPriority(UserBlockingPriority, fn.bind(null, a, b, c)); +} + +function flushPendingDiscreteUpdates() { + if (rootsWithPendingDiscreteUpdates !== null) { + // For each root with pending discrete updates, schedule a callback to + // immediately flush them. + var roots = rootsWithPendingDiscreteUpdates; + rootsWithPendingDiscreteUpdates = null; + roots.forEach(function(expirationTime, root) { + scheduleCallback( + ImmediatePriority, + renderRoot.bind(null, root, expirationTime) + ); + }); + // Now flush the immediate queue. + flushImmediateQueue(); + } +} + +function batchedUpdates$1(fn, a) { + if (workPhase !== NotWorking) { + // We're already working, or inside a batch, so batchedUpdates is a no-op. + return fn(a); + } + workPhase = BatchedPhase; + try { + return fn(a); + } finally { + workPhase = NotWorking; + // Flush the immediate callbacks that were scheduled during this batch + flushImmediateQueue(); + } +} + +function prepareFreshStack(root, expirationTime) { + root.pendingCommitExpirationTime = NoWork; + + var timeoutHandle = root.timeoutHandle; + if (timeoutHandle !== noTimeout) { + // The root previous suspended and scheduled a timeout to commit a fallback + // state. Now that we have additional work, cancel the timeout. + root.timeoutHandle = noTimeout; + // $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above + cancelTimeout(timeoutHandle); + } + + if (workInProgress !== null) { + var interruptedWork = workInProgress.return; + while (interruptedWork !== null) { + unwindInterruptedWork(interruptedWork); + interruptedWork = interruptedWork.return; + } + } + workInProgressRoot = root; + workInProgress = createWorkInProgress(root.current, null, expirationTime); + renderExpirationTime = expirationTime; + workInProgressRootExitStatus = RootIncomplete; + workInProgressRootMostRecentEventTime = Sync; + + { + ReactStrictModeWarnings.discardPendingWarnings(); + } +} + +function renderRoot(root, expirationTime, isSync) { + (function() { + if (!(workPhase !== RenderPhase && workPhase !== CommitPhase)) { + throw ReactError("Should not already be working."); + } + })(); + + if (enableUserTimingAPI && expirationTime !== Sync) { + var didExpire = isSync; + stopRequestCallbackTimer(didExpire); + } + + if (root.firstPendingTime < expirationTime) { + // If there's no work left at this expiration time, exit immediately. This + // happens when multiple callbacks are scheduled for a single root, but an + // earlier callback flushes the work of a later one. + return null; + } + + if (root.pendingCommitExpirationTime === expirationTime) { + // There's already a pending commit at this expiration time. + root.pendingCommitExpirationTime = NoWork; + return commitRoot.bind(null, root, expirationTime); + } + + flushPassiveEffects(); + + // If the root or expiration time have changed, throw out the existing stack + // and prepare a fresh one. Otherwise we'll continue where we left off. + if (root !== workInProgressRoot || expirationTime !== renderExpirationTime) { + prepareFreshStack(root, expirationTime); + startWorkOnPendingInteraction(root, expirationTime); + } + + // If we have a work-in-progress fiber, it means there's still work to do + // in this root. + if (workInProgress !== null) { + var prevWorkPhase = workPhase; + workPhase = RenderPhase; + var prevDispatcher = ReactCurrentDispatcher.current; + if (prevDispatcher === null) { + // The React isomorphic package does not include a default dispatcher. + // Instead the first renderer will lazily attach one, in order to give + // nicer error messages. + prevDispatcher = ContextOnlyDispatcher; + } + ReactCurrentDispatcher.current = ContextOnlyDispatcher; + var prevInteractions = null; + if (enableSchedulerTracing) { + prevInteractions = tracing.__interactionsRef.current; + tracing.__interactionsRef.current = root.memoizedInteractions; + } + + startWorkLoopTimer(workInProgress); + + // TODO: Fork renderRoot into renderRootSync and renderRootAsync + if (isSync) { + if (expirationTime !== Sync) { + // An async update expired. There may be other expired updates on + // this root. We should render all the expired work in a + // single batch. + var currentTime = requestCurrentTime(); + if (currentTime < expirationTime) { + // Restart at the current time. + workPhase = prevWorkPhase; + resetContextDependences(); + ReactCurrentDispatcher.current = prevDispatcher; + if (enableSchedulerTracing) { + tracing.__interactionsRef.current = prevInteractions; + } + return renderRoot.bind(null, root, currentTime); + } + } + } else { + // Since we know we're in a React event, we can clear the current + // event time. The next update will compute a new event time. + currentEventTime = NoWork; + } + + do { + try { + if (isSync) { + workLoopSync(); + } else { + workLoop(); + } + break; + } catch (thrownValue) { + // Reset module-level state that was set during the render phase. + resetContextDependences(); + resetHooks(); + + var sourceFiber = workInProgress; + if (sourceFiber === null || sourceFiber.return === null) { + // Expected to be working on a non-root fiber. This is a fatal error + // because there's no ancestor that can handle it; the root is + // supposed to capture all errors that weren't caught by an error + // boundary. + prepareFreshStack(root, expirationTime); + workPhase = prevWorkPhase; + throw thrownValue; + } + + if (enableProfilerTimer && sourceFiber.mode & ProfileMode) { + // Record the time spent rendering before an error was thrown. This + // avoids inaccurate Profiler durations in the case of a + // suspended render. + stopProfilerTimerIfRunningAndRecordDelta(sourceFiber, true); + } + + var returnFiber = sourceFiber.return; + throwException( + root, + returnFiber, + sourceFiber, + thrownValue, + renderExpirationTime + ); + workInProgress = completeUnitOfWork(sourceFiber); + } + } while (true); + + workPhase = prevWorkPhase; + resetContextDependences(); + ReactCurrentDispatcher.current = prevDispatcher; + if (enableSchedulerTracing) { + tracing.__interactionsRef.current = prevInteractions; + } + + if (workInProgress !== null) { + // There's still work left over. Return a continuation. + stopInterruptedWorkLoopTimer(); + if (expirationTime !== Sync) { + startRequestCallbackTimer(); + } + return renderRoot.bind(null, root, expirationTime); + } + } + + // We now have a consistent tree. The next step is either to commit it, or, if + // something suspended, wait to commit it after a timeout. + stopFinishedWorkLoopTimer(); + + var isLocked = resolveLocksOnRoot(root, expirationTime); + if (isLocked) { + // This root has a lock that prevents it from committing. Exit. If we begin + // work on the root again, without any intervening updates, it will finish + // without doing additional work. + return null; + } + + // Set this to null to indicate there's no in-progress render. + workInProgressRoot = null; + + switch (workInProgressRootExitStatus) { + case RootIncomplete: { + (function() { + { + throw ReactError("Should have a work-in-progress."); + } + })(); + } + // Flow knows about invariant, so it compains if I add a break statement, + // but eslint doesn't know about invariant, so it complains if I do. + // eslint-disable-next-line no-fallthrough + case RootErrored: { + // An error was thrown. First check if there is lower priority work + // scheduled on this root. + var lastPendingTime = root.lastPendingTime; + if (root.lastPendingTime < expirationTime) { + // There's lower priority work. Before raising the error, try rendering + // at the lower priority to see if it fixes it. Use a continuation to + // maintain the existing priority and position in the queue. + return renderRoot.bind(null, root, lastPendingTime); + } + if (!isSync) { + // If we're rendering asynchronously, it's possible the error was + // caused by tearing due to a mutation during an event. Try rendering + // one more time without yiedling to events. + prepareFreshStack(root, expirationTime); + scheduleCallback( + ImmediatePriority, + renderRoot.bind(null, root, expirationTime) + ); + return null; + } + // If we're already rendering synchronously, commit the root in its + // errored state. + return commitRoot.bind(null, root, expirationTime); + } + case RootSuspended: { + if (!isSync) { + var _lastPendingTime = root.lastPendingTime; + if (root.lastPendingTime < expirationTime) { + // There's lower priority work. It might be unsuspended. Try rendering + // at that level. + return renderRoot.bind(null, root, _lastPendingTime); + } + // If workInProgressRootMostRecentEventTime is Sync, that means we didn't + // track any event times. That can happen if we retried but nothing switched + // from fallback to content. There's no reason to delay doing no work. + if (workInProgressRootMostRecentEventTime !== Sync) { + var msUntilTimeout = computeMsUntilTimeout( + workInProgressRootMostRecentEventTime, + expirationTime + ); + // Don't bother with a very short suspense time. + if (msUntilTimeout > 10) { + // The render is suspended, it hasn't timed out, and there's no lower + // priority work to do. Instead of committing the fallback + // immediately, wait for more data to arrive. + root.timeoutHandle = scheduleTimeout( + commitRoot.bind(null, root, expirationTime), + msUntilTimeout + ); + return null; + } + } + } + // The work expired. Commit immediately. + return commitRoot.bind(null, root, expirationTime); + } + case RootCompleted: { + // The work completed. Ready to commit. + return commitRoot.bind(null, root, expirationTime); + } + default: { + (function() { + { + throw ReactError("Unknown root exit status."); + } + })(); + } + } +} + +function markRenderEventTime(expirationTime) { + if (expirationTime < workInProgressRootMostRecentEventTime) { + workInProgressRootMostRecentEventTime = expirationTime; + } +} + +function renderDidSuspend() { + if (workInProgressRootExitStatus === RootIncomplete) { + workInProgressRootExitStatus = RootSuspended; + } +} + +function renderDidError() { + if ( + workInProgressRootExitStatus === RootIncomplete || + workInProgressRootExitStatus === RootSuspended + ) { + workInProgressRootExitStatus = RootErrored; + } +} + +function inferTimeFromExpirationTime(expirationTime) { + // We don't know exactly when the update was scheduled, but we can infer an + // approximate start time from the expiration time. + var earliestExpirationTimeMs = expirationTimeToMs(expirationTime); + return earliestExpirationTimeMs - LOW_PRIORITY_EXPIRATION; +} + +function workLoopSync() { + // Already timed out, so perform work without checking if we need to yield. + while (workInProgress !== null) { + workInProgress = performUnitOfWork(workInProgress); + } +} + +function workLoop() { + // Perform work until Scheduler asks us to yield + while (workInProgress !== null && !shouldYield()) { + workInProgress = performUnitOfWork(workInProgress); + } +} + +function performUnitOfWork(unitOfWork) { + // The current, flushed, state of this fiber is the alternate. Ideally + // nothing should rely on this, but relying on it here means that we don't + // need an additional field on the work in progress. + var current$$1 = unitOfWork.alternate; + + startWorkTimer(unitOfWork); + setCurrentFiber(unitOfWork); + + var next = void 0; + if (enableProfilerTimer && (unitOfWork.mode & ProfileMode) !== NoContext) { + startProfilerTimer(unitOfWork); + next = beginWork$$1(current$$1, unitOfWork, renderExpirationTime); + stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true); + } else { + next = beginWork$$1(current$$1, unitOfWork, renderExpirationTime); + } + + resetCurrentFiber(); + unitOfWork.memoizedProps = unitOfWork.pendingProps; + if (next === null) { + // If this doesn't spawn new work, complete the current work. + next = completeUnitOfWork(unitOfWork); + } + + ReactCurrentOwner$2.current = null; + return next; +} + +function completeUnitOfWork(unitOfWork) { + // Attempt to complete the current unit of work, then move to the next + // sibling. If there are no more siblings, return to the parent fiber. + workInProgress = unitOfWork; + do { + // The current, flushed, state of this fiber is the alternate. Ideally + // nothing should rely on this, but relying on it here means that we don't + // need an additional field on the work in progress. + var current$$1 = workInProgress.alternate; + var returnFiber = workInProgress.return; + + // Check if the work completed or if something threw. + if ((workInProgress.effectTag & Incomplete) === NoEffect) { + setCurrentFiber(workInProgress); + var next = void 0; + if ( + !enableProfilerTimer || + (workInProgress.mode & ProfileMode) === NoContext + ) { + next = completeWork(current$$1, workInProgress, renderExpirationTime); + } else { + startProfilerTimer(workInProgress); + next = completeWork(current$$1, workInProgress, renderExpirationTime); + // Update render duration assuming we didn't error. + stopProfilerTimerIfRunningAndRecordDelta(workInProgress, false); + } + stopWorkTimer(workInProgress); + resetCurrentFiber(); + resetChildExpirationTime(workInProgress); + + if (next !== null) { + // Completing this fiber spawned new work. Work on that next. + return next; + } + + if ( + returnFiber !== null && + // Do not append effects to parents if a sibling failed to complete + (returnFiber.effectTag & Incomplete) === NoEffect + ) { + // Append all the effects of the subtree and this fiber onto the effect + // list of the parent. The completion order of the children affects the + // side-effect order. + if (returnFiber.firstEffect === null) { + returnFiber.firstEffect = workInProgress.firstEffect; + } + if (workInProgress.lastEffect !== null) { + if (returnFiber.lastEffect !== null) { + returnFiber.lastEffect.nextEffect = workInProgress.firstEffect; + } + returnFiber.lastEffect = workInProgress.lastEffect; + } + + // If this fiber had side-effects, we append it AFTER the children's + // side-effects. We can perform certain side-effects earlier if needed, + // by doing multiple passes over the effect list. We don't want to + // schedule our own side-effect on our own list because if end up + // reusing children we'll schedule this effect onto itself since we're + // at the end. + var effectTag = workInProgress.effectTag; + + // Skip both NoWork and PerformedWork tags when creating the effect + // list. PerformedWork effect is read by React DevTools but shouldn't be + // committed. + if (effectTag > PerformedWork) { + if (returnFiber.lastEffect !== null) { + returnFiber.lastEffect.nextEffect = workInProgress; + } else { + returnFiber.firstEffect = workInProgress; + } + returnFiber.lastEffect = workInProgress; + } + } + } else { + // This fiber did not complete because something threw. Pop values off + // the stack without entering the complete phase. If this is a boundary, + // capture values if possible. + var _next = unwindWork(workInProgress, renderExpirationTime); + + // Because this fiber did not complete, don't reset its expiration time. + + if ( + enableProfilerTimer && + (workInProgress.mode & ProfileMode) !== NoContext + ) { + // Record the render duration for the fiber that errored. + stopProfilerTimerIfRunningAndRecordDelta(workInProgress, false); + + // Include the time spent working on failed children before continuing. + var actualDuration = workInProgress.actualDuration; + var child = workInProgress.child; + while (child !== null) { + actualDuration += child.actualDuration; + child = child.sibling; + } + workInProgress.actualDuration = actualDuration; + } + + if (_next !== null) { + // If completing this work spawned new work, do that next. We'll come + // back here again. + // Since we're restarting, remove anything that is not a host effect + // from the effect tag. + // TODO: The name stopFailedWorkTimer is misleading because Suspense + // also captures and restarts. + stopFailedWorkTimer(workInProgress); + _next.effectTag &= HostEffectMask; + return _next; + } + stopWorkTimer(workInProgress); + + if (returnFiber !== null) { + // Mark the parent fiber as incomplete and clear its effect list. + returnFiber.firstEffect = returnFiber.lastEffect = null; + returnFiber.effectTag |= Incomplete; + } + } + + var siblingFiber = workInProgress.sibling; + if (siblingFiber !== null) { + // If there is more work to do in this returnFiber, do that next. + return siblingFiber; + } + // Otherwise, return to the parent + workInProgress = returnFiber; + } while (workInProgress !== null); + + // We've reached the root. + if (workInProgressRootExitStatus === RootIncomplete) { + workInProgressRootExitStatus = RootCompleted; + } + return null; +} + +function resetChildExpirationTime(completedWork) { + if ( + renderExpirationTime !== Never && + completedWork.childExpirationTime === Never + ) { + // The children of this component are hidden. Don't bubble their + // expiration times. + return; + } + + var newChildExpirationTime = NoWork; + + // Bubble up the earliest expiration time. + if (enableProfilerTimer && (completedWork.mode & ProfileMode) !== NoContext) { + // In profiling mode, resetChildExpirationTime is also used to reset + // profiler durations. + var actualDuration = completedWork.actualDuration; + var treeBaseDuration = completedWork.selfBaseDuration; + + // When a fiber is cloned, its actualDuration is reset to 0. This value will + // only be updated if work is done on the fiber (i.e. it doesn't bailout). + // When work is done, it should bubble to the parent's actualDuration. If + // the fiber has not been cloned though, (meaning no work was done), then + // this value will reflect the amount of time spent working on a previous + // render. In that case it should not bubble. We determine whether it was + // cloned by comparing the child pointer. + var shouldBubbleActualDurations = + completedWork.alternate === null || + completedWork.child !== completedWork.alternate.child; + + var child = completedWork.child; + while (child !== null) { + var childUpdateExpirationTime = child.expirationTime; + var childChildExpirationTime = child.childExpirationTime; + if (childUpdateExpirationTime > newChildExpirationTime) { + newChildExpirationTime = childUpdateExpirationTime; + } + if (childChildExpirationTime > newChildExpirationTime) { + newChildExpirationTime = childChildExpirationTime; + } + if (shouldBubbleActualDurations) { + actualDuration += child.actualDuration; + } + treeBaseDuration += child.treeBaseDuration; + child = child.sibling; + } + completedWork.actualDuration = actualDuration; + completedWork.treeBaseDuration = treeBaseDuration; + } else { + var _child = completedWork.child; + while (_child !== null) { + var _childUpdateExpirationTime = _child.expirationTime; + var _childChildExpirationTime = _child.childExpirationTime; + if (_childUpdateExpirationTime > newChildExpirationTime) { + newChildExpirationTime = _childUpdateExpirationTime; + } + if (_childChildExpirationTime > newChildExpirationTime) { + newChildExpirationTime = _childChildExpirationTime; + } + _child = _child.sibling; + } + } + + completedWork.childExpirationTime = newChildExpirationTime; +} + +function commitRoot(root, expirationTime) { + runWithPriority( + ImmediatePriority, + commitRootImpl.bind(null, root, expirationTime) + ); + // If there are passive effects, schedule a callback to flush them. This goes + // outside commitRootImpl so that it inherits the priority of the render. + if (rootWithPendingPassiveEffects !== null) { + var priorityLevel = getCurrentPriorityLevel(); + scheduleCallback(priorityLevel, function() { + flushPassiveEffects(); + return null; + }); + } + return null; +} + +function commitRootImpl(root, expirationTime) { + flushPassiveEffects(); + flushRenderPhaseStrictModeWarningsInDEV(); + + (function() { + if (!(workPhase !== RenderPhase && workPhase !== CommitPhase)) { + throw ReactError("Should not already be working."); + } + })(); + var finishedWork = root.current.alternate; + (function() { + if (!(finishedWork !== null)) { + throw ReactError("Should have a work-in-progress root."); + } + })(); + + // commitRoot never returns a continuation; it always finishes synchronously. + // So we can clear these now to allow a new callback to be scheduled. + root.callbackNode = null; + root.callbackExpirationTime = NoWork; + + startCommitTimer(); + + // Update the first and last pending times on this root. The new first + // pending time is whatever is left on the root fiber. + var updateExpirationTimeBeforeCommit = finishedWork.expirationTime; + var childExpirationTimeBeforeCommit = finishedWork.childExpirationTime; + var firstPendingTimeBeforeCommit = + childExpirationTimeBeforeCommit > updateExpirationTimeBeforeCommit + ? childExpirationTimeBeforeCommit + : updateExpirationTimeBeforeCommit; + root.firstPendingTime = firstPendingTimeBeforeCommit; + if (firstPendingTimeBeforeCommit < root.lastPendingTime) { + // This usually means we've finished all the work, but it can also happen + // when something gets downprioritized during render, like a hidden tree. + root.lastPendingTime = firstPendingTimeBeforeCommit; + } + + if (root === workInProgressRoot) { + // We can reset these now that they are finished. + workInProgressRoot = null; + workInProgress = null; + renderExpirationTime = NoWork; + } else { + } + // This indicates that the last root we worked on is not the same one that + // we're committing now. This most commonly happens when a suspended root + // times out. + + // Get the list of effects. + var firstEffect = void 0; + if (finishedWork.effectTag > PerformedWork) { + // A fiber's effect list consists only of its children, not itself. So if + // the root has an effect, we need to add it to the end of the list. The + // resulting list is the set that would belong to the root's parent, if it + // had one; that is, all the effects in the tree including the root. + if (finishedWork.lastEffect !== null) { + finishedWork.lastEffect.nextEffect = finishedWork; + firstEffect = finishedWork.firstEffect; + } else { + firstEffect = finishedWork; + } + } else { + // There is no effect on the root. + firstEffect = finishedWork.firstEffect; + } + + if (firstEffect !== null) { + var prevWorkPhase = workPhase; + workPhase = CommitPhase; + var prevInteractions = null; + if (enableSchedulerTracing) { + prevInteractions = tracing.__interactionsRef.current; + tracing.__interactionsRef.current = root.memoizedInteractions; + } + + // Reset this to null before calling lifecycles + ReactCurrentOwner$2.current = null; + + // The commit phase is broken into several sub-phases. We do a separate pass + // of the effect list for each phase: all mutation effects come before all + // layout effects, and so on. + + // The first phase a "before mutation" phase. We use this phase to read the + // state of the host tree right before we mutate it. This is where + // getSnapshotBeforeUpdate is called. + startCommitSnapshotEffectsTimer(); + prepareForCommit(root.containerInfo); + nextEffect = firstEffect; + do { + { + invokeGuardedCallback(null, commitBeforeMutationEffects, null); + if (hasCaughtError()) { + (function() { + if (!(nextEffect !== null)) { + throw ReactError("Should be working on an effect."); + } + })(); + var error = clearCaughtError(); + captureCommitPhaseError(nextEffect, error); + nextEffect = nextEffect.nextEffect; + } + } + } while (nextEffect !== null); + stopCommitSnapshotEffectsTimer(); + + if (enableProfilerTimer) { + // Mark the current commit time to be shared by all Profilers in this + // batch. This enables them to be grouped later. + recordCommitTime(); + } + + // The next phase is the mutation phase, where we mutate the host tree. + startCommitHostEffectsTimer(); + nextEffect = firstEffect; + do { + { + invokeGuardedCallback(null, commitMutationEffects, null); + if (hasCaughtError()) { + (function() { + if (!(nextEffect !== null)) { + throw ReactError("Should be working on an effect."); + } + })(); + var _error = clearCaughtError(); + captureCommitPhaseError(nextEffect, _error); + nextEffect = nextEffect.nextEffect; + } + } + } while (nextEffect !== null); + stopCommitHostEffectsTimer(); + resetAfterCommit(root.containerInfo); + + // The work-in-progress tree is now the current tree. This must come after + // the mutation phase, so that the previous tree is still current during + // componentWillUnmount, but before the layout phase, so that the finished + // work is current during componentDidMount/Update. + root.current = finishedWork; + + // The next phase is the layout phase, where we call effects that read + // the host tree after it's been mutated. The idiomatic use case for this is + // layout, but class component lifecycles also fire here for legacy reasons. + startCommitLifeCyclesTimer(); + nextEffect = firstEffect; + do { + { + invokeGuardedCallback( + null, + commitLayoutEffects, + null, + root, + expirationTime + ); + if (hasCaughtError()) { + (function() { + if (!(nextEffect !== null)) { + throw ReactError("Should be working on an effect."); + } + })(); + var _error2 = clearCaughtError(); + captureCommitPhaseError(nextEffect, _error2); + nextEffect = nextEffect.nextEffect; + } + } + } while (nextEffect !== null); + stopCommitLifeCyclesTimer(); + + nextEffect = null; + + if (enableSchedulerTracing) { + tracing.__interactionsRef.current = prevInteractions; + } + workPhase = prevWorkPhase; + } else { + // No effects. + root.current = finishedWork; + // Measure these anyway so the flamegraph explicitly shows that there were + // no effects. + // TODO: Maybe there's a better way to report this. + startCommitSnapshotEffectsTimer(); + stopCommitSnapshotEffectsTimer(); + if (enableProfilerTimer) { + recordCommitTime(); + } + startCommitHostEffectsTimer(); + stopCommitHostEffectsTimer(); + startCommitLifeCyclesTimer(); + stopCommitLifeCyclesTimer(); + } + + stopCommitTimer(); + + if (rootDoesHavePassiveEffects) { + // This commit has passive effects. Stash a reference to them. But don't + // schedule a callback until after flushing layout work. + rootDoesHavePassiveEffects = false; + rootWithPendingPassiveEffects = root; + pendingPassiveEffectsExpirationTime = expirationTime; + } else { + if (enableSchedulerTracing) { + // If there are no passive effects, then we can complete the pending + // interactions. Otherwise, we'll wait until after the passive effects + // are flushed. + finishPendingInteractions(root, expirationTime); + } + } + + // Check if there's remaining work on this root + var remainingExpirationTime = root.firstPendingTime; + if (remainingExpirationTime !== NoWork) { + var currentTime = requestCurrentTime(); + var priorityLevel = inferPriorityFromExpirationTime( + currentTime, + remainingExpirationTime + ); + scheduleCallbackForRoot(root, priorityLevel, remainingExpirationTime); + } else { + // If there's no remaining work, we can clear the set of already failed + // error boundaries. + legacyErrorBoundariesThatAlreadyFailed = null; + } + + onCommitRoot(finishedWork.stateNode); + + if (remainingExpirationTime === Sync) { + // Count the number of times the root synchronously re-renders without + // finishing. If there are too many, it indicates an infinite update loop. + if (root === rootWithNestedUpdates) { + nestedUpdateCount++; + } else { + nestedUpdateCount = 0; + rootWithNestedUpdates = root; + } + } else { + nestedUpdateCount = 0; + } + + if (hasUncaughtError) { + hasUncaughtError = false; + var _error3 = firstUncaughtError; + firstUncaughtError = null; + throw _error3; + } + + if (workPhase === LegacyUnbatchedPhase) { + // This is a legacy edge case. We just committed the initial mount of + // a ReactDOM.render-ed root inside of batchedUpdates. The commit fired + // synchronously, but layout updates should be deferred until the end + // of the batch. + return null; + } + + // If layout work was scheduled, flush it now. + flushImmediateQueue(); + return null; +} + +function commitBeforeMutationEffects() { + while (nextEffect !== null) { + if ((nextEffect.effectTag & Snapshot) !== NoEffect) { + setCurrentFiber(nextEffect); + recordEffect(); + + var current$$1 = nextEffect.alternate; + commitBeforeMutationLifeCycles(current$$1, nextEffect); + + resetCurrentFiber(); + } + nextEffect = nextEffect.nextEffect; + } +} + +function commitMutationEffects() { + // TODO: Should probably move the bulk of this function to commitWork. + while (nextEffect !== null) { + setCurrentFiber(nextEffect); + + var effectTag = nextEffect.effectTag; + + if (effectTag & ContentReset) { + commitResetTextContent(nextEffect); + } + + if (effectTag & Ref) { + var current$$1 = nextEffect.alternate; + if (current$$1 !== null) { + commitDetachRef(current$$1); + } + } + + // The following switch statement is only concerned about placement, + // updates, and deletions. To avoid needing to add a case for every possible + // bitmap value, we remove the secondary effects from the effect tag and + // switch on that value. + var primaryEffectTag = effectTag & (Placement | Update | Deletion); + switch (primaryEffectTag) { + case Placement: { + commitPlacement(nextEffect); + // Clear the "placement" from effect tag so that we know that this is + // inserted, before any life-cycles like componentDidMount gets called. + // TODO: findDOMNode doesn't rely on this any more but isMounted does + // and isMounted is deprecated anyway so we should be able to kill this. + nextEffect.effectTag &= ~Placement; + break; + } + case PlacementAndUpdate: { + // Placement + commitPlacement(nextEffect); + // Clear the "placement" from effect tag so that we know that this is + // inserted, before any life-cycles like componentDidMount gets called. + nextEffect.effectTag &= ~Placement; + + // Update + var _current = nextEffect.alternate; + commitWork(_current, nextEffect); + break; + } + case Update: { + var _current2 = nextEffect.alternate; + commitWork(_current2, nextEffect); + break; + } + case Deletion: { + commitDeletion(nextEffect); + break; + } + } + + // TODO: Only record a mutation effect if primaryEffectTag is non-zero. + recordEffect(); + + resetCurrentFiber(); + nextEffect = nextEffect.nextEffect; + } +} + +function commitLayoutEffects(root, committedExpirationTime) { + // TODO: Should probably move the bulk of this function to commitWork. + while (nextEffect !== null) { + setCurrentFiber(nextEffect); + + var effectTag = nextEffect.effectTag; + + if (effectTag & (Update | Callback)) { + recordEffect(); + var current$$1 = nextEffect.alternate; + commitLifeCycles(root, current$$1, nextEffect, committedExpirationTime); + } + + if (effectTag & Ref) { + recordEffect(); + commitAttachRef(nextEffect); + } + + if (effectTag & Passive) { + rootDoesHavePassiveEffects = true; + } + + resetCurrentFiber(); + nextEffect = nextEffect.nextEffect; + } +} + +function flushPassiveEffects() { + if (rootWithPendingPassiveEffects === null) { + return false; + } + var root = rootWithPendingPassiveEffects; + var expirationTime = pendingPassiveEffectsExpirationTime; + rootWithPendingPassiveEffects = null; + pendingPassiveEffectsExpirationTime = NoWork; + + var prevInteractions = null; + if (enableSchedulerTracing) { + prevInteractions = tracing.__interactionsRef.current; + tracing.__interactionsRef.current = root.memoizedInteractions; + } + + (function() { + if (!(workPhase !== RenderPhase && workPhase !== CommitPhase)) { + throw ReactError("Cannot flush passive effects while already rendering."); + } + })(); + var prevWorkPhase = workPhase; + workPhase = CommitPhase; + + // Note: This currently assumes there are no passive effects on the root + // fiber, because the root is not part of its own effect list. This could + // change in the future. + var effect = root.current.firstEffect; + while (effect !== null) { + { + setCurrentFiber(effect); + invokeGuardedCallback(null, commitPassiveHookEffects, null, effect); + if (hasCaughtError()) { + (function() { + if (!(effect !== null)) { + throw ReactError("Should be working on an effect."); + } + })(); + var error = clearCaughtError(); + captureCommitPhaseError(effect, error); + } + resetCurrentFiber(); + } + effect = effect.nextEffect; + } + + if (enableSchedulerTracing) { + tracing.__interactionsRef.current = prevInteractions; + finishPendingInteractions(root, expirationTime); + } + + workPhase = prevWorkPhase; + flushImmediateQueue(); + + // If additional passive effects were scheduled, increment a counter. If this + // exceeds the limit, we'll fire a warning. + nestedPassiveUpdateCount = + rootWithPendingPassiveEffects === null ? 0 : nestedPassiveUpdateCount + 1; + + return true; +} + +function isAlreadyFailedLegacyErrorBoundary(instance) { + return ( + legacyErrorBoundariesThatAlreadyFailed !== null && + legacyErrorBoundariesThatAlreadyFailed.has(instance) + ); +} + +function markLegacyErrorBoundaryAsFailed(instance) { + if (legacyErrorBoundariesThatAlreadyFailed === null) { + legacyErrorBoundariesThatAlreadyFailed = new Set([instance]); + } else { + legacyErrorBoundariesThatAlreadyFailed.add(instance); + } +} + +function prepareToThrowUncaughtError(error) { + if (!hasUncaughtError) { + hasUncaughtError = true; + firstUncaughtError = error; + } +} +var onUncaughtError = prepareToThrowUncaughtError; + +function captureCommitPhaseErrorOnRoot(rootFiber, sourceFiber, error) { + var errorInfo = createCapturedValue(error, sourceFiber); + var update = createRootErrorUpdate(rootFiber, errorInfo, Sync); + enqueueUpdate(rootFiber, update); + var root = markUpdateTimeFromFiberToRoot(rootFiber, Sync); + if (root !== null) { + scheduleCallbackForRoot(root, ImmediatePriority, Sync); + } +} + +function captureCommitPhaseError(sourceFiber, error) { + if (sourceFiber.tag === HostRoot) { + // Error was thrown at the root. There is no parent, so the root + // itself should capture it. + captureCommitPhaseErrorOnRoot(sourceFiber, sourceFiber, error); + return; + } + + var fiber = sourceFiber.return; + while (fiber !== null) { + if (fiber.tag === HostRoot) { + captureCommitPhaseErrorOnRoot(fiber, sourceFiber, error); + return; + } else if (fiber.tag === ClassComponent) { + var ctor = fiber.type; + var instance = fiber.stateNode; + if ( + typeof ctor.getDerivedStateFromError === "function" || + (typeof instance.componentDidCatch === "function" && + !isAlreadyFailedLegacyErrorBoundary(instance)) + ) { + var errorInfo = createCapturedValue(error, sourceFiber); + var update = createClassErrorUpdate( + fiber, + errorInfo, + // TODO: This is always sync + Sync + ); + enqueueUpdate(fiber, update); + var root = markUpdateTimeFromFiberToRoot(fiber, Sync); + if (root !== null) { + scheduleCallbackForRoot(root, ImmediatePriority, Sync); + } + return; + } + } + fiber = fiber.return; + } +} + +function pingSuspendedRoot(root, thenable, suspendedTime) { + var pingCache = root.pingCache; + if (pingCache !== null) { + // The thenable resolved, so we no longer need to memoize, because it will + // never be thrown again. + pingCache.delete(thenable); + } + + if (workInProgressRoot === root && renderExpirationTime === suspendedTime) { + // Received a ping at the same priority level at which we're currently + // rendering. Restart from the root. Don't need to schedule a ping because + // we're already working on this tree. + prepareFreshStack(root, renderExpirationTime); + return; + } + + var lastPendingTime = root.lastPendingTime; + if (lastPendingTime < suspendedTime) { + // The root is no longer suspended at this time. + return; + } + + var pingTime = root.pingTime; + if (pingTime !== NoWork && pingTime < suspendedTime) { + // There's already a lower priority ping scheduled. + return; + } + + // Mark the time at which this ping was scheduled. + root.pingTime = suspendedTime; + + var currentTime = requestCurrentTime(); + var priorityLevel = inferPriorityFromExpirationTime( + currentTime, + suspendedTime + ); + scheduleCallbackForRoot(root, priorityLevel, suspendedTime); +} + +function retryTimedOutBoundary(boundaryFiber) { + // The boundary fiber (a Suspense component) previously timed out and was + // rendered in its fallback state. One of the promises that suspended it has + // resolved, which means at least part of the tree was likely unblocked. Try + // rendering again, at a new expiration time. + var currentTime = requestCurrentTime(); + var retryTime = computeExpirationForFiber(currentTime, boundaryFiber); + // TODO: Special case idle priority? + var priorityLevel = inferPriorityFromExpirationTime(currentTime, retryTime); + var root = markUpdateTimeFromFiberToRoot(boundaryFiber, retryTime); + if (root !== null) { + scheduleCallbackForRoot(root, priorityLevel, retryTime); + } +} + +function resolveRetryThenable(boundaryFiber, thenable) { + var retryCache = void 0; + if (enableSuspenseServerRenderer) { + switch (boundaryFiber.tag) { + case SuspenseComponent: + retryCache = boundaryFiber.stateNode; + break; + case DehydratedSuspenseComponent: + retryCache = boundaryFiber.memoizedState; + break; + default: + (function() { + { + throw ReactError( + "Pinged unknown suspense boundary type. This is probably a bug in React." + ); + } + })(); + } + } else { + retryCache = boundaryFiber.stateNode; + } + + if (retryCache !== null) { + // The thenable resolved, so we no longer need to memoize, because it will + // never be thrown again. + retryCache.delete(thenable); + } + + retryTimedOutBoundary(boundaryFiber); +} + +// Computes the next Just Noticeable Difference (JND) boundary. +// The theory is that a person can't tell the difference between small differences in time. +// Therefore, if we wait a bit longer than necessary that won't translate to a noticeable +// difference in the experience. However, waiting for longer might mean that we can avoid +// showing an intermediate loading state. The longer we have already waited, the harder it +// is to tell small differences in time. Therefore, the longer we've already waited, +// the longer we can wait additionally. At some point we have to give up though. +// We pick a train model where the next boundary commits at a consistent schedule. +// These particular numbers are vague estimates. We expect to adjust them based on research. +function jnd(timeElapsed) { + return timeElapsed < 120 + ? 120 + : timeElapsed < 480 + ? 480 + : timeElapsed < 1080 + ? 1080 + : timeElapsed < 1920 + ? 1920 + : timeElapsed < 3000 + ? 3000 + : timeElapsed < 4320 + ? 4320 + : ceil(timeElapsed / 1960) * 1960; +} + +function computeMsUntilTimeout(mostRecentEventTime, committedExpirationTime) { + if (disableYielding) { + // Timeout immediately when yielding is disabled. + return 0; + } + + var eventTimeMs = inferTimeFromExpirationTime(mostRecentEventTime); + var currentTimeMs = now(); + var timeElapsed = currentTimeMs - eventTimeMs; + + var msUntilTimeout = jnd(timeElapsed) - timeElapsed; + + // Compute the time until this render pass would expire. + var timeUntilExpirationMs = + expirationTimeToMs(committedExpirationTime) - currentTimeMs; + + // Clamp the timeout to the expiration time. + // TODO: Once the event time is exact instead of inferred from expiration time + // we don't need this. + if (timeUntilExpirationMs < msUntilTimeout) { + msUntilTimeout = timeUntilExpirationMs; + } + + // This is the value that is passed to `setTimeout`. + return msUntilTimeout; +} + +function checkForNestedUpdates() { + if (nestedUpdateCount > NESTED_UPDATE_LIMIT) { + nestedUpdateCount = 0; + rootWithNestedUpdates = null; + (function() { + { + throw ReactError( + "Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops." + ); + } + })(); + } + + { + if (nestedPassiveUpdateCount > NESTED_PASSIVE_UPDATE_LIMIT) { + nestedPassiveUpdateCount = 0; + warning$1( + false, + "Maximum update depth exceeded. This can happen when a component " + + "calls setState inside useEffect, but useEffect either doesn't " + + "have a dependency array, or one of the dependencies changes on " + + "every render." + ); + } + } +} + +function flushRenderPhaseStrictModeWarningsInDEV() { + { + ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings(); + ReactStrictModeWarnings.flushLegacyContextWarning(); + + if (warnAboutDeprecatedLifecycles) { + ReactStrictModeWarnings.flushPendingDeprecationWarnings(); + } + } +} + +function stopFinishedWorkLoopTimer() { + var didCompleteRoot = true; + stopWorkLoopTimer(interruptedBy, didCompleteRoot); + interruptedBy = null; +} + +function stopInterruptedWorkLoopTimer() { + // TODO: Track which fiber caused the interruption. + var didCompleteRoot = false; + stopWorkLoopTimer(interruptedBy, didCompleteRoot); + interruptedBy = null; +} + +function checkForInterruption(fiberThatReceivedUpdate, updateExpirationTime) { + if ( + enableUserTimingAPI && + workInProgressRoot !== null && + updateExpirationTime > renderExpirationTime + ) { + interruptedBy = fiberThatReceivedUpdate; + } +} + +var didWarnStateUpdateForUnmountedComponent = null; +function warnAboutUpdateOnUnmountedFiberInDEV(fiber) { + { + var tag = fiber.tag; + if ( + tag !== HostRoot && + tag !== ClassComponent && + tag !== FunctionComponent && + tag !== ForwardRef && + tag !== MemoComponent && + tag !== SimpleMemoComponent + ) { + // Only warn for user-defined components, not internal ones like Suspense. + return; + } + // We show the whole stack but dedupe on the top component's name because + // the problematic code almost always lies inside that component. + var componentName = getComponentName(fiber.type) || "ReactComponent"; + if (didWarnStateUpdateForUnmountedComponent !== null) { + if (didWarnStateUpdateForUnmountedComponent.has(componentName)) { + return; + } + didWarnStateUpdateForUnmountedComponent.add(componentName); + } else { + didWarnStateUpdateForUnmountedComponent = new Set([componentName]); + } + warningWithoutStack$1( + false, + "Can't perform a React state update on an unmounted component. This " + + "is a no-op, but it indicates a memory leak in your application. To " + + "fix, cancel all subscriptions and asynchronous tasks in %s.%s", + tag === ClassComponent + ? "the componentWillUnmount method" + : "a useEffect cleanup function", + getStackByFiberInDevAndProd(fiber) + ); + } +} + +var beginWork$$1 = void 0; +if (true && replayFailedUnitOfWorkWithInvokeGuardedCallback) { + var dummyFiber = null; + beginWork$$1 = function(current$$1, unitOfWork, expirationTime) { + // If a component throws an error, we replay it again in a synchronously + // dispatched event, so that the debugger will treat it as an uncaught + // error See ReactErrorUtils for more information. + + // Before entering the begin phase, copy the work-in-progress onto a dummy + // fiber. If beginWork throws, we'll use this to reset the state. + var originalWorkInProgressCopy = assignFiberPropertiesInDEV( + dummyFiber, + unitOfWork + ); + try { + return beginWork$1(current$$1, unitOfWork, expirationTime); + } catch (originalError) { + if ( + originalError !== null && + typeof originalError === "object" && + typeof originalError.then === "function" + ) { + // Don't replay promises. Treat everything else like an error. + throw originalError; + } + + // Keep this code in sync with renderRoot; any changes here must have + // corresponding changes there. + resetContextDependences(); + resetHooks(); + + // Unwind the failed stack frame + unwindInterruptedWork(unitOfWork); + + // Restore the original properties of the fiber. + assignFiberPropertiesInDEV(unitOfWork, originalWorkInProgressCopy); + + if (enableProfilerTimer && unitOfWork.mode & ProfileMode) { + // Reset the profiler timer. + startProfilerTimer(unitOfWork); + } + + // Run beginWork again. + invokeGuardedCallback( + null, + beginWork$1, + null, + current$$1, + unitOfWork, + expirationTime + ); + + if (hasCaughtError()) { + var replayError = clearCaughtError(); + // `invokeGuardedCallback` sometimes sets an expando `_suppressLogging`. + // Rethrow this error instead of the original one. + throw replayError; + } else { + // This branch is reachable if the render phase is impure. + throw originalError; + } + } + }; +} else { + beginWork$$1 = beginWork$1; +} + +var didWarnAboutUpdateInRender = false; +var didWarnAboutUpdateInGetChildContext = false; +function warnAboutInvalidUpdatesOnClassComponentsInDEV(fiber) { + { + if (fiber.tag === ClassComponent) { + switch (phase) { + case "getChildContext": + if (didWarnAboutUpdateInGetChildContext) { + return; + } + warningWithoutStack$1( + false, + "setState(...): Cannot call setState() inside getChildContext()" + ); + didWarnAboutUpdateInGetChildContext = true; + break; + case "render": + if (didWarnAboutUpdateInRender) { + return; + } + warningWithoutStack$1( + false, + "Cannot update during an existing state transition (such as " + + "within `render`). Render methods should be a pure function of " + + "props and state." + ); + didWarnAboutUpdateInRender = true; + break; + } + } + } +} + +function warnIfNotCurrentlyActingUpdatesInDEV(fiber) { + { + if ( + workPhase === NotWorking && + ReactShouldWarnActingUpdates.current === false + ) { + warningWithoutStack$1( + false, + "An update to %s inside a test was not wrapped in act(...).\n\n" + + "When testing, code that causes React state updates should be " + + "wrapped into act(...):\n\n" + + "act(() => {\n" + + " /* fire events that update state */\n" + + "});\n" + + "/* assert on the output */\n\n" + + "This ensures that you're testing the behavior the user would see " + + "in the browser." + + " Learn more at https://fb.me/react-wrap-tests-with-act" + + "%s", + getComponentName(fiber.type), + getStackByFiberInDevAndProd(fiber) + ); + } + } +} + +var warnIfNotCurrentlyActingUpdatesInDev = warnIfNotCurrentlyActingUpdatesInDEV; + +function computeThreadID(root, expirationTime) { + // Interaction threads are unique per root and expiration time. + return expirationTime * 1000 + root.interactionThreadID; +} + +function schedulePendingInteraction(root, expirationTime) { + // This is called when work is scheduled on a root. It sets up a pending + // interaction, which is completed once the work commits. + if (!enableSchedulerTracing) { + return; + } + + var interactions = tracing.__interactionsRef.current; + if (interactions.size > 0) { + var pendingInteractionMap = root.pendingInteractionMap; + var pendingInteractions = pendingInteractionMap.get(expirationTime); + if (pendingInteractions != null) { + interactions.forEach(function(interaction) { + if (!pendingInteractions.has(interaction)) { + // Update the pending async work count for previously unscheduled interaction. + interaction.__count++; + } + + pendingInteractions.add(interaction); + }); + } else { + pendingInteractionMap.set(expirationTime, new Set(interactions)); + + // Update the pending async work count for the current interactions. + interactions.forEach(function(interaction) { + interaction.__count++; + }); + } + + var subscriber = tracing.__subscriberRef.current; + if (subscriber !== null) { + var threadID = computeThreadID(root, expirationTime); + subscriber.onWorkScheduled(interactions, threadID); + } + } +} + +function startWorkOnPendingInteraction(root, expirationTime) { + // This is called when new work is started on a root. + if (!enableSchedulerTracing) { + return; + } + + // Determine which interactions this batch of work currently includes, So that + // we can accurately attribute time spent working on it, And so that cascading + // work triggered during the render phase will be associated with it. + var interactions = new Set(); + root.pendingInteractionMap.forEach(function( + scheduledInteractions, + scheduledExpirationTime + ) { + if (scheduledExpirationTime >= expirationTime) { + scheduledInteractions.forEach(function(interaction) { + return interactions.add(interaction); + }); + } + }); + + // Store the current set of interactions on the FiberRoot for a few reasons: + // We can re-use it in hot functions like renderRoot() without having to + // recalculate it. We will also use it in commitWork() to pass to any Profiler + // onRender() hooks. This also provides DevTools with a way to access it when + // the onCommitRoot() hook is called. + root.memoizedInteractions = interactions; + + if (interactions.size > 0) { + var subscriber = tracing.__subscriberRef.current; + if (subscriber !== null) { + var threadID = computeThreadID(root, expirationTime); + try { + subscriber.onWorkStarted(interactions, threadID); + } catch (error) { + // If the subscriber throws, rethrow it in a separate task + scheduleCallback(ImmediatePriority, function() { + throw error; + }); + } + } + } +} + +function finishPendingInteractions(root, committedExpirationTime) { + if (!enableSchedulerTracing) { + return; + } + + var earliestRemainingTimeAfterCommit = root.firstPendingTime; + + var subscriber = void 0; + + try { + subscriber = tracing.__subscriberRef.current; + if (subscriber !== null && root.memoizedInteractions.size > 0) { + var threadID = computeThreadID(root, committedExpirationTime); + subscriber.onWorkStopped(root.memoizedInteractions, threadID); + } + } catch (error) { + // If the subscriber throws, rethrow it in a separate task + scheduleCallback(ImmediatePriority, function() { + throw error; + }); + } finally { + // Clear completed interactions from the pending Map. + // Unless the render was suspended or cascading work was scheduled, + // In which case– leave pending interactions until the subsequent render. + var pendingInteractionMap = root.pendingInteractionMap; + pendingInteractionMap.forEach(function( + scheduledInteractions, + scheduledExpirationTime + ) { + // Only decrement the pending interaction count if we're done. + // If there's still work at the current priority, + // That indicates that we are waiting for suspense data. + if (scheduledExpirationTime > earliestRemainingTimeAfterCommit) { + pendingInteractionMap.delete(scheduledExpirationTime); + + scheduledInteractions.forEach(function(interaction) { + interaction.__count--; + + if (subscriber !== null && interaction.__count === 0) { + try { + subscriber.onInteractionScheduledWorkCompleted(interaction); + } catch (error) { + // If the subscriber throws, rethrow it in a separate task + scheduleCallback(ImmediatePriority, function() { + throw error; + }); + } + } + }); + } + }); + } +} + +// This lets us hook into Fiber to debug what it's doing. +// See https://github.com/facebook/react/pull/8033. +// This is not part of the public API, not even for React DevTools. +// You may only inject a debugTool if you work on React Fiber itself. +var ReactFiberInstrumentation = { + debugTool: null +}; + +var ReactFiberInstrumentation_1 = ReactFiberInstrumentation; + +// 0 is PROD, 1 is DEV. +// Might add PROFILE later. + +var didWarnAboutNestedUpdates = void 0; +var didWarnAboutFindNodeInStrictMode = void 0; + +{ + didWarnAboutNestedUpdates = false; + didWarnAboutFindNodeInStrictMode = {}; +} + +function getContextForSubtree(parentComponent) { + if (!parentComponent) { + return emptyContextObject; + } + + var fiber = get(parentComponent); + var parentContext = findCurrentUnmaskedContext(fiber); + + if (fiber.tag === ClassComponent) { + var Component = fiber.type; + if (isContextProvider(Component)) { + return processChildContext(fiber, Component, parentContext); + } + } + + return parentContext; +} + +function scheduleRootUpdate(current$$1, element, expirationTime, callback) { + { + if (phase === "render" && current !== null && !didWarnAboutNestedUpdates) { + didWarnAboutNestedUpdates = true; + warningWithoutStack$1( + false, + "Render methods should be a pure function of props and state; " + + "triggering nested component updates from render is not allowed. " + + "If necessary, trigger nested updates in componentDidUpdate.\n\n" + + "Check the render method of %s.", + getComponentName(current.type) || "Unknown" + ); + } + } + + var update = createUpdate(expirationTime); + // Caution: React DevTools currently depends on this property + // being called "element". + update.payload = { element: element }; + + callback = callback === undefined ? null : callback; + if (callback !== null) { + !(typeof callback === "function") + ? warningWithoutStack$1( + false, + "render(...): Expected the last optional `callback` argument to be a " + + "function. Instead received: %s.", + callback + ) + : void 0; + update.callback = callback; + } + + flushPassiveEffects(); + enqueueUpdate(current$$1, update); + scheduleWork(current$$1, expirationTime); + + return expirationTime; +} + +function updateContainerAtExpirationTime( + element, + container, + parentComponent, + expirationTime, + callback +) { + // TODO: If this is a nested container, this won't be the root. + var current$$1 = container.current; + + { + if (ReactFiberInstrumentation_1.debugTool) { + if (current$$1.alternate === null) { + ReactFiberInstrumentation_1.debugTool.onMountContainer(container); + } else if (element === null) { + ReactFiberInstrumentation_1.debugTool.onUnmountContainer(container); + } else { + ReactFiberInstrumentation_1.debugTool.onUpdateContainer(container); + } + } + } + + var context = getContextForSubtree(parentComponent); + if (container.context === null) { + container.context = context; + } else { + container.pendingContext = context; + } + + return scheduleRootUpdate(current$$1, element, expirationTime, callback); +} + +function findHostInstance(component) { + var fiber = get(component); + if (fiber === undefined) { + if (typeof component.render === "function") { + (function() { + { + throw ReactError("Unable to find node on an unmounted component."); + } + })(); + } else { + (function() { + { + throw ReactError( + "Argument appears to not be a ReactComponent. Keys: " + + Object.keys(component) + ); + } + })(); + } + } + var hostFiber = findCurrentHostFiber(fiber); + if (hostFiber === null) { + return null; + } + return hostFiber.stateNode; +} + +function findHostInstanceWithWarning(component, methodName) { + { + var fiber = get(component); + if (fiber === undefined) { + if (typeof component.render === "function") { + (function() { + { + throw ReactError("Unable to find node on an unmounted component."); + } + })(); + } else { + (function() { + { + throw ReactError( + "Argument appears to not be a ReactComponent. Keys: " + + Object.keys(component) + ); + } + })(); + } + } + var hostFiber = findCurrentHostFiber(fiber); + if (hostFiber === null) { + return null; + } + if (hostFiber.mode & StrictMode) { + var componentName = getComponentName(fiber.type) || "Component"; + if (!didWarnAboutFindNodeInStrictMode[componentName]) { + didWarnAboutFindNodeInStrictMode[componentName] = true; + if (fiber.mode & StrictMode) { + warningWithoutStack$1( + false, + "%s is deprecated in StrictMode. " + + "%s was passed an instance of %s which is inside StrictMode. " + + "Instead, add a ref directly to the element you want to reference." + + "\n%s" + + "\n\nLearn more about using refs safely here:" + + "\nhttps://fb.me/react-strict-mode-find-node", + methodName, + methodName, + componentName, + getStackByFiberInDevAndProd(hostFiber) + ); + } else { + warningWithoutStack$1( + false, + "%s is deprecated in StrictMode. " + + "%s was passed an instance of %s which renders StrictMode children. " + + "Instead, add a ref directly to the element you want to reference." + + "\n%s" + + "\n\nLearn more about using refs safely here:" + + "\nhttps://fb.me/react-strict-mode-find-node", + methodName, + methodName, + componentName, + getStackByFiberInDevAndProd(hostFiber) + ); + } + } + } + return hostFiber.stateNode; + } + return findHostInstance(component); +} + +function createContainer(containerInfo, isConcurrent, hydrate) { + return createFiberRoot(containerInfo, isConcurrent, hydrate); +} + +function updateContainer(element, container, parentComponent, callback) { + var current$$1 = container.current; + var currentTime = requestCurrentTime(); + var expirationTime = computeExpirationForFiber(currentTime, current$$1); + return updateContainerAtExpirationTime( + element, + container, + parentComponent, + expirationTime, + callback + ); +} + +function getPublicRootInstance(container) { + var containerFiber = container.current; + if (!containerFiber.child) { + return null; + } + switch (containerFiber.child.tag) { + case HostComponent: + return getPublicInstance(containerFiber.child.stateNode); + default: + return containerFiber.child.stateNode; + } +} + +var shouldSuspendImpl = function(fiber) { + return false; +}; + +function shouldSuspend(fiber) { + return shouldSuspendImpl(fiber); +} + +var overrideHookState = null; +var overrideProps = null; +var scheduleUpdate = null; +var setSuspenseHandler = null; + +{ + var copyWithSetImpl = function(obj, path, idx, value) { + if (idx >= path.length) { + return value; + } + var key = path[idx]; + var updated = Array.isArray(obj) ? obj.slice() : Object.assign({}, obj); + // $FlowFixMe number or string is fine here + updated[key] = copyWithSetImpl(obj[key], path, idx + 1, value); + return updated; + }; + + var copyWithSet = function(obj, path, value) { + return copyWithSetImpl(obj, path, 0, value); + }; + + // Support DevTools editable values for useState and useReducer. + overrideHookState = function(fiber, id, path, value) { + // For now, the "id" of stateful hooks is just the stateful hook index. + // This may change in the future with e.g. nested hooks. + var currentHook = fiber.memoizedState; + while (currentHook !== null && id > 0) { + currentHook = currentHook.next; + id--; + } + if (currentHook !== null) { + flushPassiveEffects(); + + var newState = copyWithSet(currentHook.memoizedState, path, value); + currentHook.memoizedState = newState; + currentHook.baseState = newState; + + // We aren't actually adding an update to the queue, + // because there is no update we can add for useReducer hooks that won't trigger an error. + // (There's no appropriate action type for DevTools overrides.) + // As a result though, React will see the scheduled update as a noop and bailout. + // Shallow cloning props works as a workaround for now to bypass the bailout check. + fiber.memoizedProps = Object.assign({}, fiber.memoizedProps); + + scheduleWork(fiber, Sync); + } + }; + + // Support DevTools props for function components, forwardRef, memo, host components, etc. + overrideProps = function(fiber, path, value) { + flushPassiveEffects(); + fiber.pendingProps = copyWithSet(fiber.memoizedProps, path, value); + if (fiber.alternate) { + fiber.alternate.pendingProps = fiber.pendingProps; + } + scheduleWork(fiber, Sync); + }; + + scheduleUpdate = function(fiber) { + flushPassiveEffects(); + scheduleWork(fiber, Sync); + }; + + setSuspenseHandler = function(newShouldSuspendImpl) { + shouldSuspendImpl = newShouldSuspendImpl; + }; +} + +function injectIntoDevTools(devToolsConfig) { + var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; + var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher; + + return injectInternals( + Object.assign({}, devToolsConfig, { + overrideHookState: overrideHookState, + overrideProps: overrideProps, + setSuspenseHandler: setSuspenseHandler, + scheduleUpdate: scheduleUpdate, + currentDispatcherRef: ReactCurrentDispatcher, + findHostInstanceByFiber: function(fiber) { + var hostFiber = findCurrentHostFiber(fiber); + if (hostFiber === null) { + return null; + } + return hostFiber.stateNode; + }, + findFiberByHostInstance: function(instance) { + if (!findFiberByHostInstance) { + // Might not be implemented by the renderer. + return null; + } + return findFiberByHostInstance(instance); + } + }) + ); +} + +// This file intentionally does *not* have the Flow annotation. +// Don't add it. See `./inline-typed.js` for an explanation. + +function createPortal( + children, + containerInfo, + // TODO: figure out the API for cross-renderer implementation. + implementation +) { + var key = + arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; + + return { + // This tag allow us to uniquely identify this as a React Portal + $$typeof: REACT_PORTAL_TYPE, + key: key == null ? null : "" + key, + children: children, + containerInfo: containerInfo, + implementation: implementation + }; +} + +// TODO: this is special because it gets imported during build. + +var ReactVersion = "16.8.6"; + +// Modules provided by RN: +var NativeMethodsMixin = function(findNodeHandle, findHostInstance) { + /** + * `NativeMethodsMixin` provides methods to access the underlying native + * component directly. This can be useful in cases when you want to focus + * a view or measure its on-screen dimensions, for example. + * + * The methods described here are available on most of the default components + * provided by React Native. Note, however, that they are *not* available on + * composite components that aren't directly backed by a native view. This will + * generally include most components that you define in your own app. For more + * information, see [Direct + * Manipulation](docs/direct-manipulation.html). + * + * Note the Flow $Exact<> syntax is required to support mixins. + * React createClass mixins can only be used with exact types. + */ + var NativeMethodsMixin = { + /** + * Determines the location on screen, width, and height of the given view and + * returns the values via an async callback. If successful, the callback will + * be called with the following arguments: + * + * - x + * - y + * - width + * - height + * - pageX + * - pageY + * + * Note that these measurements are not available until after the rendering + * has been completed in native. If you need the measurements as soon as + * possible, consider using the [`onLayout` + * prop](docs/view.html#onlayout) instead. + */ + measure: function(callback) { + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + if (maybeInstance.canonical) { + // We can't call FabricUIManager here because it won't be loaded in paper + // at initialization time. See https://github.com/facebook/react/pull/15490 + // for more info. + nativeFabricUIManager.measure( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + } else { + ReactNativePrivateInterface.UIManager.measure( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + } + }, + + /** + * Determines the location of the given view in the window and returns the + * values via an async callback. If the React root view is embedded in + * another native view, this will give you the absolute coordinates. If + * successful, the callback will be called with the following + * arguments: + * + * - x + * - y + * - width + * - height + * + * Note that these measurements are not available until after the rendering + * has been completed in native. + */ + measureInWindow: function(callback) { + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + if (maybeInstance.canonical) { + // We can't call FabricUIManager here because it won't be loaded in paper + // at initialization time. See https://github.com/facebook/react/pull/15490 + // for more info. + nativeFabricUIManager.measureInWindow( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + } else { + ReactNativePrivateInterface.UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + } + }, + + /** + * Like [`measure()`](#measure), but measures the view relative an ancestor, + * specified as `relativeToNativeNode`. This means that the returned x, y + * are relative to the origin x, y of the ancestor view. + * + * As always, to obtain a native node handle for a component, you can use + * `findNodeHandle(component)`. + */ + measureLayout: function( + relativeToNativeNode, + onSuccess, + onFail /* currently unused */ + ) { + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + if (maybeInstance.canonical) { + warningWithoutStack$1( + false, + "Warning: measureLayout on components using NativeMethodsMixin " + + "or ReactNative.NativeComponent is not currently supported in Fabric. " + + "measureLayout must be called on a native ref. Consider using forwardRef." + ); + return; + } else { + var relativeNode = void 0; + + if (typeof relativeToNativeNode === "number") { + // Already a node handle + relativeNode = relativeToNativeNode; + } else if (relativeToNativeNode._nativeTag) { + relativeNode = relativeToNativeNode._nativeTag; + } + + if (relativeNode == null) { + warningWithoutStack$1( + false, + "Warning: ref.measureLayout must be called with a node handle or a ref to a native component." + ); + + return; + } + + ReactNativePrivateInterface.UIManager.measureLayout( + findNodeHandle(this), + relativeNode, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + ); + } + }, + + /** + * This function sends props straight to native. They will not participate in + * future diff process - this means that if you do not include them in the + * next render, they will remain active (see [Direct + * Manipulation](docs/direct-manipulation.html)). + */ + setNativeProps: function(nativeProps) { + // Class components don't have viewConfig -> validateAttributes. + // Nor does it make sense to set native props on a non-native component. + // Instead, find the nearest host component and set props on it. + // Use findNodeHandle() rather than findNodeHandle() because + // We want the instance/wrapper (not the native tag). + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + if (maybeInstance.canonical) { + warningWithoutStack$1( + false, + "Warning: setNativeProps is not currently supported in Fabric" + ); + return; + } + + { + if (warnAboutDeprecatedSetNativeProps) { + warningWithoutStack$1( + false, + "Warning: Calling ref.setNativeProps(nativeProps) " + + "is deprecated and will be removed in a future release. " + + "Use the setNativeProps export from the react-native package instead." + + "\n\timport {setNativeProps} from 'react-native';\n\tsetNativeProps(ref, nativeProps);\n" + ); + } + } + + var nativeTag = + maybeInstance._nativeTag || maybeInstance.canonical._nativeTag; + var viewConfig = + maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; + + { + warnForStyleProps(nativeProps, viewConfig.validAttributes); + } + + var updatePayload = create(nativeProps, viewConfig.validAttributes); + + // Avoid the overhead of bridge calls if there's no update. + // This is an expensive no-op for Android, and causes an unnecessary + // view invalidation for certain components (eg RCTTextInput) on iOS. + if (updatePayload != null) { + ReactNativePrivateInterface.UIManager.updateView( + nativeTag, + viewConfig.uiViewClassName, + updatePayload + ); + } + }, + + /** + * Requests focus for the given input or view. The exact behavior triggered + * will depend on the platform and type of view. + */ + focus: function() { + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); + }, + + /** + * Removes focus from an input or view. This is the opposite of `focus()`. + */ + blur: function() { + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); + } + }; + + { + // hide this from Flow since we can't define these properties outside of + // true without actually implementing them (setting them to undefined + // isn't allowed by ReactClass) + var NativeMethodsMixin_DEV = NativeMethodsMixin; + (function() { + if ( + !( + !NativeMethodsMixin_DEV.componentWillMount && + !NativeMethodsMixin_DEV.componentWillReceiveProps && + !NativeMethodsMixin_DEV.UNSAFE_componentWillMount && + !NativeMethodsMixin_DEV.UNSAFE_componentWillReceiveProps + ) + ) { + throw ReactError("Do not override existing functions."); + } + })(); + // TODO (bvaughn) Remove cWM and cWRP in a future version of React Native, + // Once these lifecycles have been remove from the reconciler. + NativeMethodsMixin_DEV.componentWillMount = function() { + throwOnStylesProp(this, this.props); + }; + NativeMethodsMixin_DEV.componentWillReceiveProps = function(newProps) { + throwOnStylesProp(this, newProps); + }; + NativeMethodsMixin_DEV.UNSAFE_componentWillMount = function() { + throwOnStylesProp(this, this.props); + }; + NativeMethodsMixin_DEV.UNSAFE_componentWillReceiveProps = function( + newProps + ) { + throwOnStylesProp(this, newProps); + }; + + // React may warn about cWM/cWRP/cWU methods being deprecated. + // Add a flag to suppress these warnings for this special case. + // TODO (bvaughn) Remove this flag once the above methods have been removed. + NativeMethodsMixin_DEV.componentWillMount.__suppressDeprecationWarning = true; + NativeMethodsMixin_DEV.componentWillReceiveProps.__suppressDeprecationWarning = true; + } + + return NativeMethodsMixin; +}; + +function _classCallCheck$1(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } +} + +function _possibleConstructorReturn(self, call) { + if (!self) { + throw new ReferenceError( + "this hasn't been initialised - super() hasn't been called" + ); + } + return call && (typeof call === "object" || typeof call === "function") + ? call + : self; +} + +function _inherits(subClass, superClass) { + if (typeof superClass !== "function" && superClass !== null) { + throw new TypeError( + "Super expression must either be null or a function, not " + + typeof superClass + ); + } + subClass.prototype = Object.create(superClass && superClass.prototype, { + constructor: { + value: subClass, + enumerable: false, + writable: true, + configurable: true + } + }); + if (superClass) + Object.setPrototypeOf + ? Object.setPrototypeOf(subClass, superClass) + : (subClass.__proto__ = superClass); +} + +// Modules provided by RN: +var ReactNativeComponent = function(findNodeHandle, findHostInstance) { + /** + * Superclass that provides methods to access the underlying native component. + * This can be useful when you want to focus a view or measure its dimensions. + * + * Methods implemented by this class are available on most default components + * provided by React Native. However, they are *not* available on composite + * components that are not directly backed by a native view. For more + * information, see [Direct Manipulation](docs/direct-manipulation.html). + * + * @abstract + */ + var ReactNativeComponent = (function(_React$Component) { + _inherits(ReactNativeComponent, _React$Component); + + function ReactNativeComponent() { + _classCallCheck$1(this, ReactNativeComponent); + + return _possibleConstructorReturn( + this, + _React$Component.apply(this, arguments) + ); + } + + /** + * Removes focus. This is the opposite of `focus()`. + */ + + /** + * Due to bugs in Flow's handling of React.createClass, some fields already + * declared in the base class need to be redeclared below. + */ + ReactNativeComponent.prototype.blur = function blur() { + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); + }; + + /** + * Requests focus. The exact behavior depends on the platform and view. + */ + + ReactNativeComponent.prototype.focus = function focus() { + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); + }; + + /** + * Measures the on-screen location and dimensions. If successful, the callback + * will be called asynchronously with the following arguments: + * + * - x + * - y + * - width + * - height + * - pageX + * - pageY + * + * These values are not available until after natives rendering completes. If + * you need the measurements as soon as possible, consider using the + * [`onLayout` prop](docs/view.html#onlayout) instead. + */ + + ReactNativeComponent.prototype.measure = function measure(callback) { + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + if (maybeInstance.canonical) { + // We can't call FabricUIManager here because it won't be loaded in paper + // at initialization time. See https://github.com/facebook/react/pull/15490 + // for more info. + nativeFabricUIManager.measure( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + } else { + ReactNativePrivateInterface.UIManager.measure( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + } + }; + + /** + * Measures the on-screen location and dimensions. Even if the React Native + * root view is embedded within another native view, this method will give you + * the absolute coordinates measured from the window. If successful, the + * callback will be called asynchronously with the following arguments: + * + * - x + * - y + * - width + * - height + * + * These values are not available until after natives rendering completes. + */ + + ReactNativeComponent.prototype.measureInWindow = function measureInWindow( + callback + ) { + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + if (maybeInstance.canonical) { + // We can't call FabricUIManager here because it won't be loaded in paper + // at initialization time. See https://github.com/facebook/react/pull/15490 + // for more info. + nativeFabricUIManager.measureInWindow( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + } else { + ReactNativePrivateInterface.UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + } + }; + + /** + * Similar to [`measure()`](#measure), but the resulting location will be + * relative to the supplied ancestor's location. + * + * Obtain a native node handle with `ReactNative.findNodeHandle(component)`. + */ + + ReactNativeComponent.prototype.measureLayout = function measureLayout( + relativeToNativeNode, + onSuccess, + onFail /* currently unused */ + ) { + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + if (maybeInstance.canonical) { + warningWithoutStack$1( + false, + "Warning: measureLayout on components using NativeMethodsMixin " + + "or ReactNative.NativeComponent is not currently supported in Fabric. " + + "measureLayout must be called on a native ref. Consider using forwardRef." + ); + return; + } else { + var relativeNode = void 0; + + if (typeof relativeToNativeNode === "number") { + // Already a node handle + relativeNode = relativeToNativeNode; + } else if (relativeToNativeNode._nativeTag) { + relativeNode = relativeToNativeNode._nativeTag; + } + + if (relativeNode == null) { + warningWithoutStack$1( + false, + "Warning: ref.measureLayout must be called with a node handle or a ref to a native component." + ); + + return; + } + + ReactNativePrivateInterface.UIManager.measureLayout( + findNodeHandle(this), + relativeNode, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + ); + } + }; + + /** + * This function sends props straight to native. They will not participate in + * future diff process - this means that if you do not include them in the + * next render, they will remain active (see [Direct + * Manipulation](docs/direct-manipulation.html)). + */ + + ReactNativeComponent.prototype.setNativeProps = function setNativeProps( + nativeProps + ) { + // Class components don't have viewConfig -> validateAttributes. + // Nor does it make sense to set native props on a non-native component. + // Instead, find the nearest host component and set props on it. + // Use findNodeHandle() rather than ReactNative.findNodeHandle() because + // We want the instance/wrapper (not the native tag). + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + if (maybeInstance.canonical) { + warningWithoutStack$1( + false, + "Warning: setNativeProps is not currently supported in Fabric" + ); + return; + } + + { + if (warnAboutDeprecatedSetNativeProps) { + warningWithoutStack$1( + false, + "Warning: Calling ref.setNativeProps(nativeProps) " + + "is deprecated and will be removed in a future release. " + + "Use the setNativeProps export from the react-native package instead." + + "\n\timport {setNativeProps} from 'react-native';\n\tsetNativeProps(ref, nativeProps);\n" + ); + } + } + + var nativeTag = + maybeInstance._nativeTag || maybeInstance.canonical._nativeTag; + var viewConfig = + maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; + + var updatePayload = create(nativeProps, viewConfig.validAttributes); + + // Avoid the overhead of bridge calls if there's no update. + // This is an expensive no-op for Android, and causes an unnecessary + // view invalidation for certain components (eg RCTTextInput) on iOS. + if (updatePayload != null) { + ReactNativePrivateInterface.UIManager.updateView( + nativeTag, + viewConfig.uiViewClassName, + updatePayload + ); + } + }; + + return ReactNativeComponent; + })(React.Component); + + // eslint-disable-next-line no-unused-expressions + + return ReactNativeComponent; +}; + +// Module provided by RN: +var emptyObject$1 = {}; +{ + Object.freeze(emptyObject$1); +} + +var getInspectorDataForViewTag = void 0; + +{ + var traverseOwnerTreeUp = function(hierarchy, instance) { + if (instance) { + hierarchy.unshift(instance); + traverseOwnerTreeUp(hierarchy, instance._debugOwner); + } + }; + + var getOwnerHierarchy = function(instance) { + var hierarchy = []; + traverseOwnerTreeUp(hierarchy, instance); + return hierarchy; + }; + + var lastNonHostInstance = function(hierarchy) { + for (var i = hierarchy.length - 1; i > 1; i--) { + var instance = hierarchy[i]; + + if (instance.tag !== HostComponent) { + return instance; + } + } + return hierarchy[0]; + }; + + var getHostProps = function(fiber) { + var host = findCurrentHostFiber(fiber); + if (host) { + return host.memoizedProps || emptyObject$1; + } + return emptyObject$1; + }; + + var getHostNode = function(fiber, findNodeHandle) { + var hostNode = void 0; + // look for children first for the hostNode + // as composite fibers do not have a hostNode + while (fiber) { + if (fiber.stateNode !== null && fiber.tag === HostComponent) { + hostNode = findNodeHandle(fiber.stateNode); + } + if (hostNode) { + return hostNode; + } + fiber = fiber.child; + } + return null; + }; + + var createHierarchy = function(fiberHierarchy) { + return fiberHierarchy.map(function(fiber) { + return { + name: getComponentName(fiber.type), + getInspectorData: function(findNodeHandle) { + return { + measure: function(callback) { + return ReactNativePrivateInterface.UIManager.measure( + getHostNode(fiber, findNodeHandle), + callback + ); + }, + props: getHostProps(fiber), + source: fiber._debugSource + }; + } + }; + }); + }; + + getInspectorDataForViewTag = function(viewTag) { + var closestInstance = getInstanceFromTag(viewTag); + + // Handle case where user clicks outside of ReactNative + if (!closestInstance) { + return { + hierarchy: [], + props: emptyObject$1, + selection: null, + source: null + }; + } + + var fiber = findCurrentFiberUsingSlowPath(closestInstance); + var fiberHierarchy = getOwnerHierarchy(fiber); + var instance = lastNonHostInstance(fiberHierarchy); + var hierarchy = createHierarchy(fiberHierarchy); + var props = getHostProps(instance); + var source = instance._debugSource; + var selection = fiberHierarchy.indexOf(instance); + + return { + hierarchy: hierarchy, + props: props, + selection: selection, + source: source + }; + }; +} + +// Module provided by RN: +function setNativeProps(handle, nativeProps) { + if (handle._nativeTag == null) { + !(handle._nativeTag != null) + ? warningWithoutStack$1( + false, + "setNativeProps was called with a ref that isn't a " + + "native component. Use React.forwardRef to get access to the underlying native component" + ) + : void 0; + return; + } + + { + warnForStyleProps(nativeProps, handle.viewConfig.validAttributes); + } + + var updatePayload = create(nativeProps, handle.viewConfig.validAttributes); + // Avoid the overhead of bridge calls if there's no update. + // This is an expensive no-op for Android, and causes an unnecessary + // view invalidation for certain components (eg RCTTextInput) on iOS. + if (updatePayload != null) { + ReactNativePrivateInterface.UIManager.updateView( + handle._nativeTag, + handle.viewConfig.uiViewClassName, + updatePayload + ); + } +} + +// TODO: direct imports like some-package/src/* are bad. Fix me. +// Module provided by RN: +var ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner; + +function findNodeHandle(componentOrHandle) { + { + var owner = ReactCurrentOwner.current; + if (owner !== null && owner.stateNode !== null) { + !owner.stateNode._warnedAboutRefsInRender + ? warningWithoutStack$1( + false, + "%s is accessing findNodeHandle inside its render(). " + + "render() should be a pure function of props and state. It should " + + "never access something that requires stale data from the previous " + + "render, such as refs. Move this logic to componentDidMount and " + + "componentDidUpdate instead.", + getComponentName(owner.type) || "A component" + ) + : void 0; + + owner.stateNode._warnedAboutRefsInRender = true; + } + } + if (componentOrHandle == null) { + return null; + } + if (typeof componentOrHandle === "number") { + // Already a node handle + return componentOrHandle; + } + if (componentOrHandle._nativeTag) { + return componentOrHandle._nativeTag; + } + if (componentOrHandle.canonical && componentOrHandle.canonical._nativeTag) { + return componentOrHandle.canonical._nativeTag; + } + var hostInstance = void 0; + { + hostInstance = findHostInstanceWithWarning( + componentOrHandle, + "findNodeHandle" + ); + } + + if (hostInstance == null) { + return hostInstance; + } + if (hostInstance.canonical) { + // Fabric + return hostInstance.canonical._nativeTag; + } + return hostInstance._nativeTag; +} + +setBatchingImplementation( + batchedUpdates$1, + interactiveUpdates$1, + flushInteractiveUpdates$1 +); + +function computeComponentStackForErrorReporting(reactTag) { + var fiber = getInstanceFromTag(reactTag); + if (!fiber) { + return ""; + } + return getStackByFiberInDevAndProd(fiber); +} + +var roots = new Map(); + +var ReactNativeRenderer = { + NativeComponent: ReactNativeComponent(findNodeHandle, findHostInstance), + + findNodeHandle: findNodeHandle, + + setNativeProps: setNativeProps, + + render: function(element, containerTag, callback) { + var root = roots.get(containerTag); + + if (!root) { + // TODO (bvaughn): If we decide to keep the wrapper component, + // We could create a wrapper for containerTag as well to reduce special casing. + root = createContainer(containerTag, false, false); + roots.set(containerTag, root); + } + updateContainer(element, root, null, callback); + + return getPublicRootInstance(root); + }, + unmountComponentAtNode: function(containerTag) { + var root = roots.get(containerTag); + if (root) { + // TODO: Is it safe to reset this now or should I wait since this unmount could be deferred? + updateContainer(null, root, null, function() { + roots.delete(containerTag); + }); + } + }, + unmountComponentAtNodeAndRemoveContainer: function(containerTag) { + ReactNativeRenderer.unmountComponentAtNode(containerTag); + + // Call back into native to remove all of the subviews from this container + ReactNativePrivateInterface.UIManager.removeRootView(containerTag); + }, + createPortal: function(children, containerTag) { + var key = + arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; + + return createPortal(children, containerTag, null, key); + }, + + unstable_batchedUpdates: batchedUpdates, + + __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { + // Used as a mixin in many createClass-based components + NativeMethodsMixin: NativeMethodsMixin(findNodeHandle, findHostInstance), + computeComponentStackForErrorReporting: computeComponentStackForErrorReporting + } +}; + +injectIntoDevTools({ + findFiberByHostInstance: getInstanceFromTag, + getInspectorDataForViewTag: getInspectorDataForViewTag, + bundleType: 1, + version: ReactVersion, + rendererPackageName: "react-native-renderer" +}); + +var ReactNativeRenderer$2 = Object.freeze({ + default: ReactNativeRenderer +}); + +var ReactNativeRenderer$3 = + (ReactNativeRenderer$2 && ReactNativeRenderer) || ReactNativeRenderer$2; + +// TODO: decide on the top-level export form. +// This is hacky but makes it work with both Rollup and Jest. +var reactNativeRenderer = + ReactNativeRenderer$3.default || ReactNativeRenderer$3; + +module.exports = reactNativeRenderer; + + })(); +} diff --git a/Libraries/Renderer/oss/ReactNativeRenderer-dev.js b/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js similarity index 99% rename from Libraries/Renderer/oss/ReactNativeRenderer-dev.js rename to Libraries/Renderer/implementations/ReactNativeRenderer-dev.js index 38166b62db37e4..1566edf036983a 100644 --- a/Libraries/Renderer/oss/ReactNativeRenderer-dev.js +++ b/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js @@ -16,19 +16,12 @@ if (__DEV__) { (function() { "use strict"; -require("InitializeCore"); -var ReactNativeViewConfigRegistry = require("ReactNativeViewConfigRegistry"); -var UIManager = require("UIManager"); -var RCTEventEmitter = require("RCTEventEmitter"); +require("react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore"); +var ReactNativePrivateInterface = require("react-native/Libraries/ReactPrivate/ReactNativePrivateInterface"); var React = require("react"); -var deepFreezeAndThrowOnMutationInDev = require("deepFreezeAndThrowOnMutationInDev"); -var deepDiffer = require("deepDiffer"); -var flattenStyle = require("flattenStyle"); -var TextInputState = require("TextInputState"); var checkPropTypes = require("prop-types/checkPropTypes"); var Scheduler = require("scheduler"); var tracing = require("scheduler/tracing"); -var ExceptionsManager = require("ExceptionsManager"); // Do not require this module directly! Use a normal error constructor with // template literal strings. The messages will be converted to ReactError during @@ -1561,7 +1554,7 @@ function getPooledWarningPropertyDefinition(propName, getVal) { return { configurable: true, set: set, - get: get$$1 + get: get }; function set(val) { @@ -1570,7 +1563,7 @@ function getPooledWarningPropertyDefinition(propName, getVal) { return val; } - function get$$1() { + function get() { var action = isFunction ? "accessing the method" : "accessing the property"; var result = isFunction ? "This is a no-op function" @@ -1913,7 +1906,7 @@ var changeResponder = function(nextResponderInst, blockHostResponder) { } }; -var eventTypes$1 = { +var eventTypes = { /** * On a `touchStart`/`mouseDown`, is it desired that this element become the * responder? @@ -2204,12 +2197,12 @@ function setResponderAndExtractTransfer( nativeEventTarget ) { var shouldSetEventType = isStartish(topLevelType) - ? eventTypes$1.startShouldSetResponder + ? eventTypes.startShouldSetResponder : isMoveish(topLevelType) - ? eventTypes$1.moveShouldSetResponder + ? eventTypes.moveShouldSetResponder : topLevelType === TOP_SELECTION_CHANGE - ? eventTypes$1.selectionChangeShouldSetResponder - : eventTypes$1.scrollShouldSetResponder; + ? eventTypes.selectionChangeShouldSetResponder + : eventTypes.scrollShouldSetResponder; // TODO: stop one short of the current responder. var bubbleShouldSetFrom = !responderInst @@ -2243,7 +2236,7 @@ function setResponderAndExtractTransfer( } var extracted = void 0; var grantEvent = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderGrant, + eventTypes.responderGrant, wantsResponderInst, nativeEvent, nativeEventTarget @@ -2254,7 +2247,7 @@ function setResponderAndExtractTransfer( var blockHostResponder = executeDirectDispatch(grantEvent) === true; if (responderInst) { var terminationRequestEvent = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderTerminationRequest, + eventTypes.responderTerminationRequest, responderInst, nativeEvent, nativeEventTarget @@ -2271,7 +2264,7 @@ function setResponderAndExtractTransfer( if (shouldSwitch) { var terminateEvent = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderTerminate, + eventTypes.responderTerminate, responderInst, nativeEvent, nativeEventTarget @@ -2282,7 +2275,7 @@ function setResponderAndExtractTransfer( changeResponder(wantsResponderInst, blockHostResponder); } else { var rejectEvent = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderReject, + eventTypes.responderReject, wantsResponderInst, nativeEvent, nativeEventTarget @@ -2351,7 +2344,7 @@ var ResponderEventPlugin = { return responderInst; }, - eventTypes: eventTypes$1, + eventTypes: eventTypes, /** * We must be resilient to `targetInst` being `null` on `touchMove` or @@ -2401,11 +2394,11 @@ var ResponderEventPlugin = { var isResponderTouchMove = responderInst && isMoveish(topLevelType); var isResponderTouchEnd = responderInst && isEndish(topLevelType); var incrementalTouch = isResponderTouchStart - ? eventTypes$1.responderStart + ? eventTypes.responderStart : isResponderTouchMove - ? eventTypes$1.responderMove + ? eventTypes.responderMove : isResponderTouchEnd - ? eventTypes$1.responderEnd + ? eventTypes.responderEnd : null; if (incrementalTouch) { @@ -2428,9 +2421,9 @@ var ResponderEventPlugin = { isEndish(topLevelType) && noResponderTouches(nativeEvent); var finalTouch = isResponderTerminate - ? eventTypes$1.responderTerminate + ? eventTypes.responderTerminate : isResponderRelease - ? eventTypes$1.responderRelease + ? eventTypes.responderRelease : null; if (finalTouch) { var finalEvent = ResponderSyntheticEvent.getPooled( @@ -2462,8 +2455,18 @@ var ResponderEventPlugin = { } }; +// Module provided by RN: +var customBubblingEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customBubblingEventTypes; +var customDirectEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customDirectEventTypes; +var eventTypes$1 = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes; + var ReactNativeBridgeEventPlugin = { - eventTypes: ReactNativeViewConfigRegistry.eventTypes, + eventTypes: eventTypes$1, /** * @see {EventPluginHub.extractEvents} @@ -2478,10 +2481,8 @@ var ReactNativeBridgeEventPlugin = { // Probably a node belonging to another renderer's tree. return null; } - var bubbleDispatchConfig = - ReactNativeViewConfigRegistry.customBubblingEventTypes[topLevelType]; - var directDispatchConfig = - ReactNativeViewConfigRegistry.customDirectEventTypes[topLevelType]; + var bubbleDispatchConfig = customBubblingEventTypes[topLevelType]; + var directDispatchConfig = customDirectEventTypes[topLevelType]; (function() { if (!(bubbleDispatchConfig || directDispatchConfig)) { throw ReactError( @@ -2816,9 +2817,12 @@ var ReactNativeGlobalResponderHandler = { onChange: function(from, to, blockNativeResponder) { if (to !== null) { var tag = to.stateNode._nativeTag; - UIManager.setJSResponder(tag, blockNativeResponder); + ReactNativePrivateInterface.UIManager.setJSResponder( + tag, + blockNativeResponder + ); } else { - UIManager.clearJSResponder(); + ReactNativePrivateInterface.UIManager.clearJSResponder(); } } }; @@ -2827,7 +2831,7 @@ var ReactNativeGlobalResponderHandler = { /** * Register the event emitter with the native bridge */ -RCTEventEmitter.register({ +ReactNativePrivateInterface.RCTEventEmitter.register({ receiveEvent: receiveEvent, receiveTouches: receiveTouches }); @@ -2858,7 +2862,7 @@ ResponderEventPlugin.injection.injectGlobalResponderHandler( * supported we can rename it. */ -function get$1(key) { +function get(key) { return key._reactInternalFiber; } @@ -3125,7 +3129,7 @@ function isMounted(component) { } } - var fiber = get$1(component); + var fiber = get(component); if (!fiber) { return false; } @@ -3344,7 +3348,7 @@ function defaultDiffer(prevProp, nextProp) { return true; } else { // For objects and arrays, the default diffing algorithm is a deep compare - return deepDiffer(prevProp, nextProp); + return ReactNativePrivateInterface.deepDiffer(prevProp, nextProp); } } @@ -3484,7 +3488,7 @@ function diffNestedProperty( return diffProperties( updatePayload, // $FlowFixMe - We know that this is always an object when the input is. - flattenStyle(prevProp), + ReactNativePrivateInterface.flattenStyle(prevProp), // $FlowFixMe - We know that this isn't an array because of above flow. nextProp, validAttributes @@ -3495,7 +3499,7 @@ function diffNestedProperty( updatePayload, prevProp, // $FlowFixMe - We know that this is always an object when the input is. - flattenStyle(nextProp), + ReactNativePrivateInterface.flattenStyle(nextProp), validAttributes ); } @@ -3852,15 +3856,15 @@ var ReactNativeFiberHostComponent = (function() { } ReactNativeFiberHostComponent.prototype.blur = function blur() { - TextInputState.blurTextInput(this._nativeTag); + ReactNativePrivateInterface.TextInputState.blurTextInput(this._nativeTag); }; ReactNativeFiberHostComponent.prototype.focus = function focus() { - TextInputState.focusTextInput(this._nativeTag); + ReactNativePrivateInterface.TextInputState.focusTextInput(this._nativeTag); }; ReactNativeFiberHostComponent.prototype.measure = function measure(callback) { - UIManager.measure( + ReactNativePrivateInterface.UIManager.measure( this._nativeTag, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); @@ -3869,7 +3873,7 @@ var ReactNativeFiberHostComponent = (function() { ReactNativeFiberHostComponent.prototype.measureInWindow = function measureInWindow( callback ) { - UIManager.measureInWindow( + ReactNativePrivateInterface.UIManager.measureInWindow( this._nativeTag, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); @@ -3903,7 +3907,7 @@ var ReactNativeFiberHostComponent = (function() { return; } - UIManager.measureLayout( + ReactNativePrivateInterface.UIManager.measureLayout( this._nativeTag, relativeNode, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -3933,7 +3937,7 @@ var ReactNativeFiberHostComponent = (function() { // This is an expensive no-op for Android, and causes an unnecessary // view invalidation for certain components (eg RCTTextInput) on iOS. if (updatePayload != null) { - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( this._nativeTag, this.viewConfig.uiViewClassName, updatePayload @@ -4008,6 +4012,8 @@ var didNotFindHydratableTextInstance = shim$1; var didNotFindHydratableSuspenseInstance = shim$1; // Modules provided by RN: +var getViewConfigForType = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.get; // Unused // Unused var UPDATE_SIGNAL = {}; @@ -4051,19 +4057,21 @@ function createInstance( internalInstanceHandle ) { var tag = allocateTag(); - var viewConfig = ReactNativeViewConfigRegistry.get(type); + var viewConfig = getViewConfigForType(type); { for (var key in viewConfig.validAttributes) { if (props.hasOwnProperty(key)) { - deepFreezeAndThrowOnMutationInDev(props[key]); + ReactNativePrivateInterface.deepFreezeAndThrowOnMutationInDev( + props[key] + ); } } } var updatePayload = create(props, viewConfig.validAttributes); - UIManager.createView( + ReactNativePrivateInterface.UIManager.createView( tag, // reactTag viewConfig.uiViewClassName, // viewName rootContainerInstance, // rootTag @@ -4096,7 +4104,7 @@ function createTextInstance( var tag = allocateTag(); - UIManager.createView( + ReactNativePrivateInterface.UIManager.createView( tag, // reactTag "RCTRawText", // viewName rootContainerInstance, // rootTag @@ -4128,7 +4136,7 @@ function finalizeInitialChildren( : child._nativeTag; }); - UIManager.setChildren( + ReactNativePrivateInterface.UIManager.setChildren( parentInstance._nativeTag, // containerTag nativeTags // reactTags ); @@ -4224,7 +4232,7 @@ function appendChild(parentInstance, child) { children.splice(index, 1); children.push(child); - UIManager.manageChildren( + ReactNativePrivateInterface.UIManager.manageChildren( parentInstance._nativeTag, // containerTag [index], // moveFromIndices [children.length - 1], // moveToIndices @@ -4235,7 +4243,7 @@ function appendChild(parentInstance, child) { } else { children.push(child); - UIManager.manageChildren( + ReactNativePrivateInterface.UIManager.manageChildren( parentInstance._nativeTag, // containerTag [], // moveFromIndices [], // moveToIndices @@ -4248,14 +4256,14 @@ function appendChild(parentInstance, child) { function appendChildToContainer(parentInstance, child) { var childTag = typeof child === "number" ? child : child._nativeTag; - UIManager.setChildren( + ReactNativePrivateInterface.UIManager.setChildren( parentInstance, // containerTag [childTag] // reactTags ); } function commitTextUpdate(textInstance, oldText, newText) { - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( textInstance, // reactTag "RCTRawText", // viewName { text: newText } // props @@ -4280,7 +4288,7 @@ function commitUpdate( // This is an expensive no-op for Android, and causes an unnecessary // view invalidation for certain components (eg RCTTextInput) on iOS. if (updatePayload != null) { - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( instance._nativeTag, // reactTag viewConfig.uiViewClassName, // viewName updatePayload // props @@ -4298,7 +4306,7 @@ function insertBefore(parentInstance, child, beforeChild) { var beforeChildIndex = children.indexOf(beforeChild); children.splice(beforeChildIndex, 0, child); - UIManager.manageChildren( + ReactNativePrivateInterface.UIManager.manageChildren( parentInstance._nativeTag, // containerID [index], // moveFromIndices [beforeChildIndex], // moveToIndices @@ -4312,7 +4320,7 @@ function insertBefore(parentInstance, child, beforeChild) { var childTag = typeof child === "number" ? child : child._nativeTag; - UIManager.manageChildren( + ReactNativePrivateInterface.UIManager.manageChildren( parentInstance._nativeTag, // containerID [], // moveFromIndices [], // moveToIndices @@ -4342,7 +4350,7 @@ function removeChild(parentInstance, child) { children.splice(index, 1); - UIManager.manageChildren( + ReactNativePrivateInterface.UIManager.manageChildren( parentInstance._nativeTag, // containerID [], // moveFromIndices [], // moveToIndices @@ -4354,7 +4362,7 @@ function removeChild(parentInstance, child) { function removeChildFromContainer(parentInstance, child) { recursivelyUncacheFiberNode(child); - UIManager.manageChildren( + ReactNativePrivateInterface.UIManager.manageChildren( parentInstance, // containerID [], // moveFromIndices [], // moveToIndices @@ -4374,7 +4382,7 @@ function hideInstance(instance) { { style: { display: "none" } }, viewConfig.validAttributes ); - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( instance._nativeTag, viewConfig.uiViewClassName, updatePayload @@ -4392,7 +4400,7 @@ function unhideInstance(instance, props) { props, viewConfig.validAttributes ); - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( instance._nativeTag, viewConfig.uiViewClassName, updatePayload @@ -7894,7 +7902,7 @@ function applyDerivedStateFromProps( var classComponentUpdater = { isMounted: isMounted, enqueueSetState: function(inst, payload, callback) { - var fiber = get$1(inst); + var fiber = get(inst); var currentTime = requestCurrentTime(); var expirationTime = computeExpirationForFiber(currentTime, fiber); @@ -7912,7 +7920,7 @@ var classComponentUpdater = { scheduleWork(fiber, expirationTime); }, enqueueReplaceState: function(inst, payload, callback) { - var fiber = get$1(inst); + var fiber = get(inst); var currentTime = requestCurrentTime(); var expirationTime = computeExpirationForFiber(currentTime, fiber); @@ -7932,7 +7940,7 @@ var classComponentUpdater = { scheduleWork(fiber, expirationTime); }, enqueueForceUpdate: function(inst, callback) { - var fiber = get$1(inst); + var fiber = get(inst); var currentTime = requestCurrentTime(); var expirationTime = computeExpirationForFiber(currentTime, fiber); @@ -15226,7 +15234,10 @@ function showErrorDialog(capturedError) { errorToHandle = new Error("Unspecified error at:" + componentStack); } - ExceptionsManager.handleException(errorToHandle, false); + ReactNativePrivateInterface.ExceptionsManager.handleException( + errorToHandle, + false + ); // Return false here to prevent ReactFiberErrorLogger default behavior of // logging error details to console.error. Calls to console.error are @@ -18887,7 +18898,7 @@ function getContextForSubtree(parentComponent) { return emptyContextObject; } - var fiber = get$1(parentComponent); + var fiber = get(parentComponent); var parentContext = findCurrentUnmaskedContext(fiber); if (fiber.tag === ClassComponent) { @@ -18973,7 +18984,7 @@ function updateContainerAtExpirationTime( } function findHostInstance(component) { - var fiber = get$1(component); + var fiber = get(component); if (fiber === undefined) { if (typeof component.render === "function") { (function() { @@ -19001,7 +19012,7 @@ function findHostInstance(component) { function findHostInstanceWithWarning(component, methodName) { { - var fiber = get$1(component); + var fiber = get(component); if (fiber === undefined) { if (typeof component.render === "function") { (function() { @@ -19286,7 +19297,7 @@ var NativeMethodsMixin = function(findNodeHandle, findHostInstance) { mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); } else { - UIManager.measure( + ReactNativePrivateInterface.UIManager.measure( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); @@ -19334,7 +19345,7 @@ var NativeMethodsMixin = function(findNodeHandle, findHostInstance) { mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); } else { - UIManager.measureInWindow( + ReactNativePrivateInterface.UIManager.measureInWindow( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); @@ -19397,7 +19408,7 @@ var NativeMethodsMixin = function(findNodeHandle, findHostInstance) { return; } - UIManager.measureLayout( + ReactNativePrivateInterface.UIManager.measureLayout( findNodeHandle(this), relativeNode, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -19469,7 +19480,7 @@ var NativeMethodsMixin = function(findNodeHandle, findHostInstance) { // This is an expensive no-op for Android, and causes an unnecessary // view invalidation for certain components (eg RCTTextInput) on iOS. if (updatePayload != null) { - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( nativeTag, viewConfig.uiViewClassName, updatePayload @@ -19482,14 +19493,18 @@ var NativeMethodsMixin = function(findNodeHandle, findHostInstance) { * will depend on the platform and type of view. */ focus: function() { - TextInputState.focusTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); }, /** * Removes focus from an input or view. This is the opposite of `focus()`. */ blur: function() { - TextInputState.blurTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); } }; @@ -19609,7 +19624,9 @@ var ReactNativeComponent = function(findNodeHandle, findHostInstance) { * declared in the base class need to be redeclared below. */ ReactNativeComponent.prototype.blur = function blur() { - TextInputState.blurTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); }; /** @@ -19617,7 +19634,9 @@ var ReactNativeComponent = function(findNodeHandle, findHostInstance) { */ ReactNativeComponent.prototype.focus = function focus() { - TextInputState.focusTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); }; /** @@ -19662,7 +19681,7 @@ var ReactNativeComponent = function(findNodeHandle, findHostInstance) { mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); } else { - UIManager.measure( + ReactNativePrivateInterface.UIManager.measure( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); @@ -19711,7 +19730,7 @@ var ReactNativeComponent = function(findNodeHandle, findHostInstance) { mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); } else { - UIManager.measureInWindow( + ReactNativePrivateInterface.UIManager.measureInWindow( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); @@ -19773,7 +19792,7 @@ var ReactNativeComponent = function(findNodeHandle, findHostInstance) { return; } - UIManager.measureLayout( + ReactNativePrivateInterface.UIManager.measureLayout( findNodeHandle(this), relativeNode, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -19844,7 +19863,7 @@ var ReactNativeComponent = function(findNodeHandle, findHostInstance) { // This is an expensive no-op for Android, and causes an unnecessary // view invalidation for certain components (eg RCTTextInput) on iOS. if (updatePayload != null) { - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( nativeTag, viewConfig.uiViewClassName, updatePayload @@ -19924,7 +19943,7 @@ var getInspectorDataForViewTag = void 0; getInspectorData: function(findNodeHandle) { return { measure: function(callback) { - return UIManager.measure( + return ReactNativePrivateInterface.UIManager.measure( getHostNode(fiber, findNodeHandle), callback ); @@ -19989,7 +20008,7 @@ function setNativeProps(handle, nativeProps) { // This is an expensive no-op for Android, and causes an unnecessary // view invalidation for certain components (eg RCTTextInput) on iOS. if (updatePayload != null) { - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( handle._nativeTag, handle.viewConfig.uiViewClassName, updatePayload @@ -20100,7 +20119,7 @@ var ReactNativeRenderer = { ReactNativeRenderer.unmountComponentAtNode(containerTag); // Call back into native to remove all of the subviews from this container - UIManager.removeRootView(containerTag); + ReactNativePrivateInterface.UIManager.removeRootView(containerTag); }, createPortal: function(children, containerTag) { var key = diff --git a/Libraries/Renderer/implementations/ReactNativeRenderer-prod.fb.js b/Libraries/Renderer/implementations/ReactNativeRenderer-prod.fb.js new file mode 100644 index 00000000000000..a97536ba85c30c --- /dev/null +++ b/Libraries/Renderer/implementations/ReactNativeRenderer-prod.fb.js @@ -0,0 +1,7205 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @noflow + * @preventMunge + * @generated + */ + +"use strict"; +require("react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore"); +var ReactNativePrivateInterface = require("react-native/Libraries/ReactPrivate/ReactNativePrivateInterface"), + React = require("react"), + Scheduler = require("scheduler"); +function ReactError(message) { + message = Error(message); + message.name = "Invariant Violation"; + return message; +} +var eventPluginOrder = null, + namesToPlugins = {}; +function recomputePluginOrdering() { + if (eventPluginOrder) + for (var pluginName in namesToPlugins) { + var pluginModule = namesToPlugins[pluginName], + pluginIndex = eventPluginOrder.indexOf(pluginName); + if (!(-1 < pluginIndex)) + throw ReactError( + "EventPluginRegistry: Cannot inject event plugins that do not exist in the plugin ordering, `" + + pluginName + + "`." + ); + if (!plugins[pluginIndex]) { + if (!pluginModule.extractEvents) + throw ReactError( + "EventPluginRegistry: Event plugins must implement an `extractEvents` method, but `" + + pluginName + + "` does not." + ); + plugins[pluginIndex] = pluginModule; + pluginIndex = pluginModule.eventTypes; + for (var eventName in pluginIndex) { + var JSCompiler_inline_result = void 0; + var dispatchConfig = pluginIndex[eventName], + pluginModule$jscomp$0 = pluginModule, + eventName$jscomp$0 = eventName; + if (eventNameDispatchConfigs.hasOwnProperty(eventName$jscomp$0)) + throw ReactError( + "EventPluginHub: More than one plugin attempted to publish the same event name, `" + + eventName$jscomp$0 + + "`." + ); + eventNameDispatchConfigs[eventName$jscomp$0] = dispatchConfig; + var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames; + if (phasedRegistrationNames) { + for (JSCompiler_inline_result in phasedRegistrationNames) + phasedRegistrationNames.hasOwnProperty( + JSCompiler_inline_result + ) && + publishRegistrationName( + phasedRegistrationNames[JSCompiler_inline_result], + pluginModule$jscomp$0, + eventName$jscomp$0 + ); + JSCompiler_inline_result = !0; + } else + dispatchConfig.registrationName + ? (publishRegistrationName( + dispatchConfig.registrationName, + pluginModule$jscomp$0, + eventName$jscomp$0 + ), + (JSCompiler_inline_result = !0)) + : (JSCompiler_inline_result = !1); + if (!JSCompiler_inline_result) + throw ReactError( + "EventPluginRegistry: Failed to publish event `" + + eventName + + "` for plugin `" + + pluginName + + "`." + ); + } + } + } +} +function publishRegistrationName(registrationName, pluginModule) { + if (registrationNameModules[registrationName]) + throw ReactError( + "EventPluginHub: More than one plugin attempted to publish the same registration name, `" + + registrationName + + "`." + ); + registrationNameModules[registrationName] = pluginModule; +} +var plugins = [], + eventNameDispatchConfigs = {}, + registrationNameModules = {}; +function invokeGuardedCallbackImpl(name, func, context, a, b, c, d, e, f) { + var funcArgs = Array.prototype.slice.call(arguments, 3); + try { + func.apply(context, funcArgs); + } catch (error) { + this.onError(error); + } +} +var hasError = !1, + caughtError = null, + hasRethrowError = !1, + rethrowError = null, + reporter = { + onError: function(error) { + hasError = !0; + caughtError = error; + } + }; +function invokeGuardedCallback(name, func, context, a, b, c, d, e, f) { + hasError = !1; + caughtError = null; + invokeGuardedCallbackImpl.apply(reporter, arguments); +} +function invokeGuardedCallbackAndCatchFirstError( + name, + func, + context, + a, + b, + c, + d, + e, + f +) { + invokeGuardedCallback.apply(this, arguments); + if (hasError) { + if (hasError) { + var error = caughtError; + hasError = !1; + caughtError = null; + } else + throw ReactError( + "clearCaughtError was called but no error was captured. This error is likely caused by a bug in React. Please file an issue." + ); + hasRethrowError || ((hasRethrowError = !0), (rethrowError = error)); + } +} +var getFiberCurrentPropsFromNode = null, + getInstanceFromNode = null, + getNodeFromInstance = null; +function executeDispatch(event, listener, inst) { + var type = event.type || "unknown-event"; + event.currentTarget = getNodeFromInstance(inst); + invokeGuardedCallbackAndCatchFirstError(type, listener, void 0, event); + event.currentTarget = null; +} +function executeDirectDispatch(event) { + var dispatchListener = event._dispatchListeners, + dispatchInstance = event._dispatchInstances; + if (Array.isArray(dispatchListener)) + throw ReactError("executeDirectDispatch(...): Invalid `event`."); + event.currentTarget = dispatchListener + ? getNodeFromInstance(dispatchInstance) + : null; + dispatchListener = dispatchListener ? dispatchListener(event) : null; + event.currentTarget = null; + event._dispatchListeners = null; + event._dispatchInstances = null; + return dispatchListener; +} +function accumulateInto(current, next) { + if (null == next) + throw ReactError( + "accumulateInto(...): Accumulated items must not be null or undefined." + ); + if (null == current) return next; + if (Array.isArray(current)) { + if (Array.isArray(next)) return current.push.apply(current, next), current; + current.push(next); + return current; + } + return Array.isArray(next) ? [current].concat(next) : [current, next]; +} +function forEachAccumulated(arr, cb, scope) { + Array.isArray(arr) ? arr.forEach(cb, scope) : arr && cb.call(scope, arr); +} +var eventQueue = null; +function executeDispatchesAndReleaseTopLevel(e) { + if (e) { + var dispatchListeners = e._dispatchListeners, + dispatchInstances = e._dispatchInstances; + if (Array.isArray(dispatchListeners)) + for ( + var i = 0; + i < dispatchListeners.length && !e.isPropagationStopped(); + i++ + ) + executeDispatch(e, dispatchListeners[i], dispatchInstances[i]); + else + dispatchListeners && + executeDispatch(e, dispatchListeners, dispatchInstances); + e._dispatchListeners = null; + e._dispatchInstances = null; + e.isPersistent() || e.constructor.release(e); + } +} +var injection = { + injectEventPluginOrder: function(injectedEventPluginOrder) { + if (eventPluginOrder) + throw ReactError( + "EventPluginRegistry: Cannot inject event plugin ordering more than once. You are likely trying to load more than one copy of React." + ); + eventPluginOrder = Array.prototype.slice.call(injectedEventPluginOrder); + recomputePluginOrdering(); + }, + injectEventPluginsByName: function(injectedNamesToPlugins) { + var isOrderingDirty = !1, + pluginName; + for (pluginName in injectedNamesToPlugins) + if (injectedNamesToPlugins.hasOwnProperty(pluginName)) { + var pluginModule = injectedNamesToPlugins[pluginName]; + if ( + !namesToPlugins.hasOwnProperty(pluginName) || + namesToPlugins[pluginName] !== pluginModule + ) { + if (namesToPlugins[pluginName]) + throw ReactError( + "EventPluginRegistry: Cannot inject two different event plugins using the same name, `" + + pluginName + + "`." + ); + namesToPlugins[pluginName] = pluginModule; + isOrderingDirty = !0; + } + } + isOrderingDirty && recomputePluginOrdering(); + } +}; +function getListener(inst, registrationName) { + var listener = inst.stateNode; + if (!listener) return null; + var props = getFiberCurrentPropsFromNode(listener); + if (!props) return null; + listener = props[registrationName]; + a: switch (registrationName) { + case "onClick": + case "onClickCapture": + case "onDoubleClick": + case "onDoubleClickCapture": + case "onMouseDown": + case "onMouseDownCapture": + case "onMouseMove": + case "onMouseMoveCapture": + case "onMouseUp": + case "onMouseUpCapture": + (props = !props.disabled) || + ((inst = inst.type), + (props = !( + "button" === inst || + "input" === inst || + "select" === inst || + "textarea" === inst + ))); + inst = !props; + break a; + default: + inst = !1; + } + if (inst) return null; + if (listener && "function" !== typeof listener) + throw ReactError( + "Expected `" + + registrationName + + "` listener to be a function, instead got a value of `" + + typeof listener + + "` type." + ); + return listener; +} +function getParent(inst) { + do inst = inst.return; + while (inst && 5 !== inst.tag); + return inst ? inst : null; +} +function traverseTwoPhase(inst, fn, arg) { + for (var path = []; inst; ) path.push(inst), (inst = getParent(inst)); + for (inst = path.length; 0 < inst--; ) fn(path[inst], "captured", arg); + for (inst = 0; inst < path.length; inst++) fn(path[inst], "bubbled", arg); +} +function accumulateDirectionalDispatches(inst, phase, event) { + if ( + (phase = getListener( + inst, + event.dispatchConfig.phasedRegistrationNames[phase] + )) + ) + (event._dispatchListeners = accumulateInto( + event._dispatchListeners, + phase + )), + (event._dispatchInstances = accumulateInto( + event._dispatchInstances, + inst + )); +} +function accumulateTwoPhaseDispatchesSingle(event) { + event && + event.dispatchConfig.phasedRegistrationNames && + traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event); +} +function accumulateTwoPhaseDispatchesSingleSkipTarget(event) { + if (event && event.dispatchConfig.phasedRegistrationNames) { + var targetInst = event._targetInst; + targetInst = targetInst ? getParent(targetInst) : null; + traverseTwoPhase(targetInst, accumulateDirectionalDispatches, event); + } +} +function accumulateDirectDispatchesSingle(event) { + if (event && event.dispatchConfig.registrationName) { + var inst = event._targetInst; + if (inst && event && event.dispatchConfig.registrationName) { + var listener = getListener(inst, event.dispatchConfig.registrationName); + listener && + ((event._dispatchListeners = accumulateInto( + event._dispatchListeners, + listener + )), + (event._dispatchInstances = accumulateInto( + event._dispatchInstances, + inst + ))); + } + } +} +function functionThatReturnsTrue() { + return !0; +} +function functionThatReturnsFalse() { + return !1; +} +function SyntheticEvent( + dispatchConfig, + targetInst, + nativeEvent, + nativeEventTarget +) { + this.dispatchConfig = dispatchConfig; + this._targetInst = targetInst; + this.nativeEvent = nativeEvent; + dispatchConfig = this.constructor.Interface; + for (var propName in dispatchConfig) + dispatchConfig.hasOwnProperty(propName) && + ((targetInst = dispatchConfig[propName]) + ? (this[propName] = targetInst(nativeEvent)) + : "target" === propName + ? (this.target = nativeEventTarget) + : (this[propName] = nativeEvent[propName])); + this.isDefaultPrevented = (null != nativeEvent.defaultPrevented + ? nativeEvent.defaultPrevented + : !1 === nativeEvent.returnValue) + ? functionThatReturnsTrue + : functionThatReturnsFalse; + this.isPropagationStopped = functionThatReturnsFalse; + return this; +} +Object.assign(SyntheticEvent.prototype, { + preventDefault: function() { + this.defaultPrevented = !0; + var event = this.nativeEvent; + event && + (event.preventDefault + ? event.preventDefault() + : "unknown" !== typeof event.returnValue && (event.returnValue = !1), + (this.isDefaultPrevented = functionThatReturnsTrue)); + }, + stopPropagation: function() { + var event = this.nativeEvent; + event && + (event.stopPropagation + ? event.stopPropagation() + : "unknown" !== typeof event.cancelBubble && (event.cancelBubble = !0), + (this.isPropagationStopped = functionThatReturnsTrue)); + }, + persist: function() { + this.isPersistent = functionThatReturnsTrue; + }, + isPersistent: functionThatReturnsFalse, + destructor: function() { + var Interface = this.constructor.Interface, + propName; + for (propName in Interface) this[propName] = null; + this.nativeEvent = this._targetInst = this.dispatchConfig = null; + this.isPropagationStopped = this.isDefaultPrevented = functionThatReturnsFalse; + this._dispatchInstances = this._dispatchListeners = null; + } +}); +SyntheticEvent.Interface = { + type: null, + target: null, + currentTarget: function() { + return null; + }, + eventPhase: null, + bubbles: null, + cancelable: null, + timeStamp: function(event) { + return event.timeStamp || Date.now(); + }, + defaultPrevented: null, + isTrusted: null +}; +SyntheticEvent.extend = function(Interface) { + function E() {} + function Class() { + return Super.apply(this, arguments); + } + var Super = this; + E.prototype = Super.prototype; + var prototype = new E(); + Object.assign(prototype, Class.prototype); + Class.prototype = prototype; + Class.prototype.constructor = Class; + Class.Interface = Object.assign({}, Super.Interface, Interface); + Class.extend = Super.extend; + addEventPoolingTo(Class); + return Class; +}; +addEventPoolingTo(SyntheticEvent); +function getPooledEvent(dispatchConfig, targetInst, nativeEvent, nativeInst) { + if (this.eventPool.length) { + var instance = this.eventPool.pop(); + this.call(instance, dispatchConfig, targetInst, nativeEvent, nativeInst); + return instance; + } + return new this(dispatchConfig, targetInst, nativeEvent, nativeInst); +} +function releasePooledEvent(event) { + if (!(event instanceof this)) + throw ReactError( + "Trying to release an event instance into a pool of a different type." + ); + event.destructor(); + 10 > this.eventPool.length && this.eventPool.push(event); +} +function addEventPoolingTo(EventConstructor) { + EventConstructor.eventPool = []; + EventConstructor.getPooled = getPooledEvent; + EventConstructor.release = releasePooledEvent; +} +var ResponderSyntheticEvent = SyntheticEvent.extend({ + touchHistory: function() { + return null; + } +}); +function isStartish(topLevelType) { + return "topTouchStart" === topLevelType; +} +function isMoveish(topLevelType) { + return "topTouchMove" === topLevelType; +} +var startDependencies = ["topTouchStart"], + moveDependencies = ["topTouchMove"], + endDependencies = ["topTouchCancel", "topTouchEnd"], + touchBank = [], + touchHistory = { + touchBank: touchBank, + numberActiveTouches: 0, + indexOfSingleActiveTouch: -1, + mostRecentTimeStamp: 0 + }; +function timestampForTouch(touch) { + return touch.timeStamp || touch.timestamp; +} +function getTouchIdentifier(_ref) { + _ref = _ref.identifier; + if (null == _ref) throw ReactError("Touch object is missing identifier."); + return _ref; +} +function recordTouchStart(touch) { + var identifier = getTouchIdentifier(touch), + touchRecord = touchBank[identifier]; + touchRecord + ? ((touchRecord.touchActive = !0), + (touchRecord.startPageX = touch.pageX), + (touchRecord.startPageY = touch.pageY), + (touchRecord.startTimeStamp = timestampForTouch(touch)), + (touchRecord.currentPageX = touch.pageX), + (touchRecord.currentPageY = touch.pageY), + (touchRecord.currentTimeStamp = timestampForTouch(touch)), + (touchRecord.previousPageX = touch.pageX), + (touchRecord.previousPageY = touch.pageY), + (touchRecord.previousTimeStamp = timestampForTouch(touch))) + : ((touchRecord = { + touchActive: !0, + startPageX: touch.pageX, + startPageY: touch.pageY, + startTimeStamp: timestampForTouch(touch), + currentPageX: touch.pageX, + currentPageY: touch.pageY, + currentTimeStamp: timestampForTouch(touch), + previousPageX: touch.pageX, + previousPageY: touch.pageY, + previousTimeStamp: timestampForTouch(touch) + }), + (touchBank[identifier] = touchRecord)); + touchHistory.mostRecentTimeStamp = timestampForTouch(touch); +} +function recordTouchMove(touch) { + var touchRecord = touchBank[getTouchIdentifier(touch)]; + touchRecord + ? ((touchRecord.touchActive = !0), + (touchRecord.previousPageX = touchRecord.currentPageX), + (touchRecord.previousPageY = touchRecord.currentPageY), + (touchRecord.previousTimeStamp = touchRecord.currentTimeStamp), + (touchRecord.currentPageX = touch.pageX), + (touchRecord.currentPageY = touch.pageY), + (touchRecord.currentTimeStamp = timestampForTouch(touch)), + (touchHistory.mostRecentTimeStamp = timestampForTouch(touch))) + : console.error( + "Cannot record touch move without a touch start.\nTouch Move: %s\n", + "Touch Bank: %s", + printTouch(touch), + printTouchBank() + ); +} +function recordTouchEnd(touch) { + var touchRecord = touchBank[getTouchIdentifier(touch)]; + touchRecord + ? ((touchRecord.touchActive = !1), + (touchRecord.previousPageX = touchRecord.currentPageX), + (touchRecord.previousPageY = touchRecord.currentPageY), + (touchRecord.previousTimeStamp = touchRecord.currentTimeStamp), + (touchRecord.currentPageX = touch.pageX), + (touchRecord.currentPageY = touch.pageY), + (touchRecord.currentTimeStamp = timestampForTouch(touch)), + (touchHistory.mostRecentTimeStamp = timestampForTouch(touch))) + : console.error( + "Cannot record touch end without a touch start.\nTouch End: %s\n", + "Touch Bank: %s", + printTouch(touch), + printTouchBank() + ); +} +function printTouch(touch) { + return JSON.stringify({ + identifier: touch.identifier, + pageX: touch.pageX, + pageY: touch.pageY, + timestamp: timestampForTouch(touch) + }); +} +function printTouchBank() { + var printed = JSON.stringify(touchBank.slice(0, 20)); + 20 < touchBank.length && + (printed += " (original size: " + touchBank.length + ")"); + return printed; +} +var ResponderTouchHistoryStore = { + recordTouchTrack: function(topLevelType, nativeEvent) { + if (isMoveish(topLevelType)) + nativeEvent.changedTouches.forEach(recordTouchMove); + else if (isStartish(topLevelType)) + nativeEvent.changedTouches.forEach(recordTouchStart), + (touchHistory.numberActiveTouches = nativeEvent.touches.length), + 1 === touchHistory.numberActiveTouches && + (touchHistory.indexOfSingleActiveTouch = + nativeEvent.touches[0].identifier); + else if ( + "topTouchEnd" === topLevelType || + "topTouchCancel" === topLevelType + ) + if ( + (nativeEvent.changedTouches.forEach(recordTouchEnd), + (touchHistory.numberActiveTouches = nativeEvent.touches.length), + 1 === touchHistory.numberActiveTouches) + ) + for (topLevelType = 0; topLevelType < touchBank.length; topLevelType++) + if ( + ((nativeEvent = touchBank[topLevelType]), + null != nativeEvent && nativeEvent.touchActive) + ) { + touchHistory.indexOfSingleActiveTouch = topLevelType; + break; + } + }, + touchHistory: touchHistory +}; +function accumulate(current, next) { + if (null == next) + throw ReactError( + "accumulate(...): Accumulated items must not be null or undefined." + ); + return null == current + ? next + : Array.isArray(current) + ? current.concat(next) + : Array.isArray(next) + ? [current].concat(next) + : [current, next]; +} +var responderInst = null, + trackedTouchCount = 0; +function changeResponder(nextResponderInst, blockHostResponder) { + var oldResponderInst = responderInst; + responderInst = nextResponderInst; + if (null !== ResponderEventPlugin.GlobalResponderHandler) + ResponderEventPlugin.GlobalResponderHandler.onChange( + oldResponderInst, + nextResponderInst, + blockHostResponder + ); +} +var eventTypes = { + startShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onStartShouldSetResponder", + captured: "onStartShouldSetResponderCapture" + }, + dependencies: startDependencies + }, + scrollShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onScrollShouldSetResponder", + captured: "onScrollShouldSetResponderCapture" + }, + dependencies: ["topScroll"] + }, + selectionChangeShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onSelectionChangeShouldSetResponder", + captured: "onSelectionChangeShouldSetResponderCapture" + }, + dependencies: ["topSelectionChange"] + }, + moveShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onMoveShouldSetResponder", + captured: "onMoveShouldSetResponderCapture" + }, + dependencies: moveDependencies + }, + responderStart: { + registrationName: "onResponderStart", + dependencies: startDependencies + }, + responderMove: { + registrationName: "onResponderMove", + dependencies: moveDependencies + }, + responderEnd: { + registrationName: "onResponderEnd", + dependencies: endDependencies + }, + responderRelease: { + registrationName: "onResponderRelease", + dependencies: endDependencies + }, + responderTerminationRequest: { + registrationName: "onResponderTerminationRequest", + dependencies: [] + }, + responderGrant: { registrationName: "onResponderGrant", dependencies: [] }, + responderReject: { + registrationName: "onResponderReject", + dependencies: [] + }, + responderTerminate: { + registrationName: "onResponderTerminate", + dependencies: [] + } + }, + ResponderEventPlugin = { + _getResponder: function() { + return responderInst; + }, + eventTypes: eventTypes, + extractEvents: function( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ) { + if (isStartish(topLevelType)) trackedTouchCount += 1; + else if ( + "topTouchEnd" === topLevelType || + "topTouchCancel" === topLevelType + ) + if (0 <= trackedTouchCount) --trackedTouchCount; + else + return ( + console.error( + "Ended a touch event which was not counted in `trackedTouchCount`." + ), + null + ); + ResponderTouchHistoryStore.recordTouchTrack(topLevelType, nativeEvent); + if ( + targetInst && + (("topScroll" === topLevelType && !nativeEvent.responderIgnoreScroll) || + (0 < trackedTouchCount && "topSelectionChange" === topLevelType) || + isStartish(topLevelType) || + isMoveish(topLevelType)) + ) { + var JSCompiler_temp = isStartish(topLevelType) + ? eventTypes.startShouldSetResponder + : isMoveish(topLevelType) + ? eventTypes.moveShouldSetResponder + : "topSelectionChange" === topLevelType + ? eventTypes.selectionChangeShouldSetResponder + : eventTypes.scrollShouldSetResponder; + if (responderInst) + b: { + var JSCompiler_temp$jscomp$0 = responderInst; + for ( + var depthA = 0, tempA = JSCompiler_temp$jscomp$0; + tempA; + tempA = getParent(tempA) + ) + depthA++; + tempA = 0; + for (var tempB = targetInst; tempB; tempB = getParent(tempB)) + tempA++; + for (; 0 < depthA - tempA; ) + (JSCompiler_temp$jscomp$0 = getParent(JSCompiler_temp$jscomp$0)), + depthA--; + for (; 0 < tempA - depthA; ) + (targetInst = getParent(targetInst)), tempA--; + for (; depthA--; ) { + if ( + JSCompiler_temp$jscomp$0 === targetInst || + JSCompiler_temp$jscomp$0 === targetInst.alternate + ) + break b; + JSCompiler_temp$jscomp$0 = getParent(JSCompiler_temp$jscomp$0); + targetInst = getParent(targetInst); + } + JSCompiler_temp$jscomp$0 = null; + } + else JSCompiler_temp$jscomp$0 = targetInst; + targetInst = JSCompiler_temp$jscomp$0 === responderInst; + JSCompiler_temp$jscomp$0 = ResponderSyntheticEvent.getPooled( + JSCompiler_temp, + JSCompiler_temp$jscomp$0, + nativeEvent, + nativeEventTarget + ); + JSCompiler_temp$jscomp$0.touchHistory = + ResponderTouchHistoryStore.touchHistory; + targetInst + ? forEachAccumulated( + JSCompiler_temp$jscomp$0, + accumulateTwoPhaseDispatchesSingleSkipTarget + ) + : forEachAccumulated( + JSCompiler_temp$jscomp$0, + accumulateTwoPhaseDispatchesSingle + ); + b: { + JSCompiler_temp = JSCompiler_temp$jscomp$0._dispatchListeners; + targetInst = JSCompiler_temp$jscomp$0._dispatchInstances; + if (Array.isArray(JSCompiler_temp)) + for ( + depthA = 0; + depthA < JSCompiler_temp.length && + !JSCompiler_temp$jscomp$0.isPropagationStopped(); + depthA++ + ) { + if ( + JSCompiler_temp[depthA]( + JSCompiler_temp$jscomp$0, + targetInst[depthA] + ) + ) { + JSCompiler_temp = targetInst[depthA]; + break b; + } + } + else if ( + JSCompiler_temp && + JSCompiler_temp(JSCompiler_temp$jscomp$0, targetInst) + ) { + JSCompiler_temp = targetInst; + break b; + } + JSCompiler_temp = null; + } + JSCompiler_temp$jscomp$0._dispatchInstances = null; + JSCompiler_temp$jscomp$0._dispatchListeners = null; + JSCompiler_temp$jscomp$0.isPersistent() || + JSCompiler_temp$jscomp$0.constructor.release( + JSCompiler_temp$jscomp$0 + ); + JSCompiler_temp && JSCompiler_temp !== responderInst + ? ((JSCompiler_temp$jscomp$0 = void 0), + (targetInst = ResponderSyntheticEvent.getPooled( + eventTypes.responderGrant, + JSCompiler_temp, + nativeEvent, + nativeEventTarget + )), + (targetInst.touchHistory = ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(targetInst, accumulateDirectDispatchesSingle), + (depthA = !0 === executeDirectDispatch(targetInst)), + responderInst + ? ((tempA = ResponderSyntheticEvent.getPooled( + eventTypes.responderTerminationRequest, + responderInst, + nativeEvent, + nativeEventTarget + )), + (tempA.touchHistory = ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(tempA, accumulateDirectDispatchesSingle), + (tempB = + !tempA._dispatchListeners || executeDirectDispatch(tempA)), + tempA.isPersistent() || tempA.constructor.release(tempA), + tempB + ? ((tempA = ResponderSyntheticEvent.getPooled( + eventTypes.responderTerminate, + responderInst, + nativeEvent, + nativeEventTarget + )), + (tempA.touchHistory = + ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(tempA, accumulateDirectDispatchesSingle), + (JSCompiler_temp$jscomp$0 = accumulate( + JSCompiler_temp$jscomp$0, + [targetInst, tempA] + )), + changeResponder(JSCompiler_temp, depthA)) + : ((JSCompiler_temp = ResponderSyntheticEvent.getPooled( + eventTypes.responderReject, + JSCompiler_temp, + nativeEvent, + nativeEventTarget + )), + (JSCompiler_temp.touchHistory = + ResponderTouchHistoryStore.touchHistory), + forEachAccumulated( + JSCompiler_temp, + accumulateDirectDispatchesSingle + ), + (JSCompiler_temp$jscomp$0 = accumulate( + JSCompiler_temp$jscomp$0, + JSCompiler_temp + )))) + : ((JSCompiler_temp$jscomp$0 = accumulate( + JSCompiler_temp$jscomp$0, + targetInst + )), + changeResponder(JSCompiler_temp, depthA)), + (JSCompiler_temp = JSCompiler_temp$jscomp$0)) + : (JSCompiler_temp = null); + } else JSCompiler_temp = null; + JSCompiler_temp$jscomp$0 = responderInst && isStartish(topLevelType); + targetInst = responderInst && isMoveish(topLevelType); + depthA = + responderInst && + ("topTouchEnd" === topLevelType || "topTouchCancel" === topLevelType); + if ( + (JSCompiler_temp$jscomp$0 = JSCompiler_temp$jscomp$0 + ? eventTypes.responderStart + : targetInst + ? eventTypes.responderMove + : depthA + ? eventTypes.responderEnd + : null) + ) + (JSCompiler_temp$jscomp$0 = ResponderSyntheticEvent.getPooled( + JSCompiler_temp$jscomp$0, + responderInst, + nativeEvent, + nativeEventTarget + )), + (JSCompiler_temp$jscomp$0.touchHistory = + ResponderTouchHistoryStore.touchHistory), + forEachAccumulated( + JSCompiler_temp$jscomp$0, + accumulateDirectDispatchesSingle + ), + (JSCompiler_temp = accumulate( + JSCompiler_temp, + JSCompiler_temp$jscomp$0 + )); + JSCompiler_temp$jscomp$0 = + responderInst && "topTouchCancel" === topLevelType; + if ( + (topLevelType = + responderInst && + !JSCompiler_temp$jscomp$0 && + ("topTouchEnd" === topLevelType || "topTouchCancel" === topLevelType)) + ) + a: { + if ((topLevelType = nativeEvent.touches) && 0 !== topLevelType.length) + for (targetInst = 0; targetInst < topLevelType.length; targetInst++) + if ( + ((depthA = topLevelType[targetInst].target), + null !== depthA && void 0 !== depthA && 0 !== depthA) + ) { + tempA = getInstanceFromNode(depthA); + b: { + for (depthA = responderInst; tempA; ) { + if (depthA === tempA || depthA === tempA.alternate) { + depthA = !0; + break b; + } + tempA = getParent(tempA); + } + depthA = !1; + } + if (depthA) { + topLevelType = !1; + break a; + } + } + topLevelType = !0; + } + if ( + (topLevelType = JSCompiler_temp$jscomp$0 + ? eventTypes.responderTerminate + : topLevelType + ? eventTypes.responderRelease + : null) + ) + (nativeEvent = ResponderSyntheticEvent.getPooled( + topLevelType, + responderInst, + nativeEvent, + nativeEventTarget + )), + (nativeEvent.touchHistory = ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(nativeEvent, accumulateDirectDispatchesSingle), + (JSCompiler_temp = accumulate(JSCompiler_temp, nativeEvent)), + changeResponder(null); + return JSCompiler_temp; + }, + GlobalResponderHandler: null, + injection: { + injectGlobalResponderHandler: function(GlobalResponderHandler) { + ResponderEventPlugin.GlobalResponderHandler = GlobalResponderHandler; + } + } + }, + customBubblingEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customBubblingEventTypes, + customDirectEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customDirectEventTypes, + ReactNativeBridgeEventPlugin = { + eventTypes: + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes, + extractEvents: function( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ) { + if (null == targetInst) return null; + var bubbleDispatchConfig = customBubblingEventTypes[topLevelType], + directDispatchConfig = customDirectEventTypes[topLevelType]; + if (!bubbleDispatchConfig && !directDispatchConfig) + throw ReactError( + 'Unsupported top level event type "' + topLevelType + '" dispatched' + ); + topLevelType = SyntheticEvent.getPooled( + bubbleDispatchConfig || directDispatchConfig, + targetInst, + nativeEvent, + nativeEventTarget + ); + if (bubbleDispatchConfig) + forEachAccumulated(topLevelType, accumulateTwoPhaseDispatchesSingle); + else if (directDispatchConfig) + forEachAccumulated(topLevelType, accumulateDirectDispatchesSingle); + else return null; + return topLevelType; + } + }; +injection.injectEventPluginOrder([ + "ResponderEventPlugin", + "ReactNativeBridgeEventPlugin" +]); +injection.injectEventPluginsByName({ + ResponderEventPlugin: ResponderEventPlugin, + ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin +}); +var instanceCache = {}, + instanceProps = {}; +function getInstanceFromTag(tag) { + return instanceCache[tag] || null; +} +var restoreTarget = null, + restoreQueue = null; +function restoreStateOfTarget(target) { + if (getInstanceFromNode(target)) + throw ReactError( + "setRestoreImplementation() needs to be called to handle a target for controlled events. This error is likely caused by a bug in React. Please file an issue." + ); +} +function _batchedUpdatesImpl(fn, bookkeeping) { + return fn(bookkeeping); +} +function _flushInteractiveUpdatesImpl() {} +var isBatching = !1; +function batchedUpdates(fn, bookkeeping) { + if (isBatching) return fn(bookkeeping); + isBatching = !0; + try { + return _batchedUpdatesImpl(fn, bookkeeping); + } finally { + if (((isBatching = !1), null !== restoreTarget || null !== restoreQueue)) + if ( + (_flushInteractiveUpdatesImpl(), + restoreTarget && + ((bookkeeping = restoreTarget), + (fn = restoreQueue), + (restoreQueue = restoreTarget = null), + restoreStateOfTarget(bookkeeping), + fn)) + ) + for (bookkeeping = 0; bookkeeping < fn.length; bookkeeping++) + restoreStateOfTarget(fn[bookkeeping]); + } +} +var EMPTY_NATIVE_EVENT = {}; +function _receiveRootNodeIDEvent(rootNodeID, topLevelType, nativeEventParam) { + var nativeEvent = nativeEventParam || EMPTY_NATIVE_EVENT, + inst = getInstanceFromTag(rootNodeID); + batchedUpdates(function() { + var events = nativeEvent.target; + for (var events$jscomp$0 = null, i = 0; i < plugins.length; i++) { + var possiblePlugin = plugins[i]; + possiblePlugin && + (possiblePlugin = possiblePlugin.extractEvents( + topLevelType, + inst, + nativeEvent, + events + )) && + (events$jscomp$0 = accumulateInto(events$jscomp$0, possiblePlugin)); + } + events = events$jscomp$0; + null !== events && (eventQueue = accumulateInto(eventQueue, events)); + events = eventQueue; + eventQueue = null; + if (events) { + forEachAccumulated(events, executeDispatchesAndReleaseTopLevel); + if (eventQueue) + throw ReactError( + "processEventQueue(): Additional events were enqueued while processing an event queue. Support for this has not yet been implemented." + ); + if (hasRethrowError) + throw ((events = rethrowError), + (hasRethrowError = !1), + (rethrowError = null), + events); + } + }); +} +ReactNativePrivateInterface.RCTEventEmitter.register({ + receiveEvent: function(rootNodeID, topLevelType, nativeEventParam) { + _receiveRootNodeIDEvent(rootNodeID, topLevelType, nativeEventParam); + }, + receiveTouches: function(eventTopLevelType, touches, changedIndices) { + if ( + "topTouchEnd" === eventTopLevelType || + "topTouchCancel" === eventTopLevelType + ) { + var JSCompiler_temp = []; + for (var i = 0; i < changedIndices.length; i++) { + var index = changedIndices[i]; + JSCompiler_temp.push(touches[index]); + touches[index] = null; + } + for (i = changedIndices = 0; i < touches.length; i++) + (index = touches[i]), + null !== index && (touches[changedIndices++] = index); + touches.length = changedIndices; + } else + for (JSCompiler_temp = [], i = 0; i < changedIndices.length; i++) + JSCompiler_temp.push(touches[changedIndices[i]]); + for ( + changedIndices = 0; + changedIndices < JSCompiler_temp.length; + changedIndices++ + ) { + i = JSCompiler_temp[changedIndices]; + i.changedTouches = JSCompiler_temp; + i.touches = touches; + index = null; + var target = i.target; + null === target || void 0 === target || 1 > target || (index = target); + _receiveRootNodeIDEvent(index, eventTopLevelType, i); + } + } +}); +getFiberCurrentPropsFromNode = function(stateNode) { + return instanceProps[stateNode._nativeTag] || null; +}; +getInstanceFromNode = getInstanceFromTag; +getNodeFromInstance = function(inst) { + var tag = inst.stateNode._nativeTag; + void 0 === tag && (tag = inst.stateNode.canonical._nativeTag); + if (!tag) throw ReactError("All native instances should have a tag."); + return tag; +}; +ResponderEventPlugin.injection.injectGlobalResponderHandler({ + onChange: function(from, to, blockNativeResponder) { + null !== to + ? ReactNativePrivateInterface.UIManager.setJSResponder( + to.stateNode._nativeTag, + blockNativeResponder + ) + : ReactNativePrivateInterface.UIManager.clearJSResponder(); + } +}); +var ReactSharedInternals = + React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; +ReactSharedInternals.hasOwnProperty("ReactCurrentDispatcher") || + (ReactSharedInternals.ReactCurrentDispatcher = { current: null }); +var hasSymbol = "function" === typeof Symbol && Symbol.for, + REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for("react.element") : 60103, + REACT_PORTAL_TYPE = hasSymbol ? Symbol.for("react.portal") : 60106, + REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for("react.fragment") : 60107, + REACT_STRICT_MODE_TYPE = hasSymbol ? Symbol.for("react.strict_mode") : 60108, + REACT_PROFILER_TYPE = hasSymbol ? Symbol.for("react.profiler") : 60114, + REACT_PROVIDER_TYPE = hasSymbol ? Symbol.for("react.provider") : 60109, + REACT_CONTEXT_TYPE = hasSymbol ? Symbol.for("react.context") : 60110, + REACT_CONCURRENT_MODE_TYPE = hasSymbol + ? Symbol.for("react.concurrent_mode") + : 60111, + REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for("react.forward_ref") : 60112, + REACT_SUSPENSE_TYPE = hasSymbol ? Symbol.for("react.suspense") : 60113, + REACT_MEMO_TYPE = hasSymbol ? Symbol.for("react.memo") : 60115, + REACT_LAZY_TYPE = hasSymbol ? Symbol.for("react.lazy") : 60116; +hasSymbol && Symbol.for("react.event_component"); +hasSymbol && Symbol.for("react.event_target"); +hasSymbol && Symbol.for("react.event_target.touch_hit"); +var MAYBE_ITERATOR_SYMBOL = "function" === typeof Symbol && Symbol.iterator; +function getIteratorFn(maybeIterable) { + if (null === maybeIterable || "object" !== typeof maybeIterable) return null; + maybeIterable = + (MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL]) || + maybeIterable["@@iterator"]; + return "function" === typeof maybeIterable ? maybeIterable : null; +} +require("../shims/ReactFeatureFlags"); +function getComponentName(type) { + if (null == type) return null; + if ("function" === typeof type) return type.displayName || type.name || null; + if ("string" === typeof type) return type; + switch (type) { + case REACT_CONCURRENT_MODE_TYPE: + return "ConcurrentMode"; + case REACT_FRAGMENT_TYPE: + return "Fragment"; + case REACT_PORTAL_TYPE: + return "Portal"; + case REACT_PROFILER_TYPE: + return "Profiler"; + case REACT_STRICT_MODE_TYPE: + return "StrictMode"; + case REACT_SUSPENSE_TYPE: + return "Suspense"; + } + if ("object" === typeof type) + switch (type.$$typeof) { + case REACT_CONTEXT_TYPE: + return "Context.Consumer"; + case REACT_PROVIDER_TYPE: + return "Context.Provider"; + case REACT_FORWARD_REF_TYPE: + var innerType = type.render; + innerType = innerType.displayName || innerType.name || ""; + return ( + type.displayName || + ("" !== innerType ? "ForwardRef(" + innerType + ")" : "ForwardRef") + ); + case REACT_MEMO_TYPE: + return getComponentName(type.type); + case REACT_LAZY_TYPE: + if ((type = 1 === type._status ? type._result : null)) + return getComponentName(type); + } + return null; +} +function isFiberMountedImpl(fiber) { + var node = fiber; + if (fiber.alternate) for (; node.return; ) node = node.return; + else { + if (0 !== (node.effectTag & 2)) return 1; + for (; node.return; ) + if (((node = node.return), 0 !== (node.effectTag & 2))) return 1; + } + return 3 === node.tag ? 2 : 3; +} +function assertIsMounted(fiber) { + if (2 !== isFiberMountedImpl(fiber)) + throw ReactError("Unable to find node on an unmounted component."); +} +function findCurrentFiberUsingSlowPath(fiber) { + var alternate = fiber.alternate; + if (!alternate) { + alternate = isFiberMountedImpl(fiber); + if (3 === alternate) + throw ReactError("Unable to find node on an unmounted component."); + return 1 === alternate ? null : fiber; + } + for (var a = fiber, b = alternate; ; ) { + var parentA = a.return; + if (null === parentA) break; + var parentB = parentA.alternate; + if (null === parentB) { + b = parentA.return; + if (null !== b) { + a = b; + continue; + } + break; + } + if (parentA.child === parentB.child) { + for (parentB = parentA.child; parentB; ) { + if (parentB === a) return assertIsMounted(parentA), fiber; + if (parentB === b) return assertIsMounted(parentA), alternate; + parentB = parentB.sibling; + } + throw ReactError("Unable to find node on an unmounted component."); + } + if (a.return !== b.return) (a = parentA), (b = parentB); + else { + for (var didFindChild = !1, _child = parentA.child; _child; ) { + if (_child === a) { + didFindChild = !0; + a = parentA; + b = parentB; + break; + } + if (_child === b) { + didFindChild = !0; + b = parentA; + a = parentB; + break; + } + _child = _child.sibling; + } + if (!didFindChild) { + for (_child = parentB.child; _child; ) { + if (_child === a) { + didFindChild = !0; + a = parentB; + b = parentA; + break; + } + if (_child === b) { + didFindChild = !0; + b = parentB; + a = parentA; + break; + } + _child = _child.sibling; + } + if (!didFindChild) + throw ReactError( + "Child was not found in either parent set. This indicates a bug in React related to the return pointer. Please file an issue." + ); + } + } + if (a.alternate !== b) + throw ReactError( + "Return fibers should always be each others' alternates. This error is likely caused by a bug in React. Please file an issue." + ); + } + if (3 !== a.tag) + throw ReactError("Unable to find node on an unmounted component."); + return a.stateNode.current === a ? fiber : alternate; +} +function findCurrentHostFiber(parent) { + parent = findCurrentFiberUsingSlowPath(parent); + if (!parent) return null; + for (var node = parent; ; ) { + if (5 === node.tag || 6 === node.tag) return node; + if (node.child) (node.child.return = node), (node = node.child); + else { + if (node === parent) break; + for (; !node.sibling; ) { + if (!node.return || node.return === parent) return null; + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + } + return null; +} +var emptyObject = {}, + removedKeys = null, + removedKeyCount = 0; +function restoreDeletedValuesInNestedArray( + updatePayload, + node, + validAttributes +) { + if (Array.isArray(node)) + for (var i = node.length; i-- && 0 < removedKeyCount; ) + restoreDeletedValuesInNestedArray( + updatePayload, + node[i], + validAttributes + ); + else if (node && 0 < removedKeyCount) + for (i in removedKeys) + if (removedKeys[i]) { + var nextProp = node[i]; + if (void 0 !== nextProp) { + var attributeConfig = validAttributes[i]; + if (attributeConfig) { + "function" === typeof nextProp && (nextProp = !0); + "undefined" === typeof nextProp && (nextProp = null); + if ("object" !== typeof attributeConfig) + updatePayload[i] = nextProp; + else if ( + "function" === typeof attributeConfig.diff || + "function" === typeof attributeConfig.process + ) + (nextProp = + "function" === typeof attributeConfig.process + ? attributeConfig.process(nextProp) + : nextProp), + (updatePayload[i] = nextProp); + removedKeys[i] = !1; + removedKeyCount--; + } + } + } +} +function diffNestedProperty( + updatePayload, + prevProp, + nextProp, + validAttributes +) { + if (!updatePayload && prevProp === nextProp) return updatePayload; + if (!prevProp || !nextProp) + return nextProp + ? addNestedProperty(updatePayload, nextProp, validAttributes) + : prevProp + ? clearNestedProperty(updatePayload, prevProp, validAttributes) + : updatePayload; + if (!Array.isArray(prevProp) && !Array.isArray(nextProp)) + return diffProperties(updatePayload, prevProp, nextProp, validAttributes); + if (Array.isArray(prevProp) && Array.isArray(nextProp)) { + var minLength = + prevProp.length < nextProp.length ? prevProp.length : nextProp.length, + i; + for (i = 0; i < minLength; i++) + updatePayload = diffNestedProperty( + updatePayload, + prevProp[i], + nextProp[i], + validAttributes + ); + for (; i < prevProp.length; i++) + updatePayload = clearNestedProperty( + updatePayload, + prevProp[i], + validAttributes + ); + for (; i < nextProp.length; i++) + updatePayload = addNestedProperty( + updatePayload, + nextProp[i], + validAttributes + ); + return updatePayload; + } + return Array.isArray(prevProp) + ? diffProperties( + updatePayload, + ReactNativePrivateInterface.flattenStyle(prevProp), + nextProp, + validAttributes + ) + : diffProperties( + updatePayload, + prevProp, + ReactNativePrivateInterface.flattenStyle(nextProp), + validAttributes + ); +} +function addNestedProperty(updatePayload, nextProp, validAttributes) { + if (!nextProp) return updatePayload; + if (!Array.isArray(nextProp)) + return diffProperties( + updatePayload, + emptyObject, + nextProp, + validAttributes + ); + for (var i = 0; i < nextProp.length; i++) + updatePayload = addNestedProperty( + updatePayload, + nextProp[i], + validAttributes + ); + return updatePayload; +} +function clearNestedProperty(updatePayload, prevProp, validAttributes) { + if (!prevProp) return updatePayload; + if (!Array.isArray(prevProp)) + return diffProperties( + updatePayload, + prevProp, + emptyObject, + validAttributes + ); + for (var i = 0; i < prevProp.length; i++) + updatePayload = clearNestedProperty( + updatePayload, + prevProp[i], + validAttributes + ); + return updatePayload; +} +function diffProperties(updatePayload, prevProps, nextProps, validAttributes) { + var attributeConfig, propKey; + for (propKey in nextProps) + if ((attributeConfig = validAttributes[propKey])) { + var prevProp = prevProps[propKey]; + var nextProp = nextProps[propKey]; + "function" === typeof nextProp && + ((nextProp = !0), "function" === typeof prevProp && (prevProp = !0)); + "undefined" === typeof nextProp && + ((nextProp = null), + "undefined" === typeof prevProp && (prevProp = null)); + removedKeys && (removedKeys[propKey] = !1); + if (updatePayload && void 0 !== updatePayload[propKey]) + if ("object" !== typeof attributeConfig) + updatePayload[propKey] = nextProp; + else { + if ( + "function" === typeof attributeConfig.diff || + "function" === typeof attributeConfig.process + ) + (attributeConfig = + "function" === typeof attributeConfig.process + ? attributeConfig.process(nextProp) + : nextProp), + (updatePayload[propKey] = attributeConfig); + } + else if (prevProp !== nextProp) + if ("object" !== typeof attributeConfig) + ("object" !== typeof nextProp || + null === nextProp || + ReactNativePrivateInterface.deepDiffer(prevProp, nextProp)) && + ((updatePayload || (updatePayload = {}))[propKey] = nextProp); + else if ( + "function" === typeof attributeConfig.diff || + "function" === typeof attributeConfig.process + ) { + if ( + void 0 === prevProp || + ("function" === typeof attributeConfig.diff + ? attributeConfig.diff(prevProp, nextProp) + : "object" !== typeof nextProp || + null === nextProp || + ReactNativePrivateInterface.deepDiffer(prevProp, nextProp)) + ) + (attributeConfig = + "function" === typeof attributeConfig.process + ? attributeConfig.process(nextProp) + : nextProp), + ((updatePayload || (updatePayload = {}))[ + propKey + ] = attributeConfig); + } else + (removedKeys = null), + (removedKeyCount = 0), + (updatePayload = diffNestedProperty( + updatePayload, + prevProp, + nextProp, + attributeConfig + )), + 0 < removedKeyCount && + updatePayload && + (restoreDeletedValuesInNestedArray( + updatePayload, + nextProp, + attributeConfig + ), + (removedKeys = null)); + } + for (var _propKey in prevProps) + void 0 === nextProps[_propKey] && + (!(attributeConfig = validAttributes[_propKey]) || + (updatePayload && void 0 !== updatePayload[_propKey]) || + ((prevProp = prevProps[_propKey]), + void 0 !== prevProp && + ("object" !== typeof attributeConfig || + "function" === typeof attributeConfig.diff || + "function" === typeof attributeConfig.process + ? (((updatePayload || (updatePayload = {}))[_propKey] = null), + removedKeys || (removedKeys = {}), + removedKeys[_propKey] || + ((removedKeys[_propKey] = !0), removedKeyCount++)) + : (updatePayload = clearNestedProperty( + updatePayload, + prevProp, + attributeConfig + ))))); + return updatePayload; +} +function mountSafeCallback_NOT_REALLY_SAFE(context, callback) { + return function() { + if ( + callback && + ("boolean" !== typeof context.__isMounted || context.__isMounted) + ) + return callback.apply(context, arguments); + }; +} +var ReactNativeFiberHostComponent = (function() { + function ReactNativeFiberHostComponent(tag, viewConfig) { + if (!(this instanceof ReactNativeFiberHostComponent)) + throw new TypeError("Cannot call a class as a function"); + this._nativeTag = tag; + this._children = []; + this.viewConfig = viewConfig; + } + ReactNativeFiberHostComponent.prototype.blur = function() { + ReactNativePrivateInterface.TextInputState.blurTextInput(this._nativeTag); + }; + ReactNativeFiberHostComponent.prototype.focus = function() { + ReactNativePrivateInterface.TextInputState.focusTextInput(this._nativeTag); + }; + ReactNativeFiberHostComponent.prototype.measure = function(callback) { + ReactNativePrivateInterface.UIManager.measure( + this._nativeTag, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + }; + ReactNativeFiberHostComponent.prototype.measureInWindow = function(callback) { + ReactNativePrivateInterface.UIManager.measureInWindow( + this._nativeTag, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + }; + ReactNativeFiberHostComponent.prototype.measureLayout = function( + relativeToNativeNode, + onSuccess, + onFail + ) { + var relativeNode = void 0; + "number" === typeof relativeToNativeNode + ? (relativeNode = relativeToNativeNode) + : relativeToNativeNode._nativeTag + ? (relativeNode = relativeToNativeNode._nativeTag) + : relativeToNativeNode.canonical && + relativeToNativeNode.canonical._nativeTag && + (relativeNode = relativeToNativeNode.canonical._nativeTag); + null != relativeNode && + ReactNativePrivateInterface.UIManager.measureLayout( + this._nativeTag, + relativeNode, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + ); + }; + ReactNativeFiberHostComponent.prototype.setNativeProps = function( + nativeProps + ) { + nativeProps = diffProperties( + null, + emptyObject, + nativeProps, + this.viewConfig.validAttributes + ); + null != nativeProps && + ReactNativePrivateInterface.UIManager.updateView( + this._nativeTag, + this.viewConfig.uiViewClassName, + nativeProps + ); + }; + return ReactNativeFiberHostComponent; +})(); +function shim$1() { + throw ReactError( + "The current renderer does not support hydration. This error is likely caused by a bug in React. Please file an issue." + ); +} +var getViewConfigForType = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.get, + UPDATE_SIGNAL = {}, + nextReactTag = 3; +function allocateTag() { + var tag = nextReactTag; + 1 === tag % 10 && (tag += 2); + nextReactTag = tag + 2; + return tag; +} +function recursivelyUncacheFiberNode(node) { + if ("number" === typeof node) + delete instanceCache[node], delete instanceProps[node]; + else { + var tag = node._nativeTag; + delete instanceCache[tag]; + delete instanceProps[tag]; + node._children.forEach(recursivelyUncacheFiberNode); + } +} +function finalizeInitialChildren(parentInstance) { + if (0 === parentInstance._children.length) return !1; + var nativeTags = parentInstance._children.map(function(child) { + return "number" === typeof child ? child : child._nativeTag; + }); + ReactNativePrivateInterface.UIManager.setChildren( + parentInstance._nativeTag, + nativeTags + ); + return !1; +} +var scheduleTimeout = setTimeout, + cancelTimeout = clearTimeout, + BEFORE_SLASH_RE = /^(.*)[\\\/]/; +function getStackByFiberInDevAndProd(workInProgress) { + var info = ""; + do { + a: switch (workInProgress.tag) { + case 3: + case 4: + case 6: + case 7: + case 10: + case 9: + var JSCompiler_inline_result = ""; + break a; + default: + var owner = workInProgress._debugOwner, + source = workInProgress._debugSource, + name = getComponentName(workInProgress.type); + JSCompiler_inline_result = null; + owner && (JSCompiler_inline_result = getComponentName(owner.type)); + owner = name; + name = ""; + source + ? (name = + " (at " + + source.fileName.replace(BEFORE_SLASH_RE, "") + + ":" + + source.lineNumber + + ")") + : JSCompiler_inline_result && + (name = " (created by " + JSCompiler_inline_result + ")"); + JSCompiler_inline_result = "\n in " + (owner || "Unknown") + name; + } + info += JSCompiler_inline_result; + workInProgress = workInProgress.return; + } while (workInProgress); + return info; +} +new Set(); +var valueStack = [], + index = -1; +function pop(cursor) { + 0 > index || + ((cursor.current = valueStack[index]), (valueStack[index] = null), index--); +} +function push(cursor, value) { + index++; + valueStack[index] = cursor.current; + cursor.current = value; +} +var emptyContextObject = {}, + contextStackCursor = { current: emptyContextObject }, + didPerformWorkStackCursor = { current: !1 }, + previousContext = emptyContextObject; +function getMaskedContext(workInProgress, unmaskedContext) { + var contextTypes = workInProgress.type.contextTypes; + if (!contextTypes) return emptyContextObject; + var instance = workInProgress.stateNode; + if ( + instance && + instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext + ) + return instance.__reactInternalMemoizedMaskedChildContext; + var context = {}, + key; + for (key in contextTypes) context[key] = unmaskedContext[key]; + instance && + ((workInProgress = workInProgress.stateNode), + (workInProgress.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext), + (workInProgress.__reactInternalMemoizedMaskedChildContext = context)); + return context; +} +function isContextProvider(type) { + type = type.childContextTypes; + return null !== type && void 0 !== type; +} +function popContext(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); +} +function popTopLevelContextObject(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); +} +function pushTopLevelContextObject(fiber, context, didChange) { + if (contextStackCursor.current !== emptyContextObject) + throw ReactError( + "Unexpected context found on stack. This error is likely caused by a bug in React. Please file an issue." + ); + push(contextStackCursor, context, fiber); + push(didPerformWorkStackCursor, didChange, fiber); +} +function processChildContext(fiber, type, parentContext) { + var instance = fiber.stateNode; + fiber = type.childContextTypes; + if ("function" !== typeof instance.getChildContext) return parentContext; + instance = instance.getChildContext(); + for (var contextKey in instance) + if (!(contextKey in fiber)) + throw ReactError( + (getComponentName(type) || "Unknown") + + '.getChildContext(): key "' + + contextKey + + '" is not defined in childContextTypes.' + ); + return Object.assign({}, parentContext, instance); +} +function pushContextProvider(workInProgress) { + var instance = workInProgress.stateNode; + instance = + (instance && instance.__reactInternalMemoizedMergedChildContext) || + emptyContextObject; + previousContext = contextStackCursor.current; + push(contextStackCursor, instance, workInProgress); + push( + didPerformWorkStackCursor, + didPerformWorkStackCursor.current, + workInProgress + ); + return !0; +} +function invalidateContextProvider(workInProgress, type, didChange) { + var instance = workInProgress.stateNode; + if (!instance) + throw ReactError( + "Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue." + ); + didChange + ? ((type = processChildContext(workInProgress, type, previousContext)), + (instance.__reactInternalMemoizedMergedChildContext = type), + pop(didPerformWorkStackCursor, workInProgress), + pop(contextStackCursor, workInProgress), + push(contextStackCursor, type, workInProgress)) + : pop(didPerformWorkStackCursor, workInProgress); + push(didPerformWorkStackCursor, didChange, workInProgress); +} +var onCommitFiberRoot = null, + onCommitFiberUnmount = null; +function catchErrors(fn) { + return function(arg) { + try { + return fn(arg); + } catch (err) {} + }; +} +function injectInternals(internals) { + if ("undefined" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) return !1; + var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__; + if (hook.isDisabled || !hook.supportsFiber) return !0; + try { + var rendererID = hook.inject(internals); + onCommitFiberRoot = catchErrors(function(root) { + return hook.onCommitFiberRoot(rendererID, root); + }); + onCommitFiberUnmount = catchErrors(function(fiber) { + return hook.onCommitFiberUnmount(rendererID, fiber); + }); + } catch (err) {} + return !0; +} +var Scheduler_runWithPriority = Scheduler.unstable_runWithPriority, + Scheduler_scheduleCallback = Scheduler.unstable_scheduleCallback, + Scheduler_cancelCallback = Scheduler.unstable_cancelCallback, + Scheduler_now = Scheduler.unstable_now, + Scheduler_getCurrentPriorityLevel = + Scheduler.unstable_getCurrentPriorityLevel, + Scheduler_ImmediatePriority = Scheduler.unstable_ImmediatePriority, + Scheduler_UserBlockingPriority = Scheduler.unstable_UserBlockingPriority, + Scheduler_NormalPriority = Scheduler.unstable_NormalPriority, + Scheduler_LowPriority = Scheduler.unstable_LowPriority, + Scheduler_IdlePriority = Scheduler.unstable_IdlePriority, + fakeCallbackNode = {}, + shouldYield = Scheduler.unstable_shouldYield, + immediateQueue = null, + immediateQueueCallbackNode = null, + isFlushingImmediate = !1, + initialTimeMs = Scheduler_now(), + now = + 1e4 > initialTimeMs + ? Scheduler_now + : function() { + return Scheduler_now() - initialTimeMs; + }; +function getCurrentPriorityLevel() { + switch (Scheduler_getCurrentPriorityLevel()) { + case Scheduler_ImmediatePriority: + return 99; + case Scheduler_UserBlockingPriority: + return 98; + case Scheduler_NormalPriority: + return 97; + case Scheduler_LowPriority: + return 96; + case Scheduler_IdlePriority: + return 95; + default: + throw ReactError("Unknown priority level."); + } +} +function reactPriorityToSchedulerPriority(reactPriorityLevel) { + switch (reactPriorityLevel) { + case 99: + return Scheduler_ImmediatePriority; + case 98: + return Scheduler_UserBlockingPriority; + case 97: + return Scheduler_NormalPriority; + case 96: + return Scheduler_LowPriority; + case 95: + return Scheduler_IdlePriority; + default: + throw ReactError("Unknown priority level."); + } +} +function runWithPriority(reactPriorityLevel, fn) { + reactPriorityLevel = reactPriorityToSchedulerPriority(reactPriorityLevel); + return Scheduler_runWithPriority(reactPriorityLevel, fn); +} +function scheduleCallback(reactPriorityLevel, callback, options) { + if (99 === reactPriorityLevel) + return ( + null === immediateQueue + ? ((immediateQueue = [callback]), + (immediateQueueCallbackNode = Scheduler_scheduleCallback( + Scheduler_ImmediatePriority, + flushImmediateQueueImpl + ))) + : immediateQueue.push(callback), + fakeCallbackNode + ); + reactPriorityLevel = reactPriorityToSchedulerPriority(reactPriorityLevel); + return Scheduler_scheduleCallback(reactPriorityLevel, callback, options); +} +function flushImmediateQueue() { + null !== immediateQueueCallbackNode && + Scheduler_cancelCallback(immediateQueueCallbackNode); + flushImmediateQueueImpl(); +} +function flushImmediateQueueImpl() { + if (!isFlushingImmediate && null !== immediateQueue) { + isFlushingImmediate = !0; + var i = 0; + try { + for (; i < immediateQueue.length; i++) { + var callback = immediateQueue[i]; + do callback = callback(!0); + while (null !== callback); + } + immediateQueue = null; + } catch (error) { + throw (null !== immediateQueue && + (immediateQueue = immediateQueue.slice(i + 1)), + Scheduler_scheduleCallback( + Scheduler_ImmediatePriority, + flushImmediateQueue + ), + error); + } finally { + isFlushingImmediate = !1; + } + } +} +function inferPriorityFromExpirationTime(currentTime, expirationTime) { + if (1073741823 === expirationTime) return 99; + if (1 === expirationTime) return 95; + currentTime = + 10 * (1073741822 - expirationTime) - 10 * (1073741822 - currentTime); + return 0 >= currentTime + ? 99 + : 250 >= currentTime + ? 98 + : 5250 >= currentTime + ? 97 + : 95; +} +function FiberNode(tag, pendingProps, key, mode) { + this.tag = tag; + this.key = key; + this.sibling = this.child = this.return = this.stateNode = this.type = this.elementType = null; + this.index = 0; + this.ref = null; + this.pendingProps = pendingProps; + this.contextDependencies = this.memoizedState = this.updateQueue = this.memoizedProps = null; + this.mode = mode; + this.effectTag = 0; + this.lastEffect = this.firstEffect = this.nextEffect = null; + this.childExpirationTime = this.expirationTime = 0; + this.alternate = null; +} +function createFiber(tag, pendingProps, key, mode) { + return new FiberNode(tag, pendingProps, key, mode); +} +function shouldConstruct(Component) { + Component = Component.prototype; + return !(!Component || !Component.isReactComponent); +} +function resolveLazyComponentTag(Component) { + if ("function" === typeof Component) + return shouldConstruct(Component) ? 1 : 0; + if (void 0 !== Component && null !== Component) { + Component = Component.$$typeof; + if (Component === REACT_FORWARD_REF_TYPE) return 11; + if (Component === REACT_MEMO_TYPE) return 14; + } + return 2; +} +function createWorkInProgress(current, pendingProps) { + var workInProgress = current.alternate; + null === workInProgress + ? ((workInProgress = createFiber( + current.tag, + pendingProps, + current.key, + current.mode + )), + (workInProgress.elementType = current.elementType), + (workInProgress.type = current.type), + (workInProgress.stateNode = current.stateNode), + (workInProgress.alternate = current), + (current.alternate = workInProgress)) + : ((workInProgress.pendingProps = pendingProps), + (workInProgress.effectTag = 0), + (workInProgress.nextEffect = null), + (workInProgress.firstEffect = null), + (workInProgress.lastEffect = null)); + workInProgress.childExpirationTime = current.childExpirationTime; + workInProgress.expirationTime = current.expirationTime; + workInProgress.child = current.child; + workInProgress.memoizedProps = current.memoizedProps; + workInProgress.memoizedState = current.memoizedState; + workInProgress.updateQueue = current.updateQueue; + workInProgress.contextDependencies = current.contextDependencies; + workInProgress.sibling = current.sibling; + workInProgress.index = current.index; + workInProgress.ref = current.ref; + return workInProgress; +} +function createFiberFromTypeAndProps( + type, + key, + pendingProps, + owner, + mode, + expirationTime +) { + var fiberTag = 2; + owner = type; + if ("function" === typeof type) shouldConstruct(type) && (fiberTag = 1); + else if ("string" === typeof type) fiberTag = 5; + else + a: switch (type) { + case REACT_FRAGMENT_TYPE: + return createFiberFromFragment( + pendingProps.children, + mode, + expirationTime, + key + ); + case REACT_CONCURRENT_MODE_TYPE: + return createFiberFromMode(pendingProps, mode | 3, expirationTime, key); + case REACT_STRICT_MODE_TYPE: + return createFiberFromMode(pendingProps, mode | 2, expirationTime, key); + case REACT_PROFILER_TYPE: + return ( + (type = createFiber(12, pendingProps, key, mode | 4)), + (type.elementType = REACT_PROFILER_TYPE), + (type.type = REACT_PROFILER_TYPE), + (type.expirationTime = expirationTime), + type + ); + case REACT_SUSPENSE_TYPE: + return ( + (type = createFiber(13, pendingProps, key, mode)), + (type.elementType = REACT_SUSPENSE_TYPE), + (type.type = REACT_SUSPENSE_TYPE), + (type.expirationTime = expirationTime), + type + ); + default: + if ("object" === typeof type && null !== type) + switch (type.$$typeof) { + case REACT_PROVIDER_TYPE: + fiberTag = 10; + break a; + case REACT_CONTEXT_TYPE: + fiberTag = 9; + break a; + case REACT_FORWARD_REF_TYPE: + fiberTag = 11; + break a; + case REACT_MEMO_TYPE: + fiberTag = 14; + break a; + case REACT_LAZY_TYPE: + fiberTag = 16; + owner = null; + break a; + } + throw ReactError( + "Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: " + + (null == type ? type : typeof type) + + "." + ); + } + key = createFiber(fiberTag, pendingProps, key, mode); + key.elementType = type; + key.type = owner; + key.expirationTime = expirationTime; + return key; +} +function createFiberFromFragment(elements, mode, expirationTime, key) { + elements = createFiber(7, elements, key, mode); + elements.expirationTime = expirationTime; + return elements; +} +function createFiberFromMode(pendingProps, mode, expirationTime, key) { + pendingProps = createFiber(8, pendingProps, key, mode); + mode = 0 === (mode & 1) ? REACT_STRICT_MODE_TYPE : REACT_CONCURRENT_MODE_TYPE; + pendingProps.elementType = mode; + pendingProps.type = mode; + pendingProps.expirationTime = expirationTime; + return pendingProps; +} +function createFiberFromText(content, mode, expirationTime) { + content = createFiber(6, content, null, mode); + content.expirationTime = expirationTime; + return content; +} +function createFiberFromPortal(portal, mode, expirationTime) { + mode = createFiber( + 4, + null !== portal.children ? portal.children : [], + portal.key, + mode + ); + mode.expirationTime = expirationTime; + mode.stateNode = { + containerInfo: portal.containerInfo, + pendingChildren: null, + implementation: portal.implementation + }; + return mode; +} +function FiberRootNode(containerInfo, hydrate) { + this.current = null; + this.containerInfo = containerInfo; + this.pingCache = this.pendingChildren = null; + this.pendingCommitExpirationTime = 0; + this.finishedWork = null; + this.timeoutHandle = -1; + this.pendingContext = this.context = null; + this.hydrate = hydrate; + this.callbackNode = this.firstBatch = null; + this.pingTime = this.lastPendingTime = this.firstPendingTime = this.callbackExpirationTime = 0; +} +function is(x, y) { + return (x === y && (0 !== x || 1 / x === 1 / y)) || (x !== x && y !== y); +} +var hasOwnProperty = Object.prototype.hasOwnProperty; +function shallowEqual(objA, objB) { + if (is(objA, objB)) return !0; + if ( + "object" !== typeof objA || + null === objA || + "object" !== typeof objB || + null === objB + ) + return !1; + var keysA = Object.keys(objA), + keysB = Object.keys(objB); + if (keysA.length !== keysB.length) return !1; + for (keysB = 0; keysB < keysA.length; keysB++) + if ( + !hasOwnProperty.call(objB, keysA[keysB]) || + !is(objA[keysA[keysB]], objB[keysA[keysB]]) + ) + return !1; + return !0; +} +function resolveDefaultProps(Component, baseProps) { + if (Component && Component.defaultProps) { + baseProps = Object.assign({}, baseProps); + Component = Component.defaultProps; + for (var propName in Component) + void 0 === baseProps[propName] && + (baseProps[propName] = Component[propName]); + } + return baseProps; +} +function readLazyComponentType(lazyComponent) { + var result = lazyComponent._result; + switch (lazyComponent._status) { + case 1: + return result; + case 2: + throw result; + case 0: + throw result; + default: + lazyComponent._status = 0; + result = lazyComponent._ctor; + result = result(); + result.then( + function(moduleObject) { + 0 === lazyComponent._status && + ((moduleObject = moduleObject.default), + (lazyComponent._status = 1), + (lazyComponent._result = moduleObject)); + }, + function(error) { + 0 === lazyComponent._status && + ((lazyComponent._status = 2), (lazyComponent._result = error)); + } + ); + switch (lazyComponent._status) { + case 1: + return lazyComponent._result; + case 2: + throw lazyComponent._result; + } + lazyComponent._result = result; + throw result; + } +} +var valueCursor = { current: null }, + currentlyRenderingFiber = null, + lastContextDependency = null, + lastContextWithAllBitsObserved = null; +function resetContextDependences() { + lastContextWithAllBitsObserved = lastContextDependency = currentlyRenderingFiber = null; +} +function pushProvider(providerFiber, nextValue) { + var context = providerFiber.type._context; + push(valueCursor, context._currentValue, providerFiber); + context._currentValue = nextValue; +} +function popProvider(providerFiber) { + var currentValue = valueCursor.current; + pop(valueCursor, providerFiber); + providerFiber.type._context._currentValue = currentValue; +} +function prepareToReadContext(workInProgress, renderExpirationTime) { + currentlyRenderingFiber = workInProgress; + lastContextWithAllBitsObserved = lastContextDependency = null; + var currentDependencies = workInProgress.contextDependencies; + null !== currentDependencies && + currentDependencies.expirationTime >= renderExpirationTime && + (didReceiveUpdate = !0); + workInProgress.contextDependencies = null; +} +function readContext(context, observedBits) { + if ( + lastContextWithAllBitsObserved !== context && + !1 !== observedBits && + 0 !== observedBits + ) { + if ("number" !== typeof observedBits || 1073741823 === observedBits) + (lastContextWithAllBitsObserved = context), (observedBits = 1073741823); + observedBits = { context: context, observedBits: observedBits, next: null }; + if (null === lastContextDependency) { + if (null === currentlyRenderingFiber) + throw ReactError( + "Context can only be read while React is rendering. In classes, you can read it in the render method or getDerivedStateFromProps. In function components, you can read it directly in the function body, but not inside Hooks like useReducer() or useMemo()." + ); + lastContextDependency = observedBits; + currentlyRenderingFiber.contextDependencies = { + first: observedBits, + expirationTime: 0 + }; + } else lastContextDependency = lastContextDependency.next = observedBits; + } + return context._currentValue; +} +var hasForceUpdate = !1; +function createUpdateQueue(baseState) { + return { + baseState: baseState, + firstUpdate: null, + lastUpdate: null, + firstCapturedUpdate: null, + lastCapturedUpdate: null, + firstEffect: null, + lastEffect: null, + firstCapturedEffect: null, + lastCapturedEffect: null + }; +} +function cloneUpdateQueue(currentQueue) { + return { + baseState: currentQueue.baseState, + firstUpdate: currentQueue.firstUpdate, + lastUpdate: currentQueue.lastUpdate, + firstCapturedUpdate: null, + lastCapturedUpdate: null, + firstEffect: null, + lastEffect: null, + firstCapturedEffect: null, + lastCapturedEffect: null + }; +} +function createUpdate(expirationTime) { + return { + expirationTime: expirationTime, + tag: 0, + payload: null, + callback: null, + next: null, + nextEffect: null + }; +} +function appendUpdateToQueue(queue, update) { + null === queue.lastUpdate + ? (queue.firstUpdate = queue.lastUpdate = update) + : ((queue.lastUpdate.next = update), (queue.lastUpdate = update)); +} +function enqueueUpdate(fiber, update) { + var alternate = fiber.alternate; + if (null === alternate) { + var queue1 = fiber.updateQueue; + var queue2 = null; + null === queue1 && + (queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState)); + } else + (queue1 = fiber.updateQueue), + (queue2 = alternate.updateQueue), + null === queue1 + ? null === queue2 + ? ((queue1 = fiber.updateQueue = createUpdateQueue( + fiber.memoizedState + )), + (queue2 = alternate.updateQueue = createUpdateQueue( + alternate.memoizedState + ))) + : (queue1 = fiber.updateQueue = cloneUpdateQueue(queue2)) + : null === queue2 && + (queue2 = alternate.updateQueue = cloneUpdateQueue(queue1)); + null === queue2 || queue1 === queue2 + ? appendUpdateToQueue(queue1, update) + : null === queue1.lastUpdate || null === queue2.lastUpdate + ? (appendUpdateToQueue(queue1, update), + appendUpdateToQueue(queue2, update)) + : (appendUpdateToQueue(queue1, update), (queue2.lastUpdate = update)); +} +function enqueueCapturedUpdate(workInProgress, update) { + var workInProgressQueue = workInProgress.updateQueue; + workInProgressQueue = + null === workInProgressQueue + ? (workInProgress.updateQueue = createUpdateQueue( + workInProgress.memoizedState + )) + : ensureWorkInProgressQueueIsAClone(workInProgress, workInProgressQueue); + null === workInProgressQueue.lastCapturedUpdate + ? (workInProgressQueue.firstCapturedUpdate = workInProgressQueue.lastCapturedUpdate = update) + : ((workInProgressQueue.lastCapturedUpdate.next = update), + (workInProgressQueue.lastCapturedUpdate = update)); +} +function ensureWorkInProgressQueueIsAClone(workInProgress, queue) { + var current = workInProgress.alternate; + null !== current && + queue === current.updateQueue && + (queue = workInProgress.updateQueue = cloneUpdateQueue(queue)); + return queue; +} +function getStateFromUpdate( + workInProgress, + queue, + update, + prevState, + nextProps, + instance +) { + switch (update.tag) { + case 1: + return ( + (workInProgress = update.payload), + "function" === typeof workInProgress + ? workInProgress.call(instance, prevState, nextProps) + : workInProgress + ); + case 3: + workInProgress.effectTag = (workInProgress.effectTag & -2049) | 64; + case 0: + workInProgress = update.payload; + nextProps = + "function" === typeof workInProgress + ? workInProgress.call(instance, prevState, nextProps) + : workInProgress; + if (null === nextProps || void 0 === nextProps) break; + return Object.assign({}, prevState, nextProps); + case 2: + hasForceUpdate = !0; + } + return prevState; +} +function processUpdateQueue( + workInProgress, + queue, + props, + instance, + renderExpirationTime +) { + hasForceUpdate = !1; + queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue); + for ( + var newBaseState = queue.baseState, + newFirstUpdate = null, + newExpirationTime = 0, + update = queue.firstUpdate, + resultState = newBaseState; + null !== update; + + ) { + var updateExpirationTime = update.expirationTime; + updateExpirationTime < renderExpirationTime + ? (null === newFirstUpdate && + ((newFirstUpdate = update), (newBaseState = resultState)), + newExpirationTime < updateExpirationTime && + (newExpirationTime = updateExpirationTime)) + : (updateExpirationTime < workInProgressRootMostRecentEventTime && + (workInProgressRootMostRecentEventTime = updateExpirationTime), + (resultState = getStateFromUpdate( + workInProgress, + queue, + update, + resultState, + props, + instance + )), + null !== update.callback && + ((workInProgress.effectTag |= 32), + (update.nextEffect = null), + null === queue.lastEffect + ? (queue.firstEffect = queue.lastEffect = update) + : ((queue.lastEffect.nextEffect = update), + (queue.lastEffect = update)))); + update = update.next; + } + updateExpirationTime = null; + for (update = queue.firstCapturedUpdate; null !== update; ) { + var _updateExpirationTime = update.expirationTime; + _updateExpirationTime < renderExpirationTime + ? (null === updateExpirationTime && + ((updateExpirationTime = update), + null === newFirstUpdate && (newBaseState = resultState)), + newExpirationTime < _updateExpirationTime && + (newExpirationTime = _updateExpirationTime)) + : ((resultState = getStateFromUpdate( + workInProgress, + queue, + update, + resultState, + props, + instance + )), + null !== update.callback && + ((workInProgress.effectTag |= 32), + (update.nextEffect = null), + null === queue.lastCapturedEffect + ? (queue.firstCapturedEffect = queue.lastCapturedEffect = update) + : ((queue.lastCapturedEffect.nextEffect = update), + (queue.lastCapturedEffect = update)))); + update = update.next; + } + null === newFirstUpdate && (queue.lastUpdate = null); + null === updateExpirationTime + ? (queue.lastCapturedUpdate = null) + : (workInProgress.effectTag |= 32); + null === newFirstUpdate && + null === updateExpirationTime && + (newBaseState = resultState); + queue.baseState = newBaseState; + queue.firstUpdate = newFirstUpdate; + queue.firstCapturedUpdate = updateExpirationTime; + workInProgress.expirationTime = newExpirationTime; + workInProgress.memoizedState = resultState; +} +function commitUpdateQueue(finishedWork, finishedQueue, instance) { + null !== finishedQueue.firstCapturedUpdate && + (null !== finishedQueue.lastUpdate && + ((finishedQueue.lastUpdate.next = finishedQueue.firstCapturedUpdate), + (finishedQueue.lastUpdate = finishedQueue.lastCapturedUpdate)), + (finishedQueue.firstCapturedUpdate = finishedQueue.lastCapturedUpdate = null)); + commitUpdateEffects(finishedQueue.firstEffect, instance); + finishedQueue.firstEffect = finishedQueue.lastEffect = null; + commitUpdateEffects(finishedQueue.firstCapturedEffect, instance); + finishedQueue.firstCapturedEffect = finishedQueue.lastCapturedEffect = null; +} +function commitUpdateEffects(effect, instance) { + for (; null !== effect; ) { + var _callback3 = effect.callback; + if (null !== _callback3) { + effect.callback = null; + var context = instance; + if ("function" !== typeof _callback3) + throw ReactError( + "Invalid argument passed as callback. Expected a function. Instead received: " + + _callback3 + ); + _callback3.call(context); + } + effect = effect.nextEffect; + } +} +var emptyRefsObject = new React.Component().refs; +function applyDerivedStateFromProps( + workInProgress, + ctor, + getDerivedStateFromProps, + nextProps +) { + ctor = workInProgress.memoizedState; + getDerivedStateFromProps = getDerivedStateFromProps(nextProps, ctor); + getDerivedStateFromProps = + null === getDerivedStateFromProps || void 0 === getDerivedStateFromProps + ? ctor + : Object.assign({}, ctor, getDerivedStateFromProps); + workInProgress.memoizedState = getDerivedStateFromProps; + nextProps = workInProgress.updateQueue; + null !== nextProps && + 0 === workInProgress.expirationTime && + (nextProps.baseState = getDerivedStateFromProps); +} +var classComponentUpdater = { + isMounted: function(component) { + return (component = component._reactInternalFiber) + ? 2 === isFiberMountedImpl(component) + : !1; + }, + enqueueSetState: function(inst, payload, callback) { + inst = inst._reactInternalFiber; + var currentTime = requestCurrentTime(); + currentTime = computeExpirationForFiber(currentTime, inst); + var update = createUpdate(currentTime); + update.payload = payload; + void 0 !== callback && null !== callback && (update.callback = callback); + flushPassiveEffects(); + enqueueUpdate(inst, update); + scheduleUpdateOnFiber(inst, currentTime); + }, + enqueueReplaceState: function(inst, payload, callback) { + inst = inst._reactInternalFiber; + var currentTime = requestCurrentTime(); + currentTime = computeExpirationForFiber(currentTime, inst); + var update = createUpdate(currentTime); + update.tag = 1; + update.payload = payload; + void 0 !== callback && null !== callback && (update.callback = callback); + flushPassiveEffects(); + enqueueUpdate(inst, update); + scheduleUpdateOnFiber(inst, currentTime); + }, + enqueueForceUpdate: function(inst, callback) { + inst = inst._reactInternalFiber; + var currentTime = requestCurrentTime(); + currentTime = computeExpirationForFiber(currentTime, inst); + var update = createUpdate(currentTime); + update.tag = 2; + void 0 !== callback && null !== callback && (update.callback = callback); + flushPassiveEffects(); + enqueueUpdate(inst, update); + scheduleUpdateOnFiber(inst, currentTime); + } +}; +function checkShouldComponentUpdate( + workInProgress, + ctor, + oldProps, + newProps, + oldState, + newState, + nextContext +) { + workInProgress = workInProgress.stateNode; + return "function" === typeof workInProgress.shouldComponentUpdate + ? workInProgress.shouldComponentUpdate(newProps, newState, nextContext) + : ctor.prototype && ctor.prototype.isPureReactComponent + ? !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState) + : !0; +} +function constructClassInstance(workInProgress, ctor, props) { + var isLegacyContextConsumer = !1, + unmaskedContext = emptyContextObject; + var context = ctor.contextType; + "object" === typeof context && null !== context + ? (context = readContext(context)) + : ((unmaskedContext = isContextProvider(ctor) + ? previousContext + : contextStackCursor.current), + (isLegacyContextConsumer = ctor.contextTypes), + (context = (isLegacyContextConsumer = + null !== isLegacyContextConsumer && void 0 !== isLegacyContextConsumer) + ? getMaskedContext(workInProgress, unmaskedContext) + : emptyContextObject)); + ctor = new ctor(props, context); + workInProgress.memoizedState = + null !== ctor.state && void 0 !== ctor.state ? ctor.state : null; + ctor.updater = classComponentUpdater; + workInProgress.stateNode = ctor; + ctor._reactInternalFiber = workInProgress; + isLegacyContextConsumer && + ((workInProgress = workInProgress.stateNode), + (workInProgress.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext), + (workInProgress.__reactInternalMemoizedMaskedChildContext = context)); + return ctor; +} +function callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + nextContext +) { + workInProgress = instance.state; + "function" === typeof instance.componentWillReceiveProps && + instance.componentWillReceiveProps(newProps, nextContext); + "function" === typeof instance.UNSAFE_componentWillReceiveProps && + instance.UNSAFE_componentWillReceiveProps(newProps, nextContext); + instance.state !== workInProgress && + classComponentUpdater.enqueueReplaceState(instance, instance.state, null); +} +function mountClassInstance( + workInProgress, + ctor, + newProps, + renderExpirationTime +) { + var instance = workInProgress.stateNode; + instance.props = newProps; + instance.state = workInProgress.memoizedState; + instance.refs = emptyRefsObject; + var contextType = ctor.contextType; + "object" === typeof contextType && null !== contextType + ? (instance.context = readContext(contextType)) + : ((contextType = isContextProvider(ctor) + ? previousContext + : contextStackCursor.current), + (instance.context = getMaskedContext(workInProgress, contextType))); + contextType = workInProgress.updateQueue; + null !== contextType && + (processUpdateQueue( + workInProgress, + contextType, + newProps, + instance, + renderExpirationTime + ), + (instance.state = workInProgress.memoizedState)); + contextType = ctor.getDerivedStateFromProps; + "function" === typeof contextType && + (applyDerivedStateFromProps(workInProgress, ctor, contextType, newProps), + (instance.state = workInProgress.memoizedState)); + "function" === typeof ctor.getDerivedStateFromProps || + "function" === typeof instance.getSnapshotBeforeUpdate || + ("function" !== typeof instance.UNSAFE_componentWillMount && + "function" !== typeof instance.componentWillMount) || + ((ctor = instance.state), + "function" === typeof instance.componentWillMount && + instance.componentWillMount(), + "function" === typeof instance.UNSAFE_componentWillMount && + instance.UNSAFE_componentWillMount(), + ctor !== instance.state && + classComponentUpdater.enqueueReplaceState(instance, instance.state, null), + (contextType = workInProgress.updateQueue), + null !== contextType && + (processUpdateQueue( + workInProgress, + contextType, + newProps, + instance, + renderExpirationTime + ), + (instance.state = workInProgress.memoizedState))); + "function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4); +} +var isArray = Array.isArray; +function coerceRef(returnFiber, current$$1, element) { + returnFiber = element.ref; + if ( + null !== returnFiber && + "function" !== typeof returnFiber && + "object" !== typeof returnFiber + ) { + if (element._owner) { + element = element._owner; + var inst = void 0; + if (element) { + if (1 !== element.tag) + throw ReactError( + "Function components cannot have refs. Did you mean to use React.forwardRef()?" + ); + inst = element.stateNode; + } + if (!inst) + throw ReactError( + "Missing owner for string ref " + + returnFiber + + ". This error is likely caused by a bug in React. Please file an issue." + ); + var stringRef = "" + returnFiber; + if ( + null !== current$$1 && + null !== current$$1.ref && + "function" === typeof current$$1.ref && + current$$1.ref._stringRef === stringRef + ) + return current$$1.ref; + current$$1 = function(value) { + var refs = inst.refs; + refs === emptyRefsObject && (refs = inst.refs = {}); + null === value ? delete refs[stringRef] : (refs[stringRef] = value); + }; + current$$1._stringRef = stringRef; + return current$$1; + } + if ("string" !== typeof returnFiber) + throw ReactError( + "Expected ref to be a function, a string, an object returned by React.createRef(), or null." + ); + if (!element._owner) + throw ReactError( + "Element ref was specified as a string (" + + returnFiber + + ") but no owner was set. This could happen for one of the following reasons:\n1. You may be adding a ref to a function component\n2. You may be adding a ref to a component that was not created inside a component's render method\n3. You have multiple copies of React loaded\nSee https://fb.me/react-refs-must-have-owner for more information." + ); + } + return returnFiber; +} +function throwOnInvalidObjectType(returnFiber, newChild) { + if ("textarea" !== returnFiber.type) + throw ReactError( + "Objects are not valid as a React child (found: " + + ("[object Object]" === Object.prototype.toString.call(newChild) + ? "object with keys {" + Object.keys(newChild).join(", ") + "}" + : newChild) + + ")." + ); +} +function ChildReconciler(shouldTrackSideEffects) { + function deleteChild(returnFiber, childToDelete) { + if (shouldTrackSideEffects) { + var last = returnFiber.lastEffect; + null !== last + ? ((last.nextEffect = childToDelete), + (returnFiber.lastEffect = childToDelete)) + : (returnFiber.firstEffect = returnFiber.lastEffect = childToDelete); + childToDelete.nextEffect = null; + childToDelete.effectTag = 8; + } + } + function deleteRemainingChildren(returnFiber, currentFirstChild) { + if (!shouldTrackSideEffects) return null; + for (; null !== currentFirstChild; ) + deleteChild(returnFiber, currentFirstChild), + (currentFirstChild = currentFirstChild.sibling); + return null; + } + function mapRemainingChildren(returnFiber, currentFirstChild) { + for (returnFiber = new Map(); null !== currentFirstChild; ) + null !== currentFirstChild.key + ? returnFiber.set(currentFirstChild.key, currentFirstChild) + : returnFiber.set(currentFirstChild.index, currentFirstChild), + (currentFirstChild = currentFirstChild.sibling); + return returnFiber; + } + function useFiber(fiber, pendingProps, expirationTime) { + fiber = createWorkInProgress(fiber, pendingProps, expirationTime); + fiber.index = 0; + fiber.sibling = null; + return fiber; + } + function placeChild(newFiber, lastPlacedIndex, newIndex) { + newFiber.index = newIndex; + if (!shouldTrackSideEffects) return lastPlacedIndex; + newIndex = newFiber.alternate; + if (null !== newIndex) + return ( + (newIndex = newIndex.index), + newIndex < lastPlacedIndex + ? ((newFiber.effectTag = 2), lastPlacedIndex) + : newIndex + ); + newFiber.effectTag = 2; + return lastPlacedIndex; + } + function placeSingleChild(newFiber) { + shouldTrackSideEffects && + null === newFiber.alternate && + (newFiber.effectTag = 2); + return newFiber; + } + function updateTextNode( + returnFiber, + current$$1, + textContent, + expirationTime + ) { + if (null === current$$1 || 6 !== current$$1.tag) + return ( + (current$$1 = createFiberFromText( + textContent, + returnFiber.mode, + expirationTime + )), + (current$$1.return = returnFiber), + current$$1 + ); + current$$1 = useFiber(current$$1, textContent, expirationTime); + current$$1.return = returnFiber; + return current$$1; + } + function updateElement(returnFiber, current$$1, element, expirationTime) { + if (null !== current$$1 && current$$1.elementType === element.type) + return ( + (expirationTime = useFiber(current$$1, element.props, expirationTime)), + (expirationTime.ref = coerceRef(returnFiber, current$$1, element)), + (expirationTime.return = returnFiber), + expirationTime + ); + expirationTime = createFiberFromTypeAndProps( + element.type, + element.key, + element.props, + null, + returnFiber.mode, + expirationTime + ); + expirationTime.ref = coerceRef(returnFiber, current$$1, element); + expirationTime.return = returnFiber; + return expirationTime; + } + function updatePortal(returnFiber, current$$1, portal, expirationTime) { + if ( + null === current$$1 || + 4 !== current$$1.tag || + current$$1.stateNode.containerInfo !== portal.containerInfo || + current$$1.stateNode.implementation !== portal.implementation + ) + return ( + (current$$1 = createFiberFromPortal( + portal, + returnFiber.mode, + expirationTime + )), + (current$$1.return = returnFiber), + current$$1 + ); + current$$1 = useFiber(current$$1, portal.children || [], expirationTime); + current$$1.return = returnFiber; + return current$$1; + } + function updateFragment( + returnFiber, + current$$1, + fragment, + expirationTime, + key + ) { + if (null === current$$1 || 7 !== current$$1.tag) + return ( + (current$$1 = createFiberFromFragment( + fragment, + returnFiber.mode, + expirationTime, + key + )), + (current$$1.return = returnFiber), + current$$1 + ); + current$$1 = useFiber(current$$1, fragment, expirationTime); + current$$1.return = returnFiber; + return current$$1; + } + function createChild(returnFiber, newChild, expirationTime) { + if ("string" === typeof newChild || "number" === typeof newChild) + return ( + (newChild = createFiberFromText( + "" + newChild, + returnFiber.mode, + expirationTime + )), + (newChild.return = returnFiber), + newChild + ); + if ("object" === typeof newChild && null !== newChild) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return ( + (expirationTime = createFiberFromTypeAndProps( + newChild.type, + newChild.key, + newChild.props, + null, + returnFiber.mode, + expirationTime + )), + (expirationTime.ref = coerceRef(returnFiber, null, newChild)), + (expirationTime.return = returnFiber), + expirationTime + ); + case REACT_PORTAL_TYPE: + return ( + (newChild = createFiberFromPortal( + newChild, + returnFiber.mode, + expirationTime + )), + (newChild.return = returnFiber), + newChild + ); + } + if (isArray(newChild) || getIteratorFn(newChild)) + return ( + (newChild = createFiberFromFragment( + newChild, + returnFiber.mode, + expirationTime, + null + )), + (newChild.return = returnFiber), + newChild + ); + throwOnInvalidObjectType(returnFiber, newChild); + } + return null; + } + function updateSlot(returnFiber, oldFiber, newChild, expirationTime) { + var key = null !== oldFiber ? oldFiber.key : null; + if ("string" === typeof newChild || "number" === typeof newChild) + return null !== key + ? null + : updateTextNode(returnFiber, oldFiber, "" + newChild, expirationTime); + if ("object" === typeof newChild && null !== newChild) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return newChild.key === key + ? newChild.type === REACT_FRAGMENT_TYPE + ? updateFragment( + returnFiber, + oldFiber, + newChild.props.children, + expirationTime, + key + ) + : updateElement(returnFiber, oldFiber, newChild, expirationTime) + : null; + case REACT_PORTAL_TYPE: + return newChild.key === key + ? updatePortal(returnFiber, oldFiber, newChild, expirationTime) + : null; + } + if (isArray(newChild) || getIteratorFn(newChild)) + return null !== key + ? null + : updateFragment( + returnFiber, + oldFiber, + newChild, + expirationTime, + null + ); + throwOnInvalidObjectType(returnFiber, newChild); + } + return null; + } + function updateFromMap( + existingChildren, + returnFiber, + newIdx, + newChild, + expirationTime + ) { + if ("string" === typeof newChild || "number" === typeof newChild) + return ( + (existingChildren = existingChildren.get(newIdx) || null), + updateTextNode( + returnFiber, + existingChildren, + "" + newChild, + expirationTime + ) + ); + if ("object" === typeof newChild && null !== newChild) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return ( + (existingChildren = + existingChildren.get( + null === newChild.key ? newIdx : newChild.key + ) || null), + newChild.type === REACT_FRAGMENT_TYPE + ? updateFragment( + returnFiber, + existingChildren, + newChild.props.children, + expirationTime, + newChild.key + ) + : updateElement( + returnFiber, + existingChildren, + newChild, + expirationTime + ) + ); + case REACT_PORTAL_TYPE: + return ( + (existingChildren = + existingChildren.get( + null === newChild.key ? newIdx : newChild.key + ) || null), + updatePortal( + returnFiber, + existingChildren, + newChild, + expirationTime + ) + ); + } + if (isArray(newChild) || getIteratorFn(newChild)) + return ( + (existingChildren = existingChildren.get(newIdx) || null), + updateFragment( + returnFiber, + existingChildren, + newChild, + expirationTime, + null + ) + ); + throwOnInvalidObjectType(returnFiber, newChild); + } + return null; + } + function reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChildren, + expirationTime + ) { + for ( + var resultingFirstChild = null, + previousNewFiber = null, + oldFiber = currentFirstChild, + newIdx = (currentFirstChild = 0), + nextOldFiber = null; + null !== oldFiber && newIdx < newChildren.length; + newIdx++ + ) { + oldFiber.index > newIdx + ? ((nextOldFiber = oldFiber), (oldFiber = null)) + : (nextOldFiber = oldFiber.sibling); + var newFiber = updateSlot( + returnFiber, + oldFiber, + newChildren[newIdx], + expirationTime + ); + if (null === newFiber) { + null === oldFiber && (oldFiber = nextOldFiber); + break; + } + shouldTrackSideEffects && + oldFiber && + null === newFiber.alternate && + deleteChild(returnFiber, oldFiber); + currentFirstChild = placeChild(newFiber, currentFirstChild, newIdx); + null === previousNewFiber + ? (resultingFirstChild = newFiber) + : (previousNewFiber.sibling = newFiber); + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } + if (newIdx === newChildren.length) + return ( + deleteRemainingChildren(returnFiber, oldFiber), resultingFirstChild + ); + if (null === oldFiber) { + for (; newIdx < newChildren.length; newIdx++) + (oldFiber = createChild( + returnFiber, + newChildren[newIdx], + expirationTime + )), + null !== oldFiber && + ((currentFirstChild = placeChild( + oldFiber, + currentFirstChild, + newIdx + )), + null === previousNewFiber + ? (resultingFirstChild = oldFiber) + : (previousNewFiber.sibling = oldFiber), + (previousNewFiber = oldFiber)); + return resultingFirstChild; + } + for ( + oldFiber = mapRemainingChildren(returnFiber, oldFiber); + newIdx < newChildren.length; + newIdx++ + ) + (nextOldFiber = updateFromMap( + oldFiber, + returnFiber, + newIdx, + newChildren[newIdx], + expirationTime + )), + null !== nextOldFiber && + (shouldTrackSideEffects && + null !== nextOldFiber.alternate && + oldFiber.delete( + null === nextOldFiber.key ? newIdx : nextOldFiber.key + ), + (currentFirstChild = placeChild( + nextOldFiber, + currentFirstChild, + newIdx + )), + null === previousNewFiber + ? (resultingFirstChild = nextOldFiber) + : (previousNewFiber.sibling = nextOldFiber), + (previousNewFiber = nextOldFiber)); + shouldTrackSideEffects && + oldFiber.forEach(function(child) { + return deleteChild(returnFiber, child); + }); + return resultingFirstChild; + } + function reconcileChildrenIterator( + returnFiber, + currentFirstChild, + newChildrenIterable, + expirationTime + ) { + var iteratorFn = getIteratorFn(newChildrenIterable); + if ("function" !== typeof iteratorFn) + throw ReactError( + "An object is not an iterable. This error is likely caused by a bug in React. Please file an issue." + ); + newChildrenIterable = iteratorFn.call(newChildrenIterable); + if (null == newChildrenIterable) + throw ReactError("An iterable object provided no iterator."); + for ( + var previousNewFiber = (iteratorFn = null), + oldFiber = currentFirstChild, + newIdx = (currentFirstChild = 0), + nextOldFiber = null, + step = newChildrenIterable.next(); + null !== oldFiber && !step.done; + newIdx++, step = newChildrenIterable.next() + ) { + oldFiber.index > newIdx + ? ((nextOldFiber = oldFiber), (oldFiber = null)) + : (nextOldFiber = oldFiber.sibling); + var newFiber = updateSlot( + returnFiber, + oldFiber, + step.value, + expirationTime + ); + if (null === newFiber) { + null === oldFiber && (oldFiber = nextOldFiber); + break; + } + shouldTrackSideEffects && + oldFiber && + null === newFiber.alternate && + deleteChild(returnFiber, oldFiber); + currentFirstChild = placeChild(newFiber, currentFirstChild, newIdx); + null === previousNewFiber + ? (iteratorFn = newFiber) + : (previousNewFiber.sibling = newFiber); + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } + if (step.done) + return deleteRemainingChildren(returnFiber, oldFiber), iteratorFn; + if (null === oldFiber) { + for (; !step.done; newIdx++, step = newChildrenIterable.next()) + (step = createChild(returnFiber, step.value, expirationTime)), + null !== step && + ((currentFirstChild = placeChild(step, currentFirstChild, newIdx)), + null === previousNewFiber + ? (iteratorFn = step) + : (previousNewFiber.sibling = step), + (previousNewFiber = step)); + return iteratorFn; + } + for ( + oldFiber = mapRemainingChildren(returnFiber, oldFiber); + !step.done; + newIdx++, step = newChildrenIterable.next() + ) + (step = updateFromMap( + oldFiber, + returnFiber, + newIdx, + step.value, + expirationTime + )), + null !== step && + (shouldTrackSideEffects && + null !== step.alternate && + oldFiber.delete(null === step.key ? newIdx : step.key), + (currentFirstChild = placeChild(step, currentFirstChild, newIdx)), + null === previousNewFiber + ? (iteratorFn = step) + : (previousNewFiber.sibling = step), + (previousNewFiber = step)); + shouldTrackSideEffects && + oldFiber.forEach(function(child) { + return deleteChild(returnFiber, child); + }); + return iteratorFn; + } + return function(returnFiber, currentFirstChild, newChild, expirationTime) { + var isUnkeyedTopLevelFragment = + "object" === typeof newChild && + null !== newChild && + newChild.type === REACT_FRAGMENT_TYPE && + null === newChild.key; + isUnkeyedTopLevelFragment && (newChild = newChild.props.children); + var isObject = "object" === typeof newChild && null !== newChild; + if (isObject) + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + a: { + isObject = newChild.key; + for ( + isUnkeyedTopLevelFragment = currentFirstChild; + null !== isUnkeyedTopLevelFragment; + + ) { + if (isUnkeyedTopLevelFragment.key === isObject) { + if ( + 7 === isUnkeyedTopLevelFragment.tag + ? newChild.type === REACT_FRAGMENT_TYPE + : isUnkeyedTopLevelFragment.elementType === newChild.type + ) { + deleteRemainingChildren( + returnFiber, + isUnkeyedTopLevelFragment.sibling + ); + currentFirstChild = useFiber( + isUnkeyedTopLevelFragment, + newChild.type === REACT_FRAGMENT_TYPE + ? newChild.props.children + : newChild.props, + expirationTime + ); + currentFirstChild.ref = coerceRef( + returnFiber, + isUnkeyedTopLevelFragment, + newChild + ); + currentFirstChild.return = returnFiber; + returnFiber = currentFirstChild; + break a; + } + deleteRemainingChildren(returnFiber, isUnkeyedTopLevelFragment); + break; + } else deleteChild(returnFiber, isUnkeyedTopLevelFragment); + isUnkeyedTopLevelFragment = isUnkeyedTopLevelFragment.sibling; + } + newChild.type === REACT_FRAGMENT_TYPE + ? ((currentFirstChild = createFiberFromFragment( + newChild.props.children, + returnFiber.mode, + expirationTime, + newChild.key + )), + (currentFirstChild.return = returnFiber), + (returnFiber = currentFirstChild)) + : ((expirationTime = createFiberFromTypeAndProps( + newChild.type, + newChild.key, + newChild.props, + null, + returnFiber.mode, + expirationTime + )), + (expirationTime.ref = coerceRef( + returnFiber, + currentFirstChild, + newChild + )), + (expirationTime.return = returnFiber), + (returnFiber = expirationTime)); + } + return placeSingleChild(returnFiber); + case REACT_PORTAL_TYPE: + a: { + for ( + isUnkeyedTopLevelFragment = newChild.key; + null !== currentFirstChild; + + ) { + if (currentFirstChild.key === isUnkeyedTopLevelFragment) { + if ( + 4 === currentFirstChild.tag && + currentFirstChild.stateNode.containerInfo === + newChild.containerInfo && + currentFirstChild.stateNode.implementation === + newChild.implementation + ) { + deleteRemainingChildren( + returnFiber, + currentFirstChild.sibling + ); + currentFirstChild = useFiber( + currentFirstChild, + newChild.children || [], + expirationTime + ); + currentFirstChild.return = returnFiber; + returnFiber = currentFirstChild; + break a; + } + deleteRemainingChildren(returnFiber, currentFirstChild); + break; + } else deleteChild(returnFiber, currentFirstChild); + currentFirstChild = currentFirstChild.sibling; + } + currentFirstChild = createFiberFromPortal( + newChild, + returnFiber.mode, + expirationTime + ); + currentFirstChild.return = returnFiber; + returnFiber = currentFirstChild; + } + return placeSingleChild(returnFiber); + } + if ("string" === typeof newChild || "number" === typeof newChild) + return ( + (newChild = "" + newChild), + null !== currentFirstChild && 6 === currentFirstChild.tag + ? (deleteRemainingChildren(returnFiber, currentFirstChild.sibling), + (currentFirstChild = useFiber( + currentFirstChild, + newChild, + expirationTime + )), + (currentFirstChild.return = returnFiber), + (returnFiber = currentFirstChild)) + : (deleteRemainingChildren(returnFiber, currentFirstChild), + (currentFirstChild = createFiberFromText( + newChild, + returnFiber.mode, + expirationTime + )), + (currentFirstChild.return = returnFiber), + (returnFiber = currentFirstChild)), + placeSingleChild(returnFiber) + ); + if (isArray(newChild)) + return reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ); + if (getIteratorFn(newChild)) + return reconcileChildrenIterator( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ); + isObject && throwOnInvalidObjectType(returnFiber, newChild); + if ("undefined" === typeof newChild && !isUnkeyedTopLevelFragment) + switch (returnFiber.tag) { + case 1: + case 0: + throw ((returnFiber = returnFiber.type), + ReactError( + (returnFiber.displayName || returnFiber.name || "Component") + + "(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null." + )); + } + return deleteRemainingChildren(returnFiber, currentFirstChild); + }; +} +var reconcileChildFibers = ChildReconciler(!0), + mountChildFibers = ChildReconciler(!1), + NO_CONTEXT = {}, + contextStackCursor$1 = { current: NO_CONTEXT }, + contextFiberStackCursor = { current: NO_CONTEXT }, + rootInstanceStackCursor = { current: NO_CONTEXT }; +function requiredContext(c) { + if (c === NO_CONTEXT) + throw ReactError( + "Expected host context to exist. This error is likely caused by a bug in React. Please file an issue." + ); + return c; +} +function pushHostContainer(fiber, nextRootInstance) { + push(rootInstanceStackCursor, nextRootInstance, fiber); + push(contextFiberStackCursor, fiber, fiber); + push(contextStackCursor$1, NO_CONTEXT, fiber); + pop(contextStackCursor$1, fiber); + push(contextStackCursor$1, { isInAParentText: !1 }, fiber); +} +function popHostContainer(fiber) { + pop(contextStackCursor$1, fiber); + pop(contextFiberStackCursor, fiber); + pop(rootInstanceStackCursor, fiber); +} +function pushHostContext(fiber) { + requiredContext(rootInstanceStackCursor.current); + var context = requiredContext(contextStackCursor$1.current); + var nextContext = fiber.type; + nextContext = + "AndroidTextInput" === nextContext || + "RCTMultilineTextInputView" === nextContext || + "RCTSinglelineTextInputView" === nextContext || + "RCTText" === nextContext || + "RCTVirtualText" === nextContext; + nextContext = + context.isInAParentText !== nextContext + ? { isInAParentText: nextContext } + : context; + context !== nextContext && + (push(contextFiberStackCursor, fiber, fiber), + push(contextStackCursor$1, nextContext, fiber)); +} +function popHostContext(fiber) { + contextFiberStackCursor.current === fiber && + (pop(contextStackCursor$1, fiber), pop(contextFiberStackCursor, fiber)); +} +var NoEffect$1 = 0, + UnmountSnapshot = 2, + UnmountMutation = 4, + MountMutation = 8, + UnmountLayout = 16, + MountLayout = 32, + MountPassive = 64, + UnmountPassive = 128, + ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher, + renderExpirationTime$1 = 0, + currentlyRenderingFiber$1 = null, + currentHook = null, + nextCurrentHook = null, + firstWorkInProgressHook = null, + workInProgressHook = null, + nextWorkInProgressHook = null, + remainingExpirationTime = 0, + componentUpdateQueue = null, + sideEffectTag = 0, + didScheduleRenderPhaseUpdate = !1, + renderPhaseUpdates = null, + numberOfReRenders = 0; +function throwInvalidHookError() { + throw ReactError( + "Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:\n1. You might have mismatching versions of React and the renderer (such as React DOM)\n2. You might be breaking the Rules of Hooks\n3. You might have more than one copy of React in the same app\nSee https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem." + ); +} +function areHookInputsEqual(nextDeps, prevDeps) { + if (null === prevDeps) return !1; + for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++) + if (!is(nextDeps[i], prevDeps[i])) return !1; + return !0; +} +function renderWithHooks( + current, + workInProgress, + Component, + props, + refOrContext, + nextRenderExpirationTime +) { + renderExpirationTime$1 = nextRenderExpirationTime; + currentlyRenderingFiber$1 = workInProgress; + nextCurrentHook = null !== current ? current.memoizedState : null; + ReactCurrentDispatcher$1.current = + null === nextCurrentHook ? HooksDispatcherOnMount : HooksDispatcherOnUpdate; + workInProgress = Component(props, refOrContext); + if (didScheduleRenderPhaseUpdate) { + do + (didScheduleRenderPhaseUpdate = !1), + (numberOfReRenders += 1), + (nextCurrentHook = null !== current ? current.memoizedState : null), + (nextWorkInProgressHook = firstWorkInProgressHook), + (componentUpdateQueue = workInProgressHook = currentHook = null), + (ReactCurrentDispatcher$1.current = HooksDispatcherOnUpdate), + (workInProgress = Component(props, refOrContext)); + while (didScheduleRenderPhaseUpdate); + renderPhaseUpdates = null; + numberOfReRenders = 0; + } + ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; + current = currentlyRenderingFiber$1; + current.memoizedState = firstWorkInProgressHook; + current.expirationTime = remainingExpirationTime; + current.updateQueue = componentUpdateQueue; + current.effectTag |= sideEffectTag; + current = null !== currentHook && null !== currentHook.next; + renderExpirationTime$1 = 0; + nextWorkInProgressHook = workInProgressHook = firstWorkInProgressHook = nextCurrentHook = currentHook = currentlyRenderingFiber$1 = null; + remainingExpirationTime = 0; + componentUpdateQueue = null; + sideEffectTag = 0; + if (current) + throw ReactError( + "Rendered fewer hooks than expected. This may be caused by an accidental early return statement." + ); + return workInProgress; +} +function resetHooks() { + ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; + renderExpirationTime$1 = 0; + nextWorkInProgressHook = workInProgressHook = firstWorkInProgressHook = nextCurrentHook = currentHook = currentlyRenderingFiber$1 = null; + remainingExpirationTime = 0; + componentUpdateQueue = null; + sideEffectTag = 0; + didScheduleRenderPhaseUpdate = !1; + renderPhaseUpdates = null; + numberOfReRenders = 0; +} +function mountWorkInProgressHook() { + var hook = { + memoizedState: null, + baseState: null, + queue: null, + baseUpdate: null, + next: null + }; + null === workInProgressHook + ? (firstWorkInProgressHook = workInProgressHook = hook) + : (workInProgressHook = workInProgressHook.next = hook); + return workInProgressHook; +} +function updateWorkInProgressHook() { + if (null !== nextWorkInProgressHook) + (workInProgressHook = nextWorkInProgressHook), + (nextWorkInProgressHook = workInProgressHook.next), + (currentHook = nextCurrentHook), + (nextCurrentHook = null !== currentHook ? currentHook.next : null); + else { + if (null === nextCurrentHook) + throw ReactError("Rendered more hooks than during the previous render."); + currentHook = nextCurrentHook; + var newHook = { + memoizedState: currentHook.memoizedState, + baseState: currentHook.baseState, + queue: currentHook.queue, + baseUpdate: currentHook.baseUpdate, + next: null + }; + workInProgressHook = + null === workInProgressHook + ? (firstWorkInProgressHook = newHook) + : (workInProgressHook.next = newHook); + nextCurrentHook = currentHook.next; + } + return workInProgressHook; +} +function basicStateReducer(state, action) { + return "function" === typeof action ? action(state) : action; +} +function updateReducer(reducer) { + var hook = updateWorkInProgressHook(), + queue = hook.queue; + if (null === queue) + throw ReactError( + "Should have a queue. This is likely a bug in React. Please file an issue." + ); + queue.lastRenderedReducer = reducer; + if (0 < numberOfReRenders) { + var _dispatch = queue.dispatch; + if (null !== renderPhaseUpdates) { + var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue); + if (void 0 !== firstRenderPhaseUpdate) { + renderPhaseUpdates.delete(queue); + var newState = hook.memoizedState; + do + (newState = reducer(newState, firstRenderPhaseUpdate.action)), + (firstRenderPhaseUpdate = firstRenderPhaseUpdate.next); + while (null !== firstRenderPhaseUpdate); + is(newState, hook.memoizedState) || (didReceiveUpdate = !0); + hook.memoizedState = newState; + hook.baseUpdate === queue.last && (hook.baseState = newState); + queue.lastRenderedState = newState; + return [newState, _dispatch]; + } + } + return [hook.memoizedState, _dispatch]; + } + _dispatch = queue.last; + var baseUpdate = hook.baseUpdate; + newState = hook.baseState; + null !== baseUpdate + ? (null !== _dispatch && (_dispatch.next = null), + (_dispatch = baseUpdate.next)) + : (_dispatch = null !== _dispatch ? _dispatch.next : null); + if (null !== _dispatch) { + var newBaseUpdate = (firstRenderPhaseUpdate = null), + _update = _dispatch, + didSkip = !1; + do { + var updateExpirationTime = _update.expirationTime; + updateExpirationTime < renderExpirationTime$1 + ? (didSkip || + ((didSkip = !0), + (newBaseUpdate = baseUpdate), + (firstRenderPhaseUpdate = newState)), + updateExpirationTime > remainingExpirationTime && + (remainingExpirationTime = updateExpirationTime)) + : (updateExpirationTime < workInProgressRootMostRecentEventTime && + (workInProgressRootMostRecentEventTime = updateExpirationTime), + (newState = + _update.eagerReducer === reducer + ? _update.eagerState + : reducer(newState, _update.action))); + baseUpdate = _update; + _update = _update.next; + } while (null !== _update && _update !== _dispatch); + didSkip || + ((newBaseUpdate = baseUpdate), (firstRenderPhaseUpdate = newState)); + is(newState, hook.memoizedState) || (didReceiveUpdate = !0); + hook.memoizedState = newState; + hook.baseUpdate = newBaseUpdate; + hook.baseState = firstRenderPhaseUpdate; + queue.lastRenderedState = newState; + } + return [hook.memoizedState, queue.dispatch]; +} +function pushEffect(tag, create, destroy, deps) { + tag = { tag: tag, create: create, destroy: destroy, deps: deps, next: null }; + null === componentUpdateQueue + ? ((componentUpdateQueue = { lastEffect: null }), + (componentUpdateQueue.lastEffect = tag.next = tag)) + : ((create = componentUpdateQueue.lastEffect), + null === create + ? (componentUpdateQueue.lastEffect = tag.next = tag) + : ((destroy = create.next), + (create.next = tag), + (tag.next = destroy), + (componentUpdateQueue.lastEffect = tag))); + return tag; +} +function mountEffectImpl(fiberEffectTag, hookEffectTag, create, deps) { + var hook = mountWorkInProgressHook(); + sideEffectTag |= fiberEffectTag; + hook.memoizedState = pushEffect( + hookEffectTag, + create, + void 0, + void 0 === deps ? null : deps + ); +} +function updateEffectImpl(fiberEffectTag, hookEffectTag, create, deps) { + var hook = updateWorkInProgressHook(); + deps = void 0 === deps ? null : deps; + var destroy = void 0; + if (null !== currentHook) { + var prevEffect = currentHook.memoizedState; + destroy = prevEffect.destroy; + if (null !== deps && areHookInputsEqual(deps, prevEffect.deps)) { + pushEffect(NoEffect$1, create, destroy, deps); + return; + } + } + sideEffectTag |= fiberEffectTag; + hook.memoizedState = pushEffect(hookEffectTag, create, destroy, deps); +} +function imperativeHandleEffect(create, ref) { + if ("function" === typeof ref) + return ( + (create = create()), + ref(create), + function() { + ref(null); + } + ); + if (null !== ref && void 0 !== ref) + return ( + (create = create()), + (ref.current = create), + function() { + ref.current = null; + } + ); +} +function mountDebugValue() {} +function dispatchAction(fiber, queue, action) { + if (!(25 > numberOfReRenders)) + throw ReactError( + "Too many re-renders. React limits the number of renders to prevent an infinite loop." + ); + var alternate = fiber.alternate; + if ( + fiber === currentlyRenderingFiber$1 || + (null !== alternate && alternate === currentlyRenderingFiber$1) + ) + if ( + ((didScheduleRenderPhaseUpdate = !0), + (fiber = { + expirationTime: renderExpirationTime$1, + action: action, + eagerReducer: null, + eagerState: null, + next: null + }), + null === renderPhaseUpdates && (renderPhaseUpdates = new Map()), + (action = renderPhaseUpdates.get(queue)), + void 0 === action) + ) + renderPhaseUpdates.set(queue, fiber); + else { + for (queue = action; null !== queue.next; ) queue = queue.next; + queue.next = fiber; + } + else { + flushPassiveEffects(); + var currentTime = requestCurrentTime(); + currentTime = computeExpirationForFiber(currentTime, fiber); + var _update2 = { + expirationTime: currentTime, + action: action, + eagerReducer: null, + eagerState: null, + next: null + }, + _last = queue.last; + if (null === _last) _update2.next = _update2; + else { + var first = _last.next; + null !== first && (_update2.next = first); + _last.next = _update2; + } + queue.last = _update2; + if ( + 0 === fiber.expirationTime && + (null === alternate || 0 === alternate.expirationTime) && + ((alternate = queue.lastRenderedReducer), null !== alternate) + ) + try { + var currentState = queue.lastRenderedState, + _eagerState = alternate(currentState, action); + _update2.eagerReducer = alternate; + _update2.eagerState = _eagerState; + if (is(_eagerState, currentState)) return; + } catch (error) { + } finally { + } + scheduleUpdateOnFiber(fiber, currentTime); + } +} +var ContextOnlyDispatcher = { + readContext: readContext, + useCallback: throwInvalidHookError, + useContext: throwInvalidHookError, + useEffect: throwInvalidHookError, + useImperativeHandle: throwInvalidHookError, + useLayoutEffect: throwInvalidHookError, + useMemo: throwInvalidHookError, + useReducer: throwInvalidHookError, + useRef: throwInvalidHookError, + useState: throwInvalidHookError, + useDebugValue: throwInvalidHookError + }, + HooksDispatcherOnMount = { + readContext: readContext, + useCallback: function(callback, deps) { + mountWorkInProgressHook().memoizedState = [ + callback, + void 0 === deps ? null : deps + ]; + return callback; + }, + useContext: readContext, + useEffect: function(create, deps) { + return mountEffectImpl(516, UnmountPassive | MountPassive, create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + deps = null !== deps && void 0 !== deps ? deps.concat([ref]) : null; + return mountEffectImpl( + 4, + UnmountMutation | MountLayout, + imperativeHandleEffect.bind(null, create, ref), + deps + ); + }, + useLayoutEffect: function(create, deps) { + return mountEffectImpl(4, UnmountMutation | MountLayout, create, deps); + }, + useMemo: function(nextCreate, deps) { + var hook = mountWorkInProgressHook(); + deps = void 0 === deps ? null : deps; + nextCreate = nextCreate(); + hook.memoizedState = [nextCreate, deps]; + return nextCreate; + }, + useReducer: function(reducer, initialArg, init) { + var hook = mountWorkInProgressHook(); + initialArg = void 0 !== init ? init(initialArg) : initialArg; + hook.memoizedState = hook.baseState = initialArg; + reducer = hook.queue = { + last: null, + dispatch: null, + lastRenderedReducer: reducer, + lastRenderedState: initialArg + }; + reducer = reducer.dispatch = dispatchAction.bind( + null, + currentlyRenderingFiber$1, + reducer + ); + return [hook.memoizedState, reducer]; + }, + useRef: function(initialValue) { + var hook = mountWorkInProgressHook(); + initialValue = { current: initialValue }; + return (hook.memoizedState = initialValue); + }, + useState: function(initialState) { + var hook = mountWorkInProgressHook(); + "function" === typeof initialState && (initialState = initialState()); + hook.memoizedState = hook.baseState = initialState; + initialState = hook.queue = { + last: null, + dispatch: null, + lastRenderedReducer: basicStateReducer, + lastRenderedState: initialState + }; + initialState = initialState.dispatch = dispatchAction.bind( + null, + currentlyRenderingFiber$1, + initialState + ); + return [hook.memoizedState, initialState]; + }, + useDebugValue: mountDebugValue + }, + HooksDispatcherOnUpdate = { + readContext: readContext, + useCallback: function(callback, deps) { + var hook = updateWorkInProgressHook(); + deps = void 0 === deps ? null : deps; + var prevState = hook.memoizedState; + if ( + null !== prevState && + null !== deps && + areHookInputsEqual(deps, prevState[1]) + ) + return prevState[0]; + hook.memoizedState = [callback, deps]; + return callback; + }, + useContext: readContext, + useEffect: function(create, deps) { + return updateEffectImpl(516, UnmountPassive | MountPassive, create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + deps = null !== deps && void 0 !== deps ? deps.concat([ref]) : null; + return updateEffectImpl( + 4, + UnmountMutation | MountLayout, + imperativeHandleEffect.bind(null, create, ref), + deps + ); + }, + useLayoutEffect: function(create, deps) { + return updateEffectImpl(4, UnmountMutation | MountLayout, create, deps); + }, + useMemo: function(nextCreate, deps) { + var hook = updateWorkInProgressHook(); + deps = void 0 === deps ? null : deps; + var prevState = hook.memoizedState; + if ( + null !== prevState && + null !== deps && + areHookInputsEqual(deps, prevState[1]) + ) + return prevState[0]; + nextCreate = nextCreate(); + hook.memoizedState = [nextCreate, deps]; + return nextCreate; + }, + useReducer: updateReducer, + useRef: function() { + return updateWorkInProgressHook().memoizedState; + }, + useState: function(initialState) { + return updateReducer(basicStateReducer, initialState); + }, + useDebugValue: mountDebugValue + }, + hydrationParentFiber = null, + nextHydratableInstance = null, + isHydrating = !1; +function tryHydrate(fiber, nextInstance) { + switch (fiber.tag) { + case 5: + return ( + (nextInstance = shim$1(nextInstance, fiber.type, fiber.pendingProps)), + null !== nextInstance ? ((fiber.stateNode = nextInstance), !0) : !1 + ); + case 6: + return ( + (nextInstance = shim$1(nextInstance, fiber.pendingProps)), + null !== nextInstance ? ((fiber.stateNode = nextInstance), !0) : !1 + ); + case 13: + return !1; + default: + return !1; + } +} +function tryToClaimNextHydratableInstance(fiber$jscomp$0) { + if (isHydrating) { + var nextInstance = nextHydratableInstance; + if (nextInstance) { + var firstAttemptedInstance = nextInstance; + if (!tryHydrate(fiber$jscomp$0, nextInstance)) { + nextInstance = shim$1(firstAttemptedInstance); + if (!nextInstance || !tryHydrate(fiber$jscomp$0, nextInstance)) { + fiber$jscomp$0.effectTag |= 2; + isHydrating = !1; + hydrationParentFiber = fiber$jscomp$0; + return; + } + var returnFiber = hydrationParentFiber, + fiber = createFiber(5, null, null, 0); + fiber.elementType = "DELETED"; + fiber.type = "DELETED"; + fiber.stateNode = firstAttemptedInstance; + fiber.return = returnFiber; + fiber.effectTag = 8; + null !== returnFiber.lastEffect + ? ((returnFiber.lastEffect.nextEffect = fiber), + (returnFiber.lastEffect = fiber)) + : (returnFiber.firstEffect = returnFiber.lastEffect = fiber); + } + hydrationParentFiber = fiber$jscomp$0; + nextHydratableInstance = shim$1(nextInstance); + } else + (fiber$jscomp$0.effectTag |= 2), + (isHydrating = !1), + (hydrationParentFiber = fiber$jscomp$0); + } +} +var ReactCurrentOwner$3 = ReactSharedInternals.ReactCurrentOwner, + didReceiveUpdate = !1; +function reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime +) { + workInProgress.child = + null === current$$1 + ? mountChildFibers( + workInProgress, + null, + nextChildren, + renderExpirationTime + ) + : reconcileChildFibers( + workInProgress, + current$$1.child, + nextChildren, + renderExpirationTime + ); +} +function updateForwardRef( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + Component = Component.render; + var ref = workInProgress.ref; + prepareToReadContext(workInProgress, renderExpirationTime); + nextProps = renderWithHooks( + current$$1, + workInProgress, + Component, + nextProps, + ref, + renderExpirationTime + ); + if (null !== current$$1 && !didReceiveUpdate) + return ( + (workInProgress.updateQueue = current$$1.updateQueue), + (workInProgress.effectTag &= -517), + current$$1.expirationTime <= renderExpirationTime && + (current$$1.expirationTime = 0), + bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ) + ); + workInProgress.effectTag |= 1; + reconcileChildren( + current$$1, + workInProgress, + nextProps, + renderExpirationTime + ); + return workInProgress.child; +} +function updateMemoComponent( + current$$1, + workInProgress, + Component, + nextProps, + updateExpirationTime, + renderExpirationTime +) { + if (null === current$$1) { + var type = Component.type; + if ( + "function" === typeof type && + !shouldConstruct(type) && + void 0 === type.defaultProps && + null === Component.compare && + void 0 === Component.defaultProps + ) + return ( + (workInProgress.tag = 15), + (workInProgress.type = type), + updateSimpleMemoComponent( + current$$1, + workInProgress, + type, + nextProps, + updateExpirationTime, + renderExpirationTime + ) + ); + current$$1 = createFiberFromTypeAndProps( + Component.type, + null, + nextProps, + null, + workInProgress.mode, + renderExpirationTime + ); + current$$1.ref = workInProgress.ref; + current$$1.return = workInProgress; + return (workInProgress.child = current$$1); + } + type = current$$1.child; + if ( + updateExpirationTime < renderExpirationTime && + ((updateExpirationTime = type.memoizedProps), + (Component = Component.compare), + (Component = null !== Component ? Component : shallowEqual), + Component(updateExpirationTime, nextProps) && + current$$1.ref === workInProgress.ref) + ) + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + workInProgress.effectTag |= 1; + current$$1 = createWorkInProgress(type, nextProps, renderExpirationTime); + current$$1.ref = workInProgress.ref; + current$$1.return = workInProgress; + return (workInProgress.child = current$$1); +} +function updateSimpleMemoComponent( + current$$1, + workInProgress, + Component, + nextProps, + updateExpirationTime, + renderExpirationTime +) { + return null !== current$$1 && + shallowEqual(current$$1.memoizedProps, nextProps) && + current$$1.ref === workInProgress.ref && + ((didReceiveUpdate = !1), updateExpirationTime < renderExpirationTime) + ? bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ) + : updateFunctionComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime + ); +} +function markRef(current$$1, workInProgress) { + var ref = workInProgress.ref; + if ( + (null === current$$1 && null !== ref) || + (null !== current$$1 && current$$1.ref !== ref) + ) + workInProgress.effectTag |= 128; +} +function updateFunctionComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + var unmaskedContext = isContextProvider(Component) + ? previousContext + : contextStackCursor.current; + unmaskedContext = getMaskedContext(workInProgress, unmaskedContext); + prepareToReadContext(workInProgress, renderExpirationTime); + Component = renderWithHooks( + current$$1, + workInProgress, + Component, + nextProps, + unmaskedContext, + renderExpirationTime + ); + if (null !== current$$1 && !didReceiveUpdate) + return ( + (workInProgress.updateQueue = current$$1.updateQueue), + (workInProgress.effectTag &= -517), + current$$1.expirationTime <= renderExpirationTime && + (current$$1.expirationTime = 0), + bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ) + ); + workInProgress.effectTag |= 1; + reconcileChildren( + current$$1, + workInProgress, + Component, + renderExpirationTime + ); + return workInProgress.child; +} +function updateClassComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + if (isContextProvider(Component)) { + var hasContext = !0; + pushContextProvider(workInProgress); + } else hasContext = !1; + prepareToReadContext(workInProgress, renderExpirationTime); + if (null === workInProgress.stateNode) + null !== current$$1 && + ((current$$1.alternate = null), + (workInProgress.alternate = null), + (workInProgress.effectTag |= 2)), + constructClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ), + mountClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ), + (nextProps = !0); + else if (null === current$$1) { + var instance = workInProgress.stateNode, + oldProps = workInProgress.memoizedProps; + instance.props = oldProps; + var oldContext = instance.context, + contextType = Component.contextType; + "object" === typeof contextType && null !== contextType + ? (contextType = readContext(contextType)) + : ((contextType = isContextProvider(Component) + ? previousContext + : contextStackCursor.current), + (contextType = getMaskedContext(workInProgress, contextType))); + var getDerivedStateFromProps = Component.getDerivedStateFromProps, + hasNewLifecycles = + "function" === typeof getDerivedStateFromProps || + "function" === typeof instance.getSnapshotBeforeUpdate; + hasNewLifecycles || + ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && + "function" !== typeof instance.componentWillReceiveProps) || + ((oldProps !== nextProps || oldContext !== contextType) && + callComponentWillReceiveProps( + workInProgress, + instance, + nextProps, + contextType + )); + hasForceUpdate = !1; + var oldState = workInProgress.memoizedState; + oldContext = instance.state = oldState; + var updateQueue = workInProgress.updateQueue; + null !== updateQueue && + (processUpdateQueue( + workInProgress, + updateQueue, + nextProps, + instance, + renderExpirationTime + ), + (oldContext = workInProgress.memoizedState)); + oldProps !== nextProps || + oldState !== oldContext || + didPerformWorkStackCursor.current || + hasForceUpdate + ? ("function" === typeof getDerivedStateFromProps && + (applyDerivedStateFromProps( + workInProgress, + Component, + getDerivedStateFromProps, + nextProps + ), + (oldContext = workInProgress.memoizedState)), + (oldProps = + hasForceUpdate || + checkShouldComponentUpdate( + workInProgress, + Component, + oldProps, + nextProps, + oldState, + oldContext, + contextType + )) + ? (hasNewLifecycles || + ("function" !== typeof instance.UNSAFE_componentWillMount && + "function" !== typeof instance.componentWillMount) || + ("function" === typeof instance.componentWillMount && + instance.componentWillMount(), + "function" === typeof instance.UNSAFE_componentWillMount && + instance.UNSAFE_componentWillMount()), + "function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4)) + : ("function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4), + (workInProgress.memoizedProps = nextProps), + (workInProgress.memoizedState = oldContext)), + (instance.props = nextProps), + (instance.state = oldContext), + (instance.context = contextType), + (nextProps = oldProps)) + : ("function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4), + (nextProps = !1)); + } else + (instance = workInProgress.stateNode), + (oldProps = workInProgress.memoizedProps), + (instance.props = + workInProgress.type === workInProgress.elementType + ? oldProps + : resolveDefaultProps(workInProgress.type, oldProps)), + (oldContext = instance.context), + (contextType = Component.contextType), + "object" === typeof contextType && null !== contextType + ? (contextType = readContext(contextType)) + : ((contextType = isContextProvider(Component) + ? previousContext + : contextStackCursor.current), + (contextType = getMaskedContext(workInProgress, contextType))), + (getDerivedStateFromProps = Component.getDerivedStateFromProps), + (hasNewLifecycles = + "function" === typeof getDerivedStateFromProps || + "function" === typeof instance.getSnapshotBeforeUpdate) || + ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && + "function" !== typeof instance.componentWillReceiveProps) || + ((oldProps !== nextProps || oldContext !== contextType) && + callComponentWillReceiveProps( + workInProgress, + instance, + nextProps, + contextType + )), + (hasForceUpdate = !1), + (oldContext = workInProgress.memoizedState), + (oldState = instance.state = oldContext), + (updateQueue = workInProgress.updateQueue), + null !== updateQueue && + (processUpdateQueue( + workInProgress, + updateQueue, + nextProps, + instance, + renderExpirationTime + ), + (oldState = workInProgress.memoizedState)), + oldProps !== nextProps || + oldContext !== oldState || + didPerformWorkStackCursor.current || + hasForceUpdate + ? ("function" === typeof getDerivedStateFromProps && + (applyDerivedStateFromProps( + workInProgress, + Component, + getDerivedStateFromProps, + nextProps + ), + (oldState = workInProgress.memoizedState)), + (getDerivedStateFromProps = + hasForceUpdate || + checkShouldComponentUpdate( + workInProgress, + Component, + oldProps, + nextProps, + oldContext, + oldState, + contextType + )) + ? (hasNewLifecycles || + ("function" !== typeof instance.UNSAFE_componentWillUpdate && + "function" !== typeof instance.componentWillUpdate) || + ("function" === typeof instance.componentWillUpdate && + instance.componentWillUpdate( + nextProps, + oldState, + contextType + ), + "function" === typeof instance.UNSAFE_componentWillUpdate && + instance.UNSAFE_componentWillUpdate( + nextProps, + oldState, + contextType + )), + "function" === typeof instance.componentDidUpdate && + (workInProgress.effectTag |= 4), + "function" === typeof instance.getSnapshotBeforeUpdate && + (workInProgress.effectTag |= 256)) + : ("function" !== typeof instance.componentDidUpdate || + (oldProps === current$$1.memoizedProps && + oldContext === current$$1.memoizedState) || + (workInProgress.effectTag |= 4), + "function" !== typeof instance.getSnapshotBeforeUpdate || + (oldProps === current$$1.memoizedProps && + oldContext === current$$1.memoizedState) || + (workInProgress.effectTag |= 256), + (workInProgress.memoizedProps = nextProps), + (workInProgress.memoizedState = oldState)), + (instance.props = nextProps), + (instance.state = oldState), + (instance.context = contextType), + (nextProps = getDerivedStateFromProps)) + : ("function" !== typeof instance.componentDidUpdate || + (oldProps === current$$1.memoizedProps && + oldContext === current$$1.memoizedState) || + (workInProgress.effectTag |= 4), + "function" !== typeof instance.getSnapshotBeforeUpdate || + (oldProps === current$$1.memoizedProps && + oldContext === current$$1.memoizedState) || + (workInProgress.effectTag |= 256), + (nextProps = !1)); + return finishClassComponent( + current$$1, + workInProgress, + Component, + nextProps, + hasContext, + renderExpirationTime + ); +} +function finishClassComponent( + current$$1, + workInProgress, + Component, + shouldUpdate, + hasContext, + renderExpirationTime +) { + markRef(current$$1, workInProgress); + var didCaptureError = 0 !== (workInProgress.effectTag & 64); + if (!shouldUpdate && !didCaptureError) + return ( + hasContext && invalidateContextProvider(workInProgress, Component, !1), + bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ) + ); + shouldUpdate = workInProgress.stateNode; + ReactCurrentOwner$3.current = workInProgress; + var nextChildren = + didCaptureError && "function" !== typeof Component.getDerivedStateFromError + ? null + : shouldUpdate.render(); + workInProgress.effectTag |= 1; + null !== current$$1 && didCaptureError + ? ((workInProgress.child = reconcileChildFibers( + workInProgress, + current$$1.child, + null, + renderExpirationTime + )), + (workInProgress.child = reconcileChildFibers( + workInProgress, + null, + nextChildren, + renderExpirationTime + ))) + : reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + workInProgress.memoizedState = shouldUpdate.state; + hasContext && invalidateContextProvider(workInProgress, Component, !0); + return workInProgress.child; +} +function pushHostRootContext(workInProgress) { + var root = workInProgress.stateNode; + root.pendingContext + ? pushTopLevelContextObject( + workInProgress, + root.pendingContext, + root.pendingContext !== root.context + ) + : root.context && + pushTopLevelContextObject(workInProgress, root.context, !1); + pushHostContainer(workInProgress, root.containerInfo); +} +function updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime +) { + var mode = workInProgress.mode, + nextProps = workInProgress.pendingProps, + nextState = workInProgress.memoizedState; + if (0 === (workInProgress.effectTag & 64)) { + nextState = null; + var nextDidTimeout = !1; + } else + (nextState = { + fallbackExpirationTime: + null !== nextState ? nextState.fallbackExpirationTime : 0 + }), + (nextDidTimeout = !0), + (workInProgress.effectTag &= -65); + if (null === current$$1) + if (nextDidTimeout) { + var nextFallbackChildren = nextProps.fallback; + current$$1 = createFiberFromFragment(null, mode, 0, null); + 0 === (workInProgress.mode & 1) && + (current$$1.child = + null !== workInProgress.memoizedState + ? workInProgress.child.child + : workInProgress.child); + mode = createFiberFromFragment( + nextFallbackChildren, + mode, + renderExpirationTime, + null + ); + current$$1.sibling = mode; + renderExpirationTime = current$$1; + renderExpirationTime.return = mode.return = workInProgress; + } else + renderExpirationTime = mode = mountChildFibers( + workInProgress, + null, + nextProps.children, + renderExpirationTime + ); + else + null !== current$$1.memoizedState + ? ((mode = current$$1.child), + (nextFallbackChildren = mode.sibling), + nextDidTimeout + ? ((renderExpirationTime = nextProps.fallback), + (nextProps = createWorkInProgress(mode, mode.pendingProps, 0)), + 0 === (workInProgress.mode & 1) && + ((nextDidTimeout = + null !== workInProgress.memoizedState + ? workInProgress.child.child + : workInProgress.child), + nextDidTimeout !== mode.child && + (nextProps.child = nextDidTimeout)), + (mode = nextProps.sibling = createWorkInProgress( + nextFallbackChildren, + renderExpirationTime, + nextFallbackChildren.expirationTime + )), + (renderExpirationTime = nextProps), + (nextProps.childExpirationTime = 0), + (renderExpirationTime.return = mode.return = workInProgress)) + : (renderExpirationTime = mode = reconcileChildFibers( + workInProgress, + mode.child, + nextProps.children, + renderExpirationTime + ))) + : ((nextFallbackChildren = current$$1.child), + nextDidTimeout + ? ((nextDidTimeout = nextProps.fallback), + (nextProps = createFiberFromFragment(null, mode, 0, null)), + (nextProps.child = nextFallbackChildren), + 0 === (workInProgress.mode & 1) && + (nextProps.child = + null !== workInProgress.memoizedState + ? workInProgress.child.child + : workInProgress.child), + (mode = nextProps.sibling = createFiberFromFragment( + nextDidTimeout, + mode, + renderExpirationTime, + null + )), + (mode.effectTag |= 2), + (renderExpirationTime = nextProps), + (nextProps.childExpirationTime = 0), + (renderExpirationTime.return = mode.return = workInProgress)) + : (mode = renderExpirationTime = reconcileChildFibers( + workInProgress, + nextFallbackChildren, + nextProps.children, + renderExpirationTime + ))), + (workInProgress.stateNode = current$$1.stateNode); + workInProgress.memoizedState = nextState; + workInProgress.child = renderExpirationTime; + return mode; +} +function bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime +) { + null !== current$$1 && + (workInProgress.contextDependencies = current$$1.contextDependencies); + if (workInProgress.childExpirationTime < renderExpirationTime) return null; + if (null !== current$$1 && workInProgress.child !== current$$1.child) + throw ReactError("Resuming work not yet implemented."); + if (null !== workInProgress.child) { + current$$1 = workInProgress.child; + renderExpirationTime = createWorkInProgress( + current$$1, + current$$1.pendingProps, + current$$1.expirationTime + ); + workInProgress.child = renderExpirationTime; + for ( + renderExpirationTime.return = workInProgress; + null !== current$$1.sibling; + + ) + (current$$1 = current$$1.sibling), + (renderExpirationTime = renderExpirationTime.sibling = createWorkInProgress( + current$$1, + current$$1.pendingProps, + current$$1.expirationTime + )), + (renderExpirationTime.return = workInProgress); + renderExpirationTime.sibling = null; + } + return workInProgress.child; +} +var appendAllChildren = void 0, + updateHostContainer = void 0, + updateHostComponent$1 = void 0, + updateHostText$1 = void 0; +appendAllChildren = function(parent, workInProgress) { + for (var node = workInProgress.child; null !== node; ) { + if (5 === node.tag || 6 === node.tag) parent._children.push(node.stateNode); + else if (4 !== node.tag && null !== node.child) { + node.child.return = node; + node = node.child; + continue; + } + if (node === workInProgress) break; + for (; null === node.sibling; ) { + if (null === node.return || node.return === workInProgress) return; + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } +}; +updateHostContainer = function() {}; +updateHostComponent$1 = function(current, workInProgress, type, newProps) { + current.memoizedProps !== newProps && + (requiredContext(contextStackCursor$1.current), + (workInProgress.updateQueue = UPDATE_SIGNAL)) && + (workInProgress.effectTag |= 4); +}; +updateHostText$1 = function(current, workInProgress, oldText, newText) { + oldText !== newText && (workInProgress.effectTag |= 4); +}; +function createCapturedValue(value, source) { + return { + value: value, + source: source, + stack: getStackByFiberInDevAndProd(source) + }; +} +function logCapturedError(capturedError) { + var componentStack = capturedError.componentStack, + error = capturedError.error; + if (error instanceof Error) { + capturedError = error.message; + var name = error.name; + try { + error.message = + (capturedError ? name + ": " + capturedError : name) + + "\n\nThis error is located at:" + + componentStack; + } catch (e) {} + } else + error = + "string" === typeof error + ? Error(error + "\n\nThis error is located at:" + componentStack) + : Error("Unspecified error at:" + componentStack); + ReactNativePrivateInterface.ExceptionsManager.handleException(error, !1); +} +var PossiblyWeakSet$1 = "function" === typeof WeakSet ? WeakSet : Set; +function logError(boundary, errorInfo) { + var source = errorInfo.source, + stack = errorInfo.stack; + null === stack && + null !== source && + (stack = getStackByFiberInDevAndProd(source)); + errorInfo = { + componentName: null !== source ? getComponentName(source.type) : null, + componentStack: null !== stack ? stack : "", + error: errorInfo.value, + errorBoundary: null, + errorBoundaryName: null, + errorBoundaryFound: !1, + willRetry: !1 + }; + null !== boundary && + 1 === boundary.tag && + ((errorInfo.errorBoundary = boundary.stateNode), + (errorInfo.errorBoundaryName = getComponentName(boundary.type)), + (errorInfo.errorBoundaryFound = !0), + (errorInfo.willRetry = !0)); + try { + logCapturedError(errorInfo); + } catch (e) { + setTimeout(function() { + throw e; + }); + } +} +function safelyDetachRef(current$$1) { + var ref = current$$1.ref; + if (null !== ref) + if ("function" === typeof ref) + try { + ref(null); + } catch (refError) { + captureCommitPhaseError(current$$1, refError); + } + else ref.current = null; +} +function commitHookEffectList(unmountTag, mountTag, finishedWork) { + finishedWork = finishedWork.updateQueue; + finishedWork = null !== finishedWork ? finishedWork.lastEffect : null; + if (null !== finishedWork) { + var effect = (finishedWork = finishedWork.next); + do { + if ((effect.tag & unmountTag) !== NoEffect$1) { + var destroy = effect.destroy; + effect.destroy = void 0; + void 0 !== destroy && destroy(); + } + (effect.tag & mountTag) !== NoEffect$1 && + ((destroy = effect.create), (effect.destroy = destroy())); + effect = effect.next; + } while (effect !== finishedWork); + } +} +function hideOrUnhideAllChildren(finishedWork, isHidden) { + for (var node = finishedWork; ; ) { + if (5 === node.tag) { + var instance = node.stateNode; + if (isHidden) { + var viewConfig = instance.viewConfig; + var updatePayload = diffProperties( + null, + emptyObject, + { style: { display: "none" } }, + viewConfig.validAttributes + ); + ReactNativePrivateInterface.UIManager.updateView( + instance._nativeTag, + viewConfig.uiViewClassName, + updatePayload + ); + } else { + instance = node.stateNode; + updatePayload = node.memoizedProps; + viewConfig = instance.viewConfig; + var prevProps = Object.assign({}, updatePayload, { + style: [updatePayload.style, { display: "none" }] + }); + updatePayload = diffProperties( + null, + prevProps, + updatePayload, + viewConfig.validAttributes + ); + ReactNativePrivateInterface.UIManager.updateView( + instance._nativeTag, + viewConfig.uiViewClassName, + updatePayload + ); + } + } else { + if (6 === node.tag) throw Error("Not yet implemented."); + if (13 === node.tag && null !== node.memoizedState) { + instance = node.child.sibling; + instance.return = node; + node = instance; + continue; + } else if (null !== node.child) { + node.child.return = node; + node = node.child; + continue; + } + } + if (node === finishedWork) break; + for (; null === node.sibling; ) { + if (null === node.return || node.return === finishedWork) return; + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } +} +function commitUnmount(current$$1$jscomp$0) { + "function" === typeof onCommitFiberUnmount && + onCommitFiberUnmount(current$$1$jscomp$0); + switch (current$$1$jscomp$0.tag) { + case 0: + case 11: + case 14: + case 15: + var updateQueue = current$$1$jscomp$0.updateQueue; + if ( + null !== updateQueue && + ((updateQueue = updateQueue.lastEffect), null !== updateQueue) + ) { + var effect = (updateQueue = updateQueue.next); + do { + var destroy = effect.destroy; + if (void 0 !== destroy) { + var current$$1 = current$$1$jscomp$0; + try { + destroy(); + } catch (error) { + captureCommitPhaseError(current$$1, error); + } + } + effect = effect.next; + } while (effect !== updateQueue); + } + break; + case 1: + safelyDetachRef(current$$1$jscomp$0); + updateQueue = current$$1$jscomp$0.stateNode; + if ("function" === typeof updateQueue.componentWillUnmount) + try { + (updateQueue.props = current$$1$jscomp$0.memoizedProps), + (updateQueue.state = current$$1$jscomp$0.memoizedState), + updateQueue.componentWillUnmount(); + } catch (unmountError) { + captureCommitPhaseError(current$$1$jscomp$0, unmountError); + } + break; + case 5: + safelyDetachRef(current$$1$jscomp$0); + break; + case 4: + unmountHostComponents(current$$1$jscomp$0); + } +} +function isHostParent(fiber) { + return 5 === fiber.tag || 3 === fiber.tag || 4 === fiber.tag; +} +function commitPlacement(finishedWork) { + a: { + for (var parent = finishedWork.return; null !== parent; ) { + if (isHostParent(parent)) { + var parentFiber = parent; + break a; + } + parent = parent.return; + } + throw ReactError( + "Expected to find a host parent. This error is likely caused by a bug in React. Please file an issue." + ); + } + switch (parentFiber.tag) { + case 5: + parent = parentFiber.stateNode; + var isContainer = !1; + break; + case 3: + parent = parentFiber.stateNode.containerInfo; + isContainer = !0; + break; + case 4: + parent = parentFiber.stateNode.containerInfo; + isContainer = !0; + break; + default: + throw ReactError( + "Invalid host parent fiber. This error is likely caused by a bug in React. Please file an issue." + ); + } + parentFiber.effectTag & 16 && (parentFiber.effectTag &= -17); + a: b: for (parentFiber = finishedWork; ; ) { + for (; null === parentFiber.sibling; ) { + if (null === parentFiber.return || isHostParent(parentFiber.return)) { + parentFiber = null; + break a; + } + parentFiber = parentFiber.return; + } + parentFiber.sibling.return = parentFiber.return; + for ( + parentFiber = parentFiber.sibling; + 5 !== parentFiber.tag && 6 !== parentFiber.tag && 18 !== parentFiber.tag; + + ) { + if (parentFiber.effectTag & 2) continue b; + if (null === parentFiber.child || 4 === parentFiber.tag) continue b; + else + (parentFiber.child.return = parentFiber), + (parentFiber = parentFiber.child); + } + if (!(parentFiber.effectTag & 2)) { + parentFiber = parentFiber.stateNode; + break a; + } + } + for (var node = finishedWork; ; ) { + if (5 === node.tag || 6 === node.tag) { + var stateNode = node.stateNode; + if (parentFiber) + if (isContainer) { + if ("number" === typeof parent) + throw ReactError( + "Container does not support insertBefore operation" + ); + } else { + var parentInstance = parent, + beforeChild = parentFiber, + children = parentInstance._children, + index = children.indexOf(stateNode); + 0 <= index + ? (children.splice(index, 1), + (beforeChild = children.indexOf(beforeChild)), + children.splice(beforeChild, 0, stateNode), + ReactNativePrivateInterface.UIManager.manageChildren( + parentInstance._nativeTag, + [index], + [beforeChild], + [], + [], + [] + )) + : ((index = children.indexOf(beforeChild)), + children.splice(index, 0, stateNode), + ReactNativePrivateInterface.UIManager.manageChildren( + parentInstance._nativeTag, + [], + [], + [ + "number" === typeof stateNode + ? stateNode + : stateNode._nativeTag + ], + [index], + [] + )); + } + else + isContainer + ? ReactNativePrivateInterface.UIManager.setChildren(parent, [ + "number" === typeof stateNode ? stateNode : stateNode._nativeTag + ]) + : ((parentInstance = parent), + (children = + "number" === typeof stateNode ? stateNode : stateNode._nativeTag), + (index = parentInstance._children), + (beforeChild = index.indexOf(stateNode)), + 0 <= beforeChild + ? (index.splice(beforeChild, 1), + index.push(stateNode), + ReactNativePrivateInterface.UIManager.manageChildren( + parentInstance._nativeTag, + [beforeChild], + [index.length - 1], + [], + [], + [] + )) + : (index.push(stateNode), + ReactNativePrivateInterface.UIManager.manageChildren( + parentInstance._nativeTag, + [], + [], + [children], + [index.length - 1], + [] + ))); + } else if (4 !== node.tag && null !== node.child) { + node.child.return = node; + node = node.child; + continue; + } + if (node === finishedWork) break; + for (; null === node.sibling; ) { + if (null === node.return || node.return === finishedWork) return; + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } +} +function unmountHostComponents(current$$1) { + for ( + var node = current$$1, + currentParentIsValid = !1, + currentParent = void 0, + currentParentIsContainer = void 0; + ; + + ) { + if (!currentParentIsValid) { + currentParentIsValid = node.return; + a: for (;;) { + if (null === currentParentIsValid) + throw ReactError( + "Expected to find a host parent. This error is likely caused by a bug in React. Please file an issue." + ); + switch (currentParentIsValid.tag) { + case 5: + currentParent = currentParentIsValid.stateNode; + currentParentIsContainer = !1; + break a; + case 3: + currentParent = currentParentIsValid.stateNode.containerInfo; + currentParentIsContainer = !0; + break a; + case 4: + currentParent = currentParentIsValid.stateNode.containerInfo; + currentParentIsContainer = !0; + break a; + } + currentParentIsValid = currentParentIsValid.return; + } + currentParentIsValid = !0; + } + if (5 === node.tag || 6 === node.tag) { + a: for (var root = node, node$jscomp$0 = root; ; ) + if ( + (commitUnmount(node$jscomp$0), + null !== node$jscomp$0.child && 4 !== node$jscomp$0.tag) + ) + (node$jscomp$0.child.return = node$jscomp$0), + (node$jscomp$0 = node$jscomp$0.child); + else { + if (node$jscomp$0 === root) break; + for (; null === node$jscomp$0.sibling; ) { + if (null === node$jscomp$0.return || node$jscomp$0.return === root) + break a; + node$jscomp$0 = node$jscomp$0.return; + } + node$jscomp$0.sibling.return = node$jscomp$0.return; + node$jscomp$0 = node$jscomp$0.sibling; + } + if (currentParentIsContainer) + (root = currentParent), + recursivelyUncacheFiberNode(node.stateNode), + ReactNativePrivateInterface.UIManager.manageChildren( + root, + [], + [], + [], + [], + [0] + ); + else { + root = currentParent; + var child = node.stateNode; + recursivelyUncacheFiberNode(child); + node$jscomp$0 = root._children; + child = node$jscomp$0.indexOf(child); + node$jscomp$0.splice(child, 1); + ReactNativePrivateInterface.UIManager.manageChildren( + root._nativeTag, + [], + [], + [], + [], + [child] + ); + } + } else if (4 === node.tag) { + if (null !== node.child) { + currentParent = node.stateNode.containerInfo; + currentParentIsContainer = !0; + node.child.return = node; + node = node.child; + continue; + } + } else if ((commitUnmount(node), null !== node.child)) { + node.child.return = node; + node = node.child; + continue; + } + if (node === current$$1) break; + for (; null === node.sibling; ) { + if (null === node.return || node.return === current$$1) return; + node = node.return; + 4 === node.tag && (currentParentIsValid = !1); + } + node.sibling.return = node.return; + node = node.sibling; + } +} +function commitWork(current$$1, finishedWork) { + switch (finishedWork.tag) { + case 0: + case 11: + case 14: + case 15: + commitHookEffectList(UnmountMutation, MountMutation, finishedWork); + break; + case 1: + break; + case 5: + var instance = finishedWork.stateNode; + if (null != instance) { + var newProps = finishedWork.memoizedProps; + current$$1 = null !== current$$1 ? current$$1.memoizedProps : newProps; + var updatePayload = finishedWork.updateQueue; + finishedWork.updateQueue = null; + null !== updatePayload && + ((finishedWork = instance.viewConfig), + (instanceProps[instance._nativeTag] = newProps), + (newProps = diffProperties( + null, + current$$1, + newProps, + finishedWork.validAttributes + )), + null != newProps && + ReactNativePrivateInterface.UIManager.updateView( + instance._nativeTag, + finishedWork.uiViewClassName, + newProps + )); + } + break; + case 6: + if (null === finishedWork.stateNode) + throw ReactError( + "This should have a text node initialized. This error is likely caused by a bug in React. Please file an issue." + ); + ReactNativePrivateInterface.UIManager.updateView( + finishedWork.stateNode, + "RCTRawText", + { text: finishedWork.memoizedProps } + ); + break; + case 20: + break; + case 3: + break; + case 12: + break; + case 13: + commitSuspenseComponent(finishedWork); + break; + case 17: + break; + case 19: + break; + default: + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } +} +function commitSuspenseComponent(finishedWork) { + var newState = finishedWork.memoizedState, + newDidTimeout = void 0, + primaryChildParent = finishedWork; + null === newState + ? (newDidTimeout = !1) + : ((newDidTimeout = !0), + (primaryChildParent = finishedWork.child), + 0 === newState.fallbackExpirationTime && + (newState.fallbackExpirationTime = requestCurrentTime() - 500)); + null !== primaryChildParent && + hideOrUnhideAllChildren(primaryChildParent, newDidTimeout); + newState = finishedWork.updateQueue; + if (null !== newState) { + finishedWork.updateQueue = null; + var retryCache = finishedWork.stateNode; + null === retryCache && + (retryCache = finishedWork.stateNode = new PossiblyWeakSet$1()); + newState.forEach(function(thenable) { + var retry = resolveRetryThenable.bind(null, finishedWork, thenable); + retryCache.has(thenable) || + (retryCache.add(thenable), thenable.then(retry, retry)); + }); + } +} +var PossiblyWeakMap = "function" === typeof WeakMap ? WeakMap : Map; +function createRootErrorUpdate(fiber, errorInfo, expirationTime) { + expirationTime = createUpdate(expirationTime); + expirationTime.tag = 3; + expirationTime.payload = { element: null }; + var error = errorInfo.value; + expirationTime.callback = function() { + hasUncaughtError || ((hasUncaughtError = !0), (firstUncaughtError = error)); + logError(fiber, errorInfo); + }; + return expirationTime; +} +function createClassErrorUpdate(fiber, errorInfo, expirationTime) { + expirationTime = createUpdate(expirationTime); + expirationTime.tag = 3; + var getDerivedStateFromError = fiber.type.getDerivedStateFromError; + if ("function" === typeof getDerivedStateFromError) { + var error$jscomp$0 = errorInfo.value; + expirationTime.payload = function() { + return getDerivedStateFromError(error$jscomp$0); + }; + } + var inst = fiber.stateNode; + null !== inst && + "function" === typeof inst.componentDidCatch && + (expirationTime.callback = function() { + "function" !== typeof getDerivedStateFromError && + (null === legacyErrorBoundariesThatAlreadyFailed + ? (legacyErrorBoundariesThatAlreadyFailed = new Set([this])) + : legacyErrorBoundariesThatAlreadyFailed.add(this)); + var error = errorInfo.value, + stack = errorInfo.stack; + logError(fiber, errorInfo); + this.componentDidCatch(error, { + componentStack: null !== stack ? stack : "" + }); + }); + return expirationTime; +} +function unwindWork(workInProgress) { + switch (workInProgress.tag) { + case 1: + isContextProvider(workInProgress.type) && popContext(workInProgress); + var effectTag = workInProgress.effectTag; + return effectTag & 2048 + ? ((workInProgress.effectTag = (effectTag & -2049) | 64), + workInProgress) + : null; + case 3: + popHostContainer(workInProgress); + popTopLevelContextObject(workInProgress); + effectTag = workInProgress.effectTag; + if (0 !== (effectTag & 64)) + throw ReactError( + "The root failed to unmount after an error. This is likely a bug in React. Please file an issue." + ); + workInProgress.effectTag = (effectTag & -2049) | 64; + return workInProgress; + case 5: + return popHostContext(workInProgress), null; + case 13: + return ( + (effectTag = workInProgress.effectTag), + effectTag & 2048 + ? ((workInProgress.effectTag = (effectTag & -2049) | 64), + workInProgress) + : null + ); + case 18: + return null; + case 4: + return popHostContainer(workInProgress), null; + case 10: + return popProvider(workInProgress), null; + case 19: + case 20: + return null; + default: + return null; + } +} +var ceil = Math.ceil, + ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher, + ReactCurrentOwner$2 = ReactSharedInternals.ReactCurrentOwner, + LegacyUnbatchedPhase = 2, + RenderPhase = 4, + CommitPhase = 5, + RootIncomplete = 0, + RootErrored = 1, + RootSuspended = 2, + RootCompleted = 3, + workPhase = 0, + workInProgressRoot = null, + workInProgress = null, + renderExpirationTime = 0, + workInProgressRootExitStatus = RootIncomplete, + workInProgressRootMostRecentEventTime = 1073741823, + nextEffect = null, + hasUncaughtError = !1, + firstUncaughtError = null, + legacyErrorBoundariesThatAlreadyFailed = null, + rootDoesHavePassiveEffects = !1, + rootWithPendingPassiveEffects = null, + rootsWithPendingDiscreteUpdates = null, + nestedUpdateCount = 0, + rootWithNestedUpdates = null, + currentEventTime = 0; +function requestCurrentTime() { + return workPhase === RenderPhase || workPhase === CommitPhase + ? 1073741822 - ((now() / 10) | 0) + : 0 !== currentEventTime + ? currentEventTime + : (currentEventTime = 1073741822 - ((now() / 10) | 0)); +} +function computeExpirationForFiber(currentTime, fiber) { + if (0 === (fiber.mode & 1)) return 1073741823; + if (workPhase === RenderPhase) return renderExpirationTime; + switch (getCurrentPriorityLevel()) { + case 99: + currentTime = 1073741823; + break; + case 98: + currentTime = + 1073741822 - 10 * ((((1073741822 - currentTime + 15) / 10) | 0) + 1); + break; + case 97: + case 96: + currentTime = + 1073741822 - 25 * ((((1073741822 - currentTime + 500) / 25) | 0) + 1); + break; + case 95: + currentTime = 1; + break; + default: + throw ReactError("Expected a valid priority level"); + } + null !== workInProgressRoot && + currentTime === renderExpirationTime && + --currentTime; + return currentTime; +} +function scheduleUpdateOnFiber(fiber, expirationTime) { + if (50 < nestedUpdateCount) + throw ((nestedUpdateCount = 0), + (rootWithNestedUpdates = null), + ReactError( + "Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops." + )); + fiber = markUpdateTimeFromFiberToRoot(fiber, expirationTime); + if (null !== fiber) + if (((fiber.pingTime = 0), 1073741823 === expirationTime)) + if (workPhase === LegacyUnbatchedPhase) + for ( + expirationTime = renderRoot(fiber, 1073741823, !0); + null !== expirationTime; + + ) + expirationTime = expirationTime(!0); + else + scheduleCallbackForRoot(fiber, 99, 1073741823), + 0 === workPhase && flushImmediateQueue(); + else { + var priorityLevel = getCurrentPriorityLevel(); + if (98 === priorityLevel) + if (null === rootsWithPendingDiscreteUpdates) + rootsWithPendingDiscreteUpdates = new Map([[fiber, expirationTime]]); + else { + var lastDiscreteTime = rootsWithPendingDiscreteUpdates.get(fiber); + (void 0 === lastDiscreteTime || lastDiscreteTime > expirationTime) && + rootsWithPendingDiscreteUpdates.set(fiber, expirationTime); + } + scheduleCallbackForRoot(fiber, priorityLevel, expirationTime); + } +} +function markUpdateTimeFromFiberToRoot(fiber, expirationTime) { + fiber.expirationTime < expirationTime && + (fiber.expirationTime = expirationTime); + var alternate = fiber.alternate; + null !== alternate && + alternate.expirationTime < expirationTime && + (alternate.expirationTime = expirationTime); + var node = fiber.return, + root = null; + if (null === node && 3 === fiber.tag) root = fiber.stateNode; + else + for (; null !== node; ) { + alternate = node.alternate; + node.childExpirationTime < expirationTime && + (node.childExpirationTime = expirationTime); + null !== alternate && + alternate.childExpirationTime < expirationTime && + (alternate.childExpirationTime = expirationTime); + if (null === node.return && 3 === node.tag) { + root = node.stateNode; + break; + } + node = node.return; + } + null !== root && + (expirationTime > root.firstPendingTime && + (root.firstPendingTime = expirationTime), + (fiber = root.lastPendingTime), + 0 === fiber || expirationTime < fiber) && + (root.lastPendingTime = expirationTime); + return root; +} +function scheduleCallbackForRoot(root, priorityLevel, expirationTime) { + if (root.callbackExpirationTime < expirationTime) { + var existingCallbackNode = root.callbackNode; + null !== existingCallbackNode && + existingCallbackNode !== fakeCallbackNode && + Scheduler_cancelCallback(existingCallbackNode); + root.callbackExpirationTime = expirationTime; + existingCallbackNode = null; + 1073741823 !== expirationTime && + 1 !== expirationTime && + ((existingCallbackNode = 10 * (1073741822 - expirationTime) - now()), + 5e3 < existingCallbackNode && (existingCallbackNode = 5e3), + (existingCallbackNode = { timeout: existingCallbackNode })); + root.callbackNode = scheduleCallback( + priorityLevel, + runRootCallback.bind( + null, + root, + renderRoot.bind(null, root, expirationTime) + ), + existingCallbackNode + ); + } +} +function runRootCallback(root, callback, isSync) { + var prevCallbackNode = root.callbackNode, + continuation = null; + try { + return ( + (continuation = callback(isSync)), + null !== continuation + ? runRootCallback.bind(null, root, continuation) + : null + ); + } finally { + null === continuation && + prevCallbackNode === root.callbackNode && + ((root.callbackNode = null), (root.callbackExpirationTime = 0)); + } +} +function resolveLocksOnRoot(root, expirationTime) { + var firstBatch = root.firstBatch; + return null !== firstBatch && + firstBatch._defer && + firstBatch._expirationTime >= expirationTime + ? ((root.finishedWork = root.current.alternate), + (root.pendingCommitExpirationTime = expirationTime), + scheduleCallback(97, function() { + firstBatch._onComplete(); + return null; + }), + !0) + : !1; +} +function flushPendingDiscreteUpdates() { + if (null !== rootsWithPendingDiscreteUpdates) { + var roots = rootsWithPendingDiscreteUpdates; + rootsWithPendingDiscreteUpdates = null; + roots.forEach(function(expirationTime, root) { + scheduleCallback(99, renderRoot.bind(null, root, expirationTime)); + }); + flushImmediateQueue(); + } +} +function prepareFreshStack(root, expirationTime) { + root.pendingCommitExpirationTime = 0; + var timeoutHandle = root.timeoutHandle; + -1 !== timeoutHandle && + ((root.timeoutHandle = -1), cancelTimeout(timeoutHandle)); + if (null !== workInProgress) + for (timeoutHandle = workInProgress.return; null !== timeoutHandle; ) { + var interruptedWork = timeoutHandle; + switch (interruptedWork.tag) { + case 1: + var childContextTypes = interruptedWork.type.childContextTypes; + null !== childContextTypes && + void 0 !== childContextTypes && + popContext(interruptedWork); + break; + case 3: + popHostContainer(interruptedWork); + popTopLevelContextObject(interruptedWork); + break; + case 5: + popHostContext(interruptedWork); + break; + case 4: + popHostContainer(interruptedWork); + break; + case 10: + popProvider(interruptedWork); + } + timeoutHandle = timeoutHandle.return; + } + workInProgressRoot = root; + workInProgress = createWorkInProgress(root.current, null, expirationTime); + renderExpirationTime = expirationTime; + workInProgressRootExitStatus = RootIncomplete; + workInProgressRootMostRecentEventTime = 1073741823; +} +function renderRoot(root$jscomp$0, expirationTime, isSync) { + if (workPhase === RenderPhase || workPhase === CommitPhase) + throw ReactError("Should not already be working."); + if (root$jscomp$0.firstPendingTime < expirationTime) return null; + if (root$jscomp$0.pendingCommitExpirationTime === expirationTime) + return ( + (root$jscomp$0.pendingCommitExpirationTime = 0), + commitRoot.bind(null, root$jscomp$0, expirationTime) + ); + flushPassiveEffects(); + (root$jscomp$0 === workInProgressRoot && + expirationTime === renderExpirationTime) || + prepareFreshStack(root$jscomp$0, expirationTime); + if (null !== workInProgress) { + var prevWorkPhase = workPhase; + workPhase = RenderPhase; + var prevDispatcher = ReactCurrentDispatcher.current; + null === prevDispatcher && (prevDispatcher = ContextOnlyDispatcher); + ReactCurrentDispatcher.current = ContextOnlyDispatcher; + if (isSync) { + if (1073741823 !== expirationTime) { + var currentTime = requestCurrentTime(); + if (currentTime < expirationTime) + return ( + (workPhase = prevWorkPhase), + resetContextDependences(), + (ReactCurrentDispatcher.current = prevDispatcher), + renderRoot.bind(null, root$jscomp$0, currentTime) + ); + } + } else currentEventTime = 0; + do + try { + if (isSync) + for (; null !== workInProgress; ) + workInProgress = performUnitOfWork(workInProgress); + else + for (; null !== workInProgress && !shouldYield(); ) + workInProgress = performUnitOfWork(workInProgress); + break; + } catch (thrownValue) { + resetContextDependences(); + resetHooks(); + currentTime = workInProgress; + if (null === currentTime || null === currentTime.return) + throw (prepareFreshStack(root$jscomp$0, expirationTime), + (workPhase = prevWorkPhase), + thrownValue); + a: { + var root = root$jscomp$0, + returnFiber = currentTime.return, + sourceFiber = currentTime, + value = thrownValue, + renderExpirationTime$jscomp$0 = renderExpirationTime; + sourceFiber.effectTag |= 1024; + sourceFiber.firstEffect = sourceFiber.lastEffect = null; + if ( + null !== value && + "object" === typeof value && + "function" === typeof value.then + ) { + var thenable = value; + value = returnFiber; + do { + if ( + 13 === value.tag && + (void 0 === value.memoizedProps.fallback + ? 0 + : null === value.memoizedState) + ) { + returnFiber = value.updateQueue; + null === returnFiber + ? ((returnFiber = new Set()), + returnFiber.add(thenable), + (value.updateQueue = returnFiber)) + : returnFiber.add(thenable); + if (0 === (value.mode & 1)) { + value.effectTag |= 64; + sourceFiber.effectTag &= -1957; + 1 === sourceFiber.tag && + (null === sourceFiber.alternate + ? (sourceFiber.tag = 17) + : ((renderExpirationTime$jscomp$0 = createUpdate( + 1073741823 + )), + (renderExpirationTime$jscomp$0.tag = 2), + enqueueUpdate( + sourceFiber, + renderExpirationTime$jscomp$0 + ))); + sourceFiber.expirationTime = 1073741823; + break a; + } + sourceFiber = root; + root = renderExpirationTime$jscomp$0; + var pingCache = sourceFiber.pingCache; + null === pingCache + ? ((pingCache = sourceFiber.pingCache = new PossiblyWeakMap()), + (returnFiber = new Set()), + pingCache.set(thenable, returnFiber)) + : ((returnFiber = pingCache.get(thenable)), + void 0 === returnFiber && + ((returnFiber = new Set()), + pingCache.set(thenable, returnFiber))); + returnFiber.has(root) || + (returnFiber.add(root), + (sourceFiber = pingSuspendedRoot.bind( + null, + sourceFiber, + thenable, + root + )), + thenable.then(sourceFiber, sourceFiber)); + value.effectTag |= 2048; + value.expirationTime = renderExpirationTime$jscomp$0; + break a; + } + value = value.return; + } while (null !== value); + value = Error( + (getComponentName(sourceFiber.type) || "A React component") + + " suspended while rendering, but no fallback UI was specified.\n\nAdd a component higher in the tree to provide a loading indicator or placeholder to display." + + getStackByFiberInDevAndProd(sourceFiber) + ); + } + if ( + workInProgressRootExitStatus === RootIncomplete || + workInProgressRootExitStatus === RootSuspended + ) + workInProgressRootExitStatus = RootErrored; + value = createCapturedValue(value, sourceFiber); + sourceFiber = returnFiber; + do { + switch (sourceFiber.tag) { + case 3: + sourceFiber.effectTag |= 2048; + sourceFiber.expirationTime = renderExpirationTime$jscomp$0; + renderExpirationTime$jscomp$0 = createRootErrorUpdate( + sourceFiber, + value, + renderExpirationTime$jscomp$0 + ); + enqueueCapturedUpdate( + sourceFiber, + renderExpirationTime$jscomp$0 + ); + break a; + case 1: + if ( + ((thenable = value), + (root = sourceFiber.type), + (returnFiber = sourceFiber.stateNode), + 0 === (sourceFiber.effectTag & 64) && + ("function" === typeof root.getDerivedStateFromError || + (null !== returnFiber && + "function" === typeof returnFiber.componentDidCatch && + (null === legacyErrorBoundariesThatAlreadyFailed || + !legacyErrorBoundariesThatAlreadyFailed.has( + returnFiber + ))))) + ) { + sourceFiber.effectTag |= 2048; + sourceFiber.expirationTime = renderExpirationTime$jscomp$0; + renderExpirationTime$jscomp$0 = createClassErrorUpdate( + sourceFiber, + thenable, + renderExpirationTime$jscomp$0 + ); + enqueueCapturedUpdate( + sourceFiber, + renderExpirationTime$jscomp$0 + ); + break a; + } + } + sourceFiber = sourceFiber.return; + } while (null !== sourceFiber); + } + workInProgress = completeUnitOfWork(currentTime); + } + while (1); + workPhase = prevWorkPhase; + resetContextDependences(); + ReactCurrentDispatcher.current = prevDispatcher; + if (null !== workInProgress) + return renderRoot.bind(null, root$jscomp$0, expirationTime); + } + if (resolveLocksOnRoot(root$jscomp$0, expirationTime)) return null; + workInProgressRoot = null; + switch (workInProgressRootExitStatus) { + case RootIncomplete: + throw ReactError("Should have a work-in-progress."); + case RootErrored: + return ( + (prevWorkPhase = root$jscomp$0.lastPendingTime), + root$jscomp$0.lastPendingTime < expirationTime + ? renderRoot.bind(null, root$jscomp$0, prevWorkPhase) + : isSync + ? commitRoot.bind(null, root$jscomp$0, expirationTime) + : (prepareFreshStack(root$jscomp$0, expirationTime), + scheduleCallback( + 99, + renderRoot.bind(null, root$jscomp$0, expirationTime) + ), + null) + ); + case RootSuspended: + if (!isSync) { + isSync = root$jscomp$0.lastPendingTime; + if (root$jscomp$0.lastPendingTime < expirationTime) + return renderRoot.bind(null, root$jscomp$0, isSync); + if ( + 1073741823 !== workInProgressRootMostRecentEventTime && + ((prevWorkPhase = + 10 * (1073741822 - workInProgressRootMostRecentEventTime) - 5e3), + (isSync = now()), + (prevWorkPhase = isSync - prevWorkPhase), + (prevWorkPhase = + (120 > prevWorkPhase + ? 120 + : 480 > prevWorkPhase + ? 480 + : 1080 > prevWorkPhase + ? 1080 + : 1920 > prevWorkPhase + ? 1920 + : 3e3 > prevWorkPhase + ? 3e3 + : 4320 > prevWorkPhase + ? 4320 + : 1960 * ceil(prevWorkPhase / 1960)) - prevWorkPhase), + (isSync = 10 * (1073741822 - expirationTime) - isSync), + isSync < prevWorkPhase && (prevWorkPhase = isSync), + (isSync = prevWorkPhase), + 10 < isSync) + ) + return ( + (root$jscomp$0.timeoutHandle = scheduleTimeout( + commitRoot.bind(null, root$jscomp$0, expirationTime), + isSync + )), + null + ); + } + return commitRoot.bind(null, root$jscomp$0, expirationTime); + case RootCompleted: + return commitRoot.bind(null, root$jscomp$0, expirationTime); + default: + throw ReactError("Unknown root exit status."); + } +} +function performUnitOfWork(unitOfWork) { + var next = beginWork$$1( + unitOfWork.alternate, + unitOfWork, + renderExpirationTime + ); + unitOfWork.memoizedProps = unitOfWork.pendingProps; + null === next && (next = completeUnitOfWork(unitOfWork)); + ReactCurrentOwner$2.current = null; + return next; +} +function completeUnitOfWork(unitOfWork) { + workInProgress = unitOfWork; + do { + var current$$1 = workInProgress.alternate; + unitOfWork = workInProgress.return; + if (0 === (workInProgress.effectTag & 1024)) { + a: { + var current = current$$1; + current$$1 = workInProgress; + var renderExpirationTime$jscomp$0 = renderExpirationTime, + newProps = current$$1.pendingProps; + switch (current$$1.tag) { + case 2: + break; + case 16: + break; + case 15: + case 0: + break; + case 1: + isContextProvider(current$$1.type) && popContext(current$$1); + break; + case 3: + popHostContainer(current$$1); + popTopLevelContextObject(current$$1); + newProps = current$$1.stateNode; + newProps.pendingContext && + ((newProps.context = newProps.pendingContext), + (newProps.pendingContext = null)); + if (null === current || null === current.child) + current$$1.effectTag &= -3; + updateHostContainer(current$$1); + break; + case 5: + popHostContext(current$$1); + renderExpirationTime$jscomp$0 = requiredContext( + rootInstanceStackCursor.current + ); + var type = current$$1.type; + if (null !== current && null != current$$1.stateNode) + updateHostComponent$1( + current, + current$$1, + type, + newProps, + renderExpirationTime$jscomp$0 + ), + current.ref !== current$$1.ref && (current$$1.effectTag |= 128); + else if (newProps) { + current = requiredContext(contextStackCursor$1.current); + var type$jscomp$0 = type; + var instance = newProps; + var rootContainerInstance = renderExpirationTime$jscomp$0, + internalInstanceHandle = current$$1, + tag = allocateTag(); + type$jscomp$0 = getViewConfigForType(type$jscomp$0); + var updatePayload = diffProperties( + null, + emptyObject, + instance, + type$jscomp$0.validAttributes + ); + ReactNativePrivateInterface.UIManager.createView( + tag, + type$jscomp$0.uiViewClassName, + rootContainerInstance, + updatePayload + ); + rootContainerInstance = new ReactNativeFiberHostComponent( + tag, + type$jscomp$0 + ); + instanceCache[tag] = internalInstanceHandle; + instanceProps[tag] = instance; + instance = rootContainerInstance; + appendAllChildren(instance, current$$1, !1, !1); + finalizeInitialChildren( + instance, + type, + newProps, + renderExpirationTime$jscomp$0, + current + ) && (current$$1.effectTag |= 4); + current$$1.stateNode = instance; + null !== current$$1.ref && (current$$1.effectTag |= 128); + } else if (null === current$$1.stateNode) + throw ReactError( + "We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue." + ); + break; + case 6: + if (current && null != current$$1.stateNode) + updateHostText$1( + current, + current$$1, + current.memoizedProps, + newProps + ); + else { + if ("string" !== typeof newProps && null === current$$1.stateNode) + throw ReactError( + "We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue." + ); + current = requiredContext(rootInstanceStackCursor.current); + type = requiredContext(contextStackCursor$1.current); + renderExpirationTime$jscomp$0 = current$$1; + if (!type.isInAParentText) + throw ReactError( + "Text strings must be rendered within a component." + ); + type = allocateTag(); + ReactNativePrivateInterface.UIManager.createView( + type, + "RCTRawText", + current, + { text: newProps } + ); + instanceCache[type] = current$$1; + renderExpirationTime$jscomp$0.stateNode = type; + } + break; + case 11: + break; + case 13: + newProps = current$$1.memoizedState; + if (0 !== (current$$1.effectTag & 64)) { + current$$1.expirationTime = renderExpirationTime$jscomp$0; + break a; + } + newProps = null !== newProps; + renderExpirationTime$jscomp$0 = !1; + null !== current && + ((type = current.memoizedState), + (renderExpirationTime$jscomp$0 = null !== type), + newProps || + null === type || + ((type = type.fallbackExpirationTime), + type < workInProgressRootMostRecentEventTime && + (workInProgressRootMostRecentEventTime = type), + (type = current.child.sibling), + null !== type && + ((current = current$$1.firstEffect), + null !== current + ? ((current$$1.firstEffect = type), + (type.nextEffect = current)) + : ((current$$1.firstEffect = current$$1.lastEffect = type), + (type.nextEffect = null)), + (type.effectTag = 8)))); + newProps && + !renderExpirationTime$jscomp$0 && + 0 !== (current$$1.mode & 1) && + workInProgressRootExitStatus === RootIncomplete && + (workInProgressRootExitStatus = RootSuspended); + if (newProps || renderExpirationTime$jscomp$0) + current$$1.effectTag |= 4; + break; + case 7: + break; + case 8: + break; + case 12: + break; + case 4: + popHostContainer(current$$1); + updateHostContainer(current$$1); + break; + case 10: + popProvider(current$$1); + break; + case 9: + break; + case 14: + break; + case 17: + isContextProvider(current$$1.type) && popContext(current$$1); + break; + case 18: + break; + case 19: + break; + case 20: + break; + default: + throw ReactError( + "Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue." + ); + } + current$$1 = null; + } + newProps = workInProgress; + if (1 === renderExpirationTime || 1 !== newProps.childExpirationTime) { + renderExpirationTime$jscomp$0 = 0; + for (type = newProps.child; null !== type; ) + (current = type.expirationTime), + (instance = type.childExpirationTime), + current > renderExpirationTime$jscomp$0 && + (renderExpirationTime$jscomp$0 = current), + instance > renderExpirationTime$jscomp$0 && + (renderExpirationTime$jscomp$0 = instance), + (type = type.sibling); + newProps.childExpirationTime = renderExpirationTime$jscomp$0; + } + if (null !== current$$1) return current$$1; + null !== unitOfWork && + 0 === (unitOfWork.effectTag & 1024) && + (null === unitOfWork.firstEffect && + (unitOfWork.firstEffect = workInProgress.firstEffect), + null !== workInProgress.lastEffect && + (null !== unitOfWork.lastEffect && + (unitOfWork.lastEffect.nextEffect = workInProgress.firstEffect), + (unitOfWork.lastEffect = workInProgress.lastEffect)), + 1 < workInProgress.effectTag && + (null !== unitOfWork.lastEffect + ? (unitOfWork.lastEffect.nextEffect = workInProgress) + : (unitOfWork.firstEffect = workInProgress), + (unitOfWork.lastEffect = workInProgress))); + } else { + current$$1 = unwindWork(workInProgress, renderExpirationTime); + if (null !== current$$1) + return (current$$1.effectTag &= 1023), current$$1; + null !== unitOfWork && + ((unitOfWork.firstEffect = unitOfWork.lastEffect = null), + (unitOfWork.effectTag |= 1024)); + } + current$$1 = workInProgress.sibling; + if (null !== current$$1) return current$$1; + workInProgress = unitOfWork; + } while (null !== workInProgress); + workInProgressRootExitStatus === RootIncomplete && + (workInProgressRootExitStatus = RootCompleted); + return null; +} +function commitRoot(root, expirationTime) { + runWithPriority(99, commitRootImpl.bind(null, root, expirationTime)); + null !== rootWithPendingPassiveEffects && + ((root = getCurrentPriorityLevel()), + scheduleCallback(root, function() { + flushPassiveEffects(); + return null; + })); + return null; +} +function commitRootImpl(root, expirationTime) { + flushPassiveEffects(); + if (workPhase === RenderPhase || workPhase === CommitPhase) + throw ReactError("Should not already be working."); + var finishedWork = root.current.alternate; + if (null === finishedWork) + throw ReactError("Should have a work-in-progress root."); + root.callbackNode = null; + root.callbackExpirationTime = 0; + var updateExpirationTimeBeforeCommit = finishedWork.expirationTime, + childExpirationTimeBeforeCommit = finishedWork.childExpirationTime; + updateExpirationTimeBeforeCommit = + childExpirationTimeBeforeCommit > updateExpirationTimeBeforeCommit + ? childExpirationTimeBeforeCommit + : updateExpirationTimeBeforeCommit; + root.firstPendingTime = updateExpirationTimeBeforeCommit; + updateExpirationTimeBeforeCommit < root.lastPendingTime && + (root.lastPendingTime = updateExpirationTimeBeforeCommit); + root === workInProgressRoot && + ((workInProgress = workInProgressRoot = null), (renderExpirationTime = 0)); + 1 < finishedWork.effectTag + ? null !== finishedWork.lastEffect + ? ((finishedWork.lastEffect.nextEffect = finishedWork), + (childExpirationTimeBeforeCommit = finishedWork.firstEffect)) + : (childExpirationTimeBeforeCommit = finishedWork) + : (childExpirationTimeBeforeCommit = finishedWork.firstEffect); + if (null !== childExpirationTimeBeforeCommit) { + updateExpirationTimeBeforeCommit = workPhase; + workPhase = CommitPhase; + ReactCurrentOwner$2.current = null; + nextEffect = childExpirationTimeBeforeCommit; + do + try { + for (; null !== nextEffect; ) { + if (0 !== (nextEffect.effectTag & 256)) { + var current$$1 = nextEffect.alternate, + finishedWork$jscomp$0 = nextEffect; + switch (finishedWork$jscomp$0.tag) { + case 0: + case 11: + case 15: + commitHookEffectList( + UnmountSnapshot, + NoEffect$1, + finishedWork$jscomp$0 + ); + break; + case 1: + if ( + finishedWork$jscomp$0.effectTag & 256 && + null !== current$$1 + ) { + var prevProps = current$$1.memoizedProps, + prevState = current$$1.memoizedState, + instance = finishedWork$jscomp$0.stateNode, + snapshot = instance.getSnapshotBeforeUpdate( + finishedWork$jscomp$0.elementType === + finishedWork$jscomp$0.type + ? prevProps + : resolveDefaultProps( + finishedWork$jscomp$0.type, + prevProps + ), + prevState + ); + instance.__reactInternalSnapshotBeforeUpdate = snapshot; + } + break; + case 3: + case 5: + case 6: + case 4: + case 17: + case 20: + break; + default: + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + } + nextEffect = nextEffect.nextEffect; + } + } catch (error) { + if (null === nextEffect) + throw ReactError("Should be working on an effect."); + captureCommitPhaseError(nextEffect, error); + nextEffect = nextEffect.nextEffect; + } + while (null !== nextEffect); + nextEffect = childExpirationTimeBeforeCommit; + do + try { + for (; null !== nextEffect; ) { + var effectTag = nextEffect.effectTag; + if (effectTag & 128) { + var current$$1$jscomp$0 = nextEffect.alternate; + if (null !== current$$1$jscomp$0) { + var currentRef = current$$1$jscomp$0.ref; + null !== currentRef && + ("function" === typeof currentRef + ? currentRef(null) + : (currentRef.current = null)); + } + } + switch (effectTag & 14) { + case 2: + commitPlacement(nextEffect); + nextEffect.effectTag &= -3; + break; + case 6: + commitPlacement(nextEffect); + nextEffect.effectTag &= -3; + commitWork(nextEffect.alternate, nextEffect); + break; + case 4: + commitWork(nextEffect.alternate, nextEffect); + break; + case 8: + current$$1 = nextEffect; + unmountHostComponents(current$$1); + current$$1.return = null; + current$$1.child = null; + current$$1.memoizedState = null; + current$$1.updateQueue = null; + var alternate = current$$1.alternate; + null !== alternate && + ((alternate.return = null), + (alternate.child = null), + (alternate.memoizedState = null), + (alternate.updateQueue = null)); + } + nextEffect = nextEffect.nextEffect; + } + } catch (error) { + if (null === nextEffect) + throw ReactError("Should be working on an effect."); + captureCommitPhaseError(nextEffect, error); + nextEffect = nextEffect.nextEffect; + } + while (null !== nextEffect); + root.current = finishedWork; + nextEffect = childExpirationTimeBeforeCommit; + do + try { + for (effectTag = expirationTime; null !== nextEffect; ) { + var effectTag$jscomp$0 = nextEffect.effectTag; + if (effectTag$jscomp$0 & 36) { + var current$$1$jscomp$1 = nextEffect.alternate; + current$$1$jscomp$0 = nextEffect; + currentRef = effectTag; + switch (current$$1$jscomp$0.tag) { + case 0: + case 11: + case 15: + commitHookEffectList( + UnmountLayout, + MountLayout, + current$$1$jscomp$0 + ); + break; + case 1: + var instance$jscomp$0 = current$$1$jscomp$0.stateNode; + if (current$$1$jscomp$0.effectTag & 4) + if (null === current$$1$jscomp$1) + instance$jscomp$0.componentDidMount(); + else { + var prevProps$jscomp$0 = + current$$1$jscomp$0.elementType === + current$$1$jscomp$0.type + ? current$$1$jscomp$1.memoizedProps + : resolveDefaultProps( + current$$1$jscomp$0.type, + current$$1$jscomp$1.memoizedProps + ); + instance$jscomp$0.componentDidUpdate( + prevProps$jscomp$0, + current$$1$jscomp$1.memoizedState, + instance$jscomp$0.__reactInternalSnapshotBeforeUpdate + ); + } + var updateQueue = current$$1$jscomp$0.updateQueue; + null !== updateQueue && + commitUpdateQueue( + current$$1$jscomp$0, + updateQueue, + instance$jscomp$0, + currentRef + ); + break; + case 3: + var _updateQueue = current$$1$jscomp$0.updateQueue; + if (null !== _updateQueue) { + alternate = null; + if (null !== current$$1$jscomp$0.child) + switch (current$$1$jscomp$0.child.tag) { + case 5: + alternate = current$$1$jscomp$0.child.stateNode; + break; + case 1: + alternate = current$$1$jscomp$0.child.stateNode; + } + commitUpdateQueue( + current$$1$jscomp$0, + _updateQueue, + alternate, + currentRef + ); + } + break; + case 5: + break; + case 6: + break; + case 4: + break; + case 12: + break; + case 13: + case 17: + break; + case 20: + break; + case 19: + break; + default: + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + } + if (effectTag$jscomp$0 & 128) { + var ref = nextEffect.ref; + if (null !== ref) { + var instance$jscomp$1 = nextEffect.stateNode; + switch (nextEffect.tag) { + case 5: + var instanceToUse = instance$jscomp$1; + break; + default: + instanceToUse = instance$jscomp$1; + } + "function" === typeof ref + ? ref(instanceToUse) + : (ref.current = instanceToUse); + } + } + effectTag$jscomp$0 & 512 && (rootDoesHavePassiveEffects = !0); + nextEffect = nextEffect.nextEffect; + } + } catch (error) { + if (null === nextEffect) + throw ReactError("Should be working on an effect."); + captureCommitPhaseError(nextEffect, error); + nextEffect = nextEffect.nextEffect; + } + while (null !== nextEffect); + nextEffect = null; + workPhase = updateExpirationTimeBeforeCommit; + } else root.current = finishedWork; + rootDoesHavePassiveEffects && + ((rootDoesHavePassiveEffects = !1), (rootWithPendingPassiveEffects = root)); + expirationTime = root.firstPendingTime; + 0 !== expirationTime + ? ((effectTag$jscomp$0 = requestCurrentTime()), + (effectTag$jscomp$0 = inferPriorityFromExpirationTime( + effectTag$jscomp$0, + expirationTime + )), + scheduleCallbackForRoot(root, effectTag$jscomp$0, expirationTime)) + : (legacyErrorBoundariesThatAlreadyFailed = null); + "function" === typeof onCommitFiberRoot && + onCommitFiberRoot(finishedWork.stateNode); + 1073741823 === expirationTime + ? root === rootWithNestedUpdates + ? nestedUpdateCount++ + : ((nestedUpdateCount = 0), (rootWithNestedUpdates = root)) + : (nestedUpdateCount = 0); + if (hasUncaughtError) + throw ((hasUncaughtError = !1), + (root = firstUncaughtError), + (firstUncaughtError = null), + root); + if (workPhase === LegacyUnbatchedPhase) return null; + flushImmediateQueue(); + return null; +} +function flushPassiveEffects() { + if (null === rootWithPendingPassiveEffects) return !1; + var root = rootWithPendingPassiveEffects; + rootWithPendingPassiveEffects = null; + if (workPhase === RenderPhase || workPhase === CommitPhase) + throw ReactError("Cannot flush passive effects while already rendering."); + var prevWorkPhase = workPhase; + workPhase = CommitPhase; + for (root = root.current.firstEffect; null !== root; ) { + try { + var finishedWork = root; + commitHookEffectList(UnmountPassive, NoEffect$1, finishedWork); + commitHookEffectList(NoEffect$1, MountPassive, finishedWork); + } catch (error) { + if (null === root) throw ReactError("Should be working on an effect."); + captureCommitPhaseError(root, error); + } + root = root.nextEffect; + } + workPhase = prevWorkPhase; + flushImmediateQueue(); + return !0; +} +function captureCommitPhaseErrorOnRoot(rootFiber, sourceFiber, error) { + sourceFiber = createCapturedValue(error, sourceFiber); + sourceFiber = createRootErrorUpdate(rootFiber, sourceFiber, 1073741823); + enqueueUpdate(rootFiber, sourceFiber); + rootFiber = markUpdateTimeFromFiberToRoot(rootFiber, 1073741823); + null !== rootFiber && scheduleCallbackForRoot(rootFiber, 99, 1073741823); +} +function captureCommitPhaseError(sourceFiber, error) { + if (3 === sourceFiber.tag) + captureCommitPhaseErrorOnRoot(sourceFiber, sourceFiber, error); + else + for (var fiber = sourceFiber.return; null !== fiber; ) { + if (3 === fiber.tag) { + captureCommitPhaseErrorOnRoot(fiber, sourceFiber, error); + break; + } else if (1 === fiber.tag) { + var instance = fiber.stateNode; + if ( + "function" === typeof fiber.type.getDerivedStateFromError || + ("function" === typeof instance.componentDidCatch && + (null === legacyErrorBoundariesThatAlreadyFailed || + !legacyErrorBoundariesThatAlreadyFailed.has(instance))) + ) { + sourceFiber = createCapturedValue(error, sourceFiber); + sourceFiber = createClassErrorUpdate(fiber, sourceFiber, 1073741823); + enqueueUpdate(fiber, sourceFiber); + fiber = markUpdateTimeFromFiberToRoot(fiber, 1073741823); + null !== fiber && scheduleCallbackForRoot(fiber, 99, 1073741823); + break; + } + } + fiber = fiber.return; + } +} +function pingSuspendedRoot(root, thenable, suspendedTime) { + var pingCache = root.pingCache; + null !== pingCache && pingCache.delete(thenable); + workInProgressRoot === root && renderExpirationTime === suspendedTime + ? prepareFreshStack(root, renderExpirationTime) + : root.lastPendingTime < suspendedTime || + ((thenable = root.pingTime), + (0 !== thenable && thenable < suspendedTime) || + ((root.pingTime = suspendedTime), + (thenable = requestCurrentTime()), + (thenable = inferPriorityFromExpirationTime(thenable, suspendedTime)), + scheduleCallbackForRoot(root, thenable, suspendedTime))); +} +function resolveRetryThenable(boundaryFiber, thenable) { + var retryCache = boundaryFiber.stateNode; + null !== retryCache && retryCache.delete(thenable); + retryCache = requestCurrentTime(); + thenable = computeExpirationForFiber(retryCache, boundaryFiber); + retryCache = inferPriorityFromExpirationTime(retryCache, thenable); + boundaryFiber = markUpdateTimeFromFiberToRoot(boundaryFiber, thenable); + null !== boundaryFiber && + scheduleCallbackForRoot(boundaryFiber, retryCache, thenable); +} +var beginWork$$1 = void 0; +beginWork$$1 = function(current$$1, workInProgress, renderExpirationTime) { + var updateExpirationTime = workInProgress.expirationTime; + if (null !== current$$1) + if ( + current$$1.memoizedProps !== workInProgress.pendingProps || + didPerformWorkStackCursor.current + ) + didReceiveUpdate = !0; + else { + if (updateExpirationTime < renderExpirationTime) { + didReceiveUpdate = !1; + switch (workInProgress.tag) { + case 3: + pushHostRootContext(workInProgress); + break; + case 5: + pushHostContext(workInProgress); + break; + case 1: + isContextProvider(workInProgress.type) && + pushContextProvider(workInProgress); + break; + case 4: + pushHostContainer( + workInProgress, + workInProgress.stateNode.containerInfo + ); + break; + case 10: + pushProvider(workInProgress, workInProgress.memoizedProps.value); + break; + case 13: + if (null !== workInProgress.memoizedState) { + updateExpirationTime = workInProgress.child.childExpirationTime; + if ( + 0 !== updateExpirationTime && + updateExpirationTime >= renderExpirationTime + ) + return updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + workInProgress = bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + return null !== workInProgress ? workInProgress.sibling : null; + } + } + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + } + else didReceiveUpdate = !1; + workInProgress.expirationTime = 0; + switch (workInProgress.tag) { + case 2: + updateExpirationTime = workInProgress.elementType; + null !== current$$1 && + ((current$$1.alternate = null), + (workInProgress.alternate = null), + (workInProgress.effectTag |= 2)); + current$$1 = workInProgress.pendingProps; + var context = getMaskedContext( + workInProgress, + contextStackCursor.current + ); + prepareToReadContext(workInProgress, renderExpirationTime); + context = renderWithHooks( + null, + workInProgress, + updateExpirationTime, + current$$1, + context, + renderExpirationTime + ); + workInProgress.effectTag |= 1; + if ( + "object" === typeof context && + null !== context && + "function" === typeof context.render && + void 0 === context.$$typeof + ) { + workInProgress.tag = 1; + resetHooks(); + if (isContextProvider(updateExpirationTime)) { + var hasContext = !0; + pushContextProvider(workInProgress); + } else hasContext = !1; + workInProgress.memoizedState = + null !== context.state && void 0 !== context.state + ? context.state + : null; + var getDerivedStateFromProps = + updateExpirationTime.getDerivedStateFromProps; + "function" === typeof getDerivedStateFromProps && + applyDerivedStateFromProps( + workInProgress, + updateExpirationTime, + getDerivedStateFromProps, + current$$1 + ); + context.updater = classComponentUpdater; + workInProgress.stateNode = context; + context._reactInternalFiber = workInProgress; + mountClassInstance( + workInProgress, + updateExpirationTime, + current$$1, + renderExpirationTime + ); + workInProgress = finishClassComponent( + null, + workInProgress, + updateExpirationTime, + !0, + hasContext, + renderExpirationTime + ); + } else + (workInProgress.tag = 0), + reconcileChildren( + null, + workInProgress, + context, + renderExpirationTime + ), + (workInProgress = workInProgress.child); + return workInProgress; + case 16: + context = workInProgress.elementType; + null !== current$$1 && + ((current$$1.alternate = null), + (workInProgress.alternate = null), + (workInProgress.effectTag |= 2)); + current$$1 = workInProgress.pendingProps; + context = readLazyComponentType(context); + workInProgress.type = context; + hasContext = workInProgress.tag = resolveLazyComponentTag(context); + current$$1 = resolveDefaultProps(context, current$$1); + switch (hasContext) { + case 0: + workInProgress = updateFunctionComponent( + null, + workInProgress, + context, + current$$1, + renderExpirationTime + ); + break; + case 1: + workInProgress = updateClassComponent( + null, + workInProgress, + context, + current$$1, + renderExpirationTime + ); + break; + case 11: + workInProgress = updateForwardRef( + null, + workInProgress, + context, + current$$1, + renderExpirationTime + ); + break; + case 14: + workInProgress = updateMemoComponent( + null, + workInProgress, + context, + resolveDefaultProps(context.type, current$$1), + updateExpirationTime, + renderExpirationTime + ); + break; + default: + throw ReactError( + "Element type is invalid. Received a promise that resolves to: " + + context + + ". Lazy element type must resolve to a class or function." + ); + } + return workInProgress; + case 0: + return ( + (updateExpirationTime = workInProgress.type), + (context = workInProgress.pendingProps), + (context = + workInProgress.elementType === updateExpirationTime + ? context + : resolveDefaultProps(updateExpirationTime, context)), + updateFunctionComponent( + current$$1, + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ) + ); + case 1: + return ( + (updateExpirationTime = workInProgress.type), + (context = workInProgress.pendingProps), + (context = + workInProgress.elementType === updateExpirationTime + ? context + : resolveDefaultProps(updateExpirationTime, context)), + updateClassComponent( + current$$1, + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ) + ); + case 3: + pushHostRootContext(workInProgress); + updateExpirationTime = workInProgress.updateQueue; + if (null === updateExpirationTime) + throw ReactError( + "If the root does not have an updateQueue, we should have already bailed out. This error is likely caused by a bug in React. Please file an issue." + ); + context = workInProgress.memoizedState; + context = null !== context ? context.element : null; + processUpdateQueue( + workInProgress, + updateExpirationTime, + workInProgress.pendingProps, + null, + renderExpirationTime + ); + updateExpirationTime = workInProgress.memoizedState.element; + updateExpirationTime === context + ? (workInProgress = bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + )) + : (reconcileChildren( + current$$1, + workInProgress, + updateExpirationTime, + renderExpirationTime + ), + (workInProgress = workInProgress.child)); + return workInProgress; + case 5: + return ( + pushHostContext(workInProgress), + null === current$$1 && tryToClaimNextHydratableInstance(workInProgress), + (updateExpirationTime = workInProgress.pendingProps.children), + markRef(current$$1, workInProgress), + reconcileChildren( + current$$1, + workInProgress, + updateExpirationTime, + renderExpirationTime + ), + workInProgress.child + ); + case 6: + return ( + null === current$$1 && tryToClaimNextHydratableInstance(workInProgress), + null + ); + case 13: + return updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + case 4: + return ( + pushHostContainer( + workInProgress, + workInProgress.stateNode.containerInfo + ), + (updateExpirationTime = workInProgress.pendingProps), + null === current$$1 + ? (workInProgress.child = reconcileChildFibers( + workInProgress, + null, + updateExpirationTime, + renderExpirationTime + )) + : reconcileChildren( + current$$1, + workInProgress, + updateExpirationTime, + renderExpirationTime + ), + workInProgress.child + ); + case 11: + return ( + (updateExpirationTime = workInProgress.type), + (context = workInProgress.pendingProps), + (context = + workInProgress.elementType === updateExpirationTime + ? context + : resolveDefaultProps(updateExpirationTime, context)), + updateForwardRef( + current$$1, + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ) + ); + case 7: + return ( + reconcileChildren( + current$$1, + workInProgress, + workInProgress.pendingProps, + renderExpirationTime + ), + workInProgress.child + ); + case 8: + return ( + reconcileChildren( + current$$1, + workInProgress, + workInProgress.pendingProps.children, + renderExpirationTime + ), + workInProgress.child + ); + case 12: + return ( + reconcileChildren( + current$$1, + workInProgress, + workInProgress.pendingProps.children, + renderExpirationTime + ), + workInProgress.child + ); + case 10: + a: { + updateExpirationTime = workInProgress.type._context; + context = workInProgress.pendingProps; + getDerivedStateFromProps = workInProgress.memoizedProps; + hasContext = context.value; + pushProvider(workInProgress, hasContext); + if (null !== getDerivedStateFromProps) { + var oldValue = getDerivedStateFromProps.value; + hasContext = is(oldValue, hasContext) + ? 0 + : ("function" === typeof updateExpirationTime._calculateChangedBits + ? updateExpirationTime._calculateChangedBits( + oldValue, + hasContext + ) + : 1073741823) | 0; + if (0 === hasContext) { + if ( + getDerivedStateFromProps.children === context.children && + !didPerformWorkStackCursor.current + ) { + workInProgress = bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + break a; + } + } else + for ( + oldValue = workInProgress.child, + null !== oldValue && (oldValue.return = workInProgress); + null !== oldValue; + + ) { + var list = oldValue.contextDependencies; + if (null !== list) { + getDerivedStateFromProps = oldValue.child; + for (var dependency = list.first; null !== dependency; ) { + if ( + dependency.context === updateExpirationTime && + 0 !== (dependency.observedBits & hasContext) + ) { + 1 === oldValue.tag && + ((dependency = createUpdate(renderExpirationTime)), + (dependency.tag = 2), + enqueueUpdate(oldValue, dependency)); + oldValue.expirationTime < renderExpirationTime && + (oldValue.expirationTime = renderExpirationTime); + dependency = oldValue.alternate; + null !== dependency && + dependency.expirationTime < renderExpirationTime && + (dependency.expirationTime = renderExpirationTime); + dependency = renderExpirationTime; + for (var node = oldValue.return; null !== node; ) { + var alternate = node.alternate; + if (node.childExpirationTime < dependency) + (node.childExpirationTime = dependency), + null !== alternate && + alternate.childExpirationTime < dependency && + (alternate.childExpirationTime = dependency); + else if ( + null !== alternate && + alternate.childExpirationTime < dependency + ) + alternate.childExpirationTime = dependency; + else break; + node = node.return; + } + list.expirationTime < renderExpirationTime && + (list.expirationTime = renderExpirationTime); + break; + } + dependency = dependency.next; + } + } else + getDerivedStateFromProps = + 10 === oldValue.tag + ? oldValue.type === workInProgress.type + ? null + : oldValue.child + : oldValue.child; + if (null !== getDerivedStateFromProps) + getDerivedStateFromProps.return = oldValue; + else + for ( + getDerivedStateFromProps = oldValue; + null !== getDerivedStateFromProps; + + ) { + if (getDerivedStateFromProps === workInProgress) { + getDerivedStateFromProps = null; + break; + } + oldValue = getDerivedStateFromProps.sibling; + if (null !== oldValue) { + oldValue.return = getDerivedStateFromProps.return; + getDerivedStateFromProps = oldValue; + break; + } + getDerivedStateFromProps = getDerivedStateFromProps.return; + } + oldValue = getDerivedStateFromProps; + } + } + reconcileChildren( + current$$1, + workInProgress, + context.children, + renderExpirationTime + ); + workInProgress = workInProgress.child; + } + return workInProgress; + case 9: + return ( + (context = workInProgress.type), + (hasContext = workInProgress.pendingProps), + (updateExpirationTime = hasContext.children), + prepareToReadContext(workInProgress, renderExpirationTime), + (context = readContext(context, hasContext.unstable_observedBits)), + (updateExpirationTime = updateExpirationTime(context)), + (workInProgress.effectTag |= 1), + reconcileChildren( + current$$1, + workInProgress, + updateExpirationTime, + renderExpirationTime + ), + workInProgress.child + ); + case 14: + return ( + (context = workInProgress.type), + (hasContext = resolveDefaultProps( + context, + workInProgress.pendingProps + )), + (hasContext = resolveDefaultProps(context.type, hasContext)), + updateMemoComponent( + current$$1, + workInProgress, + context, + hasContext, + updateExpirationTime, + renderExpirationTime + ) + ); + case 15: + return updateSimpleMemoComponent( + current$$1, + workInProgress, + workInProgress.type, + workInProgress.pendingProps, + updateExpirationTime, + renderExpirationTime + ); + case 17: + return ( + (updateExpirationTime = workInProgress.type), + (context = workInProgress.pendingProps), + (context = + workInProgress.elementType === updateExpirationTime + ? context + : resolveDefaultProps(updateExpirationTime, context)), + null !== current$$1 && + ((current$$1.alternate = null), + (workInProgress.alternate = null), + (workInProgress.effectTag |= 2)), + (workInProgress.tag = 1), + isContextProvider(updateExpirationTime) + ? ((current$$1 = !0), pushContextProvider(workInProgress)) + : (current$$1 = !1), + prepareToReadContext(workInProgress, renderExpirationTime), + constructClassInstance( + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ), + mountClassInstance( + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ), + finishClassComponent( + null, + workInProgress, + updateExpirationTime, + !0, + current$$1, + renderExpirationTime + ) + ); + } + throw ReactError( + "Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue." + ); +}; +function findHostInstance(component) { + var fiber = component._reactInternalFiber; + if (void 0 === fiber) { + if ("function" === typeof component.render) + throw ReactError("Unable to find node on an unmounted component."); + throw ReactError( + "Argument appears to not be a ReactComponent. Keys: " + + Object.keys(component) + ); + } + component = findCurrentHostFiber(fiber); + return null === component ? null : component.stateNode; +} +function updateContainer(element, container, parentComponent, callback) { + var current$$1 = container.current, + currentTime = requestCurrentTime(); + current$$1 = computeExpirationForFiber(currentTime, current$$1); + currentTime = container.current; + a: if (parentComponent) { + parentComponent = parentComponent._reactInternalFiber; + b: { + if ( + 2 !== isFiberMountedImpl(parentComponent) || + 1 !== parentComponent.tag + ) + throw ReactError( + "Expected subtree parent to be a mounted class component. This error is likely caused by a bug in React. Please file an issue." + ); + var parentContext = parentComponent; + do { + switch (parentContext.tag) { + case 3: + parentContext = parentContext.stateNode.context; + break b; + case 1: + if (isContextProvider(parentContext.type)) { + parentContext = + parentContext.stateNode + .__reactInternalMemoizedMergedChildContext; + break b; + } + } + parentContext = parentContext.return; + } while (null !== parentContext); + throw ReactError( + "Found unexpected detached subtree parent. This error is likely caused by a bug in React. Please file an issue." + ); + } + if (1 === parentComponent.tag) { + var Component = parentComponent.type; + if (isContextProvider(Component)) { + parentComponent = processChildContext( + parentComponent, + Component, + parentContext + ); + break a; + } + } + parentComponent = parentContext; + } else parentComponent = emptyContextObject; + null === container.context + ? (container.context = parentComponent) + : (container.pendingContext = parentComponent); + container = callback; + callback = createUpdate(current$$1); + callback.payload = { element: element }; + container = void 0 === container ? null : container; + null !== container && (callback.callback = container); + flushPassiveEffects(); + enqueueUpdate(currentTime, callback); + scheduleUpdateOnFiber(currentTime, current$$1); + return current$$1; +} +function createPortal(children, containerInfo, implementation) { + var key = + 3 < arguments.length && void 0 !== arguments[3] ? arguments[3] : null; + return { + $$typeof: REACT_PORTAL_TYPE, + key: null == key ? null : "" + key, + children: children, + containerInfo: containerInfo, + implementation: implementation + }; +} +function _inherits(subClass, superClass) { + if ("function" !== typeof superClass && null !== superClass) + throw new TypeError( + "Super expression must either be null or a function, not " + + typeof superClass + ); + subClass.prototype = Object.create(superClass && superClass.prototype, { + constructor: { + value: subClass, + enumerable: !1, + writable: !0, + configurable: !0 + } + }); + superClass && + (Object.setPrototypeOf + ? Object.setPrototypeOf(subClass, superClass) + : (subClass.__proto__ = superClass)); +} +var getInspectorDataForViewTag = void 0; +getInspectorDataForViewTag = function() { + throw ReactError( + "getInspectorDataForViewTag() is not available in production" + ); +}; +function findNodeHandle(componentOrHandle) { + if (null == componentOrHandle) return null; + if ("number" === typeof componentOrHandle) return componentOrHandle; + if (componentOrHandle._nativeTag) return componentOrHandle._nativeTag; + if (componentOrHandle.canonical && componentOrHandle.canonical._nativeTag) + return componentOrHandle.canonical._nativeTag; + componentOrHandle = findHostInstance(componentOrHandle); + return null == componentOrHandle + ? componentOrHandle + : componentOrHandle.canonical + ? componentOrHandle.canonical._nativeTag + : componentOrHandle._nativeTag; +} +_batchedUpdatesImpl = function(fn, a) { + if (0 !== workPhase) return fn(a); + workPhase = 1; + try { + return fn(a); + } finally { + (workPhase = 0), flushImmediateQueue(); + } +}; +_flushInteractiveUpdatesImpl = function() { + workPhase !== RenderPhase && + workPhase !== CommitPhase && + flushPendingDiscreteUpdates(); +}; +var roots = new Map(), + ReactNativeRenderer = { + NativeComponent: (function(findNodeHandle, findHostInstance) { + return (function(_React$Component) { + function ReactNativeComponent() { + if (!(this instanceof ReactNativeComponent)) + throw new TypeError("Cannot call a class as a function"); + var call = _React$Component.apply(this, arguments); + if (!this) + throw new ReferenceError( + "this hasn't been initialised - super() hasn't been called" + ); + return !call || + ("object" !== typeof call && "function" !== typeof call) + ? this + : call; + } + _inherits(ReactNativeComponent, _React$Component); + ReactNativeComponent.prototype.blur = function() { + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); + }; + ReactNativeComponent.prototype.focus = function() { + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); + }; + ReactNativeComponent.prototype.measure = function(callback) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null != maybeInstance && + (maybeInstance.canonical + ? nativeFabricUIManager.measure( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ) + : ReactNativePrivateInterface.UIManager.measure( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + )); + }; + ReactNativeComponent.prototype.measureInWindow = function(callback) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null != maybeInstance && + (maybeInstance.canonical + ? nativeFabricUIManager.measureInWindow( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ) + : ReactNativePrivateInterface.UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + )); + }; + ReactNativeComponent.prototype.measureLayout = function( + relativeToNativeNode, + onSuccess, + onFail + ) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null == maybeInstance || + maybeInstance.canonical || + ((maybeInstance = void 0), + "number" === typeof relativeToNativeNode + ? (maybeInstance = relativeToNativeNode) + : relativeToNativeNode._nativeTag && + (maybeInstance = relativeToNativeNode._nativeTag), + null != maybeInstance && + ReactNativePrivateInterface.UIManager.measureLayout( + findNodeHandle(this), + maybeInstance, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + )); + }; + ReactNativeComponent.prototype.setNativeProps = function(nativeProps) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + if (null != maybeInstance && !maybeInstance.canonical) { + var nativeTag = + maybeInstance._nativeTag || maybeInstance.canonical._nativeTag; + maybeInstance = + maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; + nativeProps = diffProperties( + null, + emptyObject, + nativeProps, + maybeInstance.validAttributes + ); + null != nativeProps && + ReactNativePrivateInterface.UIManager.updateView( + nativeTag, + maybeInstance.uiViewClassName, + nativeProps + ); + } + }; + return ReactNativeComponent; + })(React.Component); + })(findNodeHandle, findHostInstance), + findNodeHandle: findNodeHandle, + setNativeProps: function(handle, nativeProps) { + null != handle._nativeTag && + ((nativeProps = diffProperties( + null, + emptyObject, + nativeProps, + handle.viewConfig.validAttributes + )), + null != nativeProps && + ReactNativePrivateInterface.UIManager.updateView( + handle._nativeTag, + handle.viewConfig.uiViewClassName, + nativeProps + )); + }, + render: function(element, containerTag, callback) { + var root = roots.get(containerTag); + if (!root) { + root = new FiberRootNode(containerTag, !1); + var uninitializedFiber = createFiber(3, null, null, 0); + root.current = uninitializedFiber; + uninitializedFiber.stateNode = root; + roots.set(containerTag, root); + } + updateContainer(element, root, null, callback); + a: if (((element = root.current), element.child)) + switch (element.child.tag) { + case 5: + element = element.child.stateNode; + break a; + default: + element = element.child.stateNode; + } + else element = null; + return element; + }, + unmountComponentAtNode: function(containerTag) { + var root = roots.get(containerTag); + root && + updateContainer(null, root, null, function() { + roots.delete(containerTag); + }); + }, + unmountComponentAtNodeAndRemoveContainer: function(containerTag) { + ReactNativeRenderer.unmountComponentAtNode(containerTag); + ReactNativePrivateInterface.UIManager.removeRootView(containerTag); + }, + createPortal: function(children, containerTag) { + return createPortal( + children, + containerTag, + null, + 2 < arguments.length && void 0 !== arguments[2] ? arguments[2] : null + ); + }, + unstable_batchedUpdates: batchedUpdates, + __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { + NativeMethodsMixin: (function(findNodeHandle, findHostInstance) { + return { + measure: function(callback) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null != maybeInstance && + (maybeInstance.canonical + ? nativeFabricUIManager.measure( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ) + : ReactNativePrivateInterface.UIManager.measure( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + )); + }, + measureInWindow: function(callback) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null != maybeInstance && + (maybeInstance.canonical + ? nativeFabricUIManager.measureInWindow( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ) + : ReactNativePrivateInterface.UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + )); + }, + measureLayout: function(relativeToNativeNode, onSuccess, onFail) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null == maybeInstance || + maybeInstance.canonical || + ((maybeInstance = void 0), + "number" === typeof relativeToNativeNode + ? (maybeInstance = relativeToNativeNode) + : relativeToNativeNode._nativeTag && + (maybeInstance = relativeToNativeNode._nativeTag), + null != maybeInstance && + ReactNativePrivateInterface.UIManager.measureLayout( + findNodeHandle(this), + maybeInstance, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + )); + }, + setNativeProps: function(nativeProps) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + if (null != maybeInstance && !maybeInstance.canonical) { + var nativeTag = + maybeInstance._nativeTag || maybeInstance.canonical._nativeTag; + maybeInstance = + maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; + nativeProps = diffProperties( + null, + emptyObject, + nativeProps, + maybeInstance.validAttributes + ); + null != nativeProps && + ReactNativePrivateInterface.UIManager.updateView( + nativeTag, + maybeInstance.uiViewClassName, + nativeProps + ); + } + }, + focus: function() { + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); + }, + blur: function() { + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); + } + }; + })(findNodeHandle, findHostInstance), + computeComponentStackForErrorReporting: function(reactTag) { + return (reactTag = getInstanceFromTag(reactTag)) + ? getStackByFiberInDevAndProd(reactTag) + : ""; + } + } + }; +(function(devToolsConfig) { + var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; + return injectInternals( + Object.assign({}, devToolsConfig, { + overrideHookState: null, + overrideProps: null, + setSuspenseHandler: null, + scheduleUpdate: null, + currentDispatcherRef: ReactSharedInternals.ReactCurrentDispatcher, + findHostInstanceByFiber: function(fiber) { + fiber = findCurrentHostFiber(fiber); + return null === fiber ? null : fiber.stateNode; + }, + findFiberByHostInstance: function(instance) { + return findFiberByHostInstance + ? findFiberByHostInstance(instance) + : null; + } + }) + ); +})({ + findFiberByHostInstance: getInstanceFromTag, + getInspectorDataForViewTag: getInspectorDataForViewTag, + bundleType: 0, + version: "16.8.6", + rendererPackageName: "react-native-renderer" +}); +var ReactNativeRenderer$2 = { default: ReactNativeRenderer }, + ReactNativeRenderer$3 = + (ReactNativeRenderer$2 && ReactNativeRenderer) || ReactNativeRenderer$2; +module.exports = ReactNativeRenderer$3.default || ReactNativeRenderer$3; diff --git a/Libraries/Renderer/oss/ReactNativeRenderer-prod.js b/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js similarity index 97% rename from Libraries/Renderer/oss/ReactNativeRenderer-prod.js rename to Libraries/Renderer/implementations/ReactNativeRenderer-prod.js index 5fbb834c706292..4e2b964402e434 100644 --- a/Libraries/Renderer/oss/ReactNativeRenderer-prod.js +++ b/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js @@ -11,16 +11,10 @@ */ "use strict"; -require("InitializeCore"); -var ReactNativeViewConfigRegistry = require("ReactNativeViewConfigRegistry"), - UIManager = require("UIManager"), - RCTEventEmitter = require("RCTEventEmitter"), +require("react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore"); +var ReactNativePrivateInterface = require("react-native/Libraries/ReactPrivate/ReactNativePrivateInterface"), React = require("react"), - deepDiffer = require("deepDiffer"), - flattenStyle = require("flattenStyle"), - TextInputState = require("TextInputState"), Scheduler = require("scheduler"); -var ExceptionsManager = require("ExceptionsManager"); function ReactError(message) { message = Error(message); message.name = "Invariant Violation"; @@ -617,7 +611,7 @@ function changeResponder(nextResponderInst, blockHostResponder) { blockHostResponder ); } -var eventTypes$1 = { +var eventTypes = { startShouldSetResponder: { phasedRegistrationNames: { bubbled: "onStartShouldSetResponder", @@ -680,7 +674,7 @@ var eventTypes$1 = { _getResponder: function() { return responderInst; }, - eventTypes: eventTypes$1, + eventTypes: eventTypes, extractEvents: function( topLevelType, targetInst, @@ -709,12 +703,12 @@ var eventTypes$1 = { isMoveish(topLevelType)) ) { var JSCompiler_temp = isStartish(topLevelType) - ? eventTypes$1.startShouldSetResponder + ? eventTypes.startShouldSetResponder : isMoveish(topLevelType) - ? eventTypes$1.moveShouldSetResponder + ? eventTypes.moveShouldSetResponder : "topSelectionChange" === topLevelType - ? eventTypes$1.selectionChangeShouldSetResponder - : eventTypes$1.scrollShouldSetResponder; + ? eventTypes.selectionChangeShouldSetResponder + : eventTypes.scrollShouldSetResponder; if (responderInst) b: { var JSCompiler_temp$jscomp$0 = responderInst; @@ -800,7 +794,7 @@ var eventTypes$1 = { JSCompiler_temp && JSCompiler_temp !== responderInst ? ((JSCompiler_temp$jscomp$0 = void 0), (targetInst = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderGrant, + eventTypes.responderGrant, JSCompiler_temp, nativeEvent, nativeEventTarget @@ -810,7 +804,7 @@ var eventTypes$1 = { (depthA = !0 === executeDirectDispatch(targetInst)), responderInst ? ((tempA = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderTerminationRequest, + eventTypes.responderTerminationRequest, responderInst, nativeEvent, nativeEventTarget @@ -822,7 +816,7 @@ var eventTypes$1 = { tempA.isPersistent() || tempA.constructor.release(tempA), tempB ? ((tempA = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderTerminate, + eventTypes.responderTerminate, responderInst, nativeEvent, nativeEventTarget @@ -836,7 +830,7 @@ var eventTypes$1 = { )), changeResponder(JSCompiler_temp, depthA)) : ((JSCompiler_temp = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderReject, + eventTypes.responderReject, JSCompiler_temp, nativeEvent, nativeEventTarget @@ -866,11 +860,11 @@ var eventTypes$1 = { ("topTouchEnd" === topLevelType || "topTouchCancel" === topLevelType); if ( (JSCompiler_temp$jscomp$0 = JSCompiler_temp$jscomp$0 - ? eventTypes$1.responderStart + ? eventTypes.responderStart : targetInst - ? eventTypes$1.responderMove + ? eventTypes.responderMove : depthA - ? eventTypes$1.responderEnd + ? eventTypes.responderEnd : null) ) (JSCompiler_temp$jscomp$0 = ResponderSyntheticEvent.getPooled( @@ -924,9 +918,9 @@ var eventTypes$1 = { } if ( (topLevelType = JSCompiler_temp$jscomp$0 - ? eventTypes$1.responderTerminate + ? eventTypes.responderTerminate : topLevelType - ? eventTypes$1.responderRelease + ? eventTypes.responderRelease : null) ) (nativeEvent = ResponderSyntheticEvent.getPooled( @@ -948,8 +942,15 @@ var eventTypes$1 = { } } }, + customBubblingEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customBubblingEventTypes, + customDirectEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customDirectEventTypes, ReactNativeBridgeEventPlugin = { - eventTypes: ReactNativeViewConfigRegistry.eventTypes, + eventTypes: + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes, extractEvents: function( topLevelType, targetInst, @@ -957,10 +958,8 @@ var eventTypes$1 = { nativeEventTarget ) { if (null == targetInst) return null; - var bubbleDispatchConfig = - ReactNativeViewConfigRegistry.customBubblingEventTypes[topLevelType], - directDispatchConfig = - ReactNativeViewConfigRegistry.customDirectEventTypes[topLevelType]; + var bubbleDispatchConfig = customBubblingEventTypes[topLevelType], + directDispatchConfig = customDirectEventTypes[topLevelType]; if (!bubbleDispatchConfig && !directDispatchConfig) throw ReactError( 'Unsupported top level event type "' + topLevelType + '" dispatched' @@ -1060,7 +1059,7 @@ function _receiveRootNodeIDEvent(rootNodeID, topLevelType, nativeEventParam) { } }); } -RCTEventEmitter.register({ +ReactNativePrivateInterface.RCTEventEmitter.register({ receiveEvent: function(rootNodeID, topLevelType, nativeEventParam) { _receiveRootNodeIDEvent(rootNodeID, topLevelType, nativeEventParam); }, @@ -1110,8 +1109,11 @@ getNodeFromInstance = function(inst) { ResponderEventPlugin.injection.injectGlobalResponderHandler({ onChange: function(from, to, blockNativeResponder) { null !== to - ? UIManager.setJSResponder(to.stateNode._nativeTag, blockNativeResponder) - : UIManager.clearJSResponder(); + ? ReactNativePrivateInterface.UIManager.setJSResponder( + to.stateNode._nativeTag, + blockNativeResponder + ) + : ReactNativePrivateInterface.UIManager.clearJSResponder(); } }); var ReactSharedInternals = @@ -1375,14 +1377,14 @@ function diffNestedProperty( return Array.isArray(prevProp) ? diffProperties( updatePayload, - flattenStyle(prevProp), + ReactNativePrivateInterface.flattenStyle(prevProp), nextProp, validAttributes ) : diffProperties( updatePayload, prevProp, - flattenStyle(nextProp), + ReactNativePrivateInterface.flattenStyle(nextProp), validAttributes ); } @@ -1450,7 +1452,7 @@ function diffProperties(updatePayload, prevProps, nextProps, validAttributes) { if ("object" !== typeof attributeConfig) ("object" !== typeof nextProp || null === nextProp || - deepDiffer(prevProp, nextProp)) && + ReactNativePrivateInterface.deepDiffer(prevProp, nextProp)) && ((updatePayload || (updatePayload = {}))[propKey] = nextProp); else if ( "function" === typeof attributeConfig.diff || @@ -1462,7 +1464,7 @@ function diffProperties(updatePayload, prevProps, nextProps, validAttributes) { ? attributeConfig.diff(prevProp, nextProp) : "object" !== typeof nextProp || null === nextProp || - deepDiffer(prevProp, nextProp)) + ReactNativePrivateInterface.deepDiffer(prevProp, nextProp)) ) (attributeConfig = "function" === typeof attributeConfig.process @@ -1527,19 +1529,19 @@ var ReactNativeFiberHostComponent = (function() { this.viewConfig = viewConfig; } ReactNativeFiberHostComponent.prototype.blur = function() { - TextInputState.blurTextInput(this._nativeTag); + ReactNativePrivateInterface.TextInputState.blurTextInput(this._nativeTag); }; ReactNativeFiberHostComponent.prototype.focus = function() { - TextInputState.focusTextInput(this._nativeTag); + ReactNativePrivateInterface.TextInputState.focusTextInput(this._nativeTag); }; ReactNativeFiberHostComponent.prototype.measure = function(callback) { - UIManager.measure( + ReactNativePrivateInterface.UIManager.measure( this._nativeTag, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); }; ReactNativeFiberHostComponent.prototype.measureInWindow = function(callback) { - UIManager.measureInWindow( + ReactNativePrivateInterface.UIManager.measureInWindow( this._nativeTag, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); @@ -1558,7 +1560,7 @@ var ReactNativeFiberHostComponent = (function() { relativeToNativeNode.canonical._nativeTag && (relativeNode = relativeToNativeNode.canonical._nativeTag); null != relativeNode && - UIManager.measureLayout( + ReactNativePrivateInterface.UIManager.measureLayout( this._nativeTag, relativeNode, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -1575,7 +1577,7 @@ var ReactNativeFiberHostComponent = (function() { this.viewConfig.validAttributes ); null != nativeProps && - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( this._nativeTag, this.viewConfig.uiViewClassName, nativeProps @@ -1588,7 +1590,9 @@ function shim$1() { "The current renderer does not support hydration. This error is likely caused by a bug in React. Please file an issue." ); } -var UPDATE_SIGNAL = {}, +var getViewConfigForType = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.get, + UPDATE_SIGNAL = {}, nextReactTag = 3; function allocateTag() { var tag = nextReactTag; @@ -1611,7 +1615,10 @@ function finalizeInitialChildren(parentInstance) { var nativeTags = parentInstance._children.map(function(child) { return "number" === typeof child ? child : child._nativeTag; }); - UIManager.setChildren(parentInstance._nativeTag, nativeTags); + ReactNativePrivateInterface.UIManager.setChildren( + parentInstance._nativeTag, + nativeTags + ); return !1; } var scheduleTimeout = setTimeout, @@ -4535,7 +4542,7 @@ function logCapturedError(capturedError) { "string" === typeof error ? Error(error + "\n\nThis error is located at:" + componentStack) : Error("Unspecified error at:" + componentStack); - ExceptionsManager.handleException(error, !1); + ReactNativePrivateInterface.ExceptionsManager.handleException(error, !1); } var PossiblyWeakSet$1 = "function" === typeof WeakSet ? WeakSet : Set; function logError(boundary, errorInfo) { @@ -4607,7 +4614,7 @@ function hideOrUnhideAllChildren(finishedWork, isHidden) { { style: { display: "none" } }, viewConfig.validAttributes ); - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( instance._nativeTag, viewConfig.uiViewClassName, updatePayload @@ -4625,7 +4632,7 @@ function hideOrUnhideAllChildren(finishedWork, isHidden) { updatePayload, viewConfig.validAttributes ); - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( instance._nativeTag, viewConfig.uiViewClassName, updatePayload @@ -4778,7 +4785,7 @@ function commitPlacement(finishedWork) { ? (children.splice(index, 1), (beforeChild = children.indexOf(beforeChild)), children.splice(beforeChild, 0, stateNode), - UIManager.manageChildren( + ReactNativePrivateInterface.UIManager.manageChildren( parentInstance._nativeTag, [index], [beforeChild], @@ -4788,7 +4795,7 @@ function commitPlacement(finishedWork) { )) : ((index = children.indexOf(beforeChild)), children.splice(index, 0, stateNode), - UIManager.manageChildren( + ReactNativePrivateInterface.UIManager.manageChildren( parentInstance._nativeTag, [], [], @@ -4803,7 +4810,7 @@ function commitPlacement(finishedWork) { } else isContainer - ? UIManager.setChildren(parent, [ + ? ReactNativePrivateInterface.UIManager.setChildren(parent, [ "number" === typeof stateNode ? stateNode : stateNode._nativeTag ]) : ((parentInstance = parent), @@ -4814,7 +4821,7 @@ function commitPlacement(finishedWork) { 0 <= beforeChild ? (index.splice(beforeChild, 1), index.push(stateNode), - UIManager.manageChildren( + ReactNativePrivateInterface.UIManager.manageChildren( parentInstance._nativeTag, [beforeChild], [index.length - 1], @@ -4823,7 +4830,7 @@ function commitPlacement(finishedWork) { [] )) : (index.push(stateNode), - UIManager.manageChildren( + ReactNativePrivateInterface.UIManager.manageChildren( parentInstance._nativeTag, [], [], @@ -4900,7 +4907,14 @@ function unmountHostComponents(current$$1) { if (currentParentIsContainer) (root = currentParent), recursivelyUncacheFiberNode(node.stateNode), - UIManager.manageChildren(root, [], [], [], [], [0]); + ReactNativePrivateInterface.UIManager.manageChildren( + root, + [], + [], + [], + [], + [0] + ); else { root = currentParent; var child = node.stateNode; @@ -4908,7 +4922,14 @@ function unmountHostComponents(current$$1) { node$jscomp$0 = root._children; child = node$jscomp$0.indexOf(child); node$jscomp$0.splice(child, 1); - UIManager.manageChildren(root._nativeTag, [], [], [], [], [child]); + ReactNativePrivateInterface.UIManager.manageChildren( + root._nativeTag, + [], + [], + [], + [], + [child] + ); } } else if (4 === node.tag) { if (null !== node.child) { @@ -4960,7 +4981,7 @@ function commitWork(current$$1, finishedWork) { finishedWork.validAttributes )), null != newProps && - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( instance._nativeTag, finishedWork.uiViewClassName, newProps @@ -4972,9 +4993,11 @@ function commitWork(current$$1, finishedWork) { throw ReactError( "This should have a text node initialized. This error is likely caused by a bug in React. Please file an issue." ); - UIManager.updateView(finishedWork.stateNode, "RCTRawText", { - text: finishedWork.memoizedProps - }); + ReactNativePrivateInterface.UIManager.updateView( + finishedWork.stateNode, + "RCTRawText", + { text: finishedWork.memoizedProps } + ); break; case 20: break; @@ -5643,14 +5666,14 @@ function completeUnitOfWork(unitOfWork) { var rootContainerInstance = renderExpirationTime$jscomp$0, internalInstanceHandle = current$$1, tag = allocateTag(); - type$jscomp$0 = ReactNativeViewConfigRegistry.get(type$jscomp$0); + type$jscomp$0 = getViewConfigForType(type$jscomp$0); var updatePayload = diffProperties( null, emptyObject, instance, type$jscomp$0.validAttributes ); - UIManager.createView( + ReactNativePrivateInterface.UIManager.createView( tag, type$jscomp$0.uiViewClassName, rootContainerInstance, @@ -5699,9 +5722,12 @@ function completeUnitOfWork(unitOfWork) { "Text strings must be rendered within a component." ); type = allocateTag(); - UIManager.createView(type, "RCTRawText", current, { - text: newProps - }); + ReactNativePrivateInterface.UIManager.createView( + type, + "RCTRawText", + current, + { text: newProps } + ); instanceCache[type] = current$$1; renderExpirationTime$jscomp$0.stateNode = type; } @@ -6899,10 +6925,14 @@ var roots = new Map(), } _inherits(ReactNativeComponent, _React$Component); ReactNativeComponent.prototype.blur = function() { - TextInputState.blurTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); }; ReactNativeComponent.prototype.focus = function() { - TextInputState.focusTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); }; ReactNativeComponent.prototype.measure = function(callback) { var maybeInstance = void 0; @@ -6915,7 +6945,7 @@ var roots = new Map(), maybeInstance.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ) - : UIManager.measure( + : ReactNativePrivateInterface.UIManager.measure( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) )); @@ -6931,7 +6961,7 @@ var roots = new Map(), maybeInstance.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ) - : UIManager.measureInWindow( + : ReactNativePrivateInterface.UIManager.measureInWindow( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) )); @@ -6953,7 +6983,7 @@ var roots = new Map(), : relativeToNativeNode._nativeTag && (maybeInstance = relativeToNativeNode._nativeTag), null != maybeInstance && - UIManager.measureLayout( + ReactNativePrivateInterface.UIManager.measureLayout( findNodeHandle(this), maybeInstance, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -6977,7 +7007,7 @@ var roots = new Map(), maybeInstance.validAttributes ); null != nativeProps && - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( nativeTag, maybeInstance.uiViewClassName, nativeProps @@ -6997,7 +7027,7 @@ var roots = new Map(), handle.viewConfig.validAttributes )), null != nativeProps && - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( handle._nativeTag, handle.viewConfig.uiViewClassName, nativeProps @@ -7033,7 +7063,7 @@ var roots = new Map(), }, unmountComponentAtNodeAndRemoveContainer: function(containerTag) { ReactNativeRenderer.unmountComponentAtNode(containerTag); - UIManager.removeRootView(containerTag); + ReactNativePrivateInterface.UIManager.removeRootView(containerTag); }, createPortal: function(children, containerTag) { return createPortal( @@ -7058,7 +7088,7 @@ var roots = new Map(), maybeInstance.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ) - : UIManager.measure( + : ReactNativePrivateInterface.UIManager.measure( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) )); @@ -7074,7 +7104,7 @@ var roots = new Map(), maybeInstance.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ) - : UIManager.measureInWindow( + : ReactNativePrivateInterface.UIManager.measureInWindow( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) )); @@ -7092,7 +7122,7 @@ var roots = new Map(), : relativeToNativeNode._nativeTag && (maybeInstance = relativeToNativeNode._nativeTag), null != maybeInstance && - UIManager.measureLayout( + ReactNativePrivateInterface.UIManager.measureLayout( findNodeHandle(this), maybeInstance, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -7116,7 +7146,7 @@ var roots = new Map(), maybeInstance.validAttributes ); null != nativeProps && - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( nativeTag, maybeInstance.uiViewClassName, nativeProps @@ -7124,10 +7154,14 @@ var roots = new Map(), } }, focus: function() { - TextInputState.focusTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); }, blur: function() { - TextInputState.blurTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); } }; })(findNodeHandle, findHostInstance), diff --git a/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.fb.js b/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.fb.js new file mode 100644 index 00000000000000..656ffb77a84847 --- /dev/null +++ b/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.fb.js @@ -0,0 +1,7445 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @noflow + * @preventMunge + * @generated + */ + +"use strict"; +require("react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore"); +var ReactNativePrivateInterface = require("react-native/Libraries/ReactPrivate/ReactNativePrivateInterface"), + React = require("react"), + Scheduler = require("scheduler"), + tracing = require("scheduler/tracing"); +function ReactError(message) { + message = Error(message); + message.name = "Invariant Violation"; + return message; +} +var eventPluginOrder = null, + namesToPlugins = {}; +function recomputePluginOrdering() { + if (eventPluginOrder) + for (var pluginName in namesToPlugins) { + var pluginModule = namesToPlugins[pluginName], + pluginIndex = eventPluginOrder.indexOf(pluginName); + if (!(-1 < pluginIndex)) + throw ReactError( + "EventPluginRegistry: Cannot inject event plugins that do not exist in the plugin ordering, `" + + pluginName + + "`." + ); + if (!plugins[pluginIndex]) { + if (!pluginModule.extractEvents) + throw ReactError( + "EventPluginRegistry: Event plugins must implement an `extractEvents` method, but `" + + pluginName + + "` does not." + ); + plugins[pluginIndex] = pluginModule; + pluginIndex = pluginModule.eventTypes; + for (var eventName in pluginIndex) { + var JSCompiler_inline_result = void 0; + var dispatchConfig = pluginIndex[eventName], + pluginModule$jscomp$0 = pluginModule, + eventName$jscomp$0 = eventName; + if (eventNameDispatchConfigs.hasOwnProperty(eventName$jscomp$0)) + throw ReactError( + "EventPluginHub: More than one plugin attempted to publish the same event name, `" + + eventName$jscomp$0 + + "`." + ); + eventNameDispatchConfigs[eventName$jscomp$0] = dispatchConfig; + var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames; + if (phasedRegistrationNames) { + for (JSCompiler_inline_result in phasedRegistrationNames) + phasedRegistrationNames.hasOwnProperty( + JSCompiler_inline_result + ) && + publishRegistrationName( + phasedRegistrationNames[JSCompiler_inline_result], + pluginModule$jscomp$0, + eventName$jscomp$0 + ); + JSCompiler_inline_result = !0; + } else + dispatchConfig.registrationName + ? (publishRegistrationName( + dispatchConfig.registrationName, + pluginModule$jscomp$0, + eventName$jscomp$0 + ), + (JSCompiler_inline_result = !0)) + : (JSCompiler_inline_result = !1); + if (!JSCompiler_inline_result) + throw ReactError( + "EventPluginRegistry: Failed to publish event `" + + eventName + + "` for plugin `" + + pluginName + + "`." + ); + } + } + } +} +function publishRegistrationName(registrationName, pluginModule) { + if (registrationNameModules[registrationName]) + throw ReactError( + "EventPluginHub: More than one plugin attempted to publish the same registration name, `" + + registrationName + + "`." + ); + registrationNameModules[registrationName] = pluginModule; +} +var plugins = [], + eventNameDispatchConfigs = {}, + registrationNameModules = {}; +function invokeGuardedCallbackImpl(name, func, context, a, b, c, d, e, f) { + var funcArgs = Array.prototype.slice.call(arguments, 3); + try { + func.apply(context, funcArgs); + } catch (error) { + this.onError(error); + } +} +var hasError = !1, + caughtError = null, + hasRethrowError = !1, + rethrowError = null, + reporter = { + onError: function(error) { + hasError = !0; + caughtError = error; + } + }; +function invokeGuardedCallback(name, func, context, a, b, c, d, e, f) { + hasError = !1; + caughtError = null; + invokeGuardedCallbackImpl.apply(reporter, arguments); +} +function invokeGuardedCallbackAndCatchFirstError( + name, + func, + context, + a, + b, + c, + d, + e, + f +) { + invokeGuardedCallback.apply(this, arguments); + if (hasError) { + if (hasError) { + var error = caughtError; + hasError = !1; + caughtError = null; + } else + throw ReactError( + "clearCaughtError was called but no error was captured. This error is likely caused by a bug in React. Please file an issue." + ); + hasRethrowError || ((hasRethrowError = !0), (rethrowError = error)); + } +} +var getFiberCurrentPropsFromNode = null, + getInstanceFromNode = null, + getNodeFromInstance = null; +function executeDispatch(event, listener, inst) { + var type = event.type || "unknown-event"; + event.currentTarget = getNodeFromInstance(inst); + invokeGuardedCallbackAndCatchFirstError(type, listener, void 0, event); + event.currentTarget = null; +} +function executeDirectDispatch(event) { + var dispatchListener = event._dispatchListeners, + dispatchInstance = event._dispatchInstances; + if (Array.isArray(dispatchListener)) + throw ReactError("executeDirectDispatch(...): Invalid `event`."); + event.currentTarget = dispatchListener + ? getNodeFromInstance(dispatchInstance) + : null; + dispatchListener = dispatchListener ? dispatchListener(event) : null; + event.currentTarget = null; + event._dispatchListeners = null; + event._dispatchInstances = null; + return dispatchListener; +} +function accumulateInto(current, next) { + if (null == next) + throw ReactError( + "accumulateInto(...): Accumulated items must not be null or undefined." + ); + if (null == current) return next; + if (Array.isArray(current)) { + if (Array.isArray(next)) return current.push.apply(current, next), current; + current.push(next); + return current; + } + return Array.isArray(next) ? [current].concat(next) : [current, next]; +} +function forEachAccumulated(arr, cb, scope) { + Array.isArray(arr) ? arr.forEach(cb, scope) : arr && cb.call(scope, arr); +} +var eventQueue = null; +function executeDispatchesAndReleaseTopLevel(e) { + if (e) { + var dispatchListeners = e._dispatchListeners, + dispatchInstances = e._dispatchInstances; + if (Array.isArray(dispatchListeners)) + for ( + var i = 0; + i < dispatchListeners.length && !e.isPropagationStopped(); + i++ + ) + executeDispatch(e, dispatchListeners[i], dispatchInstances[i]); + else + dispatchListeners && + executeDispatch(e, dispatchListeners, dispatchInstances); + e._dispatchListeners = null; + e._dispatchInstances = null; + e.isPersistent() || e.constructor.release(e); + } +} +var injection = { + injectEventPluginOrder: function(injectedEventPluginOrder) { + if (eventPluginOrder) + throw ReactError( + "EventPluginRegistry: Cannot inject event plugin ordering more than once. You are likely trying to load more than one copy of React." + ); + eventPluginOrder = Array.prototype.slice.call(injectedEventPluginOrder); + recomputePluginOrdering(); + }, + injectEventPluginsByName: function(injectedNamesToPlugins) { + var isOrderingDirty = !1, + pluginName; + for (pluginName in injectedNamesToPlugins) + if (injectedNamesToPlugins.hasOwnProperty(pluginName)) { + var pluginModule = injectedNamesToPlugins[pluginName]; + if ( + !namesToPlugins.hasOwnProperty(pluginName) || + namesToPlugins[pluginName] !== pluginModule + ) { + if (namesToPlugins[pluginName]) + throw ReactError( + "EventPluginRegistry: Cannot inject two different event plugins using the same name, `" + + pluginName + + "`." + ); + namesToPlugins[pluginName] = pluginModule; + isOrderingDirty = !0; + } + } + isOrderingDirty && recomputePluginOrdering(); + } +}; +function getListener(inst, registrationName) { + var listener = inst.stateNode; + if (!listener) return null; + var props = getFiberCurrentPropsFromNode(listener); + if (!props) return null; + listener = props[registrationName]; + a: switch (registrationName) { + case "onClick": + case "onClickCapture": + case "onDoubleClick": + case "onDoubleClickCapture": + case "onMouseDown": + case "onMouseDownCapture": + case "onMouseMove": + case "onMouseMoveCapture": + case "onMouseUp": + case "onMouseUpCapture": + (props = !props.disabled) || + ((inst = inst.type), + (props = !( + "button" === inst || + "input" === inst || + "select" === inst || + "textarea" === inst + ))); + inst = !props; + break a; + default: + inst = !1; + } + if (inst) return null; + if (listener && "function" !== typeof listener) + throw ReactError( + "Expected `" + + registrationName + + "` listener to be a function, instead got a value of `" + + typeof listener + + "` type." + ); + return listener; +} +function getParent(inst) { + do inst = inst.return; + while (inst && 5 !== inst.tag); + return inst ? inst : null; +} +function traverseTwoPhase(inst, fn, arg) { + for (var path = []; inst; ) path.push(inst), (inst = getParent(inst)); + for (inst = path.length; 0 < inst--; ) fn(path[inst], "captured", arg); + for (inst = 0; inst < path.length; inst++) fn(path[inst], "bubbled", arg); +} +function accumulateDirectionalDispatches(inst, phase, event) { + if ( + (phase = getListener( + inst, + event.dispatchConfig.phasedRegistrationNames[phase] + )) + ) + (event._dispatchListeners = accumulateInto( + event._dispatchListeners, + phase + )), + (event._dispatchInstances = accumulateInto( + event._dispatchInstances, + inst + )); +} +function accumulateTwoPhaseDispatchesSingle(event) { + event && + event.dispatchConfig.phasedRegistrationNames && + traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event); +} +function accumulateTwoPhaseDispatchesSingleSkipTarget(event) { + if (event && event.dispatchConfig.phasedRegistrationNames) { + var targetInst = event._targetInst; + targetInst = targetInst ? getParent(targetInst) : null; + traverseTwoPhase(targetInst, accumulateDirectionalDispatches, event); + } +} +function accumulateDirectDispatchesSingle(event) { + if (event && event.dispatchConfig.registrationName) { + var inst = event._targetInst; + if (inst && event && event.dispatchConfig.registrationName) { + var listener = getListener(inst, event.dispatchConfig.registrationName); + listener && + ((event._dispatchListeners = accumulateInto( + event._dispatchListeners, + listener + )), + (event._dispatchInstances = accumulateInto( + event._dispatchInstances, + inst + ))); + } + } +} +function functionThatReturnsTrue() { + return !0; +} +function functionThatReturnsFalse() { + return !1; +} +function SyntheticEvent( + dispatchConfig, + targetInst, + nativeEvent, + nativeEventTarget +) { + this.dispatchConfig = dispatchConfig; + this._targetInst = targetInst; + this.nativeEvent = nativeEvent; + dispatchConfig = this.constructor.Interface; + for (var propName in dispatchConfig) + dispatchConfig.hasOwnProperty(propName) && + ((targetInst = dispatchConfig[propName]) + ? (this[propName] = targetInst(nativeEvent)) + : "target" === propName + ? (this.target = nativeEventTarget) + : (this[propName] = nativeEvent[propName])); + this.isDefaultPrevented = (null != nativeEvent.defaultPrevented + ? nativeEvent.defaultPrevented + : !1 === nativeEvent.returnValue) + ? functionThatReturnsTrue + : functionThatReturnsFalse; + this.isPropagationStopped = functionThatReturnsFalse; + return this; +} +Object.assign(SyntheticEvent.prototype, { + preventDefault: function() { + this.defaultPrevented = !0; + var event = this.nativeEvent; + event && + (event.preventDefault + ? event.preventDefault() + : "unknown" !== typeof event.returnValue && (event.returnValue = !1), + (this.isDefaultPrevented = functionThatReturnsTrue)); + }, + stopPropagation: function() { + var event = this.nativeEvent; + event && + (event.stopPropagation + ? event.stopPropagation() + : "unknown" !== typeof event.cancelBubble && (event.cancelBubble = !0), + (this.isPropagationStopped = functionThatReturnsTrue)); + }, + persist: function() { + this.isPersistent = functionThatReturnsTrue; + }, + isPersistent: functionThatReturnsFalse, + destructor: function() { + var Interface = this.constructor.Interface, + propName; + for (propName in Interface) this[propName] = null; + this.nativeEvent = this._targetInst = this.dispatchConfig = null; + this.isPropagationStopped = this.isDefaultPrevented = functionThatReturnsFalse; + this._dispatchInstances = this._dispatchListeners = null; + } +}); +SyntheticEvent.Interface = { + type: null, + target: null, + currentTarget: function() { + return null; + }, + eventPhase: null, + bubbles: null, + cancelable: null, + timeStamp: function(event) { + return event.timeStamp || Date.now(); + }, + defaultPrevented: null, + isTrusted: null +}; +SyntheticEvent.extend = function(Interface) { + function E() {} + function Class() { + return Super.apply(this, arguments); + } + var Super = this; + E.prototype = Super.prototype; + var prototype = new E(); + Object.assign(prototype, Class.prototype); + Class.prototype = prototype; + Class.prototype.constructor = Class; + Class.Interface = Object.assign({}, Super.Interface, Interface); + Class.extend = Super.extend; + addEventPoolingTo(Class); + return Class; +}; +addEventPoolingTo(SyntheticEvent); +function getPooledEvent(dispatchConfig, targetInst, nativeEvent, nativeInst) { + if (this.eventPool.length) { + var instance = this.eventPool.pop(); + this.call(instance, dispatchConfig, targetInst, nativeEvent, nativeInst); + return instance; + } + return new this(dispatchConfig, targetInst, nativeEvent, nativeInst); +} +function releasePooledEvent(event) { + if (!(event instanceof this)) + throw ReactError( + "Trying to release an event instance into a pool of a different type." + ); + event.destructor(); + 10 > this.eventPool.length && this.eventPool.push(event); +} +function addEventPoolingTo(EventConstructor) { + EventConstructor.eventPool = []; + EventConstructor.getPooled = getPooledEvent; + EventConstructor.release = releasePooledEvent; +} +var ResponderSyntheticEvent = SyntheticEvent.extend({ + touchHistory: function() { + return null; + } +}); +function isStartish(topLevelType) { + return "topTouchStart" === topLevelType; +} +function isMoveish(topLevelType) { + return "topTouchMove" === topLevelType; +} +var startDependencies = ["topTouchStart"], + moveDependencies = ["topTouchMove"], + endDependencies = ["topTouchCancel", "topTouchEnd"], + touchBank = [], + touchHistory = { + touchBank: touchBank, + numberActiveTouches: 0, + indexOfSingleActiveTouch: -1, + mostRecentTimeStamp: 0 + }; +function timestampForTouch(touch) { + return touch.timeStamp || touch.timestamp; +} +function getTouchIdentifier(_ref) { + _ref = _ref.identifier; + if (null == _ref) throw ReactError("Touch object is missing identifier."); + return _ref; +} +function recordTouchStart(touch) { + var identifier = getTouchIdentifier(touch), + touchRecord = touchBank[identifier]; + touchRecord + ? ((touchRecord.touchActive = !0), + (touchRecord.startPageX = touch.pageX), + (touchRecord.startPageY = touch.pageY), + (touchRecord.startTimeStamp = timestampForTouch(touch)), + (touchRecord.currentPageX = touch.pageX), + (touchRecord.currentPageY = touch.pageY), + (touchRecord.currentTimeStamp = timestampForTouch(touch)), + (touchRecord.previousPageX = touch.pageX), + (touchRecord.previousPageY = touch.pageY), + (touchRecord.previousTimeStamp = timestampForTouch(touch))) + : ((touchRecord = { + touchActive: !0, + startPageX: touch.pageX, + startPageY: touch.pageY, + startTimeStamp: timestampForTouch(touch), + currentPageX: touch.pageX, + currentPageY: touch.pageY, + currentTimeStamp: timestampForTouch(touch), + previousPageX: touch.pageX, + previousPageY: touch.pageY, + previousTimeStamp: timestampForTouch(touch) + }), + (touchBank[identifier] = touchRecord)); + touchHistory.mostRecentTimeStamp = timestampForTouch(touch); +} +function recordTouchMove(touch) { + var touchRecord = touchBank[getTouchIdentifier(touch)]; + touchRecord + ? ((touchRecord.touchActive = !0), + (touchRecord.previousPageX = touchRecord.currentPageX), + (touchRecord.previousPageY = touchRecord.currentPageY), + (touchRecord.previousTimeStamp = touchRecord.currentTimeStamp), + (touchRecord.currentPageX = touch.pageX), + (touchRecord.currentPageY = touch.pageY), + (touchRecord.currentTimeStamp = timestampForTouch(touch)), + (touchHistory.mostRecentTimeStamp = timestampForTouch(touch))) + : console.error( + "Cannot record touch move without a touch start.\nTouch Move: %s\n", + "Touch Bank: %s", + printTouch(touch), + printTouchBank() + ); +} +function recordTouchEnd(touch) { + var touchRecord = touchBank[getTouchIdentifier(touch)]; + touchRecord + ? ((touchRecord.touchActive = !1), + (touchRecord.previousPageX = touchRecord.currentPageX), + (touchRecord.previousPageY = touchRecord.currentPageY), + (touchRecord.previousTimeStamp = touchRecord.currentTimeStamp), + (touchRecord.currentPageX = touch.pageX), + (touchRecord.currentPageY = touch.pageY), + (touchRecord.currentTimeStamp = timestampForTouch(touch)), + (touchHistory.mostRecentTimeStamp = timestampForTouch(touch))) + : console.error( + "Cannot record touch end without a touch start.\nTouch End: %s\n", + "Touch Bank: %s", + printTouch(touch), + printTouchBank() + ); +} +function printTouch(touch) { + return JSON.stringify({ + identifier: touch.identifier, + pageX: touch.pageX, + pageY: touch.pageY, + timestamp: timestampForTouch(touch) + }); +} +function printTouchBank() { + var printed = JSON.stringify(touchBank.slice(0, 20)); + 20 < touchBank.length && + (printed += " (original size: " + touchBank.length + ")"); + return printed; +} +var ResponderTouchHistoryStore = { + recordTouchTrack: function(topLevelType, nativeEvent) { + if (isMoveish(topLevelType)) + nativeEvent.changedTouches.forEach(recordTouchMove); + else if (isStartish(topLevelType)) + nativeEvent.changedTouches.forEach(recordTouchStart), + (touchHistory.numberActiveTouches = nativeEvent.touches.length), + 1 === touchHistory.numberActiveTouches && + (touchHistory.indexOfSingleActiveTouch = + nativeEvent.touches[0].identifier); + else if ( + "topTouchEnd" === topLevelType || + "topTouchCancel" === topLevelType + ) + if ( + (nativeEvent.changedTouches.forEach(recordTouchEnd), + (touchHistory.numberActiveTouches = nativeEvent.touches.length), + 1 === touchHistory.numberActiveTouches) + ) + for (topLevelType = 0; topLevelType < touchBank.length; topLevelType++) + if ( + ((nativeEvent = touchBank[topLevelType]), + null != nativeEvent && nativeEvent.touchActive) + ) { + touchHistory.indexOfSingleActiveTouch = topLevelType; + break; + } + }, + touchHistory: touchHistory +}; +function accumulate(current, next) { + if (null == next) + throw ReactError( + "accumulate(...): Accumulated items must not be null or undefined." + ); + return null == current + ? next + : Array.isArray(current) + ? current.concat(next) + : Array.isArray(next) + ? [current].concat(next) + : [current, next]; +} +var responderInst = null, + trackedTouchCount = 0; +function changeResponder(nextResponderInst, blockHostResponder) { + var oldResponderInst = responderInst; + responderInst = nextResponderInst; + if (null !== ResponderEventPlugin.GlobalResponderHandler) + ResponderEventPlugin.GlobalResponderHandler.onChange( + oldResponderInst, + nextResponderInst, + blockHostResponder + ); +} +var eventTypes = { + startShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onStartShouldSetResponder", + captured: "onStartShouldSetResponderCapture" + }, + dependencies: startDependencies + }, + scrollShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onScrollShouldSetResponder", + captured: "onScrollShouldSetResponderCapture" + }, + dependencies: ["topScroll"] + }, + selectionChangeShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onSelectionChangeShouldSetResponder", + captured: "onSelectionChangeShouldSetResponderCapture" + }, + dependencies: ["topSelectionChange"] + }, + moveShouldSetResponder: { + phasedRegistrationNames: { + bubbled: "onMoveShouldSetResponder", + captured: "onMoveShouldSetResponderCapture" + }, + dependencies: moveDependencies + }, + responderStart: { + registrationName: "onResponderStart", + dependencies: startDependencies + }, + responderMove: { + registrationName: "onResponderMove", + dependencies: moveDependencies + }, + responderEnd: { + registrationName: "onResponderEnd", + dependencies: endDependencies + }, + responderRelease: { + registrationName: "onResponderRelease", + dependencies: endDependencies + }, + responderTerminationRequest: { + registrationName: "onResponderTerminationRequest", + dependencies: [] + }, + responderGrant: { registrationName: "onResponderGrant", dependencies: [] }, + responderReject: { + registrationName: "onResponderReject", + dependencies: [] + }, + responderTerminate: { + registrationName: "onResponderTerminate", + dependencies: [] + } + }, + ResponderEventPlugin = { + _getResponder: function() { + return responderInst; + }, + eventTypes: eventTypes, + extractEvents: function( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ) { + if (isStartish(topLevelType)) trackedTouchCount += 1; + else if ( + "topTouchEnd" === topLevelType || + "topTouchCancel" === topLevelType + ) + if (0 <= trackedTouchCount) --trackedTouchCount; + else + return ( + console.error( + "Ended a touch event which was not counted in `trackedTouchCount`." + ), + null + ); + ResponderTouchHistoryStore.recordTouchTrack(topLevelType, nativeEvent); + if ( + targetInst && + (("topScroll" === topLevelType && !nativeEvent.responderIgnoreScroll) || + (0 < trackedTouchCount && "topSelectionChange" === topLevelType) || + isStartish(topLevelType) || + isMoveish(topLevelType)) + ) { + var JSCompiler_temp = isStartish(topLevelType) + ? eventTypes.startShouldSetResponder + : isMoveish(topLevelType) + ? eventTypes.moveShouldSetResponder + : "topSelectionChange" === topLevelType + ? eventTypes.selectionChangeShouldSetResponder + : eventTypes.scrollShouldSetResponder; + if (responderInst) + b: { + var JSCompiler_temp$jscomp$0 = responderInst; + for ( + var depthA = 0, tempA = JSCompiler_temp$jscomp$0; + tempA; + tempA = getParent(tempA) + ) + depthA++; + tempA = 0; + for (var tempB = targetInst; tempB; tempB = getParent(tempB)) + tempA++; + for (; 0 < depthA - tempA; ) + (JSCompiler_temp$jscomp$0 = getParent(JSCompiler_temp$jscomp$0)), + depthA--; + for (; 0 < tempA - depthA; ) + (targetInst = getParent(targetInst)), tempA--; + for (; depthA--; ) { + if ( + JSCompiler_temp$jscomp$0 === targetInst || + JSCompiler_temp$jscomp$0 === targetInst.alternate + ) + break b; + JSCompiler_temp$jscomp$0 = getParent(JSCompiler_temp$jscomp$0); + targetInst = getParent(targetInst); + } + JSCompiler_temp$jscomp$0 = null; + } + else JSCompiler_temp$jscomp$0 = targetInst; + targetInst = JSCompiler_temp$jscomp$0 === responderInst; + JSCompiler_temp$jscomp$0 = ResponderSyntheticEvent.getPooled( + JSCompiler_temp, + JSCompiler_temp$jscomp$0, + nativeEvent, + nativeEventTarget + ); + JSCompiler_temp$jscomp$0.touchHistory = + ResponderTouchHistoryStore.touchHistory; + targetInst + ? forEachAccumulated( + JSCompiler_temp$jscomp$0, + accumulateTwoPhaseDispatchesSingleSkipTarget + ) + : forEachAccumulated( + JSCompiler_temp$jscomp$0, + accumulateTwoPhaseDispatchesSingle + ); + b: { + JSCompiler_temp = JSCompiler_temp$jscomp$0._dispatchListeners; + targetInst = JSCompiler_temp$jscomp$0._dispatchInstances; + if (Array.isArray(JSCompiler_temp)) + for ( + depthA = 0; + depthA < JSCompiler_temp.length && + !JSCompiler_temp$jscomp$0.isPropagationStopped(); + depthA++ + ) { + if ( + JSCompiler_temp[depthA]( + JSCompiler_temp$jscomp$0, + targetInst[depthA] + ) + ) { + JSCompiler_temp = targetInst[depthA]; + break b; + } + } + else if ( + JSCompiler_temp && + JSCompiler_temp(JSCompiler_temp$jscomp$0, targetInst) + ) { + JSCompiler_temp = targetInst; + break b; + } + JSCompiler_temp = null; + } + JSCompiler_temp$jscomp$0._dispatchInstances = null; + JSCompiler_temp$jscomp$0._dispatchListeners = null; + JSCompiler_temp$jscomp$0.isPersistent() || + JSCompiler_temp$jscomp$0.constructor.release( + JSCompiler_temp$jscomp$0 + ); + JSCompiler_temp && JSCompiler_temp !== responderInst + ? ((JSCompiler_temp$jscomp$0 = void 0), + (targetInst = ResponderSyntheticEvent.getPooled( + eventTypes.responderGrant, + JSCompiler_temp, + nativeEvent, + nativeEventTarget + )), + (targetInst.touchHistory = ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(targetInst, accumulateDirectDispatchesSingle), + (depthA = !0 === executeDirectDispatch(targetInst)), + responderInst + ? ((tempA = ResponderSyntheticEvent.getPooled( + eventTypes.responderTerminationRequest, + responderInst, + nativeEvent, + nativeEventTarget + )), + (tempA.touchHistory = ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(tempA, accumulateDirectDispatchesSingle), + (tempB = + !tempA._dispatchListeners || executeDirectDispatch(tempA)), + tempA.isPersistent() || tempA.constructor.release(tempA), + tempB + ? ((tempA = ResponderSyntheticEvent.getPooled( + eventTypes.responderTerminate, + responderInst, + nativeEvent, + nativeEventTarget + )), + (tempA.touchHistory = + ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(tempA, accumulateDirectDispatchesSingle), + (JSCompiler_temp$jscomp$0 = accumulate( + JSCompiler_temp$jscomp$0, + [targetInst, tempA] + )), + changeResponder(JSCompiler_temp, depthA)) + : ((JSCompiler_temp = ResponderSyntheticEvent.getPooled( + eventTypes.responderReject, + JSCompiler_temp, + nativeEvent, + nativeEventTarget + )), + (JSCompiler_temp.touchHistory = + ResponderTouchHistoryStore.touchHistory), + forEachAccumulated( + JSCompiler_temp, + accumulateDirectDispatchesSingle + ), + (JSCompiler_temp$jscomp$0 = accumulate( + JSCompiler_temp$jscomp$0, + JSCompiler_temp + )))) + : ((JSCompiler_temp$jscomp$0 = accumulate( + JSCompiler_temp$jscomp$0, + targetInst + )), + changeResponder(JSCompiler_temp, depthA)), + (JSCompiler_temp = JSCompiler_temp$jscomp$0)) + : (JSCompiler_temp = null); + } else JSCompiler_temp = null; + JSCompiler_temp$jscomp$0 = responderInst && isStartish(topLevelType); + targetInst = responderInst && isMoveish(topLevelType); + depthA = + responderInst && + ("topTouchEnd" === topLevelType || "topTouchCancel" === topLevelType); + if ( + (JSCompiler_temp$jscomp$0 = JSCompiler_temp$jscomp$0 + ? eventTypes.responderStart + : targetInst + ? eventTypes.responderMove + : depthA + ? eventTypes.responderEnd + : null) + ) + (JSCompiler_temp$jscomp$0 = ResponderSyntheticEvent.getPooled( + JSCompiler_temp$jscomp$0, + responderInst, + nativeEvent, + nativeEventTarget + )), + (JSCompiler_temp$jscomp$0.touchHistory = + ResponderTouchHistoryStore.touchHistory), + forEachAccumulated( + JSCompiler_temp$jscomp$0, + accumulateDirectDispatchesSingle + ), + (JSCompiler_temp = accumulate( + JSCompiler_temp, + JSCompiler_temp$jscomp$0 + )); + JSCompiler_temp$jscomp$0 = + responderInst && "topTouchCancel" === topLevelType; + if ( + (topLevelType = + responderInst && + !JSCompiler_temp$jscomp$0 && + ("topTouchEnd" === topLevelType || "topTouchCancel" === topLevelType)) + ) + a: { + if ((topLevelType = nativeEvent.touches) && 0 !== topLevelType.length) + for (targetInst = 0; targetInst < topLevelType.length; targetInst++) + if ( + ((depthA = topLevelType[targetInst].target), + null !== depthA && void 0 !== depthA && 0 !== depthA) + ) { + tempA = getInstanceFromNode(depthA); + b: { + for (depthA = responderInst; tempA; ) { + if (depthA === tempA || depthA === tempA.alternate) { + depthA = !0; + break b; + } + tempA = getParent(tempA); + } + depthA = !1; + } + if (depthA) { + topLevelType = !1; + break a; + } + } + topLevelType = !0; + } + if ( + (topLevelType = JSCompiler_temp$jscomp$0 + ? eventTypes.responderTerminate + : topLevelType + ? eventTypes.responderRelease + : null) + ) + (nativeEvent = ResponderSyntheticEvent.getPooled( + topLevelType, + responderInst, + nativeEvent, + nativeEventTarget + )), + (nativeEvent.touchHistory = ResponderTouchHistoryStore.touchHistory), + forEachAccumulated(nativeEvent, accumulateDirectDispatchesSingle), + (JSCompiler_temp = accumulate(JSCompiler_temp, nativeEvent)), + changeResponder(null); + return JSCompiler_temp; + }, + GlobalResponderHandler: null, + injection: { + injectGlobalResponderHandler: function(GlobalResponderHandler) { + ResponderEventPlugin.GlobalResponderHandler = GlobalResponderHandler; + } + } + }, + customBubblingEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customBubblingEventTypes, + customDirectEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customDirectEventTypes, + ReactNativeBridgeEventPlugin = { + eventTypes: + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes, + extractEvents: function( + topLevelType, + targetInst, + nativeEvent, + nativeEventTarget + ) { + if (null == targetInst) return null; + var bubbleDispatchConfig = customBubblingEventTypes[topLevelType], + directDispatchConfig = customDirectEventTypes[topLevelType]; + if (!bubbleDispatchConfig && !directDispatchConfig) + throw ReactError( + 'Unsupported top level event type "' + topLevelType + '" dispatched' + ); + topLevelType = SyntheticEvent.getPooled( + bubbleDispatchConfig || directDispatchConfig, + targetInst, + nativeEvent, + nativeEventTarget + ); + if (bubbleDispatchConfig) + forEachAccumulated(topLevelType, accumulateTwoPhaseDispatchesSingle); + else if (directDispatchConfig) + forEachAccumulated(topLevelType, accumulateDirectDispatchesSingle); + else return null; + return topLevelType; + } + }; +injection.injectEventPluginOrder([ + "ResponderEventPlugin", + "ReactNativeBridgeEventPlugin" +]); +injection.injectEventPluginsByName({ + ResponderEventPlugin: ResponderEventPlugin, + ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin +}); +var instanceCache = {}, + instanceProps = {}; +function getInstanceFromTag(tag) { + return instanceCache[tag] || null; +} +var restoreTarget = null, + restoreQueue = null; +function restoreStateOfTarget(target) { + if (getInstanceFromNode(target)) + throw ReactError( + "setRestoreImplementation() needs to be called to handle a target for controlled events. This error is likely caused by a bug in React. Please file an issue." + ); +} +function _batchedUpdatesImpl(fn, bookkeeping) { + return fn(bookkeeping); +} +function _flushInteractiveUpdatesImpl() {} +var isBatching = !1; +function batchedUpdates(fn, bookkeeping) { + if (isBatching) return fn(bookkeeping); + isBatching = !0; + try { + return _batchedUpdatesImpl(fn, bookkeeping); + } finally { + if (((isBatching = !1), null !== restoreTarget || null !== restoreQueue)) + if ( + (_flushInteractiveUpdatesImpl(), + restoreTarget && + ((bookkeeping = restoreTarget), + (fn = restoreQueue), + (restoreQueue = restoreTarget = null), + restoreStateOfTarget(bookkeeping), + fn)) + ) + for (bookkeeping = 0; bookkeeping < fn.length; bookkeeping++) + restoreStateOfTarget(fn[bookkeeping]); + } +} +var EMPTY_NATIVE_EVENT = {}; +function _receiveRootNodeIDEvent(rootNodeID, topLevelType, nativeEventParam) { + var nativeEvent = nativeEventParam || EMPTY_NATIVE_EVENT, + inst = getInstanceFromTag(rootNodeID); + batchedUpdates(function() { + var events = nativeEvent.target; + for (var events$jscomp$0 = null, i = 0; i < plugins.length; i++) { + var possiblePlugin = plugins[i]; + possiblePlugin && + (possiblePlugin = possiblePlugin.extractEvents( + topLevelType, + inst, + nativeEvent, + events + )) && + (events$jscomp$0 = accumulateInto(events$jscomp$0, possiblePlugin)); + } + events = events$jscomp$0; + null !== events && (eventQueue = accumulateInto(eventQueue, events)); + events = eventQueue; + eventQueue = null; + if (events) { + forEachAccumulated(events, executeDispatchesAndReleaseTopLevel); + if (eventQueue) + throw ReactError( + "processEventQueue(): Additional events were enqueued while processing an event queue. Support for this has not yet been implemented." + ); + if (hasRethrowError) + throw ((events = rethrowError), + (hasRethrowError = !1), + (rethrowError = null), + events); + } + }); +} +ReactNativePrivateInterface.RCTEventEmitter.register({ + receiveEvent: function(rootNodeID, topLevelType, nativeEventParam) { + _receiveRootNodeIDEvent(rootNodeID, topLevelType, nativeEventParam); + }, + receiveTouches: function(eventTopLevelType, touches, changedIndices) { + if ( + "topTouchEnd" === eventTopLevelType || + "topTouchCancel" === eventTopLevelType + ) { + var JSCompiler_temp = []; + for (var i = 0; i < changedIndices.length; i++) { + var index = changedIndices[i]; + JSCompiler_temp.push(touches[index]); + touches[index] = null; + } + for (i = changedIndices = 0; i < touches.length; i++) + (index = touches[i]), + null !== index && (touches[changedIndices++] = index); + touches.length = changedIndices; + } else + for (JSCompiler_temp = [], i = 0; i < changedIndices.length; i++) + JSCompiler_temp.push(touches[changedIndices[i]]); + for ( + changedIndices = 0; + changedIndices < JSCompiler_temp.length; + changedIndices++ + ) { + i = JSCompiler_temp[changedIndices]; + i.changedTouches = JSCompiler_temp; + i.touches = touches; + index = null; + var target = i.target; + null === target || void 0 === target || 1 > target || (index = target); + _receiveRootNodeIDEvent(index, eventTopLevelType, i); + } + } +}); +getFiberCurrentPropsFromNode = function(stateNode) { + return instanceProps[stateNode._nativeTag] || null; +}; +getInstanceFromNode = getInstanceFromTag; +getNodeFromInstance = function(inst) { + var tag = inst.stateNode._nativeTag; + void 0 === tag && (tag = inst.stateNode.canonical._nativeTag); + if (!tag) throw ReactError("All native instances should have a tag."); + return tag; +}; +ResponderEventPlugin.injection.injectGlobalResponderHandler({ + onChange: function(from, to, blockNativeResponder) { + null !== to + ? ReactNativePrivateInterface.UIManager.setJSResponder( + to.stateNode._nativeTag, + blockNativeResponder + ) + : ReactNativePrivateInterface.UIManager.clearJSResponder(); + } +}); +var ReactSharedInternals = + React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; +ReactSharedInternals.hasOwnProperty("ReactCurrentDispatcher") || + (ReactSharedInternals.ReactCurrentDispatcher = { current: null }); +var hasSymbol = "function" === typeof Symbol && Symbol.for, + REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for("react.element") : 60103, + REACT_PORTAL_TYPE = hasSymbol ? Symbol.for("react.portal") : 60106, + REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for("react.fragment") : 60107, + REACT_STRICT_MODE_TYPE = hasSymbol ? Symbol.for("react.strict_mode") : 60108, + REACT_PROFILER_TYPE = hasSymbol ? Symbol.for("react.profiler") : 60114, + REACT_PROVIDER_TYPE = hasSymbol ? Symbol.for("react.provider") : 60109, + REACT_CONTEXT_TYPE = hasSymbol ? Symbol.for("react.context") : 60110, + REACT_CONCURRENT_MODE_TYPE = hasSymbol + ? Symbol.for("react.concurrent_mode") + : 60111, + REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for("react.forward_ref") : 60112, + REACT_SUSPENSE_TYPE = hasSymbol ? Symbol.for("react.suspense") : 60113, + REACT_MEMO_TYPE = hasSymbol ? Symbol.for("react.memo") : 60115, + REACT_LAZY_TYPE = hasSymbol ? Symbol.for("react.lazy") : 60116; +hasSymbol && Symbol.for("react.event_component"); +hasSymbol && Symbol.for("react.event_target"); +hasSymbol && Symbol.for("react.event_target.touch_hit"); +var MAYBE_ITERATOR_SYMBOL = "function" === typeof Symbol && Symbol.iterator; +function getIteratorFn(maybeIterable) { + if (null === maybeIterable || "object" !== typeof maybeIterable) return null; + maybeIterable = + (MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL]) || + maybeIterable["@@iterator"]; + return "function" === typeof maybeIterable ? maybeIterable : null; +} +require("../shims/ReactFeatureFlags"); +function getComponentName(type) { + if (null == type) return null; + if ("function" === typeof type) return type.displayName || type.name || null; + if ("string" === typeof type) return type; + switch (type) { + case REACT_CONCURRENT_MODE_TYPE: + return "ConcurrentMode"; + case REACT_FRAGMENT_TYPE: + return "Fragment"; + case REACT_PORTAL_TYPE: + return "Portal"; + case REACT_PROFILER_TYPE: + return "Profiler"; + case REACT_STRICT_MODE_TYPE: + return "StrictMode"; + case REACT_SUSPENSE_TYPE: + return "Suspense"; + } + if ("object" === typeof type) + switch (type.$$typeof) { + case REACT_CONTEXT_TYPE: + return "Context.Consumer"; + case REACT_PROVIDER_TYPE: + return "Context.Provider"; + case REACT_FORWARD_REF_TYPE: + var innerType = type.render; + innerType = innerType.displayName || innerType.name || ""; + return ( + type.displayName || + ("" !== innerType ? "ForwardRef(" + innerType + ")" : "ForwardRef") + ); + case REACT_MEMO_TYPE: + return getComponentName(type.type); + case REACT_LAZY_TYPE: + if ((type = 1 === type._status ? type._result : null)) + return getComponentName(type); + } + return null; +} +function isFiberMountedImpl(fiber) { + var node = fiber; + if (fiber.alternate) for (; node.return; ) node = node.return; + else { + if (0 !== (node.effectTag & 2)) return 1; + for (; node.return; ) + if (((node = node.return), 0 !== (node.effectTag & 2))) return 1; + } + return 3 === node.tag ? 2 : 3; +} +function assertIsMounted(fiber) { + if (2 !== isFiberMountedImpl(fiber)) + throw ReactError("Unable to find node on an unmounted component."); +} +function findCurrentFiberUsingSlowPath(fiber) { + var alternate = fiber.alternate; + if (!alternate) { + alternate = isFiberMountedImpl(fiber); + if (3 === alternate) + throw ReactError("Unable to find node on an unmounted component."); + return 1 === alternate ? null : fiber; + } + for (var a = fiber, b = alternate; ; ) { + var parentA = a.return; + if (null === parentA) break; + var parentB = parentA.alternate; + if (null === parentB) { + b = parentA.return; + if (null !== b) { + a = b; + continue; + } + break; + } + if (parentA.child === parentB.child) { + for (parentB = parentA.child; parentB; ) { + if (parentB === a) return assertIsMounted(parentA), fiber; + if (parentB === b) return assertIsMounted(parentA), alternate; + parentB = parentB.sibling; + } + throw ReactError("Unable to find node on an unmounted component."); + } + if (a.return !== b.return) (a = parentA), (b = parentB); + else { + for (var didFindChild = !1, _child = parentA.child; _child; ) { + if (_child === a) { + didFindChild = !0; + a = parentA; + b = parentB; + break; + } + if (_child === b) { + didFindChild = !0; + b = parentA; + a = parentB; + break; + } + _child = _child.sibling; + } + if (!didFindChild) { + for (_child = parentB.child; _child; ) { + if (_child === a) { + didFindChild = !0; + a = parentB; + b = parentA; + break; + } + if (_child === b) { + didFindChild = !0; + b = parentB; + a = parentA; + break; + } + _child = _child.sibling; + } + if (!didFindChild) + throw ReactError( + "Child was not found in either parent set. This indicates a bug in React related to the return pointer. Please file an issue." + ); + } + } + if (a.alternate !== b) + throw ReactError( + "Return fibers should always be each others' alternates. This error is likely caused by a bug in React. Please file an issue." + ); + } + if (3 !== a.tag) + throw ReactError("Unable to find node on an unmounted component."); + return a.stateNode.current === a ? fiber : alternate; +} +function findCurrentHostFiber(parent) { + parent = findCurrentFiberUsingSlowPath(parent); + if (!parent) return null; + for (var node = parent; ; ) { + if (5 === node.tag || 6 === node.tag) return node; + if (node.child) (node.child.return = node), (node = node.child); + else { + if (node === parent) break; + for (; !node.sibling; ) { + if (!node.return || node.return === parent) return null; + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + } + return null; +} +var emptyObject = {}, + removedKeys = null, + removedKeyCount = 0; +function restoreDeletedValuesInNestedArray( + updatePayload, + node, + validAttributes +) { + if (Array.isArray(node)) + for (var i = node.length; i-- && 0 < removedKeyCount; ) + restoreDeletedValuesInNestedArray( + updatePayload, + node[i], + validAttributes + ); + else if (node && 0 < removedKeyCount) + for (i in removedKeys) + if (removedKeys[i]) { + var nextProp = node[i]; + if (void 0 !== nextProp) { + var attributeConfig = validAttributes[i]; + if (attributeConfig) { + "function" === typeof nextProp && (nextProp = !0); + "undefined" === typeof nextProp && (nextProp = null); + if ("object" !== typeof attributeConfig) + updatePayload[i] = nextProp; + else if ( + "function" === typeof attributeConfig.diff || + "function" === typeof attributeConfig.process + ) + (nextProp = + "function" === typeof attributeConfig.process + ? attributeConfig.process(nextProp) + : nextProp), + (updatePayload[i] = nextProp); + removedKeys[i] = !1; + removedKeyCount--; + } + } + } +} +function diffNestedProperty( + updatePayload, + prevProp, + nextProp, + validAttributes +) { + if (!updatePayload && prevProp === nextProp) return updatePayload; + if (!prevProp || !nextProp) + return nextProp + ? addNestedProperty(updatePayload, nextProp, validAttributes) + : prevProp + ? clearNestedProperty(updatePayload, prevProp, validAttributes) + : updatePayload; + if (!Array.isArray(prevProp) && !Array.isArray(nextProp)) + return diffProperties(updatePayload, prevProp, nextProp, validAttributes); + if (Array.isArray(prevProp) && Array.isArray(nextProp)) { + var minLength = + prevProp.length < nextProp.length ? prevProp.length : nextProp.length, + i; + for (i = 0; i < minLength; i++) + updatePayload = diffNestedProperty( + updatePayload, + prevProp[i], + nextProp[i], + validAttributes + ); + for (; i < prevProp.length; i++) + updatePayload = clearNestedProperty( + updatePayload, + prevProp[i], + validAttributes + ); + for (; i < nextProp.length; i++) + updatePayload = addNestedProperty( + updatePayload, + nextProp[i], + validAttributes + ); + return updatePayload; + } + return Array.isArray(prevProp) + ? diffProperties( + updatePayload, + ReactNativePrivateInterface.flattenStyle(prevProp), + nextProp, + validAttributes + ) + : diffProperties( + updatePayload, + prevProp, + ReactNativePrivateInterface.flattenStyle(nextProp), + validAttributes + ); +} +function addNestedProperty(updatePayload, nextProp, validAttributes) { + if (!nextProp) return updatePayload; + if (!Array.isArray(nextProp)) + return diffProperties( + updatePayload, + emptyObject, + nextProp, + validAttributes + ); + for (var i = 0; i < nextProp.length; i++) + updatePayload = addNestedProperty( + updatePayload, + nextProp[i], + validAttributes + ); + return updatePayload; +} +function clearNestedProperty(updatePayload, prevProp, validAttributes) { + if (!prevProp) return updatePayload; + if (!Array.isArray(prevProp)) + return diffProperties( + updatePayload, + prevProp, + emptyObject, + validAttributes + ); + for (var i = 0; i < prevProp.length; i++) + updatePayload = clearNestedProperty( + updatePayload, + prevProp[i], + validAttributes + ); + return updatePayload; +} +function diffProperties(updatePayload, prevProps, nextProps, validAttributes) { + var attributeConfig, propKey; + for (propKey in nextProps) + if ((attributeConfig = validAttributes[propKey])) { + var prevProp = prevProps[propKey]; + var nextProp = nextProps[propKey]; + "function" === typeof nextProp && + ((nextProp = !0), "function" === typeof prevProp && (prevProp = !0)); + "undefined" === typeof nextProp && + ((nextProp = null), + "undefined" === typeof prevProp && (prevProp = null)); + removedKeys && (removedKeys[propKey] = !1); + if (updatePayload && void 0 !== updatePayload[propKey]) + if ("object" !== typeof attributeConfig) + updatePayload[propKey] = nextProp; + else { + if ( + "function" === typeof attributeConfig.diff || + "function" === typeof attributeConfig.process + ) + (attributeConfig = + "function" === typeof attributeConfig.process + ? attributeConfig.process(nextProp) + : nextProp), + (updatePayload[propKey] = attributeConfig); + } + else if (prevProp !== nextProp) + if ("object" !== typeof attributeConfig) + ("object" !== typeof nextProp || + null === nextProp || + ReactNativePrivateInterface.deepDiffer(prevProp, nextProp)) && + ((updatePayload || (updatePayload = {}))[propKey] = nextProp); + else if ( + "function" === typeof attributeConfig.diff || + "function" === typeof attributeConfig.process + ) { + if ( + void 0 === prevProp || + ("function" === typeof attributeConfig.diff + ? attributeConfig.diff(prevProp, nextProp) + : "object" !== typeof nextProp || + null === nextProp || + ReactNativePrivateInterface.deepDiffer(prevProp, nextProp)) + ) + (attributeConfig = + "function" === typeof attributeConfig.process + ? attributeConfig.process(nextProp) + : nextProp), + ((updatePayload || (updatePayload = {}))[ + propKey + ] = attributeConfig); + } else + (removedKeys = null), + (removedKeyCount = 0), + (updatePayload = diffNestedProperty( + updatePayload, + prevProp, + nextProp, + attributeConfig + )), + 0 < removedKeyCount && + updatePayload && + (restoreDeletedValuesInNestedArray( + updatePayload, + nextProp, + attributeConfig + ), + (removedKeys = null)); + } + for (var _propKey in prevProps) + void 0 === nextProps[_propKey] && + (!(attributeConfig = validAttributes[_propKey]) || + (updatePayload && void 0 !== updatePayload[_propKey]) || + ((prevProp = prevProps[_propKey]), + void 0 !== prevProp && + ("object" !== typeof attributeConfig || + "function" === typeof attributeConfig.diff || + "function" === typeof attributeConfig.process + ? (((updatePayload || (updatePayload = {}))[_propKey] = null), + removedKeys || (removedKeys = {}), + removedKeys[_propKey] || + ((removedKeys[_propKey] = !0), removedKeyCount++)) + : (updatePayload = clearNestedProperty( + updatePayload, + prevProp, + attributeConfig + ))))); + return updatePayload; +} +function mountSafeCallback_NOT_REALLY_SAFE(context, callback) { + return function() { + if ( + callback && + ("boolean" !== typeof context.__isMounted || context.__isMounted) + ) + return callback.apply(context, arguments); + }; +} +var ReactNativeFiberHostComponent = (function() { + function ReactNativeFiberHostComponent(tag, viewConfig) { + if (!(this instanceof ReactNativeFiberHostComponent)) + throw new TypeError("Cannot call a class as a function"); + this._nativeTag = tag; + this._children = []; + this.viewConfig = viewConfig; + } + ReactNativeFiberHostComponent.prototype.blur = function() { + ReactNativePrivateInterface.TextInputState.blurTextInput(this._nativeTag); + }; + ReactNativeFiberHostComponent.prototype.focus = function() { + ReactNativePrivateInterface.TextInputState.focusTextInput(this._nativeTag); + }; + ReactNativeFiberHostComponent.prototype.measure = function(callback) { + ReactNativePrivateInterface.UIManager.measure( + this._nativeTag, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + }; + ReactNativeFiberHostComponent.prototype.measureInWindow = function(callback) { + ReactNativePrivateInterface.UIManager.measureInWindow( + this._nativeTag, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ); + }; + ReactNativeFiberHostComponent.prototype.measureLayout = function( + relativeToNativeNode, + onSuccess, + onFail + ) { + var relativeNode = void 0; + "number" === typeof relativeToNativeNode + ? (relativeNode = relativeToNativeNode) + : relativeToNativeNode._nativeTag + ? (relativeNode = relativeToNativeNode._nativeTag) + : relativeToNativeNode.canonical && + relativeToNativeNode.canonical._nativeTag && + (relativeNode = relativeToNativeNode.canonical._nativeTag); + null != relativeNode && + ReactNativePrivateInterface.UIManager.measureLayout( + this._nativeTag, + relativeNode, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + ); + }; + ReactNativeFiberHostComponent.prototype.setNativeProps = function( + nativeProps + ) { + nativeProps = diffProperties( + null, + emptyObject, + nativeProps, + this.viewConfig.validAttributes + ); + null != nativeProps && + ReactNativePrivateInterface.UIManager.updateView( + this._nativeTag, + this.viewConfig.uiViewClassName, + nativeProps + ); + }; + return ReactNativeFiberHostComponent; +})(); +function shim$1() { + throw ReactError( + "The current renderer does not support hydration. This error is likely caused by a bug in React. Please file an issue." + ); +} +var getViewConfigForType = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.get, + UPDATE_SIGNAL = {}, + nextReactTag = 3; +function allocateTag() { + var tag = nextReactTag; + 1 === tag % 10 && (tag += 2); + nextReactTag = tag + 2; + return tag; +} +function recursivelyUncacheFiberNode(node) { + if ("number" === typeof node) + delete instanceCache[node], delete instanceProps[node]; + else { + var tag = node._nativeTag; + delete instanceCache[tag]; + delete instanceProps[tag]; + node._children.forEach(recursivelyUncacheFiberNode); + } +} +function finalizeInitialChildren(parentInstance) { + if (0 === parentInstance._children.length) return !1; + var nativeTags = parentInstance._children.map(function(child) { + return "number" === typeof child ? child : child._nativeTag; + }); + ReactNativePrivateInterface.UIManager.setChildren( + parentInstance._nativeTag, + nativeTags + ); + return !1; +} +var scheduleTimeout = setTimeout, + cancelTimeout = clearTimeout, + BEFORE_SLASH_RE = /^(.*)[\\\/]/; +function getStackByFiberInDevAndProd(workInProgress) { + var info = ""; + do { + a: switch (workInProgress.tag) { + case 3: + case 4: + case 6: + case 7: + case 10: + case 9: + var JSCompiler_inline_result = ""; + break a; + default: + var owner = workInProgress._debugOwner, + source = workInProgress._debugSource, + name = getComponentName(workInProgress.type); + JSCompiler_inline_result = null; + owner && (JSCompiler_inline_result = getComponentName(owner.type)); + owner = name; + name = ""; + source + ? (name = + " (at " + + source.fileName.replace(BEFORE_SLASH_RE, "") + + ":" + + source.lineNumber + + ")") + : JSCompiler_inline_result && + (name = " (created by " + JSCompiler_inline_result + ")"); + JSCompiler_inline_result = "\n in " + (owner || "Unknown") + name; + } + info += JSCompiler_inline_result; + workInProgress = workInProgress.return; + } while (workInProgress); + return info; +} +new Set(); +var valueStack = [], + index = -1; +function pop(cursor) { + 0 > index || + ((cursor.current = valueStack[index]), (valueStack[index] = null), index--); +} +function push(cursor, value) { + index++; + valueStack[index] = cursor.current; + cursor.current = value; +} +var emptyContextObject = {}, + contextStackCursor = { current: emptyContextObject }, + didPerformWorkStackCursor = { current: !1 }, + previousContext = emptyContextObject; +function getMaskedContext(workInProgress, unmaskedContext) { + var contextTypes = workInProgress.type.contextTypes; + if (!contextTypes) return emptyContextObject; + var instance = workInProgress.stateNode; + if ( + instance && + instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext + ) + return instance.__reactInternalMemoizedMaskedChildContext; + var context = {}, + key; + for (key in contextTypes) context[key] = unmaskedContext[key]; + instance && + ((workInProgress = workInProgress.stateNode), + (workInProgress.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext), + (workInProgress.__reactInternalMemoizedMaskedChildContext = context)); + return context; +} +function isContextProvider(type) { + type = type.childContextTypes; + return null !== type && void 0 !== type; +} +function popContext(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); +} +function popTopLevelContextObject(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); +} +function pushTopLevelContextObject(fiber, context, didChange) { + if (contextStackCursor.current !== emptyContextObject) + throw ReactError( + "Unexpected context found on stack. This error is likely caused by a bug in React. Please file an issue." + ); + push(contextStackCursor, context, fiber); + push(didPerformWorkStackCursor, didChange, fiber); +} +function processChildContext(fiber, type, parentContext) { + var instance = fiber.stateNode; + fiber = type.childContextTypes; + if ("function" !== typeof instance.getChildContext) return parentContext; + instance = instance.getChildContext(); + for (var contextKey in instance) + if (!(contextKey in fiber)) + throw ReactError( + (getComponentName(type) || "Unknown") + + '.getChildContext(): key "' + + contextKey + + '" is not defined in childContextTypes.' + ); + return Object.assign({}, parentContext, instance); +} +function pushContextProvider(workInProgress) { + var instance = workInProgress.stateNode; + instance = + (instance && instance.__reactInternalMemoizedMergedChildContext) || + emptyContextObject; + previousContext = contextStackCursor.current; + push(contextStackCursor, instance, workInProgress); + push( + didPerformWorkStackCursor, + didPerformWorkStackCursor.current, + workInProgress + ); + return !0; +} +function invalidateContextProvider(workInProgress, type, didChange) { + var instance = workInProgress.stateNode; + if (!instance) + throw ReactError( + "Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue." + ); + didChange + ? ((type = processChildContext(workInProgress, type, previousContext)), + (instance.__reactInternalMemoizedMergedChildContext = type), + pop(didPerformWorkStackCursor, workInProgress), + pop(contextStackCursor, workInProgress), + push(contextStackCursor, type, workInProgress)) + : pop(didPerformWorkStackCursor, workInProgress); + push(didPerformWorkStackCursor, didChange, workInProgress); +} +var onCommitFiberRoot = null, + onCommitFiberUnmount = null; +function catchErrors(fn) { + return function(arg) { + try { + return fn(arg); + } catch (err) {} + }; +} +var isDevToolsPresent = "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__; +function injectInternals(internals) { + if ("undefined" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) return !1; + var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__; + if (hook.isDisabled || !hook.supportsFiber) return !0; + try { + var rendererID = hook.inject(internals); + onCommitFiberRoot = catchErrors(function(root) { + return hook.onCommitFiberRoot(rendererID, root); + }); + onCommitFiberUnmount = catchErrors(function(fiber) { + return hook.onCommitFiberUnmount(rendererID, fiber); + }); + } catch (err) {} + return !0; +} +var Scheduler_runWithPriority = Scheduler.unstable_runWithPriority, + Scheduler_scheduleCallback = Scheduler.unstable_scheduleCallback, + Scheduler_cancelCallback = Scheduler.unstable_cancelCallback, + Scheduler_shouldYield = Scheduler.unstable_shouldYield, + Scheduler_now = Scheduler.unstable_now, + Scheduler_getCurrentPriorityLevel = + Scheduler.unstable_getCurrentPriorityLevel, + Scheduler_ImmediatePriority = Scheduler.unstable_ImmediatePriority, + Scheduler_UserBlockingPriority = Scheduler.unstable_UserBlockingPriority, + Scheduler_NormalPriority = Scheduler.unstable_NormalPriority, + Scheduler_LowPriority = Scheduler.unstable_LowPriority, + Scheduler_IdlePriority = Scheduler.unstable_IdlePriority; +if ( + null == tracing.__interactionsRef || + null == tracing.__interactionsRef.current +) + throw ReactError( + "It is not supported to run the profiling version of a renderer (for example, `react-dom/profiling`) without also replacing the `scheduler/tracing` module with `scheduler/tracing-profiling`. Your bundler might have a setting for aliasing both modules. Learn more at http://fb.me/react-profiling" + ); +var fakeCallbackNode = {}, + immediateQueue = null, + immediateQueueCallbackNode = null, + isFlushingImmediate = !1, + initialTimeMs = Scheduler_now(), + now = + 1e4 > initialTimeMs + ? Scheduler_now + : function() { + return Scheduler_now() - initialTimeMs; + }; +function getCurrentPriorityLevel() { + switch (Scheduler_getCurrentPriorityLevel()) { + case Scheduler_ImmediatePriority: + return 99; + case Scheduler_UserBlockingPriority: + return 98; + case Scheduler_NormalPriority: + return 97; + case Scheduler_LowPriority: + return 96; + case Scheduler_IdlePriority: + return 95; + default: + throw ReactError("Unknown priority level."); + } +} +function reactPriorityToSchedulerPriority(reactPriorityLevel) { + switch (reactPriorityLevel) { + case 99: + return Scheduler_ImmediatePriority; + case 98: + return Scheduler_UserBlockingPriority; + case 97: + return Scheduler_NormalPriority; + case 96: + return Scheduler_LowPriority; + case 95: + return Scheduler_IdlePriority; + default: + throw ReactError("Unknown priority level."); + } +} +function runWithPriority(reactPriorityLevel, fn) { + reactPriorityLevel = reactPriorityToSchedulerPriority(reactPriorityLevel); + return Scheduler_runWithPriority(reactPriorityLevel, fn); +} +function scheduleCallback(reactPriorityLevel, callback, options) { + if (99 === reactPriorityLevel) + return ( + null === immediateQueue + ? ((immediateQueue = [callback]), + (immediateQueueCallbackNode = Scheduler_scheduleCallback( + Scheduler_ImmediatePriority, + flushImmediateQueueImpl + ))) + : immediateQueue.push(callback), + fakeCallbackNode + ); + reactPriorityLevel = reactPriorityToSchedulerPriority(reactPriorityLevel); + return Scheduler_scheduleCallback(reactPriorityLevel, callback, options); +} +function flushImmediateQueue() { + null !== immediateQueueCallbackNode && + Scheduler_cancelCallback(immediateQueueCallbackNode); + flushImmediateQueueImpl(); +} +function flushImmediateQueueImpl() { + if (!isFlushingImmediate && null !== immediateQueue) { + isFlushingImmediate = !0; + var i = 0; + try { + for (; i < immediateQueue.length; i++) { + var callback = immediateQueue[i]; + do callback = callback(!0); + while (null !== callback); + } + immediateQueue = null; + } catch (error) { + throw (null !== immediateQueue && + (immediateQueue = immediateQueue.slice(i + 1)), + Scheduler_scheduleCallback( + Scheduler_ImmediatePriority, + flushImmediateQueue + ), + error); + } finally { + isFlushingImmediate = !1; + } + } +} +function inferPriorityFromExpirationTime(currentTime, expirationTime) { + if (1073741823 === expirationTime) return 99; + if (1 === expirationTime) return 95; + currentTime = + 10 * (1073741822 - expirationTime) - 10 * (1073741822 - currentTime); + return 0 >= currentTime + ? 99 + : 250 >= currentTime + ? 98 + : 5250 >= currentTime + ? 97 + : 95; +} +function FiberNode(tag, pendingProps, key, mode) { + this.tag = tag; + this.key = key; + this.sibling = this.child = this.return = this.stateNode = this.type = this.elementType = null; + this.index = 0; + this.ref = null; + this.pendingProps = pendingProps; + this.contextDependencies = this.memoizedState = this.updateQueue = this.memoizedProps = null; + this.mode = mode; + this.effectTag = 0; + this.lastEffect = this.firstEffect = this.nextEffect = null; + this.childExpirationTime = this.expirationTime = 0; + this.alternate = null; + this.actualDuration = 0; + this.actualStartTime = -1; + this.treeBaseDuration = this.selfBaseDuration = 0; +} +function createFiber(tag, pendingProps, key, mode) { + return new FiberNode(tag, pendingProps, key, mode); +} +function shouldConstruct(Component) { + Component = Component.prototype; + return !(!Component || !Component.isReactComponent); +} +function resolveLazyComponentTag(Component) { + if ("function" === typeof Component) + return shouldConstruct(Component) ? 1 : 0; + if (void 0 !== Component && null !== Component) { + Component = Component.$$typeof; + if (Component === REACT_FORWARD_REF_TYPE) return 11; + if (Component === REACT_MEMO_TYPE) return 14; + } + return 2; +} +function createWorkInProgress(current, pendingProps) { + var workInProgress = current.alternate; + null === workInProgress + ? ((workInProgress = createFiber( + current.tag, + pendingProps, + current.key, + current.mode + )), + (workInProgress.elementType = current.elementType), + (workInProgress.type = current.type), + (workInProgress.stateNode = current.stateNode), + (workInProgress.alternate = current), + (current.alternate = workInProgress)) + : ((workInProgress.pendingProps = pendingProps), + (workInProgress.effectTag = 0), + (workInProgress.nextEffect = null), + (workInProgress.firstEffect = null), + (workInProgress.lastEffect = null), + (workInProgress.actualDuration = 0), + (workInProgress.actualStartTime = -1)); + workInProgress.childExpirationTime = current.childExpirationTime; + workInProgress.expirationTime = current.expirationTime; + workInProgress.child = current.child; + workInProgress.memoizedProps = current.memoizedProps; + workInProgress.memoizedState = current.memoizedState; + workInProgress.updateQueue = current.updateQueue; + workInProgress.contextDependencies = current.contextDependencies; + workInProgress.sibling = current.sibling; + workInProgress.index = current.index; + workInProgress.ref = current.ref; + workInProgress.selfBaseDuration = current.selfBaseDuration; + workInProgress.treeBaseDuration = current.treeBaseDuration; + return workInProgress; +} +function createFiberFromTypeAndProps( + type, + key, + pendingProps, + owner, + mode, + expirationTime +) { + var fiberTag = 2; + owner = type; + if ("function" === typeof type) shouldConstruct(type) && (fiberTag = 1); + else if ("string" === typeof type) fiberTag = 5; + else + a: switch (type) { + case REACT_FRAGMENT_TYPE: + return createFiberFromFragment( + pendingProps.children, + mode, + expirationTime, + key + ); + case REACT_CONCURRENT_MODE_TYPE: + return createFiberFromMode(pendingProps, mode | 3, expirationTime, key); + case REACT_STRICT_MODE_TYPE: + return createFiberFromMode(pendingProps, mode | 2, expirationTime, key); + case REACT_PROFILER_TYPE: + return ( + (type = createFiber(12, pendingProps, key, mode | 4)), + (type.elementType = REACT_PROFILER_TYPE), + (type.type = REACT_PROFILER_TYPE), + (type.expirationTime = expirationTime), + type + ); + case REACT_SUSPENSE_TYPE: + return ( + (type = createFiber(13, pendingProps, key, mode)), + (type.elementType = REACT_SUSPENSE_TYPE), + (type.type = REACT_SUSPENSE_TYPE), + (type.expirationTime = expirationTime), + type + ); + default: + if ("object" === typeof type && null !== type) + switch (type.$$typeof) { + case REACT_PROVIDER_TYPE: + fiberTag = 10; + break a; + case REACT_CONTEXT_TYPE: + fiberTag = 9; + break a; + case REACT_FORWARD_REF_TYPE: + fiberTag = 11; + break a; + case REACT_MEMO_TYPE: + fiberTag = 14; + break a; + case REACT_LAZY_TYPE: + fiberTag = 16; + owner = null; + break a; + } + throw ReactError( + "Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: " + + (null == type ? type : typeof type) + + "." + ); + } + key = createFiber(fiberTag, pendingProps, key, mode); + key.elementType = type; + key.type = owner; + key.expirationTime = expirationTime; + return key; +} +function createFiberFromFragment(elements, mode, expirationTime, key) { + elements = createFiber(7, elements, key, mode); + elements.expirationTime = expirationTime; + return elements; +} +function createFiberFromMode(pendingProps, mode, expirationTime, key) { + pendingProps = createFiber(8, pendingProps, key, mode); + mode = 0 === (mode & 1) ? REACT_STRICT_MODE_TYPE : REACT_CONCURRENT_MODE_TYPE; + pendingProps.elementType = mode; + pendingProps.type = mode; + pendingProps.expirationTime = expirationTime; + return pendingProps; +} +function createFiberFromText(content, mode, expirationTime) { + content = createFiber(6, content, null, mode); + content.expirationTime = expirationTime; + return content; +} +function createFiberFromPortal(portal, mode, expirationTime) { + mode = createFiber( + 4, + null !== portal.children ? portal.children : [], + portal.key, + mode + ); + mode.expirationTime = expirationTime; + mode.stateNode = { + containerInfo: portal.containerInfo, + pendingChildren: null, + implementation: portal.implementation + }; + return mode; +} +function FiberRootNode(containerInfo, hydrate) { + this.current = null; + this.containerInfo = containerInfo; + this.pingCache = this.pendingChildren = null; + this.pendingCommitExpirationTime = 0; + this.finishedWork = null; + this.timeoutHandle = -1; + this.pendingContext = this.context = null; + this.hydrate = hydrate; + this.callbackNode = this.firstBatch = null; + this.pingTime = this.lastPendingTime = this.firstPendingTime = this.callbackExpirationTime = 0; + this.interactionThreadID = tracing.unstable_getThreadID(); + this.memoizedInteractions = new Set(); + this.pendingInteractionMap = new Map(); +} +function is(x, y) { + return (x === y && (0 !== x || 1 / x === 1 / y)) || (x !== x && y !== y); +} +var hasOwnProperty = Object.prototype.hasOwnProperty; +function shallowEqual(objA, objB) { + if (is(objA, objB)) return !0; + if ( + "object" !== typeof objA || + null === objA || + "object" !== typeof objB || + null === objB + ) + return !1; + var keysA = Object.keys(objA), + keysB = Object.keys(objB); + if (keysA.length !== keysB.length) return !1; + for (keysB = 0; keysB < keysA.length; keysB++) + if ( + !hasOwnProperty.call(objB, keysA[keysB]) || + !is(objA[keysA[keysB]], objB[keysA[keysB]]) + ) + return !1; + return !0; +} +function resolveDefaultProps(Component, baseProps) { + if (Component && Component.defaultProps) { + baseProps = Object.assign({}, baseProps); + Component = Component.defaultProps; + for (var propName in Component) + void 0 === baseProps[propName] && + (baseProps[propName] = Component[propName]); + } + return baseProps; +} +function readLazyComponentType(lazyComponent) { + var result = lazyComponent._result; + switch (lazyComponent._status) { + case 1: + return result; + case 2: + throw result; + case 0: + throw result; + default: + lazyComponent._status = 0; + result = lazyComponent._ctor; + result = result(); + result.then( + function(moduleObject) { + 0 === lazyComponent._status && + ((moduleObject = moduleObject.default), + (lazyComponent._status = 1), + (lazyComponent._result = moduleObject)); + }, + function(error) { + 0 === lazyComponent._status && + ((lazyComponent._status = 2), (lazyComponent._result = error)); + } + ); + switch (lazyComponent._status) { + case 1: + return lazyComponent._result; + case 2: + throw lazyComponent._result; + } + lazyComponent._result = result; + throw result; + } +} +var valueCursor = { current: null }, + currentlyRenderingFiber = null, + lastContextDependency = null, + lastContextWithAllBitsObserved = null; +function resetContextDependences() { + lastContextWithAllBitsObserved = lastContextDependency = currentlyRenderingFiber = null; +} +function pushProvider(providerFiber, nextValue) { + var context = providerFiber.type._context; + push(valueCursor, context._currentValue, providerFiber); + context._currentValue = nextValue; +} +function popProvider(providerFiber) { + var currentValue = valueCursor.current; + pop(valueCursor, providerFiber); + providerFiber.type._context._currentValue = currentValue; +} +function prepareToReadContext(workInProgress, renderExpirationTime) { + currentlyRenderingFiber = workInProgress; + lastContextWithAllBitsObserved = lastContextDependency = null; + var currentDependencies = workInProgress.contextDependencies; + null !== currentDependencies && + currentDependencies.expirationTime >= renderExpirationTime && + (didReceiveUpdate = !0); + workInProgress.contextDependencies = null; +} +function readContext(context, observedBits) { + if ( + lastContextWithAllBitsObserved !== context && + !1 !== observedBits && + 0 !== observedBits + ) { + if ("number" !== typeof observedBits || 1073741823 === observedBits) + (lastContextWithAllBitsObserved = context), (observedBits = 1073741823); + observedBits = { context: context, observedBits: observedBits, next: null }; + if (null === lastContextDependency) { + if (null === currentlyRenderingFiber) + throw ReactError( + "Context can only be read while React is rendering. In classes, you can read it in the render method or getDerivedStateFromProps. In function components, you can read it directly in the function body, but not inside Hooks like useReducer() or useMemo()." + ); + lastContextDependency = observedBits; + currentlyRenderingFiber.contextDependencies = { + first: observedBits, + expirationTime: 0 + }; + } else lastContextDependency = lastContextDependency.next = observedBits; + } + return context._currentValue; +} +var hasForceUpdate = !1; +function createUpdateQueue(baseState) { + return { + baseState: baseState, + firstUpdate: null, + lastUpdate: null, + firstCapturedUpdate: null, + lastCapturedUpdate: null, + firstEffect: null, + lastEffect: null, + firstCapturedEffect: null, + lastCapturedEffect: null + }; +} +function cloneUpdateQueue(currentQueue) { + return { + baseState: currentQueue.baseState, + firstUpdate: currentQueue.firstUpdate, + lastUpdate: currentQueue.lastUpdate, + firstCapturedUpdate: null, + lastCapturedUpdate: null, + firstEffect: null, + lastEffect: null, + firstCapturedEffect: null, + lastCapturedEffect: null + }; +} +function createUpdate(expirationTime) { + return { + expirationTime: expirationTime, + tag: 0, + payload: null, + callback: null, + next: null, + nextEffect: null + }; +} +function appendUpdateToQueue(queue, update) { + null === queue.lastUpdate + ? (queue.firstUpdate = queue.lastUpdate = update) + : ((queue.lastUpdate.next = update), (queue.lastUpdate = update)); +} +function enqueueUpdate(fiber, update) { + var alternate = fiber.alternate; + if (null === alternate) { + var queue1 = fiber.updateQueue; + var queue2 = null; + null === queue1 && + (queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState)); + } else + (queue1 = fiber.updateQueue), + (queue2 = alternate.updateQueue), + null === queue1 + ? null === queue2 + ? ((queue1 = fiber.updateQueue = createUpdateQueue( + fiber.memoizedState + )), + (queue2 = alternate.updateQueue = createUpdateQueue( + alternate.memoizedState + ))) + : (queue1 = fiber.updateQueue = cloneUpdateQueue(queue2)) + : null === queue2 && + (queue2 = alternate.updateQueue = cloneUpdateQueue(queue1)); + null === queue2 || queue1 === queue2 + ? appendUpdateToQueue(queue1, update) + : null === queue1.lastUpdate || null === queue2.lastUpdate + ? (appendUpdateToQueue(queue1, update), + appendUpdateToQueue(queue2, update)) + : (appendUpdateToQueue(queue1, update), (queue2.lastUpdate = update)); +} +function enqueueCapturedUpdate(workInProgress, update) { + var workInProgressQueue = workInProgress.updateQueue; + workInProgressQueue = + null === workInProgressQueue + ? (workInProgress.updateQueue = createUpdateQueue( + workInProgress.memoizedState + )) + : ensureWorkInProgressQueueIsAClone(workInProgress, workInProgressQueue); + null === workInProgressQueue.lastCapturedUpdate + ? (workInProgressQueue.firstCapturedUpdate = workInProgressQueue.lastCapturedUpdate = update) + : ((workInProgressQueue.lastCapturedUpdate.next = update), + (workInProgressQueue.lastCapturedUpdate = update)); +} +function ensureWorkInProgressQueueIsAClone(workInProgress, queue) { + var current = workInProgress.alternate; + null !== current && + queue === current.updateQueue && + (queue = workInProgress.updateQueue = cloneUpdateQueue(queue)); + return queue; +} +function getStateFromUpdate( + workInProgress, + queue, + update, + prevState, + nextProps, + instance +) { + switch (update.tag) { + case 1: + return ( + (workInProgress = update.payload), + "function" === typeof workInProgress + ? workInProgress.call(instance, prevState, nextProps) + : workInProgress + ); + case 3: + workInProgress.effectTag = (workInProgress.effectTag & -2049) | 64; + case 0: + workInProgress = update.payload; + nextProps = + "function" === typeof workInProgress + ? workInProgress.call(instance, prevState, nextProps) + : workInProgress; + if (null === nextProps || void 0 === nextProps) break; + return Object.assign({}, prevState, nextProps); + case 2: + hasForceUpdate = !0; + } + return prevState; +} +function processUpdateQueue( + workInProgress, + queue, + props, + instance, + renderExpirationTime +) { + hasForceUpdate = !1; + queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue); + for ( + var newBaseState = queue.baseState, + newFirstUpdate = null, + newExpirationTime = 0, + update = queue.firstUpdate, + resultState = newBaseState; + null !== update; + + ) { + var updateExpirationTime = update.expirationTime; + updateExpirationTime < renderExpirationTime + ? (null === newFirstUpdate && + ((newFirstUpdate = update), (newBaseState = resultState)), + newExpirationTime < updateExpirationTime && + (newExpirationTime = updateExpirationTime)) + : (updateExpirationTime < workInProgressRootMostRecentEventTime && + (workInProgressRootMostRecentEventTime = updateExpirationTime), + (resultState = getStateFromUpdate( + workInProgress, + queue, + update, + resultState, + props, + instance + )), + null !== update.callback && + ((workInProgress.effectTag |= 32), + (update.nextEffect = null), + null === queue.lastEffect + ? (queue.firstEffect = queue.lastEffect = update) + : ((queue.lastEffect.nextEffect = update), + (queue.lastEffect = update)))); + update = update.next; + } + updateExpirationTime = null; + for (update = queue.firstCapturedUpdate; null !== update; ) { + var _updateExpirationTime = update.expirationTime; + _updateExpirationTime < renderExpirationTime + ? (null === updateExpirationTime && + ((updateExpirationTime = update), + null === newFirstUpdate && (newBaseState = resultState)), + newExpirationTime < _updateExpirationTime && + (newExpirationTime = _updateExpirationTime)) + : ((resultState = getStateFromUpdate( + workInProgress, + queue, + update, + resultState, + props, + instance + )), + null !== update.callback && + ((workInProgress.effectTag |= 32), + (update.nextEffect = null), + null === queue.lastCapturedEffect + ? (queue.firstCapturedEffect = queue.lastCapturedEffect = update) + : ((queue.lastCapturedEffect.nextEffect = update), + (queue.lastCapturedEffect = update)))); + update = update.next; + } + null === newFirstUpdate && (queue.lastUpdate = null); + null === updateExpirationTime + ? (queue.lastCapturedUpdate = null) + : (workInProgress.effectTag |= 32); + null === newFirstUpdate && + null === updateExpirationTime && + (newBaseState = resultState); + queue.baseState = newBaseState; + queue.firstUpdate = newFirstUpdate; + queue.firstCapturedUpdate = updateExpirationTime; + workInProgress.expirationTime = newExpirationTime; + workInProgress.memoizedState = resultState; +} +function commitUpdateQueue(finishedWork, finishedQueue, instance) { + null !== finishedQueue.firstCapturedUpdate && + (null !== finishedQueue.lastUpdate && + ((finishedQueue.lastUpdate.next = finishedQueue.firstCapturedUpdate), + (finishedQueue.lastUpdate = finishedQueue.lastCapturedUpdate)), + (finishedQueue.firstCapturedUpdate = finishedQueue.lastCapturedUpdate = null)); + commitUpdateEffects(finishedQueue.firstEffect, instance); + finishedQueue.firstEffect = finishedQueue.lastEffect = null; + commitUpdateEffects(finishedQueue.firstCapturedEffect, instance); + finishedQueue.firstCapturedEffect = finishedQueue.lastCapturedEffect = null; +} +function commitUpdateEffects(effect, instance) { + for (; null !== effect; ) { + var _callback3 = effect.callback; + if (null !== _callback3) { + effect.callback = null; + var context = instance; + if ("function" !== typeof _callback3) + throw ReactError( + "Invalid argument passed as callback. Expected a function. Instead received: " + + _callback3 + ); + _callback3.call(context); + } + effect = effect.nextEffect; + } +} +var emptyRefsObject = new React.Component().refs; +function applyDerivedStateFromProps( + workInProgress, + ctor, + getDerivedStateFromProps, + nextProps +) { + ctor = workInProgress.memoizedState; + getDerivedStateFromProps = getDerivedStateFromProps(nextProps, ctor); + getDerivedStateFromProps = + null === getDerivedStateFromProps || void 0 === getDerivedStateFromProps + ? ctor + : Object.assign({}, ctor, getDerivedStateFromProps); + workInProgress.memoizedState = getDerivedStateFromProps; + nextProps = workInProgress.updateQueue; + null !== nextProps && + 0 === workInProgress.expirationTime && + (nextProps.baseState = getDerivedStateFromProps); +} +var classComponentUpdater = { + isMounted: function(component) { + return (component = component._reactInternalFiber) + ? 2 === isFiberMountedImpl(component) + : !1; + }, + enqueueSetState: function(inst, payload, callback) { + inst = inst._reactInternalFiber; + var currentTime = requestCurrentTime(); + currentTime = computeExpirationForFiber(currentTime, inst); + var update = createUpdate(currentTime); + update.payload = payload; + void 0 !== callback && null !== callback && (update.callback = callback); + flushPassiveEffects(); + enqueueUpdate(inst, update); + scheduleUpdateOnFiber(inst, currentTime); + }, + enqueueReplaceState: function(inst, payload, callback) { + inst = inst._reactInternalFiber; + var currentTime = requestCurrentTime(); + currentTime = computeExpirationForFiber(currentTime, inst); + var update = createUpdate(currentTime); + update.tag = 1; + update.payload = payload; + void 0 !== callback && null !== callback && (update.callback = callback); + flushPassiveEffects(); + enqueueUpdate(inst, update); + scheduleUpdateOnFiber(inst, currentTime); + }, + enqueueForceUpdate: function(inst, callback) { + inst = inst._reactInternalFiber; + var currentTime = requestCurrentTime(); + currentTime = computeExpirationForFiber(currentTime, inst); + var update = createUpdate(currentTime); + update.tag = 2; + void 0 !== callback && null !== callback && (update.callback = callback); + flushPassiveEffects(); + enqueueUpdate(inst, update); + scheduleUpdateOnFiber(inst, currentTime); + } +}; +function checkShouldComponentUpdate( + workInProgress, + ctor, + oldProps, + newProps, + oldState, + newState, + nextContext +) { + workInProgress = workInProgress.stateNode; + return "function" === typeof workInProgress.shouldComponentUpdate + ? workInProgress.shouldComponentUpdate(newProps, newState, nextContext) + : ctor.prototype && ctor.prototype.isPureReactComponent + ? !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState) + : !0; +} +function constructClassInstance(workInProgress, ctor, props) { + var isLegacyContextConsumer = !1, + unmaskedContext = emptyContextObject; + var context = ctor.contextType; + "object" === typeof context && null !== context + ? (context = readContext(context)) + : ((unmaskedContext = isContextProvider(ctor) + ? previousContext + : contextStackCursor.current), + (isLegacyContextConsumer = ctor.contextTypes), + (context = (isLegacyContextConsumer = + null !== isLegacyContextConsumer && void 0 !== isLegacyContextConsumer) + ? getMaskedContext(workInProgress, unmaskedContext) + : emptyContextObject)); + ctor = new ctor(props, context); + workInProgress.memoizedState = + null !== ctor.state && void 0 !== ctor.state ? ctor.state : null; + ctor.updater = classComponentUpdater; + workInProgress.stateNode = ctor; + ctor._reactInternalFiber = workInProgress; + isLegacyContextConsumer && + ((workInProgress = workInProgress.stateNode), + (workInProgress.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext), + (workInProgress.__reactInternalMemoizedMaskedChildContext = context)); + return ctor; +} +function callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + nextContext +) { + workInProgress = instance.state; + "function" === typeof instance.componentWillReceiveProps && + instance.componentWillReceiveProps(newProps, nextContext); + "function" === typeof instance.UNSAFE_componentWillReceiveProps && + instance.UNSAFE_componentWillReceiveProps(newProps, nextContext); + instance.state !== workInProgress && + classComponentUpdater.enqueueReplaceState(instance, instance.state, null); +} +function mountClassInstance( + workInProgress, + ctor, + newProps, + renderExpirationTime +) { + var instance = workInProgress.stateNode; + instance.props = newProps; + instance.state = workInProgress.memoizedState; + instance.refs = emptyRefsObject; + var contextType = ctor.contextType; + "object" === typeof contextType && null !== contextType + ? (instance.context = readContext(contextType)) + : ((contextType = isContextProvider(ctor) + ? previousContext + : contextStackCursor.current), + (instance.context = getMaskedContext(workInProgress, contextType))); + contextType = workInProgress.updateQueue; + null !== contextType && + (processUpdateQueue( + workInProgress, + contextType, + newProps, + instance, + renderExpirationTime + ), + (instance.state = workInProgress.memoizedState)); + contextType = ctor.getDerivedStateFromProps; + "function" === typeof contextType && + (applyDerivedStateFromProps(workInProgress, ctor, contextType, newProps), + (instance.state = workInProgress.memoizedState)); + "function" === typeof ctor.getDerivedStateFromProps || + "function" === typeof instance.getSnapshotBeforeUpdate || + ("function" !== typeof instance.UNSAFE_componentWillMount && + "function" !== typeof instance.componentWillMount) || + ((ctor = instance.state), + "function" === typeof instance.componentWillMount && + instance.componentWillMount(), + "function" === typeof instance.UNSAFE_componentWillMount && + instance.UNSAFE_componentWillMount(), + ctor !== instance.state && + classComponentUpdater.enqueueReplaceState(instance, instance.state, null), + (contextType = workInProgress.updateQueue), + null !== contextType && + (processUpdateQueue( + workInProgress, + contextType, + newProps, + instance, + renderExpirationTime + ), + (instance.state = workInProgress.memoizedState))); + "function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4); +} +var isArray = Array.isArray; +function coerceRef(returnFiber, current$$1, element) { + returnFiber = element.ref; + if ( + null !== returnFiber && + "function" !== typeof returnFiber && + "object" !== typeof returnFiber + ) { + if (element._owner) { + element = element._owner; + var inst = void 0; + if (element) { + if (1 !== element.tag) + throw ReactError( + "Function components cannot have refs. Did you mean to use React.forwardRef()?" + ); + inst = element.stateNode; + } + if (!inst) + throw ReactError( + "Missing owner for string ref " + + returnFiber + + ". This error is likely caused by a bug in React. Please file an issue." + ); + var stringRef = "" + returnFiber; + if ( + null !== current$$1 && + null !== current$$1.ref && + "function" === typeof current$$1.ref && + current$$1.ref._stringRef === stringRef + ) + return current$$1.ref; + current$$1 = function(value) { + var refs = inst.refs; + refs === emptyRefsObject && (refs = inst.refs = {}); + null === value ? delete refs[stringRef] : (refs[stringRef] = value); + }; + current$$1._stringRef = stringRef; + return current$$1; + } + if ("string" !== typeof returnFiber) + throw ReactError( + "Expected ref to be a function, a string, an object returned by React.createRef(), or null." + ); + if (!element._owner) + throw ReactError( + "Element ref was specified as a string (" + + returnFiber + + ") but no owner was set. This could happen for one of the following reasons:\n1. You may be adding a ref to a function component\n2. You may be adding a ref to a component that was not created inside a component's render method\n3. You have multiple copies of React loaded\nSee https://fb.me/react-refs-must-have-owner for more information." + ); + } + return returnFiber; +} +function throwOnInvalidObjectType(returnFiber, newChild) { + if ("textarea" !== returnFiber.type) + throw ReactError( + "Objects are not valid as a React child (found: " + + ("[object Object]" === Object.prototype.toString.call(newChild) + ? "object with keys {" + Object.keys(newChild).join(", ") + "}" + : newChild) + + ")." + ); +} +function ChildReconciler(shouldTrackSideEffects) { + function deleteChild(returnFiber, childToDelete) { + if (shouldTrackSideEffects) { + var last = returnFiber.lastEffect; + null !== last + ? ((last.nextEffect = childToDelete), + (returnFiber.lastEffect = childToDelete)) + : (returnFiber.firstEffect = returnFiber.lastEffect = childToDelete); + childToDelete.nextEffect = null; + childToDelete.effectTag = 8; + } + } + function deleteRemainingChildren(returnFiber, currentFirstChild) { + if (!shouldTrackSideEffects) return null; + for (; null !== currentFirstChild; ) + deleteChild(returnFiber, currentFirstChild), + (currentFirstChild = currentFirstChild.sibling); + return null; + } + function mapRemainingChildren(returnFiber, currentFirstChild) { + for (returnFiber = new Map(); null !== currentFirstChild; ) + null !== currentFirstChild.key + ? returnFiber.set(currentFirstChild.key, currentFirstChild) + : returnFiber.set(currentFirstChild.index, currentFirstChild), + (currentFirstChild = currentFirstChild.sibling); + return returnFiber; + } + function useFiber(fiber, pendingProps, expirationTime) { + fiber = createWorkInProgress(fiber, pendingProps, expirationTime); + fiber.index = 0; + fiber.sibling = null; + return fiber; + } + function placeChild(newFiber, lastPlacedIndex, newIndex) { + newFiber.index = newIndex; + if (!shouldTrackSideEffects) return lastPlacedIndex; + newIndex = newFiber.alternate; + if (null !== newIndex) + return ( + (newIndex = newIndex.index), + newIndex < lastPlacedIndex + ? ((newFiber.effectTag = 2), lastPlacedIndex) + : newIndex + ); + newFiber.effectTag = 2; + return lastPlacedIndex; + } + function placeSingleChild(newFiber) { + shouldTrackSideEffects && + null === newFiber.alternate && + (newFiber.effectTag = 2); + return newFiber; + } + function updateTextNode( + returnFiber, + current$$1, + textContent, + expirationTime + ) { + if (null === current$$1 || 6 !== current$$1.tag) + return ( + (current$$1 = createFiberFromText( + textContent, + returnFiber.mode, + expirationTime + )), + (current$$1.return = returnFiber), + current$$1 + ); + current$$1 = useFiber(current$$1, textContent, expirationTime); + current$$1.return = returnFiber; + return current$$1; + } + function updateElement(returnFiber, current$$1, element, expirationTime) { + if (null !== current$$1 && current$$1.elementType === element.type) + return ( + (expirationTime = useFiber(current$$1, element.props, expirationTime)), + (expirationTime.ref = coerceRef(returnFiber, current$$1, element)), + (expirationTime.return = returnFiber), + expirationTime + ); + expirationTime = createFiberFromTypeAndProps( + element.type, + element.key, + element.props, + null, + returnFiber.mode, + expirationTime + ); + expirationTime.ref = coerceRef(returnFiber, current$$1, element); + expirationTime.return = returnFiber; + return expirationTime; + } + function updatePortal(returnFiber, current$$1, portal, expirationTime) { + if ( + null === current$$1 || + 4 !== current$$1.tag || + current$$1.stateNode.containerInfo !== portal.containerInfo || + current$$1.stateNode.implementation !== portal.implementation + ) + return ( + (current$$1 = createFiberFromPortal( + portal, + returnFiber.mode, + expirationTime + )), + (current$$1.return = returnFiber), + current$$1 + ); + current$$1 = useFiber(current$$1, portal.children || [], expirationTime); + current$$1.return = returnFiber; + return current$$1; + } + function updateFragment( + returnFiber, + current$$1, + fragment, + expirationTime, + key + ) { + if (null === current$$1 || 7 !== current$$1.tag) + return ( + (current$$1 = createFiberFromFragment( + fragment, + returnFiber.mode, + expirationTime, + key + )), + (current$$1.return = returnFiber), + current$$1 + ); + current$$1 = useFiber(current$$1, fragment, expirationTime); + current$$1.return = returnFiber; + return current$$1; + } + function createChild(returnFiber, newChild, expirationTime) { + if ("string" === typeof newChild || "number" === typeof newChild) + return ( + (newChild = createFiberFromText( + "" + newChild, + returnFiber.mode, + expirationTime + )), + (newChild.return = returnFiber), + newChild + ); + if ("object" === typeof newChild && null !== newChild) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return ( + (expirationTime = createFiberFromTypeAndProps( + newChild.type, + newChild.key, + newChild.props, + null, + returnFiber.mode, + expirationTime + )), + (expirationTime.ref = coerceRef(returnFiber, null, newChild)), + (expirationTime.return = returnFiber), + expirationTime + ); + case REACT_PORTAL_TYPE: + return ( + (newChild = createFiberFromPortal( + newChild, + returnFiber.mode, + expirationTime + )), + (newChild.return = returnFiber), + newChild + ); + } + if (isArray(newChild) || getIteratorFn(newChild)) + return ( + (newChild = createFiberFromFragment( + newChild, + returnFiber.mode, + expirationTime, + null + )), + (newChild.return = returnFiber), + newChild + ); + throwOnInvalidObjectType(returnFiber, newChild); + } + return null; + } + function updateSlot(returnFiber, oldFiber, newChild, expirationTime) { + var key = null !== oldFiber ? oldFiber.key : null; + if ("string" === typeof newChild || "number" === typeof newChild) + return null !== key + ? null + : updateTextNode(returnFiber, oldFiber, "" + newChild, expirationTime); + if ("object" === typeof newChild && null !== newChild) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return newChild.key === key + ? newChild.type === REACT_FRAGMENT_TYPE + ? updateFragment( + returnFiber, + oldFiber, + newChild.props.children, + expirationTime, + key + ) + : updateElement(returnFiber, oldFiber, newChild, expirationTime) + : null; + case REACT_PORTAL_TYPE: + return newChild.key === key + ? updatePortal(returnFiber, oldFiber, newChild, expirationTime) + : null; + } + if (isArray(newChild) || getIteratorFn(newChild)) + return null !== key + ? null + : updateFragment( + returnFiber, + oldFiber, + newChild, + expirationTime, + null + ); + throwOnInvalidObjectType(returnFiber, newChild); + } + return null; + } + function updateFromMap( + existingChildren, + returnFiber, + newIdx, + newChild, + expirationTime + ) { + if ("string" === typeof newChild || "number" === typeof newChild) + return ( + (existingChildren = existingChildren.get(newIdx) || null), + updateTextNode( + returnFiber, + existingChildren, + "" + newChild, + expirationTime + ) + ); + if ("object" === typeof newChild && null !== newChild) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return ( + (existingChildren = + existingChildren.get( + null === newChild.key ? newIdx : newChild.key + ) || null), + newChild.type === REACT_FRAGMENT_TYPE + ? updateFragment( + returnFiber, + existingChildren, + newChild.props.children, + expirationTime, + newChild.key + ) + : updateElement( + returnFiber, + existingChildren, + newChild, + expirationTime + ) + ); + case REACT_PORTAL_TYPE: + return ( + (existingChildren = + existingChildren.get( + null === newChild.key ? newIdx : newChild.key + ) || null), + updatePortal( + returnFiber, + existingChildren, + newChild, + expirationTime + ) + ); + } + if (isArray(newChild) || getIteratorFn(newChild)) + return ( + (existingChildren = existingChildren.get(newIdx) || null), + updateFragment( + returnFiber, + existingChildren, + newChild, + expirationTime, + null + ) + ); + throwOnInvalidObjectType(returnFiber, newChild); + } + return null; + } + function reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChildren, + expirationTime + ) { + for ( + var resultingFirstChild = null, + previousNewFiber = null, + oldFiber = currentFirstChild, + newIdx = (currentFirstChild = 0), + nextOldFiber = null; + null !== oldFiber && newIdx < newChildren.length; + newIdx++ + ) { + oldFiber.index > newIdx + ? ((nextOldFiber = oldFiber), (oldFiber = null)) + : (nextOldFiber = oldFiber.sibling); + var newFiber = updateSlot( + returnFiber, + oldFiber, + newChildren[newIdx], + expirationTime + ); + if (null === newFiber) { + null === oldFiber && (oldFiber = nextOldFiber); + break; + } + shouldTrackSideEffects && + oldFiber && + null === newFiber.alternate && + deleteChild(returnFiber, oldFiber); + currentFirstChild = placeChild(newFiber, currentFirstChild, newIdx); + null === previousNewFiber + ? (resultingFirstChild = newFiber) + : (previousNewFiber.sibling = newFiber); + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } + if (newIdx === newChildren.length) + return ( + deleteRemainingChildren(returnFiber, oldFiber), resultingFirstChild + ); + if (null === oldFiber) { + for (; newIdx < newChildren.length; newIdx++) + (oldFiber = createChild( + returnFiber, + newChildren[newIdx], + expirationTime + )), + null !== oldFiber && + ((currentFirstChild = placeChild( + oldFiber, + currentFirstChild, + newIdx + )), + null === previousNewFiber + ? (resultingFirstChild = oldFiber) + : (previousNewFiber.sibling = oldFiber), + (previousNewFiber = oldFiber)); + return resultingFirstChild; + } + for ( + oldFiber = mapRemainingChildren(returnFiber, oldFiber); + newIdx < newChildren.length; + newIdx++ + ) + (nextOldFiber = updateFromMap( + oldFiber, + returnFiber, + newIdx, + newChildren[newIdx], + expirationTime + )), + null !== nextOldFiber && + (shouldTrackSideEffects && + null !== nextOldFiber.alternate && + oldFiber.delete( + null === nextOldFiber.key ? newIdx : nextOldFiber.key + ), + (currentFirstChild = placeChild( + nextOldFiber, + currentFirstChild, + newIdx + )), + null === previousNewFiber + ? (resultingFirstChild = nextOldFiber) + : (previousNewFiber.sibling = nextOldFiber), + (previousNewFiber = nextOldFiber)); + shouldTrackSideEffects && + oldFiber.forEach(function(child) { + return deleteChild(returnFiber, child); + }); + return resultingFirstChild; + } + function reconcileChildrenIterator( + returnFiber, + currentFirstChild, + newChildrenIterable, + expirationTime + ) { + var iteratorFn = getIteratorFn(newChildrenIterable); + if ("function" !== typeof iteratorFn) + throw ReactError( + "An object is not an iterable. This error is likely caused by a bug in React. Please file an issue." + ); + newChildrenIterable = iteratorFn.call(newChildrenIterable); + if (null == newChildrenIterable) + throw ReactError("An iterable object provided no iterator."); + for ( + var previousNewFiber = (iteratorFn = null), + oldFiber = currentFirstChild, + newIdx = (currentFirstChild = 0), + nextOldFiber = null, + step = newChildrenIterable.next(); + null !== oldFiber && !step.done; + newIdx++, step = newChildrenIterable.next() + ) { + oldFiber.index > newIdx + ? ((nextOldFiber = oldFiber), (oldFiber = null)) + : (nextOldFiber = oldFiber.sibling); + var newFiber = updateSlot( + returnFiber, + oldFiber, + step.value, + expirationTime + ); + if (null === newFiber) { + null === oldFiber && (oldFiber = nextOldFiber); + break; + } + shouldTrackSideEffects && + oldFiber && + null === newFiber.alternate && + deleteChild(returnFiber, oldFiber); + currentFirstChild = placeChild(newFiber, currentFirstChild, newIdx); + null === previousNewFiber + ? (iteratorFn = newFiber) + : (previousNewFiber.sibling = newFiber); + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } + if (step.done) + return deleteRemainingChildren(returnFiber, oldFiber), iteratorFn; + if (null === oldFiber) { + for (; !step.done; newIdx++, step = newChildrenIterable.next()) + (step = createChild(returnFiber, step.value, expirationTime)), + null !== step && + ((currentFirstChild = placeChild(step, currentFirstChild, newIdx)), + null === previousNewFiber + ? (iteratorFn = step) + : (previousNewFiber.sibling = step), + (previousNewFiber = step)); + return iteratorFn; + } + for ( + oldFiber = mapRemainingChildren(returnFiber, oldFiber); + !step.done; + newIdx++, step = newChildrenIterable.next() + ) + (step = updateFromMap( + oldFiber, + returnFiber, + newIdx, + step.value, + expirationTime + )), + null !== step && + (shouldTrackSideEffects && + null !== step.alternate && + oldFiber.delete(null === step.key ? newIdx : step.key), + (currentFirstChild = placeChild(step, currentFirstChild, newIdx)), + null === previousNewFiber + ? (iteratorFn = step) + : (previousNewFiber.sibling = step), + (previousNewFiber = step)); + shouldTrackSideEffects && + oldFiber.forEach(function(child) { + return deleteChild(returnFiber, child); + }); + return iteratorFn; + } + return function(returnFiber, currentFirstChild, newChild, expirationTime) { + var isUnkeyedTopLevelFragment = + "object" === typeof newChild && + null !== newChild && + newChild.type === REACT_FRAGMENT_TYPE && + null === newChild.key; + isUnkeyedTopLevelFragment && (newChild = newChild.props.children); + var isObject = "object" === typeof newChild && null !== newChild; + if (isObject) + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + a: { + isObject = newChild.key; + for ( + isUnkeyedTopLevelFragment = currentFirstChild; + null !== isUnkeyedTopLevelFragment; + + ) { + if (isUnkeyedTopLevelFragment.key === isObject) { + if ( + 7 === isUnkeyedTopLevelFragment.tag + ? newChild.type === REACT_FRAGMENT_TYPE + : isUnkeyedTopLevelFragment.elementType === newChild.type + ) { + deleteRemainingChildren( + returnFiber, + isUnkeyedTopLevelFragment.sibling + ); + currentFirstChild = useFiber( + isUnkeyedTopLevelFragment, + newChild.type === REACT_FRAGMENT_TYPE + ? newChild.props.children + : newChild.props, + expirationTime + ); + currentFirstChild.ref = coerceRef( + returnFiber, + isUnkeyedTopLevelFragment, + newChild + ); + currentFirstChild.return = returnFiber; + returnFiber = currentFirstChild; + break a; + } + deleteRemainingChildren(returnFiber, isUnkeyedTopLevelFragment); + break; + } else deleteChild(returnFiber, isUnkeyedTopLevelFragment); + isUnkeyedTopLevelFragment = isUnkeyedTopLevelFragment.sibling; + } + newChild.type === REACT_FRAGMENT_TYPE + ? ((currentFirstChild = createFiberFromFragment( + newChild.props.children, + returnFiber.mode, + expirationTime, + newChild.key + )), + (currentFirstChild.return = returnFiber), + (returnFiber = currentFirstChild)) + : ((expirationTime = createFiberFromTypeAndProps( + newChild.type, + newChild.key, + newChild.props, + null, + returnFiber.mode, + expirationTime + )), + (expirationTime.ref = coerceRef( + returnFiber, + currentFirstChild, + newChild + )), + (expirationTime.return = returnFiber), + (returnFiber = expirationTime)); + } + return placeSingleChild(returnFiber); + case REACT_PORTAL_TYPE: + a: { + for ( + isUnkeyedTopLevelFragment = newChild.key; + null !== currentFirstChild; + + ) { + if (currentFirstChild.key === isUnkeyedTopLevelFragment) { + if ( + 4 === currentFirstChild.tag && + currentFirstChild.stateNode.containerInfo === + newChild.containerInfo && + currentFirstChild.stateNode.implementation === + newChild.implementation + ) { + deleteRemainingChildren( + returnFiber, + currentFirstChild.sibling + ); + currentFirstChild = useFiber( + currentFirstChild, + newChild.children || [], + expirationTime + ); + currentFirstChild.return = returnFiber; + returnFiber = currentFirstChild; + break a; + } + deleteRemainingChildren(returnFiber, currentFirstChild); + break; + } else deleteChild(returnFiber, currentFirstChild); + currentFirstChild = currentFirstChild.sibling; + } + currentFirstChild = createFiberFromPortal( + newChild, + returnFiber.mode, + expirationTime + ); + currentFirstChild.return = returnFiber; + returnFiber = currentFirstChild; + } + return placeSingleChild(returnFiber); + } + if ("string" === typeof newChild || "number" === typeof newChild) + return ( + (newChild = "" + newChild), + null !== currentFirstChild && 6 === currentFirstChild.tag + ? (deleteRemainingChildren(returnFiber, currentFirstChild.sibling), + (currentFirstChild = useFiber( + currentFirstChild, + newChild, + expirationTime + )), + (currentFirstChild.return = returnFiber), + (returnFiber = currentFirstChild)) + : (deleteRemainingChildren(returnFiber, currentFirstChild), + (currentFirstChild = createFiberFromText( + newChild, + returnFiber.mode, + expirationTime + )), + (currentFirstChild.return = returnFiber), + (returnFiber = currentFirstChild)), + placeSingleChild(returnFiber) + ); + if (isArray(newChild)) + return reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ); + if (getIteratorFn(newChild)) + return reconcileChildrenIterator( + returnFiber, + currentFirstChild, + newChild, + expirationTime + ); + isObject && throwOnInvalidObjectType(returnFiber, newChild); + if ("undefined" === typeof newChild && !isUnkeyedTopLevelFragment) + switch (returnFiber.tag) { + case 1: + case 0: + throw ((returnFiber = returnFiber.type), + ReactError( + (returnFiber.displayName || returnFiber.name || "Component") + + "(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null." + )); + } + return deleteRemainingChildren(returnFiber, currentFirstChild); + }; +} +var reconcileChildFibers = ChildReconciler(!0), + mountChildFibers = ChildReconciler(!1), + NO_CONTEXT = {}, + contextStackCursor$1 = { current: NO_CONTEXT }, + contextFiberStackCursor = { current: NO_CONTEXT }, + rootInstanceStackCursor = { current: NO_CONTEXT }; +function requiredContext(c) { + if (c === NO_CONTEXT) + throw ReactError( + "Expected host context to exist. This error is likely caused by a bug in React. Please file an issue." + ); + return c; +} +function pushHostContainer(fiber, nextRootInstance) { + push(rootInstanceStackCursor, nextRootInstance, fiber); + push(contextFiberStackCursor, fiber, fiber); + push(contextStackCursor$1, NO_CONTEXT, fiber); + pop(contextStackCursor$1, fiber); + push(contextStackCursor$1, { isInAParentText: !1 }, fiber); +} +function popHostContainer(fiber) { + pop(contextStackCursor$1, fiber); + pop(contextFiberStackCursor, fiber); + pop(rootInstanceStackCursor, fiber); +} +function pushHostContext(fiber) { + requiredContext(rootInstanceStackCursor.current); + var context = requiredContext(contextStackCursor$1.current); + var nextContext = fiber.type; + nextContext = + "AndroidTextInput" === nextContext || + "RCTMultilineTextInputView" === nextContext || + "RCTSinglelineTextInputView" === nextContext || + "RCTText" === nextContext || + "RCTVirtualText" === nextContext; + nextContext = + context.isInAParentText !== nextContext + ? { isInAParentText: nextContext } + : context; + context !== nextContext && + (push(contextFiberStackCursor, fiber, fiber), + push(contextStackCursor$1, nextContext, fiber)); +} +function popHostContext(fiber) { + contextFiberStackCursor.current === fiber && + (pop(contextStackCursor$1, fiber), pop(contextFiberStackCursor, fiber)); +} +var NoEffect$1 = 0, + UnmountSnapshot = 2, + UnmountMutation = 4, + MountMutation = 8, + UnmountLayout = 16, + MountLayout = 32, + MountPassive = 64, + UnmountPassive = 128, + ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher, + renderExpirationTime$1 = 0, + currentlyRenderingFiber$1 = null, + currentHook = null, + nextCurrentHook = null, + firstWorkInProgressHook = null, + workInProgressHook = null, + nextWorkInProgressHook = null, + remainingExpirationTime = 0, + componentUpdateQueue = null, + sideEffectTag = 0, + didScheduleRenderPhaseUpdate = !1, + renderPhaseUpdates = null, + numberOfReRenders = 0; +function throwInvalidHookError() { + throw ReactError( + "Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:\n1. You might have mismatching versions of React and the renderer (such as React DOM)\n2. You might be breaking the Rules of Hooks\n3. You might have more than one copy of React in the same app\nSee https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem." + ); +} +function areHookInputsEqual(nextDeps, prevDeps) { + if (null === prevDeps) return !1; + for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++) + if (!is(nextDeps[i], prevDeps[i])) return !1; + return !0; +} +function renderWithHooks( + current, + workInProgress, + Component, + props, + refOrContext, + nextRenderExpirationTime +) { + renderExpirationTime$1 = nextRenderExpirationTime; + currentlyRenderingFiber$1 = workInProgress; + nextCurrentHook = null !== current ? current.memoizedState : null; + ReactCurrentDispatcher$1.current = + null === nextCurrentHook ? HooksDispatcherOnMount : HooksDispatcherOnUpdate; + workInProgress = Component(props, refOrContext); + if (didScheduleRenderPhaseUpdate) { + do + (didScheduleRenderPhaseUpdate = !1), + (numberOfReRenders += 1), + (nextCurrentHook = null !== current ? current.memoizedState : null), + (nextWorkInProgressHook = firstWorkInProgressHook), + (componentUpdateQueue = workInProgressHook = currentHook = null), + (ReactCurrentDispatcher$1.current = HooksDispatcherOnUpdate), + (workInProgress = Component(props, refOrContext)); + while (didScheduleRenderPhaseUpdate); + renderPhaseUpdates = null; + numberOfReRenders = 0; + } + ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; + current = currentlyRenderingFiber$1; + current.memoizedState = firstWorkInProgressHook; + current.expirationTime = remainingExpirationTime; + current.updateQueue = componentUpdateQueue; + current.effectTag |= sideEffectTag; + current = null !== currentHook && null !== currentHook.next; + renderExpirationTime$1 = 0; + nextWorkInProgressHook = workInProgressHook = firstWorkInProgressHook = nextCurrentHook = currentHook = currentlyRenderingFiber$1 = null; + remainingExpirationTime = 0; + componentUpdateQueue = null; + sideEffectTag = 0; + if (current) + throw ReactError( + "Rendered fewer hooks than expected. This may be caused by an accidental early return statement." + ); + return workInProgress; +} +function resetHooks() { + ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; + renderExpirationTime$1 = 0; + nextWorkInProgressHook = workInProgressHook = firstWorkInProgressHook = nextCurrentHook = currentHook = currentlyRenderingFiber$1 = null; + remainingExpirationTime = 0; + componentUpdateQueue = null; + sideEffectTag = 0; + didScheduleRenderPhaseUpdate = !1; + renderPhaseUpdates = null; + numberOfReRenders = 0; +} +function mountWorkInProgressHook() { + var hook = { + memoizedState: null, + baseState: null, + queue: null, + baseUpdate: null, + next: null + }; + null === workInProgressHook + ? (firstWorkInProgressHook = workInProgressHook = hook) + : (workInProgressHook = workInProgressHook.next = hook); + return workInProgressHook; +} +function updateWorkInProgressHook() { + if (null !== nextWorkInProgressHook) + (workInProgressHook = nextWorkInProgressHook), + (nextWorkInProgressHook = workInProgressHook.next), + (currentHook = nextCurrentHook), + (nextCurrentHook = null !== currentHook ? currentHook.next : null); + else { + if (null === nextCurrentHook) + throw ReactError("Rendered more hooks than during the previous render."); + currentHook = nextCurrentHook; + var newHook = { + memoizedState: currentHook.memoizedState, + baseState: currentHook.baseState, + queue: currentHook.queue, + baseUpdate: currentHook.baseUpdate, + next: null + }; + workInProgressHook = + null === workInProgressHook + ? (firstWorkInProgressHook = newHook) + : (workInProgressHook.next = newHook); + nextCurrentHook = currentHook.next; + } + return workInProgressHook; +} +function basicStateReducer(state, action) { + return "function" === typeof action ? action(state) : action; +} +function updateReducer(reducer) { + var hook = updateWorkInProgressHook(), + queue = hook.queue; + if (null === queue) + throw ReactError( + "Should have a queue. This is likely a bug in React. Please file an issue." + ); + queue.lastRenderedReducer = reducer; + if (0 < numberOfReRenders) { + var _dispatch = queue.dispatch; + if (null !== renderPhaseUpdates) { + var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue); + if (void 0 !== firstRenderPhaseUpdate) { + renderPhaseUpdates.delete(queue); + var newState = hook.memoizedState; + do + (newState = reducer(newState, firstRenderPhaseUpdate.action)), + (firstRenderPhaseUpdate = firstRenderPhaseUpdate.next); + while (null !== firstRenderPhaseUpdate); + is(newState, hook.memoizedState) || (didReceiveUpdate = !0); + hook.memoizedState = newState; + hook.baseUpdate === queue.last && (hook.baseState = newState); + queue.lastRenderedState = newState; + return [newState, _dispatch]; + } + } + return [hook.memoizedState, _dispatch]; + } + _dispatch = queue.last; + var baseUpdate = hook.baseUpdate; + newState = hook.baseState; + null !== baseUpdate + ? (null !== _dispatch && (_dispatch.next = null), + (_dispatch = baseUpdate.next)) + : (_dispatch = null !== _dispatch ? _dispatch.next : null); + if (null !== _dispatch) { + var newBaseUpdate = (firstRenderPhaseUpdate = null), + _update = _dispatch, + didSkip = !1; + do { + var updateExpirationTime = _update.expirationTime; + updateExpirationTime < renderExpirationTime$1 + ? (didSkip || + ((didSkip = !0), + (newBaseUpdate = baseUpdate), + (firstRenderPhaseUpdate = newState)), + updateExpirationTime > remainingExpirationTime && + (remainingExpirationTime = updateExpirationTime)) + : (updateExpirationTime < workInProgressRootMostRecentEventTime && + (workInProgressRootMostRecentEventTime = updateExpirationTime), + (newState = + _update.eagerReducer === reducer + ? _update.eagerState + : reducer(newState, _update.action))); + baseUpdate = _update; + _update = _update.next; + } while (null !== _update && _update !== _dispatch); + didSkip || + ((newBaseUpdate = baseUpdate), (firstRenderPhaseUpdate = newState)); + is(newState, hook.memoizedState) || (didReceiveUpdate = !0); + hook.memoizedState = newState; + hook.baseUpdate = newBaseUpdate; + hook.baseState = firstRenderPhaseUpdate; + queue.lastRenderedState = newState; + } + return [hook.memoizedState, queue.dispatch]; +} +function pushEffect(tag, create, destroy, deps) { + tag = { tag: tag, create: create, destroy: destroy, deps: deps, next: null }; + null === componentUpdateQueue + ? ((componentUpdateQueue = { lastEffect: null }), + (componentUpdateQueue.lastEffect = tag.next = tag)) + : ((create = componentUpdateQueue.lastEffect), + null === create + ? (componentUpdateQueue.lastEffect = tag.next = tag) + : ((destroy = create.next), + (create.next = tag), + (tag.next = destroy), + (componentUpdateQueue.lastEffect = tag))); + return tag; +} +function mountEffectImpl(fiberEffectTag, hookEffectTag, create, deps) { + var hook = mountWorkInProgressHook(); + sideEffectTag |= fiberEffectTag; + hook.memoizedState = pushEffect( + hookEffectTag, + create, + void 0, + void 0 === deps ? null : deps + ); +} +function updateEffectImpl(fiberEffectTag, hookEffectTag, create, deps) { + var hook = updateWorkInProgressHook(); + deps = void 0 === deps ? null : deps; + var destroy = void 0; + if (null !== currentHook) { + var prevEffect = currentHook.memoizedState; + destroy = prevEffect.destroy; + if (null !== deps && areHookInputsEqual(deps, prevEffect.deps)) { + pushEffect(NoEffect$1, create, destroy, deps); + return; + } + } + sideEffectTag |= fiberEffectTag; + hook.memoizedState = pushEffect(hookEffectTag, create, destroy, deps); +} +function imperativeHandleEffect(create, ref) { + if ("function" === typeof ref) + return ( + (create = create()), + ref(create), + function() { + ref(null); + } + ); + if (null !== ref && void 0 !== ref) + return ( + (create = create()), + (ref.current = create), + function() { + ref.current = null; + } + ); +} +function mountDebugValue() {} +function dispatchAction(fiber, queue, action) { + if (!(25 > numberOfReRenders)) + throw ReactError( + "Too many re-renders. React limits the number of renders to prevent an infinite loop." + ); + var alternate = fiber.alternate; + if ( + fiber === currentlyRenderingFiber$1 || + (null !== alternate && alternate === currentlyRenderingFiber$1) + ) + if ( + ((didScheduleRenderPhaseUpdate = !0), + (fiber = { + expirationTime: renderExpirationTime$1, + action: action, + eagerReducer: null, + eagerState: null, + next: null + }), + null === renderPhaseUpdates && (renderPhaseUpdates = new Map()), + (action = renderPhaseUpdates.get(queue)), + void 0 === action) + ) + renderPhaseUpdates.set(queue, fiber); + else { + for (queue = action; null !== queue.next; ) queue = queue.next; + queue.next = fiber; + } + else { + flushPassiveEffects(); + var currentTime = requestCurrentTime(); + currentTime = computeExpirationForFiber(currentTime, fiber); + var _update2 = { + expirationTime: currentTime, + action: action, + eagerReducer: null, + eagerState: null, + next: null + }, + _last = queue.last; + if (null === _last) _update2.next = _update2; + else { + var first = _last.next; + null !== first && (_update2.next = first); + _last.next = _update2; + } + queue.last = _update2; + if ( + 0 === fiber.expirationTime && + (null === alternate || 0 === alternate.expirationTime) && + ((alternate = queue.lastRenderedReducer), null !== alternate) + ) + try { + var currentState = queue.lastRenderedState, + _eagerState = alternate(currentState, action); + _update2.eagerReducer = alternate; + _update2.eagerState = _eagerState; + if (is(_eagerState, currentState)) return; + } catch (error) { + } finally { + } + scheduleUpdateOnFiber(fiber, currentTime); + } +} +var ContextOnlyDispatcher = { + readContext: readContext, + useCallback: throwInvalidHookError, + useContext: throwInvalidHookError, + useEffect: throwInvalidHookError, + useImperativeHandle: throwInvalidHookError, + useLayoutEffect: throwInvalidHookError, + useMemo: throwInvalidHookError, + useReducer: throwInvalidHookError, + useRef: throwInvalidHookError, + useState: throwInvalidHookError, + useDebugValue: throwInvalidHookError + }, + HooksDispatcherOnMount = { + readContext: readContext, + useCallback: function(callback, deps) { + mountWorkInProgressHook().memoizedState = [ + callback, + void 0 === deps ? null : deps + ]; + return callback; + }, + useContext: readContext, + useEffect: function(create, deps) { + return mountEffectImpl(516, UnmountPassive | MountPassive, create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + deps = null !== deps && void 0 !== deps ? deps.concat([ref]) : null; + return mountEffectImpl( + 4, + UnmountMutation | MountLayout, + imperativeHandleEffect.bind(null, create, ref), + deps + ); + }, + useLayoutEffect: function(create, deps) { + return mountEffectImpl(4, UnmountMutation | MountLayout, create, deps); + }, + useMemo: function(nextCreate, deps) { + var hook = mountWorkInProgressHook(); + deps = void 0 === deps ? null : deps; + nextCreate = nextCreate(); + hook.memoizedState = [nextCreate, deps]; + return nextCreate; + }, + useReducer: function(reducer, initialArg, init) { + var hook = mountWorkInProgressHook(); + initialArg = void 0 !== init ? init(initialArg) : initialArg; + hook.memoizedState = hook.baseState = initialArg; + reducer = hook.queue = { + last: null, + dispatch: null, + lastRenderedReducer: reducer, + lastRenderedState: initialArg + }; + reducer = reducer.dispatch = dispatchAction.bind( + null, + currentlyRenderingFiber$1, + reducer + ); + return [hook.memoizedState, reducer]; + }, + useRef: function(initialValue) { + var hook = mountWorkInProgressHook(); + initialValue = { current: initialValue }; + return (hook.memoizedState = initialValue); + }, + useState: function(initialState) { + var hook = mountWorkInProgressHook(); + "function" === typeof initialState && (initialState = initialState()); + hook.memoizedState = hook.baseState = initialState; + initialState = hook.queue = { + last: null, + dispatch: null, + lastRenderedReducer: basicStateReducer, + lastRenderedState: initialState + }; + initialState = initialState.dispatch = dispatchAction.bind( + null, + currentlyRenderingFiber$1, + initialState + ); + return [hook.memoizedState, initialState]; + }, + useDebugValue: mountDebugValue + }, + HooksDispatcherOnUpdate = { + readContext: readContext, + useCallback: function(callback, deps) { + var hook = updateWorkInProgressHook(); + deps = void 0 === deps ? null : deps; + var prevState = hook.memoizedState; + if ( + null !== prevState && + null !== deps && + areHookInputsEqual(deps, prevState[1]) + ) + return prevState[0]; + hook.memoizedState = [callback, deps]; + return callback; + }, + useContext: readContext, + useEffect: function(create, deps) { + return updateEffectImpl(516, UnmountPassive | MountPassive, create, deps); + }, + useImperativeHandle: function(ref, create, deps) { + deps = null !== deps && void 0 !== deps ? deps.concat([ref]) : null; + return updateEffectImpl( + 4, + UnmountMutation | MountLayout, + imperativeHandleEffect.bind(null, create, ref), + deps + ); + }, + useLayoutEffect: function(create, deps) { + return updateEffectImpl(4, UnmountMutation | MountLayout, create, deps); + }, + useMemo: function(nextCreate, deps) { + var hook = updateWorkInProgressHook(); + deps = void 0 === deps ? null : deps; + var prevState = hook.memoizedState; + if ( + null !== prevState && + null !== deps && + areHookInputsEqual(deps, prevState[1]) + ) + return prevState[0]; + nextCreate = nextCreate(); + hook.memoizedState = [nextCreate, deps]; + return nextCreate; + }, + useReducer: updateReducer, + useRef: function() { + return updateWorkInProgressHook().memoizedState; + }, + useState: function(initialState) { + return updateReducer(basicStateReducer, initialState); + }, + useDebugValue: mountDebugValue + }, + now$1 = Scheduler.unstable_now, + commitTime = 0, + profilerStartTime = -1; +function stopProfilerTimerIfRunningAndRecordDelta(fiber, overrideBaseTime) { + if (0 <= profilerStartTime) { + var elapsedTime = now$1() - profilerStartTime; + fiber.actualDuration += elapsedTime; + overrideBaseTime && (fiber.selfBaseDuration = elapsedTime); + profilerStartTime = -1; + } +} +var hydrationParentFiber = null, + nextHydratableInstance = null, + isHydrating = !1; +function tryHydrate(fiber, nextInstance) { + switch (fiber.tag) { + case 5: + return ( + (nextInstance = shim$1(nextInstance, fiber.type, fiber.pendingProps)), + null !== nextInstance ? ((fiber.stateNode = nextInstance), !0) : !1 + ); + case 6: + return ( + (nextInstance = shim$1(nextInstance, fiber.pendingProps)), + null !== nextInstance ? ((fiber.stateNode = nextInstance), !0) : !1 + ); + case 13: + return !1; + default: + return !1; + } +} +function tryToClaimNextHydratableInstance(fiber$jscomp$0) { + if (isHydrating) { + var nextInstance = nextHydratableInstance; + if (nextInstance) { + var firstAttemptedInstance = nextInstance; + if (!tryHydrate(fiber$jscomp$0, nextInstance)) { + nextInstance = shim$1(firstAttemptedInstance); + if (!nextInstance || !tryHydrate(fiber$jscomp$0, nextInstance)) { + fiber$jscomp$0.effectTag |= 2; + isHydrating = !1; + hydrationParentFiber = fiber$jscomp$0; + return; + } + var returnFiber = hydrationParentFiber, + fiber = createFiber(5, null, null, 0); + fiber.elementType = "DELETED"; + fiber.type = "DELETED"; + fiber.stateNode = firstAttemptedInstance; + fiber.return = returnFiber; + fiber.effectTag = 8; + null !== returnFiber.lastEffect + ? ((returnFiber.lastEffect.nextEffect = fiber), + (returnFiber.lastEffect = fiber)) + : (returnFiber.firstEffect = returnFiber.lastEffect = fiber); + } + hydrationParentFiber = fiber$jscomp$0; + nextHydratableInstance = shim$1(nextInstance); + } else + (fiber$jscomp$0.effectTag |= 2), + (isHydrating = !1), + (hydrationParentFiber = fiber$jscomp$0); + } +} +var ReactCurrentOwner$3 = ReactSharedInternals.ReactCurrentOwner, + didReceiveUpdate = !1; +function reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime +) { + workInProgress.child = + null === current$$1 + ? mountChildFibers( + workInProgress, + null, + nextChildren, + renderExpirationTime + ) + : reconcileChildFibers( + workInProgress, + current$$1.child, + nextChildren, + renderExpirationTime + ); +} +function updateForwardRef( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + Component = Component.render; + var ref = workInProgress.ref; + prepareToReadContext(workInProgress, renderExpirationTime); + nextProps = renderWithHooks( + current$$1, + workInProgress, + Component, + nextProps, + ref, + renderExpirationTime + ); + if (null !== current$$1 && !didReceiveUpdate) + return ( + (workInProgress.updateQueue = current$$1.updateQueue), + (workInProgress.effectTag &= -517), + current$$1.expirationTime <= renderExpirationTime && + (current$$1.expirationTime = 0), + bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ) + ); + workInProgress.effectTag |= 1; + reconcileChildren( + current$$1, + workInProgress, + nextProps, + renderExpirationTime + ); + return workInProgress.child; +} +function updateMemoComponent( + current$$1, + workInProgress, + Component, + nextProps, + updateExpirationTime, + renderExpirationTime +) { + if (null === current$$1) { + var type = Component.type; + if ( + "function" === typeof type && + !shouldConstruct(type) && + void 0 === type.defaultProps && + null === Component.compare && + void 0 === Component.defaultProps + ) + return ( + (workInProgress.tag = 15), + (workInProgress.type = type), + updateSimpleMemoComponent( + current$$1, + workInProgress, + type, + nextProps, + updateExpirationTime, + renderExpirationTime + ) + ); + current$$1 = createFiberFromTypeAndProps( + Component.type, + null, + nextProps, + null, + workInProgress.mode, + renderExpirationTime + ); + current$$1.ref = workInProgress.ref; + current$$1.return = workInProgress; + return (workInProgress.child = current$$1); + } + type = current$$1.child; + if ( + updateExpirationTime < renderExpirationTime && + ((updateExpirationTime = type.memoizedProps), + (Component = Component.compare), + (Component = null !== Component ? Component : shallowEqual), + Component(updateExpirationTime, nextProps) && + current$$1.ref === workInProgress.ref) + ) + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + workInProgress.effectTag |= 1; + current$$1 = createWorkInProgress(type, nextProps, renderExpirationTime); + current$$1.ref = workInProgress.ref; + current$$1.return = workInProgress; + return (workInProgress.child = current$$1); +} +function updateSimpleMemoComponent( + current$$1, + workInProgress, + Component, + nextProps, + updateExpirationTime, + renderExpirationTime +) { + return null !== current$$1 && + shallowEqual(current$$1.memoizedProps, nextProps) && + current$$1.ref === workInProgress.ref && + ((didReceiveUpdate = !1), updateExpirationTime < renderExpirationTime) + ? bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ) + : updateFunctionComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime + ); +} +function markRef(current$$1, workInProgress) { + var ref = workInProgress.ref; + if ( + (null === current$$1 && null !== ref) || + (null !== current$$1 && current$$1.ref !== ref) + ) + workInProgress.effectTag |= 128; +} +function updateFunctionComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + var unmaskedContext = isContextProvider(Component) + ? previousContext + : contextStackCursor.current; + unmaskedContext = getMaskedContext(workInProgress, unmaskedContext); + prepareToReadContext(workInProgress, renderExpirationTime); + Component = renderWithHooks( + current$$1, + workInProgress, + Component, + nextProps, + unmaskedContext, + renderExpirationTime + ); + if (null !== current$$1 && !didReceiveUpdate) + return ( + (workInProgress.updateQueue = current$$1.updateQueue), + (workInProgress.effectTag &= -517), + current$$1.expirationTime <= renderExpirationTime && + (current$$1.expirationTime = 0), + bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ) + ); + workInProgress.effectTag |= 1; + reconcileChildren( + current$$1, + workInProgress, + Component, + renderExpirationTime + ); + return workInProgress.child; +} +function updateClassComponent( + current$$1, + workInProgress, + Component, + nextProps, + renderExpirationTime +) { + if (isContextProvider(Component)) { + var hasContext = !0; + pushContextProvider(workInProgress); + } else hasContext = !1; + prepareToReadContext(workInProgress, renderExpirationTime); + if (null === workInProgress.stateNode) + null !== current$$1 && + ((current$$1.alternate = null), + (workInProgress.alternate = null), + (workInProgress.effectTag |= 2)), + constructClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ), + mountClassInstance( + workInProgress, + Component, + nextProps, + renderExpirationTime + ), + (nextProps = !0); + else if (null === current$$1) { + var instance = workInProgress.stateNode, + oldProps = workInProgress.memoizedProps; + instance.props = oldProps; + var oldContext = instance.context, + contextType = Component.contextType; + "object" === typeof contextType && null !== contextType + ? (contextType = readContext(contextType)) + : ((contextType = isContextProvider(Component) + ? previousContext + : contextStackCursor.current), + (contextType = getMaskedContext(workInProgress, contextType))); + var getDerivedStateFromProps = Component.getDerivedStateFromProps, + hasNewLifecycles = + "function" === typeof getDerivedStateFromProps || + "function" === typeof instance.getSnapshotBeforeUpdate; + hasNewLifecycles || + ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && + "function" !== typeof instance.componentWillReceiveProps) || + ((oldProps !== nextProps || oldContext !== contextType) && + callComponentWillReceiveProps( + workInProgress, + instance, + nextProps, + contextType + )); + hasForceUpdate = !1; + var oldState = workInProgress.memoizedState; + oldContext = instance.state = oldState; + var updateQueue = workInProgress.updateQueue; + null !== updateQueue && + (processUpdateQueue( + workInProgress, + updateQueue, + nextProps, + instance, + renderExpirationTime + ), + (oldContext = workInProgress.memoizedState)); + oldProps !== nextProps || + oldState !== oldContext || + didPerformWorkStackCursor.current || + hasForceUpdate + ? ("function" === typeof getDerivedStateFromProps && + (applyDerivedStateFromProps( + workInProgress, + Component, + getDerivedStateFromProps, + nextProps + ), + (oldContext = workInProgress.memoizedState)), + (oldProps = + hasForceUpdate || + checkShouldComponentUpdate( + workInProgress, + Component, + oldProps, + nextProps, + oldState, + oldContext, + contextType + )) + ? (hasNewLifecycles || + ("function" !== typeof instance.UNSAFE_componentWillMount && + "function" !== typeof instance.componentWillMount) || + ("function" === typeof instance.componentWillMount && + instance.componentWillMount(), + "function" === typeof instance.UNSAFE_componentWillMount && + instance.UNSAFE_componentWillMount()), + "function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4)) + : ("function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4), + (workInProgress.memoizedProps = nextProps), + (workInProgress.memoizedState = oldContext)), + (instance.props = nextProps), + (instance.state = oldContext), + (instance.context = contextType), + (nextProps = oldProps)) + : ("function" === typeof instance.componentDidMount && + (workInProgress.effectTag |= 4), + (nextProps = !1)); + } else + (instance = workInProgress.stateNode), + (oldProps = workInProgress.memoizedProps), + (instance.props = + workInProgress.type === workInProgress.elementType + ? oldProps + : resolveDefaultProps(workInProgress.type, oldProps)), + (oldContext = instance.context), + (contextType = Component.contextType), + "object" === typeof contextType && null !== contextType + ? (contextType = readContext(contextType)) + : ((contextType = isContextProvider(Component) + ? previousContext + : contextStackCursor.current), + (contextType = getMaskedContext(workInProgress, contextType))), + (getDerivedStateFromProps = Component.getDerivedStateFromProps), + (hasNewLifecycles = + "function" === typeof getDerivedStateFromProps || + "function" === typeof instance.getSnapshotBeforeUpdate) || + ("function" !== typeof instance.UNSAFE_componentWillReceiveProps && + "function" !== typeof instance.componentWillReceiveProps) || + ((oldProps !== nextProps || oldContext !== contextType) && + callComponentWillReceiveProps( + workInProgress, + instance, + nextProps, + contextType + )), + (hasForceUpdate = !1), + (oldContext = workInProgress.memoizedState), + (oldState = instance.state = oldContext), + (updateQueue = workInProgress.updateQueue), + null !== updateQueue && + (processUpdateQueue( + workInProgress, + updateQueue, + nextProps, + instance, + renderExpirationTime + ), + (oldState = workInProgress.memoizedState)), + oldProps !== nextProps || + oldContext !== oldState || + didPerformWorkStackCursor.current || + hasForceUpdate + ? ("function" === typeof getDerivedStateFromProps && + (applyDerivedStateFromProps( + workInProgress, + Component, + getDerivedStateFromProps, + nextProps + ), + (oldState = workInProgress.memoizedState)), + (getDerivedStateFromProps = + hasForceUpdate || + checkShouldComponentUpdate( + workInProgress, + Component, + oldProps, + nextProps, + oldContext, + oldState, + contextType + )) + ? (hasNewLifecycles || + ("function" !== typeof instance.UNSAFE_componentWillUpdate && + "function" !== typeof instance.componentWillUpdate) || + ("function" === typeof instance.componentWillUpdate && + instance.componentWillUpdate( + nextProps, + oldState, + contextType + ), + "function" === typeof instance.UNSAFE_componentWillUpdate && + instance.UNSAFE_componentWillUpdate( + nextProps, + oldState, + contextType + )), + "function" === typeof instance.componentDidUpdate && + (workInProgress.effectTag |= 4), + "function" === typeof instance.getSnapshotBeforeUpdate && + (workInProgress.effectTag |= 256)) + : ("function" !== typeof instance.componentDidUpdate || + (oldProps === current$$1.memoizedProps && + oldContext === current$$1.memoizedState) || + (workInProgress.effectTag |= 4), + "function" !== typeof instance.getSnapshotBeforeUpdate || + (oldProps === current$$1.memoizedProps && + oldContext === current$$1.memoizedState) || + (workInProgress.effectTag |= 256), + (workInProgress.memoizedProps = nextProps), + (workInProgress.memoizedState = oldState)), + (instance.props = nextProps), + (instance.state = oldState), + (instance.context = contextType), + (nextProps = getDerivedStateFromProps)) + : ("function" !== typeof instance.componentDidUpdate || + (oldProps === current$$1.memoizedProps && + oldContext === current$$1.memoizedState) || + (workInProgress.effectTag |= 4), + "function" !== typeof instance.getSnapshotBeforeUpdate || + (oldProps === current$$1.memoizedProps && + oldContext === current$$1.memoizedState) || + (workInProgress.effectTag |= 256), + (nextProps = !1)); + return finishClassComponent( + current$$1, + workInProgress, + Component, + nextProps, + hasContext, + renderExpirationTime + ); +} +function finishClassComponent( + current$$1, + workInProgress, + Component, + shouldUpdate, + hasContext, + renderExpirationTime +) { + markRef(current$$1, workInProgress); + var didCaptureError = 0 !== (workInProgress.effectTag & 64); + if (!shouldUpdate && !didCaptureError) + return ( + hasContext && invalidateContextProvider(workInProgress, Component, !1), + bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ) + ); + shouldUpdate = workInProgress.stateNode; + ReactCurrentOwner$3.current = workInProgress; + if ( + didCaptureError && + "function" !== typeof Component.getDerivedStateFromError + ) { + var nextChildren = null; + profilerStartTime = -1; + } else nextChildren = shouldUpdate.render(); + workInProgress.effectTag |= 1; + null !== current$$1 && didCaptureError + ? ((didCaptureError = nextChildren), + (workInProgress.child = reconcileChildFibers( + workInProgress, + current$$1.child, + null, + renderExpirationTime + )), + (workInProgress.child = reconcileChildFibers( + workInProgress, + null, + didCaptureError, + renderExpirationTime + ))) + : reconcileChildren( + current$$1, + workInProgress, + nextChildren, + renderExpirationTime + ); + workInProgress.memoizedState = shouldUpdate.state; + hasContext && invalidateContextProvider(workInProgress, Component, !0); + return workInProgress.child; +} +function pushHostRootContext(workInProgress) { + var root = workInProgress.stateNode; + root.pendingContext + ? pushTopLevelContextObject( + workInProgress, + root.pendingContext, + root.pendingContext !== root.context + ) + : root.context && + pushTopLevelContextObject(workInProgress, root.context, !1); + pushHostContainer(workInProgress, root.containerInfo); +} +function updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime +) { + var mode = workInProgress.mode, + nextProps = workInProgress.pendingProps, + nextState = workInProgress.memoizedState; + if (0 === (workInProgress.effectTag & 64)) { + nextState = null; + var nextDidTimeout = !1; + } else + (nextState = { + fallbackExpirationTime: + null !== nextState ? nextState.fallbackExpirationTime : 0 + }), + (nextDidTimeout = !0), + (workInProgress.effectTag &= -65); + if (null === current$$1) + if (nextDidTimeout) { + var nextFallbackChildren = nextProps.fallback; + current$$1 = createFiberFromFragment(null, mode, 0, null); + 0 === (workInProgress.mode & 1) && + (current$$1.child = + null !== workInProgress.memoizedState + ? workInProgress.child.child + : workInProgress.child); + renderExpirationTime = createFiberFromFragment( + nextFallbackChildren, + mode, + renderExpirationTime, + null + ); + current$$1.sibling = renderExpirationTime; + mode = current$$1; + mode.return = renderExpirationTime.return = workInProgress; + } else + mode = renderExpirationTime = mountChildFibers( + workInProgress, + null, + nextProps.children, + renderExpirationTime + ); + else { + if (null !== current$$1.memoizedState) + if ( + ((nextFallbackChildren = current$$1.child), + (mode = nextFallbackChildren.sibling), + nextDidTimeout) + ) { + nextProps = nextProps.fallback; + renderExpirationTime = createWorkInProgress( + nextFallbackChildren, + nextFallbackChildren.pendingProps, + 0 + ); + 0 === (workInProgress.mode & 1) && + ((nextDidTimeout = + null !== workInProgress.memoizedState + ? workInProgress.child.child + : workInProgress.child), + nextDidTimeout !== nextFallbackChildren.child && + (renderExpirationTime.child = nextDidTimeout)); + if (workInProgress.mode & 4) { + nextFallbackChildren = 0; + for ( + nextDidTimeout = renderExpirationTime.child; + null !== nextDidTimeout; + + ) + (nextFallbackChildren += nextDidTimeout.treeBaseDuration), + (nextDidTimeout = nextDidTimeout.sibling); + renderExpirationTime.treeBaseDuration = nextFallbackChildren; + } + nextFallbackChildren = renderExpirationTime.sibling = createWorkInProgress( + mode, + nextProps, + mode.expirationTime + ); + mode = renderExpirationTime; + renderExpirationTime.childExpirationTime = 0; + renderExpirationTime = nextFallbackChildren; + mode.return = renderExpirationTime.return = workInProgress; + } else + mode = renderExpirationTime = reconcileChildFibers( + workInProgress, + nextFallbackChildren.child, + nextProps.children, + renderExpirationTime + ); + else { + var _currentPrimaryChild = current$$1.child; + if (nextDidTimeout) { + nextProps = nextProps.fallback; + nextFallbackChildren = createFiberFromFragment(null, mode, 0, null); + nextFallbackChildren.child = _currentPrimaryChild; + 0 === (workInProgress.mode & 1) && + (nextFallbackChildren.child = + null !== workInProgress.memoizedState + ? workInProgress.child.child + : workInProgress.child); + if (workInProgress.mode & 4) { + nextDidTimeout = 0; + for ( + _currentPrimaryChild = nextFallbackChildren.child; + null !== _currentPrimaryChild; + + ) + (nextDidTimeout += _currentPrimaryChild.treeBaseDuration), + (_currentPrimaryChild = _currentPrimaryChild.sibling); + nextFallbackChildren.treeBaseDuration = nextDidTimeout; + } + renderExpirationTime = nextFallbackChildren.sibling = createFiberFromFragment( + nextProps, + mode, + renderExpirationTime, + null + ); + renderExpirationTime.effectTag |= 2; + mode = nextFallbackChildren; + nextFallbackChildren.childExpirationTime = 0; + mode.return = renderExpirationTime.return = workInProgress; + } else + renderExpirationTime = mode = reconcileChildFibers( + workInProgress, + _currentPrimaryChild, + nextProps.children, + renderExpirationTime + ); + } + workInProgress.stateNode = current$$1.stateNode; + } + workInProgress.memoizedState = nextState; + workInProgress.child = mode; + return renderExpirationTime; +} +function bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime +) { + null !== current$$1 && + (workInProgress.contextDependencies = current$$1.contextDependencies); + profilerStartTime = -1; + if (workInProgress.childExpirationTime < renderExpirationTime) return null; + if (null !== current$$1 && workInProgress.child !== current$$1.child) + throw ReactError("Resuming work not yet implemented."); + if (null !== workInProgress.child) { + current$$1 = workInProgress.child; + renderExpirationTime = createWorkInProgress( + current$$1, + current$$1.pendingProps, + current$$1.expirationTime + ); + workInProgress.child = renderExpirationTime; + for ( + renderExpirationTime.return = workInProgress; + null !== current$$1.sibling; + + ) + (current$$1 = current$$1.sibling), + (renderExpirationTime = renderExpirationTime.sibling = createWorkInProgress( + current$$1, + current$$1.pendingProps, + current$$1.expirationTime + )), + (renderExpirationTime.return = workInProgress); + renderExpirationTime.sibling = null; + } + return workInProgress.child; +} +var appendAllChildren = void 0, + updateHostContainer = void 0, + updateHostComponent$1 = void 0, + updateHostText$1 = void 0; +appendAllChildren = function(parent, workInProgress) { + for (var node = workInProgress.child; null !== node; ) { + if (5 === node.tag || 6 === node.tag) parent._children.push(node.stateNode); + else if (4 !== node.tag && null !== node.child) { + node.child.return = node; + node = node.child; + continue; + } + if (node === workInProgress) break; + for (; null === node.sibling; ) { + if (null === node.return || node.return === workInProgress) return; + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } +}; +updateHostContainer = function() {}; +updateHostComponent$1 = function(current, workInProgress, type, newProps) { + current.memoizedProps !== newProps && + (requiredContext(contextStackCursor$1.current), + (workInProgress.updateQueue = UPDATE_SIGNAL)) && + (workInProgress.effectTag |= 4); +}; +updateHostText$1 = function(current, workInProgress, oldText, newText) { + oldText !== newText && (workInProgress.effectTag |= 4); +}; +function completeWork(current, workInProgress, renderExpirationTime) { + var newProps = workInProgress.pendingProps; + switch (workInProgress.tag) { + case 2: + break; + case 16: + break; + case 15: + case 0: + break; + case 1: + isContextProvider(workInProgress.type) && popContext(workInProgress); + break; + case 3: + popHostContainer(workInProgress); + popTopLevelContextObject(workInProgress); + newProps = workInProgress.stateNode; + newProps.pendingContext && + ((newProps.context = newProps.pendingContext), + (newProps.pendingContext = null)); + if (null === current || null === current.child) + workInProgress.effectTag &= -3; + updateHostContainer(workInProgress); + break; + case 5: + popHostContext(workInProgress); + renderExpirationTime = requiredContext(rootInstanceStackCursor.current); + var type = workInProgress.type; + if (null !== current && null != workInProgress.stateNode) + updateHostComponent$1( + current, + workInProgress, + type, + newProps, + renderExpirationTime + ), + current.ref !== workInProgress.ref && + (workInProgress.effectTag |= 128); + else if (newProps) { + current = requiredContext(contextStackCursor$1.current); + var tag = allocateTag(), + viewConfig = getViewConfigForType(type), + updatePayload = diffProperties( + null, + emptyObject, + newProps, + viewConfig.validAttributes + ); + ReactNativePrivateInterface.UIManager.createView( + tag, + viewConfig.uiViewClassName, + renderExpirationTime, + updatePayload + ); + viewConfig = new ReactNativeFiberHostComponent(tag, viewConfig); + instanceCache[tag] = workInProgress; + instanceProps[tag] = newProps; + appendAllChildren(viewConfig, workInProgress, !1, !1); + finalizeInitialChildren( + viewConfig, + type, + newProps, + renderExpirationTime, + current + ) && (workInProgress.effectTag |= 4); + workInProgress.stateNode = viewConfig; + null !== workInProgress.ref && (workInProgress.effectTag |= 128); + } else if (null === workInProgress.stateNode) + throw ReactError( + "We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue." + ); + break; + case 6: + if (current && null != workInProgress.stateNode) + updateHostText$1( + current, + workInProgress, + current.memoizedProps, + newProps + ); + else { + if ("string" !== typeof newProps && null === workInProgress.stateNode) + throw ReactError( + "We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue." + ); + current = requiredContext(rootInstanceStackCursor.current); + if (!requiredContext(contextStackCursor$1.current).isInAParentText) + throw ReactError( + "Text strings must be rendered within a component." + ); + renderExpirationTime = allocateTag(); + ReactNativePrivateInterface.UIManager.createView( + renderExpirationTime, + "RCTRawText", + current, + { text: newProps } + ); + instanceCache[renderExpirationTime] = workInProgress; + workInProgress.stateNode = renderExpirationTime; + } + break; + case 11: + break; + case 13: + newProps = workInProgress.memoizedState; + if (0 !== (workInProgress.effectTag & 64)) + return ( + (workInProgress.expirationTime = renderExpirationTime), workInProgress + ); + newProps = null !== newProps; + renderExpirationTime = !1; + null !== current && + ((type = current.memoizedState), + (renderExpirationTime = null !== type), + newProps || + null === type || + ((type = type.fallbackExpirationTime), + type < workInProgressRootMostRecentEventTime && + (workInProgressRootMostRecentEventTime = type), + (current = current.child.sibling), + null !== current && + ((type = workInProgress.firstEffect), + null !== type + ? ((workInProgress.firstEffect = current), + (current.nextEffect = type)) + : ((workInProgress.firstEffect = workInProgress.lastEffect = current), + (current.nextEffect = null)), + (current.effectTag = 8)))); + newProps && + !renderExpirationTime && + 0 !== (workInProgress.mode & 1) && + workInProgressRootExitStatus === RootIncomplete && + (workInProgressRootExitStatus = RootSuspended); + if (newProps || renderExpirationTime) workInProgress.effectTag |= 4; + break; + case 7: + break; + case 8: + break; + case 12: + break; + case 4: + popHostContainer(workInProgress); + updateHostContainer(workInProgress); + break; + case 10: + popProvider(workInProgress); + break; + case 9: + break; + case 14: + break; + case 17: + isContextProvider(workInProgress.type) && popContext(workInProgress); + break; + case 18: + break; + case 19: + break; + case 20: + break; + default: + throw ReactError( + "Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue." + ); + } + return null; +} +function createCapturedValue(value, source) { + return { + value: value, + source: source, + stack: getStackByFiberInDevAndProd(source) + }; +} +function logCapturedError(capturedError) { + var componentStack = capturedError.componentStack, + error = capturedError.error; + if (error instanceof Error) { + capturedError = error.message; + var name = error.name; + try { + error.message = + (capturedError ? name + ": " + capturedError : name) + + "\n\nThis error is located at:" + + componentStack; + } catch (e) {} + } else + error = + "string" === typeof error + ? Error(error + "\n\nThis error is located at:" + componentStack) + : Error("Unspecified error at:" + componentStack); + ReactNativePrivateInterface.ExceptionsManager.handleException(error, !1); +} +var PossiblyWeakSet$1 = "function" === typeof WeakSet ? WeakSet : Set; +function logError(boundary, errorInfo) { + var source = errorInfo.source, + stack = errorInfo.stack; + null === stack && + null !== source && + (stack = getStackByFiberInDevAndProd(source)); + errorInfo = { + componentName: null !== source ? getComponentName(source.type) : null, + componentStack: null !== stack ? stack : "", + error: errorInfo.value, + errorBoundary: null, + errorBoundaryName: null, + errorBoundaryFound: !1, + willRetry: !1 + }; + null !== boundary && + 1 === boundary.tag && + ((errorInfo.errorBoundary = boundary.stateNode), + (errorInfo.errorBoundaryName = getComponentName(boundary.type)), + (errorInfo.errorBoundaryFound = !0), + (errorInfo.willRetry = !0)); + try { + logCapturedError(errorInfo); + } catch (e) { + setTimeout(function() { + throw e; + }); + } +} +function safelyDetachRef(current$$1) { + var ref = current$$1.ref; + if (null !== ref) + if ("function" === typeof ref) + try { + ref(null); + } catch (refError) { + captureCommitPhaseError(current$$1, refError); + } + else ref.current = null; +} +function commitHookEffectList(unmountTag, mountTag, finishedWork) { + finishedWork = finishedWork.updateQueue; + finishedWork = null !== finishedWork ? finishedWork.lastEffect : null; + if (null !== finishedWork) { + var effect = (finishedWork = finishedWork.next); + do { + if ((effect.tag & unmountTag) !== NoEffect$1) { + var destroy = effect.destroy; + effect.destroy = void 0; + void 0 !== destroy && destroy(); + } + (effect.tag & mountTag) !== NoEffect$1 && + ((destroy = effect.create), (effect.destroy = destroy())); + effect = effect.next; + } while (effect !== finishedWork); + } +} +function hideOrUnhideAllChildren(finishedWork, isHidden) { + for (var node = finishedWork; ; ) { + if (5 === node.tag) { + var instance = node.stateNode; + if (isHidden) { + var viewConfig = instance.viewConfig; + var updatePayload = diffProperties( + null, + emptyObject, + { style: { display: "none" } }, + viewConfig.validAttributes + ); + ReactNativePrivateInterface.UIManager.updateView( + instance._nativeTag, + viewConfig.uiViewClassName, + updatePayload + ); + } else { + instance = node.stateNode; + updatePayload = node.memoizedProps; + viewConfig = instance.viewConfig; + var prevProps = Object.assign({}, updatePayload, { + style: [updatePayload.style, { display: "none" }] + }); + updatePayload = diffProperties( + null, + prevProps, + updatePayload, + viewConfig.validAttributes + ); + ReactNativePrivateInterface.UIManager.updateView( + instance._nativeTag, + viewConfig.uiViewClassName, + updatePayload + ); + } + } else { + if (6 === node.tag) throw Error("Not yet implemented."); + if (13 === node.tag && null !== node.memoizedState) { + instance = node.child.sibling; + instance.return = node; + node = instance; + continue; + } else if (null !== node.child) { + node.child.return = node; + node = node.child; + continue; + } + } + if (node === finishedWork) break; + for (; null === node.sibling; ) { + if (null === node.return || node.return === finishedWork) return; + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } +} +function commitUnmount(current$$1$jscomp$0) { + "function" === typeof onCommitFiberUnmount && + onCommitFiberUnmount(current$$1$jscomp$0); + switch (current$$1$jscomp$0.tag) { + case 0: + case 11: + case 14: + case 15: + var updateQueue = current$$1$jscomp$0.updateQueue; + if ( + null !== updateQueue && + ((updateQueue = updateQueue.lastEffect), null !== updateQueue) + ) { + var effect = (updateQueue = updateQueue.next); + do { + var destroy = effect.destroy; + if (void 0 !== destroy) { + var current$$1 = current$$1$jscomp$0; + try { + destroy(); + } catch (error) { + captureCommitPhaseError(current$$1, error); + } + } + effect = effect.next; + } while (effect !== updateQueue); + } + break; + case 1: + safelyDetachRef(current$$1$jscomp$0); + updateQueue = current$$1$jscomp$0.stateNode; + if ("function" === typeof updateQueue.componentWillUnmount) + try { + (updateQueue.props = current$$1$jscomp$0.memoizedProps), + (updateQueue.state = current$$1$jscomp$0.memoizedState), + updateQueue.componentWillUnmount(); + } catch (unmountError) { + captureCommitPhaseError(current$$1$jscomp$0, unmountError); + } + break; + case 5: + safelyDetachRef(current$$1$jscomp$0); + break; + case 4: + unmountHostComponents(current$$1$jscomp$0); + } +} +function isHostParent(fiber) { + return 5 === fiber.tag || 3 === fiber.tag || 4 === fiber.tag; +} +function commitPlacement(finishedWork) { + a: { + for (var parent = finishedWork.return; null !== parent; ) { + if (isHostParent(parent)) { + var parentFiber = parent; + break a; + } + parent = parent.return; + } + throw ReactError( + "Expected to find a host parent. This error is likely caused by a bug in React. Please file an issue." + ); + } + switch (parentFiber.tag) { + case 5: + parent = parentFiber.stateNode; + var isContainer = !1; + break; + case 3: + parent = parentFiber.stateNode.containerInfo; + isContainer = !0; + break; + case 4: + parent = parentFiber.stateNode.containerInfo; + isContainer = !0; + break; + default: + throw ReactError( + "Invalid host parent fiber. This error is likely caused by a bug in React. Please file an issue." + ); + } + parentFiber.effectTag & 16 && (parentFiber.effectTag &= -17); + a: b: for (parentFiber = finishedWork; ; ) { + for (; null === parentFiber.sibling; ) { + if (null === parentFiber.return || isHostParent(parentFiber.return)) { + parentFiber = null; + break a; + } + parentFiber = parentFiber.return; + } + parentFiber.sibling.return = parentFiber.return; + for ( + parentFiber = parentFiber.sibling; + 5 !== parentFiber.tag && 6 !== parentFiber.tag && 18 !== parentFiber.tag; + + ) { + if (parentFiber.effectTag & 2) continue b; + if (null === parentFiber.child || 4 === parentFiber.tag) continue b; + else + (parentFiber.child.return = parentFiber), + (parentFiber = parentFiber.child); + } + if (!(parentFiber.effectTag & 2)) { + parentFiber = parentFiber.stateNode; + break a; + } + } + for (var node = finishedWork; ; ) { + if (5 === node.tag || 6 === node.tag) { + var stateNode = node.stateNode; + if (parentFiber) + if (isContainer) { + if ("number" === typeof parent) + throw ReactError( + "Container does not support insertBefore operation" + ); + } else { + var parentInstance = parent, + beforeChild = parentFiber, + children = parentInstance._children, + index = children.indexOf(stateNode); + 0 <= index + ? (children.splice(index, 1), + (beforeChild = children.indexOf(beforeChild)), + children.splice(beforeChild, 0, stateNode), + ReactNativePrivateInterface.UIManager.manageChildren( + parentInstance._nativeTag, + [index], + [beforeChild], + [], + [], + [] + )) + : ((index = children.indexOf(beforeChild)), + children.splice(index, 0, stateNode), + ReactNativePrivateInterface.UIManager.manageChildren( + parentInstance._nativeTag, + [], + [], + [ + "number" === typeof stateNode + ? stateNode + : stateNode._nativeTag + ], + [index], + [] + )); + } + else + isContainer + ? ReactNativePrivateInterface.UIManager.setChildren(parent, [ + "number" === typeof stateNode ? stateNode : stateNode._nativeTag + ]) + : ((parentInstance = parent), + (children = + "number" === typeof stateNode ? stateNode : stateNode._nativeTag), + (index = parentInstance._children), + (beforeChild = index.indexOf(stateNode)), + 0 <= beforeChild + ? (index.splice(beforeChild, 1), + index.push(stateNode), + ReactNativePrivateInterface.UIManager.manageChildren( + parentInstance._nativeTag, + [beforeChild], + [index.length - 1], + [], + [], + [] + )) + : (index.push(stateNode), + ReactNativePrivateInterface.UIManager.manageChildren( + parentInstance._nativeTag, + [], + [], + [children], + [index.length - 1], + [] + ))); + } else if (4 !== node.tag && null !== node.child) { + node.child.return = node; + node = node.child; + continue; + } + if (node === finishedWork) break; + for (; null === node.sibling; ) { + if (null === node.return || node.return === finishedWork) return; + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } +} +function unmountHostComponents(current$$1) { + for ( + var node = current$$1, + currentParentIsValid = !1, + currentParent = void 0, + currentParentIsContainer = void 0; + ; + + ) { + if (!currentParentIsValid) { + currentParentIsValid = node.return; + a: for (;;) { + if (null === currentParentIsValid) + throw ReactError( + "Expected to find a host parent. This error is likely caused by a bug in React. Please file an issue." + ); + switch (currentParentIsValid.tag) { + case 5: + currentParent = currentParentIsValid.stateNode; + currentParentIsContainer = !1; + break a; + case 3: + currentParent = currentParentIsValid.stateNode.containerInfo; + currentParentIsContainer = !0; + break a; + case 4: + currentParent = currentParentIsValid.stateNode.containerInfo; + currentParentIsContainer = !0; + break a; + } + currentParentIsValid = currentParentIsValid.return; + } + currentParentIsValid = !0; + } + if (5 === node.tag || 6 === node.tag) { + a: for (var root = node, node$jscomp$0 = root; ; ) + if ( + (commitUnmount(node$jscomp$0), + null !== node$jscomp$0.child && 4 !== node$jscomp$0.tag) + ) + (node$jscomp$0.child.return = node$jscomp$0), + (node$jscomp$0 = node$jscomp$0.child); + else { + if (node$jscomp$0 === root) break; + for (; null === node$jscomp$0.sibling; ) { + if (null === node$jscomp$0.return || node$jscomp$0.return === root) + break a; + node$jscomp$0 = node$jscomp$0.return; + } + node$jscomp$0.sibling.return = node$jscomp$0.return; + node$jscomp$0 = node$jscomp$0.sibling; + } + if (currentParentIsContainer) + (root = currentParent), + recursivelyUncacheFiberNode(node.stateNode), + ReactNativePrivateInterface.UIManager.manageChildren( + root, + [], + [], + [], + [], + [0] + ); + else { + root = currentParent; + var child = node.stateNode; + recursivelyUncacheFiberNode(child); + node$jscomp$0 = root._children; + child = node$jscomp$0.indexOf(child); + node$jscomp$0.splice(child, 1); + ReactNativePrivateInterface.UIManager.manageChildren( + root._nativeTag, + [], + [], + [], + [], + [child] + ); + } + } else if (4 === node.tag) { + if (null !== node.child) { + currentParent = node.stateNode.containerInfo; + currentParentIsContainer = !0; + node.child.return = node; + node = node.child; + continue; + } + } else if ((commitUnmount(node), null !== node.child)) { + node.child.return = node; + node = node.child; + continue; + } + if (node === current$$1) break; + for (; null === node.sibling; ) { + if (null === node.return || node.return === current$$1) return; + node = node.return; + 4 === node.tag && (currentParentIsValid = !1); + } + node.sibling.return = node.return; + node = node.sibling; + } +} +function commitWork(current$$1, finishedWork) { + switch (finishedWork.tag) { + case 0: + case 11: + case 14: + case 15: + commitHookEffectList(UnmountMutation, MountMutation, finishedWork); + break; + case 1: + break; + case 5: + var instance = finishedWork.stateNode; + if (null != instance) { + var newProps = finishedWork.memoizedProps; + current$$1 = null !== current$$1 ? current$$1.memoizedProps : newProps; + var updatePayload = finishedWork.updateQueue; + finishedWork.updateQueue = null; + null !== updatePayload && + ((finishedWork = instance.viewConfig), + (instanceProps[instance._nativeTag] = newProps), + (newProps = diffProperties( + null, + current$$1, + newProps, + finishedWork.validAttributes + )), + null != newProps && + ReactNativePrivateInterface.UIManager.updateView( + instance._nativeTag, + finishedWork.uiViewClassName, + newProps + )); + } + break; + case 6: + if (null === finishedWork.stateNode) + throw ReactError( + "This should have a text node initialized. This error is likely caused by a bug in React. Please file an issue." + ); + ReactNativePrivateInterface.UIManager.updateView( + finishedWork.stateNode, + "RCTRawText", + { text: finishedWork.memoizedProps } + ); + break; + case 20: + break; + case 3: + break; + case 12: + break; + case 13: + commitSuspenseComponent(finishedWork); + break; + case 17: + break; + case 19: + break; + default: + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } +} +function commitSuspenseComponent(finishedWork) { + var newState = finishedWork.memoizedState, + newDidTimeout = void 0, + primaryChildParent = finishedWork; + null === newState + ? (newDidTimeout = !1) + : ((newDidTimeout = !0), + (primaryChildParent = finishedWork.child), + 0 === newState.fallbackExpirationTime && + (newState.fallbackExpirationTime = requestCurrentTime() - 500)); + null !== primaryChildParent && + hideOrUnhideAllChildren(primaryChildParent, newDidTimeout); + newState = finishedWork.updateQueue; + if (null !== newState) { + finishedWork.updateQueue = null; + var retryCache = finishedWork.stateNode; + null === retryCache && + (retryCache = finishedWork.stateNode = new PossiblyWeakSet$1()); + newState.forEach(function(thenable) { + var retry = resolveRetryThenable.bind(null, finishedWork, thenable); + retryCache.has(thenable) || + ((retry = tracing.unstable_wrap(retry)), + retryCache.add(thenable), + thenable.then(retry, retry)); + }); + } +} +var PossiblyWeakMap = "function" === typeof WeakMap ? WeakMap : Map; +function createRootErrorUpdate(fiber, errorInfo, expirationTime) { + expirationTime = createUpdate(expirationTime); + expirationTime.tag = 3; + expirationTime.payload = { element: null }; + var error = errorInfo.value; + expirationTime.callback = function() { + hasUncaughtError || ((hasUncaughtError = !0), (firstUncaughtError = error)); + logError(fiber, errorInfo); + }; + return expirationTime; +} +function createClassErrorUpdate(fiber, errorInfo, expirationTime) { + expirationTime = createUpdate(expirationTime); + expirationTime.tag = 3; + var getDerivedStateFromError = fiber.type.getDerivedStateFromError; + if ("function" === typeof getDerivedStateFromError) { + var error$jscomp$0 = errorInfo.value; + expirationTime.payload = function() { + return getDerivedStateFromError(error$jscomp$0); + }; + } + var inst = fiber.stateNode; + null !== inst && + "function" === typeof inst.componentDidCatch && + (expirationTime.callback = function() { + "function" !== typeof getDerivedStateFromError && + (null === legacyErrorBoundariesThatAlreadyFailed + ? (legacyErrorBoundariesThatAlreadyFailed = new Set([this])) + : legacyErrorBoundariesThatAlreadyFailed.add(this)); + var error = errorInfo.value, + stack = errorInfo.stack; + logError(fiber, errorInfo); + this.componentDidCatch(error, { + componentStack: null !== stack ? stack : "" + }); + }); + return expirationTime; +} +function unwindWork(workInProgress) { + switch (workInProgress.tag) { + case 1: + isContextProvider(workInProgress.type) && popContext(workInProgress); + var effectTag = workInProgress.effectTag; + return effectTag & 2048 + ? ((workInProgress.effectTag = (effectTag & -2049) | 64), + workInProgress) + : null; + case 3: + popHostContainer(workInProgress); + popTopLevelContextObject(workInProgress); + effectTag = workInProgress.effectTag; + if (0 !== (effectTag & 64)) + throw ReactError( + "The root failed to unmount after an error. This is likely a bug in React. Please file an issue." + ); + workInProgress.effectTag = (effectTag & -2049) | 64; + return workInProgress; + case 5: + return popHostContext(workInProgress), null; + case 13: + return ( + (effectTag = workInProgress.effectTag), + effectTag & 2048 + ? ((workInProgress.effectTag = (effectTag & -2049) | 64), + workInProgress) + : null + ); + case 18: + return null; + case 4: + return popHostContainer(workInProgress), null; + case 10: + return popProvider(workInProgress), null; + case 19: + case 20: + return null; + default: + return null; + } +} +var ceil = Math.ceil, + ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher, + ReactCurrentOwner$2 = ReactSharedInternals.ReactCurrentOwner, + LegacyUnbatchedPhase = 2, + RenderPhase = 4, + CommitPhase = 5, + RootIncomplete = 0, + RootErrored = 1, + RootSuspended = 2, + RootCompleted = 3, + workPhase = 0, + workInProgressRoot = null, + workInProgress = null, + renderExpirationTime = 0, + workInProgressRootExitStatus = RootIncomplete, + workInProgressRootMostRecentEventTime = 1073741823, + nextEffect = null, + hasUncaughtError = !1, + firstUncaughtError = null, + legacyErrorBoundariesThatAlreadyFailed = null, + rootDoesHavePassiveEffects = !1, + rootWithPendingPassiveEffects = null, + pendingPassiveEffectsExpirationTime = 0, + rootsWithPendingDiscreteUpdates = null, + nestedUpdateCount = 0, + rootWithNestedUpdates = null, + currentEventTime = 0; +function requestCurrentTime() { + return workPhase === RenderPhase || workPhase === CommitPhase + ? 1073741822 - ((now() / 10) | 0) + : 0 !== currentEventTime + ? currentEventTime + : (currentEventTime = 1073741822 - ((now() / 10) | 0)); +} +function computeExpirationForFiber(currentTime, fiber) { + if (0 === (fiber.mode & 1)) return 1073741823; + if (workPhase === RenderPhase) return renderExpirationTime; + switch (getCurrentPriorityLevel()) { + case 99: + currentTime = 1073741823; + break; + case 98: + currentTime = + 1073741822 - 10 * ((((1073741822 - currentTime + 15) / 10) | 0) + 1); + break; + case 97: + case 96: + currentTime = + 1073741822 - 25 * ((((1073741822 - currentTime + 500) / 25) | 0) + 1); + break; + case 95: + currentTime = 1; + break; + default: + throw ReactError("Expected a valid priority level"); + } + null !== workInProgressRoot && + currentTime === renderExpirationTime && + --currentTime; + return currentTime; +} +function scheduleUpdateOnFiber(fiber, expirationTime) { + if (50 < nestedUpdateCount) + throw ((nestedUpdateCount = 0), + (rootWithNestedUpdates = null), + ReactError( + "Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops." + )); + fiber = markUpdateTimeFromFiberToRoot(fiber, expirationTime); + if (null !== fiber) + if (((fiber.pingTime = 0), 1073741823 === expirationTime)) + if (workPhase === LegacyUnbatchedPhase) + for ( + expirationTime = renderRoot(fiber, 1073741823, !0); + null !== expirationTime; + + ) + expirationTime = expirationTime(!0); + else + scheduleCallbackForRoot(fiber, 99, 1073741823), + 0 === workPhase && flushImmediateQueue(); + else { + var priorityLevel = getCurrentPriorityLevel(); + if (98 === priorityLevel) + if (null === rootsWithPendingDiscreteUpdates) + rootsWithPendingDiscreteUpdates = new Map([[fiber, expirationTime]]); + else { + var lastDiscreteTime = rootsWithPendingDiscreteUpdates.get(fiber); + (void 0 === lastDiscreteTime || lastDiscreteTime > expirationTime) && + rootsWithPendingDiscreteUpdates.set(fiber, expirationTime); + } + scheduleCallbackForRoot(fiber, priorityLevel, expirationTime); + } +} +function markUpdateTimeFromFiberToRoot(fiber, expirationTime) { + fiber.expirationTime < expirationTime && + (fiber.expirationTime = expirationTime); + var alternate = fiber.alternate; + null !== alternate && + alternate.expirationTime < expirationTime && + (alternate.expirationTime = expirationTime); + var node = fiber.return, + root = null; + if (null === node && 3 === fiber.tag) root = fiber.stateNode; + else + for (; null !== node; ) { + alternate = node.alternate; + node.childExpirationTime < expirationTime && + (node.childExpirationTime = expirationTime); + null !== alternate && + alternate.childExpirationTime < expirationTime && + (alternate.childExpirationTime = expirationTime); + if (null === node.return && 3 === node.tag) { + root = node.stateNode; + break; + } + node = node.return; + } + null !== root && + (expirationTime > root.firstPendingTime && + (root.firstPendingTime = expirationTime), + (fiber = root.lastPendingTime), + 0 === fiber || expirationTime < fiber) && + (root.lastPendingTime = expirationTime); + return root; +} +function scheduleCallbackForRoot(root, priorityLevel, expirationTime) { + if (root.callbackExpirationTime < expirationTime) { + var existingCallbackNode = root.callbackNode; + null !== existingCallbackNode && + existingCallbackNode !== fakeCallbackNode && + Scheduler_cancelCallback(existingCallbackNode); + root.callbackExpirationTime = expirationTime; + existingCallbackNode = null; + 1073741823 !== expirationTime && + 1 !== expirationTime && + ((existingCallbackNode = 10 * (1073741822 - expirationTime) - now()), + 5e3 < existingCallbackNode && (existingCallbackNode = 5e3), + (existingCallbackNode = { timeout: existingCallbackNode })); + root.callbackNode = scheduleCallback( + priorityLevel, + runRootCallback.bind( + null, + root, + renderRoot.bind(null, root, expirationTime) + ), + existingCallbackNode + ); + } + schedulePendingInteraction(root, expirationTime); +} +function runRootCallback(root, callback, isSync) { + var prevCallbackNode = root.callbackNode, + continuation = null; + try { + return ( + (continuation = callback(isSync)), + null !== continuation + ? runRootCallback.bind(null, root, continuation) + : null + ); + } finally { + null === continuation && + prevCallbackNode === root.callbackNode && + ((root.callbackNode = null), (root.callbackExpirationTime = 0)); + } +} +function resolveLocksOnRoot(root, expirationTime) { + var firstBatch = root.firstBatch; + return null !== firstBatch && + firstBatch._defer && + firstBatch._expirationTime >= expirationTime + ? ((root.finishedWork = root.current.alternate), + (root.pendingCommitExpirationTime = expirationTime), + scheduleCallback(97, function() { + firstBatch._onComplete(); + return null; + }), + !0) + : !1; +} +function flushPendingDiscreteUpdates() { + if (null !== rootsWithPendingDiscreteUpdates) { + var roots = rootsWithPendingDiscreteUpdates; + rootsWithPendingDiscreteUpdates = null; + roots.forEach(function(expirationTime, root) { + scheduleCallback(99, renderRoot.bind(null, root, expirationTime)); + }); + flushImmediateQueue(); + } +} +function prepareFreshStack(root, expirationTime) { + root.pendingCommitExpirationTime = 0; + var timeoutHandle = root.timeoutHandle; + -1 !== timeoutHandle && + ((root.timeoutHandle = -1), cancelTimeout(timeoutHandle)); + if (null !== workInProgress) + for (timeoutHandle = workInProgress.return; null !== timeoutHandle; ) { + var interruptedWork = timeoutHandle; + switch (interruptedWork.tag) { + case 1: + var childContextTypes = interruptedWork.type.childContextTypes; + null !== childContextTypes && + void 0 !== childContextTypes && + popContext(interruptedWork); + break; + case 3: + popHostContainer(interruptedWork); + popTopLevelContextObject(interruptedWork); + break; + case 5: + popHostContext(interruptedWork); + break; + case 4: + popHostContainer(interruptedWork); + break; + case 10: + popProvider(interruptedWork); + } + timeoutHandle = timeoutHandle.return; + } + workInProgressRoot = root; + workInProgress = createWorkInProgress(root.current, null, expirationTime); + renderExpirationTime = expirationTime; + workInProgressRootExitStatus = RootIncomplete; + workInProgressRootMostRecentEventTime = 1073741823; +} +function renderRoot(root$jscomp$0, expirationTime, isSync) { + if (workPhase === RenderPhase || workPhase === CommitPhase) + throw ReactError("Should not already be working."); + if (root$jscomp$0.firstPendingTime < expirationTime) return null; + if (root$jscomp$0.pendingCommitExpirationTime === expirationTime) + return ( + (root$jscomp$0.pendingCommitExpirationTime = 0), + commitRoot.bind(null, root$jscomp$0, expirationTime) + ); + flushPassiveEffects(); + if ( + root$jscomp$0 !== workInProgressRoot || + expirationTime !== renderExpirationTime + ) + prepareFreshStack(root$jscomp$0, expirationTime), + startWorkOnPendingInteraction(root$jscomp$0, expirationTime); + if (null !== workInProgress) { + var prevWorkPhase = workPhase; + workPhase = RenderPhase; + var prevDispatcher = ReactCurrentDispatcher.current; + null === prevDispatcher && (prevDispatcher = ContextOnlyDispatcher); + ReactCurrentDispatcher.current = ContextOnlyDispatcher; + var prevInteractions = tracing.__interactionsRef.current; + tracing.__interactionsRef.current = root$jscomp$0.memoizedInteractions; + if (isSync) { + if (1073741823 !== expirationTime) { + var currentTime = requestCurrentTime(); + if (currentTime < expirationTime) + return ( + (workPhase = prevWorkPhase), + resetContextDependences(), + (ReactCurrentDispatcher.current = prevDispatcher), + (tracing.__interactionsRef.current = prevInteractions), + renderRoot.bind(null, root$jscomp$0, currentTime) + ); + } + } else currentEventTime = 0; + do + try { + if (isSync) + for (; null !== workInProgress; ) + workInProgress = performUnitOfWork(workInProgress); + else + for (; null !== workInProgress && !Scheduler_shouldYield(); ) + workInProgress = performUnitOfWork(workInProgress); + break; + } catch (thrownValue) { + resetContextDependences(); + resetHooks(); + currentTime = workInProgress; + if (null === currentTime || null === currentTime.return) + throw (prepareFreshStack(root$jscomp$0, expirationTime), + (workPhase = prevWorkPhase), + thrownValue); + currentTime.mode & 4 && + stopProfilerTimerIfRunningAndRecordDelta(currentTime, !0); + a: { + var root = root$jscomp$0, + returnFiber = currentTime.return, + sourceFiber = currentTime, + value = thrownValue, + renderExpirationTime$jscomp$0 = renderExpirationTime; + sourceFiber.effectTag |= 1024; + sourceFiber.firstEffect = sourceFiber.lastEffect = null; + if ( + null !== value && + "object" === typeof value && + "function" === typeof value.then + ) { + var thenable = value; + value = returnFiber; + do { + if ( + 13 === value.tag && + (void 0 === value.memoizedProps.fallback + ? 0 + : null === value.memoizedState) + ) { + returnFiber = value.updateQueue; + null === returnFiber + ? ((returnFiber = new Set()), + returnFiber.add(thenable), + (value.updateQueue = returnFiber)) + : returnFiber.add(thenable); + if (0 === (value.mode & 1)) { + value.effectTag |= 64; + sourceFiber.effectTag &= -1957; + 1 === sourceFiber.tag && + (null === sourceFiber.alternate + ? (sourceFiber.tag = 17) + : ((renderExpirationTime$jscomp$0 = createUpdate( + 1073741823 + )), + (renderExpirationTime$jscomp$0.tag = 2), + enqueueUpdate( + sourceFiber, + renderExpirationTime$jscomp$0 + ))); + sourceFiber.expirationTime = 1073741823; + break a; + } + sourceFiber = root; + root = renderExpirationTime$jscomp$0; + var pingCache = sourceFiber.pingCache; + null === pingCache + ? ((pingCache = sourceFiber.pingCache = new PossiblyWeakMap()), + (returnFiber = new Set()), + pingCache.set(thenable, returnFiber)) + : ((returnFiber = pingCache.get(thenable)), + void 0 === returnFiber && + ((returnFiber = new Set()), + pingCache.set(thenable, returnFiber))); + returnFiber.has(root) || + (returnFiber.add(root), + (sourceFiber = pingSuspendedRoot.bind( + null, + sourceFiber, + thenable, + root + )), + (sourceFiber = tracing.unstable_wrap(sourceFiber)), + thenable.then(sourceFiber, sourceFiber)); + value.effectTag |= 2048; + value.expirationTime = renderExpirationTime$jscomp$0; + break a; + } + value = value.return; + } while (null !== value); + value = Error( + (getComponentName(sourceFiber.type) || "A React component") + + " suspended while rendering, but no fallback UI was specified.\n\nAdd a component higher in the tree to provide a loading indicator or placeholder to display." + + getStackByFiberInDevAndProd(sourceFiber) + ); + } + if ( + workInProgressRootExitStatus === RootIncomplete || + workInProgressRootExitStatus === RootSuspended + ) + workInProgressRootExitStatus = RootErrored; + value = createCapturedValue(value, sourceFiber); + sourceFiber = returnFiber; + do { + switch (sourceFiber.tag) { + case 3: + sourceFiber.effectTag |= 2048; + sourceFiber.expirationTime = renderExpirationTime$jscomp$0; + renderExpirationTime$jscomp$0 = createRootErrorUpdate( + sourceFiber, + value, + renderExpirationTime$jscomp$0 + ); + enqueueCapturedUpdate( + sourceFiber, + renderExpirationTime$jscomp$0 + ); + break a; + case 1: + if ( + ((thenable = value), + (root = sourceFiber.type), + (returnFiber = sourceFiber.stateNode), + 0 === (sourceFiber.effectTag & 64) && + ("function" === typeof root.getDerivedStateFromError || + (null !== returnFiber && + "function" === typeof returnFiber.componentDidCatch && + (null === legacyErrorBoundariesThatAlreadyFailed || + !legacyErrorBoundariesThatAlreadyFailed.has( + returnFiber + ))))) + ) { + sourceFiber.effectTag |= 2048; + sourceFiber.expirationTime = renderExpirationTime$jscomp$0; + renderExpirationTime$jscomp$0 = createClassErrorUpdate( + sourceFiber, + thenable, + renderExpirationTime$jscomp$0 + ); + enqueueCapturedUpdate( + sourceFiber, + renderExpirationTime$jscomp$0 + ); + break a; + } + } + sourceFiber = sourceFiber.return; + } while (null !== sourceFiber); + } + workInProgress = completeUnitOfWork(currentTime); + } + while (1); + workPhase = prevWorkPhase; + resetContextDependences(); + ReactCurrentDispatcher.current = prevDispatcher; + tracing.__interactionsRef.current = prevInteractions; + if (null !== workInProgress) + return renderRoot.bind(null, root$jscomp$0, expirationTime); + } + if (resolveLocksOnRoot(root$jscomp$0, expirationTime)) return null; + workInProgressRoot = null; + switch (workInProgressRootExitStatus) { + case RootIncomplete: + throw ReactError("Should have a work-in-progress."); + case RootErrored: + return ( + (prevWorkPhase = root$jscomp$0.lastPendingTime), + root$jscomp$0.lastPendingTime < expirationTime + ? renderRoot.bind(null, root$jscomp$0, prevWorkPhase) + : isSync + ? commitRoot.bind(null, root$jscomp$0, expirationTime) + : (prepareFreshStack(root$jscomp$0, expirationTime), + scheduleCallback( + 99, + renderRoot.bind(null, root$jscomp$0, expirationTime) + ), + null) + ); + case RootSuspended: + if (!isSync) { + isSync = root$jscomp$0.lastPendingTime; + if (root$jscomp$0.lastPendingTime < expirationTime) + return renderRoot.bind(null, root$jscomp$0, isSync); + if ( + 1073741823 !== workInProgressRootMostRecentEventTime && + ((prevWorkPhase = + 10 * (1073741822 - workInProgressRootMostRecentEventTime) - 5e3), + (isSync = now()), + (prevWorkPhase = isSync - prevWorkPhase), + (prevWorkPhase = + (120 > prevWorkPhase + ? 120 + : 480 > prevWorkPhase + ? 480 + : 1080 > prevWorkPhase + ? 1080 + : 1920 > prevWorkPhase + ? 1920 + : 3e3 > prevWorkPhase + ? 3e3 + : 4320 > prevWorkPhase + ? 4320 + : 1960 * ceil(prevWorkPhase / 1960)) - prevWorkPhase), + (isSync = 10 * (1073741822 - expirationTime) - isSync), + isSync < prevWorkPhase && (prevWorkPhase = isSync), + (isSync = prevWorkPhase), + 10 < isSync) + ) + return ( + (root$jscomp$0.timeoutHandle = scheduleTimeout( + commitRoot.bind(null, root$jscomp$0, expirationTime), + isSync + )), + null + ); + } + return commitRoot.bind(null, root$jscomp$0, expirationTime); + case RootCompleted: + return commitRoot.bind(null, root$jscomp$0, expirationTime); + default: + throw ReactError("Unknown root exit status."); + } +} +function performUnitOfWork(unitOfWork) { + var current$$1 = unitOfWork.alternate; + 0 !== (unitOfWork.mode & 4) + ? ((profilerStartTime = now$1()), + 0 > unitOfWork.actualStartTime && (unitOfWork.actualStartTime = now$1()), + (current$$1 = beginWork$$1(current$$1, unitOfWork, renderExpirationTime)), + stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, !0)) + : (current$$1 = beginWork$$1(current$$1, unitOfWork, renderExpirationTime)); + unitOfWork.memoizedProps = unitOfWork.pendingProps; + null === current$$1 && (current$$1 = completeUnitOfWork(unitOfWork)); + ReactCurrentOwner$2.current = null; + return current$$1; +} +function completeUnitOfWork(unitOfWork) { + workInProgress = unitOfWork; + do { + var current$$1 = workInProgress.alternate; + unitOfWork = workInProgress.return; + if (0 === (workInProgress.effectTag & 1024)) { + if (0 === (workInProgress.mode & 4)) + current$$1 = completeWork( + current$$1, + workInProgress, + renderExpirationTime + ); + else { + var fiber = workInProgress; + profilerStartTime = now$1(); + 0 > fiber.actualStartTime && (fiber.actualStartTime = now$1()); + current$$1 = completeWork( + current$$1, + workInProgress, + renderExpirationTime + ); + stopProfilerTimerIfRunningAndRecordDelta(workInProgress, !1); + } + fiber = workInProgress; + if (1 === renderExpirationTime || 1 !== fiber.childExpirationTime) { + var newChildExpirationTime = 0; + if (0 !== (fiber.mode & 4)) { + for ( + var actualDuration = fiber.actualDuration, + treeBaseDuration = fiber.selfBaseDuration, + shouldBubbleActualDurations = + null === fiber.alternate || + fiber.child !== fiber.alternate.child, + child = fiber.child; + null !== child; + + ) { + var childUpdateExpirationTime = child.expirationTime, + childChildExpirationTime = child.childExpirationTime; + childUpdateExpirationTime > newChildExpirationTime && + (newChildExpirationTime = childUpdateExpirationTime); + childChildExpirationTime > newChildExpirationTime && + (newChildExpirationTime = childChildExpirationTime); + shouldBubbleActualDurations && + (actualDuration += child.actualDuration); + treeBaseDuration += child.treeBaseDuration; + child = child.sibling; + } + fiber.actualDuration = actualDuration; + fiber.treeBaseDuration = treeBaseDuration; + } else + for (actualDuration = fiber.child; null !== actualDuration; ) + (treeBaseDuration = actualDuration.expirationTime), + (shouldBubbleActualDurations = + actualDuration.childExpirationTime), + treeBaseDuration > newChildExpirationTime && + (newChildExpirationTime = treeBaseDuration), + shouldBubbleActualDurations > newChildExpirationTime && + (newChildExpirationTime = shouldBubbleActualDurations), + (actualDuration = actualDuration.sibling); + fiber.childExpirationTime = newChildExpirationTime; + } + if (null !== current$$1) return current$$1; + null !== unitOfWork && + 0 === (unitOfWork.effectTag & 1024) && + (null === unitOfWork.firstEffect && + (unitOfWork.firstEffect = workInProgress.firstEffect), + null !== workInProgress.lastEffect && + (null !== unitOfWork.lastEffect && + (unitOfWork.lastEffect.nextEffect = workInProgress.firstEffect), + (unitOfWork.lastEffect = workInProgress.lastEffect)), + 1 < workInProgress.effectTag && + (null !== unitOfWork.lastEffect + ? (unitOfWork.lastEffect.nextEffect = workInProgress) + : (unitOfWork.firstEffect = workInProgress), + (unitOfWork.lastEffect = workInProgress))); + } else { + current$$1 = unwindWork(workInProgress, renderExpirationTime); + if (0 !== (workInProgress.mode & 4)) { + stopProfilerTimerIfRunningAndRecordDelta(workInProgress, !1); + fiber = workInProgress.actualDuration; + for ( + newChildExpirationTime = workInProgress.child; + null !== newChildExpirationTime; + + ) + (fiber += newChildExpirationTime.actualDuration), + (newChildExpirationTime = newChildExpirationTime.sibling); + workInProgress.actualDuration = fiber; + } + if (null !== current$$1) + return (current$$1.effectTag &= 1023), current$$1; + null !== unitOfWork && + ((unitOfWork.firstEffect = unitOfWork.lastEffect = null), + (unitOfWork.effectTag |= 1024)); + } + current$$1 = workInProgress.sibling; + if (null !== current$$1) return current$$1; + workInProgress = unitOfWork; + } while (null !== workInProgress); + workInProgressRootExitStatus === RootIncomplete && + (workInProgressRootExitStatus = RootCompleted); + return null; +} +function commitRoot(root, expirationTime) { + runWithPriority(99, commitRootImpl.bind(null, root, expirationTime)); + null !== rootWithPendingPassiveEffects && + ((root = getCurrentPriorityLevel()), + scheduleCallback(root, function() { + flushPassiveEffects(); + return null; + })); + return null; +} +function commitRootImpl(root, expirationTime) { + flushPassiveEffects(); + if (workPhase === RenderPhase || workPhase === CommitPhase) + throw ReactError("Should not already be working."); + var finishedWork = root.current.alternate; + if (null === finishedWork) + throw ReactError("Should have a work-in-progress root."); + root.callbackNode = null; + root.callbackExpirationTime = 0; + var updateExpirationTimeBeforeCommit = finishedWork.expirationTime, + childExpirationTimeBeforeCommit = finishedWork.childExpirationTime; + updateExpirationTimeBeforeCommit = + childExpirationTimeBeforeCommit > updateExpirationTimeBeforeCommit + ? childExpirationTimeBeforeCommit + : updateExpirationTimeBeforeCommit; + root.firstPendingTime = updateExpirationTimeBeforeCommit; + updateExpirationTimeBeforeCommit < root.lastPendingTime && + (root.lastPendingTime = updateExpirationTimeBeforeCommit); + root === workInProgressRoot && + ((workInProgress = workInProgressRoot = null), (renderExpirationTime = 0)); + if (1 < finishedWork.effectTag) + if (null !== finishedWork.lastEffect) { + finishedWork.lastEffect.nextEffect = finishedWork; + var firstEffect = finishedWork.firstEffect; + } else firstEffect = finishedWork; + else firstEffect = finishedWork.firstEffect; + if (null !== firstEffect) { + updateExpirationTimeBeforeCommit = workPhase; + workPhase = CommitPhase; + childExpirationTimeBeforeCommit = tracing.__interactionsRef.current; + tracing.__interactionsRef.current = root.memoizedInteractions; + ReactCurrentOwner$2.current = null; + nextEffect = firstEffect; + do + try { + for (; null !== nextEffect; ) { + if (0 !== (nextEffect.effectTag & 256)) { + var current$$1 = nextEffect.alternate, + finishedWork$jscomp$0 = nextEffect; + switch (finishedWork$jscomp$0.tag) { + case 0: + case 11: + case 15: + commitHookEffectList( + UnmountSnapshot, + NoEffect$1, + finishedWork$jscomp$0 + ); + break; + case 1: + if ( + finishedWork$jscomp$0.effectTag & 256 && + null !== current$$1 + ) { + var prevProps = current$$1.memoizedProps, + prevState = current$$1.memoizedState, + instance = finishedWork$jscomp$0.stateNode, + snapshot = instance.getSnapshotBeforeUpdate( + finishedWork$jscomp$0.elementType === + finishedWork$jscomp$0.type + ? prevProps + : resolveDefaultProps( + finishedWork$jscomp$0.type, + prevProps + ), + prevState + ); + instance.__reactInternalSnapshotBeforeUpdate = snapshot; + } + break; + case 3: + case 5: + case 6: + case 4: + case 17: + case 20: + break; + default: + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + } + nextEffect = nextEffect.nextEffect; + } + } catch (error) { + if (null === nextEffect) + throw ReactError("Should be working on an effect."); + captureCommitPhaseError(nextEffect, error); + nextEffect = nextEffect.nextEffect; + } + while (null !== nextEffect); + commitTime = now$1(); + nextEffect = firstEffect; + do + try { + for (; null !== nextEffect; ) { + var effectTag = nextEffect.effectTag; + if (effectTag & 128) { + var current$$1$jscomp$0 = nextEffect.alternate; + if (null !== current$$1$jscomp$0) { + var currentRef = current$$1$jscomp$0.ref; + null !== currentRef && + ("function" === typeof currentRef + ? currentRef(null) + : (currentRef.current = null)); + } + } + switch (effectTag & 14) { + case 2: + commitPlacement(nextEffect); + nextEffect.effectTag &= -3; + break; + case 6: + commitPlacement(nextEffect); + nextEffect.effectTag &= -3; + commitWork(nextEffect.alternate, nextEffect); + break; + case 4: + commitWork(nextEffect.alternate, nextEffect); + break; + case 8: + current$$1 = nextEffect; + unmountHostComponents(current$$1); + current$$1.return = null; + current$$1.child = null; + current$$1.memoizedState = null; + current$$1.updateQueue = null; + var alternate = current$$1.alternate; + null !== alternate && + ((alternate.return = null), + (alternate.child = null), + (alternate.memoizedState = null), + (alternate.updateQueue = null)); + } + nextEffect = nextEffect.nextEffect; + } + } catch (error) { + if (null === nextEffect) + throw ReactError("Should be working on an effect."); + captureCommitPhaseError(nextEffect, error); + nextEffect = nextEffect.nextEffect; + } + while (null !== nextEffect); + root.current = finishedWork; + nextEffect = firstEffect; + do + try { + for ( + effectTag = root, current$$1$jscomp$0 = expirationTime; + null !== nextEffect; + + ) { + var effectTag$jscomp$0 = nextEffect.effectTag; + if (effectTag$jscomp$0 & 36) { + current$$1 = effectTag; + var current$$1$jscomp$1 = nextEffect.alternate; + currentRef = nextEffect; + alternate = current$$1$jscomp$0; + switch (currentRef.tag) { + case 0: + case 11: + case 15: + commitHookEffectList(UnmountLayout, MountLayout, currentRef); + break; + case 1: + var instance$jscomp$0 = currentRef.stateNode; + if (currentRef.effectTag & 4) + if (null === current$$1$jscomp$1) + instance$jscomp$0.componentDidMount(); + else { + var prevProps$jscomp$0 = + currentRef.elementType === currentRef.type + ? current$$1$jscomp$1.memoizedProps + : resolveDefaultProps( + currentRef.type, + current$$1$jscomp$1.memoizedProps + ); + instance$jscomp$0.componentDidUpdate( + prevProps$jscomp$0, + current$$1$jscomp$1.memoizedState, + instance$jscomp$0.__reactInternalSnapshotBeforeUpdate + ); + } + var updateQueue = currentRef.updateQueue; + null !== updateQueue && + commitUpdateQueue( + currentRef, + updateQueue, + instance$jscomp$0, + alternate + ); + break; + case 3: + var _updateQueue = currentRef.updateQueue; + if (null !== _updateQueue) { + current$$1 = null; + if (null !== currentRef.child) + switch (currentRef.child.tag) { + case 5: + current$$1 = currentRef.child.stateNode; + break; + case 1: + current$$1 = currentRef.child.stateNode; + } + commitUpdateQueue( + currentRef, + _updateQueue, + current$$1, + alternate + ); + } + break; + case 5: + break; + case 6: + break; + case 4: + break; + case 12: + var onRender = currentRef.memoizedProps.onRender; + onRender( + currentRef.memoizedProps.id, + null === current$$1$jscomp$1 ? "mount" : "update", + currentRef.actualDuration, + currentRef.treeBaseDuration, + currentRef.actualStartTime, + commitTime, + current$$1.memoizedInteractions + ); + break; + case 13: + case 17: + break; + case 20: + break; + case 19: + break; + default: + throw ReactError( + "This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue." + ); + } + } + if (effectTag$jscomp$0 & 128) { + var ref = nextEffect.ref; + if (null !== ref) { + var instance$jscomp$1 = nextEffect.stateNode; + switch (nextEffect.tag) { + case 5: + var instanceToUse = instance$jscomp$1; + break; + default: + instanceToUse = instance$jscomp$1; + } + "function" === typeof ref + ? ref(instanceToUse) + : (ref.current = instanceToUse); + } + } + effectTag$jscomp$0 & 512 && (rootDoesHavePassiveEffects = !0); + nextEffect = nextEffect.nextEffect; + } + } catch (error) { + if (null === nextEffect) + throw ReactError("Should be working on an effect."); + captureCommitPhaseError(nextEffect, error); + nextEffect = nextEffect.nextEffect; + } + while (null !== nextEffect); + nextEffect = null; + tracing.__interactionsRef.current = childExpirationTimeBeforeCommit; + workPhase = updateExpirationTimeBeforeCommit; + } else (root.current = finishedWork), (commitTime = now$1()); + rootDoesHavePassiveEffects + ? ((rootDoesHavePassiveEffects = !1), + (rootWithPendingPassiveEffects = root), + (pendingPassiveEffectsExpirationTime = expirationTime)) + : finishPendingInteractions(root, expirationTime); + expirationTime = root.firstPendingTime; + 0 !== expirationTime + ? ((effectTag$jscomp$0 = requestCurrentTime()), + (effectTag$jscomp$0 = inferPriorityFromExpirationTime( + effectTag$jscomp$0, + expirationTime + )), + scheduleCallbackForRoot(root, effectTag$jscomp$0, expirationTime)) + : (legacyErrorBoundariesThatAlreadyFailed = null); + "function" === typeof onCommitFiberRoot && + onCommitFiberRoot(finishedWork.stateNode); + 1073741823 === expirationTime + ? root === rootWithNestedUpdates + ? nestedUpdateCount++ + : ((nestedUpdateCount = 0), (rootWithNestedUpdates = root)) + : (nestedUpdateCount = 0); + if (hasUncaughtError) + throw ((hasUncaughtError = !1), + (root = firstUncaughtError), + (firstUncaughtError = null), + root); + if (workPhase === LegacyUnbatchedPhase) return null; + flushImmediateQueue(); + return null; +} +function flushPassiveEffects() { + if (null === rootWithPendingPassiveEffects) return !1; + var root = rootWithPendingPassiveEffects, + expirationTime = pendingPassiveEffectsExpirationTime; + rootWithPendingPassiveEffects = null; + pendingPassiveEffectsExpirationTime = 0; + var prevInteractions = tracing.__interactionsRef.current; + tracing.__interactionsRef.current = root.memoizedInteractions; + if (workPhase === RenderPhase || workPhase === CommitPhase) + throw ReactError("Cannot flush passive effects while already rendering."); + var prevWorkPhase = workPhase; + workPhase = CommitPhase; + for (var effect = root.current.firstEffect; null !== effect; ) { + try { + var finishedWork = effect; + commitHookEffectList(UnmountPassive, NoEffect$1, finishedWork); + commitHookEffectList(NoEffect$1, MountPassive, finishedWork); + } catch (error) { + if (null === effect) throw ReactError("Should be working on an effect."); + captureCommitPhaseError(effect, error); + } + effect = effect.nextEffect; + } + tracing.__interactionsRef.current = prevInteractions; + finishPendingInteractions(root, expirationTime); + workPhase = prevWorkPhase; + flushImmediateQueue(); + return !0; +} +function captureCommitPhaseErrorOnRoot(rootFiber, sourceFiber, error) { + sourceFiber = createCapturedValue(error, sourceFiber); + sourceFiber = createRootErrorUpdate(rootFiber, sourceFiber, 1073741823); + enqueueUpdate(rootFiber, sourceFiber); + rootFiber = markUpdateTimeFromFiberToRoot(rootFiber, 1073741823); + null !== rootFiber && scheduleCallbackForRoot(rootFiber, 99, 1073741823); +} +function captureCommitPhaseError(sourceFiber, error) { + if (3 === sourceFiber.tag) + captureCommitPhaseErrorOnRoot(sourceFiber, sourceFiber, error); + else + for (var fiber = sourceFiber.return; null !== fiber; ) { + if (3 === fiber.tag) { + captureCommitPhaseErrorOnRoot(fiber, sourceFiber, error); + break; + } else if (1 === fiber.tag) { + var instance = fiber.stateNode; + if ( + "function" === typeof fiber.type.getDerivedStateFromError || + ("function" === typeof instance.componentDidCatch && + (null === legacyErrorBoundariesThatAlreadyFailed || + !legacyErrorBoundariesThatAlreadyFailed.has(instance))) + ) { + sourceFiber = createCapturedValue(error, sourceFiber); + sourceFiber = createClassErrorUpdate(fiber, sourceFiber, 1073741823); + enqueueUpdate(fiber, sourceFiber); + fiber = markUpdateTimeFromFiberToRoot(fiber, 1073741823); + null !== fiber && scheduleCallbackForRoot(fiber, 99, 1073741823); + break; + } + } + fiber = fiber.return; + } +} +function pingSuspendedRoot(root, thenable, suspendedTime) { + var pingCache = root.pingCache; + null !== pingCache && pingCache.delete(thenable); + workInProgressRoot === root && renderExpirationTime === suspendedTime + ? prepareFreshStack(root, renderExpirationTime) + : root.lastPendingTime < suspendedTime || + ((thenable = root.pingTime), + (0 !== thenable && thenable < suspendedTime) || + ((root.pingTime = suspendedTime), + (thenable = requestCurrentTime()), + (thenable = inferPriorityFromExpirationTime(thenable, suspendedTime)), + scheduleCallbackForRoot(root, thenable, suspendedTime))); +} +function resolveRetryThenable(boundaryFiber, thenable) { + var retryCache = boundaryFiber.stateNode; + null !== retryCache && retryCache.delete(thenable); + retryCache = requestCurrentTime(); + thenable = computeExpirationForFiber(retryCache, boundaryFiber); + retryCache = inferPriorityFromExpirationTime(retryCache, thenable); + boundaryFiber = markUpdateTimeFromFiberToRoot(boundaryFiber, thenable); + null !== boundaryFiber && + scheduleCallbackForRoot(boundaryFiber, retryCache, thenable); +} +var beginWork$$1 = void 0; +beginWork$$1 = function(current$$1, workInProgress, renderExpirationTime) { + var updateExpirationTime = workInProgress.expirationTime; + if (null !== current$$1) + if ( + current$$1.memoizedProps !== workInProgress.pendingProps || + didPerformWorkStackCursor.current + ) + didReceiveUpdate = !0; + else { + if (updateExpirationTime < renderExpirationTime) { + didReceiveUpdate = !1; + switch (workInProgress.tag) { + case 3: + pushHostRootContext(workInProgress); + break; + case 5: + pushHostContext(workInProgress); + break; + case 1: + isContextProvider(workInProgress.type) && + pushContextProvider(workInProgress); + break; + case 4: + pushHostContainer( + workInProgress, + workInProgress.stateNode.containerInfo + ); + break; + case 10: + pushProvider(workInProgress, workInProgress.memoizedProps.value); + break; + case 12: + workInProgress.effectTag |= 4; + break; + case 13: + if (null !== workInProgress.memoizedState) { + updateExpirationTime = workInProgress.child.childExpirationTime; + if ( + 0 !== updateExpirationTime && + updateExpirationTime >= renderExpirationTime + ) + return updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + workInProgress = bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + return null !== workInProgress ? workInProgress.sibling : null; + } + } + return bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + } + } + else didReceiveUpdate = !1; + workInProgress.expirationTime = 0; + switch (workInProgress.tag) { + case 2: + updateExpirationTime = workInProgress.elementType; + null !== current$$1 && + ((current$$1.alternate = null), + (workInProgress.alternate = null), + (workInProgress.effectTag |= 2)); + current$$1 = workInProgress.pendingProps; + var context = getMaskedContext( + workInProgress, + contextStackCursor.current + ); + prepareToReadContext(workInProgress, renderExpirationTime); + context = renderWithHooks( + null, + workInProgress, + updateExpirationTime, + current$$1, + context, + renderExpirationTime + ); + workInProgress.effectTag |= 1; + if ( + "object" === typeof context && + null !== context && + "function" === typeof context.render && + void 0 === context.$$typeof + ) { + workInProgress.tag = 1; + resetHooks(); + if (isContextProvider(updateExpirationTime)) { + var hasContext = !0; + pushContextProvider(workInProgress); + } else hasContext = !1; + workInProgress.memoizedState = + null !== context.state && void 0 !== context.state + ? context.state + : null; + var getDerivedStateFromProps = + updateExpirationTime.getDerivedStateFromProps; + "function" === typeof getDerivedStateFromProps && + applyDerivedStateFromProps( + workInProgress, + updateExpirationTime, + getDerivedStateFromProps, + current$$1 + ); + context.updater = classComponentUpdater; + workInProgress.stateNode = context; + context._reactInternalFiber = workInProgress; + mountClassInstance( + workInProgress, + updateExpirationTime, + current$$1, + renderExpirationTime + ); + workInProgress = finishClassComponent( + null, + workInProgress, + updateExpirationTime, + !0, + hasContext, + renderExpirationTime + ); + } else + (workInProgress.tag = 0), + reconcileChildren( + null, + workInProgress, + context, + renderExpirationTime + ), + (workInProgress = workInProgress.child); + return workInProgress; + case 16: + context = workInProgress.elementType; + null !== current$$1 && + ((current$$1.alternate = null), + (workInProgress.alternate = null), + (workInProgress.effectTag |= 2)); + current$$1 = workInProgress.pendingProps; + context = readLazyComponentType(context); + workInProgress.type = context; + hasContext = workInProgress.tag = resolveLazyComponentTag(context); + current$$1 = resolveDefaultProps(context, current$$1); + switch (hasContext) { + case 0: + workInProgress = updateFunctionComponent( + null, + workInProgress, + context, + current$$1, + renderExpirationTime + ); + break; + case 1: + workInProgress = updateClassComponent( + null, + workInProgress, + context, + current$$1, + renderExpirationTime + ); + break; + case 11: + workInProgress = updateForwardRef( + null, + workInProgress, + context, + current$$1, + renderExpirationTime + ); + break; + case 14: + workInProgress = updateMemoComponent( + null, + workInProgress, + context, + resolveDefaultProps(context.type, current$$1), + updateExpirationTime, + renderExpirationTime + ); + break; + default: + throw ReactError( + "Element type is invalid. Received a promise that resolves to: " + + context + + ". Lazy element type must resolve to a class or function." + ); + } + return workInProgress; + case 0: + return ( + (updateExpirationTime = workInProgress.type), + (context = workInProgress.pendingProps), + (context = + workInProgress.elementType === updateExpirationTime + ? context + : resolveDefaultProps(updateExpirationTime, context)), + updateFunctionComponent( + current$$1, + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ) + ); + case 1: + return ( + (updateExpirationTime = workInProgress.type), + (context = workInProgress.pendingProps), + (context = + workInProgress.elementType === updateExpirationTime + ? context + : resolveDefaultProps(updateExpirationTime, context)), + updateClassComponent( + current$$1, + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ) + ); + case 3: + pushHostRootContext(workInProgress); + updateExpirationTime = workInProgress.updateQueue; + if (null === updateExpirationTime) + throw ReactError( + "If the root does not have an updateQueue, we should have already bailed out. This error is likely caused by a bug in React. Please file an issue." + ); + context = workInProgress.memoizedState; + context = null !== context ? context.element : null; + processUpdateQueue( + workInProgress, + updateExpirationTime, + workInProgress.pendingProps, + null, + renderExpirationTime + ); + updateExpirationTime = workInProgress.memoizedState.element; + updateExpirationTime === context + ? (workInProgress = bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + )) + : (reconcileChildren( + current$$1, + workInProgress, + updateExpirationTime, + renderExpirationTime + ), + (workInProgress = workInProgress.child)); + return workInProgress; + case 5: + return ( + pushHostContext(workInProgress), + null === current$$1 && tryToClaimNextHydratableInstance(workInProgress), + (updateExpirationTime = workInProgress.pendingProps.children), + markRef(current$$1, workInProgress), + reconcileChildren( + current$$1, + workInProgress, + updateExpirationTime, + renderExpirationTime + ), + workInProgress.child + ); + case 6: + return ( + null === current$$1 && tryToClaimNextHydratableInstance(workInProgress), + null + ); + case 13: + return updateSuspenseComponent( + current$$1, + workInProgress, + renderExpirationTime + ); + case 4: + return ( + pushHostContainer( + workInProgress, + workInProgress.stateNode.containerInfo + ), + (updateExpirationTime = workInProgress.pendingProps), + null === current$$1 + ? (workInProgress.child = reconcileChildFibers( + workInProgress, + null, + updateExpirationTime, + renderExpirationTime + )) + : reconcileChildren( + current$$1, + workInProgress, + updateExpirationTime, + renderExpirationTime + ), + workInProgress.child + ); + case 11: + return ( + (updateExpirationTime = workInProgress.type), + (context = workInProgress.pendingProps), + (context = + workInProgress.elementType === updateExpirationTime + ? context + : resolveDefaultProps(updateExpirationTime, context)), + updateForwardRef( + current$$1, + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ) + ); + case 7: + return ( + reconcileChildren( + current$$1, + workInProgress, + workInProgress.pendingProps, + renderExpirationTime + ), + workInProgress.child + ); + case 8: + return ( + reconcileChildren( + current$$1, + workInProgress, + workInProgress.pendingProps.children, + renderExpirationTime + ), + workInProgress.child + ); + case 12: + return ( + (workInProgress.effectTag |= 4), + reconcileChildren( + current$$1, + workInProgress, + workInProgress.pendingProps.children, + renderExpirationTime + ), + workInProgress.child + ); + case 10: + a: { + updateExpirationTime = workInProgress.type._context; + context = workInProgress.pendingProps; + getDerivedStateFromProps = workInProgress.memoizedProps; + hasContext = context.value; + pushProvider(workInProgress, hasContext); + if (null !== getDerivedStateFromProps) { + var oldValue = getDerivedStateFromProps.value; + hasContext = is(oldValue, hasContext) + ? 0 + : ("function" === typeof updateExpirationTime._calculateChangedBits + ? updateExpirationTime._calculateChangedBits( + oldValue, + hasContext + ) + : 1073741823) | 0; + if (0 === hasContext) { + if ( + getDerivedStateFromProps.children === context.children && + !didPerformWorkStackCursor.current + ) { + workInProgress = bailoutOnAlreadyFinishedWork( + current$$1, + workInProgress, + renderExpirationTime + ); + break a; + } + } else + for ( + oldValue = workInProgress.child, + null !== oldValue && (oldValue.return = workInProgress); + null !== oldValue; + + ) { + var list = oldValue.contextDependencies; + if (null !== list) { + getDerivedStateFromProps = oldValue.child; + for (var dependency = list.first; null !== dependency; ) { + if ( + dependency.context === updateExpirationTime && + 0 !== (dependency.observedBits & hasContext) + ) { + 1 === oldValue.tag && + ((dependency = createUpdate(renderExpirationTime)), + (dependency.tag = 2), + enqueueUpdate(oldValue, dependency)); + oldValue.expirationTime < renderExpirationTime && + (oldValue.expirationTime = renderExpirationTime); + dependency = oldValue.alternate; + null !== dependency && + dependency.expirationTime < renderExpirationTime && + (dependency.expirationTime = renderExpirationTime); + dependency = renderExpirationTime; + for (var node = oldValue.return; null !== node; ) { + var alternate = node.alternate; + if (node.childExpirationTime < dependency) + (node.childExpirationTime = dependency), + null !== alternate && + alternate.childExpirationTime < dependency && + (alternate.childExpirationTime = dependency); + else if ( + null !== alternate && + alternate.childExpirationTime < dependency + ) + alternate.childExpirationTime = dependency; + else break; + node = node.return; + } + list.expirationTime < renderExpirationTime && + (list.expirationTime = renderExpirationTime); + break; + } + dependency = dependency.next; + } + } else + getDerivedStateFromProps = + 10 === oldValue.tag + ? oldValue.type === workInProgress.type + ? null + : oldValue.child + : oldValue.child; + if (null !== getDerivedStateFromProps) + getDerivedStateFromProps.return = oldValue; + else + for ( + getDerivedStateFromProps = oldValue; + null !== getDerivedStateFromProps; + + ) { + if (getDerivedStateFromProps === workInProgress) { + getDerivedStateFromProps = null; + break; + } + oldValue = getDerivedStateFromProps.sibling; + if (null !== oldValue) { + oldValue.return = getDerivedStateFromProps.return; + getDerivedStateFromProps = oldValue; + break; + } + getDerivedStateFromProps = getDerivedStateFromProps.return; + } + oldValue = getDerivedStateFromProps; + } + } + reconcileChildren( + current$$1, + workInProgress, + context.children, + renderExpirationTime + ); + workInProgress = workInProgress.child; + } + return workInProgress; + case 9: + return ( + (context = workInProgress.type), + (hasContext = workInProgress.pendingProps), + (updateExpirationTime = hasContext.children), + prepareToReadContext(workInProgress, renderExpirationTime), + (context = readContext(context, hasContext.unstable_observedBits)), + (updateExpirationTime = updateExpirationTime(context)), + (workInProgress.effectTag |= 1), + reconcileChildren( + current$$1, + workInProgress, + updateExpirationTime, + renderExpirationTime + ), + workInProgress.child + ); + case 14: + return ( + (context = workInProgress.type), + (hasContext = resolveDefaultProps( + context, + workInProgress.pendingProps + )), + (hasContext = resolveDefaultProps(context.type, hasContext)), + updateMemoComponent( + current$$1, + workInProgress, + context, + hasContext, + updateExpirationTime, + renderExpirationTime + ) + ); + case 15: + return updateSimpleMemoComponent( + current$$1, + workInProgress, + workInProgress.type, + workInProgress.pendingProps, + updateExpirationTime, + renderExpirationTime + ); + case 17: + return ( + (updateExpirationTime = workInProgress.type), + (context = workInProgress.pendingProps), + (context = + workInProgress.elementType === updateExpirationTime + ? context + : resolveDefaultProps(updateExpirationTime, context)), + null !== current$$1 && + ((current$$1.alternate = null), + (workInProgress.alternate = null), + (workInProgress.effectTag |= 2)), + (workInProgress.tag = 1), + isContextProvider(updateExpirationTime) + ? ((current$$1 = !0), pushContextProvider(workInProgress)) + : (current$$1 = !1), + prepareToReadContext(workInProgress, renderExpirationTime), + constructClassInstance( + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ), + mountClassInstance( + workInProgress, + updateExpirationTime, + context, + renderExpirationTime + ), + finishClassComponent( + null, + workInProgress, + updateExpirationTime, + !0, + current$$1, + renderExpirationTime + ) + ); + } + throw ReactError( + "Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue." + ); +}; +function schedulePendingInteraction(root, expirationTime) { + var interactions = tracing.__interactionsRef.current; + if (0 < interactions.size) { + var pendingInteractionMap = root.pendingInteractionMap, + pendingInteractions = pendingInteractionMap.get(expirationTime); + null != pendingInteractions + ? interactions.forEach(function(interaction) { + pendingInteractions.has(interaction) || interaction.__count++; + pendingInteractions.add(interaction); + }) + : (pendingInteractionMap.set(expirationTime, new Set(interactions)), + interactions.forEach(function(interaction) { + interaction.__count++; + })); + pendingInteractionMap = tracing.__subscriberRef.current; + if (null !== pendingInteractionMap) + pendingInteractionMap.onWorkScheduled( + interactions, + 1e3 * expirationTime + root.interactionThreadID + ); + } +} +function startWorkOnPendingInteraction(root, expirationTime) { + var interactions = new Set(); + root.pendingInteractionMap.forEach(function( + scheduledInteractions, + scheduledExpirationTime + ) { + scheduledExpirationTime >= expirationTime && + scheduledInteractions.forEach(function(interaction) { + return interactions.add(interaction); + }); + }); + root.memoizedInteractions = interactions; + if (0 < interactions.size) { + var subscriber = tracing.__subscriberRef.current; + if (null !== subscriber) { + root = 1e3 * expirationTime + root.interactionThreadID; + try { + subscriber.onWorkStarted(interactions, root); + } catch (error) { + scheduleCallback(99, function() { + throw error; + }); + } + } + } +} +function finishPendingInteractions(root, committedExpirationTime) { + var earliestRemainingTimeAfterCommit = root.firstPendingTime, + subscriber = void 0; + try { + if ( + ((subscriber = tracing.__subscriberRef.current), + null !== subscriber && 0 < root.memoizedInteractions.size) + ) + subscriber.onWorkStopped( + root.memoizedInteractions, + 1e3 * committedExpirationTime + root.interactionThreadID + ); + } catch (error) { + scheduleCallback(99, function() { + throw error; + }); + } finally { + var pendingInteractionMap = root.pendingInteractionMap; + pendingInteractionMap.forEach(function( + scheduledInteractions, + scheduledExpirationTime + ) { + scheduledExpirationTime > earliestRemainingTimeAfterCommit && + (pendingInteractionMap.delete(scheduledExpirationTime), + scheduledInteractions.forEach(function(interaction) { + interaction.__count--; + if (null !== subscriber && 0 === interaction.__count) + try { + subscriber.onInteractionScheduledWorkCompleted(interaction); + } catch (error) { + scheduleCallback(99, function() { + throw error; + }); + } + })); + }); + } +} +function findHostInstance(component) { + var fiber = component._reactInternalFiber; + if (void 0 === fiber) { + if ("function" === typeof component.render) + throw ReactError("Unable to find node on an unmounted component."); + throw ReactError( + "Argument appears to not be a ReactComponent. Keys: " + + Object.keys(component) + ); + } + component = findCurrentHostFiber(fiber); + return null === component ? null : component.stateNode; +} +function updateContainer(element, container, parentComponent, callback) { + var current$$1 = container.current, + currentTime = requestCurrentTime(); + current$$1 = computeExpirationForFiber(currentTime, current$$1); + currentTime = container.current; + a: if (parentComponent) { + parentComponent = parentComponent._reactInternalFiber; + b: { + if ( + 2 !== isFiberMountedImpl(parentComponent) || + 1 !== parentComponent.tag + ) + throw ReactError( + "Expected subtree parent to be a mounted class component. This error is likely caused by a bug in React. Please file an issue." + ); + var parentContext = parentComponent; + do { + switch (parentContext.tag) { + case 3: + parentContext = parentContext.stateNode.context; + break b; + case 1: + if (isContextProvider(parentContext.type)) { + parentContext = + parentContext.stateNode + .__reactInternalMemoizedMergedChildContext; + break b; + } + } + parentContext = parentContext.return; + } while (null !== parentContext); + throw ReactError( + "Found unexpected detached subtree parent. This error is likely caused by a bug in React. Please file an issue." + ); + } + if (1 === parentComponent.tag) { + var Component = parentComponent.type; + if (isContextProvider(Component)) { + parentComponent = processChildContext( + parentComponent, + Component, + parentContext + ); + break a; + } + } + parentComponent = parentContext; + } else parentComponent = emptyContextObject; + null === container.context + ? (container.context = parentComponent) + : (container.pendingContext = parentComponent); + container = callback; + callback = createUpdate(current$$1); + callback.payload = { element: element }; + container = void 0 === container ? null : container; + null !== container && (callback.callback = container); + flushPassiveEffects(); + enqueueUpdate(currentTime, callback); + scheduleUpdateOnFiber(currentTime, current$$1); + return current$$1; +} +function createPortal(children, containerInfo, implementation) { + var key = + 3 < arguments.length && void 0 !== arguments[3] ? arguments[3] : null; + return { + $$typeof: REACT_PORTAL_TYPE, + key: null == key ? null : "" + key, + children: children, + containerInfo: containerInfo, + implementation: implementation + }; +} +function _inherits(subClass, superClass) { + if ("function" !== typeof superClass && null !== superClass) + throw new TypeError( + "Super expression must either be null or a function, not " + + typeof superClass + ); + subClass.prototype = Object.create(superClass && superClass.prototype, { + constructor: { + value: subClass, + enumerable: !1, + writable: !0, + configurable: !0 + } + }); + superClass && + (Object.setPrototypeOf + ? Object.setPrototypeOf(subClass, superClass) + : (subClass.__proto__ = superClass)); +} +var getInspectorDataForViewTag = void 0; +getInspectorDataForViewTag = function() { + throw ReactError( + "getInspectorDataForViewTag() is not available in production" + ); +}; +function findNodeHandle(componentOrHandle) { + if (null == componentOrHandle) return null; + if ("number" === typeof componentOrHandle) return componentOrHandle; + if (componentOrHandle._nativeTag) return componentOrHandle._nativeTag; + if (componentOrHandle.canonical && componentOrHandle.canonical._nativeTag) + return componentOrHandle.canonical._nativeTag; + componentOrHandle = findHostInstance(componentOrHandle); + return null == componentOrHandle + ? componentOrHandle + : componentOrHandle.canonical + ? componentOrHandle.canonical._nativeTag + : componentOrHandle._nativeTag; +} +_batchedUpdatesImpl = function(fn, a) { + if (0 !== workPhase) return fn(a); + workPhase = 1; + try { + return fn(a); + } finally { + (workPhase = 0), flushImmediateQueue(); + } +}; +_flushInteractiveUpdatesImpl = function() { + workPhase !== RenderPhase && + workPhase !== CommitPhase && + flushPendingDiscreteUpdates(); +}; +var roots = new Map(), + ReactNativeRenderer = { + NativeComponent: (function(findNodeHandle, findHostInstance) { + return (function(_React$Component) { + function ReactNativeComponent() { + if (!(this instanceof ReactNativeComponent)) + throw new TypeError("Cannot call a class as a function"); + var call = _React$Component.apply(this, arguments); + if (!this) + throw new ReferenceError( + "this hasn't been initialised - super() hasn't been called" + ); + return !call || + ("object" !== typeof call && "function" !== typeof call) + ? this + : call; + } + _inherits(ReactNativeComponent, _React$Component); + ReactNativeComponent.prototype.blur = function() { + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); + }; + ReactNativeComponent.prototype.focus = function() { + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); + }; + ReactNativeComponent.prototype.measure = function(callback) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null != maybeInstance && + (maybeInstance.canonical + ? nativeFabricUIManager.measure( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ) + : ReactNativePrivateInterface.UIManager.measure( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + )); + }; + ReactNativeComponent.prototype.measureInWindow = function(callback) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null != maybeInstance && + (maybeInstance.canonical + ? nativeFabricUIManager.measureInWindow( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ) + : ReactNativePrivateInterface.UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + )); + }; + ReactNativeComponent.prototype.measureLayout = function( + relativeToNativeNode, + onSuccess, + onFail + ) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null == maybeInstance || + maybeInstance.canonical || + ((maybeInstance = void 0), + "number" === typeof relativeToNativeNode + ? (maybeInstance = relativeToNativeNode) + : relativeToNativeNode._nativeTag && + (maybeInstance = relativeToNativeNode._nativeTag), + null != maybeInstance && + ReactNativePrivateInterface.UIManager.measureLayout( + findNodeHandle(this), + maybeInstance, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + )); + }; + ReactNativeComponent.prototype.setNativeProps = function(nativeProps) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + if (null != maybeInstance && !maybeInstance.canonical) { + var nativeTag = + maybeInstance._nativeTag || maybeInstance.canonical._nativeTag; + maybeInstance = + maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; + nativeProps = diffProperties( + null, + emptyObject, + nativeProps, + maybeInstance.validAttributes + ); + null != nativeProps && + ReactNativePrivateInterface.UIManager.updateView( + nativeTag, + maybeInstance.uiViewClassName, + nativeProps + ); + } + }; + return ReactNativeComponent; + })(React.Component); + })(findNodeHandle, findHostInstance), + findNodeHandle: findNodeHandle, + setNativeProps: function(handle, nativeProps) { + null != handle._nativeTag && + ((nativeProps = diffProperties( + null, + emptyObject, + nativeProps, + handle.viewConfig.validAttributes + )), + null != nativeProps && + ReactNativePrivateInterface.UIManager.updateView( + handle._nativeTag, + handle.viewConfig.uiViewClassName, + nativeProps + )); + }, + render: function(element, containerTag, callback) { + var root = roots.get(containerTag); + if (!root) { + root = new FiberRootNode(containerTag, !1); + var uninitializedFiber = 0; + isDevToolsPresent && (uninitializedFiber |= 4); + uninitializedFiber = createFiber(3, null, null, uninitializedFiber); + root.current = uninitializedFiber; + uninitializedFiber.stateNode = root; + roots.set(containerTag, root); + } + updateContainer(element, root, null, callback); + a: if (((element = root.current), element.child)) + switch (element.child.tag) { + case 5: + element = element.child.stateNode; + break a; + default: + element = element.child.stateNode; + } + else element = null; + return element; + }, + unmountComponentAtNode: function(containerTag) { + var root = roots.get(containerTag); + root && + updateContainer(null, root, null, function() { + roots.delete(containerTag); + }); + }, + unmountComponentAtNodeAndRemoveContainer: function(containerTag) { + ReactNativeRenderer.unmountComponentAtNode(containerTag); + ReactNativePrivateInterface.UIManager.removeRootView(containerTag); + }, + createPortal: function(children, containerTag) { + return createPortal( + children, + containerTag, + null, + 2 < arguments.length && void 0 !== arguments[2] ? arguments[2] : null + ); + }, + unstable_batchedUpdates: batchedUpdates, + __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { + NativeMethodsMixin: (function(findNodeHandle, findHostInstance) { + return { + measure: function(callback) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null != maybeInstance && + (maybeInstance.canonical + ? nativeFabricUIManager.measure( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ) + : ReactNativePrivateInterface.UIManager.measure( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + )); + }, + measureInWindow: function(callback) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null != maybeInstance && + (maybeInstance.canonical + ? nativeFabricUIManager.measureInWindow( + maybeInstance.node, + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + ) + : ReactNativePrivateInterface.UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback_NOT_REALLY_SAFE(this, callback) + )); + }, + measureLayout: function(relativeToNativeNode, onSuccess, onFail) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + null == maybeInstance || + maybeInstance.canonical || + ((maybeInstance = void 0), + "number" === typeof relativeToNativeNode + ? (maybeInstance = relativeToNativeNode) + : relativeToNativeNode._nativeTag && + (maybeInstance = relativeToNativeNode._nativeTag), + null != maybeInstance && + ReactNativePrivateInterface.UIManager.measureLayout( + findNodeHandle(this), + maybeInstance, + mountSafeCallback_NOT_REALLY_SAFE(this, onFail), + mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess) + )); + }, + setNativeProps: function(nativeProps) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + if (null != maybeInstance && !maybeInstance.canonical) { + var nativeTag = + maybeInstance._nativeTag || maybeInstance.canonical._nativeTag; + maybeInstance = + maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; + nativeProps = diffProperties( + null, + emptyObject, + nativeProps, + maybeInstance.validAttributes + ); + null != nativeProps && + ReactNativePrivateInterface.UIManager.updateView( + nativeTag, + maybeInstance.uiViewClassName, + nativeProps + ); + } + }, + focus: function() { + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); + }, + blur: function() { + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); + } + }; + })(findNodeHandle, findHostInstance), + computeComponentStackForErrorReporting: function(reactTag) { + return (reactTag = getInstanceFromTag(reactTag)) + ? getStackByFiberInDevAndProd(reactTag) + : ""; + } + } + }; +(function(devToolsConfig) { + var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; + return injectInternals( + Object.assign({}, devToolsConfig, { + overrideHookState: null, + overrideProps: null, + setSuspenseHandler: null, + scheduleUpdate: null, + currentDispatcherRef: ReactSharedInternals.ReactCurrentDispatcher, + findHostInstanceByFiber: function(fiber) { + fiber = findCurrentHostFiber(fiber); + return null === fiber ? null : fiber.stateNode; + }, + findFiberByHostInstance: function(instance) { + return findFiberByHostInstance + ? findFiberByHostInstance(instance) + : null; + } + }) + ); +})({ + findFiberByHostInstance: getInstanceFromTag, + getInspectorDataForViewTag: getInspectorDataForViewTag, + bundleType: 0, + version: "16.8.6", + rendererPackageName: "react-native-renderer" +}); +var ReactNativeRenderer$2 = { default: ReactNativeRenderer }, + ReactNativeRenderer$3 = + (ReactNativeRenderer$2 && ReactNativeRenderer) || ReactNativeRenderer$2; +module.exports = ReactNativeRenderer$3.default || ReactNativeRenderer$3; diff --git a/Libraries/Renderer/oss/ReactNativeRenderer-profiling.js b/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.js similarity index 98% rename from Libraries/Renderer/oss/ReactNativeRenderer-profiling.js rename to Libraries/Renderer/implementations/ReactNativeRenderer-profiling.js index 5a356fca8b050c..0df2e6154a6b70 100644 --- a/Libraries/Renderer/oss/ReactNativeRenderer-profiling.js +++ b/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.js @@ -11,17 +11,11 @@ */ "use strict"; -require("InitializeCore"); -var ReactNativeViewConfigRegistry = require("ReactNativeViewConfigRegistry"), - UIManager = require("UIManager"), - RCTEventEmitter = require("RCTEventEmitter"), +require("react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore"); +var ReactNativePrivateInterface = require("react-native/Libraries/ReactPrivate/ReactNativePrivateInterface"), React = require("react"), - deepDiffer = require("deepDiffer"), - flattenStyle = require("flattenStyle"), - TextInputState = require("TextInputState"), Scheduler = require("scheduler"), - tracing = require("scheduler/tracing"), - ExceptionsManager = require("ExceptionsManager"); + tracing = require("scheduler/tracing"); function ReactError(message) { message = Error(message); message.name = "Invariant Violation"; @@ -618,7 +612,7 @@ function changeResponder(nextResponderInst, blockHostResponder) { blockHostResponder ); } -var eventTypes$1 = { +var eventTypes = { startShouldSetResponder: { phasedRegistrationNames: { bubbled: "onStartShouldSetResponder", @@ -681,7 +675,7 @@ var eventTypes$1 = { _getResponder: function() { return responderInst; }, - eventTypes: eventTypes$1, + eventTypes: eventTypes, extractEvents: function( topLevelType, targetInst, @@ -710,12 +704,12 @@ var eventTypes$1 = { isMoveish(topLevelType)) ) { var JSCompiler_temp = isStartish(topLevelType) - ? eventTypes$1.startShouldSetResponder + ? eventTypes.startShouldSetResponder : isMoveish(topLevelType) - ? eventTypes$1.moveShouldSetResponder + ? eventTypes.moveShouldSetResponder : "topSelectionChange" === topLevelType - ? eventTypes$1.selectionChangeShouldSetResponder - : eventTypes$1.scrollShouldSetResponder; + ? eventTypes.selectionChangeShouldSetResponder + : eventTypes.scrollShouldSetResponder; if (responderInst) b: { var JSCompiler_temp$jscomp$0 = responderInst; @@ -801,7 +795,7 @@ var eventTypes$1 = { JSCompiler_temp && JSCompiler_temp !== responderInst ? ((JSCompiler_temp$jscomp$0 = void 0), (targetInst = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderGrant, + eventTypes.responderGrant, JSCompiler_temp, nativeEvent, nativeEventTarget @@ -811,7 +805,7 @@ var eventTypes$1 = { (depthA = !0 === executeDirectDispatch(targetInst)), responderInst ? ((tempA = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderTerminationRequest, + eventTypes.responderTerminationRequest, responderInst, nativeEvent, nativeEventTarget @@ -823,7 +817,7 @@ var eventTypes$1 = { tempA.isPersistent() || tempA.constructor.release(tempA), tempB ? ((tempA = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderTerminate, + eventTypes.responderTerminate, responderInst, nativeEvent, nativeEventTarget @@ -837,7 +831,7 @@ var eventTypes$1 = { )), changeResponder(JSCompiler_temp, depthA)) : ((JSCompiler_temp = ResponderSyntheticEvent.getPooled( - eventTypes$1.responderReject, + eventTypes.responderReject, JSCompiler_temp, nativeEvent, nativeEventTarget @@ -867,11 +861,11 @@ var eventTypes$1 = { ("topTouchEnd" === topLevelType || "topTouchCancel" === topLevelType); if ( (JSCompiler_temp$jscomp$0 = JSCompiler_temp$jscomp$0 - ? eventTypes$1.responderStart + ? eventTypes.responderStart : targetInst - ? eventTypes$1.responderMove + ? eventTypes.responderMove : depthA - ? eventTypes$1.responderEnd + ? eventTypes.responderEnd : null) ) (JSCompiler_temp$jscomp$0 = ResponderSyntheticEvent.getPooled( @@ -925,9 +919,9 @@ var eventTypes$1 = { } if ( (topLevelType = JSCompiler_temp$jscomp$0 - ? eventTypes$1.responderTerminate + ? eventTypes.responderTerminate : topLevelType - ? eventTypes$1.responderRelease + ? eventTypes.responderRelease : null) ) (nativeEvent = ResponderSyntheticEvent.getPooled( @@ -949,8 +943,15 @@ var eventTypes$1 = { } } }, + customBubblingEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customBubblingEventTypes, + customDirectEventTypes = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry + .customDirectEventTypes, ReactNativeBridgeEventPlugin = { - eventTypes: ReactNativeViewConfigRegistry.eventTypes, + eventTypes: + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes, extractEvents: function( topLevelType, targetInst, @@ -958,10 +959,8 @@ var eventTypes$1 = { nativeEventTarget ) { if (null == targetInst) return null; - var bubbleDispatchConfig = - ReactNativeViewConfigRegistry.customBubblingEventTypes[topLevelType], - directDispatchConfig = - ReactNativeViewConfigRegistry.customDirectEventTypes[topLevelType]; + var bubbleDispatchConfig = customBubblingEventTypes[topLevelType], + directDispatchConfig = customDirectEventTypes[topLevelType]; if (!bubbleDispatchConfig && !directDispatchConfig) throw ReactError( 'Unsupported top level event type "' + topLevelType + '" dispatched' @@ -1061,7 +1060,7 @@ function _receiveRootNodeIDEvent(rootNodeID, topLevelType, nativeEventParam) { } }); } -RCTEventEmitter.register({ +ReactNativePrivateInterface.RCTEventEmitter.register({ receiveEvent: function(rootNodeID, topLevelType, nativeEventParam) { _receiveRootNodeIDEvent(rootNodeID, topLevelType, nativeEventParam); }, @@ -1111,8 +1110,11 @@ getNodeFromInstance = function(inst) { ResponderEventPlugin.injection.injectGlobalResponderHandler({ onChange: function(from, to, blockNativeResponder) { null !== to - ? UIManager.setJSResponder(to.stateNode._nativeTag, blockNativeResponder) - : UIManager.clearJSResponder(); + ? ReactNativePrivateInterface.UIManager.setJSResponder( + to.stateNode._nativeTag, + blockNativeResponder + ) + : ReactNativePrivateInterface.UIManager.clearJSResponder(); } }); var ReactSharedInternals = @@ -1376,14 +1378,14 @@ function diffNestedProperty( return Array.isArray(prevProp) ? diffProperties( updatePayload, - flattenStyle(prevProp), + ReactNativePrivateInterface.flattenStyle(prevProp), nextProp, validAttributes ) : diffProperties( updatePayload, prevProp, - flattenStyle(nextProp), + ReactNativePrivateInterface.flattenStyle(nextProp), validAttributes ); } @@ -1451,7 +1453,7 @@ function diffProperties(updatePayload, prevProps, nextProps, validAttributes) { if ("object" !== typeof attributeConfig) ("object" !== typeof nextProp || null === nextProp || - deepDiffer(prevProp, nextProp)) && + ReactNativePrivateInterface.deepDiffer(prevProp, nextProp)) && ((updatePayload || (updatePayload = {}))[propKey] = nextProp); else if ( "function" === typeof attributeConfig.diff || @@ -1463,7 +1465,7 @@ function diffProperties(updatePayload, prevProps, nextProps, validAttributes) { ? attributeConfig.diff(prevProp, nextProp) : "object" !== typeof nextProp || null === nextProp || - deepDiffer(prevProp, nextProp)) + ReactNativePrivateInterface.deepDiffer(prevProp, nextProp)) ) (attributeConfig = "function" === typeof attributeConfig.process @@ -1528,19 +1530,19 @@ var ReactNativeFiberHostComponent = (function() { this.viewConfig = viewConfig; } ReactNativeFiberHostComponent.prototype.blur = function() { - TextInputState.blurTextInput(this._nativeTag); + ReactNativePrivateInterface.TextInputState.blurTextInput(this._nativeTag); }; ReactNativeFiberHostComponent.prototype.focus = function() { - TextInputState.focusTextInput(this._nativeTag); + ReactNativePrivateInterface.TextInputState.focusTextInput(this._nativeTag); }; ReactNativeFiberHostComponent.prototype.measure = function(callback) { - UIManager.measure( + ReactNativePrivateInterface.UIManager.measure( this._nativeTag, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); }; ReactNativeFiberHostComponent.prototype.measureInWindow = function(callback) { - UIManager.measureInWindow( + ReactNativePrivateInterface.UIManager.measureInWindow( this._nativeTag, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ); @@ -1559,7 +1561,7 @@ var ReactNativeFiberHostComponent = (function() { relativeToNativeNode.canonical._nativeTag && (relativeNode = relativeToNativeNode.canonical._nativeTag); null != relativeNode && - UIManager.measureLayout( + ReactNativePrivateInterface.UIManager.measureLayout( this._nativeTag, relativeNode, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -1576,7 +1578,7 @@ var ReactNativeFiberHostComponent = (function() { this.viewConfig.validAttributes ); null != nativeProps && - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( this._nativeTag, this.viewConfig.uiViewClassName, nativeProps @@ -1589,7 +1591,9 @@ function shim$1() { "The current renderer does not support hydration. This error is likely caused by a bug in React. Please file an issue." ); } -var UPDATE_SIGNAL = {}, +var getViewConfigForType = + ReactNativePrivateInterface.ReactNativeViewConfigRegistry.get, + UPDATE_SIGNAL = {}, nextReactTag = 3; function allocateTag() { var tag = nextReactTag; @@ -1612,7 +1616,10 @@ function finalizeInitialChildren(parentInstance) { var nativeTags = parentInstance._children.map(function(child) { return "number" === typeof child ? child : child._nativeTag; }); - UIManager.setChildren(parentInstance._nativeTag, nativeTags); + ReactNativePrivateInterface.UIManager.setChildren( + parentInstance._nativeTag, + nativeTags + ); return !1; } var scheduleTimeout = setTimeout, @@ -4621,14 +4628,14 @@ function completeWork(current, workInProgress, renderExpirationTime) { else if (newProps) { current = requiredContext(contextStackCursor$1.current); var tag = allocateTag(), - viewConfig = ReactNativeViewConfigRegistry.get(type), + viewConfig = getViewConfigForType(type), updatePayload = diffProperties( null, emptyObject, newProps, viewConfig.validAttributes ); - UIManager.createView( + ReactNativePrivateInterface.UIManager.createView( tag, viewConfig.uiViewClassName, renderExpirationTime, @@ -4671,9 +4678,12 @@ function completeWork(current, workInProgress, renderExpirationTime) { "Text strings must be rendered within a component." ); renderExpirationTime = allocateTag(); - UIManager.createView(renderExpirationTime, "RCTRawText", current, { - text: newProps - }); + ReactNativePrivateInterface.UIManager.createView( + renderExpirationTime, + "RCTRawText", + current, + { text: newProps } + ); instanceCache[renderExpirationTime] = workInProgress; workInProgress.stateNode = renderExpirationTime; } @@ -4769,7 +4779,7 @@ function logCapturedError(capturedError) { "string" === typeof error ? Error(error + "\n\nThis error is located at:" + componentStack) : Error("Unspecified error at:" + componentStack); - ExceptionsManager.handleException(error, !1); + ReactNativePrivateInterface.ExceptionsManager.handleException(error, !1); } var PossiblyWeakSet$1 = "function" === typeof WeakSet ? WeakSet : Set; function logError(boundary, errorInfo) { @@ -4841,7 +4851,7 @@ function hideOrUnhideAllChildren(finishedWork, isHidden) { { style: { display: "none" } }, viewConfig.validAttributes ); - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( instance._nativeTag, viewConfig.uiViewClassName, updatePayload @@ -4859,7 +4869,7 @@ function hideOrUnhideAllChildren(finishedWork, isHidden) { updatePayload, viewConfig.validAttributes ); - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( instance._nativeTag, viewConfig.uiViewClassName, updatePayload @@ -5012,7 +5022,7 @@ function commitPlacement(finishedWork) { ? (children.splice(index, 1), (beforeChild = children.indexOf(beforeChild)), children.splice(beforeChild, 0, stateNode), - UIManager.manageChildren( + ReactNativePrivateInterface.UIManager.manageChildren( parentInstance._nativeTag, [index], [beforeChild], @@ -5022,7 +5032,7 @@ function commitPlacement(finishedWork) { )) : ((index = children.indexOf(beforeChild)), children.splice(index, 0, stateNode), - UIManager.manageChildren( + ReactNativePrivateInterface.UIManager.manageChildren( parentInstance._nativeTag, [], [], @@ -5037,7 +5047,7 @@ function commitPlacement(finishedWork) { } else isContainer - ? UIManager.setChildren(parent, [ + ? ReactNativePrivateInterface.UIManager.setChildren(parent, [ "number" === typeof stateNode ? stateNode : stateNode._nativeTag ]) : ((parentInstance = parent), @@ -5048,7 +5058,7 @@ function commitPlacement(finishedWork) { 0 <= beforeChild ? (index.splice(beforeChild, 1), index.push(stateNode), - UIManager.manageChildren( + ReactNativePrivateInterface.UIManager.manageChildren( parentInstance._nativeTag, [beforeChild], [index.length - 1], @@ -5057,7 +5067,7 @@ function commitPlacement(finishedWork) { [] )) : (index.push(stateNode), - UIManager.manageChildren( + ReactNativePrivateInterface.UIManager.manageChildren( parentInstance._nativeTag, [], [], @@ -5134,7 +5144,14 @@ function unmountHostComponents(current$$1) { if (currentParentIsContainer) (root = currentParent), recursivelyUncacheFiberNode(node.stateNode), - UIManager.manageChildren(root, [], [], [], [], [0]); + ReactNativePrivateInterface.UIManager.manageChildren( + root, + [], + [], + [], + [], + [0] + ); else { root = currentParent; var child = node.stateNode; @@ -5142,7 +5159,14 @@ function unmountHostComponents(current$$1) { node$jscomp$0 = root._children; child = node$jscomp$0.indexOf(child); node$jscomp$0.splice(child, 1); - UIManager.manageChildren(root._nativeTag, [], [], [], [], [child]); + ReactNativePrivateInterface.UIManager.manageChildren( + root._nativeTag, + [], + [], + [], + [], + [child] + ); } } else if (4 === node.tag) { if (null !== node.child) { @@ -5194,7 +5218,7 @@ function commitWork(current$$1, finishedWork) { finishedWork.validAttributes )), null != newProps && - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( instance._nativeTag, finishedWork.uiViewClassName, newProps @@ -5206,9 +5230,11 @@ function commitWork(current$$1, finishedWork) { throw ReactError( "This should have a text node initialized. This error is likely caused by a bug in React. Please file an issue." ); - UIManager.updateView(finishedWork.stateNode, "RCTRawText", { - text: finishedWork.memoizedProps - }); + ReactNativePrivateInterface.UIManager.updateView( + finishedWork.stateNode, + "RCTRawText", + { text: finishedWork.memoizedProps } + ); break; case 20: break; @@ -7137,10 +7163,14 @@ var roots = new Map(), } _inherits(ReactNativeComponent, _React$Component); ReactNativeComponent.prototype.blur = function() { - TextInputState.blurTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); }; ReactNativeComponent.prototype.focus = function() { - TextInputState.focusTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); }; ReactNativeComponent.prototype.measure = function(callback) { var maybeInstance = void 0; @@ -7153,7 +7183,7 @@ var roots = new Map(), maybeInstance.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ) - : UIManager.measure( + : ReactNativePrivateInterface.UIManager.measure( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) )); @@ -7169,7 +7199,7 @@ var roots = new Map(), maybeInstance.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ) - : UIManager.measureInWindow( + : ReactNativePrivateInterface.UIManager.measureInWindow( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) )); @@ -7191,7 +7221,7 @@ var roots = new Map(), : relativeToNativeNode._nativeTag && (maybeInstance = relativeToNativeNode._nativeTag), null != maybeInstance && - UIManager.measureLayout( + ReactNativePrivateInterface.UIManager.measureLayout( findNodeHandle(this), maybeInstance, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -7215,7 +7245,7 @@ var roots = new Map(), maybeInstance.validAttributes ); null != nativeProps && - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( nativeTag, maybeInstance.uiViewClassName, nativeProps @@ -7235,7 +7265,7 @@ var roots = new Map(), handle.viewConfig.validAttributes )), null != nativeProps && - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( handle._nativeTag, handle.viewConfig.uiViewClassName, nativeProps @@ -7273,7 +7303,7 @@ var roots = new Map(), }, unmountComponentAtNodeAndRemoveContainer: function(containerTag) { ReactNativeRenderer.unmountComponentAtNode(containerTag); - UIManager.removeRootView(containerTag); + ReactNativePrivateInterface.UIManager.removeRootView(containerTag); }, createPortal: function(children, containerTag) { return createPortal( @@ -7298,7 +7328,7 @@ var roots = new Map(), maybeInstance.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ) - : UIManager.measure( + : ReactNativePrivateInterface.UIManager.measure( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) )); @@ -7314,7 +7344,7 @@ var roots = new Map(), maybeInstance.node, mountSafeCallback_NOT_REALLY_SAFE(this, callback) ) - : UIManager.measureInWindow( + : ReactNativePrivateInterface.UIManager.measureInWindow( findNodeHandle(this), mountSafeCallback_NOT_REALLY_SAFE(this, callback) )); @@ -7332,7 +7362,7 @@ var roots = new Map(), : relativeToNativeNode._nativeTag && (maybeInstance = relativeToNativeNode._nativeTag), null != maybeInstance && - UIManager.measureLayout( + ReactNativePrivateInterface.UIManager.measureLayout( findNodeHandle(this), maybeInstance, mountSafeCallback_NOT_REALLY_SAFE(this, onFail), @@ -7356,7 +7386,7 @@ var roots = new Map(), maybeInstance.validAttributes ); null != nativeProps && - UIManager.updateView( + ReactNativePrivateInterface.UIManager.updateView( nativeTag, maybeInstance.uiViewClassName, nativeProps @@ -7364,10 +7394,14 @@ var roots = new Map(), } }, focus: function() { - TextInputState.focusTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.focusTextInput( + findNodeHandle(this) + ); }, blur: function() { - TextInputState.blurTextInput(findNodeHandle(this)); + ReactNativePrivateInterface.TextInputState.blurTextInput( + findNodeHandle(this) + ); } }; })(findNodeHandle, findHostInstance), diff --git a/Libraries/Renderer/shims/ReactFabric.js b/Libraries/Renderer/shims/ReactFabric.js index 5cea0e09037851..8f6a708fd20579 100644 --- a/Libraries/Renderer/shims/ReactFabric.js +++ b/Libraries/Renderer/shims/ReactFabric.js @@ -10,7 +10,7 @@ 'use strict'; -const BatchedBridge = require('../../BatchedBridge/BatchedBridge'); +import {BatchedBridge} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface'; // TODO @sema: Adjust types import type {ReactNativeType} from './ReactNativeTypes'; @@ -18,9 +18,9 @@ import type {ReactNativeType} from './ReactNativeTypes'; let ReactFabric; if (__DEV__) { - ReactFabric = require('ReactFabric-dev'); + ReactFabric = require('../implementations/ReactFabric-dev'); } else { - ReactFabric = require('ReactFabric-prod'); + ReactFabric = require('../implementations/ReactFabric-prod'); } BatchedBridge.registerCallableModule('ReactFabric', ReactFabric); diff --git a/Libraries/Renderer/shims/ReactFeatureFlags.js b/Libraries/Renderer/shims/ReactFeatureFlags.js new file mode 100644 index 00000000000000..86feb9c0228212 --- /dev/null +++ b/Libraries/Renderer/shims/ReactFeatureFlags.js @@ -0,0 +1,17 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow + */ + +'use strict'; + +const ReactFeatureFlags = { + debugRenderPhaseSideEffects: false, +}; + +module.exports = ReactFeatureFlags; diff --git a/Libraries/Renderer/shims/ReactNative.js b/Libraries/Renderer/shims/ReactNative.js index 857858e55bd39a..9f471e4107a7ee 100644 --- a/Libraries/Renderer/shims/ReactNative.js +++ b/Libraries/Renderer/shims/ReactNative.js @@ -15,9 +15,9 @@ import type {ReactNativeType} from './ReactNativeTypes'; let ReactNative; if (__DEV__) { - ReactNative = require('ReactNativeRenderer-dev'); + ReactNative = require('../implementations/ReactNativeRenderer-dev'); } else { - ReactNative = require('ReactNativeRenderer-prod'); + ReactNative = require('../implementations/ReactNativeRenderer-prod'); } module.exports = (ReactNative: ReactNativeType); diff --git a/Libraries/Renderer/shims/createReactNativeComponentClass.js b/Libraries/Renderer/shims/createReactNativeComponentClass.js index c632a3c0fbb35a..86a758d918b483 100644 --- a/Libraries/Renderer/shims/createReactNativeComponentClass.js +++ b/Libraries/Renderer/shims/createReactNativeComponentClass.js @@ -10,9 +10,11 @@ 'use strict'; +import {ReactNativeViewConfigRegistry} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface'; + import type {ViewConfigGetter} from './ReactNativeTypes'; -const {register} = require('./ReactNativeViewConfigRegistry'); +const {register} = ReactNativeViewConfigRegistry; /** * Creates a renderable ReactNative host component. From 2dd7dd8e45f9d4a1086f84d5b70ea66406d98439 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Wed, 5 Jun 2019 04:58:11 -0700 Subject: [PATCH 0201/1084] Removed autoresizing mask for modal host container view (#25150) Summary: Fixes #18177 . Related #24497. Autoresizing mask would conflict with `AutoLayout`. For example , it would impact `SafeAreaView`. And actually we don't need to use autoresizing mask, we observe the bounds change notification and [update the frame manually](https://github.com/facebook/react-native/blob/1151c096dab17e5d9a6ac05b61aacecd4305f3db/React/Views/RCTModalHostView.m#L59). ## Changelog [iOS] [Fixed] - Removed autoresizing mask for modal host container view Pull Request resolved: https://github.com/facebook/react-native/pull/25150 Differential Revision: D15645148 Pulled By: cpojer fbshipit-source-id: 95d5f40feaa980b959a3de6e273dccac8158c57b --- React/Views/RCTModalHostView.m | 2 -- 1 file changed, 2 deletions(-) diff --git a/React/Views/RCTModalHostView.m b/React/Views/RCTModalHostView.m index f586e4ad0eadb5..bc0cac18b3ec94 100644 --- a/React/Views/RCTModalHostView.m +++ b/React/Views/RCTModalHostView.m @@ -129,8 +129,6 @@ - (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)atIndex [subview addGestureRecognizer:_menuButtonGestureRecognizer]; } #endif - subview.autoresizingMask = UIViewAutoresizingFlexibleHeight | - UIViewAutoresizingFlexibleWidth; [_modalViewController.view insertSubview:subview atIndex:0]; _reactSubview = subview; From 68bca1fbd042f87ec29b65abf8ebb3e4a8234bc1 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Wed, 5 Jun 2019 05:08:59 -0700 Subject: [PATCH 0202/1084] Excluded tests file from JSI pod (#25151) Summary: Tests file exposed in https://github.com/facebook/react-native/commit/608b1b5ea2d9861816aaf3c4289e4316d9304b87. This break e2e tests, so let's excluded them from JSI pod. ## Changelog [iOS] [Fixed] - Excluded tests file from JSI pod Pull Request resolved: https://github.com/facebook/react-native/pull/25151 Differential Revision: D15645046 Pulled By: cpojer fbshipit-source-id: 19c712e4307cf712b8377d721661a2b476151732 --- ReactCommon/React-Fabric.podspec | 2 +- ReactCommon/jsi/React-jsi.podspec | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ReactCommon/React-Fabric.podspec b/ReactCommon/React-Fabric.podspec index 9fe685f5701775..ea8116e2cec922 100644 --- a/ReactCommon/React-Fabric.podspec +++ b/ReactCommon/React-Fabric.podspec @@ -69,7 +69,7 @@ Pod::Spec.new do |s| ss.dependency folly_dep_name, folly_version ss.compiler_flags = folly_compiler_flags + ' ' + boost_compiler_flags ss.source_files = "fabric/core/**/*.{m,mm,cpp,h}" - ss.exclude_files = "**/tests/*" + ss.exclude_files = "**/tests/**/*" ss.header_dir = "react/core" ss.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost-for-react-native\" \"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_ROOT)/Folly\"" } end diff --git a/ReactCommon/jsi/React-jsi.podspec b/ReactCommon/jsi/React-jsi.podspec index 180905ca40b443..0b0ff66eb581e8 100644 --- a/ReactCommon/jsi/React-jsi.podspec +++ b/ReactCommon/jsi/React-jsi.podspec @@ -31,6 +31,7 @@ Pod::Spec.new do |s| s.platforms = { :ios => "9.0", :tvos => "9.2" } s.source = source s.source_files = "**/*.{cpp,h}" + s.exclude_files = "**/test/*" s.framework = "JavaScriptCore" s.compiler_flags = folly_compiler_flags + ' ' + boost_compiler_flags s.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost-for-react-native\" \"$(PODS_ROOT)/Folly\"" } From 995b4d30491d2336fed4a975e965668d9c8d5b7c Mon Sep 17 00:00:00 2001 From: Nate Date: Wed, 5 Jun 2019 06:09:09 -0700 Subject: [PATCH 0203/1084] Android Fix for 9145: No longer hard code build port (#23616) Summary: ### Problem According to https://github.com/facebook/react-native/issues/9145, the `--port` setting is not respected when executing `react-native run-android`. The templates that report things like what port the dev server runs on are hard coded as well. ### Solution This commit replaces the hardcoded instances of port 8081 on Android with a build configuration property. This allows setting of the port React Native Android connects to for the local build server. For this change to work, there must also be an update to the react native CLI to pass along this setting: https://github.com/react-native-community/react-native-cli/compare/master...nhunzaker:9145-android-no-port-hardcode-cli To avoid some noise on their end, I figured I wouldn't submit a PR until it's this approach is deemed workable. ## Changelog [Android][fixed] - `react-native run-android --port ` correctly connects to dev server and related error messages display the correct port Pull Request resolved: https://github.com/facebook/react-native/pull/23616 Differential Revision: D15645200 Pulled By: cpojer fbshipit-source-id: 3bdfd458b8ac3ec78290736c9ed0db2e5776ed46 --- ReactAndroid/build.gradle | 14 +++++++ .../facebook/react/bridge/JSBundleLoader.java | 4 +- .../react/common/DebugServerException.java | 19 ++++++---- .../react/devsupport/BundleDownloader.java | 8 ++-- .../react/devsupport/DevServerHelper.java | 7 ++-- .../systeminfo/AndroidInfoHelpers.java | 37 +++++++++++++++---- .../modules/systeminfo/AndroidInfoModule.java | 17 +++++++-- .../facebook/react/modules/systeminfo/BUCK | 3 ++ .../PackagerConnectionSettings.java | 12 +++--- ReactAndroid/src/main/res/BUCK | 9 +++++ .../src/main/res/systeminfo/values/values.xml | 5 +++ react.gradle | 16 ++++++++ 12 files changed, 119 insertions(+), 32 deletions(-) create mode 100644 ReactAndroid/src/main/res/systeminfo/values/values.xml diff --git a/ReactAndroid/build.gradle b/ReactAndroid/build.gradle index 81e2d74ac759cd..f04bb4ad12db20 100644 --- a/ReactAndroid/build.gradle +++ b/ReactAndroid/build.gradle @@ -203,6 +203,16 @@ def findNdkBuildFullPath() { return null } +def reactNativeDevServerPort() { + def value = project.getProperties().get("reactNativeDevServerPort") + return value != null ? value : "8081" +} + +def reactNativeInspectorProxyPort() { + def value = project.getProperties().get("reactNativeInspectorProxyPort") + return value != null ? value : reactNativeDevServerPort() +} + def getNdkBuildFullPath() { def ndkBuildFullPath = findNdkBuildFullPath() if (ndkBuildFullPath == null) { @@ -288,6 +298,10 @@ android { buildConfigField("boolean", "IS_INTERNAL_BUILD", "false") buildConfigField("int", "EXOPACKAGE_FLAGS", "0") + + resValue "integer", "react_native_dev_server_port", reactNativeDevServerPort() + resValue "integer", "react_native_inspector_proxy_port", reactNativeInspectorProxyPort() + testApplicationId("com.facebook.react.tests.gradle") testInstrumentationRunner("androidx.test.runner.AndroidJUnitRunner") } diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.java index 3aff0da69e3026..9a67632c5c3661 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.java @@ -72,7 +72,7 @@ public String loadScript(JSBundleLoaderDelegate delegate) { delegate.loadScriptFromFile(cachedFileLocation, sourceURL, false); return sourceURL; } catch (Exception e) { - throw DebugServerException.makeGeneric(e.getMessage(), e); + throw DebugServerException.makeGeneric(sourceURL, e.getMessage(), e); } } }; @@ -94,7 +94,7 @@ public String loadScript(JSBundleLoaderDelegate delegate) { delegate.loadScriptFromDeltaBundle(sourceURL, nativeDeltaClient, false); return sourceURL; } catch (Exception e) { - throw DebugServerException.makeGeneric(e.getMessage(), e); + throw DebugServerException.makeGeneric(sourceURL, e.getMessage(), e); } } }; diff --git a/ReactAndroid/src/main/java/com/facebook/react/common/DebugServerException.java b/ReactAndroid/src/main/java/com/facebook/react/common/DebugServerException.java index bc2423b665b8ce..6c84a9bbc6f5f0 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/common/DebugServerException.java +++ b/ReactAndroid/src/main/java/com/facebook/react/common/DebugServerException.java @@ -11,6 +11,7 @@ import java.io.IOException; +import android.net.Uri; import android.text.TextUtils; import com.facebook.common.logging.FLog; @@ -28,15 +29,19 @@ public class DebugServerException extends RuntimeException { "\u2022 Ensure that the packager server is running\n" + "\u2022 Ensure that your device/emulator is connected to your machine and has USB debugging enabled - run 'adb devices' to see a list of connected devices\n" + "\u2022 Ensure Airplane Mode is disabled\n" + - "\u2022 If you're on a physical device connected to the same machine, run 'adb reverse tcp:8081 tcp:8081' to forward requests from your device\n" + - "\u2022 If your device is on the same Wi-Fi network, set 'Debug server host & port for device' in 'Dev settings' to your machine's IP address and the port of the local dev server - e.g. 10.0.1.1:8081\n\n"; + "\u2022 If you're on a physical device connected to the same machine, run 'adb reverse tcp: tcp:' to forward requests from your device\n" + + "\u2022 If your device is on the same Wi-Fi network, set 'Debug server host & port for device' in 'Dev settings' to your machine's IP address and the port of the local dev server - e.g. 10.0.1.1:\n\n"; - public static DebugServerException makeGeneric(String reason, Throwable t) { - return makeGeneric(reason, "", t); + public static DebugServerException makeGeneric(String url, String reason, Throwable t) { + return makeGeneric(url, reason, "", t); } - public static DebugServerException makeGeneric(String reason, String extra, Throwable t) { - return new DebugServerException(reason + GENERIC_ERROR_MESSAGE + extra, t); + public static DebugServerException makeGeneric(String url, String reason, String extra, Throwable t) { + Uri uri = Uri.parse(url); + + String message = GENERIC_ERROR_MESSAGE.replace("", String.valueOf(uri.getPort())); + + return new DebugServerException(reason + message + extra, t); } private DebugServerException(String description, String fileName, int lineNumber, int column) { @@ -56,7 +61,7 @@ public DebugServerException(String detailMessage, Throwable throwable) { * @param str json string returned by the debug server * @return A DebugServerException or null if the string is not of proper form. */ - @Nullable public static DebugServerException parse(String str) { + @Nullable public static DebugServerException parse(String url, String str) { if (TextUtils.isEmpty(str)) { return null; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/BundleDownloader.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/BundleDownloader.java index ba798c14165ccc..e7a6fdb0cffd70 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/BundleDownloader.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/BundleDownloader.java @@ -142,10 +142,12 @@ public void onFailure(Call call, IOException e) { } mDownloadBundleFromURLCall = null; + String url = call.request().url().toString(); + callback.onFailure( - DebugServerException.makeGeneric( + DebugServerException.makeGeneric(url, "Could not connect to development server.", - "URL: " + call.request().url().toString(), + "URL: " + url, e)); } @@ -284,7 +286,7 @@ private void processBundleResult( // Check for server errors. If the server error has the expected form, fail with more info. if (statusCode != 200) { String bodyString = body.readUtf8(); - DebugServerException debugServerException = DebugServerException.parse(bodyString); + DebugServerException debugServerException = DebugServerException.parse(url, bodyString); if (debugServerException != null) { callback.onFailure(debugServerException); } else { diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java index 2f70a32292ece7..deaffe8ed5baec 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java @@ -8,6 +8,7 @@ package com.facebook.react.devsupport; import android.content.Context; +import android.content.res.Resources; import android.os.AsyncTask; import android.os.Handler; import android.os.Looper; @@ -261,7 +262,7 @@ protected Boolean doInBackground(Void... ignore) { public boolean doSync() { try { - String attachToNuclideUrl = getInspectorAttachUrl(title); + String attachToNuclideUrl = getInspectorAttachUrl(context, title); OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder().url(attachToNuclideUrl).build(); client.newCall(request).execute(); @@ -367,11 +368,11 @@ private String getInspectorDeviceUrl() { mPackageName); } - private String getInspectorAttachUrl(String title) { + private String getInspectorAttachUrl(Context context, String title) { return String.format( Locale.US, "http://%s/nuclide/attach-debugger-nuclide?title=%s&app=%s&device=%s", - AndroidInfoHelpers.getServerHost(), + AndroidInfoHelpers.getServerHost(context), title, mPackageName, AndroidInfoHelpers.getFriendlyDeviceName()); diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/AndroidInfoHelpers.java b/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/AndroidInfoHelpers.java index c336a7b5d6ada8..3659abaccc0ec7 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/AndroidInfoHelpers.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/AndroidInfoHelpers.java @@ -8,12 +8,14 @@ import java.io.BufferedReader; import java.io.InputStreamReader; import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; import java.util.Locale; +import android.content.Context; +import android.content.res.Resources; import android.os.Build; import com.facebook.common.logging.FLog; +import com.facebook.react.R; public class AndroidInfoHelpers { @@ -23,9 +25,6 @@ public class AndroidInfoHelpers { public static final String METRO_HOST_PROP_NAME = "metro.host"; - private static final int DEBUG_SERVER_HOST_PORT = 8081; - private static final int INSPECTOR_PROXY_PORT = 8081; - private static final String TAG = AndroidInfoHelpers.class.getSimpleName(); private static boolean isRunningOnGenymotion() { @@ -36,12 +35,24 @@ private static boolean isRunningOnStockEmulator() { return Build.FINGERPRINT.contains("generic"); } - public static String getServerHost() { - return getServerIpAddress(DEBUG_SERVER_HOST_PORT); + public static String getServerHost(Integer port) { + return getServerIpAddress(port); + } + + public static String getServerHost(Context context) { + return getServerIpAddress(getDevServerPort(context)); } - public static String getInspectorProxyHost() { - return getServerIpAddress(INSPECTOR_PROXY_PORT); + public static String getAdbReverseTcpCommand(Integer port) { + return "adb reverse tcp:" + port + " tcp:" + port; + } + + public static String getAdbReverseTcpCommand(Context context) { + return getAdbReverseTcpCommand(getDevServerPort(context)); + } + + public static String getInspectorProxyHost(Context context) { + return getServerIpAddress(getInspectorProxyPort(context)); } // WARNING(festevezga): This RN helper method has been copied to another FB-only target. Any changes should be applied to both. @@ -54,6 +65,16 @@ public static String getFriendlyDeviceName() { } } + private static Integer getDevServerPort(Context context) { + Resources resources = context.getResources(); + return resources.getInteger(R.integer.react_native_dev_server_port); + } + + private static Integer getInspectorProxyPort(Context context) { + Resources resources = context.getResources(); + return resources.getInteger(R.integer.react_native_dev_server_port); + } + private static String getServerIpAddress(int port) { // Since genymotion runs in vbox it use different hostname to refer to adb host. // We detect whether app runs on genymotion and replace js bundle server hostname accordingly diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/AndroidInfoModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/AndroidInfoModule.java index 391dedccd869c5..cf5ca4036c5597 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/AndroidInfoModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/AndroidInfoModule.java @@ -9,10 +9,13 @@ import android.annotation.SuppressLint; import android.app.UiModeManager; +import android.content.Context; import android.content.res.Configuration; +import android.content.res.Resources; import android.os.Build; import android.provider.Settings.Secure; +import com.facebook.react.R; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.common.build.ReactBuildConfig; @@ -35,9 +38,7 @@ public class AndroidInfoModule extends ReactContextBaseJavaModule { public static final String NAME = "PlatformConstants"; private static final String IS_TESTING = "IS_TESTING"; - public AndroidInfoModule(ReactApplicationContext reactContext) { - super(reactContext); - } + public AndroidInfoModule(ReactApplicationContext reactContext) { super(reactContext); } /** * See: https://developer.android.com/reference/android/app/UiModeManager.html#getCurrentModeType() @@ -74,7 +75,7 @@ public String getName() { constants.put("Fingerprint", Build.FINGERPRINT); constants.put("Model", Build.MODEL); if (ReactBuildConfig.DEBUG) { - constants.put("ServerHost", AndroidInfoHelpers.getServerHost()); + constants.put("ServerHost", getServerHost()); } constants.put("isTesting", "true".equals(System.getProperty(IS_TESTING)) || isRunningScreenshotTest()); @@ -96,4 +97,12 @@ private Boolean isRunningScreenshotTest() { return false; } } + + private String getServerHost() { + Resources resources = getReactApplicationContext().getApplicationContext().getResources(); + + Integer devServerPort = resources.getInteger(R.integer.react_native_dev_server_port); + + return AndroidInfoHelpers.getServerHost(devServerPort); + } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/BUCK index 396d6c574e3046..433ecaf80863a3 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/BUCK @@ -14,6 +14,7 @@ rn_android_library( react_native_target("java/com/facebook/react/bridge:bridge"), react_native_target("java/com/facebook/react/common:common"), react_native_target("java/com/facebook/react/module/annotations:annotations"), + react_native_target("res:systeminfo"), ], exported_deps = [ ":systeminfo-moduleless", @@ -29,8 +30,10 @@ rn_android_library( "PUBLIC", ], deps = [ + react_native_target("java/com/facebook/react/common:common"), react_native_dep("libraries/fbcore/src/main/java/com/facebook/common/logging:logging"), react_native_dep("third-party/java/infer-annotations:infer-annotations"), react_native_dep("third-party/java/jsr-305:jsr-305"), + react_native_target("res:systeminfo"), ], ) diff --git a/ReactAndroid/src/main/java/com/facebook/react/packagerconnection/PackagerConnectionSettings.java b/ReactAndroid/src/main/java/com/facebook/react/packagerconnection/PackagerConnectionSettings.java index 98ac8cff7f552e..a154553f0d06b1 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/packagerconnection/PackagerConnectionSettings.java +++ b/ReactAndroid/src/main/java/com/facebook/react/packagerconnection/PackagerConnectionSettings.java @@ -7,13 +7,13 @@ package com.facebook.react.packagerconnection; -import javax.annotation.Nullable; - import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; import android.text.TextUtils; +import javax.annotation.Nullable; + import com.facebook.common.logging.FLog; import com.facebook.infer.annotation.Assertions; import com.facebook.react.modules.systeminfo.AndroidInfoHelpers; @@ -24,10 +24,12 @@ public class PackagerConnectionSettings { private final SharedPreferences mPreferences; private final String mPackageName; + private final Context mAppContext; public PackagerConnectionSettings(Context applicationContext) { mPreferences = PreferenceManager.getDefaultSharedPreferences(applicationContext); mPackageName = applicationContext.getPackageName(); + mAppContext = applicationContext; } public String getDebugServerHost() { @@ -39,12 +41,12 @@ public String getDebugServerHost() { return Assertions.assertNotNull(hostFromSettings); } - String host = AndroidInfoHelpers.getServerHost(); + String host = AndroidInfoHelpers.getServerHost(mAppContext); if (host.equals(AndroidInfoHelpers.DEVICE_LOCALHOST)) { FLog.w( TAG, - "You seem to be running on device. Run 'adb reverse tcp:8081 tcp:8081' " + + "You seem to be running on device. Run '" + AndroidInfoHelpers.getAdbReverseTcpCommand(mAppContext) + "' " + "to forward the debug server's port to the device."); } @@ -52,7 +54,7 @@ public String getDebugServerHost() { } public String getInspectorServerHost() { - return AndroidInfoHelpers.getInspectorProxyHost(); + return AndroidInfoHelpers.getInspectorProxyHost(mAppContext); } public @Nullable String getPackageName() { diff --git a/ReactAndroid/src/main/res/BUCK b/ReactAndroid/src/main/res/BUCK index afb0be006d627c..9d24c6224833fe 100644 --- a/ReactAndroid/src/main/res/BUCK +++ b/ReactAndroid/src/main/res/BUCK @@ -36,4 +36,13 @@ rn_android_resource( ], ) +rn_android_resource( + name = "systeminfo", + package = "com.facebook.react", + res = "systeminfo", + visibility = [ + "PUBLIC", + ], +) + # New resource directories must be added to react-native-github/ReactAndroid/build.gradle diff --git a/ReactAndroid/src/main/res/systeminfo/values/values.xml b/ReactAndroid/src/main/res/systeminfo/values/values.xml new file mode 100644 index 00000000000000..7d52389be83dad --- /dev/null +++ b/ReactAndroid/src/main/res/systeminfo/values/values.xml @@ -0,0 +1,5 @@ + + + 8081 + @integer/react_native_dev_server_port + diff --git a/react.gradle b/react.gradle index 07fd9e3f2541be..9b45a8899c384e 100644 --- a/react.gradle +++ b/react.gradle @@ -15,6 +15,22 @@ def reactRoot = file(config.root ?: "../../") def inputExcludes = config.inputExcludes ?: ["android/**", "ios/**"] def bundleConfig = config.bundleConfig ? "${reactRoot}/${config.bundleConfig}" : null ; +def reactNativeDevServerPort() { + def value = project.getProperties().get("reactNativeDevServerPort") + return value != null ? value : "8081" +} + +def reactNativeInspectorProxyPort() { + def value = project.getProperties().get("reactNativeInspectorProxyPort") + return value != null ? value : reactNativeDevServerPort() +} + +android { + buildTypes.all { + resValue "integer", "react_native_dev_server_port", reactNativeDevServerPort() + resValue "integer", "react_native_inspector_proxy_port", reactNativeInspectorProxyPort() + } +} afterEvaluate { def isAndroidLibrary = plugins.hasPlugin("com.android.library") From 7a2463e1f396ffcfbd86e68170f624d31a1be4e1 Mon Sep 17 00:00:00 2001 From: James Ide Date: Wed, 5 Jun 2019 10:51:51 -0700 Subject: [PATCH 0204/1084] Delete hasteImpl, providesModuleNodeModules, and modulePathNameMapper (#24811) Summary: **Depends on https://github.com/facebook/react-native/pull/25100** This commit depends on having migrated all of RN away from Haste. With 100% standard path-based requires, the key foundation is set and we no longer need `hasteImpl` and related settings in the Jest configuration. This commit deletes the `hasteImpl` file and setting as well as `providesModuleNodeModules` and `modulePathNameMapper`, removing most of the dependency graph overriding performed by Jest. ## Changelog [General] [Changed] - Delete hasteImpl, providesModuleNodeModules, and modulePathNameMapper from Jest config Pull Request resolved: https://github.com/facebook/react-native/pull/24811 Differential Revision: D15659274 Pulled By: cpojer fbshipit-source-id: 8a4a3b97ddf7e38fbe62c6d3cc9c98248bfca343 --- jest-preset.js | 8 --- jest.config.js | 38 ------------- jest/__tests__/hasteImpl-test.js | 93 -------------------------------- jest/hasteImpl.js | 85 +---------------------------- 4 files changed, 2 insertions(+), 222 deletions(-) delete mode 100644 jest/__tests__/hasteImpl-test.js diff --git a/jest-preset.js b/jest-preset.js index 3de412bebd571e..5a3051ff384b2f 100644 --- a/jest-preset.js +++ b/jest-preset.js @@ -9,19 +9,11 @@ 'use strict'; -const dir = __dirname; - module.exports = { haste: { defaultPlatform: 'ios', platforms: ['android', 'ios', 'native'], - hasteImplModulePath: require.resolve('./jest/hasteImpl.js'), - providesModuleNodeModules: ['react-native'], - }, - moduleNameMapper: { - '^React$': require.resolve('react'), }, - modulePathIgnorePatterns: [`${dir}/Libraries/react-native/`], transform: { '^.+\\.(js|ts|tsx)$': 'babel-jest', '^.+\\.(bmp|gif|jpg|jpeg|mp4|png|psd|svg|webp)$': require.resolve( diff --git a/jest.config.js b/jest.config.js index 3ed6cd49c14fb6..a157f236941cf4 100644 --- a/jest.config.js +++ b/jest.config.js @@ -17,9 +17,6 @@ module.exports = { './jest/setup.js', ], 'timers': 'fake', - 'moduleNameMapper': { - '^React$': '/Libraries/react-native/React.js', - }, 'testRegex': '/__tests__/.*-test\\.js$', 'testPathIgnorePatterns': [ '/node_modules/', @@ -29,46 +26,11 @@ module.exports = { ], 'haste': { 'defaultPlatform': 'ios', - 'hasteImplModulePath': '/jest/hasteImpl.js', - 'providesModuleNodeModules': [ - 'react-native', - ], 'platforms': [ 'ios', 'android', ], }, - 'modulePathIgnorePatterns': [ - '/node_modules/(?!react|fbjs|react-native|react-transform-hmr|core-js|promise)/', - 'node_modules/react/node_modules/fbjs/', - 'node_modules/react/lib/ReactDOM.js', - 'node_modules/fbjs/lib/Map.js', - 'node_modules/fbjs/lib/Promise.js', - 'node_modules/fbjs/lib/fetch.js', - 'node_modules/fbjs/lib/ErrorUtils.js', - 'node_modules/fbjs/lib/URI.js', - 'node_modules/fbjs/lib/Deferred.js', - 'node_modules/fbjs/lib/PromiseMap.js', - 'node_modules/fbjs/lib/UserAgent.js', - 'node_modules/fbjs/lib/areEqual.js', - 'node_modules/fbjs/lib/base62.js', - 'node_modules/fbjs/lib/crc32.js', - 'node_modules/fbjs/lib/everyObject.js', - 'node_modules/fbjs/lib/fetchWithRetries.js', - 'node_modules/fbjs/lib/filterObject.js', - 'node_modules/fbjs/lib/flattenArray.js', - 'node_modules/fbjs/lib/forEachObject.js', - 'node_modules/fbjs/lib/isEmpty.js', - 'node_modules/fbjs/lib/removeFromArray.js', - 'node_modules/fbjs/lib/resolveImmediate.js', - 'node_modules/fbjs/lib/someObject.js', - 'node_modules/fbjs/lib/sprintf.js', - 'node_modules/fbjs/lib/xhrSimpleDataSerializer.js', - 'node_modules/jest-cli', - 'node_modules/react/dist', - 'node_modules/fbjs/.*/__mocks__/', - 'node_modules/fbjs/node_modules/', - ], 'unmockedModulePathPatterns': [ 'node_modules/react/', 'Libraries/Renderer', diff --git a/jest/__tests__/hasteImpl-test.js b/jest/__tests__/hasteImpl-test.js deleted file mode 100644 index 9cab29a52215f8..00000000000000 --- a/jest/__tests__/hasteImpl-test.js +++ /dev/null @@ -1,93 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @emails oncall+js_foundation - */ - -'use strict'; - -const path = require('path'); - -const {getHasteName} = require('../hasteImpl'); - -function getPath(...parts) { - return path.join(__dirname, '..', '..', ...parts); -} - -it('returns the correct haste name for a RN library file', () => { - expect( - getHasteName( - getPath( - 'Libraries', - 'Components', - 'AccessibilityInfo', - 'AccessibilityInfo.js', - ), - ), - ).toEqual('AccessibilityInfo'); -}); - -it('returns the correct haste name for a file with a platform suffix', () => { - for (const platform of ['android', 'ios', 'native']) { - expect( - getHasteName( - getPath( - 'Libraries', - 'Components', - 'AccessibilityInfo', - `AccessibilityInfo.${platform}.js`, - ), - ), - ).toEqual('AccessibilityInfo'); - } -}); - -it('returns the correct haste name for a file with a flow suffix', () => { - expect( - getHasteName( - getPath( - 'Libraries', - 'Components', - 'AccessibilityInfo', - 'AccessibilityInfo.ios.js.flow', - ), - ), - ).toEqual('AccessibilityInfo'); -}); - -it('does not calculate the haste name for a file that is not JS', () => { - expect( - getHasteName( - getPath( - 'Libraries', - 'Components', - 'AccessibilityInfo', - 'AccessibilityInfo.txt', - ), - ), - ).toBe(undefined); -}); - -it('does not calculate the haste name for a file outside of RN', () => { - expect( - getHasteName(getPath('..', 'Libraries', 'AccessibilityInfo.txt')), - ).toBe(undefined); -}); - -it('does not calculate the haste name for a blacklisted file', () => { - expect( - getHasteName( - getPath( - 'Libraries', - 'Components', - '__mocks__', - 'AccessibilityInfo', - 'AccessibilityInfo.js', - ), - ), - ).toBe(undefined); -}); diff --git a/jest/hasteImpl.js b/jest/hasteImpl.js index eae413a937df2f..d1c1fad686ba5d 100644 --- a/jest/hasteImpl.js +++ b/jest/hasteImpl.js @@ -5,93 +5,12 @@ * LICENSE file in the root directory of this source tree. * * @format - * @flow */ 'use strict'; -const path = require('path'); -const cli = require('@react-native-community/cli'); - -// Use duck-typing because of Facebook-internal infra that doesn't have the cli package. -const {haste} = (cli.loadConfig && cli.loadConfig()) || { - haste: { - providesModuleNodeModules: [], - platforms: ['ios', 'android'], - }, -}; - -// Detect out-of-tree platforms and add them to the whitelists -const pluginRoots /*: Array */ = haste.providesModuleNodeModules.map( - name => path.resolve(__dirname, '../../', name) + path.sep, -); - -const pluginNameReducers /*: Array<[RegExp, string]> */ = haste.platforms.map( - name => [new RegExp(`^(.*)\\.(${name})$`), '$1'], -); - -const ROOTS = [path.resolve(__dirname, '..') + path.sep, ...pluginRoots]; - -const BLACKLISTED_PATTERNS /*: Array */ = [ - /.*[\\\/]__(mocks|tests)__[\\\/].*/, - /^Libraries[\\\/]Animated[\\\/]src[\\\/]polyfills[\\\/].*/, - /^Libraries[\\\/]Renderer[\\\/]fb[\\\/].*/, - /DerivedData[\\\/].*/, -]; - -const WHITELISTED_PREFIXES /*: Array */ = [ - 'IntegrationTests', - 'Libraries', - 'ReactAndroid', - 'RNTester', -]; - -const NAME_REDUCERS /*: Array<[RegExp, string]> */ = [ - // extract basename - [/^(?:.*[\\\/])?([a-zA-Z0-9$_.-]+)$/, '$1'], - // strip .js/.js.flow suffix - [/^(.*)\.js(\.flow)?$/, '$1'], - // strip native suffix - [/^(.*)\.(native)$/, '$1'], - // strip plugin platform suffixes - ...pluginNameReducers, -]; - -function isHastePath(filePath /*: string */) /*: boolean */ { - if (!filePath.endsWith('.js') && !filePath.endsWith('.js.flow')) { - return false; - } - - const root = ROOTS.find(r => filePath.startsWith(r)); - if (!root) { - return false; - } - - filePath = filePath.substr(root.length); - if (BLACKLISTED_PATTERNS.some(pattern => pattern.test(filePath))) { - return false; - } - return WHITELISTED_PREFIXES.some(prefix => filePath.startsWith(prefix)); -} - module.exports = { - /* - * @return {string|void} hasteName for module at filePath; or undefined if - * filePath is not a haste module - */ - getHasteName( - filePath /*: string */, - sourceCode /*: ?string */, - ) /*: string | void */ { - if (!isHastePath(filePath)) { - return undefined; - } - - const hasteName = NAME_REDUCERS.reduce( - (name, [pattern, replacement]) => name.replace(pattern, replacement), - filePath, - ); - - return hasteName; + getHasteName() { + return undefined; }, }; From c1e03b34dfe29b0ef9dc677b0c7c2c9ae399b782 Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Wed, 5 Jun 2019 15:10:50 -0700 Subject: [PATCH 0205/1084] Sync commit from React Summary: This diff syncs a commit from React to bring in https://github.com/facebook/react/pull/15802#pullrequestreview-245969201 Reviewed By: cpojer Differential Revision: D15660020 fbshipit-source-id: 15d2413a69968b2898bb37d256f35bc09ebc8d58 --- .../implementations/ReactFabric-dev.fb.js | 4 +--- .../implementations/ReactFabric-dev.js | 4 +--- .../implementations/ReactFabric-prod.fb.js | 22 +++++++++---------- .../implementations/ReactFabric-prod.js | 22 +++++++++---------- .../ReactFabric-profiling.fb.js | 22 +++++++++---------- .../implementations/ReactFabric-profiling.js | 22 +++++++++---------- .../ReactNativeRenderer-dev.fb.js | 4 +--- .../ReactNativeRenderer-dev.js | 4 +--- .../ReactNativeRenderer-prod.fb.js | 22 +++++++++---------- .../ReactNativeRenderer-prod.js | 22 +++++++++---------- .../ReactNativeRenderer-profiling.fb.js | 22 +++++++++---------- .../ReactNativeRenderer-profiling.js | 22 +++++++++---------- .../shims/ReactNativeViewConfigRegistry.js | 7 ++---- 13 files changed, 86 insertions(+), 113 deletions(-) diff --git a/Libraries/Renderer/implementations/ReactFabric-dev.fb.js b/Libraries/Renderer/implementations/ReactFabric-dev.fb.js index 01a54327173ccf..d2974a687cf44e 100644 --- a/Libraries/Renderer/implementations/ReactFabric-dev.fb.js +++ b/Libraries/Renderer/implementations/ReactFabric-dev.fb.js @@ -2461,11 +2461,9 @@ var customBubblingEventTypes = var customDirectEventTypes = ReactNativePrivateInterface.ReactNativeViewConfigRegistry .customDirectEventTypes; -var eventTypes$1 = - ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes; var ReactNativeBridgeEventPlugin = { - eventTypes: eventTypes$1, + eventTypes: {}, /** * @see {EventPluginHub.extractEvents} diff --git a/Libraries/Renderer/implementations/ReactFabric-dev.js b/Libraries/Renderer/implementations/ReactFabric-dev.js index f1676471c4da4e..9d98a9b2c01198 100644 --- a/Libraries/Renderer/implementations/ReactFabric-dev.js +++ b/Libraries/Renderer/implementations/ReactFabric-dev.js @@ -2462,11 +2462,9 @@ var customBubblingEventTypes = var customDirectEventTypes = ReactNativePrivateInterface.ReactNativeViewConfigRegistry .customDirectEventTypes; -var eventTypes$1 = - ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes; var ReactNativeBridgeEventPlugin = { - eventTypes: eventTypes$1, + eventTypes: {}, /** * @see {EventPluginHub.extractEvents} diff --git a/Libraries/Renderer/implementations/ReactFabric-prod.fb.js b/Libraries/Renderer/implementations/ReactFabric-prod.fb.js index 414151d1168e47..311927f216750e 100644 --- a/Libraries/Renderer/implementations/ReactFabric-prod.fb.js +++ b/Libraries/Renderer/implementations/ReactFabric-prod.fb.js @@ -946,10 +946,15 @@ var eventTypes = { .customBubblingEventTypes, customDirectEventTypes = ReactNativePrivateInterface.ReactNativeViewConfigRegistry - .customDirectEventTypes, - ReactNativeBridgeEventPlugin = { - eventTypes: - ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes, + .customDirectEventTypes; +injection.injectEventPluginOrder([ + "ResponderEventPlugin", + "ReactNativeBridgeEventPlugin" +]); +injection.injectEventPluginsByName({ + ResponderEventPlugin: ResponderEventPlugin, + ReactNativeBridgeEventPlugin: { + eventTypes: {}, extractEvents: function( topLevelType, targetInst, @@ -976,14 +981,7 @@ var eventTypes = { else return null; return topLevelType; } - }; -injection.injectEventPluginOrder([ - "ResponderEventPlugin", - "ReactNativeBridgeEventPlugin" -]); -injection.injectEventPluginsByName({ - ResponderEventPlugin: ResponderEventPlugin, - ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin + } }); function getInstanceFromInstance(instanceHandle) { return instanceHandle; diff --git a/Libraries/Renderer/implementations/ReactFabric-prod.js b/Libraries/Renderer/implementations/ReactFabric-prod.js index 50abb2ccc511cd..a3f53b2478f817 100644 --- a/Libraries/Renderer/implementations/ReactFabric-prod.js +++ b/Libraries/Renderer/implementations/ReactFabric-prod.js @@ -947,10 +947,15 @@ var eventTypes = { .customBubblingEventTypes, customDirectEventTypes = ReactNativePrivateInterface.ReactNativeViewConfigRegistry - .customDirectEventTypes, - ReactNativeBridgeEventPlugin = { - eventTypes: - ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes, + .customDirectEventTypes; +injection.injectEventPluginOrder([ + "ResponderEventPlugin", + "ReactNativeBridgeEventPlugin" +]); +injection.injectEventPluginsByName({ + ResponderEventPlugin: ResponderEventPlugin, + ReactNativeBridgeEventPlugin: { + eventTypes: {}, extractEvents: function( topLevelType, targetInst, @@ -977,14 +982,7 @@ var eventTypes = { else return null; return topLevelType; } - }; -injection.injectEventPluginOrder([ - "ResponderEventPlugin", - "ReactNativeBridgeEventPlugin" -]); -injection.injectEventPluginsByName({ - ResponderEventPlugin: ResponderEventPlugin, - ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin + } }); function getInstanceFromInstance(instanceHandle) { return instanceHandle; diff --git a/Libraries/Renderer/implementations/ReactFabric-profiling.fb.js b/Libraries/Renderer/implementations/ReactFabric-profiling.fb.js index 722fac68035257..86dc0c56155220 100644 --- a/Libraries/Renderer/implementations/ReactFabric-profiling.fb.js +++ b/Libraries/Renderer/implementations/ReactFabric-profiling.fb.js @@ -947,10 +947,15 @@ var eventTypes = { .customBubblingEventTypes, customDirectEventTypes = ReactNativePrivateInterface.ReactNativeViewConfigRegistry - .customDirectEventTypes, - ReactNativeBridgeEventPlugin = { - eventTypes: - ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes, + .customDirectEventTypes; +injection.injectEventPluginOrder([ + "ResponderEventPlugin", + "ReactNativeBridgeEventPlugin" +]); +injection.injectEventPluginsByName({ + ResponderEventPlugin: ResponderEventPlugin, + ReactNativeBridgeEventPlugin: { + eventTypes: {}, extractEvents: function( topLevelType, targetInst, @@ -977,14 +982,7 @@ var eventTypes = { else return null; return topLevelType; } - }; -injection.injectEventPluginOrder([ - "ResponderEventPlugin", - "ReactNativeBridgeEventPlugin" -]); -injection.injectEventPluginsByName({ - ResponderEventPlugin: ResponderEventPlugin, - ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin + } }); function getInstanceFromInstance(instanceHandle) { return instanceHandle; diff --git a/Libraries/Renderer/implementations/ReactFabric-profiling.js b/Libraries/Renderer/implementations/ReactFabric-profiling.js index 9cd8fe74bcf731..5f93b0a2a343a9 100644 --- a/Libraries/Renderer/implementations/ReactFabric-profiling.js +++ b/Libraries/Renderer/implementations/ReactFabric-profiling.js @@ -948,10 +948,15 @@ var eventTypes = { .customBubblingEventTypes, customDirectEventTypes = ReactNativePrivateInterface.ReactNativeViewConfigRegistry - .customDirectEventTypes, - ReactNativeBridgeEventPlugin = { - eventTypes: - ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes, + .customDirectEventTypes; +injection.injectEventPluginOrder([ + "ResponderEventPlugin", + "ReactNativeBridgeEventPlugin" +]); +injection.injectEventPluginsByName({ + ResponderEventPlugin: ResponderEventPlugin, + ReactNativeBridgeEventPlugin: { + eventTypes: {}, extractEvents: function( topLevelType, targetInst, @@ -978,14 +983,7 @@ var eventTypes = { else return null; return topLevelType; } - }; -injection.injectEventPluginOrder([ - "ResponderEventPlugin", - "ReactNativeBridgeEventPlugin" -]); -injection.injectEventPluginsByName({ - ResponderEventPlugin: ResponderEventPlugin, - ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin + } }); function getInstanceFromInstance(instanceHandle) { return instanceHandle; diff --git a/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js b/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js index d6da48c340b9b9..dbc36332f0bbe5 100644 --- a/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js +++ b/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js @@ -2461,11 +2461,9 @@ var customBubblingEventTypes = var customDirectEventTypes = ReactNativePrivateInterface.ReactNativeViewConfigRegistry .customDirectEventTypes; -var eventTypes$1 = - ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes; var ReactNativeBridgeEventPlugin = { - eventTypes: eventTypes$1, + eventTypes: {}, /** * @see {EventPluginHub.extractEvents} diff --git a/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js b/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js index 1566edf036983a..fa0c313a207946 100644 --- a/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js +++ b/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js @@ -2462,11 +2462,9 @@ var customBubblingEventTypes = var customDirectEventTypes = ReactNativePrivateInterface.ReactNativeViewConfigRegistry .customDirectEventTypes; -var eventTypes$1 = - ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes; var ReactNativeBridgeEventPlugin = { - eventTypes: eventTypes$1, + eventTypes: {}, /** * @see {EventPluginHub.extractEvents} diff --git a/Libraries/Renderer/implementations/ReactNativeRenderer-prod.fb.js b/Libraries/Renderer/implementations/ReactNativeRenderer-prod.fb.js index a97536ba85c30c..172a8fa197f016 100644 --- a/Libraries/Renderer/implementations/ReactNativeRenderer-prod.fb.js +++ b/Libraries/Renderer/implementations/ReactNativeRenderer-prod.fb.js @@ -946,10 +946,15 @@ var eventTypes = { .customBubblingEventTypes, customDirectEventTypes = ReactNativePrivateInterface.ReactNativeViewConfigRegistry - .customDirectEventTypes, - ReactNativeBridgeEventPlugin = { - eventTypes: - ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes, + .customDirectEventTypes; +injection.injectEventPluginOrder([ + "ResponderEventPlugin", + "ReactNativeBridgeEventPlugin" +]); +injection.injectEventPluginsByName({ + ResponderEventPlugin: ResponderEventPlugin, + ReactNativeBridgeEventPlugin: { + eventTypes: {}, extractEvents: function( topLevelType, targetInst, @@ -976,14 +981,7 @@ var eventTypes = { else return null; return topLevelType; } - }; -injection.injectEventPluginOrder([ - "ResponderEventPlugin", - "ReactNativeBridgeEventPlugin" -]); -injection.injectEventPluginsByName({ - ResponderEventPlugin: ResponderEventPlugin, - ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin + } }); var instanceCache = {}, instanceProps = {}; diff --git a/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js b/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js index 4e2b964402e434..131b6b97ef8086 100644 --- a/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js +++ b/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js @@ -947,10 +947,15 @@ var eventTypes = { .customBubblingEventTypes, customDirectEventTypes = ReactNativePrivateInterface.ReactNativeViewConfigRegistry - .customDirectEventTypes, - ReactNativeBridgeEventPlugin = { - eventTypes: - ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes, + .customDirectEventTypes; +injection.injectEventPluginOrder([ + "ResponderEventPlugin", + "ReactNativeBridgeEventPlugin" +]); +injection.injectEventPluginsByName({ + ResponderEventPlugin: ResponderEventPlugin, + ReactNativeBridgeEventPlugin: { + eventTypes: {}, extractEvents: function( topLevelType, targetInst, @@ -977,14 +982,7 @@ var eventTypes = { else return null; return topLevelType; } - }; -injection.injectEventPluginOrder([ - "ResponderEventPlugin", - "ReactNativeBridgeEventPlugin" -]); -injection.injectEventPluginsByName({ - ResponderEventPlugin: ResponderEventPlugin, - ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin + } }); var instanceCache = {}, instanceProps = {}; diff --git a/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.fb.js b/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.fb.js index 656ffb77a84847..78400babb59af5 100644 --- a/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.fb.js +++ b/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.fb.js @@ -947,10 +947,15 @@ var eventTypes = { .customBubblingEventTypes, customDirectEventTypes = ReactNativePrivateInterface.ReactNativeViewConfigRegistry - .customDirectEventTypes, - ReactNativeBridgeEventPlugin = { - eventTypes: - ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes, + .customDirectEventTypes; +injection.injectEventPluginOrder([ + "ResponderEventPlugin", + "ReactNativeBridgeEventPlugin" +]); +injection.injectEventPluginsByName({ + ResponderEventPlugin: ResponderEventPlugin, + ReactNativeBridgeEventPlugin: { + eventTypes: {}, extractEvents: function( topLevelType, targetInst, @@ -977,14 +982,7 @@ var eventTypes = { else return null; return topLevelType; } - }; -injection.injectEventPluginOrder([ - "ResponderEventPlugin", - "ReactNativeBridgeEventPlugin" -]); -injection.injectEventPluginsByName({ - ResponderEventPlugin: ResponderEventPlugin, - ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin + } }); var instanceCache = {}, instanceProps = {}; diff --git a/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.js b/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.js index 0df2e6154a6b70..c75d5a1e4dccf0 100644 --- a/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.js +++ b/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.js @@ -948,10 +948,15 @@ var eventTypes = { .customBubblingEventTypes, customDirectEventTypes = ReactNativePrivateInterface.ReactNativeViewConfigRegistry - .customDirectEventTypes, - ReactNativeBridgeEventPlugin = { - eventTypes: - ReactNativePrivateInterface.ReactNativeViewConfigRegistry.eventTypes, + .customDirectEventTypes; +injection.injectEventPluginOrder([ + "ResponderEventPlugin", + "ReactNativeBridgeEventPlugin" +]); +injection.injectEventPluginsByName({ + ResponderEventPlugin: ResponderEventPlugin, + ReactNativeBridgeEventPlugin: { + eventTypes: {}, extractEvents: function( topLevelType, targetInst, @@ -978,14 +983,7 @@ var eventTypes = { else return null; return topLevelType; } - }; -injection.injectEventPluginOrder([ - "ResponderEventPlugin", - "ReactNativeBridgeEventPlugin" -]); -injection.injectEventPluginsByName({ - ResponderEventPlugin: ResponderEventPlugin, - ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin + } }); var instanceCache = {}, instanceProps = {}; diff --git a/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js b/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js index cb27a9d9668616..b39983d5e6062d 100644 --- a/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js +++ b/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js @@ -20,11 +20,9 @@ const invariant = require('invariant'); // Event configs const customBubblingEventTypes = {}; const customDirectEventTypes = {}; -const eventTypes = {}; exports.customBubblingEventTypes = customBubblingEventTypes; exports.customDirectEventTypes = customDirectEventTypes; -exports.eventTypes = eventTypes; const viewConfigCallbacks = new Map(); const viewConfigs = new Map(); @@ -49,7 +47,7 @@ function processEventTypes( if (bubblingEventTypes != null) { for (const topLevelType in bubblingEventTypes) { if (customBubblingEventTypes[topLevelType] == null) { - eventTypes[topLevelType] = customBubblingEventTypes[topLevelType] = + customBubblingEventTypes[topLevelType] = bubblingEventTypes[topLevelType]; } } @@ -58,8 +56,7 @@ function processEventTypes( if (directEventTypes != null) { for (const topLevelType in directEventTypes) { if (customDirectEventTypes[topLevelType] == null) { - eventTypes[topLevelType] = customDirectEventTypes[topLevelType] = - directEventTypes[topLevelType]; + customDirectEventTypes[topLevelType] = directEventTypes[topLevelType]; } } } From bf8d91868182955899edab3b0b91a0be53ce276d Mon Sep 17 00:00:00 2001 From: James Ide Date: Wed, 5 Jun 2019 15:57:36 -0700 Subject: [PATCH 0206/1084] Make Flow configs use path-based imports instead of Haste (#24812) Summary: **Depends on https://github.com/facebook/react-native/pull/25100** This is one of the steps unlocked by migrating RN from Haste to path-based imports. This commit sets Flow to use path-based imports by removing all of the Haste-related configuration options. Additionally, it maps `react-native` to import from within this module to match Node's module resolution behavior. It also adds `` to the image name mapper so that the mapped name doesn't rely on Haste. ## Changelog [General] [Changed] - Make Flow configs use path-based imports instead of Haste Pull Request resolved: https://github.com/facebook/react-native/pull/24812 Differential Revision: D15659189 Pulled By: cpojer fbshipit-source-id: d0efaa2884485a492dcdef8d94061129cebc2566 --- .flowconfig | 31 +++---------------------------- .flowconfig.android | 31 +++---------------------------- template/_flowconfig | 30 +++--------------------------- 3 files changed, 9 insertions(+), 83 deletions(-) diff --git a/.flowconfig b/.flowconfig index 2df42b89ca436c..0fa25e0ca34dd2 100644 --- a/.flowconfig +++ b/.flowconfig @@ -11,14 +11,6 @@ ; Ignore "BUCK" generated dirs /\.buckd/ -; Ignore unexpected extra "@providesModule" -.*/node_modules/.*/node_modules/fbjs/.* - -; Ignore duplicate module providers -; For RN Apps installed via npm, "Libraries" folder is inside -; "node_modules/react-native" but in the source repo it is in the root -.*/Libraries/react-native/React.js - ; Ignore polyfills .*/Libraries/polyfills/.* @@ -48,28 +40,11 @@ module.file_ext=.js module.file_ext=.json module.file_ext=.ios.js -module.system=haste -module.system.haste.use_name_reducers=true -# keep the following in sync with server/haste/hasteImpl.js -# get basename -module.system.haste.name_reducers='^.*/\([a-zA-Z0-9$_.-]+\.js\(\.flow\)?\)$' -> '\1' -# strip .js or .js.flow suffix -module.system.haste.name_reducers='^\(.*\)\.js\(\.flow\)?$' -> '\1' -# strip .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.whitelist=/Libraries/.* -module.system.haste.paths.whitelist=/RNTester/.* -module.system.haste.paths.whitelist=/IntegrationTests/.* -module.system.haste.paths.blacklist=/Libraries/react-native/react-native-implementation.js -module.system.haste.paths.blacklist=/Libraries/Animated/src/polyfills/.* - munge_underscores=true -module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' +module.name_mapper='^react-native$' -> '/Libraries/react-native/react-native-implementation' +module.name_mapper='^react-native/\(.*\)$' -> '/\1' +module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> '/Libraries/Image/RelativeImageStub' suppress_type=$FlowIssue suppress_type=$FlowFixMe diff --git a/.flowconfig.android b/.flowconfig.android index 1d47c484efc3ca..97f4f99ad060db 100644 --- a/.flowconfig.android +++ b/.flowconfig.android @@ -11,14 +11,6 @@ ; Ignore "BUCK" generated dirs /\.buckd/ -; Ignore unexpected extra "@providesModule" -.*/node_modules/.*/node_modules/fbjs/.* - -; Ignore duplicate module providers -; For RN Apps installed via npm, "Libraries" folder is inside -; "node_modules/react-native" but in the source repo it is in the root -.*/Libraries/react-native/React.js - ; Ignore polyfills .*/Libraries/polyfills/.* @@ -48,28 +40,11 @@ module.file_ext=.js module.file_ext=.json module.file_ext=.android.js -module.system=haste -module.system.haste.use_name_reducers=true -# keep the following in sync with server/haste/hasteImpl.js -# get basename -module.system.haste.name_reducers='^.*/\([a-zA-Z0-9$_.-]+\.js\(\.flow\)?\)$' -> '\1' -# strip .js or .js.flow suffix -module.system.haste.name_reducers='^\(.*\)\.js\(\.flow\)?$' -> '\1' -# strip .android suffix -module.system.haste.name_reducers='^\(.*\)\.android$' -> '\1' -module.system.haste.name_reducers='^\(.*\)\.ios$' -> '\1' -module.system.haste.name_reducers='^\(.*\)\.native$' -> '\1' -module.system.haste.paths.blacklist=.*/__tests__/.* -module.system.haste.paths.blacklist=.*/__mocks__/.* -module.system.haste.paths.whitelist=/Libraries/.* -module.system.haste.paths.whitelist=/RNTester/.* -module.system.haste.paths.whitelist=/IntegrationTests/.* -module.system.haste.paths.blacklist=/Libraries/react-native/react-native-implementation.js -module.system.haste.paths.blacklist=/Libraries/Animated/src/polyfills/.* - munge_underscores=true -module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' +module.name_mapper='^react-native$' -> '/Libraries/react-native/react-native-implementation' +module.name_mapper='^react-native/\(.*\)$' -> '/\1' +module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> '/Libraries/Image/RelativeImageStub' suppress_type=$FlowIssue suppress_type=$FlowFixMe diff --git a/template/_flowconfig b/template/_flowconfig index 80fa55fc38a41d..49091799f945e8 100644 --- a/template/_flowconfig +++ b/template/_flowconfig @@ -5,14 +5,6 @@ ; Ignore "BUCK" generated dirs /\.buckd/ -; Ignore unexpected extra "@providesModule" -.*/node_modules/.*/node_modules/fbjs/.* - -; Ignore duplicate module providers -; For RN Apps installed via npm, "Libraries" folder is inside -; "node_modules/react-native" but in the source repo it is in the root -node_modules/react-native/Libraries/react-native/React.js - ; Ignore polyfills node_modules/react-native/Libraries/polyfills/.* @@ -42,27 +34,11 @@ module.file_ext=.js module.file_ext=.json module.file_ext=.ios.js -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.whitelist=/node_modules/react-native/Libraries/.* -module.system.haste.paths.whitelist=/node_modules/react-native/RNTester/.* -module.system.haste.paths.whitelist=/node_modules/react-native/IntegrationTests/.* -module.system.haste.paths.blacklist=/node_modules/react-native/Libraries/react-native/react-native-implementation.js -module.system.haste.paths.blacklist=/node_modules/react-native/Libraries/Animated/src/polyfills/.* - munge_underscores=true -module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' +module.name_mapper='^react-native$' -> '/Libraries/react-native/react-native-implementation' +module.name_mapper='^react-native/\(.*\)$' -> '/\1' +module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> '/Libraries/Image/RelativeImageStub' suppress_type=$FlowIssue suppress_type=$FlowFixMe From d45818fe47c53a670db933cf805910e227aa79c9 Mon Sep 17 00:00:00 2001 From: Krzysztof Borowy Date: Wed, 5 Jun 2019 15:59:46 -0700 Subject: [PATCH 0207/1084] Feature to listen on window focus events (#25039) Summary: Addressed issue: https://github.com/facebook/react-native/issues/24149 On Android, activity's lifecycle events are not triggered when the user pulls down the Status Bar (opening Notification Drawer). In order to know that, you need to override [onWindowFocusChanged method](https://developer.android.com/reference/android/app/Activity.html#onWindowFocusChanged(boolean)). ## Changelog [Android] [Added] - Adds a new listener for `onWindowFocusChanged` [JavaScript] [Added] - New event, `focusChanged`, to listen on focus gain/loss Pull Request resolved: https://github.com/facebook/react-native/pull/25039 Differential Revision: D15644954 Pulled By: cpojer fbshipit-source-id: 823acffc4287bec4bf56e9f5ffcac65c01cf13d3 --- Libraries/AppState/AppState.js | 58 +++++++++++++------ .../com/facebook/react/ReactActivity.java | 6 ++ .../facebook/react/ReactActivityDelegate.java | 6 ++ .../facebook/react/ReactInstanceManager.java | 9 +++ .../facebook/react/bridge/ReactContext.java | 21 +++++++ .../bridge/WindowFocusChangeListener.java | 15 +++++ .../modules/appstate/AppStateModule.java | 10 +++- 7 files changed, 106 insertions(+), 19 deletions(-) create mode 100644 ReactAndroid/src/main/java/com/facebook/react/bridge/WindowFocusChangeListener.java diff --git a/Libraries/AppState/AppState.js b/Libraries/AppState/AppState.js index 24b7da77d01481..e848978a106894 100644 --- a/Libraries/AppState/AppState.js +++ b/Libraries/AppState/AppState.js @@ -25,6 +25,7 @@ const invariant = require('invariant'); */ class AppState extends NativeEventEmitter { _eventHandlers: Object; + _supportedEvents = ['change', 'memoryWarning', 'blur', 'focus']; currentState: ?string; isAvailable: boolean; @@ -32,10 +33,10 @@ class AppState extends NativeEventEmitter { super(NativeAppState); this.isAvailable = true; - this._eventHandlers = { - change: new Map(), - memoryWarning: new Map(), - }; + this._eventHandlers = this._supportedEvents.reduce((handlers, key) => { + handlers[key] = new Map(); + return handlers; + }, {}); this.currentState = NativeAppState.getConstants().initialAppState; @@ -75,22 +76,43 @@ class AppState extends NativeEventEmitter { */ addEventListener(type: string, handler: Function) { invariant( - ['change', 'memoryWarning'].indexOf(type) !== -1, + this._supportedEvents.indexOf(type) !== -1, 'Trying to subscribe to unknown event: "%s"', type, ); - if (type === 'change') { - this._eventHandlers[type].set( - handler, - this.addListener('appStateDidChange', appStateData => { - handler(appStateData.app_state); - }), - ); - } else if (type === 'memoryWarning') { - this._eventHandlers[type].set( - handler, - this.addListener('memoryWarning', handler), - ); + + switch (type) { + case 'change': { + this._eventHandlers[type].set( + handler, + this.addListener('appStateDidChange', appStateData => { + handler(appStateData.app_state); + }), + ); + break; + } + case 'memoryWarning': { + this._eventHandlers[type].set( + handler, + this.addListener('memoryWarning', handler), + ); + break; + } + + case 'blur': + case 'focus': { + this._eventHandlers[type].set( + handler, + this.addListener('appStateFocusChange', hasFocus => { + if (type === 'blur' && !hasFocus) { + handler(); + } + if (type === 'focus' && hasFocus) { + handler(); + } + }), + ); + } } } @@ -101,7 +123,7 @@ class AppState extends NativeEventEmitter { */ removeEventListener(type: string, handler: Function) { invariant( - ['change', 'memoryWarning'].indexOf(type) !== -1, + this._supportedEvents.indexOf(type) !== -1, 'Trying to remove listener for unknown event: "%s"', type, ); diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java b/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java index 080fb54e083df4..1dd6d18073c2e8 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java @@ -125,6 +125,12 @@ public void onRequestPermissionsResult( mDelegate.onRequestPermissionsResult(requestCode, permissions, grantResults); } + @Override + public void onWindowFocusChanged(boolean hasFocus) { + super.onWindowFocusChanged(hasFocus); + mDelegate.onWindowFocusChanged(hasFocus); + } + protected final ReactNativeHost getReactNativeHost() { return mDelegate.getReactNativeHost(); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactActivityDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/ReactActivityDelegate.java index 26a95665654d32..c6534217a084e3 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactActivityDelegate.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactActivityDelegate.java @@ -182,6 +182,12 @@ public boolean onNewIntent(Intent intent) { return false; } + public void onWindowFocusChanged(boolean hasFocus) { + if (getReactNativeHost().hasInstance()) { + getReactNativeHost().getReactInstanceManager().onWindowFocusChange(hasFocus); + } + } + @TargetApi(Build.VERSION_CODES.M) public void requestPermissions( String[] permissions, diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java index 0926cf7efb37ce..1247027e29ad1e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java @@ -703,6 +703,15 @@ public void onActivityResult(Activity activity, int requestCode, int resultCode, } } + @ThreadConfined(UI) + public void onWindowFocusChange(boolean hasFocus) { + UiThreadUtil.assertOnUiThread(); + ReactContext currentContext = getCurrentReactContext(); + if (currentContext != null) { + currentContext.onWindowFocusChange(hasFocus); + } + } + @ThreadConfined(UI) public void showDevOptionsDialog() { UiThreadUtil.assertOnUiThread(); diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java index 532c226324a9d0..c2e74c0b89726d 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java @@ -36,6 +36,8 @@ public class ReactContext extends ContextWrapper { new CopyOnWriteArraySet<>(); private final CopyOnWriteArraySet mActivityEventListeners = new CopyOnWriteArraySet<>(); + private final CopyOnWriteArraySet mWindowFocusEventListeners = + new CopyOnWriteArraySet<>(); private LifecycleState mLifecycleState = LifecycleState.BEFORE_CREATE; @@ -196,6 +198,14 @@ public void removeActivityEventListener(ActivityEventListener listener) { mActivityEventListeners.remove(listener); } + public void addWindowFocusChangeListener(WindowFocusChangeListener listener) { + mWindowFocusEventListeners.add(listener); + } + + public void removeWindowFocusChangeListener(WindowFocusChangeListener listener) { + mWindowFocusEventListeners.remove(listener); + } + /** * Should be called by the hosting Fragment in {@link Fragment#onResume} */ @@ -281,6 +291,17 @@ public void onActivityResult(Activity activity, int requestCode, int resultCode, } } + public void onWindowFocusChange(boolean hasFocus) { + UiThreadUtil.assertOnUiThread(); + for (WindowFocusChangeListener listener : mWindowFocusEventListeners) { + try { + listener.onWindowFocusChange(hasFocus); + } catch (RuntimeException e) { + handleException(e); + } + } + } + public void assertOnUiQueueThread() { Assertions.assertNotNull(mUiMessageQueueThread).assertIsOnThread(); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/WindowFocusChangeListener.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/WindowFocusChangeListener.java new file mode 100644 index 00000000000000..d74b1089f9a0c1 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/WindowFocusChangeListener.java @@ -0,0 +1,15 @@ +// Copyright (c) Facebook, Inc. and its affiliates. + +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + + +package com.facebook.react.bridge; + + +/* + * Listener for receiving window focus events. + */ +public interface WindowFocusChangeListener { + void onWindowFocusChange(boolean hasFocus); +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.java index ee158be0f40fcb..6dc073cd275d54 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.java @@ -13,6 +13,7 @@ import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.WindowFocusChangeListener; import com.facebook.react.bridge.WritableMap; import com.facebook.react.common.LifecycleState; import com.facebook.react.module.annotations.ReactModule; @@ -23,7 +24,7 @@ @ReactModule(name = AppStateModule.NAME) public class AppStateModule extends ReactContextBaseJavaModule - implements LifecycleEventListener { + implements LifecycleEventListener, WindowFocusChangeListener { protected static final String NAME = "AppState"; @@ -37,6 +38,7 @@ public class AppStateModule extends ReactContextBaseJavaModule public AppStateModule(ReactApplicationContext reactContext) { super(reactContext); reactContext.addLifecycleEventListener(this); + reactContext.addWindowFocusChangeListener(this); mAppState = (reactContext.getLifecycleState() == LifecycleState.RESUMED ? APP_STATE_ACTIVE : APP_STATE_BACKGROUND); } @@ -76,6 +78,12 @@ public void onHostDestroy() { // catalyst instance is going to be immediately dropped, and all JS calls with it. } + @Override + public void onWindowFocusChange(boolean hasFocus) { + getReactApplicationContext().getJSModule(RCTDeviceEventEmitter.class) + .emit("appStateFocusChange", hasFocus); + } + private WritableMap createAppStateEventMap() { WritableMap appState = Arguments.createMap(); appState.putString("app_state", mAppState); From 8a014cdfb3f33a7b49a68205e72c609c9ff3bb62 Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Wed, 5 Jun 2019 17:30:04 -0700 Subject: [PATCH 0208/1084] TurboModules: Improve Error Message Summary: More verbose but descriptive error message when `TurboModule.getEnforcing` fails to find a native module. Reviewed By: cpojer, gaearon Differential Revision: D15619293 fbshipit-source-id: 0e8af4986d6ce9002966bb062766218ce9f89a13 --- Libraries/TurboModule/TurboModuleRegistry.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Libraries/TurboModule/TurboModuleRegistry.js b/Libraries/TurboModule/TurboModuleRegistry.js index fcec0d8ada5eda..d0e0cd0176c33a 100644 --- a/Libraries/TurboModule/TurboModuleRegistry.js +++ b/Libraries/TurboModule/TurboModuleRegistry.js @@ -33,6 +33,10 @@ export function get(name: string): ?T { export function getEnforcing(name: string): T { const module = get(name); - invariant(module != null, `${name} is not available in this app.`); + invariant( + module != null, + `TurboModuleRegistry.getEnforcing(...): '${name}' could not be found. ` + + 'Verify that a module by this name is registered in the native binary.', + ); return module; } From 664646055a3eee2a6ad031294eac4b2ec18a2cf4 Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Wed, 5 Jun 2019 18:55:34 -0700 Subject: [PATCH 0209/1084] RN: Restore Debug Bridge Description (iOS) Summary: Restores the bridge description in the debug menu on iOS. Reviewed By: fkgozali Differential Revision: D15680775 fbshipit-source-id: c17ad44f2287e03bb2039b4aa4b1311e7ec9106b --- React/CxxBridge/RCTCxxBridge.mm | 4 +--- React/DevSupport/RCTDevMenu.m | 9 +++++++-- ReactCommon/jsiexecutor/jsireact/JSIExecutor.cpp | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/React/CxxBridge/RCTCxxBridge.mm b/React/CxxBridge/RCTCxxBridge.mm index 5a7188b5030761..93eac488eab00c 100644 --- a/React/CxxBridge/RCTCxxBridge.mm +++ b/React/CxxBridge/RCTCxxBridge.mm @@ -80,9 +80,7 @@ typedef NS_ENUM(NSUInteger, RCTBridgeFields) { std::shared_ptr delegate, std::shared_ptr jsQueue) override { auto ret = factory_->createJSExecutor(delegate, jsQueue); - bridge_.bridgeDescription = - [NSString stringWithFormat:@"RCTCxxBridge %s", - ret->getDescription().c_str()]; + bridge_.bridgeDescription = @(ret->getDescription().c_str()); return ret; } diff --git a/React/DevSupport/RCTDevMenu.m b/React/DevSupport/RCTDevMenu.m index a57c4222cfdde0..80ad94cbf387b6 100644 --- a/React/DevSupport/RCTDevMenu.m +++ b/React/DevSupport/RCTDevMenu.m @@ -354,10 +354,15 @@ - (void)setDefaultJSBundle { return; } + NSString *bridgeDescription = _bridge.bridgeDescription; + NSString *description = bridgeDescription.length > 0 + ? [NSString stringWithFormat:@"Running %@", bridgeDescription] + : nil; + // On larger devices we don't have an anchor point for the action sheet UIAlertControllerStyle style = [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone ? UIAlertControllerStyleActionSheet : UIAlertControllerStyleAlert; - _actionSheet = [UIAlertController alertControllerWithTitle:nil - message:nil + _actionSheet = [UIAlertController alertControllerWithTitle:@"React Native Debug Menu" + message:description preferredStyle:style]; NSArray *items = [self _menuItemsToPresent]; diff --git a/ReactCommon/jsiexecutor/jsireact/JSIExecutor.cpp b/ReactCommon/jsiexecutor/jsireact/JSIExecutor.cpp index e7ec74077fda82..351d26fe06714b 100644 --- a/ReactCommon/jsiexecutor/jsireact/JSIExecutor.cpp +++ b/ReactCommon/jsiexecutor/jsireact/JSIExecutor.cpp @@ -241,7 +241,7 @@ void JSIExecutor::setGlobalVariable( } std::string JSIExecutor::getDescription() { - return "JSI " + runtime_->description(); + return "JSI (" + runtime_->description() + ")"; } void *JSIExecutor::getJavaScriptContext() { From 764fd955db7150313c51dd3303e30ed8e7f14772 Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Wed, 5 Jun 2019 18:58:38 -0700 Subject: [PATCH 0210/1084] Setup TurboModuleManager inside Fb4a Summary: This diff introduces `TurboModuleManagerDelegate` in Fb4a and Workplace. `Fb4aTurboModuleManagerDelegate` is responsible for creating TurboModules for Fb4a. `WorkTurboModuleManagerDelegate` is responsible for creating TurboModules for Workplace. Reviewed By: mdvacca Differential Revision: D15268563 fbshipit-source-id: c254c31856c59b3551bfe54b25c715c848646c5a --- ...eactPackageTurboModuleManagerDelegate.java | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/ReactPackageTurboModuleManagerDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/ReactPackageTurboModuleManagerDelegate.java index 839ada2cf080bc..4f5ba651247be2 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/ReactPackageTurboModuleManagerDelegate.java +++ b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/ReactPackageTurboModuleManagerDelegate.java @@ -2,6 +2,7 @@ package com.facebook.react.turbomodule.core; +import com.facebook.infer.annotation.Assertions; import com.facebook.react.ReactPackage; import com.facebook.react.TurboReactPackage; import com.facebook.react.bridge.CxxModuleWrapper; @@ -19,7 +20,7 @@ public abstract class ReactPackageTurboModuleManagerDelegate extends TurboModule private final Map mModules = new HashMap<>(); private final ReactApplicationContext mReactApplicationContext; - public ReactPackageTurboModuleManagerDelegate(ReactApplicationContext reactApplicationContext, List packages) { + protected ReactPackageTurboModuleManagerDelegate(ReactApplicationContext reactApplicationContext, List packages) { super(); mReactApplicationContext = reactApplicationContext; for (ReactPackage reactPackage : packages) { @@ -101,4 +102,27 @@ private TurboModule resolveModule(String moduleName) { return mModules.get(moduleName); } + + public static abstract class Builder { + private @Nullable List mPackages; + private @Nullable ReactApplicationContext mContext; + + public Builder setPackages(List packages) { + mPackages = new ArrayList<>(packages); + return this; + } + + public Builder setReactApplicationContext(ReactApplicationContext context) { + mContext = context; + return this; + } + + protected abstract ReactPackageTurboModuleManagerDelegate build(ReactApplicationContext context, List packages); + + public ReactPackageTurboModuleManagerDelegate build() { + Assertions.assertNotNull(mContext, "The ReactApplicationContext must be provided to create ReactPackageTurboModuleManagerDelegate"); + Assertions.assertNotNull(mPackages, "A set of ReactPackages must be provided to create ReactPackageTurboModuleManagerDelegate"); + return build(mContext, mPackages); + } + } } From 7b9c456e7d9299e908aa1bdeff0c3f8ab5bd5f01 Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Wed, 5 Jun 2019 18:58:38 -0700 Subject: [PATCH 0211/1084] Enable TurboModules for FB4A Summary: ## Summary If a NativeModule Spec interface extends `TurboModule`, we want to make the auto-generated Java base class for that NativeModule to implement `com.facebook.react.turbomodule.core.interfaces.TurboModule`. This makes it so that our Android code recognizes that Java module as a TurboModule. When this diff lands, all internal FB4A NativeModules will start going through the TurboModule system. Reviewed By: fkgozali Differential Revision: D15327683 fbshipit-source-id: e295dafdab7a0e130820318aeaf0cafa41487689 --- .../main/java/com/facebook/react/bridge/BaseJavaModule.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java index 04ca7a91c74969..da1d60f94f0897 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java @@ -67,4 +67,9 @@ public void onCatalystInstanceDestroy() { public boolean hasConstants() { return false; } + + // Cleanup Logic for TurboModuels + public void invalidate() { + // Do nothing + } } From 9fdc8daf6152382e787b5da175722435c28bf8b9 Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Wed, 5 Jun 2019 18:58:38 -0700 Subject: [PATCH 0212/1084] Fix race in TurboModuleManager initialization Summary: ## Description To initialize `TurboModuleManager`, we first need to wait until `ReactContext` is initialized. Then, we get the `TurboModuleManager` instance and assign it as the `TurboModuleRegistry` of `CatalystInstanceImpl`. This allows `CatalystInstanceImpl` to return TurboModules from its `getNativeModule` method. In `FbReactFragment`, we also wait until the `ReactContext` is initialized before then eagerly initialize a bunch of NativeModules. All this waiting is done by adding instances of `ReactInstanceEventListener` to `ReactInstanceManager`'s `mReactInstanceEventListeners` synchronized Set. When the `ReactContext` is finally initialized, we loop over this set and invoke all the listeners. ## Problem We want to initialize `TurboModuleManager` and set it as the `TurboModuleRegistry` of `CatalystInstanceImpl` before we start eagerly initializing our NativeModules. Why? Because otherwise TurboModules that need to be eagerly initialized won't be. The fact that we're using a Set to manage the `ReactInstanceEventListener`s means that our listeners can be invoked in any order. This is bad because we can start to eagerly initialize NativeModules before we've had the chance to assign `TurboModuleManager` as the `TurboModuleRegistry` of `CatalystInstanceImpl`. In development, this race was leading to the following crash: ``` 06-05 11:11:02.020 10461 10617 E AndroidRuntime: FATAL EXCEPTION: CombinedTP8 06-05 11:11:02.020 10461 10617 E AndroidRuntime: Process: com.facebook.wakizashi, PID: 10461 06-05 11:11:02.020 10461 10617 E AndroidRuntime: java.lang.AssertionError: Could not find module with name PrimedStorage 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at com.facebook.infer.annotation.Assertions.assertNotNull(Assertions.java:35) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at com.facebook.react.bridge.NativeModuleRegistry.getModule(NativeModuleRegistry.java:147) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at com.facebook.react.bridge.CatalystInstanceImpl.getNativeModule(CatalystInstanceImpl.java:444) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at com.facebook.fbreact.fragment.FbReactFragment$4$1.run(FbReactFragment.java:418) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:457) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at com.facebook.common.executors.WrappingExecutorService$1.run(WrappingExecutorService.java:82) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at com.facebook.common.combinedthreadpool.queue.CombinedSimpleTask.run(CombinedSimpleTask.java:81) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at com.facebook.common.combinedthreadpool.queue.CombinedLifetimeThreadFactory$1.run(CombinedLifetimeThreadFactory.java:40) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at com.facebook.common.executors.NamedThreadFactory$1.run(NamedThreadFactory.java:53) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at java.lang.Thread.run(Thread.java:764) ``` ## Diagnosing the crash It looks like `NativeModuleRegistry.getModule` was throwing an error because `PrimedStorage` was null. `PrimedStorage` was turned into a TurboModule, so of course it wouldn't be in the `NativeModuleRegistry`. It should be in the `TurboModuleRegistry`. So, I placed an assertion in `CatalystInstanceImpl`: ``` Override public NativeModule getNativeModule(String moduleName) { Assertions.assertNotNull(mTurboModuleRegistry, "TurboModuleRegsitry is not null"); if (mTurboModuleRegistry != null) { TurboModule turboModule = mTurboModuleRegistry.getModule(moduleName); if (turboModule != null) { return (NativeModule)turboModule; } } return mNativeModuleRegistry.getModule(moduleName); } ``` Sure enough, this assertion started tripping, which meant that `mTurboModuleRegistry` was null. From this information, I hypothesized that we started to eagerly initialize our NativeModules before `TurboModuleManager` was initialized. To verify this hypothesis, I added logging statements in each `ReactInstanceEventListener`: P65477469. `eagerInitializeReactNativeComponents (START)` documents when we start to eagerly intialize our NativeModules. `getReactInstanceManager (START)` documents when we start to initialize `TurboModuleManager` inside `FbReactInstanceHolder.getReactInstanceManager` method. Sure enough, when the program finally crashed, I saw in our logs that we started eagerly initializing our NativeModules before we initialized the TurboModuleManager: ``` 06-05 11:11:01.951 10461 10617 V Ramanpreet: eagerInitializeReactNativeComponents (START): 1559758261951 06-05 11:11:01.956 10461 10461 V Ramanpreet: getReactInstanceManager (START): 1559758261956 06-05 11:11:01.958 10461 10461 D SoLoader: About to load: libturbomodulejsijni.so 06-05 11:11:01.960 10461 10461 D SoLoader: libturbomodulejsijni.so not found on /data/data/com.facebook.wakizashi/lib-zstd 06-05 11:11:01.960 10461 10461 D SoLoader: libturbomodulejsijni.so not found on /data/data/com.facebook.wakizashi/lib-xzs 06-05 11:11:01.960 10461 10461 D SoLoader: libturbomodulejsijni.so not found on /data/data/com.facebook.wakizashi/lib-assets 06-05 11:11:01.961 10461 10461 D SoLoader: libturbomodulejsijni.so found on /data/data/com.facebook.wakizashi/lib-main 06-05 11:11:01.965 10461 10461 D SoLoader: Loading lib dependencies: [libfb.so, libfbjni.so, libglog.so, libdouble-conversion.so, libxplat_jsi_jsiAndroid.so, libxplat_jsi_JSIDynamicAndroid.so, libfbsystrace.so, libmemalign16.so, libgnustl_shared.so, libm.so, libc.so] 06-05 11:11:01.999 10461 10769 D SoLoader: init exiting 06-05 11:11:01.999 10461 10461 D SoLoader: Loaded: libturbomodulejsijni.so 06-05 11:11:01.999 10461 10461 D SoLoader: About to load: libfb4aturbomodulemanagerdelegate.so 06-05 11:11:01.999 10461 10769 W fb4a.ImagePipelineFactory: ImagePipelineFactory has already been initialized! `ImagePipelineFactory.initialize(...)` should only be called once to avoid unexpected behavior. 06-05 11:11:02.002 10461 10461 D SoLoader: libfb4aturbomodulemanagerdelegate.so not found on /data/data/com.facebook.wakizashi/lib-zstd 06-05 11:11:02.002 10461 10461 D SoLoader: libfb4aturbomodulemanagerdelegate.so not found on /data/data/com.facebook.wakizashi/lib-xzs 06-05 11:11:02.002 10461 10461 D SoLoader: libfb4aturbomodulemanagerdelegate.so not found on /data/data/com.facebook.wakizashi/lib-assets 06-05 11:11:02.004 10461 10461 D SoLoader: libfb4aturbomodulemanagerdelegate.so found on /data/data/com.facebook.wakizashi/lib-main 06-05 11:11:02.007 10461 10461 D SoLoader: Loading lib dependencies: [libturbomodulejsijni.so, libfb.so, libfbjni.so, libxplat_jsi_jsiAndroid.so, libxplat_jsi_JSIDynamicAndroid.so, libreactnativejni.so, libmemalign16.so, libgnustl_shared.so, libc.so] 06-05 11:11:02.020 10461 10617 E AndroidRuntime: FATAL EXCEPTION: CombinedTP8 06-05 11:11:02.020 10461 10617 E AndroidRuntime: Process: com.facebook.wakizashi, PID: 10461 06-05 11:11:02.020 10461 10617 E AndroidRuntime: java.lang.AssertionError: Could not find module with name PrimedStorage 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at com.facebook.infer.annotation.Assertions.assertNotNull(Assertions.java:35) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at com.facebook.react.bridge.NativeModuleRegistry.getModule(NativeModuleRegistry.java:147) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at com.facebook.react.bridge.CatalystInstanceImpl.getNativeModule(CatalystInstanceImpl.java:444) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at com.facebook.fbreact.fragment.FbReactFragment$4$1.run(FbReactFragment.java:418) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:457) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at com.facebook.common.executors.WrappingExecutorService$1.run(WrappingExecutorService.java:82) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at com.facebook.common.combinedthreadpool.queue.CombinedSimpleTask.run(CombinedSimpleTask.java:81) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at com.facebook.common.combinedthreadpool.queue.CombinedLifetimeThreadFactory$1.run(CombinedLifetimeThreadFactory.java:40) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at com.facebook.common.executors.NamedThreadFactory$1.run(NamedThreadFactory.java:53) 06-05 11:11:02.020 10461 10617 E AndroidRuntime: at java.lang.Thread.run(Thread.java:764) 06-05 11:11:02.038 1647 1667 I WifiService: requestActivityInfo uid=1000 06-05 11:11:02.038 1647 1667 I WifiService: reportActivityInfo uid=1000 06-05 11:11:02.038 1647 1667 I WifiService: getSupportedFeatures uid=1000 06-05 11:11:02.044 1647 1667 E BluetoothAdapter: Bluetooth binder is null 06-05 11:11:02.049 1647 1667 E KernelCpuSpeedReader: Failed to read cpu-freq: /sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state (No such file or directory) 06-05 11:11:02.050 1647 1667 E BatteryExternalStatsWorker: modem info is invalid: ModemActivityInfo{ mTimestamp=0 mSleepTimeMs=0 mIdleTimeMs=0 mTxTimeMs[]=[0, 0, 0, 0, 0] mRxTimeMs=0 mEnergyUsed=0} 06-05 11:11:02.057 2147 10435 W ctxmgr : [AclManager]No 2 for (accnt=account#-517948760#, com.google.android.gms(10013):IndoorOutdoorProducer, vrsn=13280000, 0, 3pPkg = null , 3pMdlId = null , pid = 2147). Was: 3 for 57, account#-517948760# 06-05 11:11:02.077 10461 10461 D SoLoader: Loaded: libfb4aturbomodulemanagerdelegate.so 06-05 11:11:02.079 10461 10461 V Ramanpreet: getReactInstanceManager (END): 1559758262079 ``` Reviewed By: mdvacca Differential Revision: D15676746 fbshipit-source-id: a7ac02d868abf31c5d664b10f70b6db247f388f5 --- .../src/main/java/com/facebook/react/ReactInstanceManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java index 1247027e29ad1e..f7f46ee13e88e1 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java @@ -158,7 +158,7 @@ public interface ReactInstanceEventListener { private @Nullable @ThreadConfined(UI) DefaultHardwareBackBtnHandler mDefaultBackButtonImpl; private @Nullable Activity mCurrentActivity; private final Collection mReactInstanceEventListeners = - Collections.synchronizedSet(new HashSet()); + Collections.synchronizedList(new ArrayList()); // Identifies whether the instance manager is or soon will be initialized (on background thread) private volatile boolean mHasStartedCreatingInitialContext = false; // Identifies whether the instance manager destroy function is in process, From 7c2433c6d938c7a8fdfb55709473242d03272b9c Mon Sep 17 00:00:00 2001 From: Emily Janzer Date: Wed, 5 Jun 2019 21:32:15 -0700 Subject: [PATCH 0213/1084] DeviceInfo TurboModule Summary: Making DeviceInfo support TurboModule on Android; implementing the interface in the Java class and setting up codegen for the spec. Reviewed By: mdvacca Differential Revision: D15616194 fbshipit-source-id: 6326f23d95295e570df6f6c88289102ac733def7 --- ReactAndroid/src/main/java/com/facebook/react/BUCK | 1 + .../main/java/com/facebook/react/modules/deviceinfo/BUCK | 1 + .../facebook/react/modules/deviceinfo/DeviceInfoModule.java | 6 +++++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/BUCK b/ReactAndroid/src/main/java/com/facebook/react/BUCK index 2f9fa2dd606083..f5f371753deb76 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/BUCK @@ -44,6 +44,7 @@ rn_android_library( react_native_target("java/com/facebook/react/module/annotations:annotations"), react_native_target("java/com/facebook/react/views/imagehelper:imagehelper"), react_native_target("java/com/facebook/react/config:config"), + react_native_target("java/com/facebook/react/turbomodule/core/interfaces:interfaces"), ], exported_deps = [ react_native_target("java/com/facebook/react/packagerconnection:packagerconnection"), diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/deviceinfo/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/deviceinfo/BUCK index 76ee3429914464..e44249ce319b86 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/deviceinfo/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/deviceinfo/BUCK @@ -12,6 +12,7 @@ rn_android_library( react_native_target("java/com/facebook/react/common:common"), react_native_target("java/com/facebook/react/module/annotations:annotations"), react_native_target("java/com/facebook/react/modules/core:core"), + react_native_target("java/com/facebook/react/turbomodule/core/interfaces:interfaces"), react_native_target("java/com/facebook/react/uimanager:uimanager"), ], ) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/deviceinfo/DeviceInfoModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/deviceinfo/DeviceInfoModule.java index eb792e8c16e81c..97629bf9048034 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/deviceinfo/DeviceInfoModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/deviceinfo/DeviceInfoModule.java @@ -19,6 +19,7 @@ import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.module.annotations.ReactModule; import com.facebook.react.modules.core.DeviceEventManagerModule; +import com.facebook.react.turbomodule.core.interfaces.TurboModule; import com.facebook.react.uimanager.DisplayMetricsHolder; /** @@ -26,7 +27,7 @@ */ @ReactModule(name = DeviceInfoModule.NAME) public class DeviceInfoModule extends BaseJavaModule implements - LifecycleEventListener { + LifecycleEventListener, TurboModule { public static final String NAME = "DeviceInfo"; @@ -89,4 +90,7 @@ public void emitUpdateDimensionsEvent() { .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) .emit("didUpdateDimensions", DisplayMetricsHolder.getDisplayMetricsNativeMap(mFontScale)); } + + @Override + public void invalidate() {} } From 56751851dfefd4b99d7cf478e6d04d9dc1aa4d11 Mon Sep 17 00:00:00 2001 From: Emily Janzer Date: Wed, 5 Jun 2019 21:32:15 -0700 Subject: [PATCH 0214/1084] TurboModule for PlatformConstants Summary: Adding TurboModule for PlatformConstantsAndroid, and adding to Catalyst and Venice Reviewed By: mdvacca Differential Revision: D15630344 fbshipit-source-id: df6d5868cd3c9f54297bfea58683c8c1fd9375f0 --- .../react/modules/systeminfo/AndroidInfoModule.java | 6 +++++- .../main/java/com/facebook/react/modules/systeminfo/BUCK | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/AndroidInfoModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/AndroidInfoModule.java index cf5ca4036c5597..6e2d61a3f34dc3 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/AndroidInfoModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/AndroidInfoModule.java @@ -21,6 +21,7 @@ import com.facebook.react.common.build.ReactBuildConfig; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.module.annotations.ReactModule; +import com.facebook.react.turbomodule.core.interfaces.TurboModule; import java.util.HashMap; import java.util.Map; @@ -34,7 +35,7 @@ */ @ReactModule(name = AndroidInfoModule.NAME) @SuppressLint("HardwareIds") -public class AndroidInfoModule extends ReactContextBaseJavaModule { +public class AndroidInfoModule extends ReactContextBaseJavaModule implements TurboModule { public static final String NAME = "PlatformConstants"; private static final String IS_TESTING = "IS_TESTING"; @@ -89,6 +90,9 @@ public String getAndroidID(){ return Secure.getString(getReactApplicationContext().getContentResolver(),Secure.ANDROID_ID); } + @Override + public void invalidate() {} + private Boolean isRunningScreenshotTest() { try { Class.forName("android.support.test.rule.ActivityTestRule"); diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/BUCK index 433ecaf80863a3..934de8ce65990d 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/BUCK @@ -15,6 +15,7 @@ rn_android_library( react_native_target("java/com/facebook/react/common:common"), react_native_target("java/com/facebook/react/module/annotations:annotations"), react_native_target("res:systeminfo"), + react_native_target("java/com/facebook/react/turbomodule/core/interfaces:interfaces"), ], exported_deps = [ ":systeminfo-moduleless", From cbbbb455dda313cca1a1763cc5453079ce87bc73 Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Thu, 6 Jun 2019 02:40:34 -0700 Subject: [PATCH 0215/1084] Move ToolbarAndroid Java code to FB internal Summary: This moves the Toolbar Java files out RN and into our internal React shell. Reviewed By: fkgozali Differential Revision: D15469205 fbshipit-source-id: 15298505d74260618eb89673deb12d1b837b559f --- .../main/java/com/facebook/react/shell/BUCK | 1 - .../react/shell/MainReactPackage.java | 2 - .../com/facebook/react/views/toolbar/BUCK | 30 -- .../toolbar/DrawableWithIntrinsicSize.java | 47 --- .../react/views/toolbar/ReactToolbar.java | 332 ------------------ .../views/toolbar/ReactToolbarManager.java | 267 -------------- .../toolbar/events/ToolbarClickEvent.java | 49 --- 7 files changed, 728 deletions(-) delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/toolbar/BUCK delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/toolbar/DrawableWithIntrinsicSize.java delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbar.java delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbarManager.java delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/views/toolbar/events/ToolbarClickEvent.java diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK b/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK index e97f9ae9547134..fc134a5af2d35d 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK @@ -63,7 +63,6 @@ rn_android_library( react_native_target("java/com/facebook/react/views/text:text"), react_native_target("java/com/facebook/react/views/text/frescosupport:frescosupport"), react_native_target("java/com/facebook/react/views/textinput:textinput"), - react_native_target("java/com/facebook/react/views/toolbar:toolbar"), react_native_target("java/com/facebook/react/views/view:view"), react_native_target("java/com/facebook/react/views/viewpager:viewpager"), react_native_target("java/com/facebook/react/module/annotations:annotations"), diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java index 22348ac1dc63c0..3d1c17ae4dce3a 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java +++ b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java @@ -59,7 +59,6 @@ import com.facebook.react.views.text.ReactVirtualTextViewManager; import com.facebook.react.views.text.frescosupport.FrescoBasedReactTextInlineImageViewManager; import com.facebook.react.views.textinput.ReactTextInputManager; -import com.facebook.react.views.toolbar.ReactToolbarManager; import com.facebook.react.views.view.ReactViewManager; import com.facebook.react.views.viewpager.ReactViewPagerManager; import java.util.ArrayList; @@ -335,7 +334,6 @@ public List createViewManagers(ReactApplicationContext reactContext viewManagers.add(new ReactScrollViewManager()); viewManagers.add(new ReactSliderManager()); viewManagers.add(new ReactSwitchManager()); - viewManagers.add(new ReactToolbarManager()); viewManagers.add(new SwipeRefreshLayoutManager()); // Native equivalents diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/BUCK deleted file mode 100644 index 55d7e0c8ed878c..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/BUCK +++ /dev/null @@ -1,30 +0,0 @@ -load("//tools/build_defs/oss:rn_defs.bzl", "YOGA_TARGET", "react_native_dep", "react_native_target", "rn_android_library") - -rn_android_library( - name = "toolbar", - srcs = glob(["**/*.java"]), - is_androidx = True, - provided_deps = [ - react_native_dep("third-party/android/androidx:annotation"), - react_native_dep("third-party/android/androidx:appcompat"), - react_native_dep("third-party/android/androidx:core"), - react_native_dep("third-party/android/androidx:fragment"), - react_native_dep("third-party/android/androidx:legacy-support-core-ui"), - react_native_dep("third-party/android/androidx:legacy-support-core-utils"), - ], - visibility = [ - "PUBLIC", - ], - deps = [ - YOGA_TARGET, - react_native_dep("libraries/fresco/fresco-react-native:fbcore"), - react_native_dep("libraries/fresco/fresco-react-native:fresco-drawee"), - react_native_dep("libraries/fresco/fresco-react-native:fresco-react-native"), - react_native_dep("libraries/fresco/fresco-react-native:imagepipeline"), - react_native_dep("third-party/java/jsr-305:jsr-305"), - react_native_target("java/com/facebook/react/bridge:bridge"), - react_native_target("java/com/facebook/react/common:common"), - react_native_target("java/com/facebook/react/uimanager:uimanager"), - react_native_target("java/com/facebook/react/uimanager/annotations:annotations"), - ], -) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/DrawableWithIntrinsicSize.java b/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/DrawableWithIntrinsicSize.java deleted file mode 100644 index b673abd96049ba..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/DrawableWithIntrinsicSize.java +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react.views.toolbar; - -import android.graphics.drawable.Drawable; - -import com.facebook.drawee.drawable.ForwardingDrawable; -import com.facebook.imagepipeline.image.ImageInfo; -import com.facebook.react.uimanager.PixelUtil; - -/** - * Fresco currently sets drawables' intrinsic size to (-1, -1). This is to guarantee that scaling is - * performed correctly. In the case of the Toolbar, we don't have access to the widget's internal - * ImageView, which has width/height set to WRAP_CONTENT, which relies on intrinsic size. - * - * To work around this we have this class which just wraps another Drawable, but returns the correct - * dimensions in getIntrinsicWidth/Height. This makes WRAP_CONTENT work in Toolbar's internals. - * - * This drawable uses the size of a loaded image to determine the intrinsic size. It therefore can't - * be used safely until *after* an image has loaded, and must be replaced when the image is - * replaced. - */ -public class DrawableWithIntrinsicSize extends ForwardingDrawable implements Drawable.Callback { - - private final ImageInfo mImageInfo; - - public DrawableWithIntrinsicSize(Drawable drawable, ImageInfo imageInfo) { - super(drawable); - mImageInfo = imageInfo; - } - - @Override - public int getIntrinsicWidth() { - return mImageInfo.getWidth(); - } - - @Override - public int getIntrinsicHeight() { - return mImageInfo.getHeight(); - } - -} diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbar.java b/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbar.java deleted file mode 100644 index aca9653bb6702e..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbar.java +++ /dev/null @@ -1,332 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react.views.toolbar; - -import android.content.Context; -import android.graphics.drawable.Animatable; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import androidx.appcompat.widget.Toolbar; -import android.view.Menu; -import android.view.MenuItem; - -import com.facebook.drawee.backends.pipeline.Fresco; -import com.facebook.drawee.controller.BaseControllerListener; -import com.facebook.drawee.drawable.ScalingUtils; -import com.facebook.drawee.generic.GenericDraweeHierarchy; -import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder; -import com.facebook.drawee.interfaces.DraweeController; -import com.facebook.drawee.view.DraweeHolder; -import com.facebook.drawee.view.MultiDraweeHolder; -import com.facebook.imagepipeline.image.ImageInfo; -import com.facebook.imagepipeline.image.QualityInfo; -import com.facebook.react.bridge.ReadableArray; -import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.uimanager.PixelUtil; - -import javax.annotation.Nullable; - -/** - * Custom implementation of the {@link Toolbar} widget that adds support for remote images in logo - * and navigationIcon using fresco. - */ -public class ReactToolbar extends Toolbar { - - private static final String PROP_ACTION_ICON = "icon"; - private static final String PROP_ACTION_SHOW = "show"; - private static final String PROP_ACTION_SHOW_WITH_TEXT = "showWithText"; - private static final String PROP_ACTION_TITLE = "title"; - - private static final String PROP_ICON_URI = "uri"; - private static final String PROP_ICON_WIDTH = "width"; - private static final String PROP_ICON_HEIGHT = "height"; - - private final DraweeHolder mLogoHolder; - private final DraweeHolder mNavIconHolder; - private final DraweeHolder mOverflowIconHolder; - private final MultiDraweeHolder mActionsHolder = - new MultiDraweeHolder<>(); - - private IconControllerListener mLogoControllerListener; - private IconControllerListener mNavIconControllerListener; - private IconControllerListener mOverflowIconControllerListener; - - /** - * Attaches specific icon width & height to a BaseControllerListener which will be used to - * create the Drawable - */ - private abstract class IconControllerListener extends BaseControllerListener { - - private final DraweeHolder mHolder; - - private IconImageInfo mIconImageInfo; - - public IconControllerListener(DraweeHolder holder) { - mHolder = holder; - } - - public void setIconImageInfo(IconImageInfo iconImageInfo) { - mIconImageInfo = iconImageInfo; - } - - @Override - public void onFinalImageSet(String id, @Nullable ImageInfo imageInfo, @Nullable Animatable animatable) { - super.onFinalImageSet(id, imageInfo, animatable); - - final ImageInfo info = mIconImageInfo != null ? mIconImageInfo : imageInfo; - setDrawable(new DrawableWithIntrinsicSize(mHolder.getTopLevelDrawable(), info)); - } - - protected abstract void setDrawable(Drawable d); - - } - - private class ActionIconControllerListener extends IconControllerListener { - private final MenuItem mItem; - - ActionIconControllerListener(MenuItem item, DraweeHolder holder) { - super(holder); - mItem = item; - } - - @Override - protected void setDrawable(Drawable d) { - mItem.setIcon(d); - ReactToolbar.this.requestLayout(); - } - } - - /** - * Simple implementation of ImageInfo, only providing width & height - */ - private static class IconImageInfo implements ImageInfo { - - private int mWidth; - private int mHeight; - - public IconImageInfo(int width, int height) { - mWidth = width; - mHeight = height; - } - - @Override - public int getWidth() { - return mWidth; - } - - @Override - public int getHeight() { - return mHeight; - } - - @Override - public QualityInfo getQualityInfo() { - return null; - } - - } - - public ReactToolbar(Context context) { - super(context); - - mLogoHolder = DraweeHolder.create(createDraweeHierarchy(), context); - mNavIconHolder = DraweeHolder.create(createDraweeHierarchy(), context); - mOverflowIconHolder = DraweeHolder.create(createDraweeHierarchy(), context); - - mLogoControllerListener = new IconControllerListener(mLogoHolder) { - @Override - protected void setDrawable(Drawable d) { - setLogo(d); - } - }; - - mNavIconControllerListener = new IconControllerListener(mNavIconHolder) { - @Override - protected void setDrawable(Drawable d) { - setNavigationIcon(d); - } - }; - - mOverflowIconControllerListener = new IconControllerListener(mOverflowIconHolder) { - @Override - protected void setDrawable(Drawable d) { - setOverflowIcon(d); - } - }; - - } - - private final Runnable mLayoutRunnable = new Runnable() { - @Override - public void run() { - measure( - MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.EXACTLY)); - layout(getLeft(), getTop(), getRight(), getBottom()); - } - }; - - @Override - public void requestLayout() { - super.requestLayout(); - - // The toolbar relies on a measure + layout pass happening after it calls requestLayout(). - // Without this, certain calls (e.g. setLogo) only take effect after a second invalidation. - post(mLayoutRunnable); - } - - @Override - public void onDetachedFromWindow() { - super.onDetachedFromWindow(); - detachDraweeHolders(); - } - - @Override - public void onStartTemporaryDetach() { - super.onStartTemporaryDetach(); - detachDraweeHolders(); - } - - @Override - public void onAttachedToWindow() { - super.onAttachedToWindow(); - attachDraweeHolders(); - } - - @Override - public void onFinishTemporaryDetach() { - super.onFinishTemporaryDetach(); - attachDraweeHolders(); - } - - private void detachDraweeHolders() { - mLogoHolder.onDetach(); - mNavIconHolder.onDetach(); - mOverflowIconHolder.onDetach(); - mActionsHolder.onDetach(); - } - - private void attachDraweeHolders() { - mLogoHolder.onAttach(); - mNavIconHolder.onAttach(); - mOverflowIconHolder.onAttach(); - mActionsHolder.onAttach(); - } - - /* package */ void setLogoSource(@Nullable ReadableMap source) { - setIconSource(source, mLogoControllerListener, mLogoHolder); - } - - /* package */ void setNavIconSource(@Nullable ReadableMap source) { - setIconSource(source, mNavIconControllerListener, mNavIconHolder); - } - - /* package */ void setOverflowIconSource(@Nullable ReadableMap source) { - setIconSource(source, mOverflowIconControllerListener, mOverflowIconHolder); - } - - /* package */ void setActions(@Nullable ReadableArray actions) { - Menu menu = getMenu(); - menu.clear(); - mActionsHolder.clear(); - if (actions != null) { - for (int i = 0; i < actions.size(); i++) { - ReadableMap action = actions.getMap(i); - - MenuItem item = menu.add(Menu.NONE, Menu.NONE, i, action.getString(PROP_ACTION_TITLE)); - - if (action.hasKey(PROP_ACTION_ICON)) { - setMenuItemIcon(item, action.getMap(PROP_ACTION_ICON)); - } - - int showAsAction = action.hasKey(PROP_ACTION_SHOW) - ? action.getInt(PROP_ACTION_SHOW) - : MenuItem.SHOW_AS_ACTION_NEVER; - if (action.hasKey(PROP_ACTION_SHOW_WITH_TEXT) && - action.getBoolean(PROP_ACTION_SHOW_WITH_TEXT)) { - showAsAction = showAsAction | MenuItem.SHOW_AS_ACTION_WITH_TEXT; - } - item.setShowAsAction(showAsAction); - } - } - } - - private void setMenuItemIcon(final MenuItem item, ReadableMap iconSource) { - - DraweeHolder holder = - DraweeHolder.create(createDraweeHierarchy(), getContext()); - ActionIconControllerListener controllerListener = new ActionIconControllerListener(item, holder); - controllerListener.setIconImageInfo(getIconImageInfo(iconSource)); - - setIconSource(iconSource, controllerListener, holder); - - mActionsHolder.add(holder); - - } - - /** - * Sets an icon for a specific icon source. If the uri indicates an icon - * to be somewhere remote (http/https) or on the local filesystem, it uses fresco to load it. - * Otherwise it loads the Drawable from the Resources and directly returns it via a callback - */ - private void setIconSource(ReadableMap source, IconControllerListener controllerListener, DraweeHolder holder) { - - String uri = source != null ? source.getString(PROP_ICON_URI) : null; - - if (uri == null) { - controllerListener.setIconImageInfo(null); - controllerListener.setDrawable(null); - } else if (uri.startsWith("http://") || uri.startsWith("https://") || uri.startsWith("file://")) { - controllerListener.setIconImageInfo(getIconImageInfo(source)); - DraweeController controller = Fresco.newDraweeControllerBuilder() - .setUri(Uri.parse(uri)) - .setControllerListener(controllerListener) - .setOldController(holder.getController()) - .build(); - holder.setController(controller); - holder.getTopLevelDrawable().setVisible(true, true); - } else { - controllerListener.setDrawable(getDrawableByName(uri)); - } - - } - - private GenericDraweeHierarchy createDraweeHierarchy() { - return new GenericDraweeHierarchyBuilder(getResources()) - .setActualImageScaleType(ScalingUtils.ScaleType.FIT_CENTER) - .setFadeDuration(0) - .build(); - } - - private int getDrawableResourceByName(String name) { - return getResources().getIdentifier( - name, - "drawable", - getContext().getPackageName()); - } - - private Drawable getDrawableByName(String name) { - int drawableResId = getDrawableResourceByName(name); - if (drawableResId != 0) { - return getResources().getDrawable(getDrawableResourceByName(name)); - } else { - return null; - } - } - - private IconImageInfo getIconImageInfo(ReadableMap source) { - if (source.hasKey(PROP_ICON_WIDTH) && source.hasKey(PROP_ICON_HEIGHT)) { - final int width = Math.round(PixelUtil.toPixelFromDIP(source.getInt(PROP_ICON_WIDTH))); - final int height = Math.round(PixelUtil.toPixelFromDIP(source.getInt(PROP_ICON_HEIGHT))); - return new IconImageInfo(width, height); - } else { - return null; - } - } - -} diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbarManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbarManager.java deleted file mode 100644 index 422d77d18c106e..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/ReactToolbarManager.java +++ /dev/null @@ -1,267 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react.views.toolbar; - -import android.content.Context; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.graphics.Color; -import androidx.core.view.ViewCompat; -import android.util.LayoutDirection; -import android.view.MenuItem; -import android.view.View; -import com.facebook.react.bridge.ReadableArray; -import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.common.MapBuilder; -import com.facebook.react.uimanager.PixelUtil; -import com.facebook.react.uimanager.ThemedReactContext; -import com.facebook.react.uimanager.UIManagerModule; -import com.facebook.react.uimanager.ViewGroupManager; -import com.facebook.react.uimanager.annotations.ReactProp; -import com.facebook.react.uimanager.events.EventDispatcher; -import com.facebook.react.views.toolbar.events.ToolbarClickEvent; -import java.util.Map; -import javax.annotation.Nullable; - -/** - * Manages instances of ReactToolbar. - */ -public class ReactToolbarManager extends ViewGroupManager { - - private static final String REACT_CLASS = "ToolbarAndroid"; - private static final int COMMAND_DISMISS_POPUP_MENUS = 1; - - @Override - public String getName() { - return REACT_CLASS; - } - - @Override - protected ReactToolbar createViewInstance(ThemedReactContext reactContext) { - return new ReactToolbar(reactContext); - } - - @ReactProp(name = "logo") - public void setLogo(ReactToolbar view, @Nullable ReadableMap logo) { - view.setLogoSource(logo); - } - - @ReactProp(name = "navIcon") - public void setNavIcon(ReactToolbar view, @Nullable ReadableMap navIcon) { - view.setNavIconSource(navIcon); - } - - @ReactProp(name = "overflowIcon") - public void setOverflowIcon(ReactToolbar view, @Nullable ReadableMap overflowIcon) { - view.setOverflowIconSource(overflowIcon); - } - - @ReactProp(name = "rtl") - public void setRtl(ReactToolbar view, boolean rtl) { - ViewCompat.setLayoutDirection(view, rtl ? ViewCompat.LAYOUT_DIRECTION_RTL : ViewCompat.LAYOUT_DIRECTION_LTR); - } - - @ReactProp(name = "subtitle") - public void setSubtitle(ReactToolbar view, @Nullable String subtitle) { - view.setSubtitle(subtitle); - } - - @ReactProp(name = "subtitleColor", customType = "Color") - public void setSubtitleColor(ReactToolbar view, @Nullable Integer subtitleColor) { - int[] defaultColors = getDefaultColors(view.getContext()); - if (subtitleColor != null) { - view.setSubtitleTextColor(subtitleColor); - } else { - view.setSubtitleTextColor(defaultColors[1]); - } - } - - @ReactProp(name = "title") - public void setTitle(ReactToolbar view, @Nullable String title) { - view.setTitle(title); - } - - @ReactProp(name = "titleColor", customType = "Color") - public void setTitleColor(ReactToolbar view, @Nullable Integer titleColor) { - int[] defaultColors = getDefaultColors(view.getContext()); - if (titleColor != null) { - view.setTitleTextColor(titleColor); - } else { - view.setTitleTextColor(defaultColors[0]); - } - } - - @ReactProp(name = "contentInsetStart", defaultFloat = Float.NaN) - public void setContentInsetStart(ReactToolbar view, float insetStart) { - int inset = Float.isNaN(insetStart) ? - getDefaultContentInsets(view.getContext())[0] : - Math.round(PixelUtil.toPixelFromDIP(insetStart)); - view.setContentInsetsRelative(inset, view.getContentInsetEnd()); - } - - @ReactProp(name = "contentInsetEnd", defaultFloat = Float.NaN) - public void setContentInsetEnd(ReactToolbar view, float insetEnd) { - int inset = Float.isNaN(insetEnd) ? - getDefaultContentInsets(view.getContext())[1] : - Math.round(PixelUtil.toPixelFromDIP(insetEnd)); - view.setContentInsetsRelative(view.getContentInsetStart(), inset); - } - - @ReactProp(name = "nativeActions") - public void setActions(ReactToolbar view, @Nullable ReadableArray actions) { - view.setActions(actions); - } - - @Override - protected void addEventEmitters(final ThemedReactContext reactContext, final ReactToolbar view) { - final EventDispatcher mEventDispatcher = reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher(); - view.setNavigationOnClickListener( - new View.OnClickListener() { - @Override - public void onClick(View v) { - mEventDispatcher.dispatchEvent( - new ToolbarClickEvent(view.getId(), -1)); - } - }); - - view.setOnMenuItemClickListener( - new ReactToolbar.OnMenuItemClickListener() { - @Override - public boolean onMenuItemClick(MenuItem menuItem) { - mEventDispatcher.dispatchEvent( - new ToolbarClickEvent( - view.getId(), - menuItem.getOrder())); - return true; - } - }); - } - - @Nullable - @Override - public Map getExportedViewConstants() { - return MapBuilder.of( - "ShowAsAction", - MapBuilder.of( - "never", MenuItem.SHOW_AS_ACTION_NEVER, - "always", MenuItem.SHOW_AS_ACTION_ALWAYS, - "ifRoom", MenuItem.SHOW_AS_ACTION_IF_ROOM)); - } - - @Override - public boolean needsCustomLayoutForChildren() { - return true; - } - - @Nullable - @Override - public Map getCommandsMap() { - return MapBuilder.of("dismissPopupMenus", COMMAND_DISMISS_POPUP_MENUS); - } - - @Override - public void receiveCommand(ReactToolbar view, int commandType, @Nullable ReadableArray args) { - switch (commandType) { - case COMMAND_DISMISS_POPUP_MENUS: { - view.dismissPopupMenus(); - return; - } - default: - throw new IllegalArgumentException(String.format( - "Unsupported command %d received by %s.", - commandType, - getClass().getSimpleName())); - } - } - - private int[] getDefaultContentInsets(Context context) { - Resources.Theme theme = context.getTheme(); - TypedArray toolbarStyle = null; - TypedArray contentInsets = null; - - try { - toolbarStyle = - theme.obtainStyledAttributes(new int[] {getIdentifier(context, "toolbarStyle")}); - - int toolbarStyleResId = toolbarStyle.getResourceId(0, 0); - - contentInsets = - theme.obtainStyledAttributes( - toolbarStyleResId, - new int[] { - getIdentifier(context, "contentInsetStart"), - getIdentifier(context, "contentInsetEnd"), - }); - - int contentInsetStart = contentInsets.getDimensionPixelSize(0, 0); - int contentInsetEnd = contentInsets.getDimensionPixelSize(1, 0); - - return new int[] {contentInsetStart, contentInsetEnd}; - } finally { - recycleQuietly(toolbarStyle); - recycleQuietly(contentInsets); - } - - } - - private static int[] getDefaultColors(Context context) { - Resources.Theme theme = context.getTheme(); - TypedArray toolbarStyle = null; - TypedArray textAppearances = null; - TypedArray titleTextAppearance = null; - TypedArray subtitleTextAppearance = null; - - try { - toolbarStyle = - theme.obtainStyledAttributes(new int[] {getIdentifier(context, "toolbarStyle")}); - - int toolbarStyleResId = toolbarStyle.getResourceId(0, 0); - textAppearances = - theme.obtainStyledAttributes( - toolbarStyleResId, - new int[] { - getIdentifier(context, "titleTextAppearance"), - getIdentifier(context, "subtitleTextAppearance"), - }); - - int titleTextAppearanceResId = textAppearances.getResourceId(0, 0); - int subtitleTextAppearanceResId = textAppearances.getResourceId(1, 0); - - titleTextAppearance = theme - .obtainStyledAttributes(titleTextAppearanceResId, new int[]{android.R.attr.textColor}); - subtitleTextAppearance = theme - .obtainStyledAttributes(subtitleTextAppearanceResId, new int[]{android.R.attr.textColor}); - - int titleTextColor = titleTextAppearance.getColor(0, Color.BLACK); - int subtitleTextColor = subtitleTextAppearance.getColor(0, Color.BLACK); - - return new int[] {titleTextColor, subtitleTextColor}; - } finally { - recycleQuietly(toolbarStyle); - recycleQuietly(textAppearances); - recycleQuietly(titleTextAppearance); - recycleQuietly(subtitleTextAppearance); - } - } - - private static void recycleQuietly(@Nullable TypedArray style) { - if (style != null) { - style.recycle(); - } - } - - /** - * The appcompat-v7 BUCK dep is listed as a provided_dep, which complains that - * com.facebook.react.R doesn't exist. Since the attributes provided from a parent, we can access - * those attributes dynamically. - */ - private static int getIdentifier(Context context, String name) { - return context.getResources().getIdentifier(name, "attr", context.getPackageName()); - } - -} diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/events/ToolbarClickEvent.java b/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/events/ToolbarClickEvent.java deleted file mode 100644 index 9025178c050e1f..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/views/toolbar/events/ToolbarClickEvent.java +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -package com.facebook.react.views.toolbar.events; - -import com.facebook.react.bridge.WritableMap; -import com.facebook.react.bridge.WritableNativeMap; -import com.facebook.react.uimanager.events.Event; -import com.facebook.react.uimanager.events.RCTEventEmitter; - -/** - * Represents a click on the toolbar. - * Position is meaningful when the click happened on a menu - */ -public class ToolbarClickEvent extends Event { - - private static final String EVENT_NAME = "topSelect"; - private final int position; - - public ToolbarClickEvent(int viewId, int position) { - super(viewId); - this.position = position; - } - - public int getPosition() { - return position; - } - - @Override - public String getEventName() { - return EVENT_NAME; - } - - @Override - public boolean canCoalesce() { - return false; - } - - @Override - public void dispatch(RCTEventEmitter rctEventEmitter) { - WritableMap event = new WritableNativeMap(); - event.putInt("position", getPosition()); - rctEventEmitter.receiveEvent(getViewTag(), getEventName(), event); - } - -} From 022470ce62186ffb1a471a3a92c7bfdd579c824a Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Thu, 6 Jun 2019 02:41:36 -0700 Subject: [PATCH 0216/1084] Remove Map/Set from RN Open Source Summary: This moves Map/Set to fb internal. We do not need them in open source any more but we still need this in some apps at FB that use an old version of JSC. Reviewed By: TheSavior Differential Revision: D14786123 fbshipit-source-id: 1c49b47d547ad30f2d93c00b44382cf410100b67 --- Libraries/Core/InitializeCore.js | 1 - .../Core/__tests__/MapAndSetPolyfills-test.js | 102 --- Libraries/Core/polyfillES6Collections.js | 27 - Libraries/vendor/core/Map.js | 590 ------------------ Libraries/vendor/core/Set.js | 198 ------ .../core/_shouldPolyfillES6Collection.js | 66 -- flow/Map.js | 40 -- flow/Set.js | 36 -- 8 files changed, 1060 deletions(-) delete mode 100644 Libraries/Core/__tests__/MapAndSetPolyfills-test.js delete mode 100644 Libraries/Core/polyfillES6Collections.js delete mode 100644 Libraries/vendor/core/Map.js delete mode 100644 Libraries/vendor/core/Set.js delete mode 100644 Libraries/vendor/core/_shouldPolyfillES6Collection.js delete mode 100644 flow/Map.js delete mode 100644 flow/Set.js diff --git a/Libraries/Core/InitializeCore.js b/Libraries/Core/InitializeCore.js index 263001547b6132..8b9a6a490739d1 100644 --- a/Libraries/Core/InitializeCore.js +++ b/Libraries/Core/InitializeCore.js @@ -28,7 +28,6 @@ const start = Date.now(); require('./setUpGlobals'); -require('./polyfillES6Collections'); require('./setUpSystrace'); require('./setUpErrorHandling'); require('./polyfillPromise'); diff --git a/Libraries/Core/__tests__/MapAndSetPolyfills-test.js b/Libraries/Core/__tests__/MapAndSetPolyfills-test.js deleted file mode 100644 index 20f54a0e68d9d5..00000000000000 --- a/Libraries/Core/__tests__/MapAndSetPolyfills-test.js +++ /dev/null @@ -1,102 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @emails oncall+react_native - */ -'use strict'; - -// Save these methods so that we can restore them afterward. -const {freeze, seal, preventExtensions} = Object; - -function setup() { - jest.setMock('../../vendor/core/_shouldPolyfillES6Collection', () => true); -} - -function cleanup() { - Object.assign(Object, {freeze, seal, preventExtensions}); -} - -describe('Map polyfill', () => { - setup(); - - const Map = require('../../vendor/core/Map'); - - it('is not native', () => { - const getCode = Function.prototype.toString.call(Map.prototype.get); - expect(getCode).not.toContain('[native code]'); - expect(getCode).toContain('getIndex'); - }); - - it('should tolerate non-extensible object keys', () => { - const map = new Map(); - const key = Object.create(null); - Object.freeze(key); - map.set(key, key); - expect(map.size).toBe(1); - expect(map.has(key)).toBe(true); - map.delete(key); - expect(map.size).toBe(0); - expect(map.has(key)).toBe(false); - }); - - it('should not get confused by prototypal inheritance', () => { - const map = new Map(); - const proto = Object.create(null); - const base = Object.create(proto); - map.set(proto, proto); - expect(map.size).toBe(1); - expect(map.has(proto)).toBe(true); - expect(map.has(base)).toBe(false); - map.set(base, base); - expect(map.size).toBe(2); - expect(map.get(proto)).toBe(proto); - expect(map.get(base)).toBe(base); - }); - - afterAll(cleanup); -}); - -describe('Set polyfill', () => { - setup(); - - const Set = require('../../vendor/core/Set'); - - it('is not native', () => { - const addCode = Function.prototype.toString.call(Set.prototype.add); - expect(addCode).not.toContain('[native code]'); - }); - - it('should tolerate non-extensible object elements', () => { - const set = new Set(); - const elem = Object.create(null); - Object.freeze(elem); - set.add(elem); - expect(set.size).toBe(1); - expect(set.has(elem)).toBe(true); - set.add(elem); - expect(set.size).toBe(1); - set.delete(elem); - expect(set.size).toBe(0); - expect(set.has(elem)).toBe(false); - }); - - it('should not get confused by prototypal inheritance', () => { - const set = new Set(); - const proto = Object.create(null); - const base = Object.create(proto); - set.add(proto); - expect(set.size).toBe(1); - expect(set.has(proto)).toBe(true); - expect(set.has(base)).toBe(false); - set.add(base); - expect(set.size).toBe(2); - expect(set.has(proto)).toBe(true); - expect(set.has(base)).toBe(true); - }); - - afterAll(cleanup); -}); diff --git a/Libraries/Core/polyfillES6Collections.js b/Libraries/Core/polyfillES6Collections.js deleted file mode 100644 index b58718540fedca..00000000000000 --- a/Libraries/Core/polyfillES6Collections.js +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow strict-local - * @format - */ -'use strict'; - -const {polyfillGlobal} = require('../Utilities/PolyfillFunctions'); - -/** - * Polyfill ES6 collections (Map and Set). - * If you don't need these polyfills, don't use InitializeCore; just directly - * require the modules you need from InitializeCore for setup. - */ -const _shouldPolyfillCollection = require('../vendor/core/_shouldPolyfillES6Collection'); -if (_shouldPolyfillCollection('Map')) { - // $FlowFixMe: even in strict-local mode Flow expects Map to be Flow-typed - polyfillGlobal('Map', () => require('../vendor/core/Map')); -} -if (_shouldPolyfillCollection('Set')) { - // $FlowFixMe: even in strict-local mode Flow expects Set to be Flow-typed - polyfillGlobal('Set', () => require('../vendor/core/Set')); -} diff --git a/Libraries/vendor/core/Map.js b/Libraries/vendor/core/Map.js deleted file mode 100644 index 4f23b1f4783ab8..00000000000000 --- a/Libraries/vendor/core/Map.js +++ /dev/null @@ -1,590 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @preventMunge - * @typechecks - */ - -/* eslint-disable no-extend-native, no-shadow-restricted-names */ - -'use strict'; - -const _shouldPolyfillES6Collection = require('./_shouldPolyfillES6Collection'); -const guid = require('./guid'); -const toIterator = require('./toIterator'); - -module.exports = (function(global, undefined) { - // Since our implementation is spec-compliant for the most part we can safely - // delegate to a built-in version if exists and is implemented correctly. - // Firefox had gotten a few implementation details wrong across different - // versions so we guard against that. - if (!_shouldPolyfillES6Collection('Map')) { - return global.Map; - } - - const hasOwn = Object.prototype.hasOwnProperty; - - /** - * == ES6 Map Collection == - * - * This module is meant to implement a Map collection as described in chapter - * 23.1 of the ES6 specification. - * - * Map objects are collections of key/value pairs where both the keys and - * values may be arbitrary ECMAScript language values. A distinct key value - * may only occur in one key/value pair within the Map's collection. - * - * https://people.mozilla.org/~jorendorff/es6-draft.html#sec-map-objects - * - * There only two -- rather small -- deviations from the spec: - * - * 1. The use of untagged frozen objects as keys. - * We decided not to allow and simply throw an error, because this - * implementation of Map works by tagging objects used as Map keys - * with a secret hash property for fast access to the object's place - * in the internal _mapData array. However, to limit the impact of - * this spec deviation, Libraries/Core/InitializeCore.js also wraps - * Object.freeze, Object.seal, and Object.preventExtensions so that - * they tag objects before making them non-extensible, by inserting - * each object into a Map and then immediately removing it. - * - * 2. The `size` property on a map object is a regular property and not a - * computed property on the prototype as described by the spec. - * The reason being is that we simply want to support ES3 environments - * which doesn't implement computed properties. - * - * == Usage == - * - * var map = new Map(iterable); - * - * map.set(key, value); - * map.get(key); // value - * map.has(key); // true - * map.delete(key); // true - * - * var iterator = map.keys(); - * iterator.next(); // {value: key, done: false} - * - * var iterator = map.values(); - * iterator.next(); // {value: value, done: false} - * - * var iterator = map.entries(); - * iterator.next(); // {value: [key, value], done: false} - * - * map.forEach(function(value, key){ this === thisArg }, thisArg); - * - * map.clear(); // resets map. - */ - - /** - * Constants - */ - - // Kinds of map iterations 23.1.5.3 - const KIND_KEY = 'key'; - const KIND_VALUE = 'value'; - const KIND_KEY_VALUE = 'key+value'; - - // In older browsers we can't create a null-prototype object so we have to - // defend against key collisions with built-in methods. - const KEY_PREFIX = '$map_'; - - // This property will be used as the internal size variable to disallow - // writing and to issue warnings for writings in development. - let SECRET_SIZE_PROP; - if (__DEV__) { - SECRET_SIZE_PROP = '$size' + guid(); - } - - class Map { - /** - * 23.1.1.1 - * Takes an `iterable` which is basically any object that implements a - * Symbol.iterator (@@iterator) method. The iterable is expected to be a - * collection of pairs. Each pair is a key/value pair that will be used - * to instantiate the map. - * - * @param {*} iterable - */ - constructor(iterable) { - if (!isObject(this)) { - throw new TypeError('Wrong map object type.'); - } - - initMap(this); - - if (iterable != null) { - const it = toIterator(iterable); - let next; - while (!(next = it.next()).done) { - if (!isObject(next.value)) { - throw new TypeError('Expected iterable items to be pair objects.'); - } - this.set(next.value[0], next.value[1]); - } - } - } - - /** - * 23.1.3.1 - * Clears the map from all keys and values. - */ - clear() { - initMap(this); - } - - /** - * 23.1.3.7 - * Check if a key exists in the collection. - * - * @param {*} key - * @return {boolean} - */ - has(key) { - const index = getIndex(this, key); - return !!(index != null && this._mapData[index]); - } - - /** - * 23.1.3.9 - * Adds a key/value pair to the collection. - * - * @param {*} key - * @param {*} value - * @return {map} - */ - set(key, value) { - let index = getIndex(this, key); - - if (index != null && this._mapData[index]) { - this._mapData[index][1] = value; - } else { - index = this._mapData.push([key, value]) - 1; - setIndex(this, key, index); - if (__DEV__) { - this[SECRET_SIZE_PROP] += 1; - } else { - this.size += 1; - } - } - - return this; - } - - /** - * 23.1.3.6 - * Gets a value associated with a key in the collection. - * - * @param {*} key - * @return {*} - */ - get(key) { - const index = getIndex(this, key); - if (index == null) { - return undefined; - } else { - return this._mapData[index][1]; - } - } - - /** - * 23.1.3.3 - * Delete a key/value from the collection. - * - * @param {*} key - * @return {boolean} Whether the key was found and deleted. - */ - delete(key) { - const index = getIndex(this, key); - if (index != null && this._mapData[index]) { - setIndex(this, key, undefined); - this._mapData[index] = undefined; - if (__DEV__) { - this[SECRET_SIZE_PROP] -= 1; - } else { - this.size -= 1; - } - return true; - } else { - return false; - } - } - - /** - * 23.1.3.4 - * Returns an iterator over the key/value pairs (in the form of an Array) in - * the collection. - * - * @return {MapIterator} - */ - entries() { - return new MapIterator(this, KIND_KEY_VALUE); - } - - /** - * 23.1.3.8 - * Returns an iterator over the keys in the collection. - * - * @return {MapIterator} - */ - keys() { - return new MapIterator(this, KIND_KEY); - } - - /** - * 23.1.3.11 - * Returns an iterator over the values pairs in the collection. - * - * @return {MapIterator} - */ - values() { - return new MapIterator(this, KIND_VALUE); - } - - /** - * 23.1.3.5 - * Iterates over the key/value pairs in the collection calling `callback` - * with [value, key, map]. An optional `thisArg` can be passed to set the - * context when `callback` is called. - * - * @param {function} callback - * @param {?object} thisArg - */ - forEach(callback, thisArg) { - if (typeof callback !== 'function') { - throw new TypeError('Callback must be callable.'); - } - - const boundCallback = callback.bind(thisArg || undefined); - const mapData = this._mapData; - - // Note that `mapData.length` should be computed on each iteration to - // support iterating over new items in the map that were added after the - // start of the iteration. - for (let i = 0; i < mapData.length; i++) { - const entry = mapData[i]; - if (entry != null) { - boundCallback(entry[1], entry[0], this); - } - } - } - } - - // 23.1.3.12 - Map.prototype[toIterator.ITERATOR_SYMBOL] = Map.prototype.entries; - - class MapIterator { - /** - * 23.1.5.1 - * Create a `MapIterator` for a given `map`. While this class is private it - * will create objects that will be passed around publicily. - * - * @param {map} map - * @param {string} kind - */ - constructor(map, kind) { - if (!(isObject(map) && map._mapData)) { - throw new TypeError('Object is not a map.'); - } - - if ([KIND_KEY, KIND_KEY_VALUE, KIND_VALUE].indexOf(kind) === -1) { - throw new Error('Invalid iteration kind.'); - } - - this._map = map; - this._nextIndex = 0; - this._kind = kind; - } - - /** - * 23.1.5.2.1 - * Get the next iteration. - * - * @return {object} - */ - next() { - if (!this instanceof Map) { - throw new TypeError('Expected to be called on a MapIterator.'); - } - - const map = this._map; - let index = this._nextIndex; - const kind = this._kind; - - if (map == null) { - return createIterResultObject(undefined, true); - } - - const entries = map._mapData; - - while (index < entries.length) { - const record = entries[index]; - - index += 1; - this._nextIndex = index; - - if (record) { - if (kind === KIND_KEY) { - return createIterResultObject(record[0], false); - } else if (kind === KIND_VALUE) { - return createIterResultObject(record[1], false); - } else if (kind) { - return createIterResultObject(record, false); - } - } - } - - this._map = undefined; - - return createIterResultObject(undefined, true); - } - } - - // We can put this in the class definition once we have computed props - // transform. - // 23.1.5.2.2 - MapIterator.prototype[toIterator.ITERATOR_SYMBOL] = function() { - return this; - }; - - /** - * Helper Functions. - */ - - /** - * Return an index to map.[[MapData]] array for a given Key. - * - * @param {map} map - * @param {*} key - * @return {?number} - */ - function getIndex(map, key) { - if (isObject(key)) { - const hash = getHash(key); - return map._objectIndex[hash]; - } else { - const prefixedKey = KEY_PREFIX + key; - if (typeof key === 'string') { - return map._stringIndex[prefixedKey]; - } else { - return map._otherIndex[prefixedKey]; - } - } - } - - /** - * Setup an index that refer to the key's location in map.[[MapData]]. - * - * @param {map} map - * @param {*} key - */ - function setIndex(map, key, index) { - const shouldDelete = index == null; - - if (isObject(key)) { - const hash = getHash(key); - if (shouldDelete) { - delete map._objectIndex[hash]; - } else { - map._objectIndex[hash] = index; - } - } else { - const prefixedKey = KEY_PREFIX + key; - if (typeof key === 'string') { - if (shouldDelete) { - delete map._stringIndex[prefixedKey]; - } else { - map._stringIndex[prefixedKey] = index; - } - } else { - if (shouldDelete) { - delete map._otherIndex[prefixedKey]; - } else { - map._otherIndex[prefixedKey] = index; - } - } - } - } - - /** - * Instantiate a map with internal slots. - * - * @param {map} map - */ - function initMap(map) { - // Data structure design inspired by Traceur's Map implementation. - // We maintain an internal array for all the entries. The array is needed - // to remember order. However, to have a reasonable HashMap performance - // i.e. O(1) for insertion, deletion, and retrieval. We maintain indices - // in objects for fast look ups. Indices are split up according to data - // types to avoid collisions. - map._mapData = []; - - // Object index maps from an object "hash" to index. The hash being a unique - // property of our choosing that we associate with the object. Association - // is done by ways of keeping a non-enumerable property on the object. - // Ideally these would be `Object.create(null)` objects but since we're - // trying to support ES3 we'll have to guard against collisions using - // prefixes on the keys rather than rely on null prototype objects. - map._objectIndex = {}; - - // String index maps from strings to index. - map._stringIndex = {}; - - // Numbers, booleans, undefined, and null. - map._otherIndex = {}; - - // Unfortunately we have to support ES3 and cannot have `Map.prototype.size` - // be a getter method but just a regular method. The biggest problem with - // this is safety. Clients can change the size property easily and possibly - // without noticing (e.g. `if (map.size = 1) {..}` kind of typo). What we - // can do to mitigate use getters and setters in development to disallow - // and issue a warning for changing the `size` property. - if (__DEV__) { - if (isES5) { - // If the `SECRET_SIZE_PROP` property is already defined then we're not - // in the first call to `initMap` (e.g. coming from `map.clear()`) so - // all we need to do is reset the size without defining the properties. - if (hasOwn.call(map, SECRET_SIZE_PROP)) { - map[SECRET_SIZE_PROP] = 0; - } else { - Object.defineProperty(map, SECRET_SIZE_PROP, { - value: 0, - writable: true, - }); - Object.defineProperty(map, 'size', { - set: v => { - console.error( - 'PLEASE FIX ME: You are changing the map size property which ' + - 'should not be writable and will break in production.', - ); - throw new Error('The map size property is not writable.'); - }, - get: () => map[SECRET_SIZE_PROP], - }); - } - - // NOTE: Early return to implement immutable `.size` in DEV. - return; - } - } - - // This is a diviation from the spec. `size` should be a getter on - // `Map.prototype`. However, we have to support IE8. - map.size = 0; - } - - /** - * Check if something is an object. - * - * @param {*} o - * @return {boolean} - */ - function isObject(o) { - return o != null && (typeof o === 'object' || typeof o === 'function'); - } - - /** - * Create an iteration object. - * - * @param {*} value - * @param {boolean} done - * @return {object} - */ - function createIterResultObject(value, done) { - return {value, done}; - } - - // Are we in a legit ES5 environment. Spoiler alert: that doesn't include IE8. - const isES5 = (function() { - try { - Object.defineProperty({}, 'x', {}); - return true; - } catch (e) { - return false; - } - })(); - - /** - * Check if an object can be extended. - * - * @param {object|array|function|regexp} o - * @return {boolean} - */ - function isExtensible(o) { - if (!isES5) { - return true; - } else { - return Object.isExtensible(o); - } - } - - const getHash = (function() { - const propIsEnumerable = Object.prototype.propertyIsEnumerable; - const hashProperty = '__MAP_POLYFILL_INTERNAL_HASH__'; - let hashCounter = 0; - - const nonExtensibleObjects = []; - const nonExtensibleHashes = []; - - /** - * Get the "hash" associated with an object. - * - * @param {object|array|function|regexp} o - * @return {number} - */ - return function getHash(o) { - if (hasOwn.call(o, hashProperty)) { - return o[hashProperty]; - } - - if (!isES5) { - if ( - hasOwn.call(o, 'propertyIsEnumerable') && - hasOwn.call(o.propertyIsEnumerable, hashProperty) - ) { - return o.propertyIsEnumerable[hashProperty]; - } - } - - if (isExtensible(o)) { - if (isES5) { - Object.defineProperty(o, hashProperty, { - enumerable: false, - writable: false, - configurable: false, - value: ++hashCounter, - }); - return hashCounter; - } - - if (o.propertyIsEnumerable) { - // Since we can't define a non-enumerable property on the object - // we'll hijack one of the less-used non-enumerable properties to - // save our hash on it. Additionally, since this is a function it - // will not show up in `JSON.stringify` which is what we want. - o.propertyIsEnumerable = function() { - return propIsEnumerable.apply(this, arguments); - }; - return (o.propertyIsEnumerable[hashProperty] = ++hashCounter); - } - } - - // If the object is not extensible, fall back to storing it in an - // array and using Array.prototype.indexOf to find it. - let index = nonExtensibleObjects.indexOf(o); - if (index < 0) { - index = nonExtensibleObjects.length; - nonExtensibleObjects[index] = o; - nonExtensibleHashes[index] = ++hashCounter; - } - return nonExtensibleHashes[index]; - }; - })(); - - return Map; -})(Function('return this')()); // eslint-disable-line no-new-func diff --git a/Libraries/vendor/core/Set.js b/Libraries/vendor/core/Set.js deleted file mode 100644 index 564f530b9afd8a..00000000000000 --- a/Libraries/vendor/core/Set.js +++ /dev/null @@ -1,198 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @preventMunge - * @typechecks - */ - -/* eslint-disable no-extend-native */ - -'use strict'; - -const Map = require('./Map'); - -const _shouldPolyfillES6Collection = require('./_shouldPolyfillES6Collection'); -const toIterator = require('./toIterator'); - -module.exports = (function(global) { - // Since our implementation is spec-compliant for the most part we can safely - // delegate to a built-in version if exists and is implemented correctly. - // Firefox had gotten a few implementation details wrong across different - // versions so we guard against that. - // These checks are adapted from es6-shim https://fburl.com/34437854 - if (!_shouldPolyfillES6Collection('Set')) { - return global.Set; - } - - /** - * == ES6 Set Collection == - * - * This module is meant to implement a Set collection as described in chapter - * 23.2 of the ES6 specification. - * - * Set objects are collections of unique values. Where values can be any - * JavaScript value. - * https://people.mozilla.org/~jorendorff/es6-draft.html#sec-map-objects - * - * There only two -- rather small -- diviations from the spec: - * - * 1. The use of frozen objects as keys. @see Map module for more on this. - * - * 2. The `size` property on a map object is a regular property and not a - * computed property on the prototype as described by the spec. - * The reason being is that we simply want to support ES3 environments - * which doesn't implement computed properties. - * - * == Usage == - * - * var set = new set(iterable); - * - * set.set(value); - * set.has(value); // true - * set.delete(value); // true - * - * var iterator = set.keys(); - * iterator.next(); // {value: value, done: false} - * - * var iterator = set.values(); - * iterator.next(); // {value: value, done: false} - * - * var iterator = set.entries(); - * iterator.next(); // {value: [value, value], done: false} - * - * set.forEach(function(value, value){ this === thisArg }, thisArg); - * - * set.clear(); // resets set. - */ - - class Set { - /** - * 23.2.1.1 - * - * Takes an optional `iterable` (which is basically any object that - * implements a Symbol.iterator (@@iterator) method). That is a collection - * of values used to instantiate the set. - * - * @param {*} iterable - */ - constructor(iterable) { - if ( - this == null || - (typeof this !== 'object' && typeof this !== 'function') - ) { - throw new TypeError('Wrong set object type.'); - } - - initSet(this); - - if (iterable != null) { - const it = toIterator(iterable); - let next; - while (!(next = it.next()).done) { - this.add(next.value); - } - } - } - - /** - * 23.2.3.1 - * - * If it doesn't already exist in the collection a `value` is added. - * - * @param {*} value - * @return {set} - */ - add(value) { - this._map.set(value, value); - this.size = this._map.size; - return this; - } - - /** - * 23.2.3.2 - * - * Clears the set. - */ - clear() { - initSet(this); - } - - /** - * 23.2.3.4 - * - * Deletes a `value` from the collection if it exists. - * Returns true if the value was found and deleted and false otherwise. - * - * @param {*} value - * @return {boolean} - */ - delete(value) { - const ret = this._map.delete(value); - this.size = this._map.size; - return ret; - } - - /** - * 23.2.3.5 - * - * Returns an iterator over a collection of [value, value] tuples. - */ - entries() { - return this._map.entries(); - } - - /** - * 23.2.3.6 - * - * Iterate over the collection calling `callback` with (value, value, set). - * - * @param {function} callback - */ - forEach(callback) { - const thisArg = arguments[1]; - const it = this._map.keys(); - let next; - while (!(next = it.next()).done) { - callback.call(thisArg, next.value, next.value, this); - } - } - - /** - * 23.2.3.7 - * - * Iterate over the collection calling `callback` with (value, value, set). - * - * @param {*} value - * @return {boolean} - */ - has(value) { - return this._map.has(value); - } - - /** - * 23.2.3.7 - * - * Returns an iterator over the colleciton of values. - */ - values() { - return this._map.values(); - } - } - - // 23.2.3.11 - Set.prototype[toIterator.ITERATOR_SYMBOL] = Set.prototype.values; - - // 23.2.3.7 - Set.prototype.keys = Set.prototype.values; - - function initSet(set) { - set._map = new Map(); - set.size = set._map.size; - } - - return Set; -})(Function('return this')()); // eslint-disable-line no-new-func diff --git a/Libraries/vendor/core/_shouldPolyfillES6Collection.js b/Libraries/vendor/core/_shouldPolyfillES6Collection.js deleted file mode 100644 index 1ba893c5aebdbe..00000000000000 --- a/Libraries/vendor/core/_shouldPolyfillES6Collection.js +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @preventMunge - * @flow strict - */ - -'use strict'; - -/** - * Checks whether a collection name (e.g. "Map" or "Set") has a native polyfill - * that is safe to be used. - */ -function _shouldActuallyPolyfillES6Collection(collectionName: string): boolean { - const Collection = global[collectionName]; - if (Collection == null) { - return true; - } - - // The iterator protocol depends on `Symbol.iterator`. If a collection is - // implemented, but `Symbol` is not, it's going to break iteration because - // we'll be using custom "@@iterator" instead, which is not implemented on - // native collections. - if (typeof global.Symbol !== 'function') { - return true; - } - - const proto = Collection.prototype; - - // These checks are adapted from es6-shim: https://fburl.com/34437854 - // NOTE: `isCallableWithoutNew` and `!supportsSubclassing` are not checked - // because they make debugging with "break on exceptions" difficult. - return ( - Collection == null || - typeof Collection !== 'function' || - typeof proto.clear !== 'function' || - new Collection().size !== 0 || - typeof proto.keys !== 'function' || - typeof proto.forEach !== 'function' - ); -} - -const cache: {[name: string]: boolean} = {}; - -/** - * Checks whether a collection name (e.g. "Map" or "Set") has a native polyfill - * that is safe to be used and caches this result. - * Make sure to make a first call to this function before a corresponding - * property on global was overriden in any way. - */ -function _shouldPolyfillES6Collection(collectionName: string) { - let result = cache[collectionName]; - if (result !== undefined) { - return result; - } - - result = _shouldActuallyPolyfillES6Collection(collectionName); - cache[collectionName] = result; - return result; -} - -module.exports = _shouldPolyfillES6Collection; diff --git a/flow/Map.js b/flow/Map.js deleted file mode 100644 index c8e830529798ff..00000000000000 --- a/flow/Map.js +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow strict - * @format - */ - -// These annotations are copy/pasted from the built-in Flow definitions for -// Native Map. - -declare module 'Map' { - // Use the name "MapPolyfill" so that we don't get confusing error - // messages about "Using Map instead of Map". - declare class MapPolyfill { - @@iterator(): Iterator<[K, V]>; - constructor(_: void): MapPolyfill; - constructor(_: null): MapPolyfill; - constructor( - iterable: Iterable<[Key, Value]>, - ): MapPolyfill; - clear(): void; - delete(key: K): boolean; - entries(): Iterator<[K, V]>; - forEach( - callbackfn: (value: V, index: K, map: MapPolyfill) => mixed, - thisArg?: any, - ): void; - get(key: K): V | void; - has(key: K): boolean; - keys(): Iterator; - set(key: K, value: V): MapPolyfill; - size: number; - values(): Iterator; - } - - declare module.exports: typeof MapPolyfill; -} diff --git a/flow/Set.js b/flow/Set.js deleted file mode 100644 index 64099c2a6028c3..00000000000000 --- a/flow/Set.js +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow strict - * @nolint - * @format - */ - -// These annotations are copy/pasted from the built-in Flow definitions for -// Native Set. - -declare module 'Set' { - // Use the name "SetPolyfill" so that we don't get confusing error - // messages about "Using Set instead of Set". - declare class SetPolyfill { - @@iterator(): Iterator; - constructor(iterable: ?Iterable): void; - add(value: T): SetPolyfill; - clear(): void; - delete(value: T): boolean; - entries(): Iterator<[T, T]>; - forEach( - callbackfn: (value: T, index: T, set: SetPolyfill) => mixed, - thisArg?: any, - ): void; - has(value: T): boolean; - keys(): Iterator; - size: number; - values(): Iterator; - } - - declare module.exports: typeof SetPolyfill; -} From 67e589ce06449f690017079dbbcf2a2a93eff239 Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Thu, 6 Jun 2019 03:00:04 -0700 Subject: [PATCH 0217/1084] Move NetInfo Android files to FB internal Summary: This moves the Android related files to FB internal and moves the BUCK deps around. Reviewed By: fkgozali Differential Revision: D15392573 fbshipit-source-id: 251d2766729ed42a6fe312b3ab9c6b8f1a8c46d1 --- .../com/facebook/react/modules/netinfo/BUCK | 26 -- .../react/modules/netinfo/NetInfoModule.java | 268 ------------------ .../main/java/com/facebook/react/shell/BUCK | 1 - .../react/shell/MainReactPackage.java | 10 - 4 files changed, 305 deletions(-) delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/BUCK delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/NetInfoModule.java diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/BUCK deleted file mode 100644 index fc907537682617..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/BUCK +++ /dev/null @@ -1,26 +0,0 @@ -load("//tools/build_defs/oss:rn_defs.bzl", "react_native_dep", "react_native_target", "rn_android_library") - -rn_android_library( - name = "netinfo", - srcs = glob(["**/*.java"]), - is_androidx = True, - provided_deps = [ - react_native_dep("third-party/android/androidx:annotation"), - react_native_dep("third-party/android/androidx:core"), - react_native_dep("third-party/android/androidx:fragment"), - react_native_dep("third-party/android/androidx:legacy-support-core-ui"), - react_native_dep("third-party/android/androidx:legacy-support-core-utils"), - ], - visibility = [ - "PUBLIC", - ], - deps = [ - react_native_dep("libraries/fbcore/src/main/java/com/facebook/common/logging:logging"), - react_native_dep("third-party/java/infer-annotations:infer-annotations"), - react_native_dep("third-party/java/jsr-305:jsr-305"), - react_native_target("java/com/facebook/react/bridge:bridge"), - react_native_target("java/com/facebook/react/common:common"), - react_native_target("java/com/facebook/react/module/annotations:annotations"), - react_native_target("java/com/facebook/react/modules/core:core"), - ], -) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/NetInfoModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/NetInfoModule.java deleted file mode 100644 index 56a953d06c4ec7..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/netinfo/NetInfoModule.java +++ /dev/null @@ -1,268 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react.modules.netinfo; - -import android.annotation.SuppressLint; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; -import androidx.core.net.ConnectivityManagerCompat; -import android.telephony.TelephonyManager; - -import com.facebook.react.bridge.LifecycleEventListener; -import com.facebook.react.bridge.Promise; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.ReactContextBaseJavaModule; -import com.facebook.react.bridge.ReactMethod; -import com.facebook.react.bridge.WritableMap; -import com.facebook.react.bridge.WritableNativeMap; -import com.facebook.react.module.annotations.ReactModule; - -import static com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter; - -/** - * Module that monitors and provides information about the connectivity state of the device. - */ -@SuppressLint("MissingPermission") -@ReactModule(name = NetInfoModule.NAME) -public class NetInfoModule extends ReactContextBaseJavaModule - implements LifecycleEventListener { - - // Based on the ConnectionType enum described in the W3C Network Information API spec - // (https://wicg.github.io/netinfo/). - private static final String CONNECTION_TYPE_BLUETOOTH = "bluetooth"; - private static final String CONNECTION_TYPE_CELLULAR = "cellular"; - private static final String CONNECTION_TYPE_ETHERNET = "ethernet"; - private static final String CONNECTION_TYPE_NONE = "none"; - private static final String CONNECTION_TYPE_UNKNOWN = "unknown"; - private static final String CONNECTION_TYPE_WIFI = "wifi"; - private static final String CONNECTION_TYPE_WIMAX = "wimax"; - - // Based on the EffectiveConnectionType enum described in the W3C Network Information API spec - // (https://wicg.github.io/netinfo/). - private static final String EFFECTIVE_CONNECTION_TYPE_UNKNOWN = "unknown"; - private static final String EFFECTIVE_CONNECTION_TYPE_2G = "2g"; - private static final String EFFECTIVE_CONNECTION_TYPE_3G = "3g"; - private static final String EFFECTIVE_CONNECTION_TYPE_4G = "4g"; - - private static final String CONNECTION_TYPE_NONE_DEPRECATED = "NONE"; - private static final String CONNECTION_TYPE_UNKNOWN_DEPRECATED = "UNKNOWN"; - - private static final String MISSING_PERMISSION_MESSAGE = - "To use NetInfo on Android, add the following to your AndroidManifest.xml:\n" + - ""; - - private static final String ERROR_MISSING_PERMISSION = "E_MISSING_PERMISSION"; - public static final String NAME = "NetInfo"; - - private final ConnectivityManager mConnectivityManager; - private final ConnectivityBroadcastReceiver mConnectivityBroadcastReceiver; - private boolean mNoNetworkPermission = false; - - private String mConnectivityDeprecated = CONNECTION_TYPE_UNKNOWN_DEPRECATED; - private String mConnectionType = CONNECTION_TYPE_UNKNOWN; - private String mEffectiveConnectionType = EFFECTIVE_CONNECTION_TYPE_UNKNOWN; - - public NetInfoModule(ReactApplicationContext reactContext) { - super(reactContext); - mConnectivityManager = - (ConnectivityManager) reactContext.getSystemService(Context.CONNECTIVITY_SERVICE); - mConnectivityBroadcastReceiver = new ConnectivityBroadcastReceiver(); - } - - @Override - public void onHostResume() { - registerReceiver(); - } - - @Override - public void onHostPause() { - unregisterReceiver(); - } - - @Override - public void onHostDestroy() { - } - - @Override - public void initialize() { - getReactApplicationContext().addLifecycleEventListener(this); - } - - @Override - public String getName() { - return NAME; - } - - @ReactMethod - public void getCurrentConnectivity(Promise promise) { - if (mNoNetworkPermission) { - promise.reject(ERROR_MISSING_PERMISSION, MISSING_PERMISSION_MESSAGE); - return; - } - promise.resolve(createConnectivityEventMap()); - } - - @ReactMethod - public void isConnectionMetered(Promise promise) { - if (mNoNetworkPermission) { - promise.reject(ERROR_MISSING_PERMISSION, MISSING_PERMISSION_MESSAGE); - return; - } - promise.resolve(ConnectivityManagerCompat.isActiveNetworkMetered(mConnectivityManager)); - } - - private void registerReceiver() { - IntentFilter filter = new IntentFilter(); - filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); - getReactApplicationContext().registerReceiver(mConnectivityBroadcastReceiver, filter); - mConnectivityBroadcastReceiver.setRegistered(true); - updateAndSendConnectionType(); - } - - private void unregisterReceiver() { - if (mConnectivityBroadcastReceiver.isRegistered()) { - getReactApplicationContext().unregisterReceiver(mConnectivityBroadcastReceiver); - mConnectivityBroadcastReceiver.setRegistered(false); - } - } - - private void updateAndSendConnectionType() { - String connectionType = CONNECTION_TYPE_UNKNOWN; - String effectiveConnectionType = EFFECTIVE_CONNECTION_TYPE_UNKNOWN; - - try { - NetworkInfo networkInfo = mConnectivityManager.getActiveNetworkInfo(); - if (networkInfo == null || !networkInfo.isConnected()) { - connectionType = CONNECTION_TYPE_NONE; - } else { - int networkType = networkInfo.getType(); - switch (networkType) { - case ConnectivityManager.TYPE_BLUETOOTH: - connectionType = CONNECTION_TYPE_BLUETOOTH; - break; - case ConnectivityManager.TYPE_ETHERNET: - connectionType = CONNECTION_TYPE_ETHERNET; - break; - case ConnectivityManager.TYPE_MOBILE: - case ConnectivityManager.TYPE_MOBILE_DUN: - connectionType = CONNECTION_TYPE_CELLULAR; - effectiveConnectionType = getEffectiveConnectionType(networkInfo); - break; - case ConnectivityManager.TYPE_WIFI: - connectionType = CONNECTION_TYPE_WIFI; - break; - case ConnectivityManager.TYPE_WIMAX: - connectionType = CONNECTION_TYPE_WIMAX; - break; - default: - connectionType = CONNECTION_TYPE_UNKNOWN; - break; - } - } - } catch (SecurityException e) { - mNoNetworkPermission = true; - connectionType = CONNECTION_TYPE_UNKNOWN; - } - - String currentConnectivity = getCurrentConnectionType(); - // It is possible to get multiple broadcasts for the same connectivity change, so we only - // update and send an event when the connectivity has indeed changed. - if (!connectionType.equalsIgnoreCase(mConnectionType) || - !effectiveConnectionType.equalsIgnoreCase(mEffectiveConnectionType) || - !currentConnectivity.equalsIgnoreCase(mConnectivityDeprecated)) { - mConnectionType = connectionType; - mEffectiveConnectionType = effectiveConnectionType; - mConnectivityDeprecated = currentConnectivity; - sendConnectivityChangedEvent(); - } - } - - private String getCurrentConnectionType() { - try { - NetworkInfo networkInfo = mConnectivityManager.getActiveNetworkInfo(); - if (networkInfo == null || !networkInfo.isConnected()) { - return CONNECTION_TYPE_NONE_DEPRECATED; - } else if (ConnectivityManager.isNetworkTypeValid(networkInfo.getType())) { - return networkInfo.getTypeName().toUpperCase(); - } else { - return CONNECTION_TYPE_UNKNOWN_DEPRECATED; - } - } catch (SecurityException e) { - mNoNetworkPermission = true; - return CONNECTION_TYPE_UNKNOWN_DEPRECATED; - } - } - - private String getEffectiveConnectionType(NetworkInfo networkInfo) { - switch (networkInfo.getSubtype()) { - case TelephonyManager.NETWORK_TYPE_1xRTT: - case TelephonyManager.NETWORK_TYPE_CDMA: - case TelephonyManager.NETWORK_TYPE_EDGE: - case TelephonyManager.NETWORK_TYPE_GPRS: - case TelephonyManager.NETWORK_TYPE_IDEN: - return EFFECTIVE_CONNECTION_TYPE_2G; - case TelephonyManager.NETWORK_TYPE_EHRPD: - case TelephonyManager.NETWORK_TYPE_EVDO_0: - case TelephonyManager.NETWORK_TYPE_EVDO_A: - case TelephonyManager.NETWORK_TYPE_EVDO_B: - case TelephonyManager.NETWORK_TYPE_HSDPA: - case TelephonyManager.NETWORK_TYPE_HSPA: - case TelephonyManager.NETWORK_TYPE_HSUPA: - case TelephonyManager.NETWORK_TYPE_UMTS: - return EFFECTIVE_CONNECTION_TYPE_3G; - case TelephonyManager.NETWORK_TYPE_HSPAP: - case TelephonyManager.NETWORK_TYPE_LTE: - return EFFECTIVE_CONNECTION_TYPE_4G; - case TelephonyManager.NETWORK_TYPE_UNKNOWN: - default: - return EFFECTIVE_CONNECTION_TYPE_UNKNOWN; - } - } - - private void sendConnectivityChangedEvent() { - getReactApplicationContext().getJSModule(RCTDeviceEventEmitter.class) - .emit("networkStatusDidChange", createConnectivityEventMap()); - } - - private WritableMap createConnectivityEventMap() { - WritableMap event = new WritableNativeMap(); - event.putString("network_info", mConnectivityDeprecated); - event.putString("connectionType", mConnectionType); - event.putString("effectiveConnectionType", mEffectiveConnectionType); - return event; - } - - /** - * Class that receives intents whenever the connection type changes. - * NB: It is possible on some devices to receive certain connection type changes multiple times. - */ - private class ConnectivityBroadcastReceiver extends BroadcastReceiver { - - //TODO: Remove registered check when source of crash is found. t9846865 - private boolean isRegistered = false; - - public void setRegistered(boolean registered) { - isRegistered = registered; - } - - public boolean isRegistered() { - return isRegistered; - } - - @Override - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) { - updateAndSendConnectionType(); - } - } - } -} diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK b/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK index fc134a5af2d35d..ddd632a1b4f12d 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK @@ -38,7 +38,6 @@ rn_android_library( react_native_target("java/com/facebook/react/modules/i18nmanager:i18nmanager"), react_native_target("java/com/facebook/react/modules/image:image"), react_native_target("java/com/facebook/react/modules/intent:intent"), - react_native_target("java/com/facebook/react/modules/netinfo:netinfo"), react_native_target("java/com/facebook/react/modules/network:network"), react_native_target("java/com/facebook/react/modules/permissions:permissions"), react_native_target("java/com/facebook/react/modules/share:share"), diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java index 3d1c17ae4dce3a..cf1f81113f8028 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java +++ b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java @@ -28,7 +28,6 @@ import com.facebook.react.modules.i18nmanager.I18nManagerModule; import com.facebook.react.modules.image.ImageLoaderModule; import com.facebook.react.modules.intent.IntentModule; -import com.facebook.react.modules.netinfo.NetInfoModule; import com.facebook.react.modules.network.NetworkingModule; import com.facebook.react.modules.permissions.PermissionsModule; import com.facebook.react.modules.share.ShareModule; @@ -87,7 +86,6 @@ IntentModule.class, NativeAnimatedModule.class, NetworkingModule.class, - NetInfoModule.class, PermissionsModule.class, ShareModule.class, StatusBarModule.class, @@ -251,14 +249,6 @@ public NativeModule get() { return new NetworkingModule(context); } }), - ModuleSpec.nativeModuleSpec( - NetInfoModule.class, - new Provider() { - @Override - public NativeModule get() { - return new NetInfoModule(context); - } - }), ModuleSpec.nativeModuleSpec( PermissionsModule.class, new Provider() { From 831f5fe210a3ffd827a8ab64bc868456df971397 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Thu, 6 Jun 2019 04:04:59 -0700 Subject: [PATCH 0218/1084] Fixes race condition of Network module (#25156) Summary: There exists race condition in `sendRequest:withDelegate:` method, it can do the session creation multiple times, because we don't lock that, which would leads `EXC_BAD_ACCESS` because use and deallocated session concurrently, we can refer to how to create a singleton safely. Related https://github.com/facebook/react-native/issues/25152. ## Changelog [iOS] [Fixed] - Fixes race condition of Network module Pull Request resolved: https://github.com/facebook/react-native/pull/25156 Differential Revision: D15671734 Pulled By: sammy-SC fbshipit-source-id: 5021e6cf33c2b55e3f7adf573ab5c8e6a8d82e23 --- Libraries/Network/RCTHTTPRequestHandler.mm | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/Libraries/Network/RCTHTTPRequestHandler.mm b/Libraries/Network/RCTHTTPRequestHandler.mm index 76131fa69f7797..9a555fab4e205c 100644 --- a/Libraries/Network/RCTHTTPRequestHandler.mm +++ b/Libraries/Network/RCTHTTPRequestHandler.mm @@ -29,12 +29,12 @@ @implementation RCTHTTPRequestHandler - (void)invalidate { - dispatch_async(self->_methodQueue, ^{ - [self->_session invalidateAndCancel]; - self->_session = nil; - }); + std::lock_guard lock(_mutex); + [self->_session invalidateAndCancel]; + self->_session = nil; } +// Needs to lock before call this method. - (BOOL)isValid { // if session == nil and delegates != nil, we've been invalidated @@ -58,6 +58,7 @@ - (BOOL)canHandleRequest:(NSURLRequest *)request - (NSURLSessionDataTask *)sendRequest:(NSURLRequest *)request withDelegate:(id)delegate { + std::lock_guard lock(_mutex); // Lazy setup if (!_session && [self isValid]) { // You can override default NSURLSession instance property allowsCellularAccess (default value YES) @@ -83,19 +84,12 @@ - (NSURLSessionDataTask *)sendRequest:(NSURLRequest *)request delegate:self delegateQueue:callbackQueue]; - std::lock_guard lock(_mutex); _delegates = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsStrongMemory capacity:0]; } - __block NSURLSessionDataTask *task = nil; - dispatch_sync(self->_methodQueue, ^{ - task = [self->_session dataTaskWithRequest:request]; - }); - { - std::lock_guard lock(_mutex); - [_delegates setObject:delegate forKey:task]; - } + NSURLSessionDataTask *task = [_session dataTaskWithRequest:request]; + [_delegates setObject:delegate forKey:task]; [task resume]; return task; } From 417e191a1cfd6a049d1d4b0a511f87aa7f176082 Mon Sep 17 00:00:00 2001 From: Brian Zhao Date: Thu, 6 Jun 2019 04:24:12 -0700 Subject: [PATCH 0219/1084] Correctly bypass sync calls in UIManager during remote debugging (#25162) Summary: Remote debugging stopped working (since 0.58, according to #23254). See https://github.com/facebook/react-native/issues/23254#issuecomment-474692753 for repro steps. The root cause is incorrect checks for Chrome debugging environment in `UIManager.js`. - In one place where sync function `lazilyLoadView` should be avoided, we effectively use `if (__DEV__ && !global.nativeCallSyncHook)` to check remote debugging, which misses ship flavor (i.e. `__DEV__` is false). - In another place where we want to pre-populate view managers' constants to avoid calling sync function `getConstantsForViewManager`, `if (__DEV__)` is used, also missing ship flavor. This PR fixes both checks, only using the absense of `global.nativeCallSyncHook` to determine remote debugging environments. ## Changelog [JavaScript] [Fixed] - Correctly bypass sync calls in UIManager during remote debugging Pull Request resolved: https://github.com/facebook/react-native/pull/25162 Differential Revision: D15692492 Pulled By: cpojer fbshipit-source-id: 173b688f140916b767fcdbbaaf68a5c303adbcd1 --- Libraries/ReactNative/UIManager.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Libraries/ReactNative/UIManager.js b/Libraries/ReactNative/UIManager.js index e7dd0691724881..19dfa44853a16e 100644 --- a/Libraries/ReactNative/UIManager.js +++ b/Libraries/ReactNative/UIManager.js @@ -78,10 +78,8 @@ const UIManagerJS: UIManagerJSInterface = { // If we're in the Chrome Debugger, let's not even try calling the sync // method. - if (__DEV__) { - if (!global.nativeCallSyncHook) { - return config; - } + if (!global.nativeCallSyncHook) { + return config; } if ( @@ -182,7 +180,7 @@ if (Platform.OS === 'ios') { } } -if (__DEV__) { +if (!global.nativeCallSyncHook) { Object.keys(getConstants()).forEach(viewManagerName => { if (!UIManagerProperties.includes(viewManagerName)) { if (!viewManagerConfigs[viewManagerName]) { From bdc530b9bbf6099563d64fb573c4e6cbc93f9c5d Mon Sep 17 00:00:00 2001 From: Mikael Sand Date: Thu, 6 Jun 2019 04:48:32 -0700 Subject: [PATCH 0220/1084] Fix connection of animated nodes and scroll offset with useNativeDriver. (#24177) Summary: Add example showing regression before this fix is applied. https://github.com/facebook/react-native/pull/18187 Was found to introduce a regression in some internal facebook code-base end to end test which couldn't be shared. I was able to create a reproducible demo of a regression I found, and made a fix for it. Hopefully this will fix the internal test, such that the pr can stay merged. ## Changelog [GENERAL] [Fixed] - Fix connection of animated nodes and scroll offset with useNativeDriver. Pull Request resolved: https://github.com/facebook/react-native/pull/24177 Reviewed By: rickhanlonii Differential Revision: D14845617 Pulled By: cpojer fbshipit-source-id: 1f121dbe773b0cde2adf1ee5a8c3c0266034e50d --- .../Animated/src/NativeAnimatedHelper.js | 25 +++- .../Animated/src/animations/Animation.js | 2 + .../src/nodes/AnimatedInterpolation.js | 11 +- Libraries/Animated/src/nodes/AnimatedNode.js | 2 +- Libraries/Animated/src/nodes/AnimatedProps.js | 1 + Libraries/Animated/src/nodes/AnimatedStyle.js | 4 +- .../Nodes/RCTInterpolationAnimatedNode.m | 110 +++++++++++++++++- .../Nodes/RCTPropsAnimatedNode.m | 9 +- .../Nodes/RCTValueAnimatedNode.h | 1 + .../ScrollView/ScrollViewAnimatedExample.js | 103 ++++++++++++++++ RNTester/js/utils/RNTesterList.android.js | 4 + RNTester/js/utils/RNTesterList.ios.js | 5 + .../animated/InterpolationAnimatedNode.java | 98 +++++++++++++++- .../react/animated/PropsAnimatedNode.java | 7 +- .../react/animated/ValueAnimatedNode.java | 5 + 15 files changed, 366 insertions(+), 21 deletions(-) create mode 100644 RNTester/js/examples/ScrollView/ScrollViewAnimatedExample.js diff --git a/Libraries/Animated/src/NativeAnimatedHelper.js b/Libraries/Animated/src/NativeAnimatedHelper.js index a5352046fbbf9f..2128123963a837 100644 --- a/Libraries/Animated/src/NativeAnimatedHelper.js +++ b/Libraries/Animated/src/NativeAnimatedHelper.js @@ -27,11 +27,25 @@ let __nativeAnimationIdCount = 1; /* used for started animations */ let nativeEventEmitter; +let queueConnections = false; +let queue = []; + /** * Simple wrappers around NativeAnimatedModule to provide flow and autocmplete support for * the native module methods */ const API = { + enableQueue: function(): void { + queueConnections = true; + }, + disableQueue: function(): void { + invariant(NativeAnimatedModule, 'Native animated module is not available'); + queueConnections = false; + while (queue.length) { + const args = queue.shift(); + NativeAnimatedModule.connectAnimatedNodes(args[0], args[1]); + } + }, createAnimatedNode: function(tag: ?number, config: AnimatedNodeConfig): void { invariant(NativeAnimatedModule, 'Native animated module is not available'); NativeAnimatedModule.createAnimatedNode(tag, config); @@ -46,6 +60,10 @@ const API = { }, connectAnimatedNodes: function(parentTag: ?number, childTag: ?number): void { invariant(NativeAnimatedModule, 'Native animated module is not available'); + if (queueConnections) { + queue.push([parentTag, childTag]); + return; + } NativeAnimatedModule.connectAnimatedNodes(parentTag, childTag); }, disconnectAnimatedNodes: function( @@ -197,7 +215,7 @@ function addWhitelistedInterpolationParam(param: string): void { function validateTransform( configs: Array< | {type: 'animated', property: string, nodeTag: ?number} - | {type: 'static', property: string, value: number}, + | {type: 'static', property: string, value: number | string}, >, ): void { configs.forEach(config => { @@ -263,7 +281,7 @@ function shouldUseNativeDriver(config: AnimationConfig | EventConfig): boolean { return config.useNativeDriver || false; } -function transformDataType(value: number | string): number { +function transformDataType(value: number | string): number | string { // Change the string type to number type so we can reuse the same logic in // iOS and Android platform if (typeof value !== 'string') { @@ -274,8 +292,7 @@ function transformDataType(value: number | string): number { const radians = (degrees * Math.PI) / 180.0; return radians; } else { - // Assume radians - return parseFloat(value) || 0; + return value; } } diff --git a/Libraries/Animated/src/animations/Animation.js b/Libraries/Animated/src/animations/Animation.js index 32ccb1e72f0832..24482d22b7ccfc 100644 --- a/Libraries/Animated/src/animations/Animation.js +++ b/Libraries/Animated/src/animations/Animation.js @@ -56,7 +56,9 @@ class Animation { onEnd && onEnd(result); } __startNativeAnimation(animatedValue: AnimatedValue): void { + NativeAnimatedHelper.API.enableQueue(); animatedValue.__makeNative(); + NativeAnimatedHelper.API.disableQueue(); this.__nativeId = NativeAnimatedHelper.generateNewAnimationId(); NativeAnimatedHelper.API.startAnimatingNode( this.__nativeId, diff --git a/Libraries/Animated/src/nodes/AnimatedInterpolation.js b/Libraries/Animated/src/nodes/AnimatedInterpolation.js index d4df33a2f7d5e2..19387984ccf64b 100644 --- a/Libraries/Animated/src/nodes/AnimatedInterpolation.js +++ b/Libraries/Animated/src/nodes/AnimatedInterpolation.js @@ -181,7 +181,7 @@ function colorToRgba(input: string): string { return `rgba(${r}, ${g}, ${b}, ${a})`; } -const stringShapeRegex = /[0-9\.-]+/g; +const stringShapeRegex = /[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?/g; /** * Supports string shapes by extracting numbers so new values can be computed, @@ -242,10 +242,11 @@ function createInterpolationFromStringOutputRange( // -> // 'rgba(${interpolations[0](input)}, ${interpolations[1](input)}, ...' return outputRange[0].replace(stringShapeRegex, () => { - const val = +interpolations[i++](input); - const rounded = - shouldRound && i < 4 ? Math.round(val) : Math.round(val * 1000) / 1000; - return String(rounded); + let val = +interpolations[i++](input); + if (shouldRound) { + val = i < 4 ? Math.round(val) : Math.round(val * 1000) / 1000; + } + return String(val); }); }; } diff --git a/Libraries/Animated/src/nodes/AnimatedNode.js b/Libraries/Animated/src/nodes/AnimatedNode.js index b90b4c185b8ec6..f6bb39648a80fe 100644 --- a/Libraries/Animated/src/nodes/AnimatedNode.js +++ b/Libraries/Animated/src/nodes/AnimatedNode.js @@ -157,11 +157,11 @@ class AnimatedNode { ); if (this.__nativeTag == null) { const nativeTag: ?number = NativeAnimatedHelper.generateNewNodeTag(); + this.__nativeTag = nativeTag; NativeAnimatedHelper.API.createAnimatedNode( nativeTag, this.__getNativeConfig(), ); - this.__nativeTag = nativeTag; this.__shouldUpdateListenersForNewNativeTag = true; } return this.__nativeTag; diff --git a/Libraries/Animated/src/nodes/AnimatedProps.js b/Libraries/Animated/src/nodes/AnimatedProps.js index 23866ed4356aff..d6914d23bd8a31 100644 --- a/Libraries/Animated/src/nodes/AnimatedProps.js +++ b/Libraries/Animated/src/nodes/AnimatedProps.js @@ -151,6 +151,7 @@ class AnimatedProps extends AnimatedNode { for (const propKey in this._props) { const value = this._props[propKey]; if (value instanceof AnimatedNode) { + value.__makeNative(); propsConfig[propKey] = value.__getNativeTag(); } } diff --git a/Libraries/Animated/src/nodes/AnimatedStyle.js b/Libraries/Animated/src/nodes/AnimatedStyle.js index 4830b2e8d0c1a4..1219bda5962fa4 100644 --- a/Libraries/Animated/src/nodes/AnimatedStyle.js +++ b/Libraries/Animated/src/nodes/AnimatedStyle.js @@ -108,7 +108,9 @@ class AnimatedStyle extends AnimatedWithChildren { const styleConfig = {}; for (const styleKey in this._style) { if (this._style[styleKey] instanceof AnimatedNode) { - styleConfig[styleKey] = this._style[styleKey].__getNativeTag(); + const style = this._style[styleKey]; + style.__makeNative(); + styleConfig[styleKey] = style.__getNativeTag(); } // Non-animated styles are set using `setNativeProps`, no need // to pass those as a part of the node config diff --git a/Libraries/NativeAnimation/Nodes/RCTInterpolationAnimatedNode.m b/Libraries/NativeAnimation/Nodes/RCTInterpolationAnimatedNode.m index 0fbaf57d4b4ac4..1fdadc263d538e 100644 --- a/Libraries/NativeAnimation/Nodes/RCTInterpolationAnimatedNode.m +++ b/Libraries/NativeAnimation/Nodes/RCTInterpolationAnimatedNode.m @@ -9,27 +9,90 @@ #import "RCTAnimationUtils.h" +static NSRegularExpression *regex; + @implementation RCTInterpolationAnimatedNode { __weak RCTValueAnimatedNode *_parentNode; NSArray *_inputRange; NSArray *_outputRange; + NSArray *> *_outputs; + NSArray *_soutputRange; NSString *_extrapolateLeft; NSString *_extrapolateRight; + NSUInteger _numVals; + bool _hasStringOutput; + bool _shouldRound; + NSArray *_matches; } - (instancetype)initWithTag:(NSNumber *)tag config:(NSDictionary *)config { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSString *fpRegex = @"[+-]?(\\d+\\.?\\d*|\\.\\d+)([eE][+-]?\\d+)?"; + regex = [NSRegularExpression regularExpressionWithPattern:fpRegex options:NSRegularExpressionCaseInsensitive error:nil]; + }); if ((self = [super initWithTag:tag config:config])) { _inputRange = [config[@"inputRange"] copy]; NSMutableArray *outputRange = [NSMutableArray array]; + NSMutableArray *soutputRange = [NSMutableArray array]; + NSMutableArray *> *_outputRanges = [NSMutableArray array]; + + _hasStringOutput = NO; for (id value in config[@"outputRange"]) { if ([value isKindOfClass:[NSNumber class]]) { [outputRange addObject:value]; + } else if ([value isKindOfClass:[NSString class]]) { + /** + * Supports string shapes by extracting numbers so new values can be computed, + * and recombines those values into new strings of the same shape. Supports + * things like: + * + * rgba(123, 42, 99, 0.36) // colors + * -45deg // values with units + */ + NSMutableArray *output = [NSMutableArray array]; + [_outputRanges addObject:output]; + [soutputRange addObject:value]; + + _matches = [regex matchesInString:value options:0 range:NSMakeRange(0, [value length])]; + for (NSTextCheckingResult *match in _matches) { + NSString* strNumber = [value substringWithRange:match.range]; + [output addObject:[NSNumber numberWithDouble:strNumber.doubleValue]]; + } + + _hasStringOutput = YES; + [outputRange addObject:[output objectAtIndex:0]]; + } + } + if (_hasStringOutput) { + // ['rgba(0, 100, 200, 0)', 'rgba(50, 150, 250, 0.5)'] + // -> + // [ + // [0, 50], + // [100, 150], + // [200, 250], + // [0, 0.5], + // ] + _numVals = [_matches count]; + NSString *value = [soutputRange objectAtIndex:0]; + _shouldRound = [value containsString:@"rgb"]; + _matches = [regex matchesInString:value options:0 range:NSMakeRange(0, [value length])]; + NSMutableArray *> *outputs = [NSMutableArray arrayWithCapacity:_numVals]; + NSUInteger size = [soutputRange count]; + for (NSUInteger j = 0; j < _numVals; j++) { + NSMutableArray *output = [NSMutableArray arrayWithCapacity:size]; + [outputs addObject:output]; + for (int i = 0; i < size; i++) { + [output addObject:[[_outputRanges objectAtIndex:i] objectAtIndex:j]]; + } } + _outputs = [outputs copy]; } _outputRange = [outputRange copy]; + _soutputRange = [soutputRange copy]; _extrapolateLeft = config[@"extrapolateLeft"]; _extrapolateRight = config[@"extrapolateRight"]; } @@ -61,11 +124,48 @@ - (void)performUpdate CGFloat inputValue = _parentNode.value; - self.value = RCTInterpolateValueInRange(inputValue, - _inputRange, - _outputRange, - _extrapolateLeft, - _extrapolateRight); + CGFloat interpolated = RCTInterpolateValueInRange(inputValue, + _inputRange, + _outputRange, + _extrapolateLeft, + _extrapolateRight); + self.value = interpolated; + if (_hasStringOutput) { + // 'rgba(0, 100, 200, 0)' + // -> + // 'rgba(${interpolations[0](input)}, ${interpolations[1](input)}, ...' + if (_numVals > 1) { + NSString *text = _soutputRange[0]; + NSMutableString *formattedText = [NSMutableString stringWithString:text]; + NSUInteger i = _numVals; + for (NSTextCheckingResult *match in [_matches reverseObjectEnumerator]) { + CGFloat val = RCTInterpolateValueInRange(inputValue, + _inputRange, + _outputs[--i], + _extrapolateLeft, + _extrapolateRight); + NSString *str; + if (_shouldRound) { + // rgba requires that the r,g,b are integers.... so we want to round them, but we *dont* want to + // round the opacity (4th column). + bool isAlpha = i == 3; + CGFloat rounded = isAlpha ? round(val * 1000) / 1000 : round(val); + str = isAlpha ? [NSString stringWithFormat:@"%1.3f", rounded] : [NSString stringWithFormat:@"%1.0f", rounded]; + } else { + NSNumber *numberValue = [NSNumber numberWithDouble:val]; + str = [numberValue stringValue]; + } + + [formattedText replaceCharactersInRange:[match range] withString:str]; + } + self.animatedObject = formattedText; + } else { + self.animatedObject = [regex stringByReplacingMatchesInString:_soutputRange[0] + options:0 + range:NSMakeRange(0, _soutputRange[0].length) + withTemplate:[NSString stringWithFormat:@"%1f", interpolated]]; + } + } } @end diff --git a/Libraries/NativeAnimation/Nodes/RCTPropsAnimatedNode.m b/Libraries/NativeAnimation/Nodes/RCTPropsAnimatedNode.m index 0a9a33434fb461..37f81a148e6821 100644 --- a/Libraries/NativeAnimation/Nodes/RCTPropsAnimatedNode.m +++ b/Libraries/NativeAnimation/Nodes/RCTPropsAnimatedNode.m @@ -115,8 +115,13 @@ - (void)performUpdate } else if ([parentNode isKindOfClass:[RCTValueAnimatedNode class]]) { NSString *property = [self propertyNameForParentTag:parentTag]; - CGFloat value = [(RCTValueAnimatedNode *)parentNode value]; - self->_propsDictionary[property] = @(value); + id animatedObject = [(RCTValueAnimatedNode *)parentNode animatedObject]; + if (animatedObject) { + self->_propsDictionary[property] = animatedObject; + } else { + CGFloat value = [(RCTValueAnimatedNode *)parentNode value]; + self->_propsDictionary[property] = @(value); + } } } diff --git a/Libraries/NativeAnimation/Nodes/RCTValueAnimatedNode.h b/Libraries/NativeAnimation/Nodes/RCTValueAnimatedNode.h index 53b5da3803e51f..c46d392caaac79 100644 --- a/Libraries/NativeAnimation/Nodes/RCTValueAnimatedNode.h +++ b/Libraries/NativeAnimation/Nodes/RCTValueAnimatedNode.h @@ -24,6 +24,7 @@ - (void)extractOffset; @property (nonatomic, assign) CGFloat value; +@property (nonatomic, strong) id animatedObject; @property (nonatomic, weak) id valueObserver; @end diff --git a/RNTester/js/examples/ScrollView/ScrollViewAnimatedExample.js b/RNTester/js/examples/ScrollView/ScrollViewAnimatedExample.js new file mode 100644 index 00000000000000..d69e91ded20659 --- /dev/null +++ b/RNTester/js/examples/ScrollView/ScrollViewAnimatedExample.js @@ -0,0 +1,103 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow + */ + +'use strict'; + +const React = require('react'); +const ReactNative = require('react-native'); +const {Component} = React; +const { + StyleSheet, + Text, + View, + Animated, + Easing, + TouchableOpacity, + Dimensions, +} = ReactNative; + +class ScrollViewAnimatedExample extends Component<{}> { + _scrollViewPos = new Animated.Value(0); + + startAnimation = () => { + this._scrollViewPos.setValue(0); + Animated.timing(this._scrollViewPos, { + toValue: 100, + duration: 10000, + easing: Easing.linear, + useNativeDriver: true, + }).start(); + }; + + render() { + const interpolated = this._scrollViewPos.interpolate({ + inputRange: [0, 1], + outputRange: [0, 0.1], + }); + const interpolated2 = this._scrollViewPos.interpolate({ + inputRange: [0, 1], + outputRange: ['0deg', '1deg'], + }); + return ( + + + + + + Scroll me horizontally + + + + + ); + } +} + +const {width, height} = Dimensions.get('window'); + +const styles = StyleSheet.create({ + container: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + backgroundColor: '#F5FCFF', + }, + button: { + margin: 50, + width: width, + marginRight: width, + height: height / 2, + }, +}); + +exports.title = ''; +exports.description = 'Component that is animated when ScrollView is offset.'; + +exports.examples = [ + { + title: 'Animated by scroll view', + render: function(): React.Element { + return ; + }, + }, +]; diff --git a/RNTester/js/utils/RNTesterList.android.js b/RNTester/js/utils/RNTesterList.android.js index 929d0b78cea949..31c0ffbbad83e7 100644 --- a/RNTester/js/utils/RNTesterList.android.js +++ b/RNTester/js/utils/RNTesterList.android.js @@ -65,6 +65,10 @@ const ComponentExamples: Array = [ key: 'ScrollViewSimpleExample', module: require('../examples/ScrollView/ScrollViewSimpleExample'), }, + { + key: 'ScrollViewAnimatedExample', + module: require('../examples/ScrollView/ScrollViewAnimatedExample'), + }, { key: 'SectionListExample', module: require('../examples/SectionList/SectionListExample'), diff --git a/RNTester/js/utils/RNTesterList.ios.js b/RNTester/js/utils/RNTesterList.ios.js index e5e4de716b544e..2dae203030a76f 100644 --- a/RNTester/js/utils/RNTesterList.ios.js +++ b/RNTester/js/utils/RNTesterList.ios.js @@ -113,6 +113,11 @@ const ComponentExamples: Array = [ module: require('../examples/ScrollView/ScrollViewExample'), supportsTVOS: true, }, + { + key: 'ScrollViewAnimatedExample', + module: require('../examples/ScrollView/ScrollViewAnimatedExample'), + supportsTVOS: true, + }, { key: 'SectionListExample', module: require('../examples/SectionList/SectionListExample'), diff --git a/ReactAndroid/src/main/java/com/facebook/react/animated/InterpolationAnimatedNode.java b/ReactAndroid/src/main/java/com/facebook/react/animated/InterpolationAnimatedNode.java index be2f38c055de42..bc2e08c7adaad8 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/animated/InterpolationAnimatedNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/animated/InterpolationAnimatedNode.java @@ -9,6 +9,12 @@ import com.facebook.react.bridge.JSApplicationIllegalArgumentException; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.bridge.ReadableType; + +import java.util.ArrayList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + import javax.annotation.Nullable; /** @@ -22,6 +28,9 @@ public static final String EXTRAPOLATE_TYPE_CLAMP = "clamp"; public static final String EXTRAPOLATE_TYPE_EXTEND = "extend"; + private static final String fpRegex = "[+-]?(\\d+\\.?\\d*|\\.\\d+)([eE][+-]?\\d+)?"; + private static final Pattern fpPattern = Pattern.compile(fpRegex); + private static double[] fromDoubleArray(ReadableArray ary) { double[] res = new double[ary.size()]; for (int i = 0; i < res.length; i++) { @@ -116,13 +125,68 @@ private static int findRangeIndex(double value, double[] ranges) { private final double mInputRange[]; private final double mOutputRange[]; + private String mPattern; + private double mOutputs[][]; + private final boolean mHasStringOutput; + private final Matcher mSOutputMatcher; private final String mExtrapolateLeft; private final String mExtrapolateRight; private @Nullable ValueAnimatedNode mParent; + private boolean mShouldRound; + private int mNumVals; public InterpolationAnimatedNode(ReadableMap config) { mInputRange = fromDoubleArray(config.getArray("inputRange")); - mOutputRange = fromDoubleArray(config.getArray("outputRange")); + ReadableArray output = config.getArray("outputRange"); + mHasStringOutput = output.getType(0) == ReadableType.String; + if (mHasStringOutput) { + /* + * Supports string shapes by extracting numbers so new values can be computed, + * and recombines those values into new strings of the same shape. Supports + * things like: + * + * rgba(123, 42, 99, 0.36) // colors + * -45deg // values with units + */ + int size = output.size(); + mOutputRange = new double[size]; + mPattern = output.getString(0); + mShouldRound = mPattern.startsWith("rgb"); + mSOutputMatcher = fpPattern.matcher(mPattern); + ArrayList> mOutputRanges = new ArrayList<>(); + for (int i = 0; i < size; i++) { + String val = output.getString(i); + Matcher m = fpPattern.matcher(val); + ArrayList outputRange = new ArrayList<>(); + mOutputRanges.add(outputRange); + while (m.find()) { + Double parsed = Double.parseDouble(m.group()); + outputRange.add(parsed); + } + mOutputRange[i] = outputRange.get(0); + } + + // ['rgba(0, 100, 200, 0)', 'rgba(50, 150, 250, 0.5)'] + // -> + // [ + // [0, 50], + // [100, 150], + // [200, 250], + // [0, 0.5], + // ] + mNumVals = mOutputRanges.get(0).size(); + mOutputs = new double[mNumVals][]; + for (int j = 0; j < mNumVals; j++) { + double[] arr = new double[size]; + mOutputs[j] = arr; + for (int i = 0; i < size; i++) { + arr[i] = mOutputRanges.get(i).get(j); + } + } + } else { + mOutputRange = fromDoubleArray(output); + mSOutputMatcher = null; + } mExtrapolateLeft = config.getString("extrapolateLeft"); mExtrapolateRight = config.getString("extrapolateRight"); } @@ -153,6 +217,36 @@ public void update() { // unattached node. return; } - mValue = interpolate(mParent.getValue(), mInputRange, mOutputRange, mExtrapolateLeft, mExtrapolateRight); + double value = mParent.getValue(); + mValue = interpolate(value, mInputRange, mOutputRange, mExtrapolateLeft, mExtrapolateRight); + if (mHasStringOutput) { + // 'rgba(0, 100, 200, 0)' + // -> + // 'rgba(${interpolations[0](input)}, ${interpolations[1](input)}, ...' + if (mNumVals > 1) { + StringBuffer sb = new StringBuffer(mPattern.length()); + int i = 0; + mSOutputMatcher.reset(); + while (mSOutputMatcher.find()) { + double val = interpolate(value, mInputRange, mOutputs[i++], mExtrapolateLeft, mExtrapolateRight); + if (mShouldRound) { + // rgba requires that the r,g,b are integers.... so we want to round them, but we *dont* want to + // round the opacity (4th column). + boolean isAlpha = i == 4; + int rounded = (int)Math.round(isAlpha ? val * 1000 : val); + String num = isAlpha ? Double.toString((double)rounded / 1000) : Integer.toString(rounded); + mSOutputMatcher.appendReplacement(sb, num); + } else { + int intVal = (int)val; + String num = intVal != val ? Double.toString(val) : Integer.toString(intVal); + mSOutputMatcher.appendReplacement(sb, num); + } + } + mSOutputMatcher.appendTail(sb); + mAnimatedObject = sb.toString(); + } else { + mAnimatedObject = mSOutputMatcher.replaceFirst(String.valueOf(mValue)); + } + } } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/animated/PropsAnimatedNode.java b/ReactAndroid/src/main/java/com/facebook/react/animated/PropsAnimatedNode.java index 250eb21dbc0d9a..7bb7eaaeba2cd9 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/animated/PropsAnimatedNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/animated/PropsAnimatedNode.java @@ -84,7 +84,12 @@ public final void updateView() { } else if (node instanceof StyleAnimatedNode) { ((StyleAnimatedNode) node).collectViewUpdates(mPropMap); } else if (node instanceof ValueAnimatedNode) { - mPropMap.putDouble(entry.getKey(), ((ValueAnimatedNode) node).getValue()); + Object animatedObject = ((ValueAnimatedNode) node).getAnimatedObject(); + if (animatedObject instanceof String) { + mPropMap.putString(entry.getKey(), (String)animatedObject); + } else { + mPropMap.putDouble(entry.getKey(), ((ValueAnimatedNode) node).getValue()); + } } else { throw new IllegalArgumentException("Unsupported type of node used in property node " + node.getClass()); diff --git a/ReactAndroid/src/main/java/com/facebook/react/animated/ValueAnimatedNode.java b/ReactAndroid/src/main/java/com/facebook/react/animated/ValueAnimatedNode.java index 49426c77ebb237..0c92f11f899362 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/animated/ValueAnimatedNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/animated/ValueAnimatedNode.java @@ -16,6 +16,7 @@ * library. */ /*package*/ class ValueAnimatedNode extends AnimatedNode { + /*package*/ Object mAnimatedObject = null; /*package*/ double mValue = Double.NaN; /*package*/ double mOffset = 0; private @Nullable AnimatedNodeValueListener mValueListener; @@ -33,6 +34,10 @@ public double getValue() { return mOffset + mValue; } + public Object getAnimatedObject() { + return mAnimatedObject; + } + public void flattenOffset() { mValue += mOffset; mOffset = 0; From 63bc4b4aac0911086b9818e45dfb3ba5b6181bde Mon Sep 17 00:00:00 2001 From: Felix Oghina Date: Thu, 6 Jun 2019 04:49:51 -0700 Subject: [PATCH 0221/1084] @build-break Back out "[RN] Remove Map/Set from RN Open Source" Summary: Backing out D14786123 as it's causing failures on fbandroid/stable. Differential Revision: D15693250 Ninja: sheriff fbshipit-source-id: 526054d4f0dab2a811f2328540e7418ece9810b1 --- Libraries/Core/InitializeCore.js | 1 + .../Core/__tests__/MapAndSetPolyfills-test.js | 102 +++ Libraries/Core/polyfillES6Collections.js | 27 + Libraries/vendor/core/Map.js | 590 ++++++++++++++++++ Libraries/vendor/core/Set.js | 198 ++++++ .../core/_shouldPolyfillES6Collection.js | 66 ++ flow/Map.js | 40 ++ flow/Set.js | 36 ++ 8 files changed, 1060 insertions(+) create mode 100644 Libraries/Core/__tests__/MapAndSetPolyfills-test.js create mode 100644 Libraries/Core/polyfillES6Collections.js create mode 100644 Libraries/vendor/core/Map.js create mode 100644 Libraries/vendor/core/Set.js create mode 100644 Libraries/vendor/core/_shouldPolyfillES6Collection.js create mode 100644 flow/Map.js create mode 100644 flow/Set.js diff --git a/Libraries/Core/InitializeCore.js b/Libraries/Core/InitializeCore.js index 8b9a6a490739d1..263001547b6132 100644 --- a/Libraries/Core/InitializeCore.js +++ b/Libraries/Core/InitializeCore.js @@ -28,6 +28,7 @@ const start = Date.now(); require('./setUpGlobals'); +require('./polyfillES6Collections'); require('./setUpSystrace'); require('./setUpErrorHandling'); require('./polyfillPromise'); diff --git a/Libraries/Core/__tests__/MapAndSetPolyfills-test.js b/Libraries/Core/__tests__/MapAndSetPolyfills-test.js new file mode 100644 index 00000000000000..20f54a0e68d9d5 --- /dev/null +++ b/Libraries/Core/__tests__/MapAndSetPolyfills-test.js @@ -0,0 +1,102 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @emails oncall+react_native + */ +'use strict'; + +// Save these methods so that we can restore them afterward. +const {freeze, seal, preventExtensions} = Object; + +function setup() { + jest.setMock('../../vendor/core/_shouldPolyfillES6Collection', () => true); +} + +function cleanup() { + Object.assign(Object, {freeze, seal, preventExtensions}); +} + +describe('Map polyfill', () => { + setup(); + + const Map = require('../../vendor/core/Map'); + + it('is not native', () => { + const getCode = Function.prototype.toString.call(Map.prototype.get); + expect(getCode).not.toContain('[native code]'); + expect(getCode).toContain('getIndex'); + }); + + it('should tolerate non-extensible object keys', () => { + const map = new Map(); + const key = Object.create(null); + Object.freeze(key); + map.set(key, key); + expect(map.size).toBe(1); + expect(map.has(key)).toBe(true); + map.delete(key); + expect(map.size).toBe(0); + expect(map.has(key)).toBe(false); + }); + + it('should not get confused by prototypal inheritance', () => { + const map = new Map(); + const proto = Object.create(null); + const base = Object.create(proto); + map.set(proto, proto); + expect(map.size).toBe(1); + expect(map.has(proto)).toBe(true); + expect(map.has(base)).toBe(false); + map.set(base, base); + expect(map.size).toBe(2); + expect(map.get(proto)).toBe(proto); + expect(map.get(base)).toBe(base); + }); + + afterAll(cleanup); +}); + +describe('Set polyfill', () => { + setup(); + + const Set = require('../../vendor/core/Set'); + + it('is not native', () => { + const addCode = Function.prototype.toString.call(Set.prototype.add); + expect(addCode).not.toContain('[native code]'); + }); + + it('should tolerate non-extensible object elements', () => { + const set = new Set(); + const elem = Object.create(null); + Object.freeze(elem); + set.add(elem); + expect(set.size).toBe(1); + expect(set.has(elem)).toBe(true); + set.add(elem); + expect(set.size).toBe(1); + set.delete(elem); + expect(set.size).toBe(0); + expect(set.has(elem)).toBe(false); + }); + + it('should not get confused by prototypal inheritance', () => { + const set = new Set(); + const proto = Object.create(null); + const base = Object.create(proto); + set.add(proto); + expect(set.size).toBe(1); + expect(set.has(proto)).toBe(true); + expect(set.has(base)).toBe(false); + set.add(base); + expect(set.size).toBe(2); + expect(set.has(proto)).toBe(true); + expect(set.has(base)).toBe(true); + }); + + afterAll(cleanup); +}); diff --git a/Libraries/Core/polyfillES6Collections.js b/Libraries/Core/polyfillES6Collections.js new file mode 100644 index 00000000000000..b58718540fedca --- /dev/null +++ b/Libraries/Core/polyfillES6Collections.js @@ -0,0 +1,27 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ +'use strict'; + +const {polyfillGlobal} = require('../Utilities/PolyfillFunctions'); + +/** + * Polyfill ES6 collections (Map and Set). + * If you don't need these polyfills, don't use InitializeCore; just directly + * require the modules you need from InitializeCore for setup. + */ +const _shouldPolyfillCollection = require('../vendor/core/_shouldPolyfillES6Collection'); +if (_shouldPolyfillCollection('Map')) { + // $FlowFixMe: even in strict-local mode Flow expects Map to be Flow-typed + polyfillGlobal('Map', () => require('../vendor/core/Map')); +} +if (_shouldPolyfillCollection('Set')) { + // $FlowFixMe: even in strict-local mode Flow expects Set to be Flow-typed + polyfillGlobal('Set', () => require('../vendor/core/Set')); +} diff --git a/Libraries/vendor/core/Map.js b/Libraries/vendor/core/Map.js new file mode 100644 index 00000000000000..4f23b1f4783ab8 --- /dev/null +++ b/Libraries/vendor/core/Map.js @@ -0,0 +1,590 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @preventMunge + * @typechecks + */ + +/* eslint-disable no-extend-native, no-shadow-restricted-names */ + +'use strict'; + +const _shouldPolyfillES6Collection = require('./_shouldPolyfillES6Collection'); +const guid = require('./guid'); +const toIterator = require('./toIterator'); + +module.exports = (function(global, undefined) { + // Since our implementation is spec-compliant for the most part we can safely + // delegate to a built-in version if exists and is implemented correctly. + // Firefox had gotten a few implementation details wrong across different + // versions so we guard against that. + if (!_shouldPolyfillES6Collection('Map')) { + return global.Map; + } + + const hasOwn = Object.prototype.hasOwnProperty; + + /** + * == ES6 Map Collection == + * + * This module is meant to implement a Map collection as described in chapter + * 23.1 of the ES6 specification. + * + * Map objects are collections of key/value pairs where both the keys and + * values may be arbitrary ECMAScript language values. A distinct key value + * may only occur in one key/value pair within the Map's collection. + * + * https://people.mozilla.org/~jorendorff/es6-draft.html#sec-map-objects + * + * There only two -- rather small -- deviations from the spec: + * + * 1. The use of untagged frozen objects as keys. + * We decided not to allow and simply throw an error, because this + * implementation of Map works by tagging objects used as Map keys + * with a secret hash property for fast access to the object's place + * in the internal _mapData array. However, to limit the impact of + * this spec deviation, Libraries/Core/InitializeCore.js also wraps + * Object.freeze, Object.seal, and Object.preventExtensions so that + * they tag objects before making them non-extensible, by inserting + * each object into a Map and then immediately removing it. + * + * 2. The `size` property on a map object is a regular property and not a + * computed property on the prototype as described by the spec. + * The reason being is that we simply want to support ES3 environments + * which doesn't implement computed properties. + * + * == Usage == + * + * var map = new Map(iterable); + * + * map.set(key, value); + * map.get(key); // value + * map.has(key); // true + * map.delete(key); // true + * + * var iterator = map.keys(); + * iterator.next(); // {value: key, done: false} + * + * var iterator = map.values(); + * iterator.next(); // {value: value, done: false} + * + * var iterator = map.entries(); + * iterator.next(); // {value: [key, value], done: false} + * + * map.forEach(function(value, key){ this === thisArg }, thisArg); + * + * map.clear(); // resets map. + */ + + /** + * Constants + */ + + // Kinds of map iterations 23.1.5.3 + const KIND_KEY = 'key'; + const KIND_VALUE = 'value'; + const KIND_KEY_VALUE = 'key+value'; + + // In older browsers we can't create a null-prototype object so we have to + // defend against key collisions with built-in methods. + const KEY_PREFIX = '$map_'; + + // This property will be used as the internal size variable to disallow + // writing and to issue warnings for writings in development. + let SECRET_SIZE_PROP; + if (__DEV__) { + SECRET_SIZE_PROP = '$size' + guid(); + } + + class Map { + /** + * 23.1.1.1 + * Takes an `iterable` which is basically any object that implements a + * Symbol.iterator (@@iterator) method. The iterable is expected to be a + * collection of pairs. Each pair is a key/value pair that will be used + * to instantiate the map. + * + * @param {*} iterable + */ + constructor(iterable) { + if (!isObject(this)) { + throw new TypeError('Wrong map object type.'); + } + + initMap(this); + + if (iterable != null) { + const it = toIterator(iterable); + let next; + while (!(next = it.next()).done) { + if (!isObject(next.value)) { + throw new TypeError('Expected iterable items to be pair objects.'); + } + this.set(next.value[0], next.value[1]); + } + } + } + + /** + * 23.1.3.1 + * Clears the map from all keys and values. + */ + clear() { + initMap(this); + } + + /** + * 23.1.3.7 + * Check if a key exists in the collection. + * + * @param {*} key + * @return {boolean} + */ + has(key) { + const index = getIndex(this, key); + return !!(index != null && this._mapData[index]); + } + + /** + * 23.1.3.9 + * Adds a key/value pair to the collection. + * + * @param {*} key + * @param {*} value + * @return {map} + */ + set(key, value) { + let index = getIndex(this, key); + + if (index != null && this._mapData[index]) { + this._mapData[index][1] = value; + } else { + index = this._mapData.push([key, value]) - 1; + setIndex(this, key, index); + if (__DEV__) { + this[SECRET_SIZE_PROP] += 1; + } else { + this.size += 1; + } + } + + return this; + } + + /** + * 23.1.3.6 + * Gets a value associated with a key in the collection. + * + * @param {*} key + * @return {*} + */ + get(key) { + const index = getIndex(this, key); + if (index == null) { + return undefined; + } else { + return this._mapData[index][1]; + } + } + + /** + * 23.1.3.3 + * Delete a key/value from the collection. + * + * @param {*} key + * @return {boolean} Whether the key was found and deleted. + */ + delete(key) { + const index = getIndex(this, key); + if (index != null && this._mapData[index]) { + setIndex(this, key, undefined); + this._mapData[index] = undefined; + if (__DEV__) { + this[SECRET_SIZE_PROP] -= 1; + } else { + this.size -= 1; + } + return true; + } else { + return false; + } + } + + /** + * 23.1.3.4 + * Returns an iterator over the key/value pairs (in the form of an Array) in + * the collection. + * + * @return {MapIterator} + */ + entries() { + return new MapIterator(this, KIND_KEY_VALUE); + } + + /** + * 23.1.3.8 + * Returns an iterator over the keys in the collection. + * + * @return {MapIterator} + */ + keys() { + return new MapIterator(this, KIND_KEY); + } + + /** + * 23.1.3.11 + * Returns an iterator over the values pairs in the collection. + * + * @return {MapIterator} + */ + values() { + return new MapIterator(this, KIND_VALUE); + } + + /** + * 23.1.3.5 + * Iterates over the key/value pairs in the collection calling `callback` + * with [value, key, map]. An optional `thisArg` can be passed to set the + * context when `callback` is called. + * + * @param {function} callback + * @param {?object} thisArg + */ + forEach(callback, thisArg) { + if (typeof callback !== 'function') { + throw new TypeError('Callback must be callable.'); + } + + const boundCallback = callback.bind(thisArg || undefined); + const mapData = this._mapData; + + // Note that `mapData.length` should be computed on each iteration to + // support iterating over new items in the map that were added after the + // start of the iteration. + for (let i = 0; i < mapData.length; i++) { + const entry = mapData[i]; + if (entry != null) { + boundCallback(entry[1], entry[0], this); + } + } + } + } + + // 23.1.3.12 + Map.prototype[toIterator.ITERATOR_SYMBOL] = Map.prototype.entries; + + class MapIterator { + /** + * 23.1.5.1 + * Create a `MapIterator` for a given `map`. While this class is private it + * will create objects that will be passed around publicily. + * + * @param {map} map + * @param {string} kind + */ + constructor(map, kind) { + if (!(isObject(map) && map._mapData)) { + throw new TypeError('Object is not a map.'); + } + + if ([KIND_KEY, KIND_KEY_VALUE, KIND_VALUE].indexOf(kind) === -1) { + throw new Error('Invalid iteration kind.'); + } + + this._map = map; + this._nextIndex = 0; + this._kind = kind; + } + + /** + * 23.1.5.2.1 + * Get the next iteration. + * + * @return {object} + */ + next() { + if (!this instanceof Map) { + throw new TypeError('Expected to be called on a MapIterator.'); + } + + const map = this._map; + let index = this._nextIndex; + const kind = this._kind; + + if (map == null) { + return createIterResultObject(undefined, true); + } + + const entries = map._mapData; + + while (index < entries.length) { + const record = entries[index]; + + index += 1; + this._nextIndex = index; + + if (record) { + if (kind === KIND_KEY) { + return createIterResultObject(record[0], false); + } else if (kind === KIND_VALUE) { + return createIterResultObject(record[1], false); + } else if (kind) { + return createIterResultObject(record, false); + } + } + } + + this._map = undefined; + + return createIterResultObject(undefined, true); + } + } + + // We can put this in the class definition once we have computed props + // transform. + // 23.1.5.2.2 + MapIterator.prototype[toIterator.ITERATOR_SYMBOL] = function() { + return this; + }; + + /** + * Helper Functions. + */ + + /** + * Return an index to map.[[MapData]] array for a given Key. + * + * @param {map} map + * @param {*} key + * @return {?number} + */ + function getIndex(map, key) { + if (isObject(key)) { + const hash = getHash(key); + return map._objectIndex[hash]; + } else { + const prefixedKey = KEY_PREFIX + key; + if (typeof key === 'string') { + return map._stringIndex[prefixedKey]; + } else { + return map._otherIndex[prefixedKey]; + } + } + } + + /** + * Setup an index that refer to the key's location in map.[[MapData]]. + * + * @param {map} map + * @param {*} key + */ + function setIndex(map, key, index) { + const shouldDelete = index == null; + + if (isObject(key)) { + const hash = getHash(key); + if (shouldDelete) { + delete map._objectIndex[hash]; + } else { + map._objectIndex[hash] = index; + } + } else { + const prefixedKey = KEY_PREFIX + key; + if (typeof key === 'string') { + if (shouldDelete) { + delete map._stringIndex[prefixedKey]; + } else { + map._stringIndex[prefixedKey] = index; + } + } else { + if (shouldDelete) { + delete map._otherIndex[prefixedKey]; + } else { + map._otherIndex[prefixedKey] = index; + } + } + } + } + + /** + * Instantiate a map with internal slots. + * + * @param {map} map + */ + function initMap(map) { + // Data structure design inspired by Traceur's Map implementation. + // We maintain an internal array for all the entries. The array is needed + // to remember order. However, to have a reasonable HashMap performance + // i.e. O(1) for insertion, deletion, and retrieval. We maintain indices + // in objects for fast look ups. Indices are split up according to data + // types to avoid collisions. + map._mapData = []; + + // Object index maps from an object "hash" to index. The hash being a unique + // property of our choosing that we associate with the object. Association + // is done by ways of keeping a non-enumerable property on the object. + // Ideally these would be `Object.create(null)` objects but since we're + // trying to support ES3 we'll have to guard against collisions using + // prefixes on the keys rather than rely on null prototype objects. + map._objectIndex = {}; + + // String index maps from strings to index. + map._stringIndex = {}; + + // Numbers, booleans, undefined, and null. + map._otherIndex = {}; + + // Unfortunately we have to support ES3 and cannot have `Map.prototype.size` + // be a getter method but just a regular method. The biggest problem with + // this is safety. Clients can change the size property easily and possibly + // without noticing (e.g. `if (map.size = 1) {..}` kind of typo). What we + // can do to mitigate use getters and setters in development to disallow + // and issue a warning for changing the `size` property. + if (__DEV__) { + if (isES5) { + // If the `SECRET_SIZE_PROP` property is already defined then we're not + // in the first call to `initMap` (e.g. coming from `map.clear()`) so + // all we need to do is reset the size without defining the properties. + if (hasOwn.call(map, SECRET_SIZE_PROP)) { + map[SECRET_SIZE_PROP] = 0; + } else { + Object.defineProperty(map, SECRET_SIZE_PROP, { + value: 0, + writable: true, + }); + Object.defineProperty(map, 'size', { + set: v => { + console.error( + 'PLEASE FIX ME: You are changing the map size property which ' + + 'should not be writable and will break in production.', + ); + throw new Error('The map size property is not writable.'); + }, + get: () => map[SECRET_SIZE_PROP], + }); + } + + // NOTE: Early return to implement immutable `.size` in DEV. + return; + } + } + + // This is a diviation from the spec. `size` should be a getter on + // `Map.prototype`. However, we have to support IE8. + map.size = 0; + } + + /** + * Check if something is an object. + * + * @param {*} o + * @return {boolean} + */ + function isObject(o) { + return o != null && (typeof o === 'object' || typeof o === 'function'); + } + + /** + * Create an iteration object. + * + * @param {*} value + * @param {boolean} done + * @return {object} + */ + function createIterResultObject(value, done) { + return {value, done}; + } + + // Are we in a legit ES5 environment. Spoiler alert: that doesn't include IE8. + const isES5 = (function() { + try { + Object.defineProperty({}, 'x', {}); + return true; + } catch (e) { + return false; + } + })(); + + /** + * Check if an object can be extended. + * + * @param {object|array|function|regexp} o + * @return {boolean} + */ + function isExtensible(o) { + if (!isES5) { + return true; + } else { + return Object.isExtensible(o); + } + } + + const getHash = (function() { + const propIsEnumerable = Object.prototype.propertyIsEnumerable; + const hashProperty = '__MAP_POLYFILL_INTERNAL_HASH__'; + let hashCounter = 0; + + const nonExtensibleObjects = []; + const nonExtensibleHashes = []; + + /** + * Get the "hash" associated with an object. + * + * @param {object|array|function|regexp} o + * @return {number} + */ + return function getHash(o) { + if (hasOwn.call(o, hashProperty)) { + return o[hashProperty]; + } + + if (!isES5) { + if ( + hasOwn.call(o, 'propertyIsEnumerable') && + hasOwn.call(o.propertyIsEnumerable, hashProperty) + ) { + return o.propertyIsEnumerable[hashProperty]; + } + } + + if (isExtensible(o)) { + if (isES5) { + Object.defineProperty(o, hashProperty, { + enumerable: false, + writable: false, + configurable: false, + value: ++hashCounter, + }); + return hashCounter; + } + + if (o.propertyIsEnumerable) { + // Since we can't define a non-enumerable property on the object + // we'll hijack one of the less-used non-enumerable properties to + // save our hash on it. Additionally, since this is a function it + // will not show up in `JSON.stringify` which is what we want. + o.propertyIsEnumerable = function() { + return propIsEnumerable.apply(this, arguments); + }; + return (o.propertyIsEnumerable[hashProperty] = ++hashCounter); + } + } + + // If the object is not extensible, fall back to storing it in an + // array and using Array.prototype.indexOf to find it. + let index = nonExtensibleObjects.indexOf(o); + if (index < 0) { + index = nonExtensibleObjects.length; + nonExtensibleObjects[index] = o; + nonExtensibleHashes[index] = ++hashCounter; + } + return nonExtensibleHashes[index]; + }; + })(); + + return Map; +})(Function('return this')()); // eslint-disable-line no-new-func diff --git a/Libraries/vendor/core/Set.js b/Libraries/vendor/core/Set.js new file mode 100644 index 00000000000000..564f530b9afd8a --- /dev/null +++ b/Libraries/vendor/core/Set.js @@ -0,0 +1,198 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @preventMunge + * @typechecks + */ + +/* eslint-disable no-extend-native */ + +'use strict'; + +const Map = require('./Map'); + +const _shouldPolyfillES6Collection = require('./_shouldPolyfillES6Collection'); +const toIterator = require('./toIterator'); + +module.exports = (function(global) { + // Since our implementation is spec-compliant for the most part we can safely + // delegate to a built-in version if exists and is implemented correctly. + // Firefox had gotten a few implementation details wrong across different + // versions so we guard against that. + // These checks are adapted from es6-shim https://fburl.com/34437854 + if (!_shouldPolyfillES6Collection('Set')) { + return global.Set; + } + + /** + * == ES6 Set Collection == + * + * This module is meant to implement a Set collection as described in chapter + * 23.2 of the ES6 specification. + * + * Set objects are collections of unique values. Where values can be any + * JavaScript value. + * https://people.mozilla.org/~jorendorff/es6-draft.html#sec-map-objects + * + * There only two -- rather small -- diviations from the spec: + * + * 1. The use of frozen objects as keys. @see Map module for more on this. + * + * 2. The `size` property on a map object is a regular property and not a + * computed property on the prototype as described by the spec. + * The reason being is that we simply want to support ES3 environments + * which doesn't implement computed properties. + * + * == Usage == + * + * var set = new set(iterable); + * + * set.set(value); + * set.has(value); // true + * set.delete(value); // true + * + * var iterator = set.keys(); + * iterator.next(); // {value: value, done: false} + * + * var iterator = set.values(); + * iterator.next(); // {value: value, done: false} + * + * var iterator = set.entries(); + * iterator.next(); // {value: [value, value], done: false} + * + * set.forEach(function(value, value){ this === thisArg }, thisArg); + * + * set.clear(); // resets set. + */ + + class Set { + /** + * 23.2.1.1 + * + * Takes an optional `iterable` (which is basically any object that + * implements a Symbol.iterator (@@iterator) method). That is a collection + * of values used to instantiate the set. + * + * @param {*} iterable + */ + constructor(iterable) { + if ( + this == null || + (typeof this !== 'object' && typeof this !== 'function') + ) { + throw new TypeError('Wrong set object type.'); + } + + initSet(this); + + if (iterable != null) { + const it = toIterator(iterable); + let next; + while (!(next = it.next()).done) { + this.add(next.value); + } + } + } + + /** + * 23.2.3.1 + * + * If it doesn't already exist in the collection a `value` is added. + * + * @param {*} value + * @return {set} + */ + add(value) { + this._map.set(value, value); + this.size = this._map.size; + return this; + } + + /** + * 23.2.3.2 + * + * Clears the set. + */ + clear() { + initSet(this); + } + + /** + * 23.2.3.4 + * + * Deletes a `value` from the collection if it exists. + * Returns true if the value was found and deleted and false otherwise. + * + * @param {*} value + * @return {boolean} + */ + delete(value) { + const ret = this._map.delete(value); + this.size = this._map.size; + return ret; + } + + /** + * 23.2.3.5 + * + * Returns an iterator over a collection of [value, value] tuples. + */ + entries() { + return this._map.entries(); + } + + /** + * 23.2.3.6 + * + * Iterate over the collection calling `callback` with (value, value, set). + * + * @param {function} callback + */ + forEach(callback) { + const thisArg = arguments[1]; + const it = this._map.keys(); + let next; + while (!(next = it.next()).done) { + callback.call(thisArg, next.value, next.value, this); + } + } + + /** + * 23.2.3.7 + * + * Iterate over the collection calling `callback` with (value, value, set). + * + * @param {*} value + * @return {boolean} + */ + has(value) { + return this._map.has(value); + } + + /** + * 23.2.3.7 + * + * Returns an iterator over the colleciton of values. + */ + values() { + return this._map.values(); + } + } + + // 23.2.3.11 + Set.prototype[toIterator.ITERATOR_SYMBOL] = Set.prototype.values; + + // 23.2.3.7 + Set.prototype.keys = Set.prototype.values; + + function initSet(set) { + set._map = new Map(); + set.size = set._map.size; + } + + return Set; +})(Function('return this')()); // eslint-disable-line no-new-func diff --git a/Libraries/vendor/core/_shouldPolyfillES6Collection.js b/Libraries/vendor/core/_shouldPolyfillES6Collection.js new file mode 100644 index 00000000000000..1ba893c5aebdbe --- /dev/null +++ b/Libraries/vendor/core/_shouldPolyfillES6Collection.js @@ -0,0 +1,66 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @preventMunge + * @flow strict + */ + +'use strict'; + +/** + * Checks whether a collection name (e.g. "Map" or "Set") has a native polyfill + * that is safe to be used. + */ +function _shouldActuallyPolyfillES6Collection(collectionName: string): boolean { + const Collection = global[collectionName]; + if (Collection == null) { + return true; + } + + // The iterator protocol depends on `Symbol.iterator`. If a collection is + // implemented, but `Symbol` is not, it's going to break iteration because + // we'll be using custom "@@iterator" instead, which is not implemented on + // native collections. + if (typeof global.Symbol !== 'function') { + return true; + } + + const proto = Collection.prototype; + + // These checks are adapted from es6-shim: https://fburl.com/34437854 + // NOTE: `isCallableWithoutNew` and `!supportsSubclassing` are not checked + // because they make debugging with "break on exceptions" difficult. + return ( + Collection == null || + typeof Collection !== 'function' || + typeof proto.clear !== 'function' || + new Collection().size !== 0 || + typeof proto.keys !== 'function' || + typeof proto.forEach !== 'function' + ); +} + +const cache: {[name: string]: boolean} = {}; + +/** + * Checks whether a collection name (e.g. "Map" or "Set") has a native polyfill + * that is safe to be used and caches this result. + * Make sure to make a first call to this function before a corresponding + * property on global was overriden in any way. + */ +function _shouldPolyfillES6Collection(collectionName: string) { + let result = cache[collectionName]; + if (result !== undefined) { + return result; + } + + result = _shouldActuallyPolyfillES6Collection(collectionName); + cache[collectionName] = result; + return result; +} + +module.exports = _shouldPolyfillES6Collection; diff --git a/flow/Map.js b/flow/Map.js new file mode 100644 index 00000000000000..c8e830529798ff --- /dev/null +++ b/flow/Map.js @@ -0,0 +1,40 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict + * @format + */ + +// These annotations are copy/pasted from the built-in Flow definitions for +// Native Map. + +declare module 'Map' { + // Use the name "MapPolyfill" so that we don't get confusing error + // messages about "Using Map instead of Map". + declare class MapPolyfill { + @@iterator(): Iterator<[K, V]>; + constructor(_: void): MapPolyfill; + constructor(_: null): MapPolyfill; + constructor( + iterable: Iterable<[Key, Value]>, + ): MapPolyfill; + clear(): void; + delete(key: K): boolean; + entries(): Iterator<[K, V]>; + forEach( + callbackfn: (value: V, index: K, map: MapPolyfill) => mixed, + thisArg?: any, + ): void; + get(key: K): V | void; + has(key: K): boolean; + keys(): Iterator; + set(key: K, value: V): MapPolyfill; + size: number; + values(): Iterator; + } + + declare module.exports: typeof MapPolyfill; +} diff --git a/flow/Set.js b/flow/Set.js new file mode 100644 index 00000000000000..64099c2a6028c3 --- /dev/null +++ b/flow/Set.js @@ -0,0 +1,36 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict + * @nolint + * @format + */ + +// These annotations are copy/pasted from the built-in Flow definitions for +// Native Set. + +declare module 'Set' { + // Use the name "SetPolyfill" so that we don't get confusing error + // messages about "Using Set instead of Set". + declare class SetPolyfill { + @@iterator(): Iterator; + constructor(iterable: ?Iterable): void; + add(value: T): SetPolyfill; + clear(): void; + delete(value: T): boolean; + entries(): Iterator<[T, T]>; + forEach( + callbackfn: (value: T, index: T, set: SetPolyfill) => mixed, + thisArg?: any, + ): void; + has(value: T): boolean; + keys(): Iterator; + size: number; + values(): Iterator; + } + + declare module.exports: typeof SetPolyfill; +} From 9b61896f406cfe80fe2941bd846cc5cdbbeab238 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Thu, 6 Jun 2019 09:13:52 -0700 Subject: [PATCH 0222/1084] Don't apply empty attributed string for TextInput (#25143) Summary: Issue reported by Titozzz , `TextInput` would shrink when we have attributes like `lineHeight`. Demonstration can see GIF like below: https://giphy.com/gifs/KGNs1qIMHF3DIk1EPK I think the reason is we apply an empty attributed string to `UITextField`, now if the length is 0, we just nil the `attributedText` instead. ## Changelog [iOS] [Fixed] - Don't apply empty attributed string for TextInput Pull Request resolved: https://github.com/facebook/react-native/pull/25143 Differential Revision: D15661751 Pulled By: sammy-SC fbshipit-source-id: 9770484a1b68a6409e63ea25ac9a6fd0d3589b14 --- Libraries/Text/TextInput/RCTBaseTextInputShadowView.m | 7 ++++++- Libraries/Text/TextInput/RCTBaseTextInputView.h | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Libraries/Text/TextInput/RCTBaseTextInputShadowView.m b/Libraries/Text/TextInput/RCTBaseTextInputShadowView.m index c79d65e136f88f..c6cc08bb8bf0f3 100644 --- a/Libraries/Text/TextInput/RCTBaseTextInputShadowView.m +++ b/Libraries/Text/TextInput/RCTBaseTextInputShadowView.m @@ -174,7 +174,12 @@ - (void)uiManagerWillPerformMounting baseTextInputView.reactPaddingInsets = paddingInsets; if (isAttributedTextChanged) { - baseTextInputView.attributedText = attributedText; + // Don't set `attributedText` if length equal to zero, otherwise it would shrink when attributes contain like `lineHeight`. + if (attributedText.length != 0) { + baseTextInputView.attributedText = attributedText; + } else { + baseTextInputView.attributedText = nil; + } } }]; } diff --git a/Libraries/Text/TextInput/RCTBaseTextInputView.h b/Libraries/Text/TextInput/RCTBaseTextInputView.h index 5b62f90251492e..ead709672f8f9a 100644 --- a/Libraries/Text/TextInput/RCTBaseTextInputView.h +++ b/Libraries/Text/TextInput/RCTBaseTextInputView.h @@ -46,7 +46,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, assign) BOOL secureTextEntry; @property (nonatomic, copy) RCTTextSelection *selection; @property (nonatomic, strong, nullable) NSNumber *maxLength; -@property (nonatomic, copy) NSAttributedString *attributedText; +@property (nonatomic, copy, nullable) NSAttributedString *attributedText; @property (nonatomic, copy) NSString *inputAccessoryViewID; @property (nonatomic, assign) UIKeyboardType keyboardType; From 360e999937dc1d15d7b67f3fde5f3dde448e23cd Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Thu, 6 Jun 2019 09:35:16 -0700 Subject: [PATCH 0223/1084] TM iOS: reduce the scope of cache access lock Summary: We just need to protect access to the cache, we don't need to protect the entire module lookup, because a module initialization may try to lookup another module, causing deadlocks. Reviewed By: RSNara Differential Revision: D15690645 fbshipit-source-id: cbb780db8699a94f2c9a2e121b35ddad2b125b65 --- .../platform/ios/RCTTurboModuleManager.mm | 68 ++++++++++--------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm b/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm index 93f91f00ef7769..91fdbc9b329efd 100644 --- a/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm +++ b/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm @@ -211,37 +211,46 @@ - (void)notifyAboutTurboModuleSetup:(const char *)name */ - (id)provideRCTTurboModule:(const char *)moduleName { - std::lock_guard guard{_rctTurboModuleCacheLock}; + Class moduleClass; + id module = nil; - auto rctTurboModuleCacheLookup = _rctTurboModuleCache.find(moduleName); - if (rctTurboModuleCacheLookup != _rctTurboModuleCache.end()) { - return rctTurboModuleCacheLookup->second; - } + { + std::unique_lock lock(_rctTurboModuleCacheLock); - /** - * Step 2a: Resolve platform-specific class. - */ - Class moduleClass; - if ([_delegate respondsToSelector:@selector(getModuleClassFromName:)]) { - moduleClass = [_delegate getModuleClassFromName:moduleName]; - } + auto rctTurboModuleCacheLookup = _rctTurboModuleCache.find(moduleName); + if (rctTurboModuleCacheLookup != _rctTurboModuleCache.end()) { + return rctTurboModuleCacheLookup->second; + } - if (!moduleClass) { - moduleClass = getFallbackClassFromName(moduleName); - } + /** + * Step 2a: Resolve platform-specific class. + */ + if ([_delegate respondsToSelector:@selector(getModuleClassFromName:)]) { + moduleClass = [_delegate getModuleClassFromName:moduleName]; + } - if (![moduleClass conformsToProtocol:@protocol(RCTTurboModule)]) { - return nil; - } + if (!moduleClass) { + moduleClass = getFallbackClassFromName(moduleName); + } - /** - * Step 2b: Ask hosting application/delegate to instantiate this class - */ - id module = nil; - if ([_delegate respondsToSelector:@selector(getModuleInstanceFromClass:)]) { - module = [_delegate getModuleInstanceFromClass:moduleClass]; - } else { - module = [moduleClass new]; + if (![moduleClass conformsToProtocol:@protocol(RCTTurboModule)]) { + return nil; + } + + /** + * Step 2b: Ask hosting application/delegate to instantiate this class + */ + if ([_delegate respondsToSelector:@selector(getModuleInstanceFromClass:)]) { + module = [_delegate getModuleInstanceFromClass:moduleClass]; + } else { + module = [moduleClass new]; + } + + if ([module respondsToSelector:@selector(setTurboModuleLookupDelegate:)]) { + [module setTurboModuleLookupDelegate:self]; + } + + _rctTurboModuleCache.insert({moduleName, module}); } /** @@ -280,12 +289,6 @@ - (void)notifyAboutTurboModuleSetup:(const char *)name } } - if ([module respondsToSelector:@selector(setTurboModuleLookupDelegate:)]) { - [module setTurboModuleLookupDelegate:self]; - } - - _rctTurboModuleCache.insert({moduleName, module}); - /** * Broadcast that this TurboModule was created. * @@ -336,6 +339,7 @@ - (id)moduleForName:(const char *)moduleName warnOnLookupFailure:(BOOL)warnOnLoo - (BOOL)moduleIsInitialized:(const char *)moduleName { + std::unique_lock lock(_rctTurboModuleCacheLock); return _rctTurboModuleCache.find(std::string(moduleName)) != _rctTurboModuleCache.end(); } From 2fe3dd2e7d27789918079c66636c5161e22c5c33 Mon Sep 17 00:00:00 2001 From: Arthur Lee Date: Thu, 6 Jun 2019 11:30:19 -0700 Subject: [PATCH 0224/1084] Use fetch as a polyfill Summary: The old whatwg-fetch module doesn't actually export anything, so we would always hit the `else` condition. The new whatwg-fetch (3.0.0, introduced in #24418) now exports an ES module. As a result, `whatwg` and `whatwg.fetch` are both truthy but the `module.exports` will end up empty. This breaks the RN fetch module. This will switch the behavior back to the expected polyfill behavior (calling `require('whatwg-fetch')` and allowing it to polyfill fetch in global scope). The RN fetch module will re-export these globals. Reviewed By: cpojer Differential Revision: D15639851 fbshipit-source-id: ebd8bce85f7797d8539f53982e515ac47f6425e7 --- Libraries/Network/fetch.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Libraries/Network/fetch.js b/Libraries/Network/fetch.js index 66687e70de2035..65a02b9ee4d428 100644 --- a/Libraries/Network/fetch.js +++ b/Libraries/Network/fetch.js @@ -11,10 +11,8 @@ 'use strict'; -const whatwg = require('whatwg-fetch'); +// side-effectful require() to put fetch, +// Headers, Request, Response in global scope +require('whatwg-fetch'); -if (whatwg && whatwg.fetch) { - module.exports = whatwg; -} else { - module.exports = {fetch, Headers, Request, Response}; -} +module.exports = {fetch, Headers, Request, Response}; From ac7ec4602fd4d8ec033a084df6a92437ea2d3a8a Mon Sep 17 00:00:00 2001 From: Joshua Ong Date: Thu, 6 Jun 2019 11:54:08 -0700 Subject: [PATCH 0225/1084] Allow headless JS tasks to retry (#23231) Summary: `setTimeout` inside a headless JS task does not always works; the function does not get invoked until the user starts an `Activity`. This was attempted to be used in the context of widgets. When the widget update or user interaction causes the process and React context to be created, the headless JS task may run before other app-specific JS initialisation logic has completed. If it's not possible to change the behaviour of the pre-requisites to be synchronous, then the headless JS task blocks such asynchronous JS work that it may depend on. A primitive solution is the use of `setTimeout` in order to wait for the pre-conditions to be met before continuing with the rest of the headless JS task. But as the function passed to `setTimeout` is not always called, the task will not run to completion. This PR solves this scenario by allowing the task to be retried again with a delay. If the task returns a promise that resolves to a `{'timeout': number}` object, `AppRegistry.js` will not notify that the task has finished as per master, instead it will tell `HeadlessJsContext` to `startTask` again (cleaning up any posted `Runnable`s beforehand) via a `Handler` within the `HeadlessJsContext`. Documentation also updated here: https://github.com/facebook/react-native-website/pull/771 ### AppRegistry.js If the task provider does not return any data, or if the data it returns does not contain `timeout` as a number, then it behaves as `master`; notifies that the task has finished. If the response does contain `{timeout: number}`, then it will attempt to queue a retry. If that fails, then it will behaves as if the task provider returned no response i.e. behaves as `master` again. If the retry was successfully queued, then there is nothing to do as we do not want the `Service` to stop itself. ### HeadlessJsTaskSupportModule.java Similar to notify start/finished, we simply check if the context is running, and if so, pass the request onto `HeadlessJsTaskContext`. The only difference here is that we return a `Promise`, so that `AppRegistry`, as above, knows whether the enqueuing failed and thus needs to perform the usual task clean-up. ### HeadlessJsTaskContext.java Before retrying, we need to clean-up any timeout `Runnable`'s posted for the first attempt. Then we need to copy the task config so that if this retry (second attempt) also fails, then on the third attempt (second retry) we do not run into a consumed exception. This is also why in `startTask` we copy the config before putting it in the `Map`, so that the initial attempt does leave the config's in the map as consumed. Then we post a `Runnable` to call `startTask` on the main thread's `Handler`. We use the same `taskId` because the `Service` is keeping track of active task IDs in order to calculate whether it needs to `stopSelf`. This negates the need to inform the `Service` of a new task id and us having to remove the old one. ## Changelog [Android][added] - Allow headless JS tasks to return a promise that will cause the task to be retried again with the specified delay Pull Request resolved: https://github.com/facebook/react-native/pull/23231 Differential Revision: D15646870 fbshipit-source-id: 4440f4b4392f1fa5c69aab7908b51b7007ba2c40 --- Libraries/ReactNative/AppRegistry.js | 15 +++- Libraries/ReactNative/HeadlessJsTaskError.js | 12 +++ .../NativeHeadlessJsTaskSupport.js | 1 + .../tests/core/WritableNativeMapTest.java | 26 +++++- .../facebook/react/bridge/JavaOnlyMap.java | 7 ++ .../facebook/react/bridge/UiThreadUtil.java | 9 +- .../facebook/react/bridge/WritableMap.java | 1 + .../react/bridge/WritableNativeMap.java | 7 ++ .../react/jstasks/HeadlessJsTaskConfig.java | 46 ++++++++++ .../react/jstasks/HeadlessJsTaskContext.java | 83 ++++++++++++++++--- .../jstasks/HeadlessJsTaskRetryPolicy.java | 16 ++++ .../jstasks/LinearCountingRetryPolicy.java | 38 +++++++++ .../facebook/react/jstasks/NoRetryPolicy.java | 30 +++++++ .../core/HeadlessJsTaskSupportModule.java | 17 ++++ 14 files changed, 290 insertions(+), 18 deletions(-) create mode 100644 Libraries/ReactNative/HeadlessJsTaskError.js create mode 100644 ReactAndroid/src/main/java/com/facebook/react/jstasks/HeadlessJsTaskRetryPolicy.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/jstasks/LinearCountingRetryPolicy.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/jstasks/NoRetryPolicy.java diff --git a/Libraries/ReactNative/AppRegistry.js b/Libraries/ReactNative/AppRegistry.js index 2d517ce6dd0f10..d7e9fc788a8adb 100644 --- a/Libraries/ReactNative/AppRegistry.js +++ b/Libraries/ReactNative/AppRegistry.js @@ -21,6 +21,7 @@ const createPerformanceLogger = require('../Utilities/createPerformanceLogger'); import type {IPerformanceLogger} from '../Utilities/createPerformanceLogger'; import NativeHeadlessJsTaskSupport from './NativeHeadlessJsTaskSupport'; +import HeadlessJsTaskError from './HeadlessJsTaskError'; type Task = (taskData: any) => Promise; type TaskProvider = () => Task; @@ -275,8 +276,18 @@ const AppRegistry = { }) .catch(reason => { console.error(reason); - if (NativeHeadlessJsTaskSupport) { - NativeHeadlessJsTaskSupport.notifyTaskFinished(taskId); + + if ( + NativeHeadlessJsTaskSupport && + reason instanceof HeadlessJsTaskError + ) { + NativeHeadlessJsTaskSupport.notifyTaskRetry(taskId).then( + retryPosted => { + if (!retryPosted) { + NativeHeadlessJsTaskSupport.notifyTaskFinished(taskId); + } + }, + ); } }); }, diff --git a/Libraries/ReactNative/HeadlessJsTaskError.js b/Libraries/ReactNative/HeadlessJsTaskError.js new file mode 100644 index 00000000000000..0f85e138bb5a5f --- /dev/null +++ b/Libraries/ReactNative/HeadlessJsTaskError.js @@ -0,0 +1,12 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ +'use strict'; + +export default class HeadlessJsTaskError extends Error {} diff --git a/Libraries/ReactNative/NativeHeadlessJsTaskSupport.js b/Libraries/ReactNative/NativeHeadlessJsTaskSupport.js index 686ababaa9ae4f..d3256f49e10046 100644 --- a/Libraries/ReactNative/NativeHeadlessJsTaskSupport.js +++ b/Libraries/ReactNative/NativeHeadlessJsTaskSupport.js @@ -15,6 +15,7 @@ import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { +notifyTaskFinished: (taskId: number) => void; + +notifyTaskRetry: (taskId: number) => Promise; } export default TurboModuleRegistry.get('HeadlessJsTaskSupport'); diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/core/WritableNativeMapTest.java b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/core/WritableNativeMapTest.java index 5199156393d99e..e709799f66e7dd 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/core/WritableNativeMapTest.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/core/WritableNativeMapTest.java @@ -5,6 +5,8 @@ import androidx.test.runner.AndroidJUnit4; import com.facebook.react.bridge.NoSuchKeyException; import com.facebook.react.bridge.UnexpectedNativeTypeException; +import com.facebook.react.bridge.WritableArray; +import com.facebook.react.bridge.WritableMap; import com.facebook.react.bridge.WritableNativeArray; import com.facebook.react.bridge.WritableNativeMap; import org.junit.Assert; @@ -16,6 +18,8 @@ @RunWith(AndroidJUnit4.class) public class WritableNativeMapTest { + private static final String ARRAY = "array"; + private static final String MAP = "map"; private WritableNativeMap mMap; @Before @@ -25,8 +29,8 @@ public void setup() { mMap.putDouble("double", 1.2); mMap.putInt("int", 1); mMap.putString("string", "abc"); - mMap.putMap("map", new WritableNativeMap()); - mMap.putArray("array", new WritableNativeArray()); + mMap.putMap(MAP, new WritableNativeMap()); + mMap.putArray(ARRAY, new WritableNativeArray()); mMap.putBoolean("dvacca", true); } @@ -100,4 +104,22 @@ public void testErrorMessageContainsKey() { assertThat(e.getMessage()).contains(key); } } + + @Test + public void testCopy() { + final WritableMap copy = mMap.copy(); + + assertThat(copy).isNotSameAs(mMap); + assertThat(copy.getMap(MAP)).isNotSameAs(mMap.getMap(MAP)); + assertThat(copy.getArray(ARRAY)).isNotSameAs(mMap.getArray(ARRAY)); + } + + @Test + public void testCopyModification() { + final WritableMap copy = mMap.copy(); + copy.putString("string", "foo"); + + assertThat(copy.getString("string")).isEqualTo("foo"); + assertThat(mMap.getString("string")).isEqualTo("abc"); + } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaOnlyMap.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaOnlyMap.java index 139f824611338a..ddf450f814ccfb 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaOnlyMap.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaOnlyMap.java @@ -206,6 +206,13 @@ public void merge(@Nonnull ReadableMap source) { mBackingMap.putAll(((JavaOnlyMap) source).mBackingMap); } + @Override + public WritableMap copy() { + final JavaOnlyMap target = new JavaOnlyMap(); + target.merge(this); + return target; + } + @Override public void putArray(@Nonnull String key, @Nullable WritableArray value) { mBackingMap.put(key, value); diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/UiThreadUtil.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/UiThreadUtil.java index 3adf9b8359e6f3..9b320097d69e56 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/UiThreadUtil.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/UiThreadUtil.java @@ -44,11 +44,18 @@ public static void assertNotOnUiThread() { * Runs the given {@code Runnable} on the UI thread. */ public static void runOnUiThread(Runnable runnable) { + runOnUiThread(runnable, 0); + } + + /** + * Runs the given {@code Runnable} on the UI thread with the specified delay. + */ + public static void runOnUiThread(Runnable runnable, long delayInMs) { synchronized (UiThreadUtil.class) { if (sMainHandler == null) { sMainHandler = new Handler(Looper.getMainLooper()); } } - sMainHandler.post(runnable); + sMainHandler.postDelayed(runnable, delayInMs); } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/WritableMap.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/WritableMap.java index 1aa2d7a108f683..9338c19ae96903 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/WritableMap.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/WritableMap.java @@ -24,4 +24,5 @@ public interface WritableMap extends ReadableMap { void putMap(@Nonnull String key, @Nullable WritableMap value); void merge(@Nonnull ReadableMap source); + WritableMap copy(); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/WritableNativeMap.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/WritableNativeMap.java index ec632940b47e86..997f4058783336 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/WritableNativeMap.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/WritableNativeMap.java @@ -61,6 +61,13 @@ public void merge(@Nonnull ReadableMap source) { mergeNativeMap((ReadableNativeMap) source); } + @Override + public WritableMap copy() { + final WritableNativeMap target = new WritableNativeMap(); + target.merge(this); + return target; + } + public WritableNativeMap() { super(initHybrid()); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/jstasks/HeadlessJsTaskConfig.java b/ReactAndroid/src/main/java/com/facebook/react/jstasks/HeadlessJsTaskConfig.java index f0e15451f7cd7e..1c441300ba1a40 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/jstasks/HeadlessJsTaskConfig.java +++ b/ReactAndroid/src/main/java/com/facebook/react/jstasks/HeadlessJsTaskConfig.java @@ -15,6 +15,7 @@ public class HeadlessJsTaskConfig { private final WritableMap mData; private final long mTimeout; private final boolean mAllowedInForeground; + private final HeadlessJsTaskRetryPolicy mRetryPolicy; /** * Create a HeadlessJsTaskConfig. Equivalent to calling @@ -55,10 +56,51 @@ public HeadlessJsTaskConfig( WritableMap data, long timeout, boolean allowedInForeground) { + this(taskKey, data, timeout, allowedInForeground, NoRetryPolicy.INSTANCE); + } + + /** + * Create a HeadlessJsTaskConfig. + * + * @param taskKey the key for the JS task to execute. This is the same key that you call {@code + * AppRegistry.registerTask} with in JS. + * @param data a map of parameters passed to the JS task executor. + * @param timeout the amount of time (in ms) after which the React instance should be terminated + * regardless of whether the task has completed or not. This is meant as a safeguard against + * accidentally keeping the device awake for long periods of time because JS crashed or some + * request timed out. A value of 0 means no timeout (should only be used for long-running tasks + * such as music playback). + * @param allowedInForeground whether to allow this task to run while the app is in the foreground + * (i.e. there is a host in resumed mode for the current ReactContext). Only set this to true if + * you really need it. Note that tasks run in the same JS thread as UI code, so doing expensive + * operations would degrade user experience. + * @param retryPolicy the number of times & delays the task should be retried on error. + */ + public HeadlessJsTaskConfig( + String taskKey, + WritableMap data, + long timeout, + boolean allowedInForeground, + HeadlessJsTaskRetryPolicy retryPolicy) { mTaskKey = taskKey; mData = data; mTimeout = timeout; mAllowedInForeground = allowedInForeground; + mRetryPolicy = retryPolicy; + } + + public HeadlessJsTaskConfig(HeadlessJsTaskConfig source) { + mTaskKey = source.mTaskKey; + mData = source.mData.copy(); + mTimeout = source.mTimeout; + mAllowedInForeground = source.mAllowedInForeground; + + final HeadlessJsTaskRetryPolicy retryPolicy = source.mRetryPolicy; + if (retryPolicy != null) { + mRetryPolicy = retryPolicy.copy(); + } else { + mRetryPolicy = null; + } } /* package */ String getTaskKey() { @@ -76,4 +118,8 @@ public HeadlessJsTaskConfig( /* package */ boolean isAllowedInForeground() { return mAllowedInForeground; } + + /* package */ HeadlessJsTaskRetryPolicy getRetryPolicy() { + return mRetryPolicy; + } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/jstasks/HeadlessJsTaskContext.java b/ReactAndroid/src/main/java/com/facebook/react/jstasks/HeadlessJsTaskContext.java index fbf38f1a41ee4a..e69505f396a9cd 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/jstasks/HeadlessJsTaskContext.java +++ b/ReactAndroid/src/main/java/com/facebook/react/jstasks/HeadlessJsTaskContext.java @@ -5,12 +5,6 @@ package com.facebook.react.jstasks; -import java.lang.ref.WeakReference; -import java.util.Set; -import java.util.WeakHashMap; -import java.util.concurrent.CopyOnWriteArraySet; -import java.util.concurrent.atomic.AtomicInteger; - import android.os.Handler; import android.util.SparseArray; @@ -20,6 +14,14 @@ import com.facebook.react.common.LifecycleState; import com.facebook.react.modules.appregistry.AppRegistry; +import java.lang.ref.WeakReference; +import java.util.Map; +import java.util.Set; +import java.util.WeakHashMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.atomic.AtomicInteger; + /** * Helper class for dealing with JS tasks. Handles per-ReactContext active task tracking, starting / * stopping tasks and notifying listeners. @@ -51,6 +53,7 @@ public static HeadlessJsTaskContext getInstance(ReactContext context) { private final AtomicInteger mLastTaskId = new AtomicInteger(0); private final Handler mHandler = new Handler(); private final Set mActiveTasks = new CopyOnWriteArraySet<>(); + private final Map mActiveTaskConfigs = new ConcurrentHashMap<>(); private final SparseArray mTaskTimeouts = new SparseArray<>(); private HeadlessJsTaskContext(ReactContext reactContext) { @@ -85,6 +88,16 @@ public boolean hasActiveTasks() { * @return a unique id representing this task instance. */ public synchronized int startTask(final HeadlessJsTaskConfig taskConfig) { + final int taskId = mLastTaskId.incrementAndGet(); + startTask(taskConfig, taskId); + return taskId; + } + + /** + * Start a JS task the provided task id. Handles invoking {@link AppRegistry#startHeadlessTask} + * and notifying listeners. + */ + private synchronized void startTask(final HeadlessJsTaskConfig taskConfig, int taskId) { UiThreadUtil.assertOnUiThread(); ReactContext reactContext = Assertions.assertNotNull( mReactContext.get(), @@ -95,8 +108,8 @@ public synchronized int startTask(final HeadlessJsTaskConfig taskConfig) { "Tried to start task " + taskConfig.getTaskKey() + " while in foreground, but this is not allowed."); } - final int taskId = mLastTaskId.incrementAndGet(); mActiveTasks.add(taskId); + mActiveTaskConfigs.put(taskId, new HeadlessJsTaskConfig(taskConfig)); reactContext.getJSModule(AppRegistry.class) .startHeadlessTask(taskId, taskConfig.getTaskKey(), taskConfig.getData()); if (taskConfig.getTimeout() > 0) { @@ -105,7 +118,44 @@ public synchronized int startTask(final HeadlessJsTaskConfig taskConfig) { for (HeadlessJsTaskEventListener listener : mHeadlessJsTaskEventListeners) { listener.onHeadlessJsTaskStart(taskId); } - return taskId; + } + + /** + * Retry a running JS task with a delay. Invokes + * {@link HeadlessJsTaskContext#startTask(HeadlessJsTaskConfig, int)} as long as the process does + * not get killed. + * + * @return true if a retry attempt has been posted. + */ + public synchronized boolean retryTask(final int taskId) { + final HeadlessJsTaskConfig sourceTaskConfig = mActiveTaskConfigs.get(taskId); + Assertions.assertCondition( + sourceTaskConfig != null, + "Tried to retrieve non-existent task config with id " + taskId + "."); + + final HeadlessJsTaskRetryPolicy retryPolicy = sourceTaskConfig.getRetryPolicy(); + if (!retryPolicy.canRetry()) { + return false; + } + + removeTimeout(taskId); + final HeadlessJsTaskConfig taskConfig = new HeadlessJsTaskConfig( + sourceTaskConfig.getTaskKey(), + sourceTaskConfig.getData(), + sourceTaskConfig.getTimeout(), + sourceTaskConfig.isAllowedInForeground(), + retryPolicy.update() + ); + + final Runnable retryAttempt = new Runnable() { + @Override + public void run() { + startTask(taskConfig, taskId); + } + }; + + UiThreadUtil.runOnUiThread(retryAttempt, retryPolicy.getDelay()); + return true; } /** @@ -118,11 +168,10 @@ public synchronized void finishTask(final int taskId) { Assertions.assertCondition( mActiveTasks.remove(taskId), "Tried to finish non-existent task with id " + taskId + "."); - Runnable timeout = mTaskTimeouts.get(taskId); - if (timeout != null) { - mHandler.removeCallbacks(timeout); - mTaskTimeouts.remove(taskId); - } + Assertions.assertCondition( + mActiveTaskConfigs.remove(taskId) != null, + "Tried to remove non-existent task config with id " + taskId + "."); + removeTimeout(taskId); UiThreadUtil.runOnUiThread(new Runnable() { @Override public void run() { @@ -133,6 +182,14 @@ public void run() { }); } + private void removeTimeout(int taskId) { + Runnable timeout = mTaskTimeouts.get(taskId); + if (timeout != null) { + mHandler.removeCallbacks(timeout); + mTaskTimeouts.remove(taskId); + } + } + /** * Check if a given task is currently running. A task is stopped if either {@link #finishTask} is * called or it times out. diff --git a/ReactAndroid/src/main/java/com/facebook/react/jstasks/HeadlessJsTaskRetryPolicy.java b/ReactAndroid/src/main/java/com/facebook/react/jstasks/HeadlessJsTaskRetryPolicy.java new file mode 100644 index 00000000000000..215f5b8b44cb8a --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/jstasks/HeadlessJsTaskRetryPolicy.java @@ -0,0 +1,16 @@ +package com.facebook.react.jstasks; + +import javax.annotation.CheckReturnValue; + +public interface HeadlessJsTaskRetryPolicy { + + boolean canRetry(); + + int getDelay(); + + @CheckReturnValue + HeadlessJsTaskRetryPolicy update(); + + HeadlessJsTaskRetryPolicy copy(); + +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/jstasks/LinearCountingRetryPolicy.java b/ReactAndroid/src/main/java/com/facebook/react/jstasks/LinearCountingRetryPolicy.java new file mode 100644 index 00000000000000..b319d35435ead1 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/jstasks/LinearCountingRetryPolicy.java @@ -0,0 +1,38 @@ +package com.facebook.react.jstasks; + +public class LinearCountingRetryPolicy implements HeadlessJsTaskRetryPolicy { + + private final int mRetryAttempts; + private final int mDelayBetweenAttemptsInMs; + + public LinearCountingRetryPolicy(int retryAttempts, int delayBetweenAttemptsInMs) { + mRetryAttempts = retryAttempts; + mDelayBetweenAttemptsInMs = delayBetweenAttemptsInMs; + } + + @Override + public boolean canRetry() { + return mRetryAttempts > 0; + } + + @Override + public int getDelay() { + return mDelayBetweenAttemptsInMs; + } + + @Override + public HeadlessJsTaskRetryPolicy update() { + final int remainingRetryAttempts = mRetryAttempts - 1; + + if (remainingRetryAttempts > 0) { + return new LinearCountingRetryPolicy(remainingRetryAttempts, mDelayBetweenAttemptsInMs); + } else { + return NoRetryPolicy.INSTANCE; + } + } + + @Override + public HeadlessJsTaskRetryPolicy copy() { + return new LinearCountingRetryPolicy(mRetryAttempts, mDelayBetweenAttemptsInMs); + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/jstasks/NoRetryPolicy.java b/ReactAndroid/src/main/java/com/facebook/react/jstasks/NoRetryPolicy.java new file mode 100644 index 00000000000000..ac707ab70d7789 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/jstasks/NoRetryPolicy.java @@ -0,0 +1,30 @@ +package com.facebook.react.jstasks; + +public class NoRetryPolicy implements HeadlessJsTaskRetryPolicy { + + public static final NoRetryPolicy INSTANCE = new NoRetryPolicy(); + + private NoRetryPolicy() { + } + + @Override + public boolean canRetry() { + return false; + } + + @Override + public int getDelay() { + throw new IllegalStateException("Should not retrieve delay as canRetry is: " + canRetry()); + } + + @Override + public HeadlessJsTaskRetryPolicy update() { + throw new IllegalStateException("Should not update as canRetry is: " + canRetry()); + } + + @Override + public HeadlessJsTaskRetryPolicy copy() { + // Class is immutable so no need to copy + return this; + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/core/HeadlessJsTaskSupportModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/core/HeadlessJsTaskSupportModule.java index 2d783585a77a6d..e9c2cae2a69c9a 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/core/HeadlessJsTaskSupportModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/core/HeadlessJsTaskSupportModule.java @@ -8,6 +8,7 @@ package com.facebook.react.modules.core; import com.facebook.common.logging.FLog; +import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; @@ -32,6 +33,22 @@ public String getName() { return NAME; } + @ReactMethod + public void notifyTaskRetry(int taskId, Promise promise) { + HeadlessJsTaskContext headlessJsTaskContext = + HeadlessJsTaskContext.getInstance(getReactApplicationContext()); + if (headlessJsTaskContext.isTaskRunning(taskId)) { + final boolean retryPosted = headlessJsTaskContext.retryTask(taskId); + promise.resolve(retryPosted); + } else { + FLog.w( + HeadlessJsTaskSupportModule.class, + "Tried to retry non-active task with id %d. Did it time out?", + taskId); + promise.resolve(false); + } + } + @ReactMethod public void notifyTaskFinished(int taskId) { HeadlessJsTaskContext headlessJsTaskContext = From 14f249178ef46db9dc1e1200c9ce5a27fc25524a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rain=20=E2=81=A3?= Date: Thu, 6 Jun 2019 19:36:56 -0700 Subject: [PATCH 0226/1084] standardize C-like MIT copyright headers throughout fbsource Summary: `/*` is the standard throughout open source code. For example, Firefox uses single /*: https://hg.mozilla.org/mozilla-central/file/21d22b2f541258d3d1cf96c7ba5ad73e96e616b5/gfx/ipc/CompositorWidgetVsyncObserver.cpp#l3 In addition, Rust considers `/**` to be a doc comment (similar to Javadoc) and having such a comment at the beginning of the file causes `rustc` to barf. Note that some JavaScript tooling requires `/**`. This is OK since JavaScript files were not covered by the linter in the first place, but it would be good to have that tooling fixed too. Reviewed By: zertosh Differential Revision: D15640366 fbshipit-source-id: b4ed4599071516364d6109720750d6a43304c089 --- ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp | 2 +- ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.cpp | 2 +- ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.h | 2 +- ReactCommon/jsi/jsi/JSIDynamic.cpp | 2 +- ReactCommon/jsi/jsi/JSIDynamic.h | 2 +- ReactCommon/jsi/jsi/decorator.h | 2 +- ReactCommon/jsi/jsi/instrumentation.h | 2 +- ReactCommon/jsi/jsi/jsi-inl.h | 2 +- ReactCommon/jsi/jsi/jsi.cpp | 2 +- ReactCommon/jsi/jsi/jsi.h | 2 +- ReactCommon/jsi/jsi/jsilib-posix.cpp | 2 +- ReactCommon/jsi/jsi/jsilib-windows.cpp | 2 +- ReactCommon/jsi/jsi/jsilib.h | 2 +- ReactCommon/jsi/jsi/test/testlib.cpp | 2 +- ReactCommon/jsi/jsi/test/testlib.h | 2 +- ReactCommon/jsi/jsi/threadsafe.h | 2 +- ReactCommon/yoga/yoga/CompactValue.h | 2 +- ReactCommon/yoga/yoga/Utils.cpp | 2 +- ReactCommon/yoga/yoga/Utils.h | 2 +- ReactCommon/yoga/yoga/YGConfig.cpp | 2 +- ReactCommon/yoga/yoga/YGConfig.h | 2 +- ReactCommon/yoga/yoga/YGEnums.cpp | 2 +- ReactCommon/yoga/yoga/YGEnums.h | 2 +- ReactCommon/yoga/yoga/YGFloatOptional.h | 2 +- ReactCommon/yoga/yoga/YGLayout.cpp | 2 +- ReactCommon/yoga/yoga/YGLayout.h | 2 +- ReactCommon/yoga/yoga/YGMacros.h | 2 +- ReactCommon/yoga/yoga/YGMarker.cpp | 2 +- ReactCommon/yoga/yoga/YGMarker.h | 2 +- ReactCommon/yoga/yoga/YGNode.cpp | 2 +- ReactCommon/yoga/yoga/YGNode.h | 2 +- ReactCommon/yoga/yoga/YGNodePrint.cpp | 2 +- ReactCommon/yoga/yoga/YGNodePrint.h | 2 +- ReactCommon/yoga/yoga/YGStyle.cpp | 2 +- ReactCommon/yoga/yoga/YGStyle.h | 2 +- ReactCommon/yoga/yoga/YGValue.cpp | 2 +- ReactCommon/yoga/yoga/YGValue.h | 2 +- ReactCommon/yoga/yoga/Yoga-internal.h | 2 +- ReactCommon/yoga/yoga/Yoga.cpp | 2 +- ReactCommon/yoga/yoga/Yoga.h | 2 +- ReactCommon/yoga/yoga/event/event.cpp | 2 +- ReactCommon/yoga/yoga/event/event.h | 2 +- ReactCommon/yoga/yoga/instrumentation.h | 2 +- ReactCommon/yoga/yoga/log.cpp | 2 +- ReactCommon/yoga/yoga/log.h | 2 +- 45 files changed, 45 insertions(+), 45 deletions(-) diff --git a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp index 28011661441036..5a2ce90cc6bdaa 100644 --- a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp +++ b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.cpp b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.cpp index 6be244958b827d..032be5c5e499aa 100644 --- a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.cpp +++ b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.h b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.h index c2c5fc518e3070..21bf395977592b 100644 --- a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.h +++ b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/jsi/jsi/JSIDynamic.cpp b/ReactCommon/jsi/jsi/JSIDynamic.cpp index f63254e94fbe8a..2640c81c3faf87 100644 --- a/ReactCommon/jsi/jsi/JSIDynamic.cpp +++ b/ReactCommon/jsi/jsi/JSIDynamic.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/jsi/jsi/JSIDynamic.h b/ReactCommon/jsi/jsi/JSIDynamic.h index be28b532eb7e7d..2ad0f55c7601b9 100644 --- a/ReactCommon/jsi/jsi/JSIDynamic.h +++ b/ReactCommon/jsi/jsi/JSIDynamic.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/jsi/jsi/decorator.h b/ReactCommon/jsi/jsi/decorator.h index ac30bbe58544a1..c073569287bfd2 100644 --- a/ReactCommon/jsi/jsi/decorator.h +++ b/ReactCommon/jsi/jsi/decorator.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/jsi/jsi/instrumentation.h b/ReactCommon/jsi/jsi/instrumentation.h index f10fb69fbe88fb..595e6889c1c081 100644 --- a/ReactCommon/jsi/jsi/instrumentation.h +++ b/ReactCommon/jsi/jsi/instrumentation.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/jsi/jsi/jsi-inl.h b/ReactCommon/jsi/jsi/jsi-inl.h index c15d22f6e44965..5e53f7191b7db3 100644 --- a/ReactCommon/jsi/jsi/jsi-inl.h +++ b/ReactCommon/jsi/jsi/jsi-inl.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/jsi/jsi/jsi.cpp b/ReactCommon/jsi/jsi/jsi.cpp index 719dd9310b499e..90ec784ef2eeca 100644 --- a/ReactCommon/jsi/jsi/jsi.cpp +++ b/ReactCommon/jsi/jsi/jsi.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/jsi/jsi/jsi.h b/ReactCommon/jsi/jsi/jsi.h index 14334d2c4fc258..c05c5ae369bffc 100644 --- a/ReactCommon/jsi/jsi/jsi.h +++ b/ReactCommon/jsi/jsi/jsi.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/jsi/jsi/jsilib-posix.cpp b/ReactCommon/jsi/jsi/jsilib-posix.cpp index e020437ab7175c..91c9e3820da811 100644 --- a/ReactCommon/jsi/jsi/jsilib-posix.cpp +++ b/ReactCommon/jsi/jsi/jsilib-posix.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/jsi/jsi/jsilib-windows.cpp b/ReactCommon/jsi/jsi/jsilib-windows.cpp index 69581bbbeab567..d01c0e341b757a 100644 --- a/ReactCommon/jsi/jsi/jsilib-windows.cpp +++ b/ReactCommon/jsi/jsi/jsilib-windows.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/jsi/jsi/jsilib.h b/ReactCommon/jsi/jsi/jsilib.h index 49967f4aa449f4..5a359619bd7d78 100644 --- a/ReactCommon/jsi/jsi/jsilib.h +++ b/ReactCommon/jsi/jsi/jsilib.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/jsi/jsi/test/testlib.cpp b/ReactCommon/jsi/jsi/test/testlib.cpp index 640fb133570395..71e2bf4389aa91 100644 --- a/ReactCommon/jsi/jsi/test/testlib.cpp +++ b/ReactCommon/jsi/jsi/test/testlib.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/jsi/jsi/test/testlib.h b/ReactCommon/jsi/jsi/test/testlib.h index 604fc044d6f773..ef8adda4a45403 100644 --- a/ReactCommon/jsi/jsi/test/testlib.h +++ b/ReactCommon/jsi/jsi/test/testlib.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/jsi/jsi/threadsafe.h b/ReactCommon/jsi/jsi/threadsafe.h index 2e1fb918b11341..aeef85fa3b95e3 100644 --- a/ReactCommon/jsi/jsi/threadsafe.h +++ b/ReactCommon/jsi/jsi/threadsafe.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/CompactValue.h b/ReactCommon/yoga/yoga/CompactValue.h index 2045177951a81d..899dcc58c26048 100644 --- a/ReactCommon/yoga/yoga/CompactValue.h +++ b/ReactCommon/yoga/yoga/CompactValue.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/Utils.cpp b/ReactCommon/yoga/yoga/Utils.cpp index 38b686c581a7bd..8864155bd7cc34 100644 --- a/ReactCommon/yoga/yoga/Utils.cpp +++ b/ReactCommon/yoga/yoga/Utils.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/Utils.h b/ReactCommon/yoga/yoga/Utils.h index 900ccb1bee6736..d6fbc26891ffca 100644 --- a/ReactCommon/yoga/yoga/Utils.h +++ b/ReactCommon/yoga/yoga/Utils.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGConfig.cpp b/ReactCommon/yoga/yoga/YGConfig.cpp index 773ad24aba7e96..4e805823d03da3 100644 --- a/ReactCommon/yoga/yoga/YGConfig.cpp +++ b/ReactCommon/yoga/yoga/YGConfig.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGConfig.h b/ReactCommon/yoga/yoga/YGConfig.h index 311c159701b6ff..aaf6d1370efcd4 100644 --- a/ReactCommon/yoga/yoga/YGConfig.h +++ b/ReactCommon/yoga/yoga/YGConfig.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGEnums.cpp b/ReactCommon/yoga/yoga/YGEnums.cpp index ff4b130766f00c..bf5844c57cf092 100644 --- a/ReactCommon/yoga/yoga/YGEnums.cpp +++ b/ReactCommon/yoga/yoga/YGEnums.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGEnums.h b/ReactCommon/yoga/yoga/YGEnums.h index f06b0e045cf9a4..b3c57fb835992f 100644 --- a/ReactCommon/yoga/yoga/YGEnums.h +++ b/ReactCommon/yoga/yoga/YGEnums.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGFloatOptional.h b/ReactCommon/yoga/yoga/YGFloatOptional.h index 7ca1fc12134cba..60fcad99be0049 100644 --- a/ReactCommon/yoga/yoga/YGFloatOptional.h +++ b/ReactCommon/yoga/yoga/YGFloatOptional.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGLayout.cpp b/ReactCommon/yoga/yoga/YGLayout.cpp index 6f55d862ca69be..d1144ea6f26dac 100644 --- a/ReactCommon/yoga/yoga/YGLayout.cpp +++ b/ReactCommon/yoga/yoga/YGLayout.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGLayout.h b/ReactCommon/yoga/yoga/YGLayout.h index 0e559d7429b322..1b30cc8ce29221 100644 --- a/ReactCommon/yoga/yoga/YGLayout.h +++ b/ReactCommon/yoga/yoga/YGLayout.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGMacros.h b/ReactCommon/yoga/yoga/YGMacros.h index badea8c3c3e489..d56f3aeb7377f0 100644 --- a/ReactCommon/yoga/yoga/YGMacros.h +++ b/ReactCommon/yoga/yoga/YGMacros.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGMarker.cpp b/ReactCommon/yoga/yoga/YGMarker.cpp index 21a8d1f6cad4a3..e0758e2308bfa5 100644 --- a/ReactCommon/yoga/yoga/YGMarker.cpp +++ b/ReactCommon/yoga/yoga/YGMarker.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGMarker.h b/ReactCommon/yoga/yoga/YGMarker.h index 89b03684312b6a..625adc2cece8fa 100644 --- a/ReactCommon/yoga/yoga/YGMarker.h +++ b/ReactCommon/yoga/yoga/YGMarker.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGNode.cpp b/ReactCommon/yoga/yoga/YGNode.cpp index 81a4216eb6616a..8941487fb5e097 100644 --- a/ReactCommon/yoga/yoga/YGNode.cpp +++ b/ReactCommon/yoga/yoga/YGNode.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGNode.h b/ReactCommon/yoga/yoga/YGNode.h index 1ef8014214b8e0..cc11cc88d836bd 100644 --- a/ReactCommon/yoga/yoga/YGNode.h +++ b/ReactCommon/yoga/yoga/YGNode.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGNodePrint.cpp b/ReactCommon/yoga/yoga/YGNodePrint.cpp index 301e72a2e28acb..f91d037462ebde 100644 --- a/ReactCommon/yoga/yoga/YGNodePrint.cpp +++ b/ReactCommon/yoga/yoga/YGNodePrint.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGNodePrint.h b/ReactCommon/yoga/yoga/YGNodePrint.h index 13cf367b531adb..8df30e2ccc6427 100644 --- a/ReactCommon/yoga/yoga/YGNodePrint.h +++ b/ReactCommon/yoga/yoga/YGNodePrint.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGStyle.cpp b/ReactCommon/yoga/yoga/YGStyle.cpp index 6672c81faafcf6..a4a7a0473ac1b8 100644 --- a/ReactCommon/yoga/yoga/YGStyle.cpp +++ b/ReactCommon/yoga/yoga/YGStyle.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGStyle.h b/ReactCommon/yoga/yoga/YGStyle.h index 77c7e0386874e7..edefcb7cc9db54 100644 --- a/ReactCommon/yoga/yoga/YGStyle.h +++ b/ReactCommon/yoga/yoga/YGStyle.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGValue.cpp b/ReactCommon/yoga/yoga/YGValue.cpp index fcdd0c6931b007..995f211391afda 100644 --- a/ReactCommon/yoga/yoga/YGValue.cpp +++ b/ReactCommon/yoga/yoga/YGValue.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/YGValue.h b/ReactCommon/yoga/yoga/YGValue.h index 170047ea596197..0405bc6288bd4e 100644 --- a/ReactCommon/yoga/yoga/YGValue.h +++ b/ReactCommon/yoga/yoga/YGValue.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/Yoga-internal.h b/ReactCommon/yoga/yoga/Yoga-internal.h index 4d32a96bcec13d..34c0b077f793e6 100644 --- a/ReactCommon/yoga/yoga/Yoga-internal.h +++ b/ReactCommon/yoga/yoga/Yoga-internal.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index d41a12013cd75d..bf02dd9965cd07 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/Yoga.h b/ReactCommon/yoga/yoga/Yoga.h index a9dc01dcab1f67..6ec796d84b23a8 100644 --- a/ReactCommon/yoga/yoga/Yoga.h +++ b/ReactCommon/yoga/yoga/Yoga.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/event/event.cpp b/ReactCommon/yoga/yoga/event/event.cpp index 02e70dce02eb33..9fc00120935e9b 100644 --- a/ReactCommon/yoga/yoga/event/event.cpp +++ b/ReactCommon/yoga/yoga/event/event.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/event/event.h b/ReactCommon/yoga/yoga/event/event.h index 578d2f3a66a5e8..1937dafcc10c94 100644 --- a/ReactCommon/yoga/yoga/event/event.h +++ b/ReactCommon/yoga/yoga/event/event.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/instrumentation.h b/ReactCommon/yoga/yoga/instrumentation.h index b8691c1865b014..e15f2fb1e45d79 100644 --- a/ReactCommon/yoga/yoga/instrumentation.h +++ b/ReactCommon/yoga/yoga/instrumentation.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/log.cpp b/ReactCommon/yoga/yoga/log.cpp index 62b3d4f0589769..45e5f7b16a3e42 100644 --- a/ReactCommon/yoga/yoga/log.cpp +++ b/ReactCommon/yoga/yoga/log.cpp @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE diff --git a/ReactCommon/yoga/yoga/log.h b/ReactCommon/yoga/yoga/log.h index f25ee1a2b0c397..effe23b5b96a00 100644 --- a/ReactCommon/yoga/yoga/log.h +++ b/ReactCommon/yoga/yoga/log.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the LICENSE From c44b221e134d32a5b60dde0fd5c817773fbfbbdd Mon Sep 17 00:00:00 2001 From: Sidharth Guglani Date: Thu, 6 Jun 2019 20:59:24 -0700 Subject: [PATCH 0227/1084] moved PtrJNode map to YGJtypes.h and passing layout context as data in LayoutPassEnd Event Summary: Move PtrJNodeMap to header file so that it can be accessed in events subscribers outside yoga Reviewed By: davidaurelio Differential Revision: D15619629 fbshipit-source-id: 1bf213efd38ec7bcac6a38070f21fa837c5f17da --- .../jni/first-party/yogajni/jni/YGJNI.cpp | 28 ---------------- .../jni/first-party/yogajni/jni/YGJTypes.h | 33 +++++++++++++++++++ ReactCommon/yoga/yoga/Yoga.cpp | 2 +- ReactCommon/yoga/yoga/event/event.h | 5 +++ 4 files changed, 39 insertions(+), 29 deletions(-) diff --git a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp index 5a2ce90cc6bdaa..f12836816788ac 100644 --- a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp +++ b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp @@ -75,34 +75,6 @@ const short int LAYOUT_BORDER_START_INDEX = 14; bool useBatchingForLayoutOutputs; -class PtrJNodeMap { - using JNodeArray = JArrayClass; - std::map ptrsToIdxs_; - alias_ref javaNodes_; - -public: - PtrJNodeMap() : ptrsToIdxs_{}, javaNodes_{} {} - PtrJNodeMap( - alias_ref nativePointers, - alias_ref javaNodes) - : javaNodes_{javaNodes} { - auto pin = nativePointers->pinCritical(); - auto ptrs = pin.get(); - for (size_t i = 0, n = pin.size(); i < n; ++i) { - ptrsToIdxs_[(YGNodeRef) ptrs[i]] = i; - } - } - - local_ref ref(YGNodeRef node) { - auto idx = ptrsToIdxs_.find(node); - if (idx == ptrsToIdxs_.end()) { - return local_ref{}; - } else { - return javaNodes_->getElement(idx->second); - } - } -}; - namespace { union YGNodeContext { diff --git a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.h b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.h index 21bf395977592b..bd8e6c7b947e53 100644 --- a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.h +++ b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJTypes.h @@ -6,6 +6,11 @@ */ #include #include +#include +#include + +using namespace facebook::jni; +using namespace std; struct JYogaNode : public facebook::jni::JavaClass { static constexpr auto kJavaDescriptor = "Lcom/facebook/yoga/YogaNodeJNIBase;"; @@ -28,3 +33,31 @@ struct JYogaLogger : public facebook::jni::JavaClass { facebook::jni::alias_ref, jstring); }; + +class PtrJNodeMap { + using JNodeArray = JArrayClass; + std::map ptrsToIdxs_; + alias_ref javaNodes_; + +public: + PtrJNodeMap() : ptrsToIdxs_{}, javaNodes_{} {} + PtrJNodeMap( + alias_ref nativePointers, + alias_ref javaNodes) + : javaNodes_{javaNodes} { + auto pin = nativePointers->pinCritical(); + auto ptrs = pin.get(); + for (size_t i = 0, n = pin.size(); i < n; ++i) { + ptrsToIdxs_[(YGNodeRef) ptrs[i]] = i; + } + } + + local_ref ref(YGNodeRef node) { + auto idx = ptrsToIdxs_.find(node); + if (idx == ptrsToIdxs_.end()) { + return local_ref{}; + } else { + return javaNodes_->getElement(idx->second); + } + } +}; diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index bf02dd9965cd07..763d9bfcdca890 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -4093,7 +4093,7 @@ void YGNodeCalculateLayoutWithContext( marker = nullptr; #ifdef YG_ENABLE_EVENTS - Event::publish(node); + Event::publish(node, {layoutContext}); #endif // We want to get rid off `useLegacyStretchBehaviour` from YGConfig. But we diff --git a/ReactCommon/yoga/yoga/event/event.h b/ReactCommon/yoga/yoga/event/event.h index 1937dafcc10c94..f0f427974a5c9c 100644 --- a/ReactCommon/yoga/yoga/event/event.h +++ b/ReactCommon/yoga/yoga/event/event.h @@ -71,5 +71,10 @@ struct Event::TypedData { YGConfig* config; }; +template <> +struct Event::TypedData { + void* layoutContext; +}; + } // namespace yoga } // namespace facebook From 348c3ebefafb881ec839209e01118f8cbcfa162e Mon Sep 17 00:00:00 2001 From: Sidharth Guglani Date: Thu, 6 Jun 2019 20:59:24 -0700 Subject: [PATCH 0228/1084] add node measure event and passing the callback to java layer Summary: Adds measure event and its listener initial code structure Reviewed By: davidaurelio Differential Revision: D15600738 fbshipit-source-id: d15764e0b64edb170fcb15e0912ecce5f7e53595 --- .../main/java/com/facebook/yoga/YogaEventListener.java | 4 +++- ReactCommon/yoga/yoga/Yoga.cpp | 4 ++++ ReactCommon/yoga/yoga/event/event.h | 8 +++++++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaEventListener.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaEventListener.java index 6d1d486be28a44..97791224577d67 100644 --- a/ReactAndroid/src/main/java/com/facebook/yoga/YogaEventListener.java +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaEventListener.java @@ -10,4 +10,6 @@ public interface YogaEventListener { void onLayoutPassEnd(YogaNode node); -} \ No newline at end of file + void onNodeMeasure(YogaNode node); + +} diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index 763d9bfcdca890..c46104be1d33e1 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -1635,6 +1635,10 @@ static void YGNodeWithMeasureFuncSetMeasuredDimensions( heightMeasureMode, layoutContext); +#ifdef YG_ENABLE_EVENTS + Event::publish(node, {layoutContext}); +#endif + node->setLayoutMeasuredDimension( YGNodeBoundAxis( node, diff --git a/ReactCommon/yoga/yoga/event/event.h b/ReactCommon/yoga/yoga/event/event.h index f0f427974a5c9c..bff8dbfd8952fc 100644 --- a/ReactCommon/yoga/yoga/event/event.h +++ b/ReactCommon/yoga/yoga/event/event.h @@ -21,7 +21,8 @@ struct Event { NodeDeallocation, NodeLayout, LayoutPassStart, - LayoutPassEnd + LayoutPassEnd, + NodeMeasure, }; class Data; using Subscriber = void(const YGNode&, Type, Data); @@ -76,5 +77,10 @@ struct Event::TypedData { void* layoutContext; }; +template <> +struct Event::TypedData { + void* layoutContext; +}; + } // namespace yoga } // namespace facebook From d9a8ac5071d23275c5d4a8e9936f391b967416d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D1=91=D1=82=D1=80=20=D0=9F=D0=BE=D1=82=D0=B0=D0=BF?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Fri, 7 Jun 2019 02:44:21 -0700 Subject: [PATCH 0229/1084] Fix: RefreshControl in FlatList makes borderWidth not working (#24411) Summary: Fixes #22752 On line 1021 you are passing base style to props: `style: [baseStyle, this.props.style],` Explicitly passing base style to ScrollView just overrides this line and doesn't let developers to customise style of any inheritors of ScrollView (not only FlatList) with custom RefreshControl. So this line (1113) seems to be removed. ## Changelog [GENERAL] [Fixed] - fix of Android's bug that doesn't let override ScrollView's Style with custom RefreshControl. Pull Request resolved: https://github.com/facebook/react-native/pull/24411 Differential Revision: D15713061 Pulled By: cpojer fbshipit-source-id: 461259800f867af15e53e0743a5057ea4528ae69 --- Libraries/Components/ScrollView/ScrollView.js | 9 +-- .../__tests__/splitLayoutProps-test.js | 44 +++++++++++++ Libraries/StyleSheet/splitLayoutProps.js | 62 +++++++++++++++++++ 3 files changed, 111 insertions(+), 4 deletions(-) create mode 100644 Libraries/StyleSheet/__tests__/splitLayoutProps-test.js create mode 100644 Libraries/StyleSheet/splitLayoutProps.js diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js index f28d77908811fe..260bc0fd94c10d 100644 --- a/Libraries/Components/ScrollView/ScrollView.js +++ b/Libraries/Components/ScrollView/ScrollView.js @@ -25,6 +25,7 @@ const invariant = require('invariant'); const processDecelerationRate = require('./processDecelerationRate'); const requireNativeComponent = require('../../ReactNative/requireNativeComponent'); const resolveAssetSource = require('../../Image/resolveAssetSource'); +const splitLayoutProps = require('../../StyleSheet/splitLayoutProps'); import type { PressEvent, @@ -1125,15 +1126,15 @@ class ScrollView extends React.Component { // On Android wrap the ScrollView with a AndroidSwipeRefreshLayout. // Since the ScrollView is wrapped add the style props to the // AndroidSwipeRefreshLayout and use flex: 1 for the ScrollView. - // Note: we should only apply props.style on the wrapper + // Note: we should split props.style on the inner and outer props // however, the ScrollView still needs the baseStyle to be scrollable - + const {outer, inner} = splitLayoutProps(flattenStyle(props.style)); return React.cloneElement( refreshControl, - {style: props.style}, + {style: [baseStyle, outer]}, {contentContainer} diff --git a/Libraries/StyleSheet/__tests__/splitLayoutProps-test.js b/Libraries/StyleSheet/__tests__/splitLayoutProps-test.js new file mode 100644 index 00000000000000..70b2877ae2cc4d --- /dev/null +++ b/Libraries/StyleSheet/__tests__/splitLayoutProps-test.js @@ -0,0 +1,44 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @emails oncall+react_native + */ + +'use strict'; + +const splitLayoutProps = require('../splitLayoutProps'); + +test('splits style objects', () => { + const style = {width: 10, margin: 20, padding: 30}; + const {outer, inner} = splitLayoutProps(style); + expect(outer).toMatchInlineSnapshot(` + Object { + "margin": 20, + "width": 10, + } + `); + expect(inner).toMatchInlineSnapshot(` + Object { + "padding": 30, + } + `); +}); + +test('does not copy values to both returned objects', () => { + const style = {marginVertical: 5, paddingHorizontal: 10}; + const {outer, inner} = splitLayoutProps(style); + expect(outer).toMatchInlineSnapshot(` + Object { + "marginVertical": 5, + } + `); + expect(inner).toMatchInlineSnapshot(` + Object { + "paddingHorizontal": 10, + } + `); +}); diff --git a/Libraries/StyleSheet/splitLayoutProps.js b/Libraries/StyleSheet/splitLayoutProps.js new file mode 100644 index 00000000000000..700fbea437f893 --- /dev/null +++ b/Libraries/StyleSheet/splitLayoutProps.js @@ -0,0 +1,62 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow strict-local + */ + +'use strict'; + +import type {DangerouslyImpreciseStyle} from './StyleSheet'; + +const OUTER_PROPS = Object.assign(Object.create(null), { + margin: true, + marginHorizontal: true, + marginVertical: true, + marginBottom: true, + marginTop: true, + marginLeft: true, + marginRight: true, + flex: true, + flexGrow: true, + flexShrink: true, + flexBasis: true, + alignSelf: true, + height: true, + minHeight: true, + maxHeight: true, + width: true, + minWidth: true, + maxWidth: true, + position: true, + left: true, + right: true, + bottom: true, + top: true, +}); + +function splitLayoutProps( + props: ?DangerouslyImpreciseStyle, +): { + outer: DangerouslyImpreciseStyle, + inner: DangerouslyImpreciseStyle, +} { + const inner = {}; + const outer = {}; + if (props) { + Object.keys(props).forEach(k => { + const value: $ElementType = props[k]; + if (OUTER_PROPS[k]) { + outer[k] = value; + } else { + inner[k] = value; + } + }); + } + return {outer, inner}; +} + +module.exports = splitLayoutProps; From 3b1dbccaaf90aa05a0b25e4853e6b8d48da1deaf Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Fri, 7 Jun 2019 02:55:28 -0700 Subject: [PATCH 0230/1084] Do a hard reload if hot update can't be applied MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Hot reloading propagates upwards through the inverse dependency tree — from a file you edited, to the files that import it, and so on. However, we can't always reevaluate everything. Many core infra modules can't run twice, and also the more you run, the more the risk of encountering a module with init side effects. So our practical compromise is to stop the propagation when we reach a module whose exports look like React components. We say that such module "accepts" an update. This means that in practice, changes trigger module reevaluation up to the closest component modules from the edited file. (If you edited a component file, it re-executes alone — unless it exports a non-component.) However, current implementation has a problem. Sometimes there is an inverse dependency path that has no "accepting" modules whatsoever. For example, maybe you're editing some core module, and its inverse dependency tree reaches goes into React Native itself. Or maybe it reaches the entry point with a bunch of side effects that can't be repeated, like registering the app root component. In the past, such cases would lead to confusing errors like "Expected `FBPrelude.conclude()` to have been called" after hot reload. This was because we kept re-executing modules all the way upwards, even if there is nothing that can accept the update on the path. Eventually we'd reach top-level modules in the import graph that don't like to run twice. This diff changes the logic so that we *don't attempt* to re-execute the module factories if we know that some inverse dependency path doesn't terminate in a component. In that case we know we simply *can't apply the hot update* because it doesn't stop at a point we can handle, like a React component. Since the hot update fails in this case, I'm making it fall back to a regular reload. This is similar to how webpack handles a similar situation on the web. This means that hot updates normally don't refresh, but if we can't apply a hot update to this file, we do refresh automatically. Reviewed By: cpojer Differential Revision: D15631864 fbshipit-source-id: 52cd1b03739fd760f1b1b1ab8c7276a150cc3c4c --- Libraries/Core/InitializeCore.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Libraries/Core/InitializeCore.js b/Libraries/Core/InitializeCore.js index 263001547b6132..a3e19687e4bb46 100644 --- a/Libraries/Core/InitializeCore.js +++ b/Libraries/Core/InitializeCore.js @@ -42,6 +42,15 @@ require('./setUpSegmentFetcher'); if (__DEV__) { require('./checkNativeVersion'); require('./setUpDeveloperTools'); + + // This is used by the require.js polyfill for hot reloading. + // TODO(t9759686) Scan polyfills for dependencies, too + const reload = require('../NativeModules/specs/NativeDevSettings').default + .reload; + if (typeof reload !== 'function') { + throw new Error('Could not find the reload() implementation.'); + } + (require: any).reload = reload; } const GlobalPerformanceLogger = require('../Utilities/GlobalPerformanceLogger'); From ea090a10e63bb75ab9446ed2bd84647bf3d28bd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Fri, 7 Jun 2019 03:04:54 -0700 Subject: [PATCH 0231/1084] Bump CLI to 2.0.0-rc.0 (#25175) Summary: Upgrading the CLI to the latest with a bunch of fixes and features included. ## Changelog [General] [Changed] - Bump CLI to 2.0.0-rc.0 Pull Request resolved: https://github.com/facebook/react-native/pull/25175 Differential Revision: D15694764 Pulled By: cpojer fbshipit-source-id: 25fbf1c275ed5379e1cdb372512b6bb6327dea92 --- jest/hasteImpl.js | 16 ---------------- package.json | 6 +++--- yarn.lock | 42 +++++++++++++++++++++--------------------- 3 files changed, 24 insertions(+), 40 deletions(-) delete mode 100644 jest/hasteImpl.js diff --git a/jest/hasteImpl.js b/jest/hasteImpl.js deleted file mode 100644 index d1c1fad686ba5d..00000000000000 --- a/jest/hasteImpl.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -'use strict'; - -module.exports = { - getHasteName() { - return undefined; - }, -}; diff --git a/package.json b/package.json index 0be5ffb403a123..0a3190a401376a 100644 --- a/package.json +++ b/package.json @@ -82,9 +82,9 @@ }, "dependencies": { "@babel/runtime": "^7.0.0", - "@react-native-community/cli": "2.0.0-alpha.23", - "@react-native-community/cli-platform-android": "2.0.0-alpha.23", - "@react-native-community/cli-platform-ios": "2.0.0-alpha.23", + "@react-native-community/cli": "2.0.0-rc.0", + "@react-native-community/cli-platform-android": "2.0.0-rc.0", + "@react-native-community/cli-platform-ios": "2.0.0-rc.0", "abort-controller": "^3.0.0", "art": "^0.10.0", "base64-js": "^1.1.2", diff --git a/yarn.lock b/yarn.lock index 9c5859f6db42db..b39d6f59e1a8d3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1090,44 +1090,44 @@ "@types/istanbul-lib-coverage" "^2.0.0" "@types/yargs" "^12.0.9" -"@react-native-community/cli-platform-android@2.0.0-alpha.23", "@react-native-community/cli-platform-android@^2.0.0-alpha.23": - version "2.0.0-alpha.23" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-android/-/cli-platform-android-2.0.0-alpha.23.tgz#f4941cca17eedef694bf420027b816ecd2e1f1c3" - integrity sha512-V57NWTyi20VQA2EPL1xmiibIQD0bUVe0ecVQxSb903f4M3ml0x4TEqWOToE2wgda/c4Z3pEKJuRCzyZHfuEYPA== +"@react-native-community/cli-platform-android@2.0.0-rc.0", "@react-native-community/cli-platform-android@^2.0.0-rc.0": + version "2.0.0-rc.0" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-android/-/cli-platform-android-2.0.0-rc.0.tgz#8fcc57a68b3f971d322034c21ba09c580ce5455a" + integrity sha512-i9xCMx1AFTscFlEsUJZVn5r6h7ndjvBUUTgLR/4oV639Bcwlci3OvKD1bV5fdp1/L9Mv14iuDo7y1Jv9ubRi5w== dependencies: - "@react-native-community/cli-tools" "^2.0.0-alpha.23" + "@react-native-community/cli-tools" "^2.0.0-rc.0" logkitty "^0.4.0" slash "^2.0.0" xmldoc "^0.4.0" -"@react-native-community/cli-platform-ios@2.0.0-alpha.23", "@react-native-community/cli-platform-ios@^2.0.0-alpha.23": - version "2.0.0-alpha.23" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-ios/-/cli-platform-ios-2.0.0-alpha.23.tgz#3ef22cc5d5ce32b85f9f9604056ca3cea652a59a" - integrity sha512-jAffpJNw9zrlI5rwM/BfaTNtKjrx+Rvuei1YqfjLaQKUiXgrbJYbIu9+6Lc+sAn1qFGwL2+CShpywwbvN2ehGQ== +"@react-native-community/cli-platform-ios@2.0.0-rc.0", "@react-native-community/cli-platform-ios@^2.0.0-rc.0": + version "2.0.0-rc.0" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-ios/-/cli-platform-ios-2.0.0-rc.0.tgz#00489529d1715c80042a1649b0c6822aa7c785ba" + integrity sha512-v1BxVFHrrypI9XVtwtq0FPtZHusvCouPbpX7c4h4SiP66KT/+eAYVuOTpjSN+EMss/WZLeJKIPOiBn2ZohxcwA== dependencies: - "@react-native-community/cli-tools" "^2.0.0-alpha.23" + "@react-native-community/cli-tools" "^2.0.0-rc.0" chalk "^1.1.1" xcode "^2.0.0" -"@react-native-community/cli-tools@^2.0.0-alpha.23": - version "2.0.0-alpha.23" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-tools/-/cli-tools-2.0.0-alpha.23.tgz#001a6ef134e1488bf8ef41dd203fda67f7aed8d6" - integrity sha512-+a+IByj0EXQg6M3Q0aT1hsGSmmqWPPkrx+LeY4Gi2pnmOR+DB9A/dDEDOvwxd/OPBsXqzNmdO+iUcg3HNm/twg== +"@react-native-community/cli-tools@^2.0.0-rc.0": + version "2.0.0-rc.0" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-tools/-/cli-tools-2.0.0-rc.0.tgz#82eedb621921b4511a0a98dbc98eedc12bd98b9b" + integrity sha512-svdIsrcd905lberrY7jVMrHsoCy5PkVgJeiloMFjV6nPTPaKF7ujw2ftdUp9P66KRb7y/IMT5/4EDtntr8SkGg== dependencies: chalk "^1.1.1" lodash "^4.17.5" mime "^2.4.1" node-fetch "^2.5.0" -"@react-native-community/cli@2.0.0-alpha.23": - version "2.0.0-alpha.23" - resolved "https://registry.yarnpkg.com/@react-native-community/cli/-/cli-2.0.0-alpha.23.tgz#321ea633ffdf1160170e4428b5886f4d731ff373" - integrity sha512-NIIRgdqA1IA3+K1l1jcXEtS0qL0aos75GXVwGBOmEkC4TfNoOpVQZl2Ffy+/j+IPGpzl2xecOMMmIvlzQRGDtQ== +"@react-native-community/cli@2.0.0-rc.0": + version "2.0.0-rc.0" + resolved "https://registry.yarnpkg.com/@react-native-community/cli/-/cli-2.0.0-rc.0.tgz#fcc7551e93bc5fad456d26396de3b91b20ae7190" + integrity sha512-juHl7U3DSYjTexWmTiN54YSK52dM2nz0P2sJipZkJLbYSsSJTtvLiRWIKzaG/1Q03EfPp3DbkYTOXQMEERzQEg== dependencies: "@hapi/joi" "^15.0.3" - "@react-native-community/cli-platform-android" "^2.0.0-alpha.23" - "@react-native-community/cli-platform-ios" "^2.0.0-alpha.23" - "@react-native-community/cli-tools" "^2.0.0-alpha.23" + "@react-native-community/cli-platform-android" "^2.0.0-rc.0" + "@react-native-community/cli-platform-ios" "^2.0.0-rc.0" + "@react-native-community/cli-tools" "^2.0.0-rc.0" chalk "^1.1.1" command-exists "^1.2.8" commander "^2.19.0" From 93b9ac74e59bbe84ea388d7c1879857b4acab114 Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Fri, 7 Jun 2019 06:35:19 -0700 Subject: [PATCH 0232/1084] Remove Map/Set from RN Open Source Summary: This is the same diff as D14786123 but with one of the buck targets fixed that only failed on continuous and didn't run during land time. This moves Map/Set to fb internal. We do not need them in open source any more but we still need this in some apps at FB that use an old version of JSC. Reviewed By: rickhanlonii Differential Revision: D15713305 fbshipit-source-id: caec43c76a6255b2af1693c13d8dea31d7d674f5 --- Libraries/Core/InitializeCore.js | 1 - .../Core/__tests__/MapAndSetPolyfills-test.js | 102 --- Libraries/Core/polyfillES6Collections.js | 27 - Libraries/vendor/core/Map.js | 590 ------------------ Libraries/vendor/core/Set.js | 198 ------ .../core/_shouldPolyfillES6Collection.js | 66 -- flow/Map.js | 40 -- flow/Set.js | 36 -- 8 files changed, 1060 deletions(-) delete mode 100644 Libraries/Core/__tests__/MapAndSetPolyfills-test.js delete mode 100644 Libraries/Core/polyfillES6Collections.js delete mode 100644 Libraries/vendor/core/Map.js delete mode 100644 Libraries/vendor/core/Set.js delete mode 100644 Libraries/vendor/core/_shouldPolyfillES6Collection.js delete mode 100644 flow/Map.js delete mode 100644 flow/Set.js diff --git a/Libraries/Core/InitializeCore.js b/Libraries/Core/InitializeCore.js index a3e19687e4bb46..d1807071d03eb3 100644 --- a/Libraries/Core/InitializeCore.js +++ b/Libraries/Core/InitializeCore.js @@ -28,7 +28,6 @@ const start = Date.now(); require('./setUpGlobals'); -require('./polyfillES6Collections'); require('./setUpSystrace'); require('./setUpErrorHandling'); require('./polyfillPromise'); diff --git a/Libraries/Core/__tests__/MapAndSetPolyfills-test.js b/Libraries/Core/__tests__/MapAndSetPolyfills-test.js deleted file mode 100644 index 20f54a0e68d9d5..00000000000000 --- a/Libraries/Core/__tests__/MapAndSetPolyfills-test.js +++ /dev/null @@ -1,102 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @emails oncall+react_native - */ -'use strict'; - -// Save these methods so that we can restore them afterward. -const {freeze, seal, preventExtensions} = Object; - -function setup() { - jest.setMock('../../vendor/core/_shouldPolyfillES6Collection', () => true); -} - -function cleanup() { - Object.assign(Object, {freeze, seal, preventExtensions}); -} - -describe('Map polyfill', () => { - setup(); - - const Map = require('../../vendor/core/Map'); - - it('is not native', () => { - const getCode = Function.prototype.toString.call(Map.prototype.get); - expect(getCode).not.toContain('[native code]'); - expect(getCode).toContain('getIndex'); - }); - - it('should tolerate non-extensible object keys', () => { - const map = new Map(); - const key = Object.create(null); - Object.freeze(key); - map.set(key, key); - expect(map.size).toBe(1); - expect(map.has(key)).toBe(true); - map.delete(key); - expect(map.size).toBe(0); - expect(map.has(key)).toBe(false); - }); - - it('should not get confused by prototypal inheritance', () => { - const map = new Map(); - const proto = Object.create(null); - const base = Object.create(proto); - map.set(proto, proto); - expect(map.size).toBe(1); - expect(map.has(proto)).toBe(true); - expect(map.has(base)).toBe(false); - map.set(base, base); - expect(map.size).toBe(2); - expect(map.get(proto)).toBe(proto); - expect(map.get(base)).toBe(base); - }); - - afterAll(cleanup); -}); - -describe('Set polyfill', () => { - setup(); - - const Set = require('../../vendor/core/Set'); - - it('is not native', () => { - const addCode = Function.prototype.toString.call(Set.prototype.add); - expect(addCode).not.toContain('[native code]'); - }); - - it('should tolerate non-extensible object elements', () => { - const set = new Set(); - const elem = Object.create(null); - Object.freeze(elem); - set.add(elem); - expect(set.size).toBe(1); - expect(set.has(elem)).toBe(true); - set.add(elem); - expect(set.size).toBe(1); - set.delete(elem); - expect(set.size).toBe(0); - expect(set.has(elem)).toBe(false); - }); - - it('should not get confused by prototypal inheritance', () => { - const set = new Set(); - const proto = Object.create(null); - const base = Object.create(proto); - set.add(proto); - expect(set.size).toBe(1); - expect(set.has(proto)).toBe(true); - expect(set.has(base)).toBe(false); - set.add(base); - expect(set.size).toBe(2); - expect(set.has(proto)).toBe(true); - expect(set.has(base)).toBe(true); - }); - - afterAll(cleanup); -}); diff --git a/Libraries/Core/polyfillES6Collections.js b/Libraries/Core/polyfillES6Collections.js deleted file mode 100644 index b58718540fedca..00000000000000 --- a/Libraries/Core/polyfillES6Collections.js +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow strict-local - * @format - */ -'use strict'; - -const {polyfillGlobal} = require('../Utilities/PolyfillFunctions'); - -/** - * Polyfill ES6 collections (Map and Set). - * If you don't need these polyfills, don't use InitializeCore; just directly - * require the modules you need from InitializeCore for setup. - */ -const _shouldPolyfillCollection = require('../vendor/core/_shouldPolyfillES6Collection'); -if (_shouldPolyfillCollection('Map')) { - // $FlowFixMe: even in strict-local mode Flow expects Map to be Flow-typed - polyfillGlobal('Map', () => require('../vendor/core/Map')); -} -if (_shouldPolyfillCollection('Set')) { - // $FlowFixMe: even in strict-local mode Flow expects Set to be Flow-typed - polyfillGlobal('Set', () => require('../vendor/core/Set')); -} diff --git a/Libraries/vendor/core/Map.js b/Libraries/vendor/core/Map.js deleted file mode 100644 index 4f23b1f4783ab8..00000000000000 --- a/Libraries/vendor/core/Map.js +++ /dev/null @@ -1,590 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @preventMunge - * @typechecks - */ - -/* eslint-disable no-extend-native, no-shadow-restricted-names */ - -'use strict'; - -const _shouldPolyfillES6Collection = require('./_shouldPolyfillES6Collection'); -const guid = require('./guid'); -const toIterator = require('./toIterator'); - -module.exports = (function(global, undefined) { - // Since our implementation is spec-compliant for the most part we can safely - // delegate to a built-in version if exists and is implemented correctly. - // Firefox had gotten a few implementation details wrong across different - // versions so we guard against that. - if (!_shouldPolyfillES6Collection('Map')) { - return global.Map; - } - - const hasOwn = Object.prototype.hasOwnProperty; - - /** - * == ES6 Map Collection == - * - * This module is meant to implement a Map collection as described in chapter - * 23.1 of the ES6 specification. - * - * Map objects are collections of key/value pairs where both the keys and - * values may be arbitrary ECMAScript language values. A distinct key value - * may only occur in one key/value pair within the Map's collection. - * - * https://people.mozilla.org/~jorendorff/es6-draft.html#sec-map-objects - * - * There only two -- rather small -- deviations from the spec: - * - * 1. The use of untagged frozen objects as keys. - * We decided not to allow and simply throw an error, because this - * implementation of Map works by tagging objects used as Map keys - * with a secret hash property for fast access to the object's place - * in the internal _mapData array. However, to limit the impact of - * this spec deviation, Libraries/Core/InitializeCore.js also wraps - * Object.freeze, Object.seal, and Object.preventExtensions so that - * they tag objects before making them non-extensible, by inserting - * each object into a Map and then immediately removing it. - * - * 2. The `size` property on a map object is a regular property and not a - * computed property on the prototype as described by the spec. - * The reason being is that we simply want to support ES3 environments - * which doesn't implement computed properties. - * - * == Usage == - * - * var map = new Map(iterable); - * - * map.set(key, value); - * map.get(key); // value - * map.has(key); // true - * map.delete(key); // true - * - * var iterator = map.keys(); - * iterator.next(); // {value: key, done: false} - * - * var iterator = map.values(); - * iterator.next(); // {value: value, done: false} - * - * var iterator = map.entries(); - * iterator.next(); // {value: [key, value], done: false} - * - * map.forEach(function(value, key){ this === thisArg }, thisArg); - * - * map.clear(); // resets map. - */ - - /** - * Constants - */ - - // Kinds of map iterations 23.1.5.3 - const KIND_KEY = 'key'; - const KIND_VALUE = 'value'; - const KIND_KEY_VALUE = 'key+value'; - - // In older browsers we can't create a null-prototype object so we have to - // defend against key collisions with built-in methods. - const KEY_PREFIX = '$map_'; - - // This property will be used as the internal size variable to disallow - // writing and to issue warnings for writings in development. - let SECRET_SIZE_PROP; - if (__DEV__) { - SECRET_SIZE_PROP = '$size' + guid(); - } - - class Map { - /** - * 23.1.1.1 - * Takes an `iterable` which is basically any object that implements a - * Symbol.iterator (@@iterator) method. The iterable is expected to be a - * collection of pairs. Each pair is a key/value pair that will be used - * to instantiate the map. - * - * @param {*} iterable - */ - constructor(iterable) { - if (!isObject(this)) { - throw new TypeError('Wrong map object type.'); - } - - initMap(this); - - if (iterable != null) { - const it = toIterator(iterable); - let next; - while (!(next = it.next()).done) { - if (!isObject(next.value)) { - throw new TypeError('Expected iterable items to be pair objects.'); - } - this.set(next.value[0], next.value[1]); - } - } - } - - /** - * 23.1.3.1 - * Clears the map from all keys and values. - */ - clear() { - initMap(this); - } - - /** - * 23.1.3.7 - * Check if a key exists in the collection. - * - * @param {*} key - * @return {boolean} - */ - has(key) { - const index = getIndex(this, key); - return !!(index != null && this._mapData[index]); - } - - /** - * 23.1.3.9 - * Adds a key/value pair to the collection. - * - * @param {*} key - * @param {*} value - * @return {map} - */ - set(key, value) { - let index = getIndex(this, key); - - if (index != null && this._mapData[index]) { - this._mapData[index][1] = value; - } else { - index = this._mapData.push([key, value]) - 1; - setIndex(this, key, index); - if (__DEV__) { - this[SECRET_SIZE_PROP] += 1; - } else { - this.size += 1; - } - } - - return this; - } - - /** - * 23.1.3.6 - * Gets a value associated with a key in the collection. - * - * @param {*} key - * @return {*} - */ - get(key) { - const index = getIndex(this, key); - if (index == null) { - return undefined; - } else { - return this._mapData[index][1]; - } - } - - /** - * 23.1.3.3 - * Delete a key/value from the collection. - * - * @param {*} key - * @return {boolean} Whether the key was found and deleted. - */ - delete(key) { - const index = getIndex(this, key); - if (index != null && this._mapData[index]) { - setIndex(this, key, undefined); - this._mapData[index] = undefined; - if (__DEV__) { - this[SECRET_SIZE_PROP] -= 1; - } else { - this.size -= 1; - } - return true; - } else { - return false; - } - } - - /** - * 23.1.3.4 - * Returns an iterator over the key/value pairs (in the form of an Array) in - * the collection. - * - * @return {MapIterator} - */ - entries() { - return new MapIterator(this, KIND_KEY_VALUE); - } - - /** - * 23.1.3.8 - * Returns an iterator over the keys in the collection. - * - * @return {MapIterator} - */ - keys() { - return new MapIterator(this, KIND_KEY); - } - - /** - * 23.1.3.11 - * Returns an iterator over the values pairs in the collection. - * - * @return {MapIterator} - */ - values() { - return new MapIterator(this, KIND_VALUE); - } - - /** - * 23.1.3.5 - * Iterates over the key/value pairs in the collection calling `callback` - * with [value, key, map]. An optional `thisArg` can be passed to set the - * context when `callback` is called. - * - * @param {function} callback - * @param {?object} thisArg - */ - forEach(callback, thisArg) { - if (typeof callback !== 'function') { - throw new TypeError('Callback must be callable.'); - } - - const boundCallback = callback.bind(thisArg || undefined); - const mapData = this._mapData; - - // Note that `mapData.length` should be computed on each iteration to - // support iterating over new items in the map that were added after the - // start of the iteration. - for (let i = 0; i < mapData.length; i++) { - const entry = mapData[i]; - if (entry != null) { - boundCallback(entry[1], entry[0], this); - } - } - } - } - - // 23.1.3.12 - Map.prototype[toIterator.ITERATOR_SYMBOL] = Map.prototype.entries; - - class MapIterator { - /** - * 23.1.5.1 - * Create a `MapIterator` for a given `map`. While this class is private it - * will create objects that will be passed around publicily. - * - * @param {map} map - * @param {string} kind - */ - constructor(map, kind) { - if (!(isObject(map) && map._mapData)) { - throw new TypeError('Object is not a map.'); - } - - if ([KIND_KEY, KIND_KEY_VALUE, KIND_VALUE].indexOf(kind) === -1) { - throw new Error('Invalid iteration kind.'); - } - - this._map = map; - this._nextIndex = 0; - this._kind = kind; - } - - /** - * 23.1.5.2.1 - * Get the next iteration. - * - * @return {object} - */ - next() { - if (!this instanceof Map) { - throw new TypeError('Expected to be called on a MapIterator.'); - } - - const map = this._map; - let index = this._nextIndex; - const kind = this._kind; - - if (map == null) { - return createIterResultObject(undefined, true); - } - - const entries = map._mapData; - - while (index < entries.length) { - const record = entries[index]; - - index += 1; - this._nextIndex = index; - - if (record) { - if (kind === KIND_KEY) { - return createIterResultObject(record[0], false); - } else if (kind === KIND_VALUE) { - return createIterResultObject(record[1], false); - } else if (kind) { - return createIterResultObject(record, false); - } - } - } - - this._map = undefined; - - return createIterResultObject(undefined, true); - } - } - - // We can put this in the class definition once we have computed props - // transform. - // 23.1.5.2.2 - MapIterator.prototype[toIterator.ITERATOR_SYMBOL] = function() { - return this; - }; - - /** - * Helper Functions. - */ - - /** - * Return an index to map.[[MapData]] array for a given Key. - * - * @param {map} map - * @param {*} key - * @return {?number} - */ - function getIndex(map, key) { - if (isObject(key)) { - const hash = getHash(key); - return map._objectIndex[hash]; - } else { - const prefixedKey = KEY_PREFIX + key; - if (typeof key === 'string') { - return map._stringIndex[prefixedKey]; - } else { - return map._otherIndex[prefixedKey]; - } - } - } - - /** - * Setup an index that refer to the key's location in map.[[MapData]]. - * - * @param {map} map - * @param {*} key - */ - function setIndex(map, key, index) { - const shouldDelete = index == null; - - if (isObject(key)) { - const hash = getHash(key); - if (shouldDelete) { - delete map._objectIndex[hash]; - } else { - map._objectIndex[hash] = index; - } - } else { - const prefixedKey = KEY_PREFIX + key; - if (typeof key === 'string') { - if (shouldDelete) { - delete map._stringIndex[prefixedKey]; - } else { - map._stringIndex[prefixedKey] = index; - } - } else { - if (shouldDelete) { - delete map._otherIndex[prefixedKey]; - } else { - map._otherIndex[prefixedKey] = index; - } - } - } - } - - /** - * Instantiate a map with internal slots. - * - * @param {map} map - */ - function initMap(map) { - // Data structure design inspired by Traceur's Map implementation. - // We maintain an internal array for all the entries. The array is needed - // to remember order. However, to have a reasonable HashMap performance - // i.e. O(1) for insertion, deletion, and retrieval. We maintain indices - // in objects for fast look ups. Indices are split up according to data - // types to avoid collisions. - map._mapData = []; - - // Object index maps from an object "hash" to index. The hash being a unique - // property of our choosing that we associate with the object. Association - // is done by ways of keeping a non-enumerable property on the object. - // Ideally these would be `Object.create(null)` objects but since we're - // trying to support ES3 we'll have to guard against collisions using - // prefixes on the keys rather than rely on null prototype objects. - map._objectIndex = {}; - - // String index maps from strings to index. - map._stringIndex = {}; - - // Numbers, booleans, undefined, and null. - map._otherIndex = {}; - - // Unfortunately we have to support ES3 and cannot have `Map.prototype.size` - // be a getter method but just a regular method. The biggest problem with - // this is safety. Clients can change the size property easily and possibly - // without noticing (e.g. `if (map.size = 1) {..}` kind of typo). What we - // can do to mitigate use getters and setters in development to disallow - // and issue a warning for changing the `size` property. - if (__DEV__) { - if (isES5) { - // If the `SECRET_SIZE_PROP` property is already defined then we're not - // in the first call to `initMap` (e.g. coming from `map.clear()`) so - // all we need to do is reset the size without defining the properties. - if (hasOwn.call(map, SECRET_SIZE_PROP)) { - map[SECRET_SIZE_PROP] = 0; - } else { - Object.defineProperty(map, SECRET_SIZE_PROP, { - value: 0, - writable: true, - }); - Object.defineProperty(map, 'size', { - set: v => { - console.error( - 'PLEASE FIX ME: You are changing the map size property which ' + - 'should not be writable and will break in production.', - ); - throw new Error('The map size property is not writable.'); - }, - get: () => map[SECRET_SIZE_PROP], - }); - } - - // NOTE: Early return to implement immutable `.size` in DEV. - return; - } - } - - // This is a diviation from the spec. `size` should be a getter on - // `Map.prototype`. However, we have to support IE8. - map.size = 0; - } - - /** - * Check if something is an object. - * - * @param {*} o - * @return {boolean} - */ - function isObject(o) { - return o != null && (typeof o === 'object' || typeof o === 'function'); - } - - /** - * Create an iteration object. - * - * @param {*} value - * @param {boolean} done - * @return {object} - */ - function createIterResultObject(value, done) { - return {value, done}; - } - - // Are we in a legit ES5 environment. Spoiler alert: that doesn't include IE8. - const isES5 = (function() { - try { - Object.defineProperty({}, 'x', {}); - return true; - } catch (e) { - return false; - } - })(); - - /** - * Check if an object can be extended. - * - * @param {object|array|function|regexp} o - * @return {boolean} - */ - function isExtensible(o) { - if (!isES5) { - return true; - } else { - return Object.isExtensible(o); - } - } - - const getHash = (function() { - const propIsEnumerable = Object.prototype.propertyIsEnumerable; - const hashProperty = '__MAP_POLYFILL_INTERNAL_HASH__'; - let hashCounter = 0; - - const nonExtensibleObjects = []; - const nonExtensibleHashes = []; - - /** - * Get the "hash" associated with an object. - * - * @param {object|array|function|regexp} o - * @return {number} - */ - return function getHash(o) { - if (hasOwn.call(o, hashProperty)) { - return o[hashProperty]; - } - - if (!isES5) { - if ( - hasOwn.call(o, 'propertyIsEnumerable') && - hasOwn.call(o.propertyIsEnumerable, hashProperty) - ) { - return o.propertyIsEnumerable[hashProperty]; - } - } - - if (isExtensible(o)) { - if (isES5) { - Object.defineProperty(o, hashProperty, { - enumerable: false, - writable: false, - configurable: false, - value: ++hashCounter, - }); - return hashCounter; - } - - if (o.propertyIsEnumerable) { - // Since we can't define a non-enumerable property on the object - // we'll hijack one of the less-used non-enumerable properties to - // save our hash on it. Additionally, since this is a function it - // will not show up in `JSON.stringify` which is what we want. - o.propertyIsEnumerable = function() { - return propIsEnumerable.apply(this, arguments); - }; - return (o.propertyIsEnumerable[hashProperty] = ++hashCounter); - } - } - - // If the object is not extensible, fall back to storing it in an - // array and using Array.prototype.indexOf to find it. - let index = nonExtensibleObjects.indexOf(o); - if (index < 0) { - index = nonExtensibleObjects.length; - nonExtensibleObjects[index] = o; - nonExtensibleHashes[index] = ++hashCounter; - } - return nonExtensibleHashes[index]; - }; - })(); - - return Map; -})(Function('return this')()); // eslint-disable-line no-new-func diff --git a/Libraries/vendor/core/Set.js b/Libraries/vendor/core/Set.js deleted file mode 100644 index 564f530b9afd8a..00000000000000 --- a/Libraries/vendor/core/Set.js +++ /dev/null @@ -1,198 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @preventMunge - * @typechecks - */ - -/* eslint-disable no-extend-native */ - -'use strict'; - -const Map = require('./Map'); - -const _shouldPolyfillES6Collection = require('./_shouldPolyfillES6Collection'); -const toIterator = require('./toIterator'); - -module.exports = (function(global) { - // Since our implementation is spec-compliant for the most part we can safely - // delegate to a built-in version if exists and is implemented correctly. - // Firefox had gotten a few implementation details wrong across different - // versions so we guard against that. - // These checks are adapted from es6-shim https://fburl.com/34437854 - if (!_shouldPolyfillES6Collection('Set')) { - return global.Set; - } - - /** - * == ES6 Set Collection == - * - * This module is meant to implement a Set collection as described in chapter - * 23.2 of the ES6 specification. - * - * Set objects are collections of unique values. Where values can be any - * JavaScript value. - * https://people.mozilla.org/~jorendorff/es6-draft.html#sec-map-objects - * - * There only two -- rather small -- diviations from the spec: - * - * 1. The use of frozen objects as keys. @see Map module for more on this. - * - * 2. The `size` property on a map object is a regular property and not a - * computed property on the prototype as described by the spec. - * The reason being is that we simply want to support ES3 environments - * which doesn't implement computed properties. - * - * == Usage == - * - * var set = new set(iterable); - * - * set.set(value); - * set.has(value); // true - * set.delete(value); // true - * - * var iterator = set.keys(); - * iterator.next(); // {value: value, done: false} - * - * var iterator = set.values(); - * iterator.next(); // {value: value, done: false} - * - * var iterator = set.entries(); - * iterator.next(); // {value: [value, value], done: false} - * - * set.forEach(function(value, value){ this === thisArg }, thisArg); - * - * set.clear(); // resets set. - */ - - class Set { - /** - * 23.2.1.1 - * - * Takes an optional `iterable` (which is basically any object that - * implements a Symbol.iterator (@@iterator) method). That is a collection - * of values used to instantiate the set. - * - * @param {*} iterable - */ - constructor(iterable) { - if ( - this == null || - (typeof this !== 'object' && typeof this !== 'function') - ) { - throw new TypeError('Wrong set object type.'); - } - - initSet(this); - - if (iterable != null) { - const it = toIterator(iterable); - let next; - while (!(next = it.next()).done) { - this.add(next.value); - } - } - } - - /** - * 23.2.3.1 - * - * If it doesn't already exist in the collection a `value` is added. - * - * @param {*} value - * @return {set} - */ - add(value) { - this._map.set(value, value); - this.size = this._map.size; - return this; - } - - /** - * 23.2.3.2 - * - * Clears the set. - */ - clear() { - initSet(this); - } - - /** - * 23.2.3.4 - * - * Deletes a `value` from the collection if it exists. - * Returns true if the value was found and deleted and false otherwise. - * - * @param {*} value - * @return {boolean} - */ - delete(value) { - const ret = this._map.delete(value); - this.size = this._map.size; - return ret; - } - - /** - * 23.2.3.5 - * - * Returns an iterator over a collection of [value, value] tuples. - */ - entries() { - return this._map.entries(); - } - - /** - * 23.2.3.6 - * - * Iterate over the collection calling `callback` with (value, value, set). - * - * @param {function} callback - */ - forEach(callback) { - const thisArg = arguments[1]; - const it = this._map.keys(); - let next; - while (!(next = it.next()).done) { - callback.call(thisArg, next.value, next.value, this); - } - } - - /** - * 23.2.3.7 - * - * Iterate over the collection calling `callback` with (value, value, set). - * - * @param {*} value - * @return {boolean} - */ - has(value) { - return this._map.has(value); - } - - /** - * 23.2.3.7 - * - * Returns an iterator over the colleciton of values. - */ - values() { - return this._map.values(); - } - } - - // 23.2.3.11 - Set.prototype[toIterator.ITERATOR_SYMBOL] = Set.prototype.values; - - // 23.2.3.7 - Set.prototype.keys = Set.prototype.values; - - function initSet(set) { - set._map = new Map(); - set.size = set._map.size; - } - - return Set; -})(Function('return this')()); // eslint-disable-line no-new-func diff --git a/Libraries/vendor/core/_shouldPolyfillES6Collection.js b/Libraries/vendor/core/_shouldPolyfillES6Collection.js deleted file mode 100644 index 1ba893c5aebdbe..00000000000000 --- a/Libraries/vendor/core/_shouldPolyfillES6Collection.js +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @preventMunge - * @flow strict - */ - -'use strict'; - -/** - * Checks whether a collection name (e.g. "Map" or "Set") has a native polyfill - * that is safe to be used. - */ -function _shouldActuallyPolyfillES6Collection(collectionName: string): boolean { - const Collection = global[collectionName]; - if (Collection == null) { - return true; - } - - // The iterator protocol depends on `Symbol.iterator`. If a collection is - // implemented, but `Symbol` is not, it's going to break iteration because - // we'll be using custom "@@iterator" instead, which is not implemented on - // native collections. - if (typeof global.Symbol !== 'function') { - return true; - } - - const proto = Collection.prototype; - - // These checks are adapted from es6-shim: https://fburl.com/34437854 - // NOTE: `isCallableWithoutNew` and `!supportsSubclassing` are not checked - // because they make debugging with "break on exceptions" difficult. - return ( - Collection == null || - typeof Collection !== 'function' || - typeof proto.clear !== 'function' || - new Collection().size !== 0 || - typeof proto.keys !== 'function' || - typeof proto.forEach !== 'function' - ); -} - -const cache: {[name: string]: boolean} = {}; - -/** - * Checks whether a collection name (e.g. "Map" or "Set") has a native polyfill - * that is safe to be used and caches this result. - * Make sure to make a first call to this function before a corresponding - * property on global was overriden in any way. - */ -function _shouldPolyfillES6Collection(collectionName: string) { - let result = cache[collectionName]; - if (result !== undefined) { - return result; - } - - result = _shouldActuallyPolyfillES6Collection(collectionName); - cache[collectionName] = result; - return result; -} - -module.exports = _shouldPolyfillES6Collection; diff --git a/flow/Map.js b/flow/Map.js deleted file mode 100644 index c8e830529798ff..00000000000000 --- a/flow/Map.js +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow strict - * @format - */ - -// These annotations are copy/pasted from the built-in Flow definitions for -// Native Map. - -declare module 'Map' { - // Use the name "MapPolyfill" so that we don't get confusing error - // messages about "Using Map instead of Map". - declare class MapPolyfill { - @@iterator(): Iterator<[K, V]>; - constructor(_: void): MapPolyfill; - constructor(_: null): MapPolyfill; - constructor( - iterable: Iterable<[Key, Value]>, - ): MapPolyfill; - clear(): void; - delete(key: K): boolean; - entries(): Iterator<[K, V]>; - forEach( - callbackfn: (value: V, index: K, map: MapPolyfill) => mixed, - thisArg?: any, - ): void; - get(key: K): V | void; - has(key: K): boolean; - keys(): Iterator; - set(key: K, value: V): MapPolyfill; - size: number; - values(): Iterator; - } - - declare module.exports: typeof MapPolyfill; -} diff --git a/flow/Set.js b/flow/Set.js deleted file mode 100644 index 64099c2a6028c3..00000000000000 --- a/flow/Set.js +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow strict - * @nolint - * @format - */ - -// These annotations are copy/pasted from the built-in Flow definitions for -// Native Set. - -declare module 'Set' { - // Use the name "SetPolyfill" so that we don't get confusing error - // messages about "Using Set instead of Set". - declare class SetPolyfill { - @@iterator(): Iterator; - constructor(iterable: ?Iterable): void; - add(value: T): SetPolyfill; - clear(): void; - delete(value: T): boolean; - entries(): Iterator<[T, T]>; - forEach( - callbackfn: (value: T, index: T, set: SetPolyfill) => mixed, - thisArg?: any, - ): void; - has(value: T): boolean; - keys(): Iterator; - size: number; - values(): Iterator; - } - - declare module.exports: typeof SetPolyfill; -} From 8e16a60faa6a70c9b5131aa2a4bc388bf342a15e Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Fri, 7 Jun 2019 06:35:19 -0700 Subject: [PATCH 0233/1084] Remove ImageStore JS files from RN open source Summary: This is being removed from RN as part of Lean Core. Reviewed By: rickhanlonii Differential Revision: D15666249 fbshipit-source-id: 00612b999184f216cc3deb72c6b24af359060abe --- Libraries/Image/ImageStore.js | 103 ------------------ Libraries/Image/NativeImageStore.js | 34 ------ .../react-native-implementation.js | 24 ++-- 3 files changed, 14 insertions(+), 147 deletions(-) delete mode 100644 Libraries/Image/ImageStore.js delete mode 100644 Libraries/Image/NativeImageStore.js diff --git a/Libraries/Image/ImageStore.js b/Libraries/Image/ImageStore.js deleted file mode 100644 index 7d6e7be5d6faac..00000000000000 --- a/Libraries/Image/ImageStore.js +++ /dev/null @@ -1,103 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - * @format - */ -'use strict'; - -import NativeImageStore from './NativeImageStore'; - -const Platform = require('../Utilities/Platform'); - -const warnOnce = require('../Utilities/warnOnce'); - -function warnUnimplementedMethod(methodName: string): void { - warnOnce( - `imagestore-${methodName}`, - `react-native: ImageStore.${methodName}() is not implemented on ${ - Platform.OS - }`, - ); -} - -class ImageStore { - /** - * Check if the ImageStore contains image data for the specified URI. - * @platform ios - */ - static hasImageForTag(uri: string, callback: (hasImage: boolean) => void) { - if (NativeImageStore.hasImageForTag) { - NativeImageStore.hasImageForTag(uri, callback); - } else { - warnUnimplementedMethod('hasImageForTag'); - } - } - - /** - * Delete an image from the ImageStore. Images are stored in memory and - * must be manually removed when you are finished with them, otherwise they - * will continue to use up RAM until the app is terminated. It is safe to - * call `removeImageForTag()` without first calling `hasImageForTag()`, it - * will simply fail silently. - * @platform ios - */ - static removeImageForTag(uri: string) { - if (NativeImageStore.removeImageForTag) { - NativeImageStore.removeImageForTag(uri); - } else { - warnUnimplementedMethod('removeImageForTag'); - } - } - - /** - * Stores a base64-encoded image in the ImageStore, and returns a URI that - * can be used to access or display the image later. Images are stored in - * memory only, and must be manually deleted when you are finished with - * them by calling `removeImageForTag()`. - * - * Note that it is very inefficient to transfer large quantities of binary - * data between JS and native code, so you should avoid calling this more - * than necessary. - * @platform ios - */ - static addImageFromBase64( - base64ImageData: string, - success: (uri: string) => void, - failure: (error: any) => void, - ) { - if (NativeImageStore.addImageFromBase64) { - NativeImageStore.addImageFromBase64(base64ImageData, success, failure); - } else { - warnUnimplementedMethod('addImageFromBase64'); - } - } - - /** - * Retrieves the base64-encoded data for an image in the ImageStore. If the - * specified URI does not match an image in the store, the failure callback - * will be called. - * - * Note that it is very inefficient to transfer large quantities of binary - * data between JS and native code, so you should avoid calling this more - * than necessary. To display an image in the ImageStore, you can just pass - * the URI to an `` component; there is no need to retrieve the - * base64 data. - */ - static getBase64ForTag( - uri: string, - success: (base64ImageData: string) => void, - failure: (error: any) => void, - ) { - if (NativeImageStore.getBase64ForTag) { - NativeImageStore.getBase64ForTag(uri, success, failure); - } else { - warnUnimplementedMethod('getBase64ForTag'); - } - } -} - -module.exports = ImageStore; diff --git a/Libraries/Image/NativeImageStore.js b/Libraries/Image/NativeImageStore.js deleted file mode 100644 index 0bc4948f1fb0a8..00000000000000 --- a/Libraries/Image/NativeImageStore.js +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - * @format - */ - -'use strict'; - -import type {TurboModule} from '../TurboModule/RCTExport'; -import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; - -export interface Spec extends TurboModule { - // Common - +getBase64ForTag: ( - uri: string, - success: (base64ImageData: string) => void, - failure: (error: Object) => void, - ) => void; - - // iOS-only - +hasImageForTag: (uri: string, callback: (hasImage: boolean) => void) => void; - +removeImageForTag: (uri: string) => void; - +addImageFromBase64: ( - base64ImageData: string, - success: (uri: string) => void, - failure: (error: Object) => void, - ) => void; -} - -export default TurboModuleRegistry.getEnforcing('ImageStoreManager'); diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js index d3602050e7f760..1fb35b409b6bdd 100644 --- a/Libraries/react-native/react-native-implementation.js +++ b/Libraries/react-native/react-native-implementation.js @@ -61,16 +61,6 @@ module.exports = { ); return require('../Image/ImageEditor'); }, - get ImageStore() { - warnOnce( - 'imagestore-deprecation', - 'ImageStore is deprecated and will be removed in a future release. ' + - 'To get a base64-encoded string from a local image use either of the following third-party libraries:' + - "* expo-file-system: `readAsStringAsync(filepath, 'base64')`" + - "* react-native-fs: `readFile(filepath, 'base64')`", - ); - return require('../Image/ImageStore'); - }, get InputAccessoryView() { return require('../Components/TextInput/InputAccessoryView'); }, @@ -413,4 +403,18 @@ if (__DEV__) { ); }, }); + + // $FlowFixMe This is intentional: Flow will error when attempting to access ImageStore. + Object.defineProperty(module.exports, 'ImageStore', { + configurable: true, + get() { + invariant( + false, + 'ImageStore has been removed from React Native. ' + + 'To get a base64-encoded string from a local image use either of the following third-party libraries:' + + "* expo-file-system: `readAsStringAsync(filepath, 'base64')`" + + "* react-native-fs: `readFile(filepath, 'base64')`", + ); + }, + }); } From 2b262ec78b48a7aaa164125cadc4f0593b71fdf3 Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Fri, 7 Jun 2019 08:04:52 -0700 Subject: [PATCH 0234/1084] Back out "[RN][TurboModule] Enable TurboModules for FB4A" Summary: Original commit changeset: e295dafdab7a I'm backing this out because it's broken Catalyst. The fixes are in D15711539, but it could take some time to review and land them. Reviewed By: rickhanlonii Differential Revision: D15714896 fbshipit-source-id: c2c555a52d3d140dfdea7d54ccd8d3102c22a1c6 --- .../main/java/com/facebook/react/bridge/BaseJavaModule.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java index da1d60f94f0897..04ca7a91c74969 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java @@ -67,9 +67,4 @@ public void onCatalystInstanceDestroy() { public boolean hasConstants() { return false; } - - // Cleanup Logic for TurboModuels - public void invalidate() { - // Do nothing - } } From 5751035f648879c6ed84293270ffc4902ee64d6e Mon Sep 17 00:00:00 2001 From: Aditya Sharat Date: Fri, 7 Jun 2019 09:22:17 -0700 Subject: [PATCH 0235/1084] Adds check to unset a YogaNode's parent during reconciliation. Summary: Adds check to unset a YogaNode's parent during reconciliation. Reviewed By: davidaurelio Differential Revision: D15714899 fbshipit-source-id: 6e2c2a28106574d062fec722c9a051acea87d0b6 --- ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java | 2 ++ .../src/main/java/com/facebook/yoga/YogaNodeJNIBase.java | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java index a01a0bdde49ddb..9a8e19663fd1a0 100644 --- a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java @@ -42,6 +42,8 @@ public static YogaNode create(YogaConfig config) { @Nullable public abstract YogaNode getOwner(); + public abstract void unsetOwner(); + /** @deprecated Use #getOwner() instead. This will be removed in the next version. */ @Deprecated @Nullable diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeJNIBase.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeJNIBase.java index c48162f4a470d6..0e1f68c8e97a35 100644 --- a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeJNIBase.java +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeJNIBase.java @@ -137,6 +137,11 @@ public YogaNodeJNIBase getOwner() { return mOwner; } + @Override + public void unsetOwner() { + mOwner = null; + } + /** @deprecated Use #getOwner() instead. This will be removed in the next version. */ @Deprecated @Nullable From 63ed75fe9e902f0c9be2417ff977b5882630f453 Mon Sep 17 00:00:00 2001 From: Chris Blappert Date: Fri, 7 Jun 2019 11:35:12 -0700 Subject: [PATCH 0236/1084] Fix comment Reviewed By: yungsters Differential Revision: D15585102 fbshipit-source-id: c6809d6600d66559e5dd9fa054e31e5e38744af3 --- Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js | 1 - 1 file changed, 1 deletion(-) diff --git a/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js b/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js index b39983d5e6062d..c4d00585437137 100644 --- a/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js +++ b/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js @@ -66,7 +66,6 @@ function processEventTypes( * Registers a native view/component by name. * A callback is provided to load the view config from UIManager. * The callback is deferred until the view is actually rendered. - * This is done to avoid causing Prepack deopts. */ exports.register = function(name: string, callback: ViewConfigGetter): string { invariant( From a19cfc227323910991eff9071f05f47140f709db Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Fri, 7 Jun 2019 12:00:01 -0700 Subject: [PATCH 0237/1084] Fabric: Scheduler-specific dependencies were moved to a separate class from ContextContainer Summary: ContextContainer should contain only product/component-specific dependencies and stay unchanged during VM/Scheduler reloading. Reviewed By: JoshuaGross Differential Revision: D15636656 fbshipit-source-id: fe5de1b6c92f659b28d31eba901c04c5b23fe1d1 --- React/Fabric/RCTScheduler.h | 4 +- React/Fabric/RCTScheduler.mm | 5 +- React/Fabric/RCTSurfacePresenter.mm | 57 +++++++++++-------- .../com/facebook/react/fabric/jni/Binding.cpp | 16 +++--- ReactCommon/fabric/uimanager/Scheduler.cpp | 24 +++----- ReactCommon/fabric/uimanager/Scheduler.h | 5 +- .../fabric/uimanager/SchedulerToolbox.cpp | 6 ++ .../fabric/uimanager/SchedulerToolbox.h | 47 +++++++++++++++ 8 files changed, 108 insertions(+), 56 deletions(-) create mode 100644 ReactCommon/fabric/uimanager/SchedulerToolbox.cpp create mode 100644 ReactCommon/fabric/uimanager/SchedulerToolbox.h diff --git a/React/Fabric/RCTScheduler.h b/React/Fabric/RCTScheduler.h index bebdaedcfe827f..a48ef1f0592cfd 100644 --- a/React/Fabric/RCTScheduler.h +++ b/React/Fabric/RCTScheduler.h @@ -14,6 +14,7 @@ #import #import #import +#import #import NS_ASSUME_NONNULL_BEGIN @@ -36,8 +37,7 @@ NS_ASSUME_NONNULL_BEGIN @property (atomic, weak, nullable) id delegate; -- (instancetype)initWithContextContainer:(facebook::react::ContextContainer::Shared)contextContatiner - componentRegistryFactory:(facebook::react::ComponentRegistryFactory)componentRegistryFactory; +- (instancetype)initWithToolbox:(facebook::react::SchedulerToolbox)toolbox; - (void)startSurfaceWithSurfaceId:(facebook::react::SurfaceId)surfaceId moduleName:(NSString *)moduleName diff --git a/React/Fabric/RCTScheduler.mm b/React/Fabric/RCTScheduler.mm index 185e012fed60d2..a21051f04fbce5 100644 --- a/React/Fabric/RCTScheduler.mm +++ b/React/Fabric/RCTScheduler.mm @@ -43,12 +43,11 @@ @implementation RCTScheduler { std::shared_ptr _delegateProxy; } -- (instancetype)initWithContextContainer:(ContextContainer::Shared)contextContainer - componentRegistryFactory:(ComponentRegistryFactory)componentRegistryFactory +- (instancetype)initWithToolbox:(facebook::react::SchedulerToolbox)toolbox { if (self = [super init]) { _delegateProxy = std::make_shared((__bridge void *)self); - _scheduler = std::make_shared(contextContainer, componentRegistryFactory); + _scheduler = std::make_shared(toolbox); _scheduler->setDelegate(_delegateProxy.get()); } diff --git a/React/Fabric/RCTSurfacePresenter.mm b/React/Fabric/RCTSurfacePresenter.mm index 06c8c5cab728db..0892963a39bcd2 100644 --- a/React/Fabric/RCTSurfacePresenter.mm +++ b/React/Fabric/RCTSurfacePresenter.mm @@ -31,6 +31,7 @@ #import #import #import +#import #import #import @@ -203,8 +204,22 @@ - (RCTScheduler *)_scheduler createComponentDescriptorRegistryWithParameters:{eventDispatcher, contextContainer}]; }; - _scheduler = [[RCTScheduler alloc] initWithContextContainer:self.contextContainer - componentRegistryFactory:componentRegistryFactory]; + auto runtimeExecutor = [self _runtimeExecutor]; + + auto toolbox = SchedulerToolbox{}; + toolbox.contextContainer = _contextContainer; + toolbox.componentRegistryFactory = componentRegistryFactory; + toolbox.runtimeExecutor = runtimeExecutor; + + toolbox.synchronousEventBeatFactory = [runtimeExecutor]() { + return std::make_unique(runtimeExecutor); + }; + + toolbox.asynchronousEventBeatFactory = [runtimeExecutor]() { + return std::make_unique(runtimeExecutor); + }; + + _scheduler = [[RCTScheduler alloc] initWithToolbox:toolbox]; _scheduler.delegate = self; return _scheduler; @@ -212,18 +227,8 @@ - (RCTScheduler *)_scheduler @synthesize contextContainer = _contextContainer; -- (ContextContainer::Shared)contextContainer +- (RuntimeExecutor)_runtimeExecutor { - std::lock_guard lock(_contextContainerMutex); - - if (_contextContainer) { - return _contextContainer; - } - - _contextContainer = std::make_shared(); - - _contextContainer->registerInstance(_reactNativeConfig, "ReactNativeConfig"); - auto messageQueueThread = _batchedBridge.jsMessageThread; if (messageQueueThread) { // Make sure initializeBridge completed @@ -239,20 +244,25 @@ - (RCTScheduler *)_scheduler [((RCTCxxBridge *)_batchedBridge) invokeAsync:[runtime, callback = std::move(callback)]() { callback(*runtime); }]; }; - EventBeatFactory synchronousBeatFactory = [runtimeExecutor]() { - return std::make_unique(runtimeExecutor); - }; - - EventBeatFactory asynchronousBeatFactory = [runtimeExecutor]() { - return std::make_unique(runtimeExecutor); - }; + return runtimeExecutor; +} - _contextContainer->registerInstance(synchronousBeatFactory, "synchronous"); - _contextContainer->registerInstance(asynchronousBeatFactory, "asynchronous"); +- (ContextContainer::Shared)contextContainer +{ + std::lock_guard lock(_contextContainerMutex); - _contextContainer->registerInstance(runtimeExecutor, "runtime-executor"); + if (_contextContainer) { + return _contextContainer; + } + _contextContainer = std::make_shared(); + // Please do not add stuff here; `SurfacePresenter` must not alter `ContextContainer`. + // Those two pieces eventually should be moved out there: + // * `RCTImageLoader` should be moved to `RNImageComponentView`. + // * `ReactNativeConfig` should be set by outside product code. + _contextContainer->registerInstance(_reactNativeConfig, "ReactNativeConfig"); _contextContainer->registerInstance(wrapManagedObject([_bridge imageLoader]), "RCTImageLoader"); + return _contextContainer; } @@ -390,7 +400,6 @@ - (void)handleBridgeWillReloadNotification:(NSNotification *)notification { std::lock_guard lock(_schedulerMutex); _scheduler = nil; - _contextContainer = nil; } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp index e38edd549d76bf..9d2a6c12cac6f4 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -136,16 +137,15 @@ void Binding::installFabricUIManager( std::shared_ptr config = std::make_shared(reactNativeConfig); contextContainer->registerInstance(config, "ReactNativeConfig"); - contextContainer->registerInstance( - synchronousBeatFactory, "synchronous"); - contextContainer->registerInstance( - asynchronousBeatFactory, "asynchronous"); contextContainer->registerInstance(javaUIManager_, "FabricUIManager"); - contextContainer->registerInstance(runtimeExecutor, "runtime-executor"); - - scheduler_ = std::make_shared( - contextContainer, componentsRegistry->buildRegistryFunction); + auto toolbox = SchedulerToolbox{}; + toolbox.contextContainer = contextContainer; + toolbox.componentRegistryFactory = componentsRegistry->buildRegistryFunction; + toolbox.runtimeExecutor = runtimeExecutor; + toolbox.synchronousEventBeatFactory = synchronousBeatFactory; + toolbox.asynchronousEventBeatFactory = asynchronousBeatFactory; + scheduler_ = std::make_shared(toolbox); scheduler_->setDelegate(this); } diff --git a/ReactCommon/fabric/uimanager/Scheduler.cpp b/ReactCommon/fabric/uimanager/Scheduler.cpp index aab1121d9341e8..1eb3fcd969f55c 100644 --- a/ReactCommon/fabric/uimanager/Scheduler.cpp +++ b/ReactCommon/fabric/uimanager/Scheduler.cpp @@ -18,19 +18,11 @@ namespace facebook { namespace react { -Scheduler::Scheduler( - ContextContainer::Shared const &contextContainer, - ComponentRegistryFactory buildRegistryFunction) { - const auto asynchronousEventBeatFactory = - contextContainer->getInstance("asynchronous"); - const auto synchronousEventBeatFactory = - contextContainer->getInstance("synchronous"); - - runtimeExecutor_ = - contextContainer->getInstance("runtime-executor"); +Scheduler::Scheduler(SchedulerToolbox schedulerToolbox) { + runtimeExecutor_ = schedulerToolbox.runtimeExecutor; reactNativeConfig_ = - contextContainer->getInstance>( + schedulerToolbox.contextContainer->getInstance>( "ReactNativeConfig"); auto uiManager = std::make_unique(); @@ -55,11 +47,11 @@ Scheduler::Scheduler( auto eventDispatcher = std::make_shared( eventPipe, statePipe, - synchronousEventBeatFactory, - asynchronousEventBeatFactory); + schedulerToolbox.synchronousEventBeatFactory, + schedulerToolbox.asynchronousEventBeatFactory); - componentDescriptorRegistry_ = - buildRegistryFunction(eventDispatcher, contextContainer); + componentDescriptorRegistry_ = schedulerToolbox.componentRegistryFactory( + eventDispatcher, schedulerToolbox.contextContainer); rootComponentDescriptor_ = std::make_unique(eventDispatcher); @@ -72,7 +64,7 @@ Scheduler::Scheduler( UIManagerBinding::install(runtime, uiManagerBinding_); }); - contextContainer->registerInstance( + schedulerToolbox.contextContainer->registerInstance( std::weak_ptr( componentDescriptorRegistry_), "ComponentDescriptorRegistry_DO_NOT_USE_PRETTY_PLEASE"); diff --git a/ReactCommon/fabric/uimanager/Scheduler.h b/ReactCommon/fabric/uimanager/Scheduler.h index ea4469ac3ed767..6cd4322501cbd0 100644 --- a/ReactCommon/fabric/uimanager/Scheduler.h +++ b/ReactCommon/fabric/uimanager/Scheduler.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -31,9 +32,7 @@ namespace react { */ class Scheduler final : public UIManagerDelegate, public ShadowTreeDelegate { public: - Scheduler( - ContextContainer::Shared const &contextContainer, - ComponentRegistryFactory buildRegistryFunction); + Scheduler(SchedulerToolbox schedulerToolbox); ~Scheduler(); #pragma mark - Surface Management diff --git a/ReactCommon/fabric/uimanager/SchedulerToolbox.cpp b/ReactCommon/fabric/uimanager/SchedulerToolbox.cpp new file mode 100644 index 00000000000000..c02009d00d3043 --- /dev/null +++ b/ReactCommon/fabric/uimanager/SchedulerToolbox.cpp @@ -0,0 +1,6 @@ +// Copyright (c) Facebook, Inc. and its affiliates. + +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + +#include "SchedulerToolbox.h" diff --git a/ReactCommon/fabric/uimanager/SchedulerToolbox.h b/ReactCommon/fabric/uimanager/SchedulerToolbox.h new file mode 100644 index 00000000000000..083609c6ad9c86 --- /dev/null +++ b/ReactCommon/fabric/uimanager/SchedulerToolbox.h @@ -0,0 +1,47 @@ +// Copyright (c) Facebook, Inc. and its affiliates. + +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + +#pragma once + +#include +#include +#include +#include + +namespace facebook { +namespace react { + +/* + * Contains all external dependencies of Scheduler. + * Copyable. + */ +struct SchedulerToolbox final { + /* + * Represents general purpose DI container for product components/needs. + * Must not be `nullptr`. + */ + ContextContainer::Shared contextContainer; + + /* + * Represents externally managed, lazily available collection of components. + */ + ComponentRegistryFactory componentRegistryFactory; + + /* + * Represents running JavaScript VM and associated execution queue. + */ + RuntimeExecutor runtimeExecutor; + + /* + * Asynchronous & synchronous event beats. + * Represent connections with the platform-specific run loops and general + * purpose background queue. + */ + EventBeatFactory asynchronousEventBeatFactory; + EventBeatFactory synchronousEventBeatFactory; +}; + +} // namespace react +} // namespace facebook From 205de0538cd16943bfe1cb8c35bb8005310e1600 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Fri, 7 Jun 2019 12:00:01 -0700 Subject: [PATCH 0238/1084] Fabric: New names for ContextContainer methods Summary: ... and slighly new behaviour for one of them. The method does nothing if given `key` already exists in the container. This diff finishes the transition of ContextContainer from an internal bag of things with unclear yet ownership into a legit dedicated dependency injection container for the product code. The original names of methods imply that the container can have only one object of a given type which is no longer true. The new API is much more generic and idiomatic to C++, it mimics `std:map` API which is intuitive to anyone who familiar with C++ containers. Besides the naming, `insert` method changed the semantic a bit; now it does nothing in case of inserting an object with a key that already exists. That might seem counterintuitive for "normal" people, but C++ has some wired reasons for that and, hopefully, it's expected behavior in the C++ community. Fun fact: We need this to fix hot-reload. Reviewed By: sahrens Differential Revision: D15681736 fbshipit-source-id: 194f342528446a911eaf072ba3a94a5d8af3cb52 --- React/Fabric/RCTSurfacePresenter.mm | 4 ++-- .../java/com/facebook/react/fabric/jni/Binding.cpp | 4 ++-- .../platform/android/SliderMeasurementsManager.cpp | 3 +-- .../fabric/imagemanager/platform/ios/ImageManager.mm | 2 +- .../platform/android/TextLayoutManager.cpp | 3 +-- ReactCommon/fabric/uimanager/Scheduler.cpp | 10 +++++----- ReactCommon/utils/ContextContainer.h | 10 ++++------ 7 files changed, 16 insertions(+), 20 deletions(-) diff --git a/React/Fabric/RCTSurfacePresenter.mm b/React/Fabric/RCTSurfacePresenter.mm index 0892963a39bcd2..edb6972ea2d6c3 100644 --- a/React/Fabric/RCTSurfacePresenter.mm +++ b/React/Fabric/RCTSurfacePresenter.mm @@ -260,8 +260,8 @@ - (RuntimeExecutor)_runtimeExecutor // Those two pieces eventually should be moved out there: // * `RCTImageLoader` should be moved to `RNImageComponentView`. // * `ReactNativeConfig` should be set by outside product code. - _contextContainer->registerInstance(_reactNativeConfig, "ReactNativeConfig"); - _contextContainer->registerInstance(wrapManagedObject([_bridge imageLoader]), "RCTImageLoader"); + _contextContainer->insert("ReactNativeConfig", _reactNativeConfig); + _contextContainer->insert("RCTImageLoader", wrapManagedObject([_bridge imageLoader])); return _contextContainer; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp index 9d2a6c12cac6f4..80295048094023 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp @@ -136,8 +136,8 @@ void Binding::installFabricUIManager( std::shared_ptr config = std::make_shared(reactNativeConfig); - contextContainer->registerInstance(config, "ReactNativeConfig"); - contextContainer->registerInstance(javaUIManager_, "FabricUIManager"); + contextContainer->insert("ReactNativeConfig", config); + contextContainer->insert("FabricUIManager", javaUIManager_); auto toolbox = SchedulerToolbox{}; toolbox.contextContainer = contextContainer; diff --git a/ReactCommon/fabric/components/slider/platform/android/SliderMeasurementsManager.cpp b/ReactCommon/fabric/components/slider/platform/android/SliderMeasurementsManager.cpp index ca6e6808f2cb91..c44288caefc65f 100644 --- a/ReactCommon/fabric/components/slider/platform/android/SliderMeasurementsManager.cpp +++ b/ReactCommon/fabric/components/slider/platform/android/SliderMeasurementsManager.cpp @@ -26,8 +26,7 @@ Size SliderMeasurementsManager::measure( } const jni::global_ref &fabricUIManager = - contextContainer_->getInstance>( - "FabricUIManager"); + contextContainer_->at>("FabricUIManager"); static auto measure = jni::findClassStatic("com/facebook/react/fabric/FabricUIManager") diff --git a/ReactCommon/fabric/imagemanager/platform/ios/ImageManager.mm b/ReactCommon/fabric/imagemanager/platform/ios/ImageManager.mm index d5c64f5f06b3cf..e3b4074eb24a59 100644 --- a/ReactCommon/fabric/imagemanager/platform/ios/ImageManager.mm +++ b/ReactCommon/fabric/imagemanager/platform/ios/ImageManager.mm @@ -18,7 +18,7 @@ ImageManager::ImageManager(ContextContainer::Shared const &contextContainer) { RCTImageLoader *imageLoader = - (RCTImageLoader *)unwrapManagedObject(contextContainer->getInstance>("RCTImageLoader")); + (RCTImageLoader *)unwrapManagedObject(contextContainer->at>("RCTImageLoader")); self_ = (__bridge_retained void *)[[RCTImageManager alloc] initWithImageLoader:imageLoader]; } diff --git a/ReactCommon/fabric/textlayoutmanager/platform/android/TextLayoutManager.cpp b/ReactCommon/fabric/textlayoutmanager/platform/android/TextLayoutManager.cpp index b6e04fe311e172..46e9fb6e68ff47 100644 --- a/ReactCommon/fabric/textlayoutmanager/platform/android/TextLayoutManager.cpp +++ b/ReactCommon/fabric/textlayoutmanager/platform/android/TextLayoutManager.cpp @@ -27,8 +27,7 @@ Size TextLayoutManager::measure( ParagraphAttributes paragraphAttributes, LayoutConstraints layoutConstraints) const { const jni::global_ref &fabricUIManager = - contextContainer_->getInstance>( - "FabricUIManager"); + contextContainer_->at>("FabricUIManager"); static auto measure = jni::findClassStatic("com/facebook/react/fabric/FabricUIManager") diff --git a/ReactCommon/fabric/uimanager/Scheduler.cpp b/ReactCommon/fabric/uimanager/Scheduler.cpp index 1eb3fcd969f55c..9b78bdc649eb38 100644 --- a/ReactCommon/fabric/uimanager/Scheduler.cpp +++ b/ReactCommon/fabric/uimanager/Scheduler.cpp @@ -22,8 +22,8 @@ Scheduler::Scheduler(SchedulerToolbox schedulerToolbox) { runtimeExecutor_ = schedulerToolbox.runtimeExecutor; reactNativeConfig_ = - schedulerToolbox.contextContainer->getInstance>( - "ReactNativeConfig"); + schedulerToolbox.contextContainer + ->at>("ReactNativeConfig"); auto uiManager = std::make_unique(); auto &uiManagerRef = *uiManager; @@ -64,10 +64,10 @@ Scheduler::Scheduler(SchedulerToolbox schedulerToolbox) { UIManagerBinding::install(runtime, uiManagerBinding_); }); - schedulerToolbox.contextContainer->registerInstance( + schedulerToolbox.contextContainer->insert( + "ComponentDescriptorRegistry_DO_NOT_USE_PRETTY_PLEASE", std::weak_ptr( - componentDescriptorRegistry_), - "ComponentDescriptorRegistry_DO_NOT_USE_PRETTY_PLEASE"); + componentDescriptorRegistry_)); } Scheduler::~Scheduler() { diff --git a/ReactCommon/utils/ContextContainer.h b/ReactCommon/utils/ContextContainer.h index 4e5a653607ba8d..4889a43bc7b716 100644 --- a/ReactCommon/utils/ContextContainer.h +++ b/ReactCommon/utils/ContextContainer.h @@ -27,6 +27,7 @@ class ContextContainer final { /* * Registers an instance of the particular type `T` in the container * using the provided `key`. Only one instance can be registered per key. + * The method does nothing if given `key` already exists in the container. * * Convention is to use the plain base class name for the key, so for * example if the type `T` is `std::shared_ptr`, @@ -35,12 +36,9 @@ class ContextContainer final { *`EmptyReactNativeConfig`. */ template - void registerInstance(T const &instance, std::string const &key) const { + void insert(std::string const &key, T const &instance) const { std::unique_lock lock(mutex_); - assert( - instances_.find(key) == instances_.end() && - "ContextContainer already had instance for given key."); instances_.insert({key, std::make_shared(instance)}); #ifndef NDEBUG @@ -54,7 +52,7 @@ class ContextContainer final { * Throws an exception if the instance could not be found. */ template - T getInstance(std::string const &key) const { + T at(std::string const &key) const { std::shared_lock lock(mutex_); assert( @@ -72,7 +70,7 @@ class ContextContainer final { * Returns an empty optional if the instance could not be found. */ template - better::optional findInstance(std::string const &key) const { + better::optional find(std::string const &key) const { std::shared_lock lock(mutex_); auto iterator = instances_.find(key); From 12c09a2d6cf20e3591c19986ce24924ae5f63fd3 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Fri, 7 Jun 2019 12:00:01 -0700 Subject: [PATCH 0239/1084] Fabric: Bunch of code style changes Summary: Code style only. Reviewed By: sahrens Differential Revision: D15681737 fbshipit-source-id: 24cc2e9b9434448026e7cb3cfd274ea14bd835a2 --- React/Fabric/RCTSurfacePresenter.mm | 48 +++++--------- .../imagemanager/platform/ios/ImageManager.mm | 6 +- ReactCommon/fabric/uimanager/Scheduler.cpp | 66 +++++++++---------- 3 files changed, 53 insertions(+), 67 deletions(-) diff --git a/React/Fabric/RCTSurfacePresenter.mm b/React/Fabric/RCTSurfacePresenter.mm index edb6972ea2d6c3..adc049828ad2cb 100644 --- a/React/Fabric/RCTSurfacePresenter.mm +++ b/React/Fabric/RCTSurfacePresenter.mm @@ -7,10 +7,10 @@ #import "RCTSurfacePresenter.h" +#import +#import #import #import -#import -#import #import #import @@ -36,8 +36,8 @@ #import #import "MainRunLoopEventBeat.h" -#import "RuntimeEventBeat.h" #import "RCTConversions.h" +#import "RuntimeEventBeat.h" using namespace facebook::react; @@ -52,9 +52,10 @@ @interface RCTSurfacePresenter () _reactNativeConfig; @@ -123,8 +124,7 @@ - (void)unregisterSurface:(RCTFabricSurface *)surface [_surfaceRegistry unregisterSurface:surface]; } -- (void)setProps:(NSDictionary *)props - surface:(RCTFabricSurface *)surface +- (void)setProps:(NSDictionary *)props surface:(RCTFabricSurface *)surface { // This implementation is suboptimal indeed but still better than nothing for now. [self _stopSurface:surface]; @@ -140,32 +140,22 @@ - (CGSize)sizeThatFitsMinimumSize:(CGSize)minimumSize maximumSize:(CGSize)maximumSize surface:(RCTFabricSurface *)surface { - LayoutContext layoutContext = { - .pointScaleFactor = RCTScreenScale() - }; + LayoutContext layoutContext = {.pointScaleFactor = RCTScreenScale()}; - LayoutConstraints layoutConstraints = { - .minimumSize = RCTSizeFromCGSize(minimumSize), - .maximumSize = RCTSizeFromCGSize(maximumSize) - }; + LayoutConstraints layoutConstraints = {.minimumSize = RCTSizeFromCGSize(minimumSize), + .maximumSize = RCTSizeFromCGSize(maximumSize)}; return [self._scheduler measureSurfaceWithLayoutConstraints:layoutConstraints layoutContext:layoutContext surfaceId:surface.rootTag]; } -- (void)setMinimumSize:(CGSize)minimumSize - maximumSize:(CGSize)maximumSize - surface:(RCTFabricSurface *)surface +- (void)setMinimumSize:(CGSize)minimumSize maximumSize:(CGSize)maximumSize surface:(RCTFabricSurface *)surface { - LayoutContext layoutContext = { - .pointScaleFactor = RCTScreenScale() - }; + LayoutContext layoutContext = {.pointScaleFactor = RCTScreenScale()}; - LayoutConstraints layoutConstraints = { - .minimumSize = RCTSizeFromCGSize(minimumSize), - .maximumSize = RCTSizeFromCGSize(maximumSize) - }; + LayoutConstraints layoutConstraints = {.minimumSize = RCTSizeFromCGSize(minimumSize), + .maximumSize = RCTSizeFromCGSize(maximumSize)}; [self._scheduler constraintSurfaceLayoutWithLayoutConstraints:layoutConstraints layoutContext:layoutContext @@ -274,14 +264,10 @@ - (void)_startSurface:(RCTFabricSurface *)surface tag:surface.rootTag]; }); - LayoutContext layoutContext = { - .pointScaleFactor = RCTScreenScale() - }; + LayoutContext layoutContext = {.pointScaleFactor = RCTScreenScale()}; - LayoutConstraints layoutConstraints = { - .minimumSize = RCTSizeFromCGSize(surface.minimumSize), - .maximumSize = RCTSizeFromCGSize(surface.maximumSize) - }; + LayoutConstraints layoutConstraints = {.minimumSize = RCTSizeFromCGSize(surface.minimumSize), + .maximumSize = RCTSizeFromCGSize(surface.maximumSize)}; [self._scheduler startSurfaceWithSurfaceId:surface.rootTag moduleName:surface.moduleName diff --git a/ReactCommon/fabric/imagemanager/platform/ios/ImageManager.mm b/ReactCommon/fabric/imagemanager/platform/ios/ImageManager.mm index e3b4074eb24a59..148b95fe1663ce 100644 --- a/ReactCommon/fabric/imagemanager/platform/ios/ImageManager.mm +++ b/ReactCommon/fabric/imagemanager/platform/ios/ImageManager.mm @@ -22,12 +22,14 @@ self_ = (__bridge_retained void *)[[RCTImageManager alloc] initWithImageLoader:imageLoader]; } -ImageManager::~ImageManager() { +ImageManager::~ImageManager() +{ CFRelease(self_); self_ = nullptr; } -ImageRequest ImageManager::requestImage(const ImageSource &imageSource) const { +ImageRequest ImageManager::requestImage(const ImageSource &imageSource) const +{ RCTImageManager *imageManager = (__bridge RCTImageManager *)self_; return [imageManager requestImage:imageSource]; } diff --git a/ReactCommon/fabric/uimanager/Scheduler.cpp b/ReactCommon/fabric/uimanager/Scheduler.cpp index 9b78bdc649eb38..1029584f9fa65a 100644 --- a/ReactCommon/fabric/uimanager/Scheduler.cpp +++ b/ReactCommon/fabric/uimanager/Scheduler.cpp @@ -138,25 +138,24 @@ void Scheduler::renderTemplateToSurface( void Scheduler::stopSurface(SurfaceId surfaceId) const { SystraceSection s("Scheduler::stopSurface"); - shadowTreeRegistry_.visit( - surfaceId, [](const ShadowTree &shadowTree) { - // As part of stopping the Surface, we have to commit an empty tree. - return shadowTree.tryCommit( - [&](const SharedRootShadowNode &oldRootShadowNode) { - return std::make_shared( - *oldRootShadowNode, - ShadowNodeFragment{ - /* .tag = */ ShadowNodeFragment::tagPlaceholder(), - /* .surfaceId = */ - ShadowNodeFragment::surfaceIdPlaceholder(), - /* .props = */ ShadowNodeFragment::propsPlaceholder(), - /* .eventEmitter = */ - ShadowNodeFragment::eventEmitterPlaceholder(), - /* .children = */ - ShadowNode::emptySharedShadowNodeSharedList(), - }); - }); - }); + shadowTreeRegistry_.visit(surfaceId, [](const ShadowTree &shadowTree) { + // As part of stopping the Surface, we have to commit an empty tree. + return shadowTree.tryCommit( + [&](const SharedRootShadowNode &oldRootShadowNode) { + return std::make_shared( + *oldRootShadowNode, + ShadowNodeFragment{ + /* .tag = */ ShadowNodeFragment::tagPlaceholder(), + /* .surfaceId = */ + ShadowNodeFragment::surfaceIdPlaceholder(), + /* .props = */ ShadowNodeFragment::propsPlaceholder(), + /* .eventEmitter = */ + ShadowNodeFragment::eventEmitterPlaceholder(), + /* .children = */ + ShadowNode::emptySharedShadowNodeSharedList(), + }); + }); + }); auto shadowTree = shadowTreeRegistry_.remove(surfaceId); shadowTree->setDelegate(nullptr); @@ -232,21 +231,20 @@ void Scheduler::uiManagerDidFinishTransaction( const SharedShadowNodeUnsharedList &rootChildNodes) { SystraceSection s("Scheduler::uiManagerDidFinishTransaction"); - shadowTreeRegistry_.visit( - surfaceId, [&](const ShadowTree &shadowTree) { - shadowTree.commit([&](const SharedRootShadowNode &oldRootShadowNode) { - return std::make_shared( - *oldRootShadowNode, - ShadowNodeFragment{ - /* .tag = */ ShadowNodeFragment::tagPlaceholder(), - /* .surfaceId = */ ShadowNodeFragment::surfaceIdPlaceholder(), - /* .props = */ ShadowNodeFragment::propsPlaceholder(), - /* .eventEmitter = */ - ShadowNodeFragment::eventEmitterPlaceholder(), - /* .children = */ rootChildNodes, - }); - }); - }); + shadowTreeRegistry_.visit(surfaceId, [&](const ShadowTree &shadowTree) { + shadowTree.commit([&](const SharedRootShadowNode &oldRootShadowNode) { + return std::make_shared( + *oldRootShadowNode, + ShadowNodeFragment{ + /* .tag = */ ShadowNodeFragment::tagPlaceholder(), + /* .surfaceId = */ ShadowNodeFragment::surfaceIdPlaceholder(), + /* .props = */ ShadowNodeFragment::propsPlaceholder(), + /* .eventEmitter = */ + ShadowNodeFragment::eventEmitterPlaceholder(), + /* .children = */ rootChildNodes, + }); + }); + }); } void Scheduler::uiManagerDidCreateShadowNode( From 886fb501bdbd875dcc424723d30ad325e367b1f1 Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Fri, 7 Jun 2019 12:23:55 -0700 Subject: [PATCH 0240/1084] RN Codegen] Add registerGeneratedViewConfig Summary: This diff updated the format of generated view configs so that they don't need to spread View props into every config, by adding a new registerGeneratedConfig function which will spread them instead This is a bit of a cleanup of the generated output but is primarily so that the view config babel plugin will not need to rely on object spreading or object.assigns Reviewed By: TheSavior, cpojer Differential Revision: D15517199 fbshipit-source-id: 08e575578177bad12d40ee3dcad9381974b6466d --- .../PullToRefreshViewNativeViewConfig.js | 19 +- .../Utilities/registerGeneratedViewConfig.js | 70 ++++ .../src/generators/GenerateViewConfigJs.js | 53 +-- .../GenerateViewConfigJs-test.js.snap | 341 ++---------------- 4 files changed, 106 insertions(+), 377 deletions(-) create mode 100644 Libraries/Utilities/registerGeneratedViewConfig.js diff --git a/Libraries/Components/RefreshControl/PullToRefreshViewNativeViewConfig.js b/Libraries/Components/RefreshControl/PullToRefreshViewNativeViewConfig.js index f76c8e02dd2140..e6157a13b05f79 100644 --- a/Libraries/Components/RefreshControl/PullToRefreshViewNativeViewConfig.js +++ b/Libraries/Components/RefreshControl/PullToRefreshViewNativeViewConfig.js @@ -10,17 +10,12 @@ 'use strict'; -const ReactNativeViewConfigRegistry = require('../../Renderer/shims/ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('../View/ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('../../Utilities/verifyComponentAttributeEquivalence'); +const registerGeneratedViewConfig = require('../../Utilities/registerGeneratedViewConfig'); const PullToRefreshViewViewConfig = { uiViewClassName: 'PullToRefreshView', - Commands: {}, bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - topRefresh: { phasedRegistrationNames: { captured: 'onRefreshCapture', @@ -29,12 +24,7 @@ const PullToRefreshViewViewConfig = { }, }, - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, - validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, tintColor: { process: require('../../StyleSheet/processColor') }, titleColor: { process: require('../../StyleSheet/processColor') }, title: true, @@ -43,11 +33,6 @@ const PullToRefreshViewViewConfig = { }, }; -verifyComponentAttributeEquivalence('PullToRefreshView', PullToRefreshViewViewConfig); - -ReactNativeViewConfigRegistry.register( - 'PullToRefreshView', - () => PullToRefreshViewViewConfig, -); +registerGeneratedViewConfig('PullToRefreshView', PullToRefreshViewViewConfig); module.exports = 'PullToRefreshView'; diff --git a/Libraries/Utilities/registerGeneratedViewConfig.js b/Libraries/Utilities/registerGeneratedViewConfig.js new file mode 100644 index 00000000000000..ee73030867845c --- /dev/null +++ b/Libraries/Utilities/registerGeneratedViewConfig.js @@ -0,0 +1,70 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +const ReactNativeViewConfigRegistry = require('../Renderer/shims/ReactNativeViewConfigRegistry'); +const ReactNativeViewViewConfig = require('../Components/View/ReactNativeViewViewConfig'); +const verifyComponentAttributeEquivalence = require('./verifyComponentAttributeEquivalence'); + +type GeneratedViewConfig = { + uiViewClassName: string, + bubblingEventTypes?: $ReadOnly<{ + [eventName: string]: $ReadOnly<{| + phasedRegistrationNames: $ReadOnly<{| + captured: string, + bubbled: string, + |}>, + |}>, + }>, + directEventTypes?: $ReadOnly<{ + [eventName: string]: $ReadOnly<{| + registrationName: string, + |}>, + }>, + validAttributes?: { + [propName: string]: + | true + | $ReadOnly<{| + diff?: (arg1: any, arg2: any) => boolean, + process?: (arg1: any) => any, + |}>, + }, +}; + +function registerGeneratedViewConfig( + componentName: string, + viewConfig: GeneratedViewConfig, +) { + const mergedViewConfig = { + uiViewClassName: viewConfig.uiViewClassName, + Commands: {}, + bubblingEventTypes: { + ...ReactNativeViewViewConfig.bubblingEventTypes, + ...(viewConfig.bubblingEventTypes || {}), + }, + directEventTypes: { + ...ReactNativeViewViewConfig.directEventTypes, + ...(viewConfig.directEventTypes || {}), + }, + validAttributes: { + ...ReactNativeViewViewConfig.validAttributes, + ...(viewConfig.validAttributes || {}), + }, + }; + + ReactNativeViewConfigRegistry.register(componentName, () => { + verifyComponentAttributeEquivalence(componentName, mergedViewConfig); + + return mergedViewConfig; + }); +} + +module.exports = registerGeneratedViewConfig; diff --git a/packages/react-native-codegen/src/generators/GenerateViewConfigJs.js b/packages/react-native-codegen/src/generators/GenerateViewConfigJs.js index d5e1583ea2bccc..d5f8cde857f88a 100644 --- a/packages/react-native-codegen/src/generators/GenerateViewConfigJs.js +++ b/packages/react-native-codegen/src/generators/GenerateViewConfigJs.js @@ -87,12 +87,7 @@ function getReactDiffProcessValue(typeAnnotation) { const componentTemplate = ` const ::_COMPONENT_NAME_::ViewConfig = VIEW_CONFIG; -verifyComponentAttributeEquivalence('::_COMPONENT_NAME_WITH_COMPAT_SUPPORT_::', ::_COMPONENT_NAME_::ViewConfig); - -ReactNativeViewConfigRegistry.register( - '::_COMPONENT_NAME_WITH_COMPAT_SUPPORT_::', - () => ::_COMPONENT_NAME_::ViewConfig, -); +registerGeneratedViewConfig('::_COMPONENT_NAME_WITH_COMPAT_SUPPORT_::', ::_COMPONENT_NAME_::ViewConfig); module.exports = '::_COMPONENT_NAME_WITH_COMPAT_SUPPORT_::';::_COMPAT_COMMENT_:: `.trim(); @@ -159,38 +154,13 @@ function buildViewConfig( const componentProps = component.props; const componentEvents = component.events; - let viewAttributes = null; - let viewEvents = null; - let viewDirectEvents = null; - component.extendsProps.forEach(extendProps => { switch (extendProps.type) { case 'ReactNativeBuiltInType': switch (extendProps.knownTypeName) { case 'ReactNativeCoreViewProps': imports.add( - "const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig');", - ); - - viewAttributes = j.spreadProperty( - j.memberExpression( - j.identifier('ReactNativeViewViewConfig'), - j.identifier('validAttributes'), - ), - ); - - viewEvents = j.spreadProperty( - j.memberExpression( - j.identifier('ReactNativeViewViewConfig'), - j.identifier('bubblingEventTypes'), - ), - ); - - viewDirectEvents = j.spreadProperty( - j.memberExpression( - j.identifier('ReactNativeViewViewConfig'), - j.identifier('directEventTypes'), - ), + "const registerGeneratedViewConfig = require('registerGeneratedViewConfig');", ); return; @@ -205,7 +175,6 @@ function buildViewConfig( }); const validAttributes = j.objectExpression([ - viewAttributes, ...componentProps.map(schemaProp => { return j.property( 'init', @@ -220,8 +189,6 @@ function buildViewConfig( .filter(event => event.bubblingType === 'bubble') .map(generateBubblingEventInfo); - bubblingEventNames.unshift(viewEvents); - const bubblingEvents = bubblingEventNames.length > 0 ? j.property( @@ -235,8 +202,6 @@ function buildViewConfig( .filter(event => event.bubblingType === 'direct') .map(generateDirectEventInfo); - directEventNames.unshift(viewDirectEvents); - const directEvents = directEventNames.length > 0 ? j.property( @@ -246,19 +211,12 @@ function buildViewConfig( ) : null; - const commands = j.property( - 'init', - j.identifier('Commands'), - j.objectExpression([]), - ); - const properties = [ j.property( 'init', j.identifier('uiViewClassName'), j.literal(componentName), ), - commands, bubblingEvents, directEvents, j.property('init', j.identifier('validAttributes'), validAttributes), @@ -273,13 +231,6 @@ module.exports = { const fileName = `${libraryName}NativeViewConfig.js`; const imports: Set = new Set(); - imports.add( - "const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry');", - ); - imports.add( - "const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence');", - ); - const moduleResults = Object.keys(schema.modules) .map(moduleName => { const components = schema.modules[moduleName].components; diff --git a/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap b/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap index 729bfac1050bf9..1fd81850c2be64 100644 --- a/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap +++ b/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap @@ -14,24 +14,12 @@ Map { 'use strict'; -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); +const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); const ArrayPropsNativeComponentViewConfig = { uiViewClassName: 'ArrayPropsNativeComponent', - Commands: {}, - - bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - }, - - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, names: true, disableds: true, progress: true, @@ -42,12 +30,7 @@ const ArrayPropsNativeComponentViewConfig = { }, }; -verifyComponentAttributeEquivalence('ArrayPropsNativeComponent', ArrayPropsNativeComponentViewConfig); - -ReactNativeViewConfigRegistry.register( - 'ArrayPropsNativeComponent', - () => ArrayPropsNativeComponentViewConfig, -); +registerGeneratedViewConfig('ArrayPropsNativeComponent', ArrayPropsNativeComponentViewConfig); module.exports = 'ArrayPropsNativeComponent'; ", @@ -68,34 +51,17 @@ Map { 'use strict'; -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); +const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); const BooleanPropNativeComponentViewConfig = { uiViewClassName: 'BooleanPropNativeComponent', - Commands: {}, - - bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - }, - - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, disabled: true, }, }; -verifyComponentAttributeEquivalence('BooleanPropNativeComponent', BooleanPropNativeComponentViewConfig); - -ReactNativeViewConfigRegistry.register( - 'BooleanPropNativeComponent', - () => BooleanPropNativeComponentViewConfig, -); +registerGeneratedViewConfig('BooleanPropNativeComponent', BooleanPropNativeComponentViewConfig); module.exports = 'BooleanPropNativeComponent'; ", @@ -116,34 +82,17 @@ Map { 'use strict'; -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); +const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); const ColorPropNativeComponentViewConfig = { uiViewClassName: 'ColorPropNativeComponent', - Commands: {}, - - bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - }, - - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, tintColor: { process: require('processColor') }, }, }; -verifyComponentAttributeEquivalence('ColorPropNativeComponent', ColorPropNativeComponentViewConfig); - -ReactNativeViewConfigRegistry.register( - 'ColorPropNativeComponent', - () => ColorPropNativeComponentViewConfig, -); +registerGeneratedViewConfig('ColorPropNativeComponent', ColorPropNativeComponentViewConfig); module.exports = 'ColorPropNativeComponent'; ", @@ -164,34 +113,17 @@ Map { 'use strict'; -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); +const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); const EnumPropsNativeComponentViewConfig = { uiViewClassName: 'EnumPropsNativeComponent', - Commands: {}, - - bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - }, - - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, alignment: true, }, }; -verifyComponentAttributeEquivalence('EnumPropsNativeComponent', EnumPropsNativeComponentViewConfig); - -ReactNativeViewConfigRegistry.register( - 'EnumPropsNativeComponent', - () => EnumPropsNativeComponentViewConfig, -); +registerGeneratedViewConfig('EnumPropsNativeComponent', EnumPropsNativeComponentViewConfig); module.exports = 'EnumPropsNativeComponent'; ", @@ -212,17 +144,12 @@ Map { 'use strict'; -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); +const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); const EventsNestedObjectNativeComponentViewConfig = { uiViewClassName: 'EventsNestedObjectNativeComponent', - Commands: {}, bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - topChange: { phasedRegistrationNames: { captured: 'onChangeCapture', @@ -231,23 +158,13 @@ const EventsNestedObjectNativeComponentViewConfig = { }, }, - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, - validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, disabled: true, onChange: true, }, }; -verifyComponentAttributeEquivalence('EventsNestedObjectNativeComponent', EventsNestedObjectNativeComponentViewConfig); - -ReactNativeViewConfigRegistry.register( - 'EventsNestedObjectNativeComponent', - () => EventsNestedObjectNativeComponentViewConfig, -); +registerGeneratedViewConfig('EventsNestedObjectNativeComponent', EventsNestedObjectNativeComponentViewConfig); module.exports = 'EventsNestedObjectNativeComponent'; ", @@ -268,17 +185,12 @@ Map { 'use strict'; -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); +const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); const EventsNativeComponentViewConfig = { uiViewClassName: 'EventsNativeComponent', - Commands: {}, bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - topChange: { phasedRegistrationNames: { captured: 'onChangeCapture', @@ -295,15 +207,12 @@ const EventsNativeComponentViewConfig = { }, directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - topEventDirect: { registrationName: 'onEventDirect', }, }, validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, disabled: true, onChange: true, onEventDirect: true, @@ -311,12 +220,7 @@ const EventsNativeComponentViewConfig = { }, }; -verifyComponentAttributeEquivalence('EventsNativeComponent', EventsNativeComponentViewConfig); - -ReactNativeViewConfigRegistry.register( - 'EventsNativeComponent', - () => EventsNativeComponentViewConfig, -); +registerGeneratedViewConfig('EventsNativeComponent', EventsNativeComponentViewConfig); module.exports = 'EventsNativeComponent'; ", @@ -337,24 +241,12 @@ Map { 'use strict'; -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); +const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); const FloatPropNativeComponentViewConfig = { uiViewClassName: 'FloatPropNativeComponent', - Commands: {}, - - bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - }, - - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, blurRadius: true, blurRadius2: true, blurRadius3: true, @@ -364,12 +256,7 @@ const FloatPropNativeComponentViewConfig = { }, }; -verifyComponentAttributeEquivalence('FloatPropNativeComponent', FloatPropNativeComponentViewConfig); - -ReactNativeViewConfigRegistry.register( - 'FloatPropNativeComponent', - () => FloatPropNativeComponentViewConfig, -); +registerGeneratedViewConfig('FloatPropNativeComponent', FloatPropNativeComponentViewConfig); module.exports = 'FloatPropNativeComponent'; ", @@ -390,34 +277,17 @@ Map { 'use strict'; -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); +const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); const ImagePropNativeComponentViewConfig = { uiViewClassName: 'ImagePropNativeComponent', - Commands: {}, - - bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - }, - - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, thumbImage: { process: require('resolveAssetSource') }, }, }; -verifyComponentAttributeEquivalence('ImagePropNativeComponent', ImagePropNativeComponentViewConfig); - -ReactNativeViewConfigRegistry.register( - 'ImagePropNativeComponent', - () => ImagePropNativeComponentViewConfig, -); +registerGeneratedViewConfig('ImagePropNativeComponent', ImagePropNativeComponentViewConfig); module.exports = 'ImagePropNativeComponent'; ", @@ -438,36 +308,19 @@ Map { 'use strict'; -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); +const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); const IntegerPropNativeComponentViewConfig = { uiViewClassName: 'IntegerPropNativeComponent', - Commands: {}, - - bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - }, - - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, progress1: true, progress2: true, progress3: true, }, }; -verifyComponentAttributeEquivalence('IntegerPropNativeComponent', IntegerPropNativeComponentViewConfig); - -ReactNativeViewConfigRegistry.register( - 'IntegerPropNativeComponent', - () => IntegerPropNativeComponentViewConfig, -); +registerGeneratedViewConfig('IntegerPropNativeComponent', IntegerPropNativeComponentViewConfig); module.exports = 'IntegerPropNativeComponent'; ", @@ -488,17 +341,12 @@ Map { 'use strict'; -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); +const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); const InterfaceOnlyComponentViewConfig = { uiViewClassName: 'RCTInterfaceOnlyComponent', - Commands: {}, bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - topChange: { phasedRegistrationNames: { captured: 'onChangeCapture', @@ -507,23 +355,13 @@ const InterfaceOnlyComponentViewConfig = { }, }, - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, - validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, accessibilityHint: true, onChange: true, }, }; -verifyComponentAttributeEquivalence('RCTInterfaceOnlyComponent', InterfaceOnlyComponentViewConfig); - -ReactNativeViewConfigRegistry.register( - 'RCTInterfaceOnlyComponent', - () => InterfaceOnlyComponentViewConfig, -); +registerGeneratedViewConfig('RCTInterfaceOnlyComponent', InterfaceOnlyComponentViewConfig); module.exports = 'RCTInterfaceOnlyComponent'; // RCT prefix present for paper support ", @@ -544,24 +382,12 @@ Map { 'use strict'; -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); +const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); const ImageColorPropNativeComponentViewConfig = { uiViewClassName: 'ImageColorPropNativeComponent', - Commands: {}, - - bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - }, - - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, thumbImage: { process: require('resolveAssetSource') }, color: { process: require('processColor') }, thumbTintColor: { process: require('processColor') }, @@ -569,12 +395,7 @@ const ImageColorPropNativeComponentViewConfig = { }, }; -verifyComponentAttributeEquivalence('ImageColorPropNativeComponent', ImageColorPropNativeComponentViewConfig); - -ReactNativeViewConfigRegistry.register( - 'ImageColorPropNativeComponent', - () => ImageColorPropNativeComponentViewConfig, -); +registerGeneratedViewConfig('ImageColorPropNativeComponent', ImageColorPropNativeComponentViewConfig); module.exports = 'ImageColorPropNativeComponent'; ", @@ -595,34 +416,17 @@ Map { 'use strict'; -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); +const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); const PointPropNativeComponentViewConfig = { uiViewClassName: 'PointPropNativeComponent', - Commands: {}, - - bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - }, - - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, startPoint: { diff: require('pointsDiffer') }, }, }; -verifyComponentAttributeEquivalence('PointPropNativeComponent', PointPropNativeComponentViewConfig); - -ReactNativeViewConfigRegistry.register( - 'PointPropNativeComponent', - () => PointPropNativeComponentViewConfig, -); +registerGeneratedViewConfig('PointPropNativeComponent', PointPropNativeComponentViewConfig); module.exports = 'PointPropNativeComponent'; ", @@ -643,34 +447,17 @@ Map { 'use strict'; -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); +const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); const StringPropComponentViewConfig = { uiViewClassName: 'StringPropComponent', - Commands: {}, - - bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - }, - - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, accessibilityHint: true, }, }; -verifyComponentAttributeEquivalence('StringPropComponent', StringPropComponentViewConfig); - -ReactNativeViewConfigRegistry.register( - 'StringPropComponent', - () => StringPropComponentViewConfig, -); +registerGeneratedViewConfig('StringPropComponent', StringPropComponentViewConfig); module.exports = 'StringPropComponent'; ", @@ -691,61 +478,29 @@ Map { 'use strict'; -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); +const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); const MultiFile1NativeComponentViewConfig = { uiViewClassName: 'MultiFile1NativeComponent', - Commands: {}, - - bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - }, - - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, disabled: true, }, }; -verifyComponentAttributeEquivalence('MultiFile1NativeComponent', MultiFile1NativeComponentViewConfig); - -ReactNativeViewConfigRegistry.register( - 'MultiFile1NativeComponent', - () => MultiFile1NativeComponentViewConfig, -); +registerGeneratedViewConfig('MultiFile1NativeComponent', MultiFile1NativeComponentViewConfig); module.exports = 'MultiFile1NativeComponent'; const MultiFile2NativeComponentViewConfig = { uiViewClassName: 'MultiFile2NativeComponent', - Commands: {}, - - bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - }, - - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, disabled: true, }, }; -verifyComponentAttributeEquivalence('MultiFile2NativeComponent', MultiFile2NativeComponentViewConfig); - -ReactNativeViewConfigRegistry.register( - 'MultiFile2NativeComponent', - () => MultiFile2NativeComponentViewConfig, -); +registerGeneratedViewConfig('MultiFile2NativeComponent', MultiFile2NativeComponentViewConfig); module.exports = 'MultiFile2NativeComponent'; ", @@ -766,61 +521,29 @@ Map { 'use strict'; -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry'); -const ReactNativeViewViewConfig = require('ReactNativeViewViewConfig'); -const verifyComponentAttributeEquivalence = require('verifyComponentAttributeEquivalence'); +const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); const MultiComponent1NativeComponentViewConfig = { uiViewClassName: 'MultiComponent1NativeComponent', - Commands: {}, - - bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - }, - - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, disabled: true, }, }; -verifyComponentAttributeEquivalence('MultiComponent1NativeComponent', MultiComponent1NativeComponentViewConfig); - -ReactNativeViewConfigRegistry.register( - 'MultiComponent1NativeComponent', - () => MultiComponent1NativeComponentViewConfig, -); +registerGeneratedViewConfig('MultiComponent1NativeComponent', MultiComponent1NativeComponentViewConfig); module.exports = 'MultiComponent1NativeComponent'; const MultiComponent2NativeComponentViewConfig = { uiViewClassName: 'MultiComponent2NativeComponent', - Commands: {}, - - bubblingEventTypes: { - ...ReactNativeViewViewConfig.bubblingEventTypes, - }, - - directEventTypes: { - ...ReactNativeViewViewConfig.directEventTypes, - }, validAttributes: { - ...ReactNativeViewViewConfig.validAttributes, disabled: true, }, }; -verifyComponentAttributeEquivalence('MultiComponent2NativeComponent', MultiComponent2NativeComponentViewConfig); - -ReactNativeViewConfigRegistry.register( - 'MultiComponent2NativeComponent', - () => MultiComponent2NativeComponentViewConfig, -); +registerGeneratedViewConfig('MultiComponent2NativeComponent', MultiComponent2NativeComponentViewConfig); module.exports = 'MultiComponent2NativeComponent'; ", From efec97f2be535def834e0c2da061bb25875224c3 Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Fri, 7 Jun 2019 12:23:55 -0700 Subject: [PATCH 0241/1084] Add view config babel plugin Summary: This diff adds a babel plugin for the generated view configs which will inline them in the file instead of needing to check the view configs in (fb only) The way it works is: - babel reads the code - looks for type alias `CodegenNativeComponent` in `*NativeComponet.js` files - run the flow parser on the file source to create a schema - run the schema into codegen to get the view config source code - inject the generated source code back into the NativeComponent.js file - remove the original export - profit After this diff we will remove the `js1 build viewconfigs` command and the checked-in NativeViewConfig.js files Note: since this plugin is not published to open source, for now OSS will continue using the `requireNativeComponent` function Reviewed By: cpojer Differential Revision: D15516062 fbshipit-source-id: a8efb077773e04fd9753a7036682eeaae9175e09 --- .../PullToRefreshViewNativeComponent.js | 21 +++---- .../babel-plugin-inline-view-configs/BUCK | 23 ++++++++ .../__test_fixtures__/fixtures.js | 54 +++++++++++++++++ .../__snapshots__/index-test.js.snap | 52 ++++++++++++++++ .../__tests__/index-test.js | 32 ++++++++++ .../babel-plugin-inline-view-configs/index.js | 59 +++++++++++++++++++ .../package.json | 16 +++++ packages/react-native-codegen/BUCK | 23 ++++++++ packages/react-native-codegen/package.json | 2 +- .../src/cli/parser/parser.js | 5 +- .../cli/viewconfigs/generate-view-configs.js | 2 +- .../src/generators/RNCodegen.js | 14 +++++ .../src/parsers/flow/__tests__/parser-test.js | 2 +- .../src/parsers/flow/index.js | 16 +++-- 14 files changed, 298 insertions(+), 23 deletions(-) create mode 100644 packages/babel-plugin-inline-view-configs/BUCK create mode 100644 packages/babel-plugin-inline-view-configs/__test_fixtures__/fixtures.js create mode 100644 packages/babel-plugin-inline-view-configs/__tests__/__snapshots__/index-test.js.snap create mode 100644 packages/babel-plugin-inline-view-configs/__tests__/index-test.js create mode 100644 packages/babel-plugin-inline-view-configs/index.js create mode 100644 packages/babel-plugin-inline-view-configs/package.json diff --git a/Libraries/Components/RefreshControl/PullToRefreshViewNativeComponent.js b/Libraries/Components/RefreshControl/PullToRefreshViewNativeComponent.js index 5274896fb75e11..43105157841ded 100644 --- a/Libraries/Components/RefreshControl/PullToRefreshViewNativeComponent.js +++ b/Libraries/Components/RefreshControl/PullToRefreshViewNativeComponent.js @@ -10,17 +10,13 @@ 'use strict'; -import type { - BubblingEvent, - WithDefault, - CodegenNativeComponent, -} from '../../Types/CodegenTypes'; - -const requireNativeComponent = require('../../ReactNative/requireNativeComponent'); - +import type {BubblingEvent, WithDefault} from '../../Types/CodegenTypes'; +import type {NativeComponent} from '../../Renderer/shims/ReactNative'; import type {ColorValue} from '../../StyleSheet/StyleSheetTypes'; import type {ViewProps} from '../View/ViewPropTypes'; +const requireNativeComponent = require('../../ReactNative/requireNativeComponent'); + type NativeProps = $ReadOnly<{| ...ViewProps, @@ -48,13 +44,10 @@ type NativeProps = $ReadOnly<{| refreshing: WithDefault, |}>; -type PullToRefreshViewType = CodegenNativeComponent< - 'PullToRefreshView', - NativeProps, ->; - -// TODO: Switch this over to require('./PullToRefreshNativeViewConfig') +// TODO: Switch this over to CodegenNativeComponent // once the native components are renamed in paper and fabric +type PullToRefreshViewType = Class>; + module.exports = ((requireNativeComponent( 'RCTRefreshControl', ): any): PullToRefreshViewType); diff --git a/packages/babel-plugin-inline-view-configs/BUCK b/packages/babel-plugin-inline-view-configs/BUCK new file mode 100644 index 00000000000000..8fd38289431bdb --- /dev/null +++ b/packages/babel-plugin-inline-view-configs/BUCK @@ -0,0 +1,23 @@ +load("@fbsource//tools/build_defs/third_party:yarn_defs.bzl", "yarn_workspace") + +yarn_workspace( + name = "yarn-workspace", + srcs = glob( + ["**/*.js"], + exclude = [ + "**/__fixtures__/**", + "**/__flowtests__/**", + "**/__mocks__/**", + "**/__server_snapshot_tests__/**", + "**/__tests__/**", + "**/node_modules/**", + "**/node_modules/.bin/**", + "**/.*", + "**/.*/**", + "**/.*/.*", + "**/*.xcodeproj/**", + "**/*.xcworkspace/**", + ], + ), + visibility = ["PUBLIC"], +) diff --git a/packages/babel-plugin-inline-view-configs/__test_fixtures__/fixtures.js b/packages/babel-plugin-inline-view-configs/__test_fixtures__/fixtures.js new file mode 100644 index 00000000000000..8af50cd1e1ffb8 --- /dev/null +++ b/packages/babel-plugin-inline-view-configs/__test_fixtures__/fixtures.js @@ -0,0 +1,54 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; +const NOT_A_NATIVE_COMPONENT = ` +const requireNativeComponent = require('requireNativeComponent'); + +export default 'Not a view config' +`; + +const FULL_NATIVE_COMPONENT = ` +const requireNativeComponent = require('requireNativeComponent'); + +import type { + BubblingEvent, + DirectEvent, + WithDefault, + CodegenNativeComponent, +} from 'CodegenFlowtypes'; + +import type {ViewProps} from 'ViewPropTypes'; + +type ModuleProps = $ReadOnly<{| + ...ViewProps, + + // Props + boolean_default_true_optional_both?: ?WithDefault, + + // Events + onDirectEventDefinedInlineNull: (event: DirectEvent) => void, + onBubblingEventDefinedInlineNull: (event: BubblingEvent) => void, +|}>; + +type Options = { + interfaceOnly: true, + isDeprecatedPaperComponentNameRCT: true, +}; + +type ModuleType = CodegenNativeComponent<'Module', ModuleProps, Options>; + +module.exports = ((requireNativeComponent('RCTModule'): any): ModuleType); +`; + +module.exports = { + 'NotANativeComponent.js': NOT_A_NATIVE_COMPONENT, + 'FullNativeComponent.js': FULL_NATIVE_COMPONENT, +}; diff --git a/packages/babel-plugin-inline-view-configs/__tests__/__snapshots__/index-test.js.snap b/packages/babel-plugin-inline-view-configs/__tests__/__snapshots__/index-test.js.snap new file mode 100644 index 00000000000000..7413b19d349409 --- /dev/null +++ b/packages/babel-plugin-inline-view-configs/__tests__/__snapshots__/index-test.js.snap @@ -0,0 +1,52 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Babel plugin inline view configs can inline config for FullNativeComponent.js 1`] = ` +"const requireNativeComponent = require('requireNativeComponent'); + +import type { BubblingEvent, DirectEvent, WithDefault, CodegenNativeComponent } from 'CodegenFlowtypes'; +import type { ViewProps } from 'ViewPropTypes'; +type ModuleProps = $ReadOnly<{| ...ViewProps, + // Props + boolean_default_true_optional_both?: ?WithDefault, + // Events + onDirectEventDefinedInlineNull: (event: DirectEvent) => void, + onBubblingEventDefinedInlineNull: (event: BubblingEvent) => void, +|}>; +type Options = { + interfaceOnly: true, + isDeprecatedPaperComponentNameRCT: true, +}; +type ModuleType = CodegenNativeComponent<'Module', ModuleProps, Options>; + +const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); + +const ModuleViewConfig = { + uiViewClassName: 'RCTModule', + bubblingEventTypes: { + topBubblingEventDefinedInlineNull: { + phasedRegistrationNames: { + captured: 'onBubblingEventDefinedInlineNullCapture', + bubbled: 'onBubblingEventDefinedInlineNull' + } + } + }, + directEventTypes: { + topDirectEventDefinedInlineNull: { + registrationName: 'onDirectEventDefinedInlineNull' + } + }, + validAttributes: { + boolean_default_true_optional_both: true, + onDirectEventDefinedInlineNull: true, + onBubblingEventDefinedInlineNull: true + } +}; +registerGeneratedViewConfig('RCTModule', ModuleViewConfig); +module.exports = 'RCTModule'; // RCT prefix present for paper support" +`; + +exports[`Babel plugin inline view configs can inline config for NotANativeComponent.js 1`] = ` +"const requireNativeComponent = require('requireNativeComponent'); + +export default 'Not a view config';" +`; diff --git a/packages/babel-plugin-inline-view-configs/__tests__/index-test.js b/packages/babel-plugin-inline-view-configs/__tests__/index-test.js new file mode 100644 index 00000000000000..da09f29a5df4d7 --- /dev/null +++ b/packages/babel-plugin-inline-view-configs/__tests__/index-test.js @@ -0,0 +1,32 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @emails oncall+react_native + * @format + */ + +'use strict'; + +const {transform: babelTransform} = require('@babel/core'); +const fixtures = require('../__test_fixtures__/fixtures.js'); + +function transform(filename) { + return babelTransform(fixtures[filename], { + plugins: [require('@babel/plugin-syntax-flow'), require('../index')], + babelrc: false, + filename, + }).code; +} + +describe('Babel plugin inline view configs', () => { + Object.keys(fixtures) + .sort() + .forEach(fixtureName => { + it(`can inline config for ${fixtureName}`, () => { + expect(transform(fixtureName)).toMatchSnapshot(); + }); + }); +}); diff --git a/packages/babel-plugin-inline-view-configs/index.js b/packages/babel-plugin-inline-view-configs/index.js new file mode 100644 index 00000000000000..235e870912cf53 --- /dev/null +++ b/packages/babel-plugin-inline-view-configs/index.js @@ -0,0 +1,59 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ +'use strict'; + +const {parseString} = require('react-native-codegen/src/parsers/flow'); +const RNCodegen = require('react-native-codegen/src/generators/RNCodegen'); +const path = require('path'); + +function generateViewConfig(filename, code) { + const schema = parseString(code); + + const libraryName = path + .basename(filename) + .replace(/NativeComponent\.js$/, ''); + + return RNCodegen.generateViewConfig({ + schema, + libraryName, + }); +} + +module.exports = function(context) { + return { + pre(state) { + this.code = state.code; + this.filename = state.opts.filename; + this.inserted = false; + }, + visitor: { + TypeAlias(nodePath, state) { + if ( + !this.inserted && + nodePath.node.right && + nodePath.node.right.type === 'GenericTypeAnnotation' && + nodePath.node.right.id.name === 'CodegenNativeComponent' + ) { + const code = generateViewConfig(this.filename, this.code); + + // Remove the original export + nodePath.parentPath.traverse({ + MemberExpression(exportPath) { + if (exportPath.node.property.name === 'exports') { + exportPath.parentPath.remove(); + } + }, + }); + nodePath.insertAfter(context.parse(code).program.body); + this.inserted = true; + } + }, + }, + }; +}; diff --git a/packages/babel-plugin-inline-view-configs/package.json b/packages/babel-plugin-inline-view-configs/package.json new file mode 100644 index 00000000000000..1c7b21410cfa24 --- /dev/null +++ b/packages/babel-plugin-inline-view-configs/package.json @@ -0,0 +1,16 @@ +{ + "version": "0.0.0", + "name": "babel-plugin-inline-view-configs", + "description": "Babel plugin to inline view configs for React Native", + "repository": { + "type": "git", + "url": "git@github.com:facebook/react-native.git" + }, + "dependencies": { + "react-native-codegen": "*" + }, + "devDependencies": { + "@babel/core": "^7.0.0" + }, + "license": "MIT" +} diff --git a/packages/react-native-codegen/BUCK b/packages/react-native-codegen/BUCK index 8cd540b1244cdb..9fab520a5130b5 100644 --- a/packages/react-native-codegen/BUCK +++ b/packages/react-native-codegen/BUCK @@ -2,6 +2,7 @@ load("@fbsource//tools/build_defs:default_platform_defs.bzl", "ANDROID", "APPLE" load("@fbsource//tools/build_defs:fb_native_wrapper.bzl", "fb_native") load("@fbsource//tools/build_defs:fb_xplat_cxx_binary.bzl", "fb_xplat_cxx_binary") load("@fbsource//tools/build_defs/oss:rn_defs.bzl", "rn_xplat_cxx_library") +load("@fbsource//tools/build_defs/third_party:yarn_defs.bzl", "yarn_workspace") load("@fbsource//xplat/js/react-native-github/packages/react-native-codegen:DEFS.bzl", "rn_codegen_test") fb_native.sh_binary( @@ -173,3 +174,25 @@ rn_xplat_cxx_library( ":generated_components-TWO_COMPONENTS_SAME_FILE", ], ) + +yarn_workspace( + name = "yarn-workspace", + srcs = glob( + ["**/*.js"], + exclude = [ + "**/__fixtures__/**", + "**/__flowtests__/**", + "**/__mocks__/**", + "**/__server_snapshot_tests__/**", + "**/__tests__/**", + "**/node_modules/**", + "**/node_modules/.bin/**", + "**/.*", + "**/.*/**", + "**/.*/.*", + "**/*.xcodeproj/**", + "**/*.xcworkspace/**", + ], + ), + visibility = ["PUBLIC"], +) diff --git a/packages/react-native-codegen/package.json b/packages/react-native-codegen/package.json index 7fffd48187652e..85a9de6d5acfaf 100644 --- a/packages/react-native-codegen/package.json +++ b/packages/react-native-codegen/package.json @@ -1,6 +1,6 @@ { "version": "0.0.1", - "name": "react-native-codgen", + "name": "react-native-codegen", "description": "⚛️ Code generation tools for React Native", "repository": { "type": "git", diff --git a/packages/react-native-codegen/src/cli/parser/parser.js b/packages/react-native-codegen/src/cli/parser/parser.js index c1ec866f8a8ba1..1cc5247033ba23 100644 --- a/packages/react-native-codegen/src/cli/parser/parser.js +++ b/packages/react-native-codegen/src/cli/parser/parser.js @@ -14,7 +14,10 @@ const FlowParser = require('../../parsers/flow'); function parseFiles(files: Array) { files.forEach(filename => { - console.log(filename, JSON.stringify(FlowParser.parse(filename), null, 2)); + console.log( + filename, + JSON.stringify(FlowParser.parseFile(filename), null, 2), + ); }); } diff --git a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.js b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.js index 64abcb27935b87..9730f9722ed897 100644 --- a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.js +++ b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.js @@ -33,7 +33,7 @@ function generateFilesWithResults( return files.reduce((aggregated, filename) => { const schema = config.parser === 'flow' - ? FlowParser.parse(filename) + ? FlowParser.parseFile(filename) : SchemaParser.parse(filename); if (schema && schema.modules) { const libraryName = path diff --git a/packages/react-native-codegen/src/generators/RNCodegen.js b/packages/react-native-codegen/src/generators/RNCodegen.js index ac9383f4f2ff6d..1a83cc27f901e8 100644 --- a/packages/react-native-codegen/src/generators/RNCodegen.js +++ b/packages/react-native-codegen/src/generators/RNCodegen.js @@ -118,4 +118,18 @@ module.exports = { return writeMapToFiles(filesToUpdate, outputDirectory); }, + generateViewConfig({libraryName, schema}: Options): string { + schemaValidator.validate(schema); + + const result = generateViewConfigJs + .generate(libraryName, schema) + .values() + .next(); + + if (typeof result.value !== 'string') { + throw new Error(`Failed to generate view config for ${libraryName}`); + } + + return result.value; + }, }; diff --git a/packages/react-native-codegen/src/parsers/flow/__tests__/parser-test.js b/packages/react-native-codegen/src/parsers/flow/__tests__/parser-test.js index 05c7374569a424..3807a1670ba569 100644 --- a/packages/react-native-codegen/src/parsers/flow/__tests__/parser-test.js +++ b/packages/react-native-codegen/src/parsers/flow/__tests__/parser-test.js @@ -22,7 +22,7 @@ describe('RN Codegen Flow Parser', () => { .sort() .forEach(fixtureName => { it(`can generate fixture ${fixtureName}`, () => { - expect(FlowParser.parse(fixtureName)).toMatchSnapshot(); + expect(FlowParser.parseFile(fixtureName)).toMatchSnapshot(); }); }); }); diff --git a/packages/react-native-codegen/src/parsers/flow/index.js b/packages/react-native-codegen/src/parsers/flow/index.js index 861b444412e86b..019560fcf97a5f 100644 --- a/packages/react-native-codegen/src/parsers/flow/index.js +++ b/packages/react-native-codegen/src/parsers/flow/index.js @@ -71,8 +71,7 @@ function getPropProperties(propsTypeName, types) { } } -function parseFileAst(filename: string) { - const contents = fs.readFileSync(filename, 'utf8'); +function processString(contents: string) { const ast = flowParser.parse(contents); const types = getTypes(ast); @@ -96,10 +95,17 @@ function parseFileAst(filename: string) { }; } -function parse(filename: string): ?SchemaType { - return buildSchema(parseFileAst(filename)); +function parseFile(filename: string): ?SchemaType { + const contents = fs.readFileSync(filename, 'utf8'); + + return buildSchema(processString(contents)); +} + +function parseString(contents: string): ?SchemaType { + return buildSchema(processString(contents)); } module.exports = { - parse, + parseFile, + parseString, }; From 504fc0c7d08a0c8e80fb5198c72bba6c0be13de8 Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Fri, 7 Jun 2019 12:23:56 -0700 Subject: [PATCH 0242/1084] Update flow parser to use codegenNativeComponent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: This diff updated the codegen flow types syntax replacing: ``` type Options = { isDeprecatedPaperComponentNameRCT: true, }; type ActivityIndicatorNativeType = CodegenNativeComponent< 'ActivityIndicatorView', NativeProps, Options, >; module.exports = ((requireNativeComponent( 'RCTActivityIndicatorView', ): any): ActivityIndicatorNativeType); ``` with: ``` export default codegenNativeComponent('ActivityIndicatorView', { isDeprecatedPaperComponentNameRCT: true, }); ``` This is from Tim's comment in the [View Config Codegen Quip](https://fb.quip.com/jR2aASHad4Se): > What it CodegenNativeComponent were instead `NativeComponent.fromFlow('…')` that returned `'...'`? >And the Babel plugin swapped it for NativeComponent.fromSchema('...', {…}) which would both register and return '...'? I went with `codegenNativeComponent` because it has nice parity with `requireNativeComponent` I also didn't update the babel output here (we can update that whenever) because I think `registerGeneratedViewConfig` is more clear for what it's doing Reviewed By: cpojer Differential Revision: D15602077 fbshipit-source-id: 2d24dc32136ba6d31724f8c929b51417ba625a58 --- .../ActivityIndicator/ActivityIndicator.js | 2 +- .../ActivityIndicatorViewNativeComponent.js | 21 ++---- .../Slider/SliderNativeComponent.js | 13 ++-- Libraries/Types/CodegenTypes.js | 9 +-- Libraries/Utilities/codegenNativeComponent.js | 41 ++++++++++++ .../__test_fixtures__/fixtures.js | 11 +-- .../__snapshots__/index-test.js.snap | 11 +-- .../babel-plugin-inline-view-configs/index.js | 46 +++++++------ .../src/generators/GenerateViewConfigJs.js | 2 +- .../GenerateViewConfigJs-test.js.snap | 34 +++++----- .../flow/__test_fixtures__/fixtures.js | 67 +++++++------------ .../src/parsers/flow/index.js | 27 +++++--- .../src/parsers/flow/options.js | 6 +- 13 files changed, 143 insertions(+), 147 deletions(-) create mode 100644 Libraries/Utilities/codegenNativeComponent.js diff --git a/Libraries/Components/ActivityIndicator/ActivityIndicator.js b/Libraries/Components/ActivityIndicator/ActivityIndicator.js index 70f73db0ce0cdd..df6cd3c5cc1b90 100644 --- a/Libraries/Components/ActivityIndicator/ActivityIndicator.js +++ b/Libraries/Components/ActivityIndicator/ActivityIndicator.js @@ -21,7 +21,7 @@ import type {ViewProps} from '../View/ViewPropTypes'; const PlatformActivityIndicator = Platform.OS === 'android' ? require('../ProgressBarAndroid/ProgressBarAndroid') - : require('./ActivityIndicatorViewNativeComponent'); + : require('./ActivityIndicatorViewNativeComponent').default; const GRAY = '#999999'; diff --git a/Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeComponent.js b/Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeComponent.js index 213f1d0e796a24..8781a230d4d437 100644 --- a/Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeComponent.js +++ b/Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeComponent.js @@ -10,15 +10,12 @@ 'use strict'; -import type { - WithDefault, - CodegenNativeComponent, -} from '../../Types/CodegenTypes'; +import type {WithDefault} from '../../Types/CodegenTypes'; import type {ColorValue} from '../../StyleSheet/StyleSheetTypes'; import type {ViewProps} from '../View/ViewPropTypes'; -const requireNativeComponent = require('../../ReactNative/requireNativeComponent'); +import codegenNativeComponent from '../../Utilities/codegenNativeComponent'; type NativeProps = $ReadOnly<{| ...ViewProps, @@ -53,16 +50,6 @@ type NativeProps = $ReadOnly<{| size?: ?WithDefault<'small' | 'large', 'small'>, |}>; -type Options = { +export default codegenNativeComponent('ActivityIndicatorView', { isDeprecatedPaperComponentNameRCT: true, -}; - -type ActivityIndicatorNativeType = CodegenNativeComponent< - 'ActivityIndicatorView', - NativeProps, - Options, ->; - -module.exports = ((requireNativeComponent( - 'RCTActivityIndicatorView', -): any): ActivityIndicatorNativeType); +}); diff --git a/Libraries/Components/Slider/SliderNativeComponent.js b/Libraries/Components/Slider/SliderNativeComponent.js index d7d90e0cdab608..004fed84ed8ad5 100644 --- a/Libraries/Components/Slider/SliderNativeComponent.js +++ b/Libraries/Components/Slider/SliderNativeComponent.js @@ -15,15 +15,14 @@ import type { BubblingEvent, DirectEvent, WithDefault, - CodegenNativeComponent, } from '../../Types/CodegenTypes'; +import codegenNativeComponent from '../../Utilities/codegenNativeComponent'; + import type {ColorValue} from '../../StyleSheet/StyleSheetTypes'; import type {ImageSource} from '../../Image/ImageSource'; import type {ViewProps} from '../View/ViewPropTypes'; -const requireNativeComponent = require('../../ReactNative/requireNativeComponent'); - type Event = $ReadOnly<{| value: Float, fromUser?: boolean, @@ -54,11 +53,7 @@ type NativeProps = $ReadOnly<{| onSlidingComplete?: ?(event: DirectEvent) => void, |}>; -type Options = { +module.exports = codegenNativeComponent('Slider', { interfaceOnly: true, isDeprecatedPaperComponentNameRCT: true, -}; - -type SliderType = CodegenNativeComponent<'Slider', NativeProps, Options>; - -module.exports = ((requireNativeComponent('RCTSlider'): any): SliderType); +}); diff --git a/Libraries/Types/CodegenTypes.js b/Libraries/Types/CodegenTypes.js index 4ee7fadd651019..b3e6c853e025cd 100644 --- a/Libraries/Types/CodegenTypes.js +++ b/Libraries/Types/CodegenTypes.js @@ -26,13 +26,6 @@ export type Int32 = number; // // TODO: (rickhanlonii) T44881457 If a default is provided, it should always be optional // but that is currently not supported in the codegen since we require a default -// eslint-disable-next-line no-unused-vars -export type WithDefault = Type; - -// We're not using ComponentName or Options in JS -// We only use these types to codegen native code // // eslint-disable-next-line no-unused-vars -export type CodegenNativeComponent = Class< - NativeComponent, ->; +export type WithDefault = Type; diff --git a/Libraries/Utilities/codegenNativeComponent.js b/Libraries/Utilities/codegenNativeComponent.js new file mode 100644 index 00000000000000..ad55cc84354793 --- /dev/null +++ b/Libraries/Utilities/codegenNativeComponent.js @@ -0,0 +1,41 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow + */ +// TODO: move this file to shims/ReactNative (requires React update and sync) + +'use strict'; + +import type {NativeComponent} from '../../Libraries/Renderer/shims/ReactNative'; +import requireNativeComponent from '../../Libraries/ReactNative/requireNativeComponent'; + +// TODO: import from CodegenSchema once workspaces are enabled +type Options = $ReadOnly<{| + interfaceOnly?: boolean, + isDeprecatedPaperComponentNameRCT?: boolean, +|}>; + +function codegenNativeComponent( + componentName: string, + options?: Options, +): Class> { + let componentNameInUse = componentName; + if (options && options.isDeprecatedPaperComponentNameRCT === true) { + componentNameInUse = `RCT${componentName}`; + } + + // If this function is run at runtime then that means the view configs were not + // generated with the view config babel plugin, so we need to require the native component. + // + // This will be useful during migration, but eventually this will error. + return ((requireNativeComponent(componentNameInUse): any): Class< + NativeComponent, + >); +} + +export default codegenNativeComponent; diff --git a/packages/babel-plugin-inline-view-configs/__test_fixtures__/fixtures.js b/packages/babel-plugin-inline-view-configs/__test_fixtures__/fixtures.js index 8af50cd1e1ffb8..1a26fc15aef783 100644 --- a/packages/babel-plugin-inline-view-configs/__test_fixtures__/fixtures.js +++ b/packages/babel-plugin-inline-view-configs/__test_fixtures__/fixtures.js @@ -16,13 +16,12 @@ export default 'Not a view config' `; const FULL_NATIVE_COMPONENT = ` -const requireNativeComponent = require('requireNativeComponent'); +const codegenNativeComponent = require('codegenNativeComponent'); import type { BubblingEvent, DirectEvent, WithDefault, - CodegenNativeComponent, } from 'CodegenFlowtypes'; import type {ViewProps} from 'ViewPropTypes'; @@ -38,14 +37,10 @@ type ModuleProps = $ReadOnly<{| onBubblingEventDefinedInlineNull: (event: BubblingEvent) => void, |}>; -type Options = { +export default codegenNativeComponent('Module', { interfaceOnly: true, isDeprecatedPaperComponentNameRCT: true, -}; - -type ModuleType = CodegenNativeComponent<'Module', ModuleProps, Options>; - -module.exports = ((requireNativeComponent('RCTModule'): any): ModuleType); +}); `; module.exports = { diff --git a/packages/babel-plugin-inline-view-configs/__tests__/__snapshots__/index-test.js.snap b/packages/babel-plugin-inline-view-configs/__tests__/__snapshots__/index-test.js.snap index 7413b19d349409..898ad51671f144 100644 --- a/packages/babel-plugin-inline-view-configs/__tests__/__snapshots__/index-test.js.snap +++ b/packages/babel-plugin-inline-view-configs/__tests__/__snapshots__/index-test.js.snap @@ -1,9 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Babel plugin inline view configs can inline config for FullNativeComponent.js 1`] = ` -"const requireNativeComponent = require('requireNativeComponent'); +"const codegenNativeComponent = require('codegenNativeComponent'); -import type { BubblingEvent, DirectEvent, WithDefault, CodegenNativeComponent } from 'CodegenFlowtypes'; +import type { BubblingEvent, DirectEvent, WithDefault } from 'CodegenFlowtypes'; import type { ViewProps } from 'ViewPropTypes'; type ModuleProps = $ReadOnly<{| ...ViewProps, // Props @@ -12,11 +12,6 @@ type ModuleProps = $ReadOnly<{| ...ViewProps, onDirectEventDefinedInlineNull: (event: DirectEvent) => void, onBubblingEventDefinedInlineNull: (event: BubblingEvent) => void, |}>; -type Options = { - interfaceOnly: true, - isDeprecatedPaperComponentNameRCT: true, -}; -type ModuleType = CodegenNativeComponent<'Module', ModuleProps, Options>; const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); @@ -42,7 +37,7 @@ const ModuleViewConfig = { } }; registerGeneratedViewConfig('RCTModule', ModuleViewConfig); -module.exports = 'RCTModule'; // RCT prefix present for paper support" +export default 'RCTModule'; // RCT prefix present for paper support" `; exports[`Babel plugin inline view configs can inline config for NotANativeComponent.js 1`] = ` diff --git a/packages/babel-plugin-inline-view-configs/index.js b/packages/babel-plugin-inline-view-configs/index.js index 235e870912cf53..c7ea03798d958c 100644 --- a/packages/babel-plugin-inline-view-configs/index.js +++ b/packages/babel-plugin-inline-view-configs/index.js @@ -25,33 +25,39 @@ function generateViewConfig(filename, code) { }); } +function isCodegenDeclaration(declaration) { + if (!declaration) { + return false; + } + + if ( + declaration.left && + declaration.left.left && + declaration.left.left.name === 'codegenNativeComponent' + ) { + return true; + } else if ( + declaration.callee && + declaration.callee.name && + declaration.callee.name === 'codegenNativeComponent' + ) { + return true; + } + + return false; +} + module.exports = function(context) { return { pre(state) { this.code = state.code; this.filename = state.opts.filename; - this.inserted = false; }, visitor: { - TypeAlias(nodePath, state) { - if ( - !this.inserted && - nodePath.node.right && - nodePath.node.right.type === 'GenericTypeAnnotation' && - nodePath.node.right.id.name === 'CodegenNativeComponent' - ) { - const code = generateViewConfig(this.filename, this.code); - - // Remove the original export - nodePath.parentPath.traverse({ - MemberExpression(exportPath) { - if (exportPath.node.property.name === 'exports') { - exportPath.parentPath.remove(); - } - }, - }); - nodePath.insertAfter(context.parse(code).program.body); - this.inserted = true; + ExportDefaultDeclaration(nodePath, state) { + if (isCodegenDeclaration(nodePath.node.declaration)) { + const viewConfig = generateViewConfig(this.filename, this.code); + nodePath.replaceWithMultiple(context.parse(viewConfig).program.body); } }, }, diff --git a/packages/react-native-codegen/src/generators/GenerateViewConfigJs.js b/packages/react-native-codegen/src/generators/GenerateViewConfigJs.js index d5f8cde857f88a..ef5ec793b09b21 100644 --- a/packages/react-native-codegen/src/generators/GenerateViewConfigJs.js +++ b/packages/react-native-codegen/src/generators/GenerateViewConfigJs.js @@ -89,7 +89,7 @@ const ::_COMPONENT_NAME_::ViewConfig = VIEW_CONFIG; registerGeneratedViewConfig('::_COMPONENT_NAME_WITH_COMPAT_SUPPORT_::', ::_COMPONENT_NAME_::ViewConfig); -module.exports = '::_COMPONENT_NAME_WITH_COMPAT_SUPPORT_::';::_COMPAT_COMMENT_:: +export default '::_COMPONENT_NAME_WITH_COMPAT_SUPPORT_::';::_COMPAT_COMMENT_:: `.trim(); // Replicates the behavior of RCTNormalizeInputEventName in RCTEventDispatcher.m diff --git a/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap b/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap index 1fd81850c2be64..16d056333dfcab 100644 --- a/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap +++ b/packages/react-native-codegen/src/generators/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap @@ -32,7 +32,7 @@ const ArrayPropsNativeComponentViewConfig = { registerGeneratedViewConfig('ArrayPropsNativeComponent', ArrayPropsNativeComponentViewConfig); -module.exports = 'ArrayPropsNativeComponent'; +export default 'ArrayPropsNativeComponent'; ", } `; @@ -63,7 +63,7 @@ const BooleanPropNativeComponentViewConfig = { registerGeneratedViewConfig('BooleanPropNativeComponent', BooleanPropNativeComponentViewConfig); -module.exports = 'BooleanPropNativeComponent'; +export default 'BooleanPropNativeComponent'; ", } `; @@ -94,7 +94,7 @@ const ColorPropNativeComponentViewConfig = { registerGeneratedViewConfig('ColorPropNativeComponent', ColorPropNativeComponentViewConfig); -module.exports = 'ColorPropNativeComponent'; +export default 'ColorPropNativeComponent'; ", } `; @@ -125,7 +125,7 @@ const EnumPropsNativeComponentViewConfig = { registerGeneratedViewConfig('EnumPropsNativeComponent', EnumPropsNativeComponentViewConfig); -module.exports = 'EnumPropsNativeComponent'; +export default 'EnumPropsNativeComponent'; ", } `; @@ -166,7 +166,7 @@ const EventsNestedObjectNativeComponentViewConfig = { registerGeneratedViewConfig('EventsNestedObjectNativeComponent', EventsNestedObjectNativeComponentViewConfig); -module.exports = 'EventsNestedObjectNativeComponent'; +export default 'EventsNestedObjectNativeComponent'; ", } `; @@ -222,7 +222,7 @@ const EventsNativeComponentViewConfig = { registerGeneratedViewConfig('EventsNativeComponent', EventsNativeComponentViewConfig); -module.exports = 'EventsNativeComponent'; +export default 'EventsNativeComponent'; ", } `; @@ -258,7 +258,7 @@ const FloatPropNativeComponentViewConfig = { registerGeneratedViewConfig('FloatPropNativeComponent', FloatPropNativeComponentViewConfig); -module.exports = 'FloatPropNativeComponent'; +export default 'FloatPropNativeComponent'; ", } `; @@ -289,7 +289,7 @@ const ImagePropNativeComponentViewConfig = { registerGeneratedViewConfig('ImagePropNativeComponent', ImagePropNativeComponentViewConfig); -module.exports = 'ImagePropNativeComponent'; +export default 'ImagePropNativeComponent'; ", } `; @@ -322,7 +322,7 @@ const IntegerPropNativeComponentViewConfig = { registerGeneratedViewConfig('IntegerPropNativeComponent', IntegerPropNativeComponentViewConfig); -module.exports = 'IntegerPropNativeComponent'; +export default 'IntegerPropNativeComponent'; ", } `; @@ -363,7 +363,7 @@ const InterfaceOnlyComponentViewConfig = { registerGeneratedViewConfig('RCTInterfaceOnlyComponent', InterfaceOnlyComponentViewConfig); -module.exports = 'RCTInterfaceOnlyComponent'; // RCT prefix present for paper support +export default 'RCTInterfaceOnlyComponent'; // RCT prefix present for paper support ", } `; @@ -397,7 +397,7 @@ const ImageColorPropNativeComponentViewConfig = { registerGeneratedViewConfig('ImageColorPropNativeComponent', ImageColorPropNativeComponentViewConfig); -module.exports = 'ImageColorPropNativeComponent'; +export default 'ImageColorPropNativeComponent'; ", } `; @@ -428,7 +428,7 @@ const PointPropNativeComponentViewConfig = { registerGeneratedViewConfig('PointPropNativeComponent', PointPropNativeComponentViewConfig); -module.exports = 'PointPropNativeComponent'; +export default 'PointPropNativeComponent'; ", } `; @@ -459,7 +459,7 @@ const StringPropComponentViewConfig = { registerGeneratedViewConfig('StringPropComponent', StringPropComponentViewConfig); -module.exports = 'StringPropComponent'; +export default 'StringPropComponent'; ", } `; @@ -490,7 +490,7 @@ const MultiFile1NativeComponentViewConfig = { registerGeneratedViewConfig('MultiFile1NativeComponent', MultiFile1NativeComponentViewConfig); -module.exports = 'MultiFile1NativeComponent'; +export default 'MultiFile1NativeComponent'; const MultiFile2NativeComponentViewConfig = { uiViewClassName: 'MultiFile2NativeComponent', @@ -502,7 +502,7 @@ const MultiFile2NativeComponentViewConfig = { registerGeneratedViewConfig('MultiFile2NativeComponent', MultiFile2NativeComponentViewConfig); -module.exports = 'MultiFile2NativeComponent'; +export default 'MultiFile2NativeComponent'; ", } `; @@ -533,7 +533,7 @@ const MultiComponent1NativeComponentViewConfig = { registerGeneratedViewConfig('MultiComponent1NativeComponent', MultiComponent1NativeComponentViewConfig); -module.exports = 'MultiComponent1NativeComponent'; +export default 'MultiComponent1NativeComponent'; const MultiComponent2NativeComponentViewConfig = { uiViewClassName: 'MultiComponent2NativeComponent', @@ -545,7 +545,7 @@ const MultiComponent2NativeComponentViewConfig = { registerGeneratedViewConfig('MultiComponent2NativeComponent', MultiComponent2NativeComponentViewConfig); -module.exports = 'MultiComponent2NativeComponent'; +export default 'MultiComponent2NativeComponent'; ", } `; diff --git a/packages/react-native-codegen/src/parsers/flow/__test_fixtures__/fixtures.js b/packages/react-native-codegen/src/parsers/flow/__test_fixtures__/fixtures.js index d971d6dba4e5dc..a54aa2bb62bebc 100644 --- a/packages/react-native-codegen/src/parsers/flow/__test_fixtures__/fixtures.js +++ b/packages/react-native-codegen/src/parsers/flow/__test_fixtures__/fixtures.js @@ -55,6 +55,7 @@ const EVENT_DEFINITION = ` } } `; + const ONE_OF_EACH_PROP_EVENT_DEFAULT_AND_OPTIONS = ` /** * Copyright (c) Facebook, Inc. and its affiliates. @@ -68,14 +69,13 @@ const ONE_OF_EACH_PROP_EVENT_DEFAULT_AND_OPTIONS = ` 'use strict'; -const requireNativeComponent = require('requireNativeComponent'); +const codegenNativeComponent = require('codegenNativeComponent'); import type { BubblingEvent, DirectEvent, WithDefault, - CodegenNativeComponent, -} from 'CodegenFlowtypes'; +} from 'CodegenTypes'; import type {ViewProps} from 'ViewPropTypes'; @@ -90,14 +90,10 @@ type ModuleProps = $ReadOnly<{| onBubblingEventDefinedInlineNull: (event: BubblingEvent) => void, |}>; -type Options = { +export default codegenNativeComponent('Module', { interfaceOnly: true, isDeprecatedPaperComponentNameRCT: true, -}; - -type ModuleType = CodegenNativeComponent<'Module', ModuleProps, Options>; - -module.exports = ((requireNativeComponent('RCTModule'): any): ModuleType); +}); `; const ALL_PROP_TYPES_NO_EVENTS = ` @@ -113,14 +109,13 @@ const ALL_PROP_TYPES_NO_EVENTS = ` 'use strict'; -const requireNativeComponent = require('requireNativeComponent'); +const codegenNativeComponent = require('codegenNativeComponent'); import type { Int32, Float, WithDefault, - CodegenNativeComponent, -} from 'CodegenFlowtypes'; +} from 'CodegenTypes'; import type {ColorValue, ColorArrayValue, PointValue} from 'StyleSheetTypes'; import type {ImageSource} from 'ImageSource'; @@ -184,9 +179,7 @@ type ModuleProps = $ReadOnly<{| point_optional_both?: ?PointValue, |}>; -type ModuleType = CodegenNativeComponent<'Module', ModuleProps, Options>; - -module.exports = ((requireNativeComponent('RCTModule'): any): ModuleType); +export default codegenNativeComponent('Module'); `; const ARRAY_PROP_TYPES_NO_EVENTS = ` @@ -202,14 +195,13 @@ const ARRAY_PROP_TYPES_NO_EVENTS = ` 'use strict'; -const requireNativeComponent = require('requireNativeComponent'); +const codegenNativeComponent = require('codegenNativeComponent'); import type { Int32, Float, WithDefault, - CodegenNativeComponent, -} from 'CodegenFlowtypes'; +} from 'CodegenTypes'; import type {ColorValue, PointValue} from 'StyleSheetTypes'; import type {ImageSource} from 'ImageSource'; @@ -268,9 +260,7 @@ type ModuleProps = $ReadOnly<{| array_point_optional_both?: ?$ReadOnlyArray, |}>; -type ModuleType = CodegenNativeComponent<'Module', ModuleProps, Options>; - -module.exports = ((requireNativeComponent('RCTModule'): any): ModuleType); +export default codegenNativeComponent('Module'); `; const EVENTS_DEFINED_INLINE_WITH_ALL_TYPES = ` @@ -286,15 +276,14 @@ const EVENTS_DEFINED_INLINE_WITH_ALL_TYPES = ` 'use strict'; -const requireNativeComponent = require('requireNativeComponent'); +const codegenNativeComponent = require('codegenNativeComponent'); import type { Int32, Float, BubblingEvent, DirectEvent, - CodegenNativeComponent, -} from 'CodegenFlowtypes'; +} from 'CodegenTypes'; import type {ViewProps} from 'ViewPropTypes'; @@ -368,9 +357,7 @@ type ModuleProps = $ReadOnly<{| ) => void, |}>; -type ModuleType = CodegenNativeComponent<'Module', ModuleProps>; - -module.exports = ((requireNativeComponent('RCTModule'): any): ModuleType); +export default codegenNativeComponent('Module'); `; const EVENTS_DEFINED_IN_FILE_WITH_ALL_TYPES = ` @@ -386,15 +373,14 @@ const EVENTS_DEFINED_IN_FILE_WITH_ALL_TYPES = ` 'use strict'; -const requireNativeComponent = require('requireNativeComponent'); +const codegenNativeComponent = require('codegenNativeComponent'); import type { Float, Int32, BubblingEvent, DirectEvent, - CodegenNativeComponent, -} from 'CodegenFlowtypes'; +} from 'CodegenTypes'; import type {ViewProps} from 'ViewPropTypes'; @@ -430,9 +416,7 @@ type ModuleProps = $ReadOnly<{| ) => void, |}>; -type ModuleType = CodegenNativeComponent<'Module', ModuleProps>; - -module.exports = ((requireNativeComponent('RCTModule'): any): ModuleType); +export default codegenNativeComponent('Module'); `; const EVENTS_DEFINED_AS_NULL_IN_FILE = ` @@ -448,13 +432,12 @@ const EVENTS_DEFINED_AS_NULL_IN_FILE = ` 'use strict'; -const requireNativeComponent = require('requireNativeComponent'); +const codegenNativeComponent = require('codegenNativeComponent'); import type { BubblingEvent, DirectEvent, - CodegenNativeComponent, -} from 'CodegenFlowtypes'; +} from 'CodegenTypes'; import type {ViewProps} from 'ViewPropTypes'; @@ -492,9 +475,8 @@ type ModuleProps = $ReadOnly<{| ) => void, |}>; -type ModuleType = CodegenNativeComponent<'Module', ModuleProps>; -module.exports = ((requireNativeComponent('RCTModule'): any): ModuleType); +export default codegenNativeComponent('Module'); `; const EVENTS_DEFINED_AS_NULL_INLINE = ` @@ -510,13 +492,12 @@ const EVENTS_DEFINED_AS_NULL_INLINE = ` 'use strict'; -const requireNativeComponent = require('requireNativeComponent'); +const codegenNativeComponent = require('codegenNativeComponent'); import type { BubblingEvent, DirectEvent, - CodegenNativeComponent, -} from 'CodegenFlowtypes'; +} from 'CodegenTypese'; import type {ViewProps} from 'ViewPropTypes'; @@ -549,9 +530,7 @@ type ModuleProps = $ReadOnly<{| ) => void, |}>; -type ModuleType = CodegenNativeComponent<'Module', ModuleProps>; - -module.exports = ((requireNativeComponent('RCTModule'): any): ModuleType); +export default codegenNativeComponent('Module'); `; module.exports = { diff --git a/packages/react-native-codegen/src/parsers/flow/index.js b/packages/react-native-codegen/src/parsers/flow/index.js index 019560fcf97a5f..bf1129bcb157fb 100644 --- a/packages/react-native-codegen/src/parsers/flow/index.js +++ b/packages/react-native-codegen/src/parsers/flow/index.js @@ -20,19 +20,24 @@ const {getProps} = require('./props'); const {getOptions} = require('./options'); const {getExtendsProps} = require('./extends'); -function findConfig(types) { +function findConfig(ast) { const foundConfigs = []; - Object.keys(types).forEach(key => { + const allExports = ast.body.filter( + node => node.type === 'ExportDefaultDeclaration', + ); + + allExports.forEach(statement => { try { - const type = types[key]; - if (type.right.id.name === 'CodegenNativeComponent') { - const params = type.right.typeParameters.params; + if (statement.declaration.callee.name === 'codegenNativeComponent') { + const typeArgumentParams = statement.declaration.typeArguments.params; + const funcArgumentParams = statement.declaration.arguments; + const nativeComponentType = {}; - nativeComponentType.componentName = params[0].value; - nativeComponentType.propsTypeName = params[1].id.name; - if (params.length > 2) { - nativeComponentType.optionsTypeName = params[2].id.name; + nativeComponentType.propsTypeName = typeArgumentParams[0].id.name; + nativeComponentType.componentName = funcArgumentParams[0].value; + if (funcArgumentParams.length > 1) { + nativeComponentType.optionsExpression = funcArgumentParams[1]; } foundConfigs.push(nativeComponentType); } @@ -75,12 +80,12 @@ function processString(contents: string) { const ast = flowParser.parse(contents); const types = getTypes(ast); - const {componentName, propsTypeName, optionsTypeName} = findConfig(types); + const {componentName, propsTypeName, optionsExpression} = findConfig(ast); const propProperties = getPropProperties(propsTypeName, types); const extendsProps = getExtendsProps(propProperties); - const options = getOptions(types[optionsTypeName]); + const options = getOptions(optionsExpression); const props = getProps(propProperties); const events = getEvents(propProperties, types); diff --git a/packages/react-native-codegen/src/parsers/flow/options.js b/packages/react-native-codegen/src/parsers/flow/options.js index 157de570179f37..1b42e25fa3851a 100644 --- a/packages/react-native-codegen/src/parsers/flow/options.js +++ b/packages/react-native-codegen/src/parsers/flow/options.js @@ -15,12 +15,12 @@ import type {OptionsShape} from '../../CodegenSchema.js'; // $FlowFixMe there's no flowtype for ASTs type OptionsAST = Object; -function getOptions(optionsDefinition: OptionsAST): ?OptionsShape { - if (!optionsDefinition) { +function getOptions(optionsExpression: OptionsAST): ?OptionsShape { + if (!optionsExpression) { return null; } try { - return optionsDefinition.right.properties.reduce((options, prop) => { + return optionsExpression.properties.reduce((options, prop) => { options[prop.key.name] = prop.value.value; return options; }, {}); From 97d439e0baee3cba2b2e0841bbb8f8db88965fb1 Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Fri, 7 Jun 2019 12:23:56 -0700 Subject: [PATCH 0243/1084] Remove checked-in view configs and js1 build viewconfigs Summary: Now that we have the babel plugin, we can remove the checked in view configs Note that this requires switching the old NativeComponent.js files back to `requireNativeComponent` for open source support (until the babel plugin and codegen are published to a package) The babel plugin replaces this export with the inline view config Reviewed By: cpojer Differential Revision: D15524779 fbshipit-source-id: ab819ce6f24cb2f15a1897ed6d510a0db6aff3a1 --- .../viewconfigs/generate-view-configs-cli.js | 38 --------- .../cli/viewconfigs/generate-view-configs.js | 81 ------------------- .../cli/viewconfigs/generate-view-configs.sh | 15 ---- 3 files changed, 134 deletions(-) delete mode 100644 packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js delete mode 100644 packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.js delete mode 100755 packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.sh diff --git a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js deleted file mode 100644 index 2ce923a97a16ac..00000000000000 --- a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs-cli.js +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - * @format - */ - -'use strict'; - -const generate = require('./generate-view-configs'); -const yargs = require('yargs'); - -const yargv = yargs.strict().option('t', { - alias: 'test', - describe: 'Test the changes and do not write files', - requiresArg: false, - type: 'boolean', -}); - -const argv = yargv.argv; -const fileList = argv._[0].split('\n'); - -const CURRENT_VIEW_CONFIG_FILES = []; - -generate( - fileList.filter(fileName => - CURRENT_VIEW_CONFIG_FILES.find(supportedFileName => - fileName.endsWith(supportedFileName), - ), - ), - /* $FlowFixMe(>=0.99.0 site=react_native_fb) This comment suppresses an - * error found when Flow v0.99 was deployed. To see the error, delete this - * comment and run Flow. */ - {test: argv.test, parser: 'flow'}, -); diff --git a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.js b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.js deleted file mode 100644 index 9730f9722ed897..00000000000000 --- a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.js +++ /dev/null @@ -1,81 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - * @format - */ - -'use strict'; - -const RNCodegen = require('../../generators/RNCodegen.js'); -const SchemaParser = require('../../parsers/schema'); -const FlowParser = require('../../parsers/flow'); - -const path = require('path'); - -type Result = $ReadOnly<{| - libraryName: string, - success: boolean, -|}>; - -type Config = $ReadOnly<{| - test?: boolean, - parser?: 'schema' | 'flow', -|}>; - -function generateFilesWithResults( - files: Array, - config: Config, -): Array { - return files.reduce((aggregated, filename) => { - const schema = - config.parser === 'flow' - ? FlowParser.parseFile(filename) - : SchemaParser.parse(filename); - if (schema && schema.modules) { - const libraryName = path - .basename(filename) - .replace(/NativeComponent\.js$/, ''); - const success = RNCodegen.generate( - { - schema, - libraryName, - outputDirectory: path.dirname(filename), - }, - {generators: ['view-configs'], test: config.test}, - ); - - aggregated.push({ - libraryName, - success, - }); - } - return aggregated; - }, []); -} - -function generate(files: Array, config: Config): void { - console.log(`${config.test ? 'Testing' : 'Generating'} view configs`); - - const results = generateFilesWithResults(files, config); - - const failed = results.filter(result => !result.success); - const totalCount = results.length; - - console.log( - `\n${config.test ? 'Tested' : 'Generated'} ${totalCount} view configs`, - ); - - if (failed.length) { - if (config.test === true) { - console.error(`${failed.length} configs changed`); - console.error("Please re-run 'js1 build viewconfigs'"); - } - process.exit(1); - } -} - -module.exports = generate; diff --git a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.sh b/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.sh deleted file mode 100755 index 355c9fe560b83a..00000000000000 --- a/packages/react-native-codegen/src/cli/viewconfigs/generate-view-configs.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -# set -euo pipefail - -set -e -set -u - -THIS_DIR=$(cd -P "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo "${BASH_SOURCE[0]}")")" && pwd) - -FILES=$(find "$JS_DIR/" -name "*NativeComponent.js" -print -type f) - -# shellcheck source=xplat/js/env-utils/setup_env_vars.sh -source "$THIS_DIR/../../../../../../env-utils/setup_env_vars.sh" - -exec "$FLOW_NODE_BINARY" "$THIS_DIR/generate-view-configs-cli.js" "$@" "$FILES" From e5a8e3a53e8106b861624ece5e7a70e662548467 Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Fri, 7 Jun 2019 13:08:28 -0700 Subject: [PATCH 0244/1084] Initialize TurboModules after creation Summary: When `ModuleHolder` instantiates `NativeModules`, it calls the `initialize()` method. We should replicate this call in the TurboModule system. `NativeModule.initialize()` is meant to be called after ReactApplicationContext is initialized. TurboModuleManager is initialized after ReactApplicationContext is initialized. Therefore, after we create the TurboModule, it should be safe to call `initialize()` on it. Reviewed By: mdvacca Differential Revision: D15711540 fbshipit-source-id: c2ef1a2ab164996bfc5716d81b3b3c716bf0e120 --- .../react/turbomodule/core/TurboModuleManager.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManager.java b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManager.java index 511dd690f31a03..c887c777bc050f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManager.java @@ -12,6 +12,7 @@ import com.facebook.react.bridge.CatalystInstance; import com.facebook.react.bridge.JSIModule; import com.facebook.react.bridge.JavaScriptContextHolder; +import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.queue.MessageQueueThread; import com.facebook.react.turbomodule.core.interfaces.JSCallInvokerHolder; @@ -53,6 +54,12 @@ protected TurboModule getJavaModule(String name) { final TurboModule turboModule = mTurbomoduleManagerDelegate.getModule(name); if (turboModule != null) { + /** + * TurboModuleManager is initialized after ReactApplicationContext has been setup. + * Therefore, it's safe to call initialize on the TurboModule. + */ + ((NativeModule)turboModule).initialize(); + mTurboModules.put(name, turboModule); } } From 3312146ced29c36c762954d957b5b9c715d625d8 Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Fri, 7 Jun 2019 13:08:28 -0700 Subject: [PATCH 0245/1084] Make NativeModule names public Summary: To implement the `getModule` method of `TurboReactPackages`, we need to be able to access the JS Names of NativeModule classes. Reviewed By: fkgozali Differential Revision: D15711544 fbshipit-source-id: 51a649d08410557a4bdbf20d065bf98646a8d18a --- .../com/facebook/react/modules/appstate/AppStateModule.java | 2 +- .../java/com/facebook/react/modules/blob/BlobModule.java | 2 +- .../com/facebook/react/modules/blob/FileReaderModule.java | 2 +- .../facebook/react/modules/camera/ImageEditingManager.java | 2 +- .../com/facebook/react/modules/camera/ImageStoreManager.java | 5 +++-- .../com/facebook/react/modules/network/NetworkingModule.java | 2 +- .../java/com/facebook/react/modules/share/ShareModule.java | 5 +++-- 7 files changed, 11 insertions(+), 9 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.java index 6dc073cd275d54..4b43bb7c0cf39a 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.java @@ -26,7 +26,7 @@ public class AppStateModule extends ReactContextBaseJavaModule implements LifecycleEventListener, WindowFocusChangeListener { - protected static final String NAME = "AppState"; + public static final String NAME = "AppState"; public static final String APP_STATE_ACTIVE = "active"; public static final String APP_STATE_BACKGROUND = "background"; diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java index 830180c6ffc308..d968e5800c7813 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java @@ -48,7 +48,7 @@ @ReactModule(name = BlobModule.NAME) public class BlobModule extends ReactContextBaseJavaModule { - protected static final String NAME = "BlobModule"; + public static final String NAME = "BlobModule"; private final Map mBlobs = new HashMap<>(); diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/FileReaderModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/FileReaderModule.java index a5293261ad9876..bb8f35e8d37208 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/FileReaderModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/FileReaderModule.java @@ -20,7 +20,7 @@ @ReactModule(name = FileReaderModule.NAME) public class FileReaderModule extends ReactContextBaseJavaModule { - protected static final String NAME = "FileReaderModule"; + public static final String NAME = "FileReaderModule"; private static final String ERROR_INVALID_BLOB = "ERROR_INVALID_BLOB"; public FileReaderModule(ReactApplicationContext reactContext) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageEditingManager.java b/ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageEditingManager.java index 417b7a002a59ae..152afdfd340f2c 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageEditingManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageEditingManager.java @@ -55,7 +55,7 @@ @ReactModule(name = ImageEditingManager.NAME) public class ImageEditingManager extends ReactContextBaseJavaModule { - protected static final String NAME = "ImageEditingManager"; + public static final String NAME = "ImageEditingManager"; private static final List LOCAL_URI_PREFIXES = Arrays.asList( "file://", "content://"); diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageStoreManager.java b/ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageStoreManager.java index 235cdd1931bb7a..afe625ffc56fc5 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageStoreManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageStoreManager.java @@ -27,9 +27,10 @@ import com.facebook.react.bridge.ReactMethod; import com.facebook.react.module.annotations.ReactModule; -@ReactModule(name = "ImageStoreManager") +@ReactModule(name = ImageStoreManager.NAME) public class ImageStoreManager extends ReactContextBaseJavaModule { + public static final String NAME = "ImageStoreManager"; private static final int BUFFER_SIZE = 8192; public ImageStoreManager(ReactApplicationContext reactContext) { @@ -38,7 +39,7 @@ public ImageStoreManager(ReactApplicationContext reactContext) { @Override public String getName() { - return "ImageStoreManager"; + return NAME; } /** diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java index 888fcc25f03c46..9c90084b9292b5 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java @@ -103,7 +103,7 @@ public interface ResponseHandler { WritableMap toResponseData(ResponseBody body) throws IOException; } - protected static final String NAME = "Networking"; + public static final String NAME = "Networking"; private static final String TAG = "NetworkingModule"; private static final String CONTENT_ENCODING_HEADER_NAME = "content-encoding"; diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/share/ShareModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/share/ShareModule.java index ccfab744eb4974..4db2c4ae608257 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/share/ShareModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/share/ShareModule.java @@ -22,9 +22,10 @@ /** * Intent module. Launch other activities or open URLs. */ -@ReactModule(name = "ShareModule") +@ReactModule(name = ShareModule.NAME) public class ShareModule extends ReactContextBaseJavaModule { + public static final String NAME = "ShareModule"; /* package */ static final String ACTION_SHARED = "sharedAction"; /* package */ static final String ERROR_INVALID_CONTENT = "E_INVALID_CONTENT"; /* package */ static final String ERROR_UNABLE_TO_OPEN_DIALOG = "E_UNABLE_TO_OPEN_DIALOG"; @@ -35,7 +36,7 @@ public ShareModule(ReactApplicationContext reactContext) { @Override public String getName() { - return "ShareModule"; + return NAME; } /** From e5c96a85fc947ae3d6195441b82bb6247ff35dce Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Fri, 7 Jun 2019 17:17:16 -0700 Subject: [PATCH 0246/1084] Fix layoutTime calculation Summary: LayoutTime calculation is also trivially wrong. Quick fix. Reviewed By: shergin Differential Revision: D15725167 fbshipit-source-id: b06672b9df9cbaa6c54aa97a4c0b58a43f70d5b2 --- ReactCommon/fabric/mounting/MountingTelemetry.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactCommon/fabric/mounting/MountingTelemetry.cpp b/ReactCommon/fabric/mounting/MountingTelemetry.cpp index 5f5bdf30ab7a2d..121c51e455100e 100644 --- a/ReactCommon/fabric/mounting/MountingTelemetry.cpp +++ b/ReactCommon/fabric/mounting/MountingTelemetry.cpp @@ -47,7 +47,7 @@ int64_t MountingTelemetry::getCommitTime() const { int64_t MountingTelemetry::getLayoutTime() const { assert(layoutStartTime_ != kUndefinedTime); assert(layoutEndTime_ != kUndefinedTime); - return layoutEndTime_ - layoutEndTime_; + return layoutEndTime_ - layoutStartTime_; } int64_t MountingTelemetry::getCommitStartTime() const { From 9c76e14b07cd83c1f481ff7457c965c86256c304 Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Sat, 8 Jun 2019 00:41:06 -0700 Subject: [PATCH 0247/1084] Turn FBMainReactPackage into a TurboReactPackage Summary: `ReactTurboModuleManagerDelegate` only understands `TurboReactPackage`s. So, we need to convert `FBMainReactPackage` and all its dependent packages into `TurboReactPackage`. Reviewed By: fkgozali Differential Revision: D15711546 fbshipit-source-id: df626d542a6477b116c867299219156423c6364a --- .../react/testing/StringRecordingModule.java | 4 +- .../java/com/facebook/react/tests/core/BUCK | 2 + .../react/tests/core/ReactRootViewTest.java | 58 +++- .../react/shell/MainReactPackage.java | 324 +++++++----------- 4 files changed, 176 insertions(+), 212 deletions(-) diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/StringRecordingModule.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/StringRecordingModule.java index 6dd70646f0d77c..9103a265ec5deb 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/StringRecordingModule.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/StringRecordingModule.java @@ -19,11 +19,13 @@ */ public class StringRecordingModule extends BaseJavaModule { + public static final String NAME = "Recording"; + private final List mCalls = new ArrayList(); @Override public String getName() { - return "Recording"; + return NAME; } @ReactMethod diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/core/BUCK b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/core/BUCK index 5d3380b6f8b05a..d14a43f82cfef1 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/core/BUCK +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/core/BUCK @@ -22,6 +22,8 @@ rn_android_library( react_native_target("java/com/facebook/react:react"), react_native_target("java/com/facebook/react/bridge:bridge"), react_native_target("java/com/facebook/react/common:common"), + react_native_target("java/com/facebook/react/module/annotations:annotations"), + react_native_target("java/com/facebook/react/module/model:model"), react_native_target("java/com/facebook/react/shell:shell"), react_native_target("java/com/facebook/react/uimanager:uimanager"), ]) + ([ diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/core/ReactRootViewTest.java b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/core/ReactRootViewTest.java index acc108fb3c39dc..6f6d1495385305 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/core/ReactRootViewTest.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/core/ReactRootViewTest.java @@ -26,11 +26,16 @@ import com.facebook.react.uimanager.PixelUtil; import java.util.ArrayList; import java.util.List; +import java.util.HashMap; +import java.util.Map; import javax.inject.Provider; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import com.facebook.react.module.model.ReactModuleInfo; +import com.facebook.react.module.model.ReactModuleInfoProvider; +import com.facebook.react.module.annotations.ReactModule; @RunWith(AndroidJUnit4.class) public class ReactRootViewTest { @@ -42,18 +47,47 @@ private interface ReactRootViewTestModule extends JavaScriptModule { final StringRecordingModule mRecordingModule = new StringRecordingModule(); final ReactPackage mReactPackage = new MainReactPackage() { @Override - public List getNativeModules(ReactApplicationContext context) { - List modules = new ArrayList<>(super.getNativeModules(context)); - modules.add( - ModuleSpec.nativeModuleSpec( - StringRecordingModule.class, - new Provider() { - @Override - public NativeModule get() { - return mRecordingModule; - } - })); - return modules; + public NativeModule getModule(String name, ReactApplicationContext context) { + if (name.equals(StringRecordingModule.NAME)) { + return mRecordingModule; + } + + return super.getModule(name, context); + } + + @Override + public ReactModuleInfoProvider getReactModuleInfoProvider() { + final ReactModuleInfoProvider provider = super.getReactModuleInfoProvider(); + + return new ReactModuleInfoProvider() { + private Map mModuleInfos = null; + + @Override + public Map getReactModuleInfos() { + if (mModuleInfos != null) { + return mModuleInfos; + } + + mModuleInfos = new HashMap<>(); + mModuleInfos.putAll(provider.getReactModuleInfos()); + + Class moduleClass = StringRecordingModule.class; + ReactModule reactModule = moduleClass.getAnnotation(ReactModule.class); + + mModuleInfos.put( + reactModule.name(), + new ReactModuleInfo( + reactModule.name(), + moduleClass.getName(), + reactModule.canOverrideExistingModule(), + reactModule.needsEagerInit(), + reactModule.hasConstants(), + reactModule.isCxxModule(), + false)); + + return mModuleInfos; + } + }; } }; diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java index cf1f81113f8028..bb0d8ee52e1eb6 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java +++ b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java @@ -63,7 +63,14 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import javax.annotation.Nullable; import javax.inject.Provider; +import com.facebook.react.TurboReactPackage; +import com.facebook.react.ViewManagerOnDemandReactPackage; +import java.util.Map; +import com.facebook.react.module.model.ReactModuleInfo; +import com.facebook.react.module.annotations.ReactModule; +import java.util.HashMap; /** * Package defining basic modules and view managers. @@ -93,9 +100,8 @@ ToastModule.class, VibrationModule.class, WebSocketModule.class, - }) -public class MainReactPackage extends LazyReactPackage { +public class MainReactPackage extends TurboReactPackage { private MainPackageConfig mConfig; @@ -110,201 +116,60 @@ public MainReactPackage(MainPackageConfig config) { } @Override - public List getNativeModules(final ReactApplicationContext context) { - return Arrays.asList( - ModuleSpec.nativeModuleSpec( - AccessibilityInfoModule.class, - new Provider() { - @Override - public NativeModule get() { - return new AccessibilityInfoModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - AppStateModule.class, - new Provider() { - @Override - public NativeModule get() { - return new AppStateModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - BlobModule.class, - new Provider() { - @Override - public NativeModule get() { - return new BlobModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - FileReaderModule.class, - new Provider() { - @Override - public NativeModule get() { - return new FileReaderModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - AsyncStorageModule.class, - new Provider() { - @Override - public NativeModule get() { - return new AsyncStorageModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - CameraRollManager.class, - new Provider() { - @Override - public NativeModule get() { - return new CameraRollManager(context); - } - }), - ModuleSpec.nativeModuleSpec( - ClipboardModule.class, - new Provider() { - @Override - public NativeModule get() { - return new ClipboardModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - DatePickerDialogModule.class, - new Provider() { - @Override - public NativeModule get() { - return new DatePickerDialogModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - DialogModule.class, - new Provider() { - @Override - public NativeModule get() { - return new DialogModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - FrescoModule.class, - new Provider() { - @Override - public NativeModule get() { - return new FrescoModule( - context, true, mConfig != null ? mConfig.getFrescoConfig() : null); - } - }), - ModuleSpec.nativeModuleSpec( - I18nManagerModule.class, - new Provider() { - @Override - public NativeModule get() { - return new I18nManagerModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - ImageEditingManager.class, - new Provider() { - @Override - public NativeModule get() { - return new ImageEditingManager(context); - } - }), - ModuleSpec.nativeModuleSpec( - ImageLoaderModule.class, - new Provider() { - @Override - public NativeModule get() { - return new ImageLoaderModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - ImageStoreManager.class, - new Provider() { - @Override - public NativeModule get() { - return new ImageStoreManager(context); - } - }), - ModuleSpec.nativeModuleSpec( - IntentModule.class, - new Provider() { - @Override - public NativeModule get() { - return new IntentModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - NativeAnimatedModule.class, - new Provider() { - @Override - public NativeModule get() { - return new NativeAnimatedModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - NetworkingModule.class, - new Provider() { - @Override - public NativeModule get() { - return new NetworkingModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - PermissionsModule.class, - new Provider() { - @Override - public NativeModule get() { - return new PermissionsModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - ShareModule.class, - new Provider() { - @Override - public NativeModule get() { - return new ShareModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - StatusBarModule.class, - new Provider() { - @Override - public NativeModule get() { - return new StatusBarModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - TimePickerDialogModule.class, - new Provider() { - @Override - public NativeModule get() { - return new TimePickerDialogModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - ToastModule.class, - new Provider() { - @Override - public NativeModule get() { - return new ToastModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - VibrationModule.class, - new Provider() { - @Override - public NativeModule get() { - return new VibrationModule(context); - } - }), - ModuleSpec.nativeModuleSpec( - WebSocketModule.class, - new Provider() { - @Override - public NativeModule get() { - return new WebSocketModule(context); - } - })); + public @Nullable NativeModule getModule(String name, ReactApplicationContext context) { + switch (name) { + case AccessibilityInfoModule.NAME: + return new AccessibilityInfoModule(context); + case AppStateModule.NAME: + return new AppStateModule(context); + case BlobModule.NAME: + return new BlobModule(context); + case FileReaderModule.NAME: + return new FileReaderModule(context); + case AsyncStorageModule.NAME: + return new AsyncStorageModule(context); + case CameraRollManager.NAME: + return new CameraRollManager(context); + case ClipboardModule.NAME: + return new ClipboardModule(context); + case DatePickerDialogModule.FRAGMENT_TAG: + return new DatePickerDialogModule(context); + case DialogModule.NAME: + return new DialogModule(context); + case FrescoModule.NAME: + return new FrescoModule( + context, true, mConfig != null ? mConfig.getFrescoConfig() : null); + case I18nManagerModule.NAME: + return new I18nManagerModule(context); + case ImageEditingManager.NAME: + return new ImageEditingManager(context); + case ImageLoaderModule.NAME: + return new ImageLoaderModule(context); + case ImageStoreManager.NAME: + return new ImageStoreManager(context); + case IntentModule.NAME: + return new IntentModule(context); + case NativeAnimatedModule.NAME: + return new NativeAnimatedModule(context); + case NetworkingModule.NAME: + return new NetworkingModule(context); + case PermissionsModule.NAME: + return new PermissionsModule(context); + case ShareModule.NAME: + return new ShareModule(context); + case StatusBarModule.NAME: + return new StatusBarModule(context); + case TimePickerDialogModule.FRAGMENT_TAG: + return new TimePickerDialogModule(context); + case ToastModule.NAME: + return new ToastModule(context); + case VibrationModule.NAME: + return new VibrationModule(context); + case WebSocketModule.NAME: + return new WebSocketModule(context); + default: + return null; + } } @Override @@ -343,7 +208,68 @@ public List createViewManagers(ReactApplicationContext reactContext @Override public ReactModuleInfoProvider getReactModuleInfoProvider() { - // This has to be done via reflection or we break open source. - return LazyReactPackage.getReactModuleInfoProviderViaReflection(this); + try { + Class reactModuleInfoProviderClass = + Class.forName("com.facebook.react.MainReactPackage$$ReactModuleInfoProvider"); + return (ReactModuleInfoProvider) reactModuleInfoProviderClass.newInstance(); + } catch (ClassNotFoundException e) { + // In OSS case, the annotation processor does not run. We fall back on creating this byhand + Class[] moduleList = + new Class[] { + AccessibilityInfoModule.class, + AppStateModule.class, + BlobModule.class, + FileReaderModule.class, + AsyncStorageModule.class, + CameraRollManager.class, + ClipboardModule.class, + DatePickerDialogModule.class, + DialogModule.class, + FrescoModule.class, + I18nManagerModule.class, + ImageEditingManager.class, + ImageLoaderModule.class, + ImageStoreManager.class, + IntentModule.class, + NativeAnimatedModule.class, + NetworkingModule.class, + PermissionsModule.class, + ShareModule.class, + StatusBarModule.class, + TimePickerDialogModule.class, + ToastModule.class, + VibrationModule.class, + WebSocketModule.class + }; + + final Map reactModuleInfoMap = new HashMap<>(); + for (Class moduleClass : moduleList) { + ReactModule reactModule = moduleClass.getAnnotation(ReactModule.class); + + reactModuleInfoMap.put( + reactModule.name(), + new ReactModuleInfo( + reactModule.name(), + moduleClass.getName(), + reactModule.canOverrideExistingModule(), + reactModule.needsEagerInit(), + reactModule.hasConstants(), + reactModule.isCxxModule(), + false)); + } + + return new ReactModuleInfoProvider() { + @Override + public Map getReactModuleInfos() { + return reactModuleInfoMap; + } + }; + } catch (InstantiationException e) { + throw new RuntimeException( + "No ReactModuleInfoProvider for CoreModulesPackage$$ReactModuleInfoProvider", e); + } catch (IllegalAccessException e) { + throw new RuntimeException( + "No ReactModuleInfoProvider for CoreModulesPackage$$ReactModuleInfoProvider", e); + } } } From 6236798a3fce3c4bdbd8ce340e20db16cd67e03a Mon Sep 17 00:00:00 2001 From: David Vacca Date: Sat, 8 Jun 2019 07:10:41 -0700 Subject: [PATCH 0248/1084] Create feature flag to log extra data in ReactWebView Summary: This diff creates a new react feature flag to enable extra logging on React Web Views Reviewed By: RSNara Differential Revision: D15729871 fbshipit-source-id: 931d4a1b022c6a405228bf896b50ecc7a44478d1 --- .../java/com/facebook/react/config/ReactFeatureFlags.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java b/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java index 94ae2364c6bb49..d6401919987305 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java +++ b/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java @@ -43,4 +43,10 @@ public class ReactFeatureFlags { * {@link com.facebook.react.uimanager.NativeViewHierarchyManager dropView} */ public static boolean logDroppedViews = false; + + /* + * This feature flag enables extra logging on ReactWebViews. + * Default value is false. + */ + public static boolean enableExtraWebViewLogs = false; } From 47a17fb69ef16ba92ad587ddd3fb448f09692c4d Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Sat, 8 Jun 2019 22:37:26 -0700 Subject: [PATCH 0249/1084] Fabric: Fixed incorrect SchedulerToolbox initialization in RCTSurfacePresenter Summary: We have to use a getter instead of an ivar to enable lazy initialization of ContextContainer. Reviewed By: mdvacca Differential Revision: D15731877 fbshipit-source-id: eb4d0e70c337026a91cb12a3eb26ed4d94f39f9f --- React/Fabric/RCTSurfacePresenter.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/React/Fabric/RCTSurfacePresenter.mm b/React/Fabric/RCTSurfacePresenter.mm index adc049828ad2cb..17f4491a7c582a 100644 --- a/React/Fabric/RCTSurfacePresenter.mm +++ b/React/Fabric/RCTSurfacePresenter.mm @@ -197,7 +197,7 @@ - (RCTScheduler *)_scheduler auto runtimeExecutor = [self _runtimeExecutor]; auto toolbox = SchedulerToolbox{}; - toolbox.contextContainer = _contextContainer; + toolbox.contextContainer = self.contextContainer; toolbox.componentRegistryFactory = componentRegistryFactory; toolbox.runtimeExecutor = runtimeExecutor; From c94d7d520fb2b7509d4d5fca3976d9e66616308e Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Mon, 10 Jun 2019 01:38:20 -0700 Subject: [PATCH 0250/1084] Remove ToolbarAndroid Summary: After upgrading `react-native-gesture-handler` in D15701771, we can finally remove this :) Reviewed By: rubennorte Differential Revision: D15713072 fbshipit-source-id: 5039478f211a9bdb6ba0d17bed0841e188d00b46 --- Libraries/react-native/react-native-implementation.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js index 1fb35b409b6bdd..bc20dfac8f27c2 100644 --- a/Libraries/react-native/react-native-implementation.js +++ b/Libraries/react-native/react-native-implementation.js @@ -332,10 +332,6 @@ module.exports = { get ViewPropTypes() { return require('../DeprecatedPropTypes/DeprecatedViewPropTypes'); }, - // TODO(cpojer): Temporary fix for missing Toolbar - get ToolbarAndroid() { - return require('../Components/UnimplementedViews/UnimplementedView'); - }, }; if (__DEV__) { From b6dc9587e61035f812b8be5bb47c79bd133c70b7 Mon Sep 17 00:00:00 2001 From: Sidharth Guglani Date: Mon, 10 Jun 2019 01:43:25 -0700 Subject: [PATCH 0251/1084] add node layout event and pass it java layer Summary: Listen to NodeLayout event and passes this event callback to java layer along with the information whether layout or measure was done in this pass Reviewed By: davidaurelio Differential Revision: D15696021 fbshipit-source-id: 8c5ca69330a9baca26b77052d4965cc67fe97c75 --- .../src/main/java/com/facebook/yoga/YogaEventListener.java | 2 ++ ReactCommon/yoga/yoga/Yoga.cpp | 2 +- ReactCommon/yoga/yoga/event/event.h | 6 ++++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaEventListener.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaEventListener.java index 97791224577d67..cc7e9ebd0da671 100644 --- a/ReactAndroid/src/main/java/com/facebook/yoga/YogaEventListener.java +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaEventListener.java @@ -12,4 +12,6 @@ public interface YogaEventListener { void onNodeMeasure(YogaNode node); + void onNodeLayout(YogaNode node, boolean performLayout); + } diff --git a/ReactCommon/yoga/yoga/Yoga.cpp b/ReactCommon/yoga/yoga/Yoga.cpp index c46104be1d33e1..6c739a069e0999 100644 --- a/ReactCommon/yoga/yoga/Yoga.cpp +++ b/ReactCommon/yoga/yoga/Yoga.cpp @@ -3670,7 +3670,7 @@ bool YGLayoutNodeInternal( YGMarkerLayoutData& layoutMarkerData, void* const layoutContext) { #ifdef YG_ENABLE_EVENTS - Event::publish(node); + Event::publish(node, {performLayout, layoutContext}); #endif YGLayout* layout = &node->getLayout(); diff --git a/ReactCommon/yoga/yoga/event/event.h b/ReactCommon/yoga/yoga/event/event.h index bff8dbfd8952fc..9dcd73b6a0fa59 100644 --- a/ReactCommon/yoga/yoga/event/event.h +++ b/ReactCommon/yoga/yoga/event/event.h @@ -82,5 +82,11 @@ struct Event::TypedData { void* layoutContext; }; +template <> +struct Event::TypedData { + bool performLayout; + void* layoutContext; +}; + } // namespace yoga } // namespace facebook From 2c1fd6f764f92669351713a6373a113ea6cb5da2 Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Mon, 10 Jun 2019 03:26:44 -0700 Subject: [PATCH 0252/1084] Add codegen flowtypes to UnimplementedNativeView Summary: This diff adds the generated view config for UnimplementedNativeView Note: I believe this component was created in JS just for the codegen because it's unused anywhere Reviewed By: cpojer Differential Revision: D15494268 fbshipit-source-id: 8d17465fe59861a299b76565d6edbaf168f45906 --- .../UnimplementedNativeView.js | 29 ------------------- .../UnimplementedNativeViewNativeComponent.js | 27 +++++++++++++++++ 2 files changed, 27 insertions(+), 29 deletions(-) delete mode 100644 Libraries/Components/UnimplementedViews/UnimplementedNativeView.js create mode 100644 Libraries/Components/UnimplementedViews/UnimplementedNativeViewNativeComponent.js diff --git a/Libraries/Components/UnimplementedViews/UnimplementedNativeView.js b/Libraries/Components/UnimplementedViews/UnimplementedNativeView.js deleted file mode 100644 index 9e1d5f64af019c..00000000000000 --- a/Libraries/Components/UnimplementedViews/UnimplementedNativeView.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @flow - */ - -'use strict'; - -const requireNativeComponent = require('../../ReactNative/requireNativeComponent'); - -import type {ViewProps} from '../View/ViewPropTypes'; -import type {ViewStyleProp} from '../../StyleSheet/StyleSheet'; -import type {NativeComponent} from '../../Renderer/shims/ReactNative'; - -type NativeProps = $ReadOnly<{| - ...ViewProps, - name?: ?string, - style?: ?ViewStyleProp, -|}>; - -type UnimplementedViewNativeType = Class>; - -module.exports = ((requireNativeComponent( - 'UnimplementedNativeView', -): any): UnimplementedViewNativeType); diff --git a/Libraries/Components/UnimplementedViews/UnimplementedNativeViewNativeComponent.js b/Libraries/Components/UnimplementedViews/UnimplementedNativeViewNativeComponent.js new file mode 100644 index 00000000000000..6898d1acd699db --- /dev/null +++ b/Libraries/Components/UnimplementedViews/UnimplementedNativeViewNativeComponent.js @@ -0,0 +1,27 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow + */ + +'use strict'; + +import type {WithDefault} from '../../Types/CodegenTypes'; +import type {ViewProps} from '../View/ViewPropTypes'; + +import codegenNativeComponent from '../../Utilities/codegenNativeComponent'; + +type NativeProps = $ReadOnly<{| + ...ViewProps, + name?: ?WithDefault, +|}>; + +// NOTE: This compoenent is not implemented in paper +// Do not include in paper builds +module.exports = codegenNativeComponent( + './UnimplementedNativeViewNativeViewConfig', +); From 5b7be95a1d00f813223c97ce8fe69118951ad412 Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Mon, 10 Jun 2019 03:26:44 -0700 Subject: [PATCH 0253/1084] Use generated view config for iOS Switch Summary: Adds a generated view config for iOS Switch Note: this required some refactoring because the SwitchNativeComponent file included both iOS and android componets, so I broke them out into: - AndroidSwitchNativeComponent (not generated) - SwitchNativeComponent (generated) The schema that we're using is for the iOS version so that's the config that's generated here Reviewed By: cpojer Differential Revision: D15495402 fbshipit-source-id: 07b3bc9c780cbf8f6cbf66e976e15981cefcadfa --- .../Switch/AndroidSwitchNativeComponent.js | 48 ++++++++++ Libraries/Components/Switch/Switch.js | 93 ++++++++++++------- .../Switch/SwitchNativeComponent.js | 66 +++++-------- Libraries/Types/CoreEventTypes.js | 6 -- 4 files changed, 129 insertions(+), 84 deletions(-) create mode 100644 Libraries/Components/Switch/AndroidSwitchNativeComponent.js diff --git a/Libraries/Components/Switch/AndroidSwitchNativeComponent.js b/Libraries/Components/Switch/AndroidSwitchNativeComponent.js new file mode 100644 index 00000000000000..c8c9bba9ada41f --- /dev/null +++ b/Libraries/Components/Switch/AndroidSwitchNativeComponent.js @@ -0,0 +1,48 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +const {NativeComponent} = require('../../Renderer/shims/ReactNative'); + +const requireNativeComponent = require('../../ReactNative/requireNativeComponent'); + +import type {SyntheticEvent} from '../../Types/CoreEventTypes'; +import type {ViewProps} from '../View/ViewPropTypes'; + +type SwitchChangeEvent = SyntheticEvent< + $ReadOnly<{| + value: boolean, + |}>, +>; + +type NativeProps = $ReadOnly<{| + ...ViewProps, + + // Props + disabled?: ?boolean, + enabled?: ?boolean, + thumbColor?: ?string, + trackColorForFalse?: ?string, + trackColorForTrue?: ?string, + value?: ?boolean, + on?: ?boolean, + thumbTintColor?: ?string, + trackTintColor?: ?string, + + // Events + onChange?: ?(event: SwitchChangeEvent) => mixed, +|}>; + +type SwitchNativeComponentType = Class>; + +module.exports = ((requireNativeComponent( + 'AndroidSwitch', +): any): SwitchNativeComponentType); diff --git a/Libraries/Components/Switch/Switch.js b/Libraries/Components/Switch/Switch.js index d47c61b00b04b0..dfd4067e33063b 100644 --- a/Libraries/Components/Switch/Switch.js +++ b/Libraries/Components/Switch/Switch.js @@ -11,14 +11,20 @@ 'use strict'; const SwitchNativeComponent = require('./SwitchNativeComponent'); +const AndroidSwitchNativeComponent = require('./AndroidSwitchNativeComponent'); const Platform = require('../../Utilities/Platform'); const React = require('react'); const StyleSheet = require('../../StyleSheet/StyleSheet'); -import type {SwitchChangeEvent} from '../../Types/CoreEventTypes'; +import type {SyntheticEvent} from '../../Types/CoreEventTypes'; import type {ColorValue} from '../../StyleSheet/StyleSheetTypes'; import type {ViewProps} from '../View/ViewPropTypes'; -import type {NativeAndroidProps, NativeIOSProps} from './SwitchNativeComponent'; + +type SwitchChangeEvent = SyntheticEvent< + $ReadOnly<{| + value: boolean, + |}>, +>; export type Props = $ReadOnly<{| ...ViewProps, @@ -83,7 +89,9 @@ export type Props = $ReadOnly<{| * supplied `value` prop instead of the expected result of any user actions. */ class Switch extends React.Component { - _nativeSwitchRef: ?React.ElementRef; + _nativeSwitchRef: ?React.ElementRef< + typeof SwitchNativeComponent | typeof AndroidSwitchNativeComponent, + >; render() { const { @@ -130,37 +138,50 @@ class Switch extends React.Component { } } - const platformProps = - Platform.OS === 'android' - ? ({ - enabled: disabled !== true, - on: value === true, - style, - thumbTintColor: _thumbColor, - trackColorForFalse: _trackColorForFalse, - trackColorForTrue: _trackColorForTrue, - trackTintColor: - value === true ? _trackColorForTrue : _trackColorForFalse, - }: NativeAndroidProps) - : ({ - disabled, - onTintColor: _trackColorForTrue, - style: StyleSheet.compose( - {height: 31, width: 51}, - StyleSheet.compose( - style, - ios_backgroundColor == null - ? null - : { - backgroundColor: ios_backgroundColor, - borderRadius: 16, - }, - ), - ), - thumbTintColor: _thumbColor, - tintColor: _trackColorForFalse, - value: value === true, - }: NativeIOSProps); + if (Platform.OS === 'android') { + const platformProps = { + enabled: disabled !== true, + on: value === true, + style, + thumbTintColor: _thumbColor, + trackColorForFalse: _trackColorForFalse, + trackColorForTrue: _trackColorForTrue, + trackTintColor: + value === true ? _trackColorForTrue : _trackColorForFalse, + }; + + return ( + + ); + } + + const platformProps = { + disabled, + onTintColor: _trackColorForTrue, + style: StyleSheet.compose( + {height: 31, width: 51}, + StyleSheet.compose( + style, + ios_backgroundColor == null + ? null + : { + backgroundColor: ios_backgroundColor, + borderRadius: 16, + }, + ), + ), + thumbTintColor: _thumbColor, + tintColor: _trackColorForFalse, + value: value === true, + }; return ( { }; _handleSwitchNativeComponentRef = ( - ref: ?React.ElementRef, + ref: ?React.ElementRef< + typeof SwitchNativeComponent | typeof AndroidSwitchNativeComponent, + >, ) => { this._nativeSwitchRef = ref; }; diff --git a/Libraries/Components/Switch/SwitchNativeComponent.js b/Libraries/Components/Switch/SwitchNativeComponent.js index b3be4dfaa12d22..b9c113b3b27cb0 100644 --- a/Libraries/Components/Switch/SwitchNativeComponent.js +++ b/Libraries/Components/Switch/SwitchNativeComponent.js @@ -10,55 +10,35 @@ 'use strict'; -const Platform = require('../../Utilities/Platform'); -const ReactNative = require('../../Renderer/shims/ReactNative'); - -const requireNativeComponent = require('../../ReactNative/requireNativeComponent'); - -import type {SwitchChangeEvent} from '../../Types/CoreEventTypes'; +import type {BubblingEvent, WithDefault} from '../../Types/CodegenTypes'; +import type {ColorValue} from '../../StyleSheet/StyleSheetTypes'; import type {ViewProps} from '../View/ViewPropTypes'; -type SwitchProps = $ReadOnly<{| - ...ViewProps, - disabled?: ?boolean, - onChange?: ?(event: SwitchChangeEvent) => mixed, - thumbColor?: ?string, - trackColorForFalse?: ?string, - trackColorForTrue?: ?string, - value?: ?boolean, -|}>; - -// @see ReactSwitchManager.java -export type NativeAndroidProps = $ReadOnly<{| - ...SwitchProps, +import codegenNativeComponent from '../../Utilities/codegenNativeComponent'; - enabled?: ?boolean, - on?: ?boolean, - thumbTintColor?: ?string, - trackTintColor?: ?string, +type SwitchChangeEvent = $ReadOnly<{| + value: boolean, |}>; -// @see RCTSwitchManager.m -export type NativeIOSProps = $ReadOnly<{| - ...SwitchProps, +type NativeProps = $ReadOnly<{| + ...ViewProps, - onTintColor?: ?string, - thumbTintColor?: ?string, - tintColor?: ?string, -|}>; + // Props + disabled?: ?WithDefault, + value?: ?WithDefault, + tintColor?: ?ColorValue, + onTintColor?: ?ColorValue, + thumbTintColor?: ?ColorValue, -type SwitchNativeComponentType = Class< - ReactNative.NativeComponent< - $ReadOnly<{| - ...NativeAndroidProps, - ...NativeIOSProps, - |}>, - >, ->; + // Deprecated props + thumbColor?: ?ColorValue, + trackColorForFalse?: ?ColorValue, + trackColorForTrue?: ?ColorValue, -const SwitchNativeComponent: SwitchNativeComponentType = - Platform.OS === 'android' - ? (requireNativeComponent('AndroidSwitch'): any) - : (requireNativeComponent('RCTSwitch'): any); + // Events + onChange?: ?(event: BubblingEvent) => mixed, +|}>; -module.exports = SwitchNativeComponent; +module.exports = codegenNativeComponent('Switch', { + isDeprecatedPaperComponentNameRCT: true, +}); diff --git a/Libraries/Types/CoreEventTypes.js b/Libraries/Types/CoreEventTypes.js index abe3ca172f0181..a8dd79ea17f5d6 100644 --- a/Libraries/Types/CoreEventTypes.js +++ b/Libraries/Types/CoreEventTypes.js @@ -129,9 +129,3 @@ export type ScrollEvent = SyntheticEvent< responderIgnoreScroll?: boolean, |}>, >; - -export type SwitchChangeEvent = SyntheticEvent< - $ReadOnly<{| - value: boolean, - |}>, ->; From d0792d4b8ac42711dfd9fccb782f16e72ce3e335 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Mon, 10 Jun 2019 03:27:07 -0700 Subject: [PATCH 0254/1084] Add ReactFragment for Android Summary: React Native on Android has currently been focused and targeted at using an Activity for its main form of instantiation. While this has probably worked for most companies and developers, you lose some of the modularity of a more cohesive application when working in a "brown-field" project that is currently native. This hurts more companies that are looking to adopt React Native and slowly implement it in a fully native application. A lot of developers follow Android's guidelines of using Fragments in their projects, even if it is a debated subject in the Android community, and this addition will allow others to embrace React Native more freely. (I even assume it could help with managing navigation state in applications that contain a decent amount of Native code and would be appreciated in those projects. Such as sharing the Toolbar, TabBar, ViewPager, etc in Native Android) Even with this addition, a developer will still need to host the fragment in an activity, but now that activity can contain native logic like a Drawer, Tabs, ViewPager, etc. Test plan (required) We have been using this class at Hudl for over a couple of months and have found it valuable. If the community agrees on the addition, I can add documentation to the Android sections to include notes about the potential of this Fragment. If the community agrees on the addition, I can update one or more of the examples in the /Examples folder and make use of the Fragment, or even create a new example that uses a native layout manager like Drawer, Tabs, Viewpager, etc) Make sure tests pass on both Travis and Circle CI. _To Note:_ There is also talk of using React Native inside Android Fragment's without any legit documentation, this could help remedy some of that with more documentation included in this PR https://facebook.github.io/react-native/releases/0.26/docs/embedded-app-android.html#sharing-a-reactinstance-across-multiple-activities-fragments-in-your-app Others have also requested something similar and have a half-baked solution as well http://stackoverflow.com/questions/35221447/react-native-inside-a-fragment Release Notes [ANDROID][FEATURE][ReactAndroid/src/main/java/com/facebook/react/ReactFragment.java] - Adds support for Android's Fragment system. This allows for a more hybrid application. Reviewed By: cpojer Differential Revision: D15731340 fbshipit-source-id: 74b7aaedcfd6ad6e074ff911cd7f18a5111caf5c --- .../facebook/react/ReactActivityDelegate.java | 68 ++---- .../com/facebook/react/ReactDelegate.java | 147 ++++++++++++ .../com/facebook/react/ReactFragment.java | 210 ++++++++++++++++++ 3 files changed, 371 insertions(+), 54 deletions(-) create mode 100644 ReactAndroid/src/main/java/com/facebook/react/ReactDelegate.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/ReactFragment.java diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactActivityDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/ReactActivityDelegate.java index c6534217a084e3..fcfbea9b4d37b2 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactActivityDelegate.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactActivityDelegate.java @@ -15,8 +15,7 @@ import com.facebook.infer.annotation.Assertions; import com.facebook.react.bridge.Callback; -import com.facebook.react.devsupport.DoubleTapReloadRecognizer; -import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; +import com.facebook.react.uimanager.RootView; import com.facebook.react.modules.core.PermissionListener; import javax.annotation.Nullable; @@ -31,10 +30,9 @@ public class ReactActivityDelegate { private final @Nullable Activity mActivity; private final @Nullable String mMainComponentName; - private @Nullable ReactRootView mReactRootView; - private @Nullable DoubleTapReloadRecognizer mDoubleTapReloadRecognizer; private @Nullable PermissionListener mPermissionListener; private @Nullable Callback mPermissionsCallback; + private ReactDelegate mReactDelegate; @Deprecated public ReactActivityDelegate(Activity activity, @Nullable String mainComponentName) { @@ -52,7 +50,7 @@ public ReactActivityDelegate(ReactActivity activity, @Nullable String mainCompon } protected ReactRootView createRootView() { - return new ReactRootView(getContext()); + return mReactDelegate.createRootView(); } /** @@ -67,7 +65,7 @@ protected ReactNativeHost getReactNativeHost() { } public ReactInstanceManager getReactInstanceManager() { - return getReactNativeHost().getReactInstanceManager(); + return mReactDelegate.getReactInstanceManager(); } public String getMainComponentName() { @@ -76,36 +74,23 @@ public String getMainComponentName() { protected void onCreate(Bundle savedInstanceState) { String mainComponentName = getMainComponentName(); - if (mainComponentName != null) { + mReactDelegate = new ReactDelegate(getPlainActivity(), getReactNativeHost(), mainComponentName, getLaunchOptions()); + if (mMainComponentName != null) { loadApp(mainComponentName); } - mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer(); } protected void loadApp(String appKey) { - if (mReactRootView != null) { - throw new IllegalStateException("Cannot loadApp while app is already running."); - } - mReactRootView = createRootView(); - mReactRootView.startReactApplication( - getReactNativeHost().getReactInstanceManager(), - appKey, - getLaunchOptions()); - getPlainActivity().setContentView(mReactRootView); + mReactDelegate.loadApp(appKey); + getPlainActivity().setContentView(mReactDelegate.getReactRootView()); } protected void onPause() { - if (getReactNativeHost().hasInstance()) { - getReactNativeHost().getReactInstanceManager().onHostPause(getPlainActivity()); - } + mReactDelegate.onHostPause(); } protected void onResume() { - if (getReactNativeHost().hasInstance()) { - getReactNativeHost().getReactInstanceManager().onHostResume( - getPlainActivity(), - (DefaultHardwareBackBtnHandler) getPlainActivity()); - } + mReactDelegate.onHostResume(); if (mPermissionsCallback != null) { mPermissionsCallback.invoke(); @@ -114,20 +99,11 @@ protected void onResume() { } protected void onDestroy() { - if (mReactRootView != null) { - mReactRootView.unmountReactApplication(); - mReactRootView = null; - } - if (getReactNativeHost().hasInstance()) { - getReactNativeHost().getReactInstanceManager().onHostDestroy(getPlainActivity()); - } + mReactDelegate.onHostDestroy(); } public void onActivityResult(int requestCode, int resultCode, Intent data) { - if (getReactNativeHost().hasInstance()) { - getReactNativeHost().getReactInstanceManager() - .onActivityResult(getPlainActivity(), requestCode, resultCode, data); - } + mReactDelegate.onActivityResult(requestCode, resultCode, data, true); } public boolean onKeyDown(int keyCode, KeyEvent event) { @@ -141,19 +117,7 @@ && getReactNativeHost().getUseDeveloperSupport() } public boolean onKeyUp(int keyCode, KeyEvent event) { - if (getReactNativeHost().hasInstance() && getReactNativeHost().getUseDeveloperSupport()) { - if (keyCode == KeyEvent.KEYCODE_MENU) { - getReactNativeHost().getReactInstanceManager().showDevOptionsDialog(); - return true; - } - boolean didDoubleTapR = Assertions.assertNotNull(mDoubleTapReloadRecognizer) - .didDoubleTapR(keyCode, getPlainActivity().getCurrentFocus()); - if (didDoubleTapR) { - getReactNativeHost().getReactInstanceManager().getDevSupportManager().handleReloadJS(); - return true; - } - } - return false; + return mReactDelegate.shouldShowDevMenuOrReload(keyCode, event); } public boolean onKeyLongPress(int keyCode, KeyEvent event) { @@ -167,11 +131,7 @@ && getReactNativeHost().getUseDeveloperSupport() } public boolean onBackPressed() { - if (getReactNativeHost().hasInstance()) { - getReactNativeHost().getReactInstanceManager().onBackPressed(); - return true; - } - return false; + return mReactDelegate.onBackPressed(); } public boolean onNewIntent(Intent intent) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/ReactDelegate.java new file mode 100644 index 00000000000000..e219c8be3c6626 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactDelegate.java @@ -0,0 +1,147 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.react; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.view.KeyEvent; + +import com.facebook.infer.annotation.Assertions; +import com.facebook.react.devsupport.DoubleTapReloadRecognizer; +import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; + +import javax.annotation.Nullable; + +/** + * A delegate for handling React Application support. This delegate is unaware whether it is used in + * an {@link Activity} or a {@link android.app.Fragment}. + */ +public class ReactDelegate { + + private final Activity mActivity; + private ReactRootView mReactRootView; + + @Nullable + private final String mMainComponentName; + + @Nullable + private Bundle mLaunchOptions; + + @Nullable + private DoubleTapReloadRecognizer mDoubleTapReloadRecognizer; + + private ReactNativeHost mReactNativeHost; + + + public ReactDelegate(Activity activity, ReactNativeHost reactNativeHost, @Nullable String appKey, @Nullable Bundle launchOptions) { + mActivity = activity; + mMainComponentName = appKey; + mLaunchOptions = launchOptions; + mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer(); + mReactNativeHost = reactNativeHost; + } + + public void onHostResume() { + if (getReactNativeHost().hasInstance()) { + if (mActivity instanceof DefaultHardwareBackBtnHandler) { + getReactNativeHost().getReactInstanceManager().onHostResume(mActivity, (DefaultHardwareBackBtnHandler) mActivity); + } else { + throw new ClassCastException("Host Activity does not implement DefaultHardwareBackBtnHandler"); + } + } + } + + public void onHostPause() { + if (getReactNativeHost().hasInstance()) { + getReactNativeHost().getReactInstanceManager().onHostPause(mActivity); + } + } + + public void onHostDestroy() { + if (mReactRootView != null) { + mReactRootView.unmountReactApplication(); + mReactRootView = null; + } + if (getReactNativeHost().hasInstance()) { + getReactNativeHost().getReactInstanceManager().onHostDestroy(mActivity); + } + } + + public boolean onBackPressed() { + if (getReactNativeHost().hasInstance()) { + getReactNativeHost().getReactInstanceManager().onBackPressed(); + return true; + } + return false; + } + + public void onActivityResult(int requestCode, int resultCode, Intent data, boolean shouldForwardToReactInstance) { + if (getReactNativeHost().hasInstance() && shouldForwardToReactInstance) { + getReactNativeHost().getReactInstanceManager().onActivityResult(mActivity, requestCode, resultCode, data); + } + } + + public void loadApp() { + loadApp(mMainComponentName); + } + + public void loadApp(String appKey) { + if (mReactRootView != null) { + throw new IllegalStateException("Cannot loadApp while app is already running."); + } + mReactRootView = createRootView(); + mReactRootView.startReactApplication( + getReactNativeHost().getReactInstanceManager(), + appKey, + mLaunchOptions); + + } + + public ReactRootView getReactRootView() { + return mReactRootView; + } + + + protected ReactRootView createRootView() { + return new ReactRootView(mActivity); + } + + /** + * Handles delegating the {@link Activity#onKeyUp(int, KeyEvent)} method to determine whether + * the application should show the developer menu or should reload the React Application. + * + * @return true if we consume the event and either shoed the develop menu or reloaded the application. + */ + public boolean shouldShowDevMenuOrReload(int keyCode, KeyEvent event) { + if (getReactNativeHost().hasInstance() && getReactNativeHost().getUseDeveloperSupport()) { + if (keyCode == KeyEvent.KEYCODE_MENU) { + getReactNativeHost().getReactInstanceManager().showDevOptionsDialog(); + return true; + } + boolean didDoubleTapR = Assertions.assertNotNull(mDoubleTapReloadRecognizer).didDoubleTapR(keyCode, mActivity.getCurrentFocus()); + if (didDoubleTapR) { + getReactNativeHost().getReactInstanceManager().getDevSupportManager().handleReloadJS(); + return true; + } + } + return false; + } + + /** + * Get the {@link ReactNativeHost} used by this app. + */ + private ReactNativeHost getReactNativeHost() { + return mReactNativeHost; + } + + public ReactInstanceManager getReactInstanceManager() { + return getReactNativeHost().getReactInstanceManager(); + } + +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactFragment.java b/ReactAndroid/src/main/java/com/facebook/react/ReactFragment.java new file mode 100644 index 00000000000000..6673c8955276f6 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactFragment.java @@ -0,0 +1,210 @@ + +/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + +package com.facebook.react; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.Intent; +import android.os.Build; +import android.os.Bundle; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.facebook.react.modules.core.PermissionAwareActivity; +import com.facebook.react.modules.core.PermissionListener; + +import javax.annotation.Nullable; + +import androidx.fragment.app.Fragment; + +/** +* Fragment for creating a React View. This allows the developer to "embed" a React Application +* inside native components such as a Drawer, ViewPager, etc. +*/ +public class ReactFragment extends Fragment implements PermissionAwareActivity { + +private static final String ARG_COMPONENT_NAME = "arg_component_name"; +private static final String ARG_LAUNCH_OPTIONS = "arg_launch_options"; + +private ReactDelegate mReactDelegate; + +@Nullable +private PermissionListener mPermissionListener; + + +public ReactFragment() { + // Required empty public constructor +} + +/** + * @param componentName The name of the react native component + * @return A new instance of fragment ReactFragment. + */ +private static ReactFragment newInstance(String componentName, Bundle launchOptions) { + ReactFragment fragment = new ReactFragment(); + Bundle args = new Bundle(); + args.putString(ARG_COMPONENT_NAME, componentName); + args.putBundle(ARG_LAUNCH_OPTIONS, launchOptions); + fragment.setArguments(args); + return fragment; +} + +// region Lifecycle +@Override +public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + String mainComponentName = null; + Bundle launchOptions = null; + if (getArguments() != null) { + mainComponentName = getArguments().getString(ARG_COMPONENT_NAME); + launchOptions = getArguments().getBundle(ARG_LAUNCH_OPTIONS); + } + if (mainComponentName == null) { + throw new IllegalStateException("Cannot loadApp if component name is null"); + } + mReactDelegate = new ReactDelegate(getActivity(), getReactNativeHost(), mainComponentName, launchOptions); +} + +/** + * Get the {@link ReactNativeHost} used by this app. By default, assumes + * {@link Activity#getApplication()} is an instance of {@link ReactApplication} and calls + * {@link ReactApplication#getReactNativeHost()}. Override this method if your application class + * does not implement {@code ReactApplication} or you simply have a different mechanism for + * storing a {@code ReactNativeHost}, e.g. as a static field somewhere. + */ +protected ReactNativeHost getReactNativeHost() { + return ((ReactApplication) getActivity().getApplication()).getReactNativeHost(); +} + +@Override +public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + mReactDelegate.loadApp(); + return mReactDelegate.getReactRootView(); +} + +@Override +public void onResume() { + super.onResume(); + mReactDelegate.onHostResume(); +} + +@Override +public void onPause() { + super.onPause(); + mReactDelegate.onHostPause(); +} + +@Override +public void onDestroy() { + super.onDestroy(); + mReactDelegate.onHostDestroy(); +} +// endregion + +@Override +public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + mReactDelegate.onActivityResult(requestCode, resultCode, data, false); +} + +/** + * Helper to forward hardware back presses to our React Native Host + * + * This must be called via a forward from your host Activity + * + */ +public boolean onBackPressed() { + return mReactDelegate.onBackPressed(); +} + +/** + * Helper to forward onKeyUp commands from our host Activity. + * This allows ReactFragment to handle double tap reloads and dev menus + * + * This must be called via a forward from your host Activity + * + * @param keyCode keyCode + * @param event event + * @return true if we handled onKeyUp + */ +public boolean onKeyUp(int keyCode, KeyEvent event) { + return mReactDelegate.shouldShowDevMenuOrReload(keyCode, event); +} + +@Override +public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (mPermissionListener != null && + mPermissionListener.onRequestPermissionsResult(requestCode, permissions, grantResults)) { + mPermissionListener = null; + } +} + +@Override +public int checkPermission(String permission, int pid, int uid) { + return getActivity().checkPermission(permission, pid, uid); +} + +@TargetApi(Build.VERSION_CODES.M) +@Override +public int checkSelfPermission(String permission) { + return getActivity().checkSelfPermission(permission); +} + +@TargetApi(Build.VERSION_CODES.M) +@Override +public void requestPermissions(String[] permissions, int requestCode, PermissionListener listener) { + mPermissionListener = listener; + requestPermissions(permissions, requestCode); +} + +/** + * Builder class to help instantiate a ReactFragment + */ +public static class Builder { + + String mComponentName; + Bundle mLaunchOptions; + + public Builder() { + mComponentName = null; + mLaunchOptions = null; + } + + /** + * Set the Component name for our React Native instance. + * + * @param componentName The name of the component + * @return Builder + */ + public Builder setComponentName(String componentName) { + mComponentName = componentName; + return this; + } + + /** + * Set the Launch Options for our React Native instance. + * + * @param launchOptions launchOptions + * @return Builder + */ + public Builder setLaunchOptions(Bundle launchOptions) { + mLaunchOptions = launchOptions; + return this; + } + + public ReactFragment build() { + return ReactFragment.newInstance(mComponentName, mLaunchOptions); + } + +} +} From ae231c83220941e0e5aae74ff184467f75438452 Mon Sep 17 00:00:00 2001 From: Onti Vals Date: Mon, 10 Jun 2019 03:44:16 -0700 Subject: [PATCH 0255/1084] Scrolling fixes (#25105) Summary: Scrolling improvements in ReactAndroid: 1. Issue: With current ReactHorizontalScrollView behavior, it treats all views as focusable, regardless of if they are in view or not. This is fine for non-paged horizontal scroll view, but when paged this allows focus on elements that are not within the current page. Combined with logic to scroll to the focused view, this breaks the paging for ReactHorizontalScrollView. Fix: limit the focusable elements to only elements that are currently in view when ReactHorizontalScrollView has paging enabled 2. Issue: When keyboard is attached and user tries to navigate through Tab key, Scroll views do not scroll to the focused child. Since ReactScrollView handles layout changes on JS side, it does not call super.onlayout due to which mIsLayoutDirty flag in android ScrollView remains true and prevents scrolling to child when requestChildFocus is called. Fix: To fix the focus navigation, we are overriding requestChildFocus method in ReactScrollView. We are not checking any dirty layout flag and scrolling to child directly. This will fix focus navigation issue for KeyEvents which are not handled by android's ScrollView, for example: KEYCODE_TAB. Same applies to ReactHorizontalScrollView. 3. Set Android ScrollView to be non-focusable when scroll is disabled. Prior to this change, non-scrollable Scrollview would still be focusable, causing a poor keyboarding experience ## Changelog [Android] [Fixed] Scrolling improvements in ReactAndroid Pull Request resolved: https://github.com/facebook/react-native/pull/25105 Differential Revision: D15737563 Pulled By: mdvacca fbshipit-source-id: 0d57563415c68668dc1acb05fb3399e6645c9595 --- .../scroll/ReactHorizontalScrollView.java | 147 ++++++++++++++++++ .../react/views/scroll/ReactScrollView.java | 29 ++++ .../views/scroll/ReactScrollViewManager.java | 4 + 3 files changed, 180 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java index 18687228c13142..4d97b76e90a475 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java @@ -18,6 +18,7 @@ import androidx.core.view.ViewCompat; import androidx.core.text.TextUtilsCompat; import android.util.Log; +import android.view.FocusFinder; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; @@ -37,6 +38,8 @@ import java.util.List; import java.util.Locale; import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; /** * Similar to {@link ReactScrollView} but only supports horizontal scrolling. @@ -72,6 +75,9 @@ public class ReactHorizontalScrollView extends HorizontalScrollView implements private boolean mSnapToStart = true; private boolean mSnapToEnd = true; private ReactViewBackgroundManager mReactBackgroundManager; + private boolean mPagedArrowScrolling = false; + + private final Rect mTempRect = new Rect(); public ReactHorizontalScrollView(Context context) { this(context, null); @@ -221,6 +227,82 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) { scrollTo(getScrollX(), getScrollY()); } + /** + * Since ReactHorizontalScrollView handles layout changes on JS side, it does not call super.onlayout + * due to which mIsLayoutDirty flag in HorizontalScrollView remains true and prevents scrolling to child + * when requestChildFocus is called. + * Overriding this method and scrolling to child without checking any layout dirty flag. This will fix + * focus navigation issue for KeyEvents which are not handled in HorizontalScrollView, for example: KEYCODE_TAB. + */ + @Override + public void requestChildFocus(View child, View focused) { + if (focused != null && !mPagingEnabled) { + scrollToChild(focused); + } + super.requestChildFocus(child, focused); + } + + @Override + public void addFocusables(ArrayList views, int direction, int focusableMode) { + if (mPagingEnabled && !mPagedArrowScrolling) { + // Only add elements within the current page to list of focusables + ArrayList candidateViews = new ArrayList(); + super.addFocusables(candidateViews, direction, focusableMode); + for (View candidate : candidateViews) { + // We must also include the currently focused in the focusables list or focus search will always + // return the first element within the focusables list + if (isScrolledInView(candidate) || isPartiallyScrolledInView(candidate) || candidate.isFocused()) { + views.add(candidate); + } + } + } else { + super.addFocusables(views, direction, focusableMode); + } + } + + /** + * Calculates the x delta required to scroll the given descendent into view + */ + private int getScrollDelta(View descendent) { + descendent.getDrawingRect(mTempRect); + offsetDescendantRectToMyCoords(descendent, mTempRect); + return computeScrollDeltaToGetChildRectOnScreen(mTempRect); + } + + /** + * Returns whether the given descendent is scrolled fully in view + */ + private boolean isScrolledInView(View descendent) { + return getScrollDelta(descendent) == 0; + } + + + /** + * Returns whether the given descendent is partially scrolled in view + */ + private boolean isPartiallyScrolledInView(View descendent) { + int scrollDelta = getScrollDelta(descendent); + descendent.getDrawingRect(mTempRect); + return scrollDelta != 0 && Math.abs(scrollDelta) < mTempRect.width(); + } + + /** + * Returns whether the given descendent is "mostly" (>50%) scrolled in view + */ + private boolean isMostlyScrolledInView(View descendent) { + int scrollDelta = getScrollDelta(descendent); + descendent.getDrawingRect(mTempRect); + return scrollDelta != 0 && Math.abs(scrollDelta) < (mTempRect.width() / 2); + } + + private void scrollToChild(View child) { + int scrollDelta = getScrollDelta(child); + + if (scrollDelta != 0) { + scrollBy(scrollDelta, 0); + } + } + @Override protected void onScrollChanged(int x, int y, int oldX, int oldY) { super.onScrollChanged(x, y, oldX, oldY); @@ -263,6 +345,48 @@ public boolean onInterceptTouchEvent(MotionEvent ev) { return false; } + @Override + public boolean pageScroll(int direction) { + boolean handled = super.pageScroll(direction); + + if (mPagingEnabled && handled) { + handlePostTouchScrolling(0, 0); + } + + return handled; + } + + @Override + public boolean arrowScroll(int direction) { + boolean handled = false; + + if (mPagingEnabled) { + mPagedArrowScrolling = true; + + if (getChildCount() > 0) { + View currentFocused = findFocus(); + View nextFocused = FocusFinder.getInstance().findNextFocus(this, currentFocused, direction); + View rootChild = getChildAt(0); + if (rootChild != null && nextFocused != null && nextFocused.getParent() == rootChild) { + if (!isScrolledInView(nextFocused) && !isMostlyScrolledInView(nextFocused)) { + smoothScrollToNextPage(direction); + } + nextFocused.requestFocus(); + handled = true; + } else { + smoothScrollToNextPage(direction); + handled = true; + } + } + + mPagedArrowScrolling = false; + } else { + handled = super.arrowScroll(direction); + } + + return handled; + } + @Override public boolean onTouchEvent(MotionEvent ev) { if (!mScrollEnabled) { @@ -706,6 +830,29 @@ private void flingAndSnap(int velocityX) { } } + private void smoothScrollToNextPage(int direction) { + int width = getWidth(); + int currentX = getScrollX(); + + int page = currentX / width; + if (currentX % width != 0) { + page++; + } + + if (direction == View.FOCUS_LEFT) { + page = page - 1; + } else { + page = page + 1; + } + + if (page < 0) { + page = 0; + } + + smoothScrollTo(page * width, getScrollY()); + handlePostTouchScrolling(0, 0); + } + @Override public void setBackgroundColor(int color) { mReactBackgroundManager.setBackgroundColor(color); diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java index e98c1864c36f55..de0fc82ee66b27 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java @@ -205,6 +205,35 @@ protected void onAttachedToWindow() { } } + /** + * Since ReactScrollView handles layout changes on JS side, it does not call super.onlayout + * due to which mIsLayoutDirty flag in ScrollView remains true and prevents scrolling to child + * when requestChildFocus is called. + * Overriding this method and scrolling to child without checking any layout dirty flag. This will fix + * focus navigation issue for KeyEvents which are not handled by ScrollView, for example: KEYCODE_TAB. + */ + @Override + public void requestChildFocus(View child, View focused) { + if (focused != null) { + scrollToChild(focused); + } + super.requestChildFocus(child, focused); + } + + private void scrollToChild(View child) { + Rect tempRect = new Rect(); + child.getDrawingRect(tempRect); + + /* Offset from child's local coordinates to ScrollView coordinates */ + offsetDescendantRectToMyCoords(child, tempRect); + + int scrollDelta = computeScrollDeltaToGetChildRectOnScreen(tempRect); + + if (scrollDelta != 0) { + scrollBy(0, scrollDelta); + } + } + @Override protected void onScrollChanged(int x, int y, int oldX, int oldY) { super.onScrollChanged(x, y, oldX, oldY); diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java index afe0725e43cd05..fecbd151d0121a 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java @@ -70,6 +70,10 @@ public ReactScrollView createViewInstance(ThemedReactContext context) { @ReactProp(name = "scrollEnabled", defaultBoolean = true) public void setScrollEnabled(ReactScrollView view, boolean value) { view.setScrollEnabled(value); + + // Set focusable to match whether scroll is enabled. This improves keyboarding + // experience by not making scrollview a tab stop when you cannot interact with it. + view.setFocusable(value); } @ReactProp(name = "showsVerticalScrollIndicator") From 782e8481a135009efc2902b4f13793142e8c95fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Mon, 10 Jun 2019 04:05:00 -0700 Subject: [PATCH 0256/1084] chore: upgrade CLI to 2.0.0-rc.1 (#25190) Summary: The RC1 of the CLI upgrades Metro to 0.54.1 to be compatible with 0.60 and master and fixes an issue with haste backwards compatibility. cc kelset ## Changelog [General] [Changed] - Bump CLI to 2.0.0-rc.1 Pull Request resolved: https://github.com/facebook/react-native/pull/25190 Differential Revision: D15737249 Pulled By: cpojer fbshipit-source-id: a39747620a7652507d29f5dadb6a4bdc9c1393f0 --- package.json | 6 +- yarn.lock | 423 ++++++++++----------------------------------------- 2 files changed, 86 insertions(+), 343 deletions(-) diff --git a/package.json b/package.json index 0a3190a401376a..109c9280d03259 100644 --- a/package.json +++ b/package.json @@ -82,9 +82,9 @@ }, "dependencies": { "@babel/runtime": "^7.0.0", - "@react-native-community/cli": "2.0.0-rc.0", - "@react-native-community/cli-platform-android": "2.0.0-rc.0", - "@react-native-community/cli-platform-ios": "2.0.0-rc.0", + "@react-native-community/cli": "2.0.0-rc.1", + "@react-native-community/cli-platform-android": "2.0.0-rc.1", + "@react-native-community/cli-platform-ios": "2.0.0-rc.1", "abort-controller": "^3.0.0", "art": "^0.10.0", "base64-js": "^1.1.2", diff --git a/yarn.lock b/yarn.lock index b39d6f59e1a8d3..de6dbd857b043d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -909,16 +909,6 @@ dependencies: "@hapi/hoek" "6.x.x" -"@jest/console@^24.3.0": - version "24.3.0" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-24.3.0.tgz#7bd920d250988ba0bf1352c4493a48e1cb97671e" - integrity sha512-NaCty/OOei6rSDcbPdMiCbYCI0KGFGPgGO6B09lwWt5QTxnkuhKYET9El5u5z1GAcSxkQmSMtM63e24YabCWqA== - dependencies: - "@jest/source-map" "^24.3.0" - "@types/node" "*" - chalk "^2.0.1" - slash "^2.0.0" - "@jest/console@^24.7.1": version "24.7.1" resolved "https://registry.yarnpkg.com/@jest/console/-/console-24.7.1.tgz#32a9e42535a97aedfe037e725bd67e954b459545" @@ -971,16 +961,6 @@ "@jest/types" "^24.7.0" jest-mock "^24.7.0" -"@jest/fake-timers@^24.5.0": - version "24.5.0" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-24.5.0.tgz#4a29678b91fd0876144a58f8d46e6c62de0266f0" - integrity sha512-i59KVt3QBz9d+4Qr4QxsKgsIg+NjfuCjSOWj3RQhjF5JNy+eVJDhANQ4WzulzNCHd72srMAykwtRn5NYDGVraw== - dependencies: - "@jest/types" "^24.5.0" - "@types/node" "*" - jest-message-util "^24.5.0" - jest-mock "^24.5.0" - "@jest/fake-timers@^24.7.1": version "24.7.1" resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-24.7.1.tgz#56e5d09bdec09ee81050eaff2794b26c71d19db2" @@ -1025,15 +1005,6 @@ graceful-fs "^4.1.15" source-map "^0.6.0" -"@jest/test-result@^24.5.0": - version "24.5.0" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-24.5.0.tgz#ab66fb7741a04af3363443084e72ea84861a53f2" - integrity sha512-u66j2vBfa8Bli1+o3rCaVnVYa9O8CAFZeqiqLVhnarXtreSXG33YQ6vNYBogT7+nYiFNOohTU21BKiHlgmxD5A== - dependencies: - "@jest/console" "^24.3.0" - "@jest/types" "^24.5.0" - "@types/istanbul-lib-coverage" "^1.1.0" - "@jest/test-result@^24.7.1": version "24.7.1" resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-24.7.1.tgz#19eacdb29a114300aed24db651e5d975f08b6bbe" @@ -1074,14 +1045,6 @@ source-map "^0.6.1" write-file-atomic "2.4.1" -"@jest/types@^24.5.0": - version "24.5.0" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.5.0.tgz#feee214a4d0167b0ca447284e95a57aa10b3ee95" - integrity sha512-kN7RFzNMf2R8UDadPOl6ReyI+MT8xfqRuAnuVL+i4gwjv/zubdDK+EDeLHYwq1j0CSSR2W/MmgaRlMZJzXdmVA== - dependencies: - "@types/istanbul-lib-coverage" "^1.1.0" - "@types/yargs" "^12.0.9" - "@jest/types@^24.7.0": version "24.7.0" resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.7.0.tgz#c4ec8d1828cdf23234d9b4ee31f5482a3f04f48b" @@ -1090,44 +1053,44 @@ "@types/istanbul-lib-coverage" "^2.0.0" "@types/yargs" "^12.0.9" -"@react-native-community/cli-platform-android@2.0.0-rc.0", "@react-native-community/cli-platform-android@^2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-android/-/cli-platform-android-2.0.0-rc.0.tgz#8fcc57a68b3f971d322034c21ba09c580ce5455a" - integrity sha512-i9xCMx1AFTscFlEsUJZVn5r6h7ndjvBUUTgLR/4oV639Bcwlci3OvKD1bV5fdp1/L9Mv14iuDo7y1Jv9ubRi5w== +"@react-native-community/cli-platform-android@2.0.0-rc.1", "@react-native-community/cli-platform-android@^2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-android/-/cli-platform-android-2.0.0-rc.1.tgz#9f14106104b20bd94d05a3ddad79859b566f8996" + integrity sha512-gH+ev65wxuO9KQxYTvpRh3PFCVvYwxJdZecFZDknnedIx49eVxro99svO/wcp1OLdtzxV+ErFolpIFn0gSyVFg== dependencies: - "@react-native-community/cli-tools" "^2.0.0-rc.0" + "@react-native-community/cli-tools" "^2.0.0-rc.1" logkitty "^0.4.0" slash "^2.0.0" xmldoc "^0.4.0" -"@react-native-community/cli-platform-ios@2.0.0-rc.0", "@react-native-community/cli-platform-ios@^2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-ios/-/cli-platform-ios-2.0.0-rc.0.tgz#00489529d1715c80042a1649b0c6822aa7c785ba" - integrity sha512-v1BxVFHrrypI9XVtwtq0FPtZHusvCouPbpX7c4h4SiP66KT/+eAYVuOTpjSN+EMss/WZLeJKIPOiBn2ZohxcwA== +"@react-native-community/cli-platform-ios@2.0.0-rc.1", "@react-native-community/cli-platform-ios@^2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-ios/-/cli-platform-ios-2.0.0-rc.1.tgz#832c8c873193b8829249227fa1d1f734e7aa267e" + integrity sha512-okioIW81pd5vA1tgdSo8nYGnljqhaV91zprrkko6IhMV4sr/eGlN0D/cyFhUXmnBj6q63+X4Ulr809wqXjJ14w== dependencies: - "@react-native-community/cli-tools" "^2.0.0-rc.0" + "@react-native-community/cli-tools" "^2.0.0-rc.1" chalk "^1.1.1" xcode "^2.0.0" -"@react-native-community/cli-tools@^2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-tools/-/cli-tools-2.0.0-rc.0.tgz#82eedb621921b4511a0a98dbc98eedc12bd98b9b" - integrity sha512-svdIsrcd905lberrY7jVMrHsoCy5PkVgJeiloMFjV6nPTPaKF7ujw2ftdUp9P66KRb7y/IMT5/4EDtntr8SkGg== +"@react-native-community/cli-tools@^2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-tools/-/cli-tools-2.0.0-rc.1.tgz#a8c3f76e0c33ab689c1c769cbbed83add5c13b11" + integrity sha512-ZUc5s/aGdg7d3dT9eMAzKqWd5Lsa42TrsUWjcqaG7WTYUPIUHTWOcpnRLV4B5MUfmEEt3mboOoQZRUcDltz8kA== dependencies: chalk "^1.1.1" lodash "^4.17.5" mime "^2.4.1" node-fetch "^2.5.0" -"@react-native-community/cli@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@react-native-community/cli/-/cli-2.0.0-rc.0.tgz#fcc7551e93bc5fad456d26396de3b91b20ae7190" - integrity sha512-juHl7U3DSYjTexWmTiN54YSK52dM2nz0P2sJipZkJLbYSsSJTtvLiRWIKzaG/1Q03EfPp3DbkYTOXQMEERzQEg== +"@react-native-community/cli@2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.yarnpkg.com/@react-native-community/cli/-/cli-2.0.0-rc.1.tgz#05766235131d4940315ae423848f61b302f4192a" + integrity sha512-mbU45L511eem67vRynHizKDpDv+Xm4xMwMV9HRbTspFxQyhxQd+A4zyQEWKho+/cXZbVhIh8myc/naQDZkmUxQ== dependencies: "@hapi/joi" "^15.0.3" - "@react-native-community/cli-platform-android" "^2.0.0-rc.0" - "@react-native-community/cli-platform-ios" "^2.0.0-rc.0" - "@react-native-community/cli-tools" "^2.0.0-rc.0" + "@react-native-community/cli-platform-android" "^2.0.0-rc.1" + "@react-native-community/cli-platform-ios" "^2.0.0-rc.1" + "@react-native-community/cli-tools" "^2.0.0-rc.1" chalk "^1.1.1" command-exists "^1.2.8" commander "^2.19.0" @@ -1143,10 +1106,10 @@ graceful-fs "^4.1.3" inquirer "^3.0.6" lodash "^4.17.5" - metro "^0.53.1" - metro-config "^0.53.1" - metro-core "^0.53.1" - metro-react-native-babel-transformer "^0.53.1" + metro "^0.54.1" + metro-config "^0.54.1" + metro-core "^0.54.1" + metro-react-native-babel-transformer "^0.54.1" minimist "^1.2.0" mkdirp "^0.5.1" morgan "^1.9.0" @@ -1201,21 +1164,11 @@ dependencies: "@babel/types" "^7.3.0" -"@types/istanbul-lib-coverage@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.0.tgz#2cc2ca41051498382b43157c8227fea60363f94a" - integrity sha512-ohkhb9LehJy+PA40rDtGAji61NCgdtKLAlFoYp4cnuuQEswwdK3vz9SOIkkyc3wrk8dzjphQApNs56yyXLStaQ== - "@types/istanbul-lib-coverage@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.0.tgz#1eb8c033e98cf4e1a4cedcaf8bcafe8cb7591e85" integrity sha512-eAtOAFZefEnfJiRFQBGw1eYqa5GTLCZ1y86N0XSI/D6EB+E8z6VPV/UL7Gi5UEclFqoQk+6NRqEDsfmDLXn8sg== -"@types/node@*": - version "11.11.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-11.11.2.tgz#873d2c3f3824212cc16130074699e1bcb38c0231" - integrity sha512-iEaHiDNkHv4Jrm9O5T37OYEUwjJesiyt6ZlhLFK0sbo4CLD0jyCOB4Pc2F9iD3MbW2397SLNxZKdDGntGaBjQQ== - "@types/stack-utils@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e" @@ -2898,13 +2851,6 @@ exception-formatter@^1.0.4: dependencies: colors "^1.0.3" -exec-sh@^0.2.0: - version "0.2.2" - resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.2.tgz#2a5e7ffcbd7d0ba2755bdecb16e5a427dfbdec36" - integrity sha512-FIUCJz1RbuS0FKTdaAafAByGS0CPvU3R0MeHxgtl+djzCc//F8HakL8GzmVNZanasTbTAY/3DRFA0KpVqj/eAw== - dependencies: - merge "^1.2.0" - exec-sh@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.2.tgz#6738de2eb7c8e671d0366aea0b0db8c6f7d7391b" @@ -3290,14 +3236,6 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -fsevents@^1.2.3: - version "1.2.4" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" - integrity sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg== - dependencies: - nan "^2.9.2" - node-pre-gyp "^0.10.0" - fsevents@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.7.tgz#4851b664a3783e52003b3c66eb0eee1074933aa4" @@ -4083,20 +4021,6 @@ jest-get-type@^24.3.0: resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-24.3.0.tgz#582cfd1a4f91b5cdad1d43d2932f816d543c65da" integrity sha512-HYF6pry72YUlVcvUx3sEpMRwXEWGEPlJ0bSPVnB3b3n++j4phUEoSPcS6GC0pPJ9rpyPSe4cb5muFo6D39cXow== -jest-haste-map@24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-24.0.0.tgz#e9ef51b2c9257384b4d6beb83bd48c65b37b5e6e" - integrity sha512-CcViJyUo41IQqttLxXVdI41YErkzBKbE6cS6dRAploCeutePYfUimWd3C9rQEWhX0YBOQzvNsC0O9nYxK2nnxQ== - dependencies: - fb-watchman "^2.0.0" - graceful-fs "^4.1.15" - invariant "^2.2.4" - jest-serializer "^24.0.0" - jest-util "^24.0.0" - jest-worker "^24.0.0" - micromatch "^3.1.10" - sane "^3.0.0" - jest-haste-map@^24.7.1: version "24.7.1" resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-24.7.1.tgz#772e215cd84080d4bbcb759cfb668ad649a21471" @@ -4165,20 +4089,6 @@ jest-matcher-utils@^24.7.0: jest-get-type "^24.3.0" pretty-format "^24.7.0" -jest-message-util@^24.5.0: - version "24.5.0" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-24.5.0.tgz#181420a65a7ef2e8b5c2f8e14882c453c6d41d07" - integrity sha512-6ZYgdOojowCGiV0D8WdgctZEAe+EcFU+KrVds+0ZjvpZurUW2/oKJGltJ6FWY2joZwYXN5VL36GPV6pNVRqRnQ== - dependencies: - "@babel/code-frame" "^7.0.0" - "@jest/test-result" "^24.5.0" - "@jest/types" "^24.5.0" - "@types/stack-utils" "^1.0.1" - chalk "^2.0.1" - micromatch "^3.1.10" - slash "^2.0.0" - stack-utils "^1.0.1" - jest-message-util@^24.7.1: version "24.7.1" resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-24.7.1.tgz#f1dc3a6c195647096a99d0f1dadbc447ae547018" @@ -4193,13 +4103,6 @@ jest-message-util@^24.7.1: slash "^2.0.0" stack-utils "^1.0.1" -jest-mock@^24.5.0: - version "24.5.0" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-24.5.0.tgz#976912c99a93f2a1c67497a9414aa4d9da4c7b76" - integrity sha512-ZnAtkWrKf48eERgAOiUxVoFavVBziO2pAi2MfZ1+bGXVkDfxWLxU0//oJBkgwbsv6OAmuLBz4XFFqvCFMqnGUw== - dependencies: - "@jest/types" "^24.5.0" - jest-mock@^24.7.0: version "24.7.0" resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-24.7.0.tgz#e49ce7262c12d7f5897b0d8af77f6db8e538023b" @@ -4291,12 +4194,7 @@ jest-runtime@^24.7.1: strip-bom "^3.0.0" yargs "^12.0.2" -jest-serializer@24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-24.0.0.tgz#522c44a332cdd194d8c0531eb06a1ee5afb4256b" - integrity sha512-9FKxQyrFgHtx3ozU+1a8v938ILBE7S8Ko3uiAVjT8Yfi2o91j/fj81jacCQZ/Ihjiff/VsUCXVgQ+iF1XdImOw== - -jest-serializer@^24.0.0, jest-serializer@^24.4.0: +jest-serializer@^24.4.0: version "24.4.0" resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-24.4.0.tgz#f70c5918c8ea9235ccb1276d232e459080588db3" integrity sha512-k//0DtglVstc1fv+GY/VHDIjrtNjdYvYjMlbLUed4kxrE92sIUewOi5Hj3vrpB8CXfkJntRPDRjCrCvUhBdL8Q== @@ -4319,25 +4217,6 @@ jest-snapshot@^24.7.1: pretty-format "^24.7.0" semver "^5.5.0" -jest-util@^24.0.0: - version "24.5.0" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-24.5.0.tgz#9d9cb06d9dcccc8e7cc76df91b1635025d7baa84" - integrity sha512-Xy8JsD0jvBz85K7VsTIQDuY44s+hYJyppAhcsHsOsGisVtdhar6fajf2UOf2mEVEgh15ZSdA0zkCuheN8cbr1Q== - dependencies: - "@jest/console" "^24.3.0" - "@jest/fake-timers" "^24.5.0" - "@jest/source-map" "^24.3.0" - "@jest/test-result" "^24.5.0" - "@jest/types" "^24.5.0" - "@types/node" "*" - callsites "^3.0.0" - chalk "^2.0.1" - graceful-fs "^4.1.15" - is-ci "^2.0.0" - mkdirp "^0.5.1" - slash "^2.0.0" - source-map "^0.6.0" - jest-util@^24.7.1: version "24.7.1" resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-24.7.1.tgz#b4043df57b32a23be27c75a2763d8faf242038ff" @@ -4392,23 +4271,6 @@ jest-watcher@^24.7.1: jest-util "^24.7.1" string-length "^2.0.0" -jest-worker@24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.0.0.tgz#3d3483b077bf04f412f47654a27bba7e947f8b6d" - integrity sha512-s64/OThpfQvoCeHG963MiEZOAAxu8kHsaL/rCMF7lpdzo7vgF0CtPml9hfguOMgykgH/eOm4jFP4ibfHLruytg== - dependencies: - merge-stream "^1.0.1" - supports-color "^6.1.0" - -jest-worker@^24.0.0: - version "24.4.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.4.0.tgz#fbc452b0120bb5c2a70cdc88fa132b48eeb11dd0" - integrity sha512-BH9X/klG9vxwoO99ZBUbZFfV8qO0XNZ5SIiCyYK2zOuJBl6YJVAeNIQjcoOVNu4HGEHeYEKsUWws8kSlSbZ9YQ== - dependencies: - "@types/node" "*" - merge-stream "^1.0.1" - supports-color "^6.1.0" - jest-worker@^24.6.0: version "24.6.0" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.6.0.tgz#7f81ceae34b7cde0c9827a6980c35b7cdc0161b3" @@ -4845,29 +4707,6 @@ merge-stream@^1.0.1: dependencies: readable-stream "^2.0.1" -merge@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" - integrity sha1-dTHjnUlJwoGma4xabgJl6LBYlNo= - -metro-babel-register@0.53.1: - version "0.53.1" - resolved "https://registry.yarnpkg.com/metro-babel-register/-/metro-babel-register-0.53.1.tgz#41c73313ff882d28d8f7df072d2c7a6b7b314ac8" - integrity sha512-kDu7mktGCVdpa2islDzmNXZ0sGQjUvIEcQkmO9pt4b4d8QVecEHyHSZB9jvWnE2w9lADzvnERmZLHS2iDDYOyw== - dependencies: - "@babel/core" "^7.0.0" - "@babel/plugin-proposal-class-properties" "^7.0.0" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.0.0" - "@babel/plugin-proposal-object-rest-spread" "^7.0.0" - "@babel/plugin-proposal-optional-catch-binding" "^7.0.0" - "@babel/plugin-proposal-optional-chaining" "^7.0.0" - "@babel/plugin-transform-async-to-generator" "^7.0.0" - "@babel/plugin-transform-flow-strip-types" "^7.0.0" - "@babel/plugin-transform-modules-commonjs" "^7.0.0" - "@babel/register" "^7.0.0" - core-js "^2.2.2" - escape-string-regexp "^1.0.5" - metro-babel-register@0.54.1: version "0.54.1" resolved "https://registry.yarnpkg.com/metro-babel-register/-/metro-babel-register-0.54.1.tgz#7d2bfe444b1ccef8de99aedc7d9330891d806076" @@ -4886,13 +4725,6 @@ metro-babel-register@0.54.1: core-js "^2.2.2" escape-string-regexp "^1.0.5" -metro-babel-transformer@0.53.1: - version "0.53.1" - resolved "https://registry.yarnpkg.com/metro-babel-transformer/-/metro-babel-transformer-0.53.1.tgz#a076fd77a9a7aef8004706edf537dcd1fec4a79e" - integrity sha512-cgZj9KK/SLxsO/rAmrlnZpaBlLhxuWxGrQkkiWxV/OjfbW8nvodozfZ3Euxvh4Ytf0e8qgTFG3JpQf8EGSDp7w== - dependencies: - "@babel/core" "^7.0.0" - metro-babel-transformer@0.54.1: version "0.54.1" resolved "https://registry.yarnpkg.com/metro-babel-transformer/-/metro-babel-transformer-0.54.1.tgz#371ffa2d1118b22cc9e40b3c3ea6738c49dae9dc" @@ -4900,13 +4732,6 @@ metro-babel-transformer@0.54.1: dependencies: "@babel/core" "^7.0.0" -metro-babel7-plugin-react-transform@0.53.1: - version "0.53.1" - resolved "https://registry.yarnpkg.com/metro-babel7-plugin-react-transform/-/metro-babel7-plugin-react-transform-0.53.1.tgz#9ad31e5c84f5003333a6a3cf79f2d093cd3b2ddc" - integrity sha512-98lEpTu7mox/7QurxVuLnbjrGDdayjpS2Z1T4vkLcP+mBxzloKJuTRnmtyWC8cNlx9qjimHGDlqtNY78rQ8rsA== - dependencies: - "@babel/helper-module-imports" "^7.0.0" - metro-babel7-plugin-react-transform@0.54.1: version "0.54.1" resolved "https://registry.yarnpkg.com/metro-babel7-plugin-react-transform/-/metro-babel7-plugin-react-transform-0.54.1.tgz#5335b810284789724886dc483d5bde9c149a1996" @@ -4914,97 +4739,56 @@ metro-babel7-plugin-react-transform@0.54.1: dependencies: "@babel/helper-module-imports" "^7.0.0" -metro-cache@0.53.1: - version "0.53.1" - resolved "https://registry.yarnpkg.com/metro-cache/-/metro-cache-0.53.1.tgz#38d73c441771bdd2437a55d50943e346e1897108" - integrity sha512-27Cbo32nabef/P+y5s3cpaIUWa7Hpql2xD0HqQD8AbCfSG4xraEoBOLCmvB6wusvDAnQAcuglLq9AUbTvcSebA== +metro-cache@0.54.1: + version "0.54.1" + resolved "https://registry.yarnpkg.com/metro-cache/-/metro-cache-0.54.1.tgz#2e9017cbd11106837b8c385c9eb8c8175469a8c1" + integrity sha512-RxCFoNcANHXZYi4MIQNnqh68gUnC3bMpzCFJY5pBoqqdrkkn8ibYglBweA0/DW7hx1OZTJWelwS1Dp8xxmE2CA== dependencies: - jest-serializer "24.0.0" - metro-core "0.53.1" + jest-serializer "^24.4.0" + metro-core "0.54.1" mkdirp "^0.5.1" rimraf "^2.5.4" -metro-config@0.53.1, metro-config@^0.53.1: - version "0.53.1" - resolved "https://registry.yarnpkg.com/metro-config/-/metro-config-0.53.1.tgz#a522beec446187b010c0e68273015818d1c6dfb9" - integrity sha512-3hRweWmrGs8NOjQXLsg/FHAEWqCnfNKLXM4BcI8RXQFvrQQRqhoXCuhcTfM9lSfNkefJiRp+4wW6cHXgo/TP6w== +metro-config@0.54.1, metro-config@^0.54.1: + version "0.54.1" + resolved "https://registry.yarnpkg.com/metro-config/-/metro-config-0.54.1.tgz#808b4e17625d9f4e9afa34232778fdf8e63cc8dd" + integrity sha512-FpxrA+63rGkPGvGI653dvuSreJzU+eOTILItVnnhmqwn2SAK5V00N/qGTOIJe2YIuWEFXwCzw9lXmANrXbwuGg== dependencies: cosmiconfig "^5.0.5" - metro "0.53.1" - metro-cache "0.53.1" - metro-core "0.53.1" - pretty-format "24.0.0-alpha.6" + jest-validate "^24.7.0" + metro "0.54.1" + metro-cache "0.54.1" + metro-core "0.54.1" + pretty-format "^24.7.0" -metro-core@0.53.1, metro-core@^0.53.1: - version "0.53.1" - resolved "https://registry.yarnpkg.com/metro-core/-/metro-core-0.53.1.tgz#350211c6327ccf307270199bb1c04012ec2d7d96" - integrity sha512-bBK0GMZWsZrdBGi+jh/87g0VvItT2jez6aj+vRw8AcBataT81SZ5WsSAw3CtbivBXXR7x3oK49T6ZZ+D79VZAw== +metro-core@0.54.1, metro-core@^0.54.1: + version "0.54.1" + resolved "https://registry.yarnpkg.com/metro-core/-/metro-core-0.54.1.tgz#17f6ecc167918da8819d4af5726349e55714954b" + integrity sha512-8oz3Ck7QFBzW9dG9tKFhrXHKPu2Ajx3R7eatf61Gl6Jf/tF7PNouv3wHxPsJW3oXDFiwKLszd89+OgleTGkB5g== dependencies: - jest-haste-map "24.0.0" + jest-haste-map "^24.7.1" lodash.throttle "^4.1.1" - metro-resolver "0.53.1" + metro-resolver "0.54.1" wordwrap "^1.0.0" -metro-inspector-proxy@0.53.1: - version "0.53.1" - resolved "https://registry.yarnpkg.com/metro-inspector-proxy/-/metro-inspector-proxy-0.53.1.tgz#cff4b9fa8b9e5598c034469bd30ef07093f75b28" - integrity sha512-4q5WIFFmpjtKbY2vze3tNI3hPUFrvv1iwTrpz3DMdQ+NYZO6aEwCxtgZAt8N4HC3xZMdECL+DDKKAJu+4jsiEA== +metro-inspector-proxy@0.54.1: + version "0.54.1" + resolved "https://registry.yarnpkg.com/metro-inspector-proxy/-/metro-inspector-proxy-0.54.1.tgz#0ef48ee3feb11c6da47aa100151a9bf2a7c358ee" + integrity sha512-sf6kNu7PgFW6U+hU7YGZfbAUKAPVvCJhY8YVu/A1RMKH9nNULrCo+jlWh0gWgmFfWRQiAPCElevROg+5somk8A== dependencies: - chalk "^2.4.1" connect "^3.6.5" + debug "^2.2.0" rxjs "^5.4.3" ws "^1.1.5" yargs "^9.0.0" -metro-minify-uglify@0.53.1: - version "0.53.1" - resolved "https://registry.yarnpkg.com/metro-minify-uglify/-/metro-minify-uglify-0.53.1.tgz#145b6e37c09e3ff8fb1bbd3221e5a3fded044904" - integrity sha512-uTdsoACy0WP51qDNrKcLILcpZOMLGyi2B9j3pu9zVRts7hlfVQGxBg4v3uDZ+L7zJ7TKR15p4iMXFmTAkRBpdA== +metro-minify-uglify@0.54.1: + version "0.54.1" + resolved "https://registry.yarnpkg.com/metro-minify-uglify/-/metro-minify-uglify-0.54.1.tgz#54ed1cb349245ce82dba8cc662bbf69fbca142c3" + integrity sha512-z+pOPna/8IxD4OhjW6Xo1mV2EszgqqQHqBm1FdmtdF6IpWkQp33qpDBNEi9NGZTOr7pp2bvcxZnvNJdC2lrK9Q== dependencies: uglify-es "^3.1.9" -metro-react-native-babel-preset@0.53.1: - version "0.53.1" - resolved "https://registry.yarnpkg.com/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.53.1.tgz#6cd9e41a1b9a6e210e71ef2adf114219b4eaf2ec" - integrity sha512-Uf8EGL8kIPhDkoSdAAysNPxPQclUS2R1QC4cwnc8bkk2f6yqGn+1CorfiY9AaqlLEth5mKQqdtRYFDTFfB9QyA== - dependencies: - "@babel/plugin-proposal-class-properties" "^7.0.0" - "@babel/plugin-proposal-export-default-from" "^7.0.0" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.0.0" - "@babel/plugin-proposal-object-rest-spread" "^7.0.0" - "@babel/plugin-proposal-optional-catch-binding" "^7.0.0" - "@babel/plugin-proposal-optional-chaining" "^7.0.0" - "@babel/plugin-syntax-dynamic-import" "^7.0.0" - "@babel/plugin-syntax-export-default-from" "^7.0.0" - "@babel/plugin-syntax-flow" "^7.2.0" - "@babel/plugin-transform-arrow-functions" "^7.0.0" - "@babel/plugin-transform-block-scoping" "^7.0.0" - "@babel/plugin-transform-classes" "^7.0.0" - "@babel/plugin-transform-computed-properties" "^7.0.0" - "@babel/plugin-transform-destructuring" "^7.0.0" - "@babel/plugin-transform-exponentiation-operator" "^7.0.0" - "@babel/plugin-transform-flow-strip-types" "^7.0.0" - "@babel/plugin-transform-for-of" "^7.0.0" - "@babel/plugin-transform-function-name" "^7.0.0" - "@babel/plugin-transform-literals" "^7.0.0" - "@babel/plugin-transform-modules-commonjs" "^7.0.0" - "@babel/plugin-transform-object-assign" "^7.0.0" - "@babel/plugin-transform-parameters" "^7.0.0" - "@babel/plugin-transform-react-display-name" "^7.0.0" - "@babel/plugin-transform-react-jsx" "^7.0.0" - "@babel/plugin-transform-react-jsx-source" "^7.0.0" - "@babel/plugin-transform-regenerator" "^7.0.0" - "@babel/plugin-transform-runtime" "^7.0.0" - "@babel/plugin-transform-shorthand-properties" "^7.0.0" - "@babel/plugin-transform-spread" "^7.0.0" - "@babel/plugin-transform-sticky-regex" "^7.0.0" - "@babel/plugin-transform-template-literals" "^7.0.0" - "@babel/plugin-transform-typescript" "^7.0.0" - "@babel/plugin-transform-unicode-regex" "^7.0.0" - "@babel/template" "^7.0.0" - metro-babel7-plugin-react-transform "0.53.1" - react-transform-hmr "^1.0.4" - metro-react-native-babel-preset@0.54.1: version "0.54.1" resolved "https://registry.yarnpkg.com/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.54.1.tgz#b8f03865c381841d7f8912e7ba46804ea3a928b8" @@ -5047,7 +4831,7 @@ metro-react-native-babel-preset@0.54.1: metro-babel7-plugin-react-transform "0.54.1" react-transform-hmr "^1.0.4" -metro-react-native-babel-transformer@0.54.1: +metro-react-native-babel-transformer@0.54.1, metro-react-native-babel-transformer@^0.54.1: version "0.54.1" resolved "https://registry.yarnpkg.com/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.54.1.tgz#45b56db004421134e10e739f69e8de50775fef17" integrity sha512-ECw7xG91t8dk/PHdiyoC5SP1s9OQzfmJzG5m0YOZaKtHMe534qTDbncxaKfTI3CP99yti2maXFBRVj+xyvph/g== @@ -5057,34 +4841,26 @@ metro-react-native-babel-transformer@0.54.1: metro-babel-transformer "0.54.1" metro-react-native-babel-preset "0.54.1" -metro-react-native-babel-transformer@^0.53.1: - version "0.53.1" - resolved "https://registry.yarnpkg.com/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.53.1.tgz#addf31b3a9b5fc512b9ff6967d923dcfcda56394" - integrity sha512-UB64jN/akuTdDmoQlw+yLBifJhQzJr7QPP3cwitwM5XD4d9M+12pZreeFn66oMakTy4pNx4jkaYEJ5rLyh/b0Q== - dependencies: - "@babel/core" "^7.0.0" - babel-preset-fbjs "^3.1.2" - metro-babel-transformer "0.53.1" - metro-react-native-babel-preset "0.53.1" - -metro-resolver@0.53.1: - version "0.53.1" - resolved "https://registry.yarnpkg.com/metro-resolver/-/metro-resolver-0.53.1.tgz#e21df30c0b9913c7cbeeda9c28d8ffe0ae58cd53" - integrity sha512-UOL2AY3HF3kyuwO+SXceA7MvVbxGZTwRmWOcRl2mYMZ66osSygFgR0WoYFAlxoW83c1ZDYXMIg78ob8bs0lSAg== +metro-resolver@0.54.1: + version "0.54.1" + resolved "https://registry.yarnpkg.com/metro-resolver/-/metro-resolver-0.54.1.tgz#0295b38624b678b88b16bf11d47288845132b087" + integrity sha512-Byv1LIawYAASy9CFRwzrncYnqaFGLe8vpw178EtzStqP05Hu6hXSqkNTrfoXa+3V9bPFGCrVzFx2NY3gFp2btg== dependencies: absolute-path "^0.0.0" -metro-source-map@0.53.1: - version "0.53.1" - resolved "https://registry.yarnpkg.com/metro-source-map/-/metro-source-map-0.53.1.tgz#61d915720eb90722d55252f3bd014ba0ce8fabfd" - integrity sha512-mZ8NJMq5lKE9+0gfhpYFVqK3z4wng6xCzOMXoROjkOsO/exbHGK4oSfOzEnVl6oCRBTGMfaeB32ZeECwZ9O0jw== +metro-source-map@0.54.1: + version "0.54.1" + resolved "https://registry.yarnpkg.com/metro-source-map/-/metro-source-map-0.54.1.tgz#e17bad53c11978197d3c05c9168d799c2e04dcc5" + integrity sha512-E9iSYMSUSq5qYi1R2hTQtxH4Mxjzfgr/jaSmQIWi7h3fG2P1qOZNNSzeaeUeTK+s2N/ksVlkcL5kMikol8CDrQ== dependencies: + "@babel/traverse" "^7.0.0" + "@babel/types" "^7.0.0" source-map "^0.5.6" -metro@0.53.1, metro@^0.53.1: - version "0.53.1" - resolved "https://registry.yarnpkg.com/metro/-/metro-0.53.1.tgz#23fb558eb22e8de8d84fa3f456adfdedec435021" - integrity sha512-Q2iVHfUu5NO2o0dZukBkWrW5s2LiResQuK5KalomNsOHLguOYI5r1nR5QdznZ05GI96iR0fgNvFWfPMyIhtKvw== +metro@0.54.1, metro@^0.54.1: + version "0.54.1" + resolved "https://registry.yarnpkg.com/metro/-/metro-0.54.1.tgz#a629be00abee5a450a25a8f71c24745f70cc9b44" + integrity sha512-6ODPT4mEo4FCpbExRNnQAcZmf1VeNvYOTMj2Na03FjGqhNODHhI2U/wF/Ul5gqTyJ2dVdkXeyvKW3gl/LrnJRg== dependencies: "@babel/core" "^7.0.0" "@babel/generator" "^7.0.0" @@ -5108,21 +4884,21 @@ metro@0.53.1, metro@^0.53.1: graceful-fs "^4.1.3" image-size "^0.6.0" invariant "^2.2.4" - jest-haste-map "24.0.0" - jest-worker "24.0.0" + jest-haste-map "^24.7.1" + jest-worker "^24.6.0" json-stable-stringify "^1.0.1" lodash.throttle "^4.1.1" merge-stream "^1.0.1" - metro-babel-register "0.53.1" - metro-babel-transformer "0.53.1" - metro-cache "0.53.1" - metro-config "0.53.1" - metro-core "0.53.1" - metro-inspector-proxy "0.53.1" - metro-minify-uglify "0.53.1" - metro-react-native-babel-preset "0.53.1" - metro-resolver "0.53.1" - metro-source-map "0.53.1" + metro-babel-register "0.54.1" + metro-babel-transformer "0.54.1" + metro-cache "0.54.1" + metro-config "0.54.1" + metro-core "0.54.1" + metro-inspector-proxy "0.54.1" + metro-minify-uglify "0.54.1" + metro-react-native-babel-preset "0.54.1" + metro-resolver "0.54.1" + metro-source-map "0.54.1" mime-types "2.1.11" mkdirp "^0.5.1" node-fetch "^2.2.0" @@ -5901,14 +5677,6 @@ prettier@1.17.0: resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.17.0.tgz#53b303676eed22cc14a9f0cec09b477b3026c008" integrity sha512-sXe5lSt2WQlCbydGETgfm1YBShgOX4HxQkFPvbxkcwgDvGDeqVau8h+12+lmSVlP3rHPz0oavfddSZg/q+Szjw== -pretty-format@24.0.0-alpha.6: - version "24.0.0-alpha.6" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.0.0-alpha.6.tgz#25ad2fa46b342d6278bf241c5d2114d4376fbac1" - integrity sha512-zG2m6YJeuzwBFqb5EIdmwYVf30sap+iMRuYNPytOccEXZMAJbPIFGKVJ/U0WjQegmnQbRo9CI7j6j3HtDaifiA== - dependencies: - ansi-regex "^4.0.0" - ansi-styles "^3.2.0" - pretty-format@^24.0.0: version "24.0.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.0.0.tgz#cb6599fd73ac088e37ed682f61291e4678f48591" @@ -6461,23 +6229,6 @@ safe-regex@^1.1.0: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sane@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/sane/-/sane-3.1.0.tgz#995193b7dc1445ef1fe41ddfca2faf9f111854c6" - integrity sha512-G5GClRRxT1cELXfdAq7UKtUsv8q/ZC5k8lQGmjEm4HcAl3HzBy68iglyNCmw4+0tiXPCBZntslHlRhbnsSws+Q== - dependencies: - anymatch "^2.0.0" - capture-exit "^1.2.0" - exec-sh "^0.2.0" - execa "^1.0.0" - fb-watchman "^2.0.0" - micromatch "^3.1.4" - minimist "^1.1.1" - walker "~1.0.5" - watch "~0.18.0" - optionalDependencies: - fsevents "^1.2.3" - sane@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/sane/-/sane-4.0.3.tgz#e878c3f19e25cc57fbb734602f48f8a97818b181" @@ -7329,14 +7080,6 @@ walker@^1.0.7, walker@~1.0.5: dependencies: makeerror "1.0.x" -watch@~0.18.0: - version "0.18.0" - resolved "https://registry.yarnpkg.com/watch/-/watch-0.18.0.tgz#28095476c6df7c90c963138990c0a5423eb4b986" - integrity sha1-KAlUdsbffJDJYxOJkMClQj60uYY= - dependencies: - exec-sh "^0.2.0" - minimist "^1.2.0" - wcwidth@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" From 1f3e4df6a7d42d8a6060d1a21949159a7a90d826 Mon Sep 17 00:00:00 2001 From: Aditya Sharat Date: Mon, 10 Jun 2019 06:52:54 -0700 Subject: [PATCH 0257/1084] Back out "[litho] Adds check to unset a YogaNode's parent during reconciliation." Summary: Removes `unsetOwner` from Yoga. This was temporarily for patching a crash. Reviewed By: colriot Differential Revision: D15737613 fbshipit-source-id: 8ab93ecf7ffb913df6207fe5db47a8cc93eded2c --- ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java | 2 -- .../src/main/java/com/facebook/yoga/YogaNodeJNIBase.java | 5 ----- 2 files changed, 7 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java index 9a8e19663fd1a0..a01a0bdde49ddb 100644 --- a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java @@ -42,8 +42,6 @@ public static YogaNode create(YogaConfig config) { @Nullable public abstract YogaNode getOwner(); - public abstract void unsetOwner(); - /** @deprecated Use #getOwner() instead. This will be removed in the next version. */ @Deprecated @Nullable diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeJNIBase.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeJNIBase.java index 0e1f68c8e97a35..c48162f4a470d6 100644 --- a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeJNIBase.java +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeJNIBase.java @@ -137,11 +137,6 @@ public YogaNodeJNIBase getOwner() { return mOwner; } - @Override - public void unsetOwner() { - mOwner = null; - } - /** @deprecated Use #getOwner() instead. This will be removed in the next version. */ @Deprecated @Nullable From 608cf6fe09c9beea394654bb2f5759c7e0c80c06 Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Mon, 10 Jun 2019 10:48:12 -0700 Subject: [PATCH 0258/1084] Make CompositeReactPackage support TurboReactPackage Summary: ## Description CompositeReactPackage will now eagerly initialize all NativeModules inside the TurboReactPackages. Before it would just crash the program because calling `createNativeModules()` on the TurboReactPackage instance. Longer term, we should make CompositeReactPackage a TurboReactPackage. ## Why am I making this change? I made MainReactPackage into a TurboReactPackge. But ExpressWifiTechnician uses MainReactPackage to create a CompositeReactPackage: **java/com/expresswifi/technician/MainActivity.java** ``` protected ReactPackage getPackage() { ReactInstanceManager reactInstanceManager = getReactInstanceManager(); Nullable DevSupportManager devSupportManager = null; if (reactInstanceManager != null) { devSupportManager = reactInstanceManager.getDevSupportManager(); } return new CompositeReactPackage( super.getPackage(), mXWFTechnicianReactPackage, new RNFusedLocationPackage(), mXWFTechnicialMobileConfigPackageProvider.get(devSupportManager)); } ``` **java/com/facebook/catalyst/shell/MainReactActivity.java** ``` public abstract class MainReactActivity extends AbstractReactActivity { protected ReactPackage getPackage() { return new MainReactPackage(); } } ``` Reviewed By: fkgozali Differential Revision: D15738677 fbshipit-source-id: 3220dfe6434de56f2917c77fb21acef4cfc79278 --- .../facebook/react/CompositeReactPackage.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/CompositeReactPackage.java b/ReactAndroid/src/main/java/com/facebook/react/CompositeReactPackage.java index d6c13684e01bc1..9450719098ec32 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/CompositeReactPackage.java +++ b/ReactAndroid/src/main/java/com/facebook/react/CompositeReactPackage.java @@ -8,6 +8,8 @@ import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.module.model.ReactModuleInfo; +import com.facebook.react.module.model.ReactModuleInfoProvider; import com.facebook.react.uimanager.ViewManager; import java.util.ArrayList; import java.util.Collections; @@ -18,6 +20,7 @@ import java.util.Map; import java.util.Set; import javax.annotation.Nullable; +import com.facebook.react.TurboReactPackage; /** * {@code CompositeReactPackage} allows to create a single package composed of views and modules @@ -46,6 +49,25 @@ public List createNativeModules(ReactApplicationContext reactConte // This is for backward compatibility. final Map moduleMap = new HashMap<>(); for (ReactPackage reactPackage : mChildReactPackages) { + /** + * For now, we eagerly initialize the NativeModules inside TurboReactPackages. + * Ultimately, we should turn CompositeReactPackage into a TurboReactPackage + * and remove this eager initialization. + * + * TODO: T45627020 + */ + if (reactPackage instanceof TurboReactPackage) { + TurboReactPackage turboReactPackage = (TurboReactPackage)reactPackage; + ReactModuleInfoProvider moduleInfoProvider = turboReactPackage.getReactModuleInfoProvider(); + Map moduleInfos = moduleInfoProvider.getReactModuleInfos(); + + for (final String moduleName : moduleInfos.keySet()) { + moduleMap.put(moduleName, turboReactPackage.getModule(moduleName, reactContext)); + } + + continue; + } + for (NativeModule nativeModule : reactPackage.createNativeModules(reactContext)) { moduleMap.put(nativeModule.getName(), nativeModule); } From 72be568666e58f703684ebeb2ad1a135826d8c6f Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Mon, 10 Jun 2019 10:53:29 -0700 Subject: [PATCH 0259/1084] Reland "[RN][TurboModule] Enable TurboModules for FB4A" Summary: These changes were originally landed in D15327683. Unfortunately, I had to back these out because they revelaled problems with our TurboModules infra. Those problems have since been fixed, so I think it's safe for us to re-land these changes. Please refer to D15327683 for a description. Differential Revision: D15739355 fbshipit-source-id: 69bb3cec0731ba325f60c6c8459426546c79b54d --- .../main/java/com/facebook/react/bridge/BaseJavaModule.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java index 04ca7a91c74969..da1d60f94f0897 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java @@ -67,4 +67,9 @@ public void onCatalystInstanceDestroy() { public boolean hasConstants() { return false; } + + // Cleanup Logic for TurboModuels + public void invalidate() { + // Do nothing + } } From 20102ef5b149f322347d87e4c310036704ef1a50 Mon Sep 17 00:00:00 2001 From: Emily Janzer Date: Mon, 10 Jun 2019 12:00:52 -0700 Subject: [PATCH 0260/1084] Check TurboModules first in TurboModuleRegistry Summary: Reverse the order in which we look for modules in TurboModuleRegistry to check TurboModules first, and then fall back to legacy native modules. The main motivation for this is Venice, since requiring NativeModules.js fatals because there's no batched bridge. But we'll probably want to do this eventually anyway. I ran a mobilelab for Marketplace home and am not seeing any significant difference in TTI. Reviewed By: fkgozali Differential Revision: D15703655 fbshipit-source-id: d65a4d7e09077474c30fb3938e38aee63bfa4eca --- Libraries/TurboModule/TurboModuleRegistry.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Libraries/TurboModule/TurboModuleRegistry.js b/Libraries/TurboModule/TurboModuleRegistry.js index d0e0cd0176c33a..03d84d6dd7541f 100644 --- a/Libraries/TurboModule/TurboModuleRegistry.js +++ b/Libraries/TurboModule/TurboModuleRegistry.js @@ -17,17 +17,19 @@ import invariant from 'invariant'; const turboModuleProxy = global.__turboModuleProxy; export function get(name: string): ?T { + if (turboModuleProxy != null) { + const module: ?T = turboModuleProxy(name); + if (module != null) { + return module; + } + } + // Backward compatibility layer during migration. const legacyModule = NativeModules[name]; if (legacyModule != null) { return ((legacyModule: any): T); } - if (turboModuleProxy != null) { - const module: ?T = turboModuleProxy(name); - return module; - } - return null; } From bbeace1342e078bcf250f776f6de4e432c9c6bd3 Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Mon, 10 Jun 2019 12:19:14 -0700 Subject: [PATCH 0261/1084] Remove `React.js` from RN open source Summary: This diff removes the `React.js` forwarding module from RN open source which was only used for haste requires. I moved this file to FB internal and manually changed requires from `React` to `react`. However, I can't fully remove this forwarding module because we have files shared from www that expect to require React via the capitalized named. Reviewed By: yungsters Differential Revision: D15738887 fbshipit-source-id: b5b6c0be258582cfad92c13d174e5490c75152d9 --- Libraries/react-native/React.js | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 Libraries/react-native/React.js diff --git a/Libraries/react-native/React.js b/Libraries/react-native/React.js deleted file mode 100644 index ac9f5d1bcec4a7..00000000000000 --- a/Libraries/react-native/React.js +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -'use strict'; - -module.exports = require('react'); From 5c399a9f74f22c58c11f75abde32ac7dc269ccc0 Mon Sep 17 00:00:00 2001 From: Emily Janzer Date: Mon, 10 Jun 2019 13:50:58 -0700 Subject: [PATCH 0262/1084] Workaround to avoid bridge access from ReactTextView for Venice Summary: D14014668 introduced support for nesting views within Text on Android. Part of the implementation involved accessing the UIManagerModule from ReactTextView through context. This doesn't work in bridgeless RN because we have no UIManagerModule, and the ReactContext has no Catalyst instance. Trying to access the Catalyst instance from ReactContext throws an exception if it doesn't exist, so i'm just adding a simple check here to make sure the instance exists before proceeding. This means that this feature won't work in bridgeless mode, but that's ok for now - eventually we want to change the way this works so that it doesn't rely on accessing views in Java, which is potentially unsafe (there's nothing to stop you from mutating the views, and cpp/js would never know about it). Reviewed By: mdvacca Differential Revision: D15703100 fbshipit-source-id: 0448d55b8345fc707a25210a505cb6ac520c708a --- .../java/com/facebook/react/views/text/ReactTextView.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java index b14e49e8bf9afd..feede92d6e83b3 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java @@ -114,6 +114,12 @@ protected void onLayout(boolean changed, return; } + if (!getReactContext().hasCatalystInstance()) { + // In bridgeless mode there's no Catalyst instance; in that case, bail. + // TODO (T45503888): Figure out how to support nested views from JS or cpp. + return; + } + UIManagerModule uiManager = getReactContext().getNativeModule(UIManagerModule.class); Spanned text = (Spanned) getText(); From 4e7155ee5338e0a48ab8dd1380d7fa64d70d7a1d Mon Sep 17 00:00:00 2001 From: Emily Janzer Date: Mon, 10 Jun 2019 14:59:21 -0700 Subject: [PATCH 0263/1084] Add RN$Bridgeless flag, use it to conditionally skip bridge setup Summary: In bridgeless mode we don't want to set up the batched bridge, which is set up as part of InitializeCore. Instead of deleting InitializeCore completely, let's just skip this step if we're in bridgeless mode, which we'll detect using a global variable set on the runtime from cpp (`RN$Bridgeless`). This way you still get an error if the bridge is somehow not set up properly when you're not in bridgeless mode (it won't fail silently). Reviewed By: fkgozali Differential Revision: D15721940 fbshipit-source-id: 73896e25874dd000f37d1abc9cf6be549ab3434f --- Libraries/Core/setUpBatchedBridge.js | 78 +++++++++++++++------------- 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/Libraries/Core/setUpBatchedBridge.js b/Libraries/Core/setUpBatchedBridge.js index e9d33fe6ae3a25..21c85c690312d6 100644 --- a/Libraries/Core/setUpBatchedBridge.js +++ b/Libraries/Core/setUpBatchedBridge.js @@ -10,42 +10,48 @@ 'use strict'; /** - * Set up the BatchedBridge. This must be done after the other steps in - * InitializeCore to ensure that the JS environment has been initialized. - * You can use this module directly, or just require InitializeCore. + * We don't set up the batched bridge in bridgeless mode. Once we've migrated + * everything over to bridgeless we can just delete this file. */ -const BatchedBridge = require('../BatchedBridge/BatchedBridge'); -BatchedBridge.registerLazyCallableModule('Systrace', () => - require('../Performance/Systrace'), -); -BatchedBridge.registerLazyCallableModule('JSTimers', () => - require('./Timers/JSTimers'), -); -BatchedBridge.registerLazyCallableModule('HeapCapture', () => - require('../HeapCapture/HeapCapture'), -); -BatchedBridge.registerLazyCallableModule('SamplingProfiler', () => - require('../Performance/SamplingProfiler'), -); -BatchedBridge.registerLazyCallableModule('RCTLog', () => - require('../Utilities/RCTLog'), -); -BatchedBridge.registerLazyCallableModule('RCTDeviceEventEmitter', () => - require('../EventEmitter/RCTDeviceEventEmitter'), -); -BatchedBridge.registerLazyCallableModule('RCTNativeAppEventEmitter', () => - require('../EventEmitter/RCTNativeAppEventEmitter'), -); -BatchedBridge.registerLazyCallableModule('GlobalPerformanceLogger', () => - require('../Utilities/GlobalPerformanceLogger'), -); -BatchedBridge.registerLazyCallableModule('JSDevSupportModule', () => - require('../Utilities/JSDevSupportModule'), -); - -if (__DEV__ && !global.__RCTProfileIsProfiling) { - BatchedBridge.registerCallableModule( - 'HMRClient', - require('../Utilities/HMRClient'), +if (!global.RN$Bridgeless) { + /** + * Set up the BatchedBridge. This must be done after the other steps in + * InitializeCore to ensure that the JS environment has been initialized. + * You can use this module directly, or just require InitializeCore. + */ + const BatchedBridge = require('../BatchedBridge/BatchedBridge'); + BatchedBridge.registerLazyCallableModule('Systrace', () => + require('../Performance/Systrace'), + ); + BatchedBridge.registerLazyCallableModule('JSTimers', () => + require('./Timers/JSTimers'), + ); + BatchedBridge.registerLazyCallableModule('HeapCapture', () => + require('../HeapCapture/HeapCapture'), + ); + BatchedBridge.registerLazyCallableModule('SamplingProfiler', () => + require('../Performance/SamplingProfiler'), + ); + BatchedBridge.registerLazyCallableModule('RCTLog', () => + require('../Utilities/RCTLog'), ); + BatchedBridge.registerLazyCallableModule('RCTDeviceEventEmitter', () => + require('../EventEmitter/RCTDeviceEventEmitter'), + ); + BatchedBridge.registerLazyCallableModule('RCTNativeAppEventEmitter', () => + require('../EventEmitter/RCTNativeAppEventEmitter'), + ); + BatchedBridge.registerLazyCallableModule('GlobalPerformanceLogger', () => + require('../Utilities/GlobalPerformanceLogger'), + ); + BatchedBridge.registerLazyCallableModule('JSDevSupportModule', () => + require('../Utilities/JSDevSupportModule'), + ); + + if (__DEV__ && !global.__RCTProfileIsProfiling) { + BatchedBridge.registerCallableModule( + 'HMRClient', + require('../Utilities/HMRClient'), + ); + } } From 422472e5d91ea2023ea121ebce6e02fa361c3905 Mon Sep 17 00:00:00 2001 From: Emily Janzer Date: Mon, 10 Jun 2019 14:59:21 -0700 Subject: [PATCH 0264/1084] Don't check native view configs in bridgeless mode Summary: `verifyComponentAttributeEquivalence` checks the new JS view configs against what we get from native at runtime (in dev only). This breaks in bridgeless mode because there is no paper UIManager to ask for the viewconfigs from; this diff uses the flag from D15721940 to skip this check. Reviewed By: fkgozali Differential Revision: D15722127 fbshipit-source-id: d9227107e0ff7814c34beaae6461bb8232699c94 --- Libraries/Utilities/verifyComponentAttributeEquivalence.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libraries/Utilities/verifyComponentAttributeEquivalence.js b/Libraries/Utilities/verifyComponentAttributeEquivalence.js index 296b7837cbd7af..e64eb65d828905 100644 --- a/Libraries/Utilities/verifyComponentAttributeEquivalence.js +++ b/Libraries/Utilities/verifyComponentAttributeEquivalence.js @@ -42,7 +42,7 @@ function verifyComponentAttributeEquivalence( componentName: string, config: ReactNativeBaseComponentViewConfig<>, ) { - if (__DEV__) { + if (__DEV__ && !global.RN$Bridgeless) { const nativeAttributes = getNativeComponentAttributes(componentName); ['validAttributes', 'bubblingEventTypes', 'directEventTypes'].forEach( From 7225daf98d5b1cf71a90a491275077e454e7e4db Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Mon, 10 Jun 2019 18:37:57 -0700 Subject: [PATCH 0265/1084] TM iOS: Support @synthesize methodQueue auto queue creation Summary: Some native modules defined `synthesize methodQueue` which will ask the bridge to create a new serial queue for them. TM system needs to preserve this behavior for backward compatibility. In the future though, this magic shall be removed. Reviewed By: mdvacca Differential Revision: D15748198 fbshipit-source-id: 66a4b60a2769ac967a8d3bb00c4c635a68daebbc --- .../platform/ios/RCTTurboModuleManager.mm | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm b/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm index 91fdbc9b329efd..83da4c8b50b952 100644 --- a/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm +++ b/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm @@ -289,6 +289,30 @@ - (void)notifyAboutTurboModuleSetup:(const char *)name } } + /** + * Some modules need their own queues, but don't provide any, so we need to create it for them. + * These modules typically have the following: + * `@synthesize methodQueue = _methodQueue` + */ + if ([module respondsToSelector:@selector(methodQueue)]) { + dispatch_queue_t methodQueue = [module performSelector:@selector(methodQueue)]; + if (!methodQueue) { + NSString *moduleClassName = NSStringFromClass(module.class); + NSString *queueName = [NSString stringWithFormat:@"com.facebook.react.%@Queue", moduleClassName]; + methodQueue = dispatch_queue_create(queueName.UTF8String, DISPATCH_QUEUE_SERIAL); + @try { + [(id)module setValue:methodQueue forKey:@"methodQueue"]; + } @catch (NSException *exception) { + RCTLogError( + @"TM: %@ is returning nil for its methodQueue, which is not " + "permitted. You must either return a pre-initialized " + "queue, or @synthesize the methodQueue to let the bridge " + "create a queue for you.", + moduleClassName); + } + } + } + /** * Broadcast that this TurboModule was created. * From c0bf53b7165ab6b48b853b3eebda9593f347fcdf Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Mon, 10 Jun 2019 18:37:57 -0700 Subject: [PATCH 0266/1084] TM iOS: attempt to convert number args using RCTConvert as well Summary: Some native modules methods expects number-based args like `NSDate`. For backward compatibility, the incoming numbers should be converted using RCTConvert, just like object args. Reviewed By: mdvacca Differential Revision: D15748968 fbshipit-source-id: 4db2cb0c41eda1bbe8cde7b0365d9c3d675f5fb5 --- .../core/platform/ios/RCTTurboModule.mm | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/ReactCommon/turbomodule/core/platform/ios/RCTTurboModule.mm b/ReactCommon/turbomodule/core/platform/ios/RCTTurboModule.mm index f2862d60d71cf9..ce6c7616788173 100644 --- a/ReactCommon/turbomodule/core/platform/ios/RCTTurboModule.mm +++ b/ReactCommon/turbomodule/core/platform/ios/RCTTurboModule.mm @@ -460,6 +460,29 @@ void cleanup() { */ if (objCArgType[0] == _C_ID) { id objCArg = [NSNumber numberWithDouble:v]; + NSString *methodNameNSString = @(methodName.c_str()); + + /** + * Convert numbers using RCTConvert if possible. + */ + NSString *argumentType = getArgumentTypeName(methodNameNSString, i); + if (argumentType != nil) { + NSString *rctConvertMethodName = [NSString stringWithFormat:@"%@:", argumentType]; + SEL rctConvertSelector = NSSelectorFromString(rctConvertMethodName); + + if ([RCTConvert respondsToSelector:rctConvertSelector]) { + // Message dispatch logic from old infra + id (*convert)(id, SEL, id) = (__typeof__(convert))objc_msgSend; + id convertedObjCArg = convert([RCTConvert class], rctConvertSelector, objCArg); + + [inv setArgument:(void *)&convertedObjCArg atIndex:i + 2]; + if (convertedObjCArg) { + [retainedObjectsForInvocation addObject:convertedObjCArg]; + } + continue; + } + } + [inv setArgument:(void *)&objCArg atIndex:i + 2]; [retainedObjectsForInvocation addObject:objCArg]; } else { @@ -486,7 +509,7 @@ void cleanup() { NSString *rctConvertMethodName = [NSString stringWithFormat:@"%@:", argumentType]; SEL rctConvertSelector = NSSelectorFromString(rctConvertMethodName); - if ([RCTConvert respondsToSelector: rctConvertSelector]) { + if ([RCTConvert respondsToSelector:rctConvertSelector]) { // Message dispatch logic from old infra id (*convert)(id, SEL, id) = (__typeof__(convert))objc_msgSend; id convertedObjCArg = convert([RCTConvert class], rctConvertSelector, objCArg); From 66e02588850ee81aa8574edc46c954e7bccf42e7 Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Mon, 10 Jun 2019 20:34:06 -0700 Subject: [PATCH 0267/1084] TM: attempt to integrate with internal codegen infra Summary: An attempt to integrate the module flow types with internal codegen infra. Nothing of interest here, other than minor tweak on a spec (we don't support tupples...). Reviewed By: mdvacca Differential Revision: D15753278 fbshipit-source-id: b91d564fdbe8f72b90bea725779a9684993472b5 --- Libraries/Alert/Alert.js | 18 +++++++++++++++++- Libraries/Alert/NativeAlertManager.js | 19 +------------------ Libraries/ReactNative/NativeUIManager.js | 2 +- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/Libraries/Alert/Alert.js b/Libraries/Alert/Alert.js index c0afc6573bb73f..55bdce3fd40704 100644 --- a/Libraries/Alert/Alert.js +++ b/Libraries/Alert/Alert.js @@ -15,7 +15,23 @@ import NativeDialogManagerAndroid, { type DialogOptions, } from '../NativeModules/specs/NativeDialogManagerAndroid'; import RCTAlertManager from './RCTAlertManager'; -import {type Buttons, type Options, type AlertType} from './NativeAlertManager'; + +export type AlertType = + | 'default' + | 'plain-text' + | 'secure-text' + | 'login-password'; +export type AlertButtonStyle = 'default' | 'cancel' | 'destructive'; +export type Buttons = Array<{ + text?: string, + onPress?: ?Function, + style?: AlertButtonStyle, +}>; + +type Options = { + cancelable?: ?boolean, + onDismiss?: ?() => void, +}; /** * Launches an alert dialog with the specified title and message. diff --git a/Libraries/Alert/NativeAlertManager.js b/Libraries/Alert/NativeAlertManager.js index 16191e7e4721e9..1dcae0d265bd17 100644 --- a/Libraries/Alert/NativeAlertManager.js +++ b/Libraries/Alert/NativeAlertManager.js @@ -13,27 +13,10 @@ import type {TurboModule} from '../TurboModule/RCTExport'; import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; -export type Buttons = Array<{ - text?: string, - onPress?: ?Function, - style?: AlertButtonStyle, -}>; - -export type Options = { - cancelable?: ?boolean, - onDismiss?: ?() => void, -}; - -/* 'default' | plain-text' | 'secure-text' | 'login-password' */ -export type AlertType = string; - -/* 'default' | 'cancel' | 'destructive' */ -export type AlertButtonStyle = string; - export type Args = {| title?: string, message?: string, - buttons?: Buttons, + buttons?: Object, // TODO: have a better type type?: string, defaultValue?: string, cancelButtonKey?: string, diff --git a/Libraries/ReactNative/NativeUIManager.js b/Libraries/ReactNative/NativeUIManager.js index 9eb60e68194b81..ccfcd4928180d1 100644 --- a/Libraries/ReactNative/NativeUIManager.js +++ b/Libraries/ReactNative/NativeUIManager.js @@ -30,7 +30,7 @@ export interface Spec extends TurboModule { +blur: (reactTag: ?number) => void; +findSubviewIn: ( reactTag: ?number, - point: [number, number], + point: Array, callback: ( nativeViewTag: number, left: number, From 1f8e08a4fad28e42c1cf9f886a850c538ff038c4 Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Tue, 11 Jun 2019 00:22:11 -0700 Subject: [PATCH 0268/1084] Move ImageEditor JS files to FB internal Summary: This module is being removed from RN as part of the Lean Core effort. Reviewed By: TheSavior Differential Revision: D15714507 fbshipit-source-id: bb5dc2025a25ad450d6971e5948e7a2e678a9a25 --- Libraries/Image/ImageEditor.js | 71 ------------------- Libraries/Image/NativeImageEditor.js | 25 ------- .../react-native-implementation.js | 22 +++--- 3 files changed, 13 insertions(+), 105 deletions(-) delete mode 100644 Libraries/Image/ImageEditor.js delete mode 100644 Libraries/Image/NativeImageEditor.js diff --git a/Libraries/Image/ImageEditor.js b/Libraries/Image/ImageEditor.js deleted file mode 100644 index 69a7a9121e0783..00000000000000 --- a/Libraries/Image/ImageEditor.js +++ /dev/null @@ -1,71 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - * @format - */ -'use strict'; -import NativeImageEditor from './NativeImageEditor'; - -type ImageCropData = { - /** - * The top-left corner of the cropped image, specified in the original - * image's coordinate space. - */ - offset: {| - x: number, - y: number, - |}, - /** - * The size (dimensions) of the cropped image, specified in the original - * image's coordinate space. - */ - size: {| - width: number, - height: number, - |}, - /** - * (Optional) size to scale the cropped image to. - */ - displaySize?: ?{| - width: number, - height: number, - |}, - /** - * (Optional) the resizing mode to use when scaling the image. If the - * `displaySize` param is not specified, this has no effect. - */ - resizeMode?: ?$Keys<{ - contain: string, - cover: string, - stretch: string, - }>, -}; - -class ImageEditor { - /** - * Crop the image specified by the URI param. If URI points to a remote - * image, it will be downloaded automatically. If the image cannot be - * loaded/downloaded, the failure callback will be called. On Android, a - * downloaded image may be cached in external storage, a publicly accessible - * location, if it has more available space than internal storage. - * - * If the cropping process is successful, the resultant cropped image - * will be stored in the ImageStore, and the URI returned in the success - * callback will point to the image in the store. Remember to delete the - * cropped image from the ImageStore when you are done with it. - */ - static cropImage( - uri: string, - cropData: ImageCropData, - success: (uri: string) => void, - failure: (error: Object) => void, - ) { - NativeImageEditor.cropImage(uri, cropData, success, failure); - } -} - -module.exports = ImageEditor; diff --git a/Libraries/Image/NativeImageEditor.js b/Libraries/Image/NativeImageEditor.js deleted file mode 100644 index e208cb47b6df1c..00000000000000 --- a/Libraries/Image/NativeImageEditor.js +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - * @format - */ - -'use strict'; - -import type {TurboModule} from '../TurboModule/RCTExport'; -import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; - -export interface Spec extends TurboModule { - +cropImage: ( - uri: string, - options: Object, // TODO: type this better - success: (uri: string) => void, - error: (error: string) => void, - ) => void; -} - -export default TurboModuleRegistry.getEnforcing('ImageEditingManager'); diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js index bc20dfac8f27c2..d22e4f2ac84a8d 100644 --- a/Libraries/react-native/react-native-implementation.js +++ b/Libraries/react-native/react-native-implementation.js @@ -52,15 +52,6 @@ module.exports = { get ImageBackground() { return require('../Image/ImageBackground'); }, - get ImageEditor() { - warnOnce( - 'image-editor-moved', - 'Image Editor has been extracted from react-native core and will be removed in a future release. ' + - "It can now be installed and imported from '@react-native-community/image-editor' instead of 'react-native'. " + - 'See https://github.com/react-native-community/react-native-image-editor', - ); - return require('../Image/ImageEditor'); - }, get InputAccessoryView() { return require('../Components/TextInput/InputAccessoryView'); }, @@ -413,4 +404,17 @@ if (__DEV__) { ); }, }); + + // $FlowFixMe This is intentional: Flow will error when attempting to access ImageEditor. + Object.defineProperty(module.exports, 'ImageEditor', { + configurable: true, + get() { + invariant( + false, + 'ImageEditor has been removed from React Native. ' + + "It can now be installed and imported from 'react-native-image-editor' instead of 'react-native'. " + + 'See https://github.com/react-native-community/react-native-image-editor', + ); + }, + }); } From f8a400a53fd7f336da3809ab87d88be0cd55b1af Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Tue, 11 Jun 2019 00:22:11 -0700 Subject: [PATCH 0269/1084] Move ViewPagerAndroid JS code to FB Internal Summary: This module is being removed from React Native via Lean Core. This diff moves all the related JS files to FB internal. Note: I removed two references to previously removed modules from some files in this diff. I hope you don't mind. Reviewed By: TheSavior Differential Revision: D15714919 fbshipit-source-id: 88ea406396b31f5c255e06d9c92b67127c81db4a --- .../AndroidViewPagerNativeComponent.js | 112 ------- .../ViewPager/ViewPagerAndroid.android.js | 277 ---------------- .../ViewPager/ViewPagerAndroid.ios.js | 12 - .../react-native-implementation.js | 22 +- .../ViewPagerAndroidExample.android.js | 302 ------------------ RNTester/js/utils/RNTesterList.android.js | 4 - 6 files changed, 13 insertions(+), 716 deletions(-) delete mode 100644 Libraries/Components/ViewPager/AndroidViewPagerNativeComponent.js delete mode 100644 Libraries/Components/ViewPager/ViewPagerAndroid.android.js delete mode 100644 Libraries/Components/ViewPager/ViewPagerAndroid.ios.js delete mode 100644 RNTester/js/examples/ViewPagerAndroid/ViewPagerAndroidExample.android.js diff --git a/Libraries/Components/ViewPager/AndroidViewPagerNativeComponent.js b/Libraries/Components/ViewPager/AndroidViewPagerNativeComponent.js deleted file mode 100644 index 82c7e18fb65d4b..00000000000000 --- a/Libraries/Components/ViewPager/AndroidViewPagerNativeComponent.js +++ /dev/null @@ -1,112 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @flow - */ - -'use strict'; - -const requireNativeComponent = require('../../ReactNative/requireNativeComponent'); - -import type {SyntheticEvent} from '../../Types/CoreEventTypes'; -import type {NativeComponent} from '../../Renderer/shims/ReactNative'; -import type {Node} from 'react'; -import type {ViewStyleProp} from '../../StyleSheet/StyleSheet'; - -type PageScrollState = 'idle' | 'dragging' | 'settling'; - -type PageScrollEvent = SyntheticEvent< - $ReadOnly<{| - position: number, - offset: number, - |}>, ->; - -type PageScrollStateChangedEvent = SyntheticEvent< - $ReadOnly<{| - pageScrollState: PageScrollState, - |}>, ->; - -type PageSelectedEvent = SyntheticEvent< - $ReadOnly<{| - position: number, - |}>, ->; - -type NativeProps = $ReadOnly<{| - /** - * Index of initial page that should be selected. Use `setPage` method to - * update the page, and `onPageSelected` to monitor page changes - */ - initialPage?: ?number, - - /** - * Executed when transitioning between pages (ether because of animation for - * the requested page change or when user is swiping/dragging between pages) - * The `event.nativeEvent` object for this callback will carry following data: - * - position - index of first page from the left that is currently visible - * - offset - value from range [0,1) describing stage between page transitions. - * Value x means that (1 - x) fraction of the page at "position" index is - * visible, and x fraction of the next page is visible. - */ - onPageScroll?: ?(e: PageScrollEvent) => void, - - /** - * Function called when the page scrolling state has changed. - * The page scrolling state can be in 3 states: - * - idle, meaning there is no interaction with the page scroller happening at the time - * - dragging, meaning there is currently an interaction with the page scroller - * - settling, meaning that there was an interaction with the page scroller, and the - * page scroller is now finishing it's closing or opening animation - */ - onPageScrollStateChanged?: ?(e: PageScrollStateChangedEvent) => void, - - /** - * This callback will be called once ViewPager finish navigating to selected page - * (when user swipes between pages). The `event.nativeEvent` object passed to this - * callback will have following fields: - * - position - index of page that has been selected - */ - onPageSelected?: ?(e: PageSelectedEvent) => void, - - /** - * Blank space to show between pages. This is only visible while scrolling, pages are still - * edge-to-edge. - */ - pageMargin?: ?number, - - /** - * Whether enable showing peekFraction or not. If this is true, the preview of - * last and next page will show in current screen. Defaults to false. - */ - - peekEnabled?: ?boolean, - - /** - * Determines whether the keyboard gets dismissed in response to a drag. - * - 'none' (the default), drags do not dismiss the keyboard. - * - 'on-drag', the keyboard is dismissed when a drag begins. - */ - keyboardDismissMode?: ?('none' | 'on-drag'), - - /** - * When false, the content does not scroll. - * The default value is true. - */ - scrollEnabled?: ?boolean, - - children?: Node, - - style?: ?ViewStyleProp, -|}>; - -type ViewPagerNativeType = Class>; - -module.exports = ((requireNativeComponent( - 'AndroidViewPager', -): any): ViewPagerNativeType); diff --git a/Libraries/Components/ViewPager/ViewPagerAndroid.android.js b/Libraries/Components/ViewPager/ViewPagerAndroid.android.js deleted file mode 100644 index 0ffb242736f4b6..00000000000000 --- a/Libraries/Components/ViewPager/ViewPagerAndroid.android.js +++ /dev/null @@ -1,277 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @flow strict-local - */ - -'use strict'; - -const React = require('react'); -const ReactNative = require('../../Renderer/shims/ReactNative'); -const UIManager = require('../../ReactNative/UIManager'); - -const dismissKeyboard = require('../../Utilities/dismissKeyboard'); - -const NativeAndroidViewPager = require('./AndroidViewPagerNativeComponent'); - -import type {SyntheticEvent} from '../../Types/CoreEventTypes'; -import type {ViewStyleProp} from '../../StyleSheet/StyleSheet'; - -const VIEWPAGER_REF = 'viewPager'; - -type PageScrollState = 'idle' | 'dragging' | 'settling'; - -type PageScrollEvent = SyntheticEvent< - $ReadOnly<{| - position: number, - offset: number, - |}>, ->; - -type PageScrollStateChangedEvent = SyntheticEvent< - $ReadOnly<{| - pageScrollState: PageScrollState, - |}>, ->; - -type PageSelectedEvent = SyntheticEvent< - $ReadOnly<{| - position: number, - |}>, ->; - -export type ViewPagerScrollState = $Keys<{ - idle: string, - dragging: string, - settling: string, -}>; - -type Props = $ReadOnly<{| - /** - * Index of initial page that should be selected. Use `setPage` method to - * update the page, and `onPageSelected` to monitor page changes - */ - initialPage?: ?number, - - /** - * Executed when transitioning between pages (ether because of animation for - * the requested page change or when user is swiping/dragging between pages) - * The `event.nativeEvent` object for this callback will carry following data: - * - position - index of first page from the left that is currently visible - * - offset - value from range [0,1) describing stage between page transitions. - * Value x means that (1 - x) fraction of the page at "position" index is - * visible, and x fraction of the next page is visible. - */ - onPageScroll?: ?(e: PageScrollEvent) => void, - - /** - * Function called when the page scrolling state has changed. - * The page scrolling state can be in 3 states: - * - idle, meaning there is no interaction with the page scroller happening at the time - * - dragging, meaning there is currently an interaction with the page scroller - * - settling, meaning that there was an interaction with the page scroller, and the - * page scroller is now finishing it's closing or opening animation - */ - onPageScrollStateChanged?: ?(e: PageScrollStateChangedEvent) => void, - - /** - * This callback will be called once ViewPager finish navigating to selected page - * (when user swipes between pages). The `event.nativeEvent` object passed to this - * callback will have following fields: - * - position - index of page that has been selected - */ - onPageSelected?: ?(e: PageSelectedEvent) => void, - - /** - * Blank space to show between pages. This is only visible while scrolling, pages are still - * edge-to-edge. - */ - pageMargin?: ?number, - - /** - * Whether enable showing peekFraction or not. If this is true, the preview of - * last and next page will show in current screen. Defaults to false. - */ - - peekEnabled?: ?boolean, - - /** - * Determines whether the keyboard gets dismissed in response to a drag. - * - 'none' (the default), drags do not dismiss the keyboard. - * - 'on-drag', the keyboard is dismissed when a drag begins. - */ - keyboardDismissMode?: ?('none' | 'on-drag'), - - /** - * When false, the content does not scroll. - * The default value is true. - */ - scrollEnabled?: ?boolean, - - children?: React.Node, - - style?: ?ViewStyleProp, -|}>; - -/** - * Container that allows to flip left and right between child views. Each - * child view of the `ViewPagerAndroid` will be treated as a separate page - * and will be stretched to fill the `ViewPagerAndroid`. - * - * It is important all children are ``s and not composite components. - * You can set style properties like `padding` or `backgroundColor` for each - * child. It is also important that each child have a `key` prop. - * - * Example: - * - * ``` - * render: function() { - * return ( - * - * - * First page - * - * - * Second page - * - * - * ); - * } - * - * ... - * - * var styles = { - * ... - * viewPager: { - * flex: 1 - * }, - * pageStyle: { - * alignItems: 'center', - * padding: 20, - * } - * } - * ``` - */ - -class ViewPagerAndroid extends React.Component { - componentDidMount() { - if (this.props.initialPage != null) { - this.setPageWithoutAnimation(this.props.initialPage); - } - } - - /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found - * when making Flow check .android.js files. */ - getInnerViewNode = (): ReactComponent => { - return this.refs[VIEWPAGER_REF].getInnerViewNode(); - }; - - /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found - * when making Flow check .android.js files. */ - _childrenWithOverridenStyle = (): Array => { - // Override styles so that each page will fill the parent. Native component - // will handle positioning of elements, so it's not important to offset - // them correctly. - return React.Children.map(this.props.children, function(child) { - if (!child) { - return null; - } - const newProps = { - ...child.props, - style: [ - child.props.style, - { - position: 'absolute', - left: 0, - top: 0, - right: 0, - bottom: 0, - width: undefined, - height: undefined, - }, - ], - collapsable: false, - }; - if ( - child.type && - child.type.displayName && - child.type.displayName !== 'RCTView' && - child.type.displayName !== 'View' - ) { - console.warn( - 'Each ViewPager child must be a . Was ' + - child.type.displayName, - ); - } - return React.createElement(child.type, newProps); - }); - }; - - _onPageScroll = (e: PageScrollEvent) => { - if (this.props.onPageScroll) { - this.props.onPageScroll(e); - } - if (this.props.keyboardDismissMode === 'on-drag') { - dismissKeyboard(); - } - }; - - _onPageScrollStateChanged = (e: PageScrollStateChangedEvent) => { - if (this.props.onPageScrollStateChanged) { - this.props.onPageScrollStateChanged(e); - } - }; - - _onPageSelected = (e: PageSelectedEvent) => { - if (this.props.onPageSelected) { - this.props.onPageSelected(e); - } - }; - - /** - * A helper function to scroll to a specific page in the ViewPager. - * The transition between pages will be animated. - */ - setPage = (selectedPage: number) => { - UIManager.dispatchViewManagerCommand( - ReactNative.findNodeHandle(this), - UIManager.getViewManagerConfig('AndroidViewPager').Commands.setPage, - [selectedPage], - ); - }; - - /** - * A helper function to scroll to a specific page in the ViewPager. - * The transition between pages will *not* be animated. - */ - setPageWithoutAnimation = (selectedPage: number) => { - UIManager.dispatchViewManagerCommand( - ReactNative.findNodeHandle(this), - UIManager.getViewManagerConfig('AndroidViewPager').Commands - .setPageWithoutAnimation, - [selectedPage], - ); - }; - - render() { - return ( - - ); - } -} - -module.exports = ViewPagerAndroid; diff --git a/Libraries/Components/ViewPager/ViewPagerAndroid.ios.js b/Libraries/Components/ViewPager/ViewPagerAndroid.ios.js deleted file mode 100644 index d5fd5cf83f7560..00000000000000 --- a/Libraries/Components/ViewPager/ViewPagerAndroid.ios.js +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -'use strict'; - -module.exports = require('../UnimplementedViews/UnimplementedView'); diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js index d22e4f2ac84a8d..bea2d5cd5cb491 100644 --- a/Libraries/react-native/react-native-implementation.js +++ b/Libraries/react-native/react-native-implementation.js @@ -136,15 +136,6 @@ module.exports = { get View() { return require('../Components/View/View'); }, - get ViewPagerAndroid() { - warnOnce( - 'viewpager-moved', - 'ViewPagerAndroid has been extracted from react-native core and will be removed in a future release. ' + - "It can now be installed and imported from '@react-native-community/viewpager' instead of 'react-native'. " + - 'See https://github.com/react-native-community/react-native-viewpager', - ); - return require('../Components/ViewPager/ViewPagerAndroid'); - }, get VirtualizedList() { return require('../Lists/VirtualizedList'); }, @@ -417,4 +408,17 @@ if (__DEV__) { ); }, }); + + // $FlowFixMe This is intentional: Flow will error when attempting to access ViewPagerAndroid. + Object.defineProperty(module.exports, 'ViewPagerAndroid', { + configurable: true, + get() { + invariant( + false, + 'ViewPagerAndroid has been removed from React Native. ' + + "It can now be installed and imported from 'react-native-viewpager' instead of 'react-native'. " + + 'See https://github.com/react-native-community/react-native-viewpager', + ); + }, + }); } diff --git a/RNTester/js/examples/ViewPagerAndroid/ViewPagerAndroidExample.android.js b/RNTester/js/examples/ViewPagerAndroid/ViewPagerAndroidExample.android.js deleted file mode 100644 index 579d6f76495379..00000000000000 --- a/RNTester/js/examples/ViewPagerAndroid/ViewPagerAndroidExample.android.js +++ /dev/null @@ -1,302 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -'use strict'; - -const React = require('react'); -const { - Image, - StyleSheet, - Text, - TouchableWithoutFeedback, - TouchableOpacity, - View, - ViewPagerAndroid, -} = require('react-native'); - -import type {ViewPagerScrollState} from '../../../../Libraries/Components/ViewPager/ViewPagerAndroid'; - -const PAGES = 5; -const BGCOLOR = ['#fdc08e', '#fff6b9', '#99d1b7', '#dde5fe', '#f79273']; -const IMAGE_URIS = [ - 'https://apod.nasa.gov/apod/image/1410/20141008tleBaldridge001h990.jpg', - 'https://apod.nasa.gov/apod/image/1409/volcanicpillar_vetter_960.jpg', - 'https://apod.nasa.gov/apod/image/1409/m27_snyder_960.jpg', - 'https://apod.nasa.gov/apod/image/1409/PupAmulti_rot0.jpg', - 'https://apod.nasa.gov/apod/image/1510/lunareclipse_27Sep_beletskycrop4.jpg', -]; - -type Props = $ReadOnly<{||}>; -type State = {|likes: number|}; -class LikeCount extends React.Component { - state = { - likes: 7, - }; - - onClick = () => { - this.setState({likes: this.state.likes + 1}); - }; - - render() { - const thumbsUp = '\uD83D\uDC4D'; - return ( - - - {thumbsUp + ' Like'} - - {this.state.likes + ' likes'} - - ); - } -} - -class Button extends React.Component { - _handlePress = () => { - if (this.props.enabled && this.props.onPress) { - this.props.onPress(); - } - }; - - render() { - return ( - - - {this.props.text} - - - ); - } -} - -class ProgressBar extends React.Component { - render() { - const fractionalPosition = - this.props.progress.position + this.props.progress.offset; - const progressBarSize = - (fractionalPosition / (PAGES - 1)) * this.props.size; - return ( - - - - ); - } -} - -class ViewPagerAndroidExample extends React.Component { - state = { - page: 0, - animationsAreEnabled: true, - scrollEnabled: true, - progress: { - position: 0, - offset: 0, - }, - }; - - onPageSelected = e => { - this.setState({page: e.nativeEvent.position}); - }; - - onPageScroll = e => { - this.setState({progress: e.nativeEvent}); - }; - - onPageScrollStateChanged = (state: ViewPagerScrollState) => { - this.setState({scrollState: state}); - }; - - move = delta => { - const page = this.state.page + delta; - this.go(page); - }; - - go = page => { - if (this.state.animationsAreEnabled) { - this.viewPager.setPage(page); - } else { - this.viewPager.setPageWithoutAnimation(page); - } - - this.setState({page}); - }; - - render() { - const pages = []; - for (let i = 0; i < PAGES; i++) { - const pageStyle = { - backgroundColor: BGCOLOR[i % BGCOLOR.length], - alignItems: 'center', - padding: 20, - }; - pages.push( - - - - , - ); - } - const {page, animationsAreEnabled} = this.state; - return ( - - { - this.viewPager = viewPager; - }}> - {pages} - - -