|
@@ -1,10 +1,10 @@
|
|
|
import * as React from 'react';
|
|
|
-import {Link} from 'react-router';
|
|
|
+import {Link, withRouter, WithRouterProps} from 'react-router';
|
|
|
import styled from '@emotion/styled';
|
|
|
import classNames from 'classnames';
|
|
|
import {LocationDescriptor} from 'history';
|
|
|
import omit from 'lodash/omit';
|
|
|
-import PropTypes from 'prop-types';
|
|
|
+import * as qs from 'query-string';
|
|
|
|
|
|
type DefaultProps = {
|
|
|
index: boolean;
|
|
@@ -12,7 +12,8 @@ type DefaultProps = {
|
|
|
disabled: boolean;
|
|
|
};
|
|
|
|
|
|
-type Props = DefaultProps &
|
|
|
+type Props = WithRouterProps &
|
|
|
+ Partial<DefaultProps> &
|
|
|
React.ComponentProps<typeof Link> & {
|
|
|
query?: string;
|
|
|
// If supplied by parent component, decides whether link element
|
|
@@ -24,23 +25,28 @@ type Props = DefaultProps &
|
|
|
class ListLink extends React.Component<Props> {
|
|
|
static displayName = 'ListLink';
|
|
|
|
|
|
- static contextTypes = {
|
|
|
- router: PropTypes.object.isRequired,
|
|
|
- };
|
|
|
-
|
|
|
static defaultProps: DefaultProps = {
|
|
|
activeClassName: 'active',
|
|
|
index: false,
|
|
|
disabled: false,
|
|
|
};
|
|
|
|
|
|
- isActive = () => {
|
|
|
- const {isActive, to, query, index} = this.props;
|
|
|
+ isActive() {
|
|
|
+ const {isActive, to, query, index, location, router} = this.props;
|
|
|
+ const queryData = query ? qs.parse(query) : undefined;
|
|
|
+ const target: LocationDescriptor =
|
|
|
+ typeof to === 'string'
|
|
|
+ ? {pathname: to, query: queryData}
|
|
|
+ : typeof to === 'function'
|
|
|
+ ? to(location)
|
|
|
+ : to;
|
|
|
|
|
|
- // TODO(ts) Removing context here results in a TypeError because `to` is not compatible
|
|
|
- // with LocationDescriptor.
|
|
|
- return (isActive || this.context.router.isActive)({pathname: to, query}, index);
|
|
|
- };
|
|
|
+ if (typeof isActive === 'function') {
|
|
|
+ return isActive(target, index);
|
|
|
+ }
|
|
|
+
|
|
|
+ return router.isActive(target, index);
|
|
|
+ }
|
|
|
|
|
|
getClassName = () => {
|
|
|
const _classNames = {};
|
|
@@ -50,7 +56,7 @@ class ListLink extends React.Component<Props> {
|
|
|
_classNames[className] = true;
|
|
|
}
|
|
|
|
|
|
- if (this.isActive()) {
|
|
|
+ if (this.isActive() && activeClassName) {
|
|
|
_classNames[activeClassName] = true;
|
|
|
}
|
|
|
|
|
@@ -59,7 +65,15 @@ class ListLink extends React.Component<Props> {
|
|
|
|
|
|
render() {
|
|
|
const {index, children, to, disabled, ...props} = this.props;
|
|
|
- const carriedProps = omit(props, 'activeClassName', 'isActive', 'index');
|
|
|
+ const carriedProps = omit(
|
|
|
+ props,
|
|
|
+ 'activeClassName',
|
|
|
+ 'css',
|
|
|
+ 'isActive',
|
|
|
+ 'index',
|
|
|
+ 'router',
|
|
|
+ 'location'
|
|
|
+ );
|
|
|
|
|
|
return (
|
|
|
<StyledLi className={this.getClassName()} disabled={disabled}>
|
|
@@ -71,7 +85,7 @@ class ListLink extends React.Component<Props> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-export default ListLink;
|
|
|
+export default withRouter(ListLink);
|
|
|
|
|
|
const StyledLi = styled('li', {
|
|
|
shouldForwardProp: prop => prop !== 'disabled',
|