Browse Source

ref(ui) Remove contextTypes from ListLink (#25937)

Remove contextTypes from ListLink. This required some runtime changes as
isActive() now needs to handle the various prop values more carefully
due to typescript having more visibility into types.
Mark Story 3 years ago
parent
commit
17bd839d68
1 changed files with 30 additions and 16 deletions
  1. 30 16
      static/app/components/links/listLink.tsx

+ 30 - 16
static/app/components/links/listLink.tsx

@@ -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',