npm package: @funda/storybook-wrapper-helper
Description: storybook warpper helper
Latest version: 2.1.0
Deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.

# Storybook wrapper helper

## Installation

1. `npm install --save-dev @funda/storybook-wrapper-helper` (depending on your
   project configuration, you may want to install this as a regular dependency)
1. register the 'storybook-addon-designs' addon in storybook main.js
1. import `story` and `book` functions in your story and follow the
   [usage docs](#usage)

Register storybook addon example

```js
// main.js
module.exports = {
  addons: ['storybook-addon-designs'],
}
```

## Why?

Why where these wrapper components created?
Why not write stories just like I see in the storybook documentation?

As long as wrappers do not confuse the developer, any steps that can be taken
to reduce the amount of code that the developer is copying and pasting, the
better. This will reduce errors and will make writing stories more enjoyable.
This makes stories look more cohesive and reduces distractions for a book (a
collection of stories) where most of the stories have their own templates and
args.

Storybook stories will also go through improvements between Story Component
Format (SCF) v2 SCF v3, and breaking changes between Vue v2 and Vue v3.
While updating a single story through a breaking change is a trivial
task, reformatting every story written, would take a lot of
time. This should allow us to move through the breaking changes by only
changing the internals of a function that generates a story.

For more information on why this will still be relevant for the forseeable
future, please read the [roadmap](./ROADMAP.md).

## Usage

All configuration here is built from functional components, so a developer
will be able to easily debug any storybook configuration by seeing the
output of each of these functions. While the helper functions could further
abstract a storybook implementation, this crosses a line where obfuscation
begins to be a hinderance when a developer is debugging, or joining this
project for the first time.

### Single story book

If you just have a single story, then you can use the story function directly.
Any information that you need in your story needs to be added as parameters to
the story function.

```js
import { story, book } from '@funda/storybook-wrapper-helper';

// import your component that you are going to test
import SaveBox from '../SaveBox.vue';

const bookSettings = book({
    // define the folder structure for your component
    title: 'Advertisement/Create/Save Box',
    component: { SaveBox },
});

export default bookSettings;

export const Default = story({
    // all of the work that the book function does for you is included here
    ...bookSettings,
    args: {
        disabled: false,
        canBuy: false,
        waiting: false,
    },
});
```

### Multi-story book

```js
import { story, defaultStory, book } from '@funda/storybook-wrapper-helper';

// import your component that you are going to test
import UiUploadButton from '../UiUploadButton.vue';


const bookSettings = book({
    title: 'UI/Buttons/Upload',
    component: { UiUploadButton },
    // this will show up on the docs tab in storybook
    description: 'A generic upload button',
    // these will be the default arguments and will be merged with args at the
    // story level.
    defaultArgs: {
        uploadText: 'Upload a file',
        errorMessage: '',
        accept: '*',
        multiple: false,
        showFileNames: false,
    }
});

export default bookSettings;

// These stories simply rely on the values generated by the book function, and
// extend or override values when needed.

export const Default = story(bookSettings);
export const DifferentUploadText = story({
    ...bookSettings,
    description: 'An upload button that suggests the user add an image',
    args: {
        uploadText: 'Add an image',
    },
});

// This uploadButtonStory function will return all the information storybook
// needs to make a story. Args can be passed in to override any default values
function uploadButtonStoryWithMargin(args) {
    return defaultStory({
        // all of the work that the book function does for you is included here
        ...bookSettings,
        // a default template that shows what the component looks like if a
        // margin is added into the component
        defaultTemplate: '<UiUploadButton v-bind="$props" class="mt-3"></UiUploadButton>',
        ...args,
    });
}

// For these stories, we are using the defaultStories that have a custom
// template. Since the uploadButtonStoryWithMargin function already includes the
// bookSettings, we do not need to do that.

export const DifferentUploadValidation = uploadButtonStoryWithMargin({
    description: 'An upload button that allows any kind of video type',
    args: {
        accept: 'video/*',
        uploadText: 'Add a video',
    },
});
export const Error = uploadButtonStoryWithMargin({
    args: {
        errorMessage: 'The image that you tried to upload is too small',
    },
});
export const MultipleSelection = uploadButtonStoryWithMargin({
    description: 'An upload button that allows the user to upload more than one thing',
    args: {
        multiple: true,
    },
});
export const ShowFileNames = uploadButtonStoryWithMargin({
    args: {
        showFileNames: true,
        multiple: true,
    },
});

```

### A full example

This is an example of a component that makes use of every option in the `story`
function configuration.

```js
import { story, book } from '@funda/storybook-wrapper-helper';

// import your component that you are going to test
import SaveBox from '../SaveBox.vue';
import SuccessNotification from '../SuccessNotification.vue';

const bookSettings = book({
    // define the folder structure for your component
    title: 'Advertisement/Create/Save Box',
    component: { SaveBox },
    // when @close and @save are triggered, it will be logged in the actions pane
    events: ['close', 'save', 'mouse-in-zone'],
    design: [
        {
            type: 'figma',
            url: 'https://www.figma.com/file/file-key',
        },
        {
            type: 'link',
            url: 'https://www.figma.com/file/file-key-2',
        },
    ],
    description: "A save box for an advertisement",
    links: [
      {
        name: "Business requirements document",
        value: "https://intranet.funda.nl/example/SaveBox/documentation"
      },
    ],
    // add a little bit of margin around all our stories
    decorators: ['<div class="m-3"><story/></div>'],
});

export default bookSettings;

export const Default = story({
    // all of the work that the book function does for you is included here
    ...bookSettings,
    // arguments for our component
    args: {
        disabled: false,
        canBuy: false,
        waiting: false,
    },
    // allow us to use the SuccessNotification in our custom template
    additionalComponents: { SuccessNotification },
    description: 'A custom description for this component',
    // wrap this story in a custom div that constrains the max width
    decorators: ['<div style="max-width: 800px;"><story/></div>'],
    // set our background color to a custom shade of blue
    parameters: {
      backgrounds: {
        default: 'custom-blue',
        values: [
            {
                name: 'custom-blue',
                value: '#139ec1'
            }
        ]
      },
    },
    // include our SuccessNotification, overriding the default slot in our
    // SaveBox component. Note that the props and actions must be bound in this
    // template or you will disconnect them from the story.
    template: `
      <SaveBox
        v-bind="$props"
        @close="close"
        @save="save"
        @mouse-in-zone="mouseInZone"
     >
        <SuccessNotification>You did it!</SuccessNotification>
      </SaveBox>
    `
});
```

### Automatic features

If you specify a book that has a title that starts with `page` (case
insensitive), the layout of the story will be full screen to closer emulate
what the page will look like (especially on mobile devices). This can be
overwritten at the story level.

```js
const bookSettings = book({
    title: 'Page/Home',
    component: { ... }
});
```

### Typescript

This project is written in TypeScript, which provides helpful hints to
developers consuming this package. Even if you are not using TypeScript in your
project, editors like VSCode include the ability to enable type checking in
normal JS files.

While storybook does have
[some TypeScript support](https://storybook.js.org/docs/vue/configure/typescript)
for the components that you are testing, there seems to be no complete
TypeScript definition for the interface that defines stories in
`@storybook/vue`. Ideally, this project imports types from the
`@storybook/vue` and/or `@storybook/csf` packages and extends them to fit the
needs of this wrapper, but for now, the plan is to define all types here until
the API has been proven to work in a variety of situations across several Funda
applications.

## Getting started

- `npm install`
- `npm run build` (if you want to check the build output)

The directory `src/lib` is where you will spend most of your time.
All remaining directories are just there to help you focus on building the component in an efficient way.

## Contributing

### How to push your changes

This repo uses [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) and uses [commitlint](https://github.com/conventional-changelog/commitlint) to enforce it. This means that you need to follow a set of rules otherwise you don't be able to commit. This is required for automating the release of the package.

Examples of commit messages:

* `feat(branch_name): new feature added`
* `fix(branch_name): fix added`

PS: It is recommended to use the terminal for commit, if you use any GUI it might be necessary to update you local variable PATH on your GUI.
Reference: [Husky issues](https://typicode.github.io/husky/#/?id=command-not-found)

### Releasing a new version

This project uses [semantic-release](https://semantic-release.gitbook.io/semantic-release/) a tool that will automatically releases, increment the package version and generate a changelog entry based on the new commits.
Simply following the commitlint standard and merging your changes into main will release the project.

## Consuming the package locally

If don't want to publish a new version and you just want to test it locally you can use `npm run link-local` on the package and then `npm link @funda/storybook-wrapper-helper` on the project.

Keep in mind that some tools don't understand file symlink (what npm link uses) and that can cause problems.

## Ownership

This codebase is owned by **FE Cluster**

For questions about this codebase contact a frontend engineer or email **devteam-frontend@funda.nl**