Skip to content

Commit

Permalink
Merge pull request #12530 from storybookjs/docs/dynamic-source-snippets
Browse files Browse the repository at this point in the history
Addon-docs: Document dynamic source snippets
  • Loading branch information
shilman committed Oct 22, 2020
1 parent fc82a55 commit c580260
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 1 deletion.
54 changes: 54 additions & 0 deletions addons/docs/docs/multiframework.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Storybook Docs [provides basic support for all non-RN Storybook view layers](../
- [Arg tables](#arg-tables)
- [Component descriptions](#component-descriptions)
- [Inline story rendering](#inline-story-rendering)
- [Dynamic source rendering](#dynamic-source-rendering)
- [More resources](#more-resources)

## Framework-specific configuration
Expand Down Expand Up @@ -103,6 +104,59 @@ addParameters({

The input is the story function and the story context (id, parameters, args, etc.), and the output is a React element, because we render docs pages in react. In the case of Vue, all of the work is done by the `@egoist/vue-to-react` library. If there's no analogous library for your framework, you may need to figure it out yourself!

## Dynamic source rendering

With the release of Storybook 6.0, we've improved how stories are rendered in the [Source doc block](https://storybook.js.org/docs/react/writing-docs/doc-blocks#source). One of such improvements is the `dynamic` source type, which renders a snippet based on the output the story function.

This dynamic rendering is framework-specific, meaning it needs a custom implementation for each framework.

Let's take a look at the React framework implementation of `dynamic` snippets as a reference for implementing this feature in other frameworks:

```tsx
import { addons, StoryContext } from '@storybook/addons';
import { SNIPPET_RENDERED } from '../../shared';

export const jsxDecorator = (storyFn: any, context: StoryContext) => {
const story = storyFn();

// We only need to render JSX if the source block is actually going to
// consume it. Otherwise it's just slowing us down.
if (skipJsxRender(context)) {
return story;
}

const channel = addons.getChannel();

const options = {}; // retrieve from story parameters
const jsx = renderJsx(story, options);
channel.emit(SNIPPET_RENDERED, (context || {}).id, jsx);

return story;
};
```

A few key points from the above snippet:

- The **renderJsx** function call is responsible for transforming the output of a story function into a string specific to the framework (in this case React).
- The returned snippet string is emitted on Storybook's channel through **channel.emit()** and subsequently consumed up by the Source block for any given story, if it exists.

<div class="aside">
To learn more and see how it's implemented in context, check out <a href="https://github.com/storybookjs/storybook/blob/next/addons/docs/src/frameworks/react/jsxDecorator.tsx">the code</a> .
</div>

Now we need a way to configure how it's displayed in the UI:

```tsx
import { jsxDecorator } from './jsxDecorator';
export const decorators = [jsxDecorator];
```

This configures the `jsxDecorator` to be run on every story.

<div class="aside">
To learn more and see how it's implemented in context, check out <a href="https://github.com/storybookjs/storybook/blob/next/addons/docs/src/frameworks/react/jsxDecorator.tsx">the code</a> .
</div>

## More resources

- References: [README](../README.md) / [DocsPage](docspage.md) / [MDX](mdx.md) / [FAQ](faq.md) / [Recipes](recipes.md) / [Theming](theming.md) / [Props](props-tables.md)
Expand Down
5 changes: 5 additions & 0 deletions docs/frameworks.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,11 @@ module.exports = {
unsupported: [],
path: 'writing-docs/doc-blocks#source',
},
{
name: 'Dynamic source',
supported: ['react'],
path: 'writing-docs/doc-blocks#source',
},
{
name: 'Args Table',
supported: ['react', 'vue', 'angular', 'html', 'ember', 'web-components'],
Expand Down
10 changes: 9 additions & 1 deletion docs/writing-docs/doc-blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ title: 'Doc Blocks'

Doc Blocks are the building blocks of Storybook documentation pages. By default, [DocsPage](./docs-page.md) uses a combination of the blocks below to build a page for each of your components automatically.

Custom [addons](../configure/storybook-addons.md) can also provide their own doc blocks.
Custom [addons](../api/addons.md) can also provide their own doc blocks.

## ArgsTable

Expand Down Expand Up @@ -149,6 +149,14 @@ To customize the source snippet that’s displayed for a story, set the `docs.so

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

There is also a `docs.source.type` parameter that controls how source is auto-generated. Valid values include:

| Value | Description | Support |
| :----------------- | :------------------------------------------------------------------------------------------------------------------ | :------------------------------------------: |
| **auto** (default) | Use `dynamic` snippets if the story is written using [Args](../writing-stories/args) and the framework supports it. | All |
| **dynamic** | Dynamically generated snippet based on the output of the story function, e.g. JSX code for react. | [Limited](../api/frameworks-feature-support) |
| **code** | Use the raw story source as written in the story file. | All |

### MDX

You can also use the `Source` block in MDX. It accepts either a story ID or `code` snippet. Use the `language` for syntax highlighting.
Expand Down

0 comments on commit c580260

Please sign in to comment.