veza/apps/web/desy/components/ui/input.tsx
2026-01-22 17:23:11 +01:00

93 lines
2.9 KiB
TypeScript

import * as React from 'react'
import { cva, type VariantProps } from 'class-variance-authority'
import { cn } from '@/lib/utils'
const inputVariants = cva(
'flex w-full min-w-0 rounded-md border bg-transparent px-3 py-2 text-base transition-all outline-none file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
{
variants: {
variant: {
default:
'border-input bg-background focus:border-primary focus:ring-2 focus:ring-primary/20',
filled:
'border-transparent bg-muted focus:bg-background focus:border-primary focus:ring-2 focus:ring-primary/20',
ghost:
'border-transparent bg-transparent hover:bg-muted/50 focus:bg-muted focus:border-primary',
terminal:
'border-[oklch(0.72_0.19_145)] bg-black text-[oklch(0.72_0.19_145)] font-mono placeholder:text-[oklch(0.72_0.19_145_/_0.5)] focus:ring-2 focus:ring-[oklch(0.72_0.19_145_/_0.3)] focus:shadow-[0_0_10px_oklch(0.72_0.19_145_/_0.2)]',
error:
'border-destructive bg-destructive/5 focus:border-destructive focus:ring-2 focus:ring-destructive/20',
success:
'border-success bg-success/5 focus:border-success focus:ring-2 focus:ring-success/20',
},
inputSize: {
default: 'h-10',
sm: 'h-8 px-2 text-xs',
lg: 'h-12 px-4 text-base',
},
},
defaultVariants: {
variant: 'default',
inputSize: 'default',
},
},
)
interface InputProps
extends Omit<React.ComponentProps<'input'>, 'size'>,
VariantProps<typeof inputVariants> {
startIcon?: React.ReactNode
endIcon?: React.ReactNode
}
const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ className, type, variant, inputSize, startIcon, endIcon, ...props }, ref) => {
if (startIcon || endIcon) {
return (
<div className="relative flex items-center">
{startIcon && (
<div className="absolute left-3 flex items-center text-muted-foreground [&>svg]:size-4">
{startIcon}
</div>
)}
<input
type={type}
data-slot="input"
className={cn(
inputVariants({ variant, inputSize }),
startIcon && 'pl-10',
endIcon && 'pr-10',
className
)}
ref={ref}
{...props}
/>
{endIcon && (
<div className="absolute right-3 flex items-center text-muted-foreground [&>svg]:size-4">
{endIcon}
</div>
)}
</div>
)
}
return (
<input
type={type}
data-slot="input"
className={cn(inputVariants({ variant, inputSize }), className)}
ref={ref}
{...props}
/>
)
}
)
Input.displayName = 'Input'
export { Input, inputVariants }