Custom Material UI theme not picked up in emotion component - material-ui

Im implementing a mui theme through createStyles via `
import { createTheme, ThemeProvider } from '#mui/material/styles'
which looks something like
createTheme({
...other stuff
borders: { ... }
})
The theme gets created fine, and when using useTheme in a child component im able to see the custom borders object. However when logging the same from within the styled emotion component, it removes the non standard keys:
const t = useTheme()
console.log('t===',t)
const S = styled('div')`
backgroud-color: ${props => {
console.log('inside----', props.theme)
return 'red'
}}`
t=== logs fine with the borders
inside---- logs with the theme but without borders attached
Ive tried importing styled from #mui/material instead of #emotion/styled and both do the same.
Ive also created a theme.d.ts for defining the custom theme via module augmentation but that also doesnt assis
declare module '#mui/material/styles' {
interface CustomTheme {
borders?: {
lrg: any;
};
}
interface Theme extends CustomTheme {}
interface ThemeOptions extends CustomTheme {}
}
does anyone have any ideas?

Related

Common MUI theme for multiple Project

using createTheme I have created a theme for my project, it works fine.
My question is how can I use that particular theme for my other projects without copying it again n again.
I asked this Ques. with Mui team they replied " Concerning your question, you can store your theme in a "shared" repository and use this repo as a dependency on all your projects. Once the theme is changed in the shared repo, all other projects would get the changes."
please let me know an efficient way of using it.How to create shared Repository.
I tried to implement some solutions from the blog post Extending the theme in Material UI with TypeScript:
In the shared project/components lib I created a ThemeInterface.ts file. This file has the extra properties that I want in my projects.
import { Theme } from '#mui/material/styles';
export type Modify<T, R> = Omit<T, keyof R> & R;
export type CustomTheme = Modify<
Theme,
{
space: {
small: number,
general: number,
},
borderRadius: {
general: number
},
layout: {
sidebar: {
citizenBackGroundColor: React.CSSProperties['color'];
};
};
}
>;
Then I use it where I create the theme (this is still in the shared project)
import { createTheme } from '#mui/material';
import { CustomTheme } from './ThemeInterface';
export function createCustomTheme(): CustomTheme {
const baseTheme = createTheme({
//Here you can set your palettes etc..
});
return {
...baseTheme,
//Here comes the properties that we added before
space: {
small: 2,
general: 4,
},
borderRadius: {
general: 2,
},
layout: {
sidebar: {
//themeColors.secondary is just a const
citizenBackGroundColor: themeColors.secondary
}
},
}
}
I have setup my components lib with rollup an story book.
In the project that is consuming the shared theme you can now do this:
// App.tsx
const theme = createCustomTheme();
<ThemeProvider<CustomTheme> theme={theme}>
As a side note. When using storybook in your components you might need to useTheme this way otherwise it wont recognize your typings.. But this should not be needed in the consuming projects.
const theme = useTheme<CustomTheme>();

Setting a body background image in MuiThemeProvider

I have a react app with Material UI. I know how to set the theme's default background color on body. However, I want to set a background image instead. How can I accomplish this?
const theme = createMuiTheme({
palette: {
background: {
default: ???
}
}
});
If you are using CssBaseline you can apply a global style through theme overrides and set the backgroundImage for body e.g. https://codesandbox.io/s/v30yq681ql. You should be able to set the global style through any component that you are using.

Dynamically rendering react components

I'm new to reactjs and I'm having a hell of a time understanding this bug.
I've read this, and it seems like the solution is there but I'm drawing a blank on how to implement this correctly:
https://facebook.github.io/react/docs/jsx-in-depth.html#user-defined-components-must-be-capitalized
I am trying to render components based on classNames of clicked elements. The classNames match to component names. When I click an element it calls a function that sets the state of my app to that elements className. I then render the component based on the new state.
When testing, if I place the component directly into my app (not rendering the component name dynamically), it works just fine. But when i render the component name dynamically react thinks it's a built-in DOM element and doesn't render properly at all.
In this image you can see both components, rendered next to each other:
both components, first directly added, and the second with the name rendered dynamically
here is my app component code that is rendering everything:
import React, { Component } from 'react';
import logo from '../logo.svg';
import '../css/App.css';
import menus from '../menus';
import MainNav from './MainNav';
import Products from './Products';
import Demos from './Demos';
import Industry from './Industry';
import Customers from './Customers';
import Trials from './Trials';
import Contact from './Contact';
import Newsroom from './Newsroom';
import About from './About';
import Home from './Home';
class App extends Component {
constructor() {
super();
this.chooseComponent = this.chooseComponent.bind(this);
this.state = {
allMenus: menus,
componentMenu: menus,
//sets initial component to load, changes on each click to the clicked component
clickedComponent: Home
};
}
chooseComponent(event) {
//save the classname of the menu i click
var clickedComp = event.target.className;
//saves a reference to a json object for later use
var menu = menus[clickedComp];
//adds those two vars to the state
this.setState({
componentMenu: menu,
clickedComponent: clickedComp
});
}
render() {
//saves a var for rendering the currently clicked component
var ActiveComponent = this.state.clickedComponent;
return (
<div className="App">
<MainNav choose={this.chooseComponent}/>
//renders the components directly without issue
<Products menuData={this.state.componentMenu} />
//renders the component dynamically with problems
<ActiveComponent menuData={this.state.componentMenu} />
</div>
);
}
}
export default App;
here is and example of one of my component being rendered in the App that's giving problems:
import React from 'react';
import products from '../products';
import ProductsMenu from './ProductsMenu';
import Platform from './Platform';
import Applications from './Applications';
import ExMachina from './ExMachina';
import ProductsHome from './ProductsHome';
import Submenu from './Submenu';
import menus from '../menus';
class Products extends React.Component {
constructor() {
super();
this.showContent=this.showContent.bind(this);
this.state = {
productsOverview: products,
content: <ProductsHome />
}
}
render(props) {
return (
<div className="content">
{this.state.content}
</div>
);
}
}
export default Products;

How do I get intellisense to work inside es6 classes?

I have a class that extends React. Component like so:
class Main extends Component {
static propTypes = {
flavor: string.isRequired,
iceCreamMap: object.isRequired,
restUrl: string.isRequired,
token: string.isRequired,
username: string.isRequired
};
}
I want the methods of Component.prototype to show up in intellisense but it is not working. It however will work when I do. React.Component.prototype.

Is it OK to put propTypes and defaultProps as static props inside React class?

This is the way I've been doing it for quite some time now:
export default class AttachmentCreator extends Component {
render() {
return <div>
<RaisedButton primary label="Add Attachment" />
</div>
}
}
AttachmentCreator.propTypes = {
id: PropTypes.string,
};
But I've seen people doing it this way:
export default class AttachmentCreator extends Component {
static propTypes = {
id: PropTypes.string,
};
render() {
return <div>
<RaisedButton primary label="Add Attachment" />
</div>
}
}
And in fact I've seen people setting initial state outside the constructor as well. Is this good practice? It's been bugging me, but I remember a discussion somewhere where someone said that setting default props as a static is not a good idea - I just don't remember why.
In fact, it's exactly the same in terms of performance. React.JS is a relatively new technology, so it's not clear yet what are considered good practices or don't. If you want to trust someone, check this AirBNB's styleguide:
https://github.com/airbnb/javascript/tree/master/react#ordering
import React, { PropTypes } from 'react';
const propTypes = {
id: PropTypes.number.isRequired,
url: PropTypes.string.isRequired,
text: PropTypes.string,
};
const defaultProps = {
text: 'Hello World',
};
class Link extends React.Component {
static methodsAreOk() {
return true;
}
render() {
return <a href={this.props.url} data-id={this.props.id}>{this.props.text}</a>
}
}
Link.propTypes = propTypes;
Link.defaultProps = defaultProps;
export default Link;
They are declaring a const with the propTypes object literals, keep the class pretty clean and assign them later to the static properties. I personally like this approach :)
Oh yes, it's totaly legit with Babel (or other transpilers)
class DataLoader extends React.Component {
static propTypes = {
onFinishedLoading: PropTypes.func
}
static defaultProps = {
onFinishedLoading: () => {}
}
}
...as it gets transpiled to this anyway.
class DataLoader extends React.Component {}
DataLoader.propTypes = {
onFinishedLoading: PropTypes.func
};
DataLoader.defaultProps = {
onFinishedLoading: () => {}
};
Static fields get transpiled as properties on the class object under the hood.
Look here at Babel REPL.
Moreover, assigning state or other class fields directly in the class body gets transpiled into the constructor.
non-function properties are not currently supported for es2015 classes. its a proposal for es2016. the second method is considerably more convenient, but a plugin would be required to support the syntax (theres a very common babel plugin for it).
On the other end, a hand full of open source projects are beginning to treat proptypes like TypeScript interfaces, or ActionConstants and actually create separate folders/files that house various component prop types and are then imported into the component.
So in summary, both syntaxes are ok to use. but if you want to only use strictly ES2015, the latter syntax is not yet supported in the specification.
If the component is state-less, meaning it does not change it's own state at all, you should declare it as a stateless component (export default function MyComponent(props)) and declare the propTypes outside.
Whether it's good practice to put initial state declaration in constructor is up to you. In our project we declare initial state in componentWillMount() just because we do not like the super(props) boilerplate you have to use with the constructor.