如何将自定义组件添加到 Mui 主题选项中以便覆盖它?

gin*_*93r 4 typescript reactjs material-ui

我已经搞乱了这一点,并且不断遇到类型错误,所以一定是我遗漏了一些东西。

我想要做的是创建自己的组件,然后能够覆盖主题的组件部分中的某些样式。根据我所读到的内容,我需要将组件添加到 Components 接口,这允许我将该自定义组件添加到 中的部分componentsThemeOptions但我找不到任何描述如何添加styleOverrides或自定义道具的内容,root例如bottom我可以将它们拉出来并将样式应用到组件。

// module aug
declare module '@mui/material/styles'{
   interface Components {MyComponent?:type of MyComponent}
}
// my component
type MyComponentProps = {prop1:string, prop2:string, styleOverrides?:{bottom:CSSProperties}
const MyComponent = ({prop1:string, props2:string}:MyComponentprops) => { return <> ... </> }
// theme options
const options = {components:MyComponent:{styleOverrides:{bottom:{color:'red'}}}}


Run Code Online (Sandbox Code Playgroud)

我收到一个错误type {styleOverrides?:bottom:{color:string} } is not comparable to {prop1:string, prop2:string, styleOverrides}:MyComponentProps. type {styleOverrides?:bottom:{color:string}} provides no match for the signature {prop1:string, prop2:string, styleOverrides}:MyComponentProps):Element

我尝试了几种不同的方法来格式化组件的 props,但 styleOverrides 总是返回空。

我在这里做错了什么?

Rya*_*ell 6

在您的模块增强示例中,您有,但您需要定义主题interface Components {MyComponent?:type of MyComponent}中将出现的类型的完整结构。MyComponent这意味着您需要指定defaultProps密钥和styleOverrides密钥的完整结构(variants如果您想支持该概念,但我不关心示例中的变体)。您可以在此处查看MUI 如何为其每个组件定义这一点。

defaultProps可以与组件的 props 具有相同的类型(MyComponentProps在我的示例中)。

关键styleOverrides是要复杂一些。您可以在此处查看MUI 如何为组件定义此类型,并且我的示例重新使用了 MUI 的OverridesStyleRules类型。该类型泛型的主要“输入”是允许的类键。我的示例在类型中定义了这一点MyComponentClassKey。为了对 MUI 方法进行建模,通常您将为最外面的组件定义一个“根”类键,然后为嵌套在其中的任何元素定义附加键(例如,在我的示例中为“底部”)。

下一步是利用组件中主题的defaultProps和。您可以在这里styleOverrides看到MUI 如何使用支持默认 props,我的示例使用相同的方法。为了支持样式覆盖,您可以使用 API传递第二个选项参数,该参数指示组件名称、插槽(即哪个 CSS 类键),以及确定样式覆盖的哪些部分适用于该插槽(并且它可能如果处理变体,请考虑道具/状态)。您可以在此处查看 MUI 中的示例。useThemePropsstyledoverridesResolver

下面是一个完整的工作示例:

import * as React from "react";
import {
  createTheme,
  ThemeProvider,
  Theme,
  styled,
  useThemeProps
} from "@mui/material/styles";
import { OverridesStyleRules } from "@mui/material/styles/overrides";

interface MyComponentProps {
  greetee?: string;
}
type MyComponentClassKey = "root" | "bottom";

const MyComponentRoot = styled("div", {
  name: "MyComponent",
  slot: "Root",
  overridesResolver: (props, styles) => styles.root
})(({ theme }) => {
  return {
    padding: 8
  };
});

const MyComponentBottom = styled("div", {
  name: "MyComponent",
  slot: "Bottom",
  overridesResolver: (props, styles) => styles.bottom
})(({ theme }) => {
  return {
    borderBottom: "1px solid black"
  };
});

const MyComponent = React.forwardRef(function MyComponent(
  inProps: MyComponentProps,
  ref
) {
  const props = useThemeProps({ props: inProps, name: "MyComponent" });
  const { greetee } = props;
  return (
    <MyComponentRoot>
      Hello {greetee}
      <MyComponentBottom />
    </MyComponentRoot>
  );
});

declare module "@mui/material/styles" {
  interface Components {
    MyComponent?: {
      defaultProps?: MyComponentProps;
      styleOverrides?: Partial<
        OverridesStyleRules<MyComponentClassKey, "MyComponent", Theme>
      >;
    };
  }
}

const theme = createTheme({
  components: {
    MyComponent: {
      defaultProps: {
        greetee: "World!"
      },
      styleOverrides: {
        root: {
          backgroundColor: "green",
          padding: 16
        },
        bottom: {
          borderColor: "purple"
        }
      }
    }
  }
});

export default function CustomStyles() {
  return (
    <ThemeProvider theme={theme}>
      <MyComponent />
    </ThemeProvider>
  );
}
Run Code Online (Sandbox Code Playgroud)

使用 styleOverrides 支持编辑自定义组件