diff --git a/src/design-system/primitives/StatusText/StatusText.module.css b/src/design-system/primitives/StatusText/StatusText.module.css new file mode 100644 index 0000000..20d2127 --- /dev/null +++ b/src/design-system/primitives/StatusText/StatusText.module.css @@ -0,0 +1,7 @@ +.statusText {} +.success { color: var(--success); } +.warning { color: var(--warning); } +.error { color: var(--error); } +.running { color: var(--running); } +.muted { color: var(--text-muted); } +.bold { font-weight: 600; } diff --git a/src/design-system/primitives/StatusText/StatusText.test.tsx b/src/design-system/primitives/StatusText/StatusText.test.tsx new file mode 100644 index 0000000..7b1bab7 --- /dev/null +++ b/src/design-system/primitives/StatusText/StatusText.test.tsx @@ -0,0 +1,47 @@ +import { describe, it, expect } from 'vitest' +import { render, screen } from '@testing-library/react' +import { StatusText } from './StatusText' + +describe('StatusText', () => { + it('renders children text', () => { + render(Online) + expect(screen.getByText('Online')).toBeInTheDocument() + }) + + it('renders as a span element', () => { + render(Status) + const el = screen.getByText('Status') + expect(el.tagName).toBe('SPAN') + }) + + it('applies variant class', () => { + render(Failed) + expect(screen.getByText('Failed')).toHaveClass('error') + }) + + it('applies bold class when bold=true', () => { + render(OK) + expect(screen.getByText('OK')).toHaveClass('bold') + }) + + it('does not apply bold class by default', () => { + render(OK) + expect(screen.getByText('OK')).not.toHaveClass('bold') + }) + + it('accepts custom className', () => { + render(Text) + expect(screen.getByText('Text')).toHaveClass('custom') + }) + + it('renders all 5 variant classes correctly', () => { + const variants = ['success', 'warning', 'error', 'running', 'muted'] as const + for (const variant of variants) { + const { unmount } = render( + {variant} + ) + expect(screen.getByText(variant)).toHaveClass(variant) + unmount() + } + }) +}) diff --git a/src/design-system/primitives/StatusText/StatusText.tsx b/src/design-system/primitives/StatusText/StatusText.tsx new file mode 100644 index 0000000..cc2798e --- /dev/null +++ b/src/design-system/primitives/StatusText/StatusText.tsx @@ -0,0 +1,20 @@ +import styles from './StatusText.module.css' +import type { ReactNode } from 'react' + +interface StatusTextProps { + variant: 'success' | 'warning' | 'error' | 'running' | 'muted' + bold?: boolean + children: ReactNode + className?: string +} + +export function StatusText({ variant, bold = false, children, className }: StatusTextProps) { + const classes = [ + styles.statusText, + styles[variant], + bold ? styles.bold : '', + className ?? '', + ].filter(Boolean).join(' ') + + return {children} +} diff --git a/src/design-system/primitives/index.ts b/src/design-system/primitives/index.ts index 23798e3..06cdb0b 100644 --- a/src/design-system/primitives/index.ts +++ b/src/design-system/primitives/index.ts @@ -30,6 +30,7 @@ export { Sparkline } from './Sparkline/Sparkline' export { Spinner } from './Spinner/Spinner' export { StatCard } from './StatCard/StatCard' export { StatusDot } from './StatusDot/StatusDot' +export { StatusText } from './StatusText/StatusText' export { Tag } from './Tag/Tag' export { Textarea } from './Textarea/Textarea' export { TimeRangeDropdown } from './TimeRangeDropdown/TimeRangeDropdown'