diff --git a/.changeset/slick-books-sleep.md b/.changeset/slick-books-sleep.md new file mode 100644 index 0000000000..7aa3be5b03 --- /dev/null +++ b/.changeset/slick-books-sleep.md @@ -0,0 +1,5 @@ +--- +'@backstage/theme': patch +--- + +Added a `themeName` prop to `UnifiedThemeProvider`, enabling Backstage UI `data-theme-name` CSS attribute to be set based on active theme. diff --git a/packages/theme/report.api.md b/packages/theme/report.api.md index 18ac96ecec..f4e31db8e9 100644 --- a/packages/theme/report.api.md +++ b/packages/theme/report.api.md @@ -460,5 +460,6 @@ export interface UnifiedThemeProviderProps { children: ReactNode; // (undocumented) theme: UnifiedTheme; + themeName?: string; } ``` diff --git a/packages/theme/src/unified/UnifiedThemeProvider.test.tsx b/packages/theme/src/unified/UnifiedThemeProvider.test.tsx index 85a47dbb1e..52769b65a3 100644 --- a/packages/theme/src/unified/UnifiedThemeProvider.test.tsx +++ b/packages/theme/src/unified/UnifiedThemeProvider.test.tsx @@ -20,11 +20,17 @@ import { } from '@material-ui/core/styles'; import { useTheme as useV5Theme } from '@mui/material/styles'; import { makeStyles as makeV5Styles } from '@mui/styles'; -import { render, screen } from '@testing-library/react'; +import { render, screen, waitFor } from '@testing-library/react'; import { UnifiedThemeProvider } from './UnifiedThemeProvider'; import { themes } from './themes'; describe('UnifiedThemeProvider', () => { + afterEach(() => { + document.body.removeAttribute('data-theme-name'); + document.body.removeAttribute('data-theme-mode'); + document.body.removeAttribute('data-unified-theme-stack'); + }); + it('provides a themes for v4 and v5 directly', () => { function MyV4Component() { const theme = useV4Theme(); @@ -81,4 +87,17 @@ describe('UnifiedThemeProvider', () => { 'rgb(158, 158, 158)', ); }); + + it('applies theme attributes based on the provided options', async () => { + render( + + theme + , + ); + + await waitFor(() => + expect(document.body.getAttribute('data-theme-name')).toBe('aperture'), + ); + expect(document.body.getAttribute('data-theme-mode')).toBe('light'); + }); }); diff --git a/packages/theme/src/unified/UnifiedThemeProvider.tsx b/packages/theme/src/unified/UnifiedThemeProvider.tsx index d0886cd146..69d843ed3e 100644 --- a/packages/theme/src/unified/UnifiedThemeProvider.tsx +++ b/packages/theme/src/unified/UnifiedThemeProvider.tsx @@ -37,6 +37,8 @@ import { unstable_ClassNameGenerator as ClassNameGenerator } from '@mui/material export interface UnifiedThemeProviderProps { children: ReactNode; theme: UnifiedTheme; + /** Optional override for the value written to the `data-theme-name` attribute. */ + themeName?: string; } /** @@ -66,15 +68,14 @@ import { useApplyThemeAttributes } from './useApplyThemeAttributes'; export function UnifiedThemeProvider( props: UnifiedThemeProviderProps, ): JSX.Element { - const { children, theme } = props; + const { children, theme, themeName } = props; const v4Theme = theme.getTheme('v4') as Mui4Theme; const v5Theme = theme.getTheme('v5') as Mui5Theme; - useApplyThemeAttributes( - v4Theme ? v4Theme.palette.type : v5Theme?.palette.mode, - 'backstage', - ); + const themeMode = v4Theme ? v4Theme.palette.type : v5Theme?.palette.mode; + + useApplyThemeAttributes(themeMode, themeName ?? 'backstage'); let result = children as JSX.Element;