mirror of
https://github.com/status-im/react-native.git
synced 2025-02-23 22:58:19 +00:00
Summary: **Problem:** When you type an invalid regex into the input field of the RNTester app, it crashes. What's worse is that it remembers the input string so refreshing the view doesn't get rid of the error. Observe: https://pxl.cl/jdm3 Reviewed By: yungsters Differential Revision: D10349249 fbshipit-source-id: aab5977bd47271e9a4ff6202c93b47550da778d2
263 lines
6.9 KiB
JavaScript
263 lines
6.9 KiB
JavaScript
/**
|
|
* Copyright (c) Facebook, Inc. and 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 Platform = require('Platform');
|
|
const React = require('react');
|
|
const SectionList = require('SectionList');
|
|
const StyleSheet = require('StyleSheet');
|
|
const Text = require('Text');
|
|
const TextInput = require('TextInput');
|
|
const TouchableHighlight = require('TouchableHighlight');
|
|
const RNTesterActions = require('./RNTesterActions');
|
|
const RNTesterStatePersister = require('./RNTesterStatePersister');
|
|
const View = require('View');
|
|
|
|
/* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found when
|
|
* making Flow check .android.js files. */
|
|
import type {RNTesterExample} from './RNTesterList.ios';
|
|
import type {PassProps} from './RNTesterStatePersister';
|
|
import type {TextStyleProp, ViewStyleProp} from 'StyleSheet';
|
|
|
|
type Props = {
|
|
onNavigate: Function,
|
|
list: {
|
|
ComponentExamples: Array<RNTesterExample>,
|
|
APIExamples: Array<RNTesterExample>,
|
|
},
|
|
persister: PassProps<*>,
|
|
searchTextInputStyle: TextStyleProp,
|
|
style?: ?ViewStyleProp,
|
|
};
|
|
|
|
class RowComponent extends React.PureComponent<{
|
|
item: Object,
|
|
onNavigate: Function,
|
|
onPress?: Function,
|
|
onShowUnderlay?: Function,
|
|
onHideUnderlay?: Function,
|
|
}> {
|
|
_onPress = () => {
|
|
if (this.props.onPress) {
|
|
this.props.onPress();
|
|
return;
|
|
}
|
|
this.props.onNavigate(RNTesterActions.ExampleAction(this.props.item.key));
|
|
};
|
|
render() {
|
|
const {item} = this.props;
|
|
return (
|
|
<TouchableHighlight
|
|
onShowUnderlay={this.props.onShowUnderlay}
|
|
onHideUnderlay={this.props.onHideUnderlay}
|
|
onPress={this._onPress}>
|
|
<View style={styles.row}>
|
|
<Text style={styles.rowTitleText}>{item.module.title}</Text>
|
|
<Text style={styles.rowDetailText}>{item.module.description}</Text>
|
|
</View>
|
|
</TouchableHighlight>
|
|
);
|
|
}
|
|
}
|
|
|
|
const renderSectionHeader = ({section}) => (
|
|
<Text style={styles.sectionHeader}>{section.title}</Text>
|
|
);
|
|
|
|
class RNTesterExampleList extends React.Component<Props, $FlowFixMeState> {
|
|
render() {
|
|
const filterText = this.props.persister.state.filter;
|
|
let filterRegex = /.*/;
|
|
|
|
try {
|
|
filterRegex = new RegExp(String(filterText), 'i');
|
|
} catch (error) {
|
|
console.warn(
|
|
'Failed to create RegExp: %s\n%s',
|
|
filterText,
|
|
error.message,
|
|
);
|
|
}
|
|
|
|
const filter = example =>
|
|
/* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an
|
|
* error found when Flow v0.68 was deployed. To see the error delete this
|
|
* comment and run Flow. */
|
|
this.props.disableSearch ||
|
|
(filterRegex.test(example.module.title) &&
|
|
(!Platform.isTV || example.supportsTVOS));
|
|
|
|
const sections = [
|
|
{
|
|
data: this.props.list.ComponentExamples.filter(filter),
|
|
title: 'COMPONENTS',
|
|
key: 'c',
|
|
},
|
|
{
|
|
data: this.props.list.APIExamples.filter(filter),
|
|
title: 'APIS',
|
|
key: 'a',
|
|
},
|
|
];
|
|
return (
|
|
<View style={[styles.listContainer, this.props.style]}>
|
|
{this._renderTitleRow()}
|
|
{this._renderTextInput()}
|
|
<SectionList
|
|
ItemSeparatorComponent={ItemSeparator}
|
|
contentContainerStyle={{backgroundColor: 'white'}}
|
|
style={styles.list}
|
|
sections={sections}
|
|
renderItem={this._renderItem}
|
|
enableEmptySections={true}
|
|
itemShouldUpdate={this._itemShouldUpdate}
|
|
keyboardShouldPersistTaps="handled"
|
|
automaticallyAdjustContentInsets={false}
|
|
keyboardDismissMode="on-drag"
|
|
renderSectionHeader={renderSectionHeader}
|
|
/>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
_itemShouldUpdate(curr, prev) {
|
|
return curr.item !== prev.item;
|
|
}
|
|
|
|
_renderItem = ({item, separators}) => (
|
|
<RowComponent
|
|
item={item}
|
|
onNavigate={this.props.onNavigate}
|
|
onShowUnderlay={separators.highlight}
|
|
onHideUnderlay={separators.unhighlight}
|
|
/>
|
|
);
|
|
|
|
_renderTitleRow(): ?React.Element<any> {
|
|
/* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an
|
|
* error found when Flow v0.68 was deployed. To see the error delete this
|
|
* comment and run Flow. */
|
|
if (!this.props.displayTitleRow) {
|
|
return null;
|
|
}
|
|
return (
|
|
<RowComponent
|
|
item={{
|
|
module: {
|
|
title: 'RNTester',
|
|
description: 'React Native Examples',
|
|
},
|
|
}}
|
|
onNavigate={this.props.onNavigate}
|
|
onPress={() => {
|
|
this.props.onNavigate(RNTesterActions.ExampleList());
|
|
}}
|
|
/>
|
|
);
|
|
}
|
|
|
|
_renderTextInput(): ?React.Element<any> {
|
|
/* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an
|
|
* error found when Flow v0.68 was deployed. To see the error delete this
|
|
* comment and run Flow. */
|
|
if (this.props.disableSearch) {
|
|
return null;
|
|
}
|
|
return (
|
|
<View style={styles.searchRow}>
|
|
<TextInput
|
|
autoCapitalize="none"
|
|
autoCorrect={false}
|
|
clearButtonMode="always"
|
|
onChangeText={text => {
|
|
this.props.persister.setState(() => ({filter: text}));
|
|
}}
|
|
placeholder="Search..."
|
|
underlineColorAndroid="transparent"
|
|
style={[styles.searchTextInput, this.props.searchTextInputStyle]}
|
|
testID="explorer_search"
|
|
value={this.props.persister.state.filter}
|
|
/>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
_handleRowPress(exampleKey: string): void {
|
|
this.props.onNavigate(RNTesterActions.ExampleAction(exampleKey));
|
|
}
|
|
}
|
|
|
|
const ItemSeparator = ({highlighted}) => (
|
|
<View style={highlighted ? styles.separatorHighlighted : styles.separator} />
|
|
);
|
|
|
|
RNTesterExampleList = RNTesterStatePersister.createContainer(
|
|
RNTesterExampleList,
|
|
{
|
|
cacheKeySuffix: () => 'mainList',
|
|
getInitialState: () => ({filter: ''}),
|
|
},
|
|
);
|
|
|
|
const styles = StyleSheet.create({
|
|
listContainer: {
|
|
flex: 1,
|
|
},
|
|
list: {
|
|
backgroundColor: '#eeeeee',
|
|
},
|
|
sectionHeader: {
|
|
backgroundColor: '#eeeeee',
|
|
padding: 5,
|
|
fontWeight: '500',
|
|
fontSize: 11,
|
|
},
|
|
row: {
|
|
backgroundColor: 'white',
|
|
justifyContent: 'center',
|
|
paddingHorizontal: 15,
|
|
paddingVertical: 8,
|
|
},
|
|
separator: {
|
|
height: StyleSheet.hairlineWidth,
|
|
backgroundColor: '#bbbbbb',
|
|
marginLeft: 15,
|
|
},
|
|
separatorHighlighted: {
|
|
height: StyleSheet.hairlineWidth,
|
|
backgroundColor: 'rgb(217, 217, 217)',
|
|
},
|
|
rowTitleText: {
|
|
fontSize: 17,
|
|
fontWeight: '500',
|
|
},
|
|
rowDetailText: {
|
|
fontSize: 15,
|
|
color: '#888888',
|
|
lineHeight: 20,
|
|
},
|
|
searchRow: {
|
|
backgroundColor: '#eeeeee',
|
|
padding: 10,
|
|
},
|
|
searchTextInput: {
|
|
backgroundColor: 'white',
|
|
borderColor: '#cccccc',
|
|
borderRadius: 3,
|
|
borderWidth: 1,
|
|
paddingLeft: 8,
|
|
paddingVertical: 0,
|
|
height: 35,
|
|
},
|
|
});
|
|
|
|
module.exports = RNTesterExampleList;
|