Created
April 11, 2016 08:39
-
-
Save xymostech/51578b633c6a6238e137412064a6937a to your computer and use it in GitHub Desktop.
Make React Router's Link work with Aphrodite
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// almost 100% stolen from https://github.com/reactjs/react-router/blob/master/modules/Link.js | |
import React from 'react' | |
import { css } from 'aphrodite'; | |
import warning from './routerWarning' | |
const { bool, object, string, func, oneOfType } = React.PropTypes | |
function isLeftClickEvent(event) { | |
return event.button === 0 | |
} | |
function isModifiedEvent(event) { | |
return !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey) | |
} | |
// TODO: De-duplicate against hasAnyProperties in createTransitionManager. | |
function isEmptyObject(object) { | |
for (const p in object) | |
if (Object.prototype.hasOwnProperty.call(object, p)) | |
return false | |
return true | |
} | |
function createLocationDescriptor(to, { query, hash, state }) { | |
if (query || hash || state) { | |
return { pathname: to, query, hash, state } | |
} | |
return to | |
} | |
/** | |
* A <Link> is used to create an <a> element that links to a route. | |
* When that route is active, the link gets the value of its | |
* activeClassName prop. | |
* | |
* For example, assuming you have the following route: | |
* | |
* <Route path="/posts/:postID" component={Post} /> | |
* | |
* You could use the following component to link to that route: | |
* | |
* <Link to={`/posts/${post.id}`} /> | |
* | |
* Links may pass along location state and/or query string parameters | |
* in the state/query props, respectively. | |
* | |
* <Link ... query={{ show: true }} state={{ the: 'state' }} /> | |
*/ | |
const Link = React.createClass({ | |
contextTypes: { | |
router: object | |
}, | |
propTypes: { | |
to: oneOfType([ string, object ]).isRequired, | |
query: object, | |
hash: string, | |
state: object, | |
style: object, | |
activeStyle: object, | |
onlyActiveOnIndex: bool.isRequired, | |
onClick: func | |
}, | |
getDefaultProps() { | |
return { | |
onlyActiveOnIndex: false, | |
style: null | |
} | |
}, | |
handleClick(event) { | |
let allowTransition = true | |
if (this.props.onClick) | |
this.props.onClick(event) | |
if (isModifiedEvent(event) || !isLeftClickEvent(event)) | |
return | |
if (event.defaultPrevented === true) | |
allowTransition = false | |
// If target prop is set (e.g. to "_blank") let browser handle link. | |
/* istanbul ignore if: untestable with Karma */ | |
if (this.props.target) { | |
if (!allowTransition) | |
event.preventDefault() | |
return | |
} | |
event.preventDefault() | |
if (allowTransition) { | |
const { to, query, hash, state } = this.props | |
const location = createLocationDescriptor(to, { query, hash, state }) | |
this.context.router.push(location) | |
} | |
}, | |
render() { | |
const { to, query, hash, state, activeClassName, activeStyle, onlyActiveOnIndex, ...props } = this.props | |
warning( | |
!(query || hash || state), | |
'the `query`, `hash`, and `state` props on `<Link>` are deprecated, use `<Link to={{ pathname, query, hash, state }}/>. http://tiny.cc/router-isActivedeprecated' | |
) | |
// Ignore if rendered outside the context of router, simplifies unit testing. | |
const { router } = this.context | |
if (router) { | |
const location = createLocationDescriptor(to, { query, hash, state }) | |
props.href = router.createHref(location) | |
props.className = css( | |
props.style, | |
router.isActive(location, onlyActiveOnIndex) && props.activeStyle | |
) | |
} else { | |
props.className = css(props.style) | |
} | |
return <a {...props} onClick={this.handleClick} /> | |
} | |
}) | |
export default Link |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment