UNPKG

@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.

495 lines (494 loc) 15.5 kB
import accordionSummaryClasses from "../AccordionSummary/accordionSummaryClasses.mjs"; import autocompleteClasses from "../Autocomplete/autocompleteClasses.mjs"; import checkboxClasses from "../Checkbox/checkboxClasses.mjs"; import filledInputClasses from "../FilledInput/filledInputClasses.mjs"; import formControlLabelClasses from "../FormControlLabel/formControlLabelClasses.mjs"; import formHelperTextClasses from "../FormHelperText/formHelperTextClasses.mjs"; import formLabelClasses from "../FormLabel/formLabelClasses.mjs"; import inputClasses from "../Input/inputClasses.mjs"; import listItemButtonClasses from "../ListItemButton/listItemButtonClasses.mjs"; import menuItemClasses from "../MenuItem/menuItemClasses.mjs"; import nativeSelectClasses from "../NativeSelect/nativeSelectClasses.mjs"; import outlinedInputClasses from "../OutlinedInput/outlinedInputClasses.mjs"; import radioClasses from "../Radio/radioClasses.mjs"; import sliderClasses from "../Slider/sliderClasses.mjs"; import toggleButtonClasses from "../ToggleButton/toggleButtonClasses.mjs"; // 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' }); */ export default 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.disabled}`]: { [HCM]: { opacity: 1 } } }] } }, MuiAutocomplete: { ...c?.MuiAutocomplete, styleOverrides: { ...c?.MuiAutocomplete?.styleOverrides, listbox: [c?.MuiAutocomplete?.styleOverrides?.listbox, { [`& .${autocompleteClasses.option}`]: { '&[aria-disabled="true"]': { [HCM]: { color: hcTokens.disabled, opacity: 1 } }, [`&.${autocompleteClasses.focused}, &.${autocompleteClasses.focusVisible}`]: { [HCM]: { forcedColorAdjust: 'none', color: hcTokens.activeText, backgroundColor: hcTokens.activeBackground } }, '&[aria-selected="true"]': { [HCM]: { forcedColorAdjust: 'none', color: hcTokens.selectedText, backgroundColor: hcTokens.selectedBackground }, [`&.${autocompleteClasses.focused}`]: { [HCM]: { color: hcTokens.activeText, backgroundColor: hcTokens.activeBackground } } } } }] } }, MuiCheckbox: { ...c?.MuiCheckbox, styleOverrides: { ...c?.MuiCheckbox?.styleOverrides, root: [c?.MuiCheckbox?.styleOverrides?.root, { [`&.${checkboxClasses.disabled}`]: { [HCM]: { color: hcTokens.disabled } } }] } }, MuiFilledInput: { ...c?.MuiFilledInput, styleOverrides: { ...c?.MuiFilledInput?.styleOverrides, root: [c?.MuiFilledInput?.styleOverrides?.root, { [`&.${filledInputClasses.error}`]: { '&::before, &::after': { [HCM]: { borderBottomColor: hcTokens.error } } }, [`&.${filledInputClasses.disabled}:before`]: { [HCM]: { borderBottomStyle: 'solid', borderBottomColor: hcTokens.disabled } }, [`&.${filledInputClasses.disabled}`]: { [HCM]: { color: hcTokens.disabled } } }] } }, MuiFormControlLabel: { ...c?.MuiFormControlLabel, styleOverrides: { ...c?.MuiFormControlLabel?.styleOverrides, root: [c?.MuiFormControlLabel?.styleOverrides?.root, { [`& .${formControlLabelClasses.label}.${formControlLabelClasses.disabled}`]: { [HCM]: { color: hcTokens.disabled } } }] } }, MuiFormHelperText: { ...c?.MuiFormHelperText, styleOverrides: { ...c?.MuiFormHelperText?.styleOverrides, root: [c?.MuiFormHelperText?.styleOverrides?.root, { [`&.${formHelperTextClasses.error}`]: { [HCM]: { color: hcTokens.error } }, [`&.${formHelperTextClasses.disabled}`]: { [HCM]: { color: hcTokens.disabled } } }] } }, MuiFormLabel: { ...c?.MuiFormLabel, styleOverrides: { ...c?.MuiFormLabel?.styleOverrides, root: [c?.MuiFormLabel?.styleOverrides?.root, { [`&.${formLabelClasses.error}`]: { [HCM]: { color: hcTokens.error } }, [`&.${formLabelClasses.disabled}`]: { [HCM]: { color: hcTokens.disabled } } }] } }, MuiInput: { ...c?.MuiInput, styleOverrides: { ...c?.MuiInput?.styleOverrides, root: [c?.MuiInput?.styleOverrides?.root, { [`&.${inputClasses.error}`]: { '&::before, &::after': { [HCM]: { borderBottomColor: hcTokens.error } } }, [`&.${inputClasses.disabled}:before`]: { [HCM]: { borderBottomStyle: 'solid', borderBottomColor: hcTokens.disabled } }, [`&.${inputClasses.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.disabled}`]: { [HCM]: { color: hcTokens.disabled, opacity: 1 } }, [`&.${menuItemClasses.focusVisible}, &:hover`]: { [HCM]: { forcedColorAdjust: 'none', color: hcTokens.activeText, backgroundColor: hcTokens.activeBackground, outline: 'none' } }, [`&.${menuItemClasses.selected}`]: { [HCM]: { forcedColorAdjust: 'none', color: hcTokens.selectedText, backgroundColor: hcTokens.selectedBackground } }, [`&.${menuItemClasses.selected}.${menuItemClasses.focusVisible}, &.${menuItemClasses.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.focusVisible}, &:hover`]: { [HCM]: { forcedColorAdjust: 'none', color: hcTokens.activeText, backgroundColor: hcTokens.activeBackground } }, [`&.${listItemButtonClasses.selected}`]: { [HCM]: { forcedColorAdjust: 'none', color: hcTokens.selectedText, backgroundColor: hcTokens.selectedBackground } }, [`&.${listItemButtonClasses.selected}.${listItemButtonClasses.focusVisible}, &.${listItemButtonClasses.selected}:hover`]: { [HCM]: { color: hcTokens.activeText, backgroundColor: hcTokens.activeBackground } } }] } }, MuiNativeSelect: { ...c?.MuiNativeSelect, styleOverrides: { ...c?.MuiNativeSelect?.styleOverrides, icon: [c?.MuiNativeSelect?.styleOverrides?.icon, { [`&.${nativeSelectClasses.disabled}`]: { [HCM]: { color: hcTokens.disabled } } }] } }, MuiOutlinedInput: { ...c?.MuiOutlinedInput, styleOverrides: { ...c?.MuiOutlinedInput?.styleOverrides, root: [c?.MuiOutlinedInput?.styleOverrides?.root, { [`&.${outlinedInputClasses.error} .${outlinedInputClasses.notchedOutline}`]: { [HCM]: { borderColor: hcTokens.error } }, [`&.${outlinedInputClasses.disabled} .${outlinedInputClasses.notchedOutline}`]: { [HCM]: { borderColor: hcTokens.disabled } }, [`&.${outlinedInputClasses.disabled}`]: { [HCM]: { color: hcTokens.disabled } } }] } }, MuiRadio: { ...c?.MuiRadio, styleOverrides: { ...c?.MuiRadio?.styleOverrides, root: [c?.MuiRadio?.styleOverrides?.root, { [`&.${radioClasses.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.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.selected}`]: { [HCM]: { forcedColorAdjust: 'none', color: hcTokens.activeText, backgroundColor: hcTokens.activeBackground, borderColor: hcTokens.activeBackground }, '&:hover': { [HCM]: { backgroundColor: hcTokens.activeBackground, borderColor: hcTokens.buttonBorder } } } }] } } }; return theme; }