如何在Material-UI中保留禁用按钮的背景颜色?

7

我希望更改Material-UI中禁用状态下Button组件的全局样式。但问题是,我无法保持按钮的原始颜色方案。

考虑以下按钮:

<Button color="secondary" disabled={isLoading}>Create Account</Button>

现在默认情况下,Mui-disabled将会附加到此按钮上。它的colorbackground-color取自theme.palatte.action属性。因此,这个禁用的按钮将具有以下CSS:

color: rgba(0,0,0,0.26);
box-shadow: none;
background-color: rgba(0,0,0,0.12);

但是我希望我的禁用按钮保持其原始颜色("primary,secondary","error"等),并添加不透明度为0.7。默认情况下,MUI将光标事件设置为无。

我尝试使用自定义主题,但不知道如何保持按钮的原始颜色。例如,如果Buttonprimary,则保持主要颜色,如果Buttonsecondary,则保持次要颜色。

    MuiButton: {
        styleOverrides: {
            root: {
                textTransform: "none",
                boxShadow: "none",
                "&.Mui-disabled": {
                    // background: "initial",
                    // color: "initial",
                    opacity: .7
                }
            },
        }
    }

当然,我不想为每个按钮编写自定义代码。通过创建 MUI 按钮周围的包装器并在我的代码中到处使用该包装器,我可以做到这一点。 但我希望按照 MUI 的方式通过覆盖主题来实现它。
如何实现全局解决方案?
3个回答

6

这是您想要的吗?只需不在调色板中设置禁用背景颜色:

import Button, { buttonClasses } from "@mui/material/Button";
import { createTheme, ThemeProvider } from "@mui/material/styles";

const defaultTheme = createTheme();
const theme = createTheme({
  palette: {
    action: {
      disabledBackground: "", // don't set the disable background color
      disabled: "white", // set the disable foreground color
    }
  },
  components: {
    MuiButtonBase: {
      styleOverrides: {
        root: {
          [`&.${buttonClasses.disabled}`]: {
            opacity: 0.5
          },
          // Fix ButtonGroup disabled styles.
          [`&.${toggleButtonClasses.root}.${buttonClasses.disabled}`]: {
            color: defaultTheme.palette.action.disabled,
            borderColor: defaultTheme.palette.action.disabledBackground
          }
        }
      }
    }
  }
);

目前我正在编写此内容。还有一些组件正在复用disableBackground属性,请确保您查看并对此也感到满意。我在下面的示例中展示了它们所有。

实时演示

Codesandbox Demo


已经尝试过了,这不起作用。因为空字符串是无效值,所以 Mui-disabled 样式会被应用。 - The Coder
1
@TheCoder 是的。我会在演示中向您展示所有受该更改影响的组件,以便您决定是否采用这种方法足够好。 - NearHuscarl
这仅适用于“enclosed”按钮。如果背景色为白色,则禁用按钮的文本将不可见。 - The Coder
@TheCoder 我猜您也希望“text”和“outlined”变体在任何状态下都具有相同的按钮颜色(而不是灰色),对吗? - NearHuscarl
禁用状态适用于每种类型的按钮。 - The Coder
显示剩余3条评论

2
以默认样式处理残疾状态的方式,我认为您需要在覆盖中重新定义默认颜色,以使其起作用。
在源代码中,您可以找到textoutlinedcontained变体的默认颜色如何定义。
以下示例演示了通过重新定义非残疾颜色来覆盖所有三个变体的禁用样式,使用"&.Mui-disabled"样式覆盖。其中,opacity: 0.7
import * as React from "react";
import Stack from "@mui/material/Stack";
import Button from "@mui/material/Button";
import { createTheme, ThemeProvider } from "@mui/material/styles";
import { alpha } from "@mui/system";
const defaultTheme = createTheme();
const colors = [
  "inherit",
  "primary",
  "secondary",
  "success",
  "error",
  "info",
  "warning"
];
const containedColorStyles = {};
const textColorStyles = {};
const outlinedColorStyles = {};
function capitalizeFirstLetter(string) {
  return string.charAt(0).toUpperCase() + string.slice(1);
}
colors.forEach((color) => {
  containedColorStyles[`&.MuiButton-contained${capitalizeFirstLetter(color)}`] =
    color === "inherit"
      ? {
          backgroundColor: defaultTheme.palette.grey[300],
          color: defaultTheme.palette.getContrastText(
            defaultTheme.palette.grey[300]
          )
        }
      : {
          backgroundColor: defaultTheme.palette[color].main,
          color: defaultTheme.palette[color].contrastText
        };
  textColorStyles[`&.MuiButton-text${capitalizeFirstLetter(color)}`] =
    color === "inherit"
      ? {
          color: "inherit"
        }
      : {
          color: defaultTheme.palette[color].main
        };
  outlinedColorStyles[`&.MuiButton-outlined${capitalizeFirstLetter(color)}`] =
    color === "inherit"
      ? {
          color: "inherit",
          borderColor:
            defaultTheme.palette.mode === "light"
              ? "rgba(0, 0, 0, 0.23)"
              : "rgba(255, 255, 255, 0.23)"
        }
      : {
          color: defaultTheme.palette[color].main,
          borderColor: `${alpha(defaultTheme.palette[color].main, 0.5)}`
        };
});
const theme = createTheme({
  components: {
    MuiButton: {
      styleOverrides: {
        root: {
          textTransform: "none",
          boxShadow: "none",
          "&.Mui-disabled": {
            ...containedColorStyles,
            ...textColorStyles,
            ...outlinedColorStyles,
            opacity: 0.7
          }
        }
      }
    }
  }
});
export default function ColorButtons() {
  const variants = ["text", "outlined", "contained"];
  return (
    <ThemeProvider theme={theme}>
      {variants.map((variant) => (
        <div key={variant}>
          {capitalizeFirstLetter(variant)} Variant
          <Stack direction="row" spacing={2}>
            {colors.map((color) => (
              <Button key={color} variant={variant} color={color}>
                {capitalizeFirstLetter(color)}
              </Button>
            ))}
          </Stack>
          Disabled {capitalizeFirstLetter(variant)} Variant
          <Stack direction="row" spacing={2} sx={{ mb: 2 }}>
            {colors.map((color) => (
              <Button key={color} disabled variant={variant} color={color}>
                {capitalizeFirstLetter(color)}
              </Button>
            ))}
          </Stack>
        </div>
      ))}
    </ThemeProvider>
  );
}

Edit ColorButtons override disabled colors


1
感谢你详细的回答,Ryan。 - The Coder

0

我现在有一个不错的解决方案。

我使用 ownerState 属性来获取颜色属性,接下来,我将它用于主题的调色板。下面的示例说明如何为 contained 按钮执行此操作。

let theme = createTheme({
  palette: {
    // Your custom palette
  },
});

theme = createTheme(theme, {
  components: {
    MuiButton: {
      defaultProps: {
        disableElevation: true
      },
      styleOverrides: {
        root: ({ ownerState }) => ({
          '&.MuiButton-contained.Mui-disabled': {
            backgroundColor: theme.palette[ownerState.color].main,
          }
        }),
      }
    }
  }
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接