grcm-components
Version:
> ⚡ Crea formularios dinámicos en Angular de forma rápida, limpia y reutilizable.
574 lines (561 loc) • 40.5 kB
JavaScript
import { RouterLink } from '@angular/router';
import * as i1 from '@angular/common';
import { CommonModule } from '@angular/common';
import * as i0 from '@angular/core';
import { input, output, computed, Component, inject, Injector, DestroyRef, viewChild, ViewContainerRef, OutputEmitterRef, isSignal, forwardRef, viewChildren, signal, ChangeDetectionStrategy } from '@angular/core';
import { distinctUntilChanged, Subject, debounceTime } from 'rxjs';
import * as i2 from '@angular/forms';
import { ReactiveFormsModule, NG_VALUE_ACCESSOR, FormBuilder, Validators, FormsModule } from '@angular/forms';
import { toObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop';
class GrcmButtonComponent {
label = input('');
title = input('');
disabled = input(false);
link = input(null);
type = input('button');
variant = input('primary');
outline = input(false);
size = input('default');
additionalClasses = input('');
icon = input('');
submitter = input(null);
fontSizeIcon = input(6);
clicked = output();
classes = computed(() => {
return `w-100 btn btn-${(this.outline() ? 'outline-' : '') + this.variant() + (this.size() ? ` btn-${this.size()} ` : ' ') + this.additionalClasses()}`;
});
click() {
this.clicked.emit();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: GrcmButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.6", type: GrcmButtonComponent, isStandalone: true, selector: "lib-grcm-button", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, link: { classPropertyName: "link", publicName: "link", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, outline: { classPropertyName: "outline", publicName: "outline", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, additionalClasses: { classPropertyName: "additionalClasses", publicName: "additionalClasses", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, submitter: { classPropertyName: "submitter", publicName: "submitter", isSignal: true, isRequired: false, transformFunction: null }, fontSizeIcon: { classPropertyName: "fontSizeIcon", publicName: "fontSizeIcon", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clicked: "clicked" }, ngImport: i0, template: "<button [type]=\"type()\" [attr.disabled]=\"disabled() ? 'disabled' : null\" (click)=\"click()\" [title]=\"title()\" [ngClass]=\"classes()\" [routerLink]=\"link()\" [attr.data-submitter]=\"submitter() ? submitter() : null\">\r\n @if (icon()) {\r\n <i [ngClass]=\"'fs-' + fontSizeIcon() + ' bi bi-' + icon()\"></i>\r\n }\r\n {{ label() }}\r\n</button>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: GrcmButtonComponent, decorators: [{
type: Component,
args: [{ selector: 'lib-grcm-button', imports: [CommonModule, RouterLink], template: "<button [type]=\"type()\" [attr.disabled]=\"disabled() ? 'disabled' : null\" (click)=\"click()\" [title]=\"title()\" [ngClass]=\"classes()\" [routerLink]=\"link()\" [attr.data-submitter]=\"submitter() ? submitter() : null\">\r\n @if (icon()) {\r\n <i [ngClass]=\"'fs-' + fontSizeIcon() + ' bi bi-' + icon()\"></i>\r\n }\r\n {{ label() }}\r\n</button>\r\n" }]
}] });
/* eslint-disable @typescript-eslint/no-explicit-any */
function createGrcmControl(data) {
return data;
}
/* eslint-disable @typescript-eslint/no-explicit-any */
class GrcmControlComponent {
_injector = inject(Injector);
_destroyRef = inject(DestroyRef);
_container = viewChild('container', { read: ViewContainerRef });
_grcmFormComponent = inject(GrcmFormComponent);
formControlName = input.required();
_componentRef;
_componentRefFormField;
id = computed(() => this._grcmFormComponent.identifier() + '_' + this.formControlName());
_form = computed(() => this._grcmFormComponent.form());
_data = computed(() => this._grcmFormComponent.data().controls[this.formControlName()]);
control = computed(() => this._form()?.controls[this.formControlName()]);
_hasPendingValue = false;
_hasPendingDisabledValue = false;
_pendingValue = null;
_onChange = null;
_onTouched = null;
_pendingDisabled = null;
ngAfterContentInit() {
this.initialize();
}
initialize() {
this.createComponents();
this.setInputsOutputs();
this.setClasses();
this.flushPendingControlValueAccessors();
}
createComponents() {
const { component, formFieldComponent } = this._data();
const viewContainer = this._container();
if (!formFieldComponent || !viewContainer)
return;
viewContainer.clear();
this._componentRefFormField = viewContainer.createComponent(formFieldComponent);
this._componentRefFormField.setInput('control', this.control());
this._componentRefFormField.setInput('id', this.id());
const formFieldInstance = this._componentRefFormField.instance;
formFieldInstance.controlView().clear();
this._componentRef = formFieldInstance.controlView().createComponent(component);
}
setInputsOutputs() {
const args = this._data().args;
if (!args)
return;
const { control = {}, formField = {} } = args;
const componentRef = this._componentRef;
const componentRefFormField = this._componentRefFormField;
const setInputsOutputs = (args, componentRef) => {
const keys = Object.keys(args);
keys.forEach((argProperty) => {
const argValue = args[argProperty];
const componentProperty = componentRef.instance[argProperty];
switch (typeof componentProperty) {
case 'function':
if (isSignal(argValue)) {
const obs = toObservable(argValue, {
injector: this._injector
}).subscribe(() => componentRef.setInput(argProperty, argValue()));
this._destroyRef.onDestroy(() => obs.unsubscribe());
}
else {
componentRef.setInput(argProperty, argValue);
}
break;
case 'object':
if (!(componentProperty instanceof OutputEmitterRef))
return;
const subs = componentProperty.subscribe(argValue);
this._destroyRef.onDestroy(() => subs.unsubscribe());
}
});
};
setInputsOutputs(control, componentRef);
setInputsOutputs(formField, componentRefFormField);
}
setClasses() {
const classes = this._data().classes;
if (!classes)
return;
const { control, formField } = classes;
if (control)
this._componentRef.location.nativeElement.classList = control;
if (formField)
this._componentRefFormField.location.nativeElement.classList = formField;
}
flushPendingControlValueAccessors() {
const instance = this._componentRef?.instance;
if (this._hasPendingValue) {
instance.writeValue(this._pendingValue);
this._hasPendingValue = false;
}
if (this._onChange) {
instance.registerOnChange(this._onChange);
this._onChange = null;
}
if (this._onTouched) {
instance.registerOnTouched(this._onTouched);
this._onTouched = null;
}
if (this._hasPendingDisabledValue) {
instance.setDisabledState?.(this._pendingDisabled);
this._hasPendingDisabledValue = false;
}
}
writeValue(obj) {
const instance = this._componentRef?.instance;
if (instance) {
instance.writeValue(obj);
return;
}
this._hasPendingValue = true;
this._pendingValue = obj;
}
registerOnChange(fn) {
const instance = this._componentRef?.instance;
if (instance) {
instance.registerOnChange(fn);
return;
}
this._onChange = fn;
}
registerOnTouched(fn) {
const instance = this._componentRef?.instance;
if (instance) {
instance.registerOnTouched(fn);
return;
}
this._onTouched = fn;
}
setDisabledState(isDisabled) {
const instance = this._componentRef?.instance;
if (instance) {
instance?.setDisabledState?.(isDisabled);
return;
}
this._hasPendingDisabledValue = true;
this._pendingDisabled = isDisabled;
}
ngOnDestroy() {
this._componentRef?.destroy();
this._componentRefFormField?.destroy();
this._container()?.clear();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: GrcmControlComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "19.2.6", type: GrcmControlComponent, isStandalone: true, selector: "lib-grcm-control", inputs: { formControlName: { classPropertyName: "formControlName", publicName: "formControlName", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "attr.data-control-id": "id()" } }, providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => GrcmControlComponent),
multi: true
}
], viewQueries: [{ propertyName: "_container", first: true, predicate: ["container"], descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0, template: "<ng-container #container></ng-container>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: GrcmControlComponent, decorators: [{
type: Component,
args: [{ selector: 'lib-grcm-control', imports: [CommonModule, ReactiveFormsModule], providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => GrcmControlComponent),
multi: true
}
], host: {
'[attr.data-control-id]': 'id()'
}, template: "<ng-container #container></ng-container>\r\n" }]
}] });
/* eslint-disable @typescript-eslint/no-explicit-any */
class GrcmFormComponent {
grcmControls = viewChildren(GrcmControlComponent, { read: ViewContainerRef });
_destroyRef = inject(DestroyRef);
_formBuilder = inject(FormBuilder);
data = input.required();
additionalClasses = computed(() => this.data().form.classes || "");
buildForm = output();
formSubmit = output();
formChange = output();
_form = signal(null);
form = this._form.asReadonly();
formKeys = [];
templates = input({});
identifier = computed(() => this.data().form.id);
formControlNames = computed(() => Object.keys(this._form()?.controls || {}));
ngOnInit() {
this.initialize();
}
ngAfterViewInit() {
this.buildForm.emit(this.form());
}
initialize() {
this.initForm();
this.initSubscriptionsForControlValueChanges();
}
initForm() {
const data = this.data();
this._form.set(this._formBuilder.record({}, {
validators: data.form.validators,
asyncValidators: data.form.asyncValidators,
updateOn: data.form.updateOn || 'change'
}));
Object.keys(data.controls).forEach((name) => {
const dataControl = data.controls[name];
this.addControl(name, dataControl);
});
}
addControl(name, control) {
this._form()?.addControl(name, this._formBuilder.control(control.value, [...control.validators || []], [...control.asyncValidators || []]));
}
initSubscriptionsForControlValueChanges() {
const form = this.form();
if (!form)
return;
this.formControlNames().forEach((key) => {
if (!this.data().controls[key].valueChangesSubscribe)
return;
form.controls[key].valueChanges.pipe(distinctUntilChanged(), takeUntilDestroyed(this._destroyRef)).subscribe((value) => {
this.formChange.emit({ field: key, newValue: value });
});
});
}
getErrors(errors) {
if (!errors)
return [];
return Object.keys(errors);
}
onSubmit(event = null) {
const submitter = event?.submitter?.dataset['submitter'] || null;
const form = this.form();
this.markAsTouched();
if (!form || form.invalid)
return;
if (form.valid)
this.formSubmit.emit({ form, submitter });
}
markAsTouched() {
const form = this.form();
form?.markAsTouched();
form?.updateValueAndValidity();
}
getDataForTemplateContext(formControlName = null) {
const form = this.form();
if (!form)
return {};
const data = {
form
};
if (formControlName) {
data['control'] = form.controls[formControlName];
}
return data;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: GrcmFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.6", type: GrcmFormComponent, isStandalone: true, selector: "lib-grcm-form", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, templates: { classPropertyName: "templates", publicName: "templates", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { buildForm: "buildForm", formSubmit: "formSubmit", formChange: "formChange" }, viewQueries: [{ propertyName: "grcmControls", predicate: GrcmControlComponent, descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0, template: "\r\n\r\n<ng-template #renderTemplate let-templateKey let-controlName>\r\n @let tmpl = templates()[templateKey];\r\n @if (tmpl) {\r\n <ng-container *ngTemplateOutlet=\"tmpl; context: getDataForTemplateContext(controlName)\"></ng-container>\r\n }\r\n</ng-template>\r\n\r\n<!-- <ng-container *ngTemplateOutlet=\"renderTemplate; context: {\r\n templateKey: 'before_' + controlName,\r\n controlName: controlName\r\n}\"></ng-container> -->\r\n\r\n@let formInstance = form();\r\n@if (formInstance) {\r\n <form [formGroup]=\"formInstance\" (ngSubmit)=\"onSubmit($event)\" [ngClass]=\"additionalClasses()\" novalidate>\r\n @let beforeFormTemplate = templates()[\"beforeFormTemplate\"];\r\n @if (beforeFormTemplate) {\r\n <ng-container *ngTemplateOutlet=\"beforeFormTemplate; context: getDataForTemplateContext()\"></ng-container>\r\n }\r\n @for (controlName of formControlNames(); track controlName) {\r\n @let beforeControlTemplate = templates()[\"before_\" + controlName];\r\n @if (beforeControlTemplate) {\r\n <ng-container *ngTemplateOutlet=\"beforeControlTemplate; context: getDataForTemplateContext(controlName)\"></ng-container>\r\n }\r\n <lib-grcm-control [formControlName]=\"controlName\" style=\"width: 100%;\"></lib-grcm-control>\r\n @let afterControlTemplate = templates()[\"after_\" + controlName];\r\n @if (afterControlTemplate) {\r\n <ng-container *ngTemplateOutlet=\"afterControlTemplate; context: getDataForTemplateContext(controlName)\"></ng-container>\r\n }\r\n }\r\n @let afterFormTemplate = templates()[\"afterFormTemplate\"];\r\n @if (afterFormTemplate) {\r\n <ng-container *ngTemplateOutlet=\"afterFormTemplate; context: getDataForTemplateContext()\"></ng-container>\r\n }\r\n </form>\r\n}\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { 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: "component", type: GrcmControlComponent, selector: "lib-grcm-control", inputs: ["formControlName"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: GrcmFormComponent, decorators: [{
type: Component,
args: [{ selector: 'lib-grcm-form', imports: [CommonModule, ReactiveFormsModule, GrcmControlComponent], template: "\r\n\r\n<ng-template #renderTemplate let-templateKey let-controlName>\r\n @let tmpl = templates()[templateKey];\r\n @if (tmpl) {\r\n <ng-container *ngTemplateOutlet=\"tmpl; context: getDataForTemplateContext(controlName)\"></ng-container>\r\n }\r\n</ng-template>\r\n\r\n<!-- <ng-container *ngTemplateOutlet=\"renderTemplate; context: {\r\n templateKey: 'before_' + controlName,\r\n controlName: controlName\r\n}\"></ng-container> -->\r\n\r\n@let formInstance = form();\r\n@if (formInstance) {\r\n <form [formGroup]=\"formInstance\" (ngSubmit)=\"onSubmit($event)\" [ngClass]=\"additionalClasses()\" novalidate>\r\n @let beforeFormTemplate = templates()[\"beforeFormTemplate\"];\r\n @if (beforeFormTemplate) {\r\n <ng-container *ngTemplateOutlet=\"beforeFormTemplate; context: getDataForTemplateContext()\"></ng-container>\r\n }\r\n @for (controlName of formControlNames(); track controlName) {\r\n @let beforeControlTemplate = templates()[\"before_\" + controlName];\r\n @if (beforeControlTemplate) {\r\n <ng-container *ngTemplateOutlet=\"beforeControlTemplate; context: getDataForTemplateContext(controlName)\"></ng-container>\r\n }\r\n <lib-grcm-control [formControlName]=\"controlName\" style=\"width: 100%;\"></lib-grcm-control>\r\n @let afterControlTemplate = templates()[\"after_\" + controlName];\r\n @if (afterControlTemplate) {\r\n <ng-container *ngTemplateOutlet=\"afterControlTemplate; context: getDataForTemplateContext(controlName)\"></ng-container>\r\n }\r\n }\r\n @let afterFormTemplate = templates()[\"afterFormTemplate\"];\r\n @if (afterFormTemplate) {\r\n <ng-container *ngTemplateOutlet=\"afterFormTemplate; context: getDataForTemplateContext()\"></ng-container>\r\n }\r\n </form>\r\n}\r\n" }]
}] });
/* eslint-disable @typescript-eslint/no-explicit-any */
class GrcmFormFieldComponent {
_destroyRef = inject(DestroyRef);
controlView = viewChild.required('controlView', { read: ViewContainerRef });
control = input.required();
id = input.required();
_formComponent = inject(GrcmFormComponent);
label = input("");
_isRequired = signal(false);
isRequired = this._isRequired.asReadonly();
_useCompleteLabel = signal(false);
useCompleteLabel = this._useCompleteLabel.asReadonly();
requiredTag = "*";
optionalTag = "(Opcional)";
form = computed(() => this._formComponent.form());
completeLabel = computed(() => {
return this.label() + (this.useCompleteLabel() ? (this.isRequired() ? this.requiredTag : this.optionalTag) : "");
});
ngOnInit() {
this.initialize();
}
initialize() {
this.setIsRequired();
this.initControlStatusChanges();
this.initFormStatusChanges();
}
initControlStatusChanges() {
this.control().statusChanges.pipe(takeUntilDestroyed(this._destroyRef)).subscribe(() => {
this.setIsRequired();
});
}
initFormStatusChanges() {
const form = this._formComponent.form();
if (!form)
return;
this.setUseCompleteLabel(form);
form.statusChanges.pipe(takeUntilDestroyed(this._destroyRef)).subscribe(() => {
this.setUseCompleteLabel(form);
});
}
setUseCompleteLabel(form) {
let requiredControls = 0;
const keys = Object.keys(form.controls);
keys.forEach(key => {
if (this.controlIsRequired(form.controls[key]))
requiredControls++;
});
const keysLen = keys.length / 2;
if (this.isRequired() && requiredControls <= keysLen) {
this._useCompleteLabel.set(true);
}
else {
this._useCompleteLabel.set(!this.isRequired() && requiredControls > keysLen);
}
}
setIsRequired() {
this._isRequired.set(this.controlIsRequired(this.control()));
}
controlIsRequired(control) {
return control.hasValidator(Validators.required);
}
getError(errors) {
const keys = Object.keys(errors);
if (!keys.length)
return '';
const error = keys[0];
const data = errors[keys[0]];
switch (error) {
case 'required':
return 'Este campo es requerido.';
case 'minlength':
return `Tiene que tener como mínimo ${data.requiredLength} caracteres.`;
case 'maxlength':
return `Tiene que tener como máximo ${data.requiredLength} caracteres.`;
case 'pattern':
return 'La contraseña debe contener al menos una letra mayúscula, una minúscula y un símbolo especial.';
default:
return 'Revisa el valor ingresado.';
}
}
ngOnDestroy() {
this.controlView().clear();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: GrcmFormFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.6", type: GrcmFormFieldComponent, isStandalone: true, selector: "lib-grcm-form-field", inputs: { control: { classPropertyName: "control", publicName: "control", isSignal: true, isRequired: true, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "form-group" }, viewQueries: [{ propertyName: "controlView", first: true, predicate: ["controlView"], descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0, template: "@let errors = control().errors;\r\n@let touched = control().touched;\r\n<label [for]=\"id()\" class=\"form-label\">{{ completeLabel() }}</label>\r\n<div class=\"input-group has-validation form-field-invalid d-block\">\r\n <ng-container #controlView></ng-container>\r\n <div class=\"invalid-feedback d-block\">\r\n @if (touched && errors) {\r\n <p>{{ getError(errors) }}<p>\r\n }\r\n </div>\r\n <!-- @else {\r\n <div class=\"valid-feedback d-block\">\r\n Looks good!\r\n </div>\r\n } -->\r\n</div>\r\n", styles: [":host{margin:0;padding:0;width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: GrcmFormFieldComponent, decorators: [{
type: Component,
args: [{ selector: 'lib-grcm-form-field', imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, host: {
class: 'form-group'
}, template: "@let errors = control().errors;\r\n@let touched = control().touched;\r\n<label [for]=\"id()\" class=\"form-label\">{{ completeLabel() }}</label>\r\n<div class=\"input-group has-validation form-field-invalid d-block\">\r\n <ng-container #controlView></ng-container>\r\n <div class=\"invalid-feedback d-block\">\r\n @if (touched && errors) {\r\n <p>{{ getError(errors) }}<p>\r\n }\r\n </div>\r\n <!-- @else {\r\n <div class=\"valid-feedback d-block\">\r\n Looks good!\r\n </div>\r\n } -->\r\n</div>\r\n", styles: [":host{margin:0;padding:0;width:100%}\n"] }]
}] });
class GrcmPlainFormFieldComponent {
controlView = viewChild.required('controlView', { read: ViewContainerRef });
control = input.required();
id = input.required();
ngOnDestroy() {
this.controlView().clear();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: GrcmPlainFormFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "19.2.6", type: GrcmPlainFormFieldComponent, isStandalone: true, selector: "lib-grcm-plain-form-field", inputs: { control: { classPropertyName: "control", publicName: "control", isSignal: true, isRequired: true, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: true, transformFunction: null } }, viewQueries: [{ propertyName: "controlView", first: true, predicate: ["controlView"], descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0, template: "<ng-container #controlView></ng-container>\r\n", styles: [":host{margin:0;padding:0;width:100%}\n"] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: GrcmPlainFormFieldComponent, decorators: [{
type: Component,
args: [{ selector: 'lib-grcm-plain-form-field', imports: [], template: "<ng-container #controlView></ng-container>\r\n", styles: [":host{margin:0;padding:0;width:100%}\n"] }]
}] });
/* eslint-disable @typescript-eslint/no-explicit-any */
class GrcmInputComponent {
_grcmFormComponent = inject(GrcmFormComponent);
controlComp = inject(GrcmControlComponent);
_destroyRef = inject(DestroyRef);
type = input('text');
placeholder = input('');
debounceTimer = input(300);
icon = input();
autocomplete = input(true);
submitFormOnDebounce = input(false);
changeValue = output();
debounce = output();
additionalClasses = input("");
control = computed(() => this.controlComp.control());
id = computed(() => this.controlComp.id());
_value = signal("");
value = this._value.asReadonly();
_disabled = signal(false);
disabled = this._disabled.asReadonly();
_debouncer = new Subject();
_inputRef = viewChild("input");
ngOnInit() {
this.initialize();
}
initialize() {
this._debouncer
.pipe(takeUntilDestroyed(this._destroyRef), debounceTime(this.debounceTimer()))
.subscribe(value => {
this.debounce.emit(value);
if (this.submitFormOnDebounce())
this._grcmFormComponent.onSubmit();
});
}
change(value) {
this._onTouched();
this._onChange(value);
}
onBlur() {
this._onTouched();
}
_onChange = () => { };
_onTouched = () => { };
registerOnChange(fn) {
this._onChange = fn;
}
registerOnTouched(fn) {
this._onTouched = fn;
}
writeValue(value) {
if (typeof value === "string")
this.updateValue(value);
}
updateValue(value) {
this._value.set(value);
const inputRef = this._inputRef();
if (inputRef)
inputRef.nativeElement.value = value;
}
setDisabledState(isDisabled) {
this._disabled.set(isDisabled);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: GrcmInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.6", type: GrcmInputComponent, isStandalone: true, selector: "lib-grcm-input", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, debounceTimer: { classPropertyName: "debounceTimer", publicName: "debounceTimer", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, autocomplete: { classPropertyName: "autocomplete", publicName: "autocomplete", isSignal: true, isRequired: false, transformFunction: null }, submitFormOnDebounce: { classPropertyName: "submitFormOnDebounce", publicName: "submitFormOnDebounce", isSignal: true, isRequired: false, transformFunction: null }, additionalClasses: { classPropertyName: "additionalClasses", publicName: "additionalClasses", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changeValue: "changeValue", debounce: "debounce" }, viewQueries: [{ propertyName: "_inputRef", first: true, predicate: ["input"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (control()) {\r\n @if (icon()) {\r\n <span class=\"input-group-text\">\r\n <i [ngClass]=\"'bi bi-' + icon()\"></i>\r\n </span>\r\n }\r\n @let validator = control()!.validator;\r\n @let valid = control()!.valid;\r\n @let invalid = control()!.invalid;\r\n @let touched = control()!.touched;\r\n <input\r\n [type]=\"type()\"\r\n [placeholder]=\"placeholder()\"\r\n class=\"form-control\"\r\n [class.is-valid]=\"validator && valid && touched\"\r\n [class.is-invalid]=\"validator && invalid && touched\"\r\n (input)=\"change( input.value )\"\r\n [value]=\"value()\"\r\n [id]=\"id()\"\r\n [attr.disabled]=\"disabled() ? 'disabled' : null\"\r\n [attr.autocomplete]=\"autocomplete() ? 'on' : 'off'\"\r\n (blur)=\"onBlur()\"\r\n [ngClass]=\"additionalClasses()\" #input>\r\n}\r\n\r\n\r\n <!--\r\n [class.is-invalid]=\"control().validator && control().invalid && control().touched\" -->\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: FormsModule }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: GrcmInputComponent, decorators: [{
type: Component,
args: [{ selector: 'lib-grcm-input', imports: [CommonModule, ReactiveFormsModule, FormsModule], template: "@if (control()) {\r\n @if (icon()) {\r\n <span class=\"input-group-text\">\r\n <i [ngClass]=\"'bi bi-' + icon()\"></i>\r\n </span>\r\n }\r\n @let validator = control()!.validator;\r\n @let valid = control()!.valid;\r\n @let invalid = control()!.invalid;\r\n @let touched = control()!.touched;\r\n <input\r\n [type]=\"type()\"\r\n [placeholder]=\"placeholder()\"\r\n class=\"form-control\"\r\n [class.is-valid]=\"validator && valid && touched\"\r\n [class.is-invalid]=\"validator && invalid && touched\"\r\n (input)=\"change( input.value )\"\r\n [value]=\"value()\"\r\n [id]=\"id()\"\r\n [attr.disabled]=\"disabled() ? 'disabled' : null\"\r\n [attr.autocomplete]=\"autocomplete() ? 'on' : 'off'\"\r\n (blur)=\"onBlur()\"\r\n [ngClass]=\"additionalClasses()\" #input>\r\n}\r\n\r\n\r\n <!--\r\n [class.is-invalid]=\"control().validator && control().invalid && control().touched\" -->\r\n" }]
}] });
/* eslint-disable @typescript-eslint/no-unused-vars */
class GrcmExampleLoginComponent {
_responseForm = signal(null);
responseForm = this._responseForm.asReadonly();
submitForm = output();
dataForm = {
form: {
id: 'login'
},
controls: {
username: createGrcmControl({
component: GrcmInputComponent,
formFieldComponent: GrcmFormFieldComponent,
value: "",
validators: [Validators.required, Validators.minLength(3), Validators.maxLength(10)],
args: {
control: {
debounceTimer: 1000,
placeholder: "Escriba su usuario",
icon: "person-circle",
autocomplete: false,
// debounce: (value: string) => {
// console.log(value)
// }
},
formField: {
label: "Usuario"
}
},
classes: {
control: "input-group"
}
}),
password: createGrcmControl({
component: GrcmInputComponent,
formFieldComponent: GrcmFormFieldComponent,
value: "",
validators: [Validators.required, Validators.minLength(6), Validators.maxLength(15), Validators.pattern('^(?=.*[a-z])(?=.*[A-Z])(?=.*[-_!@#$%^&*(),.?":{}|<>]).+$')],
args: {
control: {
type: 'password',
placeholder: "Escriba su contraseña",
icon: "lock",
autocomplete: false,
},
formField: {
label: "Contraseña"
}
},
classes: {
control: "input-group"
}
}),
}
};
buildForm(form) {
// console.log(form);
}
onChangeControl(data) {
// console.log(data)
}
onSubmit(data) {
const user = { ...data.form.value };
this._responseForm.set(user);
this.submitForm.emit(user);
}
getErrors(errors) {
console.log({ errors });
if (!errors)
return [];
return Object.keys(errors);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: GrcmExampleLoginComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.6", type: GrcmExampleLoginComponent, isStandalone: true, selector: "lib-grcm-example-login", outputs: { submitForm: "submitForm" }, ngImport: i0, template: "<lib-grcm-form [data]=\"dataForm\" classes=\"row pb-4\" (buildForm)=\"buildForm($event)\" (formChange)=\"onChangeControl($event)\"\r\n (formSubmit)=\"onSubmit($event)\" [templates]=\"{afterFormTemplate}\">\r\n <!-- <ng-template #before_username>, before_username\r\n nombreeee antes\r\n @if (control.valid) {\r\n V\u00C1LIDO\r\n } @else {\r\n INV\u00C1LIDO\r\n }\r\n </ng-template> -->\r\n <ng-template #afterFormTemplate let-form=\"form\">\r\n <div class=\"invalid-feedback d-block\">\r\n @if (form.errors) {\r\n @for (error of getErrors(form); track $index) {\r\n <p>{{ error }}\r\n <p>\r\n }\r\n }\r\n </div>\r\n <lib-grcm-button label=\"Entrar\" class=\"w-100\" [disabled]=\"form.invalid\" type=\"submit\"></lib-grcm-button>\r\n </ng-template>\r\n</lib-grcm-form>\r\n@if (responseForm()) {\r\n <div class=\"container mt-4\">\r\n <p>Respuesta del formulario</p>\r\n <div class=\"p-2\">\r\n <pre><code class=\"language-javascript\" data-lang=\"js\">{{responseForm() | json }}</code></pre>\r\n </div>\r\n </div>\r\n}\r\n", styles: [".highlight{background-color:#f7f7f9}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1.JsonPipe, name: "json" }, { kind: "component", type: GrcmButtonComponent, selector: "lib-grcm-button", inputs: ["label", "title", "disabled", "link", "type", "variant", "outline", "size", "additionalClasses", "icon", "submitter", "fontSizeIcon"], outputs: ["clicked"] }, { kind: "component", type: GrcmFormComponent, selector: "lib-grcm-form", inputs: ["data", "templates"], outputs: ["buildForm", "formSubmit", "formChange"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: GrcmExampleLoginComponent, decorators: [{
type: Component,
args: [{ selector: 'lib-grcm-example-login', imports: [CommonModule, GrcmButtonComponent, GrcmFormComponent], template: "<lib-grcm-form [data]=\"dataForm\" classes=\"row pb-4\" (buildForm)=\"buildForm($event)\" (formChange)=\"onChangeControl($event)\"\r\n (formSubmit)=\"onSubmit($event)\" [templates]=\"{afterFormTemplate}\">\r\n <!-- <ng-template #before_username>, before_username\r\n nombreeee antes\r\n @if (control.valid) {\r\n V\u00C1LIDO\r\n } @else {\r\n INV\u00C1LIDO\r\n }\r\n </ng-template> -->\r\n <ng-template #afterFormTemplate let-form=\"form\">\r\n <div class=\"invalid-feedback d-block\">\r\n @if (form.errors) {\r\n @for (error of getErrors(form); track $index) {\r\n <p>{{ error }}\r\n <p>\r\n }\r\n }\r\n </div>\r\n <lib-grcm-button label=\"Entrar\" class=\"w-100\" [disabled]=\"form.invalid\" type=\"submit\"></lib-grcm-button>\r\n </ng-template>\r\n</lib-grcm-form>\r\n@if (responseForm()) {\r\n <div class=\"container mt-4\">\r\n <p>Respuesta del formulario</p>\r\n <div class=\"p-2\">\r\n <pre><code class=\"language-javascript\" data-lang=\"js\">{{responseForm() | json }}</code></pre>\r\n </div>\r\n </div>\r\n}\r\n", styles: [".highlight{background-color:#f7f7f9}\n"] }]
}] });
/*
* Public API Surface of grcm-components
*/
// UI
// COMPONENTS
// BUTTON
/**
* Generated bundle index. Do not edit.
*/
export { GrcmButtonComponent, GrcmControlComponent, GrcmExampleLoginComponent, GrcmFormComponent, GrcmFormFieldComponent, GrcmInputComponent, GrcmPlainFormFieldComponent, createGrcmControl };
//# sourceMappingURL=grcm-components.mjs.map