UNPKG

@octopusdeploy/design-system-components

Version:
195 lines (194 loc) • 9.1 kB
"use strict"; 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 }); }