Lab 06: Documentation - andreaswissel/design-systems-workshop GitHub Wiki

Hint: if you got lost, you can always check out the corresponding branch for the lab. If you want to start over, you can reset it by typing executing git reset --hard origin/lab-5

Lab

We've provided quite a bit of functionality by now. To share the knowledge with anyone that is using this functionality, we need to work on the favorite task of every developer: Documentation!

Inline documentation

Let's first start off by writing some good old code comments. By default, Storybook will parse these comments through JS Doc and render them in the Docs tab. We will refer to this kind of documentation as inline documentation from now on. Writing inline documentation is always a good idea, as this is not only accessible through Storybook, but also when using IDEs. Fellow developers can inspect the components in their IDEs and get a very quick idea of what's going on, and where they can get further information.

Our ButtonComponent doesn't have any documentation yet, so why don't we start off by adding some context to it?

  • Add code comments to src/app/button/button.component.ts
import { Component, Input, OnInit } from '@angular/core';

export type ButtonType = 'primary' | 'secondary';

+/**
+ * This is the button component. It can be used to build clicky things!
+ *
+ * [Figma reference](https://www.figma.com/file/X1JRLUCEp6JnoeKAxRPNeF/Angular-Architects-Design-Systems?node-id=1%3A3)
+ *  |
+ * [Implementation](https://github.com/andreaswissel/design-systems-workshop-latest/blob/lab-6/src/app/button/button.component.ts)
+ *  |
+ * [Specification](https://github.com/andreaswissel/design-systems-workshop/wiki/Lab-06:-Documentation)
+ */
@Component({
  selector: 'app-button',
  templateUrl: './button.component.html',
  styleUrls: ['./button.component.scss'],
})
export class ButtonComponent implements OnInit {
  @Input() public label: string = 'Button Label';
  @Input() public type: ButtonType = 'primary';

  constructor() {}

  ngOnInit(): void {}
}

As you can see, adding inline documentation is very straight forward. It follows the plain old principle of multi-line comments and renders right away in the Docs tab. Once you've restarted Storybook (Compodoc only does a full scan on startup due to performance reasons) your documentation should pop right up:

Documenting pretty much anything using DocBlocks and the MDX format

Another way of documenting things in Storybook is the MDX format. It is an extended version of the Markdown format, which is also able to display Storybook components (and much more). Storybook provides us with a few building blocks for MDX called Doc Blocks. With the Doc Blocks, we can render stories, components and even fully auto-generated tables containig inputs and outputs. We'll start things slowly with an easy example, though.

  • Create MDX file in src/app/button/button.mdx with the contents listed below:
import { Meta } from "@storybook/blocks";
import * as ButtonStories from "./button.stories";

# Button Component

[Source code](https://github.com/andreaswissel/cypress-storybook-testing-talk/tree/main/projects/lego/src/components/Button)
 | 
[Figma reference](https://github.com/andreaswissel/cypress-storybook-testing-talk/tree/main/src/components/Button)
 | 
[Usage guidelines](#usage-guidelines)

<Meta of={ButtonStories} name="Overview" />

Once you've added the MDX file, it should show right up in Storybook:

Adding a component to an MDX page

As we've learned before, MDX pages can also be used to display components. This requires a bit more manual labour on our side, as we're now manually creating the docs.

  • Import and use Doc Blocks

To display the story inside our Docs Page, we need to import the required Doc Blocks. Additionally to the Meta block, we'll make use of Canvas and Story. We know those already from our first story. The canvas is the area that's hosting the actual Angular component, whereas the story is the hierarchical element in the component explorer.

-import { Meta } from "@storybook/addon-docs/blocks";
+import { Meta, Story, Canvas, ArgsTable } from "@storybook/blocks";
import * as ButtonStories from "./button.stories";

# Button Component

[Source code](https://github.com/andreaswissel/cypress-storybook-testing-talk/tree/main/projects/lego/src/components/Button)
&nbsp;|&nbsp;
[Figma reference](https://github.com/andreaswissel/cypress-storybook-testing-talk/tree/main/src/components/Button)
&nbsp;|&nbsp;
[Usage guidelines](#usage-guidelines)

<Meta of={ButtonStories} name="Overview" />

+<Canvas>
+  <Story of={ButtonStories.Default} />
+</Canvas>

As you can see, this will bring to live the same setup we've seen before, but right inside our MDX documentation. How cool is that?

If everything went right, your docs story should now look like this:

  • Lastly, write some prose

Try to get a bit creative here! How would you document the component? This is how I did it:

Self check

  • You should see the inline documentation on the ButtonComponent
  • You should see the MDX Format Story
  • The MDX format story should contain a canvas with the ButtonComponent

Bonus level

  • create a src/docs folder and put some documentation in there that either combines multiple component(s/states) or add any other document!
MDX file

src/app/button/button.mdx

import { Meta, Story, Canvas, Controls } from "@storybook/blocks";
import * as ButtonStories from "./button.stories";

# Button Component

[Source code](https://github.com/andreaswissel/cypress-storybook-testing-talk/tree/main/projects/lego/src/components/Button)
&nbsp;|&nbsp;
[Figma reference](https://github.com/andreaswissel/cypress-storybook-testing-talk/tree/main/src/components/Button)
&nbsp;|&nbsp;
[Usage guidelines](#usage-guidelines)

<Meta of={ButtonStories} name="Overview" />

<Canvas>
  <Story of={ButtonStories.Default} />
</Canvas>

## Getting started

You can implement the Button component by importing the `ButtonComponent` into your NgModule / Standalone Component.
import { ButtonComponent } from "@library/button";

The button has to one required attribute: `label`. The `label` specifies the button label text as a string.
You can also optionally configure a type of button by specifying a `type` attribute on the button.

## Usage guidelines

Avoid using the button as a link and vice-versa. It is a good idea to provide semantic labels, that give the user an idea of the action behind the button. Try to be more specific than `New` or `Save`,
e.g. try using `Create new item` or `Update item`.

## Component API

<Controls />
Stories file
`src/app/button/button.stories.ts`
import type { Meta, StoryObj } from '@storybook/angular';

import { ButtonComponent } from './button.component';

const meta: Meta<ButtonComponent> = {
  title: 'Components/Button',
  component: ButtonComponent,
  tags: ['autodocs'],
};

export const Default: StoryObj<ButtonComponent> = {
  args: {},
};

export default meta;
Component file

src/app/button/button.component.ts

import { Component, Input } from '@angular/core';

type ButtonType = 'primary' | 'secondary';

/**
 * This is the button component. It can be used to build clicky things!
 *
 * [Figma reference](https://www.figma.com/file/X1JRLUCEp6JnoeKAxRPNeF/Angular-Architects-Design-Systems?node-id=1%3A3)
 *  |
 * [Implementation](https://github.com/andreaswissel/design-systems-workshop-latest/blob/lab-6/src/app/button/button.component.ts)
 *  |
 * [Specification](https://github.com/andreaswissel/design-systems-workshop/wiki/Lab-06:-Documentation)
 */
@Component({
  selector: 'app-button',
  standalone: true,
  imports: [],
  templateUrl: './button.component.html',
  styleUrl: './button.component.scss',
})
export class ButtonComponent {
  @Input() public label: string = 'Button Label';
  @Input() public type: ButtonType = 'primary';
}
bonus level: MDX file

src/docs/adr-001.mdx

import { Meta, Story, Canvas, ArgsTable } from "@storybook/blocks";

<Meta name="ADR" />

# Configuration for the Jekyll template "Just the Docs"

parent: Decisions
nav_order: 100
title: ADR Template
status: proposed | rejected | accepted | deprecated | … | superseded by [ADR-0005](0005-example.md)
date: YYYY-MM-DD when the decision was last updated
deciders: list everyone involved in the decision
consulted: list everyone whose opinions are sought (typically subject-matter experts); and with whom there is a two-way communication
informed: list everyone who is kept up-to-date on progress; and with whom there is a one-way communication

we need to disable MD025, because we use the different heading "ADR Template" in the homepage (see above) than it is foreseen in the template
markdownlint-disable-next-line MD025

# Short title of solved problem and solution

## Context and Problem Statement

Describe the context and problem statement, e.g., in free form using two to three sentences or in the form of an illustrative story.
 You may want to articulate the problem in form of a question and add links to collaboration boards or issue management systems.

This is an optional element. Feel free to remove.
## Decision Drivers

* decision driver 1, e.g., a force, facing concern, …
* decision driver 2, e.g., a force, facing concern, …
* … numbers of drivers can vary

## Considered Options

* title of option 1
* title of option 2
* title of option 3
* … numbers of options can vary

## Decision Outcome

Chosen option: "title of option 1", because
justification. e.g., only option, which meets k.o. criterion decision driver | which resolves force force | … | comes out best (see below).

This is an optional element. Feel free to remove.
### Consequences

* Good, because positive consequence, e.g., improvement of one or more desired qualities, …
* Bad, because negative consequence, e.g., compromising one or more desired qualities, …
* … numbers of consequences can vary

This is an optional element. Feel free to remove.
## Validation

describe how the implementation of/compliance with the ADR is validated. E.g., by a review or an ArchUnit test

This is an optional element. Feel free to remove.
## Pros and Cons of the Options

### title of option 1

This is an optional element. Feel free to remove.
example | description | pointer to more information | …

* Good, because argument a
* Good, because argument b
use "neutral" if the given argument weights neither for good nor bad
* Neutral, because argument c
* Bad, because argument d
* … numbers of pros and cons can vary

### title of other option

example | description | pointer to more information | …

* Good, because argument a
* Good, because argument b
* Neutral, because argument c
* Bad, because argument d
* …

This is an optional element. Feel free to remove.
## More Information

You might want to provide additional evidence/confidence for the decision outcome here and/or
 document the team agreement on the decision and/or
 define when this decision when and how the decision should be realized and if/when it should be re-visited and/or
 how the decision is validated.
 Links to other decisions and resources might here appear as well.
⚠️ **GitHub.com Fallback** ⚠️