Iniciando um Design System com Storybook 5.3 e Angular
Tags: angular, storybook, design
Published: 2020-01-31 11:02:11

O [Storybook 5.3 foi lançado oficialmente](https://twitter.com/mshilman/status/1217081058849517568) há duas semanas e ele trouxe [ótimas melhorias](https://medium.com/storybookjs/storybook-5-3-83e114e8797c). Além de ficar mais fácil de usar e configurar, ele não é mais "só" um explorador de componentes UI. Ele se tornou uma ferramenta incrível para desenvolver um [Design System](https://brasil.uxdesign.cc/entendendo-design-system-f375bbb6f704), e eu vou explorar isso com vocês!

> Esse artigo é baseado principalmente nos 4 artigos, criados pela equipe do Storybook, sobre esse lançamento. Se quiser ver essas histórias, que são mais curtas e estão separadas, você pode pular direto para [Fontes](#fontes).

Se você não sabe o que é o Storybook, recomendo ler meu artigo anterior, pois também vou usar o projeto dele como base para esse artigo.

{% link klauskpm/como-criar-uma-biblioteca-de-componentes-com-angular-e-storybook-420p %}

Índice dos tópicos principais:
- [Atualizando os pacotes](#atualizando-os-pacotes)
- [Configuração declarativa](#configura%C3%A7%C3%A3o-declarativa)
- [Geração automática de documentação](#gera%C3%A7%C3%A3o-autom%C3%A1tica-de-documenta%C3%A7%C3%A3o)
- [Iniciando um Design System com MDX](#iniciando-um-design-system-com-mdx)
- [Storybook focado em Design](#storybook-focado-em-design)

----

# Preparação

Na época que esse guia foi preparado, foram usadas as seguintes tecnologias:

| tecnologia | versão | instalação |
|-|-|-|
| Node.js | 11.6.0 | [como instalar](https://nodejs.org/en/) |
| NPM | 6.13.4 | **Já vem com o Node.js** |
| Angular CLI | 8.3.21 | [como instalar](https://angular.io/guide/setup-local#step-1-install-the-angular-cli) |
| Storybook | 5.3.8 | [como instalar](#atualizando-os-pacotes) |

Todo o código desse projeto está no GitHub. Então, caso você se perca em qualquer parte, pode fazer uma comparação direta:
{% github klauskpm/angular-storybook no-readme %}

----

# Atualizando os pacotes

Se você [instalou os pacotes do Storybook](https://dev.to/klauskpm/como-criar-uma-biblioteca-de-componentes-com-angular-e-storybook-420p#instalando-o-storybook) e agora precisa atualizar eles, não se preocupe. Você só precisa rodar o seguinte comando no seu terminal:

```sh
# dentro do seu projeto
npx npm-check-updates '/storybook/' -u && npm install
```

O [`npm-check-updates`](https://www.npmjs.com/package/npm-check-updates) é um pacote que verifica se um pacote precisa atualizar. Nós passamos uma expressão regular para ele achar todos os pacotes que tenham storybook no nome, e a opção `-u` para atualizar o nosso `package.json`.

O `npx` é um comando do Node/npm para executar pacotes sem precisar instalar eles. Ótimo para casos em que não queremos instalar um pacote globalmente porque só vamos usar ele apenas uma vez.

> Pode comparar o seu progresso com a [tag v2.0 do repositório](https://github.com/klauskpm/angular-storybook/tree/v2.0)

----

# Configuração declarativa

O Storybook já tinha uma configuração bem simples, mas tinham alguns pontos que poderiam melhorar, como alguns nomes que não eram claros de acordo com as responsabilidades e a utilização da API do Webpack. Agora que resolveram esses problemas, vamos ver como a ela ficou.

## `main.js`

![Resumindo o config.js, addons.js e presets.js no novo arquivo main.js](https://miro.medium.com/max/2794/1*q_AI89haHMbERQslHrXyAA.png)[*Fonte*](https://medium.com/storybookjs/declarative-storybook-configuration-49912f77b78)

O `main.js` é o arquivo principal de configuração do Storybook e é responsável por tudo que lida com a renderização das nossas histórias. Nesse arquivo vamos declarar, onde devemos buscar as histórias e como identificar elas, quais são os addons da aplicação e as configurações de presets.

Vamos ver como escrevíamos antes e como é hoje.

### Antes

**.storybook/config.js**
```js
import { configure } from '@storybook/angular';

configure([
  require.context('../src', true, /\.stories\.[tj]s$/),
  require.context('../projects', true, /\.stories\.[tj]s$/)
], module);
```

**.storybook/addons.js**
```js
import '@storybook/addon-knobs/register';
import '@storybook/addon-actions/register';
```

### Depois

**.storybook/main.js**
```js
module.exports = {
  stories: [
    '../src/**/*.stories.(ts|js)',
    '../projects/**/*.stories.(ts|js)'
  ],
  addons: [
    '@storybook/addon-knobs',
    '@storybook/addon-actions'
  ]
};
```

Com isso nós conseguimos matar o `config.js` e o `addons.js` do nosso projeto e temos uma configuração bem mais simples de entender. Apesar de nesse exemplo nós termos matado o `config.js`, nós poderíamos ter outras configurações nele. Essas configurações foram absorvidas pelo `preview.js`.

## `preview.js`

O `preview.js` cuida do iframe que exibe (preview) a sua história e das configurações globais. É nele que vamos fazer a importação de CSS e polyfill, e configurações de parâmetros e decorators, que era a segunda responsabilidade do `config.js`.

No nosso caso só vamos configurar o addon `knobs`, que estava sendo configurado dentro do `simple-button/index.stories.ts`.

**.storybook/preview.js**
```js
import { addDecorator } from "@storybook/angular";
import { withKnobs } from "@storybook/addon-knobs";

addDecorator(withKnobs);
```

## `manager.js`

O `manager.js` cuida da parte gráfica que está em volta dos "previews" das histórias e também a parte dos addons. É nele que vamos adicionar configurações como temas, logo e nome da empresa, e configurações de exibição dos addons.

Vamos criar um tema com a base clara e definir que o nome do nosso Storybook é "Angular Storybook":

**.storybook/manager.js**
```js
import { create } from '@storybook/theming/create';
import { addons } from "@storybook/addons";

addons.setConfig({
  theme: create({
    base: 'light',
    brandTitle: 'Angular Storybook'
  })
});
```

E vamos ter o seguinte resultado:

![Storybook com título definido no manager.js](https://thepracticaldev.s3.amazonaws.com/i/xvfvwtdswltuta93kqzc.png)

O layout continua o mesmo, mas, em vez da logo do Storybook, está aparecendo o nome do nosso projeto definido no tema.

> Se quiser saber mais sobre a parte de tema, você pode ver a [documentação oficial sobre criação de temas](https://storybook.js.org/docs/configurations/theming/).

## Separadores de hierarquia

Antes do 5.3, o Storybook aceitava vários tipos de separadores de hierarquia, como `|`, `\` e `.`. mas agora ele força a hierarquia a ser definida sempre com `/`. Então, uma história que tinha esse título `UI|Buttons & Indicators/Button` ficaria assim `UI/Buttons & Indicators/Button`.

Vamos revisitar o nosso `simple-button/index.stories.ts` e substituir o título da história respeitando a nova hierarquia:

**projects/storybook-ui/src/lib/simple-button/index.stories.ts**
```ts
import { SimpleButtonComponent } from './simple-button.component';
import { text } from '@storybook/addon-knobs';
import { moduleMetadata } from '@storybook/angular';
import { action } from '@storybook/addon-actions';

export default {
  title: 'UI / Button',
  decorators: [
    moduleMetadata({declarations: [SimpleButtonComponent]})
  ],
};

export const withDefaultValues = () => ({
  component: SimpleButtonComponent
});

export const withText = () => {
  return {
    template: `
        <ui-simple-button
          [text]="text"
          (click)="click($event)"
        ></ui-simple-button>
    `,
    props: {
      text: text('Text', 'Ola'),
      click: action('Clicou')
    }
  };
};
```

#### Fazendo a atualização em massa

Fazer essa alteração na mão para apenas uma história é simples, mas quando começam a ser várias e com vários níveis, isso se torna trabalhoso. Felizmente, a equipe do Storybook fez um script para atualizar isso de forma automática. Você só precisa rodar o seguinte comando:

```sh
# dentro do seu projeto
npx -p @storybook/cli sb migrate upgrade-hierarchy-separators --glob="*.stories.(ts|js)"
```

#### Perdemos o root!

Com essa atualização nós perdemos o root/raiz das nossas histórias. O root aparecia como um texto em cima das nossas histórias. No nosso caso, era o `UI`, e tinhamos como pasta o `Button`. Sem o root, o `UI` se torna uma pasta como o `Button`.

Para recuperar essa aparência de root, nós precisamos adicionar o seguinte código no `.storybook/preview.js`:

**.storybook/preview.js**
```js
addParameters({ 
  options: {
    showRoots: true,
  },
});
```

## Migração

Tanto a parte do antigo `config.js` quanto os antigos separadores vão ser suportados até a versão 6.0.0 do Storybook. Felizmente, esse artigo já é suficiente para te preparar para essa versão, mas, caso queira consultar uma fonte oficial, a equipe do Storybook também preparou um [guia de migração do 5.2 para o 5.3](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#from-version-52x-to-53x) para facilitar todo esse processo.

## Saber mais sobre

Se quiser saber mais detalhes sobre a parte da configuração declarativa, você pode ver o artigo oficial do Storybook:

{% medium https://medium.com/storybookjs/declarative-storybook-configuration-49912f77b78 %}

> Pode comparar o seu progresso com a [tag 2.1 do repositório](https://github.com/klauskpm/angular-storybook/tree/v2.1)

----

# Geração automática de documentação

O Storybook agora da suporte ao [DocsPage](https://github.com/storybookjs/storybook/blob/next/addons/docs/docs/docspage.md) para geração automática de documentação, e ao [MDX](https://github.com/storybookjs/storybook/blob/next/addons/docs/docs/mdx.md) para documentações mais longas e customizadas - vamos falar dele mais tarde.

![Página de exemplo da documentação gerada do Storybook com Angular](https://raw.githubusercontent.com/storybookjs/storybook/next/addons/docs/docs/media/angular-hero.png)[*Fonte*](https://github.com/storybookjs/storybook/tree/next/addons/docs/angular)

## Configurando o DocsPage

Para usar o DocsPage só preciamos instalar umas dependências, adicionar poucas configurações, e a documentação está pronta. Parece mágica, mas é melhor!

### Instale as dependências

Primeiro nós vamos instalar o [`@storybook/addon-docs`](https://www.npmjs.com/package/@storybook/addon-docs) (responsável pela geração das páginas) e o [`@compodoc/compodoc`](https://www.npmjs.com/package/@compodoc/compodoc) (gerador de documentação do de projetos do Angular).

```sh
# dentro do seu projeto
npm install --save-dev @storybook/addon-docs @compodoc/compodoc
```

Mais tarde vou detalhar a importância do `compodoc`.

### Adicione os scripts de geração

Vamos criar o script `docs:storybook` que vai ser responsável por gerar a documentação do nosso projeto, e vamos adicionar esse script antes da execução do `storybook` e do `build-storybook`.

**package.json**
```json
{
  ...,
  "scripts": {
    "docs:storybook": "compodoc -p .storybook/tsconfig.json -e json -d .",
    "storybook": "npm run docs:storybook && start-storybook -p 6006",
    "build-storybook": "npm run docs:storybook && build-storybook"
  }
}
```

O comando que configuramos vai gerar um arquivo JSON chamado `documentation.json` e vamos passar essas informações para o `@storybook/addon-docs`.

> :warning: Na documentação é recomendado usar o `tsconfig.json` do projeto principal em vez do `.storybook/tsconfig.json`, mas como estamos usando o `compodoc` para o `Storybook`, na **MINHA OPINIÃO** faz mais sentido usar o do `Storybook`. Sinta-se livre para discordar e opinar!

Infelizmente, a documentação não atualiza automaticamente ao mudar o componente. Precisamos regerar o `documentation.json` sempre que quisermos as informações mais novas. Felizmente já tem uma [issue aberta sobre isso](https://github.com/storybookjs/storybook/issues/8672).

#### Explicando o `compodoc`

Explicando um pouco o comando que acabamos de configurar, nós passamos as seguintes opções:

- `-p` ou `--tsconfig` para definir qual tsconfig vai ser usado
- `-e` ou `--exportFormat` para definir o formato que vai ser exportado
- `-d` ou `--output` para definir a pasta em que vai ser exportada a documentação

Se usássemos as opções padrões do `compodoc` e gerássemos a documentação com `compodoc -p .storybook/tsconfig.json`, seria gerada a pasta `documentation` com páginas HTML com uma documentação completa do projeto.

![Exemplo de uma documentação gerada pelo compodoc](https://raw.githubusercontent.com/compodoc/compodoc/master/screenshots/main-view.gif)[*Fonte*](https://www.npmjs.com/package/@compodoc/compodoc)

### Configure o `@storybook/addon-docs`

Como todos os outros addons nós precisamos adicionar ele no `.storybook/main.js` para ele ser carregado:

**.storybook/main.js**
```js
module.exports = {
  ...
  addons: [
    ...,
    '@storybook/addon-docs',
  ]
};
```

Além disso, precisamos alimentar ele com o `documentation.json` gerado pelo `compodoc`. Vamos adicionar o seguinte no `.storybook/preview.js`:

**.storybook/preview.js**
```js
import { setCompodocJson } from "@storybook/addon-docs/dist/frameworks/angular";

import docJson from '../documentation';

setCompodocJson(docJson);
```

E por último, não podemos esquecer de adicionar a propriedade `component` na história do nosso componente. É com ela que será identificado o componente e vinculado a tabela de propriedades geradas pelo `compodoc`:

**projects/storybook-ui/src/lib/simple-button/index.stories.ts**
```ts
export default {
  title: 'UI / Button',
  component: SimpleButtonComponent, // Adicionado aqui
  decorators: [
    moduleMetadata({declarations: [SimpleButtonComponent]})
  ],
};
```

### Adicione uns enfeites (opcional)

Apenas para ver como a tabela de propriedades é gerada pelo `compodoc`, vamos adicionar o seguinte no `simple-button/index.stories.ts`:

**projects/storybook-ui/src/lib/simple-button/simple-button.component.ts**
```ts
/**
 * ViewChild que está vinculada a nada
 */
@ViewChild('empty', { static: false })
empty: TemplateRef<any>;

/**
 * Output fake
 */
@Output()
clicked = new EventEmitter();

/**
 * Input que define o texto apresentado no botão
 */
@Input()
text = 'clique aqui';

/**
 * Método simples e público
 * @return void
 */
public simpleMethod(): void {}

/**
 * Método complexo e privado
 * @return string
 */
private complexMethod(num1: number, num2: number): string {
  return '';
}
```

E também podemos controlar o tamanho do preview das histórias da documentação adicionando uma configuração no `.storybook/preview.js`:

**.storybook/preview.js**
```js
addParameters({
  ...,
  docs: {
    iframeHeight: 60
  }
});
```

### Resultado

Agora, quando rodarmos o comando `npm run storybook`, devemos ver o seguinte:

![Página de documentação no Storybook, exibindo a tabela de propriedades gerada pelo compodoc pro componente SimpleButton](https://thepracticaldev.s3.amazonaws.com/i/iyjtcl9so89mwvmtbeps.png)

:tada: Storybook com documentação gerada :tada:

## Saber mais sobre

Se quiser saber mais detalhes sobre geração de documentação, você pode ler o [guia oficial para o Angular](https://github.com/storybookjs/storybook/tree/next/addons/docs/angular), ou o artigo oficial do Storybook:

{% medium https://medium.com/storybookjs/storybook-docs-for-new-frameworks-b1f6090ee0ea %}

> Pode comparar o seu progresso com a [tag v2.2 do repositório](https://github.com/klauskpm/angular-storybook/tree/v2.2)

----

# Iniciando um Design System com MDX

[MDX](https://mdxjs.com/) é a mistura de [Markdown](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet) (MD) e [JSX](https://reactjs.org/docs/introducing-jsx.html) (sintaxe do React para escrita de templates). Com o MDX, o Storybook nos da a liberdade de melhorar ou substituir as documentações geradas automaticamente, e muito mais!

![Gif de introdução ao MDX, onde é mostrado uma imagem de exemplo de MDX, depois o que seria o resultado disso, e por último o logo do Storybook e do MDX lado a lado](https://miro.medium.com/max/800/1*2QMmoHLXMg_AoVcI6o_NSg.gif)[*Fonte*](https://medium.com/storybookjs/rich-docs-with-storybook-mdx-61bc145ae7bc)

Com o MDX podemos escrever histórias apenas com MDX ou misturar as histórias em CSF (Component Story Format) com MDX. Também podemos escrever um MDX de documentação sem histórias, como design tokens e introdução ao design system. Segue abaixo o exemplo de um projeto:

[![Colagem de imagens mostrando um repositório com Landing Page, Markdown, MDX, Props e DocsPage](https://miro.medium.com/max/3958/1*XGUPJaHY7riY2qNKtEl_3Q.png)](https://reaviz.io/?path=/story/docs-intro--page)
[Site](https://reaviz.io/?path=/story/docs-intro--page) | [GitHub](https://github.com/jask-oss/reaviz)

## Como escrevemos em MDX

![Exemplo de sintaxe de MDX](https://miro.medium.com/max/990/1*DNSAb7P_4auXdb6TjERPxw.png)[*Fonte*](https://medium.com/storybookjs/rich-docs-with-storybook-mdx-61bc145ae7bc)

Olhando a imagem acima, podemos ver o `#Badge` e o `Lets define...` e isso faz parte da sintaxe do Markdown. Enquanto isso o `<Badge>` que é um componente feito em React, e o `<Meta>`, `<Story>` e `<Preview>` que fazem parte do `addon-docs`, usam a sintaxe do JSX. Isso quer dizer que, quando quisermos adicionar textos e formatações nós vamos usar o MD (Markdown), e quando quisermos adicionar algum layout ou funcionalidade diferente, vamos usar componentes em React com JSX. Segue abaixo o que seria o resultado do MDX apresentado anteriormente:

![](https://miro.medium.com/max/2754/1*orUEtAhfGFroSSLLzCVO6A.png)[*Fonte*](https://medium.com/storybookjs/rich-docs-with-storybook-mdx-61bc145ae7bc)

O resultado dessa combinação é uma sintaxe muito mais simples. Ela é tão simples, e mais afastada da programação, que se torna fácil para que pessoas sem conhecimento da nossa linguagem de programação possam contribuir com a documentação do nosso Design System.

![Gif rodando 5 imagens que demonstram o preview de um componente, a tabela de propriedades de um componente, a tipografia, a palheta de cores, e os ícones de um sistema](https://miro.medium.com/max/600/1*SWf7TSUuDHX9CnIXmOaNhg.gif)
[*Fonte*](https://medium.com/storybookjs/rich-docs-with-storybook-mdx-61bc145ae7bc) | [Site](https://storybook-design-system.netlify.com/?path=/docs/design-system-intro--page) | [GitHub](https://github.com/storybookjs/design-system) | [Componentes de Auxílio](https://github.com/storybookjs/storybook/tree/next/lib/components/src/blocks)

## Configurando o MDX

Para fazer o MDX rodar é bem simples. Nós precisamos instalar algumas dependências e fazer nosso sistema encontrar os arquivos MDX.

### Instale as dependências

O MDX precisa do DocsPage e do React (JSX). Como já fizemos as instalações pro DocsPage anteiormente, vamos só fazer as instalações necessárias do React.

```sh
# dentro do seu projeto
npm install --save-dev react react-is babel-loader
```

### Altere o `main.js`

O nosso `.storybook/main.js` já está configurado para procurar por histórias que tenham as extensões `ts` ou `js`. Então só precisamos adicionar a extensão `mdx`:

```js
module.exports = {
  stories: [
    '../src/**/*.stories.(ts|js|mdx)',
    '../projects/**/*.stories.(ts|js|mdx)'
  ],
  addons: [
    '@storybook/addon-docs',
    '@storybook/addon-knobs',
    '@storybook/addon-actions'
  ]
};
```

### Criando um arquivo `MDX`

Por enquanto vamos criar só um arquivo de ilustração. Só precisa copiar e colar que mais tarde vou explicar a sintaxe. Dentro de `projects/storybook-ui/src/lib/` vamos criar o arquivo `design-system/getting-started.stories.mdx` para introduzir as pessoas ao nosso design system:

**projects/storybook-ui/src/lib/design-system/getting-started.stories.mdx**
```md
import { Meta } from '@storybook/addon-docs/blocks';

<Meta title='Design System / Introdução' />

# Introdução

Olá pessoa! Seja bem vinda ao meu Design System
```

### Veja o resultado

Agora, quando você rodar o comando `npm run storybook`, você deve ver algo como o que está abaixo:

![Página gerada pelo Storybook com o texto formatado do arquivo acima](https://thepracticaldev.s3.amazonaws.com/i/cbr1ke1cuaxtxqnfxuft.png)

## Criando histórias com MDX

Nós configuramos o DocsPage e o MDX, e vimos ambos em ação. Agora, nós precisamos dar o próximo passo e entender como criar histórias em MDX. Para isso, devemos saber quais ferramentas temos.

### Blocos do `@storybook/addon-docs`

O Storybook nos dá [vários blocos](https://github.com/storybookjs/storybook/tree/next/addons/docs/src/blocks) para montarmos nossas histórias, e os 4 blocos principais são:

- `Meta` para definir título, decorators e parameters (assim como o que definimos no `export default` no CSF)
- `Props` para exibir a tabela de propriedades do componente
- `Story` para criar a história do componente e exibir ela na documentação
- `Preview` para exibir a história do componente em volta de um bloco de exibição

[Existem outros blocos](https://github.com/storybookjs/storybook/tree/next/lib/components/src/blocks) além desses, como o [`ColorPalette` para design tokens](https://github.com/storybookjs/storybook/blob/next/lib/components/src/blocks/ColorPalette.stories.tsx), mas esses 4 são os principais e devem aparecer em todas as histórias que fizermos com MDX. Além disso, também podemos criar os nossos próprios blocos usando o React.

### Estilos de escrita com MDX

Diferente do React e do Vue, no Storybook o Angular não tem a habilidade de escrever histórias inline. Felizmente, temos outras abordagens:
- [histórias puras em MDX](https://github.com/storybookjs/storybook/tree/next/addons/docs/angular#mdx)
- [histórias em CSF com documentação em MDX](https://github.com/storybookjs/storybook/blob/next/addons/docs/docs/recipes.md#csf-stories-with-mdx-docs)
- [histórias em CSF definindo o MDX arbitrariamente](https://github.com/storybookjs/storybook/blob/next/addons/docs/docs/recipes.md#csf-stories-with-arbitrary-mdx) (MDX não podendo definir histórias, só referênciando).

> Não irei abordar o último estilo de escrita com MDX (histórias em CSF definindo o MDX arbitrariamente), pois eu não consegui fazer ele funcionar. Continuarei buscando soluções e atualizarei esse artigo caso consiga.

#### Histórias puras em MDX

Essa abordagem é ótima para documentações, como o `getting-started.stories.mdx`, e também para componentes simples. Como eles não precisam de muita configuração, e no máximo tem alguns inputs e outputs simples, não precisamos de um arquivo de lógica. Segue abaixo um exemplo:

**index.stories.mdx**
```md
import { Meta, Story, Props, Preview } from '@storybook/addon-docs/blocks';
import { moduleMetadata, addDecorator } from '@storybook/angular';
import { SimpleButtonComponent } from '../simple-button.component';

<Meta
  title='UI / Button'
  component={SimpleButtonComponent}
  decorators={[moduleMetadata({ declarations: [SimpleButtonComponent] })]}
/>

# SimpleButton Component

Uma descrição simples em **markdown**.
Exibindo o `SimpleButtonComponent` usando o `Story`.

<Story name='basic' height='60px'>{{
  component: SimpleButtonComponent,
  props: {},
}}</Story>

## Props

A tabela de propriedades é exibida com usando o `Props`.

<Props of={SimpleButtonComponent} />


## Stories

Fazendo preview da história com `<Preview>`.

<Preview>
  <Story name="Basic Preview">{{
    component: SimpleButtonComponent,
    props: {},
  }}</Story>
</Preview>
```

#### Histórias em CSF com documentação em MDX

As vezes nós temos componentes mais complexos, ou com dados mais longos, e queremos deixar a parte da documentação mais simples possível. Para esses casos nós vamos ter dois arquivos, um CSF (`.ts` ou `.js`) e um MDX (`.mdx`). No CSF vamos deixar as histórias e lógicas, e no MDX vamos deixar a documentação e aplicaremos as histórias nos devidos lugares. Segue abaixo um exemplo:

**stories.ts**
```ts
import { action } from '@storybook/addon-actions';
import { text } from '@storybook/addon-knobs';
import { SimpleButtonComponent } from '../simple-button.component';

export const withDefaultValues = () => ({
  component: SimpleButtonComponent
});

export const withText = () => {
  return {
    template: `
        <ui-simple-button
          [text]="text"
          (click)="click($event)"
        ></ui-simple-button>
    `,
    props: {
      text: text('Text', 'Ola'),
      click: action('Clicou')
    }
  };
};
```

**index.stories.mdx**
```md
import { Meta, Story, Props, Preview } from '@storybook/addon-docs/blocks';
import { moduleMetadata, addDecorator } from '@storybook/angular';
import { SimpleButtonComponent } from '../simple-button.component';
import * as stories from './stories.ts';

<Meta
  title='UI / Button'
  component={SimpleButtonComponent}
  decorators={[moduleMetadata({ declarations: [SimpleButtonComponent] })]}
/>

# SimpleButton Component

Uma descrição simples em **markdown**.
Exibindo o `SimpleButtonComponent` usando o `CSF` + `MDX`.

<Story name='basic' height='60px'>{stories.withDefaultValues()}</Story>

## Props

A tabela de propriedades é exibida com usando o `Props`.

<Props of={SimpleButtonComponent} />


## Stories

Usando histórias criadas em CSF no MDX

<Preview>
  <Story name="With Text">{stories.withText()}</Story>
</Preview>
```

### Vamos atualizar nossa história

Vendo as estratégias acima, podemos afirmar que nosso componente só precisa de um arquivo MDX porque ele é bem simples, mas, apenas por questão de demonstração, vamos usar os dois estilos ao mesmo tempo. Vamos pegar o nosso `simple-button/index.stories.ts` e começar a criar nossa nova documentação dele. Vamos seguir os seguintes passos:

- Crie a pasta `stories` dentro de `projects/storybook-ui/src/lib/simple-button`
- Renomei o `index.stories.ts` para `stories.ts` e mova ele para dentro de `stories`
- Crie o arquivo `index.stories.mdx` dentro `stories`

Nós renomeamos o arquivo para não haver um possível problema de carregamento das histórias, e movemos os dois arquivos para uma outra pasta apenas por questão de organização.

Agora, vamos aplicar as mudanças no conteúdo dos arquivos:

**stories.ts**
```ts
import { action } from '@storybook/addon-actions';
import { text } from '@storybook/addon-knobs';
import { SimpleButtonComponent } from '../simple-button.component';

export const withDefaultValues = () => ({
  component: SimpleButtonComponent
});

export const withText = () => {
  return {
    template: `
        <ui-simple-button
          [text]="text"
          (click)="click($event)"
        ></ui-simple-button>
    `,
    props: {
      text: text('Text', 'Ola'),
      click: action('Clicou')
    }
  };
};
```

**index.stories.mdx**
```md
import { Meta, Story, Props, Preview } from '@storybook/addon-docs/blocks';
import { moduleMetadata, addDecorator } from '@storybook/angular';
import { SimpleButtonComponent } from '../simple-button.component';
import * as stories from './stories.ts';

<Meta
  title='UI / SimpleButton'
  component={SimpleButtonComponent}
  decorators={[moduleMetadata({ declarations: [SimpleButtonComponent] })]}
/>

# SimpleButton Component

Uma descrição simples em **markdown**.
Exibindo o `SimpleButtonComponent` usando o `Story`.

<Story name='simples' height='60px'>{{
  component: SimpleButtonComponent,
  props: {},
}}</Story>

## Props

A tabela de propriedades é exibida com usando o `Props`.

<Props of={SimpleButtonComponent} />


## Stories

Usando histórias criadas em CSF no MDX

<Preview>
  <Story name="com valores default">{stories.withDefaultValues()}</Story>
</Preview>

<Preview>
  <Story name="com texto diferente">{stories.withText()}</Story>
</Preview>
```

O resultado resultado é esse:

![Imagem da documentação gerada a partir do index.stories.mdx. Exibindo o título, a história simples e a tabela de propriedades na parte principal, e na parte lateral os links das histórias: simples, com valores default e com texto diferente](https://thepracticaldev.s3.amazonaws.com/i/nvvunbj2x0qob57a61db.png)

## Saber mais sobre

Se quiser saber mais detalhes sobre documentação rica com MDX, você pode ler o artigo oficial do Storybook:

{% medium https://medium.com/storybookjs/rich-docs-with-storybook-mdx-61bc145ae7bc %}

Além disso, também tem esses links super importantes com documentações e exemplos:

- [Documentação do MDX com Angular](https://github.com/storybookjs/storybook/tree/next/addons/docs/angular#mdx)
- [Documentação geral do MDX](https://github.com/storybookjs/storybook/blob/next/addons/docs/docs/mdx.md)
- [Receitas para criações de histórias](https://github.com/storybookjs/storybook/blob/next/addons/docs/docs/recipes.md)
- [Lista de blocos em JSX disponíveis](https://github.com/storybookjs/storybook/tree/next/addons/docs/src/blocks)
- [Lista complementar de blocos em JSX](https://github.com/storybookjs/storybook/tree/next/lib/components/src/blocks)

> Antes de ir para a próxima sessão, se você já tem várias histórias criadas no Storybook no estilo do `storiesOf` ou `CSF` e quer mudar todas, ou algumas, para outro estilo, você pode dar uma olhada no [`codemod`](https://github.com/storybookjs/storybook/blob/next/lib/codemod/README.md). Ele tem scripts para mudar, em massa, as histórias de estilo e isso pode te poupar muito tempo.

> Pode comparar o seu progresso com a [tag v2.3 do repositório](https://github.com/klauskpm/angular-storybook/tree/v2.3)

----

# Storybook focado em Design

Quando lidamos com qualquer organização de um projeto, a parte mais difícil é a comunicação. Seja a falta ou o mau uso dela. Para resolver esse problema, em relação aos aspectos de Design de um sistema, existe o [Design System](https://brasil.uxdesign.cc/entendendo-design-system-f375bbb6f704).

Apesar de o Design System ser uma ótima solução, cada equipe tem um conjunto de ferramentas e elas vivem em seus universos isolados. Isso torna o trabalho de manter um Design System algo, um tanto que, trabalhoso.

Por esse motivo, eu fico muito feliz quando vejo o time do Storybook exibindo tantas integrações com essas essas ferramentas.

![Imagem mostrando, no lado esquerdo as integrações com ferramentas de Design: Sketch, Figma, Zeplin, Abstract, Invision e Adobe XD, com o Storybook, no lado direito, e o React, Vue e Angular](https://miro.medium.com/max/1944/1*zIZPDT1f9tL0hrLi5mTm6g.jpeg)[*Fonte*](https://medium.com/storybookjs/storybook-for-design-3ff761c579bf)

- [Figma addon](https://www.figma.com/resources/extensions-and-apis/storybook-figma-addon/)
  As mudanças de Design vão aparecer automaticamente no Storybook

- [Abstract addon](https://github.com/amccloud/storybook-addons-abstract) (para Sketch e Adobe XD)
  Abre um painel nas histórias do Storybook, onde você vê os layers e containers do Abstract

- [InVision Design System Manager](https://www.invisionapp.com/design-system-manager/learn/setting-up-storybook-in-dsm/)
  O DSM permite ver os componentes do Storybook, no app do DSM, junto dos designs extraídos do Sketch

- [Zeplin](https://blog.zeplin.io/introducing-connected-components-components-in-design-and-code-in-harmony-aa894ed5bd95)
  Linka e mostra uma minidocumentação dos componentes do Storybook direto com o app do Zeplin

- [Zeroheight](https://zeroheight.com/landing)
  O addon leva os componentes do Storybook para serem exibidos junto com os designs de outras ferramentas, como Sketch, Figma, ou Adobe XD

- [Story2sketch for Sketch](https://github.com/chrisvxd/story2sketch/)
  Converte histórias do Storybook em símbolos do Sketch

- [Design Token](https://github.com/UX-and-I/storybook-design-token)
  Transforma e exibe design tokens identificados em um painel no Storybook

![](https://miro.medium.com/max/1042/1*RnyPVhVKrNGT6sfXq2-mCg.jpeg)[*Fonte*](https://medium.com/storybookjs/storybook-for-design-3ff761c579bf)

São integrações para a equipe de Design ver os nossos componentes e usar eles nos próximos designs, ou para nós vermos os designs deles e compararmos cores, tamanhos e fontes. O objetivo é todos terem uma única fonte de verdade sobre os elementos de design e facilitar a manutenção e evolução do Design System

## Saber mais sobre

Se quiser saber mais detalhes sobre Storybook para Design, você pode ler o artigo oficial do Storybook:

{% medium https://medium.com/storybookjs/storybook-for-design-3ff761c579bf %}

----

# Conclusão

Além de facilitar a utilização e configuração, também adicionaram vários modos de criação de documentação (DocsPage e MDX) e várias integrações com as ferramentas de Design. O Storybook tem evoluído muito, e [vai continuar evoluindo](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md#600-alpha0-january-21-2020), para se tornar a ferramenta para criações de Design System.

Eu aprendi muito enquanto fazia esse artigo e espero que ele ajude você também.

Um forte abraço e até a próxima! :grimacing:

----

# Fontes

A base desse artigo foram os 4 artigos sobre o lançamento da nova versão do Storybook. Segue abaixo os links:
- [Declarative Storybook configuration](https://medium.com/storybookjs/declarative-storybook-configuration-49912f77b78)
- [Storybook Docs for new frameworks](https://medium.com/storybookjs/storybook-docs-for-new-frameworks-b1f6090ee0ea)
- [Rich docs with Storybook MDX](https://medium.com/storybookjs/rich-docs-with-storybook-mdx-61bc145ae7bc)
- [Storybook for Design](https://medium.com/storybookjs/storybook-for-design-3ff761c579bf)

Além desse artigos, também tiveram esses outros links:
- [CHANGELOG da versão 5.3](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md#530-january-11-2020)
- [Documentação sobre como usar o Storybook Docs/DocsPage no Angular](https://github.com/storybookjs/storybook/tree/next/addons/docs/angular)
- [Exemplos de histórias com Angular](https://github.com/storybookjs/storybook/tree/next/examples/angular-cli/src/stories)