Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[docs] Add custom default props handler #15473

Merged
merged 11 commits into from May 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 3 additions & 2 deletions docs/scripts/buildApi.js
Expand Up @@ -3,7 +3,8 @@
import { mkdir, readFileSync, writeFileSync } from 'fs';
import path from 'path';
import kebabCase from 'lodash/kebabCase';
import { parse as docgenParse } from 'react-docgen';
import { defaultHandlers, parse as docgenParse } from 'react-docgen';
import muiDefaultPropsHandler from '../src/modules/utils/defaultPropsHandler';
import generateMarkdown from '../src/modules/utils/generateMarkdown';
import { findPagesMarkdown, findComponents } from '../src/modules/utils/find';
import { getHeaders } from '../src/modules/utils/parseMarkdown';
Expand Down Expand Up @@ -132,7 +133,7 @@ async function buildDocs(options) {

let reactAPI;
try {
reactAPI = docgenParse(src, null, null, {
reactAPI = docgenParse(src, null, defaultHandlers.concat(muiDefaultPropsHandler), {
filename: componentObject.filename,
});
} catch (err) {
Expand Down
90 changes: 90 additions & 0 deletions docs/src/modules/utils/defaultPropsHandler.js
@@ -0,0 +1,90 @@
import astTypes from 'ast-types';
import { utils as docgenUtils } from 'react-docgen';

const { getPropertyName, isReactForwardRefCall, printValue, resolveToValue } = docgenUtils;

// based on https://github.com/reactjs/react-docgen/blob/735f39ef784312f4c0e740d4bfb812f0a7acd3d5/src/handlers/defaultPropsHandler.js#L1-L112
// adjusted for material-ui getThemedProps

const { namedTypes: types } = astTypes;

function getDefaultValue(path) {
let node = path.node;
let defaultValue;
if (types.Literal.check(node)) {
defaultValue = node.raw;
} else {
if (types.AssignmentPattern.check(path.node)) {
path = resolveToValue(path.get('right'));
} else {
path = resolveToValue(path);
}
if (types.ImportDeclaration.check(path.node)) {
defaultValue = node.name;
} else {
node = path.node;
defaultValue = printValue(path);
}
}
if (typeof defaultValue !== 'undefined') {
return {
value: defaultValue,
computed:
types.CallExpression.check(node) ||
types.MemberExpression.check(node) ||
types.Identifier.check(node),
};
}

return null;
}

function getDefaultValuesFromProps(properties, documentation) {
properties
.filter(propertyPath => types.Property.check(propertyPath.node))
// Don't evaluate property if component is functional and the node is not an AssignmentPattern
.filter(propertyPath => types.AssignmentPattern.check(propertyPath.get('value').node))
.forEach(propertyPath => {
const propName = getPropertyName(propertyPath);
if (!propName) return;

const propDescriptor = documentation.getPropDescriptor(propName);
const defaultValue = getDefaultValue(propertyPath.get('value', 'right'));
if (defaultValue) {
propDescriptor.defaultValue = defaultValue;
}
});
}

function getRenderBody(componentDefinition) {
const value = resolveToValue(componentDefinition);
if (isReactForwardRefCall(value)) {
return value.get('arguments', 0, 'body', 'body');
}
return value.get('body', 'body');
}

function getPropsPath(functionBody) {
let propsPath;
// visitVariableDeclarator, can't use visit body.node since it looses scope information
functionBody
.filter(path => {
return types.VariableDeclaration.check(path.node);
})
.forEach(path => {
const declaratorPath = path.get('declarations', 0);
if (declaratorPath.get('init', 'name').value === 'props') {
propsPath = declaratorPath.get('id');
}
});

return propsPath;
}

export default function defaultPropsHandler(documentation, componentDefinition) {
const renderBody = getRenderBody(componentDefinition);
const props = getPropsPath(renderBody);
if (props !== undefined) {
getDefaultValuesFromProps(props.get('properties'), documentation);
}
}
3 changes: 2 additions & 1 deletion package.json
Expand Up @@ -91,6 +91,7 @@
"@zeit/next-typescript": "^1.1.1",
"address": "^1.0.3",
"argos-cli": "^0.1.1",
"ast-types": "^0.12.4",
"autoprefixer": "^9.0.0",
"autosuggest-highlight": "^3.1.1",
"babel-core": "^7.0.0-bridge.0",
Expand Down Expand Up @@ -171,7 +172,7 @@
"raw-loader": "^1.0.0",
"react": "^16.8.5",
"react-autosuggest": "^9.3.2",
"react-docgen": "^4.0.1",
"react-docgen": "^5.0.0-beta",
"react-dom": "^16.8.5",
"react-draggable": "^3.0.5",
"react-final-form": "^4.0.2",
Expand Down
7 changes: 1 addition & 6 deletions packages/material-ui/src/AppBar/AppBar.js
Expand Up @@ -67,7 +67,7 @@ export const styles = theme => {
};

const AppBar = React.forwardRef(function AppBar(props, ref) {
const { classes, className, color, position, ...other } = props;
const { classes, className, color = 'primary', position = 'fixed', ...other } = props;

return (
<Paper
Expand Down Expand Up @@ -115,9 +115,4 @@ AppBar.propTypes = {
position: PropTypes.oneOf(['fixed', 'absolute', 'sticky', 'static', 'relative']),
};

AppBar.defaultProps = {
color: 'primary',
position: 'fixed',
};

export default withStyles(styles, { name: 'MuiAppBar' })(AppBar);
6 changes: 1 addition & 5 deletions packages/material-ui/src/Avatar/Avatar.js
Expand Up @@ -42,7 +42,7 @@ const Avatar = React.forwardRef(function Avatar(props, ref) {
childrenClassName: childrenClassNameProp,
classes,
className: classNameProp,
component: Component,
component: Component = 'div',
imgProps,
sizes,
src,
Expand Down Expand Up @@ -143,8 +143,4 @@ Avatar.propTypes = {
srcSet: PropTypes.string,
};

Avatar.defaultProps = {
component: 'div',
};

export default withStyles(styles, { name: 'MuiAvatar' })(Avatar);
6 changes: 1 addition & 5 deletions packages/material-ui/src/Backdrop/Backdrop.js
Expand Up @@ -26,7 +26,7 @@ export const styles = {
};

const Backdrop = React.forwardRef(function Backdrop(props, ref) {
const { classes, className, invisible, open, transitionDuration, ...other } = props;
const { classes, className, invisible = false, open, transitionDuration, ...other } = props;

return (
<Fade in={open} timeout={transitionDuration} {...other}>
Expand Down Expand Up @@ -75,8 +75,4 @@ Backdrop.propTypes = {
]),
};

Backdrop.defaultProps = {
invisible: false,
};

export default withStyles(styles, { name: 'MuiBackdrop' })(Backdrop);
18 changes: 5 additions & 13 deletions packages/material-ui/src/Badge/Badge.js
Expand Up @@ -81,12 +81,12 @@ const Badge = React.forwardRef(function Badge(props, ref) {
children,
classes,
className,
color,
component: ComponentProp,
color = 'default',
component: ComponentProp = 'span',
invisible: invisibleProp,
max,
showZero,
variant,
max = 99,
showZero = false,
variant = 'standard',
...other
} = props;

Expand Down Expand Up @@ -166,12 +166,4 @@ Badge.propTypes = {
variant: PropTypes.oneOf(['standard', 'dot']),
};

Badge.defaultProps = {
color: 'default',
component: 'span',
max: 99,
showZero: false,
variant: 'standard',
};

export default withStyles(styles, { name: 'MuiBadge' })(Badge);
9 changes: 2 additions & 7 deletions packages/material-ui/src/BottomNavigation/BottomNavigation.js
Expand Up @@ -19,9 +19,9 @@ const BottomNavigation = React.forwardRef(function BottomNavigation(props, ref)
children,
classes,
className,
component: Component,
component: Component = 'div',
onChange,
showLabels,
showLabels = false,
value,
...other
} = props;
Expand Down Expand Up @@ -91,9 +91,4 @@ BottomNavigation.propTypes = {
value: PropTypes.any,
};

BottomNavigation.defaultProps = {
component: 'div',
showLabels: false,
};

export default withStyles(styles, { name: 'MuiBottomNavigation' })(BottomNavigation);
18 changes: 5 additions & 13 deletions packages/material-ui/src/Breadcrumbs/Breadcrumbs.js
Expand Up @@ -52,11 +52,11 @@ const Breadcrumbs = React.forwardRef(function Breadcrumbs(props, ref) {
children,
classes,
className,
component: Component,
itemsAfterCollapse,
itemsBeforeCollapse,
maxItems,
separator,
component: Component = 'nav',
itemsAfterCollapse = 1,
itemsBeforeCollapse = 1,
maxItems = 8,
separator = '/',
...other
} = props;

Expand Down Expand Up @@ -157,12 +157,4 @@ Breadcrumbs.propTypes = {
separator: PropTypes.node,
};

Breadcrumbs.defaultProps = {
component: 'nav',
itemsAfterCollapse: 1,
itemsBeforeCollapse: 1,
maxItems: 8,
separator: '/',
};

export default withStyles(styles, { name: 'MuiBreadcrumbs' })(Breadcrumbs);
27 changes: 10 additions & 17 deletions packages/material-ui/src/Button/Button.js
Expand Up @@ -188,13 +188,15 @@ const Button = React.forwardRef(function Button(props, ref) {
children,
classes,
className: classNameProp,
color,
disabled,
disableFocusRipple,
color = 'default',
component = 'button',
disabled = false,
disableFocusRipple = false,
focusVisibleClassName,
fullWidth,
size,
variant,
fullWidth = false,
size = 'medium',
type = 'button',
variant = 'text',
...other
} = props;

Expand Down Expand Up @@ -223,10 +225,12 @@ const Button = React.forwardRef(function Button(props, ref) {
return (
<ButtonBase
className={className}
component={component}
disabled={disabled}
focusRipple={!disableFocusRipple}
focusVisibleClassName={clsx(classes.focusVisible, focusVisibleClassName)}
ref={ref}
type={type}
{...other}
>
<span className={classes.label}>{children}</span>
Expand Down Expand Up @@ -298,15 +302,4 @@ Button.propTypes = {
variant: PropTypes.oneOf(['text', 'outlined', 'contained']),
};

Button.defaultProps = {
color: 'default',
component: 'button',
disabled: false,
disableFocusRipple: false,
fullWidth: false,
size: 'medium',
type: 'button',
variant: 'text',
};

export default withStyles(styles, { name: 'MuiButton' })(Button);
6 changes: 1 addition & 5 deletions packages/material-ui/src/ButtonBase/Ripple.js
Expand Up @@ -7,7 +7,7 @@ import { Transition } from 'react-transition-group';
* @ignore - internal component.
*/
function Ripple(props) {
const { classes, className, pulsate, rippleX, rippleY, rippleSize, ...other } = props;
const { classes, className, pulsate = false, rippleX, rippleY, rippleSize, ...other } = props;
const [visible, setVisible] = React.useState(false);
const [leaving, setLeaving] = React.useState(false);

Expand Down Expand Up @@ -77,8 +77,4 @@ Ripple.propTypes = {
rippleY: PropTypes.number,
};

Ripple.defaultProps = {
pulsate: false,
};

export default Ripple;
6 changes: 1 addition & 5 deletions packages/material-ui/src/Card/Card.js
Expand Up @@ -12,7 +12,7 @@ export const styles = {
};

const Card = React.forwardRef(function Card(props, ref) {
const { classes, className, raised, ...other } = props;
const { classes, className, raised = false, ...other } = props;

return (
<Paper
Expand Down Expand Up @@ -40,8 +40,4 @@ Card.propTypes = {
raised: PropTypes.bool,
};

Card.defaultProps = {
raised: false,
};

export default withStyles(styles, { name: 'MuiCard' })(Card);
6 changes: 1 addition & 5 deletions packages/material-ui/src/CardActions/CardActions.js
Expand Up @@ -20,7 +20,7 @@ export const styles = {
};

const CardActions = React.forwardRef(function CardActions(props, ref) {
const { disableSpacing, classes, className, ...other } = props;
const { disableSpacing = false, classes, className, ...other } = props;

return (
<div
Expand Down Expand Up @@ -51,8 +51,4 @@ CardActions.propTypes = {
disableSpacing: PropTypes.bool,
};

CardActions.defaultProps = {
disableSpacing: false,
};

export default withStyles(styles, { name: 'MuiCardActions' })(CardActions);
6 changes: 1 addition & 5 deletions packages/material-ui/src/CardContent/CardContent.js
Expand Up @@ -14,7 +14,7 @@ export const styles = {
};

const CardContent = React.forwardRef(function CardContent(props, ref) {
const { classes, className, component: Component, ...other } = props;
const { classes, className, component: Component = 'div', ...other } = props;

return <Component className={clsx(classes.root, className)} ref={ref} {...other} />;
});
Expand All @@ -36,8 +36,4 @@ CardContent.propTypes = {
component: PropTypes.elementType,
};

CardContent.defaultProps = {
component: 'div',
};

export default withStyles(styles, { name: 'MuiCardContent' })(CardContent);