import React from "react";
import FP from "../fp";
import type { InputProps } from "./form.types";
import { useDisabledState } from "../../hooks/use-disabled-state";
import { resolveDisabledState } from "../../utils/accessibility";
export type { InputProps } from "./form.types";
/**
* Input component - Accessible text input with validation support
*
* A flexible input component that supports various input types, validation states,
* and proper ARIA attributes for accessibility. Integrates seamlessly with the
* Field component for complete form control composition.
*
* @component
* @example
* // Basic text input
*
*
* @example
* // Input with error state
*
*
* @example
* // Controlled input with validation
* setPassword(e.target.value)}
* minLength={8}
* required
* />
*
* @param {InputProps} props - Component props
* @returns {JSX.Element} Input element with proper accessibility attributes
*
* @see {@link https://www.w3.org/WAI/WCAG21/Understanding/error-identification.html|WCAG 3.3.1 Error Identification}
* @see {@link https://www.w3.org/WAI/WCAG21/Understanding/name-role-value.html|WCAG 4.1.2 Name, Role, Value}
*/
export const Input = React.forwardRef(
(
{
type = "text",
name,
value,
defaultValue,
placeholder,
id,
styles,
classes,
isDisabled, // Legacy support
disabled,
readOnly,
required = false,
validationState = "none",
errorMessage,
hintText,
onChange,
onBlur,
onFocus,
onKeyDown,
onEnter,
maxLength,
minLength,
pattern,
autoComplete,
autoFocus = false,
inputMode,
...props
},
ref
) => {
// Support both `disabled` and `isDisabled` props (legacy compatibility)
const isInputDisabled = resolveDisabledState(disabled, isDisabled);
// Use the disabled state hook with enhanced API for automatic className merging
const { disabledProps, handlers } = useDisabledState(
isInputDisabled,
{
handlers: {
onChange,
onBlur,
onKeyDown: (e: React.KeyboardEvent) => {
// Handle Enter key press for accessibility
if (e.key === "Enter" && onEnter) {
onEnter(e);
}
// Always call consumer's onKeyDown if provided
if (onKeyDown) {
onKeyDown(e);
}
},
// Note: onFocus is NOT wrapped to allow focus on disabled inputs
// This is handled automatically by useDisabledState
},
// Automatic className merging - hook combines disabled class with user classes
className: classes,
}
);
// Determine aria-invalid based on validation state
const isInvalid = validationState === "invalid";
// Generate describedby IDs for error and hint text
const describedByIds: string[] = [];
if (errorMessage && id) {
describedByIds.push(`${id}-error`);
}
if (hintText && id) {
describedByIds.push(`${id}-hint`);
}
const ariaDescribedBy =
describedByIds.length > 0 ? describedByIds.join(" ") : undefined;
// Generate accessible placeholder if not provided
const accessiblePlaceholder =
placeholder || (required ? `* ${type} input` : `${type} input`);
return (
);
}
);
Input.displayName = "Input";
export default Input;