72 lines
1.9 KiB
TypeScript
72 lines
1.9 KiB
TypeScript
import { cn } from "~/lib/utils"
|
|
import { forwardRef } from "react"
|
|
import { FieldLabel } from "./FieldLabel"
|
|
|
|
type InputProps<TMultiline extends boolean> = {
|
|
label?: string
|
|
addon?: string
|
|
prefix?: string
|
|
isBlock?: boolean
|
|
error?: string
|
|
help?: React.ReactNode
|
|
multiline?: TMultiline
|
|
} & React.ComponentPropsWithRef<TMultiline extends true ? "textarea" : "input">
|
|
|
|
export const Input = forwardRef(function Input<
|
|
TMultiline extends boolean = false,
|
|
>(
|
|
{
|
|
label,
|
|
addon,
|
|
prefix,
|
|
className,
|
|
isBlock,
|
|
error,
|
|
help,
|
|
multiline,
|
|
...inputProps
|
|
}: InputProps<TMultiline>,
|
|
ref: TMultiline extends true
|
|
? React.ForwardedRef<HTMLTextAreaElement>
|
|
: React.ForwardedRef<HTMLInputElement>,
|
|
) {
|
|
const hasAddon = !!addon
|
|
const hasPrefix = !!prefix
|
|
const Component = (multiline ? "textarea" : "input") as any
|
|
|
|
return (
|
|
<div>
|
|
{label && <FieldLabel label={label} id={inputProps.id} />}
|
|
<div className="flex items-center">
|
|
{prefix && (
|
|
<span className="flex items-center px-3 text-gray-600 bg-gray-50 h-10 border border-r-0 rounded-l-lg relative -z-10">
|
|
{prefix}
|
|
</span>
|
|
)}
|
|
<Component
|
|
{...inputProps}
|
|
ref={ref as any}
|
|
className={cn(
|
|
"input",
|
|
hasAddon && `has-addon`,
|
|
hasPrefix && `has-prefix`,
|
|
isBlock && `is-block`,
|
|
className,
|
|
)}
|
|
/>
|
|
{addon && (
|
|
<span className="flex items-center px-3 text-gray-600 bg-gray-50 h-10 border border-l-0 rounded-r-lg relative -z-10">
|
|
{addon}
|
|
</span>
|
|
)}
|
|
</div>
|
|
{error && <div className="text-sm mt-1 text-red-500">{error}</div>}
|
|
{help && !error && (
|
|
<div className="text-xs text-gray-400 mt-1">{help}</div>
|
|
)}
|
|
</div>
|
|
)
|
|
}) as <TMultiline extends boolean = false>(
|
|
props: InputProps<TMultiline>,
|
|
) => JSX.Element
|