From 549d711a3c6a583a942456474238982aa260d030 Mon Sep 17 00:00:00 2001 From: Muhammed Thanish Date: Wed, 15 Jun 2016 15:08:32 +0530 Subject: [PATCH] Auto detect used components --- dist/components/PropTable.js | 38 +++++++++++++++--------- dist/components/Story.js | 56 ++++++++++++++++++++++++++++++++---- src/components/PropTable.js | 30 ++++++++++--------- src/components/Story.js | 53 ++++++++++++++++++++++++++++------ src/stories/Story.js | 32 +++++++++++++++++---- 5 files changed, 163 insertions(+), 46 deletions(-) diff --git a/dist/components/PropTable.js b/dist/components/PropTable.js index c5d088707d2c..d50343e5dd6d 100644 --- a/dist/components/PropTable.js +++ b/dist/components/PropTable.js @@ -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); @@ -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; } @@ -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, @@ -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; \ No newline at end of file diff --git a/dist/components/Story.js b/dist/components/Story.js index 0545b542feca..e5bfd9653131 100644 --- a/dist/components/Story.js +++ b/dist/components/Story.js @@ -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); @@ -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', @@ -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 }) ); }); } diff --git a/src/components/PropTable.js b/src/components/PropTable.js index 82fec45625d8..1bac8d59e706 100644 --- a/src/components/PropTable.js +++ b/src/components/PropTable.js @@ -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; } @@ -53,6 +53,10 @@ export default class PropTable extends React.Component { } } + if (!Object.keys(props).length) { + return No propTypes defined!; + } + return ( diff --git a/src/components/Story.js b/src/components/Story.js index 9216aa3cd33c..a8b6b2765822 100644 --- a/src/components/Story.js +++ b/src/components/Story.js @@ -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', @@ -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) => ( -
-

{comp.displayName || comp.name} PropTypes

- -
- )); + 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 ( +
+

<{type.displayName || type.name} /> PropTypes

+ +
+ ); + }); } } diff --git a/src/stories/Story.js b/src/stories/Story.js index 7ebeb46869b9..3145715ba8f6 100644 --- a/src/stories/Story.js +++ b/src/stories/Story.js @@ -2,9 +2,9 @@ import React from 'react'; import { storiesOf, action } from '@kadira/storybook'; import Story from '../index'; -const stories = storiesOf('', module); +const stories = storiesOf('Basic Usage', module); -stories.add('Basic Usage', function (context) { +stories.add('Basic Modal', function (context) { const info = ` The \`\` component can be used to show additional information with your stories. To render text here, provide your markdown formatted text @@ -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 hello {this.props.name}; + } + }); + + const World = React.createClass({ + render() { + return hello world; + } + }); + return ( - - Click the "?" button on top-right corner for more info + + + + + ); });