react-native prop type for text style - react-native

i have component with a simple structure and a <Text> somewhere inside the tree for which i want to pass in a style. Which works perfectly but for the proptypes validation.
The basic setup is not much more than that
export default class Component extends PureComponent {
render() {
return (<View><Text style={this.props.style}>Some text</Text></view>);
}
}
Component.defaultProps = {
style: null,
};
Component.propTypes = {
style: ViewPropTypes.style,
};
The problem is that the ViewPropTypes.style does not contain i.e. color key. So providing a style with a color is invalid and produces a warning. I tried to import TextStylePropTypes as i found in https://github.com/facebook/react-native/blob/master/Libraries/Text/TextStylePropTypes.js but it is undefined.
Any advice on what to do?

For anybody trying to achieve this seems like View.propTypes.style is deprecated while Text.propTypes.style is not.

As the passed style prop is for the Text node, use Text.propTypes.style as shown below...
Component.propTypes = {
style: Text.propTypes.style
};

Related

Fluent UI React - how to apply global component styles with Fluent ThemeProvider

I'm working with the theming code below. I'm able to apply a global Fluent theme with the ThemeProvider and createTheme utility, but when I add component specific themes, I'm not getting any typings, which makes theming very difficult.
So my question is: how do I apply global component-specific styles using Fluent ThemeProvider with strong typing.
If, for example, I wanted to add a box shadow to all Fluent PrimaryButtons, I wouldn't know what properties to access on the components key passed into createTheme.
If you've done any global component theming, please let me know what pattern you used and if I'm on the right track, thanks!
import { createTheme } from '#fluentui/react';
import { PartialTheme } from '#fluentui/react-theme-provider';
// Trying to add global component styles (not getting typings)
const customComponentStyles = {
PrimaryButton: {
styles: {
root: {
background: 'red'
}
}
}
};
export const fluentLightTheme: PartialTheme = createTheme({
components: customComponentStyles, // Want to apply component styles
palette: {
themePrimary: '#0078d4',
themeLighterAlt: '#eff6fc',
themeLighter: '#deecf9',
themeLight: '#c7e0f4',
themeTertiary: '#71afe5',
themeSecondary: '#2b88d8',
themeDarkAlt: '#106ebe',
themeDark: '#005a9e',
themeDarker: '#004578',
neutralLighterAlt: '#faf9f8',
neutralLighter: '#f3f2f1',
neutralLight: '#edebe9',
neutralQuaternaryAlt: '#e1dfdd',
neutralQuaternary: '#d0d0d0',
neutralTertiaryAlt: '#c8c6c4',
neutralTertiary: '#a19f9d',
neutralSecondary: '#605e5c',
neutralPrimaryAlt: '#3b3a39',
neutralPrimary: '#323130',
neutralDark: '#201f1e',
black: '#000000',
white: '#ffffff'
}
});
The problem here is, that components is just a Record<string, ComponentStyles>, where ComponentStyles then just is a quite unspecific object of the form { styles?: IStyleFunctionOrObject<any, any>}. They would have to add an entry for every possible I<Component>Styles interface to ComponentsStyles, which I guess would be too much work and errorprone (e.g. forgetting to add a new component here ...).
Since all the I<Component>Styles interfaces are exported by Fluent, I always define the styles for each component separately and than merge them in the components object:
const buttonStyles: IButtonStyles = {
root: {
backgroundColor: 'red'
}
};
export const fluentLightTheme: PartialTheme = createTheme({
components: { PrimaryButton: { styles: buttonStyles } },
});
Here is a codepen example I created by using one of Fluent UIs basic Button examples: https://codepen.io/alex3683/pen/WNjmdWo

Is it possible to detect if docusaurus is in light or dark mode?

I have an image with a white background, which looks off on docusaurus dark theme, so I want to detect when the user changes theme so I use a different image.
If you are using the classic theme, you can leverage the useThemeContext hook to detect the current color mode setting. Since documents support MDX, you can create a component that conditionally displays the appropriate image based on the color mode value provided by the theme context. Here is a basic example.
This suggestion is based on using the following docusaurus versions:
>= #docusaurus/core#2.0.0-alpha.70
>= #docusaurus/preset-classic#2.0.0-alpha.70
ImageSwitcher Component File
Create a react component that can be imported to your documentation
import React from 'react';
import useThemeContext from '#theme/hooks/useThemeContext'; //docs: https://v2.docusaurus.io/docs/2.0.0-alpha.69/theme-classic#usethemecontext
const ImageSwitcher = ({lightImageSrc, darkImageSrc}) => {
const { isDarkTheme } = useThemeContext();
return (
<img src={isDarkTheme ? darkImageSrc : lightImageSrc} alt="Example banner" />
)
}
export default ImageSwitcher;
Documentation Markdown File
Import the component into your documentation and pass the appropiate image sources to the component.
---
id: your-docs
title: Your Docs
---
import ImageSwitcher from '../../../src/ImageSwitcher.js';
<ImageSwitcher
lightImageSrc="//satyr.io/300/black?text=LightMode"
darkImageSrc="//satyr.io/300/white?text=DarkMode"/>
for version 2.0.0-beta.15, you can get current theme mode like this:
import { useColorMode } from '#docusaurus/theme-common';
// ^^ I don't think it's in the docs yet, but I get the referencet from here
// https://github.com/rohit-gohri/redocusaurus/issues/116
const Component = () => {
const { isDarkTheme } = useColorMode();
return <div>{isDarkTheme ? 'Dark' : 'Light'}</div>;
};
Instead of creating a custom component, you can use Themed Images:
import ThemedImage from '#theme/ThemedImage';
import useBaseUrl from '#docusaurus/useBaseUrl';
<ThemedImage
alt="Docusaurus themed image"
sources={{
light: useBaseUrl('/img/docusaurus_light.svg'),
dark: useBaseUrl('/img/docusaurus_dark.svg'),
}}
/>;
With it, you will not have the following error:
`useThemeContext` is used outside of `Layout` Component.
br8dy's answer above works in development-mode, but will throw an error when you try to build the project - Docusaurus will complain that the component doesn't exist within a component (displaying a reference to this part of the docs).
The solution is to use BrowserOnly, as documented here.
Explicitly, you need to change this:
const ImageSwitcher = ({lightImageSrc, darkImageSrc}) => {
const { isDarkTheme } = useThemeContext();
return (
<img src={isDarkTheme ? darkImageSrc : lightImageSrc} alt="Example banner" />
)
}
To something like this:
const ImageSwitcher = ({lightImageSrc, darkImageSrc, altText}) => {
return (
<BrowserOnly fallback={<img src={darkImageSrc} alt={altText} />}>
{() => {
const { isDarkTheme } = useThemeContext();
const imgSrc = isDarkTheme ? darkImgSrc : lightImgSrc;
const fullImgSrc = useBaseUrl(imgSrc);
return (
<img src={fullImgSrc} alt={altText} />
)
}}
</BrowserOnly>
)
}
Now it is possible with the following, in a .mdx file:
import ThemedImage from '#theme/ThemedImage';
<ThemedImage
alt="Docusaurus themed image"
sources={{
light: useBaseUrl('/img/docusaurus_light.svg'),
dark: useBaseUrl('/img/docusaurus_dark.svg'),
}}
/>;
Reference: Docusaurus. Themed images
It sets attribute to html tag so you can check this attribute data-theme and listen to changes through MutationObserver.

React Native: How can I use the DeviceInfo isTablet() method to conditionally apply a style to an element?

I am trying to adapt the design of my app to tablet and one way to detect if the app is running on a tablet is by using the DeviceInfo module in particular the isTablet() method. How can I use this method to conditionally apply styles to an element?
Here is what I am trying to do at the moment:
import { checkIfDeviceIsTablet } from './helper-functions';
<View style={[styles.wrapper, checkIfDeviceIsTablet() === true ? styles.wrapperTablet : {}]}>
{contents}
</View>
The checkIfDeviceIsTablet() function is as follows:
import DeviceInfo from 'react-native-device-info';
function checkIfDeviceIsTablet() {
DeviceInfo.isTablet().then(isTablet => {
return isTablet;
});
}
The issue is that when the component loads the checkIfDeviceIsTablet() method returns a promise as opposed to the expected true/false value and so the conditional styles are not applied when the app is run on a tablet. I tried turning the function into an async/await format with a try/catch but the result is the same.
I would use React Native's own Platform.isPad function but the app must also work on Android.
Any help is appreciated.
I would recommend calling DeviceInfo.isTablet() only once at the beginning of your app. You can store the result globally, and then later on you can check the type without having to deal with async promises.
To store the type globally, your options are:
A global variable
React's Context API
A static property on a class (if using ES6+)
Some sort of global state management solution like Redux
You still have to deal with the initial async problem, since the first call to DeviceInfo.isTablet() will return an async promise.
I'd recommend looking into React's Context API.
Here's a rough example:
render() {
return (
<DeviceInfoContext.Consumer>
{ ({ isTablet }) => (
<Text>Is this a tablet? {isTablet}</Text>
) }
</DeviceInfoContext.Consumer>
)
}
And your DeviceInfoContext class would look something like this:
class DeviceInfoContext extends React.Component {
state = {
isTablet: false
}
componentDidMount() {
Device.IsTablet().then(result => this.setState({ isTablet: result }))
}
render() {
return (
this.props.children({ isTablet: this.state.isTablet })
)
}
}
This is just a rough example. You can learn more about the Context API in the docs
Me too had some troubles with the breaking changes of react native 0.5xx to 0.6xx. The library for device detection change it structure to promises. A paintful.
This library save the day, the installation and use is very easy.
https://github.com/m0ngr31/react-native-device-detection
import { isTablet } from 'react-native-device-detection;
// isTablet is a boolean. Return false o true immediately
//So ...
import styled from 'styled-components/native';
import theme from 'styled-theming';
import { isTablet } from 'react-native-device-detection';
const CoverPageDateText = styled.Text`
font-size: ${isTablet ? 23 : 17};
color: gray;
padding-bottom: 9;
`

What is the <{}> syntax after extends Component?

I started a new project today using React Native 0.51.0 and noticed that the class syntax for the default project file had something new added, the <{}> syntax after extends Component:
export default class App extends Component<{}> {
...
}
I tried doing research but most search engines ignore special characters even with exact string matching, so trying to find out what this syntax is has proved to be difficult. I did some testing and was able to figure out that this change appeared in v0.49.0. The release notes make no mention of what this added syntax does though.
A lot of vague keyword searching and reading leads me to believe that this may be syntax related to TypeScript, but being unfamiliar with the language, I'm at a loss as to how to search and find out more about the syntax without knowing what the proper term for it is. Could anyone tell me what the name of the syntax and what it does? Specifically with regards to React Native.
It is related to Flow typings for the props you will receive in the component. Component<{}> would mean that you don't expect the component to receive props.
With Flow and React.Component, you can define types for props and state (see React$Component type declaration for details).
Example from Flow documentation about React components
import * as React from 'react';
type Props = { /* ... */ };
type State = {
count: number,
};
class MyComponent extends React.Component<Props, State> {
state = {
count: 0,
};
componentDidMount() {
setInterval(() => {
this.setState(prevState => ({
count: prevState.count + 1,
}));
}, 1000);
}
render() {
return <div>Count: {this.state.count}</div>;
}
}
<MyComponent />;

Are there any flow types definition for react-native styles?

I'm making a react native component and using Flow to define the property types like this:
type Props = {
text: string,
textStyle: object
}
Those properties are then passed to the Text component inside my component. Are there any Flow type definitions for react-native that will allow me to do something like this:
textStyle: TextStyle
Now Flow would be able to check that the textStyle value contains only keys that are allowed for Text component style.
I see that there are interface definitions for TypeScript (React.TextStyle) but can't find anything for Flow.
Update 3:
Current best practice is:
import type {
ViewStyleProp,
TextStyleProp,
ImageStyleProp,
} from 'react-native/Libraries/StyleSheet/StyleSheet';
Update 2: The following PR makes things simpler, as of today flowtype styles are as follow.
type StyleValue = {[key: string]: Object} | number | false | null;
type StyleProp = StyleValue | Array<StyleValue>;
Obsolete: The following PR fixes it, can be found from v0.52.0
It is possible to do the following:
// #flow
import type { StyleObj } from 'react-native/Libraries/StyleSheet/StyleSheetTypes';
type Props = {
style?: StyleObj
};
Following discussion on: https://github.com/flowtype/flow-typed/issues/631#issuecomment-282009393
Update
StyleObj is no longer part of StyleSheetTypes.
Now import:
{LayoutStyle, TransformStyle, ShadowStyle, ViewStyle, TextStyle, ImageStyle, DangerouslyImpreciseStyle} from 'react-native/Libraries/StyleSheet/StyleSheetTypes';
In your case, you should:
import { TextStyle } from 'react-native/Libraries/StyleSheet/StyleSheetTypes';