Documentação de componentes em React com Typescript usando Storybook

griseduardo

Eduardo Henrique Gris

Posted on August 27, 2024

Documentação de componentes em React com Typescript usando Storybook

Introdução

Storybook é uma ferramenta que permite, dentre outras coisas, documentar componentes de forma isolada paralelamente à aplicação.
Nesse artigo, vou apresentar uma forma de customização da documentação de componentes, que fui aprendendo durante o desenvolvimento de um projeto pessoal que uso para estudo, que espero que auxilie a dar visibilidade a algumas opções dentre várias disponíveis usando essa lib. Será seguido as seguintes etapas:

  • setup: configuração do storybook
  • stories: definição dos principais cenários dos componentes a serem documentados
  • mdx: documentação dos componentes, trazendo as customizações definidas nos stories
  • exemplo: vai ser apresentado um exemplo de documentação de um componente

Cada componente terá seu próprio arquivo mdx e de stories.

Setup

Para adicionar o storybook em uma aplicação com React, com as configurações iniciais, é necessário executar no terminal: npx storybook init. Esse comando vai adicionar o storybook com base nas dependências do projeto. Para visualizar se ocorreu corretamente a adição, é executar no terminal: yarn storybook, e ver se é aberta uma página (nesse momento sem nenhum componente documentado).

Stories

Para cada componente vai ser definido um arquivo *.stories.tsx, onde será definido os cenários de customização mais importantes a serem documentados, seguindo a seguinte estrutura:

import React from "react";
import { Meta, StoryObj } from "@storybook/react";
import Component from "./Component";

const meta: Meta<typeof Component> = {
  component: Component,
  title: "Component",
  argTypes: {},
};
export default meta;

type Story = StoryObj<typeof Component>;

export const Scenario1: Story = (args) => (
  <>
    <Component {...args} />
    <Component {...args} props1="option1" />
    <Component {...args} props1="option2" />
  </>
);

Scenario1.args = {
  // (...),
  props1: "default"
};

// Scenario2
// Scenario3
Enter fullscreen mode Exit fullscreen mode

Dos imports do @storybook/react:

  • Meta: define a metadata do componente a ser documentado, nesse caso está se passando o componente em si em component e o título que vai parecer no menu lateral em title
  • StoryObj: permite definir os cenários de customização do componente a serem exibidos na documentação, que corresponde as definições de Scenario1, Scenario2... acima

Para cada cenário definido, vai ser criado uma entrada no menu lateral, dentro da "pasta" com o nome definido no title de Meta, com a seguinte estrutura:

  • Component
    • Scenario 1
    • Scenario 2
    • Scenario 3

Em Scenario1.args acima são definas as props default do componente a ser apresentado, com o objetivo de definir uma base de exibição do componente (pode ser por exemplo um texto para um botão como Button por exemplo).
Já em const Scenario1 é definido o componente a ser renderizado variando a props1, onde o objetivo é mostrar na documentação o que acontece com o componente ao mudar essa props.

MDX

Vai ser a documentação do componente, onde vai ser trazido os cenários presentes no arquivo de *.stories.tsx e definido textos para explicar as principais funcionalidades do componente, seguindo a seguinte estrutura:

import { ArgTypes, Canvas, Meta, Story } from '@storybook/blocks';
import * as Stories from './Component.stories';

<Meta of={Stories} />

# Component

Descrição do Component.

## Props

<ArgTypes />

## Predefined properties

### Scenario 1

Descrição do uso da props1.

<Canvas withToolbar>
  <Story of={Stories.Scenario1} />
</Canvas>

## Custom properties

// ### Scenario 2

// ### Scenario 3
Enter fullscreen mode Exit fullscreen mode

É um arquivo mix de markdown com javascript.
Dos imports do @storybook/blocks:

  • ArgTypes: retorna uma tabela com o nome de todas as props disponíveis pelo componente, a descrição delas (trazendo os Types das props) e se tem um valor default, isso de forma automatizada, pois o comando npx storybook init já adiciona na app o @storybook/addon-essentials. Para o caso de uma versão de storybook que não faz a instalação desse addon em conjunto, será necessário adicionar a lib com yarn add @storybook/addon-essentials --dev e no arquivo main.ts presente dentro da pasta .storybook adicionar em addons ela:
// ...
const config: StorybookConfig = {
  // ...
  addons: [
    // ...
    "@storybook/addon-essentials",
  ],
};
export default config;
Enter fullscreen mode Exit fullscreen mode

A tabela terá o seguinte layout:

Image description

  • Canvas: vai criar uma caixa onde os componentes do cenário a ser puxado do arquivo *.stories estarão presentes, que possui uma opção chamada Show code que mostra o código para usar o componente mostrado

Image description

  • Meta: define onde está o arquivo de stories associado a documentação, que vem do import import * as Stories from './Component.stories';

  • Story: permite renderizar os cenários definidos no arquivo de stories, englobado pelo Canvas para permitir ver o código também

Exemplo

Vou apresentar um exemplo simples de documentação partindo do que foi passado acima.
Começando pela criação de um componente definido em Tag.tsx:

import React from "react";
import styled from "styled-components";

export interface TagProps {
  text: string;
  backgroundColor?: string;
  type?: "success" | "alert" | "error";
}

export interface StyledTagProps {
  $backgroundColor?: string;
  $type?: "success" | "alert" | "error";
}

export const StyledTag = styled.div<StyledTagProps>`
  border: none;
  padding: 10px 12px;
  background-color: ${(props) =>
    props.$backgroundColor
      ? props.$backgroundColor
      : props.$type === "error"
        ? "#e97451"
        : props.$type === "alert"
          ? "#f8de7e"
          : props.$type === "success"
            ? "#50c878"
            : "#d3d3d3"};
  pointer-events: none;
  border-radius: 5px;
  width: fit-content;
`;

const Tag = ({
  text,
  backgroundColor,
  type,
}: TagProps) => (
  <StyledTag
    $type={type}
    $backgroundColor={backgroundColor}
  >
    <span>{text}</span>
  </StyledTag>
);

export default Tag;
Enter fullscreen mode Exit fullscreen mode

É um componente de Tag que tem uma propriedade predefinida type, ou seja, a própria app define o css associado de acordo com o type passado. Podendo ser error, alert e success.
E uma propriedade customizável backgroundColor, ou seja, customizável por quem está usando o componente, podendo escolher a cor que desejar.
No exemplo estou definindo o css a partir de uma lib chamada styled-components, mas a documentação é indiferente a forma que o css é definido.
E é definido os Types tanto das props do componente em si, quanto a referente ao styled component.

Agora será criado um componente específico para documentação StorybookContainer, que será responsável em centralizar dentro do Canvas do arquivo mdx, os componentes do cenário a ser mostrado, com um pequeno espaçamento entre eles. No arquivo StorybookContainer.tsx:

import React from "react";
import styled from "styled-components";

export interface StorybookContainerProps {
  children: React.ReactNode;
}

export const StyledStorybookContainer = styled.div`
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
`;

const StorybookContainer = ({ children }: StorybookContainerProps) => (
  <StyledStorybookContainer>
    {children}
  </StyledStorybookContainer>
);

export default StorybookContainer;
Enter fullscreen mode Exit fullscreen mode

Vai ser criado o arquivo Tag.stories.tsx com os dois cenários a serem apresentados na documentação:

import React from "react";
import { Meta, StoryObj } from "@storybook/react";
import Tag from "./Tag";
import StorybookContainer from "../StorybookContainer/StorybookContainer";

const meta: Meta<typeof Tag> = {
  component: Tag,
  title: "Tag",
  argTypes: {},
};
export default meta;

type Story = StoryObj<typeof Tag>;

export const PredefinedType: Story = (args) => (
  <StorybookContainer>
    <Tag {...args} />
    <Tag {...args} text="Success" type="success" />
    <Tag {...args} text="Alert" type="alert" />
    <Tag {...args} text="Error" type="error" />
  </StorybookContainer>
);

PredefinedType.args = {
  text: "Default",
};

export const BackgroundColor: Story = (args) => (
  <StorybookContainer>
    <Tag {...args} />
    <Tag {...args} backgroundColor="#89cff0" />
    <Tag {...args} backgroundColor="#f0aa89" />
  </StorybookContainer>
);

BackgroundColor.args = {
  text: "Tag",
  backgroundColor: "#d3d3d3",
};
Enter fullscreen mode Exit fullscreen mode

Foram definidos dois cenários no arquivo, para mostrar como o componente muda com a variação da props type (que é uma propriedade pre-definida na app) e como o componente muda com a variação da props backgroundColor (que é uma propriedade customizável, pois o usuário pode passar a cor que quiser usar).

Por fim vai ser criado o arquivo da documentação do componente Tag.mdx, onde vai ser mostrada os dois cenários definidos no arquivo de stories:

import { ArgTypes, Canvas, Meta, Story } from '@storybook/blocks';
import * as Stories from './Tag.stories';

<Meta of={Stories} />

# Tag

Tag base component.

## Props

<ArgTypes />

## Predefined properties

### Type

There are three type predefined properties: success, alert and error.

<Canvas withToolbar>
  <Story of={Stories.PredefinedType} />
</Canvas>

## Custom properties

### BackgroundColor

Tag backgroundColor can be modified.

<Canvas withToolbar>
  <Story of={Stories.BackgroundColor} />
</Canvas>
Enter fullscreen mode Exit fullscreen mode

Onde vai estar descrito o componente que está sendo mostrado, com uma tabela mostrando as prop dele devido a inclusão do <ArgTypes />, onde vai ser mostrado um cenário de customização usando a variação da props type (propriedade pre-definida) e vai ser mostrado um cenário usando a variação da props backgroundColor (propriedade customizável).

Por fim, é executar no terminal yarn storybook.
Ficando o menu lateral da seguinte forma:

Image description

E a documentação da seguinte forma:

Image description

E clicando em Show code em um dos cenários, é mostrado o código associado:

Image description

Conclusão

A ideia desse artigo foi apresentar uma ferramenta de documentação de componentes que permite customizar a documentação usando um arquivo mdx de diversas formas, a partir de blocks que a lib fornece. Foi apresentado um modo de escrita desse arquivo de documentação, mas dado a várias possibilidades que a lib fornece, vou colocar nas referências alguns links para quem quiser se aprofundar mais no assunto.

Referências

Stories File
Blocks
Argtypes Block
Canvas Block
Meta Block
Stories Block
MDX File

💖 💪 🙅 🚩
griseduardo
Eduardo Henrique Gris

Posted on August 27, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related