Support 3 levels of navigation

Summary: Changelog: [Internal] RNTester to support 3 levels of navigation

Reviewed By: kacieb

Differential Revision: D29481463

fbshipit-source-id: e48281cce7fccd7096446c5f0f5583f2588b5028
This commit is contained in:
Luna Wei 2021-07-01 14:33:45 -07:00 коммит произвёл Facebook GitHub Bot
Родитель 8765b93bae
Коммит c06d8d01ca
10 изменённых файлов: 73 добавлений и 14 удалений

Просмотреть файл

@ -111,7 +111,13 @@ const RNTesterApp = (): React.Node => {
); );
const colorScheme = useColorScheme(); const colorScheme = useColorScheme();
const {activeModuleKey, screen, bookmarks, recentlyUsed} = state; const {
activeModuleKey,
activeModuleExampleKey,
screen,
bookmarks,
recentlyUsed,
} = state;
React.useEffect(() => { React.useEffect(() => {
getInitialStateFromAsyncStorage(APP_STATE_KEY).then( getInitialStateFromAsyncStorage(APP_STATE_KEY).then(
@ -166,6 +172,16 @@ const RNTesterApp = (): React.Node => {
[dispatch], [dispatch],
); );
const handleModuleExampleCardPress = React.useCallback(
exampleName => {
dispatch({
type: RNTesterActionsType.EXAMPLE_CARD_PRESS,
data: {key: exampleName},
});
},
[dispatch],
);
const toggleBookmark = React.useCallback( const toggleBookmark = React.useCallback(
({exampleType, key}) => { ({exampleType, key}) => {
dispatch({ dispatch({
@ -194,6 +210,10 @@ const RNTesterApp = (): React.Node => {
const activeModule = const activeModule =
activeModuleKey != null ? RNTesterList.Modules[activeModuleKey] : null; activeModuleKey != null ? RNTesterList.Modules[activeModuleKey] : null;
const activeModuleExample =
activeModuleExampleKey != null
? activeModule?.examples.find(e => e.name === activeModuleExampleKey)
: null;
const title = Screens.COMPONENTS const title = Screens.COMPONENTS
? 'Components' ? 'Components'
: Screens.APIS : Screens.APIS
@ -210,7 +230,11 @@ const RNTesterApp = (): React.Node => {
theme={theme} theme={theme}
documentationURL={activeModule.documentationURL} documentationURL={activeModule.documentationURL}
/> />
<RNTesterModuleContainer module={activeModule} /> <RNTesterModuleContainer
module={activeModule}
example={activeModuleExample}
onExampleCardPress={handleModuleExampleCardPress}
/>
</View> </View>
) : ( ) : (
<ModuleListsContainer <ModuleListsContainer

Просмотреть файл

@ -37,8 +37,8 @@ export default function RNTPressableRow({
rightAddOn, rightAddOn,
bottomAddOn, bottomAddOn,
onPress, onPress,
accessibilityLabel,
style, style,
accessibilityLabel,
}: Props): React.Node { }: Props): React.Node {
const theme = React.useContext(RNTesterThemeContext); const theme = React.useContext(RNTesterThemeContext);
const label = accessibilityLabel ?? `${title} ${description ?? ''}`; const label = accessibilityLabel ?? `${title} ${description ?? ''}`;

Просмотреть файл

@ -8,9 +8,11 @@
*/ */
const React = require('react'); const React = require('react');
const {Platform} = require('react-native');
const RNTesterBlock = require('./RNTesterBlock'); const RNTesterBlock = require('./RNTesterBlock');
const RNTesterExampleFilter = require('./RNTesterExampleFilter'); const RNTesterExampleFilter = require('./RNTesterExampleFilter');
import RNTPressableRow from './RNTPressableRow';
import {RNTesterThemeContext} from './RNTesterTheme';
import {StyleSheet, Platform} from 'react-native';
const invariant = require('invariant'); const invariant = require('invariant');
import ExamplePage from './ExamplePage'; import ExamplePage from './ExamplePage';
@ -30,7 +32,8 @@ function getExampleTitle(title, platform) {
} }
export default function RNTesterModuleContainer(props: Props): React.Node { export default function RNTesterModuleContainer(props: Props): React.Node {
const {module, example} = props; const {module, example, onExampleCardPress} = props;
const theme = React.useContext(RNTesterThemeContext);
const renderExample = (e, i) => { const renderExample = (e, i) => {
// Filter platform-specific es // Filter platform-specific es
const {description, platform} = e; const {description, platform} = e;
@ -38,7 +41,18 @@ export default function RNTesterModuleContainer(props: Props): React.Node {
if (platform != null && Platform.OS !== platform) { if (platform != null && Platform.OS !== platform) {
return null; return null;
} }
return ( return module.showIndividualExamples === true ? (
<RNTPressableRow
key={e.name}
onPress={() => onExampleCardPress(e.name)}
title={e.title}
description={description}
accessibilityLabel={e.name + ' ' + description}
style={StyleSheet.compose(styles.separator, {
borderBottomColor: theme.SeparatorColor,
})}
/>
) : (
<RNTesterBlock <RNTesterBlock
key={i} key={i}
title={getExampleTitle(title, platform)} title={getExampleTitle(title, platform)}
@ -99,12 +113,7 @@ export default function RNTesterModuleContainer(props: Props): React.Node {
documentationURL={module.documentationURL} documentationURL={module.documentationURL}
category={module.category}> category={module.category}>
{module.showIndividualExamples === true && example != null ? ( {module.showIndividualExamples === true && example != null ? (
<RNTesterBlock example.render()
key={example.name}
title={getExampleTitle(example.title, example.platform)}
description={example.description}>
{example.render()}
</RNTesterBlock>
) : ( ) : (
<RNTesterExampleFilter <RNTesterExampleFilter
testID="example_search" testID="example_search"
@ -120,3 +129,13 @@ export default function RNTesterModuleContainer(props: Props): React.Node {
</ExamplePage> </ExamplePage>
); );
} }
const styles = StyleSheet.create({
separator: {
borderBottomWidth: Platform.select({
ios: StyleSheet.hairlineWidth,
android: 0,
}),
marginHorizontal: Platform.select({ios: 15, android: 0}),
},
});

Просмотреть файл

@ -39,6 +39,7 @@ export function SectionList_onEndReached(): React.Node {
export default { export default {
title: 'SectionList Inverted', title: 'SectionList Inverted',
name: 'SectionList-onEndReached', name: 'SectionList-onEndReached',
description: 'Test onEndReached behavior',
render: function(): React.Element<typeof SectionList_onEndReached> { render: function(): React.Element<typeof SectionList_onEndReached> {
return <SectionList_onEndReached />; return <SectionList_onEndReached />;
}, },

Просмотреть файл

@ -44,6 +44,7 @@ export function SectionList_stickySectionHeadersEnabled(): React.Node {
export default { export default {
title: 'SectionList Sticky Headers Enabled', title: 'SectionList Sticky Headers Enabled',
name: 'SectionList-stickyHeadersEnabled', name: 'SectionList-stickyHeadersEnabled',
description: 'Toggle sticky headers on/off',
render: function(): React.Element< render: function(): React.Element<
typeof SectionList_stickySectionHeadersEnabled, typeof SectionList_stickySectionHeadersEnabled,
> { > {

Просмотреть файл

@ -129,7 +129,7 @@ const styles = StyleSheet.create({
height: 40, height: 40,
}, },
output: { output: {
width: '80%', flex: 1,
fontSize: 12, fontSize: 12,
}, },
list: { list: {

Просмотреть файл

@ -22,6 +22,7 @@ exports.title = 'SectionList';
exports.category = 'ListView'; exports.category = 'ListView';
exports.documentationURL = 'https://reactnative.dev/docs/sectionlist'; exports.documentationURL = 'https://reactnative.dev/docs/sectionlist';
exports.description = 'Performant, scrollable list of data.'; exports.description = 'Performant, scrollable list of data.';
exports.showIndividualExamples = true;
exports.examples = [ exports.examples = [
ContentInset, ContentInset,
onEndReached, onEndReached,

Просмотреть файл

@ -61,6 +61,7 @@ export type ComponentList = null | {components: string[], apis: string[]};
export type RNTesterState = { export type RNTesterState = {
activeModuleKey: null | string, activeModuleKey: null | string,
activeModuleExampleKey: null | string,
screen: ScreenTypes, screen: ScreenTypes,
bookmarks: ComponentList, bookmarks: ComponentList,
recentlyUsed: ComponentList, recentlyUsed: ComponentList,

Просмотреть файл

@ -16,6 +16,7 @@ export const RNTesterActionsType = {
BOOKMARK_PRESS: 'BOOKMARK_PRESS', BOOKMARK_PRESS: 'BOOKMARK_PRESS',
BACK_BUTTON_PRESS: 'BACK_BUTTON_PRESS', BACK_BUTTON_PRESS: 'BACK_BUTTON_PRESS',
MODULE_CARD_PRESS: 'MODULE_CARD_PRESS', MODULE_CARD_PRESS: 'MODULE_CARD_PRESS',
EXAMPLE_CARD_PRESS: 'EXAMPLE_CARD_PRESS',
}; };
const getUpdatedBookmarks = ({ const getUpdatedBookmarks = ({
@ -77,18 +78,25 @@ export const RNTesterReducer = (
return { return {
...state, ...state,
activeModuleKey: null, activeModuleKey: null,
activeModuleExampleKey: null,
screen: action.data.screen, screen: action.data.screen,
}; };
case RNTesterActionsType.MODULE_CARD_PRESS: case RNTesterActionsType.MODULE_CARD_PRESS:
return { return {
...state, ...state,
activeModuleKey: action.data.key, activeModuleKey: action.data.key,
activeModuleExampleKey: null,
recentlyUsed: getUpdatedRecentlyUsed({ recentlyUsed: getUpdatedRecentlyUsed({
exampleType: action.data.exampleType, exampleType: action.data.exampleType,
key: action.data.key, key: action.data.key,
recentlyUsed: state.recentlyUsed, recentlyUsed: state.recentlyUsed,
}), }),
}; };
case RNTesterActionsType.EXAMPLE_CARD_PRESS:
return {
...state,
activeModuleExampleKey: action.data.key,
};
case RNTesterActionsType.BOOKMARK_PRESS: case RNTesterActionsType.BOOKMARK_PRESS:
return { return {
...state, ...state,
@ -102,7 +110,9 @@ export const RNTesterReducer = (
// Go back to module or list // Go back to module or list
return { return {
...state, ...state,
activeModuleKey: null, activeModuleExampleKey: null,
activeModuleKey:
state.activeModuleExampleKey != null ? state.activeModuleKey : null,
}; };
default: default:
throw new Error(`Invalid action type ${action.type}`); throw new Error(`Invalid action type ${action.type}`);

Просмотреть файл

@ -26,6 +26,7 @@ export const Screens = {
export const initialState: RNTesterState = { export const initialState: RNTesterState = {
activeModuleKey: null, activeModuleKey: null,
activeModuleExampleKey: null,
screen: null, screen: null,
bookmarks: null, bookmarks: null,
recentlyUsed: null, recentlyUsed: null,
@ -134,6 +135,7 @@ export const getInitialStateFromAsyncStorage = async (
if (!initialStateString) { if (!initialStateString) {
return { return {
activeModuleKey: null, activeModuleKey: null,
activeModuleExampleKey: null,
screen: Screens.COMPONENTS, screen: Screens.COMPONENTS,
bookmarks: {components: [], apis: []}, bookmarks: {components: [], apis: []},
recentlyUsed: {components: [], apis: []}, recentlyUsed: {components: [], apis: []},