Skip to content

Commit 0cccfda

Browse files
authored
Merge pull request #13999 from ethereum/shadcn-tag-button
Shadcn migration - tag button
2 parents fcb7e0b + cf0d3a8 commit 0cccfda

File tree

2 files changed

+96
-42
lines changed

2 files changed

+96
-42
lines changed
Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Meta, StoryObj } from "@storybook/react"
22

33
import { HStack, VStack } from "../flex"
4-
import { Tag } from "../tag"
4+
import { Tag, TagButton } from "../tag"
55

66
const meta = {
77
title: "Molecules / Display Content / New Tags",
@@ -16,22 +16,36 @@ type Story = StoryObj<typeof meta>
1616
const statusArray = ["normal", "tag", "success", "error", "warning"] as const
1717

1818
// "subtle" is default variant
19-
const variantArray = ["subtle", "highContrast", "solid", "outline"] as const
20-
21-
const StyleVariantList = () => (
22-
<HStack>
23-
{statusArray.map((status) => (
24-
<VStack key={status}>
25-
{variantArray.map((variant) => (
26-
<Tag key={variant} status={status} variant={variant}>
27-
Tag Name
28-
</Tag>
29-
))}
30-
</VStack>
31-
))}
32-
</HStack>
33-
)
19+
const variantArray = ["subtle", "high-contrast", "solid", "outline"] as const
3420

3521
export const StyleVariantsBasic: Story = {
36-
render: (args) => <StyleVariantList {...args} />,
22+
render: () => (
23+
<HStack>
24+
{statusArray.map((status) => (
25+
<VStack key={status}>
26+
{variantArray.map((variant) => (
27+
<Tag key={variant} status={status} variant={variant}>
28+
Tag Name
29+
</Tag>
30+
))}
31+
</VStack>
32+
))}
33+
</HStack>
34+
),
35+
}
36+
37+
export const StyleVariantsButton: Story = {
38+
render: () => (
39+
<HStack>
40+
{statusArray.map((status) => (
41+
<VStack key={status}>
42+
{variantArray.map((variant) => (
43+
<TagButton key={variant} status={status} variant={variant}>
44+
Tag Name
45+
</TagButton>
46+
))}
47+
</VStack>
48+
))}
49+
</HStack>
50+
),
3751
}

src/components/ui/tag.tsx

Lines changed: 65 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,27 @@
1+
import { forwardRef } from "react"
12
import { cva, VariantProps } from "class-variance-authority"
23
import { Slot } from "@radix-ui/react-slot"
34

45
import { cn } from "@/lib/utils/cn"
56

67
const tagVariants = cva(
7-
"inline-flex items-center rounded-full border px-2 py-0.5 min-h-8 text-xs uppercase transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
8+
"inline-flex items-center rounded-full border px-2 py-0.5 min-h-8 text-xs uppercase transition-colors",
89
{
910
variants: {
1011
status: {
11-
normal: "bg-background-highlight text-body-medium border-body-medium",
12-
tag: "bg-primary-low-contrast text-primary-high-contrast border-primary",
13-
success: "bg-success-light text-success border-success-border",
14-
error: "bg-error-light text-error border-error-border",
15-
warning: "bg-warning-light text-warning-dark border-warning-border",
12+
normal:
13+
"bg-background-highlight text-body-medium border-body-medium hover:shadow-body-medium",
14+
tag: "bg-primary-low-contrast text-primary-high-contrast border-primary hover:shadow-primary-high-contrast",
15+
success:
16+
"bg-success-light text-success border-success-border hover:shadow-success",
17+
error:
18+
"bg-error-light text-error border-error-border hover:shadow-error",
19+
warning:
20+
"bg-warning-light text-warning-dark border-warning-border hover:shadow-warning-dark dark:hover:shadow-warning",
1621
},
1722
variant: {
1823
subtle: "border-transparent",
19-
highContrast: "border-transparent",
24+
"high-contrast": "border-transparent",
2025
solid: "border-transparent text-body-inverse",
2126
outline: "bg-transparent",
2227
},
@@ -25,45 +30,50 @@ const tagVariants = cva(
2530
{
2631
variant: "solid",
2732
status: "normal",
28-
className: "bg-body-medium",
33+
className:
34+
"bg-body-medium focus-visible:outline-body hover:shadow-body",
2935
},
3036
{
3137
variant: "solid",
3238
status: "tag",
33-
className: "bg-primary",
39+
className:
40+
"bg-primary focus-visible:outline-primary-high-contrast hover:shadow-primary-high-contrast",
3441
},
3542
{
3643
variant: "solid",
3744
status: "success",
38-
className: "bg-success text-success-light",
45+
className:
46+
"bg-success text-success-light focus-visible:outline-success-dark hover:shadow-success-dark dark:hover:shadow-success-light",
3947
},
4048
{
4149
variant: "solid",
4250
status: "error",
43-
className: "bg-error text-error-light",
51+
className:
52+
"bg-error text-error-light focus-visible:outline-error-dark hover:shadow-error-dark dark:hover:shadow-error-light",
4453
},
4554
{
4655
variant: "solid",
4756
status: "warning",
48-
className: "bg-warning text-warning-dark",
57+
className:
58+
"bg-warning text-warning-dark focus-visible:outline-warning-border hover:shadow-warning-dark dark:hover:shadow-warning-light",
4959
},
5060
{
51-
variant: "highContrast",
61+
variant: "high-contrast",
5262
status: "normal",
5363
className: "bg-body-light text-body",
5464
},
5565
{
56-
variant: "highContrast",
66+
variant: "high-contrast",
5767
status: "tag",
5868
className: "bg-background-highlight",
5969
},
6070
{
61-
variant: "highContrast",
71+
variant: "high-contrast",
6272
status: "success",
6373
className: "text-success-dark",
6474
},
6575
{
66-
variant: "highContrast",
76+
variant: "high-contrast",
6777
status: "error",
6878
className: "text-error-dark",
6979
},
@@ -96,14 +106,44 @@ export interface TagProps
96106
asChild?: boolean
97107
}
98108

99-
function Tag({ className, asChild, variant, status, ...props }: TagProps) {
100-
const Comp = asChild ? Slot : "div"
101-
return (
102-
<Comp
103-
className={cn(tagVariants({ variant, status }), className)}
104-
{...props}
105-
/>
106-
)
109+
const Tag = forwardRef<HTMLDivElement, TagProps>(
110+
({ className, asChild, variant, status, ...props }, ref) => {
111+
const Comp = asChild ? Slot : "div"
112+
return (
113+
<Comp
114+
ref={ref}
115+
className={cn(tagVariants({ variant, status }), className)}
116+
{...props}
117+
/>
118+
)
119+
}
120+
)
121+
122+
Tag.displayName = "Tag"
123+
124+
export interface TagButtonProps
125+
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
126+
VariantProps<typeof tagVariants> {
127+
asChild?: boolean
107128
}
108129

109-
export { Tag }
130+
const TagButton = forwardRef<HTMLButtonElement, TagButtonProps>(
131+
({ className, asChild, variant, status, ...props }, ref) => {
132+
const Comp = asChild ? Slot : "button"
133+
return (
134+
<Comp
135+
ref={ref}
136+
className={cn(
137+
"hover:shadow-[2px_2px] focus-visible:outline focus-visible:outline-4 focus-visible:-outline-offset-1 focus-visible:outline-inherit",
138+
tagVariants({ variant, status }),
139+
className
140+
)}
141+
{...props}
142+
/>
143+
)
144+
}
145+
)
146+
147+
TagButton.displayName = "TagButton"
148+
149+
export { Tag, TagButton }

0 commit comments

Comments
 (0)