fix: resolve <Badge /> incorrect sizes (#22539)

This pull-request makes a few changes to our `<Badge />` component to
bring it inline with Figma.

* Added all variants to the stories of Figma (they can vary per
badge-type, so its better we track everything).
* Removed the `border` variant of the component, border variants should
be on all `sm` and `md`.
* Added a hover effect to the `default` variant (per-design).
* Resolved issue with sizings of `xs` and `sm` plus resolved
iconography.
* Resolved issue with icons not showing at all on `xs` variants.
This commit is contained in:
Jake Howell
2026-04-09 19:55:59 +10:00
committed by GitHub
parent 3d139c1a24
commit 2e6fdf2344
7 changed files with 151 additions and 91 deletions
+122 -28
View File
@@ -1,56 +1,150 @@
import type { Meta, StoryObj } from "@storybook/react-vite";
import { Settings, TriangleAlert } from "lucide-react";
import { Database, Settings, TriangleAlert } from "lucide-react";
import { Badges } from "#/components/Badges/Badges";
import { Badge } from "./Badge";
const meta: Meta<typeof Badge> = {
title: "components/Badge",
component: Badge,
args: {
children: "Badge",
},
};
export default meta;
type Story = StoryObj<typeof Badge>;
export const Default: Story = {};
export const Default: Story = {
render: () => (
<Badges>
<Badge size="xs">
<Database />
Text
</Badge>
<Badge size="sm">
<Database />
Text
</Badge>
<Badge size="md">
<Database />
Text
</Badge>
</Badges>
),
};
export const Warning: Story = {
args: {
variant: "warning",
},
render: () => (
<Badges>
<Badge variant="warning" size="xs">
Warning
<TriangleAlert />
</Badge>
<Badge variant="warning" size="sm">
<TriangleAlert />
Warning
</Badge>
<Badge variant="warning" size="md">
<TriangleAlert />
Warning
</Badge>
</Badges>
),
};
export const Destructive: Story = {
args: {
variant: "destructive",
},
render: () => (
<Badges>
<Badge variant="destructive" size="xs">
Destructive
<TriangleAlert />
</Badge>
<Badge variant="destructive" size="sm">
<TriangleAlert />
Destructive
</Badge>
<Badge variant="destructive" size="md">
<TriangleAlert />
Destructive
</Badge>
</Badges>
),
};
export const Info: Story = {
args: {
variant: "info",
},
render: () => (
<Badges>
<Badge variant="info" size="xs">
Info
</Badge>
<Badge variant="info" size="sm">
Info
</Badge>
<Badge variant="info" size="md">
Info
</Badge>
</Badges>
),
};
export const Green: Story = {
args: {
variant: "green",
},
render: () => (
<Badges>
<Badge variant="green" size="xs">
Green
</Badge>
<Badge variant="green" size="sm">
Green
</Badge>
<Badge variant="green" size="md">
Green
</Badge>
</Badges>
),
};
export const Purple: Story = {
render: () => (
<Badges>
<Badge variant="purple" size="xs">
Purple
</Badge>
<Badge variant="purple" size="sm">
Purple
</Badge>
<Badge variant="purple" size="md">
Purple
</Badge>
</Badges>
),
};
export const Magenta: Story = {
render: () => (
<Badges>
<Badge variant="magenta" size="xs">
Magenta
</Badge>
<Badge variant="magenta" size="sm">
Magenta
</Badge>
<Badge variant="magenta" size="md">
Magenta
</Badge>
</Badges>
),
};
export const SmallWithIcon: Story = {
args: {
variant: "default",
size: "sm",
children: <>{<Settings />} Preset</>,
},
render: () => (
<Badge variant="default" size="sm">
<Settings />
Preset
</Badge>
),
};
export const MediumWithIcon: Story = {
args: {
variant: "warning",
size: "md",
children: <>{<TriangleAlert />} Immutable</>,
},
render: () => (
<Badge variant="warning" size="md">
<TriangleAlert />
Immutable
</Badge>
),
};
+15 -21
View File
@@ -1,5 +1,5 @@
/**
* Copied from shadc/ui on 11/13/2024
* Copied from shadcn/ui on 11/13/2024
* @see {@link https://ui.shadcn.com/docs/components/badge}
*/
import { cva, type VariantProps } from "class-variance-authority";
@@ -8,35 +8,31 @@ import { cn } from "#/utils/cn";
const badgeVariants = cva(
`
inline-flex items-center rounded-md border px-2 py-1 text-nowrap
transition-colors
[&_svg]:pointer-events-none [&_svg]:pr-0.5 [&_svg]:py-0.5 [&_svg]:mr-0.5
inline-flex items-center gap-1 rounded-md border px-1.5 py-0.5 text-nowrap
transition-colors [&_svg]:py-0.5 border-solid
[&_svg]:pointer-events-none
`,
{
variants: {
variant: {
default:
"border-transparent bg-surface-secondary text-content-secondary shadow",
"border-surface-secondary bg-surface-secondary text-content-secondary shadow",
warning:
"border border-solid border-border-warning bg-surface-orange text-content-warning shadow",
"border-border-warning bg-surface-orange text-content-warning shadow",
destructive:
"border border-solid border-border-destructive bg-surface-red text-highlight-red shadow",
"border-border-destructive bg-surface-red text-highlight-red shadow",
green:
"border border-solid border-border-green bg-surface-green text-highlight-green shadow",
"border-border-green bg-surface-green text-highlight-green shadow",
purple:
"border border-solid border-border-purple bg-surface-purple text-highlight-purple shadow",
"border-border-purple bg-surface-purple text-highlight-purple shadow",
magenta:
"border border-solid border-border-magenta bg-surface-magenta text-highlight-magenta shadow",
info: "border border-solid border-border-pending bg-surface-sky text-highlight-sky shadow",
"border-border-magenta bg-surface-magenta text-highlight-magenta shadow",
info: "border-border-pending bg-surface-sky text-highlight-sky shadow",
},
size: {
xs: "text-2xs font-regular h-5 [&_svg]:hidden rounded px-1.5",
sm: "text-2xs font-regular h-5.5 [&_svg]:size-icon-xs",
md: "text-xs font-medium [&_svg]:size-icon-sm",
},
border: {
none: "border-transparent",
solid: "border border-solid",
xs: "border-0 text-2xs font-normal h-[18px] [&_svg]:size-icon-xs rounded",
sm: "text-2xs font-normal h-5.5 py-1 [&_svg]:size-icon-xs",
md: "text-xs font-normal py-1 [&_svg]:size-icon-xs",
},
hover: {
false: null,
@@ -58,7 +54,6 @@ const badgeVariants = cva(
defaultVariants: {
variant: "default",
size: "md",
border: "none",
hover: false,
},
},
@@ -73,7 +68,6 @@ export const Badge: React.FC<BadgeProps> = ({
className,
variant,
size,
border,
hover,
asChild = false,
...props
@@ -83,7 +77,7 @@ export const Badge: React.FC<BadgeProps> = ({
return (
<Comp
{...props}
className={cn(badgeVariants({ variant, size, border, hover }), className)}
className={cn(badgeVariants({ variant, size, hover }), className)}
/>
);
};
+7 -31
View File
@@ -3,18 +3,14 @@ import { Stack } from "#/components/Stack/Stack";
export const EnabledBadge: React.FC = () => {
return (
<Badge className="option-enabled" variant="green" border="solid">
<Badge className="option-enabled" variant="green">
Enabled
</Badge>
);
};
export const EntitledBadge: React.FC = () => {
return (
<Badge border="solid" variant="green">
Entitled
</Badge>
);
return <Badge variant="green">Entitled</Badge>;
};
export const DisabledBadge: React.FC<React.ComponentPropsWithRef<"div">> = ({
@@ -28,11 +24,7 @@ export const DisabledBadge: React.FC<React.ComponentPropsWithRef<"div">> = ({
};
export const EnterpriseBadge: React.FC = () => {
return (
<Badge variant="purple" border="solid">
Enterprise
</Badge>
);
return <Badge variant="purple">Enterprise</Badge>;
};
interface PremiumBadgeProps {
@@ -42,35 +34,19 @@ interface PremiumBadgeProps {
export const PremiumBadge: React.FC<PremiumBadgeProps> = ({
children = "Premium",
}) => {
return (
<Badge variant="magenta" border="solid">
{children}
</Badge>
);
return <Badge variant="magenta">{children}</Badge>;
};
export const PreviewBadge: React.FC = () => {
return (
<Badge variant="purple" border="solid">
Preview
</Badge>
);
return <Badge variant="purple">Preview</Badge>;
};
export const AlphaBadge: React.FC = () => {
return (
<Badge variant="purple" border="solid">
Alpha
</Badge>
);
return <Badge variant="purple">Alpha</Badge>;
};
export const DeprecatedBadge: React.FC = () => {
return (
<Badge variant="warning" border="solid">
Deprecated
</Badge>
);
return <Badge variant="warning">Deprecated</Badge>;
};
export const Badges: React.FC<React.PropsWithChildren> = ({ children }) => {
@@ -141,7 +141,7 @@ const ParameterLabel: FC<ParameterLabelProps> = ({
<Tooltip>
<TooltipTrigger asChild>
<span className="flex items-center">
<Badge size="sm" variant="warning" border="none">
<Badge size="sm" variant="warning">
<TriangleAlert />
Immutable
</Badge>
@@ -159,7 +159,7 @@ const ParameterLabel: FC<ParameterLabelProps> = ({
<Tooltip>
<TooltipTrigger asChild>
<span className="flex items-center">
<Badge size="sm" variant="green" border="none">
<Badge size="sm" variant="green">
<Hourglass />
Ephemeral
</Badge>
@@ -211,7 +211,7 @@ const ParameterLabel: FC<ParameterLabelProps> = ({
<Tooltip>
<TooltipTrigger asChild>
<span className="flex items-center">
<Badge size="sm" variant="destructive" border="none">
<Badge size="sm" variant="destructive">
Required
</Badge>
</span>
@@ -38,11 +38,7 @@ export const ExternalAuthButton: FC<ExternalAuthButtonProps> = ({
)}
<p className="font-semibold text-sm m-0">{auth.display_name}</p>
{!auth.authenticated && !auth.optional && (
<Badge
size="sm"
border="none"
variant={error ? "destructive" : "warning"}
>
<Badge size="sm" variant={error ? "destructive" : "warning"}>
Required
</Badge>
)}
@@ -52,7 +52,7 @@ export const AIGovernanceAddOnCard: FC<AIGovernanceAddOnCardProps> = ({
</TooltipContent>
</Tooltip>
</div>
<Badge variant="magenta" size="sm" border="solid">
<Badge variant="magenta" size="sm">
AI add-on
</Badge>
</div>
@@ -116,12 +116,12 @@ const ReviewPanel: FC<ReviewPanelProps> = ({
<span className="flex flex-row items-center gap-2">
<span className="leading-tight">{workspaceName}</span>
{running && (
<Badge size="xs" variant="warning" border="none">
<Badge size="xs" variant="warning">
Running
</Badge>
)}
{transitioning && (
<Badge size="xs" variant="warning" border="none">
<Badge size="xs" variant="warning">
Getting latest status
</Badge>
)}