From 4281509320299f87cd6ad571279cddca67d46176 Mon Sep 17 00:00:00 2001
From: Alexander Polyankin <alexander.polyankin@metabase.com>
Date: Tue, 7 Dec 2021 15:16:53 +0300
Subject: [PATCH] Convert basic components to TS (#19237)

---
 .../components/{Button.jsx => Button.tsx}     | 63 ++++++++++---------
 .../{ExternalLink.jsx => ExternalLink.tsx}    | 15 +++--
 frontend/src/metabase/components/Icon.tsx     | 13 ++--
 .../components/{Link.jsx => Link.tsx}         | 33 +++++-----
 4 files changed, 70 insertions(+), 54 deletions(-)
 rename frontend/src/metabase/components/{Button.jsx => Button.tsx} (72%)
 rename frontend/src/metabase/components/{ExternalLink.jsx => ExternalLink.tsx} (66%)
 rename frontend/src/metabase/components/{Link.jsx => Link.tsx} (60%)

diff --git a/frontend/src/metabase/components/Button.jsx b/frontend/src/metabase/components/Button.tsx
similarity index 72%
rename from frontend/src/metabase/components/Button.jsx
rename to frontend/src/metabase/components/Button.tsx
index d68f02e9d1c..20fdd444ea0 100644
--- a/frontend/src/metabase/components/Button.jsx
+++ b/frontend/src/metabase/components/Button.tsx
@@ -1,13 +1,10 @@
-/* eslint-disable react/prop-types */
-import React, { forwardRef } from "react";
-import PropTypes from "prop-types";
 import cx from "classnames";
-import _ from "underscore";
+import React, { ButtonHTMLAttributes, forwardRef, ReactNode, Ref } from "react";
 import styled from "styled-components";
 import { color, space } from "styled-system";
-
-import { forwardRefToInnerRef } from "metabase/styled-components/utils";
+import _ from "underscore";
 import Icon from "metabase/components/Icon";
+import { forwardRefToInnerRef } from "metabase/styled-components/utils";
 
 const BUTTON_VARIANTS = [
   "small",
@@ -23,7 +20,34 @@ const BUTTON_VARIANTS = [
   "white",
   "borderless",
   "onlyIcon",
-];
+] as const;
+
+interface Props extends ButtonHTMLAttributes<HTMLButtonElement> {
+  className?: string;
+  icon?: string;
+  iconSize?: number;
+  iconColor?: string;
+  iconRight?: string;
+  iconVertical?: boolean;
+  labelBreakpoint?: string;
+  children?: ReactNode;
+
+  small?: boolean;
+  medium?: boolean;
+  large?: boolean;
+
+  primary?: boolean;
+  success?: boolean;
+  danger?: boolean;
+  warning?: boolean;
+  cancel?: boolean;
+  white?: boolean;
+  purple?: boolean;
+
+  round?: boolean;
+  borderless?: boolean;
+  onlyIcon?: boolean;
+}
 
 const BaseButton = forwardRef(function BaseButton(
   {
@@ -34,11 +58,10 @@ const BaseButton = forwardRef(function BaseButton(
     iconColor,
     iconVertical,
     labelBreakpoint,
-    color,
     children,
     ...props
-  },
-  ref,
+  }: Props,
+  ref: Ref<HTMLButtonElement>,
 ) {
   const variantClasses = BUTTON_VARIANTS.filter(variant => props[variant]).map(
     variant => "Button--" + variant,
@@ -54,7 +77,7 @@ const BaseButton = forwardRef(function BaseButton(
     >
       <div
         className={cx("flex layout-centered", { "flex-column": iconVertical })}
-        style={iconVertical ? { minWidth: 60 } : null}
+        style={iconVertical ? { minWidth: 60 } : undefined}
       >
         {icon && (
           <Icon color={iconColor} name={icon} size={iconSize ? iconSize : 14} />
@@ -82,24 +105,6 @@ const BaseButton = forwardRef(function BaseButton(
   );
 });
 
-BaseButton.propTypes = {
-  className: PropTypes.string,
-  icon: PropTypes.string,
-  iconSize: PropTypes.number,
-  children: PropTypes.any,
-
-  small: PropTypes.bool,
-  medium: PropTypes.bool,
-  large: PropTypes.bool,
-
-  primary: PropTypes.bool,
-  warning: PropTypes.bool,
-  cancel: PropTypes.bool,
-  purple: PropTypes.bool,
-
-  borderless: PropTypes.bool,
-};
-
 const Button = forwardRefToInnerRef(styled(BaseButton)`
   ${color};
   ${space};
diff --git a/frontend/src/metabase/components/ExternalLink.jsx b/frontend/src/metabase/components/ExternalLink.tsx
similarity index 66%
rename from frontend/src/metabase/components/ExternalLink.jsx
rename to frontend/src/metabase/components/ExternalLink.tsx
index 2cadcb73c68..9f3c651e0af 100644
--- a/frontend/src/metabase/components/ExternalLink.jsx
+++ b/frontend/src/metabase/components/ExternalLink.tsx
@@ -1,11 +1,16 @@
-/* eslint-disable react/prop-types */
-import React, { forwardRef } from "react";
-
+import React, { AnchorHTMLAttributes, forwardRef, ReactNode, Ref } from "react";
 import { getUrlTarget } from "metabase/lib/dom";
 
+interface Props extends AnchorHTMLAttributes<HTMLAnchorElement> {
+  href?: string;
+  target?: string;
+  className?: string;
+  children?: ReactNode;
+}
+
 const ExternalLink = forwardRef(function ExternalLink(
-  { href, target = getUrlTarget(href), className, children, ...props },
-  ref,
+  { href, target = getUrlTarget(href), className, children, ...props }: Props,
+  ref: Ref<HTMLAnchorElement>,
 ) {
   return (
     <a
diff --git a/frontend/src/metabase/components/Icon.tsx b/frontend/src/metabase/components/Icon.tsx
index 7595c1f3fe2..7fc41a43de4 100644
--- a/frontend/src/metabase/components/Icon.tsx
+++ b/frontend/src/metabase/components/Icon.tsx
@@ -1,13 +1,12 @@
+import cx from "classnames";
 import PropTypes from "prop-types";
 import React, { Component, forwardRef } from "react";
 import styled from "styled-components";
-import { color, space, hover } from "styled-system";
-import cx from "classnames";
-
-import { color as c } from "metabase/lib/colors";
+import { color, hover, space } from "styled-system";
+import Tooltip from "metabase/components/Tooltip";
 import { loadIcon } from "metabase/icon_paths";
+import { color as c } from "metabase/lib/colors";
 import { stripLayoutProps } from "metabase/lib/utils";
-import Tooltip from "metabase/components/Tooltip";
 import { forwardRefToInnerRef } from "metabase/styled-components/utils";
 
 const MISSING_ICON_NAME = "unknown";
@@ -51,13 +50,15 @@ const stringOrNumberPropType = PropTypes.oneOfType([
 
 export const iconPropTypes = {
   name: PropTypes.string.isRequired,
+  color: PropTypes.string,
   size: stringOrNumberPropType,
   width: stringOrNumberPropType,
   height: stringOrNumberPropType,
   scale: stringOrNumberPropType,
   tooltip: PropTypes.string,
   className: PropTypes.string,
-  innerRef: PropTypes.func.isRequired,
+  innerRef: PropTypes.any,
+  onClick: PropTypes.func,
 };
 
 type IconProps = PropTypes.InferProps<typeof iconPropTypes>;
diff --git a/frontend/src/metabase/components/Link.jsx b/frontend/src/metabase/components/Link.tsx
similarity index 60%
rename from frontend/src/metabase/components/Link.jsx
rename to frontend/src/metabase/components/Link.tsx
index 689e2b6e81c..c775485039d 100644
--- a/frontend/src/metabase/components/Link.jsx
+++ b/frontend/src/metabase/components/Link.tsx
@@ -1,22 +1,27 @@
-import React from "react";
 import cx from "classnames";
-import PropTypes from "prop-types";
-import { Link as ReactRouterLink } from "react-router";
+import React, { ReactNode } from "react";
+import { Link as ReactRouterLink, LinkProps } from "react-router";
 import styled from "styled-components";
-import { display, color, hover, space } from "styled-system";
-
-import { stripLayoutProps } from "metabase/lib/utils";
+import { color, display, hover, space } from "styled-system";
 import Tooltip from "metabase/components/Tooltip";
+import { stripLayoutProps } from "metabase/lib/utils";
 
-BaseLink.propTypes = {
-  to: PropTypes.string.isRequired,
-  disabled: PropTypes.bool,
-  className: PropTypes.string,
-  children: PropTypes.node,
-  tooltip: PropTypes.string,
-};
+interface Props extends LinkProps {
+  to: string;
+  disabled?: boolean;
+  className?: string;
+  children?: ReactNode;
+  tooltip?: string;
+}
 
-function BaseLink({ to, className, children, disabled, tooltip, ...props }) {
+function BaseLink({
+  to,
+  className,
+  children,
+  disabled,
+  tooltip,
+  ...props
+}: Props) {
   const link = (
     <ReactRouterLink
       to={to}
-- 
GitLab