UNPKG

@wise-community/angular-password-strength-meter

Version:

[![CI](https://github.com/antoantonyk/password-strength-meter/actions/workflows/ci-workflow.yml/badge.svg)](https://github.com/antoantonyk/password-strength-meter/actions/workflows/ci-workflow.yml) [![npm version](https://badge.fury.io/js/angular-password

220 lines (213 loc) 13.1 kB
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