garronej / tss-react

✨ Dynamic CSS-in-TS solution, based on Emotion
https://tss-react.dev
MIT License
608 stars 37 forks source link

Mui v5 component classes always take precedence #25

Closed chazsolo closed 2 years ago

chazsolo commented 2 years ago

Hi @garronej

First of all - thank you so much for your work - I was really worried about the direction of MUI's styling for v5.

Trying to implement tss-react as my team has moved to migrated to mui v5 but having a lot of trouble. I've been reading your documentation, the mui migration guide, issues, everything I can, but I've yet to successfully apply tss-react properly. I believe I have most things set up properly, as the styles generated are correct, but the ultimate problem is order/specificity. MUI v5 styles are the same specificity of tss-react generated ones and come after, therefore they always override what tss generates on components.

My relevant configuration:

makeStyles.ts

import { createMakeStyles } from 'tss-react';

import theme from '$src/theme';

function useTheme() { return theme; }

export const { makeStyles, useStyles } = createMakeStyles({ useTheme });

index.tsx

import { CacheProvider } from '@emotion/react';
import CssBaseline from '@mui/material/CssBaseline';
import { ThemeProvider } from '@mui/material/styles';
import { render } from 'react-dom';
import createCache from 'tss-react/@emotion/cache';

import Root from '$components/Root';
import theme from '$src/theme';

export const muiCache = createCache({
  key: 'mui', // all material ui classes start with 'css' instead of 'mui' even with this here
  prepend: true,
});

render(
  <CacheProvider value={muiCache}>
    <ThemeProvider theme={theme}>
      <CssBaseline />
      <Root />
    </ThemeProvider>
  </CacheProvider>,
  document.getElementById('root')
);

An example of how I'm using it in a component:

Banner.tsx

import { Typography } from '@mui/material';
import React from 'react';

import useStyles from './styles';

export default function Banner(): JSX.Element {
  const { classes } = useStyles();

  return (
    // no problems here
    <div className={classes.banner}>
      // two classes here, ".css-XX-MuiTypography-root" and ".tss-XX" but the former wins by order
      <Typography className={classes.text}>
        Banner
      </Typography>
    </div>
  );
}

styles.ts

import { makeStyles } from '$src/makeStyles.ts';

export default makeStyles()((theme) => ({
  banner: {
    // styles here applied to a div, everything good
  },
  text: {
    // styles here conflict with mui styles coming from ".css-XX-MuiTypography-root"
  }
});

I don't know what I'm missing. Unfortunately it's a bit difficult for me to make a workable copy as my code is on another system. I will do my best to explain more if needed.

garronej commented 2 years ago

Hi, Thanks you for the kind words and the comprehensive description of your issue. Trust that I will have a look promptly.

garronej commented 2 years ago

Your problem is due to the fact that, in your workspace, @mui/material and tss-react aren't using the same instance of @emotion/cache.
I'll get back to you

garronej commented 2 years ago

Everything should work in v0.9.4. Update @mui/material, tss-react, @emotion/react and @emotion/styled to the latest version in your package.json, remove your .yarn.lock file and reinstall.
Sorry you had to go through this.

garronej commented 2 years ago

Just one last thing, I'd suggest you this change in your configuration:

import { useTheme } from '@mui/material/styles';
-import theme from '$src/theme';
+import type theme from '$src/theme';

-function useTheme() { return theme; }

-export const { makeStyles, useStyles } = createMakeStyles({ useTheme });
+export const { makeStyles, useStyles } = createMakeStyles({ "useTheme": useTheme as (()=> typeof theme) });

It's better as you might want, in the future, implement a dark mode or something like that. The useTheme hook is supposed to pick up the contextual theme object that you provided using <ThemeProvider />

I have updated the documentation regarding this aspect as you are not the first one my documentation confused.

chazsolo commented 2 years ago

I will be able to check to see if all this works on Tuesday - I'll let you know how it goes!

chazsolo commented 2 years ago

Unfortunately this did not work for us - after making the updates the order of CSS injection is still backwards with tss- classes being overwritten.

I'm still curious as to what the cache creation is really doing as I commented above in my code - even though I'm creating a new cache with the key of mui that doesn't seem to make any effect. Whether I include the cache or not everything remains the same.

garronej commented 2 years ago

😮
I'm sorry you still have problems. Your problem is due to the fact that tss-react and @mui/material are using different versions of @emotion/cache.
Have you tried updating @emotion/react, @emotion/styled, @mui/material, tss-react in your package.json, deleting you .yarn.lock or package-lock.json file and reinstalling everything?
What package manager are you using?

@emotion/cache is a dependency of @emotion/react that is, itself, a peer-dependency of both @mui/material and tss-react.

garronej commented 2 years ago

If you repo is open-source I can fix it directly. Otherwise will you send me your yarn.lock file (after re-installing everything).

chazsolo commented 2 years ago

We're using npm. I'd love to send you something but as I said it's all on a different system, I have to type out what we have by hand.

I did remove our lock file and reinstall everything, ensuring those packages are up-to-date. I will do some more investigation and let you know if I can't figure it out.

Here's the packages/versions we're running:

"@emotion/cache": "^11.4.0",
"@emotion/react": "^11.4.1",
"@emotion/styled": "^10.0.27",
"@mui/material": "^5.0.2",
"tss-react": "^0.9.4",
garronej commented 2 years ago

I'd love to send you something but as I said it's all on a different system, I have to type out what we have by hand.

Damn man, I feel you.

Don't forget to update this:

- import createCache from 'tss-react/@emotion/cache';
+ import createCache from "@emotion/cache";
- "@emotion/cache": "^11.4.0", #You don't need that. 
"@emotion/react": "^11.4.1",
-"@emotion/styled": "^10.0.27",
+"@emotion/styled": "^11.3.0",
"@mui/material": "^5.0.2",
- "tss-react": "^0.9.4",
+ "tss-react": "^1.0.0",

I think it's the outdated @emotion/styled that is the source of the problem.

chazsolo commented 2 years ago

I think it's the outdated @emotion/styled that is the source of the problem.

You were spot on - this fixed it!

garronej commented 2 years ago

Let's go! Glad it worked!

netzwerg commented 2 years ago

First things first: Thanks for tss-react – long live makeStyles! 🎉

I've just spent more than an hour figuring out that @emotion/styled is a required dependency – where would be the best place to document this more prominently?

garronej commented 2 years ago

Hi @netzwerg,

Sorry you had to go through this. Been there, very frustrating. I added a warning in the setup page but apparently it's not enough, I will edit.

image

garronej commented 2 years ago

image

netzwerg commented 2 years ago

I copied the yarn add line, so this totally would have saved me (the warning was too far down 🙈) – thanks a lot! 🎉

garronej commented 2 years ago

Thanks for reporting