@theseam/ui-common 1.0.2-beta.42 → 1.0.2-beta.44

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.
@@ -1,16 +1,18 @@
1
1
  import * as i0 from '@angular/core';
2
- import { isDevMode, inject, ElementRef, Directive, InjectionToken, ChangeDetectorRef, HostListener, HostBinding, Input, forwardRef, ViewContainerRef, TemplateRef, ContentChild, ViewEncapsulation, ChangeDetectionStrategy, Component, NgModule, ViewChild, EventEmitter, Output, Injectable, Injector, ViewChildren, Inject, Optional, ContentChildren } from '@angular/core';
2
+ import { isDevMode, Input, ChangeDetectionStrategy, Component, inject, ElementRef, Directive, InjectionToken, ChangeDetectorRef, HostListener, HostBinding, forwardRef, ViewContainerRef, TemplateRef, ContentChild, ViewEncapsulation, NgModule, ViewChild, EventEmitter, Output, Injectable, Injector, ViewChildren, Inject, Optional, ContentChildren } from '@angular/core';
3
3
  import * as i3$2 from '@angular/forms';
4
4
  import { AbstractControl, Validators, FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
5
5
  import { isEmptyInputValue, hasProperty, notNullOrUndefined, observeControlValue, observeControlStatus, isNullOrUndefined } from '@theseam/ui-common/utils';
6
- import { firstValueFrom, isObservable, BehaviorSubject, from, Subject, of, combineLatest, map as map$1, defer, Observable } from 'rxjs';
7
- import { take, map, distinctUntilChanged, auditTime, tap, startWith, switchMap, shareReplay, mapTo, debounceTime, takeUntil, finalize, filter } from 'rxjs/operators';
6
+ import { firstValueFrom, isObservable, BehaviorSubject, of, merge, from, Subject, combineLatest, map as map$1, defer, Observable } from 'rxjs';
7
+ import { take, map, switchMap, startWith, distinctUntilChanged, auditTime, tap, shareReplay, mapTo, debounceTime, takeUntil, finalize, filter } from 'rxjs/operators';
8
+ import * as i2$1 from '@angular/common';
9
+ import { AsyncPipe, NgIf, NgFor, NgTemplateOutlet, CommonModule, NgStyle } from '@angular/common';
10
+ import { faCheck, faTimes, faAngleDoubleRight, faAngleDoubleLeft, faLock, faUnlock, faAngleLeft, faBars, faAngleDown } from '@fortawesome/free-solid-svg-icons';
11
+ import * as i2 from '@theseam/ui-common/icon';
12
+ import { TheSeamIconModule } from '@theseam/ui-common/icon';
8
13
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
9
14
  import * as i1 from '@angular/cdk/portal';
10
15
  import { TemplatePortal, PortalModule, BasePortalOutlet, ComponentPortal } from '@angular/cdk/portal';
11
- import * as i2$1 from '@angular/common';
12
- import { NgIf, NgFor, NgTemplateOutlet, AsyncPipe, CommonModule, NgStyle } from '@angular/common';
13
- import { faAngleDoubleRight, faAngleDoubleLeft, faLock, faUnlock, faAngleLeft, faBars, faAngleDown } from '@fortawesome/free-solid-svg-icons';
14
16
  import * as i1$3 from '@theseam/ui-common/layout';
15
17
  import { TheSeamLayoutService, TheSeamLayoutModule } from '@theseam/ui-common/layout';
16
18
  import { TheSeamOverlayScrollbarDirective } from '@theseam/ui-common/scrollbar';
@@ -21,8 +23,6 @@ import { moveItemInArray, transferArrayItem, DragDropModule, CdkDrag } from '@an
21
23
  import { InputBoolean, InputNumber, mixinDisabled } from '@theseam/ui-common/core';
22
24
  import { TheSeamElemResizedDirective } from '@theseam/ui-common/shared';
23
25
  import { THESEAM_WIDGET_DATA, THESEAM_WIDGET_ACCESSOR } from '@theseam/ui-common/widget';
24
- import * as i2 from '@theseam/ui-common/icon';
25
- import { TheSeamIconModule } from '@theseam/ui-common/icon';
26
26
  import * as i3 from '@theseam/ui-common/buttons';
27
27
  import { TheSeamButtonsModule } from '@theseam/ui-common/buttons';
28
28
  import { TheSeamDynamicComponentLoader } from '@theseam/ui-common/dynamic-component-loader';
@@ -65,6 +65,10 @@ const DEFAULT_USERNAME_FIELD_CONFIG = {
65
65
  pattern: /^[a-zA-Z0-9\-._@+]+$/,
66
66
  };
67
67
 
68
+ const DEFAULT_PASSWORD_FIELD_CONFIG = {
69
+ minLength: 8,
70
+ };
71
+
68
72
  function isCountryUSA(control) {
69
73
  return control.value === 'USA';
70
74
  }
@@ -156,6 +160,87 @@ function usernameExistsValidator(userExists) {
156
160
  };
157
161
  }
158
162
 
163
+ /**
164
+ * Rejects passwords that contain the word "password" (case-insensitive).
165
+ */
166
+ function passwordContentValidator(control) {
167
+ if (isEmptyInputValue(control.value)) {
168
+ return null;
169
+ }
170
+ return control.value.toLowerCase().indexOf('password') === -1
171
+ ? null
172
+ : { passwordContent: { value: 'password' } };
173
+ }
174
+
175
+ /**
176
+ * Requires at least one lowercase letter.
177
+ */
178
+ function passwordLowercaseValidator(control) {
179
+ if (isEmptyInputValue(control.value)) {
180
+ return null;
181
+ }
182
+ return control.value.match(/[a-z]/) ? null : { passwordLowercase: {} };
183
+ }
184
+
185
+ /**
186
+ * Requires at least one uppercase letter.
187
+ */
188
+ function passwordUppercaseValidator(control) {
189
+ if (isEmptyInputValue(control.value)) {
190
+ return null;
191
+ }
192
+ return control.value.match(/[A-Z]/) ? null : { passwordUppercase: {} };
193
+ }
194
+
195
+ /**
196
+ * Requires at least one digit.
197
+ */
198
+ function passwordNumberValidator(control) {
199
+ if (isEmptyInputValue(control.value)) {
200
+ return null;
201
+ }
202
+ return control.value.match(/\d/) ? null : { passwordNumber: {} };
203
+ }
204
+
205
+ /**
206
+ * Requires at least one special character.
207
+ */
208
+ function passwordSpecialCharValidator(control) {
209
+ if (isEmptyInputValue(control.value)) {
210
+ return null;
211
+ }
212
+ return control.value.match(/[-!@#$%^&*()_+|~=`{}[\]:";'<>?,./]/)
213
+ ? null
214
+ : { passwordSpecialChar: {} };
215
+ }
216
+
217
+ const DEFAULT_CONFIG = {
218
+ minLength: 8,
219
+ };
220
+ /**
221
+ * Requires password to meet a minimum length.
222
+ */
223
+ function passwordLengthValidator(config) {
224
+ const c = { ...DEFAULT_CONFIG, ...config };
225
+ return (control) => {
226
+ if (isEmptyInputValue(control.value)) {
227
+ return null;
228
+ }
229
+ return control.value.length >= c.minLength ? null : { passwordLength: {} };
230
+ };
231
+ }
232
+
233
+ /**
234
+ * Group-level validator that checks password1 and password2 controls match.
235
+ */
236
+ function passwordMatchValidator(g) {
237
+ const control1 = g.get('password1');
238
+ const control2 = g.get('password2');
239
+ const value1 = control1 && control1.value;
240
+ const value2 = control2 && control2.value;
241
+ return value1 === value2 ? null : { passwordMatch: true };
242
+ }
243
+
159
244
  function getAddress1Validators(config, overrides) {
160
245
  const c = { ...DEFAULT_ADDRESS_FIELD_CONFIG, ...config };
161
246
  const o = { required: true, ...overrides };
@@ -250,6 +335,22 @@ function getUsernameValidators(userExists, config, overrides) {
250
335
  };
251
336
  }
252
337
 
338
+ function getPasswordValidators(config, overrides) {
339
+ const o = { required: true, ...overrides };
340
+ return {
341
+ validators: [
342
+ ...(o.required ? [Validators.required] : []),
343
+ passwordContentValidator,
344
+ passwordLengthValidator(config),
345
+ passwordUppercaseValidator,
346
+ passwordLowercaseValidator,
347
+ passwordNumberValidator,
348
+ passwordSpecialCharValidator,
349
+ ],
350
+ asyncValidators: [],
351
+ };
352
+ }
353
+
253
354
  function createAddress1Control(formState = null, config, overrides) {
254
355
  const v = getAddress1Validators(config, overrides);
255
356
  return new FormControl(formState, v.validators, v.asyncValidators);
@@ -285,6 +386,122 @@ function createUsernameControl(formState = null, userExists, config, overrides)
285
386
  return new FormControl(formState, v.validators, v.asyncValidators);
286
387
  }
287
388
 
389
+ const DEFAULT_VALIDATORS = [
390
+ { validatorName: 'passwordLength', message: 'Be at least 8 characters.' },
391
+ {
392
+ validatorName: 'passwordLowercase',
393
+ message: 'At least one lowercase letter.',
394
+ },
395
+ {
396
+ validatorName: 'passwordUppercase',
397
+ message: 'At least one uppercase letter.',
398
+ },
399
+ { validatorName: 'passwordNumber', message: 'At least one number.' },
400
+ {
401
+ validatorName: 'passwordSpecialChar',
402
+ message: 'At least one special character (!, @, #, etc.).',
403
+ },
404
+ {
405
+ validatorName: 'passwordContent',
406
+ message: 'Cannot contain "password".',
407
+ },
408
+ {
409
+ validatorName: 'passwordMatch',
410
+ message: 'Both password fields must match.',
411
+ target: 'group',
412
+ },
413
+ ];
414
+ class TheSeamPasswordValidatorsListComponent {
415
+ _successIcon = { icon: faCheck, iconClass: 'text-success' };
416
+ _errorIcon = { icon: faTimes, iconClass: 'text-danger' };
417
+ fieldOneName = 'password1';
418
+ fieldTwoName = 'password2';
419
+ /**
420
+ * Override the default validator list. Each item specifies a validatorName,
421
+ * display message, and optionally whether the error is on the field or group.
422
+ */
423
+ validators = DEFAULT_VALIDATORS;
424
+ get control() {
425
+ return this._controlSubject.value;
426
+ }
427
+ set control(value) {
428
+ this._controlSubject.next(value);
429
+ }
430
+ _controlSubject = new BehaviorSubject(undefined);
431
+ _touched = new BehaviorSubject(false);
432
+ _records$ = this._createRecordsObservable();
433
+ ngDoCheck() {
434
+ const fieldOne = this._getField(this.fieldOneName);
435
+ const fieldTwo = this._getField(this.fieldTwoName);
436
+ if (!fieldOne || !fieldTwo) {
437
+ return;
438
+ }
439
+ const touched = fieldOne.touched || fieldTwo.touched;
440
+ if (this._touched.value !== touched) {
441
+ this._touched.next(touched);
442
+ }
443
+ }
444
+ _getField(name) {
445
+ return this.control?.get(name);
446
+ }
447
+ _createRecordsObservable() {
448
+ return this._controlSubject.pipe(switchMap((control) => {
449
+ if (!control) {
450
+ return of([]);
451
+ }
452
+ return merge(control.statusChanges, this._touched).pipe(startWith(control.status), map(() => this._buildRecords(control)));
453
+ }));
454
+ }
455
+ _buildRecords(group) {
456
+ const fieldOne = this._getField(this.fieldOneName);
457
+ const fieldTwo = this._getField(this.fieldTwoName);
458
+ return this.validators.map((item) => {
459
+ const record = {
460
+ _id: item.validatorName,
461
+ message: item.message,
462
+ };
463
+ if (!fieldOne || !fieldTwo) {
464
+ return record;
465
+ }
466
+ const isGroupValidator = item.target === 'group';
467
+ if (isGroupValidator) {
468
+ // Group validators only show status when both fields are dirty
469
+ if (!fieldOne.dirty || !fieldTwo.dirty) {
470
+ return record;
471
+ }
472
+ const hasError = group.hasError(item.validatorName);
473
+ Object.assign(record, hasError ? this._errorIcon : this._successIcon);
474
+ }
475
+ else {
476
+ // Field validators show status when password1 is dirty
477
+ if (!fieldOne.dirty) {
478
+ return record;
479
+ }
480
+ const hasError = fieldOne.hasError(item.validatorName);
481
+ Object.assign(record, hasError ? this._errorIcon : this._successIcon);
482
+ }
483
+ return record;
484
+ });
485
+ }
486
+ _trackBy(_index, item) {
487
+ return item._id;
488
+ }
489
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TheSeamPasswordValidatorsListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
490
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: TheSeamPasswordValidatorsListComponent, isStandalone: true, selector: "seam-password-validators-list", inputs: { fieldOneName: "fieldOneName", fieldTwoName: "fieldTwoName", validators: "validators", control: "control" }, ngImport: i0, template: "<h5 class=\"password-validators-list--header\">\n Password must meet the following\n <br />\n requirements:\n</h5>\n<hr />\n<div class=\"password-validators-list--items\">\n @for (item of _records$ | async; track item._id) {\n <div class=\"password-validators-list--item\">\n <div class=\"password-validators-list--item-icon\">\n @if (item.icon) {\n <seam-icon [icon]=\"item.icon\" [class]=\"item.iconClass\"></seam-icon>\n }\n </div>\n {{ item.message }}\n </div>\n }\n</div>\n", styles: [":host{display:flex;flex-direction:column;width:340px}@media screen and (max-width:340px){:host{width:auto}}.password-validators-list--header{color:var(--gray-900, #212529);font-weight:500;font-size:17px;text-align:center;padding:6px 10px 0;margin-bottom:0}hr{margin:5px 0 10px}.password-validators-list--items{color:#000;font-size:15px;padding:0 10px 10px 21px}.password-validators-list--item{display:flex;flex-direction:row}.password-validators-list--item-icon{flex:0 0 auto;width:30px;height:24px}\n"], dependencies: [{ kind: "ngmodule", type: TheSeamIconModule }, { kind: "component", type: i2.IconComponent, selector: "seam-icon", inputs: ["grayscaleOnDisable", "disabled", "iconClass", "icon", "size", "showDefaultOnError", "defaultIcon", "iconType"] }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
491
+ }
492
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TheSeamPasswordValidatorsListComponent, decorators: [{
493
+ type: Component,
494
+ args: [{ selector: 'seam-password-validators-list', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [AsyncPipe, TheSeamIconModule], template: "<h5 class=\"password-validators-list--header\">\n Password must meet the following\n <br />\n requirements:\n</h5>\n<hr />\n<div class=\"password-validators-list--items\">\n @for (item of _records$ | async; track item._id) {\n <div class=\"password-validators-list--item\">\n <div class=\"password-validators-list--item-icon\">\n @if (item.icon) {\n <seam-icon [icon]=\"item.icon\" [class]=\"item.iconClass\"></seam-icon>\n }\n </div>\n {{ item.message }}\n </div>\n }\n</div>\n", styles: [":host{display:flex;flex-direction:column;width:340px}@media screen and (max-width:340px){:host{width:auto}}.password-validators-list--header{color:var(--gray-900, #212529);font-weight:500;font-size:17px;text-align:center;padding:6px 10px 0;margin-bottom:0}hr{margin:5px 0 10px}.password-validators-list--items{color:#000;font-size:15px;padding:0 10px 10px 21px}.password-validators-list--item{display:flex;flex-direction:row}.password-validators-list--item-icon{flex:0 0 auto;width:30px;height:24px}\n"] }]
495
+ }], propDecorators: { fieldOneName: [{
496
+ type: Input
497
+ }], fieldTwoName: [{
498
+ type: Input
499
+ }], validators: [{
500
+ type: Input
501
+ }], control: [{
502
+ type: Input
503
+ }] } });
504
+
288
505
  function createAddressFormGroup(options) {
289
506
  const config = options.config;
290
507
  const countryRequiredOutsideUSA = options.countryRequiredOutsideUSA ?? true;
@@ -317,6 +534,14 @@ function createAddressFormGroup(options) {
317
534
  return { group, subscription };
318
535
  }
319
536
 
537
+ function createPasswordFormGroup(config) {
538
+ const v = getPasswordValidators(config);
539
+ return new FormGroup({
540
+ password1: new FormControl(null, v.validators, v.asyncValidators),
541
+ password2: new FormControl(null, Validators.required),
542
+ }, { validators: [passwordMatchValidator] });
543
+ }
544
+
320
545
  // Models
321
546
 
322
547
  class BaseLayoutContentFooterDirective {
@@ -4559,5 +4784,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
4559
4784
  * Generated bundle index. Do not edit.
4560
4785
  */
4561
4786
 
4562
- export { BaseLayoutContentDirective, BaseLayoutContentFooterDirective, BaseLayoutContentHeaderDirective, BaseLayoutSideBarDirective, BaseLayoutSideBarFooterDirective, BaseLayoutSideBarHeaderDirective, BaseLayoutTopBarDirective, DEFAULT_ADDRESS_FIELD_CONFIG, DEFAULT_SIDE_NAV_CONFIG, DEFAULT_USERNAME_FIELD_CONFIG, DashboardComponent, DashboardWidgetContainerComponent, DashboardWidgetPortalOutletDirective, DashboardWidgetTemplateContainerComponent, DashboardWidgetsComponent, DashboardWidgetsPreferencesService, DashboardWidgetsService, HierarchyLevelResolver, HierarchyRouterOutletComponent, HorizontalNavComponent, NavItemComponent, SeamRouteShellComponent, SideNavComponent, SideNavItemComponent, SideNavToggleComponent, THESEAM_BASE_LAYOUT_REF, THESEAM_DASHBOARD_WIDGETS_PREFERENCES_ACCESSOR, THESEAM_SCHEMA_FRAMEWORK_OVERRIDES, THESEAM_SIDE_NAV_ACCESSOR, THESEAM_SIDE_NAV_CONFIG, THE_SEAM_BASE_LAYOUT, TheSeamBaseLayoutComponent, TheSeamBaseLayoutModule, TheSeamBaseLayoutNavToggleDirective, TheSeamDashboardModule, TheSeamDynamicRouterModule, TheSeamFramework, TheSeamNavModule, TheSeamSchemaFormFrameworkComponent, TheSeamSchemaFormModule, TheSeamSideNavModule, TheSeamTopBarComponent, TheSeamTopBarModule, TopBarCompactMenuBtnDetailDirective, TopBarItemDirective, TopBarMenuBtnDetailDirective, TopBarMenuButtonComponent, TopBarMenuDirective, TopBarNavToggleBtnDetailDirective, TopBarTitleComponent, applyItemConfig, areSameHorizontalNavItem, canBeActive, canExpand, canHaveChildren, computeDirection, createAddress1Control, createAddress2Control, createAddressFormGroup, createCityControl, createCountryControl, createStateControl, createUsernameControl, createZipControl, extendFramework, fader, findHorizontalNavLinkItems, findLinkItems, getAddress1Validators, getAddress2Validators, getCityValidators, getCountryValidators, getHorizontalNavItemStateProp, getItemStateProp, getStateValidators, getUrlSegments, getUsernameValidators, getZipValidators, hasActiveChild, hasChildren, hasExpandedChild, horizontalNavItemCanBeActive, horizontalNavItemCanExpand, horizontalNavItemCanHaveChildren, horizontalNavItemHasActiveChild, horizontalNavItemHasChildren, horizontalNavItemHasExpandedChild, ifUSA, isCountryUSA, isExpanded, isHorizontalNavItemActive, isHorizontalNavItemExpanded, isHorizontalNavItemFocused, isHorizontalNavItemType, isNavItemActive, isNavItemType, routeChanges, seamRouteTransition, setDefaultHorizontalNavItemState, setDefaultState, setHorizontalNavItemStateProp, setItemStateProp, sideNavExpandStateChangeFn, sideToSide, slider, stateProvinceRegionValidator, stepper, transformer, usernameExistsValidator };
4787
+ export { BaseLayoutContentDirective, BaseLayoutContentFooterDirective, BaseLayoutContentHeaderDirective, BaseLayoutSideBarDirective, BaseLayoutSideBarFooterDirective, BaseLayoutSideBarHeaderDirective, BaseLayoutTopBarDirective, DEFAULT_ADDRESS_FIELD_CONFIG, DEFAULT_PASSWORD_FIELD_CONFIG, DEFAULT_SIDE_NAV_CONFIG, DEFAULT_USERNAME_FIELD_CONFIG, DashboardComponent, DashboardWidgetContainerComponent, DashboardWidgetPortalOutletDirective, DashboardWidgetTemplateContainerComponent, DashboardWidgetsComponent, DashboardWidgetsPreferencesService, DashboardWidgetsService, HierarchyLevelResolver, HierarchyRouterOutletComponent, HorizontalNavComponent, NavItemComponent, SeamRouteShellComponent, SideNavComponent, SideNavItemComponent, SideNavToggleComponent, THESEAM_BASE_LAYOUT_REF, THESEAM_DASHBOARD_WIDGETS_PREFERENCES_ACCESSOR, THESEAM_SCHEMA_FRAMEWORK_OVERRIDES, THESEAM_SIDE_NAV_ACCESSOR, THESEAM_SIDE_NAV_CONFIG, THE_SEAM_BASE_LAYOUT, TheSeamBaseLayoutComponent, TheSeamBaseLayoutModule, TheSeamBaseLayoutNavToggleDirective, TheSeamDashboardModule, TheSeamDynamicRouterModule, TheSeamFramework, TheSeamNavModule, TheSeamPasswordValidatorsListComponent, TheSeamSchemaFormFrameworkComponent, TheSeamSchemaFormModule, TheSeamSideNavModule, TheSeamTopBarComponent, TheSeamTopBarModule, TopBarCompactMenuBtnDetailDirective, TopBarItemDirective, TopBarMenuBtnDetailDirective, TopBarMenuButtonComponent, TopBarMenuDirective, TopBarNavToggleBtnDetailDirective, TopBarTitleComponent, applyItemConfig, areSameHorizontalNavItem, canBeActive, canExpand, canHaveChildren, computeDirection, createAddress1Control, createAddress2Control, createAddressFormGroup, createCityControl, createCountryControl, createPasswordFormGroup, createStateControl, createUsernameControl, createZipControl, extendFramework, fader, findHorizontalNavLinkItems, findLinkItems, getAddress1Validators, getAddress2Validators, getCityValidators, getCountryValidators, getHorizontalNavItemStateProp, getItemStateProp, getPasswordValidators, getStateValidators, getUrlSegments, getUsernameValidators, getZipValidators, hasActiveChild, hasChildren, hasExpandedChild, horizontalNavItemCanBeActive, horizontalNavItemCanExpand, horizontalNavItemCanHaveChildren, horizontalNavItemHasActiveChild, horizontalNavItemHasChildren, horizontalNavItemHasExpandedChild, ifUSA, isCountryUSA, isExpanded, isHorizontalNavItemActive, isHorizontalNavItemExpanded, isHorizontalNavItemFocused, isHorizontalNavItemType, isNavItemActive, isNavItemType, passwordContentValidator, passwordLengthValidator, passwordLowercaseValidator, passwordMatchValidator, passwordNumberValidator, passwordSpecialCharValidator, passwordUppercaseValidator, routeChanges, seamRouteTransition, setDefaultHorizontalNavItemState, setDefaultState, setHorizontalNavItemStateProp, setItemStateProp, sideNavExpandStateChangeFn, sideToSide, slider, stateProvinceRegionValidator, stepper, transformer, usernameExistsValidator };
4563
4788
  //# sourceMappingURL=theseam-ui-common-framework.mjs.map