From ffe0e45dc8c0df3235ca653729752859296d54aa Mon Sep 17 00:00:00 2001 From: mainframev Date: Wed, 11 Nov 2026 13:16:02 +0100 Subject: [PATCH] fix(react-migration-v8-v9): use webDarkTheme as createV9Theme base for inverted v8 themes createV9Theme always fell back to webLightTheme, so tokens without a v8 mapping (e.g. status colors) kept light values for dark v8 themes. Fall back to webDarkTheme when themeV8.isInverted is set; an explicit base theme still wins. Fixes #31728 --- ...ation-v8-v9-create-v9-theme-dark-base.json | 7 +++++ .../src/components/Theme/v9ThemeShim.test.ts | 27 +++++++++++++++++++ .../src/components/Theme/v9ThemeShim.ts | 7 ++--- 3 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 change/@fluentui-react-migration-v8-v9-create-v9-theme-dark-base.json create mode 100644 packages/react-components/react-migration-v8-v9/library/src/components/Theme/v9ThemeShim.test.ts diff --git a/change/@fluentui-react-migration-v8-v9-create-v9-theme-dark-base.json b/change/@fluentui-react-migration-v8-v9-create-v9-theme-dark-base.json new file mode 100644 index 00000000000000..0a9a51779d925d --- /dev/null +++ b/change/@fluentui-react-migration-v8-v9-create-v9-theme-dark-base.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "fix: createV9Theme uses webDarkTheme as the base theme for inverted v8 themes", + "packageName": "@fluentui/react-migration-v8-v9", + "email": "vgenaev@gmail.com", + "dependentChangeType": "patch" +} diff --git a/packages/react-components/react-migration-v8-v9/library/src/components/Theme/v9ThemeShim.test.ts b/packages/react-components/react-migration-v8-v9/library/src/components/Theme/v9ThemeShim.test.ts new file mode 100644 index 00000000000000..c6905569fd73a6 --- /dev/null +++ b/packages/react-components/react-migration-v8-v9/library/src/components/Theme/v9ThemeShim.test.ts @@ -0,0 +1,27 @@ +import { createTheme } from '@fluentui/react'; +import { teamsHighContrastTheme, webDarkTheme, webLightTheme } from '@fluentui/react-components'; +import { createV9Theme } from './v9ThemeShim'; + +describe('createV9Theme', () => { + // Status tokens have no v8 equivalent, so their values always come from the base v9 theme. + it('uses webLightTheme as the base for a non-inverted v8 theme', () => { + const theme = createV9Theme(createTheme({ isInverted: false })); + + expect(theme.colorStatusDangerForeground1).toBe(webLightTheme.colorStatusDangerForeground1); + expect(theme.colorStatusSuccessBackground1).toBe(webLightTheme.colorStatusSuccessBackground1); + }); + + // Regression: https://github.com/microsoft/fluentui/issues/31728 + it('uses webDarkTheme as the base for an inverted v8 theme', () => { + const theme = createV9Theme(createTheme({ isInverted: true })); + + expect(theme.colorStatusDangerForeground1).toBe(webDarkTheme.colorStatusDangerForeground1); + expect(theme.colorStatusSuccessBackground1).toBe(webDarkTheme.colorStatusSuccessBackground1); + }); + + it('prefers an explicitly passed base theme over the inferred one', () => { + const theme = createV9Theme(createTheme({ isInverted: true }), teamsHighContrastTheme); + + expect(theme.colorStatusDangerForeground1).toBe(teamsHighContrastTheme.colorStatusDangerForeground1); + }); +}); diff --git a/packages/react-components/react-migration-v8-v9/library/src/components/Theme/v9ThemeShim.ts b/packages/react-components/react-migration-v8-v9/library/src/components/Theme/v9ThemeShim.ts index 557bea7c75463f..2d194e2b564117 100644 --- a/packages/react-components/react-migration-v8-v9/library/src/components/Theme/v9ThemeShim.ts +++ b/packages/react-components/react-migration-v8-v9/library/src/components/Theme/v9ThemeShim.ts @@ -1,6 +1,6 @@ import type { Theme as ThemeV8 } from '@fluentui/react'; import type { IEffects, IPalette } from '@fluentui/react'; -import { webLightTheme } from '@fluentui/react-components'; +import { webDarkTheme, webLightTheme } from '@fluentui/react-components'; import type { BorderRadiusTokens, ColorTokens, ShadowTokens, Theme as ThemeV9 } from '@fluentui/react-components'; import { blackAlpha, whiteAlpha, grey, grey10Alpha, grey12Alpha } from './themeDuplicates'; @@ -221,10 +221,11 @@ const mapBorderRadiusTokens = (effects: IEffects): Partial = /** * Creates a v9 theme from a v8 theme. - * You can optional pass a base v9 theme; otherwise webLightTheme is used. + * You can optionally pass a base v9 theme; otherwise webDarkTheme is used for inverted (dark) v8 themes + * and webLightTheme for the rest. */ export const createV9Theme = (themeV8: ThemeV8, baseThemeV9?: ThemeV9): ThemeV9 => { - const baseTheme = baseThemeV9 ?? webLightTheme; + const baseTheme = baseThemeV9 ?? (themeV8.isInverted ? webDarkTheme : webLightTheme); return { ...baseTheme,