mat-password-strength 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Peter Adison
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,266 @@
1
+ # mat-password-strength
2
+
3
+ [![npm](https://img.shields.io/npm/v/mat-password-strength?color=crimson&logo=npm)](https://www.npmjs.com/package/mat-password-strength)
4
+ [![GitHub Stars](https://img.shields.io/github/stars/cpeteradison/mat-password-strength?style=flat&logo=github)](https://github.com/cpeteradison/mat-password-strength/stargazers)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
6
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/cpeteradison/mat-password-strength/blob/main/CONTRIBUTING.md)
7
+ [![Sponsor](https://img.shields.io/badge/Sponsor-%E2%9D%A4-pink?logo=github-sponsors)](https://github.com/sponsors/cpeteradison)
8
+
9
+ Modern Angular Material password strength indicator with simple rule-based or advanced [zxcvbn](https://github.com/dropbox/zxcvbn) analysis.
10
+
11
+ ## Preview
12
+
13
+ | Simple mode | Advanced mode |
14
+ |:-----------:|:-------------:|
15
+ | ![Simple mode](docs/preview-simple.png) | ![Advanced mode](docs/preview-advanced.png) |
16
+
17
+ **[Live Demo →](https://cpeteradison.github.io/mat-password-strength/)**
18
+
19
+ ## Features
20
+
21
+ - Standalone component, no `NgModule` required
22
+ - Signals-based API (`input()` / `computed()`) with `OnPush` change detection
23
+ - Color feedback: red (weak) → yellow (moderate) → green (strong)
24
+
25
+ ### Simple mode
26
+ - Fast, regex-based rule checks, no extra dependencies
27
+ - Configurable rules: minimum length, lowercase, uppercase, numbers, special characters
28
+ - Per-rule checklist so users know exactly what to fix
29
+ - Independently show or hide the strength label and checklist
30
+
31
+ ### Advanced mode
32
+ - Powered by [zxcvbn](https://github.com/dropbox/zxcvbn) for realistic dictionary and pattern analysis
33
+ - Lazy-loaded on first use, deferred until `mode="advanced"` is first rendered, reducing initial parse time
34
+ - Displays tailored warnings and improvement suggestions
35
+ - Independently show or hide the strength label and feedback
36
+ - Exposes `crack_times_display` via `zxcvbnResult()` signal for custom UI
37
+
38
+ ## Version compatibility & requirements
39
+
40
+ | Library version | Angular | `@angular/core` | `@angular/common` | `@angular/material` | `zxcvbn` |
41
+ |---|---|---|---|---|---|
42
+ | `1.x` | 19 | `^19.0.0` | `^19.0.0` | `^19.0.0` | `^4.4.2` |
43
+
44
+ > **Note:** `zxcvbn` must be installed in your application even if you only use `mode="simple"`. Bundlers resolve dynamic imports at build time, so the package must be present in `node_modules`. It is only **loaded at runtime** when `mode="advanced"` is first rendered, so it has no bundle cost if you never use advanced mode.
45
+
46
+ ## Installation
47
+
48
+ ```bash
49
+ npm install mat-password-strength zxcvbn
50
+ ```
51
+
52
+ Make sure Angular Material and its required animations are set up in your application:
53
+
54
+ ```ts
55
+ // main.ts
56
+ import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
57
+
58
+ bootstrapApplication(AppComponent, {
59
+ providers: [provideAnimationsAsync()]
60
+ });
61
+ ```
62
+
63
+ You also need a Material theme in your global stylesheet, e.g.:
64
+
65
+ ```scss
66
+ // styles.scss
67
+ @import '@angular/material/prebuilt-themes/indigo-pink.css';
68
+ ```
69
+
70
+ ## Usage
71
+
72
+ Import `PasswordStrengthComponent` in your standalone component (or `NgModule`):
73
+
74
+ ```ts
75
+ import { FormsModule } from '@angular/forms';
76
+ import { PasswordStrengthComponent } from 'mat-password-strength';
77
+
78
+ @Component({
79
+ // standalone: true is the default in Angular 19+
80
+ imports: [FormsModule, PasswordStrengthComponent],
81
+ template: `
82
+ <input [(ngModel)]="password" />
83
+ <mat-password-strength [password]="password" />
84
+ `
85
+ })
86
+ export class MyComponent {
87
+ password = '';
88
+ }
89
+ ```
90
+
91
+ ### Simple mode (default)
92
+
93
+ Scores the password by checking configurable regex rules. Ideal when you want
94
+ predictable, rule-based feedback.
95
+
96
+ ```html
97
+ <!-- bar only (default) -->
98
+ <mat-password-strength [password]="password" />
99
+
100
+ <!-- bar + label ("Fair", "Strong", …) -->
101
+ <mat-password-strength [password]="password" [hideStrength]="false" />
102
+
103
+ <!-- bar + label + per-rule checklist -->
104
+ <mat-password-strength [password]="password" [hideStrength]="false" [hideFeedback]="false" />
105
+ ```
106
+
107
+ ### Advanced mode
108
+
109
+ Delegates scoring to [zxcvbn](https://github.com/dropbox/zxcvbn) for realistic
110
+ dictionary and pattern analysis. Displays zxcvbn's warning and improvement suggestions.
111
+
112
+ ```html
113
+ <mat-password-strength
114
+ [password]="password"
115
+ mode="advanced"
116
+ [hideStrength]="false"
117
+ [hideFeedback]="false"
118
+ />
119
+ ```
120
+
121
+ Pass user-specific context so zxcvbn can penalize passwords containing personal information:
122
+
123
+ ```html
124
+ <mat-password-strength
125
+ [password]="password"
126
+ mode="advanced"
127
+ [userInputs]="[user.name, user.email]"
128
+ [hideStrength]="false"
129
+ [hideFeedback]="false"
130
+ />
131
+ ```
132
+
133
+ ### Custom rules (simple mode)
134
+
135
+ ```html
136
+ <mat-password-strength
137
+ [password]="password"
138
+ [options]="{ min: 12, lowercase: true, uppercase: true, number: true, specialChar: false }"
139
+ />
140
+ ```
141
+
142
+ ### Reading signals from a parent
143
+
144
+ ```ts
145
+ import { ViewChild } from '@angular/core';
146
+ import { PasswordStrengthComponent } from 'mat-password-strength';
147
+
148
+ @ViewChild(PasswordStrengthComponent) strengthComp!: PasswordStrengthComponent;
149
+
150
+ // label: 'Very Weak' | 'Weak' | 'Fair' | 'Good' | 'Strong' | 'Very Strong'
151
+ get label() { return this.strengthComp.strengthLabel(); }
152
+
153
+ // per-rule pass/fail list (simple mode)
154
+ get rules() { return this.strengthComp.ruleChecks(); }
155
+
156
+ // warning and suggestions from zxcvbn (advanced mode)
157
+ get feedback() { return this.strengthComp.zxcvbnResult()?.feedback; }
158
+
159
+ // human-readable crack-time estimate (advanced mode)
160
+ get crackTime() {
161
+ return this.strengthComp.zxcvbnResult()
162
+ ?.crack_times_display.offline_slow_hashing_1e4_per_second;
163
+ }
164
+ ```
165
+
166
+ ## API
167
+
168
+ ### Inputs
169
+
170
+ | Input | Type | Default | Description |
171
+ |----------------|---------------------------|----------------------------------------------------------------------------------|-------------|
172
+ | `password` | `string` | `''` | Password string to evaluate |
173
+ | `mode` | `'simple' \| 'advanced'` | `'simple'` | Scoring engine to use |
174
+ | `options` | `PasswordStrengthOptions` | see `PasswordStrengthOptions` defaults below | Rules for simple mode |
175
+ | `hideStrength` | `boolean` | `true` | When `false`, shows the strength label below the bar |
176
+ | `hideFeedback` | `boolean` | `true` | When `false`, shows the rule checklist (simple) or zxcvbn warning/suggestions (advanced) |
177
+ | `userInputs` | `string[]` | `[]` | User-specific strings passed to zxcvbn (advanced mode only) |
178
+
179
+ ### Computed Signals
180
+
181
+ | Signal | Type | Description |
182
+ |-----------------|-------------------------|-------------|
183
+ | `strength()` | `number` | Current strength as a 0–100 value |
184
+ | `strengthLabel()` | `string` | Human-readable label for the current score |
185
+ | `ruleChecks()` | `PasswordRuleCheck[]` | Per-rule pass/fail list (populated in simple mode only) |
186
+ | `zxcvbnResult()` | `ZXCVBNResult \| null` | Raw zxcvbn result with `score`, `feedback`, and `crack_times_display` (populated in advanced mode only) |
187
+
188
+ ### `PasswordStrengthOptions` _(simple mode only)_
189
+
190
+ | Property | Type | Default | Description |
191
+ |---------------|-----------|---------|-------------|
192
+ | `min` | `number` | `8` | Minimum password length |
193
+ | `lowercase` | `boolean` | `true` | Require at least one lowercase letter |
194
+ | `uppercase` | `boolean` | `true` | Require at least one uppercase letter |
195
+ | `number` | `boolean` | `true` | Require at least one digit |
196
+ | `specialChar` | `boolean` | `true` | Require at least one special character |
197
+
198
+ ### `PasswordRuleCheck` _(simple mode only)_
199
+
200
+ | Property | Type | Description |
201
+ |-----------|-----------|-------------|
202
+ | `label` | `string` | Human-readable rule description (e.g. `"At least 1 uppercase letter"`) |
203
+ | `passed` | `boolean` | Whether the password currently satisfies this rule |
204
+
205
+ ### `ZXCVBNResult` _(advanced mode only)_
206
+
207
+ | Property | Type | Description |
208
+ |-----------------------|-----------------------------|-------------|
209
+ | `score` | `0 \| 1 \| 2 \| 3 \| 4` | Strength score from very weak (0) to very strong (4) |
210
+ | `feedback.warning` | `string` | Short explanation of the main weakness |
211
+ | `feedback.suggestions`| `string[]` | Actionable improvement tips |
212
+ | `crack_times_display.online_throttling_100_per_hour` | `string` | Rate-limited login (100 attempts/hr) |
213
+ | `crack_times_display.online_no_throttling_10_per_second` | `string` | Unthrottled online attack |
214
+ | `crack_times_display.offline_slow_hashing_1e4_per_second` | `string` | bcrypt/scrypt offline breach — most realistic for production use |
215
+ | `crack_times_display.offline_fast_hashing_1e10_per_second` | `string` | MD5/SHA1 offline breach — worst case |
216
+
217
+ ### Strength labels
218
+
219
+ | Strength value | Label |
220
+ |----------------|--------------|
221
+ | 0 | Very Weak |
222
+ | 1 – 25 | Weak |
223
+ | 26 – 50 | Fair |
224
+ | 51 – 75 | Good |
225
+ | 76 – 99 | Strong |
226
+ | 100 | Very Strong |
227
+
228
+ ### Color thresholds
229
+
230
+ | Strength value | Material color | Meaning |
231
+ |----------------|-------------------|----------|
232
+ | < 21 | `warn` (red) | Weak |
233
+ | 21 – 80 | `accent` (yellow) | Moderate |
234
+ | ≥ 81 | `primary` (green) | Strong |
235
+
236
+ ## Theming
237
+
238
+ The bar and rule colours can be overridden with CSS custom properties:
239
+
240
+ ```css
241
+ mat-password-strength {
242
+ --psc-weak-color: #e53935; /* rule fail + weak bar */
243
+ --psc-medium-color: #fdd835; /* medium bar */
244
+ --psc-strong-color: #43a047; /* rule pass + strong bar */
245
+ --psc-buffer-color: rgba(0, 0, 0, 0.12); /* unfilled bar track */
246
+ }
247
+ ```
248
+
249
+ ## Acknowledgements
250
+
251
+ This library was inspired by
252
+ [`angular-material-extensions/password-strength`](https://github.com/angular-material-extensions/password-strength).
253
+ Thank you to its authors for the original concept. This package was created to continue
254
+ support for Angular 19 and beyond.
255
+
256
+ ## Contributing
257
+
258
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for local development setup, running the demo, and submitting pull requests.
259
+
260
+ ## Changelog
261
+
262
+ See [CHANGELOG.md](CHANGELOG.md) for release history.
263
+
264
+ ## License
265
+
266
+ [MIT](LICENSE)
@@ -0,0 +1,153 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, signal, effect, computed, ViewEncapsulation, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { MatProgressBar } from '@angular/material/progress-bar';
4
+
5
+ /** Mapped from zxcvbn score (0–4) to a 0–100 progress value. */
6
+ const ZXCVBN_SCORE_MAP = { 0: 0, 1: 25, 2: 50, 3: 75, 4: 100 };
7
+ const LOWERCASE_RE = /[a-z]/;
8
+ const UPPERCASE_RE = /[A-Z]/;
9
+ const NUMBER_RE = /\d/;
10
+ const SPECIAL_CHAR_RE = /[!"#$%&'()*+,\-./:;<=>?@[\]^_`{|}~]/;
11
+ // With 5 rules the possible scores are 0/20/40/60/80/100;
12
+ // 21 and 81 ensure 0–20 → warn, 40–80 → accent, 100 → primary
13
+ const WARN_THRESHOLD = 21;
14
+ const ACCENT_THRESHOLD = 81;
15
+ class PasswordStrengthComponent {
16
+ password = input('');
17
+ options = input({
18
+ min: 8,
19
+ lowercase: true,
20
+ uppercase: true,
21
+ number: true,
22
+ specialChar: true,
23
+ });
24
+ hideStrength = input(true);
25
+ /** When true, hides the per-rule checklist (simple) or zxcvbn warning/suggestions (advanced). */
26
+ hideFeedback = input(true);
27
+ /**
28
+ * Scoring mode:
29
+ * - `'simple'` — fast regex-based rule checks (default)
30
+ * - `'advanced'` — zxcvbn dictionary/pattern analysis with crack-time feedback
31
+ */
32
+ mode = input('simple');
33
+ /**
34
+ * Optional list of user-supplied inputs (name, email, username, etc.) passed
35
+ * to zxcvbn so it can penalise passwords that contain personal information.
36
+ * Only used when mode is 'advanced'.
37
+ */
38
+ userInputs = input([]);
39
+ _zxcvbnFn = signal(null);
40
+ constructor() {
41
+ effect(() => {
42
+ if (this.mode() === 'advanced' && !this._zxcvbnFn()) {
43
+ import('zxcvbn').then(m => {
44
+ const mod = m;
45
+ this._zxcvbnFn.set((typeof mod === 'function' ? mod : mod.default));
46
+ });
47
+ }
48
+ });
49
+ }
50
+ /** Raw zxcvbn result — only populated when mode() is 'advanced' and zxcvbn has loaded. */
51
+ zxcvbnResult = computed(() => {
52
+ if (this.mode() !== 'advanced' || !this.password())
53
+ return null;
54
+ const fn = this._zxcvbnFn();
55
+ if (!fn)
56
+ return null;
57
+ return fn(this.password(), this.userInputs());
58
+ });
59
+ strength = computed(() => {
60
+ if (this.mode() === 'advanced') {
61
+ const result = this.zxcvbnResult();
62
+ return result ? ZXCVBN_SCORE_MAP[result.score] : 0;
63
+ }
64
+ const password = this.password();
65
+ const opts = this.options();
66
+ let score = 0;
67
+ let total = 0;
68
+ if (opts.lowercase) {
69
+ total++;
70
+ if (LOWERCASE_RE.test(password))
71
+ score++;
72
+ }
73
+ if (opts.uppercase) {
74
+ total++;
75
+ if (UPPERCASE_RE.test(password))
76
+ score++;
77
+ }
78
+ if (opts.number) {
79
+ total++;
80
+ if (NUMBER_RE.test(password))
81
+ score++;
82
+ }
83
+ if (opts.specialChar) {
84
+ total++;
85
+ if (SPECIAL_CHAR_RE.test(password))
86
+ score++;
87
+ }
88
+ if (opts.min) {
89
+ total++;
90
+ if (password.length >= opts.min)
91
+ score++;
92
+ }
93
+ return total === 0 ? 0 : Math.floor((score / total) * 100);
94
+ });
95
+ color = computed(() => {
96
+ const value = this.strength();
97
+ if (value < WARN_THRESHOLD)
98
+ return 'warn';
99
+ if (value < ACCENT_THRESHOLD)
100
+ return 'accent';
101
+ return 'primary';
102
+ });
103
+ strengthLabel = computed(() => {
104
+ const value = this.strength();
105
+ if (value === 0)
106
+ return 'Very Weak';
107
+ if (value <= 25)
108
+ return 'Weak';
109
+ if (value <= 50)
110
+ return 'Fair';
111
+ if (value <= 75)
112
+ return 'Good';
113
+ if (value < 100)
114
+ return 'Strong';
115
+ return 'Very Strong';
116
+ });
117
+ /** Per-rule pass/fail list — only populated in simple mode. */
118
+ ruleChecks = computed(() => {
119
+ if (this.mode() !== 'simple')
120
+ return [];
121
+ const password = this.password();
122
+ const opts = this.options();
123
+ const checks = [];
124
+ if (opts.lowercase)
125
+ checks.push({ label: 'At least 1 lowercase letter', passed: LOWERCASE_RE.test(password) });
126
+ if (opts.uppercase)
127
+ checks.push({ label: 'At least 1 uppercase letter', passed: UPPERCASE_RE.test(password) });
128
+ if (opts.number)
129
+ checks.push({ label: 'At least 1 number', passed: NUMBER_RE.test(password) });
130
+ if (opts.specialChar)
131
+ checks.push({ label: 'At least 1 special character', passed: SPECIAL_CHAR_RE.test(password) });
132
+ if (opts.min)
133
+ checks.push({ label: `At least ${opts.min} characters`, passed: password.length >= opts.min });
134
+ return checks;
135
+ });
136
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.19", ngImport: i0, type: PasswordStrengthComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
137
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.19", type: PasswordStrengthComponent, isStandalone: true, selector: "mat-password-strength", inputs: { password: { classPropertyName: "password", publicName: "password", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, hideStrength: { classPropertyName: "hideStrength", publicName: "hideStrength", isSignal: true, isRequired: false, transformFunction: null }, hideFeedback: { classPropertyName: "hideFeedback", publicName: "hideFeedback", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, userInputs: { classPropertyName: "userInputs", publicName: "userInputs", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"password-strength-container\">\r\n <mat-progress-bar [value]=\"strength()\" [color]=\"color()\" mode=\"determinate\"></mat-progress-bar>\r\n @if (!hideStrength()) {\r\n <p class=\"password-strength-label\">{{ strengthLabel() }}</p>\r\n }\r\n @if (!hideFeedback()) {\r\n @if (mode() === 'simple') {\r\n <ul class=\"password-strength-rules\">\r\n @for (rule of ruleChecks(); track rule.label) {\r\n <li [class.passed]=\"rule.passed\" [class.failed]=\"!rule.passed\">\r\n {{ rule.passed ? '\u2713' : '\u2717' }} {{ rule.label }}\r\n </li>\r\n }\r\n </ul>\r\n }\r\n @if (mode() === 'advanced' && zxcvbnResult(); as result) {\r\n @if (result.feedback.warning) {\r\n <p class=\"password-strength-warning\">{{ result.feedback.warning }}</p>\r\n }\r\n @if (result.feedback.suggestions.length) {\r\n <ul class=\"password-strength-suggestions\">\r\n @for (suggestion of result.feedback.suggestions; track suggestion) {\r\n <li>{{ suggestion }}</li>\r\n }\r\n </ul>\r\n }\r\n }\r\n }\r\n</div>\r\n", styles: [".password-strength-container .password-strength-label{margin-top:10px}.password-strength-container .mdc-linear-progress__buffer-bar{background-color:var(--psc-buffer-color, #888888)}.password-strength-container .mat-mdc-progress-bar.mat-warn .mdc-linear-progress__bar-inner{background-color:var(--psc-weak-color, #ed1c24);border-color:var(--psc-weak-color, #ed1c24)}.password-strength-container .mat-mdc-progress-bar.mat-accent .mdc-linear-progress__bar-inner{background-color:var(--psc-medium-color, gold);border-color:var(--psc-medium-color, gold)}.password-strength-container .mat-mdc-progress-bar.mat-primary .mdc-linear-progress__bar-inner{background-color:var(--psc-strong-color, #258341);border-color:var(--psc-strong-color, #258341)}.password-strength-container .password-strength-rules{list-style:none;margin:6px 0 0;padding:0;font-size:.8rem}.password-strength-container .password-strength-rules li{margin:2px 0}.password-strength-container .password-strength-rules li.passed{color:var(--psc-strong-color, #258341)}.password-strength-container .password-strength-rules li.failed{color:var(--psc-weak-color, #ed1c24)}\n"], dependencies: [{ kind: "component", type: MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
138
+ }
139
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.19", ngImport: i0, type: PasswordStrengthComponent, decorators: [{
140
+ type: Component,
141
+ args: [{ selector: 'mat-password-strength', standalone: true, imports: [MatProgressBar], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div class=\"password-strength-container\">\r\n <mat-progress-bar [value]=\"strength()\" [color]=\"color()\" mode=\"determinate\"></mat-progress-bar>\r\n @if (!hideStrength()) {\r\n <p class=\"password-strength-label\">{{ strengthLabel() }}</p>\r\n }\r\n @if (!hideFeedback()) {\r\n @if (mode() === 'simple') {\r\n <ul class=\"password-strength-rules\">\r\n @for (rule of ruleChecks(); track rule.label) {\r\n <li [class.passed]=\"rule.passed\" [class.failed]=\"!rule.passed\">\r\n {{ rule.passed ? '\u2713' : '\u2717' }} {{ rule.label }}\r\n </li>\r\n }\r\n </ul>\r\n }\r\n @if (mode() === 'advanced' && zxcvbnResult(); as result) {\r\n @if (result.feedback.warning) {\r\n <p class=\"password-strength-warning\">{{ result.feedback.warning }}</p>\r\n }\r\n @if (result.feedback.suggestions.length) {\r\n <ul class=\"password-strength-suggestions\">\r\n @for (suggestion of result.feedback.suggestions; track suggestion) {\r\n <li>{{ suggestion }}</li>\r\n }\r\n </ul>\r\n }\r\n }\r\n }\r\n</div>\r\n", styles: [".password-strength-container .password-strength-label{margin-top:10px}.password-strength-container .mdc-linear-progress__buffer-bar{background-color:var(--psc-buffer-color, #888888)}.password-strength-container .mat-mdc-progress-bar.mat-warn .mdc-linear-progress__bar-inner{background-color:var(--psc-weak-color, #ed1c24);border-color:var(--psc-weak-color, #ed1c24)}.password-strength-container .mat-mdc-progress-bar.mat-accent .mdc-linear-progress__bar-inner{background-color:var(--psc-medium-color, gold);border-color:var(--psc-medium-color, gold)}.password-strength-container .mat-mdc-progress-bar.mat-primary .mdc-linear-progress__bar-inner{background-color:var(--psc-strong-color, #258341);border-color:var(--psc-strong-color, #258341)}.password-strength-container .password-strength-rules{list-style:none;margin:6px 0 0;padding:0;font-size:.8rem}.password-strength-container .password-strength-rules li{margin:2px 0}.password-strength-container .password-strength-rules li.passed{color:var(--psc-strong-color, #258341)}.password-strength-container .password-strength-rules li.failed{color:var(--psc-weak-color, #ed1c24)}\n"] }]
142
+ }], ctorParameters: () => [] });
143
+
144
+ /*
145
+ * Public API Surface of mat-password-strength
146
+ */
147
+
148
+ /**
149
+ * Generated bundle index. Do not edit.
150
+ */
151
+
152
+ export { PasswordStrengthComponent };
153
+ //# sourceMappingURL=mat-password-strength.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mat-password-strength.mjs","sources":["../../src/lib/password-strength.component.ts","../../src/lib/password-strength.component.html","../../src/public-api.ts","../../src/mat-password-strength.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, ViewEncapsulation, computed, effect, input, signal } from '@angular/core';\r\nimport { MatProgressBar } from '@angular/material/progress-bar';\r\n\r\ntype ZxcvbnFn = (password: string, userInputs?: string[]) => ZXCVBNResult;\r\n\r\n/** Subset of the zxcvbn result exposed in the public API. */\r\nexport interface ZXCVBNResult {\r\n /** 0 = very weak … 4 = very strong */\r\n score: 0 | 1 | 2 | 3 | 4;\r\n feedback: {\r\n warning: string;\r\n suggestions: string[];\r\n };\r\n /** Human-readable crack-time estimates for common attack scenarios. */\r\n crack_times_display: {\r\n online_throttling_100_per_hour: string;\r\n online_no_throttling_10_per_second: string;\r\n offline_slow_hashing_1e4_per_second: string;\r\n offline_fast_hashing_1e10_per_second: string;\r\n };\r\n}\r\n\r\nexport interface PasswordStrengthOptions {\r\n min?: number;\r\n lowercase?: boolean;\r\n uppercase?: boolean;\r\n number?: boolean;\r\n specialChar?: boolean;\r\n}\r\n\r\nexport interface PasswordRuleCheck {\r\n label: string;\r\n passed: boolean;\r\n}\r\n\r\n/** Mapped from zxcvbn score (0–4) to a 0–100 progress value. */\r\nconst ZXCVBN_SCORE_MAP: Record<number, number> = { 0: 0, 1: 25, 2: 50, 3: 75, 4: 100 };\r\n\r\nconst LOWERCASE_RE = /[a-z]/;\r\nconst UPPERCASE_RE = /[A-Z]/;\r\nconst NUMBER_RE = /\\d/;\r\nconst SPECIAL_CHAR_RE = /[!\"#$%&'()*+,\\-./:;<=>?@[\\]^_`{|}~]/;\r\n\r\n// With 5 rules the possible scores are 0/20/40/60/80/100;\r\n// 21 and 81 ensure 0–20 → warn, 40–80 → accent, 100 → primary\r\nconst WARN_THRESHOLD = 21;\r\nconst ACCENT_THRESHOLD = 81;\r\n\r\n@Component({\r\n selector: 'mat-password-strength',\r\n standalone: true,\r\n imports: [MatProgressBar],\r\n templateUrl: './password-strength.component.html',\r\n styleUrls: ['./password-strength.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.None,\r\n})\r\nexport class PasswordStrengthComponent {\r\n password = input<string>('');\r\n options = input<PasswordStrengthOptions>({\r\n min: 8,\r\n lowercase: true,\r\n uppercase: true,\r\n number: true,\r\n specialChar: true,\r\n });\r\n hideStrength = input<boolean>(true);\r\n /** When true, hides the per-rule checklist (simple) or zxcvbn warning/suggestions (advanced). */\r\n hideFeedback = input<boolean>(true);\r\n /**\r\n * Scoring mode:\r\n * - `'simple'` — fast regex-based rule checks (default)\r\n * - `'advanced'` — zxcvbn dictionary/pattern analysis with crack-time feedback\r\n */\r\n mode = input<'simple' | 'advanced'>('simple');\r\n /**\r\n * Optional list of user-supplied inputs (name, email, username, etc.) passed\r\n * to zxcvbn so it can penalise passwords that contain personal information.\r\n * Only used when mode is 'advanced'.\r\n */\r\n userInputs = input<string[]>([]);\r\n\r\n private readonly _zxcvbnFn = signal<ZxcvbnFn | null>(null);\r\n\r\n constructor() {\r\n effect(() => {\r\n if (this.mode() === 'advanced' && !this._zxcvbnFn()) {\r\n import('zxcvbn').then(m => {\r\n const mod = m as unknown as { default?: ZxcvbnFn } | ZxcvbnFn;\r\n this._zxcvbnFn.set((typeof mod === 'function' ? mod : (mod as { default: ZxcvbnFn }).default) as ZxcvbnFn);\r\n });\r\n }\r\n });\r\n }\r\n\r\n /** Raw zxcvbn result — only populated when mode() is 'advanced' and zxcvbn has loaded. */\r\n zxcvbnResult = computed((): ZXCVBNResult | null => {\r\n if (this.mode() !== 'advanced' || !this.password()) return null;\r\n const fn = this._zxcvbnFn();\r\n if (!fn) return null;\r\n return fn(this.password(), this.userInputs());\r\n });\r\n\r\n strength = computed((): number => {\r\n if (this.mode() === 'advanced') {\r\n const result = this.zxcvbnResult();\r\n return result ? ZXCVBN_SCORE_MAP[result.score] : 0;\r\n }\r\n\r\n const password = this.password();\r\n const opts = this.options();\r\n let score = 0;\r\n let total = 0;\r\n\r\n if (opts.lowercase) {\r\n total++;\r\n if (LOWERCASE_RE.test(password)) score++;\r\n }\r\n\r\n if (opts.uppercase) {\r\n total++;\r\n if (UPPERCASE_RE.test(password)) score++;\r\n }\r\n\r\n if (opts.number) {\r\n total++;\r\n if (NUMBER_RE.test(password)) score++;\r\n }\r\n\r\n if (opts.specialChar) {\r\n total++;\r\n if (SPECIAL_CHAR_RE.test(password)) score++;\r\n }\r\n\r\n if (opts.min) {\r\n total++;\r\n if (password.length >= opts.min) score++;\r\n }\r\n\r\n return total === 0 ? 0 : Math.floor((score / total) * 100);\r\n });\r\n\r\n color = computed((): 'warn' | 'accent' | 'primary' => {\r\n const value = this.strength();\r\n if (value < WARN_THRESHOLD) return 'warn';\r\n if (value < ACCENT_THRESHOLD) return 'accent';\r\n return 'primary';\r\n });\r\n\r\n strengthLabel = computed((): string => {\r\n const value = this.strength();\r\n if (value === 0) return 'Very Weak';\r\n if (value <= 25) return 'Weak';\r\n if (value <= 50) return 'Fair';\r\n if (value <= 75) return 'Good';\r\n if (value < 100) return 'Strong';\r\n return 'Very Strong';\r\n });\r\n\r\n /** Per-rule pass/fail list — only populated in simple mode. */\r\n ruleChecks = computed((): PasswordRuleCheck[] => {\r\n if (this.mode() !== 'simple') return [];\r\n const password = this.password();\r\n const opts = this.options();\r\n const checks: PasswordRuleCheck[] = [];\r\n\r\n if (opts.lowercase) checks.push({ label: 'At least 1 lowercase letter', passed: LOWERCASE_RE.test(password) });\r\n if (opts.uppercase) checks.push({ label: 'At least 1 uppercase letter', passed: UPPERCASE_RE.test(password) });\r\n if (opts.number) checks.push({ label: 'At least 1 number', passed: NUMBER_RE.test(password) });\r\n if (opts.specialChar)checks.push({ label: 'At least 1 special character', passed: SPECIAL_CHAR_RE.test(password) });\r\n if (opts.min) checks.push({ label: `At least ${opts.min} characters`, passed: password.length >= opts.min });\r\n\r\n return checks;\r\n });\r\n}\r\n","<div class=\"password-strength-container\">\r\n <mat-progress-bar [value]=\"strength()\" [color]=\"color()\" mode=\"determinate\"></mat-progress-bar>\r\n @if (!hideStrength()) {\r\n <p class=\"password-strength-label\">{{ strengthLabel() }}</p>\r\n }\r\n @if (!hideFeedback()) {\r\n @if (mode() === 'simple') {\r\n <ul class=\"password-strength-rules\">\r\n @for (rule of ruleChecks(); track rule.label) {\r\n <li [class.passed]=\"rule.passed\" [class.failed]=\"!rule.passed\">\r\n {{ rule.passed ? '✓' : '✗' }} {{ rule.label }}\r\n </li>\r\n }\r\n </ul>\r\n }\r\n @if (mode() === 'advanced' && zxcvbnResult(); as result) {\r\n @if (result.feedback.warning) {\r\n <p class=\"password-strength-warning\">{{ result.feedback.warning }}</p>\r\n }\r\n @if (result.feedback.suggestions.length) {\r\n <ul class=\"password-strength-suggestions\">\r\n @for (suggestion of result.feedback.suggestions; track suggestion) {\r\n <li>{{ suggestion }}</li>\r\n }\r\n </ul>\r\n }\r\n }\r\n }\r\n</div>\r\n","/*\r\n * Public API Surface of mat-password-strength\r\n */\r\nexport * from './lib/password-strength.component';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
package/index.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Generated bundle index. Do not edit.
3
+ */
4
+ /// <amd-module name="mat-password-strength" />
5
+ export * from './public-api';
@@ -0,0 +1,58 @@
1
+ import * as i0 from "@angular/core";
2
+ /** Subset of the zxcvbn result exposed in the public API. */
3
+ export interface ZXCVBNResult {
4
+ /** 0 = very weak … 4 = very strong */
5
+ score: 0 | 1 | 2 | 3 | 4;
6
+ feedback: {
7
+ warning: string;
8
+ suggestions: string[];
9
+ };
10
+ /** Human-readable crack-time estimates for common attack scenarios. */
11
+ crack_times_display: {
12
+ online_throttling_100_per_hour: string;
13
+ online_no_throttling_10_per_second: string;
14
+ offline_slow_hashing_1e4_per_second: string;
15
+ offline_fast_hashing_1e10_per_second: string;
16
+ };
17
+ }
18
+ export interface PasswordStrengthOptions {
19
+ min?: number;
20
+ lowercase?: boolean;
21
+ uppercase?: boolean;
22
+ number?: boolean;
23
+ specialChar?: boolean;
24
+ }
25
+ export interface PasswordRuleCheck {
26
+ label: string;
27
+ passed: boolean;
28
+ }
29
+ export declare class PasswordStrengthComponent {
30
+ password: import("@angular/core").InputSignal<string>;
31
+ options: import("@angular/core").InputSignal<PasswordStrengthOptions>;
32
+ hideStrength: import("@angular/core").InputSignal<boolean>;
33
+ /** When true, hides the per-rule checklist (simple) or zxcvbn warning/suggestions (advanced). */
34
+ hideFeedback: import("@angular/core").InputSignal<boolean>;
35
+ /**
36
+ * Scoring mode:
37
+ * - `'simple'` — fast regex-based rule checks (default)
38
+ * - `'advanced'` — zxcvbn dictionary/pattern analysis with crack-time feedback
39
+ */
40
+ mode: import("@angular/core").InputSignal<"simple" | "advanced">;
41
+ /**
42
+ * Optional list of user-supplied inputs (name, email, username, etc.) passed
43
+ * to zxcvbn so it can penalise passwords that contain personal information.
44
+ * Only used when mode is 'advanced'.
45
+ */
46
+ userInputs: import("@angular/core").InputSignal<string[]>;
47
+ private readonly _zxcvbnFn;
48
+ constructor();
49
+ /** Raw zxcvbn result — only populated when mode() is 'advanced' and zxcvbn has loaded. */
50
+ zxcvbnResult: import("@angular/core").Signal<ZXCVBNResult>;
51
+ strength: import("@angular/core").Signal<number>;
52
+ color: import("@angular/core").Signal<"warn" | "accent" | "primary">;
53
+ strengthLabel: import("@angular/core").Signal<string>;
54
+ /** Per-rule pass/fail list — only populated in simple mode. */
55
+ ruleChecks: import("@angular/core").Signal<PasswordRuleCheck[]>;
56
+ static ɵfac: i0.ɵɵFactoryDeclaration<PasswordStrengthComponent, never>;
57
+ static ɵcmp: i0.ɵɵComponentDeclaration<PasswordStrengthComponent, "mat-password-strength", never, { "password": { "alias": "password"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": false; "isSignal": true; }; "hideStrength": { "alias": "hideStrength"; "required": false; "isSignal": true; }; "hideFeedback": { "alias": "hideFeedback"; "required": false; "isSignal": true; }; "mode": { "alias": "mode"; "required": false; "isSignal": true; }; "userInputs": { "alias": "userInputs"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
58
+ }
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "mat-password-strength",
3
+ "version": "1.0.8",
4
+ "description": "An Angular Material password strength indicator component",
5
+ "author": "Peter Adison",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/cpeteradison/mat-password-strength.git"
9
+ },
10
+ "keywords": [
11
+ "angular",
12
+ "angular material",
13
+ "password",
14
+ "password strength",
15
+ "component"
16
+ ],
17
+ "license": "MIT",
18
+ "peerDependencies": {
19
+ "@angular/common": "^19.0.0",
20
+ "@angular/core": "^19.0.0",
21
+ "@angular/material": "^19.0.0",
22
+ "zxcvbn": "^4.4.2"
23
+ },
24
+ "peerDependenciesMeta": {
25
+ "zxcvbn": {
26
+ "optional": true
27
+ }
28
+ },
29
+ "overrides": {
30
+ "@tootallnate/once": "3.0.1"
31
+ },
32
+ "sideEffects": false,
33
+ "module": "fesm2022/mat-password-strength.mjs",
34
+ "typings": "index.d.ts",
35
+ "exports": {
36
+ "./package.json": {
37
+ "default": "./package.json"
38
+ },
39
+ ".": {
40
+ "types": "./index.d.ts",
41
+ "default": "./fesm2022/mat-password-strength.mjs"
42
+ }
43
+ },
44
+ "dependencies": {
45
+ "tslib": "^2.3.0"
46
+ }
47
+ }
@@ -0,0 +1 @@
1
+ export * from './lib/password-strength.component';