jose.gp
jose.gp

Reputation: 132

Split MUI theme into separate files

In my Next.js project, I have this index.ts in src/theme folder.

'use client'; // necessary for MUI to work with nextjs (SSR)
import { createTheme } from '@mui/material/styles';
import { typography } from './typography';
import { palette } from './palette';

const theme = createTheme({
  palette,
  typography,
  components: {
    MuiButton: {
      styleOverrides: {
        root: {
          borderRadius: 8,
        }
      },
      variants: [
        {
          props: { variant: 'primary' },
          style: {
            backgroundColor: '#FFCB3C',
            color: '#1A334D',
            '&:hover': {
              backgroundColor: '#FFAA01',
            },
          },
        },
        {
          props: { variant: 'complementaryPrimary' },
          style: {
            backgroundColor: '#a09a88',
            color: '#ffffff',
            '&:hover': {
              backgroundColor: '#FFAA01',
            },
          },
        }
      ],
    }
  },
});

export default theme;

This works without problem and I create new variants.I am also importing palette and typography from their own .ts files.

The problem is that if I want to refactor this and create a buttonStyles.ts file

const buttonStyles = {
  MuiButton: {
    styleOverrides: {
      root: {
        borderRadius: 8,
      }
    },
    variants: [
      {
        props: { variant: 'primary' },  // Ensure this is correctly recognized by TS as augmented
        style: {
          backgroundColor: '#FFCB3C',
          color: '#1A334D',
          '&:hover': {
            backgroundColor: '#FFAA01',
          },
        },
      },
      {
        props: { variant: 'complementaryPrimary' },  // Ensure this is correctly recognized by TS as augmented
        style: {
          backgroundColor: '#a09a88',
          color: '#ffffff',
          '&:hover': {
            backgroundColor: '#FFAA01',
          },
        },
      }
    ],
  },
}

export default buttonStyles;

and import it into index.ts file:

'use client'; // necessary for MUI to work with nextjs (SSR)
import { createTheme } from '@mui/material/styles';
import buttonStyles from './buttonStyles';
import { typography } from './typography';
import { palette } from './palette';

const theme = createTheme({
  palette,
  typography,
  components: {
    ...buttonStyles,
  },
});

export default theme;

It keeps failing with this error

Type '{ MuiButton: { styleOverrides: { root: { borderRadius: number; }; }; variants: { props: { variant: string; }; style: { backgroundColor: string; color: string; '&:hover': { backgroundColor: string; }; }; }[]; }; }' is not assignable to type 'Components<Omit<Theme, "components">>'.
  The types of 'MuiButton.variants' are incompatible between these types.
    Type '{ props: { variant: string; }; style: { backgroundColor: string; color: string; '&:hover': { backgroundColor: string; }; }; }[]' is not assignable to type '{ props: Partial<ButtonProps> | ((props: Partial<ButtonProps> & { ownerState: Partial<ButtonProps>; }) => boolean); style: Interpolation<...>; }[]'.
      Type '{ props: { variant: string; }; style: { backgroundColor: string; color: string; '&:hover': { backgroundColor: string; }; }; }' is not assignable to type '{ props: Partial<ButtonProps> | ((props: Partial<ButtonProps> & { ownerState: Partial<ButtonProps>; }) => boolean); style: Interpolation<...>; }'.
        Types of property 'props' are incompatible.
          Type '{ variant: string; }' is not assignable to type 'Partial<ButtonProps> | ((props: Partial<ButtonProps> & { ownerState: Partial<ButtonProps>; }) => boolean)'.
            Type '{ variant: string; }' is not assignable to type 'Partial<ButtonProps>'.
              Types of property 'variant' are incompatible.
                Type 'string' is not assignable to type 'OverridableStringUnion<"text" | "outlined" | "contained", ButtonPropsVariantOverrides> | undefined'.ts(2322)
(property) ThemeOptions.components?: Components<Omit<Theme, "components">> | undefined

I am not sure why if I write it in index.ts it works and if not, it doesn't. I tried different ways to import it:

components: {
    ...buttonStyles,
  },

or

components: {
    ...buttonStyles.MuiButton,
  },

and I get this

Type '{ styleOverrides: { root: { borderRadius: number; }; }; variants: { props: { variant: string; }; style: { backgroundColor: string; color: string; '&:hover': { backgroundColor: string; }; }; }[]; }' has no properties in common with type 'Components<Omit<Theme, "components">>'.ts(2559)
(property) ThemeOptions.components?: Components<Omit<Theme, "components">> | undefined

or

  components: {
    MuiButton: {...buttonStyles},
  },

after updating buttonStyles.ts like this

const buttonStyles = {
  styleOverrides: {
    root: {
      borderRadius: 8,
    }
  },
  variants: [
    {
      props: { variant: 'primary' },  // Ensure this is correctly recognized by TS as augmented
      style: {
        backgroundColor: '#FFCB3C',
        color: '#1A334D',
        '&:hover': {
          backgroundColor: '#FFAA01',
        },
      },
    },
    {
      props: { variant: 'complementaryPrimary' },  // Ensure this is correctly recognized by TS as augmented
      style: {
        backgroundColor: '#a09a88',
        color: '#ffffff',
        '&:hover': {
          backgroundColor: '#FFAA01',
        },
      },
    }
  ],

}

export default buttonStyles;

and I get this error:

Type '{ styleOverrides: { root: { borderRadius: number; }; }; variants: { props: { variant: string; }; style: { backgroundColor: string; color: string; '&:hover': { backgroundColor: string; }; }; }[]; }' is not assignable to type '{ defaultProps?: Partial<ButtonProps> | undefined; styleOverrides?: Partial<OverridesStyleRules<keyof ButtonClasses, "MuiButton", Omit<Theme, "components">>> | undefined; variants?: { ...; }[] | undefined; }'.
  Types of property 'variants' are incompatible.
    Type '{ props: { variant: string; }; style: { backgroundColor: string; color: string; '&:hover': { backgroundColor: string; }; }; }[]' is not assignable to type '{ props: Partial<ButtonProps> | ((props: Partial<ButtonProps> & { ownerState: Partial<ButtonProps>; }) => boolean); style: Interpolation<...>; }[]'.
      Type '{ props: { variant: string; }; style: { backgroundColor: string; color: string; '&:hover': { backgroundColor: string; }; }; }' is not assignable to type '{ props: Partial<ButtonProps> | ((props: Partial<ButtonProps> & { ownerState: Partial<ButtonProps>; }) => boolean); style: Interpolation<...>; }'.
        Types of property 'props' are incompatible.
          Type '{ variant: string; }' is not assignable to type 'Partial<ButtonProps> | ((props: Partial<ButtonProps> & { ownerState: Partial<ButtonProps>; }) => boolean)'.
            Type '{ variant: string; }' is not assignable to type 'Partial<ButtonProps>'.
              Types of property 'variant' are incompatible.
                Type 'string' is not assignable to type 'OverridableStringUnion<"text" | "outlined" | "contained", ButtonPropsVariantOverrides> | undefined'.ts(2322)
(property) Components<Omit<Theme, "components">>.MuiButton?: {
    defaultProps?: Partial<ButtonProps> | undefined;
    styleOverrides?: Partial<OverridesStyleRules<keyof ButtonClasses, "MuiButton", Omit<Theme, "components">>> | undefined;
    variants?: {
        ...;
    }[] | undefined;
} | undefined

Around Stack Overflow there is another question about theme organization:

How to split MUI v5 theme into separate files by theme options?

but it does not answer my problem. How should I update my code?

Upvotes: 0

Views: 82

Answers (1)

jose.gp
jose.gp

Reputation: 132

Had to explicitly set the type:

import { Components } from '@mui/material/styles';

export const buttonStyles: Components = {

now it works

const theme = createTheme({
  palette,
  typography,
  components: {
    ...buttonStyles,
  }
});

Upvotes: 0

Related Questions