feat: add Label primitive
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
11
src/design-system/primitives/Label/Label.module.css
Normal file
11
src/design-system/primitives/Label/Label.module.css
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
.label {
|
||||||
|
font-family: var(--font-body);
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.asterisk {
|
||||||
|
color: var(--error);
|
||||||
|
margin-left: 2px;
|
||||||
|
}
|
||||||
34
src/design-system/primitives/Label/Label.test.tsx
Normal file
34
src/design-system/primitives/Label/Label.test.tsx
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import { describe, it, expect } from 'vitest'
|
||||||
|
import { render, screen } from '@testing-library/react'
|
||||||
|
import { Label } from './Label'
|
||||||
|
|
||||||
|
describe('Label', () => {
|
||||||
|
it('renders label text', () => {
|
||||||
|
render(<Label>Email address</Label>)
|
||||||
|
expect(screen.getByText('Email address')).toBeInTheDocument()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('does not show asterisk when required is not set', () => {
|
||||||
|
render(<Label>Username</Label>)
|
||||||
|
expect(screen.queryByText('*')).not.toBeInTheDocument()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shows asterisk when required', () => {
|
||||||
|
render(<Label required>Password</Label>)
|
||||||
|
expect(screen.getByText('*')).toBeInTheDocument()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('passes htmlFor to the label element', () => {
|
||||||
|
render(<Label htmlFor="email-input">Email</Label>)
|
||||||
|
const label = screen.getByText('Email')
|
||||||
|
expect(label).toHaveAttribute('for', 'email-input')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('forwards ref to the label element', () => {
|
||||||
|
let ref: HTMLLabelElement | null = null
|
||||||
|
render(
|
||||||
|
<Label ref={(el) => { ref = el }}>Ref test</Label>
|
||||||
|
)
|
||||||
|
expect(ref).toBeInstanceOf(HTMLLabelElement)
|
||||||
|
})
|
||||||
|
})
|
||||||
20
src/design-system/primitives/Label/Label.tsx
Normal file
20
src/design-system/primitives/Label/Label.tsx
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import styles from './Label.module.css'
|
||||||
|
import { forwardRef, type LabelHTMLAttributes, type ReactNode } from 'react'
|
||||||
|
|
||||||
|
interface LabelProps extends LabelHTMLAttributes<HTMLLabelElement> {
|
||||||
|
required?: boolean
|
||||||
|
children?: ReactNode
|
||||||
|
className?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Label = forwardRef<HTMLLabelElement, LabelProps>(
|
||||||
|
({ required, children, className, ...rest }, ref) => {
|
||||||
|
return (
|
||||||
|
<label ref={ref} className={`${styles.label} ${className ?? ''}`} {...rest}>
|
||||||
|
{children}
|
||||||
|
{required && <span className={styles.asterisk}>*</span>}
|
||||||
|
</label>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
Label.displayName = 'Label'
|
||||||
Reference in New Issue
Block a user