UNPKG

@yyasinaslan/easyform

Version:
908 lines (892 loc) 77.6 kB
import * as i1 from '@angular/forms'; import { Validators, FormControl, FormGroup, FormArray, ReactiveFormsModule, FormsModule } from '@angular/forms'; import * as i0 from '@angular/core'; import { InjectionToken, inject, ChangeDetectorRef, Pipe, signal, computed, TemplateRef, Component, ContentChild, Input, DestroyRef, ViewContainerRef, EventEmitter, Injector, Directive, Output, HostListener, ElementRef } from '@angular/core'; import { isObservable, switchMap, of, filter } from 'rxjs'; import { AsyncPipe, NgTemplateOutlet, KeyValuePipe } from '@angular/common'; import { toObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop'; var AdvancedControlTypes; (function (AdvancedControlTypes) { // Form group AdvancedControlTypes["Group"] = "group"; // Form array AdvancedControlTypes["Array"] = "array"; // Form array with single control AdvancedControlTypes["ArraySimple"] = "arraySimple"; })(AdvancedControlTypes || (AdvancedControlTypes = {})); var BasicControlTypes; (function (BasicControlTypes) { // Textbox BasicControlTypes["Text"] = "text"; // Textarea BasicControlTypes["TextArea"] = "textarea"; // Checkbox with label BasicControlTypes["Checkbox"] = "checkbox"; // Checkbox group BasicControlTypes["CheckboxGroup"] = "checkboxGroup"; // Radio group BasicControlTypes["Radio"] = "radio"; // Select BasicControlTypes["Select"] = "select"; BasicControlTypes["Combobox"] = "combobox"; BasicControlTypes["Date"] = "date"; BasicControlTypes["Number"] = "number"; BasicControlTypes["Time"] = "time"; BasicControlTypes["DateTime"] = "datetime"; // Switch with label BasicControlTypes["Switch"] = "switch"; })(BasicControlTypes || (BasicControlTypes = {})); class EasyFormField { constructor(options) { /** * The type of control to be rendered */ this.controlType = ''; this.validations = {}; Object.assign(this, options); } /** * Add a required validation to the field * @param message */ required(message) { if (this.validations && this.validations["required"]) return this; if (!this.validations) this.validations = {}; this.validations["required"] = { validator: Validators.required, message }; return this; } /** * Add a requiredTrue validation to the field * @param message */ requiredTrue(message) { if (this.validations && this.validations["required"]) return this; if (!this.validations) this.validations = {}; this.validations["required"] = { validator: Validators.requiredTrue, message }; return this; } /** * Add a minLength validation to the field * @param minLength * @param message */ minLength(minLength, message) { if (this.validations && this.validations["minlength"]) return this; if (!this.validations) this.validations = {}; this.validations["minlength"] = { validator: Validators.minLength(minLength), message }; return this; } /** * Add a maxLength validation to the field * @param maxLength * @param message */ maxLength(maxLength, message) { if (this.validations && this.validations["maxlength"]) return this; if (!this.validations) this.validations = {}; this.validations["maxlength"] = { validator: Validators.maxLength(maxLength), message }; return this; } /** * Add an email validation to the field * @param message */ email(message) { if (this.validations && this.validations["email"]) return this; if (!this.validations) this.validations = {}; this.validations["email"] = { validator: Validators.email, message }; return this; } /** * Add a pattern validation to the field * @param pattern * @param message */ pattern(pattern, message) { if (this.validations && this.validations["pattern"]) return this; if (!this.validations) this.validations = {}; this.validations["pattern"] = { validator: Validators.pattern(pattern), message }; return this; } /** * Add a min validation to the field * @param min * @param message */ min(min, message) { if (this.validations && this.validations["min"]) return this; if (!this.validations) this.validations = {}; this.validations["min"] = { validator: Validators.min(min), message }; return this; } /** * Add a max validation to the field * @param max * @param message */ max(max, message) { if (this.validations && this.validations["max"]) return this; if (!this.validations) this.validations = {}; this.validations["max"] = { validator: Validators.max(max), message }; return this; } /** * Add a custom validation to the field * @param validator * @param messages */ customValidator(validator, messages) { if (!this.validations) this.validations = {}; Object.keys(messages).forEach(key => { this.validations[key] = { validator, message: messages[key] }; }); return this; } /** * Set the initial value of the field * @param value */ default(value) { this.initialValue = value; return this; } } class EasyFormGenerator { static text(value, label, configs) { return new EasyFormField({ ...configs, label, initialValue: value, controlType: "text" }); } static textarea(value, label, configs) { return new EasyFormField({ ...configs, label, initialValue: value, controlType: "textarea" }); } static select(value, options, label, configs) { const vc = new EasyFormField({ ...configs, label, initialValue: value, controlType: BasicControlTypes.Select }); vc.options = options; return vc; } static checkbox(value, label, configs) { return new EasyFormField({ ...configs, label, initialValue: value, controlType: BasicControlTypes.Checkbox }); } static switch(value, label, configs) { return new EasyFormField({ ...configs, label, initialValue: value, controlType: BasicControlTypes.Switch }); } static radio(value, options, label, configs) { const vc = new EasyFormField({ ...configs, label, initialValue: value, controlType: BasicControlTypes.Radio }); vc.options = options; return vc; } static custom(value, type, label, configs) { return new EasyFormField({ ...configs, label, initialValue: value, controlType: type }); } static group(schema, configs) { return new EasyFormField({ ...configs, controlType: AdvancedControlTypes.Group, schema: schema }); } static array(schema, configs) { if (schema instanceof EasyFormField) { return new EasyFormField({ ...configs, controlType: AdvancedControlTypes.ArraySimple, schema: schema }); } return new EasyFormField({ ...configs, controlType: AdvancedControlTypes.Array, schema: schema }); } } class EasyForm extends EasyFormGenerator { constructor(schema, options) { super(); // default options this.options = { showErrors: 'submitted', components: {} }; this.schema = schema; this.options = { ...this.options, ...options }; this.formGroup = this.createFormGroup(this.schema); } get invalid() { return this.formGroup.invalid; } get valid() { return this.formGroup.valid; } get value() { return this.formGroup.value; } get valueChanges() { return this.formGroup.valueChanges; } /** * Create a new instance of EasyForm * @param schema * @param options */ static create(schema, options) { return new EasyForm(schema, options); } /** * Traverse through schema and get definition * @param path */ getSchema(path) { const normalisedPath = typeof path == 'string' ? path.split('.') : path; if (!path || path.length == 0) { return null; } return this._getSchemaWithPath(normalisedPath, this.schema); } /** * Disable all form */ disable() { this.formGroup.disable(); } /** * Enable all form */ enable() { this.formGroup.enable(); } getComponentType(type) { if (!this.options.components) { return null; } const c = this.options.components[type]; if (!c) { return null; } return c; } getControl(path) { return this.formGroup.get(path); } getArrayControls(path) { const arrayControl = this.getControl(path); if (!arrayControl) return []; return arrayControl.controls; } getValue(path) { if (path) { return this.formGroup.get(path)?.value; } return this.formGroup.value; } getRawValue(path) { if (path) { return this.formGroup.get(path)?.getRawValue(); } return this.formGroup.getRawValue(); } setValue(value, path) { if (path) { this.formGroup.get(path)?.setValue(value); return; } this.formGroup.setValue(value); } patchValue(value, path) { if (path) { this.formGroup.get(path)?.patchValue(value); return; } this.formGroup.patchValue(value); } addToArray(path, value) { const arr = this.formGroup.get(path); const schema = this.getSchema(path); if (!schema) { throw new Error(`Cannot find form schema for ${path}`); } if (!arr) { throw new Error(`Cannot find form array for ${path}`); } if (schema.controlType === AdvancedControlTypes.Array) { const g = this.createFormGroup(schema.schema, value); arr.push(g); } else if (schema.controlType === AdvancedControlTypes.ArraySimple) { const arrayField = schema.schema; const validations = arrayField.validations ?? {}; const control = new FormControl(value, this.createValidations(validations)); arr.push(control); } } removeFromArray(path, index) { const arr = this.formGroup.get(path); if (arr) { arr.removeAt(index); } } createFormGroup(schema, initialValue, validations) { const group = new FormGroup({}); for (const key in schema) { const field = schema[key]; if (field.controlType == 'group') { const g = this.createFormGroup(field.schema, field.initialValue, field.validations); group.addControl(key, g); } else if (field.controlType == 'array') { const a = this.createFormArray(field.schema, field.initialValue, field.validations); group.addControl(key, a); } else if (field.controlType == 'arraySimple') { const a = this.createSimpleFormArray(field, field.initialValue, field.validations); group.addControl(key, a); } else { const control = new FormControl(field.initialValue, field.validations ? this.createValidations(field.validations) : []); group.addControl(key, control); } } if (validations) { group.addValidators(this.createValidations(validations)); } if (initialValue) { group.patchValue(initialValue); } return group; } createFormArray(schema, initialValue, validations) { const array = new FormArray([]); if (initialValue && Array.isArray(initialValue)) { initialValue.forEach((item) => { const group = this.createFormGroup(schema); group.patchValue(item); array.push(group); }); } if (validations) { array.addValidators(this.createValidations(validations)); } return array; } createSimpleFormArray(schema, initialValue, validations) { const array = new FormArray([]); const field = schema.schema; if (initialValue && Array.isArray(initialValue)) { initialValue.forEach((item, index) => { const control = new FormControl(item, field.validations ? this.createValidations(field.validations) : []); array.push(control); }); } if (validations) { array.addValidators(this.createValidations(validations)); } return array; } createValidations(validations) { const validators = []; if (validations) { for (const validationKey in validations) { const v = validations[validationKey]; validators.push(v.validator); } } return validators; } _getSchemaWithPath(path, schema) { const head = path[0]; const tail = path.slice(1); const hasIndex = !!head.toString().match(/^[0-9]+/); if (hasIndex) { if (schema instanceof EasyFormField) { return schema ?? null; } else { if (tail.length == 0) { return schema ?? null; } else { return this._getSchemaWithPath(tail, schema); } } } if (schema instanceof EasyFormField) { return schema.schema ?? null; } const childSchema = schema[head.toString()]; if (childSchema) { if (tail.length == 0) { return childSchema; } else { return this._getSchemaWithPath(tail, childSchema.schema ?? {}); } } return null; } } const EASY_FORM_CONFIG_TOKEN = 'EASY_FORM_CONFIG_TOKEN'; const EASY_FORM_CONFIG = new InjectionToken(EASY_FORM_CONFIG_TOKEN); /** * Observe both Observable and Signal values */ class ObservePipe { constructor() { this.cdr = inject(ChangeDetectorRef); this.asyncPipe = new AsyncPipe(this.cdr); } transform(value) { if (value === undefined) return null; if (isObservable(value)) { return this.asyncPipe.transform(value); } return value; } ngOnDestroy() { this.asyncPipe.ngOnDestroy(); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: ObservePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); } static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.2.12", ngImport: i0, type: ObservePipe, isStandalone: true, name: "observe", pure: false }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: ObservePipe, decorators: [{ type: Pipe, args: [{ name: 'observe', pure: false, standalone: true }] }], ctorParameters: () => [] }); /** * Every form control should extend this class * to work with EasyFormComponent */ class EasyFormControl { constructor() { this.easyFormControl = signal({ id: null, control: null, schema: null, // formFieldDirective: null }); this.control = computed(() => this.easyFormControl().control); this.schema = computed(() => this.easyFormControl().schema); // formFieldDirective = computed(() => this.easyFormControl().formFieldDirective); this.options = computed(() => { return this.schema()?.options; }); this.props = signal({}); this.hasControl = computed(() => this.easyFormControl().control !== null); this.hasInitialized = computed(() => { const efData = this.easyFormControl(); return efData.control !== null && efData.schema !== null; }); this.value = toObservable(this.control) .pipe(takeUntilDestroyed(), switchMap(control => control ? control.valueChanges : of(null))); /** * Emit events * Usage: (input)="emitEvent($event)" * @param event */ this.emitEvent = (event) => { // const directive = this.formFieldDirective; // if (directive && directive.fieldEvent && directive.fieldEvent instanceof EventEmitter) { // // Check if there are any subscribers to the event // if (directive.fieldEvent.observed) { // directive.fieldEvent.emit(event); // } // } }; } setValue(value) { this.control()?.setValue(value); } } class EfErrorsComponent { get _control() { if (this.control) return this.control; if (!this.path || !this.form) throw new Error('Path and form inputs are required'); return this.form.getControl(this.path); } get _formField() { if (this.formField) return this.formField; if (!this.path || !this.form) throw new Error('Path and form inputs are required'); return this.form.getSchema(this.path); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: EfErrorsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.12", type: EfErrorsComponent, isStandalone: true, selector: "ef-errors", inputs: { form: "form", path: "path", control: "control", formField: "formField" }, queries: [{ propertyName: "messageTemplate", first: true, predicate: ["messageTemplate"], descendants: true, read: TemplateRef }], ngImport: i0, template: "<ng-template #defaultErrorMessage let-message>\r\n @if (message) {\r\n <div class=\"ef-errors\">{{ message | observe }}</div>\r\n }\r\n</ng-template>\r\n\r\n@if (_control && _formField && _formField.validations) {\r\n @for (validation of (_formField.validations | keyvalue); track validation.key) {\r\n @if (_control.hasError(validation.key)) {\r\n <ng-container [ngTemplateOutlet]=\"messageTemplate ?? defaultErrorMessage\"\r\n [ngTemplateOutletContext]=\"{$implicit: validation.value.message}\"/>\r\n }\r\n }\r\n}\r\n", styles: [":host{display:none}:host-context(.show-errors-submitted .ng-submitted,.show-errors-always,.show-errors-touched .ng-touched,.show-errors-dirty .ng-dirty){display:block}.ef-errors{color:hsl(var(--ef-invalid-color, 0 100% 50%));font-size:var(--ef-form-errors-font-size, .8em)}\n"], dependencies: [{ kind: "pipe", type: ObservePipe, name: "observe" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: KeyValuePipe, name: "keyvalue" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: EfErrorsComponent, decorators: [{ type: Component, args: [{ selector: 'ef-errors', standalone: true, imports: [ ObservePipe, NgTemplateOutlet, KeyValuePipe ], template: "<ng-template #defaultErrorMessage let-message>\r\n @if (message) {\r\n <div class=\"ef-errors\">{{ message | observe }}</div>\r\n }\r\n</ng-template>\r\n\r\n@if (_control && _formField && _formField.validations) {\r\n @for (validation of (_formField.validations | keyvalue); track validation.key) {\r\n @if (_control.hasError(validation.key)) {\r\n <ng-container [ngTemplateOutlet]=\"messageTemplate ?? defaultErrorMessage\"\r\n [ngTemplateOutletContext]=\"{$implicit: validation.value.message}\"/>\r\n }\r\n }\r\n}\r\n", styles: [":host{display:none}:host-context(.show-errors-submitted .ng-submitted,.show-errors-always,.show-errors-touched .ng-touched,.show-errors-dirty .ng-dirty){display:block}.ef-errors{color:hsl(var(--ef-invalid-color, 0 100% 50%));font-size:var(--ef-form-errors-font-size, .8em)}\n"] }] }], propDecorators: { messageTemplate: [{ type: ContentChild, args: ['messageTemplate', { read: TemplateRef }] }], form: [{ type: Input }], path: [{ type: Input }], control: [{ type: Input }], formField: [{ type: Input }] } }); function isComponent(component) { return component.hasOwnProperty('ɵcmp'); } class FormFieldDirective { constructor() { this.destroyRef = inject(DestroyRef); this.viewContainerRef = inject(ViewContainerRef); this.easyFormComponent = inject(EasyFormComponent); this.disabled = false; // It emits control value changes this.change = new EventEmitter(); // Emit all events this.fieldEvent = new EventEmitter(); // Filter events this.focus = this.fieldEvent.pipe(filter(e => e.type == 'focus' || e.type == 'focusin')); this.blur = this.fieldEvent.pipe(filter(e => e.type == 'blur' || e.type == 'focusout')); // Event emitters derived from fieldEvent this.input = this.fieldEvent.pipe(filter(e => e.type == 'input')); this.keyup = this.fieldEvent.pipe(filter(e => e.type == 'keyup')); this.keydown = this.fieldEvent.pipe(filter(e => e.type == 'keydown')); } get value() { return this.control?.value; } get form() { return this.easyFormComponent.form; } ngOnChanges(changes) { if (changes['path']) { this.pathChanged(); } if (changes['disabled']) { const control = this.control; if (control) { if (this.disabled) { control.disable(); } else { control.enable(); } } } if (changes['props'] && this.componentRef) { this.componentRef.instance.props.set(changes['props'].currentValue); this.componentRef.changeDetectorRef.detectChanges(); } } pathChanged() { const control = this.setControl(); if (control) { if (this.valueChangeSubscription) { this.valueChangeSubscription.unsubscribe(); } this.control = control; this.valueChangeSubscription = control.valueChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(value => { this.change.emit(value); }); this.render(); } } setControl() { const path = this.path; if (!path || path.length === 0) { return; } if (!this.easyFormComponent.form) { return undefined; } const control = this.easyFormComponent.form.getControl(path); if (!control) { return undefined; } return control; } async render() { await this._render(); const control = this.control; if (control) { setTimeout(() => { if (this.disabled) { control.disable(); } else { control.enable(); } }); } } async _render() { const path = this.path; if (!path) { return; } const schema = this.form.getSchema(path); if (!schema) { throw new Error(`Path not found for ${path}`); } let componentDefinition = typeof schema.controlType === 'string' ? this.form.getComponentType(schema.controlType) : schema.controlType; let component; if (!componentDefinition) { // Get component from formConfig componentDefinition = this.easyFormComponent.getComponentType(schema.controlType); } if (!componentDefinition) { throw new Error(`Component configuration not found for ${schema.controlType}`); } if (!isComponent(componentDefinition)) { // Assume this is lazy loading component if (typeof componentDefinition !== 'function') { throw new Error(`${schema.controlType} is not a valid Angular component`); } const lazyLoadingComponent = componentDefinition; const loaded = await lazyLoadingComponent(); if (loaded.default) { component = loaded.default; } else if (typeof loaded === 'function' && isComponent(loaded)) { component = loaded; } else { throw new Error(`${schema.controlType} has no default export or is not a valid Angular component`); } } else { component = componentDefinition; } // Double check if component is a valid Angular component if (!isComponent(component)) { throw new Error(`${schema.controlType} is not a valid Angular component. Please provide a valid Angular component for ${schema.controlType} on provider EasyFormConfig`); } // Forwards this instance to the child component const injector = Injector.create({ parent: this.viewContainerRef.injector, providers: [ { provide: FormFieldDirective, useValue: this } ] }); this.viewContainerRef.clear(); if (this.componentRef) { this.componentRef.destroy(); } const componentRef = this.viewContainerRef.createComponent(component, { injector: injector }); this.componentRef = componentRef; this.instance = componentRef.instance; // This usage is removed in favor of directives props input // if (schema.props) { // // Initialize props // this.instance.props.set(schema.props); // } // Set component specific properties if (this.props) { this.componentRef.instance.props.set(this.props); } componentRef.instance.easyFormControl.set({ id: path.join('_') + '_' + Math.random().toString(36).substring(2), control: this.control, schema: schema }); componentRef.changeDetectorRef.detectChanges(); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: FormFieldDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "18.2.12", type: FormFieldDirective, isStandalone: true, selector: "ng-container[easyFormField]", inputs: { disabled: "disabled", props: "props", path: ["path", "path", (val) => { const path = val; if (typeof path === 'string') { return path.split('.'); } return path; }] }, outputs: { change: "change", fieldEvent: "fieldEvent", focus: "focus", blur: "blur", input: "input", keyup: "keyup", keydown: "keydown" }, exportAs: ["easyFormField"], usesOnChanges: true, ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: FormFieldDirective, decorators: [{ type: Directive, args: [{ selector: 'ng-container[easyFormField]', standalone: true, exportAs: 'easyFormField', }] }], propDecorators: { disabled: [{ type: Input }], props: [{ type: Input }], change: [{ type: Output }], fieldEvent: [{ type: Output }], focus: [{ type: Output, args: ["focus"] }], blur: [{ type: Output, args: ["blur"] }], input: [{ type: Output, args: ["input"] }], keyup: [{ type: Output, args: ["keyup"] }], keydown: [{ type: Output, args: ["keydown"] }], path: [{ type: Input, args: [{ required: true, transform: (val) => { const path = val; if (typeof path === 'string') { return path.split('.'); } return path; } }] }] } }); /** * Bind events to input, textarea, select elements and emit events to the parent form field directive */ class BindEventsDirective { constructor() { this.formFieldDirective = inject(FormFieldDirective, { skipSelf: true }); this.emitEvent = (event) => { const directive = this.formFieldDirective; if (directive.fieldEvent && directive.fieldEvent instanceof EventEmitter) { // Check if there are any subscribers to the event if (directive.fieldEvent.observed) { directive.fieldEvent.emit(event); } } }; } onInput(event) { this.emitEvent(event); } onFocus(event) { this.emitEvent(event); } onBlur(event) { this.emitEvent(event); } onKeyup(event) { this.emitEvent(event); } onKeydown(event) { this.emitEvent(event); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: BindEventsDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.12", type: BindEventsDirective, isStandalone: true, selector: "input[bindEvents], textarea[bindEvents], select[bindEvents]", host: { listeners: { "input": "onInput($event)", "focus": "onFocus($event)", "blur": "onBlur($event)", "keyup": "onKeyup($event)", "keydown": "onKeydown($event)" } }, ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: BindEventsDirective, decorators: [{ type: Directive, args: [{ selector: 'input[bindEvents], textarea[bindEvents], select[bindEvents]', standalone: true }] }], propDecorators: { onInput: [{ type: HostListener, args: ['input', ['$event']] }], onFocus: [{ type: HostListener, args: ['focus', ['$event']] }], onBlur: [{ type: HostListener, args: ['blur', ['$event']] }], onKeyup: [{ type: HostListener, args: ['keyup', ['$event']] }], onKeydown: [{ type: HostListener, args: ['keydown', ['$event']] }] } }); class EfTextAreaComponent extends EasyFormControl { static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: EfTextAreaComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.12", type: EfTextAreaComponent, isStandalone: true, selector: "ef-text", usesInheritance: true, ngImport: i0, template: "@if (hasInitialized()) {\r\n @if (easyFormControl().schema!.label) {\r\n <label class=\"ef-form-label\" [for]=\"easyFormControl().id\">{{ easyFormControl().schema!.label | observe }}</label>\r\n }\r\n <textarea bindEvents [id]=\"easyFormControl().id\" [formControl]=\"easyFormControl().control!\"\r\n class=\"ef-input-textarea\">\r\n </textarea>\r\n <ef-errors [control]=\"easyFormControl().control!\" [formField]=\"easyFormControl().schema!\"/>\r\n}\r\n", styles: [":host{display:block}:host-context(.show-errors-submitted .ng-submitted,.show-errors-always,.show-errors-touched .ng-touched,.show-errors-dirty .ng-dirty) .ef-input-textarea.ng-invalid{border-color:hsl(var(--ef-invalid-color, 0 100% 50%))}:host-context(.show-errors-submitted .ng-submitted,.show-errors-always,.show-errors-touched .ng-touched,.show-errors-dirty .ng-dirty) .ef-input-textarea.ng-invalid:focus{outline-color:hsla(var(--ef-invalid-color, 0 100% 50%)/.5)}:host-context(.show-errors-submitted .ng-submitted,.show-errors-always,.show-errors-touched .ng-touched,.show-errors-dirty .ng-dirty) .ef-input-textarea.ng-valid{border-color:hsl(var(--ef-valid-color, 120 100% 42%))}:host-context(.show-errors-submitted .ng-submitted,.show-errors-always,.show-errors-touched .ng-touched,.show-errors-dirty .ng-dirty) .ef-input-textarea.ng-valid:focus{outline-color:hsla(var(--ef-valid-color, 120 100% 42%)/.5)}.ef-form-label{display:block}.ef-input-textarea{width:100%;padding:var(--ef-input-padding, .5em);background:hsl(var(--ef-input-bg, 0 100% 100%));border:1px solid hsl(var(--ef-input-border-color, 0 0% 90%));border-radius:var(--ef-input-border-radius, 5px);outline:3px solid transparent;outline-offset:2px;transition:outline .2s ease-in-out;height:auto;min-height:72px}.ef-input-textarea:focus{outline-color:hsla(var(--ef-input-border-color, 0 0% 90%)/.5)}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.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: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "pipe", type: ObservePipe, name: "observe" }, { kind: "component", type: EfErrorsComponent, selector: "ef-errors", inputs: ["form", "path", "control", "formField"] }, { kind: "directive", type: BindEventsDirective, selector: "input[bindEvents], textarea[bindEvents], select[bindEvents]" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: EfTextAreaComponent, decorators: [{ type: Component, args: [{ selector: 'ef-text', standalone: true, imports: [ ReactiveFormsModule, ObservePipe, EfErrorsComponent, BindEventsDirective ], template: "@if (hasInitialized()) {\r\n @if (easyFormControl().schema!.label) {\r\n <label class=\"ef-form-label\" [for]=\"easyFormControl().id\">{{ easyFormControl().schema!.label | observe }}</label>\r\n }\r\n <textarea bindEvents [id]=\"easyFormControl().id\" [formControl]=\"easyFormControl().control!\"\r\n class=\"ef-input-textarea\">\r\n </textarea>\r\n <ef-errors [control]=\"easyFormControl().control!\" [formField]=\"easyFormControl().schema!\"/>\r\n}\r\n", styles: [":host{display:block}:host-context(.show-errors-submitted .ng-submitted,.show-errors-always,.show-errors-touched .ng-touched,.show-errors-dirty .ng-dirty) .ef-input-textarea.ng-invalid{border-color:hsl(var(--ef-invalid-color, 0 100% 50%))}:host-context(.show-errors-submitted .ng-submitted,.show-errors-always,.show-errors-touched .ng-touched,.show-errors-dirty .ng-dirty) .ef-input-textarea.ng-invalid:focus{outline-color:hsla(var(--ef-invalid-color, 0 100% 50%)/.5)}:host-context(.show-errors-submitted .ng-submitted,.show-errors-always,.show-errors-touched .ng-touched,.show-errors-dirty .ng-dirty) .ef-input-textarea.ng-valid{border-color:hsl(var(--ef-valid-color, 120 100% 42%))}:host-context(.show-errors-submitted .ng-submitted,.show-errors-always,.show-errors-touched .ng-touched,.show-errors-dirty .ng-dirty) .ef-input-textarea.ng-valid:focus{outline-color:hsla(var(--ef-valid-color, 120 100% 42%)/.5)}.ef-form-label{display:block}.ef-input-textarea{width:100%;padding:var(--ef-input-padding, .5em);background:hsl(var(--ef-input-bg, 0 100% 100%));border:1px solid hsl(var(--ef-input-border-color, 0 0% 90%));border-radius:var(--ef-input-border-radius, 5px);outline:3px solid transparent;outline-offset:2px;transition:outline .2s ease-in-out;height:auto;min-height:72px}.ef-input-textarea:focus{outline-color:hsla(var(--ef-input-border-color, 0 0% 90%)/.5)}\n"] }] }] }); class EfSelectComponent extends EasyFormControl { static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: EfSelectComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.12", type: EfSelectComponent, isStandalone: true, selector: "ef-select", usesInheritance: true, ngImport: i0, template: "@if (hasInitialized()) {\r\n @if (schema()!.label) {\r\n <label class=\"ef-form-label\" [for]=\"easyFormControl().id\">{{ easyFormControl().schema?.label | observe }}</label>\r\n }\r\n <select bindEvents [id]=\"easyFormControl().id\" [formControl]=\"easyFormControl().control!\"\r\n class=\"ef-input-select\">\r\n @if (easyFormControl().schema?.options) {\r\n @for (item of (easyFormControl().schema?.options | observe); track item.value) {\r\n <option [value]=\"item.value\">{{ item.label | observe }}</option>\r\n }\r\n }\r\n </select>\r\n <ef-errors [control]=\"easyFormControl().control!\" [formField]=\"easyFormControl().schema!\"/>\r\n}\r\n", styles: [":host{display:block}.ef-form-label{display:block}.ef-input-select{width:100%;padding:var(--ef-input-padding, .5em);background:hsl(var(--ef-input-bg, 0 100% 100%));border:1px solid hsl(var(--ef-input-border-color, 0 0% 90%));border-radius:var(--ef-input-border-radius, 5px);outline:3px solid transparent;outline-offset:2px;transition:outline .2s ease-in-out}.ef-input-select:focus{outline-color:hsla(var(--ef-input-border-color, 0 0% 90%)/.5)}:host-context(.show-errors-submitted .ng-submitted,.show-errors-always,.show-errors-touched .ng-touched,.show-errors-dirty .ng-dirty) .ef-input-select.ng-invalid{border-color:hsl(var(--ef-invalid-color, 0 100% 50%))}:host-context(.show-errors-submitted .ng-submitted,.show-errors-always,.show-errors-touched .ng-touched,.show-errors-dirty .ng-dirty) .ef-input-select.ng-invalid:focus{outline-color:hsla(var(--ef-invalid-color, 0 100% 50%)/.5)}:host-context(.show-errors-submitted .ng-submitted,.show-errors-always,.show-errors-touched .ng-touched,.show-errors-dirty .ng-dirty) .ef-input-select.ng-valid{border-color:hsl(var(--ef-valid-color, 120 100% 42%))}:host-context(.show-errors-submitted .ng-submitted,.show-errors-always,.show-errors-touched .ng-touched,.show-errors-dirty .ng-dirty) .ef-input-select.ng-valid:focus{outline-color:hsla(var(--ef-valid-color, 120 100% 42%)/.5)}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "pipe", type: ObservePipe, name: "observe" }, { kind: "component", type: EfErrorsComponent, selector: "ef-errors", inputs: ["form", "path", "control", "formField"] }, { kind: "directive", type: BindEventsDirective, selector: "input[bindEvents], textarea[bindEvents], select[bindEvents]" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: EfSelectComponent, decorators: [{ type: Component, args: [{ selector: 'ef-select', standalone: true, imports: [ ReactiveFormsModule, ObservePipe, EfErrorsComponent, BindEventsDirective ], template: "@if (hasInitialized()) {\r\n @if (schema()!.label) {\r\n <label class=\"ef-form-label\" [for]=\"easyFormControl().id\">{{ easyFormControl().schema?.label | observe }}</label>\r\n }\r\n <select bindEvents [id]=\"easyFormControl().id\" [formControl]=\"easyFormControl().control!\"\r\n class=\"ef-input-select\">\r\n @if (easyFormControl().schema?.options) {\r\n @for (item of (easyFormControl().schema?.options | observe); track item.value) {\r\n <option [value]=\"item.value\">{{ item.label | observe }}</option>\r\n }\r\n }\r\n </select>\r\n <ef-errors [control]=\"easyFormControl().control!\" [formField]=\"easyFormControl().schema!\"/>\r\n}\r\n", styles: [":host{display:block}.ef-form-label{display:block}.ef-input-select{width:100%;padding:var(--ef-input-padding, .5em);background:hsl(var(--ef-input-bg, 0 100% 100%));border:1px solid hsl(var(--ef-input-border-color, 0 0% 90%));border-radius:var(--ef-input-border-radius, 5px);outline:3px solid transparent;outline-offset:2px;transition:outline .2s ease-in-out}.ef-input-select:focus{outline-color:hsla(var(--ef-input-border-color, 0 0% 90%)/.5)}:host-context(.show-errors-submitted .ng-submitted,.show-errors-always,.show-errors-touched .ng-touched,.show-errors-dirty .ng-dirty) .ef-input-select.ng-invalid{border-color:hsl(var(--ef-invalid-color, 0 100% 50%))}:host-context(.show-errors-submitted .ng-submitted,.show-errors-always,.show-errors-touched .ng-touched,.show-errors-dirty .ng-dirty) .ef-input-select.ng-invalid:focus{outline-color:hsla(var(--ef-invalid-color, 0 100% 50%)/.5)}:host-context(.show-errors-submitted .ng-submitted,.show-errors-always,.show-errors-touched .ng-touched,.show-errors-dirty .ng-dirty) .ef-input-select.ng-valid{border-color:hsl(var(--ef-valid-color, 120 100% 42%))}:host-context(.show-errors-submitted .ng-submitted,.show-errors-always,.show-errors-touched .ng-touched,.show-errors-dirty .ng-dirty) .ef-input-select.ng-valid:focus{outline-color:hsla(var(--ef-valid-color, 120 100% 42%)/.5)}\n"] }] }] }); class EfCheckboxComponent extends EasyFormControl { static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: EfCheckboxComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.12", type: EfCheckboxComponent, isStandalone: true, selector: "ef-checkbox", usesInheritance: true, ngImport: i0, template: "@if (hasInitialized()) {\r\n <input type=\"checkbox\" bindEvents [formControl]=\"easyFormControl().control!\" [id]=\"easyFormControl().id\">\r\n @if (easyFormControl().schema?.label) {\r\n <label class=\"ef-form-label\" [for]=\"easyFormControl().id\">{{ easyFormControl().schema?.label | observe }}</label>\r\n }\r\n <ef-errors [control]=\"easyFormControl().control!\" [formField]=\"easyFormControl().schema!\"/>\r\n}\r\n", styles: [":host{display:flex;align-items:center;gap:.5rem}:host input[type=checkbox]{appearance:none;display:inline-flex;justify-content:center;align-items:center;min-width:var(--checkbox-size, 1.5rem);min-height:var(--checkbox-size, 1.5rem);max-width:var(--checkbox-size, 1.5rem);max-height:var(--checkbox-size, 1.5rem);border-radius:20%;padding:0;background-color:hsl(var(--ef-input-bg, 0 100% 100%));border:1px solid hsl(var(--ef-input-border-color, 0 0% 90%));accent-color:hsl(var(--ef-input-accent-color, 200 100% 50%));transition:transform 50ms ease-in-out}:host input[type=checkbox]:active{transform:scale(1.2)}:host input[type=checkbox]:active:disabled{transform:none}:host input[type=checkbox]:focus-visible{outline:3px solid hsl(var(--ef-input-border-color, 0 0% 90%));outline-offset:2px}:host input[type=checkbox]:checked{border:1px solid hsl(var(--ef-input-accent-color, 200 100% 50%));background-color:hsl(var(--ef-input-accent-color, 200 100% 50%))}:host input[type=checkbox]:checked:after{content:\"\";width:calc(var(--checkbox-size, 1.5rem) * .8);height:calc(var(--checkbox-size, 1.5rem) * .8);border-radius:20%;background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e\");background-repeat:no-repeat}:host[disabled],:host:disabled{opacity:.5;cursor:default}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "pipe", type: ObservePipe, name: "observe" }, { kind: "component", type: EfErrorsComponent, selector: "ef-errors", inputs: ["form", "path", "control", "formField"] }, { kind: "directive", type: BindEventsDirective, selector: "input[bindEvents], textarea[bindEvents], select[bindEvents]" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: EfCheckboxComponent, decorators: [{ type: Component, args: [{ selector: 'ef-checkbox', standalone: true, imports: [ ReactiveFormsModule, ObservePipe, EfErrorsComponent, BindEventsDirective ], template: "@if (hasInitialized()) {\r\n <input type=\"checkbox\" bindEvents [formControl]=\"easyFormControl().control!\" [id]=\"easyFormControl().id\">\r\n @if (easyFormControl().schema?.label) {\r\n <label class=\"ef-form-label\" [for]=\"easyFormControl().id\">{{ easyFormControl().schema?.label | observe }}</label>\r\n }\r\n <ef-errors [control]=\"easyFormControl().control!\" [formField]=\"easyFormControl().schema!\"/>\r\n}\r\n", styles: [":host{display:flex;align-items:center;gap:.5rem}:host input[type=checkbox]{appearance:none;display:inline-flex;justify-content:center;align-items:center;min-width:var(--checkbox-size, 1.5rem);min-height:var(--checkbox-size, 1.5rem);max-width:var(--checkbox-size, 1.5rem);max-height:var(--checkbox-size, 1.5rem);border-radius:20%;padding:0;background-color:hsl(var(--ef-input-bg, 0 100% 100%));border:1px solid hsl(var(--ef-input-border-color, 0 0% 90%));accent-color:hsl(var(--ef-input-accent-color, 200 100% 50%));transition:transform 50ms ease-in-out}:host input[type=checkbox]:active{transform:scale(1.2)}:host input[type=checkbox]:active:disabled{transform:none}:host input[type=checkbox]:focus-visible{outline:3px solid hsl(var(--ef-input-border-color, 0 0% 90%));outline-offset:2px}:host input[type=checkbox]:checked{border:1px solid hsl(var(--ef-input-accent-color, 200 100% 50%));background-color:hsl(var(--ef-input-accent-color, 200 100% 50%))}:host input[type=checkbox]:checked:after{content:\"\";width:calc(var(--checkbox-size, 1.5rem) * .8);height:calc(var(--checkbox-size, 1.5rem) * .8);border-radius:20%;background-image:url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e\");background-repeat:no-repeat}:host[disabled],:host:disabled{opacity:.5;cursor:default}\n"] }] }] }); class EfRadioComponent extends EasyFormControl { static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: EfRadioComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.12", type: EfRadioComponent, isStandalone: true, selector: "lib-ef-radio", usesInheritance: true, ngImport: i0, template: "@if