I have one button (from material ui) which is greyed out if the date is not set. If you set a date it should be clickable. I want to style the button for those cases.
This is the button:
<Button style={{
marginTop: 10
}} disabled={this.props.date ? false : true} onClick={this.sendRequest} variant="contained" color="primary">Send Request</Button>
Those are my button-classes for styling:
'.enabledButton': {
background: '#ffb303!important',
},
'.defaultButton': {
background: '#cfcfcf!important',
},
I tried to apply it in the false / true check. If its true it should apply the .enabledButton and for the false case it should apply the .defaultButton.
Can someone help me with it?
Thank you very much!
You can override css which is injected by material ui
you can use rule name
Both options are covered in the working demo here
Code snippet
const useStyles = makeStyles(theme => ({
root: {
"& > *": {
margin: theme.spacing(1)
},
// using classname
"& .Mui-disabled": {
background: "#ffb303"
}
}
}));
const useStyles2 = makeStyles(theme => ({
root: {
"& > *": {
margin: theme.spacing(1)
},
"&$disabled": {
background: "rgba(0, 0, 0, 0.12)",
color: "red",
boxShadow: "none"
}
},
disabled: {}
}));
export default function ContainedButtons(props) {
const classes = useStyles();
const classes2 = useStyles2();
return (
<>
<div className={classes.root}>
<Button
variant="contained"
color="primary"
disabled={props.date ? false : true}
>
Button (using css name)
</Button>
</div>
<div>
<Button
classes={{ root: classes2.root, disabled: classes2.disabled }}
variant="contained"
color="primary"
disabled={props.date ? false : true}
>
Button (using rule name)
</Button>
</div>
</>
);
}
In your case you can use classes atribute by material-ui. I made you a full example using a functional component:
import React from 'react'
import Button from '#material-ui/core/Button'
import { makeStyles } from '#material-ui/core/styles'
const useStyles = makeStyles(theme => ({
button: {
backgroundColor: '#ffb303',
},
disabledButton: {
backgroundColor: '#cfcfcf',
}
}))
export default () => {
const [disabled, setDisabled] = React.useState(false)
const classes = useStyles()
const toggleDisabled = () => setDisabled(prev => !prev)
return (
<>
<Button
disabled={disabled}
onClick={toggleDisabled}
classes={{
root: classes.button,
disabled: classes.disabled
}}
variant="contained"
>
Toggle
</Button>
<Button
disabled={!disabled}
onClick={toggleDisabled}
classes={{
root: classes.button,
disabled: classes.disabled
}}
variant="contained"
>
Toggle
</Button>
</>
)
}
const useStyles = makeStyles({
enabledButton: {
background: '#ffb303!important',
'&:disabled': {
background: '#cfcfcf!important',
}
},
});
function Componenet() {
const classes = useStyles();
...
...
return (
<Button
className={classes.enabledButton}
disabled={!this.props.date}
onClick={this.sendRequest}
variant="contained"
color="primary"
>
Send Request
</Button>
);
}
You can try it in 2 ways:
1st Method:
You can add the styles directly and do the validation like this (but its not preferrable to inject styles directly)
<div className={classes.root}>
<Button variant="contained">Default</Button>
<Button style={{
marginTop: 10,
backgroundColor: `${this.props.date ? '#ffb303':'#cfcfcf'}`
}} disabled={this.props.date ? false : true}
variant="contained" color="primary">Send Request</Button>
2nd Method:
You can use styles and do the validation in your code.
const useStyles = makeStyles((theme) => ({
enabledButton: {
backgroundColor: '#ffb303',
},
defaultButton: {
backgroundColor: '#cfcfcf',
},
}));
const classes = useStyles();
<div className={classes.root}>
<Button variant="contained">Default</Button>
<Button style={{
marginTop: 10,
}} disabled={this.props.date ? false : true}
className={this.props.date ? classes.enabledButton : classes.defaultButton}
variant="contained" color="primary">Send Request</Button>
simple and easy to use my snippet:
<TextField
fullWidth={fullWidth}
disabled={disabled}
onChange={onChange}
InputProps={{
classes: {
underline: classes.underline,
disabled: disabled ? classes.disabled : {},
},
}}
{...rest}
/>
)
classes
const useStyles = makeStyles((theme) => ({
label: {
paddingRight: theme.spacing(1),
fontFamily: 'Montserrat Light',
fontSize: `0.875rem`,
},
underline: {
marginTop: 0,
marginBottom: 0,
fontFamily: 'Montserrat Light',
color: `${$white}`,
fontSize: `0.875rem`,
'&::after': {
borderBottom: `1px solid ${$white}`,
},
'&::before': {
borderBottom: `1px solid rgba(255, 255, 255, 0.36)`,
},
'&:hover&::before': {
borderBottom: `1px solid ${$white}`,
},
},
disabled: {
'&:hover&::before': {
borderBottom: `1px dotted rgba(255, 255, 255, 0.36)`,
},
},
}))
Related
I have:
const Button: React.FC<ButtonProps> = ({
label,
size,
variant = 'primary',
disabled = false,
}: ButtonProps) => {
const classes = useStyles();
return (
<MaterialButton
className={`${classes.buttonBase} size-${size}`}
disabled={disabled}
>
{label}
</MaterialButton>
);
};
and
const useStyles = makeStyles(() => ({
buttonBase: {
background:'#000000',
color: '#ffffff',
However, if variant is secondary, I want to basically swap the background and color. How do I go about doing this?
You can set it in your theme.
The example below is for using the variant="contained" with color="secondary"
export const theme = createTheme({
components: {
MuiButton: {
styleOverrides: {
containedSecondary: {
backgroundColor: '#808080',
color: '#FFFFFF',
'&:hover': {
backgroundColor: '#565656',
},
},
}
}
}
<Button variant="contained" color="secondary">Test button</Button>
Or if you want to set the style in your component you can set up a variant for the secondary like this. Here is a working codesandbox
const useStyles = makeStyles({
primary: {
backgroundColor: "purple",
color: "#FFF"
},
secondary: {
backgroundColor: "red",
color: "#FFF"
}
});
<Button className={classes.secondary}>Secondary</Button>
<Button className={classes.primary}>Primary</Button>
I learn ReactJs and material-ui and now I have a problem with material TextField.
The code below creates this:
The problem I have is that the label="Tag Name" does not show the label text in the TextField.
When I click the TextField it looks like this:
The label label="Tag Name" should be visible in the TextFiled like this:
Please advice what is wrong?
import React from 'react';
import { connect } from 'react-redux';
import Dots from 'react-activity/lib/Dots';
import 'react-activity/lib/Dots/Dots.css';
import { Button, FormControl, InputLabel, Select, TextField, MenuItem } from '#material-ui/core';
import { withStyles } from '#material-ui/core/styles';
import { compose } from 'recompose';
import { changeDisplayName } from '../../../../../redux/userData/user.actions';
const styles = theme => ({
root: {
backgroundColor: theme.palette.primary.light,
// textAlign: 'center',
padding: '10px',
margin: 'auto',
display: 'flex',
justifyContent: 'space-around',
},
tagTextField: {
textAlign: 'left',
padding: '8px',
margin: '5px',
border: 'none',
borderRadius: '2px',
fontSize: '12pt',
// background: 'blue',
},
input: {
background: 'white',
color: 'black',
},
changeNameButton: {
backgroundColor: theme.palette.primary.main,
boxShadow: theme.shadows[5],
border: 'none',
borderRadius: '2px',
color: 'white',
margin: '5px',
padding: '8px',
cursor: 'pointer',
'&:hover': {
cursor: 'pointer',
backgroundColor: theme.palette.primary.dark,
},
'&:active': {
cursor: 'pointer',
backgroundColor: theme.palette.primary.dark,
},
'&:disabled': {
cursor: 'default',
color: 'gray',
backgroundColor: theme.palette.primary.main,
},
},
});
class AddTag extends React.Component {
constructor(props) {
super(props);
this.state = {
tagName: '',
categoryName: 'aaa',
categoryNames: ['aaaa', 'bbbb', 'cccc', 'dddd', 'fff'],
};
}
submit = () => {
// let todoListCopy = [...this.state.todoList];
// todoListCopy.push({
// todoName: this.state.todoName,
// userName: this.state.userName,
// });
// this.setState({
// todoName: '',
// todoList: todoListCopy,
// });
};
changeCategoryName = categoryName => {
this.setState({
categoryName,
});
};
changeTagName = tagName => {
this.setState({
tagName,
});
};
render() {
const { classes } = this.props;
const { tagName, categoryName, categoryNames } = this.state;
return (
<div className={classes.root}>
<TextField
className={classes.tagTextField}
id="outlined-basic"
label="Tag Name"
variant="outlined"
value={tagName}
onChange={e => this.changeTagName(e.target.value)}
autoComplete="off"
InputProps={{
className: classes.input,
}}
/>
<FormControl>
<InputLabel id="demo-simple-select-helper-label">Category</InputLabel>
<Select
labelId="demo-simple-select-helper-label"
id="demo-simple-select-helper"
value={categoryName}
onChange={e => this.changeCategoryName(e.target.value)}
>
{categoryNames &&
categoryNames.map((element, index) => {
return (
<MenuItem value={element} key={index}>
{element}
</MenuItem>
);
})}
</Select>
</FormControl>
<Button
className={classes.changeNameButton}
onClick={() => this.submit()}
variant="contained"
color="primary"
disabled={!tagName && !categoryName}
>
Save Tag
</Button>
</div>
);
}
}
const mapDispatchToProps = dispatch => ({
changeUserDisplayName: displayName => dispatch(changeDisplayName(displayName)),
});
const mapStateToProps = state => {
return {
savingDisplayName: state.user.isSavingDisplayName,
newDisplayName: state.user.displayName,
changeDisplayNameErr: state.user.changeDisplayNameErrMsg,
};
};
const enhance = compose(withStyles(styles), connect(mapStateToProps, mapDispatchToProps));
export default enhance(AddTag);
There is prop for this placeholder
Haven't made this feature before where you can change the color of button's hover.
I have already made a feature to change the radius with a slider, background color and font color using color-picker. However, I noticed the hover (for background AND font) could be better.
Here is the code:
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import Grid from "#material-ui/core/Grid";
import Slider from "#material-ui/core/Slider";
import Input from "#material-ui/core/Input";
import Button from "#material-ui/core/Button";
import { ChromePicker } from "react-color";
const useStyles = makeStyles((theme) => ({
root: {
"& > *": {
margin: theme.spacing(1)
}
},
Button: {
width: 150,
height: 50,
borderRadius: "var(--borderRadius)"
},
color: {
width: "36px",
height: "14px",
borderRadius: "2px"
},
swatch: {
padding: "5px",
background: "#fff",
borderRadius: "1px",
display: "inline-block",
cursor: "pointer"
},
popover: {
position: "absolute",
zIndex: "2"
},
cover: {
position: "fixed",
top: "0px",
right: "0px",
bottom: "0px",
left: "0px"
}
}));
export default function InputSlider() {
const classes = useStyles();
const [value, setValue] = React.useState(30);
const [color, setColor] = React.useState({ r: 0, g: 0, b: 0, a: 1 });
const [fontColor, setFontColor] = React.useState({
r: 255,
g: 255,
b: 255,
a: 1
});
const [displayColorPicker, setDisplayColorPicker] = React.useState(true);
const handleSliderChange = (event, newValue) => {
setValue(newValue);
};
const handleInputChange = (event) => {
setValue(event.target.value === "" ? "" : Number(event.target.value));
};
const handleBlur = () => {
if (value < 0) {
setValue(0);
} else if (value > 30) {
setValue(30);
}
};
const handleClick = () => {
setDisplayColorPicker(!displayColorPicker);
};
const handleClose = () => {
setDisplayColorPicker(false);
};
const handleChange = (color) => {
setColor(color.rgb);
};
const handleFontColorChange = (color) => {
setFontColor(color.rgb);
};
return (
<div className={classes.root}>
<style>
{`:root {
--borderRadius = ${value}px;
}`}
</style>
<Button
style={{
borderRadius: value,
background: `rgba(${color.r}, ${color.g}, ${color.b}, ${color.a})`,
color: `rgba(${fontColor.r}, ${fontColor.g}, ${fontColor.b}, ${fontColor.a})`
}}
variant="contained"
color="primary"
value="value"
onChange={handleSliderChange}
className={classes.Button}
>
Fire laser
</Button>
<Grid container spacing={2}>
<Grid item xs>
<Slider
value={typeof value === "number" ? value : 0}
onChange={handleSliderChange}
aria-labelledby="input-slider"
/>
</Grid>
<Grid item>
<Input
value={value}
margin="dense"
onChange={handleInputChange}
onBlur={handleBlur}
inputProps={{
step: 10,
min: 0,
max: 24,
type: "number"
}}
/>
</Grid>
</Grid>
<div>
<div style={useStyles.swatch} onClick={handleClick}>
{displayColorPicker} <p class="h4">Background</p>
<div style={useStyles.color} />
</div>
{displayColorPicker ? (
<div style={useStyles.popover}>
<div style={useStyles.cover} onClick={handleClose}></div>
<ChromePicker color={color} onChange={handleChange} />
</div>
) : null}
</div>
<div>
<div style={useStyles.swatch} onClick={handleClick}>
{displayColorPicker} <p class="h4">Font</p>
<div style={useStyles.color} />
</div>
{displayColorPicker ? (
<div style={useStyles.popover}>
<div style={useStyles.cover} onClick={handleClose}></div>
<ChromePicker color={fontColor} onChange={handleFontColorChange} />
</div>
) : null}
</div>
</div>
);
}
And here is the sandbox - https://codesandbox.io/s/material-demo-forked-t8xut?file=/demo.js
Any advice?
Does anyone have a good Material UI article for editing/cool features and projects to play with?
You need to pass props to makeStyles.
First, pass fontColor variable as below when declaring classes:
const classes = useStyles({ hoverBackgroundColor, hoverFontColor })();
then in the useStyles, you can have access to the fontColor as a prop, as below:
const useStyles = ({ hoverBackgroundColor, hoverFontColor }) =>
makeStyles((theme) => ({
Button: {
width: 150,
height: 50,
borderRadius: "var(--borderRadius)",
"&:hover": {
backgroundColor: `rgba(${hoverBackgroundColor.r}, ${hoverBackgroundColor.g}, ${hoverBackgroundColor.b}, ${hoverBackgroundColor.a}) !important`,
color: `rgba(${hoverFontColor.r}, ${hoverFontColor.g}, ${hoverFontColor.b}, ${hoverFontColor.a}) !important`
}
},
sandbox
I have a select textfiled and i want when i hover or select the textfiled the arrow down color change too, this is my textfiled and style of that
Style
const styles = theme => ({
icon: {
fill: themeStyle.textColor,
},
underline: {
'&:before': {
borderBottomColor: themeStyle.textFieldUnderLineColor,
},
'&:after': {
borderBottomColor: themeStyle.tabIndicatorProps,
color: themeStyle.tabIndicatorProps,
},
'&:hover:before': {
borderBottomColor: [themeStyle.underLineSearchTextFieldColor, '!important'],
},
color: themeStyle.titleTextColor,
},
notchedOutline: {},
outlinedInput: {
'&$focused $notchedOutline': {
border: `2px solid ${themeStyle.tabIndicatorProps}`
},
backgroundColor: themeStyle.bkgBodyColor
},
focused: {},
notchedOutline: {},
})
textfield
<TextField
select
SelectProps={{
native: true,
}}
className = {classes.textField}
InputLabelProps={{
classes: {
root: classes.cssLabel,
focused: classes.cssFocused,
}
}}
InputProps={{
classes:{
underline: classes.underline,
icon: classes.icon
}
}}
type= 'select'
>
{Tools.GetEnumSelectOptionsAddAll(APP_Enums.DoModeEnum)}
</TextField>
now i want to change the color of this when i hover or select or ...
You should use the SelectProps property to feed the style you required.
Here is a working example - https://codesandbox.io/s/material-demo-select-6lewu
Refer to the below,
const useStyles = makeStyles((theme) => ({
root: {
"& .MuiTextField-root": {
margin: theme.spacing(1),
width: "25ch"
}
},
icon: {
color: "red"
}
}));
export default function MultilineTextFields() {
const classes = useStyles();
const [currency, setCurrency] = React.useState("EUR");
const [isMouseOver, setMouseOver] = React.useState(false);
const handleChange = (event) => {
setCurrency(event.target.value);
};
const handleMouseEnter = () => {
setMouseOver(true);
};
const handleMouseLeave = () => {
setMouseOver(false);
};
return (
<form className={classes.root} noValidate autoComplete="off">
<div>
<TextField
id="standard-select-currency-native"
select
label="Native select"
value={currency}
onChange={handleChange}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
SelectProps={{
native: true,
classes: {
icon: isMouseOver ? classes.icon : null
}
}}
helperText="Please select your currency"
>
{currencies.map((option) => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</TextField>
</div>
</form>
);
}
In addition to that, I used onMouseEnter and onMouseLeave triggers to apply the special request you had to change the icon color when mouse over.
I've tried multiple different ways to try to attach an image in draft-js.
My attempts followed the example in the tutorial https://www.draft-js-plugins.com/plugin/image. For the "Add Image Button Example", the full source of which can be found here https://github.com/draft-js-plugins/draft-js-plugins/tree/master/docs/client/components/pages/Image/AddImageEditor. I have also tried to follow this medium article that does not use the image plugin to do a similar thing https://medium.com/#siobhanpmahoney/building-a-rich-text-editor-with-react-and-draft-js-part-2-4-persisting-data-to-server-cd68e81c820.
If I set the initial state with the image already embedded it renders. However, when using a mechanism that adds it later on it doesn't seem to work. I've read some mentions of various version of plugins / draft.js having issues.
My versions:
"draft-js-image-plugin": "^2.0.7",
"draft-js": "^0.11.6",
import { EditorState } from 'draft-js';
import Editor from 'draft-js-plugins-editor';
import createInlineToolbarPlugin, { Separator } from 'draft-js-inline-toolbar-plugin';
import createImagePlugin from 'draft-js-image-plugin';
import 'draft-js/dist/Draft.css';
import 'draft-js-inline-toolbar-plugin/lib/plugin.css';
import {
ItalicButton,
BoldButton,
UnderlineButton,
HeadlineOneButton,
CodeButton,
UnorderedListButton,
OrderedListButton,
BlockquoteButton,
} from 'draft-js-buttons';
interface TextEditorProps {
label?: string;
value: EditorState;
onChange?: (editorState: EditorState) => void;
className?: string;
disabled?: boolean;
}
const useStyles = makeStyles((theme) => ({
label: {
margin: theme.spacing(1)
},
editor: {
boxSizing: 'border-box',
border: '1px solid #ddd',
cursor: 'text',
padding: '16px',
borderRadius: '2px',
marginBottom: '2em',
boxShadow: 'inset 0px 1px 8px -3px #ABABAB',
background: '#fefefe',
minHeight: '50vh'
}
}));
const inlineToolbarPlugin = createInlineToolbarPlugin();
const imagePlugin = createImagePlugin();
const { InlineToolbar } = inlineToolbarPlugin;
const plugins = [inlineToolbarPlugin, imagePlugin];
const TextEditor:React.FunctionComponent<TextEditorProps> = ({label, value, onChange, className, disabled }: TextEditorProps) => {
const editor = React.useRef(null);
const focusEditor = () => {
editor.current.focus();
}
React.useEffect(() => {
focusEditor()
}, []);
const classes = useStyles();
const insertImage = () => {
onChange(imagePlugin.addImage(value, "https://ichef.bbci.co.uk/news/976/cpsprodpb/12A9B/production/_111434467_gettyimages-1143489763.jpg"));
}
return (
<Box className={className} onClick={focusEditor}>
{label && <InputLabel className={classes.label}>{label}</InputLabel>}
<div className="menuButtons">
<button className="inline styleButton">
<i
className="material-icons"
style={{
fontSize: "16px",
textAlign: "center",
padding: "0px",
margin: "0px"
}}
onClick={insertImage}
>
image
</i>
</button>
</div>
<Box className={!disabled && classes.editor} >
<Editor
ref={editor}
editorState={value}
onChange={onChange}
plugins={plugins}
spellCheck={true}
readOnly={disabled}
/>
{<InlineToolbar>
{(externalProps) => (
<>
<BoldButton {...externalProps} />
<ItalicButton {...externalProps} />
<UnderlineButton {...externalProps} />
<CodeButton {...externalProps} />
<Separator {...externalProps} />
<UnorderedListButton {...externalProps} />
<OrderedListButton {...externalProps} />
<BlockquoteButton {...externalProps} />
<HeadlineOneButton {...externalProps} />
</>
)}
</InlineToolbar>}
</Box>
</Box>
)
}
You editorState change is overriding the change from insertImage. You are triggering focusEditor along with onClick insertImage
Don't need additional plugins, if you don't mind getting hands dirty and learning how to insert into content.
<i
className="material-icons"
style={{
fontSize: "16px",
textAlign: "center",
padding: "0px",
margin: "0px"
}}
onClick={() => insertImage('https://ichef.bbci.co.uk/news/976/cpsprodpb/12A9B/production/_111434467_gettyimages-1143489763.jpg')}
>
custom insertImage function, in your case, editorState should be replaced with 'value'
import { EditorState, AtomicBlockUtils } from “draft-js”; //<-- need add this import
const insertImage = ( url ) => {
const contentState = editorState.getCurrentContent();
const contentStateWithEntity = contentState.createEntity(
'IMAGE',
'IMMUTABLE',
{ src: url },)
const entityKey = contentStateWithEntity.getLastCreatedEntityKey();
const newEditorState = EditorState.set( editorState, { currentContent: contentStateWithEntity });
onChange(AtomicBlockUtils.insertAtomicBlock(newEditorState, entityKey, '')) //Update the editor state
};
image upload with draftjs