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

Commit

Permalink
Merge pull request #5 from kadirahq/autodetect-props
Browse files Browse the repository at this point in the history
Auto detect used components
  • Loading branch information
Muhammed Thanish authored Jun 15, 2016
2 parents 799ec14 + 549d711 commit b993df5
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 46 deletions.
38 changes: 25 additions & 13 deletions dist/components/PropTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ var _values = require('babel-runtime/core-js/object/values');

var _values2 = _interopRequireDefault(_values);

var _keys = require('babel-runtime/core-js/object/keys');

var _keys2 = _interopRequireDefault(_keys);

var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');

var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
Expand Down Expand Up @@ -58,33 +62,33 @@ var PropTable = function (_React$Component) {
(0, _createClass3.default)(PropTable, [{
key: 'render',
value: function render() {
var comp = this.props.comp;
var type = this.props.type;

if (!comp) {
if (!type) {
return null;
}

var props = {};

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

if (comp.defaultProps) {
for (var _property in comp.defaultProps) {
if (!comp.defaultProps.hasOwnProperty(_property)) {
if (type.defaultProps) {
for (var _property in type.defaultProps) {
if (!type.defaultProps.hasOwnProperty(_property)) {
continue;
}
var value = comp.defaultProps[_property];
var value = type.defaultProps[_property];
if (value === undefined) {
continue;
}
Expand All @@ -95,6 +99,14 @@ var PropTable = function (_React$Component) {
}
}

if (!(0, _keys2.default)(props).length) {
return _react2.default.createElement(
'small',
null,
'No propTypes defined!'
);
}

return _react2.default.createElement(
'table',
null,
Expand Down Expand Up @@ -164,6 +176,6 @@ var PropTable = function (_React$Component) {

PropTable.displayName = 'PropTable';
PropTable.propTypes = {
comp: _react2.default.PropTypes.func
type: _react2.default.PropTypes.func
};
exports.default = PropTable;
56 changes: 50 additions & 6 deletions dist/components/Story.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ Object.defineProperty(exports, "__esModule", {
value: true
});

var _from = require('babel-runtime/core-js/array/from');

var _from2 = _interopRequireDefault(_from);

var _map = require('babel-runtime/core-js/map');

var _map2 = _interopRequireDefault(_map);

var _assign = require('babel-runtime/core-js/object/assign');

var _assign2 = _interopRequireDefault(_assign);
Expand Down Expand Up @@ -70,7 +78,7 @@ var Story = function (_React$Component) {
fontFamily: 'sans-serif',
fontSize: 12,
display: 'block',
position: 'absolute',
position: 'fixed',
textDecoration: 'none',
background: '#28c',
color: '#fff',
Expand Down Expand Up @@ -249,21 +257,57 @@ var Story = function (_React$Component) {
}, {
key: '_getPropTables',
value: function _getPropTables() {
if (!this.props.propTables) {
if (!this.props.children && !this.props.propTables) {
return null;
}

return this.props.propTables.map(function (comp, idx) {
var types = new _map2.default();

if (this.props.propTables) {
this.props.propTables.forEach(function (type) {
types.set(type, true);
});
}

function extract(children) {
if (Array.isArray(children)) {
children.forEach(extract);
return;
}
if (typeof children === 'string' || typeof children.type === 'string') {
return;
}

var type = children.type;
var name = type.displayName || type.name;
if (!types.has(type)) {
types.set(type, true);
}
if (children.props.children) {
extract(children.props.children);
}
}

// extract components from children
extract(this.props.children);

var array = (0, _from2.default)(types.keys());
array.sort(function (a, b) {
return (a.displayName || a.name) > (b.displayName || b.name);
});

return array.map(function (type, idx) {
return _react2.default.createElement(
'div',
{ key: idx },
_react2.default.createElement(
'h3',
null,
comp.displayName || comp.name,
' PropTypes'
'<',
type.displayName || type.name,
' /> PropTypes'
),
_react2.default.createElement(_PropTable2.default, { comp: comp })
_react2.default.createElement(_PropTable2.default, { type: type })
);
});
}
Expand Down
30 changes: 17 additions & 13 deletions src/components/PropTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,37 +12,37 @@ for (let typeName in React.PropTypes) {
export default class PropTable extends React.Component {
static displayName = 'PropTable';
static propTypes = {
comp: React.PropTypes.func
type: React.PropTypes.func
};

render () {
const comp = this.props.comp;
const type = this.props.type;

if (!comp) {
if (!type) {
return null;
}

const props = {};

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

if (comp.defaultProps) {
for (let property in comp.defaultProps) {
if (!comp.defaultProps.hasOwnProperty(property)) {
if (type.defaultProps) {
for (let property in type.defaultProps) {
if (!type.defaultProps.hasOwnProperty(property)) {
continue
}
const value = comp.defaultProps[property];
const value = type.defaultProps[property];
if (value === undefined) {
continue;
}
Expand All @@ -53,6 +53,10 @@ export default class PropTable extends React.Component {
}
}

if (!Object.keys(props).length) {
return <small>No propTypes defined!</small>;
}

return (
<table>
<thead>
Expand Down
53 changes: 45 additions & 8 deletions src/components/Story.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export default class Story extends React.Component {
fontFamily: 'sans-serif',
fontSize: 12,
display: 'block',
position: 'absolute',
position: 'fixed',
textDecoration: 'none',
background: '#28c',
color: '#fff',
Expand Down Expand Up @@ -164,15 +164,52 @@ export default class Story extends React.Component {
}

_getPropTables() {
if (!this.props.propTables) {
if (!this.props.children && !this.props.propTables) {
return null;
}

return this.props.propTables.map((comp, idx) => (
<div key={idx}>
<h3>{comp.displayName || comp.name} PropTypes</h3>
<PropTable comp={comp} />
</div>
));
const types = new Map();

if (this.props.propTables) {
this.props.propTables.forEach(function (type) {
types.set(type, true);
});
}

function extract(children) {
if (Array.isArray(children)) {
children.forEach(extract);
return;
}
if (typeof children === 'string' || typeof children.type === 'string') {
return;
}

const type = children.type;
const name = type.displayName || type.name;
if (!types.has(type)) {
types.set(type, true);
}
if (children.props.children) {
extract(children.props.children);
}
}

// extract components from children
extract(this.props.children);

const array = Array.from(types.keys());
array.sort(function (a, b) {
return (a.displayName || a.name) > (b.displayName || b.name);
});

return array.map(function (type, idx) {
return (
<div key={idx}>
<h3>&lt;{type.displayName || type.name} /&gt; PropTypes</h3>
<PropTable type={type} />
</div>
);
});
}
}
32 changes: 26 additions & 6 deletions src/stories/Story.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import React from 'react';
import { storiesOf, action } from '@kadira/storybook';
import Story from '../index';

const stories = storiesOf('<Story />', module);
const stories = storiesOf('Basic Usage', module);

stories.add('Basic Usage', function (context) {
stories.add('Basic Modal', function (context) {
const info = `
The \`<Story>\` component can be used to show additional information with
your stories. To render text here, provide your markdown formatted text
Expand Down Expand Up @@ -37,13 +37,33 @@ stories.add('Show Inline', function (context) {
stories.add('Prop Tables', function (context) {
const info = `
You can also automatically generate propType tables for components.
Just provide an array of react components as \`propTables\` property
to the story component.
If you have any custom react components in your story, prop-type
tables will be automatically generated for them. If you need to provide
additional components, just give an array of react components as \`propTables\`
property to the story component.
`;

const Hello = React.createClass({
propTypes: {
name: React.PropTypes.string,
},
render() {
return <em>hello {this.props.name}</em>;
}
});

const World = React.createClass({
render() {
return <em>hello world</em>;
}
});

return (
<Story info={info} propTables={[Story]} showInline={true}>
<em>Click the "?" button on top-right corner for more info</em>
<Story context={context} info={info}>
<Hello name={'world'}>
<Hello name={'ninja'} />
<World />
</Hello>
</Story>
);
});

0 comments on commit b993df5

Please sign in to comment.