-
-
Notifications
You must be signed in to change notification settings - Fork 9.8k
React: Fix several CSF factory bugs #33354
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
56aa06d
28ea8b0
c59a0a2
e0c73db
f817405
365c71d
02804b5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -49,16 +49,16 @@ export function processCSFFile<TRenderer extends Renderer>( | |
| ): CSFFile<TRenderer> { | ||
| const { default: defaultExport, __namedExportsOrder, ...namedExports } = moduleExports; | ||
|
|
||
| const firstStory = Object.values(namedExports)[0]; | ||
| if (isStory<TRenderer>(firstStory)) { | ||
| const factoryStory = Object.values(namedExports).find((it) => isStory<TRenderer>(it)); | ||
| if (factoryStory) { | ||
| const meta: NormalizedComponentAnnotations<TRenderer> = | ||
| normalizeComponentAnnotations<TRenderer>(firstStory.meta.input, title, importPath); | ||
| normalizeComponentAnnotations<TRenderer>(factoryStory.meta.input, title, importPath); | ||
| checkDisallowedParameters(meta.parameters); | ||
|
|
||
| const csfFile: CSFFile<TRenderer> = { meta, stories: {}, moduleExports }; | ||
|
|
||
| Object.keys(namedExports).forEach((key) => { | ||
| if (isExportStory(key, meta)) { | ||
| if (isExportStory(key, meta) && isStory<TRenderer>(namedExports[key])) { | ||
|
||
| const story: Story<TRenderer> = namedExports[key]; | ||
|
|
||
| const storyMeta = normalizeStory(key, story.input as any, meta); | ||
|
|
@@ -82,7 +82,7 @@ export function processCSFFile<TRenderer extends Renderer>( | |
| } | ||
| }); | ||
|
|
||
| csfFile.projectAnnotations = firstStory.meta.preview.composed; | ||
| csfFile.projectAnnotations = factoryStory.meta.preview.composed; | ||
|
|
||
| return csfFile; | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -77,7 +77,7 @@ describe('Args can be provided in multiple ways', () => { | |||||
| args: { label: 'good' }, | ||||||
| }); | ||||||
| // @ts-expect-error disabled not provided ❌ | ||||||
| const Basic = meta.story({}); | ||||||
| const Basic = meta.story(); | ||||||
|
||||||
| const Basic = meta.story(); | |
| meta.story(); |
Copilot
AI
Dec 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused variable ExtendedInteractionsStory.
| const ExtendedInteractionsStory = meta.story({ | |
| meta.story({ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -38,6 +38,7 @@ export function __definePreview<Addons extends PreviewAddon<never>[]>( | |
| preview.meta = (_input) => { | ||
| const meta = defineMeta(_input); | ||
| const defineStory = meta.story.bind(meta); | ||
| // @ts-expect-error internal code that is hard to type | ||
| meta.story = (__input: any) => { | ||
| const story = defineStory(__input); | ||
| // TODO: [test-syntax] Are we sure we want this? the Component construct was for | ||
|
|
@@ -52,6 +53,12 @@ export function __definePreview<Addons extends PreviewAddon<never>[]>( | |
| return preview; | ||
| } | ||
|
|
||
| type InferArgs< | ||
| TArgs extends Args, | ||
| T extends AddonTypes, | ||
| Decorators extends DecoratorFunction<ReactTypes & T, any>, | ||
| > = Simplify<TArgs & Simplify<RemoveIndexSignature<DecoratorsArgs<ReactTypes & T, Decorators>>>>; | ||
|
|
||
| /** @ts-expect-error We cannot implement the meta faithfully here, but that is okay. */ | ||
| export interface ReactPreview<T extends AddonTypes> extends Preview<ReactTypes & T> { | ||
| meta< | ||
|
|
@@ -70,13 +77,13 @@ export interface ReactPreview<T extends AddonTypes> extends Preview<ReactTypes & | |
| 'decorators' | 'component' | 'args' | 'render' | ||
| > | ||
| ): ReactMeta< | ||
| ReactTypes & | ||
| T & { | ||
| args: Simplify< | ||
| TArgs & Simplify<RemoveIndexSignature<DecoratorsArgs<ReactTypes & T, Decorators>>> | ||
| >; | ||
| }, | ||
| { args: Partial<TArgs> extends TMetaArgs ? {} : TMetaArgs } | ||
| ReactTypes & T & { args: InferArgs<TArgs, T, Decorators> }, | ||
| Omit< | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add a comment explaining what's going on? |
||
| ComponentAnnotations<ReactTypes & T & { args: InferArgs<TArgs, T, Decorators> }>, | ||
| 'args' | ||
| > & { | ||
| args: Partial<TArgs> extends TMetaArgs ? {} : TMetaArgs; | ||
| } | ||
| >; | ||
| } | ||
|
|
||
|
|
@@ -95,7 +102,7 @@ export interface ReactMeta<T extends ReactTypes, MetaInput extends ComponentAnno | |
| render: () => ReactTypes['storyResult']; | ||
| }), | ||
| >( | ||
| story?: TInput | ||
| story: TInput | ||
| ): ReactStory<T, TInput extends () => ReactTypes['storyResult'] ? { render: TInput } : TInput>; | ||
|
|
||
| story< | ||
|
|
@@ -108,9 +115,19 @@ export interface ReactMeta<T extends ReactTypes, MetaInput extends ComponentAnno | |
| > | ||
| >, | ||
| >( | ||
| story?: TInput | ||
| story: TInput | ||
| /** @ts-expect-error hard */ | ||
| ): ReactStory<T, TInput>; | ||
|
|
||
| // This overload matches meta.story(), but only when all args are optional | ||
| story( | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add a comment here to explain what's going on? |
||
| ..._args: Partial<T['args']> extends SetOptional< | ||
| T['args'], | ||
| keyof T['args'] & keyof MetaInput['args'] | ||
| > | ||
| ? [] | ||
| : [never] | ||
| ): ReactStory<T, {}>; | ||
| } | ||
|
|
||
| export interface ReactStory<T extends ReactTypes, TInput extends StoryAnnotations<T, T['args']>> | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The change from
Object.values(namedExports)[0]toObject.values(namedExports).find((it) => isStory<TRenderer>(it))is a bug fix that ensures the code finds an actual story export rather than assuming the first export is a story. However, there appears to be no test coverage for this scenario inprocessCSFFile.test.ts. Consider adding a test case where the first named export is not a story (e.g., a helper function or constant) to verify this fix works correctly.