@decaf-ts/for-angular 0.0.25 → 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 +1465 -1488
  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/stepped-form/stepped-form.component.d.ts +0 -255
  23. package/directives/collapsable.directive.d.ts +0 -9
  24. package/directives/index.d.ts +0 -1
  25. package/engine/DynamicModule.d.ts +0 -17
  26. package/engine/NgxBaseComponent.d.ts +0 -541
  27. package/engine/NgxCrudFormField.d.ts +0 -123
  28. package/engine/NgxFormService.d.ts +0 -601
  29. package/engine/NgxRenderingEngine.d.ts +0 -282
  30. package/engine/ValidatorFactory.d.ts +0 -15
  31. package/engine/constants.d.ts +0 -168
  32. package/engine/decorators.d.ts +0 -25
  33. package/engine/index.d.ts +0 -18
  34. package/engine/interfaces.d.ts +0 -271
  35. package/engine/types.d.ts +0 -200
  36. package/esm2022/components/component-renderer/component-renderer.component.mjs +0 -321
  37. package/esm2022/components/crud-field/crud-field.component.mjs +0 -518
  38. package/esm2022/components/crud-form/constants.mjs +0 -14
  39. package/esm2022/components/crud-form/crud-form.component.mjs +0 -259
  40. package/esm2022/components/crud-form/types.mjs +0 -2
  41. package/esm2022/components/empty-state/empty-state.component.mjs +0 -345
  42. package/esm2022/components/fieldset/fieldset.component.mjs +0 -677
  43. package/esm2022/components/filter/filter.component.mjs +0 -700
  44. package/esm2022/components/for-angular-components.module.mjs +0 -84
  45. package/esm2022/components/index.mjs +0 -20
  46. package/esm2022/components/layout/layout.component.mjs +0 -150
  47. package/esm2022/components/list/list.component.mjs +0 -1238
  48. package/esm2022/components/list-item/list-item.component.mjs +0 -405
  49. package/esm2022/components/model-renderer/model-renderer.component.mjs +0 -144
  50. package/esm2022/components/pagination/constants.mjs +0 -2
  51. package/esm2022/components/pagination/pagination.component.mjs +0 -321
  52. package/esm2022/components/searchbar/searchbar.component.mjs +0 -491
  53. package/esm2022/components/stepped-form/stepped-form.component.mjs +0 -306
  54. package/esm2022/decaf-ts-for-angular.mjs +0 -5
  55. package/esm2022/directives/collapsable.directive.mjs +0 -29
  56. package/esm2022/directives/index.mjs +0 -2
  57. package/esm2022/engine/DynamicModule.mjs +0 -18
  58. package/esm2022/engine/NgxBaseComponent.mjs +0 -541
  59. package/esm2022/engine/NgxCrudFormField.mjs +0 -137
  60. package/esm2022/engine/NgxFormService.mjs +0 -917
  61. package/esm2022/engine/NgxRenderingEngine.mjs +0 -376
  62. package/esm2022/engine/ValidatorFactory.mjs +0 -106
  63. package/esm2022/engine/constants.mjs +0 -170
  64. package/esm2022/engine/decorators.mjs +0 -38
  65. package/esm2022/engine/index.mjs +0 -19
  66. package/esm2022/engine/interfaces.mjs +0 -4
  67. package/esm2022/engine/types.mjs +0 -2
  68. package/esm2022/for-angular-common.module.mjs +0 -84
  69. package/esm2022/helpers/index.mjs +0 -13
  70. package/esm2022/helpers/utils.mjs +0 -436
  71. package/esm2022/i18n/Loader.mjs +0 -86
  72. package/esm2022/i18n/data/en.json +0 -85
  73. package/esm2022/public-apis.mjs +0 -15
  74. package/for-angular-common.module.d.ts +0 -50
  75. package/helpers/index.d.ts +0 -12
  76. package/helpers/utils.d.ts +0 -279
  77. package/i18n/Loader.d.ts +0 -43
  78. package/public-apis.d.ts +0 -14
@@ -11,11 +11,10 @@ import { TranslateModule, TranslatePipe, TranslateService } from '@ngx-translate
11
11
  import { Logging } from '@decaf-ts/logging';
12
12
  import { __decorate, __metadata } from 'tslib';
13
13
  import { apply, metadata } from '@decaf-ts/reflection';
14
- import { IonInput, IonItem, IonCheckbox, IonRadioGroup, IonRadio, IonSelect, IonSelectOption, IonLabel, IonText, IonTextarea, IonIcon, IonButton, IonCard, IonCardContent, IonAccordionGroup, IonAccordion, IonList, IonReorder, IonReorderGroup, IonSearchbar, IonChip, IonListHeader, IonItemSliding, IonItemOptions, IonItemOption, IonContent, IonPopover, IonRefresher, IonThumbnail, IonSkeletonText, IonRefresherContent, IonInfiniteScroll, IonInfiniteScrollContent, IonLoading } from '@ionic/angular/standalone';
14
+ import { IonInput, IonItem, IonCheckbox, IonRadioGroup, IonRadio, IonSelect, IonSelectOption, IonLabel, IonText, IonTextarea, IonButton, IonIcon, IonCard, IonCardContent, IonAccordionGroup, IonAccordion, IonList, IonReorder, IonReorderGroup, IonSearchbar, IonChip, IonRefresher, IonThumbnail, IonSkeletonText, IonRefresherContent, IonInfiniteScroll, IonInfiniteScrollContent, IonListHeader, IonItemSliding, IonItemOptions, IonItemOption, IonContent, IonPopover } from '@ionic/angular/standalone';
15
15
  import { addIcons } from 'ionicons';
16
16
  import * as allIcons from 'ionicons/icons';
17
17
  import { chevronUpOutline, chevronDownOutline, createOutline, alertCircleOutline, chevronForwardOutline, chevronBackOutline, arrowBackOutline, arrowForwardOutline } from 'ionicons/icons';
18
- import { TranslateHttpLoader } from '@ngx-translate/http-loader';
19
18
  import { forkJoin, fromEvent, debounceTime, Subject, timer } from 'rxjs';
20
19
  import { map } from 'rxjs/operators';
21
20
  import { Repository, OrderDirection, Condition } from '@decaf-ts/core';
@@ -292,8 +291,19 @@ class ValidatorFactory {
292
291
  }
293
292
  }
294
293
 
294
+ /** */
295
295
  const DB_ADAPTER_PROVIDER_TOKEN = new InjectionToken('DB_ADAPTER_PROVIDER');
296
296
  const I18N_CONFIG_TOKEN = new InjectionToken('I18N_CONFIG_TOKEN');
297
+ function provideDbAdapter(adapterClass, options = {}) {
298
+ const adapter = new adapterClass(options);
299
+ // Log and expose adapter flavour globally
300
+ getLogger(provideDbAdapter).info(`Using ${adapter.flavour} as Db Provider`);
301
+ // getWindow()['dbAdapterFlavour'] = adapter.flavour;
302
+ return {
303
+ provide: DB_ADAPTER_PROVIDER_TOKEN,
304
+ useValue: adapter,
305
+ };
306
+ }
297
307
  const ComponentsAndModules = [
298
308
  CommonModule,
299
309
  FormsModule,
@@ -341,8 +351,8 @@ class ForAngularCommonModule {
341
351
  ngModule: ForAngularCommonModule,
342
352
  };
343
353
  }
344
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ForAngularCommonModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
345
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.14", ngImport: i0, type: ForAngularCommonModule, imports: [CommonModule,
354
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ForAngularCommonModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
355
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.2", ngImport: i0, type: ForAngularCommonModule, imports: [CommonModule,
346
356
  FormsModule,
347
357
  ReactiveFormsModule,
348
358
  TranslateModule,
@@ -351,7 +361,7 @@ class ForAngularCommonModule {
351
361
  ReactiveFormsModule,
352
362
  TranslateModule,
353
363
  TranslatePipe] }); }
354
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ForAngularCommonModule, imports: [CommonModule,
364
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ForAngularCommonModule, imports: [CommonModule,
355
365
  FormsModule,
356
366
  ReactiveFormsModule,
357
367
  TranslateModule,
@@ -360,7 +370,7 @@ class ForAngularCommonModule {
360
370
  ReactiveFormsModule,
361
371
  TranslateModule] }); }
362
372
  }
363
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ForAngularCommonModule, decorators: [{
373
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ForAngularCommonModule, decorators: [{
364
374
  type: NgModule,
365
375
  args: [{
366
376
  imports: ComponentsAndModules,
@@ -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: [{
@@ -2660,20 +2670,6 @@ var en = {
2660
2670
  component: component
2661
2671
  };
2662
2672
 
2663
- class I18nLoader {
2664
- static loadFromHttp(http) {
2665
- function getSuffix() {
2666
- const today = new Date();
2667
- return `.json?version=${today.getFullYear()}${today.getMonth()}${today.getDay()}`;
2668
- }
2669
- return new (class extends TranslateHttpLoader {
2670
- getTranslation(lang) {
2671
- const res = super.getTranslation(lang);
2672
- return res;
2673
- }
2674
- })(http, './assets/i18n/', getSuffix());
2675
- }
2676
- }
2677
2673
  function getLocaleContext(clazz, suffix) {
2678
2674
  return getLocaleFromClassName(clazz, suffix);
2679
2675
  }
@@ -2700,22 +2696,21 @@ function getLocaleContextByKey(locale, phrase) {
2700
2696
  return `${locale}.${cleanSpaces(parts.join('.'), true)}`;
2701
2697
  }
2702
2698
  function I18nLoaderFactory(http) {
2703
- const { resources, versionedSuffix } = inject(I18N_CONFIG_TOKEN, { optional: true }) ?? getI18nLoaderFactoryProviderConfig().useValue;
2704
- 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);
2705
2701
  }
2706
- function getI18nLoaderFactoryProviderConfig(resources = [], versionedSuffix = false) {
2702
+ function provideI18nLoader(resources = [], versionedSuffix = false) {
2707
2703
  if (!Array.isArray(resources))
2708
2704
  resources = [resources];
2709
2705
  return {
2710
2706
  provide: I18N_CONFIG_TOKEN,
2711
2707
  useValue: { resources: [
2712
- // { prefix: './assets/i18n/', suffix: '.json' },
2713
2708
  ...resources
2714
2709
  ], versionedSuffix }
2715
2710
  };
2716
2711
  }
2717
2712
  const libLanguage = { en };
2718
- class MultiI18nLoader {
2713
+ class I18nLoader {
2719
2714
  constructor(http, resources = [], versionedSuffix = false) {
2720
2715
  this.http = http;
2721
2716
  this.resources = resources;
@@ -3101,13 +3096,13 @@ let CrudFieldComponent = class CrudFieldComponent extends NgxCrudFormField {
3101
3096
  });
3102
3097
  component.dispatchEvent(event);
3103
3098
  }
3104
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CrudFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
3105
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: CrudFieldComponent, isStandalone: true, selector: "ngx-decaf-crud-field", inputs: { operation: "operation", name: "name", path: "path", childOf: "childOf", type: "type", value: "value", disabled: "disabled", label: "label", placeholder: "placeholder", format: "format", hidden: "hidden", max: "max", maxlength: "maxlength", min: "min", minlength: "minlength", pattern: "pattern", readonly: "readonly", required: "required", step: "step", equals: "equals", different: "different", lessThan: "lessThan", lessThanOrEqual: "lessThanOrEqual", greaterThan: "greaterThan", greaterThanOrEqual: "greaterThanOrEqual", cols: "cols", rows: "rows", alignment: "alignment", checked: "checked", justify: "justify", cancelText: "cancelText", interface: "interface", options: "options", mode: "mode", spellcheck: "spellcheck", inputmode: "inputmode", autocomplete: "autocomplete", fill: "fill", labelPlacement: "labelPlacement", updateOn: "updateOn", formGroup: "formGroup", formControl: "formControl", multiple: "multiple", uid: "uid", page: "page", translatable: "translatable", activeFormGroup: "activeFormGroup", pk: "pk" }, host: { listeners: { "window:fieldsetAddGroupEvent": "handleFieldsetCreateGroupEvent($event)", "window:fieldsetUpdateGroupEvent": "handleFieldsetUpdateGroupEvent($event)", "window:fieldsetRemoveGroupEvent": "handleFieldsetRemoveGroupEvent($event)" }, properties: { "attr.id": "uid" } }, viewQueries: [{ propertyName: "component", first: true, predicate: ["component"], descendants: true, read: ElementRef }], usesInheritance: true, ngImport: i0, template: "@if(operation === 'read' || operation === 'delete') {\n <ng-container #component>\n <div [class]=\"'dcf-input-item ' + operation\">\n <ion-item>\n <ion-label>\n {{ label | translate }}<br />\n @if(value) {\n <ion-text [innerHTML]=\"type === 'password' ? '********' : value\"></ion-text>\n } @else {\n <br />\n }\n </ion-label>\n </ion-item>\n </div>\n </ng-container>\n} @else {\n <ng-container [formGroup]=\"getActiveFormGroup\">\n <div #container [class]=\"'dcf-input-item ' + (operation || 'create')\" (createGroupEvent)=\"multiple ? handleFieldsetCreateGroupEvent($event) : ''\">\n @if(type === 'textarea') {\n <ion-textarea\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [autoGrow]=\"true\"\n [required]=\"required !== undefined ? required : null\"\n [minlength]=\"minlength !== undefined ? minlength : null\"\n [maxlength]=\"maxlength !== undefined ? maxlength : null\"\n [readonly]=\"readonly !== undefined ? readonly : null\"\n [inputmode]=\"inputmode\"\n [spellcheck]=\"spellcheck\"\n [rows]=\"rows\"\n [labelPlacement]=\"labelPlacement\"\n [value]=\"value\"\n [fill]=\"fill\"\n [errorText]=\"getErrors(container)\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [label]=\"label | translate\"\n #component>\n </ion-textarea>\n }\n @else if(type === 'checkbox') {\n <ion-item>\n <ion-checkbox\n #checkboxElement\n [mode]=\"mode\"\n [errorText]=\"getErrors(container)\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"justify\"\n [value]=\"value\"\n [checked]=\"checked\"\n [readonly]=\"readonly\"\n (ionChange)=\"checked = !checked\"\n [formControlName]=\"name\"\n #component>\n <span [innerHTML]=\"label | translate\"></span>\n </ion-checkbox>\n </ion-item>\n }\n @else if(type === 'radio') {\n <ion-radio-group [formControlName]=\"name\" [value]=\"value\" #component>\n <label class=\"dcf-radio-group-label\" [for]=\"path\">{{label | translate}}</label>\n @for(option of options; track option) {\n <ion-item>\n <ion-radio\n [errorText]=\"getErrors(container)\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [alignment]=\"alignment\"\n [justify]=\"justify\"\n [readonly]=\"readonly\"\n [value]=\"option.value\"\n >{{ translatable ? (option?.text | translate) : option?.text }}</ion-radio>\n </ion-item>\n }\n </ion-radio-group>\n }\n @else if(type === 'select') {\n <ion-select\n toggleIcon=\"chevron-down-outline\"\n expandedIcon=\"chevron-up-outline\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [label]=\"translatable ? (label | translate) : label\"\n [value]=\"value\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [errorText]=\"getErrors(container)\"\n [interface]=\"interface\" #component>\n @for(option of options; track option.value) {\n <ion-select-option [value]=\"option.value\">\n {{ option.text | translate }}\n </ion-select-option>\n }\n </ion-select>\n }\n @else {\n <ion-input\n [type]=\"type\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [inputmode]=\"inputmode\"\n [labelPlacement]=\"labelPlacement\"\n [required]=\"required !== undefined ? required : false\"\n [minlength]=\"minlength !== undefined ? minlength : null\"\n [maxlength]=\"maxlength !== undefined ? maxlength : null\"\n [readonly]=\"readonly !== undefined ? readonly : null\"\n [max]=\"max !== undefined ? max : null\"\n [min]=\"min !== undefined ? min : null\"\n [pattern]=\"pattern !== undefined ? pattern : null\"\n [step]=\"step !== undefined ? step : null\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [errorText]=\"getErrors(container)\"\n [label]=\"label | translate\" #component />\n }\n </div>\n </ng-container>\n}\n\n", styles: [".dcf-input-item.create,.dcf-input-item.update{margin-bottom:1.8rem;margin-top:0!important}.dcf-input-item.create.checkbox+.checkbox,.dcf-input-item.update.checkbox+.checkbox{margin-top:-.25rem!important}.dcf-input-item.create ion-item,.dcf-input-item.update ion-item{--border-color: transparent}.dcf-input-item.create ion-item.dcf-text-wrap ion-label>*,.dcf-input-item.update ion-item.dcf-text-wrap ion-label>*{white-space:wrap!important;word-break:break-all!important}.dcf-input-item.read ion-label,.dcf-input-item.delete ion-label{font-weight:600}@media (prefers-color-scheme: light){.dcf-input-item.read ion-label,.dcf-input-item.delete ion-label{color:var(--dcf-color-gray-7)}}.dcf-input-item.read ion-text,.dcf-input-item.delete ion-text{display:block;margin-top:.5rem!important}.dcf-input-item ion-item{--padding-end: 0rem;--padding-start: 0px !important;--padding-top: 0px !important;--background: transparent;--background-hover-opacity: .1;--background-activated-opacity: .15;--background-focused-opacity: .15}@media (prefers-color-scheme: dark){.dcf-input-item ion-item{--border-color: var(--dcf-color-gray-6)}}@media (prefers-color-scheme: light){.dcf-input-item ion-item{--background-hover: var(--dcf-color-primary);--background-focused: var(--dcf-color-primary);--border-color: var(--dcf-color-gray-2)}}.dcf-input-item ion-item span,.dcf-input-item ion-item ion-text{font-weight:400!important;font-size:.925rem;min-height:.5rem!important}.dcf-input-item ion-item span:not(.dcf-display-block),.dcf-input-item ion-item ion-text:not(.dcf-display-block){display:inline-block}.dcf-input-item ion-item span.dcf-display-block,.dcf-input-item ion-item ion-text.dcf-display-block{display:block!important}ion-textarea textarea{scrollbar-width:thin!important;margin-bottom:.5rem!important}ion-select.dcf-select-label-placement-floating::part(label){line-height:1.2rem!important}.dcf-proccessing,.dcf-proccessing *{pointer-events:none;touch-action:none;cursor:text}ion-checkbox{--size: 1.5rem;--checkbox-background-checked: var(--dcf-color-primary);--checkmark-width: 2px}ion-item{--inner-padding-start: .75rem}ion-checkbox::part(container){border-radius:50%;padding:3px}@media (prefers-color-scheme: light){ion-checkbox::part(container){border:2px solid var(--dcf-color-primary)}}ion-item .dcf-radio-group-label,ion-radio-group .dcf-radio-group-label{font-weight:600}ion-item .dcf-radio-group-label~ion-item,ion-radio-group .dcf-radio-group-label~ion-item{margin-top:.5rem;--inner-padding-start: .75rem}ion-item+.dcf-helper,ion-radio-group+.dcf-helper{padding-left:.75rem;position:relative}.dcf-error{position:absolute;color:var(--dcf-color-danger)!important;font-size:.8rem!important;font-weight:600!important;line-height:1.1rem;box-sizing:border-box;z-index:9999;margin-top:0;animation-duration:.1s;animation-timing-function:ease-out;animation-fill-mode:both;animation-name:fadeTopSmallAnimation;display:flex;align-items:flex-start;gap:.25rem}.dcf-error .ti,.dcf-error ion-icon{position:relative;top:2px!important;min-width:20px;font-size:1rem!important;text-align:left}.dcf-helper{font-size:.875rem!important;font-weight:500;margin-top:.25rem;margin-bottom:-.75rem}.dcf-helper.dcf-has-action{cursor:pointer;color:var(--dcf-color-gray-7)!important;text-decoration:underline}.dcf-error+.dcf-helper{padding-top:1rem}@keyframes fadeTopSmallAnimation{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeBottomSmallAnimation{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeTopMediumAnimation{0%{opacity:0;transform:translateY(-50px)}to{opacity:1;transform:translateY(0)}}::ng-deep ion-textarea{min-height:80px!important;scrollbar-color:#888 #f0f0f0;scrollbar-width:thin}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.MinLengthValidator, selector: "[minlength][formControlName],[minlength][formControl],[minlength][ngModel]", inputs: ["minlength"] }, { kind: "directive", type: i1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "component", type: IonInput, selector: "ion-input", inputs: ["accept", "autocapitalize", "autocomplete", "autocorrect", "autofocus", "clearInput", "clearOnEdit", "color", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "max", "maxlength", "min", "minlength", "mode", "multiple", "name", "pattern", "placeholder", "readonly", "required", "shape", "size", "spellcheck", "step", "type", "value"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonCheckbox, selector: "ion-checkbox", inputs: ["checked", "color", "disabled", "errorText", "helperText", "indeterminate", "justify", "labelPlacement", "mode", "name", "value"] }, { kind: "component", type: IonRadioGroup, selector: "ion-radio-group", inputs: ["allowEmptySelection", "compareWith", "errorText", "helperText", "name", "value"] }, { kind: "component", type: IonRadio, selector: "ion-radio", inputs: ["alignment", "color", "disabled", "justify", "labelPlacement", "mode", "name", "value"] }, { kind: "component", type: IonSelect, selector: "ion-select", inputs: ["cancelText", "color", "compareWith", "disabled", "errorText", "expandedIcon", "fill", "helperText", "interface", "interfaceOptions", "justify", "label", "labelPlacement", "mode", "multiple", "name", "okText", "placeholder", "selectedText", "shape", "toggleIcon", "value"] }, { kind: "component", type: IonSelectOption, selector: "ion-select-option", inputs: ["disabled", "value"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonTextarea, selector: "ion-textarea", inputs: ["autoGrow", "autocapitalize", "autofocus", "clearOnEdit", "color", "cols", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "maxlength", "minlength", "mode", "name", "placeholder", "readonly", "required", "rows", "shape", "spellcheck", "value", "wrap"] }] }); }
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" }] }); }
3106
3101
  };
3107
3102
  CrudFieldComponent = __decorate([
3108
3103
  Dynamic()
3109
3104
  ], CrudFieldComponent);
3110
- 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: [{
3111
3106
  type: Component,
3112
3107
  args: [{ standalone: true, imports: [
3113
3108
  ReactiveFormsModule,
@@ -3121,9 +3116,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
3121
3116
  IonSelectOption,
3122
3117
  IonLabel,
3123
3118
  IonText,
3124
- IonTextarea,
3125
- IonIcon
3126
- ], selector: 'ngx-decaf-crud-field', schemas: [CUSTOM_ELEMENTS_SCHEMA], host: { '[attr.id]': 'uid' }, template: "@if(operation === 'read' || operation === 'delete') {\n <ng-container #component>\n <div [class]=\"'dcf-input-item ' + operation\">\n <ion-item>\n <ion-label>\n {{ label | translate }}<br />\n @if(value) {\n <ion-text [innerHTML]=\"type === 'password' ? '********' : value\"></ion-text>\n } @else {\n <br />\n }\n </ion-label>\n </ion-item>\n </div>\n </ng-container>\n} @else {\n <ng-container [formGroup]=\"getActiveFormGroup\">\n <div #container [class]=\"'dcf-input-item ' + (operation || 'create')\" (createGroupEvent)=\"multiple ? handleFieldsetCreateGroupEvent($event) : ''\">\n @if(type === 'textarea') {\n <ion-textarea\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [autoGrow]=\"true\"\n [required]=\"required !== undefined ? required : null\"\n [minlength]=\"minlength !== undefined ? minlength : null\"\n [maxlength]=\"maxlength !== undefined ? maxlength : null\"\n [readonly]=\"readonly !== undefined ? readonly : null\"\n [inputmode]=\"inputmode\"\n [spellcheck]=\"spellcheck\"\n [rows]=\"rows\"\n [labelPlacement]=\"labelPlacement\"\n [value]=\"value\"\n [fill]=\"fill\"\n [errorText]=\"getErrors(container)\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [label]=\"label | translate\"\n #component>\n </ion-textarea>\n }\n @else if(type === 'checkbox') {\n <ion-item>\n <ion-checkbox\n #checkboxElement\n [mode]=\"mode\"\n [errorText]=\"getErrors(container)\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"justify\"\n [value]=\"value\"\n [checked]=\"checked\"\n [readonly]=\"readonly\"\n (ionChange)=\"checked = !checked\"\n [formControlName]=\"name\"\n #component>\n <span [innerHTML]=\"label | translate\"></span>\n </ion-checkbox>\n </ion-item>\n }\n @else if(type === 'radio') {\n <ion-radio-group [formControlName]=\"name\" [value]=\"value\" #component>\n <label class=\"dcf-radio-group-label\" [for]=\"path\">{{label | translate}}</label>\n @for(option of options; track option) {\n <ion-item>\n <ion-radio\n [errorText]=\"getErrors(container)\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [alignment]=\"alignment\"\n [justify]=\"justify\"\n [readonly]=\"readonly\"\n [value]=\"option.value\"\n >{{ translatable ? (option?.text | translate) : option?.text }}</ion-radio>\n </ion-item>\n }\n </ion-radio-group>\n }\n @else if(type === 'select') {\n <ion-select\n toggleIcon=\"chevron-down-outline\"\n expandedIcon=\"chevron-up-outline\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [label]=\"translatable ? (label | translate) : label\"\n [value]=\"value\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [errorText]=\"getErrors(container)\"\n [interface]=\"interface\" #component>\n @for(option of options; track option.value) {\n <ion-select-option [value]=\"option.value\">\n {{ option.text | translate }}\n </ion-select-option>\n }\n </ion-select>\n }\n @else {\n <ion-input\n [type]=\"type\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [inputmode]=\"inputmode\"\n [labelPlacement]=\"labelPlacement\"\n [required]=\"required !== undefined ? required : false\"\n [minlength]=\"minlength !== undefined ? minlength : null\"\n [maxlength]=\"maxlength !== undefined ? maxlength : null\"\n [readonly]=\"readonly !== undefined ? readonly : null\"\n [max]=\"max !== undefined ? max : null\"\n [min]=\"min !== undefined ? min : null\"\n [pattern]=\"pattern !== undefined ? pattern : null\"\n [step]=\"step !== undefined ? step : null\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [errorText]=\"getErrors(container)\"\n [label]=\"label | translate\" #component />\n }\n </div>\n </ng-container>\n}\n\n", styles: [".dcf-input-item.create,.dcf-input-item.update{margin-bottom:1.8rem;margin-top:0!important}.dcf-input-item.create.checkbox+.checkbox,.dcf-input-item.update.checkbox+.checkbox{margin-top:-.25rem!important}.dcf-input-item.create ion-item,.dcf-input-item.update ion-item{--border-color: transparent}.dcf-input-item.create ion-item.dcf-text-wrap ion-label>*,.dcf-input-item.update ion-item.dcf-text-wrap ion-label>*{white-space:wrap!important;word-break:break-all!important}.dcf-input-item.read ion-label,.dcf-input-item.delete ion-label{font-weight:600}@media (prefers-color-scheme: light){.dcf-input-item.read ion-label,.dcf-input-item.delete ion-label{color:var(--dcf-color-gray-7)}}.dcf-input-item.read ion-text,.dcf-input-item.delete ion-text{display:block;margin-top:.5rem!important}.dcf-input-item ion-item{--padding-end: 0rem;--padding-start: 0px !important;--padding-top: 0px !important;--background: transparent;--background-hover-opacity: .1;--background-activated-opacity: .15;--background-focused-opacity: .15}@media (prefers-color-scheme: dark){.dcf-input-item ion-item{--border-color: var(--dcf-color-gray-6)}}@media (prefers-color-scheme: light){.dcf-input-item ion-item{--background-hover: var(--dcf-color-primary);--background-focused: var(--dcf-color-primary);--border-color: var(--dcf-color-gray-2)}}.dcf-input-item ion-item span,.dcf-input-item ion-item ion-text{font-weight:400!important;font-size:.925rem;min-height:.5rem!important}.dcf-input-item ion-item span:not(.dcf-display-block),.dcf-input-item ion-item ion-text:not(.dcf-display-block){display:inline-block}.dcf-input-item ion-item span.dcf-display-block,.dcf-input-item ion-item ion-text.dcf-display-block{display:block!important}ion-textarea textarea{scrollbar-width:thin!important;margin-bottom:.5rem!important}ion-select.dcf-select-label-placement-floating::part(label){line-height:1.2rem!important}.dcf-proccessing,.dcf-proccessing *{pointer-events:none;touch-action:none;cursor:text}ion-checkbox{--size: 1.5rem;--checkbox-background-checked: var(--dcf-color-primary);--checkmark-width: 2px}ion-item{--inner-padding-start: .75rem}ion-checkbox::part(container){border-radius:50%;padding:3px}@media (prefers-color-scheme: light){ion-checkbox::part(container){border:2px solid var(--dcf-color-primary)}}ion-item .dcf-radio-group-label,ion-radio-group .dcf-radio-group-label{font-weight:600}ion-item .dcf-radio-group-label~ion-item,ion-radio-group .dcf-radio-group-label~ion-item{margin-top:.5rem;--inner-padding-start: .75rem}ion-item+.dcf-helper,ion-radio-group+.dcf-helper{padding-left:.75rem;position:relative}.dcf-error{position:absolute;color:var(--dcf-color-danger)!important;font-size:.8rem!important;font-weight:600!important;line-height:1.1rem;box-sizing:border-box;z-index:9999;margin-top:0;animation-duration:.1s;animation-timing-function:ease-out;animation-fill-mode:both;animation-name:fadeTopSmallAnimation;display:flex;align-items:flex-start;gap:.25rem}.dcf-error .ti,.dcf-error ion-icon{position:relative;top:2px!important;min-width:20px;font-size:1rem!important;text-align:left}.dcf-helper{font-size:.875rem!important;font-weight:500;margin-top:.25rem;margin-bottom:-.75rem}.dcf-helper.dcf-has-action{cursor:pointer;color:var(--dcf-color-gray-7)!important;text-decoration:underline}.dcf-error+.dcf-helper{padding-top:1rem}@keyframes fadeTopSmallAnimation{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeBottomSmallAnimation{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeTopMediumAnimation{0%{opacity:0;transform:translateY(-50px)}to{opacity:1;transform:translateY(0)}}::ng-deep ion-textarea{min-height:80px!important;scrollbar-color:#888 #f0f0f0;scrollbar-width:thin}\n"] }]
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"] }]
3127
3121
  }], propDecorators: { operation: [{
3128
3122
  type: Input,
3129
3123
  args: [{ required: true }]
@@ -3743,10 +3737,10 @@ class NgxBaseComponent {
3743
3737
  if (!this.initialized)
3744
3738
  this.initialized = true;
3745
3739
  }
3746
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NgxBaseComponent, deps: [{ token: 'instanceToken' }], target: i0.ɵɵFactoryTarget.Component }); }
3747
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: NgxBaseComponent, isStandalone: true, selector: "ng-component", inputs: { rendererId: "rendererId", model: "model", props: "props", item: "item", pk: "pk", route: "route", operations: "operations", uid: "uid", mapper: "mapper", locale: "locale", translatable: "translatable", className: "className", mode: "mode", renderChild: "renderChild" }, outputs: { listenEvent: "listenEvent" }, host: { properties: { "attr.id": "uid" } }, viewQueries: [{ propertyName: "component", first: true, predicate: ["component"], descendants: true, read: ElementRef, static: true }], usesOnChanges: true, ngImport: i0, template: '<div></div>', isInline: true }); }
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 }); }
3748
3742
  }
3749
- 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: [{
3750
3744
  type: Component,
3751
3745
  args: [{
3752
3746
  standalone: true,
@@ -4015,13 +4009,13 @@ let CrudFormComponent = class CrudFormComponent {
4015
4009
  name: EventConstants.SUBMIT,
4016
4010
  });
4017
4011
  }
4018
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CrudFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4019
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: CrudFormComponent, isStandalone: true, selector: "ngx-decaf-crud-form", inputs: { model: "model", modelId: "modelId", updateOn: "updateOn", target: "target", method: "method", options: "options", action: "action", operation: "operation", handlers: "handlers", formGroup: "formGroup", childOf: "childOf", rendererId: "rendererId", uid: "uid", allowClear: "allowClear" }, outputs: { submitEvent: "submitEvent" }, host: { properties: { "attr.id": "uid" } }, viewQueries: [{ propertyName: "component", first: true, predicate: ["reactiveForm"], descendants: true, read: ElementRef }], ngImport: i0, template: "@if(operation !== 'read' && operation !== 'delete') {\n <form #reactiveForm [id]=\"rendererId\" [formGroup]=\"formGroup\" (submit)=\"submit($event)\" novalidate [target]=\"target\">\n <ng-content #formContent></ng-content>\n <div class=\"dcf-buttons-container dcf-grid dcf-grid-collapse dcf-flex dcf-flex-left\">\n <div>\n <ion-button type=\"submit\" [expand]=\"action ? 'block' : 'default'\">\n @if(options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{ action ? action : options.buttons.submit.text}}\n </ion-button>\n </div>\n @if(!action) {\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if(options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n Back\n </ion-button>\n </div>\n }\n </div>\n </form>\n} @else {\n <div [class]=\"'dcf-buttons-container dcf-grid dcf-grid-collapse dcf-flex dcf-flex-left ' + operation\" [id]=\"uid\">\n @if(operation === OperationKeys.READ && modelId) {\n <div>\n <ion-button\n (click)=\"handleDelete()\"\n color=\"danger\"\n type=\"button\">\n @if(options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n Delete\n </ion-button>\n </div>\n\n }\n @if(operation === OperationKeys.CREATE || operation === OperationKeys.UPDATE) {\n\n <div>\n <ion-button\n type=\"submit\">\n @if(options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{options.buttons.submit.text}}\n </ion-button>\n </div>\n }\n\n @if(options.buttons.clear) {\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if(options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n {{ [OperationKeys.DELETE, OperationKeys.READ, OperationKeys.UPDATE].includes(operation) ? 'Back' : options.buttons.clear?.text}}\n </ion-button>\n </div>\n\n }\n </div>\n}\n\n", styles: [".dcf-buttons-container{margin-top:1.8rem;margin-bottom:0}@media (min-width: 768px){.dcf-buttons-container.dcf-flex{flex-direction:row-reverse}}@media (max-width: 767px){.dcf-buttons-container.dcf-flex div{width:100%}.dcf-buttons-container.dcf-flex ion-button{width:100%;margin-bottom:1rem}}form{padding:2rem 1rem}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }] }); }
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"] }] }); }
4020
4014
  };
4021
4015
  CrudFormComponent = __decorate([
4022
4016
  Dynamic()
4023
4017
  ], CrudFormComponent);
4024
- 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: [{
4025
4019
  type: Component,
4026
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"] }]
4027
4021
  }], propDecorators: { model: [{
@@ -4347,17 +4341,16 @@ let EmptyStateComponent = class EmptyStateComponent extends NgxBaseComponent {
4347
4341
  const result = await this.translate.instant(content, { 'value0': this.searchValue });
4348
4342
  return this.sanitizer.bypassSecurityTrustHtml(result);
4349
4343
  }
4350
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: EmptyStateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4351
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: EmptyStateComponent, isStandalone: true, selector: "ngx-decaf-empty-state", inputs: { title: "title", titleColor: "titleColor", subtitle: "subtitle", subtitleColor: "subtitleColor", showIcon: "showIcon", icon: "icon", iconSize: "iconSize", iconColor: "iconColor", buttonLink: "buttonLink", buttonText: "buttonText", buttonFill: "buttonFill", buttonColor: "buttonColor", buttonSize: "buttonSize", searchValue: "searchValue" }, usesInheritance: true, ngImport: i0, template: "\n<ion-card [id]=\"uid\" [class]=\"className\">\n <ion-card-content>\n @if(icon && showIcon) {\n <div class=\"dcf-icon-container\">\n <ion-icon\n name=\"alert-circle-outline\"\n size=\"large\"\n color=\"danger\"\n />\n </div>\n }\n @if(title) {\n <h5 [class]=\"titleColor\" [innerHTML]=\"title\"></h5>\n }\n @if(subtitle) {\n @if(!searchValue) {\n <p [class]=\"subtitleColor\" [innerHTML]=\"subtitle\"></p>\n } @else {\n <p [class]=\"subtitleColor\" [innerHTML]=\"searchSubtitle\"></p>\n }\n }\n @if(buttonLink && buttonText) {\n <div>\n <ion-button\n [size]=\"buttonSize\"\n [fill]=\"buttonFill\"\n [color]=\"buttonColor\"\n (click)=\"handleClick()\">\n {{ buttonText }}\n </ion-button>\n </div>\n }\n </ion-card-content>\n</ion-card>\n", styles: ["ion-card{text-align:center}ion-card ion-button{margin-top:.75rem}ion-card ion-icon{font-size:2.5rem}ion-card .dcf-icon-container{transform:scale(1.25);opacity:.75;margin-top:1.25rem!important;margin-bottom:.5rem!important}ion-card .dcf-ititle{font-weight:600!important;color:var(--dcf-color-gray-6)!important}ion-card .dcf-isubtitle{font-weight:500!important}\n"], dependencies: [{ kind: "component", type: IonCard, selector: "ion-card", inputs: ["button", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonCardContent, selector: "ion-card-content", inputs: ["mode"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }] }); }
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"] }] }); }
4352
4346
  };
4353
4347
  EmptyStateComponent = __decorate([
4354
4348
  Dynamic(),
4355
4349
  __metadata("design:paramtypes", [])
4356
4350
  ], EmptyStateComponent);
4357
- 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: [{
4358
4352
  type: Component,
4359
4353
  args: [{ selector: 'ngx-decaf-empty-state', standalone: true, imports: [
4360
- TranslatePipe,
4361
4354
  IonCard,
4362
4355
  IonCardContent,
4363
4356
  IonIcon
@@ -5001,14 +4994,14 @@ let FieldsetComponent = class FieldsetComponent extends NgxBaseComponent {
5001
4994
  }
5002
4995
  return this.mapper;
5003
4996
  }
5004
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FieldsetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
5005
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: FieldsetComponent, isStandalone: true, selector: "ngx-decaf-fieldset", inputs: { name: "name", childOf: "childOf", page: "page", uid: "uid", customTypes: "customTypes", operation: "operation", formGroup: "formGroup", title: "title", description: "description", target: "target", multiple: "multiple", value: "value", handlers: "handlers" }, host: { properties: { "attr.id": "overriode " } }, viewQueries: [{ propertyName: "accordionComponent", first: true, predicate: ["accordionComponent"], descendants: true }], usesInheritance: true, ngImport: i0, template: "\n\n<fieldset\n (fieldsetAddGroupEvent)=\"handleCreateItem($event)\"\n (fieldsetRemoveGroupEvent)=\"handleRemoveItem(undefined, $event)\"\n [class]=\"'dcf-fieldset ' + operation\"\n #component>\n <ion-accordion-group [class.open]=\"isOpen\" [class.hasValidationErrors]=\"hasValidationErrors\" (validationErrorEvent)=\"handleValidationError($event)\" #accordionComponent>\n <ion-accordion value=\"open\">\n <ion-item slot=\"header\" (click)=\"handleAccordionToggle($event)\">\n <div class=\"dcf-grid dcf-grid-collapse dcf-flex dcf-flex-middle dcf-width-1-1\">\n <div class=\"dcf-width-expand\">\n <legend>{{ name | translate }}</legend>\n </div>\n @if(!isRequired && ['create', 'update'].includes(operation)) {\n <div class=\"dcf-width-auto dcf-delete\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleRemoveComponent($event)\">\n <ion-icon name=\"trash-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n }\n </div>\n </ion-item>\n <div slot=\"content\" [attr.aria-hidden]=\"!isOpen\">\n @if(multiple && items.length) {\n <ion-list class=\"dcf-fields-list\">\n <ion-reorder-group [formGroup]=\"formGroup.parent\" [disabled]=\"updatingItem\" (ionItemReorder)=\"handleReorderItems($any($event))\" #accordionComponent>\n @for(item of items; track item.index) {\n <ion-item [class.not-unique]=\"item.title === isUniqueError\" [class.updating]=\"updatingItem?.[pk] === item.title\" lines=\"full\" [button]=\"false\">\n @if(items?.length > 1 && !updatingItem) {\n <ion-reorder slot=\"start\">\n <ion-icon name=\"swap-vertical-outline\"></ion-icon>\n </ion-reorder>\n } @else {\n <div slot=\"start\">\n <ion-icon class=\"dcf-reorder-disabled\" size=\"small\" name=\"swap-vertical-outline\" disabled></ion-icon>\n </div>\n }\n <ion-label [color]=\"(item.title === isUniqueError && !updatingItem?.[pk] === item.title) ? 'danger' : ''\">{{ item.index }}. {{ item.title }}\n @if(item.description?.length > 0) {\n <br />\n <ion-text class=\"dcf-subtitle\">{{item.description}}</ion-text>\n }\n </ion-label>\n @if(!updatingItem || updatingItem?.[pk] !== item.title) {\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleUpdateItem(item.title, $index)\">\n <ion-icon name=\"create-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n }\n\n @if(!updatingItem) {\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleRemoveItem(item.title)\">\n <ion-icon name=\"trash-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n }\n </ion-item>\n }\n </ion-reorder-group>\n </ion-list>\n }\n\n <ng-content select=\"[slot=content]\"></ng-content>\n\n @if(multiple && ['create', 'update'].includes(operation)) {\n @if(isUniqueError) {\n <div class=\"dcf-not-unique-container dcf-animation dcf-animation-bottom-small dcf-animation-fast\">\n <div class=\" dcf-grid dcf-grid-collapse dcf-width-1-1 \">\n <div class=\"dcf-auto\" [attr.style]=\"'max-width: 50px'\">\n <ion-icon name=\"alert-circle-outline\"></ion-icon>\n </div>\n <div class=\"dcf-width-expand\">\n <ion-text color=\"danger\" class=\"dcf-text-small\">{{ locale + '.not_unique' | translate : { value: isUniqueError } }}</ion-text>\n </div>\n </div>\n </div>\n }\n <div class=\"dcf-margin-bottom dcf-grid dcf-grid-collapse dcf-flex\">\n @if(updatingItem) {\n <ion-button size=\"small\" fill=\"clear\" color=\"danger\" (click)=\"handleCancelUpdateItem()\">\n {{ buttonCancelLabel }}\n </ion-button>\n }\n <ion-button size=\"small\" fill=\"clear\" class=\"dcf-button-add\" (click)=\"handleCreateItem()\">\n <ion-icon name=\"add-outline\" slot=\"start\"></ion-icon>\n {{buttonLabel}}\n </ion-button>\n\n </div>\n }\n\n </div>\n </ion-accordion>\n </ion-accordion-group>\n</fieldset>\n\n", styles: ["ion-accordion-group ion-item[slot=header] .dcf-delete{width:30px}ion-accordion-group ion-item[slot=header] .dcf-delete ion-button{transform:translateY(-2px)}ion-accordion-group ion-item[slot=header] .dcf-delete ion-icon{font-size:1.15rem}::ng-deep ion-accordion ngx-decaf-crud-field:last-child ion-item{--inner-border-width: 0px !important;--border-width: 0px !important}.dcf-fieldset{margin-bottom:1.8rem;margin-top:1rem;padding-bottom:0;padding-top:1rem;background:var(--dcf-card-background);border-radius:6px;height:100%}@media (prefers-color-scheme: light){.dcf-fieldset{border:1px solid var(--dcf-color-gray-3)}.dcf-fieldset .dcf-button-add{color:var(--ion-color-dark)!important}}@media (prefers-color-scheme: dark){.dcf-fieldset{border:1px solid var(--dcf-color-step-400)}.dcf-fieldset .dcf-button-add{color:var(--ion-color-gray-2)}}.dcf-fieldset.read,.dcf-fieldset.delete{margin-top:1.25rem;padding-bottom:1rem}.dcf-fieldset.read [slot=content],.dcf-fieldset.delete [slot=content]{padding-top:0!important}.dcf-fieldset.read ion-accordion,.dcf-fieldset.delete ion-accordion{margin-bottom:0rem!important}@media (prefers-color-scheme: dark){.dcf-fieldset.read,.dcf-fieldset.delete{border:1px solid var(--dcf-color-gray-6)}}.dcf-fieldset ion-accordion{background:var(--dcf-card-background);margin-bottom:1rem}.dcf-fieldset ion-accordion.accordion-collapsing,.dcf-fieldset ion-accordion.accordion-collapsed{margin-bottom:1rem}.dcf-fieldset ion-accordion ion-item[slot=header]{--border-color: transparent;--border-radius: 6px;--inner-border-width: 0;--padding-start: 12px}.dcf-fieldset ion-accordion ion-item[slot=header] legend{font-weight:600;font-size:1rem;margin:0}@media (prefers-color-scheme: light){.dcf-fieldset ion-accordion ion-item[slot=header] legend{color:var(--dcf-color-gray-7)}}.dcf-fieldset ion-accordion [slot=content]{padding-top:2rem!important;padding-inline:.75rem}.dcf-not-unique-container{display:flex;justify-content:center;align-items:center;margin-bottom:1rem;flex:1 1 auto}.dcf-not-unique-container>div{display:flex;justify-content:center;align-items:center}.dcf-not-unique-container ion-icon{transform:translatey(2px);margin-right:5px}.dcf-fields-list{margin-top:-1rem;margin-bottom:1rem;padding:0!important}.dcf-fields-list ion-item{--min-height: 50px;--padding-top: .25rem;--padding-bottom: .25rem;--padding-start: .75rem;--padding-end: .75rem;--inner-padding-start: 0px !important;--inner-padding-end: 0px !important;--border-color: var(--dcf-color-gray-2) !important;border:1px solid transparent;box-sizing:border-box}.dcf-fields-list ion-item ion-icon.dcf-reorder-disabled{width:1rem;transform:translatey(2px);color:var(--dcf-color-gray-4)}.dcf-fields-list ion-item.updating{--background: rgba(var(--dcf-color-primary-rgb), .1) !important}.dcf-fields-list ion-item.not-unique{--background: rgba(var(--dcf-color-danger-rgb), .05) !important}.dcf-fields-list ion-item .dcf-subtitle{font-size:.8rem;color:var(--dcf-color-gray-7)}\n"], dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: IonAccordionGroup, selector: "ion-accordion-group", inputs: ["animated", "disabled", "expand", "mode", "multiple", "readonly", "value"] }, { kind: "component", type: IonAccordion, selector: "ion-accordion", inputs: ["disabled", "mode", "readonly", "toggleIcon", "toggleIconSlot", "value"] }, { kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonReorder, selector: "ion-reorder" }, { kind: "component", type: IonReorderGroup, selector: "ion-reorder-group", inputs: ["disabled"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }] }); }
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" }] }); }
5006
4999
  };
5007
5000
  FieldsetComponent = __decorate([
5008
5001
  Dynamic(),
5009
5002
  __metadata("design:paramtypes", [])
5010
5003
  ], FieldsetComponent);
5011
- 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: [{
5012
5005
  type: Component,
5013
5006
  args: [{ standalone: true, selector: 'ngx-decaf-fieldset', schemas: [], imports: [
5014
5007
  TranslatePipe,
@@ -5023,7 +5016,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
5023
5016
  IonReorderGroup,
5024
5017
  IonButton,
5025
5018
  IonIcon,
5026
- ], host: { '[attr.id]': 'overriode ' }, template: "\n\n<fieldset\n (fieldsetAddGroupEvent)=\"handleCreateItem($event)\"\n (fieldsetRemoveGroupEvent)=\"handleRemoveItem(undefined, $event)\"\n [class]=\"'dcf-fieldset ' + operation\"\n #component>\n <ion-accordion-group [class.open]=\"isOpen\" [class.hasValidationErrors]=\"hasValidationErrors\" (validationErrorEvent)=\"handleValidationError($event)\" #accordionComponent>\n <ion-accordion value=\"open\">\n <ion-item slot=\"header\" (click)=\"handleAccordionToggle($event)\">\n <div class=\"dcf-grid dcf-grid-collapse dcf-flex dcf-flex-middle dcf-width-1-1\">\n <div class=\"dcf-width-expand\">\n <legend>{{ name | translate }}</legend>\n </div>\n @if(!isRequired && ['create', 'update'].includes(operation)) {\n <div class=\"dcf-width-auto dcf-delete\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleRemoveComponent($event)\">\n <ion-icon name=\"trash-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n }\n </div>\n </ion-item>\n <div slot=\"content\" [attr.aria-hidden]=\"!isOpen\">\n @if(multiple && items.length) {\n <ion-list class=\"dcf-fields-list\">\n <ion-reorder-group [formGroup]=\"formGroup.parent\" [disabled]=\"updatingItem\" (ionItemReorder)=\"handleReorderItems($any($event))\" #accordionComponent>\n @for(item of items; track item.index) {\n <ion-item [class.not-unique]=\"item.title === isUniqueError\" [class.updating]=\"updatingItem?.[pk] === item.title\" lines=\"full\" [button]=\"false\">\n @if(items?.length > 1 && !updatingItem) {\n <ion-reorder slot=\"start\">\n <ion-icon name=\"swap-vertical-outline\"></ion-icon>\n </ion-reorder>\n } @else {\n <div slot=\"start\">\n <ion-icon class=\"dcf-reorder-disabled\" size=\"small\" name=\"swap-vertical-outline\" disabled></ion-icon>\n </div>\n }\n <ion-label [color]=\"(item.title === isUniqueError && !updatingItem?.[pk] === item.title) ? 'danger' : ''\">{{ item.index }}. {{ item.title }}\n @if(item.description?.length > 0) {\n <br />\n <ion-text class=\"dcf-subtitle\">{{item.description}}</ion-text>\n }\n </ion-label>\n @if(!updatingItem || updatingItem?.[pk] !== item.title) {\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleUpdateItem(item.title, $index)\">\n <ion-icon name=\"create-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n }\n\n @if(!updatingItem) {\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleRemoveItem(item.title)\">\n <ion-icon name=\"trash-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n }\n </ion-item>\n }\n </ion-reorder-group>\n </ion-list>\n }\n\n <ng-content select=\"[slot=content]\"></ng-content>\n\n @if(multiple && ['create', 'update'].includes(operation)) {\n @if(isUniqueError) {\n <div class=\"dcf-not-unique-container dcf-animation dcf-animation-bottom-small dcf-animation-fast\">\n <div class=\" dcf-grid dcf-grid-collapse dcf-width-1-1 \">\n <div class=\"dcf-auto\" [attr.style]=\"'max-width: 50px'\">\n <ion-icon name=\"alert-circle-outline\"></ion-icon>\n </div>\n <div class=\"dcf-width-expand\">\n <ion-text color=\"danger\" class=\"dcf-text-small\">{{ locale + '.not_unique' | translate : { value: isUniqueError } }}</ion-text>\n </div>\n </div>\n </div>\n }\n <div class=\"dcf-margin-bottom dcf-grid dcf-grid-collapse dcf-flex\">\n @if(updatingItem) {\n <ion-button size=\"small\" fill=\"clear\" color=\"danger\" (click)=\"handleCancelUpdateItem()\">\n {{ buttonCancelLabel }}\n </ion-button>\n }\n <ion-button size=\"small\" fill=\"clear\" class=\"dcf-button-add\" (click)=\"handleCreateItem()\">\n <ion-icon name=\"add-outline\" slot=\"start\"></ion-icon>\n {{buttonLabel}}\n </ion-button>\n\n </div>\n }\n\n </div>\n </ion-accordion>\n </ion-accordion-group>\n</fieldset>\n\n", styles: ["ion-accordion-group ion-item[slot=header] .dcf-delete{width:30px}ion-accordion-group ion-item[slot=header] .dcf-delete ion-button{transform:translateY(-2px)}ion-accordion-group ion-item[slot=header] .dcf-delete ion-icon{font-size:1.15rem}::ng-deep ion-accordion ngx-decaf-crud-field:last-child ion-item{--inner-border-width: 0px !important;--border-width: 0px !important}.dcf-fieldset{margin-bottom:1.8rem;margin-top:1rem;padding-bottom:0;padding-top:1rem;background:var(--dcf-card-background);border-radius:6px;height:100%}@media (prefers-color-scheme: light){.dcf-fieldset{border:1px solid var(--dcf-color-gray-3)}.dcf-fieldset .dcf-button-add{color:var(--ion-color-dark)!important}}@media (prefers-color-scheme: dark){.dcf-fieldset{border:1px solid var(--dcf-color-step-400)}.dcf-fieldset .dcf-button-add{color:var(--ion-color-gray-2)}}.dcf-fieldset.read,.dcf-fieldset.delete{margin-top:1.25rem;padding-bottom:1rem}.dcf-fieldset.read [slot=content],.dcf-fieldset.delete [slot=content]{padding-top:0!important}.dcf-fieldset.read ion-accordion,.dcf-fieldset.delete ion-accordion{margin-bottom:0rem!important}@media (prefers-color-scheme: dark){.dcf-fieldset.read,.dcf-fieldset.delete{border:1px solid var(--dcf-color-gray-6)}}.dcf-fieldset ion-accordion{background:var(--dcf-card-background);margin-bottom:1rem}.dcf-fieldset ion-accordion.accordion-collapsing,.dcf-fieldset ion-accordion.accordion-collapsed{margin-bottom:1rem}.dcf-fieldset ion-accordion ion-item[slot=header]{--border-color: transparent;--border-radius: 6px;--inner-border-width: 0;--padding-start: 12px}.dcf-fieldset ion-accordion ion-item[slot=header] legend{font-weight:600;font-size:1rem;margin:0}@media (prefers-color-scheme: light){.dcf-fieldset ion-accordion ion-item[slot=header] legend{color:var(--dcf-color-gray-7)}}.dcf-fieldset ion-accordion [slot=content]{padding-top:2rem!important;padding-inline:.75rem}.dcf-not-unique-container{display:flex;justify-content:center;align-items:center;margin-bottom:1rem;flex:1 1 auto}.dcf-not-unique-container>div{display:flex;justify-content:center;align-items:center}.dcf-not-unique-container ion-icon{transform:translatey(2px);margin-right:5px}.dcf-fields-list{margin-top:-1rem;margin-bottom:1rem;padding:0!important}.dcf-fields-list ion-item{--min-height: 50px;--padding-top: .25rem;--padding-bottom: .25rem;--padding-start: .75rem;--padding-end: .75rem;--inner-padding-start: 0px !important;--inner-padding-end: 0px !important;--border-color: var(--dcf-color-gray-2) !important;border:1px solid transparent;box-sizing:border-box}.dcf-fields-list ion-item ion-icon.dcf-reorder-disabled{width:1rem;transform:translatey(2px);color:var(--dcf-color-gray-4)}.dcf-fields-list ion-item.updating{--background: rgba(var(--dcf-color-primary-rgb), .1) !important}.dcf-fields-list ion-item.not-unique{--background: rgba(var(--dcf-color-danger-rgb), .05) !important}.dcf-fields-list ion-item .dcf-subtitle{font-size:.8rem;color:var(--dcf-color-gray-7)}\n"] }]
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"] }]
5027
5020
  }], ctorParameters: () => [], propDecorators: { accordionComponent: [{
5028
5021
  type: ViewChild,
5029
5022
  args: ['accordionComponent', { static: false }]
@@ -5481,10 +5474,10 @@ class SearchbarComponent extends NgxBaseComponent {
5481
5474
  preventChange(event) {
5482
5475
  event.preventDefault();
5483
5476
  }
5484
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SearchbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
5485
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: SearchbarComponent, isStandalone: true, selector: "ngx-decaf-searchbar", inputs: { autocomplete: "autocomplete", autocorrect: "autocorrect", animated: "animated", buttonCancelText: "buttonCancelText", clearIcon: "clearIcon", color: "color", debounce: "debounce", disabled: "disabled", enterkeyhint: "enterkeyhint", inputmode: "inputmode", placeholder: "placeholder", searchIcon: "searchIcon", showCancelButton: "showCancelButton", showClearButton: "showClearButton", spellcheck: "spellcheck", type: "type", value: "value", queryKeys: "queryKeys", isVisible: "isVisible", wrapper: "wrapper", wrapperColor: "wrapperColor", emitEventToWindow: "emitEventToWindow" }, outputs: { searchEvent: "searchEvent" }, host: { listeners: { "window:toggleSearchbarVisibility": "handleToggleVisibility($event)" } }, usesInheritance: true, ngImport: i0, template: "<ion-searchbar\n [id]=\"uid\"\n ngClass=\"dcf-searchbar\"\n name=\"search\"\n mode=\"ios\"\n (keyup.enter)=\"preventChange($event)\"\n (ionChange)=\"handleChange($event)\"\n (ionInput)=\"handleInput($event)\"\n (ionClear)=\"handleClear()\"\n [autocomplete]=\"autocomplete\"\n [showCancelButton]=\"showCancelButton\"\n [cancelButtonText]=\"buttonCancelText\"\n [clearIcon]=\"clearIcon\"\n [color]=\"color\"\n [debounce]=\"debounce\"\n [disabled]=\"disabled\"\n [enterkeyhint]=\"enterkeyhint\"\n [inputmode]=\"inputmode\"\n [placeholder]=\"placeholder\"\n [searchIcon]=\"searchIcon\"\n [showClearButton]=\"showClearButton\"\n [spellcheck]=\"spellcheck\"\n [type]=\"type\"\n #component\n />\n", styles: [""], dependencies: [{ kind: "component", type: IonSearchbar, selector: "ion-searchbar", inputs: ["animated", "autocomplete", "autocorrect", "cancelButtonIcon", "cancelButtonText", "clearIcon", "color", "debounce", "disabled", "enterkeyhint", "inputmode", "mode", "name", "placeholder", "searchIcon", "showCancelButton", "showClearButton", "spellcheck", "type", "value"] }] }); }
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"] }] }); }
5486
5479
  }
5487
- 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: [{
5488
5481
  type: Component,
5489
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" }]
5490
5483
  }], ctorParameters: () => [], propDecorators: { autocomplete: [{
@@ -6183,20 +6176,18 @@ let FilterComponent = class FilterComponent extends NgxBaseComponent {
6183
6176
  handleSearch(value) {
6184
6177
  this.searchEvent.emit(value);
6185
6178
  }
6186
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FilterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6187
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: FilterComponent, isStandalone: true, selector: "ngx-decaf-filter", inputs: { indexes: "indexes", conditions: "conditions", sortBy: "sortBy", disableSort: "disableSort" }, outputs: { filterEvent: "filterEvent", searchEvent: "searchEvent" }, viewQueries: [{ propertyName: "optionsFilterElement", first: true, predicate: ["optionsFilterElement"], descendants: true, read: ElementRef }], usesInheritance: true, ngImport: i0, template: "\n@if(!indexes.length) {\n <ngx-decaf-searchbar [emitEventToWindow]=\"false\" [debounce]=\"500\" (searchEvent)=\"handleSearch($event)\" />\n}\n\n<div [id]=\"uid\" class=\"dcf-grid dcf-grid-small dcf-grid-match dcf-filter-grid\" [class.dcf-hidden]=\"!indexes.length\">\n <div class=\"dcf-width-expand\">\n <div class=\"dcf-filter\">\n <div class=\"dcf-input\">\n @for(filter of filterValue; track trackItemFn($index, filter?.['index'])) {\n @if(filter?.['index']) {\n <ion-chip [outline]=\"true\">{{ filter?.['index'] }}</ion-chip>\n }\n @if(filter?.['condition']) {\n <ion-chip [outline]=\"true\">{{ filter?.['condition'] }}</ion-chip>\n }\n @if(filter?.['value']) {\n <ion-chip [outline]=\"true\" class=\"dcf-filter-value\">\n {{ filter?.['value'] }}\n <ion-icon name=\"close\" (click)=\"removeFilter(filter?.['value'])\" size=\"small\"></ion-icon>\n </ion-chip>\n }\n }\n <div class=\"dcf-width-1-1\">\n <!-- [readonly]=\"step !== 3\" -->\n <input\n fill=\"none\"\n [(ngModel)]=\"value\"\n (keydown.enter)=\"addFilter(value, $event)\"\n (keydown.backspace)=\"clear(value)\"\n (input)=\"handleInput($event)\"\n (click)=\"handleFocus()\"\n (blur)=\"handleBlur()\"\n type=\"text\"\n\n placeholder=\"{{ locale + (step === 3 ? '.type' : '.select') | translate }}\"\n #component\n />\n @if(windowWidth >= 768) {\n <div [class]=\"'dcf-dropdown ' + (options.length > 0 ? ' dcf-active' : '')\" #optionsFilterElement>\n <div>\n @if(filteredOptions.length > 0) {\n @for(key of filteredOptions; track key) {\n <div\n class=\"dcf-item\"\n tabindex=\"0\"\n (keydown.enter)=\"selectOption(key)\"\n (click)=\"selectOption(key)\">\n {{ key }}\n </div>\n }\n } @else {\n <div class=\"dcf-empty\"\n (click)=\"filteredOptions = options; value = ''\"\n tabindex=\"0\"\n (keydown.enter)=\"filteredOptions = options; value = ''\"\n >\n {{ locale + '.no_suggestions' | translate }}\n </div>\n }\n </div>\n </div>\n }\n </div>\n </div>\n @if(filterValue.length > 0) {\n <div class=\"dcf-icon-clear\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"clear()\">\n <ion-icon name=\"trash-outline\" [color]=\"!isDarkMode ? 'dark' : 'medium'\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n }\n <div class=\"dcf-icon-search\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"submit()\">\n <ion-icon name=\"search-outline\" [color]=\"!isDarkMode ? 'dark' : 'medium'\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n </div>\n @if(windowWidth < 768) {\n <div [class]=\"'dcf-dropdown ' + (options.length > 0 ? ' dcf-active' : '')\" #optionsFilterElement>\n <div>\n @if(filteredOptions.length > 0) {\n @for(key of filteredOptions; track key) {\n <div\n class=\"dcf-item\"\n tabindex=\"0\"\n (keydown.enter)=\"selectOption(key)\"\n (click)=\"selectOption(key)\">\n {{ key }}\n </div>\n }\n } @else {\n <div class=\"dcf-empty\"\n (click)=\"filteredOptions = options; value = ''\"\n tabindex=\"0\"\n (keydown.enter)=\"filteredOptions = options; value = ''\"\n >\n {{ locale + '.no_suggestions' | translate }}\n </div>\n }\n </div>\n </div>\n }\n </div>\n @if(!disableSort) {\n <div class=\"dcf-width-1-5@m dcf-width-1-1 dcf-sort-container\">\n <div class=\"dcf-grid dcf-grid-collapse dcf-flex dcf-flex-middle dcf-grid-match\">\n <div class=\"dcf-width-expand\">\n <ion-select\n toggleIcon=\"chevron-down-outline\"\n expandedIcon=\"chevron-up-outline\"\n class=\"dcf-sort-select\"\n (ionChange)=\"handleSortChange($event)\"\n interface=\"popover\"\n [value]=\"sortValue\"\n label-placement=\"floating\"\n fill=\"outline\"\n [label]=\"locale + '.sort' | translate\"\n >\n @for(sort of sortBy; track sort) {\n\n <ion-select-option [value]=\"sort\">{{ sort | translate }}</ion-select-option>\n }\n </ion-select>\n </div>\n <div class=\"dcf-width-auto\">\n <ion-button (click)=\"handleSortDirectionChange()\" fill=\"clear\">\n <ion-icon slot=\"icon-only\" [color]=\"!isDarkMode ? 'primary' : 'medium'\" [name]=\"sortDirection === 'desc' ? 'arrow-down-outline' : 'arrow-up-outline'\"></ion-icon>\n </ion-button>\n </div>\n </div>\n </div>\n }\n</div>\n\n\n", styles: [".dcf-filter-grid{padding:0 .5rem;margin-top:.75rem;margin-bottom:.75rem}ion-select{min-height:44px!important}.dcf-hidden{display:none!important}.dcf-filter{display:flex;width:100%;min-height:40px;box-shadow:0 1px 2px #0a0d120d;border-radius:var(--dcf-border-radius);box-sizing:border-box}@media (prefers-color-scheme: light){.dcf-filter{border:1px solid var(--dcf-color-gray-3);background-color:#fff}.dcf-filter:focus-within{border-color:var(--dcf-color-primary);background-color:#fff}}@media (prefers-color-scheme: dark){.dcf-filter{border:1px solid var(--dcf-color-step-500)}.dcf-filter ::-webkit-input-placeholder,.dcf-filter ::placeholder{color:var(--dcf-color-gray-4)!important}.dcf-filter:hover{border-color:var(--dcf-color-gray-2)}.dcf-filter:focus-within{border-color:var(--dcf-color-gray-2)}}.dcf-filter ion-chip{border-radius:6px;padding:0 8px!important;height:24px;min-height:24px;font-size:.75rem;font-style:normal;font-weight:500;flex-shrink:0;margin-right:2px;white-space:nowrap}@media (prefers-color-scheme: light){.dcf-filter ion-chip{border:1px solid var(--dcf-color-gray-3);color:var(--dcf-color-gray-7)}.dcf-filter ion-chip.dcf-filter-value{background:var(--dcf-color-gray-2);border-color:var(--dcf-color-gray-4)!important;color:var(--dcf-color-gray-8)!important}}@media (prefers-color-scheme: dark){.dcf-filter ion-chip{border-color:var(--dcf-color-step-300);background:rgba(var(--dcf-color-medium-rgb),.1)}.dcf-filter ion-chip.dcf-filter-value{background:rgba(var(--dcf-color-medium-rgb),.3)!important;border-color:var(--dcf-color-step-500)}}.dcf-filter ion-chip.sc-ion-chip-md-h,.dcf-filter ion-chip.sc-ion-chip-ios-h{height:24px;min-height:24px}.dcf-filter ion-chip.sc-ion-chip-md-h .chip-native,.dcf-filter ion-chip.sc-ion-chip-ios-h .chip-native{padding:0 8px!important;height:24px;min-height:24px}.dcf-filter ion-chip ion-label{padding:0 4px;margin:0;font-size:.75rem;white-space:nowrap}.dcf-filter ion-chip ion-icon{margin:0 2px;font-size:.75rem}.dcf-filter .dcf-input{width:100%;display:flex;align-items:center;overflow-x:auto;overflow-y:hidden;white-space:nowrap;padding-left:.5rem}.dcf-filter .dcf-input input{min-height:40px;min-width:100px;width:100%;font-size:1rem;border:none;outline:none;background:transparent;border:0px!important;outline:none!important}@media (prefers-color-scheme: light){.dcf-filter .dcf-input input{color:var(--dcf-color-gray-7)}}@media (prefers-color-scheme: dark){.dcf-filter .dcf-input input{color:var(--dcf-color-gray-1)}}.dcf-filter .dcf-input input:focus{border:0px!important;outline:none!important}.dcf-filter .dcf-icon-clear,.dcf-filter .dcf-icon-search{display:flex;justify-content:center;text-align:center;align-items:center;min-width:40px}.dcf-filter .dcf-icon-search ion-icon{font-size:1.25rem}.dcf-sort-container{min-width:200px!important;width:auto}@media (min-width: 990px){.dcf-sort-container{max-width:20%!important}}@media (max-width: 680px){.dcf-sort-container{min-width:100%!important;margin:.75rem 0rem}}.dcf-dropdown{position:absolute;max-height:200px;overflow-y:auto;border-radius:4px;z-index:1000!important;min-width:200px;max-width:300px;display:none}@media (prefers-color-scheme: light){.dcf-dropdown{background-color:#fff}.dcf-dropdown.dcf-active{border:1px solid var(--dcf-color-gray-2)}}@media (prefers-color-scheme: dark){.dcf-dropdown{background-color:var(--dcf-item-background)}.dcf-dropdown.dcf-active{border:1px solid var(--dcf-color-step-600)}}.dcf-dropdown.dcf-active{display:block;margin-top:-3px;box-shadow:0 12px 16px -4px #0a0d1214,0 4px 6px -2px #0a0d1208,0 2px 2px -1px #0a0d120a!important;border-radius:var(--dcf-border-radius);padding:.5rem .25rem}@media (max-width: 768px){.dcf-dropdown.dcf-active{margin-top:55px}}.dcf-dropdown.dcf-active>div>div{cursor:pointer;height:35px;padding:.5rem 1rem;border:1px solid transparent;font-size:1rem;display:flex;align-items:center;border-radius:6px}@media (prefers-color-scheme: light){.dcf-dropdown.dcf-active>div>div{color:var(--dcf-color-gray-8)}.dcf-dropdown.dcf-active>div>div.dcf-filtering-item,.dcf-dropdown.dcf-active>div>div:only-child{border-color:var(--dcf-color-gray-3)}.dcf-dropdown.dcf-active>div>div.dcf-filtering-item.dcf-empty,.dcf-dropdown.dcf-active>div>div:only-child.dcf-empty{pointer-events:none;touch-action:none;cursor:text!important;border-color:transparent!important}.dcf-dropdown.dcf-active>div>div:hover{background-color:var(--dcf-color-gray-1)}}@media (prefers-color-scheme: dark){.dcf-dropdown.dcf-active>div>div{color:var(--dcf-color-gray-1)}.dcf-dropdown.dcf-active>div>div.dcf-filtering-item,.dcf-dropdown.dcf-active>div>div:only-child{border-color:var(--dcf-color-gray-5)}.dcf-dropdown.dcf-active>div>div.dcf-filtering-item.dcf-empty,.dcf-dropdown.dcf-active>div>div:only-child.dcf-empty{cursor:text!important;pointer-events:none;touch-action:none;border-color:transparent!important}.dcf-dropdown.dcf-active>div>div:hover{background-color:var(--dcf-color-gray-8)}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "component", type: IonChip, selector: "ion-chip", inputs: ["color", "disabled", "mode", "outline"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonSelect, selector: "ion-select", inputs: ["cancelText", "color", "compareWith", "disabled", "errorText", "expandedIcon", "fill", "helperText", "interface", "interfaceOptions", "justify", "label", "labelPlacement", "mode", "multiple", "name", "okText", "placeholder", "selectedText", "shape", "toggleIcon", "value"] }, { kind: "component", type: IonSelectOption, selector: "ion-select-option", inputs: ["disabled", "value"] }, { kind: "component", type: SearchbarComponent, selector: "ngx-decaf-searchbar", inputs: ["autocomplete", "autocorrect", "animated", "buttonCancelText", "clearIcon", "color", "debounce", "disabled", "enterkeyhint", "inputmode", "placeholder", "searchIcon", "showCancelButton", "showClearButton", "spellcheck", "type", "value", "queryKeys", "isVisible", "wrapper", "wrapperColor", "emitEventToWindow"], outputs: ["searchEvent"] }] }); }
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" }] }); }
6188
6181
  };
6189
6182
  FilterComponent = __decorate([
6190
6183
  Dynamic(),
6191
6184
  __metadata("design:paramtypes", [])
6192
6185
  ], FilterComponent);
6193
- 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: [{
6194
6187
  type: Component,
6195
6188
  args: [{ selector: 'ngx-decaf-filter', imports: [
6196
6189
  FormsModule,
6197
6190
  TranslatePipe,
6198
- IonLabel,
6199
- IonItem,
6200
6191
  IonChip,
6201
6192
  IonIcon,
6202
6193
  IonButton,
@@ -6204,7 +6195,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
6204
6195
  IonSelectOption,
6205
6196
  IonIcon,
6206
6197
  SearchbarComponent
6207
- ], standalone: true, template: "\n@if(!indexes.length) {\n <ngx-decaf-searchbar [emitEventToWindow]=\"false\" [debounce]=\"500\" (searchEvent)=\"handleSearch($event)\" />\n}\n\n<div [id]=\"uid\" class=\"dcf-grid dcf-grid-small dcf-grid-match dcf-filter-grid\" [class.dcf-hidden]=\"!indexes.length\">\n <div class=\"dcf-width-expand\">\n <div class=\"dcf-filter\">\n <div class=\"dcf-input\">\n @for(filter of filterValue; track trackItemFn($index, filter?.['index'])) {\n @if(filter?.['index']) {\n <ion-chip [outline]=\"true\">{{ filter?.['index'] }}</ion-chip>\n }\n @if(filter?.['condition']) {\n <ion-chip [outline]=\"true\">{{ filter?.['condition'] }}</ion-chip>\n }\n @if(filter?.['value']) {\n <ion-chip [outline]=\"true\" class=\"dcf-filter-value\">\n {{ filter?.['value'] }}\n <ion-icon name=\"close\" (click)=\"removeFilter(filter?.['value'])\" size=\"small\"></ion-icon>\n </ion-chip>\n }\n }\n <div class=\"dcf-width-1-1\">\n <!-- [readonly]=\"step !== 3\" -->\n <input\n fill=\"none\"\n [(ngModel)]=\"value\"\n (keydown.enter)=\"addFilter(value, $event)\"\n (keydown.backspace)=\"clear(value)\"\n (input)=\"handleInput($event)\"\n (click)=\"handleFocus()\"\n (blur)=\"handleBlur()\"\n type=\"text\"\n\n placeholder=\"{{ locale + (step === 3 ? '.type' : '.select') | translate }}\"\n #component\n />\n @if(windowWidth >= 768) {\n <div [class]=\"'dcf-dropdown ' + (options.length > 0 ? ' dcf-active' : '')\" #optionsFilterElement>\n <div>\n @if(filteredOptions.length > 0) {\n @for(key of filteredOptions; track key) {\n <div\n class=\"dcf-item\"\n tabindex=\"0\"\n (keydown.enter)=\"selectOption(key)\"\n (click)=\"selectOption(key)\">\n {{ key }}\n </div>\n }\n } @else {\n <div class=\"dcf-empty\"\n (click)=\"filteredOptions = options; value = ''\"\n tabindex=\"0\"\n (keydown.enter)=\"filteredOptions = options; value = ''\"\n >\n {{ locale + '.no_suggestions' | translate }}\n </div>\n }\n </div>\n </div>\n }\n </div>\n </div>\n @if(filterValue.length > 0) {\n <div class=\"dcf-icon-clear\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"clear()\">\n <ion-icon name=\"trash-outline\" [color]=\"!isDarkMode ? 'dark' : 'medium'\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n }\n <div class=\"dcf-icon-search\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"submit()\">\n <ion-icon name=\"search-outline\" [color]=\"!isDarkMode ? 'dark' : 'medium'\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n </div>\n @if(windowWidth < 768) {\n <div [class]=\"'dcf-dropdown ' + (options.length > 0 ? ' dcf-active' : '')\" #optionsFilterElement>\n <div>\n @if(filteredOptions.length > 0) {\n @for(key of filteredOptions; track key) {\n <div\n class=\"dcf-item\"\n tabindex=\"0\"\n (keydown.enter)=\"selectOption(key)\"\n (click)=\"selectOption(key)\">\n {{ key }}\n </div>\n }\n } @else {\n <div class=\"dcf-empty\"\n (click)=\"filteredOptions = options; value = ''\"\n tabindex=\"0\"\n (keydown.enter)=\"filteredOptions = options; value = ''\"\n >\n {{ locale + '.no_suggestions' | translate }}\n </div>\n }\n </div>\n </div>\n }\n </div>\n @if(!disableSort) {\n <div class=\"dcf-width-1-5@m dcf-width-1-1 dcf-sort-container\">\n <div class=\"dcf-grid dcf-grid-collapse dcf-flex dcf-flex-middle dcf-grid-match\">\n <div class=\"dcf-width-expand\">\n <ion-select\n toggleIcon=\"chevron-down-outline\"\n expandedIcon=\"chevron-up-outline\"\n class=\"dcf-sort-select\"\n (ionChange)=\"handleSortChange($event)\"\n interface=\"popover\"\n [value]=\"sortValue\"\n label-placement=\"floating\"\n fill=\"outline\"\n [label]=\"locale + '.sort' | translate\"\n >\n @for(sort of sortBy; track sort) {\n\n <ion-select-option [value]=\"sort\">{{ sort | translate }}</ion-select-option>\n }\n </ion-select>\n </div>\n <div class=\"dcf-width-auto\">\n <ion-button (click)=\"handleSortDirectionChange()\" fill=\"clear\">\n <ion-icon slot=\"icon-only\" [color]=\"!isDarkMode ? 'primary' : 'medium'\" [name]=\"sortDirection === 'desc' ? 'arrow-down-outline' : 'arrow-up-outline'\"></ion-icon>\n </ion-button>\n </div>\n </div>\n </div>\n }\n</div>\n\n\n", styles: [".dcf-filter-grid{padding:0 .5rem;margin-top:.75rem;margin-bottom:.75rem}ion-select{min-height:44px!important}.dcf-hidden{display:none!important}.dcf-filter{display:flex;width:100%;min-height:40px;box-shadow:0 1px 2px #0a0d120d;border-radius:var(--dcf-border-radius);box-sizing:border-box}@media (prefers-color-scheme: light){.dcf-filter{border:1px solid var(--dcf-color-gray-3);background-color:#fff}.dcf-filter:focus-within{border-color:var(--dcf-color-primary);background-color:#fff}}@media (prefers-color-scheme: dark){.dcf-filter{border:1px solid var(--dcf-color-step-500)}.dcf-filter ::-webkit-input-placeholder,.dcf-filter ::placeholder{color:var(--dcf-color-gray-4)!important}.dcf-filter:hover{border-color:var(--dcf-color-gray-2)}.dcf-filter:focus-within{border-color:var(--dcf-color-gray-2)}}.dcf-filter ion-chip{border-radius:6px;padding:0 8px!important;height:24px;min-height:24px;font-size:.75rem;font-style:normal;font-weight:500;flex-shrink:0;margin-right:2px;white-space:nowrap}@media (prefers-color-scheme: light){.dcf-filter ion-chip{border:1px solid var(--dcf-color-gray-3);color:var(--dcf-color-gray-7)}.dcf-filter ion-chip.dcf-filter-value{background:var(--dcf-color-gray-2);border-color:var(--dcf-color-gray-4)!important;color:var(--dcf-color-gray-8)!important}}@media (prefers-color-scheme: dark){.dcf-filter ion-chip{border-color:var(--dcf-color-step-300);background:rgba(var(--dcf-color-medium-rgb),.1)}.dcf-filter ion-chip.dcf-filter-value{background:rgba(var(--dcf-color-medium-rgb),.3)!important;border-color:var(--dcf-color-step-500)}}.dcf-filter ion-chip.sc-ion-chip-md-h,.dcf-filter ion-chip.sc-ion-chip-ios-h{height:24px;min-height:24px}.dcf-filter ion-chip.sc-ion-chip-md-h .chip-native,.dcf-filter ion-chip.sc-ion-chip-ios-h .chip-native{padding:0 8px!important;height:24px;min-height:24px}.dcf-filter ion-chip ion-label{padding:0 4px;margin:0;font-size:.75rem;white-space:nowrap}.dcf-filter ion-chip ion-icon{margin:0 2px;font-size:.75rem}.dcf-filter .dcf-input{width:100%;display:flex;align-items:center;overflow-x:auto;overflow-y:hidden;white-space:nowrap;padding-left:.5rem}.dcf-filter .dcf-input input{min-height:40px;min-width:100px;width:100%;font-size:1rem;border:none;outline:none;background:transparent;border:0px!important;outline:none!important}@media (prefers-color-scheme: light){.dcf-filter .dcf-input input{color:var(--dcf-color-gray-7)}}@media (prefers-color-scheme: dark){.dcf-filter .dcf-input input{color:var(--dcf-color-gray-1)}}.dcf-filter .dcf-input input:focus{border:0px!important;outline:none!important}.dcf-filter .dcf-icon-clear,.dcf-filter .dcf-icon-search{display:flex;justify-content:center;text-align:center;align-items:center;min-width:40px}.dcf-filter .dcf-icon-search ion-icon{font-size:1.25rem}.dcf-sort-container{min-width:200px!important;width:auto}@media (min-width: 990px){.dcf-sort-container{max-width:20%!important}}@media (max-width: 680px){.dcf-sort-container{min-width:100%!important;margin:.75rem 0rem}}.dcf-dropdown{position:absolute;max-height:200px;overflow-y:auto;border-radius:4px;z-index:1000!important;min-width:200px;max-width:300px;display:none}@media (prefers-color-scheme: light){.dcf-dropdown{background-color:#fff}.dcf-dropdown.dcf-active{border:1px solid var(--dcf-color-gray-2)}}@media (prefers-color-scheme: dark){.dcf-dropdown{background-color:var(--dcf-item-background)}.dcf-dropdown.dcf-active{border:1px solid var(--dcf-color-step-600)}}.dcf-dropdown.dcf-active{display:block;margin-top:-3px;box-shadow:0 12px 16px -4px #0a0d1214,0 4px 6px -2px #0a0d1208,0 2px 2px -1px #0a0d120a!important;border-radius:var(--dcf-border-radius);padding:.5rem .25rem}@media (max-width: 768px){.dcf-dropdown.dcf-active{margin-top:55px}}.dcf-dropdown.dcf-active>div>div{cursor:pointer;height:35px;padding:.5rem 1rem;border:1px solid transparent;font-size:1rem;display:flex;align-items:center;border-radius:6px}@media (prefers-color-scheme: light){.dcf-dropdown.dcf-active>div>div{color:var(--dcf-color-gray-8)}.dcf-dropdown.dcf-active>div>div.dcf-filtering-item,.dcf-dropdown.dcf-active>div>div:only-child{border-color:var(--dcf-color-gray-3)}.dcf-dropdown.dcf-active>div>div.dcf-filtering-item.dcf-empty,.dcf-dropdown.dcf-active>div>div:only-child.dcf-empty{pointer-events:none;touch-action:none;cursor:text!important;border-color:transparent!important}.dcf-dropdown.dcf-active>div>div:hover{background-color:var(--dcf-color-gray-1)}}@media (prefers-color-scheme: dark){.dcf-dropdown.dcf-active>div>div{color:var(--dcf-color-gray-1)}.dcf-dropdown.dcf-active>div>div.dcf-filtering-item,.dcf-dropdown.dcf-active>div>div:only-child{border-color:var(--dcf-color-gray-5)}.dcf-dropdown.dcf-active>div>div.dcf-filtering-item.dcf-empty,.dcf-dropdown.dcf-active>div>div:only-child.dcf-empty{cursor:text!important;pointer-events:none;touch-action:none;border-color:transparent!important}.dcf-dropdown.dcf-active>div>div:hover{background-color:var(--dcf-color-gray-8)}}\n"] }]
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"] }]
6208
6199
  }], ctorParameters: () => [], propDecorators: { optionsFilterElement: [{
6209
6200
  type: ViewChild,
6210
6201
  args: ['optionsFilterElement', { read: ElementRef, static: false }]
@@ -6335,10 +6326,10 @@ class ModelRendererComponent {
6335
6326
  }
6336
6327
  }
6337
6328
  }
6338
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ModelRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6339
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ModelRendererComponent, isStandalone: true, selector: "ngx-decaf-model-renderer", inputs: { model: "model", globals: "globals", projectable: "projectable", rendererId: "rendererId" }, outputs: { listenEvent: "listenEvent" }, host: { properties: { "attr.id": "rendererId" } }, viewQueries: [{ propertyName: "inner", first: true, predicate: ["inner"], descendants: true, read: TemplateRef, static: true }, { propertyName: "vcr", first: true, predicate: ["componentOuter"], descendants: true, read: ViewContainerRef, static: true }], usesOnChanges: true, ngImport: i0, template: " <!-- Keep to avoid id conflicts -->\n <div [id]=\"rendererId\"></div>\n\n <ng-template #componentOuter></ng-template>\n <ng-template #inner>\n <div [id]=\"rendererId || null\">\n @for (child of output?.children; track child) {\n @if(child?.children?.length) {\n <ngx-decaf-component-renderer [parent]=\"child\" />\n } @else {\n <ng-container\n #childComponents\n *ngComponentOutlet=\"\n child.component;\n injector: child.injector;\n inputs: child.inputs;\n content:child.content;\n \"\n />\n }\n }\n </div>\n </ng-template>\n", styles: [""], dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "children", "model", "parent"], outputs: ["listenEvent"] }] }); }
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"] }] }); }
6340
6331
  }
6341
- 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: [{
6342
6333
  type: Component,
6343
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" }]
6344
6335
  }], propDecorators: { model: [{
@@ -6488,10 +6479,10 @@ class LayoutComponent extends NgxBaseComponent {
6488
6479
  this.rows = this._rows;
6489
6480
  this.initialized = true;
6490
6481
  }
6491
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6492
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: LayoutComponent, isStandalone: true, selector: "ngx-decaf-layout", inputs: { cols: "cols", rows: "rows", breakpoint: "breakpoint", children: "children" }, usesInheritance: true, ngImport: i0, template: "\n@if(initialized) {\n @for (row of rows; track trackItemFn($index, row); let rowIndex = $index) {\n <div [id]=\"uid\" class=\"dcf-grid dcf-grid-collapse dcf-grid-match\">\n @if(row) {\n <div class=\"dcf-width-1-1 dcf-grid-title\">\n <ion-card class=\"dcf-grid-title\">\n {{row.title | translate}}\n </ion-card>\n </div>\n }\n @for (child of row.cols; track trackItemFn($index, child.col); let colIndex = $index) {\n <div [class]=\"(child.col === cols.length ? 'dcf-width-1-1' : 'dcf-width-'+child.col+'-'+cols.length+'@'+breakpoint)\">\n <div [class]=\"'dcf-grid-child '+child.col \">\n @if(child.tag === 'ngx-decaf-crud-form') {\n <ion-card [class]=\"'dcf-height-1-1 ' + className\">\n <ion-card-content>\n <ngx-decaf-model-renderer\n [model]=\"child.props.name\"\n (listenEvent)=\"handleEvent($event)\"\n />\n </ion-card-content>\n </ion-card>\n } @else {\n <ngx-decaf-component-renderer\n [tag]=\"child.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]=\"{props: child.props}\"\n />\n }\n </div>\n </div>\n }\n </div>\n }\n}\n", styles: [".dcf-grid>div:not(.dcf-grid-title) ::ng-deep ngx-decaf-component-renderer>*>*{height:100%;display:flex;justify-content:center!important;align-items:center!important}.dcf-grid ion-card.dcf-height-1-1>ion-card-content{margin-top:2rem}.dcf-grid.dcf-grid-small .dcf-grid-child{margin-bottom:2rem}.dcf-grid.dcf-grid-collapse .dcf-grid-child{margin-bottom:1.25rem}.dcf-grid.dcf-grid-collapse .dcf-grid-child ion-card{margin-bottom:1.25rem}.dcf-grid-title{font-size:1.05rem!important;background:none;box-shadow:none;margin-bottom:0;padding-bottom:0;font-weight:600;color:var(--dcf-color-dark);display:flex;align-items:center;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}\n"], dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "component", type: ModelRendererComponent, selector: "ngx-decaf-model-renderer", inputs: ["model", "globals", "projectable", "rendererId"], outputs: ["listenEvent"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "children", "model", "parent"], outputs: ["listenEvent"] }] }); }
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" }] }); }
6493
6484
  }
6494
- 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: [{
6495
6486
  type: Component,
6496
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"] }]
6497
6488
  }], ctorParameters: () => [], propDecorators: { cols: [{
@@ -6505,857 +6496,466 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
6505
6496
  }] } });
6506
6497
 
6507
6498
  /**
6508
- * @description A component for displaying a list item with various customization options.
6509
- * @summary The ListItemComponent is an Angular component that extends NgxBaseComponent. It provides a flexible and customizable list item interface with support for icons, buttons, and various text elements. The component also handles actions and navigation based on user interactions.
6510
- *
6511
- * @class
6512
- * @extends NgxBaseComponent
6513
- *
6514
- * @param {string} [lines='none'] - Determines the line style of the item. Can be 'inset', 'inseet', or 'none'.
6515
- * @param {Record<string, any>} item - The data item to be displayed in the list item.
6516
- * @param {string} icon - The name of the icon to be displayed.
6517
- * @param {'start' | 'end'} [iconSlot='start'] - The position of the icon within the item.
6518
- * @param {StringOrBoolean} [button=true] - Determines if the item should behave as a button.
6519
- * @param {string} [title] - The main title of the list item.
6520
- * @param {string} [description] - A description for the list item.
6521
- * @param {string} [info] - Additional information for the list item.
6522
- * @param {string} [subinfo] - Sub-information for the list item.
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.
6523
6503
  *
6524
- * @example
6525
- * <ngx-decaf-list-item
6526
- * [item]="dataItem"
6527
- * icon="star"
6528
- * title="Item Title"
6529
- * description="Item Description"
6530
- * (clickEvent)="handleItemClick($event)">
6531
- * </ngx-decaf-list-item>
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.
6532
6507
  *
6533
6508
  * @mermaid
6534
6509
  * sequenceDiagram
6535
- * participant C as Component
6536
- * participant V as View
6537
6510
  * participant U as User
6538
- * C->>V: Initialize component
6539
- * V->>U: Display list item
6540
- * U->>V: Click on item or action
6541
- * V->>C: Trigger handleAction()
6542
- * C->>C: Process action
6543
- * C->>V: Update view or navigate
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}
6544
6538
  */
6545
- let ListItemComponent = class ListItemComponent extends NgxBaseComponent {
6539
+ class PaginationComponent extends NgxBaseComponent {
6546
6540
  /**
6547
- * @description Creates an instance of ListItemComponent.
6548
- * @summary Initializes a new ListItemComponent by calling the parent class constructor
6549
- * with the component name for logging and identification purposes. Also registers
6550
- * all available Ionic icons to ensure they can be displayed in the component.
6551
- *
6552
- * @memberOf ListItemComponent
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.
6553
6544
  */
6554
6545
  constructor() {
6555
- super("ListItemComponent");
6556
- /**
6557
- * @description Controls the display of lines around the list item.
6558
- * @summary Determines how lines are displayed around the list item borders.
6559
- * 'inset' shows lines with padding, 'full' shows full-width lines, and 'none'
6560
- * removes all lines. This affects the visual separation between list items.
6561
- *
6562
- * @type {'inset' | 'full' | 'none'}
6563
- * @default 'inset'
6564
- * @memberOf ListItemComponent
6565
- */
6566
- this.lines = 'full';
6567
- /**
6568
- * @description Position of the icon within the list item.
6569
- * @summary Determines whether the icon appears at the start (left in LTR languages)
6570
- * or end (right in LTR languages) of the list item. This affects the overall
6571
- * layout and visual hierarchy of the item content.
6572
- *
6573
- * @type {'start' | 'end'}
6574
- * @default 'start'
6575
- * @memberOf ListItemComponent
6576
- */
6577
- this.iconSlot = 'start';
6546
+ super("PaginationComponent");
6578
6547
  /**
6579
- * @description Controls whether the list item behaves as a clickable button.
6580
- * @summary When set to true, the list item will have button-like behavior including
6581
- * hover effects, click handling, and appropriate accessibility attributes.
6582
- * When false, the item is displayed as static content without interactive behavior.
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.
6583
6551
  *
6584
6552
  * @type {StringOrBoolean}
6585
6553
  * @default true
6586
- * @memberOf ListItemComponent
6587
- */
6588
- this.button = true;
6589
- /**
6590
- * @description Event emitter for list item click interactions.
6591
- * @summary Emits custom events when the list item is clicked or when actions
6592
- * are performed on it. The emitted event contains information about the action,
6593
- * the item data, and other relevant context for parent components to handle.
6594
- *
6595
- * @type {EventEmitter<ListItemCustomEvent>}
6596
- * @memberOf ListItemComponent
6597
- */
6598
- this.clickEvent = new EventEmitter();
6599
- /**
6600
- * @description Flag indicating whether slide items are currently enabled.
6601
- * @summary Controls the visibility of slide actions based on screen size and
6602
- * available operations. When true, users can swipe on the item to reveal
6603
- * action buttons for operations like edit and delete.
6604
- *
6605
- * @type {boolean}
6606
- * @default false
6607
- * @memberOf ListItemComponent
6554
+ * @memberOf PaginationComponent
6608
6555
  */
6609
- this.showSlideItems = false;
6556
+ this.translatable = true;
6610
6557
  /**
6611
- * @description Flag indicating whether the action menu popover is currently open.
6612
- * @summary Tracks the state of the action menu to prevent multiple instances
6613
- * from being opened simultaneously and to ensure proper cleanup when actions
6614
- * are performed. Used for managing the popover lifecycle.
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.
6615
6561
  *
6616
- * @type {boolean}
6617
- * @default false
6618
- * @memberOf ListItemComponent
6562
+ * @type {number}
6563
+ * @default 1
6564
+ * @memberOf PaginationComponent
6619
6565
  */
6620
- this.actionMenuOpen = false;
6566
+ this.current = 1;
6621
6567
  /**
6622
- * @description Angular NavController service for handling navigation.
6623
- * @summary Injected service that provides methods for programmatic navigation
6624
- * within the Ionic application. Used for navigating to different routes when
6625
- * list item actions are performed or when the item itself is clicked.
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.
6626
6572
  *
6627
- * @private
6628
- * @type {NavController}
6629
- * @memberOf ListItemComponent
6573
+ * @type {EventEmitter<PaginationCustomEvent>}
6574
+ * @memberOf PaginationComponent
6630
6575
  */
6631
- this.navController = inject(NavController);
6632
- addIcons(allIcons);
6576
+ this.clickEvent = new EventEmitter();
6577
+ addIcons({ chevronBackOutline, chevronForwardOutline });
6633
6578
  }
6634
6579
  /**
6635
- * @description Initializes the component after Angular first displays the data-bound properties.
6636
- * @summary Sets up the component by determining slide item visibility, processing boolean inputs,
6637
- * building CSS class names based on properties, and capturing the current window width.
6638
- * This method prepares the component for user interaction by ensuring all properties are
6639
- * properly initialized and responsive behavior is configured.
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.
6640
6584
  *
6641
6585
  * @mermaid
6642
6586
  * sequenceDiagram
6643
6587
  * participant A as Angular Lifecycle
6644
- * participant L as ListItemComponent
6645
- * participant W as Window
6588
+ * participant P as PaginationComponent
6646
6589
  *
6647
- * A->>L: ngOnInit()
6648
- * L->>L: enableSlideItems()
6649
- * L->>L: Process button boolean
6650
- * L->>L: Build className with flex classes
6651
- * alt operations exist
6652
- * L->>L: Add 'action' class
6653
- * end
6654
- * L->>W: getWindowWidth()
6655
- * W-->>L: Return current width
6656
- * L->>L: Store windowWidth
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
6657
6596
  *
6658
- * @return {Promise<void>}
6659
- * @memberOf ListItemComponent
6597
+ * @returns {void}
6598
+ * @memberOf PaginationComponent
6660
6599
  */
6661
- async ngOnInit() {
6662
- this.showSlideItems = this.enableSlideItems();
6663
- this.button = stringToBoolean(this.button);
6664
- this.className = `${this.className} dcf-flex dcf-flex-middle grid-item`;
6665
- if (this.operations?.length)
6666
- this.className += ` action`;
6667
- this.windowWidth = getWindowWidth();
6600
+ ngOnInit() {
6601
+ this.locale = this.getLocale(this.translatable);
6602
+ this.pages = this.getPages(this.totalPages, this.current);
6603
+ this.last = this.totalPages;
6668
6604
  }
6669
6605
  /**
6670
- * @description Handles user interactions and actions performed on the list item.
6671
- * @summary This method is the central action handler for list item interactions. It manages
6672
- * event propagation, dismisses open action menus, removes focus traps, and either emits
6673
- * events for parent components to handle or performs navigation based on the component's
6674
- * route configuration. This method supports both event-driven and navigation-driven architectures.
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.
6675
6610
  *
6676
- * @param {CrudOperations} action - The type of CRUD operation being performed
6677
- * @param {Event} event - The browser event that triggered the action
6678
- * @param {HTMLElement} [target] - Optional target element for the event
6679
- * @return {Promise<boolean|void>} A promise that resolves to navigation success or void for events
6611
+ * @param {('next' | 'previous')} direction - The direction of navigation
6612
+ * @param {number} [page] - Optional page number to navigate to directly
6613
+ * @returns {void}
6680
6614
  *
6681
6615
  * @mermaid
6682
6616
  * sequenceDiagram
6683
6617
  * participant U as User
6684
- * participant L as ListItemComponent
6685
- * participant P as Parent Component
6686
- * participant N as NavController
6687
- * participant E as Event System
6618
+ * participant P as PaginationComponent
6619
+ * participant E as External Component
6688
6620
  *
6689
- * U->>L: Perform action (click/swipe)
6690
- * L->>L: stopImmediatePropagation()
6691
- * alt actionMenuOpen
6692
- * L->>L: Dismiss action menu
6693
- * end
6694
- * L->>L: removeFocusTrap()
6695
- * alt No route configured
6696
- * L->>E: windowEventEmitter()
6697
- * L->>P: clickEvent.emit()
6698
- * else Route configured
6699
- * L->>N: redirect(action, uid)
6700
- * N-->>L: Return navigation result
6621
+ * U->>P: Click pagination control
6622
+ * P->>P: handleClick(direction, page?)
6623
+ * alt page is provided
6624
+ * P->>P: Update current page
6701
6625
  * end
6626
+ * P->>E: Emit clickEvent with direction and page
6702
6627
  *
6703
- * @memberOf ListItemComponent
6628
+ * @memberOf PaginationComponent
6704
6629
  */
6705
- async handleAction(action, event, target) {
6706
- event.stopImmediatePropagation();
6707
- if (this.actionMenuOpen)
6708
- await this.actionMenuComponent.dismiss();
6709
- // forcing trap focus
6710
- removeFocusTrap();
6711
- if (!this.route) {
6712
- const event = { target: target, action, pk: this.pk, data: this.uid, name: EventConstants.CLICK, component: this.componentName };
6713
- windowEventEmitter(`ListItem${EventConstants.CLICK}`, event);
6714
- return this.clickEvent.emit(event);
6715
- }
6716
- return await this.redirect(action, (typeof this.uid === 'number' ? `${this.uid}` : this.uid));
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
+ });
6717
6641
  }
6718
6642
  /**
6719
- * @description Responsive handler that enables or disables slide items based on screen size and operations.
6720
- * @summary This method is automatically called when the window is resized and also during component
6721
- * initialization. It determines whether slide actions should be available based on the current
6722
- * window width and the presence of UPDATE or DELETE operations. Slide items are typically hidden
6723
- * on larger screens where there's space for dedicated action buttons.
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.
6724
6648
  *
6725
- * @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
6726
6652
  *
6727
6653
  * @mermaid
6728
- * sequenceDiagram
6729
- * participant W as Window
6730
- * participant L as ListItemComponent
6731
- * 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
6732
6662
  *
6733
- * W->>L: resize event
6734
- * L->>W: getWindowWidth()
6735
- * W-->>L: Return current width
6736
- * L->>L: Store windowWidth
6737
- * alt No operations OR width > 639px
6738
- * L->>U: showSlideItems = false
6739
- * else Operations include UPDATE/DELETE
6740
- * L->>U: showSlideItems = true
6741
- * end
6742
- * L-->>U: Return showSlideItems value
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.
6743
6701
  *
6744
- * @memberOf ListItemComponent
6702
+ * @returns {number} The current page number
6703
+ * @memberOf PaginationComponent
6745
6704
  */
6746
- enableSlideItems() {
6747
- this.windowWidth = getWindowWidth();
6748
- if (!this.operations?.length || this.windowWidth > 639)
6749
- return this.showSlideItems = false;
6750
- this.showSlideItems = this.operations.includes(OperationKeys.UPDATE) || this.operations.includes(OperationKeys.DELETE);
6751
- return this.showSlideItems;
6705
+ getCurrent() {
6706
+ return this.current;
6752
6707
  }
6753
6708
  /**
6754
- * @description Animates and removes an element from the DOM.
6755
- * @summary This method applies CSS animation classes to create a smooth fade-out effect
6756
- * before removing the element from the DOM. The animation enhances user experience by
6757
- * providing visual feedback when items are deleted or removed from lists. The timing
6758
- * is coordinated with the CSS animation duration to ensure the element is removed
6759
- * after the animation completes.
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.
6760
6713
  *
6761
- * @param {HTMLElement} element - The DOM element to animate and remove
6762
- * @return {void}
6714
+ * @returns {void}
6763
6715
  *
6764
6716
  * @mermaid
6765
6717
  * sequenceDiagram
6766
- * participant L as ListItemComponent
6767
- * participant E as HTMLElement
6768
- * participant D as DOM
6718
+ * participant U as User
6719
+ * participant P as PaginationComponent
6769
6720
  *
6770
- * L->>E: Add animation classes
6771
- * Note over E: uk-animation-fade, uk-animation-medium, uk-animation-reverse
6772
- * E->>E: Start fade animation
6773
- * L->>L: setTimeout(600ms)
6774
- * Note over L: Wait for animation to complete
6775
- * L->>D: element.remove()
6776
- * D->>D: Remove element from DOM
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
6777
6727
  *
6778
- * @memberOf ListItemComponent
6728
+ * @memberOf PaginationComponent
6779
6729
  */
6780
- removeElement(element) {
6781
- element.classList.add('uk-animation-fade', 'uk-animation-medium', 'uk-animation-reverse');
6782
- 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
+ }
6783
6736
  }
6784
6737
  /**
6785
- * @description Navigates to a new route based on the specified action and item ID.
6786
- * @summary This method constructs a navigation URL using the component's route configuration,
6787
- * the specified action, and an item identifier. It uses Ionic's NavController to perform
6788
- * forward navigation with appropriate animations. This method is typically used for
6789
- * CRUD operations where each action (create, read, update, delete) has its own route.
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.
6790
6742
  *
6791
- * @param {string} action - The action to be performed (e.g., 'edit', 'view', 'delete')
6792
- * @param {string} [id] - The unique identifier of the item to be acted upon
6793
- * @return {Promise<boolean>} A promise that resolves to true if navigation was successful
6743
+ * @returns {void}
6794
6744
  *
6795
6745
  * @mermaid
6796
6746
  * sequenceDiagram
6797
- * participant L as ListItemComponent
6798
- * participant N as NavController
6799
- * participant R as Router
6747
+ * participant U as User
6748
+ * participant P as PaginationComponent
6800
6749
  *
6801
- * L->>L: redirect(action, id)
6802
- * L->>L: Construct URL: /{route}/{action}/{id}
6803
- * L->>N: navigateForward(url)
6804
- * N->>R: Navigate to constructed URL
6805
- * R-->>N: Return navigation result
6806
- * N-->>L: Return boolean success
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
6807
6756
  *
6808
- * @memberOf ListItemComponent
6757
+ * @memberOf PaginationComponent
6809
6758
  */
6810
- async redirect(action, id) {
6811
- 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
+ }
6812
6765
  }
6813
6766
  /**
6814
- * @description Presents the actions menu popover for the list item.
6815
- * @summary This method handles the display of a contextual action menu when triggered by user
6816
- * interaction (typically a long press or right-click). It stops event propagation to prevent
6817
- * unwanted side effects, removes any existing focus traps for accessibility, configures the
6818
- * popover with the triggering event, and opens the action menu. The menu typically contains
6819
- * available CRUD operations for the item.
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.
6820
6771
  *
6821
- * @param {Event} event - The event that triggered the action menu request
6822
- * @return {void}
6772
+ * @param {number | null} page - The page number to navigate to
6773
+ * @returns {void}
6823
6774
  *
6824
6775
  * @mermaid
6825
6776
  * sequenceDiagram
6826
6777
  * participant U as User
6827
- * participant L as ListItemComponent
6828
- * participant P as Popover
6829
- * participant A as Accessibility
6778
+ * participant P as PaginationComponent
6830
6779
  *
6831
- * U->>L: Trigger action menu (long press/right-click)
6832
- * L->>L: stopImmediatePropagation()
6833
- * L->>A: removeFocusTrap()
6834
- * L->>P: Set event reference
6835
- * L->>L: actionMenuOpen = true
6836
- * L->>P: Display popover with actions
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
6837
6786
  *
6838
- * @memberOf ListItemComponent
6787
+ * @memberOf PaginationComponent
6839
6788
  */
6840
- presentActionsMenu(event) {
6841
- event.stopImmediatePropagation();
6842
- // forcing trap focus
6843
- removeFocusTrap();
6844
- this.actionMenuComponent.event = event;
6845
- this.actionMenuOpen = true;
6789
+ navigate(page) {
6790
+ if (page !== null && this.current !== page)
6791
+ this.handleClick(page > this.current ? 'next' : 'previous', page);
6846
6792
  }
6847
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ListItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6848
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ListItemComponent, isStandalone: true, selector: "ngx-decaf-list-item", inputs: { lines: "lines", item: "item", icon: "icon", iconSlot: "iconSlot", button: "button", title: "title", description: "description", info: "info", subinfo: "subinfo" }, outputs: { clickEvent: "clickEvent" }, host: { listeners: { "window:resize": "enableSlideItems($event)" } }, viewQueries: [{ propertyName: "actionMenuComponent", first: true, predicate: ["actionMenuComponent"], descendants: true }], usesInheritance: true, ngImport: i0, template: "\n@if(title || description) {\n <ion-item-sliding #component>\n <ion-item\n [id]=\"uid\"\n [lines]=\"lines\"\n [button]=\"button\"\n [class]=\"className\"\n (click)=\"operations?.includes('read') ? handleAction('read', $event, component) : ''\n \">\n @if(icon && lines !== 'inset') {\n <div class=\"dcf-icon\" [slot]=\"iconSlot\">\n <ion-avatar>\n <ion-icon aria-hidden=\"true\" name=\"reader-outline\" size=\"default\"></ion-icon>\n </ion-avatar>\n </div>\n }\n <div class=\"dcf-width-expand\">\n <div class=\"dcf-flex dcf-flex-middle dcf-grid-collapse\" dcf-grid>\n @if(icon && lines === 'inset') {\n <div class=\"dcf-icon dcf-grid-icon\">\n <ion-avatar>\n <ion-icon aria-hidden=\"true\" name=\"reader-outline\" size=\"default\"></ion-icon>\n </ion-avatar>\n </div>\n }\n <div class=\"dcf-width-expand@s dcf-width-1-1 dcf-label\">\n <ion-label class=\"dcf-item-title\" [innerHTML]=\"uid + ' - ' + title\" ></ion-label>\n @if(description) {\n <div class=\"dcf-description\" [innerHTML]=\"description\"></div>\n }\n </div>\n @if(info || subinfo) {\n <div class=\"dcf-width-auto@s dcf-width-expand dcf-info dcf-flex dcf-flex-right@s\">\n <div>\n @if(info) {\n <span [innerHTML]=\"info\"></span>\n }\n @if(subinfo) {\n <div class=\"dcf-subinfo dcf-text-truncate\" [innerHTML]=\"subinfo\" ></div>\n }\n </div>\n </div>\n }\n\n <div class=\"dcf-width-auto dcf-flex dcf-flex-middle dcf-flex-right\">\n @if((operations.includes('delete') || operations.includes('update')) && uid) {\n <div class=\"dcf-visible@m\" id=\"dcf-actions\">\n <ion-button class=\"dcf-hidden@m\" shape=\"round\" fill=\"clear\" color=\"primary\" (click)=\"presentActionsMenu($event)\">\n <ion-icon slot=\"icon-only\" aria-hidden=\"true\" name=\"ellipsis-vertical-outline\"></ion-icon>\n </ion-button>\n <ion-popover\n #actionMenuComponent\n side=\"bottom\"\n alignment=\"left\"\n\n [isOpen]=\"actionMenuOpen\"\n (didDismiss)=\"actionMenuOpen = false\">\n <ng-template>\n <ion-content class=\"ion-padding\">\n <ion-list lines=\"none\">\n <ion-list-header>\n <h4 class=\"dcf-text-capitalize\" [innerHTML]=\"'actions' | translate\"></h4>\n </ion-list-header>\n @for (operation of ['update', 'delete']; track operation) {\n @if(operations.includes(operation)) {\n <ion-item [button]=\"true\" (click)=\"handleAction(operation, $event, component)\">\n <ion-avatar class=\"dcf-flex dcf-flex-middle\" aria-hidden=\"true\" slot=\"start\">\n @if(operation === 'update') {\n <ion-icon color=\"primary\" aria-hidden=\"true\" name=\"create-outline\"></ion-icon>\n } @else {\n <ion-icon color=\"danger\" aria-hidden=\"true\" name=\"trash\"></ion-icon>\n }\n </ion-avatar>\n <ion-label class=\"dcf-text-capitalize\">{{ operation | translate }}</ion-label>\n </ion-item>\n }\n }\n </ion-list>\n </ion-content>\n </ng-template>\n </ion-popover>\n </div>\n }\n <!-- @if(operations?.length && uid) {\n <div class=\"dcf-visible@m\" id=\"dcf-actions\">\n @if(operations?.includes('update')) {\n <ion-button fill=\"clear\" size=\"small\" color=\"primary\" (click)=\"handleAction('update', component)\">\n <ion-icon aria-hidden=\"true\" slot=\"icon-only\" name=\"create-outline\"></ion-icon>\n </ion-button>\n }\n @if(operations?.includes('delete')) {\n <ion-button fill=\"clear\" size=\"small\" color=\"danger\" (click)=\"handleAction('delete', component)\">\n <ion-icon aria-hidden=\"true\" slot=\"icon-only\" name=\"trash\"></ion-icon>\n </ion-button>\n }\n </div>\n } -->\n @if(windowWidth > 639) {\n <div id=\"end\">\n <ng-content select=\"[slot='end']\"></ng-content>\n </div>\n }\n </div>\n </div>\n </div>\n </ion-item>\n @if(showSlideItems && uid) {\n <ion-item-options side=\"end\" (ionSwipe)=\"operations.length === 1 ? handleAction(operations[0], $event, component) : ''\">\n @if(operations?.includes('update')) {\n <ion-item-option class=\"dcf-update\" (click)=\"handleAction('update', $event, component)\" [expandable]=\"operations.length === 1\">\n <ion-icon aria-hidden=\"true\" slot=\"icon-only\" name=\"create-outline\"></ion-icon>\n </ion-item-option>\n }\n @if(operations?.includes('delete')) {\n <ion-item-option class=\"dcf- delete\" (click)=\"handleAction('delete', $event, component)\" [expandable]=\"operations.length === 1\">\n <ion-icon aria-hidden=\"true\" slot=\"icon-only\" name=\"trash\"></ion-icon>\n </ion-item-option>\n }\n </ion-item-options>\n }\n </ion-item-sliding>\n}\n", styles: ["ion-item{--min-height: 50px;--padding-top: .25rem;--padding-bottom: .25rem;--padding-start: .75rem;--padding-end: .75rem;--inner-padding-start: 0px !important;--inner-padding-end: 0px !important;--background-hover: var(--dcf-color-gray-8);--background-focused: var(--dcf-color-gray-8)}@media (prefers-color-scheme: dark){ion-item{--background-hover-opacity: .25;--background-focused-opacity: .25}}@media (prefers-color-scheme: light){ion-item{--background-hover-opacity: .1;--background-focused-opacity: .1}}ion-item.item-lines-full{--padding-top: .5rem;--padding-bottom: .5rem;--padding-start: .25rem;-padding-end:.25rem;padding:0 .65rem}ion-item.item-lines-inset{--padding-top: 0rem !important;--padding-bottom: 0rem !important;--inner-padding-top: .5rem !important;--inner-padding-bottom: .65rem !important}@media (prefers-color-scheme: light){ion-item{--border-color: var(--dcf-color-gray-2)}ion-item .dcf-info{color:var(--dcf-color-gray-6)}ion-item .dcf-item-title{color:var(--dcf-color-gray-8)}ion-item .dcf-description{color:var(--dcf-color-gray-6)}}@media (prefers-color-scheme: dark){ion-item{--border-color: var(--dcf-color-gray-6)}ion-item .dcf-description{color:var(--dcf-color-gray-4)}}ion-item .dcf-info{min-width:10vw;background:transparent!important}ion-item .dcf-grid{padding:0!important;margin:0!important;min-width:100%!important}ion-item .dcf-item-title{font-style:normal;font-weight:700}ion-item .dcf-description{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-style:normal;font-weight:400;font-size:.925rem}ion-item::part(native){min-width:100%}ion-item [slot=start]{margin-right:.5rem!important}ion-item [slot=end]{margin-left:.5rem!important}ion-item .dcf-info{font-size:.9rem}ion-item .dcf-info .dcf-subinfo.dcf-line{margin-left:.5rem}@media (min-width: var(--dcf-width-sm)){ion-item .dcf-info .dcf-subinfo.dcf-line{display:block;margin-left:0}}ion-item #dcf-actions{padding:5px}@media (max-width: var(--dcf-width-m)){ion-item #dcf-actions{display:none;pointer-events:none!important;cursor:text!important}ion-item #dcf-actions *{display:none;pointer-events:none!important;cursor:text!important}}ion-item #dcf-actions ion-button{--padding-start: 1rem;--padding-end: .75rem;--padding-top: .85rem !important;--padding-bottom: .85rem !important;color:#ccc;margin-right:.5rem!important;--background: var(--dcf-color-gray-2) !important}ion-item #dcf-actions ion-button ion-icon{position:relative;left:-1px}@media (max-width: var(--dcf-width-m)){ion-item #dcf-end,ion-item [slot=end]{display:none!important}}ion-item #dcf-end{padding-top:5px;display:flex;align-items:flex-end}ion-item .dcf-icon{display:flex;justify-content:center;align-items:center;text-align:center;margin-right:.5rem!important}ion-item .dcf-icon.dcf-grid-icon{min-width:50px;text-align:left;display:flex;justify-content:flex-start}@media (max-width: var(--dcf-width-s)){ion-item .dcf-icon{align-items:flex-start!important}}@media (prefers-color-scheme: light){ion-item .dcf-icon ion-button{color:var(--dcf-color-gray-7);--background: var(--dcf-color-gray-1) !important}}@media (prefers-color-scheme: dark){ion-item .dcf-icon ion-button{color:var(--dcf-color-gray-1)!important;--background: var(--dcf-color-gray-7) !important}}ion-item .dcf-icon ion-button ion-icon{font-size:20px}ion-item .dcf-icon ion-avatar{width:48px;height:48px;display:flex;justify-content:center;align-items:center;text-align:center}@media (prefers-color-scheme: light){ion-item .dcf-icon ion-avatar{color:var(--dcf-color-gray-7);background:var(--dcf-color-gray-1)!important}}@media (prefers-color-scheme: dark){ion-item .dcf-icon ion-avatar{color:var(--dcf-color-gray-1)!important;background:var(--dcf-background-color)!important}}ion-item .dcf-icon ion-avatar ion-icon{font-size:20px}ion-item .dcf-icon ion-avatar .dcf-icon-large{transform:translateY(5px)}ion-item-sliding{box-sizing:border-box}@media (prefers-color-scheme: light){ion-item-sliding ion-item-option:not(.dcf-delete),ion-item-sliding ion-item-option:not(.dcf-update){background:rgba(var(--dcf-color-dark-rgb),.25)!important}ion-item-sliding ion-item-option:not(.dcf-delete) .dcf-ti,ion-item-sliding ion-item-option:not(.dcf-delete) ion-icon,ion-item-sliding ion-item-option:not(.dcf-update) .dcf-ti,ion-item-sliding ion-item-option:not(.dcf-update) ion-icon{color:var(--dcf-color-gray-7)!important}ion-item-sliding ion-item-option.dcf-delete{background:rgba(var(--dcf-color-danger-rgb),.05)!important}ion-item-sliding ion-item-option.dcf-delete .dcf-ti,ion-item-sliding ion-item-option.dcf-delete *,ion-item-sliding ion-item-option.dcf-delete ion-icon{color:var(--dcf-color-danger)!important}ion-item-sliding ion-item-option.dcf-update{background:rgba(var(--dcf-color-primary-rgb),.05)!important}ion-item-sliding ion-item-option.dcf-update .dcf-ti,ion-item-sliding ion-item-option.dcf-update ion-icon{color:var(--dcf-color-primary)!important}}@media (prefers-color-scheme: dark){ion-item-sliding ion-item-option:not(.dcf-delete),ion-item-sliding ion-item-option:not(.dcf-update){background:rgba(var(--dcf-color-dark-rgb),1)!important}ion-item-sliding ion-item-option:not(.dcf-delete) .dcf-ti,ion-item-sliding ion-item-option:not(.dcf-delete) ion-icon,ion-item-sliding ion-item-option:not(.dcf-update) .dcf-ti,ion-item-sliding ion-item-option:not(.dcf-update) ion-icon{color:var(--dcf-color-gray-2)!important}ion-item-sliding ion-item-option.dcf-delete{background:rgba(var(--dcf-color-danger-rgb),.05)!important}ion-item-sliding ion-item-option.dcf-delete .dcf-ti,ion-item-sliding ion-item-option.dcf-delete *,ion-item-sliding ion-item-option.dcf-delete ion-icon{color:var(--dcf-color-danger)!important}ion-item-sliding ion-item-option.dcf-update{background:rgba(var(--dcf-color-primary-rgb),.05)!important}ion-item-sliding ion-item-option.dcf-update .dcf-ti,ion-item-sliding ion-item-option.dcf-update ion-icon{color:var(--dcf-color-gray-2)!important}}ion-item-sliding[class*=active-slide]{border-color:var(--dcf-color-gray-3)}ion-item-sliding ion-item-option{color:var(--dcf-color-gray-5);box-shadow:inset 0 0 5px rgba(var(--dcf-color-dark-rgb),.15)!important;background:var(--dcf-color-gray-3)}\n"], dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: IonListHeader, selector: "ion-list-header", inputs: ["color", "lines", "mode"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonItemSliding, selector: "ion-item-sliding", inputs: ["disabled"] }, { kind: "component", type: IonItemOptions, selector: "ion-item-options", inputs: ["side"] }, { kind: "component", type: IonItemOption, selector: "ion-item-option", inputs: ["color", "disabled", "download", "expandable", "href", "mode", "rel", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: IonPopover, selector: "ion-popover" }] }); }
6849
- };
6850
- ListItemComponent = __decorate([
6851
- Dynamic(),
6852
- __metadata("design:paramtypes", [])
6853
- ], ListItemComponent);
6854
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ListItemComponent, decorators: [{
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: [{
6855
6797
  type: Component,
6856
- args: [{ selector: 'ngx-decaf-list-item', standalone: true, imports: [
6798
+ args: [{ selector: 'ngx-decaf-pagination', imports: [
6857
6799
  TranslatePipe,
6858
- IonList,
6859
- IonListHeader,
6860
- IonItem,
6861
- IonItemSliding,
6862
- IonItemOptions,
6863
- IonItemOption,
6864
- IonIcon,
6865
- IonLabel,
6866
- IonButton,
6867
- IonContent,
6868
- IonPopover
6869
- ], template: "\n@if(title || description) {\n <ion-item-sliding #component>\n <ion-item\n [id]=\"uid\"\n [lines]=\"lines\"\n [button]=\"button\"\n [class]=\"className\"\n (click)=\"operations?.includes('read') ? handleAction('read', $event, component) : ''\n \">\n @if(icon && lines !== 'inset') {\n <div class=\"dcf-icon\" [slot]=\"iconSlot\">\n <ion-avatar>\n <ion-icon aria-hidden=\"true\" name=\"reader-outline\" size=\"default\"></ion-icon>\n </ion-avatar>\n </div>\n }\n <div class=\"dcf-width-expand\">\n <div class=\"dcf-flex dcf-flex-middle dcf-grid-collapse\" dcf-grid>\n @if(icon && lines === 'inset') {\n <div class=\"dcf-icon dcf-grid-icon\">\n <ion-avatar>\n <ion-icon aria-hidden=\"true\" name=\"reader-outline\" size=\"default\"></ion-icon>\n </ion-avatar>\n </div>\n }\n <div class=\"dcf-width-expand@s dcf-width-1-1 dcf-label\">\n <ion-label class=\"dcf-item-title\" [innerHTML]=\"uid + ' - ' + title\" ></ion-label>\n @if(description) {\n <div class=\"dcf-description\" [innerHTML]=\"description\"></div>\n }\n </div>\n @if(info || subinfo) {\n <div class=\"dcf-width-auto@s dcf-width-expand dcf-info dcf-flex dcf-flex-right@s\">\n <div>\n @if(info) {\n <span [innerHTML]=\"info\"></span>\n }\n @if(subinfo) {\n <div class=\"dcf-subinfo dcf-text-truncate\" [innerHTML]=\"subinfo\" ></div>\n }\n </div>\n </div>\n }\n\n <div class=\"dcf-width-auto dcf-flex dcf-flex-middle dcf-flex-right\">\n @if((operations.includes('delete') || operations.includes('update')) && uid) {\n <div class=\"dcf-visible@m\" id=\"dcf-actions\">\n <ion-button class=\"dcf-hidden@m\" shape=\"round\" fill=\"clear\" color=\"primary\" (click)=\"presentActionsMenu($event)\">\n <ion-icon slot=\"icon-only\" aria-hidden=\"true\" name=\"ellipsis-vertical-outline\"></ion-icon>\n </ion-button>\n <ion-popover\n #actionMenuComponent\n side=\"bottom\"\n alignment=\"left\"\n\n [isOpen]=\"actionMenuOpen\"\n (didDismiss)=\"actionMenuOpen = false\">\n <ng-template>\n <ion-content class=\"ion-padding\">\n <ion-list lines=\"none\">\n <ion-list-header>\n <h4 class=\"dcf-text-capitalize\" [innerHTML]=\"'actions' | translate\"></h4>\n </ion-list-header>\n @for (operation of ['update', 'delete']; track operation) {\n @if(operations.includes(operation)) {\n <ion-item [button]=\"true\" (click)=\"handleAction(operation, $event, component)\">\n <ion-avatar class=\"dcf-flex dcf-flex-middle\" aria-hidden=\"true\" slot=\"start\">\n @if(operation === 'update') {\n <ion-icon color=\"primary\" aria-hidden=\"true\" name=\"create-outline\"></ion-icon>\n } @else {\n <ion-icon color=\"danger\" aria-hidden=\"true\" name=\"trash\"></ion-icon>\n }\n </ion-avatar>\n <ion-label class=\"dcf-text-capitalize\">{{ operation | translate }}</ion-label>\n </ion-item>\n }\n }\n </ion-list>\n </ion-content>\n </ng-template>\n </ion-popover>\n </div>\n }\n <!-- @if(operations?.length && uid) {\n <div class=\"dcf-visible@m\" id=\"dcf-actions\">\n @if(operations?.includes('update')) {\n <ion-button fill=\"clear\" size=\"small\" color=\"primary\" (click)=\"handleAction('update', component)\">\n <ion-icon aria-hidden=\"true\" slot=\"icon-only\" name=\"create-outline\"></ion-icon>\n </ion-button>\n }\n @if(operations?.includes('delete')) {\n <ion-button fill=\"clear\" size=\"small\" color=\"danger\" (click)=\"handleAction('delete', component)\">\n <ion-icon aria-hidden=\"true\" slot=\"icon-only\" name=\"trash\"></ion-icon>\n </ion-button>\n }\n </div>\n } -->\n @if(windowWidth > 639) {\n <div id=\"end\">\n <ng-content select=\"[slot='end']\"></ng-content>\n </div>\n }\n </div>\n </div>\n </div>\n </ion-item>\n @if(showSlideItems && uid) {\n <ion-item-options side=\"end\" (ionSwipe)=\"operations.length === 1 ? handleAction(operations[0], $event, component) : ''\">\n @if(operations?.includes('update')) {\n <ion-item-option class=\"dcf-update\" (click)=\"handleAction('update', $event, component)\" [expandable]=\"operations.length === 1\">\n <ion-icon aria-hidden=\"true\" slot=\"icon-only\" name=\"create-outline\"></ion-icon>\n </ion-item-option>\n }\n @if(operations?.includes('delete')) {\n <ion-item-option class=\"dcf- delete\" (click)=\"handleAction('delete', $event, component)\" [expandable]=\"operations.length === 1\">\n <ion-icon aria-hidden=\"true\" slot=\"icon-only\" name=\"trash\"></ion-icon>\n </ion-item-option>\n }\n </ion-item-options>\n }\n </ion-item-sliding>\n}\n", styles: ["ion-item{--min-height: 50px;--padding-top: .25rem;--padding-bottom: .25rem;--padding-start: .75rem;--padding-end: .75rem;--inner-padding-start: 0px !important;--inner-padding-end: 0px !important;--background-hover: var(--dcf-color-gray-8);--background-focused: var(--dcf-color-gray-8)}@media (prefers-color-scheme: dark){ion-item{--background-hover-opacity: .25;--background-focused-opacity: .25}}@media (prefers-color-scheme: light){ion-item{--background-hover-opacity: .1;--background-focused-opacity: .1}}ion-item.item-lines-full{--padding-top: .5rem;--padding-bottom: .5rem;--padding-start: .25rem;-padding-end:.25rem;padding:0 .65rem}ion-item.item-lines-inset{--padding-top: 0rem !important;--padding-bottom: 0rem !important;--inner-padding-top: .5rem !important;--inner-padding-bottom: .65rem !important}@media (prefers-color-scheme: light){ion-item{--border-color: var(--dcf-color-gray-2)}ion-item .dcf-info{color:var(--dcf-color-gray-6)}ion-item .dcf-item-title{color:var(--dcf-color-gray-8)}ion-item .dcf-description{color:var(--dcf-color-gray-6)}}@media (prefers-color-scheme: dark){ion-item{--border-color: var(--dcf-color-gray-6)}ion-item .dcf-description{color:var(--dcf-color-gray-4)}}ion-item .dcf-info{min-width:10vw;background:transparent!important}ion-item .dcf-grid{padding:0!important;margin:0!important;min-width:100%!important}ion-item .dcf-item-title{font-style:normal;font-weight:700}ion-item .dcf-description{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-style:normal;font-weight:400;font-size:.925rem}ion-item::part(native){min-width:100%}ion-item [slot=start]{margin-right:.5rem!important}ion-item [slot=end]{margin-left:.5rem!important}ion-item .dcf-info{font-size:.9rem}ion-item .dcf-info .dcf-subinfo.dcf-line{margin-left:.5rem}@media (min-width: var(--dcf-width-sm)){ion-item .dcf-info .dcf-subinfo.dcf-line{display:block;margin-left:0}}ion-item #dcf-actions{padding:5px}@media (max-width: var(--dcf-width-m)){ion-item #dcf-actions{display:none;pointer-events:none!important;cursor:text!important}ion-item #dcf-actions *{display:none;pointer-events:none!important;cursor:text!important}}ion-item #dcf-actions ion-button{--padding-start: 1rem;--padding-end: .75rem;--padding-top: .85rem !important;--padding-bottom: .85rem !important;color:#ccc;margin-right:.5rem!important;--background: var(--dcf-color-gray-2) !important}ion-item #dcf-actions ion-button ion-icon{position:relative;left:-1px}@media (max-width: var(--dcf-width-m)){ion-item #dcf-end,ion-item [slot=end]{display:none!important}}ion-item #dcf-end{padding-top:5px;display:flex;align-items:flex-end}ion-item .dcf-icon{display:flex;justify-content:center;align-items:center;text-align:center;margin-right:.5rem!important}ion-item .dcf-icon.dcf-grid-icon{min-width:50px;text-align:left;display:flex;justify-content:flex-start}@media (max-width: var(--dcf-width-s)){ion-item .dcf-icon{align-items:flex-start!important}}@media (prefers-color-scheme: light){ion-item .dcf-icon ion-button{color:var(--dcf-color-gray-7);--background: var(--dcf-color-gray-1) !important}}@media (prefers-color-scheme: dark){ion-item .dcf-icon ion-button{color:var(--dcf-color-gray-1)!important;--background: var(--dcf-color-gray-7) !important}}ion-item .dcf-icon ion-button ion-icon{font-size:20px}ion-item .dcf-icon ion-avatar{width:48px;height:48px;display:flex;justify-content:center;align-items:center;text-align:center}@media (prefers-color-scheme: light){ion-item .dcf-icon ion-avatar{color:var(--dcf-color-gray-7);background:var(--dcf-color-gray-1)!important}}@media (prefers-color-scheme: dark){ion-item .dcf-icon ion-avatar{color:var(--dcf-color-gray-1)!important;background:var(--dcf-background-color)!important}}ion-item .dcf-icon ion-avatar ion-icon{font-size:20px}ion-item .dcf-icon ion-avatar .dcf-icon-large{transform:translateY(5px)}ion-item-sliding{box-sizing:border-box}@media (prefers-color-scheme: light){ion-item-sliding ion-item-option:not(.dcf-delete),ion-item-sliding ion-item-option:not(.dcf-update){background:rgba(var(--dcf-color-dark-rgb),.25)!important}ion-item-sliding ion-item-option:not(.dcf-delete) .dcf-ti,ion-item-sliding ion-item-option:not(.dcf-delete) ion-icon,ion-item-sliding ion-item-option:not(.dcf-update) .dcf-ti,ion-item-sliding ion-item-option:not(.dcf-update) ion-icon{color:var(--dcf-color-gray-7)!important}ion-item-sliding ion-item-option.dcf-delete{background:rgba(var(--dcf-color-danger-rgb),.05)!important}ion-item-sliding ion-item-option.dcf-delete .dcf-ti,ion-item-sliding ion-item-option.dcf-delete *,ion-item-sliding ion-item-option.dcf-delete ion-icon{color:var(--dcf-color-danger)!important}ion-item-sliding ion-item-option.dcf-update{background:rgba(var(--dcf-color-primary-rgb),.05)!important}ion-item-sliding ion-item-option.dcf-update .dcf-ti,ion-item-sliding ion-item-option.dcf-update ion-icon{color:var(--dcf-color-primary)!important}}@media (prefers-color-scheme: dark){ion-item-sliding ion-item-option:not(.dcf-delete),ion-item-sliding ion-item-option:not(.dcf-update){background:rgba(var(--dcf-color-dark-rgb),1)!important}ion-item-sliding ion-item-option:not(.dcf-delete) .dcf-ti,ion-item-sliding ion-item-option:not(.dcf-delete) ion-icon,ion-item-sliding ion-item-option:not(.dcf-update) .dcf-ti,ion-item-sliding ion-item-option:not(.dcf-update) ion-icon{color:var(--dcf-color-gray-2)!important}ion-item-sliding ion-item-option.dcf-delete{background:rgba(var(--dcf-color-danger-rgb),.05)!important}ion-item-sliding ion-item-option.dcf-delete .dcf-ti,ion-item-sliding ion-item-option.dcf-delete *,ion-item-sliding ion-item-option.dcf-delete ion-icon{color:var(--dcf-color-danger)!important}ion-item-sliding ion-item-option.dcf-update{background:rgba(var(--dcf-color-primary-rgb),.05)!important}ion-item-sliding ion-item-option.dcf-update .dcf-ti,ion-item-sliding ion-item-option.dcf-update ion-icon{color:var(--dcf-color-gray-2)!important}}ion-item-sliding[class*=active-slide]{border-color:var(--dcf-color-gray-3)}ion-item-sliding ion-item-option{color:var(--dcf-color-gray-5);box-shadow:inset 0 0 5px rgba(var(--dcf-color-dark-rgb),.15)!important;background:var(--dcf-color-gray-3)}\n"] }]
6870
- }], ctorParameters: () => [], propDecorators: { actionMenuComponent: [{
6871
- type: ViewChild,
6872
- args: ['actionMenuComponent']
6873
- }], lines: [{
6874
- type: Input
6875
- }], item: [{
6876
- type: Input
6877
- }], icon: [{
6878
- type: Input
6879
- }], iconSlot: [{
6880
- type: Input
6881
- }], button: [{
6882
- type: Input
6883
- }], title: [{
6884
- type: Input
6885
- }], description: [{
6886
- type: Input
6887
- }], info: [{
6888
- type: Input
6889
- }], subinfo: [{
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: [{
6890
6806
  type: Input
6891
6807
  }], clickEvent: [{
6892
6808
  type: Output
6893
- }], enableSlideItems: [{
6894
- type: HostListener,
6895
- args: ['window:resize', ['$event']]
6896
6809
  }] } });
6897
6810
 
6898
6811
  /**
6899
- * @description A pagination component for navigating through multiple pages of content.
6900
- * @summary This component provides a user interface for paginated content navigation,
6901
- * displaying page numbers and navigation controls. It supports customizable page counts,
6902
- * current page tracking, and emits events when users navigate between pages.
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.
6903
6816
  *
6904
- * The component intelligently handles large numbers of pages by showing a subset of page
6905
- * numbers with ellipses to indicate skipped pages, ensuring the UI remains clean and usable
6906
- * even with many pages.
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
6907
6827
  *
6908
6828
  * @mermaid
6909
6829
  * sequenceDiagram
6910
6830
  * participant U as User
6911
- * participant P as PaginationComponent
6912
- * participant E as External Component
6831
+ * participant L as ListComponent
6832
+ * participant D as Data Source
6833
+ * participant E as External Components
6913
6834
  *
6914
- * U->>P: Click page number
6915
- * P->>P: navigate(page)
6916
- * P->>P: handleClick(direction, page)
6917
- * 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
6918
6840
  *
6919
- * U->>P: Click next button
6920
- * P->>P: next()
6921
- * P->>P: handleClick('next')
6922
- * 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
6923
6853
  *
6924
- * U->>P: Click previous button
6925
- * P->>P: previous()
6926
- * P->>P: handleClick('previous')
6927
- * 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
6928
6867
  *
6929
6868
  * @example
6930
- * <ngx-decaf-pagination
6931
- * [pages]="10"
6932
- * [current]="3"
6933
- * (clickEvent)="handlePageChange($event)">
6934
- * </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>
6935
6877
  *
6936
6878
  * @extends {NgxBaseComponent}
6937
6879
  * @implements {OnInit}
6938
6880
  */
6939
- class PaginationComponent extends NgxBaseComponent {
6881
+ let ListComponent = class ListComponent extends NgxBaseComponent {
6940
6882
  /**
6941
- * @constructor
6942
- * @description Initializes a new instance of the PaginationComponent.
6943
- * Calls the parent constructor with the component name for generate base locale string.
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
6944
6895
  */
6945
6896
  constructor() {
6946
- 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;
6947
6909
  /**
6948
6910
  * @description Controls whether the component uses translation services.
6949
6911
  * @summary When set to true, the component will attempt to use translation services
6950
- * for any text content. This allows for internationalization of the pagination component.
6912
+ * for any text content. This allows for internationalization of the list component.
6951
6913
  *
6952
6914
  * @type {StringOrBoolean}
6953
6915
  * @default true
6954
- * @memberOf PaginationComponent
6916
+ * @memberOf ListComponent
6955
6917
  */
6956
6918
  this.translatable = true;
6957
6919
  /**
6958
- * @description The currently active page number.
6959
- * @summary Specifies which page is currently active or selected. This value is used
6960
- * to highlight the current page in the UI and as a reference point for navigation.
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.
6961
6945
  *
6962
6946
  * @type {number}
6963
- * @default 1
6964
- * @memberOf PaginationComponent
6947
+ * @default 0
6948
+ * @memberOf ListComponent
6965
6949
  */
6966
- this.current = 1;
6950
+ this.start = 0;
6967
6951
  /**
6968
- * @description Event emitter for pagination navigation events.
6969
- * @summary Emits a custom event when users navigate between pages, either by clicking
6970
- * on page numbers or using the next/previous buttons. The event contains information
6971
- * about the navigation direction and the target page number.
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.
6972
6955
  *
6973
- * @type {EventEmitter<PaginationCustomEvent>}
6974
- * @memberOf PaginationComponent
6975
- */
6976
- this.clickEvent = new EventEmitter();
6977
- addIcons({ chevronBackOutline, chevronForwardOutline });
6978
- }
6979
- /**
6980
- * @description Initializes the component after Angular sets the input properties.
6981
- * @summary Sets up the component by initializing the locale settings based on the
6982
- * translatable property, generating the page numbers based on the total pages and
6983
- * current page, and storing the last page number for boundary checking.
6984
- *
6985
- * @mermaid
6986
- * sequenceDiagram
6987
- * participant A as Angular Lifecycle
6988
- * participant P as PaginationComponent
6989
- *
6990
- * A->>P: ngOnInit()
6991
- * P->>P: getLocale(translatable)
6992
- * P->>P: Set locale
6993
- * P->>P: getPages(data, current)
6994
- * P->>P: Set pages array
6995
- * P->>P: Set last page number
6996
- *
6997
- * @returns {void}
6998
- * @memberOf PaginationComponent
6999
- */
7000
- ngOnInit() {
7001
- this.locale = this.getLocale(this.translatable);
7002
- this.pages = this.getPages(this.totalPages, this.current);
7003
- this.last = this.totalPages;
7004
- }
7005
- /**
7006
- * @description Handles click events on pagination controls.
7007
- * @summary Processes user interactions with the pagination component, updating the
7008
- * current page if specified and emitting an event with navigation details. This method
7009
- * is called when users click on page numbers or navigation buttons.
7010
- *
7011
- * @param {('next' | 'previous')} direction - The direction of navigation
7012
- * @param {number} [page] - Optional page number to navigate to directly
7013
- * @returns {void}
7014
- *
7015
- * @mermaid
7016
- * sequenceDiagram
7017
- * participant U as User
7018
- * participant P as PaginationComponent
7019
- * participant E as External Component
7020
- *
7021
- * U->>P: Click pagination control
7022
- * P->>P: handleClick(direction, page?)
7023
- * alt page is provided
7024
- * P->>P: Update current page
7025
- * end
7026
- * P->>E: Emit clickEvent with direction and page
7027
- *
7028
- * @memberOf PaginationComponent
7029
- */
7030
- handleClick(direction, page) {
7031
- if (page)
7032
- this.current = page;
7033
- this.clickEvent.emit({
7034
- name: EventConstants.CLICK,
7035
- data: {
7036
- direction,
7037
- page: this.current
7038
- },
7039
- component: this.componentName
7040
- });
7041
- }
7042
- /**
7043
- * @description Generates the array of page objects for display.
7044
- * @summary Creates an array of page objects based on the total number of pages and
7045
- * the current page. For small page counts (≤5), all pages are shown. For larger page
7046
- * counts, a subset is shown with ellipses to indicate skipped pages. This ensures
7047
- * the pagination UI remains clean and usable even with many pages.
7048
- *
7049
- * @param {number} total - The total number of pages
7050
- * @param {number} [current] - The current active page (defaults to this.current)
7051
- * @returns {KeyValue[]} Array of page objects with index and text properties
7052
- *
7053
- * @mermaid
7054
- * flowchart TD
7055
- * A[Start] --> B{total <= 5?}
7056
- * B -->|Yes| C[Show all pages]
7057
- * B -->|No| D[Show first page]
7058
- * D --> E[Show last pages]
7059
- * E --> F[Add ellipses for skipped pages]
7060
- * C --> G[Return pages array]
7061
- * F --> G
7062
- *
7063
- * @memberOf PaginationComponent
7064
- */
7065
- getPages(total, current) {
7066
- if (!current)
7067
- current = this.current;
7068
- const pages = [];
7069
- function getPage(index, text = '', clazz = 'button') {
7070
- if (pages.some(item => item['index'] === index))
7071
- return;
7072
- pages.push({ index, text: index != null ? index.toString().padStart(2, '0') : text, class: clazz });
7073
- }
7074
- if (total <= 5) {
7075
- for (let i = 1; i <= total; i++)
7076
- getPage(i);
7077
- }
7078
- else {
7079
- // Adiciona os dois primeiros
7080
- getPage(1);
7081
- getPage(2);
7082
- // Adiciona "..." entre os blocos
7083
- if (current && current > 3)
7084
- getPage(null, '...');
7085
- // Adiciona a página atual (se estiver no meio)
7086
- if (current && current > 2 && current < total - 1)
7087
- getPage(current);
7088
- // Adiciona "..." entre os blocos
7089
- if (current && current < total - 2)
7090
- getPage(null, '...', 'separator');
7091
- // Adiciona os dois últimos
7092
- getPage(total - 1);
7093
- getPage(total);
7094
- }
7095
- return pages;
7096
- }
7097
- /**
7098
- * @description Gets the current active page number.
7099
- * @summary Returns the current page number that is active in the pagination component.
7100
- * This method provides a way to access the current page state from outside the component.
7101
- *
7102
- * @returns {number} The current page number
7103
- * @memberOf PaginationComponent
7104
- */
7105
- getCurrent() {
7106
- return this.current;
7107
- }
7108
- /**
7109
- * @description Navigates to the next page.
7110
- * @summary Increments the current page number if not at the last page and triggers
7111
- * the click event handler with 'next' direction. This method is typically called
7112
- * when the user clicks on the "next" button in the pagination UI.
7113
- *
7114
- * @returns {void}
7115
- *
7116
- * @mermaid
7117
- * sequenceDiagram
7118
- * participant U as User
7119
- * participant P as PaginationComponent
7120
- *
7121
- * U->>P: Click next button
7122
- * P->>P: next()
7123
- * alt page <= max pages
7124
- * P->>P: Increment current page
7125
- * P->>P: handleClick('next')
7126
- * end
7127
- *
7128
- * @memberOf PaginationComponent
7129
- */
7130
- next() {
7131
- const page = this.current + 1;
7132
- if (page <= Object.keys(this.pages)?.length || 0) {
7133
- this.current = page;
7134
- this.handleClick('next');
7135
- }
7136
- }
7137
- /**
7138
- * @description Navigates to the previous page.
7139
- * @summary Decrements the current page number if not at the first page and triggers
7140
- * the click event handler with 'previous' direction. This method is typically called
7141
- * when the user clicks on the "previous" button in the pagination UI.
7142
- *
7143
- * @returns {void}
7144
- *
7145
- * @mermaid
7146
- * sequenceDiagram
7147
- * participant U as User
7148
- * participant P as PaginationComponent
7149
- *
7150
- * U->>P: Click previous button
7151
- * P->>P: previous()
7152
- * alt page > 0
7153
- * P->>P: Decrement current page
7154
- * P->>P: handleClick('previous')
7155
- * end
7156
- *
7157
- * @memberOf PaginationComponent
7158
- */
7159
- previous() {
7160
- const page = this.current - 1;
7161
- if (page > 0) {
7162
- this.current = page;
7163
- this.handleClick('previous');
7164
- }
7165
- }
7166
- /**
7167
- * @description Navigates to a specific page number.
7168
- * @summary Updates the current page to the specified page number and triggers
7169
- * the click event handler with the appropriate direction. This method is typically
7170
- * called when the user clicks directly on a page number in the pagination UI.
7171
- *
7172
- * @param {number | null} page - The page number to navigate to
7173
- * @returns {void}
7174
- *
7175
- * @mermaid
7176
- * sequenceDiagram
7177
- * participant U as User
7178
- * participant P as PaginationComponent
7179
- *
7180
- * U->>P: Click page number
7181
- * P->>P: navigate(page)
7182
- * alt page is not null and different from current
7183
- * P->>P: Determine direction (next/previous)
7184
- * P->>P: handleClick(direction, page)
7185
- * end
7186
- *
7187
- * @memberOf PaginationComponent
7188
- */
7189
- navigate(page) {
7190
- if (page !== null && this.current !== page)
7191
- this.handleClick(page > this.current ? 'next' : 'previous', page);
7192
- }
7193
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PaginationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7194
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: PaginationComponent, isStandalone: true, selector: "ngx-decaf-pagination", inputs: { totalPages: "totalPages", current: "current" }, outputs: { clickEvent: "clickEvent" }, usesInheritance: true, ngImport: i0, template: " <div [id]=\"uid\" class=\"dcf-paginator-container dcf-flex dcf-flex-center\">\n <div class=\"dcf-width-1-1\">\n <div class=\"dcf-pagination-resume\" [innerHTML]=\"locale + '.resume' | translate: {value0: current, value1: last}\"></div>\n <div #paginationComponent class=\"dcf-pagination dcf-flex-center\">\n <div\n aria-label=\"previous\"\n tabindex=\"0\"\n (click)=\"previous()\"\n (keydown.enter)=\"previous()\" [class.dcf-disabled]=\"current === 1\">\n <ion-icon name=\"chevron-back-outline\" aria-hidden=\"true\"></ion-icon>\n </div>\n @for(page of pages; track page) {\n <div tabindex=\"0\" [class]=\"page['class']\" (click)=\"navigate(page['index'])\"\n (keydown.enter)=\"navigate(page['index'])\"\n [class.dcf-active]=\"current === page['index']\">\n <span class=\"page-item\">{{ page['text'] }}</span>\n </div>\n }\n <div\n tabindex=\"0\" (click)=\"next()\"\n (keydown.enter)=\"next()\"\n [class.dcf-disabled]=\"current === last\">\n <ion-icon name=\"chevron-forward-outline\" aria-hidden=\"true\"></ion-icon>\n </div>\n </div>\n </div>\n</div>\n", styles: [".dcf-paginator-container{margin-bottom:1rem}.dcf-pagination{display:flex;flex-wrap:wrap;align-items:center;margin-left:0;padding:0;list-style:none}.dcf-pagination .page-item{display:flex;justify-content:center;align-items:center;text-align:center;font-weight:600;width:34px;line-height:34px;padding:0!important;border-radius:50%;box-sizing:border-box}@media (prefers-color-scheme: dark){.dcf-pagination .page-item{color:var(--dcf-color-gray-3)!important}}@media (prefers-color-scheme: light){.dcf-pagination .page-item{color:var(--dcf-color-gray-7)!important}}.dcf-pagination>*{flex:none;padding-left:0;position:relative;margin:0px .15rem;cursor:pointer}.dcf-pagination>*.dcf-disabled{pointer-events:none;touch-action:none;cursor:text}.dcf-pagination>*.dcf-active{pointer-events:none;touch-action:none}@media (prefers-color-scheme: light){.dcf-pagination>*.dcf-active .page-item{background:rgba(var(--dcf-color-primary-rgb),.15)}.dcf-pagination>*:hover:not(.dcf-active) *{color:var(--dcf-color-primary)!important}}@media (prefers-color-scheme: dark){.dcf-pagination>*.dcf-active .page-item{background:var(--dcf-color-gray-7)}.dcf-pagination>*:hover:not(.dcf-active) *{color:var(--dcf-color-primary)!important}}.dcf-pagination-resume{margin:1rem 0px;text-align:center}@media (prefers-color-scheme: light){.dcf-pagination-resume{color:var(--dcf-color-gray-8)}}\n"], dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }] }); }
7195
- }
7196
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PaginationComponent, decorators: [{
7197
- type: Component,
7198
- args: [{ selector: 'ngx-decaf-pagination', imports: [
7199
- TranslatePipe,
7200
- IonIcon
7201
- ], standalone: true, template: " <div [id]=\"uid\" class=\"dcf-paginator-container dcf-flex dcf-flex-center\">\n <div class=\"dcf-width-1-1\">\n <div class=\"dcf-pagination-resume\" [innerHTML]=\"locale + '.resume' | translate: {value0: current, value1: last}\"></div>\n <div #paginationComponent class=\"dcf-pagination dcf-flex-center\">\n <div\n aria-label=\"previous\"\n tabindex=\"0\"\n (click)=\"previous()\"\n (keydown.enter)=\"previous()\" [class.dcf-disabled]=\"current === 1\">\n <ion-icon name=\"chevron-back-outline\" aria-hidden=\"true\"></ion-icon>\n </div>\n @for(page of pages; track page) {\n <div tabindex=\"0\" [class]=\"page['class']\" (click)=\"navigate(page['index'])\"\n (keydown.enter)=\"navigate(page['index'])\"\n [class.dcf-active]=\"current === page['index']\">\n <span class=\"page-item\">{{ page['text'] }}</span>\n </div>\n }\n <div\n tabindex=\"0\" (click)=\"next()\"\n (keydown.enter)=\"next()\"\n [class.dcf-disabled]=\"current === last\">\n <ion-icon name=\"chevron-forward-outline\" aria-hidden=\"true\"></ion-icon>\n </div>\n </div>\n </div>\n</div>\n", styles: [".dcf-paginator-container{margin-bottom:1rem}.dcf-pagination{display:flex;flex-wrap:wrap;align-items:center;margin-left:0;padding:0;list-style:none}.dcf-pagination .page-item{display:flex;justify-content:center;align-items:center;text-align:center;font-weight:600;width:34px;line-height:34px;padding:0!important;border-radius:50%;box-sizing:border-box}@media (prefers-color-scheme: dark){.dcf-pagination .page-item{color:var(--dcf-color-gray-3)!important}}@media (prefers-color-scheme: light){.dcf-pagination .page-item{color:var(--dcf-color-gray-7)!important}}.dcf-pagination>*{flex:none;padding-left:0;position:relative;margin:0px .15rem;cursor:pointer}.dcf-pagination>*.dcf-disabled{pointer-events:none;touch-action:none;cursor:text}.dcf-pagination>*.dcf-active{pointer-events:none;touch-action:none}@media (prefers-color-scheme: light){.dcf-pagination>*.dcf-active .page-item{background:rgba(var(--dcf-color-primary-rgb),.15)}.dcf-pagination>*:hover:not(.dcf-active) *{color:var(--dcf-color-primary)!important}}@media (prefers-color-scheme: dark){.dcf-pagination>*.dcf-active .page-item{background:var(--dcf-color-gray-7)}.dcf-pagination>*:hover:not(.dcf-active) *{color:var(--dcf-color-primary)!important}}.dcf-pagination-resume{margin:1rem 0px;text-align:center}@media (prefers-color-scheme: light){.dcf-pagination-resume{color:var(--dcf-color-gray-8)}}\n"] }]
7202
- }], ctorParameters: () => [], propDecorators: { totalPages: [{
7203
- type: Input,
7204
- args: [{ required: true }]
7205
- }], current: [{
7206
- type: Input
7207
- }], clickEvent: [{
7208
- type: Output
7209
- }] } });
7210
-
7211
- /**
7212
- * @description A versatile list component that supports various data display modes.
7213
- * @summary This component provides a flexible way to display lists of data with support
7214
- * for infinite scrolling, pagination, searching, and custom item rendering. It can fetch
7215
- * data from various sources including models, functions, or direct data input.
7216
- *
7217
- * The component supports two main display types:
7218
- * 1. Infinite scrolling - Loads more data as the user scrolls
7219
- * 2. Pagination - Displays data in pages with navigation controls
7220
- *
7221
- * Additional features include:
7222
- * - Pull-to-refresh functionality
7223
- * - Search filtering
7224
- * - Empty state customization
7225
- * - Custom item rendering
7226
- * - Event emission for interactions
7227
- *
7228
- * @mermaid
7229
- * sequenceDiagram
7230
- * participant U as User
7231
- * participant L as ListComponent
7232
- * participant D as Data Source
7233
- * participant E as External Components
7234
- *
7235
- * U->>L: Initialize component
7236
- * L->>L: ngOnInit()
7237
- * L->>D: Request initial data
7238
- * D-->>L: Return data
7239
- * L->>L: Process and display data
7240
- *
7241
- * alt User scrolls (Infinite mode)
7242
- * U->>L: Scroll to bottom
7243
- * L->>D: Request more data
7244
- * D-->>L: Return additional data
7245
- * L->>L: Append to existing data
7246
- * else User changes page (Paginated mode)
7247
- * U->>L: Click page number
7248
- * L->>L: handlePaginate()
7249
- * L->>D: Request data for page
7250
- * D-->>L: Return page data
7251
- * L->>L: Replace displayed data
7252
- * end
7253
- *
7254
- * alt User searches
7255
- * U->>L: Enter search term
7256
- * L->>L: handleSearch()
7257
- * L->>D: Filter data by search term
7258
- * D-->>L: Return filtered data
7259
- * L->>L: Update displayed data
7260
- * end
7261
- *
7262
- * alt User clicks item
7263
- * U->>L: Click list item
7264
- * L->>L: handleClick()
7265
- * L->>E: Emit clickEvent
7266
- * end
7267
- *
7268
- * @example
7269
- * <ngx-decaf-list
7270
- * [source]="dataSource"
7271
- * [limit]="10"
7272
- * [type]="'infinite'"
7273
- * [showSearchbar]="true"
7274
- * (clickEvent)="handleItemClick($event)"
7275
- * (refreshEvent)="handleRefresh($event)">
7276
- * </ngx-decaf-list>
7277
- *
7278
- * @extends {NgxBaseComponent}
7279
- * @implements {OnInit}
7280
- */
7281
- let ListComponent = class ListComponent extends NgxBaseComponent {
7282
- /**
7283
- * @description Initializes a new instance of the ListComponent.
7284
- * @summary Creates a new ListComponent and sets up the base component with the appropriate
7285
- * component name. This constructor is called when Angular instantiates the component and
7286
- * before any input properties are set. It passes the component name to the parent class
7287
- * constructor to enable proper localization and component identification.
7288
- *
7289
- * The constructor is intentionally minimal, with most initialization logic deferred to
7290
- * the ngOnInit lifecycle hook. This follows Angular best practices by keeping the constructor
7291
- * focused on dependency injection and basic setup, while complex initialization that depends
7292
- * on input properties is handled in ngOnInit.
7293
- *
7294
- * @memberOf ListComponent
7295
- */
7296
- constructor() {
7297
- super("ListComponent");
7298
- /**
7299
- * @description The display mode for the list component.
7300
- * @summary Determines how the list data is loaded and displayed. Options include:
7301
- * - INFINITE: Loads more data as the user scrolls (infinite scrolling)
7302
- * - PAGINATED: Displays data in pages with navigation controls
7303
- *
7304
- * @type {ListComponentsTypes}
7305
- * @default ListComponentsTypes.INFINITE
7306
- * @memberOf ListComponent
7307
- */
7308
- this.type = ListComponentsTypes.INFINITE;
7309
- /**
7310
- * @description Controls whether the component uses translation services.
7311
- * @summary When set to true, the component will attempt to use translation services
7312
- * for any text content. This allows for internationalization of the list component.
7313
- *
7314
- * @type {StringOrBoolean}
7315
- * @default true
7316
- * @memberOf ListComponent
7317
- */
7318
- this.translatable = true;
7319
- /**
7320
- * @description Controls the visibility of the search bar.
7321
- * @summary When set to true, displays a search bar at the top of the list that allows
7322
- * users to filter the list items. The search functionality works by filtering the
7323
- * existing data or by triggering a new data fetch with search parameters.
7324
- *
7325
- * @type {StringOrBoolean}
7326
- * @default true
7327
- * @memberOf ListComponent
7328
- */
7329
- this.showSearchbar = true;
7330
- /**
7331
- * @description Direct data input for the list component.
7332
- * @summary Provides a way to directly pass data to the list component instead of
7333
- * fetching it from a source. When both data and source are provided, the component
7334
- * will use the source to fetch data only if the data array is empty.
7335
- *
7336
- * @type {KeyValue[] | undefined}
7337
- * @default undefined
7338
- * @memberOf ListComponent
7339
- */
7340
- this.data = undefined;
7341
- /**
7342
- * @description The starting index for data fetching.
7343
- * @summary Specifies the index from which to start fetching data. This is used
7344
- * for pagination and infinite scrolling to determine which subset of data to load.
7345
- *
7346
- * @type {number}
7347
- * @default 0
7348
- * @memberOf ListComponent
7349
- */
7350
- this.start = 0;
7351
- /**
7352
- * @description The number of items to fetch per page or load operation.
7353
- * @summary Determines how many items are loaded at once during pagination or
7354
- * infinite scrolling. This affects the size of data chunks requested from the source.
7355
- *
7356
- * @type {number}
7357
- * @default 10
7358
- * @memberOf ListComponent
6956
+ * @type {number}
6957
+ * @default 10
6958
+ * @memberOf ListComponent
7359
6959
  */
7360
6960
  this.limit = 10;
7361
6961
  /**
@@ -7588,842 +7188,1221 @@ let ListComponent = class ListComponent extends NgxBaseComponent {
7588
7188
  */
7589
7189
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
7590
7190
  this.observerSubjet = new Subject();
7591
- /**
7592
- * @description Observer object for repository change notifications.
7593
- * @summary Implements the Observer interface to receive notifications when the
7594
- * underlying data repository changes. This enables automatic list updates when
7595
- * data is created, updated, or deleted through the repository.
7596
- *
7597
- * @private
7598
- * @type {Observer}
7599
- * @memberOf ListComponent
7600
- */
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() {
7601
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);
7602
7380
  }
7603
7381
  /**
7604
- * @description Initializes the component after Angular sets the input properties.
7605
- * @summary Sets up the component by initializing event subscriptions, processing boolean
7606
- * inputs, and loading the initial data. This method prepares the component for user
7607
- * interaction by ensuring all properties are properly initialized and data is loaded.
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.
7608
7386
  *
7387
+ * @param {string | undefined} value - The search term or undefined to clear search
7609
7388
  * @returns {Promise<void>}
7610
7389
  *
7611
7390
  * @mermaid
7612
- * sequenceDiagram
7613
- * participant A as Angular Lifecycle
7614
- * participant L as ListComponent
7615
- * 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
7616
7402
  *
7617
- * A->>L: ngOnInit()
7618
- * L->>L: Set up click event debouncing
7619
- * L->>L: Process boolean inputs
7620
- * L->>L: Configure component based on inputs
7621
- * L->>L: refresh()
7622
- * L->>D: Request initial data
7623
- * D-->>L: Return data
7624
- * L->>L: Process and display data
7625
- * L->>L: Configure empty state if needed
7626
- * L->>L: initialize()
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.
7627
7428
  *
7429
+ * @param {IFilterQuery | undefined} value - The filter query object or undefined to clear filters
7430
+ * @returns {Promise<void>}
7628
7431
  * @memberOf ListComponent
7629
7432
  */
7630
- async ngOnInit() {
7631
- this.clickItemSubject.pipe(debounceTime(100)).subscribe(event => this.clickEventEmit(event));
7632
- this.observerSubjet.pipe(debounceTime(100)).subscribe(args => this.handleObserveEvent(args[0], args[1], args[2]));
7633
- this.enableFilter = stringToBoolean(this.enableFilter);
7634
- this.limit = Number(this.limit);
7635
- this.start = Number(this.start);
7636
- this.inset = stringToBoolean(this.inset);
7637
- this.showRefresher = stringToBoolean(this.showRefresher);
7638
- this.loadMoreData = stringToBoolean(this.loadMoreData);
7639
- this.showSearchbar = stringToBoolean(this.showSearchbar);
7640
- this.disableSort = stringToBoolean(this.disableSort);
7641
- if (typeof this.item?.['tag'] === 'boolean' && this.item?.['tag'] === true)
7642
- this.item['tag'] = ComponentsTagNames.LIST_ITEM;
7643
- await this.refresh();
7644
- if (this.operations.includes(OperationKeys.CREATE) && this.route)
7645
- this.empty.link = `${this.route}/${OperationKeys.CREATE}`;
7646
- await this.initialize();
7647
- if (this.model instanceof Model && this._repository)
7648
- this._repository.observe(this.observer);
7433
+ async handleFilter(value) {
7434
+ await this.handleSearch(value);
7649
7435
  }
7650
7436
  /**
7651
- * @description Cleans up resources when the component is destroyed.
7652
- * @summary Performs cleanup operations when the component is being removed from the DOM.
7653
- * This includes clearing references to models and data to prevent memory leaks.
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.
7440
+ *
7441
+ * @returns {Promise<void>}
7442
+ * @memberOf ListComponent
7443
+ */
7444
+ async clearSearch() {
7445
+ await this.handleSearch(undefined);
7446
+ }
7447
+ /**
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.
7654
7451
  *
7452
+ * @param {KeyValue[]} [data] - Optional data to include in the event
7655
7453
  * @returns {void}
7454
+ *
7656
7455
  * @memberOf ListComponent
7657
7456
  */
7658
- ngOnDestroy() {
7659
- if (this._repository)
7660
- this._repository.unObserve(this.observer);
7661
- 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
+ });
7662
7466
  }
7663
7467
  /**
7664
- * @description Handles repository observation events with debouncing.
7665
- * @summary Processes repository change notifications and routes them appropriately.
7666
- * For CREATE events with a UID, handles them immediately. For other events,
7667
- * passes them to the debounced observer subject to prevent excessive updates.
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}
7668
7475
  *
7669
- * @param {...unknown[]} args - The repository event arguments including table, event type, and UID
7670
- * @returns {Promise<void>}
7671
7476
  * @memberOf ListComponent
7672
7477
  */
7673
- async observeRepository(...args) {
7674
- const [table, event, uid] = args;
7675
- if (event === OperationKeys.CREATE && !!uid)
7676
- return this.handleObserveEvent(table, event, uid);
7677
- return this.observerSubjet.next(args);
7478
+ clickEventEmit(event) {
7479
+ this.clickEvent.emit(event);
7678
7480
  }
7679
7481
  /**
7680
- * @description Handles specific repository events and updates the list accordingly.
7681
- * @summary Processes repository change events (CREATE, UPDATE, DELETE) and performs
7682
- * the appropriate list operations. This includes adding new items, updating existing
7683
- * ones, or removing deleted items from the list display.
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
7684
7529
  *
7685
- * @param {string} table - The table/model name that changed
7686
- * @param {OperationKeys} event - The type of operation (CREATE, UPDATE, DELETE)
7687
- * @param {string | number} uid - The unique identifier of the affected item
7688
- * @returns {Promise<void>}
7689
7530
  * @memberOf ListComponent
7690
7531
  */
7691
- async handleObserveEvent(table, event, uid) {
7692
- if (event === OperationKeys.CREATE) {
7693
- if (uid) {
7694
- 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;
7695
7550
  }
7696
7551
  else {
7697
- 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);
7698
7558
  }
7699
7559
  }
7700
7560
  else {
7701
- if (event === OperationKeys.UPDATE)
7702
- await this.handleUpdate(uid);
7703
- if (event === OperationKeys.DELETE)
7704
- this.handleDelete(uid);
7705
- this.refreshEventEmit();
7561
+ setTimeout(() => {
7562
+ this.refreshing = false;
7563
+ }, 200);
7706
7564
  }
7707
7565
  }
7708
7566
  /**
7709
- * @description Function for tracking items in the list.
7710
- * @summary Provides a tracking function for the `*ngFor` directive in the component template.
7711
- * This function is used to identify and control the rendering of items in the list,
7712
- * preventing duplicate or unnecessary rendering.
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);
7581
+ }
7582
+ /**
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.
7713
7587
  *
7714
- * The `trackItemFn` function takes two parameters: `index` (the index of the item in the list)
7715
- * and `item` (the actual item from the list). It returns the tracking key, which in this case
7716
- * is the union of the `uid` of the item with the model name.
7588
+ * @param {InfiniteScrollCustomEvent | CustomEvent} [event] - The refresh event
7589
+ * @returns {Promise<void>} A promise that resolves when the refresh operation is complete
7717
7590
  *
7718
- * @param {number} index - The index of the item in the list.
7719
-
7720
- * @param {KeyValue | string | number} item - The actual item from the list.
7721
- * @returns {string | number} The tracking key for the item.
7722
7591
  * @memberOf ListComponent
7723
7592
  */
7724
- trackItemFn(index, item) {
7725
- return `${item?.['uid'] || item?.[this.pk]}-${index}`;
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);
7726
7600
  }
7727
7601
  /**
7728
- * Handles the create event from the repository.
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.
7729
7606
  *
7730
- * @param {string | number} uid - The ID of the item to create.
7731
- * @returns {Promise<void>} A promise that resolves when the item is created and added to the list.
7732
- */
7733
- async handleCreate(uid) {
7734
- const result = await this._repository?.read(uid);
7735
- const item = this.mapResults([result])[0];
7736
- this.items = this.data = [item, ...this.items || []];
7737
- }
7738
- /**
7739
- * @description Handles the update event from the repository.
7740
- * @summary Updates the list item with the specified ID based on the new data.
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
7741
7610
  *
7742
- * @param {string | number} uid - The ID of the item to update
7743
- * @returns {Promise<void>}
7744
- * @private
7745
7611
  * @memberOf ListComponent
7746
7612
  */
7747
- async handleUpdate(uid) {
7748
- const item = this.itemMapper(await this._repository?.read(uid) || {}, this.mapper);
7749
- this.data = [];
7750
- for (const key in this.items) {
7751
- const child = this.items[key];
7752
- if (child['uid'] === item['uid']) {
7753
- this.items[key] = Object.assign({}, child, item);
7754
- break;
7755
- }
7756
- }
7757
- setTimeout(() => {
7758
- this.data = [...this.items];
7759
- }, 0);
7613
+ parseSearchResults(results, search) {
7614
+ return results.filter((item) => Object.values(item).some(value => value.toString().toLowerCase().includes(search?.toLowerCase())));
7760
7615
  }
7761
7616
  /**
7762
- * @description Removes an item from the list by ID.
7763
- * @summary Filters out an item with the specified ID from the data array and
7764
- * refreshes the list display. This is typically used after a delete operation.
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.
7765
7621
  *
7766
- * @param {string} uid - The ID of the item to delete
7767
- * @param {string} pk - The primary key field name
7768
- * @returns {Promise<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
7769
7626
  *
7770
7627
  * @memberOf ListComponent
7771
7628
  */
7772
- handleDelete(uid, pk) {
7773
- if (!pk)
7774
- pk = this.pk;
7775
- this.items = this.data?.filter((item) => item['uid'] !== uid) || [];
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 || [];
7776
7655
  }
7777
7656
  /**
7778
- * @description Handles click events from list items.
7779
- * @summary Listens for global ListItemClickEvent events and passes them to the
7780
- * debounced click subject. This allows the component to respond to clicks on
7781
- * list items regardless of where they originate from.
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.
7782
7661
  *
7783
- * @param {ListItemCustomEvent | RendererCustomEvent} event - The click event
7784
- * @returns {void}
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
7785
7666
  *
7786
7667
  * @memberOf ListComponent
7787
7668
  */
7788
- handleClick(event) {
7789
- this.clickItemSubject.next(event);
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`);
7701
+ }
7702
+ }
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
+ }
7712
+ }
7713
+ if (this.type === ListComponentsTypes.PAGINATED && this.paginator)
7714
+ this.getMoreData(this.paginator.total);
7715
+ return data || [];
7790
7716
  }
7791
7717
  /**
7792
- * @description Handles search events from the search bar.
7793
- * @summary Processes search queries from the search bar component, updating the
7794
- * displayed data based on the search term. The behavior differs between infinite
7795
- * and paginated modes to provide the best user experience for each mode.
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.
7796
7722
  *
7797
- * @param {string | undefined} value - The search term or undefined to clear search
7798
- * @returns {Promise<void>}
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
7799
7727
  *
7800
- * @mermaid
7801
- * flowchart TD
7802
- * A[Search Event] --> B{Type is Infinite?}
7803
- * B -->|Yes| C[Disable loadMoreData]
7804
- * B -->|No| D[Enable loadMoreData]
7805
- * C --> E{Search value undefined?}
7806
- * E -->|Yes| F[Enable loadMoreData]
7807
- * E -->|No| G[Store search value]
7808
- * D --> G
7809
- * F --> H[Reset page to 1]
7810
- * G --> I[Refresh data]
7811
- * H --> I
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
7812
7733
  *
7734
+ * @param {string | number | IFilterQuery} value - The search value or filter query object
7735
+ * @returns {Condition<Model>} A Condition object for database querying
7813
7736
  * @memberOf ListComponent
7814
7737
  */
7815
- async handleSearch(value) {
7816
- if (this.type === ListComponentsTypes.INFINITE) {
7817
- this.loadMoreData = false;
7818
- if (value === undefined) {
7819
- this.loadMoreData = true;
7820
- this.page = 1;
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);
7821
7753
  }
7822
- this.searchValue = value;
7823
- await this.refresh(true);
7824
7754
  }
7825
7755
  else {
7826
- this.loadMoreData = true;
7827
- this.searchValue = value;
7828
- if (value === undefined)
7829
- this.page = this.lastPage;
7830
- await this.refresh(true);
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;
7831
7791
  }
7792
+ return _condition;
7832
7793
  }
7833
7794
  /**
7834
- * @description Handles filter events from the filter component.
7835
- * @summary Processes filter queries from the filter component and applies them
7836
- * to the list data. This method acts as a bridge between the filter component
7837
- * and the search functionality, converting filter queries into search operations.
7838
- *
7839
- * @param {IFilterQuery | undefined} value - The filter query object or undefined to clear filters
7840
- * @returns {Promise<void>}
7841
- * @memberOf ListComponent
7842
- */
7843
- async handleFilter(value) {
7844
- await this.handleSearch(value);
7845
- }
7846
- /**
7847
- * @description Clears the current search and resets the list.
7848
- * @summary Convenience method that clears the search by calling handleSearch
7849
- * with undefined. This resets the list to show all data without filtering.
7850
- *
7851
- * @returns {Promise<void>}
7852
- * @memberOf ListComponent
7853
- */
7854
- async clearSearch() {
7855
- await this.handleSearch(undefined);
7856
- }
7857
- /**
7858
- * @description Emits a refresh event with the current data.
7859
- * @summary Creates and emits a refresh event containing the current list data.
7860
- * This notifies parent components that the list data has been refreshed.
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.
7861
7799
  *
7862
- * @param {KeyValue[]} [data] - Optional data to include in the event
7863
- * @returns {void}
7800
+ * @protected
7801
+ * @param {KeyValue[] | Paginator} result - The raw query result
7802
+ * @returns {KeyValue[]} The processed array of items
7864
7803
  *
7865
7804
  * @memberOf ListComponent
7866
7805
  */
7867
- refreshEventEmit(data) {
7868
- if (!data)
7869
- data = this.items;
7870
- this.skeletonData = new Array(data?.length || 2);
7871
- this.refreshEvent.emit({
7872
- name: EventConstants.REFRESH,
7873
- data: data || [],
7874
- component: this.componentName
7875
- });
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;
7876
7824
  }
7877
7825
  /**
7878
- * @description Emits a click event for a list item.
7879
- * @summary Processes and emits a click event when a list item is clicked.
7880
- * This extracts the relevant data from the event and passes it to parent components.
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.
7881
7830
  *
7882
- * @private
7883
- * @param {ListItemCustomEvent | RendererCustomEvent} event - The click event
7831
+ * @param {number} length - The total number of items available
7884
7832
  * @returns {void}
7885
7833
  *
7886
7834
  * @memberOf ListComponent
7887
7835
  */
7888
- clickEventEmit(event) {
7889
- this.clickEvent.emit(event);
7890
- }
7891
- /**
7892
- * @description Refreshes the list data from the configured source.
7893
- * @summary This method handles both initial data loading and subsequent refresh operations,
7894
- * including pull-to-refresh and infinite scrolling. It manages the data fetching process,
7895
- * updates the component's state, and handles pagination or infinite scrolling logic based
7896
- * on the component's configuration.
7897
- *
7898
- * The method performs the following steps:
7899
- * 1. Sets the refreshing flag to indicate a data fetch is in progress
7900
- * 2. Calculates the appropriate start and limit values based on pagination settings
7901
- * 3. Fetches data from the appropriate source (model or request)
7902
- * 4. Updates the component's data and emits a refresh event
7903
- * 5. Handles pagination or infinite scrolling state updates
7904
- * 6. Completes any provided event (like InfiniteScrollCustomEvent)
7905
- *
7906
- * @param {InfiniteScrollCustomEvent | RefresherCustomEvent | boolean} event - The event that triggered the refresh,
7907
- * or a boolean flag indicating if this is a forced refresh
7908
- * @returns {Promise<void>} A promise that resolves when the refresh operation is complete
7909
- *
7910
- * @mermaid
7911
- * sequenceDiagram
7912
- * participant L as ListComponent
7913
- * participant D as Data Source
7914
- * participant E as Event System
7915
- *
7916
- * L->>L: refresh(event)
7917
- * L->>L: Set refreshing flag
7918
- * L->>L: Calculate start and limit
7919
- * alt Using model
7920
- * L->>D: getFromModel(force, start, limit)
7921
- * D-->>L: Return data
7922
- * else Using request
7923
- * L->>D: getFromRequest(force, start, limit)
7924
- * D-->>L: Return data
7925
- * end
7926
- * L->>E: refreshEventEmit()
7927
- * alt Infinite scrolling mode
7928
- * L->>L: Check if reached last page
7929
- * alt Last page reached
7930
- * L->>L: Complete scroll event
7931
- * L->>L: Disable loadMoreData
7932
- * else More pages available
7933
- * L->>L: Increment page number
7934
- * L->>L: Complete scroll event after delay
7935
- * end
7936
- * else Paginated mode
7937
- * L->>L: Clear refreshing flag after delay
7938
- * end
7939
- *
7940
- * @memberOf ListComponent
7941
- */
7942
- async refresh(event = false) {
7943
- // if(typeof force !== 'boolean' && force.type === EventConstants.BACK_BUTTON_NAVIGATION) {
7944
- // const {refresh} = (force as CustomEvent).detail;
7945
- // if(!refresh)
7946
- // return false;
7947
- // }
7948
- this.refreshing = true;
7949
- const start = this.page > 1 ? (this.page - 1) * this.limit : this.start;
7950
- const limit = (this.page * (this.limit > 12 ? 12 : this.limit));
7951
- this.data = !this.model ?
7952
- await this.getFromRequest(!!event, start, limit)
7953
- : await this.getFromModel(!!event);
7954
- this.refreshEventEmit();
7836
+ getMoreData(length) {
7955
7837
  if (this.type === ListComponentsTypes.INFINITE) {
7956
- if (this.page === this.pages) {
7957
- if (event?.target)
7958
- event.target.complete();
7838
+ if (this.paginator)
7839
+ length = length * this.limit;
7840
+ if (length <= this.limit) {
7959
7841
  this.loadMoreData = false;
7960
7842
  }
7961
7843
  else {
7962
- this.page += 1;
7963
- this.refreshing = false;
7964
- setTimeout(() => {
7965
- if (event?.target && event?.type !== EventConstants.BACK_BUTTON_NAVIGATION)
7966
- event.target.complete();
7967
- }, 200);
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;
7968
7849
  }
7969
7850
  }
7970
7851
  else {
7971
- setTimeout(() => {
7972
- this.refreshing = false;
7973
- }, 200);
7852
+ this.pages = length;
7853
+ if (this.pages === 1)
7854
+ this.loadMoreData = false;
7974
7855
  }
7975
7856
  }
7976
7857
  /**
7977
- * @description Handles pagination events from the pagination component.
7978
- * @summary Processes pagination events by updating the current page number and
7979
- * refreshing the list data to display the selected page. This method is called
7980
- * when a user interacts with the pagination controls to navigate between pages.
7981
- *
7982
- * @param {PaginationCustomEvent} event - The pagination event containing page information
7983
- * @returns {void}
7984
- *
7985
- * @memberOf ListComponent
7986
- */
7987
- handlePaginate(event) {
7988
- const { page } = event.data;
7989
- this.page = page;
7990
- this.refresh(true);
7991
- }
7992
- /**
7993
- * @description Handles pull-to-refresh events from the refresher component.
7994
- * @summary Processes refresh events triggered by the user pulling down on the list
7995
- * or by programmatic refresh requests. This method refreshes the list data and
7996
- * completes the refresher animation when the data is loaded.
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.
7997
7862
  *
7998
- * @param {InfiniteScrollCustomEvent | CustomEvent} [event] - The refresh event
7999
- * @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
8000
7868
  *
8001
7869
  * @memberOf ListComponent
8002
7870
  */
8003
- async handleRefresh(event) {
8004
- await this.refresh(event || true);
8005
- if (event instanceof CustomEvent)
8006
- setTimeout(() => {
8007
- // Any calls to load data go here
8008
- event.target.complete();
8009
- }, 400);
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
+ }, {});
8010
7897
  }
8011
7898
  /**
8012
- * @description Filters data based on a search string.
8013
- * @summary Processes the current data array to find items that match the provided
8014
- * search string. This uses the arrayQueryByString utility to perform the filtering
8015
- * across all properties of the items.
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.
8016
7903
  *
8017
- * @param {KeyValue[]} results - The array of items to search through
8018
- * @param {string} search - The search string to filter by
8019
- * @returns {KeyValue[]} A promise that resolves to the filtered array of items
7904
+ * @param {KeyValue[]} data - The array of items to map
7905
+ * @returns {KeyValue[]} The array of mapped items
8020
7906
  *
8021
7907
  * @memberOf ListComponent
8022
7908
  */
8023
- parseSearchResults(results, search) {
8024
- 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
+ }, []);
8025
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 {
8026
8056
  /**
8027
- * @description Fetches data from a request source.
8028
- * @summary Retrieves data from the configured source function or URL, processes it,
8029
- * and updates the component's data state. This method handles both initial data loading
8030
- * and subsequent refresh operations when using an external data source rather than a model.
8031
- *
8032
- * @param {boolean} force - Whether to force a refresh even if data already exists
8033
- * @param {number} start - The starting index for pagination
8034
- * @param {number} limit - The maximum number of items to retrieve
8035
- * @returns {Promise<KeyValue[]>} A promise that resolves to the fetched data
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.
8036
8061
  *
8037
- * @memberOf ListComponent
8062
+ * @memberOf ListItemComponent
8038
8063
  */
8039
- async getFromRequest(force = false, start, limit) {
8040
- let request = [];
8041
- if (!this.data?.length || force || this.searchValue?.length || !!this.searchValue) {
8042
- // (self.data as ListItem[]) = [];
8043
- if (!this.searchValue?.length && !this.searchValue) {
8044
- if (!this.source && !this.data?.length) {
8045
- this.logger.info('No data and source passed to infinite list');
8046
- return [];
8047
- }
8048
- if (this.source instanceof Function)
8049
- request = await this.source();
8050
- if (!Array.isArray(request))
8051
- request = request?.['response']?.['data'] || request?.['results'] || [];
8052
- this.data = [...await this.parseResult(request)];
8053
- if (this.data?.length)
8054
- this.items = this.type === ListComponentsTypes.INFINITE ?
8055
- (this.items || []).concat([...this.data.slice(start, limit)]) : [...request.slice(start, limit)];
8056
- }
8057
- else {
8058
- this.data = this.parseSearchResults(this.data, this.searchValue);
8059
- this.items = this.data;
8060
- }
8061
- }
8062
- if (this.loadMoreData && this.type === ListComponentsTypes.PAGINATED)
8063
- this.getMoreData(this.data?.length || 0);
8064
- return this.data || [];
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);
8065
8143
  }
8066
8144
  /**
8067
- * @description Fetches data from a model source.
8068
- * @summary Retrieves data from the configured model using its pagination or find methods,
8069
- * processes it, and updates the component's data state. This method handles both initial
8070
- * data loading and subsequent refresh operations when using a model as the data source.
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.
8071
8150
  *
8072
- * @param {boolean} force - Whether to force a refresh even if data already exists
8073
- * @param {number} start - The starting index for pagination
8074
- * @param {number} limit - The maximum number of items to retrieve
8075
- * @returns {Promise<KeyValue[]>} A promise that resolves to the fetched data
8151
+ * @mermaid
8152
+ * sequenceDiagram
8153
+ * participant A as Angular Lifecycle
8154
+ * participant L as ListItemComponent
8155
+ * participant W as Window
8076
8156
  *
8077
- * @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
8078
8170
  */
8079
- async getFromModel(force = false) {
8080
- let data = [...this.data || []];
8081
- let request = [];
8082
- // getting model repository
8083
- if (!this._repository)
8084
- this._repository = this.repository;
8085
- const repo = this._repository;
8086
- if (!this.data?.length || force || this.searchValue?.length || !!this.searchValue) {
8087
- try {
8088
- if (!this.searchValue?.length && !this.searchValue) {
8089
- this.data = [];
8090
- // const rawQuery = this.parseQuery(self.model as Repository<Model>, start, limit);
8091
- // request = this.parseResult(await (this.model as any)?.paginate(start, limit));
8092
- if (!this.paginator) {
8093
- this.paginator = await repo
8094
- .select()
8095
- .orderBy([this.pk, this.sortDirection])
8096
- .paginate(this.limit);
8097
- }
8098
- request = await this.parseResult(this.paginator);
8099
- }
8100
- else {
8101
- if (!this.indexes)
8102
- this.indexes = (Object.values(this.mapper) || [this.pk]);
8103
- const condition = this.parseConditions(this.searchValue);
8104
- request = await this.parseResult(await repo.query(condition, (this.sortBy || this.pk), this.sortDirection));
8105
- data = [];
8106
- }
8107
- data = this.type === ListComponentsTypes.INFINITE ? [...(data).concat(request)] : [...request];
8108
- }
8109
- catch (error) {
8110
- this.logger.error(error?.message || `Unable to find ${this.model} on registry. Return empty array from component`);
8111
- }
8112
- }
8113
- if (data?.length) {
8114
- if (this.searchValue) {
8115
- this.items = [...data];
8116
- if (this.items?.length <= this.limit)
8117
- this.loadMoreData = false;
8118
- }
8119
- else {
8120
- this.items = [...data];
8121
- }
8122
- }
8123
- if (this.type === ListComponentsTypes.PAGINATED && this.paginator)
8124
- this.getMoreData(this.paginator.total);
8125
- return data || [];
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();
8126
8178
  }
8127
8179
  /**
8128
- * @description Converts search values or filter queries into database conditions.
8129
- * @summary Transforms search input or complex filter queries into Condition objects
8130
- * that can be used for database querying. Handles both simple string/number searches
8131
- * across indexed fields and complex filter queries with multiple criteria.
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.
8132
8185
  *
8133
- * For simple searches (string/number):
8134
- * - Creates conditions that search across all indexed fields
8135
- * - Uses equality for numeric values and regex for string values
8136
- * - Combines conditions with OR logic to search multiple fields
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
8137
8190
  *
8138
- * For complex filter queries:
8139
- * - Processes each filter item with its specific condition type
8140
- * - Supports Equal, Not Equal, Contains, Not Contains, Greater Than, Less Than
8141
- * - Updates sort configuration based on the filter query
8142
- * - Combines multiple filter conditions with OR logic
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
8143
8198
  *
8144
- * @param {string | number | IFilterQuery} value - The search value or filter query object
8145
- * @returns {Condition<Model>} A Condition object for database querying
8146
- * @memberOf ListComponent
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
8147
8214
  */
8148
- parseConditions(value) {
8149
- let _condition;
8150
- if (typeof value === Primitives.STRING || typeof value === Primitives.NUMBER) {
8151
- _condition = Condition.attribute(this.pk).eq(!isNaN(value) ? Number(value) : value);
8152
- for (const index of this.indexes) {
8153
- if (index === this.pk)
8154
- continue;
8155
- let orCondition;
8156
- if (!isNaN(value)) {
8157
- orCondition = Condition.attribute(index).eq(Number(value));
8158
- }
8159
- else {
8160
- orCondition = Condition.attribute(index).regexp(value);
8161
- }
8162
- _condition = _condition.or(orCondition);
8163
- }
8164
- }
8165
- else {
8166
- const { query, sort } = value;
8167
- _condition = Condition.attribute(this.pk).dif('null');
8168
- if (query?.length)
8169
- _condition = undefined;
8170
- (query || []).forEach((item) => {
8171
- const { value, condition, index } = item;
8172
- let val = value;
8173
- if (index === this.pk || !isNaN(val))
8174
- val = Number(val);
8175
- let orCondition;
8176
- switch (condition) {
8177
- case "Equal":
8178
- orCondition = Condition.attribute(index).eq(val);
8179
- break;
8180
- case "Not Equal":
8181
- orCondition = Condition.attribute(index).dif(val);
8182
- break;
8183
- case "Not Contains":
8184
- orCondition = !Condition.attribute(index).regexp(new RegExp(`^(?!.*${val}).*$`));
8185
- break;
8186
- case "Contains":
8187
- orCondition = Condition.attribute(index).regexp(val);
8188
- break;
8189
- case "Greater Than":
8190
- orCondition = Condition.attribute(index).gte(val);
8191
- break;
8192
- case "Less Than":
8193
- orCondition = Condition.attribute(index).lte(val);
8194
- break;
8195
- }
8196
- _condition = (!_condition ?
8197
- orCondition : _condition.and(orCondition));
8198
- });
8199
- this.sortBy = sort?.value || this.pk;
8200
- this.sortDirection = sort?.direction || this.sortDirection;
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);
8201
8225
  }
8202
- return _condition;
8226
+ return await this.redirect(action, (typeof this.uid === 'number' ? `${this.uid}` : this.uid));
8203
8227
  }
8204
8228
  /**
8205
- * @description Processes query results into a standardized format.
8206
- * @summary Handles different result formats from various data sources, extracting
8207
- * pagination information when available and applying any configured data mapping.
8208
- * This ensures consistent data structure regardless of the source.
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.
8209
8234
  *
8210
- * @protected
8211
- * @param {KeyValue[] | Paginator} result - The raw query result
8212
- * @returns {KeyValue[]} The processed array of items
8235
+ * @return {boolean} True if slide items should be shown, false otherwise
8213
8236
  *
8214
- * @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
8215
8255
  */
8216
- async parseResult(result) {
8217
- if (!Array.isArray(result) && ('page' in result && 'total' in result)) {
8218
- const paginator = result;
8219
- try {
8220
- result = await paginator.page(this.page);
8221
- // TODO: Chage for result.total;
8222
- this.getMoreData(paginator.total);
8223
- }
8224
- catch (error) {
8225
- this.logger.info(error?.message || 'Unable to get page from paginator. Return empty array from component');
8226
- result = [];
8227
- }
8228
- }
8229
- else {
8230
- this.getMoreData(result?.length || 0);
8231
- }
8232
- return (Object.keys(this.mapper || {}).length) ?
8233
- this.mapResults(result) : result;
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;
8234
8262
  }
8235
8263
  /**
8236
- * @description Updates pagination state based on data length.
8237
- * @summary Calculates whether more data is available and how many pages exist
8238
- * based on the total number of items and the configured limit per page.
8239
- * This information is used to control pagination UI and infinite scrolling behavior.
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.
8240
8270
  *
8241
- * @param {number} length - The total number of items available
8242
- * @returns {void}
8271
+ * @param {HTMLElement} element - The DOM element to animate and remove
8272
+ * @return {void}
8243
8273
  *
8244
- * @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
8245
8289
  */
8246
- getMoreData(length) {
8247
- if (this.type === ListComponentsTypes.INFINITE) {
8248
- if (this.paginator)
8249
- length = length * this.limit;
8250
- if (length <= this.limit) {
8251
- this.loadMoreData = false;
8252
- }
8253
- else {
8254
- this.pages = Math.floor(length / this.limit);
8255
- if ((this.pages * this.limit) < length)
8256
- this.pages += 1;
8257
- if (this.pages === 1)
8258
- this.loadMoreData = false;
8259
- }
8260
- }
8261
- else {
8262
- this.pages = length;
8263
- if (this.pages === 1)
8264
- this.loadMoreData = false;
8265
- }
8290
+ removeElement(element) {
8291
+ element.classList.add('uk-animation-fade', 'uk-animation-medium', 'uk-animation-reverse');
8292
+ setTimeout(() => { element.remove(); }, 600);
8266
8293
  }
8267
8294
  /**
8268
- * @description Maps a single item using the configured mapper.
8269
- * @summary Transforms a data item according to the mapping configuration,
8270
- * extracting nested properties and formatting values as needed. This allows
8271
- * the component to display data in a format different from how it's stored.
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.
8272
8300
  *
8273
- * @protected
8274
- * @param {KeyValue} item - The item to map
8275
- * @param {KeyValue} mapper - The mapping configuration
8276
- * @param {KeyValue} [props] - Additional properties to include
8277
- * @returns {KeyValue} The mapped item
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
8278
8304
  *
8279
- * @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
8280
8319
  */
8281
- itemMapper(item, mapper, props) {
8282
- return Object.entries(mapper).reduce((accum, [key, value]) => {
8283
- const arrayValue = value.split('.');
8284
- if (!value) {
8285
- accum[key] = value;
8286
- }
8287
- else {
8288
- if (arrayValue.length === 1) {
8289
- value = item?.[value] ? item[value] : value !== key ? value : "";
8290
- if (isValidDate(value))
8291
- value = `${formatDate(value)}`;
8292
- accum[key] = value;
8293
- }
8294
- else {
8295
- let val;
8296
- for (const _value of arrayValue)
8297
- val = !val
8298
- ? item[_value]
8299
- : (typeof val === 'string' ? JSON.parse(val) : val)[_value];
8300
- if (isValidDate(new Date(val)))
8301
- val = `${formatDate(val)}`;
8302
- accum[key] = val === null || val === undefined ? value : val;
8303
- }
8304
- }
8305
- return Object.assign({}, props || {}, accum);
8306
- }, {});
8320
+ async redirect(action, id) {
8321
+ return await this.navController.navigateForward(`/${this.route}/${action}/${id || this.uid}`);
8307
8322
  }
8308
8323
  /**
8309
- * @description Maps all result items using the configured mapper.
8310
- * @summary Applies the itemMapper to each item in the result set, adding
8311
- * common properties like operations and route information. This transforms
8312
- * the raw data into the format expected by the list item components.
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.
8313
8330
  *
8314
- * @param {KeyValue[]} data - The array of items to map
8315
- * @returns {KeyValue[]} The array of mapped items
8331
+ * @param {Event} event - The event that triggered the action menu request
8332
+ * @return {void}
8316
8333
  *
8317
- * @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
8318
8349
  */
8319
- mapResults(data) {
8320
- if (!data || !data.length)
8321
- return [];
8322
- // passing uid as prop to mapper
8323
- this.mapper = { ...this.mapper, ...{ uid: this.pk } };
8324
- const props = Object.assign({
8325
- operations: this.operations,
8326
- route: this.route,
8327
- ...Object.keys(this.item).reduce((acc, key) => {
8328
- acc[key] = this.item[key];
8329
- return acc;
8330
- }, {}),
8331
- // ... (!this.item.render ? {} : Object.keys(this.item).reduce((acc: KeyValue, key: string) => {
8332
- // acc[key] = this.item[key as keyof IListItemProp];
8333
- // return acc;
8334
- // }, {}))
8335
- });
8336
- return data.reduce((accum, curr) => {
8337
- accum.push({ ...this.itemMapper(curr, this.mapper, props), ...{ pk: this.pk } });
8338
- return accum;
8339
- }, []);
8350
+ presentActionsMenu(event) {
8351
+ event.stopImmediatePropagation();
8352
+ // forcing trap focus
8353
+ removeFocusTrap();
8354
+ this.actionMenuComponent.event = event;
8355
+ this.actionMenuOpen = true;
8340
8356
  }
8341
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8342
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ListComponent, isStandalone: true, selector: "ngx-decaf-list", inputs: { type: "type", translatable: "translatable", showSearchbar: "showSearchbar", data: "data", source: "source", start: "start", limit: "limit", loadMoreData: "loadMoreData", lines: "lines", inset: "inset", scrollThreshold: "scrollThreshold", scrollPosition: "scrollPosition", loadingText: "loadingText", showRefresher: "showRefresher", loadingSpinner: "loadingSpinner", enableFilter: "enableFilter", sortDirection: "sortDirection", sortBy: "sortBy", disableSort: "disableSort", emptyIcon: "emptyIcon", empty: "empty" }, outputs: { refreshEvent: "refreshEvent", clickEvent: "clickEvent" }, host: { listeners: { "window:ListItemClickEvent": "handleClick($event)", "window:searchbarEvent": "handleSearch($event)", "window:BackButtonNavigationEndEvent": "refresh($event)" } }, usesInheritance: true, ngImport: i0, template: "\n@if(showRefresher) {\n <ion-refresher slot=\"fixed\" [pullFactor]=\"1\" [pullMin]=\"100\" [pullMax]=\"200\" (ionRefresh)=\"handleRefresh($event)\">\n <ion-refresher-content />\n </ion-refresher>\n}\n\n@if(showSearchbar && data?.length) {\n @if(model && enableFilter) {\n <ngx-decaf-filter\n [model]=\"model\"\n [sortDirection]=\"sortDirection\"\n [disableSort]=\"disableSort\"\n (filterEvent)=\"handleFilter($event)\"\n (searchEvent)=\"handleSearch($event)\"\n />\n } @else {\n <ngx-decaf-searchbar [emitEventToWindow]=\"false\" [debounce]=\"500\" (searchEvent)=\"handleSearch($event)\" />\n }\n}\n\n@if(data?.length) {\n <ion-list [id]=\"uid\" [inset]=\"inset\" [lines]=\"lines\" #component>\n @if(item?.tag) {\n @for(child of items; track trackItemFn($index, child)) {\n <ngx-decaf-component-renderer\n [tag]=\"item.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]='{\n item: child,\n mapper: mapper,\n route: route\n }'>\n </ngx-decaf-component-renderer>\n }\n } @else {\n <ng-content></ng-content>\n }\n </ion-list>\n\n @if(loadMoreData) {\n @if(pages > 0 && type === 'paginated' && !searchValue?.length) {\n <ngx-decaf-pagination\n [totalPages]=\"pages\"\n [current]=\"page\"\n (clickEvent)=\"handlePaginate($event)\"\n />\n\n } @else {\n <ion-infinite-scroll\n [class]=\"searchValue?.length ? 'dcf-hidden' : ''\"\n\n [position]=\"scrollPosition\"\n [threshold]=\"scrollThreshold\"\n (ionInfinite)=\"handleRefresh($event)\">\n <ion-infinite-scroll-content [loadingSpinner]=\"loadingSpinner\" [loadingText]=\"loadingText\" />\n </ion-infinite-scroll>\n }\n }\n} @else {\n @if(refreshing) {\n @for(skl of skeletonData; track $index) {\n <ion-item>\n <ion-thumbnail slot=\"start\">\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n </ion-thumbnail>\n <ion-label>\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n </ion-label>\n </ion-item>\n }\n\n } @else {\n @if(!searchValue?.length) {\n <ngx-decaf-empty-state\n [title]=\"(locale + '.'+ empty.title) | translate\"\n [subtitle]=\"(locale + '.'+ empty.subtitle) | translate\"\n [buttonText]=\"empty.showButton ? (locale + '.'+ empty.button | translate) : ''\"\n [buttonLink]=\"empty.showButton ? empty.route : ''\"\n />\n } @else {\n <ngx-decaf-empty-state\n icon=\"search-outline\"\n ngClass=\"empty-search\"\n [translatable]=\"true\"\n title=\"search.title\"\n subtitle=\"search.subtitle\"\n [searchValue]=\"searchValue\"\n />\n }\n }\n}\n\n", styles: ["ion-infinite-scroll{max-height:50px}ion-infinite-scroll:not(.infinite-scroll-loading) ::ng-deep{max-height:1.5rem}ion-infinite-scroll ::ng-deep ion-spinner{--color: var(--dcf-color-primary);padding-top:1rem}@media (max-width: 768px){#end,[slot=end]{display:none!important}}\n"], dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "component", type: IonRefresher, selector: "ion-refresher", inputs: ["closeDuration", "disabled", "mode", "pullFactor", "pullMax", "pullMin", "snapbackDuration"] }, { kind: "component", type: PaginationComponent, selector: "ngx-decaf-pagination", inputs: ["totalPages", "current"], outputs: ["clickEvent"] }, { kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonThumbnail, selector: "ion-thumbnail" }, { kind: "component", type: IonSkeletonText, selector: "ion-skeleton-text", inputs: ["animated"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonRefresherContent, selector: "ion-refresher-content", inputs: ["pullingIcon", "pullingText", "refreshingSpinner", "refreshingText"] }, { kind: "component", type: IonInfiniteScroll, selector: "ion-infinite-scroll", inputs: ["disabled", "position", "threshold"] }, { kind: "component", type: IonInfiniteScrollContent, selector: "ion-infinite-scroll-content", inputs: ["loadingSpinner", "loadingText"] }, { kind: "component", type: SearchbarComponent, selector: "ngx-decaf-searchbar", inputs: ["autocomplete", "autocorrect", "animated", "buttonCancelText", "clearIcon", "color", "debounce", "disabled", "enterkeyhint", "inputmode", "placeholder", "searchIcon", "showCancelButton", "showClearButton", "spellcheck", "type", "value", "queryKeys", "isVisible", "wrapper", "wrapperColor", "emitEventToWindow"], outputs: ["searchEvent"] }, { kind: "component", type: EmptyStateComponent, selector: "ngx-decaf-empty-state", inputs: ["title", "titleColor", "subtitle", "subtitleColor", "showIcon", "icon", "iconSize", "iconColor", "buttonLink", "buttonText", "buttonFill", "buttonColor", "buttonSize", "searchValue"] }, { kind: "component", type: FilterComponent, selector: "ngx-decaf-filter", inputs: ["indexes", "conditions", "sortBy", "disableSort"], outputs: ["filterEvent", "searchEvent"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "children", "model", "parent"], outputs: ["listenEvent"] }] }); }
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" }] }); }
8343
8359
  };
8344
- ListComponent = __decorate([
8360
+ ListItemComponent = __decorate([
8345
8361
  Dynamic(),
8346
8362
  __metadata("design:paramtypes", [])
8347
- ], ListComponent);
8348
- 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: [{
8349
8365
  type: Component,
8350
- args: [{ selector: 'ngx-decaf-list', standalone: true, imports: [
8366
+ args: [{ selector: 'ngx-decaf-list-item', standalone: true, imports: [
8351
8367
  TranslatePipe,
8352
- IonRefresher,
8353
- IonLoading,
8354
- PaginationComponent,
8355
8368
  IonList,
8369
+ IonListHeader,
8356
8370
  IonItem,
8357
- IonThumbnail,
8358
- IonSkeletonText,
8371
+ IonItemSliding,
8372
+ IonItemOptions,
8373
+ IonItemOption,
8374
+ IonIcon,
8359
8375
  IonLabel,
8360
- IonText,
8361
- IonRefresherContent,
8362
- IonInfiniteScroll,
8363
- IonInfiniteScrollContent,
8364
- IonThumbnail,
8365
- IonSkeletonText,
8366
- SearchbarComponent,
8367
- EmptyStateComponent,
8368
- ListItemComponent,
8369
- FilterComponent,
8370
- ComponentRendererComponent
8371
- ], template: "\n@if(showRefresher) {\n <ion-refresher slot=\"fixed\" [pullFactor]=\"1\" [pullMin]=\"100\" [pullMax]=\"200\" (ionRefresh)=\"handleRefresh($event)\">\n <ion-refresher-content />\n </ion-refresher>\n}\n\n@if(showSearchbar && data?.length) {\n @if(model && enableFilter) {\n <ngx-decaf-filter\n [model]=\"model\"\n [sortDirection]=\"sortDirection\"\n [disableSort]=\"disableSort\"\n (filterEvent)=\"handleFilter($event)\"\n (searchEvent)=\"handleSearch($event)\"\n />\n } @else {\n <ngx-decaf-searchbar [emitEventToWindow]=\"false\" [debounce]=\"500\" (searchEvent)=\"handleSearch($event)\" />\n }\n}\n\n@if(data?.length) {\n <ion-list [id]=\"uid\" [inset]=\"inset\" [lines]=\"lines\" #component>\n @if(item?.tag) {\n @for(child of items; track trackItemFn($index, child)) {\n <ngx-decaf-component-renderer\n [tag]=\"item.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]='{\n item: child,\n mapper: mapper,\n route: route\n }'>\n </ngx-decaf-component-renderer>\n }\n } @else {\n <ng-content></ng-content>\n }\n </ion-list>\n\n @if(loadMoreData) {\n @if(pages > 0 && type === 'paginated' && !searchValue?.length) {\n <ngx-decaf-pagination\n [totalPages]=\"pages\"\n [current]=\"page\"\n (clickEvent)=\"handlePaginate($event)\"\n />\n\n } @else {\n <ion-infinite-scroll\n [class]=\"searchValue?.length ? 'dcf-hidden' : ''\"\n\n [position]=\"scrollPosition\"\n [threshold]=\"scrollThreshold\"\n (ionInfinite)=\"handleRefresh($event)\">\n <ion-infinite-scroll-content [loadingSpinner]=\"loadingSpinner\" [loadingText]=\"loadingText\" />\n </ion-infinite-scroll>\n }\n }\n} @else {\n @if(refreshing) {\n @for(skl of skeletonData; track $index) {\n <ion-item>\n <ion-thumbnail slot=\"start\">\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n </ion-thumbnail>\n <ion-label>\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n </ion-label>\n </ion-item>\n }\n\n } @else {\n @if(!searchValue?.length) {\n <ngx-decaf-empty-state\n [title]=\"(locale + '.'+ empty.title) | translate\"\n [subtitle]=\"(locale + '.'+ empty.subtitle) | translate\"\n [buttonText]=\"empty.showButton ? (locale + '.'+ empty.button | translate) : ''\"\n [buttonLink]=\"empty.showButton ? empty.route : ''\"\n />\n } @else {\n <ngx-decaf-empty-state\n icon=\"search-outline\"\n ngClass=\"empty-search\"\n [translatable]=\"true\"\n title=\"search.title\"\n subtitle=\"search.subtitle\"\n [searchValue]=\"searchValue\"\n />\n }\n }\n}\n\n", styles: ["ion-infinite-scroll{max-height:50px}ion-infinite-scroll:not(.infinite-scroll-loading) ::ng-deep{max-height:1.5rem}ion-infinite-scroll ::ng-deep ion-spinner{--color: var(--dcf-color-primary);padding-top:1rem}@media (max-width: 768px){#end,[slot=end]{display:none!important}}\n"] }]
8372
- }], ctorParameters: () => [], propDecorators: { type: [{
8373
- type: Input
8374
- }], translatable: [{
8375
- type: Input
8376
- }], showSearchbar: [{
8377
- type: Input
8378
- }], data: [{
8379
- type: Input
8380
- }], source: [{
8381
- type: Input
8382
- }], start: [{
8383
- type: Input
8384
- }], limit: [{
8385
- type: Input
8386
- }], loadMoreData: [{
8387
- type: Input
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']
8388
8383
  }], lines: [{
8389
8384
  type: Input
8390
- }], inset: [{
8391
- type: Input
8392
- }], scrollThreshold: [{
8393
- type: Input
8394
- }], scrollPosition: [{
8395
- type: Input
8396
- }], loadingText: [{
8397
- type: Input
8398
- }], showRefresher: [{
8385
+ }], item: [{
8399
8386
  type: Input
8400
- }], loadingSpinner: [{
8387
+ }], icon: [{
8401
8388
  type: Input
8402
- }], enableFilter: [{
8389
+ }], iconSlot: [{
8403
8390
  type: Input
8404
- }], sortDirection: [{
8391
+ }], button: [{
8405
8392
  type: Input
8406
- }], sortBy: [{
8393
+ }], title: [{
8407
8394
  type: Input
8408
- }], disableSort: [{
8395
+ }], description: [{
8409
8396
  type: Input
8410
- }], emptyIcon: [{
8397
+ }], info: [{
8411
8398
  type: Input
8412
- }], empty: [{
8399
+ }], subinfo: [{
8413
8400
  type: Input
8414
- }], refreshEvent: [{
8415
- type: Output
8416
8401
  }], clickEvent: [{
8417
8402
  type: Output
8418
- }], handleClick: [{
8419
- type: HostListener,
8420
- args: ['window:ListItemClickEvent', ['$event']]
8421
- }], handleSearch: [{
8422
- type: HostListener,
8423
- args: ['window:searchbarEvent', ['$event']]
8424
- }], refresh: [{
8403
+ }], enableSlideItems: [{
8425
8404
  type: HostListener,
8426
- args: ['window:BackButtonNavigationEndEvent', ['$event']]
8405
+ args: ['window:resize', ['$event']]
8427
8406
  }] } });
8428
8407
 
8429
8408
  let SteppedFormComponent = class SteppedFormComponent {
@@ -8678,17 +8657,16 @@ let SteppedFormComponent = class SteppedFormComponent {
8678
8657
  this.activeChildren = undefined;
8679
8658
  this.timerSubscription = timer(10).subscribe(() => {
8680
8659
  this.activeChildren = this.children.filter(c => c.props?.['page'] === page);
8681
- console.log(this.activeChildren);
8682
8660
  });
8683
8661
  }
8684
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SteppedFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8685
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: SteppedFormComponent, isStandalone: true, selector: "ngx-decaf-stepped-form", inputs: { locale: "locale", pages: "pages", operation: "operation", startPage: "startPage", children: "children", formGroup: "formGroup" }, outputs: { submitEvent: "submitEvent" }, ngImport: i0, template: "<form class=\"dcf-steped-form\" novalidate>\n <div class=\"dcf-page-steps\">\n <div>\n @for(page of pagesArray; track $index;) {\n <div [class.dcf-active]=\"activePage === $index + 1\" [class.dcf-passed]=\"($index + 1) < activePage\">{{ $index + 1 }}</div>\n }\n </div>\n </div>\n @if(formGroup) {\n @for(child of activeChildren; track $index) {\n <ngx-decaf-component-renderer\n [tag]=\"child?.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n }\n } @else {\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n <br />\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n }\n\n <div class=\"dcf-buttons-container dcf-grid dcf-grid-collapse dcf-flex dcf-flex-left\">\n <div class=\"dcf-width-1-2@s\">\n <ion-button fill=\"clear\" (click)=\"handleBack()\" [disabled]=\"activePage <= 1\">\n <ion-icon aria-hidden=\"true\" name=\"arrow-back-outline\"></ion-icon>\n {{locale + '.previous' | translate}}\n </ion-button>\n </div>\n\n <div class=\"dcf-width-1-2@s\">\n <ion-button [fill]=\"activePage === pages ? 'solid' : 'outline'\" (click)=\"handleNext(activePage === pages ? true : false)\">\n @if(activePage === pages) {\n {{locale + '.submit' | translate}}\n } @else {\n {{locale + '.next' | translate}}\n <ion-icon aria-hidden=\"true\" name=\"arrow-forward-outline\"></ion-icon>\n }\n </ion-button>\n </div>\n </div>\n</form>\n", styles: [".dcf-buttons-container{margin-top:1.8rem;margin-bottom:0}@media (min-width: 639px){.dcf-buttons-container.dcf-flex div:nth-child(2){display:flex;justify-content:flex-end}}@media (max-width: 638px){.dcf-buttons-container.dcf-flex div{width:100%}.dcf-buttons-container.dcf-flex ion-button{width:100%;margin-bottom:1rem}}.dcf-steped-form{padding:2rem 1rem}.dcf-page-steps{display:flex;justify-content:center;margin-bottom:2rem}.dcf-page-steps>div{justify-content:center;min-width:200px;max-width:200px;column-gap:.25em;display:flex}.dcf-page-steps>div>div{width:30px;text-align:center;border-bottom:solid var(--dcf-color-gray-3);box-sizing:border-box;border-width:3px;font-size:0px;font-weight:600}.dcf-page-steps>div>div.dcf-active{border-width:5px;font-size:1rem;color:var(--ion-color-gray-7);border-color:var(--ion-color-primary);line-height:1rem}.dcf-page-steps>div>div.dcf-passed{border-width:4px;font-size:.5rem;line-height:1.2rem;border-color:var(--dcf-color-gray-5);color:var(--ion-color-primary)}\n"], dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "component", type: IonSkeletonText, selector: "ion-skeleton-text", inputs: ["animated"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "children", "model", "parent"], outputs: ["listenEvent"] }] }); }
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" }] }); }
8686
8664
  };
8687
8665
  SteppedFormComponent = __decorate([
8688
8666
  Dynamic(),
8689
8667
  __metadata("design:paramtypes", [])
8690
8668
  ], SteppedFormComponent);
8691
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SteppedFormComponent, decorators: [{
8669
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: SteppedFormComponent, decorators: [{
8692
8670
  type: Component,
8693
8671
  args: [{ selector: 'ngx-decaf-stepped-form', imports: [
8694
8672
  TranslatePipe,
@@ -8697,7 +8675,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
8697
8675
  IonText,
8698
8676
  IonButton,
8699
8677
  IonIcon,
8700
- ModelRendererComponent,
8701
8678
  ComponentRendererComponent
8702
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"] }]
8703
8680
  }], ctorParameters: () => [], propDecorators: { locale: [{
@@ -8732,10 +8709,10 @@ class CollapsableDirective {
8732
8709
  }
8733
8710
  }
8734
8711
  }
8735
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CollapsableDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
8736
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.14", type: CollapsableDirective, isStandalone: true, selector: "[decafCollapsable]", ngImport: i0 }); }
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 }); }
8737
8714
  }
8738
- 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: [{
8739
8716
  type: Directive,
8740
8717
  args: [{
8741
8718
  selector: '[decafCollapsable]',
@@ -8761,8 +8738,8 @@ const Components = [
8761
8738
  SteppedFormComponent
8762
8739
  ];
8763
8740
  class ForAngularComponentsModule {
8764
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ForAngularComponentsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
8765
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.14", ngImport: i0, type: ForAngularComponentsModule, imports: [ModelRendererComponent,
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,
8766
8743
  ComponentRendererComponent,
8767
8744
  CrudFieldComponent,
8768
8745
  CrudFormComponent,
@@ -8789,7 +8766,7 @@ class ForAngularComponentsModule {
8789
8766
  LayoutComponent,
8790
8767
  FilterComponent,
8791
8768
  SteppedFormComponent, CollapsableDirective] }); }
8792
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ForAngularComponentsModule, imports: [CrudFieldComponent,
8769
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.2", ngImport: i0, type: ForAngularComponentsModule, imports: [CrudFieldComponent,
8793
8770
  CrudFormComponent,
8794
8771
  EmptyStateComponent,
8795
8772
  ListComponent,
@@ -8801,7 +8778,7 @@ class ForAngularComponentsModule {
8801
8778
  FilterComponent,
8802
8779
  SteppedFormComponent] }); }
8803
8780
  }
8804
- 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: [{
8805
8782
  type: NgModule,
8806
8783
  args: [{
8807
8784
  imports: [...Components, ...Directives],
@@ -8825,5 +8802,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
8825
8802
  * Generated bundle index. Do not edit.
8826
8803
  */
8827
8804
 
8828
- export { AngularEngineKeys, BaseComponentProps, CollapsableDirective, ComponentRendererComponent, ComponentsTagNames, CrudFieldComponent, CrudFormComponent, CssClasses, DB_ADAPTER_PROVIDER_TOKEN, DefaultFormReactiveOptions, Dynamic, DynamicModule, EmptyStateComponent, EventConstants, FieldsetComponent, FilterComponent, ForAngularCommonModule, ForAngularComponentsModule, FormConstants, I18N_CONFIG_TOKEN, I18nLoader, I18nLoaderFactory, LayoutComponent, ListComponent, ListComponentsTypes, ListItemComponent, LoggerLevels, ModelRendererComponent, MultiI18nLoader, NgxBaseComponent, NgxCrudFormField, NgxFormService, NgxRenderingEngine, PaginationComponent, RouteDirections, SearchbarComponent, SteppedFormComponent, cleanSpaces, dataMapper, formatDate, generateRandomValue, getI18nLoaderFactoryProviderConfig, getInjectablesRegistry, getLocaleContext, getLocaleContextByKey, getLocaleFromClassName, getLocaleLanguage, getLogger, getOnWindow, getOnWindowDocument, getWindow, getWindowDocument, getWindowWidth, isDarkMode, isDevelopmentMode, isNotUndefined, isValidDate, itemMapper, parseToValidDate, removeFocusTrap, setOnWindow, stringToBoolean, windowEventEmitter };
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 };
8829
8806
  //# sourceMappingURL=decaf-ts-for-angular.mjs.map