From 436d54fddb7f9517b18e2a6da442ee4d002d7cfc Mon Sep 17 00:00:00 2001 From: Daniel Sil Date: Wed, 24 Jan 2024 18:51:50 +0100 Subject: [PATCH] feat(Tag): migrate to Tailwind --- docs/src/data/tailwind-migration-status.yaml | 2 +- packages/orbit-components/src/Tag/README.md | 10 +- packages/orbit-components/src/Tag/consts.ts | 6 - .../src/Tag/helpers/resolveCircleColor.ts | 12 - .../src/Tag/helpers/resolveColor.ts | 28 -- packages/orbit-components/src/Tag/index.tsx | 324 +++++------------- 6 files changed, 92 insertions(+), 290 deletions(-) delete mode 100644 packages/orbit-components/src/Tag/helpers/resolveCircleColor.ts delete mode 100644 packages/orbit-components/src/Tag/helpers/resolveColor.ts diff --git a/docs/src/data/tailwind-migration-status.yaml b/docs/src/data/tailwind-migration-status.yaml index e9913e1f82..0b270c09ba 100644 --- a/docs/src/data/tailwind-migration-status.yaml +++ b/docs/src/data/tailwind-migration-status.yaml @@ -96,7 +96,7 @@ TableRow: true Tabs: true TabPanels: true TabList: true -Tag: false +Tag: true Tile: true TileGroup: true OrbitText: true diff --git a/packages/orbit-components/src/Tag/README.md b/packages/orbit-components/src/Tag/README.md index f190ad2012..effd1f2e4c 100644 --- a/packages/orbit-components/src/Tag/README.md +++ b/packages/orbit-components/src/Tag/README.md @@ -21,14 +21,14 @@ Table below contains all types of the props available in the Tag component. | **children** | `React.Node` | | The content of the Tag. | | dataTest | `string` | | Optional prop for testing purposes. | | iconLeft | `React.Node` | | The displayed icon on the left. | -| id | `string` | | Set `id` for `Tag` | -| dateTag | `string` | | Optional prop, if it's true, selected color has ink background | +| id | `string` | | Set `id` for `Tag`. | +| dateTag | `string` | | Optional prop, if it's true, selected color has a different background. | | type | [`enum`](#enum) | `neutral` | The color type of the Tag. | | onClick | `() => void \| Promise` | | Function for handling the onClick event. | | onRemove | `() => void \| Promise` | | Function for handling the onClick event of the close icon. [See Functional specs](#functional-specs) | -| selected | `boolean` | `false` | If `true`, the Tag will have selected styles. [See Functional specs](#functional-specs) | +| selected | `boolean` | `false` | If `true`, the Tag will have selected styles. | | size | [`enum`](#enum) | `small` | Size of the Tag. | -| ref | `func` | | Prop for forwarded ref of the Tag | +| ref | `func` | | Prop for forwarded ref of the Tag. | ### enum @@ -39,4 +39,4 @@ Table below contains all types of the props available in the Tag component. ## Functional specs -- By passing the `onRemove` the close icon will appear on the left side of the Tag. +- By passing the `onRemove` the close icon will appear on the right side of the Tag. diff --git a/packages/orbit-components/src/Tag/consts.ts b/packages/orbit-components/src/Tag/consts.ts index cda527ee39..099bb3337e 100644 --- a/packages/orbit-components/src/Tag/consts.ts +++ b/packages/orbit-components/src/Tag/consts.ts @@ -3,12 +3,6 @@ export enum SIZES { NORMAL = "normal", } -export enum STATES { - DEFAULT = "default", - HOVER = "hover", - ACTIVE = "active", -} - export enum TYPES { COLORED = "colored", NEUTRAL = "neutral", diff --git a/packages/orbit-components/src/Tag/helpers/resolveCircleColor.ts b/packages/orbit-components/src/Tag/helpers/resolveCircleColor.ts deleted file mode 100644 index 8a50bcbeda..0000000000 --- a/packages/orbit-components/src/Tag/helpers/resolveCircleColor.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { TYPES } from "../consts"; -import type { Type } from "../types"; -import type { Theme } from "../../defaultTheme"; - -const resolveColor = - () => - ({ theme, selected, type }: { theme: Theme; selected?: boolean; type?: Type }): string => { - if (selected) return theme.orbit.paletteWhite; - return type === TYPES.NEUTRAL ? theme.orbit.paletteInkDark : theme.orbit.paletteBlueDarker; - }; - -export default resolveColor; diff --git a/packages/orbit-components/src/Tag/helpers/resolveColor.ts b/packages/orbit-components/src/Tag/helpers/resolveColor.ts deleted file mode 100644 index 5a68f5fba8..0000000000 --- a/packages/orbit-components/src/Tag/helpers/resolveColor.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { Theme } from "../../defaultTheme"; - -const resolveColor = - ({ - removable: removableColor, - selected: selectedColor, - normal: normalColor, - }: { - removable: string; - selected: string; - normal: string; - }) => - ({ - theme, - selected, - removable, - }: { - theme: Theme; - selected?: boolean; - removable?: boolean; - }): string => { - if (removable && !selected) return theme.orbit[removableColor]; - if (selected) return theme.orbit[selectedColor]; - - return theme.orbit[normalColor]; - }; - -export default resolveColor; diff --git a/packages/orbit-components/src/Tag/index.tsx b/packages/orbit-components/src/Tag/index.tsx index b639ad1e56..168d1ae63e 100644 --- a/packages/orbit-components/src/Tag/index.tsx +++ b/packages/orbit-components/src/Tag/index.tsx @@ -1,221 +1,25 @@ "use client"; import * as React from "react"; -import styled, { css } from "styled-components"; +import cx from "clsx"; import type * as Common from "../common/types"; -import type { Theme } from "../defaultTheme"; -import defaultTheme from "../defaultTheme"; -import { left } from "../utils/rtl"; import CloseCircle from "../icons/CloseCircle"; -import { SIZES, STATES, TYPES } from "./consts"; -import KEY_CODE_MAP from "../common/keyMaps"; -import resolveColor from "./helpers/resolveColor"; -import resolveCircleColor from "./helpers/resolveCircleColor"; -import mq from "../utils/mediaQuery"; -import type { Props, Type } from "./types"; - -const getFontSize = ({ theme, size }: { theme: Theme; size: Props["size"] }): string | null => { - const tokens = { - [SIZES.SMALL]: theme.orbit.fontSizeTextSmall, - [SIZES.NORMAL]: theme.orbit.fontSizeTextNormal, - }; - - if (!size) return null; - - return tokens[size]; -}; - -const getBackgroundColor = - (state: string) => - ({ type, dateTag }: { type: Type; size: Props["size"]; dateTag?: boolean }): string => { - const states = { - [TYPES.COLORED]: { - [STATES.DEFAULT]: resolveColor({ - selected: dateTag ? "paletteInkLightHover" : "paletteBlueNormal", - removable: "paletteBlueLight", - normal: "paletteBlueLight", - }), - [STATES.HOVER]: resolveColor({ - selected: dateTag ? "paletteInkLightActive" : "paletteBlueNormalHover", - removable: "paletteBlueLightHover", - normal: "paletteBlueLightHover", - }), - [STATES.ACTIVE]: resolveColor({ - selected: dateTag ? "paletteInkLightHover" : "paletteBlueNormalActive", - removable: "paletteBlueLightActive", - normal: "paletteBlueLightActive", - }), - }, - [TYPES.NEUTRAL]: { - [STATES.DEFAULT]: resolveColor({ - selected: dateTag ? "paletteInkLightHover" : "paletteBlueNormal", - removable: "paletteCloudNormal", - normal: "paletteCloudNormal", - }), - [STATES.HOVER]: resolveColor({ - selected: dateTag ? "paletteInkLightActive" : "paletteBlueNormalHover", - removable: "paletteCloudNormalHover", - normal: "paletteCloudNormalHover", - }), - [STATES.ACTIVE]: resolveColor({ - selected: dateTag ? "paletteInkLightHover" : "paletteBlueNormalActive", - removable: "paletteCloudNormalActive", - normal: "paletteCloudNormalActive", - }), - }, - }; - return states[type][state]; - }; - -const getLineHeight = ({ theme, size }: { theme: Theme; size: Props["size"] }): string | null => { - const tokens = { - [SIZES.SMALL]: theme.orbit.lineHeightTextSmall, - [SIZES.NORMAL]: theme.orbit.lineHeightTextNormal, - }; - - if (!size) return null; - - return tokens[size]; -}; - -const CloseContainer = styled.div<{ - actionable?: boolean; - type: Type; - selected?: boolean; - removable?: boolean; -}>` - ${({ theme, actionable, type, selected }) => css` - display: flex; - margin-${left}: ${theme.orbit.spaceXSmall}; - opacity: ${selected ? "1" : "0.5"}; - color: ${resolveColor({ - selected: "paletteWhite", - removable: type === TYPES.NEUTRAL ? "paletteInkNormal" : "paletteBlueDarker", - normal: "paletteInkLink", - })}; - cursor: ${actionable && `pointer`}; - transition: all ${theme.orbit.durationFast} ease-in-out; - - &:active { - color: ${resolveCircleColor}; - } - `}; -`; - -CloseContainer.defaultProps = { - theme: defaultTheme, -}; - -export const StyledTag = styled.div<{ - selected?: boolean; - actionable?: boolean; - type: Type; - size: Props["size"]; - dateTag?: boolean; - removable?: boolean; -}>` - ${({ theme, actionable, type }) => css` - font-family: ${theme.orbit.fontFamily}; - color: ${resolveColor({ - selected: "paletteWhite", - removable: type === TYPES.NEUTRAL ? "paletteInkDark" : "paletteBlueDarker", - normal: type === TYPES.NEUTRAL ? "paletteInkDark" : "paletteBlueDarker", - })}; - background: ${getBackgroundColor(STATES.DEFAULT)}; - display: inline-flex; - box-sizing: border-box; - justify-content: center; - align-items: center; - line-height: ${getLineHeight}; - font-size: ${getFontSize}; - font-weight: ${theme.orbit.fontWeightMedium}; - border-radius: ${theme.orbit.borderRadiusLarge}; - padding: ${theme.orbit.spaceXSmall}; - transition: color ${theme.orbit.durationFast} ease-in-out, - box-shadow ${theme.orbit.durationFast} ease-in-out, - background ${theme.orbit.durationFast} ease-in-out; - - ${mq.tablet(css` - border-radius: ${theme.orbit.borderRadiusNormal}; - `)} - - ${actionable && - css` - cursor: pointer; - - &:hover, - &:focus-visible { - background: ${getBackgroundColor(STATES.HOVER)}; - box-shadow: none; - } - - &:focus { - background: ${getBackgroundColor(STATES.HOVER)}; - } - - &:active { - ${CloseContainer} { - opacity: 1; - } - background: ${getBackgroundColor(STATES.ACTIVE)}; - } - - &:focus:not(:focus-visible):not(:active) { - background: ${getBackgroundColor(STATES.HOVER)}; - } - `}; - `} -`; - -StyledTag.defaultProps = { - theme: defaultTheme, -}; - -const StyledClose = styled.div` - display: flex; - border-radius: 100%; - - &:focus { - ${CloseContainer} { - opacity: 1; - } +import { SIZES, TYPES } from "./consts"; +import type { Props } from "./types"; + +const buttonClickEmulation = ( + ev?: React.KeyboardEvent, + callback?: Common.Callback, +) => { + if (ev && ev.code === "Space") { + ev.preventDefault(); + if (callback) callback(); + } else if (ev && ev.code === "Enter") { + if (callback) callback(); } -`; - -StyledClose.defaultProps = { - theme: defaultTheme, }; -const StyledIconContainer = styled.div` - ${({ theme }) => css` - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - padding-right: ${theme.orbit.spaceXSmall}; - - svg { - width: ${theme.orbit.widthIconSmall}; - height: ${theme.orbit.heightIconSmall}; - } - `} -`; - -StyledIconContainer.defaultProps = { - theme: defaultTheme, -}; - -const buttonClickEmulation = - (callback?: Common.Callback) => (ev?: React.KeyboardEvent) => { - if (ev && ev.keyCode === KEY_CODE_MAP.SPACE) { - ev.preventDefault(); - if (callback) callback(); - } else if (ev && ev.keyCode === KEY_CODE_MAP.ENTER) { - if (callback) callback(); - } - }; - const Tag = React.forwardRef( ( { @@ -233,48 +37,92 @@ const Tag = React.forwardRef( ref, ) => { return ( - buttonClickEmulation(ev, onClick)} > - {iconLeft && {iconLeft}} + {iconLeft && ( +
+ {iconLeft} +
+ )} {children} {onRemove && ( - { + ev.stopPropagation(); + buttonClickEmulation(ev, onRemove); + }} onClick={ev => { ev.stopPropagation(); - if (onRemove) onRemove(); + onRemove(); }} > - { - ev.stopPropagation(); - buttonClickEmulation(onRemove); - }} - > - - - + + )} -
+ ); }, );