From e5eb2b38d9d3178cf9440a6e34de9afafa9491c9 Mon Sep 17 00:00:00 2001 From: demensky Date: Sat, 24 Feb 2024 17:39:47 +0200 Subject: [PATCH 1/2] feat(angular): integrate `MaskitoCVA` to `MaskitoDirective` Now the `MaskitoDirective` directive can perform the functions of the `MaskitoCVA` directive. This change will allow us to avoid the situation where the developer forgot to import `MaskitoCVA`, now it just works using `MaskitoDirective`. `MaskitoCVA` was left as a placeholder to avoid a breaking change. --- projects/angular/src/index.ts | 1 - projects/angular/src/lib/deprecated.ts | 18 +++++++-- projects/angular/src/lib/maskito.cva.ts | 39 ------------------- projects/angular/src/lib/maskito.directive.ts | 29 +++++++++++--- projects/angular/src/lib/maskito.spec.ts | 4 +- .../angular/angular-doc.component.ts | 10 ++--- .../angular/angular-doc.template.html | 14 +++---- .../component.ts | 12 ++---- .../template.html | 0 9 files changed, 56 insertions(+), 71 deletions(-) delete mode 100644 projects/angular/src/lib/maskito.cva.ts rename projects/demo/src/pages/frameworks/angular/examples/{3-cva => 3-programmatically}/component.ts (69%) rename projects/demo/src/pages/frameworks/angular/examples/{3-cva => 3-programmatically}/template.html (100%) diff --git a/projects/angular/src/index.ts b/projects/angular/src/index.ts index d8f6c23d5..cf7639c90 100644 --- a/projects/angular/src/index.ts +++ b/projects/angular/src/index.ts @@ -1,4 +1,3 @@ export * from './lib/deprecated'; -export * from './lib/maskito.cva'; export * from './lib/maskito.directive'; export * from './lib/maskito.pipe'; diff --git a/projects/angular/src/lib/deprecated.ts b/projects/angular/src/lib/deprecated.ts index d3bd2c48f..2589ab269 100644 --- a/projects/angular/src/lib/deprecated.ts +++ b/projects/angular/src/lib/deprecated.ts @@ -1,11 +1,23 @@ -import {NgModule} from '@angular/core'; +import {Directive, Input, NgModule} from '@angular/core'; +import {MaskitoOptions} from '@maskito/core'; -import {MaskitoCVA} from './maskito.cva'; import {MaskitoDirective} from './maskito.directive'; import {MaskitoPipe} from './maskito.pipe'; /** - * @deprecated Use standalone `MaskitoDirective`, `MaskitoCVA` and `MaskitoPipe` instead. + * @deprecated Just use `MaskitoDirective`, `MaskitoCVA` no longer needed. + */ +@Directive({ + standalone: true, + selector: 'input[maskito], textarea[maskito]', +}) +export class MaskitoCVA { + @Input() + maskito?: MaskitoOptions | null; +} + +/** + * @deprecated Use standalone `MaskitoDirective` and `MaskitoPipe` instead. * Learn more: https://maskito.dev/frameworks/angular * ___ * TODO: Delete it in v3.0 (after Taiga UI 4.0 will be released and bumped in this repository). diff --git a/projects/angular/src/lib/maskito.cva.ts b/projects/angular/src/lib/maskito.cva.ts deleted file mode 100644 index fc83e1ff3..000000000 --- a/projects/angular/src/lib/maskito.cva.ts +++ /dev/null @@ -1,39 +0,0 @@ -import {Directive, Input} from '@angular/core'; -import {DefaultValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms'; -import {MASKITO_DEFAULT_OPTIONS, MaskitoOptions, maskitoTransform} from '@maskito/core'; - -@Directive({ - standalone: true, - selector: 'input[maskito], textarea[maskito]', - providers: [ - DefaultValueAccessor, - { - provide: NG_VALUE_ACCESSOR, - multi: true, - useExisting: DefaultValueAccessor, - }, - ], - host: { - '(input)': '$any(this.accessor)._handleInput($event.target.value)', - '(blur)': 'accessor.onTouched()', - '(compositionstart)': '$any(this.accessor)._compositionStart()', - '(compositionend)': '$any(this.accessor)._compositionEnd($event.target.value)', - }, -}) -export class MaskitoCVA { - @Input() - maskito: MaskitoOptions | null = MASKITO_DEFAULT_OPTIONS; - - constructor(readonly accessor: DefaultValueAccessor) { - const original = accessor.writeValue.bind(accessor); - - accessor.writeValue = (value: unknown) => { - original( - maskitoTransform( - String(value ?? ''), - this.maskito ?? MASKITO_DEFAULT_OPTIONS, - ), - ); - }; - } -} diff --git a/projects/angular/src/lib/maskito.directive.ts b/projects/angular/src/lib/maskito.directive.ts index dd8f8d1b5..302752809 100644 --- a/projects/angular/src/lib/maskito.directive.ts +++ b/projects/angular/src/lib/maskito.directive.ts @@ -6,13 +6,17 @@ import { NgZone, OnChanges, OnDestroy, + Optional, + Self, } from '@angular/core'; +import {DefaultValueAccessor} from '@angular/forms'; import { Maskito, MASKITO_DEFAULT_ELEMENT_PREDICATE, MASKITO_DEFAULT_OPTIONS, MaskitoElementPredicate, MaskitoOptions, + maskitoTransform, } from '@maskito/core'; @Directive({standalone: true, selector: '[maskito]'}) @@ -20,7 +24,7 @@ export class MaskitoDirective implements OnDestroy, OnChanges { private maskedElement: Maskito | null = null; @Input() - maskito: MaskitoOptions | null = MASKITO_DEFAULT_OPTIONS; + maskito: MaskitoOptions | null = null; @Input() maskitoElement: MaskitoElementPredicate = MASKITO_DEFAULT_ELEMENT_PREDICATE; @@ -28,7 +32,23 @@ export class MaskitoDirective implements OnDestroy, OnChanges { constructor( @Inject(NgZone) private readonly ngZone: NgZone, @Inject(ElementRef) private readonly elementRef: ElementRef, - ) {} + @Inject(DefaultValueAccessor) + @Self() + @Optional() + accessor: DefaultValueAccessor | null, + ) { + if (accessor !== null) { + const original = accessor.writeValue.bind(accessor); + + accessor.writeValue = (value: unknown) => { + original(maskitoTransform(String(value ?? ''), this.options)); + }; + } + } + + private get options(): MaskitoOptions { + return this.maskito ?? MASKITO_DEFAULT_OPTIONS; + } async ngOnChanges(): Promise { this.maskedElement?.destroy(); @@ -43,10 +63,7 @@ export class MaskitoDirective implements OnDestroy, OnChanges { } this.ngZone.runOutsideAngular(() => { - this.maskedElement = new Maskito( - predicateResult, - this.maskito ?? MASKITO_DEFAULT_OPTIONS, - ); + this.maskedElement = new Maskito(predicateResult, this.options); }); } diff --git a/projects/angular/src/lib/maskito.spec.ts b/projects/angular/src/lib/maskito.spec.ts index 8a5875c53..3e5ec304c 100644 --- a/projects/angular/src/lib/maskito.spec.ts +++ b/projects/angular/src/lib/maskito.spec.ts @@ -1,13 +1,13 @@ import {Component} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; import {FormControl, ReactiveFormsModule} from '@angular/forms'; -import {MaskitoCVA, MaskitoDirective, MaskitoPipe} from '@maskito/angular'; +import {MaskitoDirective, MaskitoPipe} from '@maskito/angular'; import {MaskitoOptions} from '@maskito/core'; describe('Maskito Angular package', () => { @Component({ standalone: true, - imports: [MaskitoDirective, MaskitoCVA, MaskitoPipe, ReactiveFormsModule], + imports: [MaskitoDirective, MaskitoPipe, ReactiveFormsModule], template: `
{{ control.value | maskito: options }}
Nested input element - + When directly on native input/textarea tag, - MaskitoCVA + MaskitoDirective formats value set programmatically with Angular forms. - + Date: Mon, 26 Feb 2024 15:09:53 +0300 Subject: [PATCH 2/2] chore: fix review comment --- projects/angular/src/lib/maskito.directive.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/angular/src/lib/maskito.directive.ts b/projects/angular/src/lib/maskito.directive.ts index 302752809..6811b0445 100644 --- a/projects/angular/src/lib/maskito.directive.ts +++ b/projects/angular/src/lib/maskito.directive.ts @@ -37,7 +37,7 @@ export class MaskitoDirective implements OnDestroy, OnChanges { @Optional() accessor: DefaultValueAccessor | null, ) { - if (accessor !== null) { + if (accessor) { const original = accessor.writeValue.bind(accessor); accessor.writeValue = (value: unknown) => {