diff --git a/code/ui/blocks/src/blocks/Stories.stories.tsx b/code/ui/blocks/src/blocks/Stories.stories.tsx index 0c91aec638e6..a430c98fc3f7 100644 --- a/code/ui/blocks/src/blocks/Stories.stories.tsx +++ b/code/ui/blocks/src/blocks/Stories.stories.tsx @@ -1,10 +1,26 @@ import type { Meta, StoryObj } from '@storybook/react'; import { Stories } from './Stories'; +import * as DefaultButtonStories from '../examples/Button.stories'; +import * as ParameterStories from '../examples/StoriesParameters.stories'; +import * as ButtonSomeAutodocs from '../examples/ButtonSomeAutodocs.stories'; +import * as ButtonNoAutodocs from '../examples/ButtonNoAutodocs.stories'; -const meta = { +const meta: Meta = { component: Stories, - parameters: { docsStyles: true }, -} satisfies Meta; + parameters: { + relativeCsfPaths: [ + '../examples/Button.stories', + '../examples/StoriesParameters.stories', + '../examples/ButtonSomeAutodocs.stories', + '../examples/ButtonNoAutodocs.stories', + ], + // workaround for https://github.com/storybookjs/storybook/issues/20505 + docs: { + source: { type: 'code' }, + }, + docsStyles: true, + }, +}; export default meta; @@ -15,8 +31,8 @@ export const Default: Story = { relativeCsfPaths: ['../examples/Button.stories'], }, }; -export const WithoutPrimary: Story = { - args: { includePrimary: false }, +export const WithoutPrimaryStory: Story = { + args: { includePrimaryStory: false }, parameters: { relativeCsfPaths: ['../examples/Button.stories'], }, @@ -36,3 +52,67 @@ export const SomeAutodocs: Story = { relativeCsfPaths: ['../examples/ButtonSomeAutodocs.stories'], }, }; +export const DefaultWithOf: Story = { + name: 'Default with Of', + args: { + of: DefaultButtonStories, + }, + parameters: { + relativeCsfPaths: ['../examples/Button.stories'], + }, +}; +export const WithoutPrimaryStoryWithOf: Story = { + name: 'Without Primary Story with Of', + args: { + includePrimaryStory: false, + of: DefaultButtonStories, + }, + parameters: { + relativeCsfPaths: ['../examples/Button.stories'], + }, +}; +export const DifferentToolbarsWithOf: Story = { + name: 'Different Toolbars with Of', + args: { + of: ParameterStories, + }, + parameters: { + relativeCsfPaths: ['../examples/StoriesParameters.stories'], + }, +}; +export const DifferentTitleWithOf: Story = { + name: 'Different Title with Of', + args: { + title: 'Different Title', + of: ParameterStories, + }, + parameters: { + relativeCsfPaths: ['../examples/StoriesParameters.stories'], + }, +}; +export const NoAutodocsWithOf: Story = { + args: { + of: ButtonNoAutodocs, + }, + parameters: { + relativeCsfPaths: ['../examples/ButtonNoAutodocs.stories'], + }, +}; +export const SomeAutodocsWithOf: Story = { + args: { + of: ButtonSomeAutodocs, + }, + parameters: { + relativeCsfPaths: ['../examples/ButtonSomeAutodocs.stories'], + }, +}; +export const DefaultAttached: Story = { + parameters: { relativeCsfPaths: ['../examples/Button.stories'], attached: true }, +}; +export const OfStringMetaAttached: Story = { + name: 'Of "meta" Attached', + args: { + of: 'meta', + }, + parameters: { relativeCsfPaths: ['../examples/Button.stories'], attached: true }, +}; diff --git a/code/ui/blocks/src/blocks/Stories.tsx b/code/ui/blocks/src/blocks/Stories.tsx index c2b5c53dc729..573c8f08967c 100644 --- a/code/ui/blocks/src/blocks/Stories.tsx +++ b/code/ui/blocks/src/blocks/Stories.tsx @@ -4,10 +4,16 @@ import { styled } from '@storybook/theming'; import { DocsContext } from './DocsContext'; import { DocsStory } from './DocsStory'; import { Heading } from './Heading'; +import type { Of } from './useOf'; +import { useOf } from './useOf'; interface StoriesProps { title?: ReactElement | string; - includePrimary?: boolean; + includePrimaryStory?: boolean; + /** + * Specify where to get the stories from. + */ + of?: Of; } const StyledHeading: typeof Heading = styled(Heading)(({ theme }) => ({ @@ -26,7 +32,14 @@ const StyledHeading: typeof Heading = styled(Heading)(({ theme }) => ({ }, })); -export const Stories: FC = ({ title = 'Stories', includePrimary = true }) => { +export const Stories: FC = ( + props = { title: 'Stories', includePrimaryStory: true } +) => { + const { of } = props; + + if ('of' in props && of === undefined) { + throw new Error('Unexpected `of={undefined}`, did you mistype a CSF file reference?'); + } const { componentStories, projectAnnotations, getStoryContext } = useContext(DocsContext); let stories = componentStories(); @@ -46,7 +59,13 @@ export const Stories: FC = ({ title = 'Stories', includePrimary = stories = stories.filter((story) => story.tags?.includes('autodocs')); } - if (!includePrimary) stories = stories.slice(1); + const { preparedMeta } = useOf(of || 'meta', ['meta']); + + const title = props.title ?? preparedMeta.parameters.docs?.stories?.title; + const includePrimaryStory = + props.includePrimaryStory ?? preparedMeta.parameters.docs?.stories?.includePrimaryStory; + + if (!includePrimaryStory) stories = stories.slice(1); if (!stories || stories.length === 0) { return null; diff --git a/code/ui/blocks/src/examples/Button.stories.tsx b/code/ui/blocks/src/examples/Button.stories.tsx index a49f88f5d8f8..53cd9b160904 100644 --- a/code/ui/blocks/src/examples/Button.stories.tsx +++ b/code/ui/blocks/src/examples/Button.stories.tsx @@ -18,6 +18,10 @@ const meta = { info: 'This is info for the Button stories', jsx: { useBooleanShorthandSyntax: false }, docs: { + stories: { + title: 'Stories', + includePrimaryStory: true, + }, subtitle: 'This is the subtitle for the Button stories', }, }, diff --git a/code/ui/blocks/src/examples/ButtonNoAutodocs.stories.tsx b/code/ui/blocks/src/examples/ButtonNoAutodocs.stories.tsx index c934e70753f2..c66c65e9abcb 100644 --- a/code/ui/blocks/src/examples/ButtonNoAutodocs.stories.tsx +++ b/code/ui/blocks/src/examples/ButtonNoAutodocs.stories.tsx @@ -9,6 +9,12 @@ const meta = { }, parameters: { chromatic: { disable: true }, + docs: { + stories: { + title: 'Stories', + includePrimaryStory: true, + }, + }, }, } satisfies Meta; diff --git a/code/ui/blocks/src/examples/ButtonSomeAutodocs.stories.tsx b/code/ui/blocks/src/examples/ButtonSomeAutodocs.stories.tsx index dd5f7d227f49..06868f671f67 100644 --- a/code/ui/blocks/src/examples/ButtonSomeAutodocs.stories.tsx +++ b/code/ui/blocks/src/examples/ButtonSomeAutodocs.stories.tsx @@ -9,6 +9,12 @@ const meta = { }, parameters: { chromatic: { disable: true }, + docs: { + stories: { + title: 'Stories', + includePrimaryStory: true, + }, + }, }, } satisfies Meta; diff --git a/code/ui/blocks/src/examples/StoriesParameters.stories.tsx b/code/ui/blocks/src/examples/StoriesParameters.stories.tsx index 731291ad75f7..9eabe5f6865e 100644 --- a/code/ui/blocks/src/examples/StoriesParameters.stories.tsx +++ b/code/ui/blocks/src/examples/StoriesParameters.stories.tsx @@ -5,6 +5,14 @@ import { EmptyExample } from './EmptyExample'; const meta = { title: 'examples/Stories for the Stories and Primary Block', component: EmptyExample, + parameters: { + docs: { + stories: { + title: 'Title Parameter', + includePrimaryStory: true, + }, + }, + }, } satisfies Meta; export default meta; diff --git a/docs/api/doc-block-stories.md b/docs/api/doc-block-stories.md index b20a3496ae61..0cca8e2a16fb 100644 --- a/docs/api/doc-block-stories.md +++ b/docs/api/doc-block-stories.md @@ -29,24 +29,30 @@ import { Stories } from '@storybook/blocks'; `Stories` is configured with the following props: -### `includePrimary` +### `includePrimaryStory` Type: `boolean` -Default: `true` +Default: `parameters.docs.stories.includePrimaryStory` Determines if the collection of stories includes the primary (first) story. -If a stories file contains only one story and `includePrimary={true}`, the `Stories` block will render nothing to avoid a potentially confusing situation. +If a stories file contains only one story and `includePrimaryStory={true}`, the `Stories` block will render nothing to avoid a potentially confusing situation. +### `of` + +Type: CSF file exports + +Specifies which meta's stories are displayed. + ### `title` Type: `string` -Default: `'Stories'` +Default: `parameters.docs.stories.title` Sets the heading content preceding the collection of stories.