scrapeRL / frontend /src /components /ui /Input.tsx
NeerajCodz's picture
feat: implement React dashboard with components and hooks
0cfd364
import React, { forwardRef } from 'react';
import { classNames } from '@/utils/helpers';
interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
label?: string;
error?: string;
hint?: string;
leftIcon?: React.ReactNode;
rightIcon?: React.ReactNode;
variant?: 'default' | 'filled';
}
export const Input = forwardRef<HTMLInputElement, InputProps>(
(
{
label,
error,
hint,
leftIcon,
rightIcon,
variant = 'default',
className,
id,
...props
},
ref
) => {
const inputId = id || `input-${Math.random().toString(36).slice(2, 9)}`;
const variantStyles = {
default: 'bg-dark-900 border-dark-600',
filled: 'bg-dark-700 border-transparent',
};
return (
<div className="w-full">
{label && (
<label
htmlFor={inputId}
className="block text-sm font-medium text-dark-300 mb-1.5"
>
{label}
</label>
)}
<div className="relative">
{leftIcon && (
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none text-dark-500">
{leftIcon}
</div>
)}
<input
ref={ref}
id={inputId}
className={classNames(
'w-full px-3 py-2 border rounded-lg text-dark-100 placeholder-dark-500',
'focus:outline-none focus:border-accent-primary focus:ring-1 focus:ring-accent-primary/50',
'transition-colors duration-200',
variantStyles[variant],
leftIcon ? 'pl-10' : '',
rightIcon ? 'pr-10' : '',
error ? 'border-red-500 focus:border-red-500 focus:ring-red-500/50' : '',
className
)}
{...props}
/>
{rightIcon && (
<div className="absolute inset-y-0 right-0 pr-3 flex items-center text-dark-500">
{rightIcon}
</div>
)}
</div>
{(error || hint) && (
<p
className={classNames(
'mt-1.5 text-sm',
error ? 'text-red-400' : 'text-dark-500'
)}
>
{error || hint}
</p>
)}
</div>
);
}
);
Input.displayName = 'Input';
interface TextareaProps
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
label?: string;
error?: string;
hint?: string;
}
export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
({ label, error, hint, className, id, ...props }, ref) => {
const inputId = id || `textarea-${Math.random().toString(36).slice(2, 9)}`;
return (
<div className="w-full">
{label && (
<label
htmlFor={inputId}
className="block text-sm font-medium text-dark-300 mb-1.5"
>
{label}
</label>
)}
<textarea
ref={ref}
id={inputId}
className={classNames(
'w-full px-3 py-2 bg-dark-900 border border-dark-600 rounded-lg',
'text-dark-100 placeholder-dark-500 resize-none',
'focus:outline-none focus:border-accent-primary focus:ring-1 focus:ring-accent-primary/50',
'transition-colors duration-200',
error && 'border-red-500 focus:border-red-500 focus:ring-red-500/50',
className
)}
{...props}
/>
{(error || hint) && (
<p
className={classNames(
'mt-1.5 text-sm',
error ? 'text-red-400' : 'text-dark-500'
)}
>
{error || hint}
</p>
)}
</div>
);
}
);
Textarea.displayName = 'Textarea';
export default Input;