How to extend material-ui component style to another react component from differently library? - material-ui

For example:
import { CssBaseline, ThemeProvider, Typography } from "#material-ui/core"; // MUI **Typography** component
import { Text, RichText } from "#some-library/core"; // some-library's **Text** component
const theme = createMuiTheme({
overrides: {
typography: {
h1: {
fontFamily: Garamond,
fontSize: pxToRem(56),
lineHeight: pxToRem(64),
letterSpacing: pxToRem(-0.5),
[breakpoints.up("sm")]: {
fontSize: pxToRem(72),
lineHeight: pxToRem(76)
},
[breakpoints.up("md")]: {
fontSize: pxToRem(104),
lineHeight: pxToRem(112)
},
[breakpoints.up("lg")]: {
fontSize: pxToRem(120),
lineHeight: pxToRem(128),
letterSpacing: pxToRem(-0.75)
}
}
}
}
});
function App() {
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<Typography variant="h1">MUI Typography Heading</Typography>
<Text tag="h1">Library B text component</Text>
</ThemeProvider>
);
}
All I want is to apply the same styles of the <Typography> for the <Text> component.
I know can I can add className to the other component like <Text className={"MuiTypography-root MuiTypography-h1"} tag="h1">. Is that the right approach? And if I do like this would the props of components also be used in the component? Like <Text variant="h2"> and would it take all the responsiveness of Typography too?
Can the styles of MUI component be extended to another react component with all the other functionality (props etc) using any other way?
I am trying to create a shared (MUI components + some-library components) component library and using MUI as the base library for components and styles. And I have created custom theme for the MUI components but not able to extend these styles to the components of another library which too has few basic components (text field, buttons, form elements etc).
Please let know if the question makes sense as I am very new to react and MUI. Thanks much.

Ciao, for what I know, the answer should be no: you cannot extend material-ui component style to another component from different library. Because a component from another library would not accepts the same Material UI props (in your example, variant="h1" would be not recognized as valid props in other component except Material UI components).
Of course, as you said, you could assign the same Material UI class to another component and that component will follow the same style:
<Text className={"MuiTypography-root MuiTypography-h1"} tag="h1"> // this work
Or you could extend a Material UI component. Suppose that you want to make your own Text, you could extend Typography component using withStyles like:
import { withStyles } from "#material-ui/core/styles";
const MyText = withStyles((theme) => ({
root: {
color: "green" // in this case, MyText will have a green text color
}
}))((props) => <Typography {...props} />);
But, as you can see, I extended a Typography component, not a component coming from another library. Here a codesandbox example.
As I said, this is what I know. Maybe there is a way to achieve what you asked (even if I have some doubts because how to map Material UI props to be accepted by another component that has different props?)

Related

Material UI Customized styled element with theme

I'm starting to use Material UI in my project.
I have created a theme with some basic definitions, using my css variables:
import { createTheme } from '#mui/material/styles';
import theme from './_my-variables.scss';
const muiTheme = createTheme({
palette: {
primary: {
main: theme['color-blue'], // 'color-blue' is my css variable
},
},
typography: {
fontFamily: theme['brand-font'], // 'brand-font' is my css variable
},
}
I also used ThemeProvider in my App layout:
export const App = (props) => {
return (<Provider store={store}>
<ThemeProvider theme={muiTheme}>
<ConnectedRouter history={historyRef.history}>
<Layout {...props} />
</ConnectedRouter>
</ThemeProvider>
</Provider>);
};
I have a page with MUI elements, and it works fine and takes the new primary color and the new font.
<Box>
<Paper>
<Checkbox color="primary" /> <!-- I can see my new color in the page! Yay! -->
some text
</Paper>
</Box>
Now I want to create a custom element - like <MyCustomizeBox> that will have a different properties, using my css variables (for example - a specific width, defined in my variables).
How do I define them in my theme and how to use it to customize a new element?
I prefer not to user classes () because I want to create a generic elements for reusing. Also I don't want to change all Boxes in my app - only the customized ones.
I tries to use "withStyles" but I was getting the default theme instead of my customized theme and I saw on Google that I'm not support to use both "withStyles" and theme together.
At last, found the answer:
import { styled } from '#mui/system';
const MyCustomizedPaper = styled(Paper)(({ theme }) => ({
width: theme.custom.myCustomWidthCssVar
}));
<MyCustomizedPaper ></MyCustomizedPaper >

Is there a way to "inject" pure CSS into MUI v5

I have a custom spinner that is currently using keyframes like so:
import { keyframes } from "#mui/system";
...
const keyframeSpinner = keyframes`
0%{transform:rotate(0deg);}
100%{transform:rotate(360deg);}
`;
...
<Box
sx={{
animation: `${keyframeSpinner} 1s linear infinite`,
}}
/>
...
I don't want to import #mui/system and I don't want to use styled components.
So, I'm trying to find a solution where I can uses pure css or another solution that I'm unaware of.
You can easily apply in-line CSS styles to components using emotion, which is also used by MUI.
For example, here is the css prop from emotion being used to customize background-color and hover on a div. The code you write in the css prop can be pure CSS.
import { css, jsx } from '#emotion/react'
const color = 'darkgreen'
const customCss = css`
background-color: hotpink
&:hover { color: ${color} }
`
render(
<div css = {customCss}>
This div has a hotpink background.
</div>
)

Can't figure out how to style material ui datagrid

I'm trying to style material-ui DataGrid component to justify the content in the cells. I am reading the material ui docs about styling but I don't seem to doing it correct and frankly find the docs on styling very confusing.
The doc here: https://material-ui.com/customization/components/#overriding-styles-with-classes implies I should be able to do something like this:
const StyledDataGrid = withStyles({
cellCenter: {
justifyContent: "center",
},
})(DataGrid);
<div style={{ height: 300, width: '100%' }}>
<StyledDataGrid rows={rows} columns={columns} />
</div>
However, when I do this, I don't see the style being added to the MuiDataGrid-cellCenter DOM element. Attaching a screenshot which shows the element classes. In the inspector I see that the style isn't being added (and if I add it manually I get the desired results). Am I not using the withStyles function correctly?
So after a bit more messing around, I believe the issue is that the DataGrid component does not support the classes property (which it seems most of the material ui components do). I believe the withStyles usage about is shorthand for passing the classes via the classes prop. Since the prop isn't listed in the API https://material-ui.com/api/data-grid/ I'm assuming this is why it isn't working. I confirmed that I can get the styles working by using a combination of the className parameter with descendant selection.
If someone determines I'm wrong and there is a way to get withStyles working on this component please comment.
const useStyles = makeStyles({
root: {
"& .MuiDataGrid-cellCenter": {
justifyContent: "center"
}
}
});
...
export default function X() {
const classes = useStyles();
return (
...
<DataGrid className={classes.root} checkboxSelection={true} rows={rows} columns={columns} />
...
)
}
ALTERNATIVE SOLUTION: (for others with similar issues)
If you are working within a class and cannot use hooks...
<div>
<DataGrid
rows={rows}
columns={columns}
sx={{
'&.MuiDataGrid-root .MuiDataGrid-cell:focus': {
outline: 'none',
},
}}
/>
</div>

How do I globally override variant, color, style, etc. for Material-UI components?

Instead of doing this everywhere:
<Button variant="contained" color="primary"
style={{textTransform: "none"}}
>
Description
</Button>
I just want to write:
<Button>
Description
</Button>
Can I use theme overrides to do this and what would that look like?
Note that I'm trying to override both Material-UI properties and CSS styles. I want to do this globally (i.e. not using withStyles() stuff everywhere).
Or can this only be done by defining some kind of new AppButton component?
Currently using material-ui 3.2.2
You can do this with global overrides for your theme.
Documentation is here https://material-ui.com/customization/themes/#customizing-all-instances-of-a-component-type
Doing it this way will still allow you override the variant on a per component basis as well.
const theme = createMuiTheme({
props: {
// Name of the component ⚛️
MuiButton: {
// The properties to apply
variant: 'contained'
},
},
});
Here's an alternate way to do this, without defining a new component.
Custom components can be awkward when used with Material-UI's JSS styling solution with Typescript. I've found it difficult to define WithStyle types when combining style types from the shared component and the thing using it.
Instead of defining components, it's possible to define sets of default properties that you then apply with the spread operator.
Define and export a standard set of shared props somewhere out in your app:
import {LinearProgressProps} from "#material-ui/core/LinearProgress";
export const linearProps: LinearProgressProps = {
variant:"indeterminate",
color:"primary",
style:{height:"2px"},
};
Then use those props in your app:
<LinearProgress {...linearProps} />
This is then easy to override with custom properties, custom inline styles or JSS generated styles:
<LinearProgress {...linearProps} className={classes.customProgress}
color="secondary" style={{...linearProps.style, width: "100%"}} />
For anyone finding this question, assuming there is no Material-UI way to do this, here's my custom button component.
import * as React from "react";
import {Button} from "#material-ui/core";
import {ButtonProps} from "#material-ui/core/Button";
export class AppButton extends React.Component<ButtonProps, {}>{
render(){
let {style, ...props} = this.props;
return <Button {...props} variant="contained" color="primary"
style={{...style, textTransform: "none"}}
>
{this.props.children}
</Button>
}
}
AppButton.muiName = 'Button';

Support for a permanent clipped AppDrawer

I'm trying to make a permanent clipped navigation drawer with Material UI as per https://material.io/guidelines/patterns/navigation-drawer.html
Seems that there is a pull request out for this but not yet merged: https://github.com/callemall/material-ui/pull/6878
At this stage I'm trying to override with styles but can not get my left nav (paper) to apply the style marginTop: '50px',
Are there some samples out there on how to achieve this with v1.0.0-alpha.21?
They changed the way you have to override certain styles in v1. The inline styles no longer work. Certain parts of a component can be overridden with a simple className applied to the component. See this link for further details https://material-ui-1dab0.firebaseapp.com/customization/overrides.
Some deeper nested properties of certain components i.e the height of the Drawer can only be accessed by overriding the class itself. In this case the paper class of the drawer element.
This is a simple example
import React, { Component } from "react";
import Drawer from "material-ui/Drawer";
import { withStyles, createStyleSheet } from "material-ui/styles";
import PropTypes from 'prop-types';
const styleSheet = createStyleSheet("SideNav", {
paper: {
marginTop: '50px'
}
});
class SideNav extends Component {
....
render() {
return (
<Drawer
classes={{paper: this.props.classes.paper}}
docked={true}
>
....
</Drawer>
);
}
}
SideNav.propTypes = {
classes: PropTypes.object.isRequired
};
export default withStyles(styleSheet)(SideNav);