import type { FC, MouseEventHandler, ReactNode } from "react";
import { faXmark } from "@fortawesome/pro-duotone-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Dot } from "@/components/foundations/dot-icon";
import { cx } from "@/utils/cx";
import type { BadgeColors, BadgeTypeToColorMap, BadgeTypes, FlagTypes, IconComponentType, Sizes } from "./badge-types";
import { badgeTypes } from "./badge-types";
const CloseX: FC<{ className?: string }> = ({ className }) => ;
export const filledColors: Record = {
gray: {
root: "bg-utility-gray-50 text-utility-gray-700 ring-utility-gray-200",
addon: "text-utility-gray-500",
addonButton: "hover:bg-utility-gray-100 text-utility-gray-400 hover:text-utility-gray-500",
},
brand: {
root: "bg-utility-brand-50 text-utility-brand-700 ring-utility-brand-200",
addon: "text-utility-brand-500",
addonButton: "hover:bg-utility-brand-100 text-utility-brand-400 hover:text-utility-brand-500",
},
error: {
root: "bg-utility-error-50 text-utility-error-700 ring-utility-error-200",
addon: "text-utility-error-500",
addonButton: "hover:bg-utility-error-100 text-utility-error-400 hover:text-utility-error-500",
},
warning: {
root: "bg-utility-warning-50 text-utility-warning-700 ring-utility-warning-200",
addon: "text-utility-warning-500",
addonButton: "hover:bg-utility-warning-100 text-utility-warning-400 hover:text-utility-warning-500",
},
success: {
root: "bg-utility-success-50 text-utility-success-700 ring-utility-success-200",
addon: "text-utility-success-500",
addonButton: "hover:bg-utility-success-100 text-utility-success-400 hover:text-utility-success-500",
},
"gray-blue": {
root: "bg-utility-gray-blue-50 text-utility-gray-blue-700 ring-utility-gray-blue-200",
addon: "text-utility-gray-blue-500",
addonButton: "hover:bg-utility-gray-blue-100 text-utility-gray-blue-400 hover:text-utility-gray-blue-500",
},
"blue-light": {
root: "bg-utility-blue-light-50 text-utility-blue-light-700 ring-utility-blue-light-200",
addon: "text-utility-blue-light-500",
addonButton: "hover:bg-utility-blue-light-100 text-utility-blue-light-400 hover:text-utility-blue-light-500",
},
blue: {
root: "bg-utility-blue-50 text-utility-blue-700 ring-utility-blue-200",
addon: "text-utility-blue-500",
addonButton: "hover:bg-utility-blue-100 text-utility-blue-400 hover:text-utility-blue-500",
},
indigo: {
root: "bg-utility-indigo-50 text-utility-indigo-700 ring-utility-indigo-200",
addon: "text-utility-indigo-500",
addonButton: "hover:bg-utility-indigo-100 text-utility-indigo-400 hover:text-utility-indigo-500",
},
purple: {
root: "bg-utility-purple-50 text-utility-purple-700 ring-utility-purple-200",
addon: "text-utility-purple-500",
addonButton: "hover:bg-utility-purple-100 text-utility-purple-400 hover:text-utility-purple-500",
},
pink: {
root: "bg-utility-pink-50 text-utility-pink-700 ring-utility-pink-200",
addon: "text-utility-pink-500",
addonButton: "hover:bg-utility-pink-100 text-utility-pink-400 hover:text-utility-pink-500",
},
orange: {
root: "bg-utility-orange-50 text-utility-orange-700 ring-utility-orange-200",
addon: "text-utility-orange-500",
addonButton: "hover:bg-utility-orange-100 text-utility-orange-400 hover:text-utility-orange-500",
},
};
const addonOnlyColors = Object.fromEntries(Object.entries(filledColors).map(([key, value]) => [key, { root: "", addon: value.addon }])) as Record<
BadgeColors,
{ root: string; addon: string }
>;
const withPillTypes = {
[badgeTypes.pillColor]: {
common: "size-max flex items-center whitespace-nowrap rounded-full ring-1 ring-inset",
styles: filledColors,
},
[badgeTypes.badgeColor]: {
common: "size-max flex items-center whitespace-nowrap rounded-md ring-1 ring-inset",
styles: filledColors,
},
[badgeTypes.badgeModern]: {
common: "size-max flex items-center whitespace-nowrap rounded-md ring-1 ring-inset shadow-xs",
styles: {
gray: {
root: "bg-primary text-secondary ring-primary",
addon: "text-gray-500",
addonButton: "hover:bg-utility-gray-100 text-utility-gray-400 hover:text-utility-gray-500",
},
},
},
};
const withBadgeTypes = {
[badgeTypes.pillColor]: {
common: "size-max flex items-center whitespace-nowrap rounded-full ring-1 ring-inset",
styles: filledColors,
},
[badgeTypes.badgeColor]: {
common: "size-max flex items-center whitespace-nowrap rounded-md ring-1 ring-inset",
styles: filledColors,
},
[badgeTypes.badgeModern]: {
common: "size-max flex items-center whitespace-nowrap rounded-md ring-1 ring-inset bg-primary text-secondary ring-primary shadow-xs",
styles: addonOnlyColors,
},
};
export type BadgeColor = BadgeTypeToColorMap[T];
interface BadgeProps {
type?: T;
size?: Sizes;
color?: BadgeColor;
children: ReactNode;
className?: string;
}
export const Badge = (props: BadgeProps) => {
const { type = "pill-color", size = "md", color = "gray", children } = props;
const colors = withPillTypes[type];
const pillSizes = {
sm: "py-0.5 px-2 text-xs font-medium",
md: "py-0.5 px-2.5 text-sm font-medium",
lg: "py-1 px-3 text-sm font-medium",
};
const badgeSizes = {
sm: "py-0.5 px-1.5 text-xs font-medium",
md: "py-0.5 px-2 text-sm font-medium",
lg: "py-1 px-2.5 text-sm font-medium rounded-lg",
};
const sizes = {
[badgeTypes.pillColor]: pillSizes,
[badgeTypes.badgeColor]: badgeSizes,
[badgeTypes.badgeModern]: badgeSizes,
};
return {children};
};
interface BadgeWithDotProps {
type?: T;
size?: Sizes;
color?: BadgeTypeToColorMap[T];
className?: string;
children: ReactNode;
}
export const BadgeWithDot = (props: BadgeWithDotProps) => {
const { size = "md", color = "gray", type = "pill-color", className, children } = props;
const colors = withBadgeTypes[type];
const pillSizes = {
sm: "gap-1 py-0.5 pl-1.5 pr-2 text-xs font-medium",
md: "gap-1.5 py-0.5 pl-2 pr-2.5 text-sm font-medium",
lg: "gap-1.5 py-1 pl-2.5 pr-3 text-sm font-medium",
};
const badgeSizes = {
sm: "gap-1 py-0.5 px-1.5 text-xs font-medium",
md: "gap-1.5 py-0.5 px-2 text-sm font-medium",
lg: "gap-1.5 py-1 px-2.5 text-sm font-medium rounded-lg",
};
const sizes = {
[badgeTypes.pillColor]: pillSizes,
[badgeTypes.badgeColor]: badgeSizes,
[badgeTypes.badgeModern]: badgeSizes,
};
return (
{children}
);
};
interface BadgeWithIconProps {
type?: T;
size?: Sizes;
color?: BadgeTypeToColorMap[T];
iconLeading?: IconComponentType;
iconTrailing?: IconComponentType;
children: ReactNode;
className?: string;
}
export const BadgeWithIcon = (props: BadgeWithIconProps) => {
const { size = "md", color = "gray", type = "pill-color", iconLeading: IconLeading, iconTrailing: IconTrailing, children, className } = props;
const colors = withBadgeTypes[type];
const icon = IconLeading ? "leading" : "trailing";
const pillSizes = {
sm: {
trailing: "gap-0.5 py-0.5 pl-2 pr-1.5 text-xs font-medium",
leading: "gap-0.5 py-0.5 pr-2 pl-1.5 text-xs font-medium",
},
md: {
trailing: "gap-1 py-0.5 pl-2.5 pr-2 text-sm font-medium",
leading: "gap-1 py-0.5 pr-2.5 pl-2 text-sm font-medium",
},
lg: {
trailing: "gap-1 py-1 pl-3 pr-2.5 text-sm font-medium",
leading: "gap-1 py-1 pr-3 pl-2.5 text-sm font-medium",
},
};
const badgeSizes = {
sm: {
trailing: "gap-0.5 py-0.5 pl-2 pr-1.5 text-xs font-medium",
leading: "gap-0.5 py-0.5 pr-2 pl-1.5 text-xs font-medium",
},
md: {
trailing: "gap-1 py-0.5 pl-2 pr-1.5 text-sm font-medium",
leading: "gap-1 py-0.5 pr-2 pl-1.5 text-sm font-medium",
},
lg: {
trailing: "gap-1 py-1 pl-2.5 pr-2 text-sm font-medium rounded-lg",
leading: "gap-1 py-1 pr-2.5 pl-2 text-sm font-medium rounded-lg",
},
};
const sizes = {
[badgeTypes.pillColor]: pillSizes,
[badgeTypes.badgeColor]: badgeSizes,
[badgeTypes.badgeModern]: badgeSizes,
};
return (
{IconLeading && }
{children}
{IconTrailing && }
);
};
interface BadgeWithFlagProps {
type?: T;
size?: Sizes;
flag?: FlagTypes;
color?: BadgeTypeToColorMap[T];
children: ReactNode;
}
export const BadgeWithFlag = (props: BadgeWithFlagProps) => {
const { size = "md", color = "gray", flag = "AU", type = "pill-color", children } = props;
const colors = withPillTypes[type];
const pillSizes = {
sm: "gap-1 py-0.5 pl-0.75 pr-2 text-xs font-medium",
md: "gap-1.5 py-0.5 pl-1 pr-2.5 text-sm font-medium",
lg: "gap-1.5 py-1 pl-1.5 pr-3 text-sm font-medium",
};
const badgeSizes = {
sm: "gap-1 py-0.5 pl-1 pr-1.5 text-xs font-medium",
md: "gap-1.5 py-0.5 pl-1.5 pr-2 text-sm font-medium",
lg: "gap-1.5 py-1 pl-2 pr-2.5 text-sm font-medium rounded-lg",
};
const sizes = {
[badgeTypes.pillColor]: pillSizes,
[badgeTypes.badgeColor]: badgeSizes,
[badgeTypes.badgeModern]: badgeSizes,
};
return (
{children}
);
};
interface BadgeWithImageProps {
type?: T;
size?: Sizes;
imgSrc: string;
color?: BadgeTypeToColorMap[T];
children: ReactNode;
}
export const BadgeWithImage = (props: BadgeWithImageProps) => {
const { size = "md", color = "gray", type = "pill-color", imgSrc, children } = props;
const colors = withPillTypes[type];
const pillSizes = {
sm: "gap-1 py-0.5 pl-0.75 pr-2 text-xs font-medium",
md: "gap-1.5 py-0.5 pl-1 pr-2.5 text-sm font-medium",
lg: "gap-1.5 py-1 pl-1.5 pr-3 text-sm font-medium",
};
const badgeSizes = {
sm: "gap-1 py-0.5 pl-1 pr-1.5 text-xs font-medium",
md: "gap-1.5 py-0.5 pl-1.5 pr-2 text-sm font-medium",
lg: "gap-1.5 py-1 pl-2 pr-2.5 text-sm font-medium rounded-lg",
};
const sizes = {
[badgeTypes.pillColor]: pillSizes,
[badgeTypes.badgeColor]: badgeSizes,
[badgeTypes.badgeModern]: badgeSizes,
};
return (
{children}
);
};
interface BadgeWithButtonProps {
type?: T;
size?: Sizes;
icon?: IconComponentType;
color?: BadgeTypeToColorMap[T];
children: ReactNode;
/**
* The label for the button.
*/
buttonLabel?: string;
/**
* The click event handler for the button.
*/
onButtonClick?: MouseEventHandler;
}
export const BadgeWithButton = (props: BadgeWithButtonProps) => {
const { size = "md", color = "gray", type = "pill-color", icon: Icon = CloseX, buttonLabel, children } = props;
const colors = withPillTypes[type];
const pillSizes = {
sm: "gap-0.5 py-0.5 pl-2 pr-0.75 text-xs font-medium",
md: "gap-0.5 py-0.5 pl-2.5 pr-1 text-sm font-medium",
lg: "gap-0.5 py-1 pl-3 pr-1.5 text-sm font-medium",
};
const badgeSizes = {
sm: "gap-0.5 py-0.5 pl-1.5 pr-0.75 text-xs font-medium",
md: "gap-0.5 py-0.5 pl-2 pr-1 text-sm font-medium",
lg: "gap-0.5 py-1 pl-2.5 pr-1.5 text-sm font-medium rounded-lg",
};
const sizes = {
[badgeTypes.pillColor]: pillSizes,
[badgeTypes.badgeColor]: badgeSizes,
[badgeTypes.badgeModern]: badgeSizes,
};
return (
{children}
);
};
interface BadgeIconProps {
type?: T;
size?: Sizes;
icon: IconComponentType;
color?: BadgeTypeToColorMap[T];
children?: ReactNode;
}
export const BadgeIcon = (props: BadgeIconProps) => {
const { size = "md", color = "gray", type = "pill-color", icon: Icon } = props;
const colors = withPillTypes[type];
const pillSizes = {
sm: "p-1.25",
md: "p-1.5",
lg: "p-2",
};
const badgeSizes = {
sm: "p-1.25",
md: "p-1.5",
lg: "p-2 rounded-lg",
};
const sizes = {
[badgeTypes.pillColor]: pillSizes,
[badgeTypes.badgeColor]: badgeSizes,
[badgeTypes.badgeModern]: badgeSizes,
};
return (
);
};