I'm learning react native, and I ran into this problem, I'm trying to export a Class to another Screen, but "View config getter callback for component... must be a function" appears, if anyone can help me I'll be extremely grateful, I'll print de code below. Should I change the Class for a function? Is there any other way to export this code as a Class?
import React from 'react';
import { StyleSheet, Dimensions, ScrollView } from 'react-native';
import { Button, Block, Text, Input, theme } from 'galio-framework';
const { width } = Dimensions.get('screen');
export default class menuLateral extends React.Component {
renderSearch = () => {
const { navigation } = this.props;
const iconCamera = <Icon size={16} color={theme.COLORS.MUTED} name="zoom-in" family="material" />
return (
<Input
right
color="black"
style={styles.search}
iconContent={iconCamera}
placeholder="What are you looking for?"
onFocus={() => navigation.navigate('Pro')}
/>
)
}
renderTabs = () => {
const { navigation } = this.props;
return (
<Block row style={styles.tabs}>
<Button shadowless style={[styles.tab, styles.divider]} onPress={() => navigation.navigate('Pro')}>
<Block row middle>
<Icon name="grid" family="feather" style={{ paddingRight: 8 }} />
<Text size={16} style={styles.tabTitle}>Categories</Text>
</Block>
</Button>
<Button shadowless style={styles.tab} onPress={() => navigation.navigate('Pro')}>
<Block row middle>
<Icon size={16} name="camera-18" family="GalioExtra" style={{ paddingRight: 8 }} />
<Text size={16} style={styles.tabTitle}>Best Deals</Text>
</Block>
</Button>
</Block>
)
}
}
const styles = StyleSheet.create({
home: {
width: width,
},
search: {
height: 48,
width: width - 32,
marginHorizontal: 16,
borderWidth: 1,
borderRadius: 3,
},
tabs: {
marginBottom: 24,
marginTop: 10,
elevation: 4,
},
tab: {
backgroundColor: theme.COLORS.TRANSPARENT,
width: width * 0.50,
borderRadius: 0,
borderWidth: 0,
height: 24,
elevation: 0,
},
tabTitle: {
lineHeight: 19,
fontWeight: '300'
},
divider: {
borderRightWidth: 0.3,
borderRightColor: theme.COLORS.MUTED,
},
})
React components have to start with a capital letter so that's the first issue. Second issue is that react components need a render function.
Related
I am using react-native-google-places-autocomplete for a filter menu on a project. While I am inputting text into the <GooglePlacesAutocomplete/> object I want to track the text input with a state variable called 'address'. To do that I used a predefined function preProcess (ideally I would use onChangeText, but <GooglePlacesAutocomplete/> does not support it). Fortunately the state variable does update when input text is changed; however, after it updates, I receive a TypeError: undefined is not an object (evaluating 'stateText.length'). I've read every blog and stack overflow chain dealing with similar errors and haven't found why this error pops up with my specific application. Any help would be greatly appreciated.
import React, { useState, useEffect } from "react";
import {View, Text} from "react-native";
import Screen from "../../../../components/Screen";
import styles from "./LocationStyles";
import colors from "../../../../config/colors";
import { GooglePlacesAutocomplete } from "react-native-google-places-autocomplete";
import Geocoder from "react-native-geocoding";
import SuggestionRow from "./SuggestionRow";
function LocationScreen(props) {
const [address, setAddress] = useState("");
Geocoder.init("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", { language: "en" });
useEffect(() => {
console.log(`address is ${address}`);
}, [address]);
return (
<Screen style={styles.screen}>
<View style={{ marginTop: 25 }}>
<Text style={{ height: 25, fontSize: 14 }}>Street*</Text>
<View style={{ height: 100, position: "relative", zIndex: 10 }}>
<GooglePlacesAutocomplete
preProcess={(value) => setAddress(value)}
minLength={5}
debounce={200}
enablePoweredByContainer={false}
onPress={(data, details = null) => {
Geocoder.from(data.description)
.then((json) => {
var location = json.results[0].geometry.location;
})
.catch((error) => console.warn(error));
setAddress(`${data.terms[0].value} ${data.terms[1].value}`);
}}
styles={{
textInputContainer: {
borderWidth: 1,
borderRadius: 10,
overflow: "hidden",
paddingTop: 3,
borderColor: colors.transparentPrimary,
height: 45,
},
textInput: {
height: 38,
color: colors.black,
fontSize: 14,
},
}}
query={{
key: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
language: "en",
types: "address",
fields: "geometry",
components: "country:us",
}}
renderRow={(item) => <SuggestionRow item={item} />}
/>
</View>
<Text style={{ color: colors.medium, fontSize: 10, marginTop: -50 }}>
e.g. 100 Larch Ave
</Text>
</View>
</Screen>
);
}
export default LocationScreen;
is anyone able to help pass the data to the modal? The .map function returns the month names from the data [] array (needed for the slider), and I'd like to display that particular one in a modal view as well.
Current view:
and modal:
expectations:
unfortunately, only the first month from the [] is visible in the modal.
I am also putting the .js file for review:
import React, { useContext, useState } from 'react';
import { AuthenticatedUserContext } from '../AuthenticatedUserProvider';
import { Swiper } from 'react-native-swiper';
import Modal from 'react-native-modal';
import { db } from '../firebase';
import FontAwesome from 'react-native-vector-icons/FontAwesome';
import { View, Text, TouchableHighlight, StyleSheet, Button, TextInput, TouchableOpacity } from 'react-native';
const data = [
{ id: 1, name: 'Month1' },
{ id: 2, name: 'Month2' },
{ id: 3, name: 'Month3' }
];
export default function HomeScreen() {
const { user } = useContext(AuthenticatedUserContext);
const [ isModalVisible, setModalVisible ] = useState(false);
const [ months, setMonths ] = useState(data);
const [ values, setValues ] = useState({
budget: '',
month: '',
});
const toggleModal = () => {
setModalVisible(!isModalVisible);
};
const onSave = () => {
setValues({ ...values, userId: user.uid });
setModalVisible(!isModalVisible);
db.collection('Budget').add({
userId: user.uid,
budget: values.budget,
});
};
return (
<Swiper showsButtons={true} showsPagination={false} buttonWrapperStyle={{ alignItems: 'flex-start' }}>
{months.map((months, i) => (
<View key={i} style={styles.slider}>
<Text style={styles.text}> {months.name}</Text>
<View>
<View style={styles.mainCardView}>
<TouchableOpacity
onPress={
toggleModal
}
style={{ flex: 1, alignItems: 'flex-end', marginTop: 20 }}
>
<FontAwesome name="pencil-square-o" color="black" size={30} />
</TouchableOpacity>
</View>
</View>
<Modal isVisible={isModalVisible} style={{ margin: 0 }}>
<Text style= {{marginLeft: 50, color: '#fff'}}>Current month: {months.name}</Text>
<TextInput
style={{
height: 40,
borderColor: 'white',
borderWidth: 1,
color: 'white',
shadowColor: 'white',
margin: 50,
padding: 5,
marginVertical: 10,
}}
onChange={(e) => setValues({ ...values, budget: e.target.value })}
value={values.budget}
placeholder="Budget"
keyboardType="decimal-pad"
placeholderTextColor="#fff"
/>
<TouchableHighlight
style={{
height: 40,
borderRadius: 10,
backgroundColor: 'gray',
marginLeft: 50,
marginRight: 50,
marginTop: 20,
}}
>
<Button
onPress={onSave}
title="Confirm"
/>
</TouchableHighlight>
<TouchableHighlight
style={{
height: 40,
borderRadius: 10,
backgroundColor: 'gray',
marginLeft: 50,
marginRight: 50,
marginTop: 20,
}}
>
<Button
onPress={toggleModal}
title="Back"
/>
</TouchableHighlight>
</Modal>
</View>
))}
</Swiper>
);
}
Here are a couple suggestions:
{months.map((months, i) => (...))} I would not recommend using months as the current item in the map since its confusing. Instead, I would recommend something like months.map((month, i) => ())} since in actuality you are referring to just one month within the map.
You are rendering the modal within your map, so each month has its own modal. But you only render one modal at a time, so instead you can just put the modal outside of the map, and somehow point the modal to the currently active month (see below)
If you have another piece of state like const [activeMonth, setActiveMonth] = useState(). Then when you click one of the months you can set the modal state to open, and set the activeMonth state. Then in the modal, it would just display state based off the current active month. It seems like you can make use of your values state to do that probably!
i showing some value list description and images on home screen using Flatlist .when i onpress Flatlist item passing image source and id .value passing getparams but error was TypeError: navigation.getParam is not a function.why??. Please solve issue and edit my code . i am a new to react native please solve my issue.
import React from 'react';
import { StyleSheet, Text, View, FlatList, TouchableOpacity, Image } from 'react-native';
import { Card, Rating } from 'react-native-elements'
import { MaterialCommunityIcons } from '#expo/vector-icons';
import { dishesData } from './DishesData';
const MenuDetailScreen = ({ navigation }) => {
const dish = dishesData.find(
(dish) => dish.id === this.navigation.getParam('id')
);
return (
<View style={styles.container}>
<Card>
<Card.Title
style={styles.titleTextStyle}>{dish.title}</Card.Title>
<Image style={{ height: 300, width: 350 }} source={{ uri: dish.imageSource }} />
</Card>
<Card>
<View style={{ flexDirection: "row" }}>
<Text style={styles.commentsTextStyle}>Comments</Text>
<View style={{ flexGrow: 1 }} />
<TouchableOpacity style={{ paddingBottom: 8 }} >
<MaterialCommunityIcons name="pencil-circle" size={40} color="blue" />
</TouchableOpacity>
</View>
<FlatList
scrollEnabled={false}
data={dish.dishDetails}
keyExtractor={(item) => item.id.toString()}
renderItem={({ item }) => {
return (
<View>
<Text style={styles.headerTextStyle}>{item.comment}</Text>
<Rating
readonly
imageSize={20}
startingValue={item.rating}
style={styles.ratingStyle}
/>
<Text style={styles.spacing}>- {item.author} , {item.created_by}</Text>
</View>
);
}}
/>
</Card>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
paddingBottom: 10
},
commentsTextStyle: {
fontSize: 20,
fontWeight: 'bold',
textAlign: 'left'
},
textInputStyle: {
width: "80%",
padding: 8,
marginBottom: 8,
fontSize: 16
},
submitButtonStyle: {
alignItems: 'center',
width: "80%",
borderRadius: 5,
marginBottom: 8,
padding: 8,
fontWeight: 'bold',
backgroundColor: 'rgba(0, 0, 255, 0.6)',
color: 'black'
},
cancelButtonStyle: {
alignItems: 'center',
width: "80%",
borderRadius: 5,
marginBottom: 8,
padding: 8,
fontWeight: 'bold',
backgroundColor: 'grey',
color: 'black'
},
ratingStyle: {
alignItems: 'flex-start',
paddingBottom: 8
},
titleTextStyle: {
fontSize: 20,
textAlign: 'left'
},
textStyle: {
paddingBottom: 8
},
headerTextStyle: {
fontSize: 16,
fontWeight: 'bold',
paddingTop: 8
},
spacing: {
padding: 8
},
ratingStyle: {
alignItems: 'flex-start',
paddingTop: 8
}
});
export default MenuDetailScreen;
Error place
7 | const MenuDetailScreen = ({ navigation }) =>{
8 |
9 | const dish = dishesData.find(
> 10 | (dish) => dish.id === this.navigation.getParam('id')
11 |
12 | );
13 |
enter code here
Better way is to useNavigation and useRoute from React Navigation.
Step-by-step changes
Step 1
import { useNavigation, useRoute } from '#react-navigation/native';
Step 2
const navigation = useNavigation();
const route = useRoute();
Step 3
const { id } = route.params
Step 4 - Check if you are passing params when you navigate
Example)
onPress={() => navigation.navigate('SCREEN_NAME_HERE', {
PARAM_KEY: PARAM_VALUE
})}
Full Example
import React from 'react';
...
import { useNavigation, useRoute } from '#react-navigation/native';
/*
Navigate to this screen by
navigation.navigate('MenuDetailScreen', {
id: <ID_VALUE_HERE>
})
*/
const MenuDetailScreen = () => {
const navigation = useNavigation();
const route = useRoute();
const { id } = route.params
const dish = dishesData.find(
(dish) => dish.id === id
);
return (
...
)
}
Once you get it working, I recommend you to go over Type checking
with TypeScript for safely navigating between screens in React.
Update the MenuDetailScreen >>
const dish = dishesData.find(
(dish) => dish.id === this.navigation.getParam('id')
);
I have a ScrollView component, and within it I have a form (<AppForm >) that works using Formik and Yup. This form has some input fields (<AppTextInput >). In the form I assign the keyboardType prop for each input field.
The problem is that the fields with keyboardType set to default scroll down the whole ScrollView component when you focus on it, like adding margin to the top of it. This only happens when the keyboardType is set to default.
If I focus on an input field with the keyboardType prop set to numeric, everything works fine.
Any idea of what am I doing wrong?
Here is a gif of what's exactly the problem:
https://giphy.com/gifs/djoHUBAKu9XGyu37OO
And here is my code:
AppFormField (Main screen)
function ActivityFormScreen({ navigation }) {
return (
<View style={styles.container}>
<ActivityIndicator
visible={
postActivityApi.loading ||
editActivityApi.loading ||
getTrabajosApi.loading ||
getCosechasApi.loading ||
getMaquinariasApi.loading
}
/>
<ScrollView style={{ paddingBottom: 500 }}>
<ActivityTitle
text="InformaciĆ³n"
name="information-variant"
size={35}
/>
<AppForm
onSubmit={(form) => handleSubmit(form)}
validationSchema={validationShema}
initialValues={{
fecha: getFormValue("fecha"),
finca_id: getFormValue("finca_id"),
lote: getFormValue("lote"),
cosecha: getFormValue("cosecha"),
cultivos: getFormValue("cultivos"),
maquinaria: getFormValue("maquinaria"),
tiempo_actividad: getFormValue("tiempo_actividad"),
productos: getFormValue("productos"),
cantidad: getFormValue("cantidad"),
unidad: getFormValue("unidad"),
hectarea_trabajada: getFormValue("hectarea_trabajada"),
trabajos: getFormValue("trabajos"),
observaciones: getFormValue("observaciones"),
}}
>
<AppFormField
name="fecha"
holder="Fecha"
keyboardType="default"
placeholder="AAAA-MM-DD"
defaultValue={getFormValue("fecha")}
/>
<AppPickerField
name="finca_id"
holder="Granja"
data={context.allFarms} //Seleccionar el array de granjas
pickerPlaceholder="Seleccione una granja"
value={getFormValue("finca_id")}
/>
<AppFormField
name="lote"
holder="Lote"
keyboardType="numeric"
defaultValue={getFormValue("lote")}
/>
.
.
.
<SubmitButton title="Guardar" />
</AppForm>
</ScrollView>
</View>
);
}
const styles = StyleSheet.create({
container: {
backgroundColor: "white",
flex: 1,
justifyContent: "center",
marginHorizontal: 10,
// paddingTop: 50,
},
});
AppFormField
import React from "react";
import { useFormikContext } from "formik";
import { StyleSheet, View } from "react-native";
import AppTextInput from "../AppTextInput";
import ErrorMessage from "./ErrorMessage";
function AppFormField({ placeholder, name, width, holder, ...otherProps }) {
const { setFieldTouched, handleChange, errors, touched } = useFormikContext();
return (
<View style={styles.container}>
<AppTextInput
onBlur={() => setFieldTouched(name)}
onChangeText={handleChange(name)}
width={width}
holder={holder}
placeholder={placeholder}
{...otherProps}
/>
<ErrorMessage error={errors[name]} visible={touched[name]} />
</View>
);
}
const styles = StyleSheet.create({
container: {
marginBottom: 20,
marginHorizontal: 20,
},
});
export default AppFormField;
AppTextInput
import React from "react";
import { StyleSheet, View, TextInput, Text, Keyboard } from "react-native";
function AppTextInput({ placeholder = " ", holder, ...otherProps }) {
return (
<View style={styles.container}>
<Text style={styles.holder}>{holder}</Text>
<TextInput
style={styles.input}
placeholder={placeholder}
returnKeyLabel="Listo"
returnKeyType="done"
onSubmitEditing={Keyboard.dismiss}
{...otherProps}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
backgroundColor: "transparent",
},
holder: {
fontSize: 20,
textAlign: "left",
color: "#000",
opacity: 0.6,
width: "100%",
height: 30,
},
input: {
fontSize: 20,
borderBottomWidth: 1,
borderColor: "#D9D5DC",
width: "100%",
},
});
export default AppTextInput;
SOLVED:
For some reason my ScrollView component had the property paddingBottom set to 500, and just by removing it, I solved the issue.
I'm working on a React Native app with a typeahead component. The typeahead displays options that overlay other content on the route (see right image below). When a user clicks one of those options, an onPress listener runs a function:
This all works just fine on iOS. On Android though, the onPress event is never received. Even more strangely, when I try to click on an option lower in the list (like Boston, MA, USA), the onPress event is received by the card below the pressed option (Djerba).
Does anyone know what might cause this behavior? I'd be super grateful for any insights others can offer on this query.
Here's the code for the Explore view and the typeahead components.
Explore.js
import React from 'react'
import { connect } from 'react-redux'
import { Text, View, ScrollView, TouchableOpacity } from 'react-native'
import { gradients, sizing } from '../../style'
import { LinearGradient } from 'expo-linear-gradient'
import { MountainHero } from '../Heros'
import { CardRow } from '../Card'
import Loading from '../Loading'
import { setExploreSearch, onExploreTypeaheadClick } from '../../actions/locations'
import { Typeahead } from '../Typeahead'
const styles = {
container: {
flex: 1,
flexDirection: 'column',
},
scrollView: {
paddingBottom: sizing.margin,
},
loadingContainer: {
position: 'absolute',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
zIndex: 100,
elevation: 100,
top: 53,
width: '100%',
},
typeahead: {
margin: sizing.margin,
marginBottom: 0,
width: sizing.screen.width - (2*sizing.margin),
zIndex: 100,
elevation: 100,
}
}
const Explore = props => {
const { authenticated: a, spotlight, loading } = props;
let r = (a.recommendedLocations || []);
if (!r || !spotlight) return null;
// remove spotlight locations from the recommended locations
const ids = spotlight.map(i => i.guid);
const recommended = r.filter(i => ids.indexOf(i.guid) == -1);
return (
<LinearGradient style={styles.container} colors={gradients.teal}>
<ScrollView contentContainerStyle={styles.scrollView}>
{loading && (
<View style={styles.loadingContainer}>
<Loading />
</View>
)}
<MountainHero text='Explore' />
<Typeahead
style={styles.typeahead}
placeholder='Search Cities'
value={props.exploreSearch}
onChange={props.setExploreSearch}
vals={props.exploreTypeahead}
valKey={'place_id'}
onTypeaheadClick={props.onExploreTypeaheadClick}
/>
<CardRow
text='Explore Places'
cards={recommended}
type='location' />
<CardRow
text='In the Spotlight'
cards={spotlight}
type='location' />
</ScrollView>
</LinearGradient>
)
}
const mapStateToProps = state => ({
authenticated: state.users.authenticated,
spotlight: state.locations.spotlight,
exploreSearch: state.locations.exploreSearch,
exploreTypeahead: state.locations.exploreTypeahead,
loading: state.locations.loading,
})
const mapDispatchToProps = dispatch => ({
setExploreSearch: s => dispatch(setExploreSearch(s)),
onExploreTypeaheadClick: val => dispatch(onExploreTypeaheadClick(val)),
})
export default connect(mapStateToProps, mapDispatchToProps)(Explore)
Typeahead.js
import React from 'react'
import { Text, View, TouchableOpacity } from 'react-native'
import { sizing, GradientInput } from '../style'
const styles = {
container: {
position: 'absolute',
zIndex: 100,
elevation: 100,
height: 400,
width: '100%',
},
input: {
width: '100%',
borderRadius: 0,
},
typeaheadContainer: {
position: 'absolute',
zIndex: 100,
elevation: 100,
top: 55,
width: '100%',
},
typeaheadRow: {
padding: 10,
paddingTop: 12,
paddingBottom: 12,
borderWidth: 1,
borderColor: '#eeeeee',
backgroundColor: '#ffffff',
marginBottom: -1,
},
typeaheadRowText: {
fontSize: 15,
fontFamily: 'open-sans',
lineHeight: 20,
backgroundColor: '#ffffff',
},
}
export const Typeahead = props => {
return (
<View style={[props.container, props.style]}>
<GradientInput style={styles.input}
placeholder={props.placeholder}
value={props.value}
onChange={props.onChange} />
<TypeaheadList vals={props.vals}
valKey={props.valKey}
onTypeaheadClick={props.onTypeaheadClick} />
</View>
)
}
export const TypeaheadList = props => {
if (!props.vals) return null;
return (
<View style={styles.typeaheadContainer}>
{props.vals.map(i => {
let text = i.text;
if (text.length > 31) text = text.substring(0,31) + '...';
return (
<TouchableOpacity activeOpacity={0.5} key={i[props.valKey]}
style={styles.typeaheadRow}
onPress={() => props.onTypeaheadClick(i[props.valKey])}>
<Text numberOfLines={1} style={styles.typeaheadRowText}>{text}</Text>
</TouchableOpacity>
)
})}
</View>
)
}
export default Typeahead
Try to move Typeahead component below all CardRow components and set position:absolute for Typeahead. Probably on android - the latest view shadow all views before (I am not sure, but I think you have to try it for next discovering issue).
You should also remove position: absolute from all but one component. Working code:
Explore.js
import React from 'react'
import { connect } from 'react-redux'
import { Text, View, ScrollView, TouchableOpacity } from 'react-native'
import { gradients, sizing } from '../../style'
import { LinearGradient } from 'expo-linear-gradient'
import { MountainHero } from '../Heros'
import { CardRow } from '../Card'
import Loading from '../Loading'
import { setExploreSearch, onExploreTypeaheadClick } from '../../actions/locations'
import { Typeahead } from '../Typeahead'
const styles = {
container: {
flex: 1,
flexDirection: 'column',
},
scrollView: {
paddingBottom: sizing.margin,
},
loadingContainer: {
position: 'absolute',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
zIndex: 1,
elevation: 1,
top: 53,
width: '100%',
},
topCardRow: {
paddingTop: sizing.margin + sizing.gradientInput.height,
},
typeahead: {
margin: sizing.margin,
marginBottom: 0,
width: sizing.screen.width - (2*sizing.margin),
zIndex: 1,
elevation: 1,
position: 'absolute',
top: sizing.mountainHero.height,
left: 0,
}
}
const Explore = props => {
const { authenticated: a, spotlight, loading } = props;
let r = (a.recommendedLocations || []);
if (!r || !spotlight) return null;
// remove spotlight locations from the recommended locations
const ids = spotlight.map(i => i.guid);
const recommended = r.filter(i => ids.indexOf(i.guid) == -1);
return (
<LinearGradient style={styles.container} colors={gradients.teal}>
<ScrollView contentContainerStyle={styles.scrollView}>
{loading && (
<View style={styles.loadingContainer}>
<Loading />
</View>
)}
<MountainHero text='Explore' />
<CardRow
style={styles.topCardRow}
text='Explore Places'
cards={recommended}
type='location' />
<CardRow
text='In the Spotlight'
cards={spotlight}
type='location' />
<Typeahead
style={styles.typeahead}
placeholder='Search Cities'
value={props.exploreSearch}
onChange={props.setExploreSearch}
vals={props.exploreTypeahead}
valKey={'place_id'}
onTypeaheadClick={props.onExploreTypeaheadClick}
/>
</ScrollView>
</LinearGradient>
)
}
const mapStateToProps = state => ({
authenticated: state.users.authenticated,
spotlight: state.locations.spotlight,
exploreSearch: state.locations.exploreSearch,
exploreTypeahead: state.locations.exploreTypeahead,
loading: state.locations.loading,
})
const mapDispatchToProps = dispatch => ({
setExploreSearch: s => dispatch(setExploreSearch(s)),
onExploreTypeaheadClick: val => dispatch(onExploreTypeaheadClick(val)),
})
export default connect(mapStateToProps, mapDispatchToProps)(Explore)
Typeahead.js
import React from 'react'
import { Text, View, TouchableOpacity } from 'react-native'
import { sizing, GradientInput } from '../style'
const styles = {
container: {
zIndex: 1,
elevation: 1,
height: 400,
width: '100%',
},
input: {
width: '100%',
borderRadius: 0,
},
typeaheadContainer: {
zIndex: 1,
elevation: 1,
top: 0,
width: '100%',
},
typeaheadRow: {
padding: 10,
paddingTop: 12,
paddingBottom: 12,
borderWidth: 1,
borderColor: '#eeeeee',
backgroundColor: '#ffffff',
marginBottom: -1,
zIndex: 1,
elevation: 1,
},
typeaheadRowText: {
fontSize: 15,
fontFamily: 'open-sans',
lineHeight: 20,
backgroundColor: '#ffffff',
},
}
export const Typeahead = props => {
return (
<View style={[props.container, props.style]}>
<GradientInput style={styles.input}
placeholder={props.placeholder}
value={props.value}
onChange={props.onChange} />
<TypeaheadList vals={props.vals}
valKey={props.valKey}
onTypeaheadClick={props.onTypeaheadClick} />
</View>
)
}
export const TypeaheadList = props => {
if (!props.vals) return null;
return (
<View style={styles.typeaheadContainer}>
{props.vals.map(i => {
let text = i.text;
if (text.length > 31) text = text.substring(0,31) + '...';
return (
<TouchableOpacity activeOpacity={0.5} key={i[props.valKey]}
style={styles.typeaheadRow}
onPress={() => props.onTypeaheadClick(i[props.valKey])}>
<Text numberOfLines={1} style={styles.typeaheadRowText}>{text}</Text>
</TouchableOpacity>
)
})}
</View>
)
}
export default Typeahead