How to load Material UI Theme based on Redux Store entry - reactjs

I have the below file as the first file that loads when my application loads. I want to pull the palette type from my Redux store like this.props.pageTheme so when I trigger a change to the theme, it takes place in the whole app. though when I enter type: this.props.pageTheme I get an error saying TypeError: Cannot read property 'props' of undefined.. Which would make sense because store is not generated by the time const kicks in. But .. Then, how can I read what's in the store and change on the page? I've seen solutions like creating multiple theme const and applying that based on this.props.getTheme within return of the app but that's so ugly way of doing it. Is there any smart way to handle theme value injection into the createMuiTheme?
import React, { Component } from "react";
import { MuiThemeProvider, createMuiTheme } from "#material-ui/core/styles";
const theme = createMuiTheme({
palette: {
type: "light",
}
});
class App extends Component {
render() {
return (
<MuiThemeProvider theme={theme}>
<>page content</>
</MuiThemeProvider>
);
}
}
}
function mapStateToProps(state) {
return {
pageTheme: state.Page.Theme
};
}
export default connect(
mapStateToProps
)(App);

So I am sure there will be people looking for an answer for this issue since it's sleek to offer users an ability to change the color mode of your app. My solution is below, if I come across any, I will update it.
In Redux Store I have:
const initialState = {
Page: {
Theme: "light"
},
};
In main App.js file I have
<MuiThemeProvider theme={theme(this.props.pageTheme)}>
as a wrapper around the content that I have on the page.
and I have the below function for theme
function theme(mode) {
return createMuiTheme({
palette: {
type: mode,
primary: {
light: "#757ce8",
main: "#3f50b5",
dark: "#002884",
contrastText: "#fff"
},
secondary: {
light: "#ff7961",
main: "#f44336",
dark: "#ba000d",
contrastText: "#000"
}
}
});
}
If you have any suggestions over this to get it better, still highly appreciated.

Related

React MUI - custom colors in Alert component - Cannot read properties of undefined (reading 'type')

I'm trying to theme and customize MUI components to align them with our company design, but I stumbled across a problem.
I have defined my custom colors, for some reason we have color "danger" instead of "error".
I was following the documentation https://mui.com/material-ui/customization/palette/#adding-new-colors and everything works great for Button component.
But when I moved on to the Alert component, the same approach doesn't work, and I just simply don't know why. All I'm getting is Uncaught TypeError: Cannot read properties of undefined (reading 'type')
I also tried it to add it to the stackblitz example from the docs page mentioned above but got the same result: https://stackblitz.com/edit/react-z3xjhf?file=demo.tsx
import * as React from 'react';
import { createTheme, ThemeProvider } from '#mui/material/styles';
import Button from '#mui/material/Button';
import Alert from '#mui/material/Alert';
const theme = createTheme({
palette: {
neutral: {
main: '#64748B',
contrastText: '#fff',
},
},
});
declare module '#mui/material/styles' {
interface Palette {
neutral: Palette['primary'];
}
// allow configuration using `createTheme`
interface PaletteOptions {
neutral?: PaletteOptions['primary'];
}
}
// Update the Button's color prop options
declare module '#mui/material/Button' {
interface ButtonPropsColorOverrides {
neutral: true;
}
}
declare module '#mui/material/Alert' {
interface AlertPropsColorOverrides {
neutral: true;
}
}
export default function CustomColor() {
return (
<ThemeProvider theme={theme}>
<Button color="neutral" variant="contained">
neutral
</Button>
<Alert color="neutral">ALERT</Alert>
</ThemeProvider>
);
}
Does anybody have any idea what I'm doing wrong?
You need to add light: '<whatever_your_light_color_hex>' to your theme, too. Like this:
const theme = createTheme({
palette: {
neutral: {
main: '#64748B',
light: '#64748B',
contrastText: '#fff',
},
},
});
This stackblitz is a live working example of this solution.

How can i get the context of the MUI theme?

This is how you create a theme and propagate it using MUI.
import { ThemeProvider } from "#mui/material";
const myTheme = createTheme({
backgroundColor: {
primary: "#f9f9fb",
secondary: "#ededf3",
tertiary: "#cbcbdc",
},
})
const Index: FC = () => {
<ThemeProvider theme={theme}>
<App />
</ThemeProvider>
};
Now, for some reason, I need to get the context of the MUI theme in my app.
I've search everywhere but it seems that they do not expose the context anywhere. I found 3 contexts in private-theming, styled-engine and styled-engine-sc but none of them worked.
How can I do that ?
The way you create the theme it wrong should be like following:
const theme = createTheme({
palette: {
primary: {
main: red[500],
},
},
});
with the property palette.
and the way to get values you could use the hook useTheme .
first import
import { useTheme } from "#mui/material";
and inside your components you can use the palette you set to your theme like:
const { palette } = useTheme();
MUI uses the context provided by the styled engine:
import { ThemeContext } from '#mui/styled-engine';
It can also be imported directly from your engine of choice (emotion in the example below):
import { ThemeContext } from '#emotion/react';

react material-ui v5 theming doesnt work with storybook

I spend a few days trying to customize the primary color and add two more colors to the palette. I was able to declare properly the new colors...but at the moment to see those new colors reflected on the button doesnt work. The button are taking the default properties even when I wrapped under the Themeprovider. I'm using storybook.
import React from "react";
import { Meta } from "#storybook/react/types-6-0";
import { Button } from "#mui/material";
import { createTheme, ThemeProvider, styled } from '#mui/material/styles';
const theme = createTheme({
palette: {
primary: {
contrastText: "#ff0000",
light: "#ff0000",
main: "#ff0000",
dark: "#ff0000"
},
tertiary: {
main: "#ff0000"
},
failure: {
main: "#ff0000"
}
}
});
const CustomStyles = () => {
return (
<ThemeProvider theme={theme}>
<Button variant="contained">Click me</Button>
</ThemeProvider>
);
}
const Template = () => {
return (
<CustomStyles />
);
};
export const Default = Template.bind({});
export default {
title: "mylib/Theme"
} as Meta;
This is how it looks
default button style
Themeprovider custom palette
As you may see, the ThemeProvider has the palette color definition...but some how the button doesnt take it.
Thanks in advance
Adding this to.storybook/preview.js was enough to solve my case. Follow the official migration guide on this matter to learn more.
//.storybook/preview.js
import { ThemeProvider } from '#mui/material/styles';
import { ThemeProvider as Emotion10ThemeProvider } from 'emotion-theming';
import { theme } from '../your/system/customTheme/path';
const defaultTheme = theme;
const withThemeProvider = (Story, context) => {
return (
<Emotion10ThemeProvider theme={defaultTheme}>
<ThemeProvider theme={defaultTheme}>
<Story {...context} />
</ThemeProvider>
</Emotion10ThemeProvider>
);
};
export const decorators = [withThemeProvider];
//another storybook exports.
EDIT: this issue seems to be related to stackoverflow.com/a/70254078/17724218 as OP commented below.

Extending the default Material UI theme

I would like to create my own theme using createTheme() but I want to start with the default material UI theme and just change a few properties in it.
If I call it like so:
const theme = createTheme({
palette: {
primary: {
main: purple[500],
},
secondary: {
main: green[500],
},
},
});
then I am still missing some properties that are needed for several components, theme.palette.action.focus for instance.
Is there a way to extend the default theme?
You can extend the default theme by styleOverrides for #mui/material components.
Here is how to use it in the currently latest version.
import { createTheme } from "#mui/material/styles";
let theme = createTheme();
theme = createTheme(theme, {
paleete: {
...theme.palette,
action: {
focus: "#e6e6e6",
// other variants
}
},
components: {
MuiTableBody: {
styleOverrides: {
root: {
// overrides here
}
}
}
}
});
export default theme;
Take a look at the demo

Material-UI-next Theme not being applied to circular progress

I have updated my theme according to the docs but the circular progress continues to use the default primary color, not the one specified in the theme. Ultimately I'd like to be able to make the theme adjustable via the end user, using mobx computed values to adjust the theme, but currently I can't even get it to work with a static theme.
import {MuiThemeProvider} from "material-ui/styles"
import Loading from "../common/components/Loading";
import {createMuiTheme} from "material-ui";
const testingTheme = createMuiTheme({
primary: {
main: '#67e2ff',
light: '#a0ffff',
dark: '#1eb0cc',
contrastText: '#3b3f42'
},
secondary: {
main: '#590ce8',
light: '#9549ff',
dark: '#0000b4',
contrastText: '#fefefe'
}});
/**
* The AppContainer handles all of the logical functionality that has to happen at the root level.
* A prime example is the MuiThemeProvider, that must be the parent of all other rendered components.
* To change the muiTheme we use the AppContainer to render the MuiThemeProvider
*/
#inject("uiStore") #observer
export default class AppContainer extends Component {
componentDidMount() {
console.log(this.props.uiStore);
}
render() {
return (
<MuiThemeProvider theme={testingTheme}>
{this.props.uiStore.initialized ? <App/> : <Loading size={10}/>}
</MuiThemeProvider>
)
}
}
My definition for the theme was wrong, I was missing the root palette property.
const testingTheme = createMuiTheme({
palette: {
primary: {
main: '#67e2ff',
light: '#a0ffff',
dark: '#1eb0cc',
contrastText: '#3b3f42'
},
secondary: {
main: '#590ce8',
light: '#9549ff',
dark: '#0000b4',
contrastText: '#fefefe'
}
}
});

Resources