Initialize react hook in a class based component - reactjs

I am trying to change the function-based component to the class-based component. I am getting an error while converting. How to initialize hook in a class component.
Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
This is the error I am getting
Papebase Material UI
import React from 'react';
import PropTypes from 'prop-types';
import { createMuiTheme, ThemeProvider, withStyles } from '#material-ui/core/styles';
import CssBaseline from '#material-ui/core/CssBaseline';
import Hidden from '#material-ui/core/Hidden';
import Typography from '#material-ui/core/Typography';
import Link from '#material-ui/core/Link';
import Navigator from '../Components/Navigator';
import Content from './Content';
import Header from '../Components/Header';
import { Switch, Route, BrowserRouter, Link as RouteLink } from "react-router-dom";
import { connect } from 'react-redux';
import { logout } from '../actions/auth';
function Copyright() {
return (
<Typography variant="body2" color="textSecondary" align="center">
{'Copyright © '}
<Link color="inherit" href="https://material-ui.com/">
Podo
</Link>{' '}
{new Date().getFullYear()}
{'.'}
</Typography>
);
}
let theme = createMuiTheme({
palette: {
primary: {
light: '#63ccff',
main: '#009be5',
dark: '#006db3',
},
},
typography: {
h5: {
fontWeight: 500,
fontSize: 26,
letterSpacing: 0.5,
},
},
shape: {
borderRadius: 8,
},
props: {
MuiTab: {
disableRipple: true,
},
},
mixins: {
toolbar: {
minHeight: 48,
},
},
});
theme = {
...theme,
overrides: {
MuiDrawer: {
paper: {
backgroundColor: '#18202c',
},
},
MuiButton: {
label: {
textTransform: 'none',
},
contained: {
boxShadow: 'none',
'&:active': {
boxShadow: 'none',
},
},
},
MuiTabs: {
root: {
marginLeft: theme.spacing(1),
},
indicator: {
height: 3,
borderTopLeftRadius: 3,
borderTopRightRadius: 3,
backgroundColor: theme.palette.common.white,
},
},
MuiTab: {
root: {
textTransform: 'none',
margin: '0 16px',
minWidth: 0,
padding: 0,
[theme.breakpoints.up('md')]: {
padding: 0,
minWidth: 0,
},
},
},
MuiIconButton: {
root: {
padding: theme.spacing(1),
},
},
MuiTooltip: {
tooltip: {
borderRadius: 4,
},
},
MuiDivider: {
root: {
backgroundColor: '#404854',
},
},
MuiListItemText: {
primary: {
fontWeight: theme.typography.fontWeightMedium,
},
},
MuiListItemIcon: {
root: {
color: 'inherit',
marginRight: 0,
'& svg': {
fontSize: 20,
},
},
},
MuiAvatar: {
root: {
width: 32,
height: 32,
},
},
},
};
const drawerWidth = 256;
const styles = {
root: {
display: 'flex',
minHeight: '100vh',
},
drawer: {
[theme.breakpoints.up('sm')]: {
width: drawerWidth,
flexShrink: 0,
},
},
app: {
flex: 1,
display: 'flex',
flexDirection: 'column',
},
main: {
flex: 1,
padding: theme.spacing(6, 4),
background: '#eaeff1',
},
footer: {
padding: theme.spacing(2),
background: '#eaeff1',
},
};
export class Paperbase extends React.Component {
render() {
const { classes } = this.props;
const [mobileOpen, setMobileOpen] = React.useState(false);
const handleDrawerToggle = () => {
setMobileOpen(!mobileOpen);
};
return (
<BrowserRouter>
<ThemeProvider theme={theme}>
<div className={classes.root}>
<CssBaseline />
<nav className={classes.drawer}>
<Hidden smUp implementation="js">
<Navigator
PaperProps={{ style: { width: drawerWidth } }}
variant="temporary"
open={mobileOpen}
onClose={handleDrawerToggle}
/>
</Hidden>
<Hidden xsDown implementation="css">
<Navigator PaperProps={{ style: { width: drawerWidth } }} />
</Hidden>
</nav>
<div className={classes.app}>
<Header onDrawerToggle={handleDrawerToggle} />
<main className={classes.main}>
<Switch>
<Route exact path="/dashboard/auth" render={() => <Content /> } />
<Route path="/Inbox" render={() => <div> Page inbox</div>} />
<Route path="/Starred" render={() => <div>PSage starred</div>} />
</Switch>
</main>
<footer className={classes.footer}>
<Copyright />
</footer>
</div>
</div>
</ThemeProvider>
</BrowserRouter>
)
}
}
Paperbase.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(Paperbase);

Short answer you can't use react hooks on class based components.

Slightly longer answer:
Hooks were introduced to allow use of state in function components. If you're using a class component, then the mechanisms to manipulate state are built into the default class component behavior.
So in your example, you'd want to do something like:
Replace your state hook:
const [mobileOpen, setMobileOpen] = React.useState(false);
const handleDrawerToggle = () => {
setMobileOpen(!mobileOpen);
};
with a stateful class component and setState():
class PaperBase extends React.Component {
constructor(props){
super(props);
this.state = {
mobileOpen: true,
}
this.handleDrawerToggle = this.handleDrawerToggle.bind(this);
}
handleDrawerToggle = () => {
let mobileOpen = this.state.mobileOpen;
mobileOpen != mobileOpen;
this.setState = {
mobileOpen: mobileOpen,
}
}
// ...
}
Rather than explain how it all works here, I'll suggest reading the official tutorial on state in components: https://reactjs.org/docs/state-and-lifecycle.html

Related

Dark Mode in react using MUI v5

Trying to create a Toggle to switch from dark mode to light mode has been quite difficult for me in v5.
Using the code directly from MUI Sandbox MUI darkmode, I attempted to separate the code to work in the app.js and my Navbarpractice.js.
App.js
import React from "react";
import useMediaQuery from '#mui/material/useMediaQuery';
import { createTheme, ThemeProvider } from '#mui/material/styles';
import CssBaseline from '#mui/material/CssBaseline';
import { Paper } from "#mui/material";
import BasicCard from "./components /Card.js";
import Navbarpractice from "./components /Navbar/Navbarpractice"
const ColorModeContext = React.createContext({ toggleColorMode: () => {} });
function App() {
const [mode, setMode] = React.useState('light');
const colorMode = React.useMemo(
() => ({
toggleColorMode: () => {
setMode((prevMode) => (prevMode === 'light' ? 'dark' : 'light'));
},
}),
[],
);
const theme = React.useMemo(
() =>
createTheme({
palette: {
mode,
},
}),
[mode],
);
return (
<ColorModeContext.Provider value={colorMode}>
<ThemeProvider theme={theme}>
<div className="App">
<Navbarpractice/>
<BasicCard/>
</div>
</ThemeProvider>
</ColorModeContext.Provider>
);
}
export default App;
Navbarpractice.js
import React from 'react';
import AppBar from '#mui/material/AppBar';
import Box from '#mui/material/Box';
import Toolbar from '#mui/material/Toolbar';
import Typography from '#mui/material/Typography';
import Button from '#mui/material/Button';
import IconButton from '#mui/material/IconButton';
import MenuIcon from '#mui/icons-material/Menu';
import { useTheme, ThemeProvider, createTheme } from '#mui/material/styles';
import { teal } from '#mui/material/colors';
import { withStyles } from '#mui/styles';
import { Switch } from '#mui/material';
import Brightness4Icon from '#mui/icons-material/Brightness4';
import Brightness7Icon from '#mui/icons-material/Brightness7';
const label = { inputProps: { 'aria-label': 'Switch' } };
const ColorModeContext = React.createContext({ toggleColorMode: () => {} });
const theme = createTheme({
Navbar: {
primary: {
// Purple and green play nicely together.
main: teal[500],
},
secondary: {
// This is green.A700 as hex.
main: '#11cb5f',
},
},
});
const TealTextTypography = withStyles({
root: {
color: "#008080"
}
})(Typography);
function Navbar() {
const theme = useTheme();
const colorMode = React.useContext(ColorModeContext);
return (
<ColorModeContext.Provider value={colorMode}>
<ThemeProvider theme={theme}>\
<Box sx={{ flexGrow: 1 }}>
<AppBar position="static"
style={{ background: 'transparent', boxShadow: 'none'}}>
<Toolbar>
<IconButton
size="large"
edge="start"
aria-label="menu"
sx={{ mr: 2 }}
>
<MenuIcon />
</IconButton>
<TealTextTypography variant="h6" component="div" sx={{ flexGrow: 1 }}>
Mentors
</TealTextTypography>
<TealTextTypography variant="h6" component="div" sx={{ flexGrow: 1 }}>
Mentees
</TealTextTypography>
<Box
sx={{
display: 'flex',
width: '100%',
alignItems: 'center',
justifyContent: 'center',
bgcolor: 'background.default',
color: 'text.primary',
borderRadius: 1,
p: 3,
}}
>
<IconButton sx={{ ml: 1 }} onClick={colorMode.toggleColorMode} color="inherit">
{ theme.palette.mode === 'dark' ? <Brightness7Icon /> : <Brightness4Icon />}
</IconButton>
</Box>
</Toolbar>
</AppBar>
</Box>
</ThemeProvider>
</ColorModeContext.Provider>
);
}
export default Navbar;
I am certain I am mixing up my const. and placing them in the wrong places. Although I am new to react and Mui I did manage to get it to work statically, however, the toggle is proving to be difficult.
This seem to work for me
App.js
import React from 'react';
import {
ThemeProvider,
createTheme,
responsiveFontSizes,
} from '#mui/material/styles';
import { deepmerge } from '#mui/utils';
import useMediaQuery from '#mui/material/useMediaQuery';
import { getDesignTokens, getThemedComponents } from 'theme/Theme';
import { ColorModeContext } from 'config/color-context';
export default function App() {
const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
const [mode, setMode] = React.useState();
React.useEffect(() => {
setMode(prefersDarkMode ? 'dark' : 'light');
}, [prefersDarkMode]);
const colorMode = React.useMemo(
() => ({
toggleColorMode: () => {
setMode((prevMode) => (prevMode === 'light' ? 'dark' : 'light'));
},
}),
[]
);
let theme = React.useMemo(
() =>
createTheme(deepmerge(getDesignTokens(mode), getThemedComponents(mode))),
[mode]
);
theme = responsiveFontSizes(theme);
return (
<ColorModeContext.Provider value={colorMode}>
<ThemeProvider theme={theme}>
...
</ThemeProvider>
</ColorModeContext.Provider>
);
}
Theme.js
import { amber, deepOrange, grey, blue, common } from '#mui/material/colors';
const palette = {
light: {
primary: {
main: '#34C0AC',
light: '#B1DED3',
dark: '#00765A',
},
},
};
export const getDesignTokens = (mode) => ({
palette: {
mode,
...(mode === 'light'
? {
primary: {
main: palette.light.primary.main,
light: palette.light.primary.light,
dark: palette.light.primary.dark,
},
divider: amber[200],
text: {
primary: grey[900],
secondary: grey[800],
},
}
: {
primary: deepOrange,
divider: deepOrange[700],
background: {
default: deepOrange[900],
paper: deepOrange[900],
},
text: {
primary: '#fff',
secondary: grey[500],
},
}),
},
typography: {
fontFamily: [
'Oswald',
'Roboto',
'"Helvetica Neue"',
'Arial',
'sans-serif',
].join(','),
body1: {
fontFamily: 'Poppins, Arial, sans-serif',
},
},
});
export const getThemedComponents = (mode) => ({
components: {
...(mode === 'light'
? {
MuiAppBar: {
styleOverrides: {
colorPrimary: {
backgroundColor: grey[800],
},
},
},
MuiLink: {
variant: 'h3',
},
MuiButton: {
styleOverrides: {
root: {
borderRadius: 0,
color: common.white,
fontFamily:
"Oswald, Roboto, 'Helvetica Neue', Arial, sans-serif",
fontSize: 20,
borderWidth: 2,
'&:hover': {
borderWidth: 2,
},
},
},
variants: [
{
props: { variant: 'contained' },
style: {
fontFamily:
"Oswald, Roboto, 'Helvetica Neue', Arial, sans-serif",
},
},
{
props: { variant: 'outlined' },
style: {
color: palette.light.primary.main,
},
},
{
props: { variant: 'primary', color: 'primary' },
style: {
border: '4px dashed blue',
},
},
],
},
MuiList: {
styleOverrides: {
root: {},
},
},
MuiMenuItem: {
styleOverrides: {
root: {
color: common.white,
alignItems: 'stretch',
fontFamily:
"Oswald, Roboto, 'Helvetica Neue', Arial, sans-serif",
},
},
},
MuiAccordion: {
styleOverrides: {
root: {
color: common.white,
fontFamily:
"Oswald, Roboto, 'Helvetica Neue', Arial, sans-serif",
},
},
},
}
: {
MuiAppBar: {
styleOverrides: {
colorPrimary: {
backgroundColor: blue[800],
},
},
},
}),
},
});
color-context.js
import React from 'react';
export const ColorModeContext = React.createContext({
toggleColorMode: () => {
// This is intentional
},
});
ThemeToggler.js
import React from 'react';
import { IconButton, Box } from '#mui/material';
import { useTheme } from '#mui/material/styles';
import Brightness4Icon from '#mui/icons-material/Brightness4';
import Brightness7Icon from '#mui/icons-material/Brightness7';
import { ColorModeContext } from 'config/color-context';
export default function SubHeaderNavigation() {
const theme = useTheme();
const colorMode = React.useContext(ColorModeContext);
return (
<Box
sx={{
display: 'flex',
width: '100%',
alignItems: 'center',
justifyContent: 'center',
bgcolor: 'background.default',
color: 'text.primary',
borderRadius: 1,
p: 3,
}}
>
{theme.palette.mode} mode
<IconButton
sx={{ ml: 1 }}
onClick={colorMode.toggleColorMode}
color="inherit"
>
{theme.palette.mode === 'dark' ? (
<Brightness7Icon />
) : (
<Brightness4Icon />
)}
</IconButton>
</Box>
);
}
Make sure you are not nesting your Themes or both could be negated.
For example:
App.tsx
<>
<ThemeProvider theme={!isDark ? lightTheme : darkTheme}>
<CssBaseline />
<Dashboard />
</ThemeProvider>
</>
Dashboard.tsx taken from here
function Dashboard() {
...
return (
<ThemeProvider theme={mdTheme}>
<Box sx={{ display: 'flex' }}>
<CssBaseline />
...
</ThemeProvider>
);
}
export default function Dashboard() {
return <DashboardContent />;
}
The effect of this will negate the Themes in the App.tsx config.

Property 'spacing' does not exist on type 'DefaultTheme'

can someone see what I am doing wrong? I am getting an error property spacing does not exist on type defaulttheme.
there error is on this line... padding: theme.spacing(3),
I am using #mui/material#5.2.5
also using typescript
This is from following an example on netninja material tutorial.
below is my app.tsx
import { createTheme, ThemeProvider } from "#mui/material/styles";
const theme3 = createTheme({
palette: {
primary: {
main: "#fefefe",
},
// secondary: #dd63dd,
},
typography: {
fontFamily: "Rajdhani",
// fontFamily: "Quicksand",
fontWeightLight: 400,
fontWeightRegular: 500,
fontWeightMedium: 600,
fontWeightBold: 700,
},
});
const AskPage = React.lazy(() => import("./AskPage"));
const store = configureStore();
function App() {
return (
<ThemeProvider theme={theme3}>
<AuthProvider>
<Provider store={store}>
<BrowserRouter>
<Layout>
<Routes>
<Route path="" element={<Notes />} />
<Route path="create" element={<Create />} />
</Routes>
</Layout>
</BrowserRouter>
</Provider>
</AuthProvider>
</ThemeProvider>
);
}
export default App;
then on my layout.tsx file... this is how I am trying to use it.
import { makeStyles } from "#mui/styles";
const useStyles = makeStyles((theme) => {
return {
page: {
background: "#f1f1f1",
width: "100%",
padding: theme.spacing(3),
},
drawer: {
width: drawerWidth,
},
drawerPaper: {
width: drawerWidth,
},
root: {
display: "flex",
},
active: {
background: "#f4f4f4",
},
// appbar: {
// width: "calc(100% - ${drawerWidth}px)",
// },
// toolbar: theme.mixins.toolbar,
};
});
I am assuming you have wrapped your whole app around ThemeProvider so all you just need to remove const theme = createTheme();
In your code above there is technically 2 variables with the same name. You are declaring one which you should remove, and then the other one is being declared within makeStyles.
As long as you have wrapped your app within ThemeProvider then you can just pull the theme out of makeStyles.
Adding this to app.tsx should do
declare module "#mui/private-theming" {
interface DefaultTheme {
spacing: (spacing: number) => string;
}
}

react-autosuggest how to style input and autosuggestion when using along with Material-ui

I am using react-autosuggest in my Material-UI component to get suggestions when user types. And just not able to style the input field and the suggestions text.
Probably I am missing something basic here, and any guidance will be immensly helpful. The official dox of react-autosuggest is here for using the theme technique that uses react-themeable. But I could not implement that in my Material-UI component.
The below is my code that I am trying with.
import React, { useEffect, useState } from 'react'
import PropTypes from 'prop-types'
import { makeStyles } from '#material-ui/core/styles'
import Autosuggest from 'react-autosuggest';
import { defaultTheme } from 'react-autosuggest/dist/theme';
const useStyles = makeStyles(theme => ({
container: {
margin: 'auto',
backgroundColor: theme.background.default,
},
innerTableContainer: {
height: 'calc(100vh - 190px)',
borderRadius: theme.shape.borderRadius,
backgroundColor: theme.background.paper,
},
react_autosuggest__container: {
"position": "relative",
"width": "440px",
},
react_autosuggest__input: {
"width": "240px",
"height": "30px",
"padding": "10px 20px",
"fontFamily": "Helvetica, sans-serif",
"fontWeight": "300",
"fontSize": "16px",
"border": "1px solid #aaa",
"borderRadius": "4px"
},
react_autosuggest__input__focused: {
"outline": "none"
},
react_autosuggest__input__open: {
"borderBottomLeftRadius": "0",
"borderBottomRightRadius": "0"
},
react_autosuggest__suggestions_container__open: {
"display": "block",
"position": "absolute",
"top": "51px",
"width": "280px",
"border": "1px solid #aaa",
"backgroundColor": "#fff",
"fontFamily": "Helvetica, sans-serif",
"fontWeight": "300",
"fontSize": "16px",
"borderBottomLeftRadius": "4px",
"borderBottomRightRadius": "4px",
"zIndex": "2"
},
react_autosuggest__suggestions_list: {
"margin": "0",
"padding": "0",
"listStyleType": "none"
},
react_autosuggest__suggestion: {
"cursor": "pointer",
"padding": "10px 20px"
},
react_autosuggest__suggestion__highlighted: {
"backgroundColor": "#ddd"
}
}))
const GithubMostPopularList = () => {
const classes = useStyles()
const [value, setValue] = useState('')
const [suggestions, setSuggestions] = useState([])
const onChange = (event, { newValue, method }) => {
setValue(newValue)
};
const onSuggestionsFetchRequested = ({ value }) => {
setSuggestions(getSuggestions(value))
};
const onSuggestionsClearRequested = () => {
setSuggestions([])
};
const inputProps = {
placeholder: "Start typing your city name",
value,
onChange: onChange,
};
return (
<div className={classes.container}>
<div className={classes.react_autosuggest__container} >
<Autosuggest
suggestions={suggestions}
onSuggestionsFetchRequested={onSuggestionsFetchRequested}
onSuggestionsClearRequested={onSuggestionsClearRequested}
getSuggestionValue={getSuggestionValue}
renderSuggestion={renderSuggestion}
inputProps={inputProps}
/>
</div>
)}
</div>
)
}
export default GithubMostPopularList
I have also tried this solution given in one of Github issue
<Autosuggest
//misc extra props I've cut out for brevity
theme={{
...defaultTheme,
...{
container: {
...defaultTheme.container,
display: 'visible',
width: '340px',
},
//more overrides
}
}}
/>
But in this case the component is not compiling at all.
Answering my own question.
I was able to solve it as below, the useStyles = makeStyles() portion remains the same and the below is how to change the defulat theme of react-autosuggest.
import { defaultTheme } from 'react-autosuggest/dist/theme';
....
....
const GithubMostPopularList = () => {
.....
.....
return (
<div className={classes.container}>
{console.log('GITHUB USER ', JSON.stringify(globalStore.githubUser))}
<div className={classes.tableAndFabContainer}>
{globalStore.loading ? (
<div className={classes.spinner}>
<LoadingSpinner />
</div>
) : (
<div className={classes.table}>
{console.log('VALUE IS ', value)}
<div className={classes.inputandButtonContainer} >
<Autosuggest
suggestions={suggestions}
onSuggestionsFetchRequested={onSuggestionsFetchRequested}
onSuggestionsClearRequested={onSuggestionsClearRequested}
getSuggestionValue={getSuggestionValue}
renderSuggestion={renderSuggestion}
inputProps={inputProps}
theme={{
...defaultTheme,
container: classes.react_autosuggest__container,
input: classes.react_autosuggest__input,
inputOpen: classes.react_autosuggest__input__open,
inputFocused: classes.react_autosuggest__input__focused,
suggestionsContainer: classes.react_autosuggest__suggestions_container,
suggestionsContainerOpen: classes.react_autosuggest__suggestions_container__open,
suggestionsList: classes.react_autosuggest__suggestions_list,
suggestion: classes.react_autosuggest__suggestion,
suggestionHighlighted: classes.react_autosuggest__suggestion__highlighted,
}
}
/>
</div>
</div>
)}
</div>
</div>
)
}
export default GithubMostPopularList
Not sure about what you did. This is what I did, and it works well :
One component with the definition of your styling, and the Autosuggest component you render :
import { makeStyles } from '#material-ui/styles';
const useStyles = makeStyles({
container: {
position: "relative",
},
input: {
width: "240px",
height: "30px",
width: '80%',
padding: "10px 20px",
fontFamily: "Helvetica, sans-serif",
fontWeight: "bold",
fontSize: "16px",
border: "1px solid #aaa",
borderRadius: "4px"
},
inputFocused: {
outlineStyle: "none"
}
// add other styling here...
});
const MyAutosuggest = (props) => {
const inputProps = {
placeholder: 'Type a programming language',
value: props.value,
onChange: props.onChange
};
const theme = useStyles();
return(
<Autosuggest
suggestions={props.suggestions}
onSuggestionsFetchRequested={props.onSuggestionsFetchRequested}
onSuggestionsClearRequested={props.onSuggestionsClearRequested}
getSuggestionValue={getSuggestionValue}
renderSuggestion={renderSuggestion}
inputProps={inputProps}
theme={theme}
/>
)
}
I import MyAutosuggest in the component where I implement autosuggest :
import MyAutosuggest from './Autosuggest';
<MyAutosuggest
value={this.state.value}
onChange={this.onChange}
suggestions={this.state.suggestions}
onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
onSuggestionsClearRequested={this.onSuggestionsClearRequested}
/>

Can't declare keyframe within withStyles HOC (container.addRule(...).addRule is not a function)

So I got the latest versions of jss and material ui.
Im using withStyles HOC and dynamically changing css in styles object, but I cant seem to be able to declare keyframes in css. Im also using nextjs if that makes any difference. Ive looked at how material-ui declares their animations, and I'm following their example https://github.com/mui-org/material-ui/blob/master/packages/material-ui/src/ButtonBase/TouchRipple.js.
import React, { useEffect, useState } from "react";
import classnames from "classnames";
import PropTypes from "prop-types";
import { withStyles, makeStyles } from "#material-ui/core/styles";
import { sectionAnchors, maxContentWidth } from "../../../util/constants";
import LearnMoreLink from "./LearnMoreLink";
import SectionContent from "../../common/SectionContent";
import content from "../../../../content";
import useRealHeight from "../../../util/useRealHeight";
import SplashHeading from "./SplashHeading";
import { singleHeight, doubleHeight } from "../../common/Footer";
import GetStartedForm from "./GetStartedForm";
import { withRouter } from "next/router";
import SwipeableTextMobileStepper from "./SwipeableTextMobileStepper";
import { Link } from 'next/router'
import Radio from '#material-ui/core/Radio';
import RadioGroup from '#material-ui/core/RadioGroup';
import FormHelperText from '#material-ui/core/FormHelperText';
import FormControlLabel from '#material-ui/core/FormControlLabel';
import FormControl from '#material-ui/core/FormControl';
import FormLabel from '#material-ui/core/FormLabel';
import { green } from '#material-ui/core/colors';
import RadioButtonUncheckedIcon from '#material-ui/icons/RadioButtonUnchecked';
import RadioButtonCheckedIcon from '#material-ui/icons/RadioButtonChecked';
import Switch from '#material-ui/core/Switch';
import Button from '#material-ui/core/Button';
const styles = theme => ({
heading: {
marginBottom: theme.spacing.unit * 6
},
headingColored: {
marginBottom: 0,
color: theme.palette.primary.dark
},
container: {
width: "100%",
// '#keyframes fade': {
// '0%': {
// opacity: 1
// },
// '100%': {
// opacity: 0
// }
// },
'#keyframes enter': {
'0%': {
transform: 'scale(0)',
opacity: 0.1,
},
'100%': {
transform: 'scale(1)',
opacity: 0.3,
},
},
// backgroundColor: theme.palette.primary.dark,
// background: 'url(https://images.newscientist.com/wp-content/uploads/2019/04/08111018/screenshot-2019-04-08-10.24.34.jpg)',
backgroundImage: props => props.background,
backgroundSize: "cover",
// animation: '$fadeMe linear 1s infinite',
// animationName: '#fadeMe',
// animdationDuration: '1s',
// animation:
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center"
},
containerWizard: {
background: "none",
marginBottom: -doubleHeight,
paddingBottom: doubleHeight + theme.spacing.unit * 3,
[theme.breakpoints.up("sm")]: {
marginBottom: -singleHeight,
paddingBottom: singleHeight + theme.spacing.unit * 3
}
},
inner: {
maxWidth: maxContentWidth,
width: "100%",
flex: "1 0 auto",
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center"
},
flex: {
flex: "1 0 auto"
},
form: {
width: "100%",
maxWidth: maxContentWidth / 2,
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center"
}
});
// http://www.coverbash.com/wp-content/covers/caeli_flowers_facebook_cover.jpg
function SplashLogic() {
const [selectedValue, setSelectedValue] = React.useState(1);
let int
useEffect(() => { int = init(1) }, []);
let background = selectedValue == 1 ? bG('http://www.coverbash.com/wp-content/covers/caeli_flowers_facebook_cover.jpg') :
bG('https://images.newscientist.com/wp-content/uploads/2019/04/08111018/screenshot-2019-04-08-10.24.34.jpg?')
const handleChange = event => {
setSelectedValue(event.target.value);
clearInterval(int)
int = init(event.target.value)
};
function init(num) {
return setInterval(() => {
background = bG('http://www.coverbash.com/wp-content/covers/caeli_flowers_facebook_cover.jpg')
setSelectedValue(2)
}, 4000)
}
return <SplashFull {...{ setSelectedValue, selectedValue, background, handleChange }}></SplashFull>
}
const SplashSection = ({ classes, router, setSelectedValue, selectedValue, background, handleChange }) => {
// const [height] = useRealHeight({ resize: false });
console.log(classes.container)
useEffect(() => {
router.prefetch("/signup");
}, []);
const onSubmit = values => {
router.push(`/signup?destination=${values.destination}`, "/signup");
};
return (
<SectionContent id={sectionAnchors.SPLASH} className={classes.container}>
<div className="bg-white opacity-50 rounded-full">
<Radio
checked={selectedValue === 1}
onChange={handleChange}
value={1}
name="radio-button-demo"
inputProps={{ 'aria-label': 'A' }}
/>
<Radio
checked={selectedValue === 2}
onChange={handleChange}
value={2}
name="radio-button-demo"
inputProps={{ 'aria-label': 'B' }}
/>
<Radio
checked={selectedValue === 3}
onChange={handleChange}
value={3}
name="radio-button-demo"
inputProps={{ 'aria-label': 'D' }}
/>
<Radio
checked={selectedValue === 4}
onChange={handleChange}
value={4}
name="radio-button-demo"
inputProps={{ 'aria-label': 'E' }}
/>
</div>
<div className={classes.inner}>
<SplashHeading
classes={{
container: classes.heading
}}
/>
<GetStartedForm className={classes.form} onSubmit={onSubmit} />
</div>
<Button variant="contained" >
Default
</Button>
<LearnMoreLink />
</SectionContent>
// <SwipeableTextMobileStepper></SwipeableTextMobileStepper>
);
};
SplashSection.propTypes = {
classes: PropTypes.object.isRequired
};
function bG(arg) {
return `url(${arg})`
}
const SplashFull = withStyles(styles)(withRouter(SplashSection));
export default SplashLogic
I get error:
container.addRule(...).addRule is not a function
TypeError: container.addRule(...).addRule is not a function
at Array.onProcessStyle (/workspace/travelcontacts/node_modules/jss-plugin-nested/dist/jss-plugin-nested.cjs.js:96:10)
at PluginsRegistry.onProcessStyle (/workspace/travelcontacts/node_modules/jss/dist/jss.cjs.js:1246:51)
at PluginsRegistry.onProcessRule (/workspace/travelcontacts/node_modules/jss/dist/jss.cjs.js:1235:26)
at Array.forEach (<anonymous>)
at RuleList.process (/workspace/travelcontacts/node_modules/jss/dist/jss.cjs.js:871:25)
at new StyleSheet (/workspace/travelcontacts/node_modules/jss/dist/jss.cjs.js:1041:16)
at Jss.createStyleSheet (/workspace/travelcontacts/node_modules/jss/dist/jss.cjs.js:2007:17)
at attach (/workspace/travelcontacts/node_modules/#material-ui/styles/makeStyles/makeStyles.js:116:39)
at /workspace/travelcontacts/node_modules/#material-ui/styles/makeStyles/makeStyles.js:256:7
at useSynchronousEffect (/workspace/travelcontacts/node_modules/#material-ui/styles/makeStyles/makeStyles.js:210:14)
at /workspace/travelcontacts/node_modules/#material-ui/styles/makeStyles/makeStyles.js:248:5
at Object.WithStyles [as render] (/workspace/travelcontacts/node_modules/#material-ui/styles/withStyles/withStyles.js:70:21)
at ReactDOMServerRenderer.render (/workspace/travelcontacts/node_modules/react-dom/cjs/react-dom-server.node.development.js:3758:44)
at ReactDOMServerRenderer.read (/workspace/travelcontacts/node_modules/react-dom/cjs/react-dom-server.node.development.js:3538:29)
at renderToString (/workspace/travelcontacts/node_modules/react-dom/cjs/react-dom-server.node.development.js:4247:27)
at render (/workspace/travelcontacts/node_modules/next-server/dist/server/render.js:86:16)
The issue appears to be resolved by not nesting #keyframes definitions. The hint was in the second application of the addRule function in the error: container.addRule(...).addRule is not a function.
Solution
Try moving your keyframe animations to the root level. So from this
const styles = theme => ({
container: {
'#keyframes enter': {
'0%': {
transform: 'scale(0)',
opacity: 0.1,
},
'100%': {
transform: 'scale(1)',
opacity: 0.3,
},
}
}
}
to this
const styles = theme => ({
'#keyframes enter': {
'0%': {
transform: 'scale(0)',
opacity: 0.1,
},
'100%': {
transform: 'scale(1)',
opacity: 0.3,
},
}
}
Hope that helps.
Interesting side note: nesting the animation another level removes the error, but does not instantiate the CSS animation.
from
const styles = theme => ({
container: {
'#keyframes enter': {
'0%': {
transform: 'scale(0)',
opacity: 0.1,
},
'100%': {
transform: 'scale(1)',
opacity: 0.3,
},
}
}
}
to
const styles = theme => ({
'#global':{ //need add into global rules
'#keyframes enter': {
'0%': {
transform: 'scale(0)',
opacity: 0.1,
},
'100%': {
transform: 'scale(1)',
opacity: 0.3,
},
}
}
}

multilevel nested list in material-ui next

I'd like to create multilevel nested list to display the menu on the left side - - very similar as on oficial site: https://material-ui-next.com/.
data source is in JSON where for each item there's also information about parent item and some other data - - this is the example:
{
"task_number": 1201092,
"task": "Monthly Cash Flow from Deliveries",
"task_parent_number": 1201090,
"task_parent": "Wholesale Cash Flow"
},
{
"task_number": 1201095,
"task": "Monthly Cash Flow from Fix Amounts",
"task_parent_number": 1201090,
"task_parent": "Wholesale Cash Flow"
},
{
"task_number": 1201100,
"task": "Wholesale Positions",
"task_parent_number": 1200007,
"task_parent": "Wholesale Contract Portfolio"
},
{
"task_number": 1201200,
"task": "All Wholesale Positions",
"task_parent_number": 1201100,
"task_parent": "Wholesale Positions"
}
I'am able to create an object with various nested elements - children - if they exist with followin function:
function getNestedChildren(arr, parent) {
var out = [];
for (var i in arr) {
if (arr[i].task_parent_number == parent) {
//console.log(i, arr[i].task_parent_number, arr[i].task_number);
var children = getNestedChildren(arr, arr[i].task_number);
if (children.length) {
arr[i].children = children;
}
out.push(arr[i]);
}
}
return out;
}
I've been following instructions for creating a nested list and importing it here: https://material-ui-next.com/demos/lists/#nested-list
..but I am not able to create a menu with nested elements as desired . . if someone can point me in the right direction would be great..
OK, i got this to work combining these 2 parts:
React example recursive render: https://gist.github.com/nkvenom/bf7b1adfe982cb47dee3
Material List guide here - https://medium.com/#ali.atwa/getting-started-with-material-ui-for-react-59c82d9ffd93
There is mui component.
I add recursion to the last example.
import type { SvgIconProps } from '#mui/material/SvgIcon';
import * as React from 'react';
import { styled } from '#mui/material/styles';
import Box from '#mui/material/Box';
import TreeView, { TreeViewProps } from '#mui/lab/TreeView';
import TreeItem, { TreeItemProps, treeItemClasses } from '#mui/lab/TreeItem';
import Typography from '#mui/material/Typography';
// import DeleteIcon from '#mui/icons-material/Delete';
// import Label from '#mui/icons-material/Label';
// import SupervisorAccountIcon from '#mui/icons-material/SupervisorAccount';
// import InfoIcon from '#mui/icons-material/Info';
// import ForumIcon from '#mui/icons-material/Forum';
// import LocalOfferIcon from '#mui/icons-material/LocalOffer';
import ArrowDropDownIcon from '#mui/icons-material/ArrowDropDown';
import ArrowRightIcon from '#mui/icons-material/ArrowRight';
declare module 'react' {
interface CSSProperties {
'--tree-view-color'?: string;
'--tree-view-bg-color'?: string;
}
}
type StyledTreeItemProps = TreeItemProps & {
bgColor?: string;
color?: string;
labelIcon?: React.ElementType<SvgIconProps>;
labelInfo?: React.ReactNode;
labelText: string;
};
type RecursiveStyledTreeItemProps = StyledTreeItemProps & {
childrenProps?: RecursiveStyledTreeItemProps[]
}
const StyledTreeItemRoot = styled(TreeItem)(({ theme }) => ({
color: theme.palette.text.secondary,
[`& .${treeItemClasses.content}`]: {
color: theme.palette.text.secondary,
borderTopRightRadius: theme.spacing(2),
borderBottomRightRadius: theme.spacing(2),
paddingRight: theme.spacing(1),
fontWeight: theme.typography.fontWeightMedium,
'&.Mui-expanded': {
fontWeight: theme.typography.fontWeightRegular,
},
'&:hover': {
backgroundColor: theme.palette.action.hover,
},
'&.Mui-focused, &.Mui-selected, &.Mui-selected.Mui-focused': {
backgroundColor: `var(--tree-view-bg-color, ${theme.palette.action.selected})`,
color: 'var(--tree-view-color)',
},
[`& .${treeItemClasses.label}`]: {
fontWeight: 'inherit',
color: 'inherit',
},
},
[`& .${treeItemClasses.group}`]: {
marginLeft: 0,
[`& .${treeItemClasses.content}`]: {
paddingLeft: theme.spacing(2),
},
},
}));
const RecursiveStyledTreeItem = ({ childrenProps, ...p }: RecursiveStyledTreeItemProps) => childrenProps
? <RecursiveStyledTreeItem {...p}>
{
childrenProps.map(cP => <RecursiveStyledTreeItem
key={cP.nodeId}
{...cP}
/>)
}
</RecursiveStyledTreeItem>
: < StyledTreeItem {...p} />
function StyledTreeItem(props: StyledTreeItemProps) {
const {
bgColor,
color,
labelIcon: LabelIcon = null,
labelInfo = null,
labelText,
...other
} = props;
return (
<StyledTreeItemRoot
label={
<Box sx={{ display: 'flex', alignItems: 'center', p: 0.5, pr: 0 }}>
{
LabelIcon && <Box component={LabelIcon} color="inherit" sx={{ mr: 1 }} />
}
<Typography variant="body2" sx={{ fontWeight: 'inherit', flexGrow: 1 }}>
{labelText}
</Typography>
{
labelInfo && <Typography variant="caption" color="inherit">
{labelInfo}
</Typography>
}
</Box>
}
style={{
'--tree-view-color': color,
'--tree-view-bg-color': bgColor,
}}
{...other}
/>
);
}
export default function CustomTreeView({ treeViewProps, items }: {
treeViewProps: Partial<TreeViewProps>
items: RecursiveStyledTreeItemProps[]
}) {
return (
<TreeView
// defaultExpanded={['3']}
defaultCollapseIcon={<ArrowDropDownIcon />}
defaultExpandIcon={<ArrowRightIcon />}
defaultEndIcon={<div style={{ width: 24 }} />}
sx={{ height: 264, flexGrow: 1, maxWidth: 400, overflowY: 'auto' }}
{...treeViewProps}
>
{items.map(item => <RecursiveStyledTreeItem
key={item.nodeId}
{...item}
/>)}
</TreeView>
);
}
There is mui-tree-select

Resources