69 lines
2.3 KiB
TypeScript
69 lines
2.3 KiB
TypeScript
import { forwardRef, type InputHTMLAttributes, type TextareaHTMLAttributes } from "react";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
/* ── Input ── */
|
|
interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
|
|
label?: string;
|
|
error?: string;
|
|
}
|
|
|
|
export const Input = forwardRef<HTMLInputElement, InputProps>(
|
|
({ className, label, error, id, ...props }, ref) => (
|
|
<div className="flex flex-col gap-1.5">
|
|
{label && (
|
|
<label htmlFor={id} className="text-[10px] font-medium uppercase tracking-[0.16em] text-gray-500">
|
|
{label}
|
|
</label>
|
|
)}
|
|
<input
|
|
ref={ref}
|
|
id={id}
|
|
className={cn(
|
|
"w-full px-4 py-3.5 bg-white border border-gray-200 text-[var(--color-moy-dark)] text-sm",
|
|
"focus:outline-none focus:ring-2 focus:ring-[var(--color-moy-gold)]/40 focus:border-[var(--color-moy-gold)]",
|
|
"transition-all duration-200 placeholder:text-gray-300",
|
|
"rounded-none", // sharp corners = editorial feel
|
|
error && "border-red-300 focus:ring-red-200/50",
|
|
className
|
|
)}
|
|
{...props}
|
|
/>
|
|
{error && <span className="text-xs text-red-500">{error}</span>}
|
|
</div>
|
|
)
|
|
);
|
|
Input.displayName = "Input";
|
|
|
|
/* ── Textarea ── */
|
|
interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {
|
|
label?: string;
|
|
error?: string;
|
|
}
|
|
|
|
export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
|
|
({ className, label, error, id, ...props }, ref) => (
|
|
<div className="flex flex-col gap-1.5">
|
|
{label && (
|
|
<label htmlFor={id} className="text-[10px] font-medium uppercase tracking-[0.16em] text-gray-500">
|
|
{label}
|
|
</label>
|
|
)}
|
|
<textarea
|
|
ref={ref}
|
|
id={id}
|
|
className={cn(
|
|
"w-full px-4 py-3.5 bg-white border border-gray-200 text-[var(--color-moy-dark)] text-sm resize-none",
|
|
"focus:outline-none focus:ring-2 focus:ring-[var(--color-moy-gold)]/40 focus:border-[var(--color-moy-gold)]",
|
|
"transition-all duration-200 placeholder:text-gray-300",
|
|
"rounded-none",
|
|
error && "border-red-300 focus:ring-red-200/50",
|
|
className
|
|
)}
|
|
{...props}
|
|
/>
|
|
{error && <span className="text-xs text-red-500">{error}</span>}
|
|
</div>
|
|
)
|
|
);
|
|
Textarea.displayName = "Textarea";
|