reactjs/react-docgen

Prop types not being inferred correctly when using imported values

sebastienbarre opened this issue · 0 comments

Hi.

Per @danez suggestion in Create / use react-docgen vite plugin to show docsPage info by IanVS · Pull Request #299 · storybookjs/builder-vite, I'm opening a similar issue here.

TL;DR: PropTypes.oneOf(Object.values(foo)) does not seem to work when foo is an object containing values imported from an separate file.

I created a repo that show this behavior in Storybook (clone, npm install then npm run storybook): sebastienbarre-forks/storybook-builder-vite-react-docgen-repro

The example was lifted from storybookjs/builder-vite: Getting started with Vite and Storybook (on a new project) using build-vite README:

npm create vite@latest # follow the prompts
npx sb init --builder @storybook/builder-vite && npm run storybook

I slightly updated Button.jsx to use an object for the constants (this commit):

const sizes = {
  SMALL: "small",
  MEDIUM: "medium",
  LARGE: "large",
};

...

Button.propTypes = {
  size: PropTypes.oneOf(Object.values(sizes)),
};

...

Button.defaultProps = {
  size: sizes.MEDIUM,
};

This actually is already handled properly by react-docgen:

image

What doesn't quite work is when the constants are in a separate file. The rationale for doing this is that many of our components take props like size, shape, theme, or shade and we want the values for these props to be consistent. However, not ALL of our components support all sizes for example. In other words, we want the values of size to be consistent across all our components, but each component may support only a subset of them. Same for shapes, or shades, etc.

It looks like this (this commit):

In Size.js:

export const Size = {
  EXTRA_SMALL: "extra_small",
  SMALL: "small",
  MEDIUM: "medium",
  LARGE: "large",
  EXTRA_LARGE: "extra_large",
};

and the only change to Button is to use a subset of these sizes:

import { Size } from "./Size.js";

const sizes = {
  SMALL: Size.SMALL,
  MEDIUM: Size.MEDIUM,
  LARGE: Size.LARGE,
};

Here is what it looks like now in Storybook (notice the null):

image

Here is what it seems react-docgen generates:

Button.__docgenInfo = {
  "description": "Primary UI component for user interaction",
  "methods": [],
  "displayName": "Button",
  "props": {
    /// ...
    "size": {
      "defaultValue": {
        "value": '"medium"',
        "computed": false
      },
      "type": {
        "name": "enum",
        "value": [{
          "value": "null",
          "computed": false
        }, {
          "value": "null",
          "computed": false
        }, {
          "value": "null",
          "computed": false
        }]
      },
      "required": false,
      "description": "How large should the button be?"
    },
    /// ...
  }
};

Thank you.