From 875b7cc53365e2d7db180a4e391bb7c068983cbd Mon Sep 17 00:00:00 2001
From: Ryan Laurie <30528226+iethree@users.noreply.github.com>
Date: Fri, 29 Jul 2022 08:04:40 -0600
Subject: [PATCH] Extract TokenFieldItem component (#24377)

* extract TokenFieldItem component

* remove unnecessary spread
---
 .../TokenField/TokenField.styled.tsx          | 49 ++++++-------
 .../components/TokenField/TokenField.tsx      | 23 ++-----
 .../TokenFieldItem/TokenFieldItem.stories.tsx | 69 +++++++++++++++++++
 .../TokenFieldItem/TokenFieldItem.styled.ts   | 31 +++++++++
 .../components/TokenFieldItem/index.ts        |  1 +
 5 files changed, 129 insertions(+), 44 deletions(-)
 create mode 100644 frontend/src/metabase/components/TokenFieldItem/TokenFieldItem.stories.tsx
 create mode 100644 frontend/src/metabase/components/TokenFieldItem/TokenFieldItem.styled.ts
 create mode 100644 frontend/src/metabase/components/TokenFieldItem/index.ts

diff --git a/frontend/src/metabase/components/TokenField/TokenField.styled.tsx b/frontend/src/metabase/components/TokenField/TokenField.styled.tsx
index 70bd7e7448a..82b4a3974b0 100644
--- a/frontend/src/metabase/components/TokenField/TokenField.styled.tsx
+++ b/frontend/src/metabase/components/TokenField/TokenField.styled.tsx
@@ -1,33 +1,27 @@
 import styled from "@emotion/styled";
-import { color, alpha } from "metabase/lib/colors";
-import { breakpointMinHeightMedium } from "metabase/styled-components/theme";
 
-export const TokenFieldItem = styled.li<{
-  isValid: boolean;
-}>`
-  display: flex;
-  align-items: center;
-  margin: 0.25rem;
-  padding: 0.5rem 0.3rem;
-  ${breakpointMinHeightMedium} {
-    padding: 0.75rem 0.5rem;
-  }
-  border-radius: 0.5rem;
-  color: ${({ isValid }) => (isValid ? color("brand") : color("error"))};
-  background-color: ${alpha("brand", 0.2)};
-`;
+import { color } from "metabase/lib/colors";
 
-export const TokenFieldAddon = styled.a<{
-  isValid: boolean;
-}>`
+import {
+  space,
+  breakpointMinHeightMedium,
+} from "metabase/styled-components/theme";
+
+export const TokenFieldContainer = styled.ul`
   display: flex;
-  align-items: center;
-  padding: 0 0.5rem;
-  color: ${({ isValid }) => (isValid ? "" : color("error"))};
+  flex-wrap: wrap;
+  padding: ${space(0)};
+  gap: ${space(0)};
+  font-weight: bold;
+  cursor: pointer;
 
-  &:hover {
-    color: ${color("error")};
-  }
+  max-height: 130px;
+
+  background-color: ${color("white")};
+  overflow-x: auto;
+  overflow-y: auto;
+  border-radius: ${space(1)};
+  border: 1px solid ${color("border-dark")};
 `;
 
 export const TokenInputItem = styled.li`
@@ -36,9 +30,8 @@ export const TokenInputItem = styled.li`
   align-items: center;
   margin-right: 0.5rem;
   padding: 0.5rem;
-
-  height: 38px;
+  height: 30px;
   ${breakpointMinHeightMedium} {
-    height: 54px;
+    height: 46px;
   }
 `;
diff --git a/frontend/src/metabase/components/TokenField/TokenField.tsx b/frontend/src/metabase/components/TokenField/TokenField.tsx
index 4228e503f3a..5fa879cddbc 100644
--- a/frontend/src/metabase/components/TokenField/TokenField.tsx
+++ b/frontend/src/metabase/components/TokenField/TokenField.tsx
@@ -6,11 +6,7 @@ import cx from "classnames";
 
 import Icon from "metabase/components/Icon";
 import TippyPopover from "metabase/components/Popover/TippyPopover";
-import {
-  TokenFieldAddon,
-  TokenFieldItem,
-  TokenInputItem,
-} from "./TokenField.styled";
+import { TokenFieldAddon, TokenFieldItem } from "../TokenFieldItem";
 
 import {
   KEYCODE_ESCAPE,
@@ -23,6 +19,8 @@ import {
 } from "metabase/lib/keyboard";
 import { isObscured } from "metabase/lib/dom";
 
+import { TokenInputItem, TokenFieldContainer } from "./TokenField.styled";
+
 export type LayoutRendererArgs = {
   valuesList: React.ReactNode;
   optionsList: React.ReactNode;
@@ -574,12 +572,8 @@ export default class TokenField extends Component<
 
     const isControlledInput = !!this.onInputChange;
     const valuesList = (
-      <ul
-        className={cx(
-          className,
-          "p0 flex align-center flex-wrap bg-white scroll-x scroll-y",
-        )}
-        style={{ maxHeight: 130, ...style }}
+      <TokenFieldContainer
+        style={style}
         onMouseDownCapture={this.onMouseDownCapture}
       >
         {!!prefix && (
@@ -589,10 +583,7 @@ export default class TokenField extends Component<
         )}
         {value.map((v, index) => (
           <TokenFieldItem key={index} isValid={validateValue(v)}>
-            <span
-              style={{ ...defaultStyleValue, ...valueStyle }}
-              className={multi ? "pl1 pr0" : "px1"}
-            >
+            <span style={{ ...defaultStyleValue, ...valueStyle }}>
               {valueRenderer(v)}
             </span>
             {multi && (
@@ -628,7 +619,7 @@ export default class TokenField extends Component<
             />
           </TokenInputItem>
         )}
-      </ul>
+      </TokenFieldContainer>
     );
 
     const optionsList =
diff --git a/frontend/src/metabase/components/TokenFieldItem/TokenFieldItem.stories.tsx b/frontend/src/metabase/components/TokenFieldItem/TokenFieldItem.stories.tsx
new file mode 100644
index 00000000000..45ceedf409c
--- /dev/null
+++ b/frontend/src/metabase/components/TokenFieldItem/TokenFieldItem.stories.tsx
@@ -0,0 +1,69 @@
+import React from "react";
+import { ComponentStory } from "@storybook/react";
+
+import { TokenFieldItem, TokenFieldAddon } from "./TokenFieldItem.styled";
+
+import Icon from "../Icon";
+
+export default {
+  title: "Core/TokenFieldItem",
+  component: TokenFieldItem,
+};
+
+const Wrapper = ({ children }: { children: JSX.Element | JSX.Element[] }) => (
+  <div style={{ display: "flex", flexWrap: "wrap", maxWidth: 400 }}>
+    {children}
+  </div>
+);
+
+const Template: ComponentStory<typeof TokenFieldItem> = args => {
+  return (
+    <Wrapper>
+      <TokenFieldItem {...args} />
+    </Wrapper>
+  );
+};
+
+const ManyTemplate: ComponentStory<typeof TokenFieldItem> = args => {
+  return (
+    <Wrapper>
+      <TokenFieldItem {...args}> {`${args.children} 1`} </TokenFieldItem>
+      <TokenFieldItem {...args}> {`${args.children} 2`} </TokenFieldItem>
+      <TokenFieldItem {...args}> {`${args.children} 3`} </TokenFieldItem>
+      <TokenFieldItem {...args}> {`${args.children} 4`} </TokenFieldItem>
+      <TokenFieldItem {...args}> {`${args.children} 5`} </TokenFieldItem>
+    </Wrapper>
+  );
+};
+
+const AddonTemplate: ComponentStory<typeof TokenFieldItem> = args => {
+  return (
+    <Wrapper>
+      <TokenFieldItem isValid={args.isValid}>
+        {args.children}
+        <TokenFieldAddon isValid={args.isValid}>
+          <Icon name="close" className="flex align-center" size={12} />
+        </TokenFieldAddon>
+      </TokenFieldItem>
+    </Wrapper>
+  );
+};
+
+export const Default = Template.bind({});
+export const Many = ManyTemplate.bind({});
+export const WithAddon = AddonTemplate.bind({});
+
+Default.args = {
+  isValid: true,
+  children: "Token Item Value",
+};
+
+Many.args = {
+  isValid: true,
+  children: "Token Item Value",
+};
+
+WithAddon.args = {
+  isValid: true,
+  children: "Token Item Value",
+};
diff --git a/frontend/src/metabase/components/TokenFieldItem/TokenFieldItem.styled.ts b/frontend/src/metabase/components/TokenFieldItem/TokenFieldItem.styled.ts
new file mode 100644
index 00000000000..9eb4a06ee18
--- /dev/null
+++ b/frontend/src/metabase/components/TokenFieldItem/TokenFieldItem.styled.ts
@@ -0,0 +1,31 @@
+import styled from "@emotion/styled";
+import { color, alpha } from "metabase/lib/colors";
+import { breakpointMinHeightMedium } from "metabase/styled-components/theme";
+
+export const TokenFieldItem = styled.li<{
+  isValid: boolean;
+}>`
+  display: flex;
+  align-items: center;
+  padding: 0.75rem 1rem;
+  height: 30px;
+  ${breakpointMinHeightMedium} {
+    height: 46px;
+  }
+  border-radius: 0.5rem;
+  color: ${({ isValid }) => (isValid ? color("brand") : color("error"))};
+  background-color: ${alpha("brand", 0.2)};
+`;
+
+export const TokenFieldAddon = styled.a<{
+  isValid: boolean;
+}>`
+  display: flex;
+  align-items: center;
+  margin-left: 0.5rem;
+  color: ${({ isValid }) => (isValid ? "" : color("error"))};
+
+  &:hover {
+    color: ${color("error")};
+  }
+`;
diff --git a/frontend/src/metabase/components/TokenFieldItem/index.ts b/frontend/src/metabase/components/TokenFieldItem/index.ts
new file mode 100644
index 00000000000..f948be60005
--- /dev/null
+++ b/frontend/src/metabase/components/TokenFieldItem/index.ts
@@ -0,0 +1 @@
+export * from "./TokenFieldItem.styled";
-- 
GitLab