veza/apps/web/src/components/ui/FormField.tsx
2025-12-03 22:56:50 +01:00

119 lines
3 KiB
TypeScript

import React from 'react';
import { cn } from '@/lib/utils';
interface FormFieldProps {
label: string;
error?: string;
required?: boolean;
children: React.ReactNode;
className?: string;
helpText?: string;
}
export const FormField: React.FC<FormFieldProps> = ({
label,
error,
required = false,
children,
className,
helpText,
}) => {
return (
<div className={cn('space-y-2', className)}>
<label className="text-sm font-medium text-gray-700 dark:text-gray-300">
{label}
{required && <span className="text-red-500 ml-1">*</span>}
</label>
{children}
{helpText && !error && (
<p className="text-xs text-gray-500 dark:text-gray-400">{helpText}</p>
)}
{error && (
<p className="text-xs text-red-500 dark:text-red-400">{error}</p>
)}
</div>
);
};
interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
error?: boolean;
}
export const Input: React.FC<InputProps> = ({
error = false,
className,
...props
}) => {
return (
<input
className={cn(
'w-full px-3 py-2 border rounded-md shadow-sm transition-colors',
'focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent',
'dark:bg-gray-800 dark:border-gray-600 dark:text-white',
error
? 'border-red-500 focus:ring-red-500'
: 'border-gray-300 dark:border-gray-600',
className
)}
{...props}
/>
);
};
interface TextareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
error?: boolean;
}
export const Textarea: React.FC<TextareaProps> = ({
error = false,
className,
...props
}) => {
return (
<textarea
className={cn(
'w-full px-3 py-2 border rounded-md shadow-sm transition-colors resize-none',
'focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent',
'dark:bg-gray-800 dark:border-gray-600 dark:text-white',
error
? 'border-red-500 focus:ring-red-500'
: 'border-gray-300 dark:border-gray-600',
className
)}
{...props}
/>
);
};
interface SelectProps extends React.SelectHTMLAttributes<HTMLSelectElement> {
error?: boolean;
options: Array<{ value: string; label: string }>;
}
export const Select: React.FC<SelectProps> = ({
error = false,
className,
options,
...props
}) => {
return (
<select
className={cn(
'w-full px-3 py-2 border rounded-md shadow-sm transition-colors',
'focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent',
'dark:bg-gray-800 dark:border-gray-600 dark:text-white',
error
? 'border-red-500 focus:ring-red-500'
: 'border-gray-300 dark:border-gray-600',
className
)}
{...props}
>
{options.map((option) => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</select>
);
};