Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Show all variations of a component on a single page in React Storybook but still have Knobs?

I have a button component that can be of different types eg primary, secondary, etc:

export const buttonTypes = [
  'primary',
  'secondary',
  'tertiary',
  'positive',
  'negative',
]

const Button = ({ text, type }) => {
    return(
        <button className={type}>{text}</button>
    )
}

Button.propTypes = {
    text: PropTypes.string,
    type: PropTypes.oneOf(buttonTypes),
}

In my Storybook file I'm mapping through the options. This means you can see all the variants on a single page and if another string was added to the buttonTypes array it would automatically be added to the style guide:

import ButtonComponent, { buttonTypes } from './Button';

const Button = () => {
    return(
        <div>
            {
                buttonTypes.map(type=>(
                    <ButtonComponent key={type} text={type} type={type} />
                ))
            }
        </div>
    )
}

export default {
  title: 'Components',
  component: Button,
};

The problem is that this doens't work with with many of the add-ons eg knobs. For knobs to work you need Button to be the actual component, not a wrapper as I did above.

import ButtonComponent, { buttonTypes } from './Button';

const Button = () => {
  return (
    <ButtonComponent
      type={select('type', buttonTypes, buttonTypes.primary)}
      text="Button"
    />
  );
};

Is there a way to use knobs and show all the variations on a single page? Ideally without having to create each component manually as this is more work and then won't automatically update if a new string is added to buttonTypes.

like image 507
Evanss Avatar asked May 21 '20 09:05

Evanss


People also ask

What is knob in storybook?

Storybook Addon Knobs allow you to edit props dynamically using the Storybook UI. You can also use Knobs as a dynamic variable inside stories in Storybook. Framework Support. This is what Knobs looks like: Checkout the above Live Storybook or watch this video.

What is ArgTypes storybook?

ArgTypes are a first-class feature in Storybook for specifying the behaviour of Args. By specifying the type of an arg, you constrain the values that it can take and provide information about args that are not explicitly set (i.e., not required).


Video Answer


1 Answers

Use the grouping feature of knobs, that way each instance of your component will get its own knob instance instead of all the knob instances being shared between all of the component instances. You can even mix grouped knobs with non-grouped nobs if you want certain things to be shared and other not to be.

In the following example, I have a <Button/> story where each instance has its own copy of the type and disabled properties, but the text is shared between them all.

Each button type gets its own panel where you can set its type and disabled. The "Other" group contains any knobs that didn't have their group set (such as text).

Button StoryBook Example

src/Button/Button.component.jsx

import * as React from "react";

import "./Button.style.css";

export const Button = ({
    text,
    type,
    disabled,
    onClick
}) => (
    <button
        className={`button button--${type} ${disabled ? "button--disabled" : ""}`}
        disabled={disabled}
        onClick={onClick}
        children={text}
    />
);

src/Button/Button.stories.jsx

import * as React from "react";
import {withKnobs, text, boolean, select} from "@storybook/addon-knobs";
import {action} from "@storybook/addon-actions";

import {Button, buttonTypes} from "./";

export default {
    title: "Button",
    component: Button,
    decorators: [withKnobs]
};

export const ButtonStory = () => {
    const buttontext = text("Text", "Click Me");

    return (
        <div>
            {buttonTypes.map(buttonType => (
                <div key={buttonType}>
                    <Button
                        type={select("Type", buttonTypes, buttonType, buttonType)}
                        disabled={boolean("Disabled", false, buttonType)}
                        onClick={action(`${buttonType} clicked`)}
                        text={buttontext}
                    />
                </div>
            ))}
        </div>
    );
};

ButtonStory.story = {
    name: "All"
}

src/Button/Button.types.js

export const buttonTypes = [
    "primary",
    "secondary",
    "tertiary"
];

src/Button/Button.style.css

.button {
    padding: 0.5em;
    font-size: 1.25em;
    border-radius: 10px;
    border-width: 2px;
    border-style: solid;
    border-color: black;
}

.button--primary {
    background-color: rgb(132, 198, 106);
    color: black;
    border-color: black;
}

.button--secondary {
    background-color: rgb(194, 194, 194);
    color: black;
    border-color: black;
}

.button--tertiary {
    background-color: transparent;
    color: inherit;
    border-color: transparent;
}

.button--disabled {
    background-color: rgb(194, 194, 194);
    color: rgb(105, 102, 102);
    border-color: rgb(105, 102, 102);
}

src/Button/index.js

export {Button} from "./Button.component";
export {buttonTypes} from "./Button.types";
like image 81
zero298 Avatar answered Sep 19 '22 12:09

zero298