From e67e8f46f71ca717b7f4fb4504fd0bf6ad953916 Mon Sep 17 00:00:00 2001 From: Richie Date: Wed, 25 Mar 2026 16:08:17 +1100 Subject: [PATCH] Add large size to Badge - Add lg tokens: height 32px, paddingX 16px, fontSize 14px, iconSize 16px - Refactor component to use size map instead of ternary - Update stories: Sizes now shows all three, CompleteMatrix includes large Co-Authored-By: Claude Opus 4.6 (1M context) --- src/components/atoms/Badge/Badge.stories.tsx | 22 +++---------- src/components/atoms/Badge/Badge.tsx | 33 ++++++++++++++++---- src/theme/generated/tokens.css | 4 +++ src/theme/generated/tokens.js | 4 +++ tokens/component/badge.json | 12 ++++--- 5 files changed, 47 insertions(+), 28 deletions(-) diff --git a/src/components/atoms/Badge/Badge.stories.tsx b/src/components/atoms/Badge/Badge.stories.tsx index a3be7cd..cc40d1a 100644 --- a/src/components/atoms/Badge/Badge.stories.tsx +++ b/src/components/atoms/Badge/Badge.stories.tsx @@ -35,7 +35,7 @@ const meta: Meta = { }, size: { control: 'select', - options: ['small', 'medium'], + options: ['small', 'medium', 'large'], description: 'Size preset', table: { defaultValue: { summary: 'medium' } }, }, @@ -120,27 +120,13 @@ export const WithIconsFilled: Story = { // ─── Sizes ────────────────────────────────────────────────────────────────── -/** Both sizes side by side */ +/** All three sizes side by side */ export const Sizes: Story = { render: () => (
}>Small }>Medium -
- ), -}; - -/** All colours in small size */ -export const SmallSizes: Story = { - name: 'Small — All Colours', - render: () => ( -
- Default - }>Brand - }>Success - Warning - Error - Info + }>Large
), }; @@ -249,7 +235,7 @@ export const CompleteMatrix: Story = { {variant}
- {(['medium', 'small'] as const).map((size) => ( + {(['large', 'medium', 'small'] as const).map((size) => (
{size} {colors.map((color) => ( diff --git a/src/components/atoms/Badge/Badge.tsx b/src/components/atoms/Badge/Badge.tsx index ecc1772..7273a64 100644 --- a/src/components/atoms/Badge/Badge.tsx +++ b/src/components/atoms/Badge/Badge.tsx @@ -15,7 +15,7 @@ export interface BadgeProps extends Omit { /** Visual style: "filled" (solid background) or "soft" (tonal/subtle background) */ variant?: 'filled' | 'soft'; /** Size preset */ - size?: 'small' | 'medium'; + size?: 'small' | 'medium' | 'large'; /** Optional leading icon */ icon?: React.ReactNode; /** Label text */ @@ -91,7 +91,28 @@ export const Badge = React.forwardRef( }, ref, ) => { - const isSmall = size === 'small'; + const sizeMap = { + small: { + height: 'var(--fa-badge-height-sm)', + px: 'var(--fa-badge-padding-x-sm)', + fontSize: 'var(--fa-badge-font-size-sm)', + iconSize: 'var(--fa-badge-icon-size-sm)', + }, + medium: { + height: 'var(--fa-badge-height-md)', + px: 'var(--fa-badge-padding-x-md)', + fontSize: 'var(--fa-badge-font-size-md)', + iconSize: 'var(--fa-badge-icon-size-md)', + }, + large: { + height: 'var(--fa-badge-height-lg)', + px: 'var(--fa-badge-padding-x-lg)', + fontSize: 'var(--fa-badge-font-size-lg)', + iconSize: 'var(--fa-badge-icon-size-lg)', + }, + } as const; + + const s = sizeMap[size]; return ( ( display: 'inline-flex', alignItems: 'center', gap: 'var(--fa-badge-icon-gap-default)', - minHeight: isSmall ? 'var(--fa-badge-height-sm)' : 'var(--fa-badge-height-md)', - px: isSmall ? 'var(--fa-badge-padding-x-sm)' : 'var(--fa-badge-padding-x-md)', + minHeight: s.height, + px: s.px, borderRadius: 'var(--fa-badge-border-radius-default)', backgroundColor: colors.bg, color: colors.text, - fontSize: isSmall ? 'var(--fa-badge-font-size-sm)' : 'var(--fa-badge-font-size-md)', + fontSize: s.fontSize, fontWeight: 600, fontFamily: theme.typography.fontFamily, lineHeight: 1, @@ -121,7 +142,7 @@ export const Badge = React.forwardRef( userSelect: 'none', // Icon sizing '& > .MuiSvgIcon-root, & > svg': { - fontSize: isSmall ? 'var(--fa-badge-icon-size-sm)' : 'var(--fa-badge-icon-size-md)', + fontSize: s.iconSize, flexShrink: 0, }, }; diff --git a/src/theme/generated/tokens.css b/src/theme/generated/tokens.css index eec0f4a..dccfc04 100644 --- a/src/theme/generated/tokens.css +++ b/src/theme/generated/tokens.css @@ -5,8 +5,10 @@ :root { --fa-badge-height-sm: 22px; /** Small — compact inline status indicators */ --fa-badge-height-md: 26px; /** Medium — default status badges, card labels */ + --fa-badge-height-lg: 32px; /** Large — prominent labels, hero badges, marketing callouts */ --fa-badge-icon-size-sm: 12px; /** 12px icons in small badges */ --fa-badge-icon-size-md: 14px; /** 14px icons in medium badges */ + --fa-badge-icon-size-lg: 16px; /** 16px icons in large badges */ --fa-button-height-xs: 28px; /** Extra-small — compact text buttons, inline actions */ --fa-button-height-sm: 32px; /** Small — secondary actions, toolbar buttons */ --fa-button-height-md: 40px; /** Medium — default size, form submissions */ @@ -212,8 +214,10 @@ --fa-typography-overline-sm-letter-spacing: 1.5px; --fa-badge-padding-x-sm: var(--fa-spacing-2); /** 8px — compact horizontal padding */ --fa-badge-padding-x-md: var(--fa-spacing-3); /** 12px — default horizontal padding */ + --fa-badge-padding-x-lg: var(--fa-spacing-4); /** 16px — generous horizontal padding */ --fa-badge-font-size-sm: var(--fa-font-size-2xs); /** 11px — small badge text */ --fa-badge-font-size-md: var(--fa-font-size-xs); /** 12px — default badge text */ + --fa-badge-font-size-lg: var(--fa-font-size-sm); /** 14px — large badge text */ --fa-badge-icon-gap-default: var(--fa-spacing-1); /** 4px icon-text gap */ --fa-badge-border-radius-default: var(--fa-border-radius-full); /** Pill shape — fully rounded */ --fa-button-padding-x-xs: var(--fa-spacing-2); /** 8px — compact horizontal padding */ diff --git a/src/theme/generated/tokens.js b/src/theme/generated/tokens.js index 66f0b5f..0d6fd49 100644 --- a/src/theme/generated/tokens.js +++ b/src/theme/generated/tokens.js @@ -4,12 +4,16 @@ export const BadgeHeightSm = "22px"; // Small — compact inline status indicators export const BadgeHeightMd = "26px"; // Medium — default status badges, card labels +export const BadgeHeightLg = "32px"; // Large — prominent labels, hero badges, marketing callouts export const BadgePaddingXSm = "8px"; // 8px — compact horizontal padding export const BadgePaddingXMd = "12px"; // 12px — default horizontal padding +export const BadgePaddingXLg = "16px"; // 16px — generous horizontal padding export const BadgeFontSizeSm = "0.6875rem"; // 11px — small badge text export const BadgeFontSizeMd = "0.75rem"; // 12px — default badge text +export const BadgeFontSizeLg = "0.875rem"; // 14px — large badge text export const BadgeIconSizeSm = "12px"; // 12px icons in small badges export const BadgeIconSizeMd = "14px"; // 14px icons in medium badges +export const BadgeIconSizeLg = "16px"; // 16px icons in large badges export const BadgeIconGapDefault = "4px"; // 4px icon-text gap export const BadgeBorderRadiusDefault = "9999px"; // Pill shape — fully rounded export const ButtonHeightXs = "28px"; // Extra-small — compact text buttons, inline actions diff --git a/tokens/component/badge.json b/tokens/component/badge.json index 9f1aa8f..dac9914 100644 --- a/tokens/component/badge.json +++ b/tokens/component/badge.json @@ -5,25 +5,29 @@ "$type": "dimension", "$description": "Badge heights per size.", "sm": { "$value": "22px", "$description": "Small — compact inline status indicators" }, - "md": { "$value": "26px", "$description": "Medium — default status badges, card labels" } + "md": { "$value": "26px", "$description": "Medium — default status badges, card labels" }, + "lg": { "$value": "32px", "$description": "Large — prominent labels, hero badges, marketing callouts" } }, "paddingX": { "$type": "dimension", "$description": "Horizontal padding per size.", "sm": { "$value": "{spacing.2}", "$description": "8px — compact horizontal padding" }, - "md": { "$value": "{spacing.3}", "$description": "12px — default horizontal padding" } + "md": { "$value": "{spacing.3}", "$description": "12px — default horizontal padding" }, + "lg": { "$value": "{spacing.4}", "$description": "16px — generous horizontal padding" } }, "fontSize": { "$type": "dimension", "$description": "Font size per badge size.", "sm": { "$value": "{fontSize.2xs}", "$description": "11px — small badge text" }, - "md": { "$value": "{fontSize.xs}", "$description": "12px — default badge text" } + "md": { "$value": "{fontSize.xs}", "$description": "12px — default badge text" }, + "lg": { "$value": "{fontSize.sm}", "$description": "14px — large badge text" } }, "iconSize": { "$type": "dimension", "$description": "Icon dimensions per badge size.", "sm": { "$value": "12px", "$description": "12px icons in small badges" }, - "md": { "$value": "14px", "$description": "14px icons in medium badges" } + "md": { "$value": "14px", "$description": "14px icons in medium badges" }, + "lg": { "$value": "16px", "$description": "16px icons in large badges" } }, "iconGap": { "$type": "dimension",