mirror of
https://github.com/andwati/zitadel.git
synced 2026-11-09 23:55:12 +00:00
fix(console): formfield changes and ux (#1020)
* cnsl-formfield, cnsl-label, cnsl-input, ch prefix * create user cnsl-fields, add cnsl-error * replace user forms with cnsl-fields * replace all other occurrences of mat-form-field with cnsl-fields * improve hover, active, focus behavior, headlin styling * user-grant refactor * style cleanup * stylelint * fix detail layout flexstart, user table header * input dir * error, input directives instead components, on blur handler * error directive, formfield content children * formfield control directive * use new field for new contact dialog * formfield hint, error directive, scss * hint or error binding, animation after view init * avatar changes, policy header * style lint * lint * input control within formfield, errorstatematcher * use matformcontrol to merge with selects * member table min width, lint * lint * implement from matformcontrol insteat custom, add selector * find error * add focus listener * labelfloat * fix input directive * renaming * rm logs * user search overflow, org create i18n, meta cleanup * sidenav shadow * redirect to org table * lint * lint test files * remove usage of formfieldmodule, use input module, layout optim * replace formfieldmodule usage with inputmodule * lint input dir, scss * user grant, user table optimisations * reorganize sidenav, project table empty, tooltips, avatar ch * user grant tooltips, form field error directive accessor * checkbox overflow fix, table dateblock, i18n tooltips * app placeholder, i18n, optimize mobile layout * change refresh table order, i18n, redirect chips * stylelint * chore(deps-dev): bump stylelint from 13.7.2 to 13.8.0 in /console (#1007) * fix: add project validation (#996) * fix: project add validation (#997) * fix: add project validation * fix: removed loop * chore(deps-dev): bump stylelint from 13.7.2 to 13.8.0 in /console Bumps [stylelint](https://github.com/stylelint/stylelint) from 13.7.2 to 13.8.0. - [Release notes](https://github.com/stylelint/stylelint/releases) - [Changelog](https://github.com/stylelint/stylelint/blob/master/CHANGELOG.md) - [Commits](https://github.com/stylelint/stylelint/compare/13.7.2...13.8.0) Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: Silvan <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump @angular/cli from 11.0.1 to 11.0.2 in /console (#1006) * fix: add project validation (#996) * fix: project add validation (#997) * fix: add project validation * fix: removed loop * chore(deps-dev): bump @angular/cli from 11.0.1 to 11.0.2 in /console Bumps [@angular/cli](https://github.com/angular/angular-cli) from 11.0.1 to 11.0.2. - [Release notes](https://github.com/angular/angular-cli/releases) - [Commits](https://github.com/angular/angular-cli/compare/v11.0.1...v11.0.2) Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: Silvan <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump google-proto-files from 2.2.0 to 2.3.0 in /console (#1005) * fix: add project validation (#996) * fix: project add validation (#997) * fix: add project validation * fix: removed loop * chore(deps): bump google-proto-files from 2.2.0 to 2.3.0 in /console Bumps [google-proto-files](https://github.com/googleapis/nodejs-proto-files) from 2.2.0 to 2.3.0. - [Release notes](https://github.com/googleapis/nodejs-proto-files/releases) - [Changelog](https://github.com/googleapis/nodejs-proto-files/blob/master/CHANGELOG.md) - [Commits](https://github.com/googleapis/nodejs-proto-files/compare/v2.2.0...v2.3.0) Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: Silvan <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump @types/node from 14.14.6 to 14.14.9 in /console (#1004) * fix: add project validation (#996) * fix: project add validation (#997) * fix: add project validation * fix: removed loop * chore(deps-dev): bump @types/node from 14.14.6 to 14.14.9 in /console Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 14.14.6 to 14.14.9. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: Silvan <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump @angular/language-service from 11.0.0 to 11.0.2 in /console (#999) * fix: add project validation (#996) * fix: project add validation (#997) * fix: add project validation * fix: removed loop * chore(deps-dev): bump @angular/language-service in /console Bumps [@angular/language-service](https://github.com/angular/angular/tree/HEAD/packages/language-service) from 11.0.0 to 11.0.2. - [Release notes](https://github.com/angular/angular/releases) - [Changelog](https://github.com/angular/angular/blob/master/CHANGELOG.md) - [Commits](https://github.com/angular/angular/commits/11.0.2/packages/language-service) Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: Silvan <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump @angular-devkit/build-angular from 0.1100.1 to 0.1100.2 in /console (#1003) * fix: add project validation (#996) * fix: project add validation (#997) * fix: add project validation * fix: removed loop * chore(deps-dev): bump @angular-devkit/build-angular in /console Bumps [@angular-devkit/build-angular](https://github.com/angular/angular-cli) from 0.1100.1 to 0.1100.2. - [Release notes](https://github.com/angular/angular-cli/releases) - [Commits](https://github.com/angular/angular-cli/commits) Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: Silvan <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Max Peintner <[email protected]> * chore(deps-dev): bump prettier from 2.1.2 to 2.2.0 in /console (#1002) * fix: add project validation (#996) * fix: project add validation (#997) * fix: add project validation * fix: removed loop * chore(deps-dev): bump prettier from 2.1.2 to 2.2.0 in /console Bumps [prettier](https://github.com/prettier/prettier) from 2.1.2 to 2.2.0. - [Release notes](https://github.com/prettier/prettier/releases) - [Changelog](https://github.com/prettier/prettier/blob/master/CHANGELOG.md) - [Commits](https://github.com/prettier/prettier/compare/2.1.2...2.2.0) Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: Silvan <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump @types/jasmine from 3.6.1 to 3.6.2 in /console (#1001) * fix: add project validation (#996) * fix: project add validation (#997) * fix: add project validation * fix: removed loop * chore(deps-dev): bump @types/jasmine from 3.6.1 to 3.6.2 in /console Bumps [@types/jasmine](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jasmine) from 3.6.1 to 3.6.2. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jasmine) Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: Silvan <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Max Peintner <[email protected]> * chore(deps): bump file-saver from 2.0.2 to 2.0.5 in /console (#1000) * fix: add project validation (#996) * fix: project add validation (#997) * fix: add project validation * fix: removed loop * chore(deps): bump file-saver from 2.0.2 to 2.0.5 in /console Bumps [file-saver](https://github.com/eligrey/FileSaver.js) from 2.0.2 to 2.0.5. - [Release notes](https://github.com/eligrey/FileSaver.js/releases) - [Changelog](https://github.com/eligrey/FileSaver.js/blob/master/CHANGELOG.md) - [Commits](https://github.com/eligrey/FileSaver.js/commits) Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: Silvan <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Max Peintner <[email protected]> * chore(deps-dev): bump jasmine-spec-reporter in /console (#974) Bumps [jasmine-spec-reporter](https://github.com/bcaudan/jasmine-spec-reporter) from 5.0.2 to 6.0.0. - [Release notes](https://github.com/bcaudan/jasmine-spec-reporter/releases) - [Changelog](https://github.com/bcaudan/jasmine-spec-reporter/blob/master/CHANGELOG.md) - [Commits](https://github.com/bcaudan/jasmine-spec-reporter/compare/v5.0.2...v6.0.0) Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * input field border improvements, primary color * redirect form, conventional ux * redirects inputs on app create * fix dynamic suffix padding, user grant layout, lint * input style accessor, contact view optim, ext idp, card fixes * hide error on untouched formfield, border red on error touched * fix change detector * change, user, form validation, delete refresh * safari font weight adjustment, change refresh emitter * key validation * remove tabls layout from projects * app changes, refactor project, app state, meta layout * add key dialog validation, startdate, rever change tabs * stylelint * Update console/src/assets/i18n/en.json Co-authored-by: Florian Forster <[email protected]> * Update console/src/assets/i18n/en.json Co-authored-by: Florian Forster <[email protected]> * Update console/src/assets/i18n/de.json Co-authored-by: Florian Forster <[email protected]> * Update console/src/assets/i18n/de.json Co-authored-by: Florian Forster <[email protected]> * Update console/src/assets/i18n/de.json Co-authored-by: Florian Forster <[email protected]> * Update console/src/assets/i18n/de.json Co-authored-by: Florian Forster <[email protected]> * Update console/src/assets/i18n/de.json Co-authored-by: Florian Forster <[email protected]> * Update console/src/assets/i18n/de.json Co-authored-by: Florian Forster <[email protected]> * Update console/src/assets/i18n/en.json Co-authored-by: Florian Forster <[email protected]> * Update console/src/assets/i18n/en.json Co-authored-by: Florian Forster <[email protected]> * finnaly fix fckntimestamp picker * optional key expiry * small state badge * Update console/src/assets/i18n/de.json Co-authored-by: Florian Forster <[email protected]> * Update console/src/assets/i18n/de.json Co-authored-by: Florian Forster <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Silvan <[email protected]> Co-authored-by: Florian Forster <[email protected]>
This commit is contained in:
co-authored by
dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Florian Forster
dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Silvan
parent
42f50de790
commit
ae26999834
@@ -0,0 +1,18 @@
|
||||
import { animate, AnimationTriggerMetadata, state, style, transition, trigger } from '@angular/animations';
|
||||
|
||||
/**
|
||||
* Animations used by the CnslFormFieldComponent.
|
||||
*/
|
||||
export const cnslFormFieldAnimations: {
|
||||
readonly transitionMessages: AnimationTriggerMetadata;
|
||||
} = {
|
||||
/** Animation that transitions the form field's error and hint messages. */
|
||||
transitionMessages: trigger('transitionMessages', [
|
||||
// TODO(mmalerba): Use angular animations for label animation as well.
|
||||
state('enter', style({ opacity: 1, transform: 'translateY(0%)' })),
|
||||
transition('void => enter', [
|
||||
style({ opacity: 0, transform: 'translateY(-100%)' }),
|
||||
animate('3000ms cubic-bezier(0.55, 0, 0.55, 0.2)'),
|
||||
]),
|
||||
]),
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
import { Directive, InjectionToken, Input } from '@angular/core';
|
||||
|
||||
let nextUniqueId = 0;
|
||||
|
||||
export const CNSL_ERROR = new InjectionToken<CnslErrorDirective>('CnslError');
|
||||
|
||||
@Directive({
|
||||
selector: '[cnsl-error]',
|
||||
host: {
|
||||
'class': 'cnsl-error',
|
||||
'role': 'alert',
|
||||
'[attr.id]': 'id',
|
||||
},
|
||||
providers: [{ provide: CNSL_ERROR, useExisting: CnslErrorDirective }],
|
||||
})
|
||||
export class CnslErrorDirective {
|
||||
@Input() id: string = `cnsl-error-${nextUniqueId++}`;
|
||||
|
||||
constructor() { }
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<div class="cnsl-form-field-wrapper" (click)="_control.onContainerClick && _control.onContainerClick($event)">
|
||||
<ng-content select="cnsl-label"></ng-content>
|
||||
<div class="cnsl-rel" #inputContainer>
|
||||
<ng-content></ng-content>
|
||||
<ng-content select="cnslSuffix"></ng-content>
|
||||
</div>
|
||||
<div class="cnsl-form-field-subscript-wrapper" [ngSwitch]="_getDisplayedMessages()">
|
||||
<div *ngSwitchCase="'error'" class="cnsl-form-field-error-wrapper"
|
||||
[@transitionMessages]="_subscriptAnimationState">
|
||||
<ng-content select="cnsl-error"></ng-content>
|
||||
</div>
|
||||
<div *ngSwitchCase="'hint'" class="cnsl-form-field-hint-wrapper"
|
||||
[@transitionMessages]="_subscriptAnimationState">
|
||||
<ng-content select="cnsl-hint"></ng-content>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,45 @@
|
||||
|
||||
@import '~@angular/material/theming';
|
||||
|
||||
@mixin cnsl-form-field-theme($theme) {
|
||||
$primary: map-get($theme, primary);
|
||||
$primary-color: mat-color($primary, 500);
|
||||
$is-dark-theme: map-get($theme, is-dark);
|
||||
|
||||
.ng-untouched {
|
||||
.cnsl-error {
|
||||
visibility: hidden;
|
||||
transition: visibility .2 ease;
|
||||
}
|
||||
}
|
||||
|
||||
.cnsl-form-field-wrapper {
|
||||
width: 100%;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.cnsl-rel {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
[cnslSuffix] {
|
||||
position: absolute;
|
||||
right: .5rem;
|
||||
top: 9px;
|
||||
height: inherit;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
// Wrapper for the hints and error messages.
|
||||
.cnsl-form-field-subscript-wrapper {
|
||||
position: absolute;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
overflow: hidden; // prevents multi-line errors from overlapping the control
|
||||
}
|
||||
|
||||
.cnsl-form-field-hint-wrapper,
|
||||
.cnsl-form-field-error-wrapper {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { CnslFormFieldComponent } from './form-field.component';
|
||||
|
||||
describe('CnslFormFieldComponent', () => {
|
||||
let component: CnslFormFieldComponent;
|
||||
let fixture: ComponentFixture<CnslFormFieldComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [CnslFormFieldComponent],
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CnslFormFieldComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,164 @@
|
||||
import {
|
||||
AfterContentInit,
|
||||
AfterViewInit,
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
ContentChild,
|
||||
ContentChildren,
|
||||
ElementRef,
|
||||
HostListener,
|
||||
Inject,
|
||||
InjectionToken,
|
||||
OnDestroy,
|
||||
QueryList,
|
||||
ViewChild,
|
||||
ViewEncapsulation,
|
||||
} from '@angular/core';
|
||||
import { NgControl } from '@angular/forms';
|
||||
import { MatFormFieldControl } from '@angular/material/form-field';
|
||||
import { Subject } from 'rxjs';
|
||||
import { startWith, takeUntil } from 'rxjs/operators';
|
||||
|
||||
import { cnslFormFieldAnimations } from './animations';
|
||||
import { CNSL_ERROR, CnslErrorDirective } from './error.directive';
|
||||
import { _CNSL_HINT, CnslHintDirective } from './hint.directive';
|
||||
|
||||
export const CNSL_FORM_FIELD = new InjectionToken<CnslFormFieldComponent>('CnslFormFieldComponent');
|
||||
|
||||
class CnslFormFieldBase {
|
||||
constructor(public _elementRef: ElementRef) { }
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-form-field',
|
||||
templateUrl: './form-field.component.html',
|
||||
styleUrls: ['./form-field.component.scss'],
|
||||
providers: [
|
||||
{ provide: CNSL_FORM_FIELD, useExisting: CnslFormFieldComponent },
|
||||
],
|
||||
host: {
|
||||
'[class.ng-untouched]': '_shouldForward("untouched")',
|
||||
'[class.ng-touched]': '_shouldForward("touched")',
|
||||
'[class.ng-pristine]': '_shouldForward("pristine")',
|
||||
'[class.ng-dirty]': '_shouldForward("dirty")',
|
||||
'[class.ng-valid]': '_shouldForward("valid")',
|
||||
'[class.ng-invalid]': '_shouldForward("invalid")',
|
||||
'[class.ng-pending]': '_shouldForward("pending")',
|
||||
// '[class.cnsl-form-field-invalid]': '_control.errorState',
|
||||
},
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
animations: [cnslFormFieldAnimations.transitionMessages],
|
||||
})
|
||||
export class CnslFormFieldComponent extends CnslFormFieldBase implements OnDestroy, AfterContentInit, AfterViewInit {
|
||||
focused: boolean = false;
|
||||
private _destroyed: Subject<void> = new Subject<void>();
|
||||
|
||||
@ViewChild('connectionContainer', { static: true }) _connectionContainerRef!: ElementRef;
|
||||
@ViewChild('inputContainer') _inputContainerRef!: ElementRef;
|
||||
@ContentChild(MatFormFieldControl) _controlNonStatic!: MatFormFieldControl<any>;
|
||||
@ContentChild(MatFormFieldControl, { static: true }) _controlStatic!: MatFormFieldControl<any>;
|
||||
get _control(): MatFormFieldControl<any> {
|
||||
// TODO(crisbeto): we need this workaround in order to support both Ivy and ViewEngine.
|
||||
// We should clean this up once Ivy is the default renderer.
|
||||
return this._explicitFormFieldControl || this._controlNonStatic || this._controlStatic;
|
||||
}
|
||||
set _control(value: MatFormFieldControl<any>) {
|
||||
this._explicitFormFieldControl = value;
|
||||
}
|
||||
private _explicitFormFieldControl!: MatFormFieldControl<any>;
|
||||
readonly stateChanges: Subject<void> = new Subject<void>();
|
||||
|
||||
_subscriptAnimationState: string = '';
|
||||
|
||||
@ContentChildren(CNSL_ERROR as any, { descendants: true }) _errorChildren!: QueryList<CnslErrorDirective>;
|
||||
@ContentChildren(_CNSL_HINT, { descendants: true }) _hintChildren!: QueryList<CnslHintDirective>;
|
||||
|
||||
@HostListener('blur', ['false'])
|
||||
_focusChanged(isFocused: boolean): void {
|
||||
console.log('blur1');
|
||||
if (isFocused !== this.focused && (!isFocused)) {
|
||||
this.focused = isFocused;
|
||||
this.stateChanges.next();
|
||||
}
|
||||
}
|
||||
|
||||
constructor(public _elementRef: ElementRef, private _changeDetectorRef: ChangeDetectorRef,
|
||||
@Inject(ElementRef)
|
||||
// Use `ElementRef` here so Angular has something to inject.
|
||||
_labelOptions: any) {
|
||||
super(_elementRef);
|
||||
|
||||
}
|
||||
|
||||
public ngAfterViewInit(): void {
|
||||
// Avoid animations on load.
|
||||
this._subscriptAnimationState = 'enter';
|
||||
this._changeDetectorRef.detectChanges();
|
||||
}
|
||||
|
||||
public ngOnDestroy(): void {
|
||||
this._destroyed.next();
|
||||
this._destroyed.complete();
|
||||
}
|
||||
|
||||
public ngAfterContentInit(): void {
|
||||
this._validateControlChild();
|
||||
|
||||
const control = this._control;
|
||||
control.stateChanges.pipe(startWith(null)).subscribe(() => {
|
||||
this._syncDescribedByIds();
|
||||
this._changeDetectorRef.markForCheck();
|
||||
});
|
||||
|
||||
// Run change detection if the value changes.
|
||||
if (control.ngControl && control.ngControl.valueChanges) {
|
||||
control.ngControl.valueChanges
|
||||
.pipe(takeUntil(this._destroyed))
|
||||
.subscribe(() => this._changeDetectorRef.markForCheck());
|
||||
}
|
||||
|
||||
// Update the aria-described by when the number of errors changes.
|
||||
this._errorChildren.changes.pipe(startWith(null)).subscribe(() => {
|
||||
this._syncDescribedByIds();
|
||||
this._changeDetectorRef.markForCheck();
|
||||
});
|
||||
}
|
||||
|
||||
/** Throws an error if the form field's control is missing. */
|
||||
protected _validateControlChild(): void {
|
||||
if (!this._control) {
|
||||
throw Error('cnsl-form-field must contain a MatFormFieldControl.');
|
||||
}
|
||||
}
|
||||
|
||||
private _syncDescribedByIds(): void {
|
||||
if (this._control) {
|
||||
const ids: string[] = [];
|
||||
|
||||
// TODO(wagnermaciel): Remove the type check when we find the root cause of this bug.
|
||||
if (this._control.userAriaDescribedBy &&
|
||||
typeof this._control.userAriaDescribedBy === 'string') {
|
||||
ids.push(...this._control.userAriaDescribedBy.split(' '));
|
||||
}
|
||||
|
||||
if (this._errorChildren) {
|
||||
ids.push(...this._errorChildren.map(error => error.id));
|
||||
}
|
||||
|
||||
this._control.setDescribedByIds(ids);
|
||||
}
|
||||
}
|
||||
|
||||
/** Determines whether a class from the NgControl should be forwarded to the host element. */
|
||||
_shouldForward(prop: keyof NgControl): boolean {
|
||||
const ngControl = this._control ? this._control.ngControl : null;
|
||||
return ngControl && ngControl[prop];
|
||||
}
|
||||
|
||||
/** Determines whether to display hints or errors. */
|
||||
_getDisplayedMessages(): 'error' | 'hint' {
|
||||
return (this._errorChildren && this._errorChildren.length > 0) ? 'error' : 'hint';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { MatRippleModule } from '@angular/material/core';
|
||||
import { LabelModule } from 'src/app/modules/label/label.module';
|
||||
|
||||
import { LabelComponent } from '../label/label.component';
|
||||
import { CnslErrorDirective } from './error.directive';
|
||||
import { CnslFormFieldComponent } from './form-field.component';
|
||||
import { CnslHintDirective } from './hint.directive';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
CnslFormFieldComponent,
|
||||
CnslErrorDirective,
|
||||
CnslHintDirective,
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
MatRippleModule,
|
||||
LabelModule,
|
||||
],
|
||||
exports: [
|
||||
CnslFormFieldComponent,
|
||||
LabelComponent,
|
||||
CnslErrorDirective,
|
||||
CnslHintDirective,
|
||||
],
|
||||
})
|
||||
export class FormFieldModule { }
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import { Directive, InjectionToken, Input } from '@angular/core';
|
||||
|
||||
let nextUniqueId = 0;
|
||||
|
||||
/**
|
||||
* Injection token that can be used to reference instances of `MatHint`. It serves as
|
||||
* alternative token to the actual `MatHint` class which could cause unnecessary
|
||||
* retention of the class and its directive metadata.
|
||||
*
|
||||
* *Note*: This is not part of the public API as the MDC-based form-field will not
|
||||
* need a lightweight token for `MatHint` and we want to reduce breaking changes.
|
||||
*/
|
||||
export const _CNSL_HINT = new InjectionToken<CnslHintDirective>('CnslHintDirective');
|
||||
|
||||
/** Hint text to be shown underneath the form field control. */
|
||||
@Directive({
|
||||
selector: 'cnsl-hint',
|
||||
host: {
|
||||
'class': 'cnsl-hint',
|
||||
'[class.cnsl-form-field-hint-end]': 'align === "end"',
|
||||
'[attr.id]': 'id',
|
||||
// Remove align attribute to prevent it from interfering with layout.
|
||||
'[attr.align]': 'null',
|
||||
},
|
||||
providers: [{ provide: _CNSL_HINT, useExisting: CnslHintDirective }],
|
||||
})
|
||||
export class CnslHintDirective {
|
||||
/** Whether to align the hint label at the start or end of the line. */
|
||||
@Input() align: 'start' | 'end' = 'start';
|
||||
|
||||
/** Unique ID for the hint. Used for the aria-describedby on the form field control. */
|
||||
@Input() id: string = `mat-hint-${nextUniqueId++}`;
|
||||
}
|
||||
Reference in New Issue
Block a user