@masterteam/forms 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,24 @@
1
+ # @masterteam/forms
2
+
3
+ Angular Form Components Library
4
+
5
+ ## Components
6
+
7
+ - **DynamicFieldComponent**: A dynamic field component that renders different input types based on configuration
8
+ - **DynamicFormComponent**: A dynamic form component that creates forms based on configuration objects
9
+
10
+ ## Pipes
11
+
12
+ - **SortPipe**: A pipe for sorting arrays by specified keys and directions
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install @masterteam/forms
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ ```typescript
23
+ import { DynamicFieldComponent, DynamicFormComponent, SortPipe } from '@masterteam/forms';
24
+ ```
@@ -0,0 +1,16 @@
1
+ import * as _angular_core from '@angular/core';
2
+ import { Signal } from '@angular/core';
3
+ import { DynamicFieldConfig } from '@masterteam/components';
4
+
5
+ declare class DynamicField {
6
+ readonly fieldConfig: _angular_core.InputSignal<DynamicFieldConfig>;
7
+ readonly transformedFieldConfig: Signal<DynamicFieldConfig>;
8
+ private controlContainer;
9
+ readonly fieldName: _angular_core.InputSignal<string>;
10
+ constructor();
11
+ private transformToFieldConfig;
12
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<DynamicField, never>;
13
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DynamicField, "mt-dynamic-field", never, { "fieldConfig": { "alias": "fieldConfig"; "required": true; "isSignal": true; }; "fieldName": { "alias": "fieldName"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
14
+ }
15
+
16
+ export { DynamicField };
@@ -0,0 +1,28 @@
1
+ import * as i0 from '@angular/core';
2
+ import { OnDestroy } from '@angular/core';
3
+ import { ControlValueAccessor, Validator, FormGroup, AbstractControl, ValidationErrors } from '@angular/forms';
4
+ import { DynamicFormConfig } from '@masterteam/components';
5
+
6
+ declare class DynamicForm implements OnDestroy, ControlValueAccessor, Validator {
7
+ private fb;
8
+ readonly formConfig: i0.InputSignal<DynamicFormConfig>;
9
+ form: FormGroup<{}>;
10
+ private onChange;
11
+ private onTouched;
12
+ private onValidatorChange;
13
+ private formSubscription?;
14
+ private statusSubscription?;
15
+ constructor();
16
+ registerOnValidatorChange(fn: () => void): void;
17
+ registerOnChange(fn: (value: any) => void): void;
18
+ registerOnTouched(fn: () => void): void;
19
+ private buildForm;
20
+ writeValue(value: any): void;
21
+ validate(_control: AbstractControl): ValidationErrors | null;
22
+ private buildValidators;
23
+ ngOnDestroy(): void;
24
+ static ɵfac: i0.ɵɵFactoryDeclaration<DynamicForm, never>;
25
+ static ɵcmp: i0.ɵɵComponentDeclaration<DynamicForm, "mt-dynamic-form", never, { "formConfig": { "alias": "formConfig"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
26
+ }
27
+
28
+ export { DynamicForm };
@@ -0,0 +1,85 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, computed, inject, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import * as i1 from '@angular/forms';
4
+ import { ControlContainer, FormGroupDirective, ReactiveFormsModule } from '@angular/forms';
5
+ import { TextField } from '@masterteam/components/text-field';
6
+ import { TextareaField } from '@masterteam/components/textarea-field';
7
+ import { SelectField } from '@masterteam/components/select-field';
8
+ import { DateField } from '@masterteam/components/date-field';
9
+ import { NumberField } from '@masterteam/components/number-field';
10
+ import { SliderField } from '@masterteam/components/slider-field';
11
+ import { MultiSelectField } from '@masterteam/components/multi-select-field';
12
+ import { CheckboxField } from '@masterteam/components/checkbox-field';
13
+ import { TextFieldConfig, TextareaFieldConfig, SelectFieldConfig, DateFieldConfig, NumberFieldConfig, SliderFieldConfig, MultiSelectFieldConfig, CheckboxFieldConfig } from '@masterteam/components';
14
+
15
+ class DynamicField {
16
+ // Input signal with transform to handle class for text type
17
+ fieldConfig = input.required(...(ngDevMode ? [{ debugName: "fieldConfig" }] : []));
18
+ // Computed property for transformed field config
19
+ transformedFieldConfig = computed(() => this.transformToFieldConfig(this.fieldConfig()), ...(ngDevMode ? [{ debugName: "transformedFieldConfig" }] : []));
20
+ // Inject ControlContainer to connect directly with parent form
21
+ controlContainer = inject(ControlContainer);
22
+ // Input for the form control name
23
+ fieldName = input.required(...(ngDevMode ? [{ debugName: "fieldName" }] : []));
24
+ constructor() { }
25
+ transformToFieldConfig(value) {
26
+ // If it's a plain object, transform it to appropriate field config
27
+ if (typeof value === 'object') {
28
+ if (value.type === 'text') {
29
+ return new TextFieldConfig(value);
30
+ }
31
+ if (value.type === 'textarea') {
32
+ return new TextareaFieldConfig(value);
33
+ }
34
+ if (value.type === 'select') {
35
+ return new SelectFieldConfig(value);
36
+ }
37
+ if (value.type === 'date') {
38
+ return new DateFieldConfig(value);
39
+ }
40
+ if (value.type === 'number') {
41
+ return new NumberFieldConfig(value);
42
+ }
43
+ if (value.type === 'slider') {
44
+ return new SliderFieldConfig(value);
45
+ }
46
+ if (value.type === 'multi-select') {
47
+ return new MultiSelectFieldConfig(value);
48
+ }
49
+ if (value.type === 'checkbox') {
50
+ return new CheckboxFieldConfig(value);
51
+ }
52
+ }
53
+ // Default fallback to TextFieldConfig
54
+ return new TextFieldConfig({
55
+ ...value,
56
+ });
57
+ }
58
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: DynamicField, deps: [], target: i0.ɵɵFactoryTarget.Component });
59
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.0", type: DynamicField, isStandalone: true, selector: "mt-dynamic-field", inputs: { fieldConfig: { classPropertyName: "fieldConfig", publicName: "fieldConfig", isSignal: true, isRequired: true, transformFunction: null }, fieldName: { classPropertyName: "fieldName", publicName: "fieldName", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "@switch (transformedFieldConfig().type) {\n @case (\"text\") {\n <mt-text-field\n [label]=\"transformedFieldConfig().label\"\n [placeholder]=\"transformedFieldConfig().placeholder\"\n [type]=\"transformedFieldConfig().inputType || 'text'\"\n [readonly]=\"transformedFieldConfig().readonly!\"\n [formControlName]=\"fieldName()\"\n />\n }\n @case (\"textarea\") {\n <mt-textarea-field\n [label]=\"transformedFieldConfig().label\"\n [placeholder]=\"transformedFieldConfig().placeholder\"\n [readonly]=\"transformedFieldConfig().readonly!\"\n [formControlName]=\"fieldName()\"\n />\n }\n @case (\"select\") {\n <mt-select-field\n [label]=\"transformedFieldConfig().label || ''\"\n [placeholder]=\"transformedFieldConfig().placeholder || ''\"\n [options]=\"transformedFieldConfig().options || []\"\n [optionLabel]=\"transformedFieldConfig().optionLabel || 'label'\"\n [optionValue]=\"transformedFieldConfig().optionValue || 'value'\"\n [readonly]=\"transformedFieldConfig().readonly!\"\n [formControlName]=\"fieldName()\"\n />\n }\n @case (\"date\") {\n <mt-date-field\n [label]=\"transformedFieldConfig().label\"\n [placeholder]=\"transformedFieldConfig().placeholder\"\n [readonly]=\"transformedFieldConfig().readonly!\"\n [formControlName]=\"fieldName()\"\n />\n }\n @case (\"number\") {\n <mt-number-field\n [label]=\"transformedFieldConfig().label\"\n [placeholder]=\"transformedFieldConfig().placeholder\"\n [readonly]=\"transformedFieldConfig().readonly!\"\n [formControlName]=\"fieldName()\"\n />\n }\n @case (\"slider\") {\n <mt-slider-field\n [label]=\"transformedFieldConfig().label\"\n [readonly]=\"transformedFieldConfig().readonly!\"\n [formControlName]=\"fieldName()\"\n />\n }\n @case (\"multi-select\") {\n <mt-multi-select-field\n [label]=\"transformedFieldConfig().label || ''\"\n [placeholder]=\"transformedFieldConfig().placeholder || ''\"\n [options]=\"transformedFieldConfig().options || []\"\n [optionLabel]=\"transformedFieldConfig().optionLabel || 'label'\"\n [optionValue]=\"transformedFieldConfig().optionValue || 'value'\"\n [readonly]=\"transformedFieldConfig().readonly!\"\n [formControlName]=\"fieldName()\"\n />\n }\n @case (\"checkbox\") {\n <mt-checkbox-field\n [label]=\"transformedFieldConfig().label\"\n [readonly]=\"transformedFieldConfig().readonly!\"\n [formControlName]=\"fieldName()\"\n />\n }\n}\n", styles: [":host{display:block;width:100%}\n"], dependencies: [{ kind: "component", type: TextField, selector: "mt-text-field", inputs: ["field", "hint", "label", "placeholder", "class", "type", "readonly", "pInputs", "pKeyFilter"] }, { kind: "component", type: TextareaField, selector: "mt-textarea-field", inputs: ["field", "label", "placeholder", "class", "readonly", "noErrorStyle", "pInputs", "rows"] }, { kind: "component", type: SelectField, selector: "mt-select-field", inputs: ["field", "label", "placeholder", "hasPlaceholderPrefix", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "clearAfterSelect"], outputs: ["onChange"] }, { kind: "component", type: DateField, selector: "mt-date-field", inputs: ["field", "label", "placeholder", "class", "readonly", "showIcon", "showClear", "showTime", "pInputs"] }, { kind: "component", type: NumberField, selector: "mt-number-field", inputs: ["field", "label", "placeholder", "class", "readonly", "pInputs", "format", "maxFractionDigits", "min", "max"] }, { kind: "component", type: SliderField, selector: "mt-slider-field", inputs: ["field", "label", "animate", "class", "min", "max", "step", "hideNumber", "unit", "readonly", "pInputs"], outputs: ["onChange", "onSlideEnd"] }, { kind: "component", type: MultiSelectField, selector: "mt-multi-select-field", inputs: ["field", "label", "placeholder", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "display"], outputs: ["onChange"] }, { kind: "component", type: CheckboxField, selector: "mt-checkbox-field", inputs: ["label", "placeholder", "class", "readonly", "pInputs"], outputs: ["onChange"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }], viewProviders: [
60
+ { provide: ControlContainer, useExisting: FormGroupDirective },
61
+ ], changeDetection: i0.ChangeDetectionStrategy.OnPush });
62
+ }
63
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: DynamicField, decorators: [{
64
+ type: Component,
65
+ args: [{ selector: 'mt-dynamic-field', standalone: true, imports: [
66
+ TextField,
67
+ TextareaField,
68
+ SelectField,
69
+ DateField,
70
+ NumberField,
71
+ SliderField,
72
+ MultiSelectField,
73
+ CheckboxField,
74
+ ReactiveFormsModule,
75
+ ], changeDetection: ChangeDetectionStrategy.OnPush, viewProviders: [
76
+ { provide: ControlContainer, useExisting: FormGroupDirective },
77
+ ], template: "@switch (transformedFieldConfig().type) {\n @case (\"text\") {\n <mt-text-field\n [label]=\"transformedFieldConfig().label\"\n [placeholder]=\"transformedFieldConfig().placeholder\"\n [type]=\"transformedFieldConfig().inputType || 'text'\"\n [readonly]=\"transformedFieldConfig().readonly!\"\n [formControlName]=\"fieldName()\"\n />\n }\n @case (\"textarea\") {\n <mt-textarea-field\n [label]=\"transformedFieldConfig().label\"\n [placeholder]=\"transformedFieldConfig().placeholder\"\n [readonly]=\"transformedFieldConfig().readonly!\"\n [formControlName]=\"fieldName()\"\n />\n }\n @case (\"select\") {\n <mt-select-field\n [label]=\"transformedFieldConfig().label || ''\"\n [placeholder]=\"transformedFieldConfig().placeholder || ''\"\n [options]=\"transformedFieldConfig().options || []\"\n [optionLabel]=\"transformedFieldConfig().optionLabel || 'label'\"\n [optionValue]=\"transformedFieldConfig().optionValue || 'value'\"\n [readonly]=\"transformedFieldConfig().readonly!\"\n [formControlName]=\"fieldName()\"\n />\n }\n @case (\"date\") {\n <mt-date-field\n [label]=\"transformedFieldConfig().label\"\n [placeholder]=\"transformedFieldConfig().placeholder\"\n [readonly]=\"transformedFieldConfig().readonly!\"\n [formControlName]=\"fieldName()\"\n />\n }\n @case (\"number\") {\n <mt-number-field\n [label]=\"transformedFieldConfig().label\"\n [placeholder]=\"transformedFieldConfig().placeholder\"\n [readonly]=\"transformedFieldConfig().readonly!\"\n [formControlName]=\"fieldName()\"\n />\n }\n @case (\"slider\") {\n <mt-slider-field\n [label]=\"transformedFieldConfig().label\"\n [readonly]=\"transformedFieldConfig().readonly!\"\n [formControlName]=\"fieldName()\"\n />\n }\n @case (\"multi-select\") {\n <mt-multi-select-field\n [label]=\"transformedFieldConfig().label || ''\"\n [placeholder]=\"transformedFieldConfig().placeholder || ''\"\n [options]=\"transformedFieldConfig().options || []\"\n [optionLabel]=\"transformedFieldConfig().optionLabel || 'label'\"\n [optionValue]=\"transformedFieldConfig().optionValue || 'value'\"\n [readonly]=\"transformedFieldConfig().readonly!\"\n [formControlName]=\"fieldName()\"\n />\n }\n @case (\"checkbox\") {\n <mt-checkbox-field\n [label]=\"transformedFieldConfig().label\"\n [readonly]=\"transformedFieldConfig().readonly!\"\n [formControlName]=\"fieldName()\"\n />\n }\n}\n", styles: [":host{display:block;width:100%}\n"] }]
78
+ }], ctorParameters: () => [] });
79
+
80
+ /**
81
+ * Generated bundle index. Do not edit.
82
+ */
83
+
84
+ export { DynamicField };
85
+ //# sourceMappingURL=masterteam-forms-dynamic-field.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"masterteam-forms-dynamic-field.mjs","sources":["../../../../packages/masterteam/forms/dynamic-field/dynamic-field.ts","../../../../packages/masterteam/forms/dynamic-field/dynamic-field.html","../../../../packages/masterteam/forms/dynamic-field/masterteam-forms-dynamic-field.ts"],"sourcesContent":["import {\n Component,\n input,\n computed,\n ChangeDetectionStrategy,\n Signal,\n inject,\n} from '@angular/core';\nimport {\n ReactiveFormsModule,\n ControlContainer,\n FormGroupDirective,\n} from '@angular/forms';\nimport { TextField } from '@masterteam/components/text-field';\nimport { TextareaField } from '@masterteam/components/textarea-field';\nimport { SelectField } from '@masterteam/components/select-field';\nimport { DateField } from '@masterteam/components/date-field';\nimport { NumberField } from '@masterteam/components/number-field';\nimport { SliderField } from '@masterteam/components/slider-field';\nimport { MultiSelectField } from '@masterteam/components/multi-select-field';\nimport { CheckboxField } from '@masterteam/components/checkbox-field';\nimport {\n TextFieldConfig,\n TextareaFieldConfig,\n SelectFieldConfig,\n DateFieldConfig,\n NumberFieldConfig,\n SliderFieldConfig,\n MultiSelectFieldConfig,\n CheckboxFieldConfig,\n DynamicFieldConfig,\n} from '@masterteam/components';\n\n@Component({\n selector: 'mt-dynamic-field',\n standalone: true,\n imports: [\n TextField,\n TextareaField,\n SelectField,\n DateField,\n NumberField,\n SliderField,\n MultiSelectField,\n CheckboxField,\n ReactiveFormsModule,\n ],\n templateUrl: './dynamic-field.html',\n styleUrls: ['./dynamic-field.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n viewProviders: [\n { provide: ControlContainer, useExisting: FormGroupDirective },\n ],\n})\nexport class DynamicField {\n // Input signal with transform to handle class for text type\n readonly fieldConfig = input.required<DynamicFieldConfig>();\n\n // Computed property for transformed field config\n readonly transformedFieldConfig: Signal<DynamicFieldConfig> = computed(() =>\n this.transformToFieldConfig(this.fieldConfig()),\n );\n\n // Inject ControlContainer to connect directly with parent form\n private controlContainer = inject(ControlContainer);\n\n // Input for the form control name\n readonly fieldName = input.required<string>();\n constructor() {}\n\n private transformToFieldConfig(value: any): DynamicFieldConfig {\n // If it's a plain object, transform it to appropriate field config\n if (typeof value === 'object') {\n if (value.type === 'text') {\n return new TextFieldConfig(value);\n }\n if (value.type === 'textarea') {\n return new TextareaFieldConfig(value);\n }\n if (value.type === 'select') {\n return new SelectFieldConfig(value);\n }\n if (value.type === 'date') {\n return new DateFieldConfig(value);\n }\n if (value.type === 'number') {\n return new NumberFieldConfig(value);\n }\n if (value.type === 'slider') {\n return new SliderFieldConfig(value);\n }\n if (value.type === 'multi-select') {\n return new MultiSelectFieldConfig(value);\n }\n if (value.type === 'checkbox') {\n return new CheckboxFieldConfig(value);\n }\n }\n\n // Default fallback to TextFieldConfig\n return new TextFieldConfig({\n ...value,\n });\n }\n}\n","@switch (transformedFieldConfig().type) {\n @case (\"text\") {\n <mt-text-field\n [label]=\"transformedFieldConfig().label\"\n [placeholder]=\"transformedFieldConfig().placeholder\"\n [type]=\"transformedFieldConfig().inputType || 'text'\"\n [readonly]=\"transformedFieldConfig().readonly!\"\n [formControlName]=\"fieldName()\"\n />\n }\n @case (\"textarea\") {\n <mt-textarea-field\n [label]=\"transformedFieldConfig().label\"\n [placeholder]=\"transformedFieldConfig().placeholder\"\n [readonly]=\"transformedFieldConfig().readonly!\"\n [formControlName]=\"fieldName()\"\n />\n }\n @case (\"select\") {\n <mt-select-field\n [label]=\"transformedFieldConfig().label || ''\"\n [placeholder]=\"transformedFieldConfig().placeholder || ''\"\n [options]=\"transformedFieldConfig().options || []\"\n [optionLabel]=\"transformedFieldConfig().optionLabel || 'label'\"\n [optionValue]=\"transformedFieldConfig().optionValue || 'value'\"\n [readonly]=\"transformedFieldConfig().readonly!\"\n [formControlName]=\"fieldName()\"\n />\n }\n @case (\"date\") {\n <mt-date-field\n [label]=\"transformedFieldConfig().label\"\n [placeholder]=\"transformedFieldConfig().placeholder\"\n [readonly]=\"transformedFieldConfig().readonly!\"\n [formControlName]=\"fieldName()\"\n />\n }\n @case (\"number\") {\n <mt-number-field\n [label]=\"transformedFieldConfig().label\"\n [placeholder]=\"transformedFieldConfig().placeholder\"\n [readonly]=\"transformedFieldConfig().readonly!\"\n [formControlName]=\"fieldName()\"\n />\n }\n @case (\"slider\") {\n <mt-slider-field\n [label]=\"transformedFieldConfig().label\"\n [readonly]=\"transformedFieldConfig().readonly!\"\n [formControlName]=\"fieldName()\"\n />\n }\n @case (\"multi-select\") {\n <mt-multi-select-field\n [label]=\"transformedFieldConfig().label || ''\"\n [placeholder]=\"transformedFieldConfig().placeholder || ''\"\n [options]=\"transformedFieldConfig().options || []\"\n [optionLabel]=\"transformedFieldConfig().optionLabel || 'label'\"\n [optionValue]=\"transformedFieldConfig().optionValue || 'value'\"\n [readonly]=\"transformedFieldConfig().readonly!\"\n [formControlName]=\"fieldName()\"\n />\n }\n @case (\"checkbox\") {\n <mt-checkbox-field\n [label]=\"transformedFieldConfig().label\"\n [readonly]=\"transformedFieldConfig().readonly!\"\n [formControlName]=\"fieldName()\"\n />\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;;;;;;;;;MAsDa,YAAY,CAAA;;AAEd,IAAA,WAAW,GAAG,KAAK,CAAC,QAAQ,sDAAsB;;AAGlD,IAAA,sBAAsB,GAA+B,QAAQ,CAAC,MACrE,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,kEAChD;;AAGO,IAAA,gBAAgB,GAAG,MAAM,CAAC,gBAAgB,CAAC;;AAG1C,IAAA,SAAS,GAAG,KAAK,CAAC,QAAQ,oDAAU;AAC7C,IAAA,WAAA,GAAA,EAAe;AAEP,IAAA,sBAAsB,CAAC,KAAU,EAAA;;AAEvC,QAAA,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;AAC7B,YAAA,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE;AACzB,gBAAA,OAAO,IAAI,eAAe,CAAC,KAAK,CAAC;YACnC;AACA,YAAA,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE;AAC7B,gBAAA,OAAO,IAAI,mBAAmB,CAAC,KAAK,CAAC;YACvC;AACA,YAAA,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE;AAC3B,gBAAA,OAAO,IAAI,iBAAiB,CAAC,KAAK,CAAC;YACrC;AACA,YAAA,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE;AACzB,gBAAA,OAAO,IAAI,eAAe,CAAC,KAAK,CAAC;YACnC;AACA,YAAA,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE;AAC3B,gBAAA,OAAO,IAAI,iBAAiB,CAAC,KAAK,CAAC;YACrC;AACA,YAAA,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE;AAC3B,gBAAA,OAAO,IAAI,iBAAiB,CAAC,KAAK,CAAC;YACrC;AACA,YAAA,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,EAAE;AACjC,gBAAA,OAAO,IAAI,sBAAsB,CAAC,KAAK,CAAC;YAC1C;AACA,YAAA,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE;AAC7B,gBAAA,OAAO,IAAI,mBAAmB,CAAC,KAAK,CAAC;YACvC;QACF;;QAGA,OAAO,IAAI,eAAe,CAAC;AACzB,YAAA,GAAG,KAAK;AACT,SAAA,CAAC;IACJ;uGAjDW,YAAY,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAZ,YAAY,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,kBAAA,EAAA,MAAA,EAAA,EAAA,WAAA,EAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,UAAA,EAAA,aAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECtDzB,2hFAuEA,EAAA,MAAA,EAAA,CAAA,mCAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EDlCI,SAAS,mKACT,aAAa,EAAA,QAAA,EAAA,mBAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,OAAA,EAAA,aAAA,EAAA,OAAA,EAAA,UAAA,EAAA,cAAA,EAAA,SAAA,EAAA,MAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACb,WAAW,EAAA,QAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,OAAA,EAAA,aAAA,EAAA,sBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,SAAA,EAAA,SAAA,EAAA,aAAA,EAAA,aAAA,EAAA,QAAA,EAAA,UAAA,EAAA,SAAA,EAAA,WAAA,EAAA,kBAAA,CAAA,EAAA,OAAA,EAAA,CAAA,UAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACX,SAAS,0KACT,WAAW,EAAA,QAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,OAAA,EAAA,aAAA,EAAA,OAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,mBAAA,EAAA,KAAA,EAAA,KAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACX,WAAW,EAAA,QAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,OAAA,EAAA,SAAA,EAAA,OAAA,EAAA,KAAA,EAAA,KAAA,EAAA,MAAA,EAAA,YAAA,EAAA,MAAA,EAAA,UAAA,EAAA,SAAA,CAAA,EAAA,OAAA,EAAA,CAAA,UAAA,EAAA,YAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACX,gBAAgB,sQAChB,aAAa,EAAA,QAAA,EAAA,mBAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,aAAA,EAAA,OAAA,EAAA,UAAA,EAAA,SAAA,CAAA,EAAA,OAAA,EAAA,CAAA,UAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EACb,mBAAmB,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,eAAA,EAAA,QAAA,EAAA,2CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,eAAA,EAAA,QAAA,EAAA,mBAAA,EAAA,MAAA,EAAA,CAAA,iBAAA,EAAA,UAAA,EAAA,SAAA,CAAA,EAAA,OAAA,EAAA,CAAA,eAAA,CAAA,EAAA,CAAA,EAAA,aAAA,EAKN;AACb,YAAA,EAAE,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,kBAAkB,EAAE;AAC/D,SAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAEU,YAAY,EAAA,UAAA,EAAA,CAAA;kBArBxB,SAAS;+BACE,kBAAkB,EAAA,UAAA,EAChB,IAAI,EAAA,OAAA,EACP;wBACP,SAAS;wBACT,aAAa;wBACb,WAAW;wBACX,SAAS;wBACT,WAAW;wBACX,WAAW;wBACX,gBAAgB;wBAChB,aAAa;wBACb,mBAAmB;qBACpB,EAAA,eAAA,EAGgB,uBAAuB,CAAC,MAAM,EAAA,aAAA,EAChC;AACb,wBAAA,EAAE,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,kBAAkB,EAAE;AAC/D,qBAAA,EAAA,QAAA,EAAA,2hFAAA,EAAA,MAAA,EAAA,CAAA,mCAAA,CAAA,EAAA;;;AEpDH;;AAEG;;;;"}
@@ -0,0 +1,174 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, input, effect, forwardRef, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import * as i1 from '@angular/forms';
4
+ import { FormBuilder, FormGroup, Validators, ReactiveFormsModule, NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms';
5
+ import { CommonModule } from '@angular/common';
6
+ import { DynamicField } from '@masterteam/forms/dynamic-field';
7
+ import { SortPipe } from '@masterteam/forms/pipes';
8
+ import { createCustomValidator, wrapValidatorWithMessage } from '@masterteam/components';
9
+
10
+ class DynamicForm {
11
+ fb = inject(FormBuilder);
12
+ formConfig = input.required(...(ngDevMode ? [{ debugName: "formConfig" }] : []));
13
+ form = new FormGroup({});
14
+ // ControlValueAccessor implementation
15
+ onChange = (_value) => { };
16
+ onTouched = () => { };
17
+ onValidatorChange = () => { };
18
+ // private disabled = false;
19
+ formSubscription;
20
+ statusSubscription;
21
+ constructor() {
22
+ // Effect to rebuild form when config changes
23
+ effect(() => {
24
+ this.buildForm();
25
+ });
26
+ }
27
+ registerOnValidatorChange(fn) {
28
+ this.onValidatorChange = fn;
29
+ }
30
+ registerOnChange(fn) {
31
+ this.onChange = fn;
32
+ }
33
+ registerOnTouched(fn) {
34
+ this.onTouched = fn;
35
+ }
36
+ buildForm() {
37
+ // Clean up previous subscriptions
38
+ if (this.formSubscription) {
39
+ this.formSubscription.unsubscribe();
40
+ }
41
+ if (this.statusSubscription) {
42
+ this.statusSubscription.unsubscribe();
43
+ }
44
+ const formControls = {};
45
+ this.formConfig().sections.forEach((section) => {
46
+ section.fields.forEach((field) => {
47
+ if (field.key) {
48
+ const validators = this.buildValidators(field.validators || []);
49
+ const control = this.fb.control({
50
+ value: field.defaultValue || '',
51
+ disabled: field.disabled || false,
52
+ }, validators);
53
+ formControls[field.key] = control;
54
+ }
55
+ });
56
+ });
57
+ this.form = this.fb.group(formControls);
58
+ // Subscribe to form value changes
59
+ this.formSubscription = this.form.valueChanges.subscribe((value) => {
60
+ this.onChange(value);
61
+ });
62
+ // Trigger initial validation state
63
+ this.onValidatorChange();
64
+ }
65
+ // ControlValueAccessor implementation
66
+ writeValue(value) {
67
+ if (value && this.form) {
68
+ this.form.patchValue(value, { emitEvent: false });
69
+ }
70
+ }
71
+ validate(_control) {
72
+ if (!this.form) {
73
+ return null;
74
+ }
75
+ // Return the form's errors if invalid, null if valid
76
+ return this.form.valid ? null : { invalidForm: true };
77
+ }
78
+ buildValidators(validatorConfigs) {
79
+ const validators = [];
80
+ validatorConfigs.forEach((config) => {
81
+ let validator = null;
82
+ switch (config.type) {
83
+ case 'required':
84
+ validator = Validators.required;
85
+ break;
86
+ case 'email':
87
+ validator = Validators.email;
88
+ break;
89
+ case 'minLength':
90
+ if (config.value) {
91
+ validator = Validators.minLength(config.value);
92
+ }
93
+ break;
94
+ case 'maxLength':
95
+ if (config.value) {
96
+ validator = Validators.maxLength(config.value);
97
+ }
98
+ break;
99
+ case 'min':
100
+ if (config.value !== undefined) {
101
+ validator = Validators.min(config.value);
102
+ }
103
+ break;
104
+ case 'max':
105
+ if (config.value !== undefined) {
106
+ validator = Validators.max(config.value);
107
+ }
108
+ break;
109
+ case 'pattern':
110
+ if (config.value) {
111
+ validator = Validators.pattern(config.value);
112
+ }
113
+ break;
114
+ case 'custom':
115
+ if (config.customValidator) {
116
+ validators.push(createCustomValidator(config.customValidator, config.message));
117
+ }
118
+ break;
119
+ }
120
+ // If we have a validator and a custom message, wrap it
121
+ if (validator && config.message) {
122
+ validators.push(wrapValidatorWithMessage(validator, config.type, config.message));
123
+ }
124
+ else if (validator) {
125
+ validators.push(validator);
126
+ }
127
+ });
128
+ return validators;
129
+ }
130
+ ngOnDestroy() {
131
+ // Clean up subscriptions
132
+ if (this.formSubscription) {
133
+ this.formSubscription.unsubscribe();
134
+ }
135
+ if (this.statusSubscription) {
136
+ this.statusSubscription.unsubscribe();
137
+ }
138
+ }
139
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: DynamicForm, deps: [], target: i0.ɵɵFactoryTarget.Component });
140
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.0", type: DynamicForm, isStandalone: true, selector: "mt-dynamic-form", inputs: { formConfig: { classPropertyName: "formConfig", publicName: "formConfig", isSignal: true, isRequired: true, transformFunction: null } }, providers: [
141
+ {
142
+ provide: NG_VALUE_ACCESSOR,
143
+ useExisting: forwardRef(() => DynamicForm),
144
+ multi: true,
145
+ },
146
+ {
147
+ provide: NG_VALIDATORS,
148
+ useExisting: forwardRef(() => DynamicForm),
149
+ multi: true,
150
+ },
151
+ ], ngImport: i0, template: "<form [formGroup]=\"form\">\n <div\n class=\"flex flex-col gap-6 max-w-4xl mx-auto p-4\"\n [class]=\"formConfig().layout?.containerClass\"\n >\n @for (\n section of formConfig().sections | sort: \"order\";\n track section.key || $index\n ) {\n <div\n [class]=\"\n section.cssClass ||\n formConfig().layout?.sectionClass ||\n 'flex flex-col gap-4'\n \"\n >\n @if (section.type === \"header\" && section.label) {\n <h3\n [class]=\"\n section?.headerClass ||\n 'text-xl font-semibold text-gray-800 border-b-2 border-gray-200 pb-2 mb-4'\n \"\n >\n {{ section.label }}\n </h3>\n }\n\n <div\n [class]=\"\n section?.bodyClass ||\n 'grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 items-start'\n \"\n >\n @for (field of section.fields | sort: \"order\"; track field.key) {\n <div\n [class]=\"\n field.cssClass ||\n formConfig().layout?.fieldClass ||\n 'flex flex-col gap-1'\n \"\n [hidden]=\"field.hidden\"\n >\n <mt-dynamic-field\n [fieldConfig]=\"field\"\n [fieldName]=\"field.key!\"\n />\n </div>\n }\n </div>\n </div>\n }\n </div>\n</form>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: DynamicField, selector: "mt-dynamic-field", inputs: ["fieldConfig", "fieldName"] }, { kind: "pipe", type: SortPipe, name: "sort" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
152
+ }
153
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: DynamicForm, decorators: [{
154
+ type: Component,
155
+ args: [{ selector: 'mt-dynamic-form', standalone: true, imports: [CommonModule, ReactiveFormsModule, DynamicField, SortPipe], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
156
+ {
157
+ provide: NG_VALUE_ACCESSOR,
158
+ useExisting: forwardRef(() => DynamicForm),
159
+ multi: true,
160
+ },
161
+ {
162
+ provide: NG_VALIDATORS,
163
+ useExisting: forwardRef(() => DynamicForm),
164
+ multi: true,
165
+ },
166
+ ], template: "<form [formGroup]=\"form\">\n <div\n class=\"flex flex-col gap-6 max-w-4xl mx-auto p-4\"\n [class]=\"formConfig().layout?.containerClass\"\n >\n @for (\n section of formConfig().sections | sort: \"order\";\n track section.key || $index\n ) {\n <div\n [class]=\"\n section.cssClass ||\n formConfig().layout?.sectionClass ||\n 'flex flex-col gap-4'\n \"\n >\n @if (section.type === \"header\" && section.label) {\n <h3\n [class]=\"\n section?.headerClass ||\n 'text-xl font-semibold text-gray-800 border-b-2 border-gray-200 pb-2 mb-4'\n \"\n >\n {{ section.label }}\n </h3>\n }\n\n <div\n [class]=\"\n section?.bodyClass ||\n 'grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 items-start'\n \"\n >\n @for (field of section.fields | sort: \"order\"; track field.key) {\n <div\n [class]=\"\n field.cssClass ||\n formConfig().layout?.fieldClass ||\n 'flex flex-col gap-1'\n \"\n [hidden]=\"field.hidden\"\n >\n <mt-dynamic-field\n [fieldConfig]=\"field\"\n [fieldName]=\"field.key!\"\n />\n </div>\n }\n </div>\n </div>\n }\n </div>\n</form>\n" }]
167
+ }], ctorParameters: () => [] });
168
+
169
+ /**
170
+ * Generated bundle index. Do not edit.
171
+ */
172
+
173
+ export { DynamicForm };
174
+ //# sourceMappingURL=masterteam-forms-dynamic-form.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"masterteam-forms-dynamic-form.mjs","sources":["../../../../packages/masterteam/forms/dynamic-form/dynamic-form.ts","../../../../packages/masterteam/forms/dynamic-form/dynamic-form.html","../../../../packages/masterteam/forms/dynamic-form/masterteam-forms-dynamic-form.ts"],"sourcesContent":["import {\n Component,\n input,\n effect,\n ChangeDetectionStrategy,\n OnDestroy,\n forwardRef,\n inject,\n} from '@angular/core';\nimport {\n FormBuilder,\n FormGroup,\n ReactiveFormsModule,\n Validators,\n AbstractControl,\n ValidatorFn,\n ControlValueAccessor,\n NG_VALUE_ACCESSOR,\n Validator,\n ValidationErrors,\n NG_VALIDATORS,\n} from '@angular/forms';\nimport { CommonModule } from '@angular/common';\nimport { DynamicField } from '@masterteam/forms/dynamic-field';\nimport { SortPipe } from '@masterteam/forms/pipes';\n// import { SortPipe } from '../pipes/sort.pipe';\nimport {\n DynamicFormConfig,\n ValidatorConfig,\n createCustomValidator,\n wrapValidatorWithMessage,\n} from '@masterteam/components';\nimport { Subscription } from 'rxjs';\n\n@Component({\n selector: 'mt-dynamic-form',\n standalone: true,\n imports: [CommonModule, ReactiveFormsModule, DynamicField, SortPipe],\n templateUrl: './dynamic-form.html',\n styleUrls: ['./dynamic-form.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => DynamicForm),\n multi: true,\n },\n {\n provide: NG_VALIDATORS,\n useExisting: forwardRef(() => DynamicForm),\n multi: true,\n },\n ],\n})\nexport class DynamicForm implements OnDestroy, ControlValueAccessor, Validator {\n private fb = inject(FormBuilder);\n\n readonly formConfig = input.required<DynamicFormConfig>();\n\n form = new FormGroup({});\n\n // ControlValueAccessor implementation\n private onChange = (_value: any) => {};\n private onTouched = () => {};\n private onValidatorChange = () => {};\n // private disabled = false;\n private formSubscription?: Subscription;\n private statusSubscription?: Subscription;\n\n constructor() {\n // Effect to rebuild form when config changes\n effect(() => {\n this.buildForm();\n });\n }\n\n registerOnValidatorChange(fn: () => void): void {\n this.onValidatorChange = fn;\n }\n registerOnChange(fn: (value: any) => void): void {\n this.onChange = fn;\n }\n\n registerOnTouched(fn: () => void): void {\n this.onTouched = fn;\n }\n\n private buildForm() {\n // Clean up previous subscriptions\n if (this.formSubscription) {\n this.formSubscription.unsubscribe();\n }\n if (this.statusSubscription) {\n this.statusSubscription.unsubscribe();\n }\n\n const formControls: { [key: string]: AbstractControl } = {};\n\n this.formConfig().sections.forEach((section) => {\n section.fields.forEach((field) => {\n if (field.key) {\n const validators = this.buildValidators(field.validators || []);\n const control = this.fb.control(\n {\n value: field.defaultValue || '',\n disabled: field.disabled || false,\n },\n validators,\n );\n formControls[field.key] = control;\n }\n });\n });\n\n this.form = this.fb.group(formControls);\n\n // Subscribe to form value changes\n this.formSubscription = this.form.valueChanges.subscribe((value) => {\n this.onChange(value);\n });\n\n // Trigger initial validation state\n this.onValidatorChange();\n }\n\n // ControlValueAccessor implementation\n writeValue(value: any): void {\n if (value && this.form) {\n this.form.patchValue(value, { emitEvent: false });\n }\n }\n\n validate(_control: AbstractControl): ValidationErrors | null {\n if (!this.form) {\n return null;\n }\n // Return the form's errors if invalid, null if valid\n return this.form.valid ? null : { invalidForm: true };\n }\n\n private buildValidators(validatorConfigs: ValidatorConfig[]): ValidatorFn[] {\n const validators: ValidatorFn[] = [];\n\n validatorConfigs.forEach((config) => {\n let validator: ValidatorFn | null = null;\n\n switch (config.type) {\n case 'required':\n validator = Validators.required;\n break;\n case 'email':\n validator = Validators.email;\n break;\n case 'minLength':\n if (config.value) {\n validator = Validators.minLength(config.value);\n }\n break;\n case 'maxLength':\n if (config.value) {\n validator = Validators.maxLength(config.value);\n }\n break;\n case 'min':\n if (config.value !== undefined) {\n validator = Validators.min(config.value);\n }\n break;\n case 'max':\n if (config.value !== undefined) {\n validator = Validators.max(config.value);\n }\n break;\n case 'pattern':\n if (config.value) {\n validator = Validators.pattern(config.value);\n }\n break;\n case 'custom':\n if (config.customValidator) {\n validators.push(\n createCustomValidator(config.customValidator, config.message),\n );\n }\n break;\n }\n\n // If we have a validator and a custom message, wrap it\n if (validator && config.message) {\n validators.push(\n wrapValidatorWithMessage(validator, config.type, config.message),\n );\n } else if (validator) {\n validators.push(validator);\n }\n });\n\n return validators;\n }\n\n ngOnDestroy(): void {\n // Clean up subscriptions\n if (this.formSubscription) {\n this.formSubscription.unsubscribe();\n }\n if (this.statusSubscription) {\n this.statusSubscription.unsubscribe();\n }\n }\n}\n","<form [formGroup]=\"form\">\n <div\n class=\"flex flex-col gap-6 max-w-4xl mx-auto p-4\"\n [class]=\"formConfig().layout?.containerClass\"\n >\n @for (\n section of formConfig().sections | sort: \"order\";\n track section.key || $index\n ) {\n <div\n [class]=\"\n section.cssClass ||\n formConfig().layout?.sectionClass ||\n 'flex flex-col gap-4'\n \"\n >\n @if (section.type === \"header\" && section.label) {\n <h3\n [class]=\"\n section?.headerClass ||\n 'text-xl font-semibold text-gray-800 border-b-2 border-gray-200 pb-2 mb-4'\n \"\n >\n {{ section.label }}\n </h3>\n }\n\n <div\n [class]=\"\n section?.bodyClass ||\n 'grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 items-start'\n \"\n >\n @for (field of section.fields | sort: \"order\"; track field.key) {\n <div\n [class]=\"\n field.cssClass ||\n formConfig().layout?.fieldClass ||\n 'flex flex-col gap-1'\n \"\n [hidden]=\"field.hidden\"\n >\n <mt-dynamic-field\n [fieldConfig]=\"field\"\n [fieldName]=\"field.key!\"\n />\n </div>\n }\n </div>\n </div>\n }\n </div>\n</form>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;;;;MAsDa,WAAW,CAAA;AACd,IAAA,EAAE,GAAG,MAAM,CAAC,WAAW,CAAC;AAEvB,IAAA,UAAU,GAAG,KAAK,CAAC,QAAQ,qDAAqB;AAEzD,IAAA,IAAI,GAAG,IAAI,SAAS,CAAC,EAAE,CAAC;;AAGhB,IAAA,QAAQ,GAAG,CAAC,MAAW,KAAI,EAAE,CAAC;AAC9B,IAAA,SAAS,GAAG,MAAK,EAAE,CAAC;AACpB,IAAA,iBAAiB,GAAG,MAAK,EAAE,CAAC;;AAE5B,IAAA,gBAAgB;AAChB,IAAA,kBAAkB;AAE1B,IAAA,WAAA,GAAA;;QAEE,MAAM,CAAC,MAAK;YACV,IAAI,CAAC,SAAS,EAAE;AAClB,QAAA,CAAC,CAAC;IACJ;AAEA,IAAA,yBAAyB,CAAC,EAAc,EAAA;AACtC,QAAA,IAAI,CAAC,iBAAiB,GAAG,EAAE;IAC7B;AACA,IAAA,gBAAgB,CAAC,EAAwB,EAAA;AACvC,QAAA,IAAI,CAAC,QAAQ,GAAG,EAAE;IACpB;AAEA,IAAA,iBAAiB,CAAC,EAAc,EAAA;AAC9B,QAAA,IAAI,CAAC,SAAS,GAAG,EAAE;IACrB;IAEQ,SAAS,GAAA;;AAEf,QAAA,IAAI,IAAI,CAAC,gBAAgB,EAAE;AACzB,YAAA,IAAI,CAAC,gBAAgB,CAAC,WAAW,EAAE;QACrC;AACA,QAAA,IAAI,IAAI,CAAC,kBAAkB,EAAE;AAC3B,YAAA,IAAI,CAAC,kBAAkB,CAAC,WAAW,EAAE;QACvC;QAEA,MAAM,YAAY,GAAuC,EAAE;QAE3D,IAAI,CAAC,UAAU,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,KAAI;YAC7C,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,KAAI;AAC/B,gBAAA,IAAI,KAAK,CAAC,GAAG,EAAE;AACb,oBAAA,MAAM,UAAU,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,UAAU,IAAI,EAAE,CAAC;AAC/D,oBAAA,MAAM,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAC7B;AACE,wBAAA,KAAK,EAAE,KAAK,CAAC,YAAY,IAAI,EAAE;AAC/B,wBAAA,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,KAAK;qBAClC,EACD,UAAU,CACX;AACD,oBAAA,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,OAAO;gBACnC;AACF,YAAA,CAAC,CAAC;AACJ,QAAA,CAAC,CAAC;QAEF,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC;;AAGvC,QAAA,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,KAAK,KAAI;AACjE,YAAA,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;AACtB,QAAA,CAAC,CAAC;;QAGF,IAAI,CAAC,iBAAiB,EAAE;IAC1B;;AAGA,IAAA,UAAU,CAAC,KAAU,EAAA;AACnB,QAAA,IAAI,KAAK,IAAI,IAAI,CAAC,IAAI,EAAE;AACtB,YAAA,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;QACnD;IACF;AAEA,IAAA,QAAQ,CAAC,QAAyB,EAAA;AAChC,QAAA,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;AACd,YAAA,OAAO,IAAI;QACb;;AAEA,QAAA,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE;IACvD;AAEQ,IAAA,eAAe,CAAC,gBAAmC,EAAA;QACzD,MAAM,UAAU,GAAkB,EAAE;AAEpC,QAAA,gBAAgB,CAAC,OAAO,CAAC,CAAC,MAAM,KAAI;YAClC,IAAI,SAAS,GAAuB,IAAI;AAExC,YAAA,QAAQ,MAAM,CAAC,IAAI;AACjB,gBAAA,KAAK,UAAU;AACb,oBAAA,SAAS,GAAG,UAAU,CAAC,QAAQ;oBAC/B;AACF,gBAAA,KAAK,OAAO;AACV,oBAAA,SAAS,GAAG,UAAU,CAAC,KAAK;oBAC5B;AACF,gBAAA,KAAK,WAAW;AACd,oBAAA,IAAI,MAAM,CAAC,KAAK,EAAE;wBAChB,SAAS,GAAG,UAAU,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC;oBAChD;oBACA;AACF,gBAAA,KAAK,WAAW;AACd,oBAAA,IAAI,MAAM,CAAC,KAAK,EAAE;wBAChB,SAAS,GAAG,UAAU,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC;oBAChD;oBACA;AACF,gBAAA,KAAK,KAAK;AACR,oBAAA,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,EAAE;wBAC9B,SAAS,GAAG,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC;oBAC1C;oBACA;AACF,gBAAA,KAAK,KAAK;AACR,oBAAA,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,EAAE;wBAC9B,SAAS,GAAG,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC;oBAC1C;oBACA;AACF,gBAAA,KAAK,SAAS;AACZ,oBAAA,IAAI,MAAM,CAAC,KAAK,EAAE;wBAChB,SAAS,GAAG,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;oBAC9C;oBACA;AACF,gBAAA,KAAK,QAAQ;AACX,oBAAA,IAAI,MAAM,CAAC,eAAe,EAAE;AAC1B,wBAAA,UAAU,CAAC,IAAI,CACb,qBAAqB,CAAC,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC,OAAO,CAAC,CAC9D;oBACH;oBACA;;;AAIJ,YAAA,IAAI,SAAS,IAAI,MAAM,CAAC,OAAO,EAAE;AAC/B,gBAAA,UAAU,CAAC,IAAI,CACb,wBAAwB,CAAC,SAAS,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,CACjE;YACH;iBAAO,IAAI,SAAS,EAAE;AACpB,gBAAA,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC;YAC5B;AACF,QAAA,CAAC,CAAC;AAEF,QAAA,OAAO,UAAU;IACnB;IAEA,WAAW,GAAA;;AAET,QAAA,IAAI,IAAI,CAAC,gBAAgB,EAAE;AACzB,YAAA,IAAI,CAAC,gBAAgB,CAAC,WAAW,EAAE;QACrC;AACA,QAAA,IAAI,IAAI,CAAC,kBAAkB,EAAE;AAC3B,YAAA,IAAI,CAAC,kBAAkB,CAAC,WAAW,EAAE;QACvC;IACF;uGA1JW,WAAW,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAX,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,WAAW,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,EAAA,UAAA,EAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,UAAA,EAAA,YAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,SAAA,EAbX;AACT,YAAA;AACE,gBAAA,OAAO,EAAE,iBAAiB;AAC1B,gBAAA,WAAW,EAAE,UAAU,CAAC,MAAM,WAAW,CAAC;AAC1C,gBAAA,KAAK,EAAE,IAAI;AACZ,aAAA;AACD,YAAA;AACE,gBAAA,OAAO,EAAE,aAAa;AACtB,gBAAA,WAAW,EAAE,UAAU,CAAC,MAAM,WAAW,CAAC;AAC1C,gBAAA,KAAK,EAAE,IAAI;AACZ,aAAA;SACF,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECpDH,w8CAqDA,yDDhBY,YAAY,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAE,mBAAmB,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,aAAA,EAAA,QAAA,EAAA,8CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,oBAAA,EAAA,QAAA,EAAA,0FAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,kBAAA,EAAA,QAAA,EAAA,aAAA,EAAA,MAAA,EAAA,CAAA,WAAA,CAAA,EAAA,OAAA,EAAA,CAAA,UAAA,CAAA,EAAA,QAAA,EAAA,CAAA,QAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,YAAY,8FAAE,QAAQ,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAiBxD,WAAW,EAAA,UAAA,EAAA,CAAA;kBApBvB,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,iBAAiB,cACf,IAAI,EAAA,OAAA,EACP,CAAC,YAAY,EAAE,mBAAmB,EAAE,YAAY,EAAE,QAAQ,CAAC,EAAA,eAAA,EAGnD,uBAAuB,CAAC,MAAM,EAAA,SAAA,EACpC;AACT,wBAAA;AACE,4BAAA,OAAO,EAAE,iBAAiB;AAC1B,4BAAA,WAAW,EAAE,UAAU,CAAC,iBAAiB,CAAC;AAC1C,4BAAA,KAAK,EAAE,IAAI;AACZ,yBAAA;AACD,wBAAA;AACE,4BAAA,OAAO,EAAE,aAAa;AACtB,4BAAA,WAAW,EAAE,UAAU,CAAC,iBAAiB,CAAC;AAC1C,4BAAA,KAAK,EAAE,IAAI;AACZ,yBAAA;AACF,qBAAA,EAAA,QAAA,EAAA,w8CAAA,EAAA;;;AEpDH;;AAEG;;;;"}
@@ -0,0 +1,57 @@
1
+ import * as i0 from '@angular/core';
2
+ import { Pipe } from '@angular/core';
3
+
4
+ class SortPipe {
5
+ transform(array, keySort = 'order', direction = 'asc') {
6
+ if (!array || !Array.isArray(array)) {
7
+ return [];
8
+ }
9
+ return [...array].sort((a, b) => {
10
+ const aValue = this.getNestedValue(a, keySort);
11
+ const bValue = this.getNestedValue(b, keySort);
12
+ // Handle null/undefined values - they should go to the end
13
+ if (aValue == null && bValue == null)
14
+ return 0;
15
+ if (aValue == null)
16
+ return 1;
17
+ if (bValue == null)
18
+ return -1;
19
+ let comparison = 0;
20
+ if (typeof aValue === 'string' && typeof bValue === 'string') {
21
+ comparison = aValue.localeCompare(bValue);
22
+ }
23
+ else if (typeof aValue === 'number' && typeof bValue === 'number') {
24
+ comparison = aValue - bValue;
25
+ }
26
+ else {
27
+ // Convert to string for comparison
28
+ const aStr = String(aValue);
29
+ const bStr = String(bValue);
30
+ comparison = aStr.localeCompare(bStr);
31
+ }
32
+ return direction === 'desc' ? -comparison : comparison;
33
+ });
34
+ }
35
+ getNestedValue(obj, path) {
36
+ return path.split('.').reduce((current, key) => {
37
+ return current && current[key] !== undefined ? current[key] : 0;
38
+ }, obj);
39
+ }
40
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: SortPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
41
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.1.0", ngImport: i0, type: SortPipe, isStandalone: true, name: "sort" });
42
+ }
43
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: SortPipe, decorators: [{
44
+ type: Pipe,
45
+ args: [{
46
+ name: 'sort',
47
+ standalone: true,
48
+ pure: true,
49
+ }]
50
+ }] });
51
+
52
+ /**
53
+ * Generated bundle index. Do not edit.
54
+ */
55
+
56
+ export { SortPipe };
57
+ //# sourceMappingURL=masterteam-forms-pipes.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"masterteam-forms-pipes.mjs","sources":["../../../../packages/masterteam/forms/pipes/sort.pipe.ts","../../../../packages/masterteam/forms/pipes/masterteam-forms-pipes.ts"],"sourcesContent":["import { Pipe, PipeTransform } from '@angular/core';\n\n@Pipe({\n name: 'sort',\n standalone: true,\n pure: true,\n})\nexport class SortPipe implements PipeTransform {\n transform<T>(\n array: T[] | null | undefined,\n keySort: string = 'order',\n direction: 'asc' | 'desc' = 'asc',\n ): T[] {\n if (!array || !Array.isArray(array)) {\n return [];\n }\n\n return [...array].sort((a, b) => {\n const aValue = this.getNestedValue(a, keySort);\n const bValue = this.getNestedValue(b, keySort);\n\n // Handle null/undefined values - they should go to the end\n if (aValue == null && bValue == null) return 0;\n if (aValue == null) return 1;\n if (bValue == null) return -1;\n\n let comparison = 0;\n\n if (typeof aValue === 'string' && typeof bValue === 'string') {\n comparison = aValue.localeCompare(bValue);\n } else if (typeof aValue === 'number' && typeof bValue === 'number') {\n comparison = aValue - bValue;\n } else {\n // Convert to string for comparison\n const aStr = String(aValue);\n const bStr = String(bValue);\n comparison = aStr.localeCompare(bStr);\n }\n\n return direction === 'desc' ? -comparison : comparison;\n });\n }\n\n private getNestedValue(obj: any, path: string): any {\n return path.split('.').reduce((current, key) => {\n return current && current[key] !== undefined ? current[key] : 0;\n }, obj);\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;MAOa,QAAQ,CAAA;AACnB,IAAA,SAAS,CACP,KAA6B,EAC7B,UAAkB,OAAO,EACzB,YAA4B,KAAK,EAAA;QAEjC,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;AACnC,YAAA,OAAO,EAAE;QACX;AAEA,QAAA,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAI;YAC9B,MAAM,MAAM,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC,EAAE,OAAO,CAAC;YAC9C,MAAM,MAAM,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC,EAAE,OAAO,CAAC;;AAG9C,YAAA,IAAI,MAAM,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI;AAAE,gBAAA,OAAO,CAAC;YAC9C,IAAI,MAAM,IAAI,IAAI;AAAE,gBAAA,OAAO,CAAC;YAC5B,IAAI,MAAM,IAAI,IAAI;gBAAE,OAAO,CAAC,CAAC;YAE7B,IAAI,UAAU,GAAG,CAAC;YAElB,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;AAC5D,gBAAA,UAAU,GAAG,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC;YAC3C;iBAAO,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;AACnE,gBAAA,UAAU,GAAG,MAAM,GAAG,MAAM;YAC9B;iBAAO;;AAEL,gBAAA,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC;AAC3B,gBAAA,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC;AAC3B,gBAAA,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC;YACvC;AAEA,YAAA,OAAO,SAAS,KAAK,MAAM,GAAG,CAAC,UAAU,GAAG,UAAU;AACxD,QAAA,CAAC,CAAC;IACJ;IAEQ,cAAc,CAAC,GAAQ,EAAE,IAAY,EAAA;AAC3C,QAAA,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,GAAG,KAAI;AAC7C,YAAA,OAAO,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;QACjE,CAAC,EAAE,GAAG,CAAC;IACT;uGAxCW,QAAQ,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,IAAA,EAAA,CAAA;qGAAR,QAAQ,EAAA,YAAA,EAAA,IAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA;;2FAAR,QAAQ,EAAA,UAAA,EAAA,CAAA;kBALpB,IAAI;AAAC,YAAA,IAAA,EAAA,CAAA;AACJ,oBAAA,IAAI,EAAE,MAAM;AACZ,oBAAA,UAAU,EAAE,IAAI;AAChB,oBAAA,IAAI,EAAE,IAAI;AACX,iBAAA;;;ACND;;AAEG;;;;"}
@@ -0,0 +1,6 @@
1
+ var publicApi = {};
2
+
3
+ /**
4
+ * Generated bundle index. Do not edit.
5
+ */
6
+ //# sourceMappingURL=masterteam-forms.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"masterteam-forms.mjs","sources":["../../../../packages/masterteam/forms/src/public-api.ts","../../../../packages/masterteam/forms/src/masterteam-forms.ts"],"sourcesContent":["export default {};\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"AAAA,gBAAe,EAAE;;ACAjB;;AAEG"}
package/index.d.ts ADDED
@@ -0,0 +1,2 @@
1
+
2
+ export { };
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@masterteam/forms",
3
+ "version": "0.0.1",
4
+ "publishConfig": {
5
+ "directory": ".",
6
+ "linkDirectory": false,
7
+ "access": "public"
8
+ },
9
+ "peerDependencies": {
10
+ "@angular/common": "^20.1.0",
11
+ "@angular/core": "^20.1.0",
12
+ "@angular/forms": "^20.1.0",
13
+ "postcss": "^8.5.6",
14
+ "@tailwindcss/postcss": "^4.1.11",
15
+ "tailwindcss": "^4.1.11",
16
+ "tailwindcss-primeui": "^0.6.1",
17
+ "primeng": "20.0.0-rc.3",
18
+ "@primeuix/themes": "^1.2.1",
19
+ "rxjs": "^7.8.2"
20
+ },
21
+ "dependencies": {
22
+ "@masterteam/components": "x",
23
+ "tslib": "^2.3.0"
24
+ },
25
+ "sideEffects": false,
26
+ "module": "fesm2022/masterteam-forms.mjs",
27
+ "typings": "index.d.ts",
28
+ "exports": {
29
+ "./package.json": {
30
+ "default": "./package.json"
31
+ },
32
+ ".": {
33
+ "types": "./index.d.ts",
34
+ "default": "./fesm2022/masterteam-forms.mjs"
35
+ },
36
+ "./dynamic-field": {
37
+ "types": "./dynamic-field/index.d.ts",
38
+ "default": "./fesm2022/masterteam-forms-dynamic-field.mjs"
39
+ },
40
+ "./dynamic-form": {
41
+ "types": "./dynamic-form/index.d.ts",
42
+ "default": "./fesm2022/masterteam-forms-dynamic-form.mjs"
43
+ },
44
+ "./pipes": {
45
+ "types": "./pipes/index.d.ts",
46
+ "default": "./fesm2022/masterteam-forms-pipes.mjs"
47
+ }
48
+ }
49
+ }
@@ -0,0 +1,11 @@
1
+ import * as i0 from '@angular/core';
2
+ import { PipeTransform } from '@angular/core';
3
+
4
+ declare class SortPipe implements PipeTransform {
5
+ transform<T>(array: T[] | null | undefined, keySort?: string, direction?: 'asc' | 'desc'): T[];
6
+ private getNestedValue;
7
+ static ɵfac: i0.ɵɵFactoryDeclaration<SortPipe, never>;
8
+ static ɵpipe: i0.ɵɵPipeDeclaration<SortPipe, "sort", true>;
9
+ }
10
+
11
+ export { SortPipe };