Theme with custom color missing in Storybook control value - Problem solution for Material UI, TypeScript and Storybook
<p>I'm using React 18, TypeScript, MUI 5 and Storybook 6.5. </p><p>
I'm trying to add a custom color to my MUI theme and have it reflected in the Storybook's dropdown options for the color property of my Button component, but it doesn't seem to work. </p><p>
I followed the module augmentation guide in the MUI documentation, and when hardcoded, the MaterialButton component does accept "myCustomColor", but Storybook doesn't show it in the dropdown selection for the color property. </p><p>
I would appreciate any guidance/ideas.</p>
<p>目前我的文件如下:</p>
<pre class="brush:php;toolbar:false;">// src/styles/theme.ts
import { createTheme } from "@mui/material";
export const theme = createTheme({
palette: {
myCustomColor: {
main: '#ff5555',
contrastText: '#fff',
},
},
});</pre>
<pre class="brush:php;toolbar:false;">// src/styles/expanded-theme.ts
import '@mui/material/styles';
import '@mui/material/Button';
declare module '@mui/material/styles/createPalette' {
interface Palette {
myCustomColor: Palette['primary'];
}
interface PaletteOptions {
myCustomColor?: PaletteOptions['primary'];
}
}
declare module '@mui/material/Button/Button' {
interface ButtonPropsColorOverrides {
myCustomColor: true;
}
}</pre>
<pre class="brush:php;toolbar:false;">// src/components/Button.tsx
import React from "react";
import { Button as MaterialButton } from "@mui/material";
import type { ButtonProps as MuiButtonProps } from "@mui/material";
export interface ButtonProps extends MuiButtonProps {
label: string;
onClick: React.MouseEventHandler<HTMLButtonElement>;
}
export const Button = (props: ButtonProps) => {
const { label } = props;
return <MaterialButton {...props}>{label}</MaterialButton>;
};</pre>
<pre class="brush:php;toolbar:false;">// .storybook/preview.js
import { CssBaseline, ThemeProvider } from "@mui/material";
import { Story } from "@storybook/react";
import { theme } from "../src/styles/theme";
export const parameters = {
actions: { argTypesRegex: "^on[A-Z].*" },
controls: {
expanded: true, // Adds the description and default columns
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
};
export const withMuiTheme = (Story) => {
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<Story />
</ThemeProvider>
);
};
export const decorators = [withMuiTheme];</pre>
<pre class="brush:php;toolbar:false;">// .storybook/main.js
module.exports = {
stories: ["../src/**/*.stories.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
addons: [
"@storybook/addon-links",
"@storybook/addon-essentials",
"@storybook/addon-interactions",
],
framework: "@storybook/react",
core: {
builder: "@storybook/builder-webpack5",
},
typescript: {
check: false,
checkOptions: {},
reactDocgen: "react-docgen-typescript",
reactDocgenTypescriptOptions: {
allowSyntheticDefaultImports: false, // speeds up storybook build time
esModuleInterop: false, // speeds up storybook build time
shouldExtractLiteralValuesFromEnum: true, // makes union prop types like variant and size appear as select controls
shouldRemoveUndefinedFromOptional: true, // makes string and boolean types that can be undefined appear as inputs and switches
savePropValueAsString: true,
propFilter: (prop) => (prop.parent ? !/node_modules/.test(prop.parent.fileName) : true),
},
},
};</pre></p>