feat(design-system): add MUI theme adapter

This commit is contained in:
Sergey Krylov 2026-06-21 09:28:38 +03:00
parent fdffe204e4
commit 1107a1fc8b
5 changed files with 124 additions and 0 deletions

View File

@ -0,0 +1,20 @@
import { type ReactNode } from 'react';
import { ThemeProvider } from '@mui/material/styles';
import CssBaseline from '@mui/material/CssBaseline';
import { Experimental_CssVarsProvider as CssVarsProvider } from '@mui/material/styles';
import { createMoexVibeTheme } from './createMoexVibeTheme';
const theme = createMoexVibeTheme();
export interface MoexVibeThemeProviderProps {
children: ReactNode;
}
export function MoexVibeThemeProvider({ children }: MoexVibeThemeProviderProps) {
return (
<CssVarsProvider theme={theme}>
<CssBaseline />
{children}
</CssVarsProvider>
);
}

View File

@ -0,0 +1,29 @@
import { describe, it, expect } from 'vitest';
import { createMoexVibeTheme } from './createMoexVibeTheme';
describe('createMoexVibeTheme', () => {
it('sets cssVarPrefix to mv', () => {
const theme = createMoexVibeTheme();
expect(theme.cssVarPrefix).toBe('mv');
});
it('maps color.action.primary to MUI primary main', () => {
const theme = createMoexVibeTheme();
expect(theme.colorSchemes.light.palette.primary.main).toBe('#176747');
});
it('uses Inter in typography', () => {
const theme = createMoexVibeTheme();
expect(theme.typography.body1.fontFamily).toContain('Inter');
});
it('maps radius.md to shape border radius', () => {
const theme = createMoexVibeTheme();
expect(theme.shape.borderRadius).toBe(8);
});
it('disables elevation on MuiButton by default', () => {
const theme = createMoexVibeTheme();
expect(theme.components?.MuiButton?.defaultProps).toMatchObject({ disableElevation: true });
});
});

View File

@ -0,0 +1,55 @@
import { createTheme } from '@mui/material/styles';
import { primitiveTokens, semanticLightTokens, componentTokens, resolveToken } from '../tokens';
const allTokens = {
...primitiveTokens,
...semanticLightTokens,
...componentTokens,
} as const;
function resolveValue(name: string): string | number | readonly number[] | readonly string[] {
return resolveToken(allTokens, name).value;
}
export function createMoexVibeTheme() {
return createTheme({
cssVariables: { cssVarPrefix: 'mv' },
colorSchemes: {
light: {
palette: {
primary: { main: resolveValue('color.action.primary') as string },
secondary: { main: resolveValue('color.action.secondary') as string },
error: { main: resolveValue('color.feedback.error') as string },
warning: { main: resolveValue('color.feedback.warning') as string },
info: { main: resolveValue('color.feedback.info') as string },
success: { main: resolveValue('color.finance.positive') as string },
background: {
default: resolveValue('color.canvas') as string,
paper: resolveValue('color.surface.default') as string,
},
text: {
primary: resolveValue('color.text.primary') as string,
secondary: resolveValue('color.text.secondary') as string,
disabled: resolveValue('color.text.disabled') as string,
},
divider: resolveValue('color.border.default') as string,
},
},
},
typography: {
fontFamily: (resolveValue('font.family.sans') as readonly string[]).join(', '),
body1: { fontFamily: (resolveValue('font.family.body') as readonly string[]).join(', ') },
fontWeightRegular: resolveValue('font.weight.regular') as number,
fontWeightMedium: resolveValue('font.weight.medium') as number,
fontWeightBold: resolveValue('font.weight.bold') as number,
},
shape: {
borderRadius: parseInt(resolveValue('radius.md') as string, 10),
},
components: {
MuiButton: {
defaultProps: { disableElevation: true },
},
},
});
}

View File

@ -0,0 +1,2 @@
export { createMoexVibeTheme } from './createMoexVibeTheme';
export { MoexVibeThemeProvider } from './MoexVibeThemeProvider';

View File

@ -0,0 +1,18 @@
import type {} from '@mui/material/themeCssVarsAugmentation';
declare module '@mui/material/styles' {
interface Palette {
finance: {
positive: string;
negative: string;
neutral: string;
};
}
interface PaletteOptions {
finance?: {
positive: string;
negative: string;
neutral: string;
};
}
}