From e95ee2cac4c0238a0a40715c1c7adf685a0d9d89 Mon Sep 17 00:00:00 2001 From: Alexander Fedyashov Date: Fri, 20 Oct 2017 03:40:28 +0300 Subject: [PATCH] docs(ComponentDoc): refactor and optimize (#2123) * docs(ComponentDoc): refactor and optimize * fix(utils): move exampleContent * refactor(ComponentDoc): create ComponentDocWrapper, remove doc utils * refactor(ComponentDoc): refactor to HOC * fix(plugin): correct path for windows --- .../Components/ComponentDoc/ComponentDoc.js | 289 +++--------------- .../ComponentDoc/ComponentDocHeader.js | 23 ++ .../ComponentDoc/ComponentDocLinks.js | 43 +++ .../ComponentDoc/ComponentDocSee.js | 40 +++ .../ComponentDoc/ComponentExamples.js | 10 +- .../ComponentPropDefaultValue.js | 13 + .../ComponentProp/ComponentPropDescription.js | 17 ++ .../ComponentPropEnum.js} | 22 +- .../ComponentPropEnumToggle.js} | 6 +- .../ComponentPropEnumValue.js} | 6 +- .../ComponentPropExtra.js} | 6 +- .../ComponentPropFunctionSignature.js} | 12 +- .../ComponentProp/ComponentPropHeader.js | 17 ++ .../ComponentPropName.js} | 6 +- .../ComponentProps/ComponentProps.js | 85 ++++-- .../ComponentProps/ComponentPropsComponent.js | 23 ++ .../ComponentPropsComponents.js | 34 +++ .../ComponentPropsDefaultValue.js | 13 - .../ComponentPropsDescription.js | 20 +- .../ComponentProps/ComponentPropsHeader.js | 54 +++- .../ComponentTable/ComponentTable.js | 25 ++ .../ComponentTable/ComponentTableHeader.js | 17 ++ .../ComponentTableRow.js} | 22 +- .../ComponentDoc/ComponentTable/index.js | 1 + docs/app/Components/ComponentDoc/index.js | 1 + docs/app/Components/DocsRoot.js | 10 +- docs/app/HOC/index.js | 1 + docs/app/HOC/withDocInfo.js | 47 +++ docs/app/utils/constants.js | 14 + docs/app/utils/getComponentGroup.js | 21 ++ docs/app/utils/getSeeItems.js | 13 + docs/app/utils/index.js | 19 ++ .../app/{utils.js => utils/scrollToAnchor.js} | 32 +- gulp/plugins/gulp-react-docgen.js | 8 +- 34 files changed, 587 insertions(+), 383 deletions(-) create mode 100644 docs/app/Components/ComponentDoc/ComponentDocHeader.js create mode 100644 docs/app/Components/ComponentDoc/ComponentDocLinks.js create mode 100644 docs/app/Components/ComponentDoc/ComponentDocSee.js create mode 100644 docs/app/Components/ComponentDoc/ComponentProp/ComponentPropDefaultValue.js create mode 100644 docs/app/Components/ComponentDoc/ComponentProp/ComponentPropDescription.js rename docs/app/Components/ComponentDoc/{ComponentProps/ComponentPropsEnum.js => ComponentProp/ComponentPropEnum.js} (52%) rename docs/app/Components/ComponentDoc/{ComponentProps/ComponentPropsEnumToggle.js => ComponentProp/ComponentPropEnumToggle.js} (66%) rename docs/app/Components/ComponentDoc/{ComponentProps/ComponentPropsEnumValue.js => ComponentProp/ComponentPropEnumValue.js} (66%) rename docs/app/Components/ComponentDoc/{ComponentProps/ComponentPropsExtra.js => ComponentProp/ComponentPropExtra.js} (79%) rename docs/app/Components/ComponentDoc/{ComponentProps/ComponentPropsFunctionSignature.js => ComponentProp/ComponentPropFunctionSignature.js} (78%) create mode 100644 docs/app/Components/ComponentDoc/ComponentProp/ComponentPropHeader.js rename docs/app/Components/ComponentDoc/{ComponentProps/ComponentPropsName.js => ComponentProp/ComponentPropName.js} (80%) create mode 100644 docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsComponent.js create mode 100644 docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsComponents.js delete mode 100644 docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsDefaultValue.js create mode 100644 docs/app/Components/ComponentDoc/ComponentTable/ComponentTable.js create mode 100644 docs/app/Components/ComponentDoc/ComponentTable/ComponentTableHeader.js rename docs/app/Components/ComponentDoc/{ComponentProps/ComponentPropsRow.js => ComponentTable/ComponentTableRow.js} (59%) create mode 100644 docs/app/Components/ComponentDoc/ComponentTable/index.js create mode 100644 docs/app/Components/ComponentDoc/index.js create mode 100644 docs/app/HOC/withDocInfo.js create mode 100644 docs/app/utils/constants.js create mode 100644 docs/app/utils/getComponentGroup.js create mode 100644 docs/app/utils/getSeeItems.js create mode 100644 docs/app/utils/index.js rename docs/app/{utils.js => utils/scrollToAnchor.js} (50%) diff --git a/docs/app/Components/ComponentDoc/ComponentDoc.js b/docs/app/Components/ComponentDoc/ComponentDoc.js index 8adb676aed..a2ade56d99 100644 --- a/docs/app/Components/ComponentDoc/ComponentDoc.js +++ b/docs/app/Components/ComponentDoc/ComponentDoc.js @@ -1,253 +1,56 @@ -import cx from 'classnames' -import _ from 'lodash' import PropTypes from 'prop-types' -import React, { Component } from 'react' +import React from 'react' import DocumentTitle from 'react-document-title' -import { Link } from 'react-router-dom' +import { Grid } from 'semantic-ui-react' -import { repoURL } from 'docs/app/utils' -import { META } from 'src/lib' -import * as semanticUIReact from 'src' -import docgenInfo from '../../docgenInfo.json' +import { withDocInfo } from 'docs/app/HOC' +import ComponentDocHeader from './ComponentDocHeader' +import ComponentDocLinks from './ComponentDocLinks' +import ComponentDocSee from './ComponentDocSee' import ComponentExamples from './ComponentExamples' import ComponentProps from './ComponentProps' -const { Divider, Grid, Header, Icon, List } = semanticUIReact - -const docgenPaths = _.keys(docgenInfo) - -const pathSepRegEx = new RegExp(_.escapeRegExp(__PATH_SEP__), 'g') - -const getDocgenPath = componentName => _.find(docgenPaths, path => ( - new RegExp(`${__PATH_SEP__}${componentName}.js$`).test(path) -)) - -// no matter the OS path separator, use '/' -const getPosixPath = componentName => getDocgenPath(componentName).replace(pathSepRegEx, '/') - -const getGithubSourceUrl = (componentName) => { - const posixPath = getPosixPath(componentName) - return `${repoURL}/blob/master/${posixPath}` -} - -const getGithubEditUrl = (componentName) => { - const posixPath = getPosixPath(componentName) - return `${repoURL}/edit/master/${posixPath}` -} - -const getSemanticUIDocsUrl = _meta => ( - `https://semantic-ui.com/${_meta.type}s/${_meta.parent || _meta.name}`.toLowerCase() +const ComponentDoc = ({ componentGroup, componentName, description, ghLink, path, seeItems, suiLink }) => ( + +
+ + + + + + + + + + +
+
) -const showPropsStyle = { - display: 'inline-flex', - margin: '1em 0.5em', - marginLeft: 0, - cursor: 'pointer', +ComponentDoc.propTypes = { + componentGroup: PropTypes.arrayOf( + PropTypes.shape({ + description: PropTypes.string, + props: PropTypes.object, + }), + ), + componentName: PropTypes.string.isRequired, + description: PropTypes.string, + ghLink: PropTypes.string.isRequired, + path: PropTypes.string.isRequired, + seeItems: PropTypes.arrayOf( + PropTypes.shape({ + description: PropTypes.string, + name: PropTypes.string, + type: PropTypes.string, + }), + ).isRequired, + suiLink: PropTypes.string, } -const subDescriptionStyle = { - fontSize: '1.08em', - color: '#777', -} - -const linkListStyle = { - position: 'absolute', - padding: '0.5em', - margin: '0.5em', - top: '0', - right: '0', - boxShadow: '0 0 1em 0.5em #f7f7f7', - background: '#f7f7f7', -} - -export default class ComponentDoc extends Component { - static propTypes = { - _meta: PropTypes.object, - } - - componentWillMount() { - this.setState({ - showPropsFor: this.props._meta.name, - }) - } - - componentWillReceiveProps(nextProps) { - this.setState({ - showPropsFor: this.state.showPropsFor ? nextProps._meta.name : null, - }) - } - - toggleProps = (name) => { - this.setState({ - showPropsFor: this.state.showPropsFor === name ? null : name, - }) - } - - renderSee() { - const { _meta } = this.props - const docPath = getDocgenPath(_meta.name) - const docgen = docgenInfo[docPath] - const seeTags = _.filter(docgen.docBlock.tags, ['title', 'see']) - - const seeLinks = _.map(seeTags, ({ description }) => { - const seeMeta = _.get(semanticUIReact[description], '_meta') - if (!seeMeta) return - - const { type, name } = seeMeta - - return ( - - {description} - - ) - }) - - // still render empty lists to reserve the whitespace - return ( - - -
- {seeLinks.length > 0 ? 'See:' : ' '} -
-
- {seeLinks} -
- ) - } - - renderSemanticDocsLink = () => { - const { _meta } = this.props - - if (META.isAddon(_meta)) return null - - return ( - - - - - Semantic UI {_meta.parent || _meta.name} Docs - - - - ) - } - - renderGithubSourceLink() { - const { _meta } = this.props - const docPath = getDocgenPath(_meta.name) - // no matter the OS path separator, use '/' since these link to github - const posixPath = docPath.replace(pathSepRegEx, '/') - return ( - - - - - {posixPath} - - - - ) - } - - renderProps = () => { - const { _meta } = this.props - const { showPropsFor } = this.state - - const itemCX = name => cx(showPropsFor === name && 'active', 'link item') - const selectedDocgen = docgenInfo[getDocgenPath(showPropsFor)] - const toggleIcon = `toggle ${showPropsFor ? 'on' : 'off'}` - - const subComponents = _.flatMap(semanticUIReact, SDComponent => _.filter(SDComponent, staticValue => ( - _.get(staticValue, '_meta.parent') === _meta.name - ))) - - const hasSubComponents = !_.isEmpty(subComponents) - const showSubDescription = hasSubComponents && _.get(selectedDocgen, 'docBlock.description') - - const subComponentItems = _.map(subComponents, ({ _meta: { name } }) => ( -
this.toggleProps(name)}> - {_meta.name}.{name.replace(_meta.name, '')} -
- )) - - return ( -
-
this.toggleProps(showPropsFor || _meta.name)} - > - Props{hasSubComponents && ':'} -
-
- {hasSubComponents && ( -
this.toggleProps(_meta.name)}> - {_meta.name} -
- )} - {subComponentItems} -
- {selectedDocgen && ( -
- {showSubDescription && ( -
- {selectedDocgen.docBlock.description} - -
- )} - -
- )} -
- ) - } - - renderHeader = () => { - const { _meta } = this.props - const docgen = docgenInfo[getDocgenPath(_meta.name)] - - return ( -
- {_meta.name} - - {/* TODO: Remove once all components have descriptions */} - {docgen.docBlock.description || ( - - Add a description. Instructions are{' '} - - here. - - {' '}Description is in the SUI Docs, right there - - )} - -
- ) - } - - render() { - const { _meta } = this.props - - return ( - -
- - - {this.renderHeader()} - {this.renderSee()} - - {this.renderGithubSourceLink()} - {this.renderSemanticDocsLink()} - - {this.renderProps()} - - - -
-
- ) - } -} +export default withDocInfo(ComponentDoc) diff --git a/docs/app/Components/ComponentDoc/ComponentDocHeader.js b/docs/app/Components/ComponentDoc/ComponentDocHeader.js new file mode 100644 index 0000000000..87c7909570 --- /dev/null +++ b/docs/app/Components/ComponentDoc/ComponentDocHeader.js @@ -0,0 +1,23 @@ +import PropTypes from 'prop-types' +import React from 'react' +import { Header } from 'semantic-ui-react' + +import { pure } from 'docs/app/HOC' + +const headerStyle = { marginBottom: '0.25em' } + +const ComponentDocHeader = ({ componentName, description }) => ( +
+) + +ComponentDocHeader.propTypes = { + componentName: PropTypes.string.isRequired, + description: PropTypes.string, +} + +export default pure(ComponentDocHeader) diff --git a/docs/app/Components/ComponentDoc/ComponentDocLinks.js b/docs/app/Components/ComponentDoc/ComponentDocLinks.js new file mode 100644 index 0000000000..2b003e5d81 --- /dev/null +++ b/docs/app/Components/ComponentDoc/ComponentDocLinks.js @@ -0,0 +1,43 @@ +import PropTypes from 'prop-types' +import React from 'react' +import { List } from 'semantic-ui-react' + +import { pure } from 'docs/app/HOC' + +const linkListStyle = { + background: '#f7f7f7', + boxShadow: '0 0 1em 0.5em #f7f7f7', + margin: '0.5em', + padding: '0.5em', + position: 'absolute', + right: '0', + top: '0', +} + +const ComponentDocLinks = ({ componentName, ghLink, path, suiLink }) => ( + + + {path} + + )} + icon='github' + /> + {suiLink && ( + Semantic UI {componentName} Docs} + icon='book' + /> + )} + +) + +ComponentDocLinks.propTypes = { + componentName: PropTypes.string.isRequired, + ghLink: PropTypes.string.isRequired, + path: PropTypes.string.isRequired, + suiLink: PropTypes.string, +} + +export default pure(ComponentDocLinks) diff --git a/docs/app/Components/ComponentDoc/ComponentDocSee.js b/docs/app/Components/ComponentDoc/ComponentDocSee.js new file mode 100644 index 0000000000..dcbe08fc4c --- /dev/null +++ b/docs/app/Components/ComponentDoc/ComponentDocSee.js @@ -0,0 +1,40 @@ +import _ from 'lodash' +import PropTypes from 'prop-types' +import React from 'react' +import { Link } from 'react-router-dom' +import { Header, List } from 'semantic-ui-react' + +const listStyle = { display: 'block' } + +const ComponentDocSee = ({ items }) => ( + + {/* Heads up! Still render empty lists to reserve the whitespace */} + +
0 ? 'See:' : ' '} + size='tiny' + /> + + {_.map(items, ({ description, name, type }) => ( + + ))} + +) + +ComponentDocSee.propTypes = { + items: PropTypes.arrayOf( + PropTypes.shape({ + description: PropTypes.string, + name: PropTypes.string, + type: PropTypes.string, + }), + ).isRequired, +} + +export default ComponentDocSee diff --git a/docs/app/Components/ComponentDoc/ComponentExamples.js b/docs/app/Components/ComponentDoc/ComponentExamples.js index 6f5908eaa7..3326d76048 100644 --- a/docs/app/Components/ComponentDoc/ComponentExamples.js +++ b/docs/app/Components/ComponentDoc/ComponentExamples.js @@ -8,24 +8,24 @@ import ContributionPrompt from './ContributionPrompt' export default class ComponentExamples extends Component { static propTypes = { - name: PropTypes.string, + componentName: PropTypes.string, } renderExamples = () => { - const { name } = this.props + const { componentName } = this.props - const examplePath = _.find(exampleContext.keys(), path => new RegExp(`${name}/index.js$`).test(path)) + const examplePath = _.find(exampleContext.keys(), path => new RegExp(`${componentName}/index.js$`).test(path)) return examplePath && createElement(exampleContext(examplePath).default) } renderMissingExamples = () => { - const { name } = this.props + const { componentName } = this.props return ( - Looks like we're missing {`<${name} />`} examples. + Looks like we're missing {`<${componentName} />`} examples. diff --git a/docs/app/Components/ComponentDoc/ComponentProp/ComponentPropDefaultValue.js b/docs/app/Components/ComponentDoc/ComponentProp/ComponentPropDefaultValue.js new file mode 100644 index 0000000000..579fb4948e --- /dev/null +++ b/docs/app/Components/ComponentDoc/ComponentProp/ComponentPropDefaultValue.js @@ -0,0 +1,13 @@ +import _ from 'lodash' +import PropTypes from 'prop-types' +import React from 'react' + +import { pure } from 'docs/app/HOC' + +const ComponentPropDefaultValue = ({ value }) => (_.isNil(value) ? null : {value}) + +ComponentPropDefaultValue.propTypes = { + value: PropTypes.node, +} + +export default pure(ComponentPropDefaultValue) diff --git a/docs/app/Components/ComponentDoc/ComponentProp/ComponentPropDescription.js b/docs/app/Components/ComponentDoc/ComponentProp/ComponentPropDescription.js new file mode 100644 index 0000000000..af8d80471e --- /dev/null +++ b/docs/app/Components/ComponentDoc/ComponentProp/ComponentPropDescription.js @@ -0,0 +1,17 @@ +import _ from 'lodash' +import PropTypes from 'prop-types' +import React from 'react' + +import { pure } from 'docs/app/HOC' + +const ComponentPropDescription = ({ description }) => (_.isNil(description) ? null : ( +

+ {_.map(description, line => [line,
])} +

+)) + +ComponentPropDescription.propTypes = { + description: PropTypes.arrayOf(PropTypes.string), +} + +export default pure(ComponentPropDescription) diff --git a/docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsEnum.js b/docs/app/Components/ComponentDoc/ComponentProp/ComponentPropEnum.js similarity index 52% rename from docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsEnum.js rename to docs/app/Components/ComponentDoc/ComponentProp/ComponentPropEnum.js index e7271296e9..5d0f68c23a 100644 --- a/docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsEnum.js +++ b/docs/app/Components/ComponentDoc/ComponentProp/ComponentPropEnum.js @@ -3,20 +3,20 @@ import PropTypes from 'prop-types' import React from 'react' import { updateForKeys } from 'docs/app/HOC' -import ComponentPropsExtra from './ComponentPropsExtra' -import ComponentPropsToggle from './ComponentPropsEnumToggle' -import ComponentPropsValue from './ComponentPropsEnumValue' +import ComponentPropExtra from './ComponentPropExtra' +import ComponentPropToggle from './ComponentPropEnumToggle' +import ComponentPropValue from './ComponentPropEnumValue' -const ComponentPropsEnum = ({ limit, showAll, toggle, type, values }) => { +const ComponentPropEnum = ({ limit, showAll, toggle, type, values }) => { if (!_.includes(type, 'enum') || !values) return null const exceeds = values.length > limit const sliced = showAll ? values : _.slice(values, 0, limit) return ( - + {exceeds && ( - { )}
- {_.map(sliced, value => {value})} + {_.map(sliced, value => {value})} {exceeds && !showAll && '...'}
-
+ ) } -ComponentPropsEnum.defaultProps = { +ComponentPropEnum.defaultProps = { limit: 50, } -ComponentPropsEnum.propTypes = { +ComponentPropEnum.propTypes = { limit: PropTypes.number, showAll: PropTypes.bool, toggle: PropTypes.func, @@ -43,4 +43,4 @@ ComponentPropsEnum.propTypes = { values: PropTypes.array, } -export default updateForKeys(['showAll'])(ComponentPropsEnum) +export default updateForKeys(['showAll'])(ComponentPropEnum) diff --git a/docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsEnumToggle.js b/docs/app/Components/ComponentDoc/ComponentProp/ComponentPropEnumToggle.js similarity index 66% rename from docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsEnumToggle.js rename to docs/app/Components/ComponentDoc/ComponentProp/ComponentPropEnumToggle.js index 1186444ac1..c166318691 100644 --- a/docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsEnumToggle.js +++ b/docs/app/Components/ComponentDoc/ComponentProp/ComponentPropEnumToggle.js @@ -7,16 +7,16 @@ const toggleStyle = { cursor: 'pointer', } -const ComponentPropsEnumToggle = ({ showAll, toggle, total }) => ( +const ComponentPropEnumToggle = ({ showAll, toggle, total }) => ( {showAll ? 'Show less' : `Show all ${total}`} ) -ComponentPropsEnumToggle.propTypes = { +ComponentPropEnumToggle.propTypes = { showAll: PropTypes.bool, toggle: PropTypes.func, total: PropTypes.number, } -export default updateForKeys(['showAll'])(ComponentPropsEnumToggle) +export default updateForKeys(['showAll'])(ComponentPropEnumToggle) diff --git a/docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsEnumValue.js b/docs/app/Components/ComponentDoc/ComponentProp/ComponentPropEnumValue.js similarity index 66% rename from docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsEnumValue.js rename to docs/app/Components/ComponentDoc/ComponentProp/ComponentPropEnumValue.js index e85a479122..9a94835fbf 100644 --- a/docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsEnumValue.js +++ b/docs/app/Components/ComponentDoc/ComponentProp/ComponentPropEnumValue.js @@ -8,14 +8,14 @@ const spanStyle = { paddingRight: '0.2em', } -const ComponentPropsEnumValue = ({ children }) => ( +const ComponentPropEnumValue = ({ children }) => ( {children} ) -ComponentPropsEnumValue.propTypes = { +ComponentPropEnumValue.propTypes = { children: PropTypes.node, } -export default neverUpdate(ComponentPropsEnumValue) +export default neverUpdate(ComponentPropEnumValue) diff --git a/docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsExtra.js b/docs/app/Components/ComponentDoc/ComponentProp/ComponentPropExtra.js similarity index 79% rename from docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsExtra.js rename to docs/app/Components/ComponentDoc/ComponentProp/ComponentPropExtra.js index 8df08ecdaf..d7d3c5b22f 100644 --- a/docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsExtra.js +++ b/docs/app/Components/ComponentDoc/ComponentProp/ComponentPropExtra.js @@ -16,7 +16,7 @@ const contentInlineStyle = { display: 'inline', } -const ComponentPropsExtra = ({ children, inline, title, ...rest }) => ( +const ComponentPropExtra = ({ children, inline, title, ...rest }) => (
{title}
@@ -25,10 +25,10 @@ const ComponentPropsExtra = ({ children, inline, title, ...rest }) => (
) -ComponentPropsExtra.propTypes = { +ComponentPropExtra.propTypes = { children: PropTypes.node, inline: PropTypes.bool, title: PropTypes.node, } -export default ComponentPropsExtra +export default ComponentPropExtra diff --git a/docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsFunctionSignature.js b/docs/app/Components/ComponentDoc/ComponentProp/ComponentPropFunctionSignature.js similarity index 78% rename from docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsFunctionSignature.js rename to docs/app/Components/ComponentDoc/ComponentProp/ComponentPropFunctionSignature.js index 0c818bbc7f..6c17584045 100644 --- a/docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsFunctionSignature.js +++ b/docs/app/Components/ComponentDoc/ComponentProp/ComponentPropFunctionSignature.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types' import React from 'react' import { neverUpdate } from 'docs/app/HOC' -import ComponentPropsExtra from './ComponentPropsExtra' +import ComponentPropExtra from './ComponentPropExtra' const descriptionStyle = { flex: '5 5 0', @@ -22,7 +22,7 @@ const rowStyle = { const getTagType = tag => (tag.type.type === 'AllLiteral' ? 'any' : tag.type.name) -const ComponentPropsFunctionSignature = ({ name, tags }) => { +const ComponentPropFunctionSignature = ({ name, tags }) => { const params = _.filter(tags, { title: 'param' }) const returns = _.find(tags, { title: 'returns' }) @@ -51,15 +51,15 @@ const ComponentPropsFunctionSignature = ({ name, tags }) => { }) return ( - {name}({paramSignature}){returns ? `: ${getTagType(returns)}` : ''}}> + {name}({paramSignature}){returns ? `: ${getTagType(returns)}` : ''}}> {tagDescriptionRows} - + ) } -ComponentPropsFunctionSignature.propTypes = { +ComponentPropFunctionSignature.propTypes = { name: PropTypes.string, tags: PropTypes.object, } -export default neverUpdate(ComponentPropsFunctionSignature) +export default neverUpdate(ComponentPropFunctionSignature) diff --git a/docs/app/Components/ComponentDoc/ComponentProp/ComponentPropHeader.js b/docs/app/Components/ComponentDoc/ComponentProp/ComponentPropHeader.js new file mode 100644 index 0000000000..7142336f53 --- /dev/null +++ b/docs/app/Components/ComponentDoc/ComponentProp/ComponentPropHeader.js @@ -0,0 +1,17 @@ +import React from 'react' +import { Table } from 'semantic-ui-react' + +import { neverUpdate } from 'docs/app/HOC' + +const ComponentPropHeader = () => ( + + + Name + Default + Type + Description + + +) + +export default neverUpdate(ComponentPropHeader) diff --git a/docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsName.js b/docs/app/Components/ComponentDoc/ComponentProp/ComponentPropName.js similarity index 80% rename from docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsName.js rename to docs/app/Components/ComponentDoc/ComponentProp/ComponentPropName.js index 1ab990d885..60043a4401 100644 --- a/docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsName.js +++ b/docs/app/Components/ComponentDoc/ComponentProp/ComponentPropName.js @@ -6,7 +6,7 @@ import { pure } from 'docs/app/HOC' const popupStyle = { padding: '0.5em' } -const ComponentPropsName = ({ name, required }) => ( +const ComponentPropName = ({ name, required }) => (
{name} {required && ( @@ -22,9 +22,9 @@ const ComponentPropsName = ({ name, required }) => (
) -ComponentPropsName.propTypes = { +ComponentPropName.propTypes = { name: PropTypes.string, required: PropTypes.bool, } -export default pure(ComponentPropsName) +export default pure(ComponentPropName) diff --git a/docs/app/Components/ComponentDoc/ComponentProps/ComponentProps.js b/docs/app/Components/ComponentDoc/ComponentProps/ComponentProps.js index b78a19873c..d52384d153 100644 --- a/docs/app/Components/ComponentDoc/ComponentProps/ComponentProps.js +++ b/docs/app/Components/ComponentDoc/ComponentProps/ComponentProps.js @@ -1,34 +1,61 @@ import _ from 'lodash' import PropTypes from 'prop-types' -import React from 'react' -import { Table } from 'semantic-ui-react' +import React, { Component } from 'react' +import ComponentTable from '../ComponentTable' +import ComponentPropsComponents from './ComponentPropsComponents' +import ComponentPropsDescription from './ComponentPropsDescription' import ComponentPropsHeader from './ComponentPropsHeader' -import ComponentPropsRow from './ComponentPropsRow' - -/** - * Displays a table of a Component's PropTypes. - */ -const ComponentProps = ({ props: propsDefinition }) => ( - - - - {_.map(propsDefinition, item => )} - -
-) - -ComponentProps.propTypes = { - /** - * A single Component's prop info as generated by react-docgen. - * @type {object} Props info object where keys are prop names and values are prop definitions. - */ - props: PropTypes.object, - /** - * A single Component's meta info. - * @type {object} Meta info object where enum prop values are defined. - */ - meta: PropTypes.object, -} -export default ComponentProps +export default class ComponentProps extends Component { + static propTypes = { + componentGroup: PropTypes.arrayOf(PropTypes.object), + componentName: PropTypes.string, + props: PropTypes.arrayOf(PropTypes.object), + } + + constructor(props) { + super(props) + + this.state = { activeName: props.componentName } + } + + componentWillReceiveProps({ componentName: next }) { + const current = this.props.componentName + + if (current !== next) this.setState({ activeName: next }) + } + + handleComponentClick = (e, { name }) => this.setState({ activeName: name }) + + handleToggle = () => this.setState({ activeName: this.state.activeName ? false : this.props.componentName }) + + render() { + const { componentGroup, componentName } = this.props + const { activeName } = this.state + const { description, props } = componentGroup[activeName] || {} + + return ( +
+ 1} + showProps={activeName} + onClick={this.handleToggle} + /> + + + {activeName && ( +
+ + +
+ )} +
+ ) + } +} diff --git a/docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsComponent.js b/docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsComponent.js new file mode 100644 index 0000000000..0f6f397a9a --- /dev/null +++ b/docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsComponent.js @@ -0,0 +1,23 @@ +import PropTypes from 'prop-types' +import React from 'react' +import { Menu } from 'semantic-ui-react' + +import { updateForKeys } from 'docs/app/HOC' + +const ComponentPropsComponent = ({ active, name, onClick, parent }) => ( + +) + +ComponentPropsComponent.propTypes = { + active: PropTypes.bool, + name: PropTypes.string, + onClick: PropTypes.func, + parent: PropTypes.string, +} + +export default updateForKeys(['active'])(ComponentPropsComponent) diff --git a/docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsComponents.js b/docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsComponents.js new file mode 100644 index 0000000000..bd610db13f --- /dev/null +++ b/docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsComponents.js @@ -0,0 +1,34 @@ +import _ from 'lodash' +import PropTypes from 'prop-types' +import React from 'react' +import { Menu } from 'semantic-ui-react' + +import { updateForKeys } from 'docs/app/HOC' +import ComponentPropsSubComponent from './ComponentPropsComponent' + +const ComponentPropsComponents = ({ activeName, components, onItemClick, parent }) => + components.length > 1 && ( + + {_.map(components, component => ( + + ))} + + ) + +ComponentPropsComponents.propTypes = { + activeName: PropTypes.oneOf([ + PropTypes.bool, + PropTypes.string, + ]), + components: PropTypes.array, + onItemClick: PropTypes.func, + parent: PropTypes.string.isRequired, +} + +export default updateForKeys(['activeName', 'parent'])(ComponentPropsComponents) diff --git a/docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsDefaultValue.js b/docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsDefaultValue.js deleted file mode 100644 index 689ee154a1..0000000000 --- a/docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsDefaultValue.js +++ /dev/null @@ -1,13 +0,0 @@ -import _ from 'lodash' -import PropTypes from 'prop-types' -import React from 'react' - -import { pure } from 'docs/app/HOC' - -const ComponentPropsDefaultValue = ({ value }) => (_.isNil(value) ? null : {value}) - -ComponentPropsDefaultValue.propTypes = { - value: PropTypes.node, -} - -export default pure(ComponentPropsDefaultValue) diff --git a/docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsDescription.js b/docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsDescription.js index fca3df9b71..74d313c966 100644 --- a/docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsDescription.js +++ b/docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsDescription.js @@ -1,17 +1,23 @@ -import _ from 'lodash' import PropTypes from 'prop-types' import React from 'react' +import { Divider } from 'semantic-ui-react' import { pure } from 'docs/app/HOC' -const ComponentPropsDescription = ({ description }) => (_.isNil(description) ? null : ( -

- {_.map(description, line => [line,
])} -

-)) +const descriptionStyle = { + fontSize: '1.08em', + color: '#777', +} + +const ComponentPropsDescription = ({ description }) => ( +
+ {description} + +
+) ComponentPropsDescription.propTypes = { - description: PropTypes.arrayOf(PropTypes.string), + description: PropTypes.string, } export default pure(ComponentPropsDescription) diff --git a/docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsHeader.js b/docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsHeader.js index abf98a9750..434bf48a36 100644 --- a/docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsHeader.js +++ b/docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsHeader.js @@ -1,17 +1,45 @@ +import cx from 'classnames' +import PropTypes from 'prop-types' import React from 'react' -import { Table } from 'semantic-ui-react' +import { Header, Icon } from 'semantic-ui-react' -import { neverUpdate } from 'docs/app/HOC' +import { updateForKeys } from 'docs/app/HOC' -const ComponentPropsHeader = () => ( - - - Name - Default - Type - Description - - -) +const headerStyle = { + cursor: 'pointer', + display: 'inline-flex', + margin: '1em 0.5em', + marginLeft: 0, +} -export default neverUpdate(ComponentPropsHeader) +const linkStyle = { color: 'inherit' } + +const ComponentPropsHeader = ({ hasSubComponents, onClick, showProps }) => { + const iconClasses = cx( + showProps ? 'on' : 'off', + 'toggle', + ) + + return ( +
+ + + Props{hasSubComponents && ':'} + +
+ ) +} + +ComponentPropsHeader.propTypes = { + hasSubComponents: PropTypes.bool, + onClick: PropTypes.func, + showProps: PropTypes.bool, +} + +export default updateForKeys(['hasSubComponents', 'showProps'])(ComponentPropsHeader) diff --git a/docs/app/Components/ComponentDoc/ComponentTable/ComponentTable.js b/docs/app/Components/ComponentDoc/ComponentTable/ComponentTable.js new file mode 100644 index 0000000000..976c232acc --- /dev/null +++ b/docs/app/Components/ComponentDoc/ComponentTable/ComponentTable.js @@ -0,0 +1,25 @@ +import _ from 'lodash' +import PropTypes from 'prop-types' +import React from 'react' +import { Table } from 'semantic-ui-react' + +import ComponentTableHeader from './ComponentTableHeader' +import ComponentTableRow from './ComponentTableRow' + +/** + * Displays a table of a Component's PropTypes. + */ +const ComponentTable = ({ props }) => ( + + + + {_.map(props, ({ name, ...rest }) => )} + +
+) + +ComponentTable.propTypes = { + props: PropTypes.arrayOf(PropTypes.object), +} + +export default ComponentTable diff --git a/docs/app/Components/ComponentDoc/ComponentTable/ComponentTableHeader.js b/docs/app/Components/ComponentDoc/ComponentTable/ComponentTableHeader.js new file mode 100644 index 0000000000..7079a6fb91 --- /dev/null +++ b/docs/app/Components/ComponentDoc/ComponentTable/ComponentTableHeader.js @@ -0,0 +1,17 @@ +import React from 'react' +import { Table } from 'semantic-ui-react' + +import { neverUpdate } from 'docs/app/HOC' + +const ComponentTableHeader = () => ( + + + Name + Default + Type + Description + + +) + +export default neverUpdate(ComponentTableHeader) diff --git a/docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsRow.js b/docs/app/Components/ComponentDoc/ComponentTable/ComponentTableRow.js similarity index 59% rename from docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsRow.js rename to docs/app/Components/ComponentDoc/ComponentTable/ComponentTableRow.js index f3b3333d34..93103fb0f6 100644 --- a/docs/app/Components/ComponentDoc/ComponentProps/ComponentPropsRow.js +++ b/docs/app/Components/ComponentDoc/ComponentTable/ComponentTableRow.js @@ -2,13 +2,13 @@ import PropTypes from 'prop-types' import React, { Component } from 'react' import { Table } from 'semantic-ui-react' -import ComponentPropsDefaultValue from './ComponentPropsDefaultValue' -import ComponentPropsDescription from './ComponentPropsDescription' -import ComponentPropsEnum from './ComponentPropsEnum' -import ComponentPropsFunctionSignature from './ComponentPropsFunctionSignature' -import ComponentPropsName from './ComponentPropsName' +import ComponentPropDefaultValue from '../ComponentProp/ComponentPropDefaultValue' +import ComponentPropDescription from '../ComponentProp/ComponentPropDescription' +import ComponentPropEnum from '../ComponentProp/ComponentPropEnum' +import ComponentPropFunctionSignature from '../ComponentProp/ComponentPropFunctionSignature' +import ComponentPropName from '../ComponentProp/ComponentPropName' -export default class ComponentPropsRow extends Component { +export default class ComponentTableRow extends Component { static propTypes = { defaultValue: PropTypes.string, description: PropTypes.string, @@ -33,16 +33,16 @@ export default class ComponentPropsRow extends Component { return ( - + - + {`{${type}}`} - - - + + { const { name } = props.match.params @@ -12,7 +12,13 @@ const DocsRoot = (props) => { const component = semanticUIReact[componentName] if (!component || !component._meta || !META.isParent(component)) return null - return + return ( + + ) } DocsRoot.propTypes = { diff --git a/docs/app/HOC/index.js b/docs/app/HOC/index.js index 072a6b5e7c..2f790c35b1 100644 --- a/docs/app/HOC/index.js +++ b/docs/app/HOC/index.js @@ -1,3 +1,4 @@ export neverUpdate from './neverUpdate' export pure from './pure' export updateForKeys from './updateForKeys' +export withDocInfo from './withDocInfo' diff --git a/docs/app/HOC/withDocInfo.js b/docs/app/HOC/withDocInfo.js new file mode 100644 index 0000000000..ec2478738a --- /dev/null +++ b/docs/app/HOC/withDocInfo.js @@ -0,0 +1,47 @@ +import PropTypes from 'prop-types' +import React, { Component } from 'react' + +import docInfo from 'docs/app/docgenInfo.json' +import { getComponentGroup, getSeeItems, repoURL } from 'docs/app/utils' + +const withDocInfo = ChildComponent => class extends Component { + static propTypes = { + name: PropTypes.string.isRequired, + parent: PropTypes.string, + type: PropTypes.string, + } + + constructor(props) { + super(props) + + this.state = this.computeProps(props) + } + + componentWillReceiveProps(nextProps) { + this.setState(this.computeProps(nextProps)) + } + + computeProps = ({ name, parent, type }) => { + const { docBlock, path } = docInfo[name] + const { description } = docBlock + + const ghLink = `${repoURL}/blob/master/${path}` + const suiLink = `https://semantic-ui.com/${type}s/${name || parent}`.toLowerCase() + + return { + description, + ghLink, + path, + suiLink, + componentGroup: getComponentGroup(docInfo, name), + componentName: name, + seeItems: getSeeItems(docInfo, name), + } + } + + render() { + return + } +} + +export default withDocInfo diff --git a/docs/app/utils/constants.js b/docs/app/utils/constants.js new file mode 100644 index 0000000000..61d5f3cd07 --- /dev/null +++ b/docs/app/utils/constants.js @@ -0,0 +1,14 @@ +import { META } from 'src/lib' + +export const repoURL = 'https://github.com/Semantic-Org/Semantic-UI-React' +export const typeOrder = [ + META.TYPES.ELEMENT, + META.TYPES.COLLECTION, + META.TYPES.VIEW, + META.TYPES.MODULE, + META.TYPES.BEHAVIOR, + META.TYPES.ADDON, +] +export const semanticUIDocsURL = 'https://semantic-ui.com/' +export const semanticUIRepoURL = 'https://github.com/Semantic-Org/Semantic-UI' +export const semanticUICSSRepoURL = 'https://github.com/Semantic-Org/Semantic-UI-CSS' diff --git a/docs/app/utils/getComponentGroup.js b/docs/app/utils/getComponentGroup.js new file mode 100644 index 0000000000..9e4f291eb3 --- /dev/null +++ b/docs/app/utils/getComponentGroup.js @@ -0,0 +1,21 @@ +import _ from 'lodash/fp' +import * as semanticUIReact from 'src' + +const getComponentGroup = (docInfo, componentName) => ({ + [componentName]: { + description: _.get('docBlock.description', docInfo[componentName]), + props: _.get('props', docInfo[componentName]), + }, + ..._.flow( + _.filter(component => _.get('_meta.parent', component) === componentName), + _.map('_meta.name'), + _.map(name => ({ + name, + description: _.get('docBlock.description', docInfo[name]), + props: _.get('props', docInfo[name]), + })), + _.keyBy('name'), + )(semanticUIReact), +}) + +export default getComponentGroup diff --git a/docs/app/utils/getSeeItems.js b/docs/app/utils/getSeeItems.js new file mode 100644 index 0000000000..f8bab29a5e --- /dev/null +++ b/docs/app/utils/getSeeItems.js @@ -0,0 +1,13 @@ +import _ from 'lodash/fp' +import * as semanticUIReact from 'src' + +const getSeeItems = (docInfo, componentName) => _.map(({ description }) => { + const seeMeta = _.get('_meta', semanticUIReact[description]) + + if (!seeMeta) return null + const { type, name } = seeMeta + + return { description, name, type } +}, _.filter(['title', 'see'], _.get('docBlock.tags', docInfo[componentName]))) + +export default getSeeItems diff --git a/docs/app/utils/index.js b/docs/app/utils/index.js new file mode 100644 index 0000000000..39952acda7 --- /dev/null +++ b/docs/app/utils/index.js @@ -0,0 +1,19 @@ +import _ from 'lodash/fp' + +import * as semanticUIReact from 'src' +import { META } from 'src/lib' + +export * from './constants' +export getComponentGroup from './getComponentGroup' +export getSeeItems from './getSeeItems' +export scrollToAnchor from './scrollToAnchor' + +/** + * Get the Webpack Context for all doc site examples. + */ +export const exampleContext = require.context('docs/app/Examples/', true, /(\w+Example\w*|index)\.js$/) + +export const parentComponents = _.flow( + _.filter(META.isParent), + _.sortBy('_meta.name'), +)(semanticUIReact) diff --git a/docs/app/utils.js b/docs/app/utils/scrollToAnchor.js similarity index 50% rename from docs/app/utils.js rename to docs/app/utils/scrollToAnchor.js index 3ceb257562..0704dc5df3 100644 --- a/docs/app/utils.js +++ b/docs/app/utils/scrollToAnchor.js @@ -1,21 +1,3 @@ -import _ from 'lodash/fp' -import * as semanticUIReact from 'src' -import { META } from 'src/lib' - -export const typeOrder = [ - META.TYPES.ELEMENT, - META.TYPES.COLLECTION, - META.TYPES.VIEW, - META.TYPES.MODULE, - META.TYPES.BEHAVIOR, - META.TYPES.ADDON, -] - -export const parentComponents = _.flow( - _.filter(META.isParent), - _.sortBy('_meta.name'), -)(semanticUIReact) - const mathSign = Math.sign || function (x) { const val = +x @@ -23,17 +5,7 @@ const mathSign = Math.sign || function (x) { return val > 0 ? 1 : -1 } -/** - * Get the Webpack Context for all doc site examples. - */ -export const exampleContext = require.context('docs/app/Examples/', true, /(\w+Example\w*|index)\.js$/) - -export const repoURL = 'https://github.com/Semantic-Org/Semantic-UI-React' -export const semanticUIDocsURL = 'https://semantic-ui.com/' -export const semanticUIRepoURL = 'https://github.com/Semantic-Org/Semantic-UI' -export const semanticUICSSRepoURL = 'https://github.com/Semantic-Org/Semantic-UI-CSS' - -export const scrollToAnchor = () => { +const scrollToAnchor = () => { const anchor = location.hash && document.querySelector(location.hash) const offsetY = window.scrollY || window.pageYOffset @@ -56,3 +28,5 @@ export const scrollToAnchor = () => { scrollBy(0, scrollStep) requestAnimationFrame(scrollToAnchor) } + +export default scrollToAnchor diff --git a/gulp/plugins/gulp-react-docgen.js b/gulp/plugins/gulp-react-docgen.js index f42fed6913..291cd457ae 100644 --- a/gulp/plugins/gulp-react-docgen.js +++ b/gulp/plugins/gulp-react-docgen.js @@ -27,7 +27,7 @@ export default (filename) => { } try { - const relativePath = file.path.replace(`${process.cwd()}/`, '') + const componentName = path.basename(file.path, '.js') const parsed = parse(file.contents, null, [ ...defaultHandlers, parserCustomHandler, @@ -52,9 +52,13 @@ export default (filename) => { type: name, } }) + + parsed.path = file.path + .replace(new RegExp(_.escapeRegExp(path.sep), 'g'), '/') + .replace(`${process.cwd()}/`, '') parsed.props = _.sortBy(parsed.props, 'name') - result[relativePath] = parsed + result[componentName] = parsed cb() } catch (err) {