diff --git a/frontend/src/metabase/components/TokenField/TokenField.styled.tsx b/frontend/src/metabase/components/TokenField/TokenField.styled.tsx index 70bd7e7448ac5f9a65a856db06a6250d47ee399c..82b4a3974b0abd3a2bc85ed303b415c04cf4651d 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 4228e503f3ade875f264d889182616d57a48e42f..5fa879cddbcdade013a2778e5ef42c950b4dd695 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 0000000000000000000000000000000000000000..45ceedf409cf7946921904220f1205f02bf22e8f --- /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 0000000000000000000000000000000000000000..9eb4a06ee18fd5fe70af574d305773698c86d488 --- /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 0000000000000000000000000000000000000000..f948be60005dd8494e0dcf862403e0c82d0032fa --- /dev/null +++ b/frontend/src/metabase/components/TokenFieldItem/index.ts @@ -0,0 +1 @@ +export * from "./TokenFieldItem.styled";