diff --git a/packages/gatsby-link/index.d.ts b/packages/gatsby-link/index.d.ts
index 039dc625bd465..c2a76e17bb95a 100644
--- a/packages/gatsby-link/index.d.ts
+++ b/packages/gatsby-link/index.d.ts
@@ -2,7 +2,6 @@ import * as React from "react";
import { NavLinkProps } from "react-router-dom";
export interface GatsbyLinkProps extends NavLinkProps {
- to: string;
onClick?: (event: any) => void
className?: string
}
diff --git a/packages/gatsby-link/src/__tests__/index.js b/packages/gatsby-link/src/__tests__/index.js
index f79aa0645fcd8..0c926a4e20322 100644
--- a/packages/gatsby-link/src/__tests__/index.js
+++ b/packages/gatsby-link/src/__tests__/index.js
@@ -1,11 +1,17 @@
+import React from "react"
+import ReactDOM from "react-dom"
+import { MemoryRouter } from "react-router-dom"
+
const getInstance = (props, pathPrefix = ``) => {
Object.assign(global.window, {
__PREFIX_PATHS__: pathPrefix ? true : false,
__PATH_PREFIX__: pathPrefix,
})
+ const context = { router: { history: {} } }
+
const Link = require(`../`).default
- return new Link(props)
+ return new Link(props, context)
}
const getNavigateTo = () => {
@@ -27,8 +33,9 @@ const getWithPrefix = (pathPrefix = ``) => {
describe(``, () => {
it(`does not fail to initialize when __PREFIX_PATHS__ is not defined`, () => {
expect(() => {
+ const context = { router: { history: {} } }
const Link = require(`../`).default
- const link = new Link({}) //eslint-disable-line no-unused-vars
+ const link = new Link({}, context) //eslint-disable-line no-unused-vars
}).not.toThrow()
})
@@ -39,7 +46,7 @@ describe(``, () => {
to,
})
- expect(instance.state.to).toEqual(to)
+ expect(instance.state.to.pathname).toEqual(to)
})
/*
@@ -60,6 +67,74 @@ describe(``, () => {
})
})
+ describe(`the location to link to`, () => {
+ global.___loader = {
+ enqueue: jest.fn(),
+ }
+
+ it(`accepts to as a string`, () => {
+ const location = `/courses?sort=name`
+
+ const node = document.createElement(`div`)
+ const Link = require(`../`).default
+
+ ReactDOM.render(
+
+ link
+ ,
+ node
+ )
+
+ const href = node.querySelector(`a`).getAttribute(`href`)
+
+ expect(href).toEqual(location)
+ })
+
+ it(`accepts a location "to" prop`, () => {
+ const location = {
+ pathname: `/courses`,
+ search: `?sort=name`,
+ hash: `#the-hash`,
+ state: { fromDashboard: true },
+ }
+
+ const node = document.createElement(`div`)
+ const Link = require(`../`).default
+
+ ReactDOM.render(
+
+ link
+ ,
+ node
+ )
+
+ const href = node.querySelector(`a`).getAttribute(`href`)
+
+ expect(href).toEqual(`/courses?sort=name#the-hash`)
+ })
+
+ it(`resolves to with no pathname using current location`, () => {
+ const location = {
+ search: `?sort=name`,
+ hash: `#the-hash`,
+ }
+
+ const node = document.createElement(`div`)
+ const Link = require(`../`).default
+
+ ReactDOM.render(
+
+ link
+ ,
+ node
+ )
+
+ const href = node.querySelector(`a`).getAttribute(`href`)
+
+ expect(href).toEqual(`/somewhere?sort=name#the-hash`)
+ })
+ })
+
it(`navigateTo is called with correct args`, () => {
getNavigateTo()(`/some-path`)
diff --git a/packages/gatsby-link/src/index.js b/packages/gatsby-link/src/index.js
index 0065f651d54a8..853298429fc49 100644
--- a/packages/gatsby-link/src/index.js
+++ b/packages/gatsby-link/src/index.js
@@ -2,6 +2,7 @@
import React from "react"
import { Link, NavLink } from "react-router-dom"
import PropTypes from "prop-types"
+import { createLocation as cL, createPath } from "history"
let pathPrefix = `/`
if (typeof __PREFIX_PATHS__ !== `undefined` && __PREFIX_PATHS__) {
@@ -16,6 +17,12 @@ function normalizePath(path) {
return path.replace(/^\/\//g, `/`)
}
+function createLocation(path, history) {
+ const location = cL(path, null, null, history.location)
+ location.pathname = withPrefix(location.pathname)
+ return location
+}
+
const NavLinkPropTypes = {
activeClassName: PropTypes.string,
activeStyle: PropTypes.object,
@@ -45,7 +52,7 @@ const handleIntersection = (el, cb) => {
}
class GatsbyLink extends React.Component {
- constructor(props) {
+ constructor(props, context) {
super()
// Default to no support for IntersectionObserver
let IOSupported = false
@@ -53,8 +60,12 @@ class GatsbyLink extends React.Component {
IOSupported = true
}
+ const { history } = context.router
+ const to = createLocation(props.to, history)
+
this.state = {
- to: withPrefix(props.to),
+ path: createPath(to),
+ to,
IOSupported,
}
this.handleRef = this.handleRef.bind(this)
@@ -62,12 +73,14 @@ class GatsbyLink extends React.Component {
componentWillReceiveProps(nextProps) {
if (this.props.to !== nextProps.to) {
+ const to = createLocation(nextProps.to, history)
this.setState({
- to: withPrefix(nextProps.to),
+ path: createPath(to),
+ to,
})
// Preserve non IO functionality if no support
if (!this.state.IOSupported) {
- ___loader.enqueue(this.state.to)
+ ___loader.enqueue(this.state.path)
}
}
}
@@ -75,7 +88,7 @@ class GatsbyLink extends React.Component {
componentDidMount() {
// Preserve non IO functionality if no support
if (!this.state.IOSupported) {
- ___loader.enqueue(this.state.to)
+ ___loader.enqueue(this.state.path)
}
}
@@ -85,7 +98,7 @@ class GatsbyLink extends React.Component {
if (this.state.IOSupported && ref) {
// If IO supported and element reference found, setup Observer functionality
handleIntersection(ref, () => {
- ___loader.enqueue(this.state.to)
+ ___loader.enqueue(this.state.path)
})
}
}
@@ -116,7 +129,7 @@ class GatsbyLink extends React.Component {
) {
// Is this link pointing to a hash on the same page? If so,
// just scroll there.
- let pathname = this.state.to
+ let pathname = this.state.path
if (pathname.split(`#`).length > 1) {
pathname = pathname
.split(`#`)
@@ -124,7 +137,7 @@ class GatsbyLink extends React.Component {
.join(``)
}
if (pathname === window.location.pathname) {
- const hashFragment = this.state.to
+ const hashFragment = this.state.path
.split(`#`)
.slice(1)
.join(`#`)
@@ -139,7 +152,7 @@ class GatsbyLink extends React.Component {
// loaded before continuing.
if (process.env.NODE_ENV === `production`) {
e.preventDefault()
- window.___navigateTo(this.state.to)
+ window.___navigateTo(this.state.path)
}
}
@@ -157,7 +170,7 @@ GatsbyLink.propTypes = {
...NavLinkPropTypes,
innerRef: PropTypes.func,
onClick: PropTypes.func,
- to: PropTypes.string.isRequired,
+ to: PropTypes.oneOfType([PropTypes.string, PropTypes.object]).isRequired,
}
GatsbyLink.contextTypes = {
@@ -167,5 +180,5 @@ GatsbyLink.contextTypes = {
export default GatsbyLink
export const navigateTo = pathname => {
- window.___navigateTo(withPrefix(pathname))
+ window.___navigateTo(pathname)
}