diff --git a/change/@fluentui-react-theme-c1768520-8e1c-4d97-b64c-b2792d4ed903.json b/change/@fluentui-react-theme-c1768520-8e1c-4d97-b64c-b2792d4ed903.json
new file mode 100644
index 0000000000000..4bb3850be9a44
--- /dev/null
+++ b/change/@fluentui-react-theme-c1768520-8e1c-4d97-b64c-b2792d4ed903.json
@@ -0,0 +1,7 @@
+{
+ "type": "patch",
+ "comment": "fix mergeThemes() to avoid object's mutation",
+ "packageName": "@fluentui/react-theme",
+ "email": "olfedias@microsoft.com",
+ "dependentChangeType": "patch"
+}
diff --git a/packages/react-theme/src/utils/mergeThemes.ts b/packages/react-theme/src/utils/mergeThemes.ts
index ecd79ca8ad064..0e8f4f8b431d7 100644
--- a/packages/react-theme/src/utils/mergeThemes.ts
+++ b/packages/react-theme/src/utils/mergeThemes.ts
@@ -2,5 +2,5 @@ import { merge } from '@fluentui/utilities';
import { PartialTheme, Theme } from '../types';
export function mergeThemes(a: Theme, b: PartialTheme | Theme): Theme {
- return merge(a, b) as Theme;
+ return merge({}, a, b) as Theme;
}
diff --git a/packages/storybook/package.json b/packages/storybook/package.json
index 19fcb238881b7..15a65c10be6ab 100644
--- a/packages/storybook/package.json
+++ b/packages/storybook/package.json
@@ -25,6 +25,8 @@
},
"dependencies": {
"@fluentui/react": "^8.0.0-beta.49",
+ "@fluentui/react-provider": "^0.1.2",
+ "@fluentui/react-theme": "^0.3.0",
"@fluentui/react-theme-provider": "^1.0.0-beta.20",
"@fluentui/theme": "^2.0.0-beta.13",
"@storybook/addon-knobs": "^5.3.8",
diff --git a/packages/storybook/src/decorators/index.ts b/packages/storybook/src/decorators/index.ts
index b5fff59b37f15..acef2356b2a05 100644
--- a/packages/storybook/src/decorators/index.ts
+++ b/packages/storybook/src/decorators/index.ts
@@ -1,3 +1,4 @@
+export * from './withFluentProvider';
export * from './withKeytipLayer';
export * from './withStrictMode';
export * from './withCompatThemeProvider';
diff --git a/packages/storybook/src/decorators/withFluentProvider.tsx b/packages/storybook/src/decorators/withFluentProvider.tsx
new file mode 100644
index 0000000000000..2d55636bad8f8
--- /dev/null
+++ b/packages/storybook/src/decorators/withFluentProvider.tsx
@@ -0,0 +1,20 @@
+import { makeDecorator } from '@storybook/addons';
+import { FluentProvider } from '@fluentui/react-provider';
+import * as React from 'react';
+
+import { useFluentTheme } from '../knobs/useFluentTheme';
+
+const ProviderWrapper: React.FunctionComponent = props => {
+ const { theme } = useFluentTheme();
+
+ return {props.children};
+};
+
+export const withFluentProvider = makeDecorator({
+ name: 'withFluentProvider',
+ parameterName: 'theme',
+ skipIfNoParametersOrOptions: false,
+ wrapper: (storyFn, context) => {
+ return {storyFn(context)};
+ },
+});
diff --git a/packages/storybook/src/knobs/useFluentTheme.ts b/packages/storybook/src/knobs/useFluentTheme.ts
new file mode 100644
index 0000000000000..52f646559f52f
--- /dev/null
+++ b/packages/storybook/src/knobs/useFluentTheme.ts
@@ -0,0 +1,26 @@
+import {
+ webLightTheme,
+ webDarkTheme,
+ webHighContrastTheme,
+ teamsLightTheme,
+ teamsDarkTheme,
+ teamsHighContrastTheme,
+ Theme,
+} from '@fluentui/react-theme';
+import { select } from '@storybook/addon-knobs';
+
+const themeSelectorLabel = 'Theme';
+
+const themeOptions = [
+ { label: 'Web Light', theme: webLightTheme },
+ { label: 'Web Dark', theme: webDarkTheme },
+ { label: 'Web High Contrast', theme: webHighContrastTheme },
+ { label: 'Teams Light', theme: teamsLightTheme },
+ { label: 'Teams Dark', theme: teamsDarkTheme },
+ { label: 'Teams High Contrast', theme: teamsHighContrastTheme },
+];
+
+export const useFluentTheme = (): { label: string; theme: Theme } =>
+ // Casting any here due to issue: https://github.com/storybookjs/storybook/issues/9751
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ select(themeSelectorLabel, themeOptions as any, themeOptions[0] as any);