All files / src/components/ui password-strength.tsx

100% Statements 11/11
100% Branches 12/12
100% Functions 4/4
100% Lines 9/9

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                73x   73x 38x 38x     38x           73x       73x                     73x 73x                                        
import { PASSWORD_RULES } from "../../lib/validation";
import { Check, X } from "lucide-react";
 
interface PasswordStrengthProps {
	password: string;
}
 
export function PasswordStrength({ password }: PasswordStrengthProps) {
	if (!password) return null;
 
	const passed = PASSWORD_RULES.filter((r) => r.test(password)).length;
	const total = PASSWORD_RULES.length;
	const strength = passed / total;
 
	const barColor =
		strength <= 0.4
			? "bg-destructive"
			: strength <= 0.8
				? "bg-yellow-500"
				: "bg-green-500";
 
	return (
		<div className="space-y-2 mt-2">
			<div className="flex gap-1">
				{Array.from({ length: total }).map((_, i) => (
					<div
						// biome-ignore lint/suspicious/noArrayIndexKey: fixed-length strength segments
						key={i}
						className={`h-1 flex-1 rounded-full transition-colors ${
							i < passed ? barColor : "bg-muted"
						}`}
					/>
				))}
			</div>
			<ul className="space-y-0.5">
				{PASSWORD_RULES.map((rule) => {
					const ok = rule.test(password);
					return (
						<li
							key={rule.label}
							className={`flex items-center gap-1.5 text-xs ${
								ok ? "text-green-600" : "text-muted-foreground"
							}`}
						>
							{ok ? (
								<Check className="h-3 w-3 shrink-0" />
							) : (
								<X className="h-3 w-3 shrink-0" />
							)}
							{rule.label}
						</li>
					);
				})}
			</ul>
		</div>
	);
}