Text and TouchableOpacity Style Type Annotations - react-native

I am trying to type annotate my React Native project using Flow, but I am having trouble finding the type definitions for the Text and TouchableOpacity elements so I can reference their style prop type definitions. How can I import and/or reference the type definitions for these elements?
Code below:
// #flow
import * as React from "react";
import { Text, TouchableOpacity } from "react-native";
type Props = {
segmentIndex: number,
segmentInfo: {
title: string
},
segmentStyle: ???, // WHAT SHOULD I USE HERE?
titleStyle: ???, // WHAT SHOULD I USE HERE?
onSelection: (number) => void
}
export const SegmentButton = (props: Props) => {
const _segmentPressed = () => {
props.onSelection(props.segmentIndex)
}
return (
<TouchableOpacity style={props.segmentStyle} onPress={_segmentPressed}>
<Text style={props.titleStyle}>{props.segmentInfo.title.charAt(0).toUpperCase() + props.segmentInfo.title.substring(1)}</Text>
</TouchableOpacity>
)
}

There are many ways to define StyleSheet type.
1. react-native generic way
reference from react-native library,
SwipeableQuickActionButton.js
import { View } from 'react-native';
type Prop = {
style?: ?View.propTypes.style,
}
2. react-navigation generic way
reference from react-navigation library,
TypeDefinition.js
export type Style =
| { [key: string]: any }
| number
| false
| null
| void
| Array<Style>;
If you already installed react-navigation, import it from:
import type { Style } from 'react-navigation/src/TypeDefinition';
type Prop = {
style?: Style,
}
Or you can still use it by define in your own file.
3. make Style type specific for <Text /> and <TouchableOpacity />
It would be the hard way -- although doable, see if that worth the trouble.
take <Picker /> for reference, it defined itemStyle for <Text /> like below, which corresponding to text style for each picker item.
var StyleSheetPropType = require('StyleSheetPropType');
var TextStylePropTypes = require('TextStylePropTypes');
var TextStyle = StyleSheetPropType(TextStylePropTypes);
type Prop = {
itemStyle: TextStyle
}
To use it in your own library, import them from:
import TextStylePropTypes from 'react-native/Libraries/Text/TextStylePropTypes';
import StyleSheetPropType from 'react-native/Libraries/StyleSheet/StyleSheetPropType';
let TextStyle = StyleSheetPropType(TextStylePropTypes);
type Prop = {
style?: ?TextStyle,
}

Related

i18next how to use the Trans component in React Native

How to apply a bold weight to certain parts of the translation using the Trans component in React Native?
Since HTML tags like <strong></strong> don't work, we have to create our own custom <Strong/> component that applies certain text styling to the translation, but I don't know how to do that despite reading the docs?
Docs:
import { Trans } from 'react-i18next';
function MyComponent({ person, messages }) {
const { name } = person;
const count = messages.length;
return (
<Trans i18nKey="userMessagesUnread" count={count}>
Hello <strong title={t('nameTitle')}>{{name}}</strong>, you have {{count}} unread message. <Link to="/msgs">Go to messages</Link>.
</Trans>
);
}
i guess you can use <Text style={{fontWeight: 'bold'}}>{{name}}</Text> instead of <strong title={t('nameTitle')}>{{name}}</strong>.
or using useTranslation
import React from 'react';
import { useTranslation } from 'react-i18next';
export function MyComponent() {
const { t, i18n } = useTranslation();
// or const [t, i18n] = useTranslation();
return <Text style={{fontWeight: 'bold'}}>{t('my translated text')}</Text>
}
don't test yet

Using a class as props in a react native component

I'm learning react (coming from a native iOS/Swift background) and I'm a bit confused about something I can't get to work.
I have a component that accepts props, so I figured I would write a class to model those props:
class HeaderProps {
text: string;
constructor(headerText:string) {
this.text = headerText;
}
}
// Make a component
const Header = (props:HeaderProps) => {
const { textStyle, viewStyle } = styles;
return (
<View style={viewStyle}>
<Text style={textStyle}>{props.text}</Text>
</View>
);
};
and I'm exporting from my component like so:
export {Header, HeaderProps};
I'm then importing it:
import {Header, HeaderProps} from './src/components/header';
// Create a component
const App = () => ( <Header headerText={ new HeaderProps('Album') } />);
No text is appearing in my component.
If I just pass a string through as props it works fine, can't think of any reason why sending a class through wouldn't work.
I'm using flow type to declare the types of my arguments, not sure if that might be causing any issues.
A point in the right direction would be much appreciated!

Font loading error when using the ShoutemUI/TextInput component in a Exponent react-native framework

I'm trying to use shoutem/ui with exponent and I’m getting an error using the shoutem/ui textinput component, where I get the following error message fontFamily Rubik is not a system font and has not been loaded through Exponent.Font.loadAsync
However I loaded all the custom shoutem fonts that were listed in the blog post https://blog.getexponent.com/using-react-native-ui-toolkits-with-exponent-3993434caf66#.iyiwjpwgu
Using the Exponent.Font.loadAsync method.
fonts: [
FontAwesome.font,
{'space-mono': require('./assets/fonts/SpaceMono-Regular.ttf')},
{'Rubik-Black': require('./node_modules/#shoutem/ui/fonts/Rubik-Black.ttf')},
{'Rubik-BlackItalic': require('./node_modules/#shoutem/ui/fonts/Rubik-BlackItalic.ttf')},
{'Rubik-Bold': require('./node_modules/#shoutem/ui/fonts/Rubik-Bold.ttf')},
{'Rubik-BoldItalic': require('./node_modules/#shoutem/ui/fonts/Rubik-BoldItalic.ttf')},
{'Rubik-Italic': require('./node_modules/#shoutem/ui/fonts/Rubik-Italic.ttf')},
{'Rubik-Light': require('./node_modules/#shoutem/ui/fonts/Rubik-Light.ttf')},
{'Rubik-LightItalic': require('./node_modules/#shoutem/ui/fonts/Rubik-LightItalic.ttf')},
{'Rubik-Medium': require('./node_modules/#shoutem/ui/fonts/Rubik-Medium.ttf')},
{'Rubik-MediumItalic': require('./node_modules/#shoutem/ui/fonts/Rubik-MediumItalic.ttf')},
{'Rubik-Regular': require('./node_modules/#shoutem/ui/fonts/Rubik-Regular.ttf')},
{'rubicon-icon-font': require('./node_modules/#shoutem/ui/fonts/rubicon-icon-font.ttf')},
],
});
Looking through the code I couldn't find the obvious fix - had trouble even finding where the style was set to throw the error.
The code above seem to be missing one line. Try adding this line to the array list:
{'Rubik': require('./node_modules/#shoutem/ui/fonts/Rubik-Regular.ttf')}
Use this code from the link
import React, { Component } from 'react';
import { StatusBar } from 'react-native';
import { Font, AppLoading } from 'expo';
import { View, Examples } from '#shoutem/ui';
export default class App extends React.Component {
state = {
fontsAreLoaded: false,
};
async componentWillMount() {
await Font.loadAsync({
'Rubik': require('./node_modules/#shoutem/ui/fonts/Rubik-Regular.ttf'),
'Rubik-Black': require('./node_modules/#shoutem/ui/fonts/Rubik-Black.ttf'),
'Rubik-BlackItalic': require('./node_modules/#shoutem/ui/fonts/Rubik-BlackItalic.ttf'),
'Rubik-Bold': require('./node_modules/#shoutem/ui/fonts/Rubik-Bold.ttf'),
'Rubik-BoldItalic': require('./node_modules/#shoutem/ui/fonts/Rubik-BoldItalic.ttf'),
'Rubik-Italic': require('./node_modules/#shoutem/ui/fonts/Rubik-Italic.ttf'),
'Rubik-Light': require('./node_modules/#shoutem/ui/fonts/Rubik-Light.ttf'),
'Rubik-LightItalic': require('./node_modules/#shoutem/ui/fonts/Rubik-LightItalic.ttf'),
'Rubik-Medium': require('./node_modules/#shoutem/ui/fonts/Rubik-Medium.ttf'),
'Rubik-MediumItalic': require('./node_modules/#shoutem/ui/fonts/Rubik-MediumItalic.ttf'),
'Rubik-Regular': require('./node_modules/#shoutem/ui/fonts/Rubik-Regular.ttf'),
'rubicon-icon-font': require('./node_modules/#shoutem/ui/fonts/rubicon-icon-font.ttf'),
});
this.setState({ fontsAreLoaded: true });
}
render() {
if (!this.state.fontsAreLoaded) {
return <AppLoading />;
}
return (
<View styleName="flexible">
<Examples />
<StatusBar barStyle="default" hidden={false} />
</View>
);
}
}

What is the recommended way to apply styles to an extended React Native component?

I have extended the Text component in order to have a reusable text component with a custom font.
My custom component should accept the styles passed to it and add the custom font to it.
I'm currently doing this:
MyText.js
import React from 'react'
import {
Text,
StyleSheet
} from 'react-native';
export default class MyText extends React.Component {
render() {
const style =
Object.assign( {},
StyleSheet.flatten(this.props.style),
{fontFamily: "My Font"}
);
return (
<Text style={style}>
{this.props.children}
</Text>
);
}
}
While this works as expected, having to flatten the stylesheet every time seems wrong. The above is a trivial example, and I can think of other components on which I could use this pattern. For that reason, I want to make sure I'm not ignoring a more suitable approach.
Well it depends on how much you would want to customize. In this case , if it is just a different font, it could be something like
import React from 'react'
import {
Text,
StyleSheet
} from 'react-native';
import _ from 'lodash';
export default class MyText extends React.Component {
render() {
const filteredProps = _.omit(this.props, 'style');
return (
<Text style={[{fontFamily: "My Font"}, this.props.style]} {...filteredProps} />
);
}
}

React Native Button causing Invariant Invalid

For the life of me, I cannot figure out why this little bit of code will not work!
I have isolated the issue to the Button element (the import statement seems fine).
I am seeing the error "Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. Check the render method of Login.
import React, { ScrollView, Image, StyleSheet, Button } from "react-
native";
import { connect } from "react-redux/native";
const onButtonClicked = () => {};
class Login extends React.Component {
componentDidMount() {}
render() {
return (
<ScrollView
style={{ flex: 1 }}
contentContainerStyle={{
justifyContent: "center",
alignItems: "center"
}}
>
<Image
source={require("../../img/coin.png")}
resizeMode={Image.resizeMode.cover}
style={Styles.coinLogo}
/>
<Button title="Login default" onPress={() => {}} />
</ScrollView>
);
}
}
Login.propTypes = {
dispatch: React.PropTypes.func
};
Login.defaultProps = {
dispatch: () => {}
};
const Styles = StyleSheet.create({
coinLogo: {
marginTop: 50,
height: 200,
width: 200
},
loginButton: {
marginTop: 50
}
});
export default connect(state => ({}))(Login);
This is a nasty issue because the error message is really vague. It has to do (I think) with object destructuring.
When you destructure an object, say:
var myObject = {a: 1, b: 2, c: 3};
let {a, b, c, d} = myObject;
Your transpiler does the following:
let a = myObject.a;
let b = myObject.b;
let c = myObject.c;
let d = myObject.d; // Ah! But we never defined a 'd' key, did we?
And of course, non-existing keys evaluate to undefined without raising an error, so what you get is d having a value of undefined.
Let's go back to your imports. I think they should look like this:
import React from 'react'; // The React API moved to the react package, you should be getting an error because of this. See https://github.com/facebook/react-native/releases/tag/v0.26.0 (Unless you are using React Native <= 0.25)
import { ScrollView, Image, StyleSheet, Button } from "react-native";
import { connect } from "react-redux"; // As far as I know, the connect is exported directly from 'react-redux', but it might be OK the way you had it.
Now, let's go to your render. We are trying to render a ScrollView, a Image and a Button. RN is raising the error because one of those is being evaluated to undefined, which is not allowed, but it is not telling us which one. You can try and console.log the values of the three and check which one is undefined. However, I strongly think it is the Button, because it was added in RN 0.37, and as I mentioned before in the import of React, you must be running a version of RN previous to the 0.26.0 tag, otherwise the code would have raised a different error.
Let me know if that is the case.