@mui/material
Version:
Material UI is an open-source React component library that implements Google's Material Design. It's comprehensive and can be used in production out of the box.
502 lines (500 loc) • 16.4 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = enhanceHighContrast;
var _accordionSummaryClasses = _interopRequireDefault(require("../AccordionSummary/accordionSummaryClasses"));
var _autocompleteClasses = _interopRequireDefault(require("../Autocomplete/autocompleteClasses"));
var _checkboxClasses = _interopRequireDefault(require("../Checkbox/checkboxClasses"));
var _filledInputClasses = _interopRequireDefault(require("../FilledInput/filledInputClasses"));
var _formControlLabelClasses = _interopRequireDefault(require("../FormControlLabel/formControlLabelClasses"));
var _formHelperTextClasses = _interopRequireDefault(require("../FormHelperText/formHelperTextClasses"));
var _formLabelClasses = _interopRequireDefault(require("../FormLabel/formLabelClasses"));
var _inputClasses = _interopRequireDefault(require("../Input/inputClasses"));
var _listItemButtonClasses = _interopRequireDefault(require("../ListItemButton/listItemButtonClasses"));
var _menuItemClasses = _interopRequireDefault(require("../MenuItem/menuItemClasses"));
var _nativeSelectClasses = _interopRequireDefault(require("../NativeSelect/nativeSelectClasses"));
var _outlinedInputClasses = _interopRequireDefault(require("../OutlinedInput/outlinedInputClasses"));
var _radioClasses = _interopRequireDefault(require("../Radio/radioClasses"));
var _sliderClasses = _interopRequireDefault(require("../Slider/sliderClasses"));
var _toggleButtonClasses = _interopRequireDefault(require("../ToggleButton/toggleButtonClasses"));
// System color keywords used in forced-colors / high contrast mode.
const defaultHcTokens = {
disabled: 'GrayText',
error: 'ActiveText',
selectedBackground: 'SelectedItem',
selectedText: 'SelectedItemText',
activeBackground: 'Highlight',
activeText: 'HighlightText',
buttonBorder: 'ButtonBorder',
buttonText: 'ButtonText',
canvas: 'Canvas'
};
const HCM = '@media (forced-colors: active)';
/**
* Enhances a theme with styles for Windows High Contrast Mode (forced-colors).
*
* Accepts a fully-created theme, merges in HCM component overrides using arrays
* so that Emotion emits each entry as a separate CSS rule and the browser
* cascade (rather than JS object merging) resolves specificity.
*
* @param themeInput - The theme to enhance.
* @param tokens - Override any of the default system color tokens.
* @returns The enhanced theme (same type as the input).
*
* @example
* // Use defaults
* const theme = enhanceHighContrast(createTheme({ palette: { ... } }));
*
* @example
* // Override specific tokens
* const theme = enhanceHighContrast(createTheme(), { disabled: 'ButtonText' });
*/
function enhanceHighContrast(themeInput, tokens) {
const hcTokens = {
disabled: tokens?.disabled ?? defaultHcTokens.disabled,
error: tokens?.error ?? defaultHcTokens.error,
selectedBackground: tokens?.selectedBackground ?? defaultHcTokens.selectedBackground,
selectedText: tokens?.selectedText ?? defaultHcTokens.selectedText,
activeBackground: tokens?.activeBackground ?? defaultHcTokens.activeBackground,
activeText: tokens?.activeText ?? defaultHcTokens.activeText,
buttonBorder: tokens?.buttonBorder ?? defaultHcTokens.buttonBorder,
buttonText: tokens?.buttonText ?? defaultHcTokens.buttonText,
canvas: tokens?.canvas ?? defaultHcTokens.canvas
};
const theme = {
...themeInput
};
const c = theme.components;
theme.components = {
...c,
MuiAccordionSummary: {
...c?.MuiAccordionSummary,
styleOverrides: {
...c?.MuiAccordionSummary?.styleOverrides,
root: [c?.MuiAccordionSummary?.styleOverrides?.root, {
[`&.${_accordionSummaryClasses.default.disabled}`]: {
[HCM]: {
opacity: 1
}
}
}]
}
},
MuiAutocomplete: {
...c?.MuiAutocomplete,
styleOverrides: {
...c?.MuiAutocomplete?.styleOverrides,
listbox: [c?.MuiAutocomplete?.styleOverrides?.listbox, {
[`& .${_autocompleteClasses.default.option}`]: {
'&[aria-disabled="true"]': {
[HCM]: {
color: hcTokens.disabled,
opacity: 1
}
},
[`&.${_autocompleteClasses.default.focused}, &.${_autocompleteClasses.default.focusVisible}`]: {
[HCM]: {
forcedColorAdjust: 'none',
color: hcTokens.activeText,
backgroundColor: hcTokens.activeBackground
}
},
'&[aria-selected="true"]': {
[HCM]: {
forcedColorAdjust: 'none',
color: hcTokens.selectedText,
backgroundColor: hcTokens.selectedBackground
},
[`&.${_autocompleteClasses.default.focused}`]: {
[HCM]: {
color: hcTokens.activeText,
backgroundColor: hcTokens.activeBackground
}
}
}
}
}]
}
},
MuiCheckbox: {
...c?.MuiCheckbox,
styleOverrides: {
...c?.MuiCheckbox?.styleOverrides,
root: [c?.MuiCheckbox?.styleOverrides?.root, {
[`&.${_checkboxClasses.default.disabled}`]: {
[HCM]: {
color: hcTokens.disabled
}
}
}]
}
},
MuiFilledInput: {
...c?.MuiFilledInput,
styleOverrides: {
...c?.MuiFilledInput?.styleOverrides,
root: [c?.MuiFilledInput?.styleOverrides?.root, {
[`&.${_filledInputClasses.default.error}`]: {
'&::before, &::after': {
[HCM]: {
borderBottomColor: hcTokens.error
}
}
},
[`&.${_filledInputClasses.default.disabled}:before`]: {
[HCM]: {
borderBottomStyle: 'solid',
borderBottomColor: hcTokens.disabled
}
},
[`&.${_filledInputClasses.default.disabled}`]: {
[HCM]: {
color: hcTokens.disabled
}
}
}]
}
},
MuiFormControlLabel: {
...c?.MuiFormControlLabel,
styleOverrides: {
...c?.MuiFormControlLabel?.styleOverrides,
root: [c?.MuiFormControlLabel?.styleOverrides?.root, {
[`& .${_formControlLabelClasses.default.label}.${_formControlLabelClasses.default.disabled}`]: {
[HCM]: {
color: hcTokens.disabled
}
}
}]
}
},
MuiFormHelperText: {
...c?.MuiFormHelperText,
styleOverrides: {
...c?.MuiFormHelperText?.styleOverrides,
root: [c?.MuiFormHelperText?.styleOverrides?.root, {
[`&.${_formHelperTextClasses.default.error}`]: {
[HCM]: {
color: hcTokens.error
}
},
[`&.${_formHelperTextClasses.default.disabled}`]: {
[HCM]: {
color: hcTokens.disabled
}
}
}]
}
},
MuiFormLabel: {
...c?.MuiFormLabel,
styleOverrides: {
...c?.MuiFormLabel?.styleOverrides,
root: [c?.MuiFormLabel?.styleOverrides?.root, {
[`&.${_formLabelClasses.default.error}`]: {
[HCM]: {
color: hcTokens.error
}
},
[`&.${_formLabelClasses.default.disabled}`]: {
[HCM]: {
color: hcTokens.disabled
}
}
}]
}
},
MuiInput: {
...c?.MuiInput,
styleOverrides: {
...c?.MuiInput?.styleOverrides,
root: [c?.MuiInput?.styleOverrides?.root, {
[`&.${_inputClasses.default.error}`]: {
'&::before, &::after': {
[HCM]: {
borderBottomColor: hcTokens.error
}
}
},
[`&.${_inputClasses.default.disabled}:before`]: {
[HCM]: {
borderBottomStyle: 'solid',
borderBottomColor: hcTokens.disabled
}
},
[`&.${_inputClasses.default.disabled}`]: {
[HCM]: {
color: hcTokens.disabled
}
}
}]
}
},
MuiLinearProgress: {
...c?.MuiLinearProgress,
styleOverrides: {
...c?.MuiLinearProgress?.styleOverrides,
root: [c?.MuiLinearProgress?.styleOverrides?.root, {
[HCM]: {
forcedColorAdjust: 'none',
outline: `1px solid ${hcTokens.buttonBorder}`,
backgroundColor: hcTokens.canvas
}
}],
bar: [c?.MuiLinearProgress?.styleOverrides?.bar, {
[HCM]: {
backgroundColor: hcTokens.buttonText
}
}],
bar2: [c?.MuiLinearProgress?.styleOverrides?.bar2, {
variants: [{
props: {
variant: 'buffer'
},
style: {
[HCM]: {
backgroundColor: hcTokens.disabled
}
}
}]
}]
}
},
MuiInputBase: {
...c?.MuiInputBase,
styleOverrides: {
...c?.MuiInputBase?.styleOverrides,
input: [c?.MuiInputBase?.styleOverrides?.input, {
[HCM]: {
'&::placeholder': {
opacity: 1
}
}
}]
}
},
MuiMenuItem: {
...c?.MuiMenuItem,
styleOverrides: {
...c?.MuiMenuItem?.styleOverrides,
root: [c?.MuiMenuItem?.styleOverrides?.root, {
[`&.${_menuItemClasses.default.disabled}`]: {
[HCM]: {
color: hcTokens.disabled,
opacity: 1
}
},
[`&.${_menuItemClasses.default.focusVisible}, &:hover`]: {
[HCM]: {
forcedColorAdjust: 'none',
color: hcTokens.activeText,
backgroundColor: hcTokens.activeBackground,
outline: 'none'
}
},
[`&.${_menuItemClasses.default.selected}`]: {
[HCM]: {
forcedColorAdjust: 'none',
color: hcTokens.selectedText,
backgroundColor: hcTokens.selectedBackground
}
},
[`&.${_menuItemClasses.default.selected}.${_menuItemClasses.default.focusVisible}, &.${_menuItemClasses.default.selected}:hover`]: {
[HCM]: {
color: hcTokens.activeText,
backgroundColor: hcTokens.activeBackground
}
}
}]
}
},
MuiListItemIcon: {
...c?.MuiListItemIcon,
styleOverrides: {
...c?.MuiListItemIcon?.styleOverrides,
root: [c?.MuiListItemIcon?.styleOverrides?.root, {
[HCM]: {
color: 'inherit'
}
}]
}
},
MuiListItemButton: {
...c?.MuiListItemButton,
styleOverrides: {
...c?.MuiListItemButton?.styleOverrides,
root: [c?.MuiListItemButton?.styleOverrides?.root, {
[`&.${_listItemButtonClasses.default.focusVisible}, &:hover`]: {
[HCM]: {
forcedColorAdjust: 'none',
color: hcTokens.activeText,
backgroundColor: hcTokens.activeBackground
}
},
[`&.${_listItemButtonClasses.default.selected}`]: {
[HCM]: {
forcedColorAdjust: 'none',
color: hcTokens.selectedText,
backgroundColor: hcTokens.selectedBackground
}
},
[`&.${_listItemButtonClasses.default.selected}.${_listItemButtonClasses.default.focusVisible}, &.${_listItemButtonClasses.default.selected}:hover`]: {
[HCM]: {
color: hcTokens.activeText,
backgroundColor: hcTokens.activeBackground
}
}
}]
}
},
MuiNativeSelect: {
...c?.MuiNativeSelect,
styleOverrides: {
...c?.MuiNativeSelect?.styleOverrides,
icon: [c?.MuiNativeSelect?.styleOverrides?.icon, {
[`&.${_nativeSelectClasses.default.disabled}`]: {
[HCM]: {
color: hcTokens.disabled
}
}
}]
}
},
MuiOutlinedInput: {
...c?.MuiOutlinedInput,
styleOverrides: {
...c?.MuiOutlinedInput?.styleOverrides,
root: [c?.MuiOutlinedInput?.styleOverrides?.root, {
[`&.${_outlinedInputClasses.default.error} .${_outlinedInputClasses.default.notchedOutline}`]: {
[HCM]: {
borderColor: hcTokens.error
}
},
[`&.${_outlinedInputClasses.default.disabled} .${_outlinedInputClasses.default.notchedOutline}`]: {
[HCM]: {
borderColor: hcTokens.disabled
}
},
[`&.${_outlinedInputClasses.default.disabled}`]: {
[HCM]: {
color: hcTokens.disabled
}
}
}]
}
},
MuiRadio: {
...c?.MuiRadio,
styleOverrides: {
...c?.MuiRadio?.styleOverrides,
root: [c?.MuiRadio?.styleOverrides?.root, {
[`&.${_radioClasses.default.disabled}`]: {
[HCM]: {
color: hcTokens.disabled
}
}
}]
}
},
MuiSlider: {
...c?.MuiSlider,
styleOverrides: {
...c?.MuiSlider?.styleOverrides,
// track doesn't receive the disabled class — use ownerState
track: [c?.MuiSlider?.styleOverrides?.track, ({
ownerState
}) => ({
...(ownerState.disabled && {
[HCM]: {
borderColor: hcTokens.disabled
}
})
})],
// thumb receives the disabled class directly
thumb: [c?.MuiSlider?.styleOverrides?.thumb, {
[`&.${_sliderClasses.default.disabled}`]: {
[HCM]: {
borderColor: hcTokens.disabled
}
}
}]
}
},
MuiSwitch: {
...c?.MuiSwitch,
styleOverrides: {
...c?.MuiSwitch?.styleOverrides,
// track and thumb don't receive the disabled class — use ownerState
track: [c?.MuiSwitch?.styleOverrides?.track, ({
ownerState
}) => ({
...(ownerState.disabled && {
[HCM]: {
borderColor: hcTokens.disabled
}
})
})],
thumb: [c?.MuiSwitch?.styleOverrides?.thumb, ({
ownerState
}) => ({
...(ownerState.disabled && {
[HCM]: {
borderColor: hcTokens.disabled
}
})
})]
}
},
MuiButtonBase: {
...c?.MuiButtonBase,
styleOverrides: {
...c?.MuiButtonBase?.styleOverrides,
root: [c?.MuiButtonBase?.styleOverrides?.root, {
// Restore the focus outline in HCM since the ripple is not visible.
// Also handle components where the focusable element is a hidden inner input (Checkbox, Radio, Switch).
[HCM]: {
'&:focus-visible, &:focus-within:has(input:focus-visible)': {
outline: `5px auto ${hcTokens.activeBackground}`
}
}
}]
}
},
MuiTooltip: {
...c?.MuiTooltip,
styleOverrides: {
...c?.MuiTooltip?.styleOverrides,
tooltip: [c?.MuiTooltip?.styleOverrides?.tooltip, {
[HCM]: {
border: `1px solid ${hcTokens.buttonText}`
}
}]
}
},
MuiToggleButton: {
...c?.MuiToggleButton,
styleOverrides: {
...c?.MuiToggleButton?.styleOverrides,
root: [c?.MuiToggleButton?.styleOverrides?.root, {
[`&.${_toggleButtonClasses.default.selected}`]: {
[HCM]: {
forcedColorAdjust: 'none',
color: hcTokens.activeText,
backgroundColor: hcTokens.activeBackground,
borderColor: hcTokens.activeBackground
},
'&:hover': {
[HCM]: {
backgroundColor: hcTokens.activeBackground,
borderColor: hcTokens.buttonBorder
}
}
}
}]
}
}
};
return theme;
}