Add of prop and deprecate componentSubtitle

This commit is contained in:
João Nuno Mota 2023-05-15 02:25:06 +01:00
parent 84b1609cdd
commit 764c819a38
8 changed files with 235 additions and 8 deletions

View File

@ -71,6 +71,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)
@ -1333,7 +1334,7 @@ Additionally to changing the docs information architecture, we've updated the AP
- When you've attached to a CSF file (with the `Meta` block, or in Autodocs), you can drop the `of` and the block will reference the first story or the CSF file as a whole.
- Most other props controlling rendering of blocks now correspond precisely to the parameters for that block [defined for autodocs above](#autodocs-changes).
- Most other props controlling rendering of blocks now correspond precisely to the parameters for that block [defined for autodocs above](#autodocsautodocs-changes).
##### Meta block
@ -1449,6 +1450,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

View File

@ -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>,
};

View File

@ -1,16 +1,41 @@
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#description-block-parameters';
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 { parameters } = preparedMeta;
const { componentSubtitle, docs } = 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>

View File

@ -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>;

View File

@ -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',
},
};

View File

@ -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',
},
};

View File

@ -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',
},
};

View File

@ -24,10 +24,16 @@ import { Subtitle } from '@storybook/blocks';
`Subtitle` is configured with the following props:
### `of`
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.