@gravitee/ui-particles-angular 5.14.0-showcase-http-proxy-28de21a → 5.15.0-showcase-http-proxy-fa50d15
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/esm2020/lib/gio-form-focus-first-invalid/gio-form-focus-first-invalid.directive.mjs +6 -6
- package/esm2020/lib/gio-form-json-schema/gio-form-json-schema.component.mjs +29 -17
- package/esm2020/lib/gio-form-json-schema/gio-form-json-schema.module.mjs +21 -6
- package/esm2020/lib/gio-form-json-schema/gio-formly-json-schema.service.mjs +18 -1
- package/esm2020/lib/gio-form-json-schema/type-component/multischema-type.component.mjs +2 -2
- package/esm2020/lib/gio-form-json-schema/wrappers/gio-password-eye.component.mjs +72 -0
- package/fesm2015/gravitee-ui-particles-angular.mjs +132 -27
- package/fesm2015/gravitee-ui-particles-angular.mjs.map +1 -1
- package/fesm2020/gravitee-ui-particles-angular.mjs +138 -27
- package/fesm2020/gravitee-ui-particles-angular.mjs.map +1 -1
- package/lib/gio-form-json-schema/gio-form-json-schema.component.d.ts +1 -0
- package/lib/gio-form-json-schema/gio-form-json-schema.module.d.ts +12 -11
- package/lib/gio-form-json-schema/gio-formly-json-schema.service.d.ts +1 -0
- package/lib/gio-form-json-schema/wrappers/gio-password-eye.component.d.ts +12 -0
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { trigger, transition, style, animate } from '@angular/animations';
|
|
2
2
|
import * as i0 from '@angular/core';
|
|
3
3
|
import { EventEmitter, Component, HostBinding, Input, Output, HostListener, NgModule, Optional, Self, ViewChild, Directive, Inject, forwardRef, ChangeDetectionStrategy, Injectable, ViewEncapsulation, ContentChildren, Host, ContentChild, InjectionToken } from '@angular/core';
|
|
4
|
-
import { timer, Subject, fromEvent, of, BehaviorSubject, ReplaySubject } from 'rxjs';
|
|
4
|
+
import { timer, Subject, fromEvent, of, BehaviorSubject, combineLatest, ReplaySubject } from 'rxjs';
|
|
5
5
|
import * as i1 from '@angular/material/card';
|
|
6
6
|
import { MatCardModule } from '@angular/material/card';
|
|
7
7
|
import * as i2 from '@angular/material/button';
|
|
@@ -2762,6 +2762,7 @@ class GioFormlyJsonSchemaService {
|
|
|
2762
2762
|
return this.formlyJsonschema.toFieldConfig(jsonSchema, {
|
|
2763
2763
|
map: (mappedField, mapSource) => {
|
|
2764
2764
|
mappedField = this.uiTypeMap(mappedField, mapSource);
|
|
2765
|
+
mappedField = this.formatMap(mappedField, mapSource);
|
|
2765
2766
|
mappedField = this.bannerMap(mappedField, mapSource);
|
|
2766
2767
|
mappedField = this.toggleMap(mappedField, mapSource);
|
|
2767
2768
|
return mappedField;
|
|
@@ -2773,6 +2774,16 @@ class GioFormlyJsonSchemaService {
|
|
|
2773
2774
|
mappedField.type = (_b = (_a = mapSource.gioConfig) === null || _a === void 0 ? void 0 : _a.uiType) !== null && _b !== void 0 ? _b : mappedField.type;
|
|
2774
2775
|
return mappedField;
|
|
2775
2776
|
}
|
|
2777
|
+
formatMap(mappedField, mapSource) {
|
|
2778
|
+
if (mapSource.type === 'string' && mapSource.format === 'text') {
|
|
2779
|
+
mappedField.type = 'textarea';
|
|
2780
|
+
mappedField.props = Object.assign(Object.assign({}, mappedField.props), { autosize: true });
|
|
2781
|
+
}
|
|
2782
|
+
else if (mapSource.type === 'string' && mapSource.format === 'password') {
|
|
2783
|
+
mappedField.props = Object.assign(Object.assign({}, mappedField.props), { type: 'password' });
|
|
2784
|
+
}
|
|
2785
|
+
return mappedField;
|
|
2786
|
+
}
|
|
2776
2787
|
bannerMap(mappedField, mapSource) {
|
|
2777
2788
|
var _a;
|
|
2778
2789
|
mappedField.props = Object.assign(Object.assign({}, mappedField.props), (((_a = mapSource.gioConfig) === null || _a === void 0 ? void 0 : _a.banner) ? getBannerProperties(mapSource.gioConfig.banner) : {}));
|
|
@@ -2827,6 +2838,7 @@ class GioFormJsonSchemaComponent {
|
|
|
2827
2838
|
this._onChange = () => ({});
|
|
2828
2839
|
this._onTouched = () => ({});
|
|
2829
2840
|
this.touched = false;
|
|
2841
|
+
this.stateChanges$ = new Subject();
|
|
2830
2842
|
if (ngControl) {
|
|
2831
2843
|
// Setting the value accessor directly (instead of using
|
|
2832
2844
|
// the providers `NG_VALUE_ACCESSOR`) to avoid running into a circular import.
|
|
@@ -2847,26 +2859,37 @@ class GioFormJsonSchemaComponent {
|
|
|
2847
2859
|
}
|
|
2848
2860
|
ngOnInit() {
|
|
2849
2861
|
var _a, _b, _c;
|
|
2850
|
-
// When the parent form is touched, mark all the sub formGroup as touched
|
|
2862
|
+
// When the parent form is touched, mark all the sub formGroup as touched ony once
|
|
2851
2863
|
const parentControl = (_b = (_a = this.ngControl) === null || _a === void 0 ? void 0 : _a.control) === null || _b === void 0 ? void 0 : _b.parent;
|
|
2852
|
-
(_c = parentControl === null || parentControl === void 0 ? void 0 : parentControl.statusChanges) === null || _c === void 0 ? void 0 : _c.pipe(takeUntil(this.unsubscribe$), map(() => parentControl === null || parentControl === void 0 ? void 0 : parentControl.touched), filter(touched => touched === true),
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
if (status === 'VALID') {
|
|
2856
|
-
(_b = (_a = this.ngControl) === null || _a === void 0 ? void 0 : _a.control) === null || _b === void 0 ? void 0 : _b.setErrors(null);
|
|
2857
|
-
}
|
|
2858
|
-
if (status === 'INVALID') {
|
|
2859
|
-
(_d = (_c = this.ngControl) === null || _c === void 0 ? void 0 : _c.control) === null || _d === void 0 ? void 0 : _d.setErrors({ invalid: true });
|
|
2860
|
-
}
|
|
2864
|
+
(_c = parentControl === null || parentControl === void 0 ? void 0 : parentControl.statusChanges) === null || _c === void 0 ? void 0 : _c.pipe(takeUntil(this.unsubscribe$), map(() => parentControl === null || parentControl === void 0 ? void 0 : parentControl.touched), filter(touched => touched === true), distinctUntilChanged()).subscribe(() => {
|
|
2865
|
+
this.formGroup.markAllAsTouched();
|
|
2866
|
+
this.stateChanges$.next();
|
|
2861
2867
|
});
|
|
2862
2868
|
// To simulate the behavior of classic form controls, emit value only when the form is touched
|
|
2863
2869
|
// Allow to keep the formControl pristine until the user interact with it
|
|
2864
|
-
this.formGroup.valueChanges
|
|
2870
|
+
combineLatest([this.formGroup.statusChanges, this.formGroup.valueChanges])
|
|
2865
2871
|
.pipe(takeUntil(this.unsubscribe$),
|
|
2866
2872
|
// Group all valueChanges events emit by formly in a single one
|
|
2867
|
-
debounceTime(
|
|
2868
|
-
.subscribe(
|
|
2869
|
-
this.
|
|
2873
|
+
debounceTime(100))
|
|
2874
|
+
.subscribe(() => {
|
|
2875
|
+
this.stateChanges$.next();
|
|
2876
|
+
});
|
|
2877
|
+
this.stateChanges$.pipe(takeUntil(this.unsubscribe$)).subscribe(() => {
|
|
2878
|
+
var _a, _b, _c, _d;
|
|
2879
|
+
const { status, value, touched } = this.formGroup;
|
|
2880
|
+
if (touched) {
|
|
2881
|
+
this._onTouched();
|
|
2882
|
+
this.touched = true;
|
|
2883
|
+
}
|
|
2884
|
+
if (this.touched) {
|
|
2885
|
+
this._onChange(value);
|
|
2886
|
+
if (status === 'VALID') {
|
|
2887
|
+
(_b = (_a = this.ngControl) === null || _a === void 0 ? void 0 : _a.control) === null || _b === void 0 ? void 0 : _b.setErrors(null);
|
|
2888
|
+
}
|
|
2889
|
+
if (status === 'INVALID') {
|
|
2890
|
+
(_d = (_c = this.ngControl) === null || _c === void 0 ? void 0 : _c.control) === null || _d === void 0 ? void 0 : _d.setErrors({ invalid: true });
|
|
2891
|
+
}
|
|
2892
|
+
}
|
|
2870
2893
|
});
|
|
2871
2894
|
}
|
|
2872
2895
|
ngOnDestroy() {
|
|
@@ -3332,7 +3355,7 @@ GioFjsMultiSchemaTypeComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
|
3332
3355
|
</div>
|
|
3333
3356
|
<formly-field *ngFor="let f of field.fieldGroup" [field]="f"></formly-field>
|
|
3334
3357
|
</div>
|
|
3335
|
-
`, isInline: true, styles: [".
|
|
3358
|
+
`, isInline: true, styles: [".wrapper__title{font-size:16px;font-weight:500;line-height:24px;font:600 14px/20px Golos UI,Roboto,Helvetica Neue,sans-serif;letter-spacing:.4px;margin-bottom:4px}.wrapper:empty{display:none}.wrapper__error{font:400 12px/16px Golos UI,Roboto,Helvetica Neue,sans-serif;letter-spacing:normal;color:#ec4899}\n"], components: [{ type: i1$4.ɵFormlyValidationMessage, selector: "formly-validation-message", inputs: ["field"] }, { type: i1$4.FormlyField, selector: "formly-field", inputs: ["field"] }], directives: [{ type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }] });
|
|
3336
3359
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: GioFjsMultiSchemaTypeComponent, decorators: [{
|
|
3337
3360
|
type: Component,
|
|
3338
3361
|
args: [{ selector: 'gio-fjs-multi-schema-type', template: `
|
|
@@ -3344,7 +3367,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImpo
|
|
|
3344
3367
|
</div>
|
|
3345
3368
|
<formly-field *ngFor="let f of field.fieldGroup" [field]="f"></formly-field>
|
|
3346
3369
|
</div>
|
|
3347
|
-
`, styles: [".
|
|
3370
|
+
`, styles: [".wrapper__title{font-size:16px;font-weight:500;line-height:24px;font:600 14px/20px Golos UI,Roboto,Helvetica Neue,sans-serif;letter-spacing:.4px;margin-bottom:4px}.wrapper:empty{display:none}.wrapper__error{font:400 12px/16px Golos UI,Roboto,Helvetica Neue,sans-serif;letter-spacing:normal;color:#ec4899}\n"] }]
|
|
3348
3371
|
}] });
|
|
3349
3372
|
|
|
3350
3373
|
/*
|
|
@@ -3482,6 +3505,74 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImpo
|
|
|
3482
3505
|
`, styles: [".wrapper{display:flex;flex-direction:column;padding:8px;border:1px solid #d3d5dc;border-radius:8px}.wrapper__header{display:flex}.wrapper__header__text{flex:1 1 auto}.wrapper__header__text__title{font:600 16px/24px Golos UI,Roboto,Helvetica Neue,sans-serif;letter-spacing:.4px;margin-bottom:8px}.wrapper__header__collapse{flex:0 0 auto}.wrapper__header__collapse .collapse-open{transform:rotate(180deg);transition:transform 225ms cubic-bezier(.4,0,.2,1)}.wrapper__header__collapse .collapse-close{transform:rotate(0);transition:transform 225ms cubic-bezier(.4,0,.2,1)}.wrapper__error{font:400 12px/16px Golos UI,Roboto,Helvetica Neue,sans-serif;letter-spacing:normal;color:#ec4899}\n"] }]
|
|
3483
3506
|
}] });
|
|
3484
3507
|
|
|
3508
|
+
/*
|
|
3509
|
+
* Copyright (C) 2023 The Gravitee team (http://gravitee.io)
|
|
3510
|
+
*
|
|
3511
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
3512
|
+
* you may not use this file except in compliance with the License.
|
|
3513
|
+
* You may obtain a copy of the License at
|
|
3514
|
+
*
|
|
3515
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
3516
|
+
*
|
|
3517
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
3518
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
3519
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
3520
|
+
* See the License for the specific language governing permissions and
|
|
3521
|
+
* limitations under the License.
|
|
3522
|
+
*/
|
|
3523
|
+
class GioPasswordEyeWrapperComponent extends FieldWrapper {
|
|
3524
|
+
constructor() {
|
|
3525
|
+
super(...arguments);
|
|
3526
|
+
this.hide = true;
|
|
3527
|
+
}
|
|
3528
|
+
ngAfterViewInit() {
|
|
3529
|
+
if (this.matSuffix) {
|
|
3530
|
+
this.props.suffix = this.matSuffix;
|
|
3531
|
+
}
|
|
3532
|
+
}
|
|
3533
|
+
addonEyeClick($event) {
|
|
3534
|
+
$event.stopPropagation();
|
|
3535
|
+
this.hide = !this.hide;
|
|
3536
|
+
this.props.type = this.hide ? 'password' : 'text';
|
|
3537
|
+
}
|
|
3538
|
+
}
|
|
3539
|
+
GioPasswordEyeWrapperComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: GioPasswordEyeWrapperComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
3540
|
+
GioPasswordEyeWrapperComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.12", type: GioPasswordEyeWrapperComponent, selector: "gio-password-eye-wrapper", viewQueries: [{ propertyName: "matSuffix", first: true, predicate: ["matSuffix"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: `
|
|
3541
|
+
<ng-container #fieldComponent></ng-container>
|
|
3542
|
+
|
|
3543
|
+
<ng-template #matSuffix>
|
|
3544
|
+
<span style="cursor: pointer" (click)="addonEyeClick($event)">
|
|
3545
|
+
<mat-icon [svgIcon]="hide ? 'gio:eye-empty' : 'gio:eye-off'"></mat-icon>
|
|
3546
|
+
</span>
|
|
3547
|
+
</ng-template>
|
|
3548
|
+
`, isInline: true, components: [{ type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }] });
|
|
3549
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: GioPasswordEyeWrapperComponent, decorators: [{
|
|
3550
|
+
type: Component,
|
|
3551
|
+
args: [{
|
|
3552
|
+
selector: 'gio-password-eye-wrapper',
|
|
3553
|
+
template: `
|
|
3554
|
+
<ng-container #fieldComponent></ng-container>
|
|
3555
|
+
|
|
3556
|
+
<ng-template #matSuffix>
|
|
3557
|
+
<span style="cursor: pointer" (click)="addonEyeClick($event)">
|
|
3558
|
+
<mat-icon [svgIcon]="hide ? 'gio:eye-empty' : 'gio:eye-off'"></mat-icon>
|
|
3559
|
+
</span>
|
|
3560
|
+
</ng-template>
|
|
3561
|
+
`,
|
|
3562
|
+
}]
|
|
3563
|
+
}], propDecorators: { matSuffix: [{
|
|
3564
|
+
type: ViewChild,
|
|
3565
|
+
args: ['matSuffix', { static: true }]
|
|
3566
|
+
}] } });
|
|
3567
|
+
function passwordEyeExtension(field) {
|
|
3568
|
+
if (!field.props || (field.wrappers && field.wrappers.indexOf('gio-password-eye') !== -1)) {
|
|
3569
|
+
return;
|
|
3570
|
+
}
|
|
3571
|
+
if (field.props.type === 'password') {
|
|
3572
|
+
field.wrappers = [...(field.wrappers || []), 'gio-password-eye'];
|
|
3573
|
+
}
|
|
3574
|
+
}
|
|
3575
|
+
|
|
3485
3576
|
/*
|
|
3486
3577
|
* Copyright (C) 2015 The Gravitee team (http://gravitee.io)
|
|
3487
3578
|
*
|
|
@@ -3507,7 +3598,8 @@ GioFormJsonSchemaModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0",
|
|
|
3507
3598
|
GioFjsArrayTypeComponent,
|
|
3508
3599
|
GioFjsToggleTypeComponent,
|
|
3509
3600
|
GioFjsHeadersTypeComponent,
|
|
3510
|
-
GioFormFieldWrapperComponent
|
|
3601
|
+
GioFormFieldWrapperComponent,
|
|
3602
|
+
GioPasswordEyeWrapperComponent], imports: [CommonModule,
|
|
3511
3603
|
A11yModule,
|
|
3512
3604
|
ReactiveFormsModule, i1$4.FormlyModule, FormlyMaterialModule,
|
|
3513
3605
|
GioIconsModule,
|
|
@@ -3535,7 +3627,10 @@ GioFormJsonSchemaModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0",
|
|
|
3535
3627
|
{ name: 'uniqueItems', message: 'Should NOT have duplicate items' },
|
|
3536
3628
|
{ name: 'const', message: constValidationMessage },
|
|
3537
3629
|
],
|
|
3538
|
-
wrappers: [
|
|
3630
|
+
wrappers: [
|
|
3631
|
+
{ name: 'gio-with-banner', component: GioFormFieldWrapperComponent },
|
|
3632
|
+
{ name: 'gio-password-eye', component: GioPasswordEyeWrapperComponent },
|
|
3633
|
+
],
|
|
3539
3634
|
types: [
|
|
3540
3635
|
{ name: 'null', component: GioFjsNullTypeComponent, wrappers: ['form-field'] },
|
|
3541
3636
|
{ name: 'array', component: GioFjsArrayTypeComponent },
|
|
@@ -3550,7 +3645,10 @@ GioFormJsonSchemaModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0",
|
|
|
3550
3645
|
component: GioFjsHeadersTypeComponent,
|
|
3551
3646
|
},
|
|
3552
3647
|
],
|
|
3553
|
-
extensions: [
|
|
3648
|
+
extensions: [
|
|
3649
|
+
{ name: 'banner', extension: { onPopulate: bannerExtension } },
|
|
3650
|
+
{ name: 'password-eye', extension: { onPopulate: passwordEyeExtension } },
|
|
3651
|
+
],
|
|
3554
3652
|
extras: {
|
|
3555
3653
|
checkExpressionOn: 'changeDetectionCheck',
|
|
3556
3654
|
},
|
|
@@ -3574,6 +3672,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImpo
|
|
|
3574
3672
|
GioFjsToggleTypeComponent,
|
|
3575
3673
|
GioFjsHeadersTypeComponent,
|
|
3576
3674
|
GioFormFieldWrapperComponent,
|
|
3675
|
+
GioPasswordEyeWrapperComponent,
|
|
3577
3676
|
],
|
|
3578
3677
|
imports: [
|
|
3579
3678
|
CommonModule,
|
|
@@ -3595,7 +3694,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImpo
|
|
|
3595
3694
|
{ name: 'uniqueItems', message: 'Should NOT have duplicate items' },
|
|
3596
3695
|
{ name: 'const', message: constValidationMessage },
|
|
3597
3696
|
],
|
|
3598
|
-
wrappers: [
|
|
3697
|
+
wrappers: [
|
|
3698
|
+
{ name: 'gio-with-banner', component: GioFormFieldWrapperComponent },
|
|
3699
|
+
{ name: 'gio-password-eye', component: GioPasswordEyeWrapperComponent },
|
|
3700
|
+
],
|
|
3599
3701
|
types: [
|
|
3600
3702
|
{ name: 'null', component: GioFjsNullTypeComponent, wrappers: ['form-field'] },
|
|
3601
3703
|
{ name: 'array', component: GioFjsArrayTypeComponent },
|
|
@@ -3610,7 +3712,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImpo
|
|
|
3610
3712
|
component: GioFjsHeadersTypeComponent,
|
|
3611
3713
|
},
|
|
3612
3714
|
],
|
|
3613
|
-
extensions: [
|
|
3715
|
+
extensions: [
|
|
3716
|
+
{ name: 'banner', extension: { onPopulate: bannerExtension } },
|
|
3717
|
+
{ name: 'password-eye', extension: { onPopulate: passwordEyeExtension } },
|
|
3718
|
+
],
|
|
3614
3719
|
extras: {
|
|
3615
3720
|
checkExpressionOn: 'changeDetectionCheck',
|
|
3616
3721
|
},
|
|
@@ -3650,17 +3755,17 @@ class GioFormFocusInvalidDirective {
|
|
|
3650
3755
|
onFormSubmit() {
|
|
3651
3756
|
const selector = '.ng-invalid[formControlName],input.ng-invalid,mat-select.ng-invalid,textarea.ng-invalid,.gio-ng-invalid';
|
|
3652
3757
|
try {
|
|
3758
|
+
// Mark all controls as touched to display errors
|
|
3759
|
+
if (this.formGroupDirective) {
|
|
3760
|
+
this.formGroupDirective.control.markAllAsTouched();
|
|
3761
|
+
this.formGroupDirective.control.updateValueAndValidity();
|
|
3762
|
+
}
|
|
3653
3763
|
let invalidControl = this.renderer.selectRootElement(selector, true);
|
|
3654
3764
|
// If the form is a GioFormJsonSchema, we need to focus the first invalid control inside
|
|
3655
3765
|
if (invalidControl.tagName === 'GIO-FORM-JSON-SCHEMA') {
|
|
3656
3766
|
invalidControl = invalidControl.querySelector(selector);
|
|
3657
3767
|
}
|
|
3658
3768
|
if (invalidControl) {
|
|
3659
|
-
// Mark all controls as touched to display errors
|
|
3660
|
-
if (this.formGroupDirective) {
|
|
3661
|
-
this.formGroupDirective.control.markAllAsTouched();
|
|
3662
|
-
this.formGroupDirective.control.updateValueAndValidity();
|
|
3663
|
-
}
|
|
3664
3769
|
invalidControl.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
3665
3770
|
invalidControl.focus({ preventScroll: true });
|
|
3666
3771
|
}
|