learning_ai_common_plat/packages/ui/src/components/Input.tsx
saravanakumardb1 5da71f3735 feat(ui): add Input, Textarea, Card, Label, Select, Separator components to @bytelyst/ui
- Input: with label, error, hint, a11y attributes
- Textarea: resizable with label, error, hint
- Card: with CardHeader, CardTitle, CardDescription sub-components
- Label: with required indicator
- Select: native select with chevron icon, label, error
- Separator: horizontal/vertical with ARIA roles
- All components use --bl-* design token CSS variables
- 12 total components in @bytelyst/ui
2026-03-28 00:33:38 -07:00

55 lines
1.7 KiB
TypeScript

import * as React from 'react';
import { clsx } from 'clsx';
export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
label?: string;
error?: string;
hint?: string;
}
export const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ label, error, hint, className, id, ...props }, ref) => {
const inputId = id ?? (label ? `input-${label.toLowerCase().replace(/\s+/g, '-')}` : undefined);
return (
<div className="space-y-1">
{label && (
<label
htmlFor={inputId}
className="block text-sm font-medium text-[var(--bl-text-secondary,#a0a0b0)]"
>
{label}
</label>
)}
<input
ref={ref}
id={inputId}
className={clsx(
'w-full rounded-md border px-3 py-2 text-sm outline-none transition-colors',
'bg-[var(--bl-surface-card,#1a1a2e)] text-[var(--bl-text-primary,#fff)]',
'placeholder:text-[var(--bl-text-tertiary,#555)]',
'focus:ring-2 focus:ring-[var(--bl-accent,#5A8CFF)] focus:ring-offset-0',
error ? 'border-red-500' : 'border-[var(--bl-border,#2a2a4a)]',
className
)}
aria-invalid={error ? 'true' : undefined}
aria-describedby={error ? `${inputId}-error` : hint ? `${inputId}-hint` : undefined}
{...props}
/>
{error && (
<p id={`${inputId}-error`} className="text-xs text-red-400" role="alert">
{error}
</p>
)}
{hint && !error && (
<p id={`${inputId}-hint`} className="text-xs text-[var(--bl-text-tertiary,#555)]">
{hint}
</p>
)}
</div>
);
}
);
Input.displayName = 'Input';