Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
18 changes: 18 additions & 0 deletions MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@
- [Description Doc block properties](#description-doc-block-properties)
- [Story Doc block properties](#story-doc-block-properties)
- [Manager API expandAll and collapseAll methods](#manager-api-expandall-and-collapseall-methods)
- [Source Doc block properties](#source-doc-block-properties)
- [Canvas Doc block properties](#canvas-doc-block-properties)
- [`Primary` Doc block properties](#primary-doc-block-properties)
- [`createChannel` from `@storybook/postmessage` and `@storybook/channel-websocket`](#createchannel-from-storybookpostmessage-and--storybookchannel-websocket)
- [From version 7.5.0 to 7.6.0](#from-version-750-to-760)
Expand Down Expand Up @@ -950,6 +952,22 @@ api.collapseAll() // becomes api.emit(STORIES_COLLAPSE_ALL)
api.expandAll() // becomes api.emit(STORIES_EXPAND_ALL)
```

#### Source Doc block properties

`id` and `ids` are now removed in favor of the `of` property. [More info](#doc-blocks).

#### Canvas Doc block properties

The following properties were removed from the Canvas Doc block:

- children
- isColumn
- columns
- withSource
- mdxSource

[More info](#doc-blocks).

#### `Primary` Doc block properties

The `name` prop is now removed in favor of the `of` property. [More info](#doc-blocks).
Expand Down
163 changes: 10 additions & 153 deletions code/ui/blocks/src/blocks/Canvas.tsx
Original file line number Diff line number Diff line change
@@ -1,47 +1,17 @@
/* eslint-disable react/destructuring-assignment */
import React, { Children, useContext } from 'react';
import type { FC, ReactElement, ReactNode } from 'react';
import type { ModuleExport, ModuleExports, PreparedStory, Renderer } from '@storybook/types';
import { deprecate } from '@storybook/client-logger';
import dedent from 'ts-dedent';
import React, { useContext } from 'react';
import type { FC } from 'react';
import type { ModuleExport, ModuleExports } from '@storybook/types';
import type { Layout, PreviewProps as PurePreviewProps } from '../components';
import { Preview as PurePreview, PreviewSkeleton } from '../components';
import type { DocsContextProps } from './DocsContext';
import { Preview as PurePreview } from '../components';
import { DocsContext } from './DocsContext';
import type { SourceContextProps } from './SourceContainer';
import { SourceContext } from './SourceContainer';
import type { SourceProps } from './Source';
import { useSourceProps, SourceState as DeprecatedSourceState, SourceState } from './Source';
import { useStories } from './useStory';
import { useSourceProps } from './Source';
import type { StoryProps } from './Story';
import { getStoryId, Story } from './Story';
import { Story } from './Story';
import { useOf } from './useOf';

export { DeprecatedSourceState as SourceState };

type DeprecatedCanvasProps = {
/**
* @deprecated multiple stories are not supported
*/
isColumn?: boolean;
/**
* @deprecated multiple stories are not supported
*/
columns?: number;
/**
* @deprecated use `sourceState` instead
*/
withSource?: DeprecatedSourceState;
/**
* @deprecated use `source.code` instead
*/
mdxSource?: string;
/**
* @deprecated reference stories with the `of` prop instead
*/
children?: ReactNode;
};

type CanvasProps = Pick<PurePreviewProps, 'withToolbar' | 'additionalActions' | 'className'> & {
/**
* Pass the export defining a story to render that story
Expand Down Expand Up @@ -92,129 +62,16 @@ type CanvasProps = Pick<PurePreviewProps, 'withToolbar' | 'additionalActions' |
story?: Pick<StoryProps, 'inline' | 'height' | 'autoplay' | '__forceInitialArgs' | '__primary'>;
};

const useDeprecatedPreviewProps = (
{
withSource,
mdxSource,
children,
layout: layoutProp,
...props
}: DeprecatedCanvasProps & { of?: ModuleExport; layout?: Layout },
docsContext: DocsContextProps<Renderer>,
sourceContext: SourceContextProps
) => {
/*
get all story IDs by traversing through the children,
filter out any non-story children (e.g. text nodes)
and then get the id from each story depending on available props
*/
const storyIds = (Children.toArray(children) as ReactElement[])
.filter((c) => c.props && (c.props.id || c.props.name || c.props.of))
.map((c) => getStoryId(c.props, docsContext));

const stories = useStories(storyIds, docsContext);
const isLoading = stories.some((s) => !s);
const sourceProps = useSourceProps(
{
...(mdxSource ? { code: decodeURI(mdxSource) } : { ids: storyIds }),
...(props.of && { of: props.of }),
},
docsContext,
sourceContext
);
if (withSource === SourceState.NONE) {
return { isLoading, previewProps: props };
}

// if the user has specified a layout prop, use that...
let layout = layoutProp;
// ...otherwise, try to infer it from the story parameters
stories.forEach((story) => {
if (layout || !story) {
return;
}
layout = story?.parameters.layout ?? story.parameters.docs?.canvas?.layout;
});

return {
isLoading,
previewProps: {
...props, // pass through columns etc.
layout: layout ?? 'padded',
withSource: sourceProps,
isExpanded: (withSource || sourceProps.state) === SourceState.OPEN,
},
};
};

export const Canvas: FC<CanvasProps & DeprecatedCanvasProps> = (props) => {
export const Canvas: FC<CanvasProps> = (props) => {
const docsContext = useContext(DocsContext);
const sourceContext = useContext(SourceContext);
const { children, of, source } = props;
const { of, source } = props;
if ('of' in props && of === undefined) {
throw new Error('Unexpected `of={undefined}`, did you mistype a CSF file reference?');
}

const { isLoading, previewProps } = useDeprecatedPreviewProps(props, docsContext, sourceContext);

let story: PreparedStory;
let sourceProps;
/**
* useOf and useSourceProps will throw if they can't find the story, in the scenario where
* the doc is unattached (no primary story) and 'of' is undefined.
* That scenario is valid in the deprecated API, where children is used as story refs rather than 'of'.
* So if children is passed we allow the error to be swallowed and we'll use them instead.
* We use two separate try blocks and throw the error afterwards to not break the rules of hooks.
*/
let hookError;
try {
({ story } = useOf(of || 'story', ['story']));
} catch (error) {
if (!children) {
hookError = error;
}
}
try {
sourceProps = useSourceProps({ ...source, ...(of && { of }) }, docsContext, sourceContext);
} catch (error) {
if (!children) {
hookError = error;
}
}
if (hookError) {
// eslint-disable-next-line @typescript-eslint/no-throw-literal
throw hookError;
}

if (props.withSource) {
deprecate(dedent`Setting source state with \`withSource\` is deprecated, please use \`sourceState\` with 'hidden', 'shown' or 'none' instead.

Please refer to the migration guide: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#canvas-block
`);
}
if (props.mdxSource) {
deprecate(dedent`Setting source code with \`mdxSource\` is deprecated, please use source={{code: '...'}} instead.

Please refer to the migration guide: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#canvas-block
`);
}
if (props.isColumn !== undefined || props.columns !== undefined) {
deprecate(dedent`\`isColumn\` and \`columns\` props are deprecated as the Canvas block now only supports showing a single story.

Please refer to the migration guide: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#canvas-block
`);
}
if (children) {
deprecate(dedent`Passing children to Canvas is deprecated, please use the \`of\` prop instead to reference a story.

Please refer to the migration guide: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#canvas-block
`);
return isLoading ? (
<PreviewSkeleton />
) : (
<PurePreview {...previewProps}>{children}</PurePreview>
);
}
const { story } = useOf(of || 'story', ['story']);
const sourceProps = useSourceProps({ ...source, ...(of && { of }) }, docsContext, sourceContext);

const layout =
props.layout ?? story.parameters.layout ?? story.parameters.docs?.canvas?.layout ?? 'padded';
Expand Down
Loading