import {
Component, Input, Output, EventEmitter, trigger, HostBinding,
state, style, transition, animate, OnInit, OnChanges,
forwardRef, ViewChild, ElementRef
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR, NgModel } from '@angular/forms';
import { InputTypes } from './input-types';
import './input.scss';
let nextId = 0;
const INPUT_VALUE_ACCESSOR = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => InputComponent),
multi: true
};
@Component({
selector: 'swui-input',
providers: [INPUT_VALUE_ACCESSOR],
template: `
`,
animations: [
trigger('labelState', [
state('inside', style({
'font-size': '1rem',
top: '0',
})),
state('outside', style({
'font-size': '.7rem',
top: '-15px',
})),
transition('inside => outside', animate('150ms ease-out')),
transition('outside => inside', animate('150ms ease-out'))
]),
trigger('underlineState', [
state('collapsed', style({
width: '0%',
})),
state('expanded', style({
width: '100%',
})),
transition('collapsed => expanded', animate('150ms ease-out')),
transition('expanded => collapsed', animate('150ms ease-out'))
])
]
})
export class InputComponent implements OnInit, ControlValueAccessor {
@Input() id: string = `input-${++nextId}`;
@Input() name: string;
@Input() label: string = '';
@Input() type: InputTypes = InputTypes.text;
@Input() hint: string;
@Input() placeholder: string = '';
@Input() disabled: boolean = false;
@Input() tabindex: number;
@Input() min: number;
@Input() max: number;
@Input() required: boolean = false;
@Input() requiredIndicator: string|boolean = '*';
@Input() passwordToggleEnabled: boolean = true;
@Input() passwordTextVisible: boolean = false;
@Input() autofocus: boolean = false;
@Input() autocomplete: boolean = false;
@Input() autocorrect: boolean = false;
@Input() spellcheck: boolean = false;
@Output() change = new EventEmitter();
@Output() blur = new EventEmitter();
@Output() focus = new EventEmitter();
@Output() keyup = new EventEmitter();
@Output() click = new EventEmitter();
get value(): string {
return this._value;
}
set value(val: string) {
if (val !== this._value) {
this._value = val;
this.onChangeCallback(this._value);
}
}
get focusedOrDirty(): any {
return this.focused || (this.value && this.value.length);
}
@HostBinding('class')
private get getHostCssClasses(): string {
return 'swui-input';
}
private get getCssClasses(): any {
return {
'ng-invalid': this.inputModel.invalid,
'ng-touched': this.inputModel.touched,
'ng-valid': this.inputModel.valid
};
}
@ViewChild('inputModel')
private inputModel: NgModel;
@ViewChild('inputControl')
private inputControl: ElementRef;
@ViewChild('passwordControl')
private passwordControl: ElementRef;
private get labelState(): string {
if (this.focusedOrDirty) return 'outside';
return 'inside';
}
private get underlineState(): string {
if (this.focused) return 'expanded';
return 'collapsed';
}
private get requiredIndicatorView(): string {
if(!this.requiredIndicator || !this.required) return '';
return this.requiredIndicator as string;
}
private focused: boolean = false;
private _value: string;
ngOnInit() {
if(!this.value) this.value = '';
}
ngAfterViewInit() {
if(this.autofocus) {
setTimeout(() => {
this.inputControl.nativeElement.focus();
});
}
}
onChange(event) {
event.stopPropagation();
this.change.emit(this.value);
}
onKeyUp(event) {
event.stopPropagation();
this.keyup.emit(event);
}
onFocus(event) {
event.stopPropagation();
this.focused = true;
this.focus.emit(event);
this.onTouchedCallback();
}
onBlur(event) {
event.stopPropagation();
this.focused = false;
this.blur.emit(event);
}
writeValue(val: string) {
if (val !== this._value) {
this._value = val;
}
}
registerOnChange(fn: any) {
this.onChangeCallback = fn;
}
registerOnTouched(fn: any) {
this.onTouchedCallback = fn;
}
togglePassword() {
this.passwordTextVisible = !this.passwordTextVisible;
setTimeout(() => {
if(this.passwordTextVisible) {
this.passwordControl.nativeElement.focus();
} else {
this.inputControl.nativeElement.focus();
}
});
}
private onTouchedCallback: () => void = () => {
// placeholder
}
private onChangeCallback: (_: any) => void = () => {
// placeholder
}
}