From 037e185df35f3777cf7ca26f64f29e57e2066072 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Sun, 15 Jan 2023 22:44:58 +1100 Subject: [PATCH 01/11] Change to `forceInitialArgs` --- code/jest.config.js | 2 +- .../src/modules/preview-web/Preview.tsx | 6 +- .../modules/preview-web/PreviewWeb.test.ts | 33 +++++++++++ .../preview-web/render/StoryRender.test.ts | 43 +++++++++++++++ .../modules/preview-web/render/StoryRender.ts | 24 ++++++-- code/lib/types/src/modules/docs.ts | 1 + code/ui/blocks/src/blocks/DocsStory.tsx | 3 +- code/ui/blocks/src/blocks/Stories.tsx | 6 +- code/ui/blocks/src/blocks/Story.stories.tsx | 16 +++++- code/ui/blocks/src/blocks/Story.tsx | 8 ++- code/ui/blocks/src/blocks/types.ts | 1 + .../blocks/src/components/Story.stories.tsx | 55 ++++++++++++++----- code/ui/blocks/src/components/Story.tsx | 4 +- 13 files changed, 174 insertions(+), 28 deletions(-) diff --git a/code/jest.config.js b/code/jest.config.js index ee2ebd55a9ac..6e72f4acb974 100644 --- a/code/jest.config.js +++ b/code/jest.config.js @@ -4,7 +4,7 @@ module.exports = { '/frameworks/!(angular)*', '/lib/*', '/renderers/*', - '/ui/*', + '/ui/!(node_modules)*', ], collectCoverage: false, collectCoverageFrom: [ diff --git a/code/lib/preview-api/src/modules/preview-web/Preview.tsx b/code/lib/preview-api/src/modules/preview-web/Preview.tsx index f1c2da44c15b..18aba716d046 100644 --- a/code/lib/preview-api/src/modules/preview-web/Preview.tsx +++ b/code/lib/preview-api/src/modules/preview-web/Preview.tsx @@ -265,7 +265,11 @@ export class Preview { async onUpdateArgs({ storyId, updatedArgs }: { storyId: StoryId; updatedArgs: Args }) { this.storyStore.args.update(storyId, updatedArgs); - await Promise.all(this.storyRenders.filter((r) => r.id === storyId).map((r) => r.rerender())); + await Promise.all( + this.storyRenders + .filter((r) => r.id === storyId && !r.renderOptions.forceInitialArgs) + .map((r) => r.rerender()) + ); this.channel.emit(STORY_ARGS_UPDATED, { storyId, diff --git a/code/lib/preview-api/src/modules/preview-web/PreviewWeb.test.ts b/code/lib/preview-api/src/modules/preview-web/PreviewWeb.test.ts index 9639db4617a2..e6dc88486c0a 100644 --- a/code/lib/preview-api/src/modules/preview-web/PreviewWeb.test.ts +++ b/code/lib/preview-api/src/modules/preview-web/PreviewWeb.test.ts @@ -1131,6 +1131,39 @@ describe('PreviewWeb', () => { 'story-element' ); }); + + it('does not re-render the story when forceInitialArgs=true', async () => { + document.location.search = '?id=component-one--docs&viewMode=docs'; + + const preview = await createAndRenderPreview(); + await waitForRender(); + + mockChannel.emit.mockClear(); + const story = await preview.storyStore.loadStory({ storyId: 'component-one--a' }); + preview.renderStoryToElement(story, 'story-element' as any, { forceInitialArgs: true }); + await waitForRender(); + + expect(projectAnnotations.renderToCanvas).toHaveBeenCalledWith( + expect.objectContaining({ + storyContext: expect.objectContaining({ + args: { foo: 'a' }, + }), + }), + 'story-element' + ); + + docsRenderer.render.mockClear(); + mockChannel.emit.mockClear(); + emitter.emit(UPDATE_STORY_ARGS, { + storyId: 'component-one--a', + updatedArgs: { new: 'arg' }, + }); + await waitForEvents([STORY_ARGS_UPDATED]); + + // We don't re-render the story + await expect(waitForRender).rejects.toThrow(); + expect(projectAnnotations.renderToCanvas).toHaveBeenCalledTimes(1); + }); }); }); }); diff --git a/code/lib/preview-api/src/modules/preview-web/render/StoryRender.test.ts b/code/lib/preview-api/src/modules/preview-web/render/StoryRender.test.ts index d40adca995f0..cb382cb3506b 100644 --- a/code/lib/preview-api/src/modules/preview-web/render/StoryRender.test.ts +++ b/code/lib/preview-api/src/modules/preview-web/render/StoryRender.test.ts @@ -101,4 +101,47 @@ describe('StoryRender', () => { await render.renderToElement({} as any); expect(story.playFunction).not.toHaveBeenCalled(); }); + + it('passes the initialArgs to loaders and render function if forceInitialArgs is true', async () => { + const story = { + id: 'id', + title: 'title', + name: 'name', + tags: [], + initialArgs: { a: 'b' }, + applyLoaders: jest.fn(), + unboundStoryFn: jest.fn(), + playFunction: jest.fn(), + }; + + const renderToScreen = jest.fn(); + + const render = new StoryRender( + new Channel(), + { getStoryContext: () => ({ args: { a: 'c ' } }) } as any, + renderToScreen as any, + {} as any, + entry.id, + 'story', + { forceInitialArgs: true }, + story as any + ); + + await render.renderToElement({} as any); + + expect(story.applyLoaders).toHaveBeenCalledWith( + expect.objectContaining({ + args: { a: 'b' }, + }) + ); + + expect(renderToScreen).toHaveBeenCalledWith( + expect.objectContaining({ + storyContext: expect.objectContaining({ + args: { a: 'b' }, + }), + }), + expect.any(Object) + ); + }); }); diff --git a/code/lib/preview-api/src/modules/preview-web/render/StoryRender.ts b/code/lib/preview-api/src/modules/preview-web/render/StoryRender.ts index 89c7422872cd..9df19ae2d1d6 100644 --- a/code/lib/preview-api/src/modules/preview-web/render/StoryRender.ts +++ b/code/lib/preview-api/src/modules/preview-web/render/StoryRender.ts @@ -73,7 +73,7 @@ export class StoryRender implements Render, public id: StoryId, public viewMode: ViewMode, - public renderOptions: StoryRenderOptions = { autoplay: true }, + public renderOptions: StoryRenderOptions = { autoplay: true, forceInitialArgs: false }, story?: PreparedStory ) { this.abortController = new AbortController(); @@ -154,8 +154,17 @@ export class StoryRender implements Render implements Render ({ + ...this.storyContext(), + ...(this.renderOptions.forceInitialArgs && { args: initialArgs }), + }); + let loadedContext: Awaited>; await this.runPhase(abortSignal, 'loading', async () => { loadedContext = await applyLoaders({ - ...this.storyContext(), + ...getCurrentContext(), viewMode: this.viewMode, } as StoryContextForLoaders); }); @@ -185,7 +199,7 @@ export class StoryRender implements Render { diff --git a/code/ui/blocks/src/blocks/DocsStory.tsx b/code/ui/blocks/src/blocks/DocsStory.tsx index 44063200d09d..62341ecfcc93 100644 --- a/code/ui/blocks/src/blocks/DocsStory.tsx +++ b/code/ui/blocks/src/blocks/DocsStory.tsx @@ -13,6 +13,7 @@ export const DocsStory: FC = ({ expanded = true, withToolbar = false, parameters = {}, + __forceInitialArgs = false, }) => { let description; const { docs } = parameters; @@ -27,7 +28,7 @@ export const DocsStory: FC = ({ {subheading && {subheading}} {description && } - + ); diff --git a/code/ui/blocks/src/blocks/Stories.tsx b/code/ui/blocks/src/blocks/Stories.tsx index 7f635e0d110c..76cb3a6a1e04 100644 --- a/code/ui/blocks/src/blocks/Stories.tsx +++ b/code/ui/blocks/src/blocks/Stories.tsx @@ -10,7 +10,7 @@ interface StoriesProps { includePrimary?: boolean; } -export const Stories: FC = ({ title, includePrimary = false }) => { +export const Stories: FC = ({ title, includePrimary = true }) => { const { componentStories } = useContext(DocsContext); let stories: DocsStoryProps[] = componentStories(); @@ -23,7 +23,9 @@ export const Stories: FC = ({ title, includePrimary = false }) => return ( <> {title} - {stories.map((story) => story && )} + {stories.map( + (story) => story && + )} ); }; diff --git a/code/ui/blocks/src/blocks/Story.stories.tsx b/code/ui/blocks/src/blocks/Story.stories.tsx index a64517faf40f..7d99064d3960 100644 --- a/code/ui/blocks/src/blocks/Story.stories.tsx +++ b/code/ui/blocks/src/blocks/Story.stories.tsx @@ -2,11 +2,12 @@ import React from 'react'; import type { Meta, StoryObj } from '@storybook/react'; -import { Story as StoryComponent } from './Story'; +import { Story as StoryBlock } from './Story'; import * as ButtonStories from '../examples/Button.stories'; +import * as StoryComponentStories from '../components/Story.stories'; -const meta: Meta = { - component: StoryComponent, +const meta: Meta = { + component: StoryBlock, parameters: { relativeCsfPaths: ['../examples/Button.stories', '../blocks/Story.stories'], }, @@ -178,3 +179,12 @@ export const WithInteractionsAutoplayInStory: Story = { chromatic: { delay: 500 }, }, }; + +export const IgnoreArgsUpdates: Story = { + ...StoryComponentStories.ForceInitialArgs, + args: { + of: ButtonStories.Primary, + storyExport: ButtonStories.Primary, + __forceInitialArgs: true, + } as any, +}; diff --git a/code/ui/blocks/src/blocks/Story.tsx b/code/ui/blocks/src/blocks/Story.tsx index 439550156a24..ef8309d027d5 100644 --- a/code/ui/blocks/src/blocks/Story.tsx +++ b/code/ui/blocks/src/blocks/Story.tsx @@ -72,6 +72,10 @@ type StoryParameters = { * Whether to run the story's play function */ autoplay?: boolean; + /** + * Internal prop to control if a story re-renders on args updates + */ + __forceInitialArgs?: boolean; }; export type StoryProps = (StoryDefProps | StoryRefProps) & StoryParameters; @@ -131,6 +135,8 @@ export const getStoryProps = ( inline: true, height, autoplay, + // eslint-disable-next-line no-underscore-dangle + forceInitialArgs: !!props.__forceInitialArgs, renderStoryToElement: context.renderStoryToElement, }; } @@ -145,7 +151,7 @@ export const getStoryProps = ( }; }; -const Story: FC = (props) => { +const Story: FC = (props = { __forceInitialArgs: false }) => { const context = useContext(DocsContext); const storyId = getStoryId(props, context); const story = useStory(storyId, context); diff --git a/code/ui/blocks/src/blocks/types.ts b/code/ui/blocks/src/blocks/types.ts index b48e9ac5f2bf..27d62c250387 100644 --- a/code/ui/blocks/src/blocks/types.ts +++ b/code/ui/blocks/src/blocks/types.ts @@ -14,4 +14,5 @@ export interface StoryData { export type DocsStoryProps = StoryData & { expanded?: boolean; withToolbar?: boolean; + __forceInitialArgs?: boolean; }; diff --git a/code/ui/blocks/src/components/Story.stories.tsx b/code/ui/blocks/src/components/Story.stories.tsx index 20c4107bc7dc..15c9f1c447f7 100644 --- a/code/ui/blocks/src/components/Story.stories.tsx +++ b/code/ui/blocks/src/components/Story.stories.tsx @@ -1,6 +1,10 @@ import React from 'react'; -import type { StoryObj, Meta } from '@storybook/react'; -import type { StoryProps } from './Story'; +import type { Meta } from '@storybook/react'; +import { within } from '@storybook/testing-library'; +import type { PlayFunctionContext } from '@storybook/csf'; +import type { WebRenderer } from '@storybook/types'; +import { RESET_STORY_ARGS, STORY_ARGS_UPDATED, UPDATE_STORY_ARGS } from '@storybook/core-events'; + import { Story as StoryComponent, StorySkeleton } from './Story'; import type { DocsContextProps } from '../blocks'; import * as ButtonStories from '../examples/Button.stories'; @@ -8,26 +12,22 @@ import * as ButtonStories from '../examples/Button.stories'; const preview = __STORYBOOK_PREVIEW__; const renderStoryToElement = preview.renderStoryToElement.bind(preview); -// TODO: can't quite figure out types here. -// type OverriddenStoryProps = StoryProps & { -// story: typeof ButtonStories.Primary; -// }; - -const meta: Meta = { +const meta: Meta = { component: StoryComponent, parameters: { relativeCsfPaths: ['../examples/Button.stories'], }, args: { height: '100px', - // NOTE: the real story arg is a PreparedStory, which we'll get in the render function below - story: ButtonStories.Primary as any, + storyExport: ButtonStories.Primary, + autoplay: false, + ignoreArgsUpdates: false, }, render(args, { loaded }) { const docsContext = loaded.docsContext as DocsContextProps; - const storyId = docsContext.storyIdByModuleExport(args.story); + const storyId = docsContext.storyIdByModuleExport(args.storyExport); const story = docsContext.storyById(storyId); - return ; + return ; }, }; export default meta; @@ -48,9 +48,38 @@ export const IFrame = { }, }; +export const ForceInitialArgs = { + args: { + storyExport: ButtonStories.Primary, + inline: true, + autoplay: true, + forceInitialArgs: true, + renderStoryToElement, + }, + play: async ({ args, canvasElement, loaded }: PlayFunctionContext) => { + const docsContext = loaded.docsContext as DocsContextProps; + const storyId = docsContext.storyIdByModuleExport(args.storyExport); + + const channel = globalThis.__STORYBOOK_ADDONS_CHANNEL__; + await within(canvasElement).findByText(/Button/); + + const updatedPromise = new Promise((resolve) => { + channel.once(STORY_ARGS_UPDATED, resolve); + }); + await channel.emit(UPDATE_STORY_ARGS, { storyId, updatedArgs: { label: 'Updated' } }); + await updatedPromise; + + await within(canvasElement).findByText(/Button/); + await channel.emit(RESET_STORY_ARGS, { storyId }); + await new Promise((resolve) => { + channel.once(STORY_ARGS_UPDATED, resolve); + }); + }, +}; + export const Autoplay = { args: { - story: ButtonStories.Clicking, + storyExport: ButtonStories.Clicking, inline: true, autoplay: true, renderStoryToElement, diff --git a/code/ui/blocks/src/components/Story.tsx b/code/ui/blocks/src/components/Story.tsx index e5b9b20c0f80..e0907d466d47 100644 --- a/code/ui/blocks/src/components/Story.tsx +++ b/code/ui/blocks/src/components/Story.tsx @@ -18,6 +18,7 @@ interface InlineStoryProps extends CommonProps { inline: true; height?: string; autoplay: boolean; + forceInitialArgs: boolean; renderStoryToElement: DocsContextProps['renderStoryToElement']; } @@ -32,6 +33,7 @@ const InlineStory: FunctionComponent = ({ story, height, autoplay, + forceInitialArgs, renderStoryToElement, }) => { const storyRef = useRef(); @@ -42,7 +44,7 @@ const InlineStory: FunctionComponent = ({ return () => {}; } const element = storyRef.current as HTMLElement; - const cleanup = renderStoryToElement(story, element, { autoplay }); + const cleanup = renderStoryToElement(story, element, { autoplay, forceInitialArgs }); setShowLoader(false); return () => { cleanup(); From aaeeb1a8b8da1abfd1a3531ec3cc9b6745fd9467 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Sun, 15 Jan 2023 22:46:04 +1100 Subject: [PATCH 02/11] Suggestion --- code/ui/blocks/src/components/Story.stories.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/ui/blocks/src/components/Story.stories.tsx b/code/ui/blocks/src/components/Story.stories.tsx index 15c9f1c447f7..3b97b7fda98c 100644 --- a/code/ui/blocks/src/components/Story.stories.tsx +++ b/code/ui/blocks/src/components/Story.stories.tsx @@ -56,6 +56,7 @@ export const ForceInitialArgs = { forceInitialArgs: true, renderStoryToElement, }, + // test that it ignores updated args by emitting an arg update and assert that it isn't reflected in the DOM play: async ({ args, canvasElement, loaded }: PlayFunctionContext) => { const docsContext = loaded.docsContext as DocsContextProps; const storyId = docsContext.storyIdByModuleExport(args.storyExport); @@ -68,8 +69,8 @@ export const ForceInitialArgs = { }); await channel.emit(UPDATE_STORY_ARGS, { storyId, updatedArgs: { label: 'Updated' } }); await updatedPromise; - await within(canvasElement).findByText(/Button/); + await channel.emit(RESET_STORY_ARGS, { storyId }); await new Promise((resolve) => { channel.once(STORY_ARGS_UPDATED, resolve); From 681782c511de6fa98d2fc0781e31533f146614c4 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Mon, 16 Jan 2023 12:05:28 +1100 Subject: [PATCH 03/11] Fix Preview stories --- code/ui/blocks/src/components/Preview.stories.tsx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/code/ui/blocks/src/components/Preview.stories.tsx b/code/ui/blocks/src/components/Preview.stories.tsx index 61596130556c..53c7247eb622 100644 --- a/code/ui/blocks/src/components/Preview.stories.tsx +++ b/code/ui/blocks/src/components/Preview.stories.tsx @@ -107,6 +107,7 @@ export const WithToolbar = ( story={getPreparedStory(docsContext, ButtonStories.Primary)} renderStoryToElement={renderStoryToElement} autoplay={false} + forceInitialArgs={false} height="100px" /> @@ -137,6 +138,7 @@ export const WithToolbarMulti = ( story={getPreparedStory(docsContext, ButtonStories.Primary)} renderStoryToElement={renderStoryToElement} autoplay={false} + forceInitialArgs={false} height="100px" /> @@ -159,6 +162,7 @@ export const WithFullscreenSingle = ( story={getPreparedStory(docsContext, ButtonStories.Primary)} renderStoryToElement={renderStoryToElement} autoplay={false} + forceInitialArgs={false} height="100px" /> @@ -174,6 +178,7 @@ export const WithFullscreenMulti = ( story={getPreparedStory(docsContext, ButtonStories.Primary)} renderStoryToElement={renderStoryToElement} autoplay={false} + forceInitialArgs={false} height="100px" /> @@ -196,6 +202,7 @@ export const WithCenteredSingle = ( story={getPreparedStory(docsContext, ButtonStories.Primary)} renderStoryToElement={renderStoryToElement} autoplay={false} + forceInitialArgs={false} height="100px" /> @@ -211,6 +218,7 @@ export const WithCenteredMulti = ( story={getPreparedStory(docsContext, ButtonStories.Primary)} renderStoryToElement={renderStoryToElement} autoplay={false} + forceInitialArgs={false} height="100px" /> From c22aac8e5bb8a85bb81fd58db1d9664a9662e6c3 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Mon, 16 Jan 2023 12:20:29 +1100 Subject: [PATCH 04/11] Fix ordering spec --- code/e2e-tests/addon-docs.spec.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/code/e2e-tests/addon-docs.spec.ts b/code/e2e-tests/addon-docs.spec.ts index 402ba144ece0..1e50e4433794 100644 --- a/code/e2e-tests/addon-docs.spec.ts +++ b/code/e2e-tests/addon-docs.spec.ts @@ -58,11 +58,12 @@ test.describe('addon-docs', () => { await sbPage.navigateToStory('addons/docs/docspage/basic', 'docs'); // The `` block should render the "Basic" story, and the `` block should - // render the "Another" story + // render both the "Basic" and "Another" story const root = sbPage.previewRoot(); const stories = root.locator('.sbdocs-h3'); - await expect(await stories.count()).toBe(1); - await expect(stories.first()).toHaveText('Another'); + await expect(await stories.count()).toBe(2); + await expect(stories.first()).toHaveText('Basic'); + await expect(stories.last()).toHaveText('Another'); }); }); From a08c2a205776cd4e7e9e23559872d354f2e8dec6 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Mon, 16 Jan 2023 12:58:01 +1100 Subject: [PATCH 05/11] Add a `__primary` prop and use it to alter the idea of `` --- code/ui/blocks/src/blocks/DocsStory.tsx | 8 ++++- code/ui/blocks/src/blocks/Primary.tsx | 2 +- code/ui/blocks/src/blocks/Story.tsx | 18 ++++++----- code/ui/blocks/src/blocks/types.ts | 1 + .../blocks/src/components/Story.stories.tsx | 1 + code/ui/blocks/src/components/Story.tsx | 31 ++++++++++++------- 6 files changed, 39 insertions(+), 22 deletions(-) diff --git a/code/ui/blocks/src/blocks/DocsStory.tsx b/code/ui/blocks/src/blocks/DocsStory.tsx index 62341ecfcc93..efdf5e51081b 100644 --- a/code/ui/blocks/src/blocks/DocsStory.tsx +++ b/code/ui/blocks/src/blocks/DocsStory.tsx @@ -14,6 +14,7 @@ export const DocsStory: FC = ({ withToolbar = false, parameters = {}, __forceInitialArgs = false, + __primary = false, }) => { let description; const { docs } = parameters; @@ -28,7 +29,12 @@ export const DocsStory: FC = ({ {subheading && {subheading}} {description && } - + ); diff --git a/code/ui/blocks/src/blocks/Primary.tsx b/code/ui/blocks/src/blocks/Primary.tsx index c430345e7717..8095d079323e 100644 --- a/code/ui/blocks/src/blocks/Primary.tsx +++ b/code/ui/blocks/src/blocks/Primary.tsx @@ -12,5 +12,5 @@ export const Primary: FC = ({ name }) => { const docsContext = useContext(DocsContext); const storyId = name && docsContext.storyIdByName(name); const story = docsContext.storyById(storyId); - return story ? : null; + return story ? : null; }; diff --git a/code/ui/blocks/src/blocks/Story.tsx b/code/ui/blocks/src/blocks/Story.tsx index 17d86a8324c8..ef834d1f6c8c 100644 --- a/code/ui/blocks/src/blocks/Story.tsx +++ b/code/ui/blocks/src/blocks/Story.tsx @@ -15,8 +15,6 @@ import type { DocsContextProps } from './DocsContext'; import { DocsContext } from './DocsContext'; import { useStory } from './useStory'; -export const storyBlockIdFromId = (storyId: string) => `story--${storyId}`; - type PureStoryProps = ComponentProps; /** @@ -76,6 +74,10 @@ type StoryParameters = { * Internal prop to control if a story re-renders on args updates */ __forceInitialArgs?: boolean; + /** + * Internal prop if this story is the primary story + */ + __primary: boolean; }; export type StoryProps = (StoryDefProps | StoryRefProps) & StoryParameters; @@ -142,6 +144,8 @@ export const getStoryProps = ( autoplay, // eslint-disable-next-line no-underscore-dangle forceInitialArgs: !!props.__forceInitialArgs, + // eslint-disable-next-line no-underscore-dangle + primary: !!props.__primary, renderStoryToElement: context.renderStoryToElement, }; } @@ -153,10 +157,12 @@ export const getStoryProps = ( story, inline: false, height, + // eslint-disable-next-line no-underscore-dangle + primary: !!props.__primary, }; }; -const Story: FC = (props = { __forceInitialArgs: false }) => { +const Story: FC = (props = { __forceInitialArgs: false, __primary: false }) => { const context = useContext(DocsContext); const storyId = getStoryId(props, context); const story = useStory(storyId, context); @@ -170,11 +176,7 @@ const Story: FC = (props = { __forceInitialArgs: false }) => { return null; } - return ( -
- -
- ); + return ; }; export { Story }; diff --git a/code/ui/blocks/src/blocks/types.ts b/code/ui/blocks/src/blocks/types.ts index 27d62c250387..5aab18554b8e 100644 --- a/code/ui/blocks/src/blocks/types.ts +++ b/code/ui/blocks/src/blocks/types.ts @@ -15,4 +15,5 @@ export type DocsStoryProps = StoryData & { expanded?: boolean; withToolbar?: boolean; __forceInitialArgs?: boolean; + __primary?: boolean; }; diff --git a/code/ui/blocks/src/components/Story.stories.tsx b/code/ui/blocks/src/components/Story.stories.tsx index 46e8db74ca38..a45cfa281b1b 100644 --- a/code/ui/blocks/src/components/Story.stories.tsx +++ b/code/ui/blocks/src/components/Story.stories.tsx @@ -26,6 +26,7 @@ const meta: Meta = { }, args: { height: '100px', + primary: false, // NOTE: the real story arg is a PreparedStory, which we'll get in the render function below storyExport: ButtonStories.Primary as any, }, diff --git a/code/ui/blocks/src/components/Story.tsx b/code/ui/blocks/src/components/Story.tsx index e0907d466d47..c2e97dca3d38 100644 --- a/code/ui/blocks/src/components/Story.tsx +++ b/code/ui/blocks/src/components/Story.tsx @@ -12,6 +12,7 @@ const BASE_URL = PREVIEW_URL || 'iframe.html'; interface CommonProps { story: PreparedStory; inline: boolean; + primary: boolean; } interface InlineStoryProps extends CommonProps { @@ -29,16 +30,15 @@ interface IFrameStoryProps extends CommonProps { export type StoryProps = InlineStoryProps | IFrameStoryProps; -const InlineStory: FunctionComponent = ({ - story, - height, - autoplay, - forceInitialArgs, - renderStoryToElement, -}) => { +export const storyBlockIdFromId = ({ story, primary }: StoryProps) => + `story--${story.id}${primary ? '--primary' : ''}`; + +const InlineStory: FunctionComponent = (props) => { const storyRef = useRef(); const [showLoader, setShowLoader] = useState(true); + const { story, height, autoplay, forceInitialArgs, renderStoryToElement } = props; + useEffect(() => { if (!(story && storyRef.current)) { return () => {}; @@ -57,7 +57,9 @@ const InlineStory: FunctionComponent = ({ return ( <> {height ? ( - + ) : null} {showLoader && }
= ({ story, height = '500 */ const Story: FunctionComponent = (props) => { const { inline } = props; - return inline ? ( - - ) : ( - + + return ( +
+ {inline ? ( + + ) : ( + + )} +
); }; From 0186f3cd3c4701aee9aa517618740602f2cbc07e Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Mon, 16 Jan 2023 14:50:00 +1100 Subject: [PATCH 06/11] Fix up some props --- code/ui/blocks/src/blocks/Story.tsx | 2 +- code/ui/blocks/src/components/Preview.stories.tsx | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/code/ui/blocks/src/blocks/Story.tsx b/code/ui/blocks/src/blocks/Story.tsx index ef834d1f6c8c..7cae4fa51d45 100644 --- a/code/ui/blocks/src/blocks/Story.tsx +++ b/code/ui/blocks/src/blocks/Story.tsx @@ -77,7 +77,7 @@ type StoryParameters = { /** * Internal prop if this story is the primary story */ - __primary: boolean; + __primary?: boolean; }; export type StoryProps = (StoryDefProps | StoryRefProps) & StoryParameters; diff --git a/code/ui/blocks/src/components/Preview.stories.tsx b/code/ui/blocks/src/components/Preview.stories.tsx index 53c7247eb622..3f50ef522d44 100644 --- a/code/ui/blocks/src/components/Preview.stories.tsx +++ b/code/ui/blocks/src/components/Preview.stories.tsx @@ -108,6 +108,7 @@ export const WithToolbar = ( renderStoryToElement={renderStoryToElement} autoplay={false} forceInitialArgs={false} + primary={false} height="100px" /> @@ -139,6 +140,7 @@ export const WithToolbarMulti = ( renderStoryToElement={renderStoryToElement} autoplay={false} forceInitialArgs={false} + primary={false} height="100px" /> @@ -163,6 +166,7 @@ export const WithFullscreenSingle = ( renderStoryToElement={renderStoryToElement} autoplay={false} forceInitialArgs={false} + primary={false} height="100px" /> @@ -179,6 +183,7 @@ export const WithFullscreenMulti = ( renderStoryToElement={renderStoryToElement} autoplay={false} forceInitialArgs={false} + primary={false} height="100px" /> @@ -203,6 +209,7 @@ export const WithCenteredSingle = ( renderStoryToElement={renderStoryToElement} autoplay={false} forceInitialArgs={false} + primary={false} height="100px" /> @@ -219,6 +226,7 @@ export const WithCenteredMulti = ( renderStoryToElement={renderStoryToElement} autoplay={false} forceInitialArgs={false} + primary={false} height="100px" /> From ebda378f3e2f503212131a107880e9e2af425d48 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Mon, 16 Jan 2023 14:58:31 +1100 Subject: [PATCH 07/11] Update test to cope with story rendering more than once --- code/e2e-tests/preview-web.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/e2e-tests/preview-web.spec.ts b/code/e2e-tests/preview-web.spec.ts index 3dec28a68910..28c3b2e1b01d 100644 --- a/code/e2e-tests/preview-web.spec.ts +++ b/code/e2e-tests/preview-web.spec.ts @@ -26,7 +26,7 @@ test.describe('preview-web', () => { await expect(sbPage.page.locator('.sidebar-container')).toBeVisible(); - await sbPage.previewRoot().getByRole('button').getByText('Submit').press('s'); + await sbPage.previewRoot().getByRole('button').getByText('Submit').first().press('s'); await expect(sbPage.page.locator('.sidebar-container')).not.toBeVisible(); }); }); From eaf762fe31126fec5b836de4889ab915aa95c41e Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Wed, 18 Jan 2023 20:02:54 +1100 Subject: [PATCH 08/11] Update code/ui/blocks/src/blocks/Story.stories.tsx Co-authored-by: Jeppe Reinhold --- code/ui/blocks/src/blocks/Story.stories.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/ui/blocks/src/blocks/Story.stories.tsx b/code/ui/blocks/src/blocks/Story.stories.tsx index 2368ec2d91fd..34cc6738af61 100644 --- a/code/ui/blocks/src/blocks/Story.stories.tsx +++ b/code/ui/blocks/src/blocks/Story.stories.tsx @@ -201,7 +201,7 @@ export const WithInteractionsAutoplayInStory: Story = { }, }; -export const IgnoreArgsUpdates: Story = { +export const ForceInitialArgs: Story = { ...StoryComponentStories.ForceInitialArgs, args: { of: ButtonStories.Primary, From 00fad256594a0593450cffadf0cc4e69ca85c00d Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Wed, 18 Jan 2023 13:59:29 +0100 Subject: [PATCH 09/11] Fixed Angular components on Docs paged rendered Story twice --- .../src/client/angular-beta/AbstractRenderer.ts | 10 ++++------ .../angular/src/client/angular-beta/RendererFactory.ts | 7 ++++--- code/ui/blocks/src/components/Story.tsx | 1 + 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/code/frameworks/angular/src/client/angular-beta/AbstractRenderer.ts b/code/frameworks/angular/src/client/angular-beta/AbstractRenderer.ts index 8caee3001496..5716c9464ddb 100644 --- a/code/frameworks/angular/src/client/angular-beta/AbstractRenderer.ts +++ b/code/frameworks/angular/src/client/angular-beta/AbstractRenderer.ts @@ -93,7 +93,7 @@ export abstract class AbstractRenderer { parameters: Parameters; targetDOMNode: HTMLElement; }) { - const targetSelector = `${this.generateTargetSelectorFromStoryId()}`; + const targetSelector = this.generateTargetSelectorFromStoryId(targetDOMNode.id); const newStoryProps$ = new BehaviorSubject(storyFnAngular.props); @@ -142,12 +142,10 @@ export abstract class AbstractRenderer { * @protected * @memberof AbstractRenderer */ - protected generateTargetSelectorFromStoryId() { + protected generateTargetSelectorFromStoryId(id: string) { const invalidHtmlTag = /[^A-Za-z0-9-]/g; - const storyIdIsInvalidHtmlTagName = invalidHtmlTag.test(this.storyId); - return storyIdIsInvalidHtmlTagName - ? `sb-${this.storyId.replace(invalidHtmlTag, '')}-component` - : this.storyId; + const storyIdIsInvalidHtmlTagName = invalidHtmlTag.test(id); + return storyIdIsInvalidHtmlTagName ? `sb-${id.replace(invalidHtmlTag, '')}-component` : id; } protected initAngularRootElement(targetDOMNode: HTMLElement, targetSelector: string) { diff --git a/code/frameworks/angular/src/client/angular-beta/RendererFactory.ts b/code/frameworks/angular/src/client/angular-beta/RendererFactory.ts index 9ae768c57c29..3bf703d83d07 100644 --- a/code/frameworks/angular/src/client/angular-beta/RendererFactory.ts +++ b/code/frameworks/angular/src/client/angular-beta/RendererFactory.ts @@ -12,6 +12,7 @@ export class RendererFactory { storyId: string, targetDOMNode: HTMLElement ): Promise { + const targetId = targetDOMNode.id; // do nothing if the target node is null // fix a problem when the docs asks 2 times the same component at the same time // the 1st targetDOMNode of the 1st requested rendering becomes null 🤷‍♂️ @@ -27,12 +28,12 @@ export class RendererFactory { this.rendererMap.clear(); } - if (!this.rendererMap.has(storyId)) { - this.rendererMap.set(storyId, this.buildRenderer(storyId, renderType)); + if (!this.rendererMap.has(targetId)) { + this.rendererMap.set(targetId, this.buildRenderer(storyId, renderType)); } this.lastRenderType = renderType; - return this.rendererMap.get(storyId); + return this.rendererMap.get(targetId); } private buildRenderer(storyId: string, renderType: RenderType) { diff --git a/code/ui/blocks/src/components/Story.tsx b/code/ui/blocks/src/components/Story.tsx index c2e97dca3d38..78153eae5ef5 100644 --- a/code/ui/blocks/src/components/Story.tsx +++ b/code/ui/blocks/src/components/Story.tsx @@ -64,6 +64,7 @@ const InlineStory: FunctionComponent = (props) => { {showLoader && }
Date: Thu, 19 Jan 2023 13:03:14 +1100 Subject: [PATCH 10/11] Fix typing --- code/ui/blocks/src/components/Story.stories.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/code/ui/blocks/src/components/Story.stories.tsx b/code/ui/blocks/src/components/Story.stories.tsx index 50b85097e681..899355063100 100644 --- a/code/ui/blocks/src/components/Story.stories.tsx +++ b/code/ui/blocks/src/components/Story.stories.tsx @@ -4,6 +4,7 @@ import { within } from '@storybook/testing-library'; import type { PlayFunctionContext } from '@storybook/csf'; import type { WebRenderer, ModuleExport } from '@storybook/types'; import { RESET_STORY_ARGS, STORY_ARGS_UPDATED, UPDATE_STORY_ARGS } from '@storybook/core-events'; +import { global as globalThis } from '@storybook/global'; import type { StoryProps } from './Story'; import { Story as StoryComponent, StorySkeleton } from './Story'; From 621fa3c79c3ceefc7e17bfff5b5115ea9d26e570 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Thu, 19 Jan 2023 13:17:47 +1100 Subject: [PATCH 11/11] Still trying to fix typing --- code/ui/blocks/src/components/Story.stories.tsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/code/ui/blocks/src/components/Story.stories.tsx b/code/ui/blocks/src/components/Story.stories.tsx index 899355063100..ec80ff650d3c 100644 --- a/code/ui/blocks/src/components/Story.stories.tsx +++ b/code/ui/blocks/src/components/Story.stories.tsx @@ -1,10 +1,11 @@ import React from 'react'; -import type { Meta, StoryObj } from '@storybook/react'; +import type { Meta, ReactRenderer, StoryObj } from '@storybook/react'; import { within } from '@storybook/testing-library'; import type { PlayFunctionContext } from '@storybook/csf'; import type { WebRenderer, ModuleExport } from '@storybook/types'; import { RESET_STORY_ARGS, STORY_ARGS_UPDATED, UPDATE_STORY_ARGS } from '@storybook/core-events'; -import { global as globalThis } from '@storybook/global'; +import type { PreviewWeb } from '@storybook/preview-api'; +import type { Channel } from '@storybook/channels'; import type { StoryProps } from './Story'; import { Story as StoryComponent, StorySkeleton } from './Story'; @@ -12,7 +13,8 @@ import type { DocsContextProps } from '../blocks'; import * as ButtonStories from '../examples/Button.stories'; // eslint-disable-next-line no-underscore-dangle -const preview = (window as any).__STORYBOOK_PREVIEW__; +const preview = (window as any).__STORYBOOK_PREVIEW__ as PreviewWeb; +const channel = (window as any).__STORYBOOK_ADDONS_CHANNEL__ as Channel; const renderStoryToElement = preview.renderStoryToElement.bind(preview); type ExtendedStoryProps = Omit & { @@ -76,7 +78,6 @@ export const ForceInitialArgs = { const resolved = docsContext.resolveModuleExport(args.storyExport); if (resolved.type !== 'story') throw new Error('Bad export, pass a story!'); - const channel = globalThis.__STORYBOOK_ADDONS_CHANNEL__; await within(canvasElement).findByText(/Button/); const updatedPromise = new Promise((resolve) => {