Skip to content

Commit

Permalink
Merge pull request #22552 from joaonunomota/subtitle-of-prop
Browse files Browse the repository at this point in the history
Blocks: Add support for `of` prop to `Subtitle`
  • Loading branch information
JReinhold committed Apr 22, 2024
2 parents 3c33b3c + 1c204ea commit 2bff7a1
Show file tree
Hide file tree
Showing 9 changed files with 249 additions and 19 deletions.
34 changes: 22 additions & 12 deletions MIGRATION.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<h1>Migration</h1>

- [From version 8.0 to 8.1.0](#from-version-80-to-810)
- [Subtitle block and `parameters.componentSubtitle`](#subtitle-block-and-parameterscomponentsubtitle)
- [From version 7.x to 8.0.0](#from-version-7x-to-800)
- [Portable stories](#portable-stories)
- [Project annotations are now merged instead of overwritten in composeStory](#project-annotations-are-now-merged-instead-of-overwritten-in-composestory)
Expand Down Expand Up @@ -90,17 +92,17 @@
- [Tab addons cannot manually route, Tool addons can filter their visibility via tabId](#tab-addons-cannot-manually-route-tool-addons-can-filter-their-visibility-via-tabid)
- [Removed `config` preset](#removed-config-preset-1)
- [From version 7.5.0 to 7.6.0](#from-version-750-to-760)
- [CommonJS with Vite is deprecated](#commonjs-with-vite-is-deprecated)
- [Using implicit actions during rendering is deprecated](#using-implicit-actions-during-rendering-is-deprecated)
- [typescript.skipBabel deprecated](#typescriptskipbabel-deprecated)
- [Primary doc block accepts of prop](#primary-doc-block-accepts-of-prop)
- [Addons no longer need a peer dependency on React](#addons-no-longer-need-a-peer-dependency-on-react)
- [CommonJS with Vite is deprecated](#commonjs-with-vite-is-deprecated)
- [Using implicit actions during rendering is deprecated](#using-implicit-actions-during-rendering-is-deprecated)
- [typescript.skipBabel deprecated](#typescriptskipbabel-deprecated)
- [Primary doc block accepts of prop](#primary-doc-block-accepts-of-prop)
- [Addons no longer need a peer dependency on React](#addons-no-longer-need-a-peer-dependency-on-react)
- [From version 7.4.0 to 7.5.0](#from-version-740-to-750)
- [`storyStoreV6` and `storiesOf` is deprecated](#storystorev6-and-storiesof-is-deprecated)
- [`storyIndexers` is replaced with `experimental_indexers`](#storyindexers-is-replaced-with-experimental_indexers)
- [`storyStoreV6` and `storiesOf` is deprecated](#storystorev6-and-storiesof-is-deprecated)
- [`storyIndexers` is replaced with `experimental_indexers`](#storyindexers-is-replaced-with-experimental_indexers)
- [From version 7.0.0 to 7.2.0](#from-version-700-to-720)
- [Addon API is more type-strict](#addon-api-is-more-type-strict)
- [Addon-controls hideNoControlsWarning parameter is deprecated](#addon-controls-hidenocontrolswarning-parameter-is-deprecated)
- [Addon API is more type-strict](#addon-api-is-more-type-strict)
- [Addon-controls hideNoControlsWarning parameter is deprecated](#addon-controls-hidenocontrolswarning-parameter-is-deprecated)
- [From version 6.5.x to 7.0.0](#from-version-65x-to-700)
- [7.0 breaking changes](#70-breaking-changes)
- [Dropped support for Node 15 and below](#dropped-support-for-node-15-and-below)
Expand All @@ -126,7 +128,7 @@
- [Deploying build artifacts](#deploying-build-artifacts)
- [Dropped support for file URLs](#dropped-support-for-file-urls)
- [Serving with nginx](#serving-with-nginx)
- [Ignore story files from node_modules](#ignore-story-files-from-node_modules)
- [Ignore story files from node\_modules](#ignore-story-files-from-node_modules)
- [7.0 Core changes](#70-core-changes)
- [7.0 feature flags removed](#70-feature-flags-removed)
- [Story context is prepared before for supporting fine grained updates](#story-context-is-prepared-before-for-supporting-fine-grained-updates)
Expand All @@ -140,7 +142,7 @@
- [Addon-interactions: Interactions debugger is now default](#addon-interactions-interactions-debugger-is-now-default)
- [7.0 Vite changes](#70-vite-changes)
- [Vite builder uses Vite config automatically](#vite-builder-uses-vite-config-automatically)
- [Vite cache moved to node_modules/.cache/.vite-storybook](#vite-cache-moved-to-node_modulescachevite-storybook)
- [Vite cache moved to node\_modules/.cache/.vite-storybook](#vite-cache-moved-to-node_modulescachevite-storybook)
- [7.0 Webpack changes](#70-webpack-changes)
- [Webpack4 support discontinued](#webpack4-support-discontinued)
- [Babel mode v7 exclusively](#babel-mode-v7-exclusively)
Expand Down Expand Up @@ -190,7 +192,7 @@
- [Dropped addon-docs manual babel configuration](#dropped-addon-docs-manual-babel-configuration)
- [Dropped addon-docs manual configuration](#dropped-addon-docs-manual-configuration)
- [Autoplay in docs](#autoplay-in-docs)
- [Removed STORYBOOK_REACT_CLASSES global](#removed-storybook_react_classes-global)
- [Removed STORYBOOK\_REACT\_CLASSES global](#removed-storybook_react_classes-global)
- [7.0 Deprecations and default changes](#70-deprecations-and-default-changes)
- [storyStoreV7 enabled by default](#storystorev7-enabled-by-default)
- [`Story` type deprecated](#story-type-deprecated)
Expand Down Expand Up @@ -403,6 +405,14 @@
- [Packages renaming](#packages-renaming)
- [Deprecated embedded addons](#deprecated-embedded-addons)

## From version 8.0 to 8.1.0

### 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`.

## From version 7.x to 8.0.0

### Portable stories
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 ButtonStoriesWithMetaSubtitleAsBoth from '../examples/ButtonWithMetaSubtitleAsBoth.stories';
import * as ButtonStoriesWithMetaSubtitleAsComponentSubtitle from '../examples/ButtonWithMetaSubtitleAsComponentSubtitle.stories';
import * as ButtonStoriesWithMetaSubtitleAsDocsSubtitle from '../examples/ButtonWithMetaSubtitleAsDocsSubtitle.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 OfCSFFileAsBoth: Story = {
args: {
of: ButtonStoriesWithMetaSubtitleAsBoth,
},
parameters: {
relativeCsfPaths: ['../examples/ButtonWithMetaSubtitleAsBoth.stories'],
},
};
export const OfCSFFileAsComponentSubtitle: Story = {
name: 'Of CSF File As parameters.componentSubtitle',
args: {
of: ButtonStoriesWithMetaSubtitleAsComponentSubtitle,
},
parameters: {
relativeCsfPaths: ['../examples/ButtonWithMetaSubtitleAsComponentSubtitle.stories'],
},
};
export const OfCSFFileAsDocsSubtitle: Story = {
name: 'Of CSF File As parameters.docs.subtitle',
args: {
of: ButtonStoriesWithMetaSubtitleAsDocsSubtitle,
},
parameters: {
relativeCsfPaths: ['../examples/ButtonWithMetaSubtitleAsDocsSubtitle.stories'],
},
};
export const OfMetaAsBoth: Story = {
args: {
of: ButtonStoriesWithMetaSubtitleAsBoth.default,
},
parameters: {
relativeCsfPaths: ['../examples/ButtonWithMetaSubtitleAsBoth.stories'],
},
};
export const OfMetaAsComponentSubtitle: Story = {
name: 'Of Meta As parameters.componentSubtitle',
args: {
of: ButtonStoriesWithMetaSubtitleAsComponentSubtitle.default,
},
parameters: {
relativeCsfPaths: ['../examples/ButtonWithMetaSubtitleAsComponentSubtitle.stories'],
},
};
export const OfMetaAsDocsSubtitle: Story = {
name: 'Of Meta As parameters.docs.subtitle',
args: {
of: ButtonStoriesWithMetaSubtitleAsDocsSubtitle.default,
},
parameters: {
relativeCsfPaths: ['../examples/ButtonWithMetaSubtitleAsDocsSubtitle.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 a string passed as a children</Subtitle>,
};
35 changes: 30 additions & 5 deletions code/ui/blocks/src/blocks/Subtitle.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +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 content = children || docsContext.storyById().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 @@ -17,6 +17,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 WithMetaSubtitleAsBoth: 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 @@ -2,7 +2,7 @@ import React from 'react';

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 @@ -30,6 +30,12 @@ import { Subtitle } from '@storybook/blocks';

Type: `JSX.Element | string`

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

Provides the content.

### `of`

Type: CSF file exports

Specifies which meta's subtitle is displayed.

0 comments on commit 2bff7a1

Please sign in to comment.