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: improve storyIndexers & makeTitle documentation #20810

Merged
merged 5 commits into from
Feb 14, 2023
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
39 changes: 21 additions & 18 deletions docs/configure/sidebar-and-urls.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,52 +137,55 @@ When Storybook generates the titles for all matching stories, they'll retain the

### Story Indexers

Story Indexers are usually responsible of crawling through your filesystem on your given glob path, and retrieve the stories that match that glob, afterwards Storybook analyzes these stories and create entries for these stories in the `index.json` (formerly `stories.json`). This `index.json` is used to populate the sidebar links based on the `title` retrieved for each story from the story file.

For CSF, it is either auto generated or retrieved from the meta configuration.
Story Indexers are a set of heuristics used by Storybook to crawl your filesystem based on a given glob pattern searching for matching stories, which is then used to generate an index.json (formerly stories.json) file responsible for populating the sidebar with the necessary information. By default, this heuristic will look for files that contain the following scheme \*.stories.@(js|jsx|ts|tsx). However, if you need, you can create your custom story indexer that you can use to include stories that have a different naming convention. For example:

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

<CodeSnippets
paths={[
'common/csf-3-example-title.ts.mdx',
'common/storybook-main-csf-indexer.ts.mdx',
]}
/>

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

While for "Docs Only" pages, that title resides in the `title` attribute of the `Meta` tag. If the `title` attribute does not exist, Storybook indexer will be looking for the `of` attribute to retrieve a CSF story and get the title from there.
### Processing custom titles

Out of the box, Storybook automatically infers the story's title based on a set of patterns, including, for example, the file's physical location. If you're working on creating a custom story indexer and you want to handle the titles based on your set of rules, you can adjust it and provide a `makeTitle` function inside the `loadCsf` function. Below is a condensed table and examples of how these patterns work and how they relate to stories.

| Pattern | Description |
| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `titlePrefix` | Prefixes the indexed story title based on the [configuration](./overview.md#with-a-configuration-object). |
| `title` | Requires CSF and MDX.<br/>Infers the story title based on the information defined in the metadata. |
| `name` | Requires CSF and MDX.<br/> Overrides the story title based on the provided [name](../writing-stories/introduction.md#rename-stories) property. |
| `component` | Requires CSF.<br/> Generates the title based on the component property defined in the metadata. |
| `of` | Requires MDX.<br/> Retrieves the title based on the referenced story file. |
| `story export` | Requires CSF. <br/> Defines the title based on the [named story export](../api/csf.md#named-story-exports). |
| `filename` | Enabled with custom indexers.<br/> Defines the story title based on the filename parsed with the indexer. |

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

<CodeSnippets
paths={[
'common/storybook-auto-docs-mdx-docs-docs-only-page.mdx.mdx',
'common/csf-3-example-title.ts.mdx',
'common/csf-3-example-title.mdx.mdx',
]}
/>

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

Typically Storybook provides indexing capabilities for files that end with `.(story|stories).@(js|ts|jsx|tsx|mdx)`. If you feel the need to include stories that have different naming convention, e.g. [`20478`](https://github.com/storybookjs/storybook/issues/20478), you will need to introduce a new story indexer.

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

<CodeSnippets
paths={[
'common/storybook-main-csf-indexer.js.mdx',
'common/storybook-main-story-indexer-main.ts.mdx'
]}
/>

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

Another example listed below for indexing `.md` & `.html` files which is already implemented by one of our community addons [`Markdown Docs`](https://storybook.js.org/addons/@sheriffmoose/storybook-md/).
<div class="aside">

<!-- prettier-ignore-start -->
💡 Story indexers are a great way to get non-developers playing with your components and stories. They can do much more than documented here; we encourage you to check out the [`@storybook-extras/markdown` ](https://storybook.js.org/addons/@storybook-extras/markdown/) to learn more about these techniques.

<CodeSnippets
paths={[
'common/storybook-main-md-html-indexer.js.mdx',
]}
/>

<!-- prettier-ignore-end -->
</div>
14 changes: 14 additions & 0 deletions docs/snippets/common/csf-3-example-title.mdx.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
```mdx
{/* src/components/Button/Button.mdx */}

import { Meta } from '@storybook/blocks';

{/* 👇 Documentation-only page */}
<Meta title="Documentation" />


{/* 👇 Component documentation page */}
import * as ExampleComponentStories from './ExampleComponent.stories';

<Meta of={ExampleComponentStories} />
```
14 changes: 13 additions & 1 deletion docs/snippets/common/csf-3-example-title.ts.mdx
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
```ts
// CSF 3
// src/components/Button/Button.stories.tsx

const meta: Meta<Button> = {
// Sets the name for the stories container
title: 'components/Button',
// The component name will be used if `title` is not set
component: Button,
};
export default meta;

// The story variable name will be used if `name` is not set
const Primary: Story = {
// Sets the name for that particular story
name: 'Primary',
args: {
label: 'Button',
},
};
```
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
```js
// .storybook/main.js
```ts
// .storybook/main.ts

import { readFileSync } from 'fs';
import { loadCsf } from '@storybook/csf-tools';
Expand All @@ -16,8 +16,8 @@ export default {
test: /(stories|story)\.[tj]sx?$/,
indexer,
},
...(indexers || [])
]
}
...(indexers || []),
];
},
};
```
39 changes: 0 additions & 39 deletions docs/snippets/common/storybook-main-md-html-indexer.js.mdx

This file was deleted.

35 changes: 35 additions & 0 deletions docs/snippets/common/storybook-main-story-indexer-main.ts.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
```ts
// .storybook/main.ts

// Replace your-framework with the framework you are using (e.g., angular, react-webpack5, vue3-webpack5)
import type { StorybookConfig } from '@storybook/your-framework';

// this can be as easy as fs.readFileSync and return the string
// or as complex as creating a new MDX file with the content of the original file
import { parseCode } from './parseCode';

const config: StorybookConfig = {
storyIndexers: (indexers, addonOptions) => {
const indexer = async (fileName, compilationOptions) => {
const code = parseCode(fileName, addonOptions);
const makeTitle = (userTitle) => {
// Do something with the auto title retrieved by Storybook
return userTitle;
};

// Parse the CSF file with makeTitle as a custom context
return loadCsf(code, { ...compilationOptions, makeTitle, fileName }).parse();
};

return [
{
test: /\.(md|html)$/,
indexer,
},
...(indexers || []),
];
},
};

export default config;
```