93 lines
2.9 KiB
TypeScript
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 }
|