Skip to content
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

Blocks: Add of prop to Subtitle #22552

Merged
merged 18 commits into from
Apr 22, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
- [Source block](#source-block)
- [Canvas block](#canvas-block)
- [ArgsTable block](#argstable-block)
- [Subtitle block and `parameters.componentSubtitle`](#subtitle-block-and-parameterscomponentsubtitle)
- [Configuring Autodocs](#configuring-autodocs)
- [MDX2 upgrade](#mdx2-upgrade)
- [Legacy MDX1 support](#legacy-mdx1-support)
Expand Down Expand Up @@ -1328,6 +1329,7 @@ We've renamed many of the parameters that control docs rendering for consistency
- `docs.inlineStories` has been renamed `docs.story.inline`
- `docs.iframeHeight` has been renamed `docs.story.iframeHeight`
- `notes` and `info` are no longer supported, instead use `docs.description.story | component`
- `componentSubtitle` is no longer supported, instead use `docs.subtitle`

#### MDX docs files

Expand Down Expand Up @@ -1488,6 +1490,12 @@ The following props are not supported in the new blocks:
- `story="^"` to reference the primary story (just omit `of` in that case, for `Controls`).
- `story="."` to reference the current story (this no longer makes sense in Docs 2).
- `story="name"` to reference a story (use `of={}`).
-
##### Subtitle block and `parameters.componentSubtitle`

The `Subtitle` block now accepts an `of` prop, which can be a reference to a CSF file or a default export (meta).

`parameters.componentSubtitle` has been deprecated to be consistent with other parameters related to autodocs, instead use `parameters.docs.subtitle`.

#### Configuring Autodocs

Expand Down
104 changes: 104 additions & 0 deletions code/ui/blocks/src/blocks/Subtitle.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import type { Meta, StoryObj } from '@storybook/react';
import React from 'react';
import { Subtitle } from './Subtitle';
import * as DefaultButtonStories from '../examples/Button.stories';
import * as ButtonStoriesWithMetaSubtitleInBoth from '../examples/ButtonWithMetaSubtitleInBoth.stories';
import * as ButtonStoriesWithMetaSubtitleInComponentSubtitle from '../examples/ButtonWithMetaSubtitleInComponentSubtitle.stories';
import * as ButtonStoriesWithMetaSubtitleInDocsSubtitle from '../examples/ButtonWithMetaSubtitleInDocsSubtitle.stories';

const meta: Meta<typeof Subtitle> = {
component: Subtitle,
parameters: {
controls: {
include: [],
hideNoControlsWarning: true,
},
// workaround for https://github.com/storybookjs/storybook/issues/20505
docs: { source: { type: 'code' } },
attached: false,
docsStyles: true,
},
};
export default meta;

type Story = StoryObj<typeof meta>;

export const OfCSFFileInBoth: Story = {
args: {
of: ButtonStoriesWithMetaSubtitleInBoth,
},
parameters: {
relativeCsfPaths: ['../examples/ButtonWithMetaSubtitleInBoth.stories'],
},
};
export const OfCSFFileInComponentSubtitle: Story = {
name: 'Of CSF File In parameters.componentSubtitle',
args: {
of: ButtonStoriesWithMetaSubtitleInComponentSubtitle,
},
parameters: {
relativeCsfPaths: ['../examples/ButtonWithMetaSubtitleInComponentSubtitle.stories'],
},
};
export const OfCSFFileInDocsSubtitle: Story = {
name: 'Of CSF File In parameters.docs.subtitle',
args: {
of: ButtonStoriesWithMetaSubtitleInDocsSubtitle,
},
parameters: {
relativeCsfPaths: ['../examples/ButtonWithMetaSubtitleInDocsSubtitle.stories'],
},
};
export const OfMetaInBoth: Story = {
args: {
of: ButtonStoriesWithMetaSubtitleInBoth.default,
},
parameters: {
relativeCsfPaths: ['../examples/ButtonWithMetaSubtitleInBoth.stories'],
},
};
export const OfMetaInComponentSubtitle: Story = {
name: 'Of Meta In parameters.componentSubtitle',
args: {
of: ButtonStoriesWithMetaSubtitleInComponentSubtitle.default,
},
parameters: {
relativeCsfPaths: ['../examples/ButtonWithMetaSubtitleInComponentSubtitle.stories'],
},
};
export const OfMetaInDocsSubtitle: Story = {
name: 'Of Meta In parameters.docs.subtitle',
args: {
of: ButtonStoriesWithMetaSubtitleInDocsSubtitle.default,
},
parameters: {
relativeCsfPaths: ['../examples/ButtonWithMetaSubtitleInDocsSubtitle.stories'],
},
};
export const DefaultAttached: Story = {
parameters: { relativeCsfPaths: ['../examples/Button.stories'], attached: true },
};
export const OfUndefinedAttached: Story = {
args: {
// @ts-expect-error this is supposed to be undefined
// eslint-disable-next-line import/namespace
of: DefaultButtonStories.NotDefined,
},
parameters: {
chromatic: { disableSnapshot: true },
relativeCsfPaths: ['../examples/Button.stories'],
attached: true,
},
decorators: [(s) => (window?.navigator.userAgent.match(/StorybookTestRunner/) ? <div /> : s())],
};
export const OfStringMetaAttached: Story = {
name: 'Of "meta" Attached',
args: {
of: 'meta',
},
parameters: { relativeCsfPaths: ['../examples/Button.stories'], attached: true },
};
export const Children: Story = {
parameters: { relativeCsfPaths: ['../examples/Button.stories'], attached: true },
render: () => <Subtitle>This subtitle is set inside the Subtitle element.</Subtitle>,
};
36 changes: 30 additions & 6 deletions code/ui/blocks/src/blocks/Subtitle.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,40 @@
import type { FunctionComponent, ReactNode } from 'react';
import React, { useContext } from 'react';
import React from 'react';
import { deprecate } from '@storybook/client-logger';

import { Subtitle as PureSubtitle } from '../components';
import { DocsContext } from './DocsContext';
import type { Of } from './useOf';
import { useOf } from './useOf';

interface SubtitleProps {
children?: ReactNode;
/**
* Specify where to get the subtitle from.
* If not specified, the subtitle will be extracted from the meta of the attached CSF file.
*/
of?: Of;
}

export const Subtitle: FunctionComponent<SubtitleProps> = ({ children }) => {
const docsContext = useContext(DocsContext);
const { parameters } = docsContext.storyById();
const content = children || parameters?.componentSubtitle;
const DEPRECATION_MIGRATION_LINK =
'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#subtitle-block-and-parameterscomponentsubtitle';

export const Subtitle: FunctionComponent<SubtitleProps> = (props) => {
const { of, children } = props;

if ('of' in props && of === undefined) {
throw new Error('Unexpected `of={undefined}`, did you mistype a CSF file reference?');
}

const { preparedMeta } = useOf(of || 'meta', ['meta']);
const { componentSubtitle, docs } = preparedMeta.parameters || {};

if (componentSubtitle) {
deprecate(
`Using 'parameters.componentSubtitle' property to subtitle stories is deprecated. See ${DEPRECATION_MIGRATION_LINK}`
);
}

const content = children || docs?.subtitle || componentSubtitle;

return content ? (
<PureSubtitle className="sbdocs-subtitle sb-unstyled">{content}</PureSubtitle>
Expand Down
3 changes: 3 additions & 0 deletions code/ui/blocks/src/examples/Button.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ const meta = {
notes: 'These are notes for the Button stories',
info: 'This is info for the Button stories',
jsx: { useBooleanShorthandSyntax: false },
docs: {
subtitle: 'This is the subtitle for the Button stories',
},
},
} satisfies Meta<typeof Button>;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';

const meta = {
title: 'examples/Button with Meta Subtitle in Both',
component: Button,
argTypes: {
backgroundColor: { control: 'color' },
},
parameters: {
// Stop *this* story from being stacked in Chromatic
theme: 'default',
// this is to test the deprecated features of the Subtitle block
componentSubtitle: 'This subtitle is set in parameters.componentSubtitle',
docs: {
subtitle: 'This subtitle is set in parameters.docs.subtitle',
},
},
} satisfies Meta<typeof Button>;

export default meta;
type Story = StoryObj<typeof meta>;

export const WithMetaSubtitleInBoth: Story = {
args: {
primary: true,
label: 'Button',
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';

const meta = {
title: 'examples/Button with Meta Subtitle in componentSubtitle',
component: Button,
argTypes: {
backgroundColor: { control: 'color' },
},
parameters: {
// Stop *this* story from being stacked in Chromatic
theme: 'default',
// this is to test the deprecated features of the Subtitle block
componentSubtitle: 'This subtitle is set in parameters.componentSubtitle',
},
} satisfies Meta<typeof Button>;

export default meta;
type Story = StoryObj<typeof meta>;

export const WithMetaSubtitleInComponentSubtitle: Story = {
args: {
primary: true,
label: 'Button',
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';

const meta = {
title: 'examples/Button with Meta Subtitle in docs.subtitle',
component: Button,
argTypes: {
backgroundColor: { control: 'color' },
},
parameters: {
// Stop *this* story from being stacked in Chromatic
theme: 'default',
docs: {
subtitle: 'This subtitle is set in parameters.docs.subtitle',
},
},
} satisfies Meta<typeof Button>;

export default meta;
type Story = StoryObj<typeof meta>;

export const WithMetaSubtitleInDocsSubtitle: Story = {
args: {
primary: true,
label: 'Button',
},
};
2 changes: 1 addition & 1 deletion code/ui/blocks/src/examples/EmptyExample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import React from 'react';
// eslint-disable-next-line no-empty-pattern
export const EmptyExample = ({}) => (
<div>
This component is not intended to render anything, it simply serves a something to hang
This component is not intended to render anything, it simply serves as something to hang
parameters off
</div>
);
8 changes: 7 additions & 1 deletion docs/api/doc-block-subtitle.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,16 @@ import { Subtitle } from '@storybook/blocks';

`Subtitle` is configured with the following props:

### `of`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for updating the API reference! ❤️

Could you please keep these props in alphabetical order?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorted :)


Type: CSF file exports

Specifies which meta's subtitle is displayed.

### `children`

Type: `JSX.Element | string`

Default: `parameters.componentSubtitle`
Default: `parameters.docs.subtitle`

Provides the content.