Skip to content
Merged
36 changes: 20 additions & 16 deletions addons/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,16 +75,16 @@ For more information on `MDX`, see the [`MDX` reference](./docs/mdx.md).

Storybook Docs supports all view layers that Storybook supports except for React Native (currently). There are some framework-specific features as well, such as props tables and inline story rendering. This chart captures the current state of support:

| | React | Vue | Angular | HTML | Svelte | Polymer | Marko | Mithril | Riot | Ember | Preact |
| ----------------- | :---: | :-: | :-----: | :--: | :----: | :-----: | :---: | :-----: | :--: | :---: | :----: |
| MDX stories | + | + | + | + | + | + | + | + | + | + | + |
| CSF stories | + | + | + | + | + | + | + | + | + | + | + |
| StoriesOf stories | + | + | + | + | + | + | + | + | + | + | + |
| Source | + | + | + | + | + | + | + | + | + | + | + |
| Notes / Info | + | + | + | + | + | + | + | + | + | + | + |
| Props table | + | + | # | | | | | | | | |
| Docgen | + | + | # | | | | | | | | |
| Inline stories | + | + | | | | | | | | | |
| | React | Vue | Angular | HTML | [Web Components](./web-components) | Svelte | Polymer | Marko | Mithril | Riot | Ember | Preact |
| ----------------- | :---: | :-: | :-----: | :--: | :--------------------------------: | :----: | :-----: | :---: | :-----: | :--: | :---: | :----: |
| MDX stories | + | + | + | + | + | + | + | + | + | + | + | + |
| CSF stories | + | + | + | + | + | + | + | + | + | + | + | + |
| StoriesOf stories | + | + | + | + | + | + | + | + | + | + | + | + |
| Source | + | + | + | + | + | + | + | + | + | + | + | + |
| Notes / Info | + | + | + | + | + | + | + | + | + | + | + | + |
| Props table | + | + | # | | + | | | | | | | |
| Description | + | + | # | | + | | | | | | | |
| Inline stories | + | + | | | | | | | | | | |

**Note:** `#` = WIP support

Expand Down Expand Up @@ -122,20 +122,24 @@ configure(require.context('../src', true, /\.stories\.(js|mdx)$/), module);

For more information on the new `configure`, see ["Loading stories"](https://github.com/storybookjs/storybook/blob/next/docs/src/pages/basics/writing-stories/index.md#loading-stories) in the Storybook documentation.

If using in conjunction with the [storyshots add-on](../storyshots/storyshots-core/README.md), you will need to
If using in conjunction with the [storyshots add-on](../storyshots/storyshots-core/README.md), you will need to
configure Jest to transform MDX stories into something Storyshots can understand:

Add the following to your Jest configuration:

```json
{
"transform": {
"^.+\\.[tj]sx?$": "babel-jest",
"^.+\\.mdx$": "@storybook/addon-docs/jest-transform-mdx"
}
"transform": {
"^.+\\.[tj]sx?$": "babel-jest",
"^.+\\.mdx$": "@storybook/addon-docs/jest-transform-mdx"
}
}
```

### Be sure to check framework specific installation needs

- [Web Components](./web-components)

## Preset options

The `addon-docs` preset has a few configuration options that can be used to configure its babel/webpack loading behavior. Here's an example of how to use the preset with options:
Expand Down
72 changes: 72 additions & 0 deletions addons/docs/src/frameworks/web-components/config.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,82 @@
/* global window */
/* eslint-disable import/no-extraneous-dependencies */
import { addParameters } from '@storybook/web-components';
import { DocsPage, DocsContainer } from '@storybook/addon-docs/blocks';
import { getCustomElements } from './customElements';

function mapData(data) {
return data.map(item => ({
name: item.name,
type: { name: item.type },
required: '',
description: item.description,
defaultValue: item.default,
}));
}

function isEmpty(obj) {
return Object.entries(obj).length === 0 && obj.constructor === Object;
}

function isValidComponent(tagName, customElements) {
if (!tagName) {
return false;
}
if (tagName && typeof tagName === 'string') {
return true;
}
throw new Error('Provided component needs to be a string. e.g. component: "my-element"');
}

function isValidMetaData(customElements) {
if (!customElements) {
return false;
}
if (customElements && customElements.tags && Array.isArray(customElements.tags)) {
return true;
}
throw new Error(`You need to setup valid meta data in your config.js via setCustomElements().
See the readme of addon-docs for web components for more details.`);
}

addParameters({
docs: {
container: DocsContainer,
page: DocsPage,
extractProps: tagName => {
const customElements = getCustomElements();
if (isValidComponent(tagName) && isValidMetaData(customElements)) {
const metaData = customElements.tags.find(
tag => tag.name.toUpperCase() === tagName.toUpperCase()
);
const sections = {};
if (metaData.properties) {
sections.props = mapData(metaData.properties);
}
if (metaData.events) {
sections.events = mapData(metaData.events);
}
if (metaData.slots) {
sections.slots = mapData(metaData.slots);
}
if (metaData.cssProperties) {
sections.css = mapData(metaData.cssProperties);
}
return isEmpty(sections) ? false : { sections };
}
return false;
},
extractComponentDescription: tagName => {
const customElements = getCustomElements();
if (isValidComponent(tagName) && isValidMetaData(customElements)) {
const metaData = customElements.tags.find(
tag => tag.name.toUpperCase() === tagName.toUpperCase()
);
if (metaData && metaData.description) {
return metaData.description;
}
}
return false;
},
},
});
15 changes: 15 additions & 0 deletions addons/docs/src/frameworks/web-components/customElements.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/* eslint-disable no-underscore-dangle */
/* global window */

/**
* @param customElements any for now as spec is not super stable yet
*/
export function setCustomElements(customElements: any) {
// @ts-ignore
window.__STORYBOOK_CUSTOM_ELEMENTS__ = customElements;
}

export function getCustomElements() {
// @ts-ignore
return window.__STORYBOOK_CUSTOM_ELEMENTS__;
}
1 change: 1 addition & 0 deletions addons/docs/src/public_api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { setCustomElements, getCustomElements } from './frameworks/web-components/customElements';
63 changes: 63 additions & 0 deletions addons/docs/web-components/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Storybook Docs for Web Components

## Installation

- Be sure to check the [installation section of the general addon-docs page](../README.md) before proceeding.
- Be sure to have a [custom-elements.json](./#custom-elementsjson) file.
- Add to your `.storybook/config.js`

```js
import { setCustomElements } from '@storybook/addon-docs';
import customElements from '../custom-elements.json';

setCustomElements(customElements);
```

- Add to your story files

```js
export default {
title: 'Demo Card',
component: 'your-component-name', // which is also found in the `custom-elements.json`
};
```

### custom-elements.json

In order to get documentation for web-components you will need to have a [custom-elements.json](https://github.com/webcomponents/custom-elements-json) file.

You can hand write it or better generate it. Depending on the web components sugar you are choosing your milage may vary.

Known analyzers that output `custom-elements.json`:

- [web-component-analyzer](https://github.com/runem/web-component-analyzer)
- Supports LitElement, Polymer, Vanilla, (Stencil)
- [stenciljs](https://stenciljs.com/)
- Supports Stencil (but does not have all metadata)

It basically looks like this:

```json
{
"version": 2,
"tags": [
{
"name": "demo-wc-card",
"properties": [
{
"name": "header",
"type": "String",
"attribute": "header",
"description": "Shown at the top of the card",
"default": "Your Message"
}
],
"events": [],
"slots": [],
"cssProperties": []
}
]
}
```

For a full example see the [web-components-kitchen-sink/custom-elements.json](../../../examples/web-components-kitchen-sink/custom-elements.json).
5 changes: 5 additions & 0 deletions examples/web-components-kitchen-sink/.storybook/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

import { configure, addParameters, addDecorator } from '@storybook/web-components';
import { withA11y } from '@storybook/addon-a11y';
import { setCustomElements } from '@storybook/addon-docs';

import customElements from '../custom-elements.json';

setCustomElements(customElements);

addDecorator(withA11y);

Expand Down
62 changes: 62 additions & 0 deletions examples/web-components-kitchen-sink/custom-elements.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{
"version": 2,
"tags": [
{
"name": "demo-wc-card",
"description": "This is a container looking like a card with a back and front side you can switch",
"properties": [
{
"name": "header",
"type": "String",
"attribute": "header",
"description": "Shown at the top of the card",
"default": "Your Message"
},
{
"name": "rows",
"type": "Array",
"attribute": "rows",
"description": "Tabular data shown on the back of the card",
"default": []
},
{
"name": "backSide",
"type": "Boolean",
"attribute": "back-side",
"reflect": true,
"description": "Indicates that the back of the card is shown",
"default": false
}
],
"events": [
{
"name": "side-changed",
"description": "Fires whenever it switches between front/back"
}
],
"slots": [
{
"name": "",
"description": "Content inside the card gets displayed on the front page"
}
],
"cssProperties": [
{
"name": "--demo-wc-card-header-font-size",
"description": "Header Font size",
"type": "Length"
},
{
"name": "--demo-wc-card-front-color",
"description": "Font color for the front",
"type": "Color"
},
{
"name": "--demo-wc-card-back-color",
"description": "Font color for the back",
"type": "Color"
}
]
}
]
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Story, Preview, Meta } from '@storybook/addon-docs/blocks';
import { Story, Preview, Meta, Props } from '@storybook/addon-docs/blocks';
import { action } from '@storybook/addon-actions';
import { html } from 'lit-html';
import '../demo-wc-card.js';
Expand All @@ -17,6 +17,12 @@ A story can be a simple return of `html`
`}
</Story>

## API

You can show the api table of a web component at any point in your documentation.

<Props of="demo-wc-card" />

## Function stories

Or a function
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import '../demo-wc-card.js';

export default {
title: 'Demo Card',
component: 'demo-wc-card',
};

export const Front = () => html`
Expand Down