@wise-community/angular-password-strength-meter
Version:
[](https://github.com/antoantonyk/password-strength-meter/actions/workflows/ci-workflow.yml) [ • 13.1 kB
JavaScript
import * as i0 from '@angular/core';
import { Directive, Input, HostBinding, EventEmitter, inject, booleanAttribute, Component, Output } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { Subject, distinctUntilChanged, debounceTime, switchMap, of } from 'rxjs';
class IPasswordStrengthMeterService {
}
/* eslint-disable @angular-eslint/directive-selector */
class PSMProgressBarDirective {
constructor(renderer, el) {
this.renderer = renderer;
this.el = el;
this.colors = [];
this.minProgressVal = 0;
this.maxProgressVal = 100;
this.currentProgressVal = 0;
this.dataPasswordStrength = 0;
this.defaultColors = [
'darkred',
'orangered',
'orange',
'yellowgreen',
'green',
];
this.progressBar = this.el.nativeElement;
}
ngOnChanges(changes) {
if (changes['numberOfProgressBarItems']) {
this.setProgressBarItems();
}
this.setProgressBar();
}
setProgressBarItems() {
const progressBarItemContainer = this.progressBar.querySelector('.psm__progress-bar-items');
const width = 100 / this.numberOfProgressBarItems;
progressBarItemContainer?.childNodes.forEach((item) => {
this.renderer.removeChild(progressBarItemContainer, item);
});
Array(this.numberOfProgressBarItems)
.fill(1)
.forEach(() => {
const progressBarItem = this.renderer.createElement('div');
this.renderer.addClass(progressBarItem, 'psm__progress-bar-item');
this.renderer.setStyle(progressBarItem, 'width', `${width}%`);
this.renderer.appendChild(progressBarItemContainer, progressBarItem);
});
}
setProgressBar() {
const progressBarOverlayWidth = this.getFillMeterWidth(this.passwordStrength);
const progressBarOverlayWidthInPx = `${progressBarOverlayWidth}%`;
const progressLevelBasedOnItems = (progressBarOverlayWidth / 100) * this.numberOfProgressBarItems;
const progressBarOverlayColor = this.getMeterFillColor(progressLevelBasedOnItems);
this.dataPasswordStrength = this.passwordStrength || 0;
this.currentProgressVal = progressBarOverlayWidth;
const overlayElement = this.progressBar.querySelector('.psm__progress-bar-overlay');
if (overlayElement) {
this.renderer.setStyle(overlayElement, 'width', progressBarOverlayWidthInPx);
this.renderer.setStyle(overlayElement, 'background-color', progressBarOverlayColor);
}
}
getFillMeterWidth(strength) {
if (strength === null || strength === undefined) {
return 0;
}
const strengthInPercentage = strength !== null ? ((strength + 1) / 5) * 100 : 0;
const roundedStrengthInPercentage = this.getRoundedStrength(strengthInPercentage, 100 / this.numberOfProgressBarItems);
return roundedStrengthInPercentage;
}
getMeterFillColor(progressLevel) {
if (!progressLevel ||
progressLevel <= 0 ||
(progressLevel > this.colors.length &&
progressLevel > this.defaultColors.length)) {
return this.colors[0] ? this.colors[0] : this.defaultColors[0];
}
const index = progressLevel - 1;
return this.colors[index] ? this.colors[index] : this.defaultColors[index];
}
getRoundedStrength(strength, roundTo) {
return Math.round(strength / roundTo) * roundTo;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.4", ngImport: i0, type: PSMProgressBarDirective, deps: [{ token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.1.4", type: PSMProgressBarDirective, isStandalone: true, selector: ".psm__progress-bar", inputs: { numberOfProgressBarItems: "numberOfProgressBarItems", passwordStrength: "passwordStrength", colors: "colors" }, host: { properties: { "attr.aria-valuemin": "this.minProgressVal", "attr.aria-valuemax": "this.maxProgressVal", "attr.aria-valuenow": "this.currentProgressVal", "attr.data-strength": "this.dataPasswordStrength" } }, usesOnChanges: true, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.4", ngImport: i0, type: PSMProgressBarDirective, decorators: [{
type: Directive,
args: [{
standalone: true,
selector: '.psm__progress-bar',
}]
}], ctorParameters: () => [{ type: i0.Renderer2 }, { type: i0.ElementRef }], propDecorators: { numberOfProgressBarItems: [{
type: Input,
args: [{ required: true }]
}], passwordStrength: [{
type: Input,
args: [{ required: true }]
}], colors: [{
type: Input
}], minProgressVal: [{
type: HostBinding,
args: ['attr.aria-valuemin']
}], maxProgressVal: [{
type: HostBinding,
args: ['attr.aria-valuemax']
}], currentProgressVal: [{
type: HostBinding,
args: ['attr.aria-valuenow']
}], dataPasswordStrength: [{
type: HostBinding,
args: ['attr.data-strength']
}] } });
/* eslint-disable @angular-eslint/component-selector */
class PasswordStrengthMeterComponent {
constructor() {
this.minPasswordLength = 8;
this.enableFeedback = false;
this.enableAsync = false;
this.colors = [];
this.numberOfProgressBarItems = 5;
this.strengthChange = new EventEmitter();
this.baseClass = 'psm';
this.passwordStrengthMeterService = inject(IPasswordStrengthMeterService);
this.passwordStrength = null;
this.feedback = null;
this.prevPasswordStrength = null;
this.passwordChangeObservable$ = new Subject();
this.init();
}
ngOnChanges(changes) {
if (changes['password']) {
this.passwordChangeObservable$.next(this.password);
}
}
init() {
this.passwordChangeObservable$
.pipe(distinctUntilChanged(), debounceTime(100), switchMap((value) => {
if (!value) {
return of({ score: null, feedback: null });
}
if (value && value.length < this.minPasswordLength) {
return of({ score: 0, feedback: null });
}
if (this.enableAsync) {
return this.calculateScoreAsync(value);
}
const result = this.calculateScore(value);
return of(result);
}), takeUntilDestroyed())
.subscribe((result) => {
this.passwordStrength = result.score;
this.feedback = result.feedback;
// Only emit the passwordStrength if it changed
if (this.prevPasswordStrength !== this.passwordStrength) {
this.strengthChange.emit(this.passwordStrength);
this.prevPasswordStrength = this.passwordStrength;
}
});
}
calculateScore(value) {
if (this.enableFeedback) {
return this.passwordStrengthMeterService.scoreWithFeedback(value);
}
const feedbackResult = {
score: this.passwordStrengthMeterService.score(value),
feedback: null,
};
return feedbackResult;
}
calculateScoreAsync(value) {
if (this.enableFeedback) {
return this.passwordStrengthMeterService.scoreWithFeedbackAsync(value);
}
return this.passwordStrengthMeterService
.scoreAsync(value)
.then((result) => ({
score: result,
feedback: null,
}));
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.4", ngImport: i0, type: PasswordStrengthMeterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.4", type: PasswordStrengthMeterComponent, isStandalone: true, selector: "password-strength-meter", inputs: { password: "password", minPasswordLength: "minPasswordLength", enableFeedback: ["enableFeedback", "enableFeedback", booleanAttribute], enableAsync: ["enableAsync", "enableAsync", booleanAttribute], colors: "colors", numberOfProgressBarItems: "numberOfProgressBarItems" }, outputs: { strengthChange: "strengthChange" }, host: { properties: { "class": "this.baseClass" } }, usesOnChanges: true, ngImport: i0, template: "<div\n class=\"psm__progress-bar\"\n role=\"progressbar\"\n [passwordStrength]=\"passwordStrength\"\n [numberOfProgressBarItems]=\"numberOfProgressBarItems\"\n [colors]=\"colors\"\n>\n <div class=\"psm__progress-bar-items\"></div>\n <div class=\"psm__progress-bar-overlay\"></div>\n</div>\n\n@if(enableFeedback && feedback) {\n\n @if(feedback.warning) {\n <small class=\"psm__feedback\">\n {{ feedback.warning }}\n </small>\n }\n\n @if(feedback.suggestions && feedback.suggestions.length) {\n <small class=\"psm__suggestion\">\n @for (suggestion of feedback.suggestions; track suggestion; let isLast = $last) {\n {{ suggestion }}{{ isLast ? '' : ' ' }}\n }\n </small>\n }\n}\n\n", styles: ["*,*:before,*:after{box-sizing:border-box}.psm__progress-bar{position:relative;height:3px;margin:10px auto;border-radius:3px;background:#fff}.psm__progress-bar-items{display:flex;justify-content:space-evenly;width:100%;height:100%;background:#ddd}.psm__progress-bar-item{height:100%;z-index:5;border-right:4px solid #fff}.psm__progress-bar-item:last-child{border-right:0px}.psm__progress-bar-overlay{position:absolute;background:red;border-radius:3px;height:3px;top:0;transition:width .5s ease-in-out,background .25s}.psm__feedback,.psm__suggestion{font-size:70%;font-weight:400;color:#6c757d!important;display:block;margin-top:.25rem}\n"], dependencies: [{ kind: "directive", type: PSMProgressBarDirective, selector: ".psm__progress-bar", inputs: ["numberOfProgressBarItems", "passwordStrength", "colors"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.4", ngImport: i0, type: PasswordStrengthMeterComponent, decorators: [{
type: Component,
args: [{ selector: 'password-strength-meter', imports: [PSMProgressBarDirective], template: "<div\n class=\"psm__progress-bar\"\n role=\"progressbar\"\n [passwordStrength]=\"passwordStrength\"\n [numberOfProgressBarItems]=\"numberOfProgressBarItems\"\n [colors]=\"colors\"\n>\n <div class=\"psm__progress-bar-items\"></div>\n <div class=\"psm__progress-bar-overlay\"></div>\n</div>\n\n@if(enableFeedback && feedback) {\n\n @if(feedback.warning) {\n <small class=\"psm__feedback\">\n {{ feedback.warning }}\n </small>\n }\n\n @if(feedback.suggestions && feedback.suggestions.length) {\n <small class=\"psm__suggestion\">\n @for (suggestion of feedback.suggestions; track suggestion; let isLast = $last) {\n {{ suggestion }}{{ isLast ? '' : ' ' }}\n }\n </small>\n }\n}\n\n", styles: ["*,*:before,*:after{box-sizing:border-box}.psm__progress-bar{position:relative;height:3px;margin:10px auto;border-radius:3px;background:#fff}.psm__progress-bar-items{display:flex;justify-content:space-evenly;width:100%;height:100%;background:#ddd}.psm__progress-bar-item{height:100%;z-index:5;border-right:4px solid #fff}.psm__progress-bar-item:last-child{border-right:0px}.psm__progress-bar-overlay{position:absolute;background:red;border-radius:3px;height:3px;top:0;transition:width .5s ease-in-out,background .25s}.psm__feedback,.psm__suggestion{font-size:70%;font-weight:400;color:#6c757d!important;display:block;margin-top:.25rem}\n"] }]
}], ctorParameters: () => [], propDecorators: { password: [{
type: Input,
args: [{ required: true }]
}], minPasswordLength: [{
type: Input
}], enableFeedback: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], enableAsync: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], colors: [{
type: Input
}], numberOfProgressBarItems: [{
type: Input
}], strengthChange: [{
type: Output
}], baseClass: [{
type: HostBinding,
args: ['class']
}] } });
/*
* Public API Surface of password-strength-meter
*/
/**
* Generated bundle index. Do not edit.
*/
export { IPasswordStrengthMeterService, PSMProgressBarDirective, PasswordStrengthMeterComponent };
//# sourceMappingURL=wise-community-angular-password-strength-meter.mjs.map