From 3d58924b83313ad14d7649efc3b959c01894b410 Mon Sep 17 00:00:00 2001 From: Oleksandr Fediashov Date: Tue, 16 Jul 2024 11:30:05 +0200 Subject: [PATCH 1/2] fix(storybook-addon): fix decorators to functions --- .../.storybook/preview.js | 8 +++++++- .../etc/react-storybook-addon.api.md | 7 +++++++ .../src/decorators/withAriaLive.tsx | 19 ++++++++++++++++--- .../src/decorators/withFluentProvider.tsx | 8 +++++++- .../src/decorators/withReactStrictMode.tsx | 6 ++++++ .../react-storybook-addon/src/hooks.ts | 1 + 6 files changed, 44 insertions(+), 5 deletions(-) diff --git a/apps/vr-tests-react-components/.storybook/preview.js b/apps/vr-tests-react-components/.storybook/preview.js index 4d58f82e03742c..35158e1c8750b9 100644 --- a/apps/vr-tests-react-components/.storybook/preview.js +++ b/apps/vr-tests-react-components/.storybook/preview.js @@ -69,4 +69,10 @@ setAddon({ }); /** @type {import("@fluentui/react-storybook-addon").FluentParameters} */ -export const parameters = { layout: 'none', mode: 'vr-test' }; +export const parameters = { + layout: 'none', + mode: 'vr-test', + reactStorybookAddon: { + disabledDecorators: ['AriaLive'], + }, +}; diff --git a/packages/react-components/react-storybook-addon/etc/react-storybook-addon.api.md b/packages/react-components/react-storybook-addon/etc/react-storybook-addon.api.md index 952e79d996d901..33c63e5b47d7dc 100644 --- a/packages/react-components/react-storybook-addon/etc/react-storybook-addon.api.md +++ b/packages/react-components/react-storybook-addon/etc/react-storybook-addon.api.md @@ -31,6 +31,10 @@ export interface FluentParameters extends Parameters_2 { fluentTheme?: ThemeIds; // (undocumented) mode?: 'default' | 'vr-test'; + // (undocumented) + reactStorybookAddon?: { + disabledDecorators: ['AriaLive' | 'FluentProvider' | 'ReactStrictMode']; + }; } // @public (undocumented) @@ -46,6 +50,9 @@ export function parameters(options?: FluentParameters): { dir: string; fluentTheme: string; mode: string; + reactStorybookAddon?: { + disabledDecorators: ["AriaLive" | "FluentProvider" | "ReactStrictMode"]; + } | undefined; fileName?: string | undefined; options?: OptionsParameter | undefined; layout?: "centered" | "fullscreen" | "padded" | "none" | undefined; diff --git a/packages/react-components/react-storybook-addon/src/decorators/withAriaLive.tsx b/packages/react-components/react-storybook-addon/src/decorators/withAriaLive.tsx index adf4ceec180b8d..30f7579afe967b 100644 --- a/packages/react-components/react-storybook-addon/src/decorators/withAriaLive.tsx +++ b/packages/react-components/react-storybook-addon/src/decorators/withAriaLive.tsx @@ -1,17 +1,30 @@ +import { AriaLiveAnnouncer } from '@fluentui/react-aria'; import * as React from 'react'; -import { AriaLiveAnnouncer } from '@fluentui/react-aria'; +import { FluentStoryContext } from '../hooks'; + +export const withAriaLive = (Story: () => JSX.Element, context: FluentStoryContext) => { + const shouldDisable = context.parameters.reactStorybookAddon?.disabledDecorators?.includes('AriaLive'); -export const withAriaLive = (StoryFn: () => JSX.Element) => { - return {StoryFn()}; + if (shouldDisable) { + return Story(); + } + + return ( + + + + ); }; const AriaLiveWrapper: React.FC<{ children: React.ReactNode }> = props => { const [mounted, setMounted] = React.useState(false); + React.useEffect(() => { // The AriaLiveAnnouncer appends an element to DOM in an effect // Trigger an extra renderer to make sure that doc examples that need to announce on mount can do so setMounted(true); }, []); + return {mounted && props.children}; }; diff --git a/packages/react-components/react-storybook-addon/src/decorators/withFluentProvider.tsx b/packages/react-components/react-storybook-addon/src/decorators/withFluentProvider.tsx index a13d68508160d4..ad1eaa888a5918 100644 --- a/packages/react-components/react-storybook-addon/src/decorators/withFluentProvider.tsx +++ b/packages/react-components/react-storybook-addon/src/decorators/withFluentProvider.tsx @@ -23,8 +23,14 @@ const getActiveFluentTheme = (globals: FluentGlobals) => { export const withFluentProvider = (StoryFn: () => JSX.Element, context: FluentStoryContext) => { const { globals, parameters } = context; const { mode } = parameters; - const isVrTest = mode === 'vr-test'; + const shouldDisable = parameters.reactStorybookAddon?.disabledDecorators?.includes('FluentProvider'); + + if (shouldDisable) { + return StoryFn(); + } + + const isVrTest = mode === 'vr-test'; const dir = parameters.dir ?? globals[DIR_ID] ?? 'ltr'; const globalTheme = getActiveFluentTheme(globals); const paramTheme = findTheme(parameters.fluentTheme); diff --git a/packages/react-components/react-storybook-addon/src/decorators/withReactStrictMode.tsx b/packages/react-components/react-storybook-addon/src/decorators/withReactStrictMode.tsx index d1aab6613e2d5b..efe774f821c779 100644 --- a/packages/react-components/react-storybook-addon/src/decorators/withReactStrictMode.tsx +++ b/packages/react-components/react-storybook-addon/src/decorators/withReactStrictMode.tsx @@ -4,6 +4,12 @@ import { STRICT_MODE_ID } from '../constants'; import { FluentStoryContext } from '../hooks'; export const withReactStrictMode = (StoryFn: () => JSX.Element, context: FluentStoryContext) => { + const shouldDisable = context.parameters.reactStorybookAddon?.disabledDecorators?.includes('ReactStrictMode'); + + if (shouldDisable) { + return StoryFn(); + } + const isActive = context.globals[STRICT_MODE_ID] ?? false; return {StoryFn()}; diff --git a/packages/react-components/react-storybook-addon/src/hooks.ts b/packages/react-components/react-storybook-addon/src/hooks.ts index bfdd1b644c9aee..9a22aaa2eaecd2 100644 --- a/packages/react-components/react-storybook-addon/src/hooks.ts +++ b/packages/react-components/react-storybook-addon/src/hooks.ts @@ -25,6 +25,7 @@ export interface FluentParameters extends Parameters { dir?: 'ltr' | 'rtl'; fluentTheme?: ThemeIds; mode?: 'default' | 'vr-test'; + reactStorybookAddon?: { disabledDecorators: ['AriaLive' | 'FluentProvider' | 'ReactStrictMode'] }; } export function useGlobals(): [FluentGlobals, (newGlobals: FluentGlobals) => void] { From e5257ff646f070a4914ac55a35184487fd976579 Mon Sep 17 00:00:00 2001 From: Oleksandr Fediashov Date: Tue, 23 Jul 2024 15:11:01 +0200 Subject: [PATCH 2/2] PR comments --- .../react-storybook-addon/src/decorators/withAriaLive.tsx | 5 ++--- .../src/decorators/withFluentProvider.tsx | 5 ++--- .../src/decorators/withReactStrictMode.tsx | 5 ++--- .../react-storybook-addon/src/utils/isDecoratorDisabled.ts | 7 +++++++ 4 files changed, 13 insertions(+), 9 deletions(-) create mode 100644 packages/react-components/react-storybook-addon/src/utils/isDecoratorDisabled.ts diff --git a/packages/react-components/react-storybook-addon/src/decorators/withAriaLive.tsx b/packages/react-components/react-storybook-addon/src/decorators/withAriaLive.tsx index 30f7579afe967b..a607fb28a5c79d 100644 --- a/packages/react-components/react-storybook-addon/src/decorators/withAriaLive.tsx +++ b/packages/react-components/react-storybook-addon/src/decorators/withAriaLive.tsx @@ -2,11 +2,10 @@ import { AriaLiveAnnouncer } from '@fluentui/react-aria'; import * as React from 'react'; import { FluentStoryContext } from '../hooks'; +import { isDecoratorDisabled } from '../utils/isDecoratorDisabled'; export const withAriaLive = (Story: () => JSX.Element, context: FluentStoryContext) => { - const shouldDisable = context.parameters.reactStorybookAddon?.disabledDecorators?.includes('AriaLive'); - - if (shouldDisable) { + if (isDecoratorDisabled(context, 'AriaLive')) { return Story(); } diff --git a/packages/react-components/react-storybook-addon/src/decorators/withFluentProvider.tsx b/packages/react-components/react-storybook-addon/src/decorators/withFluentProvider.tsx index ad1eaa888a5918..467bed589a9d64 100644 --- a/packages/react-components/react-storybook-addon/src/decorators/withFluentProvider.tsx +++ b/packages/react-components/react-storybook-addon/src/decorators/withFluentProvider.tsx @@ -5,6 +5,7 @@ import { Theme } from '@fluentui/react-theme'; import { themes, defaultTheme, ThemeIds } from '../theme'; import { DIR_ID, THEME_ID } from '../constants'; import { FluentGlobals, FluentStoryContext } from '../hooks'; +import { isDecoratorDisabled } from '../utils/isDecoratorDisabled'; const findTheme = (themeId?: ThemeIds) => { if (!themeId) { @@ -24,9 +25,7 @@ export const withFluentProvider = (StoryFn: () => JSX.Element, context: FluentSt const { globals, parameters } = context; const { mode } = parameters; - const shouldDisable = parameters.reactStorybookAddon?.disabledDecorators?.includes('FluentProvider'); - - if (shouldDisable) { + if (isDecoratorDisabled(context, 'FluentProvider')) { return StoryFn(); } diff --git a/packages/react-components/react-storybook-addon/src/decorators/withReactStrictMode.tsx b/packages/react-components/react-storybook-addon/src/decorators/withReactStrictMode.tsx index efe774f821c779..3592371cd96527 100644 --- a/packages/react-components/react-storybook-addon/src/decorators/withReactStrictMode.tsx +++ b/packages/react-components/react-storybook-addon/src/decorators/withReactStrictMode.tsx @@ -2,11 +2,10 @@ import * as React from 'react'; import { STRICT_MODE_ID } from '../constants'; import { FluentStoryContext } from '../hooks'; +import { isDecoratorDisabled } from '../utils/isDecoratorDisabled'; export const withReactStrictMode = (StoryFn: () => JSX.Element, context: FluentStoryContext) => { - const shouldDisable = context.parameters.reactStorybookAddon?.disabledDecorators?.includes('ReactStrictMode'); - - if (shouldDisable) { + if (isDecoratorDisabled(context, 'ReactStrictMode')) { return StoryFn(); } diff --git a/packages/react-components/react-storybook-addon/src/utils/isDecoratorDisabled.ts b/packages/react-components/react-storybook-addon/src/utils/isDecoratorDisabled.ts new file mode 100644 index 00000000000000..9295f69a4a992c --- /dev/null +++ b/packages/react-components/react-storybook-addon/src/utils/isDecoratorDisabled.ts @@ -0,0 +1,7 @@ +import type { FluentParameters, FluentStoryContext } from '../hooks'; + +type DecoratorName = NonNullable['disabledDecorators'][number]; + +export function isDecoratorDisabled(context: FluentStoryContext, decoratorName: DecoratorName): boolean { + return context.parameters.reactStorybookAddon?.disabledDecorators?.includes(decoratorName) ?? false; +}