Skip to content

Commit

Permalink
feat(react-storybook-addon): make withFluentProvider decorator config…
Browse files Browse the repository at this point in the history
…urable to be used for VR tests (microsoft#25162)
  • Loading branch information
TristanWatanabe authored and NotWoods committed Nov 18, 2022
1 parent d1e4cde commit 5dca84e
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 12 deletions.
32 changes: 32 additions & 0 deletions packages/react-components/react-storybook-addon/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,35 @@ module.exports = {
- > 💡 this will run `prestorybook` script that compiles addon implementation with all of its direct dependencies that live within monorepo, so it can be consumed by local storybook
2. Every time you do any change to implementation, after you ran your local storybook you'll need to manually run `yarn workspace @fluentui/react-storybook-addon build` to reflect those changes

## Parameter Configuration

- Three custom optional parameters can be set to alter behavior of the addon
1. `dir` - determines whether to render story in `ltr` or `rtl` mode. Default is `undefined`.
2. `fluentTheme` - determines whether to render story theme in `web-light`, `web-dark`, `teams-high-contrast`, `teams-dark`, or `teams-light`. Setting this
parameter will disable ability to dynamically change the theme within story canvas or doc.
3. `mode` - when set to `vr-test`, this removes injected padding and background theme that's automatically applied from rendered story. Default is `default`.

```js
import { FluentParameters, parameters } from '@fluentui/react-storybook-addon';
import { Button } from '@fluentui/react-components';

export const Button = () => <Button> Hello World </Button>;

export const ButtonDarkMode = {
render: Button,
parameters: { fluentTheme: 'web-dark' } as FluentParameters, // story renders in Dark mode.
};

export const ButtonHighContrast = {
render: Button,
parameters: { fluentTheme: 'teams-high-contrast', mode: 'vr-test' } as FluentParameters; // story renders in High Contrast mode without injected padding and background style.
}

export const ButtonRTL = {
render: Button,
// parameters identity function will have all TS type annotations built in for intellisense.
parameters: parameters({ fluentTheme: 'web-light', dir: 'rtl', mode: 'vr-test'}), // story renders in RTL, Web light mode and without injected padding and background style.
};

```
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
```ts

import { Args } from '@storybook/api';
import { Parameters as Parameters_2 } from '@storybook/api';
import { StoryContext } from '@storybook/addons';
import type { Theme } from '@fluentui/react-theme';

Expand All @@ -14,12 +15,31 @@ export interface FluentGlobals extends Args {
[THEME_ID]?: ThemeIds;
}

// @public
export interface FluentParameters extends Parameters_2 {
// (undocumented)
dir?: 'ltr' | 'rtl';
// (undocumented)
fluentTheme?: ThemeIds;
// (undocumented)
mode?: 'default' | 'vr-test';
}

// @public (undocumented)
export interface FluentStoryContext extends StoryContext {
// (undocumented)
globals: FluentGlobals;
// (undocumented)
parameters: FluentParameters;
}

// @public (undocumented)
export function parameters(options?: FluentParameters): {
dir: string;
fluentTheme: string;
mode: string;
};

// @public (undocumented)
export const THEME_ID: "storybook/fluentui-react-addon/theme";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import * as React from 'react';
import { IconButton, Icons, TooltipLinkList, WithTooltip } from '@storybook/components';
import { useParameter } from '@storybook/api';

import { ThemeIds, themes, defaultTheme } from '../theme';
import { THEME_ID } from '../constants';
import { useGlobals } from '../hooks';
import { useGlobals, FluentParameters } from '../hooks';

export interface ThemeSelectorItem {
id: string;
Expand Down Expand Up @@ -33,7 +34,9 @@ function createThemeItems(

export const ThemePicker = () => {
const [globals, updateGlobals] = useGlobals();
const selectedThemeId = globals[THEME_ID] ?? defaultTheme.id;
const fluentTheme: FluentParameters['fluentTheme'] = useParameter('fluentTheme');

const selectedThemeId = fluentTheme ? fluentTheme : globals[THEME_ID] ?? defaultTheme.id;
const selectedTheme = themes.find(entry => entry.id === selectedThemeId);

const isActive = selectedThemeId !== defaultTheme.id;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,36 @@ import * as React from 'react';

import { FluentProvider } from '@fluentui/react-provider';
import { Theme } from '@fluentui/react-theme';

import { themes, defaultTheme } from '../theme';
import { themes, defaultTheme, ThemeIds } from '../theme';
import { THEME_ID } from '../constants';
import { FluentGlobals, FluentStoryContext } from '../hooks';

const findTheme = (themeId?: ThemeIds) => {
if (!themeId) {
return;
}
return themes.find(value => value.id === themeId);
};

const getActiveFluentTheme = (globals: FluentGlobals) => {
const selectedThemeId = globals[THEME_ID];
const { theme } = themes.find(value => value.id === selectedThemeId) ?? defaultTheme;
const { theme } = findTheme(selectedThemeId) ?? defaultTheme;

return { theme };
};

export const withFluentProvider = (StoryFn: () => JSX.Element, context: FluentStoryContext) => {
const { theme } = getActiveFluentTheme(context.globals);
const { globals, parameters } = context;
const { mode } = parameters;
const isVrTest = mode === 'vr-test';

const globalTheme = getActiveFluentTheme(globals);
const paramTheme = findTheme(parameters.fluentTheme);
const { theme } = paramTheme ?? globalTheme;

return (
<FluentProvider theme={theme}>
<FluentExampleContainer theme={theme}>{StoryFn()}</FluentExampleContainer>
<FluentProvider theme={theme} dir={parameters.dir}>
{isVrTest ? StoryFn() : <FluentExampleContainer theme={theme}>{StoryFn()}</FluentExampleContainer>}
</FluentProvider>
);
};
Expand All @@ -28,5 +40,5 @@ const FluentExampleContainer: React.FC<{ theme: Theme }> = props => {
const { theme } = props;

const backgroundColor = theme.colorNeutralBackground2;
return <div style={{ padding: '48px 24px', backgroundColor: backgroundColor }}>{props.children}</div>;
return <div style={{ padding: '48px 24px', backgroundColor }}>{props.children}</div>;
};
18 changes: 16 additions & 2 deletions packages/react-components/react-storybook-addon/src/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,34 @@
import { useGlobals as useStorybookGlobals, Args as StorybookArgs } from '@storybook/api';
import { useGlobals as useStorybookGlobals, Args as StorybookArgs, Parameters } from '@storybook/api';
import { StoryContext as StorybookContext } from '@storybook/addons';

import { THEME_ID } from './constants';
import { ThemeIds } from './theme';

export interface FluentStoryContext extends StorybookContext {
globals: FluentGlobals;
parameters: FluentParameters;
}

/**
* Extends the storybook globals object to include fluent specific propoerties
* Extends the storybook globals object to include fluent specific properties
*/
export interface FluentGlobals extends StorybookArgs {
[THEME_ID]?: ThemeIds;
}

/**
* Extends the storybook parameters object to include fluent specific properties
*/
export interface FluentParameters extends Parameters {
dir?: 'ltr' | 'rtl';
fluentTheme?: ThemeIds;
mode?: 'default' | 'vr-test';
}

export function useGlobals(): [FluentGlobals, (newGlobals: FluentGlobals) => void] {
return useStorybookGlobals();
}

export function parameters(options?: FluentParameters) {
return { dir: 'ltr', fluentTheme: 'web-light', mode: 'default', ...options };
}
3 changes: 2 additions & 1 deletion packages/react-components/react-storybook-addon/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export type { FluentGlobals, FluentStoryContext } from './hooks';
export type { FluentGlobals, FluentParameters, FluentStoryContext } from './hooks';
export type { ThemeIds } from './theme';
export { themes } from './theme';
export { THEME_ID } from './constants';
export { parameters } from './hooks';

0 comments on commit 5dca84e

Please sign in to comment.