Skip to content

Commit

Permalink
fix: scroll behaviour when navigating back to anchor on the same page (
Browse files Browse the repository at this point in the history
…#8061)

* Move scroll handling from Link to shouldUpdateScroll

* Pass all router props to shouldUpdateScroll

* Pass saved scroll positions to shouldUpdateScroll

* Let scroll-behavior handle everything

* Let scroll-behavior also handle element checking

* Keep pathname for backwards compatibility

* Make tests pass

* Don't expose history

* Only expose read method

* Update docs

* Update docs

* Lint

* Trigger travis rebuild (empty commit)

* remove TODO, scrollbehaviour in fact does that
  • Loading branch information
stefanprobst authored and pieh committed Sep 24, 2018
1 parent 7f88243 commit ef44cff
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 39 deletions.
2 changes: 1 addition & 1 deletion packages/gatsby-link/src/__tests__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ afterEach(() => {

const getInstance = (props, pathPrefix = ``) => {
getWithPrefix()(pathPrefix)
return Link(props)
return <Link {...props} />
}

const getNavigate = () => {
Expand Down
30 changes: 2 additions & 28 deletions packages/gatsby-link/src/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*global __PATH_PREFIX__ */
import PropTypes from "prop-types"
import React from "react"
import { Link, Location } from "@reach/router"
import { Link } from "@reach/router"
import { parsePath } from "gatsby"

export function withPrefix(path) {
Expand Down Expand Up @@ -45,11 +45,8 @@ class GatsbyLink extends React.Component {
IOSupported = true
}

const { location } = props

this.state = {
IOSupported,
location,
}
this.handleRef = this.handleRef.bind(this)
}
Expand Down Expand Up @@ -97,7 +94,6 @@ class GatsbyLink extends React.Component {
getProps = this.defaultGetProps,
onClick,
onMouseEnter,
location,
/* eslint-disable no-unused-vars */
activeClassName: $activeClassName,
activeStyle: $activeStyle,
Expand Down Expand Up @@ -136,21 +132,6 @@ class GatsbyLink extends React.Component {
!e.shiftKey
) {
e.preventDefault()
// Is this link pointing to a hash on the same page? If so,
// just scroll there.
const { pathname, hash } = parsePath(prefixedTo)
if (pathname === location.pathname || !pathname) {
const element = hash
? document.getElementById(hash.substr(1))
: null
if (element !== null) {
element.scrollIntoView()
} else {
// This is just a normal link to the current page so let's emulate default
// browser behavior by scrolling now to the top of the page.
window.scrollTo(0, 0)
}
}

// Make sure the necessary scripts and data are
// loaded before continuing.
Expand All @@ -173,14 +154,7 @@ GatsbyLink.propTypes = {
replace: PropTypes.bool,
}

// eslint-disable-next-line react/display-name
const withLocation = Comp => props => (
<Location>
{({ location }) => <Comp location={location} {...props} />}
</Location>
)

export default withLocation(GatsbyLink)
export default GatsbyLink

export const navigate = (to, options) => {
window.___navigate(withPrefix(to), options)
Expand Down
10 changes: 8 additions & 2 deletions packages/gatsby/cache-dir/navigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,14 @@ window.addEventListener(`popstate`, () => {
resetRouteChangePromise()
})

function shouldUpdateScroll(prevRouterProps, { location: { pathname } }) {
function shouldUpdateScroll(prevRouterProps, { location }) {
const { pathname, hash } = location
const results = apiRunner(`shouldUpdateScroll`, {
prevRouterProps,
// `pathname` for backwards compatibility
pathname,
routerProps: { location },
getSavedScrollPosition: args => this._stateStorage.read(args),
})
if (results.length > 0) {
return results[0]
Expand All @@ -121,7 +125,9 @@ function shouldUpdateScroll(prevRouterProps, { location: { pathname } }) {
location: { pathname: oldPathname },
} = prevRouterProps
if (oldPathname === pathname) {
return false
// Scroll to element if it exists, if it doesn't, or no hash is provided,
// scroll to top.
return hash ? hash.slice(1) : [0, 0]
}
}
return true
Expand Down
6 changes: 0 additions & 6 deletions packages/gatsby/cache-dir/production-app.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,6 @@ apiRunnerAsync(`onClientEntry`).then(() => {
class RouteHandler extends React.Component {
render() {
let { location } = this.props
// TODO
// check if hash + if element and if so scroll
// remove hash handling from gatsby-link
// check if scrollbehavior handles back button for
// restoring old position
// if not, add that.

return (
<EnsureResources location={location}>
Expand Down
25 changes: 23 additions & 2 deletions packages/gatsby/src/utils/api-browser-docs.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,32 @@ exports.onRouteUpdateDelayed = true
exports.onRouteUpdate = true

/**
* Allow a plugin to decide if the "scroll" should update or
* Allow a plugin to decide if the scroll position should update or
* not on a route change.
* @param {object} $0
* @param {object} $0.prevRouterProps The previous state of the router before the route change.
* @param {object} $0.pathname The new pathname
* @param {object} $0.routerProps The current state of the router.
* @param {string} $0.pathname The new pathname (for backwards compatibility with v1).
* @param {function} $0.getSavedScrollPosition Takes a location and returns the
* coordinates of the last scroll position for that location, or `null`. Gatsby
* saves scroll positions for each route in `SessionStorage`, so they are
* available after page reload.
* @returns {(boolean|string|Array)} Should return either an [x, y] Array of
* coordinates to scroll to, a string of the `id` or `name` of an element to
* scroll to, `false` to not update the scroll position, or `true` for the
* default behavior.
* @example
* exports.shouldUpdateScroll = ({
* routerProps: { location },
* getSavedScrollPosition
* }) => {
* const currentPosition = getSavedScrollPosition(location)
* const queriedPosition = getSavedScrollPosition({ pathname: `/random` })
*
* window.scrollTo(...(currentPosition || [0, 0]))
*
* return false
* }
*/
exports.shouldUpdateScroll = true

Expand Down

0 comments on commit ef44cff

Please sign in to comment.