Some checks failed
No response / noResponse (push) Has been cancelled
CI / Continuous releases (push) Has been cancelled
CI / test-dev (macos-latest) (push) Has been cancelled
CI / test-dev (ubuntu-latest) (push) Has been cancelled
CI / test-dev (windows-latest) (push) Has been cancelled
Maintenance / main (push) Has been cancelled
Scorecards supply-chain security / Scorecards analysis (push) Has been cancelled
CodeQL / Analyze (push) Has been cancelled
161 lines
4.9 KiB
TypeScript
161 lines
4.9 KiB
TypeScript
import * as React from 'react';
|
|
import { expect } from 'chai';
|
|
import { spy } from 'sinon';
|
|
import { createRenderer, screen } from '@mui/internal-test-utils';
|
|
import { ThemeContext } from '@mui/styled-engine';
|
|
import * as material from '@mui/material';
|
|
import * as joy from '@mui/joy';
|
|
|
|
// simulate 3rd-party library like Theme-UI, Chakra-UI, or Mantine
|
|
interface LibTheme {
|
|
palette: { brand: string };
|
|
vars: { palette: { brand: string } };
|
|
}
|
|
function LibThemeProvider({ children }: React.PropsWithChildren<{}>) {
|
|
const theme = React.useMemo<LibTheme>(
|
|
() => ({ palette: { brand: '#ff5252' }, vars: { palette: { brand: 'var(--palette-brand)' } } }),
|
|
[],
|
|
);
|
|
return <ThemeContext.Provider value={theme}>{children}</ThemeContext.Provider>;
|
|
}
|
|
|
|
function LibComponent() {
|
|
const theme = React.useContext(ThemeContext as unknown as React.Context<LibTheme>);
|
|
return <div style={{ color: theme.palette.brand }} />;
|
|
}
|
|
|
|
const joyTheme = joy.extendTheme({
|
|
components: {
|
|
JoyButton: {
|
|
defaultProps: {
|
|
variant: 'outlined',
|
|
},
|
|
styleOverrides: {
|
|
root: ({ theme }) => ({
|
|
color: theme.vars.palette.text.primary,
|
|
mixBlendMode: 'darken',
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
});
|
|
const CustomJoy = joy.styled('div')(({ theme }) => ({
|
|
fontSize: theme.vars.fontSize.md,
|
|
}));
|
|
|
|
const materialTheme = material.createTheme({
|
|
components: {
|
|
MuiButton: {
|
|
defaultProps: {
|
|
variant: 'outlined',
|
|
},
|
|
styleOverrides: {
|
|
root: ({ theme }) => ({
|
|
color: theme.palette.text.primary,
|
|
mixBlendMode: 'darken',
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
});
|
|
const CustomMaterial = material.styled('div')(({ theme }) => ({
|
|
borderRadius: theme.shape.borderRadius,
|
|
}));
|
|
|
|
describe('Multiple nested theme providers', () => {
|
|
const { render } = createRenderer();
|
|
let originalMatchmedia: any;
|
|
let storage: Record<string, string> = {};
|
|
const createMatchMedia = (matches: boolean) => () => ({
|
|
matches,
|
|
// Keep mocking legacy methods because @mui/material v5 still uses them
|
|
addListener: () => {},
|
|
addEventListener: () => {},
|
|
removeListener: () => {},
|
|
removeEventListener: () => {},
|
|
});
|
|
|
|
beforeEach(() => {
|
|
originalMatchmedia = window.matchMedia;
|
|
|
|
// Create mocks of localStorage getItem and setItem functions
|
|
Object.defineProperty(globalThis, 'localStorage', {
|
|
value: {
|
|
getItem: spy((key) => storage[key]),
|
|
setItem: spy((key, value) => {
|
|
storage[key] = value;
|
|
}),
|
|
},
|
|
configurable: true,
|
|
});
|
|
|
|
// clear the localstorage
|
|
storage = {};
|
|
window.matchMedia = createMatchMedia(false) as unknown as typeof window.matchMedia;
|
|
});
|
|
|
|
afterEach(() => {
|
|
window.matchMedia = originalMatchmedia;
|
|
});
|
|
|
|
it('[docs] Material UI + Joy UI', () => {
|
|
render(
|
|
<joy.CssVarsProvider theme={{ [joy.THEME_ID]: joyTheme }}>
|
|
<material.ThemeProvider theme={materialTheme}>
|
|
<joy.Button
|
|
sx={(theme) => ({
|
|
// test `sx`
|
|
bgcolor: theme.vars.palette.neutral[100],
|
|
})}
|
|
>
|
|
Joy
|
|
</joy.Button>
|
|
<material.Button
|
|
sx={(theme) => ({
|
|
bgcolor: theme.palette.secondary.light,
|
|
})}
|
|
>
|
|
Material
|
|
</material.Button>
|
|
</material.ThemeProvider>
|
|
</joy.CssVarsProvider>,
|
|
);
|
|
|
|
// these test if `useThemeProps` works with theme scoping
|
|
expect(screen.getByText('Joy')).to.have.class(joy.buttonClasses.variantOutlined);
|
|
expect(screen.getByText('Joy')).toHaveComputedStyle({ mixBlendMode: 'darken' });
|
|
expect(screen.getByText('Material')).to.have.class(material.buttonClasses.outlinedPrimary);
|
|
expect(screen.getByText('Material')).toHaveComputedStyle({ mixBlendMode: 'darken' });
|
|
});
|
|
|
|
it('Material UI works with 3rd-party lib', () => {
|
|
render(
|
|
<LibThemeProvider>
|
|
<material.ThemeProvider theme={{ [material.THEME_ID]: materialTheme }}>
|
|
<material.Button>Material</material.Button>
|
|
<CustomMaterial /> {/* styled() should work with theme scoping */}
|
|
<LibComponent />{' '}
|
|
{/* still able to render even though it is wrapped in Material UI ThemeProvider */}
|
|
</material.ThemeProvider>
|
|
</LibThemeProvider>,
|
|
);
|
|
|
|
expect(screen.getByText('Material')).to.have.class(material.buttonClasses.outlinedPrimary);
|
|
});
|
|
|
|
it('Joy UI works with 3rd-party lib', () => {
|
|
render(
|
|
<LibThemeProvider>
|
|
<joy.ThemeProvider theme={{ [joy.THEME_ID]: joyTheme }}>
|
|
<joy.Button>Joy</joy.Button>
|
|
<CustomJoy /> {/* styled() should work with theme scoping */}
|
|
<LibComponent />{' '}
|
|
{/* still able to render even though it is wrapped in Material UI ThemeProvider */}
|
|
</joy.ThemeProvider>
|
|
</LibThemeProvider>,
|
|
);
|
|
|
|
expect(screen.getByText('Joy')).to.have.class(joy.buttonClasses.variantOutlined);
|
|
});
|
|
});
|