<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: suvo</title>
    <description>The latest articles on DEV Community by suvo (@suvo).</description>
    <link>https://dev.to/suvo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F182338%2Ff37ae3ca-79fe-47a2-b03f-78eb0883b258.png</url>
      <title>DEV Community: suvo</title>
      <link>https://dev.to/suvo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/suvo"/>
    <language>en</language>
    <item>
      <title>Upgrade material ui 4 makeStyles and withStyles to material ui 5 using emotion JS with TS</title>
      <dc:creator>suvo</dc:creator>
      <pubDate>Fri, 17 Jun 2022 11:04:42 +0000</pubDate>
      <link>https://dev.to/suvo/upgrade-material-ui-4-makestyles-and-withstyles-to-material-ui-5-using-emotion-js-with-ts-3gc2</link>
      <guid>https://dev.to/suvo/upgrade-material-ui-4-makestyles-and-withstyles-to-material-ui-5-using-emotion-js-with-ts-3gc2</guid>
      <description>&lt;p&gt;I just came across a very nice blog when the upgrading to mui5 using emotion, it is nicely demonstrated &lt;a href="https://dev.to/atonchev/material-ui-5-the-easiest-way-to-migrate-from-makestyles-to-emotion-1i9l"&gt;here&lt;/a&gt;&lt;br&gt;
But there are a few things which are lacking in this implementation, i.e. TS support, how to handle withStyles Styled components.&lt;br&gt;
In this blog post I would mention those missing items.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Styles Root part is same as mentioned in the above mentioned blog.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The emotion theme declaration
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Theme as MuiTheme } from '@mui/material/styles'
import '@emotion/react'

declare module '@emotion/react' {
  // eslint-disable-next-line @typescript-eslint/no-empty-interface
  export interface Theme extends MuiTheme {}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Custom hook with TS support
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useMemo } from 'react'
import { css, CSSInterpolation } from '@emotion/css'
import { useTheme } from '@emotion/react'
import { Theme as MuiTheme } from '@mui/material/styles'

function useEmotionStyles(
  styles: () =&amp;gt; Record&amp;lt;string, CSSInterpolation&amp;gt;
): Record&amp;lt;string, ReturnType&amp;lt;typeof css&amp;gt;&amp;gt;

function useEmotionStyles(
  styles: (theme: MuiTheme) =&amp;gt; Record&amp;lt;string, CSSInterpolation&amp;gt;
): Record&amp;lt;string, ReturnType&amp;lt;typeof css&amp;gt;&amp;gt;

function useEmotionStyles&amp;lt;T&amp;gt;(
  styles: (theme: MuiTheme, props: T) =&amp;gt; Record&amp;lt;string, CSSInterpolation&amp;gt;,
  props: T
): Record&amp;lt;string, ReturnType&amp;lt;typeof css&amp;gt;&amp;gt;

function useEmotionStyles&amp;lt;T&amp;gt;(
  styles: (theme: MuiTheme, props?: T) =&amp;gt; Record&amp;lt;string, CSSInterpolation&amp;gt;,
  props?: T
): Record&amp;lt;string, ReturnType&amp;lt;typeof css&amp;gt;&amp;gt; {
  const theme = useTheme()
  return useMemo(() =&amp;gt; {
    const classes = styles(theme, props)
    const classNameMap = {}

    Object.entries(classes).forEach(([key, value]) =&amp;gt; {
      classNameMap[key] = css(value)
    })

    return classNameMap
  }, [props, styles, theme])
}

export default useEmotionStyles
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Here we have a overloaded hook for possible calls to the hook.&lt;/p&gt;

&lt;p&gt;A simple example would be&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type GridProps = { itemMargin: number | string }

const gridStyles = (theme: Theme, { itemMargin }: GridProps) =&amp;gt; ({
  container: {
    display: 'flex',
    justifyContent: 'center',
    alignItems: 'center',
    flexWrap: 'wrap' as CSSTypes.Property.FlexWrap,
    maxWidth: theme.breakpoints.values.md,
    [theme.breakpoints.down('sm')]: {
      maxWidth: 420
    },
    '&amp;amp;&amp;gt;*': {
      margin: itemMargin
    }
  }
})


const Component = () =&amp;gt; {
  const { container } = useEmotionStyles&amp;lt;GridProps&amp;gt;(gridStyles, { itemMargin })

  return (
    &amp;lt;Container className={container}&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to implement keyframes animations using emotion you can use this way.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { css, keyframes } from '@emotion/react'

const fadeIn = keyframes({
  '0%': {
    opacity: 0
  },
  '100%': {
    opacity: 1
  }
})
const styles = () =&amp;gt; ({
  text: css({
    display: 'flex',
    alignItems: 'center',
    animation: `${fadeIn} 2s`
  })
})

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Custom Hook for Styled Component (replacement for withStyles)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useMemo } from 'react'
import { Theme, useTheme } from '@emotion/react'
import { Theme as MuiTheme } from '@mui/material/styles'
import styled, { StyledComponent } from '@emotion/styled/macro'
import { CSSInterpolation } from '@emotion/css'
import {
  OverridableComponent,
  OverridableTypeMap
} from '@mui/material/OverridableComponent'

type ReturnedType&amp;lt;T extends ComponentType&amp;gt; = StyledComponent&amp;lt;
  JSX.LibraryManagedAttributes&amp;lt;T, React.ComponentProps&amp;lt;T&amp;gt;&amp;gt; &amp;amp; {
    theme?: Theme
  }
&amp;gt;

type ComponentType =
  | OverridableComponent&amp;lt;OverridableTypeMap&amp;gt;
  | React.JSXElementConstructor&amp;lt;JSX.Element&amp;gt;
  | ((props?: React.ComponentProps&amp;lt;any&amp;gt;) =&amp;gt; JSX.Element)

function useEmotionStyledComponent&amp;lt;T extends ComponentType&amp;gt;(
  styles: () =&amp;gt; Record&amp;lt;string, CSSInterpolation&amp;gt;,
  WrappedComponent: T
): ReturnedType&amp;lt;T&amp;gt;

function useEmotionStyledComponent&amp;lt;T extends ComponentType&amp;gt;(
  styles: (theme: MuiTheme) =&amp;gt; Record&amp;lt;string, CSSInterpolation&amp;gt;,
  WrappedComponent: T
): ReturnedType&amp;lt;T&amp;gt;

function useEmotionStyledComponent&amp;lt;T extends ComponentType, R&amp;gt;(
  styles: (theme: MuiTheme, props: R) =&amp;gt; Record&amp;lt;string, CSSInterpolation&amp;gt;,
  WrappedComponent: T,
  props: R
): ReturnedType&amp;lt;T&amp;gt;

function useEmotionStyledComponent&amp;lt;T extends ComponentType, R&amp;gt;(
  styles: (theme: MuiTheme, props?: R) =&amp;gt; Record&amp;lt;string, CSSInterpolation&amp;gt;,
  WrappedComponent: T,
  props?: R
): ReturnedType&amp;lt;T&amp;gt; {
  const theme = useTheme()
  return useMemo(() =&amp;gt; {
    const strings = styles(theme, props)

    return styled(WrappedComponent)(strings?.root)
  }, [WrappedComponent, props, styles, theme])
}

export default useEmotionStyledComponent

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To use this hook there must be only one root element in styles and all styles must be inside it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const StyledDialog = (props: DialogProps) =&amp;gt; {
  const Component = useEmotionStyledComponent&amp;lt;typeof Dialog&amp;gt;(
    (theme: Theme) =&amp;gt; ({
      root: {
        '&amp;amp; div.MuiDialog-container': {
          height: 'auto'
        },
        '&amp;amp; div.MuiDialog-paper': {
          alignItems: 'center',
          padding: theme.spacing(0, 2, 2, 2),
          minWidth: 240
        }
      }
    }),
    Dialog
  )
  return &amp;lt;Component {...props} /&amp;gt;
}

const MenuButton = (props: FabProps) =&amp;gt; {
  const StyledMenuButton = useEmotionStyledComponent&amp;lt;typeof Fab, FabProps&amp;gt;(
    (theme: Theme) =&amp;gt; ({
      root: {
        position: 'fixed',
        top: theme.spacing(2),
        left: theme.spacing(4)
      }
    }),
    Fab,
    props
  )
  return &amp;lt;StyledMenuButton {...props} /&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and use this component as a Styled component.&lt;/p&gt;

&lt;p&gt;With this two custom hooks you can replace the makeStyles and withStyles, if you have any questions, let me know.&lt;/p&gt;

</description>
      <category>mui5</category>
      <category>react</category>
      <category>emotion</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
