From 62380492863de6c8ea6a698656ddb326ddc88ba4 Mon Sep 17 00:00:00 2001 From: Sanjar Mirakhmedov Date: Mon, 29 Sep 2025 15:25:30 +0500 Subject: [PATCH 1/5] feat(tag): [STMS-4933] fix typography --- packages/ui/src/Typography/typographyOptions.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/ui/src/Typography/typographyOptions.tsx b/packages/ui/src/Typography/typographyOptions.tsx index 6a56f0b8..e50e7e3c 100644 --- a/packages/ui/src/Typography/typographyOptions.tsx +++ b/packages/ui/src/Typography/typographyOptions.tsx @@ -4,7 +4,7 @@ import type { } from "@mui/material/styles"; export function createTypographyOptions( - breakpoints: Breakpoints, + breakpoints: Breakpoints ): TypographyVariantsOptions { const xsOnly = breakpoints.only("xs"); @@ -80,8 +80,8 @@ export function createTypographyOptions( body: { fontSize: "14px", - lineHeight: "20px", - fontWeight: 600, + lineHeight: "22px", + fontWeight: 400, [xsOnly]: { fontSize: "16px", lineHeight: "26px", @@ -90,8 +90,8 @@ export function createTypographyOptions( "body-semibold": { fontSize: "14px", - lineHeight: "20px", - fontWeight: 400, + lineHeight: "22px", + fontWeight: 600, [xsOnly]: { fontSize: "16px", lineHeight: "26px", From 19c08c25e323d039134403612393cae5e5077cad Mon Sep 17 00:00:00 2001 From: Sanjar Mirakhmedov Date: Mon, 29 Sep 2025 16:11:54 +0500 Subject: [PATCH 2/5] feat(tag): [STMS-4933] implement tag component --- packages/ui/src/Tag/Tag.stories.tsx | 100 ++++++++++++++++++++ packages/ui/src/Tag/Tag.tsx | 138 ++++++++++++++++++++++++++++ packages/ui/src/Tag/constants.ts | 11 +++ packages/ui/src/Tag/index.ts | 1 + packages/ui/src/internal/icons.tsx | 18 ++++ 5 files changed, 268 insertions(+) create mode 100644 packages/ui/src/Tag/Tag.stories.tsx create mode 100644 packages/ui/src/Tag/Tag.tsx create mode 100644 packages/ui/src/Tag/constants.ts create mode 100644 packages/ui/src/Tag/index.ts create mode 100644 packages/ui/src/internal/icons.tsx diff --git a/packages/ui/src/Tag/Tag.stories.tsx b/packages/ui/src/Tag/Tag.stories.tsx new file mode 100644 index 00000000..436a1de8 --- /dev/null +++ b/packages/ui/src/Tag/Tag.stories.tsx @@ -0,0 +1,100 @@ +import { Box } from "@mui/material"; +import { Tag, type TagProps } from "./Tag"; +import { TAG_COLORS, TAG_VARIANTS } from "./constants"; +import type { StoryFn, Meta } from "@storybook/react-vite"; +import { CheckmarkIcon } from "../internal/icons"; + +type Args = Omit & { + startIcon?: boolean; + endIcon?: boolean; +}; + +const meta: Meta = { + title: "Components/Tag", + component: Tag, + argTypes: { + color: { + control: { + type: "select", + }, + options: TAG_COLORS, + }, + variant: { + control: { + type: "select", + }, + options: TAG_VARIANTS, + }, + isBold: { + control: { + type: "boolean", + }, + }, + startIcon: { + control: { + type: "boolean", + }, + }, + endIcon: { + control: { + type: "boolean", + }, + }, + }, + tags: ["autodocs"], +}; + +export default meta; + +function TagRenderer(args: Args) { + return ( + : undefined} + endIcon={args.endIcon ? : undefined} + /> + ); +} + +const Template: StoryFn = (args) => ; + +export const Default = Template.bind({}); + +Default.args = { + label: "Text", + startIcon: false, + endIcon: false, +}; + +const AllVariantsAndColorsTemplate: StoryFn> = ( + args +) => ( + <> + {TAG_VARIANTS.map((variant) => ( + + {TAG_COLORS.map((color) => ( + + + + ))} + + ))} + +); + +export const AllVariantsAndColors = AllVariantsAndColorsTemplate.bind({}); + +AllVariantsAndColors.args = { + label: "Text", + startIcon: false, + endIcon: false, +}; + +AllVariantsAndColors.parameters = { + controls: { + exclude: ["variant", "color"], + }, +}; diff --git a/packages/ui/src/Tag/Tag.tsx b/packages/ui/src/Tag/Tag.tsx new file mode 100644 index 00000000..0281dd0e --- /dev/null +++ b/packages/ui/src/Tag/Tag.tsx @@ -0,0 +1,138 @@ +import { Box } from "@mui/material"; +import { ColorDynamic } from "../color"; +import { Typography } from "../Typography"; +import type { TAG_COLORS, TAG_VARIANTS } from "./constants"; + +export type TagColor = (typeof TAG_COLORS)[number]; +export type TagVariant = (typeof TAG_VARIANTS)[number]; + +export interface TagProps { + label: string; + color?: TagColor; + variant?: TagVariant; + isBold?: boolean; + startIcon?: React.ReactNode; + endIcon?: React.ReactNode; +} + +const variantToColorMap: Record< + TagVariant, + Record< + TagColor, + { + color: string; + backgroundColor: string; + } + > +> = { + filled: { + blue: { + color: ColorDynamic.White, + backgroundColor: ColorDynamic.Blue300, + }, + teal: { + color: ColorDynamic.White, + backgroundColor: ColorDynamic.Teal300, + }, + gray: { + color: ColorDynamic.White, + backgroundColor: ColorDynamic.Dark300, + }, + green: { + color: ColorDynamic.White, + backgroundColor: ColorDynamic.Green300, + }, + purple: { + color: ColorDynamic.White, + backgroundColor: ColorDynamic.Purple300, + }, + red: { + color: ColorDynamic.White, + backgroundColor: ColorDynamic.Red300, + }, + yellow: { + color: ColorDynamic.White, + backgroundColor: ColorDynamic.Yellow300, + }, + }, + subtle: { + blue: { + color: ColorDynamic.Blue500, + backgroundColor: ColorDynamic.Blue50, + }, + teal: { + color: ColorDynamic.Teal500, + backgroundColor: ColorDynamic.Teal50, + }, + gray: { + color: ColorDynamic.Dark300, + backgroundColor: ColorDynamic.Silver200, + }, + green: { + color: ColorDynamic.Green500, + backgroundColor: ColorDynamic.Green50, + }, + purple: { + color: ColorDynamic.Purple500, + backgroundColor: ColorDynamic.Purple50, + }, + red: { + color: ColorDynamic.Red500, + backgroundColor: ColorDynamic.Red50, + }, + yellow: { + color: ColorDynamic.Yellow500, + backgroundColor: ColorDynamic.Yellow50, + }, + }, +}; + +export function Tag({ + label, + variant = "filled", + color = "blue", + isBold = true, + startIcon, + endIcon, +}: TagProps) { + const colorMap = variantToColorMap[variant][color]; + + return ( + ({ + color: colorMap.color, + backgroundColor: colorMap.backgroundColor, + borderRadius: "4px", + height: "22px", + paddingLeft: theme.spacing(0.5), + paddingRight: theme.spacing(0.5), + display: "inline-flex", + alignItems: "center", + gap: theme.spacing(0.5), + + [theme.breakpoints.only("xs")]: { + height: "26px", + }, + })} + > + {startIcon && {startIcon}} + + + {label} + + + {endIcon && {endIcon}} + + ); +} + +function TagIcon({ children }: { children: React.ReactNode }) { + return ( + :nth-of-type(1)": { fontSize: "16px" } }} + > + {children} + + ); +} diff --git a/packages/ui/src/Tag/constants.ts b/packages/ui/src/Tag/constants.ts new file mode 100644 index 00000000..b92515d2 --- /dev/null +++ b/packages/ui/src/Tag/constants.ts @@ -0,0 +1,11 @@ +export const TAG_COLORS = [ + "blue", + "gray", + "green", + "purple", + "red", + "teal", + "yellow", +] as const; + +export const TAG_VARIANTS = ["filled", "subtle"] as const; diff --git a/packages/ui/src/Tag/index.ts b/packages/ui/src/Tag/index.ts new file mode 100644 index 00000000..c5a66e12 --- /dev/null +++ b/packages/ui/src/Tag/index.ts @@ -0,0 +1 @@ +export { Tag, type TagProps, type TagColor, type TagVariant } from "./Tag"; diff --git a/packages/ui/src/internal/icons.tsx b/packages/ui/src/internal/icons.tsx new file mode 100644 index 00000000..b436fd58 --- /dev/null +++ b/packages/ui/src/internal/icons.tsx @@ -0,0 +1,18 @@ +import { SvgIcon, type SvgIconProps } from "@mui/material"; + +export const CheckmarkIcon = (props: SvgIconProps) => { + return ( + + + + + ); +}; From 680143257ed8122fde538ce8cf3a1befc67d6e42 Mon Sep 17 00:00:00 2001 From: Sanjar Mirakhmedov Date: Mon, 29 Sep 2025 16:15:06 +0500 Subject: [PATCH 3/5] feat(tag): [STMS-4933] remove explicit arg type for isBold --- packages/ui/src/Tag/Tag.stories.tsx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/ui/src/Tag/Tag.stories.tsx b/packages/ui/src/Tag/Tag.stories.tsx index 436a1de8..4272ca21 100644 --- a/packages/ui/src/Tag/Tag.stories.tsx +++ b/packages/ui/src/Tag/Tag.stories.tsx @@ -25,11 +25,6 @@ const meta: Meta = { }, options: TAG_VARIANTS, }, - isBold: { - control: { - type: "boolean", - }, - }, startIcon: { control: { type: "boolean", From d1ff36fe82310a1ed11edf2e7d93961a1b2f0bbf Mon Sep 17 00:00:00 2001 From: Sanjar Mirakhmedov Date: Tue, 30 Sep 2025 12:07:02 +0500 Subject: [PATCH 4/5] feat(tag): [STMS-4933] use subtle variant as default --- packages/ui/src/Tag/Tag.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui/src/Tag/Tag.tsx b/packages/ui/src/Tag/Tag.tsx index 0281dd0e..ec4c1ab1 100644 --- a/packages/ui/src/Tag/Tag.tsx +++ b/packages/ui/src/Tag/Tag.tsx @@ -89,7 +89,7 @@ const variantToColorMap: Record< export function Tag({ label, - variant = "filled", + variant = "subtle", color = "blue", isBold = true, startIcon, From f90bba92df55aa673225f8dfc07ecef8da3448c3 Mon Sep 17 00:00:00 2001 From: Sanjar Mirakhmedov Date: Tue, 30 Sep 2025 18:51:57 +0500 Subject: [PATCH 5/5] feat(tag): [STMS-4933] add whitespace nowrap & flex no wrap --- packages/ui/src/Tag/Tag.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/ui/src/Tag/Tag.tsx b/packages/ui/src/Tag/Tag.tsx index ec4c1ab1..707658f7 100644 --- a/packages/ui/src/Tag/Tag.tsx +++ b/packages/ui/src/Tag/Tag.tsx @@ -107,6 +107,8 @@ export function Tag({ paddingLeft: theme.spacing(0.5), paddingRight: theme.spacing(0.5), display: "inline-flex", + flexWrap: "nowrap", + whiteSpace: "nowrap", alignItems: "center", gap: theme.spacing(0.5),