how can i change an args control conditionally base on the value of an other arg in storybook react?

579 Views Asked by At

I hope you are fine. I have a react TS Button component. Its variant system is that it has main variants options. It gets main variant from variant prop. Each variant has its own color variants. To understand better, look at this interface, variants and color variants:

Button component props:

export interface ButtonProps<T extends keyof typeof variants> {
  /** the main variant of component*/
  variant?: T;
  /** each main variant has some color variants and you can set the color variant of a main variant here  */
  colorVariant?: keyof (typeof colorVariants)[T];
  /** a number that will be in use in border-radius of button  */
  radiusVariant?: keyof typeof radiusVariants;
  fontVariant?: keyof typeof fontVariants;
  /** the amount of height of button. if it is number, it will be used as `px` and if it is a sting it will be used itself */
  height?: string | number;
  /** the amount of width of button. if it is number, it will be used as `px` and if it is a sting it will be used itself */
  width?: string | number;
  /** the state of loading in button. if it is true, a loading spinner will be displayed at the center of button instead of displaying children */
  isLoading?: boolean;
}

Main variants data:

export const variants = {
  normal: "",
  fill: "py-8 px-8 sd:px-16 flex justify-center items-center gap-[8px]",
  outline:
    "py-8 px-16 sd:px-16 flex justify-center items-center bg-transparent border border-solid ",
};

Color variants:

export const colorVariants = {
  normal: {
    primary: "",
  },
  fill: {
    primary: "hover:bg-shade-1 bg-primary text-white",
  },
  outline: {
    primary: "border-white text-white hover:bg-white hover:text-primary",
    secondary: "border-shade-2 text-shade-2 hover:bg-shade-2 hover:text-white",
    tertiary: "border-gray-7 text-gray-1 hover:bg-gray-7",
  },
};

It's important to see how Button component is:

interface Props<T extends VariantsType>
  extends ButtonProps<T>,
    DetailedHTMLProps<
      ButtonHTMLAttributes<HTMLButtonElement>,
      HTMLButtonElement
    > {}

function Button<T extends VariantsType>(props: Props<T>): JSX.Element;

function Button({
  children,
  variant = "normal",
  height = "auto",
  width = "auto",
  radiusVariant = 0,
  fontVariant = "captionSmAndBtnLg",
  colorVariant = "primary",
  className,
  style,
  isLoading = false,
  ...props
}: Props<VariantsType>) {
  return (
    <button
      className={`transition duration-300 flex justify-center items-center ${
        variants[variant]
      } ${radiusVariants[radiusVariant]} ${fontVariants[fontVariant]} ${
        className || ""
      } ${colorVariants[variant][colorVariant]}`}
      style={{
        height: typeof height === "number" ? height + "px" : height,
        width: typeof width === "number" ? width + "px" : width,
        ...(style || {}),
      }}
      {...props}
    >
      {isLoading ? <LoadingIcon /> : children}
    </button>
  );
}

Well, base on my codes, if developer selects fill in variant prop, developer will only have primary option in colorVariant and if developer selects different colorVariant value like secondary, there will be an error for this. In other words, developer can set colorVariant option base on what is selected for variant. Now i want to implement this functionality in storybook document. I want to display all properties of variants in variant field in document. And i want to display colorVariant options base on what option user did select in variant field in document. I use storybook autodoc to generate document for my Button component. Here is a part of my codes for this section:

type Story = StoryObj<typeof Button>;

/** a Button component with different variants */
const meta: Meta<typeof Button> = {
  component: Button,
  tags: ["autodocs"],
  argTypes: {
    variant: {
      control: {
        type: "select",
      },
    },
  },
};

const defaultArgs: ButtonProps<VariantsType> & { children?: React.ReactNode } =
  {
    height: 48,
    width: 100,
    radiusVariant: 4,
    children: "Button!",
    colorVariant: "primary",
  };

const Normal: Story = {
  args: {
    ...defaultArgs,
    variant: "normal",
  },
  argTypes: {
    variant: {
      options: ["normal"],
    },
    colorVariant: {
      options: ["primary"] as ButtonProps<"normal">["colorVariant"][],
    },
  },
  parameters: {
    backgrounds: {
      default: "dawn",
    },
  },
};

Storybook itself can't detect what i implemented for variant system and how options must be displayed. It displays just one option in select input in variant field of document and it is normal variant. It doesnt display other variants like fill and outline. And in colorVariant select field of document, there is just one option and it is primary. So do you have any idea to do what i implemented for variant system in TS, in storybook too? thanks for your help :)

0

There are 0 best solutions below