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: Support subcomponents in ArgTypes and Controls, remove ArgsTable block #25614

Merged
merged 13 commits into from
Jan 18, 2024
Merged
15 changes: 11 additions & 4 deletions MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,9 @@
- [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)
- [`ArgsTable` Doc block removed](#argstable-doc-block-removed)
- [`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)
- [StoryStore and methods deprecated](#storystore-and-methods-deprecated)
Expand Down Expand Up @@ -995,11 +996,17 @@ api.collapseAll(); // becomes api.emit(STORIES_COLLAPSE_ALL)
api.expandAll(); // becomes api.emit(STORIES_EXPAND_ALL)
```

#### Source Doc block properties
#### `ArgsTable` Doc block removed

The `ArgsTable` doc block have now been removed in favor of `ArgTypes` and `Controls`. [More info](#argstable-block).
JReinhold marked this conversation as resolved.
Show resolved Hide resolved

With this removal we've reintroduced `subcomponents` support to `ArgTypes`, `Controls` and in autodocs by popular demand.
JReinhold marked this conversation as resolved.
Show resolved Hide resolved

#### `Source` Doc block properties

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

#### Canvas Doc block properties
#### `Canvas` Doc block properties

The following properties were removed from the Canvas Doc block:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { global as globalThis } from '@storybook/global';

export default {
component: globalThis.Components.Button,
// FIXME: remove array subcomponents in 7.0?
subcomponents: {
Pre: globalThis.Components.Pre,
},
Expand Down
13 changes: 1 addition & 12 deletions code/lib/preview-api/src/modules/store/csf/processCSFFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ import type {
NormalizedComponentAnnotations,
} from '@storybook/types';
import { isExportStory } from '@storybook/csf';
import { deprecate, logger } from '@storybook/client-logger';
import { logger } from '@storybook/client-logger';

import dedent from 'ts-dedent';
import { normalizeStory } from './normalizeStory';
import { normalizeComponentAnnotations } from './normalizeComponentAnnotations';

Expand Down Expand Up @@ -39,15 +38,6 @@ const checkDisallowedParameters = (parameters?: Parameters) => {
checkStorySort(parameters);
};

const checkSubcomponents = (meta: ModuleExports) => {
if (meta.subcomponents) {
deprecate(dedent`The \`subcomponents\` annotation is deprecated.

Please refer to the migration guide: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#argstable-block'
`);
}
};

// Given the raw exports of a CSF file, check and normalize it.
export function processCSFFile<TRenderer extends Renderer>(
moduleExports: ModuleExports,
Expand All @@ -63,7 +53,6 @@ export function processCSFFile<TRenderer extends Renderer>(
importPath
);
checkDisallowedParameters(meta.parameters);
checkSubcomponents(meta);

const csfFile: CSFFile<TRenderer> = { meta, stories: {}, moduleExports };

Expand Down
46 changes: 44 additions & 2 deletions code/ui/blocks/src/blocks/ArgTypes.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@ import type { Meta, StoryObj } from '@storybook/react';

import { ArgTypes } from './ArgTypes';
import * as ExampleStories from '../examples/ArgTypesParameters.stories';
import * as SubcomponentsExampleStories from '../examples/ArgTypesWithSubcomponentsParameters.stories';

const meta: Meta<typeof ArgTypes> = {
title: 'Blocks/ArgTypes',
component: ArgTypes,
parameters: {
relativeCsfPaths: ['../examples/ArgTypesParameters.stories'],
relativeCsfPaths: [
'../examples/ArgTypesParameters.stories',
'../examples/ArgTypesWithSubcomponentsParameters.stories',
],
docsStyles: true,
},
};
Expand Down Expand Up @@ -46,7 +50,6 @@ export const OfUndefined: Story = {
decorators: [(s) => (window?.navigator.userAgent.match(/StorybookTestRunner/) ? <div /> : s())],
};

// NOTE: this will throw with no of prop
export const OfStoryUnattached: Story = {
parameters: { attached: false },
args: {
Expand Down Expand Up @@ -92,3 +95,42 @@ export const SortParameter: Story = {
of: ExampleStories.Sort,
},
};

export const Categories: Story = {
args: {
of: ExampleStories.Categories,
},
};

export const SubcomponentsOfMeta: Story = {
args: {
of: SubcomponentsExampleStories.default,
},
};

export const SubcomponentsOfStory: Story = {
args: {
of: SubcomponentsExampleStories.NoParameters,
},
};

export const SubcomponentsIncludeProp: Story = {
args: {
of: SubcomponentsExampleStories.NoParameters,
include: ['a', 'f'],
},
};

export const SubcomponentsExcludeProp: Story = {
args: {
of: SubcomponentsExampleStories.NoParameters,
exclude: ['a', 'c', 'f', 'g'],
},
};

export const SubcomponentsSortProp: Story = {
args: {
of: SubcomponentsExampleStories.NoParameters,
sort: 'alpha',
},
};
34 changes: 26 additions & 8 deletions code/ui/blocks/src/blocks/ArgTypes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import { filterArgTypes } from '@storybook/preview-api';
import type { ArgTypesExtractor } from '@storybook/docs-tools';
import React from 'react';

import { mapValues } from 'lodash';
import type { SortType } from '../components';
import { ArgsTable as PureArgsTable, ArgsTableError } from '../components';
import { ArgsTable as PureArgsTable, ArgsTableError, TabbedArgsTable } from '../components';
import { useOf } from './useOf';
import { getComponentName } from './utils';

type ArgTypesParameters = {
include?: PropDescriptor;
Expand All @@ -31,7 +33,7 @@ function extractComponentArgTypes(
return extractArgTypes(component);
}

function getArgTypesFromResolved(resolved: ReturnType<typeof useOf>, props: ArgTypesProps) {
function getArgTypesFromResolved(resolved: ReturnType<typeof useOf>) {
if (resolved.type === 'component') {
const {
component,
Expand All @@ -40,22 +42,23 @@ function getArgTypesFromResolved(resolved: ReturnType<typeof useOf>, props: ArgT
return {
argTypes: extractComponentArgTypes(component, parameters),
parameters,
component,
};
}

if (resolved.type === 'meta') {
const {
preparedMeta: { argTypes, parameters },
preparedMeta: { argTypes, parameters, component, subcomponents },
} = resolved;
return { argTypes, parameters };
return { argTypes, parameters, component, subcomponents };
}

// In the case of the story, the enhanceArgs argTypeEnhancer has already added the extracted
// arg types from the component to the prepared story.
const {
story: { argTypes, parameters },
story: { argTypes, parameters, component, subcomponents },
} = resolved;
return { argTypes, parameters };
return { argTypes, parameters, component, subcomponents };
}

export const ArgTypes: FC<ArgTypesProps> = (props) => {
Expand All @@ -64,7 +67,7 @@ export const ArgTypes: FC<ArgTypesProps> = (props) => {
throw new Error('Unexpected `of={undefined}`, did you mistype a CSF file reference?');
}
const resolved = useOf(of || 'meta');
const { argTypes, parameters } = getArgTypesFromResolved(resolved, props);
const { argTypes, parameters, component, subcomponents } = getArgTypesFromResolved(resolved);
const argTypesParameters = parameters.docs?.argTypes || ({} as ArgTypesParameters);

const include = props.include ?? argTypesParameters.include;
Expand All @@ -73,5 +76,20 @@ export const ArgTypes: FC<ArgTypesProps> = (props) => {

const filteredArgTypes = filterArgTypes(argTypes, include, exclude);

return <PureArgsTable rows={filteredArgTypes} sort={sort} />;
const hasSubcomponents = Boolean(subcomponents) && Object.keys(subcomponents).length > 0;

if (!hasSubcomponents) {
return <PureArgsTable rows={filteredArgTypes} sort={sort} />;
}

const mainComponentName = getComponentName(component);
const subcomponentTabs = mapValues(subcomponents, (comp) => ({
rows: filterArgTypes(extractComponentArgTypes(comp, parameters), include, exclude),
sort,
}));
const tabs = {
[mainComponentName]: { rows: filteredArgTypes, sort },
...subcomponentTabs,
};
return <TabbedArgsTable tabs={tabs} sort={sort} />;
};
Loading