Storybook: Props table not displaying in MDX

Created on 3 Dec 2019  路  4Comments  路  Source: storybookjs/storybook

Describe the bug
I have a component DonutChart with defaultProps and propTypes defined (w/ comments).
This component has a story defined (index.stories.mdx). Despite this the prop table is not showing up...

Note: Another component RangeChart composed very similarly has propTypes and they ARE showing up in storybook.

Expected Behavior I expect the Props table to show up for both components (RangeChart and DonutChart)
Actual Behavior DonutChart component docs is missing the Props table.

RangeChartDocs
DonutChartDocs

DonutChart/index.js

import React, { useState } from 'react';
import cn from 'classnames';
import moize from 'moize';
import PropTypes from 'prop-types';
import { scaleOrdinal as d3ScaleOrdinal } from 'd3-scale';
import { arc as d3Arc, pie as d3Pie } from 'd3-shape';

import style from './styles.css';

const pie = d3Pie().value(d => d.value);

const getCachedArc = moize.deep(
  (width, height, anglePadding, ringWidth, cornerRadius, margin) => {
    const radius = Math.min(width, height) / 2;
    const outerRadius = radius - margin;

    return d3Arc()
      .padAngle(anglePadding)
      .outerRadius(outerRadius)
      .innerRadius(outerRadius - ringWidth)
      .cornerRadius(cornerRadius);
  }
);

const getCachedColor = moize.deep((data, colors) =>
  d3ScaleOrdinal()
    .domain(data.map(d => d.label))
    .range(colors)
);

const getCachedPieData = moize.deep(data => pie(data));

/**
  Donut Chart
*/
const DonutChart = props => {
  const [activeSegment, activateSegment] = useState(null);

  const getArc = () => {
    return getCachedArc(
      props.width,
      props.height,
      props.anglePadding,
      props.ringWidth,
      props.cornerRadius,
      props.margin
    );
  };

  const getColor = () => {
    return getCachedColor(props.data, props.colors);
  };

  const getPieData = () => {
    return getCachedPieData(props.data);
  };

  const {
    data,
    height,
    margin,
    ringWidth,
    showActiveLabel,
    showLabels,
    title,
    valueFormatter,
    width
  } = props;

  const activeSegmentData =
    activeSegment && data.find(d => d.label === activeSegment).value;

  const showTitle = (!showActiveLabel || !activeSegment) && title;
  const showActiveSegment = showActiveLabel && activeSegment;

  return (
    <div className={cn('pie-chart', { 'has-active': activeSegment })}>
      <div
        className="center-text"
        style={{ width, height, padding: margin + ringWidth }}>
        {showTitle && <span className="title">{title}</span>}
        {showActiveSegment && (
          <span className="active-segment-label">
            {activeSegment}
            <br />
            <strong>{valueFormatter(activeSegmentData)}</strong>
          </span>
        )}
      </div>

      <svg width={width} height={height}>
        <g transform={`translate(${width / 2},${height / 2})`}>
          {getPieData().map(slice => (
            <g
              onMouseEnter={() => activateSegment(slice.data.label)}
              onMouseLeave={() => activateSegment(null)}
              key={`arc-${slice.data.label}`}
              className={cn('arc', {
                active: activeSegment === slice.data.label
              })}>
              <path d={getArc()(slice)} fill={getColor()(slice.data.label)} />
              {showLabels && (
                <text
                  transform={`translate(${getArc().centroid(slice)})`}
                  className="segment-label">
                  {slice.data.label}
                </text>
              )}
            </g>
          ))}
        </g>
      </svg>
      <style jsx>{style}</style>
    </div>
  );
};

DonutChart.defaultProps = {
  anglePadding: 0.01,
  width: 300,
  height: 300,
  valueFormatter: x => x,
  colors: ['#004b71', '#ffdf00', '#e37a00', '#c03123', '#614a7a', '#7c993f'],
  cornerRadius: 2,
  margin: 10,
  ringWidth: 10,
  showActiveLabel: true,
  showLabels: false
};

DonutChart.propTypes = {
  /**
      Padding of each slice angle
      useful for adding space between
      slices
    */
  anglePadding: PropTypes.number,
  /**
      segment data needed to render
      the chart
    */
  data: PropTypes.arrayOf(
    PropTypes.shape({
      label: PropTypes.string.isRequired,
      value: PropTypes.number.isRequired
    })
  ).isRequired,
  /**
      width of the pie chart
    */
  width: PropTypes.number,
  /**
      height the pie chart
    */
  height: PropTypes.number,
  /**
      function that formats the
      value for display
    */
  valueFormatter: PropTypes.func,
  /**
      array of colors in hex format
    */
  colors: PropTypes.arrayOf(PropTypes.string),
  /**
      border/corner radius
      of each arc segment
    */
  cornerRadius: PropTypes.number,
  /**
      Margin from the exterior
      of the svg chart to the ring
    */
  margin: PropTypes.number,
  /**
      width in pixels of the ring
    */
  ringWidth: PropTypes.number,
  /**
      boolean that represents
      whether the active segment label
      and value should be
      seen in the center text
    */
  showActiveLabel: PropTypes.bool,
  /**
      boolean which represents whether
      arc segments should be labeled
    */
  showLabels: PropTypes.bool
};

export default DonutChart;

DonutChart/index.stories.mdx

import { Meta, Story, Preview } from '@storybook/addon-docs/blocks';
import * as knobs from '@storybook/addon-knobs';
import DonutChart from '.';

<Meta title="visualizations/DonutChart" component={DonutChart} />

# DonutChart

A Reusable Donut Chart Component

## Props

<Props of={DonutChart} />

## Examples

A basic example:

<Preview>
  <Story name="basic example">
    <DonutChart
      title={knobs.text('Title: ', 'Asset Allocation')}
      colors={knobs.object('Colors: ', DonutChart.defaultProps.colors)}
      cornerRadius={knobs.number(
        'Corner Radius: ',
        DonutChart.defaultProps.cornerRadius
      )}
      height={knobs.number('Height: ', DonutChart.defaultProps.height)}
      width={knobs.number('Width: ', DonutChart.defaultProps.width)}
      margin={knobs.number('Margin: ', DonutChart.defaultProps.margin)}
      ringWidth={knobs.number(
        'Ring Width: ',
        DonutChart.defaultProps.ringWidth
      )}
      showActiveLabel={knobs.boolean(
        'Show Active Label: ',
        DonutChart.defaultProps.showActiveLabel
      )}
      showLabels={knobs.boolean(
        'Show Labels: ',
        DonutChart.defaultProps.showLabels
      )}
      anglePadding={knobs.number(
        'Angle Padding: ',
        DonutChart.defaultProps.anglePadding
      )}
      data={knobs.object('Data:', [
        { label: 'Domestic Stock', value: 75 },
        { label: 'Foreign Stock', value: 19 },
        { label: 'Other', value: 6 }
      ])}
    />
  </Story>
</Preview>

You can customize the title

<Preview>
  <Story name="another example">
    <DonutChart
      title="Here is a custom title"
      colors={[
        '#004b71',
        '#ffdf00',
        '#e37a00',
        '#c03123',
        '#614a7a',
        '#7c993f'
      ]}
      cornerRadius={2}
      height={300}
      width={300}
      margin={10}
      ringWidth={10}
      showActiveLabel
      anglePadding={0.01}
      data={[
        { label: 'Domestic Stock', value: 75 },
        { label: 'Foreign Stock', value: 19 },
        { label: 'Other', value: 6 }
      ]}
    />
  </Story>
</Preview>

RangeChart/index.js

import React from 'react';
import PropTypes from 'prop-types';
import cn from 'classnames';
import styles from './styles.css';

/**
  Simple RangeChart component
  Horizontal line with marker
  indicating a percent 0 - 100
*/
const RangeChart = ({ barWidthPercent, valuePercent, markerClass, labels }) => {
  const leftVal = (() => {
    const left = valuePercent - barWidthPercent / 2;
    if (left < barWidthPercent) {
      return 0;
    }
    const maxLeft = 100 - barWidthPercent;
    if (left > maxLeft) {
      return maxLeft;
    }
    return left;
  })();
  const markerStyle = {
    width: `${barWidthPercent}%`,
    left: `${leftVal}%`
  };

  return (
    <>
      <div className="bar">
        <div
          className={cn(markerClass, 'marker', {
            'default-bg': !markerClass
          })}
          style={markerStyle}
        />
      </div>

      <div className="labels">
        {labels.map(l => (
          <div key={`rp-l-${l}`}>{l}</div>
        ))}
      </div>
      <style jsx>{styles}</style>
    </>
  );
};

RangeChart.defaultProps = {
  barWidthPercent: 10,
  valuePercent: 0,
  markerClass: '',
  labels: []
};

RangeChart.propTypes = {
  /**
      width of the range marker
      percent of parent contianer
      (0 - 100)
    */
  barWidthPercent: PropTypes.number,
  /**
      value percentage of data
      (0 - 100)
    */
  valuePercent: PropTypes.number,
  /**
      classname to give the marker
      useful for different styling
    */
  markerClass: PropTypes.string,
  /**
      a list of labels to evenly display below chart
    */
  labels: PropTypes.arrayOf(PropTypes.string)
};

export default RangeChart;

RangeChart/index.stories.mdx

import { Meta, Story, Preview, Props } from '@storybook/addon-docs/blocks';
import * as knobs from '@storybook/addon-knobs';
import RangeChart from '.';

<Meta title="visualizations/RangeChart" component={RangeChart} />

# RangeChart

The range chart is used to visualize a value over a percentage of a horizontal bar.

## Props
<Props of={RangeChart} />


## Examples
A basic example:
<Preview>
  <Story name="basic example (with knobs)">
    <RangeChart
      barWidthPercent={knobs.number('Bar Width Percent', 10)}
      valuePercent={knobs.number('Value Percent', 25)}
      labels={knobs.object('Labels', ['Low', 'Medium', 'High'])}
    />
  </Story>
</Preview>

It allows the ability to add labels spaced evenly over the horizontal axis.

<Preview>
  <Story name="many labels">
    <RangeChart
      barWidthPercent={10}
      valuePercent={65}
      labels={['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']}
    />
  </Story>
</Preview>

Useful for showing hi-lo range (e.g. 52 week).

<Preview>
  <Story name="52 week example">
    <RangeChart
      barWidthPercent={1}
      valuePercent={100}
      labels={['$9.94', '52 WEEK RANGE', '$10.25']}
    />
  </Story>
</Preview>

The width of the bar can be customized

<Preview>
  <Story name="custom bar width">
    <RangeChart
      barWidthPercent={50}
      valuePercent={100}
      labels={['LOW', 'MIDDLE', 'HIGH']}
    />
  </Story>
</Preview>

I can try to give more details if needed.

props question / support

Most helpful comment

Looks like they forgot to import Props
image

All 4 comments

NM I found what I did wrong.

@cphoover what was it? might help anybody who stumbles on this issue

@cphoover Could you share what fixed it for you? I have a similar issue in my project

Looks like they forgot to import Props
image

Was this page helpful?
0 / 5 - 0 ratings

Related issues

moimikey picture moimikey  路  67Comments

ilyaulyanov picture ilyaulyanov  路  100Comments

tycho01 picture tycho01  路  76Comments

p3k picture p3k  路  61Comments

Olian04 picture Olian04  路  78Comments