diff --git a/code/frameworks/angular/src/client/docs/sourceDecorator.ts b/code/frameworks/angular/src/client/docs/sourceDecorator.ts index e86df2a05835..8a80008cbfee 100644 --- a/code/frameworks/angular/src/client/docs/sourceDecorator.ts +++ b/code/frameworks/angular/src/client/docs/sourceDecorator.ts @@ -38,8 +38,8 @@ export const sourceDecorator = ( useEffect(() => { if (toEmit) { - const { id, args } = context; - channel.emit(SNIPPET_RENDERED, { id, args, source: toEmit, format: 'angular' }); + const { id, unmappedArgs } = context; + channel.emit(SNIPPET_RENDERED, { id, args: unmappedArgs, source: toEmit, format: 'angular' }); } }); diff --git a/code/lib/preview-api/src/modules/preview-web/PreviewWithSelection.tsx b/code/lib/preview-api/src/modules/preview-web/PreviewWithSelection.tsx index 269d05bf1e39..01f8172ad18c 100644 --- a/code/lib/preview-api/src/modules/preview-web/PreviewWithSelection.tsx +++ b/code/lib/preview-api/src/modules/preview-web/PreviewWithSelection.tsx @@ -380,7 +380,7 @@ export class PreviewWithSelection extends Preview extends Preview extends Preview { 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(), - prepareContext: jest.fn((ctx) => ctx), - }; - - 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 5602bbc4313d..b50489ecb785 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 @@ -136,7 +136,8 @@ export class StoryRender implements Render implements Render implements Render - prepareContext({ - ...this.storyContext(), - ...(this.renderOptions.forceInitialArgs && { args: initialArgs }), - } as StoryContext); - let loadedContext: Awaited>; await this.runPhase(abortSignal, 'loading', async () => { loadedContext = await applyLoaders({ - ...getCurrentContext(), + ...this.storyContext(), viewMode: this.viewMode, } as StoryContextForLoaders); }); @@ -197,7 +182,7 @@ export class StoryRender implements Render ({ + ...jest.requireActual('./csf/prepareStory'), prepareStory: jest.fn(jest.requireActual('./csf/prepareStory').prepareStory), })); jest.mock('./csf/processCSFFile', () => ({ @@ -425,6 +426,20 @@ describe('StoryStore', () => { }); }); + it('can force initial args', async () => { + const store = new StoryStore(); + store.setProjectAnnotations(projectAnnotations); + store.initialize({ storyIndex, importFn, cache: false }); + + const story = await store.loadStory({ storyId: 'component-one--a' }); + + store.args.update(story.id, { foo: 'bar' }); + + expect(store.getStoryContext(story, { forceInitialArgs: true })).toMatchObject({ + args: { foo: 'a' }, + }); + }); + it('returns the same hooks each time', async () => { const store = new StoryStore(); store.setProjectAnnotations(projectAnnotations); @@ -735,7 +750,6 @@ describe('StoryStore', () => { "fileName": "./src/ComponentOne.stories.js", }, "playFunction": undefined, - "prepareContext": [Function], "story": "A", "storyFn": [Function], "subcomponents": undefined, @@ -781,7 +795,6 @@ describe('StoryStore', () => { "fileName": "./src/ComponentOne.stories.js", }, "playFunction": undefined, - "prepareContext": [Function], "story": "B", "storyFn": [Function], "subcomponents": undefined, @@ -827,7 +840,6 @@ describe('StoryStore', () => { "fileName": "./src/ComponentTwo.stories.js", }, "playFunction": undefined, - "prepareContext": [Function], "story": "C", "storyFn": [Function], "subcomponents": undefined, diff --git a/code/lib/preview-api/src/modules/store/StoryStore.ts b/code/lib/preview-api/src/modules/store/StoryStore.ts index 9a6fbf4543f1..1fc0fa547d2a 100644 --- a/code/lib/preview-api/src/modules/store/StoryStore.ts +++ b/code/lib/preview-api/src/modules/store/StoryStore.ts @@ -30,7 +30,13 @@ import { HooksContext } from '../addons'; import { StoryIndexStore } from './StoryIndexStore'; import { ArgsStore } from './ArgsStore'; import { GlobalsStore } from './GlobalsStore'; -import { processCSFFile, prepareStory, prepareMeta, normalizeProjectAnnotations } from './csf'; +import { + processCSFFile, + prepareStory, + prepareMeta, + normalizeProjectAnnotations, + prepareContext, +} from './csf'; const CSF_CACHE_SIZE = 1000; const STORY_CACHE_SIZE = 10000; @@ -276,16 +282,17 @@ export class StoryStore { // A prepared story does not include args, globals or hooks. These are stored in the story store // and updated separtely to the (immutable) story. getStoryContext( - story: PreparedStory - ): Omit, 'viewMode'> { + story: PreparedStory, + { forceInitialArgs = false } = {} + ): Omit { if (!this.globals) throw new Error(`getStoryContext called before initialization`); - return { + return prepareContext({ ...story, - args: this.args.get(story.id), + args: forceInitialArgs ? story.initialArgs : this.args.get(story.id), globals: this.globals.get(), hooks: this.hooks[story.id] as unknown, - }; + }); } cleanupStory(story: PreparedStory): void { diff --git a/code/lib/preview-api/src/modules/store/args.test.ts b/code/lib/preview-api/src/modules/store/args.test.ts index e134129acaed..f567d54cbe5e 100644 --- a/code/lib/preview-api/src/modules/store/args.test.ts +++ b/code/lib/preview-api/src/modules/store/args.test.ts @@ -276,8 +276,12 @@ describe('groupArgsByTarget', () => { it('groups targeted args', () => { const groups = groupArgsByTarget({ args: { a: 1, b: 2, c: 3 }, - argTypes: { a: { target: 'group1' }, b: { target: 'group2' }, c: { target: 'group2' } }, - } as any); + argTypes: { + a: { name: 'a', target: 'group1' }, + b: { name: 'b', target: 'group2' }, + c: { name: 'c', target: 'group2' }, + }, + }); expect(groups).toEqual({ group1: { a: 1, @@ -292,8 +296,8 @@ describe('groupArgsByTarget', () => { it('groups non-targetted args into a group with no name', () => { const groups = groupArgsByTarget({ args: { a: 1, b: 2, c: 3 }, - argTypes: { b: { name: 'b', target: 'group2' }, c: {} }, - } as any); + argTypes: { a: { name: 'a' }, b: { name: 'b', target: 'group2' }, c: { name: 'c' } }, + }); expect(groups).toEqual({ [UNTARGETED]: { a: 1, diff --git a/code/lib/preview-api/src/modules/store/args.ts b/code/lib/preview-api/src/modules/store/args.ts index 4dcccb6261a8..2634015bce76 100644 --- a/code/lib/preview-api/src/modules/store/args.ts +++ b/code/lib/preview-api/src/modules/store/args.ts @@ -148,7 +148,7 @@ export const UNTARGETED = 'UNTARGETED'; export function groupArgsByTarget({ args, argTypes, -}: StoryContext) { +}: Pick, 'args' | 'argTypes'>) { const groupedArgs: Record> = {}; (Object.entries(args) as [keyof TArgs, any][]).forEach(([name, value]) => { const { target = UNTARGETED } = (argTypes[name] || {}) as { target?: string }; @@ -159,6 +159,8 @@ export function groupArgsByTarget({ return groupedArgs; } -export function noTargetArgs(context: StoryContext) { +export function noTargetArgs( + context: Pick, 'args' | 'argTypes'> +) { return groupArgsByTarget(context)[UNTARGETED]; } diff --git a/code/lib/preview-api/src/modules/store/csf/prepareStory.test.ts b/code/lib/preview-api/src/modules/store/csf/prepareStory.test.ts index 9ce02ca343a0..a7cb1d971e6d 100644 --- a/code/lib/preview-api/src/modules/store/csf/prepareStory.test.ts +++ b/code/lib/preview-api/src/modules/store/csf/prepareStory.test.ts @@ -6,7 +6,7 @@ import type { Renderer, ArgsEnhancer, PlayFunctionContext, SBScalarType } from ' import { addons, HooksContext } from '../../addons'; import { UNTARGETED } from '../args'; -import { prepareStory, prepareMeta } from './prepareStory'; +import { prepareStory, prepareMeta, prepareContext } from './prepareStory'; jest.mock('@storybook/global', () => ({ global: { @@ -24,6 +24,15 @@ const stringType: SBScalarType = { name: 'string' }; const numberType: SBScalarType = { name: 'number' }; const booleanType: SBScalarType = { name: 'boolean' }; +// Extra fields that must be added to the story context after enhancers +const storyContextExtras = () => ({ + hooks: new HooksContext(), + viewMode: 'story' as const, + loaded: {}, + abortSignal: new AbortController().signal, + canvasElement: {}, +}); + describe('prepareStory', () => { describe('tags', () => { it('story tags override component', () => { @@ -403,8 +412,8 @@ describe('prepareStory', () => { { render: renderMock } ); - const context = story.prepareContext({ args: story.initialArgs, ...story } as any); - story.undecoratedStoryFn(context); + const context = prepareContext({ args: story.initialArgs, globals: {}, ...story }); + story.undecoratedStoryFn({ ...context, ...storyContextExtras() }); expect(renderMock).toHaveBeenCalledWith( { one: 'mapped', two: 2, three: 3 }, expect.objectContaining({ args: { one: 'mapped', two: 2, three: 3 } }) @@ -499,12 +508,12 @@ describe('prepareStory', () => { ); const hooks = new HooksContext(); - const context = story.prepareContext({ args: story.initialArgs, hooks, ...story } as any); - story.unboundStoryFn(context); + const context = prepareContext({ args: story.initialArgs, globals: {}, ...story }); + story.unboundStoryFn({ ...context, ...storyContextExtras(), hooks }); - expect(ctx1).toMatchObject({ args: { one: 'mapped-1' } }); - expect(ctx2).toMatchObject({ args: { one: 'mapped-1' } }); - expect(ctx3).toMatchObject({ args: { one: 'mapped-1' } }); + expect(ctx1).toMatchObject({ unmappedArgs: { one: 1 }, args: { one: 'mapped-1' } }); + expect(ctx2).toMatchObject({ unmappedArgs: { one: 1 }, args: { one: 'mapped-1' } }); + expect(ctx3).toMatchObject({ unmappedArgs: { one: 1 }, args: { one: 'mapped-1' } }); hooks.clean(); }); @@ -525,7 +534,7 @@ describe('prepareStory', () => { { render: jest.fn() } ); - const context = story.prepareContext({ args: { one: 1 }, ...story } as any); + const context = prepareContext({ args: { one: 1 }, globals: {}, ...story }); expect(context).toMatchObject({ args: { one: 'mapped-1' }, }); @@ -545,10 +554,11 @@ describe('prepareStory', () => { { render: jest.fn() } ); - const context = story.prepareContext({ + const context = prepareContext({ args: { one: [1, 1] }, + globals: {}, ...story, - } as any); + }); expect(context).toMatchObject({ args: { one: ['mapped-1', 'mapped-1'] }, }); @@ -573,12 +583,8 @@ describe('prepareStory', () => { { render: renderMock } ); - const context = firstStory.prepareContext({ - args: firstStory.initialArgs, - hooks: new HooksContext(), - ...firstStory, - } as any); - firstStory.unboundStoryFn(context); + const context = prepareContext({ args: firstStory.initialArgs, globals: {}, ...firstStory }); + firstStory.unboundStoryFn({ ...context, ...storyContextExtras() }); expect(renderMock).toHaveBeenCalledWith( { a: 1 }, expect.objectContaining({ args: { a: 1 }, allArgs: { a: 1, b: 2 } }) @@ -599,12 +605,8 @@ describe('prepareStory', () => { { render: renderMock } ); - const context = firstStory.prepareContext({ - args: firstStory.initialArgs, - hooks: new HooksContext(), - ...firstStory, - } as any); - firstStory.unboundStoryFn(context); + const context = prepareContext({ args: firstStory.initialArgs, globals: {}, ...firstStory }); + firstStory.unboundStoryFn({ ...context, ...storyContextExtras() }); expect(renderMock).toHaveBeenCalledWith( { a: 1 }, expect.objectContaining({ args: { a: 1 }, allArgs: { a: 1, b: 2 } }) @@ -625,12 +627,8 @@ describe('prepareStory', () => { { render: renderMock } ); - const context = firstStory.prepareContext({ - args: firstStory.initialArgs, - hooks: new HooksContext(), - ...firstStory, - } as any); - firstStory.unboundStoryFn(context); + const context = prepareContext({ args: firstStory.initialArgs, globals: {}, ...firstStory }); + firstStory.unboundStoryFn({ ...context, ...storyContextExtras() }); expect(renderMock).toHaveBeenCalledWith( { a: 1 }, expect.objectContaining({ argsByTarget: { [UNTARGETED]: { a: 1 }, foo: { b: 2 } } }) @@ -651,12 +649,8 @@ describe('prepareStory', () => { { render: renderMock } ); - const context = firstStory.prepareContext({ - args: firstStory.initialArgs, - hooks: new HooksContext(), - ...firstStory, - } as any); - firstStory.unboundStoryFn(context); + const context = prepareContext({ args: firstStory.initialArgs, globals: {}, ...firstStory }); + firstStory.unboundStoryFn({ ...context, ...storyContextExtras() }); expect(renderMock).toHaveBeenCalledWith( {}, expect.objectContaining({ argsByTarget: { foo: { b: 2 } } }) @@ -675,12 +669,8 @@ describe('prepareStory', () => { { render: renderMock } ); - const context = firstStory.prepareContext({ - args: firstStory.initialArgs, - hooks: new HooksContext(), - ...firstStory, - } as any); - firstStory.unboundStoryFn(context); + const context = prepareContext({ args: firstStory.initialArgs, globals: {}, ...firstStory }); + firstStory.unboundStoryFn({ ...context, ...storyContextExtras() }); expect(renderMock).toHaveBeenCalledWith({}, expect.objectContaining({ argsByTarget: {} })); }); }); @@ -768,7 +758,6 @@ describe('prepareMeta', () => { unboundStoryFn, undecoratedStoryFn, playFunction, - prepareContext, // eslint-disable-next-line @typescript-eslint/naming-convention parameters: { __isArgsStory, ...parameters }, ...expectedPreparedMeta diff --git a/code/lib/preview-api/src/modules/store/csf/prepareStory.ts b/code/lib/preview-api/src/modules/store/csf/prepareStory.ts index b73a27eb0d96..e4bfb1937114 100644 --- a/code/lib/preview-api/src/modules/store/csf/prepareStory.ts +++ b/code/lib/preview-api/src/modules/store/csf/prepareStory.ts @@ -87,49 +87,6 @@ export function prepareStory( const decoratedStoryFn = applyHooks(applyDecorators)(undecoratedStoryFn, decorators); const unboundStoryFn = (context: StoryContext) => decoratedStoryFn(context); - // prepareContext is invoked at StoryRender.render() - // the context is prepared before invoking the render function, instead of here directly - // to ensure args don't loose there special properties set by the renderer - // eg. reactive proxies set by frameworks like SolidJS or Vue - const prepareContext = (context: StoryContext) => { - let finalContext: StoryContext = context; - - if (global.FEATURES?.argTypeTargetsV7) { - const argsByTarget = groupArgsByTarget(context); - finalContext = { - ...context, - allArgs: context.args, - argsByTarget, - args: argsByTarget[UNTARGETED] || {}, - }; - } - - const mappedArgs = Object.entries(finalContext.args).reduce((acc, [key, val]) => { - if (!finalContext.argTypes[key]?.mapping) { - acc[key] = val; - - return acc; - } - - const mappingFn = (originalValue: any) => - originalValue in finalContext.argTypes[key].mapping - ? finalContext.argTypes[key].mapping[originalValue] - : originalValue; - - acc[key] = Array.isArray(val) ? val.map(mappingFn) : mappingFn(val); - - return acc; - }, {} as Args); - - const includedArgs = Object.entries(mappedArgs).reduce((acc, [key, val]) => { - const argType = finalContext.argTypes[key] || {}; - if (includeConditionalArg(argType, mappedArgs, finalContext.globals)) acc[key] = val; - return acc; - }, {} as Args); - - return { ...finalContext, args: includedArgs }; - }; - const play = storyAnnotations?.play || componentAnnotations.play; const playFunction = @@ -156,7 +113,6 @@ export function prepareStory( unboundStoryFn, applyLoaders, playFunction, - prepareContext, }; } @@ -258,3 +214,56 @@ function preparePartialAnnotations( return withoutStoryIdentifiers; } + +// the context is prepared before invoking the render function, instead of here directly +// to ensure args don't loose there special properties set by the renderer +// eg. reactive proxies set by frameworks like SolidJS or Vue +export function prepareContext< + TRenderer extends Renderer, + TContext extends Pick, 'args' | 'argTypes' | 'globals'> +>( + context: TContext +): TContext & Pick, 'allArgs' | 'argsByTarget' | 'unmappedArgs'> { + const { args: unmappedArgs } = context; + + let targetedContext: TContext & + Pick, 'allArgs' | 'argsByTarget'> = { + ...context, + allArgs: undefined, + argsByTarget: undefined, + }; + if (global.FEATURES?.argTypeTargetsV7) { + const argsByTarget = groupArgsByTarget(context); + targetedContext = { + ...context, + allArgs: context.args, + argsByTarget, + args: argsByTarget[UNTARGETED] || {}, + }; + } + + const mappedArgs = Object.entries(targetedContext.args).reduce((acc, [key, val]) => { + if (!targetedContext.argTypes[key]?.mapping) { + acc[key] = val; + + return acc; + } + + const mappingFn = (originalValue: any) => + originalValue in targetedContext.argTypes[key].mapping + ? targetedContext.argTypes[key].mapping[originalValue] + : originalValue; + + acc[key] = Array.isArray(val) ? val.map(mappingFn) : mappingFn(val); + + return acc; + }, {} as Args); + + const includedArgs = Object.entries(mappedArgs).reduce((acc, [key, val]) => { + const argType = targetedContext.argTypes[key] || {}; + if (includeConditionalArg(argType, mappedArgs, targetedContext.globals)) acc[key] = val; + return acc; + }, {} as Args); + + return { ...targetedContext, unmappedArgs, args: includedArgs }; +} diff --git a/code/lib/preview-api/src/modules/store/csf/testing-utils/index.ts b/code/lib/preview-api/src/modules/store/csf/testing-utils/index.ts index 13cf81424441..9b5ff0a6edb0 100644 --- a/code/lib/preview-api/src/modules/store/csf/testing-utils/index.ts +++ b/code/lib/preview-api/src/modules/store/csf/testing-utils/index.ts @@ -15,7 +15,7 @@ import type { import { HooksContext } from '../../../addons'; import { composeConfigs } from '../composeConfigs'; -import { prepareStory } from '../prepareStory'; +import { prepareContext, prepareStory } from '../prepareStory'; import { normalizeStory } from '../normalizeStory'; import { normalizeComponentAnnotations } from '../normalizeComponentAnnotations'; import { getValuesFromArgTypes } from '../getValuesFromArgTypes'; @@ -81,7 +81,7 @@ export function composeStory = context: StoryContextForLoaders ) => Promise & { loaded: StoryContext['loaded'] }>; playFunction?: (context: StoryContext) => Promise | void; - prepareContext: (context: StoryContext) => StoryContext; }; export type PreparedMeta = Omit< diff --git a/code/renderers/html/src/docs/sourceDecorator.test.ts b/code/renderers/html/src/docs/sourceDecorator.test.ts index 84407727e8fe..22550ab8050f 100644 --- a/code/renderers/html/src/docs/sourceDecorator.test.ts +++ b/code/renderers/html/src/docs/sourceDecorator.test.ts @@ -15,6 +15,7 @@ expect.addSnapshotSerializer({ const tick = () => new Promise((r) => setTimeout(r, 0)); const makeContext = (name: string, parameters: any, args: any, extra?: object): StoryContext => + // @ts-expect-error haven't added unmapped args to StoryContext yet ({ id: `html-test--${name}`, kind: 'js-text', @@ -23,6 +24,7 @@ const makeContext = (name: string, parameters: any, args: any, extra?: object): componentId: '', title: '', story: '', + unmappedArgs: args, args, argTypes: {}, globals: {}, diff --git a/code/renderers/html/src/docs/sourceDecorator.ts b/code/renderers/html/src/docs/sourceDecorator.ts index 73680d2cf117..da1160fdc4f7 100644 --- a/code/renderers/html/src/docs/sourceDecorator.ts +++ b/code/renderers/html/src/docs/sourceDecorator.ts @@ -37,8 +37,8 @@ export function sourceDecorator(storyFn: PartialStoryFn, context: } } useEffect(() => { - const { id, args } = context; - if (source) addons.getChannel().emit(SNIPPET_RENDERED, { id, args, source }); + const { id, unmappedArgs } = context; + if (source) addons.getChannel().emit(SNIPPET_RENDERED, { id, args: unmappedArgs, source }); }); return story; diff --git a/code/renderers/react/src/docs/jsxDecorator.test.tsx b/code/renderers/react/src/docs/jsxDecorator.test.tsx index 0309b0ba62a6..63fe5fb217b5 100644 --- a/code/renderers/react/src/docs/jsxDecorator.test.tsx +++ b/code/renderers/react/src/docs/jsxDecorator.test.tsx @@ -183,6 +183,7 @@ const makeContext = (name: string, parameters: any, args: any, extra?: object): kind: 'js-text', name, parameters, + unmappedArgs: args, args, ...extra, }); diff --git a/code/renderers/react/src/docs/jsxDecorator.tsx b/code/renderers/react/src/docs/jsxDecorator.tsx index a74bcc19d2c4..d2df67445a17 100644 --- a/code/renderers/react/src/docs/jsxDecorator.tsx +++ b/code/renderers/react/src/docs/jsxDecorator.tsx @@ -175,11 +175,11 @@ export const jsxDecorator = ( useEffect(() => { if (!skip) { - const { id, args } = context; + const { id, unmappedArgs } = context; channel.emit(SNIPPET_RENDERED, { id, source: jsx, - args, + args: unmappedArgs, }); } }); diff --git a/code/renderers/svelte/src/docs/sourceDecorator.ts b/code/renderers/svelte/src/docs/sourceDecorator.ts index efc3852255b1..9f16caf80162 100644 --- a/code/renderers/svelte/src/docs/sourceDecorator.ts +++ b/code/renderers/svelte/src/docs/sourceDecorator.ts @@ -157,8 +157,8 @@ export const sourceDecorator = (storyFn: any, context: StoryContext) = useEffect(() => { if (!skip && source) { - const { id, args } = context; - channel.emit(SNIPPET_RENDERED, { id, args, source }); + const { id, unmappedArgs } = context; + channel.emit(SNIPPET_RENDERED, { id, args: unmappedArgs, source }); } }); diff --git a/code/renderers/vue/src/docs/sourceDecorator.ts b/code/renderers/vue/src/docs/sourceDecorator.ts index 8d64ffbb217b..24c4fe3c4ddb 100644 --- a/code/renderers/vue/src/docs/sourceDecorator.ts +++ b/code/renderers/vue/src/docs/sourceDecorator.ts @@ -54,10 +54,10 @@ export const sourceDecorator = (storyFn: any, context: StoryContext) => { // @ts-expect-error TS says it is called $vnode const code = vnodeToString(storyNode._vnode); - const { id, args } = context; + const { id, unmappedArgs } = context; channel.emit(SNIPPET_RENDERED, { id, - args, + args: unmappedArgs, source: ``, format: 'vue', }); diff --git a/code/renderers/vue3/src/docs/sourceDecorator.ts b/code/renderers/vue3/src/docs/sourceDecorator.ts index ac2536218a24..4331324b796a 100644 --- a/code/renderers/vue3/src/docs/sourceDecorator.ts +++ b/code/renderers/vue3/src/docs/sourceDecorator.ts @@ -289,8 +289,8 @@ export const sourceDecorator = (storyFn: any, context: StoryContext) = useEffect(() => { if (!skip && source) { - const { id, args } = context; - channel.emit(SNIPPET_RENDERED, { id, args, source, format: 'vue' }); + const { id, unmappedArgs } = context; + channel.emit(SNIPPET_RENDERED, { id, args: unmappedArgs, source, format: 'vue' }); } }); diff --git a/code/renderers/web-components/src/docs/sourceDecorator.test.ts b/code/renderers/web-components/src/docs/sourceDecorator.test.ts index 4b1d5fc8f2f3..57990d4c193d 100644 --- a/code/renderers/web-components/src/docs/sourceDecorator.test.ts +++ b/code/renderers/web-components/src/docs/sourceDecorator.test.ts @@ -22,6 +22,7 @@ const makeContext = (name: string, parameters: any, args: any, extra?: Partial { - const { id, args } = context; - if (source) addons.getChannel().emit(SNIPPET_RENDERED, { id, source, args }); + const { id, unmappedArgs } = context; + if (source) addons.getChannel().emit(SNIPPET_RENDERED, { id, source, args: unmappedArgs }); }); if (!skipSourceRender(context)) { const container = window.document.createElement('div'); diff --git a/code/ui/blocks/src/blocks/Source.tsx b/code/ui/blocks/src/blocks/Source.tsx index 177caefc0aca..30b279d1e9af 100644 --- a/code/ui/blocks/src/blocks/Source.tsx +++ b/code/ui/blocks/src/blocks/Source.tsx @@ -19,7 +19,6 @@ import type { SourceContextProps, SourceItem } from './SourceContainer'; import { UNKNOWN_ARGS_HASH, argsHash, SourceContext } from './SourceContainer'; import { useStories } from './useStory'; -import { useArgsList } from './useArgs'; export enum SourceState { OPEN = 'open', @@ -186,8 +185,6 @@ export const useSourceProps = ( // You are allowed to use and unattached. } } - const argsFromStories = useArgsList(stories, docsContext); - if (!storiesFromIds.every(Boolean)) { return { error: SourceError.SOURCE_UNAVAILABLE, state: SourceState.NONE }; } @@ -204,12 +201,12 @@ export const useSourceProps = ( // In theory you can use a storyId from a different CSF file that hasn't loaded yet. if (!story) return ''; - // NOTE: args *does* have to be defined here due to the null check on story above - const [args] = argsFromStories[index] || []; const storyContext = docsContext.getStoryContext(story); // eslint-disable-next-line no-underscore-dangle - const argsForSource = props.__forceInitialArgs ? storyContext.initialArgs : args; + const argsForSource = props.__forceInitialArgs + ? storyContext.initialArgs + : storyContext.unmappedArgs; const source = getStorySource(story.id, argsForSource, sourceContext); if (index === 0) { diff --git a/code/ui/blocks/src/blocks/useArgs.ts b/code/ui/blocks/src/blocks/useArgs.ts index 76dc8a021ae9..bc95fd52c501 100644 --- a/code/ui/blocks/src/blocks/useArgs.ts +++ b/code/ui/blocks/src/blocks/useArgs.ts @@ -1,5 +1,5 @@ import { useCallback, useEffect, useState } from 'react'; -import type { Args, DocsContextProps, PreparedStory, Renderer } from '@storybook/types'; +import type { Args, DocsContextProps, PreparedStory } from '@storybook/types'; import { STORY_ARGS_UPDATED, UPDATE_STORY_ARGS, RESET_STORY_ARGS } from '@storybook/core-events'; export const useArgs = ( @@ -38,10 +38,3 @@ export const useArgsIfDefined = ( ); return story && [args, updateArgs, resetArgs]; }; - -export function useArgsList( - stories: (PreparedStory | void)[], - context: DocsContextProps -) { - return stories.map((story) => useArgsIfDefined(story, context)); -}