theme: add v5->v4 component theme adapter

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2022-12-31 12:32:17 +01:00
committed by Philipp Hugenroth
parent be7c4cdab9
commit 231b39bae8
2 changed files with 209 additions and 0 deletions
+138
View File
@@ -0,0 +1,138 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Theme } from '@mui/material';
import { transformV5ComponentThemesToV4 } from './overrides';
describe('transformV5ComponentThemesToV4', () => {
const mockTheme = {
palette: {
primary: {
main: 'red',
},
},
} as unknown as Theme;
it('transforms empty component themes', () => {
expect(transformV5ComponentThemesToV4(mockTheme)).toEqual({
overrides: {},
props: {},
});
expect(transformV5ComponentThemesToV4(mockTheme, {})).toEqual({
overrides: {},
props: {},
});
expect(
transformV5ComponentThemesToV4(mockTheme, {
MuiButton: {
styleOverrides: undefined,
defaultProps: undefined,
},
}),
).toEqual({ overrides: {}, props: {} });
expect(
transformV5ComponentThemesToV4(mockTheme, {
MuiButton: {
styleOverrides: {},
defaultProps: {},
},
}),
).toEqual({ overrides: { MuiButton: {} }, props: { MuiButton: {} } });
});
it('transforms component themes', () => {
expect(
transformV5ComponentThemesToV4(mockTheme, {
MuiButton: {
styleOverrides: {
root: {
color: 'green',
},
},
defaultProps: {
disableRipple: true,
},
},
}),
).toEqual({
overrides: {
MuiButton: {
root: {
color: 'green',
},
},
},
props: {
MuiButton: {
disableRipple: true,
},
},
});
expect(
transformV5ComponentThemesToV4(mockTheme, {
MuiButton: {
styleOverrides: {
root: ({ theme }) => ({
color: theme.palette.primary.main,
}),
},
},
}),
).toEqual({
overrides: {
MuiButton: {
root: {
color: 'red',
},
},
},
props: {},
});
});
it('transforms CSSBaseline theme', () => {
expect(
transformV5ComponentThemesToV4(mockTheme, {
MuiCssBaseline: {
styleOverrides: theme => ({
'@global': {
html: {
color: theme.palette.primary.main,
},
},
}),
defaultProps: {
enableColorScheme: true,
},
},
}),
).toEqual({
overrides: {
MuiCssBaseline: {
'@global': {
html: {
color: 'red',
},
},
},
},
props: {
MuiCssBaseline: {
enableColorScheme: true,
},
},
});
});
});
+71
View File
@@ -0,0 +1,71 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Overrides } from '@material-ui/core/styles/overrides';
import { ComponentsProps } from '@material-ui/core/styles/props';
import { ComponentsOverrides, Theme } from '@mui/material/styles';
type V5Override = ComponentsOverrides[keyof ComponentsOverrides];
type V4Override = Overrides[keyof Overrides];
// Converts callback-based overrides to static styles, e.g.
// { root: theme => ({ color: theme.color }) } -> { root: { color: 'red' } }
function adaptV5Override(theme: Theme, overrides: V5Override): V4Override {
if (!overrides) {
return overrides as V4Override;
}
if (typeof overrides === 'function') {
return overrides(theme) as V4Override;
}
if (typeof overrides === 'object') {
return Object.fromEntries(
Object.entries(overrides).map(([className, style]) => {
if (typeof style === 'function') {
return [className, style({ theme })];
}
return [className, style];
}),
);
}
return overrides as V4Override;
}
// Transform v5 theme overrides into a v4 theme, by converting the callback-based overrides
export function transformV5ComponentThemesToV4(
theme: Theme,
components: Theme['components'] = {},
): { overrides: Overrides; props: ComponentsProps } {
const overrides: Record<string, V4Override> = {};
const props: Record<string, ComponentsProps[keyof ComponentsProps]> = {};
for (const name of Object.keys(components)) {
const component = components[name as keyof typeof components];
if (!component) {
continue;
}
if ('styleOverrides' in component) {
overrides[name] = adaptV5Override(
theme,
component.styleOverrides as V5Override,
);
}
if ('defaultProps' in component) {
props[name] = component.defaultProps;
}
}
return { overrides, props };
}