All files / packages/components/src input.web.tsx

92.3% Statements 12/13
100% Branches 6/6
83.33% Functions 5/6
92.3% Lines 12/13

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116                              292x 21518x                                                                                     8942x                       10786x 10786x   10x 9x         10786x       10786x             10786x 10786x           12x                                  
import React from "react";
 
import { Input as InputRaw, Textarea } from "@heroui/input";
 
import { cn } from "~components/utils";
import type { ViewReactNode } from "~components/view";
 
import { useMutationErrors, usePasswordVisibility } from "./input.base";
import type { FieldError, MutationsProp } from "./utils";
 
export type InputHandler = {
	focus: () => void;
	blur: () => void;
};
 
export const InputWrapper: React.FC<React.ComponentProps<"div">> = (props) => (
	<div {...props} data-testid="input-wrapper" />
);
 
export type Props = Pick<
	React.ComponentProps<typeof InputRaw>,
	| "value"
	| "onValueChange"
	| "className"
	| "placeholder"
	| "color"
	| "isDisabled"
	| "isReadOnly"
	| "isRequired"
	| "defaultValue"
	| "isClearable"
	| "name"
	| "size"
	| "autoFocus"
	| "aria-label"
> & {
	autoCapitalize?: "none" | "sentences" | "words" | "characters";
	onBlur?: () => void;
	onFocus?: () => void;
	onPress?: () => void;
	onKeyPress?: (key: string) => void;
	errorMessage?: string;
	ref?: React.RefObject<InputHandler>;
	label?: string;
	description?: string;
	startContent?: ViewReactNode;
	endContent?: ViewReactNode;
	fieldError?: FieldError;
	mutation?: MutationsProp;
	multiline?: boolean;
	type?: React.ComponentProps<"input">["type"];
	autoComplete?: "email" | "name" | "new-password" | "username";
	continuousMutations?: boolean;
	labelPlacement?: "outside" | "inside" | "outside-left";
	variant?: "flat" | "bordered";
	inputClassName?: string;
	testID?: string;
};
 
export const Input: React.FC<Props> = ({
	fieldError,
	mutation,
	multiline,
	ref,
	onPress,
	onKeyPress,
	continuousMutations,
	inputClassName,
	testID,
	...props
}) => {
	const innerRef = React.useRef<HTMLInputElement | HTMLTextAreaElement>(null);
	React.useImperativeHandle(
		ref,
		() => ({
			focus: () => innerRef.current?.focus(),
			blur: () => innerRef.current?.blur(),
		}),
		[],
	);
	const { endContent, type } = usePasswordVisibility({
		type: props.type,
		endContent: props.endContent,
	});
	const { isDisabled, color, description } = useMutationErrors({
		isDisabled: props.isDisabled,
		color: props.color,
		mutation,
		fieldError,
		continuousMutations,
	});
	const Component = (multiline ? Textarea : InputRaw) as typeof InputRaw;
	return (
		<Component
			as={InputWrapper}
			ref={innerRef as React.RefObject<HTMLInputElement | null>}
			{...props}
			onClick={onPress}
			onKeyDown={(e) => onKeyPress?.(e.key)}
			isDisabled={isDisabled}
			color={color}
			description={description}
			classNames={{
				description: cn(
					"whitespace-pre",
					color === "warning" ? "text-warning" : undefined,
				),
				input: inputClassName,
			}}
			type={type ?? "text"}
			endContent={endContent}
			data-testid={testID}
		/>
	);
};