diff --git a/.changeset/perfect-apes-sing.md b/.changeset/perfect-apes-sing.md new file mode 100644 index 0000000000..fede777057 --- /dev/null +++ b/.changeset/perfect-apes-sing.md @@ -0,0 +1,7 @@ +--- +'@backstage/core-components': patch +'@backstage/plugin-catalog-react': patch +'@backstage/plugin-catalog': patch +--- + +Register component overrides in the global `OverrideComponentNameToClassKeys` provided by `@backstage/theme`. This will in turn will provide component style override types for `createUnifiedTheme`. diff --git a/.changeset/violet-zebras-thank.md b/.changeset/violet-zebras-thank.md new file mode 100644 index 0000000000..eda6137dc1 --- /dev/null +++ b/.changeset/violet-zebras-thank.md @@ -0,0 +1,5 @@ +--- +'@backstage/theme': minor +--- + +Added a global `OverrideComponentNameToClassKeys` for other plugins and packages to populate using module augmentation. This will in turn will provide component style override types for `createUnifiedTheme`. diff --git a/packages/core-components/src/overridableComponents.ts b/packages/core-components/src/overridableComponents.ts index c872317049..750303e4df 100644 --- a/packages/core-components/src/overridableComponents.ts +++ b/packages/core-components/src/overridableComponents.ts @@ -173,3 +173,8 @@ export type BackstageOverrides = Overrides & { StyleRules >; }; + +declare module '@backstage/theme' { + interface OverrideComponentNameToClassKeys + extends BackstageComponentsNameToClassKey {} +} diff --git a/packages/theme/api-report.md b/packages/theme/api-report.md index 4ab05e8770..21d6be6a78 100644 --- a/packages/theme/api-report.md +++ b/packages/theme/api-report.md @@ -15,6 +15,7 @@ import { Theme as Theme_3 } 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'; +import { UnifiedTheme as UnifiedTheme_2 } from '@backstage/theme'; // @public @deprecated export type BackstagePalette = Palette & BackstagePaletteAdditions; @@ -216,6 +217,9 @@ export function genPageTheme(props: { // @public @deprecated export const lightTheme: Theme_3; +// @public +export interface OverrideComponentNameToClassKeys {} + // @public export type PageTheme = { colors: string[]; @@ -401,8 +405,8 @@ export type SupportedVersions = 'v4' | 'v5'; // @public export const themes: { - light: UnifiedTheme; - dark: UnifiedTheme; + light: UnifiedTheme_2; + dark: UnifiedTheme_2; }; // @public diff --git a/packages/theme/src/v5/types.test.ts b/packages/theme/src/v5/types.test.ts new file mode 100644 index 0000000000..12bd0ff2b8 --- /dev/null +++ b/packages/theme/src/v5/types.test.ts @@ -0,0 +1,47 @@ +/* + * Copyright 2023 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 '../unified'; + +declare module '@backstage/theme' { + interface OverrideComponentNameToClassKeys { + MyTestComponent: 'root' | 'header'; + } +} + +describe('OverrideComponentNameToClassKeys', () => { + it('should provide type safe component style overrides', () => { + const theme = createUnifiedTheme({ + palette: palettes.light, + components: { + MyTestComponent: { + styleOverrides: { + root: { + color: '#f00', + }, + // @ts-expect-error + invalid: { + color: '#b45', + }, + }, + }, + }, + }); + + expect(theme).toBeDefined(); + }); +}); diff --git a/packages/theme/src/v5/types.ts b/packages/theme/src/v5/types.ts index 0d6d46cef9..aa80c903fa 100644 --- a/packages/theme/src/v5/types.ts +++ b/packages/theme/src/v5/types.ts @@ -19,6 +19,8 @@ import { BackstagePaletteAdditions, BackstageThemeAdditions, } from '../base/types'; +// eslint-disable-next-line no-restricted-imports +import { OverridesStyleRules } from '@mui/material/styles/overrides'; declare module '@mui/material/styles' { interface Palette extends BackstagePaletteAdditions {} @@ -35,3 +37,30 @@ declare module '@mui/material/styles' { declare module '@mui/private-theming/defaultTheme' { interface DefaultTheme extends Theme {} } + +/** + * Merge interface declarations into this type to register overrides for your components. + * + * @public + * @example + * ```ts + * declare module '@backstage/theme' { + * interface OverrideComponentNameToClassKeys { + * MyComponent: 'root' | 'header'; + * } + * } + * ``` + */ +export interface OverrideComponentNameToClassKeys {} + +type BackstageComponentOverrides = { + [TName in keyof OverrideComponentNameToClassKeys]?: { + styleOverrides?: Partial< + OverridesStyleRules + >; + }; +}; + +declare module '@mui/material/styles' { + interface Components extends BackstageComponentOverrides {} +} diff --git a/plugins/catalog-react/src/overridableComponents.ts b/plugins/catalog-react/src/overridableComponents.ts index e94af1c4fb..6424c95ab5 100644 --- a/plugins/catalog-react/src/overridableComponents.ts +++ b/plugins/catalog-react/src/overridableComponents.ts @@ -44,3 +44,8 @@ export type BackstageOverrides = Overrides & { StyleRules >; }; + +declare module '@backstage/theme' { + interface OverrideComponentNameToClassKeys + extends CatalogReactComponentsNameToClassKey {} +} diff --git a/plugins/catalog/src/overridableComponents.ts b/plugins/catalog/src/overridableComponents.ts index 5cd82202d5..0d981b1700 100644 --- a/plugins/catalog/src/overridableComponents.ts +++ b/plugins/catalog/src/overridableComponents.ts @@ -33,3 +33,8 @@ export type BackstageOverrides = Overrides & { StyleRules >; }; + +declare module '@backstage/theme' { + interface OverrideComponentNameToClassKeys + extends PluginCatalogComponentsNameToClassKey {} +}