web-dev-qa-db-ja.com

React Storybookのコンポーネントのすべてのバリエーションを1つのページに表示しますが、ノブはありますか?

primarysecondaryなど、さまざまなタイプのボタンコンポーネントがあります。

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),
}

私のStorybookファイルでは、オプションを使用してマッピングしています。つまり、1つのページですべてのバリアントを確認できます。別の文字列がbuttonTypes配列に追加された場合、スタイルガイドに自動的に追加されます。

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,
};

問題は、これが多くのアドオン(ノブなど)では機能しないことです。ノブが機能するためには、実際のコンポーネントであるButtonが必要です。上記のようにラッパーではありません。

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

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

ノブを使用してすべてのバリエーションを1つのページに表示する方法はありますか?これはより手間がかかるため、各コンポーネントを手動で作成する必要がなく、buttonTypesに新しい文字列が追加されても自動的に更新されないのが理想的です。

6
Evanss

ノブの grouping 機能を使用すると、コンポーネントのすべてのインスタンスがすべてのコンポーネントインスタンス間で共有されるのではなく、コンポーネントの各インスタンスが独自のノブインスタンスを取得します。グループ化されたノブとグループ化されていないノブを混ぜて、特定のものを共有したい場合と共有したくない場合もあります。

次の例では、<Button/>ストーリー。各インスタンスにはtypeおよびdisabledプロパティの独自のコピーがありますが、textはそれらすべての間で共有されます。

各ボタンタイプには、typeおよびdisabledを設定できる独自のパネルがあります。 「その他」グループには、グループが設定されていないノブ(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";
2
zero298