@decaf-ts/for-angular 0.0.25 → 0.0.27

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.
Files changed (78) hide show
  1. package/fesm2022/decaf-ts-for-angular.mjs +1486 -1505
  2. package/fesm2022/decaf-ts-for-angular.mjs.map +1 -1
  3. package/index.d.ts +7482 -3
  4. package/package.json +15 -18
  5. package/components/component-renderer/component-renderer.component.d.ts +0 -278
  6. package/components/crud-field/crud-field.component.d.ts +0 -611
  7. package/components/crud-form/constants.d.ts +0 -5
  8. package/components/crud-form/crud-form.component.d.ts +0 -288
  9. package/components/crud-form/types.d.ts +0 -17
  10. package/components/empty-state/empty-state.component.d.ts +0 -300
  11. package/components/fieldset/fieldset.component.d.ts +0 -555
  12. package/components/filter/filter.component.d.ts +0 -514
  13. package/components/for-angular-components.module.d.ts +0 -20
  14. package/components/index.d.ts +0 -16
  15. package/components/layout/layout.component.d.ts +0 -110
  16. package/components/list/list.component.d.ts +0 -848
  17. package/components/list-item/list-item.component.d.ts +0 -390
  18. package/components/model-renderer/model-renderer.component.d.ts +0 -97
  19. package/components/pagination/constants.d.ts +0 -7
  20. package/components/pagination/pagination.component.d.ts +0 -264
  21. package/components/searchbar/searchbar.component.d.ts +0 -407
  22. package/components/stepped-form/stepped-form.component.d.ts +0 -255
  23. package/directives/collapsable.directive.d.ts +0 -9
  24. package/directives/index.d.ts +0 -1
  25. package/engine/DynamicModule.d.ts +0 -17
  26. package/engine/NgxBaseComponent.d.ts +0 -541
  27. package/engine/NgxCrudFormField.d.ts +0 -123
  28. package/engine/NgxFormService.d.ts +0 -601
  29. package/engine/NgxRenderingEngine.d.ts +0 -282
  30. package/engine/ValidatorFactory.d.ts +0 -15
  31. package/engine/constants.d.ts +0 -168
  32. package/engine/decorators.d.ts +0 -25
  33. package/engine/index.d.ts +0 -18
  34. package/engine/interfaces.d.ts +0 -271
  35. package/engine/types.d.ts +0 -200
  36. package/esm2022/components/component-renderer/component-renderer.component.mjs +0 -321
  37. package/esm2022/components/crud-field/crud-field.component.mjs +0 -518
  38. package/esm2022/components/crud-form/constants.mjs +0 -14
  39. package/esm2022/components/crud-form/crud-form.component.mjs +0 -259
  40. package/esm2022/components/crud-form/types.mjs +0 -2
  41. package/esm2022/components/empty-state/empty-state.component.mjs +0 -345
  42. package/esm2022/components/fieldset/fieldset.component.mjs +0 -677
  43. package/esm2022/components/filter/filter.component.mjs +0 -700
  44. package/esm2022/components/for-angular-components.module.mjs +0 -84
  45. package/esm2022/components/index.mjs +0 -20
  46. package/esm2022/components/layout/layout.component.mjs +0 -150
  47. package/esm2022/components/list/list.component.mjs +0 -1238
  48. package/esm2022/components/list-item/list-item.component.mjs +0 -405
  49. package/esm2022/components/model-renderer/model-renderer.component.mjs +0 -144
  50. package/esm2022/components/pagination/constants.mjs +0 -2
  51. package/esm2022/components/pagination/pagination.component.mjs +0 -321
  52. package/esm2022/components/searchbar/searchbar.component.mjs +0 -491
  53. package/esm2022/components/stepped-form/stepped-form.component.mjs +0 -306
  54. package/esm2022/decaf-ts-for-angular.mjs +0 -5
  55. package/esm2022/directives/collapsable.directive.mjs +0 -29
  56. package/esm2022/directives/index.mjs +0 -2
  57. package/esm2022/engine/DynamicModule.mjs +0 -18
  58. package/esm2022/engine/NgxBaseComponent.mjs +0 -541
  59. package/esm2022/engine/NgxCrudFormField.mjs +0 -137
  60. package/esm2022/engine/NgxFormService.mjs +0 -917
  61. package/esm2022/engine/NgxRenderingEngine.mjs +0 -376
  62. package/esm2022/engine/ValidatorFactory.mjs +0 -106
  63. package/esm2022/engine/constants.mjs +0 -170
  64. package/esm2022/engine/decorators.mjs +0 -38
  65. package/esm2022/engine/index.mjs +0 -19
  66. package/esm2022/engine/interfaces.mjs +0 -4
  67. package/esm2022/engine/types.mjs +0 -2
  68. package/esm2022/for-angular-common.module.mjs +0 -84
  69. package/esm2022/helpers/index.mjs +0 -13
  70. package/esm2022/helpers/utils.mjs +0 -436
  71. package/esm2022/i18n/Loader.mjs +0 -86
  72. package/esm2022/i18n/data/en.json +0 -85
  73. package/esm2022/public-apis.mjs +0 -15
  74. package/for-angular-common.module.d.ts +0 -50
  75. package/helpers/index.d.ts +0 -12
  76. package/helpers/utils.d.ts +0 -279
  77. package/i18n/Loader.d.ts +0 -43
  78. package/public-apis.d.ts +0 -14
@@ -11,11 +11,10 @@ import { TranslateModule, TranslatePipe, TranslateService } from '@ngx-translate
11
11
  import { Logging } from '@decaf-ts/logging';
12
12
  import { __decorate, __metadata } from 'tslib';
13
13
  import { apply, metadata } from '@decaf-ts/reflection';
14
- import { IonInput, IonItem, IonCheckbox, IonRadioGroup, IonRadio, IonSelect, IonSelectOption, IonLabel, IonText, IonTextarea, IonIcon, IonButton, IonCard, IonCardContent, IonAccordionGroup, IonAccordion, IonList, IonReorder, IonReorderGroup, IonSearchbar, IonChip, IonListHeader, IonItemSliding, IonItemOptions, IonItemOption, IonContent, IonPopover, IonRefresher, IonThumbnail, IonSkeletonText, IonRefresherContent, IonInfiniteScroll, IonInfiniteScrollContent, IonLoading } from '@ionic/angular/standalone';
14
+ import { IonInput, IonItem, IonCheckbox, IonRadioGroup, IonRadio, IonSelect, IonSelectOption, IonLabel, IonText, IonTextarea, IonButton, IonIcon, IonCard, IonCardContent, IonAccordionGroup, IonAccordion, IonList, IonReorder, IonReorderGroup, IonSearchbar, IonChip, IonRefresher, IonThumbnail, IonSkeletonText, IonRefresherContent, IonInfiniteScroll, IonInfiniteScrollContent, IonListHeader, IonItemSliding, IonItemOptions, IonItemOption, IonContent, IonPopover } from '@ionic/angular/standalone';
15
15
  import { addIcons } from 'ionicons';
16
16
  import * as allIcons from 'ionicons/icons';
17
17
  import { chevronUpOutline, chevronDownOutline, createOutline, alertCircleOutline, chevronForwardOutline, chevronBackOutline, arrowBackOutline, arrowForwardOutline } from 'ionicons/icons';
18
- import { TranslateHttpLoader } from '@ngx-translate/http-loader';
19
18
  import { forkJoin, fromEvent, debounceTime, Subject, timer } from 'rxjs';
20
19
  import { map } from 'rxjs/operators';
21
20
  import { Repository, OrderDirection, Condition } from '@decaf-ts/core';
@@ -292,8 +291,19 @@ class ValidatorFactory {
292
291
  }
293
292
  }
294
293
 
294
+ /** */
295
295
  const DB_ADAPTER_PROVIDER_TOKEN = new InjectionToken('DB_ADAPTER_PROVIDER');
296
296
  const I18N_CONFIG_TOKEN = new InjectionToken('I18N_CONFIG_TOKEN');
297
+ function provideDbAdapter(adapterClass, options = {}) {
298
+ const adapter = new adapterClass(options);
299
+ // Log and expose adapter flavour globally
300
+ getLogger(provideDbAdapter).info(`Using ${adapter.flavour} as Db Provider`);
301
+ // getWindow()['dbAdapterFlavour'] = adapter.flavour;
302
+ return {
303
+ provide: DB_ADAPTER_PROVIDER_TOKEN,
304
+ useValue: adapter,
305
+ };
306
+ }
297
307
  const ComponentsAndModules = [
298
308
  CommonModule,
299
309
  FormsModule,
@@ -341,8 +351,8 @@ class ForAngularCommonModule {
341
351
  ngModule: ForAngularCommonModule,
342
352
  };
343
353
  }
344
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ForAngularCommonModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
345
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.14", ngImport: i0, type: ForAngularCommonModule, imports: [CommonModule,
354
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ForAngularCommonModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
355
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.2", ngImport: i0, type: ForAngularCommonModule, imports: [CommonModule,
346
356
  FormsModule,
347
357
  ReactiveFormsModule,
348
358
  TranslateModule,
@@ -351,7 +361,7 @@ class ForAngularCommonModule {
351
361
  ReactiveFormsModule,
352
362
  TranslateModule,
353
363
  TranslatePipe] }); }
354
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ForAngularCommonModule, imports: [CommonModule,
364
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ForAngularCommonModule, imports: [CommonModule,
355
365
  FormsModule,
356
366
  ReactiveFormsModule,
357
367
  TranslateModule,
@@ -360,7 +370,7 @@ class ForAngularCommonModule {
360
370
  ReactiveFormsModule,
361
371
  TranslateModule] }); }
362
372
  }
363
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ForAngularCommonModule, decorators: [{
373
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ForAngularCommonModule, decorators: [{
364
374
  type: NgModule,
365
375
  args: [{
366
376
  imports: ComponentsAndModules,
@@ -875,7 +885,6 @@ class NgxFormService {
875
885
  * @memberOf NgxFormService
876
886
  */
877
887
  static { this.formRegistry = new Map(); }
878
- static { this.pageMapper = {}; }
879
888
  /**
880
889
  * @description Creates a new form group or form array with the specified identifier.
881
890
  * @summary Generates a FormGroup or FormArray based on the provided properties. If pages are specified
@@ -2382,10 +2391,10 @@ class ComponentRendererComponent {
2382
2391
  }
2383
2392
  }
2384
2393
  }
2385
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ComponentRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2386
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ComponentRendererComponent, isStandalone: true, selector: "ngx-decaf-component-renderer", inputs: { tag: "tag", globals: "globals", children: "children", model: "model", parent: "parent" }, outputs: { listenEvent: "listenEvent" }, host: { properties: { "attr.id": "uid" } }, viewQueries: [{ propertyName: "vcr", first: true, predicate: ["componentViewContainer"], descendants: true, read: ViewContainerRef, static: true }, { propertyName: "inner", first: true, predicate: ["inner"], descendants: true, read: TemplateRef, static: true }], ngImport: i0, template: "<!-- Keep to avoid id conflicts -->\n<div [id]=\"uid\"></div>\n\n<ng-template #componentViewContainer></ng-template>\n<ng-template #inner>\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(children?.length) {\n @for(child of children; track child) {\n @if(child.children?.length) {\n <ngx-decaf-component-renderer [parent]=\"child\"> </ngx-decaf-component-renderer>\n } @else {\n <ngx-decaf-component-renderer\n [tag]=\"child?.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]=\"{props: child.props}\" />\n }\n }\n }\n</ng-template>\n\n\n", styles: [""], dependencies: [{ kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "children", "model", "parent"], outputs: ["listenEvent"] }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"] }] }); }
2394
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ComponentRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2395
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.2", type: ComponentRendererComponent, isStandalone: true, selector: "ngx-decaf-component-renderer", inputs: { tag: "tag", globals: "globals", children: "children", model: "model", parent: "parent" }, outputs: { listenEvent: "listenEvent" }, host: { properties: { "attr.id": "uid" } }, viewQueries: [{ propertyName: "vcr", first: true, predicate: ["componentViewContainer"], descendants: true, read: ViewContainerRef, static: true }, { propertyName: "inner", first: true, predicate: ["inner"], descendants: true, read: TemplateRef, static: true }], ngImport: i0, template: "<!-- Keep to avoid id conflicts -->\n<div [id]=\"uid\"></div>\n\n<ng-template #componentViewContainer></ng-template>\n<ng-template #inner>\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(children?.length) {\n @for(child of children; track child) {\n @if(child.children?.length) {\n <ngx-decaf-component-renderer [parent]=\"child\"> </ngx-decaf-component-renderer>\n } @else {\n <ngx-decaf-component-renderer\n [tag]=\"child?.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]=\"{props: child.props}\" />\n }\n }\n }\n</ng-template>\n\n\n", styles: [""], dependencies: [{ kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "children", "model", "parent"], outputs: ["listenEvent"] }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }] }); }
2387
2396
  }
2388
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ComponentRendererComponent, decorators: [{
2397
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ComponentRendererComponent, decorators: [{
2389
2398
  type: Component,
2390
2399
  args: [{ selector: 'ngx-decaf-component-renderer', imports: [NgComponentOutlet], standalone: true, host: { '[attr.id]': 'uid' }, template: "<!-- Keep to avoid id conflicts -->\n<div [id]=\"uid\"></div>\n\n<ng-template #componentViewContainer></ng-template>\n<ng-template #inner>\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(children?.length) {\n @for(child of children; track child) {\n @if(child.children?.length) {\n <ngx-decaf-component-renderer [parent]=\"child\"> </ngx-decaf-component-renderer>\n } @else {\n <ngx-decaf-component-renderer\n [tag]=\"child?.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]=\"{props: child.props}\" />\n }\n }\n }\n</ng-template>\n\n\n" }]
2391
2400
  }], ctorParameters: () => [], propDecorators: { vcr: [{
@@ -2660,20 +2669,6 @@ var en = {
2660
2669
  component: component
2661
2670
  };
2662
2671
 
2663
- class I18nLoader {
2664
- static loadFromHttp(http) {
2665
- function getSuffix() {
2666
- const today = new Date();
2667
- return `.json?version=${today.getFullYear()}${today.getMonth()}${today.getDay()}`;
2668
- }
2669
- return new (class extends TranslateHttpLoader {
2670
- getTranslation(lang) {
2671
- const res = super.getTranslation(lang);
2672
- return res;
2673
- }
2674
- })(http, './assets/i18n/', getSuffix());
2675
- }
2676
- }
2677
2672
  function getLocaleContext(clazz, suffix) {
2678
2673
  return getLocaleFromClassName(clazz, suffix);
2679
2674
  }
@@ -2700,22 +2695,21 @@ function getLocaleContextByKey(locale, phrase) {
2700
2695
  return `${locale}.${cleanSpaces(parts.join('.'), true)}`;
2701
2696
  }
2702
2697
  function I18nLoaderFactory(http) {
2703
- const { resources, versionedSuffix } = inject(I18N_CONFIG_TOKEN, { optional: true }) ?? getI18nLoaderFactoryProviderConfig().useValue;
2704
- return new MultiI18nLoader(http, resources, versionedSuffix);
2698
+ const { resources, versionedSuffix } = inject(I18N_CONFIG_TOKEN, { optional: true }) ?? provideI18nLoader().useValue;
2699
+ return new I18nLoader(http, resources?.length ? resources : [{ prefix: './app/assets/i18n/', suffix: '.json' }], versionedSuffix);
2705
2700
  }
2706
- function getI18nLoaderFactoryProviderConfig(resources = [], versionedSuffix = false) {
2701
+ function provideI18nLoader(resources = [], versionedSuffix = false) {
2707
2702
  if (!Array.isArray(resources))
2708
2703
  resources = [resources];
2709
2704
  return {
2710
2705
  provide: I18N_CONFIG_TOKEN,
2711
2706
  useValue: { resources: [
2712
- // { prefix: './assets/i18n/', suffix: '.json' },
2713
2707
  ...resources
2714
2708
  ], versionedSuffix }
2715
2709
  };
2716
2710
  }
2717
2711
  const libLanguage = { en };
2718
- class MultiI18nLoader {
2712
+ class I18nLoader {
2719
2713
  constructor(http, resources = [], versionedSuffix = false) {
2720
2714
  this.http = http;
2721
2715
  this.resources = resources;
@@ -3101,13 +3095,13 @@ let CrudFieldComponent = class CrudFieldComponent extends NgxCrudFormField {
3101
3095
  });
3102
3096
  component.dispatchEvent(event);
3103
3097
  }
3104
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CrudFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
3105
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: CrudFieldComponent, isStandalone: true, selector: "ngx-decaf-crud-field", inputs: { operation: "operation", name: "name", 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", cols: "cols", rows: "rows", 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", activeFormGroup: "activeFormGroup", pk: "pk" }, host: { listeners: { "window:fieldsetAddGroupEvent": "handleFieldsetCreateGroupEvent($event)", "window:fieldsetUpdateGroupEvent": "handleFieldsetUpdateGroupEvent($event)", "window:fieldsetRemoveGroupEvent": "handleFieldsetRemoveGroupEvent($event)" }, properties: { "attr.id": "uid" } }, viewQueries: [{ propertyName: "component", first: true, predicate: ["component"], descendants: true, read: ElementRef }], usesInheritance: true, ngImport: i0, template: "@if(operation === 'read' || operation === 'delete') {\n <ng-container #component>\n <div [class]=\"'dcf-input-item ' + operation\">\n <ion-item>\n <ion-label>\n {{ label | translate }}<br />\n @if(value) {\n <ion-text [innerHTML]=\"type === 'password' ? '********' : value\"></ion-text>\n } @else {\n <br />\n }\n </ion-label>\n </ion-item>\n </div>\n </ng-container>\n} @else {\n <ng-container [formGroup]=\"getActiveFormGroup\">\n <div #container [class]=\"'dcf-input-item ' + (operation || 'create')\" (createGroupEvent)=\"multiple ? handleFieldsetCreateGroupEvent($event) : ''\">\n @if(type === 'textarea') {\n <ion-textarea\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [autoGrow]=\"true\"\n [required]=\"required !== undefined ? required : null\"\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 <ion-item>\n <ion-checkbox\n #checkboxElement\n [mode]=\"mode\"\n [errorText]=\"getErrors(container)\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"justify\"\n [value]=\"value\"\n [checked]=\"checked\"\n [readonly]=\"readonly\"\n (ionChange)=\"checked = !checked\"\n [formControlName]=\"name\"\n #component>\n <span [innerHTML]=\"label | translate\"></span>\n </ion-checkbox>\n </ion-item>\n }\n @else if(type === 'radio') {\n <ion-radio-group [formControlName]=\"name\" [value]=\"value\" #component>\n <label class=\"dcf-radio-group-label\" [for]=\"path\">{{label | translate}}</label>\n @for(option of options; track option) {\n <ion-item>\n <ion-radio\n [errorText]=\"getErrors(container)\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [alignment]=\"alignment\"\n [justify]=\"justify\"\n [readonly]=\"readonly\"\n [value]=\"option.value\"\n >{{ translatable ? (option?.text | translate) : option?.text }}</ion-radio>\n </ion-item>\n }\n </ion-radio-group>\n }\n @else if(type === 'select') {\n <ion-select\n toggleIcon=\"chevron-down-outline\"\n expandedIcon=\"chevron-up-outline\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [label]=\"translatable ? (label | translate) : label\"\n [value]=\"value\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [errorText]=\"getErrors(container)\"\n [interface]=\"interface\" #component>\n @for(option of options; track option.value) {\n <ion-select-option [value]=\"option.value\">\n {{ option.text | translate }}\n </ion-select-option>\n }\n </ion-select>\n }\n @else {\n <ion-input\n [type]=\"type\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [inputmode]=\"inputmode\"\n [labelPlacement]=\"labelPlacement\"\n [required]=\"required !== undefined ? required : false\"\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}\n\n", styles: [".dcf-input-item.create,.dcf-input-item.update{margin-bottom:1.8rem;margin-top:0!important}.dcf-input-item.create.checkbox+.checkbox,.dcf-input-item.update.checkbox+.checkbox{margin-top:-.25rem!important}.dcf-input-item.create ion-item,.dcf-input-item.update ion-item{--border-color: transparent}.dcf-input-item.create ion-item.dcf-text-wrap ion-label>*,.dcf-input-item.update ion-item.dcf-text-wrap ion-label>*{white-space:wrap!important;word-break:break-all!important}.dcf-input-item.read ion-label,.dcf-input-item.delete ion-label{font-weight:600}@media (prefers-color-scheme: light){.dcf-input-item.read ion-label,.dcf-input-item.delete ion-label{color:var(--dcf-color-gray-7)}}.dcf-input-item.read ion-text,.dcf-input-item.delete ion-text{display:block;margin-top:.5rem!important}.dcf-input-item ion-item{--padding-end: 0rem;--padding-start: 0px !important;--padding-top: 0px !important;--background: transparent;--background-hover-opacity: .1;--background-activated-opacity: .15;--background-focused-opacity: .15}@media (prefers-color-scheme: dark){.dcf-input-item ion-item{--border-color: var(--dcf-color-gray-6)}}@media (prefers-color-scheme: light){.dcf-input-item ion-item{--background-hover: var(--dcf-color-primary);--background-focused: var(--dcf-color-primary);--border-color: var(--dcf-color-gray-2)}}.dcf-input-item ion-item span,.dcf-input-item ion-item ion-text{font-weight:400!important;font-size:.925rem;min-height:.5rem!important}.dcf-input-item ion-item span:not(.dcf-display-block),.dcf-input-item ion-item ion-text:not(.dcf-display-block){display:inline-block}.dcf-input-item ion-item span.dcf-display-block,.dcf-input-item ion-item ion-text.dcf-display-block{display:block!important}ion-textarea textarea{scrollbar-width:thin!important;margin-bottom:.5rem!important}ion-select.dcf-select-label-placement-floating::part(label){line-height:1.2rem!important}.dcf-proccessing,.dcf-proccessing *{pointer-events:none;touch-action:none;cursor:text}ion-checkbox{--size: 1.5rem;--checkbox-background-checked: var(--dcf-color-primary);--checkmark-width: 2px}ion-item{--inner-padding-start: .75rem}ion-checkbox::part(container){border-radius:50%;padding:3px}@media (prefers-color-scheme: light){ion-checkbox::part(container){border:2px solid var(--dcf-color-primary)}}ion-item .dcf-radio-group-label,ion-radio-group .dcf-radio-group-label{font-weight:600}ion-item .dcf-radio-group-label~ion-item,ion-radio-group .dcf-radio-group-label~ion-item{margin-top:.5rem;--inner-padding-start: .75rem}ion-item+.dcf-helper,ion-radio-group+.dcf-helper{padding-left:.75rem;position:relative}.dcf-error{position:absolute;color:var(--dcf-color-danger)!important;font-size:.8rem!important;font-weight:600!important;line-height:1.1rem;box-sizing:border-box;z-index:9999;margin-top:0;animation-duration:.1s;animation-timing-function:ease-out;animation-fill-mode:both;animation-name:fadeTopSmallAnimation;display:flex;align-items:flex-start;gap:.25rem}.dcf-error .ti,.dcf-error ion-icon{position:relative;top:2px!important;min-width:20px;font-size:1rem!important;text-align:left}.dcf-helper{font-size:.875rem!important;font-weight:500;margin-top:.25rem;margin-bottom:-.75rem}.dcf-helper.dcf-has-action{cursor:pointer;color:var(--dcf-color-gray-7)!important;text-decoration:underline}.dcf-error+.dcf-helper{padding-top:1rem}@keyframes fadeTopSmallAnimation{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeBottomSmallAnimation{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeTopMediumAnimation{0%{opacity:0;transform:translateY(-50px)}to{opacity:1;transform:translateY(0)}}::ng-deep ion-textarea{min-height:80px!important;scrollbar-color:#888 #f0f0f0;scrollbar-width:thin}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { 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: "pipe", type: TranslatePipe, name: "translate" }, { 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"] }] }); }
3098
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: CrudFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
3099
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.2", type: CrudFieldComponent, isStandalone: true, selector: "ngx-decaf-crud-field", inputs: { operation: "operation", name: "name", 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", cols: "cols", rows: "rows", 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", activeFormGroup: "activeFormGroup", pk: "pk" }, host: { listeners: { "window:fieldsetAddGroupEvent": "handleFieldsetCreateGroupEvent($event)", "window:fieldsetUpdateGroupEvent": "handleFieldsetUpdateGroupEvent($event)", "window:fieldsetRemoveGroupEvent": "handleFieldsetRemoveGroupEvent($event)" }, properties: { "attr.id": "uid" } }, viewQueries: [{ propertyName: "component", first: true, predicate: ["component"], descendants: true, read: ElementRef }], usesInheritance: true, ngImport: i0, template: "@if(operation === 'read' || operation === 'delete') {\n <ng-container #component>\n <div [class]=\"'dcf-input-item ' + operation\">\n <ion-item>\n <ion-label>\n {{ label | translate }}<br />\n @if(value) {\n <ion-text [innerHTML]=\"type === 'password' ? '********' : value\"></ion-text>\n } @else {\n <br />\n }\n </ion-label>\n </ion-item>\n </div>\n </ng-container>\n} @else {\n <ng-container [formGroup]=\"getActiveFormGroup\">\n <div #container [class]=\"'dcf-input-item ' + (operation || 'create')\" (createGroupEvent)=\"multiple ? handleFieldsetCreateGroupEvent($event) : ''\">\n @if(type === 'textarea') {\n <ion-textarea\n [id]=\"name\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [autoGrow]=\"true\"\n [required]=\"required !== undefined ? required : null\"\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 <ion-item>\n <ion-checkbox\n [id]=\"name\"\n [mode]=\"mode\"\n [errorText]=\"getErrors(container)\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"justify\"\n [value]=\"value\"\n [checked]=\"checked\"\n [readonly]=\"readonly\"\n (ionChange)=\"checked = !checked\"\n [formControlName]=\"name\"\n #component>\n <span [innerHTML]=\"label | translate\"></span>\n </ion-checkbox>\n </ion-item>\n }\n @else if(type === 'radio') {\n <ion-radio-group [formControlName]=\"name\" [value]=\"value\" #component>\n <label class=\"dcf-radio-group-label\" [for]=\"path\">{{label | translate}}</label>\n @for(option of options; track option) {\n <ion-item>\n <ion-radio\n [id]=\"name\"\n [errorText]=\"getErrors(container)\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [alignment]=\"alignment\"\n [justify]=\"justify\"\n [readonly]=\"readonly\"\n [value]=\"option.value\"\n >{{ translatable ? (option?.text | translate) : option?.text }}</ion-radio>\n </ion-item>\n }\n </ion-radio-group>\n }\n @else if(type === 'select') {\n <ion-select\n [id]=\"name\"\n toggleIcon=\"chevron-down-outline\"\n expandedIcon=\"chevron-up-outline\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [label]=\"translatable ? (label | translate) : label\"\n [value]=\"value\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [errorText]=\"getErrors(container)\"\n [interface]=\"interface\" #component>\n @for(option of options; track option.value) {\n <ion-select-option [value]=\"option.value\">\n {{ option.text | translate }}\n </ion-select-option>\n }\n </ion-select>\n }\n @else {\n <ion-input\n [id]=\"name\"\n [type]=\"type\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [inputmode]=\"inputmode\"\n [labelPlacement]=\"labelPlacement\"\n [required]=\"required !== undefined ? required : false\"\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}\n\n", styles: ["@media (prefers-color-scheme: light){.dcf-input-item.read ion-label,.dcf-input-item.delete ion-label{color:var(--dcf-color-gray-7)}.dcf-input-item ion-item{--background-hover: var(--dcf-color-primary);--background-focused: var(--dcf-color-primary);--border-color: var(--dcf-color-gray-2)}ion-checkbox::part(container){border:2px solid var(--dcf-color-primary)}}@media (prefers-color-scheme: dark){.dcf-input-item ion-item{--border-color: var(--dcf-color-gray-6)}}.dcf-input-item.create,.dcf-input-item.update{margin-bottom:1.8rem;margin-top:0!important}.dcf-input-item.create.checkbox+.checkbox,.dcf-input-item.update.checkbox+.checkbox{margin-top:-.25rem!important}.dcf-input-item.create ion-item,.dcf-input-item.update ion-item{--border-color: transparent}.dcf-input-item.create ion-item.dcf-text-wrap ion-label>*,.dcf-input-item.update ion-item.dcf-text-wrap ion-label>*{white-space:wrap!important;word-break:break-all!important}.dcf-input-item.read ion-label,.dcf-input-item.delete ion-label{font-weight:600}.dcf-input-item.read ion-text,.dcf-input-item.delete ion-text{display:block;margin-top:.5rem!important}.dcf-input-item ion-item{--padding-end: 0rem;--padding-start: 0px !important;--padding-top: 0px !important;--background: transparent;--background-hover-opacity: .1;--background-activated-opacity: .15;--background-focused-opacity: .15}.dcf-input-item ion-item span,.dcf-input-item ion-item ion-text{font-weight:400!important;font-size:.925rem;min-height:.5rem!important}.dcf-input-item ion-item span:not(.dcf-display-block),.dcf-input-item ion-item ion-text:not(.dcf-display-block){display:inline-block}.dcf-input-item ion-item span.dcf-display-block,.dcf-input-item ion-item ion-text.dcf-display-block{display:block!important}ion-textarea textarea{scrollbar-width:thin!important;margin-bottom:.5rem!important}ion-select.dcf-select-label-placement-floating::part(label){line-height:1.2rem!important}.dcf-proccessing,.dcf-proccessing *{pointer-events:none;touch-action:none;cursor:text}ion-checkbox{--size: 1.5rem;--checkbox-background-checked: var(--dcf-color-primary);--checkmark-width: 2px}ion-item{--inner-padding-start: .75rem}ion-checkbox::part(container){border-radius:50%;padding:3px}ion-item .dcf-radio-group-label,ion-radio-group .dcf-radio-group-label{font-weight:600}ion-item .dcf-radio-group-label~ion-item,ion-radio-group .dcf-radio-group-label~ion-item{margin-top:.5rem;--inner-padding-start: .75rem}ion-item+.dcf-helper,ion-radio-group+.dcf-helper{padding-left:.75rem;position:relative}.dcf-error{position:absolute;color:var(--dcf-color-danger)!important;font-size:.8rem!important;font-weight:600!important;line-height:1.1rem;box-sizing:border-box;z-index:9999;margin-top:0;animation-duration:.1s;animation-timing-function:ease-out;animation-fill-mode:both;animation-name:fadeTopSmallAnimation;display:flex;align-items:flex-start;gap:.25rem}.dcf-error .ti,.dcf-error ion-icon{position:relative;top:2px!important;min-width:20px;font-size:1rem!important;text-align:left}.dcf-helper{font-size:.875rem!important;font-weight:500;margin-top:.25rem;margin-bottom:-.75rem}.dcf-helper.dcf-has-action{cursor:pointer;color:var(--dcf-color-gray-7)!important;text-decoration:underline}.dcf-error+.dcf-helper{padding-top:1rem}@keyframes fadeTopSmallAnimation{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeBottomSmallAnimation{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeTopMediumAnimation{0%{opacity:0;transform:translateY(-50px)}to{opacity:1;transform:translateY(0)}}::ng-deep ion-textarea{min-height:80px!important;scrollbar-color:#888 #f0f0f0;scrollbar-width:thin}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { 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" }] }); }
3106
3100
  };
3107
3101
  CrudFieldComponent = __decorate([
3108
3102
  Dynamic()
3109
3103
  ], CrudFieldComponent);
3110
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CrudFieldComponent, decorators: [{
3104
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: CrudFieldComponent, decorators: [{
3111
3105
  type: Component,
3112
3106
  args: [{ standalone: true, imports: [
3113
3107
  ReactiveFormsModule,
@@ -3121,9 +3115,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
3121
3115
  IonSelectOption,
3122
3116
  IonLabel,
3123
3117
  IonText,
3124
- IonTextarea,
3125
- IonIcon
3126
- ], selector: 'ngx-decaf-crud-field', schemas: [CUSTOM_ELEMENTS_SCHEMA], host: { '[attr.id]': 'uid' }, template: "@if(operation === 'read' || operation === 'delete') {\n <ng-container #component>\n <div [class]=\"'dcf-input-item ' + operation\">\n <ion-item>\n <ion-label>\n {{ label | translate }}<br />\n @if(value) {\n <ion-text [innerHTML]=\"type === 'password' ? '********' : value\"></ion-text>\n } @else {\n <br />\n }\n </ion-label>\n </ion-item>\n </div>\n </ng-container>\n} @else {\n <ng-container [formGroup]=\"getActiveFormGroup\">\n <div #container [class]=\"'dcf-input-item ' + (operation || 'create')\" (createGroupEvent)=\"multiple ? handleFieldsetCreateGroupEvent($event) : ''\">\n @if(type === 'textarea') {\n <ion-textarea\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [autoGrow]=\"true\"\n [required]=\"required !== undefined ? required : null\"\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 <ion-item>\n <ion-checkbox\n #checkboxElement\n [mode]=\"mode\"\n [errorText]=\"getErrors(container)\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"justify\"\n [value]=\"value\"\n [checked]=\"checked\"\n [readonly]=\"readonly\"\n (ionChange)=\"checked = !checked\"\n [formControlName]=\"name\"\n #component>\n <span [innerHTML]=\"label | translate\"></span>\n </ion-checkbox>\n </ion-item>\n }\n @else if(type === 'radio') {\n <ion-radio-group [formControlName]=\"name\" [value]=\"value\" #component>\n <label class=\"dcf-radio-group-label\" [for]=\"path\">{{label | translate}}</label>\n @for(option of options; track option) {\n <ion-item>\n <ion-radio\n [errorText]=\"getErrors(container)\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [alignment]=\"alignment\"\n [justify]=\"justify\"\n [readonly]=\"readonly\"\n [value]=\"option.value\"\n >{{ translatable ? (option?.text | translate) : option?.text }}</ion-radio>\n </ion-item>\n }\n </ion-radio-group>\n }\n @else if(type === 'select') {\n <ion-select\n toggleIcon=\"chevron-down-outline\"\n expandedIcon=\"chevron-up-outline\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [label]=\"translatable ? (label | translate) : label\"\n [value]=\"value\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [errorText]=\"getErrors(container)\"\n [interface]=\"interface\" #component>\n @for(option of options; track option.value) {\n <ion-select-option [value]=\"option.value\">\n {{ option.text | translate }}\n </ion-select-option>\n }\n </ion-select>\n }\n @else {\n <ion-input\n [type]=\"type\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [inputmode]=\"inputmode\"\n [labelPlacement]=\"labelPlacement\"\n [required]=\"required !== undefined ? required : false\"\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}\n\n", styles: [".dcf-input-item.create,.dcf-input-item.update{margin-bottom:1.8rem;margin-top:0!important}.dcf-input-item.create.checkbox+.checkbox,.dcf-input-item.update.checkbox+.checkbox{margin-top:-.25rem!important}.dcf-input-item.create ion-item,.dcf-input-item.update ion-item{--border-color: transparent}.dcf-input-item.create ion-item.dcf-text-wrap ion-label>*,.dcf-input-item.update ion-item.dcf-text-wrap ion-label>*{white-space:wrap!important;word-break:break-all!important}.dcf-input-item.read ion-label,.dcf-input-item.delete ion-label{font-weight:600}@media (prefers-color-scheme: light){.dcf-input-item.read ion-label,.dcf-input-item.delete ion-label{color:var(--dcf-color-gray-7)}}.dcf-input-item.read ion-text,.dcf-input-item.delete ion-text{display:block;margin-top:.5rem!important}.dcf-input-item ion-item{--padding-end: 0rem;--padding-start: 0px !important;--padding-top: 0px !important;--background: transparent;--background-hover-opacity: .1;--background-activated-opacity: .15;--background-focused-opacity: .15}@media (prefers-color-scheme: dark){.dcf-input-item ion-item{--border-color: var(--dcf-color-gray-6)}}@media (prefers-color-scheme: light){.dcf-input-item ion-item{--background-hover: var(--dcf-color-primary);--background-focused: var(--dcf-color-primary);--border-color: var(--dcf-color-gray-2)}}.dcf-input-item ion-item span,.dcf-input-item ion-item ion-text{font-weight:400!important;font-size:.925rem;min-height:.5rem!important}.dcf-input-item ion-item span:not(.dcf-display-block),.dcf-input-item ion-item ion-text:not(.dcf-display-block){display:inline-block}.dcf-input-item ion-item span.dcf-display-block,.dcf-input-item ion-item ion-text.dcf-display-block{display:block!important}ion-textarea textarea{scrollbar-width:thin!important;margin-bottom:.5rem!important}ion-select.dcf-select-label-placement-floating::part(label){line-height:1.2rem!important}.dcf-proccessing,.dcf-proccessing *{pointer-events:none;touch-action:none;cursor:text}ion-checkbox{--size: 1.5rem;--checkbox-background-checked: var(--dcf-color-primary);--checkmark-width: 2px}ion-item{--inner-padding-start: .75rem}ion-checkbox::part(container){border-radius:50%;padding:3px}@media (prefers-color-scheme: light){ion-checkbox::part(container){border:2px solid var(--dcf-color-primary)}}ion-item .dcf-radio-group-label,ion-radio-group .dcf-radio-group-label{font-weight:600}ion-item .dcf-radio-group-label~ion-item,ion-radio-group .dcf-radio-group-label~ion-item{margin-top:.5rem;--inner-padding-start: .75rem}ion-item+.dcf-helper,ion-radio-group+.dcf-helper{padding-left:.75rem;position:relative}.dcf-error{position:absolute;color:var(--dcf-color-danger)!important;font-size:.8rem!important;font-weight:600!important;line-height:1.1rem;box-sizing:border-box;z-index:9999;margin-top:0;animation-duration:.1s;animation-timing-function:ease-out;animation-fill-mode:both;animation-name:fadeTopSmallAnimation;display:flex;align-items:flex-start;gap:.25rem}.dcf-error .ti,.dcf-error ion-icon{position:relative;top:2px!important;min-width:20px;font-size:1rem!important;text-align:left}.dcf-helper{font-size:.875rem!important;font-weight:500;margin-top:.25rem;margin-bottom:-.75rem}.dcf-helper.dcf-has-action{cursor:pointer;color:var(--dcf-color-gray-7)!important;text-decoration:underline}.dcf-error+.dcf-helper{padding-top:1rem}@keyframes fadeTopSmallAnimation{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeBottomSmallAnimation{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeTopMediumAnimation{0%{opacity:0;transform:translateY(-50px)}to{opacity:1;transform:translateY(0)}}::ng-deep ion-textarea{min-height:80px!important;scrollbar-color:#888 #f0f0f0;scrollbar-width:thin}\n"] }]
3118
+ IonTextarea
3119
+ ], selector: 'ngx-decaf-crud-field', schemas: [CUSTOM_ELEMENTS_SCHEMA], host: { '[attr.id]': 'uid' }, template: "@if(operation === 'read' || operation === 'delete') {\n <ng-container #component>\n <div [class]=\"'dcf-input-item ' + operation\">\n <ion-item>\n <ion-label>\n {{ label | translate }}<br />\n @if(value) {\n <ion-text [innerHTML]=\"type === 'password' ? '********' : value\"></ion-text>\n } @else {\n <br />\n }\n </ion-label>\n </ion-item>\n </div>\n </ng-container>\n} @else {\n <ng-container [formGroup]=\"getActiveFormGroup\">\n <div #container [class]=\"'dcf-input-item ' + (operation || 'create')\" (createGroupEvent)=\"multiple ? handleFieldsetCreateGroupEvent($event) : ''\">\n @if(type === 'textarea') {\n <ion-textarea\n [id]=\"name\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [autoGrow]=\"true\"\n [required]=\"required !== undefined ? required : null\"\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 <ion-item>\n <ion-checkbox\n [id]=\"name\"\n [mode]=\"mode\"\n [errorText]=\"getErrors(container)\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"justify\"\n [value]=\"value\"\n [checked]=\"checked\"\n [readonly]=\"readonly\"\n (ionChange)=\"checked = !checked\"\n [formControlName]=\"name\"\n #component>\n <span [innerHTML]=\"label | translate\"></span>\n </ion-checkbox>\n </ion-item>\n }\n @else if(type === 'radio') {\n <ion-radio-group [formControlName]=\"name\" [value]=\"value\" #component>\n <label class=\"dcf-radio-group-label\" [for]=\"path\">{{label | translate}}</label>\n @for(option of options; track option) {\n <ion-item>\n <ion-radio\n [id]=\"name\"\n [errorText]=\"getErrors(container)\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [alignment]=\"alignment\"\n [justify]=\"justify\"\n [readonly]=\"readonly\"\n [value]=\"option.value\"\n >{{ translatable ? (option?.text | translate) : option?.text }}</ion-radio>\n </ion-item>\n }\n </ion-radio-group>\n }\n @else if(type === 'select') {\n <ion-select\n [id]=\"name\"\n toggleIcon=\"chevron-down-outline\"\n expandedIcon=\"chevron-up-outline\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [label]=\"translatable ? (label | translate) : label\"\n [value]=\"value\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [errorText]=\"getErrors(container)\"\n [interface]=\"interface\" #component>\n @for(option of options; track option.value) {\n <ion-select-option [value]=\"option.value\">\n {{ option.text | translate }}\n </ion-select-option>\n }\n </ion-select>\n }\n @else {\n <ion-input\n [id]=\"name\"\n [type]=\"type\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [inputmode]=\"inputmode\"\n [labelPlacement]=\"labelPlacement\"\n [required]=\"required !== undefined ? required : false\"\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}\n\n", styles: ["@media (prefers-color-scheme: light){.dcf-input-item.read ion-label,.dcf-input-item.delete ion-label{color:var(--dcf-color-gray-7)}.dcf-input-item ion-item{--background-hover: var(--dcf-color-primary);--background-focused: var(--dcf-color-primary);--border-color: var(--dcf-color-gray-2)}ion-checkbox::part(container){border:2px solid var(--dcf-color-primary)}}@media (prefers-color-scheme: dark){.dcf-input-item ion-item{--border-color: var(--dcf-color-gray-6)}}.dcf-input-item.create,.dcf-input-item.update{margin-bottom:1.8rem;margin-top:0!important}.dcf-input-item.create.checkbox+.checkbox,.dcf-input-item.update.checkbox+.checkbox{margin-top:-.25rem!important}.dcf-input-item.create ion-item,.dcf-input-item.update ion-item{--border-color: transparent}.dcf-input-item.create ion-item.dcf-text-wrap ion-label>*,.dcf-input-item.update ion-item.dcf-text-wrap ion-label>*{white-space:wrap!important;word-break:break-all!important}.dcf-input-item.read ion-label,.dcf-input-item.delete ion-label{font-weight:600}.dcf-input-item.read ion-text,.dcf-input-item.delete ion-text{display:block;margin-top:.5rem!important}.dcf-input-item ion-item{--padding-end: 0rem;--padding-start: 0px !important;--padding-top: 0px !important;--background: transparent;--background-hover-opacity: .1;--background-activated-opacity: .15;--background-focused-opacity: .15}.dcf-input-item ion-item span,.dcf-input-item ion-item ion-text{font-weight:400!important;font-size:.925rem;min-height:.5rem!important}.dcf-input-item ion-item span:not(.dcf-display-block),.dcf-input-item ion-item ion-text:not(.dcf-display-block){display:inline-block}.dcf-input-item ion-item span.dcf-display-block,.dcf-input-item ion-item ion-text.dcf-display-block{display:block!important}ion-textarea textarea{scrollbar-width:thin!important;margin-bottom:.5rem!important}ion-select.dcf-select-label-placement-floating::part(label){line-height:1.2rem!important}.dcf-proccessing,.dcf-proccessing *{pointer-events:none;touch-action:none;cursor:text}ion-checkbox{--size: 1.5rem;--checkbox-background-checked: var(--dcf-color-primary);--checkmark-width: 2px}ion-item{--inner-padding-start: .75rem}ion-checkbox::part(container){border-radius:50%;padding:3px}ion-item .dcf-radio-group-label,ion-radio-group .dcf-radio-group-label{font-weight:600}ion-item .dcf-radio-group-label~ion-item,ion-radio-group .dcf-radio-group-label~ion-item{margin-top:.5rem;--inner-padding-start: .75rem}ion-item+.dcf-helper,ion-radio-group+.dcf-helper{padding-left:.75rem;position:relative}.dcf-error{position:absolute;color:var(--dcf-color-danger)!important;font-size:.8rem!important;font-weight:600!important;line-height:1.1rem;box-sizing:border-box;z-index:9999;margin-top:0;animation-duration:.1s;animation-timing-function:ease-out;animation-fill-mode:both;animation-name:fadeTopSmallAnimation;display:flex;align-items:flex-start;gap:.25rem}.dcf-error .ti,.dcf-error ion-icon{position:relative;top:2px!important;min-width:20px;font-size:1rem!important;text-align:left}.dcf-helper{font-size:.875rem!important;font-weight:500;margin-top:.25rem;margin-bottom:-.75rem}.dcf-helper.dcf-has-action{cursor:pointer;color:var(--dcf-color-gray-7)!important;text-decoration:underline}.dcf-error+.dcf-helper{padding-top:1rem}@keyframes fadeTopSmallAnimation{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeBottomSmallAnimation{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeTopMediumAnimation{0%{opacity:0;transform:translateY(-50px)}to{opacity:1;transform:translateY(0)}}::ng-deep ion-textarea{min-height:80px!important;scrollbar-color:#888 #f0f0f0;scrollbar-width:thin}\n"] }]
3127
3120
  }], propDecorators: { operation: [{
3128
3121
  type: Input,
3129
3122
  args: [{ required: true }]
@@ -3743,10 +3736,10 @@ class NgxBaseComponent {
3743
3736
  if (!this.initialized)
3744
3737
  this.initialized = true;
3745
3738
  }
3746
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NgxBaseComponent, deps: [{ token: 'instanceToken' }], target: i0.ɵɵFactoryTarget.Component }); }
3747
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: NgxBaseComponent, isStandalone: true, selector: "ng-component", inputs: { rendererId: "rendererId", model: "model", props: "props", item: "item", pk: "pk", route: "route", operations: "operations", uid: "uid", mapper: "mapper", locale: "locale", translatable: "translatable", className: "className", mode: "mode", renderChild: "renderChild" }, outputs: { listenEvent: "listenEvent" }, host: { properties: { "attr.id": "uid" } }, viewQueries: [{ propertyName: "component", first: true, predicate: ["component"], descendants: true, read: ElementRef, static: true }], usesOnChanges: true, ngImport: i0, template: '<div></div>', isInline: true }); }
3739
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NgxBaseComponent, deps: [{ token: 'instanceToken' }], target: i0.ɵɵFactoryTarget.Component }); }
3740
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.2", type: NgxBaseComponent, isStandalone: true, selector: "ng-component", inputs: { rendererId: "rendererId", model: "model", props: "props", item: "item", pk: "pk", route: "route", operations: "operations", uid: "uid", mapper: "mapper", locale: "locale", translatable: "translatable", className: "className", mode: "mode", renderChild: "renderChild" }, outputs: { listenEvent: "listenEvent" }, host: { properties: { "attr.id": "uid" } }, viewQueries: [{ propertyName: "component", first: true, predicate: ["component"], descendants: true, read: ElementRef, static: true }], usesOnChanges: true, ngImport: i0, template: '<div></div>', isInline: true }); }
3748
3741
  }
3749
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NgxBaseComponent, decorators: [{
3742
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NgxBaseComponent, decorators: [{
3750
3743
  type: Component,
3751
3744
  args: [{
3752
3745
  standalone: true,
@@ -4015,13 +4008,13 @@ let CrudFormComponent = class CrudFormComponent {
4015
4008
  name: EventConstants.SUBMIT,
4016
4009
  });
4017
4010
  }
4018
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CrudFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4019
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: CrudFormComponent, isStandalone: true, selector: "ngx-decaf-crud-form", inputs: { model: "model", modelId: "modelId", updateOn: "updateOn", target: "target", method: "method", options: "options", action: "action", operation: "operation", handlers: "handlers", formGroup: "formGroup", childOf: "childOf", rendererId: "rendererId", uid: "uid", allowClear: "allowClear" }, outputs: { submitEvent: "submitEvent" }, host: { properties: { "attr.id": "uid" } }, viewQueries: [{ propertyName: "component", first: true, predicate: ["reactiveForm"], descendants: true, read: ElementRef }], ngImport: i0, template: "@if(operation !== 'read' && operation !== 'delete') {\n <form #reactiveForm [id]=\"rendererId\" [formGroup]=\"formGroup\" (submit)=\"submit($event)\" novalidate [target]=\"target\">\n <ng-content #formContent></ng-content>\n <div class=\"dcf-buttons-container dcf-grid dcf-grid-collapse dcf-flex dcf-flex-left\">\n <div>\n <ion-button type=\"submit\" [expand]=\"action ? 'block' : 'default'\">\n @if(options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{ action ? action : options.buttons.submit.text}}\n </ion-button>\n </div>\n @if(!action) {\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if(options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n Back\n </ion-button>\n </div>\n }\n </div>\n </form>\n} @else {\n <div [class]=\"'dcf-buttons-container dcf-grid dcf-grid-collapse dcf-flex dcf-flex-left ' + operation\" [id]=\"uid\">\n @if(operation === OperationKeys.READ && modelId) {\n <div>\n <ion-button\n (click)=\"handleDelete()\"\n color=\"danger\"\n type=\"button\">\n @if(options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n Delete\n </ion-button>\n </div>\n\n }\n @if(operation === OperationKeys.CREATE || operation === OperationKeys.UPDATE) {\n\n <div>\n <ion-button\n type=\"submit\">\n @if(options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{options.buttons.submit.text}}\n </ion-button>\n </div>\n }\n\n @if(options.buttons.clear) {\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if(options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n {{ [OperationKeys.DELETE, OperationKeys.READ, OperationKeys.UPDATE].includes(operation) ? 'Back' : options.buttons.clear?.text}}\n </ion-button>\n </div>\n\n }\n </div>\n}\n\n", styles: [".dcf-buttons-container{margin-top:1.8rem;margin-bottom:0}@media (min-width: 768px){.dcf-buttons-container.dcf-flex{flex-direction:row-reverse}}@media (max-width: 767px){.dcf-buttons-container.dcf-flex div{width:100%}.dcf-buttons-container.dcf-flex ion-button{width:100%;margin-bottom:1rem}}form{padding:2rem 1rem}\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: 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"] }] }); }
4011
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: CrudFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4012
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.2", type: CrudFormComponent, isStandalone: true, selector: "ngx-decaf-crud-form", inputs: { model: "model", modelId: "modelId", updateOn: "updateOn", target: "target", method: "method", options: "options", action: "action", operation: "operation", handlers: "handlers", formGroup: "formGroup", childOf: "childOf", rendererId: "rendererId", uid: "uid", allowClear: "allowClear" }, outputs: { submitEvent: "submitEvent" }, host: { properties: { "attr.id": "uid" } }, viewQueries: [{ propertyName: "component", first: true, predicate: ["reactiveForm"], descendants: true, read: ElementRef }], ngImport: i0, template: "@if(operation !== 'read' && operation !== 'delete') {\n <form #reactiveForm [id]=\"rendererId\" [formGroup]=\"formGroup\" (submit)=\"submit($event)\" novalidate [target]=\"target\">\n <ng-content #formContent></ng-content>\n <div class=\"dcf-buttons-container dcf-grid dcf-grid-collapse dcf-flex dcf-flex-left\">\n <div>\n <ion-button type=\"submit\" [expand]=\"action ? 'block' : 'default'\">\n @if(options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{ action ? action : options.buttons.submit.text}}\n </ion-button>\n </div>\n @if(!action) {\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if(options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n Back\n </ion-button>\n </div>\n }\n </div>\n </form>\n} @else {\n <div [class]=\"'dcf-buttons-container dcf-grid dcf-grid-collapse dcf-flex dcf-flex-left ' + operation\" [id]=\"uid\">\n @if(operation === OperationKeys.READ && modelId) {\n <div>\n <ion-button\n (click)=\"handleDelete()\"\n color=\"danger\"\n type=\"button\">\n @if(options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n Delete\n </ion-button>\n </div>\n\n }\n @if(operation === OperationKeys.CREATE || operation === OperationKeys.UPDATE) {\n\n <div>\n <ion-button\n type=\"submit\">\n @if(options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{options.buttons.submit.text}}\n </ion-button>\n </div>\n }\n\n @if(options.buttons.clear) {\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if(options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n {{ [OperationKeys.DELETE, OperationKeys.READ, OperationKeys.UPDATE].includes(operation) ? 'Back' : options.buttons.clear?.text}}\n </ion-button>\n </div>\n\n }\n </div>\n}\n\n", styles: [".dcf-buttons-container{margin-top:1.8rem;margin-bottom:0}@media (min-width: 768px){.dcf-buttons-container.dcf-flex{flex-direction:row-reverse}}@media (max-width: 767px){.dcf-buttons-container.dcf-flex div{width:100%}.dcf-buttons-container.dcf-flex ion-button{width:100%;margin-bottom:1rem}}form{padding:2rem 1rem}\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: 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"] }] }); }
4020
4013
  };
4021
4014
  CrudFormComponent = __decorate([
4022
4015
  Dynamic()
4023
4016
  ], CrudFormComponent);
4024
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CrudFormComponent, decorators: [{
4017
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: CrudFormComponent, decorators: [{
4025
4018
  type: Component,
4026
4019
  args: [{ standalone: true, selector: 'ngx-decaf-crud-form', imports: [ReactiveFormsModule, IonButton, IonIcon], host: { '[attr.id]': 'uid' }, template: "@if(operation !== 'read' && operation !== 'delete') {\n <form #reactiveForm [id]=\"rendererId\" [formGroup]=\"formGroup\" (submit)=\"submit($event)\" novalidate [target]=\"target\">\n <ng-content #formContent></ng-content>\n <div class=\"dcf-buttons-container dcf-grid dcf-grid-collapse dcf-flex dcf-flex-left\">\n <div>\n <ion-button type=\"submit\" [expand]=\"action ? 'block' : 'default'\">\n @if(options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{ action ? action : options.buttons.submit.text}}\n </ion-button>\n </div>\n @if(!action) {\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if(options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n Back\n </ion-button>\n </div>\n }\n </div>\n </form>\n} @else {\n <div [class]=\"'dcf-buttons-container dcf-grid dcf-grid-collapse dcf-flex dcf-flex-left ' + operation\" [id]=\"uid\">\n @if(operation === OperationKeys.READ && modelId) {\n <div>\n <ion-button\n (click)=\"handleDelete()\"\n color=\"danger\"\n type=\"button\">\n @if(options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n Delete\n </ion-button>\n </div>\n\n }\n @if(operation === OperationKeys.CREATE || operation === OperationKeys.UPDATE) {\n\n <div>\n <ion-button\n type=\"submit\">\n @if(options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{options.buttons.submit.text}}\n </ion-button>\n </div>\n }\n\n @if(options.buttons.clear) {\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if(options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n {{ [OperationKeys.DELETE, OperationKeys.READ, OperationKeys.UPDATE].includes(operation) ? 'Back' : options.buttons.clear?.text}}\n </ion-button>\n </div>\n\n }\n </div>\n}\n\n", styles: [".dcf-buttons-container{margin-top:1.8rem;margin-bottom:0}@media (min-width: 768px){.dcf-buttons-container.dcf-flex{flex-direction:row-reverse}}@media (max-width: 767px){.dcf-buttons-container.dcf-flex div{width:100%}.dcf-buttons-container.dcf-flex ion-button{width:100%;margin-bottom:1rem}}form{padding:2rem 1rem}\n"] }]
4027
4020
  }], propDecorators: { model: [{
@@ -4347,17 +4340,16 @@ let EmptyStateComponent = class EmptyStateComponent extends NgxBaseComponent {
4347
4340
  const result = await this.translate.instant(content, { 'value0': this.searchValue });
4348
4341
  return this.sanitizer.bypassSecurityTrustHtml(result);
4349
4342
  }
4350
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: EmptyStateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4351
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: EmptyStateComponent, isStandalone: true, selector: "ngx-decaf-empty-state", inputs: { title: "title", titleColor: "titleColor", subtitle: "subtitle", subtitleColor: "subtitleColor", showIcon: "showIcon", icon: "icon", iconSize: "iconSize", iconColor: "iconColor", buttonLink: "buttonLink", buttonText: "buttonText", buttonFill: "buttonFill", buttonColor: "buttonColor", buttonSize: "buttonSize", searchValue: "searchValue" }, usesInheritance: true, ngImport: i0, template: "\n<ion-card [id]=\"uid\" [class]=\"className\">\n <ion-card-content>\n @if(icon && showIcon) {\n <div class=\"dcf-icon-container\">\n <ion-icon\n name=\"alert-circle-outline\"\n size=\"large\"\n color=\"danger\"\n />\n </div>\n }\n @if(title) {\n <h5 [class]=\"titleColor\" [innerHTML]=\"title\"></h5>\n }\n @if(subtitle) {\n @if(!searchValue) {\n <p [class]=\"subtitleColor\" [innerHTML]=\"subtitle\"></p>\n } @else {\n <p [class]=\"subtitleColor\" [innerHTML]=\"searchSubtitle\"></p>\n }\n }\n @if(buttonLink && buttonText) {\n <div>\n <ion-button\n [size]=\"buttonSize\"\n [fill]=\"buttonFill\"\n [color]=\"buttonColor\"\n (click)=\"handleClick()\">\n {{ buttonText }}\n </ion-button>\n </div>\n }\n </ion-card-content>\n</ion-card>\n", styles: ["ion-card{text-align:center}ion-card ion-button{margin-top:.75rem}ion-card ion-icon{font-size:2.5rem}ion-card .dcf-icon-container{transform:scale(1.25);opacity:.75;margin-top:1.25rem!important;margin-bottom:.5rem!important}ion-card .dcf-ititle{font-weight:600!important;color:var(--dcf-color-gray-6)!important}ion-card .dcf-isubtitle{font-weight:500!important}\n"], dependencies: [{ kind: "component", type: IonCard, selector: "ion-card", inputs: ["button", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonCardContent, selector: "ion-card-content", inputs: ["mode"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }] }); }
4343
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: EmptyStateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4344
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.2", type: EmptyStateComponent, isStandalone: true, selector: "ngx-decaf-empty-state", inputs: { title: "title", titleColor: "titleColor", subtitle: "subtitle", subtitleColor: "subtitleColor", showIcon: "showIcon", icon: "icon", iconSize: "iconSize", iconColor: "iconColor", buttonLink: "buttonLink", buttonText: "buttonText", buttonFill: "buttonFill", buttonColor: "buttonColor", buttonSize: "buttonSize", searchValue: "searchValue" }, usesInheritance: true, ngImport: i0, template: "\n<ion-card [id]=\"uid\" [class]=\"className\">\n <ion-card-content>\n @if(icon && showIcon) {\n <div class=\"dcf-icon-container\">\n <ion-icon\n name=\"alert-circle-outline\"\n size=\"large\"\n color=\"danger\"\n />\n </div>\n }\n @if(title) {\n <h5 [class]=\"titleColor\" [innerHTML]=\"title\"></h5>\n }\n @if(subtitle) {\n @if(!searchValue) {\n <p [class]=\"subtitleColor\" [innerHTML]=\"subtitle\"></p>\n } @else {\n <p [class]=\"subtitleColor\" [innerHTML]=\"searchSubtitle\"></p>\n }\n }\n @if(buttonLink && buttonText) {\n <div>\n <ion-button\n [size]=\"buttonSize\"\n [fill]=\"buttonFill\"\n [color]=\"buttonColor\"\n (click)=\"handleClick()\">\n {{ buttonText }}\n </ion-button>\n </div>\n }\n </ion-card-content>\n</ion-card>\n", styles: ["ion-card{text-align:center}ion-card ion-button{margin-top:.75rem}ion-card ion-icon{font-size:2.5rem}ion-card .dcf-icon-container{transform:scale(1.25);opacity:.75;margin-top:1.25rem!important;margin-bottom:.5rem!important}ion-card .dcf-ititle{font-weight:600!important;color:var(--dcf-color-gray-6)!important}ion-card .dcf-isubtitle{font-weight:500!important}\n"], dependencies: [{ kind: "component", type: IonCard, selector: "ion-card", inputs: ["button", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonCardContent, selector: "ion-card-content", inputs: ["mode"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }] }); }
4352
4345
  };
4353
4346
  EmptyStateComponent = __decorate([
4354
4347
  Dynamic(),
4355
4348
  __metadata("design:paramtypes", [])
4356
4349
  ], EmptyStateComponent);
4357
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: EmptyStateComponent, decorators: [{
4350
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: EmptyStateComponent, decorators: [{
4358
4351
  type: Component,
4359
4352
  args: [{ selector: 'ngx-decaf-empty-state', standalone: true, imports: [
4360
- TranslatePipe,
4361
4353
  IonCard,
4362
4354
  IonCardContent,
4363
4355
  IonIcon
@@ -5001,14 +4993,14 @@ let FieldsetComponent = class FieldsetComponent extends NgxBaseComponent {
5001
4993
  }
5002
4994
  return this.mapper;
5003
4995
  }
5004
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FieldsetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
5005
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: FieldsetComponent, isStandalone: true, selector: "ngx-decaf-fieldset", inputs: { name: "name", childOf: "childOf", page: "page", uid: "uid", customTypes: "customTypes", operation: "operation", formGroup: "formGroup", title: "title", description: "description", target: "target", multiple: "multiple", value: "value", handlers: "handlers" }, host: { properties: { "attr.id": "overriode " } }, viewQueries: [{ propertyName: "accordionComponent", first: true, predicate: ["accordionComponent"], descendants: true }], usesInheritance: true, ngImport: i0, template: "\n\n<fieldset\n (fieldsetAddGroupEvent)=\"handleCreateItem($event)\"\n (fieldsetRemoveGroupEvent)=\"handleRemoveItem(undefined, $event)\"\n [class]=\"'dcf-fieldset ' + operation\"\n #component>\n <ion-accordion-group [class.open]=\"isOpen\" [class.hasValidationErrors]=\"hasValidationErrors\" (validationErrorEvent)=\"handleValidationError($event)\" #accordionComponent>\n <ion-accordion value=\"open\">\n <ion-item slot=\"header\" (click)=\"handleAccordionToggle($event)\">\n <div class=\"dcf-grid dcf-grid-collapse dcf-flex dcf-flex-middle dcf-width-1-1\">\n <div class=\"dcf-width-expand\">\n <legend>{{ name | translate }}</legend>\n </div>\n @if(!isRequired && ['create', 'update'].includes(operation)) {\n <div class=\"dcf-width-auto dcf-delete\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleRemoveComponent($event)\">\n <ion-icon name=\"trash-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n }\n </div>\n </ion-item>\n <div slot=\"content\" [attr.aria-hidden]=\"!isOpen\">\n @if(multiple && items.length) {\n <ion-list class=\"dcf-fields-list\">\n <ion-reorder-group [formGroup]=\"formGroup.parent\" [disabled]=\"updatingItem\" (ionItemReorder)=\"handleReorderItems($any($event))\" #accordionComponent>\n @for(item of items; track item.index) {\n <ion-item [class.not-unique]=\"item.title === isUniqueError\" [class.updating]=\"updatingItem?.[pk] === item.title\" lines=\"full\" [button]=\"false\">\n @if(items?.length > 1 && !updatingItem) {\n <ion-reorder slot=\"start\">\n <ion-icon name=\"swap-vertical-outline\"></ion-icon>\n </ion-reorder>\n } @else {\n <div slot=\"start\">\n <ion-icon class=\"dcf-reorder-disabled\" size=\"small\" name=\"swap-vertical-outline\" disabled></ion-icon>\n </div>\n }\n <ion-label [color]=\"(item.title === isUniqueError && !updatingItem?.[pk] === item.title) ? 'danger' : ''\">{{ item.index }}. {{ item.title }}\n @if(item.description?.length > 0) {\n <br />\n <ion-text class=\"dcf-subtitle\">{{item.description}}</ion-text>\n }\n </ion-label>\n @if(!updatingItem || updatingItem?.[pk] !== item.title) {\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleUpdateItem(item.title, $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(item.title)\">\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 <ng-content select=\"[slot=content]\"></ng-content>\n\n @if(multiple && ['create', 'update'].includes(operation)) {\n @if(isUniqueError) {\n <div class=\"dcf-not-unique-container dcf-animation dcf-animation-bottom-small dcf-animation-fast\">\n <div class=\" dcf-grid dcf-grid-collapse dcf-width-1-1 \">\n <div class=\"dcf-auto\" [attr.style]=\"'max-width: 50px'\">\n <ion-icon name=\"alert-circle-outline\"></ion-icon>\n </div>\n <div class=\"dcf-width-expand\">\n <ion-text color=\"danger\" class=\"dcf-text-small\">{{ locale + '.not_unique' | translate : { value: isUniqueError } }}</ion-text>\n </div>\n </div>\n </div>\n }\n <div class=\"dcf-margin-bottom dcf-grid dcf-grid-collapse dcf-flex\">\n @if(updatingItem) {\n <ion-button size=\"small\" fill=\"clear\" color=\"danger\" (click)=\"handleCancelUpdateItem()\">\n {{ buttonCancelLabel }}\n </ion-button>\n }\n <ion-button size=\"small\" fill=\"clear\" class=\"dcf-button-add\" (click)=\"handleCreateItem()\">\n <ion-icon name=\"add-outline\" slot=\"start\"></ion-icon>\n {{buttonLabel}}\n </ion-button>\n\n </div>\n }\n\n </div>\n </ion-accordion>\n </ion-accordion-group>\n</fieldset>\n\n", styles: ["ion-accordion-group ion-item[slot=header] .dcf-delete{width:30px}ion-accordion-group ion-item[slot=header] .dcf-delete ion-button{transform:translateY(-2px)}ion-accordion-group ion-item[slot=header] .dcf-delete ion-icon{font-size:1.15rem}::ng-deep ion-accordion ngx-decaf-crud-field:last-child ion-item{--inner-border-width: 0px !important;--border-width: 0px !important}.dcf-fieldset{margin-bottom:1.8rem;margin-top:1rem;padding-bottom:0;padding-top:1rem;background:var(--dcf-card-background);border-radius:6px;height:100%}@media (prefers-color-scheme: light){.dcf-fieldset{border:1px solid var(--dcf-color-gray-3)}.dcf-fieldset .dcf-button-add{color:var(--ion-color-dark)!important}}@media (prefers-color-scheme: dark){.dcf-fieldset{border:1px solid var(--dcf-color-step-400)}.dcf-fieldset .dcf-button-add{color:var(--ion-color-gray-2)}}.dcf-fieldset.read,.dcf-fieldset.delete{margin-top:1.25rem;padding-bottom:1rem}.dcf-fieldset.read [slot=content],.dcf-fieldset.delete [slot=content]{padding-top:0!important}.dcf-fieldset.read ion-accordion,.dcf-fieldset.delete ion-accordion{margin-bottom:0rem!important}@media (prefers-color-scheme: dark){.dcf-fieldset.read,.dcf-fieldset.delete{border:1px solid var(--dcf-color-gray-6)}}.dcf-fieldset ion-accordion{background:var(--dcf-card-background);margin-bottom:1rem}.dcf-fieldset ion-accordion.accordion-collapsing,.dcf-fieldset ion-accordion.accordion-collapsed{margin-bottom:1rem}.dcf-fieldset ion-accordion ion-item[slot=header]{--border-color: transparent;--border-radius: 6px;--inner-border-width: 0;--padding-start: 12px}.dcf-fieldset ion-accordion ion-item[slot=header] legend{font-weight:600;font-size:1rem;margin:0}@media (prefers-color-scheme: light){.dcf-fieldset ion-accordion ion-item[slot=header] legend{color:var(--dcf-color-gray-7)}}.dcf-fieldset ion-accordion [slot=content]{padding-top:2rem!important;padding-inline:.75rem}.dcf-not-unique-container{display:flex;justify-content:center;align-items:center;margin-bottom:1rem;flex:1 1 auto}.dcf-not-unique-container>div{display:flex;justify-content:center;align-items:center}.dcf-not-unique-container ion-icon{transform:translatey(2px);margin-right:5px}.dcf-fields-list{margin-top:-1rem;margin-bottom:1rem;padding:0!important}.dcf-fields-list ion-item{--min-height: 50px;--padding-top: .25rem;--padding-bottom: .25rem;--padding-start: .75rem;--padding-end: .75rem;--inner-padding-start: 0px !important;--inner-padding-end: 0px !important;--border-color: var(--dcf-color-gray-2) !important;border:1px solid transparent;box-sizing:border-box}.dcf-fields-list ion-item ion-icon.dcf-reorder-disabled{width:1rem;transform:translatey(2px);color:var(--dcf-color-gray-4)}.dcf-fields-list ion-item.updating{--background: rgba(var(--dcf-color-primary-rgb), .1) !important}.dcf-fields-list ion-item.not-unique{--background: rgba(var(--dcf-color-danger-rgb), .05) !important}.dcf-fields-list ion-item .dcf-subtitle{font-size:.8rem;color:var(--dcf-color-gray-7)}\n"], dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }, { 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"] }] }); }
4996
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: FieldsetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4997
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.2", type: FieldsetComponent, isStandalone: true, selector: "ngx-decaf-fieldset", inputs: { name: "name", childOf: "childOf", page: "page", uid: "uid", customTypes: "customTypes", operation: "operation", formGroup: "formGroup", title: "title", description: "description", target: "target", multiple: "multiple", value: "value", handlers: "handlers" }, host: { properties: { "attr.id": "overriode " } }, viewQueries: [{ propertyName: "accordionComponent", first: true, predicate: ["accordionComponent"], descendants: true }], usesInheritance: true, ngImport: i0, template: "\n\n<fieldset\n (fieldsetAddGroupEvent)=\"handleCreateItem($event)\"\n (fieldsetRemoveGroupEvent)=\"handleRemoveItem(undefined, $event)\"\n [class]=\"'dcf-fieldset ' + operation\"\n #component>\n <ion-accordion-group [class.open]=\"isOpen\" [class.hasValidationErrors]=\"hasValidationErrors\" (validationErrorEvent)=\"handleValidationError($event)\" #accordionComponent>\n <ion-accordion value=\"open\">\n <ion-item slot=\"header\" (click)=\"handleAccordionToggle($event)\">\n <div class=\"dcf-grid dcf-grid-collapse dcf-flex dcf-flex-middle dcf-width-1-1\">\n <div class=\"dcf-width-expand\">\n <legend>{{ name | translate }}</legend>\n </div>\n @if(!isRequired && ['create', 'update'].includes(operation)) {\n <div class=\"dcf-width-auto dcf-delete\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleRemoveComponent($event)\">\n <ion-icon name=\"trash-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n }\n </div>\n </ion-item>\n <div slot=\"content\" [attr.aria-hidden]=\"!isOpen\">\n @if(multiple && items.length) {\n <ion-list class=\"dcf-fields-list\">\n <ion-reorder-group [formGroup]=\"formGroup.parent\" [disabled]=\"updatingItem\" (ionItemReorder)=\"handleReorderItems($any($event))\" #accordionComponent>\n @for(item of items; track item.index) {\n <ion-item [class.not-unique]=\"item.title === isUniqueError\" [class.updating]=\"updatingItem?.[pk] === item.title\" lines=\"full\" [button]=\"false\">\n @if(items?.length > 1 && !updatingItem) {\n <ion-reorder slot=\"start\">\n <ion-icon name=\"swap-vertical-outline\"></ion-icon>\n </ion-reorder>\n } @else {\n <div slot=\"start\">\n <ion-icon class=\"dcf-reorder-disabled\" size=\"small\" name=\"swap-vertical-outline\" disabled></ion-icon>\n </div>\n }\n <ion-label [color]=\"(item.title === isUniqueError && !updatingItem?.[pk] === item.title) ? 'danger' : ''\">{{ item.index }}. {{ item.title }}\n @if(item.description?.length > 0) {\n <br />\n <ion-text class=\"dcf-subtitle\">{{item.description}}</ion-text>\n }\n </ion-label>\n @if(!updatingItem || updatingItem?.[pk] !== item.title) {\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleUpdateItem(item.title, $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(item.title)\">\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 <ng-content select=\"[slot=content]\"></ng-content>\n\n @if(multiple && ['create', 'update'].includes(operation)) {\n @if(isUniqueError) {\n <div class=\"dcf-not-unique-container dcf-animation dcf-animation-bottom-small dcf-animation-fast\">\n <div class=\" dcf-grid dcf-grid-collapse dcf-width-1-1 \">\n <div class=\"dcf-auto\" [attr.style]=\"'max-width: 50px'\">\n <ion-icon name=\"alert-circle-outline\"></ion-icon>\n </div>\n <div class=\"dcf-width-expand\">\n <ion-text color=\"danger\" class=\"dcf-text-small\">{{ locale + '.not_unique' | translate : { value: isUniqueError } }}</ion-text>\n </div>\n </div>\n </div>\n }\n <div class=\"dcf-margin-bottom dcf-grid dcf-grid-collapse dcf-flex\">\n @if(updatingItem) {\n <ion-button size=\"small\" fill=\"clear\" color=\"danger\" (click)=\"handleCancelUpdateItem()\">\n {{ buttonCancelLabel }}\n </ion-button>\n }\n <ion-button size=\"small\" fill=\"clear\" class=\"dcf-button-add\" (click)=\"handleCreateItem()\">\n <ion-icon name=\"add-outline\" slot=\"start\"></ion-icon>\n {{buttonLabel}}\n </ion-button>\n\n </div>\n }\n\n </div>\n </ion-accordion>\n </ion-accordion-group>\n</fieldset>\n\n", styles: ["ion-accordion-group ion-item[slot=header] .dcf-delete{width:30px}ion-accordion-group ion-item[slot=header] .dcf-delete ion-button{transform:translateY(-2px)}ion-accordion-group ion-item[slot=header] .dcf-delete ion-icon{font-size:1.15rem}::ng-deep ion-accordion ngx-decaf-crud-field:last-child ion-item{--inner-border-width: 0px !important;--border-width: 0px !important}@media (prefers-color-scheme: light){.dcf-fieldset{border:1px solid var(--dcf-color-gray-3)}.dcf-fieldset .dcf-button-add{color:var(--ion-color-dark)!important}ion-accordion ion-item[slot=header] legend{color:var(--dcf-color-gray-7)}}@media (prefers-color-scheme: dark){.dcf-fieldset{border:1px solid var(--dcf-color-step-400)}.dcf-fieldset .dcf-button-add{color:var(--ion-color-gray-2)}.dcf-fieldset.read,.dcf-fieldset.delete{border:1px solid var(--dcf-color-gray-6)}}.dcf-fieldset{margin-bottom:1.8rem;margin-top:1rem;padding-bottom:0;padding-top:1rem;background:var(--dcf-card-background);border-radius:6px;height:100%}.dcf-fieldset.read,.dcf-fieldset.delete{margin-top:1.25rem;padding-bottom:1rem}.dcf-fieldset.read [slot=content],.dcf-fieldset.delete [slot=content]{padding-top:0!important}.dcf-fieldset.read ion-accordion,.dcf-fieldset.delete ion-accordion{margin-bottom:0rem!important}.dcf-fieldset ion-accordion{background:var(--dcf-card-background);margin-bottom:1rem}.dcf-fieldset ion-accordion.accordion-collapsing,.dcf-fieldset ion-accordion.accordion-collapsed{margin-bottom:1rem}.dcf-fieldset ion-accordion ion-item[slot=header]{--border-color: transparent;--border-radius: 6px;--inner-border-width: 0;--padding-start: 12px}.dcf-fieldset ion-accordion ion-item[slot=header] legend{font-weight:600;font-size:1rem;margin:0}.dcf-fieldset ion-accordion [slot=content]{padding-top:2rem!important;padding-inline:.75rem}.dcf-not-unique-container{display:flex;justify-content:center;align-items:center;margin-bottom:1rem;flex:1 1 auto}.dcf-not-unique-container>div{display:flex;justify-content:center;align-items:center}.dcf-not-unique-container ion-icon{transform:translatey(2px);margin-right:5px}.dcf-fields-list{margin-top:-1rem;margin-bottom:1rem;padding:0!important}.dcf-fields-list ion-item{--min-height: 50px;--padding-top: .25rem;--padding-bottom: .25rem;--padding-start: .75rem;--padding-end: .75rem;--inner-padding-start: 0px !important;--inner-padding-end: 0px !important;--border-color: var(--dcf-color-gray-2) !important;border:1px solid transparent;box-sizing:border-box}.dcf-fields-list ion-item ion-icon.dcf-reorder-disabled{width:1rem;transform:translatey(2px);color:var(--dcf-color-gray-4)}.dcf-fields-list ion-item.updating{--background: rgba(var(--dcf-color-primary-rgb), .1) !important}.dcf-fields-list ion-item.not-unique{--background: rgba(var(--dcf-color-danger-rgb), .05) !important}.dcf-fields-list ion-item .dcf-subtitle{font-size:.8rem;color:var(--dcf-color-gray-7)}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: IonAccordionGroup, selector: "ion-accordion-group", inputs: ["animated", "disabled", "expand", "mode", "multiple", "readonly", "value"] }, { kind: "component", type: IonAccordion, selector: "ion-accordion", inputs: ["disabled", "mode", "readonly", "toggleIcon", "toggleIconSlot", "value"] }, { kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonReorder, selector: "ion-reorder" }, { kind: "component", type: IonReorderGroup, selector: "ion-reorder-group", inputs: ["disabled"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
5006
4998
  };
5007
4999
  FieldsetComponent = __decorate([
5008
5000
  Dynamic(),
5009
5001
  __metadata("design:paramtypes", [])
5010
5002
  ], FieldsetComponent);
5011
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FieldsetComponent, decorators: [{
5003
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: FieldsetComponent, decorators: [{
5012
5004
  type: Component,
5013
5005
  args: [{ standalone: true, selector: 'ngx-decaf-fieldset', schemas: [], imports: [
5014
5006
  TranslatePipe,
@@ -5023,7 +5015,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
5023
5015
  IonReorderGroup,
5024
5016
  IonButton,
5025
5017
  IonIcon,
5026
- ], host: { '[attr.id]': 'overriode ' }, template: "\n\n<fieldset\n (fieldsetAddGroupEvent)=\"handleCreateItem($event)\"\n (fieldsetRemoveGroupEvent)=\"handleRemoveItem(undefined, $event)\"\n [class]=\"'dcf-fieldset ' + operation\"\n #component>\n <ion-accordion-group [class.open]=\"isOpen\" [class.hasValidationErrors]=\"hasValidationErrors\" (validationErrorEvent)=\"handleValidationError($event)\" #accordionComponent>\n <ion-accordion value=\"open\">\n <ion-item slot=\"header\" (click)=\"handleAccordionToggle($event)\">\n <div class=\"dcf-grid dcf-grid-collapse dcf-flex dcf-flex-middle dcf-width-1-1\">\n <div class=\"dcf-width-expand\">\n <legend>{{ name | translate }}</legend>\n </div>\n @if(!isRequired && ['create', 'update'].includes(operation)) {\n <div class=\"dcf-width-auto dcf-delete\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleRemoveComponent($event)\">\n <ion-icon name=\"trash-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n }\n </div>\n </ion-item>\n <div slot=\"content\" [attr.aria-hidden]=\"!isOpen\">\n @if(multiple && items.length) {\n <ion-list class=\"dcf-fields-list\">\n <ion-reorder-group [formGroup]=\"formGroup.parent\" [disabled]=\"updatingItem\" (ionItemReorder)=\"handleReorderItems($any($event))\" #accordionComponent>\n @for(item of items; track item.index) {\n <ion-item [class.not-unique]=\"item.title === isUniqueError\" [class.updating]=\"updatingItem?.[pk] === item.title\" lines=\"full\" [button]=\"false\">\n @if(items?.length > 1 && !updatingItem) {\n <ion-reorder slot=\"start\">\n <ion-icon name=\"swap-vertical-outline\"></ion-icon>\n </ion-reorder>\n } @else {\n <div slot=\"start\">\n <ion-icon class=\"dcf-reorder-disabled\" size=\"small\" name=\"swap-vertical-outline\" disabled></ion-icon>\n </div>\n }\n <ion-label [color]=\"(item.title === isUniqueError && !updatingItem?.[pk] === item.title) ? 'danger' : ''\">{{ item.index }}. {{ item.title }}\n @if(item.description?.length > 0) {\n <br />\n <ion-text class=\"dcf-subtitle\">{{item.description}}</ion-text>\n }\n </ion-label>\n @if(!updatingItem || updatingItem?.[pk] !== item.title) {\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleUpdateItem(item.title, $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(item.title)\">\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 <ng-content select=\"[slot=content]\"></ng-content>\n\n @if(multiple && ['create', 'update'].includes(operation)) {\n @if(isUniqueError) {\n <div class=\"dcf-not-unique-container dcf-animation dcf-animation-bottom-small dcf-animation-fast\">\n <div class=\" dcf-grid dcf-grid-collapse dcf-width-1-1 \">\n <div class=\"dcf-auto\" [attr.style]=\"'max-width: 50px'\">\n <ion-icon name=\"alert-circle-outline\"></ion-icon>\n </div>\n <div class=\"dcf-width-expand\">\n <ion-text color=\"danger\" class=\"dcf-text-small\">{{ locale + '.not_unique' | translate : { value: isUniqueError } }}</ion-text>\n </div>\n </div>\n </div>\n }\n <div class=\"dcf-margin-bottom dcf-grid dcf-grid-collapse dcf-flex\">\n @if(updatingItem) {\n <ion-button size=\"small\" fill=\"clear\" color=\"danger\" (click)=\"handleCancelUpdateItem()\">\n {{ buttonCancelLabel }}\n </ion-button>\n }\n <ion-button size=\"small\" fill=\"clear\" class=\"dcf-button-add\" (click)=\"handleCreateItem()\">\n <ion-icon name=\"add-outline\" slot=\"start\"></ion-icon>\n {{buttonLabel}}\n </ion-button>\n\n </div>\n }\n\n </div>\n </ion-accordion>\n </ion-accordion-group>\n</fieldset>\n\n", styles: ["ion-accordion-group ion-item[slot=header] .dcf-delete{width:30px}ion-accordion-group ion-item[slot=header] .dcf-delete ion-button{transform:translateY(-2px)}ion-accordion-group ion-item[slot=header] .dcf-delete ion-icon{font-size:1.15rem}::ng-deep ion-accordion ngx-decaf-crud-field:last-child ion-item{--inner-border-width: 0px !important;--border-width: 0px !important}.dcf-fieldset{margin-bottom:1.8rem;margin-top:1rem;padding-bottom:0;padding-top:1rem;background:var(--dcf-card-background);border-radius:6px;height:100%}@media (prefers-color-scheme: light){.dcf-fieldset{border:1px solid var(--dcf-color-gray-3)}.dcf-fieldset .dcf-button-add{color:var(--ion-color-dark)!important}}@media (prefers-color-scheme: dark){.dcf-fieldset{border:1px solid var(--dcf-color-step-400)}.dcf-fieldset .dcf-button-add{color:var(--ion-color-gray-2)}}.dcf-fieldset.read,.dcf-fieldset.delete{margin-top:1.25rem;padding-bottom:1rem}.dcf-fieldset.read [slot=content],.dcf-fieldset.delete [slot=content]{padding-top:0!important}.dcf-fieldset.read ion-accordion,.dcf-fieldset.delete ion-accordion{margin-bottom:0rem!important}@media (prefers-color-scheme: dark){.dcf-fieldset.read,.dcf-fieldset.delete{border:1px solid var(--dcf-color-gray-6)}}.dcf-fieldset ion-accordion{background:var(--dcf-card-background);margin-bottom:1rem}.dcf-fieldset ion-accordion.accordion-collapsing,.dcf-fieldset ion-accordion.accordion-collapsed{margin-bottom:1rem}.dcf-fieldset ion-accordion ion-item[slot=header]{--border-color: transparent;--border-radius: 6px;--inner-border-width: 0;--padding-start: 12px}.dcf-fieldset ion-accordion ion-item[slot=header] legend{font-weight:600;font-size:1rem;margin:0}@media (prefers-color-scheme: light){.dcf-fieldset ion-accordion ion-item[slot=header] legend{color:var(--dcf-color-gray-7)}}.dcf-fieldset ion-accordion [slot=content]{padding-top:2rem!important;padding-inline:.75rem}.dcf-not-unique-container{display:flex;justify-content:center;align-items:center;margin-bottom:1rem;flex:1 1 auto}.dcf-not-unique-container>div{display:flex;justify-content:center;align-items:center}.dcf-not-unique-container ion-icon{transform:translatey(2px);margin-right:5px}.dcf-fields-list{margin-top:-1rem;margin-bottom:1rem;padding:0!important}.dcf-fields-list ion-item{--min-height: 50px;--padding-top: .25rem;--padding-bottom: .25rem;--padding-start: .75rem;--padding-end: .75rem;--inner-padding-start: 0px !important;--inner-padding-end: 0px !important;--border-color: var(--dcf-color-gray-2) !important;border:1px solid transparent;box-sizing:border-box}.dcf-fields-list ion-item ion-icon.dcf-reorder-disabled{width:1rem;transform:translatey(2px);color:var(--dcf-color-gray-4)}.dcf-fields-list ion-item.updating{--background: rgba(var(--dcf-color-primary-rgb), .1) !important}.dcf-fields-list ion-item.not-unique{--background: rgba(var(--dcf-color-danger-rgb), .05) !important}.dcf-fields-list ion-item .dcf-subtitle{font-size:.8rem;color:var(--dcf-color-gray-7)}\n"] }]
5018
+ ], host: { '[attr.id]': 'overriode ' }, template: "\n\n<fieldset\n (fieldsetAddGroupEvent)=\"handleCreateItem($event)\"\n (fieldsetRemoveGroupEvent)=\"handleRemoveItem(undefined, $event)\"\n [class]=\"'dcf-fieldset ' + operation\"\n #component>\n <ion-accordion-group [class.open]=\"isOpen\" [class.hasValidationErrors]=\"hasValidationErrors\" (validationErrorEvent)=\"handleValidationError($event)\" #accordionComponent>\n <ion-accordion value=\"open\">\n <ion-item slot=\"header\" (click)=\"handleAccordionToggle($event)\">\n <div class=\"dcf-grid dcf-grid-collapse dcf-flex dcf-flex-middle dcf-width-1-1\">\n <div class=\"dcf-width-expand\">\n <legend>{{ name | translate }}</legend>\n </div>\n @if(!isRequired && ['create', 'update'].includes(operation)) {\n <div class=\"dcf-width-auto dcf-delete\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleRemoveComponent($event)\">\n <ion-icon name=\"trash-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n }\n </div>\n </ion-item>\n <div slot=\"content\" [attr.aria-hidden]=\"!isOpen\">\n @if(multiple && items.length) {\n <ion-list class=\"dcf-fields-list\">\n <ion-reorder-group [formGroup]=\"formGroup.parent\" [disabled]=\"updatingItem\" (ionItemReorder)=\"handleReorderItems($any($event))\" #accordionComponent>\n @for(item of items; track item.index) {\n <ion-item [class.not-unique]=\"item.title === isUniqueError\" [class.updating]=\"updatingItem?.[pk] === item.title\" lines=\"full\" [button]=\"false\">\n @if(items?.length > 1 && !updatingItem) {\n <ion-reorder slot=\"start\">\n <ion-icon name=\"swap-vertical-outline\"></ion-icon>\n </ion-reorder>\n } @else {\n <div slot=\"start\">\n <ion-icon class=\"dcf-reorder-disabled\" size=\"small\" name=\"swap-vertical-outline\" disabled></ion-icon>\n </div>\n }\n <ion-label [color]=\"(item.title === isUniqueError && !updatingItem?.[pk] === item.title) ? 'danger' : ''\">{{ item.index }}. {{ item.title }}\n @if(item.description?.length > 0) {\n <br />\n <ion-text class=\"dcf-subtitle\">{{item.description}}</ion-text>\n }\n </ion-label>\n @if(!updatingItem || updatingItem?.[pk] !== item.title) {\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleUpdateItem(item.title, $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(item.title)\">\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 <ng-content select=\"[slot=content]\"></ng-content>\n\n @if(multiple && ['create', 'update'].includes(operation)) {\n @if(isUniqueError) {\n <div class=\"dcf-not-unique-container dcf-animation dcf-animation-bottom-small dcf-animation-fast\">\n <div class=\" dcf-grid dcf-grid-collapse dcf-width-1-1 \">\n <div class=\"dcf-auto\" [attr.style]=\"'max-width: 50px'\">\n <ion-icon name=\"alert-circle-outline\"></ion-icon>\n </div>\n <div class=\"dcf-width-expand\">\n <ion-text color=\"danger\" class=\"dcf-text-small\">{{ locale + '.not_unique' | translate : { value: isUniqueError } }}</ion-text>\n </div>\n </div>\n </div>\n }\n <div class=\"dcf-margin-bottom dcf-grid dcf-grid-collapse dcf-flex\">\n @if(updatingItem) {\n <ion-button size=\"small\" fill=\"clear\" color=\"danger\" (click)=\"handleCancelUpdateItem()\">\n {{ buttonCancelLabel }}\n </ion-button>\n }\n <ion-button size=\"small\" fill=\"clear\" class=\"dcf-button-add\" (click)=\"handleCreateItem()\">\n <ion-icon name=\"add-outline\" slot=\"start\"></ion-icon>\n {{buttonLabel}}\n </ion-button>\n\n </div>\n }\n\n </div>\n </ion-accordion>\n </ion-accordion-group>\n</fieldset>\n\n", styles: ["ion-accordion-group ion-item[slot=header] .dcf-delete{width:30px}ion-accordion-group ion-item[slot=header] .dcf-delete ion-button{transform:translateY(-2px)}ion-accordion-group ion-item[slot=header] .dcf-delete ion-icon{font-size:1.15rem}::ng-deep ion-accordion ngx-decaf-crud-field:last-child ion-item{--inner-border-width: 0px !important;--border-width: 0px !important}@media (prefers-color-scheme: light){.dcf-fieldset{border:1px solid var(--dcf-color-gray-3)}.dcf-fieldset .dcf-button-add{color:var(--ion-color-dark)!important}ion-accordion ion-item[slot=header] legend{color:var(--dcf-color-gray-7)}}@media (prefers-color-scheme: dark){.dcf-fieldset{border:1px solid var(--dcf-color-step-400)}.dcf-fieldset .dcf-button-add{color:var(--ion-color-gray-2)}.dcf-fieldset.read,.dcf-fieldset.delete{border:1px solid var(--dcf-color-gray-6)}}.dcf-fieldset{margin-bottom:1.8rem;margin-top:1rem;padding-bottom:0;padding-top:1rem;background:var(--dcf-card-background);border-radius:6px;height:100%}.dcf-fieldset.read,.dcf-fieldset.delete{margin-top:1.25rem;padding-bottom:1rem}.dcf-fieldset.read [slot=content],.dcf-fieldset.delete [slot=content]{padding-top:0!important}.dcf-fieldset.read ion-accordion,.dcf-fieldset.delete ion-accordion{margin-bottom:0rem!important}.dcf-fieldset ion-accordion{background:var(--dcf-card-background);margin-bottom:1rem}.dcf-fieldset ion-accordion.accordion-collapsing,.dcf-fieldset ion-accordion.accordion-collapsed{margin-bottom:1rem}.dcf-fieldset ion-accordion ion-item[slot=header]{--border-color: transparent;--border-radius: 6px;--inner-border-width: 0;--padding-start: 12px}.dcf-fieldset ion-accordion ion-item[slot=header] legend{font-weight:600;font-size:1rem;margin:0}.dcf-fieldset ion-accordion [slot=content]{padding-top:2rem!important;padding-inline:.75rem}.dcf-not-unique-container{display:flex;justify-content:center;align-items:center;margin-bottom:1rem;flex:1 1 auto}.dcf-not-unique-container>div{display:flex;justify-content:center;align-items:center}.dcf-not-unique-container ion-icon{transform:translatey(2px);margin-right:5px}.dcf-fields-list{margin-top:-1rem;margin-bottom:1rem;padding:0!important}.dcf-fields-list ion-item{--min-height: 50px;--padding-top: .25rem;--padding-bottom: .25rem;--padding-start: .75rem;--padding-end: .75rem;--inner-padding-start: 0px !important;--inner-padding-end: 0px !important;--border-color: var(--dcf-color-gray-2) !important;border:1px solid transparent;box-sizing:border-box}.dcf-fields-list ion-item ion-icon.dcf-reorder-disabled{width:1rem;transform:translatey(2px);color:var(--dcf-color-gray-4)}.dcf-fields-list ion-item.updating{--background: rgba(var(--dcf-color-primary-rgb), .1) !important}.dcf-fields-list ion-item.not-unique{--background: rgba(var(--dcf-color-danger-rgb), .05) !important}.dcf-fields-list ion-item .dcf-subtitle{font-size:.8rem;color:var(--dcf-color-gray-7)}\n"] }]
5027
5019
  }], ctorParameters: () => [], propDecorators: { accordionComponent: [{
5028
5020
  type: ViewChild,
5029
5021
  args: ['accordionComponent', { static: false }]
@@ -5481,10 +5473,10 @@ class SearchbarComponent extends NgxBaseComponent {
5481
5473
  preventChange(event) {
5482
5474
  event.preventDefault();
5483
5475
  }
5484
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SearchbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
5485
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: SearchbarComponent, isStandalone: true, selector: "ngx-decaf-searchbar", inputs: { autocomplete: "autocomplete", autocorrect: "autocorrect", animated: "animated", buttonCancelText: "buttonCancelText", clearIcon: "clearIcon", color: "color", debounce: "debounce", disabled: "disabled", enterkeyhint: "enterkeyhint", inputmode: "inputmode", placeholder: "placeholder", searchIcon: "searchIcon", showCancelButton: "showCancelButton", showClearButton: "showClearButton", spellcheck: "spellcheck", type: "type", value: "value", queryKeys: "queryKeys", isVisible: "isVisible", wrapper: "wrapper", wrapperColor: "wrapperColor", emitEventToWindow: "emitEventToWindow" }, outputs: { searchEvent: "searchEvent" }, host: { listeners: { "window:toggleSearchbarVisibility": "handleToggleVisibility($event)" } }, usesInheritance: true, ngImport: i0, template: "<ion-searchbar\n [id]=\"uid\"\n ngClass=\"dcf-searchbar\"\n name=\"search\"\n mode=\"ios\"\n (keyup.enter)=\"preventChange($event)\"\n (ionChange)=\"handleChange($event)\"\n (ionInput)=\"handleInput($event)\"\n (ionClear)=\"handleClear()\"\n [autocomplete]=\"autocomplete\"\n [showCancelButton]=\"showCancelButton\"\n [cancelButtonText]=\"buttonCancelText\"\n [clearIcon]=\"clearIcon\"\n [color]=\"color\"\n [debounce]=\"debounce\"\n [disabled]=\"disabled\"\n [enterkeyhint]=\"enterkeyhint\"\n [inputmode]=\"inputmode\"\n [placeholder]=\"placeholder\"\n [searchIcon]=\"searchIcon\"\n [showClearButton]=\"showClearButton\"\n [spellcheck]=\"spellcheck\"\n [type]=\"type\"\n #component\n />\n", styles: [""], dependencies: [{ kind: "component", type: IonSearchbar, selector: "ion-searchbar", inputs: ["animated", "autocomplete", "autocorrect", "cancelButtonIcon", "cancelButtonText", "clearIcon", "color", "debounce", "disabled", "enterkeyhint", "inputmode", "mode", "name", "placeholder", "searchIcon", "showCancelButton", "showClearButton", "spellcheck", "type", "value"] }] }); }
5476
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: SearchbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
5477
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.2", type: SearchbarComponent, isStandalone: true, selector: "ngx-decaf-searchbar", inputs: { autocomplete: "autocomplete", autocorrect: "autocorrect", animated: "animated", buttonCancelText: "buttonCancelText", clearIcon: "clearIcon", color: "color", debounce: "debounce", disabled: "disabled", enterkeyhint: "enterkeyhint", inputmode: "inputmode", placeholder: "placeholder", searchIcon: "searchIcon", showCancelButton: "showCancelButton", showClearButton: "showClearButton", spellcheck: "spellcheck", type: "type", value: "value", queryKeys: "queryKeys", isVisible: "isVisible", wrapper: "wrapper", wrapperColor: "wrapperColor", emitEventToWindow: "emitEventToWindow" }, outputs: { searchEvent: "searchEvent" }, host: { listeners: { "window:toggleSearchbarVisibility": "handleToggleVisibility($event)" } }, usesInheritance: true, ngImport: i0, template: "<ion-searchbar\n [id]=\"uid\"\n ngClass=\"dcf-searchbar\"\n name=\"search\"\n mode=\"ios\"\n (keyup.enter)=\"preventChange($event)\"\n (ionChange)=\"handleChange($event)\"\n (ionInput)=\"handleInput($event)\"\n (ionClear)=\"handleClear()\"\n [autocomplete]=\"autocomplete\"\n [showCancelButton]=\"showCancelButton\"\n [cancelButtonText]=\"buttonCancelText\"\n [clearIcon]=\"clearIcon\"\n [color]=\"color\"\n [debounce]=\"debounce\"\n [disabled]=\"disabled\"\n [enterkeyhint]=\"enterkeyhint\"\n [inputmode]=\"inputmode\"\n [placeholder]=\"placeholder\"\n [searchIcon]=\"searchIcon\"\n [showClearButton]=\"showClearButton\"\n [spellcheck]=\"spellcheck\"\n [type]=\"type\"\n #component\n />\n", styles: [""], dependencies: [{ kind: "component", type: IonSearchbar, selector: "ion-searchbar", inputs: ["animated", "autocomplete", "autocorrect", "cancelButtonIcon", "cancelButtonText", "clearIcon", "color", "debounce", "disabled", "enterkeyhint", "inputmode", "mode", "name", "placeholder", "searchIcon", "showCancelButton", "showClearButton", "spellcheck", "type", "value"] }] }); }
5486
5478
  }
5487
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SearchbarComponent, decorators: [{
5479
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: SearchbarComponent, decorators: [{
5488
5480
  type: Component,
5489
5481
  args: [{ selector: 'ngx-decaf-searchbar', standalone: true, imports: [IonSearchbar], template: "<ion-searchbar\n [id]=\"uid\"\n ngClass=\"dcf-searchbar\"\n name=\"search\"\n mode=\"ios\"\n (keyup.enter)=\"preventChange($event)\"\n (ionChange)=\"handleChange($event)\"\n (ionInput)=\"handleInput($event)\"\n (ionClear)=\"handleClear()\"\n [autocomplete]=\"autocomplete\"\n [showCancelButton]=\"showCancelButton\"\n [cancelButtonText]=\"buttonCancelText\"\n [clearIcon]=\"clearIcon\"\n [color]=\"color\"\n [debounce]=\"debounce\"\n [disabled]=\"disabled\"\n [enterkeyhint]=\"enterkeyhint\"\n [inputmode]=\"inputmode\"\n [placeholder]=\"placeholder\"\n [searchIcon]=\"searchIcon\"\n [showClearButton]=\"showClearButton\"\n [spellcheck]=\"spellcheck\"\n [type]=\"type\"\n #component\n />\n" }]
5490
5482
  }], ctorParameters: () => [], propDecorators: { autocomplete: [{
@@ -6183,20 +6175,18 @@ let FilterComponent = class FilterComponent extends NgxBaseComponent {
6183
6175
  handleSearch(value) {
6184
6176
  this.searchEvent.emit(value);
6185
6177
  }
6186
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FilterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6187
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: FilterComponent, isStandalone: true, selector: "ngx-decaf-filter", inputs: { indexes: "indexes", conditions: "conditions", sortBy: "sortBy", disableSort: "disableSort" }, outputs: { filterEvent: "filterEvent", searchEvent: "searchEvent" }, 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-grid\" [class.dcf-hidden]=\"!indexes.length\">\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\" (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\n placeholder=\"{{ locale + (step === 3 ? '.type' : '.select') | translate }}\"\n #component\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' : 'medium'\" 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' : 'medium'\" 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' : 'medium'\" [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-grid{padding:0 .5rem;margin-top:.75rem;margin-bottom:.75rem}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}@media (prefers-color-scheme: light){.dcf-filter{border:1px solid var(--dcf-color-gray-3);background-color:#fff}.dcf-filter:focus-within{border-color:var(--dcf-color-primary);background-color:#fff}}@media (prefers-color-scheme: dark){.dcf-filter{border:1px solid var(--dcf-color-step-500)}.dcf-filter ::-webkit-input-placeholder,.dcf-filter ::placeholder{color:var(--dcf-color-gray-4)!important}.dcf-filter:hover{border-color:var(--dcf-color-gray-2)}.dcf-filter:focus-within{border-color:var(--dcf-color-gray-2)}}.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}@media (prefers-color-scheme: light){.dcf-filter ion-chip{border:1px solid var(--dcf-color-gray-3);color:var(--dcf-color-gray-7)}.dcf-filter 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}}@media (prefers-color-scheme: dark){.dcf-filter ion-chip{border-color:var(--dcf-color-step-300);background:rgba(var(--dcf-color-medium-rgb),.1)}.dcf-filter ion-chip.dcf-filter-value{background:rgba(var(--dcf-color-medium-rgb),.3)!important;border-color:var(--dcf-color-step-500)}}.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}@media (prefers-color-scheme: light){.dcf-filter .dcf-input input{color:var(--dcf-color-gray-7)}}@media (prefers-color-scheme: dark){.dcf-filter .dcf-input input{color:var(--dcf-color-gray-1)}}.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}@media (prefers-color-scheme: light){.dcf-dropdown{background-color:#fff}.dcf-dropdown.dcf-active{border:1px solid var(--dcf-color-gray-2)}}@media (prefers-color-scheme: dark){.dcf-dropdown{background-color:var(--dcf-item-background)}.dcf-dropdown.dcf-active{border:1px solid var(--dcf-color-step-600)}}.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}@media (prefers-color-scheme: light){.dcf-dropdown.dcf-active>div>div{color:var(--dcf-color-gray-8)}.dcf-dropdown.dcf-active>div>div.dcf-filtering-item,.dcf-dropdown.dcf-active>div>div:only-child{border-color:var(--dcf-color-gray-3)}.dcf-dropdown.dcf-active>div>div.dcf-filtering-item.dcf-empty,.dcf-dropdown.dcf-active>div>div:only-child.dcf-empty{pointer-events:none;touch-action:none;cursor:text!important;border-color:transparent!important}.dcf-dropdown.dcf-active>div>div:hover{background-color:var(--dcf-color-gray-1)}}@media (prefers-color-scheme: dark){.dcf-dropdown.dcf-active>div>div{color:var(--dcf-color-gray-1)}.dcf-dropdown.dcf-active>div>div.dcf-filtering-item,.dcf-dropdown.dcf-active>div>div:only-child{border-color:var(--dcf-color-gray-5)}.dcf-dropdown.dcf-active>div>div.dcf-filtering-item.dcf-empty,.dcf-dropdown.dcf-active>div>div:only-child.dcf-empty{cursor:text!important;pointer-events:none;touch-action:none;border-color:transparent!important}.dcf-dropdown.dcf-active>div>div:hover{background-color:var(--dcf-color-gray-8)}}\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: "pipe", type: TranslatePipe, name: "translate" }, { 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"] }] }); }
6178
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: FilterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6179
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.2", type: FilterComponent, isStandalone: true, selector: "ngx-decaf-filter", inputs: { indexes: "indexes", conditions: "conditions", sortBy: "sortBy", disableSort: "disableSort" }, outputs: { filterEvent: "filterEvent", searchEvent: "searchEvent" }, 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-grid\" [class.dcf-hidden]=\"!indexes.length\">\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\" (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\n placeholder=\"{{ locale + (step === 3 ? '.type' : '.select') | translate }}\"\n #component\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' : 'medium'\" 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' : 'medium'\" 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' : 'medium'\" [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: ["@media (prefers-color-scheme: light){.dcf-filter{border:1px solid var(--dcf-color-gray-3);background-color:#fff}.dcf-filter:focus-within{border-color:var(--dcf-color-primary);background-color:#fff}ion-chip{border:1px solid var(--dcf-color-gray-3);color:var(--dcf-color-gray-7)}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-input input{color:var(--dcf-color-gray-7)}.dcf-dropdown{background-color:#fff}.dcf-dropdown.dcf-active{border:1px solid var(--dcf-color-gray-2)}.dcf-dropdown.dcf-active>div>div{color:var(--dcf-color-gray-8)}.dcf-dropdown.dcf-active>div>div.dcf-filtering-item,.dcf-dropdown.dcf-active>div>div:only-child{border-color:var(--dcf-color-gray-3)}.dcf-dropdown.dcf-active>div>div.dcf-filtering-item.dcf-empty,.dcf-dropdown.dcf-active>div>div:only-child.dcf-empty{pointer-events:none;touch-action:none;cursor:text!important;border-color:transparent!important}.dcf-dropdown.dcf-active>div>div:hover{background-color:var(--dcf-color-gray-1)}}@media (prefers-color-scheme: dark){.dcf-filter{border:1px solid var(--dcf-color-step-500)}.dcf-filter ::-webkit-input-placeholder,.dcf-filter ::placeholder{color:var(--dcf-color-gray-4)!important}.dcf-filter:hover{border-color:var(--dcf-color-gray-2)}.dcf-filter:focus-within{border-color:var(--dcf-color-gray-2)}ion-chip{border-color:var(--dcf-color-step-300);background:rgba(var(--dcf-color-medium-rgb),.1)}ion-chip.dcf-filter-value{background:rgba(var(--dcf-color-medium-rgb),.3)!important;border-color:var(--dcf-color-step-500)}.dcf-input input{color:var(--dcf-color-gray-1)}.dcf-dropdown{background-color:var(--dcf-item-background)}.dcf-dropdown.dcf-active{border:1px solid var(--dcf-color-step-600)}.dcf-dropdown.dcf-active>div>div{color:var(--dcf-color-gray-1)}.dcf-dropdown.dcf-active>div>div.dcf-filtering-item,.dcf-dropdown.dcf-active>div>div:only-child{border-color:var(--dcf-color-gray-5)}.dcf-dropdown.dcf-active>div>div.dcf-filtering-item.dcf-empty,.dcf-dropdown.dcf-active>div>div:only-child.dcf-empty{cursor:text!important;pointer-events:none;touch-action:none;border-color:transparent!important}.dcf-dropdown.dcf-active>div>div:hover{background-color:var(--dcf-color-gray-8)}}.dcf-filter-grid{padding:0 .5rem;margin-top:.75rem;margin-bottom:.75rem}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" }] }); }
6188
6180
  };
6189
6181
  FilterComponent = __decorate([
6190
6182
  Dynamic(),
6191
6183
  __metadata("design:paramtypes", [])
6192
6184
  ], FilterComponent);
6193
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FilterComponent, decorators: [{
6185
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: FilterComponent, decorators: [{
6194
6186
  type: Component,
6195
6187
  args: [{ selector: 'ngx-decaf-filter', imports: [
6196
6188
  FormsModule,
6197
6189
  TranslatePipe,
6198
- IonLabel,
6199
- IonItem,
6200
6190
  IonChip,
6201
6191
  IonIcon,
6202
6192
  IonButton,
@@ -6204,7 +6194,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
6204
6194
  IonSelectOption,
6205
6195
  IonIcon,
6206
6196
  SearchbarComponent
6207
- ], standalone: true, 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-grid\" [class.dcf-hidden]=\"!indexes.length\">\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\" (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\n placeholder=\"{{ locale + (step === 3 ? '.type' : '.select') | translate }}\"\n #component\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' : 'medium'\" 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' : 'medium'\" 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' : 'medium'\" [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-grid{padding:0 .5rem;margin-top:.75rem;margin-bottom:.75rem}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}@media (prefers-color-scheme: light){.dcf-filter{border:1px solid var(--dcf-color-gray-3);background-color:#fff}.dcf-filter:focus-within{border-color:var(--dcf-color-primary);background-color:#fff}}@media (prefers-color-scheme: dark){.dcf-filter{border:1px solid var(--dcf-color-step-500)}.dcf-filter ::-webkit-input-placeholder,.dcf-filter ::placeholder{color:var(--dcf-color-gray-4)!important}.dcf-filter:hover{border-color:var(--dcf-color-gray-2)}.dcf-filter:focus-within{border-color:var(--dcf-color-gray-2)}}.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}@media (prefers-color-scheme: light){.dcf-filter ion-chip{border:1px solid var(--dcf-color-gray-3);color:var(--dcf-color-gray-7)}.dcf-filter 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}}@media (prefers-color-scheme: dark){.dcf-filter ion-chip{border-color:var(--dcf-color-step-300);background:rgba(var(--dcf-color-medium-rgb),.1)}.dcf-filter ion-chip.dcf-filter-value{background:rgba(var(--dcf-color-medium-rgb),.3)!important;border-color:var(--dcf-color-step-500)}}.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}@media (prefers-color-scheme: light){.dcf-filter .dcf-input input{color:var(--dcf-color-gray-7)}}@media (prefers-color-scheme: dark){.dcf-filter .dcf-input input{color:var(--dcf-color-gray-1)}}.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}@media (prefers-color-scheme: light){.dcf-dropdown{background-color:#fff}.dcf-dropdown.dcf-active{border:1px solid var(--dcf-color-gray-2)}}@media (prefers-color-scheme: dark){.dcf-dropdown{background-color:var(--dcf-item-background)}.dcf-dropdown.dcf-active{border:1px solid var(--dcf-color-step-600)}}.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}@media (prefers-color-scheme: light){.dcf-dropdown.dcf-active>div>div{color:var(--dcf-color-gray-8)}.dcf-dropdown.dcf-active>div>div.dcf-filtering-item,.dcf-dropdown.dcf-active>div>div:only-child{border-color:var(--dcf-color-gray-3)}.dcf-dropdown.dcf-active>div>div.dcf-filtering-item.dcf-empty,.dcf-dropdown.dcf-active>div>div:only-child.dcf-empty{pointer-events:none;touch-action:none;cursor:text!important;border-color:transparent!important}.dcf-dropdown.dcf-active>div>div:hover{background-color:var(--dcf-color-gray-1)}}@media (prefers-color-scheme: dark){.dcf-dropdown.dcf-active>div>div{color:var(--dcf-color-gray-1)}.dcf-dropdown.dcf-active>div>div.dcf-filtering-item,.dcf-dropdown.dcf-active>div>div:only-child{border-color:var(--dcf-color-gray-5)}.dcf-dropdown.dcf-active>div>div.dcf-filtering-item.dcf-empty,.dcf-dropdown.dcf-active>div>div:only-child.dcf-empty{cursor:text!important;pointer-events:none;touch-action:none;border-color:transparent!important}.dcf-dropdown.dcf-active>div>div:hover{background-color:var(--dcf-color-gray-8)}}\n"] }]
6197
+ ], standalone: true, 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-grid\" [class.dcf-hidden]=\"!indexes.length\">\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\" (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\n placeholder=\"{{ locale + (step === 3 ? '.type' : '.select') | translate }}\"\n #component\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' : 'medium'\" 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' : 'medium'\" 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' : 'medium'\" [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: ["@media (prefers-color-scheme: light){.dcf-filter{border:1px solid var(--dcf-color-gray-3);background-color:#fff}.dcf-filter:focus-within{border-color:var(--dcf-color-primary);background-color:#fff}ion-chip{border:1px solid var(--dcf-color-gray-3);color:var(--dcf-color-gray-7)}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-input input{color:var(--dcf-color-gray-7)}.dcf-dropdown{background-color:#fff}.dcf-dropdown.dcf-active{border:1px solid var(--dcf-color-gray-2)}.dcf-dropdown.dcf-active>div>div{color:var(--dcf-color-gray-8)}.dcf-dropdown.dcf-active>div>div.dcf-filtering-item,.dcf-dropdown.dcf-active>div>div:only-child{border-color:var(--dcf-color-gray-3)}.dcf-dropdown.dcf-active>div>div.dcf-filtering-item.dcf-empty,.dcf-dropdown.dcf-active>div>div:only-child.dcf-empty{pointer-events:none;touch-action:none;cursor:text!important;border-color:transparent!important}.dcf-dropdown.dcf-active>div>div:hover{background-color:var(--dcf-color-gray-1)}}@media (prefers-color-scheme: dark){.dcf-filter{border:1px solid var(--dcf-color-step-500)}.dcf-filter ::-webkit-input-placeholder,.dcf-filter ::placeholder{color:var(--dcf-color-gray-4)!important}.dcf-filter:hover{border-color:var(--dcf-color-gray-2)}.dcf-filter:focus-within{border-color:var(--dcf-color-gray-2)}ion-chip{border-color:var(--dcf-color-step-300);background:rgba(var(--dcf-color-medium-rgb),.1)}ion-chip.dcf-filter-value{background:rgba(var(--dcf-color-medium-rgb),.3)!important;border-color:var(--dcf-color-step-500)}.dcf-input input{color:var(--dcf-color-gray-1)}.dcf-dropdown{background-color:var(--dcf-item-background)}.dcf-dropdown.dcf-active{border:1px solid var(--dcf-color-step-600)}.dcf-dropdown.dcf-active>div>div{color:var(--dcf-color-gray-1)}.dcf-dropdown.dcf-active>div>div.dcf-filtering-item,.dcf-dropdown.dcf-active>div>div:only-child{border-color:var(--dcf-color-gray-5)}.dcf-dropdown.dcf-active>div>div.dcf-filtering-item.dcf-empty,.dcf-dropdown.dcf-active>div>div:only-child.dcf-empty{cursor:text!important;pointer-events:none;touch-action:none;border-color:transparent!important}.dcf-dropdown.dcf-active>div>div:hover{background-color:var(--dcf-color-gray-8)}}.dcf-filter-grid{padding:0 .5rem;margin-top:.75rem;margin-bottom:.75rem}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"] }]
6208
6198
  }], ctorParameters: () => [], propDecorators: { optionsFilterElement: [{
6209
6199
  type: ViewChild,
6210
6200
  args: ['optionsFilterElement', { read: ElementRef, static: false }]
@@ -6335,10 +6325,10 @@ class ModelRendererComponent {
6335
6325
  }
6336
6326
  }
6337
6327
  }
6338
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ModelRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6339
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ModelRendererComponent, isStandalone: true, selector: "ngx-decaf-model-renderer", inputs: { model: "model", globals: "globals", projectable: "projectable", rendererId: "rendererId" }, outputs: { listenEvent: "listenEvent" }, host: { properties: { "attr.id": "rendererId" } }, viewQueries: [{ propertyName: "inner", first: true, predicate: ["inner"], descendants: true, read: TemplateRef, static: true }, { propertyName: "vcr", first: true, predicate: ["componentOuter"], descendants: true, read: ViewContainerRef, static: true }], usesOnChanges: true, ngImport: i0, template: " <!-- Keep to avoid id conflicts -->\n <div [id]=\"rendererId\"></div>\n\n <ng-template #componentOuter></ng-template>\n <ng-template #inner>\n <div [id]=\"rendererId || null\">\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: [""], dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "children", "model", "parent"], outputs: ["listenEvent"] }] }); }
6328
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ModelRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6329
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.2", type: ModelRendererComponent, isStandalone: true, selector: "ngx-decaf-model-renderer", inputs: { model: "model", globals: "globals", projectable: "projectable", rendererId: "rendererId" }, outputs: { listenEvent: "listenEvent" }, host: { properties: { "attr.id": "rendererId" } }, viewQueries: [{ propertyName: "inner", first: true, predicate: ["inner"], descendants: true, read: TemplateRef, static: true }, { propertyName: "vcr", first: true, predicate: ["componentOuter"], descendants: true, read: ViewContainerRef, static: true }], usesOnChanges: true, ngImport: i0, template: " <!-- Keep to avoid id conflicts -->\n <div [id]=\"rendererId\"></div>\n\n <ng-template #componentOuter></ng-template>\n <ng-template #inner>\n <div [id]=\"rendererId || null\">\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: [""], dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "children", "model", "parent"], outputs: ["listenEvent"] }] }); }
6340
6330
  }
6341
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ModelRendererComponent, decorators: [{
6331
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ModelRendererComponent, decorators: [{
6342
6332
  type: Component,
6343
6333
  args: [{ standalone: true, imports: [NgComponentOutlet, ComponentRendererComponent], selector: 'ngx-decaf-model-renderer', host: { '[attr.id]': 'rendererId' }, template: " <!-- Keep to avoid id conflicts -->\n <div [id]=\"rendererId\"></div>\n\n <ng-template #componentOuter></ng-template>\n <ng-template #inner>\n <div [id]=\"rendererId || null\">\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" }]
6344
6334
  }], propDecorators: { model: [{
@@ -6488,10 +6478,10 @@ class LayoutComponent extends NgxBaseComponent {
6488
6478
  this.rows = this._rows;
6489
6479
  this.initialized = true;
6490
6480
  }
6491
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6492
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: LayoutComponent, isStandalone: true, selector: "ngx-decaf-layout", inputs: { cols: "cols", rows: "rows", breakpoint: "breakpoint", children: "children" }, usesInheritance: true, ngImport: i0, template: "\n@if(initialized) {\n @for (row of rows; track trackItemFn($index, row); let rowIndex = $index) {\n <div [id]=\"uid\" class=\"dcf-grid dcf-grid-collapse dcf-grid-match\">\n @if(row) {\n <div class=\"dcf-width-1-1 dcf-grid-title\">\n <ion-card class=\"dcf-grid-title\">\n {{row.title | translate}}\n </ion-card>\n </div>\n }\n @for (child of row.cols; track trackItemFn($index, child.col); let colIndex = $index) {\n <div [class]=\"(child.col === cols.length ? 'dcf-width-1-1' : 'dcf-width-'+child.col+'-'+cols.length+'@'+breakpoint)\">\n <div [class]=\"'dcf-grid-child '+child.col \">\n @if(child.tag === 'ngx-decaf-crud-form') {\n <ion-card [class]=\"'dcf-height-1-1 ' + className\">\n <ion-card-content>\n <ngx-decaf-model-renderer\n [model]=\"child.props.name\"\n (listenEvent)=\"handleEvent($event)\"\n />\n </ion-card-content>\n </ion-card>\n } @else {\n <ngx-decaf-component-renderer\n [tag]=\"child.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]=\"{props: child.props}\"\n />\n }\n </div>\n </div>\n }\n </div>\n }\n}\n", styles: [".dcf-grid>div:not(.dcf-grid-title) ::ng-deep ngx-decaf-component-renderer>*>*{height:100%;display:flex;justify-content:center!important;align-items:center!important}.dcf-grid ion-card.dcf-height-1-1>ion-card-content{margin-top:2rem}.dcf-grid.dcf-grid-small .dcf-grid-child{margin-bottom:2rem}.dcf-grid.dcf-grid-collapse .dcf-grid-child{margin-bottom:1.25rem}.dcf-grid.dcf-grid-collapse .dcf-grid-child ion-card{margin-bottom:1.25rem}.dcf-grid-title{font-size:1.05rem!important;background:none;box-shadow:none;margin-bottom:0;padding-bottom:0;font-weight:600;color:var(--dcf-color-dark);display:flex;align-items:center;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}\n"], dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "component", type: ModelRendererComponent, selector: "ngx-decaf-model-renderer", inputs: ["model", "globals", "projectable", "rendererId"], outputs: ["listenEvent"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "children", "model", "parent"], outputs: ["listenEvent"] }] }); }
6481
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: LayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6482
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.2", type: LayoutComponent, isStandalone: true, selector: "ngx-decaf-layout", inputs: { cols: "cols", rows: "rows", breakpoint: "breakpoint", children: "children" }, usesInheritance: true, ngImport: i0, template: "\n@if(initialized) {\n @for (row of rows; track trackItemFn($index, row); let rowIndex = $index) {\n <div [id]=\"uid\" class=\"dcf-grid dcf-grid-collapse dcf-grid-match\">\n @if(row) {\n <div class=\"dcf-width-1-1 dcf-grid-title\">\n <ion-card class=\"dcf-grid-title\">\n {{row.title | translate}}\n </ion-card>\n </div>\n }\n @for (child of row.cols; track trackItemFn($index, child.col); let colIndex = $index) {\n <div [class]=\"(child.col === cols.length ? 'dcf-width-1-1' : 'dcf-width-'+child.col+'-'+cols.length+'@'+breakpoint)\">\n <div [class]=\"'dcf-grid-child '+child.col \">\n @if(child.tag === 'ngx-decaf-crud-form') {\n <ion-card [class]=\"'dcf-height-1-1 ' + className\">\n <ion-card-content>\n <ngx-decaf-model-renderer\n [model]=\"child.props.name\"\n (listenEvent)=\"handleEvent($event)\"\n />\n </ion-card-content>\n </ion-card>\n } @else {\n <ngx-decaf-component-renderer\n [tag]=\"child.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]=\"{props: child.props}\"\n />\n }\n </div>\n </div>\n }\n </div>\n }\n}\n", styles: [".dcf-grid>div:not(.dcf-grid-title) ::ng-deep ngx-decaf-component-renderer>*>*{height:100%;display:flex;justify-content:center!important;align-items:center!important}.dcf-grid ion-card.dcf-height-1-1>ion-card-content{margin-top:2rem}.dcf-grid.dcf-grid-small .dcf-grid-child{margin-bottom:2rem}.dcf-grid.dcf-grid-collapse .dcf-grid-child{margin-bottom:1.25rem}.dcf-grid.dcf-grid-collapse .dcf-grid-child ion-card{margin-bottom:1.25rem}.dcf-grid-title{font-size:1.05rem!important;background:none;box-shadow:none;margin-bottom:0;padding-bottom:0;font-weight:600;color:var(--dcf-color-dark);display:flex;align-items:center;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}\n"], dependencies: [{ kind: "component", type: ModelRendererComponent, selector: "ngx-decaf-model-renderer", inputs: ["model", "globals", "projectable", "rendererId"], outputs: ["listenEvent"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "children", "model", "parent"], outputs: ["listenEvent"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
6493
6483
  }
6494
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LayoutComponent, decorators: [{
6484
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: LayoutComponent, decorators: [{
6495
6485
  type: Component,
6496
6486
  args: [{ selector: 'ngx-decaf-layout', imports: [TranslatePipe, ModelRendererComponent, ComponentRendererComponent], standalone: true, template: "\n@if(initialized) {\n @for (row of rows; track trackItemFn($index, row); let rowIndex = $index) {\n <div [id]=\"uid\" class=\"dcf-grid dcf-grid-collapse dcf-grid-match\">\n @if(row) {\n <div class=\"dcf-width-1-1 dcf-grid-title\">\n <ion-card class=\"dcf-grid-title\">\n {{row.title | translate}}\n </ion-card>\n </div>\n }\n @for (child of row.cols; track trackItemFn($index, child.col); let colIndex = $index) {\n <div [class]=\"(child.col === cols.length ? 'dcf-width-1-1' : 'dcf-width-'+child.col+'-'+cols.length+'@'+breakpoint)\">\n <div [class]=\"'dcf-grid-child '+child.col \">\n @if(child.tag === 'ngx-decaf-crud-form') {\n <ion-card [class]=\"'dcf-height-1-1 ' + className\">\n <ion-card-content>\n <ngx-decaf-model-renderer\n [model]=\"child.props.name\"\n (listenEvent)=\"handleEvent($event)\"\n />\n </ion-card-content>\n </ion-card>\n } @else {\n <ngx-decaf-component-renderer\n [tag]=\"child.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]=\"{props: child.props}\"\n />\n }\n </div>\n </div>\n }\n </div>\n }\n}\n", styles: [".dcf-grid>div:not(.dcf-grid-title) ::ng-deep ngx-decaf-component-renderer>*>*{height:100%;display:flex;justify-content:center!important;align-items:center!important}.dcf-grid ion-card.dcf-height-1-1>ion-card-content{margin-top:2rem}.dcf-grid.dcf-grid-small .dcf-grid-child{margin-bottom:2rem}.dcf-grid.dcf-grid-collapse .dcf-grid-child{margin-bottom:1.25rem}.dcf-grid.dcf-grid-collapse .dcf-grid-child ion-card{margin-bottom:1.25rem}.dcf-grid-title{font-size:1.05rem!important;background:none;box-shadow:none;margin-bottom:0;padding-bottom:0;font-weight:600;color:var(--dcf-color-dark);display:flex;align-items:center;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}\n"] }]
6497
6487
  }], ctorParameters: () => [], propDecorators: { cols: [{
@@ -6505,857 +6495,466 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
6505
6495
  }] } });
6506
6496
 
6507
6497
  /**
6508
- * @description A component for displaying a list item with various customization options.
6509
- * @summary The ListItemComponent is an Angular component that extends NgxBaseComponent. It provides a flexible and customizable list item interface with support for icons, buttons, and various text elements. The component also handles actions and navigation based on user interactions.
6510
- *
6511
- * @class
6512
- * @extends NgxBaseComponent
6513
- *
6514
- * @param {string} [lines='none'] - Determines the line style of the item. Can be 'inset', 'inseet', or 'none'.
6515
- * @param {Record<string, any>} item - The data item to be displayed in the list item.
6516
- * @param {string} icon - The name of the icon to be displayed.
6517
- * @param {'start' | 'end'} [iconSlot='start'] - The position of the icon within the item.
6518
- * @param {StringOrBoolean} [button=true] - Determines if the item should behave as a button.
6519
- * @param {string} [title] - The main title of the list item.
6520
- * @param {string} [description] - A description for the list item.
6521
- * @param {string} [info] - Additional information for the list item.
6522
- * @param {string} [subinfo] - Sub-information for the list item.
6498
+ * @description A pagination component for navigating through multiple pages of content.
6499
+ * @summary This component provides a user interface for paginated content navigation,
6500
+ * displaying page numbers and navigation controls. It supports customizable page counts,
6501
+ * current page tracking, and emits events when users navigate between pages.
6523
6502
  *
6524
- * @example
6525
- * <ngx-decaf-list-item
6526
- * [item]="dataItem"
6527
- * icon="star"
6528
- * title="Item Title"
6529
- * description="Item Description"
6530
- * (clickEvent)="handleItemClick($event)">
6531
- * </ngx-decaf-list-item>
6503
+ * The component intelligently handles large numbers of pages by showing a subset of page
6504
+ * numbers with ellipses to indicate skipped pages, ensuring the UI remains clean and usable
6505
+ * even with many pages.
6532
6506
  *
6533
6507
  * @mermaid
6534
6508
  * sequenceDiagram
6535
- * participant C as Component
6536
- * participant V as View
6537
6509
  * participant U as User
6538
- * C->>V: Initialize component
6539
- * V->>U: Display list item
6540
- * U->>V: Click on item or action
6541
- * V->>C: Trigger handleAction()
6542
- * C->>C: Process action
6543
- * C->>V: Update view or navigate
6510
+ * participant P as PaginationComponent
6511
+ * participant E as External Component
6512
+ *
6513
+ * U->>P: Click page number
6514
+ * P->>P: navigate(page)
6515
+ * P->>P: handleClick(direction, page)
6516
+ * P->>E: Emit clickEvent with PaginationCustomEvent
6517
+ *
6518
+ * U->>P: Click next button
6519
+ * P->>P: next()
6520
+ * P->>P: handleClick('next')
6521
+ * P->>E: Emit clickEvent with PaginationCustomEvent
6522
+ *
6523
+ * U->>P: Click previous button
6524
+ * P->>P: previous()
6525
+ * P->>P: handleClick('previous')
6526
+ * P->>E: Emit clickEvent with PaginationCustomEvent
6527
+ *
6528
+ * @example
6529
+ * <ngx-decaf-pagination
6530
+ * [pages]="10"
6531
+ * [current]="3"
6532
+ * (clickEvent)="handlePageChange($event)">
6533
+ * </ngx-decaf-pagination>
6534
+ *
6535
+ * @extends {NgxBaseComponent}
6536
+ * @implements {OnInit}
6544
6537
  */
6545
- let ListItemComponent = class ListItemComponent extends NgxBaseComponent {
6538
+ class PaginationComponent extends NgxBaseComponent {
6546
6539
  /**
6547
- * @description Creates an instance of ListItemComponent.
6548
- * @summary Initializes a new ListItemComponent by calling the parent class constructor
6549
- * with the component name for logging and identification purposes. Also registers
6550
- * all available Ionic icons to ensure they can be displayed in the component.
6551
- *
6552
- * @memberOf ListItemComponent
6540
+ * @constructor
6541
+ * @description Initializes a new instance of the PaginationComponent.
6542
+ * Calls the parent constructor with the component name for generate base locale string.
6553
6543
  */
6554
6544
  constructor() {
6555
- super("ListItemComponent");
6556
- /**
6557
- * @description Controls the display of lines around the list item.
6558
- * @summary Determines how lines are displayed around the list item borders.
6559
- * 'inset' shows lines with padding, 'full' shows full-width lines, and 'none'
6560
- * removes all lines. This affects the visual separation between list items.
6561
- *
6562
- * @type {'inset' | 'full' | 'none'}
6563
- * @default 'inset'
6564
- * @memberOf ListItemComponent
6565
- */
6566
- this.lines = 'full';
6567
- /**
6568
- * @description Position of the icon within the list item.
6569
- * @summary Determines whether the icon appears at the start (left in LTR languages)
6570
- * or end (right in LTR languages) of the list item. This affects the overall
6571
- * layout and visual hierarchy of the item content.
6572
- *
6573
- * @type {'start' | 'end'}
6574
- * @default 'start'
6575
- * @memberOf ListItemComponent
6576
- */
6577
- this.iconSlot = 'start';
6545
+ super("PaginationComponent");
6578
6546
  /**
6579
- * @description Controls whether the list item behaves as a clickable button.
6580
- * @summary When set to true, the list item will have button-like behavior including
6581
- * hover effects, click handling, and appropriate accessibility attributes.
6582
- * When false, the item is displayed as static content without interactive behavior.
6547
+ * @description Controls whether the component uses translation services.
6548
+ * @summary When set to true, the component will attempt to use translation services
6549
+ * for any text content. This allows for internationalization of the pagination component.
6583
6550
  *
6584
6551
  * @type {StringOrBoolean}
6585
6552
  * @default true
6586
- * @memberOf ListItemComponent
6587
- */
6588
- this.button = true;
6589
- /**
6590
- * @description Event emitter for list item click interactions.
6591
- * @summary Emits custom events when the list item is clicked or when actions
6592
- * are performed on it. The emitted event contains information about the action,
6593
- * the item data, and other relevant context for parent components to handle.
6594
- *
6595
- * @type {EventEmitter<ListItemCustomEvent>}
6596
- * @memberOf ListItemComponent
6597
- */
6598
- this.clickEvent = new EventEmitter();
6599
- /**
6600
- * @description Flag indicating whether slide items are currently enabled.
6601
- * @summary Controls the visibility of slide actions based on screen size and
6602
- * available operations. When true, users can swipe on the item to reveal
6603
- * action buttons for operations like edit and delete.
6604
- *
6605
- * @type {boolean}
6606
- * @default false
6607
- * @memberOf ListItemComponent
6553
+ * @memberOf PaginationComponent
6608
6554
  */
6609
- this.showSlideItems = false;
6555
+ this.translatable = true;
6610
6556
  /**
6611
- * @description Flag indicating whether the action menu popover is currently open.
6612
- * @summary Tracks the state of the action menu to prevent multiple instances
6613
- * from being opened simultaneously and to ensure proper cleanup when actions
6614
- * are performed. Used for managing the popover lifecycle.
6557
+ * @description The currently active page number.
6558
+ * @summary Specifies which page is currently active or selected. This value is used
6559
+ * to highlight the current page in the UI and as a reference point for navigation.
6615
6560
  *
6616
- * @type {boolean}
6617
- * @default false
6618
- * @memberOf ListItemComponent
6561
+ * @type {number}
6562
+ * @default 1
6563
+ * @memberOf PaginationComponent
6619
6564
  */
6620
- this.actionMenuOpen = false;
6565
+ this.current = 1;
6621
6566
  /**
6622
- * @description Angular NavController service for handling navigation.
6623
- * @summary Injected service that provides methods for programmatic navigation
6624
- * within the Ionic application. Used for navigating to different routes when
6625
- * list item actions are performed or when the item itself is clicked.
6567
+ * @description Event emitter for pagination navigation events.
6568
+ * @summary Emits a custom event when users navigate between pages, either by clicking
6569
+ * on page numbers or using the next/previous buttons. The event contains information
6570
+ * about the navigation direction and the target page number.
6626
6571
  *
6627
- * @private
6628
- * @type {NavController}
6629
- * @memberOf ListItemComponent
6572
+ * @type {EventEmitter<PaginationCustomEvent>}
6573
+ * @memberOf PaginationComponent
6630
6574
  */
6631
- this.navController = inject(NavController);
6632
- addIcons(allIcons);
6575
+ this.clickEvent = new EventEmitter();
6576
+ addIcons({ chevronBackOutline, chevronForwardOutline });
6633
6577
  }
6634
6578
  /**
6635
- * @description Initializes the component after Angular first displays the data-bound properties.
6636
- * @summary Sets up the component by determining slide item visibility, processing boolean inputs,
6637
- * building CSS class names based on properties, and capturing the current window width.
6638
- * This method prepares the component for user interaction by ensuring all properties are
6639
- * properly initialized and responsive behavior is configured.
6579
+ * @description Initializes the component after Angular sets the input properties.
6580
+ * @summary Sets up the component by initializing the locale settings based on the
6581
+ * translatable property, generating the page numbers based on the total pages and
6582
+ * current page, and storing the last page number for boundary checking.
6640
6583
  *
6641
6584
  * @mermaid
6642
6585
  * sequenceDiagram
6643
6586
  * participant A as Angular Lifecycle
6644
- * participant L as ListItemComponent
6645
- * participant W as Window
6587
+ * participant P as PaginationComponent
6646
6588
  *
6647
- * A->>L: ngOnInit()
6648
- * L->>L: enableSlideItems()
6649
- * L->>L: Process button boolean
6650
- * L->>L: Build className with flex classes
6651
- * alt operations exist
6652
- * L->>L: Add 'action' class
6653
- * end
6654
- * L->>W: getWindowWidth()
6655
- * W-->>L: Return current width
6656
- * L->>L: Store windowWidth
6589
+ * A->>P: ngOnInit()
6590
+ * P->>P: getLocale(translatable)
6591
+ * P->>P: Set locale
6592
+ * P->>P: getPages(data, current)
6593
+ * P->>P: Set pages array
6594
+ * P->>P: Set last page number
6657
6595
  *
6658
- * @return {Promise<void>}
6659
- * @memberOf ListItemComponent
6596
+ * @returns {void}
6597
+ * @memberOf PaginationComponent
6660
6598
  */
6661
- async ngOnInit() {
6662
- this.showSlideItems = this.enableSlideItems();
6663
- this.button = stringToBoolean(this.button);
6664
- this.className = `${this.className} dcf-flex dcf-flex-middle grid-item`;
6665
- if (this.operations?.length)
6666
- this.className += ` action`;
6667
- this.windowWidth = getWindowWidth();
6599
+ ngOnInit() {
6600
+ this.locale = this.getLocale(this.translatable);
6601
+ this.pages = this.getPages(this.totalPages, this.current);
6602
+ this.last = this.totalPages;
6668
6603
  }
6669
6604
  /**
6670
- * @description Handles user interactions and actions performed on the list item.
6671
- * @summary This method is the central action handler for list item interactions. It manages
6672
- * event propagation, dismisses open action menus, removes focus traps, and either emits
6673
- * events for parent components to handle or performs navigation based on the component's
6674
- * route configuration. This method supports both event-driven and navigation-driven architectures.
6605
+ * @description Handles click events on pagination controls.
6606
+ * @summary Processes user interactions with the pagination component, updating the
6607
+ * current page if specified and emitting an event with navigation details. This method
6608
+ * is called when users click on page numbers or navigation buttons.
6675
6609
  *
6676
- * @param {CrudOperations} action - The type of CRUD operation being performed
6677
- * @param {Event} event - The browser event that triggered the action
6678
- * @param {HTMLElement} [target] - Optional target element for the event
6679
- * @return {Promise<boolean|void>} A promise that resolves to navigation success or void for events
6610
+ * @param {('next' | 'previous')} direction - The direction of navigation
6611
+ * @param {number} [page] - Optional page number to navigate to directly
6612
+ * @returns {void}
6680
6613
  *
6681
6614
  * @mermaid
6682
6615
  * sequenceDiagram
6683
6616
  * participant U as User
6684
- * participant L as ListItemComponent
6685
- * participant P as Parent Component
6686
- * participant N as NavController
6687
- * participant E as Event System
6617
+ * participant P as PaginationComponent
6618
+ * participant E as External Component
6688
6619
  *
6689
- * U->>L: Perform action (click/swipe)
6690
- * L->>L: stopImmediatePropagation()
6691
- * alt actionMenuOpen
6692
- * L->>L: Dismiss action menu
6693
- * end
6694
- * L->>L: removeFocusTrap()
6695
- * alt No route configured
6696
- * L->>E: windowEventEmitter()
6697
- * L->>P: clickEvent.emit()
6698
- * else Route configured
6699
- * L->>N: redirect(action, uid)
6700
- * N-->>L: Return navigation result
6620
+ * U->>P: Click pagination control
6621
+ * P->>P: handleClick(direction, page?)
6622
+ * alt page is provided
6623
+ * P->>P: Update current page
6701
6624
  * end
6625
+ * P->>E: Emit clickEvent with direction and page
6702
6626
  *
6703
- * @memberOf ListItemComponent
6627
+ * @memberOf PaginationComponent
6704
6628
  */
6705
- async handleAction(action, event, target) {
6706
- event.stopImmediatePropagation();
6707
- if (this.actionMenuOpen)
6708
- await this.actionMenuComponent.dismiss();
6709
- // forcing trap focus
6710
- removeFocusTrap();
6711
- if (!this.route) {
6712
- const event = { target: target, action, pk: this.pk, data: this.uid, name: EventConstants.CLICK, component: this.componentName };
6713
- windowEventEmitter(`ListItem${EventConstants.CLICK}`, event);
6714
- return this.clickEvent.emit(event);
6715
- }
6716
- return await this.redirect(action, (typeof this.uid === 'number' ? `${this.uid}` : this.uid));
6629
+ handleClick(direction, page) {
6630
+ if (page)
6631
+ this.current = page;
6632
+ this.clickEvent.emit({
6633
+ name: EventConstants.CLICK,
6634
+ data: {
6635
+ direction,
6636
+ page: this.current
6637
+ },
6638
+ component: this.componentName
6639
+ });
6717
6640
  }
6718
6641
  /**
6719
- * @description Responsive handler that enables or disables slide items based on screen size and operations.
6720
- * @summary This method is automatically called when the window is resized and also during component
6721
- * initialization. It determines whether slide actions should be available based on the current
6722
- * window width and the presence of UPDATE or DELETE operations. Slide items are typically hidden
6723
- * on larger screens where there's space for dedicated action buttons.
6642
+ * @description Generates the array of page objects for display.
6643
+ * @summary Creates an array of page objects based on the total number of pages and
6644
+ * the current page. For small page counts (≤5), all pages are shown. For larger page
6645
+ * counts, a subset is shown with ellipses to indicate skipped pages. This ensures
6646
+ * the pagination UI remains clean and usable even with many pages.
6724
6647
  *
6725
- * @return {boolean} True if slide items should be shown, false otherwise
6648
+ * @param {number} total - The total number of pages
6649
+ * @param {number} [current] - The current active page (defaults to this.current)
6650
+ * @returns {KeyValue[]} Array of page objects with index and text properties
6726
6651
  *
6727
6652
  * @mermaid
6728
- * sequenceDiagram
6729
- * participant W as Window
6730
- * participant L as ListItemComponent
6731
- * participant U as UI
6653
+ * flowchart TD
6654
+ * A[Start] --> B{total <= 5?}
6655
+ * B -->|Yes| C[Show all pages]
6656
+ * B -->|No| D[Show first page]
6657
+ * D --> E[Show last pages]
6658
+ * E --> F[Add ellipses for skipped pages]
6659
+ * C --> G[Return pages array]
6660
+ * F --> G
6732
6661
  *
6733
- * W->>L: resize event
6734
- * L->>W: getWindowWidth()
6735
- * W-->>L: Return current width
6736
- * L->>L: Store windowWidth
6737
- * alt No operations OR width > 639px
6738
- * L->>U: showSlideItems = false
6739
- * else Operations include UPDATE/DELETE
6740
- * L->>U: showSlideItems = true
6741
- * end
6742
- * L-->>U: Return showSlideItems value
6662
+ * @memberOf PaginationComponent
6663
+ */
6664
+ getPages(total, current) {
6665
+ if (!current)
6666
+ current = this.current;
6667
+ const pages = [];
6668
+ function getPage(index, text = '', clazz = 'button') {
6669
+ if (pages.some(item => item['index'] === index))
6670
+ return;
6671
+ pages.push({ index, text: index != null ? index.toString().padStart(2, '0') : text, class: clazz });
6672
+ }
6673
+ if (total <= 5) {
6674
+ for (let i = 1; i <= total; i++)
6675
+ getPage(i);
6676
+ }
6677
+ else {
6678
+ // Adiciona os dois primeiros
6679
+ getPage(1);
6680
+ getPage(2);
6681
+ // Adiciona "..." entre os blocos
6682
+ if (current && current > 3)
6683
+ getPage(null, '...');
6684
+ // Adiciona a página atual (se estiver no meio)
6685
+ if (current && current > 2 && current < total - 1)
6686
+ getPage(current);
6687
+ // Adiciona "..." entre os blocos
6688
+ if (current && current < total - 2)
6689
+ getPage(null, '...', 'separator');
6690
+ // Adiciona os dois últimos
6691
+ getPage(total - 1);
6692
+ getPage(total);
6693
+ }
6694
+ return pages;
6695
+ }
6696
+ /**
6697
+ * @description Gets the current active page number.
6698
+ * @summary Returns the current page number that is active in the pagination component.
6699
+ * This method provides a way to access the current page state from outside the component.
6743
6700
  *
6744
- * @memberOf ListItemComponent
6701
+ * @returns {number} The current page number
6702
+ * @memberOf PaginationComponent
6745
6703
  */
6746
- enableSlideItems() {
6747
- this.windowWidth = getWindowWidth();
6748
- if (!this.operations?.length || this.windowWidth > 639)
6749
- return this.showSlideItems = false;
6750
- this.showSlideItems = this.operations.includes(OperationKeys.UPDATE) || this.operations.includes(OperationKeys.DELETE);
6751
- return this.showSlideItems;
6704
+ getCurrent() {
6705
+ return this.current;
6752
6706
  }
6753
6707
  /**
6754
- * @description Animates and removes an element from the DOM.
6755
- * @summary This method applies CSS animation classes to create a smooth fade-out effect
6756
- * before removing the element from the DOM. The animation enhances user experience by
6757
- * providing visual feedback when items are deleted or removed from lists. The timing
6758
- * is coordinated with the CSS animation duration to ensure the element is removed
6759
- * after the animation completes.
6708
+ * @description Navigates to the next page.
6709
+ * @summary Increments the current page number if not at the last page and triggers
6710
+ * the click event handler with 'next' direction. This method is typically called
6711
+ * when the user clicks on the "next" button in the pagination UI.
6760
6712
  *
6761
- * @param {HTMLElement} element - The DOM element to animate and remove
6762
- * @return {void}
6713
+ * @returns {void}
6763
6714
  *
6764
6715
  * @mermaid
6765
6716
  * sequenceDiagram
6766
- * participant L as ListItemComponent
6767
- * participant E as HTMLElement
6768
- * participant D as DOM
6717
+ * participant U as User
6718
+ * participant P as PaginationComponent
6769
6719
  *
6770
- * L->>E: Add animation classes
6771
- * Note over E: uk-animation-fade, uk-animation-medium, uk-animation-reverse
6772
- * E->>E: Start fade animation
6773
- * L->>L: setTimeout(600ms)
6774
- * Note over L: Wait for animation to complete
6775
- * L->>D: element.remove()
6776
- * D->>D: Remove element from DOM
6720
+ * U->>P: Click next button
6721
+ * P->>P: next()
6722
+ * alt page <= max pages
6723
+ * P->>P: Increment current page
6724
+ * P->>P: handleClick('next')
6725
+ * end
6777
6726
  *
6778
- * @memberOf ListItemComponent
6727
+ * @memberOf PaginationComponent
6779
6728
  */
6780
- removeElement(element) {
6781
- element.classList.add('uk-animation-fade', 'uk-animation-medium', 'uk-animation-reverse');
6782
- setTimeout(() => { element.remove(); }, 600);
6729
+ next() {
6730
+ const page = this.current + 1;
6731
+ if (page <= Object.keys(this.pages)?.length || 0) {
6732
+ this.current = page;
6733
+ this.handleClick('next');
6734
+ }
6783
6735
  }
6784
6736
  /**
6785
- * @description Navigates to a new route based on the specified action and item ID.
6786
- * @summary This method constructs a navigation URL using the component's route configuration,
6787
- * the specified action, and an item identifier. It uses Ionic's NavController to perform
6788
- * forward navigation with appropriate animations. This method is typically used for
6789
- * CRUD operations where each action (create, read, update, delete) has its own route.
6737
+ * @description Navigates to the previous page.
6738
+ * @summary Decrements the current page number if not at the first page and triggers
6739
+ * the click event handler with 'previous' direction. This method is typically called
6740
+ * when the user clicks on the "previous" button in the pagination UI.
6790
6741
  *
6791
- * @param {string} action - The action to be performed (e.g., 'edit', 'view', 'delete')
6792
- * @param {string} [id] - The unique identifier of the item to be acted upon
6793
- * @return {Promise<boolean>} A promise that resolves to true if navigation was successful
6742
+ * @returns {void}
6794
6743
  *
6795
6744
  * @mermaid
6796
6745
  * sequenceDiagram
6797
- * participant L as ListItemComponent
6798
- * participant N as NavController
6799
- * participant R as Router
6746
+ * participant U as User
6747
+ * participant P as PaginationComponent
6800
6748
  *
6801
- * L->>L: redirect(action, id)
6802
- * L->>L: Construct URL: /{route}/{action}/{id}
6803
- * L->>N: navigateForward(url)
6804
- * N->>R: Navigate to constructed URL
6805
- * R-->>N: Return navigation result
6806
- * N-->>L: Return boolean success
6749
+ * U->>P: Click previous button
6750
+ * P->>P: previous()
6751
+ * alt page > 0
6752
+ * P->>P: Decrement current page
6753
+ * P->>P: handleClick('previous')
6754
+ * end
6807
6755
  *
6808
- * @memberOf ListItemComponent
6756
+ * @memberOf PaginationComponent
6809
6757
  */
6810
- async redirect(action, id) {
6811
- return await this.navController.navigateForward(`/${this.route}/${action}/${id || this.uid}`);
6758
+ previous() {
6759
+ const page = this.current - 1;
6760
+ if (page > 0) {
6761
+ this.current = page;
6762
+ this.handleClick('previous');
6763
+ }
6812
6764
  }
6813
6765
  /**
6814
- * @description Presents the actions menu popover for the list item.
6815
- * @summary This method handles the display of a contextual action menu when triggered by user
6816
- * interaction (typically a long press or right-click). It stops event propagation to prevent
6817
- * unwanted side effects, removes any existing focus traps for accessibility, configures the
6818
- * popover with the triggering event, and opens the action menu. The menu typically contains
6819
- * available CRUD operations for the item.
6766
+ * @description Navigates to a specific page number.
6767
+ * @summary Updates the current page to the specified page number and triggers
6768
+ * the click event handler with the appropriate direction. This method is typically
6769
+ * called when the user clicks directly on a page number in the pagination UI.
6820
6770
  *
6821
- * @param {Event} event - The event that triggered the action menu request
6822
- * @return {void}
6771
+ * @param {number | null} page - The page number to navigate to
6772
+ * @returns {void}
6823
6773
  *
6824
6774
  * @mermaid
6825
6775
  * sequenceDiagram
6826
6776
  * participant U as User
6827
- * participant L as ListItemComponent
6828
- * participant P as Popover
6829
- * participant A as Accessibility
6777
+ * participant P as PaginationComponent
6830
6778
  *
6831
- * U->>L: Trigger action menu (long press/right-click)
6832
- * L->>L: stopImmediatePropagation()
6833
- * L->>A: removeFocusTrap()
6834
- * L->>P: Set event reference
6835
- * L->>L: actionMenuOpen = true
6836
- * L->>P: Display popover with actions
6779
+ * U->>P: Click page number
6780
+ * P->>P: navigate(page)
6781
+ * alt page is not null and different from current
6782
+ * P->>P: Determine direction (next/previous)
6783
+ * P->>P: handleClick(direction, page)
6784
+ * end
6837
6785
  *
6838
- * @memberOf ListItemComponent
6786
+ * @memberOf PaginationComponent
6839
6787
  */
6840
- presentActionsMenu(event) {
6841
- event.stopImmediatePropagation();
6842
- // forcing trap focus
6843
- removeFocusTrap();
6844
- this.actionMenuComponent.event = event;
6845
- this.actionMenuOpen = true;
6788
+ navigate(page) {
6789
+ if (page !== null && this.current !== page)
6790
+ this.handleClick(page > this.current ? 'next' : 'previous', page);
6846
6791
  }
6847
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ListItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6848
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", 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)" } }, viewQueries: [{ propertyName: "actionMenuComponent", first: true, predicate: ["actionMenuComponent"], descendants: true }], usesInheritance: true, ngImport: i0, template: "\n@if(title || description) {\n <ion-item-sliding #component>\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 \">\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 <ion-label class=\"dcf-item-title\" [innerHTML]=\"uid + ' - ' + title\" ></ion-label>\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 <div class=\"dcf-visible@m\" id=\"dcf-actions\">\n <ion-button class=\"dcf-hidden@m\" 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{--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)}@media (prefers-color-scheme: dark){ion-item{--background-hover-opacity: .25;--background-focused-opacity: .25}}@media (prefers-color-scheme: light){ion-item{--background-hover-opacity: .1;--background-focused-opacity: .1}}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}@media (prefers-color-scheme: light){ion-item{--border-color: var(--dcf-color-gray-2)}ion-item .dcf-info{color:var(--dcf-color-gray-6)}ion-item .dcf-item-title{color:var(--dcf-color-gray-8)}ion-item .dcf-description{color:var(--dcf-color-gray-6)}}@media (prefers-color-scheme: dark){ion-item{--border-color: var(--dcf-color-gray-6)}ion-item .dcf-description{color:var(--dcf-color-gray-4)}}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}}@media (prefers-color-scheme: light){ion-item .dcf-icon ion-button{color:var(--dcf-color-gray-7);--background: var(--dcf-color-gray-1) !important}}@media (prefers-color-scheme: dark){ion-item .dcf-icon ion-button{color:var(--dcf-color-gray-1)!important;--background: var(--dcf-color-gray-7) !important}}ion-item .dcf-icon ion-button ion-icon{font-size:20px}ion-item .dcf-icon ion-avatar{width:48px;height:48px;display:flex;justify-content:center;align-items:center;text-align:center}@media (prefers-color-scheme: light){ion-item .dcf-icon ion-avatar{color:var(--dcf-color-gray-7);background:var(--dcf-color-gray-1)!important}}@media (prefers-color-scheme: dark){ion-item .dcf-icon ion-avatar{color:var(--dcf-color-gray-1)!important;background:var(--dcf-background-color)!important}}ion-item .dcf-icon ion-avatar ion-icon{font-size:20px}ion-item .dcf-icon ion-avatar .dcf-icon-large{transform:translateY(5px)}ion-item-sliding{box-sizing:border-box}@media (prefers-color-scheme: light){ion-item-sliding ion-item-option:not(.dcf-delete),ion-item-sliding ion-item-option:not(.dcf-update){background:rgba(var(--dcf-color-dark-rgb),.25)!important}ion-item-sliding ion-item-option:not(.dcf-delete) .dcf-ti,ion-item-sliding ion-item-option:not(.dcf-delete) ion-icon,ion-item-sliding ion-item-option:not(.dcf-update) .dcf-ti,ion-item-sliding ion-item-option:not(.dcf-update) ion-icon{color:var(--dcf-color-gray-7)!important}ion-item-sliding ion-item-option.dcf-delete{background:rgba(var(--dcf-color-danger-rgb),.05)!important}ion-item-sliding ion-item-option.dcf-delete .dcf-ti,ion-item-sliding ion-item-option.dcf-delete *,ion-item-sliding ion-item-option.dcf-delete ion-icon{color:var(--dcf-color-danger)!important}ion-item-sliding ion-item-option.dcf-update{background:rgba(var(--dcf-color-primary-rgb),.05)!important}ion-item-sliding ion-item-option.dcf-update .dcf-ti,ion-item-sliding ion-item-option.dcf-update ion-icon{color:var(--dcf-color-primary)!important}}@media (prefers-color-scheme: dark){ion-item-sliding ion-item-option:not(.dcf-delete),ion-item-sliding ion-item-option:not(.dcf-update){background:rgba(var(--dcf-color-dark-rgb),1)!important}ion-item-sliding ion-item-option:not(.dcf-delete) .dcf-ti,ion-item-sliding ion-item-option:not(.dcf-delete) ion-icon,ion-item-sliding ion-item-option:not(.dcf-update) .dcf-ti,ion-item-sliding ion-item-option:not(.dcf-update) ion-icon{color:var(--dcf-color-gray-2)!important}ion-item-sliding ion-item-option.dcf-delete{background:rgba(var(--dcf-color-danger-rgb),.05)!important}ion-item-sliding ion-item-option.dcf-delete .dcf-ti,ion-item-sliding ion-item-option.dcf-delete *,ion-item-sliding ion-item-option.dcf-delete ion-icon{color:var(--dcf-color-danger)!important}ion-item-sliding ion-item-option.dcf-update{background:rgba(var(--dcf-color-primary-rgb),.05)!important}ion-item-sliding ion-item-option.dcf-update .dcf-ti,ion-item-sliding ion-item-option.dcf-update ion-icon{color:var(--dcf-color-gray-2)!important}}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)}\n"], dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }, { 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" }] }); }
6849
- };
6850
- ListItemComponent = __decorate([
6851
- Dynamic(),
6852
- __metadata("design:paramtypes", [])
6853
- ], ListItemComponent);
6854
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ListItemComponent, decorators: [{
6792
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: PaginationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6793
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.2", type: PaginationComponent, isStandalone: true, selector: "ngx-decaf-pagination", inputs: { totalPages: "totalPages", current: "current" }, outputs: { clickEvent: "clickEvent" }, usesInheritance: true, ngImport: i0, template: " <div [id]=\"uid\" class=\"dcf-paginator-container dcf-flex dcf-flex-center\">\n <div class=\"dcf-width-1-1\">\n <div class=\"dcf-pagination-resume\" [innerHTML]=\"locale + '.resume' | translate: {value0: current, value1: last}\"></div>\n <div #paginationComponent class=\"dcf-pagination dcf-flex-center\">\n <div\n aria-label=\"previous\"\n tabindex=\"0\"\n (click)=\"previous()\"\n (keydown.enter)=\"previous()\" [class.dcf-disabled]=\"current === 1\">\n <ion-icon name=\"chevron-back-outline\" aria-hidden=\"true\"></ion-icon>\n </div>\n @for(page of pages; track page) {\n <div tabindex=\"0\" [class]=\"page['class']\" (click)=\"navigate(page['index'])\"\n (keydown.enter)=\"navigate(page['index'])\"\n [class.dcf-active]=\"current === page['index']\">\n <span class=\"page-item\">{{ page['text'] }}</span>\n </div>\n }\n <div\n tabindex=\"0\" (click)=\"next()\"\n (keydown.enter)=\"next()\"\n [class.dcf-disabled]=\"current === last\">\n <ion-icon name=\"chevron-forward-outline\" aria-hidden=\"true\"></ion-icon>\n </div>\n </div>\n </div>\n</div>\n", styles: [".dcf-paginator-container{margin-bottom:1rem}.dcf-pagination{display:flex;flex-wrap:wrap;align-items:center;margin-left:0;padding:0;list-style:none}.dcf-pagination .page-item{display:flex;justify-content:center;align-items:center;text-align:center;font-weight:600;width:34px;line-height:34px;padding:0!important;border-radius:50%;box-sizing:border-box}@media (prefers-color-scheme: dark){.dcf-pagination .page-item{color:var(--dcf-color-gray-3)!important}}@media (prefers-color-scheme: light){.dcf-pagination .page-item{color:var(--dcf-color-gray-7)!important}}.dcf-pagination>*{flex:none;padding-left:0;position:relative;margin:0px .15rem;cursor:pointer}.dcf-pagination>*.dcf-disabled{pointer-events:none;touch-action:none;cursor:text}.dcf-pagination>*.dcf-active{pointer-events:none;touch-action:none}@media (prefers-color-scheme: light){.dcf-pagination>*.dcf-active .page-item{background:rgba(var(--dcf-color-primary-rgb),.15)}.dcf-pagination>*:hover:not(.dcf-active) *{color:var(--dcf-color-primary)!important}}@media (prefers-color-scheme: dark){.dcf-pagination>*.dcf-active .page-item{background:var(--dcf-color-gray-7)}.dcf-pagination>*:hover:not(.dcf-active) *{color:var(--dcf-color-primary)!important}}.dcf-pagination-resume{margin:1rem 0px;text-align:center}@media (prefers-color-scheme: light){.dcf-pagination-resume{color:var(--dcf-color-gray-8)}}\n"], dependencies: [{ kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
6794
+ }
6795
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: PaginationComponent, decorators: [{
6855
6796
  type: Component,
6856
- args: [{ selector: 'ngx-decaf-list-item', standalone: true, imports: [
6797
+ args: [{ selector: 'ngx-decaf-pagination', imports: [
6857
6798
  TranslatePipe,
6858
- IonList,
6859
- IonListHeader,
6860
- IonItem,
6861
- IonItemSliding,
6862
- IonItemOptions,
6863
- IonItemOption,
6864
- IonIcon,
6865
- IonLabel,
6866
- IonButton,
6867
- IonContent,
6868
- IonPopover
6869
- ], template: "\n@if(title || description) {\n <ion-item-sliding #component>\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 \">\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 <ion-label class=\"dcf-item-title\" [innerHTML]=\"uid + ' - ' + title\" ></ion-label>\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 <div class=\"dcf-visible@m\" id=\"dcf-actions\">\n <ion-button class=\"dcf-hidden@m\" 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{--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)}@media (prefers-color-scheme: dark){ion-item{--background-hover-opacity: .25;--background-focused-opacity: .25}}@media (prefers-color-scheme: light){ion-item{--background-hover-opacity: .1;--background-focused-opacity: .1}}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}@media (prefers-color-scheme: light){ion-item{--border-color: var(--dcf-color-gray-2)}ion-item .dcf-info{color:var(--dcf-color-gray-6)}ion-item .dcf-item-title{color:var(--dcf-color-gray-8)}ion-item .dcf-description{color:var(--dcf-color-gray-6)}}@media (prefers-color-scheme: dark){ion-item{--border-color: var(--dcf-color-gray-6)}ion-item .dcf-description{color:var(--dcf-color-gray-4)}}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}}@media (prefers-color-scheme: light){ion-item .dcf-icon ion-button{color:var(--dcf-color-gray-7);--background: var(--dcf-color-gray-1) !important}}@media (prefers-color-scheme: dark){ion-item .dcf-icon ion-button{color:var(--dcf-color-gray-1)!important;--background: var(--dcf-color-gray-7) !important}}ion-item .dcf-icon ion-button ion-icon{font-size:20px}ion-item .dcf-icon ion-avatar{width:48px;height:48px;display:flex;justify-content:center;align-items:center;text-align:center}@media (prefers-color-scheme: light){ion-item .dcf-icon ion-avatar{color:var(--dcf-color-gray-7);background:var(--dcf-color-gray-1)!important}}@media (prefers-color-scheme: dark){ion-item .dcf-icon ion-avatar{color:var(--dcf-color-gray-1)!important;background:var(--dcf-background-color)!important}}ion-item .dcf-icon ion-avatar ion-icon{font-size:20px}ion-item .dcf-icon ion-avatar .dcf-icon-large{transform:translateY(5px)}ion-item-sliding{box-sizing:border-box}@media (prefers-color-scheme: light){ion-item-sliding ion-item-option:not(.dcf-delete),ion-item-sliding ion-item-option:not(.dcf-update){background:rgba(var(--dcf-color-dark-rgb),.25)!important}ion-item-sliding ion-item-option:not(.dcf-delete) .dcf-ti,ion-item-sliding ion-item-option:not(.dcf-delete) ion-icon,ion-item-sliding ion-item-option:not(.dcf-update) .dcf-ti,ion-item-sliding ion-item-option:not(.dcf-update) ion-icon{color:var(--dcf-color-gray-7)!important}ion-item-sliding ion-item-option.dcf-delete{background:rgba(var(--dcf-color-danger-rgb),.05)!important}ion-item-sliding ion-item-option.dcf-delete .dcf-ti,ion-item-sliding ion-item-option.dcf-delete *,ion-item-sliding ion-item-option.dcf-delete ion-icon{color:var(--dcf-color-danger)!important}ion-item-sliding ion-item-option.dcf-update{background:rgba(var(--dcf-color-primary-rgb),.05)!important}ion-item-sliding ion-item-option.dcf-update .dcf-ti,ion-item-sliding ion-item-option.dcf-update ion-icon{color:var(--dcf-color-primary)!important}}@media (prefers-color-scheme: dark){ion-item-sliding ion-item-option:not(.dcf-delete),ion-item-sliding ion-item-option:not(.dcf-update){background:rgba(var(--dcf-color-dark-rgb),1)!important}ion-item-sliding ion-item-option:not(.dcf-delete) .dcf-ti,ion-item-sliding ion-item-option:not(.dcf-delete) ion-icon,ion-item-sliding ion-item-option:not(.dcf-update) .dcf-ti,ion-item-sliding ion-item-option:not(.dcf-update) ion-icon{color:var(--dcf-color-gray-2)!important}ion-item-sliding ion-item-option.dcf-delete{background:rgba(var(--dcf-color-danger-rgb),.05)!important}ion-item-sliding ion-item-option.dcf-delete .dcf-ti,ion-item-sliding ion-item-option.dcf-delete *,ion-item-sliding ion-item-option.dcf-delete ion-icon{color:var(--dcf-color-danger)!important}ion-item-sliding ion-item-option.dcf-update{background:rgba(var(--dcf-color-primary-rgb),.05)!important}ion-item-sliding ion-item-option.dcf-update .dcf-ti,ion-item-sliding ion-item-option.dcf-update ion-icon{color:var(--dcf-color-gray-2)!important}}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)}\n"] }]
6870
- }], ctorParameters: () => [], propDecorators: { actionMenuComponent: [{
6871
- type: ViewChild,
6872
- args: ['actionMenuComponent']
6873
- }], lines: [{
6874
- type: Input
6875
- }], item: [{
6876
- type: Input
6877
- }], icon: [{
6878
- type: Input
6879
- }], iconSlot: [{
6880
- type: Input
6881
- }], button: [{
6882
- type: Input
6883
- }], title: [{
6884
- type: Input
6885
- }], description: [{
6886
- type: Input
6887
- }], info: [{
6888
- type: Input
6889
- }], subinfo: [{
6799
+ IonIcon
6800
+ ], standalone: true, template: " <div [id]=\"uid\" class=\"dcf-paginator-container dcf-flex dcf-flex-center\">\n <div class=\"dcf-width-1-1\">\n <div class=\"dcf-pagination-resume\" [innerHTML]=\"locale + '.resume' | translate: {value0: current, value1: last}\"></div>\n <div #paginationComponent class=\"dcf-pagination dcf-flex-center\">\n <div\n aria-label=\"previous\"\n tabindex=\"0\"\n (click)=\"previous()\"\n (keydown.enter)=\"previous()\" [class.dcf-disabled]=\"current === 1\">\n <ion-icon name=\"chevron-back-outline\" aria-hidden=\"true\"></ion-icon>\n </div>\n @for(page of pages; track page) {\n <div tabindex=\"0\" [class]=\"page['class']\" (click)=\"navigate(page['index'])\"\n (keydown.enter)=\"navigate(page['index'])\"\n [class.dcf-active]=\"current === page['index']\">\n <span class=\"page-item\">{{ page['text'] }}</span>\n </div>\n }\n <div\n tabindex=\"0\" (click)=\"next()\"\n (keydown.enter)=\"next()\"\n [class.dcf-disabled]=\"current === last\">\n <ion-icon name=\"chevron-forward-outline\" aria-hidden=\"true\"></ion-icon>\n </div>\n </div>\n </div>\n</div>\n", styles: [".dcf-paginator-container{margin-bottom:1rem}.dcf-pagination{display:flex;flex-wrap:wrap;align-items:center;margin-left:0;padding:0;list-style:none}.dcf-pagination .page-item{display:flex;justify-content:center;align-items:center;text-align:center;font-weight:600;width:34px;line-height:34px;padding:0!important;border-radius:50%;box-sizing:border-box}@media (prefers-color-scheme: dark){.dcf-pagination .page-item{color:var(--dcf-color-gray-3)!important}}@media (prefers-color-scheme: light){.dcf-pagination .page-item{color:var(--dcf-color-gray-7)!important}}.dcf-pagination>*{flex:none;padding-left:0;position:relative;margin:0px .15rem;cursor:pointer}.dcf-pagination>*.dcf-disabled{pointer-events:none;touch-action:none;cursor:text}.dcf-pagination>*.dcf-active{pointer-events:none;touch-action:none}@media (prefers-color-scheme: light){.dcf-pagination>*.dcf-active .page-item{background:rgba(var(--dcf-color-primary-rgb),.15)}.dcf-pagination>*:hover:not(.dcf-active) *{color:var(--dcf-color-primary)!important}}@media (prefers-color-scheme: dark){.dcf-pagination>*.dcf-active .page-item{background:var(--dcf-color-gray-7)}.dcf-pagination>*:hover:not(.dcf-active) *{color:var(--dcf-color-primary)!important}}.dcf-pagination-resume{margin:1rem 0px;text-align:center}@media (prefers-color-scheme: light){.dcf-pagination-resume{color:var(--dcf-color-gray-8)}}\n"] }]
6801
+ }], ctorParameters: () => [], propDecorators: { totalPages: [{
6802
+ type: Input,
6803
+ args: [{ required: true }]
6804
+ }], current: [{
6890
6805
  type: Input
6891
6806
  }], clickEvent: [{
6892
6807
  type: Output
6893
- }], enableSlideItems: [{
6894
- type: HostListener,
6895
- args: ['window:resize', ['$event']]
6896
6808
  }] } });
6897
6809
 
6898
6810
  /**
6899
- * @description A pagination component for navigating through multiple pages of content.
6900
- * @summary This component provides a user interface for paginated content navigation,
6901
- * displaying page numbers and navigation controls. It supports customizable page counts,
6902
- * current page tracking, and emits events when users navigate between pages.
6811
+ * @description A versatile list component that supports various data display modes.
6812
+ * @summary This component provides a flexible way to display lists of data with support
6813
+ * for infinite scrolling, pagination, searching, and custom item rendering. It can fetch
6814
+ * data from various sources including models, functions, or direct data input.
6903
6815
  *
6904
- * The component intelligently handles large numbers of pages by showing a subset of page
6905
- * numbers with ellipses to indicate skipped pages, ensuring the UI remains clean and usable
6906
- * even with many pages.
6816
+ * The component supports two main display types:
6817
+ * 1. Infinite scrolling - Loads more data as the user scrolls
6818
+ * 2. Pagination - Displays data in pages with navigation controls
6819
+ *
6820
+ * Additional features include:
6821
+ * - Pull-to-refresh functionality
6822
+ * - Search filtering
6823
+ * - Empty state customization
6824
+ * - Custom item rendering
6825
+ * - Event emission for interactions
6907
6826
  *
6908
6827
  * @mermaid
6909
6828
  * sequenceDiagram
6910
6829
  * participant U as User
6911
- * participant P as PaginationComponent
6912
- * participant E as External Component
6830
+ * participant L as ListComponent
6831
+ * participant D as Data Source
6832
+ * participant E as External Components
6913
6833
  *
6914
- * U->>P: Click page number
6915
- * P->>P: navigate(page)
6916
- * P->>P: handleClick(direction, page)
6917
- * P->>E: Emit clickEvent with PaginationCustomEvent
6834
+ * U->>L: Initialize component
6835
+ * L->>L: ngOnInit()
6836
+ * L->>D: Request initial data
6837
+ * D-->>L: Return data
6838
+ * L->>L: Process and display data
6918
6839
  *
6919
- * U->>P: Click next button
6920
- * P->>P: next()
6921
- * P->>P: handleClick('next')
6922
- * P->>E: Emit clickEvent with PaginationCustomEvent
6840
+ * alt User scrolls (Infinite mode)
6841
+ * U->>L: Scroll to bottom
6842
+ * L->>D: Request more data
6843
+ * D-->>L: Return additional data
6844
+ * L->>L: Append to existing data
6845
+ * else User changes page (Paginated mode)
6846
+ * U->>L: Click page number
6847
+ * L->>L: handlePaginate()
6848
+ * L->>D: Request data for page
6849
+ * D-->>L: Return page data
6850
+ * L->>L: Replace displayed data
6851
+ * end
6923
6852
  *
6924
- * U->>P: Click previous button
6925
- * P->>P: previous()
6926
- * P->>P: handleClick('previous')
6927
- * P->>E: Emit clickEvent with PaginationCustomEvent
6853
+ * alt User searches
6854
+ * U->>L: Enter search term
6855
+ * L->>L: handleSearch()
6856
+ * L->>D: Filter data by search term
6857
+ * D-->>L: Return filtered data
6858
+ * L->>L: Update displayed data
6859
+ * end
6860
+ *
6861
+ * alt User clicks item
6862
+ * U->>L: Click list item
6863
+ * L->>L: handleClick()
6864
+ * L->>E: Emit clickEvent
6865
+ * end
6928
6866
  *
6929
6867
  * @example
6930
- * <ngx-decaf-pagination
6931
- * [pages]="10"
6932
- * [current]="3"
6933
- * (clickEvent)="handlePageChange($event)">
6934
- * </ngx-decaf-pagination>
6868
+ * <ngx-decaf-list
6869
+ * [source]="dataSource"
6870
+ * [limit]="10"
6871
+ * [type]="'infinite'"
6872
+ * [showSearchbar]="true"
6873
+ * (clickEvent)="handleItemClick($event)"
6874
+ * (refreshEvent)="handleRefresh($event)">
6875
+ * </ngx-decaf-list>
6935
6876
  *
6936
6877
  * @extends {NgxBaseComponent}
6937
6878
  * @implements {OnInit}
6938
6879
  */
6939
- class PaginationComponent extends NgxBaseComponent {
6880
+ let ListComponent = class ListComponent extends NgxBaseComponent {
6940
6881
  /**
6941
- * @constructor
6942
- * @description Initializes a new instance of the PaginationComponent.
6943
- * Calls the parent constructor with the component name for generate base locale string.
6882
+ * @description Initializes a new instance of the ListComponent.
6883
+ * @summary Creates a new ListComponent and sets up the base component with the appropriate
6884
+ * component name. This constructor is called when Angular instantiates the component and
6885
+ * before any input properties are set. It passes the component name to the parent class
6886
+ * constructor to enable proper localization and component identification.
6887
+ *
6888
+ * The constructor is intentionally minimal, with most initialization logic deferred to
6889
+ * the ngOnInit lifecycle hook. This follows Angular best practices by keeping the constructor
6890
+ * focused on dependency injection and basic setup, while complex initialization that depends
6891
+ * on input properties is handled in ngOnInit.
6892
+ *
6893
+ * @memberOf ListComponent
6944
6894
  */
6945
6895
  constructor() {
6946
- super("PaginationComponent");
6896
+ super("ListComponent");
6897
+ /**
6898
+ * @description The display mode for the list component.
6899
+ * @summary Determines how the list data is loaded and displayed. Options include:
6900
+ * - INFINITE: Loads more data as the user scrolls (infinite scrolling)
6901
+ * - PAGINATED: Displays data in pages with navigation controls
6902
+ *
6903
+ * @type {ListComponentsTypes}
6904
+ * @default ListComponentsTypes.INFINITE
6905
+ * @memberOf ListComponent
6906
+ */
6907
+ this.type = ListComponentsTypes.INFINITE;
6947
6908
  /**
6948
6909
  * @description Controls whether the component uses translation services.
6949
6910
  * @summary When set to true, the component will attempt to use translation services
6950
- * for any text content. This allows for internationalization of the pagination component.
6911
+ * for any text content. This allows for internationalization of the list component.
6951
6912
  *
6952
6913
  * @type {StringOrBoolean}
6953
6914
  * @default true
6954
- * @memberOf PaginationComponent
6915
+ * @memberOf ListComponent
6955
6916
  */
6956
6917
  this.translatable = true;
6957
6918
  /**
6958
- * @description The currently active page number.
6959
- * @summary Specifies which page is currently active or selected. This value is used
6960
- * to highlight the current page in the UI and as a reference point for navigation.
6919
+ * @description Controls the visibility of the search bar.
6920
+ * @summary When set to true, displays a search bar at the top of the list that allows
6921
+ * users to filter the list items. The search functionality works by filtering the
6922
+ * existing data or by triggering a new data fetch with search parameters.
6923
+ *
6924
+ * @type {StringOrBoolean}
6925
+ * @default true
6926
+ * @memberOf ListComponent
6927
+ */
6928
+ this.showSearchbar = true;
6929
+ /**
6930
+ * @description Direct data input for the list component.
6931
+ * @summary Provides a way to directly pass data to the list component instead of
6932
+ * fetching it from a source. When both data and source are provided, the component
6933
+ * will use the source to fetch data only if the data array is empty.
6934
+ *
6935
+ * @type {KeyValue[] | undefined}
6936
+ * @default undefined
6937
+ * @memberOf ListComponent
6938
+ */
6939
+ this.data = undefined;
6940
+ /**
6941
+ * @description The starting index for data fetching.
6942
+ * @summary Specifies the index from which to start fetching data. This is used
6943
+ * for pagination and infinite scrolling to determine which subset of data to load.
6961
6944
  *
6962
6945
  * @type {number}
6963
- * @default 1
6964
- * @memberOf PaginationComponent
6946
+ * @default 0
6947
+ * @memberOf ListComponent
6965
6948
  */
6966
- this.current = 1;
6949
+ this.start = 0;
6967
6950
  /**
6968
- * @description Event emitter for pagination navigation events.
6969
- * @summary Emits a custom event when users navigate between pages, either by clicking
6970
- * on page numbers or using the next/previous buttons. The event contains information
6971
- * about the navigation direction and the target page number.
6951
+ * @description The number of items to fetch per page or load operation.
6952
+ * @summary Determines how many items are loaded at once during pagination or
6953
+ * infinite scrolling. This affects the size of data chunks requested from the source.
6972
6954
  *
6973
- * @type {EventEmitter<PaginationCustomEvent>}
6974
- * @memberOf PaginationComponent
6975
- */
6976
- this.clickEvent = new EventEmitter();
6977
- addIcons({ chevronBackOutline, chevronForwardOutline });
6978
- }
6979
- /**
6980
- * @description Initializes the component after Angular sets the input properties.
6981
- * @summary Sets up the component by initializing the locale settings based on the
6982
- * translatable property, generating the page numbers based on the total pages and
6983
- * current page, and storing the last page number for boundary checking.
6984
- *
6985
- * @mermaid
6986
- * sequenceDiagram
6987
- * participant A as Angular Lifecycle
6988
- * participant P as PaginationComponent
6989
- *
6990
- * A->>P: ngOnInit()
6991
- * P->>P: getLocale(translatable)
6992
- * P->>P: Set locale
6993
- * P->>P: getPages(data, current)
6994
- * P->>P: Set pages array
6995
- * P->>P: Set last page number
6996
- *
6997
- * @returns {void}
6998
- * @memberOf PaginationComponent
6999
- */
7000
- ngOnInit() {
7001
- this.locale = this.getLocale(this.translatable);
7002
- this.pages = this.getPages(this.totalPages, this.current);
7003
- this.last = this.totalPages;
7004
- }
7005
- /**
7006
- * @description Handles click events on pagination controls.
7007
- * @summary Processes user interactions with the pagination component, updating the
7008
- * current page if specified and emitting an event with navigation details. This method
7009
- * is called when users click on page numbers or navigation buttons.
7010
- *
7011
- * @param {('next' | 'previous')} direction - The direction of navigation
7012
- * @param {number} [page] - Optional page number to navigate to directly
7013
- * @returns {void}
7014
- *
7015
- * @mermaid
7016
- * sequenceDiagram
7017
- * participant U as User
7018
- * participant P as PaginationComponent
7019
- * participant E as External Component
7020
- *
7021
- * U->>P: Click pagination control
7022
- * P->>P: handleClick(direction, page?)
7023
- * alt page is provided
7024
- * P->>P: Update current page
7025
- * end
7026
- * P->>E: Emit clickEvent with direction and page
7027
- *
7028
- * @memberOf PaginationComponent
7029
- */
7030
- handleClick(direction, page) {
7031
- if (page)
7032
- this.current = page;
7033
- this.clickEvent.emit({
7034
- name: EventConstants.CLICK,
7035
- data: {
7036
- direction,
7037
- page: this.current
7038
- },
7039
- component: this.componentName
7040
- });
7041
- }
7042
- /**
7043
- * @description Generates the array of page objects for display.
7044
- * @summary Creates an array of page objects based on the total number of pages and
7045
- * the current page. For small page counts (≤5), all pages are shown. For larger page
7046
- * counts, a subset is shown with ellipses to indicate skipped pages. This ensures
7047
- * the pagination UI remains clean and usable even with many pages.
7048
- *
7049
- * @param {number} total - The total number of pages
7050
- * @param {number} [current] - The current active page (defaults to this.current)
7051
- * @returns {KeyValue[]} Array of page objects with index and text properties
7052
- *
7053
- * @mermaid
7054
- * flowchart TD
7055
- * A[Start] --> B{total <= 5?}
7056
- * B -->|Yes| C[Show all pages]
7057
- * B -->|No| D[Show first page]
7058
- * D --> E[Show last pages]
7059
- * E --> F[Add ellipses for skipped pages]
7060
- * C --> G[Return pages array]
7061
- * F --> G
7062
- *
7063
- * @memberOf PaginationComponent
7064
- */
7065
- getPages(total, current) {
7066
- if (!current)
7067
- current = this.current;
7068
- const pages = [];
7069
- function getPage(index, text = '', clazz = 'button') {
7070
- if (pages.some(item => item['index'] === index))
7071
- return;
7072
- pages.push({ index, text: index != null ? index.toString().padStart(2, '0') : text, class: clazz });
7073
- }
7074
- if (total <= 5) {
7075
- for (let i = 1; i <= total; i++)
7076
- getPage(i);
7077
- }
7078
- else {
7079
- // Adiciona os dois primeiros
7080
- getPage(1);
7081
- getPage(2);
7082
- // Adiciona "..." entre os blocos
7083
- if (current && current > 3)
7084
- getPage(null, '...');
7085
- // Adiciona a página atual (se estiver no meio)
7086
- if (current && current > 2 && current < total - 1)
7087
- getPage(current);
7088
- // Adiciona "..." entre os blocos
7089
- if (current && current < total - 2)
7090
- getPage(null, '...', 'separator');
7091
- // Adiciona os dois últimos
7092
- getPage(total - 1);
7093
- getPage(total);
7094
- }
7095
- return pages;
7096
- }
7097
- /**
7098
- * @description Gets the current active page number.
7099
- * @summary Returns the current page number that is active in the pagination component.
7100
- * This method provides a way to access the current page state from outside the component.
7101
- *
7102
- * @returns {number} The current page number
7103
- * @memberOf PaginationComponent
7104
- */
7105
- getCurrent() {
7106
- return this.current;
7107
- }
7108
- /**
7109
- * @description Navigates to the next page.
7110
- * @summary Increments the current page number if not at the last page and triggers
7111
- * the click event handler with 'next' direction. This method is typically called
7112
- * when the user clicks on the "next" button in the pagination UI.
7113
- *
7114
- * @returns {void}
7115
- *
7116
- * @mermaid
7117
- * sequenceDiagram
7118
- * participant U as User
7119
- * participant P as PaginationComponent
7120
- *
7121
- * U->>P: Click next button
7122
- * P->>P: next()
7123
- * alt page <= max pages
7124
- * P->>P: Increment current page
7125
- * P->>P: handleClick('next')
7126
- * end
7127
- *
7128
- * @memberOf PaginationComponent
7129
- */
7130
- next() {
7131
- const page = this.current + 1;
7132
- if (page <= Object.keys(this.pages)?.length || 0) {
7133
- this.current = page;
7134
- this.handleClick('next');
7135
- }
7136
- }
7137
- /**
7138
- * @description Navigates to the previous page.
7139
- * @summary Decrements the current page number if not at the first page and triggers
7140
- * the click event handler with 'previous' direction. This method is typically called
7141
- * when the user clicks on the "previous" button in the pagination UI.
7142
- *
7143
- * @returns {void}
7144
- *
7145
- * @mermaid
7146
- * sequenceDiagram
7147
- * participant U as User
7148
- * participant P as PaginationComponent
7149
- *
7150
- * U->>P: Click previous button
7151
- * P->>P: previous()
7152
- * alt page > 0
7153
- * P->>P: Decrement current page
7154
- * P->>P: handleClick('previous')
7155
- * end
7156
- *
7157
- * @memberOf PaginationComponent
7158
- */
7159
- previous() {
7160
- const page = this.current - 1;
7161
- if (page > 0) {
7162
- this.current = page;
7163
- this.handleClick('previous');
7164
- }
7165
- }
7166
- /**
7167
- * @description Navigates to a specific page number.
7168
- * @summary Updates the current page to the specified page number and triggers
7169
- * the click event handler with the appropriate direction. This method is typically
7170
- * called when the user clicks directly on a page number in the pagination UI.
7171
- *
7172
- * @param {number | null} page - The page number to navigate to
7173
- * @returns {void}
7174
- *
7175
- * @mermaid
7176
- * sequenceDiagram
7177
- * participant U as User
7178
- * participant P as PaginationComponent
7179
- *
7180
- * U->>P: Click page number
7181
- * P->>P: navigate(page)
7182
- * alt page is not null and different from current
7183
- * P->>P: Determine direction (next/previous)
7184
- * P->>P: handleClick(direction, page)
7185
- * end
7186
- *
7187
- * @memberOf PaginationComponent
7188
- */
7189
- navigate(page) {
7190
- if (page !== null && this.current !== page)
7191
- this.handleClick(page > this.current ? 'next' : 'previous', page);
7192
- }
7193
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PaginationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7194
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: PaginationComponent, isStandalone: true, selector: "ngx-decaf-pagination", inputs: { totalPages: "totalPages", current: "current" }, outputs: { clickEvent: "clickEvent" }, usesInheritance: true, ngImport: i0, template: " <div [id]=\"uid\" class=\"dcf-paginator-container dcf-flex dcf-flex-center\">\n <div class=\"dcf-width-1-1\">\n <div class=\"dcf-pagination-resume\" [innerHTML]=\"locale + '.resume' | translate: {value0: current, value1: last}\"></div>\n <div #paginationComponent class=\"dcf-pagination dcf-flex-center\">\n <div\n aria-label=\"previous\"\n tabindex=\"0\"\n (click)=\"previous()\"\n (keydown.enter)=\"previous()\" [class.dcf-disabled]=\"current === 1\">\n <ion-icon name=\"chevron-back-outline\" aria-hidden=\"true\"></ion-icon>\n </div>\n @for(page of pages; track page) {\n <div tabindex=\"0\" [class]=\"page['class']\" (click)=\"navigate(page['index'])\"\n (keydown.enter)=\"navigate(page['index'])\"\n [class.dcf-active]=\"current === page['index']\">\n <span class=\"page-item\">{{ page['text'] }}</span>\n </div>\n }\n <div\n tabindex=\"0\" (click)=\"next()\"\n (keydown.enter)=\"next()\"\n [class.dcf-disabled]=\"current === last\">\n <ion-icon name=\"chevron-forward-outline\" aria-hidden=\"true\"></ion-icon>\n </div>\n </div>\n </div>\n</div>\n", styles: [".dcf-paginator-container{margin-bottom:1rem}.dcf-pagination{display:flex;flex-wrap:wrap;align-items:center;margin-left:0;padding:0;list-style:none}.dcf-pagination .page-item{display:flex;justify-content:center;align-items:center;text-align:center;font-weight:600;width:34px;line-height:34px;padding:0!important;border-radius:50%;box-sizing:border-box}@media (prefers-color-scheme: dark){.dcf-pagination .page-item{color:var(--dcf-color-gray-3)!important}}@media (prefers-color-scheme: light){.dcf-pagination .page-item{color:var(--dcf-color-gray-7)!important}}.dcf-pagination>*{flex:none;padding-left:0;position:relative;margin:0px .15rem;cursor:pointer}.dcf-pagination>*.dcf-disabled{pointer-events:none;touch-action:none;cursor:text}.dcf-pagination>*.dcf-active{pointer-events:none;touch-action:none}@media (prefers-color-scheme: light){.dcf-pagination>*.dcf-active .page-item{background:rgba(var(--dcf-color-primary-rgb),.15)}.dcf-pagination>*:hover:not(.dcf-active) *{color:var(--dcf-color-primary)!important}}@media (prefers-color-scheme: dark){.dcf-pagination>*.dcf-active .page-item{background:var(--dcf-color-gray-7)}.dcf-pagination>*:hover:not(.dcf-active) *{color:var(--dcf-color-primary)!important}}.dcf-pagination-resume{margin:1rem 0px;text-align:center}@media (prefers-color-scheme: light){.dcf-pagination-resume{color:var(--dcf-color-gray-8)}}\n"], dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }] }); }
7195
- }
7196
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PaginationComponent, decorators: [{
7197
- type: Component,
7198
- args: [{ selector: 'ngx-decaf-pagination', imports: [
7199
- TranslatePipe,
7200
- IonIcon
7201
- ], standalone: true, template: " <div [id]=\"uid\" class=\"dcf-paginator-container dcf-flex dcf-flex-center\">\n <div class=\"dcf-width-1-1\">\n <div class=\"dcf-pagination-resume\" [innerHTML]=\"locale + '.resume' | translate: {value0: current, value1: last}\"></div>\n <div #paginationComponent class=\"dcf-pagination dcf-flex-center\">\n <div\n aria-label=\"previous\"\n tabindex=\"0\"\n (click)=\"previous()\"\n (keydown.enter)=\"previous()\" [class.dcf-disabled]=\"current === 1\">\n <ion-icon name=\"chevron-back-outline\" aria-hidden=\"true\"></ion-icon>\n </div>\n @for(page of pages; track page) {\n <div tabindex=\"0\" [class]=\"page['class']\" (click)=\"navigate(page['index'])\"\n (keydown.enter)=\"navigate(page['index'])\"\n [class.dcf-active]=\"current === page['index']\">\n <span class=\"page-item\">{{ page['text'] }}</span>\n </div>\n }\n <div\n tabindex=\"0\" (click)=\"next()\"\n (keydown.enter)=\"next()\"\n [class.dcf-disabled]=\"current === last\">\n <ion-icon name=\"chevron-forward-outline\" aria-hidden=\"true\"></ion-icon>\n </div>\n </div>\n </div>\n</div>\n", styles: [".dcf-paginator-container{margin-bottom:1rem}.dcf-pagination{display:flex;flex-wrap:wrap;align-items:center;margin-left:0;padding:0;list-style:none}.dcf-pagination .page-item{display:flex;justify-content:center;align-items:center;text-align:center;font-weight:600;width:34px;line-height:34px;padding:0!important;border-radius:50%;box-sizing:border-box}@media (prefers-color-scheme: dark){.dcf-pagination .page-item{color:var(--dcf-color-gray-3)!important}}@media (prefers-color-scheme: light){.dcf-pagination .page-item{color:var(--dcf-color-gray-7)!important}}.dcf-pagination>*{flex:none;padding-left:0;position:relative;margin:0px .15rem;cursor:pointer}.dcf-pagination>*.dcf-disabled{pointer-events:none;touch-action:none;cursor:text}.dcf-pagination>*.dcf-active{pointer-events:none;touch-action:none}@media (prefers-color-scheme: light){.dcf-pagination>*.dcf-active .page-item{background:rgba(var(--dcf-color-primary-rgb),.15)}.dcf-pagination>*:hover:not(.dcf-active) *{color:var(--dcf-color-primary)!important}}@media (prefers-color-scheme: dark){.dcf-pagination>*.dcf-active .page-item{background:var(--dcf-color-gray-7)}.dcf-pagination>*:hover:not(.dcf-active) *{color:var(--dcf-color-primary)!important}}.dcf-pagination-resume{margin:1rem 0px;text-align:center}@media (prefers-color-scheme: light){.dcf-pagination-resume{color:var(--dcf-color-gray-8)}}\n"] }]
7202
- }], ctorParameters: () => [], propDecorators: { totalPages: [{
7203
- type: Input,
7204
- args: [{ required: true }]
7205
- }], current: [{
7206
- type: Input
7207
- }], clickEvent: [{
7208
- type: Output
7209
- }] } });
7210
-
7211
- /**
7212
- * @description A versatile list component that supports various data display modes.
7213
- * @summary This component provides a flexible way to display lists of data with support
7214
- * for infinite scrolling, pagination, searching, and custom item rendering. It can fetch
7215
- * data from various sources including models, functions, or direct data input.
7216
- *
7217
- * The component supports two main display types:
7218
- * 1. Infinite scrolling - Loads more data as the user scrolls
7219
- * 2. Pagination - Displays data in pages with navigation controls
7220
- *
7221
- * Additional features include:
7222
- * - Pull-to-refresh functionality
7223
- * - Search filtering
7224
- * - Empty state customization
7225
- * - Custom item rendering
7226
- * - Event emission for interactions
7227
- *
7228
- * @mermaid
7229
- * sequenceDiagram
7230
- * participant U as User
7231
- * participant L as ListComponent
7232
- * participant D as Data Source
7233
- * participant E as External Components
7234
- *
7235
- * U->>L: Initialize component
7236
- * L->>L: ngOnInit()
7237
- * L->>D: Request initial data
7238
- * D-->>L: Return data
7239
- * L->>L: Process and display data
7240
- *
7241
- * alt User scrolls (Infinite mode)
7242
- * U->>L: Scroll to bottom
7243
- * L->>D: Request more data
7244
- * D-->>L: Return additional data
7245
- * L->>L: Append to existing data
7246
- * else User changes page (Paginated mode)
7247
- * U->>L: Click page number
7248
- * L->>L: handlePaginate()
7249
- * L->>D: Request data for page
7250
- * D-->>L: Return page data
7251
- * L->>L: Replace displayed data
7252
- * end
7253
- *
7254
- * alt User searches
7255
- * U->>L: Enter search term
7256
- * L->>L: handleSearch()
7257
- * L->>D: Filter data by search term
7258
- * D-->>L: Return filtered data
7259
- * L->>L: Update displayed data
7260
- * end
7261
- *
7262
- * alt User clicks item
7263
- * U->>L: Click list item
7264
- * L->>L: handleClick()
7265
- * L->>E: Emit clickEvent
7266
- * end
7267
- *
7268
- * @example
7269
- * <ngx-decaf-list
7270
- * [source]="dataSource"
7271
- * [limit]="10"
7272
- * [type]="'infinite'"
7273
- * [showSearchbar]="true"
7274
- * (clickEvent)="handleItemClick($event)"
7275
- * (refreshEvent)="handleRefresh($event)">
7276
- * </ngx-decaf-list>
7277
- *
7278
- * @extends {NgxBaseComponent}
7279
- * @implements {OnInit}
7280
- */
7281
- let ListComponent = class ListComponent extends NgxBaseComponent {
7282
- /**
7283
- * @description Initializes a new instance of the ListComponent.
7284
- * @summary Creates a new ListComponent and sets up the base component with the appropriate
7285
- * component name. This constructor is called when Angular instantiates the component and
7286
- * before any input properties are set. It passes the component name to the parent class
7287
- * constructor to enable proper localization and component identification.
7288
- *
7289
- * The constructor is intentionally minimal, with most initialization logic deferred to
7290
- * the ngOnInit lifecycle hook. This follows Angular best practices by keeping the constructor
7291
- * focused on dependency injection and basic setup, while complex initialization that depends
7292
- * on input properties is handled in ngOnInit.
7293
- *
7294
- * @memberOf ListComponent
7295
- */
7296
- constructor() {
7297
- super("ListComponent");
7298
- /**
7299
- * @description The display mode for the list component.
7300
- * @summary Determines how the list data is loaded and displayed. Options include:
7301
- * - INFINITE: Loads more data as the user scrolls (infinite scrolling)
7302
- * - PAGINATED: Displays data in pages with navigation controls
7303
- *
7304
- * @type {ListComponentsTypes}
7305
- * @default ListComponentsTypes.INFINITE
7306
- * @memberOf ListComponent
7307
- */
7308
- this.type = ListComponentsTypes.INFINITE;
7309
- /**
7310
- * @description Controls whether the component uses translation services.
7311
- * @summary When set to true, the component will attempt to use translation services
7312
- * for any text content. This allows for internationalization of the list component.
7313
- *
7314
- * @type {StringOrBoolean}
7315
- * @default true
7316
- * @memberOf ListComponent
7317
- */
7318
- this.translatable = true;
7319
- /**
7320
- * @description Controls the visibility of the search bar.
7321
- * @summary When set to true, displays a search bar at the top of the list that allows
7322
- * users to filter the list items. The search functionality works by filtering the
7323
- * existing data or by triggering a new data fetch with search parameters.
7324
- *
7325
- * @type {StringOrBoolean}
7326
- * @default true
7327
- * @memberOf ListComponent
7328
- */
7329
- this.showSearchbar = true;
7330
- /**
7331
- * @description Direct data input for the list component.
7332
- * @summary Provides a way to directly pass data to the list component instead of
7333
- * fetching it from a source. When both data and source are provided, the component
7334
- * will use the source to fetch data only if the data array is empty.
7335
- *
7336
- * @type {KeyValue[] | undefined}
7337
- * @default undefined
7338
- * @memberOf ListComponent
7339
- */
7340
- this.data = undefined;
7341
- /**
7342
- * @description The starting index for data fetching.
7343
- * @summary Specifies the index from which to start fetching data. This is used
7344
- * for pagination and infinite scrolling to determine which subset of data to load.
7345
- *
7346
- * @type {number}
7347
- * @default 0
7348
- * @memberOf ListComponent
7349
- */
7350
- this.start = 0;
7351
- /**
7352
- * @description The number of items to fetch per page or load operation.
7353
- * @summary Determines how many items are loaded at once during pagination or
7354
- * infinite scrolling. This affects the size of data chunks requested from the source.
7355
- *
7356
- * @type {number}
7357
- * @default 10
7358
- * @memberOf ListComponent
6955
+ * @type {number}
6956
+ * @default 10
6957
+ * @memberOf ListComponent
7359
6958
  */
7360
6959
  this.limit = 10;
7361
6960
  /**
@@ -7588,842 +7187,1221 @@ let ListComponent = class ListComponent extends NgxBaseComponent {
7588
7187
  */
7589
7188
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
7590
7189
  this.observerSubjet = new Subject();
7591
- /**
7592
- * @description Observer object for repository change notifications.
7593
- * @summary Implements the Observer interface to receive notifications when the
7594
- * underlying data repository changes. This enables automatic list updates when
7595
- * data is created, updated, or deleted through the repository.
7596
- *
7597
- * @private
7598
- * @type {Observer}
7599
- * @memberOf ListComponent
7600
- */
7190
+ }
7191
+ /**
7192
+ * @description Initializes the component after Angular sets the input properties.
7193
+ * @summary Sets up the component by initializing event subscriptions, processing boolean
7194
+ * inputs, and loading the initial data. This method prepares the component for user
7195
+ * interaction by ensuring all properties are properly initialized and data is loaded.
7196
+ *
7197
+ * @returns {Promise<void>}
7198
+ *
7199
+ * @mermaid
7200
+ * sequenceDiagram
7201
+ * participant A as Angular Lifecycle
7202
+ * participant L as ListComponent
7203
+ * participant D as Data Source
7204
+ *
7205
+ * A->>L: ngOnInit()
7206
+ * L->>L: Set up click event debouncing
7207
+ * L->>L: Process boolean inputs
7208
+ * L->>L: Configure component based on inputs
7209
+ * L->>L: refresh()
7210
+ * L->>D: Request initial data
7211
+ * D-->>L: Return data
7212
+ * L->>L: Process and display data
7213
+ * L->>L: Configure empty state if needed
7214
+ * L->>L: initialize()
7215
+ *
7216
+ * @memberOf ListComponent
7217
+ */
7218
+ async ngOnInit() {
7601
7219
  this.observer = { refresh: async (...args) => this.observeRepository(...args) };
7220
+ this.clickItemSubject.pipe(debounceTime(100)).subscribe(event => this.clickEventEmit(event));
7221
+ this.observerSubjet.pipe(debounceTime(100)).subscribe(args => this.handleObserveEvent(args[0], args[1], args[2]));
7222
+ this.enableFilter = stringToBoolean(this.enableFilter);
7223
+ this.limit = Number(this.limit);
7224
+ this.start = Number(this.start);
7225
+ this.inset = stringToBoolean(this.inset);
7226
+ this.showRefresher = stringToBoolean(this.showRefresher);
7227
+ this.loadMoreData = stringToBoolean(this.loadMoreData);
7228
+ this.showSearchbar = stringToBoolean(this.showSearchbar);
7229
+ this.disableSort = stringToBoolean(this.disableSort);
7230
+ if (typeof this.item?.['tag'] === 'boolean' && this.item?.['tag'] === true)
7231
+ this.item['tag'] = ComponentsTagNames.LIST_ITEM;
7232
+ await this.refresh();
7233
+ if (this.operations.includes(OperationKeys.CREATE) && this.route)
7234
+ this.empty.link = `${this.route}/${OperationKeys.CREATE}`;
7235
+ await this.initialize();
7236
+ if (this.model instanceof Model && this._repository)
7237
+ this._repository.observe(this.observer);
7238
+ }
7239
+ /**
7240
+ * @description Cleans up resources when the component is destroyed.
7241
+ * @summary Performs cleanup operations when the component is being removed from the DOM.
7242
+ * This includes clearing references to models and data to prevent memory leaks.
7243
+ *
7244
+ * @returns {void}
7245
+ * @memberOf ListComponent
7246
+ */
7247
+ ngOnDestroy() {
7248
+ if (this._repository)
7249
+ this._repository.unObserve(this.observer);
7250
+ this.data = this.model = this._repository = this.paginator = undefined;
7251
+ }
7252
+ /**
7253
+ * @description Handles repository observation events with debouncing.
7254
+ * @summary Processes repository change notifications and routes them appropriately.
7255
+ * For CREATE events with a UID, handles them immediately. For other events,
7256
+ * passes them to the debounced observer subject to prevent excessive updates.
7257
+ *
7258
+ * @param {...unknown[]} args - The repository event arguments including table, event type, and UID
7259
+ * @returns {Promise<void>}
7260
+ * @memberOf ListComponent
7261
+ */
7262
+ async observeRepository(...args) {
7263
+ const [table, event, uid] = args;
7264
+ if (event === OperationKeys.CREATE && !!uid)
7265
+ return this.handleObserveEvent(table, event, uid);
7266
+ return this.observerSubjet.next(args);
7267
+ }
7268
+ /**
7269
+ * @description Handles specific repository events and updates the list accordingly.
7270
+ * @summary Processes repository change events (CREATE, UPDATE, DELETE) and performs
7271
+ * the appropriate list operations. This includes adding new items, updating existing
7272
+ * ones, or removing deleted items from the list display.
7273
+ *
7274
+ * @param {string} table - The table/model name that changed
7275
+ * @param {OperationKeys} event - The type of operation (CREATE, UPDATE, DELETE)
7276
+ * @param {string | number} uid - The unique identifier of the affected item
7277
+ * @returns {Promise<void>}
7278
+ * @memberOf ListComponent
7279
+ */
7280
+ async handleObserveEvent(table, event, uid) {
7281
+ if (event === OperationKeys.CREATE) {
7282
+ if (uid) {
7283
+ await this.handleCreate(uid);
7284
+ }
7285
+ else {
7286
+ await this.refresh(true);
7287
+ }
7288
+ }
7289
+ else {
7290
+ if (event === OperationKeys.UPDATE)
7291
+ await this.handleUpdate(uid);
7292
+ if (event === OperationKeys.DELETE)
7293
+ this.handleDelete(uid);
7294
+ this.refreshEventEmit();
7295
+ }
7296
+ }
7297
+ /**
7298
+ * @description Function for tracking items in the list.
7299
+ * @summary Provides a tracking function for the `*ngFor` directive in the component template.
7300
+ * This function is used to identify and control the rendering of items in the list,
7301
+ * preventing duplicate or unnecessary rendering.
7302
+ *
7303
+ * The `trackItemFn` function takes two parameters: `index` (the index of the item in the list)
7304
+ * and `item` (the actual item from the list). It returns the tracking key, which in this case
7305
+ * is the union of the `uid` of the item with the model name.
7306
+ *
7307
+ * @param {number} index - The index of the item in the list.
7308
+
7309
+ * @param {KeyValue | string | number} item - The actual item from the list.
7310
+ * @returns {string | number} The tracking key for the item.
7311
+ * @memberOf ListComponent
7312
+ */
7313
+ trackItemFn(index, item) {
7314
+ return `${item?.['uid'] || item?.[this.pk]}-${index}`;
7315
+ }
7316
+ /**
7317
+ * Handles the create event from the repository.
7318
+ *
7319
+ * @param {string | number} uid - The ID of the item to create.
7320
+ * @returns {Promise<void>} A promise that resolves when the item is created and added to the list.
7321
+ */
7322
+ async handleCreate(uid) {
7323
+ const result = await this._repository?.read(uid);
7324
+ const item = this.mapResults([result])[0];
7325
+ this.items = this.data = [item, ...this.items || []];
7326
+ }
7327
+ /**
7328
+ * @description Handles the update event from the repository.
7329
+ * @summary Updates the list item with the specified ID based on the new data.
7330
+ *
7331
+ * @param {string | number} uid - The ID of the item to update
7332
+ * @returns {Promise<void>}
7333
+ * @private
7334
+ * @memberOf ListComponent
7335
+ */
7336
+ async handleUpdate(uid) {
7337
+ const item = this.itemMapper(await this._repository?.read(uid) || {}, this.mapper);
7338
+ this.data = [];
7339
+ for (const key in this.items) {
7340
+ const child = this.items[key];
7341
+ if (child['uid'] === item['uid']) {
7342
+ this.items[key] = Object.assign({}, child, item);
7343
+ break;
7344
+ }
7345
+ }
7346
+ setTimeout(() => {
7347
+ this.data = [...this.items];
7348
+ }, 0);
7349
+ }
7350
+ /**
7351
+ * @description Removes an item from the list by ID.
7352
+ * @summary Filters out an item with the specified ID from the data array and
7353
+ * refreshes the list display. This is typically used after a delete operation.
7354
+ *
7355
+ * @param {string} uid - The ID of the item to delete
7356
+ * @param {string} pk - The primary key field name
7357
+ * @returns {Promise<void>}
7358
+ *
7359
+ * @memberOf ListComponent
7360
+ */
7361
+ handleDelete(uid, pk) {
7362
+ if (!pk)
7363
+ pk = this.pk;
7364
+ this.items = this.data?.filter((item) => item['uid'] !== uid) || [];
7365
+ }
7366
+ /**
7367
+ * @description Handles click events from list items.
7368
+ * @summary Listens for global ListItemClickEvent events and passes them to the
7369
+ * debounced click subject. This allows the component to respond to clicks on
7370
+ * list items regardless of where they originate from.
7371
+ *
7372
+ * @param {ListItemCustomEvent | RendererCustomEvent} event - The click event
7373
+ * @returns {void}
7374
+ *
7375
+ * @memberOf ListComponent
7376
+ */
7377
+ handleClick(event) {
7378
+ this.clickItemSubject.next(event);
7602
7379
  }
7603
7380
  /**
7604
- * @description Initializes the component after Angular sets the input properties.
7605
- * @summary Sets up the component by initializing event subscriptions, processing boolean
7606
- * inputs, and loading the initial data. This method prepares the component for user
7607
- * interaction by ensuring all properties are properly initialized and data is loaded.
7381
+ * @description Handles search events from the search bar.
7382
+ * @summary Processes search queries from the search bar component, updating the
7383
+ * displayed data based on the search term. The behavior differs between infinite
7384
+ * and paginated modes to provide the best user experience for each mode.
7608
7385
  *
7386
+ * @param {string | undefined} value - The search term or undefined to clear search
7609
7387
  * @returns {Promise<void>}
7610
7388
  *
7611
7389
  * @mermaid
7612
- * sequenceDiagram
7613
- * participant A as Angular Lifecycle
7614
- * participant L as ListComponent
7615
- * participant D as Data Source
7390
+ * flowchart TD
7391
+ * A[Search Event] --> B{Type is Infinite?}
7392
+ * B -->|Yes| C[Disable loadMoreData]
7393
+ * B -->|No| D[Enable loadMoreData]
7394
+ * C --> E{Search value undefined?}
7395
+ * E -->|Yes| F[Enable loadMoreData]
7396
+ * E -->|No| G[Store search value]
7397
+ * D --> G
7398
+ * F --> H[Reset page to 1]
7399
+ * G --> I[Refresh data]
7400
+ * H --> I
7616
7401
  *
7617
- * A->>L: ngOnInit()
7618
- * L->>L: Set up click event debouncing
7619
- * L->>L: Process boolean inputs
7620
- * L->>L: Configure component based on inputs
7621
- * L->>L: refresh()
7622
- * L->>D: Request initial data
7623
- * D-->>L: Return data
7624
- * L->>L: Process and display data
7625
- * L->>L: Configure empty state if needed
7626
- * L->>L: initialize()
7402
+ * @memberOf ListComponent
7403
+ */
7404
+ async handleSearch(value) {
7405
+ if (this.type === ListComponentsTypes.INFINITE) {
7406
+ this.loadMoreData = false;
7407
+ if (value === undefined) {
7408
+ this.loadMoreData = true;
7409
+ this.page = 1;
7410
+ }
7411
+ this.searchValue = value;
7412
+ await this.refresh(true);
7413
+ }
7414
+ else {
7415
+ this.loadMoreData = true;
7416
+ this.searchValue = value;
7417
+ if (value === undefined)
7418
+ this.page = this.lastPage;
7419
+ await this.refresh(true);
7420
+ }
7421
+ }
7422
+ /**
7423
+ * @description Handles filter events from the filter component.
7424
+ * @summary Processes filter queries from the filter component and applies them
7425
+ * to the list data. This method acts as a bridge between the filter component
7426
+ * and the search functionality, converting filter queries into search operations.
7427
+ *
7428
+ * @param {IFilterQuery | undefined} value - The filter query object or undefined to clear filters
7429
+ * @returns {Promise<void>}
7430
+ * @memberOf ListComponent
7431
+ */
7432
+ async handleFilter(value) {
7433
+ await this.handleSearch(value);
7434
+ }
7435
+ /**
7436
+ * @description Clears the current search and resets the list.
7437
+ * @summary Convenience method that clears the search by calling handleSearch
7438
+ * with undefined. This resets the list to show all data without filtering.
7627
7439
  *
7440
+ * @returns {Promise<void>}
7628
7441
  * @memberOf ListComponent
7629
7442
  */
7630
- async ngOnInit() {
7631
- this.clickItemSubject.pipe(debounceTime(100)).subscribe(event => this.clickEventEmit(event));
7632
- this.observerSubjet.pipe(debounceTime(100)).subscribe(args => this.handleObserveEvent(args[0], args[1], args[2]));
7633
- this.enableFilter = stringToBoolean(this.enableFilter);
7634
- this.limit = Number(this.limit);
7635
- this.start = Number(this.start);
7636
- this.inset = stringToBoolean(this.inset);
7637
- this.showRefresher = stringToBoolean(this.showRefresher);
7638
- this.loadMoreData = stringToBoolean(this.loadMoreData);
7639
- this.showSearchbar = stringToBoolean(this.showSearchbar);
7640
- this.disableSort = stringToBoolean(this.disableSort);
7641
- if (typeof this.item?.['tag'] === 'boolean' && this.item?.['tag'] === true)
7642
- this.item['tag'] = ComponentsTagNames.LIST_ITEM;
7643
- await this.refresh();
7644
- if (this.operations.includes(OperationKeys.CREATE) && this.route)
7645
- this.empty.link = `${this.route}/${OperationKeys.CREATE}`;
7646
- await this.initialize();
7647
- if (this.model instanceof Model && this._repository)
7648
- this._repository.observe(this.observer);
7443
+ async clearSearch() {
7444
+ await this.handleSearch(undefined);
7649
7445
  }
7650
7446
  /**
7651
- * @description Cleans up resources when the component is destroyed.
7652
- * @summary Performs cleanup operations when the component is being removed from the DOM.
7653
- * This includes clearing references to models and data to prevent memory leaks.
7447
+ * @description Emits a refresh event with the current data.
7448
+ * @summary Creates and emits a refresh event containing the current list data.
7449
+ * This notifies parent components that the list data has been refreshed.
7654
7450
  *
7451
+ * @param {KeyValue[]} [data] - Optional data to include in the event
7655
7452
  * @returns {void}
7453
+ *
7656
7454
  * @memberOf ListComponent
7657
7455
  */
7658
- ngOnDestroy() {
7659
- if (this._repository)
7660
- this._repository.unObserve(this.observer);
7661
- this.data = this.model = this._repository = this.paginator = undefined;
7456
+ refreshEventEmit(data) {
7457
+ if (!data)
7458
+ data = this.items;
7459
+ this.skeletonData = new Array(data?.length || 2);
7460
+ this.refreshEvent.emit({
7461
+ name: EventConstants.REFRESH,
7462
+ data: data || [],
7463
+ component: this.componentName
7464
+ });
7662
7465
  }
7663
7466
  /**
7664
- * @description Handles repository observation events with debouncing.
7665
- * @summary Processes repository change notifications and routes them appropriately.
7666
- * For CREATE events with a UID, handles them immediately. For other events,
7667
- * passes them to the debounced observer subject to prevent excessive updates.
7467
+ * @description Emits a click event for a list item.
7468
+ * @summary Processes and emits a click event when a list item is clicked.
7469
+ * This extracts the relevant data from the event and passes it to parent components.
7470
+ *
7471
+ * @private
7472
+ * @param {ListItemCustomEvent | RendererCustomEvent} event - The click event
7473
+ * @returns {void}
7668
7474
  *
7669
- * @param {...unknown[]} args - The repository event arguments including table, event type, and UID
7670
- * @returns {Promise<void>}
7671
7475
  * @memberOf ListComponent
7672
7476
  */
7673
- async observeRepository(...args) {
7674
- const [table, event, uid] = args;
7675
- if (event === OperationKeys.CREATE && !!uid)
7676
- return this.handleObserveEvent(table, event, uid);
7677
- return this.observerSubjet.next(args);
7477
+ clickEventEmit(event) {
7478
+ this.clickEvent.emit(event);
7678
7479
  }
7679
7480
  /**
7680
- * @description Handles specific repository events and updates the list accordingly.
7681
- * @summary Processes repository change events (CREATE, UPDATE, DELETE) and performs
7682
- * the appropriate list operations. This includes adding new items, updating existing
7683
- * ones, or removing deleted items from the list display.
7481
+ * @description Refreshes the list data from the configured source.
7482
+ * @summary This method handles both initial data loading and subsequent refresh operations,
7483
+ * including pull-to-refresh and infinite scrolling. It manages the data fetching process,
7484
+ * updates the component's state, and handles pagination or infinite scrolling logic based
7485
+ * on the component's configuration.
7486
+ *
7487
+ * The method performs the following steps:
7488
+ * 1. Sets the refreshing flag to indicate a data fetch is in progress
7489
+ * 2. Calculates the appropriate start and limit values based on pagination settings
7490
+ * 3. Fetches data from the appropriate source (model or request)
7491
+ * 4. Updates the component's data and emits a refresh event
7492
+ * 5. Handles pagination or infinite scrolling state updates
7493
+ * 6. Completes any provided event (like InfiniteScrollCustomEvent)
7494
+ *
7495
+ * @param {InfiniteScrollCustomEvent | RefresherCustomEvent | boolean} event - The event that triggered the refresh,
7496
+ * or a boolean flag indicating if this is a forced refresh
7497
+ * @returns {Promise<void>} A promise that resolves when the refresh operation is complete
7498
+ *
7499
+ * @mermaid
7500
+ * sequenceDiagram
7501
+ * participant L as ListComponent
7502
+ * participant D as Data Source
7503
+ * participant E as Event System
7504
+ *
7505
+ * L->>L: refresh(event)
7506
+ * L->>L: Set refreshing flag
7507
+ * L->>L: Calculate start and limit
7508
+ * alt Using model
7509
+ * L->>D: getFromModel(force, start, limit)
7510
+ * D-->>L: Return data
7511
+ * else Using request
7512
+ * L->>D: getFromRequest(force, start, limit)
7513
+ * D-->>L: Return data
7514
+ * end
7515
+ * L->>E: refreshEventEmit()
7516
+ * alt Infinite scrolling mode
7517
+ * L->>L: Check if reached last page
7518
+ * alt Last page reached
7519
+ * L->>L: Complete scroll event
7520
+ * L->>L: Disable loadMoreData
7521
+ * else More pages available
7522
+ * L->>L: Increment page number
7523
+ * L->>L: Complete scroll event after delay
7524
+ * end
7525
+ * else Paginated mode
7526
+ * L->>L: Clear refreshing flag after delay
7527
+ * end
7684
7528
  *
7685
- * @param {string} table - The table/model name that changed
7686
- * @param {OperationKeys} event - The type of operation (CREATE, UPDATE, DELETE)
7687
- * @param {string | number} uid - The unique identifier of the affected item
7688
- * @returns {Promise<void>}
7689
7529
  * @memberOf ListComponent
7690
7530
  */
7691
- async handleObserveEvent(table, event, uid) {
7692
- if (event === OperationKeys.CREATE) {
7693
- if (uid) {
7694
- await this.handleCreate(uid);
7531
+ async refresh(event = false) {
7532
+ // if(typeof force !== 'boolean' && force.type === EventConstants.BACK_BUTTON_NAVIGATION) {
7533
+ // const {refresh} = (force as CustomEvent).detail;
7534
+ // if(!refresh)
7535
+ // return false;
7536
+ // }
7537
+ this.refreshing = true;
7538
+ const start = this.page > 1 ? (this.page - 1) * this.limit : this.start;
7539
+ const limit = (this.page * (this.limit > 12 ? 12 : this.limit));
7540
+ this.data = !this.model ?
7541
+ await this.getFromRequest(!!event, start, limit)
7542
+ : await this.getFromModel(!!event);
7543
+ this.refreshEventEmit();
7544
+ if (this.type === ListComponentsTypes.INFINITE) {
7545
+ if (this.page === this.pages) {
7546
+ if (event?.target)
7547
+ event.target.complete();
7548
+ this.loadMoreData = false;
7695
7549
  }
7696
7550
  else {
7697
- await this.refresh(true);
7551
+ this.page += 1;
7552
+ this.refreshing = false;
7553
+ setTimeout(() => {
7554
+ if (event?.target && event?.type !== EventConstants.BACK_BUTTON_NAVIGATION)
7555
+ event.target.complete();
7556
+ }, 200);
7698
7557
  }
7699
7558
  }
7700
7559
  else {
7701
- if (event === OperationKeys.UPDATE)
7702
- await this.handleUpdate(uid);
7703
- if (event === OperationKeys.DELETE)
7704
- this.handleDelete(uid);
7705
- this.refreshEventEmit();
7560
+ setTimeout(() => {
7561
+ this.refreshing = false;
7562
+ }, 200);
7706
7563
  }
7707
7564
  }
7708
7565
  /**
7709
- * @description Function for tracking items in the list.
7710
- * @summary Provides a tracking function for the `*ngFor` directive in the component template.
7711
- * This function is used to identify and control the rendering of items in the list,
7712
- * preventing duplicate or unnecessary rendering.
7713
- *
7714
- * The `trackItemFn` function takes two parameters: `index` (the index of the item in the list)
7715
- * and `item` (the actual item from the list). It returns the tracking key, which in this case
7716
- * is the union of the `uid` of the item with the model name.
7717
- *
7718
- * @param {number} index - The index of the item in the list.
7719
-
7720
- * @param {KeyValue | string | number} item - The actual item from the list.
7721
- * @returns {string | number} The tracking key for the item.
7722
- * @memberOf ListComponent
7723
- */
7724
- trackItemFn(index, item) {
7725
- return `${item?.['uid'] || item?.[this.pk]}-${index}`;
7566
+ * @description Handles pagination events from the pagination component.
7567
+ * @summary Processes pagination events by updating the current page number and
7568
+ * refreshing the list data to display the selected page. This method is called
7569
+ * when a user interacts with the pagination controls to navigate between pages.
7570
+ *
7571
+ * @param {PaginationCustomEvent} event - The pagination event containing page information
7572
+ * @returns {void}
7573
+ *
7574
+ * @memberOf ListComponent
7575
+ */
7576
+ handlePaginate(event) {
7577
+ const { page } = event.data;
7578
+ this.page = page;
7579
+ this.refresh(true);
7726
7580
  }
7727
7581
  /**
7728
- * Handles the create event from the repository.
7582
+ * @description Handles pull-to-refresh events from the refresher component.
7583
+ * @summary Processes refresh events triggered by the user pulling down on the list
7584
+ * or by programmatic refresh requests. This method refreshes the list data and
7585
+ * completes the refresher animation when the data is loaded.
7729
7586
  *
7730
- * @param {string | number} uid - The ID of the item to create.
7731
- * @returns {Promise<void>} A promise that resolves when the item is created and added to the list.
7732
- */
7733
- async handleCreate(uid) {
7734
- const result = await this._repository?.read(uid);
7735
- const item = this.mapResults([result])[0];
7736
- this.items = this.data = [item, ...this.items || []];
7737
- }
7738
- /**
7739
- * @description Handles the update event from the repository.
7740
- * @summary Updates the list item with the specified ID based on the new data.
7587
+ * @param {InfiniteScrollCustomEvent | CustomEvent} [event] - The refresh event
7588
+ * @returns {Promise<void>} A promise that resolves when the refresh operation is complete
7741
7589
  *
7742
- * @param {string | number} uid - The ID of the item to update
7743
- * @returns {Promise<void>}
7744
- * @private
7745
7590
  * @memberOf ListComponent
7746
7591
  */
7747
- async handleUpdate(uid) {
7748
- const item = this.itemMapper(await this._repository?.read(uid) || {}, this.mapper);
7749
- this.data = [];
7750
- for (const key in this.items) {
7751
- const child = this.items[key];
7752
- if (child['uid'] === item['uid']) {
7753
- this.items[key] = Object.assign({}, child, item);
7754
- break;
7755
- }
7756
- }
7757
- setTimeout(() => {
7758
- this.data = [...this.items];
7759
- }, 0);
7592
+ async handleRefresh(event) {
7593
+ await this.refresh(event || true);
7594
+ if (event instanceof CustomEvent)
7595
+ setTimeout(() => {
7596
+ // Any calls to load data go here
7597
+ event.target.complete();
7598
+ }, 400);
7760
7599
  }
7761
7600
  /**
7762
- * @description Removes an item from the list by ID.
7763
- * @summary Filters out an item with the specified ID from the data array and
7764
- * refreshes the list display. This is typically used after a delete operation.
7601
+ * @description Filters data based on a search string.
7602
+ * @summary Processes the current data array to find items that match the provided
7603
+ * search string. This uses the arrayQueryByString utility to perform the filtering
7604
+ * across all properties of the items.
7765
7605
  *
7766
- * @param {string} uid - The ID of the item to delete
7767
- * @param {string} pk - The primary key field name
7768
- * @returns {Promise<void>}
7606
+ * @param {KeyValue[]} results - The array of items to search through
7607
+ * @param {string} search - The search string to filter by
7608
+ * @returns {KeyValue[]} A promise that resolves to the filtered array of items
7769
7609
  *
7770
7610
  * @memberOf ListComponent
7771
7611
  */
7772
- handleDelete(uid, pk) {
7773
- if (!pk)
7774
- pk = this.pk;
7775
- this.items = this.data?.filter((item) => item['uid'] !== uid) || [];
7612
+ parseSearchResults(results, search) {
7613
+ return results.filter((item) => Object.values(item).some(value => value.toString().toLowerCase().includes(search?.toLowerCase())));
7776
7614
  }
7777
7615
  /**
7778
- * @description Handles click events from list items.
7779
- * @summary Listens for global ListItemClickEvent events and passes them to the
7780
- * debounced click subject. This allows the component to respond to clicks on
7781
- * list items regardless of where they originate from.
7616
+ * @description Fetches data from a request source.
7617
+ * @summary Retrieves data from the configured source function or URL, processes it,
7618
+ * and updates the component's data state. This method handles both initial data loading
7619
+ * and subsequent refresh operations when using an external data source rather than a model.
7782
7620
  *
7783
- * @param {ListItemCustomEvent | RendererCustomEvent} event - The click event
7784
- * @returns {void}
7621
+ * @param {boolean} force - Whether to force a refresh even if data already exists
7622
+ * @param {number} start - The starting index for pagination
7623
+ * @param {number} limit - The maximum number of items to retrieve
7624
+ * @returns {Promise<KeyValue[]>} A promise that resolves to the fetched data
7785
7625
  *
7786
7626
  * @memberOf ListComponent
7787
7627
  */
7788
- handleClick(event) {
7789
- this.clickItemSubject.next(event);
7628
+ async getFromRequest(force = false, start, limit) {
7629
+ let request = [];
7630
+ if (!this.data?.length || force || this.searchValue?.length || !!this.searchValue) {
7631
+ // (self.data as ListItem[]) = [];
7632
+ if (!this.searchValue?.length && !this.searchValue) {
7633
+ if (!this.source && !this.data?.length) {
7634
+ this.logger.info('No data and source passed to infinite list');
7635
+ return [];
7636
+ }
7637
+ if (this.source instanceof Function)
7638
+ request = await this.source();
7639
+ if (!Array.isArray(request))
7640
+ request = request?.['response']?.['data'] || request?.['results'] || [];
7641
+ this.data = [...await this.parseResult(request)];
7642
+ if (this.data?.length)
7643
+ this.items = this.type === ListComponentsTypes.INFINITE ?
7644
+ (this.items || []).concat([...this.data.slice(start, limit)]) : [...request.slice(start, limit)];
7645
+ }
7646
+ else {
7647
+ this.data = this.parseSearchResults(this.data, this.searchValue);
7648
+ this.items = this.data;
7649
+ }
7650
+ }
7651
+ if (this.loadMoreData && this.type === ListComponentsTypes.PAGINATED)
7652
+ this.getMoreData(this.data?.length || 0);
7653
+ return this.data || [];
7790
7654
  }
7791
7655
  /**
7792
- * @description Handles search events from the search bar.
7793
- * @summary Processes search queries from the search bar component, updating the
7794
- * displayed data based on the search term. The behavior differs between infinite
7795
- * and paginated modes to provide the best user experience for each mode.
7796
- *
7797
- * @param {string | undefined} value - The search term or undefined to clear search
7798
- * @returns {Promise<void>}
7656
+ * @description Fetches data from a model source.
7657
+ * @summary Retrieves data from the configured model using its pagination or find methods,
7658
+ * processes it, and updates the component's data state. This method handles both initial
7659
+ * data loading and subsequent refresh operations when using a model as the data source.
7799
7660
  *
7800
- * @mermaid
7801
- * flowchart TD
7802
- * A[Search Event] --> B{Type is Infinite?}
7803
- * B -->|Yes| C[Disable loadMoreData]
7804
- * B -->|No| D[Enable loadMoreData]
7805
- * C --> E{Search value undefined?}
7806
- * E -->|Yes| F[Enable loadMoreData]
7807
- * E -->|No| G[Store search value]
7808
- * D --> G
7809
- * F --> H[Reset page to 1]
7810
- * G --> I[Refresh data]
7811
- * H --> I
7661
+ * @param {boolean} force - Whether to force a refresh even if data already exists
7662
+ * @param {number} start - The starting index for pagination
7663
+ * @param {number} limit - The maximum number of items to retrieve
7664
+ * @returns {Promise<KeyValue[]>} A promise that resolves to the fetched data
7812
7665
  *
7813
7666
  * @memberOf ListComponent
7814
7667
  */
7815
- async handleSearch(value) {
7816
- if (this.type === ListComponentsTypes.INFINITE) {
7817
- this.loadMoreData = false;
7818
- if (value === undefined) {
7819
- this.loadMoreData = true;
7820
- this.page = 1;
7668
+ async getFromModel(force = false) {
7669
+ let data = [...this.data || []];
7670
+ let request = [];
7671
+ // getting model repository
7672
+ if (!this._repository)
7673
+ this._repository = this.repository;
7674
+ const repo = this._repository;
7675
+ if (!this.data?.length || force || this.searchValue?.length || !!this.searchValue) {
7676
+ try {
7677
+ if (!this.searchValue?.length && !this.searchValue) {
7678
+ this.data = [];
7679
+ // const rawQuery = this.parseQuery(self.model as Repository<Model>, start, limit);
7680
+ // request = this.parseResult(await (this.model as any)?.paginate(start, limit));
7681
+ if (!this.paginator) {
7682
+ this.paginator = await repo
7683
+ .select()
7684
+ .orderBy([this.pk, this.sortDirection])
7685
+ .paginate(this.limit);
7686
+ }
7687
+ request = await this.parseResult(this.paginator);
7688
+ }
7689
+ else {
7690
+ if (!this.indexes)
7691
+ this.indexes = (Object.values(this.mapper) || [this.pk]);
7692
+ const condition = this.parseConditions(this.searchValue);
7693
+ request = await this.parseResult(await repo.query(condition, (this.sortBy || this.pk), this.sortDirection));
7694
+ data = [];
7695
+ }
7696
+ data = this.type === ListComponentsTypes.INFINITE ? [...(data).concat(request)] : [...request];
7697
+ }
7698
+ catch (error) {
7699
+ this.logger.error(error?.message || `Unable to find ${this.model} on registry. Return empty array from component`);
7821
7700
  }
7822
- this.searchValue = value;
7823
- await this.refresh(true);
7824
7701
  }
7825
- else {
7826
- this.loadMoreData = true;
7827
- this.searchValue = value;
7828
- if (value === undefined)
7829
- this.page = this.lastPage;
7830
- await this.refresh(true);
7702
+ if (data?.length) {
7703
+ if (this.searchValue) {
7704
+ this.items = [...data];
7705
+ if (this.items?.length <= this.limit)
7706
+ this.loadMoreData = false;
7707
+ }
7708
+ else {
7709
+ this.items = [...data];
7710
+ }
7831
7711
  }
7712
+ if (this.type === ListComponentsTypes.PAGINATED && this.paginator)
7713
+ this.getMoreData(this.paginator.total);
7714
+ return data || [];
7832
7715
  }
7833
7716
  /**
7834
- * @description Handles filter events from the filter component.
7835
- * @summary Processes filter queries from the filter component and applies them
7836
- * to the list data. This method acts as a bridge between the filter component
7837
- * and the search functionality, converting filter queries into search operations.
7717
+ * @description Converts search values or filter queries into database conditions.
7718
+ * @summary Transforms search input or complex filter queries into Condition objects
7719
+ * that can be used for database querying. Handles both simple string/number searches
7720
+ * across indexed fields and complex filter queries with multiple criteria.
7838
7721
  *
7839
- * @param {IFilterQuery | undefined} value - The filter query object or undefined to clear filters
7840
- * @returns {Promise<void>}
7841
- * @memberOf ListComponent
7842
- */
7843
- async handleFilter(value) {
7844
- await this.handleSearch(value);
7845
- }
7846
- /**
7847
- * @description Clears the current search and resets the list.
7848
- * @summary Convenience method that clears the search by calling handleSearch
7849
- * with undefined. This resets the list to show all data without filtering.
7722
+ * For simple searches (string/number):
7723
+ * - Creates conditions that search across all indexed fields
7724
+ * - Uses equality for numeric values and regex for string values
7725
+ * - Combines conditions with OR logic to search multiple fields
7850
7726
  *
7851
- * @returns {Promise<void>}
7727
+ * For complex filter queries:
7728
+ * - Processes each filter item with its specific condition type
7729
+ * - Supports Equal, Not Equal, Contains, Not Contains, Greater Than, Less Than
7730
+ * - Updates sort configuration based on the filter query
7731
+ * - Combines multiple filter conditions with OR logic
7732
+ *
7733
+ * @param {string | number | IFilterQuery} value - The search value or filter query object
7734
+ * @returns {Condition<Model>} A Condition object for database querying
7852
7735
  * @memberOf ListComponent
7853
7736
  */
7854
- async clearSearch() {
7855
- await this.handleSearch(undefined);
7737
+ parseConditions(value) {
7738
+ let _condition;
7739
+ if (typeof value === Primitives.STRING || typeof value === Primitives.NUMBER) {
7740
+ _condition = Condition.attribute(this.pk).eq(!isNaN(value) ? Number(value) : value);
7741
+ for (const index of this.indexes) {
7742
+ if (index === this.pk)
7743
+ continue;
7744
+ let orCondition;
7745
+ if (!isNaN(value)) {
7746
+ orCondition = Condition.attribute(index).eq(Number(value));
7747
+ }
7748
+ else {
7749
+ orCondition = Condition.attribute(index).regexp(value);
7750
+ }
7751
+ _condition = _condition.or(orCondition);
7752
+ }
7753
+ }
7754
+ else {
7755
+ const { query, sort } = value;
7756
+ _condition = Condition.attribute(this.pk).dif('null');
7757
+ if (query?.length)
7758
+ _condition = undefined;
7759
+ (query || []).forEach((item) => {
7760
+ const { value, condition, index } = item;
7761
+ let val = value;
7762
+ if (index === this.pk || !isNaN(val))
7763
+ val = Number(val);
7764
+ let orCondition;
7765
+ switch (condition) {
7766
+ case "Equal":
7767
+ orCondition = Condition.attribute(index).eq(val);
7768
+ break;
7769
+ case "Not Equal":
7770
+ orCondition = Condition.attribute(index).dif(val);
7771
+ break;
7772
+ case "Not Contains":
7773
+ orCondition = !Condition.attribute(index).regexp(new RegExp(`^(?!.*${val}).*$`));
7774
+ break;
7775
+ case "Contains":
7776
+ orCondition = Condition.attribute(index).regexp(val);
7777
+ break;
7778
+ case "Greater Than":
7779
+ orCondition = Condition.attribute(index).gte(val);
7780
+ break;
7781
+ case "Less Than":
7782
+ orCondition = Condition.attribute(index).lte(val);
7783
+ break;
7784
+ }
7785
+ _condition = (!_condition ?
7786
+ orCondition : _condition.and(orCondition));
7787
+ });
7788
+ this.sortBy = sort?.value || this.pk;
7789
+ this.sortDirection = sort?.direction || this.sortDirection;
7790
+ }
7791
+ return _condition;
7856
7792
  }
7857
7793
  /**
7858
- * @description Emits a refresh event with the current data.
7859
- * @summary Creates and emits a refresh event containing the current list data.
7860
- * This notifies parent components that the list data has been refreshed.
7794
+ * @description Processes query results into a standardized format.
7795
+ * @summary Handles different result formats from various data sources, extracting
7796
+ * pagination information when available and applying any configured data mapping.
7797
+ * This ensures consistent data structure regardless of the source.
7861
7798
  *
7862
- * @param {KeyValue[]} [data] - Optional data to include in the event
7863
- * @returns {void}
7799
+ * @protected
7800
+ * @param {KeyValue[] | Paginator} result - The raw query result
7801
+ * @returns {KeyValue[]} The processed array of items
7864
7802
  *
7865
7803
  * @memberOf ListComponent
7866
7804
  */
7867
- refreshEventEmit(data) {
7868
- if (!data)
7869
- data = this.items;
7870
- this.skeletonData = new Array(data?.length || 2);
7871
- this.refreshEvent.emit({
7872
- name: EventConstants.REFRESH,
7873
- data: data || [],
7874
- component: this.componentName
7875
- });
7805
+ async parseResult(result) {
7806
+ if (!Array.isArray(result) && ('page' in result && 'total' in result)) {
7807
+ const paginator = result;
7808
+ try {
7809
+ result = await paginator.page(this.page);
7810
+ // TODO: Chage for result.total;
7811
+ this.getMoreData(paginator.total);
7812
+ }
7813
+ catch (error) {
7814
+ this.logger.info(error?.message || 'Unable to get page from paginator. Return empty array from component');
7815
+ result = [];
7816
+ }
7817
+ }
7818
+ else {
7819
+ this.getMoreData(result?.length || 0);
7820
+ }
7821
+ return (Object.keys(this.mapper || {}).length) ?
7822
+ this.mapResults(result) : result;
7876
7823
  }
7877
7824
  /**
7878
- * @description Emits a click event for a list item.
7879
- * @summary Processes and emits a click event when a list item is clicked.
7880
- * This extracts the relevant data from the event and passes it to parent components.
7825
+ * @description Updates pagination state based on data length.
7826
+ * @summary Calculates whether more data is available and how many pages exist
7827
+ * based on the total number of items and the configured limit per page.
7828
+ * This information is used to control pagination UI and infinite scrolling behavior.
7881
7829
  *
7882
- * @private
7883
- * @param {ListItemCustomEvent | RendererCustomEvent} event - The click event
7830
+ * @param {number} length - The total number of items available
7884
7831
  * @returns {void}
7885
7832
  *
7886
7833
  * @memberOf ListComponent
7887
7834
  */
7888
- clickEventEmit(event) {
7889
- this.clickEvent.emit(event);
7890
- }
7891
- /**
7892
- * @description Refreshes the list data from the configured source.
7893
- * @summary This method handles both initial data loading and subsequent refresh operations,
7894
- * including pull-to-refresh and infinite scrolling. It manages the data fetching process,
7895
- * updates the component's state, and handles pagination or infinite scrolling logic based
7896
- * on the component's configuration.
7897
- *
7898
- * The method performs the following steps:
7899
- * 1. Sets the refreshing flag to indicate a data fetch is in progress
7900
- * 2. Calculates the appropriate start and limit values based on pagination settings
7901
- * 3. Fetches data from the appropriate source (model or request)
7902
- * 4. Updates the component's data and emits a refresh event
7903
- * 5. Handles pagination or infinite scrolling state updates
7904
- * 6. Completes any provided event (like InfiniteScrollCustomEvent)
7905
- *
7906
- * @param {InfiniteScrollCustomEvent | RefresherCustomEvent | boolean} event - The event that triggered the refresh,
7907
- * or a boolean flag indicating if this is a forced refresh
7908
- * @returns {Promise<void>} A promise that resolves when the refresh operation is complete
7909
- *
7910
- * @mermaid
7911
- * sequenceDiagram
7912
- * participant L as ListComponent
7913
- * participant D as Data Source
7914
- * participant E as Event System
7915
- *
7916
- * L->>L: refresh(event)
7917
- * L->>L: Set refreshing flag
7918
- * L->>L: Calculate start and limit
7919
- * alt Using model
7920
- * L->>D: getFromModel(force, start, limit)
7921
- * D-->>L: Return data
7922
- * else Using request
7923
- * L->>D: getFromRequest(force, start, limit)
7924
- * D-->>L: Return data
7925
- * end
7926
- * L->>E: refreshEventEmit()
7927
- * alt Infinite scrolling mode
7928
- * L->>L: Check if reached last page
7929
- * alt Last page reached
7930
- * L->>L: Complete scroll event
7931
- * L->>L: Disable loadMoreData
7932
- * else More pages available
7933
- * L->>L: Increment page number
7934
- * L->>L: Complete scroll event after delay
7935
- * end
7936
- * else Paginated mode
7937
- * L->>L: Clear refreshing flag after delay
7938
- * end
7939
- *
7940
- * @memberOf ListComponent
7941
- */
7942
- async refresh(event = false) {
7943
- // if(typeof force !== 'boolean' && force.type === EventConstants.BACK_BUTTON_NAVIGATION) {
7944
- // const {refresh} = (force as CustomEvent).detail;
7945
- // if(!refresh)
7946
- // return false;
7947
- // }
7948
- this.refreshing = true;
7949
- const start = this.page > 1 ? (this.page - 1) * this.limit : this.start;
7950
- const limit = (this.page * (this.limit > 12 ? 12 : this.limit));
7951
- this.data = !this.model ?
7952
- await this.getFromRequest(!!event, start, limit)
7953
- : await this.getFromModel(!!event);
7954
- this.refreshEventEmit();
7835
+ getMoreData(length) {
7955
7836
  if (this.type === ListComponentsTypes.INFINITE) {
7956
- if (this.page === this.pages) {
7957
- if (event?.target)
7958
- event.target.complete();
7837
+ if (this.paginator)
7838
+ length = length * this.limit;
7839
+ if (length <= this.limit) {
7959
7840
  this.loadMoreData = false;
7960
7841
  }
7961
7842
  else {
7962
- this.page += 1;
7963
- this.refreshing = false;
7964
- setTimeout(() => {
7965
- if (event?.target && event?.type !== EventConstants.BACK_BUTTON_NAVIGATION)
7966
- event.target.complete();
7967
- }, 200);
7843
+ this.pages = Math.floor(length / this.limit);
7844
+ if ((this.pages * this.limit) < length)
7845
+ this.pages += 1;
7846
+ if (this.pages === 1)
7847
+ this.loadMoreData = false;
7968
7848
  }
7969
7849
  }
7970
7850
  else {
7971
- setTimeout(() => {
7972
- this.refreshing = false;
7973
- }, 200);
7851
+ this.pages = length;
7852
+ if (this.pages === 1)
7853
+ this.loadMoreData = false;
7974
7854
  }
7975
7855
  }
7976
7856
  /**
7977
- * @description Handles pagination events from the pagination component.
7978
- * @summary Processes pagination events by updating the current page number and
7979
- * refreshing the list data to display the selected page. This method is called
7980
- * when a user interacts with the pagination controls to navigate between pages.
7981
- *
7982
- * @param {PaginationCustomEvent} event - The pagination event containing page information
7983
- * @returns {void}
7984
- *
7985
- * @memberOf ListComponent
7986
- */
7987
- handlePaginate(event) {
7988
- const { page } = event.data;
7989
- this.page = page;
7990
- this.refresh(true);
7991
- }
7992
- /**
7993
- * @description Handles pull-to-refresh events from the refresher component.
7994
- * @summary Processes refresh events triggered by the user pulling down on the list
7995
- * or by programmatic refresh requests. This method refreshes the list data and
7996
- * completes the refresher animation when the data is loaded.
7857
+ * @description Maps a single item using the configured mapper.
7858
+ * @summary Transforms a data item according to the mapping configuration,
7859
+ * extracting nested properties and formatting values as needed. This allows
7860
+ * the component to display data in a format different from how it's stored.
7997
7861
  *
7998
- * @param {InfiniteScrollCustomEvent | CustomEvent} [event] - The refresh event
7999
- * @returns {Promise<void>} A promise that resolves when the refresh operation is complete
7862
+ * @protected
7863
+ * @param {KeyValue} item - The item to map
7864
+ * @param {KeyValue} mapper - The mapping configuration
7865
+ * @param {KeyValue} [props] - Additional properties to include
7866
+ * @returns {KeyValue} The mapped item
8000
7867
  *
8001
7868
  * @memberOf ListComponent
8002
7869
  */
8003
- async handleRefresh(event) {
8004
- await this.refresh(event || true);
8005
- if (event instanceof CustomEvent)
8006
- setTimeout(() => {
8007
- // Any calls to load data go here
8008
- event.target.complete();
8009
- }, 400);
7870
+ itemMapper(item, mapper, props) {
7871
+ return Object.entries(mapper).reduce((accum, [key, value]) => {
7872
+ const arrayValue = value.split('.');
7873
+ if (!value) {
7874
+ accum[key] = value;
7875
+ }
7876
+ else {
7877
+ if (arrayValue.length === 1) {
7878
+ value = item?.[value] ? item[value] : value !== key ? value : "";
7879
+ if (isValidDate(value))
7880
+ value = `${formatDate(value)}`;
7881
+ accum[key] = value;
7882
+ }
7883
+ else {
7884
+ let val;
7885
+ for (const _value of arrayValue)
7886
+ val = !val
7887
+ ? item[_value]
7888
+ : (typeof val === 'string' ? JSON.parse(val) : val)[_value];
7889
+ if (isValidDate(new Date(val)))
7890
+ val = `${formatDate(val)}`;
7891
+ accum[key] = val === null || val === undefined ? value : val;
7892
+ }
7893
+ }
7894
+ return Object.assign({}, props || {}, accum);
7895
+ }, {});
8010
7896
  }
8011
7897
  /**
8012
- * @description Filters data based on a search string.
8013
- * @summary Processes the current data array to find items that match the provided
8014
- * search string. This uses the arrayQueryByString utility to perform the filtering
8015
- * across all properties of the items.
7898
+ * @description Maps all result items using the configured mapper.
7899
+ * @summary Applies the itemMapper to each item in the result set, adding
7900
+ * common properties like operations and route information. This transforms
7901
+ * the raw data into the format expected by the list item components.
8016
7902
  *
8017
- * @param {KeyValue[]} results - The array of items to search through
8018
- * @param {string} search - The search string to filter by
8019
- * @returns {KeyValue[]} A promise that resolves to the filtered array of items
7903
+ * @param {KeyValue[]} data - The array of items to map
7904
+ * @returns {KeyValue[]} The array of mapped items
8020
7905
  *
8021
7906
  * @memberOf ListComponent
8022
7907
  */
8023
- parseSearchResults(results, search) {
8024
- return results.filter((item) => Object.values(item).some(value => value.toString().toLowerCase().includes(search?.toLowerCase())));
7908
+ mapResults(data) {
7909
+ if (!data || !data.length)
7910
+ return [];
7911
+ // passing uid as prop to mapper
7912
+ this.mapper = { ...this.mapper, ...{ uid: this.pk } };
7913
+ const props = Object.assign({
7914
+ operations: this.operations,
7915
+ route: this.route,
7916
+ ...Object.keys(this.item).reduce((acc, key) => {
7917
+ acc[key] = this.item[key];
7918
+ return acc;
7919
+ }, {}),
7920
+ // ... (!this.item.render ? {} : Object.keys(this.item).reduce((acc: KeyValue, key: string) => {
7921
+ // acc[key] = this.item[key as keyof IListItemProp];
7922
+ // return acc;
7923
+ // }, {}))
7924
+ });
7925
+ return data.reduce((accum, curr) => {
7926
+ accum.push({ ...this.itemMapper(curr, this.mapper, props), ...{ pk: this.pk } });
7927
+ return accum;
7928
+ }, []);
8025
7929
  }
7930
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7931
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.2", type: ListComponent, isStandalone: true, selector: "ngx-decaf-list", inputs: { type: "type", translatable: "translatable", showSearchbar: "showSearchbar", data: "data", source: "source", start: "start", limit: "limit", loadMoreData: "loadMoreData", lines: "lines", inset: "inset", scrollThreshold: "scrollThreshold", scrollPosition: "scrollPosition", loadingText: "loadingText", showRefresher: "showRefresher", loadingSpinner: "loadingSpinner", enableFilter: "enableFilter", sortDirection: "sortDirection", sortBy: "sortBy", disableSort: "disableSort", emptyIcon: "emptyIcon", empty: "empty" }, outputs: { refreshEvent: "refreshEvent", clickEvent: "clickEvent" }, host: { listeners: { "window:ListItemClickEvent": "handleClick($event)", "window:searchbarEvent": "handleSearch($event)", "window:BackButtonNavigationEndEvent": "refresh($event)" } }, usesInheritance: true, ngImport: i0, template: "\n@if(showRefresher) {\n <ion-refresher slot=\"fixed\" [pullFactor]=\"1\" [pullMin]=\"100\" [pullMax]=\"200\" (ionRefresh)=\"handleRefresh($event)\">\n <ion-refresher-content />\n </ion-refresher>\n}\n\n@if(showSearchbar && data?.length) {\n @if(model && enableFilter) {\n <ngx-decaf-filter\n [model]=\"model\"\n [sortDirection]=\"sortDirection\"\n [disableSort]=\"disableSort\"\n (filterEvent)=\"handleFilter($event)\"\n (searchEvent)=\"handleSearch($event)\"\n />\n } @else {\n <ngx-decaf-searchbar [emitEventToWindow]=\"false\" [debounce]=\"500\" (searchEvent)=\"handleSearch($event)\" />\n }\n}\n\n@if(data?.length) {\n <ion-list [id]=\"uid\" [inset]=\"inset\" [lines]=\"lines\" #component>\n @if(item?.tag) {\n @for(child of items; track trackItemFn($index, child)) {\n <ngx-decaf-component-renderer\n [tag]=\"item.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]='{\n item: child,\n mapper: mapper,\n route: route\n }'>\n </ngx-decaf-component-renderer>\n }\n } @else {\n <ng-content></ng-content>\n }\n </ion-list>\n\n @if(loadMoreData) {\n @if(pages > 0 && type === 'paginated' && !searchValue?.length) {\n <ngx-decaf-pagination\n [totalPages]=\"pages\"\n [current]=\"page\"\n (clickEvent)=\"handlePaginate($event)\"\n />\n\n } @else {\n <ion-infinite-scroll\n [class]=\"searchValue?.length ? 'dcf-hidden' : ''\"\n\n [position]=\"scrollPosition\"\n [threshold]=\"scrollThreshold\"\n (ionInfinite)=\"handleRefresh($event)\">\n <ion-infinite-scroll-content [loadingSpinner]=\"loadingSpinner\" [loadingText]=\"loadingText\" />\n </ion-infinite-scroll>\n }\n }\n} @else {\n @if(refreshing) {\n @for(skl of skeletonData; track $index) {\n <ion-item>\n <ion-thumbnail slot=\"start\">\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n </ion-thumbnail>\n <ion-label>\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n </ion-label>\n </ion-item>\n }\n\n } @else {\n @if(!searchValue?.length) {\n <ngx-decaf-empty-state\n [title]=\"(locale + '.'+ empty.title) | translate\"\n [subtitle]=\"(locale + '.'+ empty.subtitle) | translate\"\n [buttonText]=\"empty.showButton ? (locale + '.'+ empty.button | translate) : ''\"\n [buttonLink]=\"empty.showButton ? empty.route : ''\"\n />\n } @else {\n <ngx-decaf-empty-state\n icon=\"search-outline\"\n ngClass=\"empty-search\"\n [translatable]=\"true\"\n title=\"search.title\"\n subtitle=\"search.subtitle\"\n [searchValue]=\"searchValue\"\n />\n }\n }\n}\n\n", styles: ["ion-infinite-scroll{max-height:50px}ion-infinite-scroll:not(.infinite-scroll-loading) ::ng-deep{max-height:1.5rem}ion-infinite-scroll ::ng-deep ion-spinner{--color: var(--dcf-color-primary);padding-top:1rem}@media (max-width: 768px){#end,[slot=end]{display:none!important}}\n"], dependencies: [{ kind: "component", type: IonRefresher, selector: "ion-refresher", inputs: ["closeDuration", "disabled", "mode", "pullFactor", "pullMax", "pullMin", "snapbackDuration"] }, { kind: "component", type: PaginationComponent, selector: "ngx-decaf-pagination", inputs: ["totalPages", "current"], outputs: ["clickEvent"] }, { kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonThumbnail, selector: "ion-thumbnail" }, { kind: "component", type: IonSkeletonText, selector: "ion-skeleton-text", inputs: ["animated"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonRefresherContent, selector: "ion-refresher-content", inputs: ["pullingIcon", "pullingText", "refreshingSpinner", "refreshingText"] }, { kind: "component", type: IonInfiniteScroll, selector: "ion-infinite-scroll", inputs: ["disabled", "position", "threshold"] }, { kind: "component", type: IonInfiniteScrollContent, selector: "ion-infinite-scroll-content", inputs: ["loadingSpinner", "loadingText"] }, { kind: "component", type: SearchbarComponent, selector: "ngx-decaf-searchbar", inputs: ["autocomplete", "autocorrect", "animated", "buttonCancelText", "clearIcon", "color", "debounce", "disabled", "enterkeyhint", "inputmode", "placeholder", "searchIcon", "showCancelButton", "showClearButton", "spellcheck", "type", "value", "queryKeys", "isVisible", "wrapper", "wrapperColor", "emitEventToWindow"], outputs: ["searchEvent"] }, { kind: "component", type: EmptyStateComponent, selector: "ngx-decaf-empty-state", inputs: ["title", "titleColor", "subtitle", "subtitleColor", "showIcon", "icon", "iconSize", "iconColor", "buttonLink", "buttonText", "buttonFill", "buttonColor", "buttonSize", "searchValue"] }, { kind: "component", type: FilterComponent, selector: "ngx-decaf-filter", inputs: ["indexes", "conditions", "sortBy", "disableSort"], outputs: ["filterEvent", "searchEvent"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "children", "model", "parent"], outputs: ["listenEvent"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
7932
+ };
7933
+ ListComponent = __decorate([
7934
+ Dynamic(),
7935
+ __metadata("design:paramtypes", [])
7936
+ ], ListComponent);
7937
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ListComponent, decorators: [{
7938
+ type: Component,
7939
+ args: [{ selector: 'ngx-decaf-list', standalone: true, imports: [
7940
+ TranslatePipe,
7941
+ IonRefresher,
7942
+ PaginationComponent,
7943
+ IonList,
7944
+ IonItem,
7945
+ IonThumbnail,
7946
+ IonSkeletonText,
7947
+ IonLabel,
7948
+ IonText,
7949
+ IonRefresherContent,
7950
+ IonInfiniteScroll,
7951
+ IonInfiniteScrollContent,
7952
+ IonThumbnail,
7953
+ IonSkeletonText,
7954
+ SearchbarComponent,
7955
+ EmptyStateComponent,
7956
+ FilterComponent,
7957
+ ComponentRendererComponent
7958
+ ], template: "\n@if(showRefresher) {\n <ion-refresher slot=\"fixed\" [pullFactor]=\"1\" [pullMin]=\"100\" [pullMax]=\"200\" (ionRefresh)=\"handleRefresh($event)\">\n <ion-refresher-content />\n </ion-refresher>\n}\n\n@if(showSearchbar && data?.length) {\n @if(model && enableFilter) {\n <ngx-decaf-filter\n [model]=\"model\"\n [sortDirection]=\"sortDirection\"\n [disableSort]=\"disableSort\"\n (filterEvent)=\"handleFilter($event)\"\n (searchEvent)=\"handleSearch($event)\"\n />\n } @else {\n <ngx-decaf-searchbar [emitEventToWindow]=\"false\" [debounce]=\"500\" (searchEvent)=\"handleSearch($event)\" />\n }\n}\n\n@if(data?.length) {\n <ion-list [id]=\"uid\" [inset]=\"inset\" [lines]=\"lines\" #component>\n @if(item?.tag) {\n @for(child of items; track trackItemFn($index, child)) {\n <ngx-decaf-component-renderer\n [tag]=\"item.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]='{\n item: child,\n mapper: mapper,\n route: route\n }'>\n </ngx-decaf-component-renderer>\n }\n } @else {\n <ng-content></ng-content>\n }\n </ion-list>\n\n @if(loadMoreData) {\n @if(pages > 0 && type === 'paginated' && !searchValue?.length) {\n <ngx-decaf-pagination\n [totalPages]=\"pages\"\n [current]=\"page\"\n (clickEvent)=\"handlePaginate($event)\"\n />\n\n } @else {\n <ion-infinite-scroll\n [class]=\"searchValue?.length ? 'dcf-hidden' : ''\"\n\n [position]=\"scrollPosition\"\n [threshold]=\"scrollThreshold\"\n (ionInfinite)=\"handleRefresh($event)\">\n <ion-infinite-scroll-content [loadingSpinner]=\"loadingSpinner\" [loadingText]=\"loadingText\" />\n </ion-infinite-scroll>\n }\n }\n} @else {\n @if(refreshing) {\n @for(skl of skeletonData; track $index) {\n <ion-item>\n <ion-thumbnail slot=\"start\">\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n </ion-thumbnail>\n <ion-label>\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n </ion-label>\n </ion-item>\n }\n\n } @else {\n @if(!searchValue?.length) {\n <ngx-decaf-empty-state\n [title]=\"(locale + '.'+ empty.title) | translate\"\n [subtitle]=\"(locale + '.'+ empty.subtitle) | translate\"\n [buttonText]=\"empty.showButton ? (locale + '.'+ empty.button | translate) : ''\"\n [buttonLink]=\"empty.showButton ? empty.route : ''\"\n />\n } @else {\n <ngx-decaf-empty-state\n icon=\"search-outline\"\n ngClass=\"empty-search\"\n [translatable]=\"true\"\n title=\"search.title\"\n subtitle=\"search.subtitle\"\n [searchValue]=\"searchValue\"\n />\n }\n }\n}\n\n", styles: ["ion-infinite-scroll{max-height:50px}ion-infinite-scroll:not(.infinite-scroll-loading) ::ng-deep{max-height:1.5rem}ion-infinite-scroll ::ng-deep ion-spinner{--color: var(--dcf-color-primary);padding-top:1rem}@media (max-width: 768px){#end,[slot=end]{display:none!important}}\n"] }]
7959
+ }], ctorParameters: () => [], propDecorators: { type: [{
7960
+ type: Input
7961
+ }], translatable: [{
7962
+ type: Input
7963
+ }], showSearchbar: [{
7964
+ type: Input
7965
+ }], data: [{
7966
+ type: Input
7967
+ }], source: [{
7968
+ type: Input
7969
+ }], start: [{
7970
+ type: Input
7971
+ }], limit: [{
7972
+ type: Input
7973
+ }], loadMoreData: [{
7974
+ type: Input
7975
+ }], lines: [{
7976
+ type: Input
7977
+ }], inset: [{
7978
+ type: Input
7979
+ }], scrollThreshold: [{
7980
+ type: Input
7981
+ }], scrollPosition: [{
7982
+ type: Input
7983
+ }], loadingText: [{
7984
+ type: Input
7985
+ }], showRefresher: [{
7986
+ type: Input
7987
+ }], loadingSpinner: [{
7988
+ type: Input
7989
+ }], enableFilter: [{
7990
+ type: Input
7991
+ }], sortDirection: [{
7992
+ type: Input
7993
+ }], sortBy: [{
7994
+ type: Input
7995
+ }], disableSort: [{
7996
+ type: Input
7997
+ }], emptyIcon: [{
7998
+ type: Input
7999
+ }], empty: [{
8000
+ type: Input
8001
+ }], refreshEvent: [{
8002
+ type: Output
8003
+ }], clickEvent: [{
8004
+ type: Output
8005
+ }], handleClick: [{
8006
+ type: HostListener,
8007
+ args: ['window:ListItemClickEvent', ['$event']]
8008
+ }], handleSearch: [{
8009
+ type: HostListener,
8010
+ args: ['window:searchbarEvent', ['$event']]
8011
+ }], refresh: [{
8012
+ type: HostListener,
8013
+ args: ['window:BackButtonNavigationEndEvent', ['$event']]
8014
+ }] } });
8015
+
8016
+ /**
8017
+ * @description A component for displaying a list item with various customization options.
8018
+ * @summary The ListItemComponent is an Angular component that extends NgxBaseComponent. It provides a flexible and customizable list item interface with support for icons, buttons, and various text elements. The component also handles actions and navigation based on user interactions.
8019
+ *
8020
+ * @class
8021
+ * @extends NgxBaseComponent
8022
+ *
8023
+ * @param {string} [lines='none'] - Determines the line style of the item. Can be 'inset', 'inseet', or 'none'.
8024
+ * @param {Record<string, any>} item - The data item to be displayed in the list item.
8025
+ * @param {string} icon - The name of the icon to be displayed.
8026
+ * @param {'start' | 'end'} [iconSlot='start'] - The position of the icon within the item.
8027
+ * @param {StringOrBoolean} [button=true] - Determines if the item should behave as a button.
8028
+ * @param {string} [title] - The main title of the list item.
8029
+ * @param {string} [description] - A description for the list item.
8030
+ * @param {string} [info] - Additional information for the list item.
8031
+ * @param {string} [subinfo] - Sub-information for the list item.
8032
+ *
8033
+ * @example
8034
+ * <ngx-decaf-list-item
8035
+ * [item]="dataItem"
8036
+ * icon="star"
8037
+ * title="Item Title"
8038
+ * description="Item Description"
8039
+ * (clickEvent)="handleItemClick($event)">
8040
+ * </ngx-decaf-list-item>
8041
+ *
8042
+ * @mermaid
8043
+ * sequenceDiagram
8044
+ * participant C as Component
8045
+ * participant V as View
8046
+ * participant U as User
8047
+ * C->>V: Initialize component
8048
+ * V->>U: Display list item
8049
+ * U->>V: Click on item or action
8050
+ * V->>C: Trigger handleAction()
8051
+ * C->>C: Process action
8052
+ * C->>V: Update view or navigate
8053
+ */
8054
+ let ListItemComponent = class ListItemComponent extends NgxBaseComponent {
8026
8055
  /**
8027
- * @description Fetches data from a request source.
8028
- * @summary Retrieves data from the configured source function or URL, processes it,
8029
- * and updates the component's data state. This method handles both initial data loading
8030
- * and subsequent refresh operations when using an external data source rather than a model.
8031
- *
8032
- * @param {boolean} force - Whether to force a refresh even if data already exists
8033
- * @param {number} start - The starting index for pagination
8034
- * @param {number} limit - The maximum number of items to retrieve
8035
- * @returns {Promise<KeyValue[]>} A promise that resolves to the fetched data
8056
+ * @description Creates an instance of ListItemComponent.
8057
+ * @summary Initializes a new ListItemComponent by calling the parent class constructor
8058
+ * with the component name for logging and identification purposes. Also registers
8059
+ * all available Ionic icons to ensure they can be displayed in the component.
8036
8060
  *
8037
- * @memberOf ListComponent
8061
+ * @memberOf ListItemComponent
8038
8062
  */
8039
- async getFromRequest(force = false, start, limit) {
8040
- let request = [];
8041
- if (!this.data?.length || force || this.searchValue?.length || !!this.searchValue) {
8042
- // (self.data as ListItem[]) = [];
8043
- if (!this.searchValue?.length && !this.searchValue) {
8044
- if (!this.source && !this.data?.length) {
8045
- this.logger.info('No data and source passed to infinite list');
8046
- return [];
8047
- }
8048
- if (this.source instanceof Function)
8049
- request = await this.source();
8050
- if (!Array.isArray(request))
8051
- request = request?.['response']?.['data'] || request?.['results'] || [];
8052
- this.data = [...await this.parseResult(request)];
8053
- if (this.data?.length)
8054
- this.items = this.type === ListComponentsTypes.INFINITE ?
8055
- (this.items || []).concat([...this.data.slice(start, limit)]) : [...request.slice(start, limit)];
8056
- }
8057
- else {
8058
- this.data = this.parseSearchResults(this.data, this.searchValue);
8059
- this.items = this.data;
8060
- }
8061
- }
8062
- if (this.loadMoreData && this.type === ListComponentsTypes.PAGINATED)
8063
- this.getMoreData(this.data?.length || 0);
8064
- return this.data || [];
8065
- }
8066
- /**
8067
- * @description Fetches data from a model source.
8068
- * @summary Retrieves data from the configured model using its pagination or find methods,
8069
- * processes it, and updates the component's data state. This method handles both initial
8070
- * data loading and subsequent refresh operations when using a model as the data source.
8063
+ constructor() {
8064
+ super("ListItemComponent");
8065
+ /**
8066
+ * @description Controls the display of lines around the list item.
8067
+ * @summary Determines how lines are displayed around the list item borders.
8068
+ * 'inset' shows lines with padding, 'full' shows full-width lines, and 'none'
8069
+ * removes all lines. This affects the visual separation between list items.
8070
+ *
8071
+ * @type {'inset' | 'full' | 'none'}
8072
+ * @default 'inset'
8073
+ * @memberOf ListItemComponent
8074
+ */
8075
+ this.lines = 'full';
8076
+ /**
8077
+ * @description Position of the icon within the list item.
8078
+ * @summary Determines whether the icon appears at the start (left in LTR languages)
8079
+ * or end (right in LTR languages) of the list item. This affects the overall
8080
+ * layout and visual hierarchy of the item content.
8081
+ *
8082
+ * @type {'start' | 'end'}
8083
+ * @default 'start'
8084
+ * @memberOf ListItemComponent
8085
+ */
8086
+ this.iconSlot = 'start';
8087
+ /**
8088
+ * @description Controls whether the list item behaves as a clickable button.
8089
+ * @summary When set to true, the list item will have button-like behavior including
8090
+ * hover effects, click handling, and appropriate accessibility attributes.
8091
+ * When false, the item is displayed as static content without interactive behavior.
8092
+ *
8093
+ * @type {StringOrBoolean}
8094
+ * @default true
8095
+ * @memberOf ListItemComponent
8096
+ */
8097
+ this.button = true;
8098
+ /**
8099
+ * @description Event emitter for list item click interactions.
8100
+ * @summary Emits custom events when the list item is clicked or when actions
8101
+ * are performed on it. The emitted event contains information about the action,
8102
+ * the item data, and other relevant context for parent components to handle.
8103
+ *
8104
+ * @type {EventEmitter<ListItemCustomEvent>}
8105
+ * @memberOf ListItemComponent
8106
+ */
8107
+ this.clickEvent = new EventEmitter();
8108
+ /**
8109
+ * @description Flag indicating whether slide items are currently enabled.
8110
+ * @summary Controls the visibility of slide actions based on screen size and
8111
+ * available operations. When true, users can swipe on the item to reveal
8112
+ * action buttons for operations like edit and delete.
8113
+ *
8114
+ * @type {boolean}
8115
+ * @default false
8116
+ * @memberOf ListItemComponent
8117
+ */
8118
+ this.showSlideItems = false;
8119
+ /**
8120
+ * @description Flag indicating whether the action menu popover is currently open.
8121
+ * @summary Tracks the state of the action menu to prevent multiple instances
8122
+ * from being opened simultaneously and to ensure proper cleanup when actions
8123
+ * are performed. Used for managing the popover lifecycle.
8124
+ *
8125
+ * @type {boolean}
8126
+ * @default false
8127
+ * @memberOf ListItemComponent
8128
+ */
8129
+ this.actionMenuOpen = false;
8130
+ /**
8131
+ * @description Angular NavController service for handling navigation.
8132
+ * @summary Injected service that provides methods for programmatic navigation
8133
+ * within the Ionic application. Used for navigating to different routes when
8134
+ * list item actions are performed or when the item itself is clicked.
8135
+ *
8136
+ * @private
8137
+ * @type {NavController}
8138
+ * @memberOf ListItemComponent
8139
+ */
8140
+ this.navController = inject(NavController);
8141
+ addIcons(allIcons);
8142
+ }
8143
+ /**
8144
+ * @description Initializes the component after Angular first displays the data-bound properties.
8145
+ * @summary Sets up the component by determining slide item visibility, processing boolean inputs,
8146
+ * building CSS class names based on properties, and capturing the current window width.
8147
+ * This method prepares the component for user interaction by ensuring all properties are
8148
+ * properly initialized and responsive behavior is configured.
8071
8149
  *
8072
- * @param {boolean} force - Whether to force a refresh even if data already exists
8073
- * @param {number} start - The starting index for pagination
8074
- * @param {number} limit - The maximum number of items to retrieve
8075
- * @returns {Promise<KeyValue[]>} A promise that resolves to the fetched data
8150
+ * @mermaid
8151
+ * sequenceDiagram
8152
+ * participant A as Angular Lifecycle
8153
+ * participant L as ListItemComponent
8154
+ * participant W as Window
8076
8155
  *
8077
- * @memberOf ListComponent
8156
+ * A->>L: ngOnInit()
8157
+ * L->>L: enableSlideItems()
8158
+ * L->>L: Process button boolean
8159
+ * L->>L: Build className with flex classes
8160
+ * alt operations exist
8161
+ * L->>L: Add 'action' class
8162
+ * end
8163
+ * L->>W: getWindowWidth()
8164
+ * W-->>L: Return current width
8165
+ * L->>L: Store windowWidth
8166
+ *
8167
+ * @return {Promise<void>}
8168
+ * @memberOf ListItemComponent
8078
8169
  */
8079
- async getFromModel(force = false) {
8080
- let data = [...this.data || []];
8081
- let request = [];
8082
- // getting model repository
8083
- if (!this._repository)
8084
- this._repository = this.repository;
8085
- const repo = this._repository;
8086
- if (!this.data?.length || force || this.searchValue?.length || !!this.searchValue) {
8087
- try {
8088
- if (!this.searchValue?.length && !this.searchValue) {
8089
- this.data = [];
8090
- // const rawQuery = this.parseQuery(self.model as Repository<Model>, start, limit);
8091
- // request = this.parseResult(await (this.model as any)?.paginate(start, limit));
8092
- if (!this.paginator) {
8093
- this.paginator = await repo
8094
- .select()
8095
- .orderBy([this.pk, this.sortDirection])
8096
- .paginate(this.limit);
8097
- }
8098
- request = await this.parseResult(this.paginator);
8099
- }
8100
- else {
8101
- if (!this.indexes)
8102
- this.indexes = (Object.values(this.mapper) || [this.pk]);
8103
- const condition = this.parseConditions(this.searchValue);
8104
- request = await this.parseResult(await repo.query(condition, (this.sortBy || this.pk), this.sortDirection));
8105
- data = [];
8106
- }
8107
- data = this.type === ListComponentsTypes.INFINITE ? [...(data).concat(request)] : [...request];
8108
- }
8109
- catch (error) {
8110
- this.logger.error(error?.message || `Unable to find ${this.model} on registry. Return empty array from component`);
8111
- }
8112
- }
8113
- if (data?.length) {
8114
- if (this.searchValue) {
8115
- this.items = [...data];
8116
- if (this.items?.length <= this.limit)
8117
- this.loadMoreData = false;
8118
- }
8119
- else {
8120
- this.items = [...data];
8121
- }
8122
- }
8123
- if (this.type === ListComponentsTypes.PAGINATED && this.paginator)
8124
- this.getMoreData(this.paginator.total);
8125
- return data || [];
8170
+ async ngOnInit() {
8171
+ this.showSlideItems = this.enableSlideItems();
8172
+ this.button = stringToBoolean(this.button);
8173
+ this.className = `${this.className} dcf-flex dcf-flex-middle grid-item`;
8174
+ if (this.operations?.length)
8175
+ this.className += ` action`;
8176
+ this.windowWidth = getWindowWidth();
8126
8177
  }
8127
8178
  /**
8128
- * @description Converts search values or filter queries into database conditions.
8129
- * @summary Transforms search input or complex filter queries into Condition objects
8130
- * that can be used for database querying. Handles both simple string/number searches
8131
- * across indexed fields and complex filter queries with multiple criteria.
8179
+ * @description Handles user interactions and actions performed on the list item.
8180
+ * @summary This method is the central action handler for list item interactions. It manages
8181
+ * event propagation, dismisses open action menus, removes focus traps, and either emits
8182
+ * events for parent components to handle or performs navigation based on the component's
8183
+ * route configuration. This method supports both event-driven and navigation-driven architectures.
8132
8184
  *
8133
- * For simple searches (string/number):
8134
- * - Creates conditions that search across all indexed fields
8135
- * - Uses equality for numeric values and regex for string values
8136
- * - Combines conditions with OR logic to search multiple fields
8185
+ * @param {CrudOperations} action - The type of CRUD operation being performed
8186
+ * @param {Event} event - The browser event that triggered the action
8187
+ * @param {HTMLElement} [target] - Optional target element for the event
8188
+ * @return {Promise<boolean|void>} A promise that resolves to navigation success or void for events
8137
8189
  *
8138
- * For complex filter queries:
8139
- * - Processes each filter item with its specific condition type
8140
- * - Supports Equal, Not Equal, Contains, Not Contains, Greater Than, Less Than
8141
- * - Updates sort configuration based on the filter query
8142
- * - Combines multiple filter conditions with OR logic
8190
+ * @mermaid
8191
+ * sequenceDiagram
8192
+ * participant U as User
8193
+ * participant L as ListItemComponent
8194
+ * participant P as Parent Component
8195
+ * participant N as NavController
8196
+ * participant E as Event System
8143
8197
  *
8144
- * @param {string | number | IFilterQuery} value - The search value or filter query object
8145
- * @returns {Condition<Model>} A Condition object for database querying
8146
- * @memberOf ListComponent
8198
+ * U->>L: Perform action (click/swipe)
8199
+ * L->>L: stopImmediatePropagation()
8200
+ * alt actionMenuOpen
8201
+ * L->>L: Dismiss action menu
8202
+ * end
8203
+ * L->>L: removeFocusTrap()
8204
+ * alt No route configured
8205
+ * L->>E: windowEventEmitter()
8206
+ * L->>P: clickEvent.emit()
8207
+ * else Route configured
8208
+ * L->>N: redirect(action, uid)
8209
+ * N-->>L: Return navigation result
8210
+ * end
8211
+ *
8212
+ * @memberOf ListItemComponent
8147
8213
  */
8148
- parseConditions(value) {
8149
- let _condition;
8150
- if (typeof value === Primitives.STRING || typeof value === Primitives.NUMBER) {
8151
- _condition = Condition.attribute(this.pk).eq(!isNaN(value) ? Number(value) : value);
8152
- for (const index of this.indexes) {
8153
- if (index === this.pk)
8154
- continue;
8155
- let orCondition;
8156
- if (!isNaN(value)) {
8157
- orCondition = Condition.attribute(index).eq(Number(value));
8158
- }
8159
- else {
8160
- orCondition = Condition.attribute(index).regexp(value);
8161
- }
8162
- _condition = _condition.or(orCondition);
8163
- }
8164
- }
8165
- else {
8166
- const { query, sort } = value;
8167
- _condition = Condition.attribute(this.pk).dif('null');
8168
- if (query?.length)
8169
- _condition = undefined;
8170
- (query || []).forEach((item) => {
8171
- const { value, condition, index } = item;
8172
- let val = value;
8173
- if (index === this.pk || !isNaN(val))
8174
- val = Number(val);
8175
- let orCondition;
8176
- switch (condition) {
8177
- case "Equal":
8178
- orCondition = Condition.attribute(index).eq(val);
8179
- break;
8180
- case "Not Equal":
8181
- orCondition = Condition.attribute(index).dif(val);
8182
- break;
8183
- case "Not Contains":
8184
- orCondition = !Condition.attribute(index).regexp(new RegExp(`^(?!.*${val}).*$`));
8185
- break;
8186
- case "Contains":
8187
- orCondition = Condition.attribute(index).regexp(val);
8188
- break;
8189
- case "Greater Than":
8190
- orCondition = Condition.attribute(index).gte(val);
8191
- break;
8192
- case "Less Than":
8193
- orCondition = Condition.attribute(index).lte(val);
8194
- break;
8195
- }
8196
- _condition = (!_condition ?
8197
- orCondition : _condition.and(orCondition));
8198
- });
8199
- this.sortBy = sort?.value || this.pk;
8200
- this.sortDirection = sort?.direction || this.sortDirection;
8214
+ async handleAction(action, event, target) {
8215
+ event.stopImmediatePropagation();
8216
+ if (this.actionMenuOpen)
8217
+ await this.actionMenuComponent.dismiss();
8218
+ // forcing trap focus
8219
+ removeFocusTrap();
8220
+ if (!this.route) {
8221
+ const event = { target: target, action, pk: this.pk, data: this.uid, name: EventConstants.CLICK, component: this.componentName };
8222
+ windowEventEmitter(`ListItem${EventConstants.CLICK}`, event);
8223
+ return this.clickEvent.emit(event);
8201
8224
  }
8202
- return _condition;
8225
+ return await this.redirect(action, (typeof this.uid === 'number' ? `${this.uid}` : this.uid));
8203
8226
  }
8204
8227
  /**
8205
- * @description Processes query results into a standardized format.
8206
- * @summary Handles different result formats from various data sources, extracting
8207
- * pagination information when available and applying any configured data mapping.
8208
- * This ensures consistent data structure regardless of the source.
8228
+ * @description Responsive handler that enables or disables slide items based on screen size and operations.
8229
+ * @summary This method is automatically called when the window is resized and also during component
8230
+ * initialization. It determines whether slide actions should be available based on the current
8231
+ * window width and the presence of UPDATE or DELETE operations. Slide items are typically hidden
8232
+ * on larger screens where there's space for dedicated action buttons.
8209
8233
  *
8210
- * @protected
8211
- * @param {KeyValue[] | Paginator} result - The raw query result
8212
- * @returns {KeyValue[]} The processed array of items
8234
+ * @return {boolean} True if slide items should be shown, false otherwise
8213
8235
  *
8214
- * @memberOf ListComponent
8236
+ * @mermaid
8237
+ * sequenceDiagram
8238
+ * participant W as Window
8239
+ * participant L as ListItemComponent
8240
+ * participant U as UI
8241
+ *
8242
+ * W->>L: resize event
8243
+ * L->>W: getWindowWidth()
8244
+ * W-->>L: Return current width
8245
+ * L->>L: Store windowWidth
8246
+ * alt No operations OR width > 639px
8247
+ * L->>U: showSlideItems = false
8248
+ * else Operations include UPDATE/DELETE
8249
+ * L->>U: showSlideItems = true
8250
+ * end
8251
+ * L-->>U: Return showSlideItems value
8252
+ *
8253
+ * @memberOf ListItemComponent
8215
8254
  */
8216
- async parseResult(result) {
8217
- if (!Array.isArray(result) && ('page' in result && 'total' in result)) {
8218
- const paginator = result;
8219
- try {
8220
- result = await paginator.page(this.page);
8221
- // TODO: Chage for result.total;
8222
- this.getMoreData(paginator.total);
8223
- }
8224
- catch (error) {
8225
- this.logger.info(error?.message || 'Unable to get page from paginator. Return empty array from component');
8226
- result = [];
8227
- }
8228
- }
8229
- else {
8230
- this.getMoreData(result?.length || 0);
8231
- }
8232
- return (Object.keys(this.mapper || {}).length) ?
8233
- this.mapResults(result) : result;
8255
+ enableSlideItems() {
8256
+ this.windowWidth = getWindowWidth();
8257
+ if (!this.operations?.length || this.windowWidth > 639)
8258
+ return this.showSlideItems = false;
8259
+ this.showSlideItems = this.operations.includes(OperationKeys.UPDATE) || this.operations.includes(OperationKeys.DELETE);
8260
+ return this.showSlideItems;
8234
8261
  }
8235
8262
  /**
8236
- * @description Updates pagination state based on data length.
8237
- * @summary Calculates whether more data is available and how many pages exist
8238
- * based on the total number of items and the configured limit per page.
8239
- * This information is used to control pagination UI and infinite scrolling behavior.
8263
+ * @description Animates and removes an element from the DOM.
8264
+ * @summary This method applies CSS animation classes to create a smooth fade-out effect
8265
+ * before removing the element from the DOM. The animation enhances user experience by
8266
+ * providing visual feedback when items are deleted or removed from lists. The timing
8267
+ * is coordinated with the CSS animation duration to ensure the element is removed
8268
+ * after the animation completes.
8240
8269
  *
8241
- * @param {number} length - The total number of items available
8242
- * @returns {void}
8270
+ * @param {HTMLElement} element - The DOM element to animate and remove
8271
+ * @return {void}
8243
8272
  *
8244
- * @memberOf ListComponent
8273
+ * @mermaid
8274
+ * sequenceDiagram
8275
+ * participant L as ListItemComponent
8276
+ * participant E as HTMLElement
8277
+ * participant D as DOM
8278
+ *
8279
+ * L->>E: Add animation classes
8280
+ * Note over E: uk-animation-fade, uk-animation-medium, uk-animation-reverse
8281
+ * E->>E: Start fade animation
8282
+ * L->>L: setTimeout(600ms)
8283
+ * Note over L: Wait for animation to complete
8284
+ * L->>D: element.remove()
8285
+ * D->>D: Remove element from DOM
8286
+ *
8287
+ * @memberOf ListItemComponent
8245
8288
  */
8246
- getMoreData(length) {
8247
- if (this.type === ListComponentsTypes.INFINITE) {
8248
- if (this.paginator)
8249
- length = length * this.limit;
8250
- if (length <= this.limit) {
8251
- this.loadMoreData = false;
8252
- }
8253
- else {
8254
- this.pages = Math.floor(length / this.limit);
8255
- if ((this.pages * this.limit) < length)
8256
- this.pages += 1;
8257
- if (this.pages === 1)
8258
- this.loadMoreData = false;
8259
- }
8260
- }
8261
- else {
8262
- this.pages = length;
8263
- if (this.pages === 1)
8264
- this.loadMoreData = false;
8265
- }
8289
+ removeElement(element) {
8290
+ element.classList.add('uk-animation-fade', 'uk-animation-medium', 'uk-animation-reverse');
8291
+ setTimeout(() => { element.remove(); }, 600);
8266
8292
  }
8267
8293
  /**
8268
- * @description Maps a single item using the configured mapper.
8269
- * @summary Transforms a data item according to the mapping configuration,
8270
- * extracting nested properties and formatting values as needed. This allows
8271
- * the component to display data in a format different from how it's stored.
8294
+ * @description Navigates to a new route based on the specified action and item ID.
8295
+ * @summary This method constructs a navigation URL using the component's route configuration,
8296
+ * the specified action, and an item identifier. It uses Ionic's NavController to perform
8297
+ * forward navigation with appropriate animations. This method is typically used for
8298
+ * CRUD operations where each action (create, read, update, delete) has its own route.
8272
8299
  *
8273
- * @protected
8274
- * @param {KeyValue} item - The item to map
8275
- * @param {KeyValue} mapper - The mapping configuration
8276
- * @param {KeyValue} [props] - Additional properties to include
8277
- * @returns {KeyValue} The mapped item
8300
+ * @param {string} action - The action to be performed (e.g., 'edit', 'view', 'delete')
8301
+ * @param {string} [id] - The unique identifier of the item to be acted upon
8302
+ * @return {Promise<boolean>} A promise that resolves to true if navigation was successful
8278
8303
  *
8279
- * @memberOf ListComponent
8304
+ * @mermaid
8305
+ * sequenceDiagram
8306
+ * participant L as ListItemComponent
8307
+ * participant N as NavController
8308
+ * participant R as Router
8309
+ *
8310
+ * L->>L: redirect(action, id)
8311
+ * L->>L: Construct URL: /{route}/{action}/{id}
8312
+ * L->>N: navigateForward(url)
8313
+ * N->>R: Navigate to constructed URL
8314
+ * R-->>N: Return navigation result
8315
+ * N-->>L: Return boolean success
8316
+ *
8317
+ * @memberOf ListItemComponent
8280
8318
  */
8281
- itemMapper(item, mapper, props) {
8282
- return Object.entries(mapper).reduce((accum, [key, value]) => {
8283
- const arrayValue = value.split('.');
8284
- if (!value) {
8285
- accum[key] = value;
8286
- }
8287
- else {
8288
- if (arrayValue.length === 1) {
8289
- value = item?.[value] ? item[value] : value !== key ? value : "";
8290
- if (isValidDate(value))
8291
- value = `${formatDate(value)}`;
8292
- accum[key] = value;
8293
- }
8294
- else {
8295
- let val;
8296
- for (const _value of arrayValue)
8297
- val = !val
8298
- ? item[_value]
8299
- : (typeof val === 'string' ? JSON.parse(val) : val)[_value];
8300
- if (isValidDate(new Date(val)))
8301
- val = `${formatDate(val)}`;
8302
- accum[key] = val === null || val === undefined ? value : val;
8303
- }
8304
- }
8305
- return Object.assign({}, props || {}, accum);
8306
- }, {});
8319
+ async redirect(action, id) {
8320
+ return await this.navController.navigateForward(`/${this.route}/${action}/${id || this.uid}`);
8307
8321
  }
8308
8322
  /**
8309
- * @description Maps all result items using the configured mapper.
8310
- * @summary Applies the itemMapper to each item in the result set, adding
8311
- * common properties like operations and route information. This transforms
8312
- * the raw data into the format expected by the list item components.
8323
+ * @description Presents the actions menu popover for the list item.
8324
+ * @summary This method handles the display of a contextual action menu when triggered by user
8325
+ * interaction (typically a long press or right-click). It stops event propagation to prevent
8326
+ * unwanted side effects, removes any existing focus traps for accessibility, configures the
8327
+ * popover with the triggering event, and opens the action menu. The menu typically contains
8328
+ * available CRUD operations for the item.
8313
8329
  *
8314
- * @param {KeyValue[]} data - The array of items to map
8315
- * @returns {KeyValue[]} The array of mapped items
8330
+ * @param {Event} event - The event that triggered the action menu request
8331
+ * @return {void}
8316
8332
  *
8317
- * @memberOf ListComponent
8333
+ * @mermaid
8334
+ * sequenceDiagram
8335
+ * participant U as User
8336
+ * participant L as ListItemComponent
8337
+ * participant P as Popover
8338
+ * participant A as Accessibility
8339
+ *
8340
+ * U->>L: Trigger action menu (long press/right-click)
8341
+ * L->>L: stopImmediatePropagation()
8342
+ * L->>A: removeFocusTrap()
8343
+ * L->>P: Set event reference
8344
+ * L->>L: actionMenuOpen = true
8345
+ * L->>P: Display popover with actions
8346
+ *
8347
+ * @memberOf ListItemComponent
8318
8348
  */
8319
- mapResults(data) {
8320
- if (!data || !data.length)
8321
- return [];
8322
- // passing uid as prop to mapper
8323
- this.mapper = { ...this.mapper, ...{ uid: this.pk } };
8324
- const props = Object.assign({
8325
- operations: this.operations,
8326
- route: this.route,
8327
- ...Object.keys(this.item).reduce((acc, key) => {
8328
- acc[key] = this.item[key];
8329
- return acc;
8330
- }, {}),
8331
- // ... (!this.item.render ? {} : Object.keys(this.item).reduce((acc: KeyValue, key: string) => {
8332
- // acc[key] = this.item[key as keyof IListItemProp];
8333
- // return acc;
8334
- // }, {}))
8335
- });
8336
- return data.reduce((accum, curr) => {
8337
- accum.push({ ...this.itemMapper(curr, this.mapper, props), ...{ pk: this.pk } });
8338
- return accum;
8339
- }, []);
8349
+ presentActionsMenu(event) {
8350
+ event.stopImmediatePropagation();
8351
+ // forcing trap focus
8352
+ removeFocusTrap();
8353
+ this.actionMenuComponent.event = event;
8354
+ this.actionMenuOpen = true;
8340
8355
  }
8341
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8342
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ListComponent, isStandalone: true, selector: "ngx-decaf-list", inputs: { type: "type", translatable: "translatable", showSearchbar: "showSearchbar", data: "data", source: "source", start: "start", limit: "limit", loadMoreData: "loadMoreData", lines: "lines", inset: "inset", scrollThreshold: "scrollThreshold", scrollPosition: "scrollPosition", loadingText: "loadingText", showRefresher: "showRefresher", loadingSpinner: "loadingSpinner", enableFilter: "enableFilter", sortDirection: "sortDirection", sortBy: "sortBy", disableSort: "disableSort", emptyIcon: "emptyIcon", empty: "empty" }, outputs: { refreshEvent: "refreshEvent", clickEvent: "clickEvent" }, host: { listeners: { "window:ListItemClickEvent": "handleClick($event)", "window:searchbarEvent": "handleSearch($event)", "window:BackButtonNavigationEndEvent": "refresh($event)" } }, usesInheritance: true, ngImport: i0, template: "\n@if(showRefresher) {\n <ion-refresher slot=\"fixed\" [pullFactor]=\"1\" [pullMin]=\"100\" [pullMax]=\"200\" (ionRefresh)=\"handleRefresh($event)\">\n <ion-refresher-content />\n </ion-refresher>\n}\n\n@if(showSearchbar && data?.length) {\n @if(model && enableFilter) {\n <ngx-decaf-filter\n [model]=\"model\"\n [sortDirection]=\"sortDirection\"\n [disableSort]=\"disableSort\"\n (filterEvent)=\"handleFilter($event)\"\n (searchEvent)=\"handleSearch($event)\"\n />\n } @else {\n <ngx-decaf-searchbar [emitEventToWindow]=\"false\" [debounce]=\"500\" (searchEvent)=\"handleSearch($event)\" />\n }\n}\n\n@if(data?.length) {\n <ion-list [id]=\"uid\" [inset]=\"inset\" [lines]=\"lines\" #component>\n @if(item?.tag) {\n @for(child of items; track trackItemFn($index, child)) {\n <ngx-decaf-component-renderer\n [tag]=\"item.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]='{\n item: child,\n mapper: mapper,\n route: route\n }'>\n </ngx-decaf-component-renderer>\n }\n } @else {\n <ng-content></ng-content>\n }\n </ion-list>\n\n @if(loadMoreData) {\n @if(pages > 0 && type === 'paginated' && !searchValue?.length) {\n <ngx-decaf-pagination\n [totalPages]=\"pages\"\n [current]=\"page\"\n (clickEvent)=\"handlePaginate($event)\"\n />\n\n } @else {\n <ion-infinite-scroll\n [class]=\"searchValue?.length ? 'dcf-hidden' : ''\"\n\n [position]=\"scrollPosition\"\n [threshold]=\"scrollThreshold\"\n (ionInfinite)=\"handleRefresh($event)\">\n <ion-infinite-scroll-content [loadingSpinner]=\"loadingSpinner\" [loadingText]=\"loadingText\" />\n </ion-infinite-scroll>\n }\n }\n} @else {\n @if(refreshing) {\n @for(skl of skeletonData; track $index) {\n <ion-item>\n <ion-thumbnail slot=\"start\">\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n </ion-thumbnail>\n <ion-label>\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n </ion-label>\n </ion-item>\n }\n\n } @else {\n @if(!searchValue?.length) {\n <ngx-decaf-empty-state\n [title]=\"(locale + '.'+ empty.title) | translate\"\n [subtitle]=\"(locale + '.'+ empty.subtitle) | translate\"\n [buttonText]=\"empty.showButton ? (locale + '.'+ empty.button | translate) : ''\"\n [buttonLink]=\"empty.showButton ? empty.route : ''\"\n />\n } @else {\n <ngx-decaf-empty-state\n icon=\"search-outline\"\n ngClass=\"empty-search\"\n [translatable]=\"true\"\n title=\"search.title\"\n subtitle=\"search.subtitle\"\n [searchValue]=\"searchValue\"\n />\n }\n }\n}\n\n", styles: ["ion-infinite-scroll{max-height:50px}ion-infinite-scroll:not(.infinite-scroll-loading) ::ng-deep{max-height:1.5rem}ion-infinite-scroll ::ng-deep ion-spinner{--color: var(--dcf-color-primary);padding-top:1rem}@media (max-width: 768px){#end,[slot=end]{display:none!important}}\n"], dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "component", type: IonRefresher, selector: "ion-refresher", inputs: ["closeDuration", "disabled", "mode", "pullFactor", "pullMax", "pullMin", "snapbackDuration"] }, { kind: "component", type: PaginationComponent, selector: "ngx-decaf-pagination", inputs: ["totalPages", "current"], outputs: ["clickEvent"] }, { kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonThumbnail, selector: "ion-thumbnail" }, { kind: "component", type: IonSkeletonText, selector: "ion-skeleton-text", inputs: ["animated"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonRefresherContent, selector: "ion-refresher-content", inputs: ["pullingIcon", "pullingText", "refreshingSpinner", "refreshingText"] }, { kind: "component", type: IonInfiniteScroll, selector: "ion-infinite-scroll", inputs: ["disabled", "position", "threshold"] }, { kind: "component", type: IonInfiniteScrollContent, selector: "ion-infinite-scroll-content", inputs: ["loadingSpinner", "loadingText"] }, { kind: "component", type: SearchbarComponent, selector: "ngx-decaf-searchbar", inputs: ["autocomplete", "autocorrect", "animated", "buttonCancelText", "clearIcon", "color", "debounce", "disabled", "enterkeyhint", "inputmode", "placeholder", "searchIcon", "showCancelButton", "showClearButton", "spellcheck", "type", "value", "queryKeys", "isVisible", "wrapper", "wrapperColor", "emitEventToWindow"], outputs: ["searchEvent"] }, { kind: "component", type: EmptyStateComponent, selector: "ngx-decaf-empty-state", inputs: ["title", "titleColor", "subtitle", "subtitleColor", "showIcon", "icon", "iconSize", "iconColor", "buttonLink", "buttonText", "buttonFill", "buttonColor", "buttonSize", "searchValue"] }, { kind: "component", type: FilterComponent, selector: "ngx-decaf-filter", inputs: ["indexes", "conditions", "sortBy", "disableSort"], outputs: ["filterEvent", "searchEvent"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "children", "model", "parent"], outputs: ["listenEvent"] }] }); }
8356
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ListItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8357
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.2", 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)" } }, viewQueries: [{ propertyName: "actionMenuComponent", first: true, predicate: ["actionMenuComponent"], descendants: true }], usesInheritance: true, ngImport: i0, template: "\n@if(title || description) {\n <ion-item-sliding #component>\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 \">\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 <ion-label class=\"dcf-item-title\" [innerHTML]=\"uid + ' - ' + title\" ></ion-label>\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 <div class=\"dcf-visible@m\" id=\"dcf-actions\">\n <ion-button class=\"dcf-hidden@m\" 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: ["@media (prefers-color-scheme: light){ion-item{--background-hover-opacity: .1;--background-focused-opacity: .1;--border-color: var(--dcf-color-gray-2)}ion-item .dcf-info{color:var(--dcf-color-gray-6)}ion-item .dcf-item-title{color:var(--dcf-color-gray-8)}ion-item .dcf-description{color:var(--dcf-color-gray-6)}ion-button{color:var(--dcf-color-gray-7);--background: var(--dcf-color-gray-1) !important}ion-avatar{color:var(--dcf-color-gray-7);background:var(--dcf-color-gray-1)!important}ion-item-option:not(.dcf-delete),ion-item-option:not(.dcf-update){background:rgba(var(--dcf-color-dark-rgb),.25)!important}ion-item-option:not(.dcf-delete) .dcf-ti,ion-item-option:not(.dcf-delete) ion-icon,ion-item-option:not(.dcf-update) .dcf-ti,ion-item-option:not(.dcf-update) ion-icon{color:var(--dcf-color-gray-7)!important}ion-item-option.dcf-delete{background:rgba(var(--dcf-color-danger-rgb),.05)!important}ion-item-option.dcf-delete .dcf-ti,ion-item-option.dcf-delete *,ion-item-option.dcf-delete ion-icon{color:var(--dcf-color-danger)!important}ion-item-option.dcf-update{background:rgba(var(--dcf-color-primary-rgb),.05)!important}ion-item-option.dcf-update .dcf-ti,ion-item-option.dcf-update ion-icon{color:var(--dcf-color-primary)!important}}@media (prefers-color-scheme: dark){ion-item{--background-hover-opacity: .25;--background-focused-opacity: .25;--border-color: var(--dcf-color-gray-6)}ion-item .dcf-description{color:var(--dcf-color-gray-4)}ion-button{color:var(--dcf-color-gray-1)!important;--background: var(--dcf-color-gray-7) !important}ion-avatar{color:var(--dcf-color-gray-1)!important;background:var(--dcf-background-color)!important}ion-item-option:not(.dcf-delete),ion-item-option:not(.dcf-update){background:rgba(var(--dcf-color-dark-rgb),1)!important}ion-item-option:not(.dcf-delete) .dcf-ti,ion-item-option:not(.dcf-delete) ion-icon,ion-item-option:not(.dcf-update) .dcf-ti,ion-item-option:not(.dcf-update) ion-icon{color:var(--dcf-color-gray-2)!important}ion-item-option.dcf-delete{background:rgba(var(--dcf-color-danger-rgb),.05)!important}ion-item-option.dcf-delete .dcf-ti,ion-item-option.dcf-delete *,ion-item-option.dcf-delete ion-icon{color:var(--dcf-color-danger)!important}ion-item-option.dcf-update{background:rgba(var(--dcf-color-primary-rgb),.05)!important}ion-item-option.dcf-update .dcf-ti,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-item .dcf-icon ion-avatar{width:48px;height:48px;display:flex;justify-content:center;align-items:center;text-align:center}ion-item .dcf-icon ion-avatar ion-icon{font-size:20px}ion-item .dcf-icon 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" }] }); }
8343
8358
  };
8344
- ListComponent = __decorate([
8359
+ ListItemComponent = __decorate([
8345
8360
  Dynamic(),
8346
8361
  __metadata("design:paramtypes", [])
8347
- ], ListComponent);
8348
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ListComponent, decorators: [{
8362
+ ], ListItemComponent);
8363
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ListItemComponent, decorators: [{
8349
8364
  type: Component,
8350
- args: [{ selector: 'ngx-decaf-list', standalone: true, imports: [
8365
+ args: [{ selector: 'ngx-decaf-list-item', standalone: true, imports: [
8351
8366
  TranslatePipe,
8352
- IonRefresher,
8353
- IonLoading,
8354
- PaginationComponent,
8355
8367
  IonList,
8368
+ IonListHeader,
8356
8369
  IonItem,
8357
- IonThumbnail,
8358
- IonSkeletonText,
8370
+ IonItemSliding,
8371
+ IonItemOptions,
8372
+ IonItemOption,
8373
+ IonIcon,
8359
8374
  IonLabel,
8360
- IonText,
8361
- IonRefresherContent,
8362
- IonInfiniteScroll,
8363
- IonInfiniteScrollContent,
8364
- IonThumbnail,
8365
- IonSkeletonText,
8366
- SearchbarComponent,
8367
- EmptyStateComponent,
8368
- ListItemComponent,
8369
- FilterComponent,
8370
- ComponentRendererComponent
8371
- ], template: "\n@if(showRefresher) {\n <ion-refresher slot=\"fixed\" [pullFactor]=\"1\" [pullMin]=\"100\" [pullMax]=\"200\" (ionRefresh)=\"handleRefresh($event)\">\n <ion-refresher-content />\n </ion-refresher>\n}\n\n@if(showSearchbar && data?.length) {\n @if(model && enableFilter) {\n <ngx-decaf-filter\n [model]=\"model\"\n [sortDirection]=\"sortDirection\"\n [disableSort]=\"disableSort\"\n (filterEvent)=\"handleFilter($event)\"\n (searchEvent)=\"handleSearch($event)\"\n />\n } @else {\n <ngx-decaf-searchbar [emitEventToWindow]=\"false\" [debounce]=\"500\" (searchEvent)=\"handleSearch($event)\" />\n }\n}\n\n@if(data?.length) {\n <ion-list [id]=\"uid\" [inset]=\"inset\" [lines]=\"lines\" #component>\n @if(item?.tag) {\n @for(child of items; track trackItemFn($index, child)) {\n <ngx-decaf-component-renderer\n [tag]=\"item.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]='{\n item: child,\n mapper: mapper,\n route: route\n }'>\n </ngx-decaf-component-renderer>\n }\n } @else {\n <ng-content></ng-content>\n }\n </ion-list>\n\n @if(loadMoreData) {\n @if(pages > 0 && type === 'paginated' && !searchValue?.length) {\n <ngx-decaf-pagination\n [totalPages]=\"pages\"\n [current]=\"page\"\n (clickEvent)=\"handlePaginate($event)\"\n />\n\n } @else {\n <ion-infinite-scroll\n [class]=\"searchValue?.length ? 'dcf-hidden' : ''\"\n\n [position]=\"scrollPosition\"\n [threshold]=\"scrollThreshold\"\n (ionInfinite)=\"handleRefresh($event)\">\n <ion-infinite-scroll-content [loadingSpinner]=\"loadingSpinner\" [loadingText]=\"loadingText\" />\n </ion-infinite-scroll>\n }\n }\n} @else {\n @if(refreshing) {\n @for(skl of skeletonData; track $index) {\n <ion-item>\n <ion-thumbnail slot=\"start\">\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n </ion-thumbnail>\n <ion-label>\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n </ion-label>\n </ion-item>\n }\n\n } @else {\n @if(!searchValue?.length) {\n <ngx-decaf-empty-state\n [title]=\"(locale + '.'+ empty.title) | translate\"\n [subtitle]=\"(locale + '.'+ empty.subtitle) | translate\"\n [buttonText]=\"empty.showButton ? (locale + '.'+ empty.button | translate) : ''\"\n [buttonLink]=\"empty.showButton ? empty.route : ''\"\n />\n } @else {\n <ngx-decaf-empty-state\n icon=\"search-outline\"\n ngClass=\"empty-search\"\n [translatable]=\"true\"\n title=\"search.title\"\n subtitle=\"search.subtitle\"\n [searchValue]=\"searchValue\"\n />\n }\n }\n}\n\n", styles: ["ion-infinite-scroll{max-height:50px}ion-infinite-scroll:not(.infinite-scroll-loading) ::ng-deep{max-height:1.5rem}ion-infinite-scroll ::ng-deep ion-spinner{--color: var(--dcf-color-primary);padding-top:1rem}@media (max-width: 768px){#end,[slot=end]{display:none!important}}\n"] }]
8372
- }], ctorParameters: () => [], propDecorators: { type: [{
8373
- type: Input
8374
- }], translatable: [{
8375
- type: Input
8376
- }], showSearchbar: [{
8377
- type: Input
8378
- }], data: [{
8379
- type: Input
8380
- }], source: [{
8381
- type: Input
8382
- }], start: [{
8383
- type: Input
8384
- }], limit: [{
8385
- type: Input
8386
- }], loadMoreData: [{
8387
- type: Input
8375
+ IonButton,
8376
+ IonContent,
8377
+ IonPopover
8378
+ ], template: "\n@if(title || description) {\n <ion-item-sliding #component>\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 \">\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 <ion-label class=\"dcf-item-title\" [innerHTML]=\"uid + ' - ' + title\" ></ion-label>\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 <div class=\"dcf-visible@m\" id=\"dcf-actions\">\n <ion-button class=\"dcf-hidden@m\" 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: ["@media (prefers-color-scheme: light){ion-item{--background-hover-opacity: .1;--background-focused-opacity: .1;--border-color: var(--dcf-color-gray-2)}ion-item .dcf-info{color:var(--dcf-color-gray-6)}ion-item .dcf-item-title{color:var(--dcf-color-gray-8)}ion-item .dcf-description{color:var(--dcf-color-gray-6)}ion-button{color:var(--dcf-color-gray-7);--background: var(--dcf-color-gray-1) !important}ion-avatar{color:var(--dcf-color-gray-7);background:var(--dcf-color-gray-1)!important}ion-item-option:not(.dcf-delete),ion-item-option:not(.dcf-update){background:rgba(var(--dcf-color-dark-rgb),.25)!important}ion-item-option:not(.dcf-delete) .dcf-ti,ion-item-option:not(.dcf-delete) ion-icon,ion-item-option:not(.dcf-update) .dcf-ti,ion-item-option:not(.dcf-update) ion-icon{color:var(--dcf-color-gray-7)!important}ion-item-option.dcf-delete{background:rgba(var(--dcf-color-danger-rgb),.05)!important}ion-item-option.dcf-delete .dcf-ti,ion-item-option.dcf-delete *,ion-item-option.dcf-delete ion-icon{color:var(--dcf-color-danger)!important}ion-item-option.dcf-update{background:rgba(var(--dcf-color-primary-rgb),.05)!important}ion-item-option.dcf-update .dcf-ti,ion-item-option.dcf-update ion-icon{color:var(--dcf-color-primary)!important}}@media (prefers-color-scheme: dark){ion-item{--background-hover-opacity: .25;--background-focused-opacity: .25;--border-color: var(--dcf-color-gray-6)}ion-item .dcf-description{color:var(--dcf-color-gray-4)}ion-button{color:var(--dcf-color-gray-1)!important;--background: var(--dcf-color-gray-7) !important}ion-avatar{color:var(--dcf-color-gray-1)!important;background:var(--dcf-background-color)!important}ion-item-option:not(.dcf-delete),ion-item-option:not(.dcf-update){background:rgba(var(--dcf-color-dark-rgb),1)!important}ion-item-option:not(.dcf-delete) .dcf-ti,ion-item-option:not(.dcf-delete) ion-icon,ion-item-option:not(.dcf-update) .dcf-ti,ion-item-option:not(.dcf-update) ion-icon{color:var(--dcf-color-gray-2)!important}ion-item-option.dcf-delete{background:rgba(var(--dcf-color-danger-rgb),.05)!important}ion-item-option.dcf-delete .dcf-ti,ion-item-option.dcf-delete *,ion-item-option.dcf-delete ion-icon{color:var(--dcf-color-danger)!important}ion-item-option.dcf-update{background:rgba(var(--dcf-color-primary-rgb),.05)!important}ion-item-option.dcf-update .dcf-ti,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-item .dcf-icon ion-avatar{width:48px;height:48px;display:flex;justify-content:center;align-items:center;text-align:center}ion-item .dcf-icon ion-avatar ion-icon{font-size:20px}ion-item .dcf-icon ion-avatar .dcf-icon-large{transform:translateY(5px)}\n"] }]
8379
+ }], ctorParameters: () => [], propDecorators: { actionMenuComponent: [{
8380
+ type: ViewChild,
8381
+ args: ['actionMenuComponent']
8388
8382
  }], lines: [{
8389
8383
  type: Input
8390
- }], inset: [{
8391
- type: Input
8392
- }], scrollThreshold: [{
8393
- type: Input
8394
- }], scrollPosition: [{
8395
- type: Input
8396
- }], loadingText: [{
8397
- type: Input
8398
- }], showRefresher: [{
8384
+ }], item: [{
8399
8385
  type: Input
8400
- }], loadingSpinner: [{
8386
+ }], icon: [{
8401
8387
  type: Input
8402
- }], enableFilter: [{
8388
+ }], iconSlot: [{
8403
8389
  type: Input
8404
- }], sortDirection: [{
8390
+ }], button: [{
8405
8391
  type: Input
8406
- }], sortBy: [{
8392
+ }], title: [{
8407
8393
  type: Input
8408
- }], disableSort: [{
8394
+ }], description: [{
8409
8395
  type: Input
8410
- }], emptyIcon: [{
8396
+ }], info: [{
8411
8397
  type: Input
8412
- }], empty: [{
8398
+ }], subinfo: [{
8413
8399
  type: Input
8414
- }], refreshEvent: [{
8415
- type: Output
8416
8400
  }], clickEvent: [{
8417
8401
  type: Output
8418
- }], handleClick: [{
8419
- type: HostListener,
8420
- args: ['window:ListItemClickEvent', ['$event']]
8421
- }], handleSearch: [{
8422
- type: HostListener,
8423
- args: ['window:searchbarEvent', ['$event']]
8424
- }], refresh: [{
8402
+ }], enableSlideItems: [{
8425
8403
  type: HostListener,
8426
- args: ['window:BackButtonNavigationEndEvent', ['$event']]
8404
+ args: ['window:resize', ['$event']]
8427
8405
  }] } });
8428
8406
 
8429
8407
  let SteppedFormComponent = class SteppedFormComponent {
@@ -8446,6 +8424,17 @@ let SteppedFormComponent = class SteppedFormComponent {
8446
8424
  * @memberOf SteppedFormComponent
8447
8425
  */
8448
8426
  this.pages = 1;
8427
+ /**
8428
+ * List of titles and descriptions for each page of the stepped form.
8429
+ * Each object in the array represents a page, containing a title and a description.
8430
+ *
8431
+ * @example
8432
+ * pageTitles = [
8433
+ * { title: 'Personal Information', description: 'Fill in your personal details.' },
8434
+ * { title: 'Address', description: 'Provide your residential address.' }
8435
+ * ];
8436
+ */
8437
+ this.pageTitles = [];
8449
8438
  /**
8450
8439
  * @description The CRUD operation type for this form.
8451
8440
  * @summary Defines the type of operation being performed (CREATE, READ, UPDATE, DELETE).
@@ -8534,7 +8523,6 @@ let SteppedFormComponent = class SteppedFormComponent {
8534
8523
  *
8535
8524
  * A->>S: ngOnInit()
8536
8525
  * S->>S: Set activePage = startPage
8537
- * S->>S: Process children into pagesArray
8538
8526
  * S->>S: Calculate total pages
8539
8527
  * S->>S: Assign page props to children
8540
8528
  * S->>S: getCurrentFormGroup(activePage)
@@ -8547,14 +8535,9 @@ let SteppedFormComponent = class SteppedFormComponent {
8547
8535
  if (!this.locale)
8548
8536
  this.locale = getLocaleContext("SteppedFormComponent");
8549
8537
  this.activePage = this.startPage;
8550
- this.pagesArray = this.children.reduce((acc, curr, index) => {
8551
- const page = curr.props?.['page'] || index + 1;
8552
- if (!acc[page])
8553
- acc[page] = [];
8554
- acc[page].push({ index: page });
8555
- return acc;
8556
- }, []).filter(Boolean);
8557
- this.pages = this.pagesArray.length;
8538
+ if (!this.pageTitles.length)
8539
+ this.pageTitles = Array.from({ length: this.pages }, () => ({ title: '', description: '' }));
8540
+ this.pages = this.pageTitles.length;
8558
8541
  this.children = [...this.children.map((c) => {
8559
8542
  if (!c.props)
8560
8543
  c.props = {};
@@ -8563,6 +8546,7 @@ let SteppedFormComponent = class SteppedFormComponent {
8563
8546
  c.props['page'] = page > this.pages ? this.pages : page;
8564
8547
  return c;
8565
8548
  })];
8549
+ console.log(this.pageTitles);
8566
8550
  this.getCurrentFormGroup(this.activePage);
8567
8551
  }
8568
8552
  /**
@@ -8676,19 +8660,16 @@ let SteppedFormComponent = class SteppedFormComponent {
8676
8660
  getCurrentFormGroup(page) {
8677
8661
  this.activeFormGroup = this.formGroup.at(page - 1);
8678
8662
  this.activeChildren = undefined;
8679
- this.timerSubscription = timer(10).subscribe(() => {
8680
- this.activeChildren = this.children.filter(c => c.props?.['page'] === page);
8681
- console.log(this.activeChildren);
8682
- });
8663
+ this.timerSubscription = timer(10).subscribe(() => this.activeChildren = this.children.filter(c => c.props?.['page'] === page));
8683
8664
  }
8684
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SteppedFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8685
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: SteppedFormComponent, isStandalone: true, selector: "ngx-decaf-stepped-form", inputs: { locale: "locale", pages: "pages", operation: "operation", startPage: "startPage", children: "children", formGroup: "formGroup" }, outputs: { submitEvent: "submitEvent" }, ngImport: i0, template: "<form class=\"dcf-steped-form\" novalidate>\n <div class=\"dcf-page-steps\">\n <div>\n @for(page of pagesArray; track $index;) {\n <div [class.dcf-active]=\"activePage === $index + 1\" [class.dcf-passed]=\"($index + 1) < activePage\">{{ $index + 1 }}</div>\n }\n </div>\n </div>\n @if(formGroup) {\n @for(child of activeChildren; track $index) {\n <ngx-decaf-component-renderer\n [tag]=\"child?.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n }\n } @else {\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n <br />\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n }\n\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 fill=\"clear\" (click)=\"handleBack()\" [disabled]=\"activePage <= 1\">\n <ion-icon aria-hidden=\"true\" name=\"arrow-back-outline\"></ion-icon>\n {{locale + '.previous' | translate}}\n </ion-button>\n </div>\n\n <div class=\"dcf-width-1-2@s\">\n <ion-button [fill]=\"activePage === pages ? 'solid' : 'outline'\" (click)=\"handleNext(activePage === pages ? true : false)\">\n @if(activePage === pages) {\n {{locale + '.submit' | translate}}\n } @else {\n {{locale + '.next' | translate}}\n <ion-icon aria-hidden=\"true\" name=\"arrow-forward-outline\"></ion-icon>\n }\n </ion-button>\n </div>\n </div>\n</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{padding:2rem 1rem}.dcf-page-steps{display:flex;justify-content:center;margin-bottom:2rem}.dcf-page-steps>div{justify-content:center;min-width:200px;max-width:200px;column-gap:.25em;display:flex}.dcf-page-steps>div>div{width:30px;text-align:center;border-bottom:solid var(--dcf-color-gray-3);box-sizing:border-box;border-width:3px;font-size:0px;font-weight:600}.dcf-page-steps>div>div.dcf-active{border-width:5px;font-size:1rem;color:var(--ion-color-gray-7);border-color:var(--ion-color-primary);line-height:1rem}.dcf-page-steps>div>div.dcf-passed{border-width:4px;font-size:.5rem;line-height:1.2rem;border-color:var(--dcf-color-gray-5);color:var(--ion-color-primary)}\n"], dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }, { 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: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "children", "model", "parent"], outputs: ["listenEvent"] }] }); }
8665
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: SteppedFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8666
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.2", type: SteppedFormComponent, isStandalone: true, selector: "ngx-decaf-stepped-form", inputs: { locale: "locale", pages: "pages", pageTitles: "pageTitles", operation: "operation", startPage: "startPage", children: "children", formGroup: "formGroup" }, outputs: { submitEvent: "submitEvent" }, ngImport: i0, template: "<form class=\"dcf-steped-form\" novalidate>\n <div class=\"dcf-page-steps\">\n <div class=\"dcf-grid dcf-grid-collapse skip\">\n @for(page of pageTitles; track $index;) {\n <div class=\"dcf-flex dcf-flex-middle\">\n <div class=\"dcf-step\" [class.dcf-active]=\"activePage === $index + 1\" [class.dcf-passed]=\"($index + 1) < activePage\">{{ $index + 1 }}</div>\n @if((page?.title || page?.description)) {\n <div class=\"dcf-information dcf-visible@s\">\n @if(page?.title) {\n <div class=\"dcf-title\">{{ page?.title | translate }}</div>\n }\n @if(page?.description) {\n <div class=\"dcf-description\">{{ page?.description | translate }}</div>\n }\n <div class=\"dcf-separator\"></div>\n </div>\n }\n @if($index < pageTitles.length - 1) {\n <div class=\"dcf-arrow-container\">\n <svg width=\"8\" height=\"12\" viewBox=\"0 0 8 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M1.5 1L6.5 6L1.5 11\" />\n </svg>\n </div>\n }\n </div>\n }\n </div>\n </div>\n\n @if(pageTitles[activePage - 1]?.title || pageTitles[activePage - 1]?.description) {\n <div class=\"dcf-current-step\">\n <div>\n @if(pageTitles[activePage - 1]?.title) {\n <div class=\"dcf-title\">{{ pageTitles[activePage - 1]?.title | translate }}</div>\n }\n @if(pageTitles[activePage - 1]?.description) {\n <div class=\"dcf-description\">{{ pageTitles[activePage - 1]?.description | translate }}</div>\n }\n </div>\n </div>\n }\n\n\n @if(formGroup) {\n @for(child of activeChildren; track $index) {\n <ngx-decaf-component-renderer\n [tag]=\"child?.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n }\n } @else {\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n <br />\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n }\n\n <div class=\"dcf-buttons-container dcf-grid dcf-grid-collapse dcf-flex dcf-flex-left\">\n <div class=\"dcf-width-1-2@s\">\n <ion-button color=\"light\" (click)=\"handleBack()\" [disabled]=\"activePage <= 1\">\n <!-- <ion-icon aria-hidden=\"true\" name=\"arrow-back-outline\"></ion-icon> -->\n {{locale + '.previous' | translate}}\n </ion-button>\n </div>\n\n <div class=\"dcf-width-1-2@s\">\n <ion-button fill=\"solid\" (click)=\"handleNext(activePage === pages ? true : false)\">\n @if(activePage === pages) {\n {{locale + '.submit' | translate}}\n } @else {\n {{locale + '.next' | translate}}\n <!-- <ion-icon aria-hidden=\"true\" name=\"arrow-forward-outline\"></ion-icon> -->\n }\n </ion-button>\n </div>\n </div>\n</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{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}}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "component", type: IonSkeletonText, selector: "ion-skeleton-text", inputs: ["animated"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "children", "model", "parent"], outputs: ["listenEvent"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
8686
8667
  };
8687
8668
  SteppedFormComponent = __decorate([
8688
8669
  Dynamic(),
8689
8670
  __metadata("design:paramtypes", [])
8690
8671
  ], SteppedFormComponent);
8691
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SteppedFormComponent, decorators: [{
8672
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: SteppedFormComponent, decorators: [{
8692
8673
  type: Component,
8693
8674
  args: [{ selector: 'ngx-decaf-stepped-form', imports: [
8694
8675
  TranslatePipe,
@@ -8696,14 +8677,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
8696
8677
  IonSkeletonText,
8697
8678
  IonText,
8698
8679
  IonButton,
8699
- IonIcon,
8700
- ModelRendererComponent,
8701
8680
  ComponentRendererComponent
8702
- ], standalone: true, template: "<form class=\"dcf-steped-form\" novalidate>\n <div class=\"dcf-page-steps\">\n <div>\n @for(page of pagesArray; track $index;) {\n <div [class.dcf-active]=\"activePage === $index + 1\" [class.dcf-passed]=\"($index + 1) < activePage\">{{ $index + 1 }}</div>\n }\n </div>\n </div>\n @if(formGroup) {\n @for(child of activeChildren; track $index) {\n <ngx-decaf-component-renderer\n [tag]=\"child?.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n }\n } @else {\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n <br />\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n }\n\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 fill=\"clear\" (click)=\"handleBack()\" [disabled]=\"activePage <= 1\">\n <ion-icon aria-hidden=\"true\" name=\"arrow-back-outline\"></ion-icon>\n {{locale + '.previous' | translate}}\n </ion-button>\n </div>\n\n <div class=\"dcf-width-1-2@s\">\n <ion-button [fill]=\"activePage === pages ? 'solid' : 'outline'\" (click)=\"handleNext(activePage === pages ? true : false)\">\n @if(activePage === pages) {\n {{locale + '.submit' | translate}}\n } @else {\n {{locale + '.next' | translate}}\n <ion-icon aria-hidden=\"true\" name=\"arrow-forward-outline\"></ion-icon>\n }\n </ion-button>\n </div>\n </div>\n</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{padding:2rem 1rem}.dcf-page-steps{display:flex;justify-content:center;margin-bottom:2rem}.dcf-page-steps>div{justify-content:center;min-width:200px;max-width:200px;column-gap:.25em;display:flex}.dcf-page-steps>div>div{width:30px;text-align:center;border-bottom:solid var(--dcf-color-gray-3);box-sizing:border-box;border-width:3px;font-size:0px;font-weight:600}.dcf-page-steps>div>div.dcf-active{border-width:5px;font-size:1rem;color:var(--ion-color-gray-7);border-color:var(--ion-color-primary);line-height:1rem}.dcf-page-steps>div>div.dcf-passed{border-width:4px;font-size:.5rem;line-height:1.2rem;border-color:var(--dcf-color-gray-5);color:var(--ion-color-primary)}\n"] }]
8681
+ ], standalone: true, template: "<form class=\"dcf-steped-form\" novalidate>\n <div class=\"dcf-page-steps\">\n <div class=\"dcf-grid dcf-grid-collapse skip\">\n @for(page of pageTitles; track $index;) {\n <div class=\"dcf-flex dcf-flex-middle\">\n <div class=\"dcf-step\" [class.dcf-active]=\"activePage === $index + 1\" [class.dcf-passed]=\"($index + 1) < activePage\">{{ $index + 1 }}</div>\n @if((page?.title || page?.description)) {\n <div class=\"dcf-information dcf-visible@s\">\n @if(page?.title) {\n <div class=\"dcf-title\">{{ page?.title | translate }}</div>\n }\n @if(page?.description) {\n <div class=\"dcf-description\">{{ page?.description | translate }}</div>\n }\n <div class=\"dcf-separator\"></div>\n </div>\n }\n @if($index < pageTitles.length - 1) {\n <div class=\"dcf-arrow-container\">\n <svg width=\"8\" height=\"12\" viewBox=\"0 0 8 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M1.5 1L6.5 6L1.5 11\" />\n </svg>\n </div>\n }\n </div>\n }\n </div>\n </div>\n\n @if(pageTitles[activePage - 1]?.title || pageTitles[activePage - 1]?.description) {\n <div class=\"dcf-current-step\">\n <div>\n @if(pageTitles[activePage - 1]?.title) {\n <div class=\"dcf-title\">{{ pageTitles[activePage - 1]?.title | translate }}</div>\n }\n @if(pageTitles[activePage - 1]?.description) {\n <div class=\"dcf-description\">{{ pageTitles[activePage - 1]?.description | translate }}</div>\n }\n </div>\n </div>\n }\n\n\n @if(formGroup) {\n @for(child of activeChildren; track $index) {\n <ngx-decaf-component-renderer\n [tag]=\"child?.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n }\n } @else {\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n <br />\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n }\n\n <div class=\"dcf-buttons-container dcf-grid dcf-grid-collapse dcf-flex dcf-flex-left\">\n <div class=\"dcf-width-1-2@s\">\n <ion-button color=\"light\" (click)=\"handleBack()\" [disabled]=\"activePage <= 1\">\n <!-- <ion-icon aria-hidden=\"true\" name=\"arrow-back-outline\"></ion-icon> -->\n {{locale + '.previous' | translate}}\n </ion-button>\n </div>\n\n <div class=\"dcf-width-1-2@s\">\n <ion-button fill=\"solid\" (click)=\"handleNext(activePage === pages ? true : false)\">\n @if(activePage === pages) {\n {{locale + '.submit' | translate}}\n } @else {\n {{locale + '.next' | translate}}\n <!-- <ion-icon aria-hidden=\"true\" name=\"arrow-forward-outline\"></ion-icon> -->\n }\n </ion-button>\n </div>\n </div>\n</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{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}}\n"] }]
8703
8682
  }], ctorParameters: () => [], propDecorators: { locale: [{
8704
8683
  type: Input
8705
8684
  }], pages: [{
8706
8685
  type: Input
8686
+ }], pageTitles: [{
8687
+ type: Input
8707
8688
  }], operation: [{
8708
8689
  type: Input
8709
8690
  }], startPage: [{
@@ -8732,10 +8713,10 @@ class CollapsableDirective {
8732
8713
  }
8733
8714
  }
8734
8715
  }
8735
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CollapsableDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
8736
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.14", type: CollapsableDirective, isStandalone: true, selector: "[decafCollapsable]", ngImport: i0 }); }
8716
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: CollapsableDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
8717
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.2", type: CollapsableDirective, isStandalone: true, selector: "[decafCollapsable]", ngImport: i0 }); }
8737
8718
  }
8738
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CollapsableDirective, decorators: [{
8719
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: CollapsableDirective, decorators: [{
8739
8720
  type: Directive,
8740
8721
  args: [{
8741
8722
  selector: '[decafCollapsable]',
@@ -8761,8 +8742,8 @@ const Components = [
8761
8742
  SteppedFormComponent
8762
8743
  ];
8763
8744
  class ForAngularComponentsModule {
8764
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ForAngularComponentsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
8765
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.14", ngImport: i0, type: ForAngularComponentsModule, imports: [ModelRendererComponent,
8745
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ForAngularComponentsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
8746
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.2", ngImport: i0, type: ForAngularComponentsModule, imports: [ModelRendererComponent,
8766
8747
  ComponentRendererComponent,
8767
8748
  CrudFieldComponent,
8768
8749
  CrudFormComponent,
@@ -8789,7 +8770,7 @@ class ForAngularComponentsModule {
8789
8770
  LayoutComponent,
8790
8771
  FilterComponent,
8791
8772
  SteppedFormComponent, CollapsableDirective] }); }
8792
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ForAngularComponentsModule, imports: [CrudFieldComponent,
8773
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ForAngularComponentsModule, imports: [CrudFieldComponent,
8793
8774
  CrudFormComponent,
8794
8775
  EmptyStateComponent,
8795
8776
  ListComponent,
@@ -8801,7 +8782,7 @@ class ForAngularComponentsModule {
8801
8782
  FilterComponent,
8802
8783
  SteppedFormComponent] }); }
8803
8784
  }
8804
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ForAngularComponentsModule, decorators: [{
8785
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ForAngularComponentsModule, decorators: [{
8805
8786
  type: NgModule,
8806
8787
  args: [{
8807
8788
  imports: [...Components, ...Directives],
@@ -8825,5 +8806,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
8825
8806
  * Generated bundle index. Do not edit.
8826
8807
  */
8827
8808
 
8828
- export { AngularEngineKeys, BaseComponentProps, CollapsableDirective, ComponentRendererComponent, ComponentsTagNames, CrudFieldComponent, CrudFormComponent, CssClasses, DB_ADAPTER_PROVIDER_TOKEN, DefaultFormReactiveOptions, Dynamic, DynamicModule, EmptyStateComponent, EventConstants, FieldsetComponent, FilterComponent, ForAngularCommonModule, ForAngularComponentsModule, FormConstants, I18N_CONFIG_TOKEN, I18nLoader, I18nLoaderFactory, LayoutComponent, ListComponent, ListComponentsTypes, ListItemComponent, LoggerLevels, ModelRendererComponent, MultiI18nLoader, NgxBaseComponent, NgxCrudFormField, NgxFormService, NgxRenderingEngine, PaginationComponent, RouteDirections, SearchbarComponent, SteppedFormComponent, cleanSpaces, dataMapper, formatDate, generateRandomValue, getI18nLoaderFactoryProviderConfig, getInjectablesRegistry, getLocaleContext, getLocaleContextByKey, getLocaleFromClassName, getLocaleLanguage, getLogger, getOnWindow, getOnWindowDocument, getWindow, getWindowDocument, getWindowWidth, isDarkMode, isDevelopmentMode, isNotUndefined, isValidDate, itemMapper, parseToValidDate, removeFocusTrap, setOnWindow, stringToBoolean, windowEventEmitter };
8809
+ export { AngularEngineKeys, BaseComponentProps, CollapsableDirective, ComponentRendererComponent, ComponentsTagNames, CrudFieldComponent, CrudFormComponent, CssClasses, DB_ADAPTER_PROVIDER_TOKEN, DefaultFormReactiveOptions, Dynamic, DynamicModule, EmptyStateComponent, EventConstants, FieldsetComponent, FilterComponent, ForAngularCommonModule, ForAngularComponentsModule, FormConstants, I18N_CONFIG_TOKEN, I18nLoader, I18nLoaderFactory, LayoutComponent, ListComponent, ListComponentsTypes, ListItemComponent, LoggerLevels, ModelRendererComponent, NgxBaseComponent, NgxCrudFormField, NgxFormService, NgxRenderingEngine, PaginationComponent, RouteDirections, SearchbarComponent, SteppedFormComponent, cleanSpaces, dataMapper, formatDate, generateRandomValue, getInjectablesRegistry, getLocaleContext, getLocaleContextByKey, getLocaleFromClassName, getLocaleLanguage, getLogger, getOnWindow, getOnWindowDocument, getWindow, getWindowDocument, getWindowWidth, isDarkMode, isDevelopmentMode, isNotUndefined, isValidDate, itemMapper, parseToValidDate, provideDbAdapter, provideI18nLoader, removeFocusTrap, setOnWindow, stringToBoolean, windowEventEmitter };
8829
8810
  //# sourceMappingURL=decaf-ts-for-angular.mjs.map