Skip to content
This repository has been archived by the owner on Nov 10, 2017. It is now read-only.

Commit

Permalink
Add Docgen info to PropTable (#122)
Browse files Browse the repository at this point in the history
* Support show docgen prop description

* Update to comply PR

* Update Readme + Example

* Refactor to comply #PR122
  • Loading branch information
phthhieu authored and mthuret committed Apr 13, 2017
1 parent 3c4dc9a commit 092e10a
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 64 deletions.
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,25 @@ storiesOf('Button')

> Have a look at [this example](example/story.js) stories to learn more about the `addWithInfo` API.
## Use with Docgen
To add a prop description, we can use a single line or multiple lines comment as below example:
```js
Object.assign(Button, {
displayName: 'Button',
propTypes: {
/** Single line comment: This is label description */
label: React.PropTypes.string.isRequired,
/*
* Multiple lines comment: This is style description
* Must be in object
*/
style: React.PropTypes.object,
disabled: React.PropTypes.bool,
onClick: React.PropTypes.func,
},
});
```

## The FAQ

**Components lose their names on static build**
Expand Down
5 changes: 5 additions & 0 deletions example/Button.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ const Button = ({ disabled, label, style, onClick }) => (
Object.assign(Button, {
displayName: 'Button',
propTypes: {
/** Single line comment: This is label description */
label: React.PropTypes.string.isRequired,
/*
* Multiple lines comment: This is style description
* Must be in object
*/
style: React.PropTypes.object,
disabled: React.PropTypes.bool,
onClick: React.PropTypes.func,
Expand Down
187 changes: 123 additions & 64 deletions src/components/PropTable.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
import React from 'react';
import PropVal from './PropVal';

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

function isNotEmpty(obj) {
return obj && Object.keys(obj).length > 0;
}

const PropTypesMap = new Map();
for (const typeName in React.PropTypes) {
if (!React.PropTypes.hasOwnProperty(typeName)) {
Expand All @@ -11,82 +23,129 @@ for (const typeName in React.PropTypes) {
PropTypesMap.set(type.isRequired, typeName);
}

const stylesheet = {
propTable: {
marginLeft: -10,
borderSpacing: '10px 5px',
borderCollapse: 'separate',
},
};
function renderDocgenPropType(propType) {
if (!propType) {
return 'unknown';
}

export default class PropTable extends React.Component {
render() {
const type = this.props.type;
const name = propType.name;

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

function hasDocgen(type) {
return isNotEmpty(type.__docgenInfo);
}

function propsFromDocgen(type) {
let props = null;

const docgenInfo = type.__docgenInfo || {};
const docgenInfoProps = docgenInfo.props;

if (docgenInfoProps) {
props = {};
for (const propName in docgenInfoProps) {
if (!docgenInfoProps.hasOwnProperty(propName)) {
continue;
}
const docgenInfoProp = docgenInfoProps[propName];
const defaultValueDesc = docgenInfoProp.defaultValue || {};
const propType = docgenInfoProp.flowType || docgenInfoProp.type || 'other';

props[propName] = {
property: propName,
propType: renderDocgenPropType(propType),
required: docgenInfoProp.required,
description: docgenInfoProp.description,
defaultValue: defaultValueDesc.value,
};
}
}
return props;
}

function propsFromPropTypes(type) {
let props = null;

const props = {};

if (type.propTypes) {
for (const property in type.propTypes) {
if (!type.propTypes.hasOwnProperty(property)) {
continue;
}
const typeInfo = type.propTypes[property];
const propType = PropTypesMap.get(typeInfo) || 'other';
const required = typeInfo.isRequired === undefined ? 'yes' : 'no';
props[property] = { property, propType, required };
if (type.propTypes) {
props = {};
for (const property in type.propTypes) {
if (!type.propTypes.hasOwnProperty(property)) {
continue;
}
const typeInfo = type.propTypes[property];
const propType = PropTypesMap.get(typeInfo) || 'other';
const required = typeInfo.isRequired === undefined ? 'yes' : 'no';
props[property] = { property, propType, required };
}
}

if (type.defaultProps) {
for (const property in type.defaultProps) {
if (!type.defaultProps.hasOwnProperty(property)) {
continue;
}
const value = type.defaultProps[property];
if (value === undefined) {
continue;
}
if (!props[property]) {
props[property] = { property };
}
props[property].defaultValue = value;
if (type.defaultProps) {
for (const property in type.defaultProps) {
if (!type.defaultProps.hasOwnProperty(property)) {
continue;
}
const value = type.defaultProps[property];
if (value === undefined) {
continue;
}
if (!props[property]) {
props[property] = { property };
}
props[property].defaultValue = value;
}
}
return props;
}

const array = Object.values(props);
if (!array.length) {
return <small>No propTypes defined!</small>;
export default class PropTable extends React.Component {
render() {
const type = this.props.type;

if (!type) {
return null;
}
array.sort(function (a, b) {
return a.property > b.property;
});

return (
<table style={stylesheet.propTable}>
<thead>
<tr>
<th>property</th>
<th>propType</th>
<th>required</th>
<th>default</th>
</tr>
</thead>
<tbody>
{array.map(row => (
<tr key={row.property}>
<td>{row.property}</td>
<td>{row.propType}</td>
<td>{row.required}</td>
<td>{row.defaultValue === undefined ? '-' : <PropVal val={row.defaultValue} />}</td>

const props = hasDocgen(type) ? propsFromDocgen(type) : propsFromPropTypes(type);

if (isNotEmpty(props)) {
return (
<table style={stylesheet.propTable}>
<thead>
<tr>
<th>property</th>
<th>propType</th>
<th>required</th>
<th>default</th>
<th>description</th>
</tr>
))}
</tbody>
</table>
);
</thead>
<tbody>
{Object.values(props).sort((a, b) => a.property > b.property).map(row => (
<tr key={row.property}>
<td>{row.property}</td>
<td>{row.propType}</td>
<td>{row.required}</td>
<td>{row.defaultValue === undefined ? '-' : <PropVal val={row.defaultValue} />}</td>
<td>{row.description}</td>
</tr>
))}
</tbody>
</table>
);
} else {
return <small>No propTypes defined!</small>;
}
}
}

Expand Down

0 comments on commit 092e10a

Please sign in to comment.