Skip to content

Commit

Permalink
feat(gatsby-link): adds support for partiallyActive=true to Link (#12495
Browse files Browse the repository at this point in the history
)

* Adds support for partiallyActive=true to Link

* Update index.js

* Updates the documentation

* chore: add typescript declaration(s)
  • Loading branch information
arcanis authored and DSchau committed Mar 12, 2019
1 parent 2bc1bca commit e0db681
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 16 deletions.
25 changes: 12 additions & 13 deletions docs/docs/gatsby-link.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,28 +80,27 @@ const SiteNavigation = () => (
### Show active styles for partially matched and parent links
<iframe title="Screencast on egghead of how to style partially matched links in Gatsby." class="egghead-video" width=600 height=348 src="https://egghead.io/lessons/egghead-customize-styles-for-partially-matched-urls-with-gatsby-s-link-component/embed" />
Video hosted on [egghead.io][egghead].
The `activeStyle` or `activeClassName` prop are only set on a `<Link>` component if the current URL matches its `to` prop _exactly_. Sometimes, we may want to style a `<Link>` as active even if it partially matches the current URL. For example:
By default the `activeStyle` and `activeClassName` props will only be set on a `<Link>` component if the current URL matches its `to` prop _exactly_. Sometimes, we may want to style a `<Link>` as active even if it partially matches the current URL. For example:
- We may want `/blog/hello-world` to match `<Link to="/blog">`
- Or `/gatsby-link/#passing-state-through-link-and-navigate` to match `<Link to="/gatsby-link">`
In instances like these, we can use [@reach/router's](https://reach.tech/router/api/Link) `getProps` API to set active styles as follows:
In instances like these, just add the `partiallyActive` prop to your `<Link>` component and the style will also be applied even if the `to` prop only is a partial match:
```jsx
import React from "react"
import { Link } from "gatsby"
const partiallyActive = className => ({ isPartiallyCurrent }) => ({
className: className + (isPartiallyCurrent ? ` active` : ``),
})
const PartiallyActiveLink = ({ className, ...rest }) => (
<Link getProps={partiallyActive(className)} {...rest} />
)
const Header = <>
<Link
to="/articles/"
activeStyle={{ color: "red" }}
{/* highlight-next-line */}
partiallyActive={true}
>
Articles
</Link>
</>;
```
### Pass state as props to the linked page
Expand Down
2 changes: 2 additions & 0 deletions packages/gatsby-link/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ export interface GatsbyLinkProps<TState> extends LinkProps<TState> {
activeStyle?: object
innerRef?: Function
onClick?: (event: React.MouseEvent<HTMLAnchorElement>) => void
partiallyActive?: boolean
replace?: boolean
to: string
}

Expand Down
2 changes: 1 addition & 1 deletion packages/gatsby-link/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
},
"dependencies": {
"@babel/runtime": "^7.0.0",
"@reach/router": "^1.1.1",
"@types/reach__router": "^1.0.0",
"prop-types": "^15.6.1"
},
Expand All @@ -26,6 +25,7 @@
"license": "MIT",
"main": "index.js",
"peerDependencies": {
"@reach/router": "^1.1.1",
"gatsby": "^2.0.0",
"react": "^16.4.2",
"react-dom": "^16.4.2"
Expand Down
12 changes: 12 additions & 0 deletions packages/gatsby-link/src/__tests__/__snapshots__/index.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,15 @@ exports[`<Link /> matches basic snapshot 1`] = `
</a>
</div>
`;

exports[`<Link /> matches partially active snapshot 1`] = `
<div>
<a
class="link"
href="/active/nested"
style="color: black;"
>
link
</a>
</div>
`;
7 changes: 7 additions & 0 deletions packages/gatsby-link/src/__tests__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ describe(`<Link />`, () => {
expect(container).toMatchSnapshot()
})

it(`matches partially active snapshot`, () => {
const { container } = setup({
linkProps: { to: `/active/nested`, partiallyActive: true },
})
expect(container).toMatchSnapshot()
})

it(`does not fail to initialize without --prefix-paths`, () => {
expect(() => {
getInstance({})
Expand Down
6 changes: 4 additions & 2 deletions packages/gatsby-link/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ function normalizePath(path) {
const NavLinkPropTypes = {
activeClassName: PropTypes.string,
activeStyle: PropTypes.object,
partiallyActive: PropTypes.bool,
}

// Set up IntersectionObserver
Expand Down Expand Up @@ -83,8 +84,8 @@ class GatsbyLink extends React.Component {
}
}

defaultGetProps = ({ isCurrent }) => {
if (isCurrent) {
defaultGetProps = ({ isPartiallyCurrent, isCurrent }) => {
if (this.props.partiallyActive ? isPartiallyCurrent : isCurrent) {
return {
className: [this.props.className, this.props.activeClassName]
.filter(Boolean)
Expand All @@ -105,6 +106,7 @@ class GatsbyLink extends React.Component {
activeClassName: $activeClassName,
activeStyle: $activeStyle,
innerRef: $innerRef,
partiallyActive,
state,
replace,
/* eslint-enable no-unused-vars */
Expand Down

0 comments on commit e0db681

Please sign in to comment.