Skip to content

Commit c93a502

Browse files
authored
ENG-6173: Add badge component (#4)
1 parent ac65755 commit c93a502

File tree

3 files changed

+165
-2
lines changed

3 files changed

+165
-2
lines changed

demo/assets/css/globals.css

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,31 @@
5151
--secondary-a10: var(--slate-a10);
5252
--secondary-a11: var(--slate-a11);
5353
--secondary-a12: var(--slate-a12);
54+
/* Info */
55+
--info-1: var(--blue-1);
56+
--info-2: var(--blue-2);
57+
--info-3: var(--blue-3);
58+
--info-4: var(--blue-4);
59+
--info-5: var(--blue-5);
60+
--info-6: var(--blue-6);
61+
--info-7: var(--blue-7);
62+
--info-8: var(--blue-8);
63+
--info-9: var(--blue-9);
64+
--info-10: var(--blue-10);
65+
--info-11: var(--blue-11);
66+
--info-12: var(--blue-12);
67+
--info-a1: var(--blue-a1);
68+
--info-a2: var(--blue-a2);
69+
--info-a3: var(--blue-a3);
70+
--info-a4: var(--blue-a4);
71+
--info-a5: var(--blue-a5);
72+
--info-a6: var(--blue-a6);
73+
--info-a7: var(--blue-a7);
74+
--info-a8: var(--blue-a8);
75+
--info-a9: var(--blue-a9);
76+
--info-a10: var(--blue-a10);
77+
--info-a11: var(--blue-a11);
78+
--info-a12: var(--blue-a12);
5479
/* Success */
5580
--success-1: var(--jade-1);
5681
--success-2: var(--jade-2);
@@ -184,6 +209,31 @@
184209
--color-secondary-a10: var(--secondary-a10);
185210
--color-secondary-a11: var(--secondary-a11);
186211
--color-secondary-a12: var(--secondary-a12);
212+
/* Info */
213+
--color-info-1: var(--info-1);
214+
--color-info-2: var(--info-2);
215+
--color-info-3: var(--info-3);
216+
--color-info-4: var(--info-4);
217+
--color-info-5: var(--info-5);
218+
--color-info-6: var(--info-6);
219+
--color-info-7: var(--info-7);
220+
--color-info-8: var(--info-8);
221+
--color-info-9: var(--info-9);
222+
--color-info-10: var(--info-10);
223+
--color-info-11: var(--info-11);
224+
--color-info-12: var(--info-12);
225+
--color-info-a1: var(--info-a1);
226+
--color-info-a2: var(--info-a2);
227+
--color-info-a3: var(--info-a3);
228+
--color-info-a4: var(--info-a4);
229+
--color-info-a5: var(--info-a5);
230+
--color-info-a6: var(--info-a6);
231+
--color-info-a7: var(--info-a7);
232+
--color-info-a8: var(--info-a8);
233+
--color-info-a9: var(--info-a9);
234+
--color-info-a10: var(--info-a10);
235+
--color-info-a11: var(--info-a11);
236+
--color-info-a12: var(--info-a12);
187237
/* Success */
188238
--color-success-1: var(--success-1);
189239
--color-success-2: var(--success-2);
@@ -1049,7 +1099,7 @@
10491099
0px -8px 8px 0px light-dark(rgba(28, 32, 36, 0.02), rgba(0, 0, 0, 0)),
10501100
0px -2px 6px 0px light-dark(rgba(28, 32, 36, 0.02), rgba(0, 0, 0, 0));
10511101
/* Radius */
1052-
--radius-xs: calc(var(--radius) - 0rem);
1102+
--radius-xs: calc(var(--radius) - 0.375rem);
10531103
--radius-sm: calc(var(--radius) - 0.25rem);
10541104
--radius-md: calc(var(--radius) - 0.125rem);
10551105
--radius-lg: var(--radius);

reflex_ui/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
from reflex.utils import lazy_loader
44

55
_REFLEX_UI_MAPPING = {
6-
"components.base.button": ["button"],
76
"components.base.avatar": ["avatar"],
7+
"components.base.button": ["button"],
8+
"components.base.badge": ["badge"],
89
"components.base.theme_switcher": ["theme_switcher"],
910
}
1011

reflex_ui/components/base/badge.py

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
"""Badge component."""
2+
3+
from typing import Literal
4+
5+
from reflex.components.el import Span
6+
from reflex.vars import Var
7+
8+
from reflex_ui.components.component import CoreComponent
9+
10+
BaseColorType = Literal[
11+
"primary",
12+
"secondary",
13+
"info",
14+
"success",
15+
"warning",
16+
"destructive",
17+
"gray",
18+
"mauve",
19+
"slate",
20+
"sage",
21+
"olive",
22+
"sand",
23+
"tomato",
24+
"red",
25+
"ruby",
26+
"crimson",
27+
"pink",
28+
"plum",
29+
"purple",
30+
"violet",
31+
"iris",
32+
"indigo",
33+
"blue",
34+
"cyan",
35+
"teal",
36+
"jade",
37+
"green",
38+
"grass",
39+
"brown",
40+
"orange",
41+
"sky",
42+
"mint",
43+
"lime",
44+
"yellow",
45+
"amber",
46+
"gold",
47+
"bronze",
48+
]
49+
LiteralBadgeVariant = Literal["solid", "soft"]
50+
LiteralBadgeSize = Literal["xs", "sm", "md"]
51+
52+
DEFAULT_BASE_CLASSES = "inline-flex items-center font-medium [&_svg]:pointer-events-none [&_svg]:shrink-0 gap-1.5"
53+
54+
# Light colors that need dark text on solid backgrounds for better contrast
55+
LIGHT_COLORS = {"sky", "mint", "lime", "yellow", "amber", "secondary"}
56+
57+
BADGE_VARIANTS = {
58+
"size": {
59+
"xs": "px-1.5 py-0.5 h-4 rounded-xs text-[11px] [&_svg]:size-3",
60+
"sm": "px-1.5 py-0.5 h-5 rounded-sm text-xs [&_svg]:size-3.5",
61+
"md": "px-2 py-0.5 h-6 rounded-md text-sm [&_svg]:size-4",
62+
}
63+
}
64+
65+
66+
def get_color_classes(color: str, variant: LiteralBadgeVariant) -> str:
67+
"""Get the color-specific classes based on color and variant."""
68+
if variant == "solid":
69+
text_color = "text-black/90" if color in LIGHT_COLORS else "text-white"
70+
return f"border-transparent bg-{color}-9 {text_color}"
71+
# Soft variant
72+
return f"border-transparent bg-{color}-3 text-{color}-11"
73+
74+
75+
def get_badge_classes(
76+
color: str, variant: LiteralBadgeVariant, size: LiteralBadgeSize
77+
) -> str:
78+
"""Get the complete badge class string."""
79+
color_classes = get_color_classes(color, variant)
80+
size_classes = BADGE_VARIANTS["size"][size]
81+
82+
return f"{DEFAULT_BASE_CLASSES} {size_classes} {color_classes}"
83+
84+
85+
class Badge(Span, CoreComponent):
86+
"""A badge component that displays a label."""
87+
88+
# Badge color
89+
color: BaseColorType | Var[str]
90+
91+
# Badge variant
92+
variant: Var[LiteralBadgeVariant]
93+
94+
# Badge size
95+
size: Var[LiteralBadgeSize]
96+
97+
@classmethod
98+
def create(cls, *children, **props) -> Span:
99+
"""Create the badge component."""
100+
variant = props.pop("variant", "solid")
101+
color = props.pop("color", "primary")
102+
size = props.pop("size", "sm")
103+
104+
cls.set_class_name(get_badge_classes(color, variant, size), props)
105+
106+
return super().create(*children, **props)
107+
108+
def _exclude_props(self) -> list[str]:
109+
return [*super()._exclude_props(), "color", "variant", "size"]
110+
111+
112+
badge = Badge.create

0 commit comments

Comments
 (0)