Skip to content

Commit

Permalink
Merge pull request #25614 from storybookjs/jeppe/20782-subcomponents
Browse files Browse the repository at this point in the history
Blocks: Support `subcomponents` in `ArgTypes` and `Controls`, remove `ArgsTable` block
  • Loading branch information
JReinhold authored Jan 18, 2024
2 parents 81db91d + 533ea85 commit b5491cd
Show file tree
Hide file tree
Showing 17 changed files with 374 additions and 326 deletions.
15 changes: 11 additions & 4 deletions MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,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 @@ -1007,11 +1008,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 has been removed in favor of `ArgTypes` and `Controls`. [More info](#argstable-block).

With this removal we've reintroduced `subcomponents` support to `ArgTypes`, `Controls`, and autodocs. We've also undeprecated `subcomponents`, by popular demand.

#### `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
3 changes: 3 additions & 0 deletions code/ui/.storybook/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,10 @@ const config: StorybookConfig = {
],
build: {
test: {
// we have stories for the blocks here, we can't exclude them
disableBlocks: false,
// some stories in blocks (ArgTypes, Controls) depends on argTypes inference
disableDocgen: false,
},
},
framework: {
Expand Down
73 changes: 71 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,18 @@ 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';
import { within } from '@storybook/test';
import type { PlayFunctionContext } from '@storybook/csf';

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 +52,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 +97,67 @@ export const SortParameter: Story = {
of: ExampleStories.Sort,
},
};

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

const findSubcomponentTabs = async (
canvas: ReturnType<typeof within>,
step: PlayFunctionContext['step']
) => {
let subcomponentATab: HTMLElement;
let subcomponentBTab: HTMLElement;
await step('should have tabs for the subcomponents', async () => {
subcomponentATab = await canvas.findByText('SubcomponentA');
subcomponentBTab = await canvas.findByText('SubcomponentB');
});
return { subcomponentATab, subcomponentBTab };
};

export const SubcomponentsOfMeta: Story = {
args: {
of: SubcomponentsExampleStories.default,
},
play: async ({ canvasElement, step }) => {
const canvas = within(canvasElement);
await findSubcomponentTabs(canvas, step);
},
};

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

export const SubcomponentsIncludeProp: Story = {
args: {
of: SubcomponentsExampleStories.NoParameters,
include: ['a', 'f'],
},
play: async ({ canvasElement, step }) => {
const canvas = within(canvasElement);
const { subcomponentBTab } = await findSubcomponentTabs(canvas, step);
await subcomponentBTab.click();
},
};

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

export const SubcomponentsSortProp: Story = {
...SubcomponentsIncludeProp,
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

0 comments on commit b5491cd

Please sign in to comment.