Home  >  Q&A  >  body text

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>
P粉713866425P粉713866425442 days ago530

reply all(1)I'll reply

  • P粉852114752

    P粉8521147522023-08-28 00:51:49

    We eventually solved this problem by using Storybook argTypes.
    This solves the problem of missing values, but forces us to define them ourselves.

    There is a

    related question on Storybook's GH repository and I left a comment but haven't gotten any reply yet.

    We are using the keys of the MUI theme palette object and filtering out keys that we know are not actually colors:

    import { theme } from './theme';
    
    const paletteKeysThatAreNotColors = [
      'mode',
      'common',
      'grey', // 这虽然有一个颜色的名字,但实际上不是颜色 :shrug:
      'contrastThreshold',
      'getContrastText',
      'augmentColor',
      'tonalOffset',
      'text',
      'divider',
      'background',
      'action',
    ];
    
    const colors = Object.keys(theme.palette).filter(
      (colorKey) => !paletteKeysThatAreNotColors.includes(colorKey),
    );
    export default colors;

    reply
    0
  • Cancelreply