Skip to content

Commit

Permalink
[docs] Persist the side nav scroll (#15704)
Browse files Browse the repository at this point in the history
* [docs] Fix linking issues

* Fix broken CSS class name

* backtick doesn't work in the description

* Fix SEO issues

* [docs] Add PersistScroll component

* fix 300 redirections

* fix warning

* sebastian review
  • Loading branch information
oliviertassinari authored May 15, 2019
1 parent d5b2ca5 commit 752bf0e
Show file tree
Hide file tree
Showing 14 changed files with 101 additions and 88 deletions.
40 changes: 38 additions & 2 deletions docs/src/modules/components/AppDrawer.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,42 @@ import { pageToTitleI18n } from 'docs/src/modules/utils/helpers';
import PageContext from 'docs/src/modules/components/PageContext';
import compose from 'docs/src/modules/utils/compose';

let savedScrollTop = null;
function PersistScroll(props) {
const { children } = props;
const rootRef = React.useRef();

React.useEffect(() => {
const parent = rootRef.current ? rootRef.current.parentNode : null;
const activeElement = document.querySelector('.drawer-active');

if (!parent || !activeElement || !activeElement.scrollIntoView) {
return undefined;
}

const activeBox = activeElement.getBoundingClientRect();

if (savedScrollTop === null || activeBox.top - savedScrollTop < 0) {
// Center the selected item in the list container.
activeElement.scrollIntoView();
// Fix a Chrome issue, reset the tabbable ring back to the top of the document.
document.body.scrollIntoView();
} else {
parent.scrollTop = savedScrollTop;
}

return () => {
savedScrollTop = parent.scrollTop;
};
}, []);

return <div ref={rootRef}>{children}</div>;
}

PersistScroll.propTypes = {
children: PropTypes.node,
};

const styles = theme => ({
paper: {
width: 240,
Expand Down Expand Up @@ -100,7 +136,7 @@ function AppDrawer(props) {
const { activePage, pages } = React.useContext(PageContext);

const drawer = (
<div className={classes.nav}>
<PersistScroll>
<div className={classes.placeholder} />
<div className={classes.toolbarIe11}>
<div className={classes.toolbar}>
Expand All @@ -116,7 +152,7 @@ function AppDrawer(props) {
</div>
<Divider />
{renderNavItems({ props, pages, activePage, depth: 0, t })}
</div>
</PersistScroll>
);

return (
Expand Down
108 changes: 40 additions & 68 deletions docs/src/modules/components/AppDrawerNavItem.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
import { withStyles } from '@material-ui/core/styles';
import { makeStyles } from '@material-ui/core/styles';
import ListItem from '@material-ui/core/ListItem';
import Button from '@material-ui/core/Button';
import Collapse from '@material-ui/core/Collapse';
import Link from 'docs/src/modules/components/Link';

const styles = theme => ({
const useStyles = makeStyles(theme => ({
item: {
display: 'block',
paddingTop: 0,
Expand Down Expand Up @@ -38,89 +38,61 @@ const styles = theme => ({
color: theme.palette.primary.main,
fontWeight: theme.typography.fontWeightMedium,
},
});
}));

class AppDrawerNavItem extends React.Component {
state = {
open: this.props.openImmediately,
};

componentDidMount() {
// So we only run this logic once.
if (!this.props.openImmediately) {
return;
}

// Center the selected item in the list container.
const activeElement = document.querySelector(`.${this.props.classes.active}`);
if (activeElement && activeElement.scrollIntoView) {
activeElement.scrollIntoView({});
// Fix a Chrome issue, reset the tabbable ring back to the top of the document.
document.body.scrollIntoView({});
}
}
function AppDrawerNavItem(props) {
const { children, depth, href, onClick, openImmediately, title, ...other } = props;
const [open, setOpen] = React.useState(openImmediately);
const classes = useStyles();

handleClick = () => {
this.setState(state => ({ open: !state.open }));
const handleClick = () => {
setOpen(oldOpen => !oldOpen);
};

render() {
const {
children,
classes,
depth,
href,
onClick,
openImmediately,
title,
...other
} = this.props;

const style = {
paddingLeft: 8 * (3 + 2 * depth),
};

if (href) {
return (
<ListItem className={classes.itemLeaf} disableGutters {...other}>
<Button
component={React.forwardRef((props, ref) => (
<Link naked activeClassName={classes.active} href={href} ref={ref} {...props} />
))}
className={clsx(classes.buttonLeaf, `depth-${depth}`)}
disableRipple
onClick={onClick}
style={style}
>
{title}
</Button>
</ListItem>
);
}
const style = {
paddingLeft: 8 * (3 + 2 * depth),
};

if (href) {
return (
<ListItem className={classes.item} disableGutters {...other}>
<ListItem className={classes.itemLeaf} disableGutters {...other}>
<Button
classes={{
root: classes.button,
label: openImmediately ? 'algolia-lvl0' : '',
}}
onClick={this.handleClick}
component={Link}
naked
activeClassName={`drawer-active ${classes.active}`}
href={href}
className={clsx(classes.buttonLeaf, `depth-${depth}`)}
disableRipple
onClick={onClick}
style={style}
>
{title}
</Button>
<Collapse in={this.state.open} timeout="auto" unmountOnExit>
{children}
</Collapse>
</ListItem>
);
}

return (
<ListItem className={classes.item} disableGutters {...other}>
<Button
classes={{
root: classes.button,
label: openImmediately ? 'algolia-lvl0' : '',
}}
onClick={handleClick}
style={style}
>
{title}
</Button>
<Collapse in={open} timeout="auto" unmountOnExit>
{children}
</Collapse>
</ListItem>
);
}

AppDrawerNavItem.propTypes = {
children: PropTypes.node,
classes: PropTypes.object.isRequired,
depth: PropTypes.number.isRequired,
href: PropTypes.string,
onClick: PropTypes.func,
Expand All @@ -132,4 +104,4 @@ AppDrawerNavItem.defaultProps = {
openImmediately: false,
};

export default withStyles(styles)(AppDrawerNavItem);
export default AppDrawerNavItem;
5 changes: 5 additions & 0 deletions docs/src/modules/components/MarkdownDocs.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
import compose from 'docs/src/modules/utils/compose';
import { pageToTitleI18n } from 'docs/src/modules/utils/helpers';
import { LANGUAGES_IN_PROGRESS } from 'docs/src/modules/constants';
import Link from 'docs/src/modules/components/Link';

const styles = theme => ({
header: {
Expand Down Expand Up @@ -209,6 +210,8 @@ function MarkdownDocs(props) {
<div className={classes.pagination}>
{prevPage ? (
<Button
component={Link}
naked
href={prevPage.pathname}
size="large"
className={classes.pageLinkButton}
Expand All @@ -221,6 +224,8 @@ function MarkdownDocs(props) {
)}
{nextPage.displayNav === false ? null : (
<Button
component={Link}
naked
href={nextPage.pathname}
size="large"
className={classes.pageLinkButton}
Expand Down
2 changes: 1 addition & 1 deletion docs/src/pages/components/switches/CustomizedSwitches.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ function CustomizedSwitches() {
<Typography component="div">
<Grid component="label" container alignItems="center" spacing={1}>
<Grid item>Off</Grid>
<Grid item alignItems="center">
<Grid item>
<AntSwitch
checked={state.checkedC}
onChange={handleChange('checkedC')}
Expand Down
2 changes: 1 addition & 1 deletion docs/src/pages/components/switches/CustomizedSwitches.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ function CustomizedSwitches() {
<Typography component="div">
<Grid component="label" container alignItems="center" spacing={1}>
<Grid item>Off</Grid>
<Grid item alignItems="center">
<Grid item>
<AntSwitch
checked={state.checkedC}
onChange={handleChange('checkedC')}
Expand Down
4 changes: 2 additions & 2 deletions docs/src/pages/components/text-fields/CustomizedInputs.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import green from '@material-ui/core/colors/green';

const CssTextField = withStyles({
root: {
'& label.focused': {
'& label.Mui-focused': {
color: 'green',
},
'& .MuiInput-underline:after': {
Expand All @@ -23,7 +23,7 @@ const CssTextField = withStyles({
'&:hover fieldset': {
borderColor: 'yellow',
},
'&.focused fieldset': {
'&.Mui-focused fieldset': {
borderColor: 'green',
},
},
Expand Down
4 changes: 2 additions & 2 deletions docs/src/pages/components/text-fields/CustomizedInputs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { OutlinedInputProps } from '@material-ui/core/OutlinedInput';

const CssTextField = withStyles({
root: {
'& label.focused': {
'& label.Mui-focused': {
color: 'green',
},
'& .MuiInput-underline:after': {
Expand All @@ -30,7 +30,7 @@ const CssTextField = withStyles({
'&:hover fieldset': {
borderColor: 'yellow',
},
'&.focused fieldset': {
'&.Mui-focused fieldset': {
borderColor: 'green',
},
},
Expand Down
6 changes: 3 additions & 3 deletions docs/src/pages/customization/breakpoints/breakpoints.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ You will find them in the theme, in the [`breakpoints.values`](/customization/de
The breakpoints are used internally in various components to make them responsive,
but you can also take advantage of them
for controlling the layout of your application through the [Grid](/components/grid/) and
[Hidden]/components/hidden/) components.
[Hidden](/components/hidden/) components.

## CSS Media Queries

Expand Down Expand Up @@ -68,11 +68,11 @@ You might want to change the React rendering tree based on the breakpoint value,

### useMediaQuery hook

You can learn more on the [useMediaQuery]/components/use-media-query/) page.
You can learn more on the [useMediaQuery](/components/use-media-query/) page.

### withWidth()

> ⚠️ This higher-order component will be deprecated for the [useMediaQuery]/components/use-media-query/) hook when the React's hooks are released as stable.
> ⚠️ This higher-order component will be deprecated for the [useMediaQuery](/components/use-media-query/) hook when the React's hooks are released as stable.
```jsx
import withWidth from '@material-ui/core/withWidth';
Expand Down
2 changes: 1 addition & 1 deletion docs/src/pages/customization/globals/globals.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Globals

<p class="description">The overrides key enables you to customize the appearance of all instances of a component type, while the `props` key enables you to change the default value(s) of a component's props.</p>
<p class="description">The overrides key enables you to customize the appearance of all instances of a component type, while the props key enables you to change the default value(s) of a component's props.</p>

## CSS

Expand Down
4 changes: 2 additions & 2 deletions docs/src/pages/getting-started/installation/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Please note that [react](https://www.npmjs.com/package/react) >= 16.8.0 and [rea
## Roboto Font

Material-UI was designed with the [Roboto](https://fonts.google.com/specimen/Roboto)
font in mind. So be sure to follow [these instructions]/components/typography/#general).
font in mind. So be sure to follow [these instructions](/components/typography/#general).
For instance, via Google Web Fonts:

```html
Expand All @@ -31,7 +31,7 @@ For instance, via Google Web Fonts:
## Font Icons

In order to use the font `Icon` component you must first add the [Material icons](https://material.io/tools/icons/) font.
Here are [some instructions]/components/icons/#font-icons)
Here are [some instructions](/components/icons/#font-icons)
on how to do so.
For instance, via Google Web Fonts:
```html
Expand Down
4 changes: 2 additions & 2 deletions docs/src/pages/getting-started/usage/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ To ensure proper rendering and touch zooming for all devices, add the responsive

### CssBaseline

Material-UI provides an optional [CssBaseline]/components/css-baseline/) component.
Material-UI provides an optional [CssBaseline](/components/css-baseline/) component.
It's fixing some inconsistencies across browsers and devices while providing slightly more opinionated resets to common HTML elements.

## Versioned Documentation
Expand All @@ -63,6 +63,6 @@ You can find older versions of the documentation on a [separate page](/versions/

Now that you have an idea of the basic setup, it's time to learn more about:

- How to provide [the Material Design font and typography]/components/typography/).
- How to provide [the Material Design font and typography](/components/typography/).
- How to take advantage of the [theming solution](/customization/themes/).
- How to [override](/customization/components/) the look and feel of the components.
2 changes: 1 addition & 1 deletion docs/src/pages/premium-themes/onepirate/SignIn.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ class SignIn extends React.Component {
)}
</Form>
<Typography align="center">
<Link underline="always" href="/premium-themes/onepirate/forgot-password">
<Link underline="always" href="/premium-themes/onepirate/forgot-password/">
Forgot password?
</Link>
</Typography>
Expand Down
4 changes: 2 additions & 2 deletions docs/src/pages/styles/advanced/GlobalClassName.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import styled from 'styled-components';
import { TextField, NoSsr } from '@material-ui/core';

const StyledTextField = styled(TextField)`
label.focused {
label.Mui-focused {
color: green;
}
.MuiOutlinedInput-root {
Expand All @@ -13,7 +13,7 @@ const StyledTextField = styled(TextField)`
&:hover fieldset {
border-color: yellow;
}
&.focused fieldset {
&.Mui-focused fieldset {
border-color: green;
}
}
Expand Down
2 changes: 1 addition & 1 deletion docs/src/pages/styles/advanced/advanced.md
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,7 @@ const StyledTextField = styled(TextField)`
&:hover fieldset {
border-color: yellow; 💛
}
&.focused fieldset {
&.Mui-focused fieldset {
border-color: green; 💚
}
}
Expand Down

0 comments on commit 752bf0e

Please sign in to comment.