import withStyles from "#material-ui/core/styles"
function styles() {
return {
item: {
color: "red"
}
}
}
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
<li>{number}</li>
);
I want to be able to do <li className={classes.item}>. I want the each list item to get the color property from the item key in the styles object. Usually, the styles object is accessed by withStyles(styles) but how can I do this in this situation?
You could achieve this in a lot of different ways. The simplest one I can think of is using a inline style tag like this:
class YourClass extends Component {
render() {
const numbers = [1, 2, 3, 4, 5]
return (
{numbers.map(number =>
<li style={{ color: "red" }}>{number}</li>
)}
);
}
}
Or you could create a Theme like the API recommends here and use it like this:
import { MuiThemeProvider, createMuiTheme } from '#material-ui/core/styles';
import red from '#material-ui/core/colors/red';
const theme = createMuiTheme({
palette: {
customColor: { main: red },
},
});
class YourClass extends Component {
render() {
const numbers = [1, 2, 3, 4, 5]
return (
<MuiThemeProvider theme={theme}>
{numbers.map(number =>
<li style={{ color: theme.palette.customColor.main }}>{number}</li>
)}
</MuiThemeProvider>
);
}
}
Related
I currently have lots of dialogs and want to change DialogTitle to have Typography h5 heading. Currently this works:
<DialogTitle>
<Typography variant="h5">Create Exercise</Typography>
</DialogTitle>
But I want this to be applied to all dialogs without having to add use the typography component. I also have tried the following with createTheme, but this does not change the fontSize.
const theme = createTheme({
components: {
MuiDialogTitle: {
styleOverrides: {
root: {
// Set this to h5
fontSize: "1.5rem",
},
},
},
},
});
Modify the DialogTitle component as mention below 👇
import MuiDialogTitle from "#material-ui/core/DialogTitle";
import Typography from "#material-ui/core/Typography";
import { withStyles } from "#material-ui/core/styles";
const styles = (theme) => ({
root: {
margin: 0,
padding: theme.spacing(2),
},
});
const DialogTitle = withStyles(styles)((props) => {
const { children, classes, ...other } = props;
return (
<MuiDialogTitle disableTypography className={classes.root} {...other}>
<Typography variant="h5">{children}</Typography>
</MuiDialogTitle>
);
});
export default DialogTitle;
use this component as DialogTitle, even you can modify the style and also able to add extra component into DialogTitle, like closing icon or some secondary title.
I have a header and want to style all of it's buttons differently than my global theme. I have tried using a child theme like:
<ThemeProvider
theme={(outerTheme) =>
_.merge(outerTheme, {
overrides: {
MuiButton: {
label: {
color: "#fff",
},
},
},
})
}
>
However, while I had expected this to override only MuiButton's in the child theme, it overrode them in them globally.
I know I can use makeStyles but, then, as far as I know, I have to reference it in all the child components which want to use the style. I'd like to wrap a higher level component and have all child components pick up the style. How is this done?
You can do this:
import Button from '#material-ui/core/Button';
import { purple } from '#material-ui/core/colors';
import { makeStyles } from '#material-ui/core/styles';
const useStyles = makeStyles((theme) => ({
header: {
"& button": {
marginRight: theme.spacing(1),
color: theme.palette.getContrastText(purple[500]),
backgroundColor: purple[500],
"&:hover": {
backgroundColor: purple[700],
},
},
},
});
function CustomHeader(props) {
const classes = useStyles();
return (
<div className={classes.header}>
<Button>Button 1</Button>
<Button>Button 2</Button>
<Button disabled>Button 3</Button>
</div>
)
};
I'm trying to decorate some text, but instead of making the process managed by a regex strategy, it should be the results of an ajax call to specify which peace of text to decorate. Is it possible to use any method from Modifier library? My idea is to call something inside the onChange method and modify the editorstate.
Any idea would be appreciated.
My solution uses a custom decorator and a dynamic regex, this combination might help achieve the effect you are hoping for.
Code structure follows this example to decorate tweets in draftjs.
You can replace the string array (var arr = ["one", "two", "three"]) in the code with an ajax call.
import React, { Component } from 'react';
import { Editor, EditorState, CompositeDecorator } from 'draft-js';
const styles = {
handle: {
color: 'black',
backgroundColor: '#FF7F7F',
direction: 'ltr',
unicodeBidi: 'bidi-override',
},
};
// arr can be accessed from an ajax call
var arr = ["one", "two", "three"]
const HANDLE_REGEX = new RegExp("(?:[\\s]|^)(" + arr.join("|") + ")(?=[\\s]|$)", 'gi')
function handleStrategy(contentBlock, callback, contentState) {
findWithRegex(HANDLE_REGEX, contentBlock, callback);
}
function findWithRegex(regex, contentBlock, callback) {
const text = contentBlock.getText();
let matchArr, start;
while ((matchArr = regex.exec(text)) !== null) {
start = matchArr.index;
callback(start, start + matchArr[0].length);
}
}
const HandleSpan = (props) => {
return (
<span
style={styles.handle}
data-offset-key={props.offsetKey}
>
{props.children}
</span>
);
};
class App extends Component {
constructor(props) {
super(props);
const compositeDecorator = new CompositeDecorator([
{
strategy: handleStrategy,
component: HandleSpan,
}
]);
this.state = {
editorState: EditorState.createEmpty(compositeDecorator),
};
this.onChange = (editorState) => this.setState({editorState});
}
render() {
return (
<div className="container-root">
<Editor
editorState={this.state.editorState}
onChange={this.onChange}
placeholder="Write..."
ref="editor"
spellCheck={true}
/>
</div>
);
}
}
export default App;
Thinking of the concept of a SASS mixin, what would be the best approach to enable the re-use of style blocks that incorporate the current theme.
For example I have two components that import their respective styles:
Component 1
index
styles
Component 2
index
styles
Each component has a text block
Component 1
import { styles } from './styles'
....
<div className={classes.richText}>...</div>
Component 2
import { styles } from './styles'
....
<div className={classes.richText}>...</div>
The styles for richText are the same but I would rather not duplicate them in the imported styles file.
I would rather have a single file that exposes reusable CSS properties based on the theme.
The only way I can currently do this is by returning an object that I have passed the theme to e.g.
const RichText = (theme) => {
return {
fontWeight: 100,
color: theme.typography.body1.color
}
}
Then import this into the styles
Component 1
styles.js
import { RichText } from '../mixins/'
const styles = theme => ({
richText: {
...RichText(theme),
fontSize: '1rem'
}
Component 2
styles.js
import { RichText } from '../mixins/'
const styles = theme => ({
richText: {
...RichText(theme),
fontSize: '1.2rem'
}
Feels like there has to be a better way: utilising withTheme() maybe?
Let's say you want to custom a checkbox as below:
import { makeStyles } from '#material-ui/core/styles';
import CheckBox from '#material-ui/core/CheckBox';
const useStyles = makeStyles((theme) => ({
root: {
color: theme.status.danger,
'&$checked': {
color: theme.status.danger,
},
},
checked: {},
}));
function CustomCheckbox() {
const classes = useStyles();
return (
<Checkbox
defaultChecked
classes={{
root: classes.root,
checked: classes.checked,
}}
/>
);
}
And you want to reuse its style as many components as you can.
You have two options: ThemeProvider or export your custom style.
Changing the component's theme
Themes let you apply a consistent tone to your app. It allows you to customize all design aspects of your project in order to meet the specific needs of your business or brand.
import { createMuiTheme, ThemeProvider } from '#material-ui/core/styles';
import orange from '#material-ui/core/colors/orange';
const myTheme = createMuiTheme({
status: {
danger: orange[500],
},
});
export default function CustomStyles() {
return (
<ThemeProvider theme={myTheme}>
<CustomCheckbox />
</ThemeProvider>
);
}
Exporting your custom styles
Separate your components in a proper folder, i.e: ./assets/styles:
import { makeStyles } from '#material-ui/core/styles';
export const useCheckBoxStyles = makeStyles((theme) => ({
root: {
color: theme.status.danger,
'&$checked': {
color: theme.status.danger,
},
},
checked: {},
}));
And your components tree ./components:
import { useCheckBoxStyles } from './assets/styles';
function CustomCheckbox() {
const classes = useCheckBoxStyles();
return (
<Checkbox
defaultChecked
classes={{
root: classes.root,
checked: classes.checked,
}}
/>
);
}
References
https://material-ui.com/customization/theming
when i click a checkbox in a tag panel, then it becomes checked as expect. But when i switch to another panel, and then switch back, i found that checkbox which should be checked turn to unchecked. how do i fix this?
here is my code, and i use react-tab-panel from npm.
Container:
export default class Container extends Component {
static propTypes = {
};
constructor(props) {
super(props);
this.state = {
chosenItem: {
a: [],
b: [],
c: [],
d: []
}
};
}
handleCheckBoxChange = (e) => {
const value = e.target.value;
const item = e.target.attributes.getNamedItem('data-tag').value;
const chosenItem = this.state.chosenItem;
const index = chosenItem[item].indexOf(value);
if (index > -1) {
chosenItem[item].splice(index, 1);
}
chosenItem[item].push(value);
}
render() {
return (
<div>
<Panel
handleCheckBoxChange={this.handleCheckBoxChange}
/>
</div>
);
}
}
Panel:
import TabPanel from 'react-tab-panel';
import 'react-tab-panel/index.css';
import CheckBox from './CheckBox.jsx';
export default function Panel({
handleCheckBoxChange
}) {
const tabList = {
a: ['1', '2'],
b: ['1', '2'],
c: ['1', '2'],
d: ['1', '2']
};
return (
<TabPanel
tabPosition="left"
>
{
Object.keys(tabList).map((key) => {
return (
<form
key={key}
tabTitle={key}
>
{
tabList[key].map((item) =>
<CheckBox
key={item}
value={item}
handleCheckBoxChange={handleCheckBoxChange}
tag={key}
/>
)
}
</form>
);
})
}
}
</TabPanel>
);
}
Checkbox:
export default function CheckBox({
tag,
value,
handleCheckBoxChange
}) {
return (
<div>
<label>
<input
type="checkbox"
value={value}
onChange={handleCheckBoxChange}
data-tag={tag}
/>
{value}
</label>
</div>
);
}
You should consider using Flux or Redux for storing your application state tree.