All files / src/components/ui char-count-textarea.tsx

100% Statements 5/5
100% Branches 5/5
100% Functions 2/2
100% Lines 5/5

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                                              69x 69x 69x   69x         1x                                                      
import { cn } from "../../lib/utils";
 
type CharCountTextareaProps = {
	value: string;
	onChange: (value: string) => void;
	maxLength: number;
	rows?: number;
	placeholder?: string;
	id?: string;
	className?: string;
	disabled?: boolean;
};
 
export function CharCountTextarea({
	value,
	onChange,
	maxLength,
	rows = 4,
	placeholder,
	id,
	className,
	disabled,
}: CharCountTextareaProps) {
	const remaining = maxLength - value.length;
	const isNearLimit = remaining <= Math.ceil(maxLength * 0.1);
	const isAtLimit = remaining <= 0;
 
	return (
		<div>
			<textarea
				id={id}
				value={value}
				onChange={(e) => onChange(e.target.value)}
				maxLength={maxLength}
				rows={rows}
				placeholder={placeholder}
				disabled={disabled}
				className={cn(
					"w-full px-3 py-2 text-sm rounded-md border border-border-default bg-background-elevated text-foreground-default focus:ring-2 focus:ring-primary-500 focus:border-transparent resize-none",
					className,
				)}
			/>
			<div className="flex justify-end mt-1">
				<span
					className={cn(
						"text-xs",
						isAtLimit
							? "text-error"
							: isNearLimit
								? "text-warning"
								: "text-foreground-subtle",
					)}
				>
					{value.length}/{maxLength}
				</span>
			</div>
		</div>
	);
}