Implemented 8 production-ready form components with full accessibility: Components Added: - Textarea: Multi-line text input with character counter - Checkbox: Custom styled with indeterminate state support - Radio & RadioGroup: Context-based radio button groups - Switch: Toggle with animated thumb and loading state - Select: Native select with custom styling and option groups - Slider: Range input with marks, value display, cross-browser support - FormField: Wrapper component with label, error, and helper text Features: - Full accessibility (ARIA attributes, semantic HTML) - Controlled/uncontrolled patterns via useControlled hook - Dark mode support with semantic tokens - Design tokens and shared variant system - Comprehensive test coverage (856 tests passing) - Form-specific design tokens (formTokens) - Shared form variant base classes (formVariants) Playground Updates: - Added comprehensive Forms section showcasing all components - Interactive examples with state management - Complete form composition example - All components fully functional and themed Test Coverage: - 10+ describe blocks per component - All edge cases covered - Accessibility testing - Cross-browser compatibility 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
77 lines
1.6 KiB
TypeScript
77 lines
1.6 KiB
TypeScript
import { createVariants } from '../system/variants';
|
|
|
|
/**
|
|
* Textarea variant definitions
|
|
* Uses custom variant system for type-safe class composition
|
|
*/
|
|
export const textareaVariants = createVariants({
|
|
base: [
|
|
// Layout
|
|
'flex w-full',
|
|
// Typography
|
|
'font-sans',
|
|
// Borders & Radius
|
|
'rounded-md border',
|
|
// Background
|
|
'bg-background',
|
|
// Transitions
|
|
'transition-base',
|
|
// Focus
|
|
'focus-ring',
|
|
// Placeholder
|
|
'placeholder:text-foreground-tertiary',
|
|
// Disabled state
|
|
'disabled:cursor-not-allowed disabled:opacity-50',
|
|
].join(' '),
|
|
|
|
variants: {
|
|
state: {
|
|
default: [
|
|
'border-border text-foreground',
|
|
'hover:border-border-strong',
|
|
'focus:border-primary',
|
|
].join(' '),
|
|
|
|
error: [
|
|
'border-error text-foreground',
|
|
'hover:border-error',
|
|
'focus:border-error',
|
|
'focus:ring-error/20',
|
|
].join(' '),
|
|
|
|
success: [
|
|
'border-success text-foreground',
|
|
'hover:border-success',
|
|
'focus:border-success',
|
|
'focus:ring-success/20',
|
|
].join(' '),
|
|
},
|
|
|
|
size: {
|
|
sm: 'min-h-20 px-3 py-2 text-sm',
|
|
md: 'min-h-32 px-3 py-2.5 text-base',
|
|
lg: 'min-h-40 px-4 py-3 text-lg',
|
|
},
|
|
|
|
fullWidth: {
|
|
true: 'w-full',
|
|
false: 'w-auto',
|
|
},
|
|
|
|
resize: {
|
|
none: 'resize-none',
|
|
vertical: 'resize-y',
|
|
horizontal: 'resize-x',
|
|
both: 'resize',
|
|
},
|
|
},
|
|
|
|
compoundVariants: [],
|
|
|
|
defaultVariants: {
|
|
state: 'default',
|
|
size: 'md',
|
|
fullWidth: 'true',
|
|
resize: 'vertical',
|
|
},
|
|
});
|