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

Docs: Re-document subcomponents #25800

Merged
merged 8 commits into from
Jan 31, 2024
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
2 changes: 1 addition & 1 deletion docs/api/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ An overview of all available API references for Storybook.
<tr>
<td><a href="../api/parameters">Parameters</a></td>
<td>
Parameters are static metadata used to configure your <a href="../get-started/whats-a-story.md">stories</a> <a href="../addons/introduction.md">addons</a> in Storybook. They are specified at the story, meta (component), project (global) levels.
Parameters are static metadata used to configure your <a href="../get-started/whats-a-story.md">stories</a> <a href="../addons/index.md">addons</a> in Storybook. They are specified at the story, meta (component), project (global) levels.
</td>
</tr>
</tbody>
Expand Down
4 changes: 2 additions & 2 deletions docs/api/parameters.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: 'Parameters'
---

Parameters are static metadata used to configure your [stories](../get-started/whats-a-story.md) and [addons](../addons/introduction.md) in Storybook. They are specified at the story, meta (component), project (global) levels.
Parameters are static metadata used to configure your [stories](../get-started/whats-a-story.md) and [addons](../addons/index.md) in Storybook. They are specified at the story, meta (component), project (global) levels.

## Story parameters

Expand Down Expand Up @@ -36,7 +36,7 @@ Parameters specified at the story level apply to that story only. They are defin

</div>

Parameter's specified in a [CSF](../writing-stories/introduction.md#component-story-format-csf) file's meta configuration apply to all stories in that file. They are defined in the `parameters` property of the `meta` (default export):
Parameter's specified in a [CSF](../writing-stories/index.md#component-story-format-csf) file's meta configuration apply to all stories in that file. They are defined in the `parameters` property of the `meta` (default export):

<!-- prettier-ignore-start -->

Expand Down
39 changes: 39 additions & 0 deletions docs/snippets/angular/list-story-with-subcomponents.ts.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
```ts
// List.stories.ts
import type { Meta, StoryObj } from '@storybook/angular';

import { moduleMetadata } from '@storybook/angular';

import { CommonModule } from '@angular/common';

import { List } from './list.component';
import { ListItem } from './list-item.component';

const meta: Meta<List> = {
component: List,
subcomponents: { ListItem }, //👈 Adds the ListItem component as a subcomponent
decorators: [
moduleMetadata({
declarations: [List, ListItem],
imports: [CommonModule],
}),
],
};
export default meta;

type Story = StoryObj<List>;

export const Empty: Story = {};

export const OneItem: Story = {
args: {},
render: (args) => ({
props: args,
template: `
<app-list>
<app-list-item></app-list-item>
</app-list>
`,
}),
};
```
22 changes: 22 additions & 0 deletions docs/snippets/react/list-story-with-subcomponents.js.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
```jsx
// List.stories.js|jsx
import React from 'react';
kylegach marked this conversation as resolved.
Show resolved Hide resolved

import { List } from './List';
import { ListItem } from './ListItem';

export default {
component: List,
subcomponents: { ListItem }, //👈 Adds the ListItem component as a subcomponent
};

export const Empty = {};

export const OneItem = {
render: (args) => (
<List {...args}>
<ListItem />
</List>
),
};
```
26 changes: 26 additions & 0 deletions docs/snippets/react/list-story-with-subcomponents.ts-4-9.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
```tsx
// List.stories.ts|tsx
import React from 'react';
import type { Meta, StoryObj } from '@storybook/react';

import { List } from './List';
import { ListItem } from './ListItem';

const meta = {
component: List,
subcomponents: { ListItem }, //👈 Adds the ListItem component as a subcomponent
} satisfies Meta<typeof List>;
export default meta;

type Story = StoryObj<typeof meta>;

export const Empty: Story = {};

export const OneItem: Story = {
render: (args) => (
<List {...args}>
<ListItem />
</List>
),
};
```
26 changes: 26 additions & 0 deletions docs/snippets/react/list-story-with-subcomponents.ts.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
```tsx
// List.stories.ts|tsx
import React from 'react';
import type { Meta, StoryObj } from '@storybook/react';

import { List } from './List';
import { ListItem } from './ListItem';

const meta: Meta<typeof List> = {
component: List,
subcomponents: { ListItem }, //👈 Adds the ListItem component as a subcomponent
};
export default meta;

type Story = StoryObj<typeof List>;

export const Empty: Story = {};

export const OneItem: Story = {
render: (args) => (
<List {...args}>
<ListItem />
</List>
),
};
```
27 changes: 27 additions & 0 deletions docs/snippets/vue/list-story-with-sub-components.js.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
```js
// List.stories.js
import List from './List.vue';
import ListItem from './ListItem.vue';

export default {
component: List,
subcomponents: { ListItem }, //👈 Adds the ListItem component as a subcomponent
};

export const Empty = {
render: () => ({
components: { List },
template: '<List/>',
}),
};

export const OneItem = {
render: (args) => ({
components: { List, ListItem },
setup() {
return { args }
}
template: '<List v-bind="args"><ListItem /></List>',
}),
};
```
32 changes: 32 additions & 0 deletions docs/snippets/vue/list-story-with-sub-components.ts-4-9.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
```ts
// List.stories.ts
import type { Meta, StoryObj } from '@storybook/vue3';

import List from './List.vue';
import ListItem from './ListItem.vue';

const meta = {
component: List,
subcomponents: { ListItem }, //👈 Adds the ListItem component as a subcomponent
} satisfies Meta<typeof List>;
export default meta;

type Story = StoryObj<typeof meta>;

export const Empty: Story = {
render: () => ({
components: { List },
template: '<List />',
}),
};

export const OneItem: Story = {
render: (args) => ({
components: { List, ListItem },
setup() {
return { args }
}
template: '<List v-bind="args"><ListItem /></List>',
}),
};
```
32 changes: 32 additions & 0 deletions docs/snippets/vue/list-story-with-sub-components.ts.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
```ts
// List.stories.ts
import type { Meta, StoryObj } from '@storybook/vue3';

import List from './List.vue';
import ListItem from './ListItem.vue';

const meta: Meta<typeof List> = {
component: List,
subcomponents: { ListItem }, //👈 Adds the ListItem component as a subcomponent
};
export default meta;

type Story = StoryObj<typeof List>;

export const Empty: Story = {
render: () => ({
components: { List },
template: '<List />',
}),
};

export const OneItem: Story = {
render: (args) => ({
components: { List, ListItem },
setup() {
return { args }
}
template: '<List v-bind="args"><ListItem /></List>',
}),
};
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
```js
// List.stories.js
import { html } from 'lit';

export default {
title: 'List',
component: 'demo-list',
subcomponents: { ListItem: 'demo-list-item' }, // 👈 Adds the ListItem component as a subcomponent
};

export const Empty = {};

export const OneItem = {
render: () => html`
<demo-list>
<demo-list-item></demo-list-item>
</demo-list>
`,
};
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
```ts
// List.stories.ts
import type { Meta, StoryObj } from '@storybook/web-components';

import { html } from 'lit';

const meta: Meta = {
title: 'List',
component: 'demo-list',
subcomponents: { ListItem: 'demo-list-item' }, // 👈 Adds the ListItem component as a subcomponent
};
export default meta;

type Story = StoryObj;

export const Empty: Story = {};

export const OneItem: Story = {
render: () => html`
<demo-list>
<demo-list-item></demo-list-item>
</demo-list>
`,
};
```
30 changes: 30 additions & 0 deletions docs/writing-docs/autodocs.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,36 @@ Creating automated documentation with Storybook's Autodocs provides you with the

## Advanced configuration

### Documenting multiple components

Sometimes it's helpful to document multiple components together. For example, a component library’s ButtonGroup and Button components might not make sense without one another.

Autodocs allows you to document your "main" component, defined by the `component` property, as well as one or more `subcomponents` related to it.

<!-- prettier-ignore-start -->

<CodeSnippets
paths={[
'react/list-story-with-subcomponents.js.mdx',
'react/list-story-with-subcomponents.ts.mdx',
'angular/list-story-with-subcomponents.ts.mdx',
'vue/list-story-with-sub-components.js.mdx',
'vue/list-story-with-sub-components.ts.mdx',
'web-components/list-story-with-subcomponents.js.mdx',
'web-components/list-story-with-subcomponents.ts.mdx',
]}
usesCsf3
csf2Path="writing-stories/stories-for-multiple-components#snippet-list-story-with-subcomponents"
/>

<!-- prettier-ignore-end -->

![Subcomponents in ArgTypes doc block](../writing-stories/doc-block-arg-types-subcomponents-for-list.png)

The main component and its subcomponents will show up in a tabbed version of the [`ArgTypes` doc block](./doc-blocks.md#argtypes). The tab titles will correspond to the keys of the `subcomponents` object.

If you want to organize your documentation differently for component groups, we recommend [using MDX](./mdx.md). It gives you complete control over how your components are displayed and supports any configuration.

### Customize the Docs Container

The Docs Container is the component that wraps up the documentation page. It's responsible for rendering the documentation page in Storybook's UI. You can customize it by creating your own component and updating your Storybook UI configuration file (i.e., `.storybook/preview.js`) to reference it.
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
33 changes: 31 additions & 2 deletions docs/writing-stories/stories-for-multiple-components.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,40 @@
title: 'Stories for multiple components'
---

It's useful to write stories that [render two or more components](../writing-stories/index.md#stories-for-two-or-more-components) at once if those components are designed to work together. For example, `ButtonGroups`, `Lists`, and `Page` components.
It's useful to write stories that [render two or more components](../writing-stories/index.md#stories-for-two-or-more-components) at once if those components are designed to work together. For example, `ButtonGroups`, `Lists`, and `Page` components. Here's an example with `List` and `ListItem` components:

<!-- prettier-ignore-start -->

<CodeSnippets
paths={[
'react/list-story-with-subcomponents.js.mdx',
'react/list-story-with-subcomponents.ts.mdx',
'angular/list-story-with-subcomponents.ts.mdx',
'vue/list-story-with-sub-components.js.mdx',
'vue/list-story-with-sub-components.ts.mdx',
'web-components/list-story-with-subcomponents.js.mdx',
'web-components/list-story-with-subcomponents.ts.mdx',
]}
usesCsf3
csf2Path="writing-stories/stories-for-multiple-components#snippet-list-story-with-subcomponents"
/>

<!-- prettier-ignore-end -->

Note that by adding a `subcomponents` property to the default export, we get an extra panel on the [ArgTypes](../writing-docs/doc-blocks.md#argtypes) and [Controls](../essentials/controls.md#) tables, listing the props of `ListItem`:

![Subcomponents in ArgTypes doc block](./doc-block-arg-types-subcomponents-for-list.png)

Subcomponents are only intended for documentation purposes and have some limitations:

1. The [argTypes](../api/arg-types.md) of subcomponents are [inferred (for the renderers that support that feature)](../api/arg-types.md#automatic-argtype-inference) and cannot be manually defined or overridden.
2. The table for each documented subcomponent does _not_ include [controls](../essentials/controls.md) to change the value of the props, because controls always apply to the main component's args.

Let's talk about some techniques you can use to mitigate the above, which are especially useful in more complicated situations.

## Reusing subcomponent stories

The simplest approach we can take is to reuse the stories of the `ListItem` in the `List`:
The simplest change we can make to the above is to reuse the stories of the `ListItem` in the `List`:

<!-- prettier-ignore-start -->

Expand Down
Loading