builder-vite icon indicating copy to clipboard operation
builder-vite copied to clipboard

[Bug] argTypes not working in mdx

Open blowsie opened this issue 2 years ago • 5 comments

What version of vite are you using?

2.9.13

System info and storybook versions

  System:
    OS: Windows 10 10.0.19044
    CPU: (12) x64 Intel(R) Core(TM) i7-10750
H CPU @ 2.60GHz
  Binaries:
    Node: 18.4.0 - ~\scoop\persist\nvm\nodej
s\nodejs\node.EXE
    npm: 8.12.1 - ~\scoop\persist\nvm\nodejs
\nodejs\npm.CMD
  Browsers:
    Edge: Spartan (44.19041.1266.0), Chromiu
 6.5.9
    @storybook/addon-links: ^6.5.9 => 6.5.9
    @storybook/addon-notes: ^5.3.21 => 5.3.21
    @storybook/addon-postcss: ^2.0.0 => 2.0.0
    @storybook/builder-vite: ^0.1.36 => 0.1.38
    @storybook/csf-tools: ^6.5.9 => 6.5.9
    @storybook/testing-library: ^0.0.13 => 0.0.13
    @storybook/theming: ^6.5.9 => 6.5.9
    @storybook/vue3: ^6.5.9 => 6.5.9

Describe the Bug

When using argsTypes in MDX the changes are not being applied to the argsTable. The same component and config works as expected when using a normal CSF file.

Reproduction:

component.stories.mdx

import { Meta, Canvas, Story, ArgsTable, Description  } from '@storybook/addon-docs'
const Component = {
  description: 'test',
  props: {
    id: String(),
    status: String(),
    label: String()
  },
  __docgenInfo: {
    displayName: 'component',
    props: [
      {name: 'id', required: true, type: {name: 'number'}},
      {name: 'status', required: true, type: {name: 'string'}},
      {name: 'label', required: true, type: {name: 'string'}}
    ]
  }
}

<Meta title="component"  component={Component}  argTypes={{
  status: {
    name: 'Badge Status',
    description: 'Available options available to the Badge',
    options: [
      'positive',
      'negative',
      'warning',
      'error',
      'neutral'
    ],
    table: {
      defaultValue: {
        summary: 'positive'
      },
      type: {
        summary: 'Shows options to the Badge',
        detail: 'Listing of available options'
      },
    },
  },
  label: {
    name: 'Badge Content',
    description: 'Text shown by Badge',
    control: {
      type: 'text'
    },
    table: {
      type: {
        summary: 'The label contents',
        detail: 'Text displayed by the Badge'
      }
    }
  }
}} />

<ArgsTable for={Component} />

Link to Minimal Reproducible Example

No response

Participation

  • [ ] I am willing to submit a pull request for this issue.

blowsie avatar Jul 01 '22 15:07 blowsie

not sure if you're using typescript, but i had a similar issue in that none of my documentation changes were reflected, regardless of story file type. in my case, the issue was actually with @joshwooding/vite-plugin-react-docgen-typescript.

when the plugin's transform function is called, parseWithProgramProvider (from react-docgen-typescript) is used to generate a ComponentDoc array. during plugin setup, however, the program provider is created using a "static" set of files.

my guess is that even though the plugin itself receives updated code, as well as the path to the updated code, the program provider files are actually stale. i'm not sure if it's possible to update provider files, but i ended up implementing a custom plugin that parses in "real" time by only parsing the file being transformed:

import MagicString from 'magic-string'
import micromatch from 'micromatch'
import path from 'node:path'
import {
  withCustomConfig,
  type ComponentDoc,
  type FileParser
} from 'react-docgen-typescript'
import type { TransformResult } from 'rollup'
import dedent from 'ts-dedent'
import type { Plugin } from 'vite'
import { PLUGIN_NAME } from './constants'
import type Options from './options.interface'

/**
 * Creates a `react-docgen-typescript` plugin.
 *
 * @see https://github.com/styleguidist/react-docgen-typescript
 * @see https://vitejs.dev/guide/api-plugin.html
 *
 * @param {Options} [options] - Plugin options
 * @return {Plugin} Vite `react-docgen-typescript` plugin
 */
const docgen = ({
  apply,
  componentNameResolver,
  enforce = 'pre',
  customComponentTypes = [],
  exclude = ['**.stories.tsx'],
  handler = doc => doc,
  include = ['**.tsx'],
  name = doc => doc.displayName,
  propFilter = prop => !prop.parent?.fileName.includes('node_modules'),
  savePropValueAsString = false,
  shouldExtractLiteralValuesFromEnum = false,
  shouldExtractValuesFromUnion = false,
  shouldIncludeExpression = false,
  shouldIncludePropTagMap = true,
  shouldRemoveUndefinedFromOptional = true,
  skipChildrenPropWithoutDoc = true,
  tsconfigPath = path.resolve('tsconfig.json')
}: Options = {}): Plugin => {
  /**
   * Component docgen info parser.
   *
   * @see https://github.com/styleguidist/react-docgen-typescript#usage
   *
   * @const {FileParser} parser
   */
  const parser: FileParser = withCustomConfig(tsconfigPath, {
    componentNameResolver,
    customComponentTypes,
    propFilter,
    savePropValueAsString,
    shouldExtractLiteralValuesFromEnum,
    shouldExtractValuesFromUnion,
    shouldIncludeExpression,
    shouldIncludePropTagMap,
    shouldRemoveUndefinedFromOptional,
    skipChildrenPropWithoutDoc
  })

  return {
    apply,
    enforce,
    name: PLUGIN_NAME,
    /**
     * Parses component docgen info from `id`.
     *
     * The final transform result will include a new source map and updated
     * version of `code` that includes a code block to attach a `__docgenInfo`
     * property to the component exported from `id`.
     *
     * If `id` isn't explicity included via {@link include}, or is explicity
     * excluded from transformation via {@link exclude}, `undefined` will be
     * returned instead.
     *
     * @param {string} code - Source code
     * @param {string} id - Module id
     * @return {Exclude<TransformResult, string>} Transformation result
     */
    transform(code: string, id: string): Exclude<TransformResult, string> {
      // do nothing if file isn't explicity omitted
      if (!micromatch.isMatch(id, include)) return

      // do nothing if file is explicity omitted
      if (micromatch.isMatch(id, exclude)) return

      try {
        /**
         * Component docgen info.
         *
         * @see https://github.com/styleguidist/react-docgen-typescript/blob/v2.2.2/src/parser.ts#L16
         *
         * @var {ComponentDoc?} doc
         */
        let doc: ComponentDoc | undefined = parser.parse(id).pop()

        // bail if missing component docgen info
        if (!doc) return null

        /**
         * {@link code} as `MagicString`.
         *
         * @see https://github.com/Rich-Harris/magic-string
         *
         * @const {MagicString} src
         */
        const src: MagicString = new MagicString(code)

        // apply additional transformations to component docgen info
        doc = handler(doc, id, code)

        /**
         * Code block containing logic to attach a `__docgenInfo` property to
         * the component found in {@link code}.
         *
         * @const {string} docgenblock
         */
        const docgenblock: string = dedent`
          try {
            ${name(doc, id, code)}.__docgenInfo=${JSON.stringify(doc)};
          } catch (e) {
            console.error('[${PLUGIN_NAME}]' + ' ' + e.message, e)
          }
        `

        // add __docgenInfo code block to source code
        src.append(docgenblock)

        return {
          code: src.toString(),
          map: src.generateMap({ hires: true, source: id })
        }
      } catch (e: unknown) {
        return void console.error(e instanceof Error ? e.message : e)
      }
    }
  }
}

export default docgen

edit:

oops just realized you're using vue, sorry 😅! not sure what the vue equivalents are in storybook, but if they're somewhat similar, hopefully this is helpful! (leaving the snippet for react users who stumble across this issue)

unicornware avatar Jul 22 '22 00:07 unicornware

@joshwooding this sleuthing might interest you ^.

IanVS avatar Jul 22 '22 04:07 IanVS

Yeah what was discovered here is already a known issue. The ts program is created based on the current filesystem. The above approach works around that by creating a ts program every parse which is quite expensive.

joshwooding avatar Jul 22 '22 09:07 joshwooding

@joshwooding do you have any links to issues or docs regarding this issue? i was searching for known issues surrounding this matter while i was debugging, but couldn't find any.

unicornware avatar Jul 24 '22 18:07 unicornware

MDX ArgsTable is working for me on the 7.0.0 beta

khuezy avatar Dec 16 '22 22:12 khuezy