UNPKG

ngx-input-eip

Version:

Lightweight edit in place text editor.

852 lines (839 loc) 46.9 kB
import * as i0 from '@angular/core'; import { Directive, Input, EventEmitter, TemplateRef, forwardRef, Component, Output, ViewChild, NgModule } from '@angular/core'; import * as i2 from '@angular/forms'; import { FormGroup, FormControl, Validators, NG_VALUE_ACCESSOR, ReactiveFormsModule } from '@angular/forms'; import { distinctUntilChanged } from 'rxjs/operators'; import * as i1 from '@angular/common'; import { CommonModule } from '@angular/common'; const Messages = { required: 'This field cannot be blank!', email: `Invalid email!`, numbersOnly: `Only numbers are allowed!`, invalid_http_url: `Invalid http url`, numberOnly: `The value entered is not a number!`, minlength: (e) => `Minimum length: ${e.requiredLength}, current length: ${e.actualLength}`, InvalidFormat: (error) => `"${error.value}" is not a valid format. Valid example: "${error.validExample}"`, pattern: (error) => `"${error.actualValue}" is not a valid format. The format must follow the following regular expression (RegExp): "${error.requiredPattern}"`, max: (e) => `The value entered is too large! Maximum value: ${e.max}, current value: ${e.actual}`, maxlength: (e) => `The value entered is too long! Max length: ${e.requiredLength}, current length: ${e.actualLength}`, }; class ErrorsManager { static formatErrors(errors, customErrorMessages) { return new ErrorsManager(errors, customErrorMessages).formatErrors(); } constructor(errors, customMessages = Messages) { this.defaultMessages = Messages; this.messages = {}; this.enableLogging = false; this.errors = errors; if (customMessages) this.mergeMessages(customMessages); else this.assignDefaults(); } assignDefaults() { this.messages = {}; Object.keys(this.defaultMessages).forEach((key) => { this.messages[key] = this.defaultMessages[key]; }); } mergeMessages(messages) { const keys = [ ...Object.keys(this.defaultMessages), ...Object.keys(messages) ]; keys.forEach((key) => { if (messages[key]) { this.messages[key] = messages[key]; } else { this.messages[key] = this.defaultMessages[key]; } }); } formatErrors() { const result = [ ...this.errorMsgFromControl() ]; /** * TODO write here your custom logic of parsing errors. */ return result; } warn(...args) { if (!(this.enableLogging)) return; console.warn(...args); } errorMsgFromControl() { if (this.errors == undefined || this.errors == null) return []; var messages = []; Object.keys(this.errors).filter((key) => { if (this.messages.hasOwnProperty(key) && this.messages[key] && this.messages[key] != undefined) { const field = this.messages[key]; switch (typeof field) { case 'string': messages.push(field); break; case 'function': messages.push(field(this.errors[key])); break; default: messages.push(field); break; } return; } this.warn(`ReactiveFormsErrors missing error message of "${key}". Parser error with your custom logic.`); var msg = {}; msg[key] = this.errors[key]; if (!(typeof msg == 'string')) msg = JSON.stringify(msg); messages.push(msg); }); return messages; } } function DefaultErrorsParser(c, customErrorMessages) { const errors = c.errors; if (!(errors && Object.keys(errors).length > 0)) { return []; } return ErrorsManager.formatErrors(errors, customErrorMessages); } class BaseClass { } /** * Event to trigger (manually) and to listen to when the value of the input changes. */ const CustomChangeEvent = 'ngx-autosize'; const InputsDefaults = { isShort: true, isMandatory: false, enableValidations: true, placeholder: 'Type here...', label: '', showLabel: true, autosave: null, classes: '', customValidators: [], isDisabled: false, numbersOnly: false, min: undefined, max: undefined, maxLength: undefined, minLength: undefined, submitButtonLabel: 'Confirm', cancelButtonLabel: 'Cancel', actionbarMode: null, animateActionbar: true, allowInvalid: false, errorsParser: DefaultErrorsParser, showErrors: true, customErrorMessages: [], customErrorsMap: {}, inputStyle: {}, selectOnFocus: true, }; const selector$1 = 'resizableTextareaContainer'; class ResizableTextareaContainerDirective { constructor(el, cd) { this.el = el; this.cd = cd; this.enabled = true; this.defaultHeight = 'auto'; this.element = this.el.nativeElement; } ngAfterViewInit() { this.init(); } get textarea() { return this.element.childNodes[0]; } get container() { return this.element; } get style() { return this.element.style; } get diff() { return Number(this.style.paddingBottom) + Number(this.style.paddingTop); } set height(v) { if (typeof v == 'number') v = `${v}px`; if (!(v && typeof v == 'string' && v.length > 0 && v.indexOf('px') >= 0)) { this.height = this.defaultHeight; return; } if (this.textarea) this.textarea.style.height = v; if (this.container) this.container.style.minHeight = `${Number(v.replace('px', '')) + 8}px`; } get height() { return this.textarea?.scrollHeight; } init() { this.setInitialHeight(); if (!(this.textarea)) { // No textarea found, try later. setTimeout(() => this.init(), 500); return; } this.textarea.addEventListener(`${CustomChangeEvent}`, () => { this.updateHeight(); }); this.updateHeight(); } containsText() { return !!(this.textarea && this.textarea.value.length > 0); } setInitialHeight() { if (this.containsText()) { this.height = `${this.element.scrollHeight - this.diff}px`; } } updateHeight() { this.textarea.style.height = '0px'; this.height = `${this.textarea.scrollHeight - this.diff}px`; this.textarea.dispatchEvent(new CustomEvent('resize')); // window.scroll({ top: this.textarea!.offsetTop + this.textarea!.offsetHeight }); } } ResizableTextareaContainerDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ResizableTextareaContainerDirective, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive }); ResizableTextareaContainerDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.9", type: ResizableTextareaContainerDirective, selector: "[resizableTextareaContainer]", inputs: { enabled: ["resizableTextareaContainer", "enabled"] }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ResizableTextareaContainerDirective, decorators: [{ type: Directive, args: [{ selector: `[${selector$1}]` }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { enabled: [{ type: Input, args: [selector$1] }] } }); const selector = 'ngx-input-eip'; class NgxInputEipComponent extends BaseClass { constructor() { super(...arguments); this.onSubmit = new EventEmitter(); this.onCancel = new EventEmitter(); /** * Emit events using this subject. * The events that will be emitted outside will be filtered. */ this.areUnsavedChanges$ = new EventEmitter(); this._areUnsavedChanges = this.areUnsavedChanges$.pipe(distinctUntilChanged()); /** * This events are listened and emitted from the input. */ this.onChange = new EventEmitter(); this.onInput = new EventEmitter(); this.onClick = new EventEmitter(); this.onFocus = new EventEmitter(); this.onResize = new EventEmitter(); this.onDblclick = new EventEmitter(); this.onBlur = new EventEmitter(); this.onKeyDown = new EventEmitter(); this.onKeyPress = new EventEmitter(); this.onKeyUp = new EventEmitter(); /** * @description * If the input is `short`, it will appear as a common text input. * If the input is `long`, it will appear as a textarea. */ this.isShort = InputsDefaults['isShort']; /** * @description * If this input is mandatory, it cannot be empty. * Otherwise its invalid. */ this.isMandatory = InputsDefaults['isMandatory']; /** * @description * If this flag is enabled, errors will be shown. */ this.enableValidations = InputsDefaults['enableValidations']; this.inputStyle = InputsDefaults['inputStyle']; /** * @description * The placeholder for the input. */ this.placeholder = InputsDefaults['placeholder']; /** * @description * The label for the input. * Its not mandatory; * It's possible to pass a custom html-style label too, with `<span label ></span>` attribute. */ this.label = InputsDefaults['label']; /** * @description * Show/Hide label. * This will hide both html-style and text-style labels. */ this.showLabel = InputsDefaults['showLabel']; this.submitButtonLabel = InputsDefaults['submitButtonLabel']; this.cancelButtonLabel = InputsDefaults['cancelButtonLabel']; this.avaliableActionbarMode = [null, 'always', 'show', 'overlay']; this.actionbarMode = InputsDefaults['actionbarMode']; this.animateActionbar = InputsDefaults['animateActionbar']; this._autosave = InputsDefaults['autosave']; this.classes = InputsDefaults['classes']; /** * Adding custom user validators. */ this.customValidators = InputsDefaults['customValidators']; this._isDisabled = InputsDefaults['isDisabled']; /** * Is a input that allows numbers only? * If yes: * - Any non-number character will be removed. * - Arrow up will increase the value by 1. * - Arrow down will decrease the value by 1. * - If the value is empty, it will be set to 0. * - If the value is not a number, it will be set to 0. */ this.numbersOnly = InputsDefaults['numbersOnly']; /** * Minimum value for numerical inputs. */ this.min = InputsDefaults['min']; /** * Maximum value for numerical inputs. */ this.max = InputsDefaults['max']; this.maxLength = InputsDefaults['maxLength']; this.minLength = InputsDefaults['minLength']; this.showErrors = InputsDefaults['showErrors']; this.selectOnFocus = InputsDefaults['selectOnFocus']; /** * @description if false and form invalid, changes will not be emitted. */ this.allowInvalid = InputsDefaults['allowInvalid']; this.customErrorMessages = InputsDefaults['customErrorMessages']; this.customErrorsMap = InputsDefaults['customErrorsMap']; this.errorsParser = null; this.form = new FormGroup({ value: new FormControl('', this.validators) }); this.id = `ngx-input-eip-${Math.random()}`; this.debugMode = false; this.emittedValue = ''; this._registerOnTouched = () => { }; this._registerOnChange = () => { }; } get validActionbarMode() { return this.avaliableActionbarMode.includes(this.actionbarMode); } get defaultActionbarMode() { return this.isShort ? 'overlay' : 'always'; } get actionbarClass() { if (this.autosave) return 'd-none'; if (this.actionbarMode === null) return this.defaultActionbarMode; if (!(this.validActionbarMode)) { console.warn(`${this.constructor.name}.actionbarClass - Invalid actionbarMode: "${this.actionbarMode}"; Setting default "${this.defaultActionbarMode}". Avaliable options are ${this.avaliableActionbarMode}`); return this.defaultActionbarMode; } return this.actionbarMode; } get showActionsBar() { return !this.autosave; } /** * Ask confirm/deny or save automatically. */ set autosave(v) { this._autosave = v; } get autosave() { return this._autosave == null ? this.isShort : this._autosave; } get validators() { const validators = [ ...this.customValidators ]; const addIf = (condition, element) => { if (!condition) return; validators.push(element); }; addIf(this.isMandatory, Validators.required); if (this.numbersOnly) { addIf(this.numbersOnly, Validators.pattern(/^[0-9]*$/)); addIf(!!(this.min != null && this.min && !isNaN(this.min)), Validators.min(this.min)); addIf(!!(this.max != null && this.max && !isNaN(this.max)), Validators.max(this.max)); } else { addIf(!!(this.minLength != null && this.minLength && !isNaN(this.minLength)), Validators.minLength(this.minLength)); addIf(!!(this.maxLength != null && this.maxLength && !isNaN(this.maxLength)), Validators.maxLength(this.maxLength)); } return validators; } set isDisabled(v) { this.setDisabledState(v); } get isDisabled() { return this._isDisabled; } get allErrorsMessages() { if (!this.enableValidations) return []; var final = []; if (this.errorsParser && this.errorsParser != null) { final = this.errorsParser(this.control); } else { final = DefaultErrorsParser(this.control, (this.customErrorsMap || {})); } if (this.customErrorMessages && Array.isArray(this.customErrorMessages)) final = final.concat(this.customErrorMessages); return final; } get stringErrorMessages() { return this.allErrorsMessages.filter(e => typeof e === 'string'); } get templateErrorMessages() { return this.allErrorsMessages.filter(e => e instanceof TemplateRef); } get hasErrors() { return this.allErrorsMessages.length > 0; } get value() { return this.form.value.value; } set value(value) { this.form.patchValue({ value }); } get control() { return this.form.get('value'); } get isLong() { return !(this.isShort); } get invalidForm() { return this.form.invalid; } get showInvalidStatus() { return this.invalidForm && this.enableValidations && (this.control.touched || this.control.dirty); } get isEmpty() { if (this.value === undefined || this.value === null) return true; const value = `${this.value}`.trim(); return !(value.length > 0); } get inputStatusClass() { if (this.showInvalidStatus) { return 'invalid'; } if (this.isEmpty) { return 'empty'; } return ''; } set overwriteValue(v) { this.writeValue(v); } get areUnsavedChanges() { return this.emittedValue !== this.value; } get debugJson() { return { inputs: { isShort: this.isShort, enableValidations: this.enableValidations, isDisabled: this.isDisabled, isMandatory: this.isMandatory, label: this.label, placeholder: this.placeholder, autosave: this.autosave, showLabel: this.showLabel, numbersOnly: this.numbersOnly, min: this.min, max: this.max, classes: this.classes, customValidators: this.customValidators, minLength: this.minLength, maxLength: this.maxLength, actionbarMode: this.actionbarMode, actionbarClass: this.actionbarClass, allowInvalid: this.allowInvalid, }, internal: { value: this.value, emittedValue: this.emittedValue, areUnsavedChanges: this.areUnsavedChanges, showInvalidStatus: this.showInvalidStatus, control: { isEmpty: this.isEmpty, invalid: this.invalidForm, errors: this.control.errors, validators: this.validators }, } }; } /** * CONSTRUCTOR NOT NEEDED HERE */ /***************************************************************** * Angular lifecycle hooks *****************************************************************/ ngOnInit() { // super.ngOnInit(); this.validateInputs(); this.onInput.subscribe(ev => this.afterInput(ev)); this.onClick.subscribe(ev => this.afterClick(ev)); this.onFocus.subscribe(ev => this.afterFocus(ev)); this.onKeyDown.subscribe(ev => this.afterKeyDown(ev)); } ngAfterViewInit() { // super.ngAfterViewInit(); this.updateValidators(); this.control.valueChanges.subscribe(() => { this.triggerResize(); }); } ngOnDestroy() { // super.ngOnDestroy(); } /** * Triggered when any input changes. */ ngOnChanges(changes) { Object.keys(changes).forEach((key) => { switch (key) { case 'isMandatory': case 'enableValidations': case 'minLength': case 'maxLength': case 'min': case 'max': case 'numbersOnly': case 'customValidators': this.updateValidators(); break; } }); setTimeout(() => { this.triggerResize(); }); this.validateInputs(); } ngDoCheck(...args) { // super.ngDoCheck(args); } ngAfterContentInit(...args) { // super.ngAfterContentInit(args); } ngAfterContentChecked(...args) { // super.ngAfterContentChecked(args); } ngAfterViewChecked(...args) { // super.ngAfterViewChecked(args); } /***************************************************************** * Public methods *****************************************************************/ afterKeyDown(ev) { var done = () => { this.valueChanges(); }; if (ev.key === 'Escape') { // TODO // cancel but save in localStorage or cookies the element. // Then show to the user the possibility to restore the element. if (this.areUnsavedChanges) return done(); return this.blur(); } if (ev.key === 'Enter' && this.isShort) { this.submit(); return done(); } if (ev.key === 'Tab' && this.isLong) { return done(); } if (ev.key == 'Enter' && this.isLong && ev.ctrlKey) { this.submit(); return done(); } } afterInput(ev) { if (this.numbersOnly && this.value != null && this.value != undefined) { this.form.patchValue({ value: this.value.toString().replace(/[^0-9|\.|\,]+/gm, '').replace(/[\,]+/gm, '.') }, { emitEvent: true }); } this.valueChanges(); } afterClick(ev) { ev.stopPropagation(); ev.stopImmediatePropagation(); ev.preventDefault(); } afterFocus(ev) { if (this.selectOnFocus && this.input) { this.input.nativeElement.select(); } } focus() { if (this.input) { this.input.nativeElement.focus(); } } submit() { var done = () => { this.onSubmit.emit({ value: this.value, isValid: this.form.valid, errors: this.control.errors }); return this.blur(); }; if (this.autosave) { this.valueChanges(); return done(); } this.emitChanges(); done(); this.emitAreUnsavedChanges(); } cancel() { if (this.autosave) return; this.value = this.emittedValue; this.blur(); this.emitAreUnsavedChanges(); } valueChanges() { this.onChangeTimeout = setTimeout(() => { this.emitAreUnsavedChanges(); if (this.onChangeTimeout) clearTimeout(this.onChangeTimeout); if (this.emittedValue === this.value) { return; // Nothing changed. } if (this.autosave) { this.emitChanges(); } }, 200); } writeValue(obj) { let str = ``; if (typeof obj == 'string') str = this.formatValue(obj); else if (typeof obj == 'number') str = `${obj}`; this.value = str; this.emittedValue = str; } registerOnChange(fn) { this._registerOnChange = fn; } registerOnTouched(fn) { this._registerOnTouched = fn; } setDisabledState(isDisabled) { this._isDisabled = !!isDisabled; var method = this.isDisabled ? 'disable' : 'enable'; this.control[method](); } textareaFocus(event) { this.onFocus.emit(event); this.triggerResize(); } triggerResize() { (this.input?.nativeElement).dispatchEvent(new Event(CustomChangeEvent)); } /***************************************************************** * Private/Protected methods ****************************************************************/ emitChanges() { if (this.hasErrors && !this.allowInvalid) return; this._registerOnChange(this.value); this._registerOnTouched(); this.emittedValue = this.value; } formatValue(v) { if (!(v && typeof v == 'string' && v.length > 0)) return v; if (this.isLong) return v; return v.replace(/\n+/gm, " "); } blur() { this.input?.nativeElement.blur(); } updateValidators() { this.control.clearValidators(); this.control.setValidators(this.validators); this.control.updateValueAndValidity(); } validateInputs() { var errors = []; var warnings = []; if (this.numbersOnly && this.max && this.min && this.max <= this.min) { errors.push(`${this.constructor.name} Warning: [max] must be greater than [min]. [max]=${this.max}, [min]=${this.min}`); this.max = InputsDefaults.max; this.min = InputsDefaults.min; } if (!this.numbersOnly && this.maxLength && this.minLength && this.maxLength <= this.minLength) { errors.push(`${this.constructor.name} Warning: [maxLength] must be greater than [minLength]. [maxLength]=${this.maxLength}, [minLength]=${this.minLength}`); this.maxLength = InputsDefaults.maxLength; this.minLength = InputsDefaults.minLength; } for (let msg of warnings) { console.warn(msg); } for (let msg of errors) { console.error(msg); } } emitAreUnsavedChanges() { this.areUnsavedChanges$.next(this.areUnsavedChanges); } } NgxInputEipComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: NgxInputEipComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); NgxInputEipComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.9", type: NgxInputEipComponent, selector: "ngx-input-eip", inputs: { isShort: "isShort", isMandatory: "isMandatory", enableValidations: "enableValidations", inputStyle: "inputStyle", placeholder: "placeholder", label: "label", showLabel: "showLabel", submitButtonLabel: "submitButtonLabel", cancelButtonLabel: "cancelButtonLabel", actionbarMode: "actionbarMode", animateActionbar: "animateActionbar", autosave: "autosave", classes: "classes", customValidators: "customValidators", isDisabled: "isDisabled", numbersOnly: "numbersOnly", min: "min", max: "max", maxLength: "maxLength", minLength: "minLength", showErrors: "showErrors", selectOnFocus: "selectOnFocus", allowInvalid: "allowInvalid", customErrorMessages: "customErrorMessages", customErrorsMap: "customErrorsMap", errorsParser: "errorsParser", overwriteValue: ["value", "overwriteValue"] }, outputs: { onSubmit: "onSubmit", onCancel: "onCancel", _areUnsavedChanges: "areUnsavedChanges", onChange: "onChange", onInput: "onInput", onClick: "onClick", onFocus: "onFocus", onResize: "onResize", onDblclick: "onDblclick", onBlur: "onBlur", onKeyDown: "onKeyDown", onKeyPress: "onKeyPress", onKeyUp: "onKeyUp" }, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NgxInputEipComponent), multi: true } ], viewQueries: [{ propertyName: "input", first: true, predicate: ["input"], descendants: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<div [formGroup]=\"form\" class=\"d-flex flex-column\">\n <label [for]=\"id\" *ngIf=\"showLabel\">\n <ng-container *ngIf=\"label\">{{label}}</ng-container>\n <ng-content select=\"[label]\"></ng-content>\n </label>\n\n <div [ngClass]=\"{\n 'show-border': showActionsBar && areUnsavedChanges && this.actionbarClass == 'overlay'\n }\" class=\"border-actionsbar\">\n\n <div class=\"scroll-wrapper\" [resizableTextareaContainer]=\"true\">\n <textarea\n #input\n [rows]=\"1\"\n [id]=\"id\"\n [placeholder]=\"placeholder\"\n formControlName=\"value\"\n class=\"{{inputStatusClass}} {{classes}}\"\n [ngClass]=\"{\n 'is-short': isShort,\n 'is-long': isLong,\n 'active': areUnsavedChanges && !autosave || isEmpty && isShort && isMandatory\n }\"\n\n [ngStyle]=\"inputStyle || {}\"\n\n (resize)=\"onResize.emit($event)\"\n (dblclick)=\"onDblclick.emit($event)\"\n (blur)=\"onBlur.emit($event)\"\n (keypress)=\"onKeyPress.emit($event)\"\n (keyup)=\"onKeyUp.emit($event)\"\n (keydown)=\"onKeyDown.emit($event)\"\n (input)=\"onInput.emit($event)\"\n (change)=\"onChange.emit($event)\"\n (click)=\"onClick.emit($event)\"\n (focus)=\"textareaFocus($event)\"\n ></textarea>\n </div>\n\n <div #customHtmlErrors class=\"errors-container\" [ngClass]=\"{'has-items': showErrors && customHtmlErrors.hasChildNodes()}\" >\n <ng-content select=\"[errors]\" ></ng-content>\n <ng-content select=\"[error]\" ></ng-content>\n </div>\n\n <div class=\"errors-container\" [ngClass]=\"{'has-items': showErrors && hasErrors}\">\n <span *ngFor=\"let error of stringErrorMessages\">{{error}}</span>\n\n <ng-container *ngFor=\"let error of templateErrorMessages\">\n <ng-container *ngTemplateOutlet=\"error\"></ng-container>\n </ng-container>\n </div>\n </div>\n\n\n <ng-content select=\"[after-input]\"></ng-content>\n\n <div *ngIf=\"showActionsBar\" class=\"position-relative\">\n <div class=\"actionsbar {{actionbarClass}}\"\n [ngClass]=\"{'unsavedChanges': areUnsavedChanges, 'has-animation': animateActionbar}\">\n <button [disabled]=\"isDisabled || hasErrors && !allowInvalid\" type=\"button\" (click)=\"submit()\" class=\"confirm\">\n <ng-container *ngIf=\"!submitButtonContainer.hasChildNodes()\">{{submitButtonLabel}}</ng-container>\n\n <span #submitButtonContainer>\n <ng-content select=\"[submitButton]\"></ng-content>\n </span>\n\n </button>\n <button [disabled]=\"isDisabled\" type=\"button\" (click)=\"cancel()\" class=\"cancel\">\n <ng-container *ngIf=\"!cancelButtonContainer.hasChildNodes()\">{{cancelButtonLabel}}</ng-container>\n\n <span #cancelButtonContainer>\n <ng-content select=\"[cancelButton]\"></ng-content>\n </span>\n </button>\n </div>\n </div>\n</div>\n\n<pre *ngIf=\"debugMode\" [innerText]=\"debugJson | json\"></pre>\n", styles: [":host{--active-box-shadow-size: 2px;--error-message-color: red}:host .hidden,:host .hide{visibility:hidden}:host .errors-container{display:flex;flex-direction:column;transition:all 1s;max-height:0px;overflow:hidden}:host .errors-container.has-items{max-height:500px;overflow:auto}:host ::ng-deep .errors-container *{color:var(--error-message-color, red)!important;fill:var(--error-message-color, red)!important;font-size:.75em}:host label{width:-moz-fit-content;width:fit-content}:host *:disabled,:host *.disabled,:host *[disabled]{cursor:not-allowed}:host .border-actionsbar{border:1px solid transparent;display:flex;flex-direction:column}:host .border-actionsbar.show-border{border:1px solid gainsboro;border-radius:5px 5px 5px 0}:host textarea{border:var(--ngx-input-eip-border, 1px solid transparent);outline:var(--ngx-input-eip-outline, none);color:var(--ngx-input-eip-color, rgb(41, 41, 41));background-color:var(--ngx-input-eip-background-color, rgb(255, 255, 255));font-size:var(--ngx-input-eip-font-size, 1em);padding:var(--ngx-input-eip-padding, calc(.2em + var(--active-box-shadow-size)));margin:var(--ngx-input-eip-margin, none);border-radius:var(--ngx-input-eip-border-radius, 5px);box-shadow:inset 0 0 0 var(--active-box-shadow-size) transparent;width:var(--ngx-input-eip-width, 100%);overflow-y:hidden;box-sizing:border-box;resize:none}:host textarea.is-long,:host textarea.is-short.empty{background-color:#091e421f}:host textarea.is-long:hover,:host textarea.is-short.empty:hover{background-color:#091e4214}:host textarea.is-long:hover:not(.focused,:focus,.active,:active,.disabled,:disabled,[disabled]),:host textarea.is-short.empty:hover:not(.focused,:focus,.active,:active,.disabled,:disabled,[disabled]){cursor:pointer}:host textarea.is-long{min-height:60px}:host textarea.focused:not(.disabled):not(:disabled):not([disabled]),:host textarea:focus:not(.disabled):not(:disabled):not([disabled]),:host textarea.active:not(.disabled):not(:disabled):not([disabled]),:host textarea:active:not(.disabled):not(:disabled):not([disabled]){background-color:var(--ngx-input-eip-active-background-input, #fff);box-shadow:inset 0 0 0 var(--active-box-shadow-size) var(--ngx-input-eip-active-box-shadow, #0079bf)}:host .actionsbar{background-color:#fff;display:flex}:host .actionsbar.unsavedChanges,:host .actionsbar.always{padding:var(--ngx-input-eip-padding, calc(.2em + var(--active-box-shadow-size)));opacity:1}:host .actionsbar.show{max-height:0;overflow:hidden}:host .actionsbar.show.has-animation{transition:.5s}:host .actionsbar.show.unsavedChanges{max-height:200px}:host .actionsbar.always{visibility:hidden}:host .actionsbar.always.unsavedChanges{visibility:visible}:host .actionsbar.overlay{position:absolute;top:-1px;margin:0!important;background-color:#fff;border-radius:0 0 5px 5px;border:1px solid gainsboro;border-top:1px solid #fff;z-index:1;display:none}:host .actionsbar.overlay.unsavedChanges{display:block}:host .actionsbar button:first-child{margin-right:10px}:host .actionsbar button.confirm,:host .actionsbar button.cancel{border:none;box-shadow:none;outline:none;border-radius:5px;padding:.3em .6em;transition:background-color .75s}:host .actionsbar button.cancel{background-color:var(--ngx-input-eip-cancel-button-background-color, transparent);color:var(--ngx-input-eip-cancel-button-color, #172b4d)}:host .actionsbar button.cancel:hover{background-color:var(--ngx-input-eip-cancel-button-active-background-color, lightgray)}:host .actionsbar button.confirm{background-color:var(--ngx-input-eip-confirm-button-background-color, #0079bf);color:var(--ngx-input-eip-confirm-button-color, white)}:host .actionsbar button.confirm:hover{background-color:var(--ngx-input-eip-confirm-button-active-background-color, #055a8c)}:host .h1{font-size:2em!important}:host .h2{font-size:1.5em!important}:host .h3{font-size:1.17em!important}:host .h4{font-size:1em!important}:host .h5{font-size:.83em!important}:host .h6{font-size:.67em!important}:host .h1,:host .h2,:host .h3,:host .h4,:host .h5,:host .h6{font-weight:500;line-height:1.2}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: ResizableTextareaContainerDirective, selector: "[resizableTextareaContainer]", inputs: ["resizableTextareaContainer"] }, { kind: "pipe", type: i1.JsonPipe, name: "json" }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: NgxInputEipComponent, decorators: [{ type: Component, args: [{ selector: selector, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NgxInputEipComponent), multi: true } ], template: "<div [formGroup]=\"form\" class=\"d-flex flex-column\">\n <label [for]=\"id\" *ngIf=\"showLabel\">\n <ng-container *ngIf=\"label\">{{label}}</ng-container>\n <ng-content select=\"[label]\"></ng-content>\n </label>\n\n <div [ngClass]=\"{\n 'show-border': showActionsBar && areUnsavedChanges && this.actionbarClass == 'overlay'\n }\" class=\"border-actionsbar\">\n\n <div class=\"scroll-wrapper\" [resizableTextareaContainer]=\"true\">\n <textarea\n #input\n [rows]=\"1\"\n [id]=\"id\"\n [placeholder]=\"placeholder\"\n formControlName=\"value\"\n class=\"{{inputStatusClass}} {{classes}}\"\n [ngClass]=\"{\n 'is-short': isShort,\n 'is-long': isLong,\n 'active': areUnsavedChanges && !autosave || isEmpty && isShort && isMandatory\n }\"\n\n [ngStyle]=\"inputStyle || {}\"\n\n (resize)=\"onResize.emit($event)\"\n (dblclick)=\"onDblclick.emit($event)\"\n (blur)=\"onBlur.emit($event)\"\n (keypress)=\"onKeyPress.emit($event)\"\n (keyup)=\"onKeyUp.emit($event)\"\n (keydown)=\"onKeyDown.emit($event)\"\n (input)=\"onInput.emit($event)\"\n (change)=\"onChange.emit($event)\"\n (click)=\"onClick.emit($event)\"\n (focus)=\"textareaFocus($event)\"\n ></textarea>\n </div>\n\n <div #customHtmlErrors class=\"errors-container\" [ngClass]=\"{'has-items': showErrors && customHtmlErrors.hasChildNodes()}\" >\n <ng-content select=\"[errors]\" ></ng-content>\n <ng-content select=\"[error]\" ></ng-content>\n </div>\n\n <div class=\"errors-container\" [ngClass]=\"{'has-items': showErrors && hasErrors}\">\n <span *ngFor=\"let error of stringErrorMessages\">{{error}}</span>\n\n <ng-container *ngFor=\"let error of templateErrorMessages\">\n <ng-container *ngTemplateOutlet=\"error\"></ng-container>\n </ng-container>\n </div>\n </div>\n\n\n <ng-content select=\"[after-input]\"></ng-content>\n\n <div *ngIf=\"showActionsBar\" class=\"position-relative\">\n <div class=\"actionsbar {{actionbarClass}}\"\n [ngClass]=\"{'unsavedChanges': areUnsavedChanges, 'has-animation': animateActionbar}\">\n <button [disabled]=\"isDisabled || hasErrors && !allowInvalid\" type=\"button\" (click)=\"submit()\" class=\"confirm\">\n <ng-container *ngIf=\"!submitButtonContainer.hasChildNodes()\">{{submitButtonLabel}}</ng-container>\n\n <span #submitButtonContainer>\n <ng-content select=\"[submitButton]\"></ng-content>\n </span>\n\n </button>\n <button [disabled]=\"isDisabled\" type=\"button\" (click)=\"cancel()\" class=\"cancel\">\n <ng-container *ngIf=\"!cancelButtonContainer.hasChildNodes()\">{{cancelButtonLabel}}</ng-container>\n\n <span #cancelButtonContainer>\n <ng-content select=\"[cancelButton]\"></ng-content>\n </span>\n </button>\n </div>\n </div>\n</div>\n\n<pre *ngIf=\"debugMode\" [innerText]=\"debugJson | json\"></pre>\n", styles: [":host{--active-box-shadow-size: 2px;--error-message-color: red}:host .hidden,:host .hide{visibility:hidden}:host .errors-container{display:flex;flex-direction:column;transition:all 1s;max-height:0px;overflow:hidden}:host .errors-container.has-items{max-height:500px;overflow:auto}:host ::ng-deep .errors-container *{color:var(--error-message-color, red)!important;fill:var(--error-message-color, red)!important;font-size:.75em}:host label{width:-moz-fit-content;width:fit-content}:host *:disabled,:host *.disabled,:host *[disabled]{cursor:not-allowed}:host .border-actionsbar{border:1px solid transparent;display:flex;flex-direction:column}:host .border-actionsbar.show-border{border:1px solid gainsboro;border-radius:5px 5px 5px 0}:host textarea{border:var(--ngx-input-eip-border, 1px solid transparent);outline:var(--ngx-input-eip-outline, none);color:var(--ngx-input-eip-color, rgb(41, 41, 41));background-color:var(--ngx-input-eip-background-color, rgb(255, 255, 255));font-size:var(--ngx-input-eip-font-size, 1em);padding:var(--ngx-input-eip-padding, calc(.2em + var(--active-box-shadow-size)));margin:var(--ngx-input-eip-margin, none);border-radius:var(--ngx-input-eip-border-radius, 5px);box-shadow:inset 0 0 0 var(--active-box-shadow-size) transparent;width:var(--ngx-input-eip-width, 100%);overflow-y:hidden;box-sizing:border-box;resize:none}:host textarea.is-long,:host textarea.is-short.empty{background-color:#091e421f}:host textarea.is-long:hover,:host textarea.is-short.empty:hover{background-color:#091e4214}:host textarea.is-long:hover:not(.focused,:focus,.active,:active,.disabled,:disabled,[disabled]),:host textarea.is-short.empty:hover:not(.focused,:focus,.active,:active,.disabled,:disabled,[disabled]){cursor:pointer}:host textarea.is-long{min-height:60px}:host textarea.focused:not(.disabled):not(:disabled):not([disabled]),:host textarea:focus:not(.disabled):not(:disabled):not([disabled]),:host textarea.active:not(.disabled):not(:disabled):not([disabled]),:host textarea:active:not(.disabled):not(:disabled):not([disabled]){background-color:var(--ngx-input-eip-active-background-input, #fff);box-shadow:inset 0 0 0 var(--active-box-shadow-size) var(--ngx-input-eip-active-box-shadow, #0079bf)}:host .actionsbar{background-color:#fff;display:flex}:host .actionsbar.unsavedChanges,:host .actionsbar.always{padding:var(--ngx-input-eip-padding, calc(.2em + var(--active-box-shadow-size)));opacity:1}:host .actionsbar.show{max-height:0;overflow:hidden}:host .actionsbar.show.has-animation{transition:.5s}:host .actionsbar.show.unsavedChanges{max-height:200px}:host .actionsbar.always{visibility:hidden}:host .actionsbar.always.unsavedChanges{visibility:visible}:host .actionsbar.overlay{position:absolute;top:-1px;margin:0!important;background-color:#fff;border-radius:0 0 5px 5px;border:1px solid gainsboro;border-top:1px solid #fff;z-index:1;display:none}:host .actionsbar.overlay.unsavedChanges{display:block}:host .actionsbar button:first-child{margin-right:10px}:host .actionsbar button.confirm,:host .actionsbar button.cancel{border:none;box-shadow:none;outline:none;border-radius:5px;padding:.3em .6em;transition:background-color .75s}:host .actionsbar button.cancel{background-color:var(--ngx-input-eip-cancel-button-background-color, transparent);color:var(--ngx-input-eip-cancel-button-color, #172b4d)}:host .actionsbar button.cancel:hover{background-color:var(--ngx-input-eip-cancel-button-active-background-color, lightgray)}:host .actionsbar button.confirm{background-color:var(--ngx-input-eip-confirm-button-background-color, #0079bf);color:var(--ngx-input-eip-confirm-button-color, white)}:host .actionsbar button.confirm:hover{background-color:var(--ngx-input-eip-confirm-button-active-background-color, #055a8c)}:host .h1{font-size:2em!important}:host .h2{font-size:1.5em!important}:host .h3{font-size:1.17em!important}:host .h4{font-size:1em!important}:host .h5{font-size:.83em!important}:host .h6{font-size:.67em!important}:host .h1,:host .h2,:host .h3,:host .h4,:host .h5,:host .h6{font-weight:500;line-height:1.2}\n"] }] }], propDecorators: { onSubmit: [{ type: Output }], onCancel: [{ type: Output }], _areUnsavedChanges: [{ type: Output, args: [`areUnsavedChanges`] }], onChange: [{ type: Output }], onInput: [{ type: Output }], onClick: [{ type: Output }], onFocus: [{ type: Output }], onResize: [{ type: Output }], onDblclick: [{ type: Output }], onBlur: [{ type: Output }], onKeyDown: [{ type: Output }], onKeyPress: [{ type: Output }], onKeyUp: [{ type: Output }], input: [{ type: ViewChild, args: ['input'] }], isShort: [{ type: Input }], isMandatory: [{ type: Input }], enableValidations: [{ type: Input }], inputStyle: [{ type: Input }], placeholder: [{ type: Input }], label: [{ type: Input }], showLabel: [{ type: Input }], submitButtonLabel: [{ type: Input }], cancelButtonLabel: [{ type: Input }], actionbarMode: [{ type: Input }], animateActionbar: [{ type: Input }], autosave: [{ type: Input }], classes: [{ type: Input }], customValidators: [{ type: Input }], isDisabled: [{ type: Input }], numbersOnly: [{ type: Input }], min: [{ type: Input }], max: [{ type: Input }], maxLength: [{ type: Input }], minLength: [{ type: Input }], showErrors: [{ type: Input }], selectOnFocus: [{ type: Input }], allowInvalid: [{ type: Input }], customErrorMessages: [{ type: Input }], customErrorsMap: [{ type: Input }], errorsParser: [{ type: Input }], overwriteValue: [{ type: Input, args: ["value"] }] } }); const declaredExports = [ NgxInputEipComponent, ]; class NgxInputEipModule { } NgxInputEipModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: NgxInputEipModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); NgxInputEipModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.9", ngImport: i0, type: NgxInputEipModule, declarations: [ResizableTextareaContainerDirective, NgxInputEipComponent], imports: [CommonModule, ReactiveFormsModule], exports: [NgxInputEipComponent] }); NgxInputEipModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: NgxInputEipModule, imports: [CommonModule, ReactiveFormsModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: NgxInputEipModule, decorators: [{ type: NgModule, args: [{ declarations: [ ResizableTextareaContainerDirective, ...declaredExports, ], imports: [ CommonModule, ReactiveFormsModule, ], exports: [ ...declaredExports, ] }] }] }); /* * Public API Surface of ngx-input-eip */ /** * Generated bundle index. Do not edit. */ export { NgxInputEipComponent, NgxInputEipModule }; //# sourceMappingURL=ngx-input-eip.mjs.map