Introdução
English version: Documentation of components in React with TypeScript using Storybook (version 8)
Anteriormente escrevi em um artigo sobre a documentação de componentes usando storybook, quando a versão estava abaixo da 8. Devido a algumas mudanças que vieram com essa versão e ter me aprofundado mais com a lib, estou escrevendo uma versão atualizada nesse artigo.
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 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 detectar as dependências do projeto e pode apresentar algumas perguntas durante o processo. Alguns exemplos:
- se está usando
webpack
ouvite
no projeto - se é para documentação ou testes
No caso seria escolher a que corresponde ao seu projeto e no contexto de documentação, informar isso quando perguntar.
Observação: algumas libs usam o rollup
ao invés de vite
e webpack
, em uma lib que uso para estudo, que usa rollup
, escolhi a opção do vite
e funciona bem, mas precisa adicionar duas novas libs:
yarn add vite @storybook/builder-vite --dev
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 type { Meta, StoryObj } from "@storybook/react"; import Component from "./Component"; const meta: Meta<typeof Component> = { title: "Component", component: Component, argTypes: {}, }; export default meta; type Story = StoryObj<typeof Component>; export const Default: Story = { args: {}, render: (args) => ( <Component {...args} /> ), }; export const Scenario1: Story = { args: {}, render: (args) => ( <> <Component {...args} /> <Component {...args} props1="option1" /> <Component {...args} props1="option2" /> </> ), }; // Scenario2 // Scenario3
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 emtitle
- StoryObj: permite definir os cenários de customização do componente a serem exibidos na documentação, que corresponde as definições de
Default
,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
- Default
- Scenario1
- Scenario2
- Scenario3
Em Default
é renderizado o componente com as propriedades default dele.
Em args: {}
do Scenario1
acima não foi passado nenhuma props, com o objetivo de trazer na primeira renderização do componente uma base com o comportamento default dele.
Já nas duas outras renderizações do Scenario1
é variada a props props1
, onde o objetivo desse cenário é 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 { Canvas, Controls, Meta, Story } from '@storybook/blocks'; import * as Stories from './Component.stories'; <Meta of={Stories} /> # Component Descrição do Component. <Canvas of={Stories.Default} withToolbar /> <Controls of={Stories.Default} /> ## Predefined properties ### Scenario 1 Descrição do uso da props1. <Canvas of={Stories.Scenario1} withToolbar /> ## Custom properties // ### Scenario 2 // ### Scenario 3
É um arquivo mix de markdown com javascript.
Dos imports do @storybook/blocks
:
- 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 chamadaShow code
que mostra o código para usar o componente mostrado:
- Controls: vai trazer uma tabela com o nome de todas as props disponíveis pelo componente, a descrição delas (trazendo os types das props), se tem um valor default e um lugar onde pode ser mexida as props do componente para visualizar as mudanças que acontecem. Colocando em conjunto:
<Canvas of={Stories.Default} withToolbar /> <Controls of={Stories.Default} />
Está se definindo que o Controls vai impactar o componente que vem de Stories.Default
e acima está se trazendo ele <Canvas of={Stories.Default} withToolbar />
, então a cada mudança de props vai dar para ver como o componente vai sendo customizado:
- Meta: define onde está o arquivo de stories associado a documentação, que vem do import
import * as Stories from './Component.stories';
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?: "default" | "success" | "alert" | "error"; } export interface StyledTagProps { $backgroundColor?: string; $type?: "default" | "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" : props.$type === "default" && "#d3d3d3"}; pointer-events: none; border-radius: 5px; width: fit-content; `; const Tag = ({ text="Tag", backgroundColor, type="default", }: TagProps) => ( <StyledTag $type={type} $backgroundColor={backgroundColor} > <span>{text}</span> </StyledTag> ); export default Tag;
É 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 default
, 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;
Vai ser criado o arquivo Tag.stories.tsx
com o Default e os dois cenários a serem apresentados na documentação:
import React from "react"; import type { Meta, StoryObj } from "@storybook/react"; import Tag from "./Tag"; import StorybookContainer from "../StorybookContainer/StorybookContainer"; const meta: Meta<typeof Tag> = { title: "Tag", component: Tag, argTypes: {}, }; export default meta; type Story = StoryObj<typeof Tag>; export const Default: Story = { args: {}, render: (args) => ( <StorybookContainer> <Tag {...args} /> </StorybookContainer> ), }; export const PredefinedType: Story = { args: {}, render: (args) => ( <StorybookContainer> <Tag {...args} /> <Tag {...args} type="success" /> <Tag {...args} type="alert" /> <Tag {...args} type="error" /> </StorybookContainer> ), }; export const BackgroundColor: Story = { args: { backgroundColor: "#d3d3d3", }, render: (args) => ( <StorybookContainer> <Tag {...args} /> <Tag {...args} backgroundColor="#89cff0" /> <Tag {...args} backgroundColor="#f0aa89" /> </StorybookContainer> ), };
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 { Canvas, Controls, Meta } from "@storybook/blocks"; import * as Stories from "./Tag.stories"; <Meta of={Stories} /> # Tag Tag base component. <Canvas of={Stories.Default} withToolbar /> <Controls of={Stories.Default} /> ## Predefined properties ### Type There are four predefined types: default, success, alert and error. <Canvas of={Stories.PredefinedType} withToolbar /> ## Custom properties ### Background Color Tag background color can be modified. <Canvas of={Stories.BackgroundColor} withToolbar />
Onde vai estar descrito o componente que está sendo mostrado, com uma tabela permitindo controlar as prop do componente logo acima dela devido a inclusão do <Controls />
, 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:
E a documentação da seguinte forma:
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
Controls Block
Canvas Block
Meta Block
Stories Block
MDX File
Top comments (0)