@decaf-ts/for-angular 0.0.35 → 0.0.37

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.
@@ -1,7 +1,7 @@
1
1
  import { UIKeys, HTML5InputTypes, parseValueByType, HTML5CheckTypes, escapeHtml, parseToNumber, RenderingEngine, RenderingError, UIMediaBreakPoints } from '@decaf-ts/ui-decorators';
2
2
  import * as i0 from '@angular/core';
3
3
  import { InjectionToken, NgModule, isDevMode, reflectComponentType, inject, ChangeDetectorRef, Renderer2, EventEmitter, ElementRef, Input, Output, ViewChild, Inject, Directive, EnvironmentInjector, ViewContainerRef, TemplateRef, ViewEncapsulation, Component, HostListener, CUSTOM_ELEMENTS_SCHEMA, Injector } from '@angular/core';
4
- import { CommonModule, NgComponentOutlet, Location } from '@angular/common';
4
+ import { CommonModule, Location, NgComponentOutlet } from '@angular/common';
5
5
  import { VALIDATION_PARENT_KEY, ValidationKeys, DEFAULT_PATTERNS, Validation, Primitives, ComparisonValidationKeys, PathProxyEngine, Model, ModelKeys, isValidDate as isValidDate$1, parseDate, sf, ReservedModels } from '@decaf-ts/decorator-validation';
6
6
  import { InternalError, OperationKeys } from '@decaf-ts/db-decorators';
7
7
  import * as i1 from '@angular/forms';
@@ -11,9 +11,9 @@ import { TranslateModule, TranslatePipe, TranslateParser, provideTranslateServic
11
11
  import { Logging, LoggedClass } from '@decaf-ts/logging';
12
12
  import { uses, Repository, OrderDirection, Condition } from '@decaf-ts/core';
13
13
  import { apply, metadata } from '@decaf-ts/reflection';
14
- import { Router } from '@angular/router';
15
- import { provideHttpClient, HttpClient } from '@angular/common/http';
14
+ import { Router, NavigationEnd, NavigationStart } from '@angular/router';
16
15
  import { forkJoin, firstValueFrom, fromEvent, debounceTime, Subject, timer } from 'rxjs';
16
+ import { provideHttpClient, HttpClient } from '@angular/common/http';
17
17
  import { map } from 'rxjs/operators';
18
18
  import { MenuController, NavController } from '@ionic/angular';
19
19
  import { Title, DomSanitizer } from '@angular/platform-browser';
@@ -22,12 +22,13 @@ import { IonInput, IonItem, IonCheckbox, IonRadioGroup, IonRadio, IonSelect, Ion
22
22
  import { addIcons } from 'ionicons';
23
23
  import * as allIcons from 'ionicons/icons';
24
24
  import { chevronUpOutline, chevronDownOutline, createOutline, alertCircleOutline, chevronForwardOutline, chevronBackOutline, arrowBackOutline, arrowForwardOutline } from 'ionicons/icons';
25
- import { NgxParentComponentDirective as NgxParentComponentDirective$1 } from 'src/lib/engine/NgxParentComponentDirective';
26
25
 
27
26
  /**
28
- * @description Angular engine key constants
27
+ * @description Angular engine key constants.
29
28
  * @summary Contains key strings used by the Angular rendering engine for reflection,
30
- * dynamic component creation, and other engine operations.
29
+ * dynamic component creation, and other engine operations. These constants provide
30
+ * consistent naming for metadata keys, DOM attributes, and component identification
31
+ * throughout the rendering system.
31
32
  * @typedef {Object} AngularEngineKeys
32
33
  * @property {string} REFLECT - Prefix for reflection metadata keys
33
34
  * @property {string} DYNAMIC - Key for dynamic component identification
@@ -41,8 +42,10 @@ import { NgxParentComponentDirective as NgxParentComponentDirective$1 } from 'sr
41
42
  * @property {string} RENDER - Key for renderable components
42
43
  * @property {string} RENDERED_ID - Template for rendered component IDs
43
44
  * @property {string} PARENT - Key for comparison decorators and validators
45
+ * @property {string} VALIDATION_PARENT_KEY - Key for validation parent reference
46
+ * @property {string} FLAVOUR - Identifier for the Angular engine flavor
44
47
  * @const AngularEngineKeys
45
- * @memberOf module:engine
48
+ * @memberOf module:lib/engine/constants
46
49
  */
47
50
  const AngularEngineKeys = {
48
51
  REFLECT: `${UIKeys.REFLECT}.angular.`,
@@ -58,32 +61,40 @@ const AngularEngineKeys = {
58
61
  RENDERED_ID: 'rendered-as-{0}',
59
62
  PARENT: '_parent',
60
63
  VALIDATION_PARENT_KEY: VALIDATION_PARENT_KEY,
64
+ FLAVOUR: "angular",
61
65
  };
62
66
  /**
63
- * @description Form validation state constants
67
+ * @description Form validation state constants.
64
68
  * @summary Contains constants representing the possible validation states of a form.
65
69
  * These are used to check and handle form validation throughout the application.
70
+ * The VALID state indicates all form controls pass validation, while INVALID
71
+ * indicates one or more validation errors exist.
66
72
  * @typedef {Object} FormConstants
67
73
  * @property {string} VALID - Constant representing a valid form state
68
74
  * @property {string} INVALID - Constant representing an invalid form state
69
75
  * @const FormConstants
70
- * @memberOf module:engine
76
+ * @memberOf module:lib/engine/constants
71
77
  */
72
78
  const FormConstants = {
73
79
  VALID: 'VALID',
74
80
  INVALID: 'INVALID',
75
81
  };
76
82
  /**
77
- * @description Event name constants
78
- * @summary Enum containing constants for event names used throughout the application.
79
- * These are used to standardize event naming and handling.
80
- * @enum {string}
81
- * @readonly
83
+ * @description Event name constants.
84
+ * @summary Contains constants for standardized event names used throughout the application.
85
+ * These constants ensure consistent event naming across components and make it easier to
86
+ * track and handle events. Each constant represents a specific application event type.
87
+ * @typedef {Object} EventConstants
82
88
  * @property {string} BACK_BUTTON_NAVIGATION - Event fired when back button navigation ends
83
- * @property {string} REFRESH_EVENT - Event fired when a refresh action occurs
84
- * @property {string} CLICK_EVENT - Event fired when a click action occurs
85
- * @property {string} SUBMIT_EVENT - Event fired when a form submission occurs
86
- * @memberOf module:engine
89
+ * @property {string} REFRESH - Event fired when a refresh action occurs
90
+ * @property {string} CLICK - Event fired when a click action occurs
91
+ * @property {string} SUBMIT - Event fired when a form submission occurs
92
+ * @property {string} VALIDATION_ERROR - Event fired when a validation error occurs
93
+ * @property {string} FIELDSET_ADD_GROUP - Event fired when adding a group to a fieldset
94
+ * @property {string} FIELDSET_UPDATE_GROUP - Event fired when updating a fieldset group
95
+ * @property {string} FIELDSET_REMOVE_GROUP - Event fired when removing a fieldset group
96
+ * @const EventConstants
97
+ * @memberOf module:lib/engine/constants
87
98
  */
88
99
  const EventConstants = {
89
100
  BACK_BUTTON_NAVIGATION: 'backButtonNavigationEndEvent',
@@ -97,9 +108,11 @@ const EventConstants = {
97
108
  // FIELDSET_GROUP_VALIDATION: 'fieldsetGroupValidationEvent'
98
109
  };
99
110
  /**
100
- * @description Logger level constants
101
- * @summary Enum defining the logging levels used in the application's logging system.
102
- * Lower values represent more verbose logging, while higher values represent more critical logs.
111
+ * @description Logger level constants.
112
+ * @summary Defines the logging levels used in the application's logging system.
113
+ * Lower numeric values represent more verbose logging, while higher values represent
114
+ * more critical logs. These levels control which log messages are output based on
115
+ * the configured logging threshold.
103
116
  * @enum {number}
104
117
  * @readonly
105
118
  * @property {number} ALL - Log everything (most verbose)
@@ -108,7 +121,7 @@ const EventConstants = {
108
121
  * @property {number} WARN - Log warnings
109
122
  * @property {number} ERROR - Log errors
110
123
  * @property {number} CRITICAL - Log critical errors (least verbose)
111
- * @memberOf module:engine
124
+ * @memberOf module:lib/engine/constants
112
125
  */
113
126
  var LoggerLevels;
114
127
  (function (LoggerLevels) {
@@ -121,15 +134,16 @@ var LoggerLevels;
121
134
  })(LoggerLevels || (LoggerLevels = {}));
122
135
  ;
123
136
  /**
124
- * @description Route direction constants
125
- * @summary Enum defining the possible navigation directions in the application.
126
- * Used for controlling navigation flow and animation directions.
137
+ * @description Route direction constants.
138
+ * @summary Defines the possible navigation directions in the application.
139
+ * Used for controlling navigation flow and animation directions during route transitions.
140
+ * These constants help maintain consistent navigation behavior throughout the app.
127
141
  * @enum {string}
128
142
  * @readonly
129
143
  * @property {string} BACK - Navigate back to the previous page
130
144
  * @property {string} FORWARD - Navigate forward to the next page
131
145
  * @property {string} ROOT - Navigate to the root/home page
132
- * @memberOf module:engine
146
+ * @memberOf module:lib/engine/constants
133
147
  */
134
148
  var RouteDirections;
135
149
  (function (RouteDirections) {
@@ -138,15 +152,18 @@ var RouteDirections;
138
152
  RouteDirections["ROOT"] = "root";
139
153
  })(RouteDirections || (RouteDirections = {}));
140
154
  /**
141
- * @description Component tag name constants
142
- * @summary Enum defining the tag names for custom components used in the application.
143
- * These tag names are used for component registration and rendering.
155
+ * @description Component tag name constants.
156
+ * @summary Defines the custom HTML tag names for specialized components used in the application.
157
+ * These tag names are registered with Angular and used for component rendering and identification.
158
+ * Each constant represents the selector for a specific custom component type.
144
159
  * @enum {string}
145
160
  * @readonly
146
161
  * @property {string} LIST_ITEM - Tag name for list item component
147
162
  * @property {string} LIST_INFINITE - Tag name for infinite scrolling list component
148
163
  * @property {string} LIST_PAGINATED - Tag name for paginated list component
149
- * @memberOf module:engine
164
+ * @property {string} CRUD_FIELD - Tag name for CRUD form field component
165
+ * @property {string} LAYOUT_COMPONENT - Tag name for layout container component
166
+ * @memberOf module:lib/engine/constants
150
167
  */
151
168
  var ComponentsTagNames;
152
169
  (function (ComponentsTagNames) {
@@ -157,13 +174,16 @@ var ComponentsTagNames;
157
174
  ComponentsTagNames["LAYOUT_COMPONENT"] = "ngx-decaf-layout";
158
175
  })(ComponentsTagNames || (ComponentsTagNames = {}));
159
176
  /**
160
- * @description Base component property name constants
161
- * @summary Enum defining the standard property names used by base components in the application.
162
- * These property names are used for consistent property access across components.
177
+ * @description Base component property name constants.
178
+ * @summary Defines the standard property names used by base components throughout the application.
179
+ * These constants ensure consistent property naming across components and facilitate
180
+ * property access, validation, and data binding. Used primarily for component input
181
+ * properties and change detection.
163
182
  * @enum {string}
164
183
  * @readonly
165
184
  * @property {string} MODEL - Property name for the component's data model
166
185
  * @property {string} LOCALE - Property name for localization settings
186
+ * @property {string} LOCALE_ROOT - Property name for the locale root identifier
167
187
  * @property {string} PK - Property name for primary key
168
188
  * @property {string} ITEMS - Property name for collection items
169
189
  * @property {string} ROUTE - Property name for routing information
@@ -172,7 +192,10 @@ var ComponentsTagNames;
172
192
  * @property {string} TRANSLATABLE - Property name for translation flag
173
193
  * @property {string} MAPPER - Property name for property mapper
174
194
  * @property {string} INITIALIZED - Property name for initialization state
175
- * @memberOf module:engine
195
+ * @property {string} COMPONENT_NAME - Property name for component identifier
196
+ * @property {string} PARENT_COMPONENT - Property name for parent component reference
197
+ * @property {string} FORM_GROUP_COMPONENT_PROPS - Property name for form group component properties
198
+ * @memberOf module:lib/engine/constants
176
199
  */
177
200
  var BaseComponentProps;
178
201
  (function (BaseComponentProps) {
@@ -191,14 +214,48 @@ var BaseComponentProps;
191
214
  BaseComponentProps["PARENT_COMPONENT"] = "parentComponent";
192
215
  BaseComponentProps["FORM_GROUP_COMPONENT_PROPS"] = "componentProps";
193
216
  })(BaseComponentProps || (BaseComponentProps = {}));
217
+ /**
218
+ * @description List component type constants.
219
+ * @summary Defines the available types for list components, determining their
220
+ * pagination and scrolling behavior. Used to configure list rendering strategies.
221
+ * @enum {string}
222
+ * @readonly
223
+ * @property {string} INFINITE - Infinite scroll list type
224
+ * @property {string} PAGINATED - Paginated list type with page navigation
225
+ * @memberOf module:lib/engine/constants
226
+ */
194
227
  var ListComponentsTypes;
195
228
  (function (ListComponentsTypes) {
196
229
  ListComponentsTypes["INFINITE"] = "infinite";
197
230
  ListComponentsTypes["PAGINATED"] = "paginated";
198
231
  })(ListComponentsTypes || (ListComponentsTypes = {}));
232
+ /**
233
+ * @description CSS class name constants.
234
+ * @summary Contains predefined CSS class names used for consistent styling
235
+ * across components. These constants help maintain a unified visual language
236
+ * and make it easier to apply standard styles.
237
+ * @typedef {Object} CssClasses
238
+ * @property {string} BUTTONS_CONTAINER - CSS class for button container elements
239
+ * @const CssClasses
240
+ * @memberOf module:lib/engine/constants
241
+ */
199
242
  const CssClasses = {
200
243
  BUTTONS_CONTAINER: 'buttons-container',
201
244
  };
245
+ /**
246
+ * @description Default options for reactive CRUD forms.
247
+ * @summary Provides default configuration for form buttons in CRUD operations.
248
+ * Includes default text labels for submit and clear buttons, which can be
249
+ * overridden by individual form implementations.
250
+ * @type {ICrudFormOptions}
251
+ * @property {Object} buttons - Configuration for form action buttons
252
+ * @property {Object} buttons.submit - Submit button configuration
253
+ * @property {string} buttons.submit.text - Default text for submit button
254
+ * @property {Object} buttons.clear - Clear button configuration
255
+ * @property {string} buttons.clear.text - Default text for clear button
256
+ * @const DefaultFormReactiveOptions
257
+ * @memberOf module:lib/engine/constants
258
+ */
202
259
  const DefaultFormReactiveOptions = {
203
260
  buttons: {
204
261
  submit: {
@@ -209,6 +266,30 @@ const DefaultFormReactiveOptions = {
209
266
  },
210
267
  },
211
268
  };
269
+ /**
270
+ * @description Default options for empty list state display.
271
+ * @summary Provides default configuration for displaying empty state in list components
272
+ * when no data is available. Includes default text for title and subtitle, icon name,
273
+ * button text and visibility settings. These defaults can be overridden by individual
274
+ * list component implementations to customize the empty state presentation.
275
+ * @type {IListEmptyOptions}
276
+ * @property {string} title - Default translation key for empty list title
277
+ * @property {string} subtitle - Default translation key for empty list subtitle
278
+ * @property {boolean} showButton - Whether to show action button in empty state
279
+ * @property {string} icon - Default Ionic icon name for empty state
280
+ * @property {string} buttonText - Default translation key for button text
281
+ * @property {string} link - Default navigation link (empty string)
282
+ * @const DefaultListEmptyOptions
283
+ * @memberOf module:lib/engine/constants
284
+ */
285
+ const DefaultListEmptyOptions = {
286
+ title: 'empty.title',
287
+ subtitle: 'empty.subtitle',
288
+ showButton: false,
289
+ icon: 'folder-open-outline',
290
+ buttonText: 'locale.empty.button',
291
+ link: ''
292
+ };
212
293
 
213
294
  /**
214
295
  * @module module:lib/engine/ValidatorFactory
@@ -707,11 +788,17 @@ function generateRandomValue(length = 8, onlyNumbers = false) {
707
788
  return result;
708
789
  }
709
790
  /**
710
- * Converts a string representation of a boolean or a boolean value to a boolean type.
791
+ * @description Converts a string representation of a boolean or a boolean value to a boolean type.
792
+ * @summary This utility function handles conversion of string-based boolean values ('true', 'false')
793
+ * to actual boolean types. It performs case-insensitive string comparison and returns the
794
+ * corresponding boolean value. This is particularly useful when parsing configuration values,
795
+ * URL parameters, or form inputs that may come as strings but need to be used as booleans.
711
796
  *
712
- * @export
713
- * @param {('true' | 'false' | boolean)} prop - The value to convert. Can be the string 'true', 'false', or a boolean.
714
- * @returns {boolean} The boolean representation of the input value. Returns true if the input is the string 'true' or boolean true, false otherwise.
797
+ * @param {'true' | 'false' | boolean} prop - The value to convert. Can be the string 'true', 'false', or a boolean
798
+ * @returns {boolean} The boolean representation of the input value. Returns true if the input is the string 'true' or boolean true, false otherwise
799
+ *
800
+ * @function stringToBoolean
801
+ * @memberOf module:lib/helpers/utils
715
802
  */
716
803
  function stringToBoolean(prop) {
717
804
  if (typeof prop === 'string')
@@ -719,10 +806,18 @@ function stringToBoolean(prop) {
719
806
  return prop;
720
807
  }
721
808
  /**
722
- * Checks if a value is a valid Date object
809
+ * @description Checks if a value is a valid Date object.
810
+ * @summary This validation function determines whether a given value represents a valid date.
811
+ * It handles multiple input types including Date objects, timestamp numbers, and date strings.
812
+ * For string inputs, it supports ISO 8601 format (YYYY-MM-DD) with or without time components.
813
+ * The function performs comprehensive validation including regex pattern matching and Date
814
+ * object creation to ensure the date is not only parseable but also represents a real date.
815
+ *
816
+ * @param {string | Date | number} date - The value to check. Can be a Date object, a timestamp number, or a date string
817
+ * @returns {boolean} Returns true if the value is a valid Date object (not NaN), otherwise false
723
818
  *
724
- * @param {(string | Date | number)} date - The value to check. Can be a Date object, a timestamp number, or a date string
725
- * @return {boolean} Returns true if the value is a valid Date object (not NaN), otherwise false
819
+ * @function isValidDate
820
+ * @memberOf module:lib/helpers/utils
726
821
  */
727
822
  function isValidDate(date) {
728
823
  try {
@@ -742,12 +837,21 @@ function isValidDate(date) {
742
837
  }
743
838
  }
744
839
  /**
745
- * Formats a date into a localized string representation
840
+ * @description Formats a date into a localized string representation.
841
+ * @summary This function converts a date value into a formatted string according to a specified
842
+ * or system locale. It accepts multiple input formats (Date objects, timestamps, or date strings)
843
+ * and returns a consistently formatted date string in DD/MM/YYYY format. If the input date is
844
+ * invalid, the function returns the original input as a string. The function automatically
845
+ * uses the system locale if none is provided and handles string format conversions by replacing
846
+ * forward slashes with hyphens for proper Date parsing.
746
847
  *
747
- * @param {(string | Date | number)} date - The date to format. Can be a Date object, a timestamp number, or a date string
848
+ * @param {string | Date | number} date - The date to format. Can be a Date object, a timestamp number, or a date string
748
849
  * @param {string} [locale] - The locale to use for formatting. If not provided, the system's locale will be used
749
- * @return {(Date | string)} A formatted date string in the format DD/MM/YYYY according to the specified locale,
750
- * or the original input as a string if the date is invalid
850
+ * @returns {Date | string} A formatted date string in the format DD/MM/YYYY according to the specified locale,
851
+ * or the original input as a string if the date is invalid
852
+ *
853
+ * @function formatDate
854
+ * @memberOf module:lib/helpers/utils
751
855
  */
752
856
  function formatDate(date, locale) {
753
857
  if (!locale)
@@ -764,12 +868,21 @@ function formatDate(date, locale) {
764
868
  return r;
765
869
  }
766
870
  /**
767
- * Attempts to parse a date string, Date object, or number into a valid Date object
871
+ * @description Attempts to parse a date string, Date object, or number into a valid Date object.
872
+ * @summary This function provides robust date parsing functionality that handles the specific
873
+ * format "DD/MM/YYYY HH:MM:SS:MS". It first validates the input date, and if already valid,
874
+ * returns it as-is. For string inputs, it parses the date and time components separately,
875
+ * extracts numeric values, and constructs a new Date object. The function includes validation
876
+ * to ensure the resulting Date object is valid and logs a warning if parsing fails.
877
+ * Returns null for invalid or unsupported date formats.
878
+ *
879
+ * @param {string | Date | number} date - The date to parse. Can be a Date object, a timestamp number,
880
+ * or a date string in the format "DD/MM/YYYY HH:MM:SS:MS"
881
+ * @returns {Date | null} A valid Date object if parsing is successful, or null if the date is invalid
882
+ * or doesn't match the expected format
768
883
  *
769
- * @param {(string | Date | number)} date - The date to parse. Can be a Date object, a timestamp number,
770
- * or a date string in the format "DD/MM/YYYY HH:MM:SS:MS"
771
- * @return {(Date | null)} A valid Date object if parsing is successful, or null if the date is invalid
772
- * or doesn't match the expected format
884
+ * @function parseToValidDate
885
+ * @memberOf module:lib/helpers/utils
773
886
  */
774
887
  function parseToValidDate(date) {
775
888
  if (isValidDate(date))
@@ -787,13 +900,22 @@ function parseToValidDate(date) {
787
900
  return date;
788
901
  }
789
902
  /**
790
- * Maps an item object using a provided mapper object and optional additional properties.
903
+ * @description Maps an item object using a provided mapper object and optional additional properties.
904
+ * @summary This function transforms a source object into a new object based on mapping rules defined
905
+ * in the mapper parameter. It supports dot notation for nested property access (e.g., 'user.name.first')
906
+ * and handles various data types including strings and complex objects. For date values, it automatically
907
+ * formats them using the formatDate function. The function also allows merging additional properties
908
+ * into the result. When a mapped value is null or undefined, it uses the original mapper value as
909
+ * a fallback.
791
910
  *
792
- * @param {KeyValue} item - The source object to be mapped.
911
+ * @param {KeyValue} item - The source object to be mapped
793
912
  * @param {KeyValue} mapper - An object that defines the mapping rules. Keys represent the new property names,
794
- * and values represent the path to the corresponding values in the source object.
795
- * @param {KeyValue} [props] - Optional additional properties to be included in the mapped object.
796
- * @returns {KeyValue} A new object with properties mapped according to the mapper object and including any additional properties.
913
+ * and values represent the path to the corresponding values in the source object
914
+ * @param {KeyValue} [props] - Optional additional properties to be included in the mapped object
915
+ * @returns {KeyValue} A new object with properties mapped according to the mapper object and including any additional properties
916
+ *
917
+ * @function itemMapper
918
+ * @memberOf module:lib/helpers/utils
797
919
  */
798
920
  function itemMapper(item, mapper, props) {
799
921
  return Object.entries(mapper).reduce((accum, [key, value]) => {
@@ -820,15 +942,23 @@ function itemMapper(item, mapper, props) {
820
942
  }, {});
821
943
  }
822
944
  /**
823
- * Maps an array of data objects using a provided mapper object.
945
+ * @description Maps an array of data objects using a provided mapper object.
946
+ * @summary This function transforms an array of objects by applying mapping rules to each item
947
+ * using the itemMapper function. It processes each element in the data array and creates
948
+ * new mapped objects based on the mapper configuration. The function includes validation
949
+ * to ensure meaningful data: if a mapped item contains only null/undefined values, it
950
+ * preserves the original item instead. This prevents data loss during transformation.
951
+ * Returns an empty array if the input data is null, undefined, or empty.
824
952
  *
825
- * @template T - The type of the resulting mapped items.
826
- * @param {any[]} data - The array of data objects to be mapped.
827
- * @param {KeyValue} mapper - An object that defines the mapping rules.
828
- * @param {KeyValue} [props] - Additional properties to be included in the mapped items.
953
+ * @template T - The type of the resulting mapped items
954
+ * @param {T[]} data - The array of data objects to be mapped
955
+ * @param {KeyValue} mapper - An object that defines the mapping rules
956
+ * @param {KeyValue} [props] - Additional properties to be included in the mapped items
957
+ * @returns {T[]} The array of mapped items. If an item in the original array does not have any non-null values after mapping,
958
+ * the original item is returned instead
829
959
  *
830
- * @returns {T[]} - The array of mapped items. If an item in the original array does not have any non-null values after mapping,
831
- * the original item is returned instead.
960
+ * @function dataMapper
961
+ * @memberOf module:lib/helpers/utils
832
962
  */
833
963
  function dataMapper(data, mapper, props) {
834
964
  if (!data || !data.length)
@@ -907,13 +1037,11 @@ async function isDarkMode() {
907
1037
  */
908
1038
 
909
1039
  /**
910
- * @module module:lib/engine/NgxDecafFormService
1040
+ * @module lib/engine/NgxDecafFormService
911
1041
  * @description Utilities to create and manage Angular forms in Decaf components.
912
1042
  * @summary The NgxDecafFormService exposes helpers to build FormGroup/FormArray instances
913
1043
  * from component metadata or UI model definitions, register forms in a registry,
914
1044
  * validate and extract form data, and create controls with appropriate validators.
915
- *
916
- * @link {@link NgxDecafFormService}
917
1045
  */
918
1046
  /**
919
1047
  * @description Service for managing Angular forms and form controls.
@@ -936,7 +1064,6 @@ async function isDarkMode() {
936
1064
  *
937
1065
  * // Getting form data
938
1066
  * const formData = NgxDecafFormService.getFormData(form);
939
- *
940
1067
  * @mermaid
941
1068
  * sequenceDiagram
942
1069
  * participant C as Component
@@ -958,46 +1085,42 @@ class NgxDecafFormService {
958
1085
  * @description WeakMap that stores control properties for form controls.
959
1086
  * @summary A WeakMap that associates AbstractControl instances with their corresponding FieldProperties.
960
1087
  * This allows the service to track metadata for form controls without creating memory leaks.
961
- *
962
1088
  * @type {WeakMap<AbstractControl, FieldProperties>}
963
1089
  * @private
964
1090
  * @static
965
- * @memberOf NgxDecafFormService
966
1091
  */
967
1092
  static { this.controls = new WeakMap(); }
968
1093
  /**
969
1094
  * @description Registry of form groups indexed by their unique identifiers.
970
1095
  * @summary A Map that stores FormGroup instances with their unique string identifiers.
971
1096
  * This allows global access to registered forms throughout the application.
972
- *
973
1097
  * @type {Map<string, FormGroup>}
974
1098
  * @private
975
1099
  * @static
976
- * @memberOf NgxDecafFormService
977
1100
  */
978
1101
  static { this.formRegistry = new Map(); }
979
1102
  /**
980
1103
  * @description Creates a new form group or form array with the specified identifier.
981
- * @summary Generates a FormGroup or FormArray based on the provided properties. If pages are specified
982
- * and greater than 1, creates a FormArray; otherwise creates a FormGroup. The form can optionally
983
- * be registered in the global form registry for later access throughout the application.
984
- *
1104
+ * @summary Generates a FormGroup or FormArray based on the provided parameters. If formArray is true,
1105
+ * creates a FormArray; otherwise creates a FormGroup. The form can optionally be registered in the
1106
+ * global form registry for later access throughout the application. If a form with the given id
1107
+ * already exists in the registry, it returns the existing form.
985
1108
  * @param {string} id - Unique identifier for the form
986
- * @param {Partial<IComponentInput>} [props={}] - Configuration properties for the form
1109
+ * @param {boolean} [formArray=false] - Whether to create a FormArray instead of a FormGroup
987
1110
  * @param {boolean} [registry=true] - Whether to register the form in the global registry
988
- * @return {FormGroup | FormArray} The created form instance
989
- *
1111
+ * @return {FormGroup | FormArray} The created or existing form instance
990
1112
  * @mermaid
991
1113
  * sequenceDiagram
992
1114
  * participant C as Component
993
1115
  * participant NFS as NgxDecafFormService
994
1116
  * participant FR as Form Registry
995
1117
  * participant AF as Angular Forms
996
- *
997
- * C->>NFS: createForm(id, props, registry)
1118
+ * C->>NFS: createForm(id, formArray, registry)
998
1119
  * NFS->>FR: Check if form exists
999
- * alt Form doesn't exist
1000
- * alt props.pages > 1
1120
+ * alt Form exists
1121
+ * FR-->>NFS: Return existing form
1122
+ * else Form doesn't exist
1123
+ * alt formArray is true
1001
1124
  * NFS->>AF: new FormArray([])
1002
1125
  * else
1003
1126
  * NFS->>AF: new FormGroup({})
@@ -1007,9 +1130,7 @@ class NgxDecafFormService {
1007
1130
  * end
1008
1131
  * end
1009
1132
  * NFS-->>C: Return FormGroup | FormArray
1010
- *
1011
1133
  * @static
1012
- * @memberOf NgxDecafFormService
1013
1134
  */
1014
1135
  static createForm(id, formArray = false, registry = true) {
1015
1136
  const form = this.formRegistry.get(id) ?? (formArray ? new FormArray([]) : new FormGroup({}));
@@ -1022,20 +1143,26 @@ class NgxDecafFormService {
1022
1143
  * @summary Registers a FormGroup or FormArray with a unique identifier for global access throughout
1023
1144
  * the application. This allows forms to be retrieved and managed centrally. Throws an error if
1024
1145
  * the identifier is already in use to prevent conflicts.
1025
- *
1026
1146
  * @param {string} formId - The unique identifier for the form
1027
1147
  * @param {FormParent} formGroup - The FormGroup or FormArray to be registered
1028
1148
  * @return {void}
1029
1149
  * @throws {Error} If a FormGroup with the given id is already registered
1030
- *
1031
1150
  * @static
1032
- * @memberOf NgxDecafFormService
1033
1151
  */
1034
1152
  static addRegistry(formId, formGroup) {
1035
1153
  if (this.formRegistry.has(formId))
1036
1154
  throw new Error(`A FormGroup with id '${formId}' is already registered.`);
1037
1155
  this.formRegistry.set(formId, formGroup);
1038
1156
  }
1157
+ /**
1158
+ * @description Retrieves a form from the registry by its identifier.
1159
+ * @summary Gets a FormGroup or FormArray from the registry using its unique identifier.
1160
+ * Returns undefined if the form is not found in the registry. This method provides
1161
+ * safe access to registered forms without throwing errors.
1162
+ * @param {string} [id] - The unique identifier of the form to retrieve
1163
+ * @return {FormParent | undefined} The FormGroup or FormArray if found, undefined otherwise
1164
+ * @static
1165
+ */
1039
1166
  static getOnRegistry(id) {
1040
1167
  return this.formRegistry.get(id);
1041
1168
  }
@@ -1044,12 +1171,9 @@ class NgxDecafFormService {
1044
1171
  * @summary Deletes a FormGroup or FormArray from the registry using its unique identifier.
1045
1172
  * This cleans up the registry and allows the identifier to be reused. The form itself
1046
1173
  * is not destroyed, only removed from the central registry.
1047
- *
1048
1174
  * @param {string} formId - The unique identifier of the form to be removed
1049
1175
  * @return {void}
1050
- *
1051
1176
  * @static
1052
- * @memberOf NgxDecafFormService
1053
1177
  */
1054
1178
  static removeRegistry(formId) {
1055
1179
  this.formRegistry.delete(formId);
@@ -1059,20 +1183,17 @@ class NgxDecafFormService {
1059
1183
  * @summary Traverses the form group structure to find the parent group and control name for a given path.
1060
1184
  * Handles complex nested structures including arrays and sub-groups. Creates missing intermediate
1061
1185
  * groups as needed and properly configures FormArray controls for multiple value scenarios.
1062
- *
1063
1186
  * @param {FormGroup} formGroup - The root FormGroup to traverse
1064
1187
  * @param {string} path - The dot-separated path to the control (e.g., 'user.address.street')
1065
1188
  * @param {IComponentInput} componentProps - Properties defining the component configuration
1066
1189
  * @param {KeyValue} parentProps - Properties from the parent component for context
1067
1190
  * @return {FormParentGroup} A tuple containing the parent FormGroup and the control name
1068
- *
1069
1191
  * @private
1070
1192
  * @mermaid
1071
1193
  * sequenceDiagram
1072
1194
  * participant NFS as NgxDecafFormService
1073
1195
  * participant FG as FormGroup
1074
1196
  * participant FA as FormArray
1075
- *
1076
1197
  * NFS->>NFS: Split path into parts
1077
1198
  * loop For each path part
1078
1199
  * alt Control doesn't exist
@@ -1086,9 +1207,7 @@ class NgxDecafFormService {
1086
1207
  * NFS->>NFS: Navigate to next level
1087
1208
  * end
1088
1209
  * NFS-->>NFS: Return [parentGroup, controlName]
1089
- *
1090
1210
  * @static
1091
- * @memberOf NgxDecafFormService
1092
1211
  */
1093
1212
  static resolveParentGroup(formGroup, path, componentProps, parentProps) {
1094
1213
  const isMultiple = parentProps?.multiple || parentProps?.type === Array.name || false;
@@ -1135,14 +1254,11 @@ class NgxDecafFormService {
1135
1254
  * @description Retrieves component properties from a FormGroup or FormArray.
1136
1255
  * @summary Extracts component properties stored in the form group metadata. If a FormGroup is provided
1137
1256
  * and groupArrayName is specified, it will look for the FormArray within the form structure.
1138
- *
1139
1257
  * @param {FormGroup | FormArray} formGroup - The form group or form array to extract properties from
1140
1258
  * @param {string} [key] - Optional key to retrieve a specific property
1141
1259
  * @param {string} [groupArrayName] - Optional name of the group array if formGroup is not a FormArray
1142
1260
  * @return {Partial<FieldProperties>} The component properties or a specific property if key is provided
1143
- *
1144
1261
  * @static
1145
- * @memberOf NgxDecafFormService
1146
1262
  */
1147
1263
  static getComponentPropsFromGroupArray(formGroup, key, groupArrayName) {
1148
1264
  if (!(formGroup instanceof FormArray) && typeof groupArrayName === Primitives.STRING)
@@ -1154,14 +1270,12 @@ class NgxDecafFormService {
1154
1270
  * @description Adds a new group to a parent FormArray.
1155
1271
  * @summary Creates and adds a new FormGroup to the specified parent FormArray based on the
1156
1272
  * component properties stored in the parent's metadata. This is used for dynamic form arrays
1157
- * where new groups need to be added at runtime.
1158
- *
1159
- * @param {FormParent} parentForm - The root form group containing the parent FormArray
1160
- * @param {number} index - The index position where the new group should be added
1161
- * @return {FormGroup} The newly created and added FormGroup
1162
- *
1273
+ * where new groups need to be added at runtime. Clones the control at the specified index
1274
+ * to maintain the same structure and validators.
1275
+ * @param {FormParent} parentForm - The FormArray or FormGroup containing the parent FormArray
1276
+ * @param {number} [index] - The index position to clone from; defaults to last index if length > 0, otherwise 0
1277
+ * @return {FormArray} The parent FormArray after adding the new group
1163
1278
  * @static
1164
- * @memberOf NgxDecafFormService
1165
1279
  */
1166
1280
  static addGroupToParent(parentForm, index) {
1167
1281
  if (parentForm instanceof FormGroup)
@@ -1174,14 +1288,11 @@ class NgxDecafFormService {
1174
1288
  * @description Retrieves a FormGroup from a parent FormArray at the specified index.
1175
1289
  * @summary Gets a FormGroup from the specified parent FormArray. If the group doesn't exist
1176
1290
  * at the given index, it will create a new one using addGroupToParent.
1177
- *
1178
- * @param {FormGroup} formGroup - The root form group containing the parent FormArray
1291
+ * @param {FormParent} formGroup - The root form group containing the parent FormArray
1179
1292
  * @param {string} parentName - The name of the parent FormArray to retrieve the group from
1180
1293
  * @param {number} [index=1] - The index of the group to retrieve
1181
1294
  * @return {FormGroup} The FormGroup at the specified index
1182
- *
1183
1295
  * @static
1184
- * @memberOf NgxDecafFormService
1185
1296
  */
1186
1297
  static getGroupFromParent(formGroup, parentName, index = 1) {
1187
1298
  const childGroup = (formGroup.get(parentName) || formGroup).at(index);
@@ -1189,6 +1300,17 @@ class NgxDecafFormService {
1189
1300
  return childGroup;
1190
1301
  return this.addGroupToParent(formGroup, index).at(index);
1191
1302
  }
1303
+ /**
1304
+ * @description Clones a form control with its validators.
1305
+ * @summary Creates a deep copy of a FormControl, FormGroup, or FormArray, preserving
1306
+ * validators but resetting values and state. This is useful for creating new instances
1307
+ * of form controls with the same validation rules, particularly in dynamic FormArrays
1308
+ * where new groups need to be added with identical structure.
1309
+ * @param {AbstractControl} control - The control to clone (FormControl, FormGroup, or FormArray)
1310
+ * @return {AbstractControl} A new instance of the control with the same validators
1311
+ * @throws {Error} If the control type is not supported
1312
+ * @static
1313
+ */
1192
1314
  static cloneFormControl(control) {
1193
1315
  const syncValidators = (control.validator ? [control.validator] : []).filter(fn => {
1194
1316
  // if(lastIndex > 0)
@@ -1226,14 +1348,13 @@ class NgxDecafFormService {
1226
1348
  * @description Checks if a value is unique within a FormArray group.
1227
1349
  * @summary Validates that the primary key value in a FormGroup is unique among all groups
1228
1350
  * in the parent FormArray. The uniqueness check behavior differs based on the operation type.
1229
- *
1351
+ * For both CREATE and UPDATE operations, it checks that no other group in the array has the same
1352
+ * primary key value.
1230
1353
  * @param {FormGroup} formGroup - The FormGroup to check for uniqueness
1231
- * @param {number} index - The index of the current group within the FormArray
1232
1354
  * @param {OperationKeys} [operation=OperationKeys.CREATE] - The type of operation being performed
1355
+ * @param {number} [index] - The index of the current group within the FormArray
1233
1356
  * @return {boolean} True if the value is unique, false otherwise
1234
- *
1235
1357
  * @static
1236
- * @memberOf NgxDecafFormService
1237
1358
  */
1238
1359
  static isUniqueOnGroup(formGroup, operation = OperationKeys.CREATE, index) {
1239
1360
  const formArray = formGroup.parent;
@@ -1259,12 +1380,9 @@ class NgxDecafFormService {
1259
1380
  * @description Enables all controls within a FormGroup or FormArray.
1260
1381
  * @summary Recursively enables all form controls within the provided FormGroup or FormArray.
1261
1382
  * This is useful for making all controls interactive after they have been disabled.
1262
- *
1263
1383
  * @param {FormArray | FormGroup} formGroup - The FormGroup or FormArray to enable all controls for
1264
1384
  * @return {void}
1265
- *
1266
1385
  * @static
1267
- * @memberOf NgxDecafFormService
1268
1386
  */
1269
1387
  static enableAllGroupControls(formGroup) {
1270
1388
  Object.keys(formGroup.controls).forEach(key => {
@@ -1283,17 +1401,15 @@ class NgxDecafFormService {
1283
1401
  * @description Adds a form control to a form group based on component properties.
1284
1402
  * @summary Creates and configures a FormControl within the specified FormGroup using the provided
1285
1403
  * component properties. Handles nested paths, multiple controls (FormArrays), and control registration.
1286
- * This method supports complex form structures with nested groups and arrays.
1287
- *
1288
- * @param {FormGroup} formGroup - The form group to add the control to
1404
+ * This method supports complex form structures with nested groups and arrays. It also manages
1405
+ * page-based forms and FormArray indexing.
1406
+ * @param {FormParent} formGroup - The form group or form array to add the control to
1289
1407
  * @param {IComponentInput} componentProps - The component properties defining the control configuration
1290
- * @param {KeyValue} [parentProps={}] - Properties from the parent component for context
1408
+ * @param {Partial<IComponentInput>} [parentProps={}] - Properties from the parent component for context
1291
1409
  * @param {number} [index=0] - The index for multiple controls in FormArrays
1292
- * @return {void}
1293
- *
1410
+ * @return {FormParent} The updated form parent (FormGroup or FormArray)
1294
1411
  * @private
1295
1412
  * @static
1296
- * @memberOf NgxDecafFormService
1297
1413
  */
1298
1414
  static addFormControl(formGroup, componentProps, parentProps = {}, index = 0) {
1299
1415
  const isMultiple = parentProps?.['multiple'] || parentProps?.['type'] === 'Array' || false;
@@ -1329,18 +1445,15 @@ class NgxDecafFormService {
1329
1445
  * @summary Finds and returns an AbstractControl from a registered form using the form id and optional path.
1330
1446
  * This method provides centralized access to form controls across the application by leveraging
1331
1447
  * the form registry system.
1332
- *
1333
1448
  * @param {string} formId - The unique identifier of the form in the registry
1334
1449
  * @param {string} [path] - The optional dot-separated path to a specific control within the form
1335
1450
  * @return {AbstractControl} The requested AbstractControl (FormGroup, FormArray, or FormControl)
1336
1451
  * @throws {Error} If the form is not found in the registry or the control is not found in the form
1337
- *
1338
1452
  * @mermaid
1339
1453
  * sequenceDiagram
1340
1454
  * participant C as Component
1341
1455
  * participant NFS as NgxDecafFormService
1342
1456
  * participant FR as Form Registry
1343
- *
1344
1457
  * C->>NFS: getControlFromForm(formId, path?)
1345
1458
  * NFS->>FR: Get form by formId
1346
1459
  * alt Form not found
@@ -1359,9 +1472,7 @@ class NgxDecafFormService {
1359
1472
  * NFS-->>C: Return form
1360
1473
  * end
1361
1474
  * end
1362
- *
1363
1475
  * @static
1364
- * @memberOf NgxDecafFormService
1365
1476
  */
1366
1477
  static getControlFromForm(formId, path) {
1367
1478
  const form = this.formRegistry.get(formId);
@@ -1379,18 +1490,15 @@ class NgxDecafFormService {
1379
1490
  * @summary Generates a FormGroup from an array of UIModelMetadata objects, extracting component
1380
1491
  * properties and creating appropriate form controls. This method is specifically designed to work
1381
1492
  * with the UI decorator system and provides automatic form generation from metadata.
1382
- *
1383
1493
  * @param {string} id - Unique identifier for the form
1384
1494
  * @param {boolean} [registry=false] - Whether to register the created form in the global registry
1385
1495
  * @param {UIModelMetadata[]} [children] - Array of UI model metadata objects to create controls from
1386
1496
  * @return {FormGroup} The created FormGroup with controls for each child metadata
1387
- *
1388
1497
  * @mermaid
1389
1498
  * sequenceDiagram
1390
1499
  * participant C as Component
1391
1500
  * participant NFS as NgxDecafFormService
1392
1501
  * participant AF as Angular Forms
1393
- *
1394
1502
  * C->>NFS: createFormFromChildren(id, registry, children)
1395
1503
  * NFS->>AF: new FormGroup({})
1396
1504
  * loop For each child metadata
@@ -1401,9 +1509,7 @@ class NgxDecafFormService {
1401
1509
  * NFS->>NFS: addRegistry(id, form)
1402
1510
  * end
1403
1511
  * NFS-->>C: Return FormGroup
1404
- *
1405
1512
  * @static
1406
- * @memberOf NgxDecafFormService
1407
1513
  */
1408
1514
  static createFormFromChildren(id, registry = false, children) {
1409
1515
  const form = new FormGroup({});
@@ -1420,18 +1526,15 @@ class NgxDecafFormService {
1420
1526
  * @summary Generates a FormGroup based on an array of component configurations and optionally registers it.
1421
1527
  * This method processes component input configurations to create appropriate form controls with
1422
1528
  * validation and initial values.
1423
- *
1424
1529
  * @param {string} id - The unique identifier for the form
1425
1530
  * @param {IComponentConfig[]} components - An array of component configurations defining the form structure
1426
1531
  * @param {boolean} [registry=false] - Whether to register the created form in the global registry
1427
1532
  * @return {FormGroup} The created FormGroup with controls for each component configuration
1428
- *
1429
1533
  * @mermaid
1430
1534
  * sequenceDiagram
1431
1535
  * participant C as Component
1432
1536
  * participant NFS as NgxDecafFormService
1433
1537
  * participant AF as Angular Forms
1434
- *
1435
1538
  * C->>NFS: createFormFromComponents(id, components, registry)
1436
1539
  * NFS->>AF: new FormGroup({})
1437
1540
  * loop For each component config
@@ -1442,9 +1545,7 @@ class NgxDecafFormService {
1442
1545
  * NFS->>NFS: addRegistry(id, form)
1443
1546
  * end
1444
1547
  * NFS-->>C: Return FormGroup
1445
- *
1446
1548
  * @static
1447
- * @memberOf NgxDecafFormService
1448
1549
  */
1449
1550
  static createFormFromComponents(id, components, registry = false) {
1450
1551
  const form = new FormGroup({});
@@ -1459,54 +1560,51 @@ class NgxDecafFormService {
1459
1560
  * @description Adds a control to a form based on component properties.
1460
1561
  * @summary Creates and adds a form control to a form (existing or new) based on the provided component properties.
1461
1562
  * Handles multi-page forms by managing FormArray structures and proper indexing. This method supports
1462
- * complex form scenarios including nested controls and page-based form organization.
1463
- *
1563
+ * complex form scenarios including nested controls and page-based form organization. It automatically
1564
+ * creates FormArrays for forms with multiple pages and manages page indexing.
1464
1565
  * @param {string} id - The unique identifier of the form
1465
1566
  * @param {FieldProperties} componentProperties - The properties of the component to create the control from
1466
1567
  * @param {FieldProperties} [parentProps] - Optional parent properties for context and configuration
1467
- * @return {AbstractControl} The form or created control
1468
- *
1568
+ * @return {FormParent} The form or created control (FormGroup or FormArray)
1569
+ * @throws {Error} If page property is required but not provided or is invalid
1469
1570
  * @mermaid
1470
1571
  * sequenceDiagram
1471
1572
  * participant C as Component
1472
1573
  * participant NFS as NgxDecafFormService
1473
1574
  * participant F as Form
1474
- *
1475
1575
  * C->>NFS: addControlFromProps(id, componentProps, parentProps?)
1476
- * NFS->>NFS: createForm(id, parentProps, true)
1477
- * alt Multi-page form (parentProps.pages > 1)
1576
+ * NFS->>NFS: createForm(id, formArray, true)
1577
+ * alt Multi-page form (parentProps.pages > 0)
1478
1578
  * NFS->>NFS: Calculate page index
1479
- * NFS->>F: Get or create FormGroup at index
1579
+ * alt Group doesn't exist at index
1580
+ * NFS->>F: Create new FormGroup at index
1581
+ * end
1480
1582
  * NFS->>NFS: Set form to page FormGroup
1481
1583
  * end
1482
1584
  * alt componentProperties has path
1483
1585
  * NFS->>NFS: addFormControl(form, componentProperties, parentProps)
1484
1586
  * end
1485
1587
  * NFS-->>C: Return form/control
1486
- *
1487
1588
  * @static
1488
- * @memberOf NgxDecafFormService
1489
1589
  */
1490
1590
  static addControlFromProps(id, componentProperties, parentProps) {
1491
1591
  const formArray = (componentProperties?.pages && componentProperties?.pages >= 1 || componentProperties.multiple === true);
1492
1592
  let form = this.createForm(id, formArray, true);
1493
- const formLength = form.length;
1494
1593
  if (parentProps?.pages && parentProps?.pages > 0) {
1495
- let index = componentProperties.page || parentProps.page;
1594
+ const index = componentProperties.page || parentProps.page;
1496
1595
  if (!(typeof index === 'number') || index === 0)
1497
1596
  throw Error(`Property 'page' is required and greather than 0 on ${componentProperties.name}`);
1498
- if (index > formLength) {
1499
- if (form?.['lastIndex'] && index === form['lastIndex']['page']) {
1500
- index = form['lastIndex']['index'];
1501
- }
1502
- else {
1503
- form['lastIndex'] = {
1504
- page: index,
1505
- index: formLength + 1
1506
- };
1507
- index = formLength + 1;
1508
- }
1509
- }
1597
+ // if(index > formLength) {
1598
+ // if((form as KeyValue)?.['lastIndex'] && index === (form as KeyValue)['lastIndex']['page']) {
1599
+ // index = (form as KeyValue)['lastIndex']['index'];
1600
+ // } else {
1601
+ // (form as KeyValue)['lastIndex'] = {
1602
+ // page: index,
1603
+ // index: formLength + 1
1604
+ // };
1605
+ // index = formLength + 1;
1606
+ // }
1607
+ // }
1510
1608
  let group = form.controls[index - 1];
1511
1609
  if (!group) {
1512
1610
  group = new FormGroup({});
@@ -1523,17 +1621,14 @@ class NgxDecafFormService {
1523
1621
  * @summary Extracts and processes the data from a FormGroup, handling different input types and nested form groups.
1524
1622
  * Performs type conversion for various HTML5 input types, validates nested controls, and manages
1525
1623
  * multiple control scenarios. Automatically enables all group controls after data extraction.
1526
- *
1527
1624
  * @param {FormGroup} formGroup - The FormGroup to extract data from
1528
1625
  * @return {Record<string, unknown>} An object containing the processed form data with proper type conversions
1529
- *
1530
1626
  * @mermaid
1531
1627
  * sequenceDiagram
1532
1628
  * participant C as Component
1533
1629
  * participant NFS as NgxDecafFormService
1534
1630
  * participant FG as FormGroup
1535
1631
  * participant FC as FormControl
1536
- *
1537
1632
  * C->>NFS: getFormData(formGroup)
1538
1633
  * loop For each control in formGroup
1539
1634
  * alt Control is not FormControl
@@ -1557,9 +1652,7 @@ class NgxDecafFormService {
1557
1652
  * end
1558
1653
  * NFS->>NFS: enableAllGroupControls(formGroup)
1559
1654
  * NFS-->>C: Return processed data object
1560
- *
1561
1655
  * @static
1562
- * @memberOf NgxDecafFormService
1563
1656
  */
1564
1657
  static getFormData(formGroup) {
1565
1658
  const data = {};
@@ -1610,13 +1703,11 @@ class NgxDecafFormService {
1610
1703
  * @summary Recursively validates all fields in a form control or form group, marking them as touched and dirty.
1611
1704
  * Performs comprehensive validation including uniqueness checks for primary keys in FormArray scenarios.
1612
1705
  * This method ensures all validation rules are applied and form state is properly updated.
1613
- *
1614
1706
  * @param {AbstractControl} control - The control or form group to validate
1615
1707
  * @param {string} [pk] - Optional primary key field name for uniqueness validation
1616
1708
  * @param {string} [path] - The path to the control within the form for error reporting
1617
1709
  * @return {boolean} True if all fields are valid, false otherwise
1618
1710
  * @throws {Error} If no control is found at the specified path or if the control type is unknown
1619
- *
1620
1711
  * @mermaid
1621
1712
  * sequenceDiagram
1622
1713
  * participant C as Component
@@ -1624,7 +1715,6 @@ class NgxDecafFormService {
1624
1715
  * participant FC as FormControl
1625
1716
  * participant FG as FormGroup
1626
1717
  * participant FA as FormArray
1627
- *
1628
1718
  * C->>NFS: validateFields(control, pk?, path?)
1629
1719
  * alt Control is FormControl
1630
1720
  * NFS->>FC: markAsTouched()
@@ -1650,9 +1740,7 @@ class NgxDecafFormService {
1650
1740
  * else Unknown control type
1651
1741
  * NFS-->>C: Throw Error
1652
1742
  * end
1653
- *
1654
1743
  * @static
1655
- * @memberOf NgxDecafFormService
1656
1744
  */
1657
1745
  static validateFields(control, pk, path) {
1658
1746
  control = path ? control.get(path) : control;
@@ -1703,8 +1791,12 @@ class NgxDecafFormService {
1703
1791
  /**
1704
1792
  * @description Generates validators from component properties.
1705
1793
  * @summary Creates an array of ValidatorFn based on the supported validation keys in the component properties.
1706
- * @param {KeyValue} props - The component properties.
1707
- * @return {ValidatorFn[]} An array of validator functions.
1794
+ * Maps each validation property to its corresponding Angular validator function using the ValidatorFactory.
1795
+ * Only processes properties that are recognized as validation keys by the Validation utility.
1796
+ * @param {KeyValue} props - The component properties containing validation rules
1797
+ * @return {ValidatorFn[]} An array of validator functions
1798
+ * @private
1799
+ * @static
1708
1800
  */
1709
1801
  static validatorsFromProps(props) {
1710
1802
  const supportedValidationKeys = Validation.keys();
@@ -1719,18 +1811,15 @@ class NgxDecafFormService {
1719
1811
  * @summary Generates a FormControl with validators and initial configuration based on the provided
1720
1812
  * component properties. Handles different input types, sets initial values, and configures
1721
1813
  * validation rules and update modes.
1722
- *
1723
1814
  * @param {FieldProperties} props - The component properties defining the control configuration
1724
1815
  * @param {FieldUpdateMode} [updateMode='change'] - The update mode for the control ('change', 'blur', 'submit')
1725
1816
  * @return {FormControl} The created FormControl with proper configuration and validators
1726
- *
1727
1817
  * @mermaid
1728
1818
  * sequenceDiagram
1729
1819
  * participant C as Component
1730
1820
  * participant NFS as NgxDecafFormService
1731
1821
  * participant VF as ValidatorFactory
1732
1822
  * participant AF as Angular Forms
1733
- *
1734
1823
  * C->>NFS: fromProps(props, updateMode?)
1735
1824
  * NFS->>NFS: validatorsFromProps(props)
1736
1825
  * NFS->>VF: Create validators from props
@@ -1745,9 +1834,7 @@ class NgxDecafFormService {
1745
1834
  * NFS->>AF: new FormControl(config)
1746
1835
  * AF-->>NFS: Return FormControl
1747
1836
  * NFS-->>C: Return configured FormControl
1748
- *
1749
1837
  * @static
1750
- * @memberOf NgxDecafFormService
1751
1838
  */
1752
1839
  static fromProps(props, updateMode = 'change') {
1753
1840
  const validators = this.validatorsFromProps(props);
@@ -1771,12 +1858,9 @@ class NgxDecafFormService {
1771
1858
  * @summary Gets the FieldProperties associated with a form control from the internal WeakMap.
1772
1859
  * This method provides access to the original component properties that were used to create
1773
1860
  * the control, enabling validation, rendering, and behavior configuration.
1774
- *
1775
1861
  * @param {FormControl | FormArray | FormGroup} control - The form control to get properties for
1776
1862
  * @return {FieldProperties} The properties associated with the control, or empty object if not found
1777
- *
1778
1863
  * @static
1779
- * @memberOf NgxDecafFormService
1780
1864
  */
1781
1865
  static getPropsFromControl(control) {
1782
1866
  return this.controls.get(control) || {};
@@ -1786,18 +1870,15 @@ class NgxDecafFormService {
1786
1870
  * @summary Traverses up the DOM tree to find the nearest parent element with the specified tag name.
1787
1871
  * This is useful for finding container elements or specific parent components in the DOM hierarchy.
1788
1872
  * The search is case-insensitive for tag name matching.
1789
- *
1790
1873
  * @param {HTMLElement} el - The starting element to traverse from
1791
1874
  * @param {string} tag - The tag name to search for (case-insensitive)
1792
1875
  * @return {HTMLElement} The found parent element with the specified tag
1793
1876
  * @throws {Error} If no parent with the specified tag is found in the DOM tree
1794
- *
1795
1877
  * @mermaid
1796
1878
  * sequenceDiagram
1797
1879
  * participant C as Component
1798
1880
  * participant NFS as NgxDecafFormService
1799
1881
  * participant DOM as DOM Tree
1800
- *
1801
1882
  * C->>NFS: getParentEl(element, tagName)
1802
1883
  * loop Traverse up DOM tree
1803
1884
  * NFS->>DOM: Get parentElement
@@ -1808,9 +1889,7 @@ class NgxDecafFormService {
1808
1889
  * NFS-->>C: Throw Error
1809
1890
  * end
1810
1891
  * end
1811
- *
1812
1892
  * @static
1813
- * @memberOf NgxDecafFormService
1814
1893
  */
1815
1894
  static getParentEl(el, tag) {
1816
1895
  let parent;
@@ -1827,30 +1906,35 @@ class NgxDecafFormService {
1827
1906
  * @summary Associates a form control with its component properties for later retrieval.
1828
1907
  * This enables the service to maintain metadata about controls without creating memory leaks,
1829
1908
  * as WeakMap automatically cleans up references when controls are garbage collected.
1830
- *
1831
1909
  * @param {AbstractControl} control - The control to register (FormControl, FormGroup, or FormArray)
1832
1910
  * @param {FieldProperties} props - The properties to associate with the control
1833
1911
  * @return {void}
1834
- *
1835
1912
  * @static
1836
- * @memberOf NgxDecafFormService
1837
1913
  */
1838
1914
  static register(control, props) {
1839
1915
  this.controls.set(control, props);
1840
1916
  }
1841
1917
  /**
1842
- * @description Unregisters a control.
1918
+ * @description Unregisters a control from the internal WeakMap.
1843
1919
  * @summary Removes a control and its associated properties from the internal WeakMap.
1844
- * @param {AbstractControl} control - The control to unregister.
1845
- * @return {boolean} True if the control was successfully unregistered, false otherwise.
1920
+ * This cleans up the metadata tracking for the control and frees up memory. Returns
1921
+ * true if the control was found and removed, false if it was not in the registry.
1922
+ * @param {AbstractControl} control - The control to unregister (FormControl, FormGroup, or FormArray)
1923
+ * @return {boolean} True if the control was successfully unregistered, false otherwise
1924
+ * @static
1846
1925
  */
1847
1926
  static unregister(control) {
1848
1927
  return this.controls.delete(control);
1849
1928
  }
1850
1929
  /**
1851
- * @description Resets a form group.
1852
- * @summary Recursively resets all controls in a form group, clearing values, errors, and marking them as pristine and untouched.
1853
- * @param {FormGroup} formGroup - The form group to reset.
1930
+ * @description Resets a form group or form control.
1931
+ * @summary Recursively resets all controls in a form group or a single form control, clearing values,
1932
+ * errors, and marking them as pristine and untouched. For FormControls, it sets the value to empty
1933
+ * string (except for checkbox types) and clears validation errors. For FormGroups, it recursively
1934
+ * resets all child controls.
1935
+ * @param {FormGroup | FormControl} formGroup - The form group or form control to reset
1936
+ * @return {void}
1937
+ * @static
1854
1938
  */
1855
1939
  static reset(formGroup) {
1856
1940
  if (formGroup instanceof FormControl) {
@@ -1874,32 +1958,29 @@ class NgxDecafFormService {
1874
1958
  }
1875
1959
 
1876
1960
  /**
1877
- * @module module:lib/engine/NgxRenderingEngine
1961
+ * @module lib/engine/NgxRenderingEngine
1878
1962
  * @description Angular rendering engine for Decaf model-driven UIs.
1879
1963
  * @summary Implements NgxRenderingEngine which converts model decorator metadata
1880
1964
  * into Angular components, manages component registration, and orchestrates
1881
1965
  * dynamic component creation and input mapping.
1882
- *
1883
1966
  * @link {@link NgxRenderingEngine}
1884
1967
  */
1885
1968
  /**
1886
- * @description Angular implementation of the RenderingEngine with enhanced features
1887
- * @summary This class extends the base RenderingEngine to provide Angular-specific rendering capabilities
1888
- * with additional features compared to NgxRenderingEngine. It handles the conversion of field definitions
1889
- * to Angular components, manages component registration, and provides utilities for component creation
1890
- * and input handling. This implementation uses Angular's newer component APIs.
1891
- *
1969
+ * @description Angular implementation of the RenderingEngine for Decaf components.
1970
+ * @summary This class extends the base RenderingEngine to provide Angular-specific rendering capabilities.
1971
+ * It handles the conversion of field definitions to Angular components, manages component registration,
1972
+ * and provides utilities for component creation and input handling. The engine converts model decorator
1973
+ * metadata into dynamically created Angular components with proper input binding and lifecycle management.
1892
1974
  * @template AngularFieldDefinition - Type for Angular-specific field definitions
1893
1975
  * @template AngularDynamicOutput - Type for Angular-specific component output
1894
- *
1895
1976
  * @class NgxRenderingEngine
1977
+ * @extends {RenderingEngine<AngularFieldDefinition, AngularDynamicOutput>}
1896
1978
  * @example
1897
1979
  * ```typescript
1898
1980
  * const engine = NgxRenderingEngine.get();
1899
1981
  * engine.initialize();
1900
1982
  * const output = engine.render(myModel, {}, viewContainerRef, injector, templateRef);
1901
1983
  * ```
1902
- *
1903
1984
  * @mermaid
1904
1985
  * sequenceDiagram
1905
1986
  * participant Client
@@ -1915,49 +1996,61 @@ class NgxDecafFormService {
1915
1996
  * Components-->>Engine: component constructor
1916
1997
  * Engine->>Engine: createComponent(component, inputs, metadata, vcr, injector, template)
1917
1998
  * Engine-->>Client: return AngularDynamicOutput
1999
+ * @memberOf module:lib/engine/NgxRenderingEngine
1918
2000
  */
1919
2001
  class NgxRenderingEngine extends RenderingEngine {
1920
2002
  /**
1921
- * @description Current operation context for component visibility control
2003
+ * @description Current operation context for component visibility control.
1922
2004
  * @summary Static property that stores the current operation being performed,
1923
2005
  * which is used to determine component visibility through the 'hidden' property.
1924
2006
  * Components can specify operations where they should be hidden, and this property
1925
2007
  * provides the context for those visibility checks. The value is typically extracted
1926
2008
  * from the global properties during the rendering process.
1927
- *
1928
2009
  * @private
1929
2010
  * @static
1930
2011
  * @type {string | undefined}
2012
+ * @memberOf module:lib/engine/NgxRenderingEngine
1931
2013
  */
1932
2014
  static { this._operation = undefined; }
1933
2015
  // private static _projectable: boolean = true
2016
+ /**
2017
+ * @description Parent component properties for child component inheritance.
2018
+ * @summary Static property that stores parent component properties that should be
2019
+ * inherited by child components. This is particularly used for passing page configuration
2020
+ * down to child components in multi-page forms. The property is cleared after rendering
2021
+ * to prevent property leakage between unrelated component trees.
2022
+ * @private
2023
+ * @static
2024
+ * @type {KeyValue | undefined}
2025
+ * @memberOf module:lib/engine/NgxRenderingEngine
2026
+ */
1934
2027
  static { this._parentProps = undefined; }
1935
2028
  /**
1936
- * @description Constructs a new NgxRenderingEngine instance
2029
+ * @description Constructs a new NgxRenderingEngine instance.
1937
2030
  * @summary Initializes a new instance of the Angular rendering engine by calling the parent
1938
2031
  * constructor with the 'angular' engine type identifier. This constructor sets up the base
1939
2032
  * rendering engine functionality with Angular-specific configurations and prepares the
1940
2033
  * instance for component registration and rendering operations.
1941
- *
1942
2034
  * @constructor
2035
+ * @memberOf module:lib/engine/NgxRenderingEngine
1943
2036
  */
1944
2037
  constructor() {
1945
- super('angular');
2038
+ super(AngularEngineKeys.FLAVOUR);
1946
2039
  }
1947
2040
  /**
1948
- * @description Converts a field definition to an Angular component output
2041
+ * @description Converts a field definition to an Angular component output.
1949
2042
  * @summary This private method takes a field definition and creates the corresponding Angular component.
1950
- * It handles component instantiation, input property mapping, and child component rendering.
1951
- * The method validates input properties against the component's metadata and processes
2043
+ * It handles component instantiation, input property mapping, child component rendering, and visibility
2044
+ * control. The method validates input properties against the component's metadata and processes
1952
2045
  * child components recursively.
1953
- *
1954
2046
  * @param {FieldDefinition<AngularFieldDefinition>} fieldDef - The field definition to convert
1955
2047
  * @param {ViewContainerRef} vcr - The view container reference for component creation
1956
2048
  * @param {Injector} injector - The Angular injector for dependency injection
1957
2049
  * @param {TemplateRef<any>} tpl - The template reference for content projection
1958
2050
  * @param {string} registryFormId - Form identifier for the component renderer
2051
+ * @param {boolean} createComponent - Whether to create the component instance
2052
+ * @param {FormParent} [formGroup] - Optional form group for form components
1959
2053
  * @return {AngularDynamicOutput} The Angular component output with component reference and inputs
1960
- *
1961
2054
  * @mermaid
1962
2055
  * sequenceDiagram
1963
2056
  * participant Method as fromFieldDefinition
@@ -1978,6 +2071,8 @@ class NgxRenderingEngine extends RenderingEngine {
1978
2071
  * Method->>Method: Create component instance
1979
2072
  * end
1980
2073
  * Method-->>Caller: return AngularDynamicOutput
2074
+ * @private
2075
+ * @memberOf module:lib/engine/NgxRenderingEngine
1981
2076
  */
1982
2077
  fromFieldDefinition(fieldDef, vcr, injector, tpl, registryFormId = Date.now().toString(36).toUpperCase(), createComponent = true, formGroup) {
1983
2078
  const cmp = fieldDef?.['component'] || NgxRenderingEngine.components(fieldDef.tag);
@@ -2047,11 +2142,10 @@ class NgxRenderingEngine extends RenderingEngine {
2047
2142
  return result;
2048
2143
  }
2049
2144
  /**
2050
- * @description Creates an Angular component instance
2145
+ * @description Creates an Angular component instance with inputs and template projection.
2051
2146
  * @summary This static utility method creates an Angular component instance with the specified
2052
2147
  * inputs and template. It uses Angular's component creation API to instantiate the component
2053
2148
  * and then sets the input properties using the provided metadata.
2054
- *
2055
2149
  * @param {Type<unknown>} component - The component type to create
2056
2150
  * @param {KeyValue} [inputs={}] - The input properties to set on the component
2057
2151
  * @param {ComponentMirror<unknown>} metadata - The component metadata for input validation
@@ -2059,6 +2153,8 @@ class NgxRenderingEngine extends RenderingEngine {
2059
2153
  * @param {Injector} injector - The Angular injector for dependency injection
2060
2154
  * @param {Node[]} [template=[]] - The template nodes to project into the component
2061
2155
  * @return {ComponentRef<unknown>} The created component reference
2156
+ * @static
2157
+ * @memberOf module:lib/engine/NgxRenderingEngine
2062
2158
  */
2063
2159
  static createComponent(component, inputs = {}, metadata, vcr, injector, template = []) {
2064
2160
  const componentInstance = vcr.createComponent(component, {
@@ -2069,26 +2165,29 @@ class NgxRenderingEngine extends RenderingEngine {
2069
2165
  return componentInstance;
2070
2166
  }
2071
2167
  /**
2072
- * @description Extracts decorator metadata from a model
2168
+ * @description Extracts decorator metadata from a model.
2073
2169
  * @summary This method provides access to the field definition generated from a model's
2074
2170
  * decorators. It's a convenience wrapper around the toFieldDefinition method that
2075
2171
  * converts a model to a field definition based on its decorators and the provided
2076
2172
  * global properties.
2077
- *
2078
2173
  * @param {Model} model - The model to extract decorators from
2079
2174
  * @param {Record<string, unknown>} globalProps - Global properties to include in the field definition
2080
2175
  * @return {FieldDefinition<AngularFieldDefinition>} The field definition generated from the model
2176
+ * @memberOf module:lib/engine/NgxRenderingEngine
2081
2177
  */
2082
2178
  getDecorators(model, globalProps) {
2083
2179
  return this.toFieldDefinition(model, globalProps);
2084
2180
  }
2085
2181
  /**
2086
- * @description Destroys the current engine instance
2087
- * @summary This static method clears the current instance reference, effectively
2088
- * destroying the singleton instance of the rendering engine. This can be used
2089
- * to reset the engine state or to prepare for a new instance creation.
2090
- *
2182
+ * @description Destroys the current engine instance and cleans up resources.
2183
+ * @summary This static method clears the current instance reference and parent props,
2184
+ * effectively destroying the singleton instance of the rendering engine. Optionally
2185
+ * removes the form registry for the specified form ID. This can be used to reset the
2186
+ * engine state or to prepare for a new instance creation.
2187
+ * @param {string} [formId] - Optional form ID to remove from registry
2091
2188
  * @return {Promise<void>} A promise that resolves when the instance is destroyed
2189
+ * @static
2190
+ * @memberOf module:lib/engine/NgxRenderingEngine
2092
2191
  */
2093
2192
  static async destroy(formId) {
2094
2193
  if (formId)
@@ -2097,12 +2196,11 @@ class NgxRenderingEngine extends RenderingEngine {
2097
2196
  NgxRenderingEngine._parentProps = undefined;
2098
2197
  }
2099
2198
  /**
2100
- * @description Renders a model into an Angular component output
2199
+ * @description Renders a model into an Angular component output.
2101
2200
  * @summary This method takes a model and converts it to an Angular component output.
2102
2201
  * It first stores a reference to the model, then converts it to a field definition
2103
2202
  * using the base RenderingEngine's toFieldDefinition method, and finally converts
2104
2203
  * that field definition to an Angular component output using fromFieldDefinition.
2105
- *
2106
2204
  * @template M - Type extending Model
2107
2205
  * @param {M} model - The model to render
2108
2206
  * @param {Record<string, unknown>} globalProps - Global properties to pass to the component
@@ -2110,7 +2208,6 @@ class NgxRenderingEngine extends RenderingEngine {
2110
2208
  * @param {Injector} injector - The Angular injector for dependency injection
2111
2209
  * @param {TemplateRef<any>} tpl - The template reference for content projection
2112
2210
  * @return {AngularDynamicOutput} The Angular component output with component reference and inputs
2113
- *
2114
2211
  * @mermaid
2115
2212
  * sequenceDiagram
2116
2213
  * participant Client as Client Code
@@ -2125,6 +2222,8 @@ class NgxRenderingEngine extends RenderingEngine {
2125
2222
  * Render->>FromField: fromFieldDefinition(fieldDef, vcr, injector, tpl)
2126
2223
  * FromField-->>Render: AngularDynamicOutput
2127
2224
  * Render-->>Client: return AngularDynamicOutput
2225
+ * @override
2226
+ * @memberOf module:lib/engine/NgxRenderingEngine
2128
2227
  */
2129
2228
  render(model, globalProps, vcr, injector, tpl) {
2130
2229
  let result;
@@ -2148,12 +2247,13 @@ class NgxRenderingEngine extends RenderingEngine {
2148
2247
  return result;
2149
2248
  }
2150
2249
  /**
2151
- * @description Initializes the rendering engine
2250
+ * @description Initializes the rendering engine.
2152
2251
  * @summary This method initializes the rendering engine. It checks if the engine is already initialized
2153
2252
  * and sets the initialized flag to true. This method is called before the engine is used
2154
2253
  * to ensure it's properly set up for rendering operations.
2155
- *
2156
2254
  * @return {Promise<void>} A promise that resolves when initialization is complete
2255
+ * @override
2256
+ * @memberOf module:lib/engine/NgxRenderingEngine
2157
2257
  */
2158
2258
  async initialize() {
2159
2259
  if (this.initialized)
@@ -2162,15 +2262,16 @@ class NgxRenderingEngine extends RenderingEngine {
2162
2262
  this.initialized = true;
2163
2263
  }
2164
2264
  /**
2165
- * @description Registers a component with the rendering engine
2265
+ * @description Registers a component with the rendering engine.
2166
2266
  * @summary This static method registers a component constructor with the rendering engine
2167
2267
  * under a specific name. It initializes the components registry if needed and throws
2168
2268
  * an error if a component is already registered under the same name to prevent
2169
2269
  * accidental overrides.
2170
- *
2171
2270
  * @param {string} name - The name to register the component under
2172
2271
  * @param {Constructor<unknown>} constructor - The component constructor
2173
2272
  * @return {void}
2273
+ * @static
2274
+ * @memberOf module:lib/engine/NgxRenderingEngine
2174
2275
  */
2175
2276
  static registerComponent(name, constructor) {
2176
2277
  if (!this._components)
@@ -2182,14 +2283,15 @@ class NgxRenderingEngine extends RenderingEngine {
2182
2283
  };
2183
2284
  }
2184
2285
  /**
2185
- * @description Retrieves registered components from the rendering engine
2286
+ * @description Retrieves registered components from the rendering engine.
2186
2287
  * @summary This static method retrieves either all registered components or a specific component
2187
2288
  * by its selector. When called without a selector, it returns an array of all registered
2188
2289
  * components. When called with a selector, it returns the specific component if found,
2189
2290
  * or throws an error if the component is not registered.
2190
- *
2191
2291
  * @param {string} [selector] - Optional selector to retrieve a specific component
2192
2292
  * @return {Object|Array} Either a specific component or an array of all components
2293
+ * @static
2294
+ * @memberOf module:lib/engine/NgxRenderingEngine
2193
2295
  */
2194
2296
  static components(selector) {
2195
2297
  if (!selector)
@@ -2199,30 +2301,30 @@ class NgxRenderingEngine extends RenderingEngine {
2199
2301
  return this._components[selector];
2200
2302
  }
2201
2303
  /**
2202
- * @description Generates a key for reflection metadata
2304
+ * @description Generates a key for reflection metadata storage.
2203
2305
  * @summary This static method generates a key for reflection metadata by prefixing the input key
2204
2306
  * with the Angular engine's reflection prefix. This is used for storing and retrieving
2205
2307
  * metadata in a namespaced way to avoid conflicts with other metadata.
2206
- *
2207
2308
  * @param {string} key - The base key to prefix
2208
2309
  * @return {string} The prefixed key for reflection metadata
2310
+ * @static
2311
+ * @override
2312
+ * @memberOf module:lib/engine/NgxRenderingEngine
2209
2313
  */
2210
2314
  static key(key) {
2211
2315
  return `${AngularEngineKeys.REFLECT}${key}`;
2212
2316
  }
2213
2317
  /**
2214
- * @description Sets input properties on a component instance
2318
+ * @description Sets input properties on a component instance.
2215
2319
  * @summary This static utility method sets input properties on a component instance
2216
2320
  * based on the provided inputs object and component metadata. It handles both simple
2217
2321
  * values and nested objects, recursively processing object properties. The method
2218
2322
  * validates each input against the component's metadata to ensure only valid inputs
2219
2323
  * are set.
2220
- *
2221
2324
  * @param {ComponentRef<unknown>} component - The component reference to set inputs on
2222
2325
  * @param {KeyValue} inputs - The input properties to set
2223
2326
  * @param {ComponentMirror<unknown>} metadata - The component metadata for input validation
2224
2327
  * @return {void}
2225
- *
2226
2328
  * @mermaid
2227
2329
  * sequenceDiagram
2228
2330
  * participant Caller
@@ -2242,6 +2344,8 @@ class NgxRenderingEngine extends RenderingEngine {
2242
2344
  * SetInputs->>Component: setInput(key, value)
2243
2345
  * end
2244
2346
  * end
2347
+ * @static
2348
+ * @memberOf module:lib/engine/NgxRenderingEngine
2245
2349
  */
2246
2350
  static setInputs(component, inputs, metadata) {
2247
2351
  function parseInputValue(component, input) {
@@ -2344,7 +2448,8 @@ var errors = {
2344
2448
  lessThanOrEqual: "This field must be less than or equal to field {0}",
2345
2449
  greaterThan: "This field must be greater than field {0}",
2346
2450
  greaterThanOrEqual: "This field must be greater than or equal to field {0}",
2347
- form_control: "Controlador do formulário não encontrado para {0}."
2451
+ form_control: "Controlador do formulário não encontrado para {0}.",
2452
+ not_found: "No records found with <span class=\"text-bold\">{0}: {1} in {2}</span>."
2348
2453
  };
2349
2454
  var component = {
2350
2455
  fieldset: {
@@ -2378,7 +2483,7 @@ var component = {
2378
2483
  },
2379
2484
  empty_state: {
2380
2485
  title: "No data found",
2381
- button: "Create",
2486
+ button_create: "Create",
2382
2487
  search: {
2383
2488
  title: "Not data found for search",
2384
2489
  subtitle: "You searched for: <ion-text color=\"primary\" class=\"display-block ion-text-center text-bold\">{0}</ion-text>",
@@ -2507,12 +2612,11 @@ function provideI18n(config = { fallbackLang: 'en', lang: 'en' }, resources = []
2507
2612
  }
2508
2613
 
2509
2614
  /**
2510
- * @module module:lib/engine/NgxDecafComponentDirective
2615
+ * @module lib/engine/NgxDecafComponentDirective
2511
2616
  * @description Base decaf component abstraction providing shared inputs and utilities.
2512
2617
  * @summary NgxDecafComponentDirective is the abstract foundation for Decaf components and provides common
2513
2618
  * inputs (model, mapper, pk, props), logging, repository resolution, and event dispatch helpers.
2514
2619
  * It centralizes shared behavior for child components and simplifies integration with the rendering engine.
2515
- *
2516
2620
  * @link {@link NgxDecafComponentDirective}
2517
2621
  */
2518
2622
  try {
@@ -2521,194 +2625,250 @@ try {
2521
2625
  catch (e) {
2522
2626
  throw new Error(`Failed to load rendering engine: ${e}`);
2523
2627
  }
2628
+ /**
2629
+ * @description Base directive for Decaf components in Angular applications.
2630
+ * @summary Abstract base class that provides common functionality for all Decaf components.
2631
+ * This directive establishes a foundation for component development by offering shared inputs
2632
+ * (model, mapper, pk, props), logging infrastructure, repository access, event handling, and
2633
+ * internationalization support. It implements OnChanges to respond to input property changes
2634
+ * and includes utilities for navigation, localization, and dynamic property binding. All Decaf
2635
+ * components should extend this directive to inherit its foundational capabilities.
2636
+ * @class NgxDecafComponentDirective
2637
+ * @extends {LoggedClass}
2638
+ * @implements {OnChanges}
2639
+ * @memberOf module:lib/engine/NgxDecafComponentDirective
2640
+ */
2524
2641
  class NgxDecafComponentDirective extends LoggedClass {
2642
+ /**
2643
+ * @description Constructor for NgxDecafComponentDirective.
2644
+ * @summary Initializes the directive by setting up the component name, locale root,
2645
+ * and logger. Calls the parent LoggedClass constructor and configures localization
2646
+ * context. The component name and locale root can be optionally injected via the
2647
+ * CPTKN token, otherwise defaults are used.
2648
+ * @param {string} [componentName] - Optional component name for identification and logging
2649
+ * @param {string} [localeRoot] - Optional locale root key for internationalization
2650
+ * @memberOf module:lib/engine/NgxDecafComponentDirective
2651
+ */
2525
2652
  // eslint-disable-next-line @angular-eslint/prefer-inject
2526
2653
  constructor(componentName, localeRoot) {
2527
2654
  super();
2528
- this.componentName = componentName;
2529
- this.localeRoot = localeRoot;
2530
2655
  /**
2531
- * @description Unique identifier for the current record.
2532
- * @summary A unique identifier for the current record being displayed or manipulated.
2533
- * This is typically used in conjunction with the primary key for operations on specific records.
2534
- *
2656
+ * @description Unique identifier for the component instance.
2657
+ * @summary A unique identifier automatically generated for each component instance.
2658
+ * This UID is used for DOM element identification, component tracking, and debugging purposes.
2659
+ * By default, it generates a random 16-character value, but it can be explicitly set via input.
2535
2660
  * @type {string | number}
2536
- * @memberOf NgxDecafComponentDirective
2661
+ * @default generateRandomValue(16)
2662
+ * @memberOf module:lib/engine/NgxDecafComponentDirective
2537
2663
  */
2538
2664
  this.uid = generateRandomValue(16);
2539
2665
  /**
2540
- * @description Field mapping configuration.
2666
+ * @description Field mapping configuration object or function.
2541
2667
  * @summary Defines how fields from the data model should be mapped to properties used by the component.
2542
- * This allows for flexible data binding between the model and the component's display logic.
2543
- *
2544
- * @type {Record<string, string>}
2545
- * @memberOf NgxDecafComponentDirective
2668
+ * This allows for flexible data binding between the model and the component's display logic. Can be
2669
+ * provided as a static object mapping or as a function for dynamic mapping transformations.
2670
+ * @type {Record<string, string> | FunctionLike}
2671
+ * @default {}
2672
+ * @memberOf module:lib/engine/NgxDecafComponentDirective
2546
2673
  */
2547
2674
  this.mapper = {};
2548
2675
  /**
2549
- * @description Available CRUD operations for this component.
2676
+ * @description Available CRUD operations for this component instance.
2550
2677
  * @summary Defines which CRUD operations (Create, Read, Update, Delete) are available
2551
- * for this component. This affects which operations can be performed on the data.
2552
- *
2678
+ * for this component. This affects which operations can be performed on the data and
2679
+ * which operation buttons are displayed in the UI. By default, only READ operations are enabled.
2680
+ * @type {CrudOperations[]}
2553
2681
  * @default [OperationKeys.READ]
2554
- * @memberOf NgxDecafComponentDirective
2682
+ * @memberOf module:lib/engine/NgxDecafComponentDirective
2555
2683
  */
2556
2684
  this.operations = [OperationKeys.READ];
2557
2685
  /**
2558
- * @description Primary key field name for the model.
2559
- * @summary Specifies which field in the model should be used as the primary key.
2560
- * This is typically used for identifying unique records in operations like update and delete.
2686
+ * @description The CRUD operation type to be performed on the model.
2687
+ * @summary Specifies which operation (Create, Read, Update, Delete) this component instance
2688
+ * should perform. This determines the UI behavior, form configuration, and available actions.
2689
+ * The operation affects form validation, field availability, and the specific repository
2690
+ * method called during data submission.
2561
2691
  *
2692
+ * @type {OperationKeys.CREATE | OperationKeys.READ | OperationKeys.UPDATE | OperationKeys.DELETE}
2693
+ * @default OperationKeys.READ
2694
+ * @memberOf ModelPage
2695
+ */
2696
+ this.operation = OperationKeys.READ;
2697
+ /**
2698
+ * @description Row position in a grid-based layout system.
2699
+ * @summary Specifies the row position of this component when rendered within a grid-based layout.
2700
+ * This property is used for positioning components in multi-row, multi-column layouts and helps
2701
+ * establish the component's vertical placement within the grid structure.
2562
2702
  * @type {number}
2563
2703
  * @default 1
2564
- * @memberOf NgxDecafComponentDirective
2704
+ * @memberOf module:lib/engine/NgxDecafComponentDirective
2565
2705
  */
2566
2706
  this.row = 1;
2567
2707
  /**
2568
- * @description Primary key field name for the model.
2569
- * @summary Specifies which field in the model should be used as the primary key.
2570
- * This is typically used for identifying unique records in operations like update and delete.
2571
- *
2708
+ * @description Column position in a grid-based layout system.
2709
+ * @summary Specifies the column position of this component when rendered within a grid-based layout.
2710
+ * This property is used for positioning components in multi-row, multi-column layouts and helps
2711
+ * establish the component's horizontal placement within the grid structure.
2572
2712
  * @type {number}
2573
2713
  * @default 1
2574
- * @memberOf NgxDecafComponentDirective
2714
+ * @memberOf module:lib/engine/NgxDecafComponentDirective
2575
2715
  */
2576
2716
  this.col = 1;
2577
2717
  /**
2578
- * @description Additional CSS class names to apply to the component.
2718
+ * @description Additional CSS class names for component styling.
2579
2719
  * @summary Allows custom CSS classes to be added to the component's root element.
2580
2720
  * These classes are appended to any automatically generated classes based on other
2581
2721
  * component properties. Multiple classes can be provided as a space-separated string.
2582
2722
  * This provides a way to customize the component's appearance beyond the built-in styling options.
2583
- *
2584
2723
  * @type {string}
2585
2724
  * @default ""
2586
- * @memberOf NgxDecafComponentDirective
2725
+ * @memberOf module:lib/engine/NgxDecafComponentDirective
2587
2726
  */
2588
2727
  this.className = '';
2589
2728
  /**
2590
- * @description Root component of the Decaf-ts for Angular application
2591
- * @summary This component serves as the main entry point for the application.
2592
- * It sets up the navigation menu, handles routing events, and initializes
2593
- * the application state. It also manages the application title and menu visibility.
2594
- *
2595
- * @private
2729
+ * @description Ionic menu controller service for menu management.
2730
+ * @summary Injected service that provides programmatic control over Ionic menu components.
2731
+ * This service allows the component to open, close, toggle, and manage menu states within
2732
+ * the application. It provides access to menu functionality for implementing navigation
2733
+ * and layout features that require menu interaction.
2734
+ * @protected
2596
2735
  * @type {MenuController}
2597
- * @memberOf NgxDecafComponentDirective
2736
+ * @memberOf module:lib/engine/NgxDecafComponentDirective
2598
2737
  */
2599
2738
  this.menuController = inject(MenuController);
2600
2739
  /**
2601
- * @description Angular change detection service.
2602
- * @summary Injected service that provides manual control over change detection cycles.
2603
- * This is essential for ensuring that programmatic DOM changes (like setting accordion
2604
- * attributes) are properly reflected in the component's state and trigger appropriate
2605
- * view updates when modifications occur outside the normal Angular change detection flow.
2606
- *
2607
- * @protected
2608
- * @type {ChangeDetectorRef}
2609
- * @memberOf CrudFormComponent
2610
- */
2740
+ * @description Angular change detection service for manual change detection control.
2741
+ * @summary Injected service that provides manual control over change detection cycles.
2742
+ * This is essential for ensuring that programmatic DOM changes (like setting accordion
2743
+ * attributes) are properly reflected in the component's state and trigger appropriate
2744
+ * view updates when modifications occur outside the normal Angular change detection flow.
2745
+ * @protected
2746
+ * @type {ChangeDetectorRef}
2747
+ * @memberOf module:lib/engine/NgxDecafComponentDirective
2748
+ */
2611
2749
  this.changeDetectorRef = inject(ChangeDetectorRef);
2612
2750
  /**
2613
- * @description Angular Renderer2 service for safe DOM manipulation.
2751
+ * @description Angular Renderer2 service for platform-agnostic DOM manipulation.
2614
2752
  * @summary Injected service that provides a safe, platform-agnostic way to manipulate DOM elements.
2615
2753
  * This service ensures proper handling of DOM operations across different platforms and environments,
2616
- * including server-side rendering and web workers.
2617
- *
2754
+ * including server-side rendering and web workers, without direct DOM access.
2618
2755
  * @protected
2619
2756
  * @type {Renderer2}
2620
- * @memberOf CrudFormComponent
2757
+ * @memberOf module:lib/engine/NgxDecafComponentDirective
2621
2758
  */
2622
2759
  this.renderer = inject(Renderer2);
2623
2760
  /**
2624
- * @description Translation service for internationalization.
2761
+ * @description Translation service for application internationalization.
2625
2762
  * @summary Injected service that provides translation capabilities for UI text.
2626
- * Used to translate button labels and validation messages based on the current locale.
2627
- *
2763
+ * Used to translate button labels, validation messages, and other text content based
2764
+ * on the current locale setting, enabling multilingual support throughout the application.
2628
2765
  * @protected
2629
2766
  * @type {TranslateService}
2630
- * @memberOf CrudFormComponent
2767
+ * @memberOf module:lib/engine/NgxDecafComponentDirective
2631
2768
  */
2632
2769
  this.translateService = inject(TranslateService);
2633
2770
  /**
2634
- * @description Event emitter for custom renderer events.
2635
- * @summary Emits custom events that occur within child components or the layout itself.
2771
+ * @description Event emitter for custom component events.
2772
+ * @summary Emits custom events that occur within child components or the component itself.
2636
2773
  * This allows parent components to listen for and respond to user interactions or
2637
- * state changes within the grid layout. Events are passed up the component hierarchy
2638
- * to enable coordinated behavior across the application.
2639
- *
2774
+ * state changes. Events are passed up the component hierarchy to enable coordinated
2775
+ * behavior across the application.
2640
2776
  * @type {EventEmitter<IBaseCustomEvent>}
2641
- * @memberOf NgxDecafComponentDirective
2777
+ * @memberOf module:lib/engine/NgxDecafComponentDirective
2642
2778
  */
2643
2779
  this.listenEvent = new EventEmitter();
2644
2780
  /**
2645
- * @description Angular Router instance for navigation
2646
- * @summary Injected Router service used for programmatic navigation
2647
- * to other pages after successful login or other routing operations.
2648
- *
2649
- * @private
2781
+ * @description Angular Router instance for programmatic navigation.
2782
+ * @summary Injected Router service used for programmatic navigation between routes
2783
+ * in the application. This service enables navigation to different views and operations,
2784
+ * handles route parameters, and manages the browser's navigation history.
2785
+ * @protected
2650
2786
  * @type {Router}
2651
- * @memberOf NgxDecafComponentDirective
2787
+ * @memberOf module:lib/engine/NgxDecafComponentDirective
2652
2788
  */
2653
2789
  this.router = inject(Router);
2654
2790
  /**
2655
- * @description Configuration for list item rendering
2791
+ * @description Configuration for list item rendering behavior.
2656
2792
  * @summary Defines how list items should be rendered in the component.
2657
2793
  * This property holds a configuration object that specifies the tag name
2658
2794
  * and other properties needed to render list items correctly. The tag property
2659
2795
  * identifies which component should be used to render each item in a list.
2660
2796
  * Additional properties can be included to customize the rendering behavior.
2661
- *
2662
2797
  * @type {Record<string, unknown>}
2663
2798
  * @default {tag: ""}
2664
- * @memberOf NgxDecafComponentDirective
2799
+ * @memberOf module:lib/engine/NgxDecafComponentDirective
2665
2800
  */
2666
2801
  this.item = { tag: '' };
2667
2802
  /**
2668
- * @description Dynamic properties configuration object.
2803
+ * @description Dynamic properties configuration for runtime customization.
2669
2804
  * @summary Contains key-value pairs of dynamic properties that can be applied to the component
2670
2805
  * at runtime. This flexible configuration object allows for dynamic property assignment without
2671
2806
  * requiring explicit input bindings for every possible configuration option. Properties from
2672
2807
  * this object are parsed and applied to the component instance through the parseProps method,
2673
2808
  * enabling customizable component behavior based on external configuration.
2674
- *
2675
2809
  * @type {Record<string, unknown>}
2676
2810
  * @default {}
2677
- * @memberOf NgxDecafComponentDirective
2811
+ * @memberOf module:lib/engine/NgxDecafComponentDirective
2678
2812
  */
2679
2813
  this.props = {};
2680
2814
  /**
2681
- * @description Flag indicating if the component has been initialized
2815
+ * @description Initialization status flag for the component.
2682
2816
  * @summary Tracks whether the component has completed its initialization process.
2683
2817
  * This flag is used to prevent duplicate initialization and to determine if
2684
2818
  * certain operations that require initialization can be performed.
2685
- *
2686
2819
  * @type {boolean}
2687
2820
  * @default false
2688
- * @memberOf NgxDecafComponentDirective
2821
+ * @memberOf module:lib/engine/NgxDecafComponentDirective
2689
2822
  */
2690
2823
  this.initialized = false;
2691
- this.componentName = this.componentName || "NgxDecafComponentDirective";
2692
- if (!this.localeRoot)
2824
+ /**
2825
+ * @description Reference to CRUD operation constants for template usage.
2826
+ * @summary Exposes the OperationKeys enum to the component template, enabling
2827
+ * conditional rendering and behavior based on operation types. This protected
2828
+ * readonly property ensures that template logic can access operation constants
2829
+ * while maintaining encapsulation and preventing accidental modification.
2830
+ * @protected
2831
+ * @readonly
2832
+ * @memberOf module:lib/engine/NgxDecafComponentDirective
2833
+ */
2834
+ this.OperationKeys = OperationKeys;
2835
+ /**
2836
+ * @description Angular Location service.
2837
+ * @summary Injected service that provides access to the browser's URL and history.
2838
+ * This service is used for interacting with the browser's history API, allowing
2839
+ * for back navigation and URL manipulation outside of Angular's router.
2840
+ *
2841
+ * @private
2842
+ * @type {Location}
2843
+ */
2844
+ this.location = inject(Location);
2845
+ this.componentName = componentName || "NgxDecafComponentDirective";
2846
+ this.localeRoot = localeRoot;
2847
+ if (!this.localeRoot && this.componentName)
2693
2848
  this.localeRoot = this.componentName;
2849
+ if (this.localeRoot)
2850
+ this.getLocale(this.localeRoot);
2694
2851
  this.logger = this.log;
2695
2852
  }
2853
+ /**
2854
+ * @description Getter for the current locale context identifier.
2855
+ * @summary Returns the current locale identifier by calling the getLocale method.
2856
+ * This property provides convenient access to the component's active locale setting.
2857
+ * @returns {string} The current locale identifier
2858
+ * @memberOf module:lib/engine/NgxDecafComponentDirective
2859
+ */
2696
2860
  get localeContext() {
2697
2861
  return this.getLocale();
2698
2862
  }
2699
2863
  /**
2700
- * @description Getter for the repository instance.
2701
- * @summary Provides a connection to the data layer for retrieving and manipulating data.
2702
- * This method initializes the `_repository` property if it is not already set, ensuring
2703
- * that a single instance of the repository is used throughout the component.
2704
- *
2705
- * The repository is used to perform CRUD operations on the data model, such as fetching data,
2706
- * creating new items, updating existing items, and deleting items. It also provides methods
2707
- * for querying and filtering data based on specific criteria.
2708
- *
2709
- * @returns {DecafRepository<Model>} The initialized repository instance.
2710
- * @private
2711
- * @memberOf NgxDecafComponentDirective
2864
+ * @description Getter for the data repository instance.
2865
+ * @summary Lazily initializes and returns the DecafRepository instance for the current model.
2866
+ * This getter ensures the repository is created only when needed and reused for subsequent
2867
+ * access. It also automatically sets the primary key field if not explicitly configured.
2868
+ * @protected
2869
+ * @returns {DecafRepository<Model>} The repository instance for the current model
2870
+ * @throws {InternalError} If repository initialization fails
2871
+ * @memberOf module:lib/engine/NgxDecafComponentDirective
2712
2872
  */
2713
2873
  get repository() {
2714
2874
  try {
@@ -2725,16 +2885,14 @@ class NgxDecafComponentDirective extends LoggedClass {
2725
2885
  return this._repository;
2726
2886
  }
2727
2887
  /**
2728
- * @description Handles changes to component inputs
2729
- * @summary This Angular lifecycle hook is called when input properties change.
2730
- * It responds to changes in the model, locale, or translatable properties by
2731
- * updating the component's internal state accordingly. When the model changes,
2732
- * it calls getModel to process the new model and getLocale to update the locale.
2733
- * When locale or translatable properties change, it calls getLocale to update
2734
- * the translation settings.
2735
- *
2736
- * @param {SimpleChanges} changes - Object containing changed properties
2888
+ * @description Angular lifecycle hook for handling input property changes.
2889
+ * @summary Responds to changes in component input properties, specifically monitoring changes
2890
+ * to the model, locale root, and component name properties. When the model changes, it triggers
2891
+ * model initialization and locale context updates. When locale-related properties change,
2892
+ * it updates the component's locale setting accordingly.
2893
+ * @param {SimpleChanges} changes - Object containing the changed properties with their previous and current values
2737
2894
  * @return {void}
2895
+ * @memberOf module:lib/engine/NgxDecafComponentDirective
2738
2896
  */
2739
2897
  ngOnChanges(changes) {
2740
2898
  if (changes[BaseComponentProps.MODEL]) {
@@ -2746,6 +2904,18 @@ class NgxDecafComponentDirective extends LoggedClass {
2746
2904
  if (changes[BaseComponentProps.LOCALE_ROOT] || changes[BaseComponentProps.COMPONENT_NAME])
2747
2905
  this.locale = this.localeContext;
2748
2906
  }
2907
+ /**
2908
+ * @description Translates text phrases using the translation service.
2909
+ * @summary Provides a promise-based wrapper around the translation service to translate
2910
+ * UI text based on the current locale. Supports both single phrases and arrays of phrases,
2911
+ * and accepts optional parameters for template interpolation. When a string parameter is
2912
+ * provided, it's automatically converted to an object format for the translation service.
2913
+ * @protected
2914
+ * @param {string | string[]} phrase - The translation key or array of keys to translate
2915
+ * @param {object | string} [params] - Optional parameters for interpolation in translated text
2916
+ * @return {Promise<string>} A promise that resolves to the translated text
2917
+ * @memberOf module:lib/engine/NgxDecafComponentDirective
2918
+ */
2749
2919
  translate(phrase, params) {
2750
2920
  return new Promise((resolve) => {
2751
2921
  if (typeof params === Primitives.STRING)
@@ -2753,10 +2923,31 @@ class NgxDecafComponentDirective extends LoggedClass {
2753
2923
  return resolve(firstValueFrom(this.translateService.get(phrase, (params || {}))));
2754
2924
  });
2755
2925
  }
2926
+ /**
2927
+ * @description Initializes the component asynchronously with custom logic.
2928
+ * @summary Abstract initialization method that can be overridden by child components to perform
2929
+ * custom initialization logic. By default, it simply sets the initialized flag to true.
2930
+ * Child components can extend this method to load data, configure settings, or perform
2931
+ * other setup operations required before the component is fully functional.
2932
+ * @protected
2933
+ * @param {...unknown[]} args - Variable number of arguments that can be used by child implementations
2934
+ * @return {Promise<void>} A promise that resolves when initialization is complete
2935
+ * @memberOf module:lib/engine/NgxDecafComponentDirective
2936
+ */
2756
2937
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
2757
2938
  async initialize(...args) {
2758
2939
  this.initialized = true;
2759
2940
  }
2941
+ /**
2942
+ * @description Retrieves or sets the locale context for the component.
2943
+ * @summary Gets the locale identifier from the locale context system. If a locale parameter
2944
+ * is provided, it updates the localeRoot property and resolves the new locale context.
2945
+ * If no locale is currently set, it initializes it from the localeRoot.
2946
+ * @protected
2947
+ * @param {string} [locale] - Optional locale identifier to set
2948
+ * @return {string} The current locale identifier
2949
+ * @memberOf module:lib/engine/NgxDecafComponentDirective
2950
+ */
2760
2951
  getLocale(locale) {
2761
2952
  if (locale || !this.locale) {
2762
2953
  if (locale)
@@ -2766,13 +2957,13 @@ class NgxDecafComponentDirective extends LoggedClass {
2766
2957
  return this.locale;
2767
2958
  }
2768
2959
  /**
2769
- * @description Gets the route for the component
2770
- * @summary Retrieves the route path for the component, generating one based on the model
2771
- * if no route is explicitly set. This method checks if a route is already defined, and if not,
2772
- * it creates a default route based on the model's constructor name. The generated route follows
2773
- * the pattern '/model/{ModelName}'. This is useful for automatic routing in CRUD operations.
2774
- *
2775
- * @return {string} The route path for the component, or empty string if no route is available
2960
+ * @description Retrieves or generates the route path for the component.
2961
+ * @summary Gets the navigation route associated with this component. If no route is explicitly
2962
+ * set and a model is available, it automatically generates a route based on the model's
2963
+ * class name using the pattern `/model/{ModelName}`. Returns an empty string if neither
2964
+ * a route nor a model is available.
2965
+ * @return {string} The route path for this component
2966
+ * @memberOf module:lib/engine/NgxDecafComponentDirective
2776
2967
  */
2777
2968
  getRoute() {
2778
2969
  if (!this.route && this.model instanceof Model)
@@ -2780,14 +2971,15 @@ class NgxDecafComponentDirective extends LoggedClass {
2780
2971
  return this.route || '';
2781
2972
  }
2782
2973
  /**
2783
- * @description Resolves and sets the component's model
2784
- * @summary Processes the provided model parameter, which can be either a Model instance
2785
- * or a string identifier. If a string is provided, it attempts to resolve the actual model
2786
- * from the injectables registry. After resolving the model, it calls setModelDefinitions
2787
- * to configure the component based on the model's metadata.
2788
- *
2789
- * @param {string | Model} model - The model instance or identifier string
2974
+ * @description Resolves and initializes a model from various input formats.
2975
+ * @summary Accepts a model in multiple formats (string name, Model instance, or ModelConstructor)
2976
+ * and resolves it to a Model instance. When a string is provided, it looks up the model
2977
+ * by name in the Model registry. After resolution, it delegates to setModelDefinitions
2978
+ * to complete the model initialization and configuration.
2979
+ * @template M - The model type extending from Model
2980
+ * @param {string | Model | ModelConstructor<M>} model - The model to resolve and initialize
2790
2981
  * @return {void}
2982
+ * @memberOf module:lib/engine/NgxDecafComponentDirective
2791
2983
  */
2792
2984
  getModel(model) {
2793
2985
  if (!(model instanceof Model) && typeof model === Primitives.STRING)
@@ -2795,16 +2987,16 @@ class NgxDecafComponentDirective extends LoggedClass {
2795
2987
  this.setModelDefinitions(this.model);
2796
2988
  }
2797
2989
  /**
2798
- * @description Configures component properties based on model metadata
2799
- * @summary Extracts and applies configuration from the model's decorators to set up
2800
- * the component. This method uses the rendering engine to retrieve decorator metadata
2801
- * from the model, then configures the component's mapper and item properties accordingly.
2802
- * It ensures the route is properly set and merges various properties from the model's
2803
- * metadata into the component's configuration.
2804
- *
2805
- * @param {Model} model - The model to extract configuration from
2806
- * @return {void}
2807
- */
2990
+ * @description Configures component properties based on model decorators and metadata.
2991
+ * @summary Extracts rendering configuration from the model's decorators using the rendering
2992
+ * engine. This includes props, item configuration, and child component definitions. It sets
2993
+ * up the mapper for field transformations, configures the item renderer with appropriate
2994
+ * properties, and establishes the route for navigation. This method bridges the model's
2995
+ * decorator metadata with the component's runtime configuration.
2996
+ * @param {Model} model - The model instance to extract definitions from
2997
+ * @return {void}
2998
+ * @memberOf module:lib/engine/NgxDecafComponentDirective
2999
+ */
2808
3000
  setModelDefinitions(model) {
2809
3001
  if (model instanceof Model) {
2810
3002
  this.getRoute();
@@ -2830,33 +3022,34 @@ class NgxDecafComponentDirective extends LoggedClass {
2830
3022
  * component instance. This allows for dynamic property assignment based on configuration
2831
3023
  * stored in the props object, enabling flexible component customization without requiring
2832
3024
  * explicit property binding for every possible configuration option.
2833
- *
2834
3025
  * The method performs a safe property assignment by checking if each key from the instance
2835
3026
  * exists in the props object before applying it. This prevents accidental property
2836
3027
  * overwriting and ensures only intended properties are modified.
2837
- *
2838
3028
  * @param {KeyValue} instance - The component instance object to process
3029
+ * @param {string[]} [skip=[]] - Array of property names to skip during parsing
2839
3030
  * @return {void}
2840
- *
2841
3031
  * @mermaid
2842
3032
  * sequenceDiagram
2843
3033
  * participant C as Component
2844
- * participant B as NgxBaseComponentDirective
3034
+ * participant D as NgxDecafComponentDirective
2845
3035
  * participant P as Props Object
2846
3036
  *
2847
- * C->>B: parseProps(instance)
2848
- * B->>B: Get Object.keys(instance)
3037
+ * C->>D: parseProps(instance, skip)
3038
+ * D->>D: Get Object.keys(instance)
2849
3039
  * loop For each key in instance
2850
- * B->>P: Check if key exists in this.props
2851
- * alt Key exists in props
2852
- * B->>B: Set this[key] = this.props[key]
2853
- * else Key not in props
2854
- * Note over B: Skip this key
3040
+ * D->>D: Check if key in skip array
3041
+ * alt Key not in skip
3042
+ * D->>P: Check if key exists in this.props
3043
+ * alt Key exists in props
3044
+ * D->>D: Set this[key] = this.props[key]
3045
+ * D->>P: delete this.props[key]
3046
+ * else Key not in props
3047
+ * Note over D: Skip this key
3048
+ * end
2855
3049
  * end
2856
3050
  * end
2857
- *
2858
3051
  * @protected
2859
- * @memberOf NgxBaseComponentDirective
3052
+ * @memberOf module:lib/engine/NgxDecafComponentDirective
2860
3053
  */
2861
3054
  parseProps(instance, skip = []) {
2862
3055
  Object.keys(instance).forEach((key) => {
@@ -2867,21 +3060,55 @@ class NgxDecafComponentDirective extends LoggedClass {
2867
3060
  });
2868
3061
  }
2869
3062
  /**
2870
- * @description Tracks items in ngFor loops for optimal change detection.
3063
+ * @description Tracks items in ngFor loops for optimal change detection performance.
2871
3064
  * @summary Provides a tracking function for Angular's *ngFor directive to optimize rendering
2872
3065
  * performance. This method generates unique identifiers for list items based on their index
2873
3066
  * and content, allowing Angular to efficiently track changes and minimize DOM manipulations
2874
3067
  * during list updates. The tracking function is essential for maintaining component state
2875
3068
  * and preventing unnecessary re-rendering of unchanged items.
2876
- *
3069
+ * @protected
2877
3070
  * @param {number} index - The index of the item in the list
2878
3071
  * @param {KeyValue | string | number} item - The item data to track
2879
- * @returns {string | number} A unique identifier for the item
2880
- * @memberOf NgxDecafComponentDirective
3072
+ * @return {string | number} A unique identifier for the item
3073
+ * @memberOf module:lib/engine/NgxDecafComponentDirective
2881
3074
  */
2882
3075
  trackItemFn(index, item) {
2883
3076
  return `${index}-${item}`;
2884
3077
  }
3078
+ /**
3079
+ * @description Handles custom events from child components or DOM elements.
3080
+ * @summary Processes custom events by extracting event handlers and delegating to appropriate
3081
+ * handler classes. Supports both CustomEvent format with detail property and direct event
3082
+ * objects. If specific handlers are defined in the event, it instantiates the handler class
3083
+ * and invokes its handle method. If no handler is found or defined, the event is emitted
3084
+ * up the component hierarchy via the listenEvent output.
3085
+ * @param {IBaseCustomEvent | ICrudFormEvent | CustomEvent} event - The event to handle
3086
+ * @return {Promise<void>} A promise that resolves when event handling is complete
3087
+ * @mermaid
3088
+ * sequenceDiagram
3089
+ * participant C as Child Component
3090
+ * participant D as NgxDecafComponentDirective
3091
+ * participant H as Event Handler
3092
+ * participant P as Parent Component
3093
+ *
3094
+ * C->>D: handleEvent(event)
3095
+ * alt Event is CustomEvent
3096
+ * D->>D: Extract event.detail
3097
+ * end
3098
+ * D->>D: Get event name and handlers
3099
+ * alt Handlers defined
3100
+ * alt Handler exists for event
3101
+ * D->>H: new Handler(router)
3102
+ * D->>H: handle(event)
3103
+ * H-->>D: return result
3104
+ * else No handler found
3105
+ * D->>D: log.debug("No handler found")
3106
+ * end
3107
+ * else No handlers
3108
+ * D->>P: listenEvent.emit(event)
3109
+ * end
3110
+ * @memberOf module:lib/engine/NgxDecafComponentDirective
3111
+ */
2885
3112
  async handleEvent(event) {
2886
3113
  let name = "";
2887
3114
  const log = this.log.for(this.handleEvent);
@@ -2908,8 +3135,70 @@ class NgxDecafComponentDirective extends LoggedClass {
2908
3135
  }
2909
3136
  this.listenEvent.emit(event);
2910
3137
  }
3138
+ /**
3139
+ * @description Determines if a specific operation is allowed in the current context.
3140
+ * @summary This method checks if an operation is included in the list of available
3141
+ * CRUD operations and if it's not the current operation (unless the current operation
3142
+ * is CREATE). This is used to enable/disable or show/hide operation buttons in the UI.
3143
+ * Returns false if the operations array is undefined or the operation is not in the list.
3144
+ * @param {string} operation - The operation to check
3145
+ * @return {boolean} True if the operation is allowed, false otherwise
3146
+ * @mermaid
3147
+ * sequenceDiagram
3148
+ * participant D as NgxDecafComponentDirective
3149
+ * participant U as UI
3150
+ *
3151
+ * U->>D: isAllowed(operation)
3152
+ * alt operations is undefined
3153
+ * D-->>U: Return false
3154
+ * else
3155
+ * D->>D: Check if operation is in operations
3156
+ * D->>D: Check if operation is not current operation
3157
+ * D-->>U: Return result
3158
+ * end
3159
+ * @memberOf module:lib/engine/NgxDecafComponentDirective
3160
+ */
3161
+ isAllowed(operation) {
3162
+ if (!this.operations)
3163
+ return false;
3164
+ return this.operations.includes(operation) && (this.operation !== OperationKeys.CREATE && ((this.operation || "").toLowerCase() !== operation || !this.operation));
3165
+ }
3166
+ /**
3167
+ * @description Navigates to a different operation for the current model.
3168
+ * @summary This method constructs a navigation URL based on the component's base route,
3169
+ * the requested operation, and optionally a model ID. It then uses the Angular router
3170
+ * service to navigate to the constructed URL. This is typically used when switching
3171
+ * between different CRUD operations (create, read, update, delete) on a model.
3172
+ * The URL format is: {route}/{operation}/{id?}
3173
+ * @param {string} operation - The operation to navigate to (e.g., 'create', 'read', 'update', 'delete')
3174
+ * @param {string} [id] - Optional model ID to include in the navigation URL
3175
+ * @return {Promise<boolean>} A promise that resolves to true if navigation was successful
3176
+ * @mermaid
3177
+ * sequenceDiagram
3178
+ * participant U as UI
3179
+ * participant D as NgxDecafComponentDirective
3180
+ * participant R as Router
3181
+ *
3182
+ * U->>D: Click operation button
3183
+ * D->>D: changeOperation(operation, id)
3184
+ * D->>D: Construct navigation URL
3185
+ * Note over D: URL: {route}/{operation}/{id?}
3186
+ * D->>R: navigateByUrl(page)
3187
+ * R->>R: Navigate to new route
3188
+ * R-->>D: Return navigation result
3189
+ * D-->>U: Display new operation view
3190
+ * @memberOf module:lib/engine/NgxDecafComponentDirective
3191
+ */
3192
+ async changeOperation(operation, id) {
3193
+ let page = `${this.route}/${operation}/`.replace('//', '/');
3194
+ if (!id)
3195
+ id = this.modelId;
3196
+ if (this.modelId)
3197
+ page = `${page}${this.modelId || id}`;
3198
+ return this.router.navigateByUrl(page);
3199
+ }
2911
3200
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: NgxDecafComponentDirective, deps: [{ token: CPTKN }, { token: CPTKN }], target: i0.ɵɵFactoryTarget.Directive }); }
2912
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.7", type: NgxDecafComponentDirective, isStandalone: true, inputs: { name: "name", childOf: "childOf", uid: "uid", model: "model", modelId: "modelId", pk: "pk", mapper: "mapper", operations: "operations", row: "row", col: "col", className: "className", locale: "locale", item: "item", props: "props", route: "route" }, outputs: { listenEvent: "listenEvent" }, host: { properties: { "attr.id": "uid" } }, viewQueries: [{ propertyName: "component", first: true, predicate: ["component"], descendants: true, read: ElementRef, static: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0 }); }
3201
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.7", type: NgxDecafComponentDirective, isStandalone: true, inputs: { name: "name", childOf: "childOf", uid: "uid", model: "model", modelId: "modelId", pk: "pk", mapper: "mapper", operations: "operations", operation: "operation", row: "row", col: "col", className: "className", locale: "locale", item: "item", props: "props", route: "route" }, outputs: { listenEvent: "listenEvent" }, host: { properties: { "attr.id": "uid" } }, viewQueries: [{ propertyName: "component", first: true, predicate: ["component"], descendants: true, read: ElementRef, static: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0 }); }
2913
3202
  }
2914
3203
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: NgxDecafComponentDirective, decorators: [{
2915
3204
  type: Directive,
@@ -2939,6 +3228,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
2939
3228
  type: Input
2940
3229
  }], operations: [{
2941
3230
  type: Input
3231
+ }], operation: [{
3232
+ type: Input
2942
3233
  }], row: [{
2943
3234
  type: Input
2944
3235
  }], col: [{
@@ -2958,12 +3249,41 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
2958
3249
  }] } });
2959
3250
 
2960
3251
  /**
3252
+ * @module lib/engine/NgxDecafFormFieldDirective
3253
+ * @description Base directive for CRUD form fields in Decaf Angular applications.
3254
+ * @summary Provides the NgxDecafFormFieldDirective abstract class that implements ControlValueAccessor
3255
+ * and FieldProperties to enable form field integration with Angular's reactive forms system.
3256
+ * This directive handles form control lifecycle, validation, multi-entry forms, and CRUD operations.
3257
+ */
3258
+ /**
3259
+ * @description Abstract base directive for CRUD form fields in Angular applications.
3260
+ * @summary Provides the foundation for all form field components in Decaf applications by implementing
3261
+ * Angular's ControlValueAccessor interface and FieldProperties for validation. This directive manages
3262
+ * form control integration, validation state, multi-entry forms (FormArrays), and CRUD operation context.
3263
+ * It handles form group lifecycle, error messaging, change detection, and parent-child form relationships.
3264
+ * Extend this class to create custom form field components that seamlessly integrate with Angular's
3265
+ * reactive forms and Decaf's validation system.
2961
3266
  * @class NgxDecafFormFieldDirective
2962
- * @implements {FieldProperties}
3267
+ * @extends {NgxDecafComponentDirective}
2963
3268
  * @implements {ControlValueAccessor}
2964
- * @summary Abstract class representing a CRUD form field for Angular applications
2965
- * @description This class provides the base implementation for CRUD form fields in Angular,
2966
- * implementing both CrudFormField and ControlValueAccessor interfaces.
3269
+ * @implements {FieldProperties}
3270
+ * @example
3271
+ * ```typescript
3272
+ * @Component({
3273
+ * selector: 'app-text-field',
3274
+ * templateUrl: './text-field.component.html',
3275
+ * providers: [{
3276
+ * provide: NG_VALUE_ACCESSOR,
3277
+ * useExisting: forwardRef(() => TextFieldComponent),
3278
+ * multi: true
3279
+ * }]
3280
+ * })
3281
+ * export class TextFieldComponent extends NgxDecafFormFieldDirective {
3282
+ * constructor() {
3283
+ * super();
3284
+ * }
3285
+ * }
3286
+ * ```
2967
3287
  */
2968
3288
  class NgxDecafFormFieldDirective extends NgxDecafComponentDirective {
2969
3289
  constructor() {
@@ -2973,40 +3293,51 @@ class NgxDecafFormFieldDirective extends NgxDecafComponentDirective {
2973
3293
  * @summary When working with multiple form groups (form arrays), this indicates
2974
3294
  * which form group is currently active or being edited. This is used to manage
2975
3295
  * focus and data binding in multi-entry scenarios.
2976
- *
2977
3296
  * @type {number}
2978
3297
  * @default 0
2979
- * @memberOf NgxDecafFormFieldDirective
3298
+ * @public
2980
3299
  */
2981
3300
  this.activeFormGroupIndex = 0;
3301
+ this.operation = OperationKeys.CREATE;
2982
3302
  /**
2983
- * @description Field mapping configuration.
3303
+ * @description Field mapping configuration for options.
2984
3304
  * @summary Defines how fields from the data model should be mapped to properties used by the component.
2985
3305
  * This allows for flexible data binding between the model and the component's display logic.
2986
- *
3306
+ * Can be either a key-value mapping object or a function that performs the mapping.
2987
3307
  * @type {KeyValue | FunctionLike}
2988
- * @memberOf CrudFieldComponent
3308
+ * @public
2989
3309
  */
2990
3310
  this.optionsMapper = {};
3311
+ /**
3312
+ * @description Flag tracking if validation error event has been dispatched.
3313
+ * @summary Prevents duplicate validation error events from being dispatched.
3314
+ * @type {boolean}
3315
+ * @private
3316
+ */
2991
3317
  this.validationErrorEventDispatched = false;
2992
- // protected constructor() {}
2993
3318
  /**
2994
- * @summary String formatting function
2995
- * @description Provides access to the sf function for error message formatting
2996
- * @prop {function(string, ...string): string} sf - String formatting function
3319
+ * @description String formatting utility function.
3320
+ * @summary Provides access to the sf (string format) function for formatting error messages
3321
+ * and other string templates. Used primarily for localizing and parameterizing validation messages.
3322
+ * @type {function(string, ...string): string}
3323
+ * @public
2997
3324
  */
2998
3325
  this.sf = sf;
2999
3326
  /**
3000
- * @summary Change callback function
3001
- * @description Function called when the field value changes
3002
- * @property {function(): unknown} onChange - onChange event handler
3327
+ * @description Callback function invoked when the field value changes.
3328
+ * @summary Function registered by Angular's forms system through registerOnChange.
3329
+ * Called automatically when the field's value is updated to notify the form of the change.
3330
+ * @type {function(): unknown}
3331
+ * @public
3003
3332
  */
3004
3333
  // eslint-disable-next-line @typescript-eslint/no-empty-function
3005
3334
  this.onChange = () => { };
3006
3335
  /**
3007
- * @summary Touch callback function
3008
- * @description Function called when the field is touched
3009
- * @property {function(): unknown} onTouch - onTouch event handler
3336
+ * @description Callback function invoked when the field is touched.
3337
+ * @summary Function registered by Angular's forms system through registerOnTouched.
3338
+ * Called when the field is blurred or otherwise marked as touched.
3339
+ * @type {function(): unknown}
3340
+ * @public
3010
3341
  */
3011
3342
  // eslint-disable-next-line @typescript-eslint/no-empty-function
3012
3343
  this.onTouch = () => { };
@@ -3016,9 +3347,9 @@ class NgxDecafFormFieldDirective extends NgxDecafComponentDirective {
3016
3347
  * @summary Returns the appropriate FormGroup based on whether this field supports
3017
3348
  * multiple values. For single-value fields, returns the main form group.
3018
3349
  * For multi-value fields, returns the form group at the active index from the parent FormArray.
3019
- *
3020
- * @returns {FormGroup} The currently active FormGroup for this field
3021
- * @memberOf CrudFieldComponent
3350
+ * If no formGroup is set, returns the parent of the formControl.
3351
+ * @return {FormGroup} The currently active FormGroup for this field
3352
+ * @public
3022
3353
  */
3023
3354
  get activeFormGroup() {
3024
3355
  if (!this.formGroup)
@@ -3029,53 +3360,61 @@ class NgxDecafFormFieldDirective extends NgxDecafComponentDirective {
3029
3360
  return this.formGroup;
3030
3361
  }
3031
3362
  return this.formGroup;
3032
- // const formGroup = this.formGroup as FormGroup;
3033
- // try {
3034
- // const root = formGroup.root as FormGroup;
3035
- // return this.multiple
3036
- // ? ((root?.controls?.[this.name] as FormArray)?.at(this.activeFormGroupIndex) as FormGroup)
3037
- // : formGroup;
3038
- // } catch (error: unknown) {
3039
- // this.log.error("Error getting active form group:", error as Error);
3040
- // return formGroup;
3041
- // }
3042
3363
  }
3043
3364
  /**
3044
- * @summary Write value to the field
3045
- * @description Sets the value of the field
3365
+ * @description Writes a value to the form field.
3366
+ * @summary Part of Angular's ControlValueAccessor interface. Sets the field's value
3367
+ * when the form programmatically updates it. This is called by Angular forms when
3368
+ * the model value changes.
3046
3369
  * @param {string} obj - The value to be set
3370
+ * @return {void}
3371
+ * @public
3047
3372
  */
3048
3373
  writeValue(obj) {
3049
3374
  this.value = obj;
3050
3375
  }
3051
3376
  /**
3052
- * @summary Register change callback
3053
- * @description Registers a function to be called when the field value changes
3377
+ * @description Registers the onChange callback function.
3378
+ * @summary Part of Angular's ControlValueAccessor interface. Stores the function
3379
+ * that Angular forms provides to be called when the field value changes.
3054
3380
  * @param {function(): unknown} fn - The function to be called on change
3381
+ * @return {void}
3382
+ * @public
3055
3383
  */
3056
3384
  registerOnChange(fn) {
3057
3385
  this.onChange = fn;
3058
3386
  }
3059
3387
  /**
3060
- * @summary Register touch callback
3061
- * @description Registers a function to be called when the field is touched
3388
+ * @description Registers the onTouched callback function.
3389
+ * @summary Part of Angular's ControlValueAccessor interface. Stores the function
3390
+ * that Angular forms provides to be called when the field is touched/blurred.
3062
3391
  * @param {function(): unknown} fn - The function to be called on touch
3392
+ * @return {void}
3393
+ * @public
3063
3394
  */
3064
3395
  registerOnTouched(fn) {
3065
3396
  this.onTouch = fn;
3066
3397
  }
3067
3398
  /**
3068
- * @summary Set disabled state
3069
- * @description Sets the disabled state of the field
3399
+ * @description Sets the disabled state of the field.
3400
+ * @summary Part of Angular's ControlValueAccessor interface. Called by Angular forms
3401
+ * when the disabled state of the control changes.
3070
3402
  * @param {boolean} isDisabled - Whether the field should be disabled
3403
+ * @return {void}
3404
+ * @public
3071
3405
  */
3072
3406
  setDisabledState(isDisabled) {
3073
3407
  this.disabled = isDisabled;
3074
3408
  }
3075
3409
  /**
3076
- * @summary After view initialization logic
3077
- * @description Performs necessary setup after the view has been initialized
3078
- * @returns {HTMLElement} The parent element of the field
3410
+ * @description Performs setup after the view has been initialized.
3411
+ * @summary Retrieves and returns the parent HTML element based on the current CRUD operation.
3412
+ * For READ and DELETE operations, returns the immediate parent element. For CREATE and UPDATE
3413
+ * operations, finds the parent div element and registers it with the form service.
3414
+ * @return {HTMLElement} The parent element of the field
3415
+ * @throws {RenderingError} If unable to retrieve parent form element for CREATE/UPDATE operations
3416
+ * @throws {InternalError} If the operation is invalid
3417
+ * @public
3079
3418
  */
3080
3419
  afterViewInit() {
3081
3420
  let parent;
@@ -3097,6 +3436,16 @@ class NgxDecafFormFieldDirective extends NgxDecafComponentDirective {
3097
3436
  throw new InternalError(`Invalid operation: ${this.operation}`);
3098
3437
  }
3099
3438
  }
3439
+ /**
3440
+ * @description Angular lifecycle hook for detecting input property changes.
3441
+ * @summary Overrides the parent ngOnChanges to handle changes to activeFormGroupIndex and value.
3442
+ * When activeFormGroupIndex changes in a multiple field scenario, updates the active form group
3443
+ * and form control. When value changes, updates the form control value. Delegates to parent
3444
+ * implementation for initial change detection.
3445
+ * @param {SimpleChanges} changes - Object containing the changed properties
3446
+ * @return {void}
3447
+ * @public
3448
+ */
3100
3449
  ngOnChanges(changes) {
3101
3450
  if (!this.initialized)
3102
3451
  super.ngOnChanges(changes);
@@ -3110,14 +3459,38 @@ class NgxDecafFormFieldDirective extends NgxDecafComponentDirective {
3110
3459
  && (changes['value'].currentValue !== undefined && changes['value'].currentValue !== this.value))
3111
3460
  this.setValue(changes['value'].currentValue);
3112
3461
  }
3462
+ /**
3463
+ * @description Cleanup logic when the component is destroyed.
3464
+ * @summary Unregisters the form group from the form service to prevent memory leaks
3465
+ * and clean up form references.
3466
+ * @return {void}
3467
+ * @public
3468
+ */
3113
3469
  onDestroy() {
3114
3470
  if (this.formGroup)
3115
3471
  NgxDecafFormService.unregister(this.formGroup);
3116
3472
  }
3473
+ /**
3474
+ * @description Sets the value of the form control.
3475
+ * @summary Updates the form control's value and triggers validation. This is used
3476
+ * when the value needs to be programmatically updated from outside the form control.
3477
+ * @param {unknown} value - The value to set
3478
+ * @return {void}
3479
+ * @public
3480
+ */
3117
3481
  setValue(value) {
3118
3482
  this.formControl.setValue(value);
3119
3483
  this.formControl.updateValueAndValidity();
3120
3484
  }
3485
+ /**
3486
+ * @description Retrieves validation error messages for the field.
3487
+ * @summary Checks the form control for validation errors and returns formatted error messages.
3488
+ * If errors exist, dispatches a validation error event to parent accordion components.
3489
+ * Error messages are translated and formatted with relevant field properties.
3490
+ * @param {HTMLElement} parent - The parent HTML element used to find accordion components
3491
+ * @return {string | void} Formatted error message string, or void if no errors
3492
+ * @public
3493
+ */
3121
3494
  getErrors(parent) {
3122
3495
  const formControl = this.formControl;
3123
3496
  if (formControl) {
@@ -3143,12 +3516,15 @@ class NgxDecafFormFieldDirective extends NgxDecafComponentDirective {
3143
3516
  }
3144
3517
  }
3145
3518
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: NgxDecafFormFieldDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
3146
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.7", type: NgxDecafFormFieldDirective, isStandalone: true, inputs: { activeFormGroupIndex: "activeFormGroupIndex", parentComponent: "parentComponent", optionsMapper: "optionsMapper" }, usesInheritance: true, usesOnChanges: true, ngImport: i0 }); }
3519
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.7", type: NgxDecafFormFieldDirective, isStandalone: true, inputs: { activeFormGroupIndex: "activeFormGroupIndex", operation: "operation", parentComponent: "parentComponent", optionsMapper: "optionsMapper" }, usesInheritance: true, usesOnChanges: true, ngImport: i0 }); }
3147
3520
  }
3148
3521
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: NgxDecafFormFieldDirective, decorators: [{
3149
3522
  type: Directive
3150
3523
  }], ctorParameters: () => [], propDecorators: { activeFormGroupIndex: [{
3151
3524
  type: Input
3525
+ }], operation: [{
3526
+ type: Input,
3527
+ args: [{ required: true }]
3152
3528
  }], parentComponent: [{
3153
3529
  type: Input
3154
3530
  }], optionsMapper: [{
@@ -3167,32 +3543,112 @@ class NgxEventHandler extends LoggedClass {
3167
3543
  }
3168
3544
 
3169
3545
  /**
3170
- * @module module:lib/engine/NgxPageDirective
3546
+ * @module lib/engine/NgxPageDirective
3171
3547
  * @description Base page component for Decaf Angular applications.
3172
3548
  * @summary Provides a page-level base class (NgxPageDirective) that extends NgxDecafComponentDirective and
3173
3549
  * offers page-focused utilities such as menu management, title handling and router event hooks.
3174
- *
3175
3550
  * @link {@link NgxPageDirective}
3176
3551
  */
3552
+ /**
3553
+ * @description Base directive for page-level components in Decaf Angular applications.
3554
+ * @summary Abstract directive that provides foundational functionality for page components.
3555
+ * Extends NgxDecafComponentDirective to add page-specific features including menu management,
3556
+ * page title handling, and Ionic lifecycle hooks. This directive serves as the base class for
3557
+ * all page-level components, providing consistent behavior for navigation, routing, and UI state.
3558
+ * @class NgxPageDirective
3559
+ * @extends {NgxDecafComponentDirective}
3560
+ * @memberOf module:lib/engine/NgxPageDirective
3561
+ */
3177
3562
  class NgxPageDirective extends NgxDecafComponentDirective {
3563
+ /**
3564
+ * @description Constructor for NgxPageDirective.
3565
+ * @summary Initializes the page directive with optional locale root and menu visibility settings.
3566
+ * Calls the parent NgxDecafComponentDirective constructor to set up base functionality including
3567
+ * logging, localization, and component identification.
3568
+ * @param {string} [localeRoot] - Optional locale root key for internationalization
3569
+ * @param {boolean} [hasMenu=true] - Whether this page should display the menu
3570
+ * @memberOf module:lib/engine/NgxPageDirective
3571
+ */
3178
3572
  // eslint-disable-next-line @angular-eslint/prefer-inject
3179
3573
  constructor(localeRoot, hasMenu = true) {
3180
3574
  super(localeRoot);
3181
3575
  this.localeRoot = localeRoot;
3182
3576
  this.hasMenu = hasMenu;
3577
+ /**
3578
+ * @description Page title text for the current view.
3579
+ * @summary Stores the title text to be displayed for this page. This can be set dynamically
3580
+ * based on the current route or menu configuration and is used to update the browser's
3581
+ * title bar or page header.
3582
+ * @type {string}
3583
+ * @default ''
3584
+ * @memberOf module:lib/engine/NgxPageDirective
3585
+ */
3183
3586
  this.title = '';
3587
+ /**
3588
+ * @description Menu items array for page navigation.
3589
+ * @summary Contains the collection of menu items available for this page. Each menu item
3590
+ * defines a navigation option with properties like label, URL, icon, and visibility settings.
3591
+ * This array is used to construct the application's navigation menu and can be filtered or
3592
+ * customized per page.
3593
+ * @protected
3594
+ * @type {IMenuItem[]}
3595
+ * @default []
3596
+ * @memberOf module:lib/engine/NgxPageDirective
3597
+ */
3184
3598
  this.menu = [];
3599
+ /**
3600
+ * @description Angular Title service for browser title management.
3601
+ * @summary Injected service that provides control over the browser's document title.
3602
+ * Used to dynamically set the page title based on the current route or active menu item,
3603
+ * improving SEO and user experience.
3604
+ * @protected
3605
+ * @type {Title}
3606
+ * @memberOf module:lib/engine/NgxPageDirective
3607
+ */
3185
3608
  this.titleService = inject(Title);
3186
3609
  }
3187
- async ionViewWillEnter() {
3610
+ /**
3611
+ * @description Ionic lifecycle hook called when the page is about to enter view.
3612
+ * @summary This lifecycle hook is triggered just before the page becomes visible to the user.
3613
+ * It enables or disables the application menu based on the hasMenu property, allowing pages
3614
+ * to control whether the menu should be accessible. This is useful for pages like login screens
3615
+ * where the menu should be hidden.
3616
+ * @return {Promise<void>} A promise that resolves when menu state is updated
3617
+ * @memberOf module:lib/engine/NgxPageDirective
3618
+ */
3619
+ async ngAfterViewInit() {
3620
+ this.router.events.subscribe(async (event) => {
3621
+ if (event instanceof NavigationEnd) {
3622
+ const url = (event?.url || "").replace('/', '');
3623
+ this.hasMenu = url !== "login" && url !== "";
3624
+ this.setPageTitle(url);
3625
+ }
3626
+ if (event instanceof NavigationStart)
3627
+ removeFocusTrap();
3628
+ });
3188
3629
  await this.menuController.enable(this.hasMenu);
3189
3630
  }
3631
+ /**
3632
+ * @description Sets the browser page title based on the current route.
3633
+ * @summary Updates the browser's document title by finding the active menu item that matches
3634
+ * the provided route. If a matching menu item is found, it sets the title using the format
3635
+ * "Decaf For Angular - {menu title or label}". This improves SEO and provides clear context
3636
+ * to users about the current page. If a custom menu array is provided, it uses that instead
3637
+ * of the component's default menu.
3638
+ * @protected
3639
+ * @param {string} route - The current route path to match against menu items
3640
+ * @param {IMenuItem[]} [menu] - Optional custom menu array to search (uses this.menu if not provided)
3641
+ * @return {void}
3642
+ * @memberOf module:lib/engine/NgxPageDirective
3643
+ */
3190
3644
  setPageTitle(route, menu) {
3645
+ if (!route)
3646
+ route = this.router.url.replace('/', '');
3191
3647
  if (menu)
3192
3648
  menu = this.menu;
3193
3649
  const activeMenu = this.menu.find(item => item?.url?.includes(route));
3194
3650
  if (activeMenu)
3195
- this.titleService.setTitle(`Decaf For Angular - ${activeMenu?.title || activeMenu?.label}`);
3651
+ this.titleService.setTitle(`${activeMenu?.title || activeMenu?.label}`);
3196
3652
  }
3197
3653
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: NgxPageDirective, deps: [{ token: CPTKN }, { token: CPTKN }], target: i0.ɵɵFactoryTarget.Directive }); }
3198
3654
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.7", type: NgxPageDirective, isStandalone: true, usesInheritance: true, ngImport: i0 }); }
@@ -3779,7 +4235,6 @@ let CrudFieldComponent = class CrudFieldComponent extends NgxDecafFormFieldDirec
3779
4235
  if (this.optionsMapper) {
3780
4236
  if (this.optionsMapper instanceof Function || typeof this.optionsMapper === 'function') {
3781
4237
  const mapper = this.optionsMapper;
3782
- console.log(this.options);
3783
4238
  this.options = this.options.map((option) => {
3784
4239
  return mapper(option);
3785
4240
  });
@@ -3848,48 +4303,6 @@ let CrudFieldComponent = class CrudFieldComponent extends NgxDecafFormFieldDirec
3848
4303
  return false;
3849
4304
  return this.formControl.value.includes(value);
3850
4305
  }
3851
- /**
3852
- * @description Handles fieldset group creation events from parent fieldsets.
3853
- * @summary Processes events triggered when a new group needs to be added to a fieldset.
3854
- * Validates the current form group, checks for uniqueness if applicable, and either
3855
- * creates a new group or provides validation feedback. Updates the active form group
3856
- * and resets the field for new input after successful creation.
3857
- *
3858
- * @param {CustomEvent} event - The fieldset create group event containing group details
3859
- * @returns {void}
3860
- * @memberOf CrudFieldComponent
3861
- */
3862
- handleFieldsetCreateGroupEvent(event) {
3863
- event.stopImmediatePropagation();
3864
- const { formGroup } = event.detail;
3865
- // const formGroup = this.formGroup as FormGroup;
3866
- // const parentFormGroup = this.formGroup?.parent as FormArray;
3867
- // const isValid = NgxDecafFormService.validateFields(formGroup as FormGroup);
3868
- // const indexToCheck = operation === OperationKeys.CREATE ?
3869
- // index === 0 ? index : parentFormGroup.length - 1 : index;
3870
- // const isUnique = NgxDecafFormService.isUniqueOnGroup(formGroup, indexToCheck, operation || OperationKeys.CREATE);
3871
- // event = new CustomEvent(EventConstants.FIELDSET_ADD_GROUP, {
3872
- // detail: {isValid: isValid && isUnique, value: formGroup.value, formGroup: parentFormGroup, formService: NgxDecafFormService},
3873
- // });
3874
- // component.dispatchEvent(event);
3875
- // if(isValid && isUnique) {
3876
- // const newIndex = parentFormGroup?.length;
3877
- // if(operation === OperationKeys.CREATE) {
3878
- // NgxDecafFormService.addGroupToParent(parentFormGroup?.parent as FormGroup, parent, newIndex);
3879
- // this.activeFormGroup = newIndex;
3880
- // } else {
3881
- // this.activeFormGroup = newIndex - 1;
3882
- // }
3883
- // this.formGroup = this.activeFormGroup;
3884
- // // NgxDecafFormService.reset(this.formGroup as FormGroup);
3885
- // this.formControl = (this.formGroup as FormGroup).get(this.name) as FormControl;
3886
- // // NgxDecafFormService.reset(this.formControl);
3887
- // // this.component.nativeElement.setFocus();
3888
- // } else {
3889
- // if(isUnique)
3890
- // this.component.nativeElement.setFocus();
3891
- // }
3892
- }
3893
4306
  /**
3894
4307
  * @description Handles fieldset group update events from parent fieldsets.
3895
4308
  * @summary Processes events triggered when an existing group needs to be updated.
@@ -3907,31 +4320,8 @@ let CrudFieldComponent = class CrudFieldComponent extends NgxDecafFormFieldDirec
3907
4320
  this.formControl = this.formGroup.get(this.name);
3908
4321
  this.value = this.formControl.value;
3909
4322
  }
3910
- /**
3911
- * @description Handles fieldset group removal events from parent fieldsets.
3912
- * @summary Processes events triggered when a group needs to be removed from a fieldset.
3913
- * Removes the specified group from the form array, updates the active form group index,
3914
- * and refreshes the form references. Dispatches a confirmation event back to the component.
3915
- *
3916
- * @param {CustomEvent} event - The fieldset remove group event containing removal details
3917
- * @returns {void}
3918
- * @memberOf CrudFieldComponent
3919
- */
3920
- handleFieldsetRemoveGroupEvent(event) {
3921
- const { component, index } = event.detail;
3922
- const formArray = this.formGroup?.parent;
3923
- formArray.removeAt(index);
3924
- this.activeFormGroupIndex = formArray.length === 1 ? 0 : formArray.length - 1;
3925
- this.formGroup = this.activeFormGroup;
3926
- this.formControl = this.formGroup.get(this.name);
3927
- this.parentComponent = formArray;
3928
- event = new CustomEvent(EventConstants.FIELDSET_REMOVE_GROUP, {
3929
- detail: { value: true },
3930
- });
3931
- component.dispatchEvent(event);
3932
- }
3933
4323
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: CrudFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
3934
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: CrudFieldComponent, isStandalone: true, selector: "ngx-decaf-crud-field", inputs: { operation: "operation", name: "name", className: "className", path: "path", childOf: "childOf", type: "type", value: "value", disabled: "disabled", label: "label", placeholder: "placeholder", format: "format", hidden: "hidden", max: "max", maxlength: "maxlength", min: "min", minlength: "minlength", pattern: "pattern", readonly: "readonly", required: "required", step: "step", equals: "equals", different: "different", lessThan: "lessThan", lessThanOrEqual: "lessThanOrEqual", greaterThan: "greaterThan", greaterThanOrEqual: "greaterThanOrEqual", alignment: "alignment", checked: "checked", justify: "justify", cancelText: "cancelText", interface: "interface", options: "options", mode: "mode", spellcheck: "spellcheck", inputmode: "inputmode", autocomplete: "autocomplete", fill: "fill", labelPlacement: "labelPlacement", updateOn: "updateOn", formGroup: "formGroup", formControl: "formControl", multiple: "multiple", uid: "uid", page: "page", translatable: "translatable" }, host: { listeners: { "window:fieldsetAddGroupEvent": "handleFieldsetCreateGroupEvent($event)", "window:fieldsetUpdateGroupEvent": "handleFieldsetUpdateGroupEvent($event)", "window:fieldsetRemoveGroupEvent": "handleFieldsetRemoveGroupEvent($event)" }, properties: { "attr.id": "uid", "attr.class": "className" } }, viewQueries: [{ propertyName: "component", first: true, predicate: ["component"], descendants: true, read: ElementRef }], usesInheritance: true, ngImport: i0, template: "@if(operation === 'read' || operation === 'delete') {\n <ng-container #component>\n <div [class]=\"'dcf-input-item ' + operation\">\n <ion-item>\n <ion-label>\n {{ label | translate }}<br />\n @if(value) {\n <ion-text [innerHTML]=\"type === 'password' ? '********' : value\"></ion-text>\n } @else {\n @if(['checkbox', 'radio'].includes(type)) {\n <ion-icon class=\"dcf-margin-small-top\" color=\"primary\" size=\"large\" name=\"checkmark-circle-outline\"></ion-icon>\n } @else {\n <br />\n }\n }\n </ion-label>\n </ion-item>\n </div>\n </ng-container>\n} @else {\n @if(formControl) {\n <ng-container [formGroup]=\"multiple ? activeFormGroup : formControl.parent\">\n <div\n [id]=\"uid\" #container\n [class]=\"'dcf-input-item ' + (operation || 'create')\"\n (createGroupEvent)=\"multiple ? handleFieldsetCreateGroupEvent($event) : ''\"\n [class.dcf-field-required]=\"required\"\n >\n @if(type === 'textarea') {\n <ion-textarea\n [id]=\"name\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [autoGrow]=\"true\"\n [minlength]=\"minlength !== undefined ? minlength : null\"\n [maxlength]=\"maxlength !== undefined ? maxlength : null\"\n [readonly]=\"readonly !== undefined ? readonly : null\"\n [inputmode]=\"inputmode\"\n [spellcheck]=\"spellcheck\"\n [rows]=\"rows\"\n [labelPlacement]=\"labelPlacement\"\n [value]=\"value\"\n [fill]=\"fill\"\n [errorText]=\"getErrors(container)\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [label]=\"label | translate\"\n #component>\n </ion-textarea>\n }\n @else if(type === 'checkbox') {\n @if(!options?.length) {\n <ion-item class=\"dcf-width-1-1\" [hidden]=\"hidden\">\n <ion-checkbox\n [id]=\"name\"\n [mode]=\"mode\"\n [errorText]=\"getErrors(container)\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"left\"\n [value]=\"value\"\n [checked]=\"checked\"\n [readonly]=\"readonly\"\n (ionChange)=\"checked = !checked\"\n [formControlName]=\"name\"\n #component>\n <span>{{label | translate}}</span>\n </ion-checkbox>\n\n </ion-item>\n } @else {\n <div class=\"dcf-checkbox-group\">\n <label class=\"dcf-label\" [for]=\"path\">{{ label | translate }}</label>\n @for(option of options; track trackItemFn($index, option.text)) {\n <ion-item class=\"dcf-width-1-1\" [button]=\"true\">\n <ion-checkbox\n [id]=\"option.text\"\n [mode]=\"mode\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"justify\"\n [value]=\"option.value\"\n [readonly]=\"readonly\"\n [checked]=\"isOptionChecked(option.value)\"\n (ionChange)=\"toggleOptionSelection(option.value, $event)\"\n #component>\n <span>{{ $index + 1 }}. {{ option?.text | translate }}</span>\n </ion-checkbox>\n </ion-item>\n }\n <span class=\"dcf-error\" [innerHTML]=\"getErrors(container)\"></span>\n </div>\n }\n\n }\n @else if(type === 'radio' && options?.length) {\n <ion-radio-group class=\"dcf-width-1-1\" [formControlName]=\"name\" [value]=\"value\" #component>\n <label class=\"dcf-radio-group-label\" [for]=\"path\">{{label | translate}}</label>\n @for(option of options; track $index) {\n <ion-item>\n <ion-radio\n [id]=\"name\"\n [errorText]=\"getErrors(container)\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [alignment]=\"alignment\"\n [justify]=\"justify\"\n [readonly]=\"readonly\"\n [value]=\"option.value\"\n >{{ option?.text | translate }}</ion-radio>\n </ion-item>\n }\n </ion-radio-group>\n }\n @else if(type === 'select') {\n <ion-select\n [id]=\"name\"\n toggleIcon=\"chevron-down-outline\"\n expandedIcon=\"chevron-up-outline\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [label]=\"label | translate\"\n [value]=\"value\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [errorText]=\"getErrors(container)\"\n [interface]=\"interface\" #component>\n @if(options?.length) {\n @for(option of options; track trackItemFn($index, option.text)) {\n aa\n <ion-select-option [value]=\"option.value\">\n {{ option.text | translate }}\n </ion-select-option>\n }\n }\n\n </ion-select>\n }\n @else {\n <ion-input\n [class.required]=\"required\"\n [id]=\"name\"\n [type]=\"type\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [inputmode]=\"inputmode\"\n [labelPlacement]=\"labelPlacement\"\n [minlength]=\"minlength !== undefined ? minlength : null\"\n [maxlength]=\"maxlength !== undefined ? maxlength : null\"\n [readonly]=\"readonly !== undefined ? readonly : null\"\n [max]=\"max !== undefined ? max : null\"\n [min]=\"min !== undefined ? min : null\"\n [pattern]=\"pattern !== undefined ? pattern : null\"\n [step]=\"step !== undefined ? step : null\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [errorText]=\"getErrors(container)\"\n [label]=\"label | translate\" #component />\n }\n </div>\n </ng-container>\n } @else {\n <div>\n <p class=\"dcf-error\">\n {{ 'errors.form.control' | translate:{'0': name} }}\n </p>\n </div>\n }\n\n}\n\n", styles: ["@media (prefers-color-scheme: light){.dcf-input-item.read ion-label,.dcf-input-item.delete ion-label{color:var(--dcf-color-gray-7)!important}.dcf-input-item ion-item{--background-hover: var(--dcf-color-primary);--background-focused: var(--dcf-color-primary);--border-color: var(--dcf-color-gray-2)}ion-checkbox::part(container){border:2px solid var(--dcf-color-primary)}}@media (prefers-color-scheme: dark){.dcf-input-item ion-item{--border-color: var(--dcf-color-gray-6)}}.dcf-input-item.create.checkbox+.checkbox,.dcf-input-item.update.checkbox+.checkbox{margin-top:-.25rem!important}.dcf-input-item.create ion-item,.dcf-input-item.update ion-item{--border-color: transparent}.dcf-input-item.create ion-item.dcf-text-wrap ion-label>*,.dcf-input-item.update ion-item.dcf-text-wrap ion-label>*{white-space:wrap!important;word-break:break-all!important}.dcf-input-item.read,.dcf-input-item.delete{padding:0;margin:0!important}.dcf-input-item.read ion-label,.dcf-input-item.delete ion-label{font-weight:600}.dcf-input-item.read ion-text,.dcf-input-item.delete ion-text{display:block;margin-top:.5rem!important}.dcf-input-item.read ion-item,.dcf-input-item.delete ion-item{--min-height: 30px;margin-bottom:0}.dcf-input-item.read ion-item ion-label,.dcf-input-item.delete ion-item ion-label{margin-top:0!important;margin-bottom:.25rem!important}.dcf-input-item ion-item{--padding-end: 0rem;--padding-start: 0px !important;--padding-top: 0px !important;--background: transparent;--background-hover-opacity: .1;--background-activated-opacity: .15;--background-focused-opacity: .15}.dcf-input-item ion-item span,.dcf-input-item ion-item ion-text{font-weight:400!important;font-size:.925rem;min-height:.5rem!important}.dcf-input-item ion-item span:not(.dcf-display-block),.dcf-input-item ion-item ion-text:not(.dcf-display-block){display:inline-block}.dcf-input-item ion-item span.dcf-display-block,.dcf-input-item ion-item ion-text.dcf-display-block{display:block!important}ion-textarea textarea{scrollbar-width:thin!important;margin-bottom:.5rem!important}ion-select.dcf-select-label-placement-floating::part(label){line-height:1.2rem!important}.dcf-proccessing,.dcf-proccessing *{pointer-events:none;touch-action:none;cursor:text}ion-checkbox{--size: 1.5rem;--checkbox-background-checked: var(--dcf-color-primary);--checkmark-width: 2px}ion-item{--inner-padding-start: .75rem}ion-checkbox::part(container){border-radius:50%;padding:3px}ion-item .dcf-radio-group-label,ion-radio-group .dcf-radio-group-label{font-weight:600}ion-item .dcf-radio-group-label~ion-item,ion-radio-group .dcf-radio-group-label~ion-item{margin-top:.5rem;--inner-padding-start: .75rem}ion-item+.dcf-helper,ion-radio-group+.dcf-helper{padding-left:.75rem;position:relative}.dcf-checkbox-group .dcf-label{font-weight:600}.dcf-checkbox-group .dcf-label~ion-item{margin-top:.5rem;--inner-padding-start: .75rem}.dcf-checkbox-group+.dcf-helper{padding-left:.75rem;position:relative}.dcf-error{position:absolute;color:var(--dcf-color-danger)!important;font-size:.8rem!important;font-weight:600!important;line-height:1.1rem;box-sizing:border-box;z-index:9999;margin-top:0;animation-duration:.1s;animation-timing-function:ease-out;animation-fill-mode:both;animation-name:fadeTopSmallAnimation;display:flex;align-items:flex-start;gap:.25rem}.dcf-error .ti,.dcf-error ion-icon{position:relative;top:2px!important;min-width:20px;font-size:1rem!important;text-align:left}.dcf-helper{font-size:.875rem!important;font-weight:500;margin-top:.25rem;margin-bottom:-.75rem}.dcf-helper.dcf-has-action{cursor:pointer;color:var(--dcf-color-gray-7)!important;text-decoration:underline}.dcf-error+.dcf-helper{padding-top:1rem}@keyframes fadeTopSmallAnimation{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeBottomSmallAnimation{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeTopMediumAnimation{0%{opacity:0;transform:translateY(-50px)}to{opacity:1;transform:translateY(0)}}::ng-deep ion-textarea{min-height:80px!important;scrollbar-color:#888 #f0f0f0;scrollbar-width:thin}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.MinLengthValidator, selector: "[minlength][formControlName],[minlength][formControl],[minlength][ngModel]", inputs: ["minlength"] }, { kind: "directive", type: i1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: IonInput, selector: "ion-input", inputs: ["accept", "autocapitalize", "autocomplete", "autocorrect", "autofocus", "clearInput", "clearOnEdit", "color", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "max", "maxlength", "min", "minlength", "mode", "multiple", "name", "pattern", "placeholder", "readonly", "required", "shape", "size", "spellcheck", "step", "type", "value"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonCheckbox, selector: "ion-checkbox", inputs: ["checked", "color", "disabled", "errorText", "helperText", "indeterminate", "justify", "labelPlacement", "mode", "name", "value"] }, { kind: "component", type: IonRadioGroup, selector: "ion-radio-group", inputs: ["allowEmptySelection", "compareWith", "errorText", "helperText", "name", "value"] }, { kind: "component", type: IonRadio, selector: "ion-radio", inputs: ["alignment", "color", "disabled", "justify", "labelPlacement", "mode", "name", "value"] }, { kind: "component", type: IonSelect, selector: "ion-select", inputs: ["cancelText", "color", "compareWith", "disabled", "errorText", "expandedIcon", "fill", "helperText", "interface", "interfaceOptions", "justify", "label", "labelPlacement", "mode", "multiple", "name", "okText", "placeholder", "selectedText", "shape", "toggleIcon", "value"] }, { kind: "component", type: IonSelectOption, selector: "ion-select-option", inputs: ["disabled", "value"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonTextarea, selector: "ion-textarea", inputs: ["autoGrow", "autocapitalize", "autofocus", "clearOnEdit", "color", "cols", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "maxlength", "minlength", "mode", "name", "placeholder", "readonly", "required", "rows", "shape", "spellcheck", "value", "wrap"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
4324
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: CrudFieldComponent, isStandalone: true, selector: "ngx-decaf-crud-field", inputs: { operation: "operation", name: "name", className: "className", path: "path", childOf: "childOf", type: "type", value: "value", disabled: "disabled", label: "label", placeholder: "placeholder", format: "format", hidden: "hidden", max: "max", maxlength: "maxlength", min: "min", minlength: "minlength", pattern: "pattern", readonly: "readonly", required: "required", step: "step", equals: "equals", different: "different", lessThan: "lessThan", lessThanOrEqual: "lessThanOrEqual", greaterThan: "greaterThan", greaterThanOrEqual: "greaterThanOrEqual", alignment: "alignment", checked: "checked", justify: "justify", cancelText: "cancelText", interface: "interface", options: "options", mode: "mode", spellcheck: "spellcheck", inputmode: "inputmode", autocomplete: "autocomplete", fill: "fill", labelPlacement: "labelPlacement", updateOn: "updateOn", formGroup: "formGroup", formControl: "formControl", multiple: "multiple", uid: "uid", page: "page", translatable: "translatable" }, host: { listeners: { "window:fieldsetUpdateGroupEvent": "handleFieldsetUpdateGroupEvent($event)" }, properties: { "attr.id": "uid", "attr.class": "className" } }, viewQueries: [{ propertyName: "component", first: true, predicate: ["component"], descendants: true, read: ElementRef }], usesInheritance: true, ngImport: i0, template: "@if(operation === 'read' || operation === 'delete') {\n <ng-container #component>\n <div [class]=\"'dcf-input-item ' + operation\">\n <ion-item>\n <ion-label>\n {{ label | translate }}<br />\n @if(value) {\n <ion-text [innerHTML]=\"type === 'password' ? '********' : value\"></ion-text>\n } @else {\n @if(['checkbox', 'radio'].includes(type)) {\n <ion-icon class=\"dcf-margin-small-top\" color=\"primary\" size=\"large\" name=\"checkmark-circle-outline\"></ion-icon>\n } @else {\n <br />\n }\n }\n </ion-label>\n </ion-item>\n </div>\n </ng-container>\n} @else {\n @if(formControl) {\n <ng-container [formGroup]=\"multiple ? activeFormGroup : formControl.parent\">\n <div\n [id]=\"uid\" #container\n [class]=\"'dcf-input-item ' + (operation || 'create')\"\n (createGroupEvent)=\"multiple ? handleFieldsetCreateGroupEvent($event) : ''\"\n [class.dcf-field-required]=\"required\"\n >\n @if(type === 'textarea') {\n <ion-textarea\n [id]=\"name\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [autoGrow]=\"true\"\n [minlength]=\"minlength !== undefined ? minlength : null\"\n [maxlength]=\"maxlength !== undefined ? maxlength : null\"\n [readonly]=\"readonly !== undefined ? readonly : null\"\n [inputmode]=\"inputmode\"\n [spellcheck]=\"spellcheck\"\n [rows]=\"rows\"\n [labelPlacement]=\"labelPlacement\"\n [value]=\"value\"\n [fill]=\"fill\"\n [errorText]=\"getErrors(container)\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [label]=\"label | translate\"\n #component>\n </ion-textarea>\n }\n @else if(type === 'checkbox') {\n @if(!options?.length) {\n <ion-item class=\"dcf-width-1-1\" [hidden]=\"hidden\">\n <ion-checkbox\n [id]=\"name\"\n [mode]=\"mode\"\n [errorText]=\"getErrors(container)\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"left\"\n [value]=\"value\"\n [checked]=\"checked\"\n [readonly]=\"readonly\"\n (ionChange)=\"checked = !checked\"\n [formControlName]=\"name\"\n #component>\n <span>{{label | translate}}</span>\n </ion-checkbox>\n\n </ion-item>\n } @else {\n <div class=\"dcf-checkbox-group\">\n <label class=\"dcf-label\" [for]=\"path\">{{ label | translate }}</label>\n @for(option of options; track trackItemFn($index, option.text)) {\n <ion-item class=\"dcf-width-1-1\" [button]=\"true\">\n <ion-checkbox\n [id]=\"option.text\"\n [mode]=\"mode\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"justify\"\n [value]=\"option.value\"\n [readonly]=\"readonly\"\n [checked]=\"isOptionChecked(option.value)\"\n (ionChange)=\"toggleOptionSelection(option.value, $event)\"\n #component>\n <span>{{ $index + 1 }}. {{ option?.text | translate }}</span>\n </ion-checkbox>\n </ion-item>\n }\n <span class=\"dcf-error\" [innerHTML]=\"getErrors(container)\"></span>\n </div>\n }\n\n }\n @else if(type === 'radio' && options?.length) {\n <ion-radio-group class=\"dcf-width-1-1\" [formControlName]=\"name\" [value]=\"value\" #component>\n <label class=\"dcf-radio-group-label\" [for]=\"path\">{{label | translate}}</label>\n @for(option of options; track $index) {\n <ion-item>\n <ion-radio\n [id]=\"name\"\n [errorText]=\"getErrors(container)\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [alignment]=\"alignment\"\n [justify]=\"justify\"\n [readonly]=\"readonly\"\n [value]=\"option.value\"\n >{{ option?.text | translate }}</ion-radio>\n </ion-item>\n }\n </ion-radio-group>\n }\n @else if(type === 'select') {\n <ion-select\n [id]=\"name\"\n toggleIcon=\"chevron-down-outline\"\n expandedIcon=\"chevron-up-outline\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [label]=\"label | translate\"\n [value]=\"value\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [errorText]=\"getErrors(container)\"\n [interface]=\"interface\" #component>\n @if(options?.length) {\n @for(option of options; track trackItemFn($index, option.text)) {\n aa\n <ion-select-option [value]=\"option.value\">\n {{ option.text | translate }}\n </ion-select-option>\n }\n }\n\n </ion-select>\n }\n @else {\n <ion-input\n [class.required]=\"required\"\n [id]=\"name\"\n [type]=\"type\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [inputmode]=\"inputmode\"\n [labelPlacement]=\"labelPlacement\"\n [minlength]=\"minlength !== undefined ? minlength : null\"\n [maxlength]=\"maxlength !== undefined ? maxlength : null\"\n [readonly]=\"readonly !== undefined ? readonly : null\"\n [max]=\"max !== undefined ? max : null\"\n [min]=\"min !== undefined ? min : null\"\n [pattern]=\"pattern !== undefined ? pattern : null\"\n [step]=\"step !== undefined ? step : null\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [errorText]=\"getErrors(container)\"\n [label]=\"label | translate\" #component />\n }\n </div>\n </ng-container>\n } @else {\n <div>\n <p class=\"dcf-error\">\n {{ 'errors.form.control' | translate:{'0': name} }}\n </p>\n </div>\n }\n\n}\n\n", styles: ["@media (prefers-color-scheme: light){.dcf-input-item.read ion-label,.dcf-input-item.delete ion-label{color:var(--dcf-color-gray-7)!important}.dcf-input-item ion-item{--background-hover: var(--dcf-color-primary);--background-focused: var(--dcf-color-primary);--border-color: var(--dcf-color-gray-2)}ion-checkbox::part(container){border:2px solid var(--dcf-color-primary)}}@media (prefers-color-scheme: dark){.dcf-input-item ion-item{--border-color: var(--dcf-color-gray-6)}}.dcf-input-item.create.checkbox+.checkbox,.dcf-input-item.update.checkbox+.checkbox{margin-top:-.25rem!important}.dcf-input-item.create ion-item,.dcf-input-item.update ion-item{--border-color: transparent}.dcf-input-item.create ion-item.dcf-text-wrap ion-label>*,.dcf-input-item.update ion-item.dcf-text-wrap ion-label>*{white-space:wrap!important;word-break:break-all!important}.dcf-input-item.read,.dcf-input-item.delete{padding:0;margin:0!important}.dcf-input-item.read ion-label,.dcf-input-item.delete ion-label{font-weight:600}.dcf-input-item.read ion-text,.dcf-input-item.delete ion-text{display:block;margin-top:.5rem!important}.dcf-input-item.read ion-item,.dcf-input-item.delete ion-item{--min-height: 30px;margin-bottom:0}.dcf-input-item.read ion-item ion-label,.dcf-input-item.delete ion-item ion-label{margin-top:0!important;margin-bottom:.25rem!important}.dcf-input-item ion-item{--padding-end: 0rem;--padding-start: 0px !important;--padding-top: 0px !important;--background: transparent;--background-hover-opacity: .1;--background-activated-opacity: .15;--background-focused-opacity: .15}.dcf-input-item ion-item span,.dcf-input-item ion-item ion-text{font-weight:400!important;font-size:.925rem;min-height:.5rem!important}.dcf-input-item ion-item span:not(.dcf-display-block),.dcf-input-item ion-item ion-text:not(.dcf-display-block){display:inline-block}.dcf-input-item ion-item span.dcf-display-block,.dcf-input-item ion-item ion-text.dcf-display-block{display:block!important}ion-textarea textarea{scrollbar-width:thin!important;margin-bottom:.5rem!important}ion-select.dcf-select-label-placement-floating::part(label){line-height:1.2rem!important}.dcf-proccessing,.dcf-proccessing *{pointer-events:none;touch-action:none;cursor:text}ion-checkbox{--size: 1.5rem;--checkbox-background-checked: var(--dcf-color-primary);--checkmark-width: 2px}ion-item{--inner-padding-start: .75rem}ion-checkbox::part(container){border-radius:50%;padding:3px}ion-item .dcf-radio-group-label,ion-radio-group .dcf-radio-group-label{font-weight:600}ion-item .dcf-radio-group-label~ion-item,ion-radio-group .dcf-radio-group-label~ion-item{margin-top:.5rem;--inner-padding-start: .75rem}ion-item+.dcf-helper,ion-radio-group+.dcf-helper{padding-left:.75rem;position:relative}.dcf-checkbox-group{width:100%}.dcf-checkbox-group .dcf-label{font-weight:600}.dcf-checkbox-group .dcf-label~ion-item{margin-top:.5rem;--inner-padding-start: .75rem}.dcf-checkbox-group+.dcf-helper{padding-left:.75rem;position:relative}.dcf-error{position:absolute;color:var(--dcf-color-danger)!important;font-size:.8rem!important;font-weight:600!important;line-height:1.1rem;box-sizing:border-box;z-index:9999;margin-top:0;animation-duration:.1s;animation-timing-function:ease-out;animation-fill-mode:both;animation-name:fadeTopSmallAnimation;display:flex;align-items:flex-start;gap:.25rem}.dcf-error .ti,.dcf-error ion-icon{position:relative;top:2px!important;min-width:20px;font-size:1rem!important;text-align:left}.dcf-helper{font-size:.875rem!important;font-weight:500;margin-top:.25rem;margin-bottom:-.75rem}.dcf-helper.dcf-has-action{cursor:pointer;color:var(--dcf-color-gray-7)!important;text-decoration:underline}.dcf-error+.dcf-helper{padding-top:1rem}@keyframes fadeTopSmallAnimation{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeBottomSmallAnimation{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeTopMediumAnimation{0%{opacity:0;transform:translateY(-50px)}to{opacity:1;transform:translateY(0)}}::ng-deep ion-textarea{min-height:80px!important;scrollbar-color:#888 #f0f0f0;scrollbar-width:thin}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.MinLengthValidator, selector: "[minlength][formControlName],[minlength][formControl],[minlength][ngModel]", inputs: ["minlength"] }, { kind: "directive", type: i1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: IonInput, selector: "ion-input", inputs: ["accept", "autocapitalize", "autocomplete", "autocorrect", "autofocus", "clearInput", "clearOnEdit", "color", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "max", "maxlength", "min", "minlength", "mode", "multiple", "name", "pattern", "placeholder", "readonly", "required", "shape", "size", "spellcheck", "step", "type", "value"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonCheckbox, selector: "ion-checkbox", inputs: ["checked", "color", "disabled", "errorText", "helperText", "indeterminate", "justify", "labelPlacement", "mode", "name", "value"] }, { kind: "component", type: IonRadioGroup, selector: "ion-radio-group", inputs: ["allowEmptySelection", "compareWith", "errorText", "helperText", "name", "value"] }, { kind: "component", type: IonRadio, selector: "ion-radio", inputs: ["alignment", "color", "disabled", "justify", "labelPlacement", "mode", "name", "value"] }, { kind: "component", type: IonSelect, selector: "ion-select", inputs: ["cancelText", "color", "compareWith", "disabled", "errorText", "expandedIcon", "fill", "helperText", "interface", "interfaceOptions", "justify", "label", "labelPlacement", "mode", "multiple", "name", "okText", "placeholder", "selectedText", "shape", "toggleIcon", "value"] }, { kind: "component", type: IonSelectOption, selector: "ion-select-option", inputs: ["disabled", "value"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonTextarea, selector: "ion-textarea", inputs: ["autoGrow", "autocapitalize", "autofocus", "clearOnEdit", "color", "cols", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "maxlength", "minlength", "mode", "name", "placeholder", "readonly", "required", "rows", "shape", "spellcheck", "value", "wrap"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
3935
4325
  };
3936
4326
  CrudFieldComponent = __decorate([
3937
4327
  Dynamic()
@@ -3951,7 +4341,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
3951
4341
  IonLabel,
3952
4342
  IonText,
3953
4343
  IonTextarea
3954
- ], selector: 'ngx-decaf-crud-field', schemas: [CUSTOM_ELEMENTS_SCHEMA], host: { '[attr.id]': 'uid', '[attr.class]': 'className' }, template: "@if(operation === 'read' || operation === 'delete') {\n <ng-container #component>\n <div [class]=\"'dcf-input-item ' + operation\">\n <ion-item>\n <ion-label>\n {{ label | translate }}<br />\n @if(value) {\n <ion-text [innerHTML]=\"type === 'password' ? '********' : value\"></ion-text>\n } @else {\n @if(['checkbox', 'radio'].includes(type)) {\n <ion-icon class=\"dcf-margin-small-top\" color=\"primary\" size=\"large\" name=\"checkmark-circle-outline\"></ion-icon>\n } @else {\n <br />\n }\n }\n </ion-label>\n </ion-item>\n </div>\n </ng-container>\n} @else {\n @if(formControl) {\n <ng-container [formGroup]=\"multiple ? activeFormGroup : formControl.parent\">\n <div\n [id]=\"uid\" #container\n [class]=\"'dcf-input-item ' + (operation || 'create')\"\n (createGroupEvent)=\"multiple ? handleFieldsetCreateGroupEvent($event) : ''\"\n [class.dcf-field-required]=\"required\"\n >\n @if(type === 'textarea') {\n <ion-textarea\n [id]=\"name\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [autoGrow]=\"true\"\n [minlength]=\"minlength !== undefined ? minlength : null\"\n [maxlength]=\"maxlength !== undefined ? maxlength : null\"\n [readonly]=\"readonly !== undefined ? readonly : null\"\n [inputmode]=\"inputmode\"\n [spellcheck]=\"spellcheck\"\n [rows]=\"rows\"\n [labelPlacement]=\"labelPlacement\"\n [value]=\"value\"\n [fill]=\"fill\"\n [errorText]=\"getErrors(container)\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [label]=\"label | translate\"\n #component>\n </ion-textarea>\n }\n @else if(type === 'checkbox') {\n @if(!options?.length) {\n <ion-item class=\"dcf-width-1-1\" [hidden]=\"hidden\">\n <ion-checkbox\n [id]=\"name\"\n [mode]=\"mode\"\n [errorText]=\"getErrors(container)\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"left\"\n [value]=\"value\"\n [checked]=\"checked\"\n [readonly]=\"readonly\"\n (ionChange)=\"checked = !checked\"\n [formControlName]=\"name\"\n #component>\n <span>{{label | translate}}</span>\n </ion-checkbox>\n\n </ion-item>\n } @else {\n <div class=\"dcf-checkbox-group\">\n <label class=\"dcf-label\" [for]=\"path\">{{ label | translate }}</label>\n @for(option of options; track trackItemFn($index, option.text)) {\n <ion-item class=\"dcf-width-1-1\" [button]=\"true\">\n <ion-checkbox\n [id]=\"option.text\"\n [mode]=\"mode\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"justify\"\n [value]=\"option.value\"\n [readonly]=\"readonly\"\n [checked]=\"isOptionChecked(option.value)\"\n (ionChange)=\"toggleOptionSelection(option.value, $event)\"\n #component>\n <span>{{ $index + 1 }}. {{ option?.text | translate }}</span>\n </ion-checkbox>\n </ion-item>\n }\n <span class=\"dcf-error\" [innerHTML]=\"getErrors(container)\"></span>\n </div>\n }\n\n }\n @else if(type === 'radio' && options?.length) {\n <ion-radio-group class=\"dcf-width-1-1\" [formControlName]=\"name\" [value]=\"value\" #component>\n <label class=\"dcf-radio-group-label\" [for]=\"path\">{{label | translate}}</label>\n @for(option of options; track $index) {\n <ion-item>\n <ion-radio\n [id]=\"name\"\n [errorText]=\"getErrors(container)\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [alignment]=\"alignment\"\n [justify]=\"justify\"\n [readonly]=\"readonly\"\n [value]=\"option.value\"\n >{{ option?.text | translate }}</ion-radio>\n </ion-item>\n }\n </ion-radio-group>\n }\n @else if(type === 'select') {\n <ion-select\n [id]=\"name\"\n toggleIcon=\"chevron-down-outline\"\n expandedIcon=\"chevron-up-outline\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [label]=\"label | translate\"\n [value]=\"value\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [errorText]=\"getErrors(container)\"\n [interface]=\"interface\" #component>\n @if(options?.length) {\n @for(option of options; track trackItemFn($index, option.text)) {\n aa\n <ion-select-option [value]=\"option.value\">\n {{ option.text | translate }}\n </ion-select-option>\n }\n }\n\n </ion-select>\n }\n @else {\n <ion-input\n [class.required]=\"required\"\n [id]=\"name\"\n [type]=\"type\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [inputmode]=\"inputmode\"\n [labelPlacement]=\"labelPlacement\"\n [minlength]=\"minlength !== undefined ? minlength : null\"\n [maxlength]=\"maxlength !== undefined ? maxlength : null\"\n [readonly]=\"readonly !== undefined ? readonly : null\"\n [max]=\"max !== undefined ? max : null\"\n [min]=\"min !== undefined ? min : null\"\n [pattern]=\"pattern !== undefined ? pattern : null\"\n [step]=\"step !== undefined ? step : null\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [errorText]=\"getErrors(container)\"\n [label]=\"label | translate\" #component />\n }\n </div>\n </ng-container>\n } @else {\n <div>\n <p class=\"dcf-error\">\n {{ 'errors.form.control' | translate:{'0': name} }}\n </p>\n </div>\n }\n\n}\n\n", styles: ["@media (prefers-color-scheme: light){.dcf-input-item.read ion-label,.dcf-input-item.delete ion-label{color:var(--dcf-color-gray-7)!important}.dcf-input-item ion-item{--background-hover: var(--dcf-color-primary);--background-focused: var(--dcf-color-primary);--border-color: var(--dcf-color-gray-2)}ion-checkbox::part(container){border:2px solid var(--dcf-color-primary)}}@media (prefers-color-scheme: dark){.dcf-input-item ion-item{--border-color: var(--dcf-color-gray-6)}}.dcf-input-item.create.checkbox+.checkbox,.dcf-input-item.update.checkbox+.checkbox{margin-top:-.25rem!important}.dcf-input-item.create ion-item,.dcf-input-item.update ion-item{--border-color: transparent}.dcf-input-item.create ion-item.dcf-text-wrap ion-label>*,.dcf-input-item.update ion-item.dcf-text-wrap ion-label>*{white-space:wrap!important;word-break:break-all!important}.dcf-input-item.read,.dcf-input-item.delete{padding:0;margin:0!important}.dcf-input-item.read ion-label,.dcf-input-item.delete ion-label{font-weight:600}.dcf-input-item.read ion-text,.dcf-input-item.delete ion-text{display:block;margin-top:.5rem!important}.dcf-input-item.read ion-item,.dcf-input-item.delete ion-item{--min-height: 30px;margin-bottom:0}.dcf-input-item.read ion-item ion-label,.dcf-input-item.delete ion-item ion-label{margin-top:0!important;margin-bottom:.25rem!important}.dcf-input-item ion-item{--padding-end: 0rem;--padding-start: 0px !important;--padding-top: 0px !important;--background: transparent;--background-hover-opacity: .1;--background-activated-opacity: .15;--background-focused-opacity: .15}.dcf-input-item ion-item span,.dcf-input-item ion-item ion-text{font-weight:400!important;font-size:.925rem;min-height:.5rem!important}.dcf-input-item ion-item span:not(.dcf-display-block),.dcf-input-item ion-item ion-text:not(.dcf-display-block){display:inline-block}.dcf-input-item ion-item span.dcf-display-block,.dcf-input-item ion-item ion-text.dcf-display-block{display:block!important}ion-textarea textarea{scrollbar-width:thin!important;margin-bottom:.5rem!important}ion-select.dcf-select-label-placement-floating::part(label){line-height:1.2rem!important}.dcf-proccessing,.dcf-proccessing *{pointer-events:none;touch-action:none;cursor:text}ion-checkbox{--size: 1.5rem;--checkbox-background-checked: var(--dcf-color-primary);--checkmark-width: 2px}ion-item{--inner-padding-start: .75rem}ion-checkbox::part(container){border-radius:50%;padding:3px}ion-item .dcf-radio-group-label,ion-radio-group .dcf-radio-group-label{font-weight:600}ion-item .dcf-radio-group-label~ion-item,ion-radio-group .dcf-radio-group-label~ion-item{margin-top:.5rem;--inner-padding-start: .75rem}ion-item+.dcf-helper,ion-radio-group+.dcf-helper{padding-left:.75rem;position:relative}.dcf-checkbox-group .dcf-label{font-weight:600}.dcf-checkbox-group .dcf-label~ion-item{margin-top:.5rem;--inner-padding-start: .75rem}.dcf-checkbox-group+.dcf-helper{padding-left:.75rem;position:relative}.dcf-error{position:absolute;color:var(--dcf-color-danger)!important;font-size:.8rem!important;font-weight:600!important;line-height:1.1rem;box-sizing:border-box;z-index:9999;margin-top:0;animation-duration:.1s;animation-timing-function:ease-out;animation-fill-mode:both;animation-name:fadeTopSmallAnimation;display:flex;align-items:flex-start;gap:.25rem}.dcf-error .ti,.dcf-error ion-icon{position:relative;top:2px!important;min-width:20px;font-size:1rem!important;text-align:left}.dcf-helper{font-size:.875rem!important;font-weight:500;margin-top:.25rem;margin-bottom:-.75rem}.dcf-helper.dcf-has-action{cursor:pointer;color:var(--dcf-color-gray-7)!important;text-decoration:underline}.dcf-error+.dcf-helper{padding-top:1rem}@keyframes fadeTopSmallAnimation{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeBottomSmallAnimation{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeTopMediumAnimation{0%{opacity:0;transform:translateY(-50px)}to{opacity:1;transform:translateY(0)}}::ng-deep ion-textarea{min-height:80px!important;scrollbar-color:#888 #f0f0f0;scrollbar-width:thin}\n"] }]
4344
+ ], selector: 'ngx-decaf-crud-field', schemas: [CUSTOM_ELEMENTS_SCHEMA], host: { '[attr.id]': 'uid', '[attr.class]': 'className' }, template: "@if(operation === 'read' || operation === 'delete') {\n <ng-container #component>\n <div [class]=\"'dcf-input-item ' + operation\">\n <ion-item>\n <ion-label>\n {{ label | translate }}<br />\n @if(value) {\n <ion-text [innerHTML]=\"type === 'password' ? '********' : value\"></ion-text>\n } @else {\n @if(['checkbox', 'radio'].includes(type)) {\n <ion-icon class=\"dcf-margin-small-top\" color=\"primary\" size=\"large\" name=\"checkmark-circle-outline\"></ion-icon>\n } @else {\n <br />\n }\n }\n </ion-label>\n </ion-item>\n </div>\n </ng-container>\n} @else {\n @if(formControl) {\n <ng-container [formGroup]=\"multiple ? activeFormGroup : formControl.parent\">\n <div\n [id]=\"uid\" #container\n [class]=\"'dcf-input-item ' + (operation || 'create')\"\n (createGroupEvent)=\"multiple ? handleFieldsetCreateGroupEvent($event) : ''\"\n [class.dcf-field-required]=\"required\"\n >\n @if(type === 'textarea') {\n <ion-textarea\n [id]=\"name\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [autoGrow]=\"true\"\n [minlength]=\"minlength !== undefined ? minlength : null\"\n [maxlength]=\"maxlength !== undefined ? maxlength : null\"\n [readonly]=\"readonly !== undefined ? readonly : null\"\n [inputmode]=\"inputmode\"\n [spellcheck]=\"spellcheck\"\n [rows]=\"rows\"\n [labelPlacement]=\"labelPlacement\"\n [value]=\"value\"\n [fill]=\"fill\"\n [errorText]=\"getErrors(container)\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [label]=\"label | translate\"\n #component>\n </ion-textarea>\n }\n @else if(type === 'checkbox') {\n @if(!options?.length) {\n <ion-item class=\"dcf-width-1-1\" [hidden]=\"hidden\">\n <ion-checkbox\n [id]=\"name\"\n [mode]=\"mode\"\n [errorText]=\"getErrors(container)\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"left\"\n [value]=\"value\"\n [checked]=\"checked\"\n [readonly]=\"readonly\"\n (ionChange)=\"checked = !checked\"\n [formControlName]=\"name\"\n #component>\n <span>{{label | translate}}</span>\n </ion-checkbox>\n\n </ion-item>\n } @else {\n <div class=\"dcf-checkbox-group\">\n <label class=\"dcf-label\" [for]=\"path\">{{ label | translate }}</label>\n @for(option of options; track trackItemFn($index, option.text)) {\n <ion-item class=\"dcf-width-1-1\" [button]=\"true\">\n <ion-checkbox\n [id]=\"option.text\"\n [mode]=\"mode\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"justify\"\n [value]=\"option.value\"\n [readonly]=\"readonly\"\n [checked]=\"isOptionChecked(option.value)\"\n (ionChange)=\"toggleOptionSelection(option.value, $event)\"\n #component>\n <span>{{ $index + 1 }}. {{ option?.text | translate }}</span>\n </ion-checkbox>\n </ion-item>\n }\n <span class=\"dcf-error\" [innerHTML]=\"getErrors(container)\"></span>\n </div>\n }\n\n }\n @else if(type === 'radio' && options?.length) {\n <ion-radio-group class=\"dcf-width-1-1\" [formControlName]=\"name\" [value]=\"value\" #component>\n <label class=\"dcf-radio-group-label\" [for]=\"path\">{{label | translate}}</label>\n @for(option of options; track $index) {\n <ion-item>\n <ion-radio\n [id]=\"name\"\n [errorText]=\"getErrors(container)\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [alignment]=\"alignment\"\n [justify]=\"justify\"\n [readonly]=\"readonly\"\n [value]=\"option.value\"\n >{{ option?.text | translate }}</ion-radio>\n </ion-item>\n }\n </ion-radio-group>\n }\n @else if(type === 'select') {\n <ion-select\n [id]=\"name\"\n toggleIcon=\"chevron-down-outline\"\n expandedIcon=\"chevron-up-outline\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [label]=\"label | translate\"\n [value]=\"value\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [errorText]=\"getErrors(container)\"\n [interface]=\"interface\" #component>\n @if(options?.length) {\n @for(option of options; track trackItemFn($index, option.text)) {\n aa\n <ion-select-option [value]=\"option.value\">\n {{ option.text | translate }}\n </ion-select-option>\n }\n }\n\n </ion-select>\n }\n @else {\n <ion-input\n [class.required]=\"required\"\n [id]=\"name\"\n [type]=\"type\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [inputmode]=\"inputmode\"\n [labelPlacement]=\"labelPlacement\"\n [minlength]=\"minlength !== undefined ? minlength : null\"\n [maxlength]=\"maxlength !== undefined ? maxlength : null\"\n [readonly]=\"readonly !== undefined ? readonly : null\"\n [max]=\"max !== undefined ? max : null\"\n [min]=\"min !== undefined ? min : null\"\n [pattern]=\"pattern !== undefined ? pattern : null\"\n [step]=\"step !== undefined ? step : null\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [errorText]=\"getErrors(container)\"\n [label]=\"label | translate\" #component />\n }\n </div>\n </ng-container>\n } @else {\n <div>\n <p class=\"dcf-error\">\n {{ 'errors.form.control' | translate:{'0': name} }}\n </p>\n </div>\n }\n\n}\n\n", styles: ["@media (prefers-color-scheme: light){.dcf-input-item.read ion-label,.dcf-input-item.delete ion-label{color:var(--dcf-color-gray-7)!important}.dcf-input-item ion-item{--background-hover: var(--dcf-color-primary);--background-focused: var(--dcf-color-primary);--border-color: var(--dcf-color-gray-2)}ion-checkbox::part(container){border:2px solid var(--dcf-color-primary)}}@media (prefers-color-scheme: dark){.dcf-input-item ion-item{--border-color: var(--dcf-color-gray-6)}}.dcf-input-item.create.checkbox+.checkbox,.dcf-input-item.update.checkbox+.checkbox{margin-top:-.25rem!important}.dcf-input-item.create ion-item,.dcf-input-item.update ion-item{--border-color: transparent}.dcf-input-item.create ion-item.dcf-text-wrap ion-label>*,.dcf-input-item.update ion-item.dcf-text-wrap ion-label>*{white-space:wrap!important;word-break:break-all!important}.dcf-input-item.read,.dcf-input-item.delete{padding:0;margin:0!important}.dcf-input-item.read ion-label,.dcf-input-item.delete ion-label{font-weight:600}.dcf-input-item.read ion-text,.dcf-input-item.delete ion-text{display:block;margin-top:.5rem!important}.dcf-input-item.read ion-item,.dcf-input-item.delete ion-item{--min-height: 30px;margin-bottom:0}.dcf-input-item.read ion-item ion-label,.dcf-input-item.delete ion-item ion-label{margin-top:0!important;margin-bottom:.25rem!important}.dcf-input-item ion-item{--padding-end: 0rem;--padding-start: 0px !important;--padding-top: 0px !important;--background: transparent;--background-hover-opacity: .1;--background-activated-opacity: .15;--background-focused-opacity: .15}.dcf-input-item ion-item span,.dcf-input-item ion-item ion-text{font-weight:400!important;font-size:.925rem;min-height:.5rem!important}.dcf-input-item ion-item span:not(.dcf-display-block),.dcf-input-item ion-item ion-text:not(.dcf-display-block){display:inline-block}.dcf-input-item ion-item span.dcf-display-block,.dcf-input-item ion-item ion-text.dcf-display-block{display:block!important}ion-textarea textarea{scrollbar-width:thin!important;margin-bottom:.5rem!important}ion-select.dcf-select-label-placement-floating::part(label){line-height:1.2rem!important}.dcf-proccessing,.dcf-proccessing *{pointer-events:none;touch-action:none;cursor:text}ion-checkbox{--size: 1.5rem;--checkbox-background-checked: var(--dcf-color-primary);--checkmark-width: 2px}ion-item{--inner-padding-start: .75rem}ion-checkbox::part(container){border-radius:50%;padding:3px}ion-item .dcf-radio-group-label,ion-radio-group .dcf-radio-group-label{font-weight:600}ion-item .dcf-radio-group-label~ion-item,ion-radio-group .dcf-radio-group-label~ion-item{margin-top:.5rem;--inner-padding-start: .75rem}ion-item+.dcf-helper,ion-radio-group+.dcf-helper{padding-left:.75rem;position:relative}.dcf-checkbox-group{width:100%}.dcf-checkbox-group .dcf-label{font-weight:600}.dcf-checkbox-group .dcf-label~ion-item{margin-top:.5rem;--inner-padding-start: .75rem}.dcf-checkbox-group+.dcf-helper{padding-left:.75rem;position:relative}.dcf-error{position:absolute;color:var(--dcf-color-danger)!important;font-size:.8rem!important;font-weight:600!important;line-height:1.1rem;box-sizing:border-box;z-index:9999;margin-top:0;animation-duration:.1s;animation-timing-function:ease-out;animation-fill-mode:both;animation-name:fadeTopSmallAnimation;display:flex;align-items:flex-start;gap:.25rem}.dcf-error .ti,.dcf-error ion-icon{position:relative;top:2px!important;min-width:20px;font-size:1rem!important;text-align:left}.dcf-helper{font-size:.875rem!important;font-weight:500;margin-top:.25rem;margin-bottom:-.75rem}.dcf-helper.dcf-has-action{cursor:pointer;color:var(--dcf-color-gray-7)!important;text-decoration:underline}.dcf-error+.dcf-helper{padding-top:1rem}@keyframes fadeTopSmallAnimation{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeBottomSmallAnimation{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeTopMediumAnimation{0%{opacity:0;transform:translateY(-50px)}to{opacity:1;transform:translateY(0)}}::ng-deep ion-textarea{min-height:80px!important;scrollbar-color:#888 #f0f0f0;scrollbar-width:thin}\n"] }]
3955
4345
  }], propDecorators: { operation: [{
3956
4346
  type: Input,
3957
4347
  args: [{ required: true }]
@@ -4050,15 +4440,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
4050
4440
  type: Input
4051
4441
  }], translatable: [{
4052
4442
  type: Input
4053
- }], handleFieldsetCreateGroupEvent: [{
4054
- type: HostListener,
4055
- args: ['window:fieldsetAddGroupEvent', ['$event']]
4056
4443
  }], handleFieldsetUpdateGroupEvent: [{
4057
4444
  type: HostListener,
4058
4445
  args: ['window:fieldsetUpdateGroupEvent', ['$event']]
4059
- }], handleFieldsetRemoveGroupEvent: [{
4060
- type: HostListener,
4061
- args: ['window:fieldsetRemoveGroupEvent', ['$event']]
4062
4446
  }] } });
4063
4447
 
4064
4448
  /**
@@ -4079,7 +4463,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
4079
4463
  * @class NgxParentComponentDirective
4080
4464
  * @extends {NgxParentComponentDirective}
4081
4465
  * @implements {OnInit}
4082
- * @memberOf NgxParentComponentDirective
4083
4466
  */
4084
4467
  class NgxParentComponentDirective extends NgxDecafComponentDirective {
4085
4468
  constructor() {
@@ -4092,7 +4475,6 @@ class NgxParentComponentDirective extends NgxDecafComponentDirective {
4092
4475
  * page assignment, and display properties.
4093
4476
  *
4094
4477
  * @type {UIModelMetadata[]}
4095
- * @memberOf NgxParentComponentDirective
4096
4478
  */
4097
4479
  this.children = [];
4098
4480
  /**
@@ -4104,7 +4486,6 @@ class NgxParentComponentDirective extends NgxDecafComponentDirective {
4104
4486
  *
4105
4487
  * @type {(number | string[])}
4106
4488
  * @default 1
4107
- * @memberOf NgxParentComponentDirective
4108
4489
  */
4109
4490
  this.cols = 1;
4110
4491
  /**
@@ -4115,7 +4496,6 @@ class NgxParentComponentDirective extends NgxDecafComponentDirective {
4115
4496
  *
4116
4497
  * @type {(number | string[])}
4117
4498
  * @default 1
4118
- * @memberOf NgxParentComponentDirective
4119
4499
  */
4120
4500
  this.rows = 1;
4121
4501
  }
@@ -4144,17 +4524,6 @@ class NgxFormDirective extends NgxParentComponentDirective {
4144
4524
  constructor() {
4145
4525
  super(...arguments);
4146
4526
  this.crudFieldComponent = ComponentsTagNames.CRUD_FIELD;
4147
- /**
4148
- * @description Angular Location service.
4149
- * @summary Injected service that provides access to the browser's URL and history.
4150
- * This service is used for interacting with the browser's history API, allowing
4151
- * for back navigation and URL manipulation outside of Angular's router.
4152
- *
4153
- * @private
4154
- * @type {Location}
4155
- * @memberOf CrudFormComponent
4156
- */
4157
- this.location = inject(Location);
4158
4527
  /**
4159
4528
  * @description Field update trigger mode for form validation.
4160
4529
  * @summary Determines when form field validation should be triggered. Options include
@@ -4163,7 +4532,6 @@ class NgxFormDirective extends NgxParentComponentDirective {
4163
4532
  *
4164
4533
  * @type {FieldUpdateMode}
4165
4534
  * @default 'change'
4166
- * @memberOf CrudFormComponent
4167
4535
  */
4168
4536
  this.updateOn = 'change';
4169
4537
  /**
@@ -4174,7 +4542,6 @@ class NgxFormDirective extends NgxParentComponentDirective {
4174
4542
  *
4175
4543
  * @type {HTMLFormTarget}
4176
4544
  * @default '_self'
4177
- * @memberOf CrudFormComponent
4178
4545
  */
4179
4546
  this.target = '_self';
4180
4547
  /**
@@ -4185,9 +4552,18 @@ class NgxFormDirective extends NgxParentComponentDirective {
4185
4552
  *
4186
4553
  * @type {'get' | 'post' | 'event'}
4187
4554
  * @default 'event'
4188
- * @memberOf CrudFormComponent
4189
4555
  */
4190
4556
  this.method = 'event';
4557
+ /**
4558
+ * @description The current CRUD operation being performed.
4559
+ * @summary Specifies the type of operation this form is handling (CREATE, READ, UPDATE, DELETE).
4560
+ * This is a required input that determines form behavior, validation rules, and available actions.
4561
+ * The operation affects form state, button visibility, and submission logic.
4562
+ *
4563
+ * @type {CrudOperations}
4564
+ * @required
4565
+ */
4566
+ this.operation = OperationKeys.CREATE;
4191
4567
  /**
4192
4568
  * @description Angular reactive FormGroup for form state management.
4193
4569
  * @summary The FormGroup instance that manages all form controls, validation,
@@ -4195,7 +4571,6 @@ class NgxFormDirective extends NgxParentComponentDirective {
4195
4571
  * controlling form behavior. May be undefined for read-only operations.
4196
4572
  *
4197
4573
  * @type {FormGroup | undefined}
4198
- * @memberOf CrudFormComponent
4199
4574
  */
4200
4575
  this.formGroup = undefined;
4201
4576
  /**
@@ -4205,7 +4580,6 @@ class NgxFormDirective extends NgxParentComponentDirective {
4205
4580
  * components. This enables decoupled handling of form submission logic.
4206
4581
  *
4207
4582
  * @type {EventEmitter<ICrudFormEvent>}
4208
- * @memberOf CrudFormComponent
4209
4583
  */
4210
4584
  this.submitEvent = new EventEmitter();
4211
4585
  /**
@@ -4217,7 +4591,6 @@ class NgxFormDirective extends NgxParentComponentDirective {
4217
4591
  *
4218
4592
  * @type {string}
4219
4593
  * @default Randomly generated 12-character string
4220
- * @memberOf CrudFormComponent
4221
4594
  */
4222
4595
  this.allowClear = true;
4223
4596
  // /**
@@ -4253,18 +4626,6 @@ class NgxFormDirective extends NgxParentComponentDirective {
4253
4626
  // * @memberOf CrudFormComponent
4254
4627
  // */
4255
4628
  // protected translateService: TranslateService = inject(TranslateService);
4256
- /**
4257
- * @description Reference to CRUD operation constants for template usage.
4258
- * @summary Exposes the OperationKeys enum to the component template, enabling
4259
- * conditional rendering and behavior based on operation types. This protected
4260
- * readonly property ensures that template logic can access operation constants
4261
- * while maintaining encapsulation and preventing accidental modification.
4262
- *
4263
- * @protected
4264
- * @readonly
4265
- * @memberOf CrudFormComponent
4266
- */
4267
- this.OperationKeys = OperationKeys;
4268
4629
  this.activeFormGroupIndex = 0;
4269
4630
  }
4270
4631
  get activeFormGroup() {
@@ -4278,13 +4639,13 @@ class NgxFormDirective extends NgxParentComponentDirective {
4278
4639
  * form input. Configuration options are merged with default settings.
4279
4640
  *
4280
4641
  * @returns {Promise<void>}
4281
- * @memberOf CrudFormComponent
4282
4642
  */
4283
4643
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
4284
4644
  async ngOnInit(model) {
4285
4645
  // dont call super.ngOnInit to model conflicts
4286
4646
  if (this.operation === OperationKeys.READ || this.operation === OperationKeys.DELETE)
4287
4647
  this.formGroup = undefined;
4648
+ this.initialized = true;
4288
4649
  }
4289
4650
  /**
4290
4651
  * @description Component cleanup lifecycle method.
@@ -4293,7 +4654,6 @@ class NgxFormDirective extends NgxParentComponentDirective {
4293
4654
  * and ensure proper resource cleanup.
4294
4655
  *
4295
4656
  * @returns {void}
4296
- * @memberOf CrudFormComponent
4297
4657
  */
4298
4658
  ngOnDestroy() {
4299
4659
  if (this.formGroup)
@@ -4331,7 +4691,6 @@ class NgxFormDirective extends NgxParentComponentDirective {
4331
4691
  * since these operations don't have modifiable form data to reset.
4332
4692
  *
4333
4693
  * @returns {void}
4334
- * @memberOf CrudFormComponent
4335
4694
  */
4336
4695
  handleReset() {
4337
4696
  if (![OperationKeys.DELETE, OperationKeys.READ].includes(this.operation) && this.allowClear)
@@ -4555,8 +4914,7 @@ let LayoutComponent = class LayoutComponent extends NgxParentComponentDirective
4555
4914
  * @memberOf LayoutComponent
4556
4915
  */
4557
4916
  constructor() {
4558
- super();
4559
- this.initializeProps = true;
4917
+ super('LayoutComponent');
4560
4918
  /**
4561
4919
  * @description Media breakpoint for responsive behavior.
4562
4920
  * @summary Determines the responsive breakpoint at which the layout should adapt.
@@ -4569,7 +4927,6 @@ let LayoutComponent = class LayoutComponent extends NgxParentComponentDirective
4569
4927
  * @memberOf LayoutComponent
4570
4928
  */
4571
4929
  this.gap = 'collapse';
4572
- this.match = true;
4573
4930
  /**
4574
4931
  * @description Media breakpoint for responsive behavior.
4575
4932
  * @summary Determines the responsive breakpoint at which the layout should adapt.
@@ -4582,7 +4939,30 @@ let LayoutComponent = class LayoutComponent extends NgxParentComponentDirective
4582
4939
  * @memberOf LayoutComponent
4583
4940
  */
4584
4941
  this.breakpoint = UIMediaBreakPoints.MEDIUM;
4585
- this.componentName = 'LayoutComponent';
4942
+ /**
4943
+ * @description Media breakpoint for responsive behavior.
4944
+ * @summary Determines the responsive breakpoint at which the layout should adapt.
4945
+ * This affects how the grid behaves on different screen sizes, allowing for
4946
+ * mobile-first or desktop-first responsive design patterns. The breakpoint
4947
+ * is automatically processed to ensure compatibility with the UI framework.
4948
+ *
4949
+ * @type {UIMediaBreakPointsType}
4950
+ * @default 'medium'
4951
+ * @memberOf LayoutComponent
4952
+ */
4953
+ this.grid = true;
4954
+ /**
4955
+ * @description Media breakpoint for responsive behavior.
4956
+ * @summary Determines the responsive breakpoint at which the layout should adapt.
4957
+ * This affects how the grid behaves on different screen sizes, allowing for
4958
+ * mobile-first or desktop-first responsive design patterns. The breakpoint
4959
+ * is automatically processed to ensure compatibility with the UI framework.
4960
+ *
4961
+ * @type {UIMediaBreakPointsType}
4962
+ * @default 'medium'
4963
+ * @memberOf LayoutComponent
4964
+ */
4965
+ this.match = true;
4586
4966
  }
4587
4967
  /**
4588
4968
  * @description Getter that converts columns input to an array format.
@@ -4617,10 +4997,13 @@ let LayoutComponent = class LayoutComponent extends NgxParentComponentDirective
4617
4997
  if (typeof rows === Primitives.NUMBER)
4618
4998
  rows = Array.from({ length: Number(rows) }, () => ({ title: '' }));
4619
4999
  return rows.map((row, index) => {
5000
+ const rowsLength = this.rows;
4620
5001
  return {
4621
5002
  title: typeof row === Primitives.STRING ? row : row?.['title'] || "",
4622
5003
  cols: this.children.filter((child) => {
4623
- const row = child.props?.['row'] ?? 1;
5004
+ let row = child.props?.['row'] ?? 1;
5005
+ if (row > rowsLength)
5006
+ row = rowsLength;
4624
5007
  child['col'] = child.props?.['col'] ?? this.cols?.length ?? 1;
4625
5008
  if (row === index + 1)
4626
5009
  return child;
@@ -4642,10 +5025,14 @@ let LayoutComponent = class LayoutComponent extends NgxParentComponentDirective
4642
5025
  this.breakpoint = `@${this.breakpoint}`.toLowerCase();
4643
5026
  this.cols = this._cols;
4644
5027
  this.rows = this._rows;
5028
+ // if(this._rows.length === 1)
5029
+ // this.match = false;
5030
+ // if(this._cols.length === 1)
5031
+ // this.grid = false;
4645
5032
  this.initialized = true;
4646
5033
  }
4647
5034
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: LayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4648
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: LayoutComponent, isStandalone: true, selector: "ngx-decaf-layout", inputs: { initializeProps: "initializeProps", gap: "gap", match: "match", breakpoint: "breakpoint" }, usesInheritance: true, ngImport: i0, template: "\n@if(initialized) {\n @for (row of rows; track trackItemFn($index, row); let rowIndex = $index) {\n <div [id]=\"uid\"\n [class]=\"'dcf-grid ' + 'dcf-grid-' + gap\"\n [class.dcf-grid-match]=\"match\"\n\n >\n @if(row?.title?.length) {\n <div class=\"dcf-width-1-1 dcf-grid-title\">\n <ion-card class=\"dcf-grid-title\">\n {{row.title | translate}}\n </ion-card>\n </div>\n }\n @for (child of row.cols; track trackItemFn($index, child.col); let colIndex = $index) {\n <div [class]=\"(child.col === cols.length ? 'dcf-width-1-1' : 'dcf-width-'+child.col+'-'+cols.length+breakpoint)\">\n <div [class]=\"'dcf-grid-child '+child.col \">\n @if(child.tag === 'ngx-decaf-crud-form') {\n <ion-card [class]=\"'dcf-height-1-1 ' + className\">\n <ion-card-content>\n <ngx-decaf-model-renderer\n [model]=\"child.props.name\"\n (listenEvent)=\"handleEvent($event)\"\n />\n </ion-card-content>\n </ion-card>\n } @else {\n <ngx-decaf-component-renderer\n [tag]=\"child.tag\"\n [parentComponent]=\"parentComponent || child.parentComponent || child?.formGroup\"\n [children]=\"child?.children || []\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]=\"{props: child.props}\"\n />\n }\n </div>\n </div>\n }\n </div>\n }\n}\n", styles: [".dcf-grid>div:not(.dcf-grid-title) ::ng-deep ngx-decaf-component-renderer>*>*{height:100%;display:flex;justify-content:center!important;align-items:center!important}.dcf-grid ion-card.dcf-height-1-1>ion-card-content{margin-top:2rem}.dcf-grid.dcf-grid-small .dcf-grid-child{margin-bottom:2rem}.dcf-grid.dcf-grid-collapse .dcf-grid-child{margin-bottom:1.25rem}.dcf-grid.dcf-grid-collapse .dcf-grid-child ion-card{margin-bottom:1.25rem}.dcf-grid-title{font-size:1.05rem!important;background:none;box-shadow:none;margin-bottom:0;padding-bottom:0;font-weight:600;color:var(--dcf-color-dark);display:flex;align-items:center;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}\n"], dependencies: [{ kind: "component", type: ModelRendererComponent, selector: "ngx-decaf-model-renderer", inputs: ["globals", "projectable", "rendererId"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "children", "projectable", "model", "parentComponent", "parent"], outputs: ["listenEvent"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
5035
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: LayoutComponent, isStandalone: true, selector: "ngx-decaf-layout", inputs: { gap: "gap", breakpoint: "breakpoint", grid: "grid", match: "match" }, usesInheritance: true, ngImport: i0, template: "\n@if(initialized) {\n @for (row of rows; track trackItemFn($index, row); let rowIndex = $index) {\n <div [id]=\"uid\"\n [class]=\" !grid ? '' : 'dcf-grid ' + 'dcf-grid-' + gap\"\n [class.dcf-grid-match]=\"match\"\n\n >\n @if(row?.title?.length) {\n <div class=\"dcf-width-1-1 dcf-grid-title\">\n <ion-card class=\"dcf-grid-title\">\n {{row.title | translate}}\n </ion-card>\n </div>\n }\n @for (child of row.cols; track trackItemFn($index, child.col); let colIndex = $index) {\n <div [class]=\"(child.col === cols.length ? 'dcf-width-1-1' : 'dcf-width-'+child.col+'-'+cols.length+breakpoint)\">\n <div [class]=\"'dcf-grid-child '+child.col \">\n @if(child.tag === 'ngx-decaf-crud-form') {\n <ion-card [class]=\"'dcf-height-1-1 ' + className\">\n <ion-card-content>\n <ngx-decaf-model-renderer\n [model]=\"child.props.name\"\n (listenEvent)=\"handleEvent($event)\"\n />\n </ion-card-content>\n </ion-card>\n } @else {\n <ngx-decaf-component-renderer\n [tag]=\"child.tag\"\n [parentComponent]=\"parentComponent || child.parentComponent || child?.formGroup\"\n [children]=\"child?.children || []\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]=\"{props: child.props}\"\n />\n }\n </div>\n </div>\n }\n </div>\n }\n}\n", styles: [".dcf-grid>div:not(.dcf-grid-title) ::ng-deep ngx-decaf-component-renderer>*>*{height:100%;display:flex;justify-content:center!important;align-items:center!important}.dcf-grid ion-card.dcf-height-1-1>ion-card-content{margin-top:2rem}.dcf-grid.dcf-grid-small .dcf-grid-child{margin-bottom:2rem}.dcf-grid.dcf-grid-collapse .dcf-grid-child{margin-bottom:1.25rem}.dcf-grid.dcf-grid-collapse .dcf-grid-child ion-card{margin-bottom:1.25rem}.dcf-grid-title{font-size:1.05rem!important;background:none;box-shadow:none;margin-bottom:0;padding-bottom:0;font-weight:600;color:var(--dcf-color-dark);display:flex;align-items:center;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}\n"], dependencies: [{ kind: "component", type: ModelRendererComponent, selector: "ngx-decaf-model-renderer", inputs: ["globals", "projectable", "rendererId"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "children", "projectable", "model", "parentComponent", "parent"], outputs: ["listenEvent"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
4649
5036
  };
4650
5037
  LayoutComponent = __decorate([
4651
5038
  Dynamic(),
@@ -4653,21 +5040,20 @@ LayoutComponent = __decorate([
4653
5040
  ], LayoutComponent);
4654
5041
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: LayoutComponent, decorators: [{
4655
5042
  type: Component,
4656
- args: [{ selector: 'ngx-decaf-layout', imports: [TranslatePipe, ModelRendererComponent, ComponentRendererComponent], standalone: true, template: "\n@if(initialized) {\n @for (row of rows; track trackItemFn($index, row); let rowIndex = $index) {\n <div [id]=\"uid\"\n [class]=\"'dcf-grid ' + 'dcf-grid-' + gap\"\n [class.dcf-grid-match]=\"match\"\n\n >\n @if(row?.title?.length) {\n <div class=\"dcf-width-1-1 dcf-grid-title\">\n <ion-card class=\"dcf-grid-title\">\n {{row.title | translate}}\n </ion-card>\n </div>\n }\n @for (child of row.cols; track trackItemFn($index, child.col); let colIndex = $index) {\n <div [class]=\"(child.col === cols.length ? 'dcf-width-1-1' : 'dcf-width-'+child.col+'-'+cols.length+breakpoint)\">\n <div [class]=\"'dcf-grid-child '+child.col \">\n @if(child.tag === 'ngx-decaf-crud-form') {\n <ion-card [class]=\"'dcf-height-1-1 ' + className\">\n <ion-card-content>\n <ngx-decaf-model-renderer\n [model]=\"child.props.name\"\n (listenEvent)=\"handleEvent($event)\"\n />\n </ion-card-content>\n </ion-card>\n } @else {\n <ngx-decaf-component-renderer\n [tag]=\"child.tag\"\n [parentComponent]=\"parentComponent || child.parentComponent || child?.formGroup\"\n [children]=\"child?.children || []\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]=\"{props: child.props}\"\n />\n }\n </div>\n </div>\n }\n </div>\n }\n}\n", styles: [".dcf-grid>div:not(.dcf-grid-title) ::ng-deep ngx-decaf-component-renderer>*>*{height:100%;display:flex;justify-content:center!important;align-items:center!important}.dcf-grid ion-card.dcf-height-1-1>ion-card-content{margin-top:2rem}.dcf-grid.dcf-grid-small .dcf-grid-child{margin-bottom:2rem}.dcf-grid.dcf-grid-collapse .dcf-grid-child{margin-bottom:1.25rem}.dcf-grid.dcf-grid-collapse .dcf-grid-child ion-card{margin-bottom:1.25rem}.dcf-grid-title{font-size:1.05rem!important;background:none;box-shadow:none;margin-bottom:0;padding-bottom:0;font-weight:600;color:var(--dcf-color-dark);display:flex;align-items:center;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}\n"] }]
4657
- }], ctorParameters: () => [], propDecorators: { initializeProps: [{
5043
+ args: [{ selector: 'ngx-decaf-layout', imports: [TranslatePipe, ModelRendererComponent, ComponentRendererComponent], standalone: true, template: "\n@if(initialized) {\n @for (row of rows; track trackItemFn($index, row); let rowIndex = $index) {\n <div [id]=\"uid\"\n [class]=\" !grid ? '' : 'dcf-grid ' + 'dcf-grid-' + gap\"\n [class.dcf-grid-match]=\"match\"\n\n >\n @if(row?.title?.length) {\n <div class=\"dcf-width-1-1 dcf-grid-title\">\n <ion-card class=\"dcf-grid-title\">\n {{row.title | translate}}\n </ion-card>\n </div>\n }\n @for (child of row.cols; track trackItemFn($index, child.col); let colIndex = $index) {\n <div [class]=\"(child.col === cols.length ? 'dcf-width-1-1' : 'dcf-width-'+child.col+'-'+cols.length+breakpoint)\">\n <div [class]=\"'dcf-grid-child '+child.col \">\n @if(child.tag === 'ngx-decaf-crud-form') {\n <ion-card [class]=\"'dcf-height-1-1 ' + className\">\n <ion-card-content>\n <ngx-decaf-model-renderer\n [model]=\"child.props.name\"\n (listenEvent)=\"handleEvent($event)\"\n />\n </ion-card-content>\n </ion-card>\n } @else {\n <ngx-decaf-component-renderer\n [tag]=\"child.tag\"\n [parentComponent]=\"parentComponent || child.parentComponent || child?.formGroup\"\n [children]=\"child?.children || []\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]=\"{props: child.props}\"\n />\n }\n </div>\n </div>\n }\n </div>\n }\n}\n", styles: [".dcf-grid>div:not(.dcf-grid-title) ::ng-deep ngx-decaf-component-renderer>*>*{height:100%;display:flex;justify-content:center!important;align-items:center!important}.dcf-grid ion-card.dcf-height-1-1>ion-card-content{margin-top:2rem}.dcf-grid.dcf-grid-small .dcf-grid-child{margin-bottom:2rem}.dcf-grid.dcf-grid-collapse .dcf-grid-child{margin-bottom:1.25rem}.dcf-grid.dcf-grid-collapse .dcf-grid-child ion-card{margin-bottom:1.25rem}.dcf-grid-title{font-size:1.05rem!important;background:none;box-shadow:none;margin-bottom:0;padding-bottom:0;font-weight:600;color:var(--dcf-color-dark);display:flex;align-items:center;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}\n"] }]
5044
+ }], ctorParameters: () => [], propDecorators: { gap: [{
4658
5045
  type: Input
4659
- }], gap: [{
5046
+ }], breakpoint: [{
4660
5047
  type: Input
4661
- }], match: [{
5048
+ }], grid: [{
4662
5049
  type: Input
4663
- }], breakpoint: [{
5050
+ }], match: [{
4664
5051
  type: Input
4665
5052
  }] } });
4666
5053
 
4667
5054
  let CrudFormComponent = class CrudFormComponent extends NgxFormDirective {
4668
5055
  constructor() {
4669
- super();
4670
- this.componentName = 'CrudFormComponent';
5056
+ super('CrudFormComponent');
4671
5057
  }
4672
5058
  /**
4673
5059
  * @description Component initialization lifecycle method.
@@ -4680,7 +5066,6 @@ let CrudFormComponent = class CrudFormComponent extends NgxFormDirective {
4680
5066
  * @memberOf CrudFormComponent
4681
5067
  */
4682
5068
  async ngOnInit() {
4683
- // console.log(this.formGroup);
4684
5069
  this.options = Object.assign({}, DefaultFormReactiveOptions, this.options || {});
4685
5070
  await super.ngOnInit();
4686
5071
  }
@@ -4716,7 +5101,7 @@ let CrudFormComponent = class CrudFormComponent extends NgxFormDirective {
4716
5101
  });
4717
5102
  }
4718
5103
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: CrudFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4719
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: CrudFormComponent, isStandalone: true, selector: "ngx-decaf-crud-form", host: { properties: { "attr.id": "uid" } }, usesInheritance: true, ngImport: i0, template: "@if(operation !== 'read' && operation !== 'delete') {\n <form\n [class]=\"'dcf-grid dcf-grid-small dcf-child-width-1-1 dcf-form-grid ' + operation\" #component\n [id]=\"rendererId\"\n [formGroup]=\"formGroup\"\n (submit)=\"submit($event)\"\n novalidate\n [target]=\"target\">\n @if(!children?.length) {\n <ng-content #formContent></ng-content>\n } @else {\n <ngx-decaf-layout\n [children]=\"children || []\"\n [parentComponent]=\"formGroup || parentComponent\"\n gap=\"small\"\n [initializeProps]=\"false\"\n [rows]=\"rows\"\n [cols]=\"cols\" />\n\n <!-- @for (child of children; track $index) {\n <ngx-decaf-component-renderer\n [class]=\"(child?.props?.className ? 'dcf-form-item ' + child.props.className : 'dcf-form-item')\"\n [tag]=\"child?.tag\"\n [projectable]=\"false\"\n [formRoot]=\"formGroup\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n } -->\n }\n <div class=\"dcf-buttons-grid dcf-grid dcf-grid-collapse dcf-flex dcf-flex-left\">\n <div>\n <ion-button type=\"submit\" [expand]=\"action ? 'block' : 'default'\">\n @if(options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{ action ? action : options.buttons.submit.text}}\n </ion-button>\n </div>\n @if(!action) {\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if(options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n Back\n </ion-button>\n </div>\n }\n </div>\n </form>\n} @else {\n <section [class]=\"'dcf-grid dcf-grid-small dcf-child-width-1-1 dcf-form-grid ' + operation\" #component [id]=\"uid\">\n @if(!children?.length) {\n <ng-content #formContent></ng-content>\n } @else {\n @for (child of children; track $index) {\n <div [class]=\"(child?.props?.className ? 'dcf-form-item ' + child.props.className : 'dcf-form-item')\">\n <ngx-decaf-component-renderer\n [tag]=\"child?.tag\"\n [projectable]=\"false\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n </div>\n }\n }\n </section>\n <section [class]=\"'dcf-buttons-grid dcf-grid dcf-grid-collapse dcf-flex dcf-flex-left ' + operation\" [id]=\"uid\">\n @if(operation === OperationKeys.READ && modelId) {\n <div>\n <ion-button\n (click)=\"handleDelete()\"\n color=\"danger\"\n type=\"button\">\n @if(options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n Delete\n </ion-button>\n </div>\n\n }\n @if(operation === OperationKeys.CREATE || operation === OperationKeys.UPDATE) {\n\n <div>\n <ion-button\n type=\"submit\">\n @if(options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{options.buttons.submit.text}}\n </ion-button>\n </div>\n }\n\n @if(options.buttons.clear) {\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if(options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n {{ [OperationKeys.DELETE, OperationKeys.READ, OperationKeys.UPDATE].includes(operation) ? 'Back' : options.buttons.clear?.text}}\n </ion-button>\n </div>\n\n }\n </section>\n}\n\n", styles: [".dcf-buttons-grid{margin-top:.5rem;margin-bottom:0}.dcf-buttons-grid.read{margin-bottom:1rem}@media (min-width: 577px){.dcf-buttons-grid.dcf-flex{flex-direction:row-reverse}}@media (max-width: 576px){.dcf-buttons-grid.dcf-flex>div{width:100%}.dcf-buttons-grid.dcf-flex>div+div{margin-top:1rem}.dcf-buttons-grid.dcf-flex ion-button{width:100%}}.dcf-form-grid{padding:1rem}.dcf-form-grid .dcf-form-item{margin-bottom:1.8rem;margin-top:0!important}.dcf-form-grid.read .dcf-form-item{margin-bottom:1rem}::ng-deep ngx-decaf-stepped-form .dcf-input-item{margin-bottom:1.8rem;margin-top:0!important}::ng-deep ngx-decaf-fieldset .dcf-input-item{margin-bottom:1.8rem;margin-top:0!important}\n"], dependencies: [{ 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: LayoutComponent, selector: "ngx-decaf-layout", inputs: ["initializeProps", "gap", "match", "breakpoint"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "children", "projectable", "model", "parentComponent", "parent"], outputs: ["listenEvent"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }] }); }
5104
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: CrudFormComponent, isStandalone: true, selector: "ngx-decaf-crud-form", host: { properties: { "attr.id": "uid" } }, usesInheritance: true, ngImport: i0, template: "@if(operation !== 'read' && operation !== 'delete') {\n <form\n [class]=\"'dcf-form-grid ' + operation\" #component\n [id]=\"rendererId\"\n [formGroup]=\"formGroup\"\n (submit)=\"submit($event)\"\n novalidate\n [target]=\"target\">\n @if(!children?.length) {\n <ng-content #formContent></ng-content>\n } @else {\n <ngx-decaf-layout\n [children]=\"children || []\"\n [parentComponent]=\"formGroup || parentComponent\"\n gap=\"small\"\n [rows]=\"rows\"\n [cols]=\"cols\" />\n\n <!-- @for (child of children; track $index) {\n <ngx-decaf-component-renderer\n [class]=\"(child?.props?.className ? 'dcf-form-item ' + child.props.className : 'dcf-form-item')\"\n [tag]=\"child?.tag\"\n [projectable]=\"false\"\n [formRoot]=\"formGroup\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n } -->\n }\n @if(initialized) {\n <div class=\"dcf-buttons-grid dcf-grid dcf-grid-collapse dcf-flex dcf-flex-left\">\n <div>\n <ion-button type=\"submit\" [expand]=\"action ? 'block' : 'default'\">\n @if(options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{ action ? action : options.buttons.submit.text}}\n </ion-button>\n </div>\n @if(!action) {\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if(options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n Back\n </ion-button>\n </div>\n }\n </div>\n }\n\n </form>\n} @else {\n <section [class]=\"'dcf-grid dcf-grid-small dcf-child-width-1-1 dcf-form-grid ' + operation\" #component [id]=\"uid\">\n @if(!children?.length) {\n <ng-content #formContent></ng-content>\n } @else {\n @for (child of children; track $index) {\n <div [class]=\"(child?.props?.className ? 'dcf-form-item ' + child.props.className : 'dcf-form-item')\">\n <ngx-decaf-component-renderer\n [tag]=\"child?.tag\"\n [projectable]=\"false\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n </div>\n }\n }\n </section>\n <section [class]=\"'dcf-buttons-grid dcf-grid dcf-grid-collapse dcf-flex dcf-flex-left ' + operation\" [id]=\"uid\">\n @if(operation === OperationKeys.READ && modelId) {\n <div>\n <ion-button\n (click)=\"handleDelete()\"\n color=\"danger\"\n type=\"button\">\n @if(options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n Delete\n </ion-button>\n </div>\n\n }\n @if(operation === OperationKeys.CREATE || operation === OperationKeys.UPDATE) {\n\n <div>\n <ion-button\n type=\"submit\">\n @if(options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{options.buttons.submit.text}}\n </ion-button>\n </div>\n }\n\n @if(options.buttons.clear) {\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if(options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n {{ [OperationKeys.DELETE, OperationKeys.READ, OperationKeys.UPDATE].includes(operation) ? 'Back' : options.buttons.clear?.text}}\n </ion-button>\n </div>\n\n }\n </section>\n}\n\n", styles: [".dcf-buttons-grid{margin-top:.5rem;margin-bottom:0}.dcf-buttons-grid.read{margin-bottom:1rem}@media (min-width: 577px){.dcf-buttons-grid.dcf-flex{flex-direction:row-reverse}}@media (max-width: 576px){.dcf-buttons-grid.dcf-flex>div{width:100%}.dcf-buttons-grid.dcf-flex>div+div{margin-top:1rem}.dcf-buttons-grid.dcf-flex ion-button{width:100%}}.dcf-form-grid{padding:1rem}.dcf-form-grid .dcf-form-item{margin-bottom:1.8rem;margin-top:0!important}.dcf-form-grid.read .dcf-form-item{margin-bottom:1rem}::ng-deep ngx-decaf-stepped-form .dcf-input-item{margin-bottom:1.8rem;margin-top:0!important}::ng-deep ngx-decaf-fieldset .dcf-input-item{margin-bottom:1.8rem;margin-top:0!important}\n"], dependencies: [{ 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: LayoutComponent, selector: "ngx-decaf-layout", inputs: ["gap", "breakpoint", "grid", "match"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "children", "projectable", "model", "parentComponent", "parent"], outputs: ["listenEvent"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }] }); }
4720
5105
  };
4721
5106
  CrudFormComponent = __decorate([
4722
5107
  Dynamic(),
@@ -4724,7 +5109,7 @@ CrudFormComponent = __decorate([
4724
5109
  ], CrudFormComponent);
4725
5110
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: CrudFormComponent, decorators: [{
4726
5111
  type: Component,
4727
- args: [{ standalone: true, selector: 'ngx-decaf-crud-form', imports: [ReactiveFormsModule, LayoutComponent, ComponentRendererComponent, IonButton, IonIcon], host: { '[attr.id]': 'uid' }, template: "@if(operation !== 'read' && operation !== 'delete') {\n <form\n [class]=\"'dcf-grid dcf-grid-small dcf-child-width-1-1 dcf-form-grid ' + operation\" #component\n [id]=\"rendererId\"\n [formGroup]=\"formGroup\"\n (submit)=\"submit($event)\"\n novalidate\n [target]=\"target\">\n @if(!children?.length) {\n <ng-content #formContent></ng-content>\n } @else {\n <ngx-decaf-layout\n [children]=\"children || []\"\n [parentComponent]=\"formGroup || parentComponent\"\n gap=\"small\"\n [initializeProps]=\"false\"\n [rows]=\"rows\"\n [cols]=\"cols\" />\n\n <!-- @for (child of children; track $index) {\n <ngx-decaf-component-renderer\n [class]=\"(child?.props?.className ? 'dcf-form-item ' + child.props.className : 'dcf-form-item')\"\n [tag]=\"child?.tag\"\n [projectable]=\"false\"\n [formRoot]=\"formGroup\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n } -->\n }\n <div class=\"dcf-buttons-grid dcf-grid dcf-grid-collapse dcf-flex dcf-flex-left\">\n <div>\n <ion-button type=\"submit\" [expand]=\"action ? 'block' : 'default'\">\n @if(options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{ action ? action : options.buttons.submit.text}}\n </ion-button>\n </div>\n @if(!action) {\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if(options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n Back\n </ion-button>\n </div>\n }\n </div>\n </form>\n} @else {\n <section [class]=\"'dcf-grid dcf-grid-small dcf-child-width-1-1 dcf-form-grid ' + operation\" #component [id]=\"uid\">\n @if(!children?.length) {\n <ng-content #formContent></ng-content>\n } @else {\n @for (child of children; track $index) {\n <div [class]=\"(child?.props?.className ? 'dcf-form-item ' + child.props.className : 'dcf-form-item')\">\n <ngx-decaf-component-renderer\n [tag]=\"child?.tag\"\n [projectable]=\"false\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n </div>\n }\n }\n </section>\n <section [class]=\"'dcf-buttons-grid dcf-grid dcf-grid-collapse dcf-flex dcf-flex-left ' + operation\" [id]=\"uid\">\n @if(operation === OperationKeys.READ && modelId) {\n <div>\n <ion-button\n (click)=\"handleDelete()\"\n color=\"danger\"\n type=\"button\">\n @if(options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n Delete\n </ion-button>\n </div>\n\n }\n @if(operation === OperationKeys.CREATE || operation === OperationKeys.UPDATE) {\n\n <div>\n <ion-button\n type=\"submit\">\n @if(options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{options.buttons.submit.text}}\n </ion-button>\n </div>\n }\n\n @if(options.buttons.clear) {\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if(options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n {{ [OperationKeys.DELETE, OperationKeys.READ, OperationKeys.UPDATE].includes(operation) ? 'Back' : options.buttons.clear?.text}}\n </ion-button>\n </div>\n\n }\n </section>\n}\n\n", styles: [".dcf-buttons-grid{margin-top:.5rem;margin-bottom:0}.dcf-buttons-grid.read{margin-bottom:1rem}@media (min-width: 577px){.dcf-buttons-grid.dcf-flex{flex-direction:row-reverse}}@media (max-width: 576px){.dcf-buttons-grid.dcf-flex>div{width:100%}.dcf-buttons-grid.dcf-flex>div+div{margin-top:1rem}.dcf-buttons-grid.dcf-flex ion-button{width:100%}}.dcf-form-grid{padding:1rem}.dcf-form-grid .dcf-form-item{margin-bottom:1.8rem;margin-top:0!important}.dcf-form-grid.read .dcf-form-item{margin-bottom:1rem}::ng-deep ngx-decaf-stepped-form .dcf-input-item{margin-bottom:1.8rem;margin-top:0!important}::ng-deep ngx-decaf-fieldset .dcf-input-item{margin-bottom:1.8rem;margin-top:0!important}\n"] }]
5112
+ args: [{ standalone: true, selector: 'ngx-decaf-crud-form', imports: [ReactiveFormsModule, LayoutComponent, ComponentRendererComponent, IonButton, IonIcon], host: { '[attr.id]': 'uid' }, template: "@if(operation !== 'read' && operation !== 'delete') {\n <form\n [class]=\"'dcf-form-grid ' + operation\" #component\n [id]=\"rendererId\"\n [formGroup]=\"formGroup\"\n (submit)=\"submit($event)\"\n novalidate\n [target]=\"target\">\n @if(!children?.length) {\n <ng-content #formContent></ng-content>\n } @else {\n <ngx-decaf-layout\n [children]=\"children || []\"\n [parentComponent]=\"formGroup || parentComponent\"\n gap=\"small\"\n [rows]=\"rows\"\n [cols]=\"cols\" />\n\n <!-- @for (child of children; track $index) {\n <ngx-decaf-component-renderer\n [class]=\"(child?.props?.className ? 'dcf-form-item ' + child.props.className : 'dcf-form-item')\"\n [tag]=\"child?.tag\"\n [projectable]=\"false\"\n [formRoot]=\"formGroup\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n } -->\n }\n @if(initialized) {\n <div class=\"dcf-buttons-grid dcf-grid dcf-grid-collapse dcf-flex dcf-flex-left\">\n <div>\n <ion-button type=\"submit\" [expand]=\"action ? 'block' : 'default'\">\n @if(options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{ action ? action : options.buttons.submit.text}}\n </ion-button>\n </div>\n @if(!action) {\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if(options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n Back\n </ion-button>\n </div>\n }\n </div>\n }\n\n </form>\n} @else {\n <section [class]=\"'dcf-grid dcf-grid-small dcf-child-width-1-1 dcf-form-grid ' + operation\" #component [id]=\"uid\">\n @if(!children?.length) {\n <ng-content #formContent></ng-content>\n } @else {\n @for (child of children; track $index) {\n <div [class]=\"(child?.props?.className ? 'dcf-form-item ' + child.props.className : 'dcf-form-item')\">\n <ngx-decaf-component-renderer\n [tag]=\"child?.tag\"\n [projectable]=\"false\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n </div>\n }\n }\n </section>\n <section [class]=\"'dcf-buttons-grid dcf-grid dcf-grid-collapse dcf-flex dcf-flex-left ' + operation\" [id]=\"uid\">\n @if(operation === OperationKeys.READ && modelId) {\n <div>\n <ion-button\n (click)=\"handleDelete()\"\n color=\"danger\"\n type=\"button\">\n @if(options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n Delete\n </ion-button>\n </div>\n\n }\n @if(operation === OperationKeys.CREATE || operation === OperationKeys.UPDATE) {\n\n <div>\n <ion-button\n type=\"submit\">\n @if(options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{options.buttons.submit.text}}\n </ion-button>\n </div>\n }\n\n @if(options.buttons.clear) {\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if(options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n {{ [OperationKeys.DELETE, OperationKeys.READ, OperationKeys.UPDATE].includes(operation) ? 'Back' : options.buttons.clear?.text}}\n </ion-button>\n </div>\n\n }\n </section>\n}\n\n", styles: [".dcf-buttons-grid{margin-top:.5rem;margin-bottom:0}.dcf-buttons-grid.read{margin-bottom:1rem}@media (min-width: 577px){.dcf-buttons-grid.dcf-flex{flex-direction:row-reverse}}@media (max-width: 576px){.dcf-buttons-grid.dcf-flex>div{width:100%}.dcf-buttons-grid.dcf-flex>div+div{margin-top:1rem}.dcf-buttons-grid.dcf-flex ion-button{width:100%}}.dcf-form-grid{padding:1rem}.dcf-form-grid .dcf-form-item{margin-bottom:1.8rem;margin-top:0!important}.dcf-form-grid.read .dcf-form-item{margin-bottom:1rem}::ng-deep ngx-decaf-stepped-form .dcf-input-item{margin-bottom:1.8rem;margin-top:0!important}::ng-deep ngx-decaf-fieldset .dcf-input-item{margin-bottom:1.8rem;margin-top:0!important}\n"] }]
4728
5113
  }], ctorParameters: () => [] });
4729
5114
 
4730
5115
  /**
@@ -4834,10 +5219,10 @@ let EmptyStateComponent = class EmptyStateComponent extends NgxDecafComponentDir
4834
5219
  * and this value should correspond to an available icon name.
4835
5220
  *
4836
5221
  * @type {string}
4837
- * @default "ti-info-square-rounded"
5222
+ * @default "folder-open-outline"
4838
5223
  * @memberOf EmptyStateComponent
4839
5224
  */
4840
- this.icon = "ti-info-square-rounded";
5225
+ this.icon = "folder-open-outline";
4841
5226
  /**
4842
5227
  * @description The size of the displayed icon.
4843
5228
  * @summary Controls the size of the icon shown in the empty state.
@@ -4890,6 +5275,7 @@ let EmptyStateComponent = class EmptyStateComponent extends NgxDecafComponentDir
4890
5275
  */
4891
5276
  this.buttonSize = 'default';
4892
5277
  this.sanitizer = inject(DomSanitizer);
5278
+ this.enableCreationByModelRoute = false;
4893
5279
  addIcons(allIcons);
4894
5280
  }
4895
5281
  /**
@@ -4922,15 +5308,12 @@ let EmptyStateComponent = class EmptyStateComponent extends NgxDecafComponentDir
4922
5308
  async ngOnInit() {
4923
5309
  this.initialize();
4924
5310
  this.showIcon = stringToBoolean(this.showIcon);
4925
- // if(this.translatable) {
4926
- // this.title = generateLocaleFromString(this.locale, this.title);
4927
- // this.subtitle = generateLocaleFromString(this.locale, this.subtitle);
4928
- // this.buttonText = generateLocaleFromString(this.locale, this.buttonText);
4929
- // }
4930
5311
  this.titleColor = `dcf-title color-${this.titleColor}`;
4931
5312
  this.subtitleColor = `dcf-subtitle color-${this.titleColor}`;
4932
5313
  if (this.searchValue)
4933
5314
  this.searchSubtitle = await this.getSearchSubtitle(this.subtitle);
5315
+ if (!this.buttonLink && this.model && this.route)
5316
+ this.enableCreationByModelRoute = true;
4934
5317
  }
4935
5318
  /**
4936
5319
  * @description Handles click events on the action button.
@@ -5002,7 +5385,7 @@ let EmptyStateComponent = class EmptyStateComponent extends NgxDecafComponentDir
5002
5385
  return this.sanitizer.bypassSecurityTrustHtml(result);
5003
5386
  }
5004
5387
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: EmptyStateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
5005
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: EmptyStateComponent, isStandalone: true, selector: "ngx-decaf-empty-state", inputs: { title: "title", titleColor: "titleColor", subtitle: "subtitle", subtitleColor: "subtitleColor", showIcon: "showIcon", icon: "icon", iconSize: "iconSize", iconColor: "iconColor", buttonLink: "buttonLink", buttonText: "buttonText", buttonFill: "buttonFill", buttonColor: "buttonColor", buttonSize: "buttonSize", searchValue: "searchValue" }, usesInheritance: true, ngImport: i0, template: "\n<ion-card [id]=\"uid\" [class]=\"className\">\n <ion-card-content>\n @if(icon && showIcon) {\n <div class=\"dcf-icon-container\">\n <ion-icon\n name=\"alert-circle-outline\"\n size=\"large\"\n color=\"danger\"\n />\n </div>\n }\n @if(title) {\n <h5 [class]=\"titleColor\" [innerHTML]=\"title\"></h5>\n }\n @if(subtitle) {\n @if(!searchValue) {\n <p [class]=\"subtitleColor\" [innerHTML]=\"subtitle\"></p>\n } @else {\n <p [class]=\"subtitleColor\" [innerHTML]=\"searchSubtitle\"></p>\n }\n }\n @if(buttonLink && buttonText) {\n <div>\n <ion-button\n [size]=\"buttonSize\"\n [fill]=\"buttonFill\"\n [color]=\"buttonColor\"\n (click)=\"handleClick()\">\n {{ buttonText }}\n </ion-button>\n </div>\n }\n </ion-card-content>\n</ion-card>\n", styles: ["ion-card{text-align:center}ion-card ion-button{margin-top:.75rem}ion-card ion-icon{font-size:2.5rem}ion-card .dcf-icon-container{transform:scale(1.25);opacity:.75;margin-top:1.25rem!important;margin-bottom:.5rem!important}ion-card .dcf-ititle{font-weight:600!important;color:var(--dcf-color-gray-6)!important}ion-card .dcf-isubtitle{font-weight:500!important}\n"], dependencies: [{ kind: "component", type: IonCard, selector: "ion-card", inputs: ["button", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonCardContent, selector: "ion-card-content", inputs: ["mode"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }] }); }
5388
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: EmptyStateComponent, isStandalone: true, selector: "ngx-decaf-empty-state", inputs: { title: "title", titleColor: "titleColor", subtitle: "subtitle", subtitleColor: "subtitleColor", showIcon: "showIcon", icon: "icon", iconSize: "iconSize", iconColor: "iconColor", buttonLink: "buttonLink", buttonText: "buttonText", buttonFill: "buttonFill", buttonColor: "buttonColor", buttonSize: "buttonSize", searchValue: "searchValue" }, usesInheritance: true, ngImport: i0, template: "\n<ion-card [id]=\"uid\" [class]=\"className\">\n <ion-card-content>\n @if(icon && showIcon) {\n <div class=\"dcf-icon-container\">\n <ion-icon\n [name]=\"icon\"\n [size]=\"iconSize\"\n [color]=\"iconColor\"\n />\n </div>\n }\n @if(title) {\n <h5 [class]=\"titleColor\" [innerHTML]=\"title\"></h5>\n }\n @if(subtitle) {\n <p [class]=\"subtitleColor\" [innerHTML]=\"searchValue ? searchSubtitle : subtitle\"></p>\n }\n @if(!enableCreationByModelRoute) {\n @if(buttonLink && buttonText) {\n <div>\n <ion-button\n [size]=\"buttonSize\"\n [fill]=\"buttonFill\"\n [color]=\"buttonColor\"\n (click)=\"handleClick()\">\n {{ buttonText }}\n </ion-button>\n </div>\n }\n } @else {\n\n <div>\n <ion-button\n class=\"dcf-margin-top\"\n [size]=\"buttonSize\"\n [fill]=\"buttonFill\"\n [color]=\"buttonColor\"\n (click)=\"changeOperation(OperationKeys.CREATE)\" fill=\"clear\">\n {{ buttonText?.length ? buttonText : locale + '.button_create' | translate }}\n </ion-button>\n </div>\n\n }\n\n </ion-card-content>\n</ion-card>\n", styles: ["ion-card{text-align:center}ion-card ion-button{margin-top:.75rem}ion-card ion-icon{font-size:2.5rem}ion-card .dcf-icon-container{transform:scale(1.25);opacity:.75;margin-top:1.25rem!important;margin-bottom:.5rem!important}ion-card .dcf-ititle{font-weight:600!important;color:var(--dcf-color-gray-6)!important}ion-card .dcf-isubtitle{font-weight:500!important}\n"], dependencies: [{ kind: "component", type: IonCard, selector: "ion-card", inputs: ["button", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonCardContent, selector: "ion-card-content", inputs: ["mode"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
5006
5389
  };
5007
5390
  EmptyStateComponent = __decorate([
5008
5391
  Dynamic(),
@@ -5013,8 +5396,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
5013
5396
  args: [{ selector: 'ngx-decaf-empty-state', standalone: true, imports: [
5014
5397
  IonCard,
5015
5398
  IonCardContent,
5016
- IonIcon
5017
- ], template: "\n<ion-card [id]=\"uid\" [class]=\"className\">\n <ion-card-content>\n @if(icon && showIcon) {\n <div class=\"dcf-icon-container\">\n <ion-icon\n name=\"alert-circle-outline\"\n size=\"large\"\n color=\"danger\"\n />\n </div>\n }\n @if(title) {\n <h5 [class]=\"titleColor\" [innerHTML]=\"title\"></h5>\n }\n @if(subtitle) {\n @if(!searchValue) {\n <p [class]=\"subtitleColor\" [innerHTML]=\"subtitle\"></p>\n } @else {\n <p [class]=\"subtitleColor\" [innerHTML]=\"searchSubtitle\"></p>\n }\n }\n @if(buttonLink && buttonText) {\n <div>\n <ion-button\n [size]=\"buttonSize\"\n [fill]=\"buttonFill\"\n [color]=\"buttonColor\"\n (click)=\"handleClick()\">\n {{ buttonText }}\n </ion-button>\n </div>\n }\n </ion-card-content>\n</ion-card>\n", styles: ["ion-card{text-align:center}ion-card ion-button{margin-top:.75rem}ion-card ion-icon{font-size:2.5rem}ion-card .dcf-icon-container{transform:scale(1.25);opacity:.75;margin-top:1.25rem!important;margin-bottom:.5rem!important}ion-card .dcf-ititle{font-weight:600!important;color:var(--dcf-color-gray-6)!important}ion-card .dcf-isubtitle{font-weight:500!important}\n"] }]
5399
+ IonIcon,
5400
+ TranslatePipe,
5401
+ IonButton
5402
+ ], template: "\n<ion-card [id]=\"uid\" [class]=\"className\">\n <ion-card-content>\n @if(icon && showIcon) {\n <div class=\"dcf-icon-container\">\n <ion-icon\n [name]=\"icon\"\n [size]=\"iconSize\"\n [color]=\"iconColor\"\n />\n </div>\n }\n @if(title) {\n <h5 [class]=\"titleColor\" [innerHTML]=\"title\"></h5>\n }\n @if(subtitle) {\n <p [class]=\"subtitleColor\" [innerHTML]=\"searchValue ? searchSubtitle : subtitle\"></p>\n }\n @if(!enableCreationByModelRoute) {\n @if(buttonLink && buttonText) {\n <div>\n <ion-button\n [size]=\"buttonSize\"\n [fill]=\"buttonFill\"\n [color]=\"buttonColor\"\n (click)=\"handleClick()\">\n {{ buttonText }}\n </ion-button>\n </div>\n }\n } @else {\n\n <div>\n <ion-button\n class=\"dcf-margin-top\"\n [size]=\"buttonSize\"\n [fill]=\"buttonFill\"\n [color]=\"buttonColor\"\n (click)=\"changeOperation(OperationKeys.CREATE)\" fill=\"clear\">\n {{ buttonText?.length ? buttonText : locale + '.button_create' | translate }}\n </ion-button>\n </div>\n\n }\n\n </ion-card-content>\n</ion-card>\n", styles: ["ion-card{text-align:center}ion-card ion-button{margin-top:.75rem}ion-card ion-icon{font-size:2.5rem}ion-card .dcf-icon-container{transform:scale(1.25);opacity:.75;margin-top:1.25rem!important;margin-bottom:.5rem!important}ion-card .dcf-ititle{font-weight:600!important;color:var(--dcf-color-gray-6)!important}ion-card .dcf-isubtitle{font-weight:500!important}\n"] }]
5018
5403
  }], ctorParameters: () => [], propDecorators: { title: [{
5019
5404
  type: Input
5020
5405
  }], titleColor: [{
@@ -5245,11 +5630,6 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
5245
5630
  return child;
5246
5631
  });
5247
5632
  }
5248
- // if(this.model) {
5249
- // this._repository = getModelRepository(this.model);
5250
- // console.log(this._repository);
5251
- // }
5252
- // console.log(this._repository);
5253
5633
  this.initialized = true;
5254
5634
  }
5255
5635
  /**
@@ -5347,13 +5727,8 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
5347
5727
  async handleCreateItem(event) {
5348
5728
  if (event && event instanceof CustomEvent)
5349
5729
  event.stopImmediatePropagation();
5350
- // if(this.updatingItem)
5351
- // return this.handleUpdateItem(this.updatingItem.index, true);
5352
5730
  const action = this.updatingItem ? OperationKeys.UPDATE : OperationKeys.CREATE;
5353
5731
  const formGroup = this.activeFormGroup;
5354
- // currentGroup.updateValueAndValidity();
5355
- // console.log((currentGroup.parent as FormArray).value);
5356
- const parent = formGroup.parent;
5357
5732
  const isValid = NgxDecafFormService.validateFields(formGroup);
5358
5733
  // must pass correct pk here
5359
5734
  const isUnique = NgxDecafFormService.isUniqueOnGroup(formGroup, action, action === OperationKeys.UPDATE ? this.updatingItem?.index : undefined);
@@ -5372,68 +5747,13 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
5372
5747
  value?.[this.pk] || undefined : value;
5373
5748
  }
5374
5749
  }
5375
- // windowEventEmitter(EventConstants.FIELDSET_ADD_GROUP, {
5376
- // formGroup: this.updatingItem ? this.updatingItem : this.formGroup
5377
- // });
5378
- // const formParent = this.formGroup as FormArray;
5379
- // const index = formParent.length - 1;
5380
- // const formGroup = formParent.at(index) as FormGroup;
5381
- // console.log(formGroup.errors);
5382
- // const isValid = NgxDecafFormService.validateFields(this.formGroup as FormGroup);
5383
- // const isUnique = NgxDecafFormService.isUniqueOnGroup(formGroup, index, OperationKeys.CREATE);
5384
- // const value = formGroup.value;
5385
- // console.log(isValid, isUnique);
5386
- // this.changeDetectorRef.detectChanges();
5387
- // if(!Object.keys(this.mapper).length)
5388
- // this.mapper = this.getMapper(value as KeyValue);
5389
- // if(isValid && isUnique) {
5390
- // this.isUniqueError = undefined;
5391
- // this.buttonLabel = this.translateService.instant(this.locale + '.add');
5392
- // this.setValue();
5393
- // // const fb = NgxDecafFormService.addGroupToParent((this.formGroup as FormArray).root as FormGroup, this.childOf as string, formParent.length).parent as FormArray;
5394
- // } else {
5395
- // this.isUniqueError = typeof value === 'object' ? (value as KeyValue)?.[this.pk] || undefined : value;
5396
- // }
5397
- // console.log(this.formGroup);
5398
- // if(event && event instanceof CustomEvent) {
5399
- // event.stopImmediatePropagation();
5400
- // const {formGroup, value, isValid} = event.detail;
5401
- // this.formGroup = formGroup as FormArray;
5402
- // if(!this.mapper)
5403
- // this.mapper = this.getMapper(value as KeyValue);
5404
- // if(isValid ){
5405
- // this.isUniqueError = undefined;
5406
- // this.buttonLabel = this.translateService.instant(this.locale + '.add');
5407
- // this.setValue();
5408
- // } else {
5409
- // this.isUniqueError = (value as KeyValue)?.[this.pk] || undefined;
5410
- // }
5411
- // } else {
5412
- // windowEventEmitter(EventConstants.FIELDSET_ADD_GROUP, {
5413
- // component: this.component.nativeElement,
5414
- // index: this.updatingItem ? this.updatingItem.index : this.value?.length,
5415
- // parent: this.childOf,
5416
- // operation: !this.updatingItem ? OperationKeys.CREATE : OperationKeys.UPDATE
5417
- // });
5418
- // }
5419
5750
  }
5420
- handleUpdateItem(index, save = false) {
5751
+ handleUpdateItem(index) {
5421
5752
  const formGroup = this.getFormArrayIndex(index);
5422
5753
  if (formGroup) {
5423
5754
  this.updatingItem = Object.assign({}, formGroup.value || {}, { index });
5424
5755
  this.activeFormGroupIndex = index;
5425
5756
  }
5426
- // this.changeDetectorRef.detectChanges();
5427
- // const item = this.formGroup.controls.find(control => `${control.get(this.pk)?.value}`.toLowerCase() === cleanSpaces(`${value}`, true)) as FormControl;
5428
- // if(item) {
5429
- // this.buttonLabel = this.translateService.instant(this.locale + '.update');
5430
- // this.updatingItem = Object.assign({}, item.value || {}, {index});
5431
- // windowEventEmitter(EventConstants.FIELDSET_UPDATE_GROUP, {
5432
- // parent: this.childOf,
5433
- // component: this.component.nativeElement,
5434
- // index: index
5435
- // });
5436
- // }
5437
5757
  }
5438
5758
  /**
5439
5759
  * @description Cancels the update mode and resets the UI state.
@@ -5478,23 +5798,6 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
5478
5798
  this.setValue();
5479
5799
  if (this.activeFormGroupIndex > 0)
5480
5800
  this.activeFormGroupIndex = this.activeFormGroupIndex - 1;
5481
- // if(event && event instanceof CustomEvent) {
5482
- // event.stopImmediatePropagation();
5483
- // return this.setValue();
5484
- // }
5485
- // const formArray = this.formGroup as FormArray;
5486
- // const arrayLength = formArray.length;
5487
- // for (let index = arrayLength - 1; index >= 0; index--) {
5488
- // const group = formArray.at(index) as FormGroup;
5489
- // if (cleanSpaces(group.get(this.pk)?.value) === cleanSpaces(value as string)) {
5490
- // windowEventEmitter(EventConstants.FIELDSET_REMOVE_GROUP, {
5491
- // parent: this.childOf,
5492
- // component: this.component.nativeElement,
5493
- // index,
5494
- // formGroup: group
5495
- // });
5496
- // }
5497
- // }
5498
5801
  }
5499
5802
  /**
5500
5803
  * @description Handles reordering of items within the fieldset list.
@@ -5621,16 +5924,7 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
5621
5924
  index: index + 1
5622
5925
  };
5623
5926
  });
5624
- // const inputContainers = this.component.nativeElement.querySelectorAll('.dcf-input-item');
5625
- // inputContainers.forEach((container: HTMLElement) => {
5626
- // const input = container.querySelector('input, ion-input, ion-textarea, textarea') as HTMLInputElement | null;
5627
- // if(input)
5628
- // input.value = '';
5629
- // })
5630
5927
  this.updatingItem = undefined;
5631
- // console.log(this.isUniqueError);
5632
- // console.log(this.mapper);
5633
- // console.log(this.items);
5634
5928
  }
5635
5929
  /**
5636
5930
  * @description Automatically configures the field mapping based on the value structure.
@@ -5662,7 +5956,7 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
5662
5956
  return this.mapper;
5663
5957
  }
5664
5958
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: FieldsetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
5665
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: FieldsetComponent, isStandalone: true, selector: "ngx-decaf-fieldset", inputs: { formControl: "formControl", collapsable: "collapsable", page: "page", customTypes: "customTypes", title: "title", description: "description", multiple: "multiple", value: "value", borders: "borders" }, host: { properties: { "attr.id": "uid" } }, viewQueries: [{ propertyName: "accordionComponent", first: true, predicate: ["accordionComponent"], descendants: true }], usesInheritance: true, ngImport: i0, template: "\n\n<fieldset\n (fieldsetAddGroupEvent)=\"handleCreateItem($event)\"\n [class]=\"'dcf-fieldset ' + operation\"\n [class.remove-border]=\"!borders\"\n [class.open]=\"isOpen\"\n #component>\n <ion-accordion-group class=\"dcf-width-1-1\" [class.open]=\"isOpen\" [class.hasValidationErrors]=\"hasValidationErrors\" [value]=\"operation === 'read' ? 'open' : ''\" #accordionComponent>\n <ion-accordion value=\"open\">\n <ion-item [class.disable-collapse]=\"!collapsable\" slot=\"header\" [button]=\"collapsable\" (click)=\"handleAccordionToggle($event)\">\n <div class=\"dcf-grid dcf-grid-collapse dcf-flex dcf-flex-middle dcf-width-1-1\">\n <div class=\"dcf-width-expand\">\n <legend>{{ name | translate }}</legend>\n </div>\n @if ((!isRequired && ['create', 'update'].includes(operation))) {\n <div class=\"dcf-width-auto dcf-delete\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleRemoveComponent($event)\">\n <ion-icon name=\"trash-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n }\n </div>\n </ion-item>\n <div slot=\"content\" [attr.aria-hidden]=\"!isOpen\">\n @if (multiple && items.length) {\n <ion-list class=\"dcf-fields-list\">\n <ion-reorder-group [formGroup]=\"formGroup.parent\" [disabled]=\"updatingItem\" (ionItemReorder)=\"handleReorderItems($any($event))\" #accordionComponent>\n @for(item of items; track item.index) {\n <ion-item [class.not-unique]=\"item.title === isUniqueError\" [class.updating]=\"updatingItem?.[pk] === item.title\" lines=\"full\" [button]=\"false\">\n @if (items?.length > 1 && !updatingItem) {\n <ion-reorder slot=\"start\">\n <ion-icon name=\"swap-vertical-outline\"></ion-icon>\n </ion-reorder>\n } @else {\n <div slot=\"start\">\n <ion-icon class=\"dcf-reorder-disabled\" size=\"small\" name=\"swap-vertical-outline\" disabled></ion-icon>\n </div>\n }\n <ion-label [color]=\"(item.title === isUniqueError && !updatingItem?.[pk] === item.title) ? 'danger' : ''\">{{ item.index }}. {{ item.title }}\n @if (item.description?.length > 0) {\n <br />\n <ion-text class=\"dcf-subtitle\">{{item.description}}</ion-text>\n }\n </ion-label>\n @if (!updatingItem || updatingItem?.[pk] !== item.title) {\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleUpdateItem($index)\">\n <ion-icon name=\"create-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n }\n\n @if (!updatingItem) {\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleRemoveItem($index)\">\n <ion-icon name=\"trash-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n }\n </ion-item>\n }\n </ion-reorder-group>\n </ion-list>\n }\n <ng-content select=\"[slot=content]\"></ng-content>\n\n @if (this.children?.length) {\n @for (child of children; track $index) {\n <ngx-decaf-component-renderer\n [class]=\"(child?.props?.className ? ' ' + child.props.className : '')\"\n [tag]=\"child?.tag\"\n [parentComponent]=\"formGroup || parentComponent\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n }\n }\n @if (multiple && ['create', 'update'].includes(operation)) {\n @if (isUniqueError) {\n <div class=\"dcf-not-unique-container dcf-animation dcf-animation-bottom-small dcf-animation-fast\">\n <div class=\" dcf-grid dcf-grid-collapse dcf-width-1-1 \">\n <div class=\"dcf-auto\" [attr.style]=\"'max-width: 50px'\">\n <ion-icon name=\"alert-circle-outline\"></ion-icon>\n </div>\n <div class=\"dcf-width-expand\">\n <ion-text color=\"danger\" class=\"dcf-text-small\">{{ locale + '.not_unique' | translate : { value: isUniqueError } }}</ion-text>\n </div>\n </div>\n </div>\n }\n <div class=\"dcf-margin-bottom dcf-grid dcf-grid-collapse dcf-flex\">\n @if (updatingItem) {\n <ion-button size=\"small\" fill=\"clear\" color=\"danger\" (click)=\"handleCancelUpdateItem()\">\n {{ buttonCancelLabel }}\n </ion-button>\n }\n @if (items.length < max || !max) {\n <ion-button size=\"small\" fill=\"clear\" class=\"dcf-button-add\" (click)=\"handleCreateItem()\">\n <ion-icon name=\"add-outline\" slot=\"start\"></ion-icon>\n {{buttonLabel}}\n </ion-button>\n }\n </div>\n }\n </div>\n </ion-accordion>\n </ion-accordion-group>\n</fieldset>\n\n", styles: ["ion-accordion-group ion-item[slot=header] .dcf-delete{width:30px}ion-accordion-group ion-item[slot=header] .dcf-delete ion-button{transform:translateY(-2px)}ion-accordion-group ion-item[slot=header] .dcf-delete ion-icon{font-size:1.15rem}::ng-deep ion-accordion ngx-decaf-crud-field:last-child ion-item{--inner-border-width: 0px !important;--border-width: 0px !important}@media (prefers-color-scheme: light){.dcf-fieldset{border:1px solid var(--dcf-color-gray-3)}.dcf-fieldset .dcf-button-add{color:var(--ion-color-dark)!important}ion-accordion ion-item[slot=header] legend{color:var(--dcf-color-gray-7)}}@media (prefers-color-scheme: dark){.dcf-fieldset{border:1px solid var(--dcf-color-step-400)}.dcf-fieldset .dcf-button-add{color:var(--ion-color-gray-2)}.dcf-fieldset.read,.dcf-fieldset.delete{border:1px solid var(--dcf-color-gray-6)}}.dcf-fieldset{padding-top:1rem;padding-bottom:1rem;background:var(--dcf-card-background);border-radius:6px}.dcf-fieldset.remove-border{border:none!important;padding:0!important;margin:0!important}.dcf-fieldset.open ion-accordion{margin-bottom:1rem}.dcf-fieldset.open ion-accordion.accordion-collapsing,.dcf-fieldset.open ion-accordion.accordion-collapsed{margin-bottom:1rem}.dcf-fieldset.read [slot=content],.dcf-fieldset.delete [slot=content]{padding-top:0!important}.dcf-fieldset.read ion-accordion,.dcf-fieldset.delete ion-accordion{margin-bottom:0rem!important}.dcf-fieldset ion-accordion{background:var(--dcf-card-background)}.dcf-fieldset ion-accordion ion-item[slot=header]{--border-color: transparent;--border-radius: 6px;--inner-border-width: 0;--padding-start: 12px}.dcf-fieldset ion-accordion ion-item[slot=header] legend{font-weight:600;font-size:1rem;margin:0}.dcf-fieldset ion-accordion [slot=content]{padding-top:1.5rem!important;padding-inline:.75rem}.dcf-not-unique-container{display:flex;justify-content:center;align-items:center;margin-bottom:1rem;flex:1 1 auto}.dcf-not-unique-container>div{display:flex;justify-content:center;align-items:center}.dcf-not-unique-container ion-icon{transform:translatey(2px);margin-right:5px}.dcf-fields-list{margin-bottom:1rem;padding:0!important}.dcf-fields-list ion-item{--min-height: 50px;--padding-top: .25rem;--padding-bottom: .25rem;--padding-start: .75rem;--padding-end: .75rem;--inner-padding-start: 0px !important;--inner-padding-end: 0px !important;--border-color: var(--dcf-color-gray-2) !important;border:1px solid transparent;box-sizing:border-box}.dcf-fields-list ion-item ion-icon.dcf-reorder-disabled{width:1rem;transform:translatey(2px);color:var(--dcf-color-gray-4)}.dcf-fields-list ion-item.updating{--background: rgba(var(--dcf-color-primary-rgb), .1) !important}.dcf-fields-list ion-item.not-unique{--background: rgba(var(--dcf-color-danger-rgb), .05) !important}.dcf-fields-list ion-item .dcf-subtitle{font-size:.8rem;color:var(--dcf-color-gray-7)}\n"], dependencies: [{ kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "children", "projectable", "model", "parentComponent", "parent"], outputs: ["listenEvent"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { 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: IonAccordionGroup, selector: "ion-accordion-group", inputs: ["animated", "disabled", "expand", "mode", "multiple", "readonly", "value"] }, { kind: "component", type: IonAccordion, selector: "ion-accordion", inputs: ["disabled", "mode", "readonly", "toggleIcon", "toggleIconSlot", "value"] }, { kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonReorder, selector: "ion-reorder" }, { kind: "component", type: IonReorderGroup, selector: "ion-reorder-group", inputs: ["disabled"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
5959
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: FieldsetComponent, isStandalone: true, selector: "ngx-decaf-fieldset", inputs: { formControl: "formControl", collapsable: "collapsable", page: "page", customTypes: "customTypes", title: "title", description: "description", multiple: "multiple", value: "value", borders: "borders" }, viewQueries: [{ propertyName: "accordionComponent", first: true, predicate: ["accordionComponent"], descendants: true }], usesInheritance: true, ngImport: i0, template: "\n\n<fieldset\n (fieldsetAddGroupEvent)=\"handleCreateItem($event)\"\n [class]=\"'dcf-fieldset ' + operation\"\n [class.remove-border]=\"!borders\"\n [class.open]=\"isOpen\"\n #component>\n <ion-accordion-group class=\"dcf-width-1-1\" [class.open]=\"isOpen\" [class.hasValidationErrors]=\"hasValidationErrors\" [value]=\"operation === 'read' ? 'open' : ''\" #accordionComponent>\n <ion-accordion value=\"open\">\n <ion-item [class.disable-collapse]=\"!collapsable\" slot=\"header\" [button]=\"collapsable\" (click)=\"handleAccordionToggle($event)\">\n <div class=\"dcf-grid dcf-grid-collapse dcf-flex dcf-flex-middle dcf-width-1-1\">\n <div class=\"dcf-width-expand\">\n <legend>{{ name | translate }}</legend>\n </div>\n @if ((!isRequired && ['create', 'update'].includes(operation))) {\n <div class=\"dcf-width-auto dcf-delete\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleRemoveComponent($event)\">\n <ion-icon name=\"trash-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n }\n </div>\n </ion-item>\n <div slot=\"content\" [attr.aria-hidden]=\"!isOpen\">\n @if (multiple && items.length) {\n <ion-list class=\"dcf-fields-list\">\n <ion-reorder-group [formGroup]=\"formGroup.parent\" [disabled]=\"updatingItem\" (ionItemReorder)=\"handleReorderItems($any($event))\" #accordionComponent>\n @for(item of items; track item.index) {\n <ion-item [class.not-unique]=\"item.title === isUniqueError\" [class.updating]=\"updatingItem?.[pk] === item.title\" lines=\"full\" [button]=\"false\">\n @if (items?.length > 1 && !updatingItem) {\n <ion-reorder slot=\"start\">\n <ion-icon name=\"swap-vertical-outline\"></ion-icon>\n </ion-reorder>\n } @else {\n <div slot=\"start\">\n <ion-icon class=\"dcf-reorder-disabled\" size=\"small\" name=\"swap-vertical-outline\" disabled></ion-icon>\n </div>\n }\n <ion-label [color]=\"(item.title === isUniqueError && !updatingItem?.[pk] === item.title) ? 'danger' : ''\">{{ item.index }}. {{ item.title }}\n @if (item.description?.length > 0) {\n <br />\n <ion-text class=\"dcf-subtitle\">{{item.description}}</ion-text>\n }\n </ion-label>\n @if (!updatingItem || updatingItem?.[pk] !== item.title) {\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleUpdateItem($index)\">\n <ion-icon name=\"create-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n }\n\n @if (!updatingItem) {\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleRemoveItem($index)\">\n <ion-icon name=\"trash-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n }\n </ion-item>\n }\n </ion-reorder-group>\n </ion-list>\n }\n\n @if(children?.length) {\n <ngx-decaf-layout\n gap=\"small\"\n [children]=\"children || []\"\n [parentComponent]=\"formGroup || parentComponent\"\n [match]=\"false\"\n\n [rows]=\"rows\"\n [cols]=\"cols\"\n />\n }\n\n @if (multiple && ['create', 'update'].includes(operation)) {\n @if (isUniqueError) {\n <div class=\"dcf-not-unique-container dcf-animation dcf-animation-bottom-small dcf-animation-fast\">\n <div class=\" dcf-grid dcf-grid-collapse dcf-width-1-1 \">\n <div class=\"dcf-auto\" [attr.style]=\"'max-width: 50px'\">\n <ion-icon name=\"alert-circle-outline\"></ion-icon>\n </div>\n <div class=\"dcf-width-expand\">\n <ion-text color=\"danger\" class=\"dcf-text-small\">{{ locale + '.not_unique' | translate : { value: isUniqueError } }}</ion-text>\n </div>\n </div>\n </div>\n }\n <div class=\"dcf-margin-bottom dcf-grid dcf-grid-collapse dcf-flex\">\n @if (updatingItem) {\n <ion-button size=\"small\" fill=\"clear\" color=\"danger\" (click)=\"handleCancelUpdateItem()\">\n {{ buttonCancelLabel }}\n </ion-button>\n }\n @if (items.length < max || !max) {\n <ion-button size=\"small\" fill=\"clear\" class=\"dcf-button-add\" (click)=\"handleCreateItem()\">\n <ion-icon name=\"add-outline\" slot=\"start\"></ion-icon>\n {{buttonLabel}}\n </ion-button>\n }\n </div>\n }\n </div>\n </ion-accordion>\n </ion-accordion-group>\n</fieldset>\n\n", styles: ["ion-accordion-group ion-item[slot=header] .dcf-delete{width:30px}ion-accordion-group ion-item[slot=header] .dcf-delete ion-button{transform:translateY(-2px)}ion-accordion-group ion-item[slot=header] .dcf-delete ion-icon{font-size:1.15rem}::ng-deep ion-accordion ngx-decaf-crud-field:last-child ion-item{--inner-border-width: 0px !important;--border-width: 0px !important}@media (prefers-color-scheme: light){.dcf-fieldset{border:1px solid var(--dcf-color-gray-3)}.dcf-fieldset .dcf-button-add{color:var(--ion-color-dark)!important}ion-accordion ion-item[slot=header] legend{color:var(--dcf-color-gray-7)}}@media (prefers-color-scheme: dark){.dcf-fieldset{border:1px solid var(--dcf-color-step-400)}.dcf-fieldset .dcf-button-add{color:var(--ion-color-gray-2)}.dcf-fieldset.read,.dcf-fieldset.delete{border:1px solid var(--dcf-color-gray-6)}}.dcf-fieldset{padding-top:1rem;padding-bottom:1rem;background:var(--dcf-card-background);border-radius:6px}.dcf-fieldset.remove-border{border:none!important;padding:0!important;margin:0!important}.dcf-fieldset.open ion-accordion{margin-bottom:1rem}.dcf-fieldset.open ion-accordion.accordion-collapsing,.dcf-fieldset.open ion-accordion.accordion-collapsed{margin-bottom:1rem}.dcf-fieldset.read [slot=content],.dcf-fieldset.delete [slot=content]{padding-top:0!important}.dcf-fieldset.read ion-accordion,.dcf-fieldset.delete ion-accordion{margin-bottom:0rem!important}.dcf-fieldset ion-accordion{background:var(--dcf-card-background)}.dcf-fieldset ion-accordion ion-item[slot=header]{--border-color: transparent;--border-radius: 6px;--inner-border-width: 0;--padding-start: 12px}.dcf-fieldset ion-accordion ion-item[slot=header] legend{font-weight:600;font-size:1rem;margin:0}.dcf-fieldset ion-accordion [slot=content]{padding-top:1.5rem!important;padding-inline:.75rem}.dcf-not-unique-container{display:flex;justify-content:center;align-items:center;margin-bottom:1rem;flex:1 1 auto}.dcf-not-unique-container>div{display:flex;justify-content:center;align-items:center}.dcf-not-unique-container ion-icon{transform:translatey(2px);margin-right:5px}.dcf-fields-list{margin-bottom:1rem;padding:0!important}.dcf-fields-list ion-item{--min-height: 50px;--padding-top: .25rem;--padding-bottom: .25rem;--padding-start: .75rem;--padding-end: .75rem;--inner-padding-start: 0px !important;--inner-padding-end: 0px !important;--border-color: var(--dcf-color-gray-2) !important;border:1px solid transparent;box-sizing:border-box}.dcf-fields-list ion-item ion-icon.dcf-reorder-disabled{width:1rem;transform:translatey(2px);color:var(--dcf-color-gray-4)}.dcf-fields-list ion-item.updating{--background: rgba(var(--dcf-color-primary-rgb), .1) !important}.dcf-fields-list ion-item.not-unique{--background: rgba(var(--dcf-color-danger-rgb), .05) !important}.dcf-fields-list ion-item .dcf-subtitle{font-size:.8rem;color:var(--dcf-color-gray-7)}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { 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: IonAccordionGroup, selector: "ion-accordion-group", inputs: ["animated", "disabled", "expand", "mode", "multiple", "readonly", "value"] }, { kind: "component", type: IonAccordion, selector: "ion-accordion", inputs: ["disabled", "mode", "readonly", "toggleIcon", "toggleIconSlot", "value"] }, { kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonReorder, selector: "ion-reorder" }, { kind: "component", type: IonReorderGroup, selector: "ion-reorder-group", inputs: ["disabled"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: LayoutComponent, selector: "ngx-decaf-layout", inputs: ["gap", "breakpoint", "grid", "match"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
5666
5960
  };
5667
5961
  FieldsetComponent = __decorate([
5668
5962
  Dynamic(),
@@ -5672,7 +5966,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
5672
5966
  type: Component,
5673
5967
  args: [{ standalone: true, selector: 'ngx-decaf-fieldset', schemas: [], imports: [
5674
5968
  TranslatePipe,
5675
- ComponentRendererComponent,
5676
5969
  ReactiveFormsModule,
5677
5970
  IonAccordionGroup,
5678
5971
  IonAccordion,
@@ -5684,7 +5977,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
5684
5977
  IonReorderGroup,
5685
5978
  IonButton,
5686
5979
  IonIcon,
5687
- ], host: { '[attr.id]': 'uid' }, template: "\n\n<fieldset\n (fieldsetAddGroupEvent)=\"handleCreateItem($event)\"\n [class]=\"'dcf-fieldset ' + operation\"\n [class.remove-border]=\"!borders\"\n [class.open]=\"isOpen\"\n #component>\n <ion-accordion-group class=\"dcf-width-1-1\" [class.open]=\"isOpen\" [class.hasValidationErrors]=\"hasValidationErrors\" [value]=\"operation === 'read' ? 'open' : ''\" #accordionComponent>\n <ion-accordion value=\"open\">\n <ion-item [class.disable-collapse]=\"!collapsable\" slot=\"header\" [button]=\"collapsable\" (click)=\"handleAccordionToggle($event)\">\n <div class=\"dcf-grid dcf-grid-collapse dcf-flex dcf-flex-middle dcf-width-1-1\">\n <div class=\"dcf-width-expand\">\n <legend>{{ name | translate }}</legend>\n </div>\n @if ((!isRequired && ['create', 'update'].includes(operation))) {\n <div class=\"dcf-width-auto dcf-delete\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleRemoveComponent($event)\">\n <ion-icon name=\"trash-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n }\n </div>\n </ion-item>\n <div slot=\"content\" [attr.aria-hidden]=\"!isOpen\">\n @if (multiple && items.length) {\n <ion-list class=\"dcf-fields-list\">\n <ion-reorder-group [formGroup]=\"formGroup.parent\" [disabled]=\"updatingItem\" (ionItemReorder)=\"handleReorderItems($any($event))\" #accordionComponent>\n @for(item of items; track item.index) {\n <ion-item [class.not-unique]=\"item.title === isUniqueError\" [class.updating]=\"updatingItem?.[pk] === item.title\" lines=\"full\" [button]=\"false\">\n @if (items?.length > 1 && !updatingItem) {\n <ion-reorder slot=\"start\">\n <ion-icon name=\"swap-vertical-outline\"></ion-icon>\n </ion-reorder>\n } @else {\n <div slot=\"start\">\n <ion-icon class=\"dcf-reorder-disabled\" size=\"small\" name=\"swap-vertical-outline\" disabled></ion-icon>\n </div>\n }\n <ion-label [color]=\"(item.title === isUniqueError && !updatingItem?.[pk] === item.title) ? 'danger' : ''\">{{ item.index }}. {{ item.title }}\n @if (item.description?.length > 0) {\n <br />\n <ion-text class=\"dcf-subtitle\">{{item.description}}</ion-text>\n }\n </ion-label>\n @if (!updatingItem || updatingItem?.[pk] !== item.title) {\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleUpdateItem($index)\">\n <ion-icon name=\"create-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n }\n\n @if (!updatingItem) {\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleRemoveItem($index)\">\n <ion-icon name=\"trash-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n }\n </ion-item>\n }\n </ion-reorder-group>\n </ion-list>\n }\n <ng-content select=\"[slot=content]\"></ng-content>\n\n @if (this.children?.length) {\n @for (child of children; track $index) {\n <ngx-decaf-component-renderer\n [class]=\"(child?.props?.className ? ' ' + child.props.className : '')\"\n [tag]=\"child?.tag\"\n [parentComponent]=\"formGroup || parentComponent\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n }\n }\n @if (multiple && ['create', 'update'].includes(operation)) {\n @if (isUniqueError) {\n <div class=\"dcf-not-unique-container dcf-animation dcf-animation-bottom-small dcf-animation-fast\">\n <div class=\" dcf-grid dcf-grid-collapse dcf-width-1-1 \">\n <div class=\"dcf-auto\" [attr.style]=\"'max-width: 50px'\">\n <ion-icon name=\"alert-circle-outline\"></ion-icon>\n </div>\n <div class=\"dcf-width-expand\">\n <ion-text color=\"danger\" class=\"dcf-text-small\">{{ locale + '.not_unique' | translate : { value: isUniqueError } }}</ion-text>\n </div>\n </div>\n </div>\n }\n <div class=\"dcf-margin-bottom dcf-grid dcf-grid-collapse dcf-flex\">\n @if (updatingItem) {\n <ion-button size=\"small\" fill=\"clear\" color=\"danger\" (click)=\"handleCancelUpdateItem()\">\n {{ buttonCancelLabel }}\n </ion-button>\n }\n @if (items.length < max || !max) {\n <ion-button size=\"small\" fill=\"clear\" class=\"dcf-button-add\" (click)=\"handleCreateItem()\">\n <ion-icon name=\"add-outline\" slot=\"start\"></ion-icon>\n {{buttonLabel}}\n </ion-button>\n }\n </div>\n }\n </div>\n </ion-accordion>\n </ion-accordion-group>\n</fieldset>\n\n", styles: ["ion-accordion-group ion-item[slot=header] .dcf-delete{width:30px}ion-accordion-group ion-item[slot=header] .dcf-delete ion-button{transform:translateY(-2px)}ion-accordion-group ion-item[slot=header] .dcf-delete ion-icon{font-size:1.15rem}::ng-deep ion-accordion ngx-decaf-crud-field:last-child ion-item{--inner-border-width: 0px !important;--border-width: 0px !important}@media (prefers-color-scheme: light){.dcf-fieldset{border:1px solid var(--dcf-color-gray-3)}.dcf-fieldset .dcf-button-add{color:var(--ion-color-dark)!important}ion-accordion ion-item[slot=header] legend{color:var(--dcf-color-gray-7)}}@media (prefers-color-scheme: dark){.dcf-fieldset{border:1px solid var(--dcf-color-step-400)}.dcf-fieldset .dcf-button-add{color:var(--ion-color-gray-2)}.dcf-fieldset.read,.dcf-fieldset.delete{border:1px solid var(--dcf-color-gray-6)}}.dcf-fieldset{padding-top:1rem;padding-bottom:1rem;background:var(--dcf-card-background);border-radius:6px}.dcf-fieldset.remove-border{border:none!important;padding:0!important;margin:0!important}.dcf-fieldset.open ion-accordion{margin-bottom:1rem}.dcf-fieldset.open ion-accordion.accordion-collapsing,.dcf-fieldset.open ion-accordion.accordion-collapsed{margin-bottom:1rem}.dcf-fieldset.read [slot=content],.dcf-fieldset.delete [slot=content]{padding-top:0!important}.dcf-fieldset.read ion-accordion,.dcf-fieldset.delete ion-accordion{margin-bottom:0rem!important}.dcf-fieldset ion-accordion{background:var(--dcf-card-background)}.dcf-fieldset ion-accordion ion-item[slot=header]{--border-color: transparent;--border-radius: 6px;--inner-border-width: 0;--padding-start: 12px}.dcf-fieldset ion-accordion ion-item[slot=header] legend{font-weight:600;font-size:1rem;margin:0}.dcf-fieldset ion-accordion [slot=content]{padding-top:1.5rem!important;padding-inline:.75rem}.dcf-not-unique-container{display:flex;justify-content:center;align-items:center;margin-bottom:1rem;flex:1 1 auto}.dcf-not-unique-container>div{display:flex;justify-content:center;align-items:center}.dcf-not-unique-container ion-icon{transform:translatey(2px);margin-right:5px}.dcf-fields-list{margin-bottom:1rem;padding:0!important}.dcf-fields-list ion-item{--min-height: 50px;--padding-top: .25rem;--padding-bottom: .25rem;--padding-start: .75rem;--padding-end: .75rem;--inner-padding-start: 0px !important;--inner-padding-end: 0px !important;--border-color: var(--dcf-color-gray-2) !important;border:1px solid transparent;box-sizing:border-box}.dcf-fields-list ion-item ion-icon.dcf-reorder-disabled{width:1rem;transform:translatey(2px);color:var(--dcf-color-gray-4)}.dcf-fields-list ion-item.updating{--background: rgba(var(--dcf-color-primary-rgb), .1) !important}.dcf-fields-list ion-item.not-unique{--background: rgba(var(--dcf-color-danger-rgb), .05) !important}.dcf-fields-list ion-item .dcf-subtitle{font-size:.8rem;color:var(--dcf-color-gray-7)}\n"] }]
5980
+ LayoutComponent
5981
+ ], template: "\n\n<fieldset\n (fieldsetAddGroupEvent)=\"handleCreateItem($event)\"\n [class]=\"'dcf-fieldset ' + operation\"\n [class.remove-border]=\"!borders\"\n [class.open]=\"isOpen\"\n #component>\n <ion-accordion-group class=\"dcf-width-1-1\" [class.open]=\"isOpen\" [class.hasValidationErrors]=\"hasValidationErrors\" [value]=\"operation === 'read' ? 'open' : ''\" #accordionComponent>\n <ion-accordion value=\"open\">\n <ion-item [class.disable-collapse]=\"!collapsable\" slot=\"header\" [button]=\"collapsable\" (click)=\"handleAccordionToggle($event)\">\n <div class=\"dcf-grid dcf-grid-collapse dcf-flex dcf-flex-middle dcf-width-1-1\">\n <div class=\"dcf-width-expand\">\n <legend>{{ name | translate }}</legend>\n </div>\n @if ((!isRequired && ['create', 'update'].includes(operation))) {\n <div class=\"dcf-width-auto dcf-delete\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleRemoveComponent($event)\">\n <ion-icon name=\"trash-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n }\n </div>\n </ion-item>\n <div slot=\"content\" [attr.aria-hidden]=\"!isOpen\">\n @if (multiple && items.length) {\n <ion-list class=\"dcf-fields-list\">\n <ion-reorder-group [formGroup]=\"formGroup.parent\" [disabled]=\"updatingItem\" (ionItemReorder)=\"handleReorderItems($any($event))\" #accordionComponent>\n @for(item of items; track item.index) {\n <ion-item [class.not-unique]=\"item.title === isUniqueError\" [class.updating]=\"updatingItem?.[pk] === item.title\" lines=\"full\" [button]=\"false\">\n @if (items?.length > 1 && !updatingItem) {\n <ion-reorder slot=\"start\">\n <ion-icon name=\"swap-vertical-outline\"></ion-icon>\n </ion-reorder>\n } @else {\n <div slot=\"start\">\n <ion-icon class=\"dcf-reorder-disabled\" size=\"small\" name=\"swap-vertical-outline\" disabled></ion-icon>\n </div>\n }\n <ion-label [color]=\"(item.title === isUniqueError && !updatingItem?.[pk] === item.title) ? 'danger' : ''\">{{ item.index }}. {{ item.title }}\n @if (item.description?.length > 0) {\n <br />\n <ion-text class=\"dcf-subtitle\">{{item.description}}</ion-text>\n }\n </ion-label>\n @if (!updatingItem || updatingItem?.[pk] !== item.title) {\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleUpdateItem($index)\">\n <ion-icon name=\"create-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n }\n\n @if (!updatingItem) {\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleRemoveItem($index)\">\n <ion-icon name=\"trash-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n }\n </ion-item>\n }\n </ion-reorder-group>\n </ion-list>\n }\n\n @if(children?.length) {\n <ngx-decaf-layout\n gap=\"small\"\n [children]=\"children || []\"\n [parentComponent]=\"formGroup || parentComponent\"\n [match]=\"false\"\n\n [rows]=\"rows\"\n [cols]=\"cols\"\n />\n }\n\n @if (multiple && ['create', 'update'].includes(operation)) {\n @if (isUniqueError) {\n <div class=\"dcf-not-unique-container dcf-animation dcf-animation-bottom-small dcf-animation-fast\">\n <div class=\" dcf-grid dcf-grid-collapse dcf-width-1-1 \">\n <div class=\"dcf-auto\" [attr.style]=\"'max-width: 50px'\">\n <ion-icon name=\"alert-circle-outline\"></ion-icon>\n </div>\n <div class=\"dcf-width-expand\">\n <ion-text color=\"danger\" class=\"dcf-text-small\">{{ locale + '.not_unique' | translate : { value: isUniqueError } }}</ion-text>\n </div>\n </div>\n </div>\n }\n <div class=\"dcf-margin-bottom dcf-grid dcf-grid-collapse dcf-flex\">\n @if (updatingItem) {\n <ion-button size=\"small\" fill=\"clear\" color=\"danger\" (click)=\"handleCancelUpdateItem()\">\n {{ buttonCancelLabel }}\n </ion-button>\n }\n @if (items.length < max || !max) {\n <ion-button size=\"small\" fill=\"clear\" class=\"dcf-button-add\" (click)=\"handleCreateItem()\">\n <ion-icon name=\"add-outline\" slot=\"start\"></ion-icon>\n {{buttonLabel}}\n </ion-button>\n }\n </div>\n }\n </div>\n </ion-accordion>\n </ion-accordion-group>\n</fieldset>\n\n", styles: ["ion-accordion-group ion-item[slot=header] .dcf-delete{width:30px}ion-accordion-group ion-item[slot=header] .dcf-delete ion-button{transform:translateY(-2px)}ion-accordion-group ion-item[slot=header] .dcf-delete ion-icon{font-size:1.15rem}::ng-deep ion-accordion ngx-decaf-crud-field:last-child ion-item{--inner-border-width: 0px !important;--border-width: 0px !important}@media (prefers-color-scheme: light){.dcf-fieldset{border:1px solid var(--dcf-color-gray-3)}.dcf-fieldset .dcf-button-add{color:var(--ion-color-dark)!important}ion-accordion ion-item[slot=header] legend{color:var(--dcf-color-gray-7)}}@media (prefers-color-scheme: dark){.dcf-fieldset{border:1px solid var(--dcf-color-step-400)}.dcf-fieldset .dcf-button-add{color:var(--ion-color-gray-2)}.dcf-fieldset.read,.dcf-fieldset.delete{border:1px solid var(--dcf-color-gray-6)}}.dcf-fieldset{padding-top:1rem;padding-bottom:1rem;background:var(--dcf-card-background);border-radius:6px}.dcf-fieldset.remove-border{border:none!important;padding:0!important;margin:0!important}.dcf-fieldset.open ion-accordion{margin-bottom:1rem}.dcf-fieldset.open ion-accordion.accordion-collapsing,.dcf-fieldset.open ion-accordion.accordion-collapsed{margin-bottom:1rem}.dcf-fieldset.read [slot=content],.dcf-fieldset.delete [slot=content]{padding-top:0!important}.dcf-fieldset.read ion-accordion,.dcf-fieldset.delete ion-accordion{margin-bottom:0rem!important}.dcf-fieldset ion-accordion{background:var(--dcf-card-background)}.dcf-fieldset ion-accordion ion-item[slot=header]{--border-color: transparent;--border-radius: 6px;--inner-border-width: 0;--padding-start: 12px}.dcf-fieldset ion-accordion ion-item[slot=header] legend{font-weight:600;font-size:1rem;margin:0}.dcf-fieldset ion-accordion [slot=content]{padding-top:1.5rem!important;padding-inline:.75rem}.dcf-not-unique-container{display:flex;justify-content:center;align-items:center;margin-bottom:1rem;flex:1 1 auto}.dcf-not-unique-container>div{display:flex;justify-content:center;align-items:center}.dcf-not-unique-container ion-icon{transform:translatey(2px);margin-right:5px}.dcf-fields-list{margin-bottom:1rem;padding:0!important}.dcf-fields-list ion-item{--min-height: 50px;--padding-top: .25rem;--padding-bottom: .25rem;--padding-start: .75rem;--padding-end: .75rem;--inner-padding-start: 0px !important;--inner-padding-end: 0px !important;--border-color: var(--dcf-color-gray-2) !important;border:1px solid transparent;box-sizing:border-box}.dcf-fields-list ion-item ion-icon.dcf-reorder-disabled{width:1rem;transform:translatey(2px);color:var(--dcf-color-gray-4)}.dcf-fields-list ion-item.updating{--background: rgba(var(--dcf-color-primary-rgb), .1) !important}.dcf-fields-list ion-item.not-unique{--background: rgba(var(--dcf-color-danger-rgb), .05) !important}.dcf-fields-list ion-item .dcf-subtitle{font-size:.8rem;color:var(--dcf-color-gray-7)}\n"] }]
5688
5982
  }], ctorParameters: () => [], propDecorators: { accordionComponent: [{
5689
5983
  type: ViewChild,
5690
5984
  args: ['accordionComponent', { static: false }]
@@ -7453,39 +7747,22 @@ let ListComponent = class ListComponent extends NgxDecafComponentDirective {
7453
7747
  */
7454
7748
  this.disableSort = false;
7455
7749
  /**
7456
- * @description Icon to display when the list is empty.
7457
- * @summary Specifies the icon shown in the empty state when no data is available.
7458
- * This can be any icon name supported by the application's icon system.
7459
- *
7460
- * @type {string | undefined}
7461
- * @default 'ti-database-exclamation'
7462
- * @memberOf ListComponent
7463
- */
7464
- this.emptyIcon = 'ti-database-exclamation';
7465
- /**
7466
- * @description Configuration for the empty state display.
7467
- * @summary Customizes how the empty state is displayed when no data is available.
7468
- * This includes the title, subtitle, button text, icon, and navigation link.
7469
- *
7470
- * @type {Partial<IListEmptyResult>}
7471
- * @default {
7472
- * title: 'empty.title',
7473
- * subtitle: 'empty.subtitle',
7474
- * showButton: false,
7475
- * icon: 'alert-circle-outline',
7476
- * buttonText: 'locale.empty.button',
7477
- * link: ''
7478
- * }
7479
- * @memberOf ListComponent
7480
- */
7481
- this.empty = {
7482
- title: 'empty.title',
7483
- subtitle: 'empty.subtitle',
7484
- showButton: false,
7485
- icon: 'alert-circle-outline',
7486
- buttonText: 'locale.empty.button',
7487
- link: ''
7488
- };
7750
+ * @description Configuration for the empty state display.
7751
+ * @summary Customizes how the empty state is displayed when no data is available.
7752
+ * This includes the title, subtitle, button text, icon, and navigation link.
7753
+ *
7754
+ * @type {Partial<IListEmptyOptions>}
7755
+ * @default {
7756
+ * title: 'empty.title',
7757
+ * subtitle: 'empty.subtitle',
7758
+ * showButton: false,
7759
+ * icon: 'alert-circle-outline',
7760
+ * buttonText: 'locale.empty.button',
7761
+ * link: ''
7762
+ * }
7763
+ * @memberOf ListComponent
7764
+ */
7765
+ this.empty = {};
7489
7766
  /**
7490
7767
  * @description The current page number in paginated mode.
7491
7768
  * @summary Tracks which page is currently being displayed when the component
@@ -7517,6 +7794,7 @@ let ListComponent = class ListComponent extends NgxDecafComponentDirective {
7517
7794
  * @memberOf ListComponent
7518
7795
  */
7519
7796
  this.skeletonData = new Array(2);
7797
+ this.searching = false;
7520
7798
  /**
7521
7799
  * @description The last page number that was displayed.
7522
7800
  * @summary Keeps track of the previously displayed page number, which is useful
@@ -7609,9 +7887,10 @@ let ListComponent = class ListComponent extends NgxDecafComponentDirective {
7609
7887
  this.disableSort = stringToBoolean(this.disableSort);
7610
7888
  if (typeof this.item?.['tag'] === 'boolean' && this.item?.['tag'] === true)
7611
7889
  this.item['tag'] = ComponentsTagNames.LIST_ITEM;
7890
+ this.empty = Object.assign({}, DefaultListEmptyOptions, this.empty);
7612
7891
  await this.refresh();
7613
- if (this.operations.includes(OperationKeys.CREATE) && this.route)
7614
- this.empty.link = `${this.route}/${OperationKeys.CREATE}`;
7892
+ // if(this.operations.includes(OperationKeys.CREATE) && this.route)
7893
+ // this.empty.link = `${this.route}/${OperationKeys.CREATE}`;
7615
7894
  if (!this.initialized)
7616
7895
  return this.parseProps(this);
7617
7896
  this.initialized = true;
@@ -7782,6 +8061,7 @@ let ListComponent = class ListComponent extends NgxDecafComponentDirective {
7782
8061
  * @memberOf ListComponent
7783
8062
  */
7784
8063
  async handleSearch(value) {
8064
+ this.searching = value !== undefined;
7785
8065
  if (this.type === ListComponentsTypes.INFINITE) {
7786
8066
  this.loadMoreData = false;
7787
8067
  if (value === undefined) {
@@ -8073,8 +8353,10 @@ let ListComponent = class ListComponent extends NgxDecafComponentDirective {
8073
8353
  if (!this.indexes)
8074
8354
  this.indexes = (Object.values(this.mapper) || [this.pk]);
8075
8355
  const condition = this.parseConditions(this.searchValue);
8356
+ this.changeDetectorRef.detectChanges();
8076
8357
  request = await this.parseResult(await repo.query(condition, (this.sortBy || this.pk), this.sortDirection));
8077
8358
  data = [];
8359
+ this.changeDetectorRef.detectChanges();
8078
8360
  }
8079
8361
  data = this.type === ListComponentsTypes.INFINITE ? [...(data).concat(request)] : [...request];
8080
8362
  }
@@ -8311,8 +8593,14 @@ let ListComponent = class ListComponent extends NgxDecafComponentDirective {
8311
8593
  return accum;
8312
8594
  }, []);
8313
8595
  }
8596
+ parseSearchValue() {
8597
+ if (typeof this.searchValue === Primitives.STRING)
8598
+ return this.searchValue || "";
8599
+ const searchValue = this.searchValue;
8600
+ return (searchValue?.query).map(item => `${item.index} ${item.condition} ${item.value}`).join(", ");
8601
+ }
8314
8602
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: ListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8315
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: ListComponent, isStandalone: true, selector: "ngx-decaf-list", inputs: { type: "type", showSearchbar: "showSearchbar", data: "data", source: "source", start: "start", limit: "limit", loadMoreData: "loadMoreData", lines: "lines", inset: "inset", scrollThreshold: "scrollThreshold", scrollPosition: "scrollPosition", loadingText: "loadingText", showRefresher: "showRefresher", loadingSpinner: "loadingSpinner", enableFilter: "enableFilter", sortDirection: "sortDirection", sortBy: "sortBy", disableSort: "disableSort", emptyIcon: "emptyIcon", empty: "empty" }, outputs: { refreshEvent: "refreshEvent", clickEvent: "clickEvent" }, host: { listeners: { "window:ListItemClickEvent": "handleClick($event)", "window:searchbarEvent": "handleSearch($event)", "window:BackButtonNavigationEndEvent": "refresh($event)" } }, usesInheritance: true, ngImport: i0, template: "\n@if(showRefresher) {\n <ion-refresher slot=\"fixed\" [pullFactor]=\"1\" [pullMin]=\"100\" [pullMax]=\"200\" (ionRefresh)=\"handleRefresh($event)\">\n <ion-refresher-content />\n </ion-refresher>\n}\n\n@if(showSearchbar && data?.length) {\n @if(model && enableFilter) {\n <ngx-decaf-filter\n [model]=\"model\"\n [sortDirection]=\"sortDirection\"\n [disableSort]=\"disableSort\"\n (filterEvent)=\"handleFilter($event)\"\n (searchEvent)=\"handleSearch($event)\"\n />\n } @else {\n <ngx-decaf-searchbar [emitEventToWindow]=\"false\" [debounce]=\"500\" (searchEvent)=\"handleSearch($event)\" />\n }\n}\n\n@if(data?.length) {\n <ion-list [id]=\"uid\" [inset]=\"inset\" [lines]=\"lines\" #component>\n @if(item?.tag) {\n @for(child of items; track trackItemFn($index, child)) {\n <ngx-decaf-component-renderer\n [tag]=\"item.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]='{\n item: child,\n mapper: mapper,\n route: route\n }'>\n </ngx-decaf-component-renderer>\n }\n } @else {\n <ng-content></ng-content>\n }\n </ion-list>\n\n @if(loadMoreData) {\n @if(pages > 0 && type === 'paginated' && !searchValue?.length) {\n <ngx-decaf-pagination\n [totalPages]=\"pages\"\n [current]=\"page\"\n (clickEvent)=\"handlePaginate($event)\"\n />\n\n } @else {\n <ion-infinite-scroll\n [class]=\"searchValue?.length ? 'dcf-hidden' : ''\"\n\n [position]=\"scrollPosition\"\n [threshold]=\"scrollThreshold\"\n (ionInfinite)=\"handleRefresh($event)\">\n <ion-infinite-scroll-content [loadingSpinner]=\"loadingSpinner\" [loadingText]=\"loadingText\" />\n </ion-infinite-scroll>\n }\n }\n} @else {\n @if(refreshing) {\n @for(skl of skeletonData; track $index) {\n <ion-item>\n <ion-thumbnail slot=\"start\">\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n </ion-thumbnail>\n <ion-label>\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n </ion-label>\n </ion-item>\n }\n\n } @else {\n @if(!searchValue?.length) {\n <ngx-decaf-empty-state\n [title]=\"(locale + '.'+ empty.title) | translate\"\n [subtitle]=\"(locale + '.'+ empty.subtitle) | translate\"\n [buttonText]=\"empty.showButton ? (locale + '.'+ empty.button | translate) : ''\"\n [buttonLink]=\"empty.showButton ? empty.route : ''\"\n />\n } @else {\n <ngx-decaf-empty-state\n icon=\"search-outline\"\n ngClass=\"empty-search\"\n [translatable]=\"true\"\n title=\"search.title\"\n subtitle=\"search.subtitle\"\n [searchValue]=\"searchValue\"\n />\n }\n }\n}\n\n", styles: ["ion-infinite-scroll{max-height:50px}ion-infinite-scroll:not(.infinite-scroll-loading) ::ng-deep{max-height:1.5rem}ion-infinite-scroll ::ng-deep ion-spinner{--color: var(--dcf-color-primary);padding-top:1rem}@media (max-width: 768px){#end,[slot=end]{display:none!important}}\n"], dependencies: [{ kind: "component", type: IonRefresher, selector: "ion-refresher", inputs: ["closeDuration", "disabled", "mode", "pullFactor", "pullMax", "pullMin", "snapbackDuration"] }, { kind: "component", type: PaginationComponent, selector: "ngx-decaf-pagination", inputs: ["totalPages", "current"], outputs: ["clickEvent"] }, { kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonThumbnail, selector: "ion-thumbnail" }, { kind: "component", type: IonSkeletonText, selector: "ion-skeleton-text", inputs: ["animated"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonRefresherContent, selector: "ion-refresher-content", inputs: ["pullingIcon", "pullingText", "refreshingSpinner", "refreshingText"] }, { kind: "component", type: IonInfiniteScroll, selector: "ion-infinite-scroll", inputs: ["disabled", "position", "threshold"] }, { kind: "component", type: IonInfiniteScrollContent, selector: "ion-infinite-scroll-content", inputs: ["loadingSpinner", "loadingText"] }, { kind: "component", type: SearchbarComponent, selector: "ngx-decaf-searchbar", inputs: ["autocomplete", "autocorrect", "animated", "buttonCancelText", "clearIcon", "color", "debounce", "disabled", "enterkeyhint", "inputmode", "placeholder", "searchIcon", "showCancelButton", "showClearButton", "spellcheck", "type", "value", "queryKeys", "isVisible", "wrapper", "wrapperColor", "emitEventToWindow"], outputs: ["searchEvent"] }, { kind: "component", type: EmptyStateComponent, selector: "ngx-decaf-empty-state", inputs: ["title", "titleColor", "subtitle", "subtitleColor", "showIcon", "icon", "iconSize", "iconColor", "buttonLink", "buttonText", "buttonFill", "buttonColor", "buttonSize", "searchValue"] }, { kind: "component", type: FilterComponent, selector: "ngx-decaf-filter", inputs: ["indexes", "conditions", "sortBy", "disableSort"], outputs: ["filterEvent", "searchEvent"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "children", "projectable", "model", "parentComponent", "parent"], outputs: ["listenEvent"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
8603
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: ListComponent, isStandalone: true, selector: "ngx-decaf-list", inputs: { type: "type", showSearchbar: "showSearchbar", data: "data", source: "source", start: "start", limit: "limit", loadMoreData: "loadMoreData", lines: "lines", inset: "inset", scrollThreshold: "scrollThreshold", scrollPosition: "scrollPosition", loadingText: "loadingText", showRefresher: "showRefresher", loadingSpinner: "loadingSpinner", enableFilter: "enableFilter", sortDirection: "sortDirection", sortBy: "sortBy", disableSort: "disableSort", empty: "empty" }, outputs: { refreshEvent: "refreshEvent", clickEvent: "clickEvent" }, host: { listeners: { "window:ListItemClickEvent": "handleClick($event)", "window:searchbarEvent": "handleSearch($event)", "window:BackButtonNavigationEndEvent": "refresh($event)" } }, usesInheritance: true, ngImport: i0, template: "\n@if(showRefresher) {\n <ion-refresher slot=\"fixed\" [pullFactor]=\"1\" [pullMin]=\"100\" [pullMax]=\"200\" (ionRefresh)=\"handleRefresh($event)\">\n <ion-refresher-content />\n </ion-refresher>\n}\n\n@if(showSearchbar) {\n @if(model && enableFilter) {\n @if(data?.length || searching) {\n <ngx-decaf-filter\n [model]=\"model\"\n [sortDirection]=\"sortDirection\"\n [disableSort]=\"disableSort\"\n (filterEvent)=\"handleFilter($event)\"\n (searchEvent)=\"handleSearch($event)\"\n />\n }\n } @else {\n <ngx-decaf-searchbar [emitEventToWindow]=\"false\" [debounce]=\"500\" (searchEvent)=\"handleSearch($event)\" />\n }\n}\n\n@if(data?.length) {\n <ion-list [id]=\"uid\" [inset]=\"inset\" [lines]=\"lines\" #component>\n @if(item?.tag) {\n @for(child of items; track trackItemFn($index, child)) {\n <ngx-decaf-component-renderer\n [tag]=\"item.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]='{\n item: child,\n mapper: mapper,\n route: route\n }'>\n </ngx-decaf-component-renderer>\n }\n } @else {\n <ng-content></ng-content>\n }\n </ion-list>\n\n @if(loadMoreData) {\n @if(pages > 0 && type === 'paginated' && !searchValue?.length) {\n <ngx-decaf-pagination\n [totalPages]=\"pages\"\n [current]=\"page\"\n (clickEvent)=\"handlePaginate($event)\"\n />\n\n } @else {\n <ion-infinite-scroll\n [class]=\"searchValue?.length ? 'dcf-hidden' : ''\"\n\n [position]=\"scrollPosition\"\n [threshold]=\"scrollThreshold\"\n (ionInfinite)=\"handleRefresh($event)\">\n <ion-infinite-scroll-content [loadingSpinner]=\"loadingSpinner\" [loadingText]=\"loadingText\" />\n </ion-infinite-scroll>\n }\n }\n} @else {\n @if(refreshing) {\n @for(skl of skeletonData; track $index) {\n <ion-item>\n <ion-thumbnail slot=\"start\">\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n </ion-thumbnail>\n <ion-label>\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n </ion-label>\n </ion-item>\n }\n\n } @else {\n @if(!searching) {\n <ngx-decaf-empty-state\n [title]=\"(locale + '.'+ empty.title) | translate\"\n [model]=\"model\"\n [icon]=\"empty.icon\"\n [subtitle]=\"(locale + '.'+ empty.subtitle) | translate\" />\n } @else {\n <ngx-decaf-empty-state\n icon=\"search-outline\"\n [model]=\"model\"\n className=\"empty-search\"\n [translatable]=\"true\"\n [title]=\"locale + '.search.title' | translate\"\n [subtitle]=\"locale + '.search.subtitle' | translate: {'0': parseSearchValue()}\"\n [searchValue]=\"searchValue\"\n />\n }\n }\n}\n\n", styles: ["ion-infinite-scroll{max-height:50px}ion-infinite-scroll:not(.infinite-scroll-loading) ::ng-deep{max-height:1.5rem}ion-infinite-scroll ::ng-deep ion-spinner{--color: var(--dcf-color-primary);padding-top:1rem}@media (max-width: 768px){#end,[slot=end]{display:none!important}}\n"], dependencies: [{ kind: "component", type: IonRefresher, selector: "ion-refresher", inputs: ["closeDuration", "disabled", "mode", "pullFactor", "pullMax", "pullMin", "snapbackDuration"] }, { kind: "component", type: PaginationComponent, selector: "ngx-decaf-pagination", inputs: ["totalPages", "current"], outputs: ["clickEvent"] }, { kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonThumbnail, selector: "ion-thumbnail" }, { kind: "component", type: IonSkeletonText, selector: "ion-skeleton-text", inputs: ["animated"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonRefresherContent, selector: "ion-refresher-content", inputs: ["pullingIcon", "pullingText", "refreshingSpinner", "refreshingText"] }, { kind: "component", type: IonInfiniteScroll, selector: "ion-infinite-scroll", inputs: ["disabled", "position", "threshold"] }, { kind: "component", type: IonInfiniteScrollContent, selector: "ion-infinite-scroll-content", inputs: ["loadingSpinner", "loadingText"] }, { kind: "component", type: SearchbarComponent, selector: "ngx-decaf-searchbar", inputs: ["autocomplete", "autocorrect", "animated", "buttonCancelText", "clearIcon", "color", "debounce", "disabled", "enterkeyhint", "inputmode", "placeholder", "searchIcon", "showCancelButton", "showClearButton", "spellcheck", "type", "value", "queryKeys", "isVisible", "wrapper", "wrapperColor", "emitEventToWindow"], outputs: ["searchEvent"] }, { kind: "component", type: EmptyStateComponent, selector: "ngx-decaf-empty-state", inputs: ["title", "titleColor", "subtitle", "subtitleColor", "showIcon", "icon", "iconSize", "iconColor", "buttonLink", "buttonText", "buttonFill", "buttonColor", "buttonSize", "searchValue"] }, { kind: "component", type: FilterComponent, selector: "ngx-decaf-filter", inputs: ["indexes", "conditions", "sortBy", "disableSort"], outputs: ["filterEvent", "searchEvent"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "children", "projectable", "model", "parentComponent", "parent"], outputs: ["listenEvent"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
8316
8604
  };
8317
8605
  ListComponent = __decorate([
8318
8606
  Dynamic(),
@@ -8339,7 +8627,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
8339
8627
  EmptyStateComponent,
8340
8628
  FilterComponent,
8341
8629
  ComponentRendererComponent
8342
- ], template: "\n@if(showRefresher) {\n <ion-refresher slot=\"fixed\" [pullFactor]=\"1\" [pullMin]=\"100\" [pullMax]=\"200\" (ionRefresh)=\"handleRefresh($event)\">\n <ion-refresher-content />\n </ion-refresher>\n}\n\n@if(showSearchbar && data?.length) {\n @if(model && enableFilter) {\n <ngx-decaf-filter\n [model]=\"model\"\n [sortDirection]=\"sortDirection\"\n [disableSort]=\"disableSort\"\n (filterEvent)=\"handleFilter($event)\"\n (searchEvent)=\"handleSearch($event)\"\n />\n } @else {\n <ngx-decaf-searchbar [emitEventToWindow]=\"false\" [debounce]=\"500\" (searchEvent)=\"handleSearch($event)\" />\n }\n}\n\n@if(data?.length) {\n <ion-list [id]=\"uid\" [inset]=\"inset\" [lines]=\"lines\" #component>\n @if(item?.tag) {\n @for(child of items; track trackItemFn($index, child)) {\n <ngx-decaf-component-renderer\n [tag]=\"item.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]='{\n item: child,\n mapper: mapper,\n route: route\n }'>\n </ngx-decaf-component-renderer>\n }\n } @else {\n <ng-content></ng-content>\n }\n </ion-list>\n\n @if(loadMoreData) {\n @if(pages > 0 && type === 'paginated' && !searchValue?.length) {\n <ngx-decaf-pagination\n [totalPages]=\"pages\"\n [current]=\"page\"\n (clickEvent)=\"handlePaginate($event)\"\n />\n\n } @else {\n <ion-infinite-scroll\n [class]=\"searchValue?.length ? 'dcf-hidden' : ''\"\n\n [position]=\"scrollPosition\"\n [threshold]=\"scrollThreshold\"\n (ionInfinite)=\"handleRefresh($event)\">\n <ion-infinite-scroll-content [loadingSpinner]=\"loadingSpinner\" [loadingText]=\"loadingText\" />\n </ion-infinite-scroll>\n }\n }\n} @else {\n @if(refreshing) {\n @for(skl of skeletonData; track $index) {\n <ion-item>\n <ion-thumbnail slot=\"start\">\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n </ion-thumbnail>\n <ion-label>\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n </ion-label>\n </ion-item>\n }\n\n } @else {\n @if(!searchValue?.length) {\n <ngx-decaf-empty-state\n [title]=\"(locale + '.'+ empty.title) | translate\"\n [subtitle]=\"(locale + '.'+ empty.subtitle) | translate\"\n [buttonText]=\"empty.showButton ? (locale + '.'+ empty.button | translate) : ''\"\n [buttonLink]=\"empty.showButton ? empty.route : ''\"\n />\n } @else {\n <ngx-decaf-empty-state\n icon=\"search-outline\"\n ngClass=\"empty-search\"\n [translatable]=\"true\"\n title=\"search.title\"\n subtitle=\"search.subtitle\"\n [searchValue]=\"searchValue\"\n />\n }\n }\n}\n\n", styles: ["ion-infinite-scroll{max-height:50px}ion-infinite-scroll:not(.infinite-scroll-loading) ::ng-deep{max-height:1.5rem}ion-infinite-scroll ::ng-deep ion-spinner{--color: var(--dcf-color-primary);padding-top:1rem}@media (max-width: 768px){#end,[slot=end]{display:none!important}}\n"] }]
8630
+ ], template: "\n@if(showRefresher) {\n <ion-refresher slot=\"fixed\" [pullFactor]=\"1\" [pullMin]=\"100\" [pullMax]=\"200\" (ionRefresh)=\"handleRefresh($event)\">\n <ion-refresher-content />\n </ion-refresher>\n}\n\n@if(showSearchbar) {\n @if(model && enableFilter) {\n @if(data?.length || searching) {\n <ngx-decaf-filter\n [model]=\"model\"\n [sortDirection]=\"sortDirection\"\n [disableSort]=\"disableSort\"\n (filterEvent)=\"handleFilter($event)\"\n (searchEvent)=\"handleSearch($event)\"\n />\n }\n } @else {\n <ngx-decaf-searchbar [emitEventToWindow]=\"false\" [debounce]=\"500\" (searchEvent)=\"handleSearch($event)\" />\n }\n}\n\n@if(data?.length) {\n <ion-list [id]=\"uid\" [inset]=\"inset\" [lines]=\"lines\" #component>\n @if(item?.tag) {\n @for(child of items; track trackItemFn($index, child)) {\n <ngx-decaf-component-renderer\n [tag]=\"item.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]='{\n item: child,\n mapper: mapper,\n route: route\n }'>\n </ngx-decaf-component-renderer>\n }\n } @else {\n <ng-content></ng-content>\n }\n </ion-list>\n\n @if(loadMoreData) {\n @if(pages > 0 && type === 'paginated' && !searchValue?.length) {\n <ngx-decaf-pagination\n [totalPages]=\"pages\"\n [current]=\"page\"\n (clickEvent)=\"handlePaginate($event)\"\n />\n\n } @else {\n <ion-infinite-scroll\n [class]=\"searchValue?.length ? 'dcf-hidden' : ''\"\n\n [position]=\"scrollPosition\"\n [threshold]=\"scrollThreshold\"\n (ionInfinite)=\"handleRefresh($event)\">\n <ion-infinite-scroll-content [loadingSpinner]=\"loadingSpinner\" [loadingText]=\"loadingText\" />\n </ion-infinite-scroll>\n }\n }\n} @else {\n @if(refreshing) {\n @for(skl of skeletonData; track $index) {\n <ion-item>\n <ion-thumbnail slot=\"start\">\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n </ion-thumbnail>\n <ion-label>\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n </ion-label>\n </ion-item>\n }\n\n } @else {\n @if(!searching) {\n <ngx-decaf-empty-state\n [title]=\"(locale + '.'+ empty.title) | translate\"\n [model]=\"model\"\n [icon]=\"empty.icon\"\n [subtitle]=\"(locale + '.'+ empty.subtitle) | translate\" />\n } @else {\n <ngx-decaf-empty-state\n icon=\"search-outline\"\n [model]=\"model\"\n className=\"empty-search\"\n [translatable]=\"true\"\n [title]=\"locale + '.search.title' | translate\"\n [subtitle]=\"locale + '.search.subtitle' | translate: {'0': parseSearchValue()}\"\n [searchValue]=\"searchValue\"\n />\n }\n }\n}\n\n", styles: ["ion-infinite-scroll{max-height:50px}ion-infinite-scroll:not(.infinite-scroll-loading) ::ng-deep{max-height:1.5rem}ion-infinite-scroll ::ng-deep ion-spinner{--color: var(--dcf-color-primary);padding-top:1rem}@media (max-width: 768px){#end,[slot=end]{display:none!important}}\n"] }]
8343
8631
  }], ctorParameters: () => [], propDecorators: { type: [{
8344
8632
  type: Input
8345
8633
  }], showSearchbar: [{
@@ -8376,8 +8664,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
8376
8664
  type: Input
8377
8665
  }], disableSort: [{
8378
8666
  type: Input
8379
- }], emptyIcon: [{
8380
- type: Input
8381
8667
  }], empty: [{
8382
8668
  type: Input
8383
8669
  }], refreshEvent: [{
@@ -8786,7 +9072,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
8786
9072
  args: ['window:resize', ['$event']]
8787
9073
  }] } });
8788
9074
 
8789
- let SteppedFormComponent = class SteppedFormComponent extends NgxParentComponentDirective$1 {
9075
+ let SteppedFormComponent = class SteppedFormComponent extends NgxParentComponentDirective {
8790
9076
  /**
8791
9077
  * @description Creates an instance of SteppedFormComponent.
8792
9078
  * @summary Initializes a new SteppedFormComponent instance and registers the required
@@ -8892,17 +9178,6 @@ let SteppedFormComponent = class SteppedFormComponent extends NgxParentComponent
8892
9178
  * @memberOf SteppedFormComponent
8893
9179
  */
8894
9180
  this.pagesArray = [];
8895
- /**
8896
- * @description Angular Location service.
8897
- * @summary Injected service that provides access to the browser's URL and history.
8898
- * This service is used for interacting with the browser's history API, allowing
8899
- * for back navigation and URL manipulation outside of Angular's router.
8900
- *
8901
- * @private
8902
- * @type {Location}
8903
- * @memberOf CrudFormComponent
8904
- */
8905
- this.location = inject(Location);
8906
9181
  /**
8907
9182
  * @description Event emitter for form submission.
8908
9183
  * @summary Emits events when the form is submitted, typically on the last page
@@ -8938,12 +9213,16 @@ let SteppedFormComponent = class SteppedFormComponent extends NgxParentComponent
8938
9213
  * @memberOf SteppedFormComponent
8939
9214
  */
8940
9215
  async ngOnInit() {
8941
- console.log(this);
8942
9216
  if (!this.locale)
8943
9217
  this.locale = getLocaleContext("SteppedFormComponent");
8944
9218
  this.activePage = this.startPage;
8945
- if (!this.pageTitles.length)
8946
- this.pageTitles = Array.from({ length: this.pages }, () => ({ title: '', description: '', rendered: this.paginated }));
9219
+ if (typeof this.pages === 'object') {
9220
+ this.pageTitles = this.pages;
9221
+ }
9222
+ else {
9223
+ if (!this.pageTitles.length)
9224
+ this.pageTitles = Array.from({ length: this.pages }, () => ({ title: '', description: '' }));
9225
+ }
8947
9226
  this.pages = this.pageTitles.length;
8948
9227
  if (this.paginated) {
8949
9228
  this.children = [...this.children.map((c) => {
@@ -8969,6 +9248,7 @@ let SteppedFormComponent = class SteppedFormComponent extends NgxParentComponent
8969
9248
  });
8970
9249
  this.activeFormGroup = this.formGroup;
8971
9250
  }
9251
+ this.initialized = true;
8972
9252
  }
8973
9253
  /**
8974
9254
  * @description Cleanup method called when the component is destroyed.
@@ -9087,7 +9367,7 @@ let SteppedFormComponent = class SteppedFormComponent extends NgxParentComponent
9087
9367
  this.timerSubscription = timer(10).subscribe(() => this.activeChildren = this.children.filter(c => c.props?.['page'] === page));
9088
9368
  }
9089
9369
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: SteppedFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
9090
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: SteppedFormComponent, isStandalone: true, selector: "ngx-decaf-stepped-form", inputs: { children: "children", paginated: "paginated", pages: "pages", pageTitles: "pageTitles", operation: "operation", startPage: "startPage", formGroup: "formGroup" }, outputs: { submitEvent: "submitEvent" }, host: { properties: { "attr.id": "uid" } }, usesInheritance: true, ngImport: i0, template: "<form class=\"dcf-steped-form\" [class.paginated]=\"paginated\" novalidate>\n @if(paginated) {\n <div class=\"dcf-page-steps\">\n <div class=\"dcf-grid dcf-grid-collapse skip\">\n @for(page of pageTitles; track $index;) {\n <div class=\"dcf-flex dcf-flex-middle\">\n <div class=\"dcf-step\" [class.dcf-active]=\"activePage === $index + 1\" [class.dcf-passed]=\"($index + 1) < activePage\">{{ $index + 1 }}</div>\n @if((page?.title || page?.description)) {\n <div class=\"dcf-information dcf-visible@s\">\n @if(page?.title) {\n <div class=\"dcf-title\">{{ page?.title | translate }}</div>\n }\n @if(page?.description) {\n <div class=\"dcf-description\">{{ page?.description | translate }}</div>\n }\n <div class=\"dcf-separator\"></div>\n </div>\n }\n @if($index < pageTitles.length - 1) {\n <div class=\"dcf-arrow-container\">\n <svg width=\"8\" height=\"12\" viewBox=\"0 0 8 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M1.5 1L6.5 6L1.5 11\" />\n </svg>\n </div>\n }\n </div>\n }\n </div>\n </div>\n\n @if(pageTitles[activePage - 1]?.title || pageTitles[activePage - 1]?.description) {\n <div class=\"dcf-current-step\">\n <div>\n @if(pageTitles[activePage - 1]?.title) {\n <div class=\"dcf-title\">{{ pageTitles[activePage - 1]?.title | translate }}</div>\n }\n @if(pageTitles[activePage - 1]?.description) {\n <div class=\"dcf-description\">{{ pageTitles[activePage - 1]?.description | translate }}</div>\n }\n </div>\n </div>\n }\n\n @if(formGroup) {\n <!-- <ngx-decaf-layout\n [children]=\"children || []\"\n [parentComponent]=\"formGroup || parentComponent\"\n gap=\"small\"\n [initializeProps]=\"false\"\n [rows]=\"rows ?? 1\"\n [cols]=\"cols ?? 1\" /> -->\n @for(child of activeChildren; track $index) {\n <div class=\"dcf-step-form-container\">\n <ngx-decaf-component-renderer\n [tag]=\"child?.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n </div>\n\n\n }\n } @else {\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n <br />\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n }\n <div class=\"dcf-buttons-container dcf-grid dcf-grid-collapse dcf-flex dcf-flex-left\">\n <div class=\"dcf-width-1-2@s\">\n <ion-button color=\"light\" (click)=\"handleBack()\" [disabled]=\"activePage <= 1\">\n <!-- <ion-icon aria-hidden=\"true\" name=\"arrow-back-outline\"></ion-icon> -->\n {{locale + '.previous' | translate}}\n </ion-button>\n </div>\n\n <div class=\"dcf-width-1-2@s\">\n <ion-button fill=\"solid\" (click)=\"handleNext(activePage === pages ? true : false)\">\n @if(activePage === pages) {\n {{locale + '.submit' | translate}}\n } @else {\n {{locale + '.next' | translate}}\n <!-- <ion-icon aria-hidden=\"true\" name=\"arrow-forward-outline\"></ion-icon> -->\n }\n </ion-button>\n </div>\n </div>\n } @else {\n <div class=\"dcf-single-step\">\n @for (item of children; track $index) {\n <ion-card>\n <ion-card-content>\n @if(item.title || item.description) {\n <div class=\"dcf-information\">\n <div>\n @if(item.title) {\n <div class=\"dcf-title\">{{ item.title | translate }}</div>\n }\n @if(item.description) {\n <div class=\"dcf-description\">{{ item.description | translate }}</div>\n }\n </div>\n </div>\n }\n <div class=\"dcf-grid dcf-grid-small dcf-child-width-1-1\">\n @for (child of item.items; track $index) {\n <ngx-decaf-component-renderer\n [class]=\"'dcf-step-container ' + (child?.props?.className ? child.props.className + ' ' : ' ') + child.tag\"\n [tag]=\"child?.tag\"\n [projectable]=\"false\"\n (listenEvent)=\"handleEvent($event)\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n }\n </div>\n </ion-card-content>\n </ion-card>\n }\n <div class=\"dcf-buttons-container dcf-grid dcf-grid-small dcf-flex dcf-flex-right\">\n <div class=\"dcf-width-auto@s dcf-width-1-1\">\n <ion-button color=\"light\" (click)=\"handleBack()\">\n {{locale + '.cancel' | translate}}\n </ion-button>\n </div>\n\n <div class=\"dcf-width-auto@s dcf-width-1-1\">\n <ion-button fill=\"solid\" (click)=\"handleNext(true)\">\n {{locale + '.submit' | translate}}\n </ion-button>\n </div>\n </div>\n </div>\n }\n</form>\n", styles: [".dcf-buttons-container{margin-top:1.8rem;margin-bottom:0}@media (min-width: 639px){.dcf-buttons-container.dcf-flex div:nth-child(2){display:flex;justify-content:flex-end}}@media (max-width: 638px){.dcf-buttons-container.dcf-flex div{width:100%}.dcf-buttons-container.dcf-flex ion-button{width:100%;margin-bottom:1rem}}.dcf-steped-form.paginated{padding:2rem 1rem}.dcf-page-steps{display:flex;justify-content:center;align-items:center;margin-bottom:2rem;overflow-x:auto;flex-wrap:nowrap}.dcf-page-steps .dcf-grid{display:flex!important;flex-wrap:nowrap!important;align-items:center}.dcf-step{height:38px;min-width:38px;width:38px;background:var(--dcf-color-gray-2);margin:0;display:flex;color:var(--dcf-color-gray-7);justify-content:center;align-items:center;font-size:1rem;font-weight:600;border-radius:var(--dcf-border-radius)}.dcf-step.dcf-active{color:var(--dcf-color-light);background:var(--ion-color-primary);box-shadow:0 2px 6px #144c714d}.dcf-step.dcf-passed{color:var(--dcf-color-primary-shade);background:var(--dcf-color-gray-3)}.dcf-information{padding-left:.5rem}.dcf-title{font-size:.875rem;font-weight:600;margin:0;color:var(--dcf-color-gray-7)}.dcf-description{font-size:.8rem;font-weight:500;margin:0;margin-top:.25rem;color:var(--dcf-color-gray-4)}.dcf-arrow-container{display:flex;align-items:center;justify-content:center;padding:0 .5rem;height:38px}.dcf-arrow-container{display:flex;align-items:center;justify-content:center;padding:0 1rem;height:40px}.dcf-arrow-container svg{width:1rem;height:1rem;stroke:var(--dcf-color-gray-8);stroke-opacity:.7;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round}ion-button[color=light]{--background: var(--dcf-color-gray-7) !important}.dcf-current-step{margin-top:-.5rem!important;margin-bottom:1.75rem!important;display:flex;align-items:center;justify-content:center}@media (min-width: 639px){.dcf-current-step{display:none}}.dcf-single-step .dcf-information{margin-bottom:1rem}.dcf-single-step .dcf-step-container:not(.ngx-decaf-fieldset){padding-bottom:1.5rem;padding-top:.5rem}.dcf-single-step ion-card{margin-bottom:1.5rem}.dcf-single-step ion-card .dcf-information{margin-top:.75rem}.dcf-step-form-container{margin-bottom:1.75rem!important}::ng-deep ngx-decaf-component-renderer.ngx-decaf-fieldset,::ng-deep ngx-decaf-fieldset{padding-top:0!important;padding-bottom:0!important}::ng-deep ngx-decaf-component-renderer.ngx-decaf-fieldset ion-button,::ng-deep ngx-decaf-fieldset ion-button{margin-top:1rem!important}\n"], dependencies: [{ 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: "component", type: IonSkeletonText, selector: "ion-skeleton-text", inputs: ["animated"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "children", "projectable", "model", "parentComponent", "parent"], outputs: ["listenEvent"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
9370
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: SteppedFormComponent, isStandalone: true, selector: "ngx-decaf-stepped-form", inputs: { children: "children", paginated: "paginated", pages: "pages", pageTitles: "pageTitles", operation: "operation", startPage: "startPage", formGroup: "formGroup" }, outputs: { submitEvent: "submitEvent" }, usesInheritance: true, ngImport: i0, template: "<form class=\"dcf-steped-form\" [class.paginated]=\"paginated\" novalidate>\n @if(paginated) {\n <div class=\"dcf-page-steps\">\n <div class=\"dcf-grid dcf-grid-collapse skip\">\n @for(page of pageTitles; track $index;) {\n <div class=\"dcf-flex dcf-flex-middle\">\n <div class=\"dcf-step\" [class.dcf-active]=\"activePage === $index + 1\" [class.dcf-passed]=\"($index + 1) < activePage\">{{ $index + 1 }}</div>\n @if((page?.title || page?.description)) {\n <div class=\"dcf-information dcf-visible@s\">\n @if(page?.title) {\n <div class=\"dcf-title\">{{ page?.title | translate }}</div>\n }\n @if(page?.description) {\n <div class=\"dcf-description\">{{ page?.description | translate }}</div>\n }\n <div class=\"dcf-separator\"></div>\n </div>\n }\n @if($index < pageTitles.length - 1) {\n <div class=\"dcf-arrow-container\">\n <svg width=\"8\" height=\"12\" viewBox=\"0 0 8 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M1.5 1L6.5 6L1.5 11\" />\n </svg>\n </div>\n }\n </div>\n }\n </div>\n </div>\n\n @if(pageTitles[activePage - 1]?.title || pageTitles[activePage - 1]?.description) {\n <div class=\"dcf-current-step\">\n <div>\n @if(pageTitles[activePage - 1]?.title) {\n <div class=\"dcf-title\">{{ pageTitles[activePage - 1]?.title | translate }}</div>\n }\n @if(pageTitles[activePage - 1]?.description) {\n <div class=\"dcf-description\">{{ pageTitles[activePage - 1]?.description | translate }}</div>\n }\n </div>\n </div>\n }\n\n @if(initialized && activeChildren?.length) {\n <ngx-decaf-layout\n [children]=\"activeChildren || []\"\n [parentComponent]=\"formGroup || parentComponent\"\n gap=\"small\"\n [rows]=\"rows\"\n [cols]=\"cols\"\n [match]=\"false\"\n\n />\n <!-- @for(child of activeChildren; track $index) {\n <div class=\"dcf-step-form-container\">\n <ngx-decaf-component-renderer\n [tag]=\"child?.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n </div>\n\n\n } -->\n } @else {\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n <br />\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n }\n <div class=\"dcf-buttons-container dcf-grid dcf-grid-collapse dcf-flex dcf-flex-left\">\n <div class=\"dcf-width-1-2@s\">\n <ion-button color=\"light\" (click)=\"handleBack()\" [disabled]=\"activePage <= 1\">\n <!-- <ion-icon aria-hidden=\"true\" name=\"arrow-back-outline\"></ion-icon> -->\n {{locale + '.previous' | translate}}\n </ion-button>\n </div>\n\n <div class=\"dcf-width-1-2@s\">\n <ion-button fill=\"solid\" (click)=\"handleNext(activePage === pages ? true : false)\">\n @if(activePage === pages) {\n {{locale + '.submit' | translate}}\n } @else {\n {{locale + '.next' | translate}}\n <!-- <ion-icon aria-hidden=\"true\" name=\"arrow-forward-outline\"></ion-icon> -->\n }\n </ion-button>\n </div>\n </div>\n } @else {\n <div class=\"dcf-single-step\">\n @for (item of children; track $index) {\n <ion-card>\n <ion-card-content>\n @if(item.title || item.description) {\n <div class=\"dcf-information\">\n <div>\n @if(item.title) {\n <div class=\"dcf-title\">{{ item.title | translate }}</div>\n }\n @if(item.description) {\n <div class=\"dcf-description\">{{ item.description | translate }}</div>\n }\n </div>\n </div>\n }\n <div>\n @if(initialized && item.items?.length) {\n <div>\n <ngx-decaf-layout\n [children]=\"item.items || []\"\n [parentComponent]=\"formGroup || parentComponent\"\n gap=\"small\"\n [rows]=\"rows\"\n [cols]=\"cols\"\n [match]=\"false\"\n\n />\n </div>\n\n }\n </div>\n </ion-card-content>\n </ion-card>\n }\n <div class=\"dcf-buttons-container dcf-grid dcf-grid-small dcf-flex dcf-flex-right\">\n <div class=\"dcf-width-auto@s dcf-width-1-1\">\n <ion-button color=\"light\" (click)=\"handleBack()\">\n {{locale + '.cancel' | translate}}\n </ion-button>\n </div>\n\n <div class=\"dcf-width-auto@s dcf-width-1-1\">\n <ion-button fill=\"solid\" (click)=\"handleNext(true)\">\n {{locale + '.submit' | translate}}\n </ion-button>\n </div>\n </div>\n </div>\n }\n</form>\n", styles: [".dcf-buttons-container{margin-top:1.8rem;margin-bottom:0}@media (min-width: 639px){.dcf-buttons-container.dcf-flex div:nth-child(2){display:flex;justify-content:flex-end}}@media (max-width: 638px){.dcf-buttons-container.dcf-flex div{width:100%}.dcf-buttons-container.dcf-flex ion-button{width:100%;margin-bottom:1rem}}.dcf-steped-form.paginated{padding:2rem 1rem}.dcf-page-steps{display:flex;justify-content:center;align-items:center;margin-bottom:2rem;overflow-x:auto;flex-wrap:nowrap}.dcf-page-steps .dcf-grid{display:flex!important;flex-wrap:nowrap!important;align-items:center}.dcf-step{height:38px;min-width:38px;width:38px;background:var(--dcf-color-gray-2);margin:0;display:flex;color:var(--dcf-color-gray-7);justify-content:center;align-items:center;font-size:1rem;font-weight:600;border-radius:var(--dcf-border-radius)}.dcf-step.dcf-active{color:var(--dcf-color-light);background:var(--ion-color-primary);box-shadow:0 2px 6px #144c714d}.dcf-step.dcf-passed{color:var(--dcf-color-primary-shade);background:var(--dcf-color-gray-3)}.dcf-information{padding-left:.5rem}.dcf-title{font-size:.875rem;font-weight:600;margin:0;color:var(--dcf-color-gray-7)}.dcf-description{font-size:.8rem;font-weight:500;margin:0;margin-top:.25rem;color:var(--dcf-color-gray-4)}.dcf-arrow-container{display:flex;align-items:center;justify-content:center;padding:0 .5rem;height:38px}.dcf-arrow-container{display:flex;align-items:center;justify-content:center;padding:0 1rem;height:40px}.dcf-arrow-container svg{width:1rem;height:1rem;stroke:var(--dcf-color-gray-8);stroke-opacity:.7;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round}ion-button[color=light]{--background: var(--dcf-color-gray-7) !important}.dcf-current-step{margin-top:-.5rem!important;margin-bottom:1.75rem!important;display:flex;align-items:center;justify-content:center}@media (min-width: 639px){.dcf-current-step{display:none}}.dcf-single-step .dcf-information{margin-bottom:1rem}.dcf-single-step .dcf-step-container:not(.ngx-decaf-fieldset){padding-bottom:1.5rem;padding-top:.5rem}.dcf-single-step ion-card{margin-bottom:1.5rem}.dcf-single-step ion-card .dcf-information{margin-top:.75rem}.dcf-step-form-container{margin-bottom:1.75rem!important}::ng-deep ngx-decaf-component-renderer.ngx-decaf-fieldset,::ng-deep ngx-decaf-fieldset{padding-top:0!important;padding-bottom:0!important}::ng-deep ngx-decaf-component-renderer.ngx-decaf-fieldset ion-button,::ng-deep ngx-decaf-fieldset ion-button{margin-top:1rem!important}\n"], dependencies: [{ 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: "component", type: IonSkeletonText, selector: "ion-skeleton-text", inputs: ["animated"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: LayoutComponent, selector: "ngx-decaf-layout", inputs: ["gap", "breakpoint", "grid", "match"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
9091
9371
  };
9092
9372
  SteppedFormComponent = __decorate([
9093
9373
  Dynamic(),
@@ -9101,9 +9381,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
9101
9381
  IonSkeletonText,
9102
9382
  IonText,
9103
9383
  IonButton,
9104
- LayoutComponent,
9105
- ComponentRendererComponent
9106
- ], standalone: true, host: { '[attr.id]': 'uid' }, template: "<form class=\"dcf-steped-form\" [class.paginated]=\"paginated\" novalidate>\n @if(paginated) {\n <div class=\"dcf-page-steps\">\n <div class=\"dcf-grid dcf-grid-collapse skip\">\n @for(page of pageTitles; track $index;) {\n <div class=\"dcf-flex dcf-flex-middle\">\n <div class=\"dcf-step\" [class.dcf-active]=\"activePage === $index + 1\" [class.dcf-passed]=\"($index + 1) < activePage\">{{ $index + 1 }}</div>\n @if((page?.title || page?.description)) {\n <div class=\"dcf-information dcf-visible@s\">\n @if(page?.title) {\n <div class=\"dcf-title\">{{ page?.title | translate }}</div>\n }\n @if(page?.description) {\n <div class=\"dcf-description\">{{ page?.description | translate }}</div>\n }\n <div class=\"dcf-separator\"></div>\n </div>\n }\n @if($index < pageTitles.length - 1) {\n <div class=\"dcf-arrow-container\">\n <svg width=\"8\" height=\"12\" viewBox=\"0 0 8 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M1.5 1L6.5 6L1.5 11\" />\n </svg>\n </div>\n }\n </div>\n }\n </div>\n </div>\n\n @if(pageTitles[activePage - 1]?.title || pageTitles[activePage - 1]?.description) {\n <div class=\"dcf-current-step\">\n <div>\n @if(pageTitles[activePage - 1]?.title) {\n <div class=\"dcf-title\">{{ pageTitles[activePage - 1]?.title | translate }}</div>\n }\n @if(pageTitles[activePage - 1]?.description) {\n <div class=\"dcf-description\">{{ pageTitles[activePage - 1]?.description | translate }}</div>\n }\n </div>\n </div>\n }\n\n @if(formGroup) {\n <!-- <ngx-decaf-layout\n [children]=\"children || []\"\n [parentComponent]=\"formGroup || parentComponent\"\n gap=\"small\"\n [initializeProps]=\"false\"\n [rows]=\"rows ?? 1\"\n [cols]=\"cols ?? 1\" /> -->\n @for(child of activeChildren; track $index) {\n <div class=\"dcf-step-form-container\">\n <ngx-decaf-component-renderer\n [tag]=\"child?.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n </div>\n\n\n }\n } @else {\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n <br />\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n }\n <div class=\"dcf-buttons-container dcf-grid dcf-grid-collapse dcf-flex dcf-flex-left\">\n <div class=\"dcf-width-1-2@s\">\n <ion-button color=\"light\" (click)=\"handleBack()\" [disabled]=\"activePage <= 1\">\n <!-- <ion-icon aria-hidden=\"true\" name=\"arrow-back-outline\"></ion-icon> -->\n {{locale + '.previous' | translate}}\n </ion-button>\n </div>\n\n <div class=\"dcf-width-1-2@s\">\n <ion-button fill=\"solid\" (click)=\"handleNext(activePage === pages ? true : false)\">\n @if(activePage === pages) {\n {{locale + '.submit' | translate}}\n } @else {\n {{locale + '.next' | translate}}\n <!-- <ion-icon aria-hidden=\"true\" name=\"arrow-forward-outline\"></ion-icon> -->\n }\n </ion-button>\n </div>\n </div>\n } @else {\n <div class=\"dcf-single-step\">\n @for (item of children; track $index) {\n <ion-card>\n <ion-card-content>\n @if(item.title || item.description) {\n <div class=\"dcf-information\">\n <div>\n @if(item.title) {\n <div class=\"dcf-title\">{{ item.title | translate }}</div>\n }\n @if(item.description) {\n <div class=\"dcf-description\">{{ item.description | translate }}</div>\n }\n </div>\n </div>\n }\n <div class=\"dcf-grid dcf-grid-small dcf-child-width-1-1\">\n @for (child of item.items; track $index) {\n <ngx-decaf-component-renderer\n [class]=\"'dcf-step-container ' + (child?.props?.className ? child.props.className + ' ' : ' ') + child.tag\"\n [tag]=\"child?.tag\"\n [projectable]=\"false\"\n (listenEvent)=\"handleEvent($event)\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n }\n </div>\n </ion-card-content>\n </ion-card>\n }\n <div class=\"dcf-buttons-container dcf-grid dcf-grid-small dcf-flex dcf-flex-right\">\n <div class=\"dcf-width-auto@s dcf-width-1-1\">\n <ion-button color=\"light\" (click)=\"handleBack()\">\n {{locale + '.cancel' | translate}}\n </ion-button>\n </div>\n\n <div class=\"dcf-width-auto@s dcf-width-1-1\">\n <ion-button fill=\"solid\" (click)=\"handleNext(true)\">\n {{locale + '.submit' | translate}}\n </ion-button>\n </div>\n </div>\n </div>\n }\n</form>\n", styles: [".dcf-buttons-container{margin-top:1.8rem;margin-bottom:0}@media (min-width: 639px){.dcf-buttons-container.dcf-flex div:nth-child(2){display:flex;justify-content:flex-end}}@media (max-width: 638px){.dcf-buttons-container.dcf-flex div{width:100%}.dcf-buttons-container.dcf-flex ion-button{width:100%;margin-bottom:1rem}}.dcf-steped-form.paginated{padding:2rem 1rem}.dcf-page-steps{display:flex;justify-content:center;align-items:center;margin-bottom:2rem;overflow-x:auto;flex-wrap:nowrap}.dcf-page-steps .dcf-grid{display:flex!important;flex-wrap:nowrap!important;align-items:center}.dcf-step{height:38px;min-width:38px;width:38px;background:var(--dcf-color-gray-2);margin:0;display:flex;color:var(--dcf-color-gray-7);justify-content:center;align-items:center;font-size:1rem;font-weight:600;border-radius:var(--dcf-border-radius)}.dcf-step.dcf-active{color:var(--dcf-color-light);background:var(--ion-color-primary);box-shadow:0 2px 6px #144c714d}.dcf-step.dcf-passed{color:var(--dcf-color-primary-shade);background:var(--dcf-color-gray-3)}.dcf-information{padding-left:.5rem}.dcf-title{font-size:.875rem;font-weight:600;margin:0;color:var(--dcf-color-gray-7)}.dcf-description{font-size:.8rem;font-weight:500;margin:0;margin-top:.25rem;color:var(--dcf-color-gray-4)}.dcf-arrow-container{display:flex;align-items:center;justify-content:center;padding:0 .5rem;height:38px}.dcf-arrow-container{display:flex;align-items:center;justify-content:center;padding:0 1rem;height:40px}.dcf-arrow-container svg{width:1rem;height:1rem;stroke:var(--dcf-color-gray-8);stroke-opacity:.7;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round}ion-button[color=light]{--background: var(--dcf-color-gray-7) !important}.dcf-current-step{margin-top:-.5rem!important;margin-bottom:1.75rem!important;display:flex;align-items:center;justify-content:center}@media (min-width: 639px){.dcf-current-step{display:none}}.dcf-single-step .dcf-information{margin-bottom:1rem}.dcf-single-step .dcf-step-container:not(.ngx-decaf-fieldset){padding-bottom:1.5rem;padding-top:.5rem}.dcf-single-step ion-card{margin-bottom:1.5rem}.dcf-single-step ion-card .dcf-information{margin-top:.75rem}.dcf-step-form-container{margin-bottom:1.75rem!important}::ng-deep ngx-decaf-component-renderer.ngx-decaf-fieldset,::ng-deep ngx-decaf-fieldset{padding-top:0!important;padding-bottom:0!important}::ng-deep ngx-decaf-component-renderer.ngx-decaf-fieldset ion-button,::ng-deep ngx-decaf-fieldset ion-button{margin-top:1rem!important}\n"] }]
9384
+ LayoutComponent
9385
+ ], standalone: true, template: "<form class=\"dcf-steped-form\" [class.paginated]=\"paginated\" novalidate>\n @if(paginated) {\n <div class=\"dcf-page-steps\">\n <div class=\"dcf-grid dcf-grid-collapse skip\">\n @for(page of pageTitles; track $index;) {\n <div class=\"dcf-flex dcf-flex-middle\">\n <div class=\"dcf-step\" [class.dcf-active]=\"activePage === $index + 1\" [class.dcf-passed]=\"($index + 1) < activePage\">{{ $index + 1 }}</div>\n @if((page?.title || page?.description)) {\n <div class=\"dcf-information dcf-visible@s\">\n @if(page?.title) {\n <div class=\"dcf-title\">{{ page?.title | translate }}</div>\n }\n @if(page?.description) {\n <div class=\"dcf-description\">{{ page?.description | translate }}</div>\n }\n <div class=\"dcf-separator\"></div>\n </div>\n }\n @if($index < pageTitles.length - 1) {\n <div class=\"dcf-arrow-container\">\n <svg width=\"8\" height=\"12\" viewBox=\"0 0 8 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M1.5 1L6.5 6L1.5 11\" />\n </svg>\n </div>\n }\n </div>\n }\n </div>\n </div>\n\n @if(pageTitles[activePage - 1]?.title || pageTitles[activePage - 1]?.description) {\n <div class=\"dcf-current-step\">\n <div>\n @if(pageTitles[activePage - 1]?.title) {\n <div class=\"dcf-title\">{{ pageTitles[activePage - 1]?.title | translate }}</div>\n }\n @if(pageTitles[activePage - 1]?.description) {\n <div class=\"dcf-description\">{{ pageTitles[activePage - 1]?.description | translate }}</div>\n }\n </div>\n </div>\n }\n\n @if(initialized && activeChildren?.length) {\n <ngx-decaf-layout\n [children]=\"activeChildren || []\"\n [parentComponent]=\"formGroup || parentComponent\"\n gap=\"small\"\n [rows]=\"rows\"\n [cols]=\"cols\"\n [match]=\"false\"\n\n />\n <!-- @for(child of activeChildren; track $index) {\n <div class=\"dcf-step-form-container\">\n <ngx-decaf-component-renderer\n [tag]=\"child?.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n </div>\n\n\n } -->\n } @else {\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n <br />\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n }\n <div class=\"dcf-buttons-container dcf-grid dcf-grid-collapse dcf-flex dcf-flex-left\">\n <div class=\"dcf-width-1-2@s\">\n <ion-button color=\"light\" (click)=\"handleBack()\" [disabled]=\"activePage <= 1\">\n <!-- <ion-icon aria-hidden=\"true\" name=\"arrow-back-outline\"></ion-icon> -->\n {{locale + '.previous' | translate}}\n </ion-button>\n </div>\n\n <div class=\"dcf-width-1-2@s\">\n <ion-button fill=\"solid\" (click)=\"handleNext(activePage === pages ? true : false)\">\n @if(activePage === pages) {\n {{locale + '.submit' | translate}}\n } @else {\n {{locale + '.next' | translate}}\n <!-- <ion-icon aria-hidden=\"true\" name=\"arrow-forward-outline\"></ion-icon> -->\n }\n </ion-button>\n </div>\n </div>\n } @else {\n <div class=\"dcf-single-step\">\n @for (item of children; track $index) {\n <ion-card>\n <ion-card-content>\n @if(item.title || item.description) {\n <div class=\"dcf-information\">\n <div>\n @if(item.title) {\n <div class=\"dcf-title\">{{ item.title | translate }}</div>\n }\n @if(item.description) {\n <div class=\"dcf-description\">{{ item.description | translate }}</div>\n }\n </div>\n </div>\n }\n <div>\n @if(initialized && item.items?.length) {\n <div>\n <ngx-decaf-layout\n [children]=\"item.items || []\"\n [parentComponent]=\"formGroup || parentComponent\"\n gap=\"small\"\n [rows]=\"rows\"\n [cols]=\"cols\"\n [match]=\"false\"\n\n />\n </div>\n\n }\n </div>\n </ion-card-content>\n </ion-card>\n }\n <div class=\"dcf-buttons-container dcf-grid dcf-grid-small dcf-flex dcf-flex-right\">\n <div class=\"dcf-width-auto@s dcf-width-1-1\">\n <ion-button color=\"light\" (click)=\"handleBack()\">\n {{locale + '.cancel' | translate}}\n </ion-button>\n </div>\n\n <div class=\"dcf-width-auto@s dcf-width-1-1\">\n <ion-button fill=\"solid\" (click)=\"handleNext(true)\">\n {{locale + '.submit' | translate}}\n </ion-button>\n </div>\n </div>\n </div>\n }\n</form>\n", styles: [".dcf-buttons-container{margin-top:1.8rem;margin-bottom:0}@media (min-width: 639px){.dcf-buttons-container.dcf-flex div:nth-child(2){display:flex;justify-content:flex-end}}@media (max-width: 638px){.dcf-buttons-container.dcf-flex div{width:100%}.dcf-buttons-container.dcf-flex ion-button{width:100%;margin-bottom:1rem}}.dcf-steped-form.paginated{padding:2rem 1rem}.dcf-page-steps{display:flex;justify-content:center;align-items:center;margin-bottom:2rem;overflow-x:auto;flex-wrap:nowrap}.dcf-page-steps .dcf-grid{display:flex!important;flex-wrap:nowrap!important;align-items:center}.dcf-step{height:38px;min-width:38px;width:38px;background:var(--dcf-color-gray-2);margin:0;display:flex;color:var(--dcf-color-gray-7);justify-content:center;align-items:center;font-size:1rem;font-weight:600;border-radius:var(--dcf-border-radius)}.dcf-step.dcf-active{color:var(--dcf-color-light);background:var(--ion-color-primary);box-shadow:0 2px 6px #144c714d}.dcf-step.dcf-passed{color:var(--dcf-color-primary-shade);background:var(--dcf-color-gray-3)}.dcf-information{padding-left:.5rem}.dcf-title{font-size:.875rem;font-weight:600;margin:0;color:var(--dcf-color-gray-7)}.dcf-description{font-size:.8rem;font-weight:500;margin:0;margin-top:.25rem;color:var(--dcf-color-gray-4)}.dcf-arrow-container{display:flex;align-items:center;justify-content:center;padding:0 .5rem;height:38px}.dcf-arrow-container{display:flex;align-items:center;justify-content:center;padding:0 1rem;height:40px}.dcf-arrow-container svg{width:1rem;height:1rem;stroke:var(--dcf-color-gray-8);stroke-opacity:.7;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round}ion-button[color=light]{--background: var(--dcf-color-gray-7) !important}.dcf-current-step{margin-top:-.5rem!important;margin-bottom:1.75rem!important;display:flex;align-items:center;justify-content:center}@media (min-width: 639px){.dcf-current-step{display:none}}.dcf-single-step .dcf-information{margin-bottom:1rem}.dcf-single-step .dcf-step-container:not(.ngx-decaf-fieldset){padding-bottom:1.5rem;padding-top:.5rem}.dcf-single-step ion-card{margin-bottom:1.5rem}.dcf-single-step ion-card .dcf-information{margin-top:.75rem}.dcf-step-form-container{margin-bottom:1.75rem!important}::ng-deep ngx-decaf-component-renderer.ngx-decaf-fieldset,::ng-deep ngx-decaf-fieldset{padding-top:0!important;padding-bottom:0!important}::ng-deep ngx-decaf-component-renderer.ngx-decaf-fieldset ion-button,::ng-deep ngx-decaf-fieldset ion-button{margin-top:1rem!important}\n"] }]
9107
9386
  }], ctorParameters: () => [], propDecorators: { children: [{
9108
9387
  type: Input
9109
9388
  }], paginated: [{
@@ -9277,5 +9556,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
9277
9556
  * Generated bundle index. Do not edit.
9278
9557
  */
9279
9558
 
9280
- export { AngularEngineKeys, BaseComponentProps, CPTKN, CollapsableDirective, ComponentRendererComponent, ComponentsTagNames, CrudFieldComponent, CrudFormComponent, CssClasses, DB_ADAPTER_PROVIDER, DB_ADAPTER_PROVIDER_TOKEN, DefaultFormReactiveOptions, Dynamic, DynamicModule, EmptyStateComponent, EventConstants, FieldsetComponent, FilterComponent, ForAngularCommonModule, ForAngularComponentsModule, FormConstants, I18N_CONFIG_TOKEN, I18nLoader, I18nLoaderFactory, I18nParser, LOCALE_ROOT_TOKEN, LayoutComponent, ListComponent, ListComponentsTypes, ListItemComponent, LoggerLevels, ModelRendererComponent, NgxDecafComponentDirective, NgxDecafFormFieldDirective, NgxDecafFormService, NgxEventHandler, NgxPageDirective, NgxRenderingEngine, PaginationComponent, RouteDirections, SearchbarComponent, SteppedFormComponent, cleanSpaces, dataMapper, formatDate, generateRandomValue, getInjectablesRegistry, getLocaleContext, getLocaleContextByKey, getLocaleFromClassName, getLocaleLanguage, getLogger, getModelRepository, getOnWindow, getOnWindowDocument, getWindow, getWindowDocument, getWindowWidth, isDarkMode, isDevelopmentMode, isNotUndefined, isValidDate, itemMapper, parseToValidDate, provideDbAdapter, provideI18n, provideI18nLoader, removeFocusTrap, setOnWindow, stringToBoolean, windowEventEmitter };
9559
+ export { AngularEngineKeys, BaseComponentProps, CPTKN, CollapsableDirective, ComponentRendererComponent, ComponentsTagNames, CrudFieldComponent, CrudFormComponent, CssClasses, DB_ADAPTER_PROVIDER, DB_ADAPTER_PROVIDER_TOKEN, DefaultFormReactiveOptions, DefaultListEmptyOptions, Dynamic, DynamicModule, EmptyStateComponent, EventConstants, FieldsetComponent, FilterComponent, ForAngularCommonModule, ForAngularComponentsModule, FormConstants, I18N_CONFIG_TOKEN, I18nLoader, I18nLoaderFactory, I18nParser, LOCALE_ROOT_TOKEN, LayoutComponent, ListComponent, ListComponentsTypes, ListItemComponent, LoggerLevels, ModelRendererComponent, NgxDecafComponentDirective, NgxDecafFormFieldDirective, NgxDecafFormService, NgxEventHandler, NgxPageDirective, NgxRenderingEngine, PaginationComponent, RouteDirections, SearchbarComponent, SteppedFormComponent, cleanSpaces, dataMapper, formatDate, generateRandomValue, getInjectablesRegistry, getLocaleContext, getLocaleContextByKey, getLocaleFromClassName, getLocaleLanguage, getLogger, getModelRepository, getOnWindow, getOnWindowDocument, getWindow, getWindowDocument, getWindowWidth, isDarkMode, isDevelopmentMode, isNotUndefined, isValidDate, itemMapper, parseToValidDate, provideDbAdapter, provideI18n, provideI18nLoader, removeFocusTrap, setOnWindow, stringToBoolean, windowEventEmitter };
9281
9560
  //# sourceMappingURL=decaf-ts-for-angular.mjs.map