I am trying to translate and position the Badge component by overriding the root CSS style, but for some reason it's not taking anything into effect. My Card component seems to be seeing the styling via the className prop, but I for some reason I the Badge component isn't seeing anything. I am following the documentation here.
Here's my component:
import React, { useState } from "react";
import PropTypes from "prop-types";
import Card from "#material-ui/core/Card";
import { Badge } from "#material-ui/core";
import CardHeader from "#material-ui/core/CardHeader";
import { makeStyles } from "#material-ui/core/styles";
const useStyles = makeStyles(theme => ({
root: {
anchorOriginTopRightRectangle: {
transform: "translate(-100%, -50%)"
}
},
card: {
maxWidth: 345
},
}));
const CardItem = ({
name,
discount
}) => {
const classes = useStyles();
return (
<Card className={classes.card}>
<CardHeader
title={
<>
{name}
<Badge
badgeContent={`-10%`}
color="error"
></Badge>
</>
}
subheader={"$1234"}
/>
// ... Card content
</Card>
);
};
export default(CardItem);
import React, { useState } from "react";
import PropTypes from "prop-types";
import Card from "#material-ui/core/Card";
import { Badge } from "#material-ui/core";
import CardHeader from "#material-ui/core/CardHeader";
import { makeStyles } from "#material-ui/core/styles";
const useStyles = makeStyles(theme => ({
anchorTopRight: {
transform: "translate(-100%, -50%)"
},
card: {
maxWidth: 345
},
}));
const CardItem = ({
name,
discount
}) => {
const classes = useStyles();
return (
<Card className={classes.card}>
<CardHeader
title={
<>
{name}
<Badge
classes={{ anchorOriginTopRightRectangle: classes.anchorTopRight}} // <== Working Code
badgeContent={`-10%`}
color="error"
></Badge>
</>
}
subheader={"$1234"}
/>
// ... Card content
</Card>
);
};
export default(CardItem);
Related
Here is my small sandbox only with Material-UI:
In this case my styling don't work as i expect
import React from 'react'
import { Typography } from "#mui/material";
import { makeStyles } from "#mui/styles";
const useStyles = makeStyles({
text: {
fontSize: 30,
},
});
function App() {
const classes = useStyles();
return (
<div className="App">
<Typography className={classes.text}>Hello world</Typography>
</div>
);
}
export default App
Result (https://ibb.co/S74pq0m)
I think you are not using material UI theme structure or are not aware of it so try to read about createTheme so you can use it globally https://mui.com/customization/typography/
import React from "react";
import { ThemeProvider, createMuiTheme } from "#mui/material";
import { Typography } from "#mui/material";
const theme = createMuiTheme({
typography: {
body2: {
fontSize: 30
}
},
});
export default function App() {
return (
<ThemeProvider theme={theme}>
<div className="App">
<Typography variant="body2">Hello World</Typography>
</div>
</ThemeProvider>
);
}
I am attempting to recreate the theme toggle feature that the material-ui website.
My Github Repo: https://github.com/jonnyg23/flask-rest-ecommerce/tree/next-app-migration
So far, I have noticed that material-ui's website uses a cookie called paletteType in order to store the client's theme choice. I understand that a Context Provider should be used to set the cookie, however, my nav-bar implementation has an issue changing themes after the second click of my theme toggle button.
Any help would be greatly appreciated, thank you.
CustomThemeProvider.js:
import React, { createContext, useState } from "react";
import { ThemeProvider } from "#material-ui/core/styles";
import getTheme from "../themes";
import Cookie from "js-cookie";
export const CustomThemeContext = createContext({
// Set the default theme and setter.
appTheme: "light",
setTheme: null,
});
const CustomThemeProvider = ({ children, initialAppTheme }) => {
// State to hold selected theme
const [themeName, _setThemeName] = useState(initialAppTheme);
// Retrieve theme object by theme name
const theme = getTheme(themeName);
// Wrap setThemeName to store new theme names as cookie.
const setThemeName = (name) => {
// console.log("CustomThemeProvider, SetThemeName", name);
Cookie.set("appTheme", name);
_setThemeName(name);
};
const contextValue = {
appTheme: themeName,
setTheme: setThemeName,
};
return (
<CustomThemeContext.Provider value={contextValue}>
<ThemeProvider theme={theme}>{children}</ThemeProvider>
</CustomThemeContext.Provider>
);
};
export default CustomThemeProvider;
_app.js:
import "../styles/globals.css";
import React, { useContext, useEffect } from "react";
import PropTypes from "prop-types";
import { useAuth0 } from "#auth0/auth0-react";
import Head from "next/head";
import { Provider as NextAuthProvider } from "next-auth/client";
import { makeStyles } from "#material-ui/core/styles";
import CssBaseline from "#material-ui/core/CssBaseline";
import Auth0ProviderWithHistory from "../auth/auth0-provider-with-history";
import CustomThemeProvider, {
CustomThemeContext,
} from "../context/CustomThemeProvider";
export default function App({ Component, pageProps }) {
// const { isLoading } = useAuth0();
const ThemeContext = useContext(CustomThemeContext);
useEffect(() => {
// Remove the server-side injected CSS.
const jssStyles = document.querySelector("#jss-server-side");
if (jssStyles) {
jssStyles.parentElement.removeChild(jssStyles);
}
}, []);
return (
<React.Fragment>
<Head>
<meta
name="viewport"
content="minimum-scale=1, initial-scale=1, width=device-width"
/>
</Head>
<CustomThemeProvider initialAppTheme={ThemeContext.appTheme}>
<Auth0ProviderWithHistory>
<NextAuthProvider session={pageProps.session}>
<CssBaseline />
<Component {...pageProps} />
</NextAuthProvider>
</Auth0ProviderWithHistory>
</CustomThemeProvider>
</React.Fragment>
);
}
App.propTypes = {
Component: PropTypes.elementType.isRequired,
pageProps: PropTypes.object.isRequired,
};
ThemeModeToggle.js:
import React, { useContext } from "react";
import { IconButton } from "#material-ui/core";
import { makeStyles } from "#material-ui/core/styles";
import Brightness5TwoToneIcon from "#material-ui/icons/Brightness5TwoTone";
import Brightness2TwoToneIcon from "#material-ui/icons/Brightness2TwoTone";
import { CustomThemeContext } from "../context/CustomThemeProvider";
const useStyles = makeStyles((theme) => ({
light: {
color: theme.palette.secondary.main,
},
dark: {
color: theme.palette.secondary.main,
},
}));
const ThemeModeToggle = ({ fontSize }) => {
const classes = useStyles();
const { appTheme, setTheme } = useContext(CustomThemeContext);
// console.log("ThemeModeToggle", appTheme);
const handleThemeChange = (appTheme, setTheme) => {
if (appTheme === "light") {
setTheme("dark");
} else {
setTheme("light");
}
};
return (
<IconButton onClick={() => handleThemeChange(appTheme, setTheme)}>
{appTheme === "light" ? (
<Brightness5TwoToneIcon fontSize={fontSize} className={classes.light} />
) : (
<Brightness2TwoToneIcon fontSize={fontSize} className={classes.dark} />
)}
</IconButton>
);
};
export default ThemeModeToggle;
Solved, I found the issue!
It turns out that my page components such as StorefrontIcon and the AppBar colors had to be explicitly added with className={classes.NAME} or with style={{ backroundColor: theme.palette.primary.main }} for example. Both methods are shown below in my nav-bar.js file.
import React from "react";
import { AppBar, Grid, Container, Toolbar } from "#material-ui/core";
import { makeStyles, useTheme } from "#material-ui/core/styles";
import StorefrontIcon from "#material-ui/icons/Storefront";
import MainNav from "./main-nav";
import AuthNav from "./auth-nav";
import ThemeModeToggle from "./ThemeModeToggle";
import { Desktop, SmallScreen } from "./Responsive";
import HamburgerMenu from "./HamburgerMenu";
const useStyles = makeStyles((theme) => ({
root: {
[theme.breakpoints.down("sm")]: {
padding: 0,
},
},
icon: {
color: theme.palette.primary.contrastText,
},
}));
const NavBar = () => {
const classes = useStyles();
const theme = useTheme();
return (
<AppBar
position="static"
elevation={3}
style={{ backgroundColor: theme.palette.primary.main }}
>
<Toolbar>
<Container className={classes.root}>
<Grid container justify="center" alignItems="center" spacing={2}>
<Desktop>
<Grid item xs={1}>
<StorefrontIcon fontSize="large" className={classes.icon} />
</Grid>
<Grid item xs={7}>
<MainNav />
</Grid>
<Grid item xs={3}>
<AuthNav />
</Grid>
<Grid item xs={1}>
<ThemeModeToggle fontSize="large" />
</Grid>
</Desktop>
<SmallScreen>
<Grid item xs={2}>
<StorefrontIcon fontSize="medium" className={classes.icon} />
</Grid>
<Grid container item xs={10} justify="flex-end">
<HamburgerMenu />
</Grid>
</SmallScreen>
</Grid>
</Container>
</Toolbar>
</AppBar>
);
};
export default NavBar;
How can I pass makeStyle classes from parent component to child component and combine them with the makeStyle classes in the child component? E.g. as below adding the breakpoint hiding to the child component style.
Example child component:
import React from "react"
import { Button } from "#material-ui/core"
import { makeStyles } from "#material-ui/core/styles"
const useStyles = makeStyles(theme => ({
button: {
background: "#000",
color: "white",
//lots of other css here so we dont want to repeat it in the parent component
},
}))
export default function PrimaryButton(props) {
const classes = useStyles()
const { children, fullWidth = false } = props
return (
<Button
fullWidth={fullWidth}
className={classes.button}
variant="contained"
>
{children}
</Button>
)
}
Example parent component:
import React from "react"
import { PrimaryButton } from "components/PrimaryButton"
import { makeStyles } from "#material-ui/core/styles"
const useStyles = makeStyles(theme => ({
primaryButton: {
display: "inline-block",
[theme.breakpoints.down("sm")]: {
display: "none",
},
},
}))
export default function PrimaryButton(props) {
const classes = useStyles()
return (
<PrimaryButton
className={classes.primaryButton}
>
Button text
</PrimaryButton>
)
}
clsx is used internally within Material-UI and is a convenient utility for combining multiple class names. In your child component, you can grab className from the props and then use className={clsx(className, classes.button)} in the Button it renders:
import React from "react";
import { Button } from "#material-ui/core";
import { makeStyles } from "#material-ui/core/styles";
import clsx from "clsx";
const useStyles = makeStyles(theme => ({
button: {
background: "#000",
color: "white"
}
}));
export default function PrimaryButton(props) {
const classes = useStyles();
const { children, className, fullWidth = false } = props;
return (
<Button
fullWidth={fullWidth}
className={clsx(className, classes.button)}
variant="contained"
>
{children}
</Button>
);
}
For some reason my material ui styles are not applying to my html element? Any idea why? I have no other styles applied to this page
import React, { Component } from 'react';
import LoginForm from '../components/form/loginForm';
import { makeStyles } from '#material-ui/core';
const classes = makeStyles( (theme) => ({
root: {
paddingTop: theme.spacing(8),
backgroundColor: "white"
},
}) )
class Login extends Component {
render() {
return(
<div className = {classes.root}>
<LoginForm/>
</div>
);
}
}
export default Login;
In your case, if you want to style your class component, you should use withStyles. Try this:
import React, { Component } from 'react';
import LoginForm from '../components/form/loginForm';
import { withStyles } from '#material-ui/core/styles';
const useStyles = (theme) => ({
root: {
paddingTop: theme.spacing(8),
backgroundColor: "white"
},
})
class Login extends Component {
render() {
const { classes } = this.props
return(
<div className = {classes.root}>
<LoginForm/>
</div>
);
}
}
export default withStyles(useStyles)(Login);
makeStyles returns a react hook to use in the component. Hooks also only work in functional components, so you'll need to convert Login to a functional component.
import React, { Component } from 'react';
import LoginForm from '../components/form/loginForm';
import { makeStyles } from '#material-ui/core';
const useStyles = makeStyles(theme => ({
root: {
paddingTop: theme.spacing(8),
backgroundColor: "lightblue"
}
}));
const Login = props => {
const classes = useStyles();
return(
<div className={classes.root}>
<LoginForm/>
</div>
);
}
export default Login;
I need to implement a <BackButton /> in react-admin for example when I open show page for a resource I need able to back to the list page.
Can you guide me to implement this?
I'm not familiar with react-admin routing mechanism.
Now I'm using this component in my edit form actions props:
const MyActions = ({ basePath, data, resource }) => (
<CardActions>
<ShowButton basePath={basePath} record={data} />
<CloneButton basePath={basePath} record={data} />
{/* Need <BackButton /> here */}
</CardActions>
);
export const BookEdit = (props) => (
<Edit actions={<MyActions />} {...props}>
<SimpleForm>
...
</SimpleForm>
</Edit>
);
You can use react-router-redux's goBack() function to achieve this.
For example, your button component will look something like this:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import Button from '#material-ui/core/Button';
import { goBack } from 'react-router-redux';
class BackButton extends Component {
handleClick = () => {
this.props.goBack();
};
render() {
return <Button variant="contained" color="primary" onClick={this.handleClick}>Go Back</Button>;
}
}
export default connect(null, {
goBack,
})(BackButton);
Now use that button component in your CardActions.
You can get help from an example which uses react-router-redux's push() function in a similar way from the official docs.
Create a back button. This one will pass props and children (text) and uses react-router directly, which I think makes more sense and keeps your code simple.
// BackButton.js
import React from 'react'
import Button from '#material-ui/core/Button'
import { withRouter } from 'react-router'
const BackButton = ({ history: { goBack }, children, ...props }) => (
<Button {...props} onClick={goBack}>
{children}
</Button>
)
export default withRouter(BackButton)
Example usage:
import { Toolbar, SaveButton } from 'react-admin'
import BackButton from './BackButton'
const SomeToolbar = props => (
<Toolbar {...props}>
<SaveButton />
<BackButton
variant='outlined'
color='secondary'
style={{ marginLeft: '1rem' }}
>
Cancel
</BackButton>
</Toolbar>
)
The complete code is below.
//BackButton.js
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import compose from 'recompose/compose';
import { withStyles, createStyles } from '#material-ui/core/styles';
import { translate } from 'ra-core';
import Button from '#material-ui/core/Button';
import ArrowBack from '#material-ui/icons/ArrowBack';
import classnames from 'classnames';
import { fade } from '#material-ui/core/styles/colorManipulator';
const styles = theme =>
createStyles({
deleteButton: {
color: theme.palette.error.main,
'&:hover': {
backgroundColor: fade(theme.palette.error.main, 0.12),
// Reset on mouse devices
'#media (hover: none)': {
backgroundColor: 'transparent',
},
},
},
});
const sanitizeRestProps = ({
basePath,
className,
classes,
label,
invalid,
variant,
translate,
handleSubmit,
handleSubmitWithRedirect,
submitOnEnter,
record,
redirect,
resource,
locale,
...rest
}) => rest;
class BackButton extends Component {
static contextTypes = {
router: () => true, // replace with PropTypes.object if you use them
}
static propTypes = {
label: PropTypes.string,
refreshView: PropTypes.func.isRequired,
icon: PropTypes.element,
};
static defaultProps = {
label: 'ra.action.back',
icon: <ArrowBack />,
};
render() {
const {
className,
classes = {},
invalid,
label = 'ra.action.back',
pristine,
redirect,
saving,
submitOnEnter,
translate,
icon,
onClick,
...rest
} = this.props;
return (
<Button
onClick={this.context.router.history.goBack}
label={label}
className={classnames(
'ra-back-button',
classes.backButton,
className
)}
key="button"
{...sanitizeRestProps(rest)}>
{icon} {label && translate(label, { _: label })}
</Button>
)
}
}
const enhance = compose(
withStyles(styles),
translate
);
export default enhance(BackButton);
//Toolbar.js
import React from 'react';
import {
Toolbar,
SaveButton,
DeleteButton,
} from 'react-admin';
import { withStyles } from '#material-ui/core';
import BackButton from './BackButton'
const toolbarStyles = {
toolbar: {
display: 'flex',
justifyContent: 'space-between',
},
};
export const CustomEditToolbar = withStyles(toolbarStyles)(props => (
<Toolbar {...props}>
<SaveButton/>
<DeleteButton/>
<BackButton/>
</Toolbar>
));
export const CustomCreateToolbar = withStyles(toolbarStyles)(props => (
<Toolbar {...props}>
<SaveButton/>
<BackButton/>
</Toolbar>
));