fix(client): scroll top and focus an article on guide navigation

This commit is contained in:
Valeriy S
2019-01-23 09:39:35 +03:00
committed by Stuart Taylor
parent a44935a520
commit 1f4fa29860
6 changed files with 149 additions and 168 deletions

View File

@ -29,7 +29,16 @@ const propTypes = {
location: PropTypes.object
};
const Layout = ({ children }) => (
class Layout extends React.Component {
getContentRef = ref => (this.contentRef = ref);
handleNavigation = () => {
this.contentRef.scrollTop = 0;
this.contentRef.focus();
};
render() {
return (
<StaticQuery
query={graphql`
query LayoutQuery {
@ -69,19 +78,24 @@ const Layout = ({ children }) => (
>
<SideNav
expandedState={expandedState}
onNavigate={this.handleNavigation}
pages={pages}
toggleDisplaySideNav={toggleDisplaySideNav}
toggleExpandedState={toggleExpandedState}
/>
</Col>
<Col
className='content'
md={8}
smHidden={displaySideNav}
xsHidden={displaySideNav}
>
<main className='main' id='main' tabIndex='-1'>
{children}
<main
className='content'
id='main'
ref={this.getContentRef}
tabIndex='-1'
>
{this.props.children}
</main>
</Col>
</Row>
@ -93,6 +107,8 @@ const Layout = ({ children }) => (
}}
/>
);
}
}
Layout.displayName = 'Layout';
Layout.propTypes = propTypes;

View File

@ -4,17 +4,23 @@ import Link from 'gatsby-link';
const propTypes = {
isStubbed: PropTypes.bool,
onNavigate: PropTypes.func.isRequired,
path: PropTypes.string,
router: PropTypes.object,
title: PropTypes.string,
toggleDisplaySideNav: PropTypes.func.isRequired
};
function NavItem(props) {
const { isStubbed, path, title } = props;
class NavItem extends React.Component {
handleClick = () => {
this.props.toggleDisplaySideNav();
this.props.onNavigate();
};
render() {
const { isStubbed, path, title } = this.props;
return (
<li>
<Link data-navitem='true' onClick={props.toggleDisplaySideNav} to={path}>
<Link data-navitem='true' onClick={this.handleClick} to={path}>
<span className={'navItemTitle' + (isStubbed ? ' stubbed' : '')}>
{title}
</span>
@ -22,6 +28,7 @@ function NavItem(props) {
</li>
);
}
}
NavItem.displayName = 'NavItem';
NavItem.propTypes = propTypes;

View File

@ -9,6 +9,7 @@ const propTypes = {
handleClick: PropTypes.func.isRequired,
hasChildren: PropTypes.bool,
isExpanded: PropTypes.bool,
onNavigate: PropTypes.func.isRequired,
path: PropTypes.string,
title: PropTypes.string,
toggleDisplaySideNav: PropTypes.func.isRequired
@ -52,9 +53,10 @@ class NavPanel extends Component {
}
handleTitleClick() {
const { path, toggleDisplaySideNav } = this.props;
const { path, toggleDisplaySideNav, onNavigate } = this.props;
toggleDisplaySideNav();
navigate(path);
onNavigate();
}
renderHeader() {
@ -94,8 +96,6 @@ class NavPanel extends Component {
return (
<Panel
bsClass='panelStyle panel'
collapsible={true}
expanded={isExpanded}
id={`${dashedName}-panel`}
role='listitem'
>

View File

@ -7,6 +7,7 @@ import NavItem from './NavItem';
const propTypes = {
expandedState: PropTypes.object,
onNavigate: PropTypes.func.isRequired,
pages: PropTypes.arrayOf(PropTypes.object),
parents: PropTypes.arrayOf(PropTypes.object),
toggleDisplaySideNav: PropTypes.func.isRequired,
@ -42,7 +43,9 @@ class SideNav extends Component {
const [category] = pages.filter(page => page.path === path);
const { title, hasChildren, dashedName } = category;
const children = this.renderChildren(childrenForParent, pages);
const children = isExpanded
? this.renderChildren(childrenForParent, pages)
: null;
return (
<NavPanel
dashedName={dashedName}
@ -50,11 +53,12 @@ class SideNav extends Component {
hasChildren={hasChildren}
isExpanded={isExpanded}
key={parent.path}
onNavigate={this.props.onNavigate}
path={parent.path}
title={title}
toggleDisplaySideNav={this.props.toggleDisplaySideNav}
>
{isExpanded ? children : null}
{children}
</NavPanel>
);
}
@ -68,6 +72,7 @@ class SideNav extends Component {
<NavItem
isStubbed={child.isStubbed}
key={child.path}
onNavigate={this.props.onNavigate}
path={child.path}
title={child.title}
toggleDisplaySideNav={this.props.toggleDisplaySideNav}

View File

@ -84,36 +84,6 @@
height: 20px;
}
/* 404 */
.flexWrapper {
align-items: center;
display: flex;
flex-direction: column;
height: 50vh;
justify-content: center;
}
.verticalAlign {
align-items: center;
display: flex;
flex-direction: column;
justify-content: center;
vertical-align: middle;
}
.button {
color: #006400;
background: #fff;
border-color: #006400;
}
.button:hover {
color: #fff;
background: #006400;
border-color: #fff;
}
/* SideNav */
.caretStyle {
@ -197,6 +167,6 @@
position: absolute;
}
.article {
.content {
outline: 0;
}

View File

@ -1,4 +1,4 @@
import React, { Component, Fragment } from 'react';
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import { graphql } from 'gatsby';
import Helmet from 'react-helmet';
@ -13,20 +13,7 @@ const propTypes = {
})
};
class GuideArticle extends Component {
constructor(props) {
super(props);
this.article = null;
}
componentDidMount() {
if (this.article && document.activeElement.hasAttribute('data-navitem')) {
this.article.focus();
}
}
render() {
const GuideArticle = props => {
const {
location: { pathname },
data: {
@ -37,7 +24,7 @@ class GuideArticle extends Component {
}
},
pageContext: { meta }
} = this.props;
} = props;
return (
<Fragment>
<Helmet>
@ -63,15 +50,11 @@ class GuideArticle extends Component {
className='article'
dangerouslySetInnerHTML={{ __html: html }}
id='article'
ref={article => {
this.article = article;
}}
tabIndex='-1'
/>
</Fragment>
);
}
}
};
GuideArticle.displayName = 'GuideArticle';
GuideArticle.propTypes = propTypes;