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

[Bug or Question] Custom component variants via augmented module is lost when re-export #35743

Open
2 tasks done
totszwai opened this issue Jan 6, 2023 · 13 comments
Open
2 tasks done
Assignees
Labels
customization: theme Centered around the theming features docs Improvements or additions to the documentation support: question Community support but can be turned into an improvement typescript

Comments

@totszwai
Copy link

totszwai commented Jan 6, 2023

Duplicates

  • I have searched the existing issues

Latest version

  • I have tested the latest version

Steps to reproduce 🕹

It is kinda impossible to create a live example since it requires a customized MUI theme library.

TL;DR:
Following the official documentation to define the custom variants:
https://mui.com/material-ui/customization/theme-components/#creating-new-component-variants

It only works if the definition is being used within the same project. Re-exporting a defined MUI theme will not expose/re-export the custom variants... meaning if I have 10 different projects sharing a custom theme, ALL the declare module will need to be duplicated everywhere and is a maintenance nightmare.

There is a somewhat related issue #24323, is basically the father of what I am facing right now.

See Context below for long version.

Current behavior 😯

Extending the variants as well as the augmented module does not propagate to consumer apps.

Expected behavior 🤔

Extending the variants or the augmented module should propagate to the consumer apps.

Context 🔦

https://stackoverflow.com/questions/75022165/how-to-re-export-overridden-mui-theme-definitions

Long version:
I have a project that has all the MUI theme created, everything is working properly. Now I'd like to extract the defined theme out as a separate library (ex: @myproject/theme) such that I could share/redeploy it to various applications, that way, when the theme library gets updated, all downstream apps would inherit all the changes as well.

In most cases, it worked fine, however I am having trouble propagating the overridden variants with MUI. For example, I have the following variants defined for the Button:

declare module '@mui/material/Button' {
  interface ButtonPropsVariantOverrides {
    toolbar: true;
  }
}

export const myThemeOptions = {
  components: {
    MuiButton: {
      variants: [
        {
          props: { variant: 'toolbar' },
          style: { ... }
        }
      ]
    }
  }
}

export myLightTheme = createTheme(myThemeOptions, 'light'));

So the above code used to work just fine within the project (before splitting it out as a lib), and VSCode would be able to see the added toolbar variant. However, once the theme is moved to a new project/library (ex: @myproject/theme and then let's say I do, npm install -D @myproject/theme@0.0.1-alpha), it would no longer recognizing the added variants:

image
image

Your environment 🌎

Using:

    "@mui/material": "^5.10.13",
    "@mui/styled-engine-sc": "^5.10.6",
npx @mui/envinfo
  System:
    OS: Linux 5.15 Ubuntu 22.04.1 LTS 22.04.1 LTS (Jammy Jellyfish)
    CPU: (16) x64 Intel(R) Xeon(R) Silver 4108 CPU @ 1.80GHz
    Memory: 5.50 GB / 15.33 GB
    Container: Yes
    Shell: 5.1.16 - /bin/bash
  Binaries:
    Node: 14.19.2 - ~/.config/nvm/versions/node/v14.19.2/bin/node
    Yarn: 1.22.18 - ~/.config/nvm/versions/node/v14.19.2/bin/yarn
    npm: 6.14.17 - ~/.config/nvm/versions/node/v14.19.2/bin/npm
  Managers:
    Apt: 2.4.8 - /usr/bin/apt
    Maven: 3.6.3 - /usr/bin/mvn
    pip2: 20.3.4 - ~/.local/bin/pip2
    pip3: 22.0.2 - /usr/bin/pip3
  Utilities:
    Make: 4.3 - /usr/bin/make
    GCC: 11.3.0 - /usr/bin/gcc
    Git: 2.34.1 - /usr/bin/git
  Virtualization:
    Docker: 20.10.12 - /usr/bin/docker
  IDEs:
    Nano: 6.2 - /usr/bin/nano
    VSCode: 1.74.2 - /home/eto/.vscode-server/bin/e8a3071ea4344d9d48ef8a4df2c097372b0c5161/bin/remote-cli/code
    Vim: 8.2 - /usr/bin/vim
  Languages:
    Bash: 5.1.16 - /usr/bin/bash
    Java: 1.8.0_352 - /usr/bin/javac
    Perl: 5.34.0 - /usr/bin/perl
    Python: 2.7.18 - /usr/bin/python
    Python3: 3.10.6 - /usr/bin/python3
  Browsers:
    Chrome: 108.0.5359.124
    Chromium: 108.0.5359.124
@totszwai totszwai added the status: waiting for maintainer These issues haven't been looked at yet by a maintainer label Jan 6, 2023
@zannager zannager added support: question Community support but can be turned into an improvement customization: theme Centered around the theming features labels Jan 9, 2023
@siriwatknp
Copy link
Member

🤔 Somehow TypeScript does not pickup the module augmentation. I will try to reproduce it.

@siriwatknp siriwatknp added typescript and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Jan 10, 2023
@totszwai
Copy link
Author

totszwai commented Jan 10, 2023

@siriwatknp After hammering it over the weekend and today... I came up with an ugly workaround.

In the newly separated library, we have our own theme provider there, something like this, example: MyThemeProvider.ts:

import { ThemeProvider as MuiThemeProvider, StyledEngineProvider  } from '@mui/material';
import { ThemeProvider } from 'styled-components';

// ...

export const MyThemeProvider = (props) => {
  return (
    <StyledEngineProvider injectFirst>
       <MuiThemeProvider theme={...}>
         <ThemeProvider theme={...}>
           <SomeGlobalStyle />
           <SomeCssBaseline />
           {props.children}
         </ThemeProvider>
       </MuiThemeProvider>
    </StyledEngineProvider>
  );
};

In order to get the declare module to be read by the downstream project, I had to create this file (basically moving ALL of the declare module into it), typings.ts:

declare module '@mui/material/Button' {
  interface ButtonPropsVariantOverrides {
    toolbar: true;
  }
}

declare module '@mui/material/Badge' {
  interface BadgePropsVariantOverrides {
    notification: true;
  }
  interface BadgeClasses {
    notification: true;
  }
}

// others MUI components override

Once I have the above file, I go back to my MyThemeProvider.ts and put this in the file:

import '../mui/MuiThemeConfig/typings';

Once I built and installed the package... since the typings.ts is now baked into the MyThemeProvider via the import statement, when I load the provider in the downstream project, it would indirectly (hidden, auto load?) those declare module.

I don't know if this is the right way to do things and it seems a little hacky, and there is no official documentation from MUI on how to go with this. Please let me know whether this is ok (or official).

I feel like, I should be somehow defining some kind of @types/mytheme definition then somehow load/apply on top of MUI's, but I have no idea how to do/create a @types library specifically just to override other libs.

Thank you in advance!

@aluzinov
Copy link

aluzinov commented Jan 19, 2023

Try to put all declarations

declare module '@mui/material/Button' {
    interface ButtonPropsVariantOverrides {
        toolbar: true;
    }
}

in the same file there you have theme creation

export myLightTheme = createTheme(myThemeOptions, 'light'));

@siriwatknp siriwatknp added the docs Improvements or additions to the documentation label Jan 24, 2023
@siriwatknp
Copy link
Member

@totszwai Appreciate the issue and the workaround, I think we need to have a documentation guide on how to build UI library of top of Material UI or Joy UI.

@jaska120
Copy link

The module augmentation for library used to work on @mui/material": "^5.10.17 like following:

  1. Define module augmentation in a library package path of types/mui.d.ts
import type {} from "@mui/material/styles";

declare module "@mui/material/styles" {
  interface TypographyVariants {
    h1Bold: React.CSSProperties;
    h2Bold: React.CSSProperties;
  }

  interface TypographyVariantsOptions {
    h1Bold?: React.CSSProperties;
    h2Bold?: React.CSSProperties;
  }
}

declare module "@mui/material/Typography" {
  interface TypographyPropsVariantOverrides {
    h1Bold: true;
    h2Bold: true;
  }
}
  1. Import the module augmentation types from the library in a type root defined in tsconfig.json
import type {} from "@org/name-of-library/types/mui";

However, updating to @mui/material": "^5.11.6 seems to break the functionality. The TypographyPropsVariantOverrides does not contain the augmented types defined in the library. To me it seems like a regression in MUI.

@siriwatknp
Copy link
Member

@jaska120 Can you try this?

import type {} from "@mui/material/styles";
+import type {} from "@mui/material/Typography";

declare module "@mui/material/styles" {
  interface TypographyVariants {
    h1Bold: React.CSSProperties;
    h2Bold: React.CSSProperties;
  }

  interface TypographyVariantsOptions {
    h1Bold?: React.CSSProperties;
    h2Bold?: React.CSSProperties;
  }
}

declare module "@mui/material/Typography" {
  interface TypographyPropsVariantOverrides {
    h1Bold: true;
    h2Bold: true;
  }
}

@jaska120
Copy link

@jaska120 Can you try this?

import type {} from "@mui/material/styles";
+import type {} from "@mui/material/Typography";

declare module "@mui/material/styles" {
  interface TypographyVariants {
    h1Bold: React.CSSProperties;
    h2Bold: React.CSSProperties;
  }

  interface TypographyVariantsOptions {
    h1Bold?: React.CSSProperties;
    h2Bold?: React.CSSProperties;
  }
}

declare module "@mui/material/Typography" {
  interface TypographyPropsVariantOverrides {
    h1Bold: true;
    h2Bold: true;
  }
}

@siriwatknp Thanks, this works indeed! In the previous version of @mui/material": "^5.10.17, I didn't need to import Typography, but when adding it, the module augmentation works again in the library consumer.

@Grawl
Copy link

Grawl commented Feb 27, 2023

I can confirm this bug

And the workaround with import type {}

Before, broken:

declare module '@mui/material/Button' {
    interface ButtonPropsVariantOverrides {
        containedError: true;
    }
}

After, fixed:

import type {} from '@mui/material/Button';

declare module '@mui/material/Button' {
    interface ButtonPropsVariantOverrides {
        containedError: true;
    }
}

@noeszc-clara
Copy link

@siriwatknp What is the suggested way of working in a monorepo? I have a package with the theme and its overrides/augmentations, but when installing it in a new package in the same monorepo, TypeScript is lost and complains even though the component is visually taking the correct values from the theme.

@jaska120
Copy link

jaska120 commented Apr 3, 2023

@noeszc-clara We are importing the types from shared package successfully, which contains module augmentation e.g. with:

import type {} from "@org/shared/types/mui";

@peiche
Copy link

peiche commented Jun 13, 2023

@jaska120 How are you exporting the types?

@jaska120
Copy link

@jaska120 How are you exporting the types?

We are not exporting them from shared package, but importing them by accessing the file structure of shared package instead. We don't use import map in package.json, and therefore we can reference files relative to main export as I wrote in my previous reply. We are in monorepo environment.

I hope this answers your question.

@doiya46
Copy link

doiya46 commented Sep 28, 2023

I also get this issue when I use nx.dev to implement an UI for module federation (Wrap mui to a npm package). I see example of @totszwai in Stack Overflow use with @myproject/theme. When you build @myproject/theme and publish to npm it will includes some file .d.ts.

Example when use @myproject/theme to another react project:

ROOT/node_modules/@myproject/theme/overrides/components/button.d.ts

So in main.ts or any root file in your react project. Just use:

// Only use empty {} with no `.d.ts` in end of line
import type {} from '@myproject/theme/overrides/component/button'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
customization: theme Centered around the theming features docs Improvements or additions to the documentation support: question Community support but can be turned into an improvement typescript
Projects
None yet
Development

No branches or pull requests

9 participants