-
-
Notifications
You must be signed in to change notification settings - Fork 32.4k
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
[system] Use cx
instead of clsx
#32067
Conversation
@material-ui/core: parsed: +0.15% , gzip: +0.24% |
I realize that this PR might be a bit hard to grasp. Let me give you some additional technical details.
Best regards, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The changes more or less make sense (I would kill the fix for the media queries for now, but I already left a comment for it below, so we can continue the thread there).
Regarding the test-case, note that also plan to add a new API (coming from the @mui/base package), where we would have componentsProps.slot
and we would need to merge the className
prop from there in the correct order too (for the @mui/base components we don't plan to suppor the classes
prop, only the componentsProps
API, but for the @mui/material components I wouldn't kill the classes
API yet, to avoid numeros breaking changes again). Anyway, the fix would apply if the css
prop is used there too, so this fact shouldn't change much.
One scary thought is that we would need to update all components, which always comes with the risk of breaking something along the way. I am curious to hear what @siriwatknp's thoughts on the changes too.
packages/mui-styled-engine/src/cx.js
Outdated
} | ||
|
||
// https://github.com/garronej/tss-react/issues/27 | ||
const increaseSpecificityToTakePrecedenceOverMediaQueries = (() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks suspicious. I understand that it fixes an issue that was reported, but would it be better if this is reported inside emotion and we get a validation from the authors there that this is a bug? Increasing the specificity behind the scenes sounds scary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no 'bug' strictly speaking in the default cx
, it works as the specs says it work; but not as the users expect it to work.
Whether or not the increase of specificity to override media queries should be the default behavior of cx
is up to debate.
For TSS I had no choice but to implement the feature. Users were able to override media queries in v4 so I had to implement it or it would have made it very hard for some projects to upgrade to MUIv5.
I personally think that having this increase of specificity is a hard requirement for us.
If I have a button that, by default, is red for large screens and blue otherwise and I decide to make it white by passing a custom class. I expect my button to be white regardless of the screen size.
If I kill this feature MUI and TSS will end up with an avalanche of issues like "BUG: My custom style only applies on small screen size".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting, I've tried replicating this with pure CSS, and looks like it works as you are suggesting (if we assume the order of the classes in the CSS file I have would correspond with the order of the classes added in the cx
util): https://codepen.io/mnajdova/pen/VwyBEyX
@Andarist what do you think about this? I remember we once discussed this and you had a push back on it with some reason, but I don't remember what it was. I couldn't find the issue where it was discussed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting, I've tried replicating this with pure CSS, and looks like it works as you are suggesting (if we assume the order of the classes in the CSS file I have would correspond with the order of the classes added in the cx util): https://codepen.io/mnajdova/pen/VwyBEyX
Yeah, this is how it already works in Emotion because we just "flatten" everything into a single rule~. Media query doesn't increase the specificity anyhow so it "just works". However, at times this might be confusing because sometimes people only want to override the "base" declaration without affecting the media query one and there is no easy way to do this.
This might depend on how exactly you merge styles here, if you nest them etc. I would appreciate a codesandbox or something of the "broken" behavior in MUI - then I could perhaps comment further because right now I don't fully understand it as the basic case should work exactly like that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @Andarist, thank you for your involvement,
I'll fix you a sandbox ASAP
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean, I'd really love to be proven wrong but I dont see any other way to make it work but to use cx
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've successfully rendered this text as pink with just those two patches applied to your repro (this one):
Patch 1
diff --git a/node_modules/@mui/base/composeClasses/composeClasses.js b/node_modules/@mui/base/composeClasses/composeClasses.js
index 8d25ea4..2382b9c 100644
--- a/node_modules/@mui/base/composeClasses/composeClasses.js
+++ b/node_modules/@mui/base/composeClasses/composeClasses.js
@@ -3,17 +3,24 @@ export default function composeClasses(slots, getUtilityClass, classes) {
Object.keys(slots).forEach( // `Objet.keys(slots)` can't be wider than `T` because we infer `T` from `slots`.
// @ts-expect-error https://github.com/microsoft/TypeScript/pull/12253#issuecomment-263132208
slot => {
- output[slot] = slots[slot].reduce((acc, key) => {
+ const arr = slots[slot].reduce((acc, key) => {
+ if (key) {
+ acc.push(getUtilityClass(key));
+ }
+
+ return acc;
+ }, [])
+
+ slots[slot].forEach((key) => {
if (key) {
if (classes && classes[key]) {
- acc.push(classes[key]);
+ arr.push(classes[key]);
}
- acc.push(getUtilityClass(key));
}
+ })
- return acc;
- }, []).join(' ');
+ output[slot] = arr.join(' ');
});
return output;
}
Patch 2
diff --git a/node_modules/@mui/material/ButtonBase/ButtonBase.js b/node_modules/@mui/material/ButtonBase/ButtonBase.js
index f2333f8..407818e 100644
--- a/node_modules/@mui/material/ButtonBase/ButtonBase.js
+++ b/node_modules/@mui/material/ButtonBase/ButtonBase.js
@@ -321,7 +321,7 @@ const ButtonBase = /*#__PURE__*/React.forwardRef(function ButtonBase(inProps, re
const classes = useUtilityClasses(ownerState);
return /*#__PURE__*/_jsxs(ButtonBaseRoot, _extends({
as: ComponentProp,
- className: clsx(classes.root, className),
+ className: clsx(className, classes.root),
ownerState: ownerState,
onBlur: handleBlur,
onClick: onClick,
Take a look at the generated class name, now the color: pink;
is at the very bottom:
I don't advise actually using those patches, this is just a quick hack - the point is that this can be fixed without using cx
. I lack the knowledge about the internal composition of styles and "slots" to know how to actually this should be fixed.
And actually... the first patch isn't even needed here but I feel more comfortable with the logic included in it. OTOH, I don't entirely understand why the composeClasses
is inserting that root
class name there if it ends up being provided directly~ to the className
prop in the ButtonBase
anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for taking the time to prove your point.
I was stuck on the idea that:
clsx(classes.root, className) === `${classes.root} ${className}`
which I assumed to be equivalent to
`${classname} ${classes.root}`
I thought only cx
was able to enforce priority of one class over another.
Turns out I was wrong, I am not familiar enough with the inner working of emotion.
It’s good news.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What u are saying is correct but in this case the resulting className
is passed to Emotion and it can still handle decoding that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok thx, make sense!
FYI, this is on my radar. I might take a few days to get more context, will share my thought after that. |
Hi @mnajdova @siriwatknp, A lot have been said but the important pointers to understand this PR are in this message. I still think it's a problem for us that emotion, unlike vanilla CSS, assigns a higher specificity to rules within media queries but regardless, this effort is still undoubtedly worthy to be pursued. Best regards, UPDATE: |
@mnajdova Sure, I didn't give up in this, I just need to make time... |
Hi @mnajdova, |
This is great news! I am happy we can have a simple fix :) |
Hi @mnajdova,
Following our discussion there is a PR to show you what I have in mind.
You can run the test with:
Then access: http://localhost:3000/regression-Cx/Cx#no-dev
With this branch you'll get:
With
mui/material-ui#master
:Summary, for the record, of why I am doing this:
@emotion/react
to be used for writing custom-style. See PR#31825.@emotion/css
work as expected when user to write custom styles.I am looking forward to reading what you think of it.
Best regard,