@octopusdeploy/design-system-components
Version:
The design systems component library.
195 lines (194 loc) • 9.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Badge = Badge;
const jsx_runtime_1 = require("react/jsx-runtime");
const css_1 = require("@emotion/css");
const design_system_icons_1 = require("@octopusdeploy/design-system-icons");
const design_system_tokens_1 = require("@octopusdeploy/design-system-tokens");
const react_1 = require("react");
const badgeStyles = (0, css_1.css)({
display: "inline-flex",
flexShrink: 0,
width: "fit-content",
borderRadius: design_system_tokens_1.borderRadius.circle,
alignItems: "center",
justifyContent: "center",
boxSizing: "border-box",
});
const variantStyles = {
danger: (0, css_1.css)({
backgroundColor: design_system_tokens_1.themeTokens.color.badge.background.danger,
color: design_system_tokens_1.themeTokens.color.badge.text.primary,
"--badge-pulse-color": design_system_tokens_1.themeTokens.color.badge.background.danger,
}),
neutral: (0, css_1.css)({
backgroundColor: design_system_tokens_1.themeTokens.color.badge.background.neutral,
color: design_system_tokens_1.themeTokens.color.badge.text.secondary,
"--badge-pulse-color": design_system_tokens_1.themeTokens.color.badge.background.neutral,
}),
success: (0, css_1.css)({
backgroundColor: design_system_tokens_1.themeTokens.color.badge.background.success,
color: design_system_tokens_1.themeTokens.color.badge.text.primary,
"--badge-pulse-color": design_system_tokens_1.themeTokens.color.badge.background.success,
}),
info: (0, css_1.css)({
backgroundColor: design_system_tokens_1.themeTokens.color.badge.background.info,
color: design_system_tokens_1.themeTokens.color.badge.text.primary,
"--badge-pulse-color": design_system_tokens_1.themeTokens.color.badge.background.info,
}),
warning: (0, css_1.css)({
backgroundColor: design_system_tokens_1.themeTokens.color.badge.background.warning,
color: design_system_tokens_1.themeTokens.color.badge.text.primary,
"--badge-pulse-color": design_system_tokens_1.themeTokens.color.badge.background.warning,
}),
inverseNeutral: (0, css_1.css)({
backgroundColor: design_system_tokens_1.themeTokens.color.badge.background.inverseNeutral,
color: design_system_tokens_1.themeTokens.color.badge.text.primary,
"--badge-pulse-color": design_system_tokens_1.themeTokens.color.badge.background.inverseNeutral,
}),
feature: (0, css_1.css)({
backgroundColor: design_system_tokens_1.themeTokens.color.badge.background.feature,
color: design_system_tokens_1.themeTokens.color.badge.text.feature,
"--badge-pulse-color": design_system_tokens_1.themeTokens.color.badge.background.feature,
}),
upsell: (0, css_1.css)({
backgroundColor: design_system_tokens_1.themeTokens.color.badge.background.upsell,
color: design_system_tokens_1.themeTokens.color.badge.text.upsell,
"--badge-pulse-color": design_system_tokens_1.themeTokens.color.badge.background.upsell,
}),
};
const sizeStyles = {
xSmall: (0, css_1.css)({
height: "16px",
minWidth: "16px",
font: design_system_tokens_1.text.body.regular.xSmall,
fontSize: "12px",
padding: `0 ${design_system_tokens_1.space[4]}`,
}),
small: (0, css_1.css)({
height: "20px",
minWidth: "20px",
font: design_system_tokens_1.text.body.regular.xSmall,
padding: `0 ${design_system_tokens_1.space[6]}`,
gap: design_system_tokens_1.space[4],
}),
medium: (0, css_1.css)({
height: "24px",
minWidth: "24px",
font: design_system_tokens_1.text.body.regular.small,
padding: `0 ${design_system_tokens_1.space[8]} 0 ${design_system_tokens_1.space[6]}`,
gap: design_system_tokens_1.space[6],
}),
};
/**
* Returns a key that changes when badge status (variant/label/count) changes, and whether
* to run the status animation. Animation runs only when statusAnimation is true and the key
* has changed since the previous render (not on first mount).
*/
function useStatusAnimationKey(statusAnimation, deps) {
const animationKey = (0, react_1.useMemo)(() => {
if (!statusAnimation)
return "static";
return `${deps.label ?? ""}-${deps.count ?? ""}`;
}, [statusAnimation, deps.label, deps.count]);
const prevKeyRef = (0, react_1.useRef)(undefined);
const prevKey = prevKeyRef.current;
const shouldAnimate = statusAnimation === true && prevKey !== undefined && prevKey !== animationKey;
(0, react_1.useLayoutEffect)(() => {
prevKeyRef.current = animationKey;
}, [animationKey]);
return { animationKey, shouldAnimate };
}
function Badge(props) {
return props.size === "xSmall" ? (0, jsx_runtime_1.jsx)(ExtraSmallBadge, { size: props.size, count: props.count, label: props.label, variant: props.variant }) : (0, jsx_runtime_1.jsx)(SmallOrMediumBadge, { ...props });
}
function ExtraSmallBadge(props) {
const { animationKey, shouldAnimate } = useStatusAnimationKey(props.statusAnimation, { variant: props.variant, label: props.label, count: props.count });
return ((0, jsx_runtime_1.jsx)("div", { className: (0, css_1.cx)(badgeStyles, variantStyles[props.variant], sizeStyles[props.size], { [statusAnimationStyles]: shouldAnimate }), children: (0, jsx_runtime_1.jsx)(BadgeLabel, { label: props.label, count: props.count, size: props.size }) }, animationKey));
}
function SmallOrMediumBadge(props) {
const { animationKey, shouldAnimate } = useStatusAnimationKey(props.statusAnimation, { variant: props.variant, label: props.label, count: props.count });
let icon = undefined;
if (props.variant === "upsell") {
if (props.hideIcon !== true) {
const iconSize = props.size === "medium" ? 20 : 16;
icon = (0, jsx_runtime_1.jsx)(design_system_icons_1.GemIcon, { size: iconSize, color: design_system_tokens_1.themeTokens.color.badge.icon.upsell });
}
}
else if ("icon" in props) {
icon = props.icon;
}
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, css_1.cx)(badgeStyles, variantStyles[props.variant], sizeStyles[props.size], { [statusAnimationStyles]: shouldAnimate, [countOnlyBadgeStyles]: !icon && !props.label }), children: [icon && (0, jsx_runtime_1.jsx)(BadgeIcon, { size: props.size, icon: icon }), (0, jsx_runtime_1.jsx)(BadgeLabel, { label: props.label, count: props.count, size: props.size })] }, animationKey));
}
const smallBadgeIconStyles = (0, css_1.css)({
width: "16px",
height: "16px",
});
const mediumBadgeIconStyles = (0, css_1.css)({
width: "20px",
height: "20px",
});
const badgeStatusAnimationKeyFrames = (0, css_1.keyframes)({
"0%": {
backgroundColor: "color-mix(in srgb, var(--badge-pulse-color) 65%, black)",
boxShadow: "0 0 0 0 color-mix(in srgb, var(--badge-pulse-color) 60%, transparent)",
},
"70%": {
boxShadow: "0 0 0 5px transparent",
},
"100%": {
backgroundColor: "var(--badge-pulse-color)",
boxShadow: "0 0 0 0 transparent",
},
});
const statusAnimationStyles = (0, css_1.css)({
animationName: `${badgeStatusAnimationKeyFrames}`,
animationDuration: ".75s",
animationIterationCount: 1,
animationFillMode: "forwards",
animationTimingFunction: "ease-in-out",
"@media (prefers-reduced-motion: reduce)": {
animation: "none",
},
});
function BadgeIcon({ icon, size }) {
return (0, jsx_runtime_1.jsx)("div", { className: size === "medium" ? mediumBadgeIconStyles : smallBadgeIconStyles, children: icon });
}
const badgeLabelStyles = (0, css_1.css)({
display: "flex",
gap: design_system_tokens_1.space[4],
justifyContent: "center",
alignItems: "center",
});
const xSmallLabelStyles = (0, css_1.css)({
fontWeight: design_system_tokens_1.fontWeight[600],
fontSize: "12px",
lineHeight: "16px",
});
function BadgeLabel({ label, count, size }) {
return ((0, jsx_runtime_1.jsxs)("span", { className: (0, css_1.cx)(badgeLabelStyles, { [xSmallLabelStyles]: size === "xSmall" }), children: [count !== undefined && (0, jsx_runtime_1.jsx)(BadgeCount, { count: count, size: size }), label] }));
}
const badgeCountStyles = (0, css_1.css)({
display: "flex",
justifyItems: "center",
alignItems: "center",
});
const badgeCountSizeStyles = {
xSmall: (0, css_1.css)({
fontWeight: design_system_tokens_1.fontWeight[600],
fontSize: "12px",
lineHeight: "16px",
}),
small: (0, css_1.css)({
font: design_system_tokens_1.text.body.regular.xSmall,
}),
medium: (0, css_1.css)({
font: design_system_tokens_1.text.body.bold.small,
}),
};
const countOnlyBadgeStyles = (0, css_1.css)({
padding: `0 ${design_system_tokens_1.space[4]}`,
});
function BadgeCount({ count, size }) {
return (0, jsx_runtime_1.jsx)("span", { className: (0, css_1.cx)(badgeCountStyles, badgeCountSizeStyles[size]), children: count });
}