/ src / components / ui / input.tsx
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 };