StyleSheet - Extend Style Value in React Native - css

Exists some way to do something like this?
const styles = StyleSheet.create({
content: {
alignItems: 'center',
flex: 1,
justifyContent: 'center'
},
mainColor: { color: '#FFFFFF' },
usernameIcon: {
{this.styles.mainColor} // <-- How import the style, instead does write the code - color: '#FFFFFF'?
},
usernameItem: {
backgroundColor: '#FF8484',
borderColor: '#FFFFFF',
paddingTop: 7
},
});
Add many classes in my components it's very verbose and I likely do something likes the code above.

There's no style inheritance syntax (like those of CSS preprocessors) in React Native.
But since it's all JS you can just do it with JS:
const MAIN_COLOR = 'white';
const someStyle = {
padding: 5,
margin: 5,
}
const styles = StyleSheet.create({
usernameIcon: {
color: MAIN_COLOR,
...someStyle,
},
generalStyle: {
backgroundColor: 'white',
}
})
// you can also combine styles in the component
// note that the latter style will override duplicated styles
<View style={[styles.usernameIcon, styles.generalStyle]} />

Related

React Select adjust the first option layout

I'm trying to adjust the first option to be centered in the option in the React Select but nothing it is working for that ( all other adjustments in the CSS of React Select it is working). here the code that I'm using in the option values:
const option = (provided, state) => ({
...provided,
background: state.isSelected ? theme.colors.green600 : theme.colors.white,
color: state.isSelected ? theme.colors.white : theme.colors.grey500,
display: 'flex',
fontFamily: 'CircularStd',
lineHeight: '18px',
fontSize: '14px',
':nth-child(0) ': {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
textTransform: 'uppercase',
},
});
obs: the option it is inside of customStyles, and I'm passing into the Select, like styles={customStyles}
In order to style the first option you may want to target the :first-child of the MenuList. Here is the example
const styles = {
menuList: (provided, state) => {
return {
...provided,
"& :first-child": {
textAlign: "center"
}
};
}
};
Live Example

In MaterialUI, how do I apply a class to my Typography element?

In my material-ui component, I want to create an ellipsis when my Typography element overflows. I created these styles ...
const styles = (theme) => ({
root: {
textAlign: "left",
margin: theme.spacing(2),
paddingBottom: theme.spacing(1),
color: theme.color.secondary,
},
cardHeader: {
paddingBottom: theme.spacing(0),
},
cardContent: {
paddingBottom: theme.spacing(1),
},
rowBody: {
width: "100%",
flexWrap: "nowrap",
alignItems: "center",
display: "flex",
},
halfRow: {
width: "50%",
},
address: {
"& .MuiTypography-h5": {
textOverflow: "ellipsis",
overflow: "hidden",
},
}
and I applied the "address" class to my Typography element like so
<Typography variant="h5" className={classes.address}>
<a href={`https://www.google.com/maps/dir/"${location}"`}>{location}</a>
</Typography>
However, the ellipsis is not appearing and the element is wrapping
What else do I need to do to apply a style to my Typography element?
Your address class should be added to the parent of the Typography component else the style chaining won't work.
address: {
"& .MuiTypography-h5": {
textOverflow: "ellipsis",
overflow: "hidden",
},
}
What it means is that find a class .MuiTypography-h5 inside address class and apply the style but there isn't any.
Also I recommend you use makeStyles to create styles.
const styles = makeStyles(theme => ({
address: {
"& .MuiTypography-h5": {
textOverflow: "ellipsis",
overflow: "hidden"
}
}
}));
export default function App() {
const classes = styles();
return (
<div className={classes.address}>
<Typography variant="h5">
126 Phillips Key Suite 042 West Kentucky
</Typography>
</div>
);
}

How to make Material-UI Snackbar not take up the whole screen width using anchorOrigin?

I have a class in React which uses an input field which is part of the website header:
If the input is invalid then I want to display a snackbar. I'm using Material-UI components.
The problem is I defined anchorOrigin to be center and top as per Material-UI API. However the snackbar takes up the whole screen width while I want it to only take up the top center location of the screen. My message is quite short, for example "Value invalid" but if it's longer then I should be able to use newlines. I'm not sure if there's some setting in Material-UI API to alter this (I couldn't find one) or I need to use CSS.
This is my code:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import InputBase from '#material-ui/core/InputBase';
import Snackbar from '#material-ui/core/Snackbar';
import SnackbarMessage from './SnackbarMessage.js';
const classes = theme => ({
inputRoot: {
color: 'inherit',
width: '100%',
},
inputInput: {
paddingTop: theme.spacing.unit,
paddingRight: theme.spacing.unit,
paddingBottom: theme.spacing.unit,
paddingLeft: theme.spacing.unit * 10,
transition: theme.transitions.create('width'),
width: '100%',
[theme.breakpoints.up('sm')]: {
width: 120,
'&:focus': {
width: 200,
},
},
}
});
class Test extends Component {
state = {
appId: '',
snackBarOpen: false
}
render() {
return (
<div>
<InputBase
placeholder="Search…"
classes={{
root: classes.inputRoot,
input: classes.inputInput,
}}
value={'test'} />
<Snackbar
anchorOrigin={{
vertical: 'top',
horizontal: 'center'
}}
open={true}
autoHideDuration={5000}
>
<SnackbarMessage
variant="warning"
message={"test message"}
/>
</Snackbar>
</div>
)
}
}
Material-UI set Snackbars to full viewport-width below the breakpoint "md" (600px).
You can use overrides (https://material-ui.com/customization/overrides/) and set new values to the default CSS classes of the component described in the components API (i.e. https://material-ui.com/api/snackbar/). So you can override the class anchorOriginTopCenter as follows:
const styles = theme => ({
anchorOriginTopCenter: {
[theme.breakpoints.down('md')]: {
top: "your value/function here",
justifyContent: 'center',
},
},
root: {
[theme.breakpoints.down('md')]: {
borderRadius: 4,
minWidth: "your value / function here",
},
},
});
The first objects overrides the default class {anchorOriginTopCenter}, the second 'root' is applied to first element in your snackbar (probably a 'div').
I do not know if we can add some style to the component anchor origin field. I think the div needs to be managed using CSS. It's an anchor, not style.
<Snakbar
className = "my-snakbar"
{/*All your other stuff*/}
>
{//Stuff}
</Snakbar>
CSS
.my-snakbar {
width: 200px;
//Maybe use flexbox for positioning then
}
Let me know your thoughts
Daniel
Improved Answer
Code copied from origional question and modified
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Snackbar from '#material-ui/core/Snackbar';
const classes = theme => ({
inputRoot: {
color: 'inherit',
width: '100%',
},
inputInput: {
paddingTop: theme.spacing.unit,
paddingRight: theme.spacing.unit,
paddingBottom: theme.spacing.unit,
paddingLeft: theme.spacing.unit * 10,
transition: theme.transitions.create('width'),
width: '100%',
[theme.breakpoints.up('sm')]: {
width: 120,
'&:focus': {
width: 200,
},
},
}
});
class ComingSoon extends Component {
render() {
const styles = {
container: {
position: "fixed",
top: "0px",
width: "100%",
height: "30px"
},
snakbar: {
background: "black",
color: "white",
width: "100px",
height: "100%",
display: "flex",
justifyContent: "center",
alignContent: "center",
margin: "0 auto"
}
};
return (
<div className = "snakbar-container" style = {styles.container}>
<Snackbar
className = "my-snakbar"
style = {styles.snakbar}
anchorOrigin={{
vertical: 'top',
horizontal: 'center'
}}
open={true}
autoHideDuration={5000}
>
<span>My Message</span>
</Snackbar>
</div>
)
}
}
export default ComingSoon;
Screen shot:
Let me know if this helped
Daniel

Customize MUI Table styles - last-child

I am trying to adjust the padding of MUI Table.
last-child gets padding 24px which I want to adjust. I have tried to override the theme and to use classes{{root: classes.xxx}} but am not able to change it.
Below is the code I used for overriding the theme (I have also tried to override MuiTableRow and MuiTableColumn):
const theme = createMuiTheme({
overrides: {
MuiTableCell: {
root: {
paddingTop: 4,
paddingBottom: 4,
'& $lastChild': { paddingRight: '5px' },
},
paddingDefault: {
padding: '40px 12px 40px 16px',
},
},
},
});
This is the CSS that I am trying to change (the last cell of each row in the table):
.MuiTableCell-root-511:last-child {
padding-right: 24px;
}
Hope someone can give a helping hand.
Thats the right approach, you just have a few syntax errors in your JSS.
The last child selector should be:
'&:last-child': {}
Here a complete example
const theme = createMuiTheme({
overrides: {
MuiTableCell: {
root: {
paddingTop: 4,
paddingBottom: 4,
"&:last-child": {
paddingRight: 5
}
}
}
}
});
For those who don't want to override theme, you can achieve the same result by providing classes object prop as shown here.
const useStyles = makeStyles({
cell: {
'&:last-child': {
paddingRight: 5,
},
},
});
Provide it to your TableCell as usual;
<TableCell className={classes.cell}>
This will override the &:last-child attribute of your cell. I've found this method to be a little more convenient when I'm not changing anything else in the theme.
In MUI v5, you can use the sx prop and select the last TableCell like this:
<Table
sx={{
'& .MuiTableCell-root:last-child': {
bgcolor: 'pink',
},
}}
>
Or if you want to use createTheme() to override globally:
const theme = createTheme({
components: {
MuiTableCell: {
styleOverrides: {
root: {
'&:last-child': {
backgroundColor: 'tomato',
},
},
},
},
},
});
Live Demo

Can I make dynamic styles in React Native?

Say I have a component with a render like this:
<View style={jewelStyle}></View>
Where jewelStyle =
{
borderRadius: 10,
backgroundColor: '#FFEFCC',
width: 20,
height: 20,
},
How could I make the background colour dynamic and randomly assigned? I've tried
{
borderRadius: 10,
backgroundColor: getRandomColor(),
width: 20,
height: 20,
},
But this makes all instances of View have the same colour, I want each one to be unique.
Any tips?
I usually do something along the lines of:
<View style={this.jewelStyle()} />
...
jewelStyle = function(options) {
return {
borderRadius: 12,
background: randomColor(),
}
}
Every time View is rendered, a new style object will be instantiated with a random color associated with it. Of course, this means that the colors will change every time the component is re-rendered, which is perhaps not what you want. Instead, you could do something like this:
var myColor = randomColor()
<View style={jewelStyle(myColor)} />
...
jewelStyle = function(myColor) {
return {
borderRadius: 10,
background: myColor,
}
}
Yes you can and actually, you should use StyleSheet.create to create your styles.
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View
} from 'react-native';
class Header extends Component {
constructor(props){
super(props);
}
render() {
const { title, style } = this.props;
const { header, text } = defaultStyle;
const combineStyles = StyleSheet.flatten([header, style]);
return (
<View style={ combineStyles }>
<Text style={ text }>
{ title }
</Text>
</View>
);
}
}
const defaultStyle = StyleSheet.create({
header: {
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#fff',
height: 60,
paddingTop: 15,
shadowColor: '#000',
shadowOffset: { width: 0, height: 3 },
shadowOpacity: 0.4,
elevation: 2,
position: 'relative'
},
text: {
color: '#0d4220',
fontSize: 16
}
});
export default Header;
And then:
<Header title="HOME" style={ {backgroundColor: '#10f1f0'} } />
If you still want to take advantage of StyleSheet.create and also have dynamic styles, try this out:
const Circle = ({initial}) => {
const initial = user.pending ? user.email[0] : user.firstName[0];
const colorStyles = {
backgroundColor: randomColor()
};
return (
<View style={[styles.circle, colorStyles]}>
<Text style={styles.text}>{initial.toUpperCase()}</Text>
</View>
);
};
const styles = StyleSheet.create({
circle: {
height: 40,
width: 40,
borderRadius: 30,
overflow: 'hidden'
},
text: {
fontSize: 12,
lineHeight: 40,
color: '#fff',
textAlign: 'center'
}
});
Notice how the style property of the View is set as an array that combines your stylesheet with your dynamic styles.
The easiest is mine:
<TextInput
style={[
styles.default,
this.props.singleSourceOfTruth ?
{ backgroundColor: 'black' }
: { backgroundColor: 'white' }
]}/>
Had some issue syntactically.
This worked for me
<Text style={[styles.textStyle,{color: 'red'}]}> Hello </Text>
const styles = StyleSheet.create({
textStyle :{
textAlign: 'center',
fontFamily: 'Arial',
fontSize: 16
}
});
You'll want something like this:
var RandomBgApp = React.createClass({
render: function() {
var getRandomColor = function() {
var letters = '0123456789ABCDEF'.split('');
var color = '#';
for (var i = 0; i < 6; i++ ) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
};
var rows = [
{ name: 'row 1'},
{ name: 'row 2'},
{ name: 'row 3'}
];
var rowNodes = rows.map(function(row) {
return <Text style={{backgroundColor:getRandomColor()}}>{row.name}</Text>
});
return (
<View>
{rowNodes}
</View>
);
}
});
In this example I take the rows array, containing the data for the rows in the component, and map it into an array of Text components. I use inline styles to call the getRandomColor function every time I create a new Text component.
The issue with your code is that you define the style once and therefore getRandomColor only gets called once - when you define the style.
I know this is extremely late, but for anyone still wondering here's an easy solution.
You could just make an array for the styles :
this.state ={
color: "#fff"
}
style={[
styles.jewelstyle, {
backgroundColor: this.state.BGcolor
}
The second will override any original background color as stated in the stylesheet. Then have a function that changes the color:
generateNewColor(){
var randomColor = '#'+Math.floor(Math.random()*16777215).toString(16);
this.setState({BGcolor: randomColor})
}
This will generate a random hex color. Then just call that function whenever and bam, new background color.
Actually, you can write your StyleSheet.create object as a key with function value, it works properly but it has a type issue in TypeScript:
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
const SomeComponent = ({ bgColor }) => (
<View style={styles.wrapper(bgColor)}>
<Text style={styles.text}>3333</Text>
</View>
);
const styles = StyleSheet.create({
wrapper: color => ({
flex: 1,
backgroundColor: color,
}),
text: {
color: 'red',
},
});
import React, { useContext, useMemo } from 'react';
import { Text, StyleSheet, View } from 'react-native';
import colors from '../utils/colors';
import ThemeContext from './../contexts/ThemeContext';
export default (props) => {
const { theme } = useContext(ThemeContext);
// Constructing styles for current theme
const styles = useMemo(() => createStyles(theme), [theme]);
return (
<View style={styles.container}>
<Text style={styles.label}>{label}</Text>
</View>
);
};
const createStyles = (theme: AppTheme) =>
StyleSheet.create({
container: { width: '100%', position: 'relative', backgroundColor: colors[theme].background },
label: {
fontSize: 13,
fontWeight: 'bold',
},
});
colors.ts
export type AppTheme = 'dark' | 'light';
const light: Colors = {
background: '#FFFFFF',
onBackground: '#333333',
gray: '#999999',
grayLight: '#DDDDDD',
red: 'red',
};
const dark: Colors = {
background: '#333333',
onBackground: '#EEEEEE',
gray: '#999999',
grayLight: '#DDDDDD',
red: 'red',
};
const colors = {
dark,
light,
primary: '#2E9767',
secondary: '#F6D130',
};
export default colors;
Using object spread operator "..." worked for me:
<View style={{...jewelStyle, ...{'backgroundColor': getRandomColor()}}}></View>
Yes, you can make dynamic styles. You can pass values from Components.
First create StyleSheetFactory.js
import { StyleSheet } from "react-native";
export default class StyleSheetFactory {
static getSheet(backColor) {
return StyleSheet.create({
jewelStyle: {
borderRadius: 10,
backgroundColor: backColor,
width: 20,
height: 20,
}
})
}
}
then use it in your component following way
import React from "react";
import { View } from "react-native";
import StyleSheetFactory from './StyleSheetFactory'
class Main extends React.Component {
getRandomColor = () => {
var letters = "0123456789ABCDEF";
var color = "#";
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
};
render() {
return (
<View>
<View
style={StyleSheetFactory.getSheet(this.getRandomColor()).jewelStyle}
/>
<View
style={StyleSheetFactory.getSheet(this.getRandomColor()).jewelStyle}
/>
<View
style={StyleSheetFactory.getSheet(this.getRandomColor()).jewelStyle}
/>
</View>
);
}
}
<View
style={[styles.categoryItem,{marginTop: index <= numOfColumns-1 ? 10 : 0 }]}
>
I know there are several answers, but i think the best and most simple is using a state "To change" is the state purpose.
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
style: {
backgroundColor: "white"
}
};
}
onPress = function() {
this.setState({style: {backgroundColor: "red"}});
}
render() {
return (
...
<View style={this.state.style}></View>
...
)
}
}
You can bind state value directly to style object. Here is an example:
class Timer extends Component{
constructor(props){
super(props);
this.state = {timer: 0, color: '#FF0000'};
setInterval(() => {
this.setState({timer: this.state.timer + 1, color: this.state.timer % 2 == 0 ? '#FF0000' : '#0000FF'});
}, 1000);
}
render(){
return (
<View>
<Text>Timer:</Text>
<Text style={{backgroundColor: this.state.color}}>{this.state.timer}</Text>
</View>
);
}
}
If you are using a screen with filters for example, and you want to set the background of the filter regarding if it was selected or not, you can do:
<TouchableOpacity style={this.props.venueFilters.includes('Bar')?styles.filterBtnActive:styles.filterBtn} onPress={()=>this.setFilter('Bar')}>
<Text numberOfLines={1}>
Bar
</Text>
</TouchableOpacity>
On which set filter is:
setVenueFilter(filter){
var filters = this.props.venueFilters;
filters.push(filter);
console.log(filters.includes('Bar'), "Inclui Bar");
this.setState(previousState => {
return { updateFilter: !previousState.updateFilter };
});
this.props.setVenueFilter(filters);
}
PS: the function this.props.setVenueFilter(filters) is a redux action, and this.props.venueFilters is a redux state.
You can do something like this.
In your component:
const getRandomColor = () => {
// you can use your component props here.
}
<View style={[styles.jewelStyle, {backgroundColor: getRandomColor()}]} />
Create your style using stylesheet:
const styles = StyleSheet.create({
jewelStyle: {
backgroundColor: 'red',
},
});
If you are following the functional approach of React-Native, you can use a package called dynamic-styles that tries to solve exactly your problem.
// -- theme.js ------------------------------------------------------
// Initialization of a StyleSheet instance called 'styleSheet'
export const styleSheet = createStyleSheet({
theme: /* optional theme */
});
// -- MyComponent.js -----------------------------------------------
// Create dynamic stylesheet that has access
// to the previously specified theme and parameters
const useStyles = styleSheet.create(({theme, params}) => ({
root: /* Dynamic Styles */,
button: /* Dynamic Styles */,
text: /* Dynamic Styles */,
}));
const MyComponent = (props) => {
// Access dynamic styles using the created 'useStyles()' hook
// and specify the corresponding parameters
const { styles } = useStyles({ color: props.color, fontSize: 10 });
return (
<div className={styles.root}>
{/* */}
</div>
);
}
It basically allows you to create dynamic stylesheets
and link them to functional Components using the React hook pattern.
-> Codesandbox
In case someone needs to apply conditions
selectedMenuUI = function(value) {
if(value==this.state.selectedMenu){
return {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 20,
paddingVertical: 10,
backgroundColor: 'rgba(255,255,255,0.3)',
borderRadius: 5
}
}
return {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 20,
paddingVertical: 10
}
}
Here is what worked for me:
render() {
const { styleValue } = this.props;
const dynamicStyleUpdatedFromProps = {
height: styleValue,
width: styleValue,
borderRadius: styleValue,
}
return (
<View style={{ ...styles.staticStyleCreatedFromStyleSheet, ...dynamicStyleUpdatedFromProps }} />
);
}
For some reason, this was the only way that mine would update properly.
you can use styled-components for react native it will provide you dynamic styling just like emotion or styled-components for web.
For something relatively simple, you can use this approach:
StyleSheet.create({
item: props.selectedId === item.id ? {
backgroundColor: 'red',
}: null
});

Resources