diff --git a/docs/src/modules/components/AppContent.js b/docs/src/modules/components/AppContent.js
index 4a4f73bc35e280..f8735eb16c43cb 100644
--- a/docs/src/modules/components/AppContent.js
+++ b/docs/src/modules/components/AppContent.js
@@ -4,15 +4,24 @@ import classNames from 'classnames';
import { withStyles } from '@material-ui/core/styles';
const styles = theme => ({
- root: theme.mixins.gutters({
+ root: {
paddingTop: 80,
flex: '1 1 100%',
maxWidth: '100%',
margin: '0 auto',
- }),
- [theme.breakpoints.up('md')]: {
- root: {
- maxWidth: theme.breakpoints.values.md,
+ paddingLeft: theme.spacing.unit * 2,
+ paddingRight: theme.spacing.unit * 2,
+ [theme.breakpoints.up('sm')]: {
+ paddingLeft: theme.spacing.unit * 4,
+ paddingRight: theme.spacing.unit * 4,
+ },
+ [theme.breakpoints.up('md')]: {
+ maxWidth: 'calc(100% - 160px)',
+ },
+ [theme.breakpoints.up('lg')]: {
+ paddingLeft: theme.spacing.unit * 5,
+ paddingRight: theme.spacing.unit * 9,
+ maxWidth: 'calc(100% - 240px - 160px)',
},
},
});
@@ -20,7 +29,7 @@ const styles = theme => ({
function AppContent(props) {
const { className, classes, children } = props;
- return
{children}
;
+ return {children};
}
AppContent.propTypes = {
diff --git a/docs/src/modules/components/AppDrawer.js b/docs/src/modules/components/AppDrawer.js
index d45e385459b4ca..9dd1f8ff3ce870 100644
--- a/docs/src/modules/components/AppDrawer.js
+++ b/docs/src/modules/components/AppDrawer.js
@@ -14,7 +14,7 @@ import { pageToTitle } from 'docs/src/modules/utils/helpers';
const styles = theme => ({
paper: {
- width: 250,
+ width: 240,
backgroundColor: theme.palette.background.paper,
},
title: {
@@ -117,7 +117,7 @@ function AppDrawer(props, context) {
);
return (
-
+
+
);
}
diff --git a/docs/src/modules/components/AppFrame.js b/docs/src/modules/components/AppFrame.js
index a3c01d16178368..f43d3ee9cdc105 100644
--- a/docs/src/modules/components/AppFrame.js
+++ b/docs/src/modules/components/AppFrame.js
@@ -60,12 +60,13 @@ const styles = theme => ({
},
appBarShift: {
[theme.breakpoints.up('lg')]: {
- width: 'calc(100% - 250px)',
+ width: 'calc(100% - 240px)',
},
},
drawer: {
[theme.breakpoints.up('lg')]: {
- width: 250,
+ flexShrink: 0,
+ width: 240,
},
},
navIconHide: {
diff --git a/docs/src/modules/components/AppSearch.js b/docs/src/modules/components/AppSearch.js
index 04ba13f7251658..e0800edd9b1c9e 100644
--- a/docs/src/modules/components/AppSearch.js
+++ b/docs/src/modules/components/AppSearch.js
@@ -1,7 +1,6 @@
import React from 'react';
import keycode from 'keycode';
import compose from 'recompose/compose';
-import pure from 'recompose/pure';
import EventListener from 'react-event-listener';
import PropTypes from 'prop-types';
import Router from 'next/router';
@@ -196,5 +195,4 @@ AppSearch.propTypes = {
export default compose(
withStyles(styles),
withWidth(),
- pure,
)(AppSearch);
diff --git a/docs/src/modules/components/AppTableOfContents.js b/docs/src/modules/components/AppTableOfContents.js
new file mode 100644
index 00000000000000..1a0f6d193c126f
--- /dev/null
+++ b/docs/src/modules/components/AppTableOfContents.js
@@ -0,0 +1,183 @@
+/* eslint-disable react/no-danger */
+
+import React from 'react';
+import PropTypes from 'prop-types';
+import Link from 'docs/src/modules/components/Link';
+import marked from 'marked';
+import debounce from 'debounce'; // < 1kb payload overhead when lodash/debounce is > 3kb.
+import EventListener from 'react-event-listener';
+import { withStyles } from '@material-ui/core/styles';
+import Typography from '@material-ui/core/Typography';
+import { textToHash } from '@material-ui/docs/MarkdownElement/MarkdownElement';
+
+const renderer = new marked.Renderer();
+
+let itemsServer = null;
+renderer.heading = (text, level) => {
+ if (level === 1 || level > 3) {
+ return;
+ }
+
+ if (level === 2) {
+ itemsServer.push({
+ text,
+ level,
+ hash: textToHash(text),
+ children: [],
+ });
+ }
+
+ if (level === 3) {
+ itemsServer[itemsServer.length - 1].children.push({
+ text,
+ level,
+ hash: textToHash(text),
+ });
+ }
+};
+
+const styles = theme => ({
+ root: {
+ top: 70,
+ width: 160,
+ flexShrink: 0,
+ order: 2,
+ position: 'sticky',
+ wordBreak: 'break-word',
+ height: 'calc(100vh - 70px)',
+ overflowY: 'auto',
+ padding: `${theme.spacing.unit * 2}px ${theme.spacing.unit * 2}px ${theme.spacing.unit *
+ 2}px 0`,
+ display: 'none',
+ [theme.breakpoints.up('md')]: {
+ display: 'block',
+ },
+ },
+ ul: {
+ padding: 0,
+ margin: 0,
+ listStyleType: 'none',
+ },
+ item: {
+ fontSize: 13,
+ padding: `${theme.spacing.unit / 2}px 0`,
+ },
+});
+
+class AppTableOfContents extends React.Component {
+ handleScroll = debounce(() => {
+ this.findActiveIndex();
+ }, 166); // Corresponds to 10 frames at 60 Hz.
+
+ constructor(props) {
+ super(props);
+ itemsServer = [];
+ marked(props.contents.join(''), {
+ renderer,
+ });
+ }
+
+ state = {
+ active: null,
+ };
+
+ componentDidMount() {
+ this.itemsClient = [];
+
+ itemsServer.forEach(item2 => {
+ this.itemsClient.push({
+ ...item2,
+ node: document.getElementById(item2.hash),
+ });
+
+ if (item2.children.length > 0) {
+ item2.children.forEach(item3 => {
+ this.itemsClient.push({
+ ...item3,
+ node: document.getElementById(item3.hash),
+ });
+ });
+ }
+ });
+
+ this.findActiveIndex();
+ }
+
+ componentWillUnmount() {
+ this.handleScroll.clear();
+ }
+
+ findActiveIndex = () => {
+ const active = this.itemsClient.find(
+ (item, index) =>
+ document.documentElement.scrollTop < item.node.offsetTop + 100 ||
+ index === this.itemsClient.length - 1,
+ );
+
+ if (active && this.state.active !== active.hash) {
+ this.setState({
+ active: active.hash,
+ });
+ }
+ };
+
+ render() {
+ const { classes } = this.props;
+ const { active } = this.state;
+
+ return (
+
+ );
+ }
+}
+
+AppTableOfContents.propTypes = {
+ classes: PropTypes.object.isRequired,
+ contents: PropTypes.array.isRequired,
+};
+
+export default withStyles(styles)(AppTableOfContents);
diff --git a/docs/src/modules/components/Link.js b/docs/src/modules/components/Link.js
index b3accc8ae1f3de..cf89e07dc69c69 100644
--- a/docs/src/modules/components/Link.js
+++ b/docs/src/modules/components/Link.js
@@ -47,7 +47,13 @@ function Link(props) {
} = props;
let ComponentRoot;
- const className = classNames(classes.root, classes[variant], classNameProp);
+ const className = classNames(
+ classes.root,
+ {
+ [classes[variant]]: variant !== 'inherit',
+ },
+ classNameProp,
+ );
let RootProps;
let children = childrenProp;
@@ -103,7 +109,7 @@ Link.propTypes = {
router: PropTypes.shape({
pathname: PropTypes.string.isRequired,
}).isRequired,
- variant: PropTypes.oneOf(['default', 'primary', 'secondary', 'button']),
+ variant: PropTypes.oneOf(['default', 'primary', 'secondary', 'button', 'inherit']),
};
export default compose(
diff --git a/docs/src/modules/components/MarkdownDocs.js b/docs/src/modules/components/MarkdownDocs.js
index bf21716f4fdd2d..ffa57502478f12 100644
--- a/docs/src/modules/components/MarkdownDocs.js
+++ b/docs/src/modules/components/MarkdownDocs.js
@@ -10,6 +10,7 @@ import AppContent from 'docs/src/modules/components/AppContent';
import Demo from 'docs/src/modules/components/Demo';
import Carbon from 'docs/src/modules/components/Carbon';
import AppFrame from 'docs/src/modules/components/AppFrame';
+import AppTableOfContents from 'docs/src/modules/components/AppTableOfContents';
import {
getHeaders,
getContents,
@@ -55,15 +56,30 @@ function MarkdownDocs(props, context) {
}
}
- const section = markdownLocation.split('/')[4];
+ if (headers.components.length > 0) {
+ const section = markdownLocation.split('/')[4];
+ contents.push(`
+## API
+
+${headers.components
+ .map(
+ component =>
+ `- [<${component} />](${section === 'lab' ? '/lab/api' : '/api'}/${kebabCase(
+ component,
+ )})`,
+ )
+ .join('\n')}
+ `);
+ }
return (
+
+
-