@decaf-ts/for-angular 0.0.41 → 0.0.42

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,6 +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, Injector, createEnvironmentInjector, runInInjectionContext, createComponent, inject, NgZone, Injectable, ChangeDetectorRef, Renderer2, EventEmitter, ElementRef, Input, Output, ViewChild, Inject, Directive, EnvironmentInjector, ViewContainerRef, TemplateRef, Component, HostListener, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
4
+ import * as i1$1 from '@angular/common';
4
5
  import { CommonModule, Location, NgComponentOutlet } from '@angular/common';
5
6
  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
7
  import { InternalError, OperationKeys, NotFoundError } from '@decaf-ts/db-decorators';
@@ -16,14 +17,12 @@ import { forkJoin, Subject, BehaviorSubject, fromEvent, merge, of, Observable, t
16
17
  import { provideHttpClient, HttpClient } from '@angular/common/http';
17
18
  import { map, distinctUntilChanged, takeUntil, shareReplay, tap, switchMap } from 'rxjs/operators';
18
19
  import { __decorate, __metadata } from 'tslib';
19
- import { IonInput, IonItem, IonCheckbox, IonRadioGroup, IonRadio, IonSelect, IonSelectOption, IonLabel, IonText, IonTextarea, IonCard, IonCardHeader, IonCardContent, IonCardTitle, IonCardSubtitle, IonButton, IonIcon, IonAccordionGroup, IonAccordion, IonList, IonReorder, IonReorderGroup, IonSearchbar, IonChip, IonRefresher, IonThumbnail, IonSkeletonText, IonRefresherContent, IonInfiniteScroll, IonInfiniteScrollContent, IonListHeader, IonItemSliding, IonItemOptions, IonItemOption, IonContent, IonPopover, ModalController, IonModal, IonSpinner, IonButtons, IonHeader, IonTitle, IonToolbar } from '@ionic/angular/standalone';
20
+ import { IonModal, IonSpinner, IonButton, IonButtons, IonContent, IonHeader, IonTitle, IonToolbar, IonInput, IonItem, IonCheckbox, IonRadioGroup, IonRadio, IonSelect, IonSelectOption, IonLabel, IonText, IonTextarea, IonCard, IonCardHeader, IonCardContent, IonCardTitle, IonCardSubtitle, IonIcon, IonAccordionGroup, IonAccordion, IonList, IonReorder, IonReorderGroup, IonSearchbar, IonChip, IonRefresher, IonThumbnail, IonSkeletonText, IonRefresherContent, IonInfiniteScroll, IonInfiniteScrollContent, IonListHeader, IonItemSliding, IonItemOptions, IonItemOption, IonPopover } from '@ionic/angular/standalone';
20
21
  import { addIcons } from 'ionicons';
21
22
  import * as allIcons from 'ionicons/icons';
22
23
  import { chevronUpOutline, chevronDownOutline, createOutline, trashOutline, addOutline, alertCircleOutline, arrowUpOutline, arrowDownOutline, searchOutline, closeOutline, chevronForwardOutline, chevronBackOutline, arrowBackOutline, arrowForwardOutline } from 'ionicons/icons';
23
24
  import { apply, metadata } from '@decaf-ts/reflection';
24
25
  import { DomSanitizer, Title } from '@angular/platform-browser';
25
- import { modalController } from '@ionic/core';
26
- import { NgxMediaService as NgxMediaService$1 } from 'src/lib/engine';
27
26
  import { MenuController } from '@ionic/angular';
28
27
 
29
28
  /**
@@ -89,7 +88,7 @@ const FormConstants = {
89
88
  * @summary Contains constants for standardized event names used throughout the application.
90
89
  * These constants ensure consistent event naming across components and make it easier to
91
90
  * track and handle events. Each constant represents a specific application event type.
92
- * @typedef {Object} EventConstants
91
+ * @typedef {Object} ComponentEventNames
93
92
  * @property {string} BACK_BUTTON_NAVIGATION - Event fired when back button navigation ends
94
93
  * @property {string} REFRESH - Event fired when a refresh action occurs
95
94
  * @property {string} CLICK - Event fired when a click action occurs
@@ -98,13 +97,14 @@ const FormConstants = {
98
97
  * @property {string} FIELDSET_ADD_GROUP - Event fired when adding a group to a fieldset
99
98
  * @property {string} FIELDSET_UPDATE_GROUP - Event fired when updating a fieldset group
100
99
  * @property {string} FIELDSET_REMOVE_GROUP - Event fired when removing a fieldset group
101
- * @const EventConstants
100
+ * @const ComponentEventNames
102
101
  * @memberOf module:lib/engine/constants
103
102
  */
104
- const EventConstants = {
103
+ const ComponentEventNames = {
105
104
  BACK_BUTTON_NAVIGATION: 'backButtonNavigationEndEvent',
106
105
  REFRESH: 'RefreshEvent',
107
106
  CLICK: 'ClickEvent',
107
+ CHANGE: 'ChangeEvent',
108
108
  SUBMIT: 'SubmitEvent',
109
109
  VALIDATION_ERROR: 'validationErrorEvent',
110
110
  FIELDSET_ADD_GROUP: 'fieldsetAddGroupEvent',
@@ -321,6 +321,7 @@ const ElementSizes = {
321
321
  xsmall: 'xsmall',
322
322
  small: 'small',
323
323
  medium: 'medium',
324
+ default: 'default',
324
325
  large: 'large',
325
326
  xLarge: 'xlarge',
326
327
  '2xLarge': '2xlarge',
@@ -328,6 +329,13 @@ const ElementSizes = {
328
329
  expand: 'expand',
329
330
  block: 'block',
330
331
  };
332
+ const ElementPositions = {
333
+ left: 'left',
334
+ center: 'center',
335
+ right: 'right',
336
+ top: 'top',
337
+ bottom: 'bottom',
338
+ };
331
339
  const LayoutGridGaps = {
332
340
  small: 'small',
333
341
  medium: 'medium',
@@ -335,6 +343,13 @@ const LayoutGridGaps = {
335
343
  collapse: 'collapse',
336
344
  none: ''
337
345
  };
346
+ const ListItemPositions = {
347
+ uid: 'uid',
348
+ title: 'title',
349
+ description: 'description',
350
+ info: 'info',
351
+ subinfo: 'subinfo',
352
+ };
338
353
 
339
354
  /**
340
355
  * @module module:lib/engine/ValidatorFactory
@@ -502,7 +517,7 @@ const CPTKN = new InjectionToken('CPTKN', { providedIn: 'root', factory: () => '
502
517
  * @summary Used to provide configuration for internationalization resources, including
503
518
  * translation file locations and supported languages. This token configures how the
504
519
  * application loads and manages translation resources.
505
- * @const {InjectionToken<{resources: I18nResourceConfig[]; versionedSuffix: boolean}>}
520
+ * @const {InjectionToken<I18nToken>}
506
521
  * @memberOf module:lib/for-angular-common.module
507
522
  */
508
523
  const I18N_CONFIG_TOKEN = new InjectionToken('I18N_CONFIG_TOKEN');
@@ -511,8 +526,8 @@ const I18N_CONFIG_TOKEN = new InjectionToken('I18N_CONFIG_TOKEN');
511
526
  * @summary Helper function to package component constructors for registration with the
512
527
  * rendering engine. This function accepts component classes and returns them as an array
513
528
  * suitable for use with the CPTKN injection token.
514
- * @param {...Constructor<unknown>[]} components - Component constructor classes to register
515
- * @return {Constructor<unknown>[]} Array of component constructors
529
+ * @param {...Constructor[]} components - Component constructor classes to register
530
+ * @return {Constructor} Array of component constructors
516
531
  * @memberOf module:lib/for-angular-common.module
517
532
  * @example
518
533
  * // Register multiple custom components
@@ -1388,7 +1403,7 @@ class NgxFormService {
1388
1403
  const parts = path.split('.');
1389
1404
  const controlName = parts.pop();
1390
1405
  const { childOf } = componentProps;
1391
- let currentGroup = formGroup;
1406
+ const currentGroup = formGroup;
1392
1407
  function setArrayComponentProps(formGroupArray) {
1393
1408
  const props = formGroupArray?.[BaseComponentProps.FORM_GROUP_COMPONENT_PROPS] || {};
1394
1409
  if (!props[ModelKeys.MODEL][controlName])
@@ -1396,7 +1411,7 @@ class NgxFormService {
1396
1411
  }
1397
1412
  for (const part of parts) {
1398
1413
  if (!currentGroup.get(part)) {
1399
- const partFormGroup = (isMultiple && part === childOf) ? new FormArray([new FormGroup({})]) : new FormGroup({});
1414
+ const partFormGroup = (isMultiple && (part === childOf || childOf?.endsWith(`${part}`))) ? new FormArray([new FormGroup({})]) : new FormGroup({});
1400
1415
  const pk = componentProps?.pk || parentProps?.pk || '';
1401
1416
  partFormGroup[BaseComponentProps.FORM_GROUP_COMPONENT_PROPS] = {
1402
1417
  childOf: childOf || '',
@@ -1420,7 +1435,7 @@ class NgxFormService {
1420
1435
  }
1421
1436
  if (childOf && currentGroup instanceof FormArray)
1422
1437
  setArrayComponentProps(currentGroup);
1423
- currentGroup = currentGroup.get(part);
1438
+ return [currentGroup.get(part), controlName];
1424
1439
  }
1425
1440
  return [currentGroup, controlName];
1426
1441
  }
@@ -1587,7 +1602,7 @@ class NgxFormService {
1587
1602
  */
1588
1603
  static addFormControl(formGroup, componentProps, parentProps = {}, index = 0) {
1589
1604
  const isMultiple = parentProps?.['multiple'] || parentProps?.['type'] === 'Array' || false;
1590
- const { name, childOf, } = componentProps;
1605
+ const { name, childOf } = componentProps;
1591
1606
  if (isMultiple)
1592
1607
  componentProps['pk'] = componentProps['pk'] || parentProps?.['pk'] || '';
1593
1608
  const fullPath = childOf ? isMultiple ? `${childOf}.${index}.${name}` : `${childOf}.${name}` : name;
@@ -1608,11 +1623,16 @@ class NgxFormService {
1608
1623
  }
1609
1624
  }
1610
1625
  }
1611
- const root = parentGroup instanceof FormArray ? parentGroup.controls[componentProps?.['page'] - 1] : parentGroup;
1612
- componentProps['formGroup'] = root;
1626
+ let rootGroup = parentGroup;
1627
+ if (rootGroup instanceof FormArray)
1628
+ rootGroup = parentGroup.controls[componentProps?.['page'] - 1];
1629
+ // if(childOf?.includes("."))
1630
+ // rootGroup = (rootGroup as FormGroup)?.parent as FormArray
1631
+ // componentProps['formGroup'] = root as FormGroup;
1632
+ componentProps['formGroup'] = rootGroup;
1613
1633
  componentProps['formControl'] = parentGroup.get(controlName);
1614
1634
  // componentProps['multiple'] = isMultiple;
1615
- return root;
1635
+ return parentGroup;
1616
1636
  }
1617
1637
  /**
1618
1638
  * @description Retrieves a control from a registered form.
@@ -1841,6 +1861,8 @@ class NgxFormService {
1841
1861
  const control = formGroup.controls[key];
1842
1862
  const parentProps = NgxFormService.getPropsFromControl(formGroup);
1843
1863
  if (!(control instanceof FormControl)) {
1864
+ if (control.disabled)
1865
+ continue;
1844
1866
  const value = NgxFormService.getFormData(control);
1845
1867
  const isValid = control.valid;
1846
1868
  if (parentProps.multiple) {
@@ -1932,7 +1954,7 @@ class NgxFormService {
1932
1954
  throw new Error(`Unknown control type at: ${path || 'root'}`);
1933
1955
  control.markAsTouched();
1934
1956
  control.markAsDirty();
1935
- control.updateValueAndValidity();
1957
+ control.updateValueAndValidity({ emitEvent: true });
1936
1958
  if (control instanceof FormGroup) {
1937
1959
  Object.values(control.controls).forEach(childControl => {
1938
1960
  this.validateFields(childControl);
@@ -1967,7 +1989,7 @@ class NgxFormService {
1967
1989
  // return null;
1968
1990
  // return Object.keys(group.controls).find(name => control === group.get(name)) || null;
1969
1991
  // }
1970
- return control.valid;
1992
+ return control?.disabled ? true : control.valid;
1971
1993
  }
1972
1994
  /**
1973
1995
  * @description Generates validators from component properties.
@@ -2825,6 +2847,20 @@ var component = {
2825
2847
  previous: "Previous",
2826
2848
  submit: "Submit",
2827
2849
  cancel: "Cancel"
2850
+ },
2851
+ file_upload: {
2852
+ drag_file: "Drag and drop your image here",
2853
+ buttons: {
2854
+ select: "Select File",
2855
+ preview: "Preview",
2856
+ clear: "Clear"
2857
+ },
2858
+ selection: "{0} file(s) selected with success",
2859
+ selection_error: "{0} file(s) failed validation and will not be uploaded.",
2860
+ errors: {
2861
+ not_allowed: "File {0} is not allowed.",
2862
+ max_size: "The maximum allowed file size is {0} MB"
2863
+ }
2828
2864
  }
2829
2865
  };
2830
2866
  var en = {
@@ -2842,6 +2878,15 @@ var en = {
2842
2878
  *
2843
2879
  * @link {@link I18nLoader}
2844
2880
  */
2881
+ const libLanguage = { en };
2882
+ /**
2883
+ * @description Retrieves the locale context for a given class, object, or string.
2884
+ * @summary Resolves the locale context by extracting the class name or using the provided suffix.
2885
+ *
2886
+ * @param {FunctionLike | object | string} clazz - The class, object, or string to derive the locale context from.
2887
+ * @param {string} [suffix] - An optional suffix to append to the locale context.
2888
+ * @returns {string} - The resolved locale context string.
2889
+ */
2845
2890
  function getLocaleContext(clazz, suffix) {
2846
2891
  return getLocaleFromClassName(clazz, suffix);
2847
2892
  }
@@ -2867,36 +2912,81 @@ function getLocaleContextByKey(locale, phrase) {
2867
2912
  const parts = phrase.split(' ');
2868
2913
  return `${locale}.${cleanSpaces(parts.join('.'), true)}`;
2869
2914
  }
2915
+ /**
2916
+ * @description Factory function for creating an instance of I18nLoader.
2917
+ * @summary Configures and returns an I18nLoader instance with the specified HTTP client and translation resources.
2918
+ *
2919
+ * @param {HttpClient} http - The HTTP client used to fetch translation resources.
2920
+ * @returns {TranslateLoader} - An instance of I18nLoader configured with the provided HTTP client and resources.
2921
+ */
2870
2922
  function I18nLoaderFactory(http) {
2871
2923
  const { resources, versionedSuffix } = inject(I18N_CONFIG_TOKEN, { optional: true }) ?? provideI18nLoader().useValue;
2872
2924
  return new I18nLoader(http, resources?.length ? resources : [{ prefix: './app/assets/i18n/', suffix: '.json' }], versionedSuffix);
2873
2925
  }
2926
+ /**
2927
+ * @description Provides the I18nLoader configuration.
2928
+ * @summary Configures the translation resources and versioned suffix for the I18nLoader.
2929
+ *
2930
+ * @param {I18nResourceConfigType} [resources=[]] - The translation resources to be used by the loader.
2931
+ * @param {boolean} [versionedSuffix=false] - Whether to append a versioned suffix to resource URLs.
2932
+ * @returns {object} - The configuration object for the I18nLoader.
2933
+ */
2874
2934
  function provideI18nLoader(resources = [], versionedSuffix = false) {
2875
- if (!Array.isArray(resources))
2935
+ if (!Array.isArray(resources)) {
2876
2936
  resources = [resources];
2937
+ }
2877
2938
  return {
2878
2939
  provide: I18N_CONFIG_TOKEN,
2879
- useValue: { resources: [
2880
- ...resources
2881
- ], versionedSuffix }
2940
+ useValue: { resources: [...resources], versionedSuffix },
2882
2941
  };
2883
2942
  }
2884
- const libLanguage = { en };
2943
+ /**
2944
+ * @description Custom implementation of TranslateLoader for loading translations.
2945
+ * @summary Fetches and merges translation resources, supporting versioned suffixes and recursive merging.
2946
+ */
2885
2947
  class I18nLoader {
2948
+ /**
2949
+ * @param {HttpClient} http - The HTTP client used to fetch translation resources.
2950
+ * @param {I18nResourceConfig[]} [resources=[]] - The translation resources to be loaded.
2951
+ * @param {boolean} [versionedSuffix=false] - Whether to append a versioned suffix to resource URLs.
2952
+ */
2886
2953
  constructor(http, resources = [], versionedSuffix = false) {
2887
2954
  this.http = http;
2888
2955
  this.resources = resources;
2889
2956
  this.versionedSuffix = versionedSuffix;
2890
2957
  }
2958
+ /**
2959
+ * @description Appends a versioned suffix to the resource URL if enabled.
2960
+ * @summary Generates a versioned suffix based on the current date.
2961
+ *
2962
+ * @param {string} suffix - The original suffix of the resource URL.
2963
+ * @returns {string} - The modified suffix with a version string appended.
2964
+ */
2891
2965
  getSuffix(suffix) {
2892
- if (!this.versionedSuffix)
2966
+ if (!this.versionedSuffix) {
2893
2967
  return suffix;
2968
+ }
2894
2969
  const today = new Date();
2895
2970
  return `${suffix}?version=${today.getFullYear()}${today.getMonth()}${today.getDay()}`;
2896
2971
  }
2972
+ /**
2973
+ * @description Fetches and merges translations for the specified language.
2974
+ * @summary Loads translation resources, merges them recursively, and includes library keys.
2975
+ *
2976
+ * @param {string} lang - The language code for the translations to load.
2977
+ * @returns {Observable<TranslationObject>} - An observable that emits the merged translation object.
2978
+ */
2897
2979
  getTranslation(lang) {
2898
- const libKeys = libLanguage[lang] || libLanguage["en"] || {};
2899
- const httpRequests$ = forkJoin(this.resources.map(config => this.http.get(`${config.prefix}${lang}${this.getSuffix(config.suffix)}`)));
2980
+ const libKeys = libLanguage[lang] || libLanguage['en'] || {};
2981
+ const httpRequests$ = forkJoin(this.resources.map(config => this.http.get(`${config.prefix}${lang}${this.getSuffix(config.suffix || '.json')}`)));
2982
+ /**
2983
+ * @description Recursively merges two translation objects.
2984
+ * @summary Combines the properties of the source object into the target object.
2985
+ *
2986
+ * @param {KeyValue} target - The target object to merge into.
2987
+ * @param {KeyValue} source - The source object to merge from.
2988
+ * @returns {KeyValue} - The merged object.
2989
+ */
2900
2990
  function recursiveMerge(target, source) {
2901
2991
  for (const key of Object.keys(source)) {
2902
2992
  if (source[key] instanceof Object) {
@@ -2916,24 +3006,47 @@ class I18nLoader {
2916
3006
  ...res.reduce((acc, current) => {
2917
3007
  for (const key in current) {
2918
3008
  let value = current[key] || {};
2919
- if (libKeys[key])
3009
+ if (libKeys[key]) {
2920
3010
  value = { ...libKeys[key], ...recursiveMerge(libKeys[key], current[key]) };
3011
+ }
2921
3012
  acc[key] = value;
2922
3013
  }
2923
3014
  return acc;
2924
- }, {})
3015
+ }, {}),
2925
3016
  };
2926
3017
  return merged;
2927
3018
  }));
2928
3019
  }
2929
3020
  }
3021
+ /**
3022
+ * @description Custom implementation of TranslateParser for interpolation.
3023
+ * @summary Extends TranslateParser to support string formatting with parameters.
3024
+ */
2930
3025
  class I18nParser extends TranslateParser {
3026
+ /**
3027
+ * @description Interpolates a translation string with parameters.
3028
+ * @summary Replaces placeholders in the translation string with parameter values.
3029
+ *
3030
+ * @param {string} value - The translation string to interpolate.
3031
+ * @param {object | string} [params={}] - The parameters to replace placeholders with.
3032
+ * @returns {string} - The interpolated translation string.
3033
+ */
2931
3034
  interpolate(value, params = {}) {
2932
- if (typeof params === Primitives.STRING)
2933
- params = { "0": params };
3035
+ if (typeof params === Primitives.STRING) {
3036
+ params = { '0': params };
3037
+ }
2934
3038
  return sf(value, ...Object.values(params));
2935
3039
  }
2936
3040
  }
3041
+ /**
3042
+ * @description Provides the internationalization (i18n) configuration for the application.
3043
+ * @summary Configures the translation service with a fallback language, default language, custom parser, and loader.
3044
+ *
3045
+ * @param {RootTranslateServiceConfig} [config={fallbackLang: 'en', lang: 'en'}] - The configuration for the translation service, including fallback and default languages.
3046
+ * @param {I18nResourceConfigType} [resources=[]] - The translation resources to be used by the loader.
3047
+ * @param {boolean} [versionedSuffix=false] - Whether to append a versioned suffix to resource URLs.
3048
+ * @returns {Array} - An array of providers for the translation service and loader.
3049
+ */
2937
3050
  function provideI18n(config = { fallbackLang: 'en', lang: 'en' }, resources = [], versionedSuffix = false) {
2938
3051
  return [
2939
3052
  provideHttpClient(),
@@ -2947,7 +3060,7 @@ function provideI18n(config = { fallbackLang: 'en', lang: 'en' }, resources = []
2947
3060
  deps: [HttpClient],
2948
3061
  },
2949
3062
  }),
2950
- provideI18nLoader(resources, versionedSuffix)
3063
+ provideI18nLoader(resources, versionedSuffix),
2951
3064
  ];
2952
3065
  }
2953
3066
 
@@ -3961,7 +4074,7 @@ class NgxComponentDirective extends LoggedClass {
3961
4074
  return this.router.navigateByUrl(page);
3962
4075
  }
3963
4076
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: NgxComponentDirective, deps: [{ token: CPTKN }, { token: CPTKN }], target: i0.ɵɵFactoryTarget.Directive }); }
3964
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.9", type: NgxComponentDirective, isStandalone: true, inputs: { enableDarkMode: "enableDarkMode", isDarkMode: "isDarkMode", 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 }); }
4077
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.9", type: NgxComponentDirective, isStandalone: true, inputs: { enableDarkMode: "enableDarkMode", isDarkMode: "isDarkMode", 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", isModalChild: "isModalChild" }, 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 }); }
3965
4078
  }
3966
4079
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: NgxComponentDirective, decorators: [{
3967
4080
  type: Directive,
@@ -4013,6 +4126,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
4013
4126
  type: Input
4014
4127
  }], route: [{
4015
4128
  type: Input
4129
+ }], isModalChild: [{
4130
+ type: Input
4016
4131
  }] } });
4017
4132
 
4018
4133
  class NgxRenderableComponentDirective extends NgxComponentDirective {
@@ -4104,8 +4219,11 @@ class NgxRenderableComponentDirective extends NgxComponentDirective {
4104
4219
  * @return {void}
4105
4220
  * @memberOf NgxComponentDirective
4106
4221
  */
4107
- async subscribeEvents() {
4108
- const component = this?.output?.component;
4222
+ async subscribeEvents(component) {
4223
+ if (!component)
4224
+ component = this?.output?.component;
4225
+ if (!this.instance && component)
4226
+ this.instance = component;
4109
4227
  if (this.instance && component) {
4110
4228
  const componentKeys = Object.keys(this.instance);
4111
4229
  for (const key of componentKeys) {
@@ -4320,14 +4438,14 @@ class ComponentRendererComponent extends NgxRenderableComponentDirective {
4320
4438
  // const projectable = (this.children?.length && this.projectable);
4321
4439
  // const template = projectable ? this.vcr.createEmbeddedView(this.inner as TemplateRef<unknown>, this.injector).rootNodes : [];
4322
4440
  this.instance = NgxRenderingEngine.createComponent(component, props, this.injector, metadata, this.vcr, []);
4323
- this.subscribeEvents();
4441
+ this.subscribeEvents(component);
4324
4442
  }
4325
4443
  createParentComponent() {
4326
4444
  const { component, inputs } = this.parent;
4327
4445
  const metadata = reflectComponentType(component);
4328
4446
  const template = this.projectable ? this.vcr.createEmbeddedView(this.inner, this.injector).rootNodes : [];
4329
4447
  this.instance = NgxRenderingEngine.createComponent(component, inputs, this.injector, metadata, this.vcr, template);
4330
- this.subscribeEvents();
4448
+ this.subscribeEvents(component);
4331
4449
  }
4332
4450
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: ComponentRendererComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
4333
4451
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: ComponentRendererComponent, isStandalone: true, selector: "ngx-decaf-component-renderer", inputs: { tag: "tag", children: "children", projectable: "projectable", parent: "parent" }, host: { properties: { "attr.id": "uid" } }, usesInheritance: true, ngImport: i0, template: "<!-- Keep to avoid id conflicts -->\n\n<ng-template #componentOuter></ng-template>\n\n<ng-template #componentInner>\n @if (parent?.children?.length) {\n @for(child of parent.children; track child) {\n @if (!child.children?.length) {\n <ng-container\n *ngComponentOutlet=\"\n child.component;\n injector: child.injector;\n inputs: child.inputs;\n content:child.content;\n \"\n />\n } @else {\n <ngx-decaf-component-renderer [parent]=\"child\"> </ngx-decaf-component-renderer>\n }\n }\n }\n @if (projectable) {\n @if (children?.length) {\n @for(child of children; track child) {\n @if (child.children?.length) {\n <ng-container\n *ngComponentOutlet=\"\n child.component;\n injector: child.injector;\n inputs: child.inputs;\n content:child.content;\n \"\n />\n } @else {\n <ng-container\n *ngComponentOutlet=\"\n child.component;\n injector: child.injector;\n inputs: child.inputs;\n content:child.content;\n \"\n />\n }\n }\n }\n }\n\n</ng-template>\n\n", styles: [""], dependencies: [{ kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "children", "projectable", "parent"] }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }] }); }
@@ -4608,7 +4726,7 @@ class NgxFormFieldDirective extends NgxComponentDirective {
4608
4726
  }));
4609
4727
  if (errors.length) {
4610
4728
  if (accordionComponent && !this.validationErrorEventDispatched) {
4611
- const validationErrorEvent = new CustomEvent(EventConstants.VALIDATION_ERROR, {
4729
+ const validationErrorEvent = new CustomEvent(ComponentEventNames.VALIDATION_ERROR, {
4612
4730
  detail: { fieldName: this.name, hasErrors: true },
4613
4731
  bubbles: true
4614
4732
  });
@@ -4676,104 +4794,621 @@ function Dynamic() {
4676
4794
  }
4677
4795
 
4678
4796
  /**
4679
- * @description A dynamic form field component for CRUD operations.
4680
- * @summary The CrudFieldComponent is a versatile form field component that adapts to different
4681
- * input types and CRUD operations. It extends NgxFormFieldDirective to inherit form handling capabilities
4682
- * and implements lifecycle hooks to properly initialize, render, and clean up. This component
4683
- * supports various input types (text, number, date, select, etc.), validation rules, and styling
4684
- * options, making it suitable for building dynamic forms for create, read, update, and delete
4685
- * operations.
4686
- *
4687
- * @param {CrudOperations} operation - The CRUD operation being performed (create, read, update, delete)
4688
- * @param {string} name - The field name, used as form control identifier
4689
- * @param {PossibleInputTypes} type - The input type (text, number, date, select, etc.)
4690
- * @param {string|number|Date} value - The initial value of the field
4691
- * @param {boolean} disabled - Whether the field is disabled
4692
- * @param {string} label - The display label for the field
4693
- * @param {string} placeholder - Placeholder text when field is empty
4694
- * @param {string} format - Format pattern for the field value
4695
- * @param {boolean} hidden - Whether the field should be hidden
4696
- * @param {number|Date} max - Maximum allowed value
4697
- * @param {number} maxlength - Maximum allowed length
4698
- * @param {number|Date} min - Minimum allowed value
4699
- * @param {number} minlength - Minimum allowed length
4700
- * @param {string} pattern - Validation pattern
4701
- * @param {boolean} readonly - Whether the field is read-only
4702
- * @param {boolean} required - Whether the field is required
4703
- * @param {number} step - Step value for number inputs
4704
- * @param {FormGroup} formGroup - The parent form group
4705
- * @param {StringOrBoolean} translatable - Whether field labels should be translated
4797
+ * @module module:lib/components/model-renderer/model-renderer.component
4798
+ * @description Model renderer component module.
4799
+ * @summary Exposes `ModelRendererComponent` which dynamically renders UI components
4800
+ * from model definitions using the `NgxRenderingEngine`. It handles model changes,
4801
+ * event subscription and lifecycle for the rendered output.
4706
4802
  *
4707
- * @component CrudFieldComponent
4803
+ * @link {@link ModelRendererComponent}
4804
+ */
4805
+ /**
4806
+ * @description Component for rendering dynamic models
4807
+ * @summary This component is responsible for dynamically rendering models,
4808
+ * handling model changes, and managing event subscriptions for the rendered components.
4809
+ * It uses the NgxRenderingEngine to render the models and supports both string and Model inputs.
4810
+ * @class
4811
+ * @template M - Type extending Model
4812
+ * @param {Injector} injector - Angular Injector for dependency injection
4708
4813
  * @example
4709
- * <ngx-decaf-crud-field
4710
- * operation="create"
4711
- * name="firstName"
4712
- * type="text"
4713
- * label="<NAME>"
4714
- * placeholder="<NAME>"
4715
- * [value]="model.firstName"
4716
- * [disabled]="model.readOnly">
4814
+ * <ngx-decaf-model-renderer
4815
+ * [model]="myModel"
4816
+ * [globals]="globalVariables"
4817
+ * (listenEvent)="handleEvent($event)">
4818
+ * </ngx-decaf-model-renderer>
4819
+ * @mermaid
4820
+ * sequenceDiagram
4821
+ * participant App
4822
+ * participant ModelRenderer
4823
+ * participant RenderingEngine
4824
+ * participant Model
4825
+ * App->>ModelRenderer: Input model
4826
+ * ModelRenderer->>Model: Parse if string
4827
+ * Model-->>ModelRenderer: Parsed model
4828
+ * ModelRenderer->>RenderingEngine: Render model
4829
+ * RenderingEngine-->>ModelRenderer: Rendered output
4830
+ * ModelRenderer->>ModelRenderer: Subscribe to events
4831
+ * ModelRenderer-->>App: Emit events
4832
+ */
4833
+ class ModelRendererComponent extends NgxRenderableComponentDirective {
4834
+ constructor() {
4835
+ super(...arguments);
4836
+ /**
4837
+ * @description Set if render content projection is allowed
4838
+ * @default true
4839
+ */
4840
+ this.projectable = true;
4841
+ }
4842
+ // private injector: Injector = inject(Injector);
4843
+ // constructor() {}
4844
+ /**
4845
+ * @description Refreshes the rendered model
4846
+ * @param {string | M} model - The model to be rendered
4847
+ */
4848
+ refresh(model) {
4849
+ model =
4850
+ typeof model === 'string'
4851
+ ? Model.build({}, model)
4852
+ : model;
4853
+ this.output = model.render(this.globals || {}, this.vcr, this.injector, this.inner, this.projectable);
4854
+ if (this.output?.inputs)
4855
+ this.rendererId = sf(AngularEngineKeys.RENDERED_ID, this.output.inputs['rendererId']);
4856
+ this.instance = this.output?.component;
4857
+ this.subscribeEvents();
4858
+ }
4859
+ /**
4860
+ * @description Lifecycle hook that is called when data-bound properties of a directive change
4861
+ * @param {SimpleChanges} changes - Object containing changes
4862
+ */
4863
+ ngOnChanges(changes) {
4864
+ if (changes[BaseComponentProps.MODEL]) {
4865
+ const { currentValue } = changes[BaseComponentProps.MODEL];
4866
+ this.refresh(currentValue);
4867
+ }
4868
+ }
4869
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: ModelRendererComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
4870
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.9", type: ModelRendererComponent, isStandalone: true, selector: "ngx-decaf-model-renderer", inputs: { projectable: "projectable" }, host: { properties: { "attr.id": "uid" } }, usesInheritance: true, usesOnChanges: true, ngImport: i0, template: " <!-- Keep to avoid id conflicts -->\n <div class=\"dcf-hidden\" [id]=\"uid\"></div>\n\n <ng-template #componentOuter></ng-template>\n <!-- <ng-template #inner>\n <div class=\"dcf-grid dcf-grid-small dcf-model-renderer-component dcf-child-width-1-1\" [id]=\"rendererId || ''\">\n @for (child of output?.children; track child) {\n @if (child?.children?.length) {\n <ngx-decaf-component-renderer [parent]=\"child\" />\n } @else {\n <ng-container\n #childComponents\n *ngComponentOutlet=\"\n child.component;\n injector: child.injector;\n inputs: child.inputs;\n content:child.content;\n \"\n />\n }\n }\n </div>\n </ng-template> -->\n", styles: [""] }); }
4871
+ }
4872
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: ModelRendererComponent, decorators: [{
4873
+ type: Component,
4874
+ args: [{ standalone: true, imports: [], selector: 'ngx-decaf-model-renderer', host: { '[attr.id]': 'uid' }, template: " <!-- Keep to avoid id conflicts -->\n <div class=\"dcf-hidden\" [id]=\"uid\"></div>\n\n <ng-template #componentOuter></ng-template>\n <!-- <ng-template #inner>\n <div class=\"dcf-grid dcf-grid-small dcf-model-renderer-component dcf-child-width-1-1\" [id]=\"rendererId || ''\">\n @for (child of output?.children; track child) {\n @if (child?.children?.length) {\n <ngx-decaf-component-renderer [parent]=\"child\" />\n } @else {\n <ng-container\n #childComponents\n *ngComponentOutlet=\"\n child.component;\n injector: child.injector;\n inputs: child.inputs;\n content:child.content;\n \"\n />\n }\n }\n </div>\n </ng-template> -->\n" }]
4875
+ }], propDecorators: { projectable: [{
4876
+ type: Input
4877
+ }] } });
4878
+
4879
+ /**
4880
+ * @module module:lib/engine/NgxParentComponentDirective
4881
+ * @description Directive base for parent container components used by the rendering system.
4882
+ * @summary Provides NgxParentComponentDirective which offers inputs for children metadata,
4883
+ * column/row configuration and parent component wiring used by layout and container components.
4717
4884
  *
4885
+ * @link {@link NgxParentComponentDirective}
4886
+ */
4887
+ /**
4888
+ * @description Layout component for creating responsive grid layouts in Angular applications.
4889
+ * @summary This component provides a flexible grid system that can be configured with dynamic
4890
+ * rows and columns. It supports responsive breakpoints and can render child components within
4891
+ * the grid structure. The component extends NgxComponentDirective to inherit common functionality
4892
+ * and integrates with the model and component renderer systems.
4718
4893
  *
4719
- * @memberOf module:for-angular
4894
+ * @class NgxParentComponentDirective
4895
+ * @extends {NgxComponentDirective}
4896
+ * @implements {OnInit}
4720
4897
  */
4721
- let CrudFieldComponent = class CrudFieldComponent extends NgxFormFieldDirective {
4898
+ class NgxParentComponentDirective extends NgxComponentDirective {
4722
4899
  constructor() {
4723
4900
  super(...arguments);
4724
- this.className = 'dcf-width-1-1';
4725
4901
  /**
4726
- * @description The parent field path, if this field is nested.
4727
- * @summary Specifies the full dot-delimited path of the parent field. This is only set when the field is nested.
4902
+ * @description Unique identifier for the current record.
4903
+ * @summary A unique identifier for the current record being displayed or manipulated.
4904
+ * This is typically used in conjunction with the primary key for operations on specific records.
4905
+ *
4906
+ * @type {string | number}
4907
+ */
4908
+ this.page = 1;
4909
+ /**
4910
+ * @description Unique identifier for the current record.
4911
+ * @summary A unique identifier for the current record being displayed or manipulated.
4912
+ * This is typically used in conjunction with the primary key for operations on specific records.
4728
4913
  *
4729
- * @type {string}
4730
- * @memberOf CrudFieldComponent
4914
+ * @type {string | number}
4731
4915
  */
4916
+ this.pages = 1;
4732
4917
  /**
4733
- * @description The parent field path for nested field structures.
4734
- * @summary Specifies the full dot-delimited path of the parent field when this field
4735
- * is part of a nested structure. This is used for hierarchical form organization
4736
- * and proper form control resolution in complex form structures.
4918
+ * @description Array of UI model metadata for the currently active page.
4919
+ * @summary Contains only the UI model metadata for fields that should be displayed
4920
+ * on the currently active page. This is a filtered subset of the children array,
4921
+ * updated whenever the user navigates between pages.
4737
4922
  *
4738
- * @type {string}
4739
- * @default ''
4740
- * @memberOf CrudFieldComponent
4923
+ * @type { UIModelMetadata | UIModelMetadata[] | FieldDefinition | FieldDefinition[] | undefined }
4741
4924
  */
4742
- this.childOf = '';
4925
+ this.activePage = undefined;
4743
4926
  /**
4744
- * @description The initial value of the field.
4745
- * @summary Sets the initial value of the form field. This can be a string, number, or Date
4746
- * depending on the field type. For select fields, this should match one of the option values.
4927
+ * @description The currently active page number.
4928
+ * @summary Tracks which page of the multi-step form is currently being displayed.
4929
+ * This property is updated as users navigate through the form steps using
4930
+ * the next/back buttons or programmatic navigation.
4747
4931
  *
4748
- * @type {string | number | Date}
4749
- * @default ''
4750
- * @memberOf CrudFieldComponent
4932
+ * @type {number}
4751
4933
  */
4752
- this.value = '';
4934
+ this.activeIndex = 1;
4753
4935
  /**
4754
- * @description Whether the field should be hidden.
4755
- * @summary When true, the field will not be visible in the UI but will still be part of the form model.
4756
- * This is useful for fields that need to be included in form submission but should not be displayed to the user.
4936
+ * @description Array of UI model metadata for all form fields.
4937
+ * @summary Contains the complete collection of UI model metadata that defines
4938
+ * the structure, validation, and presentation of form fields across all pages.
4939
+ * Each metadata object contains information about field type, validation rules,
4940
+ * page assignment, and display properties.
4757
4941
  *
4758
- * @type {boolean}
4759
- * @memberOf CrudFieldComponent
4942
+ * @type {UIModelMetadata[]}
4760
4943
  */
4761
- this.hidden = false;
4944
+ this.children = [];
4762
4945
  /**
4763
- * @description Interface style for select inputs.
4764
- * @summary Specifies the interface style for select inputs, such as 'alert', 'action-sheet', or 'popover'.
4765
- * This determines how the select options are presented to the user.
4946
+ * @description Number of columns or array of column definitions for the grid layout.
4947
+ * @summary Defines the column structure of the grid. When a number is provided, it creates
4948
+ * that many equal-width columns. When an array is provided, each element can define specific
4949
+ * column properties or sizing. This allows for flexible grid layouts that can adapt to
4950
+ * different content requirements.
4766
4951
  *
4767
- * @type {SelectInterface}
4768
- * @memberOf CrudFieldComponent
4952
+ * @type {(number | string[])}
4953
+ * @default 1
4769
4954
  */
4770
- this.interface = 'popover';
4955
+ this.cols = 1;
4771
4956
  /**
4772
- * @description Spellcheck attribute for text inputs.
4773
- * @summary Enables or disables spellchecking for text inputs.
4774
- * When true, the browser will check the spelling of the input text.
4775
- *
4776
- * @type {boolean}
4957
+ * @description Number of rows or array of row definitions for the grid layout.
4958
+ * @summary Defines the row structure of the grid. When a number is provided, it creates
4959
+ * that many equal-height rows. When an array is provided, each element can define specific
4960
+ * row properties or sizing. This provides control over vertical spacing and content organization.
4961
+ *
4962
+ * @type {(number | string[])}
4963
+ * @default 1
4964
+ */
4965
+ this.rows = 1;
4966
+ /**
4967
+ * @description Defines the body style of the card.
4968
+ * @summary Specifies the appearance of the card body, allowing customization
4969
+ * between default, small, or blank styles. This input is used to control the
4970
+ * visual presentation of the card content.
4971
+ * @type {'default' | 'small' | 'blank'}
4972
+ * @default 'default'
4973
+ */
4974
+ this.cardBody = 'default';
4975
+ /**
4976
+ * @description Specifies the type of the card.
4977
+ * @summary Determines the card's visual style, such as clear or shadowed.
4978
+ * This input allows for flexible styling of the card component to match
4979
+ * different design requirements.
4980
+ * @type {'clear' | 'shadow'}
4981
+ * @default 'clear'
4982
+ */
4983
+ this.cardType = 'clear';
4984
+ /**
4985
+ * @description Controls whether borders are displayed around the fieldset.
4986
+ * @summary Boolean flag that determines if the fieldset should be visually outlined with borders.
4987
+ * When true, borders are shown to visually separate the fieldset from surrounding content.
4988
+ *
4989
+ * @type {boolean}
4990
+ * @default true
4991
+ */
4992
+ this.borders = false;
4993
+ /**
4994
+ * @description Media breakpoint for responsive behavior.
4995
+ * @summary Determines the responsive breakpoint at which the layout should adapt.
4996
+ * This affects how the grid behaves on different screen sizes, allowing for
4997
+ * mobile-first or desktop-first responsive design patterns. The breakpoint
4998
+ * is automatically processed to ensure compatibility with the UI framework.
4999
+ *
5000
+ * @type {UIMediaBreakPointsType}
5001
+ * @default 'medium'
5002
+ */
5003
+ this.breakpoint = UIMediaBreakPoints.MEDIUM;
5004
+ /**
5005
+ * @description Determines if the layout should match the parent container's size or configuration.
5006
+ * @summary Boolean flag that controls whether the component should adapt its layout to match its parent.
5007
+ * When true, the component will attempt to align or size itself according to the parent container.
5008
+ *
5009
+ * @type {boolean}
5010
+ * @default true
5011
+ */
5012
+ this.match = true;
5013
+ /**
5014
+ * @description Preloads card placeholders for rendering.
5015
+ * @summary Used to create an array of placeholder elements for card components,
5016
+ * typically to reserve space or trigger rendering logic before actual data is loaded.
5017
+ *
5018
+ * @type {any[]}
5019
+ * @default [undefined]
5020
+ */
5021
+ this.preloadCards = new Array(1);
5022
+ }
5023
+ async ngOnInit(model) {
5024
+ if (model)
5025
+ this.model = model;
5026
+ if (this.model && !this.repository)
5027
+ this._repository = this.repository;
5028
+ }
5029
+ ngOnDestroy() {
5030
+ super.ngOnDestroy();
5031
+ if (this.timerSubscription)
5032
+ this.timerSubscription.unsubscribe();
5033
+ }
5034
+ getActivePage(page) {
5035
+ const content = this.children[page];
5036
+ this.activePage = undefined;
5037
+ this.preloadCards = [...new Array(1)];
5038
+ this.timerSubscription = timer(1).subscribe(() => this.activePage = { ...this.children[page] });
5039
+ this.activeIndex = page;
5040
+ if (content)
5041
+ return content;
5042
+ return undefined;
5043
+ }
5044
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: NgxParentComponentDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
5045
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.9", type: NgxParentComponentDirective, isStandalone: true, inputs: { page: "page", pages: "pages", parentForm: "parentForm", children: "children", cols: "cols", rows: "rows", cardBody: "cardBody", cardType: "cardType", borders: "borders", breakpoint: "breakpoint", match: "match" }, usesInheritance: true, ngImport: i0 }); }
5046
+ }
5047
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: NgxParentComponentDirective, decorators: [{
5048
+ type: Directive
5049
+ }], propDecorators: { page: [{
5050
+ type: Input
5051
+ }], pages: [{
5052
+ type: Input
5053
+ }], parentForm: [{
5054
+ type: Input
5055
+ }], children: [{
5056
+ type: Input
5057
+ }], cols: [{
5058
+ type: Input
5059
+ }], rows: [{
5060
+ type: Input
5061
+ }], cardBody: [{
5062
+ type: Input
5063
+ }], cardType: [{
5064
+ type: Input
5065
+ }], borders: [{
5066
+ type: Input
5067
+ }], breakpoint: [{
5068
+ type: Input
5069
+ }], match: [{
5070
+ type: Input
5071
+ }] } });
5072
+
5073
+ /**
5074
+ * @description Modal component for displaying dynamic content in a modal dialog.
5075
+ * @summary This component provides a flexible and reusable modal dialog implementation
5076
+ * for Angular applications. It supports dynamic content rendering, customizable options,
5077
+ * and event handling for modal lifecycle events. The modal can be used for various purposes,
5078
+ * such as displaying forms, lightboxes, or selection dialogs.
5079
+ *
5080
+ * @class ModalComponent
5081
+ * @example
5082
+ * ```typescript
5083
+ * <ngx-decaf-modal [isOpen]="true" [title]="'Example Modal'"></ngx-decaf-modal>
5084
+ * ```
5085
+ * @mermaid
5086
+ * sequenceDiagram
5087
+ * participant User
5088
+ * participant ModalComponent
5089
+ * User->>ModalComponent: Open modal
5090
+ * ModalComponent->>ModalController: Initialize modal
5091
+ * ModalController-->>ModalComponent: Modal options set
5092
+ * User->>ModalComponent: Interact with modal
5093
+ * ModalComponent->>ModalController: Handle dismiss event
5094
+ */
5095
+ let ModalComponent = class ModalComponent extends NgxParentComponentDirective {
5096
+ constructor() {
5097
+ super("ModalComponent");
5098
+ /**
5099
+ * @description Determines whether the modal is open.
5100
+ * @summary Controls the visibility of the modal dialog. When set to true, the modal is displayed.
5101
+ * @type {boolean}
5102
+ * @default false
5103
+ */
5104
+ this.isOpen = false;
5105
+ /**
5106
+ * @description Position of the inline content within the modal.
5107
+ * @summary Determines whether the inline content is displayed at the top or bottom of the modal.
5108
+ * @type {'top' | 'bottom'}
5109
+ * @default 'bottom'
5110
+ */
5111
+ this.inlineContentPosition = 'bottom';
5112
+ /**
5113
+ * @description Enables fullscreen mode for the modal.
5114
+ * @summary When set to true, the modal occupies the entire screen.
5115
+ * @type {boolean}
5116
+ * @default false
5117
+ */
5118
+ this.fullscreen = false;
5119
+ /**
5120
+ * @description Enables lightbox mode for the modal.
5121
+ * @summary When set to true, the modal is displayed as a lightbox.
5122
+ * @type {boolean}
5123
+ * @default false
5124
+ */
5125
+ this.lightBox = false;
5126
+ /**
5127
+ * @description Event emitted when the modal is about to be dismissed.
5128
+ * @summary Emits an OverlayEventDetail object containing details about the dismiss event.
5129
+ * @type {EventEmitter<OverlayEventDetail>}
5130
+ */
5131
+ this.willDismissEvent = new EventEmitter();
5132
+ /**
5133
+ * @description Sanitizer instance for bypassing security and sanitizing HTML content.
5134
+ * @summary Used to sanitize dynamic HTML content, ensuring it is safe to render in the DOM.
5135
+ * @type {DomSanitizer}
5136
+ */
5137
+ this.domSanitizer = inject(DomSanitizer);
5138
+ addIcons(allIcons);
5139
+ }
5140
+ /**
5141
+ * @description Lifecycle hook that initializes the modal component.
5142
+ * @summary Sets up the modal controller and sanitizes inline content if provided.
5143
+ *
5144
+ * @returns {Promise<void>} - A promise that resolves when initialization is complete.
5145
+ */
5146
+ async ngOnInit() {
5147
+ if (this.inlineContent && typeof this.inlineContent === Primitives.STRING) {
5148
+ this.inlineContent = this.domSanitizer.bypassSecurityTrustHtml(this.inlineContent);
5149
+ }
5150
+ }
5151
+ /**
5152
+ * @description Initializes the modal with the provided options.
5153
+ * @summary Merges default options with user-provided options and sets global configuration.
5154
+ *
5155
+ * @param {KeyValue} [options={}] - Additional options for modal initialization.
5156
+ * @returns {Promise<void>} - A promise that resolves when initialization is complete.
5157
+ */
5158
+ async initialize(options = {}) {
5159
+ this.options = Object.assign({}, DefaultModalOptions, this.options, options);
5160
+ this.globals = Object.assign({}, this.globals || {}, { isModalChild: true });
5161
+ this.initialized = true;
5162
+ }
5163
+ /**
5164
+ * @description Creates and presents the modal.
5165
+ * @summary Initializes the modal with the provided properties and displays it.
5166
+ *
5167
+ * @param {KeyValue} [props={}] - Properties to initialize the modal.
5168
+ * @returns {Promise<ModalComponent>} - A promise that resolves with the modal instance.
5169
+ */
5170
+ async create(props = {}) {
5171
+ await this.initialize(props);
5172
+ await this.present();
5173
+ return this;
5174
+ }
5175
+ /**
5176
+ * @description Presents the modal.
5177
+ * @summary Sets the modal's visibility to true and triggers change detection.
5178
+ *
5179
+ * @returns {Promise<void>} - A promise that resolves when the modal is presented.
5180
+ */
5181
+ async present() {
5182
+ this.isOpen = true;
5183
+ this.changeDetectorRef.detectChanges();
5184
+ }
5185
+ /**
5186
+ * @description Handles custom events for the modal.
5187
+ * @summary Stops event propagation and triggers confirm or cancel actions based on event data.
5188
+ *
5189
+ * @param {IBaseCustomEvent} event - The custom event to handle.
5190
+ * @returns {Promise<void>} - A promise that resolves when the event is handled.
5191
+ */
5192
+ async handleEvent(event) {
5193
+ if (event instanceof Event) {
5194
+ event.stopImmediatePropagation();
5195
+ }
5196
+ await (event?.data ? this.confirm(event) : this.cancel());
5197
+ }
5198
+ /**
5199
+ * @description Handles the modal dismiss event.
5200
+ * @summary This method is triggered when the modal is about to be dismissed. It emits the `willDismissEvent` with the event details.
5201
+ *
5202
+ * @param {CustomEvent<OverlayEventDetail>} event - The dismiss event containing overlay details.
5203
+ * @returns {Promise<OverlayEventDetail>} - A promise that resolves with the overlay event details.
5204
+ */
5205
+ async handleWillDismiss(event) {
5206
+ const { detail } = event;
5207
+ this.willDismissEvent.emit(event);
5208
+ return detail;
5209
+ }
5210
+ /**
5211
+ * @description Cancels the modal and dismisses it with a cancel action.
5212
+ * @summary This method is used to programmatically close the modal with a cancel action.
5213
+ *
5214
+ * @returns {Promise<void>} - A promise that resolves when the modal is dismissed.
5215
+ */
5216
+ async cancel() {
5217
+ await this.modal.dismiss(undefined, ActionRoles.cancel);
5218
+ }
5219
+ /**
5220
+ * @description Confirms the modal and dismisses it with a confirm action.
5221
+ * @summary This method is used to programmatically close the modal with a confirm action, passing optional event data.
5222
+ *
5223
+ * @param {IBaseCustomEvent} event - The custom event containing data to pass during confirmation.
5224
+ * @returns {Promise<void>} - A promise that resolves when the modal is dismissed.
5225
+ */
5226
+ async confirm(event) {
5227
+ await this.modal.dismiss(event?.data || undefined, ActionRoles.confirm);
5228
+ }
5229
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: ModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
5230
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: ModalComponent, isStandalone: true, selector: "ngx-decaf-modal", inputs: { title: "title", isOpen: "isOpen", tag: "tag", options: "options", globals: "globals", inlineContent: "inlineContent", inlineContentPosition: "inlineContentPosition", fullscreen: "fullscreen", lightBox: "lightBox" }, outputs: { willDismissEvent: "willDismissEvent" }, host: { properties: { "attr.id": "uid" } }, viewQueries: [{ propertyName: "modal", first: true, predicate: ["component"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<ion-modal\n [id]=\"uid\"\n [isOpen]=\"isOpen\"\n (willDismiss)=\"handleWillDismiss($event)\"\n [backdropDismiss]=\"options?.backdropDismiss\"\n [showBackdrop]=\"options?.showBackdrop\"\n [animated]=\"options?.animated\"\n [canDismiss]=\"options?.canDismiss\"\n [class.dcf-fullscreen-modal]=\"fullscreen\"\n [class.dcf-lightbox-modal]=\"lightBox\"\n class=\"dcf-modal-component\"\n #component\n>\n <ng-template>\n <ion-header [transparent]=\"lightBox\">\n <ion-toolbar>\n @if (title) {\n <ion-title>{{ title | translate }}</ion-title>\n }\n <ion-buttons slot=\"end\">\n <ion-button size=\"small\" type=\"button\" class=\"dcf-button-close\" (click)=\"cancel()\">\n <ion-icon name=\"close-outline\" aria-hidden=\"true\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n\n <ion-content>\n <section class=\"dcf-modal-body\">\n @if (!tag && !model && !inlineContent) {\n <div class=\"dcf-loading-container\">\n <ion-spinner name=\"crescent\" color=\"primary\"></ion-spinner>\n </div>\n } @else {\n @if (inlineContent && inlineContentPosition === \"top\") {\n <div [innerHTML]=\"inlineContent\"></div>\n }\n @if (model) {\n <ngx-decaf-model-renderer\n (onIonChange)=\"handleEvent($event)\"\n (listenEvent)=\"handleEvent($event)\"\n [model]=\"model\"\n [globals]=\"globals\"\n />\n }\n @if(tag && globals) {\n <ngx-decaf-component-renderer\n [tag]=\"tag\"\n (onIonChange)=\"handleEvent($event)\"\n (listenEvent)=\"handleEvent($event)\"\n [model]=\"model\"\n [globals]=\"{props: globals}\"\n />\n }\n @if (inlineContent && inlineContentPosition === \"bottom\") {\n <div [innerHTML]=\"inlineContent\"></div>\n }\n }\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n", styles: [".dcf-modal-component.dcf-fullscreen-modal{--height: 100%;--width: 100%;--max-width: 100%;--border-radius: 0}.dcf-modal-component.dcf-fullscreen-modal.dcf-lightbox-modal{padding:var(--dcf-padding-small)}.dcf-modal-component.dcf-lightbox-modal{--background: transparent;--box-shadow: none !important}@media (max-width: 767px){.dcf-modal-component.dcf-lightbox-modal{padding:var(--dcf-padding-xsmall)}.dcf-modal-component.dcf-lightbox-modal ion-button{transform:translate(2px,2px)!important}}.dcf-modal-component.dcf-lightbox-modal ion-header{--background: transparent !important;background-color:transparent;box-shadow:none!important;padding:unset!important;margin:unset!important;height:30px}.dcf-modal-component.dcf-lightbox-modal ion-header ion-button{margin:0!important;width:32px!important;height:25px!important;--background: var(--dcf-color-light) !important;transform:translate(2px);--border-radius: var(--dcf-border-radius-small) !important}.dcf-modal-component.dcf-lightbox-modal ion-header ion-button *{margin:-5px}.dcf-modal-component.dcf-lightbox-modal ion-header ion-toolbar{--background: transparent !important;padding:unset!important;margin:unset!important}.dcf-modal-component.dcf-lightbox-modal ion-content{--background: transparent !important}.dcf-modal-component.dcf-lightbox-modal .dcf-modal-body{display:flex;height:auto;justify-content:center;align-items:center;background:#fff!important}.dcf-modal-component:not(.dcf-lightbox-modal) .dcf-modal-body{height:100%;padding:1.5rem 1rem}.dcf-modal-component .dcf-loading-container{height:50%;display:flex;justify-content:center;align-items:center}.dcf-modal-component .dcf-loading-container ion-spinner{width:60px;height:60px}\n"], dependencies: [{ kind: "component", type: IonModal, selector: "ion-modal" }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "children", "projectable", "parent"] }, { kind: "component", type: ModelRendererComponent, selector: "ngx-decaf-model-renderer", inputs: ["projectable"] }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { 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: IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
5231
+ };
5232
+ ModalComponent = __decorate([
5233
+ Dynamic(),
5234
+ __metadata("design:paramtypes", [])
5235
+ ], ModalComponent);
5236
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: ModalComponent, decorators: [{
5237
+ type: Component,
5238
+ args: [{ selector: 'ngx-decaf-modal', standalone: true, imports: [IonModal, ComponentRendererComponent, ModelRendererComponent, TranslatePipe, IonSpinner, IonButton, IonButtons, IonContent, IonHeader, IonTitle, IonToolbar], host: { '[attr.id]': 'uid' }, template: "<ion-modal\n [id]=\"uid\"\n [isOpen]=\"isOpen\"\n (willDismiss)=\"handleWillDismiss($event)\"\n [backdropDismiss]=\"options?.backdropDismiss\"\n [showBackdrop]=\"options?.showBackdrop\"\n [animated]=\"options?.animated\"\n [canDismiss]=\"options?.canDismiss\"\n [class.dcf-fullscreen-modal]=\"fullscreen\"\n [class.dcf-lightbox-modal]=\"lightBox\"\n class=\"dcf-modal-component\"\n #component\n>\n <ng-template>\n <ion-header [transparent]=\"lightBox\">\n <ion-toolbar>\n @if (title) {\n <ion-title>{{ title | translate }}</ion-title>\n }\n <ion-buttons slot=\"end\">\n <ion-button size=\"small\" type=\"button\" class=\"dcf-button-close\" (click)=\"cancel()\">\n <ion-icon name=\"close-outline\" aria-hidden=\"true\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n\n <ion-content>\n <section class=\"dcf-modal-body\">\n @if (!tag && !model && !inlineContent) {\n <div class=\"dcf-loading-container\">\n <ion-spinner name=\"crescent\" color=\"primary\"></ion-spinner>\n </div>\n } @else {\n @if (inlineContent && inlineContentPosition === \"top\") {\n <div [innerHTML]=\"inlineContent\"></div>\n }\n @if (model) {\n <ngx-decaf-model-renderer\n (onIonChange)=\"handleEvent($event)\"\n (listenEvent)=\"handleEvent($event)\"\n [model]=\"model\"\n [globals]=\"globals\"\n />\n }\n @if(tag && globals) {\n <ngx-decaf-component-renderer\n [tag]=\"tag\"\n (onIonChange)=\"handleEvent($event)\"\n (listenEvent)=\"handleEvent($event)\"\n [model]=\"model\"\n [globals]=\"{props: globals}\"\n />\n }\n @if (inlineContent && inlineContentPosition === \"bottom\") {\n <div [innerHTML]=\"inlineContent\"></div>\n }\n }\n </section>\n </ion-content>\n </ng-template>\n</ion-modal>\n", styles: [".dcf-modal-component.dcf-fullscreen-modal{--height: 100%;--width: 100%;--max-width: 100%;--border-radius: 0}.dcf-modal-component.dcf-fullscreen-modal.dcf-lightbox-modal{padding:var(--dcf-padding-small)}.dcf-modal-component.dcf-lightbox-modal{--background: transparent;--box-shadow: none !important}@media (max-width: 767px){.dcf-modal-component.dcf-lightbox-modal{padding:var(--dcf-padding-xsmall)}.dcf-modal-component.dcf-lightbox-modal ion-button{transform:translate(2px,2px)!important}}.dcf-modal-component.dcf-lightbox-modal ion-header{--background: transparent !important;background-color:transparent;box-shadow:none!important;padding:unset!important;margin:unset!important;height:30px}.dcf-modal-component.dcf-lightbox-modal ion-header ion-button{margin:0!important;width:32px!important;height:25px!important;--background: var(--dcf-color-light) !important;transform:translate(2px);--border-radius: var(--dcf-border-radius-small) !important}.dcf-modal-component.dcf-lightbox-modal ion-header ion-button *{margin:-5px}.dcf-modal-component.dcf-lightbox-modal ion-header ion-toolbar{--background: transparent !important;padding:unset!important;margin:unset!important}.dcf-modal-component.dcf-lightbox-modal ion-content{--background: transparent !important}.dcf-modal-component.dcf-lightbox-modal .dcf-modal-body{display:flex;height:auto;justify-content:center;align-items:center;background:#fff!important}.dcf-modal-component:not(.dcf-lightbox-modal) .dcf-modal-body{height:100%;padding:1.5rem 1rem}.dcf-modal-component .dcf-loading-container{height:50%;display:flex;justify-content:center;align-items:center}.dcf-modal-component .dcf-loading-container ion-spinner{width:60px;height:60px}\n"] }]
5239
+ }], ctorParameters: () => [], propDecorators: { modal: [{
5240
+ type: ViewChild,
5241
+ args: ['component']
5242
+ }], title: [{
5243
+ type: Input
5244
+ }], isOpen: [{
5245
+ type: Input
5246
+ }], tag: [{
5247
+ type: Input
5248
+ }], options: [{
5249
+ type: Input
5250
+ }], globals: [{
5251
+ type: Input
5252
+ }], inlineContent: [{
5253
+ type: Input
5254
+ }], inlineContentPosition: [{
5255
+ type: Input
5256
+ }], fullscreen: [{
5257
+ type: Input
5258
+ }], lightBox: [{
5259
+ type: Input
5260
+ }], willDismissEvent: [{
5261
+ type: Output
5262
+ }] } });
5263
+ /**
5264
+ * @description Retrieves a modal component instance.
5265
+ * @summary Creates and initializes a modal component with the provided properties and options.
5266
+ *
5267
+ * @param {Partial<ModalComponent>} [props={}] - Properties to initialize the modal component.
5268
+ * @param {Partial<ModalOptions>} [modalProps={}] - Additional modal options.
5269
+ * @param {EnvironmentInjector} [injector] - Optional environment injector for dependency injection.
5270
+ * @returns {Promise<IonModal>} - A promise that resolves with the modal instance.
5271
+ */
5272
+ async function getNgxModalComponent(props = {}, modalProps = {}, injector) {
5273
+ const { globals } = { ...props };
5274
+ if (!globals || !globals?.['operation']) {
5275
+ props.globals = { ...(globals || {}), operation: OperationKeys.CREATE };
5276
+ }
5277
+ const component = await NgxRenderingEngine.createComponent(ModalComponent, props, injector || undefined).create(modalProps);
5278
+ return component.modal;
5279
+ }
5280
+ /**
5281
+ * @description Presents a lightbox modal with inline content.
5282
+ * @summary Displays a modal in lightbox mode with the specified content and properties.
5283
+ *
5284
+ * @param {string | SafeHtml} inlineContent - The content to display in the lightbox modal.
5285
+ * @param {Partial<ModalComponent>} [props={}] - Properties to initialize the modal component.
5286
+ * @param {EnvironmentInjector} [injector] - Optional environment injector for dependency injection.
5287
+ * @returns {Promise<void>} - A promise that resolves when the modal is presented.
5288
+ */
5289
+ async function presentNgxLightBoxModal(inlineContent, props = {}, injector) {
5290
+ return (await getNgxModalComponent({ props, ...{ inlineContent, lightBox: true } }, {}, injector || undefined)).present();
5291
+ }
5292
+ /**
5293
+ * @description Retrieves a modal for selecting options.
5294
+ * @summary Creates and initializes a modal component for displaying a list of selectable options.
5295
+ *
5296
+ * @param {SelectOption[]} options - The list of options to display in the modal.
5297
+ * @param {EnvironmentInjector} [injector] - Optional environment injector for dependency injection.
5298
+ * @returns {Promise<IonModal>} - A promise that resolves with the modal instance.
5299
+ */
5300
+ async function getNgxSelectOptionsModal(options, injector) {
5301
+ const props = {
5302
+ tag: 'ngx-decaf-list',
5303
+ globals: {
5304
+ data: options,
5305
+ item: { tag: true },
5306
+ pk: 'value',
5307
+ mapper: { title: 'text', uid: 'value' },
5308
+ },
5309
+ };
5310
+ return (await getNgxModalComponent(props, {}, injector || undefined));
5311
+ }
5312
+
5313
+ /**
5314
+ * @description A dynamic form field component for CRUD operations.
5315
+ * @summary The CrudFieldComponent is a versatile form field component that adapts to different
5316
+ * input types and CRUD operations. It extends NgxFormFieldDirective to inherit form handling capabilities
5317
+ * and implements lifecycle hooks to properly initialize, render, and clean up. This component
5318
+ * supports various input types (text, number, date, select, etc.), validation rules, and styling
5319
+ * options, making it suitable for building dynamic forms for create, read, update, and delete
5320
+ * operations.
5321
+ *
5322
+ * @param {CrudOperations} operation - The CRUD operation being performed (create, read, update, delete)
5323
+ * @param {string} name - The field name, used as form control identifier
5324
+ * @param {PossibleInputTypes} type - The input type (text, number, date, select, etc.)
5325
+ * @param {string|number|Date} value - The initial value of the field
5326
+ * @param {boolean} disabled - Whether the field is disabled
5327
+ * @param {string} label - The display label for the field
5328
+ * @param {string} placeholder - Placeholder text when field is empty
5329
+ * @param {string} format - Format pattern for the field value
5330
+ * @param {boolean} hidden - Whether the field should be hidden
5331
+ * @param {number|Date} max - Maximum allowed value
5332
+ * @param {number} maxlength - Maximum allowed length
5333
+ * @param {number|Date} min - Minimum allowed value
5334
+ * @param {number} minlength - Minimum allowed length
5335
+ * @param {string} pattern - Validation pattern
5336
+ * @param {boolean} readonly - Whether the field is read-only
5337
+ * @param {boolean} required - Whether the field is required
5338
+ * @param {number} step - Step value for number inputs
5339
+ * @param {FormGroup} formGroup - The parent form group
5340
+ * @param {StringOrBoolean} translatable - Whether field labels should be translated
5341
+ *
5342
+ * @component CrudFieldComponent
5343
+ * @example
5344
+ * <ngx-decaf-crud-field
5345
+ * operation="create"
5346
+ * name="firstName"
5347
+ * type="text"
5348
+ * label="<NAME>"
5349
+ * placeholder="<NAME>"
5350
+ * [value]="model.firstName"
5351
+ * [disabled]="model.readOnly">
5352
+ *
5353
+ *
5354
+ * @memberOf module:for-angular
5355
+ */
5356
+ let CrudFieldComponent = class CrudFieldComponent extends NgxFormFieldDirective {
5357
+ constructor() {
5358
+ super(...arguments);
5359
+ this.className = 'dcf-width-1-1';
5360
+ /**
5361
+ * @description The parent field path, if this field is nested.
5362
+ * @summary Specifies the full dot-delimited path of the parent field. This is only set when the field is nested.
5363
+ *
5364
+ * @type {string}
5365
+ * @memberOf CrudFieldComponent
5366
+ */
5367
+ /**
5368
+ * @description The parent field path for nested field structures.
5369
+ * @summary Specifies the full dot-delimited path of the parent field when this field
5370
+ * is part of a nested structure. This is used for hierarchical form organization
5371
+ * and proper form control resolution in complex form structures.
5372
+ *
5373
+ * @type {string}
5374
+ * @default ''
5375
+ * @memberOf CrudFieldComponent
5376
+ */
5377
+ this.childOf = '';
5378
+ /**
5379
+ * @description The initial value of the field.
5380
+ * @summary Sets the initial value of the form field. This can be a string, number, or Date
5381
+ * depending on the field type. For select fields, this should match one of the option values.
5382
+ *
5383
+ * @type {string | number | Date}
5384
+ * @default ''
5385
+ * @memberOf CrudFieldComponent
5386
+ */
5387
+ this.value = '';
5388
+ /**
5389
+ * @description Whether the field should be hidden.
5390
+ * @summary When true, the field will not be visible in the UI but will still be part of the form model.
5391
+ * This is useful for fields that need to be included in form submission but should not be displayed to the user.
5392
+ *
5393
+ * @type {boolean}
5394
+ * @memberOf CrudFieldComponent
5395
+ */
5396
+ this.hidden = false;
5397
+ /**
5398
+ * @description Interface style for select inputs.
5399
+ * @summary Specifies the interface style for select inputs, such as 'alert', 'action-sheet', or 'popover'.
5400
+ * This determines how the select options are presented to the user.
5401
+ *
5402
+ * @type {SelectInterface}
5403
+ * @memberOf CrudFieldComponent
5404
+ */
5405
+ this.interface = 'popover';
5406
+ /**
5407
+ * @description Spellcheck attribute for text inputs.
5408
+ * @summary Enables or disables spellchecking for text inputs.
5409
+ * When true, the browser will check the spelling of the input text.
5410
+ *
5411
+ * @type {boolean}
4777
5412
  * @default false
4778
5413
  * @memberOf CrudFieldComponent
4779
5414
  */
@@ -4869,7 +5504,6 @@ let CrudFieldComponent = class CrudFieldComponent extends NgxFormFieldDirective
4869
5504
  * @memberOf CrudFieldComponent
4870
5505
  */
4871
5506
  async ngOnInit() {
4872
- console.log(this.enableDarkMode, this.operation, this.name);
4873
5507
  this.options = await this.getOptions();
4874
5508
  addIcons({ chevronDownOutline, chevronUpOutline });
4875
5509
  if (Array.isArray(this.hidden) && !this.hidden.includes(this.operation)) {
@@ -4947,6 +5581,16 @@ let CrudFieldComponent = class CrudFieldComponent extends NgxFormFieldDirective
4947
5581
  this.interface = 'modal';
4948
5582
  return this.options;
4949
5583
  }
5584
+ async openSelectOptions(event, selectInterface) {
5585
+ if (selectInterface === 'modal') {
5586
+ event.preventDefault();
5587
+ event.stopImmediatePropagation();
5588
+ const modal = await getNgxSelectOptionsModal(this.options);
5589
+ const { data, role } = await modal.onWillDismiss();
5590
+ if (role === ActionRoles.confirm && data !== this.value)
5591
+ this.setValue(data);
5592
+ }
5593
+ }
4950
5594
  /**
4951
5595
  * @description Component after view initialization lifecycle method.
4952
5596
  * @summary Calls the parent afterViewInit method for READ and DELETE operations.
@@ -5011,7 +5655,7 @@ let CrudFieldComponent = class CrudFieldComponent extends NgxFormFieldDirective
5011
5655
  this.value = this.formControl.value;
5012
5656
  }
5013
5657
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: CrudFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
5014
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", 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>\n <div>\n <ion-item [class]=\"'dcf-input-item ' + operation\" #component>\n <ion-label>\n {{ label | translate }}<br />\n @if (value) {\n <ion-text [innerHTML]=\"type === 'password' ? '********' : value\"></ion-text>\n } @else {\n @if (['checkbox'].includes(type)) {\n <ion-icon class=\"dcf-margin-small-top\" [color]=\"!isDarkMode ? 'primary' : 'light'\" 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\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 (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n [mode]=\"'md'\"\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 (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n [mode]=\"'md'\"\n [errorText]=\"getErrors(container)\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"justify || 'start'\"\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 (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"option.text\"\n [mode]=\"'md'\"\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 (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n [errorText]=\"getErrors(container)\"\n [mode]=\"'md'\"\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 <div>\n <ion-select\n (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n toggleIcon=\"chevron-down-outline\"\n expandedIcon=\"chevron-up-outline\"\n [interface]=\"interface\"\n [mode]=\"'md'\"\n [hidden]=\"hidden || !options?.length\"\n [labelPlacement]=\"labelPlacement\"\n [label]=\"label | translate\"\n [value]=\"value\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [interface]=\"interface\" #component>\n @if (options?.length) {\n @for(option of options; track trackItemFn($index, option.text)) {\n <ion-select-option [value]=\"option.value\">\n {{ option.text | translate }}\n </ion-select-option>\n }\n }\n </ion-select>\n <div class=\"dcf-error\" [innerHTML]=\"getErrors(container)\"></div>\n @if (!options?.length) {\n <ion-text color=\"danger\">\n * {{ 'errors.empty_options' | translate:{'0': name} }}\n </ion-text>\n }\n </div>\n }\n @else {\n <ion-input\n (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n [type]=\"type\"\n [mode]=\"'md'\"\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: ["ion-item{--border-color: transparent}ion-item:not(.dcf-input-item){--inner-padding-start: 0rem;--padding-start: 0rem}ion-item.dcf-input-item{--padding-end: 0rem;--padding-start: 0px !important;--padding-top: 0px !important;--inner-padding-start: .75rem;--background: transparent;--background-hover-opacity: .1;--background-activated-opacity: .15;--background-focused-opacity: .15;--background-hover: var(--dcf-color-primary);--background-focused: var(--dcf-color-primary);--border-color: var(--dcf-color-gray-2)}ion-item.dcf-input-item.dcf-palette-dark{--border-color: var(--dcf-color-gray-6) !important}ion-item.dcf-input-item.read,ion-item.dcf-input-item.delete{--min-height: 30px;padding:unset;margin:unset!important;margin-bottom:var(--dcf-margin-xsmall)!important}ion-item.dcf-input-item.read ion-label,ion-item.dcf-input-item.delete ion-label{font-weight:600;margin-top:0!important;margin-bottom:.25rem!important;font-size:.925rem}ion-item.dcf-input-item.read ion-label:not(:first-of-type),ion-item.dcf-input-item.delete ion-label:not(:first-of-type){margin:100rem}ion-item.dcf-input-item.read span,ion-item.dcf-input-item.read ion-text,ion-item.dcf-input-item.delete span,ion-item.dcf-input-item.delete ion-text{font-weight:400!important;font-size:.825rem;min-height:.5rem!important}ion-item.dcf-input-item.read span:not(.dcf-display-block),ion-item.dcf-input-item.read ion-text:not(.dcf-display-block),ion-item.dcf-input-item.delete span:not(.dcf-display-block),ion-item.dcf-input-item.delete ion-text:not(.dcf-display-block){display:inline-block}ion-item.dcf-input-item.read span.dcf-display-block,ion-item.dcf-input-item.read ion-text.dcf-display-block,ion-item.dcf-input-item.delete span.dcf-display-block,ion-item.dcf-input-item.delete ion-text.dcf-display-block{display:block!important}ion-item.dcf-input-item>*,ion-item.dcf-input-item ion-select{width:100%!important}ion-item.dcf-input-item.create.checkbox+.checkbox,ion-item.dcf-input-item.update.checkbox+.checkbox{margin-top:-.25rem!important}ion-item.dcf-input-item.create ion-item,ion-item.dcf-input-item.update ion-item{--border-color: transparent}ion-item.dcf-input-item.create ion-item.dcf-text-wrap ion-label>*,ion-item.dcf-input-item.update ion-item.dcf-text-wrap ion-label>*{white-space:wrap!important;word-break:break-all!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::part(container){border:2px solid var(--dcf-color-primary);margin-left:.5rem;margin-right:.5rem;border-radius:var(--dcf-border-radius-small);padding:3px}ion-checkbox{--size: 1.5rem;--checkbox-background-checked: var(--dcf-color-primary);--checkmark-width: 2px}ion-radio-group .dcf-radio-group-label{font-weight:600}ion-radio-group .dcf-radio-group-label~ion-item{margin-top:.5rem;--inner-padding-start: .75rem}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:500!important;line-height:1.1rem;z-index:9999}.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;text-decoration:underline}.dcf-error+.dcf-helper{padding-top:1rem}::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" }] }); }
5658
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", 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>\n <div>\n <ion-item [class]=\"'dcf-input-item ' + operation\" #component>\n <ion-label>\n {{ label | translate }}<br />\n @if (value) {\n <ion-text [innerHTML]=\"type === 'password' ? '********' : value\"></ion-text>\n } @else {\n @if (['checkbox'].includes(type)) {\n <ion-icon aria-hidden=\"true\" class=\"dcf-margin-small-top\" [color]=\"!isDarkMode ? 'primary' : 'light'\" 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\n [id]=\"uid\" #container\n [class]=\"'dcf-input-item ' + (operation || 'create')\"\n [class.dcf-field-required]=\"required\"\n >\n @if (type === 'textarea') {\n <ion-textarea\n (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n [mode]=\"'md'\"\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 (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n [mode]=\"'md'\"\n [errorText]=\"getErrors(container)\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"justify || 'start'\"\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 (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"option.text\"\n [mode]=\"'md'\"\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 (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n [errorText]=\"getErrors(container)\"\n [mode]=\"'md'\"\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 <div>\n <ion-select\n (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n toggleIcon=\"chevron-down-outline\"\n expandedIcon=\"chevron-up-outline\"\n [interface]=\"interface\"\n [mode]=\"'md'\"\n [hidden]=\"hidden || !options?.length\"\n [labelPlacement]=\"labelPlacement\"\n [label]=\"label | translate\"\n [value]=\"value\"\n (click)=\"openSelectOptions($event, interface)\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [interface]=\"interface\" #component>\n @if (options?.length) {\n @for(option of options; track trackItemFn($index, option.text)) {\n <ion-select-option [value]=\"option.value\">\n {{ option.text | translate }}\n </ion-select-option>\n }\n }\n </ion-select>\n <div class=\"dcf-error\" [innerHTML]=\"getErrors(container)\"></div>\n @if (!options?.length) {\n <ion-text color=\"danger\">\n * {{ 'errors.empty_options' | translate:{'0': name} }}\n </ion-text>\n }\n </div>\n }\n @else {\n <ion-input\n (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n [type]=\"type\"\n [mode]=\"'md'\"\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: ["ion-item{--border-color: transparent}ion-item:not(.dcf-input-item){--inner-padding-start: 0rem;--padding-start: 0rem;--background: transparent}ion-item.dcf-input-item{--padding-end: 0rem;--padding-start: 0px !important;--padding-top: 0px !important;--inner-padding-start: .75rem;--background: transparent;--background-hover-opacity: .1;--background-activated-opacity: .15;--background-focused-opacity: .15;--background-hover: var(--dcf-color-primary);--background-focused: var(--dcf-color-primary);--border-color: var(--dcf-color-gray-2)}ion-item.dcf-input-item.dcf-palette-dark{--border-color: var(--dcf-color-gray-6) !important}ion-item.dcf-input-item.read,ion-item.dcf-input-item.delete{--min-height: 30px;padding:unset;margin:unset!important;margin-bottom:var(--dcf-margin-xsmall)!important}ion-item.dcf-input-item.read ion-label,ion-item.dcf-input-item.delete ion-label{font-weight:600;margin-top:0!important;margin-bottom:.25rem!important;font-size:.925rem}ion-item.dcf-input-item.read ion-label:not(:first-of-type),ion-item.dcf-input-item.delete ion-label:not(:first-of-type){margin:100rem}ion-item.dcf-input-item.read span,ion-item.dcf-input-item.read ion-text,ion-item.dcf-input-item.delete span,ion-item.dcf-input-item.delete ion-text{font-weight:400!important;font-size:.825rem;min-height:.5rem!important}ion-item.dcf-input-item.read span:not(.dcf-display-block),ion-item.dcf-input-item.read ion-text:not(.dcf-display-block),ion-item.dcf-input-item.delete span:not(.dcf-display-block),ion-item.dcf-input-item.delete ion-text:not(.dcf-display-block){display:inline-block}ion-item.dcf-input-item.read span.dcf-display-block,ion-item.dcf-input-item.read ion-text.dcf-display-block,ion-item.dcf-input-item.delete span.dcf-display-block,ion-item.dcf-input-item.delete ion-text.dcf-display-block{display:block!important}ion-item.dcf-input-item>*,ion-item.dcf-input-item ion-select{width:100%!important}ion-item.dcf-input-item.create.checkbox+.checkbox,ion-item.dcf-input-item.update.checkbox+.checkbox{margin-top:-.25rem!important}ion-item.dcf-input-item.create ion-item,ion-item.dcf-input-item.update ion-item{--border-color: transparent}ion-item.dcf-input-item.create ion-item.dcf-text-wrap ion-label>*,ion-item.dcf-input-item.update ion-item.dcf-text-wrap ion-label>*{white-space:wrap!important;word-break:break-all!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::part(container){border:2px solid var(--dcf-color-primary);margin-left:.5rem;margin-right:.5rem;border-radius:var(--dcf-border-radius-small);padding:3px}ion-checkbox{--size: 1.5rem;--checkbox-background-checked: var(--dcf-color-primary);--checkmark-width: 2px}ion-radio-group .dcf-radio-group-label{font-weight:600}ion-radio-group .dcf-radio-group-label~ion-item{margin-top:.5rem;--inner-padding-start: .75rem}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:500!important;line-height:1.1rem;z-index:9999}.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;text-decoration:underline}.dcf-error+.dcf-helper{padding-top:1rem}::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" }] }); }
5015
5659
  };
5016
5660
  CrudFieldComponent = __decorate([
5017
5661
  Dynamic()
@@ -5031,7 +5675,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
5031
5675
  IonLabel,
5032
5676
  IonText,
5033
5677
  IonTextarea
5034
- ], 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>\n <div>\n <ion-item [class]=\"'dcf-input-item ' + operation\" #component>\n <ion-label>\n {{ label | translate }}<br />\n @if (value) {\n <ion-text [innerHTML]=\"type === 'password' ? '********' : value\"></ion-text>\n } @else {\n @if (['checkbox'].includes(type)) {\n <ion-icon class=\"dcf-margin-small-top\" [color]=\"!isDarkMode ? 'primary' : 'light'\" 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\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 (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n [mode]=\"'md'\"\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 (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n [mode]=\"'md'\"\n [errorText]=\"getErrors(container)\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"justify || 'start'\"\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 (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"option.text\"\n [mode]=\"'md'\"\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 (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n [errorText]=\"getErrors(container)\"\n [mode]=\"'md'\"\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 <div>\n <ion-select\n (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n toggleIcon=\"chevron-down-outline\"\n expandedIcon=\"chevron-up-outline\"\n [interface]=\"interface\"\n [mode]=\"'md'\"\n [hidden]=\"hidden || !options?.length\"\n [labelPlacement]=\"labelPlacement\"\n [label]=\"label | translate\"\n [value]=\"value\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [interface]=\"interface\" #component>\n @if (options?.length) {\n @for(option of options; track trackItemFn($index, option.text)) {\n <ion-select-option [value]=\"option.value\">\n {{ option.text | translate }}\n </ion-select-option>\n }\n }\n </ion-select>\n <div class=\"dcf-error\" [innerHTML]=\"getErrors(container)\"></div>\n @if (!options?.length) {\n <ion-text color=\"danger\">\n * {{ 'errors.empty_options' | translate:{'0': name} }}\n </ion-text>\n }\n </div>\n }\n @else {\n <ion-input\n (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n [type]=\"type\"\n [mode]=\"'md'\"\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: ["ion-item{--border-color: transparent}ion-item:not(.dcf-input-item){--inner-padding-start: 0rem;--padding-start: 0rem}ion-item.dcf-input-item{--padding-end: 0rem;--padding-start: 0px !important;--padding-top: 0px !important;--inner-padding-start: .75rem;--background: transparent;--background-hover-opacity: .1;--background-activated-opacity: .15;--background-focused-opacity: .15;--background-hover: var(--dcf-color-primary);--background-focused: var(--dcf-color-primary);--border-color: var(--dcf-color-gray-2)}ion-item.dcf-input-item.dcf-palette-dark{--border-color: var(--dcf-color-gray-6) !important}ion-item.dcf-input-item.read,ion-item.dcf-input-item.delete{--min-height: 30px;padding:unset;margin:unset!important;margin-bottom:var(--dcf-margin-xsmall)!important}ion-item.dcf-input-item.read ion-label,ion-item.dcf-input-item.delete ion-label{font-weight:600;margin-top:0!important;margin-bottom:.25rem!important;font-size:.925rem}ion-item.dcf-input-item.read ion-label:not(:first-of-type),ion-item.dcf-input-item.delete ion-label:not(:first-of-type){margin:100rem}ion-item.dcf-input-item.read span,ion-item.dcf-input-item.read ion-text,ion-item.dcf-input-item.delete span,ion-item.dcf-input-item.delete ion-text{font-weight:400!important;font-size:.825rem;min-height:.5rem!important}ion-item.dcf-input-item.read span:not(.dcf-display-block),ion-item.dcf-input-item.read ion-text:not(.dcf-display-block),ion-item.dcf-input-item.delete span:not(.dcf-display-block),ion-item.dcf-input-item.delete ion-text:not(.dcf-display-block){display:inline-block}ion-item.dcf-input-item.read span.dcf-display-block,ion-item.dcf-input-item.read ion-text.dcf-display-block,ion-item.dcf-input-item.delete span.dcf-display-block,ion-item.dcf-input-item.delete ion-text.dcf-display-block{display:block!important}ion-item.dcf-input-item>*,ion-item.dcf-input-item ion-select{width:100%!important}ion-item.dcf-input-item.create.checkbox+.checkbox,ion-item.dcf-input-item.update.checkbox+.checkbox{margin-top:-.25rem!important}ion-item.dcf-input-item.create ion-item,ion-item.dcf-input-item.update ion-item{--border-color: transparent}ion-item.dcf-input-item.create ion-item.dcf-text-wrap ion-label>*,ion-item.dcf-input-item.update ion-item.dcf-text-wrap ion-label>*{white-space:wrap!important;word-break:break-all!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::part(container){border:2px solid var(--dcf-color-primary);margin-left:.5rem;margin-right:.5rem;border-radius:var(--dcf-border-radius-small);padding:3px}ion-checkbox{--size: 1.5rem;--checkbox-background-checked: var(--dcf-color-primary);--checkmark-width: 2px}ion-radio-group .dcf-radio-group-label{font-weight:600}ion-radio-group .dcf-radio-group-label~ion-item{margin-top:.5rem;--inner-padding-start: .75rem}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:500!important;line-height:1.1rem;z-index:9999}.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;text-decoration:underline}.dcf-error+.dcf-helper{padding-top:1rem}::ng-deep ion-textarea{min-height:80px!important;scrollbar-color:#888 #f0f0f0;scrollbar-width:thin}\n"] }]
5678
+ ], 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>\n <div>\n <ion-item [class]=\"'dcf-input-item ' + operation\" #component>\n <ion-label>\n {{ label | translate }}<br />\n @if (value) {\n <ion-text [innerHTML]=\"type === 'password' ? '********' : value\"></ion-text>\n } @else {\n @if (['checkbox'].includes(type)) {\n <ion-icon aria-hidden=\"true\" class=\"dcf-margin-small-top\" [color]=\"!isDarkMode ? 'primary' : 'light'\" 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\n [id]=\"uid\" #container\n [class]=\"'dcf-input-item ' + (operation || 'create')\"\n [class.dcf-field-required]=\"required\"\n >\n @if (type === 'textarea') {\n <ion-textarea\n (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n [mode]=\"'md'\"\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 (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n [mode]=\"'md'\"\n [errorText]=\"getErrors(container)\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"justify || 'start'\"\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 (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"option.text\"\n [mode]=\"'md'\"\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 (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n [errorText]=\"getErrors(container)\"\n [mode]=\"'md'\"\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 <div>\n <ion-select\n (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n toggleIcon=\"chevron-down-outline\"\n expandedIcon=\"chevron-up-outline\"\n [interface]=\"interface\"\n [mode]=\"'md'\"\n [hidden]=\"hidden || !options?.length\"\n [labelPlacement]=\"labelPlacement\"\n [label]=\"label | translate\"\n [value]=\"value\"\n (click)=\"openSelectOptions($event, interface)\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [interface]=\"interface\" #component>\n @if (options?.length) {\n @for(option of options; track trackItemFn($index, option.text)) {\n <ion-select-option [value]=\"option.value\">\n {{ option.text | translate }}\n </ion-select-option>\n }\n }\n </ion-select>\n <div class=\"dcf-error\" [innerHTML]=\"getErrors(container)\"></div>\n @if (!options?.length) {\n <ion-text color=\"danger\">\n * {{ 'errors.empty_options' | translate:{'0': name} }}\n </ion-text>\n }\n </div>\n }\n @else {\n <ion-input\n (ionInput)=\"handleModalChildChanges()\"\n (ionChange)=\"handleModalChildChanges()\"\n [id]=\"name\"\n [type]=\"type\"\n [mode]=\"'md'\"\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: ["ion-item{--border-color: transparent}ion-item:not(.dcf-input-item){--inner-padding-start: 0rem;--padding-start: 0rem;--background: transparent}ion-item.dcf-input-item{--padding-end: 0rem;--padding-start: 0px !important;--padding-top: 0px !important;--inner-padding-start: .75rem;--background: transparent;--background-hover-opacity: .1;--background-activated-opacity: .15;--background-focused-opacity: .15;--background-hover: var(--dcf-color-primary);--background-focused: var(--dcf-color-primary);--border-color: var(--dcf-color-gray-2)}ion-item.dcf-input-item.dcf-palette-dark{--border-color: var(--dcf-color-gray-6) !important}ion-item.dcf-input-item.read,ion-item.dcf-input-item.delete{--min-height: 30px;padding:unset;margin:unset!important;margin-bottom:var(--dcf-margin-xsmall)!important}ion-item.dcf-input-item.read ion-label,ion-item.dcf-input-item.delete ion-label{font-weight:600;margin-top:0!important;margin-bottom:.25rem!important;font-size:.925rem}ion-item.dcf-input-item.read ion-label:not(:first-of-type),ion-item.dcf-input-item.delete ion-label:not(:first-of-type){margin:100rem}ion-item.dcf-input-item.read span,ion-item.dcf-input-item.read ion-text,ion-item.dcf-input-item.delete span,ion-item.dcf-input-item.delete ion-text{font-weight:400!important;font-size:.825rem;min-height:.5rem!important}ion-item.dcf-input-item.read span:not(.dcf-display-block),ion-item.dcf-input-item.read ion-text:not(.dcf-display-block),ion-item.dcf-input-item.delete span:not(.dcf-display-block),ion-item.dcf-input-item.delete ion-text:not(.dcf-display-block){display:inline-block}ion-item.dcf-input-item.read span.dcf-display-block,ion-item.dcf-input-item.read ion-text.dcf-display-block,ion-item.dcf-input-item.delete span.dcf-display-block,ion-item.dcf-input-item.delete ion-text.dcf-display-block{display:block!important}ion-item.dcf-input-item>*,ion-item.dcf-input-item ion-select{width:100%!important}ion-item.dcf-input-item.create.checkbox+.checkbox,ion-item.dcf-input-item.update.checkbox+.checkbox{margin-top:-.25rem!important}ion-item.dcf-input-item.create ion-item,ion-item.dcf-input-item.update ion-item{--border-color: transparent}ion-item.dcf-input-item.create ion-item.dcf-text-wrap ion-label>*,ion-item.dcf-input-item.update ion-item.dcf-text-wrap ion-label>*{white-space:wrap!important;word-break:break-all!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::part(container){border:2px solid var(--dcf-color-primary);margin-left:.5rem;margin-right:.5rem;border-radius:var(--dcf-border-radius-small);padding:3px}ion-checkbox{--size: 1.5rem;--checkbox-background-checked: var(--dcf-color-primary);--checkmark-width: 2px}ion-radio-group .dcf-radio-group-label{font-weight:600}ion-radio-group .dcf-radio-group-label~ion-item{margin-top:.5rem;--inner-padding-start: .75rem}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:500!important;line-height:1.1rem;z-index:9999}.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;text-decoration:underline}.dcf-error+.dcf-helper{padding-top:1rem}::ng-deep ion-textarea{min-height:80px!important;scrollbar-color:#888 #f0f0f0;scrollbar-width:thin}\n"] }]
5035
5679
  }], propDecorators: { operation: [{
5036
5680
  type: Input,
5037
5681
  args: [{ required: true }]
@@ -5120,138 +5764,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
5120
5764
  args: ['component', { read: ElementRef }]
5121
5765
  }], formGroup: [{
5122
5766
  type: Input
5123
- }], formControl: [{
5124
- type: Input
5125
- }], multiple: [{
5126
- type: Input
5127
- }], uid: [{
5128
- type: Input
5129
- }], page: [{
5130
- type: Input
5131
- }], translatable: [{
5132
- type: Input
5133
- }], handleFieldsetUpdateGroupEvent: [{
5134
- type: HostListener,
5135
- args: ['window:fieldsetUpdateGroupEvent', ['$event']]
5136
- }] } });
5137
-
5138
- /**
5139
- * @module module:lib/engine/NgxParentComponentDirective
5140
- * @description Directive base for parent container components used by the rendering system.
5141
- * @summary Provides NgxParentComponentDirective which offers inputs for children metadata,
5142
- * column/row configuration and parent component wiring used by layout and container components.
5143
- *
5144
- * @link {@link NgxParentComponentDirective}
5145
- */
5146
- /**
5147
- * @description Layout component for creating responsive grid layouts in Angular applications.
5148
- * @summary This component provides a flexible grid system that can be configured with dynamic
5149
- * rows and columns. It supports responsive breakpoints and can render child components within
5150
- * the grid structure. The component extends NgxComponentDirective to inherit common functionality
5151
- * and integrates with the model and component renderer systems.
5152
- *
5153
- * @class NgxParentComponentDirective
5154
- * @extends {NgxComponentDirective}
5155
- * @implements {OnInit}
5156
- */
5157
- class NgxParentComponentDirective extends NgxComponentDirective {
5158
- constructor() {
5159
- super(...arguments);
5160
- /**
5161
- * @description Unique identifier for the current record.
5162
- * @summary A unique identifier for the current record being displayed or manipulated.
5163
- * This is typically used in conjunction with the primary key for operations on specific records.
5164
- *
5165
- * @type {string | number}
5166
- */
5167
- this.page = 1;
5168
- /**
5169
- * @description Unique identifier for the current record.
5170
- * @summary A unique identifier for the current record being displayed or manipulated.
5171
- * This is typically used in conjunction with the primary key for operations on specific records.
5172
- *
5173
- * @type {string | number}
5174
- */
5175
- this.pages = 1;
5176
- /**
5177
- * @description Array of UI model metadata for the currently active page.
5178
- * @summary Contains only the UI model metadata for fields that should be displayed
5179
- * on the currently active page. This is a filtered subset of the children array,
5180
- * updated whenever the user navigates between pages.
5181
- *
5182
- * @type {UIModelMetadata | UIModelMetadata[] | undefined}
5183
- */
5184
- this.activeContent = undefined;
5185
- /**
5186
- * @description The currently active page number.
5187
- * @summary Tracks which page of the multi-step form is currently being displayed.
5188
- * This property is updated as users navigate through the form steps using
5189
- * the next/back buttons or programmatic navigation.
5190
- *
5191
- * @type {number}
5192
- */
5193
- this.activeIndex = 1;
5194
- /**
5195
- * @description Array of UI model metadata for all form fields.
5196
- * @summary Contains the complete collection of UI model metadata that defines
5197
- * the structure, validation, and presentation of form fields across all pages.
5198
- * Each metadata object contains information about field type, validation rules,
5199
- * page assignment, and display properties.
5200
- *
5201
- * @type {UIModelMetadata[]}
5202
- */
5203
- this.children = [];
5204
- /**
5205
- * @description Number of columns or array of column definitions for the grid layout.
5206
- * @summary Defines the column structure of the grid. When a number is provided, it creates
5207
- * that many equal-width columns. When an array is provided, each element can define specific
5208
- * column properties or sizing. This allows for flexible grid layouts that can adapt to
5209
- * different content requirements.
5210
- *
5211
- * @type {(number | string[])}
5212
- * @default 1
5213
- */
5214
- this.cols = 1;
5215
- /**
5216
- * @description Number of rows or array of row definitions for the grid layout.
5217
- * @summary Defines the row structure of the grid. When a number is provided, it creates
5218
- * that many equal-height rows. When an array is provided, each element can define specific
5219
- * row properties or sizing. This provides control over vertical spacing and content organization.
5220
- *
5221
- * @type {(number | string[])}
5222
- * @default 1
5223
- */
5224
- this.rows = 1;
5225
- }
5226
- async ngOnInit(model) {
5227
- if (model)
5228
- this.model = model;
5229
- if (this.model && !this.repository)
5230
- this._repository = this.repository;
5231
- }
5232
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: NgxParentComponentDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
5233
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.9", type: NgxParentComponentDirective, isStandalone: true, inputs: { page: "page", pages: "pages", parentForm: "parentForm", children: "children", cols: "cols", rows: "rows" }, usesInheritance: true, ngImport: i0 }); }
5234
- }
5235
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: NgxParentComponentDirective, decorators: [{
5236
- type: Directive
5237
- }], propDecorators: { page: [{
5238
- type: Input
5239
- }], pages: [{
5767
+ }], formControl: [{
5240
5768
  type: Input
5241
- }], parentForm: [{
5769
+ }], multiple: [{
5242
5770
  type: Input
5243
- }], children: [{
5771
+ }], uid: [{
5244
5772
  type: Input
5245
- }], cols: [{
5773
+ }], page: [{
5246
5774
  type: Input
5247
- }], rows: [{
5775
+ }], translatable: [{
5248
5776
  type: Input
5777
+ }], handleFieldsetUpdateGroupEvent: [{
5778
+ type: HostListener,
5779
+ args: ['window:fieldsetUpdateGroupEvent', ['$event']]
5249
5780
  }] } });
5250
5781
 
5251
5782
  class NgxFormDirective extends NgxParentComponentDirective {
5252
5783
  constructor() {
5253
5784
  super(...arguments);
5254
- this.crudFieldComponent = ComponentsTagNames.CRUD_FIELD;
5255
5785
  /**
5256
5786
  * @description Indicates whether this form is being used inside a modal dialog.
5257
5787
  * @summary When true, the form may alter its submit/reset behavior to integrate
@@ -5336,6 +5866,7 @@ class NgxFormDirective extends NgxParentComponentDirective {
5336
5866
  * @default Randomly generated 12-character string
5337
5867
  */
5338
5868
  this.allowClear = true;
5869
+ this.match = false;
5339
5870
  // protected override enableDarkMode: boolean = true;
5340
5871
  // /**
5341
5872
  // * @description Angular change detection service.
@@ -5386,14 +5917,14 @@ class NgxFormDirective extends NgxParentComponentDirective {
5386
5917
  */
5387
5918
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
5388
5919
  async ngOnInit(model) {
5389
- this.uid = generateRandomValue(12);
5920
+ if (!this.uid)
5921
+ this.uid = generateRandomValue(12);
5390
5922
  // dont call super.ngOnInit to model conflicts
5391
5923
  if (this.operation === OperationKeys.READ || this.operation === OperationKeys.DELETE)
5392
5924
  this.formGroup = undefined;
5393
5925
  this.initialized = true;
5394
5926
  }
5395
5927
  ngAfterViewInit() {
5396
- this.isModalChild = this.component.nativeElement?.closest('ion-modal') ? true : false;
5397
5928
  if (this.isModalChild)
5398
5929
  this.changeDetectorRef.detectChanges();
5399
5930
  }
@@ -5411,9 +5942,14 @@ class NgxFormDirective extends NgxParentComponentDirective {
5411
5942
  NgxFormService.unregister(this.formGroup);
5412
5943
  }
5413
5944
  getFormArrayIndex(index) {
5414
- if (!(this.formGroup instanceof FormArray) && this.formGroup)
5945
+ if (!(this.formGroup instanceof FormArray) && this.formGroup) {
5946
+ if (this.formGroup.disabled)
5947
+ this.formGroup.enable();
5415
5948
  return this.formGroup;
5949
+ }
5416
5950
  const formGroup = this.formGroup.at(index);
5951
+ if (formGroup.disabled)
5952
+ formGroup.enable();
5417
5953
  if (formGroup) {
5418
5954
  if (this.children.length) {
5419
5955
  const children = [...this.children];
@@ -5464,18 +6000,54 @@ class NgxFormDirective extends NgxParentComponentDirective {
5464
6000
  const isValid = NgxFormService.validateFields(this.formGroup);
5465
6001
  if (this.isModalChild)
5466
6002
  this.changeDetectorRef.detectChanges();
5467
- if (!isValid)
6003
+ if (!isValid) {
5468
6004
  return false;
6005
+ }
5469
6006
  const data = NgxFormService.getFormData(this.formGroup);
5470
6007
  this.submitEvent.emit({
5471
6008
  data,
5472
6009
  component: componentName || this.componentName,
5473
- name: eventName || this.action || EventConstants.SUBMIT,
6010
+ name: eventName || this.action || ComponentEventNames.SUBMIT,
5474
6011
  handlers: this.handlers,
5475
6012
  });
5476
6013
  }
6014
+ /**
6015
+ * @description Updates the active form group and children for the specified page.
6016
+ * @summary Extracts the FormGroup for the given page from the FormArray and filters
6017
+ * the children to show only fields belonging to that page. Uses a timer to ensure
6018
+ * proper Angular change detection when updating the activeContent.
6019
+ *
6020
+ * @param {number} page - The page number to activate
6021
+ * @return {UIModelMetadata | UIModelMetadata[] | FieldDefinition | undefined}
6022
+ *
6023
+ * @private
6024
+ * @mermaid
6025
+ * sequenceDiagram
6026
+ * participant S as SteppedFormComponent
6027
+ * participant F as FormArray
6028
+ * participant T as Timer
6029
+ *
6030
+ * S->>F: Extract FormGroup at index (page - 1)
6031
+ * F-->>S: Return page FormGroup
6032
+ * S->>S: Set activeContent = undefined
6033
+ * S->>T: timer(10).subscribe()
6034
+ * T-->>S: Filter children for active page
6035
+ * S->>S: Set activeContent
6036
+ *
6037
+ * @memberOf SteppedFormComponent
6038
+ */
6039
+ getActivePage(page) {
6040
+ if (!(this.formGroup instanceof FormArray))
6041
+ this.formGroup = this.formGroup?.parent;
6042
+ this.formGroup = this.formGroup.at(page - 1);
6043
+ this.activePage = undefined;
6044
+ this.timerSubscription = timer(10).subscribe(() => this.activePage = this.children.filter(c => c.props?.['page'] === page));
6045
+ if (this.activePage)
6046
+ return this.activePage;
6047
+ return undefined;
6048
+ }
5477
6049
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: NgxFormDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
5478
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.9", type: NgxFormDirective, isStandalone: true, inputs: { parentFormId: "parentFormId", modalForm: "modalForm", updateOn: "updateOn", target: "target", method: "method", options: "options", action: "action", operation: "operation", handlers: "handlers", formGroup: "formGroup", rendererId: "rendererId", allowClear: "allowClear" }, outputs: { submitEvent: "submitEvent" }, viewQueries: [{ propertyName: "component", first: true, predicate: ["component"], descendants: true, read: ElementRef }], usesInheritance: true, ngImport: i0 }); }
6050
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.9", type: NgxFormDirective, isStandalone: true, inputs: { parentFormId: "parentFormId", modalForm: "modalForm", updateOn: "updateOn", target: "target", method: "method", options: "options", action: "action", operation: "operation", handlers: "handlers", formGroup: "formGroup", rendererId: "rendererId", allowClear: "allowClear", match: "match" }, outputs: { submitEvent: "submitEvent" }, viewQueries: [{ propertyName: "component", first: true, predicate: ["component"], descendants: true, read: ElementRef }], usesInheritance: true, ngImport: i0 }); }
5479
6051
  }
5480
6052
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: NgxFormDirective, decorators: [{
5481
6053
  type: Directive
@@ -5509,97 +6081,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
5509
6081
  type: Output
5510
6082
  }], allowClear: [{
5511
6083
  type: Input
5512
- }] } });
5513
-
5514
- /**
5515
- * @module module:lib/components/model-renderer/model-renderer.component
5516
- * @description Model renderer component module.
5517
- * @summary Exposes `ModelRendererComponent` which dynamically renders UI components
5518
- * from model definitions using the `NgxRenderingEngine`. It handles model changes,
5519
- * event subscription and lifecycle for the rendered output.
5520
- *
5521
- * @link {@link ModelRendererComponent}
5522
- */
5523
- /**
5524
- * @description Component for rendering dynamic models
5525
- * @summary This component is responsible for dynamically rendering models,
5526
- * handling model changes, and managing event subscriptions for the rendered components.
5527
- * It uses the NgxRenderingEngine to render the models and supports both string and Model inputs.
5528
- * @class
5529
- * @template M - Type extending Model
5530
- * @param {Injector} injector - Angular Injector for dependency injection
5531
- * @example
5532
- * <ngx-decaf-model-renderer
5533
- * [model]="myModel"
5534
- * [globals]="globalVariables"
5535
- * (listenEvent)="handleEvent($event)">
5536
- * </ngx-decaf-model-renderer>
5537
- * @mermaid
5538
- * sequenceDiagram
5539
- * participant App
5540
- * participant ModelRenderer
5541
- * participant RenderingEngine
5542
- * participant Model
5543
- * App->>ModelRenderer: Input model
5544
- * ModelRenderer->>Model: Parse if string
5545
- * Model-->>ModelRenderer: Parsed model
5546
- * ModelRenderer->>RenderingEngine: Render model
5547
- * RenderingEngine-->>ModelRenderer: Rendered output
5548
- * ModelRenderer->>ModelRenderer: Subscribe to events
5549
- * ModelRenderer-->>App: Emit events
5550
- */
5551
- class ModelRendererComponent extends NgxRenderableComponentDirective {
5552
- constructor() {
5553
- super(...arguments);
5554
- /**
5555
- * @description Set if render content projection is allowed
5556
- * @default true
5557
- */
5558
- this.projectable = true;
5559
- }
5560
- // private injector: Injector = inject(Injector);
5561
- // constructor() {}
5562
- /**
5563
- * @description Refreshes the rendered model
5564
- * @param {string | M} model - The model to be rendered
5565
- */
5566
- refresh(model) {
5567
- model =
5568
- typeof model === 'string'
5569
- ? Model.build({}, model)
5570
- : model;
5571
- this.output = model.render(this.globals || {}, this.vcr, this.injector, this.inner, this.projectable);
5572
- if (this.output?.inputs)
5573
- this.rendererId = sf(AngularEngineKeys.RENDERED_ID, this.output.inputs['rendererId']);
5574
- this.instance = this.output?.component;
5575
- this.subscribeEvents();
5576
- }
5577
- /**
5578
- * @description Lifecycle hook that is called when data-bound properties of a directive change
5579
- * @param {SimpleChanges} changes - Object containing changes
5580
- */
5581
- ngOnChanges(changes) {
5582
- if (changes[BaseComponentProps.MODEL]) {
5583
- const { currentValue } = changes[BaseComponentProps.MODEL];
5584
- this.refresh(currentValue);
5585
- }
5586
- }
5587
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: ModelRendererComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
5588
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.9", type: ModelRendererComponent, isStandalone: true, selector: "ngx-decaf-model-renderer", inputs: { projectable: "projectable" }, host: { properties: { "attr.id": "uid" } }, usesInheritance: true, usesOnChanges: true, ngImport: i0, template: " <!-- Keep to avoid id conflicts -->\n <div class=\"dcf-hidden\" [id]=\"uid\"></div>\n\n <ng-template #componentOuter></ng-template>\n <!-- <ng-template #inner>\n <div class=\"dcf-grid dcf-grid-small dcf-model-renderer-component dcf-child-width-1-1\" [id]=\"rendererId || ''\">\n @for (child of output?.children; track child) {\n @if (child?.children?.length) {\n <ngx-decaf-component-renderer [parent]=\"child\" />\n } @else {\n <ng-container\n #childComponents\n *ngComponentOutlet=\"\n child.component;\n injector: child.injector;\n inputs: child.inputs;\n content:child.content;\n \"\n />\n }\n }\n </div>\n </ng-template> -->\n", styles: [""] }); }
5589
- }
5590
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: ModelRendererComponent, decorators: [{
5591
- type: Component,
5592
- args: [{ standalone: true, imports: [], selector: 'ngx-decaf-model-renderer', host: { '[attr.id]': 'uid' }, template: " <!-- Keep to avoid id conflicts -->\n <div class=\"dcf-hidden\" [id]=\"uid\"></div>\n\n <ng-template #componentOuter></ng-template>\n <!-- <ng-template #inner>\n <div class=\"dcf-grid dcf-grid-small dcf-model-renderer-component dcf-child-width-1-1\" [id]=\"rendererId || ''\">\n @for (child of output?.children; track child) {\n @if (child?.children?.length) {\n <ngx-decaf-component-renderer [parent]=\"child\" />\n } @else {\n <ng-container\n #childComponents\n *ngComponentOutlet=\"\n child.component;\n injector: child.injector;\n inputs: child.inputs;\n content:child.content;\n \"\n />\n }\n }\n </div>\n </ng-template> -->\n" }]
5593
- }], propDecorators: { projectable: [{
6084
+ }], match: [{
5594
6085
  type: Input
5595
6086
  }] } });
5596
6087
 
5597
6088
  let CardComponent = class CardComponent extends NgxComponentDirective {
5598
6089
  constructor() {
5599
6090
  super(...arguments);
5600
- this.type = 'default';
6091
+ this.type = 'clear';
5601
6092
  this.title = '';
5602
- this.body = 'small';
6093
+ this.body = 'default';
5603
6094
  this.subtitle = '';
5604
6095
  this.color = '';
5605
6096
  this.separator = false;
@@ -5608,18 +6099,21 @@ let CardComponent = class CardComponent extends NgxComponentDirective {
5608
6099
  this.componentName = 'CardComponent';
5609
6100
  }
5610
6101
  ngOnInit() {
5611
- console.log(this.componentName, this.type);
5612
6102
  this.initialized = true;
6103
+ this.mediaService.isDarkMode().subscribe(isDark => {
6104
+ this.isDarkMode = isDark;
6105
+ this.mediaService.toggleClass([this.component], AngularEngineKeys.DARK_PALETTE_CLASS, this.isDarkMode);
6106
+ });
5613
6107
  }
5614
6108
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: CardComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
5615
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: CardComponent, isStandalone: true, selector: "ngx-decaf-card", inputs: { type: "type", title: "title", body: "body", subtitle: "subtitle", color: "color", separator: "separator", borders: "borders", inlineContent: "inlineContent", inlineContentPosition: "inlineContentPosition" }, usesInheritance: true, ngImport: i0, template: "\n <ion-card\n [class]=\"'dcf-card ' + className\"\n [color]=\"color\"\n mode=\"md\"\n [class.dcf-card-separator]=\"separator\"\n [class.dcf-card-default]=\"type === 'default'\"\n [class.dcf-card-shadow]=\"type === 'shadow'\"\n [class.dcf-card-bordered]=\"borders\"\n [class.dcf-card-small]=\"body === 'small'\"\n #component\n >\n @if(title || subtitle) {\n <ion-card-header>\n @if(title) {\n <ion-card-title>{{ locale ? (title | translate) : title }}</ion-card-title>\n }\n @if(subtitle) {\n <ion-card-subtitle>{{ locale ? (subtitle | translate) : subtitle }}</ion-card-subtitle>\n }\n </ion-card-header>\n }\n <ion-card-content>\n @if(inlineContent && inlineContentPosition === 'top') {\n <div [innerHTML]=\"inlineContent\"></div>\n }\n\n <ng-content slot=\"content\"></ng-content>\n\n @if(inlineContent && inlineContentPosition === 'bottom') {\n <div [innerHTML]=\"inlineContent\"></div>\n }\n </ion-card-content>\n </ion-card>\n\n", styles: [".dcf-card{display:flow-root;border-radius:var(--dcf-border-radius-small)}.dcf-card>*{width:100%!important}.dcf-card ion-card-content{padding:var(--dcf-padding)}.dcf-card ion-card-header+ion-card-content{padding-top:0!important;margin-top:var(--dcf-margin-small)}.dcf-card ion-card-header{padding-left:1.25rem}@media (max-width: 575px){.dcf-card ion-card-header{padding-left:.2rem!important}.dcf-card ion-card-content{padding:var(--dcf-margin-small)}.dcf-card.dcf-card-small ion-content{padding:var(--dcf-padding-xsmall)}}.dcf-card.dcf-card-default{box-shadow:none!important}.dcf-card.dcf-card-default.dcf-card-bordered .dcf-card-bordered{border-color:transparent!important}.dcf-card.dcf-height-1-1{display:flex;align-items:center;justify-content:center}.dcf-card.dcf-height-1-1.dcf-card-layout{height:calc(100% - 1.5rem)}.dcf-card.dcf-card-shadow{box-shadow:var(--dcf-card-box-shadow)!important}.dcf-card.dcf-card-bordered{border:1px solid var(--dcf-color-gray-2)}.dcf-card ion-card-title{padding:var(--dcf-padding-small) var(--dcf-spacement) 0rem var(--dcf-spacement)!important;font-weight:500;font-size:1.125rem;line-height:1.75rem}.dcf-card ion-card-subtitle{padding:0rem var(--dcf-spacement);color:var(--ion-color-gray-4);margin-top:0!important}.dcf-palette-dark.dcf-card-bordered{border-color:transparent!important}::ng-deep ngx-decaf-list ion-list{padding:0!important;margin:0!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: IonCardHeader, selector: "ion-card-header", inputs: ["color", "mode", "translucent"] }, { kind: "component", type: IonCardContent, selector: "ion-card-content", inputs: ["mode"] }, { kind: "component", type: IonCardTitle, selector: "ion-card-title", inputs: ["color", "mode"] }, { kind: "component", type: IonCardSubtitle, selector: "ion-card-subtitle", inputs: ["color", "mode"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
6109
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: CardComponent, isStandalone: true, selector: "ngx-decaf-card", inputs: { type: "type", title: "title", body: "body", subtitle: "subtitle", color: "color", separator: "separator", borders: "borders", inlineContent: "inlineContent", inlineContentPosition: "inlineContentPosition" }, usesInheritance: true, ngImport: i0, template: "<ion-card\n [class]=\"'dcf-card ' + className + ' ' + 'dcf-card-' + body\"\n [color]=\"color\"\n mode=\"md\"\n [class.dcf-card-separator]=\"separator\"\n [class.dcf-card-shadow]=\"type === 'shadow'\"\n [class.dcf-card-bordered]=\"borders\"\n [class.dcf-card-separator]=\"separator\"\n #component\n>\n @if (title || subtitle) {\n <ion-card-header>\n @if (title) {\n <ion-card-title>{{\n locale ? (title | translate) : title\n }}</ion-card-title>\n }\n @if (subtitle) {\n <ion-card-subtitle>{{\n locale ? (subtitle | translate) : subtitle\n }}</ion-card-subtitle>\n }\n </ion-card-header>\n }\n <ion-card-content>\n @if (inlineContent && inlineContentPosition === \"top\") {\n <div [innerHTML]=\"inlineContent\"></div>\n }\n\n <ng-content slot=\"content\"></ng-content>\n\n @if (inlineContent && inlineContentPosition === \"bottom\") {\n <div [innerHTML]=\"inlineContent\"></div>\n }\n </ion-card-content>\n</ion-card>\n", styles: [".dcf-card{display:flow-root;border-radius:var(--dcf-border-radius-small)}.dcf-card .dcf-card{border-radius:0!important}.dcf-card:not(.dcf-card-shadow){box-shadow:none!important}.dcf-card:not(.dcf-card-shadow).dcf-card-bordered .dcf-card-bordered{border-color:transparent!important}.dcf-card.dcf-card-separator,.dcf-card.dcf-card-blank{padding:0!important;margin:0!important;background:transparent!important}.dcf-card.dcf-card-separator>*,.dcf-card.dcf-card-blank>*{padding:0!important;margin:0!important}.dcf-card.dcf-card-separator ion-card-header{padding:unset!important;margin:unset!important}.dcf-card.dcf-card-separator ion-card-title{padding:unset!important;margin:unset!important;font-weight:500;font-size:1rem;line-height:1.5rem}.dcf-card.dcf-card-separator.dcf-card-bordered{border-color:transparent!important}.dcf-card.dcf-card-small ion-card-header{padding:var(--dcf-padding-xsmall) 0!important}.dcf-card.dcf-card-small ion-card-content{padding:var(--dcf-padding-xsmall)!important}.dcf-card>*{width:100%!important}.dcf-card ion-card-content{padding:var(--dcf-padding)}.dcf-card ion-card-header+ion-card-content{padding-top:0!important;margin-top:var(--dcf-margin-small)}.dcf-card ion-card-header{padding-left:1.25rem}@media (max-width: 575px){.dcf-card ion-card-header{padding-left:.2rem!important}.dcf-card ion-card-header+ion-card-content{margin-top:var(--dcf-margin-small)}.dcf-card ion-card-content{padding:var(--dcf-margin) var(--dcf-margin-small)}.dcf-card.dcf-card-small ion-content{padding:var(--dcf-padding-xsmall)}}.dcf-card.dcf-height-1-1{display:flex;align-items:center;justify-content:center}.dcf-card.dcf-height-1-1.dcf-card-layout{height:calc(100% - 1.5rem)}.dcf-card.dcf-card-shadow{box-shadow:var(--dcf-card-box-shadow)!important}.dcf-card.dcf-card-bordered{border:1px solid var(--dcf-color-gray-2)}.dcf-card ion-card-title{padding:var(--dcf-padding-small) var(--dcf-spacement) 0rem var(--dcf-spacement)!important;font-weight:500;font-size:1.125rem;line-height:1.75rem}.dcf-card ion-card-subtitle{padding:0rem var(--dcf-spacement);color:var(--ion-color-gray-4);margin-top:0!important}.dcf-palette-dark.dcf-card-bordered{border-color:transparent!important}::ng-deep ngx-decaf-list ion-list{padding:0!important;margin:0!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: IonCardHeader, selector: "ion-card-header", inputs: ["color", "mode", "translucent"] }, { kind: "component", type: IonCardContent, selector: "ion-card-content", inputs: ["mode"] }, { kind: "component", type: IonCardTitle, selector: "ion-card-title", inputs: ["color", "mode"] }, { kind: "component", type: IonCardSubtitle, selector: "ion-card-subtitle", inputs: ["color", "mode"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
5616
6110
  };
5617
6111
  CardComponent = __decorate([
5618
6112
  Dynamic()
5619
6113
  ], CardComponent);
5620
6114
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: CardComponent, decorators: [{
5621
6115
  type: Component,
5622
- args: [{ selector: 'ngx-decaf-card', imports: [TranslatePipe, IonCard, IonCardHeader, IonCardContent, IonCardTitle, IonCardSubtitle], standalone: true, template: "\n <ion-card\n [class]=\"'dcf-card ' + className\"\n [color]=\"color\"\n mode=\"md\"\n [class.dcf-card-separator]=\"separator\"\n [class.dcf-card-default]=\"type === 'default'\"\n [class.dcf-card-shadow]=\"type === 'shadow'\"\n [class.dcf-card-bordered]=\"borders\"\n [class.dcf-card-small]=\"body === 'small'\"\n #component\n >\n @if(title || subtitle) {\n <ion-card-header>\n @if(title) {\n <ion-card-title>{{ locale ? (title | translate) : title }}</ion-card-title>\n }\n @if(subtitle) {\n <ion-card-subtitle>{{ locale ? (subtitle | translate) : subtitle }}</ion-card-subtitle>\n }\n </ion-card-header>\n }\n <ion-card-content>\n @if(inlineContent && inlineContentPosition === 'top') {\n <div [innerHTML]=\"inlineContent\"></div>\n }\n\n <ng-content slot=\"content\"></ng-content>\n\n @if(inlineContent && inlineContentPosition === 'bottom') {\n <div [innerHTML]=\"inlineContent\"></div>\n }\n </ion-card-content>\n </ion-card>\n\n", styles: [".dcf-card{display:flow-root;border-radius:var(--dcf-border-radius-small)}.dcf-card>*{width:100%!important}.dcf-card ion-card-content{padding:var(--dcf-padding)}.dcf-card ion-card-header+ion-card-content{padding-top:0!important;margin-top:var(--dcf-margin-small)}.dcf-card ion-card-header{padding-left:1.25rem}@media (max-width: 575px){.dcf-card ion-card-header{padding-left:.2rem!important}.dcf-card ion-card-content{padding:var(--dcf-margin-small)}.dcf-card.dcf-card-small ion-content{padding:var(--dcf-padding-xsmall)}}.dcf-card.dcf-card-default{box-shadow:none!important}.dcf-card.dcf-card-default.dcf-card-bordered .dcf-card-bordered{border-color:transparent!important}.dcf-card.dcf-height-1-1{display:flex;align-items:center;justify-content:center}.dcf-card.dcf-height-1-1.dcf-card-layout{height:calc(100% - 1.5rem)}.dcf-card.dcf-card-shadow{box-shadow:var(--dcf-card-box-shadow)!important}.dcf-card.dcf-card-bordered{border:1px solid var(--dcf-color-gray-2)}.dcf-card ion-card-title{padding:var(--dcf-padding-small) var(--dcf-spacement) 0rem var(--dcf-spacement)!important;font-weight:500;font-size:1.125rem;line-height:1.75rem}.dcf-card ion-card-subtitle{padding:0rem var(--dcf-spacement);color:var(--ion-color-gray-4);margin-top:0!important}.dcf-palette-dark.dcf-card-bordered{border-color:transparent!important}::ng-deep ngx-decaf-list ion-list{padding:0!important;margin:0!important}\n"] }]
6116
+ args: [{ selector: 'ngx-decaf-card', imports: [TranslatePipe, IonCard, IonCardHeader, IonCardContent, IonCardTitle, IonCardSubtitle], standalone: true, template: "<ion-card\n [class]=\"'dcf-card ' + className + ' ' + 'dcf-card-' + body\"\n [color]=\"color\"\n mode=\"md\"\n [class.dcf-card-separator]=\"separator\"\n [class.dcf-card-shadow]=\"type === 'shadow'\"\n [class.dcf-card-bordered]=\"borders\"\n [class.dcf-card-separator]=\"separator\"\n #component\n>\n @if (title || subtitle) {\n <ion-card-header>\n @if (title) {\n <ion-card-title>{{\n locale ? (title | translate) : title\n }}</ion-card-title>\n }\n @if (subtitle) {\n <ion-card-subtitle>{{\n locale ? (subtitle | translate) : subtitle\n }}</ion-card-subtitle>\n }\n </ion-card-header>\n }\n <ion-card-content>\n @if (inlineContent && inlineContentPosition === \"top\") {\n <div [innerHTML]=\"inlineContent\"></div>\n }\n\n <ng-content slot=\"content\"></ng-content>\n\n @if (inlineContent && inlineContentPosition === \"bottom\") {\n <div [innerHTML]=\"inlineContent\"></div>\n }\n </ion-card-content>\n</ion-card>\n", styles: [".dcf-card{display:flow-root;border-radius:var(--dcf-border-radius-small)}.dcf-card .dcf-card{border-radius:0!important}.dcf-card:not(.dcf-card-shadow){box-shadow:none!important}.dcf-card:not(.dcf-card-shadow).dcf-card-bordered .dcf-card-bordered{border-color:transparent!important}.dcf-card.dcf-card-separator,.dcf-card.dcf-card-blank{padding:0!important;margin:0!important;background:transparent!important}.dcf-card.dcf-card-separator>*,.dcf-card.dcf-card-blank>*{padding:0!important;margin:0!important}.dcf-card.dcf-card-separator ion-card-header{padding:unset!important;margin:unset!important}.dcf-card.dcf-card-separator ion-card-title{padding:unset!important;margin:unset!important;font-weight:500;font-size:1rem;line-height:1.5rem}.dcf-card.dcf-card-separator.dcf-card-bordered{border-color:transparent!important}.dcf-card.dcf-card-small ion-card-header{padding:var(--dcf-padding-xsmall) 0!important}.dcf-card.dcf-card-small ion-card-content{padding:var(--dcf-padding-xsmall)!important}.dcf-card>*{width:100%!important}.dcf-card ion-card-content{padding:var(--dcf-padding)}.dcf-card ion-card-header+ion-card-content{padding-top:0!important;margin-top:var(--dcf-margin-small)}.dcf-card ion-card-header{padding-left:1.25rem}@media (max-width: 575px){.dcf-card ion-card-header{padding-left:.2rem!important}.dcf-card ion-card-header+ion-card-content{margin-top:var(--dcf-margin-small)}.dcf-card ion-card-content{padding:var(--dcf-margin) var(--dcf-margin-small)}.dcf-card.dcf-card-small ion-content{padding:var(--dcf-padding-xsmall)}}.dcf-card.dcf-height-1-1{display:flex;align-items:center;justify-content:center}.dcf-card.dcf-height-1-1.dcf-card-layout{height:calc(100% - 1.5rem)}.dcf-card.dcf-card-shadow{box-shadow:var(--dcf-card-box-shadow)!important}.dcf-card.dcf-card-bordered{border:1px solid var(--dcf-color-gray-2)}.dcf-card ion-card-title{padding:var(--dcf-padding-small) var(--dcf-spacement) 0rem var(--dcf-spacement)!important;font-weight:500;font-size:1.125rem;line-height:1.75rem}.dcf-card ion-card-subtitle{padding:0rem var(--dcf-spacement);color:var(--ion-color-gray-4);margin-top:0!important}.dcf-palette-dark.dcf-card-bordered{border-color:transparent!important}::ng-deep ngx-decaf-list ion-list{padding:0!important;margin:0!important}\n"] }]
5623
6117
  }], propDecorators: { type: [{
5624
6118
  type: Input
5625
6119
  }], title: [{
@@ -5675,18 +6169,6 @@ let LayoutComponent = class LayoutComponent extends NgxParentComponentDirective
5675
6169
  * @memberOf LayoutComponent
5676
6170
  */
5677
6171
  this.gap = LayoutGridGaps.collapse;
5678
- /**
5679
- * @description Media breakpoint for responsive behavior.
5680
- * @summary Determines the responsive breakpoint at which the layout should adapt.
5681
- * This affects how the grid behaves on different screen sizes, allowing for
5682
- * mobile-first or desktop-first responsive design patterns. The breakpoint
5683
- * is automatically processed to ensure compatibility with the UI framework.
5684
- *
5685
- * @type {UIMediaBreakPointsType}
5686
- * @default 'medium'
5687
- * @memberOf LayoutComponent
5688
- */
5689
- this.breakpoint = UIMediaBreakPoints.MEDIUM;
5690
6172
  /**
5691
6173
  * @description Media breakpoint for responsive behavior.
5692
6174
  * @summary Determines the responsive breakpoint at which the layout should adapt.
@@ -5699,18 +6181,6 @@ let LayoutComponent = class LayoutComponent extends NgxParentComponentDirective
5699
6181
  * @memberOf LayoutComponent
5700
6182
  */
5701
6183
  this.grid = true;
5702
- /**
5703
- * @description Media breakpoint for responsive behavior.
5704
- * @summary Determines the responsive breakpoint at which the layout should adapt.
5705
- * This affects how the grid behaves on different screen sizes, allowing for
5706
- * mobile-first or desktop-first responsive design patterns. The breakpoint
5707
- * is automatically processed to ensure compatibility with the UI framework.
5708
- *
5709
- * @type {UIMediaBreakPointsType}
5710
- * @default 'medium'
5711
- * @memberOf LayoutComponent
5712
- */
5713
- this.match = true;
5714
6184
  /**
5715
6185
  * @description Media breakpoint for responsive behavior.
5716
6186
  * @summary Determines the responsive breakpoint at which the layout should adapt.
@@ -5760,6 +6230,10 @@ let LayoutComponent = class LayoutComponent extends NgxParentComponentDirective
5760
6230
  */
5761
6231
  get _cols() {
5762
6232
  let cols = this.cols;
6233
+ if (typeof cols === Primitives.BOOLEAN) {
6234
+ cols = 1;
6235
+ this.flexMode = true;
6236
+ }
5763
6237
  if (typeof cols === Primitives.NUMBER)
5764
6238
  cols = Array.from({ length: Number(cols) }, () => '');
5765
6239
  return cols;
@@ -5832,7 +6306,7 @@ let LayoutComponent = class LayoutComponent extends NgxParentComponentDirective
5832
6306
  return child;
5833
6307
  })
5834
6308
  };
5835
- }).map(row => {
6309
+ }).map((row, index) => {
5836
6310
  const colsLength = this.getRowColsLength(row);
5837
6311
  row.cols = row.cols.map((c) => {
5838
6312
  let { col } = c;
@@ -5845,9 +6319,8 @@ let LayoutComponent = class LayoutComponent extends NgxParentComponentDirective
5845
6319
  }
5846
6320
  }
5847
6321
  else {
5848
- if (typeof col === Primitives.NUMBER) {
5849
- col = `${col}-${colsLength}`;
5850
- }
6322
+ if (typeof col === Primitives.NUMBER)
6323
+ col = (colsLength <= this.maxColsLength) ? `${col}-${colsLength}` : `${index + 1}-${col}`;
5851
6324
  col = ['2-4', '3-6'].includes(col) ? `1-2` : col;
5852
6325
  }
5853
6326
  col = `dcf-child-${col}-${this.breakpoint} dcf-width-${col}`;
@@ -5872,7 +6345,7 @@ let LayoutComponent = class LayoutComponent extends NgxParentComponentDirective
5872
6345
  async ngOnInit() {
5873
6346
  super.parseProps(this);
5874
6347
  if (this.breakpoint)
5875
- this.breakpoint = `${this.breakpoint}`.toLowerCase();
6348
+ this.breakpoint = `${this.breakpoint.startsWith('x') ? this.breakpoint.substring(0, 2) : this.breakpoint.substring(0, 1)}`.toLowerCase();
5876
6349
  this.cols = this._cols;
5877
6350
  this.rows = this._rows;
5878
6351
  // if (this._rows.length === 1)
@@ -5880,9 +6353,10 @@ let LayoutComponent = class LayoutComponent extends NgxParentComponentDirective
5880
6353
  // if (this._cols.length === 1)
5881
6354
  // this.grid = false;
5882
6355
  this.initialized = true;
6356
+ this.changeDetectorRef.detectChanges();
5883
6357
  }
5884
6358
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: LayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
5885
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: LayoutComponent, isStandalone: true, selector: "ngx-decaf-layout", inputs: { gap: "gap", breakpoint: "breakpoint", grid: "grid", match: "match", flexMode: "flexMode", rowCard: "rowCard", maxColsLength: "maxColsLength" }, usesInheritance: true, ngImport: i0, template: "<section class=\"dcf-layout-container\">\n @if (initialized) {\n @for (row of rows; track trackItemFn($index, row); let rowIndex = $index) {\n @if (row?.cols?.length) {\n <div\n [id]=\"uid\"\n [class]=\" (!grid ? 'dcf-layout-row ' : 'dcf-layout-row dcf-grid ' + 'dcf-grid-' + gap ) + ' ' + (className || '') \"\n [class.dcf-grid-match]=\"match\"\n >\n @if (row?.title?.length) {\n <div class=\"dcf-width-1-1 dcf-grid-title\">\n <h3 class=\"\">{{row.title | translate}}</h3>\n </div>\n }\n @for (child of row.cols; track trackItemFn($index, child.col); let colIndex = $index) {\n <div\n [class]=\"child.colClass\"\n [class.dcf-first-column]=\" $index === 0\"\n >\n\n <div>\n @if (child.tag === 'ngx-decaf-crud-form') {\n <ngx-decaf-card [className]=\"(match ? 'dcf-height-1-1 dcf-card-layout' : '') + className\">\n <ngx-decaf-model-renderer\n [model]=\"child.props.name\"\n (listenEvent)=\"handleEvent($event)\"\n />\n </ngx-decaf-card>\n } @else {\n <ngx-decaf-component-renderer\n [tag]=\"child.tag\"\n [className]=\"(match ? 'dcf-height-1-1 dcf-card-layout' : '') + className\"\n [parentForm]=\"parentForm || child.parentForm || 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 }\n</section>\n", styles: [".dcf-layout-container{display:flow-root}.dcf-grid .dcf-grid-title{padding:unset;margin:unset}.dcf-grid .dcf-grid-title>*{padding:unset;margin:unset;padding-left:var(--dcf-padding-small);font-size:1.05rem!important;font-weight:600;background:none;box-shadow:none;display:flex;align-items:center;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.dcf-grid.dcf-grid-small.dcf-grid-nested{padding:0 .5rem!important}.dcf-grid.dcf-grid-small>div{margin-bottom:1.75rem}.dcf-grid.dcf-grid-small>div:last-child{margin-bottom:0}.dcf-grid.dcf-grid-small+.dcf-grid-small{margin-top:1.75rem!important}::ng-deep ngx-decaf-component-renderer>*>div{margin-bottom:0!important}\n"], dependencies: [{ kind: "component", type: CardComponent, selector: "ngx-decaf-card", inputs: ["type", "title", "body", "subtitle", "color", "separator", "borders", "inlineContent", "inlineContentPosition"] }, { kind: "component", type: ModelRendererComponent, selector: "ngx-decaf-model-renderer", inputs: ["projectable"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "children", "projectable", "parent"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
6359
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: LayoutComponent, isStandalone: true, selector: "ngx-decaf-layout", inputs: { gap: "gap", grid: "grid", flexMode: "flexMode", rowCard: "rowCard", maxColsLength: "maxColsLength" }, usesInheritance: true, ngImport: i0, template: "<section class=\"dcf-layout-container\">\n @if (initialized) {\n @for (row of rows; track trackItemFn($index, row); let rowIndex = $index) {\n @if (row?.cols?.length) {\n <div\n [id]=\"uid\"\n [class]=\"\n (!grid\n ? 'dcf-layout-row '\n : 'dcf-layout-row dcf-grid ' + 'dcf-grid-' + gap) +\n ' ' +\n (className || '')\n \"\n [class.dcf-grid-match]=\"match\"\n [class.dcf-grid-bordered]=\"borders\"\n >\n @if (row?.title?.length) {\n <div class=\"dcf-width-1-1 dcf-grid-title\">\n <h3 class=\"\">{{ row.title | translate }}</h3>\n </div>\n }\n @for (\n child of row.cols;\n track trackItemFn($index, child.col);\n let colIndex = $index\n ) {\n\n <div\n [class]=\"'dcf-grid-col ' + child.colClass\"\n [class.dcf-first-column]=\"$index === 0\"\n [class.dcf-layout-separator]=\"child.props?.separator ?? false\"\n >\n <div>\n\n @if (child.tag === \"ngx-decaf-crud-form\") {\n\n <ngx-decaf-card\n [className]=\"\n (match ? 'dcf-height-1-1 dcf-card-layout' : '') +\n className\n \"\n [body]=\"cardBody\"\n [type]=\"cardType\"\n >\n <ngx-decaf-model-renderer\n [model]=\"child.props.name\"\n (listenEvent)=\"handleEvent($event)\"\n />\n </ngx-decaf-card>\n } @else {\n\n <ngx-decaf-component-renderer\n [tag]=\"child.tag\"\n [className]=\"\n (match ? 'dcf-height-1-1 dcf-card-layout' : '') +\n className\n \"\n [parentForm]=\"parentForm || child.parentForm || 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 }\n</section>\n", styles: [".dcf-layout-container{display:flow-root}.dcf-grid.dcf-grid-bordered>div>div{padding:var(--dcf-padding);border-radius:var(--dcf-border-radius-small);border:1px solid var(--dcf-color-gray-2)}.dcf-grid .dcf-grid-title{padding:unset;margin:unset}.dcf-grid .dcf-grid-title>*{padding:unset;margin:unset;padding-left:var(--dcf-padding-small);font-size:1.05rem!important;font-weight:600;background:none;box-shadow:none;display:flex;align-items:center;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.dcf-grid.dcf-grid-match ::ng-deep ngx-decaf-component-renderer>*>*{height:100%!important}.dcf-grid.dcf-grid-small.dcf-grid-nested{padding:0 .5rem!important}.dcf-grid.dcf-grid-small>div{margin-bottom:1.75rem}.dcf-grid.dcf-grid-small>div.dcf-layout-separator{margin-bottom:1rem}.dcf-grid.dcf-grid-small>div.dcf-grid-bordered:last-child{margin-bottom:0}.dcf-grid.dcf-grid-small+.dcf-grid-small{margin-bottom:1.75rem}.dcf-grid.dcf-grid-small+.dcf-grid-small.dcf-layout-separator{margin-bottom:1rem}::ng-deep ngx-decaf-component-renderer>*>div{margin-bottom:0!important}\n"], dependencies: [{ kind: "component", type: CardComponent, selector: "ngx-decaf-card", inputs: ["type", "title", "body", "subtitle", "color", "separator", "borders", "inlineContent", "inlineContentPosition"] }, { kind: "component", type: ModelRendererComponent, selector: "ngx-decaf-model-renderer", inputs: ["projectable"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "children", "projectable", "parent"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
5886
6360
  };
5887
6361
  LayoutComponent = __decorate([
5888
6362
  Dynamic(),
@@ -5890,15 +6364,11 @@ LayoutComponent = __decorate([
5890
6364
  ], LayoutComponent);
5891
6365
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: LayoutComponent, decorators: [{
5892
6366
  type: Component,
5893
- args: [{ selector: 'ngx-decaf-layout', imports: [TranslatePipe, CardComponent, ModelRendererComponent, ComponentRendererComponent], standalone: true, template: "<section class=\"dcf-layout-container\">\n @if (initialized) {\n @for (row of rows; track trackItemFn($index, row); let rowIndex = $index) {\n @if (row?.cols?.length) {\n <div\n [id]=\"uid\"\n [class]=\" (!grid ? 'dcf-layout-row ' : 'dcf-layout-row dcf-grid ' + 'dcf-grid-' + gap ) + ' ' + (className || '') \"\n [class.dcf-grid-match]=\"match\"\n >\n @if (row?.title?.length) {\n <div class=\"dcf-width-1-1 dcf-grid-title\">\n <h3 class=\"\">{{row.title | translate}}</h3>\n </div>\n }\n @for (child of row.cols; track trackItemFn($index, child.col); let colIndex = $index) {\n <div\n [class]=\"child.colClass\"\n [class.dcf-first-column]=\" $index === 0\"\n >\n\n <div>\n @if (child.tag === 'ngx-decaf-crud-form') {\n <ngx-decaf-card [className]=\"(match ? 'dcf-height-1-1 dcf-card-layout' : '') + className\">\n <ngx-decaf-model-renderer\n [model]=\"child.props.name\"\n (listenEvent)=\"handleEvent($event)\"\n />\n </ngx-decaf-card>\n } @else {\n <ngx-decaf-component-renderer\n [tag]=\"child.tag\"\n [className]=\"(match ? 'dcf-height-1-1 dcf-card-layout' : '') + className\"\n [parentForm]=\"parentForm || child.parentForm || 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 }\n</section>\n", styles: [".dcf-layout-container{display:flow-root}.dcf-grid .dcf-grid-title{padding:unset;margin:unset}.dcf-grid .dcf-grid-title>*{padding:unset;margin:unset;padding-left:var(--dcf-padding-small);font-size:1.05rem!important;font-weight:600;background:none;box-shadow:none;display:flex;align-items:center;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.dcf-grid.dcf-grid-small.dcf-grid-nested{padding:0 .5rem!important}.dcf-grid.dcf-grid-small>div{margin-bottom:1.75rem}.dcf-grid.dcf-grid-small>div:last-child{margin-bottom:0}.dcf-grid.dcf-grid-small+.dcf-grid-small{margin-top:1.75rem!important}::ng-deep ngx-decaf-component-renderer>*>div{margin-bottom:0!important}\n"] }]
6367
+ args: [{ selector: 'ngx-decaf-layout', imports: [TranslatePipe, CardComponent, ModelRendererComponent, ComponentRendererComponent], standalone: true, template: "<section class=\"dcf-layout-container\">\n @if (initialized) {\n @for (row of rows; track trackItemFn($index, row); let rowIndex = $index) {\n @if (row?.cols?.length) {\n <div\n [id]=\"uid\"\n [class]=\"\n (!grid\n ? 'dcf-layout-row '\n : 'dcf-layout-row dcf-grid ' + 'dcf-grid-' + gap) +\n ' ' +\n (className || '')\n \"\n [class.dcf-grid-match]=\"match\"\n [class.dcf-grid-bordered]=\"borders\"\n >\n @if (row?.title?.length) {\n <div class=\"dcf-width-1-1 dcf-grid-title\">\n <h3 class=\"\">{{ row.title | translate }}</h3>\n </div>\n }\n @for (\n child of row.cols;\n track trackItemFn($index, child.col);\n let colIndex = $index\n ) {\n\n <div\n [class]=\"'dcf-grid-col ' + child.colClass\"\n [class.dcf-first-column]=\"$index === 0\"\n [class.dcf-layout-separator]=\"child.props?.separator ?? false\"\n >\n <div>\n\n @if (child.tag === \"ngx-decaf-crud-form\") {\n\n <ngx-decaf-card\n [className]=\"\n (match ? 'dcf-height-1-1 dcf-card-layout' : '') +\n className\n \"\n [body]=\"cardBody\"\n [type]=\"cardType\"\n >\n <ngx-decaf-model-renderer\n [model]=\"child.props.name\"\n (listenEvent)=\"handleEvent($event)\"\n />\n </ngx-decaf-card>\n } @else {\n\n <ngx-decaf-component-renderer\n [tag]=\"child.tag\"\n [className]=\"\n (match ? 'dcf-height-1-1 dcf-card-layout' : '') +\n className\n \"\n [parentForm]=\"parentForm || child.parentForm || 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 }\n</section>\n", styles: [".dcf-layout-container{display:flow-root}.dcf-grid.dcf-grid-bordered>div>div{padding:var(--dcf-padding);border-radius:var(--dcf-border-radius-small);border:1px solid var(--dcf-color-gray-2)}.dcf-grid .dcf-grid-title{padding:unset;margin:unset}.dcf-grid .dcf-grid-title>*{padding:unset;margin:unset;padding-left:var(--dcf-padding-small);font-size:1.05rem!important;font-weight:600;background:none;box-shadow:none;display:flex;align-items:center;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.dcf-grid.dcf-grid-match ::ng-deep ngx-decaf-component-renderer>*>*{height:100%!important}.dcf-grid.dcf-grid-small.dcf-grid-nested{padding:0 .5rem!important}.dcf-grid.dcf-grid-small>div{margin-bottom:1.75rem}.dcf-grid.dcf-grid-small>div.dcf-layout-separator{margin-bottom:1rem}.dcf-grid.dcf-grid-small>div.dcf-grid-bordered:last-child{margin-bottom:0}.dcf-grid.dcf-grid-small+.dcf-grid-small{margin-bottom:1.75rem}.dcf-grid.dcf-grid-small+.dcf-grid-small.dcf-layout-separator{margin-bottom:1rem}::ng-deep ngx-decaf-component-renderer>*>div{margin-bottom:0!important}\n"] }]
5894
6368
  }], ctorParameters: () => [], propDecorators: { gap: [{
5895
6369
  type: Input
5896
- }], breakpoint: [{
5897
- type: Input
5898
6370
  }], grid: [{
5899
6371
  type: Input
5900
- }], match: [{
5901
- type: Input
5902
6372
  }], flexMode: [{
5903
6373
  type: Input
5904
6374
  }], rowCard: [{
@@ -5939,11 +6409,11 @@ let CrudFormComponent = class CrudFormComponent extends NgxFormDirective {
5939
6409
  this.submitEvent.emit({
5940
6410
  data: this.modelId,
5941
6411
  component: 'CrudFormComponent',
5942
- name: EventConstants.SUBMIT,
6412
+ name: ComponentEventNames.SUBMIT,
5943
6413
  });
5944
6414
  }
5945
6415
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: CrudFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
5946
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: CrudFormComponent, isStandalone: true, selector: "ngx-decaf-crud-form", 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 (ngSubmit)=\"handleSubmit($event)\"\n novalidate\n [target]=\"target\">\n @if (!children?.length) {\n <ng-content #formContent></ng-content>\n } @else {\n <ngx-decaf-layout\n [className]=\"'dcf-crud-form-grid dcf-grid-nested '\"\n [children]=\"children || []\"\n [parentForm]=\"formGroup || parentForm\"\n [match]=\"false\"\n [gap]=\"'small'\"\n [flexMode]=\"props.flexMode || false\"\n [rows]=\"rows\"\n [cols]=\"cols\" />\n }\n @if (initialized) {\n <div class=\"dcf-buttons-grid dcf-grid dcf-grid-small 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=\"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-small dcf-flex dcf-flex-left ' + operation\" [id]=\"uid\">\n @if ([OperationKeys.READ, OperationKeys.DELETE].includes(operation) && 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:var(--dcf-margin-medium);margin-bottom:var(--dcf-margin)}@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.create,.dcf-form-grid.update{margin-top:var(--dcf-margin-small)}.dcf-form-grid .dcf-form-item{margin-top:0!important}.dcf-form-grid.read .dcf-form-item{margin-bottom:var(--dcf-margin-small)}\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", "flexMode", "rowCard", "maxColsLength"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "children", "projectable", "parent"] }, { 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"] }] }); }
6416
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", 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 (ngSubmit)=\"handleSubmit($event)\"\n novalidate\n [target]=\"target\">\n @if (!children?.length) {\n <ng-content #formContent></ng-content>\n } @else {\n <ngx-decaf-layout\n [className]=\"'dcf-crud-form-grid dcf-grid-nested '\"\n [children]=\"children || []\"\n [parentForm]=\"formGroup || parentForm\"\n [match]=\"match ?? false\"\n [gap]=\"'small'\"\n [flexMode]=\"props.flexMode || false\"\n [rows]=\"rows\"\n [borders]=\"borders ?? false\"\n [breakpoint]=\"breakpoint ?? 'large'\"\n [cols]=\"cols\" />\n }\n @if (initialized) {\n <div class=\"dcf-buttons-grid dcf-grid dcf-grid-small 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=\"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-small dcf-flex dcf-flex-left ' + operation\" [id]=\"uid\">\n @if ([OperationKeys.READ, OperationKeys.DELETE].includes(operation) && 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:var(--dcf-margin-medium);margin-bottom:var(--dcf-margin)}@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.create,.dcf-form-grid.update{margin-top:var(--dcf-margin-small)}.dcf-form-grid .dcf-form-item{margin-top:0!important}.dcf-form-grid.read .dcf-form-item{margin-bottom:var(--dcf-margin-small)}\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", "grid", "flexMode", "rowCard", "maxColsLength"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "children", "projectable", "parent"] }, { 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"] }] }); }
5947
6417
  };
5948
6418
  CrudFormComponent = __decorate([
5949
6419
  Dynamic(),
@@ -5951,9 +6421,97 @@ CrudFormComponent = __decorate([
5951
6421
  ], CrudFormComponent);
5952
6422
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: CrudFormComponent, decorators: [{
5953
6423
  type: Component,
5954
- args: [{ standalone: true, selector: 'ngx-decaf-crud-form', imports: [ReactiveFormsModule, LayoutComponent, ComponentRendererComponent, IonButton, IonIcon], template: "@if (operation !== 'read' && operation !== 'delete') {\n <form\n [class]=\"'dcf-form-grid ' + operation\" #component\n [id]=\"rendererId\"\n [formGroup]=\"formGroup\"\n (ngSubmit)=\"handleSubmit($event)\"\n novalidate\n [target]=\"target\">\n @if (!children?.length) {\n <ng-content #formContent></ng-content>\n } @else {\n <ngx-decaf-layout\n [className]=\"'dcf-crud-form-grid dcf-grid-nested '\"\n [children]=\"children || []\"\n [parentForm]=\"formGroup || parentForm\"\n [match]=\"false\"\n [gap]=\"'small'\"\n [flexMode]=\"props.flexMode || false\"\n [rows]=\"rows\"\n [cols]=\"cols\" />\n }\n @if (initialized) {\n <div class=\"dcf-buttons-grid dcf-grid dcf-grid-small 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=\"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-small dcf-flex dcf-flex-left ' + operation\" [id]=\"uid\">\n @if ([OperationKeys.READ, OperationKeys.DELETE].includes(operation) && 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:var(--dcf-margin-medium);margin-bottom:var(--dcf-margin)}@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.create,.dcf-form-grid.update{margin-top:var(--dcf-margin-small)}.dcf-form-grid .dcf-form-item{margin-top:0!important}.dcf-form-grid.read .dcf-form-item{margin-bottom:var(--dcf-margin-small)}\n"] }]
6424
+ 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 (ngSubmit)=\"handleSubmit($event)\"\n novalidate\n [target]=\"target\">\n @if (!children?.length) {\n <ng-content #formContent></ng-content>\n } @else {\n <ngx-decaf-layout\n [className]=\"'dcf-crud-form-grid dcf-grid-nested '\"\n [children]=\"children || []\"\n [parentForm]=\"formGroup || parentForm\"\n [match]=\"match ?? false\"\n [gap]=\"'small'\"\n [flexMode]=\"props.flexMode || false\"\n [rows]=\"rows\"\n [borders]=\"borders ?? false\"\n [breakpoint]=\"breakpoint ?? 'large'\"\n [cols]=\"cols\" />\n }\n @if (initialized) {\n <div class=\"dcf-buttons-grid dcf-grid dcf-grid-small 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=\"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-small dcf-flex dcf-flex-left ' + operation\" [id]=\"uid\">\n @if ([OperationKeys.READ, OperationKeys.DELETE].includes(operation) && 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:var(--dcf-margin-medium);margin-bottom:var(--dcf-margin)}@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.create,.dcf-form-grid.update{margin-top:var(--dcf-margin-small)}.dcf-form-grid .dcf-form-item{margin-top:0!important}.dcf-form-grid.read .dcf-form-item{margin-bottom:var(--dcf-margin-small)}\n"] }]
5955
6425
  }], ctorParameters: () => [] });
5956
6426
 
6427
+ class NgxSvgDirective {
6428
+ constructor() {
6429
+ this.mediaService = inject(NgxMediaService);
6430
+ this.element = inject(ElementRef);
6431
+ this.http = inject(HttpClient);
6432
+ }
6433
+ ngOnInit() {
6434
+ this.path = this.path?.trim() || this.element?.nativeElement?.getAttribute('src')?.trim() || '';
6435
+ if (this.path)
6436
+ this.mediaService.loadSvgObserver(this.http, this.path, this.element.nativeElement);
6437
+ }
6438
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: NgxSvgDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
6439
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.9", type: NgxSvgDirective, isStandalone: true, selector: "[ngx-decaf-svg]", inputs: { path: ["ngx-decaf-svg", "path"] }, ngImport: i0 }); }
6440
+ }
6441
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: NgxSvgDirective, decorators: [{
6442
+ type: Directive,
6443
+ args: [{
6444
+ selector: '[ngx-decaf-svg]',
6445
+ standalone: true
6446
+ }]
6447
+ }], propDecorators: { path: [{
6448
+ type: Input,
6449
+ args: ['ngx-decaf-svg']
6450
+ }] } });
6451
+
6452
+ let IconComponent = class IconComponent {
6453
+ constructor() {
6454
+ this.color = "dark";
6455
+ this.slot = 'icon-only';
6456
+ this.button = false;
6457
+ this.buttonFill = 'clear';
6458
+ this.buttonShape = 'round';
6459
+ this.size = 'default';
6460
+ this.type = 'ionic';
6461
+ this.isSvg = false;
6462
+ this.initialized = false;
6463
+ this.inline = false;
6464
+ this.isDarkMode = false;
6465
+ this.mediaService = new NgxMediaService();
6466
+ addIcons(allIcons);
6467
+ }
6468
+ ngOnInit() {
6469
+ if (this.button)
6470
+ this.slot = 'icon-only';
6471
+ if (this.name?.includes('.')) {
6472
+ this.type = 'image';
6473
+ this.isSvg = this.name.endsWith('.svg');
6474
+ }
6475
+ this.initialized = true;
6476
+ }
6477
+ ngAfterViewInit() {
6478
+ this.mediaService.isDarkMode().subscribe(isDark => {
6479
+ this.isDarkMode = isDark;
6480
+ });
6481
+ }
6482
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: IconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6483
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: IconComponent, isStandalone: true, selector: "ngx-decaf-icon", inputs: { name: "name", color: "color", slot: "slot", button: "button", buttonFill: "buttonFill", buttonShape: "buttonShape", width: "width", size: "size", inline: "inline" }, host: { properties: { "attr.id": "uid", "attr.aria-hidden": "!button" } }, viewQueries: [{ propertyName: "component", first: true, predicate: ["component"], descendants: true, read: ElementRef }], ngImport: i0, template: "<div class=\"dcf-icon\" #component>\n @if (initialized) {\n @if (button) {\n <ion-button [fill]=\"buttonFill\" [shape]=\"buttonShape\" [color]=\"isDarkMode ? 'light' : color\" [size]=\"size\">\n @if (type === \"image\") {\n @if (isSvg) {\n <span\n aria-hidden=\"true\"\n [slot]=\"slot\"\n [class]=\"color ? 'dcf-color-' + color : ''\"\n [style.width]=\"width\"\n [ngx-decaf-svg]=\"name\"\n >\n ></span\n >\n } @else {\n <img\n aria-hidden=\"true\"\n [alt]=\"name\"\n [title]=\"name\"\n [slot]=\"slot\"\n [src]=\"name\"\n [style.width]=\"width\"\n title=\"icon\"\n />\n }\n } @else {\n <ion-icon\n aria-hidden=\"true\"\n [slot]=\"slot\"\n [ios]=\"name\"\n [md]=\"name\"\n [color]=\"isDarkMode ? 'light' : color\"\n [name]=\"name\"\n />\n }\n </ion-button>\n } @else {\n @if (type === \"image\") {\n @if (isSvg) {\n <span\n aria-hidden=\"true\"\n [slot]=\"slot\"\n [class]=\"color ? 'dcf-color-' + color : ''\"\n [style.width]=\"width\"\n [ngx-decaf-svg]=\"name\"\n >\n </span>\n } @else {\n <img\n aria-hidden=\"true\"\n [alt]=\"name\"\n [title]=\"name\"\n [slot]=\"slot\"\n [src]=\"name\"\n [style.width]=\"width\"\n title=\"icon\"\n />\n }\n }\n @if (type === \"ionic\") {\n <ion-icon\n aria-hidden=\"true\"\n [slot]=\"slot\"\n [ios]=\"name\"\n [md]=\"name\"\n [size]=\"size\"\n [color]=\"isDarkMode ? 'light' : color\"\n [name]=\"name\"\n />\n }\n }\n }\n</div>\n", styles: ["::ng-deep .dcf-icon.dcf-palette-dark ion-icon{color:var(--dcf-text-color)!important}::ng-deep .dcf-icon.dcf-palette-dark svg{fill:var(--dcf-text-color);fill-opacity:.25!important;stroke:var(--dcf-text-color)!important}::ng-deep .dcf-icon.dcf-palette-dark svg *{fill:var(--dcf-color-primary)!important;stroke:var(--dcf-color-gray-1)!important}ion-button{cursor:pointer!important}.dcf-icon ion-icon:not([size]){font-size:1.35rem!important}\n"], dependencies: [{ kind: "directive", type: NgxSvgDirective, selector: "[ngx-decaf-svg]", inputs: ["ngx-decaf-svg"] }, { 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"] }] }); }
6484
+ };
6485
+ IconComponent = __decorate([
6486
+ Dynamic(),
6487
+ __metadata("design:paramtypes", [])
6488
+ ], IconComponent);
6489
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: IconComponent, decorators: [{
6490
+ type: Component,
6491
+ args: [{ selector: 'ngx-decaf-icon', imports: [NgxSvgDirective, IonIcon, IonButton], standalone: true, host: { '[attr.id]': 'uid', '[attr.aria-hidden]': '!button' }, template: "<div class=\"dcf-icon\" #component>\n @if (initialized) {\n @if (button) {\n <ion-button [fill]=\"buttonFill\" [shape]=\"buttonShape\" [color]=\"isDarkMode ? 'light' : color\" [size]=\"size\">\n @if (type === \"image\") {\n @if (isSvg) {\n <span\n aria-hidden=\"true\"\n [slot]=\"slot\"\n [class]=\"color ? 'dcf-color-' + color : ''\"\n [style.width]=\"width\"\n [ngx-decaf-svg]=\"name\"\n >\n ></span\n >\n } @else {\n <img\n aria-hidden=\"true\"\n [alt]=\"name\"\n [title]=\"name\"\n [slot]=\"slot\"\n [src]=\"name\"\n [style.width]=\"width\"\n title=\"icon\"\n />\n }\n } @else {\n <ion-icon\n aria-hidden=\"true\"\n [slot]=\"slot\"\n [ios]=\"name\"\n [md]=\"name\"\n [color]=\"isDarkMode ? 'light' : color\"\n [name]=\"name\"\n />\n }\n </ion-button>\n } @else {\n @if (type === \"image\") {\n @if (isSvg) {\n <span\n aria-hidden=\"true\"\n [slot]=\"slot\"\n [class]=\"color ? 'dcf-color-' + color : ''\"\n [style.width]=\"width\"\n [ngx-decaf-svg]=\"name\"\n >\n </span>\n } @else {\n <img\n aria-hidden=\"true\"\n [alt]=\"name\"\n [title]=\"name\"\n [slot]=\"slot\"\n [src]=\"name\"\n [style.width]=\"width\"\n title=\"icon\"\n />\n }\n }\n @if (type === \"ionic\") {\n <ion-icon\n aria-hidden=\"true\"\n [slot]=\"slot\"\n [ios]=\"name\"\n [md]=\"name\"\n [size]=\"size\"\n [color]=\"isDarkMode ? 'light' : color\"\n [name]=\"name\"\n />\n }\n }\n }\n</div>\n", styles: ["::ng-deep .dcf-icon.dcf-palette-dark ion-icon{color:var(--dcf-text-color)!important}::ng-deep .dcf-icon.dcf-palette-dark svg{fill:var(--dcf-text-color);fill-opacity:.25!important;stroke:var(--dcf-text-color)!important}::ng-deep .dcf-icon.dcf-palette-dark svg *{fill:var(--dcf-color-primary)!important;stroke:var(--dcf-color-gray-1)!important}ion-button{cursor:pointer!important}.dcf-icon ion-icon:not([size]){font-size:1.35rem!important}\n"] }]
6492
+ }], ctorParameters: () => [], propDecorators: { component: [{
6493
+ type: ViewChild,
6494
+ args: ['component', { read: ElementRef, static: false }]
6495
+ }], name: [{
6496
+ type: Input
6497
+ }], color: [{
6498
+ type: Input
6499
+ }], slot: [{
6500
+ type: Input
6501
+ }], button: [{
6502
+ type: Input
6503
+ }], buttonFill: [{
6504
+ type: Input
6505
+ }], buttonShape: [{
6506
+ type: Input
6507
+ }], width: [{
6508
+ type: Input
6509
+ }], size: [{
6510
+ type: Input
6511
+ }], inline: [{
6512
+ type: Input
6513
+ }] } });
6514
+
5957
6515
  /**
5958
6516
  * @description Component for displaying empty state messages with optional actions.
5959
6517
  * @summary This component provides a standardized way to display empty state messages
@@ -6074,13 +6632,13 @@ let EmptyStateComponent = class EmptyStateComponent extends CardComponent {
6074
6632
  * @default 'large'
6075
6633
  * @memberOf EmptyStateComponent
6076
6634
  */
6077
- this.iconSize = 'large';
6635
+ this.iconSize = ElementSizes.large;
6078
6636
  /**
6079
6637
  * @description The color of the displayed icon.
6080
6638
  * @summary Specifies the color for the icon using Ionic's predefined color system.
6081
6639
  * This allows the icon to match the application's color scheme.
6082
6640
  *
6083
- * @type {PredefinedColors | undefined}
6641
+ * @type {string}
6084
6642
  * @default 'medium'
6085
6643
  * @memberOf EmptyStateComponent
6086
6644
  */
@@ -6131,8 +6689,7 @@ let EmptyStateComponent = class EmptyStateComponent extends CardComponent {
6131
6689
  * @memberOf EmptyStateComponent
6132
6690
  */
6133
6691
  this.enableCreationByModelRoute = false;
6134
- addIcons(allIcons);
6135
- this.type = 'default';
6692
+ this.type = 'clear';
6136
6693
  this.componentName = "EmptyStateComponent";
6137
6694
  this.enableDarkMode = true;
6138
6695
  }
@@ -6167,8 +6724,8 @@ let EmptyStateComponent = class EmptyStateComponent extends CardComponent {
6167
6724
  super.ngOnInit();
6168
6725
  this.initialize();
6169
6726
  this.showIcon = stringToBoolean(this.showIcon);
6170
- this.titleColor = `dcf-title color-${this.titleColor}`;
6171
- this.subtitleColor = `dcf-subtitle color-${this.titleColor}`;
6727
+ this.titleColor = `dcf-title dcf-color-${this.titleColor}`;
6728
+ this.subtitleColor = `dcf-subtitle dcf-color-${this.subtitleColor}`;
6172
6729
  if (this.searchValue)
6173
6730
  this.searchSubtitle = await this.getSearchSubtitle(this.subtitle);
6174
6731
  if (!this.buttonLink && this.model && this.route)
@@ -6244,7 +6801,7 @@ let EmptyStateComponent = class EmptyStateComponent extends CardComponent {
6244
6801
  return this.sanitizer.bypassSecurityTrustHtml(result);
6245
6802
  }
6246
6803
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: EmptyStateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6247
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", 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: " <ngx-decaf-card [className]=\"className\">\n\n @if (icon && showIcon) {\n <div class=\"dcf-icon-container\">\n <ion-icon\n [name]=\"icon\"\n [size]=\"iconSize\"\n [color]=\"!this.isDarkMode ? 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 </ngx-decaf-card>\n", styles: [":host{text-align:center}:host ion-button{margin-top:.75rem}:host ion-icon{font-size:2.5rem}:host .dcf-icon-container{transform:scale(1.25);opacity:.75;margin-top:1.25rem!important;margin-bottom:.5rem!important}:host .dcf-ititle{font-weight:600!important;color:var(--dcf-color-gray-6)!important}:host .dcf-isubtitle{font-weight:500!important}\n"], dependencies: [{ 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: "component", type: CardComponent, selector: "ngx-decaf-card", inputs: ["type", "title", "body", "subtitle", "color", "separator", "borders", "inlineContent", "inlineContentPosition"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
6804
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", 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: "<div class=\"decaf-empty-state-component\" #component>\n <ngx-decaf-card [className]=\"className\">\n @if (icon && showIcon) {\n <div class=\"dcf-icon-container\">\n <ngx-decaf-icon\n aria-hidden=\"true\"\n [name]=\"icon\"\n [size]=\"iconSize\"\n [color]=\"!this.isDarkMode ? iconColor : ''\"\n />\n </div>\n }\n @if (title) {\n <h4 class=\"dcf-ititle\" [class]=\"isDarkMode ? 'light' : titleColor\" [innerHTML]=\"title\"></h4>\n }\n @if (subtitle) {\n <p [class]=\"isDarkMode ? 'light' : 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 </ngx-decaf-card>\n</div>\n", styles: [":host{text-align:center}:host ion-button{margin-top:.75rem}:host .dcf-icon-container{transform:scale(1.25);opacity:.75;margin-top:1.25rem!important;margin-bottom:.5rem!important}:host .dcf-ititle{font-weight:600!important}:host .dcf-subtitle{font-weight:500!important}\n"], dependencies: [{ kind: "component", type: IconComponent, selector: "ngx-decaf-icon", inputs: ["name", "color", "slot", "button", "buttonFill", "buttonShape", "width", "size", "inline"] }, { 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: CardComponent, selector: "ngx-decaf-card", inputs: ["type", "title", "body", "subtitle", "color", "separator", "borders", "inlineContent", "inlineContentPosition"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
6248
6805
  };
6249
6806
  EmptyStateComponent = __decorate([
6250
6807
  Dynamic(),
@@ -6253,11 +6810,11 @@ EmptyStateComponent = __decorate([
6253
6810
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: EmptyStateComponent, decorators: [{
6254
6811
  type: Component,
6255
6812
  args: [{ selector: 'ngx-decaf-empty-state', standalone: true, imports: [
6256
- IonIcon,
6813
+ IconComponent,
6257
6814
  TranslatePipe,
6258
6815
  IonButton,
6259
6816
  CardComponent
6260
- ], template: " <ngx-decaf-card [className]=\"className\">\n\n @if (icon && showIcon) {\n <div class=\"dcf-icon-container\">\n <ion-icon\n [name]=\"icon\"\n [size]=\"iconSize\"\n [color]=\"!this.isDarkMode ? 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 </ngx-decaf-card>\n", styles: [":host{text-align:center}:host ion-button{margin-top:.75rem}:host ion-icon{font-size:2.5rem}:host .dcf-icon-container{transform:scale(1.25);opacity:.75;margin-top:1.25rem!important;margin-bottom:.5rem!important}:host .dcf-ititle{font-weight:600!important;color:var(--dcf-color-gray-6)!important}:host .dcf-isubtitle{font-weight:500!important}\n"] }]
6817
+ ], template: "<div class=\"decaf-empty-state-component\" #component>\n <ngx-decaf-card [className]=\"className\">\n @if (icon && showIcon) {\n <div class=\"dcf-icon-container\">\n <ngx-decaf-icon\n aria-hidden=\"true\"\n [name]=\"icon\"\n [size]=\"iconSize\"\n [color]=\"!this.isDarkMode ? iconColor : ''\"\n />\n </div>\n }\n @if (title) {\n <h4 class=\"dcf-ititle\" [class]=\"isDarkMode ? 'light' : titleColor\" [innerHTML]=\"title\"></h4>\n }\n @if (subtitle) {\n <p [class]=\"isDarkMode ? 'light' : 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 </ngx-decaf-card>\n</div>\n", styles: [":host{text-align:center}:host ion-button{margin-top:.75rem}:host .dcf-icon-container{transform:scale(1.25);opacity:.75;margin-top:1.25rem!important;margin-bottom:.5rem!important}:host .dcf-ititle{font-weight:600!important}:host .dcf-subtitle{font-weight:500!important}\n"] }]
6261
6818
  }], ctorParameters: () => [], propDecorators: { title: [{
6262
6819
  type: Input
6263
6820
  }], titleColor: [{
@@ -6452,11 +7009,44 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
6452
7009
  * @summary Numeric limit that controls how many items can be added when `multiple` is true.
6453
7010
  * When set to Infinity there is no limit.
6454
7011
  *
6455
- * @type {number}
6456
- * @default Infinity
7012
+ * @type {number}
7013
+ * @default Infinity
7014
+ * @memberOf FieldsetComponent
7015
+ */
7016
+ this.max = undefined;
7017
+ /**
7018
+ * @description Maximum allowed items in the fieldset.
7019
+ * @summary Numeric limit that controls how many items can be added when `multiple` is true.
7020
+ * When set to Infinity there is no limit.
7021
+ *
7022
+ * @type {number}
7023
+ * @default Infinity
7024
+ * @memberOf FieldsetComponent
7025
+ */
7026
+ this.required = false;
7027
+ /**
7028
+ * @description Determines if the fieldset items can be reordered.
7029
+ * @summary Boolean flag that enables or disables the drag-and-drop reordering functionality
7030
+ * for the items within the fieldset. When set to true, users can rearrange the order
7031
+ * of items using drag-and-drop gestures. This is particularly useful for managing
7032
+ * lists where the order of items is significant.
7033
+ *
7034
+ * @type {boolean}
7035
+ * @default true
7036
+ * @memberOf FieldsetComponent
7037
+ */
7038
+ this.ordenable = true;
7039
+ /**
7040
+ * @description Determines if the fieldset items can be edited by the user.
7041
+ * @summary Boolean flag that enables or disables the editing functionality
7042
+ * for the items within the fieldset. When set to true, users can modify the items.
7043
+ *
7044
+ * @type {boolean}
7045
+ * @default true
6457
7046
  * @memberOf FieldsetComponent
7047
+ * @default true
6458
7048
  */
6459
- this.max = undefined;
7049
+ this.editable = true;
6460
7050
  addIcons({ alertCircleOutline, addOutline, trashOutline, createOutline });
6461
7051
  }
6462
7052
  /**
@@ -6474,21 +7064,38 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
6474
7064
  this.multiple = false;
6475
7065
  this.buttonLabel = this.translateService.instant(this.locale + '.add');
6476
7066
  this.buttonCancelLabel = this.translateService.instant(this.locale + '.cancel');
7067
+ if (!this.multiple)
7068
+ this.ordenable = false;
6477
7069
  if ([OperationKeys.CREATE, OperationKeys.UPDATE].includes(this.operation)) {
6478
7070
  if (!this.formGroup) {
6479
- if (this.parentForm instanceof FormGroup)
6480
- this.formGroup = this.parentForm.controls[this.childOf];
7071
+ if (this.parentForm instanceof FormGroup) {
7072
+ // iterate on childOf path to get correct formGroup
7073
+ const parts = this.childOf.split('.');
7074
+ let formGroup = this.parentForm;
7075
+ for (const part of parts)
7076
+ formGroup = formGroup.controls[part];
7077
+ this.formGroup = formGroup;
7078
+ if (this.formGroup instanceof FormGroup)
7079
+ this.formGroup = this.formGroup.parent;
7080
+ }
6481
7081
  if (!this.formGroup && this.parentForm instanceof FormArray)
6482
7082
  this.formGroup = this.parentForm;
6483
7083
  if (!this.formGroup && this.children[0]?.['formGroup'] instanceof FormGroup)
6484
7084
  this.formGroup = this.children[0]?.['formGroup'].parent;
7085
+ if (this.formGroup && !(this.formGroup instanceof FormArray))
7086
+ this.formGroup = this.formGroup?.parent;
6485
7087
  }
6486
- this.children = this.children.map(child => {
6487
- if (!child.props)
6488
- child.props = {};
6489
- child.props = Object.assign(child.props, { activeFormGroup: this.activeFormGroupIndex, multiple: this.multiple });
6490
- return child;
6491
- });
7088
+ }
7089
+ if (this.multiple) {
7090
+ this.formGroup?.setErrors(null);
7091
+ this.formGroup?.disable();
7092
+ if (this.required) {
7093
+ this.collapsable = false;
7094
+ this.activePage = this.getActivePage();
7095
+ }
7096
+ }
7097
+ else {
7098
+ this.activePage = this.getActivePage();
6492
7099
  }
6493
7100
  this.initialized = true;
6494
7101
  }
@@ -6523,26 +7130,25 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
6523
7130
  */
6524
7131
  ngAfterViewInit() {
6525
7132
  super.ngAfterViewInit();
6526
- if (!this.collapsable)
6527
- this.isOpen = true;
6528
- if (this.operation === OperationKeys.READ || this.operation === OperationKeys.DELETE) {
6529
- this.isOpen = true;
6530
- // hidden remove button
6531
- const accordionElement = this.component?.nativeElement.querySelector('ion-accordion-group');
6532
- if (accordionElement)
6533
- this.renderer.setAttribute(accordionElement, 'value', 'open');
6534
- }
6535
- else {
6536
- const inputs = this.component?.nativeElement.querySelectorAll('.dcf-field-required');
6537
- this.isRequired = inputs?.length > 0;
6538
- if (this.isRequired) {
6539
- this.accordionComponent.value = 'open';
6540
- this.handleAccordionToggle();
6541
- }
6542
- }
7133
+ // if (!this.collapsable)
7134
+ // this.isOpen = true;
7135
+ // if (this.operation === OperationKeys.READ || this.operation === OperationKeys.DELETE) {
7136
+ // this.isOpen = true;
7137
+ // // hidden remove button
7138
+ // const accordionElement = this.component?.nativeElement.querySelector('ion-accordion-group');
7139
+ // if (accordionElement)
7140
+ // this.renderer.setAttribute(accordionElement, 'value', 'open');
7141
+ // } else {
7142
+ // const inputs = this.component?.nativeElement.querySelectorAll('.dcf-field-required');
7143
+ // this.isRequired = inputs?.length > 0;
7144
+ // if (this.isRequired) {
7145
+ // this.accordionComponent.value = 'open';
7146
+ // this.handleAccordionToggle();
7147
+ // }
7148
+ // }
6543
7149
  // if (!(this.formGroup instanceof FormArray))
6544
7150
  // this.formGroup = (this.formGroup as FormGroup)
6545
- this.changeDetectorRef.detectChanges();
7151
+ // this.changeDetectorRef.detectChanges();
6546
7152
  }
6547
7153
  /**
6548
7154
  * @description Handles removal of the fieldset with slide animation.
@@ -6555,15 +7161,23 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
6555
7161
  * @returns {void}
6556
7162
  * @memberOf FieldsetComponent
6557
7163
  */
6558
- handleRemoveComponent(event) {
6559
- event.stopImmediatePropagation();
6560
- this.component.nativeElement.classList.add('dcf-animation', 'dcf-animation-slide-top-medium', 'dcf-animation-reverse', 'dcf-animation-fast');
6561
- setTimeout(() => {
6562
- // Use Renderer2 to safely remove the element
6563
- const parent = this.renderer.parentNode(this.component.nativeElement);
6564
- if (parent)
6565
- this.renderer.removeChild(parent, this.component.nativeElement);
6566
- }, 150);
7164
+ handleClear(event) {
7165
+ if (event)
7166
+ event.stopImmediatePropagation();
7167
+ this.formGroup?.disable();
7168
+ this.items = [];
7169
+ this.value = undefined;
7170
+ this.activePage = undefined;
7171
+ this.activeFormGroupIndex = 0;
7172
+ this.accordionComponent.value = '';
7173
+ this.changeDetectorRef.detectChanges();
7174
+ // this.component.nativeElement.classList.add('dcf-animation', 'dcf-animation-slide-top-medium', 'dcf-animation-reverse', 'dcf-animation-fast');
7175
+ // setTimeout(() => {
7176
+ // // Use Renderer2 to safely remove the element
7177
+ // const parent = this.renderer.parentNode(this.component.nativeElement);
7178
+ // if (parent)
7179
+ // this.renderer.removeChild(parent, this.component.nativeElement);
7180
+ // }, 150);
6567
7181
  }
6568
7182
  /**
6569
7183
  * @description Handles creating new items or triggering group addition events.
@@ -6588,6 +7202,10 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
6588
7202
  async handleCreateItem(event) {
6589
7203
  if (event && event instanceof CustomEvent)
6590
7204
  event.stopImmediatePropagation();
7205
+ if (!this.activePage) {
7206
+ this.activePage = this.getActivePage();
7207
+ return;
7208
+ }
6591
7209
  const formGroup = this.activeFormGroup;
6592
7210
  const value = formGroup.value;
6593
7211
  const hasSomeValue = this.hasValue(value);
@@ -6603,7 +7221,7 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
6603
7221
  this.setValue();
6604
7222
  NgxFormService.addGroupToParent(formGroup.parent);
6605
7223
  this.activeFormGroupIndex = formGroup.parent.length - 1;
6606
- this.getFormArrayIndex(this.activeFormGroupIndex);
7224
+ this.activePage = this.getActivePage();
6607
7225
  }
6608
7226
  else {
6609
7227
  this.isUniqueError = typeof value === ReservedModels.OBJECT ?
@@ -6620,6 +7238,7 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
6620
7238
  if (formGroup) {
6621
7239
  this.updatingItem = Object.assign({}, formGroup.value || {}, { index });
6622
7240
  this.activeFormGroupIndex = index;
7241
+ this.activePage = this.getActivePage();
6623
7242
  }
6624
7243
  }
6625
7244
  /**
@@ -6660,8 +7279,13 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
6660
7279
  formArray.removeAt(index);
6661
7280
  }
6662
7281
  this.setValue();
6663
- if (this.activeFormGroupIndex > 0)
6664
- this.activeFormGroupIndex = this.activeFormGroupIndex - 1;
7282
+ if (this.items.length > 0) {
7283
+ if (this.activeFormGroupIndex > 0)
7284
+ this.activeFormGroupIndex = this.activeFormGroupIndex - 1;
7285
+ }
7286
+ else {
7287
+ this.handleClear();
7288
+ }
6665
7289
  }
6666
7290
  /**
6667
7291
  * @description Handles reordering of items within the fieldset list.
@@ -6740,7 +7364,7 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
6740
7364
  handleAccordionToggle(event) {
6741
7365
  if (event)
6742
7366
  event.stopImmediatePropagation();
6743
- if (!this.collapsable) {
7367
+ if (!this.collapsable || this.isRequired) {
6744
7368
  this.isOpen = true;
6745
7369
  }
6746
7370
  else {
@@ -6758,15 +7382,32 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
6758
7382
  * error state and accordion visibility accordingly.
6759
7383
  *
6760
7384
  * @param {CustomEvent} event - Custom event containing validation error details
6761
- * @returns {void}
7385
+ * @returns {UIModelMetadata[] | undefined}
6762
7386
  * @memberOf FieldsetComponent
6763
7387
  */
6764
- handleValidationError(event) {
6765
- event.stopImmediatePropagation();
6766
- const { hasErrors } = event.detail;
6767
- this.isOpen = this.hasValidationErrors = hasErrors;
6768
- if (hasErrors)
6769
- this.accordionComponent.value = 'open';
7388
+ // handleValidationError(event: CustomEvent): void {
7389
+ // event.stopImmediatePropagation();
7390
+ // const {hasErrors} = event.detail;
7391
+ // this.isOpen = this.hasValidationErrors = hasErrors;
7392
+ // if (hasErrors)
7393
+ // this.accordionComponent.value = 'open';
7394
+ // }
7395
+ getActivePage() {
7396
+ this.activePage = undefined;
7397
+ this.isOpen = true;
7398
+ this.accordionComponent.value = 'open';
7399
+ this.changeDetectorRef.detectChanges();
7400
+ this.timerSubscription = timer(10).subscribe(() => {
7401
+ this.children = this.children.map(child => {
7402
+ if (!child.props)
7403
+ child.props = {};
7404
+ child.props = Object.assign(child.props, { activeFormGroup: this.activeFormGroupIndex, multiple: this.multiple });
7405
+ return child;
7406
+ });
7407
+ });
7408
+ if (this.multiple)
7409
+ this.getFormArrayIndex(this.activeFormGroupIndex);
7410
+ return this.children;
6770
7411
  }
6771
7412
  /**
6772
7413
  * @description Processes and stores a new or updated value in the fieldset.
@@ -6820,7 +7461,7 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
6820
7461
  return this.mapper;
6821
7462
  }
6822
7463
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: FieldsetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6823
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: FieldsetComponent, isStandalone: true, selector: "ngx-decaf-fieldset", inputs: { formControl: "formControl", collapsable: "collapsable", customTypes: "customTypes", title: "title", description: "description", multiple: "multiple", value: "value", borders: "borders", max: "max" }, 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-component ' + operation\"\n [class.dcf-blank]=\"!borders\"\n [class.open]=\"isOpen\"\n [class.not-collapsable]=\"!collapsable\"\n #component>\n <div class=\"dcf-width-1-1\">\n @if (!collapsable) {\n <legend class=\"dcf-title\">{{ (title ? title : name) | translate }}</legend>\n }\n <ion-accordion-group class=\"dcf-width-1-1\" [class.open]=\"isOpen\" [class.hasValidationErrors]=\"hasValidationErrors\" [value]=\"(operation === 'read' || !collapsable) ? 'open' : ''\" #accordionComponent>\n <ion-accordion value=\"open\">\n @if (collapsable) {\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>{{ (title ? title : name) | translate }}</legend>\n </div>\n @if (!isRequired && ['create', 'update'].includes(operation) && collapsable) {\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 }\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 [className]=\"'dcf-fieldset-grid dcf-grid-nested'\"\n [flexMode]=\"props.flexMode || false\"\n [match]=\"false\"\n [gap]=\"'small'\"\n [children]=\"children || []\"\n [parentForm]=\"formGroup || parentForm\"\n [rows]=\"rows\"\n [cols]=\"cols\"\n [hidden]=\"items.length === max && !updatingItem\"\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 @if(max) {\n <div class=\"dcf-width-1-1 dcf-max-message-container\">\n <ion-text class=\"dcf-text-small\"\n [color]=\"items.length !== max ? (!isDarkMode ? 'medium' : '') : 'primary'\"\n >\n {{ locale + (items.length !== max ? '.max_items' : '.max_items_reached') | translate : { '0': max } }}\n </ion-text>\n </div>\n }\n <div class=\"dcf-grid dcf-grid-small dcf-flex dcf-buttons-container\">\n @if (updatingItem) {\n <div>\n <ion-button size=\"small\" fill=\"clear\" color=\"danger\" (click)=\"handleCancelUpdateItem()\">\n {{ buttonCancelLabel }}\n </ion-button>\n </div>\n <div>\n <ion-button size=\"small\" fill=\"clear\" (click)=\"handleCreateItem()\">\n <ion-icon name=\"refresh-outline\" slot=\"start\"></ion-icon>\n {{ locale + '.update' | translate }}\n </ion-button>\n </div>\n } @else {\n @if (items.length < max || !max) {\n <div>\n <ion-button size=\"small\" fill=\"clear\" class=\"dcf-button-add\" [color]=\"isDarkMode ? 'light' : 'dark'\" (click)=\"handleCreateItem()\">\n <ion-icon name=\"add-outline\" slot=\"start\"></ion-icon>\n {{ locale + '.add' | translate }}\n </ion-button>\n </div>\n\n }\n }\n </div>\n }\n </div>\n </ion-accordion>\n </ion-accordion-group>\n </div>\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}*{overflow-x:hidden!important}.dcf-fieldset-component{border-radius:var(--dcf-border-radius-small);border:1px solid var(--dcf-color-gray-3)}.dcf-fieldset-component ion-accordion{background:var(--dcf-card-background)!important}.dcf-fieldset-component.read,.dcf-fieldset-component.delete{margin:var(--dcf-margin-small) 0rem!important}.dcf-fieldset-component:not(.dcf-blank) ion-accordion [slot=header]{--border-color: transparent;--border-radius: 6px;--inner-border-width: 0;--padding-start: .25rem;margin:unset;margin-top:.125rem}.dcf-fieldset-component:not(.dcf-blank) ion-accordion [slot=content]{padding:var(--dcf-padding-small) .25rem}.dcf-fieldset-component.dcf-blank{border-color:transparent;padding:0rem!important;margin:0!important}.dcf-fieldset-component.dcf-blank [slot=content]{padding:var(--dcf-padding-small) .25rem;margin:0!important}.dcf-fieldset-component legend,.dcf-fieldset-component .dcf-title{font-size:.875rem;font-weight:600;margin:0}.dcf-fieldset-component.not-collapsable .dcf-title{margin:var(--dcf-padding-small)!important;display:inline-block}.dcf-fieldset-component .dcf-max-message-container{margin:var(--dcf-padding-small)}.dcf-not-unique-container{display:flex;justify-content:center;align-items:center;margin-bottom:var(--dcf-spacement);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{padding:.25rem var(--dcf-margin-small);margin-bottom:var(--dcf-margin-small)!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}.dcf-fields-list ion-item ion-icon.dcf-reorder-disabled{width:var(--dcf-spacement);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:.925rem;color:var(--ion-color-gray-4)}.dcf-buttons-container{margin-bottom:0!important}@media (max-width: 480px){.dcf-buttons-container{flex-direction:column-reverse;gap:.5rem;align-items:stretch}.dcf-buttons-container ion-button{width:100%;justify-content:center;height:40px}}\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", "flexMode", "rowCard", "maxColsLength"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
7464
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: FieldsetComponent, isStandalone: true, selector: "ngx-decaf-fieldset", inputs: { formControl: "formControl", collapsable: "collapsable", customTypes: "customTypes", title: "title", description: "description", multiple: "multiple", value: "value", borders: "borders", max: "max", required: "required", ordenable: "ordenable", editable: "editable" }, 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-component ' + operation\"\n [class.dcf-blank]=\"!borders\"\n [class.open]=\"isOpen\"\n [class.dcf-not-collapsable]=\"!collapsable\"\n #component>\n <div class=\"dcf-width-1-1\">\n @if (!collapsable || required) {\n <legend class=\"dcf-title\">{{ (title ? title : name) | translate }}</legend>\n }\n <ion-accordion-group class=\"dcf-width-1-1\" [class.open]=\"isOpen\" [class.hasValidationErrors]=\"hasValidationErrors\" [value]=\"(operation === 'read' || !collapsable) ? 'open' : ''\" #accordionComponent>\n <ion-accordion\n value=\"open\"\n [class.dcf-disabled]=\"!activePage\"\n [class.dcf-empty]=\"!items?.length\"\n >\n @if (collapsable && !required) {\n <ion-item 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>{{ (title ? title : name) | translate }}</legend>\n </div>\n @if (!isRequired && ['create', 'update'].includes(operation) && collapsable && multiple) {\n <div class=\"dcf-width-auto dcf-delete\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleClear($event)\">\n <ion-icon aria-hidden=\"true\" name=\"trash-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n }\n </div>\n </ion-item>\n }\n <div slot=\"content\" [attr.aria-hidden]=\"!isOpen\">\n @if (activePage) {\n <div>\n <ngx-decaf-layout\n [className]=\"'dcf-fieldset-grid dcf-grid-nested'\"\n [flexMode]=\"props.flexMode ?? false\"\n [match]=\"false\"\n [gap]=\"'small'\"\n [children]=\"activePage || []\"\n [parentForm]=\"formGroup || parentForm\"\n [rows]=\"rows\"\n [cols]=\"cols\"\n [borders]=\"borders ?? false\"\n [breakpoint]=\"breakpoint ?? 'large'\"\n [hidden]=\"items.length === max && !updatingItem\"\n />\n </div>\n }\n </div>\n </ion-accordion>\n </ion-accordion-group>\n\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(ordenable) {\n @if (items?.length > 1 && !updatingItem) {\n <ion-reorder slot=\"start\">\n <ion-icon aria-hidden=\"true\" name=\"swap-vertical-outline\"></ion-icon>\n </ion-reorder>\n } @else {\n <div slot=\"start\">\n <ion-icon aria-hidden=\"true\" class=\"dcf-reorder-disabled\" size=\"small\" name=\"swap-vertical-outline\" disabled></ion-icon>\n </div>\n }\n }\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\n @if(editable) {\n @if (!updatingItem || updatingItem?.[pk] !== item.title) {\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleUpdateItem($index)\">\n <ion-icon aria-hidden=\"true\" name=\"create-outline\" color=\"dark\" ></ion-icon>\n </ion-button>\n }\n }\n\n\n @if (!updatingItem) {\n <ion-button fill=\"clear\" size=\"small\" color=\"danger\" (click)=\"handleRemoveItem($index)\">\n <ion-icon aria-hidden=\"true\" name=\"close-outline\" color=\"dark\"></ion-icon>\n </ion-button>\n }\n </ion-item>\n }\n </ion-reorder-group>\n </ion-list>\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 aria-hidden=\"true\" 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 @if(max) {\n <div class=\"dcf-width-1-1 dcf-max-message-container\">\n <ion-text class=\"dcf-text-small\"\n [color]=\"items.length !== max ? (!isDarkMode ? 'medium' : '') : 'primary'\"\n >\n {{ locale + (items.length !== max ? '.max_items' : '.max_items_reached') | translate : { '0': max } }}\n </ion-text>\n </div>\n }\n\n <div class=\"dcf-grid dcf-grid-small dcf-flex dcf-buttons-container\" [class.dcf-not-collapsable]=\"!collapsable\" [class.dcf-empty]=\"!activePage\" [class.dcf-blank]=\"!borders\">\n @if (updatingItem) {\n <div>\n <ion-button size=\"small\" fill=\"clear\" color=\"danger\" (click)=\"handleCancelUpdateItem()\">\n {{ locale + '.cancel' | translate }}\n </ion-button>\n </div>\n <div>\n <ion-button size=\"small\" fill=\"clear\" (click)=\"handleCreateItem()\">\n <ion-icon aria-hidden=\"true\" name=\"refresh-outline\" slot=\"start\"></ion-icon>\n {{ locale + '.update' | translate }}\n </ion-button>\n </div>\n } @else {\n\n @if (items.length < max || !max) {\n <div>\n <ion-button size=\"small\" fill=\"clear\" class=\"dcf-button-add\" [color]=\"isDarkMode ? 'light' : 'dark'\" (click)=\"handleCreateItem()\">\n <ion-icon aria-hidden=\"true\" name=\"add-outline\" slot=\"start\"></ion-icon>\n {{ locale + '.add' | translate }}\n </ion-button>\n </div>\n }\n }\n </div>\n }\n </div>\n</fieldset>\n\n", styles: ["ion-accordion ion-item[slot=header] .dcf-delete{width:30px}ion-accordion ion-item[slot=header] .dcf-delete ion-button{transform:translateY(-2px)}ion-accordion ion-item[slot=header] .dcf-delete ion-icon{font-size:1.15rem}ion-accordion.dcf-disabled [slot=content]{padding-bottom:0rem!important}ion-accordion.dcf-empty,ion-accordion.dcf-disabled{opacity:1!important}ion-accordion.dcf-empty ::ng-deep .ion-accordion-toggle-icon,ion-accordion.dcf-disabled ::ng-deep .ion-accordion-toggle-icon{display:none!important}ion-accordion.dcf-empty .dcf-delete,ion-accordion.dcf-disabled .dcf-delete{display:none!important}ion-accordion.dcf-empty ion-item[slot=header],ion-accordion.dcf-disabled ion-item[slot=header]{pointer-events:none;cursor:default!important}.dcf-fieldset-component{border-radius:var(--dcf-border-radius-small);border:1px solid var(--dcf-color-gray-3)}.dcf-fieldset-component.dcf-blank{border-color:transparent;padding:0rem!important;margin:0!important}.dcf-fieldset-component *{overflow-x:hidden!important}.dcf-fieldset-component ion-accordion:not(.dcf-empty){background:var(--dcf-card-background)!important}.dcf-fieldset-component ion-accordion ion-item{--background-hover: transparent !important}.dcf-fieldset-component.read,.dcf-fieldset-component.delete{margin:var(--dcf-margin-small) 0rem!important}.dcf-fieldset-component.read [slot=header],.dcf-fieldset-component.delete [slot=header]{margin-bottom:0rem!important}.dcf-fieldset-component [slot=header]{--border-color: transparent;--border-radius: 6px;--inner-border-width: 0;--padding-start: .65rem;--color: var(--ion-color-text) !important;margin:unset}.dcf-fieldset-component legend,.dcf-fieldset-component .dcf-title{font-weight:500;font-size:1rem;line-height:1.5rem;font-weight:600;margin:0;color:var(--ion-color-text)!important}.dcf-fieldset-component .dcf-title{padding:.8rem!important}.dcf-fieldset-component [slot=content]{padding:var(--dcf-padding-small) .25rem!important}.dcf-fieldset-component [slot=content]>div{padding-top:.25rem!important}.dcf-fieldset-component:not(.dcf-blank) ion-accordion [slot=header]{margin-top:.125rem}.dcf-fieldset-component .dcf-max-message-container{margin:var(--dcf-padding-small) .75rem}.dcf-not-unique-container{display:flex;justify-content:center;align-items:center;margin-bottom:var(--dcf-spacement);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{padding:.25rem var(--dcf-margin-small);margin-bottom:var(--dcf-margin-small)!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}.dcf-fields-list ion-item ion-icon.dcf-reorder-disabled{width:var(--dcf-spacement);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:.925rem;color:var(--ion-color-gray-4)}.dcf-buttons-container{margin-bottom:0!important;margin-top:-.5rem;padding:0rem .125rem}.dcf-buttons-container:not(.dcf-blank){padding-bottom:var(--dcf-padding-small)!important}.dcf-buttons-container.dcf-not-collapsable.dcf-empty{position:relative;top:-1rem!important}@media (max-width: 480px){.dcf-buttons-container{flex-direction:column-reverse;gap:.5rem;align-items:stretch}.dcf-buttons-container ion-button{width:100%;justify-content:center;height:40px}}\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", "grid", "flexMode", "rowCard", "maxColsLength"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
6824
7465
  };
6825
7466
  FieldsetComponent = __decorate([
6826
7467
  Dynamic(),
@@ -6842,7 +7483,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
6842
7483
  IonButton,
6843
7484
  IonIcon,
6844
7485
  LayoutComponent
6845
- ], template: "\n\n<fieldset\n (fieldsetAddGroupEvent)=\"handleCreateItem($event)\"\n [class]=\"'dcf-fieldset-component ' + operation\"\n [class.dcf-blank]=\"!borders\"\n [class.open]=\"isOpen\"\n [class.not-collapsable]=\"!collapsable\"\n #component>\n <div class=\"dcf-width-1-1\">\n @if (!collapsable) {\n <legend class=\"dcf-title\">{{ (title ? title : name) | translate }}</legend>\n }\n <ion-accordion-group class=\"dcf-width-1-1\" [class.open]=\"isOpen\" [class.hasValidationErrors]=\"hasValidationErrors\" [value]=\"(operation === 'read' || !collapsable) ? 'open' : ''\" #accordionComponent>\n <ion-accordion value=\"open\">\n @if (collapsable) {\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>{{ (title ? title : name) | translate }}</legend>\n </div>\n @if (!isRequired && ['create', 'update'].includes(operation) && collapsable) {\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 }\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 [className]=\"'dcf-fieldset-grid dcf-grid-nested'\"\n [flexMode]=\"props.flexMode || false\"\n [match]=\"false\"\n [gap]=\"'small'\"\n [children]=\"children || []\"\n [parentForm]=\"formGroup || parentForm\"\n [rows]=\"rows\"\n [cols]=\"cols\"\n [hidden]=\"items.length === max && !updatingItem\"\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 @if(max) {\n <div class=\"dcf-width-1-1 dcf-max-message-container\">\n <ion-text class=\"dcf-text-small\"\n [color]=\"items.length !== max ? (!isDarkMode ? 'medium' : '') : 'primary'\"\n >\n {{ locale + (items.length !== max ? '.max_items' : '.max_items_reached') | translate : { '0': max } }}\n </ion-text>\n </div>\n }\n <div class=\"dcf-grid dcf-grid-small dcf-flex dcf-buttons-container\">\n @if (updatingItem) {\n <div>\n <ion-button size=\"small\" fill=\"clear\" color=\"danger\" (click)=\"handleCancelUpdateItem()\">\n {{ buttonCancelLabel }}\n </ion-button>\n </div>\n <div>\n <ion-button size=\"small\" fill=\"clear\" (click)=\"handleCreateItem()\">\n <ion-icon name=\"refresh-outline\" slot=\"start\"></ion-icon>\n {{ locale + '.update' | translate }}\n </ion-button>\n </div>\n } @else {\n @if (items.length < max || !max) {\n <div>\n <ion-button size=\"small\" fill=\"clear\" class=\"dcf-button-add\" [color]=\"isDarkMode ? 'light' : 'dark'\" (click)=\"handleCreateItem()\">\n <ion-icon name=\"add-outline\" slot=\"start\"></ion-icon>\n {{ locale + '.add' | translate }}\n </ion-button>\n </div>\n\n }\n }\n </div>\n }\n </div>\n </ion-accordion>\n </ion-accordion-group>\n </div>\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}*{overflow-x:hidden!important}.dcf-fieldset-component{border-radius:var(--dcf-border-radius-small);border:1px solid var(--dcf-color-gray-3)}.dcf-fieldset-component ion-accordion{background:var(--dcf-card-background)!important}.dcf-fieldset-component.read,.dcf-fieldset-component.delete{margin:var(--dcf-margin-small) 0rem!important}.dcf-fieldset-component:not(.dcf-blank) ion-accordion [slot=header]{--border-color: transparent;--border-radius: 6px;--inner-border-width: 0;--padding-start: .25rem;margin:unset;margin-top:.125rem}.dcf-fieldset-component:not(.dcf-blank) ion-accordion [slot=content]{padding:var(--dcf-padding-small) .25rem}.dcf-fieldset-component.dcf-blank{border-color:transparent;padding:0rem!important;margin:0!important}.dcf-fieldset-component.dcf-blank [slot=content]{padding:var(--dcf-padding-small) .25rem;margin:0!important}.dcf-fieldset-component legend,.dcf-fieldset-component .dcf-title{font-size:.875rem;font-weight:600;margin:0}.dcf-fieldset-component.not-collapsable .dcf-title{margin:var(--dcf-padding-small)!important;display:inline-block}.dcf-fieldset-component .dcf-max-message-container{margin:var(--dcf-padding-small)}.dcf-not-unique-container{display:flex;justify-content:center;align-items:center;margin-bottom:var(--dcf-spacement);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{padding:.25rem var(--dcf-margin-small);margin-bottom:var(--dcf-margin-small)!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}.dcf-fields-list ion-item ion-icon.dcf-reorder-disabled{width:var(--dcf-spacement);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:.925rem;color:var(--ion-color-gray-4)}.dcf-buttons-container{margin-bottom:0!important}@media (max-width: 480px){.dcf-buttons-container{flex-direction:column-reverse;gap:.5rem;align-items:stretch}.dcf-buttons-container ion-button{width:100%;justify-content:center;height:40px}}\n"] }]
7486
+ ], template: "\n\n<fieldset\n (fieldsetAddGroupEvent)=\"handleCreateItem($event)\"\n [class]=\"'dcf-fieldset-component ' + operation\"\n [class.dcf-blank]=\"!borders\"\n [class.open]=\"isOpen\"\n [class.dcf-not-collapsable]=\"!collapsable\"\n #component>\n <div class=\"dcf-width-1-1\">\n @if (!collapsable || required) {\n <legend class=\"dcf-title\">{{ (title ? title : name) | translate }}</legend>\n }\n <ion-accordion-group class=\"dcf-width-1-1\" [class.open]=\"isOpen\" [class.hasValidationErrors]=\"hasValidationErrors\" [value]=\"(operation === 'read' || !collapsable) ? 'open' : ''\" #accordionComponent>\n <ion-accordion\n value=\"open\"\n [class.dcf-disabled]=\"!activePage\"\n [class.dcf-empty]=\"!items?.length\"\n >\n @if (collapsable && !required) {\n <ion-item 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>{{ (title ? title : name) | translate }}</legend>\n </div>\n @if (!isRequired && ['create', 'update'].includes(operation) && collapsable && multiple) {\n <div class=\"dcf-width-auto dcf-delete\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleClear($event)\">\n <ion-icon aria-hidden=\"true\" name=\"trash-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n }\n </div>\n </ion-item>\n }\n <div slot=\"content\" [attr.aria-hidden]=\"!isOpen\">\n @if (activePage) {\n <div>\n <ngx-decaf-layout\n [className]=\"'dcf-fieldset-grid dcf-grid-nested'\"\n [flexMode]=\"props.flexMode ?? false\"\n [match]=\"false\"\n [gap]=\"'small'\"\n [children]=\"activePage || []\"\n [parentForm]=\"formGroup || parentForm\"\n [rows]=\"rows\"\n [cols]=\"cols\"\n [borders]=\"borders ?? false\"\n [breakpoint]=\"breakpoint ?? 'large'\"\n [hidden]=\"items.length === max && !updatingItem\"\n />\n </div>\n }\n </div>\n </ion-accordion>\n </ion-accordion-group>\n\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(ordenable) {\n @if (items?.length > 1 && !updatingItem) {\n <ion-reorder slot=\"start\">\n <ion-icon aria-hidden=\"true\" name=\"swap-vertical-outline\"></ion-icon>\n </ion-reorder>\n } @else {\n <div slot=\"start\">\n <ion-icon aria-hidden=\"true\" class=\"dcf-reorder-disabled\" size=\"small\" name=\"swap-vertical-outline\" disabled></ion-icon>\n </div>\n }\n }\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\n @if(editable) {\n @if (!updatingItem || updatingItem?.[pk] !== item.title) {\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleUpdateItem($index)\">\n <ion-icon aria-hidden=\"true\" name=\"create-outline\" color=\"dark\" ></ion-icon>\n </ion-button>\n }\n }\n\n\n @if (!updatingItem) {\n <ion-button fill=\"clear\" size=\"small\" color=\"danger\" (click)=\"handleRemoveItem($index)\">\n <ion-icon aria-hidden=\"true\" name=\"close-outline\" color=\"dark\"></ion-icon>\n </ion-button>\n }\n </ion-item>\n }\n </ion-reorder-group>\n </ion-list>\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 aria-hidden=\"true\" 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 @if(max) {\n <div class=\"dcf-width-1-1 dcf-max-message-container\">\n <ion-text class=\"dcf-text-small\"\n [color]=\"items.length !== max ? (!isDarkMode ? 'medium' : '') : 'primary'\"\n >\n {{ locale + (items.length !== max ? '.max_items' : '.max_items_reached') | translate : { '0': max } }}\n </ion-text>\n </div>\n }\n\n <div class=\"dcf-grid dcf-grid-small dcf-flex dcf-buttons-container\" [class.dcf-not-collapsable]=\"!collapsable\" [class.dcf-empty]=\"!activePage\" [class.dcf-blank]=\"!borders\">\n @if (updatingItem) {\n <div>\n <ion-button size=\"small\" fill=\"clear\" color=\"danger\" (click)=\"handleCancelUpdateItem()\">\n {{ locale + '.cancel' | translate }}\n </ion-button>\n </div>\n <div>\n <ion-button size=\"small\" fill=\"clear\" (click)=\"handleCreateItem()\">\n <ion-icon aria-hidden=\"true\" name=\"refresh-outline\" slot=\"start\"></ion-icon>\n {{ locale + '.update' | translate }}\n </ion-button>\n </div>\n } @else {\n\n @if (items.length < max || !max) {\n <div>\n <ion-button size=\"small\" fill=\"clear\" class=\"dcf-button-add\" [color]=\"isDarkMode ? 'light' : 'dark'\" (click)=\"handleCreateItem()\">\n <ion-icon aria-hidden=\"true\" name=\"add-outline\" slot=\"start\"></ion-icon>\n {{ locale + '.add' | translate }}\n </ion-button>\n </div>\n }\n }\n </div>\n }\n </div>\n</fieldset>\n\n", styles: ["ion-accordion ion-item[slot=header] .dcf-delete{width:30px}ion-accordion ion-item[slot=header] .dcf-delete ion-button{transform:translateY(-2px)}ion-accordion ion-item[slot=header] .dcf-delete ion-icon{font-size:1.15rem}ion-accordion.dcf-disabled [slot=content]{padding-bottom:0rem!important}ion-accordion.dcf-empty,ion-accordion.dcf-disabled{opacity:1!important}ion-accordion.dcf-empty ::ng-deep .ion-accordion-toggle-icon,ion-accordion.dcf-disabled ::ng-deep .ion-accordion-toggle-icon{display:none!important}ion-accordion.dcf-empty .dcf-delete,ion-accordion.dcf-disabled .dcf-delete{display:none!important}ion-accordion.dcf-empty ion-item[slot=header],ion-accordion.dcf-disabled ion-item[slot=header]{pointer-events:none;cursor:default!important}.dcf-fieldset-component{border-radius:var(--dcf-border-radius-small);border:1px solid var(--dcf-color-gray-3)}.dcf-fieldset-component.dcf-blank{border-color:transparent;padding:0rem!important;margin:0!important}.dcf-fieldset-component *{overflow-x:hidden!important}.dcf-fieldset-component ion-accordion:not(.dcf-empty){background:var(--dcf-card-background)!important}.dcf-fieldset-component ion-accordion ion-item{--background-hover: transparent !important}.dcf-fieldset-component.read,.dcf-fieldset-component.delete{margin:var(--dcf-margin-small) 0rem!important}.dcf-fieldset-component.read [slot=header],.dcf-fieldset-component.delete [slot=header]{margin-bottom:0rem!important}.dcf-fieldset-component [slot=header]{--border-color: transparent;--border-radius: 6px;--inner-border-width: 0;--padding-start: .65rem;--color: var(--ion-color-text) !important;margin:unset}.dcf-fieldset-component legend,.dcf-fieldset-component .dcf-title{font-weight:500;font-size:1rem;line-height:1.5rem;font-weight:600;margin:0;color:var(--ion-color-text)!important}.dcf-fieldset-component .dcf-title{padding:.8rem!important}.dcf-fieldset-component [slot=content]{padding:var(--dcf-padding-small) .25rem!important}.dcf-fieldset-component [slot=content]>div{padding-top:.25rem!important}.dcf-fieldset-component:not(.dcf-blank) ion-accordion [slot=header]{margin-top:.125rem}.dcf-fieldset-component .dcf-max-message-container{margin:var(--dcf-padding-small) .75rem}.dcf-not-unique-container{display:flex;justify-content:center;align-items:center;margin-bottom:var(--dcf-spacement);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{padding:.25rem var(--dcf-margin-small);margin-bottom:var(--dcf-margin-small)!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}.dcf-fields-list ion-item ion-icon.dcf-reorder-disabled{width:var(--dcf-spacement);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:.925rem;color:var(--ion-color-gray-4)}.dcf-buttons-container{margin-bottom:0!important;margin-top:-.5rem;padding:0rem .125rem}.dcf-buttons-container:not(.dcf-blank){padding-bottom:var(--dcf-padding-small)!important}.dcf-buttons-container.dcf-not-collapsable.dcf-empty{position:relative;top:-1rem!important}@media (max-width: 480px){.dcf-buttons-container{flex-direction:column-reverse;gap:.5rem;align-items:stretch}.dcf-buttons-container ion-button{width:100%;justify-content:center;height:40px}}\n"] }]
6846
7487
  }], ctorParameters: () => [], propDecorators: { accordionComponent: [{
6847
7488
  type: ViewChild,
6848
7489
  args: ['accordionComponent', { static: false }]
@@ -6864,6 +7505,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
6864
7505
  type: Input
6865
7506
  }], max: [{
6866
7507
  type: Input
7508
+ }], required: [{
7509
+ type: Input
7510
+ }], ordenable: [{
7511
+ type: Input
7512
+ }], editable: [{
7513
+ type: Input
6867
7514
  }] } });
6868
7515
 
6869
7516
  /**
@@ -7999,7 +8646,7 @@ let FilterComponent = class FilterComponent extends NgxComponentDirective {
7999
8646
  this.searchEvent.emit(value);
8000
8647
  }
8001
8648
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: FilterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8002
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: FilterComponent, isStandalone: true, selector: "ngx-decaf-filter", inputs: { indexes: "indexes", conditions: "conditions", sortBy: "sortBy", disableSort: "disableSort" }, outputs: { filterEvent: "filterEvent", searchEvent: "searchEvent" }, host: { properties: { "attr.id": "uid" } }, viewQueries: [{ propertyName: "optionsFilterElement", first: true, predicate: ["optionsFilterElement"], descendants: true, read: ElementRef }], usesInheritance: true, ngImport: i0, template: "\n@if (!indexes.length) {\n <ngx-decaf-searchbar [emitEventToWindow]=\"false\" [debounce]=\"500\" (searchEvent)=\"handleSearch($event)\" />\n}\n\n<div [id]=\"uid\" class=\"dcf-grid dcf-grid-small dcf-grid-match dcf-filter-component\" [class.dcf-hidden]=\"!indexes.length\" #component>\n <div class=\"dcf-width-expand\">\n <div class=\"dcf-filter\">\n <div class=\"dcf-input\">\n @for(filter of filterValue; track trackItemFn($index, filter?.['index'])) {\n @if (filter?.['index']) {\n <ion-chip [outline]=\"true\">{{ filter?.['index'] }}</ion-chip>\n }\n @if (filter?.['condition']) {\n <ion-chip [outline]=\"true\">{{ filter?.['condition'] }}</ion-chip>\n }\n @if (filter?.['value']) {\n <ion-chip [outline]=\"true\" class=\"dcf-filter-value\">\n {{ filter?.['value'] }}\n <ion-icon name=\"close-outline\" (click)=\"removeFilter(filter?.['value'])\" size=\"small\"></ion-icon>\n </ion-chip>\n }\n }\n <div class=\"dcf-width-1-1\">\n <!-- [readonly]=\"step !== 3\" -->\n <input\n fill=\"none\"\n [(ngModel)]=\"value\"\n (keydown.enter)=\"addFilter(value, $event)\"\n (keydown.backspace)=\"clear(value)\"\n (input)=\"handleInput($event)\"\n (click)=\"handleFocus()\"\n (blur)=\"handleBlur()\"\n type=\"text\"\n id=\"dcf-filter-field\"\n placeholder=\"{{ locale + (step === 3 ? '.type' : '.select') | translate }}\"\n\n />\n @if (windowWidth >= 768) {\n <div [class]=\"'dcf-dropdown ' + (options.length > 0 ? ' dcf-active' : '')\" #optionsFilterElement>\n <div>\n @if (filteredOptions.length > 0) {\n @for(key of filteredOptions; track key) {\n <div\n class=\"dcf-item\"\n tabindex=\"0\"\n (keydown.enter)=\"selectOption(key)\"\n (click)=\"selectOption(key)\">\n {{ key }}\n </div>\n }\n } @else {\n <div class=\"dcf-empty\"\n (click)=\"filteredOptions = options; value = ''\"\n tabindex=\"0\"\n (keydown.enter)=\"filteredOptions = options; value = ''\"\n >\n {{ locale + '.no_suggestions' | translate }}\n </div>\n }\n </div>\n </div>\n }\n </div>\n </div>\n @if (filterValue.length > 0) {\n <div class=\"dcf-icon-clear\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"clear()\">\n <ion-icon name=\"trash-outline\" [color]=\"!isDarkMode ? 'dark' : 'light'\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n }\n <div class=\"dcf-icon-search\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"submit()\">\n <ion-icon name=\"search-outline\" [color]=\"!isDarkMode ? 'dark' : 'light'\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n </div>\n @if (windowWidth < 768) {\n <div [class]=\"'dcf-dropdown ' + (options.length > 0 ? ' dcf-active' : '')\" #optionsFilterElement>\n <div>\n @if (filteredOptions.length > 0) {\n @for(key of filteredOptions; track key) {\n <div\n class=\"dcf-item\"\n tabindex=\"0\"\n (keydown.enter)=\"selectOption(key)\"\n (click)=\"selectOption(key)\">\n {{ key }}\n </div>\n }\n } @else {\n <div class=\"dcf-empty\"\n (click)=\"filteredOptions = options; value = ''\"\n tabindex=\"0\"\n (keydown.enter)=\"filteredOptions = options; value = ''\"\n >\n {{ locale + '.no_suggestions' | translate }}\n </div>\n }\n </div>\n </div>\n }\n </div>\n @if (!disableSort) {\n <div class=\"dcf-width-1-5@m dcf-width-1-1 dcf-sort-container\">\n <div class=\"dcf-grid dcf-grid-collapse dcf-flex dcf-flex-middle dcf-grid-match\">\n <div class=\"dcf-width-expand\">\n <ion-select\n toggleIcon=\"chevron-down-outline\"\n expandedIcon=\"chevron-up-outline\"\n class=\"dcf-sort-select\"\n (ionChange)=\"handleSortChange($event)\"\n interface=\"popover\"\n [value]=\"sortValue\"\n label-placement=\"floating\"\n fill=\"outline\"\n [label]=\"locale + '.sort' | translate\"\n >\n @for(sort of sortBy; track sort) {\n\n <ion-select-option [value]=\"sort\">{{ sort | translate }}</ion-select-option>\n }\n </ion-select>\n </div>\n <div class=\"dcf-width-auto\">\n <ion-button (click)=\"handleSortDirectionChange()\" fill=\"clear\">\n <ion-icon slot=\"icon-only\" [color]=\"!isDarkMode ? 'primary' : 'light'\" [name]=\"sortDirection === 'desc' ? 'arrow-down-outline' : 'arrow-up-outline'\"></ion-icon>\n </ion-button>\n </div>\n </div>\n </div>\n }\n</div>\n\n\n", styles: [".dcf-filter-component{padding:0 .5rem;margin-top:.75rem;margin-bottom:.75rem}.dcf-filter-component:not(.dcf-palette-dark) .dcf-filter{border:1px solid var(--dcf-color-gray-3);background-color:#fff}.dcf-filter-component:not(.dcf-palette-dark) .dcf-filter:focus-within{border-color:var(--dcf-color-primary);background-color:#fff}.dcf-filter-component:not(.dcf-palette-dark) ion-chip{border:1px solid var(--dcf-color-gray-3);color:var(--dcf-color-gray-7)}.dcf-filter-component:not(.dcf-palette-dark) ion-chip.dcf-filter-value{background:var(--dcf-color-gray-2);border-color:var(--dcf-color-gray-4)!important;color:var(--dcf-color-gray-8)!important}.dcf-filter-component:not(.dcf-palette-dark) .dcf-input input{color:var(--dcf-color-gray-7)}.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown{background-color:#fff}.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown.dcf-active{border:1px solid var(--dcf-color-gray-2)}.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown.dcf-active>div>div{color:var(--dcf-color-gray-8)}.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown.dcf-active>div>div.dcf-filtering-item,.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown.dcf-active>div>div:only-child{border-color:var(--dcf-color-gray-3)}.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown.dcf-active>div>div.dcf-filtering-item.dcf-empty,.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown.dcf-active>div>div:only-child.dcf-empty{pointer-events:none;touch-action:none;cursor:text!important;border-color:transparent!important}.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown.dcf-active>div>div:hover{background-color:var(--dcf-color-gray-1)}.dcf-filter-component.dcf-palette-dark .dcf-filter{border:1px solid var(--dcf-color-step-500)}.dcf-filter-component.dcf-palette-dark .dcf-filter ::-webkit-input-placeholder,.dcf-filter-component.dcf-palette-dark .dcf-filter ::placeholder{color:var(--dcf-color-gray-4)!important}.dcf-filter-component.dcf-palette-dark .dcf-filter:hover{border-color:var(--dcf-color-gray-2)}.dcf-filter-component.dcf-palette-dark .dcf-filter:focus-within{border-color:var(--dcf-color-gray-2)}.dcf-filter-component.dcf-palette-dark ion-chip{border-color:var(--dcf-color-step-300);background:rgba(var(--dcf-color-medium-rgb),.1)}.dcf-filter-component.dcf-palette-dark ion-chip.dcf-filter-value{background:rgba(var(--dcf-color-medium-rgb),.3)!important;border-color:var(--dcf-color-step-500)}.dcf-filter-component.dcf-palette-dark .dcf-input input{color:var(--dcf-color-gray-1)}.dcf-filter-component.dcf-palette-dark .dcf-dropdown{background-color:var(--dcf-item-background)}.dcf-filter-component.dcf-palette-dark .dcf-dropdown.dcf-active{border:1px solid var(--dcf-color-step-600)}.dcf-filter-component.dcf-palette-dark .dcf-dropdown.dcf-active>div>div{color:var(--dcf-color-gray-1)}.dcf-filter-component.dcf-palette-dark .dcf-dropdown.dcf-active>div>div.dcf-filtering-item,.dcf-filter-component.dcf-palette-dark .dcf-dropdown.dcf-active>div>div:only-child{border-color:var(--dcf-color-gray-5)}.dcf-filter-component.dcf-palette-dark .dcf-dropdown.dcf-active>div>div.dcf-filtering-item.dcf-empty,.dcf-filter-component.dcf-palette-dark .dcf-dropdown.dcf-active>div>div:only-child.dcf-empty{cursor:text!important;pointer-events:none;touch-action:none;border-color:transparent!important}.dcf-filter-component.dcf-palette-dark .dcf-dropdown.dcf-active>div>div:hover{background-color:var(--dcf-color-gray-8)}ion-select{min-height:44px!important}.dcf-hidden{display:none!important}.dcf-filter{display:flex;width:100%;min-height:40px;box-shadow:0 1px 2px #0a0d120d;border-radius:var(--dcf-border-radius);box-sizing:border-box}.dcf-filter ion-chip{border-radius:6px;padding:0 8px!important;height:24px;min-height:24px;font-size:.75rem;font-style:normal;font-weight:500;flex-shrink:0;margin-right:2px;white-space:nowrap}.dcf-filter ion-chip.sc-ion-chip-md-h,.dcf-filter ion-chip.sc-ion-chip-ios-h{height:24px;min-height:24px}.dcf-filter ion-chip.sc-ion-chip-md-h .chip-native,.dcf-filter ion-chip.sc-ion-chip-ios-h .chip-native{padding:0 8px!important;height:24px;min-height:24px}.dcf-filter ion-chip ion-label{padding:0 4px;margin:0;font-size:.75rem;white-space:nowrap}.dcf-filter ion-chip ion-icon{margin:0 2px;font-size:.75rem}.dcf-filter .dcf-input{width:100%;display:flex;align-items:center;overflow-x:auto;overflow-y:hidden;white-space:nowrap;padding-left:.5rem}.dcf-filter .dcf-input input{min-height:40px;min-width:100px;width:100%;font-size:1rem;border:none;outline:none;background:transparent;border:0px!important;outline:none!important}.dcf-filter .dcf-input input:focus{border:0px!important;outline:none!important}.dcf-filter .dcf-icon-clear,.dcf-filter .dcf-icon-search{display:flex;justify-content:center;text-align:center;align-items:center;min-width:40px}.dcf-filter .dcf-icon-search ion-icon{font-size:1.25rem}.dcf-sort-container{min-width:200px!important;width:auto}@media (min-width: 990px){.dcf-sort-container{max-width:20%!important}}@media (max-width: 680px){.dcf-sort-container{min-width:100%!important;margin:.75rem 0rem}}.dcf-dropdown{position:absolute;max-height:200px;overflow-y:auto;border-radius:4px;z-index:1000!important;min-width:200px;max-width:300px;display:none}.dcf-dropdown.dcf-active{display:block;margin-top:-3px;box-shadow:0 12px 16px -4px #0a0d1214,0 4px 6px -2px #0a0d1208,0 2px 2px -1px #0a0d120a!important;border-radius:var(--dcf-border-radius);padding:.5rem .25rem}@media (max-width: 768px){.dcf-dropdown.dcf-active{margin-top:55px}}.dcf-dropdown.dcf-active>div>div{cursor:pointer;height:35px;padding:.5rem 1rem;border:1px solid transparent;font-size:1rem;display:flex;align-items:center;border-radius:6px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: IonChip, selector: "ion-chip", inputs: ["color", "disabled", "mode", "outline"] }, { 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: "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: 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: "pipe", type: TranslatePipe, name: "translate" }] }); }
8649
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: FilterComponent, isStandalone: true, selector: "ngx-decaf-filter", inputs: { indexes: "indexes", conditions: "conditions", sortBy: "sortBy", disableSort: "disableSort" }, outputs: { filterEvent: "filterEvent", searchEvent: "searchEvent" }, host: { properties: { "attr.id": "uid" } }, viewQueries: [{ propertyName: "optionsFilterElement", first: true, predicate: ["optionsFilterElement"], descendants: true, read: ElementRef }], usesInheritance: true, ngImport: i0, template: "\n@if (!indexes.length) {\n <ngx-decaf-searchbar [emitEventToWindow]=\"false\" [debounce]=\"500\" (searchEvent)=\"handleSearch($event)\" />\n}\n\n<div [id]=\"uid\" class=\"dcf-grid dcf-grid-small dcf-grid-match dcf-filter-component\" [class.dcf-hidden]=\"!indexes.length\" #component>\n <div class=\"dcf-width-expand\">\n <div class=\"dcf-filter\">\n <div class=\"dcf-input\">\n @for(filter of filterValue; track trackItemFn($index, filter?.['index'])) {\n @if (filter?.['index']) {\n <ion-chip [outline]=\"true\">{{ filter?.['index'] }}</ion-chip>\n }\n @if (filter?.['condition']) {\n <ion-chip [outline]=\"true\">{{ filter?.['condition'] }}</ion-chip>\n }\n @if (filter?.['value']) {\n <ion-chip [outline]=\"true\" class=\"dcf-filter-value\">\n {{ filter?.['value'] }}\n <ion-icon tabindex=\"0\" name=\"close-outline\" (click)=\"removeFilter(filter?.['value'])\" size=\"small\"></ion-icon>\n </ion-chip>\n }\n }\n <div class=\"dcf-width-1-1\">\n <!-- [readonly]=\"step !== 3\" -->\n <input\n fill=\"none\"\n [(ngModel)]=\"value\"\n (keydown.enter)=\"addFilter(value, $event)\"\n (keydown.backspace)=\"clear(value)\"\n (input)=\"handleInput($event)\"\n (click)=\"handleFocus()\"\n (blur)=\"handleBlur()\"\n type=\"text\"\n id=\"dcf-filter-field\"\n placeholder=\"{{ locale + (step === 3 ? '.type' : '.select') | translate }}\"\n\n />\n @if (windowWidth >= 768) {\n <div [class]=\"'dcf-dropdown ' + (options.length > 0 ? ' dcf-active' : '')\" #optionsFilterElement>\n <div>\n @if (filteredOptions.length > 0) {\n @for(key of filteredOptions; track key) {\n <div\n class=\"dcf-item\"\n tabindex=\"0\"\n (keydown.enter)=\"selectOption(key)\"\n (click)=\"selectOption(key)\">\n {{ key }}\n </div>\n }\n } @else {\n <div class=\"dcf-empty\"\n (click)=\"filteredOptions = options; value = ''\"\n tabindex=\"0\"\n (keydown.enter)=\"filteredOptions = options; value = ''\"\n >\n {{ locale + '.no_suggestions' | translate }}\n </div>\n }\n </div>\n </div>\n }\n </div>\n </div>\n @if (filterValue.length > 0) {\n <div class=\"dcf-icon-clear\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"clear()\">\n <ion-icon aria-hidden=\"true\" name=\"trash-outline\" [color]=\"!isDarkMode ? 'dark' : 'light'\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n }\n <div class=\"dcf-icon-search\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"submit()\">\n <ion-icon aria-hidden=\"true\" name=\"search-outline\" [color]=\"!isDarkMode ? 'dark' : 'light'\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n </div>\n @if (windowWidth < 768) {\n <div [class]=\"'dcf-dropdown ' + (options.length > 0 ? ' dcf-active' : '')\" #optionsFilterElement>\n <div>\n @if (filteredOptions.length > 0) {\n @for(key of filteredOptions; track key) {\n <div\n class=\"dcf-item\"\n tabindex=\"0\"\n (keydown.enter)=\"selectOption(key)\"\n (click)=\"selectOption(key)\">\n {{ key }}\n </div>\n }\n } @else {\n <div class=\"dcf-empty\"\n (click)=\"filteredOptions = options; value = ''\"\n tabindex=\"0\"\n (keydown.enter)=\"filteredOptions = options; value = ''\"\n >\n {{ locale + '.no_suggestions' | translate }}\n </div>\n }\n </div>\n </div>\n }\n </div>\n @if (!disableSort) {\n <div class=\"dcf-width-1-5@m dcf-width-1-1 dcf-sort-container\">\n <div class=\"dcf-grid dcf-grid-collapse dcf-flex dcf-flex-middle dcf-grid-match\">\n <div class=\"dcf-width-expand\">\n <ion-select\n toggleIcon=\"chevron-down-outline\"\n expandedIcon=\"chevron-up-outline\"\n class=\"dcf-sort-select\"\n (ionChange)=\"handleSortChange($event)\"\n interface=\"popover\"\n [value]=\"sortValue\"\n label-placement=\"floating\"\n fill=\"outline\"\n [label]=\"locale + '.sort' | translate\"\n >\n @for(sort of sortBy; track sort) {\n\n <ion-select-option [value]=\"sort\">{{ sort | translate }}</ion-select-option>\n }\n </ion-select>\n </div>\n <div class=\"dcf-width-auto\">\n <ion-button (click)=\"handleSortDirectionChange()\" fill=\"clear\">\n <ion-icon aria-hidden=\"true\" slot=\"icon-only\" [color]=\"!isDarkMode ? 'primary' : 'light'\" [name]=\"sortDirection === 'desc' ? 'arrow-down-outline' : 'arrow-up-outline'\"></ion-icon>\n </ion-button>\n </div>\n </div>\n </div>\n }\n</div>\n\n\n", styles: [".dcf-filter-component{padding:0 .5rem;margin-top:.75rem;margin-bottom:.75rem}.dcf-filter-component:not(.dcf-palette-dark) .dcf-filter{border:1px solid var(--dcf-color-gray-3);background-color:#fff}.dcf-filter-component:not(.dcf-palette-dark) .dcf-filter:focus-within{border-color:var(--dcf-color-primary);background-color:#fff}.dcf-filter-component:not(.dcf-palette-dark) ion-chip{border:1px solid var(--dcf-color-gray-3);color:var(--dcf-color-gray-7)}.dcf-filter-component:not(.dcf-palette-dark) ion-chip.dcf-filter-value{background:var(--dcf-color-gray-2);border-color:var(--dcf-color-gray-4)!important;color:var(--dcf-color-gray-8)!important}.dcf-filter-component:not(.dcf-palette-dark) .dcf-input input{color:var(--dcf-color-gray-7)}.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown{background-color:#fff}.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown.dcf-active{border:1px solid var(--dcf-color-gray-2)}.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown.dcf-active>div>div{color:var(--dcf-color-gray-8)}.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown.dcf-active>div>div.dcf-filtering-item,.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown.dcf-active>div>div:only-child{border-color:var(--dcf-color-gray-3)}.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown.dcf-active>div>div.dcf-filtering-item.dcf-empty,.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown.dcf-active>div>div:only-child.dcf-empty{pointer-events:none;touch-action:none;cursor:text!important;border-color:transparent!important}.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown.dcf-active>div>div:hover{background-color:var(--dcf-color-gray-1)}.dcf-filter-component.dcf-palette-dark .dcf-filter{border:1px solid var(--dcf-color-step-500)}.dcf-filter-component.dcf-palette-dark .dcf-filter ::-webkit-input-placeholder,.dcf-filter-component.dcf-palette-dark .dcf-filter ::placeholder{color:var(--dcf-color-gray-4)!important}.dcf-filter-component.dcf-palette-dark .dcf-filter:hover{border-color:var(--dcf-color-gray-2)}.dcf-filter-component.dcf-palette-dark .dcf-filter:focus-within{border-color:var(--dcf-color-gray-2)}.dcf-filter-component.dcf-palette-dark ion-chip{border-color:var(--dcf-color-step-300);background:rgba(var(--dcf-color-medium-rgb),.1)}.dcf-filter-component.dcf-palette-dark ion-chip.dcf-filter-value{background:rgba(var(--dcf-color-medium-rgb),.3)!important;border-color:var(--dcf-color-step-500)}.dcf-filter-component.dcf-palette-dark .dcf-input input{color:var(--dcf-color-gray-1)}.dcf-filter-component.dcf-palette-dark .dcf-dropdown{background-color:var(--dcf-item-background)}.dcf-filter-component.dcf-palette-dark .dcf-dropdown.dcf-active{border:1px solid var(--dcf-color-step-600)}.dcf-filter-component.dcf-palette-dark .dcf-dropdown.dcf-active>div>div{color:var(--dcf-color-gray-1)}.dcf-filter-component.dcf-palette-dark .dcf-dropdown.dcf-active>div>div.dcf-filtering-item,.dcf-filter-component.dcf-palette-dark .dcf-dropdown.dcf-active>div>div:only-child{border-color:var(--dcf-color-gray-5)}.dcf-filter-component.dcf-palette-dark .dcf-dropdown.dcf-active>div>div.dcf-filtering-item.dcf-empty,.dcf-filter-component.dcf-palette-dark .dcf-dropdown.dcf-active>div>div:only-child.dcf-empty{cursor:text!important;pointer-events:none;touch-action:none;border-color:transparent!important}.dcf-filter-component.dcf-palette-dark .dcf-dropdown.dcf-active>div>div:hover{background-color:var(--dcf-color-gray-8)}ion-select{min-height:44px!important}.dcf-hidden{display:none!important}.dcf-filter{display:flex;width:100%;min-height:40px;box-shadow:0 1px 2px #0a0d120d;border-radius:var(--dcf-border-radius);box-sizing:border-box}.dcf-filter ion-chip{border-radius:6px;padding:0 8px!important;height:24px;min-height:24px;font-size:.75rem;font-style:normal;font-weight:500;flex-shrink:0;margin-right:2px;white-space:nowrap}.dcf-filter ion-chip.sc-ion-chip-md-h,.dcf-filter ion-chip.sc-ion-chip-ios-h{height:24px;min-height:24px}.dcf-filter ion-chip.sc-ion-chip-md-h .chip-native,.dcf-filter ion-chip.sc-ion-chip-ios-h .chip-native{padding:0 8px!important;height:24px;min-height:24px}.dcf-filter ion-chip ion-label{padding:0 4px;margin:0;font-size:.75rem;white-space:nowrap}.dcf-filter ion-chip ion-icon{margin:0 2px;font-size:.75rem}.dcf-filter .dcf-input{width:100%;display:flex;align-items:center;overflow-x:auto;overflow-y:hidden;white-space:nowrap;padding-left:.5rem}.dcf-filter .dcf-input input{min-height:40px;min-width:100px;width:100%;font-size:1rem;border:none;outline:none;background:transparent;border:0px!important;outline:none!important}.dcf-filter .dcf-input input:focus{border:0px!important;outline:none!important}.dcf-filter .dcf-icon-clear,.dcf-filter .dcf-icon-search{display:flex;justify-content:center;text-align:center;align-items:center;min-width:40px}.dcf-filter .dcf-icon-search ion-icon{font-size:1.25rem}.dcf-sort-container{min-width:200px!important;width:auto}@media (min-width: 990px){.dcf-sort-container{max-width:20%!important}}@media (max-width: 680px){.dcf-sort-container{min-width:100%!important;margin:.75rem 0rem}}.dcf-dropdown{position:absolute;max-height:200px;overflow-y:auto;border-radius:4px;z-index:1000!important;min-width:200px;max-width:300px;display:none}.dcf-dropdown.dcf-active{display:block;margin-top:-3px;box-shadow:0 12px 16px -4px #0a0d1214,0 4px 6px -2px #0a0d1208,0 2px 2px -1px #0a0d120a!important;border-radius:var(--dcf-border-radius);padding:.5rem .25rem}@media (max-width: 768px){.dcf-dropdown.dcf-active{margin-top:55px}}.dcf-dropdown.dcf-active>div>div{cursor:pointer;height:35px;padding:.5rem 1rem;border:1px solid transparent;font-size:1rem;display:flex;align-items:center;border-radius:6px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: IonChip, selector: "ion-chip", inputs: ["color", "disabled", "mode", "outline"] }, { 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: "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: 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: "pipe", type: TranslatePipe, name: "translate" }] }); }
8003
8650
  };
8004
8651
  FilterComponent = __decorate([
8005
8652
  Dynamic(),
@@ -8017,7 +8664,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
8017
8664
  IonSelectOption,
8018
8665
  IonIcon,
8019
8666
  SearchbarComponent
8020
- ], standalone: true, host: { '[attr.id]': 'uid' }, template: "\n@if (!indexes.length) {\n <ngx-decaf-searchbar [emitEventToWindow]=\"false\" [debounce]=\"500\" (searchEvent)=\"handleSearch($event)\" />\n}\n\n<div [id]=\"uid\" class=\"dcf-grid dcf-grid-small dcf-grid-match dcf-filter-component\" [class.dcf-hidden]=\"!indexes.length\" #component>\n <div class=\"dcf-width-expand\">\n <div class=\"dcf-filter\">\n <div class=\"dcf-input\">\n @for(filter of filterValue; track trackItemFn($index, filter?.['index'])) {\n @if (filter?.['index']) {\n <ion-chip [outline]=\"true\">{{ filter?.['index'] }}</ion-chip>\n }\n @if (filter?.['condition']) {\n <ion-chip [outline]=\"true\">{{ filter?.['condition'] }}</ion-chip>\n }\n @if (filter?.['value']) {\n <ion-chip [outline]=\"true\" class=\"dcf-filter-value\">\n {{ filter?.['value'] }}\n <ion-icon name=\"close-outline\" (click)=\"removeFilter(filter?.['value'])\" size=\"small\"></ion-icon>\n </ion-chip>\n }\n }\n <div class=\"dcf-width-1-1\">\n <!-- [readonly]=\"step !== 3\" -->\n <input\n fill=\"none\"\n [(ngModel)]=\"value\"\n (keydown.enter)=\"addFilter(value, $event)\"\n (keydown.backspace)=\"clear(value)\"\n (input)=\"handleInput($event)\"\n (click)=\"handleFocus()\"\n (blur)=\"handleBlur()\"\n type=\"text\"\n id=\"dcf-filter-field\"\n placeholder=\"{{ locale + (step === 3 ? '.type' : '.select') | translate }}\"\n\n />\n @if (windowWidth >= 768) {\n <div [class]=\"'dcf-dropdown ' + (options.length > 0 ? ' dcf-active' : '')\" #optionsFilterElement>\n <div>\n @if (filteredOptions.length > 0) {\n @for(key of filteredOptions; track key) {\n <div\n class=\"dcf-item\"\n tabindex=\"0\"\n (keydown.enter)=\"selectOption(key)\"\n (click)=\"selectOption(key)\">\n {{ key }}\n </div>\n }\n } @else {\n <div class=\"dcf-empty\"\n (click)=\"filteredOptions = options; value = ''\"\n tabindex=\"0\"\n (keydown.enter)=\"filteredOptions = options; value = ''\"\n >\n {{ locale + '.no_suggestions' | translate }}\n </div>\n }\n </div>\n </div>\n }\n </div>\n </div>\n @if (filterValue.length > 0) {\n <div class=\"dcf-icon-clear\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"clear()\">\n <ion-icon name=\"trash-outline\" [color]=\"!isDarkMode ? 'dark' : 'light'\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n }\n <div class=\"dcf-icon-search\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"submit()\">\n <ion-icon name=\"search-outline\" [color]=\"!isDarkMode ? 'dark' : 'light'\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n </div>\n @if (windowWidth < 768) {\n <div [class]=\"'dcf-dropdown ' + (options.length > 0 ? ' dcf-active' : '')\" #optionsFilterElement>\n <div>\n @if (filteredOptions.length > 0) {\n @for(key of filteredOptions; track key) {\n <div\n class=\"dcf-item\"\n tabindex=\"0\"\n (keydown.enter)=\"selectOption(key)\"\n (click)=\"selectOption(key)\">\n {{ key }}\n </div>\n }\n } @else {\n <div class=\"dcf-empty\"\n (click)=\"filteredOptions = options; value = ''\"\n tabindex=\"0\"\n (keydown.enter)=\"filteredOptions = options; value = ''\"\n >\n {{ locale + '.no_suggestions' | translate }}\n </div>\n }\n </div>\n </div>\n }\n </div>\n @if (!disableSort) {\n <div class=\"dcf-width-1-5@m dcf-width-1-1 dcf-sort-container\">\n <div class=\"dcf-grid dcf-grid-collapse dcf-flex dcf-flex-middle dcf-grid-match\">\n <div class=\"dcf-width-expand\">\n <ion-select\n toggleIcon=\"chevron-down-outline\"\n expandedIcon=\"chevron-up-outline\"\n class=\"dcf-sort-select\"\n (ionChange)=\"handleSortChange($event)\"\n interface=\"popover\"\n [value]=\"sortValue\"\n label-placement=\"floating\"\n fill=\"outline\"\n [label]=\"locale + '.sort' | translate\"\n >\n @for(sort of sortBy; track sort) {\n\n <ion-select-option [value]=\"sort\">{{ sort | translate }}</ion-select-option>\n }\n </ion-select>\n </div>\n <div class=\"dcf-width-auto\">\n <ion-button (click)=\"handleSortDirectionChange()\" fill=\"clear\">\n <ion-icon slot=\"icon-only\" [color]=\"!isDarkMode ? 'primary' : 'light'\" [name]=\"sortDirection === 'desc' ? 'arrow-down-outline' : 'arrow-up-outline'\"></ion-icon>\n </ion-button>\n </div>\n </div>\n </div>\n }\n</div>\n\n\n", styles: [".dcf-filter-component{padding:0 .5rem;margin-top:.75rem;margin-bottom:.75rem}.dcf-filter-component:not(.dcf-palette-dark) .dcf-filter{border:1px solid var(--dcf-color-gray-3);background-color:#fff}.dcf-filter-component:not(.dcf-palette-dark) .dcf-filter:focus-within{border-color:var(--dcf-color-primary);background-color:#fff}.dcf-filter-component:not(.dcf-palette-dark) ion-chip{border:1px solid var(--dcf-color-gray-3);color:var(--dcf-color-gray-7)}.dcf-filter-component:not(.dcf-palette-dark) ion-chip.dcf-filter-value{background:var(--dcf-color-gray-2);border-color:var(--dcf-color-gray-4)!important;color:var(--dcf-color-gray-8)!important}.dcf-filter-component:not(.dcf-palette-dark) .dcf-input input{color:var(--dcf-color-gray-7)}.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown{background-color:#fff}.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown.dcf-active{border:1px solid var(--dcf-color-gray-2)}.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown.dcf-active>div>div{color:var(--dcf-color-gray-8)}.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown.dcf-active>div>div.dcf-filtering-item,.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown.dcf-active>div>div:only-child{border-color:var(--dcf-color-gray-3)}.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown.dcf-active>div>div.dcf-filtering-item.dcf-empty,.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown.dcf-active>div>div:only-child.dcf-empty{pointer-events:none;touch-action:none;cursor:text!important;border-color:transparent!important}.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown.dcf-active>div>div:hover{background-color:var(--dcf-color-gray-1)}.dcf-filter-component.dcf-palette-dark .dcf-filter{border:1px solid var(--dcf-color-step-500)}.dcf-filter-component.dcf-palette-dark .dcf-filter ::-webkit-input-placeholder,.dcf-filter-component.dcf-palette-dark .dcf-filter ::placeholder{color:var(--dcf-color-gray-4)!important}.dcf-filter-component.dcf-palette-dark .dcf-filter:hover{border-color:var(--dcf-color-gray-2)}.dcf-filter-component.dcf-palette-dark .dcf-filter:focus-within{border-color:var(--dcf-color-gray-2)}.dcf-filter-component.dcf-palette-dark ion-chip{border-color:var(--dcf-color-step-300);background:rgba(var(--dcf-color-medium-rgb),.1)}.dcf-filter-component.dcf-palette-dark ion-chip.dcf-filter-value{background:rgba(var(--dcf-color-medium-rgb),.3)!important;border-color:var(--dcf-color-step-500)}.dcf-filter-component.dcf-palette-dark .dcf-input input{color:var(--dcf-color-gray-1)}.dcf-filter-component.dcf-palette-dark .dcf-dropdown{background-color:var(--dcf-item-background)}.dcf-filter-component.dcf-palette-dark .dcf-dropdown.dcf-active{border:1px solid var(--dcf-color-step-600)}.dcf-filter-component.dcf-palette-dark .dcf-dropdown.dcf-active>div>div{color:var(--dcf-color-gray-1)}.dcf-filter-component.dcf-palette-dark .dcf-dropdown.dcf-active>div>div.dcf-filtering-item,.dcf-filter-component.dcf-palette-dark .dcf-dropdown.dcf-active>div>div:only-child{border-color:var(--dcf-color-gray-5)}.dcf-filter-component.dcf-palette-dark .dcf-dropdown.dcf-active>div>div.dcf-filtering-item.dcf-empty,.dcf-filter-component.dcf-palette-dark .dcf-dropdown.dcf-active>div>div:only-child.dcf-empty{cursor:text!important;pointer-events:none;touch-action:none;border-color:transparent!important}.dcf-filter-component.dcf-palette-dark .dcf-dropdown.dcf-active>div>div:hover{background-color:var(--dcf-color-gray-8)}ion-select{min-height:44px!important}.dcf-hidden{display:none!important}.dcf-filter{display:flex;width:100%;min-height:40px;box-shadow:0 1px 2px #0a0d120d;border-radius:var(--dcf-border-radius);box-sizing:border-box}.dcf-filter ion-chip{border-radius:6px;padding:0 8px!important;height:24px;min-height:24px;font-size:.75rem;font-style:normal;font-weight:500;flex-shrink:0;margin-right:2px;white-space:nowrap}.dcf-filter ion-chip.sc-ion-chip-md-h,.dcf-filter ion-chip.sc-ion-chip-ios-h{height:24px;min-height:24px}.dcf-filter ion-chip.sc-ion-chip-md-h .chip-native,.dcf-filter ion-chip.sc-ion-chip-ios-h .chip-native{padding:0 8px!important;height:24px;min-height:24px}.dcf-filter ion-chip ion-label{padding:0 4px;margin:0;font-size:.75rem;white-space:nowrap}.dcf-filter ion-chip ion-icon{margin:0 2px;font-size:.75rem}.dcf-filter .dcf-input{width:100%;display:flex;align-items:center;overflow-x:auto;overflow-y:hidden;white-space:nowrap;padding-left:.5rem}.dcf-filter .dcf-input input{min-height:40px;min-width:100px;width:100%;font-size:1rem;border:none;outline:none;background:transparent;border:0px!important;outline:none!important}.dcf-filter .dcf-input input:focus{border:0px!important;outline:none!important}.dcf-filter .dcf-icon-clear,.dcf-filter .dcf-icon-search{display:flex;justify-content:center;text-align:center;align-items:center;min-width:40px}.dcf-filter .dcf-icon-search ion-icon{font-size:1.25rem}.dcf-sort-container{min-width:200px!important;width:auto}@media (min-width: 990px){.dcf-sort-container{max-width:20%!important}}@media (max-width: 680px){.dcf-sort-container{min-width:100%!important;margin:.75rem 0rem}}.dcf-dropdown{position:absolute;max-height:200px;overflow-y:auto;border-radius:4px;z-index:1000!important;min-width:200px;max-width:300px;display:none}.dcf-dropdown.dcf-active{display:block;margin-top:-3px;box-shadow:0 12px 16px -4px #0a0d1214,0 4px 6px -2px #0a0d1208,0 2px 2px -1px #0a0d120a!important;border-radius:var(--dcf-border-radius);padding:.5rem .25rem}@media (max-width: 768px){.dcf-dropdown.dcf-active{margin-top:55px}}.dcf-dropdown.dcf-active>div>div{cursor:pointer;height:35px;padding:.5rem 1rem;border:1px solid transparent;font-size:1rem;display:flex;align-items:center;border-radius:6px}\n"] }]
8667
+ ], standalone: true, host: { '[attr.id]': 'uid' }, template: "\n@if (!indexes.length) {\n <ngx-decaf-searchbar [emitEventToWindow]=\"false\" [debounce]=\"500\" (searchEvent)=\"handleSearch($event)\" />\n}\n\n<div [id]=\"uid\" class=\"dcf-grid dcf-grid-small dcf-grid-match dcf-filter-component\" [class.dcf-hidden]=\"!indexes.length\" #component>\n <div class=\"dcf-width-expand\">\n <div class=\"dcf-filter\">\n <div class=\"dcf-input\">\n @for(filter of filterValue; track trackItemFn($index, filter?.['index'])) {\n @if (filter?.['index']) {\n <ion-chip [outline]=\"true\">{{ filter?.['index'] }}</ion-chip>\n }\n @if (filter?.['condition']) {\n <ion-chip [outline]=\"true\">{{ filter?.['condition'] }}</ion-chip>\n }\n @if (filter?.['value']) {\n <ion-chip [outline]=\"true\" class=\"dcf-filter-value\">\n {{ filter?.['value'] }}\n <ion-icon tabindex=\"0\" name=\"close-outline\" (click)=\"removeFilter(filter?.['value'])\" size=\"small\"></ion-icon>\n </ion-chip>\n }\n }\n <div class=\"dcf-width-1-1\">\n <!-- [readonly]=\"step !== 3\" -->\n <input\n fill=\"none\"\n [(ngModel)]=\"value\"\n (keydown.enter)=\"addFilter(value, $event)\"\n (keydown.backspace)=\"clear(value)\"\n (input)=\"handleInput($event)\"\n (click)=\"handleFocus()\"\n (blur)=\"handleBlur()\"\n type=\"text\"\n id=\"dcf-filter-field\"\n placeholder=\"{{ locale + (step === 3 ? '.type' : '.select') | translate }}\"\n\n />\n @if (windowWidth >= 768) {\n <div [class]=\"'dcf-dropdown ' + (options.length > 0 ? ' dcf-active' : '')\" #optionsFilterElement>\n <div>\n @if (filteredOptions.length > 0) {\n @for(key of filteredOptions; track key) {\n <div\n class=\"dcf-item\"\n tabindex=\"0\"\n (keydown.enter)=\"selectOption(key)\"\n (click)=\"selectOption(key)\">\n {{ key }}\n </div>\n }\n } @else {\n <div class=\"dcf-empty\"\n (click)=\"filteredOptions = options; value = ''\"\n tabindex=\"0\"\n (keydown.enter)=\"filteredOptions = options; value = ''\"\n >\n {{ locale + '.no_suggestions' | translate }}\n </div>\n }\n </div>\n </div>\n }\n </div>\n </div>\n @if (filterValue.length > 0) {\n <div class=\"dcf-icon-clear\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"clear()\">\n <ion-icon aria-hidden=\"true\" name=\"trash-outline\" [color]=\"!isDarkMode ? 'dark' : 'light'\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n }\n <div class=\"dcf-icon-search\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"submit()\">\n <ion-icon aria-hidden=\"true\" name=\"search-outline\" [color]=\"!isDarkMode ? 'dark' : 'light'\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n </div>\n @if (windowWidth < 768) {\n <div [class]=\"'dcf-dropdown ' + (options.length > 0 ? ' dcf-active' : '')\" #optionsFilterElement>\n <div>\n @if (filteredOptions.length > 0) {\n @for(key of filteredOptions; track key) {\n <div\n class=\"dcf-item\"\n tabindex=\"0\"\n (keydown.enter)=\"selectOption(key)\"\n (click)=\"selectOption(key)\">\n {{ key }}\n </div>\n }\n } @else {\n <div class=\"dcf-empty\"\n (click)=\"filteredOptions = options; value = ''\"\n tabindex=\"0\"\n (keydown.enter)=\"filteredOptions = options; value = ''\"\n >\n {{ locale + '.no_suggestions' | translate }}\n </div>\n }\n </div>\n </div>\n }\n </div>\n @if (!disableSort) {\n <div class=\"dcf-width-1-5@m dcf-width-1-1 dcf-sort-container\">\n <div class=\"dcf-grid dcf-grid-collapse dcf-flex dcf-flex-middle dcf-grid-match\">\n <div class=\"dcf-width-expand\">\n <ion-select\n toggleIcon=\"chevron-down-outline\"\n expandedIcon=\"chevron-up-outline\"\n class=\"dcf-sort-select\"\n (ionChange)=\"handleSortChange($event)\"\n interface=\"popover\"\n [value]=\"sortValue\"\n label-placement=\"floating\"\n fill=\"outline\"\n [label]=\"locale + '.sort' | translate\"\n >\n @for(sort of sortBy; track sort) {\n\n <ion-select-option [value]=\"sort\">{{ sort | translate }}</ion-select-option>\n }\n </ion-select>\n </div>\n <div class=\"dcf-width-auto\">\n <ion-button (click)=\"handleSortDirectionChange()\" fill=\"clear\">\n <ion-icon aria-hidden=\"true\" slot=\"icon-only\" [color]=\"!isDarkMode ? 'primary' : 'light'\" [name]=\"sortDirection === 'desc' ? 'arrow-down-outline' : 'arrow-up-outline'\"></ion-icon>\n </ion-button>\n </div>\n </div>\n </div>\n }\n</div>\n\n\n", styles: [".dcf-filter-component{padding:0 .5rem;margin-top:.75rem;margin-bottom:.75rem}.dcf-filter-component:not(.dcf-palette-dark) .dcf-filter{border:1px solid var(--dcf-color-gray-3);background-color:#fff}.dcf-filter-component:not(.dcf-palette-dark) .dcf-filter:focus-within{border-color:var(--dcf-color-primary);background-color:#fff}.dcf-filter-component:not(.dcf-palette-dark) ion-chip{border:1px solid var(--dcf-color-gray-3);color:var(--dcf-color-gray-7)}.dcf-filter-component:not(.dcf-palette-dark) ion-chip.dcf-filter-value{background:var(--dcf-color-gray-2);border-color:var(--dcf-color-gray-4)!important;color:var(--dcf-color-gray-8)!important}.dcf-filter-component:not(.dcf-palette-dark) .dcf-input input{color:var(--dcf-color-gray-7)}.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown{background-color:#fff}.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown.dcf-active{border:1px solid var(--dcf-color-gray-2)}.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown.dcf-active>div>div{color:var(--dcf-color-gray-8)}.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown.dcf-active>div>div.dcf-filtering-item,.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown.dcf-active>div>div:only-child{border-color:var(--dcf-color-gray-3)}.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown.dcf-active>div>div.dcf-filtering-item.dcf-empty,.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown.dcf-active>div>div:only-child.dcf-empty{pointer-events:none;touch-action:none;cursor:text!important;border-color:transparent!important}.dcf-filter-component:not(.dcf-palette-dark) .dcf-dropdown.dcf-active>div>div:hover{background-color:var(--dcf-color-gray-1)}.dcf-filter-component.dcf-palette-dark .dcf-filter{border:1px solid var(--dcf-color-step-500)}.dcf-filter-component.dcf-palette-dark .dcf-filter ::-webkit-input-placeholder,.dcf-filter-component.dcf-palette-dark .dcf-filter ::placeholder{color:var(--dcf-color-gray-4)!important}.dcf-filter-component.dcf-palette-dark .dcf-filter:hover{border-color:var(--dcf-color-gray-2)}.dcf-filter-component.dcf-palette-dark .dcf-filter:focus-within{border-color:var(--dcf-color-gray-2)}.dcf-filter-component.dcf-palette-dark ion-chip{border-color:var(--dcf-color-step-300);background:rgba(var(--dcf-color-medium-rgb),.1)}.dcf-filter-component.dcf-palette-dark ion-chip.dcf-filter-value{background:rgba(var(--dcf-color-medium-rgb),.3)!important;border-color:var(--dcf-color-step-500)}.dcf-filter-component.dcf-palette-dark .dcf-input input{color:var(--dcf-color-gray-1)}.dcf-filter-component.dcf-palette-dark .dcf-dropdown{background-color:var(--dcf-item-background)}.dcf-filter-component.dcf-palette-dark .dcf-dropdown.dcf-active{border:1px solid var(--dcf-color-step-600)}.dcf-filter-component.dcf-palette-dark .dcf-dropdown.dcf-active>div>div{color:var(--dcf-color-gray-1)}.dcf-filter-component.dcf-palette-dark .dcf-dropdown.dcf-active>div>div.dcf-filtering-item,.dcf-filter-component.dcf-palette-dark .dcf-dropdown.dcf-active>div>div:only-child{border-color:var(--dcf-color-gray-5)}.dcf-filter-component.dcf-palette-dark .dcf-dropdown.dcf-active>div>div.dcf-filtering-item.dcf-empty,.dcf-filter-component.dcf-palette-dark .dcf-dropdown.dcf-active>div>div:only-child.dcf-empty{cursor:text!important;pointer-events:none;touch-action:none;border-color:transparent!important}.dcf-filter-component.dcf-palette-dark .dcf-dropdown.dcf-active>div>div:hover{background-color:var(--dcf-color-gray-8)}ion-select{min-height:44px!important}.dcf-hidden{display:none!important}.dcf-filter{display:flex;width:100%;min-height:40px;box-shadow:0 1px 2px #0a0d120d;border-radius:var(--dcf-border-radius);box-sizing:border-box}.dcf-filter ion-chip{border-radius:6px;padding:0 8px!important;height:24px;min-height:24px;font-size:.75rem;font-style:normal;font-weight:500;flex-shrink:0;margin-right:2px;white-space:nowrap}.dcf-filter ion-chip.sc-ion-chip-md-h,.dcf-filter ion-chip.sc-ion-chip-ios-h{height:24px;min-height:24px}.dcf-filter ion-chip.sc-ion-chip-md-h .chip-native,.dcf-filter ion-chip.sc-ion-chip-ios-h .chip-native{padding:0 8px!important;height:24px;min-height:24px}.dcf-filter ion-chip ion-label{padding:0 4px;margin:0;font-size:.75rem;white-space:nowrap}.dcf-filter ion-chip ion-icon{margin:0 2px;font-size:.75rem}.dcf-filter .dcf-input{width:100%;display:flex;align-items:center;overflow-x:auto;overflow-y:hidden;white-space:nowrap;padding-left:.5rem}.dcf-filter .dcf-input input{min-height:40px;min-width:100px;width:100%;font-size:1rem;border:none;outline:none;background:transparent;border:0px!important;outline:none!important}.dcf-filter .dcf-input input:focus{border:0px!important;outline:none!important}.dcf-filter .dcf-icon-clear,.dcf-filter .dcf-icon-search{display:flex;justify-content:center;text-align:center;align-items:center;min-width:40px}.dcf-filter .dcf-icon-search ion-icon{font-size:1.25rem}.dcf-sort-container{min-width:200px!important;width:auto}@media (min-width: 990px){.dcf-sort-container{max-width:20%!important}}@media (max-width: 680px){.dcf-sort-container{min-width:100%!important;margin:.75rem 0rem}}.dcf-dropdown{position:absolute;max-height:200px;overflow-y:auto;border-radius:4px;z-index:1000!important;min-width:200px;max-width:300px;display:none}.dcf-dropdown.dcf-active{display:block;margin-top:-3px;box-shadow:0 12px 16px -4px #0a0d1214,0 4px 6px -2px #0a0d1208,0 2px 2px -1px #0a0d120a!important;border-radius:var(--dcf-border-radius);padding:.5rem .25rem}@media (max-width: 768px){.dcf-dropdown.dcf-active{margin-top:55px}}.dcf-dropdown.dcf-active>div>div{cursor:pointer;height:35px;padding:.5rem 1rem;border:1px solid transparent;font-size:1rem;display:flex;align-items:center;border-radius:6px}\n"] }]
8021
8668
  }], ctorParameters: () => [], propDecorators: { optionsFilterElement: [{
8022
8669
  type: ViewChild,
8023
8670
  args: ['optionsFilterElement', { read: ElementRef, static: false }]
@@ -8170,7 +8817,7 @@ class PaginationComponent extends NgxComponentDirective {
8170
8817
  if (page)
8171
8818
  this.current = page;
8172
8819
  this.clickEvent.emit({
8173
- name: EventConstants.CLICK,
8820
+ name: ComponentEventNames.CLICK,
8174
8821
  data: {
8175
8822
  direction,
8176
8823
  page: this.current
@@ -8745,11 +9392,11 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
8745
9392
  this.item['tag'] = ComponentsTagNames.LIST_ITEM;
8746
9393
  this.empty = Object.assign({}, DefaultListEmptyOptions, this.empty);
8747
9394
  await this.refresh();
8748
- // if (this.operations.includes(OperationKeys.CREATE) && this.route)
8749
- // this.empty.link = `${this.route}/${OperationKeys.CREATE}`;
8750
9395
  if (!this.initialized)
8751
- return this.parseProps(this);
9396
+ this.parseProps(this);
8752
9397
  this.initialized = true;
9398
+ if (this.isModalChild)
9399
+ this.changeDetectorRef.detectChanges();
8753
9400
  }
8754
9401
  /**
8755
9402
  * @description Cleans up resources when the component is destroyed.
@@ -8926,6 +9573,8 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
8926
9573
  this.page = 1;
8927
9574
  }
8928
9575
  this.searchValue = value;
9576
+ if (this.isModalChild)
9577
+ this.changeDetectorRef.detectChanges();
8929
9578
  await this.refresh(true);
8930
9579
  }
8931
9580
  else {
@@ -8959,6 +9608,8 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
8959
9608
  */
8960
9609
  async clearSearch() {
8961
9610
  await this.handleSearch(undefined);
9611
+ if (this.isModalChild)
9612
+ this.changeDetectorRef.detectChanges();
8962
9613
  }
8963
9614
  /**
8964
9615
  * @description Emits a refresh event with the current data.
@@ -8975,7 +9626,7 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
8975
9626
  data = this.items;
8976
9627
  this.skeletonData = new Array(data?.length || 2);
8977
9628
  this.refreshEvent.emit({
8978
- name: EventConstants.REFRESH,
9629
+ name: ComponentEventNames.REFRESH,
8979
9630
  data: data || [],
8980
9631
  component: this.componentName
8981
9632
  });
@@ -9046,7 +9697,7 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
9046
9697
  * @memberOf ListComponent
9047
9698
  */
9048
9699
  async refresh(event = false) {
9049
- // if (typeof force !== 'boolean' && force.type === EventConstants.BACK_BUTTON_NAVIGATION) {
9700
+ // if (typeof force !== 'boolean' && force.type === ComponentEventNames.BACK_BUTTON_NAVIGATION) {
9050
9701
  // const {refresh} = (force as CustomEvent).detail;
9051
9702
  // if (!refresh)
9052
9703
  // return false;
@@ -9057,7 +9708,6 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
9057
9708
  this.data = !this.model ?
9058
9709
  await this.getFromRequest(!!event, start, limit)
9059
9710
  : await this.getFromModel(!!event);
9060
- this.refreshEventEmit();
9061
9711
  if (this.type === ListComponentsTypes.INFINITE) {
9062
9712
  if (this.page === this.pages) {
9063
9713
  if (event?.target)
@@ -9068,7 +9718,7 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
9068
9718
  this.page += 1;
9069
9719
  this.refreshing = false;
9070
9720
  setTimeout(() => {
9071
- if (event?.target && event?.type !== EventConstants.BACK_BUTTON_NAVIGATION)
9721
+ if (event?.target && event?.type !== ComponentEventNames.BACK_BUTTON_NAVIGATION)
9072
9722
  event.target.complete();
9073
9723
  }, 200);
9074
9724
  }
@@ -9127,7 +9777,11 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
9127
9777
  * @memberOf ListComponent
9128
9778
  */
9129
9779
  parseSearchResults(results, search) {
9130
- return results.filter((item) => Object.values(item).some(value => value.toString().toLowerCase().includes(search?.toLowerCase())));
9780
+ const filtered = results.filter((item) => Object.values(item).some(v => {
9781
+ if (v.toString().toLowerCase().includes(search?.toLowerCase()))
9782
+ return v;
9783
+ }));
9784
+ return filtered;
9131
9785
  }
9132
9786
  /**
9133
9787
  * @description Fetches data from a request source.
@@ -9143,7 +9797,7 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
9143
9797
  * @memberOf ListComponent
9144
9798
  */
9145
9799
  async getFromRequest(force = false, start, limit) {
9146
- let request = [];
9800
+ let data = [...this.data || []];
9147
9801
  if (!this.data?.length || force || this.searchValue?.length || !!this.searchValue) {
9148
9802
  // (self.data as ListItem[]) = [];
9149
9803
  if (!this.searchValue?.length && !this.searchValue) {
@@ -9151,20 +9805,31 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
9151
9805
  this.logger.info('No data and source passed to infinite list');
9152
9806
  return [];
9153
9807
  }
9154
- if (this.source instanceof Function)
9155
- request = await this.source();
9156
- if (!Array.isArray(request))
9157
- request = request?.['response']?.['data'] || request?.['results'] || [];
9158
- this.data = [...await this.parseResult(request)];
9808
+ if (this.source instanceof Function) {
9809
+ data = await this.source();
9810
+ if (!Array.isArray(data))
9811
+ data = data?.['response']?.['data'] || data?.['results'] || [];
9812
+ }
9813
+ if (!data?.length && this.data?.length)
9814
+ data = this.data;
9815
+ this.data = [...await this.parseResult(data)];
9159
9816
  if (this.data?.length)
9160
9817
  this.items = this.type === ListComponentsTypes.INFINITE ?
9161
- (this.items || []).concat([...this.data.slice(start, limit)]) : [...request.slice(start, limit)];
9818
+ (this.items || []).concat([...this.data.slice(start, limit)]) : [...data.slice(start, limit)];
9162
9819
  }
9163
9820
  else {
9164
- this.data = this.parseSearchResults(this.data, this.searchValue);
9165
- this.items = this.data;
9821
+ const data = await this.parseResult(this.parseSearchResults(this.data, this.searchValue));
9822
+ this.items = [...data];
9823
+ if (this.isModalChild)
9824
+ this.changeDetectorRef.detectChanges();
9166
9825
  }
9167
9826
  }
9827
+ else {
9828
+ const data = [...await this.parseResult(this.data)];
9829
+ this.items = this.type === ListComponentsTypes.INFINITE ? [...(this.items || []), ...(data || [])] : [...(data || [])];
9830
+ if (this.isModalChild)
9831
+ this.changeDetectorRef.detectChanges();
9832
+ }
9168
9833
  if (this.loadMoreData && this.type === ListComponentsTypes.PAGINATED)
9169
9834
  this.getMoreData(this.data?.length || 0);
9170
9835
  return this.data || [];
@@ -9457,7 +10122,7 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
9457
10122
  return (searchValue?.query).map(item => `${item.index} ${item.condition} ${item.value}`).join(", ");
9458
10123
  }
9459
10124
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: ListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
9460
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", 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)" }, properties: { "attr.id": "uid" } }, 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 className=\"dcf-empty-data\"\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 className=\"dcf-empty-data\"\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", "children", "projectable", "parent"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
10125
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", 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)" }, properties: { "attr.id": "uid" } }, usesInheritance: true, ngImport: i0, template: "<div #component>\n\n</div>\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 (initialized && data?.length) {\n <ion-list [id]=\"uid\" [inset]=\"inset\" [lines]=\"lines\">\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 className=\"dcf-empty-data\"\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 className=\"dcf-empty-data\"\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", "children", "projectable", "parent"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
9461
10126
  };
9462
10127
  ListComponent = __decorate([
9463
10128
  Dynamic(),
@@ -9484,7 +10149,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
9484
10149
  EmptyStateComponent,
9485
10150
  FilterComponent,
9486
10151
  ComponentRendererComponent
9487
- ], host: { '[attr.id]': 'uid' }, 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 className=\"dcf-empty-data\"\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 className=\"dcf-empty-data\"\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"] }]
10152
+ ], host: { '[attr.id]': 'uid' }, template: "<div #component>\n\n</div>\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 (initialized && data?.length) {\n <ion-list [id]=\"uid\" [inset]=\"inset\" [lines]=\"lines\">\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 className=\"dcf-empty-data\"\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 className=\"dcf-empty-data\"\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"] }]
9488
10153
  }], ctorParameters: () => [], propDecorators: { type: [{
9489
10154
  type: Input
9490
10155
  }], showSearchbar: [{
@@ -9736,8 +10401,8 @@ let ListItemComponent = class ListItemComponent extends NgxComponentDirective {
9736
10401
  // forcing trap focus
9737
10402
  removeFocusTrap();
9738
10403
  if (!this.route) {
9739
- const event = { target: target, action, pk: this.pk, data: this.uid, name: EventConstants.CLICK, component: this.componentName };
9740
- windowEventEmitter(`ListItem${EventConstants.CLICK}`, event);
10404
+ const event = { target: target, action, pk: this.pk, data: this.uid, name: ComponentEventNames.CLICK, component: this.componentName };
10405
+ windowEventEmitter(`ListItem${ComponentEventNames.CLICK}`, event);
9741
10406
  return this.clickEvent.emit(event);
9742
10407
  }
9743
10408
  return await this.redirect(action, (typeof this.uid === 'number' ? `${this.uid}` : this.uid));
@@ -9872,7 +10537,7 @@ let ListItemComponent = class ListItemComponent extends NgxComponentDirective {
9872
10537
  this.actionMenuOpen = true;
9873
10538
  }
9874
10539
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: ListItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
9875
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: ListItemComponent, isStandalone: true, selector: "ngx-decaf-list-item", inputs: { lines: "lines", item: "item", icon: "icon", iconSlot: "iconSlot", button: "button", title: "title", description: "description", info: "info", subinfo: "subinfo" }, outputs: { clickEvent: "clickEvent" }, host: { listeners: { "window:resize": "enableSlideItems($event)" }, properties: { "attr.id": "uid" } }, viewQueries: [{ propertyName: "component", first: true, predicate: ["component"], descendants: true, read: ElementRef }, { propertyName: "actionMenuComponent", first: true, predicate: ["actionMenuComponent"], descendants: true }], usesInheritance: true, ngImport: i0, template: "\n@if (title || description) {\n <ion-item-sliding>\n <ion-item\n [id]=\"uid\"\n [lines]=\"lines\"\n [button]=\"button\"\n [class]=\"className\"\n (click)=\"operations?.includes('read') ? handleAction('read', $event, component) : ''\"\n #component\n >\n @if (icon && lines !== 'inset') {\n <div class=\"dcf-icon\" [slot]=\"iconSlot\">\n <ion-avatar>\n <ion-icon aria-hidden=\"true\" name=\"reader-outline\" size=\"default\"></ion-icon>\n </ion-avatar>\n </div>\n }\n <div class=\"dcf-width-expand\">\n <div class=\"dcf-flex dcf-flex-middle dcf-grid-collapse\" dcf-grid>\n @if (icon && lines === 'inset') {\n <div class=\"dcf-icon dcf-grid-icon\">\n <ion-avatar>\n <ion-icon aria-hidden=\"true\" name=\"reader-outline\" size=\"default\"></ion-icon>\n </ion-avatar>\n </div>\n }\n <div class=\"dcf-width-expand@s dcf-width-1-1 dcf-label\">\n @if (title) {\n <ion-label class=\"dcf-item-title\">\n {{ uid !== title ? (uid + ' - ' + title) : title }}\n </ion-label>\n }\n @if (description) {\n <div class=\"dcf-description\" [innerHTML]=\"description\"></div>\n }\n </div>\n @if (info || subinfo) {\n <div class=\"dcf-width-auto@s dcf-width-expand dcf-info dcf-flex dcf-flex-right@s\">\n <div>\n @if (info) {\n <span [innerHTML]=\"info\"></span>\n }\n @if (subinfo) {\n <div class=\"dcf-subinfo dcf-text-truncate\" [innerHTML]=\"subinfo\" ></div>\n }\n </div>\n </div>\n }\n\n <div class=\"dcf-width-auto dcf-flex dcf-flex-middle dcf-flex-right\">\n @if ((operations.includes('delete') || operations.includes('update')) && uid) {\n\n <div class=\"dcf-visible@s\" id=\"dcf-actions\">\n <ion-button class=\"\" shape=\"round\" fill=\"clear\" color=\"primary\" (click)=\"presentActionsMenu($event)\">\n <ion-icon slot=\"icon-only\" aria-hidden=\"true\" name=\"ellipsis-vertical-outline\"></ion-icon>\n </ion-button>\n <ion-popover\n #actionMenuComponent\n side=\"bottom\"\n alignment=\"left\"\n\n [isOpen]=\"actionMenuOpen\"\n (didDismiss)=\"actionMenuOpen = false\">\n <ng-template>\n <ion-content class=\"ion-padding\">\n <ion-list lines=\"none\">\n <ion-list-header>\n <h4 class=\"dcf-text-capitalize\" [innerHTML]=\"'actions' | translate\"></h4>\n </ion-list-header>\n @for (operation of ['update', 'delete']; track operation) {\n @if (operations.includes(operation)) {\n <ion-item [button]=\"true\" (click)=\"handleAction(operation, $event, component)\">\n <ion-avatar class=\"dcf-flex dcf-flex-middle\" aria-hidden=\"true\" slot=\"start\">\n @if (operation === 'update') {\n <ion-icon color=\"primary\" aria-hidden=\"true\" name=\"create-outline\"></ion-icon>\n } @else {\n <ion-icon color=\"danger\" aria-hidden=\"true\" name=\"trash\"></ion-icon>\n }\n </ion-avatar>\n <ion-label class=\"dcf-text-capitalize\">{{ operation | translate }}</ion-label>\n </ion-item>\n }\n }\n </ion-list>\n </ion-content>\n </ng-template>\n </ion-popover>\n </div>\n }\n <!-- @if (operations?.length && uid) {\n <div class=\"dcf-visible@m\" id=\"dcf-actions\">\n @if (operations?.includes('update')) {\n <ion-button fill=\"clear\" size=\"small\" color=\"primary\" (click)=\"handleAction('update', component)\">\n <ion-icon aria-hidden=\"true\" slot=\"icon-only\" name=\"create-outline\"></ion-icon>\n </ion-button>\n }\n @if (operations?.includes('delete')) {\n <ion-button fill=\"clear\" size=\"small\" color=\"danger\" (click)=\"handleAction('delete', component)\">\n <ion-icon aria-hidden=\"true\" slot=\"icon-only\" name=\"trash\"></ion-icon>\n </ion-button>\n }\n </div>\n } -->\n @if (windowWidth > 639) {\n <div id=\"end\">\n <ng-content select=\"[slot='end']\"></ng-content>\n </div>\n }\n </div>\n </div>\n </div>\n </ion-item>\n @if (showSlideItems && uid) {\n <ion-item-options side=\"end\" (ionSwipe)=\"operations.length === 1 ? handleAction(operations[0], $event, component) : ''\">\n @if (operations?.includes('update')) {\n <ion-item-option class=\"dcf-update\" (click)=\"handleAction('update', $event, component)\" [expandable]=\"operations.length === 1\">\n <ion-icon aria-hidden=\"true\" slot=\"icon-only\" name=\"create-outline\"></ion-icon>\n </ion-item-option>\n }\n @if (operations?.includes('delete')) {\n <ion-item-option class=\"dcf- delete\" (click)=\"handleAction('delete', $event, component)\" [expandable]=\"operations.length === 1\">\n <ion-icon aria-hidden=\"true\" slot=\"icon-only\" name=\"trash\"></ion-icon>\n </ion-item-option>\n }\n </ion-item-options>\n }\n </ion-item-sliding>\n}\n", styles: ["ion-item:not(.dcf-palette-dark){--background-hover-opacity: .1;--background-focused-opacity: .1;--border-color: var(--dcf-color-gray-2)}ion-item:not(.dcf-palette-dark) .dcf-info{color:var(--dcf-color-gray-6)}ion-item:not(.dcf-palette-dark) .dcf-item-title{color:var(--dcf-color-gray-8)}ion-item:not(.dcf-palette-dark) .dcf-description{color:var(--dcf-color-gray-6)}ion-item:not(.dcf-palette-dark) ion-button{color:var(--dcf-color-gray-7);--background: var(--dcf-color-gray-1) !important}ion-item:not(.dcf-palette-dark) ion-avatar{color:var(--dcf-color-gray-7);background:var(--dcf-color-gray-1)!important}ion-item:not(.dcf-palette-dark) ion-item-option:not(.dcf-delete),ion-item:not(.dcf-palette-dark) ion-item-option:not(.dcf-update){background:rgba(var(--dcf-color-dark-rgb),.25)!important}ion-item:not(.dcf-palette-dark) ion-item-option:not(.dcf-delete) .dcf-ti,ion-item:not(.dcf-palette-dark) ion-item-option:not(.dcf-delete) ion-icon,ion-item:not(.dcf-palette-dark) ion-item-option:not(.dcf-update) .dcf-ti,ion-item:not(.dcf-palette-dark) ion-item-option:not(.dcf-update) ion-icon{color:var(--dcf-color-gray-7)!important}ion-item:not(.dcf-palette-dark) ion-item-option.dcf-delete{background:rgba(var(--dcf-color-danger-rgb),.05)!important}ion-item:not(.dcf-palette-dark) ion-item-option.dcf-delete .dcf-ti,ion-item:not(.dcf-palette-dark) ion-item-option.dcf-delete *,ion-item:not(.dcf-palette-dark) ion-item-option.dcf-delete ion-icon{color:var(--dcf-color-danger)!important}ion-item:not(.dcf-palette-dark) ion-item-option.dcf-update{background:rgba(var(--dcf-color-primary-rgb),.05)!important}ion-item:not(.dcf-palette-dark) ion-item-option.dcf-update .dcf-ti,ion-item:not(.dcf-palette-dark) ion-item-option.dcf-update ion-icon{color:var(--dcf-color-primary)!important}ion-item.dcf-palette-dark{--background-hover-opacity: .25;--background-focused-opacity: .25;--border-color: var(--dcf-color-gray-6)}ion-item.dcf-palette-dark .dcf-description{color:var(--dcf-color-gray-4)}ion-item.dcf-palette-dark ion-button{color:var(--dcf-color-gray-1)!important;--background: var(--dcf-color-gray-7) !important}ion-item.dcf-palette-dark ion-avatar{color:var(--dcf-color-gray-1)!important;background:var(--dcf-background-color)!important}ion-item.dcf-palette-dark ion-item-option:not(.dcf-delete),ion-item.dcf-palette-dark ion-item-option:not(.dcf-update){background:rgba(var(--dcf-color-dark-rgb),1)!important}ion-item.dcf-palette-dark ion-item-option:not(.dcf-delete) .dcf-ti,ion-item.dcf-palette-dark ion-item-option:not(.dcf-delete) ion-icon,ion-item.dcf-palette-dark ion-item-option:not(.dcf-update) .dcf-ti,ion-item.dcf-palette-dark ion-item-option:not(.dcf-update) ion-icon{color:var(--dcf-color-gray-2)!important}ion-item.dcf-palette-dark ion-item-option.dcf-delete{background:rgba(var(--dcf-color-danger-rgb),.05)!important}ion-item.dcf-palette-dark ion-item-option.dcf-delete .dcf-ti,ion-item.dcf-palette-dark ion-item-option.dcf-delete *,ion-item.dcf-palette-dark ion-item-option.dcf-delete ion-icon{color:var(--dcf-color-danger)!important}ion-item.dcf-palette-dark ion-item-option.dcf-update{background:rgba(var(--dcf-color-primary-rgb),.05)!important}ion-item.dcf-palette-dark ion-item-option.dcf-update .dcf-ti,ion-item.dcf-palette-dark ion-item-option.dcf-update ion-icon{color:var(--dcf-color-gray-2)!important}ion-item-sliding{box-sizing:border-box}ion-item-sliding[class*=active-slide]{border-color:var(--dcf-color-gray-3)}ion-item-sliding ion-item-option{color:var(--dcf-color-gray-5);box-shadow:inset 0 0 5px rgba(var(--dcf-color-dark-rgb),.15)!important;background:var(--dcf-color-gray-3)}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;--background-hover: var(--dcf-color-gray-8);--background-focused: var(--dcf-color-gray-8)}ion-item.item-lines-full{--padding-top: .5rem;--padding-bottom: .5rem;--padding-start: .25rem;-padding-end:.25rem;padding:0 .65rem}ion-item.item-lines-inset{--padding-top: 0rem !important;--padding-bottom: 0rem !important;--inner-padding-top: .5rem !important;--inner-padding-bottom: .65rem !important}ion-item .dcf-info{min-width:10vw;background:transparent!important}ion-item .dcf-grid{padding:0!important;margin:0!important;min-width:100%!important}ion-item .dcf-item-title{font-style:normal;font-weight:700}ion-item .dcf-description{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-style:normal;font-weight:400;font-size:.925rem}ion-item::part(native){min-width:100%}ion-item [slot=start]{margin-right:.5rem!important}ion-item [slot=end]{margin-left:.5rem!important}ion-item .dcf-info{font-size:.9rem}ion-item .dcf-info .dcf-subinfo.dcf-line{margin-left:.5rem}@media (min-width: var(--dcf-width-sm)){ion-item .dcf-info .dcf-subinfo.dcf-line{display:block;margin-left:0}}ion-item #dcf-actions{padding:5px}@media (max-width: var(--dcf-width-m)){ion-item #dcf-actions{display:none;pointer-events:none!important;cursor:text!important}ion-item #dcf-actions *{display:none;pointer-events:none!important;cursor:text!important}}ion-item #dcf-actions ion-button{--padding-start: 1rem;--padding-end: .75rem;--padding-top: .85rem !important;--padding-bottom: .85rem !important;color:#ccc;margin-right:.5rem!important;--background: var(--dcf-color-gray-2) !important}ion-item #dcf-actions ion-button ion-icon{position:relative;left:-1px}@media (max-width: var(--dcf-width-m)){ion-item #dcf-end,ion-item [slot=end]{display:none!important}}ion-item #dcf-end{padding-top:5px;display:flex;align-items:flex-end}ion-item .dcf-icon{display:flex;justify-content:center;align-items:center;text-align:center;margin-right:.5rem!important}ion-item .dcf-icon.dcf-grid-icon{min-width:50px;text-align:left;display:flex;justify-content:flex-start}@media (max-width: var(--dcf-width-s)){ion-item .dcf-icon{align-items:flex-start!important}}ion-item .dcf-icon ion-button ion-icon{font-size:20px}ion-avatar{width:48px;height:48px;display:flex;justify-content:center;align-items:center;text-align:center}ion-avatar ion-icon{font-size:20px}ion-avatar .dcf-icon-large{transform:translateY(5px)}\n"], dependencies: [{ kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: IonListHeader, selector: "ion-list-header", inputs: ["color", "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: IonItemSliding, selector: "ion-item-sliding", inputs: ["disabled"] }, { kind: "component", type: IonItemOptions, selector: "ion-item-options", inputs: ["side"] }, { kind: "component", type: IonItemOption, selector: "ion-item-option", inputs: ["color", "disabled", "download", "expandable", "href", "mode", "rel", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { 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: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: IonPopover, selector: "ion-popover" }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
10540
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: ListItemComponent, isStandalone: true, selector: "ngx-decaf-list-item", inputs: { lines: "lines", item: "item", icon: "icon", iconSlot: "iconSlot", button: "button", title: "title", description: "description", info: "info", subinfo: "subinfo" }, outputs: { clickEvent: "clickEvent" }, host: { listeners: { "window:resize": "enableSlideItems($event)" }, properties: { "attr.id": "uid" } }, viewQueries: [{ propertyName: "component", first: true, predicate: ["component"], descendants: true, read: ElementRef }, { propertyName: "actionMenuComponent", first: true, predicate: ["actionMenuComponent"], descendants: true }], usesInheritance: true, ngImport: i0, template: "\n@if (title || description) {\n <ion-item-sliding>\n <ion-item\n [id]=\"uid\"\n [lines]=\"lines\"\n [button]=\"button\"\n [class]=\"className\"\n (click)=\"operations?.includes('read') ? handleAction('read', $event, component) : ''\"\n #component\n >\n @if (icon && lines !== 'inset') {\n <div class=\"dcf-icon\" [slot]=\"iconSlot\">\n <ion-avatar>\n <ion-icon aria-hidden=\"true\" name=\"reader-outline\" size=\"default\" />\n </ion-avatar>\n </div>\n }\n <div class=\"dcf-width-expand\">\n <div class=\"dcf-flex dcf-flex-middle dcf-grid-collapse\" dcf-grid>\n @if (icon && lines === 'inset') {\n <div class=\"dcf-icon dcf-grid-icon\">\n <ion-avatar>\n <ion-icon aria-hidden=\"true\" name=\"reader-outline\" size=\"default\" />\n </ion-avatar>\n </div>\n }\n <div class=\"dcf-width-expand@s dcf-width-1-1 dcf-label\">\n @if (title) {\n <ion-label class=\"dcf-item-title\">\n {{ uid !== title ? (uid + ' - ' + title) : title }}\n </ion-label>\n }\n @if (description) {\n <div class=\"dcf-description\" [innerHTML]=\"description\"></div>\n }\n </div>\n @if (info || subinfo) {\n <div class=\"dcf-width-auto@s dcf-width-expand dcf-info dcf-flex dcf-flex-right@s\">\n <div>\n @if (info) {\n <span [innerHTML]=\"info\"></span>\n }\n @if (subinfo) {\n <div class=\"dcf-subinfo dcf-text-truncate\" [innerHTML]=\"subinfo\" ></div>\n }\n </div>\n </div>\n }\n\n <div class=\"dcf-width-auto dcf-flex dcf-flex-middle dcf-flex-right\">\n @if ((operations.includes('delete') || operations.includes('update')) && uid) {\n\n <div class=\"dcf-visible@s\" id=\"dcf-actions\">\n <ion-button class=\"\" shape=\"round\" fill=\"clear\" color=\"primary\" (click)=\"presentActionsMenu($event)\">\n <ion-icon slot=\"icon-only\" aria-hidden=\"true\" name=\"ellipsis-vertical-outline\" />\n </ion-button>\n <ion-popover\n #actionMenuComponent\n side=\"bottom\"\n alignment=\"left\"\n\n [isOpen]=\"actionMenuOpen\"\n (didDismiss)=\"actionMenuOpen = false\">\n <ng-template>\n <ion-content class=\"ion-padding\">\n <ion-list lines=\"none\">\n <ion-list-header>\n <h4 class=\"dcf-text-capitalize\" [innerHTML]=\"'actions' | translate\"></h4>\n </ion-list-header>\n @for (operation of ['update', 'delete']; track operation) {\n @if (operations.includes(operation)) {\n <ion-item [button]=\"true\" (click)=\"handleAction(operation, $event, component)\">\n <ion-avatar class=\"dcf-flex dcf-flex-middle\" aria-hidden=\"true\" slot=\"start\">\n @if (operation === 'update') {\n <ion-icon color=\"primary\" aria-hidden=\"true\" name=\"create-outline\" />\n } @else {\n <ion-icon color=\"danger\" aria-hidden=\"true\" name=\"trash\" />\n }\n </ion-avatar>\n <ion-label class=\"dcf-text-capitalize\">{{ operation | translate }}</ion-label>\n </ion-item>\n }\n }\n </ion-list>\n </ion-content>\n </ng-template>\n </ion-popover>\n </div>\n }\n @if (windowWidth > 639) {\n <div id=\"end\">\n <ng-content select=\"[slot='end']\"></ng-content>\n </div>\n }\n </div>\n </div>\n </div>\n </ion-item>\n @if (showSlideItems && uid) {\n <ion-item-options side=\"end\" (ionSwipe)=\"operations.length === 1 ? handleAction(operations[0], $event, component) : ''\">\n @if (operations?.includes('update')) {\n <ion-item-option class=\"dcf-update\" (click)=\"handleAction('update', $event, component)\" [expandable]=\"operations.length === 1\">\n <ion-icon aria-hidden=\"true\" slot=\"icon-only\" name=\"create-outline\" />\n </ion-item-option>\n }\n @if (operations?.includes('delete')) {\n <ion-item-option class=\"dcf-delete\" (click)=\"handleAction('delete', $event, component)\" [expandable]=\"operations.length === 1\">\n <ion-icon aria-hidden=\"true\" slot=\"icon-only\" name=\"trash\" />\n </ion-item-option>\n }\n </ion-item-options>\n }\n </ion-item-sliding>\n}\n", styles: ["ion-item:not(.dcf-palette-dark){--background-hover-opacity: .1;--background-focused-opacity: .1;--border-color: var(--dcf-color-gray-2)}ion-item:not(.dcf-palette-dark) .dcf-info{color:var(--dcf-color-gray-6)}ion-item:not(.dcf-palette-dark) .dcf-item-title{color:var(--dcf-color-gray-8)}ion-item:not(.dcf-palette-dark) .dcf-description{color:var(--dcf-color-gray-6)}ion-item:not(.dcf-palette-dark) ion-button{color:var(--dcf-color-gray-7);--background: var(--dcf-color-gray-1) !important}ion-item:not(.dcf-palette-dark) ion-avatar{color:var(--dcf-color-gray-7);background:var(--dcf-color-gray-1)!important}ion-item:not(.dcf-palette-dark) ion-item-option:not(.dcf-delete),ion-item:not(.dcf-palette-dark) ion-item-option:not(.dcf-update){background:rgba(var(--dcf-color-dark-rgb),.25)!important}ion-item:not(.dcf-palette-dark) ion-item-option:not(.dcf-delete) .dcf-ti,ion-item:not(.dcf-palette-dark) ion-item-option:not(.dcf-delete) ion-icon,ion-item:not(.dcf-palette-dark) ion-item-option:not(.dcf-update) .dcf-ti,ion-item:not(.dcf-palette-dark) ion-item-option:not(.dcf-update) ion-icon{color:var(--dcf-color-gray-7)!important}ion-item:not(.dcf-palette-dark) ion-item-option.dcf-delete{background:rgba(var(--dcf-color-danger-rgb),.05)!important}ion-item:not(.dcf-palette-dark) ion-item-option.dcf-delete .dcf-ti,ion-item:not(.dcf-palette-dark) ion-item-option.dcf-delete *,ion-item:not(.dcf-palette-dark) ion-item-option.dcf-delete ion-icon{color:var(--dcf-color-danger)!important}ion-item:not(.dcf-palette-dark) ion-item-option.dcf-update{background:rgba(var(--dcf-color-primary-rgb),.05)!important}ion-item:not(.dcf-palette-dark) ion-item-option.dcf-update .dcf-ti,ion-item:not(.dcf-palette-dark) ion-item-option.dcf-update ion-icon{color:var(--dcf-color-primary)!important}ion-item.dcf-palette-dark{--background-hover-opacity: .25;--background-focused-opacity: .25;--border-color: var(--dcf-color-gray-6)}ion-item.dcf-palette-dark .dcf-description{color:var(--dcf-color-gray-4)}ion-item.dcf-palette-dark ion-button{color:var(--dcf-color-gray-1)!important;--background: var(--dcf-color-gray-7) !important}ion-item.dcf-palette-dark ion-avatar{color:var(--dcf-color-gray-1)!important;background:var(--dcf-background-color)!important}ion-item.dcf-palette-dark ion-item-option:not(.dcf-delete),ion-item.dcf-palette-dark ion-item-option:not(.dcf-update){background:rgba(var(--dcf-color-dark-rgb),1)!important}ion-item.dcf-palette-dark ion-item-option:not(.dcf-delete) .dcf-ti,ion-item.dcf-palette-dark ion-item-option:not(.dcf-delete) ion-icon,ion-item.dcf-palette-dark ion-item-option:not(.dcf-update) .dcf-ti,ion-item.dcf-palette-dark ion-item-option:not(.dcf-update) ion-icon{color:var(--dcf-color-gray-2)!important}ion-item.dcf-palette-dark ion-item-option.dcf-delete{background:rgba(var(--dcf-color-danger-rgb),.05)!important}ion-item.dcf-palette-dark ion-item-option.dcf-delete .dcf-ti,ion-item.dcf-palette-dark ion-item-option.dcf-delete *,ion-item.dcf-palette-dark ion-item-option.dcf-delete ion-icon{color:var(--dcf-color-danger)!important}ion-item.dcf-palette-dark ion-item-option.dcf-update{background:rgba(var(--dcf-color-primary-rgb),.05)!important}ion-item.dcf-palette-dark ion-item-option.dcf-update .dcf-ti,ion-item.dcf-palette-dark ion-item-option.dcf-update ion-icon{color:var(--dcf-color-gray-2)!important}ion-item-sliding{box-sizing:border-box}ion-item-sliding[class*=active-slide]{border-color:var(--dcf-color-gray-3)}ion-item-sliding ion-item-option{color:var(--dcf-color-gray-5);box-shadow:inset 0 0 5px rgba(var(--dcf-color-dark-rgb),.15)!important;background:var(--dcf-color-gray-3)}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;--background-hover: var(--dcf-color-gray-8);--background-focused: var(--dcf-color-gray-8)}ion-item.item-lines-full{--padding-top: .5rem;--padding-bottom: .5rem;--padding-start: .25rem;-padding-end:.25rem;padding:0 .65rem}ion-item.item-lines-inset{--padding-top: 0rem !important;--padding-bottom: 0rem !important;--inner-padding-top: .5rem !important;--inner-padding-bottom: .65rem !important}ion-item .dcf-info{min-width:10vw;background:transparent!important}ion-item .dcf-grid{padding:0!important;margin:0!important;min-width:100%!important}ion-item .dcf-item-title{font-style:normal;font-weight:700}ion-item .dcf-description{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-style:normal;font-weight:400;font-size:.925rem}ion-item::part(native){min-width:100%}ion-item [slot=start]{margin-right:.5rem!important}ion-item [slot=end]{margin-left:.5rem!important}ion-item .dcf-info{font-size:.9rem}ion-item .dcf-info .dcf-subinfo.dcf-line{margin-left:.5rem}@media (min-width: var(--dcf-width-sm)){ion-item .dcf-info .dcf-subinfo.dcf-line{display:block;margin-left:0}}ion-item #dcf-actions{padding:5px}@media (max-width: var(--dcf-width-m)){ion-item #dcf-actions{display:none;pointer-events:none!important;cursor:text!important}ion-item #dcf-actions *{display:none;pointer-events:none!important;cursor:text!important}}ion-item #dcf-actions ion-button{--padding-start: 1rem;--padding-end: .75rem;--padding-top: .85rem !important;--padding-bottom: .85rem !important;color:#ccc;margin-right:.5rem!important;--background: var(--dcf-color-gray-2) !important}ion-item #dcf-actions ion-button ion-icon{position:relative;left:-1px}@media (max-width: var(--dcf-width-m)){ion-item #dcf-end,ion-item [slot=end]{display:none!important}}ion-item #dcf-end{padding-top:5px;display:flex;align-items:flex-end}ion-item .dcf-icon{display:flex;justify-content:center;align-items:center;text-align:center;margin-right:.5rem!important}ion-item .dcf-icon.dcf-grid-icon{min-width:50px;text-align:left;display:flex;justify-content:flex-start}@media (max-width: var(--dcf-width-s)){ion-item .dcf-icon{align-items:flex-start!important}}ion-item .dcf-icon ion-button ion-icon{font-size:20px}ion-avatar{width:48px;height:48px;display:flex;justify-content:center;align-items:center;text-align:center}ion-avatar ion-icon{font-size:20px}ion-avatar .dcf-icon-large{transform:translateY(5px)}\n"], dependencies: [{ kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: IonListHeader, selector: "ion-list-header", inputs: ["color", "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: IonItemSliding, selector: "ion-item-sliding", inputs: ["disabled"] }, { kind: "component", type: IonItemOptions, selector: "ion-item-options", inputs: ["side"] }, { kind: "component", type: IonItemOption, selector: "ion-item-option", inputs: ["color", "disabled", "download", "expandable", "href", "mode", "rel", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { 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: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: IonPopover, selector: "ion-popover" }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
9876
10541
  };
9877
10542
  ListItemComponent = __decorate([
9878
10543
  Dynamic(),
@@ -9893,7 +10558,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
9893
10558
  IonButton,
9894
10559
  IonContent,
9895
10560
  IonPopover
9896
- ], host: { '[attr.id]': 'uid' }, template: "\n@if (title || description) {\n <ion-item-sliding>\n <ion-item\n [id]=\"uid\"\n [lines]=\"lines\"\n [button]=\"button\"\n [class]=\"className\"\n (click)=\"operations?.includes('read') ? handleAction('read', $event, component) : ''\"\n #component\n >\n @if (icon && lines !== 'inset') {\n <div class=\"dcf-icon\" [slot]=\"iconSlot\">\n <ion-avatar>\n <ion-icon aria-hidden=\"true\" name=\"reader-outline\" size=\"default\"></ion-icon>\n </ion-avatar>\n </div>\n }\n <div class=\"dcf-width-expand\">\n <div class=\"dcf-flex dcf-flex-middle dcf-grid-collapse\" dcf-grid>\n @if (icon && lines === 'inset') {\n <div class=\"dcf-icon dcf-grid-icon\">\n <ion-avatar>\n <ion-icon aria-hidden=\"true\" name=\"reader-outline\" size=\"default\"></ion-icon>\n </ion-avatar>\n </div>\n }\n <div class=\"dcf-width-expand@s dcf-width-1-1 dcf-label\">\n @if (title) {\n <ion-label class=\"dcf-item-title\">\n {{ uid !== title ? (uid + ' - ' + title) : title }}\n </ion-label>\n }\n @if (description) {\n <div class=\"dcf-description\" [innerHTML]=\"description\"></div>\n }\n </div>\n @if (info || subinfo) {\n <div class=\"dcf-width-auto@s dcf-width-expand dcf-info dcf-flex dcf-flex-right@s\">\n <div>\n @if (info) {\n <span [innerHTML]=\"info\"></span>\n }\n @if (subinfo) {\n <div class=\"dcf-subinfo dcf-text-truncate\" [innerHTML]=\"subinfo\" ></div>\n }\n </div>\n </div>\n }\n\n <div class=\"dcf-width-auto dcf-flex dcf-flex-middle dcf-flex-right\">\n @if ((operations.includes('delete') || operations.includes('update')) && uid) {\n\n <div class=\"dcf-visible@s\" id=\"dcf-actions\">\n <ion-button class=\"\" shape=\"round\" fill=\"clear\" color=\"primary\" (click)=\"presentActionsMenu($event)\">\n <ion-icon slot=\"icon-only\" aria-hidden=\"true\" name=\"ellipsis-vertical-outline\"></ion-icon>\n </ion-button>\n <ion-popover\n #actionMenuComponent\n side=\"bottom\"\n alignment=\"left\"\n\n [isOpen]=\"actionMenuOpen\"\n (didDismiss)=\"actionMenuOpen = false\">\n <ng-template>\n <ion-content class=\"ion-padding\">\n <ion-list lines=\"none\">\n <ion-list-header>\n <h4 class=\"dcf-text-capitalize\" [innerHTML]=\"'actions' | translate\"></h4>\n </ion-list-header>\n @for (operation of ['update', 'delete']; track operation) {\n @if (operations.includes(operation)) {\n <ion-item [button]=\"true\" (click)=\"handleAction(operation, $event, component)\">\n <ion-avatar class=\"dcf-flex dcf-flex-middle\" aria-hidden=\"true\" slot=\"start\">\n @if (operation === 'update') {\n <ion-icon color=\"primary\" aria-hidden=\"true\" name=\"create-outline\"></ion-icon>\n } @else {\n <ion-icon color=\"danger\" aria-hidden=\"true\" name=\"trash\"></ion-icon>\n }\n </ion-avatar>\n <ion-label class=\"dcf-text-capitalize\">{{ operation | translate }}</ion-label>\n </ion-item>\n }\n }\n </ion-list>\n </ion-content>\n </ng-template>\n </ion-popover>\n </div>\n }\n <!-- @if (operations?.length && uid) {\n <div class=\"dcf-visible@m\" id=\"dcf-actions\">\n @if (operations?.includes('update')) {\n <ion-button fill=\"clear\" size=\"small\" color=\"primary\" (click)=\"handleAction('update', component)\">\n <ion-icon aria-hidden=\"true\" slot=\"icon-only\" name=\"create-outline\"></ion-icon>\n </ion-button>\n }\n @if (operations?.includes('delete')) {\n <ion-button fill=\"clear\" size=\"small\" color=\"danger\" (click)=\"handleAction('delete', component)\">\n <ion-icon aria-hidden=\"true\" slot=\"icon-only\" name=\"trash\"></ion-icon>\n </ion-button>\n }\n </div>\n } -->\n @if (windowWidth > 639) {\n <div id=\"end\">\n <ng-content select=\"[slot='end']\"></ng-content>\n </div>\n }\n </div>\n </div>\n </div>\n </ion-item>\n @if (showSlideItems && uid) {\n <ion-item-options side=\"end\" (ionSwipe)=\"operations.length === 1 ? handleAction(operations[0], $event, component) : ''\">\n @if (operations?.includes('update')) {\n <ion-item-option class=\"dcf-update\" (click)=\"handleAction('update', $event, component)\" [expandable]=\"operations.length === 1\">\n <ion-icon aria-hidden=\"true\" slot=\"icon-only\" name=\"create-outline\"></ion-icon>\n </ion-item-option>\n }\n @if (operations?.includes('delete')) {\n <ion-item-option class=\"dcf- delete\" (click)=\"handleAction('delete', $event, component)\" [expandable]=\"operations.length === 1\">\n <ion-icon aria-hidden=\"true\" slot=\"icon-only\" name=\"trash\"></ion-icon>\n </ion-item-option>\n }\n </ion-item-options>\n }\n </ion-item-sliding>\n}\n", styles: ["ion-item:not(.dcf-palette-dark){--background-hover-opacity: .1;--background-focused-opacity: .1;--border-color: var(--dcf-color-gray-2)}ion-item:not(.dcf-palette-dark) .dcf-info{color:var(--dcf-color-gray-6)}ion-item:not(.dcf-palette-dark) .dcf-item-title{color:var(--dcf-color-gray-8)}ion-item:not(.dcf-palette-dark) .dcf-description{color:var(--dcf-color-gray-6)}ion-item:not(.dcf-palette-dark) ion-button{color:var(--dcf-color-gray-7);--background: var(--dcf-color-gray-1) !important}ion-item:not(.dcf-palette-dark) ion-avatar{color:var(--dcf-color-gray-7);background:var(--dcf-color-gray-1)!important}ion-item:not(.dcf-palette-dark) ion-item-option:not(.dcf-delete),ion-item:not(.dcf-palette-dark) ion-item-option:not(.dcf-update){background:rgba(var(--dcf-color-dark-rgb),.25)!important}ion-item:not(.dcf-palette-dark) ion-item-option:not(.dcf-delete) .dcf-ti,ion-item:not(.dcf-palette-dark) ion-item-option:not(.dcf-delete) ion-icon,ion-item:not(.dcf-palette-dark) ion-item-option:not(.dcf-update) .dcf-ti,ion-item:not(.dcf-palette-dark) ion-item-option:not(.dcf-update) ion-icon{color:var(--dcf-color-gray-7)!important}ion-item:not(.dcf-palette-dark) ion-item-option.dcf-delete{background:rgba(var(--dcf-color-danger-rgb),.05)!important}ion-item:not(.dcf-palette-dark) ion-item-option.dcf-delete .dcf-ti,ion-item:not(.dcf-palette-dark) ion-item-option.dcf-delete *,ion-item:not(.dcf-palette-dark) ion-item-option.dcf-delete ion-icon{color:var(--dcf-color-danger)!important}ion-item:not(.dcf-palette-dark) ion-item-option.dcf-update{background:rgba(var(--dcf-color-primary-rgb),.05)!important}ion-item:not(.dcf-palette-dark) ion-item-option.dcf-update .dcf-ti,ion-item:not(.dcf-palette-dark) ion-item-option.dcf-update ion-icon{color:var(--dcf-color-primary)!important}ion-item.dcf-palette-dark{--background-hover-opacity: .25;--background-focused-opacity: .25;--border-color: var(--dcf-color-gray-6)}ion-item.dcf-palette-dark .dcf-description{color:var(--dcf-color-gray-4)}ion-item.dcf-palette-dark ion-button{color:var(--dcf-color-gray-1)!important;--background: var(--dcf-color-gray-7) !important}ion-item.dcf-palette-dark ion-avatar{color:var(--dcf-color-gray-1)!important;background:var(--dcf-background-color)!important}ion-item.dcf-palette-dark ion-item-option:not(.dcf-delete),ion-item.dcf-palette-dark ion-item-option:not(.dcf-update){background:rgba(var(--dcf-color-dark-rgb),1)!important}ion-item.dcf-palette-dark ion-item-option:not(.dcf-delete) .dcf-ti,ion-item.dcf-palette-dark ion-item-option:not(.dcf-delete) ion-icon,ion-item.dcf-palette-dark ion-item-option:not(.dcf-update) .dcf-ti,ion-item.dcf-palette-dark ion-item-option:not(.dcf-update) ion-icon{color:var(--dcf-color-gray-2)!important}ion-item.dcf-palette-dark ion-item-option.dcf-delete{background:rgba(var(--dcf-color-danger-rgb),.05)!important}ion-item.dcf-palette-dark ion-item-option.dcf-delete .dcf-ti,ion-item.dcf-palette-dark ion-item-option.dcf-delete *,ion-item.dcf-palette-dark ion-item-option.dcf-delete ion-icon{color:var(--dcf-color-danger)!important}ion-item.dcf-palette-dark ion-item-option.dcf-update{background:rgba(var(--dcf-color-primary-rgb),.05)!important}ion-item.dcf-palette-dark ion-item-option.dcf-update .dcf-ti,ion-item.dcf-palette-dark ion-item-option.dcf-update ion-icon{color:var(--dcf-color-gray-2)!important}ion-item-sliding{box-sizing:border-box}ion-item-sliding[class*=active-slide]{border-color:var(--dcf-color-gray-3)}ion-item-sliding ion-item-option{color:var(--dcf-color-gray-5);box-shadow:inset 0 0 5px rgba(var(--dcf-color-dark-rgb),.15)!important;background:var(--dcf-color-gray-3)}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;--background-hover: var(--dcf-color-gray-8);--background-focused: var(--dcf-color-gray-8)}ion-item.item-lines-full{--padding-top: .5rem;--padding-bottom: .5rem;--padding-start: .25rem;-padding-end:.25rem;padding:0 .65rem}ion-item.item-lines-inset{--padding-top: 0rem !important;--padding-bottom: 0rem !important;--inner-padding-top: .5rem !important;--inner-padding-bottom: .65rem !important}ion-item .dcf-info{min-width:10vw;background:transparent!important}ion-item .dcf-grid{padding:0!important;margin:0!important;min-width:100%!important}ion-item .dcf-item-title{font-style:normal;font-weight:700}ion-item .dcf-description{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-style:normal;font-weight:400;font-size:.925rem}ion-item::part(native){min-width:100%}ion-item [slot=start]{margin-right:.5rem!important}ion-item [slot=end]{margin-left:.5rem!important}ion-item .dcf-info{font-size:.9rem}ion-item .dcf-info .dcf-subinfo.dcf-line{margin-left:.5rem}@media (min-width: var(--dcf-width-sm)){ion-item .dcf-info .dcf-subinfo.dcf-line{display:block;margin-left:0}}ion-item #dcf-actions{padding:5px}@media (max-width: var(--dcf-width-m)){ion-item #dcf-actions{display:none;pointer-events:none!important;cursor:text!important}ion-item #dcf-actions *{display:none;pointer-events:none!important;cursor:text!important}}ion-item #dcf-actions ion-button{--padding-start: 1rem;--padding-end: .75rem;--padding-top: .85rem !important;--padding-bottom: .85rem !important;color:#ccc;margin-right:.5rem!important;--background: var(--dcf-color-gray-2) !important}ion-item #dcf-actions ion-button ion-icon{position:relative;left:-1px}@media (max-width: var(--dcf-width-m)){ion-item #dcf-end,ion-item [slot=end]{display:none!important}}ion-item #dcf-end{padding-top:5px;display:flex;align-items:flex-end}ion-item .dcf-icon{display:flex;justify-content:center;align-items:center;text-align:center;margin-right:.5rem!important}ion-item .dcf-icon.dcf-grid-icon{min-width:50px;text-align:left;display:flex;justify-content:flex-start}@media (max-width: var(--dcf-width-s)){ion-item .dcf-icon{align-items:flex-start!important}}ion-item .dcf-icon ion-button ion-icon{font-size:20px}ion-avatar{width:48px;height:48px;display:flex;justify-content:center;align-items:center;text-align:center}ion-avatar ion-icon{font-size:20px}ion-avatar .dcf-icon-large{transform:translateY(5px)}\n"] }]
10561
+ ], host: { '[attr.id]': 'uid' }, template: "\n@if (title || description) {\n <ion-item-sliding>\n <ion-item\n [id]=\"uid\"\n [lines]=\"lines\"\n [button]=\"button\"\n [class]=\"className\"\n (click)=\"operations?.includes('read') ? handleAction('read', $event, component) : ''\"\n #component\n >\n @if (icon && lines !== 'inset') {\n <div class=\"dcf-icon\" [slot]=\"iconSlot\">\n <ion-avatar>\n <ion-icon aria-hidden=\"true\" name=\"reader-outline\" size=\"default\" />\n </ion-avatar>\n </div>\n }\n <div class=\"dcf-width-expand\">\n <div class=\"dcf-flex dcf-flex-middle dcf-grid-collapse\" dcf-grid>\n @if (icon && lines === 'inset') {\n <div class=\"dcf-icon dcf-grid-icon\">\n <ion-avatar>\n <ion-icon aria-hidden=\"true\" name=\"reader-outline\" size=\"default\" />\n </ion-avatar>\n </div>\n }\n <div class=\"dcf-width-expand@s dcf-width-1-1 dcf-label\">\n @if (title) {\n <ion-label class=\"dcf-item-title\">\n {{ uid !== title ? (uid + ' - ' + title) : title }}\n </ion-label>\n }\n @if (description) {\n <div class=\"dcf-description\" [innerHTML]=\"description\"></div>\n }\n </div>\n @if (info || subinfo) {\n <div class=\"dcf-width-auto@s dcf-width-expand dcf-info dcf-flex dcf-flex-right@s\">\n <div>\n @if (info) {\n <span [innerHTML]=\"info\"></span>\n }\n @if (subinfo) {\n <div class=\"dcf-subinfo dcf-text-truncate\" [innerHTML]=\"subinfo\" ></div>\n }\n </div>\n </div>\n }\n\n <div class=\"dcf-width-auto dcf-flex dcf-flex-middle dcf-flex-right\">\n @if ((operations.includes('delete') || operations.includes('update')) && uid) {\n\n <div class=\"dcf-visible@s\" id=\"dcf-actions\">\n <ion-button class=\"\" shape=\"round\" fill=\"clear\" color=\"primary\" (click)=\"presentActionsMenu($event)\">\n <ion-icon slot=\"icon-only\" aria-hidden=\"true\" name=\"ellipsis-vertical-outline\" />\n </ion-button>\n <ion-popover\n #actionMenuComponent\n side=\"bottom\"\n alignment=\"left\"\n\n [isOpen]=\"actionMenuOpen\"\n (didDismiss)=\"actionMenuOpen = false\">\n <ng-template>\n <ion-content class=\"ion-padding\">\n <ion-list lines=\"none\">\n <ion-list-header>\n <h4 class=\"dcf-text-capitalize\" [innerHTML]=\"'actions' | translate\"></h4>\n </ion-list-header>\n @for (operation of ['update', 'delete']; track operation) {\n @if (operations.includes(operation)) {\n <ion-item [button]=\"true\" (click)=\"handleAction(operation, $event, component)\">\n <ion-avatar class=\"dcf-flex dcf-flex-middle\" aria-hidden=\"true\" slot=\"start\">\n @if (operation === 'update') {\n <ion-icon color=\"primary\" aria-hidden=\"true\" name=\"create-outline\" />\n } @else {\n <ion-icon color=\"danger\" aria-hidden=\"true\" name=\"trash\" />\n }\n </ion-avatar>\n <ion-label class=\"dcf-text-capitalize\">{{ operation | translate }}</ion-label>\n </ion-item>\n }\n }\n </ion-list>\n </ion-content>\n </ng-template>\n </ion-popover>\n </div>\n }\n @if (windowWidth > 639) {\n <div id=\"end\">\n <ng-content select=\"[slot='end']\"></ng-content>\n </div>\n }\n </div>\n </div>\n </div>\n </ion-item>\n @if (showSlideItems && uid) {\n <ion-item-options side=\"end\" (ionSwipe)=\"operations.length === 1 ? handleAction(operations[0], $event, component) : ''\">\n @if (operations?.includes('update')) {\n <ion-item-option class=\"dcf-update\" (click)=\"handleAction('update', $event, component)\" [expandable]=\"operations.length === 1\">\n <ion-icon aria-hidden=\"true\" slot=\"icon-only\" name=\"create-outline\" />\n </ion-item-option>\n }\n @if (operations?.includes('delete')) {\n <ion-item-option class=\"dcf-delete\" (click)=\"handleAction('delete', $event, component)\" [expandable]=\"operations.length === 1\">\n <ion-icon aria-hidden=\"true\" slot=\"icon-only\" name=\"trash\" />\n </ion-item-option>\n }\n </ion-item-options>\n }\n </ion-item-sliding>\n}\n", styles: ["ion-item:not(.dcf-palette-dark){--background-hover-opacity: .1;--background-focused-opacity: .1;--border-color: var(--dcf-color-gray-2)}ion-item:not(.dcf-palette-dark) .dcf-info{color:var(--dcf-color-gray-6)}ion-item:not(.dcf-palette-dark) .dcf-item-title{color:var(--dcf-color-gray-8)}ion-item:not(.dcf-palette-dark) .dcf-description{color:var(--dcf-color-gray-6)}ion-item:not(.dcf-palette-dark) ion-button{color:var(--dcf-color-gray-7);--background: var(--dcf-color-gray-1) !important}ion-item:not(.dcf-palette-dark) ion-avatar{color:var(--dcf-color-gray-7);background:var(--dcf-color-gray-1)!important}ion-item:not(.dcf-palette-dark) ion-item-option:not(.dcf-delete),ion-item:not(.dcf-palette-dark) ion-item-option:not(.dcf-update){background:rgba(var(--dcf-color-dark-rgb),.25)!important}ion-item:not(.dcf-palette-dark) ion-item-option:not(.dcf-delete) .dcf-ti,ion-item:not(.dcf-palette-dark) ion-item-option:not(.dcf-delete) ion-icon,ion-item:not(.dcf-palette-dark) ion-item-option:not(.dcf-update) .dcf-ti,ion-item:not(.dcf-palette-dark) ion-item-option:not(.dcf-update) ion-icon{color:var(--dcf-color-gray-7)!important}ion-item:not(.dcf-palette-dark) ion-item-option.dcf-delete{background:rgba(var(--dcf-color-danger-rgb),.05)!important}ion-item:not(.dcf-palette-dark) ion-item-option.dcf-delete .dcf-ti,ion-item:not(.dcf-palette-dark) ion-item-option.dcf-delete *,ion-item:not(.dcf-palette-dark) ion-item-option.dcf-delete ion-icon{color:var(--dcf-color-danger)!important}ion-item:not(.dcf-palette-dark) ion-item-option.dcf-update{background:rgba(var(--dcf-color-primary-rgb),.05)!important}ion-item:not(.dcf-palette-dark) ion-item-option.dcf-update .dcf-ti,ion-item:not(.dcf-palette-dark) ion-item-option.dcf-update ion-icon{color:var(--dcf-color-primary)!important}ion-item.dcf-palette-dark{--background-hover-opacity: .25;--background-focused-opacity: .25;--border-color: var(--dcf-color-gray-6)}ion-item.dcf-palette-dark .dcf-description{color:var(--dcf-color-gray-4)}ion-item.dcf-palette-dark ion-button{color:var(--dcf-color-gray-1)!important;--background: var(--dcf-color-gray-7) !important}ion-item.dcf-palette-dark ion-avatar{color:var(--dcf-color-gray-1)!important;background:var(--dcf-background-color)!important}ion-item.dcf-palette-dark ion-item-option:not(.dcf-delete),ion-item.dcf-palette-dark ion-item-option:not(.dcf-update){background:rgba(var(--dcf-color-dark-rgb),1)!important}ion-item.dcf-palette-dark ion-item-option:not(.dcf-delete) .dcf-ti,ion-item.dcf-palette-dark ion-item-option:not(.dcf-delete) ion-icon,ion-item.dcf-palette-dark ion-item-option:not(.dcf-update) .dcf-ti,ion-item.dcf-palette-dark ion-item-option:not(.dcf-update) ion-icon{color:var(--dcf-color-gray-2)!important}ion-item.dcf-palette-dark ion-item-option.dcf-delete{background:rgba(var(--dcf-color-danger-rgb),.05)!important}ion-item.dcf-palette-dark ion-item-option.dcf-delete .dcf-ti,ion-item.dcf-palette-dark ion-item-option.dcf-delete *,ion-item.dcf-palette-dark ion-item-option.dcf-delete ion-icon{color:var(--dcf-color-danger)!important}ion-item.dcf-palette-dark ion-item-option.dcf-update{background:rgba(var(--dcf-color-primary-rgb),.05)!important}ion-item.dcf-palette-dark ion-item-option.dcf-update .dcf-ti,ion-item.dcf-palette-dark ion-item-option.dcf-update ion-icon{color:var(--dcf-color-gray-2)!important}ion-item-sliding{box-sizing:border-box}ion-item-sliding[class*=active-slide]{border-color:var(--dcf-color-gray-3)}ion-item-sliding ion-item-option{color:var(--dcf-color-gray-5);box-shadow:inset 0 0 5px rgba(var(--dcf-color-dark-rgb),.15)!important;background:var(--dcf-color-gray-3)}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;--background-hover: var(--dcf-color-gray-8);--background-focused: var(--dcf-color-gray-8)}ion-item.item-lines-full{--padding-top: .5rem;--padding-bottom: .5rem;--padding-start: .25rem;-padding-end:.25rem;padding:0 .65rem}ion-item.item-lines-inset{--padding-top: 0rem !important;--padding-bottom: 0rem !important;--inner-padding-top: .5rem !important;--inner-padding-bottom: .65rem !important}ion-item .dcf-info{min-width:10vw;background:transparent!important}ion-item .dcf-grid{padding:0!important;margin:0!important;min-width:100%!important}ion-item .dcf-item-title{font-style:normal;font-weight:700}ion-item .dcf-description{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-style:normal;font-weight:400;font-size:.925rem}ion-item::part(native){min-width:100%}ion-item [slot=start]{margin-right:.5rem!important}ion-item [slot=end]{margin-left:.5rem!important}ion-item .dcf-info{font-size:.9rem}ion-item .dcf-info .dcf-subinfo.dcf-line{margin-left:.5rem}@media (min-width: var(--dcf-width-sm)){ion-item .dcf-info .dcf-subinfo.dcf-line{display:block;margin-left:0}}ion-item #dcf-actions{padding:5px}@media (max-width: var(--dcf-width-m)){ion-item #dcf-actions{display:none;pointer-events:none!important;cursor:text!important}ion-item #dcf-actions *{display:none;pointer-events:none!important;cursor:text!important}}ion-item #dcf-actions ion-button{--padding-start: 1rem;--padding-end: .75rem;--padding-top: .85rem !important;--padding-bottom: .85rem !important;color:#ccc;margin-right:.5rem!important;--background: var(--dcf-color-gray-2) !important}ion-item #dcf-actions ion-button ion-icon{position:relative;left:-1px}@media (max-width: var(--dcf-width-m)){ion-item #dcf-end,ion-item [slot=end]{display:none!important}}ion-item #dcf-end{padding-top:5px;display:flex;align-items:flex-end}ion-item .dcf-icon{display:flex;justify-content:center;align-items:center;text-align:center;margin-right:.5rem!important}ion-item .dcf-icon.dcf-grid-icon{min-width:50px;text-align:left;display:flex;justify-content:flex-start}@media (max-width: var(--dcf-width-s)){ion-item .dcf-icon{align-items:flex-start!important}}ion-item .dcf-icon ion-button ion-icon{font-size:20px}ion-avatar{width:48px;height:48px;display:flex;justify-content:center;align-items:center;text-align:center}ion-avatar ion-icon{font-size:20px}ion-avatar .dcf-icon-large{transform:translateY(5px)}\n"] }]
9897
10562
  }], ctorParameters: () => [], propDecorators: { component: [{
9898
10563
  type: ViewChild,
9899
10564
  args: ['component', { read: ElementRef, static: false }]
@@ -10091,7 +10756,7 @@ let SteppedFormComponent = class SteppedFormComponent extends NgxFormDirective {
10091
10756
  c.props['page'] = page > this.pages ? this.pages : page;
10092
10757
  return c;
10093
10758
  })];
10094
- this.getCurrentFormGroup(this.activeIndex);
10759
+ this.getActivePage(this.activeIndex);
10095
10760
  }
10096
10761
  else {
10097
10762
  this.children = this.pageTitles.map((page, index) => {
@@ -10104,6 +10769,12 @@ let SteppedFormComponent = class SteppedFormComponent extends NgxFormDirective {
10104
10769
  items
10105
10770
  };
10106
10771
  });
10772
+ // this.formGroup = new FormGroup(
10773
+ // (this.formGroup as FormArray).controls.reduce((acc, control, index) => {
10774
+ // acc[index] = control as FormGroup;
10775
+ // return acc;
10776
+ // }, {} as Record<string, FormGroup>)
10777
+ // );
10107
10778
  }
10108
10779
  this.initialized = true;
10109
10780
  }
@@ -10147,286 +10818,631 @@ let SteppedFormComponent = class SteppedFormComponent extends NgxFormDirective {
10147
10818
  * S->>P: submitEvent.emit({data, name: SUBMIT})
10148
10819
  * end
10149
10820
  *
10150
- * @memberOf SteppedFormComponent
10821
+ * @memberOf SteppedFormComponent
10822
+ */
10823
+ handleNext(lastPage = false) {
10824
+ const isValid = NgxFormService.validateFields(this.formGroup);
10825
+ // const isValid = this.paginated ?
10826
+ // NgxFormService.validateFields(this.formGroup as FormGroup) :
10827
+ // (this.formGroup as FormArray)?.controls.every(control => NgxFormService.validateFields(control as FormGroup));
10828
+ if (!lastPage) {
10829
+ if (isValid) {
10830
+ this.activeIndex = this.activeIndex + 1;
10831
+ this.getActivePage(this.activeIndex);
10832
+ }
10833
+ }
10834
+ else {
10835
+ if (isValid) {
10836
+ const rootForm = this.formGroup?.root || this.formGroup;
10837
+ const data = Object.assign({}, ...Object.values(NgxFormService.getFormData(rootForm)));
10838
+ this.submitEvent.emit({
10839
+ data,
10840
+ component: this.componentName,
10841
+ name: this.action || ComponentEventNames.SUBMIT,
10842
+ handlers: this.handlers,
10843
+ });
10844
+ }
10845
+ }
10846
+ }
10847
+ /**
10848
+ * @description Handles navigation to the previous page.
10849
+ * @summary Moves the user back to the previous page in the stepped form.
10850
+ * This method decrements the active page number and updates the form
10851
+ * group and children to display the previous page's content.
10852
+ *
10853
+ * @return {void}
10854
+ *
10855
+ * @mermaid
10856
+ * sequenceDiagram
10857
+ * participant U as User
10858
+ * participant S as SteppedFormComponent
10859
+ *
10860
+ * U->>S: Click Back
10861
+ * S->>S: activeIndex--
10862
+ * S->>S: getCurrentFormGroup(activeIndex)
10863
+ * Note over S: Update active form and children
10864
+ *
10865
+ * @memberOf SteppedFormComponent
10866
+ */
10867
+ handleBack() {
10868
+ if (!this.paginated)
10869
+ return this.location.back();
10870
+ this.activeIndex = this.activeIndex - 1;
10871
+ this.getActivePage(this.activeIndex);
10872
+ }
10873
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: SteppedFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
10874
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: SteppedFormComponent, isStandalone: true, selector: "ngx-decaf-stepped-form", inputs: { children: "children", paginated: "paginated", pages: "pages", pageTitles: "pageTitles", operation: "operation", startPage: "startPage" }, host: { properties: { "attr.id": "uid" } }, usesInheritance: true, ngImport: i0, template: "<form\n class=\"dcf-steped-form\"\n [class.paginated]=\"paginated\"\n novalidate\n #component\n>\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\n class=\"dcf-step\"\n [class.dcf-active]=\"activeIndex === $index + 1\"\n [class.dcf-passed]=\"$index + 1 < activeIndex\"\n >\n {{ $index + 1 }}\n </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\">\n {{ page?.description | translate }}\n </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\n width=\"8\"\n height=\"12\"\n viewBox=\"0 0 8 12\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\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 (\n pageTitles[activeIndex - 1]?.title ||\n pageTitles[activeIndex - 1]?.description\n ) {\n <div class=\"dcf-current-step\">\n <div>\n @if (pageTitles[activeIndex - 1]?.title) {\n <div class=\"dcf-title\">\n {{ pageTitles[activeIndex - 1]?.title | translate }}\n </div>\n }\n @if (pageTitles[activeIndex - 1]?.description) {\n <div class=\"dcf-description\">\n {{ pageTitles[activeIndex - 1]?.description | translate }}\n </div>\n }\n </div>\n </div>\n }\n\n @if (initialized && activePage?.length) {\n <ngx-decaf-layout\n [className]=\"'dcf-stepped-form-grid paginated dcf-grid-nested'\"\n [children]=\"activePage || []\"\n [parentForm]=\"formGroup || parentForm\"\n [gap]=\"'small'\"\n [flexMode]=\"props.flexMode || false\"\n [match]=\"false\"\n [cardBody]=\"cardBody\"\n [cardType]=\"cardType\"\n [rows]=\"rows\"\n [cols]=\"cols\"\n [match]=\"false\"\n />\n } @else {\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%\"\n ><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text\n ></ion-text>\n <br />\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%\"\n ><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text\n ></ion-text>\n }\n <div\n class=\"dcf-buttons-container dcf-grid dcf-grid-collapse dcf-flex dcf-flex-left\"\n >\n <div class=\"dcf-width-1-2@s\">\n <ion-button color=\"light\" (click)=\"handleBack()\" [disabled]=\"activeIndex <= 1\">{{ locale + \".previous\" | translate }}</ion-button>\n </div>\n\n <div class=\"dcf-width-1-2@s\">\n <ion-button fill=\"solid\" (click)=\"handleNext(activeIndex === pages ? true : false)\">\n @if (activeIndex === pages) {\n {{ locale + \".submit\" | translate }}\n } @else {\n {{ locale + \".next\" | translate }}\n }\n </ion-button>\n </div>\n </div>\n } @else {\n <div class=\"dcf-single-step\">\n @for (item of children; track $index) {\n <ngx-decaf-card\n [className]=\"className\"\n [body]=\"cardBody\"\n [type]=\"cardType\"\n >\n <div>\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\">\n {{ item.description | translate }}\n </div>\n }\n </div>\n </div>\n }\n <div [class.dcf-margin-bottom]=\"cardType === 'blank'\">\n @if (initialized && item.items?.length) {\n <ngx-decaf-layout\n [className]=\"'dcf-stepped-form-grid dcf-grid-nested'\"\n [children]=\"item.items || []\"\n [parentForm]=\"formGroup || parentForm\"\n [flexMode]=\"props.flexMode || false\"\n [gap]=\"'small'\"\n [cardBody]=\"cardBody\"\n [cardType]=\"cardType\"\n [rows]=\"rows\"\n [cols]=\"cols\"\n [match]=\"false\"\n />\n }\n </div>\n </div>\n </ngx-decaf-card>\n }\n <div\n class=\"dcf-buttons-container dcf-grid dcf-grid-small dcf-flex dcf-flex-right\"\n >\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}.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}.dcf-steped-form ::ng-deep ngx-decaf-component-renderer.ngx-decaf-fieldset,.dcf-steped-form ::ng-deep ngx-decaf-fieldset{padding-top:0!important;padding-bottom:0!important}.dcf-steped-form ::ng-deep ngx-decaf-component-renderer.ngx-decaf-fieldset ion-button,.dcf-steped-form ::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", "grid", "flexMode", "rowCard", "maxColsLength"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
10875
+ };
10876
+ SteppedFormComponent = __decorate([
10877
+ Dynamic(),
10878
+ __metadata("design:paramtypes", [])
10879
+ ], SteppedFormComponent);
10880
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: SteppedFormComponent, decorators: [{
10881
+ type: Component,
10882
+ args: [{ selector: 'ngx-decaf-stepped-form', imports: [
10883
+ TranslatePipe,
10884
+ ReactiveFormsModule,
10885
+ IonSkeletonText,
10886
+ IonText,
10887
+ IonButton,
10888
+ LayoutComponent
10889
+ ], standalone: true, host: { '[attr.id]': 'uid' }, template: "<form\n class=\"dcf-steped-form\"\n [class.paginated]=\"paginated\"\n novalidate\n #component\n>\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\n class=\"dcf-step\"\n [class.dcf-active]=\"activeIndex === $index + 1\"\n [class.dcf-passed]=\"$index + 1 < activeIndex\"\n >\n {{ $index + 1 }}\n </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\">\n {{ page?.description | translate }}\n </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\n width=\"8\"\n height=\"12\"\n viewBox=\"0 0 8 12\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\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 (\n pageTitles[activeIndex - 1]?.title ||\n pageTitles[activeIndex - 1]?.description\n ) {\n <div class=\"dcf-current-step\">\n <div>\n @if (pageTitles[activeIndex - 1]?.title) {\n <div class=\"dcf-title\">\n {{ pageTitles[activeIndex - 1]?.title | translate }}\n </div>\n }\n @if (pageTitles[activeIndex - 1]?.description) {\n <div class=\"dcf-description\">\n {{ pageTitles[activeIndex - 1]?.description | translate }}\n </div>\n }\n </div>\n </div>\n }\n\n @if (initialized && activePage?.length) {\n <ngx-decaf-layout\n [className]=\"'dcf-stepped-form-grid paginated dcf-grid-nested'\"\n [children]=\"activePage || []\"\n [parentForm]=\"formGroup || parentForm\"\n [gap]=\"'small'\"\n [flexMode]=\"props.flexMode || false\"\n [match]=\"false\"\n [cardBody]=\"cardBody\"\n [cardType]=\"cardType\"\n [rows]=\"rows\"\n [cols]=\"cols\"\n [match]=\"false\"\n />\n } @else {\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%\"\n ><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text\n ></ion-text>\n <br />\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%\"\n ><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text\n ></ion-text>\n }\n <div\n class=\"dcf-buttons-container dcf-grid dcf-grid-collapse dcf-flex dcf-flex-left\"\n >\n <div class=\"dcf-width-1-2@s\">\n <ion-button color=\"light\" (click)=\"handleBack()\" [disabled]=\"activeIndex <= 1\">{{ locale + \".previous\" | translate }}</ion-button>\n </div>\n\n <div class=\"dcf-width-1-2@s\">\n <ion-button fill=\"solid\" (click)=\"handleNext(activeIndex === pages ? true : false)\">\n @if (activeIndex === pages) {\n {{ locale + \".submit\" | translate }}\n } @else {\n {{ locale + \".next\" | translate }}\n }\n </ion-button>\n </div>\n </div>\n } @else {\n <div class=\"dcf-single-step\">\n @for (item of children; track $index) {\n <ngx-decaf-card\n [className]=\"className\"\n [body]=\"cardBody\"\n [type]=\"cardType\"\n >\n <div>\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\">\n {{ item.description | translate }}\n </div>\n }\n </div>\n </div>\n }\n <div [class.dcf-margin-bottom]=\"cardType === 'blank'\">\n @if (initialized && item.items?.length) {\n <ngx-decaf-layout\n [className]=\"'dcf-stepped-form-grid dcf-grid-nested'\"\n [children]=\"item.items || []\"\n [parentForm]=\"formGroup || parentForm\"\n [flexMode]=\"props.flexMode || false\"\n [gap]=\"'small'\"\n [cardBody]=\"cardBody\"\n [cardType]=\"cardType\"\n [rows]=\"rows\"\n [cols]=\"cols\"\n [match]=\"false\"\n />\n }\n </div>\n </div>\n </ngx-decaf-card>\n }\n <div\n class=\"dcf-buttons-container dcf-grid dcf-grid-small dcf-flex dcf-flex-right\"\n >\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}.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}.dcf-steped-form ::ng-deep ngx-decaf-component-renderer.ngx-decaf-fieldset,.dcf-steped-form ::ng-deep ngx-decaf-fieldset{padding-top:0!important;padding-bottom:0!important}.dcf-steped-form ::ng-deep ngx-decaf-component-renderer.ngx-decaf-fieldset ion-button,.dcf-steped-form ::ng-deep ngx-decaf-fieldset ion-button{margin-top:1rem!important}\n"] }]
10890
+ }], ctorParameters: () => [], propDecorators: { children: [{
10891
+ type: Input
10892
+ }], paginated: [{
10893
+ type: Input
10894
+ }], pages: [{
10895
+ type: Input
10896
+ }], pageTitles: [{
10897
+ type: Input
10898
+ }], operation: [{
10899
+ type: Input
10900
+ }], startPage: [{
10901
+ type: Input
10902
+ }] } });
10903
+
10904
+ const FileErrors = {
10905
+ notAllowed: 'not_allowed',
10906
+ maxSize: 'max_size',
10907
+ };
10908
+ /**
10909
+ * @description File upload component for Angular applications.
10910
+ * @summary This component provides a user interface for uploading files with support for drag-and-drop,
10911
+ * file validation, and preview functionality. It integrates seamlessly with Angular reactive forms
10912
+ * and supports multiple file uploads, directory mode, and custom file size limits.
10913
+ *
10914
+ * @class FileUploadComponent
10915
+ * @example
10916
+ * ```typescript
10917
+ * <ngx-decaf-file-upload [formGroup]="formGroup" [name]="'fileInput'" [multiple]="true"></ngx-decaf-file-upload>
10918
+ * ```
10919
+ * @mermaid
10920
+ * sequenceDiagram
10921
+ * participant User
10922
+ * participant FileUploadComponent
10923
+ * User->>FileUploadComponent: Select or drag files
10924
+ * FileUploadComponent->>FileUploadComponent: Validate files
10925
+ * FileUploadComponent->>FileUploadComponent: Emit change event
10926
+ * User->>FileUploadComponent: Remove file
10927
+ * FileUploadComponent->>FileUploadComponent: Update file list
10928
+ */
10929
+ let FileUploadComponent = class FileUploadComponent extends NgxFormFieldDirective {
10930
+ constructor() {
10931
+ super("FileUploadComponent");
10932
+ /**
10933
+ * @description Allows multiple file selection.
10934
+ * @summary When true, the user can select multiple files for upload.
10935
+ *
10936
+ * @type {boolean}
10937
+ * @default false
10938
+ */
10939
+ this.multiple = false;
10940
+ /**
10941
+ * @description Specifies the input type for the file upload field.
10942
+ * @summary Defines the type of input element used for file uploads, such as file or directory.
10943
+ *
10944
+ * @type {PossibleInputTypes}
10945
+ * @default HTML5InputTypes.FILE
10946
+ */
10947
+ this.type = HTML5InputTypes.FILE;
10948
+ /**
10949
+ * @description Size of the file upload component.
10950
+ * @summary Determines the visual size of the file upload component, such as large, small, or default.
10951
+ *
10952
+ * @type {Extract<ElementSize, 'large' | 'small' | 'default'>}
10953
+ * @default ElementSizes.large
10954
+ */
10955
+ this.size = ElementSizes.large;
10956
+ /**
10957
+ * @description Flex positioning of the container's content.
10958
+ * @summary Controls how child elements are positioned within the container when flex layout
10959
+ * is enabled. Options include 'center', 'top', 'bottom', 'left', 'right', and combinations
10960
+ * like 'top-left'. This property is only applied when the flex property is true.
10961
+ *
10962
+ * @type {FlexPosition}
10963
+ * @default 'center'
10964
+ */
10965
+ this.position = 'center';
10966
+ /**
10967
+ * @description Accepted file types for upload.
10968
+ * @summary Specifies the file types that are allowed for upload, such as images or documents.
10969
+ *
10970
+ * @type {string | string[]}
10971
+ * @default ['image/*']
10972
+ */
10973
+ this.accept = ['image/*'];
10974
+ /**
10975
+ * @description Whether to show an icon in the file upload field.
10976
+ * @summary When true, an icon is displayed alongside the file upload input.
10977
+ *
10978
+ * @type {boolean}
10979
+ * @default true
10980
+ */
10981
+ this.showIcon = true;
10982
+ /**
10983
+ * @description Enables directory mode for file uploads.
10984
+ * @summary When true, the user can upload entire directories instead of individual files.
10985
+ *
10986
+ * @type {boolean}
10987
+ * @default false
10988
+ */
10989
+ this.enableDirectoryMode = false;
10990
+ /**
10991
+ * @description Maximum file size allowed for upload.
10992
+ * @summary Specifies the maximum size (in MB) for files that can be uploaded.
10993
+ *
10994
+ * @type {number}
10995
+ * @default 1
10996
+ */
10997
+ this.maxFileSize = 1;
10998
+ /**
10999
+ * @description Event emitted when the file upload field changes.
11000
+ * @summary Emits an event containing details about the change in the file upload field.
11001
+ *
11002
+ * @type {EventEmitter<IBaseCustomEvent>}
11003
+ */
11004
+ this.changeEvent = new EventEmitter();
11005
+ /**
11006
+ * @description Preview of the first file in the upload list.
11007
+ * @summary Stores the data URL of the first file in the upload list for preview purposes.
11008
+ * This is typically used to display a thumbnail or preview image.
11009
+ *
11010
+ * @type {string | undefined}
11011
+ */
11012
+ this.preview = undefined;
11013
+ /**
11014
+ * @description List of files selected for upload.
11015
+ * @summary Contains the files selected by the user for upload. This array is updated
11016
+ * whenever files are added or removed from the upload list.
11017
+ *
11018
+ * @type {File[]}
11019
+ */
11020
+ this.files = [];
11021
+ /**
11022
+ * @description List of errors encountered during file validation.
11023
+ * @summary Stores validation errors for files that do not meet the specified criteria,
11024
+ * such as file type or size restrictions. Each error includes the file name, size, and error message.
11025
+ *
11026
+ * @type {IFileUploadError[]}
11027
+ */
11028
+ this.errors = [];
11029
+ /**
11030
+ * @description Indicates whether a drag operation is in progress.
11031
+ * @summary This flag is set to true when a file is being dragged over the upload area.
11032
+ * It is used to provide visual feedback to the user during drag-and-drop operations.
11033
+ *
11034
+ * @type {boolean}
11035
+ * @default false
11036
+ */
11037
+ this.dragging = false;
11038
+ /**
11039
+ * @description Counter for drag events.
11040
+ * @summary Tracks the number of drag events to ensure proper handling of drag-and-drop
11041
+ * operations. The counter is incremented on drag enter and decremented on drag leave.
11042
+ *
11043
+ * @type {number}
11044
+ * @default 0
11045
+ */
11046
+ this.dragCounter = 0;
11047
+ }
11048
+ /**
11049
+ * @description Lifecycle hook that is called after Angular has initialized all data-bound properties of a directive.
11050
+ * @summary Sets up the component by enabling directory mode if specified, formatting the accepted file types,
11051
+ * and converting the maximum file size from megabytes to bytes.
11052
+ *
11053
+ * @returns {void}
11054
+ */
11055
+ ngOnInit() {
11056
+ if (this.enableDirectoryMode) {
11057
+ this.multiple = true;
11058
+ }
11059
+ if (Array.isArray(this.accept)) {
11060
+ this.accept = this.accept.join(',');
11061
+ }
11062
+ // Convert maxFileSize from MB to bytes
11063
+ this.maxFileSize = this.maxFileSize * 1024 * 1024;
11064
+ }
11065
+ /**
11066
+ * @description Lifecycle hook that is called when a directive, pipe, or service is destroyed.
11067
+ * @summary Cleans up the component by calling the parent ngOnDestroy method and clearing the file upload state.
11068
+ *
11069
+ * @returns {Promise<void> | void}
11070
+ */
11071
+ ngOnDestroy() {
11072
+ super.ngOnDestroy();
11073
+ this.handleClear();
11074
+ }
11075
+ /**
11076
+ * @description Handles the click event to trigger file selection.
11077
+ * @summary Simulates a click on the hidden file input element to open the file selection dialog.
11078
+ * This method is used to allow users to select files programmatically.
11079
+ *
11080
+ * @returns {void}
11081
+ */
11082
+ handleClickToSelect() {
11083
+ const element = this.component.nativeElement;
11084
+ if (element)
11085
+ element.querySelector('#dcf-file-input')?.click();
11086
+ }
11087
+ /**
11088
+ * @description Handles the file selection event.
11089
+ * @summary Processes the files selected by the user, validates them, and updates the file list.
11090
+ * This method is triggered when the user selects files using the file input element.
11091
+ *
11092
+ * @param {Event} event - The file selection event.
11093
+ * @returns {void}
11094
+ */
11095
+ handleSelection(event) {
11096
+ this.clearErrors();
11097
+ const input = event.target;
11098
+ if (input.files) {
11099
+ const fileList = Array.from(input.files);
11100
+ this.handleSelectionConfirm(fileList);
11101
+ input.value = '';
11102
+ }
11103
+ }
11104
+ /**
11105
+ * @description Handles the drop event for drag-and-drop file uploads.
11106
+ * @summary Processes the files dropped by the user, validates them, and updates the file list.
11107
+ * This method is triggered when the user drops files onto the upload area.
11108
+ *
11109
+ * @param {DragEvent} event - The drag-and-drop event.
11110
+ * @returns {void}
11111
+ */
11112
+ handleDrop(event) {
11113
+ event.preventDefault();
11114
+ event.stopPropagation();
11115
+ this.dragCounter = 0;
11116
+ this.dragging = false;
11117
+ this.clearErrors();
11118
+ if (!event.dataTransfer)
11119
+ return;
11120
+ const fileList = Array.from(event.dataTransfer.files);
11121
+ this.handleSelectionConfirm(fileList);
11122
+ }
11123
+ /**
11124
+ * @description Handles the drag over event for drag-and-drop file uploads.
11125
+ * @summary Sets the dragging flag to true to provide visual feedback during drag-and-drop operations.
11126
+ * This method is triggered when the user drags files over the upload area.
11127
+ *
11128
+ * @param {DragEvent} event - The drag over event.
11129
+ * @returns {void}
11130
+ */
11131
+ handleDragOver(event) {
11132
+ event.preventDefault();
11133
+ event.stopPropagation();
11134
+ this.dragging = true;
11135
+ }
11136
+ /**
11137
+ * @description Handles the drag leave event for drag-and-drop file uploads.
11138
+ * @summary Decrements the drag counter and clears the dragging flag when the counter reaches zero.
11139
+ * This method is triggered when the user drags files out of the upload area.
11140
+ *
11141
+ * @param {DragEvent} event - The drag leave event.
11142
+ * @returns {void}
11143
+ */
11144
+ handleDragLeave(event) {
11145
+ event.preventDefault();
11146
+ event.stopPropagation();
11147
+ this.dragCounter = Math.max(0, this.dragCounter - 1);
11148
+ if (this.dragCounter === 0) {
11149
+ this.dragging = false;
11150
+ }
11151
+ }
11152
+ /**
11153
+ * @description Clears the file list and validation errors.
11154
+ * @summary Resets the file upload component by clearing the selected files, preview, and errors.
11155
+ * This method is used to reset the component state.
11156
+ *
11157
+ * @returns {void}
10151
11158
  */
10152
- handleNext(lastPage = false) {
10153
- const isValid = this.paginated ?
10154
- NgxFormService.validateFields(this.formGroup) :
10155
- this.formGroup?.controls.every(control => NgxFormService.validateFields(control));
10156
- if (!lastPage) {
10157
- if (isValid) {
10158
- this.activeIndex = this.activeIndex + 1;
10159
- this.getCurrentFormGroup(this.activeIndex);
11159
+ handleClear() {
11160
+ this.clearErrors();
11161
+ this.preview = undefined;
11162
+ this.files = [];
11163
+ }
11164
+ /**
11165
+ * @description Confirms the file selection and updates the component state.
11166
+ * @summary Validates each file in the selection, updates the file list, and emits
11167
+ * the change event. If multiple or directory mode is enabled, adds files to the existing list.
11168
+ * Otherwise, replaces the existing files with the new selection.
11169
+ *
11170
+ * @param {File[]} files - The array of files selected by the user.
11171
+ * @returns {Promise<void>}
11172
+ */
11173
+ async handleSelectionConfirm(files) {
11174
+ const validFiles = [];
11175
+ for (const file of files) {
11176
+ const isValid = this.validateFile(file);
11177
+ if (isValid === true) {
11178
+ validFiles.push(file);
10160
11179
  }
10161
- }
10162
- else {
10163
- if (isValid) {
10164
- const rootForm = this.formGroup?.root || this.formGroup;
10165
- const data = Object.assign({}, ...Object.values(NgxFormService.getFormData(rootForm)));
10166
- this.submitEvent.emit({
10167
- data,
10168
- component: this.componentName,
10169
- name: this.action || EventConstants.SUBMIT,
10170
- handlers: this.handlers,
11180
+ else {
11181
+ this.errors.push({
11182
+ name: file.name,
11183
+ error: isValid,
11184
+ size: file.size
10171
11185
  });
10172
11186
  }
10173
11187
  }
11188
+ if (this.multiple || this.enableDirectoryMode) {
11189
+ this.files = this.files.concat(validFiles);
11190
+ }
11191
+ else {
11192
+ this.files = [validFiles[0]];
11193
+ }
11194
+ if (this.files.length) {
11195
+ const dataValues = await this.getDataURLs(this.files);
11196
+ this.setValue(JSON.stringify(dataValues));
11197
+ }
11198
+ await this.getPreview();
11199
+ this.changeEventEmit();
11200
+ }
11201
+ /**
11202
+ * @description Validates a single file against the component's constraints.
11203
+ * @summary Checks the file type and size against the accepted values and limits.
11204
+ * Returns true if the file is valid, or an error code if it is not.
11205
+ *
11206
+ * @param {File} file - The file to be validated.
11207
+ * @returns {true | string} - Returns true if valid, error code otherwise.
11208
+ */
11209
+ validateFile(file) {
11210
+ if (this.accept && this.accept !== '*') {
11211
+ const acceptedExtensions = Array.isArray(this.accept) ?
11212
+ this.accept : this.accept.split(',').map(ext => ext.trim());
11213
+ const accept = acceptedExtensions.some(ext => {
11214
+ if (ext === '*')
11215
+ return true;
11216
+ if (ext.endsWith('/*'))
11217
+ return file.type.startsWith(ext.replace(/\/\*$/, ''));
11218
+ const fileExtension = file.type.split('/').pop() || '';
11219
+ return file.type === ext || fileExtension === ext || file.name.toLowerCase().endsWith(ext.replace('.', ''));
11220
+ });
11221
+ if (!accept)
11222
+ return FileErrors.notAllowed;
11223
+ }
11224
+ if (this.maxFileSize && file.size > this.maxFileSize)
11225
+ return FileErrors.maxSize;
11226
+ return true;
10174
11227
  }
10175
11228
  /**
10176
- * @description Handles navigation to the previous page.
10177
- * @summary Moves the user back to the previous page in the stepped form.
10178
- * This method decrements the active page number and updates the form
10179
- * group and children to display the previous page's content.
10180
- *
10181
- * @return {void}
10182
- *
10183
- * @mermaid
10184
- * sequenceDiagram
10185
- * participant U as User
10186
- * participant S as SteppedFormComponent
10187
- *
10188
- * U->>S: Click Back
10189
- * S->>S: activeIndex--
10190
- * S->>S: getCurrentFormGroup(activeIndex)
10191
- * Note over S: Update active form and children
11229
+ * @description Displays a preview of the selected file in a lightbox.
11230
+ * @summary If the file is an image, its data URL is retrieved and displayed in a modal lightbox.
11231
+ * The lightbox shows the image at its natural size, constrained to the viewport dimensions.
10192
11232
  *
10193
- * @memberOf SteppedFormComponent
11233
+ * @param {File | string} [file] - The file to be previewed. If not provided, the current preview file is used.
11234
+ * @returns {Promise<void>}
10194
11235
  */
10195
- handleBack() {
10196
- if (this.paginated) {
10197
- this.activeIndex = this.activeIndex - 1;
10198
- this.getCurrentFormGroup(this.activeIndex);
11236
+ async showFilePreview(file, fileExtension = 'image/') {
11237
+ let content;
11238
+ if (file instanceof File) {
11239
+ const dataUrl = await this.getDataURLs(file);
11240
+ if (dataUrl && dataUrl.length)
11241
+ file = dataUrl[0];
10199
11242
  }
10200
- this.location.back();
11243
+ if (fileExtension.includes('image/'))
11244
+ content = '<img src="' + file + '" style="max-width: 100%; height: auto;" />';
11245
+ if (fileExtension.includes('xml')) {
11246
+ const parseXml = (xmlString) => {
11247
+ try {
11248
+ xmlString = xmlString.replace(/^data:[^;]+;base64,/, '').replace(/\s+/g, '');
11249
+ const decodedString = atob(xmlString);
11250
+ const parser = new DOMParser();
11251
+ const xmlDoc = parser.parseFromString(decodedString, "text/xml");
11252
+ // const encoder = new TextEncoder(); // gera bytes UTF-8
11253
+ // const utf8Bytes = encoder.encode(xmlDoc.documentElement.outerHTML);
11254
+ // return new TextDecoder("utf-8").decode(utf8Bytes);
11255
+ return xmlDoc.documentElement.innerHTML;
11256
+ }
11257
+ catch (error) {
11258
+ this.logger.error(error?.message);
11259
+ return undefined;
11260
+ }
11261
+ };
11262
+ content = parseXml(file);
11263
+ content = `<div class="dfc-padding">${content}</div>`;
11264
+ }
11265
+ await presentNgxLightBoxModal(content || "");
10201
11266
  }
10202
11267
  /**
10203
- * @description Updates the active form group and children for the specified page.
10204
- * @summary Extracts the FormGroup for the given page from the FormArray and filters
10205
- * the children to show only fields belonging to that page. Uses a timer to ensure
10206
- * proper Angular change detection when updating the activeContent.
10207
- *
10208
- * @param {number} page - The page number to activate
10209
- * @return {void}
10210
- *
10211
- * @private
10212
- * @mermaid
10213
- * sequenceDiagram
10214
- * participant S as SteppedFormComponent
10215
- * participant F as FormArray
10216
- * participant T as Timer
11268
+ * @description Checks if a file is an image based on its MIME type.
11269
+ * @summary Determines if the file can be accepted as an image by checking
11270
+ * if its type starts with 'image/'.
10217
11271
  *
10218
- * S->>F: Extract FormGroup at index (page - 1)
10219
- * F-->>S: Return page FormGroup
10220
- * S->>S: Set activeContent = undefined
10221
- * S->>T: timer(10).subscribe()
10222
- * T-->>S: Filter children for active page
10223
- * S->>S: Set activeContent
10224
- *
10225
- * @memberOf SteppedFormComponent
11272
+ * @param {File} file - The file to be checked.
11273
+ * @returns {boolean} - True if the file is an image, false otherwise.
10226
11274
  */
10227
- getCurrentFormGroup(page) {
10228
- if (!(this.formGroup instanceof FormArray))
10229
- this.formGroup = this.formGroup?.parent;
10230
- this.formGroup = this.formGroup.at(page - 1);
10231
- this.activeContent = undefined;
10232
- this.timerSubscription = timer(10).subscribe(() => this.activeContent = this.children.filter(c => c.props?.['page'] === page));
10233
- }
10234
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: SteppedFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
10235
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: SteppedFormComponent, isStandalone: true, selector: "ngx-decaf-stepped-form", inputs: { children: "children", paginated: "paginated", pages: "pages", pageTitles: "pageTitles", operation: "operation", startPage: "startPage" }, host: { properties: { "attr.id": "uid" } }, usesInheritance: true, ngImport: i0, template: "<form class=\"dcf-steped-form\" [class.paginated]=\"paginated\" novalidate #component>\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]=\"activeIndex === $index + 1\" [class.dcf-passed]=\"($index + 1) < activeIndex\">{{ $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[activeIndex - 1]?.title || pageTitles[activeIndex - 1]?.description) {\n <div class=\"dcf-current-step\">\n <div>\n @if (pageTitles[activeIndex - 1]?.title) {\n <div class=\"dcf-title\">{{ pageTitles[activeIndex - 1]?.title | translate }}</div>\n }\n @if (pageTitles[activeIndex - 1]?.description) {\n <div class=\"dcf-description\">{{ pageTitles[activeIndex - 1]?.description | translate }}</div>\n }\n </div>\n </div>\n }\n\n @if (initialized && activeContent?.length) {\n <ngx-decaf-layout\n [className]=\"'dcf-stepped-form-grid paginated dcf-grid-nested'\"\n [children]=\"activeContent || []\"\n [parentForm]=\"formGroup || parentForm\"\n [gap]=\"'small'\"\n [flexMode]=\"props.flexMode || false\"\n [match]=\"false\"\n [rows]=\"rows\"\n [cols]=\"cols\"\n [match]=\"false\"\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]=\"activeIndex <= 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(activeIndex === pages ? true : false)\">\n @if (activeIndex === 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 [className]=\"'dcf-stepped-form-grid dcf-grid-nested'\"\n [children]=\"item.items || []\"\n [parentForm]=\"formGroup || parentForm\"\n [flexMode]=\"props.flexMode || false\"\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}.dcf-steped-form ::ng-deep ngx-decaf-component-renderer.ngx-decaf-fieldset,.dcf-steped-form ::ng-deep ngx-decaf-fieldset{padding-top:0!important;padding-bottom:0!important}.dcf-steped-form ::ng-deep ngx-decaf-component-renderer.ngx-decaf-fieldset ion-button,.dcf-steped-form ::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", "flexMode", "rowCard", "maxColsLength"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
10236
- };
10237
- SteppedFormComponent = __decorate([
10238
- Dynamic(),
10239
- __metadata("design:paramtypes", [])
10240
- ], SteppedFormComponent);
10241
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: SteppedFormComponent, decorators: [{
10242
- type: Component,
10243
- args: [{ selector: 'ngx-decaf-stepped-form', imports: [
10244
- TranslatePipe,
10245
- ReactiveFormsModule,
10246
- IonSkeletonText,
10247
- IonText,
10248
- IonButton,
10249
- LayoutComponent
10250
- ], standalone: true, host: { '[attr.id]': 'uid' }, template: "<form class=\"dcf-steped-form\" [class.paginated]=\"paginated\" novalidate #component>\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]=\"activeIndex === $index + 1\" [class.dcf-passed]=\"($index + 1) < activeIndex\">{{ $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[activeIndex - 1]?.title || pageTitles[activeIndex - 1]?.description) {\n <div class=\"dcf-current-step\">\n <div>\n @if (pageTitles[activeIndex - 1]?.title) {\n <div class=\"dcf-title\">{{ pageTitles[activeIndex - 1]?.title | translate }}</div>\n }\n @if (pageTitles[activeIndex - 1]?.description) {\n <div class=\"dcf-description\">{{ pageTitles[activeIndex - 1]?.description | translate }}</div>\n }\n </div>\n </div>\n }\n\n @if (initialized && activeContent?.length) {\n <ngx-decaf-layout\n [className]=\"'dcf-stepped-form-grid paginated dcf-grid-nested'\"\n [children]=\"activeContent || []\"\n [parentForm]=\"formGroup || parentForm\"\n [gap]=\"'small'\"\n [flexMode]=\"props.flexMode || false\"\n [match]=\"false\"\n [rows]=\"rows\"\n [cols]=\"cols\"\n [match]=\"false\"\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]=\"activeIndex <= 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(activeIndex === pages ? true : false)\">\n @if (activeIndex === 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 [className]=\"'dcf-stepped-form-grid dcf-grid-nested'\"\n [children]=\"item.items || []\"\n [parentForm]=\"formGroup || parentForm\"\n [flexMode]=\"props.flexMode || false\"\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}.dcf-steped-form ::ng-deep ngx-decaf-component-renderer.ngx-decaf-fieldset,.dcf-steped-form ::ng-deep ngx-decaf-fieldset{padding-top:0!important;padding-bottom:0!important}.dcf-steped-form ::ng-deep ngx-decaf-component-renderer.ngx-decaf-fieldset ion-button,.dcf-steped-form ::ng-deep ngx-decaf-fieldset ion-button{margin-top:1rem!important}\n"] }]
10251
- }], ctorParameters: () => [], propDecorators: { children: [{
10252
- type: Input
10253
- }], paginated: [{
10254
- type: Input
10255
- }], pages: [{
10256
- type: Input
10257
- }], pageTitles: [{
10258
- type: Input
10259
- }], operation: [{
10260
- type: Input
10261
- }], startPage: [{
10262
- type: Input
10263
- }] } });
10264
-
10265
- let ModalComponent = class ModalComponent extends NgxParentComponentDirective {
10266
- constructor() {
10267
- super("ModalComponent");
10268
- this.isOpen = false;
10269
- this.InlineContentPosition = 'bottom';
10270
- this.fullscreen = false;
10271
- this.modalController = inject(ModalController);
10272
- addIcons(allIcons);
10273
- }
10274
- async ngOnInit() {
10275
- if (!this.modalController)
10276
- this.modalController = modalController;
10277
- }
10278
- async initialize(options = {}) {
10279
- if (!this.modalController)
10280
- this.modalController = modalController;
10281
- this.options = Object.assign({}, DefaultModalOptions, this.options, options);
10282
- this.initialized = true;
11275
+ isImageFile(file) {
11276
+ return file && file.type.startsWith('image/');
10283
11277
  }
10284
- async create(props = {}) {
10285
- if (!this.initialized)
10286
- await this.initialize(props);
10287
- return this;
11278
+ /**
11279
+ * @description Removes a file from the selection.
11280
+ * @summary Updates the file list to exclude the file at the specified index.
11281
+ * Emits the change event and updates the preview if necessary.
11282
+ *
11283
+ * @param {number} index - The index of the file to be removed.
11284
+ * @returns {Promise<void>}
11285
+ */
11286
+ async removeFile(index) {
11287
+ if (index <= this.files.length)
11288
+ this.files = [...this.files.filter((_, i) => i !== index)];
11289
+ await this.getPreview();
11290
+ this.changeEventEmit();
10288
11291
  }
10289
- present() {
10290
- this.isOpen = true;
10291
- this.changeDetectorRef.detectChanges();
11292
+ /**
11293
+ * @description Retrieves the preview image for the selected files.
11294
+ * @summary If the first selected file is an image, its data URL is retrieved and set as the preview.
11295
+ * If the file is not an image, the preview is cleared.
11296
+ *
11297
+ * @returns {Promise<void>}
11298
+ */
11299
+ async getPreview() {
11300
+ this.preview = undefined;
11301
+ const file = this.files && this.files.length ? this.files[0] : null;
11302
+ if (file) {
11303
+ const dataUrl = await this.getDataURLs(file);
11304
+ if (dataUrl && dataUrl.length)
11305
+ this.preview = dataUrl[0];
11306
+ }
10292
11307
  }
10293
- async handleEvent(event) {
10294
- if (event instanceof Event)
10295
- event.stopImmediatePropagation();
10296
- console.log(event);
10297
- }
10298
- handleWillDismiss(event) {
10299
- const { data, role } = event.detail;
10300
- this.listenEvent.emit({
10301
- name: role,
10302
- component: "ModalComponent",
10303
- data: data
11308
+ /**
11309
+ * @description Emits the change event for the file upload field.
11310
+ * @summary Triggers the change event, notifying any listeners that the value has changed.
11311
+ * The event contains the updated value, component name, and event type.
11312
+ *
11313
+ * @returns {void}
11314
+ */
11315
+ changeEventEmit() {
11316
+ this.changeEvent.emit({
11317
+ data: this.value,
11318
+ component: this.componentName,
11319
+ name: ComponentEventNames.CHANGE,
10304
11320
  });
10305
11321
  }
10306
- async cancel() {
10307
- this.modalController.dismiss(null, ActionRoles.cancel, this.uid);
10308
- this.isOpen = false;
10309
- }
10310
- async confirm(event) {
10311
- await this.modalController.dismiss(this.name, ActionRoles.confirm, this.uid);
10312
- this.isOpen = false;
10313
- }
10314
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: ModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
10315
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: ModalComponent, isStandalone: true, selector: "ngx-decaf-modal", inputs: { title: "title", isOpen: "isOpen", options: "options", globals: "globals", inlineContent: "inlineContent", InlineContentPosition: "InlineContentPosition", fullscreen: "fullscreen" }, host: { properties: { "attr.id": "uid" } }, usesInheritance: true, ngImport: i0, template: "<ion-modal [id]=\"uid\"\n [isOpen]=\"isOpen\"\n (willDismiss)=\"handleWillDismiss($event)\"\n [backdropDismiss]=\"options?.backdropDismiss\"\n [showBackdrop]=\"options?.showBackdrop\"\n [animated]=\"options?.animated\"\n [canDismiss]=\"options?.canDismiss\"\n [class.dcf-fullscreen-modal]=\"fullscreen\"\n >\n <ng-template>\n <ion-header>\n <ion-toolbar>\n @if (title) {\n <ion-title>{{title | translate}}</ion-title>\n }\n <ion-buttons slot=\"end\">\n <ion-button type=\"button\" class=\"dcf-button-close\" (click)=\"cancel()\">\n <ion-icon name=\"close-outline\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"dcf-modal-body\">\n @if (model) {\n <ngx-decaf-model-renderer (onIonChange)=\"handleEvent($event)\" (listenEvent)=\"handleEvent($event)\" [model]=\"model\" [globals]=\"globals\" />\n\n } @else {\n <div class=\"dcf-loading-container\">\n <ion-spinner name=\"crescent\" color=\"primary\" ></ion-spinner>\n </div>\n }\n\n </section>\n\n </ion-content>\n </ng-template>\n</ion-modal>\n", styles: [".dcf-modal-body{height:100%;padding:1.5rem 1rem}.dcf-loading-container{height:50%;display:flex;justify-content:center;align-items:center}.dcf-loading-container ion-spinner{width:60px;height:60px}ion-modal.dcf-fullscreen-modal{--height: 100%;--width: 100%;--max-width: 100%;--border-radius: 0}\n"], dependencies: [{ kind: "component", type: IonModal, selector: "ion-modal" }, { kind: "component", type: ModelRendererComponent, selector: "ngx-decaf-model-renderer", inputs: ["projectable"] }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { 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: IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
10316
- };
10317
- ModalComponent = __decorate([
10318
- Dynamic(),
10319
- __metadata("design:paramtypes", [])
10320
- ], ModalComponent);
10321
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: ModalComponent, decorators: [{
10322
- type: Component,
10323
- args: [{ selector: 'ngx-decaf-modal', standalone: true, imports: [IonModal, ModelRendererComponent, TranslatePipe, IonSpinner, IonButton, IonButtons, IonContent, IonHeader, IonTitle, IonToolbar], host: { '[attr.id]': 'uid' }, template: "<ion-modal [id]=\"uid\"\n [isOpen]=\"isOpen\"\n (willDismiss)=\"handleWillDismiss($event)\"\n [backdropDismiss]=\"options?.backdropDismiss\"\n [showBackdrop]=\"options?.showBackdrop\"\n [animated]=\"options?.animated\"\n [canDismiss]=\"options?.canDismiss\"\n [class.dcf-fullscreen-modal]=\"fullscreen\"\n >\n <ng-template>\n <ion-header>\n <ion-toolbar>\n @if (title) {\n <ion-title>{{title | translate}}</ion-title>\n }\n <ion-buttons slot=\"end\">\n <ion-button type=\"button\" class=\"dcf-button-close\" (click)=\"cancel()\">\n <ion-icon name=\"close-outline\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class=\"ion-padding\">\n <section class=\"dcf-modal-body\">\n @if (model) {\n <ngx-decaf-model-renderer (onIonChange)=\"handleEvent($event)\" (listenEvent)=\"handleEvent($event)\" [model]=\"model\" [globals]=\"globals\" />\n\n } @else {\n <div class=\"dcf-loading-container\">\n <ion-spinner name=\"crescent\" color=\"primary\" ></ion-spinner>\n </div>\n }\n\n </section>\n\n </ion-content>\n </ng-template>\n</ion-modal>\n", styles: [".dcf-modal-body{height:100%;padding:1.5rem 1rem}.dcf-loading-container{height:50%;display:flex;justify-content:center;align-items:center}.dcf-loading-container ion-spinner{width:60px;height:60px}ion-modal.dcf-fullscreen-modal{--height: 100%;--width: 100%;--max-width: 100%;--border-radius: 0}\n"] }]
10324
- }], ctorParameters: () => [], propDecorators: { title: [{
10325
- type: Input
10326
- }], isOpen: [{
10327
- type: Input
10328
- }], options: [{
10329
- type: Input
10330
- }], globals: [{
10331
- type: Input
10332
- }], inlineContent: [{
10333
- type: Input
10334
- }], InlineContentPosition: [{
10335
- type: Input
10336
- }], fullscreen: [{
10337
- type: Input
10338
- }] } });
10339
- async function getNgxModalComponent(props = {}, modalProps = {}, injector) {
10340
- const { globals } = { ...props };
10341
- if (!globals || !globals?.['operation'])
10342
- props.globals = { ...(globals || {}), operation: OperationKeys.CREATE };
10343
- const component = NgxRenderingEngine.createComponent(ModalComponent, props, injector || undefined);
10344
- return component.create(modalProps);
10345
- }
10346
-
10347
- class NgxSvgDirective {
10348
- constructor() {
10349
- this.mediaService = inject(NgxMediaService);
10350
- this.element = inject(ElementRef);
10351
- this.http = inject(HttpClient);
10352
- }
10353
- ngOnInit() {
10354
- this.path = this.path?.trim() || this.element?.nativeElement?.getAttribute('src')?.trim() || '';
10355
- if (this.path)
10356
- this.mediaService.loadSvgObserver(this.http, this.path, this.element.nativeElement);
10357
- }
10358
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: NgxSvgDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
10359
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.9", type: NgxSvgDirective, isStandalone: true, selector: "[ngx-decaf-svg]", inputs: { path: ["ngx-decaf-svg", "path"] }, ngImport: i0 }); }
10360
- }
10361
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: NgxSvgDirective, decorators: [{
10362
- type: Directive,
10363
- args: [{
10364
- selector: '[ngx-decaf-svg]',
10365
- standalone: true
10366
- }]
10367
- }], propDecorators: { path: [{
10368
- type: Input,
10369
- args: ['ngx-decaf-svg']
10370
- }] } });
10371
-
10372
- let IconComponent = class IconComponent {
10373
- constructor() {
10374
- this.color = "";
10375
- this.slot = 'icon-only';
10376
- this.button = false;
10377
- this.buttonFill = 'clear';
10378
- this.buttonShape = 'round';
10379
- this.size = 'default';
10380
- this.type = 'ionic';
10381
- this.isSvg = false;
10382
- this.initialized = false;
10383
- this.inline = false;
10384
- this.mediaService = new NgxMediaService$1();
10385
- addIcons(allIcons);
11322
+ /**
11323
+ * @description Retrieves the data URLs for the selected files.
11324
+ * @summary Converts the selected image files to data URLs using FileReader.
11325
+ * The resulting data URLs can be used for previewing images in the browser.
11326
+ *
11327
+ * @param {File[] | File} [files] - The files for which to generate data URLs.
11328
+ * If not provided, the currently selected files are used.
11329
+ *
11330
+ * @returns {Promise<string[] | undefined>} - A promise that resolves to an array of data URLs, or undefined if an error occurs.
11331
+ */
11332
+ async getDataURLs(files) {
11333
+ if (!files)
11334
+ files = this.files;
11335
+ if (!Array.isArray(files))
11336
+ files = [files];
11337
+ // files = files.filter(f => f.type && f.type.startsWith('image/'));
11338
+ return this.readFile(files).then(urls => {
11339
+ // validate generated DataURLs
11340
+ const invalid = urls.some(u => !this.isValidDataURL(u));
11341
+ if (invalid)
11342
+ return undefined;
11343
+ if (this.multiple || this.enableDirectoryMode)
11344
+ return urls;
11345
+ return urls.length ? [urls[0]] : undefined;
11346
+ }).catch(() => {
11347
+ return undefined;
11348
+ });
10386
11349
  }
10387
- ngOnInit() {
10388
- if (this.button)
10389
- this.slot = 'icon-only';
10390
- if (this.name?.includes('.')) {
10391
- this.type = 'image';
10392
- this.isSvg = this.name.endsWith('.svg');
11350
+ /**
11351
+ * @description Validates the format of a data URL.
11352
+ * @summary Checks if the data URL is a non-empty string and matches the expected pattern
11353
+ * for base64-encoded image data URLs. Uses a regular expression to validate the format.
11354
+ *
11355
+ * @param {string | undefined} dataURL - The data URL to be validated.
11356
+ * @returns {boolean} - True if the data URL is valid, false otherwise.
11357
+ */
11358
+ isValidDataURL(dataURL) {
11359
+ if (!dataURL || typeof dataURL !== 'string') {
11360
+ return false;
11361
+ }
11362
+ // Regex para qualquer MIME type seguido de ;base64
11363
+ const match = dataURL.match(/^data:([a-zA-Z0-9.+-\\/]+);base64,([A-Za-z0-9+/=\s]+)$/);
11364
+ if (!match)
11365
+ return false;
11366
+ const payload = match[2];
11367
+ try {
11368
+ if (typeof atob === 'function') {
11369
+ // remove espaços e tenta decodificar
11370
+ atob(payload.replace(/\s+/g, ''));
11371
+ }
11372
+ return true;
11373
+ }
11374
+ catch {
11375
+ return false;
10393
11376
  }
10394
- this.initialized = true;
10395
11377
  }
10396
- ngAfterViewInit() {
10397
- this.mediaService.setDarkMode(this.component.nativeElement);
11378
+ /**
11379
+ * @description Clears all error messages from the component.
11380
+ * @summary Resets the error state, removing all error messages from the display.
11381
+ *
11382
+ * @returns {void}
11383
+ */
11384
+ clearErrors() {
11385
+ this.errors = [];
10398
11386
  }
10399
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: IconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
10400
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: IconComponent, isStandalone: true, selector: "ngx-decaf-icon", inputs: { name: "name", color: "color", slot: "slot", button: "button", buttonFill: "buttonFill", buttonShape: "buttonShape", width: "width", size: "size", inline: "inline" }, host: { properties: { "attr.id": "uid" } }, viewQueries: [{ propertyName: "component", first: true, predicate: ["component"], descendants: true, read: ElementRef }], ngImport: i0, template: "<div class=\"dcf-icon\" #component>\n @if(initialized) {\n @if(button) {\n <ion-button\n [fill]=\"buttonFill\"\n [shape]=\"buttonShape\"\n [color]=\"color\">\n @if(type === 'image') {\n @if(isSvg) {\n <span\n aria-hidden=\"true\"\n [slot]=\"slot\"\n [class]=\"color ? 'dcf-color-' + color : ''\"\n [style.width]=\"width\"\n [ngx-decaf-svg]=\"name\">\n ></span>\n } @else {\n <img\n aria-hidden=\"true\" [alt]=\"name\" [title]=\"name\" [slot]=\"slot\" [src]=\"name\" [style.width]=\"width\" title=\"icon\" />\n }\n\n } @else {\n <ion-icon\n aria-hidden=\"true\"\n [slot]=\"slot\"\n [ios]=\"name\"\n [md]=\"name\"\n [size]=\"size\"\n [color]=\"color\"\n [name]=\"name\" />\n }\n </ion-button>\n } @else {\n @if(type === 'image') {\n @if(isSvg) {\n <span\n aria-hidden=\"true\"\n [slot]=\"slot\"\n [class]=\"color ? 'dcf-color-' + color : ''\"\n [style.width]=\"width\"\n [ngx-decaf-svg]=\"name\"\n\n >\n </span>\n } @else {\n <img aria-hidden=\"true\" [alt]=\"name\" [title]=\"name\" [slot]=\"slot\" [src]=\"name\" [style.width]=\"width\" title=\"icon\" />\n }\n }\n @if(type === 'ionic') {\n\n <ion-icon\n aria-hidden=\"true\"\n [slot]=\"slot\"\n [ios]=\"name\"\n [md]=\"name\"\n [size]=\"size\"\n [color]=\"color\"\n [name]=\"name\" />\n\n }\n }\n }\n</div>\n", styles: ["::ng-deep .dcf-icon.dcf-palette-dark ion-icon{color:var(--dcf-text-color)!important}::ng-deep .dcf-icon.dcf-palette-dark svg{fill:var(--dcf-text-color);fill-opacity:.25!important;stroke:var(--dcf-text-color)!important}::ng-deep .dcf-icon.dcf-palette-dark svg *{fill:var(--dcf-color-primary)!important;stroke:var(--dcf-color-gray-1)!important}.dcf-icon ion-icon:not([size]){font-size:1.35rem!important}\n"], dependencies: [{ kind: "directive", type: NgxSvgDirective, selector: "[ngx-decaf-svg]", inputs: ["ngx-decaf-svg"] }, { 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"] }] }); }
11387
+ /**
11388
+ * @description Reads the selected files as data URLs.
11389
+ * @summary Uses the FileReader API to read each file as a data URL.
11390
+ * Returns a promise that resolves to an array of data URLs.
11391
+ *
11392
+ * @param {File[]} files - The files to be read.
11393
+ * @returns {Promise<string[]>} - A promise that resolves to an array of data URLs.
11394
+ */
11395
+ readFile(files) {
11396
+ return Promise.all(files.map(file => new Promise((resolve, reject) => {
11397
+ const reader = new FileReader();
11398
+ reader.onerror = () => reject(reader.error);
11399
+ reader.onload = () => resolve(String(reader.result || ''));
11400
+ reader.readAsDataURL(file);
11401
+ })));
11402
+ }
11403
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: FileUploadComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
11404
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: FileUploadComponent, isStandalone: true, selector: "ngx-decaf-file-upload", inputs: { formGroup: "formGroup", name: "name", formControl: "formControl", required: "required", multiple: "multiple", type: "type", label: "label", buttonLabel: "buttonLabel", size: "size", position: "position", accept: "accept", showIcon: "showIcon", enableDirectoryMode: "enableDirectoryMode", maxFileSize: "maxFileSize" }, outputs: { changeEvent: "changeEvent" }, viewQueries: [{ propertyName: "component", first: true, predicate: ["component"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"decaf-file-component\" #component>\n <input\n id=\"dcf-file-input\"\n type=\"file\"\n placeholder=\"Select files\"\n [attr.accept]=\"accept\"\n [attr.multiple]=\"multiple ? true : null\"\n (change)=\"handleSelection($event)\"\n [multiple]=\"multiple\"\n hidden\n [attr.webkitdirectory]=\"enableDirectoryMode ? true : null\"\n />\n\n <ngx-decaf-card [className]=\"className\" [body]=\"'blank'\">\n <div>\n <div\n [class]=\"\n 'dcf-drop-area '\n + ' dcf-' + size\n + ' dcf-flex dcf-flex-' + position\n + ' dcf-text-' + position\n \"\n\n [class.dcf-dragging]=\"dragging\"\n [class.dcf-has-files]=\"files.length\"\n (drop)=\"!files?.length ? handleDrop($event) : dragging = false\"\n (dragover)=\"!files?.length ? handleDragOver($event) : dragging = false\"\n (dragleave)=\"!files?.length ? handleDragLeave($event) : dragging = false\"\n >\n <div>\n @if (!preview) {\n @if(showIcon) {\n <ngx-decaf-icon name=\"cloud-upload-outline\" size=\"large\" />\n }\n <p class=\"dcf-drag-description\">{{ label ? (label | translate) : (locale + \".drag_file\" | translate) }}</p>\n <ion-button class=\"dcf-button-select\" (click)=\"handleClickToSelect()\" size=\"small\">\n {{ buttonLabel ? (buttonLabel | translate) : (locale + \".buttons.select\" | translate) }}\n </ion-button>\n <div #container>\n <span class=\"dcf-error\" [innerHTML]=\"getErrors(container)\"></span>\n </div>\n } @else {\n @if ((!directoryMode && !multiple) ) {\n <div class=\"dcf-preview dcf-grid dcf-grid-match dcf-grid-collapse\">\n <div class=\"dcf-width-1-4@m dcf-width-1-3@s dcf-flex dcf-flex-center dcf-flex-middle\">\n <div class=\"dcf-preview-image\">\n <ion-img\n [src]=\"preview\"\n [title]=\"locale + '.preview' | translate\"\n [alt]=\"locale + '.preview' | translate\"\n />\n <div class=\"dcf-overlay\">\n <ion-button (click)=\"showFilePreview(preview)\" fill=\"clear\" color=\"light\" size=\"small\">\n {{ locale + \".buttons.preview\" | translate }}\n </ion-button>\n </div>\n </div>\n </div>\n <div class=\"description dcf-flex dcf-flex-middle dcf-width-expand@s\">\n <div>\n <p class=\"dcf-title\">{{ locale + \".preview\" | translate }}</p>\n <p class=\"subtitle\">{{ files[0].name }}</p>\n <ion-button (click)=\"handleClear()\" fill=\"clear\" color=\"danger\" size=\"small\">{{ locale + \".buttons.clear\" | translate }} </ion-button>\n </div>\n </div>\n </div>\n } @else {\n <div class=\"dcf-margin-bottom\">\n {{ locale + \".selection\" | translate: { \"0\": files.length > 10 ? files.length : `0${files.length}` } }}\n @if(errors.length > 0) {\n <br /><span class=\"dcf-error-message\">{{ locale + \".selection_error\" | translate: { \"0\": errors.length > 10 ? errors.length : `0${errors.length}` } }}</span>\n }\n </div>\n <div class=\"dcf-preview-list-container\">\n <ion-list class=\"dcf-preview-list\">\n @for (file of errors; track $index) {\n <ion-item lines=\"full\" class=\"dcf-error-item\">\n <ion-label slot=\"start\">{{ file.name }}</ion-label>\n <div class=\"dcf-error-message\" slot=\"end\">\n {{ locale + \".errors.\" + file.error | translate: { \"0\": file.error === 'max_size' ? maxFileSize / 1024 / 1024 : file.name.split(\".\") } }}\n </div>\n <ion-note slot=\"end\">{{ file.size / 1024 / 1024 | number: \"1.1-1\" }} MB</ion-note>\n </ion-item>\n }\n\n @for (file of files; track $index) {\n <ion-item lines=\"full\">\n <ion-label slot=\"start\">{{ file.name }}</ion-label>\n <ion-note slot=\"end\">{{ file.size / 1024 / 1024 | number: \"1.1-1\" }} MB</ion-note>\n <div class=\"dcf-flex dcf-flex-middle\" slot=\"end\">\n <ngx-decaf-icon\n [button]=\"true\"\n [slot]=\"'icon-only'\"\n (click)=\"showFilePreview(file, file.type)\"\n [name]=\"'image-outline'\"\n />\n <ngx-decaf-icon\n [button]=\"true\"\n [slot]=\"'icon-only'\"\n [name]=\"'trash-outline'\"\n (click)=\"removeFile($index)\"\n [color]=\"'danger'\"\n [size]=\"'small'\"\n />\n </div>\n </ion-item>\n }\n </ion-list>\n </div>\n }\n }\n </div>\n\n\n </div>\n </div>\n </ngx-decaf-card>\n</div>\n\n<!-- <ion-card-header>\n <ion-card-title>Upload de Imagem</ion-card-title>\n </ion-card-header>\n\n <ion-card-content>\n <div\n class=\"dcf-drop-area\"\n [class.dragging]=\"dragging\"\n (drop)=\"onDrop($event)\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n >\n <div class=\"dcf-drop-content\">\n <ion-icon name=\"cloud-upload-outline\" size=\"large\"></ion-icon>\n <p>Arraste e solte aqui ou</p>\n <ion-button size=\"small\" fill=\"outline\" (click)=\"triggerFileSelect()\">Selecionar arquivo</ion-button>\n </div>\n </div>\n\n <input\n #fileInput\n type=\"file\"\n [attr.accept]=\"accept\"\n [attr.multiple]=\"multiple ? true : null\"\n (change)=\"onFileSelected($event)\"\n hidden\n />\n\n <div *ngIf=\"previewUrl\" class=\"dcf-preview\">\n <ion-item>\n <div slot=\"start\">\n <ion-img [src]=\"previewUrl\"></ion-img>\n </div>\n <ion-label>\n <h3>Pr\u00E9-visualiza\u00E7\u00E3o</h3>\n <p *ngIf=\"files.length\">{{ files[0].name }}</p>\n </ion-label>\n </ion-item>\n </div>\n\n <ion-list *ngIf=\"files.length\">\n <ion-list-header>\n <ion-label>Arquivos selecionados</ion-label>\n </ion-list-header>\n <ion-item *ngFor=\"let f of files; let i = index\">\n <ion-label>{{ f.name }}</ion-label>\n <ion-note slot=\"end\">{{ (f.size / 1024 / 1024) | number:'1.1-1' }} MB</ion-note>\n <ion-button fill=\"clear\" slot=\"end\" (click)=\"removeFile(i)\">\n <ion-icon slot=\"icon-only\" name=\"close-circle\"></ion-icon>\n </ion-button>\n </ion-item>\n </ion-list>\n\n <div *ngIf=\"errors.length\">\n <ion-list>\n <ion-item *ngFor=\"let err of errors\">\n <ion-icon name=\"alert-circle\" slot=\"start\" color=\"danger\"></ion-icon>\n <ion-label color=\"danger\">{{ err }}</ion-label>\n </ion-item>\n </ion-list>\n </div>\n\n <ion-row class=\"dcf-actions\">\n <ion-col>\n <ion-button expand=\"block\" (click)=\"triggerFileSelect()\">Selecionar</ion-button>\n </ion-col>\n <ion-col>\n <ion-button expand=\"block\" color=\"danger\" fill=\"outline\" (click)=\"clear()\">Limpar</ion-button>\n </ion-col>\n </ion-row>\n </ion-card-content> -->\n", styles: [".decaf-file-component.dcf-palette-dark .dcf-button-select{--background: rgb(var(--dcf-color-light-rgb), .1) !important;--background-hover: rgb(var(--dcf-color-light-rgb), .75) !important;--background-activated: rgb(var(--dcf-color-light-rgb), .4) !important;--background-focused: rgb(var(--dcf-color-light-rgb), .4) !important;--color: var(--dcf-color-light) !important}.decaf-file-component.dcf-palette-dark .dcf-has-files{border-style:solid;border-color:var(--dcf-color-gray-6)!important}.decaf-file-component .dcf-upload-icon{--box-shadow: none !important}.decaf-file-component .dcf-upload-icon ion-icon{width:1.5rem!important}.decaf-file-component ion-button.dcf-button-select{--background: rgb(var(--dcf-color-primary-rgb), .1);--background-hover: rgb(var(--dcf-color-primary-rgb), .75);--background-activated: rgb(var(--dcf-color-primary-rgb), .4);--background-focused: rgb(var(--dcf-color-primary-rgb), .4);--color: var(--dcf-color-primary-shade);--border-radius: var(--dcf-border-radius-small);--box-shadow: none;--padding-top: var(--dcf-padding-xsmall);--padding-bottom: var(--dcf-padding-xsmall);--padding-start: var(--dcf-padding-small);--padding-end: var(--dcf-padding-small);font-weight:500;text-transform:none;margin-top:var(--dcf-margin-small)!important}.decaf-file-component .dcf-error{color:var(--dcf-color-danger)!important;font-size:.8rem!important;font-weight:500!important;line-height:1.1rem;z-index:9999;animation-duration:.05s;animation-timing-function:ease-in;animation-fill-mode:both;animation-name:fadeBottomSmallAnimation}.decaf-file-component .dcf-error .ti,.decaf-file-component .dcf-error ion-icon{position:relative;top:2px!important;min-width:20px;font-size:1rem!important;text-align:left}.decaf-file-component ion-card-content{width:100%}.decaf-file-component .dcf-error-message{color:var(--dcf-color-danger);font-size:.875rem}.decaf-file-component .dcf-drag-description{font-size:1rem;line-height:1.5rem;font-weight:500;margin-bottom:var(--dcf-margin-small)}.decaf-file-component .dcf-drop-area{display:flex;align-items:center;border:1.5px dashed var(--dcf-color-gray-3);border-radius:var(--dcf-border-radius-small)!important;transition:border-style .15s ease,border-color .15s ease;background:transparent}.decaf-file-component .dcf-drop-area.dcf-large{min-height:180px}.decaf-file-component .dcf-drop-area>div{width:100%}.decaf-file-component .dcf-drop-area.dcf-has-files{border-style:solid;border-color:var(--dcf-color-primary-shade);transition:border-style .15s ease,border-color .15s ease;padding:var(--dcf-spacement) var(--dcf-spacement-small)!important}.decaf-file-component .dcf-drop-area:not(.dcf-has-files){border-style:dashed;padding:var(--dcf-spacement) var(--dcf-spacement-medium)}.decaf-file-component .dcf-drop-area.dcf-dragging{background:#00000008;border-color:var(--ion-color-primary);box-shadow:0 2px 8px #0000000f}.decaf-file-component .dcf-preview .dcf-preview-image{border:1px solid var(--dcf-color-gray-3);border-radius:var(--dcf-border-radius-xsmall);max-width:320px;padding:.5rem;box-sizing:border-box;height:160px;position:relative;cursor:pointer;overflow:hidden}.decaf-file-component .dcf-preview .dcf-preview-image ion-img{height:140px!important;display:block;width:100%}.decaf-file-component .dcf-preview .dcf-preview-image:hover .dcf-overlay{opacity:1}.decaf-file-component .dcf-preview .dcf-preview-image .dcf-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background:#0009;display:flex;justify-content:center;align-items:center;opacity:0;transition:opacity .3s ease}.decaf-file-component .dcf-preview .description{text-align:left;padding:1rem;font-size:.75rem}.decaf-file-component .dcf-preview .description .dcf-title{font-size:1rem;font-weight:500}.decaf-file-component .dcf-preview .description ion-button{margin-top:var(--dcf-margin-small)!important}.decaf-file-component .dcf-preview-list-container{max-height:150px;overflow-y:auto}.decaf-file-component .dcf-preview-list-container ion-list{padding:0!important;margin:0!important}@media (max-width: 767px){.decaf-file-component .dcf-preview-list-container ion-list{width:100%;min-width:576px;overflow-x:auto}}.decaf-file-component .dcf-preview-list-container:not(:hover){scrollbar-color:rgba(var(--dcf-color-medium-rgb),.125) transparent!important}.decaf-file-component .dcf-preview-list-container ion-item{font-size:.875rem!important}.decaf-file-component .dcf-preview-list-container ion-item.dcf-error-item{--background: rgba(var(--dcf-color-danger-rgb), .02) !important;--border-color: rgba(var(--dcf-color-danger-rgb), .2) !important}.decaf-file-component .dcf-preview-list-container ion-item ion-item{--padding-top: .25rem;--padding-bottom: 0rem;--inner-padding-start: 0rem;--padding-start: var(--dcf-padding-xsmall) !important;--padding-end: 0rem;--inner-padding-end: var(--dcf-padding-xsmall) !important;--background-hover: var(--dcf-color-gray-8);--background-focused: var(--dcf-color-gray-8);--background-hover-opacity: .1;--background-focused-opacity: .1;--border-color: var(--dcf-color-gray-2)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: CardComponent, selector: "ngx-decaf-card", inputs: ["type", "title", "body", "subtitle", "color", "separator", "borders", "inlineContent", "inlineContentPosition"] }, { kind: "component", type: IconComponent, selector: "ngx-decaf-icon", inputs: ["name", "color", "slot", "button", "buttonFill", "buttonShape", "width", "size", "inline"] }, { kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { 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: 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: i1$1.DecimalPipe, name: "number" }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
10401
11405
  };
10402
- IconComponent = __decorate([
11406
+ FileUploadComponent = __decorate([
10403
11407
  Dynamic(),
10404
11408
  __metadata("design:paramtypes", [])
10405
- ], IconComponent);
10406
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: IconComponent, decorators: [{
11409
+ ], FileUploadComponent);
11410
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: FileUploadComponent, decorators: [{
10407
11411
  type: Component,
10408
- args: [{ selector: 'ngx-decaf-icon', imports: [NgxSvgDirective, IonIcon, IonButton], standalone: true, host: { '[attr.id]': 'uid' }, template: "<div class=\"dcf-icon\" #component>\n @if(initialized) {\n @if(button) {\n <ion-button\n [fill]=\"buttonFill\"\n [shape]=\"buttonShape\"\n [color]=\"color\">\n @if(type === 'image') {\n @if(isSvg) {\n <span\n aria-hidden=\"true\"\n [slot]=\"slot\"\n [class]=\"color ? 'dcf-color-' + color : ''\"\n [style.width]=\"width\"\n [ngx-decaf-svg]=\"name\">\n ></span>\n } @else {\n <img\n aria-hidden=\"true\" [alt]=\"name\" [title]=\"name\" [slot]=\"slot\" [src]=\"name\" [style.width]=\"width\" title=\"icon\" />\n }\n\n } @else {\n <ion-icon\n aria-hidden=\"true\"\n [slot]=\"slot\"\n [ios]=\"name\"\n [md]=\"name\"\n [size]=\"size\"\n [color]=\"color\"\n [name]=\"name\" />\n }\n </ion-button>\n } @else {\n @if(type === 'image') {\n @if(isSvg) {\n <span\n aria-hidden=\"true\"\n [slot]=\"slot\"\n [class]=\"color ? 'dcf-color-' + color : ''\"\n [style.width]=\"width\"\n [ngx-decaf-svg]=\"name\"\n\n >\n </span>\n } @else {\n <img aria-hidden=\"true\" [alt]=\"name\" [title]=\"name\" [slot]=\"slot\" [src]=\"name\" [style.width]=\"width\" title=\"icon\" />\n }\n }\n @if(type === 'ionic') {\n\n <ion-icon\n aria-hidden=\"true\"\n [slot]=\"slot\"\n [ios]=\"name\"\n [md]=\"name\"\n [size]=\"size\"\n [color]=\"color\"\n [name]=\"name\" />\n\n }\n }\n }\n</div>\n", styles: ["::ng-deep .dcf-icon.dcf-palette-dark ion-icon{color:var(--dcf-text-color)!important}::ng-deep .dcf-icon.dcf-palette-dark svg{fill:var(--dcf-text-color);fill-opacity:.25!important;stroke:var(--dcf-text-color)!important}::ng-deep .dcf-icon.dcf-palette-dark svg *{fill:var(--dcf-color-primary)!important;stroke:var(--dcf-color-gray-1)!important}.dcf-icon ion-icon:not([size]){font-size:1.35rem!important}\n"] }]
11412
+ args: [{ selector: 'ngx-decaf-file-upload', standalone: true, imports: [CommonModule, ReactiveFormsModule, CardComponent, IconComponent, IonList, IonLabel, IonItem, IonText, TranslatePipe, IonIcon, IonButton], template: "<div class=\"decaf-file-component\" #component>\n <input\n id=\"dcf-file-input\"\n type=\"file\"\n placeholder=\"Select files\"\n [attr.accept]=\"accept\"\n [attr.multiple]=\"multiple ? true : null\"\n (change)=\"handleSelection($event)\"\n [multiple]=\"multiple\"\n hidden\n [attr.webkitdirectory]=\"enableDirectoryMode ? true : null\"\n />\n\n <ngx-decaf-card [className]=\"className\" [body]=\"'blank'\">\n <div>\n <div\n [class]=\"\n 'dcf-drop-area '\n + ' dcf-' + size\n + ' dcf-flex dcf-flex-' + position\n + ' dcf-text-' + position\n \"\n\n [class.dcf-dragging]=\"dragging\"\n [class.dcf-has-files]=\"files.length\"\n (drop)=\"!files?.length ? handleDrop($event) : dragging = false\"\n (dragover)=\"!files?.length ? handleDragOver($event) : dragging = false\"\n (dragleave)=\"!files?.length ? handleDragLeave($event) : dragging = false\"\n >\n <div>\n @if (!preview) {\n @if(showIcon) {\n <ngx-decaf-icon name=\"cloud-upload-outline\" size=\"large\" />\n }\n <p class=\"dcf-drag-description\">{{ label ? (label | translate) : (locale + \".drag_file\" | translate) }}</p>\n <ion-button class=\"dcf-button-select\" (click)=\"handleClickToSelect()\" size=\"small\">\n {{ buttonLabel ? (buttonLabel | translate) : (locale + \".buttons.select\" | translate) }}\n </ion-button>\n <div #container>\n <span class=\"dcf-error\" [innerHTML]=\"getErrors(container)\"></span>\n </div>\n } @else {\n @if ((!directoryMode && !multiple) ) {\n <div class=\"dcf-preview dcf-grid dcf-grid-match dcf-grid-collapse\">\n <div class=\"dcf-width-1-4@m dcf-width-1-3@s dcf-flex dcf-flex-center dcf-flex-middle\">\n <div class=\"dcf-preview-image\">\n <ion-img\n [src]=\"preview\"\n [title]=\"locale + '.preview' | translate\"\n [alt]=\"locale + '.preview' | translate\"\n />\n <div class=\"dcf-overlay\">\n <ion-button (click)=\"showFilePreview(preview)\" fill=\"clear\" color=\"light\" size=\"small\">\n {{ locale + \".buttons.preview\" | translate }}\n </ion-button>\n </div>\n </div>\n </div>\n <div class=\"description dcf-flex dcf-flex-middle dcf-width-expand@s\">\n <div>\n <p class=\"dcf-title\">{{ locale + \".preview\" | translate }}</p>\n <p class=\"subtitle\">{{ files[0].name }}</p>\n <ion-button (click)=\"handleClear()\" fill=\"clear\" color=\"danger\" size=\"small\">{{ locale + \".buttons.clear\" | translate }} </ion-button>\n </div>\n </div>\n </div>\n } @else {\n <div class=\"dcf-margin-bottom\">\n {{ locale + \".selection\" | translate: { \"0\": files.length > 10 ? files.length : `0${files.length}` } }}\n @if(errors.length > 0) {\n <br /><span class=\"dcf-error-message\">{{ locale + \".selection_error\" | translate: { \"0\": errors.length > 10 ? errors.length : `0${errors.length}` } }}</span>\n }\n </div>\n <div class=\"dcf-preview-list-container\">\n <ion-list class=\"dcf-preview-list\">\n @for (file of errors; track $index) {\n <ion-item lines=\"full\" class=\"dcf-error-item\">\n <ion-label slot=\"start\">{{ file.name }}</ion-label>\n <div class=\"dcf-error-message\" slot=\"end\">\n {{ locale + \".errors.\" + file.error | translate: { \"0\": file.error === 'max_size' ? maxFileSize / 1024 / 1024 : file.name.split(\".\") } }}\n </div>\n <ion-note slot=\"end\">{{ file.size / 1024 / 1024 | number: \"1.1-1\" }} MB</ion-note>\n </ion-item>\n }\n\n @for (file of files; track $index) {\n <ion-item lines=\"full\">\n <ion-label slot=\"start\">{{ file.name }}</ion-label>\n <ion-note slot=\"end\">{{ file.size / 1024 / 1024 | number: \"1.1-1\" }} MB</ion-note>\n <div class=\"dcf-flex dcf-flex-middle\" slot=\"end\">\n <ngx-decaf-icon\n [button]=\"true\"\n [slot]=\"'icon-only'\"\n (click)=\"showFilePreview(file, file.type)\"\n [name]=\"'image-outline'\"\n />\n <ngx-decaf-icon\n [button]=\"true\"\n [slot]=\"'icon-only'\"\n [name]=\"'trash-outline'\"\n (click)=\"removeFile($index)\"\n [color]=\"'danger'\"\n [size]=\"'small'\"\n />\n </div>\n </ion-item>\n }\n </ion-list>\n </div>\n }\n }\n </div>\n\n\n </div>\n </div>\n </ngx-decaf-card>\n</div>\n\n<!-- <ion-card-header>\n <ion-card-title>Upload de Imagem</ion-card-title>\n </ion-card-header>\n\n <ion-card-content>\n <div\n class=\"dcf-drop-area\"\n [class.dragging]=\"dragging\"\n (drop)=\"onDrop($event)\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n >\n <div class=\"dcf-drop-content\">\n <ion-icon name=\"cloud-upload-outline\" size=\"large\"></ion-icon>\n <p>Arraste e solte aqui ou</p>\n <ion-button size=\"small\" fill=\"outline\" (click)=\"triggerFileSelect()\">Selecionar arquivo</ion-button>\n </div>\n </div>\n\n <input\n #fileInput\n type=\"file\"\n [attr.accept]=\"accept\"\n [attr.multiple]=\"multiple ? true : null\"\n (change)=\"onFileSelected($event)\"\n hidden\n />\n\n <div *ngIf=\"previewUrl\" class=\"dcf-preview\">\n <ion-item>\n <div slot=\"start\">\n <ion-img [src]=\"previewUrl\"></ion-img>\n </div>\n <ion-label>\n <h3>Pr\u00E9-visualiza\u00E7\u00E3o</h3>\n <p *ngIf=\"files.length\">{{ files[0].name }}</p>\n </ion-label>\n </ion-item>\n </div>\n\n <ion-list *ngIf=\"files.length\">\n <ion-list-header>\n <ion-label>Arquivos selecionados</ion-label>\n </ion-list-header>\n <ion-item *ngFor=\"let f of files; let i = index\">\n <ion-label>{{ f.name }}</ion-label>\n <ion-note slot=\"end\">{{ (f.size / 1024 / 1024) | number:'1.1-1' }} MB</ion-note>\n <ion-button fill=\"clear\" slot=\"end\" (click)=\"removeFile(i)\">\n <ion-icon slot=\"icon-only\" name=\"close-circle\"></ion-icon>\n </ion-button>\n </ion-item>\n </ion-list>\n\n <div *ngIf=\"errors.length\">\n <ion-list>\n <ion-item *ngFor=\"let err of errors\">\n <ion-icon name=\"alert-circle\" slot=\"start\" color=\"danger\"></ion-icon>\n <ion-label color=\"danger\">{{ err }}</ion-label>\n </ion-item>\n </ion-list>\n </div>\n\n <ion-row class=\"dcf-actions\">\n <ion-col>\n <ion-button expand=\"block\" (click)=\"triggerFileSelect()\">Selecionar</ion-button>\n </ion-col>\n <ion-col>\n <ion-button expand=\"block\" color=\"danger\" fill=\"outline\" (click)=\"clear()\">Limpar</ion-button>\n </ion-col>\n </ion-row>\n </ion-card-content> -->\n", styles: [".decaf-file-component.dcf-palette-dark .dcf-button-select{--background: rgb(var(--dcf-color-light-rgb), .1) !important;--background-hover: rgb(var(--dcf-color-light-rgb), .75) !important;--background-activated: rgb(var(--dcf-color-light-rgb), .4) !important;--background-focused: rgb(var(--dcf-color-light-rgb), .4) !important;--color: var(--dcf-color-light) !important}.decaf-file-component.dcf-palette-dark .dcf-has-files{border-style:solid;border-color:var(--dcf-color-gray-6)!important}.decaf-file-component .dcf-upload-icon{--box-shadow: none !important}.decaf-file-component .dcf-upload-icon ion-icon{width:1.5rem!important}.decaf-file-component ion-button.dcf-button-select{--background: rgb(var(--dcf-color-primary-rgb), .1);--background-hover: rgb(var(--dcf-color-primary-rgb), .75);--background-activated: rgb(var(--dcf-color-primary-rgb), .4);--background-focused: rgb(var(--dcf-color-primary-rgb), .4);--color: var(--dcf-color-primary-shade);--border-radius: var(--dcf-border-radius-small);--box-shadow: none;--padding-top: var(--dcf-padding-xsmall);--padding-bottom: var(--dcf-padding-xsmall);--padding-start: var(--dcf-padding-small);--padding-end: var(--dcf-padding-small);font-weight:500;text-transform:none;margin-top:var(--dcf-margin-small)!important}.decaf-file-component .dcf-error{color:var(--dcf-color-danger)!important;font-size:.8rem!important;font-weight:500!important;line-height:1.1rem;z-index:9999;animation-duration:.05s;animation-timing-function:ease-in;animation-fill-mode:both;animation-name:fadeBottomSmallAnimation}.decaf-file-component .dcf-error .ti,.decaf-file-component .dcf-error ion-icon{position:relative;top:2px!important;min-width:20px;font-size:1rem!important;text-align:left}.decaf-file-component ion-card-content{width:100%}.decaf-file-component .dcf-error-message{color:var(--dcf-color-danger);font-size:.875rem}.decaf-file-component .dcf-drag-description{font-size:1rem;line-height:1.5rem;font-weight:500;margin-bottom:var(--dcf-margin-small)}.decaf-file-component .dcf-drop-area{display:flex;align-items:center;border:1.5px dashed var(--dcf-color-gray-3);border-radius:var(--dcf-border-radius-small)!important;transition:border-style .15s ease,border-color .15s ease;background:transparent}.decaf-file-component .dcf-drop-area.dcf-large{min-height:180px}.decaf-file-component .dcf-drop-area>div{width:100%}.decaf-file-component .dcf-drop-area.dcf-has-files{border-style:solid;border-color:var(--dcf-color-primary-shade);transition:border-style .15s ease,border-color .15s ease;padding:var(--dcf-spacement) var(--dcf-spacement-small)!important}.decaf-file-component .dcf-drop-area:not(.dcf-has-files){border-style:dashed;padding:var(--dcf-spacement) var(--dcf-spacement-medium)}.decaf-file-component .dcf-drop-area.dcf-dragging{background:#00000008;border-color:var(--ion-color-primary);box-shadow:0 2px 8px #0000000f}.decaf-file-component .dcf-preview .dcf-preview-image{border:1px solid var(--dcf-color-gray-3);border-radius:var(--dcf-border-radius-xsmall);max-width:320px;padding:.5rem;box-sizing:border-box;height:160px;position:relative;cursor:pointer;overflow:hidden}.decaf-file-component .dcf-preview .dcf-preview-image ion-img{height:140px!important;display:block;width:100%}.decaf-file-component .dcf-preview .dcf-preview-image:hover .dcf-overlay{opacity:1}.decaf-file-component .dcf-preview .dcf-preview-image .dcf-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background:#0009;display:flex;justify-content:center;align-items:center;opacity:0;transition:opacity .3s ease}.decaf-file-component .dcf-preview .description{text-align:left;padding:1rem;font-size:.75rem}.decaf-file-component .dcf-preview .description .dcf-title{font-size:1rem;font-weight:500}.decaf-file-component .dcf-preview .description ion-button{margin-top:var(--dcf-margin-small)!important}.decaf-file-component .dcf-preview-list-container{max-height:150px;overflow-y:auto}.decaf-file-component .dcf-preview-list-container ion-list{padding:0!important;margin:0!important}@media (max-width: 767px){.decaf-file-component .dcf-preview-list-container ion-list{width:100%;min-width:576px;overflow-x:auto}}.decaf-file-component .dcf-preview-list-container:not(:hover){scrollbar-color:rgba(var(--dcf-color-medium-rgb),.125) transparent!important}.decaf-file-component .dcf-preview-list-container ion-item{font-size:.875rem!important}.decaf-file-component .dcf-preview-list-container ion-item.dcf-error-item{--background: rgba(var(--dcf-color-danger-rgb), .02) !important;--border-color: rgba(var(--dcf-color-danger-rgb), .2) !important}.decaf-file-component .dcf-preview-list-container ion-item ion-item{--padding-top: .25rem;--padding-bottom: 0rem;--inner-padding-start: 0rem;--padding-start: var(--dcf-padding-xsmall) !important;--padding-end: 0rem;--inner-padding-end: var(--dcf-padding-xsmall) !important;--background-hover: var(--dcf-color-gray-8);--background-focused: var(--dcf-color-gray-8);--background-hover-opacity: .1;--background-focused-opacity: .1;--border-color: var(--dcf-color-gray-2)}\n"] }]
10409
11413
  }], ctorParameters: () => [], propDecorators: { component: [{
10410
11414
  type: ViewChild,
10411
- args: ['component', { read: ElementRef, static: false }]
11415
+ args: ['component', { static: true }]
11416
+ }], formGroup: [{
11417
+ type: Input
10412
11418
  }], name: [{
10413
11419
  type: Input
10414
- }], color: [{
11420
+ }], formControl: [{
10415
11421
  type: Input
10416
- }], slot: [{
11422
+ }], required: [{
10417
11423
  type: Input
10418
- }], button: [{
11424
+ }], multiple: [{
10419
11425
  type: Input
10420
- }], buttonFill: [{
11426
+ }], type: [{
10421
11427
  type: Input
10422
- }], buttonShape: [{
11428
+ }], label: [{
10423
11429
  type: Input
10424
- }], width: [{
11430
+ }], buttonLabel: [{
10425
11431
  type: Input
10426
11432
  }], size: [{
10427
11433
  type: Input
10428
- }], inline: [{
11434
+ }], position: [{
11435
+ type: Input
11436
+ }], accept: [{
11437
+ type: Input
11438
+ }], showIcon: [{
11439
+ type: Input
11440
+ }], enableDirectoryMode: [{
10429
11441
  type: Input
11442
+ }], maxFileSize: [{
11443
+ type: Input
11444
+ }], changeEvent: [{
11445
+ type: Output
10430
11446
  }] } });
10431
11447
 
10432
11448
  /**
@@ -10455,7 +11471,8 @@ const Components = [
10455
11471
  FilterComponent,
10456
11472
  SteppedFormComponent,
10457
11473
  IconComponent,
10458
- CardComponent
11474
+ CardComponent,
11475
+ FileUploadComponent
10459
11476
  ];
10460
11477
  class ForAngularComponentsModule {
10461
11478
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: ForAngularComponentsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
@@ -10474,7 +11491,8 @@ class ForAngularComponentsModule {
10474
11491
  FilterComponent,
10475
11492
  SteppedFormComponent,
10476
11493
  IconComponent,
10477
- CardComponent], exports: [ModelRendererComponent,
11494
+ CardComponent,
11495
+ FileUploadComponent], exports: [ModelRendererComponent,
10478
11496
  ComponentRendererComponent,
10479
11497
  CrudFieldComponent,
10480
11498
  CrudFormComponent,
@@ -10489,7 +11507,8 @@ class ForAngularComponentsModule {
10489
11507
  FilterComponent,
10490
11508
  SteppedFormComponent,
10491
11509
  IconComponent,
10492
- CardComponent] }); }
11510
+ CardComponent,
11511
+ FileUploadComponent] }); }
10493
11512
  static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: ForAngularComponentsModule, imports: [CrudFieldComponent,
10494
11513
  CrudFormComponent,
10495
11514
  EmptyStateComponent,
@@ -10503,7 +11522,8 @@ class ForAngularComponentsModule {
10503
11522
  FilterComponent,
10504
11523
  SteppedFormComponent,
10505
11524
  IconComponent,
10506
- CardComponent] }); }
11525
+ CardComponent,
11526
+ FileUploadComponent] }); }
10507
11527
  }
10508
11528
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: ForAngularComponentsModule, decorators: [{
10509
11529
  type: NgModule,
@@ -10701,7 +11721,7 @@ class NgxPageDirective extends NgxComponentDirective {
10701
11721
  * @return {void}
10702
11722
  * @memberOf module:lib/engine/NgxPageDirective
10703
11723
  */
10704
- setPageTitle(route, menu) {
11724
+ async setPageTitle(route, menu) {
10705
11725
  if (!route)
10706
11726
  route = this.router.url.replace('/', '');
10707
11727
  if (!menu)
@@ -10709,7 +11729,7 @@ class NgxPageDirective extends NgxComponentDirective {
10709
11729
  const activeMenu = menu.find(item => item?.url?.includes(route));
10710
11730
  if (activeMenu) {
10711
11731
  const title = activeMenu?.title || activeMenu?.label;
10712
- this.titleService.setTitle(`${title}`);
11732
+ this.titleService.setTitle(`${await this.translate(title)} ${this.appName ? `- ${this.appName}` : ''}`);
10713
11733
  if (!this.title)
10714
11734
  this.title = title;
10715
11735
  }
@@ -10780,10 +11800,13 @@ class NgxModelPageDirective extends NgxPageDirective {
10780
11800
  // super("NgxModelPageDirective");
10781
11801
  // }
10782
11802
  get pageTitle() {
11803
+ if (!this.modelName && this.model instanceof Model)
11804
+ this.modelName = this.model?.constructor?.name || "";
10783
11805
  if (!this.operation)
10784
- return `Listing ${this.modelName}`;
11806
+ return this.title ? this.title : `Listing ${this.modelName}`;
10785
11807
  const operation = this.operation.charAt(0).toUpperCase() + this.operation.slice(1).toLowerCase();
10786
- return `${operation} ${this.modelName}`;
11808
+ return this.modelName ?
11809
+ `${operation} ${this.modelName}` : this.title;
10787
11810
  }
10788
11811
  /**
10789
11812
  * @description Lazy-initialized repository getter with model resolution.
@@ -10863,7 +11886,7 @@ class NgxModelPageDirective extends NgxPageDirective {
10863
11886
  async handleEvent(event) {
10864
11887
  const { name } = event;
10865
11888
  switch (name) {
10866
- case EventConstants.SUBMIT:
11889
+ case ComponentEventNames.SUBMIT:
10867
11890
  await this.handleSubmit(event);
10868
11891
  break;
10869
11892
  }
@@ -10879,7 +11902,7 @@ class NgxModelPageDirective extends NgxPageDirective {
10879
11902
  * @param {IBaseCustomEvent} event - The submit event containing form data
10880
11903
  * @return {Promise<IModelPageCustomEvent|void>} Promise that resolves on success or throws on error
10881
11904
  */
10882
- async handleSubmit(event) {
11905
+ async handleSubmit(event, redirect = false) {
10883
11906
  try {
10884
11907
  const repo = this._repository;
10885
11908
  const operation = this.operation === OperationKeys.READ ? 'delete' : this.operation.toLowerCase();
@@ -10893,7 +11916,8 @@ class NgxModelPageDirective extends NgxPageDirective {
10893
11916
  });
10894
11917
  if (result) {
10895
11918
  repo.refresh(this.modelName, this.operation, this.modelId);
10896
- this.location.back();
11919
+ if (redirect)
11920
+ this.location.back();
10897
11921
  }
10898
11922
  return {
10899
11923
  ...event,
@@ -10996,5 +12020,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
10996
12020
  * Generated bundle index. Do not edit.
10997
12021
  */
10998
12022
 
10999
- export { ActionRoles, AngularEngineKeys, BaseComponentProps, CPTKN, CardComponent, ComponentRendererComponent, ComponentsTagNames, CrudFieldComponent, CrudFormComponent, CssClasses, DB_ADAPTER_PROVIDER, DB_ADAPTER_PROVIDER_TOKEN, DecafFakerRepository, DefaultFormReactiveOptions, DefaultListEmptyOptions, DefaultModalOptions, Dynamic, DynamicModule, ElementSizes, EmptyStateComponent, EventConstants, FieldsetComponent, FilterComponent, ForAngularCommonModule, ForAngularComponentsModule, FormConstants, I18N_CONFIG_TOKEN, I18nLoader, I18nLoaderFactory, I18nParser, IconComponent, LOCALE_ROOT_TOKEN, LayoutComponent, LayoutGridGaps, ListComponent, ListComponentsTypes, ListItemComponent, LoggerLevels, ModalComponent, ModelRendererComponent, NgxComponentDirective, NgxEventHandler, NgxFormDirective, NgxFormFieldDirective, NgxFormService, NgxMediaService, NgxModelPageDirective, NgxPageDirective, NgxParentComponentDirective, NgxRenderingEngine, NgxSvgDirective, PaginationComponent, RouteDirections, SearchbarComponent, SteppedFormComponent, WindowColorSchemes, cleanSpaces, dataMapper, filterString, formatDate, generateRandomValue, getFakerData, getInjectablesRegistry, getLocaleContext, getLocaleContextByKey, getLocaleFromClassName, getLocaleLanguage, getLogger, getModelRepository, getNgxModalComponent, getOnWindow, getOnWindowDocument, getWindow, getWindowDocument, getWindowWidth, isDarkMode, isDevelopmentMode, isNotUndefined, isValidDate, itemMapper, parseToValidDate, provideDbAdapter, provideDynamicComponents, provideI18n, provideI18nLoader, removeFocusTrap, setOnWindow, stringToBoolean, windowEventEmitter };
12023
+ export { ActionRoles, AngularEngineKeys, BaseComponentProps, CPTKN, CardComponent, ComponentEventNames, ComponentRendererComponent, ComponentsTagNames, CrudFieldComponent, CrudFormComponent, CssClasses, DB_ADAPTER_PROVIDER, DB_ADAPTER_PROVIDER_TOKEN, DecafFakerRepository, DefaultFormReactiveOptions, DefaultListEmptyOptions, DefaultModalOptions, Dynamic, DynamicModule, ElementPositions, ElementSizes, EmptyStateComponent, FieldsetComponent, FileUploadComponent, FilterComponent, ForAngularCommonModule, ForAngularComponentsModule, FormConstants, I18N_CONFIG_TOKEN, I18nLoader, I18nLoaderFactory, I18nParser, IconComponent, LOCALE_ROOT_TOKEN, LayoutComponent, LayoutGridGaps, ListComponent, ListComponentsTypes, ListItemComponent, ListItemPositions, LoggerLevels, ModalComponent, ModelRendererComponent, NgxComponentDirective, NgxEventHandler, NgxFormDirective, NgxFormFieldDirective, NgxFormService, NgxMediaService, NgxModelPageDirective, NgxPageDirective, NgxParentComponentDirective, NgxRenderingEngine, NgxSvgDirective, PaginationComponent, RouteDirections, SearchbarComponent, SteppedFormComponent, WindowColorSchemes, cleanSpaces, dataMapper, filterString, formatDate, generateRandomValue, getFakerData, getInjectablesRegistry, getLocaleContext, getLocaleContextByKey, getLocaleFromClassName, getLocaleLanguage, getLogger, getModelRepository, getNgxModalComponent, getNgxSelectOptionsModal, getOnWindow, getOnWindowDocument, getWindow, getWindowDocument, getWindowWidth, isDarkMode, isDevelopmentMode, isNotUndefined, isValidDate, itemMapper, parseToValidDate, presentNgxLightBoxModal, provideDbAdapter, provideDynamicComponents, provideI18n, provideI18nLoader, removeFocusTrap, setOnWindow, stringToBoolean, windowEventEmitter };
11000
12024
  //# sourceMappingURL=decaf-ts-for-angular.mjs.map