Theme override support for custom components - reactjs

After the migration to mui v5 for react-admin, we realized that supporting theme overrides for our custom components seems to require more code than we expected. As it looks that this could be handled by the styled API, I would like to know if this is really required.
Here's an example of our Navigation link:
const PREFIX = 'RaMenuItemLink';
export const MenuItemLinkClasses = {
root: `${PREFIX}-root`,
active: `${PREFIX}-active`,
icon: `${PREFIX}-icon`,
};
const StyledMenuItem = styled(MenuItem, {
name: PREFIX,
// Why do I have to do this?
overridesResolver: (props, styles) => [
{ [`&.${MenuItemLinkClasses.active}`]: styles.active },
{ [`& .${MenuItemLinkClasses.icon}`]: styles.icon },
styles.root,
],
})(({ theme }) => ({
[`&.${MenuItemLinkClasses.root}`]: {
color: theme.palette.text.secondary,
},
[`&.${MenuItemLinkClasses.active}`]: {
color: theme.palette.text.primary,
},
[`& .${MenuItemLinkClasses.icon}`]: { minWidth: theme.spacing(5) },
}));

In your case, I think that I would start to simplify the code to:
const PREFIX = 'RaMenuItemLink';
export const MenuItemLinkClasses = {
root: `${PREFIX}-root`,
active: `Mui-active`,
icon: `${PREFIX}-icon`,
};
const StyledMenuItem = styled(MenuItem, {
name: PREFIX,
overridesResolver: (props, styles) => [
styles.root,
{ [`&.${MenuItemLinkClasses.active}`]: styles.active },
{ [`& .${MenuItemLinkClasses.icon}`]: styles.icon },
],
})(({ theme }) => ({
color: theme.palette.text.secondary,
[`&.${MenuItemLinkClasses.active}`]: {
color: theme.palette.text.primary,
},
[`& .${MenuItemLinkClasses.icon}`]: { minWidth: theme.spacing(5) },
}));
The overridesResolver property is meant to resolve this object:
const theme = {
components: {
[PREFIX]: {
styleOverrides: /* this object, it's the 'styles' arg of overridesResolver */,
},
},
};

Related

Is there a way to specify defaultProps for a variant?

I created variant for MuiButton like so...
const theme = createTheme({
components: {
MuiButton: {
variants: [{
props: {
variant: 'myVariantX'
},
style: {
backgroundColor: 'blue'
}
}]
}
},
});
...I know I can do this...
const theme = createTheme({
components: {
// Name of the component
MuiButton: {
defaultProps: {
// The props to change the default for.
disableRipple: true, // No more ripple, on the whole application 💣!
},
},
},
});
... but is there a way I could specify defaultProps for my 'myVariantX' variant? Dont want to target all MuiButtons. Something like...
const theme = createTheme({
components: {
MuiButton: {
variants: [{
props: {
variant: 'myVariantX',
defaultProps: {
disableRipple: true
}
},
style: {
backgroundColor: 'blue'
}
}]
}
},
});

react-tsparticles change color on click of component i made for dark mode

i Want to change theme of the react-tsparticle
function Particle() {
const particlesInit = (main) => {};
const particlesLoaded = (container) => {
<DarkMode />;
container.loadTheme("dark"); //dark mode
};
////////////////////////
themes: [
{
name: "light",
default: {
value: true,
mode: "light",
},
options: {
background: {
color: "transparent",
},
particles: {
color: {
value: "#20f0",
},
},
},
},
{
name: "dark",
default: {
value: true,
mode: "dark",
},
options: {
background: {
color: "transparent",
},
particles: {
color: {
value: "#2fff",
},
},
},
},
in container.loadtheme("dark/light)"
can be set so i want to set a onclick on the dark mode button so that dark and light can be set by on click on this container
<DarkMode />; //want onclick on this This is the button which i imported and i want this button to change the particle theme
const DarkMode = () => {
return (
<div className="toggle-theme-wrapper">
<span>☀️</span>
<label className="toggle-theme" htmlFor="checkbox">
<input
type="checkbox"
id="checkbox"
onChange={toggleTheme}
const toggleTheme: ChangeEventHandler<HTMLInputElement> = (e) => {
if (e.target.checked) {
setDark();
} else {
setLight();
}
};
You can find how to get the container on GitHub here
import Particles from "react-tsparticles";
const App = () => {
const particlesInit = (main) => {
console.log(main);
// you can initialize the tsParticles instance (main) here, adding custom shapes or presets
};
const particlesLoaded = (container) => {
console.log(container);
};
return (
<Particles id="tsparticles" url="http://foo.bar/particles.json" init={particlesInit} loaded={particlesLoaded} />
);
};
In the particlesLoaded function you can store the container in a local variable (or state) and use that to call the loadTheme function

Customize multiple mui components

From MUI's docs you have the ability to customize a component. But is there a way to customize multiple components?
Say I want to customize MuiPaper and MuiList with the same styles.
E.g of customizable components:
const theme = createTheme({
components: {
// Name of the component
MuiPaper: {
defaultProps: {
// The props to change the default for.
backgroundColor: '#101010',
},
},
},
});
there are multiple ways to customize the default props. please check below I have added three ways to customize the components. also you can add more components to it.
theme.js
const mytheme = {
components: {
MuiPaper: {
styleOverrides: {
root: ({ theme }) => ({ // using with theme
backgroundColor: theme.palette.primary.main,
color: theme.palette.primary.contrastText,
}),
},
},
MuiList : {
styleOverrides: {
root: { // adding direct CSS properties with screensize condition.
'#media (min-width:600px)': {
minHeight: '4.5rem',
backgroundColor: '#101010',
},
},
},
},
MuiButton: {
styleOverrides: {
root: ({ ownerState, theme }) => ({ // changing only 'contained' variant or adding new variant.
textTransform: 'capitalize',
...(ownerState.variant === 'contained' && {
color: theme.palette.primary.contrastText,
backgroundColor: theme.palette.primary.light,
}),
}),
},
},
},
};
export default mytheme;
app.js
const App = () => {
<ThemeProvider theme={createTheme(mytheme)}>
...
</ThemeProvider>
}
export default App;

react-select change singleValue color based on options

I would like to modify the 'selected' singleValue color in my styles object based on the options that are provided.
const statusOptions = [
{ value: "NEW", label: i18n._(t`NEW`) },
{ value: "DNC", label: i18n._(t`DNC`) },
{ value: "WON", label: i18n._(t`WON`) },
{ value: "LOST", label: i18n._(t`LOST`) },
];
For example, if the option selected in "NEW", I want the font color to be red, if it's "WON", then green, and so on. I am having trouble putting an if statement into the styles object. I see that its simple to put a ternary statement in, but how to you add more "complex" logic?
const customStyles = {
...
singleValue: (provided) => ({
...provided,
color: 'red' <----- something like if('NEW') { color: 'green' } etc..
})
};
Use an style map object:
import React from 'react';
import Select from 'react-select';
const statusOptions = [
{ value: 'NEW', label: 'NEW' },
{ value: 'DNC', label: 'DNC' },
{ value: 'WON', label: 'WON' },
{ value: 'LOST', label: 'LOST' },
];
const styleMap = {
NEW: 'red',
DNC: 'blue',
};
const colourStyles = {
singleValue: (provided, { data }) => ({
...provided,
color: styleMap[data.value] ? styleMap[data.value] : 'defaultColor',
// specify a fallback color here for those values not accounted for in the styleMap
}),
};
export default function SelectColorThing() {
return (
<Select
options={statusOptions}
styles={colourStyles}
/>
);
}

How to style Plotly depending on site's color scheme

I am working on a website using Material-UI React framework and we are making use of its theming capabilities to let the user dynamically change the appearance. Is there a way to easily set default colors for the text Plotly renders, so it contrasts nicely with the site's background?
I am doing this for the moment:
import React from 'react';
import PlotlyPlot from 'react-plotly.js';
import { useTheme } from '#material-ui/core';
import { merge } from '../lodash.custom';
const Plot = React.forwardRef((props, ref) => {
const theme = useTheme();
const layout = merge({
paper_bgcolor: theme.palette.background.paper,
plot_bgcolor: theme.palette.background.paper,
xaxis: {
color: theme.palette.text.primary
},
yaxis: {
color: theme.palette.text.primary
},
legend: {
font: {
color: theme.palette.text.primary
},
},
title: {
font: {
color: theme.palette.text.primary,
}
},
scene: {
xaxis: {
color: theme.palette.text.primary
},
yaxis: {
color: theme.palette.text.primary
},
zaxis: {
color: theme.palette.text.primary
},
}
}, props.layout);
const data = props.data.map(plotData => merge({
colorbar: {
tickfont: {
color: theme.palette.text.primary
}
}
}, plotData));
const customProps = {
layout,
data
};
return <PlotlyPlot ref={ref} {...customProps} />;
});

Resources