Skip to content

Commit

Permalink
[docs] Add custom default props handler (#15473)
Browse files Browse the repository at this point in the history
* [docs] Add custom defaultPropsHandler

* WIP defaultProps removal

Early commit to see bundle size impact.

* continue

* and now to the tricky bit

* [Grid] Resolve default props in destructuring

Removes some default values that served no purpose

* [GridListTile] Disable eslint for docs

* [CssBaseline] Use es5 syntax

* get the Grid default values back

* Upgrade react-docgen

* Use react-docgen v5 beta

* cleanup lockfile
  • Loading branch information
eps1lon committed May 8, 2019
1 parent 0bb185c commit d183b44
Show file tree
Hide file tree
Showing 99 changed files with 590 additions and 848 deletions.
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);

0 comments on commit d183b44

Please sign in to comment.