Integrate Additional RNTester Refactoring (9/2 Nightly RN Build) (#6356)
* Integrate Additional RNTester Refactoring (9/2 Nightly RN Build)
Commits: 5bc67b658...f0e80ae22
The most interesting bits here are addiontal RNTester changes, such as the removal of the back button. This forces some more E2ETest updates that were merged in a previous PR.
Nested Images inside of Text are rendered on start now, which is problematic for NetUI. ACoates forked the component for XAML RNTester, and this change forks for NetUI as well, which intention to upstream tracked by #6341. We similarly need to re-patch out AsyncStorage usage on NetUI after the code changed for it.
The fbjs dependency was removed, whichgets closer to letting us remove a node-fetch resolution (though the CLI pulls in an older Metro package which doesn't let us). Android added some extra Platform constants around manufacturer/Brand (likely related to the Xiamoi crash workaround), which we don't implement here, since we only really care about the union of Android + iOS, along with anything we think would be useful specifically for Windows.
* Work around RNW display: none issue
* Change files
This commit is contained in:
Родитель
fdf09a5447
Коммит
34d003379d
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"type": "prerelease",
|
||||
"comment": "Integrate Additional RNTester Refactoring (9/2 Nightly RN Build)",
|
||||
"packageName": "@office-iss/react-native-win32",
|
||||
"email": "ngerlem@microsoft.com",
|
||||
"dependentChangeType": "patch",
|
||||
"date": "2020-10-28T22:55:24.887Z"
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"type": "prerelease",
|
||||
"comment": "Integrate Additional RNTester Refactoring (9/2 Nightly RN Build)",
|
||||
"packageName": "react-native-windows",
|
||||
"email": "ngerlem@microsoft.com",
|
||||
"dependentChangeType": "patch",
|
||||
"date": "2020-10-28T22:55:28.008Z"
|
||||
}
|
|
@ -143,7 +143,6 @@ Pay attention to the last line of the LoginPage, we always export a new instance
|
|||
```
|
||||
// login.spec.ts
|
||||
before(() => {
|
||||
HomePage.backToHomePage();
|
||||
HomePage.clickAndGotoLoginPage();
|
||||
});
|
||||
|
||||
|
|
|
@ -5,13 +5,20 @@
|
|||
"excludePatterns": [
|
||||
"src/js/examples-win/**"
|
||||
],
|
||||
"baseVersion": "0.0.0-5bc67b658",
|
||||
"baseVersion": "0.0.0-f0e80ae22",
|
||||
"overrides": [
|
||||
{
|
||||
"type": "patch",
|
||||
"file": "src/js/components/RNTesterEmptyBookmarksState.windows.js",
|
||||
"baseFile": "packages/rn-tester/js/components/RNTesterEmptyBookmarksState.js",
|
||||
"baseHash": "312a8f4a51f942df975f865638570a5349c0cd3f",
|
||||
"issue": 6341
|
||||
},
|
||||
{
|
||||
"type": "patch",
|
||||
"file": "src/js/components/RNTesterExampleList.windows.js",
|
||||
"baseFile": "packages/rn-tester/js/components/RNTesterExampleList.js",
|
||||
"baseHash": "6292c4c6f4133f6355b8759ed5bfdefc8bcfcd44",
|
||||
"baseHash": "9e2583dfe4f3ce7119052e879a2a29ec6996b77f",
|
||||
"issue": 5834
|
||||
},
|
||||
{
|
||||
|
@ -84,12 +91,19 @@
|
|||
"baseHash": "24a37c3bb52acc5a29cf1259756490321fdf1475"
|
||||
},
|
||||
{
|
||||
"type": "derived",
|
||||
"type": "copy",
|
||||
"file": "src/js/RNTesterApp.windows.js",
|
||||
"baseFile": "packages/rn-tester/js/RNTesterApp.ios.js",
|
||||
"baseHash": "b86a1fd9363b807c340c58135e610bdae8ee2fae",
|
||||
"baseFile": "packages/rn-tester/js/RNTesterApp.android.js",
|
||||
"baseHash": "30f3ef9bdc0e2c337309079831664c4a596c404f",
|
||||
"issue": 4586
|
||||
},
|
||||
{
|
||||
"type": "patch",
|
||||
"file": "src/js/RNTesterAppShared.windows.js",
|
||||
"baseFile": "packages/rn-tester/js/RNTesterAppShared.js",
|
||||
"baseHash": "9584b88105275c66c755247acd363ad33dffcc47",
|
||||
"issue": 6355
|
||||
},
|
||||
{
|
||||
"type": "derived",
|
||||
"file": "src/js/utils/RNTesterList.windows.js",
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
"@react-native/tester": "0.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react-native": "0.0.0-5bc67b658",
|
||||
"react-native": "0.0.0-f0e80ae22",
|
||||
"react-native-windows": "^0.0.0-canary.190"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -22,7 +22,7 @@
|
|||
"@rnw-scripts/ts-config": "0.1.0",
|
||||
"eslint": "6.8.0",
|
||||
"just-scripts": "^0.44.7",
|
||||
"react-native": "0.0.0-5bc67b658",
|
||||
"react-native": "0.0.0-f0e80ae22",
|
||||
"react-native-platform-override": "^0.4.0",
|
||||
"react-native-windows": "^0.0.0-canary.190",
|
||||
"typescript": "^3.8.3"
|
||||
|
|
|
@ -10,363 +10,10 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const RNTesterActions = require('./utils/RNTesterActions');
|
||||
const RNTesterExampleContainer = require('./components/RNTesterExampleContainer');
|
||||
const RNTesterExampleList = require('./components/RNTesterExampleList');
|
||||
const RNTesterList = require('./utils/RNTesterList'); // [Windows] Remove .ios
|
||||
const RNTesterNavigationReducer = require('./utils/RNTesterNavigationReducer');
|
||||
const React = require('react');
|
||||
// const SnapshotViewIOS = require('./examples/Snapshot/SnapshotViewIOS.ios'); [Windows]
|
||||
const RNTesterNavbar = require('./components/RNTesterNavbar');
|
||||
import {AppRegistry} from 'react-native';
|
||||
|
||||
const {
|
||||
AppRegistry,
|
||||
AsyncStorage,
|
||||
BackHandler,
|
||||
Button,
|
||||
Platform,
|
||||
SafeAreaView,
|
||||
StyleSheet,
|
||||
Text,
|
||||
useColorScheme,
|
||||
View,
|
||||
LogBox,
|
||||
} = require('react-native');
|
||||
|
||||
import type {RNTesterExample} from './types/RNTesterTypes';
|
||||
import type {
|
||||
RNTesterAction,
|
||||
RNTesterExampleAction,
|
||||
} from './utils/RNTesterActions';
|
||||
import type {RNTesterNavigationState} from './utils/RNTesterNavigationReducer';
|
||||
import {RNTesterThemeContext, themes} from './components/RNTesterTheme';
|
||||
import RNTesterDocumentationURL from './components/RNTesterDocumentationURL';
|
||||
import type {ColorSchemeName} from '../../../Libraries/Utilities/NativeAppearance';
|
||||
import {
|
||||
RNTesterBookmarkContext,
|
||||
bookmarks,
|
||||
} from './components/RNTesterBookmark';
|
||||
import type {RNTesterBookmark} from './components/RNTesterBookmark';
|
||||
|
||||
type Props = {exampleFromAppetizeParams?: ?string, ...};
|
||||
|
||||
import {
|
||||
initializeAsyncStore,
|
||||
addApi,
|
||||
addComponent,
|
||||
removeApi,
|
||||
removeComponent,
|
||||
checkBookmarks,
|
||||
updateRecentlyViewedList,
|
||||
} from './utils/RNTesterAsyncStorageAbstraction';
|
||||
|
||||
const APP_STATE_KEY = 'RNTesterAppState.v2';
|
||||
|
||||
const Header = ({
|
||||
onBack,
|
||||
title,
|
||||
documentationURL,
|
||||
}: {
|
||||
onBack?: () => mixed,
|
||||
title: string,
|
||||
documentationURL?: string,
|
||||
...
|
||||
}) => (
|
||||
<RNTesterThemeContext.Consumer>
|
||||
{theme => {
|
||||
return (
|
||||
<SafeAreaView
|
||||
style={[
|
||||
styles.headerContainer,
|
||||
{
|
||||
borderBottomColor: theme.SeparatorColor,
|
||||
backgroundColor: theme.TertiarySystemBackgroundColor,
|
||||
},
|
||||
]}>
|
||||
<View style={styles.header}>
|
||||
<View style={styles.headerCenter}>
|
||||
<Text style={[styles.title, {color: theme.LabelColor}]}>
|
||||
{title}
|
||||
</Text>
|
||||
{documentationURL && (
|
||||
<RNTesterDocumentationURL documentationURL={documentationURL} />
|
||||
)}
|
||||
</View>
|
||||
{onBack && (
|
||||
<View>
|
||||
<Button
|
||||
testID="BackButton"
|
||||
title="Back"
|
||||
onPress={onBack}
|
||||
color={Platform.select({
|
||||
ios: theme.LinkColor,
|
||||
default: undefined,
|
||||
})}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}}
|
||||
</RNTesterThemeContext.Consumer>
|
||||
);
|
||||
|
||||
const RNTesterExampleContainerViaHook = ({
|
||||
onBack,
|
||||
title,
|
||||
module,
|
||||
}: {
|
||||
onBack?: () => mixed,
|
||||
title: string,
|
||||
module: RNTesterExample,
|
||||
...
|
||||
}) => {
|
||||
const colorScheme: ?ColorSchemeName = useColorScheme();
|
||||
const theme = colorScheme === 'dark' ? themes.dark : themes.light;
|
||||
return (
|
||||
<RNTesterThemeContext.Provider value={theme}>
|
||||
<View style={styles.exampleContainer}>
|
||||
<Header
|
||||
title={title}
|
||||
onBack={onBack}
|
||||
documentationURL={module.documentationURL}
|
||||
/>
|
||||
<RNTesterExampleContainer module={module} />
|
||||
</View>
|
||||
</RNTesterThemeContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
const RNTesterExampleListViaHook = ({
|
||||
onNavigate,
|
||||
UpdateRecentlyViewedList,
|
||||
recentComponents,
|
||||
recentApis,
|
||||
bookmark,
|
||||
list,
|
||||
screen,
|
||||
}: {
|
||||
onNavigate?: (item: RNTesterExampleAction, key: string) => mixed,
|
||||
UpdateRecentlyViewedList?: (item: RNTesterExample, key: string) => mixed,
|
||||
recentComponents: Array<RNTesterExample>,
|
||||
recentApis: Array<RNTesterExample>,
|
||||
bookmark: RNTesterBookmark,
|
||||
screen: string,
|
||||
list: {
|
||||
ComponentExamples: Array<RNTesterExample>,
|
||||
APIExamples: Array<RNTesterExample>,
|
||||
...
|
||||
},
|
||||
...
|
||||
}) => {
|
||||
const colorScheme: ?ColorSchemeName = useColorScheme();
|
||||
const theme = colorScheme === 'dark' ? themes.dark : themes.light;
|
||||
const exampleTitle =
|
||||
screen === 'component'
|
||||
? 'Component Store'
|
||||
: screen === 'api'
|
||||
? 'API Store'
|
||||
: 'Bookmarks';
|
||||
return (
|
||||
<RNTesterThemeContext.Provider value={theme}>
|
||||
<RNTesterBookmarkContext.Provider value={bookmark}>
|
||||
<View style={styles.exampleContainer}>
|
||||
<Header title={exampleTitle} />
|
||||
<RNTesterExampleList
|
||||
onNavigate={onNavigate}
|
||||
recentComponents={recentComponents}
|
||||
recentApis={recentApis}
|
||||
updateRecentlyViewedList={UpdateRecentlyViewedList}
|
||||
list={list}
|
||||
screen={screen}
|
||||
/>
|
||||
</View>
|
||||
</RNTesterBookmarkContext.Provider>
|
||||
</RNTesterThemeContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
class RNTesterApp extends React.Component<Props, RNTesterNavigationState> {
|
||||
_mounted: boolean;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
// RNTester App currently uses Async Storage from react-native for storing navigation state
|
||||
// and bookmark items.
|
||||
// TODO: Add Native Async Storage Module in RNTester
|
||||
LogBox.ignoreLogs([new RegExp('has been extracted from react-native')]);
|
||||
|
||||
this.state = {
|
||||
openExample: null,
|
||||
screen: 'component',
|
||||
Components: bookmarks.Components,
|
||||
Api: bookmarks.Api,
|
||||
recentComponents: [],
|
||||
recentApis: [],
|
||||
AddApi: (apiName, api) => addApi(apiName, api, this),
|
||||
AddComponent: (componentName, component) =>
|
||||
addComponent(componentName, component, this),
|
||||
RemoveApi: apiName => removeApi(apiName, this),
|
||||
RemoveComponent: componentName => removeComponent(componentName, this),
|
||||
checkBookmark: (title, key) => checkBookmarks(title, key, this),
|
||||
updateRecentlyViewedList: (item, key) =>
|
||||
updateRecentlyViewedList(item, key, this),
|
||||
};
|
||||
}
|
||||
|
||||
UNSAFE_componentWillMount() {
|
||||
BackHandler.addEventListener('hardwareBackPress', this._handleBack);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
initializeAsyncStore(this);
|
||||
}
|
||||
|
||||
_handleBack = () => {
|
||||
this._handleAction(RNTesterActions.Back(this.state.screen));
|
||||
};
|
||||
|
||||
_handleAction = (action: ?RNTesterAction) => {
|
||||
if (!action) {
|
||||
return;
|
||||
}
|
||||
const newState = RNTesterNavigationReducer(this.state, action);
|
||||
if (this.state !== newState) {
|
||||
// syncing the app screens over async storage
|
||||
this.setState(newState, () =>
|
||||
AsyncStorage.setItem(APP_STATE_KEY, JSON.stringify(this.state)),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
render(): React.Node | null {
|
||||
const bookmark = {
|
||||
Components: this.state.Components,
|
||||
Api: this.state.Api,
|
||||
AddApi: this.state.AddApi,
|
||||
AddComponent: this.state.AddComponent,
|
||||
RemoveApi: this.state.RemoveApi,
|
||||
RemoveComponent: this.state.RemoveComponent,
|
||||
checkBookmark: this.state.checkBookmark,
|
||||
};
|
||||
|
||||
if (!this.state) {
|
||||
return null;
|
||||
}
|
||||
if (this.state.openExample) {
|
||||
const Component = RNTesterList.Modules[this.state.openExample];
|
||||
if (Component && Component.external) {
|
||||
return <Component onExampleExit={this._handleBack} />;
|
||||
} else {
|
||||
return (
|
||||
<>
|
||||
<RNTesterExampleContainerViaHook
|
||||
onBack={this._handleBack}
|
||||
title={Component.title}
|
||||
module={Component}
|
||||
/>
|
||||
<View style={styles.bottomNavbar}>
|
||||
<RNTesterNavbar onNavigate={this._handleAction} />
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<RNTesterExampleListViaHook
|
||||
key={this.state.screen}
|
||||
title={'RNTester'}
|
||||
onNavigate={this._handleAction}
|
||||
UpdateRecentlyViewedList={this.state.updateRecentlyViewedList}
|
||||
recentComponents={this.state.recentComponents}
|
||||
recentApis={this.state.recentApis}
|
||||
bookmark={bookmark}
|
||||
list={RNTesterList}
|
||||
screen={this.state.screen}
|
||||
/>
|
||||
<View style={styles.bottomNavbar}>
|
||||
<RNTesterNavbar
|
||||
screen={this.state.screen}
|
||||
onNavigate={this._handleAction}
|
||||
/>
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
headerContainer: {
|
||||
borderBottomWidth: StyleSheet.hairlineWidth,
|
||||
},
|
||||
header: {
|
||||
height: 40,
|
||||
flexDirection: 'row',
|
||||
},
|
||||
headerCenter: {
|
||||
flex: 1,
|
||||
position: 'absolute',
|
||||
top: 7,
|
||||
left: 0,
|
||||
right: 0,
|
||||
alignItems: 'center',
|
||||
},
|
||||
title: {
|
||||
fontSize: 19,
|
||||
fontWeight: '600',
|
||||
textAlign: 'center',
|
||||
},
|
||||
exampleContainer: {
|
||||
flex: 1,
|
||||
},
|
||||
bottomNavbar: {
|
||||
bottom: 0,
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
position: 'absolute',
|
||||
},
|
||||
});
|
||||
// [Windows
|
||||
// AppRegistry.registerComponent('SetPropertiesExampleApp', () =>
|
||||
// require('./examples/SetPropertiesExample/SetPropertiesExampleApp'),
|
||||
// );
|
||||
// AppRegistry.registerComponent('RootViewSizeFlexibilityExampleApp', () =>
|
||||
// require('./examples/RootViewSizeFlexibilityExample/RootViewSizeFlexibilityExampleApp'),
|
||||
// );
|
||||
// Windows]
|
||||
import RNTesterApp from './RNTesterAppShared';
|
||||
|
||||
AppRegistry.registerComponent('RNTesterApp', () => RNTesterApp);
|
||||
|
||||
// [Windows
|
||||
// // Register suitable examples for snapshot tests
|
||||
// RNTesterList.ComponentExamples.concat(RNTesterList.APIExamples).forEach(
|
||||
// (Example: RNTesterExample) => {
|
||||
// const ExampleModule = Example.module;
|
||||
// if (ExampleModule.displayName) {
|
||||
// class Snapshotter extends React.Component<{...}> {
|
||||
// render() {
|
||||
// return (
|
||||
// <SnapshotViewIOS>
|
||||
// <RNTesterExampleContainer module={ExampleModule} />
|
||||
// </SnapshotViewIOS>
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
// AppRegistry.registerComponent(
|
||||
// ExampleModule.displayName,
|
||||
// () => Snapshotter,
|
||||
// );
|
||||
// }
|
||||
// },
|
||||
// );
|
||||
// Windows]
|
||||
|
||||
module.exports = RNTesterApp;
|
||||
|
|
|
@ -0,0 +1,251 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and 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 {
|
||||
BackHandler,
|
||||
StyleSheet,
|
||||
useColorScheme,
|
||||
View,
|
||||
LogBox,
|
||||
} from 'react-native';
|
||||
import * as React from 'react';
|
||||
|
||||
import RNTesterExampleContainer from './components/RNTesterExampleContainer';
|
||||
import RNTesterExampleList from './components/RNTesterExampleList';
|
||||
import RNTesterNavBar from './components/RNTesterNavbar';
|
||||
import RNTesterList from './utils/RNTesterList';
|
||||
import {
|
||||
Screens,
|
||||
initialState,
|
||||
getExamplesListWithBookmarksAndRecentlyUsed,
|
||||
getInitialStateFromAsyncStorage,
|
||||
} from './utils/testerStateUtils';
|
||||
import {useAsyncStorageReducer} from './utils/useAsyncStorageReducer';
|
||||
import {RNTesterReducer, RNTesterActionsType} from './utils/RNTesterReducer';
|
||||
import {RNTesterThemeContext, themes} from './components/RNTesterTheme';
|
||||
import {Header} from './components/RNTesterHeader';
|
||||
import {RNTesterEmptyBookmarksState} from './components/RNTesterEmptyBookmarksState';
|
||||
|
||||
import type {RNTesterTheme} from './components/RNTesterTheme';
|
||||
import type {ExamplesList} from './types/RNTesterTypes';
|
||||
|
||||
const APP_STATE_KEY = 'RNTesterAppState.v3';
|
||||
|
||||
// RNTester App currently uses AsyncStorage from react-native for storing navigation state
|
||||
// and bookmark items.
|
||||
// TODO: Vendor AsyncStorage or create our own.
|
||||
LogBox.ignoreLogs([/AsyncStorage has been extracted from react-native/]);
|
||||
|
||||
// [Windows #6355 The existing code used isVisible to control style and render
|
||||
// components with display: none. Windows will currently still propagate an
|
||||
// insvisible tree to UIA, leading to multiple components in the tree with the
|
||||
// same testId. Avoid rendering invisible trees instead.
|
||||
const DisplayIfVisible = ({isVisible, children}) => {
|
||||
if (isVisible) {
|
||||
return <View style={[styles.container]}>{children}</View>;
|
||||
} else {
|
||||
return <></>;
|
||||
}
|
||||
};
|
||||
// Windows]
|
||||
|
||||
type ExampleListsContainerProps = $ReadOnly<{|
|
||||
theme: RNTesterTheme,
|
||||
screen: string,
|
||||
title: string,
|
||||
examplesList: ExamplesList,
|
||||
toggleBookmark: (args: {exampleType: string, key: string}) => mixed,
|
||||
handleExampleCardPress: (args: {exampleType: string, key: string}) => mixed,
|
||||
isVisible: boolean,
|
||||
|}>;
|
||||
|
||||
const ExampleListsContainer = ({
|
||||
theme,
|
||||
screen,
|
||||
title,
|
||||
examplesList,
|
||||
toggleBookmark,
|
||||
handleExampleCardPress,
|
||||
isVisible,
|
||||
}: ExampleListsContainerProps) => {
|
||||
const isBookmarkEmpty = examplesList.bookmarks.length === 0;
|
||||
|
||||
return (
|
||||
<DisplayIfVisible isVisible={isVisible}>
|
||||
<Header title={title} theme={theme} />
|
||||
<DisplayIfVisible isVisible={screen === Screens.COMPONENTS}>
|
||||
<RNTesterExampleList
|
||||
sections={examplesList.components}
|
||||
toggleBookmark={toggleBookmark}
|
||||
handleExampleCardPress={handleExampleCardPress}
|
||||
/>
|
||||
</DisplayIfVisible>
|
||||
<DisplayIfVisible isVisible={screen === Screens.APIS}>
|
||||
<RNTesterExampleList
|
||||
sections={examplesList.apis}
|
||||
toggleBookmark={toggleBookmark}
|
||||
handleExampleCardPress={handleExampleCardPress}
|
||||
/>
|
||||
</DisplayIfVisible>
|
||||
<DisplayIfVisible isVisible={screen === Screens.BOOKMARKS}>
|
||||
{isBookmarkEmpty ? (
|
||||
<RNTesterEmptyBookmarksState />
|
||||
) : (
|
||||
<RNTesterExampleList
|
||||
sections={examplesList.bookmarks}
|
||||
toggleBookmark={toggleBookmark}
|
||||
handleExampleCardPress={handleExampleCardPress}
|
||||
/>
|
||||
)}
|
||||
</DisplayIfVisible>
|
||||
</DisplayIfVisible>
|
||||
);
|
||||
};
|
||||
|
||||
const RNTesterApp = (): React.Node => {
|
||||
const [state, dispatch] = useAsyncStorageReducer(
|
||||
RNTesterReducer,
|
||||
initialState,
|
||||
APP_STATE_KEY,
|
||||
);
|
||||
const colorScheme = useColorScheme();
|
||||
|
||||
const {openExample, screen, bookmarks, recentlyUsed} = state;
|
||||
|
||||
React.useEffect(() => {
|
||||
getInitialStateFromAsyncStorage(APP_STATE_KEY).then(
|
||||
initialStateFromStorage => {
|
||||
dispatch({
|
||||
type: RNTesterActionsType.INIT_FROM_STORAGE,
|
||||
data: initialStateFromStorage,
|
||||
});
|
||||
},
|
||||
);
|
||||
}, [dispatch]);
|
||||
|
||||
const examplesList = React.useMemo(
|
||||
() =>
|
||||
getExamplesListWithBookmarksAndRecentlyUsed({bookmarks, recentlyUsed}),
|
||||
[bookmarks, recentlyUsed],
|
||||
);
|
||||
|
||||
const handleBackPress = React.useCallback(() => {
|
||||
if (openExample) {
|
||||
dispatch({type: RNTesterActionsType.BACK_BUTTON_PRESS});
|
||||
}
|
||||
}, [dispatch, openExample]);
|
||||
|
||||
// Setup hardware back button press listener
|
||||
React.useEffect(() => {
|
||||
BackHandler.addEventListener('hardwareBackPress', () => {
|
||||
if (openExample) {
|
||||
handleBackPress();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}, [openExample, handleBackPress]);
|
||||
|
||||
const handleExampleCardPress = React.useCallback(
|
||||
({exampleType, key}) => {
|
||||
dispatch({
|
||||
type: RNTesterActionsType.EXAMPLE_CARD_PRESS,
|
||||
data: {exampleType, key},
|
||||
});
|
||||
},
|
||||
[dispatch],
|
||||
);
|
||||
|
||||
const toggleBookmark = React.useCallback(
|
||||
({exampleType, key}) => {
|
||||
dispatch({
|
||||
type: RNTesterActionsType.BOOKMARK_PRESS,
|
||||
data: {exampleType, key},
|
||||
});
|
||||
},
|
||||
[dispatch],
|
||||
);
|
||||
|
||||
const handleNavBarPress = React.useCallback(
|
||||
args => {
|
||||
dispatch({
|
||||
type: RNTesterActionsType.NAVBAR_PRESS,
|
||||
data: {screen: args.screen},
|
||||
});
|
||||
},
|
||||
[dispatch],
|
||||
);
|
||||
|
||||
const theme = colorScheme === 'dark' ? themes.dark : themes.light;
|
||||
|
||||
if (examplesList === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const ExampleModule = openExample && RNTesterList.Modules[openExample];
|
||||
const title = Screens.COMPONENTS
|
||||
? 'Components'
|
||||
: Screens.APIS
|
||||
? 'APIs'
|
||||
: 'Bookmarks';
|
||||
|
||||
return (
|
||||
<RNTesterThemeContext.Provider value={theme}>
|
||||
{ExampleModule && (
|
||||
<View style={styles.container}>
|
||||
<Header
|
||||
onBack={handleBackPress}
|
||||
title={title}
|
||||
theme={theme}
|
||||
documentationURL={ExampleModule.documentationURL}
|
||||
/>
|
||||
<RNTesterExampleContainer module={ExampleModule} />
|
||||
</View>
|
||||
)}
|
||||
|
||||
<ExampleListsContainer
|
||||
isVisible={!ExampleModule}
|
||||
screen={screen || Screens.COMPONENTS}
|
||||
title={title}
|
||||
theme={theme}
|
||||
examplesList={examplesList}
|
||||
handleExampleCardPress={handleExampleCardPress}
|
||||
toggleBookmark={toggleBookmark}
|
||||
/>
|
||||
<View style={styles.bottomNavbar}>
|
||||
<RNTesterNavBar
|
||||
screen={screen || Screens.COMPONENTS}
|
||||
isExamplePageOpen={!!ExampleModule}
|
||||
handleNavBarPress={handleNavBarPress}
|
||||
/>
|
||||
</View>
|
||||
</RNTesterThemeContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export default RNTesterApp;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
bottomNavbar: {
|
||||
bottom: 0,
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
position: 'absolute',
|
||||
},
|
||||
hidden: {
|
||||
display: 'none',
|
||||
},
|
||||
});
|
|
@ -0,0 +1,64 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and 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 * as React from 'react';
|
||||
import {View, Image, Text, StyleSheet} from 'react-native';
|
||||
|
||||
export const RNTesterEmptyBookmarksState = (): React.Node => (
|
||||
<View style={styles.emptyContainer}>
|
||||
<View style={styles.emptyContainerInner}>
|
||||
<Image
|
||||
source={require('../assets/empty.png')}
|
||||
resizeMode="contain"
|
||||
style={styles.emptyImage}
|
||||
/>
|
||||
<View>
|
||||
<Text style={styles.heading}>Bookmarks are empty</Text>
|
||||
<Text style={styles.subheading}>
|
||||
Please tap the{' '}
|
||||
{/* [Win32] remove the image since nested non-Text in text is unsupported in NetUI*/}
|
||||
icon to bookmark examples.
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
emptyContainer: {
|
||||
flex: 1,
|
||||
paddingHorizontal: 40,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: 'white',
|
||||
},
|
||||
emptyContainerInner: {
|
||||
marginTop: -150,
|
||||
},
|
||||
emptyImage: {
|
||||
maxWidth: '100%',
|
||||
height: 300,
|
||||
},
|
||||
heading: {
|
||||
fontSize: 24,
|
||||
textAlign: 'center',
|
||||
},
|
||||
subheading: {
|
||||
fontSize: 16,
|
||||
textAlign: 'center',
|
||||
},
|
||||
bookmarkIcon: {
|
||||
width: 24,
|
||||
height: 24,
|
||||
transform: [{translateY: 4}],
|
||||
},
|
||||
});
|
|
@ -9,9 +9,7 @@
|
|||
*/
|
||||
|
||||
'use strict';
|
||||
import type {RNTesterBookmark} from './RNTesterBookmark.js';
|
||||
|
||||
const RNTesterActions = require('../utils/RNTesterActions');
|
||||
const RNTesterExampleFilter = require('./RNTesterExampleFilter');
|
||||
const RNTesterComponentTitle = require('./RNTesterComponentTitle');
|
||||
const React = require('react');
|
||||
|
@ -26,173 +24,83 @@ const {
|
|||
View,
|
||||
} = require('react-native');
|
||||
|
||||
import type {ViewStyleProp} from '../../../Libraries/StyleSheet/StyleSheet';
|
||||
import type {RNTesterExample} from '../types/RNTesterTypes';
|
||||
import {RNTesterThemeContext} from './RNTesterTheme';
|
||||
import {RNTesterBookmarkContext} from './RNTesterBookmark';
|
||||
|
||||
type Props = {
|
||||
screen: string,
|
||||
onNavigate: Function,
|
||||
updateRecentlyViewedList: Function,
|
||||
recentApis: Array<RNTesterExample>,
|
||||
recentComponents: Array<RNTesterExample>,
|
||||
list: {
|
||||
ComponentExamples: Array<RNTesterExample>,
|
||||
APIExamples: Array<RNTesterExample>,
|
||||
...
|
||||
},
|
||||
style?: ?ViewStyleProp,
|
||||
...
|
||||
};
|
||||
|
||||
type State = {
|
||||
components: Array<RNTesterExample>,
|
||||
api: Array<RNTesterExample>,
|
||||
recentComponents: Array<RNTesterExample>,
|
||||
recentApis: Array<RNTesterExample>,
|
||||
updateRecentlyViewedList: Function,
|
||||
};
|
||||
|
||||
type ButtonState = {active: boolean, key: string, ...};
|
||||
type ButtonProps = {
|
||||
item: Object,
|
||||
section: Object,
|
||||
active: boolean,
|
||||
onNavigate: Function,
|
||||
onPress?: Function,
|
||||
onShowUnderlay?: Function,
|
||||
onHideUnderlay?: Function,
|
||||
updateRecentlyViewedList: Function,
|
||||
...
|
||||
};
|
||||
|
||||
class RowComponent extends React.PureComponent<ButtonProps, ButtonState> {
|
||||
static contextType = RNTesterBookmarkContext;
|
||||
|
||||
constructor(props: ButtonProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
active: props.active,
|
||||
title: props.item.module.title,
|
||||
key: props.section.key,
|
||||
};
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps(nextProps, prevState) {
|
||||
if (nextProps.active !== prevState.active) {
|
||||
return {active: nextProps.active};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
onButtonPress = () => {
|
||||
let bookmark = this.context;
|
||||
if (!this.state.active) {
|
||||
if (this.state.key === 'APIS' || this.state.key === 'RECENT_APIS') {
|
||||
bookmark.AddApi(this.props.item.module.title, this.props.item);
|
||||
} else {
|
||||
bookmark.AddComponent(this.props.item.module.title, this.props.item);
|
||||
}
|
||||
} else {
|
||||
if (this.state.key === 'APIS' || this.state.key === 'RECENT_APIS') {
|
||||
bookmark.RemoveApi(this.props.item.module.title);
|
||||
} else {
|
||||
bookmark.RemoveComponent(this.props.item.module.title);
|
||||
}
|
||||
}
|
||||
this.setState({
|
||||
active: !this.state.active,
|
||||
});
|
||||
};
|
||||
|
||||
_onPress = () => {
|
||||
this.props.updateRecentlyViewedList();
|
||||
if (this.props.onPress) {
|
||||
this.props.onPress();
|
||||
return;
|
||||
}
|
||||
this.props.onNavigate(RNTesterActions.ExampleAction(this.props.item.key));
|
||||
};
|
||||
render() {
|
||||
const {item} = this.props;
|
||||
const platform = item.module.platform;
|
||||
const onIos = !platform || platform === 'ios';
|
||||
const onAndroid = !platform || platform === 'android';
|
||||
return (
|
||||
<RNTesterThemeContext.Consumer>
|
||||
{theme => {
|
||||
return (
|
||||
<TouchableHighlight
|
||||
// [Windows Add testID for e2etest
|
||||
testID={item.module.title}
|
||||
// Windows]
|
||||
onShowUnderlay={this.props.onShowUnderlay}
|
||||
onHideUnderlay={this.props.onHideUnderlay}
|
||||
accessibilityLabel={
|
||||
item.module.title + ' ' + item.module.description
|
||||
const ExampleCard = ({
|
||||
onShowUnderlay,
|
||||
onHideUnderlay,
|
||||
item,
|
||||
toggleBookmark,
|
||||
handlePress,
|
||||
}) => {
|
||||
const theme = React.useContext(RNTesterThemeContext);
|
||||
const platform = item.module.platform;
|
||||
const onIos = !platform || platform === 'ios';
|
||||
const onAndroid = !platform || platform === 'android';
|
||||
return (
|
||||
<TouchableHighlight
|
||||
// [Windows Add testID for e2etest
|
||||
testID={item.module.title}
|
||||
// Windows]
|
||||
onShowUnderlay={onShowUnderlay}
|
||||
onHideUnderlay={onHideUnderlay}
|
||||
accessibilityLabel={item.module.title + ' ' + item.module.description}
|
||||
style={styles.listItem}
|
||||
underlayColor={'rgb(242,242,242)'}
|
||||
onPress={() =>
|
||||
handlePress({exampleType: item.exampleType, key: item.key})
|
||||
}>
|
||||
<View
|
||||
style={[styles.row, {backgroundColor: theme.SystemBackgroundColor}]}>
|
||||
<View style={styles.topRowStyle}>
|
||||
<RNTesterComponentTitle>{item.module.title}</RNTesterComponentTitle>
|
||||
<TouchableHighlight
|
||||
style={styles.imageViewStyle}
|
||||
onPress={() =>
|
||||
toggleBookmark({exampleType: item.exampleType, key: item.key})
|
||||
}>
|
||||
<Image
|
||||
style={styles.imageStyle}
|
||||
source={
|
||||
item.isBookmarked
|
||||
? require('../assets/bookmark-outline-blue.png')
|
||||
: require('../assets/bookmark-outline-gray.png')
|
||||
}
|
||||
style={styles.listItem}
|
||||
underlayColor={'rgb(242,242,242)'}
|
||||
onPress={this._onPress}>
|
||||
<View
|
||||
style={[
|
||||
styles.row,
|
||||
{backgroundColor: theme.SystemBackgroundColor},
|
||||
]}>
|
||||
<View style={styles.topRowStyle}>
|
||||
<RNTesterComponentTitle>
|
||||
{item.module.title}
|
||||
</RNTesterComponentTitle>
|
||||
<TouchableHighlight
|
||||
style={styles.imageViewStyle}
|
||||
onPress={() => this.onButtonPress()}>
|
||||
<Image
|
||||
style={styles.imageStyle}
|
||||
source={
|
||||
this.state.active
|
||||
? require('../assets/bookmark-outline-blue.png')
|
||||
: require('../assets/bookmark-outline-gray.png')
|
||||
}
|
||||
/>
|
||||
</TouchableHighlight>
|
||||
</View>
|
||||
<Text
|
||||
style={[
|
||||
styles.rowDetailText,
|
||||
{color: theme.SecondaryLabelColor, marginBottom: 5},
|
||||
]}>
|
||||
{item.module.description}
|
||||
</Text>
|
||||
<View style={styles.bottomRowStyle}>
|
||||
<Text style={{color: theme.SecondaryLabelColor, width: 65}}>
|
||||
{item.module.category || 'Other'}
|
||||
</Text>
|
||||
<View style={styles.platformLabelStyle}>
|
||||
<Text
|
||||
style={{
|
||||
color: onIos ? '#787878' : theme.SeparatorColor,
|
||||
fontWeight: onIos ? '500' : '300',
|
||||
}}>
|
||||
iOS
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
color: onAndroid ? '#787878' : theme.SeparatorColor,
|
||||
fontWeight: onAndroid ? '500' : '300',
|
||||
}}>
|
||||
Android
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
);
|
||||
}}
|
||||
</RNTesterThemeContext.Consumer>
|
||||
);
|
||||
}
|
||||
}
|
||||
/>
|
||||
</TouchableHighlight>
|
||||
</View>
|
||||
<Text
|
||||
style={[
|
||||
styles.rowDetailText,
|
||||
{color: theme.SecondaryLabelColor, marginBottom: 5},
|
||||
]}>
|
||||
{item.module.description}
|
||||
</Text>
|
||||
<View style={styles.bottomRowStyle}>
|
||||
<Text style={{color: theme.SecondaryLabelColor, width: 65}}>
|
||||
{item.module.category || 'Other'}
|
||||
</Text>
|
||||
<View style={styles.platformLabelStyle}>
|
||||
<Text
|
||||
style={{
|
||||
color: onIos ? '#787878' : theme.SeparatorColor,
|
||||
fontWeight: onIos ? '500' : '300',
|
||||
}}>
|
||||
iOS
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
color: onAndroid ? '#787878' : theme.SeparatorColor,
|
||||
fontWeight: onAndroid ? '500' : '300',
|
||||
}}>
|
||||
Android
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
);
|
||||
};
|
||||
|
||||
const renderSectionHeader = ({section}) => (
|
||||
<RNTesterThemeContext.Consumer>
|
||||
|
@ -213,176 +121,57 @@ const renderSectionHeader = ({section}) => (
|
|||
</RNTesterThemeContext.Consumer>
|
||||
);
|
||||
|
||||
class RNTesterExampleList extends React.Component<Props, State> {
|
||||
static contextType: React.Context<RNTesterBookmark> = RNTesterBookmarkContext;
|
||||
const RNTesterExampleList: React$AbstractComponent<any, void> = React.memo(
|
||||
({sections, toggleBookmark, handleExampleCardPress}) => {
|
||||
const theme = React.useContext(RNTesterThemeContext);
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
components: props.list.ComponentExamples,
|
||||
api: props.list.APIExamples,
|
||||
recentComponents: props.recentComponents,
|
||||
recentApis: props.recentApis,
|
||||
updateRecentlyViewedList: (item, key) =>
|
||||
props.updateRecentlyViewedList(item, key),
|
||||
};
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps(nextProps: Props, prevState: State): State {
|
||||
if (
|
||||
nextProps.recentComponents.every(
|
||||
(component, index) => component !== prevState.recentComponents[index],
|
||||
) &&
|
||||
nextProps.recentApis.every(
|
||||
(api, index) => api !== prevState.recentApis[index],
|
||||
)
|
||||
) {
|
||||
return {
|
||||
...prevState,
|
||||
recentComponents: nextProps.recentComponents,
|
||||
recentApis: nextProps.recentApis,
|
||||
};
|
||||
}
|
||||
return prevState;
|
||||
}
|
||||
|
||||
render(): React.Node {
|
||||
const bookmark = this.context;
|
||||
const filter = ({example, filterRegex, category}) =>
|
||||
filterRegex.test(example.module.title) &&
|
||||
(!category || example.module.category === category) &&
|
||||
(!category || example.category === category) &&
|
||||
(!Platform.isTV || example.supportsTVOS);
|
||||
|
||||
const {screen} = this.props;
|
||||
let sections = [];
|
||||
|
||||
if (screen === 'component') {
|
||||
if (this.state.recentComponents.length > 0) {
|
||||
sections = [
|
||||
{
|
||||
data: this.state.recentComponents,
|
||||
key: 'RECENT_COMPONENTS',
|
||||
title: 'Recently viewed',
|
||||
},
|
||||
{
|
||||
data: this.state.components,
|
||||
key: 'COMPONENTS',
|
||||
title: 'Components',
|
||||
},
|
||||
];
|
||||
} else {
|
||||
sections = [
|
||||
{
|
||||
data: this.state.components,
|
||||
key: 'COMPONENTS',
|
||||
title: 'Components',
|
||||
},
|
||||
];
|
||||
}
|
||||
} else if (screen === 'api') {
|
||||
if (this.state.recentApis.length > 0) {
|
||||
sections = [
|
||||
{
|
||||
data: this.state.recentApis,
|
||||
key: 'RECENT_APIS',
|
||||
title: 'Recently viewed',
|
||||
},
|
||||
{
|
||||
data: this.state.api,
|
||||
key: 'APIS',
|
||||
title: 'APIS',
|
||||
},
|
||||
];
|
||||
} else {
|
||||
sections = [
|
||||
{
|
||||
data: this.state.api,
|
||||
key: 'APIS',
|
||||
title: 'APIS',
|
||||
},
|
||||
];
|
||||
}
|
||||
} else if (screen === 'bookmark') {
|
||||
sections = [
|
||||
{
|
||||
data: Object.values(bookmark.Components),
|
||||
title: 'COMPONENTS',
|
||||
key: 'COMPONENTS',
|
||||
},
|
||||
{
|
||||
data: Object.values(bookmark.Api),
|
||||
title: 'APIS',
|
||||
key: 'APIS',
|
||||
},
|
||||
];
|
||||
} else {
|
||||
sections = [];
|
||||
}
|
||||
|
||||
const isEmpty = sections.filter(s => s.data.length).length === 0;
|
||||
|
||||
if (isEmpty) {
|
||||
return <EmptyState />;
|
||||
}
|
||||
const renderListItem = ({item, section, separators}) => {
|
||||
return (
|
||||
<ExampleCard
|
||||
item={item}
|
||||
section={section}
|
||||
onShowUnderlay={separators.highlight}
|
||||
onHideUnderlay={separators.unhighlight}
|
||||
toggleBookmark={toggleBookmark}
|
||||
handlePress={handleExampleCardPress}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<RNTesterThemeContext.Consumer>
|
||||
{theme => {
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
styles.listContainer,
|
||||
this.props.style,
|
||||
{backgroundColor: theme.SecondaryGroupedBackgroundColor},
|
||||
]}>
|
||||
<RNTesterExampleFilter
|
||||
testID="explorer_search"
|
||||
page="components_page"
|
||||
// $FlowFixMe
|
||||
sections={sections}
|
||||
filter={filter}
|
||||
render={({filteredSections}) => (
|
||||
<SectionList
|
||||
sections={filteredSections}
|
||||
extraData={filteredSections}
|
||||
renderItem={this._renderItem}
|
||||
ItemSeparatorComponent={ItemSeparator}
|
||||
keyboardShouldPersistTaps="handled"
|
||||
automaticallyAdjustContentInsets={false}
|
||||
keyboardDismissMode="on-drag"
|
||||
renderSectionHeader={renderSectionHeader}
|
||||
ListFooterComponent={() => <View style={{height: 200}} />}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}}
|
||||
</RNTesterThemeContext.Consumer>
|
||||
<View
|
||||
style={[
|
||||
styles.listContainer,
|
||||
{backgroundColor: theme.SecondaryGroupedBackgroundColor},
|
||||
]}>
|
||||
<RNTesterExampleFilter
|
||||
testID="explorer_search"
|
||||
page="components_page"
|
||||
sections={sections}
|
||||
filter={filter}
|
||||
render={({filteredSections}) => (
|
||||
<SectionList
|
||||
sections={filteredSections}
|
||||
extraData={filteredSections}
|
||||
renderItem={renderListItem}
|
||||
ItemSeparatorComponent={ItemSeparator}
|
||||
keyboardShouldPersistTaps="handled"
|
||||
automaticallyAdjustContentInsets={false}
|
||||
keyboardDismissMode="on-drag"
|
||||
renderSectionHeader={renderSectionHeader}
|
||||
ListFooterComponent={() => <View style={{height: 80}} />}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_renderItem = ({item, section, separators, index}) => {
|
||||
let bookmark = this.context;
|
||||
return (
|
||||
<RowComponent
|
||||
item={item}
|
||||
section={section}
|
||||
active={!bookmark.checkBookmark(item.module.title, section.key)}
|
||||
onNavigate={this.props.onNavigate}
|
||||
onShowUnderlay={separators.highlight}
|
||||
onHideUnderlay={separators.unhighlight}
|
||||
updateRecentlyViewedList={() =>
|
||||
this.state.updateRecentlyViewedList(item, section.key)
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
_handleRowPress(exampleKey: string): void {
|
||||
this.props.onNavigate(RNTesterActions.ExampleAction(exampleKey));
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const ItemSeparator = ({highlighted}) => (
|
||||
<RNTesterThemeContext.Consumer>
|
||||
|
@ -403,26 +192,6 @@ const ItemSeparator = ({highlighted}) => (
|
|||
</RNTesterThemeContext.Consumer>
|
||||
);
|
||||
|
||||
const EmptyState = () => (
|
||||
<View style={styles.emptyContainer}>
|
||||
<View style={styles.emptyContainerInner}>
|
||||
<Image
|
||||
source={require('../assets/empty.png')}
|
||||
resizeMode="contain"
|
||||
style={styles.emptyImage}
|
||||
/>
|
||||
<View>
|
||||
<Text style={styles.heading}>Bookmarks are empty</Text>
|
||||
<Text style={styles.subheading}>
|
||||
{/* [Windows replace Bookmark inline image with text Bookmark */}
|
||||
Please tap the Bookmark icon to bookmark examples.
|
||||
{/* Windows] */}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
listContainer: {
|
||||
flex: 1,
|
||||
|
@ -482,33 +251,6 @@ const styles = StyleSheet.create({
|
|||
width: 100,
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
emptyContainer: {
|
||||
flex: 1,
|
||||
paddingHorizontal: 40,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: 'white',
|
||||
},
|
||||
emptyContainerInner: {
|
||||
marginTop: -150,
|
||||
},
|
||||
emptyImage: {
|
||||
maxWidth: '100%',
|
||||
height: 300,
|
||||
},
|
||||
heading: {
|
||||
fontSize: 24,
|
||||
textAlign: 'center',
|
||||
},
|
||||
subheading: {
|
||||
fontSize: 16,
|
||||
textAlign: 'center',
|
||||
},
|
||||
bookmarkIcon: {
|
||||
width: 24,
|
||||
height: 24,
|
||||
transform: [{translateY: 4}],
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = RNTesterExampleList;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"baseVersion": "0.0.0-5bc67b658",
|
||||
"baseVersion": "0.0.0-f0e80ae22",
|
||||
"overrides": [
|
||||
{
|
||||
"type": "copy",
|
||||
|
|
|
@ -10,331 +10,9 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const RNTesterActions = require('./utils/RNTesterActions');
|
||||
const RNTesterExampleContainer = require('./components/RNTesterExampleContainer');
|
||||
const RNTesterExampleList = require('./components/RNTesterExampleList');
|
||||
const RNTesterList = require('./utils/RNTesterList');
|
||||
const RNTesterNavigationReducer = require('./utils/RNTesterNavigationReducer');
|
||||
const React = require('react');
|
||||
const RNTesterNavBar = require('./components/RNTesterNavbar');
|
||||
import {AppRegistry} from 'react-native';
|
||||
|
||||
const {
|
||||
AppRegistry,
|
||||
AsyncStorage,
|
||||
BackHandler,
|
||||
StyleSheet,
|
||||
Text,
|
||||
UIManager,
|
||||
useColorScheme,
|
||||
View,
|
||||
LogBox,
|
||||
} = require('react-native');
|
||||
|
||||
import type {RNTesterExample} from './types/RNTesterTypes';
|
||||
import type {RNTesterNavigationState} from './utils/RNTesterNavigationReducer';
|
||||
import {RNTesterThemeContext, themes} from './components/RNTesterTheme';
|
||||
import RNTesterDocumentationURL from './components/RNTesterDocumentationURL';
|
||||
import {
|
||||
RNTesterBookmarkContext,
|
||||
bookmarks,
|
||||
} from './components/RNTesterBookmark';
|
||||
import type {RNTesterBookmark} from './components/RNTesterBookmark';
|
||||
|
||||
import {
|
||||
initializeAsyncStore,
|
||||
addApi,
|
||||
addComponent,
|
||||
removeApi,
|
||||
removeComponent,
|
||||
checkBookmarks,
|
||||
updateRecentlyViewedList,
|
||||
} from './utils/RNTesterAsyncStorageAbstraction';
|
||||
|
||||
UIManager.setLayoutAnimationEnabledExperimental &&
|
||||
UIManager.setLayoutAnimationEnabledExperimental(true);
|
||||
|
||||
type Props = {exampleFromAppetizeParams?: ?string, ...};
|
||||
|
||||
const APP_STATE_KEY = 'RNTesterAppState.v2';
|
||||
|
||||
const Header = ({
|
||||
title,
|
||||
documentationURL,
|
||||
}: {
|
||||
title: string,
|
||||
documentationURL?: string,
|
||||
...
|
||||
}) => (
|
||||
<RNTesterThemeContext.Consumer>
|
||||
{theme => {
|
||||
return (
|
||||
<View style={[styles.toolbar, {backgroundColor: '#F3F8FF'}]}>
|
||||
<View style={styles.toolbarCenter}>
|
||||
<Text style={[styles.title, {color: theme.LabelColor}]}>
|
||||
{title}
|
||||
</Text>
|
||||
{documentationURL && (
|
||||
<RNTesterDocumentationURL documentationURL={documentationURL} />
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}}
|
||||
</RNTesterThemeContext.Consumer>
|
||||
);
|
||||
|
||||
const RNTesterExampleContainerViaHook = ({
|
||||
title,
|
||||
module,
|
||||
exampleRef,
|
||||
}: {
|
||||
title: string,
|
||||
module: RNTesterExample,
|
||||
exampleRef: () => void,
|
||||
...
|
||||
}) => {
|
||||
const colorScheme = useColorScheme();
|
||||
const theme = colorScheme === 'dark' ? themes.dark : themes.light;
|
||||
return (
|
||||
<RNTesterThemeContext.Provider value={theme}>
|
||||
<View style={styles.container}>
|
||||
<Header title={title} documentationURL={module.documentationURL} />
|
||||
<RNTesterExampleContainer module={module} ref={exampleRef} />
|
||||
</View>
|
||||
</RNTesterThemeContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
const RNTesterExampleListViaHook = ({
|
||||
title,
|
||||
onNavigate,
|
||||
UpdateRecentlyViewedList,
|
||||
recentComponents,
|
||||
recentApis,
|
||||
bookmark,
|
||||
list,
|
||||
screen,
|
||||
}: {
|
||||
title: string,
|
||||
screen: string,
|
||||
onNavigate?: () => mixed,
|
||||
UpdateRecentlyViewedList?: (item: RNTesterExample, key: string) => mixed,
|
||||
recentComponents: Array<RNTesterExample>,
|
||||
recentApis: Array<RNTesterExample>,
|
||||
list: {
|
||||
ComponentExamples: Array<RNTesterExample>,
|
||||
APIExamples: Array<RNTesterExample>,
|
||||
...
|
||||
},
|
||||
bookmark: RNTesterBookmark,
|
||||
...
|
||||
}) => {
|
||||
const colorScheme = useColorScheme();
|
||||
const theme = colorScheme === 'dark' ? themes.dark : themes.light;
|
||||
const exampleTitle =
|
||||
screen === 'component'
|
||||
? 'Component Store'
|
||||
: screen === 'api'
|
||||
? 'API Store'
|
||||
: 'Bookmarks';
|
||||
return (
|
||||
<RNTesterThemeContext.Provider value={theme}>
|
||||
<RNTesterBookmarkContext.Provider value={bookmark}>
|
||||
<View style={styles.container}>
|
||||
<Header title={exampleTitle} />
|
||||
<RNTesterExampleList
|
||||
onNavigate={onNavigate}
|
||||
recentComponents={recentComponents}
|
||||
recentApis={recentApis}
|
||||
updateRecentlyViewedList={UpdateRecentlyViewedList}
|
||||
list={list}
|
||||
screen={screen}
|
||||
/>
|
||||
</View>
|
||||
</RNTesterBookmarkContext.Provider>
|
||||
</RNTesterThemeContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
class RNTesterApp extends React.Component<Props, RNTesterNavigationState> {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
// RNTester App currently uses Async Storage from react-native for storing navigation state
|
||||
// and bookmark items.
|
||||
// TODO: Add Native Async Storage Module in RNTester
|
||||
LogBox.ignoreLogs([new RegExp('has been extracted from react-native')]);
|
||||
|
||||
this.state = {
|
||||
openExample: null,
|
||||
Components: bookmarks.Components,
|
||||
Api: bookmarks.Api,
|
||||
recentComponents: [],
|
||||
recentApis: [],
|
||||
screen: 'component',
|
||||
AddApi: (apiName, api) => addApi(apiName, api, this),
|
||||
AddComponent: (componentName, component) =>
|
||||
addComponent(componentName, component, this),
|
||||
RemoveApi: apiName => removeApi(apiName, this),
|
||||
RemoveComponent: componentName => removeComponent(componentName, this),
|
||||
checkBookmark: (title, key) => checkBookmarks(title, key, this),
|
||||
updateRecentlyViewedList: (item, key) =>
|
||||
updateRecentlyViewedList(item, key, this),
|
||||
};
|
||||
}
|
||||
UNSAFE_componentWillMount() {
|
||||
BackHandler.addEventListener('hardwareBackPress', () =>
|
||||
this._handleBackButtonPress(this.state.screen),
|
||||
);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
initializeAsyncStore(this);
|
||||
}
|
||||
|
||||
render(): React.Node {
|
||||
if (!this.state) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
{this._renderApp({
|
||||
Components: this.state.Components,
|
||||
Api: this.state.Api,
|
||||
AddApi: this.state.AddApi,
|
||||
AddComponent: this.state.AddComponent,
|
||||
RemoveApi: this.state.RemoveApi,
|
||||
RemoveComponent: this.state.RemoveComponent,
|
||||
checkBookmark: this.state.checkBookmark,
|
||||
})}
|
||||
<View style={styles.bottomNavbar}>
|
||||
<RNTesterNavBar
|
||||
screen={this.state.screen}
|
||||
onNavigate={this._handleAction}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_renderApp(bookmark) {
|
||||
const {openExample, screen} = this.state;
|
||||
|
||||
if (openExample) {
|
||||
const ExampleModule = RNTesterList.Modules[openExample];
|
||||
if (ExampleModule.external) {
|
||||
return (
|
||||
<ExampleModule
|
||||
onExampleExit={() => {
|
||||
this._handleAction(RNTesterActions.Back(screen));
|
||||
}}
|
||||
ref={example => {
|
||||
/* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue
|
||||
* was found when making Flow check .android.js files. */
|
||||
this._exampleRef = example;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
} else if (ExampleModule) {
|
||||
return (
|
||||
<>
|
||||
<RNTesterExampleContainerViaHook
|
||||
/* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
|
||||
* when making Flow check .android.js files. */
|
||||
title={ExampleModule.title}
|
||||
module={ExampleModule}
|
||||
exampleRef={example => {
|
||||
/* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue
|
||||
* was found when making Flow check .android.js files. */
|
||||
this._exampleRef = example;
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<RNTesterExampleListViaHook
|
||||
key={screen}
|
||||
title={'RNTester'}
|
||||
/* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
|
||||
* when making Flow check .android.js files. */
|
||||
onNavigate={this._handleAction}
|
||||
UpdateRecentlyViewedList={this.state.updateRecentlyViewedList}
|
||||
recentComponents={this.state.recentComponents}
|
||||
recentApis={this.state.recentApis}
|
||||
bookmark={bookmark}
|
||||
list={RNTesterList}
|
||||
screen={screen}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
_handleAction = (action: Object): boolean => {
|
||||
/* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
|
||||
* when making Flow check .android.js files. */
|
||||
const newState = RNTesterNavigationReducer(this.state, action);
|
||||
if (this.state !== newState) {
|
||||
this.setState(newState, () =>
|
||||
AsyncStorage.setItem(APP_STATE_KEY, JSON.stringify(this.state)),
|
||||
);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
_handleBackButtonPress = screen => {
|
||||
/* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
|
||||
* when making Flow check .android.js files. */
|
||||
if (
|
||||
/* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
|
||||
* when making Flow check .android.js files. */
|
||||
this._exampleRef &&
|
||||
/* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
|
||||
* when making Flow check .android.js files. */
|
||||
this._exampleRef.handleBackAction &&
|
||||
/* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
|
||||
* when making Flow check .android.js files. */
|
||||
this._exampleRef.handleBackAction()
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return this._handleAction(RNTesterActions.Back(screen));
|
||||
};
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
toolbar: {
|
||||
height: 56,
|
||||
},
|
||||
toolbarLeft: {
|
||||
marginTop: 2,
|
||||
},
|
||||
toolbarCenter: {
|
||||
flex: 1,
|
||||
position: 'absolute',
|
||||
top: 12,
|
||||
left: 0,
|
||||
right: 0,
|
||||
alignItems: 'center',
|
||||
},
|
||||
title: {
|
||||
fontSize: 19,
|
||||
fontWeight: '600',
|
||||
textAlign: 'center',
|
||||
},
|
||||
bottomNavbar: {
|
||||
bottom: 0,
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
position: 'absolute',
|
||||
},
|
||||
});
|
||||
import RNTesterApp from './RNTesterAppShared';
|
||||
|
||||
AppRegistry.registerComponent('RNTesterApp', () => RNTesterApp);
|
||||
|
||||
|
|
|
@ -10,328 +10,14 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
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 React = require('react');
|
||||
const SnapshotViewIOS = require('./examples/Snapshot/SnapshotViewIOS.ios');
|
||||
const RNTesterNavbar = require('./components/RNTesterNavbar');
|
||||
|
||||
const {
|
||||
AppRegistry,
|
||||
AsyncStorage,
|
||||
BackHandler,
|
||||
Button,
|
||||
Platform,
|
||||
SafeAreaView,
|
||||
StyleSheet,
|
||||
Text,
|
||||
useColorScheme,
|
||||
View,
|
||||
LogBox,
|
||||
} = require('react-native');
|
||||
import {AppRegistry} from 'react-native';
|
||||
import React from 'react';
|
||||
|
||||
import SnapshotViewIOS from './examples/Snapshot/SnapshotViewIOS.ios';
|
||||
import RNTesterExampleContainer from './components/RNTesterExampleContainer';
|
||||
import RNTesterList from './utils/RNTesterList';
|
||||
import RNTesterApp from './RNTesterAppShared';
|
||||
import type {RNTesterExample} from './types/RNTesterTypes';
|
||||
import type {
|
||||
RNTesterAction,
|
||||
RNTesterExampleAction,
|
||||
} from './utils/RNTesterActions';
|
||||
import type {RNTesterNavigationState} from './utils/RNTesterNavigationReducer';
|
||||
import {RNTesterThemeContext, themes} from './components/RNTesterTheme';
|
||||
import RNTesterDocumentationURL from './components/RNTesterDocumentationURL';
|
||||
import type {ColorSchemeName} from '../../../Libraries/Utilities/NativeAppearance';
|
||||
import {
|
||||
RNTesterBookmarkContext,
|
||||
bookmarks,
|
||||
} from './components/RNTesterBookmark';
|
||||
import type {RNTesterBookmark} from './components/RNTesterBookmark';
|
||||
|
||||
type Props = {exampleFromAppetizeParams?: ?string, ...};
|
||||
|
||||
import {
|
||||
initializeAsyncStore,
|
||||
addApi,
|
||||
addComponent,
|
||||
removeApi,
|
||||
removeComponent,
|
||||
checkBookmarks,
|
||||
updateRecentlyViewedList,
|
||||
} from './utils/RNTesterAsyncStorageAbstraction';
|
||||
|
||||
const APP_STATE_KEY = 'RNTesterAppState.v2';
|
||||
|
||||
const Header = ({
|
||||
onBack,
|
||||
title,
|
||||
documentationURL,
|
||||
}: {
|
||||
onBack?: () => mixed,
|
||||
title: string,
|
||||
documentationURL?: string,
|
||||
...
|
||||
}) => (
|
||||
<RNTesterThemeContext.Consumer>
|
||||
{theme => {
|
||||
return (
|
||||
<SafeAreaView
|
||||
style={[
|
||||
styles.headerContainer,
|
||||
{
|
||||
borderBottomColor: theme.SeparatorColor,
|
||||
backgroundColor: theme.TertiarySystemBackgroundColor,
|
||||
},
|
||||
]}>
|
||||
<View style={styles.header}>
|
||||
<View style={styles.headerCenter}>
|
||||
<Text style={[styles.title, {color: theme.LabelColor}]}>
|
||||
{title}
|
||||
</Text>
|
||||
{documentationURL && (
|
||||
<RNTesterDocumentationURL documentationURL={documentationURL} />
|
||||
)}
|
||||
</View>
|
||||
{onBack && (
|
||||
<View>
|
||||
<Button
|
||||
title="Back"
|
||||
onPress={onBack}
|
||||
color={Platform.select({
|
||||
ios: theme.LinkColor,
|
||||
default: undefined,
|
||||
})}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}}
|
||||
</RNTesterThemeContext.Consumer>
|
||||
);
|
||||
|
||||
const RNTesterExampleContainerViaHook = ({
|
||||
onBack,
|
||||
title,
|
||||
module,
|
||||
}: {
|
||||
onBack?: () => mixed,
|
||||
title: string,
|
||||
module: RNTesterExample,
|
||||
...
|
||||
}) => {
|
||||
const colorScheme: ?ColorSchemeName = useColorScheme();
|
||||
const theme = colorScheme === 'dark' ? themes.dark : themes.light;
|
||||
return (
|
||||
<RNTesterThemeContext.Provider value={theme}>
|
||||
<View style={styles.exampleContainer}>
|
||||
<Header
|
||||
title={title}
|
||||
onBack={onBack}
|
||||
documentationURL={module.documentationURL}
|
||||
/>
|
||||
<RNTesterExampleContainer module={module} />
|
||||
</View>
|
||||
</RNTesterThemeContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
const RNTesterExampleListViaHook = ({
|
||||
onNavigate,
|
||||
UpdateRecentlyViewedList,
|
||||
recentComponents,
|
||||
recentApis,
|
||||
bookmark,
|
||||
list,
|
||||
screen,
|
||||
}: {
|
||||
onNavigate?: (item: RNTesterExampleAction, key: string) => mixed,
|
||||
UpdateRecentlyViewedList?: (item: RNTesterExample, key: string) => mixed,
|
||||
recentComponents: Array<RNTesterExample>,
|
||||
recentApis: Array<RNTesterExample>,
|
||||
bookmark: RNTesterBookmark,
|
||||
screen: string,
|
||||
list: {
|
||||
ComponentExamples: Array<RNTesterExample>,
|
||||
APIExamples: Array<RNTesterExample>,
|
||||
...
|
||||
},
|
||||
...
|
||||
}) => {
|
||||
const colorScheme: ?ColorSchemeName = useColorScheme();
|
||||
const theme = colorScheme === 'dark' ? themes.dark : themes.light;
|
||||
const exampleTitle =
|
||||
screen === 'component'
|
||||
? 'Component Store'
|
||||
: screen === 'api'
|
||||
? 'API Store'
|
||||
: 'Bookmarks';
|
||||
return (
|
||||
<RNTesterThemeContext.Provider value={theme}>
|
||||
<RNTesterBookmarkContext.Provider value={bookmark}>
|
||||
<View style={styles.exampleContainer}>
|
||||
<Header title={exampleTitle} />
|
||||
<RNTesterExampleList
|
||||
onNavigate={onNavigate}
|
||||
recentComponents={recentComponents}
|
||||
recentApis={recentApis}
|
||||
updateRecentlyViewedList={UpdateRecentlyViewedList}
|
||||
list={list}
|
||||
screen={screen}
|
||||
/>
|
||||
</View>
|
||||
</RNTesterBookmarkContext.Provider>
|
||||
</RNTesterThemeContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
class RNTesterApp extends React.Component<Props, RNTesterNavigationState> {
|
||||
_mounted: boolean;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
// RNTester App currently uses Async Storage from react-native for storing navigation state
|
||||
// and bookmark items.
|
||||
// TODO: Add Native Async Storage Module in RNTester
|
||||
LogBox.ignoreLogs([new RegExp('has been extracted from react-native')]);
|
||||
|
||||
this.state = {
|
||||
openExample: null,
|
||||
screen: 'component',
|
||||
Components: bookmarks.Components,
|
||||
Api: bookmarks.Api,
|
||||
recentComponents: [],
|
||||
recentApis: [],
|
||||
AddApi: (apiName, api) => addApi(apiName, api, this),
|
||||
AddComponent: (componentName, component) =>
|
||||
addComponent(componentName, component, this),
|
||||
RemoveApi: apiName => removeApi(apiName, this),
|
||||
RemoveComponent: componentName => removeComponent(componentName, this),
|
||||
checkBookmark: (title, key) => checkBookmarks(title, key, this),
|
||||
updateRecentlyViewedList: (item, key) =>
|
||||
updateRecentlyViewedList(item, key, this),
|
||||
};
|
||||
}
|
||||
|
||||
UNSAFE_componentWillMount() {
|
||||
BackHandler.addEventListener('hardwareBackPress', this._handleBack);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
initializeAsyncStore(this);
|
||||
}
|
||||
|
||||
_handleBack = () => {
|
||||
this._handleAction(RNTesterActions.Back(this.state.screen));
|
||||
};
|
||||
|
||||
_handleAction = (action: ?RNTesterAction) => {
|
||||
if (!action) {
|
||||
return;
|
||||
}
|
||||
const newState = RNTesterNavigationReducer(this.state, action);
|
||||
if (this.state !== newState) {
|
||||
// syncing the app screens over async storage
|
||||
this.setState(newState, () =>
|
||||
AsyncStorage.setItem(APP_STATE_KEY, JSON.stringify(this.state)),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
render(): React.Node | null {
|
||||
const bookmark = {
|
||||
Components: this.state.Components,
|
||||
Api: this.state.Api,
|
||||
AddApi: this.state.AddApi,
|
||||
AddComponent: this.state.AddComponent,
|
||||
RemoveApi: this.state.RemoveApi,
|
||||
RemoveComponent: this.state.RemoveComponent,
|
||||
checkBookmark: this.state.checkBookmark,
|
||||
};
|
||||
|
||||
if (!this.state) {
|
||||
return null;
|
||||
}
|
||||
if (this.state.openExample) {
|
||||
const Component = RNTesterList.Modules[this.state.openExample];
|
||||
if (Component && Component.external) {
|
||||
return <Component onExampleExit={this._handleBack} />;
|
||||
} else {
|
||||
return (
|
||||
<>
|
||||
<RNTesterExampleContainerViaHook
|
||||
onBack={this._handleBack}
|
||||
title={Component.title}
|
||||
module={Component}
|
||||
/>
|
||||
<View style={styles.bottomNavbar}>
|
||||
<RNTesterNavbar onNavigate={this._handleAction} />
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<RNTesterExampleListViaHook
|
||||
key={this.state.screen}
|
||||
title={'RNTester'}
|
||||
onNavigate={this._handleAction}
|
||||
UpdateRecentlyViewedList={this.state.updateRecentlyViewedList}
|
||||
recentComponents={this.state.recentComponents}
|
||||
recentApis={this.state.recentApis}
|
||||
bookmark={bookmark}
|
||||
list={RNTesterList}
|
||||
screen={this.state.screen}
|
||||
/>
|
||||
<View style={styles.bottomNavbar}>
|
||||
<RNTesterNavbar
|
||||
screen={this.state.screen}
|
||||
onNavigate={this._handleAction}
|
||||
/>
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
headerContainer: {
|
||||
borderBottomWidth: StyleSheet.hairlineWidth,
|
||||
},
|
||||
header: {
|
||||
height: 40,
|
||||
flexDirection: 'row',
|
||||
},
|
||||
headerCenter: {
|
||||
flex: 1,
|
||||
position: 'absolute',
|
||||
top: 7,
|
||||
left: 0,
|
||||
right: 0,
|
||||
alignItems: 'center',
|
||||
},
|
||||
title: {
|
||||
fontSize: 19,
|
||||
fontWeight: '600',
|
||||
textAlign: 'center',
|
||||
},
|
||||
exampleContainer: {
|
||||
flex: 1,
|
||||
},
|
||||
bottomNavbar: {
|
||||
bottom: 0,
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
position: 'absolute',
|
||||
},
|
||||
});
|
||||
|
||||
AppRegistry.registerComponent('SetPropertiesExampleApp', () =>
|
||||
require('./examples/SetPropertiesExample/SetPropertiesExampleApp'),
|
||||
|
|
|
@ -0,0 +1,244 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and 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 {
|
||||
BackHandler,
|
||||
StyleSheet,
|
||||
useColorScheme,
|
||||
View,
|
||||
LogBox,
|
||||
} from 'react-native';
|
||||
import * as React from 'react';
|
||||
|
||||
import RNTesterExampleContainer from './components/RNTesterExampleContainer';
|
||||
import RNTesterExampleList from './components/RNTesterExampleList';
|
||||
import RNTesterNavBar from './components/RNTesterNavbar';
|
||||
import RNTesterList from './utils/RNTesterList';
|
||||
import {
|
||||
Screens,
|
||||
initialState,
|
||||
getExamplesListWithBookmarksAndRecentlyUsed,
|
||||
getInitialStateFromAsyncStorage,
|
||||
} from './utils/testerStateUtils';
|
||||
import {useAsyncStorageReducer} from './utils/useAsyncStorageReducer';
|
||||
import {RNTesterReducer, RNTesterActionsType} from './utils/RNTesterReducer';
|
||||
import {RNTesterThemeContext, themes} from './components/RNTesterTheme';
|
||||
import {Header} from './components/RNTesterHeader';
|
||||
import {RNTesterEmptyBookmarksState} from './components/RNTesterEmptyBookmarksState';
|
||||
|
||||
import type {RNTesterTheme} from './components/RNTesterTheme';
|
||||
import type {ExamplesList} from './types/RNTesterTypes';
|
||||
|
||||
const APP_STATE_KEY = 'RNTesterAppState.v3';
|
||||
|
||||
// RNTester App currently uses AsyncStorage from react-native for storing navigation state
|
||||
// and bookmark items.
|
||||
// TODO: Vendor AsyncStorage or create our own.
|
||||
LogBox.ignoreLogs([/AsyncStorage has been extracted from react-native/]);
|
||||
|
||||
const DisplayIfVisible = ({isVisible, children}) => (
|
||||
<View style={[styles.container, !isVisible && styles.hidden]}>
|
||||
{children}
|
||||
</View>
|
||||
);
|
||||
|
||||
type ExampleListsContainerProps = $ReadOnly<{|
|
||||
theme: RNTesterTheme,
|
||||
screen: string,
|
||||
title: string,
|
||||
examplesList: ExamplesList,
|
||||
toggleBookmark: (args: {exampleType: string, key: string}) => mixed,
|
||||
handleExampleCardPress: (args: {exampleType: string, key: string}) => mixed,
|
||||
isVisible: boolean,
|
||||
|}>;
|
||||
|
||||
const ExampleListsContainer = ({
|
||||
theme,
|
||||
screen,
|
||||
title,
|
||||
examplesList,
|
||||
toggleBookmark,
|
||||
handleExampleCardPress,
|
||||
isVisible,
|
||||
}: ExampleListsContainerProps) => {
|
||||
const isBookmarkEmpty = examplesList.bookmarks.length === 0;
|
||||
|
||||
return (
|
||||
<DisplayIfVisible isVisible={isVisible}>
|
||||
<Header title={title} theme={theme} />
|
||||
<DisplayIfVisible isVisible={screen === Screens.COMPONENTS}>
|
||||
<RNTesterExampleList
|
||||
sections={examplesList.components}
|
||||
toggleBookmark={toggleBookmark}
|
||||
handleExampleCardPress={handleExampleCardPress}
|
||||
/>
|
||||
</DisplayIfVisible>
|
||||
<DisplayIfVisible isVisible={screen === Screens.APIS}>
|
||||
<RNTesterExampleList
|
||||
sections={examplesList.apis}
|
||||
toggleBookmark={toggleBookmark}
|
||||
handleExampleCardPress={handleExampleCardPress}
|
||||
/>
|
||||
</DisplayIfVisible>
|
||||
<DisplayIfVisible isVisible={screen === Screens.BOOKMARKS}>
|
||||
{isBookmarkEmpty ? (
|
||||
<RNTesterEmptyBookmarksState />
|
||||
) : (
|
||||
<RNTesterExampleList
|
||||
sections={examplesList.bookmarks}
|
||||
toggleBookmark={toggleBookmark}
|
||||
handleExampleCardPress={handleExampleCardPress}
|
||||
/>
|
||||
)}
|
||||
</DisplayIfVisible>
|
||||
</DisplayIfVisible>
|
||||
);
|
||||
};
|
||||
|
||||
const RNTesterApp = (): React.Node => {
|
||||
const [state, dispatch] = useAsyncStorageReducer(
|
||||
RNTesterReducer,
|
||||
initialState,
|
||||
APP_STATE_KEY,
|
||||
);
|
||||
const colorScheme = useColorScheme();
|
||||
|
||||
const {openExample, screen, bookmarks, recentlyUsed} = state;
|
||||
|
||||
React.useEffect(() => {
|
||||
getInitialStateFromAsyncStorage(APP_STATE_KEY).then(
|
||||
initialStateFromStorage => {
|
||||
dispatch({
|
||||
type: RNTesterActionsType.INIT_FROM_STORAGE,
|
||||
data: initialStateFromStorage,
|
||||
});
|
||||
},
|
||||
);
|
||||
}, [dispatch]);
|
||||
|
||||
const examplesList = React.useMemo(
|
||||
() =>
|
||||
getExamplesListWithBookmarksAndRecentlyUsed({bookmarks, recentlyUsed}),
|
||||
[bookmarks, recentlyUsed],
|
||||
);
|
||||
|
||||
const handleBackPress = React.useCallback(() => {
|
||||
if (openExample) {
|
||||
dispatch({type: RNTesterActionsType.BACK_BUTTON_PRESS});
|
||||
}
|
||||
}, [dispatch, openExample]);
|
||||
|
||||
// Setup hardware back button press listener
|
||||
React.useEffect(() => {
|
||||
BackHandler.addEventListener('hardwareBackPress', () => {
|
||||
if (openExample) {
|
||||
handleBackPress();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}, [openExample, handleBackPress]);
|
||||
|
||||
const handleExampleCardPress = React.useCallback(
|
||||
({exampleType, key}) => {
|
||||
dispatch({
|
||||
type: RNTesterActionsType.EXAMPLE_CARD_PRESS,
|
||||
data: {exampleType, key},
|
||||
});
|
||||
},
|
||||
[dispatch],
|
||||
);
|
||||
|
||||
const toggleBookmark = React.useCallback(
|
||||
({exampleType, key}) => {
|
||||
dispatch({
|
||||
type: RNTesterActionsType.BOOKMARK_PRESS,
|
||||
data: {exampleType, key},
|
||||
});
|
||||
},
|
||||
[dispatch],
|
||||
);
|
||||
|
||||
const handleNavBarPress = React.useCallback(
|
||||
args => {
|
||||
dispatch({
|
||||
type: RNTesterActionsType.NAVBAR_PRESS,
|
||||
data: {screen: args.screen},
|
||||
});
|
||||
},
|
||||
[dispatch],
|
||||
);
|
||||
|
||||
const theme = colorScheme === 'dark' ? themes.dark : themes.light;
|
||||
|
||||
if (examplesList === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const ExampleModule = openExample && RNTesterList.Modules[openExample];
|
||||
const title = Screens.COMPONENTS
|
||||
? 'Components'
|
||||
: Screens.APIS
|
||||
? 'APIs'
|
||||
: 'Bookmarks';
|
||||
|
||||
return (
|
||||
<RNTesterThemeContext.Provider value={theme}>
|
||||
{ExampleModule && (
|
||||
<View style={styles.container}>
|
||||
<Header
|
||||
onBack={handleBackPress}
|
||||
title={title}
|
||||
theme={theme}
|
||||
documentationURL={ExampleModule.documentationURL}
|
||||
/>
|
||||
<RNTesterExampleContainer module={ExampleModule} />
|
||||
</View>
|
||||
)}
|
||||
|
||||
<ExampleListsContainer
|
||||
isVisible={!ExampleModule}
|
||||
screen={screen || Screens.COMPONENTS}
|
||||
title={title}
|
||||
theme={theme}
|
||||
examplesList={examplesList}
|
||||
handleExampleCardPress={handleExampleCardPress}
|
||||
toggleBookmark={toggleBookmark}
|
||||
/>
|
||||
<View style={styles.bottomNavbar}>
|
||||
<RNTesterNavBar
|
||||
screen={screen || Screens.COMPONENTS}
|
||||
isExamplePageOpen={!!ExampleModule}
|
||||
handleNavBarPress={handleNavBarPress}
|
||||
/>
|
||||
</View>
|
||||
</RNTesterThemeContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export default RNTesterApp;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
bottomNavbar: {
|
||||
bottom: 0,
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
position: 'absolute',
|
||||
},
|
||||
hidden: {
|
||||
display: 'none',
|
||||
},
|
||||
});
|
|
@ -36,7 +36,7 @@ export default function ExamplePage(props: Props): React.Node {
|
|||
return (
|
||||
<>
|
||||
<View style={styles.titleView}>
|
||||
<Text style={{marginVertical: 8, fontSize: 16}}>{description}</Text>
|
||||
<Text style={styles.description}>{description}</Text>
|
||||
<View style={styles.rowStyle}>
|
||||
<Text style={{color: theme.SecondaryLabelColor, width: 65}}>
|
||||
{category || 'Other'}
|
||||
|
@ -80,9 +80,8 @@ const styles = StyleSheet.create({
|
|||
flexGrow: 1,
|
||||
},
|
||||
description: {
|
||||
paddingVertical: 5,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
marginVertical: 8,
|
||||
fontSize: 16,
|
||||
},
|
||||
docsContainer: {
|
||||
alignContent: 'center',
|
||||
|
|
|
@ -20,9 +20,7 @@ type Props = $ReadOnly<{|
|
|||
description?: ?string,
|
||||
|}>;
|
||||
|
||||
/** functional component for generating example blocks */
|
||||
const RNTesterBlock = (props: Props): React.Node => {
|
||||
const {description, title, children} = props;
|
||||
const RNTesterBlock = ({description, title, children}: Props): React.Node => {
|
||||
const theme = React.useContext(RNTesterThemeContext);
|
||||
return (
|
||||
<View style={[[styles.container], {borderColor: theme.SeparatorColor}]}>
|
||||
|
@ -60,7 +58,7 @@ const styles = StyleSheet.create({
|
|||
color: 'black',
|
||||
},
|
||||
children: {
|
||||
paddingVertical: 10,
|
||||
paddingTop: 10,
|
||||
paddingHorizontal: 10,
|
||||
margin: 10,
|
||||
},
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and 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 * as React from 'react';
|
||||
import {View, Image, Text, StyleSheet} from 'react-native';
|
||||
|
||||
export const RNTesterEmptyBookmarksState = (): React.Node => (
|
||||
<View style={styles.emptyContainer}>
|
||||
<View style={styles.emptyContainerInner}>
|
||||
<Image
|
||||
source={require('../assets/empty.png')}
|
||||
resizeMode="contain"
|
||||
style={styles.emptyImage}
|
||||
/>
|
||||
<View>
|
||||
<Text style={styles.heading}>Bookmarks are empty</Text>
|
||||
<Text style={styles.subheading}>
|
||||
Please tap the{' '}
|
||||
<Image
|
||||
source={require('../assets/bookmark-outline-gray.png')}
|
||||
resizeMode="contain"
|
||||
style={styles.bookmarkIcon}
|
||||
/>{' '}
|
||||
icon to bookmark examples.
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
emptyContainer: {
|
||||
flex: 1,
|
||||
paddingHorizontal: 40,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: 'white',
|
||||
},
|
||||
emptyContainerInner: {
|
||||
marginTop: -150,
|
||||
},
|
||||
emptyImage: {
|
||||
maxWidth: '100%',
|
||||
height: 300,
|
||||
},
|
||||
heading: {
|
||||
fontSize: 24,
|
||||
textAlign: 'center',
|
||||
},
|
||||
subheading: {
|
||||
fontSize: 16,
|
||||
textAlign: 'center',
|
||||
},
|
||||
bookmarkIcon: {
|
||||
width: 24,
|
||||
height: 24,
|
||||
transform: [{translateY: 4}],
|
||||
},
|
||||
});
|
|
@ -22,18 +22,16 @@ const {
|
|||
import {RNTesterThemeContext} from './RNTesterTheme';
|
||||
import type {RNTesterExample} from '../types/RNTesterTypes';
|
||||
|
||||
import type {SectionData} from '../types/RNTesterTypes';
|
||||
|
||||
type Props = {
|
||||
filter: Function,
|
||||
render: Function,
|
||||
disableSearch?: boolean,
|
||||
testID?: string,
|
||||
hideFilterPills?: boolean,
|
||||
page: string, // possible values -> examples_page, components_page, bookmarks_page
|
||||
sections: Array<{
|
||||
data: Array<RNTesterExample>,
|
||||
title: string,
|
||||
key: string,
|
||||
}>,
|
||||
page: 'examples_page' | 'components_page' | 'bookmarks_page',
|
||||
sections: SectionData[],
|
||||
...
|
||||
};
|
||||
|
||||
|
@ -71,7 +69,7 @@ class RNTesterExampleFilter extends React.Component<Props, State> {
|
|||
|
||||
if (this.state.filter.trim() !== '' || this.state.category.trim() !== '') {
|
||||
filteredSections = filteredSections.filter(
|
||||
section => section.title !== 'Recently viewed',
|
||||
section => section.title !== 'Recently Viewed',
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,9 +9,7 @@
|
|||
*/
|
||||
|
||||
'use strict';
|
||||
import type {RNTesterBookmark} from './RNTesterBookmark.js';
|
||||
|
||||
const RNTesterActions = require('../utils/RNTesterActions');
|
||||
const RNTesterExampleFilter = require('./RNTesterExampleFilter');
|
||||
const RNTesterComponentTitle = require('./RNTesterComponentTitle');
|
||||
const React = require('react');
|
||||
|
@ -26,170 +24,80 @@ const {
|
|||
View,
|
||||
} = require('react-native');
|
||||
|
||||
import type {ViewStyleProp} from '../../../../Libraries/StyleSheet/StyleSheet';
|
||||
import type {RNTesterExample} from '../types/RNTesterTypes';
|
||||
import {RNTesterThemeContext} from './RNTesterTheme';
|
||||
import {RNTesterBookmarkContext} from './RNTesterBookmark';
|
||||
|
||||
type Props = {
|
||||
screen: string,
|
||||
onNavigate: Function,
|
||||
updateRecentlyViewedList: Function,
|
||||
recentApis: Array<RNTesterExample>,
|
||||
recentComponents: Array<RNTesterExample>,
|
||||
list: {
|
||||
ComponentExamples: Array<RNTesterExample>,
|
||||
APIExamples: Array<RNTesterExample>,
|
||||
...
|
||||
},
|
||||
style?: ?ViewStyleProp,
|
||||
...
|
||||
};
|
||||
|
||||
type State = {
|
||||
components: Array<RNTesterExample>,
|
||||
api: Array<RNTesterExample>,
|
||||
recentComponents: Array<RNTesterExample>,
|
||||
recentApis: Array<RNTesterExample>,
|
||||
updateRecentlyViewedList: Function,
|
||||
};
|
||||
|
||||
type ButtonState = {active: boolean, key: string, ...};
|
||||
type ButtonProps = {
|
||||
item: Object,
|
||||
section: Object,
|
||||
active: boolean,
|
||||
onNavigate: Function,
|
||||
onPress?: Function,
|
||||
onShowUnderlay?: Function,
|
||||
onHideUnderlay?: Function,
|
||||
updateRecentlyViewedList: Function,
|
||||
...
|
||||
};
|
||||
|
||||
class RowComponent extends React.PureComponent<ButtonProps, ButtonState> {
|
||||
static contextType = RNTesterBookmarkContext;
|
||||
|
||||
constructor(props: ButtonProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
active: props.active,
|
||||
title: props.item.module.title,
|
||||
key: props.section.key,
|
||||
};
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps(nextProps, prevState) {
|
||||
if (nextProps.active !== prevState.active) {
|
||||
return {active: nextProps.active};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
onButtonPress = () => {
|
||||
let bookmark = this.context;
|
||||
if (!this.state.active) {
|
||||
if (this.state.key === 'APIS' || this.state.key === 'RECENT_APIS') {
|
||||
bookmark.AddApi(this.props.item.module.title, this.props.item);
|
||||
} else {
|
||||
bookmark.AddComponent(this.props.item.module.title, this.props.item);
|
||||
}
|
||||
} else {
|
||||
if (this.state.key === 'APIS' || this.state.key === 'RECENT_APIS') {
|
||||
bookmark.RemoveApi(this.props.item.module.title);
|
||||
} else {
|
||||
bookmark.RemoveComponent(this.props.item.module.title);
|
||||
}
|
||||
}
|
||||
this.setState({
|
||||
active: !this.state.active,
|
||||
});
|
||||
};
|
||||
|
||||
_onPress = () => {
|
||||
this.props.updateRecentlyViewedList();
|
||||
if (this.props.onPress) {
|
||||
this.props.onPress();
|
||||
return;
|
||||
}
|
||||
this.props.onNavigate(RNTesterActions.ExampleAction(this.props.item.key));
|
||||
};
|
||||
render() {
|
||||
const {item} = this.props;
|
||||
const platform = item.module.platform;
|
||||
const onIos = !platform || platform === 'ios';
|
||||
const onAndroid = !platform || platform === 'android';
|
||||
return (
|
||||
<RNTesterThemeContext.Consumer>
|
||||
{theme => {
|
||||
return (
|
||||
<TouchableHighlight
|
||||
onShowUnderlay={this.props.onShowUnderlay}
|
||||
onHideUnderlay={this.props.onHideUnderlay}
|
||||
accessibilityLabel={
|
||||
item.module.title + ' ' + item.module.description
|
||||
const ExampleCard = ({
|
||||
onShowUnderlay,
|
||||
onHideUnderlay,
|
||||
item,
|
||||
toggleBookmark,
|
||||
handlePress,
|
||||
}) => {
|
||||
const theme = React.useContext(RNTesterThemeContext);
|
||||
const platform = item.module.platform;
|
||||
const onIos = !platform || platform === 'ios';
|
||||
const onAndroid = !platform || platform === 'android';
|
||||
return (
|
||||
<TouchableHighlight
|
||||
onShowUnderlay={onShowUnderlay}
|
||||
onHideUnderlay={onHideUnderlay}
|
||||
accessibilityLabel={item.module.title + ' ' + item.module.description}
|
||||
style={styles.listItem}
|
||||
underlayColor={'rgb(242,242,242)'}
|
||||
onPress={() =>
|
||||
handlePress({exampleType: item.exampleType, key: item.key})
|
||||
}>
|
||||
<View
|
||||
style={[styles.row, {backgroundColor: theme.SystemBackgroundColor}]}>
|
||||
<View style={styles.topRowStyle}>
|
||||
<RNTesterComponentTitle>{item.module.title}</RNTesterComponentTitle>
|
||||
<TouchableHighlight
|
||||
style={styles.imageViewStyle}
|
||||
onPress={() =>
|
||||
toggleBookmark({exampleType: item.exampleType, key: item.key})
|
||||
}>
|
||||
<Image
|
||||
style={styles.imageStyle}
|
||||
source={
|
||||
item.isBookmarked
|
||||
? require('../assets/bookmark-outline-blue.png')
|
||||
: require('../assets/bookmark-outline-gray.png')
|
||||
}
|
||||
style={styles.listItem}
|
||||
underlayColor={'rgb(242,242,242)'}
|
||||
onPress={this._onPress}>
|
||||
<View
|
||||
style={[
|
||||
styles.row,
|
||||
{backgroundColor: theme.SystemBackgroundColor},
|
||||
]}>
|
||||
<View style={styles.topRowStyle}>
|
||||
<RNTesterComponentTitle>
|
||||
{item.module.title}
|
||||
</RNTesterComponentTitle>
|
||||
<TouchableHighlight
|
||||
style={styles.imageViewStyle}
|
||||
onPress={() => this.onButtonPress()}>
|
||||
<Image
|
||||
style={styles.imageStyle}
|
||||
source={
|
||||
this.state.active
|
||||
? require('../assets/bookmark-outline-blue.png')
|
||||
: require('../assets/bookmark-outline-gray.png')
|
||||
}
|
||||
/>
|
||||
</TouchableHighlight>
|
||||
</View>
|
||||
<Text
|
||||
style={[
|
||||
styles.rowDetailText,
|
||||
{color: theme.SecondaryLabelColor, marginBottom: 5},
|
||||
]}>
|
||||
{item.module.description}
|
||||
</Text>
|
||||
<View style={styles.bottomRowStyle}>
|
||||
<Text style={{color: theme.SecondaryLabelColor, width: 65}}>
|
||||
{item.module.category || 'Other'}
|
||||
</Text>
|
||||
<View style={styles.platformLabelStyle}>
|
||||
<Text
|
||||
style={{
|
||||
color: onIos ? '#787878' : theme.SeparatorColor,
|
||||
fontWeight: onIos ? '500' : '300',
|
||||
}}>
|
||||
iOS
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
color: onAndroid ? '#787878' : theme.SeparatorColor,
|
||||
fontWeight: onAndroid ? '500' : '300',
|
||||
}}>
|
||||
Android
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
);
|
||||
}}
|
||||
</RNTesterThemeContext.Consumer>
|
||||
);
|
||||
}
|
||||
}
|
||||
/>
|
||||
</TouchableHighlight>
|
||||
</View>
|
||||
<Text
|
||||
style={[
|
||||
styles.rowDetailText,
|
||||
{color: theme.SecondaryLabelColor, marginBottom: 5},
|
||||
]}>
|
||||
{item.module.description}
|
||||
</Text>
|
||||
<View style={styles.bottomRowStyle}>
|
||||
<Text style={{color: theme.SecondaryLabelColor, width: 65}}>
|
||||
{item.module.category || 'Other'}
|
||||
</Text>
|
||||
<View style={styles.platformLabelStyle}>
|
||||
<Text
|
||||
style={{
|
||||
color: onIos ? '#787878' : theme.SeparatorColor,
|
||||
fontWeight: onIos ? '500' : '300',
|
||||
}}>
|
||||
iOS
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
color: onAndroid ? '#787878' : theme.SeparatorColor,
|
||||
fontWeight: onAndroid ? '500' : '300',
|
||||
}}>
|
||||
Android
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
);
|
||||
};
|
||||
|
||||
const renderSectionHeader = ({section}) => (
|
||||
<RNTesterThemeContext.Consumer>
|
||||
|
@ -210,176 +118,57 @@ const renderSectionHeader = ({section}) => (
|
|||
</RNTesterThemeContext.Consumer>
|
||||
);
|
||||
|
||||
class RNTesterExampleList extends React.Component<Props, State> {
|
||||
static contextType: React.Context<RNTesterBookmark> = RNTesterBookmarkContext;
|
||||
const RNTesterExampleList: React$AbstractComponent<any, void> = React.memo(
|
||||
({sections, toggleBookmark, handleExampleCardPress}) => {
|
||||
const theme = React.useContext(RNTesterThemeContext);
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
components: props.list.ComponentExamples,
|
||||
api: props.list.APIExamples,
|
||||
recentComponents: props.recentComponents,
|
||||
recentApis: props.recentApis,
|
||||
updateRecentlyViewedList: (item, key) =>
|
||||
props.updateRecentlyViewedList(item, key),
|
||||
};
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps(nextProps: Props, prevState: State): State {
|
||||
if (
|
||||
nextProps.recentComponents.every(
|
||||
(component, index) => component !== prevState.recentComponents[index],
|
||||
) &&
|
||||
nextProps.recentApis.every(
|
||||
(api, index) => api !== prevState.recentApis[index],
|
||||
)
|
||||
) {
|
||||
return {
|
||||
...prevState,
|
||||
recentComponents: nextProps.recentComponents,
|
||||
recentApis: nextProps.recentApis,
|
||||
};
|
||||
}
|
||||
return prevState;
|
||||
}
|
||||
|
||||
render(): React.Node {
|
||||
const bookmark = this.context;
|
||||
const filter = ({example, filterRegex, category}) =>
|
||||
filterRegex.test(example.module.title) &&
|
||||
(!category || example.module.category === category) &&
|
||||
(!category || example.category === category) &&
|
||||
(!Platform.isTV || example.supportsTVOS);
|
||||
|
||||
const {screen} = this.props;
|
||||
let sections = [];
|
||||
|
||||
if (screen === 'component') {
|
||||
if (this.state.recentComponents.length > 0) {
|
||||
sections = [
|
||||
{
|
||||
data: this.state.recentComponents,
|
||||
key: 'RECENT_COMPONENTS',
|
||||
title: 'Recently viewed',
|
||||
},
|
||||
{
|
||||
data: this.state.components,
|
||||
key: 'COMPONENTS',
|
||||
title: 'Components',
|
||||
},
|
||||
];
|
||||
} else {
|
||||
sections = [
|
||||
{
|
||||
data: this.state.components,
|
||||
key: 'COMPONENTS',
|
||||
title: 'Components',
|
||||
},
|
||||
];
|
||||
}
|
||||
} else if (screen === 'api') {
|
||||
if (this.state.recentApis.length > 0) {
|
||||
sections = [
|
||||
{
|
||||
data: this.state.recentApis,
|
||||
key: 'RECENT_APIS',
|
||||
title: 'Recently viewed',
|
||||
},
|
||||
{
|
||||
data: this.state.api,
|
||||
key: 'APIS',
|
||||
title: 'APIS',
|
||||
},
|
||||
];
|
||||
} else {
|
||||
sections = [
|
||||
{
|
||||
data: this.state.api,
|
||||
key: 'APIS',
|
||||
title: 'APIS',
|
||||
},
|
||||
];
|
||||
}
|
||||
} else if (screen === 'bookmark') {
|
||||
sections = [
|
||||
{
|
||||
data: Object.values(bookmark.Components),
|
||||
title: 'COMPONENTS',
|
||||
key: 'COMPONENTS',
|
||||
},
|
||||
{
|
||||
data: Object.values(bookmark.Api),
|
||||
title: 'APIS',
|
||||
key: 'APIS',
|
||||
},
|
||||
];
|
||||
} else {
|
||||
sections = [];
|
||||
}
|
||||
|
||||
const isEmpty = sections.filter(s => s.data.length).length === 0;
|
||||
|
||||
if (isEmpty) {
|
||||
return <EmptyState />;
|
||||
}
|
||||
const renderListItem = ({item, section, separators}) => {
|
||||
return (
|
||||
<ExampleCard
|
||||
item={item}
|
||||
section={section}
|
||||
onShowUnderlay={separators.highlight}
|
||||
onHideUnderlay={separators.unhighlight}
|
||||
toggleBookmark={toggleBookmark}
|
||||
handlePress={handleExampleCardPress}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<RNTesterThemeContext.Consumer>
|
||||
{theme => {
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
styles.listContainer,
|
||||
this.props.style,
|
||||
{backgroundColor: theme.SecondaryGroupedBackgroundColor},
|
||||
]}>
|
||||
<RNTesterExampleFilter
|
||||
testID="explorer_search"
|
||||
page="components_page"
|
||||
// $FlowFixMe
|
||||
sections={sections}
|
||||
filter={filter}
|
||||
render={({filteredSections}) => (
|
||||
<SectionList
|
||||
sections={filteredSections}
|
||||
extraData={filteredSections}
|
||||
renderItem={this._renderItem}
|
||||
ItemSeparatorComponent={ItemSeparator}
|
||||
keyboardShouldPersistTaps="handled"
|
||||
automaticallyAdjustContentInsets={false}
|
||||
keyboardDismissMode="on-drag"
|
||||
renderSectionHeader={renderSectionHeader}
|
||||
ListFooterComponent={() => <View style={{height: 200}} />}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}}
|
||||
</RNTesterThemeContext.Consumer>
|
||||
<View
|
||||
style={[
|
||||
styles.listContainer,
|
||||
{backgroundColor: theme.SecondaryGroupedBackgroundColor},
|
||||
]}>
|
||||
<RNTesterExampleFilter
|
||||
testID="explorer_search"
|
||||
page="components_page"
|
||||
sections={sections}
|
||||
filter={filter}
|
||||
render={({filteredSections}) => (
|
||||
<SectionList
|
||||
sections={filteredSections}
|
||||
extraData={filteredSections}
|
||||
renderItem={renderListItem}
|
||||
ItemSeparatorComponent={ItemSeparator}
|
||||
keyboardShouldPersistTaps="handled"
|
||||
automaticallyAdjustContentInsets={false}
|
||||
keyboardDismissMode="on-drag"
|
||||
renderSectionHeader={renderSectionHeader}
|
||||
ListFooterComponent={() => <View style={{height: 80}} />}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_renderItem = ({item, section, separators, index}) => {
|
||||
let bookmark = this.context;
|
||||
return (
|
||||
<RowComponent
|
||||
item={item}
|
||||
section={section}
|
||||
active={!bookmark.checkBookmark(item.module.title, section.key)}
|
||||
onNavigate={this.props.onNavigate}
|
||||
onShowUnderlay={separators.highlight}
|
||||
onHideUnderlay={separators.unhighlight}
|
||||
updateRecentlyViewedList={() =>
|
||||
this.state.updateRecentlyViewedList(item, section.key)
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
_handleRowPress(exampleKey: string): void {
|
||||
this.props.onNavigate(RNTesterActions.ExampleAction(exampleKey));
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const ItemSeparator = ({highlighted}) => (
|
||||
<RNTesterThemeContext.Consumer>
|
||||
|
@ -400,30 +189,6 @@ const ItemSeparator = ({highlighted}) => (
|
|||
</RNTesterThemeContext.Consumer>
|
||||
);
|
||||
|
||||
const EmptyState = () => (
|
||||
<View style={styles.emptyContainer}>
|
||||
<View style={styles.emptyContainerInner}>
|
||||
<Image
|
||||
source={require('../assets/empty.png')}
|
||||
resizeMode="contain"
|
||||
style={styles.emptyImage}
|
||||
/>
|
||||
<View>
|
||||
<Text style={styles.heading}>Bookmarks are empty</Text>
|
||||
<Text style={styles.subheading}>
|
||||
Please tap the{' '}
|
||||
<Image
|
||||
source={require('../assets/bookmark-outline-gray.png')}
|
||||
resizeMode="contain"
|
||||
style={styles.bookmarkIcon}
|
||||
/>{' '}
|
||||
icon to bookmark examples.
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
listContainer: {
|
||||
flex: 1,
|
||||
|
@ -483,33 +248,6 @@ const styles = StyleSheet.create({
|
|||
width: 100,
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
emptyContainer: {
|
||||
flex: 1,
|
||||
paddingHorizontal: 40,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: 'white',
|
||||
},
|
||||
emptyContainerInner: {
|
||||
marginTop: -150,
|
||||
},
|
||||
emptyImage: {
|
||||
maxWidth: '100%',
|
||||
height: 300,
|
||||
},
|
||||
heading: {
|
||||
fontSize: 24,
|
||||
textAlign: 'center',
|
||||
},
|
||||
subheading: {
|
||||
fontSize: 16,
|
||||
textAlign: 'center',
|
||||
},
|
||||
bookmarkIcon: {
|
||||
width: 24,
|
||||
height: 24,
|
||||
transform: [{translateY: 4}],
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = RNTesterExampleList;
|
||||
|
|
|
@ -0,0 +1,144 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and 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 {
|
||||
Text,
|
||||
View,
|
||||
SafeAreaView,
|
||||
Button,
|
||||
Platform,
|
||||
StyleSheet,
|
||||
} from 'react-native';
|
||||
import * as React from 'react';
|
||||
import RNTesterDocumentationURL from './RNTesterDocumentationURL';
|
||||
import {RNTesterThemeContext} from './RNTesterTheme';
|
||||
|
||||
const HeaderIOS = ({
|
||||
onBack,
|
||||
title,
|
||||
documentationURL,
|
||||
}: {
|
||||
onBack?: () => mixed,
|
||||
title: string,
|
||||
documentationURL?: string,
|
||||
}) => {
|
||||
const theme = React.useContext(RNTesterThemeContext);
|
||||
return (
|
||||
<SafeAreaView
|
||||
style={[
|
||||
styles.headerContainer,
|
||||
{
|
||||
borderBottomColor: theme.SeparatorColor,
|
||||
backgroundColor: theme.TertiarySystemBackgroundColor,
|
||||
},
|
||||
]}>
|
||||
<View style={styles.header}>
|
||||
<View style={styles.headerCenter}>
|
||||
<Text style={{...styles.title, ...{color: theme.LabelColor}}}>
|
||||
{title}
|
||||
</Text>
|
||||
{documentationURL && (
|
||||
<RNTesterDocumentationURL documentationURL={documentationURL} />
|
||||
)}
|
||||
</View>
|
||||
{onBack && (
|
||||
<View>
|
||||
<Button
|
||||
title="Back"
|
||||
onPress={onBack}
|
||||
color={Platform.select({
|
||||
ios: theme.LinkColor,
|
||||
default: undefined,
|
||||
})}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
};
|
||||
|
||||
const HeaderAndroid = ({
|
||||
title,
|
||||
documentationURL,
|
||||
}: {
|
||||
title: string,
|
||||
documentationURL?: string,
|
||||
}) => {
|
||||
const theme = React.useContext(RNTesterThemeContext);
|
||||
return (
|
||||
<SafeAreaView>
|
||||
<View style={[styles.toolbar, {backgroundColor: '#F3F8FF'}]}>
|
||||
<View style={styles.toolbarCenter}>
|
||||
<Text style={[styles.title, {color: theme.LabelColor}]}>{title}</Text>
|
||||
{documentationURL && (
|
||||
<RNTesterDocumentationURL documentationURL={documentationURL} />
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
};
|
||||
|
||||
export const Header = ({
|
||||
onBack,
|
||||
title,
|
||||
documentationURL,
|
||||
}: {
|
||||
onBack?: () => mixed,
|
||||
title: string,
|
||||
documentationURL?: string,
|
||||
...
|
||||
}): React.Node =>
|
||||
Platform.OS === 'ios' ? (
|
||||
<HeaderIOS
|
||||
documentationURL={documentationURL}
|
||||
title={title}
|
||||
onBack={onBack}
|
||||
/>
|
||||
) : (
|
||||
<HeaderAndroid documentationURL={documentationURL} title={title} />
|
||||
);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
headerContainer: {
|
||||
borderBottomWidth: StyleSheet.hairlineWidth,
|
||||
},
|
||||
header: {
|
||||
height: 40,
|
||||
flexDirection: 'row',
|
||||
},
|
||||
headerCenter: {
|
||||
flex: 1,
|
||||
position: 'absolute',
|
||||
top: 7,
|
||||
left: 0,
|
||||
right: 0,
|
||||
alignItems: 'center',
|
||||
},
|
||||
title: {
|
||||
fontSize: 19,
|
||||
fontWeight: '600',
|
||||
textAlign: 'center',
|
||||
},
|
||||
toolbar: {
|
||||
height: 56,
|
||||
},
|
||||
toolbarCenter: {
|
||||
flex: 1,
|
||||
position: 'absolute',
|
||||
top: 12,
|
||||
left: 0,
|
||||
right: 0,
|
||||
alignItems: 'center',
|
||||
},
|
||||
});
|
|
@ -5,31 +5,37 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import * as React from 'react';
|
||||
import {Text, View, StyleSheet, Image, Pressable} from 'react-native';
|
||||
|
||||
import {RNTesterThemeContext} from './RNTesterTheme';
|
||||
const RNTesterActions = require('../utils/RNTesterActions');
|
||||
|
||||
const RNTesterNavbar = ({onNavigate, screen}) => {
|
||||
type Props = $ReadOnly<{|
|
||||
handleNavBarPress: (data: {screen: string}) => void,
|
||||
screen: string,
|
||||
isExamplePageOpen: boolean,
|
||||
|}>;
|
||||
|
||||
const RNTesterNavbar = ({
|
||||
handleNavBarPress,
|
||||
screen,
|
||||
isExamplePageOpen,
|
||||
}: Props): React.Node => {
|
||||
const theme = React.useContext(RNTesterThemeContext);
|
||||
|
||||
/** to be attached to navigation framework */
|
||||
const isAPIActive = screen === 'api';
|
||||
const isComponentActive = screen === 'component';
|
||||
const isBookmarkActive = screen === 'bookmark';
|
||||
const isAPIActive = screen === 'apis' && !isExamplePageOpen;
|
||||
const isComponentActive = screen === 'components' && !isExamplePageOpen;
|
||||
const isBookmarkActive = screen === 'bookmarks' && !isExamplePageOpen;
|
||||
|
||||
return (
|
||||
<View>
|
||||
{/** Bottom Navbar code */}
|
||||
{/** component and APIs tab */}
|
||||
<View style={styles.buttonContainer}>
|
||||
{/** left tab with Components */}
|
||||
<Pressable
|
||||
testID="components-tab"
|
||||
onPress={() => onNavigate(RNTesterActions.OpenList('component'))}
|
||||
onPress={() => handleNavBarPress({screen: 'components'})}
|
||||
style={[styles.navButton, {backgroundColor: theme.BackgroundColor}]}>
|
||||
<View
|
||||
style={[
|
||||
|
@ -54,20 +60,16 @@ const RNTesterNavbar = ({onNavigate, screen}) => {
|
|||
</View>
|
||||
</Pressable>
|
||||
|
||||
{/** central tab with bookmark icon */}
|
||||
<View style={styles.centerBox}>
|
||||
<Image
|
||||
style={styles.centralBoxCutout}
|
||||
source={require('./../assets/bottom-nav-center-box.png')}
|
||||
/>
|
||||
|
||||
{/** floating button in center */}
|
||||
<View style={styles.floatContainer}>
|
||||
<Pressable
|
||||
testID="bookmarks-tab"
|
||||
onPress={() => {
|
||||
onNavigate(RNTesterActions.OpenList('bookmark'));
|
||||
}}>
|
||||
onPress={() => handleNavBarPress({screen: 'bookmarks'})}>
|
||||
<View
|
||||
style={[
|
||||
styles.floatingButton,
|
||||
|
@ -86,12 +88,9 @@ const RNTesterNavbar = ({onNavigate, screen}) => {
|
|||
</View>
|
||||
</View>
|
||||
|
||||
{/** right tab with Components */}
|
||||
<Pressable
|
||||
testID="apis-tab"
|
||||
onPress={() => {
|
||||
onNavigate(RNTesterActions.OpenList('api'));
|
||||
}}
|
||||
onPress={() => handleNavBarPress({screen: 'apis'})}
|
||||
style={[styles.navButton, {backgroundColor: theme.BackgroundColor}]}>
|
||||
<View
|
||||
style={[
|
||||
|
@ -163,6 +162,10 @@ const styles = StyleSheet.create({
|
|||
inactiveText: {
|
||||
color: '#B1B4BA',
|
||||
},
|
||||
activeBar: {
|
||||
borderTopWidth: 2,
|
||||
borderColor: '#005DFF',
|
||||
},
|
||||
centralBoxCutout: {
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
|
@ -185,10 +188,6 @@ const styles = StyleSheet.create({
|
|||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
activeBar: {
|
||||
borderTopWidth: 2,
|
||||
borderColor: '#005DFF',
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = RNTesterNavbar;
|
||||
|
|
|
@ -10,20 +10,8 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
import type {ComponentType} from 'react';
|
||||
import * as React from 'react';
|
||||
|
||||
export type RNTesterProps = $ReadOnly<{|
|
||||
navigator?: ?$ReadOnlyArray<
|
||||
$ReadOnly<{|
|
||||
title: string,
|
||||
component: ComponentType<any>,
|
||||
backButtonTitle: string,
|
||||
passProps: any,
|
||||
|}>,
|
||||
>,
|
||||
|}>;
|
||||
|
||||
export type RNTesterExampleModuleItem = $ReadOnly<{|
|
||||
title: string,
|
||||
platform?: string,
|
||||
|
@ -40,6 +28,8 @@ export type RNTesterExampleModule = $ReadOnly<{|
|
|||
framework?: string,
|
||||
examples: Array<RNTesterExampleModuleItem>,
|
||||
simpleExampleContainer?: ?boolean,
|
||||
category?: string,
|
||||
documentationURL?: string,
|
||||
|}>;
|
||||
|
||||
export type RNTesterExample = $ReadOnly<{|
|
||||
|
@ -48,4 +38,29 @@ export type RNTesterExample = $ReadOnly<{|
|
|||
category?: string,
|
||||
supportsTVOS?: boolean,
|
||||
documentationURL?: string,
|
||||
isBookmarked?: boolean,
|
||||
exampleType?: 'components' | 'apis',
|
||||
|}>;
|
||||
|
||||
export type SectionData = {
|
||||
key: string,
|
||||
title: string,
|
||||
data: Array<RNTesterExample>,
|
||||
};
|
||||
|
||||
export type ExamplesList = $ReadOnly<{|
|
||||
components: SectionData[],
|
||||
apis: SectionData[],
|
||||
bookmarks: SectionData[],
|
||||
|}>;
|
||||
|
||||
export type ScreenTypes = 'components' | 'apis' | 'bookmarks' | null;
|
||||
|
||||
export type ComponentList = null | {components: string[], apis: string[]};
|
||||
|
||||
export type RNTesterState = {
|
||||
openExample: null | string,
|
||||
screen: ScreenTypes,
|
||||
bookmarks: ComponentList,
|
||||
recentlyUsed: ComponentList,
|
||||
};
|
||||
|
|
|
@ -1,55 +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';
|
||||
|
||||
export type RNTesterBackAction = {type: 'RNTesterBackAction', ...};
|
||||
|
||||
export type RNTesterListAction = {type: 'RNTesterListAction', ...};
|
||||
|
||||
export type RNTesterExampleAction = {
|
||||
type: 'RNTesterExampleAction',
|
||||
openExample: string,
|
||||
...
|
||||
};
|
||||
|
||||
export type RNTesterAction =
|
||||
| RNTesterBackAction
|
||||
| RNTesterListAction
|
||||
| RNTesterExampleAction;
|
||||
|
||||
function Back(screen: string): RNTesterBackAction {
|
||||
return {
|
||||
type: 'RNTesterBackAction',
|
||||
screen,
|
||||
};
|
||||
}
|
||||
|
||||
function OpenList(screen: string): RNTesterListAction {
|
||||
return {
|
||||
type: 'RNTesterListAction',
|
||||
screen,
|
||||
};
|
||||
}
|
||||
|
||||
function ExampleAction(openExample: string): RNTesterExampleAction {
|
||||
return {
|
||||
type: 'RNTesterExampleAction',
|
||||
openExample,
|
||||
};
|
||||
}
|
||||
|
||||
const RNTesterActions = {
|
||||
Back,
|
||||
OpenList,
|
||||
ExampleAction,
|
||||
};
|
||||
|
||||
module.exports = RNTesterActions;
|
|
@ -1,190 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import {Platform, Linking} from 'react-native';
|
||||
import {AsyncStorage} from 'react-native';
|
||||
const RNTesterNavigationReducer = require('./RNTesterNavigationReducer');
|
||||
const URIActionMap = require('./URIActionMap');
|
||||
import type {RNTesterExample} from '../types/RNTesterTypes';
|
||||
|
||||
const APP_STATE_KEY = 'RNTesterAppState.v2';
|
||||
|
||||
type Context = $FlowFixMe;
|
||||
|
||||
export const initializeAsyncStore = (context: Context) => {
|
||||
Linking.getInitialURL().then(url => {
|
||||
AsyncStorage.getItem(APP_STATE_KEY, (err, storedString) => {
|
||||
const exampleAction = URIActionMap(
|
||||
context.props.exampleFromAppetizeParams,
|
||||
);
|
||||
const urlAction = URIActionMap(url);
|
||||
const launchAction = exampleAction || urlAction;
|
||||
if (err || !storedString) {
|
||||
const initialAction = launchAction || {type: 'RNTesterListAction'};
|
||||
context.setState(
|
||||
RNTesterNavigationReducer(context.state, initialAction),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const storedState = JSON.parse(storedString);
|
||||
if (launchAction) {
|
||||
context.setState(RNTesterNavigationReducer(storedState, launchAction));
|
||||
return;
|
||||
}
|
||||
context.setState({
|
||||
openExample: storedState.openExample,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
if (Platform.OS === 'ios') {
|
||||
Linking.addEventListener('url', url => {
|
||||
context._handleAction(URIActionMap(url));
|
||||
});
|
||||
}
|
||||
|
||||
AsyncStorage.getItem('Components', (err, storedString) => {
|
||||
if (err || !storedString) {
|
||||
return;
|
||||
}
|
||||
const components = JSON.parse(storedString);
|
||||
context.setState({
|
||||
Components: components,
|
||||
});
|
||||
});
|
||||
AsyncStorage.getItem('Api', (err, storedString) => {
|
||||
if (err || !storedString) {
|
||||
return;
|
||||
}
|
||||
const api = JSON.parse(storedString);
|
||||
context.setState({
|
||||
Api: api,
|
||||
});
|
||||
});
|
||||
AsyncStorage.getItem('RecentComponents', (err, storedString) => {
|
||||
if (err || !storedString) {
|
||||
return;
|
||||
}
|
||||
const recentComponents = JSON.parse(storedString);
|
||||
context.setState({
|
||||
recentComponents: recentComponents,
|
||||
});
|
||||
});
|
||||
AsyncStorage.getItem('RecentApi', (err, storedString) => {
|
||||
if (err || !storedString) {
|
||||
return;
|
||||
}
|
||||
const recentApis = JSON.parse(storedString);
|
||||
context.setState({
|
||||
recentApis: recentApis,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const addApi = (
|
||||
apiName: string,
|
||||
api: RNTesterExample,
|
||||
context: $FlowFixMe,
|
||||
) => {
|
||||
const stateApi = Object.assign({}, context.state.Api);
|
||||
stateApi[apiName] = api;
|
||||
context.setState({
|
||||
Api: stateApi,
|
||||
});
|
||||
// Syncing the bookmarks over async storage
|
||||
AsyncStorage.setItem('Api', JSON.stringify(stateApi));
|
||||
};
|
||||
|
||||
export const addComponent = (
|
||||
componentName: string,
|
||||
component: RNTesterExample,
|
||||
context: Context,
|
||||
) => {
|
||||
const stateComponent = Object.assign({}, context.state.Components);
|
||||
stateComponent[componentName] = component;
|
||||
context.setState({
|
||||
Components: stateComponent,
|
||||
});
|
||||
// Syncing the bookmarks over async storage
|
||||
AsyncStorage.setItem('Components', JSON.stringify(stateComponent));
|
||||
};
|
||||
|
||||
export const removeApi = (apiName: string, context: Context) => {
|
||||
const stateApi = Object.assign({}, context.state.Api);
|
||||
delete stateApi[apiName];
|
||||
context.setState({
|
||||
Api: stateApi,
|
||||
});
|
||||
AsyncStorage.setItem('Api', JSON.stringify(stateApi));
|
||||
};
|
||||
|
||||
export const removeComponent = (componentName: string, context: Context) => {
|
||||
const stateComponent = Object.assign({}, context.state.Components);
|
||||
delete stateComponent[componentName];
|
||||
context.setState({
|
||||
Components: stateComponent,
|
||||
});
|
||||
AsyncStorage.setItem('Components', JSON.stringify(stateComponent));
|
||||
};
|
||||
|
||||
export const checkBookmarks = (
|
||||
title: string,
|
||||
key: string,
|
||||
context: Context,
|
||||
): boolean => {
|
||||
if (key === 'APIS' || key === 'RECENT_APIS') {
|
||||
return context.state.Api[title] === undefined;
|
||||
}
|
||||
return context.state.Components[title] === undefined;
|
||||
};
|
||||
|
||||
export const updateRecentlyViewedList = (
|
||||
item: RNTesterExample,
|
||||
key: string,
|
||||
context: Context,
|
||||
) => {
|
||||
const openedItem = item;
|
||||
if (key === 'COMPONENTS' || key === 'RECENT_COMPONENTS') {
|
||||
let componentsCopy = [...context.state.recentComponents];
|
||||
const ind = componentsCopy.findIndex(
|
||||
component => component.key === openedItem.key,
|
||||
);
|
||||
if (ind !== -1) {
|
||||
componentsCopy.splice(ind, 1);
|
||||
}
|
||||
if (context.state.recentComponents.length >= 5) {
|
||||
componentsCopy.pop();
|
||||
}
|
||||
componentsCopy.unshift(openedItem);
|
||||
context.setState({
|
||||
recentComponents: componentsCopy,
|
||||
});
|
||||
// Syncing the recently viewed components over async storage
|
||||
AsyncStorage.setItem('RecentComponents', JSON.stringify(componentsCopy));
|
||||
} else {
|
||||
let apisCopy = [...context.state.recentApis];
|
||||
const ind = apisCopy.findIndex(api => api.key === openedItem.key);
|
||||
if (ind !== -1) {
|
||||
apisCopy.splice(ind, 1);
|
||||
}
|
||||
if (context.state.recentApis.length >= 5) {
|
||||
apisCopy.pop();
|
||||
}
|
||||
apisCopy.unshift(openedItem);
|
||||
context.setState({
|
||||
recentApis: apisCopy,
|
||||
});
|
||||
// Syncing the recently viewed apis over async storage
|
||||
AsyncStorage.setItem('RecentApi', JSON.stringify(apisCopy));
|
||||
}
|
||||
};
|
|
@ -1,74 +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 RNTesterList = require('./RNTesterList');
|
||||
import type {RNTesterExample} from '../types/RNTesterTypes';
|
||||
|
||||
export type RNTesterNavigationState = {
|
||||
openExample: ?string,
|
||||
screen: string,
|
||||
Components: {...},
|
||||
Api: {...},
|
||||
recentComponents: Array<RNTesterExample>,
|
||||
recentApis: Array<RNTesterExample>,
|
||||
AddApi: (apiName: string, api: RNTesterExample) => mixed,
|
||||
AddComponent: (componentName: string, component: RNTesterExample) => mixed,
|
||||
RemoveApi: (apiName: string) => mixed,
|
||||
RemoveComponent: (componentName: string) => mixed,
|
||||
checkBookmark: (title: string, key: string) => mixed,
|
||||
updateRecentlyViewedList: (item: RNTesterExample, key: string) => mixed,
|
||||
...
|
||||
};
|
||||
|
||||
function RNTesterNavigationReducer(
|
||||
state: RNTesterNavigationState,
|
||||
action: any,
|
||||
): RNTesterNavigationState {
|
||||
if (
|
||||
// Default value is to see example list
|
||||
!state ||
|
||||
// Handle the explicit list action
|
||||
action.type === 'RNTesterListAction' ||
|
||||
// Handle requests to go back to the list when an example is open
|
||||
(state.openExample && action.type === 'RNTesterBackAction')
|
||||
) {
|
||||
return {
|
||||
...state,
|
||||
screen: action.screen ?? 'component',
|
||||
// A null openExample will cause the views to display the RNTester example list
|
||||
openExample: null,
|
||||
};
|
||||
}
|
||||
|
||||
if (action.screen === 'bookmark' && action.type === 'RNTesterBackAction') {
|
||||
return {
|
||||
...state,
|
||||
screen: 'component',
|
||||
openExample: null,
|
||||
};
|
||||
}
|
||||
|
||||
if (action.type === 'RNTesterExampleAction') {
|
||||
// Make sure we see the module before returning the new state
|
||||
const ExampleModule = RNTesterList.Modules[action.openExample];
|
||||
if (ExampleModule) {
|
||||
return {
|
||||
...state,
|
||||
openExample: action.openExample,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
module.exports = RNTesterNavigationReducer;
|
|
@ -0,0 +1,111 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and 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 {RNTesterState, ComponentList} from '../types/RNTesterTypes';
|
||||
|
||||
export const RNTesterActionsType = {
|
||||
INIT_FROM_STORAGE: 'INIT_FROM_STORAGE',
|
||||
NAVBAR_PRESS: 'NAVBAR_PRESS',
|
||||
EXAMPLE_CARD_PRESS: 'EXAMPLE_CARD_PRESS',
|
||||
BOOKMARK_PRESS: 'BOOKMARK_PRESS',
|
||||
BACK_BUTTON_PRESS: 'BACK_BUTTON_PRESS',
|
||||
};
|
||||
|
||||
const getUpdatedBookmarks = ({
|
||||
exampleType,
|
||||
key,
|
||||
bookmarks,
|
||||
}: {
|
||||
exampleType: string,
|
||||
key: string,
|
||||
bookmarks: ComponentList,
|
||||
}) => {
|
||||
const updatedBookmarks = bookmarks
|
||||
? {...bookmarks}
|
||||
: {components: [], apis: []};
|
||||
|
||||
if (updatedBookmarks[exampleType].includes(key)) {
|
||||
updatedBookmarks[exampleType] = updatedBookmarks[exampleType].filter(
|
||||
k => k !== key,
|
||||
);
|
||||
} else {
|
||||
updatedBookmarks[exampleType].push(key);
|
||||
}
|
||||
return updatedBookmarks;
|
||||
};
|
||||
|
||||
const getUpdatedRecentlyUsed = ({
|
||||
exampleType,
|
||||
key,
|
||||
recentlyUsed,
|
||||
}: {
|
||||
exampleType: string,
|
||||
key: string,
|
||||
recentlyUsed: ComponentList,
|
||||
}) => {
|
||||
const updatedRecentlyUsed = recentlyUsed
|
||||
? {...recentlyUsed}
|
||||
: {components: [], apis: []};
|
||||
|
||||
let existingKeys = updatedRecentlyUsed[exampleType];
|
||||
|
||||
if (existingKeys.includes(key)) {
|
||||
existingKeys = existingKeys.filter(k => k !== key);
|
||||
}
|
||||
existingKeys.unshift(key);
|
||||
|
||||
updatedRecentlyUsed[exampleType] = existingKeys.slice(0, 5);
|
||||
|
||||
return updatedRecentlyUsed;
|
||||
};
|
||||
|
||||
export const RNTesterReducer = (
|
||||
state: RNTesterState,
|
||||
action: {type: string, data: any},
|
||||
): RNTesterState => {
|
||||
switch (action.type) {
|
||||
case RNTesterActionsType.INIT_FROM_STORAGE:
|
||||
return action.data;
|
||||
case RNTesterActionsType.NAVBAR_PRESS:
|
||||
return {
|
||||
...state,
|
||||
openExample: null,
|
||||
screen: action.data.screen,
|
||||
};
|
||||
case RNTesterActionsType.EXAMPLE_CARD_PRESS:
|
||||
return {
|
||||
...state,
|
||||
openExample: action.data.key,
|
||||
recentlyUsed: getUpdatedRecentlyUsed({
|
||||
exampleType: action.data.exampleType,
|
||||
key: action.data.key,
|
||||
recentlyUsed: state.recentlyUsed,
|
||||
}),
|
||||
};
|
||||
case RNTesterActionsType.BOOKMARK_PRESS:
|
||||
return {
|
||||
...state,
|
||||
bookmarks: getUpdatedBookmarks({
|
||||
exampleType: action.data.exampleType,
|
||||
key: action.data.key,
|
||||
bookmarks: state.bookmarks,
|
||||
}),
|
||||
};
|
||||
case RNTesterActionsType.BACK_BUTTON_PRESS:
|
||||
return {
|
||||
...state,
|
||||
openExample: null,
|
||||
};
|
||||
default:
|
||||
throw new Error(`Invalid action type ${action.type}`);
|
||||
}
|
||||
};
|
|
@ -1,48 +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 ReactNative = require('react-native');
|
||||
const RNTesterActions = require('./RNTesterActions');
|
||||
const RNTesterList = require('./RNTesterList');
|
||||
|
||||
const {Alert} = ReactNative;
|
||||
|
||||
import type {RNTesterAction} from './RNTesterActions';
|
||||
|
||||
function PathActionMap(path: string): ?RNTesterAction {
|
||||
// Warning! Hacky parsing for example code. Use a library for this!
|
||||
const exampleParts = path.split('/example/');
|
||||
const exampleKey = exampleParts[1];
|
||||
if (exampleKey) {
|
||||
if (!RNTesterList.Modules[exampleKey]) {
|
||||
Alert.alert(`${exampleKey} example could not be found!`);
|
||||
return null;
|
||||
}
|
||||
return RNTesterActions.ExampleAction(exampleKey);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function URIActionMap(uri: ?string): ?RNTesterAction {
|
||||
if (!uri) {
|
||||
return null;
|
||||
}
|
||||
// Warning! Hacky parsing for example code. Use a library for this!
|
||||
const parts = uri.split('rntester:/');
|
||||
if (!parts[1]) {
|
||||
return null;
|
||||
}
|
||||
const path = parts[1];
|
||||
return PathActionMap(path);
|
||||
}
|
||||
|
||||
module.exports = URIActionMap;
|
|
@ -0,0 +1,142 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and 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 {AsyncStorage} from 'react-native';
|
||||
|
||||
import RNTesterList from './RNTesterList';
|
||||
|
||||
import type {
|
||||
ExamplesList,
|
||||
RNTesterState,
|
||||
ComponentList,
|
||||
} from '../types/RNTesterTypes';
|
||||
|
||||
export const Screens = {
|
||||
COMPONENTS: 'components',
|
||||
APIS: 'apis',
|
||||
BOOKMARKS: 'bookmarks',
|
||||
};
|
||||
|
||||
export const initialState: RNTesterState = {
|
||||
openExample: null,
|
||||
screen: null,
|
||||
bookmarks: null,
|
||||
recentlyUsed: null,
|
||||
};
|
||||
|
||||
const filterEmptySections = (examplesList: ExamplesList): any => {
|
||||
const filteredSections = {};
|
||||
const sectionKeys = Object.keys(examplesList);
|
||||
|
||||
sectionKeys.forEach(key => {
|
||||
filteredSections[key] = examplesList[key].filter(
|
||||
section => section.data.length > 0,
|
||||
);
|
||||
});
|
||||
|
||||
return filteredSections;
|
||||
};
|
||||
|
||||
export const getExamplesListWithBookmarksAndRecentlyUsed = ({
|
||||
bookmarks,
|
||||
recentlyUsed,
|
||||
}: {
|
||||
bookmarks: ComponentList,
|
||||
recentlyUsed: ComponentList,
|
||||
}): ExamplesList | null => {
|
||||
// Return early if state has not been initialized from storage
|
||||
if (!bookmarks || !recentlyUsed) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const components = RNTesterList.ComponentExamples.map(c => ({
|
||||
...c,
|
||||
isBookmarked: bookmarks.components.includes(c.key),
|
||||
exampleType: Screens.COMPONENTS,
|
||||
}));
|
||||
|
||||
const recentlyUsedComponents = recentlyUsed.components
|
||||
.map(k => components.find(c => c.key === k))
|
||||
.filter(Boolean);
|
||||
|
||||
const bookmarkedComponents = components.filter(c => c.isBookmarked);
|
||||
|
||||
const apis = RNTesterList.APIExamples.map(c => ({
|
||||
...c,
|
||||
isBookmarked: bookmarks.apis.includes(c.key),
|
||||
exampleType: Screens.APIS,
|
||||
}));
|
||||
|
||||
const recentlyUsedAPIs = recentlyUsed.apis
|
||||
.map(k => apis.find(c => c.key === k))
|
||||
.filter(Boolean);
|
||||
|
||||
const bookmarkedAPIs = apis.filter(c => c.isBookmarked);
|
||||
|
||||
const examplesList: ExamplesList = {
|
||||
[Screens.COMPONENTS]: [
|
||||
{
|
||||
key: 'RECENT_COMPONENTS',
|
||||
data: recentlyUsedComponents,
|
||||
title: 'Recently Viewed',
|
||||
},
|
||||
{
|
||||
key: 'COMPONENTS',
|
||||
data: components,
|
||||
title: 'Components',
|
||||
},
|
||||
],
|
||||
[Screens.APIS]: [
|
||||
{
|
||||
key: 'RECENT_APIS',
|
||||
data: recentlyUsedAPIs,
|
||||
title: 'Recently viewed',
|
||||
},
|
||||
{
|
||||
key: 'APIS',
|
||||
data: apis,
|
||||
title: 'APIs',
|
||||
},
|
||||
],
|
||||
[Screens.BOOKMARKS]: [
|
||||
{
|
||||
key: 'COMPONENTS',
|
||||
data: bookmarkedComponents,
|
||||
title: 'Components',
|
||||
},
|
||||
{
|
||||
key: 'APIS',
|
||||
data: bookmarkedAPIs,
|
||||
title: 'APIs',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
return filterEmptySections(examplesList);
|
||||
};
|
||||
|
||||
export const getInitialStateFromAsyncStorage = async (
|
||||
storageKey: string,
|
||||
): Promise<RNTesterState> => {
|
||||
const initialStateString = await AsyncStorage.getItem(storageKey);
|
||||
|
||||
if (!initialStateString) {
|
||||
return {
|
||||
openExample: null,
|
||||
screen: Screens.COMPONENTS,
|
||||
bookmarks: {components: [], apis: []},
|
||||
recentlyUsed: {components: [], apis: []},
|
||||
};
|
||||
} else {
|
||||
return JSON.parse(initialStateString);
|
||||
}
|
||||
};
|
|
@ -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.
|
||||
*
|
||||
* @format
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as React from 'react';
|
||||
import {AsyncStorage} from 'react-native';
|
||||
|
||||
import type {RNTesterState} from '../types/RNTesterTypes';
|
||||
|
||||
export const useAsyncStorageReducer = (
|
||||
reducer: Function,
|
||||
initialState: RNTesterState,
|
||||
storageKey: string,
|
||||
): [RNTesterState, Function] => {
|
||||
const [state, dispatch] = React.useReducer<Function, Object>(
|
||||
reducer,
|
||||
initialState,
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (state !== initialState) {
|
||||
AsyncStorage.setItem(storageKey, JSON.stringify(state));
|
||||
}
|
||||
}, [state, storageKey, initialState]);
|
||||
|
||||
return [state, dispatch];
|
||||
};
|
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"baseVersion": "0.0.0-5bc67b658",
|
||||
"baseVersion": "0.0.0-f0e80ae22",
|
||||
"overrides": [
|
||||
{
|
||||
"type": "copy",
|
||||
"directory": "js",
|
||||
"baseDirectory": "packages/rn-tester/js",
|
||||
"baseHash": "c758fbc9a4b64d2bd5a049179fb7d27af2efd5c3",
|
||||
"baseHash": "0a19766b09b7fc4d3ccb7744b8a5ef0347c8a733",
|
||||
"issue": 4054
|
||||
},
|
||||
{
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
},
|
||||
"peerDependencies": {
|
||||
"react": "16.13.1",
|
||||
"react-native": "0.0.0-5bc67b658"
|
||||
"react-native": "0.0.0-f0e80ae22"
|
||||
},
|
||||
"devDependencies": {
|
||||
"react-native-platform-override": "^0.4.0"
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
"@react-native-windows/tester": "0.0.1",
|
||||
"prompt-sync": "^4.2.0",
|
||||
"react": "16.13.1",
|
||||
"react-native": "0.0.0-5bc67b658",
|
||||
"react-native": "0.0.0-f0e80ae22",
|
||||
"react-native-windows": "0.0.0-canary.190"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* Licensed under the MIT License.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
import { TREE_DUMP_RESULT } from '@react-native-windows/tester/js/examples-win/LegacyTests/Consts';
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* Licensed under the MIT License.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
import { BasePage, By } from './BasePage';
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
"dependencies": {
|
||||
"chai": "^4.2.0",
|
||||
"react": "16.13.1",
|
||||
"react-native": "0.0.0-5bc67b658",
|
||||
"react-native": "0.0.0-f0e80ae22",
|
||||
"react-native-windows": "^0.0.0-canary.190"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"react": "16.13.1",
|
||||
"react-native": "0.0.0-5bc67b658",
|
||||
"react-native": "0.0.0-f0e80ae22",
|
||||
"react-native-windows": "0.0.0-canary.190"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
"dependencies": {
|
||||
"@react-native-windows/tester": "0.0.1",
|
||||
"react": "16.13.1",
|
||||
"react-native": "0.0.0-5bc67b658",
|
||||
"react-native": "0.0.0-f0e80ae22",
|
||||
"react-native-windows": "0.0.0-canary.190"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -5,13 +5,13 @@
|
|||
"excludePatterns": [
|
||||
"src/js/examples-win32/**"
|
||||
],
|
||||
"baseVersion": "0.0.0-5bc67b658",
|
||||
"baseVersion": "0.0.0-f0e80ae22",
|
||||
"overrides": [
|
||||
{
|
||||
"type": "patch",
|
||||
"file": "src/js/components/ExamplePage.win32.js",
|
||||
"baseFile": "packages/rn-tester/js/components/ExamplePage.js",
|
||||
"baseHash": "7d97d2dd62d2055c1e2e7bd69ce93e1b6ec1c2c0",
|
||||
"baseHash": "929a58e006b074189564a856cfc5dd7a132205a6",
|
||||
"issue": 4050
|
||||
},
|
||||
{
|
||||
|
@ -20,11 +20,18 @@
|
|||
"baseFile": "packages/rn-tester/js/components/ListExampleShared.js",
|
||||
"baseHash": "d7be07e3fd8d9c1df8e23d5674ce3eb067d00865"
|
||||
},
|
||||
{
|
||||
"type": "patch",
|
||||
"file": "src/js/components/RNTesterEmptyBookmarksState.win32.js",
|
||||
"baseFile": "packages/rn-tester/js/components/RNTesterEmptyBookmarksState.js",
|
||||
"baseHash": "312a8f4a51f942df975f865638570a5349c0cd3f",
|
||||
"issue": 6341
|
||||
},
|
||||
{
|
||||
"type": "patch",
|
||||
"file": "src/js/components/RNTesterExampleFilter.win32.js",
|
||||
"baseFile": "packages/rn-tester/js/components/RNTesterExampleFilter.js",
|
||||
"baseHash": "7f3f22f1c2643b730bbd1e3d633c263dcd6a0a6f"
|
||||
"baseHash": "20e35122c8529a5bf848f91d9ea9b85be3c23882"
|
||||
},
|
||||
{
|
||||
"type": "patch",
|
||||
|
@ -41,24 +48,38 @@
|
|||
"issue": 6210
|
||||
},
|
||||
{
|
||||
"type": "derived",
|
||||
"type": "copy",
|
||||
"file": "src/js/RNTesterApp.win32.js",
|
||||
"baseFile": "packages/rn-tester/js/RNTesterApp.ios.js",
|
||||
"baseHash": "b86a1fd9363b807c340c58135e610bdae8ee2fae",
|
||||
"baseFile": "packages/rn-tester/js/RNTesterApp.android.js",
|
||||
"baseHash": "30f3ef9bdc0e2c337309079831664c4a596c404f",
|
||||
"issue": 4586
|
||||
},
|
||||
{
|
||||
"type": "derived",
|
||||
"file": "src/js/utils/RNTesterAsyncStorageAbstraction.win32.js",
|
||||
"baseFile": "packages/rn-tester/js/utils/RNTesterAsyncStorageAbstraction.js",
|
||||
"baseHash": "a00e706027e10d9c6d98ab3febd6a6f1e947ae5e",
|
||||
"issue": 6316
|
||||
},
|
||||
{
|
||||
"type": "derived",
|
||||
"file": "src/js/utils/RNTesterList.win32.js",
|
||||
"baseFile": "packages/rn-tester/js/utils/RNTesterList.android.js",
|
||||
"baseHash": "6e0d7dd2c48c2a46cb746cfbd56cdafd141ef3b5"
|
||||
},
|
||||
{
|
||||
"type": "patch",
|
||||
"file": "src/js/utils/RNTesterStatePersister.win32.js",
|
||||
"baseFile": "packages/rn-tester/js/utils/RNTesterStatePersister.js",
|
||||
"baseHash": "b15ee55c3730ae01faa39fad54158596061a1a49",
|
||||
"issue": 6316
|
||||
},
|
||||
{
|
||||
"type": "patch",
|
||||
"file": "src/js/utils/testerStateUtils.win32.js",
|
||||
"baseFile": "packages/rn-tester/js/utils/testerStateUtils.js",
|
||||
"baseHash": "dd1a238d51ec4926a3cb82a92994cfc3507e16f7",
|
||||
"issue": 6316
|
||||
},
|
||||
{
|
||||
"type": "patch",
|
||||
"file": "src/js/utils/useAsyncStorageReducer.win32.js",
|
||||
"baseFile": "packages/rn-tester/js/utils/useAsyncStorageReducer.js",
|
||||
"baseHash": "dd12805229a025d0c45f676d6c535f2f19386025",
|
||||
"issue": 6316
|
||||
}
|
||||
]
|
||||
}
|
|
@ -15,7 +15,7 @@
|
|||
},
|
||||
"peerDependencies": {
|
||||
"@office-iss/react-native-win32": "^0.0.0-canary.59",
|
||||
"react-native": "0.0.0-5bc67b658"
|
||||
"react-native": "0.0.0-f0e80ae22"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@office-iss/react-native-win32": "^0.0.0-canary.59",
|
||||
|
@ -23,7 +23,7 @@
|
|||
"@rnw-scripts/ts-config": "0.1.0",
|
||||
"eslint": "6.8.0",
|
||||
"just-scripts": "^0.44.7",
|
||||
"react-native": "0.0.0-5bc67b658",
|
||||
"react-native": "0.0.0-f0e80ae22",
|
||||
"react-native-platform-override": "^0.4.0",
|
||||
"typescript": "^3.8.3"
|
||||
}
|
||||
|
|
|
@ -10,361 +10,10 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const RNTesterActions = require('./utils/RNTesterActions');
|
||||
const RNTesterExampleContainer = require('./components/RNTesterExampleContainer');
|
||||
const RNTesterExampleList = require('./components/RNTesterExampleList');
|
||||
const RNTesterList = require('./utils/RNTesterList'); // [Win32] Remove .ios
|
||||
const RNTesterNavigationReducer = require('./utils/RNTesterNavigationReducer');
|
||||
const React = require('react');
|
||||
// const SnapshotViewIOS = require('./examples/Snapshot/SnapshotViewIOS.ios'); [Win32]
|
||||
const RNTesterNavbar = require('./components/RNTesterNavbar');
|
||||
import {AppRegistry} from 'react-native';
|
||||
|
||||
const {
|
||||
AppRegistry,
|
||||
// AsyncStorage, [Win32]
|
||||
// BackHandler, [Win32]
|
||||
Button,
|
||||
Platform,
|
||||
SafeAreaView,
|
||||
StyleSheet,
|
||||
Text,
|
||||
useColorScheme,
|
||||
View,
|
||||
LogBox,
|
||||
} = require('react-native');
|
||||
|
||||
import type {RNTesterExample} from './types/RNTesterTypes';
|
||||
import type {
|
||||
RNTesterAction,
|
||||
RNTesterExampleAction,
|
||||
} from './utils/RNTesterActions';
|
||||
import type {RNTesterNavigationState} from './utils/RNTesterNavigationReducer';
|
||||
import {RNTesterThemeContext, themes} from './components/RNTesterTheme';
|
||||
import RNTesterDocumentationURL from './components/RNTesterDocumentationURL';
|
||||
import type {ColorSchemeName} from '../../../Libraries/Utilities/NativeAppearance';
|
||||
import {
|
||||
RNTesterBookmarkContext,
|
||||
bookmarks,
|
||||
} from './components/RNTesterBookmark';
|
||||
import type {RNTesterBookmark} from './components/RNTesterBookmark';
|
||||
|
||||
type Props = {exampleFromAppetizeParams?: ?string, ...};
|
||||
|
||||
import {
|
||||
initializeAsyncStore,
|
||||
addApi,
|
||||
addComponent,
|
||||
removeApi,
|
||||
removeComponent,
|
||||
checkBookmarks,
|
||||
updateRecentlyViewedList,
|
||||
} from './utils/RNTesterAsyncStorageAbstraction';
|
||||
|
||||
// const APP_STATE_KEY = 'RNTesterAppState.v2'; [Win32]
|
||||
|
||||
const Header = ({
|
||||
onBack,
|
||||
title,
|
||||
documentationURL,
|
||||
}: {
|
||||
onBack?: () => mixed,
|
||||
title: string,
|
||||
documentationURL?: string,
|
||||
...
|
||||
}) => (
|
||||
<RNTesterThemeContext.Consumer>
|
||||
{theme => {
|
||||
return (
|
||||
<SafeAreaView
|
||||
style={[
|
||||
styles.headerContainer,
|
||||
{
|
||||
borderBottomColor: theme.SeparatorColor,
|
||||
backgroundColor: theme.TertiarySystemBackgroundColor,
|
||||
},
|
||||
]}>
|
||||
<View style={styles.header}>
|
||||
<View style={styles.headerCenter}>
|
||||
<Text style={[styles.title, {color: theme.LabelColor}]}>
|
||||
{title}
|
||||
</Text>
|
||||
{documentationURL && (
|
||||
<RNTesterDocumentationURL documentationURL={documentationURL} />
|
||||
)}
|
||||
</View>
|
||||
{onBack && (
|
||||
<View>
|
||||
<Button
|
||||
title="Back"
|
||||
onPress={onBack}
|
||||
color={Platform.select({
|
||||
ios: theme.LinkColor,
|
||||
default: undefined,
|
||||
})}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}}
|
||||
</RNTesterThemeContext.Consumer>
|
||||
);
|
||||
|
||||
const RNTesterExampleContainerViaHook = ({
|
||||
onBack,
|
||||
title,
|
||||
module,
|
||||
}: {
|
||||
onBack?: () => mixed,
|
||||
title: string,
|
||||
module: RNTesterExample,
|
||||
...
|
||||
}) => {
|
||||
const colorScheme: ?ColorSchemeName = useColorScheme();
|
||||
const theme = colorScheme === 'dark' ? themes.dark : themes.light;
|
||||
return (
|
||||
<RNTesterThemeContext.Provider value={theme}>
|
||||
<View style={styles.exampleContainer}>
|
||||
<Header
|
||||
title={title}
|
||||
onBack={onBack}
|
||||
documentationURL={module.documentationURL}
|
||||
/>
|
||||
<RNTesterExampleContainer module={module} />
|
||||
</View>
|
||||
</RNTesterThemeContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
const RNTesterExampleListViaHook = ({
|
||||
onNavigate,
|
||||
UpdateRecentlyViewedList,
|
||||
recentComponents,
|
||||
recentApis,
|
||||
bookmark,
|
||||
list,
|
||||
screen,
|
||||
}: {
|
||||
onNavigate?: (item: RNTesterExampleAction, key: string) => mixed,
|
||||
UpdateRecentlyViewedList?: (item: RNTesterExample, key: string) => mixed,
|
||||
recentComponents: Array<RNTesterExample>,
|
||||
recentApis: Array<RNTesterExample>,
|
||||
bookmark: RNTesterBookmark,
|
||||
screen: string,
|
||||
list: {
|
||||
ComponentExamples: Array<RNTesterExample>,
|
||||
APIExamples: Array<RNTesterExample>,
|
||||
...
|
||||
},
|
||||
...
|
||||
}) => {
|
||||
const colorScheme: ?ColorSchemeName = useColorScheme();
|
||||
const theme = colorScheme === 'dark' ? themes.dark : themes.light;
|
||||
const exampleTitle =
|
||||
screen === 'component'
|
||||
? 'Component Store'
|
||||
: screen === 'api'
|
||||
? 'API Store'
|
||||
: 'Bookmarks';
|
||||
return (
|
||||
<RNTesterThemeContext.Provider value={theme}>
|
||||
<RNTesterBookmarkContext.Provider value={bookmark}>
|
||||
<View style={styles.exampleContainer}>
|
||||
<Header title={exampleTitle} />
|
||||
<RNTesterExampleList
|
||||
onNavigate={onNavigate}
|
||||
recentComponents={recentComponents}
|
||||
recentApis={recentApis}
|
||||
updateRecentlyViewedList={UpdateRecentlyViewedList}
|
||||
list={list}
|
||||
screen={screen}
|
||||
/>
|
||||
</View>
|
||||
</RNTesterBookmarkContext.Provider>
|
||||
</RNTesterThemeContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
class RNTesterApp extends React.Component<Props, RNTesterNavigationState> {
|
||||
_mounted: boolean;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
// RNTester App currently uses Async Storage from react-native for storing navigation state
|
||||
// and bookmark items.
|
||||
// TODO: Add Native Async Storage Module in RNTester
|
||||
LogBox.ignoreLogs([new RegExp('has been extracted from react-native')]);
|
||||
|
||||
this.state = {
|
||||
openExample: null,
|
||||
screen: 'component',
|
||||
Components: bookmarks.Components,
|
||||
Api: bookmarks.Api,
|
||||
recentComponents: [],
|
||||
recentApis: [],
|
||||
AddApi: (apiName, api) => addApi(apiName, api, this),
|
||||
AddComponent: (componentName, component) =>
|
||||
addComponent(componentName, component, this),
|
||||
RemoveApi: apiName => removeApi(apiName, this),
|
||||
RemoveComponent: componentName => removeComponent(componentName, this),
|
||||
checkBookmark: (title, key) => checkBookmarks(title, key, this),
|
||||
updateRecentlyViewedList: (item, key) =>
|
||||
updateRecentlyViewedList(item, key, this),
|
||||
};
|
||||
}
|
||||
|
||||
UNSAFE_componentWillMount() {
|
||||
// [Win32 BackHandler not implemented
|
||||
// BackHandler.addEventListener('hardwareBackPress', this._handleBack);
|
||||
// Win32]
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
initializeAsyncStore(this);
|
||||
}
|
||||
|
||||
_handleBack = () => {
|
||||
this._handleAction(RNTesterActions.Back(this.state.screen));
|
||||
};
|
||||
|
||||
_handleAction = (action: ?RNTesterAction) => {
|
||||
if (!action) {
|
||||
return;
|
||||
}
|
||||
const newState = RNTesterNavigationReducer(this.state, action);
|
||||
if (this.state !== newState) {
|
||||
this.setState(newState); // [Win32] Remove AsyncStorage usage
|
||||
}
|
||||
};
|
||||
|
||||
render(): React.Node | null {
|
||||
const bookmark = {
|
||||
Components: this.state.Components,
|
||||
Api: this.state.Api,
|
||||
AddApi: this.state.AddApi,
|
||||
AddComponent: this.state.AddComponent,
|
||||
RemoveApi: this.state.RemoveApi,
|
||||
RemoveComponent: this.state.RemoveComponent,
|
||||
checkBookmark: this.state.checkBookmark,
|
||||
};
|
||||
|
||||
if (!this.state) {
|
||||
return null;
|
||||
}
|
||||
if (this.state.openExample) {
|
||||
const Component = RNTesterList.Modules[this.state.openExample];
|
||||
if (Component && Component.external) {
|
||||
return <Component onExampleExit={this._handleBack} />;
|
||||
} else {
|
||||
return (
|
||||
<>
|
||||
<RNTesterExampleContainerViaHook
|
||||
onBack={this._handleBack}
|
||||
title={Component.title}
|
||||
module={Component}
|
||||
/>
|
||||
<View style={styles.bottomNavbar}>
|
||||
<RNTesterNavbar onNavigate={this._handleAction} />
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<RNTesterExampleListViaHook
|
||||
key={this.state.screen}
|
||||
title={'RNTester'}
|
||||
onNavigate={this._handleAction}
|
||||
UpdateRecentlyViewedList={this.state.updateRecentlyViewedList}
|
||||
recentComponents={this.state.recentComponents}
|
||||
recentApis={this.state.recentApis}
|
||||
bookmark={bookmark}
|
||||
list={RNTesterList}
|
||||
screen={this.state.screen}
|
||||
/>
|
||||
<View style={styles.bottomNavbar}>
|
||||
<RNTesterNavbar
|
||||
screen={this.state.screen}
|
||||
onNavigate={this._handleAction}
|
||||
/>
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
headerContainer: {
|
||||
borderBottomWidth: StyleSheet.hairlineWidth,
|
||||
},
|
||||
header: {
|
||||
height: 40,
|
||||
flexDirection: 'row',
|
||||
},
|
||||
headerCenter: {
|
||||
flex: 1,
|
||||
position: 'absolute',
|
||||
top: 7,
|
||||
left: 0,
|
||||
right: 0,
|
||||
alignItems: 'center',
|
||||
},
|
||||
title: {
|
||||
fontSize: 19,
|
||||
fontWeight: '600',
|
||||
textAlign: 'center',
|
||||
},
|
||||
exampleContainer: {
|
||||
flex: 1,
|
||||
},
|
||||
bottomNavbar: {
|
||||
bottom: 0,
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
position: 'absolute',
|
||||
},
|
||||
});
|
||||
// [Win32
|
||||
// AppRegistry.registerComponent('SetPropertiesExampleApp', () =>
|
||||
// require('./examples/SetPropertiesExample/SetPropertiesExampleApp'),
|
||||
// );
|
||||
// AppRegistry.registerComponent('RootViewSizeFlexibilityExampleApp', () =>
|
||||
// require('./examples/RootViewSizeFlexibilityExample/RootViewSizeFlexibilityExampleApp'),
|
||||
// );
|
||||
// Win32]
|
||||
import RNTesterApp from './RNTesterAppShared';
|
||||
|
||||
AppRegistry.registerComponent('RNTesterApp', () => RNTesterApp);
|
||||
|
||||
// [Win32
|
||||
// // Register suitable examples for snapshot tests
|
||||
// RNTesterList.ComponentExamples.concat(RNTesterList.APIExamples).forEach(
|
||||
// (Example: RNTesterExample) => {
|
||||
// const ExampleModule = Example.module;
|
||||
// if (ExampleModule.displayName) {
|
||||
// class Snapshotter extends React.Component<{...}> {
|
||||
// render() {
|
||||
// return (
|
||||
// <SnapshotViewIOS>
|
||||
// <RNTesterExampleContainer module={ExampleModule} />
|
||||
// </SnapshotViewIOS>
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
// AppRegistry.registerComponent(
|
||||
// ExampleModule.displayName,
|
||||
// () => Snapshotter,
|
||||
// );
|
||||
// }
|
||||
// },
|
||||
// );
|
||||
// Win32]
|
||||
|
||||
module.exports = RNTesterApp;
|
||||
|
|
|
@ -36,7 +36,7 @@ export default function ExamplePage(props: Props): React.Node {
|
|||
return (
|
||||
<>
|
||||
<View style={styles.titleView}>
|
||||
<Text style={{marginVertical: 8, fontSize: 16}}>{description}</Text>
|
||||
<Text style={styles.description}>{description}</Text>
|
||||
<View style={styles.rowStyle}>
|
||||
<Text style={{color: theme.SecondaryLabelColor, width: 65}}>
|
||||
{category || 'Other'}
|
||||
|
@ -80,9 +80,8 @@ const styles = StyleSheet.create({
|
|||
flexGrow: 1,
|
||||
},
|
||||
description: {
|
||||
paddingVertical: 5,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
marginVertical: 8,
|
||||
fontSize: 16,
|
||||
},
|
||||
docsContainer: {
|
||||
alignContent: 'center',
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and 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 * as React from 'react';
|
||||
import {View, Image, Text, StyleSheet} from 'react-native';
|
||||
|
||||
export const RNTesterEmptyBookmarksState = (): React.Node => (
|
||||
<View style={styles.emptyContainer}>
|
||||
<View style={styles.emptyContainerInner}>
|
||||
<Image
|
||||
source={require('../assets/empty.png')}
|
||||
resizeMode="contain"
|
||||
style={styles.emptyImage}
|
||||
/>
|
||||
<View>
|
||||
<Text style={styles.heading}>Bookmarks are empty</Text>
|
||||
<Text style={styles.subheading}>
|
||||
Please tap the{' '}
|
||||
{/* [Win32] remove the image since nested non-Text in text is unsupported in NetUI*/}
|
||||
icon to bookmark examples.
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
emptyContainer: {
|
||||
flex: 1,
|
||||
paddingHorizontal: 40,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: 'white',
|
||||
},
|
||||
emptyContainerInner: {
|
||||
marginTop: -150,
|
||||
},
|
||||
emptyImage: {
|
||||
maxWidth: '100%',
|
||||
height: 300,
|
||||
},
|
||||
heading: {
|
||||
fontSize: 24,
|
||||
textAlign: 'center',
|
||||
},
|
||||
subheading: {
|
||||
fontSize: 16,
|
||||
textAlign: 'center',
|
||||
},
|
||||
bookmarkIcon: {
|
||||
width: 24,
|
||||
height: 24,
|
||||
transform: [{translateY: 4}],
|
||||
},
|
||||
});
|
|
@ -22,18 +22,16 @@ const {
|
|||
import {RNTesterThemeContext} from './RNTesterTheme';
|
||||
import type {RNTesterExample} from '../types/RNTesterTypes';
|
||||
|
||||
import type {SectionData} from '../types/RNTesterTypes';
|
||||
|
||||
type Props = {
|
||||
filter: Function,
|
||||
render: Function,
|
||||
disableSearch?: boolean,
|
||||
testID?: string,
|
||||
hideFilterPills?: boolean,
|
||||
page: string, // possible values -> examples_page, components_page, bookmarks_page
|
||||
sections: Array<{
|
||||
data: Array<RNTesterExample>,
|
||||
title: string,
|
||||
key: string,
|
||||
}>,
|
||||
page: 'examples_page' | 'components_page' | 'bookmarks_page',
|
||||
sections: SectionData[],
|
||||
...
|
||||
};
|
||||
|
||||
|
@ -71,7 +69,7 @@ class RNTesterExampleFilter extends React.Component<Props, State> {
|
|||
|
||||
if (this.state.filter.trim() !== '' || this.state.category.trim() !== '') {
|
||||
filteredSections = filteredSections.filter(
|
||||
section => section.title !== 'Recently viewed',
|
||||
section => section.title !== 'Recently Viewed',
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,115 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import type {RNTesterExample} from '../types/RNTesterTypes';
|
||||
|
||||
type Context = $FlowFixMe;
|
||||
|
||||
export const initializeAsyncStore = (_context: Context) => {
|
||||
// Stubbed on Win32 due to lack of linking + AsyncStorage in Rex
|
||||
};
|
||||
|
||||
export const addApi = (
|
||||
apiName: string,
|
||||
api: RNTesterExample,
|
||||
context: $FlowFixMe,
|
||||
) => {
|
||||
const stateApi = Object.assign({}, context.state.Api);
|
||||
stateApi[apiName] = api;
|
||||
context.setState({
|
||||
Api: stateApi,
|
||||
});
|
||||
};
|
||||
|
||||
export const addComponent = (
|
||||
componentName: string,
|
||||
component: RNTesterExample,
|
||||
context: Context,
|
||||
) => {
|
||||
const stateComponent = Object.assign({}, context.state.Components);
|
||||
stateComponent[componentName] = component;
|
||||
context.setState({
|
||||
Components: stateComponent,
|
||||
});
|
||||
// Syncing the bookmarks over async storage
|
||||
// AsyncStorage.setItem('Components', JSON.stringify(stateComponent)); [Win32]
|
||||
};
|
||||
|
||||
export const removeApi = (apiName: string, context: Context) => {
|
||||
const stateApi = Object.assign({}, context.state.Api);
|
||||
delete stateApi[apiName];
|
||||
context.setState({
|
||||
Api: stateApi,
|
||||
});
|
||||
// AsyncStorage.setItem('Api', JSON.stringify(stateApi)); [Win32]
|
||||
};
|
||||
|
||||
export const removeComponent = (componentName: string, context: Context) => {
|
||||
const stateComponent = Object.assign({}, context.state.Components);
|
||||
delete stateComponent[componentName];
|
||||
context.setState({
|
||||
Components: stateComponent,
|
||||
});
|
||||
// AsyncStorage.setItem('Components', JSON.stringify(stateComponent)); [Win32]
|
||||
};
|
||||
|
||||
export const checkBookmarks = (
|
||||
title: string,
|
||||
key: string,
|
||||
context: Context,
|
||||
): boolean => {
|
||||
if (key === 'APIS' || key === 'RECENT_APIS') {
|
||||
return context.state.Api[title] === undefined;
|
||||
}
|
||||
return context.state.Components[title] === undefined;
|
||||
};
|
||||
|
||||
export const updateRecentlyViewedList = (
|
||||
item: RNTesterExample,
|
||||
key: string,
|
||||
context: Context,
|
||||
) => {
|
||||
const openedItem = item;
|
||||
if (key === 'COMPONENTS' || key === 'RECENT_COMPONENTS') {
|
||||
let componentsCopy = [...context.state.recentComponents];
|
||||
const ind = componentsCopy.findIndex(
|
||||
component => component.key === openedItem.key,
|
||||
);
|
||||
if (ind !== -1) {
|
||||
componentsCopy.splice(ind, 1);
|
||||
}
|
||||
if (context.state.recentComponents.length >= 5) {
|
||||
componentsCopy.pop();
|
||||
}
|
||||
componentsCopy.unshift(openedItem);
|
||||
context.setState({
|
||||
recentComponents: componentsCopy,
|
||||
});
|
||||
// Syncing the recently viewed components over async storage
|
||||
// AsyncStorage.setItem('RecentComponents', JSON.stringify(componentsCopy)); [Win32]
|
||||
} else {
|
||||
let apisCopy = [...context.state.recentApis];
|
||||
const ind = apisCopy.findIndex(api => api.key === openedItem.key);
|
||||
if (ind !== -1) {
|
||||
apisCopy.splice(ind, 1);
|
||||
}
|
||||
if (context.state.recentApis.length >= 5) {
|
||||
apisCopy.pop();
|
||||
}
|
||||
apisCopy.unshift(openedItem);
|
||||
context.setState({
|
||||
recentApis: apisCopy,
|
||||
});
|
||||
// Syncing the recently viewed apis over async storage
|
||||
// AsyncStorage.setItem('RecentApi', JSON.stringify(apisCopy)); [Win32]
|
||||
}
|
||||
};
|
|
@ -0,0 +1,86 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and 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');
|
||||
// import {AsyncStorage} from 'react-native'; [Win32] #6316
|
||||
|
||||
export type PassProps<State> = {
|
||||
state: State,
|
||||
setState: (stateLamda: (state: State) => State) => void,
|
||||
...
|
||||
};
|
||||
|
||||
/**
|
||||
* A simple container for persisting some state and passing it into the wrapped component as
|
||||
* `props.persister.state`. Update it with `props.persister.setState`. The component is initially
|
||||
* rendered using `getInitialState` in the spec and is then re-rendered with the persisted data
|
||||
* once it's fetched.
|
||||
*
|
||||
* This is currently tied to RNTester because it's generally not good to use AsyncStorage like
|
||||
* this in real apps with user data, but we could maybe pull it out for other internal settings-type
|
||||
* usage.
|
||||
*/
|
||||
function createContainer<Props: Object, State>(
|
||||
Component: React.ComponentType<Props & {persister: PassProps<State>, ...}>,
|
||||
spec: {
|
||||
cacheKeySuffix: (props: Props) => string,
|
||||
getInitialState: (props: Props) => State,
|
||||
version?: string,
|
||||
...
|
||||
},
|
||||
): React.ComponentType<Props> {
|
||||
return class ComponentWithPersistedState extends React.Component<
|
||||
Props,
|
||||
$FlowFixMeState,
|
||||
> {
|
||||
static displayName = `RNTesterStatePersister(${String(
|
||||
Component.displayName ?? Component.name,
|
||||
)})`;
|
||||
state = {value: spec.getInitialState(this.props)};
|
||||
_cacheKey = `RNTester:${spec.version || 'v1'}:${spec.cacheKeySuffix(
|
||||
this.props,
|
||||
)}`;
|
||||
componentDidMount() {
|
||||
/* [Win32 #6316
|
||||
AsyncStorage.getItem(this._cacheKey, (err, value) => {
|
||||
if (!err && value) {
|
||||
this.setState({value: JSON.parse(value)});
|
||||
}
|
||||
});
|
||||
Win32] */
|
||||
}
|
||||
_passSetState = (stateLamda: (state: State) => State): void => {
|
||||
this.setState(state => {
|
||||
const value = stateLamda(state.value);
|
||||
// AsyncStorage.setItem(this._cacheKey, JSON.stringify(value)); [Win32] #6316
|
||||
return {value};
|
||||
});
|
||||
};
|
||||
render(): React.Node {
|
||||
return (
|
||||
<Component
|
||||
{...this.props}
|
||||
persister={{
|
||||
state: this.state.value,
|
||||
setState: this._passSetState,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const RNTesterStatePersister = {
|
||||
createContainer,
|
||||
};
|
||||
|
||||
module.exports = RNTesterStatePersister;
|
|
@ -0,0 +1,144 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and 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 {AsyncStorage} from 'react-native'; [Win32] #6316
|
||||
|
||||
import RNTesterList from './RNTesterList';
|
||||
|
||||
import type {
|
||||
ExamplesList,
|
||||
RNTesterState,
|
||||
ComponentList,
|
||||
} from '../types/RNTesterTypes';
|
||||
|
||||
export const Screens = {
|
||||
COMPONENTS: 'components',
|
||||
APIS: 'apis',
|
||||
BOOKMARKS: 'bookmarks',
|
||||
};
|
||||
|
||||
export const initialState: RNTesterState = {
|
||||
openExample: null,
|
||||
screen: null,
|
||||
bookmarks: null,
|
||||
recentlyUsed: null,
|
||||
};
|
||||
|
||||
const filterEmptySections = (examplesList: ExamplesList): any => {
|
||||
const filteredSections = {};
|
||||
const sectionKeys = Object.keys(examplesList);
|
||||
|
||||
sectionKeys.forEach(key => {
|
||||
filteredSections[key] = examplesList[key].filter(
|
||||
section => section.data.length > 0,
|
||||
);
|
||||
});
|
||||
|
||||
return filteredSections;
|
||||
};
|
||||
|
||||
export const getExamplesListWithBookmarksAndRecentlyUsed = ({
|
||||
bookmarks,
|
||||
recentlyUsed,
|
||||
}: {
|
||||
bookmarks: ComponentList,
|
||||
recentlyUsed: ComponentList,
|
||||
}): ExamplesList | null => {
|
||||
// Return early if state has not been initialized from storage
|
||||
if (!bookmarks || !recentlyUsed) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const components = RNTesterList.ComponentExamples.map(c => ({
|
||||
...c,
|
||||
isBookmarked: bookmarks.components.includes(c.key),
|
||||
exampleType: Screens.COMPONENTS,
|
||||
}));
|
||||
|
||||
const recentlyUsedComponents = recentlyUsed.components
|
||||
.map(k => components.find(c => c.key === k))
|
||||
.filter(Boolean);
|
||||
|
||||
const bookmarkedComponents = components.filter(c => c.isBookmarked);
|
||||
|
||||
const apis = RNTesterList.APIExamples.map(c => ({
|
||||
...c,
|
||||
isBookmarked: bookmarks.apis.includes(c.key),
|
||||
exampleType: Screens.APIS,
|
||||
}));
|
||||
|
||||
const recentlyUsedAPIs = recentlyUsed.apis
|
||||
.map(k => apis.find(c => c.key === k))
|
||||
.filter(Boolean);
|
||||
|
||||
const bookmarkedAPIs = apis.filter(c => c.isBookmarked);
|
||||
|
||||
const examplesList: ExamplesList = {
|
||||
[Screens.COMPONENTS]: [
|
||||
{
|
||||
key: 'RECENT_COMPONENTS',
|
||||
data: recentlyUsedComponents,
|
||||
title: 'Recently Viewed',
|
||||
},
|
||||
{
|
||||
key: 'COMPONENTS',
|
||||
data: components,
|
||||
title: 'Components',
|
||||
},
|
||||
],
|
||||
[Screens.APIS]: [
|
||||
{
|
||||
key: 'RECENT_APIS',
|
||||
data: recentlyUsedAPIs,
|
||||
title: 'Recently viewed',
|
||||
},
|
||||
{
|
||||
key: 'APIS',
|
||||
data: apis,
|
||||
title: 'APIs',
|
||||
},
|
||||
],
|
||||
[Screens.BOOKMARKS]: [
|
||||
{
|
||||
key: 'COMPONENTS',
|
||||
data: bookmarkedComponents,
|
||||
title: 'Components',
|
||||
},
|
||||
{
|
||||
key: 'APIS',
|
||||
data: bookmarkedAPIs,
|
||||
title: 'APIs',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
return filterEmptySections(examplesList);
|
||||
};
|
||||
|
||||
export const getInitialStateFromAsyncStorage = async (
|
||||
storageKey: string,
|
||||
): Promise<RNTesterState> => {
|
||||
// [Win32 #6316
|
||||
const initialStateString = null;
|
||||
// Win32]
|
||||
|
||||
if (!initialStateString) {
|
||||
return {
|
||||
openExample: null,
|
||||
screen: Screens.COMPONENTS,
|
||||
bookmarks: {components: [], apis: []},
|
||||
recentlyUsed: {components: [], apis: []},
|
||||
};
|
||||
} else {
|
||||
return JSON.parse(initialStateString);
|
||||
}
|
||||
};
|
|
@ -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.
|
||||
*
|
||||
* @format
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as React from 'react';
|
||||
// import {AsyncStorage} from 'react-native'; [Win32] #6316
|
||||
|
||||
import type {RNTesterState} from '../types/RNTesterTypes';
|
||||
|
||||
export const useAsyncStorageReducer = (
|
||||
reducer: Function,
|
||||
initialState: RNTesterState,
|
||||
storageKey: string,
|
||||
): [RNTesterState, Function] => {
|
||||
const [state, dispatch] = React.useReducer<Function, Object>(
|
||||
reducer,
|
||||
initialState,
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (state !== initialState) {
|
||||
// AsyncStorage.setItem(storageKey, JSON.stringify(state)); [Win32] #6316
|
||||
}
|
||||
}, [state, storageKey, initialState]);
|
||||
|
||||
return [state, dispatch];
|
||||
};
|
|
@ -50,14 +50,6 @@
|
|||
; Ignore "BUCK" generated dirs
|
||||
<PROJECT_ROOT>/\.buckd/
|
||||
|
||||
; Ignore unexpected extra "@providesModule"
|
||||
.*/node_modules/.*/node_modules/fbjs/.*
|
||||
|
||||
; These should not be required directly
|
||||
; require from fbjs/lib instead: require('fbjs/lib/warning')
|
||||
.*/node_modules/warning/.*
|
||||
|
||||
|
||||
; Ignore the src folder - flow files are combined with ones from react-native into the root Libraries folder
|
||||
.*/react-native-win32/src/.*
|
||||
|
||||
|
|
|
@ -4,13 +4,13 @@
|
|||
"flow-typed",
|
||||
"src/**"
|
||||
],
|
||||
"baseVersion": "0.0.0-5bc67b658",
|
||||
"baseVersion": "0.0.0-f0e80ae22",
|
||||
"overrides": [
|
||||
{
|
||||
"type": "derived",
|
||||
"file": ".flowconfig",
|
||||
"baseFile": ".flowconfig",
|
||||
"baseHash": "a02ec80bfa99acea12365f29e51b898a074e362a"
|
||||
"baseHash": "86d79e561c8ce6b2dd89ba20ec7d42246cb2a50f"
|
||||
},
|
||||
{
|
||||
"type": "copy",
|
||||
|
@ -23,7 +23,7 @@
|
|||
"type": "derived",
|
||||
"file": "src/index.win32.js",
|
||||
"baseFile": "index.js",
|
||||
"baseHash": "717b73b2397607b3d0a74534cc3360a1be627906"
|
||||
"baseHash": "a26839159af016e9fb20dc4c18b3c744cde55cc1"
|
||||
},
|
||||
{
|
||||
"type": "patch",
|
||||
|
@ -154,7 +154,7 @@
|
|||
"type": "derived",
|
||||
"file": "src/Libraries/Components/TextInput/TextInput.win32.tsx",
|
||||
"baseFile": "Libraries/Components/TextInput/TextInput.js",
|
||||
"baseHash": "05c8c1e9142210b472c9c1ce891314b786ecc50f"
|
||||
"baseHash": "b49b732f6a88bdc4e5783b5ac2339ee6105523fd"
|
||||
},
|
||||
{
|
||||
"type": "patch",
|
||||
|
@ -383,7 +383,7 @@
|
|||
"type": "derived",
|
||||
"file": "src/Libraries/Utilities/Platform.win32.js",
|
||||
"baseFile": "Libraries/Utilities/Platform.android.js",
|
||||
"baseHash": "750d5a0afc192d9ec98c27d28402285c9e3155a0"
|
||||
"baseHash": "1e689ecb36aaa20e7b60b5f6e7620785e3826e0a"
|
||||
},
|
||||
{
|
||||
"type": "platform",
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
"art": "^0.10.0",
|
||||
"base64-js": "^1.1.2",
|
||||
"event-target-shim": "^5.0.1",
|
||||
"fbjs": "^1.0.0",
|
||||
"fbjs-scripts": "^1.1.0",
|
||||
"hermes-engine": "~0.6.0",
|
||||
"invariant": "^2.2.4",
|
||||
|
@ -71,14 +70,14 @@
|
|||
"just-scripts": "^0.44.7",
|
||||
"prettier": "1.19.1",
|
||||
"react": "16.13.1",
|
||||
"react-native": "0.0.0-5bc67b658",
|
||||
"react-native": "0.0.0-f0e80ae22",
|
||||
"react-native-platform-override": "^0.4.0",
|
||||
"react-shallow-renderer": "^16.13.1",
|
||||
"typescript": "^3.8.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "16.13.1",
|
||||
"react-native": "0.0.0-5bc67b658"
|
||||
"react-native": "0.0.0-f0e80ae22"
|
||||
},
|
||||
"beachball": {
|
||||
"defaultNpmTag": "canary",
|
||||
|
|
|
@ -374,7 +374,7 @@ module.exports = {
|
|||
.default;
|
||||
},
|
||||
get NativeEventEmitter(): NativeEventEmitter {
|
||||
return require('./Libraries/EventEmitter/NativeEventEmitter');
|
||||
return require('./Libraries/EventEmitter/NativeEventEmitter').default;
|
||||
},
|
||||
get Networking(): Networking {
|
||||
return require('./Libraries/Network/RCTNetworking');
|
||||
|
@ -455,7 +455,7 @@ module.exports = {
|
|||
|
||||
// Plugins
|
||||
get DeviceEventEmitter(): RCTDeviceEventEmitter {
|
||||
return require('./Libraries/EventEmitter/RCTDeviceEventEmitter');
|
||||
return require('./Libraries/EventEmitter/RCTDeviceEventEmitter').default;
|
||||
},
|
||||
get NativeAppEventEmitter(): RCTNativeAppEventEmitter {
|
||||
return require('./Libraries/EventEmitter/RCTNativeAppEventEmitter');
|
||||
|
|
|
@ -57,14 +57,6 @@
|
|||
; Ignore "BUCK" generated dirs
|
||||
<PROJECT_ROOT>/\.buckd/
|
||||
|
||||
; Ignore unexpected extra "@providesModule"
|
||||
.*/node_modules/.*/node_modules/fbjs/.*
|
||||
|
||||
; These should not be required directly
|
||||
; require from fbjs/lib instead: require('fbjs/lib/warning')
|
||||
.*/node_modules/warning/.*
|
||||
|
||||
|
||||
; Ignore the src folder - flow files are combined with ones from react-native into the root Libraries folder
|
||||
.*/vnext/src/.*
|
||||
|
||||
|
|
|
@ -12,13 +12,13 @@
|
|||
"src/tsconfig.json",
|
||||
"**/*.windesktop.js"
|
||||
],
|
||||
"baseVersion": "0.0.0-5bc67b658",
|
||||
"baseVersion": "0.0.0-f0e80ae22",
|
||||
"overrides": [
|
||||
{
|
||||
"type": "derived",
|
||||
"file": ".flowconfig",
|
||||
"baseFile": ".flowconfig",
|
||||
"baseHash": "a02ec80bfa99acea12365f29e51b898a074e362a"
|
||||
"baseHash": "86d79e561c8ce6b2dd89ba20ec7d42246cb2a50f"
|
||||
},
|
||||
{
|
||||
"type": "patch",
|
||||
|
@ -66,7 +66,7 @@
|
|||
"type": "derived",
|
||||
"file": "src/index.windows.js",
|
||||
"baseFile": "index.js",
|
||||
"baseHash": "717b73b2397607b3d0a74534cc3360a1be627906"
|
||||
"baseHash": "a26839159af016e9fb20dc4c18b3c744cde55cc1"
|
||||
},
|
||||
{
|
||||
"type": "platform",
|
||||
|
@ -249,7 +249,7 @@
|
|||
"type": "patch",
|
||||
"file": "src/Libraries/Components/TextInput/TextInput.windows.js",
|
||||
"baseFile": "Libraries/Components/TextInput/TextInput.js",
|
||||
"baseHash": "05c8c1e9142210b472c9c1ce891314b786ecc50f"
|
||||
"baseHash": "b49b732f6a88bdc4e5783b5ac2339ee6105523fd"
|
||||
},
|
||||
{
|
||||
"type": "patch",
|
||||
|
@ -405,7 +405,7 @@
|
|||
"type": "derived",
|
||||
"file": "src/Libraries/Utilities/Platform.windows.js",
|
||||
"baseFile": "Libraries/Utilities/Platform.android.js",
|
||||
"baseHash": "750d5a0afc192d9ec98c27d28402285c9e3155a0"
|
||||
"baseHash": "1e689ecb36aaa20e7b60b5f6e7620785e3826e0a"
|
||||
},
|
||||
{
|
||||
"type": "platform",
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
"anser": "^1.4.9",
|
||||
"base64-js": "^1.1.2",
|
||||
"event-target-shim": "^5.0.1",
|
||||
"fbjs": "^1.0.0",
|
||||
"fbjs-scripts": "^1.1.0",
|
||||
"hermes-engine": "~0.6.0",
|
||||
"invariant": "^2.2.4",
|
||||
|
@ -69,7 +68,7 @@
|
|||
"just-scripts": "^0.44.7",
|
||||
"prettier": "1.19.1",
|
||||
"react": "16.13.1",
|
||||
"react-native": "0.0.0-5bc67b658",
|
||||
"react-native": "0.0.0-f0e80ae22",
|
||||
"react-native-platform-override": "^0.4.0",
|
||||
"react-native-windows-codegen": "0.1.7",
|
||||
"react-refresh": "^0.4.0",
|
||||
|
@ -78,7 +77,7 @@
|
|||
},
|
||||
"peerDependencies": {
|
||||
"react": "16.13.1",
|
||||
"react-native": "0.0.0-5bc67b658"
|
||||
"react-native": "0.0.0-f0e80ae22"
|
||||
},
|
||||
"beachball": {
|
||||
"defaultNpmTag": "canary",
|
||||
|
|
|
@ -496,6 +496,7 @@ export type Props = $ReadOnly<{|
|
|||
* The following values work on Android only:
|
||||
*
|
||||
* - `visible-password`
|
||||
*
|
||||
*/
|
||||
keyboardType?: ?KeyboardType,
|
||||
|
||||
|
@ -692,7 +693,12 @@ export type Props = $ReadOnly<{|
|
|||
|
||||
/**
|
||||
* If `true`, caret is hidden. The default value is `false`.
|
||||
* This property is supported only for single-line TextInput component on iOS.
|
||||
*
|
||||
* On Android devices manufactured by Xiaomi with Android Q,
|
||||
* when keyboardType equals 'email-address'this will be set
|
||||
* in native to 'true' to prevent a system related crash. This
|
||||
* will cause cursor to be diabled as a side-effect.
|
||||
*
|
||||
*/
|
||||
caretHidden?: ?boolean,
|
||||
|
||||
|
|
|
@ -369,7 +369,7 @@ module.exports = {
|
|||
.default;
|
||||
},
|
||||
get NativeEventEmitter(): NativeEventEmitter {
|
||||
return require('./Libraries/EventEmitter/NativeEventEmitter');
|
||||
return require('./Libraries/EventEmitter/NativeEventEmitter').default;
|
||||
},
|
||||
// $FlowFixMe[value-as-type]
|
||||
get Networking(): Networking {
|
||||
|
@ -451,7 +451,7 @@ module.exports = {
|
|||
|
||||
// Plugins
|
||||
get DeviceEventEmitter(): RCTDeviceEventEmitter {
|
||||
return require('./Libraries/EventEmitter/RCTDeviceEventEmitter');
|
||||
return require('./Libraries/EventEmitter/RCTDeviceEventEmitter').default;
|
||||
},
|
||||
get NativeAppEventEmitter(): RCTNativeAppEventEmitter {
|
||||
return require('./Libraries/EventEmitter/RCTNativeAppEventEmitter');
|
||||
|
|
|
@ -12074,10 +12074,10 @@ react-native-tscodegen@0.66.1:
|
|||
nullthrows "1.1.1"
|
||||
typescript "^3.5.3"
|
||||
|
||||
react-native@0.0.0-5bc67b658:
|
||||
version "0.0.0-5bc67b658"
|
||||
resolved "https://registry.yarnpkg.com/react-native/-/react-native-0.0.0-5bc67b658.tgz#926ce3dfa5683f9de303a33ae0c767b440df88ec"
|
||||
integrity sha512-ozYlcZKJ0YZNg1Q876YlKhcOykAaZrTNh7W7K3k415ySDAGfGr7RmhI6cbot7/2bQbMnFhnVR3sc/fh3589WxQ==
|
||||
react-native@0.0.0-f0e80ae22:
|
||||
version "0.0.0-f0e80ae22"
|
||||
resolved "https://registry.yarnpkg.com/react-native/-/react-native-0.0.0-f0e80ae22.tgz#f83cf1c102a24e2840da2400ee5eabbca0f9a4c8"
|
||||
integrity sha512-ojn3pfFo9MpX2pjUipmVBaC+6w6niNnoZYZCyAbOqlg6I7aLAU7jnq3Za7izsDeFbViJ3ezXflIvzjQ3zcntVA==
|
||||
dependencies:
|
||||
"@react-native-community/cli" "^4.10.0"
|
||||
"@react-native-community/cli-platform-android" "^4.10.0"
|
||||
|
@ -12089,7 +12089,6 @@ react-native@0.0.0-5bc67b658:
|
|||
anser "^1.4.9"
|
||||
base64-js "^1.1.2"
|
||||
event-target-shim "^5.0.1"
|
||||
fbjs "^1.0.0"
|
||||
fbjs-scripts "^1.1.0"
|
||||
hermes-engine "~0.6.0"
|
||||
invariant "^2.2.4"
|
||||
|
|
Загрузка…
Ссылка в новой задаче