@decaf-ts/for-angular 0.0.24 → 0.0.26

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 +1512 -1517
  2. package/fesm2022/decaf-ts-for-angular.mjs.map +1 -1
  3. package/index.d.ts +7470 -3
  4. package/package.json +14 -17
  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/steped-form/steped-form.component.d.ts +0 -243
  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/steped-form/steped-form.component.mjs +0 -291
  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 -80
  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,
@@ -2382,10 +2392,10 @@ class ComponentRendererComponent {
2382
2392
  }
2383
2393
  }
2384
2394
  }
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"] }] }); }
2395
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ComponentRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2396
+ 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
2397
  }
2388
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ComponentRendererComponent, decorators: [{
2398
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ComponentRendererComponent, decorators: [{
2389
2399
  type: Component,
2390
2400
  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
2401
  }], ctorParameters: () => [], propDecorators: { vcr: [{
@@ -2648,6 +2658,11 @@ var component = {
2648
2658
  step3: "Type a value",
2649
2659
  no_suggestions: "No suggestions",
2650
2660
  sort: "Sort by"
2661
+ },
2662
+ stepped_form: {
2663
+ next: "Next",
2664
+ previous: "Previous",
2665
+ submit: "Submit"
2651
2666
  }
2652
2667
  };
2653
2668
  var en = {
@@ -2655,20 +2670,6 @@ var en = {
2655
2670
  component: component
2656
2671
  };
2657
2672
 
2658
- class I18nLoader {
2659
- static loadFromHttp(http) {
2660
- function getSuffix() {
2661
- const today = new Date();
2662
- return `.json?version=${today.getFullYear()}${today.getMonth()}${today.getDay()}`;
2663
- }
2664
- return new (class extends TranslateHttpLoader {
2665
- getTranslation(lang) {
2666
- const res = super.getTranslation(lang);
2667
- return res;
2668
- }
2669
- })(http, './assets/i18n/', getSuffix());
2670
- }
2671
- }
2672
2673
  function getLocaleContext(clazz, suffix) {
2673
2674
  return getLocaleFromClassName(clazz, suffix);
2674
2675
  }
@@ -2695,22 +2696,21 @@ function getLocaleContextByKey(locale, phrase) {
2695
2696
  return `${locale}.${cleanSpaces(parts.join('.'), true)}`;
2696
2697
  }
2697
2698
  function I18nLoaderFactory(http) {
2698
- const { resources, versionedSuffix } = inject(I18N_CONFIG_TOKEN, { optional: true }) ?? getI18nLoaderFactoryProviderConfig().useValue;
2699
- return new MultiI18nLoader(http, resources, versionedSuffix);
2699
+ const { resources, versionedSuffix } = inject(I18N_CONFIG_TOKEN, { optional: true }) ?? provideI18nLoader().useValue;
2700
+ return new I18nLoader(http, resources?.length ? resources : [{ prefix: './app/assets/i18n/', suffix: '.json' }], versionedSuffix);
2700
2701
  }
2701
- function getI18nLoaderFactoryProviderConfig(resources = [], versionedSuffix = false) {
2702
+ function provideI18nLoader(resources = [], versionedSuffix = false) {
2702
2703
  if (!Array.isArray(resources))
2703
2704
  resources = [resources];
2704
2705
  return {
2705
2706
  provide: I18N_CONFIG_TOKEN,
2706
2707
  useValue: { resources: [
2707
- // { prefix: './assets/i18n/', suffix: '.json' },
2708
2708
  ...resources
2709
2709
  ], versionedSuffix }
2710
2710
  };
2711
2711
  }
2712
2712
  const libLanguage = { en };
2713
- class MultiI18nLoader {
2713
+ class I18nLoader {
2714
2714
  constructor(http, resources = [], versionedSuffix = false) {
2715
2715
  this.http = http;
2716
2716
  this.resources = resources;
@@ -3096,13 +3096,13 @@ let CrudFieldComponent = class CrudFieldComponent extends NgxCrudFormField {
3096
3096
  });
3097
3097
  component.dispatchEvent(event);
3098
3098
  }
3099
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CrudFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
3100
- 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"] }] }); }
3099
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: CrudFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
3100
+ 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" }] }); }
3101
3101
  };
3102
3102
  CrudFieldComponent = __decorate([
3103
3103
  Dynamic()
3104
3104
  ], CrudFieldComponent);
3105
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CrudFieldComponent, decorators: [{
3105
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: CrudFieldComponent, decorators: [{
3106
3106
  type: Component,
3107
3107
  args: [{ standalone: true, imports: [
3108
3108
  ReactiveFormsModule,
@@ -3116,9 +3116,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
3116
3116
  IonSelectOption,
3117
3117
  IonLabel,
3118
3118
  IonText,
3119
- IonTextarea,
3120
- IonIcon
3121
- ], 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"] }]
3119
+ IonTextarea
3120
+ ], 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"] }]
3122
3121
  }], propDecorators: { operation: [{
3123
3122
  type: Input,
3124
3123
  args: [{ required: true }]
@@ -3738,10 +3737,10 @@ class NgxBaseComponent {
3738
3737
  if (!this.initialized)
3739
3738
  this.initialized = true;
3740
3739
  }
3741
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NgxBaseComponent, deps: [{ token: 'instanceToken' }], target: i0.ɵɵFactoryTarget.Component }); }
3742
- 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 }); }
3740
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NgxBaseComponent, deps: [{ token: 'instanceToken' }], target: i0.ɵɵFactoryTarget.Component }); }
3741
+ 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 }); }
3743
3742
  }
3744
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NgxBaseComponent, decorators: [{
3743
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: NgxBaseComponent, decorators: [{
3745
3744
  type: Component,
3746
3745
  args: [{
3747
3746
  standalone: true,
@@ -4010,13 +4009,13 @@ let CrudFormComponent = class CrudFormComponent {
4010
4009
  name: EventConstants.SUBMIT,
4011
4010
  });
4012
4011
  }
4013
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CrudFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4014
- 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"] }] }); }
4012
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: CrudFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4013
+ 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"] }] }); }
4015
4014
  };
4016
4015
  CrudFormComponent = __decorate([
4017
4016
  Dynamic()
4018
4017
  ], CrudFormComponent);
4019
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CrudFormComponent, decorators: [{
4018
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: CrudFormComponent, decorators: [{
4020
4019
  type: Component,
4021
4020
  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"] }]
4022
4021
  }], propDecorators: { model: [{
@@ -4342,17 +4341,16 @@ let EmptyStateComponent = class EmptyStateComponent extends NgxBaseComponent {
4342
4341
  const result = await this.translate.instant(content, { 'value0': this.searchValue });
4343
4342
  return this.sanitizer.bypassSecurityTrustHtml(result);
4344
4343
  }
4345
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: EmptyStateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4346
- 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"] }] }); }
4344
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: EmptyStateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4345
+ 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"] }] }); }
4347
4346
  };
4348
4347
  EmptyStateComponent = __decorate([
4349
4348
  Dynamic(),
4350
4349
  __metadata("design:paramtypes", [])
4351
4350
  ], EmptyStateComponent);
4352
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: EmptyStateComponent, decorators: [{
4351
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: EmptyStateComponent, decorators: [{
4353
4352
  type: Component,
4354
4353
  args: [{ selector: 'ngx-decaf-empty-state', standalone: true, imports: [
4355
- TranslatePipe,
4356
4354
  IonCard,
4357
4355
  IonCardContent,
4358
4356
  IonIcon
@@ -4996,14 +4994,14 @@ let FieldsetComponent = class FieldsetComponent extends NgxBaseComponent {
4996
4994
  }
4997
4995
  return this.mapper;
4998
4996
  }
4999
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FieldsetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
5000
- 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"] }] }); }
4997
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: FieldsetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4998
+ 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" }] }); }
5001
4999
  };
5002
5000
  FieldsetComponent = __decorate([
5003
5001
  Dynamic(),
5004
5002
  __metadata("design:paramtypes", [])
5005
5003
  ], FieldsetComponent);
5006
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FieldsetComponent, decorators: [{
5004
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: FieldsetComponent, decorators: [{
5007
5005
  type: Component,
5008
5006
  args: [{ standalone: true, selector: 'ngx-decaf-fieldset', schemas: [], imports: [
5009
5007
  TranslatePipe,
@@ -5018,7 +5016,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
5018
5016
  IonReorderGroup,
5019
5017
  IonButton,
5020
5018
  IonIcon,
5021
- ], 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"] }]
5019
+ ], 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"] }]
5022
5020
  }], ctorParameters: () => [], propDecorators: { accordionComponent: [{
5023
5021
  type: ViewChild,
5024
5022
  args: ['accordionComponent', { static: false }]
@@ -5476,10 +5474,10 @@ class SearchbarComponent extends NgxBaseComponent {
5476
5474
  preventChange(event) {
5477
5475
  event.preventDefault();
5478
5476
  }
5479
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SearchbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
5480
- 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"] }] }); }
5477
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: SearchbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
5478
+ 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"] }] }); }
5481
5479
  }
5482
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SearchbarComponent, decorators: [{
5480
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: SearchbarComponent, decorators: [{
5483
5481
  type: Component,
5484
5482
  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" }]
5485
5483
  }], ctorParameters: () => [], propDecorators: { autocomplete: [{
@@ -6178,20 +6176,18 @@ let FilterComponent = class FilterComponent extends NgxBaseComponent {
6178
6176
  handleSearch(value) {
6179
6177
  this.searchEvent.emit(value);
6180
6178
  }
6181
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FilterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6182
- 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"] }] }); }
6179
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: FilterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6180
+ 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" }] }); }
6183
6181
  };
6184
6182
  FilterComponent = __decorate([
6185
6183
  Dynamic(),
6186
6184
  __metadata("design:paramtypes", [])
6187
6185
  ], FilterComponent);
6188
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FilterComponent, decorators: [{
6186
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: FilterComponent, decorators: [{
6189
6187
  type: Component,
6190
6188
  args: [{ selector: 'ngx-decaf-filter', imports: [
6191
6189
  FormsModule,
6192
6190
  TranslatePipe,
6193
- IonLabel,
6194
- IonItem,
6195
6191
  IonChip,
6196
6192
  IonIcon,
6197
6193
  IonButton,
@@ -6199,7 +6195,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
6199
6195
  IonSelectOption,
6200
6196
  IonIcon,
6201
6197
  SearchbarComponent
6202
- ], 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"] }]
6198
+ ], 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"] }]
6203
6199
  }], ctorParameters: () => [], propDecorators: { optionsFilterElement: [{
6204
6200
  type: ViewChild,
6205
6201
  args: ['optionsFilterElement', { read: ElementRef, static: false }]
@@ -6330,10 +6326,10 @@ class ModelRendererComponent {
6330
6326
  }
6331
6327
  }
6332
6328
  }
6333
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ModelRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6334
- 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"] }] }); }
6329
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ModelRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6330
+ 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"] }] }); }
6335
6331
  }
6336
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ModelRendererComponent, decorators: [{
6332
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ModelRendererComponent, decorators: [{
6337
6333
  type: Component,
6338
6334
  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" }]
6339
6335
  }], propDecorators: { model: [{
@@ -6483,10 +6479,10 @@ class LayoutComponent extends NgxBaseComponent {
6483
6479
  this.rows = this._rows;
6484
6480
  this.initialized = true;
6485
6481
  }
6486
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6487
- 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"] }] }); }
6482
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: LayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6483
+ 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" }] }); }
6488
6484
  }
6489
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LayoutComponent, decorators: [{
6485
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: LayoutComponent, decorators: [{
6490
6486
  type: Component,
6491
6487
  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"] }]
6492
6488
  }], ctorParameters: () => [], propDecorators: { cols: [{
@@ -6500,857 +6496,466 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
6500
6496
  }] } });
6501
6497
 
6502
6498
  /**
6503
- * @description A component for displaying a list item with various customization options.
6504
- * @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.
6505
- *
6506
- * @class
6507
- * @extends NgxBaseComponent
6508
- *
6509
- * @param {string} [lines='none'] - Determines the line style of the item. Can be 'inset', 'inseet', or 'none'.
6510
- * @param {Record<string, any>} item - The data item to be displayed in the list item.
6511
- * @param {string} icon - The name of the icon to be displayed.
6512
- * @param {'start' | 'end'} [iconSlot='start'] - The position of the icon within the item.
6513
- * @param {StringOrBoolean} [button=true] - Determines if the item should behave as a button.
6514
- * @param {string} [title] - The main title of the list item.
6515
- * @param {string} [description] - A description for the list item.
6516
- * @param {string} [info] - Additional information for the list item.
6517
- * @param {string} [subinfo] - Sub-information for the list item.
6499
+ * @description A pagination component for navigating through multiple pages of content.
6500
+ * @summary This component provides a user interface for paginated content navigation,
6501
+ * displaying page numbers and navigation controls. It supports customizable page counts,
6502
+ * current page tracking, and emits events when users navigate between pages.
6518
6503
  *
6519
- * @example
6520
- * <ngx-decaf-list-item
6521
- * [item]="dataItem"
6522
- * icon="star"
6523
- * title="Item Title"
6524
- * description="Item Description"
6525
- * (clickEvent)="handleItemClick($event)">
6526
- * </ngx-decaf-list-item>
6504
+ * The component intelligently handles large numbers of pages by showing a subset of page
6505
+ * numbers with ellipses to indicate skipped pages, ensuring the UI remains clean and usable
6506
+ * even with many pages.
6527
6507
  *
6528
6508
  * @mermaid
6529
6509
  * sequenceDiagram
6530
- * participant C as Component
6531
- * participant V as View
6532
6510
  * participant U as User
6533
- * C->>V: Initialize component
6534
- * V->>U: Display list item
6535
- * U->>V: Click on item or action
6536
- * V->>C: Trigger handleAction()
6537
- * C->>C: Process action
6538
- * C->>V: Update view or navigate
6511
+ * participant P as PaginationComponent
6512
+ * participant E as External Component
6513
+ *
6514
+ * U->>P: Click page number
6515
+ * P->>P: navigate(page)
6516
+ * P->>P: handleClick(direction, page)
6517
+ * P->>E: Emit clickEvent with PaginationCustomEvent
6518
+ *
6519
+ * U->>P: Click next button
6520
+ * P->>P: next()
6521
+ * P->>P: handleClick('next')
6522
+ * P->>E: Emit clickEvent with PaginationCustomEvent
6523
+ *
6524
+ * U->>P: Click previous button
6525
+ * P->>P: previous()
6526
+ * P->>P: handleClick('previous')
6527
+ * P->>E: Emit clickEvent with PaginationCustomEvent
6528
+ *
6529
+ * @example
6530
+ * <ngx-decaf-pagination
6531
+ * [pages]="10"
6532
+ * [current]="3"
6533
+ * (clickEvent)="handlePageChange($event)">
6534
+ * </ngx-decaf-pagination>
6535
+ *
6536
+ * @extends {NgxBaseComponent}
6537
+ * @implements {OnInit}
6539
6538
  */
6540
- let ListItemComponent = class ListItemComponent extends NgxBaseComponent {
6539
+ class PaginationComponent extends NgxBaseComponent {
6541
6540
  /**
6542
- * @description Creates an instance of ListItemComponent.
6543
- * @summary Initializes a new ListItemComponent by calling the parent class constructor
6544
- * with the component name for logging and identification purposes. Also registers
6545
- * all available Ionic icons to ensure they can be displayed in the component.
6546
- *
6547
- * @memberOf ListItemComponent
6541
+ * @constructor
6542
+ * @description Initializes a new instance of the PaginationComponent.
6543
+ * Calls the parent constructor with the component name for generate base locale string.
6548
6544
  */
6549
6545
  constructor() {
6550
- super("ListItemComponent");
6551
- /**
6552
- * @description Controls the display of lines around the list item.
6553
- * @summary Determines how lines are displayed around the list item borders.
6554
- * 'inset' shows lines with padding, 'full' shows full-width lines, and 'none'
6555
- * removes all lines. This affects the visual separation between list items.
6556
- *
6557
- * @type {'inset' | 'full' | 'none'}
6558
- * @default 'inset'
6559
- * @memberOf ListItemComponent
6560
- */
6561
- this.lines = 'full';
6562
- /**
6563
- * @description Position of the icon within the list item.
6564
- * @summary Determines whether the icon appears at the start (left in LTR languages)
6565
- * or end (right in LTR languages) of the list item. This affects the overall
6566
- * layout and visual hierarchy of the item content.
6567
- *
6568
- * @type {'start' | 'end'}
6569
- * @default 'start'
6570
- * @memberOf ListItemComponent
6571
- */
6572
- this.iconSlot = 'start';
6546
+ super("PaginationComponent");
6573
6547
  /**
6574
- * @description Controls whether the list item behaves as a clickable button.
6575
- * @summary When set to true, the list item will have button-like behavior including
6576
- * hover effects, click handling, and appropriate accessibility attributes.
6577
- * When false, the item is displayed as static content without interactive behavior.
6548
+ * @description Controls whether the component uses translation services.
6549
+ * @summary When set to true, the component will attempt to use translation services
6550
+ * for any text content. This allows for internationalization of the pagination component.
6578
6551
  *
6579
6552
  * @type {StringOrBoolean}
6580
6553
  * @default true
6581
- * @memberOf ListItemComponent
6582
- */
6583
- this.button = true;
6584
- /**
6585
- * @description Event emitter for list item click interactions.
6586
- * @summary Emits custom events when the list item is clicked or when actions
6587
- * are performed on it. The emitted event contains information about the action,
6588
- * the item data, and other relevant context for parent components to handle.
6589
- *
6590
- * @type {EventEmitter<ListItemCustomEvent>}
6591
- * @memberOf ListItemComponent
6592
- */
6593
- this.clickEvent = new EventEmitter();
6594
- /**
6595
- * @description Flag indicating whether slide items are currently enabled.
6596
- * @summary Controls the visibility of slide actions based on screen size and
6597
- * available operations. When true, users can swipe on the item to reveal
6598
- * action buttons for operations like edit and delete.
6599
- *
6600
- * @type {boolean}
6601
- * @default false
6602
- * @memberOf ListItemComponent
6554
+ * @memberOf PaginationComponent
6603
6555
  */
6604
- this.showSlideItems = false;
6556
+ this.translatable = true;
6605
6557
  /**
6606
- * @description Flag indicating whether the action menu popover is currently open.
6607
- * @summary Tracks the state of the action menu to prevent multiple instances
6608
- * from being opened simultaneously and to ensure proper cleanup when actions
6609
- * are performed. Used for managing the popover lifecycle.
6558
+ * @description The currently active page number.
6559
+ * @summary Specifies which page is currently active or selected. This value is used
6560
+ * to highlight the current page in the UI and as a reference point for navigation.
6610
6561
  *
6611
- * @type {boolean}
6612
- * @default false
6613
- * @memberOf ListItemComponent
6562
+ * @type {number}
6563
+ * @default 1
6564
+ * @memberOf PaginationComponent
6614
6565
  */
6615
- this.actionMenuOpen = false;
6566
+ this.current = 1;
6616
6567
  /**
6617
- * @description Angular NavController service for handling navigation.
6618
- * @summary Injected service that provides methods for programmatic navigation
6619
- * within the Ionic application. Used for navigating to different routes when
6620
- * list item actions are performed or when the item itself is clicked.
6568
+ * @description Event emitter for pagination navigation events.
6569
+ * @summary Emits a custom event when users navigate between pages, either by clicking
6570
+ * on page numbers or using the next/previous buttons. The event contains information
6571
+ * about the navigation direction and the target page number.
6621
6572
  *
6622
- * @private
6623
- * @type {NavController}
6624
- * @memberOf ListItemComponent
6573
+ * @type {EventEmitter<PaginationCustomEvent>}
6574
+ * @memberOf PaginationComponent
6625
6575
  */
6626
- this.navController = inject(NavController);
6627
- addIcons(allIcons);
6576
+ this.clickEvent = new EventEmitter();
6577
+ addIcons({ chevronBackOutline, chevronForwardOutline });
6628
6578
  }
6629
6579
  /**
6630
- * @description Initializes the component after Angular first displays the data-bound properties.
6631
- * @summary Sets up the component by determining slide item visibility, processing boolean inputs,
6632
- * building CSS class names based on properties, and capturing the current window width.
6633
- * This method prepares the component for user interaction by ensuring all properties are
6634
- * properly initialized and responsive behavior is configured.
6580
+ * @description Initializes the component after Angular sets the input properties.
6581
+ * @summary Sets up the component by initializing the locale settings based on the
6582
+ * translatable property, generating the page numbers based on the total pages and
6583
+ * current page, and storing the last page number for boundary checking.
6635
6584
  *
6636
6585
  * @mermaid
6637
6586
  * sequenceDiagram
6638
6587
  * participant A as Angular Lifecycle
6639
- * participant L as ListItemComponent
6640
- * participant W as Window
6588
+ * participant P as PaginationComponent
6641
6589
  *
6642
- * A->>L: ngOnInit()
6643
- * L->>L: enableSlideItems()
6644
- * L->>L: Process button boolean
6645
- * L->>L: Build className with flex classes
6646
- * alt operations exist
6647
- * L->>L: Add 'action' class
6648
- * end
6649
- * L->>W: getWindowWidth()
6650
- * W-->>L: Return current width
6651
- * L->>L: Store windowWidth
6590
+ * A->>P: ngOnInit()
6591
+ * P->>P: getLocale(translatable)
6592
+ * P->>P: Set locale
6593
+ * P->>P: getPages(data, current)
6594
+ * P->>P: Set pages array
6595
+ * P->>P: Set last page number
6652
6596
  *
6653
- * @return {Promise<void>}
6654
- * @memberOf ListItemComponent
6597
+ * @returns {void}
6598
+ * @memberOf PaginationComponent
6655
6599
  */
6656
- async ngOnInit() {
6657
- this.showSlideItems = this.enableSlideItems();
6658
- this.button = stringToBoolean(this.button);
6659
- this.className = `${this.className} dcf-flex dcf-flex-middle grid-item`;
6660
- if (this.operations?.length)
6661
- this.className += ` action`;
6662
- this.windowWidth = getWindowWidth();
6600
+ ngOnInit() {
6601
+ this.locale = this.getLocale(this.translatable);
6602
+ this.pages = this.getPages(this.totalPages, this.current);
6603
+ this.last = this.totalPages;
6663
6604
  }
6664
6605
  /**
6665
- * @description Handles user interactions and actions performed on the list item.
6666
- * @summary This method is the central action handler for list item interactions. It manages
6667
- * event propagation, dismisses open action menus, removes focus traps, and either emits
6668
- * events for parent components to handle or performs navigation based on the component's
6669
- * route configuration. This method supports both event-driven and navigation-driven architectures.
6606
+ * @description Handles click events on pagination controls.
6607
+ * @summary Processes user interactions with the pagination component, updating the
6608
+ * current page if specified and emitting an event with navigation details. This method
6609
+ * is called when users click on page numbers or navigation buttons.
6670
6610
  *
6671
- * @param {CrudOperations} action - The type of CRUD operation being performed
6672
- * @param {Event} event - The browser event that triggered the action
6673
- * @param {HTMLElement} [target] - Optional target element for the event
6674
- * @return {Promise<boolean|void>} A promise that resolves to navigation success or void for events
6611
+ * @param {('next' | 'previous')} direction - The direction of navigation
6612
+ * @param {number} [page] - Optional page number to navigate to directly
6613
+ * @returns {void}
6675
6614
  *
6676
6615
  * @mermaid
6677
6616
  * sequenceDiagram
6678
6617
  * participant U as User
6679
- * participant L as ListItemComponent
6680
- * participant P as Parent Component
6681
- * participant N as NavController
6682
- * participant E as Event System
6618
+ * participant P as PaginationComponent
6619
+ * participant E as External Component
6683
6620
  *
6684
- * U->>L: Perform action (click/swipe)
6685
- * L->>L: stopImmediatePropagation()
6686
- * alt actionMenuOpen
6687
- * L->>L: Dismiss action menu
6688
- * end
6689
- * L->>L: removeFocusTrap()
6690
- * alt No route configured
6691
- * L->>E: windowEventEmitter()
6692
- * L->>P: clickEvent.emit()
6693
- * else Route configured
6694
- * L->>N: redirect(action, uid)
6695
- * N-->>L: Return navigation result
6621
+ * U->>P: Click pagination control
6622
+ * P->>P: handleClick(direction, page?)
6623
+ * alt page is provided
6624
+ * P->>P: Update current page
6696
6625
  * end
6626
+ * P->>E: Emit clickEvent with direction and page
6697
6627
  *
6698
- * @memberOf ListItemComponent
6628
+ * @memberOf PaginationComponent
6699
6629
  */
6700
- async handleAction(action, event, target) {
6701
- event.stopImmediatePropagation();
6702
- if (this.actionMenuOpen)
6703
- await this.actionMenuComponent.dismiss();
6704
- // forcing trap focus
6705
- removeFocusTrap();
6706
- if (!this.route) {
6707
- const event = { target: target, action, pk: this.pk, data: this.uid, name: EventConstants.CLICK, component: this.componentName };
6708
- windowEventEmitter(`ListItem${EventConstants.CLICK}`, event);
6709
- return this.clickEvent.emit(event);
6710
- }
6711
- return await this.redirect(action, (typeof this.uid === 'number' ? `${this.uid}` : this.uid));
6630
+ handleClick(direction, page) {
6631
+ if (page)
6632
+ this.current = page;
6633
+ this.clickEvent.emit({
6634
+ name: EventConstants.CLICK,
6635
+ data: {
6636
+ direction,
6637
+ page: this.current
6638
+ },
6639
+ component: this.componentName
6640
+ });
6712
6641
  }
6713
6642
  /**
6714
- * @description Responsive handler that enables or disables slide items based on screen size and operations.
6715
- * @summary This method is automatically called when the window is resized and also during component
6716
- * initialization. It determines whether slide actions should be available based on the current
6717
- * window width and the presence of UPDATE or DELETE operations. Slide items are typically hidden
6718
- * on larger screens where there's space for dedicated action buttons.
6643
+ * @description Generates the array of page objects for display.
6644
+ * @summary Creates an array of page objects based on the total number of pages and
6645
+ * the current page. For small page counts (≤5), all pages are shown. For larger page
6646
+ * counts, a subset is shown with ellipses to indicate skipped pages. This ensures
6647
+ * the pagination UI remains clean and usable even with many pages.
6719
6648
  *
6720
- * @return {boolean} True if slide items should be shown, false otherwise
6649
+ * @param {number} total - The total number of pages
6650
+ * @param {number} [current] - The current active page (defaults to this.current)
6651
+ * @returns {KeyValue[]} Array of page objects with index and text properties
6721
6652
  *
6722
6653
  * @mermaid
6723
- * sequenceDiagram
6724
- * participant W as Window
6725
- * participant L as ListItemComponent
6726
- * participant U as UI
6654
+ * flowchart TD
6655
+ * A[Start] --> B{total <= 5?}
6656
+ * B -->|Yes| C[Show all pages]
6657
+ * B -->|No| D[Show first page]
6658
+ * D --> E[Show last pages]
6659
+ * E --> F[Add ellipses for skipped pages]
6660
+ * C --> G[Return pages array]
6661
+ * F --> G
6727
6662
  *
6728
- * W->>L: resize event
6729
- * L->>W: getWindowWidth()
6730
- * W-->>L: Return current width
6731
- * L->>L: Store windowWidth
6732
- * alt No operations OR width > 639px
6733
- * L->>U: showSlideItems = false
6734
- * else Operations include UPDATE/DELETE
6735
- * L->>U: showSlideItems = true
6736
- * end
6737
- * L-->>U: Return showSlideItems value
6663
+ * @memberOf PaginationComponent
6664
+ */
6665
+ getPages(total, current) {
6666
+ if (!current)
6667
+ current = this.current;
6668
+ const pages = [];
6669
+ function getPage(index, text = '', clazz = 'button') {
6670
+ if (pages.some(item => item['index'] === index))
6671
+ return;
6672
+ pages.push({ index, text: index != null ? index.toString().padStart(2, '0') : text, class: clazz });
6673
+ }
6674
+ if (total <= 5) {
6675
+ for (let i = 1; i <= total; i++)
6676
+ getPage(i);
6677
+ }
6678
+ else {
6679
+ // Adiciona os dois primeiros
6680
+ getPage(1);
6681
+ getPage(2);
6682
+ // Adiciona "..." entre os blocos
6683
+ if (current && current > 3)
6684
+ getPage(null, '...');
6685
+ // Adiciona a página atual (se estiver no meio)
6686
+ if (current && current > 2 && current < total - 1)
6687
+ getPage(current);
6688
+ // Adiciona "..." entre os blocos
6689
+ if (current && current < total - 2)
6690
+ getPage(null, '...', 'separator');
6691
+ // Adiciona os dois últimos
6692
+ getPage(total - 1);
6693
+ getPage(total);
6694
+ }
6695
+ return pages;
6696
+ }
6697
+ /**
6698
+ * @description Gets the current active page number.
6699
+ * @summary Returns the current page number that is active in the pagination component.
6700
+ * This method provides a way to access the current page state from outside the component.
6738
6701
  *
6739
- * @memberOf ListItemComponent
6702
+ * @returns {number} The current page number
6703
+ * @memberOf PaginationComponent
6740
6704
  */
6741
- enableSlideItems() {
6742
- this.windowWidth = getWindowWidth();
6743
- if (!this.operations?.length || this.windowWidth > 639)
6744
- return this.showSlideItems = false;
6745
- this.showSlideItems = this.operations.includes(OperationKeys.UPDATE) || this.operations.includes(OperationKeys.DELETE);
6746
- return this.showSlideItems;
6705
+ getCurrent() {
6706
+ return this.current;
6747
6707
  }
6748
6708
  /**
6749
- * @description Animates and removes an element from the DOM.
6750
- * @summary This method applies CSS animation classes to create a smooth fade-out effect
6751
- * before removing the element from the DOM. The animation enhances user experience by
6752
- * providing visual feedback when items are deleted or removed from lists. The timing
6753
- * is coordinated with the CSS animation duration to ensure the element is removed
6754
- * after the animation completes.
6709
+ * @description Navigates to the next page.
6710
+ * @summary Increments the current page number if not at the last page and triggers
6711
+ * the click event handler with 'next' direction. This method is typically called
6712
+ * when the user clicks on the "next" button in the pagination UI.
6755
6713
  *
6756
- * @param {HTMLElement} element - The DOM element to animate and remove
6757
- * @return {void}
6714
+ * @returns {void}
6758
6715
  *
6759
6716
  * @mermaid
6760
6717
  * sequenceDiagram
6761
- * participant L as ListItemComponent
6762
- * participant E as HTMLElement
6763
- * participant D as DOM
6718
+ * participant U as User
6719
+ * participant P as PaginationComponent
6764
6720
  *
6765
- * L->>E: Add animation classes
6766
- * Note over E: uk-animation-fade, uk-animation-medium, uk-animation-reverse
6767
- * E->>E: Start fade animation
6768
- * L->>L: setTimeout(600ms)
6769
- * Note over L: Wait for animation to complete
6770
- * L->>D: element.remove()
6771
- * D->>D: Remove element from DOM
6721
+ * U->>P: Click next button
6722
+ * P->>P: next()
6723
+ * alt page <= max pages
6724
+ * P->>P: Increment current page
6725
+ * P->>P: handleClick('next')
6726
+ * end
6772
6727
  *
6773
- * @memberOf ListItemComponent
6728
+ * @memberOf PaginationComponent
6774
6729
  */
6775
- removeElement(element) {
6776
- element.classList.add('uk-animation-fade', 'uk-animation-medium', 'uk-animation-reverse');
6777
- setTimeout(() => { element.remove(); }, 600);
6730
+ next() {
6731
+ const page = this.current + 1;
6732
+ if (page <= Object.keys(this.pages)?.length || 0) {
6733
+ this.current = page;
6734
+ this.handleClick('next');
6735
+ }
6778
6736
  }
6779
6737
  /**
6780
- * @description Navigates to a new route based on the specified action and item ID.
6781
- * @summary This method constructs a navigation URL using the component's route configuration,
6782
- * the specified action, and an item identifier. It uses Ionic's NavController to perform
6783
- * forward navigation with appropriate animations. This method is typically used for
6784
- * CRUD operations where each action (create, read, update, delete) has its own route.
6738
+ * @description Navigates to the previous page.
6739
+ * @summary Decrements the current page number if not at the first page and triggers
6740
+ * the click event handler with 'previous' direction. This method is typically called
6741
+ * when the user clicks on the "previous" button in the pagination UI.
6785
6742
  *
6786
- * @param {string} action - The action to be performed (e.g., 'edit', 'view', 'delete')
6787
- * @param {string} [id] - The unique identifier of the item to be acted upon
6788
- * @return {Promise<boolean>} A promise that resolves to true if navigation was successful
6743
+ * @returns {void}
6789
6744
  *
6790
6745
  * @mermaid
6791
6746
  * sequenceDiagram
6792
- * participant L as ListItemComponent
6793
- * participant N as NavController
6794
- * participant R as Router
6747
+ * participant U as User
6748
+ * participant P as PaginationComponent
6795
6749
  *
6796
- * L->>L: redirect(action, id)
6797
- * L->>L: Construct URL: /{route}/{action}/{id}
6798
- * L->>N: navigateForward(url)
6799
- * N->>R: Navigate to constructed URL
6800
- * R-->>N: Return navigation result
6801
- * N-->>L: Return boolean success
6750
+ * U->>P: Click previous button
6751
+ * P->>P: previous()
6752
+ * alt page > 0
6753
+ * P->>P: Decrement current page
6754
+ * P->>P: handleClick('previous')
6755
+ * end
6802
6756
  *
6803
- * @memberOf ListItemComponent
6757
+ * @memberOf PaginationComponent
6804
6758
  */
6805
- async redirect(action, id) {
6806
- return await this.navController.navigateForward(`/${this.route}/${action}/${id || this.uid}`);
6759
+ previous() {
6760
+ const page = this.current - 1;
6761
+ if (page > 0) {
6762
+ this.current = page;
6763
+ this.handleClick('previous');
6764
+ }
6807
6765
  }
6808
6766
  /**
6809
- * @description Presents the actions menu popover for the list item.
6810
- * @summary This method handles the display of a contextual action menu when triggered by user
6811
- * interaction (typically a long press or right-click). It stops event propagation to prevent
6812
- * unwanted side effects, removes any existing focus traps for accessibility, configures the
6813
- * popover with the triggering event, and opens the action menu. The menu typically contains
6814
- * available CRUD operations for the item.
6767
+ * @description Navigates to a specific page number.
6768
+ * @summary Updates the current page to the specified page number and triggers
6769
+ * the click event handler with the appropriate direction. This method is typically
6770
+ * called when the user clicks directly on a page number in the pagination UI.
6815
6771
  *
6816
- * @param {Event} event - The event that triggered the action menu request
6817
- * @return {void}
6772
+ * @param {number | null} page - The page number to navigate to
6773
+ * @returns {void}
6818
6774
  *
6819
6775
  * @mermaid
6820
6776
  * sequenceDiagram
6821
6777
  * participant U as User
6822
- * participant L as ListItemComponent
6823
- * participant P as Popover
6824
- * participant A as Accessibility
6778
+ * participant P as PaginationComponent
6825
6779
  *
6826
- * U->>L: Trigger action menu (long press/right-click)
6827
- * L->>L: stopImmediatePropagation()
6828
- * L->>A: removeFocusTrap()
6829
- * L->>P: Set event reference
6830
- * L->>L: actionMenuOpen = true
6831
- * L->>P: Display popover with actions
6780
+ * U->>P: Click page number
6781
+ * P->>P: navigate(page)
6782
+ * alt page is not null and different from current
6783
+ * P->>P: Determine direction (next/previous)
6784
+ * P->>P: handleClick(direction, page)
6785
+ * end
6832
6786
  *
6833
- * @memberOf ListItemComponent
6787
+ * @memberOf PaginationComponent
6834
6788
  */
6835
- presentActionsMenu(event) {
6836
- event.stopImmediatePropagation();
6837
- // forcing trap focus
6838
- removeFocusTrap();
6839
- this.actionMenuComponent.event = event;
6840
- this.actionMenuOpen = true;
6789
+ navigate(page) {
6790
+ if (page !== null && this.current !== page)
6791
+ this.handleClick(page > this.current ? 'next' : 'previous', page);
6841
6792
  }
6842
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ListItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6843
- 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" }] }); }
6844
- };
6845
- ListItemComponent = __decorate([
6846
- Dynamic(),
6847
- __metadata("design:paramtypes", [])
6848
- ], ListItemComponent);
6849
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ListItemComponent, decorators: [{
6793
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: PaginationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6794
+ 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" }] }); }
6795
+ }
6796
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: PaginationComponent, decorators: [{
6850
6797
  type: Component,
6851
- args: [{ selector: 'ngx-decaf-list-item', standalone: true, imports: [
6798
+ args: [{ selector: 'ngx-decaf-pagination', imports: [
6852
6799
  TranslatePipe,
6853
- IonList,
6854
- IonListHeader,
6855
- IonItem,
6856
- IonItemSliding,
6857
- IonItemOptions,
6858
- IonItemOption,
6859
- IonIcon,
6860
- IonLabel,
6861
- IonButton,
6862
- IonContent,
6863
- IonPopover
6864
- ], 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"] }]
6865
- }], ctorParameters: () => [], propDecorators: { actionMenuComponent: [{
6866
- type: ViewChild,
6867
- args: ['actionMenuComponent']
6868
- }], lines: [{
6869
- type: Input
6870
- }], item: [{
6871
- type: Input
6872
- }], icon: [{
6873
- type: Input
6874
- }], iconSlot: [{
6875
- type: Input
6876
- }], button: [{
6877
- type: Input
6878
- }], title: [{
6879
- type: Input
6880
- }], description: [{
6881
- type: Input
6882
- }], info: [{
6883
- type: Input
6884
- }], subinfo: [{
6800
+ IonIcon
6801
+ ], 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"] }]
6802
+ }], ctorParameters: () => [], propDecorators: { totalPages: [{
6803
+ type: Input,
6804
+ args: [{ required: true }]
6805
+ }], current: [{
6885
6806
  type: Input
6886
6807
  }], clickEvent: [{
6887
6808
  type: Output
6888
- }], enableSlideItems: [{
6889
- type: HostListener,
6890
- args: ['window:resize', ['$event']]
6891
6809
  }] } });
6892
6810
 
6893
6811
  /**
6894
- * @description A pagination component for navigating through multiple pages of content.
6895
- * @summary This component provides a user interface for paginated content navigation,
6896
- * displaying page numbers and navigation controls. It supports customizable page counts,
6897
- * current page tracking, and emits events when users navigate between pages.
6812
+ * @description A versatile list component that supports various data display modes.
6813
+ * @summary This component provides a flexible way to display lists of data with support
6814
+ * for infinite scrolling, pagination, searching, and custom item rendering. It can fetch
6815
+ * data from various sources including models, functions, or direct data input.
6898
6816
  *
6899
- * The component intelligently handles large numbers of pages by showing a subset of page
6900
- * numbers with ellipses to indicate skipped pages, ensuring the UI remains clean and usable
6901
- * even with many pages.
6817
+ * The component supports two main display types:
6818
+ * 1. Infinite scrolling - Loads more data as the user scrolls
6819
+ * 2. Pagination - Displays data in pages with navigation controls
6820
+ *
6821
+ * Additional features include:
6822
+ * - Pull-to-refresh functionality
6823
+ * - Search filtering
6824
+ * - Empty state customization
6825
+ * - Custom item rendering
6826
+ * - Event emission for interactions
6902
6827
  *
6903
6828
  * @mermaid
6904
6829
  * sequenceDiagram
6905
6830
  * participant U as User
6906
- * participant P as PaginationComponent
6907
- * participant E as External Component
6831
+ * participant L as ListComponent
6832
+ * participant D as Data Source
6833
+ * participant E as External Components
6908
6834
  *
6909
- * U->>P: Click page number
6910
- * P->>P: navigate(page)
6911
- * P->>P: handleClick(direction, page)
6912
- * P->>E: Emit clickEvent with PaginationCustomEvent
6835
+ * U->>L: Initialize component
6836
+ * L->>L: ngOnInit()
6837
+ * L->>D: Request initial data
6838
+ * D-->>L: Return data
6839
+ * L->>L: Process and display data
6913
6840
  *
6914
- * U->>P: Click next button
6915
- * P->>P: next()
6916
- * P->>P: handleClick('next')
6917
- * P->>E: Emit clickEvent with PaginationCustomEvent
6841
+ * alt User scrolls (Infinite mode)
6842
+ * U->>L: Scroll to bottom
6843
+ * L->>D: Request more data
6844
+ * D-->>L: Return additional data
6845
+ * L->>L: Append to existing data
6846
+ * else User changes page (Paginated mode)
6847
+ * U->>L: Click page number
6848
+ * L->>L: handlePaginate()
6849
+ * L->>D: Request data for page
6850
+ * D-->>L: Return page data
6851
+ * L->>L: Replace displayed data
6852
+ * end
6918
6853
  *
6919
- * U->>P: Click previous button
6920
- * P->>P: previous()
6921
- * P->>P: handleClick('previous')
6922
- * P->>E: Emit clickEvent with PaginationCustomEvent
6854
+ * alt User searches
6855
+ * U->>L: Enter search term
6856
+ * L->>L: handleSearch()
6857
+ * L->>D: Filter data by search term
6858
+ * D-->>L: Return filtered data
6859
+ * L->>L: Update displayed data
6860
+ * end
6861
+ *
6862
+ * alt User clicks item
6863
+ * U->>L: Click list item
6864
+ * L->>L: handleClick()
6865
+ * L->>E: Emit clickEvent
6866
+ * end
6923
6867
  *
6924
6868
  * @example
6925
- * <ngx-decaf-pagination
6926
- * [pages]="10"
6927
- * [current]="3"
6928
- * (clickEvent)="handlePageChange($event)">
6929
- * </ngx-decaf-pagination>
6869
+ * <ngx-decaf-list
6870
+ * [source]="dataSource"
6871
+ * [limit]="10"
6872
+ * [type]="'infinite'"
6873
+ * [showSearchbar]="true"
6874
+ * (clickEvent)="handleItemClick($event)"
6875
+ * (refreshEvent)="handleRefresh($event)">
6876
+ * </ngx-decaf-list>
6930
6877
  *
6931
6878
  * @extends {NgxBaseComponent}
6932
6879
  * @implements {OnInit}
6933
6880
  */
6934
- class PaginationComponent extends NgxBaseComponent {
6881
+ let ListComponent = class ListComponent extends NgxBaseComponent {
6935
6882
  /**
6936
- * @constructor
6937
- * @description Initializes a new instance of the PaginationComponent.
6938
- * Calls the parent constructor with the component name for generate base locale string.
6883
+ * @description Initializes a new instance of the ListComponent.
6884
+ * @summary Creates a new ListComponent and sets up the base component with the appropriate
6885
+ * component name. This constructor is called when Angular instantiates the component and
6886
+ * before any input properties are set. It passes the component name to the parent class
6887
+ * constructor to enable proper localization and component identification.
6888
+ *
6889
+ * The constructor is intentionally minimal, with most initialization logic deferred to
6890
+ * the ngOnInit lifecycle hook. This follows Angular best practices by keeping the constructor
6891
+ * focused on dependency injection and basic setup, while complex initialization that depends
6892
+ * on input properties is handled in ngOnInit.
6893
+ *
6894
+ * @memberOf ListComponent
6939
6895
  */
6940
6896
  constructor() {
6941
- super("PaginationComponent");
6897
+ super("ListComponent");
6898
+ /**
6899
+ * @description The display mode for the list component.
6900
+ * @summary Determines how the list data is loaded and displayed. Options include:
6901
+ * - INFINITE: Loads more data as the user scrolls (infinite scrolling)
6902
+ * - PAGINATED: Displays data in pages with navigation controls
6903
+ *
6904
+ * @type {ListComponentsTypes}
6905
+ * @default ListComponentsTypes.INFINITE
6906
+ * @memberOf ListComponent
6907
+ */
6908
+ this.type = ListComponentsTypes.INFINITE;
6942
6909
  /**
6943
6910
  * @description Controls whether the component uses translation services.
6944
6911
  * @summary When set to true, the component will attempt to use translation services
6945
- * for any text content. This allows for internationalization of the pagination component.
6912
+ * for any text content. This allows for internationalization of the list component.
6946
6913
  *
6947
6914
  * @type {StringOrBoolean}
6948
6915
  * @default true
6949
- * @memberOf PaginationComponent
6916
+ * @memberOf ListComponent
6950
6917
  */
6951
6918
  this.translatable = true;
6952
6919
  /**
6953
- * @description The currently active page number.
6954
- * @summary Specifies which page is currently active or selected. This value is used
6955
- * to highlight the current page in the UI and as a reference point for navigation.
6920
+ * @description Controls the visibility of the search bar.
6921
+ * @summary When set to true, displays a search bar at the top of the list that allows
6922
+ * users to filter the list items. The search functionality works by filtering the
6923
+ * existing data or by triggering a new data fetch with search parameters.
6924
+ *
6925
+ * @type {StringOrBoolean}
6926
+ * @default true
6927
+ * @memberOf ListComponent
6928
+ */
6929
+ this.showSearchbar = true;
6930
+ /**
6931
+ * @description Direct data input for the list component.
6932
+ * @summary Provides a way to directly pass data to the list component instead of
6933
+ * fetching it from a source. When both data and source are provided, the component
6934
+ * will use the source to fetch data only if the data array is empty.
6935
+ *
6936
+ * @type {KeyValue[] | undefined}
6937
+ * @default undefined
6938
+ * @memberOf ListComponent
6939
+ */
6940
+ this.data = undefined;
6941
+ /**
6942
+ * @description The starting index for data fetching.
6943
+ * @summary Specifies the index from which to start fetching data. This is used
6944
+ * for pagination and infinite scrolling to determine which subset of data to load.
6956
6945
  *
6957
6946
  * @type {number}
6958
- * @default 1
6959
- * @memberOf PaginationComponent
6947
+ * @default 0
6948
+ * @memberOf ListComponent
6960
6949
  */
6961
- this.current = 1;
6950
+ this.start = 0;
6962
6951
  /**
6963
- * @description Event emitter for pagination navigation events.
6964
- * @summary Emits a custom event when users navigate between pages, either by clicking
6965
- * on page numbers or using the next/previous buttons. The event contains information
6966
- * about the navigation direction and the target page number.
6952
+ * @description The number of items to fetch per page or load operation.
6953
+ * @summary Determines how many items are loaded at once during pagination or
6954
+ * infinite scrolling. This affects the size of data chunks requested from the source.
6967
6955
  *
6968
- * @type {EventEmitter<PaginationCustomEvent>}
6969
- * @memberOf PaginationComponent
6970
- */
6971
- this.clickEvent = new EventEmitter();
6972
- addIcons({ chevronBackOutline, chevronForwardOutline });
6973
- }
6974
- /**
6975
- * @description Initializes the component after Angular sets the input properties.
6976
- * @summary Sets up the component by initializing the locale settings based on the
6977
- * translatable property, generating the page numbers based on the total pages and
6978
- * current page, and storing the last page number for boundary checking.
6979
- *
6980
- * @mermaid
6981
- * sequenceDiagram
6982
- * participant A as Angular Lifecycle
6983
- * participant P as PaginationComponent
6984
- *
6985
- * A->>P: ngOnInit()
6986
- * P->>P: getLocale(translatable)
6987
- * P->>P: Set locale
6988
- * P->>P: getPages(data, current)
6989
- * P->>P: Set pages array
6990
- * P->>P: Set last page number
6991
- *
6992
- * @returns {void}
6993
- * @memberOf PaginationComponent
6994
- */
6995
- ngOnInit() {
6996
- this.locale = this.getLocale(this.translatable);
6997
- this.pages = this.getPages(this.totalPages, this.current);
6998
- this.last = this.totalPages;
6999
- }
7000
- /**
7001
- * @description Handles click events on pagination controls.
7002
- * @summary Processes user interactions with the pagination component, updating the
7003
- * current page if specified and emitting an event with navigation details. This method
7004
- * is called when users click on page numbers or navigation buttons.
7005
- *
7006
- * @param {('next' | 'previous')} direction - The direction of navigation
7007
- * @param {number} [page] - Optional page number to navigate to directly
7008
- * @returns {void}
7009
- *
7010
- * @mermaid
7011
- * sequenceDiagram
7012
- * participant U as User
7013
- * participant P as PaginationComponent
7014
- * participant E as External Component
7015
- *
7016
- * U->>P: Click pagination control
7017
- * P->>P: handleClick(direction, page?)
7018
- * alt page is provided
7019
- * P->>P: Update current page
7020
- * end
7021
- * P->>E: Emit clickEvent with direction and page
7022
- *
7023
- * @memberOf PaginationComponent
7024
- */
7025
- handleClick(direction, page) {
7026
- if (page)
7027
- this.current = page;
7028
- this.clickEvent.emit({
7029
- name: EventConstants.CLICK,
7030
- data: {
7031
- direction,
7032
- page: this.current
7033
- },
7034
- component: this.componentName
7035
- });
7036
- }
7037
- /**
7038
- * @description Generates the array of page objects for display.
7039
- * @summary Creates an array of page objects based on the total number of pages and
7040
- * the current page. For small page counts (≤5), all pages are shown. For larger page
7041
- * counts, a subset is shown with ellipses to indicate skipped pages. This ensures
7042
- * the pagination UI remains clean and usable even with many pages.
7043
- *
7044
- * @param {number} total - The total number of pages
7045
- * @param {number} [current] - The current active page (defaults to this.current)
7046
- * @returns {KeyValue[]} Array of page objects with index and text properties
7047
- *
7048
- * @mermaid
7049
- * flowchart TD
7050
- * A[Start] --> B{total <= 5?}
7051
- * B -->|Yes| C[Show all pages]
7052
- * B -->|No| D[Show first page]
7053
- * D --> E[Show last pages]
7054
- * E --> F[Add ellipses for skipped pages]
7055
- * C --> G[Return pages array]
7056
- * F --> G
7057
- *
7058
- * @memberOf PaginationComponent
7059
- */
7060
- getPages(total, current) {
7061
- if (!current)
7062
- current = this.current;
7063
- const pages = [];
7064
- function getPage(index, text = '', clazz = 'button') {
7065
- if (pages.some(item => item['index'] === index))
7066
- return;
7067
- pages.push({ index, text: index != null ? index.toString().padStart(2, '0') : text, class: clazz });
7068
- }
7069
- if (total <= 5) {
7070
- for (let i = 1; i <= total; i++)
7071
- getPage(i);
7072
- }
7073
- else {
7074
- // Adiciona os dois primeiros
7075
- getPage(1);
7076
- getPage(2);
7077
- // Adiciona "..." entre os blocos
7078
- if (current && current > 3)
7079
- getPage(null, '...');
7080
- // Adiciona a página atual (se estiver no meio)
7081
- if (current && current > 2 && current < total - 1)
7082
- getPage(current);
7083
- // Adiciona "..." entre os blocos
7084
- if (current && current < total - 2)
7085
- getPage(null, '...', 'separator');
7086
- // Adiciona os dois últimos
7087
- getPage(total - 1);
7088
- getPage(total);
7089
- }
7090
- return pages;
7091
- }
7092
- /**
7093
- * @description Gets the current active page number.
7094
- * @summary Returns the current page number that is active in the pagination component.
7095
- * This method provides a way to access the current page state from outside the component.
7096
- *
7097
- * @returns {number} The current page number
7098
- * @memberOf PaginationComponent
7099
- */
7100
- getCurrent() {
7101
- return this.current;
7102
- }
7103
- /**
7104
- * @description Navigates to the next page.
7105
- * @summary Increments the current page number if not at the last page and triggers
7106
- * the click event handler with 'next' direction. This method is typically called
7107
- * when the user clicks on the "next" button in the pagination UI.
7108
- *
7109
- * @returns {void}
7110
- *
7111
- * @mermaid
7112
- * sequenceDiagram
7113
- * participant U as User
7114
- * participant P as PaginationComponent
7115
- *
7116
- * U->>P: Click next button
7117
- * P->>P: next()
7118
- * alt page <= max pages
7119
- * P->>P: Increment current page
7120
- * P->>P: handleClick('next')
7121
- * end
7122
- *
7123
- * @memberOf PaginationComponent
7124
- */
7125
- next() {
7126
- const page = this.current + 1;
7127
- if (page <= Object.keys(this.pages)?.length || 0) {
7128
- this.current = page;
7129
- this.handleClick('next');
7130
- }
7131
- }
7132
- /**
7133
- * @description Navigates to the previous page.
7134
- * @summary Decrements the current page number if not at the first page and triggers
7135
- * the click event handler with 'previous' direction. This method is typically called
7136
- * when the user clicks on the "previous" button in the pagination UI.
7137
- *
7138
- * @returns {void}
7139
- *
7140
- * @mermaid
7141
- * sequenceDiagram
7142
- * participant U as User
7143
- * participant P as PaginationComponent
7144
- *
7145
- * U->>P: Click previous button
7146
- * P->>P: previous()
7147
- * alt page > 0
7148
- * P->>P: Decrement current page
7149
- * P->>P: handleClick('previous')
7150
- * end
7151
- *
7152
- * @memberOf PaginationComponent
7153
- */
7154
- previous() {
7155
- const page = this.current - 1;
7156
- if (page > 0) {
7157
- this.current = page;
7158
- this.handleClick('previous');
7159
- }
7160
- }
7161
- /**
7162
- * @description Navigates to a specific page number.
7163
- * @summary Updates the current page to the specified page number and triggers
7164
- * the click event handler with the appropriate direction. This method is typically
7165
- * called when the user clicks directly on a page number in the pagination UI.
7166
- *
7167
- * @param {number | null} page - The page number to navigate to
7168
- * @returns {void}
7169
- *
7170
- * @mermaid
7171
- * sequenceDiagram
7172
- * participant U as User
7173
- * participant P as PaginationComponent
7174
- *
7175
- * U->>P: Click page number
7176
- * P->>P: navigate(page)
7177
- * alt page is not null and different from current
7178
- * P->>P: Determine direction (next/previous)
7179
- * P->>P: handleClick(direction, page)
7180
- * end
7181
- *
7182
- * @memberOf PaginationComponent
7183
- */
7184
- navigate(page) {
7185
- if (page !== null && this.current !== page)
7186
- this.handleClick(page > this.current ? 'next' : 'previous', page);
7187
- }
7188
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PaginationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7189
- 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"] }] }); }
7190
- }
7191
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PaginationComponent, decorators: [{
7192
- type: Component,
7193
- args: [{ selector: 'ngx-decaf-pagination', imports: [
7194
- TranslatePipe,
7195
- IonIcon
7196
- ], 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"] }]
7197
- }], ctorParameters: () => [], propDecorators: { totalPages: [{
7198
- type: Input,
7199
- args: [{ required: true }]
7200
- }], current: [{
7201
- type: Input
7202
- }], clickEvent: [{
7203
- type: Output
7204
- }] } });
7205
-
7206
- /**
7207
- * @description A versatile list component that supports various data display modes.
7208
- * @summary This component provides a flexible way to display lists of data with support
7209
- * for infinite scrolling, pagination, searching, and custom item rendering. It can fetch
7210
- * data from various sources including models, functions, or direct data input.
7211
- *
7212
- * The component supports two main display types:
7213
- * 1. Infinite scrolling - Loads more data as the user scrolls
7214
- * 2. Pagination - Displays data in pages with navigation controls
7215
- *
7216
- * Additional features include:
7217
- * - Pull-to-refresh functionality
7218
- * - Search filtering
7219
- * - Empty state customization
7220
- * - Custom item rendering
7221
- * - Event emission for interactions
7222
- *
7223
- * @mermaid
7224
- * sequenceDiagram
7225
- * participant U as User
7226
- * participant L as ListComponent
7227
- * participant D as Data Source
7228
- * participant E as External Components
7229
- *
7230
- * U->>L: Initialize component
7231
- * L->>L: ngOnInit()
7232
- * L->>D: Request initial data
7233
- * D-->>L: Return data
7234
- * L->>L: Process and display data
7235
- *
7236
- * alt User scrolls (Infinite mode)
7237
- * U->>L: Scroll to bottom
7238
- * L->>D: Request more data
7239
- * D-->>L: Return additional data
7240
- * L->>L: Append to existing data
7241
- * else User changes page (Paginated mode)
7242
- * U->>L: Click page number
7243
- * L->>L: handlePaginate()
7244
- * L->>D: Request data for page
7245
- * D-->>L: Return page data
7246
- * L->>L: Replace displayed data
7247
- * end
7248
- *
7249
- * alt User searches
7250
- * U->>L: Enter search term
7251
- * L->>L: handleSearch()
7252
- * L->>D: Filter data by search term
7253
- * D-->>L: Return filtered data
7254
- * L->>L: Update displayed data
7255
- * end
7256
- *
7257
- * alt User clicks item
7258
- * U->>L: Click list item
7259
- * L->>L: handleClick()
7260
- * L->>E: Emit clickEvent
7261
- * end
7262
- *
7263
- * @example
7264
- * <ngx-decaf-list
7265
- * [source]="dataSource"
7266
- * [limit]="10"
7267
- * [type]="'infinite'"
7268
- * [showSearchbar]="true"
7269
- * (clickEvent)="handleItemClick($event)"
7270
- * (refreshEvent)="handleRefresh($event)">
7271
- * </ngx-decaf-list>
7272
- *
7273
- * @extends {NgxBaseComponent}
7274
- * @implements {OnInit}
7275
- */
7276
- let ListComponent = class ListComponent extends NgxBaseComponent {
7277
- /**
7278
- * @description Initializes a new instance of the ListComponent.
7279
- * @summary Creates a new ListComponent and sets up the base component with the appropriate
7280
- * component name. This constructor is called when Angular instantiates the component and
7281
- * before any input properties are set. It passes the component name to the parent class
7282
- * constructor to enable proper localization and component identification.
7283
- *
7284
- * The constructor is intentionally minimal, with most initialization logic deferred to
7285
- * the ngOnInit lifecycle hook. This follows Angular best practices by keeping the constructor
7286
- * focused on dependency injection and basic setup, while complex initialization that depends
7287
- * on input properties is handled in ngOnInit.
7288
- *
7289
- * @memberOf ListComponent
7290
- */
7291
- constructor() {
7292
- super("ListComponent");
7293
- /**
7294
- * @description The display mode for the list component.
7295
- * @summary Determines how the list data is loaded and displayed. Options include:
7296
- * - INFINITE: Loads more data as the user scrolls (infinite scrolling)
7297
- * - PAGINATED: Displays data in pages with navigation controls
7298
- *
7299
- * @type {ListComponentsTypes}
7300
- * @default ListComponentsTypes.INFINITE
7301
- * @memberOf ListComponent
7302
- */
7303
- this.type = ListComponentsTypes.INFINITE;
7304
- /**
7305
- * @description Controls whether the component uses translation services.
7306
- * @summary When set to true, the component will attempt to use translation services
7307
- * for any text content. This allows for internationalization of the list component.
7308
- *
7309
- * @type {StringOrBoolean}
7310
- * @default true
7311
- * @memberOf ListComponent
7312
- */
7313
- this.translatable = true;
7314
- /**
7315
- * @description Controls the visibility of the search bar.
7316
- * @summary When set to true, displays a search bar at the top of the list that allows
7317
- * users to filter the list items. The search functionality works by filtering the
7318
- * existing data or by triggering a new data fetch with search parameters.
7319
- *
7320
- * @type {StringOrBoolean}
7321
- * @default true
7322
- * @memberOf ListComponent
7323
- */
7324
- this.showSearchbar = true;
7325
- /**
7326
- * @description Direct data input for the list component.
7327
- * @summary Provides a way to directly pass data to the list component instead of
7328
- * fetching it from a source. When both data and source are provided, the component
7329
- * will use the source to fetch data only if the data array is empty.
7330
- *
7331
- * @type {KeyValue[] | undefined}
7332
- * @default undefined
7333
- * @memberOf ListComponent
7334
- */
7335
- this.data = undefined;
7336
- /**
7337
- * @description The starting index for data fetching.
7338
- * @summary Specifies the index from which to start fetching data. This is used
7339
- * for pagination and infinite scrolling to determine which subset of data to load.
7340
- *
7341
- * @type {number}
7342
- * @default 0
7343
- * @memberOf ListComponent
7344
- */
7345
- this.start = 0;
7346
- /**
7347
- * @description The number of items to fetch per page or load operation.
7348
- * @summary Determines how many items are loaded at once during pagination or
7349
- * infinite scrolling. This affects the size of data chunks requested from the source.
7350
- *
7351
- * @type {number}
7352
- * @default 10
7353
- * @memberOf ListComponent
6956
+ * @type {number}
6957
+ * @default 10
6958
+ * @memberOf ListComponent
7354
6959
  */
7355
6960
  this.limit = 10;
7356
6961
  /**
@@ -7583,851 +7188,1230 @@ let ListComponent = class ListComponent extends NgxBaseComponent {
7583
7188
  */
7584
7189
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
7585
7190
  this.observerSubjet = new Subject();
7586
- /**
7587
- * @description Observer object for repository change notifications.
7588
- * @summary Implements the Observer interface to receive notifications when the
7589
- * underlying data repository changes. This enables automatic list updates when
7590
- * data is created, updated, or deleted through the repository.
7591
- *
7592
- * @private
7593
- * @type {Observer}
7594
- * @memberOf ListComponent
7595
- */
7191
+ }
7192
+ /**
7193
+ * @description Initializes the component after Angular sets the input properties.
7194
+ * @summary Sets up the component by initializing event subscriptions, processing boolean
7195
+ * inputs, and loading the initial data. This method prepares the component for user
7196
+ * interaction by ensuring all properties are properly initialized and data is loaded.
7197
+ *
7198
+ * @returns {Promise<void>}
7199
+ *
7200
+ * @mermaid
7201
+ * sequenceDiagram
7202
+ * participant A as Angular Lifecycle
7203
+ * participant L as ListComponent
7204
+ * participant D as Data Source
7205
+ *
7206
+ * A->>L: ngOnInit()
7207
+ * L->>L: Set up click event debouncing
7208
+ * L->>L: Process boolean inputs
7209
+ * L->>L: Configure component based on inputs
7210
+ * L->>L: refresh()
7211
+ * L->>D: Request initial data
7212
+ * D-->>L: Return data
7213
+ * L->>L: Process and display data
7214
+ * L->>L: Configure empty state if needed
7215
+ * L->>L: initialize()
7216
+ *
7217
+ * @memberOf ListComponent
7218
+ */
7219
+ async ngOnInit() {
7596
7220
  this.observer = { refresh: async (...args) => this.observeRepository(...args) };
7221
+ this.clickItemSubject.pipe(debounceTime(100)).subscribe(event => this.clickEventEmit(event));
7222
+ this.observerSubjet.pipe(debounceTime(100)).subscribe(args => this.handleObserveEvent(args[0], args[1], args[2]));
7223
+ this.enableFilter = stringToBoolean(this.enableFilter);
7224
+ this.limit = Number(this.limit);
7225
+ this.start = Number(this.start);
7226
+ this.inset = stringToBoolean(this.inset);
7227
+ this.showRefresher = stringToBoolean(this.showRefresher);
7228
+ this.loadMoreData = stringToBoolean(this.loadMoreData);
7229
+ this.showSearchbar = stringToBoolean(this.showSearchbar);
7230
+ this.disableSort = stringToBoolean(this.disableSort);
7231
+ if (typeof this.item?.['tag'] === 'boolean' && this.item?.['tag'] === true)
7232
+ this.item['tag'] = ComponentsTagNames.LIST_ITEM;
7233
+ await this.refresh();
7234
+ if (this.operations.includes(OperationKeys.CREATE) && this.route)
7235
+ this.empty.link = `${this.route}/${OperationKeys.CREATE}`;
7236
+ await this.initialize();
7237
+ if (this.model instanceof Model && this._repository)
7238
+ this._repository.observe(this.observer);
7239
+ }
7240
+ /**
7241
+ * @description Cleans up resources when the component is destroyed.
7242
+ * @summary Performs cleanup operations when the component is being removed from the DOM.
7243
+ * This includes clearing references to models and data to prevent memory leaks.
7244
+ *
7245
+ * @returns {void}
7246
+ * @memberOf ListComponent
7247
+ */
7248
+ ngOnDestroy() {
7249
+ if (this._repository)
7250
+ this._repository.unObserve(this.observer);
7251
+ this.data = this.model = this._repository = this.paginator = undefined;
7252
+ }
7253
+ /**
7254
+ * @description Handles repository observation events with debouncing.
7255
+ * @summary Processes repository change notifications and routes them appropriately.
7256
+ * For CREATE events with a UID, handles them immediately. For other events,
7257
+ * passes them to the debounced observer subject to prevent excessive updates.
7258
+ *
7259
+ * @param {...unknown[]} args - The repository event arguments including table, event type, and UID
7260
+ * @returns {Promise<void>}
7261
+ * @memberOf ListComponent
7262
+ */
7263
+ async observeRepository(...args) {
7264
+ const [table, event, uid] = args;
7265
+ if (event === OperationKeys.CREATE && !!uid)
7266
+ return this.handleObserveEvent(table, event, uid);
7267
+ return this.observerSubjet.next(args);
7268
+ }
7269
+ /**
7270
+ * @description Handles specific repository events and updates the list accordingly.
7271
+ * @summary Processes repository change events (CREATE, UPDATE, DELETE) and performs
7272
+ * the appropriate list operations. This includes adding new items, updating existing
7273
+ * ones, or removing deleted items from the list display.
7274
+ *
7275
+ * @param {string} table - The table/model name that changed
7276
+ * @param {OperationKeys} event - The type of operation (CREATE, UPDATE, DELETE)
7277
+ * @param {string | number} uid - The unique identifier of the affected item
7278
+ * @returns {Promise<void>}
7279
+ * @memberOf ListComponent
7280
+ */
7281
+ async handleObserveEvent(table, event, uid) {
7282
+ if (event === OperationKeys.CREATE) {
7283
+ if (uid) {
7284
+ await this.handleCreate(uid);
7285
+ }
7286
+ else {
7287
+ await this.refresh(true);
7288
+ }
7289
+ }
7290
+ else {
7291
+ if (event === OperationKeys.UPDATE)
7292
+ await this.handleUpdate(uid);
7293
+ if (event === OperationKeys.DELETE)
7294
+ this.handleDelete(uid);
7295
+ this.refreshEventEmit();
7296
+ }
7297
+ }
7298
+ /**
7299
+ * @description Function for tracking items in the list.
7300
+ * @summary Provides a tracking function for the `*ngFor` directive in the component template.
7301
+ * This function is used to identify and control the rendering of items in the list,
7302
+ * preventing duplicate or unnecessary rendering.
7303
+ *
7304
+ * The `trackItemFn` function takes two parameters: `index` (the index of the item in the list)
7305
+ * and `item` (the actual item from the list). It returns the tracking key, which in this case
7306
+ * is the union of the `uid` of the item with the model name.
7307
+ *
7308
+ * @param {number} index - The index of the item in the list.
7309
+
7310
+ * @param {KeyValue | string | number} item - The actual item from the list.
7311
+ * @returns {string | number} The tracking key for the item.
7312
+ * @memberOf ListComponent
7313
+ */
7314
+ trackItemFn(index, item) {
7315
+ return `${item?.['uid'] || item?.[this.pk]}-${index}`;
7316
+ }
7317
+ /**
7318
+ * Handles the create event from the repository.
7319
+ *
7320
+ * @param {string | number} uid - The ID of the item to create.
7321
+ * @returns {Promise<void>} A promise that resolves when the item is created and added to the list.
7322
+ */
7323
+ async handleCreate(uid) {
7324
+ const result = await this._repository?.read(uid);
7325
+ const item = this.mapResults([result])[0];
7326
+ this.items = this.data = [item, ...this.items || []];
7327
+ }
7328
+ /**
7329
+ * @description Handles the update event from the repository.
7330
+ * @summary Updates the list item with the specified ID based on the new data.
7331
+ *
7332
+ * @param {string | number} uid - The ID of the item to update
7333
+ * @returns {Promise<void>}
7334
+ * @private
7335
+ * @memberOf ListComponent
7336
+ */
7337
+ async handleUpdate(uid) {
7338
+ const item = this.itemMapper(await this._repository?.read(uid) || {}, this.mapper);
7339
+ this.data = [];
7340
+ for (const key in this.items) {
7341
+ const child = this.items[key];
7342
+ if (child['uid'] === item['uid']) {
7343
+ this.items[key] = Object.assign({}, child, item);
7344
+ break;
7345
+ }
7346
+ }
7347
+ setTimeout(() => {
7348
+ this.data = [...this.items];
7349
+ }, 0);
7350
+ }
7351
+ /**
7352
+ * @description Removes an item from the list by ID.
7353
+ * @summary Filters out an item with the specified ID from the data array and
7354
+ * refreshes the list display. This is typically used after a delete operation.
7355
+ *
7356
+ * @param {string} uid - The ID of the item to delete
7357
+ * @param {string} pk - The primary key field name
7358
+ * @returns {Promise<void>}
7359
+ *
7360
+ * @memberOf ListComponent
7361
+ */
7362
+ handleDelete(uid, pk) {
7363
+ if (!pk)
7364
+ pk = this.pk;
7365
+ this.items = this.data?.filter((item) => item['uid'] !== uid) || [];
7366
+ }
7367
+ /**
7368
+ * @description Handles click events from list items.
7369
+ * @summary Listens for global ListItemClickEvent events and passes them to the
7370
+ * debounced click subject. This allows the component to respond to clicks on
7371
+ * list items regardless of where they originate from.
7372
+ *
7373
+ * @param {ListItemCustomEvent | RendererCustomEvent} event - The click event
7374
+ * @returns {void}
7375
+ *
7376
+ * @memberOf ListComponent
7377
+ */
7378
+ handleClick(event) {
7379
+ this.clickItemSubject.next(event);
7597
7380
  }
7598
7381
  /**
7599
- * @description Initializes the component after Angular sets the input properties.
7600
- * @summary Sets up the component by initializing event subscriptions, processing boolean
7601
- * inputs, and loading the initial data. This method prepares the component for user
7602
- * interaction by ensuring all properties are properly initialized and data is loaded.
7382
+ * @description Handles search events from the search bar.
7383
+ * @summary Processes search queries from the search bar component, updating the
7384
+ * displayed data based on the search term. The behavior differs between infinite
7385
+ * and paginated modes to provide the best user experience for each mode.
7603
7386
  *
7387
+ * @param {string | undefined} value - The search term or undefined to clear search
7604
7388
  * @returns {Promise<void>}
7605
7389
  *
7606
7390
  * @mermaid
7607
- * sequenceDiagram
7608
- * participant A as Angular Lifecycle
7609
- * participant L as ListComponent
7610
- * participant D as Data Source
7391
+ * flowchart TD
7392
+ * A[Search Event] --> B{Type is Infinite?}
7393
+ * B -->|Yes| C[Disable loadMoreData]
7394
+ * B -->|No| D[Enable loadMoreData]
7395
+ * C --> E{Search value undefined?}
7396
+ * E -->|Yes| F[Enable loadMoreData]
7397
+ * E -->|No| G[Store search value]
7398
+ * D --> G
7399
+ * F --> H[Reset page to 1]
7400
+ * G --> I[Refresh data]
7401
+ * H --> I
7611
7402
  *
7612
- * A->>L: ngOnInit()
7613
- * L->>L: Set up click event debouncing
7614
- * L->>L: Process boolean inputs
7615
- * L->>L: Configure component based on inputs
7616
- * L->>L: refresh()
7617
- * L->>D: Request initial data
7618
- * D-->>L: Return data
7619
- * L->>L: Process and display data
7620
- * L->>L: Configure empty state if needed
7621
- * L->>L: initialize()
7403
+ * @memberOf ListComponent
7404
+ */
7405
+ async handleSearch(value) {
7406
+ if (this.type === ListComponentsTypes.INFINITE) {
7407
+ this.loadMoreData = false;
7408
+ if (value === undefined) {
7409
+ this.loadMoreData = true;
7410
+ this.page = 1;
7411
+ }
7412
+ this.searchValue = value;
7413
+ await this.refresh(true);
7414
+ }
7415
+ else {
7416
+ this.loadMoreData = true;
7417
+ this.searchValue = value;
7418
+ if (value === undefined)
7419
+ this.page = this.lastPage;
7420
+ await this.refresh(true);
7421
+ }
7422
+ }
7423
+ /**
7424
+ * @description Handles filter events from the filter component.
7425
+ * @summary Processes filter queries from the filter component and applies them
7426
+ * to the list data. This method acts as a bridge between the filter component
7427
+ * and the search functionality, converting filter queries into search operations.
7428
+ *
7429
+ * @param {IFilterQuery | undefined} value - The filter query object or undefined to clear filters
7430
+ * @returns {Promise<void>}
7431
+ * @memberOf ListComponent
7432
+ */
7433
+ async handleFilter(value) {
7434
+ await this.handleSearch(value);
7435
+ }
7436
+ /**
7437
+ * @description Clears the current search and resets the list.
7438
+ * @summary Convenience method that clears the search by calling handleSearch
7439
+ * with undefined. This resets the list to show all data without filtering.
7622
7440
  *
7441
+ * @returns {Promise<void>}
7623
7442
  * @memberOf ListComponent
7624
7443
  */
7625
- async ngOnInit() {
7626
- this.clickItemSubject.pipe(debounceTime(100)).subscribe(event => this.clickEventEmit(event));
7627
- this.observerSubjet.pipe(debounceTime(100)).subscribe(args => this.handleObserveEvent(args[0], args[1], args[2]));
7628
- this.enableFilter = stringToBoolean(this.enableFilter);
7629
- this.limit = Number(this.limit);
7630
- this.start = Number(this.start);
7631
- this.inset = stringToBoolean(this.inset);
7632
- this.showRefresher = stringToBoolean(this.showRefresher);
7633
- this.loadMoreData = stringToBoolean(this.loadMoreData);
7634
- this.showSearchbar = stringToBoolean(this.showSearchbar);
7635
- this.disableSort = stringToBoolean(this.disableSort);
7636
- if (typeof this.item?.['tag'] === 'boolean' && this.item?.['tag'] === true)
7637
- this.item['tag'] = ComponentsTagNames.LIST_ITEM;
7638
- await this.refresh();
7639
- if (this.operations.includes(OperationKeys.CREATE) && this.route)
7640
- this.empty.link = `${this.route}/${OperationKeys.CREATE}`;
7641
- await this.initialize();
7642
- if (this.model instanceof Model && this._repository)
7643
- this._repository.observe(this.observer);
7444
+ async clearSearch() {
7445
+ await this.handleSearch(undefined);
7644
7446
  }
7645
7447
  /**
7646
- * @description Cleans up resources when the component is destroyed.
7647
- * @summary Performs cleanup operations when the component is being removed from the DOM.
7648
- * This includes clearing references to models and data to prevent memory leaks.
7448
+ * @description Emits a refresh event with the current data.
7449
+ * @summary Creates and emits a refresh event containing the current list data.
7450
+ * This notifies parent components that the list data has been refreshed.
7649
7451
  *
7452
+ * @param {KeyValue[]} [data] - Optional data to include in the event
7650
7453
  * @returns {void}
7454
+ *
7651
7455
  * @memberOf ListComponent
7652
7456
  */
7653
- ngOnDestroy() {
7654
- if (this._repository)
7655
- this._repository.unObserve(this.observer);
7656
- this.data = this.model = this._repository = this.paginator = undefined;
7457
+ refreshEventEmit(data) {
7458
+ if (!data)
7459
+ data = this.items;
7460
+ this.skeletonData = new Array(data?.length || 2);
7461
+ this.refreshEvent.emit({
7462
+ name: EventConstants.REFRESH,
7463
+ data: data || [],
7464
+ component: this.componentName
7465
+ });
7657
7466
  }
7658
7467
  /**
7659
- * @description Handles repository observation events with debouncing.
7660
- * @summary Processes repository change notifications and routes them appropriately.
7661
- * For CREATE events with a UID, handles them immediately. For other events,
7662
- * passes them to the debounced observer subject to prevent excessive updates.
7468
+ * @description Emits a click event for a list item.
7469
+ * @summary Processes and emits a click event when a list item is clicked.
7470
+ * This extracts the relevant data from the event and passes it to parent components.
7471
+ *
7472
+ * @private
7473
+ * @param {ListItemCustomEvent | RendererCustomEvent} event - The click event
7474
+ * @returns {void}
7663
7475
  *
7664
- * @param {...unknown[]} args - The repository event arguments including table, event type, and UID
7665
- * @returns {Promise<void>}
7666
7476
  * @memberOf ListComponent
7667
7477
  */
7668
- async observeRepository(...args) {
7669
- const [table, event, uid] = args;
7670
- if (event === OperationKeys.CREATE && !!uid)
7671
- return this.handleObserveEvent(table, event, uid);
7672
- return this.observerSubjet.next(args);
7478
+ clickEventEmit(event) {
7479
+ this.clickEvent.emit(event);
7673
7480
  }
7674
7481
  /**
7675
- * @description Handles specific repository events and updates the list accordingly.
7676
- * @summary Processes repository change events (CREATE, UPDATE, DELETE) and performs
7677
- * the appropriate list operations. This includes adding new items, updating existing
7678
- * ones, or removing deleted items from the list display.
7482
+ * @description Refreshes the list data from the configured source.
7483
+ * @summary This method handles both initial data loading and subsequent refresh operations,
7484
+ * including pull-to-refresh and infinite scrolling. It manages the data fetching process,
7485
+ * updates the component's state, and handles pagination or infinite scrolling logic based
7486
+ * on the component's configuration.
7487
+ *
7488
+ * The method performs the following steps:
7489
+ * 1. Sets the refreshing flag to indicate a data fetch is in progress
7490
+ * 2. Calculates the appropriate start and limit values based on pagination settings
7491
+ * 3. Fetches data from the appropriate source (model or request)
7492
+ * 4. Updates the component's data and emits a refresh event
7493
+ * 5. Handles pagination or infinite scrolling state updates
7494
+ * 6. Completes any provided event (like InfiniteScrollCustomEvent)
7495
+ *
7496
+ * @param {InfiniteScrollCustomEvent | RefresherCustomEvent | boolean} event - The event that triggered the refresh,
7497
+ * or a boolean flag indicating if this is a forced refresh
7498
+ * @returns {Promise<void>} A promise that resolves when the refresh operation is complete
7499
+ *
7500
+ * @mermaid
7501
+ * sequenceDiagram
7502
+ * participant L as ListComponent
7503
+ * participant D as Data Source
7504
+ * participant E as Event System
7505
+ *
7506
+ * L->>L: refresh(event)
7507
+ * L->>L: Set refreshing flag
7508
+ * L->>L: Calculate start and limit
7509
+ * alt Using model
7510
+ * L->>D: getFromModel(force, start, limit)
7511
+ * D-->>L: Return data
7512
+ * else Using request
7513
+ * L->>D: getFromRequest(force, start, limit)
7514
+ * D-->>L: Return data
7515
+ * end
7516
+ * L->>E: refreshEventEmit()
7517
+ * alt Infinite scrolling mode
7518
+ * L->>L: Check if reached last page
7519
+ * alt Last page reached
7520
+ * L->>L: Complete scroll event
7521
+ * L->>L: Disable loadMoreData
7522
+ * else More pages available
7523
+ * L->>L: Increment page number
7524
+ * L->>L: Complete scroll event after delay
7525
+ * end
7526
+ * else Paginated mode
7527
+ * L->>L: Clear refreshing flag after delay
7528
+ * end
7679
7529
  *
7680
- * @param {string} table - The table/model name that changed
7681
- * @param {OperationKeys} event - The type of operation (CREATE, UPDATE, DELETE)
7682
- * @param {string | number} uid - The unique identifier of the affected item
7683
- * @returns {Promise<void>}
7684
7530
  * @memberOf ListComponent
7685
7531
  */
7686
- async handleObserveEvent(table, event, uid) {
7687
- if (event === OperationKeys.CREATE) {
7688
- if (uid) {
7689
- await this.handleCreate(uid);
7532
+ async refresh(event = false) {
7533
+ // if(typeof force !== 'boolean' && force.type === EventConstants.BACK_BUTTON_NAVIGATION) {
7534
+ // const {refresh} = (force as CustomEvent).detail;
7535
+ // if(!refresh)
7536
+ // return false;
7537
+ // }
7538
+ this.refreshing = true;
7539
+ const start = this.page > 1 ? (this.page - 1) * this.limit : this.start;
7540
+ const limit = (this.page * (this.limit > 12 ? 12 : this.limit));
7541
+ this.data = !this.model ?
7542
+ await this.getFromRequest(!!event, start, limit)
7543
+ : await this.getFromModel(!!event);
7544
+ this.refreshEventEmit();
7545
+ if (this.type === ListComponentsTypes.INFINITE) {
7546
+ if (this.page === this.pages) {
7547
+ if (event?.target)
7548
+ event.target.complete();
7549
+ this.loadMoreData = false;
7690
7550
  }
7691
7551
  else {
7692
- await this.refresh(true);
7552
+ this.page += 1;
7553
+ this.refreshing = false;
7554
+ setTimeout(() => {
7555
+ if (event?.target && event?.type !== EventConstants.BACK_BUTTON_NAVIGATION)
7556
+ event.target.complete();
7557
+ }, 200);
7693
7558
  }
7694
7559
  }
7695
7560
  else {
7696
- if (event === OperationKeys.UPDATE)
7697
- await this.handleUpdate(uid);
7698
- if (event === OperationKeys.DELETE)
7699
- this.handleDelete(uid);
7700
- this.refreshEventEmit();
7561
+ setTimeout(() => {
7562
+ this.refreshing = false;
7563
+ }, 200);
7701
7564
  }
7702
7565
  }
7703
7566
  /**
7704
- * @description Function for tracking items in the list.
7705
- * @summary Provides a tracking function for the `*ngFor` directive in the component template.
7706
- * This function is used to identify and control the rendering of items in the list,
7707
- * preventing duplicate or unnecessary rendering.
7708
- *
7709
- * The `trackItemFn` function takes two parameters: `index` (the index of the item in the list)
7710
- * and `item` (the actual item from the list). It returns the tracking key, which in this case
7711
- * is the union of the `uid` of the item with the model name.
7712
- *
7713
- * @param {number} index - The index of the item in the list.
7714
-
7715
- * @param {KeyValue | string | number} item - The actual item from the list.
7716
- * @returns {string | number} The tracking key for the item.
7717
- * @memberOf ListComponent
7718
- */
7719
- trackItemFn(index, item) {
7720
- return `${item?.['uid'] || item?.[this.pk]}-${index}`;
7567
+ * @description Handles pagination events from the pagination component.
7568
+ * @summary Processes pagination events by updating the current page number and
7569
+ * refreshing the list data to display the selected page. This method is called
7570
+ * when a user interacts with the pagination controls to navigate between pages.
7571
+ *
7572
+ * @param {PaginationCustomEvent} event - The pagination event containing page information
7573
+ * @returns {void}
7574
+ *
7575
+ * @memberOf ListComponent
7576
+ */
7577
+ handlePaginate(event) {
7578
+ const { page } = event.data;
7579
+ this.page = page;
7580
+ this.refresh(true);
7721
7581
  }
7722
7582
  /**
7723
- * Handles the create event from the repository.
7583
+ * @description Handles pull-to-refresh events from the refresher component.
7584
+ * @summary Processes refresh events triggered by the user pulling down on the list
7585
+ * or by programmatic refresh requests. This method refreshes the list data and
7586
+ * completes the refresher animation when the data is loaded.
7724
7587
  *
7725
- * @param {string | number} uid - The ID of the item to create.
7726
- * @returns {Promise<void>} A promise that resolves when the item is created and added to the list.
7727
- */
7728
- async handleCreate(uid) {
7729
- const result = await this._repository?.read(uid);
7730
- const item = this.mapResults([result])[0];
7731
- this.items = this.data = [item, ...this.items || []];
7732
- }
7733
- /**
7734
- * @description Handles the update event from the repository.
7735
- * @summary Updates the list item with the specified ID based on the new data.
7588
+ * @param {InfiniteScrollCustomEvent | CustomEvent} [event] - The refresh event
7589
+ * @returns {Promise<void>} A promise that resolves when the refresh operation is complete
7736
7590
  *
7737
- * @param {string | number} uid - The ID of the item to update
7738
- * @returns {Promise<void>}
7739
- * @private
7740
7591
  * @memberOf ListComponent
7741
7592
  */
7742
- async handleUpdate(uid) {
7743
- const item = this.itemMapper(await this._repository?.read(uid) || {}, this.mapper);
7744
- this.data = [];
7745
- for (const key in this.items) {
7746
- const child = this.items[key];
7747
- if (child['uid'] === item['uid']) {
7748
- this.items[key] = Object.assign({}, child, item);
7749
- break;
7750
- }
7751
- }
7752
- setTimeout(() => {
7753
- this.data = [...this.items];
7754
- }, 0);
7593
+ async handleRefresh(event) {
7594
+ await this.refresh(event || true);
7595
+ if (event instanceof CustomEvent)
7596
+ setTimeout(() => {
7597
+ // Any calls to load data go here
7598
+ event.target.complete();
7599
+ }, 400);
7755
7600
  }
7756
7601
  /**
7757
- * @description Removes an item from the list by ID.
7758
- * @summary Filters out an item with the specified ID from the data array and
7759
- * refreshes the list display. This is typically used after a delete operation.
7602
+ * @description Filters data based on a search string.
7603
+ * @summary Processes the current data array to find items that match the provided
7604
+ * search string. This uses the arrayQueryByString utility to perform the filtering
7605
+ * across all properties of the items.
7760
7606
  *
7761
- * @param {string} uid - The ID of the item to delete
7762
- * @param {string} pk - The primary key field name
7763
- * @returns {Promise<void>}
7607
+ * @param {KeyValue[]} results - The array of items to search through
7608
+ * @param {string} search - The search string to filter by
7609
+ * @returns {KeyValue[]} A promise that resolves to the filtered array of items
7764
7610
  *
7765
7611
  * @memberOf ListComponent
7766
7612
  */
7767
- handleDelete(uid, pk) {
7768
- if (!pk)
7769
- pk = this.pk;
7770
- this.items = this.data?.filter((item) => item['uid'] !== uid) || [];
7613
+ parseSearchResults(results, search) {
7614
+ return results.filter((item) => Object.values(item).some(value => value.toString().toLowerCase().includes(search?.toLowerCase())));
7771
7615
  }
7772
7616
  /**
7773
- * @description Handles click events from list items.
7774
- * @summary Listens for global ListItemClickEvent events and passes them to the
7775
- * debounced click subject. This allows the component to respond to clicks on
7776
- * list items regardless of where they originate from.
7617
+ * @description Fetches data from a request source.
7618
+ * @summary Retrieves data from the configured source function or URL, processes it,
7619
+ * and updates the component's data state. This method handles both initial data loading
7620
+ * and subsequent refresh operations when using an external data source rather than a model.
7777
7621
  *
7778
- * @param {ListItemCustomEvent | RendererCustomEvent} event - The click event
7779
- * @returns {void}
7622
+ * @param {boolean} force - Whether to force a refresh even if data already exists
7623
+ * @param {number} start - The starting index for pagination
7624
+ * @param {number} limit - The maximum number of items to retrieve
7625
+ * @returns {Promise<KeyValue[]>} A promise that resolves to the fetched data
7780
7626
  *
7781
7627
  * @memberOf ListComponent
7782
7628
  */
7783
- handleClick(event) {
7784
- this.clickItemSubject.next(event);
7629
+ async getFromRequest(force = false, start, limit) {
7630
+ let request = [];
7631
+ if (!this.data?.length || force || this.searchValue?.length || !!this.searchValue) {
7632
+ // (self.data as ListItem[]) = [];
7633
+ if (!this.searchValue?.length && !this.searchValue) {
7634
+ if (!this.source && !this.data?.length) {
7635
+ this.logger.info('No data and source passed to infinite list');
7636
+ return [];
7637
+ }
7638
+ if (this.source instanceof Function)
7639
+ request = await this.source();
7640
+ if (!Array.isArray(request))
7641
+ request = request?.['response']?.['data'] || request?.['results'] || [];
7642
+ this.data = [...await this.parseResult(request)];
7643
+ if (this.data?.length)
7644
+ this.items = this.type === ListComponentsTypes.INFINITE ?
7645
+ (this.items || []).concat([...this.data.slice(start, limit)]) : [...request.slice(start, limit)];
7646
+ }
7647
+ else {
7648
+ this.data = this.parseSearchResults(this.data, this.searchValue);
7649
+ this.items = this.data;
7650
+ }
7651
+ }
7652
+ if (this.loadMoreData && this.type === ListComponentsTypes.PAGINATED)
7653
+ this.getMoreData(this.data?.length || 0);
7654
+ return this.data || [];
7785
7655
  }
7786
7656
  /**
7787
- * @description Handles search events from the search bar.
7788
- * @summary Processes search queries from the search bar component, updating the
7789
- * displayed data based on the search term. The behavior differs between infinite
7790
- * and paginated modes to provide the best user experience for each mode.
7791
- *
7792
- * @param {string | undefined} value - The search term or undefined to clear search
7793
- * @returns {Promise<void>}
7657
+ * @description Fetches data from a model source.
7658
+ * @summary Retrieves data from the configured model using its pagination or find methods,
7659
+ * processes it, and updates the component's data state. This method handles both initial
7660
+ * data loading and subsequent refresh operations when using a model as the data source.
7794
7661
  *
7795
- * @mermaid
7796
- * flowchart TD
7797
- * A[Search Event] --> B{Type is Infinite?}
7798
- * B -->|Yes| C[Disable loadMoreData]
7799
- * B -->|No| D[Enable loadMoreData]
7800
- * C --> E{Search value undefined?}
7801
- * E -->|Yes| F[Enable loadMoreData]
7802
- * E -->|No| G[Store search value]
7803
- * D --> G
7804
- * F --> H[Reset page to 1]
7805
- * G --> I[Refresh data]
7806
- * H --> I
7662
+ * @param {boolean} force - Whether to force a refresh even if data already exists
7663
+ * @param {number} start - The starting index for pagination
7664
+ * @param {number} limit - The maximum number of items to retrieve
7665
+ * @returns {Promise<KeyValue[]>} A promise that resolves to the fetched data
7807
7666
  *
7808
7667
  * @memberOf ListComponent
7809
7668
  */
7810
- async handleSearch(value) {
7811
- if (this.type === ListComponentsTypes.INFINITE) {
7812
- this.loadMoreData = false;
7813
- if (value === undefined) {
7814
- this.loadMoreData = true;
7815
- this.page = 1;
7669
+ async getFromModel(force = false) {
7670
+ let data = [...this.data || []];
7671
+ let request = [];
7672
+ // getting model repository
7673
+ if (!this._repository)
7674
+ this._repository = this.repository;
7675
+ const repo = this._repository;
7676
+ if (!this.data?.length || force || this.searchValue?.length || !!this.searchValue) {
7677
+ try {
7678
+ if (!this.searchValue?.length && !this.searchValue) {
7679
+ this.data = [];
7680
+ // const rawQuery = this.parseQuery(self.model as Repository<Model>, start, limit);
7681
+ // request = this.parseResult(await (this.model as any)?.paginate(start, limit));
7682
+ if (!this.paginator) {
7683
+ this.paginator = await repo
7684
+ .select()
7685
+ .orderBy([this.pk, this.sortDirection])
7686
+ .paginate(this.limit);
7687
+ }
7688
+ request = await this.parseResult(this.paginator);
7689
+ }
7690
+ else {
7691
+ if (!this.indexes)
7692
+ this.indexes = (Object.values(this.mapper) || [this.pk]);
7693
+ const condition = this.parseConditions(this.searchValue);
7694
+ request = await this.parseResult(await repo.query(condition, (this.sortBy || this.pk), this.sortDirection));
7695
+ data = [];
7696
+ }
7697
+ data = this.type === ListComponentsTypes.INFINITE ? [...(data).concat(request)] : [...request];
7698
+ }
7699
+ catch (error) {
7700
+ this.logger.error(error?.message || `Unable to find ${this.model} on registry. Return empty array from component`);
7816
7701
  }
7817
- this.searchValue = value;
7818
- await this.refresh(true);
7819
7702
  }
7820
- else {
7821
- this.loadMoreData = true;
7822
- this.searchValue = value;
7823
- if (value === undefined)
7824
- this.page = this.lastPage;
7825
- await this.refresh(true);
7703
+ if (data?.length) {
7704
+ if (this.searchValue) {
7705
+ this.items = [...data];
7706
+ if (this.items?.length <= this.limit)
7707
+ this.loadMoreData = false;
7708
+ }
7709
+ else {
7710
+ this.items = [...data];
7711
+ }
7826
7712
  }
7713
+ if (this.type === ListComponentsTypes.PAGINATED && this.paginator)
7714
+ this.getMoreData(this.paginator.total);
7715
+ return data || [];
7827
7716
  }
7828
7717
  /**
7829
- * @description Handles filter events from the filter component.
7830
- * @summary Processes filter queries from the filter component and applies them
7831
- * to the list data. This method acts as a bridge between the filter component
7832
- * and the search functionality, converting filter queries into search operations.
7718
+ * @description Converts search values or filter queries into database conditions.
7719
+ * @summary Transforms search input or complex filter queries into Condition objects
7720
+ * that can be used for database querying. Handles both simple string/number searches
7721
+ * across indexed fields and complex filter queries with multiple criteria.
7833
7722
  *
7834
- * @param {IFilterQuery | undefined} value - The filter query object or undefined to clear filters
7835
- * @returns {Promise<void>}
7836
- * @memberOf ListComponent
7837
- */
7838
- async handleFilter(value) {
7839
- await this.handleSearch(value);
7840
- }
7841
- /**
7842
- * @description Clears the current search and resets the list.
7843
- * @summary Convenience method that clears the search by calling handleSearch
7844
- * with undefined. This resets the list to show all data without filtering.
7723
+ * For simple searches (string/number):
7724
+ * - Creates conditions that search across all indexed fields
7725
+ * - Uses equality for numeric values and regex for string values
7726
+ * - Combines conditions with OR logic to search multiple fields
7845
7727
  *
7846
- * @returns {Promise<void>}
7728
+ * For complex filter queries:
7729
+ * - Processes each filter item with its specific condition type
7730
+ * - Supports Equal, Not Equal, Contains, Not Contains, Greater Than, Less Than
7731
+ * - Updates sort configuration based on the filter query
7732
+ * - Combines multiple filter conditions with OR logic
7733
+ *
7734
+ * @param {string | number | IFilterQuery} value - The search value or filter query object
7735
+ * @returns {Condition<Model>} A Condition object for database querying
7847
7736
  * @memberOf ListComponent
7848
7737
  */
7849
- async clearSearch() {
7850
- await this.handleSearch(undefined);
7738
+ parseConditions(value) {
7739
+ let _condition;
7740
+ if (typeof value === Primitives.STRING || typeof value === Primitives.NUMBER) {
7741
+ _condition = Condition.attribute(this.pk).eq(!isNaN(value) ? Number(value) : value);
7742
+ for (const index of this.indexes) {
7743
+ if (index === this.pk)
7744
+ continue;
7745
+ let orCondition;
7746
+ if (!isNaN(value)) {
7747
+ orCondition = Condition.attribute(index).eq(Number(value));
7748
+ }
7749
+ else {
7750
+ orCondition = Condition.attribute(index).regexp(value);
7751
+ }
7752
+ _condition = _condition.or(orCondition);
7753
+ }
7754
+ }
7755
+ else {
7756
+ const { query, sort } = value;
7757
+ _condition = Condition.attribute(this.pk).dif('null');
7758
+ if (query?.length)
7759
+ _condition = undefined;
7760
+ (query || []).forEach((item) => {
7761
+ const { value, condition, index } = item;
7762
+ let val = value;
7763
+ if (index === this.pk || !isNaN(val))
7764
+ val = Number(val);
7765
+ let orCondition;
7766
+ switch (condition) {
7767
+ case "Equal":
7768
+ orCondition = Condition.attribute(index).eq(val);
7769
+ break;
7770
+ case "Not Equal":
7771
+ orCondition = Condition.attribute(index).dif(val);
7772
+ break;
7773
+ case "Not Contains":
7774
+ orCondition = !Condition.attribute(index).regexp(new RegExp(`^(?!.*${val}).*$`));
7775
+ break;
7776
+ case "Contains":
7777
+ orCondition = Condition.attribute(index).regexp(val);
7778
+ break;
7779
+ case "Greater Than":
7780
+ orCondition = Condition.attribute(index).gte(val);
7781
+ break;
7782
+ case "Less Than":
7783
+ orCondition = Condition.attribute(index).lte(val);
7784
+ break;
7785
+ }
7786
+ _condition = (!_condition ?
7787
+ orCondition : _condition.and(orCondition));
7788
+ });
7789
+ this.sortBy = sort?.value || this.pk;
7790
+ this.sortDirection = sort?.direction || this.sortDirection;
7791
+ }
7792
+ return _condition;
7851
7793
  }
7852
7794
  /**
7853
- * @description Emits a refresh event with the current data.
7854
- * @summary Creates and emits a refresh event containing the current list data.
7855
- * This notifies parent components that the list data has been refreshed.
7795
+ * @description Processes query results into a standardized format.
7796
+ * @summary Handles different result formats from various data sources, extracting
7797
+ * pagination information when available and applying any configured data mapping.
7798
+ * This ensures consistent data structure regardless of the source.
7856
7799
  *
7857
- * @param {KeyValue[]} [data] - Optional data to include in the event
7858
- * @returns {void}
7800
+ * @protected
7801
+ * @param {KeyValue[] | Paginator} result - The raw query result
7802
+ * @returns {KeyValue[]} The processed array of items
7859
7803
  *
7860
7804
  * @memberOf ListComponent
7861
7805
  */
7862
- refreshEventEmit(data) {
7863
- if (!data)
7864
- data = this.items;
7865
- this.skeletonData = new Array(data?.length || 2);
7866
- this.refreshEvent.emit({
7867
- name: EventConstants.REFRESH,
7868
- data: data || [],
7869
- component: this.componentName
7870
- });
7806
+ async parseResult(result) {
7807
+ if (!Array.isArray(result) && ('page' in result && 'total' in result)) {
7808
+ const paginator = result;
7809
+ try {
7810
+ result = await paginator.page(this.page);
7811
+ // TODO: Chage for result.total;
7812
+ this.getMoreData(paginator.total);
7813
+ }
7814
+ catch (error) {
7815
+ this.logger.info(error?.message || 'Unable to get page from paginator. Return empty array from component');
7816
+ result = [];
7817
+ }
7818
+ }
7819
+ else {
7820
+ this.getMoreData(result?.length || 0);
7821
+ }
7822
+ return (Object.keys(this.mapper || {}).length) ?
7823
+ this.mapResults(result) : result;
7871
7824
  }
7872
7825
  /**
7873
- * @description Emits a click event for a list item.
7874
- * @summary Processes and emits a click event when a list item is clicked.
7875
- * This extracts the relevant data from the event and passes it to parent components.
7826
+ * @description Updates pagination state based on data length.
7827
+ * @summary Calculates whether more data is available and how many pages exist
7828
+ * based on the total number of items and the configured limit per page.
7829
+ * This information is used to control pagination UI and infinite scrolling behavior.
7876
7830
  *
7877
- * @private
7878
- * @param {ListItemCustomEvent | RendererCustomEvent} event - The click event
7831
+ * @param {number} length - The total number of items available
7879
7832
  * @returns {void}
7880
7833
  *
7881
7834
  * @memberOf ListComponent
7882
7835
  */
7883
- clickEventEmit(event) {
7884
- this.clickEvent.emit(event);
7885
- }
7886
- /**
7887
- * @description Refreshes the list data from the configured source.
7888
- * @summary This method handles both initial data loading and subsequent refresh operations,
7889
- * including pull-to-refresh and infinite scrolling. It manages the data fetching process,
7890
- * updates the component's state, and handles pagination or infinite scrolling logic based
7891
- * on the component's configuration.
7892
- *
7893
- * The method performs the following steps:
7894
- * 1. Sets the refreshing flag to indicate a data fetch is in progress
7895
- * 2. Calculates the appropriate start and limit values based on pagination settings
7896
- * 3. Fetches data from the appropriate source (model or request)
7897
- * 4. Updates the component's data and emits a refresh event
7898
- * 5. Handles pagination or infinite scrolling state updates
7899
- * 6. Completes any provided event (like InfiniteScrollCustomEvent)
7900
- *
7901
- * @param {InfiniteScrollCustomEvent | RefresherCustomEvent | boolean} event - The event that triggered the refresh,
7902
- * or a boolean flag indicating if this is a forced refresh
7903
- * @returns {Promise<void>} A promise that resolves when the refresh operation is complete
7904
- *
7905
- * @mermaid
7906
- * sequenceDiagram
7907
- * participant L as ListComponent
7908
- * participant D as Data Source
7909
- * participant E as Event System
7910
- *
7911
- * L->>L: refresh(event)
7912
- * L->>L: Set refreshing flag
7913
- * L->>L: Calculate start and limit
7914
- * alt Using model
7915
- * L->>D: getFromModel(force, start, limit)
7916
- * D-->>L: Return data
7917
- * else Using request
7918
- * L->>D: getFromRequest(force, start, limit)
7919
- * D-->>L: Return data
7920
- * end
7921
- * L->>E: refreshEventEmit()
7922
- * alt Infinite scrolling mode
7923
- * L->>L: Check if reached last page
7924
- * alt Last page reached
7925
- * L->>L: Complete scroll event
7926
- * L->>L: Disable loadMoreData
7927
- * else More pages available
7928
- * L->>L: Increment page number
7929
- * L->>L: Complete scroll event after delay
7930
- * end
7931
- * else Paginated mode
7932
- * L->>L: Clear refreshing flag after delay
7933
- * end
7934
- *
7935
- * @memberOf ListComponent
7936
- */
7937
- async refresh(event = false) {
7938
- // if(typeof force !== 'boolean' && force.type === EventConstants.BACK_BUTTON_NAVIGATION) {
7939
- // const {refresh} = (force as CustomEvent).detail;
7940
- // if(!refresh)
7941
- // return false;
7942
- // }
7943
- this.refreshing = true;
7944
- const start = this.page > 1 ? (this.page - 1) * this.limit : this.start;
7945
- const limit = (this.page * (this.limit > 12 ? 12 : this.limit));
7946
- this.data = !this.model ?
7947
- await this.getFromRequest(!!event, start, limit)
7948
- : await this.getFromModel(!!event);
7949
- this.refreshEventEmit();
7836
+ getMoreData(length) {
7950
7837
  if (this.type === ListComponentsTypes.INFINITE) {
7951
- if (this.page === this.pages) {
7952
- if (event?.target)
7953
- event.target.complete();
7838
+ if (this.paginator)
7839
+ length = length * this.limit;
7840
+ if (length <= this.limit) {
7954
7841
  this.loadMoreData = false;
7955
7842
  }
7956
7843
  else {
7957
- this.page += 1;
7958
- this.refreshing = false;
7959
- setTimeout(() => {
7960
- if (event?.target && event?.type !== EventConstants.BACK_BUTTON_NAVIGATION)
7961
- event.target.complete();
7962
- }, 200);
7844
+ this.pages = Math.floor(length / this.limit);
7845
+ if ((this.pages * this.limit) < length)
7846
+ this.pages += 1;
7847
+ if (this.pages === 1)
7848
+ this.loadMoreData = false;
7963
7849
  }
7964
7850
  }
7965
7851
  else {
7966
- setTimeout(() => {
7967
- this.refreshing = false;
7968
- }, 200);
7852
+ this.pages = length;
7853
+ if (this.pages === 1)
7854
+ this.loadMoreData = false;
7969
7855
  }
7970
7856
  }
7971
7857
  /**
7972
- * @description Handles pagination events from the pagination component.
7973
- * @summary Processes pagination events by updating the current page number and
7974
- * refreshing the list data to display the selected page. This method is called
7975
- * when a user interacts with the pagination controls to navigate between pages.
7976
- *
7977
- * @param {PaginationCustomEvent} event - The pagination event containing page information
7978
- * @returns {void}
7979
- *
7980
- * @memberOf ListComponent
7981
- */
7982
- handlePaginate(event) {
7983
- const { page } = event.data;
7984
- this.page = page;
7985
- this.refresh(true);
7986
- }
7987
- /**
7988
- * @description Handles pull-to-refresh events from the refresher component.
7989
- * @summary Processes refresh events triggered by the user pulling down on the list
7990
- * or by programmatic refresh requests. This method refreshes the list data and
7991
- * completes the refresher animation when the data is loaded.
7858
+ * @description Maps a single item using the configured mapper.
7859
+ * @summary Transforms a data item according to the mapping configuration,
7860
+ * extracting nested properties and formatting values as needed. This allows
7861
+ * the component to display data in a format different from how it's stored.
7992
7862
  *
7993
- * @param {InfiniteScrollCustomEvent | CustomEvent} [event] - The refresh event
7994
- * @returns {Promise<void>} A promise that resolves when the refresh operation is complete
7863
+ * @protected
7864
+ * @param {KeyValue} item - The item to map
7865
+ * @param {KeyValue} mapper - The mapping configuration
7866
+ * @param {KeyValue} [props] - Additional properties to include
7867
+ * @returns {KeyValue} The mapped item
7995
7868
  *
7996
7869
  * @memberOf ListComponent
7997
7870
  */
7998
- async handleRefresh(event) {
7999
- await this.refresh(event || true);
8000
- if (event instanceof CustomEvent)
8001
- setTimeout(() => {
8002
- // Any calls to load data go here
8003
- event.target.complete();
8004
- }, 400);
7871
+ itemMapper(item, mapper, props) {
7872
+ return Object.entries(mapper).reduce((accum, [key, value]) => {
7873
+ const arrayValue = value.split('.');
7874
+ if (!value) {
7875
+ accum[key] = value;
7876
+ }
7877
+ else {
7878
+ if (arrayValue.length === 1) {
7879
+ value = item?.[value] ? item[value] : value !== key ? value : "";
7880
+ if (isValidDate(value))
7881
+ value = `${formatDate(value)}`;
7882
+ accum[key] = value;
7883
+ }
7884
+ else {
7885
+ let val;
7886
+ for (const _value of arrayValue)
7887
+ val = !val
7888
+ ? item[_value]
7889
+ : (typeof val === 'string' ? JSON.parse(val) : val)[_value];
7890
+ if (isValidDate(new Date(val)))
7891
+ val = `${formatDate(val)}`;
7892
+ accum[key] = val === null || val === undefined ? value : val;
7893
+ }
7894
+ }
7895
+ return Object.assign({}, props || {}, accum);
7896
+ }, {});
8005
7897
  }
8006
7898
  /**
8007
- * @description Filters data based on a search string.
8008
- * @summary Processes the current data array to find items that match the provided
8009
- * search string. This uses the arrayQueryByString utility to perform the filtering
8010
- * across all properties of the items.
7899
+ * @description Maps all result items using the configured mapper.
7900
+ * @summary Applies the itemMapper to each item in the result set, adding
7901
+ * common properties like operations and route information. This transforms
7902
+ * the raw data into the format expected by the list item components.
8011
7903
  *
8012
- * @param {KeyValue[]} results - The array of items to search through
8013
- * @param {string} search - The search string to filter by
8014
- * @returns {KeyValue[]} A promise that resolves to the filtered array of items
7904
+ * @param {KeyValue[]} data - The array of items to map
7905
+ * @returns {KeyValue[]} The array of mapped items
8015
7906
  *
8016
7907
  * @memberOf ListComponent
8017
7908
  */
8018
- parseSearchResults(results, search) {
8019
- return results.filter((item) => Object.values(item).some(value => value.toString().toLowerCase().includes(search?.toLowerCase())));
7909
+ mapResults(data) {
7910
+ if (!data || !data.length)
7911
+ return [];
7912
+ // passing uid as prop to mapper
7913
+ this.mapper = { ...this.mapper, ...{ uid: this.pk } };
7914
+ const props = Object.assign({
7915
+ operations: this.operations,
7916
+ route: this.route,
7917
+ ...Object.keys(this.item).reduce((acc, key) => {
7918
+ acc[key] = this.item[key];
7919
+ return acc;
7920
+ }, {}),
7921
+ // ... (!this.item.render ? {} : Object.keys(this.item).reduce((acc: KeyValue, key: string) => {
7922
+ // acc[key] = this.item[key as keyof IListItemProp];
7923
+ // return acc;
7924
+ // }, {}))
7925
+ });
7926
+ return data.reduce((accum, curr) => {
7927
+ accum.push({ ...this.itemMapper(curr, this.mapper, props), ...{ pk: this.pk } });
7928
+ return accum;
7929
+ }, []);
8020
7930
  }
7931
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7932
+ 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" }] }); }
7933
+ };
7934
+ ListComponent = __decorate([
7935
+ Dynamic(),
7936
+ __metadata("design:paramtypes", [])
7937
+ ], ListComponent);
7938
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ListComponent, decorators: [{
7939
+ type: Component,
7940
+ args: [{ selector: 'ngx-decaf-list', standalone: true, imports: [
7941
+ TranslatePipe,
7942
+ IonRefresher,
7943
+ PaginationComponent,
7944
+ IonList,
7945
+ IonItem,
7946
+ IonThumbnail,
7947
+ IonSkeletonText,
7948
+ IonLabel,
7949
+ IonText,
7950
+ IonRefresherContent,
7951
+ IonInfiniteScroll,
7952
+ IonInfiniteScrollContent,
7953
+ IonThumbnail,
7954
+ IonSkeletonText,
7955
+ SearchbarComponent,
7956
+ EmptyStateComponent,
7957
+ FilterComponent,
7958
+ ComponentRendererComponent
7959
+ ], 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"] }]
7960
+ }], ctorParameters: () => [], propDecorators: { type: [{
7961
+ type: Input
7962
+ }], translatable: [{
7963
+ type: Input
7964
+ }], showSearchbar: [{
7965
+ type: Input
7966
+ }], data: [{
7967
+ type: Input
7968
+ }], source: [{
7969
+ type: Input
7970
+ }], start: [{
7971
+ type: Input
7972
+ }], limit: [{
7973
+ type: Input
7974
+ }], loadMoreData: [{
7975
+ type: Input
7976
+ }], lines: [{
7977
+ type: Input
7978
+ }], inset: [{
7979
+ type: Input
7980
+ }], scrollThreshold: [{
7981
+ type: Input
7982
+ }], scrollPosition: [{
7983
+ type: Input
7984
+ }], loadingText: [{
7985
+ type: Input
7986
+ }], showRefresher: [{
7987
+ type: Input
7988
+ }], loadingSpinner: [{
7989
+ type: Input
7990
+ }], enableFilter: [{
7991
+ type: Input
7992
+ }], sortDirection: [{
7993
+ type: Input
7994
+ }], sortBy: [{
7995
+ type: Input
7996
+ }], disableSort: [{
7997
+ type: Input
7998
+ }], emptyIcon: [{
7999
+ type: Input
8000
+ }], empty: [{
8001
+ type: Input
8002
+ }], refreshEvent: [{
8003
+ type: Output
8004
+ }], clickEvent: [{
8005
+ type: Output
8006
+ }], handleClick: [{
8007
+ type: HostListener,
8008
+ args: ['window:ListItemClickEvent', ['$event']]
8009
+ }], handleSearch: [{
8010
+ type: HostListener,
8011
+ args: ['window:searchbarEvent', ['$event']]
8012
+ }], refresh: [{
8013
+ type: HostListener,
8014
+ args: ['window:BackButtonNavigationEndEvent', ['$event']]
8015
+ }] } });
8016
+
8017
+ /**
8018
+ * @description A component for displaying a list item with various customization options.
8019
+ * @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.
8020
+ *
8021
+ * @class
8022
+ * @extends NgxBaseComponent
8023
+ *
8024
+ * @param {string} [lines='none'] - Determines the line style of the item. Can be 'inset', 'inseet', or 'none'.
8025
+ * @param {Record<string, any>} item - The data item to be displayed in the list item.
8026
+ * @param {string} icon - The name of the icon to be displayed.
8027
+ * @param {'start' | 'end'} [iconSlot='start'] - The position of the icon within the item.
8028
+ * @param {StringOrBoolean} [button=true] - Determines if the item should behave as a button.
8029
+ * @param {string} [title] - The main title of the list item.
8030
+ * @param {string} [description] - A description for the list item.
8031
+ * @param {string} [info] - Additional information for the list item.
8032
+ * @param {string} [subinfo] - Sub-information for the list item.
8033
+ *
8034
+ * @example
8035
+ * <ngx-decaf-list-item
8036
+ * [item]="dataItem"
8037
+ * icon="star"
8038
+ * title="Item Title"
8039
+ * description="Item Description"
8040
+ * (clickEvent)="handleItemClick($event)">
8041
+ * </ngx-decaf-list-item>
8042
+ *
8043
+ * @mermaid
8044
+ * sequenceDiagram
8045
+ * participant C as Component
8046
+ * participant V as View
8047
+ * participant U as User
8048
+ * C->>V: Initialize component
8049
+ * V->>U: Display list item
8050
+ * U->>V: Click on item or action
8051
+ * V->>C: Trigger handleAction()
8052
+ * C->>C: Process action
8053
+ * C->>V: Update view or navigate
8054
+ */
8055
+ let ListItemComponent = class ListItemComponent extends NgxBaseComponent {
8021
8056
  /**
8022
- * @description Fetches data from a request source.
8023
- * @summary Retrieves data from the configured source function or URL, processes it,
8024
- * and updates the component's data state. This method handles both initial data loading
8025
- * and subsequent refresh operations when using an external data source rather than a model.
8026
- *
8027
- * @param {boolean} force - Whether to force a refresh even if data already exists
8028
- * @param {number} start - The starting index for pagination
8029
- * @param {number} limit - The maximum number of items to retrieve
8030
- * @returns {Promise<KeyValue[]>} A promise that resolves to the fetched data
8057
+ * @description Creates an instance of ListItemComponent.
8058
+ * @summary Initializes a new ListItemComponent by calling the parent class constructor
8059
+ * with the component name for logging and identification purposes. Also registers
8060
+ * all available Ionic icons to ensure they can be displayed in the component.
8031
8061
  *
8032
- * @memberOf ListComponent
8062
+ * @memberOf ListItemComponent
8033
8063
  */
8034
- async getFromRequest(force = false, start, limit) {
8035
- let request = [];
8036
- if (!this.data?.length || force || this.searchValue?.length || !!this.searchValue) {
8037
- // (self.data as ListItem[]) = [];
8038
- if (!this.searchValue?.length && !this.searchValue) {
8039
- if (!this.source && !this.data?.length) {
8040
- this.logger.info('No data and source passed to infinite list');
8041
- return [];
8042
- }
8043
- if (this.source instanceof Function)
8044
- request = await this.source();
8045
- if (!Array.isArray(request))
8046
- request = request?.['response']?.['data'] || request?.['results'] || [];
8047
- this.data = [...await this.parseResult(request)];
8048
- if (this.data?.length)
8049
- this.items = this.type === ListComponentsTypes.INFINITE ?
8050
- (this.items || []).concat([...this.data.slice(start, limit)]) : [...request.slice(start, limit)];
8051
- }
8052
- else {
8053
- this.data = this.parseSearchResults(this.data, this.searchValue);
8054
- this.items = this.data;
8055
- }
8056
- }
8057
- if (this.loadMoreData && this.type === ListComponentsTypes.PAGINATED)
8058
- this.getMoreData(this.data?.length || 0);
8059
- return this.data || [];
8064
+ constructor() {
8065
+ super("ListItemComponent");
8066
+ /**
8067
+ * @description Controls the display of lines around the list item.
8068
+ * @summary Determines how lines are displayed around the list item borders.
8069
+ * 'inset' shows lines with padding, 'full' shows full-width lines, and 'none'
8070
+ * removes all lines. This affects the visual separation between list items.
8071
+ *
8072
+ * @type {'inset' | 'full' | 'none'}
8073
+ * @default 'inset'
8074
+ * @memberOf ListItemComponent
8075
+ */
8076
+ this.lines = 'full';
8077
+ /**
8078
+ * @description Position of the icon within the list item.
8079
+ * @summary Determines whether the icon appears at the start (left in LTR languages)
8080
+ * or end (right in LTR languages) of the list item. This affects the overall
8081
+ * layout and visual hierarchy of the item content.
8082
+ *
8083
+ * @type {'start' | 'end'}
8084
+ * @default 'start'
8085
+ * @memberOf ListItemComponent
8086
+ */
8087
+ this.iconSlot = 'start';
8088
+ /**
8089
+ * @description Controls whether the list item behaves as a clickable button.
8090
+ * @summary When set to true, the list item will have button-like behavior including
8091
+ * hover effects, click handling, and appropriate accessibility attributes.
8092
+ * When false, the item is displayed as static content without interactive behavior.
8093
+ *
8094
+ * @type {StringOrBoolean}
8095
+ * @default true
8096
+ * @memberOf ListItemComponent
8097
+ */
8098
+ this.button = true;
8099
+ /**
8100
+ * @description Event emitter for list item click interactions.
8101
+ * @summary Emits custom events when the list item is clicked or when actions
8102
+ * are performed on it. The emitted event contains information about the action,
8103
+ * the item data, and other relevant context for parent components to handle.
8104
+ *
8105
+ * @type {EventEmitter<ListItemCustomEvent>}
8106
+ * @memberOf ListItemComponent
8107
+ */
8108
+ this.clickEvent = new EventEmitter();
8109
+ /**
8110
+ * @description Flag indicating whether slide items are currently enabled.
8111
+ * @summary Controls the visibility of slide actions based on screen size and
8112
+ * available operations. When true, users can swipe on the item to reveal
8113
+ * action buttons for operations like edit and delete.
8114
+ *
8115
+ * @type {boolean}
8116
+ * @default false
8117
+ * @memberOf ListItemComponent
8118
+ */
8119
+ this.showSlideItems = false;
8120
+ /**
8121
+ * @description Flag indicating whether the action menu popover is currently open.
8122
+ * @summary Tracks the state of the action menu to prevent multiple instances
8123
+ * from being opened simultaneously and to ensure proper cleanup when actions
8124
+ * are performed. Used for managing the popover lifecycle.
8125
+ *
8126
+ * @type {boolean}
8127
+ * @default false
8128
+ * @memberOf ListItemComponent
8129
+ */
8130
+ this.actionMenuOpen = false;
8131
+ /**
8132
+ * @description Angular NavController service for handling navigation.
8133
+ * @summary Injected service that provides methods for programmatic navigation
8134
+ * within the Ionic application. Used for navigating to different routes when
8135
+ * list item actions are performed or when the item itself is clicked.
8136
+ *
8137
+ * @private
8138
+ * @type {NavController}
8139
+ * @memberOf ListItemComponent
8140
+ */
8141
+ this.navController = inject(NavController);
8142
+ addIcons(allIcons);
8060
8143
  }
8061
8144
  /**
8062
- * @description Fetches data from a model source.
8063
- * @summary Retrieves data from the configured model using its pagination or find methods,
8064
- * processes it, and updates the component's data state. This method handles both initial
8065
- * data loading and subsequent refresh operations when using a model as the data source.
8145
+ * @description Initializes the component after Angular first displays the data-bound properties.
8146
+ * @summary Sets up the component by determining slide item visibility, processing boolean inputs,
8147
+ * building CSS class names based on properties, and capturing the current window width.
8148
+ * This method prepares the component for user interaction by ensuring all properties are
8149
+ * properly initialized and responsive behavior is configured.
8066
8150
  *
8067
- * @param {boolean} force - Whether to force a refresh even if data already exists
8068
- * @param {number} start - The starting index for pagination
8069
- * @param {number} limit - The maximum number of items to retrieve
8070
- * @returns {Promise<KeyValue[]>} A promise that resolves to the fetched data
8151
+ * @mermaid
8152
+ * sequenceDiagram
8153
+ * participant A as Angular Lifecycle
8154
+ * participant L as ListItemComponent
8155
+ * participant W as Window
8071
8156
  *
8072
- * @memberOf ListComponent
8157
+ * A->>L: ngOnInit()
8158
+ * L->>L: enableSlideItems()
8159
+ * L->>L: Process button boolean
8160
+ * L->>L: Build className with flex classes
8161
+ * alt operations exist
8162
+ * L->>L: Add 'action' class
8163
+ * end
8164
+ * L->>W: getWindowWidth()
8165
+ * W-->>L: Return current width
8166
+ * L->>L: Store windowWidth
8167
+ *
8168
+ * @return {Promise<void>}
8169
+ * @memberOf ListItemComponent
8073
8170
  */
8074
- async getFromModel(force = false) {
8075
- let data = [...this.data || []];
8076
- let request = [];
8077
- // getting model repository
8078
- if (!this._repository)
8079
- this._repository = this.repository;
8080
- const repo = this._repository;
8081
- if (!this.data?.length || force || this.searchValue?.length || !!this.searchValue) {
8082
- try {
8083
- if (!this.searchValue?.length && !this.searchValue) {
8084
- this.data = [];
8085
- // const rawQuery = this.parseQuery(self.model as Repository<Model>, start, limit);
8086
- // request = this.parseResult(await (this.model as any)?.paginate(start, limit));
8087
- if (!this.paginator) {
8088
- this.paginator = await repo
8089
- .select()
8090
- .orderBy([this.pk, this.sortDirection])
8091
- .paginate(this.limit);
8092
- }
8093
- request = await this.parseResult(this.paginator);
8094
- }
8095
- else {
8096
- if (!this.indexes)
8097
- this.indexes = (Object.values(this.mapper) || [this.pk]);
8098
- const condition = this.parseConditions(this.searchValue);
8099
- request = await this.parseResult(await repo.query(condition, (this.sortBy || this.pk), this.sortDirection));
8100
- data = [];
8101
- }
8102
- data = this.type === ListComponentsTypes.INFINITE ? [...(data).concat(request)] : [...request];
8103
- }
8104
- catch (error) {
8105
- this.logger.error(error?.message || `Unable to find ${this.model} on registry. Return empty array from component`);
8106
- }
8107
- }
8108
- if (data?.length) {
8109
- if (this.searchValue) {
8110
- this.items = [...data];
8111
- if (this.items?.length <= this.limit)
8112
- this.loadMoreData = false;
8113
- }
8114
- else {
8115
- this.items = [...data];
8116
- }
8117
- }
8118
- if (this.type === ListComponentsTypes.PAGINATED && this.paginator)
8119
- this.getMoreData(this.paginator.total);
8120
- return data || [];
8171
+ async ngOnInit() {
8172
+ this.showSlideItems = this.enableSlideItems();
8173
+ this.button = stringToBoolean(this.button);
8174
+ this.className = `${this.className} dcf-flex dcf-flex-middle grid-item`;
8175
+ if (this.operations?.length)
8176
+ this.className += ` action`;
8177
+ this.windowWidth = getWindowWidth();
8121
8178
  }
8122
8179
  /**
8123
- * @description Converts search values or filter queries into database conditions.
8124
- * @summary Transforms search input or complex filter queries into Condition objects
8125
- * that can be used for database querying. Handles both simple string/number searches
8126
- * across indexed fields and complex filter queries with multiple criteria.
8180
+ * @description Handles user interactions and actions performed on the list item.
8181
+ * @summary This method is the central action handler for list item interactions. It manages
8182
+ * event propagation, dismisses open action menus, removes focus traps, and either emits
8183
+ * events for parent components to handle or performs navigation based on the component's
8184
+ * route configuration. This method supports both event-driven and navigation-driven architectures.
8127
8185
  *
8128
- * For simple searches (string/number):
8129
- * - Creates conditions that search across all indexed fields
8130
- * - Uses equality for numeric values and regex for string values
8131
- * - Combines conditions with OR logic to search multiple fields
8186
+ * @param {CrudOperations} action - The type of CRUD operation being performed
8187
+ * @param {Event} event - The browser event that triggered the action
8188
+ * @param {HTMLElement} [target] - Optional target element for the event
8189
+ * @return {Promise<boolean|void>} A promise that resolves to navigation success or void for events
8132
8190
  *
8133
- * For complex filter queries:
8134
- * - Processes each filter item with its specific condition type
8135
- * - Supports Equal, Not Equal, Contains, Not Contains, Greater Than, Less Than
8136
- * - Updates sort configuration based on the filter query
8137
- * - Combines multiple filter conditions with OR logic
8191
+ * @mermaid
8192
+ * sequenceDiagram
8193
+ * participant U as User
8194
+ * participant L as ListItemComponent
8195
+ * participant P as Parent Component
8196
+ * participant N as NavController
8197
+ * participant E as Event System
8138
8198
  *
8139
- * @param {string | number | IFilterQuery} value - The search value or filter query object
8140
- * @returns {Condition<Model>} A Condition object for database querying
8141
- * @memberOf ListComponent
8199
+ * U->>L: Perform action (click/swipe)
8200
+ * L->>L: stopImmediatePropagation()
8201
+ * alt actionMenuOpen
8202
+ * L->>L: Dismiss action menu
8203
+ * end
8204
+ * L->>L: removeFocusTrap()
8205
+ * alt No route configured
8206
+ * L->>E: windowEventEmitter()
8207
+ * L->>P: clickEvent.emit()
8208
+ * else Route configured
8209
+ * L->>N: redirect(action, uid)
8210
+ * N-->>L: Return navigation result
8211
+ * end
8212
+ *
8213
+ * @memberOf ListItemComponent
8142
8214
  */
8143
- parseConditions(value) {
8144
- let _condition;
8145
- if (typeof value === Primitives.STRING || typeof value === Primitives.NUMBER) {
8146
- _condition = Condition.attribute(this.pk).eq(!isNaN(value) ? Number(value) : value);
8147
- for (const index of this.indexes) {
8148
- if (index === this.pk)
8149
- continue;
8150
- let orCondition;
8151
- if (!isNaN(value)) {
8152
- orCondition = Condition.attribute(index).eq(Number(value));
8153
- }
8154
- else {
8155
- orCondition = Condition.attribute(index).regexp(value);
8156
- }
8157
- _condition = _condition.or(orCondition);
8158
- }
8159
- }
8160
- else {
8161
- const { query, sort } = value;
8162
- _condition = Condition.attribute(this.pk).dif('null');
8163
- if (query?.length)
8164
- _condition = undefined;
8165
- (query || []).forEach((item) => {
8166
- const { value, condition, index } = item;
8167
- let val = value;
8168
- if (index === this.pk || !isNaN(val))
8169
- val = Number(val);
8170
- let orCondition;
8171
- switch (condition) {
8172
- case "Equal":
8173
- orCondition = Condition.attribute(index).eq(val);
8174
- break;
8175
- case "Not Equal":
8176
- orCondition = Condition.attribute(index).dif(val);
8177
- break;
8178
- case "Not Contains":
8179
- orCondition = !Condition.attribute(index).regexp(new RegExp(`^(?!.*${val}).*$`));
8180
- break;
8181
- case "Contains":
8182
- orCondition = Condition.attribute(index).regexp(val);
8183
- break;
8184
- case "Greater Than":
8185
- orCondition = Condition.attribute(index).gte(val);
8186
- break;
8187
- case "Less Than":
8188
- orCondition = Condition.attribute(index).lte(val);
8189
- break;
8190
- }
8191
- _condition = (!_condition ?
8192
- orCondition : _condition.and(orCondition));
8193
- });
8194
- this.sortBy = sort?.value || this.pk;
8195
- this.sortDirection = sort?.direction || this.sortDirection;
8215
+ async handleAction(action, event, target) {
8216
+ event.stopImmediatePropagation();
8217
+ if (this.actionMenuOpen)
8218
+ await this.actionMenuComponent.dismiss();
8219
+ // forcing trap focus
8220
+ removeFocusTrap();
8221
+ if (!this.route) {
8222
+ const event = { target: target, action, pk: this.pk, data: this.uid, name: EventConstants.CLICK, component: this.componentName };
8223
+ windowEventEmitter(`ListItem${EventConstants.CLICK}`, event);
8224
+ return this.clickEvent.emit(event);
8196
8225
  }
8197
- return _condition;
8226
+ return await this.redirect(action, (typeof this.uid === 'number' ? `${this.uid}` : this.uid));
8198
8227
  }
8199
8228
  /**
8200
- * @description Processes query results into a standardized format.
8201
- * @summary Handles different result formats from various data sources, extracting
8202
- * pagination information when available and applying any configured data mapping.
8203
- * This ensures consistent data structure regardless of the source.
8229
+ * @description Responsive handler that enables or disables slide items based on screen size and operations.
8230
+ * @summary This method is automatically called when the window is resized and also during component
8231
+ * initialization. It determines whether slide actions should be available based on the current
8232
+ * window width and the presence of UPDATE or DELETE operations. Slide items are typically hidden
8233
+ * on larger screens where there's space for dedicated action buttons.
8204
8234
  *
8205
- * @protected
8206
- * @param {KeyValue[] | Paginator} result - The raw query result
8207
- * @returns {KeyValue[]} The processed array of items
8235
+ * @return {boolean} True if slide items should be shown, false otherwise
8208
8236
  *
8209
- * @memberOf ListComponent
8237
+ * @mermaid
8238
+ * sequenceDiagram
8239
+ * participant W as Window
8240
+ * participant L as ListItemComponent
8241
+ * participant U as UI
8242
+ *
8243
+ * W->>L: resize event
8244
+ * L->>W: getWindowWidth()
8245
+ * W-->>L: Return current width
8246
+ * L->>L: Store windowWidth
8247
+ * alt No operations OR width > 639px
8248
+ * L->>U: showSlideItems = false
8249
+ * else Operations include UPDATE/DELETE
8250
+ * L->>U: showSlideItems = true
8251
+ * end
8252
+ * L-->>U: Return showSlideItems value
8253
+ *
8254
+ * @memberOf ListItemComponent
8210
8255
  */
8211
- async parseResult(result) {
8212
- if (!Array.isArray(result) && ('page' in result && 'total' in result)) {
8213
- const paginator = result;
8214
- try {
8215
- result = await paginator.page(this.page);
8216
- // TODO: Chage for result.total;
8217
- this.getMoreData(paginator.total);
8218
- }
8219
- catch (error) {
8220
- this.logger.info(error?.message || 'Unable to get page from paginator. Return empty array from component');
8221
- result = [];
8222
- }
8223
- }
8224
- else {
8225
- this.getMoreData(result?.length || 0);
8226
- }
8227
- return (Object.keys(this.mapper || {}).length) ?
8228
- this.mapResults(result) : result;
8256
+ enableSlideItems() {
8257
+ this.windowWidth = getWindowWidth();
8258
+ if (!this.operations?.length || this.windowWidth > 639)
8259
+ return this.showSlideItems = false;
8260
+ this.showSlideItems = this.operations.includes(OperationKeys.UPDATE) || this.operations.includes(OperationKeys.DELETE);
8261
+ return this.showSlideItems;
8229
8262
  }
8230
8263
  /**
8231
- * @description Updates pagination state based on data length.
8232
- * @summary Calculates whether more data is available and how many pages exist
8233
- * based on the total number of items and the configured limit per page.
8234
- * This information is used to control pagination UI and infinite scrolling behavior.
8264
+ * @description Animates and removes an element from the DOM.
8265
+ * @summary This method applies CSS animation classes to create a smooth fade-out effect
8266
+ * before removing the element from the DOM. The animation enhances user experience by
8267
+ * providing visual feedback when items are deleted or removed from lists. The timing
8268
+ * is coordinated with the CSS animation duration to ensure the element is removed
8269
+ * after the animation completes.
8235
8270
  *
8236
- * @param {number} length - The total number of items available
8237
- * @returns {void}
8271
+ * @param {HTMLElement} element - The DOM element to animate and remove
8272
+ * @return {void}
8238
8273
  *
8239
- * @memberOf ListComponent
8274
+ * @mermaid
8275
+ * sequenceDiagram
8276
+ * participant L as ListItemComponent
8277
+ * participant E as HTMLElement
8278
+ * participant D as DOM
8279
+ *
8280
+ * L->>E: Add animation classes
8281
+ * Note over E: uk-animation-fade, uk-animation-medium, uk-animation-reverse
8282
+ * E->>E: Start fade animation
8283
+ * L->>L: setTimeout(600ms)
8284
+ * Note over L: Wait for animation to complete
8285
+ * L->>D: element.remove()
8286
+ * D->>D: Remove element from DOM
8287
+ *
8288
+ * @memberOf ListItemComponent
8240
8289
  */
8241
- getMoreData(length) {
8242
- if (this.type === ListComponentsTypes.INFINITE) {
8243
- if (this.paginator)
8244
- length = length * this.limit;
8245
- if (length <= this.limit) {
8246
- this.loadMoreData = false;
8247
- }
8248
- else {
8249
- this.pages = Math.floor(length / this.limit);
8250
- if ((this.pages * this.limit) < length)
8251
- this.pages += 1;
8252
- if (this.pages === 1)
8253
- this.loadMoreData = false;
8254
- }
8255
- }
8256
- else {
8257
- this.pages = length;
8258
- if (this.pages === 1)
8259
- this.loadMoreData = false;
8260
- }
8290
+ removeElement(element) {
8291
+ element.classList.add('uk-animation-fade', 'uk-animation-medium', 'uk-animation-reverse');
8292
+ setTimeout(() => { element.remove(); }, 600);
8261
8293
  }
8262
8294
  /**
8263
- * @description Maps a single item using the configured mapper.
8264
- * @summary Transforms a data item according to the mapping configuration,
8265
- * extracting nested properties and formatting values as needed. This allows
8266
- * the component to display data in a format different from how it's stored.
8295
+ * @description Navigates to a new route based on the specified action and item ID.
8296
+ * @summary This method constructs a navigation URL using the component's route configuration,
8297
+ * the specified action, and an item identifier. It uses Ionic's NavController to perform
8298
+ * forward navigation with appropriate animations. This method is typically used for
8299
+ * CRUD operations where each action (create, read, update, delete) has its own route.
8267
8300
  *
8268
- * @protected
8269
- * @param {KeyValue} item - The item to map
8270
- * @param {KeyValue} mapper - The mapping configuration
8271
- * @param {KeyValue} [props] - Additional properties to include
8272
- * @returns {KeyValue} The mapped item
8301
+ * @param {string} action - The action to be performed (e.g., 'edit', 'view', 'delete')
8302
+ * @param {string} [id] - The unique identifier of the item to be acted upon
8303
+ * @return {Promise<boolean>} A promise that resolves to true if navigation was successful
8273
8304
  *
8274
- * @memberOf ListComponent
8305
+ * @mermaid
8306
+ * sequenceDiagram
8307
+ * participant L as ListItemComponent
8308
+ * participant N as NavController
8309
+ * participant R as Router
8310
+ *
8311
+ * L->>L: redirect(action, id)
8312
+ * L->>L: Construct URL: /{route}/{action}/{id}
8313
+ * L->>N: navigateForward(url)
8314
+ * N->>R: Navigate to constructed URL
8315
+ * R-->>N: Return navigation result
8316
+ * N-->>L: Return boolean success
8317
+ *
8318
+ * @memberOf ListItemComponent
8275
8319
  */
8276
- itemMapper(item, mapper, props) {
8277
- return Object.entries(mapper).reduce((accum, [key, value]) => {
8278
- const arrayValue = value.split('.');
8279
- if (!value) {
8280
- accum[key] = value;
8281
- }
8282
- else {
8283
- if (arrayValue.length === 1) {
8284
- value = item?.[value] ? item[value] : value !== key ? value : "";
8285
- if (isValidDate(value))
8286
- value = `${formatDate(value)}`;
8287
- accum[key] = value;
8288
- }
8289
- else {
8290
- let val;
8291
- for (const _value of arrayValue)
8292
- val = !val
8293
- ? item[_value]
8294
- : (typeof val === 'string' ? JSON.parse(val) : val)[_value];
8295
- if (isValidDate(new Date(val)))
8296
- val = `${formatDate(val)}`;
8297
- accum[key] = val === null || val === undefined ? value : val;
8298
- }
8299
- }
8300
- return Object.assign({}, props || {}, accum);
8301
- }, {});
8320
+ async redirect(action, id) {
8321
+ return await this.navController.navigateForward(`/${this.route}/${action}/${id || this.uid}`);
8302
8322
  }
8303
8323
  /**
8304
- * @description Maps all result items using the configured mapper.
8305
- * @summary Applies the itemMapper to each item in the result set, adding
8306
- * common properties like operations and route information. This transforms
8307
- * the raw data into the format expected by the list item components.
8324
+ * @description Presents the actions menu popover for the list item.
8325
+ * @summary This method handles the display of a contextual action menu when triggered by user
8326
+ * interaction (typically a long press or right-click). It stops event propagation to prevent
8327
+ * unwanted side effects, removes any existing focus traps for accessibility, configures the
8328
+ * popover with the triggering event, and opens the action menu. The menu typically contains
8329
+ * available CRUD operations for the item.
8308
8330
  *
8309
- * @param {KeyValue[]} data - The array of items to map
8310
- * @returns {KeyValue[]} The array of mapped items
8331
+ * @param {Event} event - The event that triggered the action menu request
8332
+ * @return {void}
8311
8333
  *
8312
- * @memberOf ListComponent
8334
+ * @mermaid
8335
+ * sequenceDiagram
8336
+ * participant U as User
8337
+ * participant L as ListItemComponent
8338
+ * participant P as Popover
8339
+ * participant A as Accessibility
8340
+ *
8341
+ * U->>L: Trigger action menu (long press/right-click)
8342
+ * L->>L: stopImmediatePropagation()
8343
+ * L->>A: removeFocusTrap()
8344
+ * L->>P: Set event reference
8345
+ * L->>L: actionMenuOpen = true
8346
+ * L->>P: Display popover with actions
8347
+ *
8348
+ * @memberOf ListItemComponent
8313
8349
  */
8314
- mapResults(data) {
8315
- if (!data || !data.length)
8316
- return [];
8317
- // passing uid as prop to mapper
8318
- this.mapper = { ...this.mapper, ...{ uid: this.pk } };
8319
- const props = Object.assign({
8320
- operations: this.operations,
8321
- route: this.route,
8322
- ...Object.keys(this.item).reduce((acc, key) => {
8323
- acc[key] = this.item[key];
8324
- return acc;
8325
- }, {}),
8326
- // ... (!this.item.render ? {} : Object.keys(this.item).reduce((acc: KeyValue, key: string) => {
8327
- // acc[key] = this.item[key as keyof IListItemProp];
8328
- // return acc;
8329
- // }, {}))
8330
- });
8331
- return data.reduce((accum, curr) => {
8332
- accum.push({ ...this.itemMapper(curr, this.mapper, props), ...{ pk: this.pk } });
8333
- return accum;
8334
- }, []);
8350
+ presentActionsMenu(event) {
8351
+ event.stopImmediatePropagation();
8352
+ // forcing trap focus
8353
+ removeFocusTrap();
8354
+ this.actionMenuComponent.event = event;
8355
+ this.actionMenuOpen = true;
8335
8356
  }
8336
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8337
- 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"] }] }); }
8357
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ListItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8358
+ 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" }] }); }
8338
8359
  };
8339
- ListComponent = __decorate([
8360
+ ListItemComponent = __decorate([
8340
8361
  Dynamic(),
8341
8362
  __metadata("design:paramtypes", [])
8342
- ], ListComponent);
8343
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ListComponent, decorators: [{
8363
+ ], ListItemComponent);
8364
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ListItemComponent, decorators: [{
8344
8365
  type: Component,
8345
- args: [{ selector: 'ngx-decaf-list', standalone: true, imports: [
8366
+ args: [{ selector: 'ngx-decaf-list-item', standalone: true, imports: [
8346
8367
  TranslatePipe,
8347
- IonRefresher,
8348
- IonLoading,
8349
- PaginationComponent,
8350
8368
  IonList,
8369
+ IonListHeader,
8351
8370
  IonItem,
8352
- IonThumbnail,
8353
- IonSkeletonText,
8371
+ IonItemSliding,
8372
+ IonItemOptions,
8373
+ IonItemOption,
8374
+ IonIcon,
8354
8375
  IonLabel,
8355
- IonText,
8356
- IonRefresherContent,
8357
- IonInfiniteScroll,
8358
- IonInfiniteScrollContent,
8359
- IonThumbnail,
8360
- IonSkeletonText,
8361
- SearchbarComponent,
8362
- EmptyStateComponent,
8363
- ListItemComponent,
8364
- FilterComponent,
8365
- ComponentRendererComponent
8366
- ], 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"] }]
8367
- }], ctorParameters: () => [], propDecorators: { type: [{
8368
- type: Input
8369
- }], translatable: [{
8370
- type: Input
8371
- }], showSearchbar: [{
8372
- type: Input
8373
- }], data: [{
8374
- type: Input
8375
- }], source: [{
8376
- type: Input
8377
- }], start: [{
8378
- type: Input
8379
- }], limit: [{
8380
- type: Input
8381
- }], loadMoreData: [{
8382
- type: Input
8376
+ IonButton,
8377
+ IonContent,
8378
+ IonPopover
8379
+ ], 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"] }]
8380
+ }], ctorParameters: () => [], propDecorators: { actionMenuComponent: [{
8381
+ type: ViewChild,
8382
+ args: ['actionMenuComponent']
8383
8383
  }], lines: [{
8384
8384
  type: Input
8385
- }], inset: [{
8386
- type: Input
8387
- }], scrollThreshold: [{
8388
- type: Input
8389
- }], scrollPosition: [{
8390
- type: Input
8391
- }], loadingText: [{
8392
- type: Input
8393
- }], showRefresher: [{
8385
+ }], item: [{
8394
8386
  type: Input
8395
- }], loadingSpinner: [{
8387
+ }], icon: [{
8396
8388
  type: Input
8397
- }], enableFilter: [{
8389
+ }], iconSlot: [{
8398
8390
  type: Input
8399
- }], sortDirection: [{
8391
+ }], button: [{
8400
8392
  type: Input
8401
- }], sortBy: [{
8393
+ }], title: [{
8402
8394
  type: Input
8403
- }], disableSort: [{
8395
+ }], description: [{
8404
8396
  type: Input
8405
- }], emptyIcon: [{
8397
+ }], info: [{
8406
8398
  type: Input
8407
- }], empty: [{
8399
+ }], subinfo: [{
8408
8400
  type: Input
8409
- }], refreshEvent: [{
8410
- type: Output
8411
8401
  }], clickEvent: [{
8412
8402
  type: Output
8413
- }], handleClick: [{
8414
- type: HostListener,
8415
- args: ['window:ListItemClickEvent', ['$event']]
8416
- }], handleSearch: [{
8417
- type: HostListener,
8418
- args: ['window:searchbarEvent', ['$event']]
8419
- }], refresh: [{
8403
+ }], enableSlideItems: [{
8420
8404
  type: HostListener,
8421
- args: ['window:BackButtonNavigationEndEvent', ['$event']]
8405
+ args: ['window:resize', ['$event']]
8422
8406
  }] } });
8423
8407
 
8424
- let StepedFormComponent = class StepedFormComponent {
8408
+ let SteppedFormComponent = class SteppedFormComponent {
8425
8409
  /**
8426
- * @description Creates an instance of StepedFormComponent.
8427
- * @summary Initializes a new StepedFormComponent instance and registers the required
8410
+ * @description Creates an instance of SteppedFormComponent.
8411
+ * @summary Initializes a new SteppedFormComponent instance and registers the required
8428
8412
  * Ionic icons for navigation buttons (forward and back arrows).
8429
8413
  *
8430
- * @memberOf StepedFormComponent
8414
+ * @memberOf SteppedFormComponent
8431
8415
  */
8432
8416
  constructor() {
8433
8417
  /**
@@ -8438,7 +8422,7 @@ let StepedFormComponent = class StepedFormComponent {
8438
8422
  *
8439
8423
  * @type {number}
8440
8424
  * @default 1
8441
- * @memberOf StepedFormComponent
8425
+ * @memberOf SteppedFormComponent
8442
8426
  */
8443
8427
  this.pages = 1;
8444
8428
  /**
@@ -8449,7 +8433,7 @@ let StepedFormComponent = class StepedFormComponent {
8449
8433
  *
8450
8434
  * @type {CrudOperations}
8451
8435
  * @default OperationKeys.CREATE
8452
- * @memberOf StepedFormComponent
8436
+ * @memberOf SteppedFormComponent
8453
8437
  */
8454
8438
  this.operation = OperationKeys.CREATE;
8455
8439
  /**
@@ -8460,7 +8444,7 @@ let StepedFormComponent = class StepedFormComponent {
8460
8444
  *
8461
8445
  * @type {number}
8462
8446
  * @default 1
8463
- * @memberOf StepedFormComponent
8447
+ * @memberOf SteppedFormComponent
8464
8448
  */
8465
8449
  this.startPage = 1;
8466
8450
  /**
@@ -8470,7 +8454,7 @@ let StepedFormComponent = class StepedFormComponent {
8470
8454
  * updated whenever the user navigates between pages.
8471
8455
  *
8472
8456
  * @type {UIModelMetadata[] | undefined}
8473
- * @memberOf StepedFormComponent
8457
+ * @memberOf SteppedFormComponent
8474
8458
  */
8475
8459
  this.activeChildren = undefined;
8476
8460
  /**
@@ -8480,7 +8464,7 @@ let StepedFormComponent = class StepedFormComponent {
8480
8464
  * when using FormArray structure.
8481
8465
  *
8482
8466
  * @type {FormGroup | undefined}
8483
- * @memberOf StepedFormComponent
8467
+ * @memberOf SteppedFormComponent
8484
8468
  */
8485
8469
  this.activeFormGroup = undefined;
8486
8470
  /**
@@ -8490,7 +8474,7 @@ let StepedFormComponent = class StepedFormComponent {
8490
8474
  * the next/back buttons or programmatic navigation.
8491
8475
  *
8492
8476
  * @type {number}
8493
- * @memberOf StepedFormComponent
8477
+ * @memberOf SteppedFormComponent
8494
8478
  */
8495
8479
  this.activePage = 1;
8496
8480
  /**
@@ -8500,7 +8484,7 @@ let StepedFormComponent = class StepedFormComponent {
8500
8484
  * logical pages and provide navigation structure.
8501
8485
  *
8502
8486
  * @type {UIModelMetadata[]}
8503
- * @memberOf StepedFormComponent
8487
+ * @memberOf SteppedFormComponent
8504
8488
  */
8505
8489
  this.pagesArray = [];
8506
8490
  /**
@@ -8510,7 +8494,7 @@ let StepedFormComponent = class StepedFormComponent {
8510
8494
  * event type information for parent components to handle.
8511
8495
  *
8512
8496
  * @type {EventEmitter<BaseCustomEvent>}
8513
- * @memberOf StepedFormComponent
8497
+ * @memberOf SteppedFormComponent
8514
8498
  */
8515
8499
  this.submitEvent = new EventEmitter();
8516
8500
  addIcons({ arrowForwardOutline, arrowBackOutline });
@@ -8524,7 +8508,7 @@ let StepedFormComponent = class StepedFormComponent {
8524
8508
  * @mermaid
8525
8509
  * sequenceDiagram
8526
8510
  * participant A as Angular Lifecycle
8527
- * participant S as StepedFormComponent
8511
+ * participant S as SteppedFormComponent
8528
8512
  * participant F as Form Service
8529
8513
  *
8530
8514
  * A->>S: ngOnInit()
@@ -8536,9 +8520,11 @@ let StepedFormComponent = class StepedFormComponent {
8536
8520
  * S->>F: Extract FormGroup for active page
8537
8521
  * F-->>S: Return activeFormGroup
8538
8522
  *
8539
- * @memberOf StepedFormComponent
8523
+ * @memberOf SteppedFormComponent
8540
8524
  */
8541
8525
  ngOnInit() {
8526
+ if (!this.locale)
8527
+ this.locale = getLocaleContext("SteppedFormComponent");
8542
8528
  this.activePage = this.startPage;
8543
8529
  this.pagesArray = this.children.reduce((acc, curr, index) => {
8544
8530
  const page = curr.props?.['page'] || index + 1;
@@ -8563,7 +8549,7 @@ let StepedFormComponent = class StepedFormComponent {
8563
8549
  * @summary Unsubscribes from any active timer subscriptions to prevent memory leaks.
8564
8550
  * This is part of Angular's component lifecycle and ensures proper resource cleanup.
8565
8551
  *
8566
- * @memberOf StepedFormComponent
8552
+ * @memberOf SteppedFormComponent
8567
8553
  */
8568
8554
  ngOnDestroy() {
8569
8555
  if (this.timerSubscription)
@@ -8581,7 +8567,7 @@ let StepedFormComponent = class StepedFormComponent {
8581
8567
  * @mermaid
8582
8568
  * sequenceDiagram
8583
8569
  * participant U as User
8584
- * participant S as StepedFormComponent
8570
+ * participant S as SteppedFormComponent
8585
8571
  * participant F as Form Service
8586
8572
  * participant P as Parent Component
8587
8573
  *
@@ -8597,7 +8583,7 @@ let StepedFormComponent = class StepedFormComponent {
8597
8583
  * S->>P: submitEvent.emit({data, name: SUBMIT})
8598
8584
  * end
8599
8585
  *
8600
- * @memberOf StepedFormComponent
8586
+ * @memberOf SteppedFormComponent
8601
8587
  */
8602
8588
  handleNext(lastPage = false) {
8603
8589
  const isValid = NgxFormService.validateFields(this.activeFormGroup);
@@ -8628,14 +8614,14 @@ let StepedFormComponent = class StepedFormComponent {
8628
8614
  * @mermaid
8629
8615
  * sequenceDiagram
8630
8616
  * participant U as User
8631
- * participant S as StepedFormComponent
8617
+ * participant S as SteppedFormComponent
8632
8618
  *
8633
8619
  * U->>S: Click Back
8634
8620
  * S->>S: activePage--
8635
8621
  * S->>S: getCurrentFormGroup(activePage)
8636
8622
  * Note over S: Update active form and children
8637
8623
  *
8638
- * @memberOf StepedFormComponent
8624
+ * @memberOf SteppedFormComponent
8639
8625
  */
8640
8626
  handleBack() {
8641
8627
  this.activePage = this.activePage - 1;
@@ -8653,7 +8639,7 @@ let StepedFormComponent = class StepedFormComponent {
8653
8639
  * @private
8654
8640
  * @mermaid
8655
8641
  * sequenceDiagram
8656
- * participant S as StepedFormComponent
8642
+ * participant S as SteppedFormComponent
8657
8643
  * participant F as FormArray
8658
8644
  * participant T as Timer
8659
8645
  *
@@ -8664,27 +8650,36 @@ let StepedFormComponent = class StepedFormComponent {
8664
8650
  * T-->>S: Filter children for active page
8665
8651
  * S->>S: Set activeChildren
8666
8652
  *
8667
- * @memberOf StepedFormComponent
8653
+ * @memberOf SteppedFormComponent
8668
8654
  */
8669
8655
  getCurrentFormGroup(page) {
8670
8656
  this.activeFormGroup = this.formGroup.at(page - 1);
8671
8657
  this.activeChildren = undefined;
8672
8658
  this.timerSubscription = timer(10).subscribe(() => {
8673
8659
  this.activeChildren = this.children.filter(c => c.props?.['page'] === page);
8674
- console.log(this.activeChildren);
8675
8660
  });
8676
8661
  }
8677
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: StepedFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8678
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: StepedFormComponent, isStandalone: true, selector: "ngx-decaf-steped-form", inputs: { pages: "pages", operation: "operation", startPage: "startPage", children: "children", formGroup: "formGroup" }, outputs: { submitEvent: "submitEvent" }, ngImport: i0, template: " <!-- @for(child of children; track trackItemFn($index, child)) {\n {{child.tag }}\n <ngx-decaf-component-renderer\n [tag]=\"child.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]='{props: child.props}'>\n </ngx-decaf-component-renderer>\n } -->\n <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 Previous\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 Submit\n } @else {\n Next\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: "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"] }] }); }
8662
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: SteppedFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8663
+ 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", 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: "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"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
8679
8664
  };
8680
- StepedFormComponent = __decorate([
8665
+ SteppedFormComponent = __decorate([
8681
8666
  Dynamic(),
8682
8667
  __metadata("design:paramtypes", [])
8683
- ], StepedFormComponent);
8684
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: StepedFormComponent, decorators: [{
8668
+ ], SteppedFormComponent);
8669
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: SteppedFormComponent, decorators: [{
8685
8670
  type: Component,
8686
- args: [{ selector: 'ngx-decaf-steped-form', imports: [ReactiveFormsModule, IonSkeletonText, IonText, IonButton, IonIcon, ModelRendererComponent, ComponentRendererComponent], standalone: true, template: " <!-- @for(child of children; track trackItemFn($index, child)) {\n {{child.tag }}\n <ngx-decaf-component-renderer\n [tag]=\"child.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]='{props: child.props}'>\n </ngx-decaf-component-renderer>\n } -->\n <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 Previous\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 Submit\n } @else {\n Next\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"] }]
8687
- }], ctorParameters: () => [], propDecorators: { pages: [{
8671
+ args: [{ selector: 'ngx-decaf-stepped-form', imports: [
8672
+ TranslatePipe,
8673
+ ReactiveFormsModule,
8674
+ IonSkeletonText,
8675
+ IonText,
8676
+ IonButton,
8677
+ IonIcon,
8678
+ ComponentRendererComponent
8679
+ ], 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"] }]
8680
+ }], ctorParameters: () => [], propDecorators: { locale: [{
8681
+ type: Input
8682
+ }], pages: [{
8688
8683
  type: Input
8689
8684
  }], operation: [{
8690
8685
  type: Input
@@ -8714,10 +8709,10 @@ class CollapsableDirective {
8714
8709
  }
8715
8710
  }
8716
8711
  }
8717
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CollapsableDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
8718
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.14", type: CollapsableDirective, isStandalone: true, selector: "[decafCollapsable]", ngImport: i0 }); }
8712
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: CollapsableDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
8713
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.2", type: CollapsableDirective, isStandalone: true, selector: "[decafCollapsable]", ngImport: i0 }); }
8719
8714
  }
8720
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CollapsableDirective, decorators: [{
8715
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: CollapsableDirective, decorators: [{
8721
8716
  type: Directive,
8722
8717
  args: [{
8723
8718
  selector: '[decafCollapsable]',
@@ -8740,11 +8735,11 @@ const Components = [
8740
8735
  FieldsetComponent,
8741
8736
  LayoutComponent,
8742
8737
  FilterComponent,
8743
- StepedFormComponent
8738
+ SteppedFormComponent
8744
8739
  ];
8745
8740
  class ForAngularComponentsModule {
8746
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ForAngularComponentsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
8747
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.14", ngImport: i0, type: ForAngularComponentsModule, imports: [ModelRendererComponent,
8741
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ForAngularComponentsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
8742
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.2", ngImport: i0, type: ForAngularComponentsModule, imports: [ModelRendererComponent,
8748
8743
  ComponentRendererComponent,
8749
8744
  CrudFieldComponent,
8750
8745
  CrudFormComponent,
@@ -8757,7 +8752,7 @@ class ForAngularComponentsModule {
8757
8752
  FieldsetComponent,
8758
8753
  LayoutComponent,
8759
8754
  FilterComponent,
8760
- StepedFormComponent, CollapsableDirective], exports: [ModelRendererComponent,
8755
+ SteppedFormComponent, CollapsableDirective], exports: [ModelRendererComponent,
8761
8756
  ComponentRendererComponent,
8762
8757
  CrudFieldComponent,
8763
8758
  CrudFormComponent,
@@ -8770,8 +8765,8 @@ class ForAngularComponentsModule {
8770
8765
  FieldsetComponent,
8771
8766
  LayoutComponent,
8772
8767
  FilterComponent,
8773
- StepedFormComponent, CollapsableDirective] }); }
8774
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ForAngularComponentsModule, imports: [CrudFieldComponent,
8768
+ SteppedFormComponent, CollapsableDirective] }); }
8769
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ForAngularComponentsModule, imports: [CrudFieldComponent,
8775
8770
  CrudFormComponent,
8776
8771
  EmptyStateComponent,
8777
8772
  ListComponent,
@@ -8781,14 +8776,14 @@ class ForAngularComponentsModule {
8781
8776
  CrudFormComponent,
8782
8777
  FieldsetComponent,
8783
8778
  FilterComponent,
8784
- StepedFormComponent] }); }
8779
+ SteppedFormComponent] }); }
8785
8780
  }
8786
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ForAngularComponentsModule, decorators: [{
8781
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ForAngularComponentsModule, decorators: [{
8787
8782
  type: NgModule,
8788
8783
  args: [{
8789
8784
  imports: [...Components, ...Directives],
8790
8785
  declarations: [],
8791
- schemas: [CUSTOM_ELEMENTS_SCHEMA],
8786
+ schemas: [],
8792
8787
  exports: [...Components, ...Directives],
8793
8788
  }]
8794
8789
  }] });
@@ -8807,5 +8802,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
8807
8802
  * Generated bundle index. Do not edit.
8808
8803
  */
8809
8804
 
8810
- 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, StepedFormComponent, 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 };
8805
+ 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 };
8811
8806
  //# sourceMappingURL=decaf-ts-for-angular.mjs.map