'use client' import * as React from 'react' import { Input as BaseInput } from '@base-ui/react/input' import { type VariantProps } from 'class-variance-authority' import { cn, useComposedRefs } from '../../internal/utils' import { inputVariants } from './input-variants' type InputVariant = NonNullable['variant']> type InputSize = NonNullable['size']> interface InputProps extends Omit, 'size'> { /** * Field appearance - bordered or filled. * @default 'outline' */ variant?: InputVariant /** * Scales height, padding, and text. Named `inputSize` to avoid the native `size` attribute. * @default 'md' */ inputSize?: InputSize /** * Show a clear (✕) button once the field has a value. * @default false */ clearable?: boolean /** Adornment rendered before the field, inside the frame. */ startSlot?: React.ReactNode /** Adornment rendered after the field, inside the frame. */ endSlot?: React.ReactNode /** Called when the clear button is pressed. */ onClear?: () => void /** * Props for the inner `` (its own `className`, handlers, the native `size` * attribute, …). `size` here is the character count the control is intrinsically wide, * not the scale - that is `inputSize`. */ inputProps?: React.ComponentProps } function setNativeValue(input: HTMLInputElement, value: string) { const setter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value')?.set setter?.call(input, value) input.dispatchEvent(new Event('input', { bubbles: true })) } function Input({ className, variant = 'outline', inputSize = 'md', clearable, startSlot, endSlot, onClear, inputProps, ref, ...props }: InputProps) { const innerRef = React.useRef(null) const hasWrapper = Boolean(clearable || startSlot || endSlot) const ariaInvalid = props['aria-invalid'] const invalid = ariaInvalid === true || ariaInvalid === 'true' const composedRef = useComposedRefs(ref, innerRef) const handleClear = () => { if (innerRef.current && props.value === undefined) { setNativeValue(innerRef.current, '') } innerRef.current?.focus() onClear?.() } if (!hasWrapper) { return ( ) } return (
{startSlot && (
{startSlot}
)} {clearable && ( )} {endSlot && (
{endSlot}
)}
) } export { Input } export type { InputProps }