add react-docgen to provide props tables for UI component library

This commit is contained in:
Erik Ziegler committed 2021-07-15 00:04:36 +02:00
1 parent 97805df68c
commit d6877cfcf9
54 files changed
+537 -109

No files matched your search

@@ -0,0 +1,24 @@
import React from 'react'
import PropTypes from 'prop-types'
import { usePluginData } from '@docusaurus/useGlobalData';
import { PropsTable } from '../react-docgen-props-table/PropsTable'
export function ComponentPropsTable({ componentName }) {
if (!componentName) {
return null;
}
const data = usePluginData('docusaurus-plugin-react-docgen')
const componentDocGenData = data[componentName.toLowerCase()]
if (!componentDocGenData) {
return null;
}
return (
<PropsTable className={'table-auto'} props={componentDocGenData.props}/>
)
}
ComponentPropsTable.PropTypes = {
componentName: PropTypes.string.required
}
+102
View File
@@ -0,0 +1,102 @@
import React from 'react';
import get from 'lodash.get';
import capitalize from 'capitalize';
import { humanize } from './humanize-prop';
import { Table } from './components/Table';
import { Tooltip } from './components/Tooltip';
const styles = {
thead: {
textAlign: 'left',
},
};
export const getPropType = (prop, Tooltip) => {
const propName = prop.flowType ? prop.flowType.name : prop.type.name;
const isEnum = propName.startsWith('"') || propName === 'enum';
const name = capitalize(isEnum ? 'enum' : propName);
const value = prop.type && prop.type.value;
if (!name) return null;
if (
!Tooltip ||
(isEnum && typeof value === 'string') ||
(!prop.flowType && !isEnum && !value) ||
(prop.flowType && !prop.flowType.elements)
) {
return name;
}
return prop.flowType ? (
<Tooltip text={humanize(prop.flowType)}>{name}</Tooltip>
) : (
<Tooltip text={humanize(prop.type)}>{name}</Tooltip>
);
};
export const PropsTable = ({ props, ...rest }) => {
if (!props || typeof props !== 'object') {
throw new Error('invalid props passed to PropsTable');
}
const hasDescription = Object.keys(props).some(name => {
const description = get(props, `${name}.description`);
return Boolean(description) && Boolean(get(description, 'length'));
});
const Thead = 'thead';
const Tr = 'tr';
const Th = 'th';
const Tbody = 'tbody';
const Td = 'td';
return (
<Table {...rest}>
<Thead style={styles.thead}>
<Tr>
<Th>Property</Th>
<Th>Type</Th>
<Th>Required</Th>
<Th>Default</Th>
{hasDescription && <Th width="40%">Description</Th>}
</Tr>
</Thead>
<Tbody>
{props &&
Object.keys(props).map(name => {
const prop = props[name];
if (!prop.flowType && !prop.type) return null;
return (
<Tr key={name}>
<Td>{name}</Td>
<Td>{getPropType(prop, Tooltip)}</Td>
<Td>{String(prop.required)}</Td>
{!prop.defaultValue ? (
<Td>
<em>-</em>
</Td>
) : (
<Td>
{prop.defaultValue.value === "''" ? (
<em>[Empty String]</em>
) : (
prop.defaultValue &&
prop.defaultValue.value.replace(/'/g, '')
)}
</Td>
)}
{hasDescription && (
<Td>{prop.description && prop.description}</Td>
)}
</Tr>
);
})}
</Tbody>
</Table>
);
};
@@ -0,0 +1,10 @@
import React from 'react';
export const Table = props => {
const { className, style, ...rest } = props;
return (
<div className={className}>
<table className={className} {...rest} />
</div>
);
};
@@ -0,0 +1,17 @@
import React from 'react';
import ReactTooltip from 'react-tooltip';
export const Tooltip = ({ text, children }) => {
const id = JSON.stringify(text);
return (
<React.Fragment>
<a data-tip data-for={id} href="#" onClick={ev => ev.preventDefault()}>
{children}
</a>
<ReactTooltip id={id} effect="solid">
{text}
</ReactTooltip>
</React.Fragment>
);
};
@@ -0,0 +1,23 @@
import capitalize from 'capitalize'
import get from 'lodash.get'
import { humanize } from './humanize-prop'
export const getPropType = (prop) => {
const propName = get(prop.flowType || prop.type, 'name')
if (!propName) return null
const isEnum = propName.startsWith('"') || propName === 'enum'
const name = capitalize(isEnum ? 'enum' : propName)
const value = get(prop, 'type.value')
if (!name) return null
if (
(isEnum && typeof value === 'string') ||
(!prop.flowType && !isEnum && !value) ||
(prop.flowType && !prop.flowType.elements)
) {
return name
}
return prop.flowType ? humanize(prop.flowType) : humanize(prop.type)
}
@@ -0,0 +1,49 @@
import capitalize from 'capitalize'
const RE_OBJECTOF = /(?:React\.)?(?:PropTypes\.)?objectOf\((?:React\.)?(?:PropTypes\.)?(\w+)\)/
const getTypeStr = (type) => {
switch (type.name.toLowerCase()) {
case 'instanceof':
return `Class(${type.value})`
case 'enum':
if (type.computed) return type.value
return type.value
? type.value.map((v) => `${v.value}`).join(' │ ')
: type.raw
case 'union':
return type.value
? type.value.map((t) => `${getTypeStr(t)}`).join(' │ ')
: type.raw
case 'array':
return type.raw
case 'arrayof':
return `Array<${getTypeStr(type.value)}>`
case 'custom':
if (type.raw.indexOf('function') !== -1 || type.raw.indexOf('=>') !== -1) {
return 'Custom(Function)'
} else if (type.raw.toLowerCase().indexOf('objectof') !== -1) {
const m = type.raw.match(RE_OBJECTOF)
if (m && m[1]) return `ObjectOf(${capitalize(m[1])})`
return 'ObjectOf'
}
return 'Custom'
case 'bool':
return 'Boolean'
case 'func':
return 'Function'
case 'shape':
const shape = type.value
const rst = {}
Object.keys(shape).forEach(key => {
rst[key] = getTypeStr(shape[key])
})
return JSON.stringify(rst, null, 2)
default:
return capitalize(type.name)
}
}
export const humanize = (type) => getTypeStr(type)
+2
View File
@@ -0,0 +1,2 @@
import { PropsTable } from './PropsTable'
export default PropsTable