Skip to content

[Button] Migrate styles to emotion #24107

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 24 commits into from
Dec 24, 2020

Conversation

mnajdova
Copy link
Member

This PR migrates the Button's styles to emotion. In addition, it fixes #24045 - it's adding global class names for the default values of the size and color props.

@mui-pr-bot
Copy link

mui-pr-bot commented Dec 23, 2020

@material-ui/core: parsed: +0.74% , gzip: +0.56%
@material-ui/lab: parsed: +0.76% , gzip: +0.63%

Details of bundle changes

Generated by 🚫 dangerJS against 4205a69

let getByRole;

expect(() => {
const { getByRole: getByRoleLocal } = render(<Button startIcon={<span>icon</span>}>Hello World</Button>);
Copy link
Member Author

@mnajdova mnajdova Dec 23, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Emotion throws this error when ":first-child" is used. The error is shown when startIcon od endIcon is used.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it because emotion injects <style> elements in the page when SSR isn't configured?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly, but as we are following the advanced SSR configuration - https://emotion.sh/docs/ssr#advanced-approach we should be fine.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Managed to avoid the warning with 745e163. See comment - #24107 (comment)

<Button startIcon={<span>icon</span>}>Hello World</Button>,
);
getByRole = getByRoleLocal;
}).toErrorDev(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eps1lon am I using the toErrorDev correctly here? If I have this expected error in both tests as it's done currently, the tests are failing with https://app.circleci.com/pipelines/github/mui-org/material-ui/30240/workflows/2f2f8de6-1ef0-48e1-9962-9baa4d91821e/jobs/206347

If I remove the toErrorDev in the second test, then it is failing with

  19) <Button />
       should render a button with endIcon:
     Expected test not to call console.error()

If the warning is expected, test for it explicitly by using the toErrorDev() matcher.
Test location:
  D:\workspace\material-ui\packages\material-ui\src\Button\Button.test.js

console.error message:
  The pseudo class ":first-child" is potentially unsafe when doing server-side rendering. Try changing it to ":first-of-type".

Stack:
...

Should I clear the errors in between somewhere or?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is emotion deduplicating errors at the module level or something?

I wouldn't worry about it since we don't want to ship that warning anyway. SSR should not have any warnings or errors by default.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed the warning with 745e163 I've replaced the '& > *:first-child' selctor with '& > *:nth-of-type(1)' to avoid this warning. The result should be identical.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The result should be identical.

More or less 😁 https://codepen.io/oliviertassinari/pen/oNYBeEd

@mnajdova
Copy link
Member Author

Regarding the argos change - https://www.argos-ci.com/mui-org/material-ui/builds/6382 seems like we are fixing a previous issue with these changes

@mnajdova mnajdova merged commit ee64239 into mui:next Dec 24, 2020
@Jack-Works
Copy link
Contributor

I found it is a breaking change in our code. The problem is related to CSS priority. It seems like CSS is injected in the wrong order

@Jack-Works
Copy link
Contributor

The problem is that makeStyles inserted after the emotion styles which is wrong. (My styles are overwritten by emotion-based MUI styles)
image

@Jack-Works
Copy link
Contributor

How to make sure MUI styles (despite JSS or emotion) is always inserted before developer styles (despite JSS or emotion)? I can't find a workaround, is there an official guide for it? @oliviertassinari

@Jack-Works
Copy link
Contributor

Well I write a dirty workaround

const workaround = document.createElement('div')
document.body.insertBefore(workaround, null)
const shadowMap = new WeakMap<HTMLStyleElement, HTMLStyleElement>()
document.head.insertBefore = new Proxy(document.head.insertBefore, {
    apply(f, target, [dom, before]) {
        if (target === document.head && dom instanceof HTMLStyleElement) {
            if (shadowMap.has(before)) before = shadowMap.get(before)
            const meta = dom.getAttribute('data-meta')
            if (meta && meta.startsWith('makeStyle')) {
                workaround.appendChild(dom)
                const shadow = document.createElement('style')
                shadowMap.set(dom, shadow)
                Reflect.apply(f, target, [shadow, before])
                Object.defineProperty(dom, 'parentNode', {
                    get() {
                        return document.head
                    },
                })
                return dom
            }
        }
        return Reflect.apply(f, target, [dom, before])
    },
})

@mnajdova
Copy link
Member Author

@Jack-Works you need to use the <StylesProvider injectFirst> from @material-ui/core that will make sure that emotion styles are injected first. You can see this issue too #24186

@Jack-Works
Copy link
Contributor

<StylesProvider injectFirst>

I used it but it doesn't work. The problem here is both JSS and emotion can have user styles and MUI styles.

@mnajdova
Copy link
Member Author

I used it but it doesn't work. The problem here is both JSS and emotion can have user styles and MUI styles.

Yes, it cannot work if you use both style engines for overrides randomly. I would suggest if you plan to migrate to the new overrides technique, to do it step by step as we migrate the components. If you don't want to do it iterativly, I'd suggest keeping the JSS overrides and migrate in the end to emotion.

The problematic thing could be the theme overrides, as those are already using emotion. Is this the problem you are facing?

@Jack-Works
Copy link
Contributor

I'm not quite clear. My workaround works for me currently. I'll continue to use it until makeStyles moved to emotion.

@oliviertassinari
Copy link
Member

oliviertassinari commented Dec 31, 2020

I'll continue to use it until makeStyles moved to emotion.

Mind that we are removing makeStyles progressively (v6), there are no plans to port this API to emotion/sc.

@Jack-Works
Copy link
Contributor

Mind that we are removing makeStyles progressively (v6), there are no plans to port this API to emotion/sc.

Wait, all of our custom CSS are written in makeStyles, how can we migrate? that work is too heavy if it cannot be done with a codemod

@oliviertassinari
Copy link
Member

oliviertassinari commented Dec 31, 2020

@Jack-Works react-jss provides the same API, it will be the simplest path for developers that want a quick-win. But we won't drop the API before v6 so you have time.

@Jack-Works
Copy link
Contributor

Ok I found another problem. MenuItem is based on ButtonBase. And now the CSS order in our app causes problem:

makeStyles > any emotion style > rest JSS styles. Now CSS of built-in MenuItem style is overwritten by ButtonBase style which is wrong. I want to know which order is correct. Should I use makeStyles > rest JSS styles > any emotion styles?

@oliviertassinari
Copy link
Member

Should I use makeStyles > rest JSS styles > any emotion styles?

@Jack-Works It's what we recommend, so far. I have updated #24229 to mention it, in hindsight.

@zannager zannager added the component: button This is the name of the generic UI component, not the React module! label Jan 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: button This is the name of the generic UI component, not the React module!
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[IconButton] Improve size values
6 participants