@yyasinaslan/easyform
Version:
Angular Easy Form
908 lines (892 loc) • 77.6 kB
JavaScript
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