Merge pull request #15484 from backstage/rugvip/mui5

Add support for Material-UI v5
This commit is contained in:
Patrik Oldsberg
2023-05-23 17:13:01 +02:00
committed by GitHub
36 changed files with 1932 additions and 404 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-techdocs-addons-test-utils': patch
---
Avoiding re-running tests on cleanup.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/test-utils': minor
---
Test App Wrapper is now using `UnifiedThemeProvider` for supporting MUI v5 next to MUI v4 in tests.
+17
View File
@@ -0,0 +1,17 @@
---
'@backstage/app-defaults': minor
'@backstage/theme': minor
---
**MUI v5 Support:** Adding platform-wide support for MUI v5 allowing a transition phase for migrating central plugins & components over. We still support v4 instances & plugins by adding a
To allow the future support of plugins & components using MUI v5 you want to upgrade your `AppTheme`'s to using the `UnifiedThemeProvider`
```diff
Provider: ({ children }) => (
- <ThemeProvider theme={lightTheme}>
- <CssBaseline>{children}</CssBaseline>
- </ThemeProvider>
+ <UnifiedThemeProvider theme={builtinThemes.light} children={children} />
),
```
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/cli': patch
---
Enforcing MUI v5 specific linting to minimize bundle size.
+11 -10
View File
@@ -165,16 +165,17 @@ module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, {
The configuration factory also provides utilities for extending the configuration in ways that are otherwise very cumbersome to do with plain ESLint, particularly for rules like `no-restricted-syntax`. These are the extra keys that are available:
| Key | Description |
| ----------------------- | ------------------------------------------------------------------ |
| `tsRules` | Additional rules to apply to TypeScript files |
| `testRules` | Additional rules to apply to tests files |
| `restrictedImports` | Additional paths to add to `no-restricted-imports` |
| `restrictedSrcImports` | Additional paths to add to `no-restricted-imports` in src files |
| `restrictedTestImports` | Additional paths to add to `no-restricted-imports` in test files |
| `restrictedSyntax` | Additional patterns to add to `no-restricted-syntax` |
| `restrictedSrcSyntax` | Additional patterns to add to `no-restricted-syntax` in src files |
| `restrictedTestSyntax` | Additional patterns to add to `no-restricted-syntax` in test files |
| Key | Description |
| -------------------------- | ------------------------------------------------------------------ |
| `tsRules` | Additional rules to apply to TypeScript files |
| `testRules` | Additional rules to apply to tests files |
| `restrictedImports` | Additional paths to add to `no-restricted-imports` |
| `restrictedImportPatterns` | Additional patterns to add to `no-restricted-imports` |
| `restrictedSrcImports` | Additional paths to add to `no-restricted-imports` in src files |
| `restrictedTestImports` | Additional paths to add to `no-restricted-imports` in test files |
| `restrictedSyntax` | Additional patterns to add to `no-restricted-syntax` |
| `restrictedSrcSyntax` | Additional patterns to add to `no-restricted-syntax` in src files |
| `restrictedTestSyntax` | Additional patterns to add to `no-restricted-syntax` in test files |
## Type Checking
@@ -15,11 +15,12 @@
*/
import React from 'react';
import { darkTheme, lightTheme } from '@backstage/theme';
import {
UnifiedThemeProvider,
themes as builtinThemes,
} from '@backstage/theme';
import DarkIcon from '@material-ui/icons/Brightness2';
import LightIcon from '@material-ui/icons/WbSunny';
import { ThemeProvider } from '@material-ui/core/styles';
import CssBaseline from '@material-ui/core/CssBaseline';
import { AppTheme } from '@backstage/core-plugin-api';
export const themes: AppTheme[] = [
@@ -29,9 +30,7 @@ export const themes: AppTheme[] = [
variant: 'light',
icon: <LightIcon />,
Provider: ({ children }) => (
<ThemeProvider theme={lightTheme}>
<CssBaseline>{children}</CssBaseline>
</ThemeProvider>
<UnifiedThemeProvider theme={builtinThemes.light} children={children} />
),
},
{
@@ -40,9 +39,7 @@ export const themes: AppTheme[] = [
variant: 'dark',
icon: <DarkIcon />,
Provider: ({ children }) => (
<ThemeProvider theme={darkTheme}>
<CssBaseline>{children}</CssBaseline>
</ThemeProvider>
<UnifiedThemeProvider theme={builtinThemes.dark} children={children} />
),
},
];
+13
View File
@@ -24,6 +24,7 @@ const { join: joinPath } = require('path');
* - `tsRules`: Additional ESLint rules to apply to TypeScript
* - `testRules`: Additional ESLint rules to apply to tests
* - `restrictedImports`: Additional paths to add to no-restricted-imports
* - `restrictedImportsPattern`: Additional patterns to add to no-restricted-imports
* - `restrictedSrcImports`: Additional paths to add to no-restricted-imports in src files
* - `restrictedTestImports`: Additional paths to add to no-restricted-imports in test files
* - `restrictedSyntax`: Additional patterns to add to no-restricted-syntax
@@ -44,6 +45,7 @@ function createConfig(dir, extraConfig = {}) {
testRules,
restrictedImports,
restrictedImportPatterns,
restrictedSrcImports,
restrictedTestImports,
restrictedSyntax,
@@ -114,6 +116,7 @@ function createConfig(dir, extraConfig = {}) {
'*.test*',
'**/__testUtils__/**',
'**/__mocks__/**',
...(restrictedImportPatterns ?? []),
],
},
],
@@ -208,9 +211,19 @@ function createConfigForRole(dir, role, extraConfig = {}) {
name: '@material-ui/icons/', // because this is possible too ._.
message: "Please import '@material-ui/icons/<Icon>' instead.",
},
{
// https://mui.com/material-ui/guides/minimizing-bundle-size/
name: '@mui/material',
message: "Please import '@mui/material/...' instead.",
},
...require('module').builtinModules,
...(extraConfig.restrictedImports ?? []),
],
// https://mui.com/material-ui/guides/minimizing-bundle-size/
restrictedImportPatterns: [
'@mui/*/*/*',
...(extraConfig.restrictedImportPatterns ?? []),
],
tsRules: {
'react/prop-types': 0,
...extraConfig.tsRules,
+2 -10
View File
@@ -236,21 +236,13 @@ export type AppOptions = {
* title: 'Light Theme',
* variant: 'light',
* icon: <LightIcon />,
* Provider: ({ children }) => (
* <ThemeProvider theme={lightTheme}>
* <CssBaseline>{children}</CssBaseline>
* </ThemeProvider>
* ),
* Provider: ({ children }) => <UnifiedThemeProvider theme={themes.light} />,
* }, {
* id: 'dark',
* title: 'Dark Theme',
* variant: 'dark',
* icon: <DarkIcon />,
* Provider: ({ children }) => (
* <ThemeProvider theme={darkTheme}>
* <CssBaseline>{children}</CssBaseline>
* </ThemeProvider>
* ),
* Provider: ({ children }) => <UnifiedThemeProvider theme={themes.dark} />,
* }]
* ```
*/
@@ -89,7 +89,11 @@ export function OAuthRequestDialog(_props: {}) {
classes={{ root: classes.title }}
id="oauth-req-dialog-title"
>
<Typography className={classes.titleHeading} variant="h1">
<Typography
className={classes.titleHeading}
variant="h1"
variantMapping={{ h1: 'span' }}
>
Login Required
</Typography>
{authRedirect ? (
@@ -17,9 +17,7 @@
import React, { ComponentType, ReactNode, ReactElement } from 'react';
import { MemoryRouter } from 'react-router-dom';
import { Route } from 'react-router-dom';
import { lightTheme } from '@backstage/theme';
import { ThemeProvider } from '@material-ui/core/styles';
import { CssBaseline } from '@material-ui/core';
import { UnifiedThemeProvider, themes } from '@backstage/theme';
import MockIcon from '@material-ui/icons/AcUnit';
import { createSpecializedApp } from '@backstage/core-app-api';
import {
@@ -142,9 +140,9 @@ export function createTestAppWrapper(
title: 'Test App Theme',
variant: 'light',
Provider: ({ children }) => (
<ThemeProvider theme={lightTheme}>
<CssBaseline>{children}</CssBaseline>
</ThemeProvider>
<UnifiedThemeProvider theme={themes.light}>
{children}
</UnifiedThemeProvider>
),
},
],
+296 -20
View File
@@ -3,13 +3,19 @@
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import type { ComponentsProps } from '@material-ui/core/styles/props';
import { Overrides } from '@material-ui/core/styles/overrides';
import { Palette } from '@material-ui/core/styles/createPalette';
import { PaletteOptions } from '@material-ui/core/styles/createPalette';
import { Theme } from '@material-ui/core';
import { ThemeOptions } from '@material-ui/core';
import type { Palette } from '@material-ui/core/styles/createPalette';
import type { PaletteOptions } from '@material-ui/core/styles/createPalette';
import { PaletteOptions as PaletteOptions_2 } from '@mui/material/styles';
import { ReactNode } from 'react';
import { Theme } from '@mui/material/styles';
import { Theme as Theme_2 } from '@material-ui/core';
import { ThemeOptions } from '@mui/material/styles';
import { ThemeOptions as ThemeOptions_2 } from '@material-ui/core/styles';
import type { ThemeOptions as ThemeOptions_3 } from '@material-ui/core';
// @public
// @public @deprecated
export type BackstagePalette = Palette & BackstagePaletteAdditions;
// @public
@@ -75,12 +81,12 @@ export type BackstagePaletteAdditions = {
};
};
// @public
// @public @deprecated
export type BackstagePaletteOptions = PaletteOptions &
BackstagePaletteAdditions;
// @public
export interface BackstageTheme extends Theme {
// @public @deprecated
export interface BackstageTheme extends Theme_2 {
// (undocumented)
getPageTheme: (selector: PageThemeSelector) => PageTheme;
// (undocumented)
@@ -90,7 +96,13 @@ export interface BackstageTheme extends Theme {
}
// @public
export interface BackstageThemeOptions extends ThemeOptions {
export type BackstageThemeAdditions = {
page: PageTheme;
getPageTheme: (selector: PageThemeSelector) => PageTheme;
};
// @public @deprecated
export interface BackstageThemeOptions extends ThemeOptions_3 {
// (undocumented)
getPageTheme: (selector: PageThemeSelector) => PageTheme;
// (undocumented)
@@ -99,22 +111,86 @@ export interface BackstageThemeOptions extends ThemeOptions {
palette: BackstagePaletteOptions;
}
// @public
export interface BaseThemeOptionsInput<PaletteOptions> {
// (undocumented)
defaultPageTheme?: string;
// (undocumented)
fontFamily?: string;
// (undocumented)
htmlFontSize?: number;
// (undocumented)
pageTheme?: Record<string, PageTheme>;
// (undocumented)
palette: PaletteOptions;
}
// @public
export const colorVariants: Record<string, string[]>;
// @public
export function createTheme(options: SimpleThemeOptions): BackstageTheme;
export function createBaseThemeOptions<PaletteOptions>(
options: BaseThemeOptionsInput<PaletteOptions>,
): {
palette: PaletteOptions;
typography: {
htmlFontSize: number;
fontFamily: string;
h1: {
fontSize: number;
fontWeight: number;
marginBottom: number;
};
h2: {
fontSize: number;
fontWeight: number;
marginBottom: number;
};
h3: {
fontSize: number;
fontWeight: number;
marginBottom: number;
};
h4: {
fontWeight: number;
fontSize: number;
marginBottom: number;
};
h5: {
fontWeight: number;
fontSize: number;
marginBottom: number;
};
h6: {
fontWeight: number;
fontSize: number;
marginBottom: number;
};
};
page: PageTheme;
getPageTheme: ({ themeId }: PageThemeSelector) => PageTheme;
};
// @public @deprecated
export function createTheme(options: SimpleThemeOptions): Theme_2;
// @public @deprecated
export function createThemeOptions(options: SimpleThemeOptions): ThemeOptions_3;
// @public @deprecated
export function createThemeOverrides(theme: Theme_2): Overrides;
// @public
export function createThemeOptions(
options: SimpleThemeOptions,
): BackstageThemeOptions;
export function createUnifiedTheme(options: UnifiedThemeOptions): UnifiedTheme;
// @public
export function createThemeOverrides(theme: BackstageTheme): Overrides;
export function createUnifiedThemeFromV4(options: ThemeOptions_2): UnifiedTheme;
// @public @deprecated
export const darkTheme: Theme_2;
// @public
export const darkTheme: BackstageTheme;
export const defaultComponentThemes: ThemeOptions['components'];
// @public
export function genPageTheme(props: {
@@ -125,8 +201,8 @@ export function genPageTheme(props: {
};
}): PageTheme;
// @public
export const lightTheme: BackstageTheme;
// @public @deprecated
export const lightTheme: Theme_2;
// @public
export type PageTheme = {
@@ -145,14 +221,214 @@ export type PageThemeSelector = {
};
// @public
export const shapes: Record<string, string>;
export const palettes: {
light: {
type: 'light';
mode: 'light';
background: {
default: string;
paper: string;
};
status: {
ok: string;
warning: string;
error: string;
running: string;
pending: string;
aborted: string;
};
bursts: {
fontColor: string;
slackChannelText: string;
backgroundColor: {
default: string;
};
gradient: {
linear: string;
};
};
primary: {
main: string;
};
banner: {
info: string;
error: string;
text: string;
link: string;
closeButtonColor: string;
warning: string;
};
border: string;
textContrast: string;
textVerySubtle: string;
textSubtle: string;
highlight: string;
errorBackground: string;
warningBackground: string;
infoBackground: string;
errorText: string;
infoText: string;
warningText: string;
linkHover: string;
link: string;
gold: string;
navigation: {
background: string;
indicator: string;
color: string;
selectedColor: string;
navItem: {
hoverBackground: string;
};
submenu: {
background: string;
};
};
pinSidebarButton: {
icon: string;
background: string;
};
tabbar: {
indicator: string;
};
};
dark: {
type: 'dark';
mode: 'dark';
background: {
default: string;
paper: string;
};
status: {
ok: string;
warning: string;
error: string;
running: string;
pending: string;
aborted: string;
};
bursts: {
fontColor: string;
slackChannelText: string;
backgroundColor: {
default: string;
};
gradient: {
linear: string;
};
};
primary: {
main: string;
dark: string;
};
secondary: {
main: string;
};
banner: {
info: string;
error: string;
text: string;
link: string;
closeButtonColor: string;
warning: string;
};
border: string;
textContrast: string;
textVerySubtle: string;
textSubtle: string;
highlight: string;
errorBackground: string;
warningBackground: string;
infoBackground: string;
errorText: string;
infoText: string;
warningText: string;
linkHover: string;
link: string;
gold: string;
navigation: {
background: string;
indicator: string;
color: string;
selectedColor: string;
navItem: {
hoverBackground: string;
};
submenu: {
background: string;
};
};
pinSidebarButton: {
icon: string;
background: string;
};
tabbar: {
indicator: string;
};
};
};
// @public
export const shapes: Record<string, string>;
// @public @deprecated
export type SimpleThemeOptions = {
palette: BackstagePaletteOptions;
defaultPageTheme: string;
palette: PaletteOptions;
defaultPageTheme?: string;
pageTheme?: Record<string, PageTheme>;
fontFamily?: string;
htmlFontSize?: number;
};
// @public
export const themes: {
light: UnifiedTheme;
dark: UnifiedTheme;
};
// @public
export function transformV5ComponentThemesToV4(
theme: Theme,
components?: ThemeOptions['components'],
): {
overrides: Overrides;
props: ComponentsProps;
};
// @public
export interface UnifiedTheme {
// (undocumented)
getTheme(version: string): unknown | undefined;
}
// @public
export interface UnifiedThemeOptions {
// (undocumented)
components?: ThemeOptions['components'];
// (undocumented)
defaultPageTheme?: string;
// (undocumented)
fontFamily?: string;
// (undocumented)
htmlFontSize?: number;
// (undocumented)
pageTheme?: Record<string, PageTheme>;
// (undocumented)
palette: PaletteOptions & PaletteOptions_2;
}
// @public
export function UnifiedThemeProvider(
props: UnifiedThemeProviderProps,
): JSX.Element;
// @public
export interface UnifiedThemeProviderProps {
// (undocumented)
children: ReactNode;
// (undocumented)
noCssBaseline?: boolean;
// (undocumented)
theme: UnifiedTheme;
}
```
+5 -1
View File
@@ -32,9 +32,13 @@
"test": "backstage-cli package test"
},
"dependencies": {
"@material-ui/core": "^4.12.2"
"@emotion/react": "^11.10.5",
"@emotion/styled": "^11.10.5",
"@mui/material": "^5.12.2"
},
"peerDependencies": {
"@material-ui/core": "^4.12.2",
"@types/react": "^16.13.1 || ^17.0.0",
"react": "^16.13.1 || ^17.0.0",
"react-dom": "^16.13.1 || ^17.0.0"
},
@@ -0,0 +1,98 @@
/*
* 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 { PageTheme, PageThemeSelector } from './types';
import { pageTheme as defaultPageThemes } from './pageTheme';
const DEFAULT_HTML_FONT_SIZE = 16;
const DEFAULT_FONT_FAMILY =
'"Helvetica Neue", Helvetica, Roboto, Arial, sans-serif';
const DEFAULT_PAGE_THEME = 'home';
/**
* Options for {@link createBaseThemeOptions}.
*
* @public
*/
export interface BaseThemeOptionsInput<PaletteOptions> {
palette: PaletteOptions;
defaultPageTheme?: string;
pageTheme?: Record<string, PageTheme>;
fontFamily?: string;
htmlFontSize?: number;
}
/**
* A helper for creating theme options.
*
* @public
*/
export function createBaseThemeOptions<PaletteOptions>(
options: BaseThemeOptionsInput<PaletteOptions>,
) {
const {
palette,
htmlFontSize = DEFAULT_HTML_FONT_SIZE,
fontFamily = DEFAULT_FONT_FAMILY,
defaultPageTheme = DEFAULT_PAGE_THEME,
pageTheme = defaultPageThemes,
} = options;
if (!pageTheme[defaultPageTheme]) {
throw new Error(`${defaultPageTheme} is not defined in pageTheme.`);
}
return {
palette,
typography: {
htmlFontSize,
fontFamily,
h1: {
fontSize: 54,
fontWeight: 700,
marginBottom: 10,
},
h2: {
fontSize: 40,
fontWeight: 700,
marginBottom: 8,
},
h3: {
fontSize: 32,
fontWeight: 700,
marginBottom: 6,
},
h4: {
fontWeight: 700,
fontSize: 28,
marginBottom: 6,
},
h5: {
fontWeight: 700,
fontSize: 24,
marginBottom: 4,
},
h6: {
fontWeight: 700,
fontSize: 20,
marginBottom: 2,
},
},
page: pageTheme[defaultPageTheme],
getPageTheme: ({ themeId }: PageThemeSelector) =>
pageTheme[themeId] ?? pageTheme[defaultPageTheme],
};
}
+26
View File
@@ -0,0 +1,26 @@
/*
* 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.
*/
export { createBaseThemeOptions } from './createBaseThemeOptions';
export type { BaseThemeOptionsInput } from './createBaseThemeOptions';
export { colorVariants, genPageTheme, pageTheme, shapes } from './pageTheme';
export { palettes } from './palettes';
export type {
BackstageThemeAdditions,
BackstagePaletteAdditions,
PageTheme,
PageThemeSelector,
} from './types';
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { PageTheme } from './types';
/**
@@ -14,20 +14,18 @@
* limitations under the License.
*/
import { createTheme } from './baseTheme';
import { pageTheme } from './pageTheme';
import { yellow } from '@material-ui/core/colors';
/**
* The default Backstage light theme.
* Built-in Backstage color palettes.
*
* @public
*/
export const lightTheme = createTheme({
palette: {
type: 'light',
export const palettes = {
light: {
type: 'light' as const,
mode: 'light' as const,
background: {
default: '#F8F8F8',
paper: '#FFFFFF',
},
status: {
ok: '#1DB954',
@@ -71,7 +69,7 @@ export const lightTheme = createTheme({
warningText: '#000000',
linkHover: '#2196F3',
link: '#0A6EBE',
gold: yellow.A700,
gold: '#FFD600',
navigation: {
background: '#171717',
indicator: '#9BF0E1',
@@ -92,20 +90,12 @@ export const lightTheme = createTheme({
indicator: '#9BF0E1',
},
},
defaultPageTheme: 'home',
pageTheme,
});
/**
* The default Backstage dark theme.
*
* @public
*/
export const darkTheme = createTheme({
palette: {
type: 'dark',
dark: {
type: 'dark' as const,
mode: 'dark' as const,
background: {
default: '#333333',
paper: '#424242',
},
status: {
ok: '#71CF88',
@@ -153,7 +143,7 @@ export const darkTheme = createTheme({
warningText: '#000000',
linkHover: '#82BAFD',
link: '#9CC9FF',
gold: yellow.A700,
gold: '#FFD600',
navigation: {
background: '#424242',
indicator: '#9BF0E1',
@@ -174,6 +164,4 @@ export const darkTheme = createTheme({
indicator: '#9BF0E1',
},
},
defaultPageTheme: 'home',
pageTheme,
});
};
@@ -1,5 +1,5 @@
/*
* Copyright 2020 The Backstage Authors
* 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.
@@ -14,12 +14,6 @@
* limitations under the License.
*/
import { Theme, ThemeOptions } from '@material-ui/core';
import {
PaletteOptions,
Palette,
} from '@material-ui/core/styles/createPalette';
/**
* Backstage specific additions to the material-ui palette.
*
@@ -90,21 +84,6 @@ export type BackstagePaletteAdditions = {
};
};
/**
* The full Backstage palette.
*
* @public
*/
export type BackstagePalette = Palette & BackstagePaletteAdditions;
/**
* The full Backstage palette options.
*
* @public
*/
export type BackstagePaletteOptions = PaletteOptions &
BackstagePaletteAdditions;
/**
* Selector for what page theme to use.
*
@@ -114,48 +93,6 @@ export type PageThemeSelector = {
themeId: string;
};
/**
* A Backstage theme.
*
* @public
*/
export interface BackstageTheme extends Theme {
palette: BackstagePalette;
page: PageTheme;
getPageTheme: (selector: PageThemeSelector) => PageTheme;
}
/**
* Backstage theme options.
*
* @public
* @remarks
*
* This is essentially a partial theme definition made by the user, that then
* gets merged together with defaults and other values to form the final
* {@link BackstageTheme}.
*
*/
export interface BackstageThemeOptions extends ThemeOptions {
palette: BackstagePaletteOptions;
page: PageTheme;
getPageTheme: (selector: PageThemeSelector) => PageTheme;
}
/**
* A simpler configuration for creating a new theme that just tweaks some parts
* of the backstage one.
*
* @public
*/
export type SimpleThemeOptions = {
palette: BackstagePaletteOptions;
defaultPageTheme: string;
pageTheme?: Record<string, PageTheme>;
fontFamily?: string;
htmlFontSize?: number;
};
/**
* The theme definitions for a given layout page.
*
@@ -167,3 +104,13 @@ export type PageTheme = {
backgroundImage: string;
fontColor: string;
};
/**
* Backstage specific additions to the material-ui theme.
*
* @public
*/
export type BackstageThemeAdditions = {
page: PageTheme;
getPageTheme: (selector: PageThemeSelector) => PageTheme;
};
+5 -5
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2020 The Backstage Authors
* 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.
@@ -20,7 +20,7 @@
* @packageDocumentation
*/
export * from './themes';
export * from './baseTheme';
export * from './types';
export * from './pageTheme';
export * from './unified';
export * from './base';
export * from './v4';
export * from './v5';
@@ -0,0 +1,24 @@
/*
* 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 { unstable_ClassNameGenerator as ClassNameGenerator } from '@mui/material/className';
/**
* This API is introduced in @mui/material (v5.0.5) as a replacement of deprecated createGenerateClassName & only affects v5 MUI components from `@mui/*`
*/
ClassNameGenerator.configure(componentName => {
return `v5-${componentName}`;
});
+101
View File
@@ -0,0 +1,101 @@
/*
* 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 as Mui4Theme,
ThemeOptions as ThemeOptionsV4,
createTheme,
} from '@material-ui/core/styles';
import type { PaletteOptions as PaletteOptionsV4 } from '@material-ui/core/styles/createPalette';
import { PaletteOptions as PaletteOptionsV5 } from '@mui/material/styles';
import {
adaptV4Theme,
Theme as Mui5Theme,
createTheme as createV5Theme,
ThemeOptions as ThemeOptionsV5,
} from '@mui/material/styles';
import { transformV5ComponentThemesToV4 } from './overrides';
import { PageTheme } from '../base/types';
import { defaultComponentThemes } from '../v5';
import { createBaseThemeOptions } from '../base/createBaseThemeOptions';
import { UnifiedTheme } from './types';
export class UnifiedThemeHolder implements UnifiedTheme {
#themes = new Map<string, unknown>();
constructor(v4?: Mui4Theme, v5?: Mui5Theme) {
this.#themes = new Map();
if (v4) {
this.#themes.set('v4', v4);
}
if (v5) {
this.#themes.set('v5', v5);
}
}
getTheme(version: string): unknown | undefined {
return this.#themes.get(version);
}
}
/**
* Options for creating a new {@link UnifiedTheme}.
*
* @public
*/
export interface UnifiedThemeOptions {
palette: PaletteOptionsV4 & PaletteOptionsV5;
defaultPageTheme?: string;
pageTheme?: Record<string, PageTheme>;
fontFamily?: string;
htmlFontSize?: number;
components?: ThemeOptionsV5['components'];
}
/**
* Creates a new {@link UnifiedTheme} using the provided options.
*
* @public
*/
export function createUnifiedTheme(options: UnifiedThemeOptions): UnifiedTheme {
const themeOptions = createBaseThemeOptions(options);
const components = { ...defaultComponentThemes, ...options.components };
const v5Theme = createV5Theme({ ...themeOptions, components });
// TODO: Not super relevant in the beginning
/* const mui4Styles = maybeLoadMui4Styles();
if (!mui4Styles) {
return new UnifiedThemeHolder(undefined, v5Theme);
} */
const v4Overrides = transformV5ComponentThemesToV4(v5Theme, components);
const v4Theme = { ...createTheme(themeOptions), ...v4Overrides };
return new UnifiedThemeHolder(v4Theme, v5Theme);
}
/**
* Creates a new {@link UnifiedTheme} using MUI v4 theme options.
* Note that this uses `adaptV4Theme` from MUI v5, which is deprecated.
*
* @public
*/
export function createUnifiedThemeFromV4(
options: ThemeOptionsV4,
): UnifiedTheme {
const v5Theme = adaptV4Theme(options as any);
const v4Theme = createTheme(options);
return new UnifiedThemeHolder(v4Theme, v5Theme);
}
@@ -0,0 +1,76 @@
/*
* 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 React, { ReactNode } from 'react';
import './MuiClassNameSetup';
import { ThemeProvider } from '@material-ui/core/styles';
import {
StyledEngineProvider,
ThemeProvider as Mui5Provider,
} from '@mui/material/styles';
import CSSBaseline from '@mui/material/CssBaseline';
import { UnifiedTheme } from './types';
/**
* Props for {@link UnifiedThemeProvider}.
*
* @public
*/
export interface UnifiedThemeProviderProps {
children: ReactNode;
theme: UnifiedTheme;
noCssBaseline?: boolean;
}
/**
* Provides themes for all MUI versions supported by the provided unified theme.
*
* @public
*/
export function UnifiedThemeProvider(
props: UnifiedThemeProviderProps,
): JSX.Element {
const { children, theme, noCssBaseline = false } = props;
const v4Theme = theme.getTheme('v4');
const v5Theme = theme.getTheme('v5');
let cssBaseline: JSX.Element | undefined = undefined;
if (!noCssBaseline) {
cssBaseline = <CSSBaseline />;
}
let result = (
<>
{cssBaseline}
{children}
</>
);
if (v4Theme) {
result = <ThemeProvider theme={v4Theme}>{result}</ThemeProvider>;
}
if (v5Theme) {
result = (
<StyledEngineProvider injectFirst>
<Mui5Provider theme={v5Theme}>{result}</Mui5Provider>
</StyledEngineProvider>
);
}
return result;
}
+23
View File
@@ -0,0 +1,23 @@
/*
* 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.
*/
export { transformV5ComponentThemesToV4 } from './overrides';
export { createUnifiedTheme, createUnifiedThemeFromV4 } from './UnifiedTheme';
export type { UnifiedThemeOptions } from './UnifiedTheme';
export { themes } from './themes';
export { UnifiedThemeProvider } from './UnifiedThemeProvider';
export type { UnifiedThemeProviderProps } from './UnifiedThemeProvider';
export type { UnifiedTheme } from './types';
@@ -0,0 +1,165 @@
/*
* 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/styles';
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 => ({
html: {
color: theme.palette.primary.main,
},
}),
defaultProps: {
enableColorScheme: true,
},
},
}),
).toEqual({
overrides: {
MuiCssBaseline: {
'@global': {
html: {
color: 'red',
},
},
},
},
props: {
MuiCssBaseline: {
enableColorScheme: true,
},
},
});
});
it('transform state styles', () => {
expect(
transformV5ComponentThemesToV4(mockTheme, {
MuiButton: {
styleOverrides: {
root: {
color: 'green',
'&.Mui-disabled': {
color: 'red',
},
},
},
},
}),
).toEqual({
overrides: {
MuiButton: {
root: {
color: 'green',
},
disabled: {
color: 'red',
},
},
},
props: {},
});
});
});
+142
View File
@@ -0,0 +1,142 @@
/*
* 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 type { Overrides } from '@material-ui/core/styles/overrides';
import type { ComponentsProps } from '@material-ui/core/styles/props';
import { ComponentsOverrides, Theme, ThemeOptions } from '@mui/material/styles';
import { CSSProperties } from 'react';
type V5Override = ComponentsOverrides[Exclude<
keyof ComponentsOverrides,
'MuiCssBaseline'
>];
type V4Override = Overrides[keyof Overrides];
type StaticStyleRules = Record<
string,
CSSProperties | Record<string, CSSProperties>
>;
// Converts callback-based overrides to static styles, e.g.
// { root: theme => ({ color: theme.color }) } -> { root: { color: 'red' } }
function adaptV5CssBaselineOverride(
theme: Theme,
overrides: ComponentsOverrides['MuiCssBaseline'],
): StaticStyleRules | undefined {
if (!overrides || typeof overrides === 'string') {
return undefined;
}
const styles = typeof overrides === 'function' ? overrides(theme) : overrides;
if (styles) {
return { '@global': styles } as StaticStyleRules;
}
return undefined;
}
// Converts callback-based overrides to static styles, e.g.
// { root: theme => ({ color: theme.color }) } -> { root: { color: 'red' } }
function adaptV5Override(
theme: Theme,
overrides: V5Override,
): StaticStyleRules | undefined {
if (!overrides || typeof overrides === 'string') {
return undefined;
}
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 StaticStyleRules;
}
const stateStyleKeyPattern = /^&.Mui-([\w-]+)$/;
// Move state style overrides to the top level, e.g.
// { root: { '&.Mui-active': { color: 'red' } } } -> { active: { color: 'red' } }
function extractV5StateOverrides(
overrides: StaticStyleRules | undefined,
): StaticStyleRules | undefined {
let output = overrides;
if (!overrides || typeof overrides !== 'object') {
return output;
}
for (const className of Object.keys(overrides)) {
const styles = overrides[className];
if (!styles || typeof styles !== 'object') {
continue;
}
for (const _styleKey of Object.keys(styles)) {
const styleKey = _styleKey as keyof typeof styles;
const match = styleKey.match(stateStyleKeyPattern);
if (match) {
const [, state] = match;
const { [styleKey]: stateStyles, ...restStyles } = styles;
if (stateStyles) {
output = {
...output,
[className]: restStyles,
[state]: stateStyles,
};
}
}
}
}
return output;
}
/**
* Transform MUI v5 component themes into a v4 theme props and overrides.
*
* @public
*/
export function transformV5ComponentThemesToV4(
theme: Theme,
components: ThemeOptions['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) {
if (name === 'MuiCssBaseline') {
overrides[name] = adaptV5CssBaselineOverride(
theme,
component.styleOverrides as ComponentsOverrides['MuiCssBaseline'],
);
} else {
overrides[name] = extractV5StateOverrides(
adaptV5Override(theme, component.styleOverrides as V5Override),
);
}
}
if ('defaultProps' in component) {
props[name] = component.defaultProps;
}
}
return { overrides, props };
}
+28
View File
@@ -0,0 +1,28 @@
/*
* 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 { palettes } from '../base';
import { createUnifiedTheme } from './UnifiedTheme';
/**
* Built-in Backstage MUI themes.
*
* @public
*/
export const themes = {
light: createUnifiedTheme({ palette: palettes.light }),
dark: createUnifiedTheme({ palette: palettes.dark }),
};
+26
View File
@@ -0,0 +1,26 @@
/*
* 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.
*/
/**
* A container of one theme for multiple different MUI versions.
*
* Currently known keys are 'v4' and 'v5'.
*
* @public
*/
export interface UnifiedTheme {
getTheme(version: string): unknown | undefined;
}
+76
View File
@@ -0,0 +1,76 @@
/*
* Copyright 2020 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 as Mui5Theme } from '@mui/material/styles';
import { createTheme as createMuiTheme } from '@material-ui/core/styles';
import type {
GridProps,
SwitchProps,
Theme,
ThemeOptions,
} from '@material-ui/core';
import { Overrides } from '@material-ui/core/styles/overrides';
import { SimpleThemeOptions } from './types';
import { createBaseThemeOptions } from '../base';
import { defaultComponentThemes } from '../v5';
import { transformV5ComponentThemesToV4 } from '../unified/overrides';
/**
* An old helper for creating MUI v4 theme options.
*
* @public
* @deprecated Use {@link createBaseThemeOptions} instead.
*/
export function createThemeOptions(options: SimpleThemeOptions): ThemeOptions {
return {
props: {
MuiGrid: defaultComponentThemes?.MuiGrid
?.defaultProps as Partial<GridProps>,
MuiSwitch: defaultComponentThemes?.MuiSwitch
?.defaultProps as Partial<SwitchProps>,
},
...createBaseThemeOptions(options),
};
}
/**
* * An old helper for creating MUI v4 theme overrides.
*
* @public
* @deprecated Use {@link defaultComponentThemes} with {@link transformV5ComponentThemesToV4} instead.
*/
export function createThemeOverrides(theme: Theme): Overrides {
return transformV5ComponentThemesToV4(
// Safe but we have to make sure we don't use mui5 specific stuff in the default component themes
theme as unknown as Mui5Theme,
defaultComponentThemes,
).overrides;
}
/**
* The old method to create a Backstage MUI v4 theme using a palette.
* The theme is created with the common Backstage options and component styles.
*
* @public
* @deprecated Use {@link createUnifiedTheme} instead.
*/
export function createTheme(options: SimpleThemeOptions): Theme {
const themeOptions = createThemeOptions(options);
const baseTheme = createMuiTheme(themeOptions);
const overrides = createThemeOverrides(baseTheme);
const theme = { ...baseTheme, overrides };
return theme;
}
+29
View File
@@ -0,0 +1,29 @@
/*
* Copyright 2020 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.
*/
export { darkTheme, lightTheme } from './themes';
export {
createTheme,
createThemeOptions,
createThemeOverrides,
} from './baseTheme';
export type {
BackstagePalette,
BackstagePaletteOptions,
BackstageTheme,
BackstageThemeOptions,
SimpleThemeOptions,
} from './types';
+38
View File
@@ -0,0 +1,38 @@
/*
* Copyright 2020 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 { createTheme } from './baseTheme';
import { palettes } from '../base';
/**
* The old MUI v4 Backstage light theme.
*
* @public
* @deprecated Use {@link themes.light} instead.
*/
export const lightTheme = createTheme({
palette: palettes.light,
});
/**
* The old MUI v4 Backstage dark theme.
*
* @public
* @deprecated Use {@link themes.dark} instead.
*/
export const darkTheme = createTheme({
palette: palettes.dark,
});
+104
View File
@@ -0,0 +1,104 @@
/*
* Copyright 2020 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 type {
Theme as MuiTheme,
ThemeOptions as MuiThemeOptions,
} from '@material-ui/core';
import type {
PaletteOptions as MuiPaletteOptions,
Palette as MuiPalette,
} from '@material-ui/core/styles/createPalette';
import {
BackstagePaletteAdditions,
BackstageThemeAdditions,
PageTheme,
PageThemeSelector,
} from '../base/types';
/**
* The full Backstage palette.
*
* @public
* @deprecated This type is deprecated, the MUI Palette type is now always extended instead.
*/
export type BackstagePalette = MuiPalette & BackstagePaletteAdditions;
/**
* The full Backstage palette options.
*
* @public
* @deprecated This type is deprecated, the MUI PaletteOptions type is now always extended instead.
*/
export type BackstagePaletteOptions = MuiPaletteOptions &
BackstagePaletteAdditions;
/**
* Backstage theme options.
*
* @public
* @deprecated This type is deprecated, the MUI ThemeOptions type is now always extended instead.
* @remarks
*
* This is essentially a partial theme definition made by the user, that then
* gets merged together with defaults and other values to form the final
* {@link BackstageTheme}.
*
*/
export interface BackstageThemeOptions extends MuiThemeOptions {
palette: BackstagePaletteOptions;
page: PageTheme;
getPageTheme: (selector: PageThemeSelector) => PageTheme;
}
/**
* A Backstage theme.
*
* @public
* @deprecated This type is deprecated, the MUI Theme type is now always extended instead.
*/
export interface BackstageTheme extends MuiTheme {
palette: BackstagePalette;
page: PageTheme;
getPageTheme: (selector: PageThemeSelector) => PageTheme;
}
/**
* A simpler configuration for creating a new theme that just tweaks some parts
* of the backstage one.
*
* @public
* @deprecated Use {@link BaseThemeOptionsInput} instead.
*/
export type SimpleThemeOptions = {
palette: MuiPaletteOptions;
defaultPageTheme?: string;
pageTheme?: Record<string, PageTheme>;
fontFamily?: string;
htmlFontSize?: number;
};
declare module '@material-ui/core/styles/createPalette' {
interface Palette extends BackstagePaletteAdditions {}
interface PaletteOptions extends BackstagePaletteAdditions {}
}
declare module '@material-ui/core/styles/createTheme' {
interface Theme extends BackstageThemeAdditions {}
interface ThemeOptions extends BackstageThemeAdditions {}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2020 The Backstage Authors
* 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.
@@ -14,121 +14,51 @@
* limitations under the License.
*/
import { createTheme as createMuiTheme } from '@material-ui/core/styles';
import { darken, lighten } from '@material-ui/core/styles/colorManipulator';
import { Overrides } from '@material-ui/core/styles/overrides';
import {
BackstageTheme,
BackstageThemeOptions,
SimpleThemeOptions,
} from './types';
import { pageTheme as defaultPageThemes } from './pageTheme';
const DEFAULT_HTML_FONT_SIZE = 16;
const DEFAULT_FONT_FAMILY =
'"Helvetica Neue", Helvetica, Roboto, Arial, sans-serif';
/**
* A helper for creating theme options.
*
* @public
*/
export function createThemeOptions(
options: SimpleThemeOptions,
): BackstageThemeOptions {
const {
palette,
htmlFontSize = DEFAULT_HTML_FONT_SIZE,
fontFamily = DEFAULT_FONT_FAMILY,
defaultPageTheme,
pageTheme = defaultPageThemes,
} = options;
if (!pageTheme[defaultPageTheme]) {
throw new Error(`${defaultPageTheme} is not defined in pageTheme.`);
}
return {
palette,
props: {
MuiGrid: {
spacing: 2,
},
MuiSwitch: {
color: 'primary',
},
},
typography: {
htmlFontSize,
fontFamily,
h6: {
fontWeight: 700,
fontSize: 20,
marginBottom: 2,
},
h5: {
fontWeight: 700,
fontSize: 24,
marginBottom: 4,
},
h4: {
fontWeight: 700,
fontSize: 28,
marginBottom: 6,
},
h3: {
fontSize: 32,
fontWeight: 700,
marginBottom: 6,
},
h2: {
fontSize: 40,
fontWeight: 700,
marginBottom: 8,
},
h1: {
fontSize: 54,
fontWeight: 700,
marginBottom: 10,
},
},
page: pageTheme[defaultPageTheme],
getPageTheme: ({ themeId }) =>
pageTheme[themeId] ?? pageTheme[defaultPageTheme],
};
}
import { darken, lighten, ThemeOptions } from '@mui/material/styles';
/**
* A helper for creating theme overrides.
*
* @public
*/
export function createThemeOverrides(theme: BackstageTheme): Overrides {
return {
MuiCssBaseline: {
'@global': {
html: {
height: '100%',
fontFamily: theme.typography.fontFamily,
},
body: {
height: '100%',
fontFamily: theme.typography.fontFamily,
'overscroll-behavior-y': 'none',
},
a: {
color: 'inherit',
textDecoration: 'none',
},
export const defaultComponentThemes: ThemeOptions['components'] = {
MuiCssBaseline: {
styleOverrides: theme => ({
html: {
height: '100%',
fontFamily: theme.typography.fontFamily,
},
body: {
height: '100%',
fontFamily: theme.typography.fontFamily,
overscrollBehaviorY: 'none',
fontSize: '0.875rem',
lineHeight: 1.43,
},
a: {
color: 'inherit',
textDecoration: 'none',
},
}),
},
MuiGrid: {
defaultProps: {
spacing: 2,
},
MuiTableRow: {
},
MuiSwitch: {
defaultProps: {
color: 'primary',
},
},
MuiTableRow: {
styleOverrides: {
// Alternating row backgrounds
root: {
root: ({ theme }) => ({
'&:nth-of-type(odd)': {
backgroundColor: theme.palette.background.default,
},
},
}),
// Use pointer for hoverable rows
hover: {
'&:hover': {
@@ -136,15 +66,17 @@ export function createThemeOverrides(theme: BackstageTheme): Overrides {
},
},
// Alternating head backgrounds
head: {
head: ({ theme }) => ({
'&:nth-of-type(odd)': {
backgroundColor: theme.palette.background.paper,
},
},
}),
},
// Tables are more dense than default mui tables
MuiTableCell: {
root: {
},
// Tables are more dense than default mui tables
MuiTableCell: {
styleOverrides: {
root: ({ theme }) => ({
wordBreak: 'break-word',
overflow: 'hidden',
verticalAlign: 'middle',
@@ -152,26 +84,31 @@ export function createThemeOverrides(theme: BackstageTheme): Overrides {
margin: 0,
padding: theme.spacing(3, 2, 3, 2.5),
borderBottom: 0,
},
sizeSmall: {
}),
sizeSmall: ({ theme }) => ({
padding: theme.spacing(1.5, 2, 1.5, 2.5),
},
head: {
}),
head: ({ theme }) => ({
wordBreak: 'break-word',
overflow: 'hidden',
color: theme.palette.textSubtle,
fontWeight: 'normal',
lineHeight: '1',
},
}),
},
MuiTabs: {
},
MuiTabs: {
styleOverrides: {
// Tabs are smaller than default mui tab rows
root: {
minHeight: 24,
},
},
MuiTab: {
},
MuiTab: {
styleOverrides: {
// Tabs are smaller and have a hover background
root: {
root: ({ theme }) => ({
color: theme.palette.link,
minHeight: 24,
textTransform: 'initial',
@@ -185,25 +122,33 @@ export function createThemeOverrides(theme: BackstageTheme): Overrides {
fontSize: theme.typography.pxToRem(14),
fontWeight: 500,
},
},
textColorPrimary: {
}),
textColorPrimary: ({ theme }) => ({
color: theme.palette.link,
},
}),
},
MuiTableSortLabel: {
},
MuiTableSortLabel: {
styleOverrides: {
// No color change on hover, just rely on the arrow showing up instead.
root: {
color: 'inherit',
'&:hover': {
color: 'inherit',
},
},
// Bold font for highlighting selected column
active: {
fontWeight: 'bold',
'&:focus': {
color: 'inherit',
},
// Bold font for highlighting selected column
'&.Mui-active': {
fontWeight: 'bold',
color: 'inherit',
},
},
},
MuiListItemText: {
},
MuiListItemText: {
styleOverrides: {
dense: {
// Default dense list items to adding ellipsis for really long str...
whiteSpace: 'nowrap',
@@ -211,44 +156,50 @@ export function createThemeOverrides(theme: BackstageTheme): Overrides {
textOverflow: 'ellipsis',
},
},
MuiButton: {
},
MuiButton: {
styleOverrides: {
text: {
// Text buttons have less padding by default, but we want to keep the original padding
padding: undefined,
},
},
MuiChip: {
root: {
},
MuiChip: {
styleOverrides: {
root: ({ theme }) => ({
backgroundColor: '#D9D9D9',
// By default there's no margin, but it's usually wanted, so we add some trailing margin
marginRight: theme.spacing(1),
marginBottom: theme.spacing(1),
color: theme.palette.grey[900],
},
outlined: {
}),
outlined: ({ theme }) => ({
color: theme.palette.text.primary,
},
label: {
lineHeight: `${theme.spacing(2.5)}px`,
}),
label: ({ theme }) => ({
lineHeight: theme.spacing(2.5),
fontWeight: theme.typography.fontWeightMedium,
fontSize: `${theme.spacing(1.75)}px`,
},
labelSmall: {
fontSize: `${theme.spacing(1.5)}px`,
},
deleteIcon: {
fontSize: theme.spacing(1.75),
}),
labelSmall: ({ theme }) => ({
fontSize: theme.spacing(1.5),
}),
deleteIcon: ({ theme }) => ({
color: theme.palette.grey[500],
width: `${theme.spacing(3)}px`,
height: `${theme.spacing(3)}px`,
margin: `0 ${theme.spacing(0.75)}px 0 -${theme.spacing(0.75)}px`,
},
deleteIconSmall: {
width: `${theme.spacing(2)}px`,
height: `${theme.spacing(2)}px`,
margin: `0 ${theme.spacing(0.5)}px 0 -${theme.spacing(0.5)}px`,
},
width: theme.spacing(3),
height: theme.spacing(3),
margin: `0 ${theme.spacing(0.75)} 0 -${theme.spacing(0.75)}`,
}),
deleteIconSmall: ({ theme }) => ({
width: theme.spacing(2),
height: theme.spacing(2),
margin: `0 ${theme.spacing(0.5)} 0 -${theme.spacing(0.5)}`,
}),
},
MuiCard: {
},
MuiCard: {
styleOverrides: {
root: {
// When cards have a forced size, such as when they are arranged in a
// CSS grid, the content needs to flex such that the actions (buttons
@@ -258,13 +209,17 @@ export function createThemeOverrides(theme: BackstageTheme): Overrides {
flexDirection: 'column',
},
},
MuiCardHeader: {
},
MuiCardHeader: {
styleOverrides: {
root: {
// Reduce padding between header and content
paddingBottom: 0,
},
},
MuiCardContent: {
},
MuiCardContent: {
styleOverrides: {
root: {
// When cards have a forced size, such as when they are arranged in a
// CSS grid, the content needs to flex such that the actions (buttons
@@ -276,25 +231,13 @@ export function createThemeOverrides(theme: BackstageTheme): Overrides {
},
},
},
MuiCardActions: {
},
MuiCardActions: {
styleOverrides: {
root: {
// We default to putting the card actions at the end
justifyContent: 'flex-end',
},
},
};
}
/**
* Creates a Backstage MUI theme using a palette. The theme is created with the
* common Backstage options and component styles.
*
* @public
*/
export function createTheme(options: SimpleThemeOptions): BackstageTheme {
const themeOptions = createThemeOptions(options);
const baseTheme = createMuiTheme(themeOptions) as BackstageTheme;
const overrides = createThemeOverrides(baseTheme);
const theme = { ...baseTheme, overrides };
return theme;
}
},
};
+18
View File
@@ -0,0 +1,18 @@
/*
* 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.
*/
export * from './types';
export { defaultComponentThemes } from './defaultComponentThemes';
+37
View File
@@ -0,0 +1,37 @@
/*
* 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/styles';
import {
BackstagePaletteAdditions,
BackstageThemeAdditions,
} from '../base/types';
declare module '@mui/material/styles' {
interface Palette extends BackstagePaletteAdditions {}
interface PaletteOptions extends BackstagePaletteAdditions {}
}
declare module '@mui/material/styles' {
interface Theme extends BackstageThemeAdditions {}
interface ThemeOptions extends BackstageThemeAdditions {}
}
declare module '@mui/private-theming/defaultTheme' {
interface DefaultTheme extends Theme {}
}
@@ -24,7 +24,7 @@ describe('<EntityKindIcon />', () => {
<EntityKindIcon kind="Component" />,
);
expect(baseElement.querySelector('.MuiSvgIcon-root')).toBeInTheDocument();
expect(baseElement.querySelector('svg')).toBeInTheDocument();
});
it('renders without exploding for unknown kind', async () => {
@@ -32,6 +32,6 @@ describe('<EntityKindIcon />', () => {
<EntityKindIcon kind="unknown" />,
);
expect(baseElement.querySelector('.MuiSvgIcon-root')).toBeInTheDocument();
expect(baseElement.querySelector('svg')).toBeInTheDocument();
});
});
@@ -278,7 +278,7 @@ export class TechDocsAddonTester {
render(this.build());
});
const shadowHost = screen.getByTestId('techdocs-native-shadowroot');
const shadowHost = await screen.findByTestId('techdocs-native-shadowroot');
return {
...screen,
+402 -81
View File
@@ -2248,7 +2248,7 @@ __metadata:
languageName: node
linkType: hard
"@babel/helper-module-imports@npm:^7.0.0, @babel/helper-module-imports@npm:^7.12.13, @babel/helper-module-imports@npm:^7.16.0, @babel/helper-module-imports@npm:^7.18.6":
"@babel/helper-module-imports@npm:^7.0.0, @babel/helper-module-imports@npm:^7.12.13, @babel/helper-module-imports@npm:^7.16.0, @babel/helper-module-imports@npm:^7.16.7, @babel/helper-module-imports@npm:^7.18.6":
version: 7.18.6
resolution: "@babel/helper-module-imports@npm:7.18.6"
dependencies:
@@ -2730,7 +2730,7 @@ __metadata:
languageName: node
linkType: hard
"@babel/plugin-syntax-jsx@npm:^7.0.0, @babel/plugin-syntax-jsx@npm:^7.18.6, @babel/plugin-syntax-jsx@npm:^7.7.2":
"@babel/plugin-syntax-jsx@npm:^7.0.0, @babel/plugin-syntax-jsx@npm:^7.17.12, @babel/plugin-syntax-jsx@npm:^7.18.6, @babel/plugin-syntax-jsx@npm:^7.7.2":
version: 7.18.6
resolution: "@babel/plugin-syntax-jsx@npm:7.18.6"
dependencies:
@@ -3472,7 +3472,7 @@ __metadata:
languageName: node
linkType: hard
"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.14.6, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.18.6, @babel/runtime@npm:^7.2.0, @babel/runtime@npm:^7.20.1, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.4.4, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.0, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.3, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2":
"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.14.6, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.18.6, @babel/runtime@npm:^7.2.0, @babel/runtime@npm:^7.20.1, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.4.4, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.0, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.3, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2":
version: 7.21.0
resolution: "@babel/runtime@npm:7.21.0"
dependencies:
@@ -9627,9 +9627,13 @@ __metadata:
resolution: "@backstage/theme@workspace:packages/theme"
dependencies:
"@backstage/cli": "workspace:^"
"@material-ui/core": ^4.12.2
"@emotion/react": ^11.10.5
"@emotion/styled": ^11.10.5
"@mui/material": ^5.12.2
"@types/react": ^16.13.1 || ^17.0.0
peerDependencies:
"@material-ui/core": ^4.12.2
"@types/react": ^16.13.1 || ^17.0.0
react: ^16.13.1 || ^17.0.0
react-dom: ^16.13.1 || ^17.0.0
languageName: unknown
@@ -10157,6 +10161,41 @@ __metadata:
languageName: node
linkType: hard
"@emotion/babel-plugin@npm:^11.10.5":
version: 11.10.5
resolution: "@emotion/babel-plugin@npm:11.10.5"
dependencies:
"@babel/helper-module-imports": ^7.16.7
"@babel/plugin-syntax-jsx": ^7.17.12
"@babel/runtime": ^7.18.3
"@emotion/hash": ^0.9.0
"@emotion/memoize": ^0.8.0
"@emotion/serialize": ^1.1.1
babel-plugin-macros: ^3.1.0
convert-source-map: ^1.5.0
escape-string-regexp: ^4.0.0
find-root: ^1.1.0
source-map: ^0.5.7
stylis: 4.1.3
peerDependencies:
"@babel/core": ^7.0.0
checksum: e3353499c76c4422d6e900c0dfab73607056d9da86161a3f27c3459c193c4908050c5d252c68fcde231e13f02a9d8e0dc07d260317ae0e5206841e331cc4caae
languageName: node
linkType: hard
"@emotion/cache@npm:^11.10.5, @emotion/cache@npm:^11.10.7":
version: 11.10.7
resolution: "@emotion/cache@npm:11.10.7"
dependencies:
"@emotion/memoize": ^0.8.0
"@emotion/sheet": ^1.2.1
"@emotion/utils": ^1.2.0
"@emotion/weak-memoize": ^0.3.0
stylis: 4.1.3
checksum: 6b1efed2dffc93dac419409d91f6d57a200d858ec5ffa4b7c30080fdbd93db431ff86bb779c5b8830b8373f3c5dd754d9beb386604ed2667c7d55608ff653dfc
languageName: node
linkType: hard
"@emotion/hash@npm:^0.8.0":
version: 0.8.0
resolution: "@emotion/hash@npm:0.8.0"
@@ -10164,19 +10203,93 @@ __metadata:
languageName: node
linkType: hard
"@emotion/is-prop-valid@npm:^1.1.0":
version: 1.1.2
resolution: "@emotion/is-prop-valid@npm:1.1.2"
dependencies:
"@emotion/memoize": ^0.7.4
checksum: 58b1f2d429a589f8f5bc2c33a8732cbb7bbcb17131a103511ef9a94ac754d7eeb53d627f947da480cd977f9d419fd92e244991680292f3287204159652745707
"@emotion/hash@npm:^0.9.0":
version: 0.9.0
resolution: "@emotion/hash@npm:0.9.0"
checksum: b63428f7c8186607acdca5d003700cecf0ded519d0b5c5cc3b3154eafcad6ff433f8361bd2bac8882715b557e6f06945694aeb6ba8b25c6095d7a88570e2e0bb
languageName: node
linkType: hard
"@emotion/memoize@npm:^0.7.4":
version: 0.7.5
resolution: "@emotion/memoize@npm:0.7.5"
checksum: 83da8d4a7649a92c72f960817692bc6be13cc13e107b9f7e878d63766525ed4402881bfeb3cda61145c050281e7e260f114a0a2870515527346f2ef896b915b3
"@emotion/is-prop-valid@npm:^1.1.0, @emotion/is-prop-valid@npm:^1.2.0":
version: 1.2.0
resolution: "@emotion/is-prop-valid@npm:1.2.0"
dependencies:
"@emotion/memoize": ^0.8.0
checksum: cc7a19850a4c5b24f1514665289442c8c641709e6f7711067ad550e05df331da0692a16148e85eda6f47e31b3261b64d74c5e25194d053223be16231f969d633
languageName: node
linkType: hard
"@emotion/memoize@npm:^0.8.0":
version: 0.8.0
resolution: "@emotion/memoize@npm:0.8.0"
checksum: c87bb110b829edd8e1c13b90a6bc37cebc39af29c7599a1e66a48e06f9bec43e8e53495ba86278cc52e7589549492c8dfdc81d19f4fdec0cee6ba13d2ad2c928
languageName: node
linkType: hard
"@emotion/react@npm:^11.10.5":
version: 11.10.5
resolution: "@emotion/react@npm:11.10.5"
dependencies:
"@babel/runtime": ^7.18.3
"@emotion/babel-plugin": ^11.10.5
"@emotion/cache": ^11.10.5
"@emotion/serialize": ^1.1.1
"@emotion/use-insertion-effect-with-fallbacks": ^1.0.0
"@emotion/utils": ^1.2.0
"@emotion/weak-memoize": ^0.3.0
hoist-non-react-statics: ^3.3.1
peerDependencies:
"@babel/core": ^7.0.0
react: ">=16.8.0"
peerDependenciesMeta:
"@babel/core":
optional: true
"@types/react":
optional: true
checksum: 32b67b28e9b6d6c53b970072680697f04c2521441050bdeb19a1a7f0164af549b4dad39ff375eda1b6a3cf1cc86ba2c6fa55460ec040e6ebbca3e9ec58353cf7
languageName: node
linkType: hard
"@emotion/serialize@npm:^1.1.1":
version: 1.1.1
resolution: "@emotion/serialize@npm:1.1.1"
dependencies:
"@emotion/hash": ^0.9.0
"@emotion/memoize": ^0.8.0
"@emotion/unitless": ^0.8.0
"@emotion/utils": ^1.2.0
csstype: ^3.0.2
checksum: 24cfd5b16e6f2335c032ca33804a876e0442aaf8f9c94d269d23735ebd194fb1ed142542dd92191a3e6ef8bad5bd560dfc5aaf363a1b70954726dbd4dd93085c
languageName: node
linkType: hard
"@emotion/sheet@npm:^1.2.1":
version: 1.2.1
resolution: "@emotion/sheet@npm:1.2.1"
checksum: ce78763588ea522438156344d9f592203e2da582d8d67b32e1b0b98eaba26994c6c270f8c7ad46442fc9c0a9f048685d819cd73ca87e544520fd06f0e24a1562
languageName: node
linkType: hard
"@emotion/styled@npm:^11.10.5":
version: 11.10.5
resolution: "@emotion/styled@npm:11.10.5"
dependencies:
"@babel/runtime": ^7.18.3
"@emotion/babel-plugin": ^11.10.5
"@emotion/is-prop-valid": ^1.2.0
"@emotion/serialize": ^1.1.1
"@emotion/use-insertion-effect-with-fallbacks": ^1.0.0
"@emotion/utils": ^1.2.0
peerDependencies:
"@babel/core": ^7.0.0
"@emotion/react": ^11.0.0-rc.0
react: ">=16.8.0"
peerDependenciesMeta:
"@babel/core":
optional: true
"@types/react":
optional: true
checksum: 1cec5f6aeb227a7255141031e8594f38ad83902413472aae0a46c27e5f9769c01e23c1ad39adee408d8a2168a697464314d1a0c4f50b31a5d25ea506b2d7bbc8
languageName: node
linkType: hard
@@ -10194,6 +10307,36 @@ __metadata:
languageName: node
linkType: hard
"@emotion/unitless@npm:^0.8.0":
version: 0.8.0
resolution: "@emotion/unitless@npm:0.8.0"
checksum: 176141117ed23c0eb6e53a054a69c63e17ae532ec4210907a20b2208f91771821835f1c63dd2ec63e30e22fcc984026d7f933773ee6526dd038e0850919fae7a
languageName: node
linkType: hard
"@emotion/use-insertion-effect-with-fallbacks@npm:^1.0.0":
version: 1.0.0
resolution: "@emotion/use-insertion-effect-with-fallbacks@npm:1.0.0"
peerDependencies:
react: ">=16.8.0"
checksum: 4f06a3b48258c832aa8022a262572061a31ff078d377e9164cccc99951309d70f4466e774fe704461b2f8715007a82ed625a54a5c7a127c89017d3ce3187d4f1
languageName: node
linkType: hard
"@emotion/utils@npm:^1.2.0":
version: 1.2.0
resolution: "@emotion/utils@npm:1.2.0"
checksum: 55457a49ddd4db6a014ea0454dc09eaa23eedfb837095c8ff90470cb26a303f7ceb5fcc1e2190ef64683e64cfd33d3ba3ca3109cd87d12bc9e379e4195c9a4dd
languageName: node
linkType: hard
"@emotion/weak-memoize@npm:^0.3.0":
version: 0.3.0
resolution: "@emotion/weak-memoize@npm:0.3.0"
checksum: f43ef4c8b7de70d9fa5eb3105921724651e4188e895beb71f0c5919dc899a7b8743e1fdd99d38b9092dd5722c7be2312ebb47fbdad0c4e38bea58f6df5885cc0
languageName: node
linkType: hard
"@esbuild-kit/cjs-loader@npm:^2.4.1":
version: 2.4.2
resolution: "@esbuild-kit/cjs-loader@npm:2.4.2"
@@ -12734,6 +12877,162 @@ __metadata:
languageName: node
linkType: hard
"@mui/base@npm:5.0.0-alpha.127":
version: 5.0.0-alpha.127
resolution: "@mui/base@npm:5.0.0-alpha.127"
dependencies:
"@babel/runtime": ^7.21.0
"@emotion/is-prop-valid": ^1.2.0
"@mui/types": ^7.2.4
"@mui/utils": ^5.12.0
"@popperjs/core": ^2.11.7
clsx: ^1.2.1
prop-types: ^15.8.1
react-is: ^18.2.0
peerDependencies:
"@types/react": ^17.0.0 || ^18.0.0
react: ^17.0.0 || ^18.0.0
react-dom: ^17.0.0 || ^18.0.0
peerDependenciesMeta:
"@types/react":
optional: true
checksum: 330baeef1fdaa513707f295e07a3436af24d0831a18109ed877f76b86cf1f392309833d33a2c7ca250db79fdf53f5e88c2618f876f50dbbbf9323bbf08e367e7
languageName: node
linkType: hard
"@mui/core-downloads-tracker@npm:^5.12.2":
version: 5.12.2
resolution: "@mui/core-downloads-tracker@npm:5.12.2"
checksum: d748bdc56df6fdfe6712550a94263cf094c53ddcb70f6a8f633caf23927edf5ac88b1f888429d895fe2a5045b27eb7aa9826ccee5b917e31973667d604ed87fe
languageName: node
linkType: hard
"@mui/material@npm:^5.12.2":
version: 5.12.2
resolution: "@mui/material@npm:5.12.2"
dependencies:
"@babel/runtime": ^7.21.0
"@mui/base": 5.0.0-alpha.127
"@mui/core-downloads-tracker": ^5.12.2
"@mui/system": ^5.12.1
"@mui/types": ^7.2.4
"@mui/utils": ^5.12.0
"@types/react-transition-group": ^4.4.5
clsx: ^1.2.1
csstype: ^3.1.2
prop-types: ^15.8.1
react-is: ^18.2.0
react-transition-group: ^4.4.5
peerDependencies:
"@emotion/react": ^11.5.0
"@emotion/styled": ^11.3.0
"@types/react": ^17.0.0 || ^18.0.0
react: ^17.0.0 || ^18.0.0
react-dom: ^17.0.0 || ^18.0.0
peerDependenciesMeta:
"@emotion/react":
optional: true
"@emotion/styled":
optional: true
"@types/react":
optional: true
checksum: a3464dfbcc496164967e134d6f1d40e060ee02fc2ddb5fcf648ca85580efdbd5eff5aab6a73486d0a7f329f7299127b52501a13993bb131cbd4e310c7f2e633f
languageName: node
linkType: hard
"@mui/private-theming@npm:^5.12.0":
version: 5.12.0
resolution: "@mui/private-theming@npm:5.12.0"
dependencies:
"@babel/runtime": ^7.21.0
"@mui/utils": ^5.12.0
prop-types: ^15.8.1
peerDependencies:
"@types/react": ^17.0.0 || ^18.0.0
react: ^17.0.0 || ^18.0.0
peerDependenciesMeta:
"@types/react":
optional: true
checksum: 761bc7a57e1643c2c4c327886882fa5efc7bacae1c6fffe6be4197f49d337261c916a883d96996445efcdedc0672251725c1e5b264b6250d6c9527fd0cafcc62
languageName: node
linkType: hard
"@mui/styled-engine@npm:^5.12.0":
version: 5.12.0
resolution: "@mui/styled-engine@npm:5.12.0"
dependencies:
"@babel/runtime": ^7.21.0
"@emotion/cache": ^11.10.7
csstype: ^3.1.2
prop-types: ^15.8.1
peerDependencies:
"@emotion/react": ^11.4.1
"@emotion/styled": ^11.3.0
react: ^17.0.0 || ^18.0.0
peerDependenciesMeta:
"@emotion/react":
optional: true
"@emotion/styled":
optional: true
checksum: 4a415473cf62aa05012f667dd2e9b1dc2fb175be5b0c4d0b8df541e2dac3d7db410e920e0d5910c8e2b8996a4fb51f74d79483e2878a9b5c0d334498f5537d74
languageName: node
linkType: hard
"@mui/system@npm:^5.12.1":
version: 5.12.1
resolution: "@mui/system@npm:5.12.1"
dependencies:
"@babel/runtime": ^7.21.0
"@mui/private-theming": ^5.12.0
"@mui/styled-engine": ^5.12.0
"@mui/types": ^7.2.4
"@mui/utils": ^5.12.0
clsx: ^1.2.1
csstype: ^3.1.2
prop-types: ^15.8.1
peerDependencies:
"@emotion/react": ^11.5.0
"@emotion/styled": ^11.3.0
"@types/react": ^17.0.0 || ^18.0.0
react: ^17.0.0 || ^18.0.0
peerDependenciesMeta:
"@emotion/react":
optional: true
"@emotion/styled":
optional: true
"@types/react":
optional: true
checksum: b951959bf5e5af581319354c044f441d97849ff120cfec111d2ed5e7fa05efd63721acff96f48093b8e2bdeb5ccbe35c48613fb925be2b58c596447d10dbed3e
languageName: node
linkType: hard
"@mui/types@npm:^7.2.4":
version: 7.2.4
resolution: "@mui/types@npm:7.2.4"
peerDependencies:
"@types/react": "*"
peerDependenciesMeta:
"@types/react":
optional: true
checksum: 16bea0547492193a22fd1794382f314698a114f6c673825314c66b56766c3a9d305992cc495684722b7be16a1ecf7e6e48a79caa64f90c439b530e8c02611a61
languageName: node
linkType: hard
"@mui/utils@npm:^5.12.0":
version: 5.12.0
resolution: "@mui/utils@npm:5.12.0"
dependencies:
"@babel/runtime": ^7.21.0
"@types/prop-types": ^15.7.5
"@types/react-is": ^16.7.1 || ^17.0.0
prop-types: ^15.8.1
react-is: ^18.2.0
peerDependencies:
react: ^17.0.0 || ^18.0.0
checksum: 87b2c7468803b083f50af28d7c215c45291e73fef16570848b596d0f1cde1fc613c20e8951f431217b31451de254744abd50eda5013dedec4982420b5bf1c6b6
languageName: node
linkType: hard
"@n1ru4l/push-pull-async-iterable-iterator@npm:^3.1.0":
version: 3.1.0
resolution: "@n1ru4l/push-pull-async-iterable-iterator@npm:3.1.0"
@@ -13645,6 +13944,13 @@ __metadata:
languageName: node
linkType: hard
"@popperjs/core@npm:^2.11.7":
version: 2.11.7
resolution: "@popperjs/core@npm:2.11.7"
checksum: 5b6553747899683452a1d28898c1b39173a4efd780e74360bfcda8eb42f1c5e819602769c81a10920fc68c881d07fb40429604517d499567eac079cfa6470f19
languageName: node
linkType: hard
"@protobufjs/aspromise@npm:^1.1.1, @protobufjs/aspromise@npm:^1.1.2":
version: 1.1.2
resolution: "@protobufjs/aspromise@npm:1.1.2"
@@ -16489,7 +16795,7 @@ __metadata:
languageName: node
linkType: hard
"@types/prop-types@npm:*, @types/prop-types@npm:^15.0.0, @types/prop-types@npm:^15.7.3":
"@types/prop-types@npm:*, @types/prop-types@npm:^15.0.0, @types/prop-types@npm:^15.7.3, @types/prop-types@npm:^15.7.5":
version: 15.7.5
resolution: "@types/prop-types@npm:15.7.5"
checksum: 5b43b8b15415e1f298243165f1d44390403bb2bd42e662bca3b5b5633fdd39c938e91b7fce3a9483699db0f7a715d08cef220c121f723a634972fdf596aec980
@@ -16555,6 +16861,15 @@ __metadata:
languageName: node
linkType: hard
"@types/react-is@npm:^16.7.1 || ^17.0.0":
version: 17.0.3
resolution: "@types/react-is@npm:17.0.3"
dependencies:
"@types/react": "*"
checksum: 6abb7c47d54f012272650df8a962a28bd82f219291e5ef8b4dfa7fe0bb98ae243b060bf9fbe8ceff6213141794855a006db194b490b00ffd15842ae19d0ce1f0
languageName: node
linkType: hard
"@types/react-redux@npm:^7.1.16":
version: 7.1.19
resolution: "@types/react-redux@npm:7.1.19"
@@ -16603,12 +16918,12 @@ __metadata:
languageName: node
linkType: hard
"@types/react-transition-group@npm:^4.2.0":
version: 4.2.4
resolution: "@types/react-transition-group@npm:4.2.4"
"@types/react-transition-group@npm:^4.2.0, @types/react-transition-group@npm:^4.4.5":
version: 4.4.5
resolution: "@types/react-transition-group@npm:4.4.5"
dependencies:
"@types/react": "*"
checksum: a8abb3ad3c6e0575c630b591503a78ae3a94e21d1285905a49c36168e5d3de68b0886e2c6d75b751e30f2dc6e4245351cde30e4b3ff2649aec345f2088961e2c
checksum: 265f1c74061556708ffe8d15559e35c60d6c11478c9950d3735575d2c116ca69f461d85effa06d73a613eb8b73c84fd32682feb57cf7c5f9e4284021dbca25b0
languageName: node
linkType: hard
@@ -18665,6 +18980,17 @@ __metadata:
languageName: node
linkType: hard
"babel-plugin-macros@npm:^3.1.0":
version: 3.1.0
resolution: "babel-plugin-macros@npm:3.1.0"
dependencies:
"@babel/runtime": ^7.12.5
cosmiconfig: ^7.0.0
resolve: ^1.19.0
checksum: 765de4abebd3e4688ebdfbff8571ddc8cd8061f839bb6c3e550b0344a4027b04c60491f843296ce3f3379fb356cc873d57a9ee6694262547eb822c14a25be9a6
languageName: node
linkType: hard
"babel-plugin-polyfill-corejs2@npm:^0.3.1":
version: 0.3.1
resolution: "babel-plugin-polyfill-corejs2@npm:0.3.1"
@@ -20120,7 +20446,7 @@ __metadata:
languageName: node
linkType: hard
"clsx@npm:^1.0.2, clsx@npm:^1.0.4, clsx@npm:^1.1.1":
"clsx@npm:^1.0.2, clsx@npm:^1.0.4, clsx@npm:^1.1.1, clsx@npm:^1.2.1":
version: 1.2.1
resolution: "clsx@npm:1.2.1"
checksum: 30befca8019b2eb7dbad38cff6266cf543091dae2825c856a62a8ccf2c3ab9c2907c4d12b288b73101196767f66812365400a227581484a05f968b0307cfaf12
@@ -20703,12 +21029,10 @@ __metadata:
languageName: node
linkType: hard
"convert-source-map@npm:^1.6.0, convert-source-map@npm:^1.7.0":
version: 1.7.0
resolution: "convert-source-map@npm:1.7.0"
dependencies:
safe-buffer: ~5.1.1
checksum: bcd2e3ea7d37f96b85a6e362c8a89402ccc73757256e3ee53aa2c22fe915adb854c66b1f81111be815a3a6a6ce3c58e8001858e883c9d5b4fe08a853fa865967
"convert-source-map@npm:^1.5.0, convert-source-map@npm:^1.6.0, convert-source-map@npm:^1.7.0":
version: 1.9.0
resolution: "convert-source-map@npm:1.9.0"
checksum: dc55a1f28ddd0e9485ef13565f8f756b342f9a46c4ae18b843fe3c30c675d058d6a4823eff86d472f187b176f0adf51ea7b69ea38be34be4a63cbbf91b0593c8
languageName: node
linkType: hard
@@ -21328,10 +21652,10 @@ __metadata:
languageName: node
linkType: hard
"csstype@npm:^3.0.2, csstype@npm:^3.0.6":
version: 3.0.7
resolution: "csstype@npm:3.0.7"
checksum: 2f30c993be570c6d0de334b979a718370ee9bca9569c90340f13e05e542146c55b22e87372b858c061f9f8ded494da7a4715957882f9356cf9993ba11ab6f09c
"csstype@npm:^3.0.2, csstype@npm:^3.0.6, csstype@npm:^3.1.2":
version: 3.0.9
resolution: "csstype@npm:3.0.9"
checksum: 199f9af7e673f9f188525c3102a329d637ff46c52f6385a4427ff5cb17adcb736189150170a7af7c5701d18d7704bdad130273f4aa7e44c6c4f9967e6115dc93
languageName: node
linkType: hard
@@ -25963,7 +26287,7 @@ __metadata:
languageName: node
linkType: hard
"hoist-non-react-statics@npm:^3.0.0, hoist-non-react-statics@npm:^3.2.1, hoist-non-react-statics@npm:^3.3.0, hoist-non-react-statics@npm:^3.3.2":
"hoist-non-react-statics@npm:^3.0.0, hoist-non-react-statics@npm:^3.2.1, hoist-non-react-statics@npm:^3.3.0, hoist-non-react-statics@npm:^3.3.1, hoist-non-react-statics@npm:^3.3.2":
version: 3.3.2
resolution: "hoist-non-react-statics@npm:3.3.2"
dependencies:
@@ -26502,15 +26826,6 @@ __metadata:
languageName: node
linkType: hard
"indefinite-observable@npm:^2.0.1":
version: 2.0.1
resolution: "indefinite-observable@npm:2.0.1"
dependencies:
symbol-observable: 1.2.0
checksum: b4305c999b7596901f8798e569b8faa030361dfb77f8b720e229558a29f544826f7e8987c55cc2a84c37ff2723594a965b96a40a6c71daae92b918f3eb393077
languageName: node
linkType: hard
"indent-string@npm:^4.0.0":
version: 4.0.0
resolution: "indent-string@npm:4.0.0"
@@ -28844,76 +29159,76 @@ __metadata:
linkType: hard
"jss-plugin-camel-case@npm:^10.5.1":
version: 10.6.0
resolution: "jss-plugin-camel-case@npm:10.6.0"
version: 10.9.2
resolution: "jss-plugin-camel-case@npm:10.9.2"
dependencies:
"@babel/runtime": ^7.3.1
hyphenate-style-name: ^1.0.3
jss: 10.6.0
checksum: 75c23826deef63c3603cfb47331d1eaf9feeafd097bd115a076f2ee9fb696855d3f18b3f41455a046120fddf0ea11985259c1b8b8a37b3556f4de1a1c83affd5
jss: 10.9.2
checksum: 5fa617b23ce9718244691c59ace6a0d1271dbcb4430ce3e13b851ee1879c1db8ecab7e941c33802bea763a0f0e2b609d004b8a975b2063f213cdd639cdd384d2
languageName: node
linkType: hard
"jss-plugin-default-unit@npm:^10.5.1":
version: 10.6.0
resolution: "jss-plugin-default-unit@npm:10.6.0"
version: 10.9.2
resolution: "jss-plugin-default-unit@npm:10.9.2"
dependencies:
"@babel/runtime": ^7.3.1
jss: 10.6.0
checksum: 7ae36fadf4f206a16e49c40806ef92ba1f0e60395488ab8ad4df96796b408013b38ea5ed975155ecd7833a42a96c8d5cb1e90aef011279816633e60f807ec330
jss: 10.9.2
checksum: 48d8d836d36dd15513d98de11fba6be373ac29e6fd5702eb2edd143c815fb9e2f9969b2af6b1b964e9b8a052828690887042f6bcb34836836d5c359e52702d0f
languageName: node
linkType: hard
"jss-plugin-global@npm:^10.5.1":
version: 10.6.0
resolution: "jss-plugin-global@npm:10.6.0"
version: 10.9.2
resolution: "jss-plugin-global@npm:10.9.2"
dependencies:
"@babel/runtime": ^7.3.1
jss: 10.6.0
checksum: 7aab58408c77071c571dd2c2132edad8d40b683513a8de534f0ec7f63926fd9d9fcf6bdda82103eb541452a723b992f061720f8e5cf2014acb7f6bbbde111f56
jss: 10.9.2
checksum: 9b29b0c1f169d5a1033890875df072d76364a902d0f6470f448544669a388612a9a4d51844fb2bcb6d25a1c43d67c1637f11a162c2cdd9f4b6b0a8f9c94f6090
languageName: node
linkType: hard
"jss-plugin-nested@npm:^10.5.1":
version: 10.6.0
resolution: "jss-plugin-nested@npm:10.6.0"
version: 10.9.2
resolution: "jss-plugin-nested@npm:10.9.2"
dependencies:
"@babel/runtime": ^7.3.1
jss: 10.6.0
jss: 10.9.2
tiny-warning: ^1.0.2
checksum: 38095127e8b5ddb0a33ccaf61a4d89dc1b0f78e6d06d079a47a14bca4aed4e885f1957d83f11c5da08b4249b2c629e8bc62b2996f1674ca1302575a7b2b11171
checksum: ee08df07f3d553931b48037674842a8314bbc7857cc954a52f962a516bfc4b2d4e9871578b06b8fa3981edf5a927cea00021fd368d4ce315870065b7647f7b57
languageName: node
linkType: hard
"jss-plugin-props-sort@npm:^10.5.1":
version: 10.6.0
resolution: "jss-plugin-props-sort@npm:10.6.0"
version: 10.9.2
resolution: "jss-plugin-props-sort@npm:10.9.2"
dependencies:
"@babel/runtime": ^7.3.1
jss: 10.6.0
checksum: 2917ff301e667f75efa15df865a860a50d4319d415d1169c213e66b464edc2b37b6f428be2d974ccdde7c8d61c50123f18e788143a96eacc2a1c42ad250ae375
jss: 10.9.2
checksum: 70bd181a458a6078f19ad4d7350570c78d26b9aabc25a1fbde673839edcc19825af7b636861b208a38aa17e551e68d0ea38599480716b4aec08e353bbe737222
languageName: node
linkType: hard
"jss-plugin-rule-value-function@npm:^10.5.1":
version: 10.6.0
resolution: "jss-plugin-rule-value-function@npm:10.6.0"
version: 10.9.2
resolution: "jss-plugin-rule-value-function@npm:10.9.2"
dependencies:
"@babel/runtime": ^7.3.1
jss: 10.6.0
jss: 10.9.2
tiny-warning: ^1.0.2
checksum: 709e1ce0afdc39a52cb78e371fef626f933e99992790b15771d85056176bdf69365d62cfed6ce95434752cc1a1e7e05a6f2548e4cd5999808d50a28174315be3
checksum: b1a03209d0249f13ea6de766d3ee14c1769cd1f67d8c543c7d1ce6178c32cf15507c021ecb3e3b7585a8a7a2425dddbe0bdae02f4135c4598725a4152bebfc99
languageName: node
linkType: hard
"jss-plugin-vendor-prefixer@npm:^10.5.1":
version: 10.6.0
resolution: "jss-plugin-vendor-prefixer@npm:10.6.0"
version: 10.9.2
resolution: "jss-plugin-vendor-prefixer@npm:10.9.2"
dependencies:
"@babel/runtime": ^7.3.1
css-vendor: ^2.0.8
jss: 10.6.0
checksum: 9db048022ee2fb79a223a9f1be5976e131715057e3c0200cfcead9b9f8625023942534afa261e3c967cee6ad716bfd7d4a2f356556178f60f4eddcf83bcd8856
jss: 10.9.2
checksum: a5c352a500fea82e8a782a090cc9815f6331259f1a331158ed74ed77c750fb45750f5ae95f07d27922742830b45d4c3592cfaab194b3ba4a50591acbdeab04d8
languageName: node
linkType: hard
@@ -28937,16 +29252,15 @@ __metadata:
languageName: node
linkType: hard
"jss@npm:10.6.0":
version: 10.6.0
resolution: "jss@npm:10.6.0"
"jss@npm:10.9.2":
version: 10.9.2
resolution: "jss@npm:10.9.2"
dependencies:
"@babel/runtime": ^7.3.1
csstype: ^3.0.2
indefinite-observable: ^2.0.1
is-in-browser: ^1.1.3
tiny-warning: ^1.0.2
checksum: 529edd871ddf059beef55ee0f974ad8436fbcf050d6538e6d2d7edab53ce2c09983d2f863e42a1473dd0e42a0447e9912bce6706bb0e539226d92cdaad128d46
checksum: 7ae5cd2f8602bf197ec90251d774b9f10d55eb2db0854ac78dc7fb6983828c202e8eb0d5c8c59c73b2f64718ebd33d6063afa799d625a995986a22dc1cc27230
languageName: node
linkType: hard
@@ -35224,9 +35538,9 @@ __metadata:
languageName: node
linkType: hard
"react-transition-group@npm:^4.0.0, react-transition-group@npm:^4.4.0":
version: 4.4.1
resolution: "react-transition-group@npm:4.4.1"
"react-transition-group@npm:^4.0.0, react-transition-group@npm:^4.4.0, react-transition-group@npm:^4.4.5":
version: 4.4.5
resolution: "react-transition-group@npm:4.4.5"
dependencies:
"@babel/runtime": ^7.5.5
dom-helpers: ^5.0.1
@@ -35235,7 +35549,7 @@ __metadata:
peerDependencies:
react: ">=16.6.0"
react-dom: ">=16.6.0"
checksum: 0bcd8af483709832e318dcef84c26ebddeb866bf4f58010286367ef0c1e7c5106e00cfc65688b9102414cb3d572c63909c2eb7ea972b4420fc70a78c10b6e8ad
checksum: 75602840106aa9c6545149d6d7ae1502fb7b7abadcce70a6954c4b64a438ff1cd16fc77a0a1e5197cdd72da398f39eb929ea06f9005c45b132ed34e056ebdeb1
languageName: node
linkType: hard
@@ -37229,6 +37543,13 @@ __metadata:
languageName: node
linkType: hard
"source-map@npm:^0.5.7":
version: 0.5.7
resolution: "source-map@npm:0.5.7"
checksum: 5dc2043b93d2f194142c7f38f74a24670cd7a0063acdaf4bf01d2964b402257ae843c2a8fa822ad5b71013b5fcafa55af7421383da919752f22ff488bc553f4d
languageName: node
linkType: hard
"source-map@npm:^0.6.0, source-map@npm:^0.6.1, source-map@npm:~0.6.0, source-map@npm:~0.6.1":
version: 0.6.1
resolution: "source-map@npm:0.6.1"
@@ -38030,10 +38351,10 @@ __metadata:
languageName: node
linkType: hard
"stylis@npm:^4.0.6":
version: 4.0.7
resolution: "stylis@npm:4.0.7"
checksum: 4f9fdc4b131b54cdc5988aaf23e796fcf77927c9d2f3147f6b23b8f3a9568eb38ce91b338b9d1b50a50391da32969c34ff68ff971c453fc3a5af89941c60ab06
"stylis@npm:4.1.3, stylis@npm:^4.0.6":
version: 4.1.3
resolution: "stylis@npm:4.1.3"
checksum: d04dbffcb9bf2c5ca8d8dc09534203c75df3bf711d33973ea22038a99cc475412a350b661ebd99cbc01daa50d7eedcf0d130d121800eb7318759a197023442a6
languageName: node
linkType: hard