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 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 <StaticQuery
query={graphql` query={graphql`
query LayoutQuery { query LayoutQuery {
@ -69,19 +78,24 @@ const Layout = ({ children }) => (
> >
<SideNav <SideNav
expandedState={expandedState} expandedState={expandedState}
onNavigate={this.handleNavigation}
pages={pages} pages={pages}
toggleDisplaySideNav={toggleDisplaySideNav} toggleDisplaySideNav={toggleDisplaySideNav}
toggleExpandedState={toggleExpandedState} toggleExpandedState={toggleExpandedState}
/> />
</Col> </Col>
<Col <Col
className='content'
md={8} md={8}
smHidden={displaySideNav} smHidden={displaySideNav}
xsHidden={displaySideNav} xsHidden={displaySideNav}
> >
<main className='main' id='main' tabIndex='-1'> <main
{children} className='content'
id='main'
ref={this.getContentRef}
tabIndex='-1'
>
{this.props.children}
</main> </main>
</Col> </Col>
</Row> </Row>
@ -92,7 +106,9 @@ const Layout = ({ children }) => (
); );
}} }}
/> />
); );
}
}
Layout.displayName = 'Layout'; Layout.displayName = 'Layout';
Layout.propTypes = propTypes; Layout.propTypes = propTypes;

View File

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

View File

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

View File

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

View File

@ -84,36 +84,6 @@
height: 20px; 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 */ /* SideNav */
.caretStyle { .caretStyle {
@ -197,6 +167,6 @@
position: absolute; position: absolute;
} }
.article { .content {
outline: 0; 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 PropTypes from 'prop-types';
import { graphql } from 'gatsby'; import { graphql } from 'gatsby';
import Helmet from 'react-helmet'; import Helmet from 'react-helmet';
@ -13,20 +13,7 @@ const propTypes = {
}) })
}; };
class GuideArticle extends Component { const GuideArticle = props => {
constructor(props) {
super(props);
this.article = null;
}
componentDidMount() {
if (this.article && document.activeElement.hasAttribute('data-navitem')) {
this.article.focus();
}
}
render() {
const { const {
location: { pathname }, location: { pathname },
data: { data: {
@ -37,7 +24,7 @@ class GuideArticle extends Component {
} }
}, },
pageContext: { meta } pageContext: { meta }
} = this.props; } = props;
return ( return (
<Fragment> <Fragment>
<Helmet> <Helmet>
@ -63,15 +50,11 @@ class GuideArticle extends Component {
className='article' className='article'
dangerouslySetInnerHTML={{ __html: html }} dangerouslySetInnerHTML={{ __html: html }}
id='article' id='article'
ref={article => {
this.article = article;
}}
tabIndex='-1' tabIndex='-1'
/> />
</Fragment> </Fragment>
); );
} };
}
GuideArticle.displayName = 'GuideArticle'; GuideArticle.displayName = 'GuideArticle';
GuideArticle.propTypes = propTypes; GuideArticle.propTypes = propTypes;