Skip to content

Latest commit

 

History

History
145 lines (102 loc) · 5.92 KB

creating-examples.md

File metadata and controls

145 lines (102 loc) · 5.92 KB

Writing Storybook stories

To provide better a visual experience to end users and simplify workflow with creating storybook stories, we completely dropped the original API from storybook for creating stories.

One of the main reasons was that the code wasn’t DRY, it required a lot of boilerplate and you are not able to provide pretty examples to end users.

To help you creating sample examples you can leverage our scaffolding tool yarn generate:example which will scaffold skeleton of an example story.

PicassoBook

PicassoBook is our own API for writing Storybook stories. It is a simple chain API builder which collects all metadata for creating the following important things:

Generating new Page inside documentation (Story Book).

const page = PicassoBook
  .section('Components')
  .createPage(
    'Component',
    'Description of component'
  )

💡 TIP: When writing description it is prefered to add links to BASE description(if there is one) and source code of component.

💡 TIP: You can see real example here src/components/Button/story/index.jsx#L7

Generating automatic PropsTable from the passed component through AST parsing.

page
  .createTabChapter('Props')
  .addComponentDocs({
    component: Component,
    name: 'Component'
  })

💡 TIP: You can see real example here src/components/Button/story/index.jsx#L13

Extending default capability of Storybook where you can specify only one example per component.

import PicassoBook from '~/.storybook/components/PicassoBook'

import buttonGroupStory from '@components/ButtonGroup/story'

page.createChapter(...).addComponentDocs(buttonGroupStory.componentDocs)

💡 TIP: You can see real example here src/components/Button/story/index.jsx#L23

Grouping related components to a single Page inside the documentation (Button, Button.Group)

page.connect(buttonGroupStory.chapter)

💡 TIP: You can see real example here src/components/Button/story/index.jsx#L47

Generating screenshots automatically based on provided examples

page.createChapter(...).addExample('Component/story/Default.example.jsx') // this is all you need to do, live code will be screenshoted and compared inside CI automatically

💡 TIP: You can see real example here src/components/Button/story/index.jsx#L27

Showing separate Live editor for examples and keep examples separated from story definition.

page.createChapter(...).addExample('Component/story/Default.example.jsx') // this is all you need to do, live code editor will be automatically injected to the page

💡 TIP: You can see real example here src/components/Button/story/index.jsx#L27

PicassoBook.Page

Page is the main building component which is composed of the following parts

  • Title
  • Description
  • Props Table
  • Chapters
    • Text
    • TabChapters
      • ComponentDocs
    • Examples

Page holds all the necessary metadata for generating full documentation page.

Example of how to compose a page can be found at src/components/Button/story/index.jsx

Examples

As we created own renderer for examples and Live editor for them, we are able to separate all examples to separate files and the full content of this example is always shown inside the editor.

We want to make these examples as clean and as nice as possible, their purpose is not just to “render” documentation example, but the more important purpose is to let people easily copy paste sources of examples and use them. In consideration of that, we always need to think of what to put to examples and what not. If you see that some component is complex try to simplify it or omit some logic. In consideration of that, we always need to think about what to put or omit from example.

DOs and DON’Ts inside examples

DOs

  • Create simple and readable examples, which can be simply copied/pasted to the project 'as it is'
  • Name all components inside examples with meaningful names
  • Pay attention to code styling
  • Create examples for all possible states inherited from props, they are not only used for the documentation but also for visual tests
  • Try to avoid using stateful components, use hooks if you need to have state
  • Try to show only one meaningful feature per example
  • The Default example is needed to show the minimum component setup to be used

DON’Ts

  • Don’t introduce crazy helpers inside examples instead list all implementation variants by hand

  • Don’t abstract any helpers for generating props (e.g createButtonVariant) but write every variation by hand

bad_example.jsx

const createButton = (variant) => (<Button variant={variant} >{variant}</Button>)

const Example = () => {
  return (
    <div>
      {createButton('primary')}
      {createButton('secondary')}
    </div>
  )
}

good_example.jsx

const Example = () => {
  return (
    <div>
      <Button variant='primary'>Primary</Button>
      <Button variant='secondary'>Secondary</Button>
    </div>
  )
}
  • Don’t create large examples which are requiring a lot of cleaning after copy pasting
  • Don’t hide any implementation details
  • Don’t create variables unless it is critically necessary for examples to be run. (e.g. don’t extract style={style} rather list everything manually so it can be easily copy pasted to other application