GithubHelp home page GithubHelp logo

garronej / tss-react Goto Github PK

View Code? Open in Web Editor NEW
570.0 5.0 38.0 120.57 MB

✨ Dynamic CSS-in-TS solution, based on Emotion

Home Page: https://tss-react.dev

License: MIT License

TypeScript 100.00%
react typescript ssr css jss material-ui nextjs css-in-js react-hooks

tss-react's Introduction

✨ Dynamic CSS-in-TS solution, based on Emotion ✨

Home - Documentation - Playground

You can think of tss-react as @emotion/jss.
It's, in essence, a type-safe equivalent of the JSS API but powered by Emotion, just like @emotion/styled is the styled-components API but powered by Emotion.

demo.webm

While this module is written in TypeScript, using TypeScript in your application is optional (but recommended as it comes with outstanding benefits to both you and your codebase).


Get started 🚀

The more ⭐️ the project gets, the more time I spend improving and maintaining it. Thank you for your support 😊

Needless to mention, this library is heavily inspired by JSS, the OG CSS-in-JS solution.

Development

Running the demo apps:

git clone https://github.com/garronej/tss-react
cd tss-react
yarn
yarn build
npx tsc -w & npx tsc --module es2015 --outDir dist/esm -w
# Open another Terminal
yarn start_spa  # For testing in in a Create React App setup
yarn start_ssr # For testing in a Next.js setup
yarn start_appdir #  Next.js 13 setup in App directory mode

tss-react's People

Contributors

actions-user avatar baharalidurrani avatar burtek avatar cahuzacf avatar garronej avatar howlettt avatar jiby-aurum avatar jsakas avatar lsagetlethias avatar oliviertassinari avatar rlansky-percipient avatar samleatherdale avatar semigradsky avatar synaptiko avatar wald-tq avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

tss-react's Issues

Requirements for making tss-react compatible for Material-UI makeStyles replacement

Following up on our discussion started in mui/material-ui#26571 about how we can make tss-react compatible as a replacement for the makeStyles API for v5. I've done some initial testing. Here are some thoughts:

SSR

Have you tried to configure nextjs to work with tss-react? It uses @emotion/css so I believe some extra steps would be required. This would be the first requirement so that we could use it together with material-ui. Our docs (the Material-UI's) can be a good candidate for testing this out.

API suggestions

Here are some suggestions regarding the API itself:

I wouldn't return named options, if there is only one option returned. For example:

-const { createUseClassNames } = createUseClassNamesFactory({ useTheme }); // createUseClassNames is the only option
+const makeStyles = createUseClassNamesFactory({ useTheme });

-const { useClassNames } = createUseClassNames()(
+const useStyles = makeStyles()(
  (theme)=> ({
    root: {
      color: theme.palette.primary.main,
    },
  })
);

With this, we can actually make the API closer to the v4 makeStyles API. We could overcome this by adding adapters, but I will leave it to you.


Question: Is it really necessary to invoke function createUseClassNames() and then propagate the input to the next function call? What are the arguments required there? Can it be omitted?


I am open to help and move this forward :)

Add an example based on the material-ui nextjs example

I would like to see an example how to integrate tss-react based on this: https://github.com/mui-org/material-ui/tree/next/examples/nextjs-with-typescript

The current way things work is a bit confusing to me:
The example in the MUI docs has a shared util createEmotionCache which when called, always returns the result of emotions createCache function.

Now both _app and _document call that, _document uses it once in initial props, _app stores it global to the file.

The example here acts in a different way: The createDocument function returns getInitialProps logic, which internally uses getCache.
There is no _app, but I assume looking at what index.tsx does is the same what _app would do per page. index.tsx also uses the same getCache function.
What getCache basically does, is it stores a cache globally, and returns in or if it doesn't exist yet, create it using createCache from emotion.
That seems to be different from what the mui example does, since _document and _app receieve their own instance here.

Some more background to why this example would help understanding the cache utilization is in #19.

Having an example using the same structure as the MUI one would help a lot to understand the differences there.

Injection order handling as jss does

Hi, thank you for the awesome work you are providing here.

I'm using tss to replace makestyles on a mui migration.
I have a component library that i use in an application i am currently migrating to mui v5.
Both of them are using tss and i am struggling with style injection, the same way i struggled with the makeStyle back to mui v4.

here in my application:
image
The first tss class is comming from my library and should be placed below the second.

My classes are declared with clsx like so:

className={clsx(
     className,
     'AruiAppBar-root',
     defaultStyles.classes.root
)}

For jss i quickly found the index option provided on a makestyle that can tell the injection priority.
Is there anything similar in tss?

I saw in this ticket #56 that the placement of the classes does a difference in the cx function.
Is it the same foc clsx? I remember on mui they specified that the placement does not impact the injection of the styles.
Do i have to use the function cx insted of clsx?

[feature] Auto-generate label property in makeStyles

To make class names more readable for development like they are in material-ui, I would like to propose the following adjustment to make styles, to make it more compatible with old material-ui v4 makeStyles:

const useStyles = makeStyles({ name: 'MyComponent' })(theme => ({
    root: {
        color: 'red',
    },
    child: {
        color: 'blue',
    },
}));

which would internally expand the styles object to the equivalent to

const useStyles = makeStyles()(theme => ({
    root: {
        label: 'MyComponent-root',
        color: 'red',
    },
    child: {
        label: 'MyComponent-child',
        color: 'blue',
    },
}));

which would result in the following class names:

.tss-react-s0z026-MyComponent-root { color:red; }
.tss-react-pc49kh-MyComponent-child { color:blue; }

The following adjusted version of makeStyles would be able to perform this logic (which is what I am currently using and everyone else can easily patch into their own app as well:

const { useStyles } = createMakeStyles({ useTheme });

export default function makeStyles<Params = void>(opt?: { name?: string; }) {
    const labelPrefix = opt?.name ? `${opt.name}-` : '';
    return function <RuleName extends string>(
        cssObjectByRuleNameOrGetCssObjectByRuleName: Record<RuleName, CSSObject> | ((theme: Theme, params: Params, createRef: () => string) => Record<RuleName, CSSObject>)
    ) {
        const getCssObjectByRuleName = typeof cssObjectByRuleNameOrGetCssObjectByRuleName === 'function' ?
            cssObjectByRuleNameOrGetCssObjectByRuleName :
            () => cssObjectByRuleNameOrGetCssObjectByRuleName;
        function useStylesHook(params: Params) {
            const { cx, css, theme } = useStyles();
            let count = 0;
            function createRef() {
                return `tss-react-ref_${count++}`;
            }
            const cssObjectByRuleName = getCssObjectByRuleName(theme, params, createRef);
            const classes = Object.fromEntries(Object.keys(cssObjectByRuleName).map(ruleName => {
                const cssObject: CSSObject = cssObjectByRuleName[ruleName as RuleName];
                if (!cssObject.label) {
                    // Assign label to class name if none is provided
                    cssObject.label = labelPrefix + ruleName;
                }
                const className = css(cssObject);
                return [ruleName, className];
            })) as Record<RuleName, string>;
            return { classes, theme, css, cx, };
        }
        return useStylesHook;
    };
}

I think this would be a great addition to this library to make it easier to work with 👍

SSR broken with dynamic, cookie-based theme (dark mode doesn't work)

Hello!

I discovered an issue in my app (Next JS with Material UI v5 and "next-dark-mode"), and hoped you might be able to help :)

TLDR:

Determining the theme based on a cookie seems to generate two sets of stylesheets on the server. This breaks the theming on the client.

Code sandbox:

https://codesandbox.io/s/vigorous-noether-5xxr6

GIF:

ezgif-6-d2e3947a0aac

Steps to reproduce:

  1. Open up the project from the CodeSandbox linked above and let the homepage load.
  2. Refresh the page. You should see nothing out of the ordinary (I assume because there's no theme cookie yet).
  3. Now click the "switch theme" button in the middle. The theme should switch correctly to light / dark.
  4. Now refresh the page —> ???? The background should be the wrong color!
  5. Click the button to switch themes and you should see that the "new theme" is correct, and looks a lot like the old broken theme.
  6. Refresh the page again, and you should see the same bug with the opposite color as well — parts of the page are using the correct colors, while other parts are not.

Switching themes twice "fixes" the theme to have the right colors, but only until the next page visit / next refresh.

It looks like the cookie seems to work incorrectly when theme styles are generated on the server side.


Details:

After upgrading to MUI 5 last weekend, I noticed that the footer of my app always had the links in the wrong color for some reason. So I tried to investigate.

I saw that I seemed to be getting two sets of styles on the client, as can be seen in the screenshot below:

Screenshot 2021-10-23 at 9 33 10 AM

These conflicted with each other in somewhat unpredictable ways. In my case the result was that 99% of the app seemed to look fine, except for the footer. In the CodeSandbox above, it seemed to affect the body background color as well.

I'm using the "next-dark-mode" library, which uses a cookie to store the user's dark mode preference. This cookie is supposed to let my Theme component determine the right theme during server-side rendering. In my app all pages are currently server-side rendered (i.e. no static pages), but the theming bug is still present.

In the gif above you can see that the theme seems to be generated correctly when the user clicks a button to switch modes, but breaks when the user comes back to the page (e.g. after refreshing).

If I remove getInitialProps from my _document.tsx file, then this bug does not occur.

.

I'm hoping that this is just a user-error on my part. However, I didn't have this issue in MUI 4 (back then I used ServerStyleSheets from MUI styles and merged them in getInitialProps in _document.tsx in much the same way as now.)

To be honest I have no idea what's really happening under the hood here. I'm a bit new to Next JS and certainly very new to emotion (e.g. I have no idea whatsoever how it's caching works). But before I spend many hours debugging and diving down the info rabbit hole of how server-side rendered styles work, I thought I'd try my luck asking for help here first 😄


While I'm here, allow me to say that I really love this library. It made my MUI 5 migration very smooth and easy, I have no idea how many hours it would've taken if I had to refactor everything to styled components.

Also, I really love how the results of functions return objects. It makes it so easy to just autocomplete the results of everything, so I never make typos and I never have to worry about naming things. And of course being a big TS fan I love that everything could be kept type-safe 😄 So yeah, even if I need to take this issue to another library, just wanted to say thanks a lot for your hard work! 😄

MUI V5 precedence - nested classes?

Hi there,

I'm currently trying out tss-react and noticed a roadblock, which I'm not sure how to solve it: I'm unable to change the color of the deleteIcon of a Chip since the original styles take precedence. I also followed the steps of the README, see here for a repro: https://stackblitz.com/edit/tss-react-aupnsq?file=Hello.tsx

As you can see, overriding the color in the theme works, but individually styling it with withStyles creates the wrong class order.

image

Am I missing something obvious? Do I maybe somehow have to specify MuiButtonBase-root-MuiChip-root so it it's on the same level?

Mui v5 component classes always take precedence

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.

Argument of type '{ position: string; }' is not assignable to parameter of type 'CSSInterpolation'

I am not sure if this is specific to tss-react or another emotion issue, but I am finding this happens with the typings

import makeStyles from '@ui/utils/makeStyles';

export default makeStyles()((theme, _params, css) => {
  const s2 = {
    position: 'absolute',
  };

  return {
    s1: {
      [`&:hover .${css(s2)}`]: {
        color: 'red'
      }
    },
  };
});

TS error:

No overload matches this call.
  Overload 1 of 2, '(template: TemplateStringsArray, ...args: CSSInterpolation[]): string', gave the following error.
    Argument of type '{ position: string; }' is not assignable to parameter of type 'TemplateStringsArray'.
      Type '{ position: string; }' is missing the following properties from type 'TemplateStringsArray': raw, length, concat, join, and 17 more.
  Overload 2 of 2, '(...args: CSSInterpolation[]): string', gave the following error.
    Argument of type '{ position: string; }' is not assignable to parameter of type 'CSSInterpolation'.
      Type '{ position: string; }' is not assignable to type 'CSSObject'.
        Types of property 'position' are incompatible.
          Type 'string' is not assignable to type 'Position | Position[]'.ts(2769)

I can work around by casting to CSSObject but its not great.

Styles insertion order with server-side rendering

I realise this issue has been mentioned previously but, I wanted to understand something.

I recently had an issue with the insertion order of styles, the base MUI styles were being inserted after the TSS styles and so, took precedence over the TSS styles. This caused issues where I was setting the display to be flex but the MUI Container styles default to block and so rendered in a top-down approach.

Screenshot 2022-03-08 at 21 40 47

As you can see from the screenshot, the MUI Container styles are taking precedence. I tried one of the solutions recommended on another similar issue (to use &&) and that worked. But I then realised that the insertion order was possibly off due to the TSS emotion server coming before the MUI emotion server in the emotionServers array (from the docs):

const createMUICache = () =>
  createCache({
    key: "mui",
    prepend: true,
  });

....

const muiCache = createMUICache();
// sets TSS server first and then the MUI server after, meaning the MUI styles would take precedence?
const emotionServers = [getTssDefaultEmotionCache({ doReset: true }), muiCache].map(createEmotionServer);
 
.... // renders app

const css = emotionServers
    .map(({ constructStyleTagsFromChunks, extractCriticalToChunks }) => {
      const chunks = extractCriticalToChunks(html);
      return constructStyleTagsFromChunks(chunks);
    })
    .join(""); // creates the styles but the TSS ones first and then the MUI ones

Noticing this, I tried it again by swapping around the two servers like below, rather than using the && approach:

const emotionServers = [muiCache, getTssDefaultEmotionCache({ doReset: true })].map(createEmotionServer);

and that then fixes the insertion order (see the image below).

Screenshot 2022-03-08 at 21 50 34

So, my question is just, is there a particular reason as to why the MUI emotion server should come after the TSS one, or is it fine to have the TSS one last? If so, should the docs be updated for this?

Let me know if you would like any more information, this is the only issue I have come across with TSS and I think it is an awesome package and nice to see there is still support out there for JSS approaches with MUI! :)

nextjs head order on revalidated pages

On material ui v4, there was a critical bug when used with nexjs and revalidated pages:
mui/material-ui#25307

It would lead to page layouts breaking in random ways due to orders of tags in head changing.
Fixing it was out of scope for MUI v4, and as @oliviertassinari pointed out there, the same issue was unlikely to appear in emotion since that uses prop cascading.

I'm wondering now if these issues are likely to come back when using tss-react:
What I was currently trying to solve with some of the the other issues I opened, is basically the makeStyles-defined classes having more priority than the MUI ones, although following the emotion cascading logic, it would be the opposite (Outside some component using the tss version of makeStyles first, then inside/after the MUI component defining its own styles)

So far, making the makeStyles-classes have more priority only worked by using two emotion caches, and essentialy relying on the order of elements in HEAD if I get things correctly

I will prepare a sandbox like the one in the issue above to see if I can observe the same behavior.

[Help] Support for Material Ui 5 with Javascript

I am currently using a project with Material UI 4 and am in the process of changing to MUI 5. I had used a lot of makeStyles and would like to still use this way of styling. I saw this repo and thought this would be a great way to still use makeStyles, but then saw that you guys specifically made this for TS and not JS. So I am asking if you guys support JS and if you do, how can I then add it to my project? Maybe there could be a specific guide with everything you need to do to convert your MUI 5 project to use this library?

How to use with Gatsby? (Styles not loading on static-site generation)

Hey 😄 Sorry to bother, but I'm quite confused.

I've been trying to use this library with Gatsby JS (a popular static site generation framework, similar to Next JS). I've messed around with gatsby-plugin-emotion and gatsby-plugin-material-ui, but my styles never seem to be server-side rendered in production mode — when I run gatsby serve and then open up the page, there is always a "flash of unstyled content".

I'm guessing the problem is that the SSG side doesn't have access to the emotion cache from tss-react? The Gatsby documentation has a page for emotion but they don't mention anything about a custom cache, so I'm a bit stuck unfortunately 😅

Would it perhaps be possible to have an example of a tss-react setup with Gatbsy? I'm sure it would be helpful to lots of people 😄

Best,

Solution for composition?

Any way we can reuse styles that rely on props/state?

const { useClassNames } = createUseClassNames()((props) => ({
  link: {
    ...
    '&:hover':  {
      extend: 'activeLink', // JSS solution
    },
  },
  activeLink: {
    // some CSS that relies on props
  },
}));

Example using next with <CacheProvider/> in pages/_app.tsx.

Hi

Thanks a lot for this tool and your examples and docs.

I am trying to use tss-react with next

I read your docs here https://docs.tss-react.dev/ssr/next.js and checked-out the example here https://github.com/garronej/tss-react/tree/main/src/test/apps/ssr

When I move the cache provider to _app.tsx the styles no longer work when server side rendering (I get an initial un-styled page from the server which is then styled on the client)

tss-react

Here is a my code.

https://github.com/ziggy6792/tss-react/tree/provider-in-app

Thanks a lot

Class precedence

Context:

  • MUI v5 beta 4
  • Nextjs
  • Using makeStyles with tss-react

I'm used to passing classes to MUI components in a classes object in order to overwrite styles.
However, the Material UI default classes always seems to be appended later, causing the custom styles to be ignored.

For example:

const useStyles = makeStyles()((theme: Theme) => ({
  myButtonRoot: {
    backgroundColor: "green",
  },
}));

...

const { classes } = useStyles();

<Button color="primary" classes={{ root: classes.myButtonRoot  }}  />;

The resulting css will list that green background, but it will be overwritten by the own MUI Button styling, since that has a background of the primary theme color.

The custom makeStyles classes should come after/have priority over the default ones of that component.

Codemod for migration from `@material-ui/styles`'s `makeStyles` to `tss-react`

Hi,

I am trying to start a discussion to see if it is possible/feasible to create a codemod that would migrate from @material-ui/styles makeStyles and withStyles to the tss-react's equivalents.

The motivation is to help the developers to migrate from @materia-ui/core (v4) to @mui/material (v5) in a more automated way. From what I was seeing from time to time in the activity of the project, looks like most (all?) features that @material-ui/styles' API provided are already implemented. If this is the case, I would like to hear your opinion, on whether you think this could actually be automated, or there are things that are still depending on a person being involved when migrating.

Thanks!

TypeError: (0 , cache_1.default) is not a function

Good day, I'm trying to test a component that makes use of tss (I'm migrating from the materialUI v4 makeStyles), while this is working fine during development, I'm encountering an issue when trying to test a component that makes use of tss

The error is the following:

    TypeError: (0 , cache_1.default) is not a function

      12 |
      13 | export const DummyElement = () => {
    > 14 |   const { classes, cx } = useStyles();
         |                           ^
      15 |   return <div className={cx(classes.root)}>DUMMY</div>;
      16 | };
      17 |

This is with material UI v5, I followed all the steps in the readme, I created a minimal reproducible example in this repository: https://github.com/lucacampana-whs/tss-react-issue-jest-cache

How to add prefix globally?

Hey man :)

Now we are working on a project with micro-frontend architecture based on Webpack 5 Module Federation.

It's actually a single react project made up of 20 small projects.

Just a bit worried on the duplication on CSS classnames. Is it possible that there might be some duplicated classnames across these projects?

In material UI, there's a key attribute in emotion cache, as well as the prefix attribute in JSS which can avoid this problem.

export const muiCache = createCache({
  key: "mui",
  prepend: true
});

Please give us some advices, thanks mate :)

Injection order of tss and regular styles are in the wrong order for a short while

Hi there!

I'm running into an issue where the order of css and tss styles are sorted in the wrong way in the head for a short period of time..

Video of the problem: https://d.pr/v/SXxXJq

You can see it happening from the 15 second mark in the video, you see the tss- below the css- styles for a short while

It seems to be due to a reordering in the header which is happening teporarily:

Screen.Capture.on.2022-01-07.at.10-47-49.mp4

Server loaded styles:
Schermafbeelding 2022-01-07 om 10 49 34

CSS styles get applied below the tss styles:
Schermafbeelding 2022-01-07 om 10 49 45

CSS styles are now moved to the top:
Schermafbeelding 2022-01-07 om 10 49 50

I'm using the following code:

// eslint-disable-next-line @next/next/no-document-import-in-page
import type Document from 'next/document'
import { withEmotionCache } from 'tss-react/nextJs'
import { emotionCache } from './tssReact'

export function documentWithEmotion(Doc: typeof Document) {
  return withEmotionCache({ Document: Doc, getCaches: () => [emotionCache()] })
}
import createCache from '@emotion/cache'
import type { EmotionCache } from '@emotion/cache'
import { CacheProvider } from '@emotion/react'
import { getTssDefaultEmotionCache, TssCacheProvider } from 'tss-react'

let cache: EmotionCache | undefined

/** Creates a single instance of the `@emotion/cache` that is shared between server and client */
export function emotionCache() {
  if (!cache) cache = createCache({ key: 'mui', prepend: true })
  return cache
}

/** Provider that is supposed to be used in your `pages/_app.tsx` */
export function EmotionProvider({ children }: { children: React.ReactNode }) {
  return (
    <CacheProvider value={emotionCache()}>
      <TssCacheProvider value={getTssDefaultEmotionCache()}>{children}</TssCacheProvider>
    </CacheProvider>
  )
}

I've tried without the TssCacheProvider first, but that doesn't seem to be making a difference.

Ideas: After googling a bit we might be able to use this option to make this more stable?
emotion-js/emotion#2037 (comment)

(In general it bothers me a bit that it even recreates styles in the DOM, because that means that the browser must reevaluate the styles, but maybe that goes away if the locations are exactly the same..)

(I promise I'm almost done bothering you with all these issues 😗)

Wrong color applied to link when overriding MUI theme

We have a Next.js application that we are in the midst of upgrading from MUI v4 to MUI v5 with react-tss. Part of our theme file is as follows:

MuiLink: {
  styleOverrides: {
    root: {
      color: '#0068b5',
      textDecoration: 'none',
    },
    underlineNone: {
      color: '#f9f9f6',
    },
  },
  defaultProps: {
    underline: 'hover',
  },
},

In MUI v4, this color was correctly applied. However, in MUI v5 with react-tss, our link styles look like this:

image

It appears that instead of replacing the original color CSS property the new color is simply being added as an additional property. And unfortunately, probably based on the order styles are applied, the wrong color is taking precedence over the desired color. Any ideas here?

Property ''@font-face'' is incompatible with index signature.

Schermafbeelding 2022-01-05 om 11 48 39

I'm using the material ui createStyles and try to inject the complete styles of body1.

const useStyles = makeStyles()((theme) => ({
  root: {
    ...theme.typography.body1,
  },
}))

This will however give an error:

Argument of type '(theme: Theme) => { root: { backgroundColor: string; '@font-face'?: Fontface | Fontface[] | undefined; accentColor?: AccentColor | undefined; ... 783 more ...; vectorEffect?: VectorEffect | undefined; }; }' is not assignable to parameter of type 'Record<"root", CSSObject> | ((theme: Theme, params: void, classes: Record<never, string>) => Record<"root", CSSObject>)'.
  Type '(theme: Theme) => { root: { backgroundColor: string; '@font-face'?: Fontface | Fontface[] | undefined; accentColor?: AccentColor | undefined; ... 783 more ...; vectorEffect?: VectorEffect | undefined; }; }' is not assignable to type '(theme: Theme, params: void, classes: Record<never, string>) => Record<"root", CSSObject>'.
    Call signature return types '{ root: { backgroundColor: string; '@font-face'?: Fontface | Fontface[] | undefined; accentColor?: AccentColor | undefined; alignContent?: AlignContent | undefined; ... 782 more ...; vectorEffect?: VectorEffect | undefined; }; }' and 'Record<"root", CSSObject>' are incompatible.
      The types of 'root' are incompatible between these types.
        Type '{ backgroundColor: string; '@font-face'?: Fontface | Fontface[] | undefined; accentColor?: Property.AccentColor | undefined; alignContent?: Property.AlignContent | undefined; ... 782 more ...; vectorEffect?: Property.VectorEffect | undefined; }' is not assignable to type 'CSSObject'.
          Property ''@font-face'' is incompatible with index signature.
            Type 'Fontface | Fontface[]' is not assignable to type 'CSSInterpolation'.
              Type 'Fontface' is not assignable to type 'CSSInterpolation'.
                Type 'Fontface' is not assignable to type 'CSSObject'.
                  Index signature for type 'string' is missing in type 'FontFace<0 | (string & {}), string & {}> & { fallbacks?: FontFace<0 | (string & {}), string & {}>[] | undefined; }'.ts(2345)

I've ran into this issue in another situation in the past and in that case it was a version mismatch with csstype, but I've tripple checked but this doesn't seem to be the case.

It is because of this line in Material UI, if I temporarily comment this out, it wont throw the error: https://github.com/mui-org/material-ui/blob/master/packages/mui-material/src/styles/createTypography.d.ts#L38

Issues while using Yarn 3

Hi, while building our project we get these errors from Yarn 3 with PnP.

./.yarn/__virtual__/tss-react-virtual-f99a3cd5a8/0/cache/tss-react-npm-2.0.2-7ea9c3ac36-21cc281768.zip/node_modules/tss-react/cssAndCx.js
Module not found: tss-react tried to access @emotion/serialize, but it isn't declared in its dependencies; this makes the require call ambiguous and unsound.

and

./.yarn/__virtual__/tss-react-virtual-f99a3cd5a8/0/cache/tss-react-npm-2.0.2-7ea9c3ac36-21cc281768.zip/node_modules/tss-react/cssAndCx.js
Module not found: tss-react tried to access @emotion/utils, but it isn't declared in its dependencies; this makes the require call ambiguous and unsound.

While this can be fixed via .yarnrc.yml, I would appreciate it if you could add these as dependencies to your package.

no example(s) setup showing what is required (cache/theme/? provider)

Hi, thanks for all the hard work first of all. But would it be much to ask for some more extensive examples as to what is expected for this to work? I expect this lib has to order every bit off css to guarantee specificity, but following the docs it is not made clear what the minimal requirements are to do so.

Unable to install packages after Migration to React v18

Are there going to be any breaking changes after updating React to v18 in peer dependencies?
Currently, I'm unable to install tss-react in my React v18 project:

npm ERR! Could not resolve dependency:
npm ERR! peer react@"^16.8.0 || ^17.0.2" from [email protected]
npm ERR! node_modules/tss-react
npm ERR!   tss-react@"^3.6.0" from the root project

Passing a custom cache to createMakeStyles breaks SSR

This issue overlaps a bit with what I described in #18, so I moved things here.

I was able to fix the makeStyles classes priority issue in some parts, by utilizing createCache in there using the same key I used in _document and _app for it. (Actually using a shared helper createEmotionCache like done in the MUI repo example).
The custom makestyles function now looks like this:

const cache = createEmotionCache();

const { makeStyles } = createMakeStyles({
  useTheme,
  cache
});

While that works in dev, in a production build it actually breaks the server render (Fixed itself when the client side hydration kicks in). Removing that one line to pass a cache to createMakeStyles makes SSR properly work again, however Im back to the issue of makeStyles classes having less priority than MUI ones.

Since Im defining my own cache with key, I wonder, if cache is not passed, would this lib actually pick up the correct cache from the provider, or create a new one under its key "tss-react"? Looking at the code, this does work using some recently exposed context hook in emotion.

I also tried the opposite, not defining a cache and using getCache everywhere + also removing my custom _document and using your utility for it instead, however with that I would have the same result, ssr works, but makeStyles classes have less priority.
...Which basically led me to two options:
A. The way getCache in tss works is wrong
B. Creating the cache in my makeStyles and passing it along createMakeStyles is wrong, and my class order working now in dev is just a side effect.

Next I tried actually adding a second emotion cache, this time on purpose with a different cache key, then also wrapping _app in another, outer <CacheProvider (the inner would be for mui) and in _document.js I also did the style extraction a second time for that second cache key (After the first one for the default styles, to gain priority )
However, the result is similar, passing a custom cache to createMakeStyles just seems to break SSR.

Issue when using tss-react on building a customized UI library

We are upgrading the company's UI library, which is a wrapper of MUI components, and tss-react is used to customize the styles with dynamic themes. Also we use makeStyles, useStyles etc. within the UI library repository to customize the MUI styles:

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

The issue is, when consuming the customized components from the UI library from our main project, and we got this error:

Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.

I guess the reason is because the "useStyles" within the UI library repo does not work because it is actually a wrapper of the "useTheme" hooks, and it should be created in the main repo. However we need to use it in the UI library which is causing issue.

Any solutions can help?

API improvement for when there is no state arguments.

We should be able to do:

const { classNames } = useClassNames();

instead of

const { classNames } = useClassNames({});

When we have no state argument, e.g:

const { useClassNames } = createUseClassNames()(
    theme=>({
    //...
    })
);

[Help] TypeError: theme.spacing is not a function

I know this is something i'm doing wrong, but I can't seem to figure it out. I just refactored everything to use the tss-api in mui 5. Pretty stumped

image

My structure is as follows

AppThemeProvider.tsx

import { CacheProvider } from '@emotion/react';
import { LocalizationProvider } from '@mui/lab';
import AdapterDateFns from '@mui/lab/AdapterDateFns';
import { createTheme, ThemeProvider } from '@mui/material';
import * as React from 'react';
import createCache from 'tss-react/@emotion/cache';
import { defaultTheme, darkTheme } from '../../themes/default';

export const muiCache = createCache({
    key: 'mui',
    prepend: true
});

interface IAppThemeProviderProps {
    themeType: 'dark' | 'light';
}
const AppThemeProvider: React.FC<IAppThemeProviderProps> = ({ children, themeType }) => (
    <CacheProvider value={muiCache}>
        <ThemeProvider theme={createTheme(themeType === 'light' ? defaultTheme : darkTheme)}>
            {/* eslint-disable-next-line @typescript-eslint/no-unsafe-assignment */}
            <LocalizationProvider dateAdapter={AdapterDateFns}>
                {children}
            </LocalizationProvider>
        </ThemeProvider>
    </CacheProvider>
);

export default AppThemeProvider;

makeStyles.ts

import { createMakeStyles } from 'tss-react';
import { defaultTheme } from './themes/default';
import { ICustomTheme } from './themes/types';

function useTheme() {
    // I need to cast this. Before createTheme turned my theme from ThemeOptions to type Theme
    return defaultTheme as ICustomTheme;
}

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

usage:

const useStyles = makeStyles()((theme: ICustomTheme) => ({
    notificationSettingsContainer: {
        margin: theme.spacing(1, 0, 2, 0),
        padding: theme.spacing(2)
    },
    secondaryButton: {
        borderRadius: theme.spacing(0.5),
        margin: theme.spacing(1, 0, 0, 0),
        textTransform: 'uppercase'
    }
}));

I'm not sure what i'm missing here. Any help is greatly appreciated.

Error in latest release

I get the following error when compiling my project in the latest version.

Module not found: Error: Can't resolve 'tsafe/typeGuard' in '/node_modules/tss-react'

classes are not applied in correct order

Hi,

I'm migrating a project from using jss towards tss-react.
We use MUI5 and after migrating to tss-react i see some classes are changed in order.

I already checked some other topics on this behavior.
What i already did:

  • update emotion libs to the latest versions
  • added the CacheProvider as a wrapper around MuiThemeProvider
  • updated my makeStyles.ts to use tss-react > createMakeStyles
  • adding the '&&' rules to the css works, but doesn't sound like a correct solution to me

As an example:
On a mui typography the -root styling of mui is applied in a higher order then the classname which we provides to item.
This results in not applying our classname styling to it.

image

Optimization of the optimization

In this line, getDependencyArrayRef(params) should be replaced with just params.

First reason:
getDependencyArrayRef uses json serialization which can VERY easily throw exceptions if it is not a plain object or contains circular references

Second reason:
getDependencyArrayRef uses json serialization which has a huge negative performance impact again which counteracts the optimization

Third reason:
It's not even required. If the object is the same reference, we should also expect that it's values are the same (same as with React's own hooks like useEffect or useMemo).

This would of course break if someone actually does something crazy like this:

const styleParams = React.useRef({ color: 'red' });
const { classes } = useStyles(styleParams);
// ... somewhere else
styleParams.color = 'blue'

However, as mentioned before, this is the very same for React's own hooks as well so it does not make sense to try optimizing for this.

Fourth reason:
If a user does want to use params but also benefit from performance improvements, there is a simpler and way more performant way to do so:

const { classes } = useStyles(
  useMemo(() => ({
    color: props.color,
  }), [props.color])
);

Suggestion: a polyfill free version?

Hi @garronej,

First of all I'd like to thank you for all the work you've put into this. I've been using this library from the start and it's pretty much the thing that made migration to MUI v5 possible for me. The amount of work and love you've put into this is inspiring, so thank you very much!

I had previously opened an issue here with regards to an error I was having with the fromEntries polyfill included in this lib (specifically on ie11). Long story short the polyfill included here requires Symbol.Iterator, which does come with recommended ie11 polyfills for react apps. Our project doesn't use those, we instead use the polyfill.io service which allows us to reduce bundle size and also move polyfill dependencies elsewhere. For reference, we ended up including the Object.fromEntries polyfill from there which doesn't have other polyfill dependencies (https://github.com/Financial-Times/polyfill-library/blob/master/polyfills/Object/fromEntries/polyfill.js).

Recently with further upgrades we've also had to include Array.find and Proxy, the latter one being slightly harder as it's not really included in any of the major polyfill providers, so it requires that specific package which you linked. Proxy, specifically, is a problem not just in ie11, but in several older browsers, which we started to see errors for in our logs. I know it's all in your README and adding the required polyfills is not particularly hard, but specifically in our case since we run automatic dependency upgrading in our pipelines we tend to see these issues come up in production, even if it only impacts a small percentage of users.

So my suggestion would be if there is a possibility of having a version that doesn't require any of these polyfills. I haven't looked into the code to see what Proxy or Array.find is doing, and if there are other ways to do the same thing, so please excuse my request if it doesn't make any sense. I just thought I'd put the suggestion out there since, for example, even though MUI v5 itself doesn't support ie11 and older browsers, it does actually work on them bar some stying issues or other very specific problems.

Again, please ignore if this doesn't make any sense, and thank you for the great work.

Fernando

Allow &-nesting of element name

It seems as though nesting with & just concatenates whatever follows the ampersand.
So { root: { '&a': { backgroundColor: ... } } } becomes:
image
It'd be nice to be able to & element names as well.

Error: Object.fromEntries() requires a single iterable argument on old browsers (ie11 specifically)

First of all I'd like to express my gratitude on the great work done on this, it's made my migration to MUI 5 actually possible. Thanks!
Second, I know that a lot of current libraries have dropped ie11 support, and even MUIv5 states that there is only partial support for it.
I just wanted to report the issue in the hopes that there is an easy solution where we can allow our users to have some sort of experience with ie11, even if not ideal, as opposed to have to show them an error page and not being able to style anything.

Thanks

Selecting children by class name

Hello, I am trying to figure out how to select nested children by class name using this library. Below is an example of how we did it with JSS:

  el1: {
    '&:hover $el2': {
      display: 'block',
    },
  },
  el2: {
    display: 'none'
  },

Is this currently supported? The docs say:

tss-react unlike jss-react doesn't support the $ syntax, but you'll see. It isn't needed.

But don't clarify how we would do the above.

withStyles

Could you implement withStyles in tss-react too? It's convenient when just want to overwrite the style of a Mui Component.

const StyledLinearProgress = withStyles(LinearProgress)({
    root: {},
    // other LinearProgressProps.classes properties...
})

Originally posted by @Jack-Works in mui/material-ui#26571 (comment)

The render sequence is wrong when passing CSS classes to child

Let's assume we have ComponentA and ComponentB in different files.

// file1.tsx
const useStyles = makeStyles()(({ palette, breakpoints }) => ({
  extra: {
    color: "red"
  }
}));

const ComponentA = () => {
  const { classes, cx } = useStyles();
  return <ComponentB extraClasses={classes.extra} />;
}
// file2.tsx
const useStyles = makeStyles()(({ palette, breakpoints }) => ({
  root: {
    color: "blue",
    [breakpoints.up("sm")]: {
      color: "yellow"
    }
  }
}));

export const ComponentB = ({ extraClasses }: { extraClasses?: string }) => {
  const { classes, cx } = useStyles();
  return <div className={clsx(classes.root, extraClasses)}>Hi</div>;
};

Ideally when using JSS, the extraClass in ComponentA will override the root class in ComponentB which can produce the right result on screen, which is that the text should be in "red" color.

Problems:

  1. If using clsx to merge classes, then two classes will be generated but in wrong sequence. The root class in ComponentB will always override extraClass in componentA and display "blue" color which is wrong.

  2. If using cx to merge classes, then one merged class will be generated in right sequence, but if there's any breakpoint related css in ComponentB, then it will not work well because the css priority is always breakpoint first, so it will display "yellow" color which is also wrong.

Thanks for building this amazing package and this is the only issue we have so far.

Hope you can provide a fix or let us know if there's any workaround. Our project is huge so finding them and changing them one by one is kind of impossible..

Cheers
CJ

Problem with the latest MUIv5 and classes/withStyles overrides of nested elements

Hello,

when I created this PR #54 we were still using MUIv4. We are using overrides with classes prop and withStyles of MUI components a lot and since we started migrating to MUIv5, I've noticed something strange.

I've create a demo here:

I followed the recommended steps from both tss-react and MUI projects to eliminate issues with the setup.

The problem in a nutshell is the following, when you have a component with sub-elements and you'd like to override default styles (let's say color or background color), one would expect to use what was possible in MUIv4:

const StyledChip = withStyles(Chip, (theme) => ({
  root: {
    backgroundColor: theme.palette.primary.main,
    color: theme.palette.primary.contrastText,
  },
  deleteIcon: {
    color: theme.palette.primary.contrastText,
    '&:hover': {
      color: `${theme.palette.primary.contrastText}6`,
    },
  },
}));

But it doesn't work because of CSS selector specificity:
image

The only solution I found is with:

const StyledChip = withStyles(Chip, (theme, _props, classes) => ({
  root: {
    backgroundColor: theme.palette.primary.main,
    color: theme.palette.primary.contrastText,
    [`& .${classes.deleteIcon}`]: {
      color: theme.palette.primary.contrastText,
      '&:hover': {
        color: `${theme.palette.primary.contrastText}6`,
      },
    },
  },
}));

Unfortunately it requires a lot of refactoring in our code and it's also quite hard to reason about, you need to know that you are fighting with specificity here (which I assumed that emotion-based solution should help to avoid).

I'm not 100% sure if it's a problem in tss-react itself or if it's more about how MUIv5 handles classes props.

Bug in cx function

If I'm not mistaken, in this line, the code should not be

.map(classNameOrCSSObject =>
    typeof classNameOrCSSObject === "string"
        ? className
        : css(classNameOrCSSObject),
)

but instead

.map(classNameOrCSSObject =>
    typeof classNameOrCSSObject === "string"
        ? classNameOrCSSObject
        : css(classNameOrCSSObject),
)

Material UI classes argument and composition.

Problem: i use composition as you proposed in docs, but there is a problem when i use it with classes props from MUI.
Let's i have styles object tableRow, i need it class name to use in composition, i'm doing css(tableRow) and it returns tss-react-1yphcmd i then use classes.tableRow in component code like this classes={{ root: classes.tableRow }}.
Then in browser i see this element has class tss-react-1yphcmd-MuiTableRow-root, i.e. something added -MuiTableRow-root string. What's the problem? I see easy workaround here but i really would prefer to simply use css(tableRow).

Migration from MUI 4 to 5 - "Type 'string' is not assignable to type '"relative"

Hey,

I'm currently migrating from MUI 4 to version 5 and have encountered some weird behaviour.

I've got a two files tableFilterStyles.ts and TableFilter.tsx containing

tableFilterStyles.ts

import { Theme } from "@mui/material/styles";

export const tableFilterStyles = (theme: Theme) =>
  ({
    root: {
      position: "relative"
    },
    ....
  });

TableFilter.tsx

import { makeStyles } from 'tss-react/mui';
import { tableFilterStyles } from "../../styles";

const useStyles = makeStyles()(tableFilterStyles);

....

For some particular reason Typescript doesn't like the position.relative object. "Type 'string' is not assignable to type '"relative"
Everything else works expect "position".

I guess I need to add a return type to the tableFilterStyles function, maybe cssObjectByRuleNameOrGetCssObjectByRuleName?

Do you have any idea?

If I pass the style directly it works

const useStyles = makeStyles()( (theme: Theme) => ({
  root: {
    position: "relative"
  },
}));

Thanks!

The whole error message;

Argument of type '(theme: Theme) => { root: { position: string; }; checkboxes: { position: string; }; }' is not assignable to parameter of type 'Record<"root" | "checkboxes", CSSObject> | ((theme: Theme, params: void, classes: Record<never, string>) => Record<"root" | "checkboxes", CSSObject>)'.   Type '(theme: Theme) => { root: { position: string; }; checkboxes: { position: string; }; }' is not assignable to type '(theme: Theme, params: void, classes: Record<never, string>) => Record<"root" | "checkboxes", CSSObject>'.     Call signature return types '{ root: { position: string; }; checkboxes: { position: string; }; }' and 'Record<"root" | "checkboxes", CSSObject>' are incompatible.       The types of 'root.position' are incompatible between these types.         Type 'string' is not assignable to type '"relative" | "-moz-initial" | "inherit" | "initial" | "revert" | "unset" | "-webkit-sticky" | "absolute" | "fixed" | "static" | "sticky" | ("relative" | "-moz-initial" | "inherit" | ... 8 more ... | undefined)[] | Position[] | undefined'.

wrong sequence when generate storybook styles

we are using tss-react to work with storybook,

this is the preview.js file

import React from "react";
import { ThemeProvider } from "@mui/material/styles";
import { ThemeProvider as Emotion10ThemeProvider } from "emotion-theming";
import { Themes } from "../src/theme";
import { CssBaseline } from "@mui/material";

export const parameters = {
  actions: { argTypesRegex: "^on[A-Z].*" },
  controls: {
    matchers: {
      color: /(background|color)$/i,
      date: /Date$/i
    }
  },
  docs: {
    source: { type: "dynamic", excludeDecorators: true },
    inlineStories: false,
    iframeHeight: "700px"
  }
};

const withThemeProvider = (Story, context) => {
  return (
    <Emotion10ThemeProvider theme={Themes.Default}>
      <ThemeProvider theme={Themes.Default}>
        <CssBaseline />
        <Story {...context} />
      </ThemeProvider>
    </Emotion10ThemeProvider>
  );
};

export const decorators = [withThemeProvider];

in one of the component I override the chip style like this

const useStyles = makeStyles()(
  ({ palette }) => ({
    root: {
      border: "0.1rem solid",
      textAlign: "center",
      padding: "0 0.5rem",
      borderRadius: "0.2rem",
      whiteSpace: "nowrap",
      borderColor: "#ff0000",
      backgroundColor: "#ffffff",
      color: "#ff0000"
    }
  })
);

const CustomChip = ({
  text,
}: {
  text: string;
}) => {
  const { classes, cx } = useStyles();

  return (
    <Typography variant="body2" className={classes.root}>
      {text}
    </Typography>
  );
};

when it builds I got two css classes for that element:

.css-1vjo9lu {
    margin: 0px;
    font-size: 1.4rem;
    line-height: 1.71;
    color: rgb(38, 50, 56);
    letter-spacing: normal;
    font-weight: 400;
    font-family: "Cera Pro", sans-serif;
}

.tss-1ev1aua {
    border: 0.1rem
    solid rgb(0, 104, 200);
    text-align: center;
    padding: 0px 0.5rem;
    border-radius: 0.2rem;
    white-space: nowrap;
    background-color: rgb(255, 255, 255);
    color: rgb(0, 104, 200);
}

The first css class was the mui typography override and the second one was the makestyle override in the component.
The issue is the color should be the one in makestyle but it takes the typography color.

Please let me know where we did it wrong or this is a bug in storybook or tss-react.

Many thanks.

Can this be used in a single spa application?

I'm having issues using tss-react in a single spa environment. In my root app, I am able to get the UMD version of MUI and emotion (not been able to find an umd/systemjs version of this package or create one successfully):

        "@mui/material": "https://unpkg.com/@mui/[email protected]/umd/material-ui.production.min.js",
        "@emotion/react": "https://cdn.jsdelivr.net/npm/@emotion/[email protected]/dist/emotion-react.umd.min.js",
        "@emotion/styled": "https://cdn.jsdelivr.net/npm/@emotion/[email protected]/dist/emotion-styled.umd.min.js",

And they are being externalised by webpack in the sub app I am trying to use tss-react, In this app I have created a cache as the docs showed:

export const muiCache = createCache({
    'key': 'mui',
    'prepend': true,
  });

// region Component

const Theme: FunctionComponent<IThemeProps> = ({
  children,

  style
}) => {
  // handlers

  const theme = React.useMemo(() => {
    switch (style) {
      case Themes.Default:
      default:
        return DefaultTheme;
    }
  }, [style]);

  // render

  return (
    <CacheProvider value={muiCache}>
      <MuiThemeProvider theme={theme}>
        {children}
      </MuiThemeProvider>
    </CacheProvider>
  );
};

But MUI css always takes precedence over tss-react created styles and cannot seem to get it to work. Is there a way to get this to work?

Marged styles using with `cx` is defferent from using `styled`

First of all, thanks for creating a great library!

I'm migrating a project from using jss towards tss-react but I'm struggling with the different style order when using cx.

Codesandbox is here.

I have two components (Parent and Child), and I want to override the objectFit property of img tag from Parent.

const useStyles = makeStyles()(() => ({
  logo: {
    width: "100%",
    height: "53px",
    objectFit: "contain"
  }
}));

export const Parent = () => {
  const { classes } = useStyles();
  const src =
    "https://ichef.bbci.co.uk/news/640/cpsprodpb/17A21/production/_85310869_85310700.jpg";
  return (
    <>
      <Box width="200px" height="106px">
        <Child src={src} className={classes.logo} />
      </Box>
    </>
  );
};
import { makeStyles } from "tss-react/mui";

const useStyles = makeStyles()(() => ({
  img: {
    objectFit: "cover"
  }
}));

type Props = {
  className?: string;
  src: string;
};
export const Child = ({ className, src }: Props) => {
  const { classes, cx } = useStyles();
  return <img src={src} className={cx(className, classes.img)} />;
};

The style generated by cx is as follows.

.tss-5qt1p9-logo-img {
    width: 100%;
    height: 53px;
    object-fit: contain;
    object-fit: cover; // The style declared in the child component wins.
}

// Expected result
.tss-5qt1p9-logo-img {
    width: 100%;
    height: 53px;
    object-fit: cover;
    object-fit: contain;
}

Using styled instead of makeStyles get the expected result.

makeStyles in material-ui allows for passing a classes object

We've been making styles extendable by something like this:

export type UseStyles<T extends (...args: never[]) => unknown> = {
  classes?: Partial<ReturnType<T>['classes']>
}
const useStyles = makeStyles({ name: 'FixedFab' })((theme: Theme) => ({
  root: {
    width: '100%',
  },
}))

type ComponentProps = UseStyles<typeof useStyles>

function Component(props: ComponentProps) {
  const { classes } = useStyles(props)

  return <div className={classes.root}>asdf</div>
}

function ExtendingComponent() {
  return <Component classes={{ root: 'foo' }} />
}

It currently isn't possible to pass the classes prop, might this be something that can be added?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.