diff --git a/package.json b/package.json index e7508933..1afecedd 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,7 @@ "build": "npm run build:core && npm run build:plugins", "build:core": "rimraf --glob \"packages/imask/{dist,esm}\" && lerna run build --scope=imask", "build:react": "rimraf --glob \"packages/react-imask/{dist,esm}\" && lerna run build --scope=react-imask", + "build:angular": "rimraf --glob \"packages/angular-imask/dist\" && lerna run build --scope=angular-imask", "build:plugins": "rimraf --glob \"packages/!(imask)/{dist,esm}\" && lerna run build --ignore=imask", "test": "lerna run test --parallel", "make": "npm run test && npm run build", diff --git a/packages/angular-imask/example/app/app.component.ts b/packages/angular-imask/example/app/app.component.ts index b4511ea6..b0ddce2e 100644 --- a/packages/angular-imask/example/app/app.component.ts +++ b/packages/angular-imask/example/app/app.component.ts @@ -1,11 +1,10 @@ import { Component } from '@angular/core'; -import { IMaskDirective, IMASK_FACTORY } from 'angular-imask'; +import { IMASK_FACTORY } from 'angular-imask'; import { NumberIMaskFactory } from './number-imask-factory'; @Component({ selector: 'app-root', standalone: true, - imports: [IMaskDirective], providers: [ {provide: IMASK_FACTORY, useClass: NumberIMaskFactory} // it's optional ], diff --git a/packages/angular-imask/example/app/app.module.ts b/packages/angular-imask/example/app/app.module.ts new file mode 100644 index 00000000..c2012c58 --- /dev/null +++ b/packages/angular-imask/example/app/app.module.ts @@ -0,0 +1,19 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { IMaskModule } from 'angular-imask'; + +import { AppComponent } from './app.component'; + + +@NgModule({ + declarations: [ + AppComponent + ], + imports: [ + IMaskModule, + BrowserModule + ], + providers: [], + bootstrap: [AppComponent] +}) +export class AppModule { } diff --git a/packages/angular-imask/example/index.html b/packages/angular-imask/example/index.html index 0b2a9d56..6e1f31e3 100644 --- a/packages/angular-imask/example/index.html +++ b/packages/angular-imask/example/index.html @@ -2,7 +2,7 @@ - Example + Angular IMask Example diff --git a/packages/angular-imask/src/imask.directive.ts b/packages/angular-imask/src/imask.directive.ts index 0b670e68..e167b2d6 100644 --- a/packages/angular-imask/src/imask.directive.ts +++ b/packages/angular-imask/src/imask.directive.ts @@ -8,6 +8,9 @@ import { import { NG_VALUE_ACCESSOR, ControlValueAccessor, COMPOSITION_BUFFER_MODE } from '@angular/forms'; import { IMASK_FACTORY } from './imask-factory-token'; +export +type Falsy = false | 0 | "" | null | undefined; + export const MASKEDINPUT_VALUE_ACCESSOR: Provider = { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => IMaskDirective), @@ -27,7 +30,13 @@ export const DEFAULT_IMASK_ELEMENT = (elementRef: any) => elementRef.nativeEleme }, providers: [MASKEDINPUT_VALUE_ACCESSOR], }) -export class IMaskDirective implements ControlValueAccessor, AfterViewInit, OnDestroy, OnChanges { +export class IMaskDirective< + Opts extends IMask.AnyMaskedOptions, + Unmask extends ('typed' | boolean) = false, + Value = Unmask extends 'typed' ? IMask.InputMask['typedValue'] : + Unmask extends Falsy ? IMask.InputMask['value'] : + IMask.InputMask['unmaskedValue'] +> implements ControlValueAccessor, AfterViewInit, OnDestroy, OnChanges { maskRef?: IMask.InputMask; onTouched: any = () => {}; onChange: any = () => {}; @@ -43,28 +52,28 @@ export class IMaskDirective implements Cont private _compositionMode = inject(COMPOSITION_BUFFER_MODE, {optional: true}) ?? !this._isAndroid(); @Input() imask?: Opts; - @Input() unmask?: boolean|'typed'; + @Input() unmask?: Unmask; @Input() imaskElement: (elementRef: ElementRef, directiveRef: any) => IMask.MaskElement = DEFAULT_IMASK_ELEMENT; - @Output() accept = new EventEmitter(); - @Output() complete = new EventEmitter(); + @Output() accept = new EventEmitter(); + @Output() complete = new EventEmitter(); get element () { return this.imaskElement(this._elementRef, this); } - get maskValue (): any { - if (!this.maskRef) return this.element.value; + get maskValue (): Value { + if (!this.maskRef) return this.element.value as unknown as Value; - if (this.unmask === 'typed') return this.maskRef.typedValue; - if (this.unmask) return this.maskRef.unmaskedValue; - return this.maskRef.value; + if (this.unmask === 'typed') return this.maskRef.typedValue as unknown as Value; + if (this.unmask) return this.maskRef.unmaskedValue as unknown as Value; + return this.maskRef.value as unknown as Value; } - set maskValue (value: any) { + set maskValue (value: Value) { if (this.maskRef) { - if (this.unmask === 'typed') this.maskRef.typedValue = value; - else if (this.unmask) this.maskRef.unmaskedValue = value; - else this.maskRef.value = value; + if (this.unmask === 'typed') this.maskRef.typedValue = value as unknown as IMask.MaskedTypedValue; + else if (this.unmask) this.maskRef.unmaskedValue = value as unknown as IMask.InputMask['unmaskedValue']; + else this.maskRef.value = value as unknown as IMask.InputMask['value']; } else { this._renderer.setProperty(this.element, 'value', value); } @@ -105,18 +114,18 @@ export class IMaskDirective implements Cont this.complete.complete(); } - beginWrite (value: any): void { + beginWrite (value: Value): void { this._writing = true; this._writingValue = value; } - endWrite (): any { + endWrite (): Value { this._writing = false; return this._writingValue; } - writeValue(value: any) { - value = value == null && this.unmask !== 'typed' ? '' : value; + writeValue(value: Value) { + value = (value == null && this.unmask !== 'typed' ? '' : value) as Value; if (this.maskRef) { this.beginWrite(value); @@ -141,7 +150,7 @@ export class IMaskDirective implements Cont } private initMask () { - this.maskRef = this._factory.create(this.element, this.imask as Opts) + this.maskRef = this._factory.create(this.element, this.imask) .on('accept', this._onAccept.bind(this)) .on('complete', this._onComplete.bind(this)); } diff --git a/packages/react-imask/src/mixin.ts b/packages/react-imask/src/mixin.ts index 24d68bf7..d0253332 100644 --- a/packages/react-imask/src/mixin.ts +++ b/packages/react-imask/src/mixin.ts @@ -244,7 +244,7 @@ export default function IMaskMixin< } set maskValue (value: Value) { - value = (value == null ? '' : value) as Value; + value = (value == null && this.props.unmask !== 'typed' ? '' : value) as Value; if (this.props.unmask === 'typed') this.maskRef.typedValue = value as unknown as IMask.MaskedTypedValue; else if (this.props.unmask) this.maskRef.unmaskedValue = value as unknown as IMask.InputMask['unmaskedValue']; else this.maskRef.value = value as unknown as IMask.InputMask['value'];