component StrongPassword { outputs { input(payload: { value: string; score: number; maximumScore: number; percent: number; level: string }) change(payload: { value: string; score: number; maximumScore: number; percent: number; level: string }) strength(payload: { value: string; score: number; maximumScore: number; percent: number; level: string }) } props { size: string = "default" color: string = "primary" label: string = "Password" name: string = "password" value: string = "" placeholder: string = "Create a strong password" autocomplete: string = "new-password" minLength: number = 8 specialCharactersSet: string = "!@#$%^&*()_+-=[]{}|;:,.<>?" requireLowercase: boolean = true requireUppercase: boolean = true requireNumber: boolean = true requireSpecialCharacter: boolean = true showRequirements: boolean = true presentation: string = "inline" hintText: string = "Use a unique password you do not use elsewhere." emptyLabel: string = "Enter a password" weakLabel: string = "Weak" fairLabel: string = "Fair" goodLabel: string = "Good" strongLabel: string = "Strong" disabled: boolean = false readonly: boolean = false required: boolean = false invalid: boolean = false validationMessage: string = "" class: string = "" } state password = value state detailsOpen: boolean = false functions { shared function hasMinimumLength() { return password.length >= Number(minLength) } shared function hasLowercase() { return password !== password.toUpperCase() } shared function hasUppercase() { return password !== password.toLowerCase() } shared function hasNumber() { return containsCharacterAt("0123456789", 0) } shared function hasSpecialCharacter() { return containsCharacterAt(specialCharactersSet, 0) } shared function containsCharacterAt(characters, index) { if (index >= characters.length) { return false } if (password.includes(characters[index])) { return true } return containsCharacterAt(characters, index + 1) } shared function score() { return (hasMinimumLength() ? 1 : 0) + (requireLowercase && hasLowercase() ? 1 : 0) + (requireUppercase && hasUppercase() ? 1 : 0) + (requireNumber && hasNumber() ? 1 : 0) + (requireSpecialCharacter && hasSpecialCharacter() ? 1 : 0) } shared function maximumScore() { return 1 + (requireLowercase ? 1 : 0) + (requireUppercase ? 1 : 0) + (requireNumber ? 1 : 0) + (requireSpecialCharacter ? 1 : 0) } shared function strengthPercent() { return Math.round(score() / maximumScore() * 100) } shared function strengthLevel() { if (!password) { return "empty" } if (strengthPercent() <= 25) { return "weak" } if (strengthPercent() <= 50) { return "fair" } if (strengthPercent() < 100) { return "good" } return "strong" } shared function strengthLabel() { if (strengthLevel() === "weak") { return weakLabel } if (strengthLevel() === "fair") { return fairLabel } if (strengthLevel() === "good") { return goodLabel } if (strengthLevel() === "strong") { return strongLabel } return emptyLabel } } view {
{#if presentation === "popover"}
Password strength {password ? strengthLabel() : emptyLabel}
{#if showRequirements}
  • At least {minLength} characters
  • {#if requireLowercase}
  • One lowercase letter
  • {/if} {#if requireUppercase}
  • One uppercase letter
  • {/if} {#if requireNumber}
  • One number
  • {/if} {#if requireSpecialCharacter}
  • One special character: {specialCharactersSet}
  • {/if}
{/if} {#if hintText}{hintText}{/if}
{/if}
{#if presentation !== "popover"}
Password strength {password ? strengthLabel() : emptyLabel}
{#if showRequirements} {/if} {#if hintText}{hintText}{/if}
{/if} {validationMessage}
} }