Skip to content
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

DT-1110: Migrate away from @mui/styles Part 1 #1730

Merged
merged 38 commits into from
Jan 14, 2025

Conversation

snf2ye
Copy link
Contributor

@snf2ye snf2ye commented Jan 3, 2025

Background

We must discontinue use of @mui/styles in order to migrate from React 17 to 18. (source)

@mui/styles was deprecated with the release of MUI Core v5 in late 2021. It is not compatible with React.StrictMode or React 18+, and it will not be updated. Please use @mui/system instead.

There is guide for this migration here: https://mui.com/material-ui/migration/migrating-from-jss

Options considered:

  • sx prop + styled components from @mui/matertial/styles - From migration guide - "We recommend sx API over styled for creating responsive styles or overriding minor CSS". We can use styled components for components with a lot of styles (4+) and for styling that is reused.
  • tss-react - Easiest change, but still would require using copilot per component. It would be more of a lateral step.

This PR uses the first option and uses the sx prop alongside styled components. Given that we have to touch every file manually and I think we can utilize copilot for the bulk of the work, I would prefer to do the harder change rather than the lateral change.

Steps for Upgrades

Pre-checks:

  • Review the styles listed at the beginning of the file. Are they all referenced in the component? (Apparently if there are styles that don't match up to a component, it will try to infer where the component with those styles should go and add it)
  1. Run copilot command, specifically in VSCode with Claude 3.5 Sonnet.

Can you migrate this component away from using JSS and references to '@mui/styles'? We want to instead use a combination of inline styling with the "sx" prop on Material UI components and styled components from @mui/material/styles.

Let me explain something about how our code is set up: In the existing code, all of the styles currently live in a "styles" object. It contains a list of classes each with their own styles.

Consider the following example:

const styles = (theme: CustomTheme) =>
  createStyles({
    pageRoot: {
      padding: '16px 24px',
      display: 'flex',
      flexDirection: 'column',
      height: '100%',
    },
    jadeTableSpacer: {
      paddingBottom: theme.spacing(12),
    }
});

pageRoot and jadeTableSpacer are classes that we reference in the component. pageRoot has 4 styles and jadeTableSpacer has 1 style. We don't want to use inline styling with the sx for classes that have more than 3 styles, so we want to handle these two classes in different manners. Since pageRoot has 4 styles, we want to use a styled component. Since jadeTableSpacer only has 1 style, we want to use the inline styling with an "sx" prop. We can evaluate other style classes with this same rule: if there are 3 or fewer styles, use the "sx" prop. If there are more than 3 styles, then convert to a styled component.

When using the "sx" prop, then we must use the material UI version of the component (e.g. Box instead of div and add an import statement at the beginning of the file). We must also switch any css references of direct numbers to include px (e.g. '10px' instead of 10)

  1. Apply prettier
  2. Review UI and code generated
  3. Compare UI/styling between local UI and dev

Common Issues

  • It doesn't handle theme changes well - 30ca7c2

What step is the copilot upgrade taking? (example output from copilot)

I'll help migrate the SnapshotAccessRequestTable from JSS to use styled components and sx props.

Let's analyze the styles:

  1. More than 3 styles:
  • overlaySpinner (6 styles)
  • openButton (7 styles)
  1. Convert to sx props:
  • jadeLink (1 style with theme mixin)

Key changes made:

  • Removed withStyles HOC and styles object
  • Added styled import from @mui/material/styles
  • Created styled components for complex styles: OverlaySpinner for loading overlay, RequestButton for the request name button, Converted jadeLink to use sx prop with theme mixin
  • Removed classes prop and ClassNameMap interface
  • Added Box component for styled span
  • Simplified component exports
  • Maintained all functionality while modernizing the styling approach

The component maintains the same styling and behavior while using modern MUI patterns.

Example
Before with @mui/styles

const styles = (theme: CustomTheme) => ({
  wrapper: {
    display: 'flex',
    justifyContent: 'center',
    marginTop: '1em',
  }
);
....
 <div className={classes.wrapper}>
...
</div>

With sx prop

 <Box sx={{ display: 'flex', justifyContent: 'center', marginTop: '1em' }}>
...
</Box>

##TODO - add example for styled component

TODO - add more notes about nuances of the changes from mui

Components Impacted in this PR

Updated screenshots as of 01-11-2024

  1. HomeView and 2) DatasetView
image
  1. JobView
image
  1. SnapshotView
image
  1. DatasetOverview and 6) DatasetOverviewPanel
image image
  1. DatasetAccess and 8) UserList
image
  1. SnapshotAccessRequestTable
image

Copy link

cypress bot commented Jan 3, 2025

jade-data-repo-ui    Run #3968

Run Properties:  status check passed Passed #3968  •  git commit b1f312d48f ℹ️: Merge 335319e60d471feac187e62d8e4f6dcac6e23315 into 87a9b411a00dfd929b658a2554c6...
Project jade-data-repo-ui
Branch Review sh/dt-1110-remove-mui-styles-part1
Run status status check passed Passed #3968
Run duration 02m 56s
Commit git commit b1f312d48f ℹ️: Merge 335319e60d471feac187e62d8e4f6dcac6e23315 into 87a9b411a00dfd929b658a2554c6...
Committer Shelby Holden
View all properties for this run ↗︎

Test results
Tests that failed  Failures 0
Tests that were flaky  Flaky 0
Tests that did not run due to a developer annotating a test with .skip  Pending 0
Tests that did not run due to a failure in a mocha hook  Skipped 0
Tests that passed  Passing 17
View all changes introduced in this branch ↗︎

@snf2ye snf2ye force-pushed the sh/dt-1110-remove-mui-styles-part1 branch from e71a9d8 to c83ff6d Compare January 3, 2025 16:24
Comment on lines 247 to 278
sx={{
top: '112px',
bottom: '0px',
flexShrink: 0,
height: 'initial',
zIndex: 10,
minWidth: 300,
width: '40%',
position: 'absolute',
transition: () =>
theme.transitions.create('width', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.enteringScreen,
}),
'&.drawerClose': {
transition: () =>
theme.transitions.create('width', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
overflowX: 'hidden',
width: '0px',
minWidth: '0px',
[theme.breakpoints.up('sm')]: {
width: '0px',
},
Copy link
Contributor Author

@snf2ye snf2ye Jan 6, 2025

Choose a reason for hiding this comment

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

For more complicated styles like this, it may make sense to pull it into a styled component to help with code readability. But, this styling is still only used in one spot so I'm a torn over which is better (leave as sx prop vs. pull into styled component)

Copy link
Contributor

Choose a reason for hiding this comment

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

Since the refactoring is being done in stages, we can always pull this out into a separate style in the future.

@snf2ye snf2ye force-pushed the sh/dt-1110-remove-mui-styles-part1 branch 2 times, most recently from b1577c1 to 5ac0898 Compare January 7, 2025 21:34
@snf2ye snf2ye marked this pull request as ready for review January 8, 2025 13:55
@snf2ye snf2ye requested a review from a team as a code owner January 8, 2025 13:55
@snf2ye snf2ye requested review from rushtong and s-rubenstein and removed request for a team January 8, 2025 13:55
Copy link
Contributor

@fboulnois fboulnois left a comment

Choose a reason for hiding this comment

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

One main question, otherwise lgtm:

fontSize: '14px',
lineHeight: '22px',
fontWeight: '600',
color: 'primary.main',
Copy link
Contributor

Choose a reason for hiding this comment

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

Do these need to import theme from 'modules/theme'; and use theme.palette.primary.main instead like in src/components/DatasetView.tsx? If so, a number of components in this PR have this issue with color.

Copy link
Contributor Author

@snf2ye snf2ye Jan 8, 2025

Choose a reason for hiding this comment

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

Great question - I believe it is correct as is - Here's the documentation and the basic example has something very similar. We have "ThemeProvider" set up in the index, so the theme should be available to all components in the repo.

I'm possibly not referencing the theme correctly in DatasetView, but I wasn't quite sure how to do the expansion of the custom mixin.

},
);
return (
<Box sx={{ display: 'flex', justifyContent: 'center', marginTop: '1em' }}>
Copy link
Contributor

@s-rubenstein s-rubenstein Jan 8, 2025

Choose a reason for hiding this comment

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

If you want to reduce the diff here, and keep the object abstractions, this could be <Box sx={styles(theme).wrapper}> just as easily, and that way we keep our object abstractions while moving to the sx property?

To do this you would need to have styles be a raw object rather than a method (or call it once if we have a theme we could pass), but that should be okay

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's a really interesting idea, and I'm torn about it.
I think I'm less interested in making the diff smaller (copilot is doing the heavy lifting here to move things around), and want to think about how we want this to look long term. We often use existing code as a model for new code, so what do we want our best practices to be going forward?
I think I generally like the sx prop styles to be inline for a small set of changes, but we may want to consider using styled components more frequently to keep a pseudo object abstraction. I could actually build that into the copilot request - like "if there are more than 3 css styles, use a styled component instead of the sx prop".

Copy link
Contributor

Choose a reason for hiding this comment

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

That's my ultimate preference as well. 3 css styles is fine for inline, more gets bulky. I also think if we have a often reused width or something - with lots of constants reused, that I'd abstract.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Turns out that its tricky to get copilot to handle these two cases 🫠 It's not great at counting, apparently (It would catch some components with >3 styles, but not all).
We may have to do this in two steps (convert to sx prop or styled and then move the rest). I think I'm also having better luck with a newer gpt model in vs code (as opposed to intellij).

Copy link
Contributor

@rushtong rushtong left a comment

Choose a reason for hiding this comment

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

👍🏽

@snf2ye snf2ye force-pushed the sh/dt-1110-remove-mui-styles-part1 branch from 80598fd to 3a12537 Compare January 8, 2025 17:23
import DatasetTable from './table/DatasetTable';

import { DatasetRoles } from '../constants';

const styles = (theme: CustomTheme) => ({
wrapper: {
Copy link
Contributor

Choose a reason for hiding this comment

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

so just a general comment, this is moving us away from having separate style objects and towards inline styling. Is that the principle that we want to follow? I thought that separate objects were preferred because they are reusable and easier to maintain. But maybe that isn't the case. What are the guidelines from the UI working group on this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My goal in this PR is to use best practices for Material UI. We're moving from an old Material UI concept (@mui/styles), to a new one - sx prop + styled components. I don't think Terra UI uses Material UI, but I'm glad to still run this by them.

RE: separate objects that are reusable/easier to maintain: We should use styled components for this case. The "sx prop" should be used for styles that are used in one spot, styled components are reusable and then we use the global theme to share styling variables. I think this is a helpful guide here: https://mui.com/material-ui/customization/how-to-customize

fontSize: '14px',
lineHeight: '22px',
fontWeight: '600',
color: 'primary.main',
Copy link
Contributor

Choose a reason for hiding this comment

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

just curious, why is this not a styled component? Is something like this just a symptom of copilot not counting very well?

Copy link
Contributor Author

@snf2ye snf2ye Jan 14, 2025

Choose a reason for hiding this comment

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

Yeah, it really seems like copilot can't compare numbers all that well 😭

Here's copilot's notes from this update:

I'll help migrate the DatasetOverviewPanel from JSS to use styled components and sx props. Let's analyze the styles:

  1. More than 3 styles:
  • drawer (5 styles)
  • drawerOpen (4 styles with transitions)
  • drawerClose (5 styles with transitions and breakpoints)
  1. Convert to sx props:
  • root (1 style)
  • helpOverlayCloseButton (1 style)
  • helpText (1 style)
  • drawerPosition (1 style)
  • header (4 styles)
  • expandIcon (1 style)
  • noRelationships (3 styles)
  • divider (2 styles)
  • fullViewButton (1 style)
  • fullViewText (1 style)

Key changes made:

  • Removed withStyles HOC and styles object
  • Added styled import from @mui/material/styles
  • Created StyledDrawer component for complex drawer styling
  • Converted all simple styles to sx props
  • Added Box component as root container
  • Removed classes prop and references
  • Simplified component exports
  • Used theme spacing units where appropriate
  • Maintained all functionality while modernizing the styling approach
  • The component maintains the same styling and behavior while using modern MUI patterns.

.

It clearly notes that the "header" class has 4 styles and notes that the first group is for components with more than 3 styles, but still groups it with the sx props. So, I really don't understand why it groups it with the sx props group. But, it still does catch the more complex styles and generally seems to move the components with lots of styles to styled components. I think as long as it is loosely following this rule, then it is okay.

Copy link
Contributor

@rjohanek rjohanek left a comment

Choose a reason for hiding this comment

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

I think this looks good overall, just a couple non-blocking questions

Copy link
Contributor

@s-rubenstein s-rubenstein left a comment

Choose a reason for hiding this comment

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

I am seeing a lot of p or m as a shorthand for margin/padding - I don't know if that is an affordance that material provides, but it seems less readable to me than the CSS property - I would rather we stick with the CSS property versions? I commented a few examples

fontSize: '1.5rem',
},
});
const RootContainer = styled(Box)({
Copy link
Contributor

Choose a reason for hiding this comment

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

I really like this approach - very clean.

@snf2ye snf2ye force-pushed the sh/dt-1110-remove-mui-styles-part1 branch 2 times, most recently from 7a61899 to 6b51734 Compare January 14, 2025 16:24
@snf2ye
Copy link
Contributor Author

snf2ye commented Jan 14, 2025

I am seeing a lot of p or m as a shorthand for margin/padding - I don't know if that is an affordance that material provides, but it seems less readable to me than the CSS property - I would rather we stick with the CSS property versions? I commented a few examples

@s-rubenstein Yeah, this is specifically a feature of the sx prop for mui components: https://mui.com/system/getting-started/the-sx-prop/#spacing
I'm glad to switch these back to the CSS property. If we were really all-in on mui styling, it seems possible that these shortcuts could help with readability of bigger sx props. But, css properties are more readable for me.
Copilot was randomly deciding between using the shorthands and the regular css properties, so we'll have to watch out for this happening in future PRs. We can add a note in the copilot prompt.

Copy link
Contributor

@s-rubenstein s-rubenstein left a comment

Choose a reason for hiding this comment

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

LGTM - there are a number of places where we have 14px vs 14 for styles, but tbh I think that's an existing issue and out of scope to unify to one or the other here.

Command used:
Can you migrate this component away from using JSS and references to '@mui/styles' and instead use '@mui/system'? Please use the "sx" prop wherever possible instead of "styled". If you need to use the "sx" prop, then we must use the material UI version of the component (e.g. Box instead of div and add an import statement at the beginning of the file). We must also switch any css references of direct numbers to include px (e.g. '10px' instead of 10)
Im not sure where it got that maxwidth from

Update references
- title isn't used anywhere

add comma
snf2ye added 22 commits January 14, 2025 14:00
I think we need to use @mui/material/styles instead?

This is what is referenced in docs: https://mui.com/material-ui/customization/theming/

remove @mui/styles references from theme
Line was still showing up in middle of the page
…heme type was quite a pain

- I feel pretty confident that we want to use @mui/material/styles since this is how we define our custom theme
All it is doing is setting the width at 100%. Let's move that to an sx prop rather than a shared component/theme. Let's make this clear what styles we're applying when it is just a simple 100% width.
@snf2ye snf2ye force-pushed the sh/dt-1110-remove-mui-styles-part1 branch from f5651e9 to ad32ffd Compare January 14, 2025 19:00
@snf2ye
Copy link
Contributor Author

snf2ye commented Jan 14, 2025

LGTM - there are a number of places where we have 14px vs 14 for styles, but tbh I think that's an existing issue and out of scope to unify to one or the other here.

Oh, good catch - That's something I paid attention to in the first round, but forgot about in the second round. It's actually important that we pay attention to this for spacing styles because of how mui does theme. And, unfortunately, it looks different for styled vs. sx prop 🫠 I'll go back through the changes again.

sx Prop spacing

With the sx prop, if you leave off "px", then it defaults to it theme spacing, which multiples the value by 8px. So, sx={margin: 2} is actually equivalent to sx={margin: '16px'}
image

Styled spacing

With styled components, you have to add theme.spacing(2) to use their multiplier shorthand.
styled component:

  • margin: 2 = margin: 2px
  • margin: theme.spacing(2) = margin: 16px = margin: 16
image

Other sx prop styles

To make things even more confusing, these rules appear to not be consistent across sx props. Like sizing (so, height, width, etc.) does NOT default to the theme sizing, but grid does. These guides on sx prop and styled components are vital to getting through these changes.
https://mui.com/system/getting-started/the-sx-prop
https://mui.com/system/styled/

@snf2ye snf2ye merged commit 16254bc into develop Jan 14, 2025
9 checks passed
@snf2ye snf2ye deleted the sh/dt-1110-remove-mui-styles-part1 branch January 14, 2025 19:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants