How to access custom namespaced (react-)JSS theme from components? - reactjs

I'm creating a react/redux app, and want to utilize JSS theming to style my app/components. I'm also using other libraries that use JSS theming, e.g. Material UI, thus I need to create a namespaced theme as described in http://cssinjs.org/react-jss?v=v8.1.0#theming to avoid conflicts with other themes.
Does this mean that I have to import my namespaced theme in every component I want to style with that theme, and pass it to injectSheet? I.e:
import React from 'react
import injectSheet, {ThemeProvider} from 'react-jss
// import my custom namespaced theming object...
import theming from '../path/to/my/custom/theming'
const styles = theme => ({
container: {
background: theme.background,
}
})
const Demo = () => (
<div className={props.classes.container}>
//...
</div>
)
// injectSheet with my custom namespaced theming object..
export default injectSheet(styles, {theming})(Demo)
This feels very cumbersome. Is it another way that one should do this? Am I missing something? Thanks in advance :)

You could wrap your injectSheet function in a central place and always pass the theming there.

Related

React & Material-UI – Custom theme within custom component

I have React app (functional components) and I use Material-UI. I have custom theme also and I use theme provider. I have created custom component (e.g. MySuperContainer) and I need to connect it with particular styles (object) in my theme
export const myTheme = { …, components: { MySuperContainer: { padding: “10px“, … } … }
I don’t want to import it to component to sx via useTheme hook. I don’t want to use styled components nor anything similar. Finally I want to write <MySuperContainer /> and it should already find its own custom styles in myTheme.
How can I achieve this? Is there any example or tutorial how to do this? I cannot find anything.

Storybook monorepo with Material UI fails to share theme across repos

I have a classic atoms/molecules/organisms monorepo with storybooks in order to create a custom components library. At the same time, such a library is based on MUI which has applied a custom theme. All of this is built with TypeScript.
I decided to base our library on MUI because it could be easier and faster for us to develop our custom components, but while I'm saving time on making them I'm putting the rest of my time trying to fix issues with the built :(
The theme
On atoms repo I have added our custom theme json which is imported by other repos (molecules and organisms) and it also gets exported as part of the atom's library and can be applied on an external project.
It uses a basic MUI as a base theme, which has been updated with some branding changes and also some custom colours (here is the problem). To make those custom colours available I have created a createPalette.d.ts file on the same Theme/ folder to declare the additions:
import '#mui/material/styles';
declare module '#mui/material/styles' {
interface Palette {
myColor: Palette['primary'];
}
interface PaletteOptions {
myColor?: PaletteOptions['primary'];
}
}
// Updated Button's props so it allows the color
declare module '#mui/material/Button' {
interface ButtonPropsColorOverrides {
myColor: true;
}
}
The them is then applied to each repo's .storybook/preview.js file like follows:
import { ThemeProvider as MUIThemeProvider, createTheme } from '#mui/material/styles';
import { ThemeProvider } from 'emotion-theming';
import theme from '../stories/Theme';
import { withThemes } from '#react-theming/storybook-addon';
const providerFn = ({ theme, children }) => {
// this fixes some issues between emotion and mui theming
const serialTheme = JSON.parse(JSON.stringify(theme));
const muiTheme = createTheme(serialTheme);
return (
<MUIThemeProvider theme={muiTheme}>
<ThemeProvider theme={muiTheme}>{children}</ThemeProvider>
</MUIThemeProvider>
);
};
const themingDecorator = withThemes(null, [theme], {
providerFn,
});
export const decorators = [themingDecorator];
And it all works just fine. I can make use of the MUI components and my theme easily.
Well, not exactly....
The problem
While I can access the theme from any other repo, it seems to fail to find the custom colours declaration and therefore every time I try to use something like theme.palette.myColor.main (as per our sample above) I get a
Property 'myColor' does not exist on type 'Palette'.ts(2339)
I have found out that, obviously, if I just replicate createPalette.d.ts on, let's say, molecules repo, it doesn't complain when I use it and also it autocomplete it with its main, dark, light... options. However, it does still through an error on 'build':
stories/ComponentFolder/index.tsx: error TS2339: Property 'myColor' does not exist on type 'Palette'.
My thoughts
What I think would be the most obvious solution is to import/extend createPalette.d.ts on any other repo but I don't seem to find a way of doing so, but also then there is the problem when building.
I'm not convinced this will work if I import the theme on any other project because maybe it would complain again about the property not existing on type 'Palette'.
I might as well just be doing this all wrong and the Theme should be stored and applied in a different way. What would be the best approach for something like this?
Notes
I'm also exporting the Theme as part of my library because I have also not been able to find a way of building and publishing my library with my theme applied. At the moment I am importing it: import theme from '#mylibrary/atoms/lib/Theme' and applying it with <ThemeProvider />. In some way, it's basically the same problem but instead of affecting other repos within my monorepo, it's affecting any other react app that tries to make use of the library.
I really, really hope someone can shed some light on this or share their way of creating something similar, please :D
I think that you are importing an interface and using it as a theme, pretty sure that you need to use a theme object like it is shown here in Using with Material-UI
const theme = {
palette: {
primary: {
main: '#556cd6',
},
secondary: {
main: '#19857b',
},
error: {
main: red.A400,
},
background: {
default: '#fff',
},
},
};

How to apply chakra-ui styles to custom components? (react-datepicker)

I'd like to define styles for my Datepicker component through the Chakra-ui styles.
import DatePicker from 'react-datepicker';
import 'react-datepicker/dist/react-datepicker.css';
import { chakra } from '#chakra-ui/react';
const StyledDatepicker = chakra(DatePicker);
I've used the chakra factory function to be able to give the StyledDatepicker some styles through props, as shown in the code above, but I'd like to define everything in a separate styles .ts file like I've done for the built-in chakra components.
I've made a Datepicker.ts file with some style definitions and added it to the overrides object which is exported here as styles:
const styles = extendTheme(overrides);
export { styles };
which is imported in App.tsx and assigned to the theme prop of my ChakraProvider.
I've made some custom components which was fine, though not exactly what I'm looking for, and I'm looking to change the styles of the header container, the element with classname react-datepicker__header - no examples of making a custom component for this on react-datepicker website. I know I can do it with CSS files, but I'd really like to do all of it in the styles file for consistency.
The answer turned out to be fairly straightforward, but imo, chakra could have made it a bit easier to learn about this possibility.
To target a css class, you just add the classname into your styles object like this:
const DatepickerStyles = {
baseStyle: {
color: 'black',
'.react-datepicker__header': {
background: 'white',
},
},
};
Then do something like this where you want to use the component (In my case, the datepicker, but this will work for any component):
function MyDatePickerComponent(props) {
const datepickerStyles = useStyleConfig('Datepicker');
return (
<Datepicker
__css={datepickerStyles}
//some required props omitted for simplicity
/>
);
}
You can use sx instead of __css, I use __css for readability.
For react-datepicker and my case of styling the header specifically, I had to use a custom calendarContainer component, where I also applied the style in a similar manner by using useMultiStyleConfig instead of useStyleConfig. Hope this can be of help to someone.

How to share custom-styled Ionic components in bit.dev

Could you please help with the following?
We use Ionic with React in a team having 2 distinct projects.
We need to style these Ionic components a little differently.
I need to share these a-little-differently-styled Ionic components with another team for code re-use.
I would like to showcase these styled Ionic components using Storybook to the UX team and say "this is how a button looks like"
To begin with I just added the styling in a css file and imported that file in the root React page.
But it would be nice to just encapsulate component + styling in a re-usable isolated component that other people can re-use without having to import custom css files.
I am thinking of :
import { IonButton } from "#ionic/react";
import styled from "styled-components";
const StyledIonButton = styled(IonButton)`
// some custom css styling here
`;
const MyIonButton = () => <StyledIonButton {...props} />;
export default MyIonButton;
Now, I can track/export above component using e.g Bit.dev and have the other team consume it via npm-install.
However, I dislike :
a) changing the name from "IonButton" to "MyIonButton"
b) having to wrap each and every Ionic component as shown above
I would like myself and the other team to just use Ionic components in the standard way e.g
import { IonButton } from "#ionic/react";
...
<IonButton>Close</IonButton>
BUT having these base building-blocks/components styled in a certain way.
Could you please describe to me the right approach please? Many thanks for your time

Reusing custom styles in material-ui

New to material-ui here and trying to work out the best way of using the css in js. I can see from the demo code that inserting styles as classes is pretty easy using 'withStyles' but if I do the following I'd need to re-create the 'grow' and 'defaultPadding' styles in every component.
import React from 'react';
import { withStyles } from '#material-ui/core/styles';
import Paper from '#material-ui/core/Paper';
function Dashboard(props) {
const { classes } = props;
return (
<Paper className={classes.defaultPadding}>
Hello
</Paper>
);
}
const styles = theme => ({
grow: {
flexGrow: 1
},
defaultPadding: {
padding: theme.spacing.unit * 3 + 'px'
}
});
export default withStyles(styles)(Dashboard);
I could easily create a factory method in an external file that returns a massive object containing all my default styles but I'd need to be able to pass the existing theme to it if I want to use things like 'theme.spacing.unit'.
So, is there a way to create a bunch of re-usable styles of my own, using theme values, then import them into any component?
Bonus question: Is it possible to create nested objects so I can do things like this? ...
className={classes.layout.header}
I think creating an external factory method would work or you could also create a ThemeProvider to pass your theme to every component that needs the same styles.
In the Codesandbox I created two Dashboard components. One with styled-components just to show how a ThemeProvider works and the other component is using withStyles.
For withStyles factory I called it sharedStyles in the demo and with this you can create a new style object inside your components by calling it and spreading it to a new style (just if you need to add more styles).
Nesting inside styles seems not supported. You could create keys like layout.heading or flatten the object before using it (see code in the demo). Both not perfect and I wouldn't use it.
I'm personally prefering styled-components but you don't need to switch to it. You can look at the source code how they implemented it and use it in your code to pass the theme to your component.
The ThemeProvider is using React Context-Api.

Resources