Add Badge atom component
- Create badge component tokens (height, paddingX, fontSize, iconSize, iconGap, borderRadius for sm/md sizes) — 10 tokens - Build Badge component: pill-shaped status indicator label - 6 colours: default, brand, success, warning, error, info - 2 variants: soft (tonal, default) and filled (solid) - 2 sizes: small (22px) and medium (26px) - Optional leading icon prop - All colours use CSS variables from token system (no hardcoded hex) - Create 10 Storybook stories: Default, AllColoursSoft, AllColoursFilled, WithIcons, WithIconsFilled, Sizes, SmallSizes, InPriceCard, ServiceStatus, CompleteMatrix - Regenerate token pipeline outputs Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
268
src/components/atoms/Badge/Badge.stories.tsx
Normal file
268
src/components/atoms/Badge/Badge.stories.tsx
Normal file
@@ -0,0 +1,268 @@
|
|||||||
|
import type { Meta, StoryObj } from '@storybook/react';
|
||||||
|
import { Badge } from './Badge';
|
||||||
|
import { Card } from '../Card';
|
||||||
|
import { Typography } from '../Typography';
|
||||||
|
import { Button } from '../Button';
|
||||||
|
import Box from '@mui/material/Box';
|
||||||
|
import StarIcon from '@mui/icons-material/Star';
|
||||||
|
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
|
||||||
|
import WarningAmberIcon from '@mui/icons-material/WarningAmber';
|
||||||
|
import ErrorOutlineIcon from '@mui/icons-material/ErrorOutline';
|
||||||
|
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
|
||||||
|
import LocalOfferIcon from '@mui/icons-material/LocalOffer';
|
||||||
|
import NewReleasesIcon from '@mui/icons-material/NewReleases';
|
||||||
|
import VerifiedIcon from '@mui/icons-material/Verified';
|
||||||
|
|
||||||
|
const meta: Meta<typeof Badge> = {
|
||||||
|
title: 'Atoms/Badge',
|
||||||
|
component: Badge,
|
||||||
|
tags: ['autodocs'],
|
||||||
|
parameters: {
|
||||||
|
layout: 'centered',
|
||||||
|
},
|
||||||
|
argTypes: {
|
||||||
|
color: {
|
||||||
|
control: 'select',
|
||||||
|
options: ['default', 'brand', 'success', 'warning', 'error', 'info'],
|
||||||
|
description: 'Colour intent',
|
||||||
|
table: { defaultValue: { summary: 'default' } },
|
||||||
|
},
|
||||||
|
variant: {
|
||||||
|
control: 'select',
|
||||||
|
options: ['soft', 'filled'],
|
||||||
|
description: 'Visual style variant',
|
||||||
|
table: { defaultValue: { summary: 'soft' } },
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
control: 'select',
|
||||||
|
options: ['small', 'medium'],
|
||||||
|
description: 'Size preset',
|
||||||
|
table: { defaultValue: { summary: 'medium' } },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
type Story = StoryObj<typeof Badge>;
|
||||||
|
|
||||||
|
// ─── Default ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/** Default badge — soft variant, default colour */
|
||||||
|
export const Default: Story = {
|
||||||
|
args: {
|
||||||
|
children: 'Status',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// ─── All Colours — Soft ─────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/** Soft variant across all colour options */
|
||||||
|
export const AllColoursSoft: Story = {
|
||||||
|
name: 'All Colours — Soft',
|
||||||
|
render: () => (
|
||||||
|
<div style={{ display: 'flex', gap: 12, flexWrap: 'wrap', alignItems: 'center' }}>
|
||||||
|
<Badge color="default">Default</Badge>
|
||||||
|
<Badge color="brand">Brand</Badge>
|
||||||
|
<Badge color="success">Success</Badge>
|
||||||
|
<Badge color="warning">Warning</Badge>
|
||||||
|
<Badge color="error">Error</Badge>
|
||||||
|
<Badge color="info">Info</Badge>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
// ─── All Colours — Filled ───────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/** Filled variant across all colour options */
|
||||||
|
export const AllColoursFilled: Story = {
|
||||||
|
name: 'All Colours — Filled',
|
||||||
|
render: () => (
|
||||||
|
<div style={{ display: 'flex', gap: 12, flexWrap: 'wrap', alignItems: 'center' }}>
|
||||||
|
<Badge variant="filled" color="default">Default</Badge>
|
||||||
|
<Badge variant="filled" color="brand">Brand</Badge>
|
||||||
|
<Badge variant="filled" color="success">Success</Badge>
|
||||||
|
<Badge variant="filled" color="warning">Warning</Badge>
|
||||||
|
<Badge variant="filled" color="error">Error</Badge>
|
||||||
|
<Badge variant="filled" color="info">Info</Badge>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
// ─── With Icons ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/** Badges with leading icons */
|
||||||
|
export const WithIcons: Story = {
|
||||||
|
name: 'With Icons',
|
||||||
|
render: () => (
|
||||||
|
<div style={{ display: 'flex', gap: 12, flexWrap: 'wrap', alignItems: 'center' }}>
|
||||||
|
<Badge color="brand" icon={<StarIcon />}>Popular</Badge>
|
||||||
|
<Badge color="success" icon={<CheckCircleIcon />}>Verified</Badge>
|
||||||
|
<Badge color="warning" icon={<WarningAmberIcon />}>Limited</Badge>
|
||||||
|
<Badge color="error" icon={<ErrorOutlineIcon />}>Sold out</Badge>
|
||||||
|
<Badge color="info" icon={<InfoOutlinedIcon />}>New</Badge>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Filled badges with icons */
|
||||||
|
export const WithIconsFilled: Story = {
|
||||||
|
name: 'With Icons — Filled',
|
||||||
|
render: () => (
|
||||||
|
<div style={{ display: 'flex', gap: 12, flexWrap: 'wrap', alignItems: 'center' }}>
|
||||||
|
<Badge variant="filled" color="brand" icon={<StarIcon />}>Popular</Badge>
|
||||||
|
<Badge variant="filled" color="success" icon={<CheckCircleIcon />}>Included</Badge>
|
||||||
|
<Badge variant="filled" color="warning" icon={<WarningAmberIcon />}>Attention</Badge>
|
||||||
|
<Badge variant="filled" color="error" icon={<ErrorOutlineIcon />}>Unavailable</Badge>
|
||||||
|
<Badge variant="filled" color="info" icon={<InfoOutlinedIcon />}>Updated</Badge>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
// ─── Sizes ──────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/** Both sizes side by side */
|
||||||
|
export const Sizes: Story = {
|
||||||
|
render: () => (
|
||||||
|
<div style={{ display: 'flex', gap: 16, alignItems: 'center' }}>
|
||||||
|
<Badge size="small" color="brand" icon={<StarIcon />}>Small</Badge>
|
||||||
|
<Badge size="medium" color="brand" icon={<StarIcon />}>Medium</Badge>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
/** All colours in small size */
|
||||||
|
export const SmallSizes: Story = {
|
||||||
|
name: 'Small — All Colours',
|
||||||
|
render: () => (
|
||||||
|
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', alignItems: 'center' }}>
|
||||||
|
<Badge size="small" color="default">Default</Badge>
|
||||||
|
<Badge size="small" color="brand" icon={<StarIcon />}>Brand</Badge>
|
||||||
|
<Badge size="small" color="success" icon={<CheckCircleIcon />}>Success</Badge>
|
||||||
|
<Badge size="small" color="warning">Warning</Badge>
|
||||||
|
<Badge size="small" color="error">Error</Badge>
|
||||||
|
<Badge size="small" color="info">Info</Badge>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
// ─── In Context: Price Card ─────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Badge used inside a PriceCard-style layout.
|
||||||
|
* Shows how badges label card content in realistic compositions.
|
||||||
|
*/
|
||||||
|
export const InPriceCard: Story = {
|
||||||
|
name: 'In Context — Price Card',
|
||||||
|
render: () => (
|
||||||
|
<div style={{ display: 'flex', gap: 24, maxWidth: 750 }}>
|
||||||
|
<Card sx={{ flex: 1 }}>
|
||||||
|
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'start', mb: 2 }}>
|
||||||
|
<Typography variant="overline" color="text.secondary">
|
||||||
|
Essential
|
||||||
|
</Typography>
|
||||||
|
<Badge size="small" color="default">Standard</Badge>
|
||||||
|
</Box>
|
||||||
|
<Typography variant="display3" color="primary" sx={{ mb: 1 }}>
|
||||||
|
$3,200
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="body2" color="text.secondary" sx={{ mb: 3 }}>
|
||||||
|
A simple, respectful service with chapel ceremony.
|
||||||
|
</Typography>
|
||||||
|
<Button fullWidth>Select</Button>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card sx={{ flex: 1 }}>
|
||||||
|
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'start', mb: 2 }}>
|
||||||
|
<Typography variant="overline" color="text.secondary">
|
||||||
|
Premium
|
||||||
|
</Typography>
|
||||||
|
<Badge color="brand" icon={<StarIcon />}>Most popular</Badge>
|
||||||
|
</Box>
|
||||||
|
<Typography variant="display3" color="primary" sx={{ mb: 1 }}>
|
||||||
|
$5,800
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="body2" color="text.secondary" sx={{ mb: 3 }}>
|
||||||
|
Comprehensive service with premium inclusions.
|
||||||
|
</Typography>
|
||||||
|
<Button fullWidth>Select</Button>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card sx={{ flex: 1 }}>
|
||||||
|
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'start', mb: 2 }}>
|
||||||
|
<Typography variant="overline" color="text.secondary">
|
||||||
|
Bespoke
|
||||||
|
</Typography>
|
||||||
|
<Badge color="info" icon={<LocalOfferIcon />}>Best value</Badge>
|
||||||
|
</Box>
|
||||||
|
<Typography variant="display3" color="primary" sx={{ mb: 1 }}>
|
||||||
|
$8,500
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="body2" color="text.secondary" sx={{ mb: 3 }}>
|
||||||
|
Fully customised farewell with dedicated coordinator.
|
||||||
|
</Typography>
|
||||||
|
<Button fullWidth>Select</Button>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
// ─── In Context: Service Status ─────────────────────────────────────────────
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Badges used as status indicators in a service listing.
|
||||||
|
*/
|
||||||
|
export const ServiceStatus: Story = {
|
||||||
|
name: 'In Context — Service Status',
|
||||||
|
render: () => (
|
||||||
|
<div style={{ display: 'flex', flexDirection: 'column', gap: 12, maxWidth: 500 }}>
|
||||||
|
{[
|
||||||
|
{ service: 'Chapel ceremony', badge: <Badge color="success" icon={<CheckCircleIcon />}>Confirmed</Badge> },
|
||||||
|
{ service: 'Floral arrangements', badge: <Badge color="warning" icon={<WarningAmberIcon />}>Pending</Badge> },
|
||||||
|
{ service: 'Catering', badge: <Badge color="error" icon={<ErrorOutlineIcon />}>Unavailable</Badge> },
|
||||||
|
{ service: 'Memorial printing', badge: <Badge color="info" icon={<NewReleasesIcon />}>New option</Badge> },
|
||||||
|
{ service: 'Premium casket', badge: <Badge variant="filled" color="brand" icon={<VerifiedIcon />}>Included</Badge> },
|
||||||
|
].map((item) => (
|
||||||
|
<Card key={item.service} variant="outlined" padding="compact">
|
||||||
|
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||||
|
<Typography variant="labelLg">{item.service}</Typography>
|
||||||
|
{item.badge}
|
||||||
|
</Box>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
// ─── Complete Matrix ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/** Full variant × colour × size matrix for visual QA */
|
||||||
|
export const CompleteMatrix: Story = {
|
||||||
|
name: 'Complete Matrix',
|
||||||
|
render: () => {
|
||||||
|
const colors = ['default', 'brand', 'success', 'warning', 'error', 'info'] as const;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ display: 'flex', flexDirection: 'column', gap: 24 }}>
|
||||||
|
{(['soft', 'filled'] as const).map((variant) => (
|
||||||
|
<div key={variant}>
|
||||||
|
<div style={{ marginBottom: 8, fontWeight: 600, fontSize: 14, textTransform: 'capitalize' }}>
|
||||||
|
{variant}
|
||||||
|
</div>
|
||||||
|
<div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
|
||||||
|
{(['medium', 'small'] as const).map((size) => (
|
||||||
|
<div key={size} style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
|
||||||
|
<span style={{ width: 60, fontSize: 12, color: '#737373' }}>{size}</span>
|
||||||
|
{colors.map((color) => (
|
||||||
|
<Badge key={color} variant={variant} color={color} size={size} icon={<StarIcon />}>
|
||||||
|
{color}
|
||||||
|
</Badge>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
141
src/components/atoms/Badge/Badge.tsx
Normal file
141
src/components/atoms/Badge/Badge.tsx
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import Box from '@mui/material/Box';
|
||||||
|
import type { BoxProps } from '@mui/material/Box';
|
||||||
|
import type { Theme } from '@mui/material/styles';
|
||||||
|
|
||||||
|
// ─── Types ───────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/** Colour intent for the badge */
|
||||||
|
export type BadgeColor = 'default' | 'brand' | 'success' | 'warning' | 'error' | 'info';
|
||||||
|
|
||||||
|
/** Props for the FA Badge component */
|
||||||
|
export interface BadgeProps extends Omit<BoxProps, 'color'> {
|
||||||
|
/** Colour intent */
|
||||||
|
color?: BadgeColor;
|
||||||
|
/** Visual style: "filled" (solid background) or "soft" (tonal/subtle background) */
|
||||||
|
variant?: 'filled' | 'soft';
|
||||||
|
/** Size preset */
|
||||||
|
size?: 'small' | 'medium';
|
||||||
|
/** Optional leading icon */
|
||||||
|
icon?: React.ReactNode;
|
||||||
|
/** Label text */
|
||||||
|
children: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── Colour maps ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
const filledColors: Record<BadgeColor, (t: Theme) => { bg: string; text: string }> = {
|
||||||
|
default: (t) => ({ bg: t.palette.grey[700], text: t.palette.common.white }),
|
||||||
|
brand: (t) => ({ bg: t.palette.primary.main, text: t.palette.common.white }),
|
||||||
|
success: (t) => ({ bg: t.palette.success.main, text: t.palette.common.white }),
|
||||||
|
warning: (t) => ({ bg: t.palette.warning.main, text: t.palette.common.white }),
|
||||||
|
error: (t) => ({ bg: t.palette.error.main, text: t.palette.common.white }),
|
||||||
|
info: (t) => ({ bg: t.palette.info.main, text: t.palette.common.white }),
|
||||||
|
};
|
||||||
|
|
||||||
|
const softColors: Record<BadgeColor, (t: Theme) => { bg: string; text: string }> = {
|
||||||
|
default: (t) => ({ bg: t.palette.grey[200], text: t.palette.grey[700] }),
|
||||||
|
brand: () => ({
|
||||||
|
bg: 'var(--fa-color-brand-200)',
|
||||||
|
text: 'var(--fa-color-brand-700)',
|
||||||
|
}),
|
||||||
|
success: () => ({
|
||||||
|
bg: 'var(--fa-color-feedback-success-subtle)',
|
||||||
|
text: 'var(--fa-color-feedback-success)',
|
||||||
|
}),
|
||||||
|
warning: () => ({
|
||||||
|
bg: 'var(--fa-color-feedback-warning-subtle)',
|
||||||
|
text: 'var(--fa-color-text-warning)',
|
||||||
|
}),
|
||||||
|
error: () => ({
|
||||||
|
bg: 'var(--fa-color-feedback-error-subtle)',
|
||||||
|
text: 'var(--fa-color-feedback-error)',
|
||||||
|
}),
|
||||||
|
info: () => ({
|
||||||
|
bg: 'var(--fa-color-feedback-info-subtle)',
|
||||||
|
text: 'var(--fa-color-feedback-info)',
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
// ─── Component ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Status indicator label for the FA design system.
|
||||||
|
*
|
||||||
|
* Pill-shaped, display-only badge for communicating status, category,
|
||||||
|
* or emphasis. Used in PriceCard ("Popular"), ServiceOption ("Included"),
|
||||||
|
* and other contexts.
|
||||||
|
*
|
||||||
|
* Colour options:
|
||||||
|
* - `default` — neutral grey (general labels)
|
||||||
|
* - `brand` — warm gold/copper (promoted, featured)
|
||||||
|
* - `success` — green (confirmed, included, available)
|
||||||
|
* - `warning` — amber (limited, expiring, attention)
|
||||||
|
* - `error` — red (sold out, unavailable, urgent)
|
||||||
|
* - `info` — blue (new, updated, informational)
|
||||||
|
*
|
||||||
|
* Variant options:
|
||||||
|
* - `soft` (default) — tonal background, coloured text. Calmer, preferred for FA.
|
||||||
|
* - `filled` — solid background, white text. For high-priority emphasis.
|
||||||
|
*/
|
||||||
|
export const Badge = React.forwardRef<HTMLDivElement, BadgeProps>(
|
||||||
|
(
|
||||||
|
{
|
||||||
|
color = 'default',
|
||||||
|
variant = 'soft',
|
||||||
|
size = 'medium',
|
||||||
|
icon,
|
||||||
|
children,
|
||||||
|
sx,
|
||||||
|
...props
|
||||||
|
},
|
||||||
|
ref,
|
||||||
|
) => {
|
||||||
|
const isSmall = size === 'small';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
ref={ref}
|
||||||
|
component="span"
|
||||||
|
sx={[
|
||||||
|
(theme: Theme) => {
|
||||||
|
const colors = variant === 'filled'
|
||||||
|
? filledColors[color](theme)
|
||||||
|
: softColors[color](theme);
|
||||||
|
|
||||||
|
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)',
|
||||||
|
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)',
|
||||||
|
fontWeight: 600,
|
||||||
|
fontFamily: theme.typography.fontFamily,
|
||||||
|
lineHeight: 1,
|
||||||
|
letterSpacing: '0.02em',
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
userSelect: 'none',
|
||||||
|
// Icon sizing
|
||||||
|
'& > .MuiSvgIcon-root, & > svg': {
|
||||||
|
fontSize: isSmall ? 'var(--fa-badge-icon-size-sm)' : 'var(--fa-badge-icon-size-md)',
|
||||||
|
flexShrink: 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
...(Array.isArray(sx) ? sx : [sx]),
|
||||||
|
]}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{icon}
|
||||||
|
{children}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
Badge.displayName = 'Badge';
|
||||||
|
export default Badge;
|
||||||
2
src/components/atoms/Badge/index.ts
Normal file
2
src/components/atoms/Badge/index.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export { Badge, type BadgeProps, type BadgeColor } from './Badge';
|
||||||
|
export { default } from './Badge';
|
||||||
@@ -3,6 +3,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
|
--fa-badge-height-sm: 22px; /** Small — compact inline status indicators */
|
||||||
|
--fa-badge-height-md: 26px; /** Medium — default status badges, card labels */
|
||||||
|
--fa-badge-icon-size-sm: 12px; /** 12px icons in small badges */
|
||||||
|
--fa-badge-icon-size-md: 14px; /** 14px icons in medium badges */
|
||||||
--fa-button-height-xs: 28px; /** Extra-small — compact text buttons, inline actions */
|
--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-sm: 32px; /** Small — secondary actions, toolbar buttons */
|
||||||
--fa-button-height-md: 40px; /** Medium — default size, form submissions */
|
--fa-button-height-md: 40px; /** Medium — default size, form submissions */
|
||||||
@@ -206,6 +210,12 @@
|
|||||||
--fa-typography-overline-letter-spacing: 1.5px;
|
--fa-typography-overline-letter-spacing: 1.5px;
|
||||||
--fa-typography-overline-sm-line-height: 1.273;
|
--fa-typography-overline-sm-line-height: 1.273;
|
||||||
--fa-typography-overline-sm-letter-spacing: 1.5px;
|
--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-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-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 */
|
--fa-button-padding-x-xs: var(--fa-spacing-2); /** 8px — compact horizontal padding */
|
||||||
--fa-button-padding-x-sm: var(--fa-spacing-3); /** 12px — small horizontal padding */
|
--fa-button-padding-x-sm: var(--fa-spacing-3); /** 12px — small horizontal padding */
|
||||||
--fa-button-padding-x-md: var(--fa-spacing-4); /** 16px — default horizontal padding */
|
--fa-button-padding-x-md: var(--fa-spacing-4); /** 16px — default horizontal padding */
|
||||||
|
|||||||
@@ -2,6 +2,16 @@
|
|||||||
* Do not edit directly, this file was auto-generated.
|
* Do not edit directly, this file was auto-generated.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
export const BadgeHeightSm = "22px"; // Small — compact inline status indicators
|
||||||
|
export const BadgeHeightMd = "26px"; // Medium — default status badges, card labels
|
||||||
|
export const BadgePaddingXSm = "8px"; // 8px — compact horizontal padding
|
||||||
|
export const BadgePaddingXMd = "12px"; // 12px — default horizontal padding
|
||||||
|
export const BadgeFontSizeSm = "0.6875rem"; // 11px — small badge text
|
||||||
|
export const BadgeFontSizeMd = "0.75rem"; // 12px — default badge text
|
||||||
|
export const BadgeIconSizeSm = "12px"; // 12px icons in small badges
|
||||||
|
export const BadgeIconSizeMd = "14px"; // 14px icons in medium 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
|
export const ButtonHeightXs = "28px"; // Extra-small — compact text buttons, inline actions
|
||||||
export const ButtonHeightSm = "32px"; // Small — secondary actions, toolbar buttons
|
export const ButtonHeightSm = "32px"; // Small — secondary actions, toolbar buttons
|
||||||
export const ButtonHeightMd = "40px"; // Medium — default size, form submissions
|
export const ButtonHeightMd = "40px"; // Medium — default size, form submissions
|
||||||
|
|||||||
39
tokens/component/badge.json
Normal file
39
tokens/component/badge.json
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
{
|
||||||
|
"badge": {
|
||||||
|
"$description": "Badge component tokens — status indicator labels used in PriceCard, ServiceOption, and other contexts. Display-only, not interactive.",
|
||||||
|
"height": {
|
||||||
|
"$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" }
|
||||||
|
},
|
||||||
|
"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" }
|
||||||
|
},
|
||||||
|
"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" }
|
||||||
|
},
|
||||||
|
"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" }
|
||||||
|
},
|
||||||
|
"iconGap": {
|
||||||
|
"$type": "dimension",
|
||||||
|
"$description": "Gap between icon and label text.",
|
||||||
|
"default": { "$value": "{spacing.1}", "$description": "4px icon-text gap" }
|
||||||
|
},
|
||||||
|
"borderRadius": {
|
||||||
|
"$type": "dimension",
|
||||||
|
"$description": "Badge corner radius.",
|
||||||
|
"default": { "$value": "{borderRadius.full}", "$description": "Pill shape — fully rounded" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user