spread common style in makeStyles (Typescript) - material-ui

I need to spread common style across multiple styling inside makeStyles. This works for my jsx, but give errors when i move to tsx.
const abc = {
fontWeight: 600,
textTransform: 'uppercase',
}
const useStyles = makeStyles(() => ({
abcAdd: {
...abc,
color: '#B25846';
},
}))

If the object is declared in TypeScript, set its type to CSSProperties
import { CSSProperties } from "#material-ui/core/styles/withStyles";
const abc: CSSProperties = {
fontWeight: 600,
textTransform: 'uppercase',
}
Or, if the object came from JavaScript, cast it to CSSProperties
import { CSSProperties } from "#material-ui/core/styles/withStyles";
import { abc } from "./some/path/to/javascript";
const useStyles = makeStyles(() => ({
abcAdd: {
...abc as CSSProperties,
color: '#B25846',
},
}))

I found a simple workaround - add 'any' as type of callback function
const abc = {
fontWeight: 600,
textTransform: 'uppercase',
}
const useStyles = makeStyles((): any => ({
abcAdd: {
...abc,
color: '#B25846';
},
}))
And when you use the class, call it in quotes:
const classes = useStyles()
return (
<Box className={classes['abcAdd']}>
)
This way works for me and there are no errors from TS compiler.
I am sure, there could be a better solution, maybe you need to define some advanced type for callback. But it requires advanced knowledge of typescript, I'm not so experienced in it.
Any better solutions - welcome!

What about if you use #ts-ignore on that line?

There is no need to spread JSON inside makeStyles. There could be only one reason why you may want to spread it because you want to keep comment CSS in one file.
Simply make one comment file for common css:
import {
makeStyles,
} from '#material-ui/core';
const useCommonStyles = makeStyles(() => ({
abcAdd:{ fontWeight: 600,
textTransform: 'uppercase',}
}));
export default useCommonStyles;
And use it like this anywhere
import useCommonStyles from "src/utils/commonStyles";
const commonClasses = useCommonStyles();

Related

Change color of selected row on Material UI table

How to change/customize the default color of selected rows in a Material-UI table (of type Sorting & Selecting)? By default it is secondary (red) color (Codesandbox here: https://codesandbox.io/s/3sjxh). How to change it to a custom color, or at least to primary (blue), as it appears in the new beta version (https://next.material-ui.com/components/tables/#main-content) (v5).
You have to pass your styles to the classes props in order to change the styles for the TableRow.
To achieve the background-color change you want to override the default classes: .MuiTableRow-root.Mui-selected and .MuiTableRow-root.Mui-selected:hover.
To override them you have to use a parent reference with a so called $ruleName in your makeStyles hook. Here is a very good explanation from #Ryan Cogswell if you are more interested how it works.
This would then look like this:
const useStyles = makeStyles((theme) => ({
// your other styles
...,
tableRowRoot: {
"&$tableRowSelected, &$tableRowSelected:hover": {
backgroundColor: theme.palette.primary.main
}
},
tableRowSelected: {
backgroundColor: theme.palette.primary.main
}
}));
...
<TableRow
// your other props
...
classes={{
root: classes.tableRowRoot,
selected: classes. tableRowSelected,
}}
>
...
</TableRow>;
For the checkboxes, you only have to add the color prop in order to change it:
<Checkbox
// other props
...
color="primary"
/>
and for your Toolbar, you only need to change the provided highlight class inside your useToolbarStyles in order to get things working:
import { alpha } from "#material-ui/core/styles";
...
const useToolbarStyles = makeStyles((theme) => ({
...,
highlight:
theme.palette.type === "light"
? {
color: theme.palette.primary.main,
backgroundColor: alpha(
theme.palette.primary.light,
theme.palette.action.selectedOpacity
)
}
: {
color: theme.palette.text.primary,
backgroundColor: theme.palette.primary.dark
},
}));
Live demo:

Referencing another Rule in Material UI

I have the following code where I need to reference another rule name to avoid style duplication in material ui. Unfortunately the rules aren't reflecting.
const useNavStyles = makeStyles((theme) => ({
active: {
color: 'green'
},
listItem: {
borderTopRightRadius: 100,
borderBottomRightRadius: 100,
paddingBottom: 12,
paddingTop: 12,
backgroundColor: theme.palette.background.paper,
},
subListItem: {
"&$listItem": { // I wish to copy over the properties from the above listItem rule and only add padding to it, but it isn't working.
paddingLeft: theme.spacing(4),
},
},
How do I resolve this?
Thanks
Referencing a local rule name does not "copy over" other styles. It changes your selector. You will still need to apply all those classes to your elements, which in return will then also apply the respective styles.
listItem: {
color: 'hotpink',
},
subListItem: {
"&$listItem": {
fontWeight: 'bold'
}
}
this compiles to
.listItem-1: {
color: hotpink;
}
.subListItem-0.listItem-1: {
font-weight: bold;
}
In other words, this will apply styles to an element that has both these classes:
<div className={clsx(classes.listItem, classes.subListItem)}>
hotpink and bold
</div>
<div className={classes.subListItem}>no styles at all</div>

the function ToHaveStyleRule doesn't work with hover

I created a component to be an Icons wrapper, so I don't need to keep editing the icon in the style of the file I use... However, when testing a property that can be applied to the "hover" component , the test says that this property does not exist, even passing!
file index
export type IconsProps = {
hoverColor?: colorTypes
}
const Icons = ({ hoverColor }: IconsProps) => (
<S.Wrapper color={color} size={size} hoverColor={hoverColor}>
{children}
</S.Wrapper>
)
file style
const wrapperModifiers = {
hoverColor: (theme: DefaultTheme, hoverColor: colorTypes) => css`
& :hover {
color: ${theme.colors[hoverColor]};
}
`,
}
export const Wrapper = styled.main<IconsProps>`
${({ theme, hoverColor }) => css`
> ${StyledIconBase} {
${!!hoverColor && wrapperModifiers.hoverColor(theme, hoverColor)}
}
`}
`
test
import { Coffee } from '#styled-icons/boxicons-solid'
it('deve testar o hover e o transform', () => {
const { debug, container } = renderWithTheme(
<Icons color="primary" size="5rem" hoverColor="secondary">
<Coffee title="Coffee" />
</Icons>,
)
expect(screen.getByRole('img', { name: /coffee/i })).toHaveStyleRule(
'color',
'#0487cc',
{
modifier: ':hover',
},
)
})
error
No style rules found on passed Component using options:
{"modifier":":hover"}
In my opinion, the error that you are getting is that you haven't properly selected the element which is having a hover color. Because of that reason, jest-styled-component is not able to find the element with a hover modifier.
& :hover {
color: ${theme.colors[hoverColor]};
}
You added a space between & and : which is not right. The hover will not be applied to the selected element.
Solution: Remove the space between them.
&:hover {
color: ${theme.colors[hoverColor]};
}

Material-UI Typography with different variants

How can I make that the typography component of Material-UI infers the variant from the text inside it?
I have the following code:
import React from 'react';
import './styles.css';
import {createMuiTheme} from '#material-ui/core/styles';
import {ThemeProvider} from '#material-ui/styles';
import Typography from '#material-ui/core/Typography';
const theme = createMuiTheme({
typography: {
h1: {
fontSize: 200,
},
h2: {
fontSize: 5,
},
},
});
export default function App() {
return (
<ThemeProvider theme={theme}>
<Typography>
<h1>Text H1</h1>
<h2>Text H2</h2>
</Typography>
</ThemeProvider>
);
}
When it renders, "Text H1" should have a font size of 200 and "Text H2" a font size of 5.
Unfortunately, it's not like that.
Only if I change the variant prop of Typography to h1 or h2, it changes the font size. As I have a long text with different variants, I don't want to create a Typography element for each of them.
Here is a code sandbox of it:
https://codesandbox.io/s/elegant-bouman-fz3j6?file=/src/App.js:0-604
If you want to override the h1/h2 of you should use the overrides option of the createMuiTheme function:
export const theme = createMuiTheme({
overrides: {
MuiTypography: {
root: {
"& h1": {
color: "blue"
},
"& h2": {
color: "red"
}
}
}
}
});
You can see a working example here: https://codesandbox.io/s/mui-theme-typography-override-styles-192jk?file=/demo.js

How to use theme overrides with nested elements?

If I adjust the size of a button in the theme, like this:
const theme = createMuiTheme({
overrides: {
MuiButton: {
fab: {
width: 36,
height: 36,
},
},
MuiSvgIcon: {
root: {
width: 16,
},
},
},
};
Then the button and the icon appear at the size I want. However this affects all icons, whether they're inside a button or not!
How can I say that I only want the MuiSvgIcon properties to apply when the element is found inside a MuiButton element?
Well I've worked out one way to do it, but it's not ideal because it relies on the internal structure of the MuiSvgIcon. But it might serve as a starting point for someone else. Better answers are most welcome.
const theme = createMuiTheme({
overrides: {
MuiButton: {
fab: {
width: 36,
height: 36,
'& svg': {
width: 16,
},
},
},
},
};
It works by applying a style to the <svg> DOM element inside the JSX <Button variant="fab"> element.
It's not documented anywhere unfortunately, but you can use any sort of CSS selectors to help. Use the "attribute contains" pattern with the class attribute itself to target descendants:
const theme = createMuiTheme({
overrides: {
MuiButton: {
root: {
// Targets MuiSvgIcon elements that appear as descendants of MuiButton
'& [class*="MuiSvgIcon-root"]': {
width: 16
}
},
},
},
};
Note 1: Caution! Material UI minifies these classnames in prod builds by default. If you want to preserve these classnames for prod, you will need to tweak the class generator function: https://material-ui.com/customization/css-in-js/ (see dangerouslyUseGlobalCSS)
Note 2: with this pattern, occasionally you end having to use !important if there's already a competing inline style that you want to override. If you're using styled-components, you can increase the specificity by using && (see the Material UI docs).

Categories