eeff292
import type { Icon } from '@tabler/icons-react'
import { forwardRef, type InputHTMLAttributes, type ReactNode, useId } from 'react'
export interface TextFieldProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'className'> {
label: string
icon?: Icon
/** Right-side element in the label row (link, badge, timer, ...). */
aside?: ReactNode
/** Trailing interactive element inside the input box (reveal toggle, ...). */
trailing?: ReactNode
error?: string
}
/** Labelled input row matching the auth design: 10px mono label, 46px field. */
export const TextField = forwardRef<HTMLInputElement, TextFieldProps>(function TextField(
{ label, icon: Icon, aside, trailing, error, id, ...props },
ref,
) {
const autoId = useId()
const inputId = id ?? autoId
return (
<div className="flex w-full flex-col gap-[7px]">
<div className="flex w-full items-center justify-between">
<label
htmlFor={inputId}
className="font-mono text-[10px] font-bold tracking-[1.2px] text-muted-foreground uppercase"
>
{label}
</label>
{aside}
</div>
<div
className={`flex h-[46px] w-full items-center gap-2.5 rounded-field border bg-card px-3.5 transition-colors focus-within:border-foreground ${
error ? 'border-destructive' : 'border-input'
}`}
>
{Icon && <Icon size={15} className="shrink-0 text-muted-foreground" aria-hidden />}
<input
ref={ref}
id={inputId}
className="h-full w-full min-w-0 flex-1 bg-transparent text-[14.5px] text-foreground outline-none placeholder:text-muted-foreground/60"
{...props}
/>
{trailing}
</div>
{error && (
<p role="alert" className="font-sans text-xs text-error-foreground">
{error}
</p>
)}
</div>
)
})