mui-treasury
itemmui-treasurysource: ok · refreshed
MUI Treasury Theme
A minimal theme with monochromatic palette and system fonts
npx shadcn add "https://mui-treasury.com/r/mui-treasury.json"free
Visual style
terminal-monominimal
Tags auto-generated by rules on 9/24/2026 — empty means no evidence, not lack of support.
Dependencies
Bundle weight · light@mui/material@emotion/react@emotion/styled@mui/x-data-grid@mui/x-date-pickers@mui/x-tree-view
Files27 · source cached 10/7/2026, 3:16:30 AM
themes/mui-treasury/colors.ts
import type { CssVarsThemeOptions } from '@mui/material/styles';
// Augment the palette to include custom 'text' property
declare module '@mui/material/styles' {
interface PaletteColor {
text: string;
}
interface SimplePaletteColorOptions {
text?: string;
}
interface TypeText {
icon: string;
tertiary: string;
}
}
export const colors: CssVarsThemeOptions['colorSchemes'] = {
light: {
palette: {
text: {
icon: 'rgb(0 0 0 / 0.4)', // systemGray for icons
tertiary: 'rgb(0 0 0 / 0.54)', // lowest contrast text to pass AAA
},
action: {
activatedOpacity: 0.38, // Reduced from 0.54
selectedOpacity: 0.06, // Reduced from 0.08
disabledOpacity: 0.2, // Reduced from 0.38
focusOpacity: 0.08, // Reduced from 0.12
},
primary: {
main: '#000',
text: '#212121',
},
secondary: {
main: 'rgb(229, 229, 234)', // systemGray
text: 'rgb(108, 108, 112)', // systemGray increased contrast
},
success: {
main: 'rgb(52, 199, 89)', // green
text: 'rgb(0, 137, 50)', // green increased contrast
},
error: {
main: 'rgb(255, 56, 60)', // red
text: 'rgb(233, 21, 45)', // red increased contrast
},
warning: {
main: 'rgb(255, 204, 0)', // yellow
text: 'rgb(161, 106, 0)', // yellow increased contrast
},
info: {
main: 'rgb(0, 136, 255)', // blue
text: 'rgb(30, 110, 244)', // blue increased contrast
},
background: {
default: 'rgb(248, 248, 248)',
},
},
},
dark: {
palette: {
text: {
icon: 'rgb(255 255 255 / 0.54)', // systemGray for icons in dark mode
tertiary: 'rgb(255 255 255 / 0.6)', // systemGray for tertiary text
},
action: {
activatedOpacity: 0.38, // Reduced intensity
selectedOpacity: 0.06, // Subtle selection
disabledOpacity: 0.2, // Reduced opacity
focusOpacity: 0.08, // Subtle focus
},
primary: {
main: '#fff',
text: '#f5f5f5',
},
secondary: {
main: 'rgb(142, 142, 147)', // systemGray
text: 'rgb(174, 174, 178)', // systemGray for dark mode
},
success: {
main: 'rgb(48, 209, 88)', // green for dark
text: 'rgb(71, 217, 104)', // green for dark
},
error: {
main: 'rgb(255, 69, 58)', // red for dark
text: 'rgb(255, 97, 101)', // red for dark
},
warning: {
main: 'rgb(255, 214, 10)', // yellow for dark
text: 'rgb(254, 223, 67)', // yellow for dark
},
info: {
main: 'rgb(0, 145, 255)', // blue for dark
text: 'rgb(92, 184, 255)', // blue for dark
},
background: {
default: 'rgb(0, 0, 0)', // systemGrayDark
paper: 'rgb(18, 18, 18)', // systemGrayDark
},
},
},
};
themes/mui-treasury/components/alert.ts
import { ThemeComponents } from '../types';
export const alertTheme: ThemeComponents = {
MuiAlert: {
styleOverrides: {
root: {
'--Icon-color': 'currentColor',
},
},
},
};
themes/mui-treasury/components/autocomplete.ts
import { autocompleteClasses } from '@mui/material/Autocomplete';
import { chipClasses } from '@mui/material/Chip';
import { inputBaseClasses } from '@mui/material/InputBase';
import {
CONTROL_HEIGHTS,
CONTROL_TOUCH_HEIGHTS,
TOUCH_MEDIA_QUERY,
} from '../scales';
import { ThemeComponents } from '../types';
declare module '@mui/material/Autocomplete' {
interface AutocompletePropsSizeOverrides {
large: true;
}
}
export const autocompleteTheme: ThemeComponents = {
MuiAutocomplete: {
defaultProps: {
slotProps: {
paper: {
elevation: 8,
},
},
},
styleOverrides: {
root: {
variants: [
{
props: { size: 'medium' },
style: {
[`& .${autocompleteClasses.inputRoot}`]: {
paddingTop: 2,
paddingBottom: 2,
paddingRight: 40,
[`&:has(.${chipClasses.root})`]: {
paddingLeft: '2px',
},
[`& .${autocompleteClasses.input}`]: {
paddingBlock: CONTROL_HEIGHTS.md / 2 - 12.5,
...(CONTROL_HEIGHTS.md !== CONTROL_TOUCH_HEIGHTS.md && {
[TOUCH_MEDIA_QUERY]: {
paddingBlock: CONTROL_TOUCH_HEIGHTS.md / 2 - 14,
},
}),
},
},
},
},
{
props: { size: 'small' },
style: {
[`& .${autocompleteClasses.inputRoot}.${inputBaseClasses.sizeSmall}`]:
{
paddingTop: 2,
paddingBottom: 2,
paddingLeft: 2,
[`& .${autocompleteClasses.input}`]: {
paddingBlock: CONTROL_HEIGHTS.sm / 2 - 12.5,
...(CONTROL_HEIGHTS.sm !== CONTROL_TOUCH_HEIGHTS.sm && {
[TOUCH_MEDIA_QUERY]: {
paddingBlock: CONTROL_TOUCH_HEIGHTS.sm / 2 - 14,
},
}),
},
},
},
},
{
props: { size: 'large' },
style: {
[`& .${autocompleteClasses.inputRoot}`]: {
paddingTop: 4,
paddingBottom: 4,
paddingLeft: 12,
[`&:has(.${chipClasses.root})`]: {
paddingLeft: 4,
},
[`& .${autocompleteClasses.input}`]: {
paddingBlock: CONTROL_HEIGHTS.lg / 2 - 14.5,
...(CONTROL_HEIGHTS.lg !== CONTROL_TOUCH_HEIGHTS.lg && {
[TOUCH_MEDIA_QUERY]: {
paddingBlock: CONTROL_TOUCH_HEIGHTS.lg / 2 - 16,
},
}),
},
},
},
},
],
},
tag: {
margin: 2,
},
option: ({ theme }) => ({
fontSize: theme.typography.body2.fontSize,
padding: '6px',
borderRadius: 4,
}),
paper: ({ theme }) => ({
marginTop: 4,
borderRadius: 8,
border: `1px solid ${(theme.vars || theme).palette.divider}`,
}),
listbox: ({ theme }) => ({
padding: '6px',
display: 'flex',
flexDirection: 'column',
gap: '4px',
[`& .${autocompleteClasses.option}`]: {
minHeight: 40,
[theme.breakpoints.up('sm')]: {
minHeight: 'auto',
},
},
}),
noOptions: ({ theme }) => ({
fontSize: theme.typography.body2.fontSize,
color: (theme.vars || theme).palette.text.secondary,
}),
loading: ({ theme }) => ({
fontSize: theme.typography.body2.fontSize,
color: (theme.vars || theme).palette.text.secondary,
}),
clearIndicator: {
borderRadius: 4,
},
popupIndicator: {
borderRadius: 4,
variants: [
{
props: { size: 'small' },
style: {
marginRight: -5,
},
},
],
},
},
},
};
themes/mui-treasury/components/avatar.ts
import { ThemeComponents } from '../types';
export const avatarTheme: ThemeComponents = {
MuiAvatar: {
styleOverrides: {
root: ({ theme }) => ({
fontWeight: 500,
fontSize: theme.typography.body2.fontSize,
backgroundColor: (theme.vars || theme).palette.secondary.light,
color: (theme.vars || theme).palette.text.secondary,
...theme.applyStyles('dark', {
backgroundColor: (theme.vars || theme).palette.secondary.dark,
}),
}),
},
},
};
themes/mui-treasury/components/button.ts
import { buttonClasses } from '@mui/material/Button';
import {
buttonBaseClasses,
touchRippleClasses,
} from '@mui/material/ButtonBase';
import { fabClasses } from '@mui/material/Fab';
import {
CONTROL_HEIGHTS,
CONTROL_TOUCH_HEIGHTS,
TOUCH_MEDIA_QUERY,
} from '../scales';
import { ThemeComponents } from '../types';
export const buttonTheme: ThemeComponents = {
MuiButtonBase: {
styleOverrides: {
root: ({ theme }) => ({
[`&& .${touchRippleClasses.child}`]: {
background: 'color-mix(in oklch, currentColor, transparent 60%)',
},
'--Icon-color': 'color-mix(in oklch, currentColor, transparent 12%)',
'--Icon-size': '1lh',
...theme.applyStyles('dark', {
'--Icon-color': 'color-mix(in oklch, currentColor, transparent 30%)',
}),
'&:hover': {
'--Icon-color': 'currentColor',
},
}),
},
},
MuiIconButton: {
styleOverrides: {
root: ({ theme }) => ({
fontSize: 'inherit',
lineHeight: 'inherit',
[`&.${buttonBaseClasses.focusVisible}`]: {
outline: '2px solid',
outlineColor: (theme.vars || theme).palette.text.primary,
outlineOffset: '2px',
},
'&:active': {
transform: 'scale(0.98)',
},
variants: [
{
props: { color: 'default' },
style: {
'&:hover, &:focus-visible': {
color: (theme.vars || theme).palette.text.primary,
},
},
},
],
}),
},
},
MuiButton: {
defaultProps: {
disableElevation: true,
},
styleOverrides: {
root: ({ theme }) => ({
'--_g': 'initial',
gap: 'var(--_g)',
minWidth: 'unset',
textTransform: 'capitalize',
[`&.${buttonClasses.focusVisible}`]: {
outline: '2px solid',
outlineColor: (theme.vars || theme).palette.text.primary,
outlineOffset: '2px',
},
'&:active': {
transform: 'scale(0.98)',
},
[`&:not(:has(.${buttonClasses.icon}))`]: {
'--_g': `calc(${theme.spacing(1)} - 1px)`,
},
'@media (hover: hover)': {
'&:disabled': {
pointerEvents: 'auto',
cursor: 'not-allowed',
},
},
// When button contains only an icon (with or without TouchRipple)
[`&:has(> svg:only-child, > svg + .${touchRippleClasses.root})`]: {
'--Icon-color': 'currentColor',
[`&.${buttonClasses.sizeSmall}`]: {
padding: CONTROL_HEIGHTS.sm / 2 - 10,
minWidth: '28px',
...(CONTROL_HEIGHTS.sm !== CONTROL_TOUCH_HEIGHTS.sm && {
[TOUCH_MEDIA_QUERY]: {
padding: CONTROL_TOUCH_HEIGHTS.sm / 2 - 10,
},
}),
},
[`&.${buttonClasses.sizeMedium}`]: {
padding: CONTROL_HEIGHTS.md / 2 - 10,
minWidth: '36px',
...(CONTROL_HEIGHTS.md !== CONTROL_TOUCH_HEIGHTS.md && {
[TOUCH_MEDIA_QUERY]: {
padding: CONTROL_TOUCH_HEIGHTS.md / 2 - 10,
},
}),
},
[`&.${buttonClasses.sizeLarge}`]: {
padding: CONTROL_HEIGHTS.lg / 2 - 12,
minWidth: '48px',
...(CONTROL_HEIGHTS.lg !== CONTROL_TOUCH_HEIGHTS.lg && {
[TOUCH_MEDIA_QUERY]: {
padding: CONTROL_TOUCH_HEIGHTS.lg / 2 - 12,
},
}),
},
// Outlined variant needs to compensate for border
[`&.${buttonClasses.outlined}`]: {
[`&.${buttonClasses.sizeSmall}`]: {
padding: CONTROL_HEIGHTS.sm / 2 - 11,
...(CONTROL_HEIGHTS.sm !== CONTROL_TOUCH_HEIGHTS.sm && {
[TOUCH_MEDIA_QUERY]: {
padding: CONTROL_TOUCH_HEIGHTS.sm / 2 - 11,
},
}),
},
[`&.${buttonClasses.sizeMedium}`]: {
padding: CONTROL_HEIGHTS.md / 2 - 11,
...(CONTROL_HEIGHTS.md !== CONTROL_TOUCH_HEIGHTS.md && {
[TOUCH_MEDIA_QUERY]: {
padding: CONTROL_TOUCH_HEIGHTS.md / 2 - 11,
},
}),
},
[`&.${buttonClasses.sizeLarge}`]: {
padding: CONTROL_HEIGHTS.lg / 2 - 13,
...(CONTROL_HEIGHTS.lg !== CONTROL_TOUCH_HEIGHTS.lg && {
[TOUCH_MEDIA_QUERY]: {
padding: CONTROL_TOUCH_HEIGHTS.lg / 2 - 13,
},
}),
},
},
},
variants: [
// Size variants
{
props: { size: 'small' },
style: {
paddingBlock: CONTROL_HEIGHTS.sm / 2 - 10,
paddingInline: 12,
lineHeight: '20px',
...(CONTROL_HEIGHTS.sm !== CONTROL_TOUCH_HEIGHTS.sm && {
[TOUCH_MEDIA_QUERY]: {
paddingBlock: CONTROL_TOUCH_HEIGHTS.sm / 2 - 10,
},
}),
},
},
{
props: { size: 'medium' },
style: {
paddingBlock: CONTROL_HEIGHTS.md / 2 - 10,
paddingInline: 16,
lineHeight: '20px',
...(CONTROL_HEIGHTS.md !== CONTROL_TOUCH_HEIGHTS.md && {
[TOUCH_MEDIA_QUERY]: {
paddingBlock: CONTROL_TOUCH_HEIGHTS.md / 2 - 10,
},
}),
},
},
{
props: { size: 'large' },
style: {
paddingBlock: CONTROL_HEIGHTS.lg / 2 - 12,
paddingInline: 24,
lineHeight: '24px',
fontSize: '1rem',
...(CONTROL_HEIGHTS.lg !== CONTROL_TOUCH_HEIGHTS.lg && {
[TOUCH_MEDIA_QUERY]: {
paddingBlock: CONTROL_TOUCH_HEIGHTS.lg / 2 - 12,
},
}),
},
},
// Outlined border compensation for all sizes
{
props: { variant: 'outlined' },
style: {
[`&.${buttonClasses.sizeSmall}`]: {
paddingBlock: CONTROL_HEIGHTS.sm / 2 - 11,
paddingInline: 12,
...(CONTROL_HEIGHTS.sm !== CONTROL_TOUCH_HEIGHTS.sm && {
[TOUCH_MEDIA_QUERY]: {
paddingBlock: CONTROL_TOUCH_HEIGHTS.sm / 2 - 11,
},
}),
},
[`&.${buttonClasses.sizeMedium}`]: {
paddingBlock: CONTROL_HEIGHTS.md / 2 - 11,
paddingInline: 16,
...(CONTROL_HEIGHTS.md !== CONTROL_TOUCH_HEIGHTS.md && {
[TOUCH_MEDIA_QUERY]: {
paddingBlock: CONTROL_TOUCH_HEIGHTS.md / 2 - 11,
},
}),
},
[`&.${buttonClasses.sizeLarge}`]: {
paddingBlock: CONTROL_HEIGHTS.lg / 2 - 13,
paddingInline: 24,
...(CONTROL_HEIGHTS.lg !== CONTROL_TOUCH_HEIGHTS.lg && {
[TOUCH_MEDIA_QUERY]: {
paddingBlock: CONTROL_TOUCH_HEIGHTS.lg / 2 - 13,
},
}),
},
[`& .${touchRippleClasses.root}`]: {
inset: '-1px',
},
},
},
// Text variant uses custom text colors
{
props: { variant: 'text' },
style: {
[`&.${buttonClasses.colorSecondary}`]: {
'--variant-textColor': (theme.vars || theme).palette.secondary
.text,
},
[`&.${buttonClasses.colorSuccess}`]: {
'--variant-textColor': (theme.vars || theme).palette.success
.text,
},
[`&.${buttonClasses.colorError}`]: {
'--variant-textColor': (theme.vars || theme).palette.error.text,
},
[`&.${buttonClasses.colorWarning}`]: {
'--variant-textColor': (theme.vars || theme).palette.warning
.text,
},
[`&.${buttonClasses.colorInfo}`]: {
'--variant-textColor': (theme.vars || theme).palette.info.text,
},
color: 'var(--variant-textColor)',
},
},
// Outlined variant uses custom text colors and subtle borders
{
props: { variant: 'outlined' },
style: {
[`&.${buttonClasses.colorPrimary}`]: {
'--variant-outlinedBorder': `color-mix(in srgb, ${
(theme.vars || theme).palette.primary.main
} 12%, transparent)`,
},
[`&.${buttonClasses.colorSecondary}`]: {
'--variant-outlinedColor': (theme.vars || theme).palette
.secondary.text,
'--variant-outlinedBorder': `color-mix(in srgb, ${
(theme.vars || theme).palette.secondary.text
} 28%, transparent)`,
},
[`&.${buttonClasses.colorSuccess}`]: {
'--variant-outlinedColor': (theme.vars || theme).palette.success
.text,
'--variant-outlinedBorder': `color-mix(in srgb, ${
(theme.vars || theme).palette.success.text
} 28%, transparent)`,
},
[`&.${buttonClasses.colorError}`]: {
'--variant-outlinedColor': (theme.vars || theme).palette.error
.text,
'--variant-outlinedBorder': `color-mix(in srgb, ${
(theme.vars || theme).palette.error.text
} 28%, transparent)`,
},
[`&.${buttonClasses.colorWarning}`]: {
'--variant-outlinedColor': (theme.vars || theme).palette.warning
.text,
'--variant-outlinedBorder': `color-mix(in srgb, ${
(theme.vars || theme).palette.warning.text
} 28%, transparent)`,
},
[`&.${buttonClasses.colorInfo}`]: {
'--variant-outlinedColor': (theme.vars || theme).palette.info
.text,
'--variant-outlinedBorder': `color-mix(in srgb, ${
(theme.vars || theme).palette.info.text
} 28%, transparent)`,
},
color: 'var(--variant-outlinedColor)',
borderColor: 'var(--variant-outlinedBorder)',
},
},
// Contained variant for secondary, success, error, warning, info
{
props: { variant: 'contained', color: 'secondary' },
style: {
color: `color-mix(in oklch, ${
(theme.vars || theme).palette.secondary.text
}, ${(theme.vars || theme).palette.common.onBackground} 30%)`,
backgroundColor: `color-mix(in oklch, ${
(theme.vars || theme).palette.secondary.main
}, ${(theme.vars || theme).palette.common.background} 50%)`,
},
},
{
props: { variant: 'contained', color: 'success' },
style: {
color: `color-mix(in oklch, ${
(theme.vars || theme).palette.success.text
}, ${(theme.vars || theme).palette.common.onBackground} 30%)`,
backgroundColor: `color-mix(in oklch, ${
(theme.vars || theme).palette.success.main
}, ${(theme.vars || theme).palette.common.background} 60%)`,
},
},
{
props: { variant: 'contained', color: 'error' },
style: {
color: `color-mix(in oklch, ${
(theme.vars || theme).palette.error.text
}, ${(theme.vars || theme).palette.common.onBackground} 30%)`,
backgroundColor: `color-mix(in oklch, ${
(theme.vars || theme).palette.error.main
}, ${(theme.vars || theme).palette.common.background} 60%)`,
},
},
{
props: { variant: 'contained', color: 'warning' },
style: {
color: `color-mix(in oklch, ${
(theme.vars || theme).palette.warning.text
}, ${(theme.vars || theme).palette.common.onBackground} 30%)`,
backgroundColor: `color-mix(in oklch, ${
(theme.vars || theme).palette.warning.main
}, ${(theme.vars || theme).palette.common.background} 60%)`,
},
},
{
props: { variant: 'contained', color: 'info' },
style: {
color: `color-mix(in oklch, ${
(theme.vars || theme).palette.info.text
}, ${(theme.vars || theme).palette.common.onBackground} 30%)`,
backgroundColor: `color-mix(in oklch, ${
(theme.vars || theme).palette.info.main
}, ${(theme.vars || theme).palette.common.background} 60%)`,
},
},
],
}),
},
},
MuiFab: {
styleOverrides: {
root: ({ theme }) => ({
[`&.${fabClasses.focusVisible}`]: {
outline: '2px solid',
outlineColor: (theme.vars || theme).palette.text.primary,
outlineOffset: '2px',
},
'&:active': {
transform: 'scale(0.98)',
},
}),
},
},
MuiToggleButton: {
styleOverrides: {
root: {
variants: [
{
props: { size: 'small' },
style: {
padding: CONTROL_HEIGHTS.sm / 2 - 11,
...(CONTROL_HEIGHTS.sm !== CONTROL_TOUCH_HEIGHTS.sm && {
[TOUCH_MEDIA_QUERY]: {
padding: CONTROL_TOUCH_HEIGHTS.sm / 2 - 11,
},
}),
},
},
{
props: { size: 'medium' },
style: {
padding: CONTROL_HEIGHTS.md / 2 - 11,
...(CONTROL_HEIGHTS.md !== CONTROL_TOUCH_HEIGHTS.md && {
[TOUCH_MEDIA_QUERY]: {
padding: CONTROL_TOUCH_HEIGHTS.md / 2 - 11,
},
}),
},
},
{
props: { size: 'large' },
style: {
padding: CONTROL_HEIGHTS.lg / 2 - 11,
...(CONTROL_HEIGHTS.lg !== CONTROL_TOUCH_HEIGHTS.lg && {
[TOUCH_MEDIA_QUERY]: {
padding: CONTROL_TOUCH_HEIGHTS.lg / 2 - 11,
},
}),
},
},
],
},
},
},
};
themes/mui-treasury/components/card.ts
import { ThemeComponents } from '../types';
export const cardTheme: ThemeComponents = {
MuiCard: {
defaultProps: {
variant: 'outlined',
},
styleOverrides: {
root: ({ theme }) => ({
transition: theme.transitions.create(['box-shadow', 'border-color'], {
duration: theme.transitions.duration.short,
}),
'&:hover': {
boxShadow: (theme.vars || theme).shadows[4],
},
}),
},
},
MuiCardHeader: {
styleOverrides: {
root: {
padding: 16,
},
title: ({ theme }) => ({
...theme.typography.subtitle1,
fontWeight: 500,
}),
subheader: ({ theme }) => ({
...theme.typography.body2,
}),
action: {
marginTop: 0,
marginRight: 0,
},
},
},
MuiCardContent: {
styleOverrides: {
root: {
padding: 16,
'&:last-child': {
paddingBottom: 16,
},
},
},
},
MuiCardActions: {
defaultProps: {
disableSpacing: true,
},
styleOverrides: {
root: {
padding: 16,
gap: 8,
},
},
},
};
themes/mui-treasury/components/chip.ts
import { chipClasses } from '@mui/material/Chip';
import {
CONTROL_HEIGHTS,
CONTROL_TOUCH_HEIGHTS,
TOUCH_MEDIA_QUERY,
} from '../scales';
import { ThemeComponents } from '../types';
declare module '@mui/material/Chip' {
interface ChipPropsSizeOverrides {
large: true;
}
}
export const chipTheme: ThemeComponents = {
MuiChip: {
styleOverrides: {
root: ({ theme }) => ({
height: 'initial',
borderRadius: 6,
fontWeight: 400,
fontSize: theme.typography.body2.fontSize,
lineHeight: theme.typography.body2.lineHeight,
[`&.${chipClasses.focusVisible}`]: {
outline: '2px solid',
outlineColor: (theme.vars || theme).palette.text.primary,
outlineOffset: '2px',
},
variants: [
{
props: { size: 'small' },
style: {
lineHeight: 1.4285714286,
paddingBlock: CONTROL_HEIGHTS.sm / 2 - 14.5,
...(CONTROL_HEIGHTS.sm !== CONTROL_TOUCH_HEIGHTS.sm && {
[TOUCH_MEDIA_QUERY]: {
paddingBlock: CONTROL_TOUCH_HEIGHTS.sm / 2 - 14,
},
}),
},
},
{
props: { size: 'small', variant: 'outlined' },
style: {
lineHeight: 1.4285714286,
paddingBlock: CONTROL_HEIGHTS.sm / 2 - 15.5,
...(CONTROL_HEIGHTS.sm !== CONTROL_TOUCH_HEIGHTS.sm && {
[TOUCH_MEDIA_QUERY]: {
paddingBlock: CONTROL_TOUCH_HEIGHTS.sm / 2 - 15,
},
}),
},
},
{
props: { size: 'medium' },
style: {
paddingBlock: CONTROL_HEIGHTS.md / 2 - 15.5,
...(CONTROL_HEIGHTS.md !== CONTROL_TOUCH_HEIGHTS.md && {
[TOUCH_MEDIA_QUERY]: {
paddingBlock: CONTROL_TOUCH_HEIGHTS.md / 2 - 14,
},
}),
},
},
{
props: { size: 'medium', variant: 'outlined' },
style: {
paddingBlock: CONTROL_HEIGHTS.md / 2 - 16.5,
...(CONTROL_HEIGHTS.md !== CONTROL_TOUCH_HEIGHTS.md && {
[TOUCH_MEDIA_QUERY]: {
paddingBlock: CONTROL_TOUCH_HEIGHTS.md / 2 - 15,
},
}),
},
},
{
props: { size: 'large' },
style: {
paddingBlock: CONTROL_HEIGHTS.lg / 2 - 16.5,
...(CONTROL_HEIGHTS.lg !== CONTROL_TOUCH_HEIGHTS.lg && {
[TOUCH_MEDIA_QUERY]: {
paddingBlock: CONTROL_TOUCH_HEIGHTS.lg / 2 - 17,
},
}),
},
},
{
props: { size: 'large', variant: 'outlined' },
style: {
paddingBlock: CONTROL_HEIGHTS.lg / 2 - 17.5,
...(CONTROL_HEIGHTS.lg !== CONTROL_TOUCH_HEIGHTS.lg && {
[TOUCH_MEDIA_QUERY]: {
paddingBlock: CONTROL_TOUCH_HEIGHTS.lg / 2 - 18,
},
}),
},
},
{
props: { variant: 'outlined', color: 'primary' },
style: {
color: (theme.vars || theme).palette.primary.text,
},
},
{
props: { variant: 'outlined', color: 'secondary' },
style: {
color: (theme.vars || theme).palette.secondary.text,
},
},
{
props: { variant: 'outlined', color: 'success' },
style: {
color: (theme.vars || theme).palette.success.text,
},
},
{
props: { variant: 'outlined', color: 'error' },
style: {
color: (theme.vars || theme).palette.error.text,
},
},
{
props: { variant: 'outlined', color: 'warning' },
style: {
color: (theme.vars || theme).palette.warning.text,
},
},
{
props: { variant: 'outlined', color: 'info' },
style: {
color: (theme.vars || theme).palette.info.text,
},
},
// Filled variant for success, error, warning, info
{
props: { variant: 'filled' },
style: {
...theme.applyStyles('dark', {
'--_p': '60%',
}),
},
},
{
props: { variant: 'filled', color: 'success' },
style: {
color: `color-mix(in oklch, ${
(theme.vars || theme).palette.success.text
}, ${(theme.vars || theme).palette.common.onBackground} 30%)`,
backgroundColor: `color-mix(in oklch, ${
(theme.vars || theme).palette.success.main
}, ${
(theme.vars || theme).palette.common.background
} var(--_p, 80%))`,
},
},
{
props: { variant: 'filled', color: 'error' },
style: {
color: `color-mix(in oklch, ${
(theme.vars || theme).palette.error.text
}, ${(theme.vars || theme).palette.common.onBackground} 30%)`,
backgroundColor: `color-mix(in oklch, ${
(theme.vars || theme).palette.error.main
}, ${
(theme.vars || theme).palette.common.background
} var(--_p, 80%))`,
},
},
{
props: { variant: 'filled', color: 'warning' },
style: {
color: `color-mix(in oklch, ${
(theme.vars || theme).palette.warning.text
}, ${(theme.vars || theme).palette.common.onBackground} 30%)`,
backgroundColor: `color-mix(in oklch, ${
(theme.vars || theme).palette.warning.main
}, ${
(theme.vars || theme).palette.common.background
} var(--_p, 80%))`,
},
},
{
props: { variant: 'filled', color: 'info' },
style: {
color: `color-mix(in oklch, ${
(theme.vars || theme).palette.info.text
}, ${(theme.vars || theme).palette.common.onBackground} 30%)`,
backgroundColor: `color-mix(in oklch, ${
(theme.vars || theme).palette.info.main
}, ${
(theme.vars || theme).palette.common.background
} var(--_p, 80%))`,
},
},
{
props: { clickable: true },
style: {
'&:active': {
transform: 'scale(0.98)',
},
},
},
],
}),
label: {
variants: [
{
props: { size: 'medium' },
style: {
paddingInline: CONTROL_HEIGHTS.md / 2 - 8,
},
},
],
},
icon: {
fontSize: '1.125rem',
variants: [
{
props: { size: 'small' },
style: {
fontSize: '1rem',
},
},
],
},
deleteIcon: ({ theme }) => ({
fontSize: '1lh',
'&:active': {
transform: 'scale(0.97)',
},
variants: [
{
props: { color: 'default' },
style: {
color: (theme.vars || theme).palette.text.icon,
'&:hover': {
color: (theme.vars || theme).palette.text.secondary,
},
},
},
],
}),
},
},
};
themes/mui-treasury/components/controls.tsx
import React from 'react';
import { buttonBaseClasses } from '@mui/material/ButtonBase';
import { switchClasses } from '@mui/material/Switch';
import { styled } from '@mui/material/styles';
import { createSvgIcon } from '@mui/material/utils';
import {
CONTROL_HEIGHTS,
CONTROL_TOUCH_HEIGHTS,
SWITCH_SIZES,
SWITCH_TOUCH_SIZES,
TOUCH_MEDIA_QUERY,
} from '../scales';
import { ThemeComponents } from '../types';
declare module '@mui/material/Radio' {
interface RadioPropsSizeOverrides {
large: true;
}
}
declare module '@mui/material/Switch' {
interface SwitchPropsSizeOverrides {
large: true;
}
}
const borderWidth = 1;
const CheckIcon = createSvgIcon(
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"
color="currentColor"
fill="none"
>
<defs />
<path
fill="currentColor"
d="M11.943,1.75 L12.057,1.75 C14.248,1.75 15.969,1.75 17.312,1.931 C18.689,2.116 19.781,2.503 20.639,3.361 C21.497,4.219 21.884,5.311 22.069,6.688 C22.25,8.031 22.25,9.752 22.25,11.943 L22.25,12.057 C22.25,14.248 22.25,15.969 22.069,17.312 C21.884,18.689 21.497,19.781 20.639,20.639 C19.781,21.497 18.689,21.884 17.312,22.069 C15.969,22.25 14.248,22.25 12.057,22.25 L11.943,22.25 C9.752,22.25 8.031,22.25 6.688,22.069 C5.311,21.884 4.219,21.497 3.361,20.639 C2.503,19.781 2.116,18.689 1.931,17.312 C1.75,15.969 1.75,14.248 1.75,12.057 L1.75,11.943 C1.75,9.752 1.75,8.031 1.931,6.688 C2.116,5.311 2.503,4.219 3.361,3.361 C4.219,2.503 5.311,2.116 6.688,1.931 C8.031,1.75 9.752,1.75 11.943,1.75 L11.943,1.75 Z M4.422,4.422 C3.889,4.955 3.58,5.678 3.417,6.888 C3.252,8.12 3.25,9.74 3.25,12 C3.25,14.26 3.252,15.88 3.417,17.112 C3.58,18.322 3.889,19.045 4.422,19.578 C4.955,20.111 5.678,20.42 6.888,20.583 C8.12,20.748 9.74,20.75 12,20.75 C14.26,20.75 15.88,20.748 17.112,20.583 C18.322,20.42 19.045,20.111 19.578,19.578 C20.111,19.045 20.42,18.322 20.583,17.112 C20.748,15.88 20.75,14.26 20.75,12 C20.75,9.74 20.748,8.12 20.583,6.888 C20.42,5.678 20.111,4.955 19.578,4.422 C19.045,3.889 18.322,3.58 17.112,3.417 C15.88,3.252 14.26,3.25 12,3.25 C9.74,3.25 8.12,3.252 6.888,3.417 C5.678,3.58 4.955,3.889 4.422,4.422 Z M16.553,9.507 L11.053,15.507 C10.915,15.658 10.721,15.745 10.516,15.75 C10.312,15.754 10.114,15.675 9.97,15.53 L7.47,13.03 C7.177,12.737 7.177,12.263 7.47,11.97 C7.763,11.677 8.237,11.677 8.53,11.97 L10.476,13.916 L15.447,8.493 C15.727,8.188 16.201,8.167 16.507,8.447 C16.812,8.727 16.833,9.201 16.553,9.507 Z"
/>
</svg>,
'CheckOutline',
);
const CheckBorderIcon = createSvgIcon(
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"
color="currentColor"
fill="none"
>
<defs />
<path
fill="currentColor"
d="M11.943,1.75 L12.057,1.75 C14.248,1.75 15.969,1.75 17.312,1.931 C18.689,2.116 19.781,2.503 20.639,3.361 C21.497,4.219 21.884,5.311 22.069,6.688 C22.25,8.031 22.25,9.752 22.25,11.943 L22.25,12.057 C22.25,14.248 22.25,15.969 22.069,17.312 C21.884,18.689 21.497,19.781 20.639,20.639 C19.781,21.497 18.689,21.884 17.312,22.069 C15.969,22.25 14.248,22.25 12.057,22.25 L11.943,22.25 C9.752,22.25 8.031,22.25 6.688,22.069 C5.311,21.884 4.219,21.497 3.361,20.639 C2.503,19.781 2.116,18.689 1.931,17.312 C1.75,15.969 1.75,14.248 1.75,12.057 L1.75,11.943 C1.75,9.752 1.75,8.031 1.931,6.688 C2.116,5.311 2.503,4.219 3.361,3.361 C4.219,2.503 5.311,2.116 6.688,1.931 C8.031,1.75 9.752,1.75 11.943,1.75 L11.943,1.75 Z M4.422,4.422 C3.889,4.955 3.58,5.678 3.417,6.888 C3.252,8.12 3.25,9.74 3.25,12 C3.25,14.26 3.252,15.88 3.417,17.112 C3.58,18.322 3.889,19.045 4.422,19.578 C4.955,20.111 5.678,20.42 6.888,20.583 C8.12,20.748 9.74,20.75 12,20.75 C14.26,20.75 15.88,20.748 17.112,20.583 C18.322,20.42 19.045,20.111 19.578,19.578 C20.111,19.045 20.42,18.322 20.583,17.112 C20.748,15.88 20.75,14.26 20.75,12 C20.75,9.74 20.748,8.12 20.583,6.888 C20.42,5.678 20.111,4.955 19.578,4.422 C19.045,3.889 18.322,3.58 17.112,3.417 C15.88,3.252 14.26,3.25 12,3.25 C9.74,3.25 8.12,3.252 6.888,3.417 C5.678,3.58 4.955,3.889 4.422,4.422 Z"
/>
</svg>,
'CheckBorder',
);
const IntermediateIcon = createSvgIcon(
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"
color="currentColor"
fill="none"
>
<defs />
<path
fill="currentColor"
d="M11.943,1.75 L12.057,1.75 C14.248,1.75 15.969,1.75 17.312,1.931 C18.689,2.116 19.781,2.503 20.639,3.361 C21.497,4.219 21.884,5.311 22.069,6.688 C22.25,8.031 22.25,9.752 22.25,11.943 L22.25,12.057 C22.25,14.248 22.25,15.969 22.069,17.312 C21.884,18.689 21.497,19.781 20.639,20.639 C19.781,21.497 18.689,21.884 17.312,22.069 C15.969,22.25 14.248,22.25 12.057,22.25 L11.943,22.25 C9.752,22.25 8.031,22.25 6.688,22.069 C5.311,21.884 4.219,21.497 3.361,20.639 C2.503,19.781 2.116,18.689 1.931,17.312 C1.75,15.969 1.75,14.248 1.75,12.057 L1.75,11.943 C1.75,9.752 1.75,8.031 1.931,6.688 C2.116,5.311 2.503,4.219 3.361,3.361 C4.219,2.503 5.311,2.116 6.688,1.931 C8.031,1.75 9.752,1.75 11.943,1.75 L11.943,1.75 Z M4.422,4.422 C3.889,4.955 3.58,5.678 3.417,6.888 C3.252,8.12 3.25,9.74 3.25,12 C3.25,14.26 3.252,15.88 3.417,17.112 C3.58,18.322 3.889,19.045 4.422,19.578 C4.955,20.111 5.678,20.42 6.888,20.583 C8.12,20.748 9.74,20.75 12,20.75 C14.26,20.75 15.88,20.748 17.112,20.583 C18.322,20.42 19.045,20.111 19.578,19.578 C20.111,19.045 20.42,18.322 20.583,17.112 C20.748,15.88 20.75,14.26 20.75,12 C20.75,9.74 20.748,8.12 20.583,6.888 C20.42,5.678 20.111,4.955 19.578,4.422 C19.045,3.889 18.322,3.58 17.112,3.417 C15.88,3.252 14.26,3.25 12,3.25 C9.74,3.25 8.12,3.252 6.888,3.417 C5.678,3.58 4.955,3.889 4.422,4.422 Z M8,11.25 L16,11.25 C16.414,11.25 16.75,11.586 16.75,12 C16.75,12.414 16.414,12.75 16,12.75 L8,12.75 C7.586,12.75 7.25,12.414 7.25,12 C7.25,11.586 7.586,11.25 8,11.25 Z"
/>
</svg>,
'IndeterminateCheckBox',
);
const Unradio = styled('span')(({ theme }) => ({
display: 'inline-block',
boxSizing: 'border-box',
width: '1.5rem',
height: '1.5rem',
padding: 2,
borderRadius: '50%',
color: (theme.vars || theme).palette.text.icon,
'.MuiRadio-root:hover &, .MuiFormControlLabel-root:hover &': {
color: (theme.vars || theme).palette.text.primary,
},
'&::before': {
content: '""',
display: 'block',
width: '100%',
height: '100%',
border: '1px solid',
borderColor: 'currentColor',
borderRadius: 'inherit',
},
'&[font-size="large"]': {
width: '1.75rem',
height: '1.75rem',
},
}));
const RadioIcon = createSvgIcon(
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
>
<circle cx="12" cy="12" r="10" />
<circle cx="12" cy="12" r="2" fill="currentColor" />
</svg>,
'RadioIcon',
);
const iconSize = 24; // 1.5rem icon size
export const controlsTheme: ThemeComponents = {
MuiCheckbox: {
defaultProps: {
icon: <CheckBorderIcon />,
checkedIcon: <CheckIcon />,
indeterminateIcon: <IntermediateIcon />,
},
styleOverrides: {
root: {
borderRadius: 12,
variants: [
{
props: { size: 'small' },
style: {
'--Icon-size': '1.5rem',
padding: (CONTROL_HEIGHTS.sm - iconSize) / 2,
[TOUCH_MEDIA_QUERY]: {
...(CONTROL_HEIGHTS.sm !== CONTROL_TOUCH_HEIGHTS.sm && {
padding: (CONTROL_TOUCH_HEIGHTS.sm - iconSize) / 2,
}),
},
},
},
{
props: { size: 'medium' },
style: {
'--Icon-size': '1.5rem',
padding: (CONTROL_HEIGHTS.md - iconSize) / 2,
[TOUCH_MEDIA_QUERY]: {
...(CONTROL_HEIGHTS.md !== CONTROL_TOUCH_HEIGHTS.md && {
padding: (CONTROL_TOUCH_HEIGHTS.md - iconSize) / 2,
}),
},
},
},
{
props: { size: 'large' },
style: {
'--Icon-size': '1.75rem',
padding: (CONTROL_HEIGHTS.lg - iconSize) / 2 - 2,
[TOUCH_MEDIA_QUERY]: {
...(CONTROL_HEIGHTS.lg !== CONTROL_TOUCH_HEIGHTS.lg && {
padding: (CONTROL_TOUCH_HEIGHTS.lg - iconSize) / 2 - 2,
}),
},
},
},
],
[`&.${buttonBaseClasses.focusVisible}`]: {
outline: '2px solid',
outlineOffset: '-2px',
},
},
},
},
MuiRadio: {
defaultProps: {
icon: <Unradio />,
checkedIcon: <RadioIcon />,
},
styleOverrides: {
root: {
variants: [
{
props: { size: 'small' },
style: {
'--Icon-size': '1.5rem',
padding: (CONTROL_HEIGHTS.sm - iconSize) / 2,
[TOUCH_MEDIA_QUERY]: {
...(CONTROL_HEIGHTS.sm !== CONTROL_TOUCH_HEIGHTS.sm && {
padding: (CONTROL_TOUCH_HEIGHTS.sm - iconSize) / 2,
}),
},
},
},
{
props: { size: 'medium' },
style: {
'--Icon-size': '1.5rem',
padding: (CONTROL_HEIGHTS.md - iconSize) / 2,
[TOUCH_MEDIA_QUERY]: {
...(CONTROL_HEIGHTS.md !== CONTROL_TOUCH_HEIGHTS.md && {
padding: (CONTROL_TOUCH_HEIGHTS.md - iconSize) / 2,
}),
},
},
},
{
props: { size: 'large' },
style: {
'--Icon-size': '1.75rem',
padding: (CONTROL_HEIGHTS.lg - iconSize) / 2 - 2,
[TOUCH_MEDIA_QUERY]: {
...(CONTROL_HEIGHTS.lg !== CONTROL_TOUCH_HEIGHTS.lg && {
padding: (CONTROL_TOUCH_HEIGHTS.lg - iconSize) / 2 - 2,
}),
},
},
},
],
[`&.${buttonBaseClasses.focusVisible}`]: {
outline: '2px solid',
outlineOffset: '-2px',
},
},
},
},
MuiSwitch: {
styleOverrides: {
root: ({ theme }) => ({
'--_h': `${SWITCH_SIZES.md.height}px`,
'--_w': `${SWITCH_SIZES.md.width}px`,
'--_inset': `${SWITCH_SIZES.md.inset}px`,
'--_b': '1px',
'--_thumb-size': 'calc(var(--_h) - var(--_b) * 2 - var(--_inset) * 2)',
'--_thumb-w': 'var(--_thumb-size)',
'--_thumb-h': 'var(--_thumb-size)',
'--mui-opacity-switchTrackDisabled': '0.5',
width: 'var(--_w)',
height: 'var(--_h)',
padding: 0,
borderRadius: 'var(--_h)',
[`&:has(.${buttonBaseClasses.focusVisible})`]: {
outline: '2px solid',
outlineOffset: '4px',
outlineColor: (theme.vars || theme).palette.text.primary,
},
[TOUCH_MEDIA_QUERY]: {
...(SWITCH_SIZES.md.height !== SWITCH_TOUCH_SIZES.md.height && {
'--_h': `${SWITCH_TOUCH_SIZES.md.height}px`,
}),
...(SWITCH_SIZES.md.width !== SWITCH_TOUCH_SIZES.md.width && {
'--_w': `${SWITCH_TOUCH_SIZES.md.width}px`,
}),
...(SWITCH_SIZES.md.inset !== SWITCH_TOUCH_SIZES.md.inset && {
'--_inset': `${SWITCH_TOUCH_SIZES.md.inset}px`,
}),
},
variants: [
{
props: { size: 'small' },
style: {
'--_h': `${SWITCH_SIZES.sm.height}px`,
'--_w': `${SWITCH_SIZES.sm.width}px`,
'--_inset': `${SWITCH_SIZES.sm.inset}px`,
[TOUCH_MEDIA_QUERY]: {
...(SWITCH_SIZES.sm.height !== SWITCH_TOUCH_SIZES.sm.height && {
'--_h': `${SWITCH_TOUCH_SIZES.sm.height}px`,
}),
...(SWITCH_SIZES.sm.width !== SWITCH_TOUCH_SIZES.sm.width && {
'--_w': `${SWITCH_TOUCH_SIZES.sm.width}px`,
}),
...(SWITCH_SIZES.sm.inset !== SWITCH_TOUCH_SIZES.sm.inset && {
'--_inset': `${SWITCH_TOUCH_SIZES.sm.inset}px`,
}),
},
},
},
{
props: { size: 'large' },
style: {
'--_h': `${SWITCH_SIZES.lg.height}px`,
'--_w': `${SWITCH_SIZES.lg.width}px`,
'--_inset': `${SWITCH_SIZES.lg.inset}px`,
[TOUCH_MEDIA_QUERY]: {
...(SWITCH_SIZES.lg.height !== SWITCH_TOUCH_SIZES.lg.height && {
'--_h': `${SWITCH_TOUCH_SIZES.lg.height}px`,
}),
...(SWITCH_SIZES.lg.width !== SWITCH_TOUCH_SIZES.lg.width && {
'--_w': `${SWITCH_TOUCH_SIZES.lg.width}px`,
}),
...(SWITCH_SIZES.lg.inset !== SWITCH_TOUCH_SIZES.lg.inset && {
'--_inset': `${SWITCH_TOUCH_SIZES.lg.inset}px`,
}),
},
},
},
],
[`& .${switchClasses.switchBase}`]: {
padding: borderWidth,
top: 'var(--_inset)',
left: 'var(--_inset)',
[`& .${switchClasses.input}`]: {
top: 'calc(var(--_inset) * -1)',
height: 'var(--_h)',
},
[`&.${switchClasses.checked}`]: {
color: (theme.vars || theme).palette.common.white,
transform: `translateX(calc(var(--_w) - var(--_thumb-w) - var(--_b) * 2 - var(--_inset) * 2))`,
...theme.applyStyles('dark', {
[`& .${switchClasses.thumb}`]: {
background: (theme.vars || theme).palette.grey[900],
},
}),
},
[`&.${switchClasses.checked}:not(.${switchClasses.disabled}) + .${switchClasses.track}`]:
{
opacity: 1,
border: 'none',
},
'&:active': {
'--_thumb-w': 'calc(var(--_thumb-size) + 4px)',
},
[`&.${switchClasses.disabled}`]: {
[`& .${switchClasses.thumb}`]: {
opacity: theme.vars.opacity.switchTrackDisabled,
},
},
},
[`& .${switchClasses.thumb}`]: {
borderRadius: 'var(--_thumb-size)',
background: (theme.vars || theme).palette.common.white,
width: 'var(--_thumb-w)',
height: 'var(--_thumb-h)',
boxShadow:
'0 3px 8px 0 rgba(0,0,0,0.1), 0 1px 1px 0 rgba(0,0,0,0.12), 0 3px 1px 0 rgba(0,0,0,0.08)',
transition: 'width 120ms ease-out 0ms',
},
[`& .${switchClasses.track}`]: {
borderRadius: 'var(--_thumb-size)',
border: `solid ${(theme.vars || theme).palette.grey[300]}`,
borderWidth,
backgroundColor: (theme.vars || theme).palette.grey[300],
opacity: 1,
transition: 'none',
...theme.applyStyles('dark', {
border: `solid ${(theme.vars || theme).palette.grey[700]}`,
backgroundColor: (theme.vars || theme).palette.grey[900],
}),
},
}),
},
},
MuiFormControlLabel: {
styleOverrides: {
root: ({ theme }) => ({
gap: 'var(--_gap)',
marginLeft: -4,
[`&:has(.${switchClasses.root})`]: {
'--_gap': theme.spacing(1),
margin: 0,
},
}),
},
},
};
themes/mui-treasury/components/data-grid.ts
import { iconButtonClasses } from '@mui/material/IconButton';
import type {} from '@mui/x-data-grid/themeAugmentation';
import { ThemeComponents } from '../types';
export const dataGridTheme: ThemeComponents = {
MuiDataGrid: {
styleOverrides: {
root: ({ theme }) => ({
borderRadius: (theme.vars || theme).shape.borderRadius,
border: `1px solid ${(theme.vars || theme).palette.divider}`,
backgroundColor: (theme.vars || theme).palette.background.paper,
}),
cell: ({ theme }) => ({
borderBottomColor: (theme.vars || theme).palette.divider,
fontSize: theme.typography.body2.fontSize,
padding: '0 16px',
'&:focus': {
outline: 'none',
},
'&:focus-within': {
outline: `2px solid ${(theme.vars || theme).palette.primary.main}`,
outlineOffset: -2,
},
}),
columnHeader: ({ theme }) => ({
backgroundColor: `color-mix(in srgb, ${
(theme.vars || theme).palette.secondary.main
}, ${(theme.vars || theme).palette.common.background} 60%)`,
borderBottomColor: (theme.vars || theme).palette.divider,
fontSize: theme.typography.body2.fontSize,
fontWeight: 600,
color: (theme.vars || theme).palette.text.primary,
'&:focus': {
outline: 'none',
},
'&:focus-within': {
outline: `2px solid ${(theme.vars || theme).palette.primary.main}`,
outlineOffset: -2,
},
}),
columnSeparator: ({ theme }) => ({
color: (theme.vars || theme).palette.divider,
}),
menuIconButton: {
opacity: 0.5,
'&:hover': {
opacity: 1,
},
},
iconButtonContainer: {
[`& .${iconButtonClasses.root}`]: {
padding: 4,
},
},
row: ({ theme }) => ({
'&:hover': {
backgroundColor: (theme.vars || theme).palette.action.hover,
},
'&.Mui-selected': {
backgroundColor: (theme.vars || theme).palette.action.selected,
'&:hover': {
backgroundColor: (theme.vars || theme).palette.action.selected,
},
},
}),
footerContainer: ({ theme }) => ({
borderTop: `1px solid ${(theme.vars || theme).palette.divider}`,
minHeight: 52,
}),
checkboxInput: {
padding: 4,
},
columnHeaderTitle: {
fontWeight: 600,
},
toolbarContainer: ({ theme }) => ({
padding: '16px',
gap: 16,
borderBottom: `1px solid ${(theme.vars || theme).palette.divider}`,
}),
virtualScroller: {
'&::-webkit-scrollbar': {
width: '8px',
height: '8px',
},
'&::-webkit-scrollbar-track': {
backgroundColor: 'transparent',
},
'&::-webkit-scrollbar-thumb': {
backgroundColor: 'rgba(0, 0, 0, 0.2)',
borderRadius: '4px',
'&:hover': {
backgroundColor: 'rgba(0, 0, 0, 0.3)',
},
},
},
overlayWrapper: {
minHeight: 240,
},
overlay: ({ theme }) => ({
backgroundColor: 'rgba(255, 255, 255, 0.9)',
...theme.applyStyles('dark', {
backgroundColor: 'rgba(0, 0, 0, 0.9)',
}),
}),
},
},
};
themes/mui-treasury/components/date-picker.ts
import { formLabelClasses } from '@mui/material/FormLabel';
import { iconButtonClasses } from '@mui/material/IconButton';
import { inputLabelClasses } from '@mui/material/InputLabel';
import {
pickersInputBaseClasses,
pickersOutlinedInputClasses,
} from '@mui/x-date-pickers';
import { pickerDayClasses } from '@mui/x-date-pickers/PickerDay';
import { pickersCalendarHeaderClasses } from '@mui/x-date-pickers/PickersCalendarHeader';
import { pickersSectionListClasses } from '@mui/x-date-pickers/PickersSectionList';
import type {} from '@mui/x-date-pickers/themeAugmentation';
import {
CONTROL_HEIGHTS,
CONTROL_TOUCH_HEIGHTS,
TOUCH_MEDIA_QUERY,
} from '../scales';
import { ThemeComponents } from '../types';
export const datePickerTheme: ThemeComponents = {
MuiPickersTextField: {
defaultProps: {
variant: 'outlined',
},
styleOverrides: {
root: ({ theme }) => ({
variants: [
{
props: { variant: 'outlined' },
style: {
[`& .${formLabelClasses.root}, & .${inputLabelClasses.root}.${inputLabelClasses.shrink}`]:
{
position: 'static',
transform: 'none',
pointerEvents: 'auto',
marginBottom: '0.25rem',
maxWidth: 'unset',
fontWeight: 500,
lineHeight: 1.5,
color: (theme.vars || theme).palette.text.primary,
},
[`& .${pickersSectionListClasses.root}`]: {
paddingBlock: CONTROL_HEIGHTS.md / 2 - 10.5,
...(CONTROL_HEIGHTS.md !== CONTROL_TOUCH_HEIGHTS.md && {
[TOUCH_MEDIA_QUERY]: {
paddingBlock: CONTROL_TOUCH_HEIGHTS.md / 2 - 10.5,
},
}),
},
[`& .${pickersSectionListClasses.section}`]: {
lineHeight: 1.5,
},
[`& .${iconButtonClasses.root}`]: {
'&:hover': {
color: (theme.vars || theme).palette.text.primary,
backgroundColor: 'transparent',
},
},
[`&&& .${pickersInputBaseClasses.input}`]: {
'&::-webkit-input-placeholder': {
opacity: '0.42 !important',
},
'&::-moz-placeholder': {
opacity: '0.42 !important',
},
'&::-ms-input-placeholder': {
opacity: '0.42 !important',
},
},
[`&& .${pickersOutlinedInputClasses.notchedOutline}`]: {
transition: 'none',
'& legend': {
width: 0,
},
},
},
},
{
props: { variant: 'outlined', size: 'small' },
style: {
[`& .${pickersOutlinedInputClasses.root}`]: {
paddingLeft: 12,
},
[`& .${pickersSectionListClasses.root}`]: {
paddingBlock: CONTROL_HEIGHTS.sm / 2 - 10.5,
...(CONTROL_HEIGHTS.sm !== CONTROL_TOUCH_HEIGHTS.sm && {
[TOUCH_MEDIA_QUERY]: {
paddingBlock: CONTROL_TOUCH_HEIGHTS.sm / 2 - 10.5,
},
}),
},
[`& .${iconButtonClasses.root}`]: {
padding: '4px',
},
},
},
{
props: { variant: 'outlined', size: 'large' },
style: {
[`& .${pickersOutlinedInputClasses.root}`]: {
fontSize: '1rem',
},
[`& .${pickersSectionListClasses.root}`]: {
paddingBlock: CONTROL_HEIGHTS.lg / 2 - 10.5,
...(CONTROL_HEIGHTS.lg !== CONTROL_TOUCH_HEIGHTS.lg && {
[TOUCH_MEDIA_QUERY]: {
paddingBlock: CONTROL_TOUCH_HEIGHTS.lg / 2 - 10.5,
},
}),
},
},
},
],
}),
},
},
MuiPickersInputBase: {
styleOverrides: {
root: ({ theme }) => ({
fontSize: theme.typography.body2.fontSize,
variants: [
{
props: { size: 'small' },
style: {
fontSize: theme.typography.body2.fontSize,
},
},
],
}),
},
},
MuiPickerDay: {
styleOverrides: {
root: ({ theme }) => ({
borderRadius: (theme.vars || theme).shape.borderRadius,
[`&.${pickerDayClasses.today}`]: {
border: `1px solid ${(theme.vars || theme).palette.primary.main}`,
[`&:not(.${pickerDayClasses.selected})`]: {
backgroundColor: 'transparent',
},
},
}),
},
},
MuiPickersCalendarHeader: {
styleOverrides: {
root: {
[`& .${pickersCalendarHeaderClasses.label}`]: {
fontWeight: 500,
},
},
switchViewButton: {
marginRight: 0,
},
},
},
MuiPickersToolbar: {
styleOverrides: {
root: ({ theme }) => ({
borderBottom: `1px solid ${(theme.vars || theme).palette.divider}`,
}),
},
},
MuiPickerPopper: {
styleOverrides: {
paper: ({ theme }) => ({
marginTop: 8,
border: `1px solid ${(theme.vars || theme).palette.divider}`,
}),
},
},
MuiPickersSectionList: {
styleOverrides: {
root: {
[`&.${pickersInputBaseClasses.sectionsContainer}`]: {
opacity: 1,
},
},
},
},
};
themes/mui-treasury/components/dialog.ts
import { dialogClasses } from '@mui/material/Dialog';
import { dialogContentClasses } from '@mui/material/DialogContent';
import { ThemeComponents } from '../types';
export const dialogTheme: ThemeComponents = {
MuiDialog: {
styleOverrides: {
root: ({ theme }) => ({
'--_spacing-row': '16px',
'--_spacing-col': '20px',
'--_edge': '16px',
[theme.breakpoints.up('md')]: {
'--_spacing-row': '20px',
'--_spacing-col': '24px',
},
}),
paper: ({ theme }) => ({
[`&:not(.${dialogClasses.paperFullScreen})`]: {
borderRadius: (theme.vars || theme).shape.borderRadius,
boxShadow: (theme.vars || theme).shadows[8],
width: 'calc(100% - var(--_edge))',
margin: 'var(--_edge)',
},
}),
},
},
MuiDialogTitle: {
styleOverrides: {
root: {
padding: 'var(--_spacing-row) var(--_spacing-col)',
fontSize: '1.25rem',
fontWeight: 500,
},
},
},
MuiDialogContent: {
styleOverrides: {
root: {
padding: '0 var(--_spacing-col) var(--_spacing-row)',
},
dividers: ({ theme }) => ({
padding: 'var(--_spacing-row) var(--_spacing-col)',
borderTop: '1px solid',
borderBottom: '1px solid',
borderColor: (theme.vars || theme).palette.divider,
}),
},
},
MuiDialogActions: {
defaultProps: {
disableSpacing: true,
},
styleOverrides: {
root: {
padding: '0px var(--_spacing-col) var(--_spacing-row)',
gap: 8,
[`.${dialogContentClasses.dividers} + &`]: {
paddingTop: 'var(--_spacing-row)',
},
},
},
},
MuiDialogContentText: {
styleOverrides: {
root: ({ theme }) => ({
color: theme.vars.palette.text.secondary,
marginBottom: 0,
}),
},
},
};
themes/mui-treasury/components/layout.ts
import { ThemeComponents } from '../types';
export const layoutTheme: ThemeComponents = {
MuiStack: {
defaultProps: {
useFlexGap: true,
},
},
};
themes/mui-treasury/components/link.ts
import { ThemeComponents } from '../types';
export const linkTheme: ThemeComponents = {
MuiLink: {
styleOverrides: {
root: {
verticalAlign: 'var(--va)', // for button inside Typography to align properly with text
'&:focus-visible': {
outlineOffset: '4px',
outlineColor: 'var(--Link-underlineColor)',
},
},
},
},
};
themes/mui-treasury/components/list.ts
import { ThemeComponents } from '../types';
export const listTheme: ThemeComponents = {
MuiListItemAvatar: {
styleOverrides: {
root: {
minWidth: 'unset',
},
},
},
};
themes/mui-treasury/components/menu.ts
import { menuItemClasses } from '@mui/material/MenuItem';
import { ThemeComponents } from '../types';
export const menuTheme: ThemeComponents = {
MuiMenu: {
defaultProps: {
slotProps: {
paper: {
elevation: 0,
variant: 'outlined',
},
},
},
styleOverrides: {
paper: ({ theme }) => ({
marginTop: 4,
borderRadius: 8,
border: `1px solid ${(theme.vars || theme).palette.divider}`,
boxShadow: (theme.vars || theme).shadows[8],
}),
list: {
padding: '6px',
display: 'flex',
flexDirection: 'column',
gap: '4px',
},
},
},
MuiMenuItem: {
styleOverrides: {
root: ({ theme }) => ({
fontSize: theme.typography.body2.fontSize,
padding: '6px',
borderRadius: 4,
minHeight: 40,
margin: 0,
transition: theme.transitions.create(['background-color'], {
duration: theme.transitions.duration.shortest,
}),
'&:hover': {
backgroundColor: (theme.vars || theme).palette.action.hover,
},
[`&.${menuItemClasses.selected}`]: {
backgroundColor: (theme.vars || theme).palette.action.selected,
'&:hover': {
backgroundColor: (theme.vars || theme).palette.action.selected,
},
},
[`&.${menuItemClasses.focusVisible}`]: {
backgroundColor: (theme.vars || theme).palette.action.focus,
},
variants: [
{
props: { dense: true },
style: {
padding: '4px 8px',
},
},
],
}),
},
},
};
themes/mui-treasury/components/progress.ts
import { ThemeComponents } from '../types';
export const progressTheme: ThemeComponents = {
MuiCircularProgress: {
styleOverrides: {
circle: {
strokeLinecap: 'round',
},
},
},
};
themes/mui-treasury/components/select.ts
import { filledInputClasses } from '@mui/material/FilledInput';
import { inputBaseClasses } from '@mui/material/InputBase';
import { outlinedInputClasses } from '@mui/material/OutlinedInput';
import { selectClasses } from '@mui/material/Select';
import {
CONTROL_HEIGHTS,
CONTROL_TOUCH_HEIGHTS,
TOUCH_MEDIA_QUERY,
} from '../scales';
import { ThemeComponents } from '../types';
export const selectTheme: ThemeComponents = {
MuiSelect: {
styleOverrides: {
root: {
[`&.${outlinedInputClasses.root}.MuiInputBase-sizeLarge`]: {
[`& .${selectClasses.select}`]: {
paddingBlock: CONTROL_HEIGHTS.lg / 2 - 12,
...(CONTROL_HEIGHTS.lg !== CONTROL_TOUCH_HEIGHTS.lg && {
[TOUCH_MEDIA_QUERY]: {
paddingBlock: CONTROL_TOUCH_HEIGHTS.lg / 2 - 11.5,
},
}),
},
},
},
select: {
minHeight: '1.5em',
[`&.${outlinedInputClasses.input}`]: {
paddingBlock: CONTROL_HEIGHTS.md / 2 - 10,
paddingInline: 14,
minHeight: '1.42857em', // 20px
...(CONTROL_HEIGHTS.md !== CONTROL_TOUCH_HEIGHTS.md && {
[TOUCH_MEDIA_QUERY]: {
paddingBlock: CONTROL_TOUCH_HEIGHTS.md / 2 - 11.5,
},
}),
[`.${inputBaseClasses.sizeSmall} > &`]: {
paddingBlock: CONTROL_HEIGHTS.sm / 2 - 10,
paddingInline: 12,
...(CONTROL_HEIGHTS.sm !== CONTROL_TOUCH_HEIGHTS.sm && {
[TOUCH_MEDIA_QUERY]: {
paddingBlock: CONTROL_TOUCH_HEIGHTS.sm / 2 - 11.5,
},
}),
},
},
[`&.${filledInputClasses.input}`]: {
paddingTop: CONTROL_HEIGHTS.md / 2 + 5,
paddingInline: 12,
paddingBottom: CONTROL_HEIGHTS.md / 2 - 12,
...(CONTROL_HEIGHTS.md !== CONTROL_TOUCH_HEIGHTS.md && {
[TOUCH_MEDIA_QUERY]: {
paddingTop: CONTROL_TOUCH_HEIGHTS.md / 2 + 5,
paddingBottom: CONTROL_TOUCH_HEIGHTS.md / 2 - 12,
},
}),
[`.${inputBaseClasses.sizeSmall} > &`]: {
paddingTop: CONTROL_HEIGHTS.sm / 2 + 4,
paddingInline: 10,
paddingBottom: CONTROL_HEIGHTS.sm / 2 - 13,
...(CONTROL_HEIGHTS.sm !== CONTROL_TOUCH_HEIGHTS.sm && {
[TOUCH_MEDIA_QUERY]: {
paddingTop: CONTROL_TOUCH_HEIGHTS.sm / 2 + 4,
paddingBottom: CONTROL_TOUCH_HEIGHTS.sm / 2 - 13,
},
}),
},
},
[`&.${inputBaseClasses.input}.${inputBaseClasses.input}`]: {
paddingRight: 32,
},
},
icon: ({ theme }) => ({
color: (theme.vars || theme).palette.text.secondary,
right: 8,
transition: theme.transitions.create(['transform'], {
duration: theme.transitions.duration.shorter,
}),
}),
iconOpen: {
transform: 'rotate(180deg)',
},
},
},
};
themes/mui-treasury/components/svg-icon.ts
import { ThemeComponents } from '../types';
export const svgIconTheme: ThemeComponents = {
MuiSvgIcon: {
styleOverrides: {
root: ({ theme }) => ({
color: `var(--Icon-color, ${(theme.vars || theme).palette.text.icon})`,
variants: [
{
props: { fontSize: 'small' },
style: {
fontSize: 'var(--Icon-size, 1.125rem)', // 18px
},
},
{
props: { fontSize: 'medium' },
style: {
fontSize: 'var(--Icon-size, 1.25rem)', // 20px
},
},
{
props: { fontSize: 'large' },
style: {
fontSize: 'var(--Icon-size, 2rem)', // 32px
},
},
{
props: { color: 'primary' },
style: {
'--Icon-color': (theme.vars || theme).palette.primary.main,
},
},
{
props: { color: 'secondary' },
style: {
'--Icon-color': (theme.vars || theme).palette.secondary.main,
},
},
{
props: { color: 'success' },
style: {
'--Icon-color': (theme.vars || theme).palette.success.main,
},
},
{
props: { color: 'error' },
style: {
'--Icon-color': (theme.vars || theme).palette.error.main,
},
},
{
props: { color: 'warning' },
style: {
'--Icon-color': (theme.vars || theme).palette.warning.main,
},
},
{
props: { color: 'info' },
style: {
'--Icon-color': (theme.vars || theme).palette.info.main,
},
},
],
}),
},
},
};
themes/mui-treasury/components/table.ts
import { buttonBaseClasses } from '@mui/material/ButtonBase';
import { paginationItemClasses } from '@mui/material/PaginationItem';
import { tableRowClasses } from '@mui/material/TableRow';
import { tableSortLabelClasses } from '@mui/material/TableSortLabel';
import { ThemeComponents } from '../types';
export const tableTheme: ThemeComponents = {
MuiTable: {
styleOverrides: {
root: {
tableLayout: 'fixed',
},
},
},
MuiTableCell: {
styleOverrides: {
root: ({ theme }) => ({
borderBottomColor: (theme.vars || theme).palette.divider,
fontSize: theme.typography.body2.fontSize,
padding: '14px 24px 14px 12px',
}),
head: ({ theme }) => ({
fontWeight: 600,
color: (theme.vars || theme).palette.text.primary,
backgroundColor: `color-mix(in srgb, ${
(theme.vars || theme).palette.secondary.main
}, ${(theme.vars || theme).palette.common.background} 60%)`,
}),
sizeSmall: {
padding: '6px 16px 6px 12px',
},
},
},
MuiTableRow: {
styleOverrides: {
root: ({ theme }) => ({
'tbody > &:last-child td, tbody > &:last-child th': {
borderBottom: 0,
},
[`&.${tableRowClasses.hover}:hover`]: {
backgroundColor: (theme.vars || theme).palette.action.hover,
},
[`&.${tableRowClasses.selected}`]: {
backgroundColor: (theme.vars || theme).palette.action.selected,
'&:hover': {
backgroundColor: (theme.vars || theme).palette.action.selected,
},
},
}),
},
},
MuiTableContainer: {
styleOverrides: {
root: ({ theme }) => ({
borderRadius: (theme.vars || theme).shape.borderRadius,
border: `1px solid ${(theme.vars || theme).palette.divider}`,
}),
},
},
MuiTablePagination: {
styleOverrides: {
root: ({ theme }) => ({
borderTop: `1px solid ${(theme.vars || theme).palette.divider}`,
}),
select: ({ theme }) => ({
fontSize: theme.typography.body2.fontSize,
}),
selectLabel: ({ theme }) => ({
fontSize: theme.typography.body2.fontSize,
}),
displayedRows: ({ theme }) => ({
fontSize: theme.typography.body2.fontSize,
}),
},
},
MuiPaginationItem: {
styleOverrides: {
root: ({ theme }) => ({
[`&.${paginationItemClasses.focusVisible}`]: {
outline: '2px solid',
outlineColor: (theme.vars || theme).palette.text.primary,
outlineOffset: '2px',
},
}),
},
},
MuiTableSortLabel: {
styleOverrides: {
root: ({ theme }) => ({
fontWeight: 600,
'&:hover': {
color: (theme.vars || theme).palette.text.primary,
},
[`&.${tableSortLabelClasses.active}`]: {
color: (theme.vars || theme).palette.text.primary,
},
[`&.${buttonBaseClasses.focusVisible}`]: {
outline: '2px solid',
outlineColor: (theme.vars || theme).palette.text.primary,
outlineOffset: '2px',
},
}),
icon: ({ theme }) => ({
fontSize: '1.125rem',
color: (theme.vars || theme).palette.text.secondary,
}),
},
},
};
themes/mui-treasury/components/text-field.ts
import { filledInputClasses } from '@mui/material/FilledInput';
import { formHelperTextClasses } from '@mui/material/FormHelperText';
import { formLabelClasses } from '@mui/material/FormLabel';
import { iconButtonClasses } from '@mui/material/IconButton';
import { inputClasses } from '@mui/material/Input';
import { inputAdornmentClasses } from '@mui/material/InputAdornment';
import { inputBaseClasses } from '@mui/material/InputBase';
import { inputLabelClasses } from '@mui/material/InputLabel';
import { outlinedInputClasses } from '@mui/material/OutlinedInput';
import {
CONTROL_HEIGHTS,
CONTROL_TOUCH_HEIGHTS,
TOUCH_MEDIA_QUERY,
} from '../scales';
import { ThemeComponents } from '../types';
declare module '@mui/material/InputBase' {
interface InputBasePropsSizeOverrides {
large: true;
}
}
declare module '@mui/material/TextField' {
interface TextFieldPropsSizeOverrides {
large: true;
}
}
declare module '@mui/material/FormControl' {
interface FormControlPropsSizeOverrides {
large: true;
}
}
export const textFieldTheme: ThemeComponents = {
MuiFormControl: {
defaultProps: {
variant: 'outlined',
},
styleOverrides: {
root: ({ theme }) => ({
variants: [
{
props: { variant: 'outlined' },
style: {
[`&&& .${inputBaseClasses.input}`]: {
'&::-webkit-input-placeholder': {
opacity: '0.42 !important',
},
'&::-moz-placeholder': {
opacity: '0.42 !important',
},
'&::-ms-input-placeholder': {
opacity: '0.42 !important',
},
},
[`&& .${outlinedInputClasses.notchedOutline}`]: {
transition: 'none',
'& legend': {
width: 0,
},
},
[`& .${iconButtonClasses.root}`]: {
'&:hover': {
color: (theme.vars || theme).palette.text.primary,
backgroundColor: 'transparent',
},
},
},
},
],
}),
},
},
MuiInputBase: {
styleOverrides: {
root: ({ theme }) => ({
[theme.breakpoints.up(768)]: {
fontSize: theme.typography.body2.fontSize,
lineHeight: '1.42857em', // 20px
},
variants: [
{
props: { size: 'small' },
style: {
[`&:has(.${inputAdornmentClasses.positionStart})`]: {
paddingLeft: '10px',
},
[`&:has(.${inputAdornmentClasses.positionEnd})`]: {
paddingRight: '10px',
},
},
},
{
props: { size: 'medium' },
style: {
[`&:has(.${inputAdornmentClasses.positionStart})`]: {
paddingLeft: '12px',
},
[`&:has(.${inputAdornmentClasses.positionEnd})`]: {
paddingRight: '12px',
},
},
},
{
props: { size: 'large' },
style: {
fontSize: theme.typography.body1.fontSize,
[theme.breakpoints.up(768)]: {
fontSize: theme.typography.body1.fontSize,
lineHeight: theme.typography.body1.lineHeight,
},
},
},
],
}),
input: {
paddingBlock: CONTROL_HEIGHTS.md / 2 - 10.5,
paddingInline: 12,
minHeight: '1.5em',
...(CONTROL_HEIGHTS.md !== CONTROL_TOUCH_HEIGHTS.md && {
[TOUCH_MEDIA_QUERY]: {
paddingBlock: CONTROL_TOUCH_HEIGHTS.md / 2 - 12,
},
}),
variants: [
{
props: { size: 'small' },
style: {
paddingBlock: CONTROL_HEIGHTS.sm / 2 - 10.5,
paddingInline: 10,
...(CONTROL_HEIGHTS.sm !== CONTROL_TOUCH_HEIGHTS.sm && {
[TOUCH_MEDIA_QUERY]: {
paddingBlock: CONTROL_TOUCH_HEIGHTS.sm / 2 - 12,
},
}),
},
},
{
props: { size: 'large' },
style: {
paddingBlock: CONTROL_HEIGHTS.lg / 2 - 12,
paddingInline: 16,
...(CONTROL_HEIGHTS.lg !== CONTROL_TOUCH_HEIGHTS.lg && {
[TOUCH_MEDIA_QUERY]: {
paddingBlock: CONTROL_TOUCH_HEIGHTS.lg / 2 - 12,
},
}),
},
},
],
},
},
},
MuiOutlinedInput: {
styleOverrides: {
root: ({ theme }) => ({
borderRadius: 8,
[`& .${outlinedInputClasses.notchedOutline}`]: {
transition: theme.transitions.create(['border-color'], {
duration: theme.transitions.duration.shorter,
}),
},
'& legend': {
height: '11px',
},
[`&:hover .${outlinedInputClasses.notchedOutline}`]: {
borderColor: (theme.vars || theme).palette.text.primary,
},
[`&.${outlinedInputClasses.focused} .${outlinedInputClasses.notchedOutline}`]:
{
borderWidth: 2,
borderColor: (theme.vars || theme).palette.primary.main,
},
[`&.${outlinedInputClasses.error} .${outlinedInputClasses.notchedOutline}`]:
{
borderColor: (theme.vars || theme).palette.error.main,
},
[`&.${outlinedInputClasses.disabled}`]: {
backgroundColor: (theme.vars || theme).palette.action
.disabledBackground,
[`& .${outlinedInputClasses.notchedOutline}`]: {
borderColor: (theme.vars || theme).palette.action.disabled,
},
},
variants: [
{
props: { size: 'small', multiline: true },
style: {
paddingBlock: CONTROL_HEIGHTS.sm / 2 - 10.5,
paddingInline: 12,
...(CONTROL_HEIGHTS.sm !== CONTROL_TOUCH_HEIGHTS.sm && {
[TOUCH_MEDIA_QUERY]: {
paddingBlock: CONTROL_TOUCH_HEIGHTS.sm / 2 - 12,
},
}),
},
},
{
props: { size: 'medium', multiline: true },
style: {
paddingBlock: CONTROL_HEIGHTS.md / 2 - 10.5,
paddingInline: 14,
...(CONTROL_HEIGHTS.md !== CONTROL_TOUCH_HEIGHTS.md && {
[TOUCH_MEDIA_QUERY]: {
paddingBlock: CONTROL_TOUCH_HEIGHTS.md / 2 - 12,
},
}),
},
},
{
props: { size: 'large', multiline: true },
style: {
paddingBlock: CONTROL_HEIGHTS.lg / 2 - 12,
paddingInline: 14,
...(CONTROL_HEIGHTS.lg !== CONTROL_TOUCH_HEIGHTS.lg && {
[TOUCH_MEDIA_QUERY]: {
paddingBlock: CONTROL_TOUCH_HEIGHTS.lg / 2 - 12,
},
}),
},
},
],
}),
input: {
paddingBlock: CONTROL_HEIGHTS.md / 2 - 10.5,
paddingInline: 12,
[`.${inputAdornmentClasses.root} + &`]: {
paddingLeft: 0,
},
[`&:has(+ .${inputAdornmentClasses.root})`]: {
paddingRight: 0,
},
variants: [
{
props: { size: 'small' },
style: {
paddingBlock: CONTROL_HEIGHTS.sm / 2 - 10.5,
paddingInline: 12,
...(CONTROL_HEIGHTS.sm !== CONTROL_TOUCH_HEIGHTS.sm && {
[TOUCH_MEDIA_QUERY]: {
paddingBlock: CONTROL_TOUCH_HEIGHTS.sm / 2 - 12,
},
}),
},
},
{
props: { size: 'medium' },
style: {
paddingBlock: CONTROL_HEIGHTS.md / 2 - 10.5,
...(CONTROL_HEIGHTS.md !== CONTROL_TOUCH_HEIGHTS.md && {
[TOUCH_MEDIA_QUERY]: {
paddingBlock: CONTROL_TOUCH_HEIGHTS.md / 2 - 12,
},
}),
},
},
{
props: { size: 'large' },
style: {
paddingBlock: CONTROL_HEIGHTS.lg / 2 - 12,
paddingInline: 14,
...(CONTROL_HEIGHTS.lg !== CONTROL_TOUCH_HEIGHTS.lg && {
[TOUCH_MEDIA_QUERY]: {
paddingBlock: CONTROL_TOUCH_HEIGHTS.lg / 2 - 12,
},
}),
},
},
{
props: { multiline: true },
style: {
padding: 0,
},
},
],
},
},
},
MuiFilledInput: {
styleOverrides: {
root: ({ theme }) => ({
backgroundColor: (theme.vars || theme).palette.action.hover,
borderRadius: '8px 8px 0 0',
'&:hover': {
backgroundColor: (theme.vars || theme).palette.action.selected,
},
[`&.${filledInputClasses.focused}`]: {
backgroundColor: (theme.vars || theme).palette.action.selected,
},
[`&.${filledInputClasses.disabled}`]: {
backgroundColor: (theme.vars || theme).palette.action
.disabledBackground,
},
'&::before': {
transition: theme.transitions.create(['border-bottom-color'], {
duration: theme.transitions.duration.shorter,
}),
},
'&:hover::before': {
borderBottom: `2px solid ${
(theme.vars || theme).palette.text.primary
}`,
},
'&::after': {
borderBottom: `2px solid ${
(theme.vars || theme).palette.primary.main
}`,
},
[`&.${filledInputClasses.error}::after`]: {
borderBottomColor: (theme.vars || theme).palette.error.main,
},
}),
input: () => ({
'&:where(input)': {
paddingTop: CONTROL_HEIGHTS.md / 2 + 5,
paddingInline: 12,
paddingBottom: CONTROL_HEIGHTS.md / 2 - 12,
...(CONTROL_HEIGHTS.md !== CONTROL_TOUCH_HEIGHTS.md && {
[TOUCH_MEDIA_QUERY]: {
paddingTop: CONTROL_TOUCH_HEIGHTS.md / 2 + 5,
paddingBottom: CONTROL_TOUCH_HEIGHTS.md / 2 - 12,
},
}),
},
variants: [
{
props: { size: 'small' },
style: {
'&:where(input)': {
paddingTop: CONTROL_HEIGHTS.sm / 2 + 4,
paddingInline: 10,
paddingBottom: CONTROL_HEIGHTS.sm / 2 - 13,
...(CONTROL_HEIGHTS.sm !== CONTROL_TOUCH_HEIGHTS.sm && {
[TOUCH_MEDIA_QUERY]: {
paddingTop: CONTROL_TOUCH_HEIGHTS.sm / 2 + 4,
paddingBottom: CONTROL_TOUCH_HEIGHTS.sm / 2 - 13,
},
}),
},
},
},
],
}),
},
},
MuiInput: {
styleOverrides: {
root: ({ theme }) => ({
'&::before': {
transition: theme.transitions.create(['border-bottom-color'], {
duration: theme.transitions.duration.shorter,
}),
},
[`&:hover:not(.${inputClasses.disabled})::before`]: {
borderBottom: `2px solid ${
(theme.vars || theme).palette.text.primary
}`,
},
'&::after': {
borderBottom: `2px solid ${
(theme.vars || theme).palette.primary.main
}`,
},
[`&.${inputClasses.error}::after`]: {
borderBottomColor: (theme.vars || theme).palette.error.main,
},
}),
input: {
padding: '4px 0 5px',
},
},
},
MuiInputLabel: {
styleOverrides: {
root: ({ theme }) => ({
fontSize: theme.typography.body2.fontSize,
variants: [
{
props: { size: 'large' },
style: {
fontSize: theme.typography.body1.fontSize,
},
},
],
}),
outlined: ({ theme }) => ({
color: (theme.vars || theme).palette.text.primary,
[`&.${inputLabelClasses.focused}`]: {
color: (theme.vars || theme).palette.primary.main,
},
[`&.${inputLabelClasses.disabled}`]: {
color: (theme.vars || theme).palette.text.disabled,
},
[`&.${formLabelClasses.root}`]: {
position: 'static',
transform: 'none',
pointerEvents: 'auto',
marginBottom: '0.25rem',
maxWidth: 'unset',
fontWeight: 500,
lineHeight: 1.5,
[`&.${inputLabelClasses.shrink}`]: {
transform: 'none',
},
},
variants: [
{
props: { size: 'small' },
style: {
transform: 'translate(14px, 7px) scale(1)',
[`&.${inputLabelClasses.shrink}`]: {
transform: 'translate(14px, -9px) scale(0.75)',
},
},
},
],
}),
filled: {
transform: 'translate(12px, 16px) scale(1)',
[`&.${inputLabelClasses.shrink}`]: {
transform: 'translate(12px, 7px) scale(0.75)',
},
variants: [
{
props: { size: 'small' },
style: {
transform: 'translate(12px, 14px) scale(1)',
[`&.${inputLabelClasses.shrink}`]: {
transform: 'translate(10px, 6px) scale(0.75)',
},
},
},
],
},
},
},
MuiFormHelperText: {
styleOverrides: {
root: ({ theme }) => ({
marginTop: 4,
lineHeight: 'calc(20/12)',
[`&.${formHelperTextClasses.error}`]: {
color: (theme.vars || theme).palette.error.text,
},
}),
},
},
MuiInputAdornment: {
styleOverrides: {
root: ({ theme }) => ({
color: (theme.vars || theme).palette.text.secondary,
variants: [
{
props: { position: 'start' },
style: {
marginRight: 8,
},
},
{
props: { position: 'end' },
style: {
marginLeft: 8,
},
},
],
}),
},
},
};
themes/mui-treasury/components/tree-view.ts
import { treeItemClasses } from '@mui/x-tree-view/TreeItem';
import type {} from '@mui/x-tree-view/themeAugmentation';
import { ThemeComponents } from '../types';
export const treeViewTheme: ThemeComponents = {
MuiTreeItem: {
styleOverrides: {
content: ({ theme }) => ({
'&[data-selected]': {
'--Icon-color': 'currentColor',
backgroundColor: 'transparent',
'&[data-focused]': {
backgroundColor: (theme.vars || theme).palette.action.hover,
},
[`& .${treeItemClasses.label}`]: {
fontWeight: 'bold',
},
},
}),
},
},
};
themes/mui-treasury/index.ts
export { default } from './theme';
export * from './theme';
themes/mui-treasury/scales.ts
/**
* Used by: text-field, date-picker, select, autocomplete, button
*/
export const CONTROL_HEIGHTS = {
sm: 32,
md: 36,
lg: 42,
};
/**
* Touch device heights (+ for better touch targets)
*/
export const CONTROL_TOUCH_HEIGHTS = {
sm: 34,
md: 40,
lg: 48,
};
/**
* Media query for touch device sizing.
* Default: touch input + mobile viewport (hybrid approach)
* Alternatives:
* - "(pointer: coarse)" - all touch devices regardless of screen size
* - "(max-width: 768px)" - breakpoint only
*/
export const TOUCH_MEDIA_QUERY = '@media (max-width: 768px)';
/**
* Used by: controls (MuiSwitch)
* inset: space between track edge and thumb
*/
export const SWITCH_SIZES = {
sm: { height: 24, width: 36, inset: 2 }, // WCAG 2.2 requires at least 24px touch size
md: { height: 28, width: 44, inset: 2 },
lg: { height: 32, width: 52, inset: 3 },
};
export const SWITCH_TOUCH_SIZES = {
sm: { height: 28, width: 44, inset: 2 },
md: { height: 34, width: 56, inset: 3 },
lg: { height: 40, width: 64, inset: 4 },
};
themes/mui-treasury/shadows.ts
import { ThemeOptions } from './types';
export const shadows: ThemeOptions['shadows'] = [
'none',
'0 1px 2px 0 rgb(0 0 0 / 0.05)',
'0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)',
'0 2px 4px 0 rgb(0 0 0 / 0.06)',
'0 2px 4px -1px rgb(0 0 0 / 0.06), 0 1px 2px -1px rgb(0 0 0 / 0.04)',
'0 3px 5px -1px rgb(0 0 0 / 0.07), 0 1px 3px -1px rgb(0 0 0 / 0.05)',
'0 4px 6px -1px rgb(0 0 0 / 0.07), 0 2px 4px -1px rgb(0 0 0 / 0.05)',
'0 5px 8px -2px rgb(0 0 0 / 0.08), 0 2px 4px -1px rgb(0 0 0 / 0.05)',
'0 6px 10px -2px rgb(0 0 0 / 0.08), 0 3px 5px -2px rgb(0 0 0 / 0.06)',
'0 8px 12px -3px rgb(0 0 0 / 0.09), 0 3px 6px -2px rgb(0 0 0 / 0.06)',
'0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 7px -3px rgb(0 0 0 / 0.07)',
'0 12px 18px -4px rgb(0 0 0 / 0.11), 0 5px 9px -3px rgb(0 0 0 / 0.08)',
'0 15px 22px -4px rgb(0 0 0 / 0.12), 0 6px 11px -4px rgb(0 0 0 / 0.09)',
'0 18px 28px -5px rgb(0 0 0 / 0.13), 0 7px 13px -4px rgb(0 0 0 / 0.1)',
'0 22px 34px -6px rgb(0 0 0 / 0.14), 0 8px 16px -5px rgb(0 0 0 / 0.11)',
'0 26px 40px -7px rgb(0 0 0 / 0.15), 0 10px 19px -5px rgb(0 0 0 / 0.12)',
'0 31px 47px -8px rgb(0 0 0 / 0.16), 0 12px 23px -6px rgb(0 0 0 / 0.13)',
'0 36px 54px -9px rgb(0 0 0 / 0.17), 0 14px 27px -7px rgb(0 0 0 / 0.14)',
'0 42px 62px -10px rgb(0 0 0 / 0.18), 0 16px 31px -8px rgb(0 0 0 / 0.15)',
'0 48px 70px -11px rgb(0 0 0 / 0.2), 0 18px 36px -9px rgb(0 0 0 / 0.16)',
'0 54px 78px -12px rgb(0 0 0 / 0.21), 0 20px 41px -10px rgb(0 0 0 / 0.17)',
'0 60px 86px -13px rgb(0 0 0 / 0.22), 0 23px 46px -11px rgb(0 0 0 / 0.18)',
'0 66px 94px -14px rgb(0 0 0 / 0.23), 0 26px 52px -12px rgb(0 0 0 / 0.19)',
'0 72px 102px -15px rgb(0 0 0 / 0.24), 0 29px 58px -13px rgb(0 0 0 / 0.2)',
'0 58px 82px -11px rgb(0 0 0 / 0.26), 0 21px 40px -11px rgb(0 0 0 / 0.22)',
];
themes/mui-treasury/theme.tsx
'use client';
import {
ThemeProvider as MuiThemeProvider,
createTheme,
} from '@mui/material/styles';
import type {} from '@mui/material/themeCssVarsAugmentation';
import { colors } from './colors';
import { alertTheme } from './components/alert';
import { autocompleteTheme } from './components/autocomplete';
import { avatarTheme } from './components/avatar';
import { buttonTheme } from './components/button';
import { cardTheme } from './components/card';
import { chipTheme } from './components/chip';
import { controlsTheme } from './components/controls';
import { dataGridTheme } from './components/data-grid';
import { datePickerTheme } from './components/date-picker';
import { dialogTheme } from './components/dialog';
import { layoutTheme } from './components/layout';
import { linkTheme } from './components/link';
import { listTheme } from './components/list';
import { menuTheme } from './components/menu';
import { progressTheme } from './components/progress';
import { selectTheme } from './components/select';
import { svgIconTheme } from './components/svg-icon';
import { tableTheme } from './components/table';
import { textFieldTheme } from './components/text-field';
import { treeViewTheme } from './components/tree-view';
import { shadows } from './shadows';
import { typography, typographyTheme } from './typography';
const theme = createTheme({
cssVariables: {
colorSchemeSelector: 'class',
},
colorSchemes: colors,
shape: {
borderRadius: 8,
},
components: {
...buttonTheme,
...textFieldTheme,
...selectTheme,
...menuTheme,
...autocompleteTheme,
...chipTheme,
...avatarTheme,
...tableTheme,
...cardTheme,
...dialogTheme,
...datePickerTheme,
...svgIconTheme,
...dataGridTheme,
...alertTheme,
...treeViewTheme,
...layoutTheme,
...linkTheme,
...controlsTheme,
...listTheme,
...progressTheme,
...typographyTheme,
},
typography,
shadows,
});
export function ThemeProvider({ children }: { children: React.ReactNode }) {
return <MuiThemeProvider theme={theme}>{children}</MuiThemeProvider>;
}
export default theme;
themes/mui-treasury/types.ts
import { createTheme } from '@mui/material/styles';
export type ThemeOptions = NonNullable<Parameters<typeof createTheme>[0]>;
export type ThemeComponents = NonNullable<
Parameters<typeof createTheme>[0]
>['components'];
themes/mui-treasury/typography.ts
'use client';
import { unstable_createBreakpoints as createBreakpoints } from '@mui/material/styles';
import { ThemeOptions } from './types';
const breakpoints = createBreakpoints({});
// Responsive heading styles extracted from tailwind-prose configuration
const h1Styles = {
'--_fs': '2.25rem',
'--_lh': '1.11111111',
fontWeight: 800,
fontSize: 'var(--_fs)',
lineHeight: 'var(--_lh)',
[breakpoints.up('sm')]: {
'--_fs': '3rem',
'--_lh': '1',
},
[breakpoints.up('md')]: {
'--_fs': '3.5rem',
},
[breakpoints.up('xl')]: {
'--_fs': '4rem',
},
};
const h2Styles = {
'--_fs': '1.5rem',
'--_lh': '1.5',
fontWeight: 700,
fontSize: 'var(--_fs)',
lineHeight: 'var(--_lh)',
[breakpoints.up('sm')]: {
'--_fs': '1.875rem',
},
[breakpoints.up('md')]: {
'--_fs': '2.25rem',
'--_lh': '1.11111111',
},
[breakpoints.up('xl')]: {
'--_fs': '3rem',
'--_lh': '1.08333',
},
};
const h3Styles = {
'--_fs': '1.25rem',
'--_lh': '1.6',
fontWeight: 600,
fontSize: 'var(--_fs)',
lineHeight: 'var(--_lh)',
[breakpoints.up('sm')]: {
'--_fs': '1.5rem',
'--_lh': '1.5',
},
[breakpoints.up('md')]: {
'--_fs': '1.875rem',
'--_lh': '1.33333',
},
[breakpoints.up('xl')]: {
'--_fs': '2.25rem',
'--_lh': '1.22222',
},
};
const h4Styles = {
'--_fs': '1.125rem',
'--_lh': '1.55556',
fontWeight: 600,
fontSize: 'var(--_fs)',
lineHeight: 'var(--_lh)',
[breakpoints.up('sm')]: {
'--_fs': '1.25rem',
'--_lh': '1.55556',
},
[breakpoints.up('md')]: {
'--_lh': '1.6',
},
[breakpoints.up('xl')]: {
'--_lh': '1.5',
},
};
export const typography: ThemeOptions['typography'] = {
fontFamily:
'var(--font-primary, "Geist Variable", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif)',
h1: h1Styles,
h2: h2Styles,
h3: h3Styles,
h4: h4Styles,
h5: h4Styles, // use h4 styles since h5 is rarely used
h6: h4Styles, // use h4 styles since h6 is rarely used
body2: {
lineHeight: '1.4285714286',
},
button: {
lineHeight: '20px',
textTransform: 'capitalize',
},
};
export const typographyTheme: ThemeOptions['components'] = {
MuiTypography: {
styleOverrides: {
root: {
'--va': 'baseline',
},
},
},
};