Skip to content

Commit

Permalink
Merge pull request #1485 from billyvg/prop-table-detailed
Browse files Browse the repository at this point in the history
More detailed props table
  • Loading branch information
ndelangen authored Sep 6, 2017
2 parents 40c652d + f2a9b66 commit 54f01b0
Show file tree
Hide file tree
Showing 20 changed files with 451 additions and 73 deletions.
94 changes: 30 additions & 64 deletions addons/info/src/components/PropTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

import PropTypes from 'prop-types';
import React from 'react';

import { Table, Td, Th } from '@storybook/components';
import PropVal from './PropVal';
import PrettyPropType from './types/PrettyPropType';

const PropTypesMap = new Map();

Expand All @@ -13,41 +16,10 @@ Object.keys(PropTypes).forEach(typeName => {
PropTypesMap.set(type.isRequired, typeName);
});

const stylesheet = {
propTable: {
marginLeft: -10,
borderSpacing: '10px 5px',
borderCollapse: 'separate',
},
};

const isNotEmpty = obj => obj && obj.props && Object.keys(obj.props).length > 0;

const renderDocgenPropType = propType => {
if (!propType) {
return 'unknown';
}

const name = propType.name;

switch (name) {
case 'arrayOf':
return `${propType.value.name}[]`;
case 'instanceOf':
return propType.value;
case 'union':
return propType.raw;
case 'signature':
return propType.raw;
default:
return name;
}
};

const hasDocgen = type => isNotEmpty(type.__docgenInfo);

const boolToString = value => (value ? 'yes' : 'no');

const propsFromDocgen = type => {
const props = {};
const docgenInfoProps = type.__docgenInfo.props;
Expand All @@ -59,8 +31,8 @@ const propsFromDocgen = type => {

props[property] = {
property,
propType: renderDocgenPropType(propType),
required: boolToString(docgenInfoProp.required),
propType,
required: docgenInfoProp.required,
description: docgenInfoProp.description,
defaultValue: defaultValueDesc.value,
};
Expand All @@ -75,21 +47,15 @@ const propsFromPropTypes = type => {
if (type.propTypes) {
Object.keys(type.propTypes).forEach(property => {
const typeInfo = type.propTypes[property];
const required = boolToString(typeInfo.isRequired === undefined);
const description =
type.__docgenInfo && type.__docgenInfo.props && type.__docgenInfo.props[property]
? type.__docgenInfo.props[property].description
: null;
const required = typeInfo.isRequired === undefined;
const docgenInfo =
type.__docgenInfo && type.__docgenInfo.props && type.__docgenInfo.props[property];
const description = docgenInfo ? docgenInfo.description : null;
let propType = PropTypesMap.get(typeInfo) || 'other';

if (propType === 'other') {
if (
type.__docgenInfo &&
type.__docgenInfo.props &&
type.__docgenInfo.props[property] &&
type.__docgenInfo.props[property].type
) {
propType = type.__docgenInfo.props[property].type.name;
if (docgenInfo && docgenInfo.type) {
propType = docgenInfo.type.name;
}
}

Expand Down Expand Up @@ -137,40 +103,40 @@ export default function PropTable(props) {
};

return (
<table style={stylesheet.propTable}>
<Table>
<thead>
<tr>
<th>property</th>
<th>propType</th>
<th>required</th>
<th>default</th>
<th>description</th>
<Th bordered>property</Th>
<Th bordered>propType</Th>
<Th bordered>required</Th>
<Th bordered>default</Th>
<Th bordered>description</Th>
</tr>
</thead>
<tbody>
{array.map(row =>
<tr key={row.property}>
<td>
<Td bordered code>
{row.property}
</td>
<td>
{row.propType}
</td>
<td>
{row.required}
</td>
<td>
</Td>
<Td bordered code>
<PrettyPropType propType={row.propType} />
</Td>
<Td bordered>
{row.required ? 'yes' : '-'}
</Td>
<Td bordered>
{row.defaultValue === undefined
? '-'
: <PropVal val={row.defaultValue} {...propValProps} />}
</td>
<td>
</Td>
<Td bordered>
{row.description}
</td>
</Td>
</tr>
)}
</tbody>
</table>
</Table>
);
}

Expand Down
19 changes: 19 additions & 0 deletions addons/info/src/components/types/ArrayOf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react';

import PrettyPropType from './PrettyPropType';
import { TypeInfo } from './proptypes';

const ArrayOf = ({ propType }) =>
<span>
<span>[</span>
<span>
<PrettyPropType propType={propType.value} />
</span>
<span>]</span>
</span>;

ArrayOf.propTypes = {
propType: TypeInfo.isRequired,
};

export default ArrayOf;
11 changes: 11 additions & 0 deletions addons/info/src/components/types/Enum.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react';
import { TypeInfo } from './proptypes';

const Enum = ({ propType }) =>
<span>
{propType.value.map(({ value }) => value).join(' | ')}
</span>;

Enum.propTypes = {
propType: TypeInfo.isRequired,
};
13 changes: 13 additions & 0 deletions addons/info/src/components/types/InstanceOf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react';
import { TypeInfo } from './proptypes';

const InstanceOf = ({ propType }) =>
<span>
{propType.value}
</span>;

InstanceOf.propTypes = {
propType: TypeInfo.isRequired,
};

export default InstanceOf;
8 changes: 8 additions & 0 deletions addons/info/src/components/types/Object.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import React from 'react';

const ObjectType = () =>
<span>
{'{}'}
</span>;

export default ObjectType;
17 changes: 17 additions & 0 deletions addons/info/src/components/types/ObjectOf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react';

import PrettyPropType from './PrettyPropType';
import { TypeInfo } from './proptypes';

const ObjectOf = ({ propType }) =>
<span>
{'{[<key>]: '}
<PrettyPropType propType={propType.value} />
{'}'}
</span>;

ObjectOf.propTypes = {
propType: TypeInfo.isRequired,
};

export default ObjectOf;
8 changes: 8 additions & 0 deletions addons/info/src/components/types/ObjectType.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import React from 'react';

const ObjectType = () =>
<span>
{'{}'}
</span>;

export default ObjectType;
13 changes: 13 additions & 0 deletions addons/info/src/components/types/OneOf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react';
import { TypeInfo } from './proptypes';

const OneOf = ({ propType }) =>
<span>
{propType.value.map(({ value }) => value).join(' | ')}
</span>;

OneOf.propTypes = {
propType: TypeInfo.isRequired,
};

export default OneOf;
25 changes: 25 additions & 0 deletions addons/info/src/components/types/OneOfType.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react';

import PrettyPropType from './PrettyPropType';
import { TypeInfo } from './proptypes';

const OneOfType = ({ propType }) => {
const length = propType.value.length;
return (
<span>
{propType.value
.map((value, i) => [
<PrettyPropType
key={`${value.name}${value.value ? `-${value.value}` : ''}`}
propType={value}
/>,
i < length - 1 ? <span> | </span> : null,
])
.reduce((acc, tuple) => acc.concat(tuple), [])}
</span>
);
};
OneOfType.propTypes = {
propType: TypeInfo.isRequired,
};
export default OneOfType;
61 changes: 61 additions & 0 deletions addons/info/src/components/types/PrettyPropType.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import PropTypes from 'prop-types';
import React from 'react';

import ObjectType from './ObjectType';
import Shape from './Shape';
import OneOfType from './OneOfType';
import ArrayOf from './ArrayOf';
import ObjectOf from './ObjectOf';
import OneOf from './OneOf';
import InstanceOf from './InstanceOf';
import Signature from './Signature';

import { TypeInfo } from './proptypes';

// propType -> Component map - these are a bit more complex prop types to display
const propTypeComponentMap = new Map([
['shape', Shape],
['union', OneOfType],
['arrayOf', ArrayOf],
['objectOf', ObjectOf],
// Might be overkill to have below proptypes as separate components *shrug*
['object', ObjectType],
['enum', OneOf],
['instanceOf', InstanceOf],
['signature', Signature],
]);

const PrettyPropType = props => {
const { propType, depth } = props;
if (!propType) {
return <span>unknown</span>;
}

const { name } = propType || {};

if (propTypeComponentMap.has(name)) {
const Component = propTypeComponentMap.get(name);
return <Component propType={propType} depth={depth} />;
}

// Otherwise, propType does not have a dedicated component, display proptype name by default
return (
<span>
{name}
</span>
);
};

PrettyPropType.displayName = 'PrettyPropType';

PrettyPropType.defaultProps = {
propType: null,
depth: 1,
};

PrettyPropType.propTypes = {
propType: TypeInfo,
depth: PropTypes.number.isRequired,
};

export default PrettyPropType;
31 changes: 31 additions & 0 deletions addons/info/src/components/types/PropertyLabel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import PropTypes from 'prop-types';
import React from 'react';

const styles = {
hasProperty: {
whiteSpace: 'nowrap',
},
};

const PropertyLabel = ({ property, required }) => {
if (!property) return null;

return (
<span style={styles.hasProperty}>
{property}
{required ? '' : '?'}:{' '}
</span>
);
};

PropertyLabel.propTypes = {
property: PropTypes.string,
required: PropTypes.bool,
};

PropertyLabel.defaultProps = {
property: '',
required: false,
};

export default PropertyLabel;
Loading

0 comments on commit 54f01b0

Please sign in to comment.