scrapeRL / frontend /src /components /ui /Select.tsx
NeerajCodz's picture
feat: implement React dashboard with components and hooks
0cfd364
import React, { forwardRef } from 'react';
import { ChevronDown } from 'lucide-react';
import { classNames } from '@/utils/helpers';
interface SelectOption {
value: string;
label: string;
disabled?: boolean;
}
interface SelectProps extends Omit<React.SelectHTMLAttributes<HTMLSelectElement>, 'children'> {
label?: string;
error?: string;
hint?: string;
options: SelectOption[];
placeholder?: string;
}
export const Select = forwardRef<HTMLSelectElement, SelectProps>(
({ label, error, hint, options, placeholder, className, id, ...props }, ref) => {
const selectId = id || `select-${Math.random().toString(36).slice(2, 9)}`;
return (
<div className="w-full">
{label && (
<label
htmlFor={selectId}
className="block text-sm font-medium text-dark-300 mb-1.5"
>
{label}
</label>
)}
<div className="relative">
<select
ref={ref}
id={selectId}
className={classNames(
'w-full px-3 py-2 pr-10 bg-dark-900 border border-dark-600 rounded-lg',
'text-dark-100 appearance-none cursor-pointer',
'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}
>
{placeholder && (
<option value="" disabled>
{placeholder}
</option>
)}
{options.map((option) => (
<option
key={option.value}
value={option.value}
disabled={option.disabled}
>
{option.label}
</option>
))}
</select>
<div className="absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none text-dark-500">
<ChevronDown className="w-4 h-4" />
</div>
</div>
{(error || hint) && (
<p
className={classNames(
'mt-1.5 text-sm',
error ? 'text-red-400' : 'text-dark-500'
)}
>
{error || hint}
</p>
)}
</div>
);
}
);
Select.displayName = 'Select';
interface ToggleProps {
label?: string;
description?: string;
checked: boolean;
onChange: (checked: boolean) => void;
disabled?: boolean;
}
export const Toggle: React.FC<ToggleProps> = ({
label,
description,
checked,
onChange,
disabled = false,
}) => {
return (
<label
className={classNames(
'flex items-center justify-between gap-4 cursor-pointer',
disabled && 'opacity-50 cursor-not-allowed'
)}
>
<div>
{label && (
<span className="block text-sm font-medium text-dark-200">
{label}
</span>
)}
{description && (
<span className="block text-sm text-dark-500 mt-0.5">
{description}
</span>
)}
</div>
<button
type="button"
role="switch"
aria-checked={checked}
disabled={disabled}
onClick={() => !disabled && onChange(!checked)}
className={classNames(
'relative inline-flex h-6 w-11 items-center rounded-full transition-colors',
'focus:outline-none focus:ring-2 focus:ring-accent-primary/50',
checked ? 'bg-accent-primary' : 'bg-dark-600'
)}
>
<span
className={classNames(
'inline-block h-4 w-4 transform rounded-full bg-white transition-transform',
checked ? 'translate-x-6' : 'translate-x-1'
)}
/>
</button>
</label>
);
};
export default Select;