input.tsx
1 import * as React from "react"; 2 3 import { VariantProps, cva } from "class-variance-authority"; 4 import { cn, focusRing } from "../Wallet/lib/utils"; 5 import { Box } from "./box"; 6 import { Icon } from "./icon"; 7 8 const inputVariants = cva( 9 "ml-1px flex h-9 w-full px-2 py-1 shadow text-foreground hover:border-foreground text-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1", 10 { 11 compoundVariants: [ 12 { 13 isIcon: true, 14 size: "xs", 15 className: "pl-6", 16 }, 17 { 18 isIcon: true, 19 size: "sm", 20 className: "pl-7", 21 }, 22 { 23 isIcon: true, 24 size: "md", 25 className: "pl-8", 26 }, 27 { 28 isIcon: true, 29 size: "lg", 30 className: "pl-9", 31 }, 32 { 33 isIcon: true, 34 size: "xl", 35 className: "pl-10", 36 }, 37 { 38 variant: ["outline", "default"], 39 size: "xl", 40 className: "border-3", 41 }, 42 ], 43 variants: { 44 color: { 45 primary: "bg-primary/10 border-primary hover:bg-primary/25", 46 secondary: "bg-secondary/10 border-secondary hover:bg-secondary/25", 47 error: "bg-error/10 border-error hover:bg-error/25", 48 success: "bg-success/10 border-success hover:bg-success/25", 49 warning: "bg-warning/10 border-warning hover:bg-warning/25", 50 info: "bg-info/10 border-info hover:bg-info/25", 51 muted: "bg-gray-400/10 border-gray-500 hover:bg-gray-400/25", 52 }, 53 variant: { 54 default: "border-2", 55 filled: "", 56 outline: "border-2 bg-transparent", 57 ghost: "bg-transparent hover:text-foreground hover:border-foreground", 58 }, 59 size: { 60 xs: "h-5 text-xs", 61 sm: "h-6 text-sm", 62 md: "h-8 px-3 text-base", 63 lg: "h-10 px-4 text-lg", 64 xl: "h-12 px-4 text-xl", 65 }, 66 round: { 67 none: "rounded-none", 68 both: "rounded-full", 69 left: "rounded-l-full", 70 right: "rounded-r-full", 71 top: "rounded-t-sm", 72 bottom: "rounded-b-sm", 73 topLeft: "rounded-tl-sm", 74 topRight: "rounded-tr-sm", 75 bottomLeft: "rounded-bl-sm", 76 bottomRight: "rounded-br-sm", 77 }, 78 isIcon: { 79 true: "pr-0", 80 }, 81 }, 82 defaultVariants: { 83 variant: "outline", 84 color: "muted", 85 round: "both", 86 size: "md", 87 }, 88 }, 89 ); 90 91 export interface InputProps 92 extends Omit< 93 React.InputHTMLAttributes<HTMLInputElement>, 94 "size" | "color" | "height" 95 >, 96 VariantProps<typeof inputVariants> { 97 height?: string; 98 children?: React.ReactNode; 99 icon?: React.ReactNode; 100 noShadow?: boolean; 101 asChild?: boolean; 102 iconSize?: "xs" | "sm" | "md" | "lg" | "xl" | null; 103 } 104 105 const Input = React.forwardRef<HTMLInputElement, InputProps>( 106 ( 107 { 108 children, 109 color, 110 variant, 111 icon, 112 iconSize, 113 height, 114 className, 115 noShadow, 116 round, 117 size, 118 type, 119 ...props 120 }, 121 ref, 122 ) => { 123 const isIcon = !!icon; 124 const inputRef = React.useRef<HTMLInputElement>(null); 125 126 function refHandler(instance: HTMLInputElement) { 127 if (ref) { 128 if (typeof ref === "function") { 129 ref(instance); 130 } else { 131 ref.current = instance; 132 } 133 } 134 // @ts-ignore 135 inputRef.current = instance; 136 } 137 138 return ( 139 <Box className={cn("relative", className)} color={color} hoverable> 140 {isIcon && ( 141 <Icon 142 className="absolute left-0" 143 size={iconSize || size} 144 onClick={() => { 145 inputRef.current && inputRef.current.focus(); 146 }} 147 > 148 {icon} 149 </Icon> 150 )} 151 <input 152 type={type} 153 className={cn( 154 focusRing, 155 inputVariants({ round, variant, size, color, isIcon }), 156 height, 157 `rounded-${round}-${size}`, 158 noShadow && "shadow-none", 159 )} 160 ref={refHandler} 161 {...props} 162 /> 163 {children} 164 </Box> 165 ); 166 }, 167 ); 168 Input.displayName = "Input"; 169 170 export { Input };