50 lines
2.9 KiB
TypeScript
50 lines
2.9 KiB
TypeScript
import React from 'react';
|
|
|
|
interface BaseFieldProps { label?: string; description?: string; error?: string; required?: boolean; children: React.ReactNode; className?: string; }
|
|
export const Field: React.FC<BaseFieldProps> = ({ label, description, error, required, children, className }) => (
|
|
<div className={`space-y-2 ${className || ''}`}>
|
|
{label && (
|
|
<label className="block text-sm font-medium text-[--text-primary] tracking-[-0.14px]">
|
|
{label} {required && <span className="text-[--status-red]">*</span>}
|
|
</label>
|
|
)}
|
|
{children}
|
|
{description && !error && <p className="text-sm text-[--text-secondary] tracking-[-0.14px]">{description}</p>}
|
|
{error && <p className="text-sm text-[--status-red]">{error}</p>}
|
|
</div>
|
|
);
|
|
|
|
export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> { invalid?: boolean; }
|
|
export const Input = React.forwardRef<HTMLInputElement, InputProps>(({ className, invalid, ...rest }, ref) => (
|
|
<input
|
|
ref={ref}
|
|
className={`w-full px-4 py-3.5 rounded-full border text-sm bg-[--input-bg] text-[--text-primary] placeholder:text-[--input-placeholder] focus:outline-none focus:ring-2 focus:ring-[--accent] focus:border-[--accent] border-[--input-border] transition-all duration-200 ${invalid ? 'border-red-500 focus:ring-red-500' : ''} ${className || ''}`}
|
|
{...rest}
|
|
/>
|
|
));
|
|
Input.displayName = 'Input';
|
|
|
|
export interface TextareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> { invalid?: boolean; }
|
|
export const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(({ className, invalid, ...rest }, ref) => (
|
|
<textarea
|
|
ref={ref}
|
|
className={`w-full px-4 py-3.5 rounded-2xl border text-sm resize-vertical bg-[--input-bg] text-[--text-primary] placeholder:text-[--input-placeholder] focus:outline-none focus:ring-2 focus:ring-[--accent] focus:border-[--accent] border-[--input-border] transition-all duration-200 ${invalid ? 'border-red-500 focus:ring-red-500' : ''} ${className || ''}`}
|
|
{...rest}
|
|
/>
|
|
));
|
|
Textarea.displayName = 'Textarea';
|
|
|
|
export interface SelectProps extends React.SelectHTMLAttributes<HTMLSelectElement> { invalid?: boolean; }
|
|
export const Select = React.forwardRef<HTMLSelectElement, SelectProps>(({ className, invalid, children, ...rest }, ref) => (
|
|
<select
|
|
ref={ref}
|
|
className={`w-full px-4 py-3.5 rounded-full border text-sm bg-[--input-bg] text-[--text-primary] focus:outline-none focus:ring-2 focus:ring-[--accent] focus:border-[--accent] border-[--input-border] transition-all duration-200 ${invalid ? 'border-red-500 focus:ring-red-500' : ''} ${className || ''}`}
|
|
{...rest}
|
|
>
|
|
{children}
|
|
</select>
|
|
));
|
|
Select.displayName = 'Select';
|
|
|
|
export default { Field, Input, Textarea, Select };
|