@decaf-ts/for-angular 0.1.31 → 0.1.35

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.
@@ -3,8 +3,8 @@ import * as i0 from '@angular/core';
3
3
  import { InjectionToken, isDevMode, provideEnvironmentInitializer, reflectComponentType, Injector, createEnvironmentInjector, runInInjectionContext, createComponent, inject, NgZone, Injectable, Input, Directive, signal, ChangeDetectorRef, EnvironmentInjector, Renderer2, EventEmitter, effect, ElementRef, Output, ViewChild, Inject, ViewContainerRef, TemplateRef, Component, ViewEncapsulation, HostListener, Pipe, NgModule } from '@angular/core';
4
4
  import * as i1$1 from '@angular/common';
5
5
  import { Location, NgComponentOutlet, CommonModule } from '@angular/common';
6
- import { ValidationKeys, DEFAULT_PATTERNS, VALIDATION_PARENT_KEY, Primitives, Model, Validation, ComparisonValidationKeys, PathProxyEngine, ModelKeys, isValidDate as isValidDate$1, parseDate, sf as sf$1, ReservedModels } from '@decaf-ts/decorator-validation';
7
6
  import { OperationKeys, InternalError, NotFoundError } from '@decaf-ts/db-decorators';
7
+ import { ValidationKeys, DEFAULT_PATTERNS, VALIDATION_PARENT_KEY, Primitives, Model, Validation, ComparisonValidationKeys, PathProxyEngine, ModelKeys, isValidDate as isValidDate$1, parseDate, sf as sf$1, ReservedModels } from '@decaf-ts/decorator-validation';
8
8
  import * as i1 from '@angular/forms';
9
9
  import { FormGroup, FormControl, FormArray, AbstractControl, Validators, ReactiveFormsModule, FormsModule } from '@angular/forms';
10
10
  import { Repository, OrderDirection, Condition } from '@decaf-ts/core';
@@ -308,23 +308,21 @@ const CssClasses = {
308
308
  * @summary Provides default configuration for form buttons in CRUD operations.
309
309
  * Includes default text labels for submit and clear buttons, which can be
310
310
  * overridden by individual form implementations.
311
- * @type {ICrudFormOptions}
311
+ * @type {ICrudFormButtons}
312
312
  * @property {Object} buttons - Configuration for form action buttons
313
313
  * @property {Object} buttons.submit - Submit button configuration
314
314
  * @property {string} buttons.submit.text - Default text for submit button
315
315
  * @property {Object} buttons.clear - Clear button configuration
316
316
  * @property {string} buttons.clear.text - Default text for clear button
317
- * @const DefaultFormReactiveOptions
317
+ * @const DefaultFormButtonsOptions
318
318
  * @memberOf module:lib/engine/constants
319
319
  */
320
- const DefaultFormReactiveOptions = {
321
- buttons: {
322
- submit: {
323
- text: 'Submit',
324
- },
325
- clear: {
326
- text: 'Clear',
327
- },
320
+ const DefaultFormButtonsOptions = {
321
+ submit: {
322
+ text: 'Submit',
323
+ },
324
+ clear: {
325
+ text: 'Clear',
328
326
  },
329
327
  };
330
328
  /**
@@ -844,9 +842,20 @@ function getMenuIcon(label, menu) {
844
842
  return item?.icon || '';
845
843
  }
846
844
  function dateFromString(value) {
845
+ if (value instanceof Date) {
846
+ return value;
847
+ }
847
848
  const dateArray = value.includes('T') ? value.split('T') : value.split(' ');
848
849
  return new Date(dateArray.length === 1 ? `${value}T00:00:00` : value);
849
850
  }
851
+ function isValidBase64(value) {
852
+ if (!value?.trim()?.length) {
853
+ return false;
854
+ }
855
+ const pure = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
856
+ const dataUrl = /^data:([a-zA-Z0-9.+-]+\/[a-zA-Z0-9.+-]+);base64,[A-Za-z0-9+/]+={0,2}$/;
857
+ return pure.test(value) || dataUrl.test(value);
858
+ }
850
859
 
851
860
  function getDbAdapterFlavour() {
852
861
  return (getOnWindow(DB_ADAPTER_FLAVOUR_TOKEN) || '');
@@ -7306,7 +7315,7 @@ async function getNgxModalComponent(props = {}, modalProps = {}, injector) {
7306
7315
  * @param {EnvironmentInjector} [injector] - Optional environment injector for dependency injection.
7307
7316
  * @returns {Promise<IonModal>} - A promise that resolves with the modal instance.
7308
7317
  */
7309
- async function getNgxModalCrudComponent(model, props = {}, modalProps = {}, injector) {
7318
+ async function getNgxModalCrudComponent(model, props = {}, formProps = {}, modalProps = {}, injector) {
7310
7319
  if (!props || !props?.['operation']) {
7311
7320
  props.operation = OperationKeys.CREATE;
7312
7321
  }
@@ -7321,7 +7330,8 @@ async function getNgxModalCrudComponent(model, props = {}, modalProps = {}, inje
7321
7330
  }
7322
7331
  const component = await NgxRenderingEngine.createComponent(ModalComponent, {
7323
7332
  model,
7324
- globals: props,
7333
+ globals: formProps,
7334
+ props: props,
7325
7335
  }, injector || undefined).create(modalProps);
7326
7336
  return component.modal;
7327
7337
  }
@@ -7529,7 +7539,7 @@ let CrudFieldComponent = class CrudFieldComponent extends NgxFormFieldDirective
7529
7539
  * When true, the browser will check the spelling of the input text.
7530
7540
  *
7531
7541
  * @type {boolean}
7532
- * @default false
7542
+ * @default true
7533
7543
  * @memberOf CrudFieldComponent
7534
7544
  */
7535
7545
  this.startEmpty = true;
@@ -8229,7 +8239,7 @@ class NgxFormDirective extends NgxParentComponentDirective {
8229
8239
  return undefined;
8230
8240
  }
8231
8241
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: NgxFormDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
8232
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.17", type: NgxFormDirective, isStandalone: true, inputs: { parentFormId: "parentFormId", deepMerge: "deepMerge", path: "path", multiple: "multiple", updateOn: "updateOn", target: "target", method: "method", options: "options", action: "action", operation: "operation", handlers: "handlers", rendererId: "rendererId", allowClear: "allowClear", match: "match" }, outputs: { submitEvent: "submitEvent", formGroupLoadedEvent: "formGroupLoadedEvent" }, viewQueries: [{ propertyName: "component", first: true, predicate: ["component"], descendants: true, read: ElementRef }], usesInheritance: true, usesOnChanges: true, ngImport: i0 }); }
8242
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.17", type: NgxFormDirective, isStandalone: true, inputs: { parentFormId: "parentFormId", deepMerge: "deepMerge", path: "path", multiple: "multiple", updateOn: "updateOn", target: "target", method: "method", buttons: "buttons", action: "action", operation: "operation", handlers: "handlers", rendererId: "rendererId", allowClear: "allowClear", match: "match" }, outputs: { submitEvent: "submitEvent", formGroupLoadedEvent: "formGroupLoadedEvent" }, viewQueries: [{ propertyName: "component", first: true, predicate: ["component"], descendants: true, read: ElementRef }], usesInheritance: true, usesOnChanges: true, ngImport: i0 }); }
8233
8243
  }
8234
8244
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: NgxFormDirective, decorators: [{
8235
8245
  type: Directive
@@ -8250,7 +8260,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
8250
8260
  type: Input
8251
8261
  }], method: [{
8252
8262
  type: Input
8253
- }], options: [{
8263
+ }], buttons: [{
8254
8264
  type: Input
8255
8265
  }], action: [{
8256
8266
  type: Input
@@ -8694,7 +8704,7 @@ let CrudFormComponent = class CrudFormComponent extends NgxFormDirective {
8694
8704
  * @memberOf CrudFormComponent
8695
8705
  */
8696
8706
  async ngOnInit() {
8697
- this.options = Object.assign({}, DefaultFormReactiveOptions, { buttons: { submit: { text: this.operation.toLowerCase() } } }, this.options || {});
8707
+ this.buttons = Object.assign({}, DefaultFormButtonsOptions, { submit: { text: this.operation.toLowerCase() } }, this.buttons || {});
8698
8708
  if (!this.pk && this.modelName) {
8699
8709
  const repo = getModelAndRepository(this.modelName);
8700
8710
  if (repo) {
@@ -8717,7 +8727,7 @@ let CrudFormComponent = class CrudFormComponent extends NgxFormDirective {
8717
8727
  super.submitEventEmit(this.model, 'CrudFormComponent', ComponentEventNames.Submit, this.handlers, OperationKeys.DELETE);
8718
8728
  }
8719
8729
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: CrudFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8720
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: CrudFormComponent, isStandalone: true, selector: "ngx-decaf-crud-form", inputs: { showCancelButton: "showCancelButton" }, host: { properties: { "attr.id": "uid" } }, usesInheritance: true, ngImport: i0, template: "@if (operation !== 'read' && operation !== 'delete') {\n <form\n [class]=\"'dcf-form-grid ' + operation\"\n #component\n [id]=\"rendererId\"\n [formGroup]=\"formGroup\"\n (ngSubmit)=\"submit($event)\"\n novalidate\n [target]=\"target\"\n >\n @if (!children?.length) {\n <ng-content #formContent></ng-content>\n } @else {\n <ngx-decaf-layout\n [className]=\"'dcf-crud-form-grid dcf-grid-nested '\"\n [children]=\"children || []\"\n [isModalChild]=\"isModalChild\"\n [pk]=\"pk\"\n (listenEvent)=\"handleEvent($event)\"\n [parentForm]=\"formGroup || parentForm\"\n [operation]=\"operation\"\n [modelId]=\"modelId\"\n [cardType]=\"cardType ?? 'blank'\"\n [match]=\"match ?? false\"\n [refreshing]=\"refreshing\"\n [gap]=\"'small'\"\n [flexMode]=\"props.flexMode || false\"\n [rows]=\"rows\"\n [borders]=\"borders ?? false\"\n [breakpoint]=\"breakpoint ?? 'large'\"\n [cols]=\"cols\"\n />\n }\n @if (initialized) {\n <div\n class=\"dcf-buttons-grid dcf-grid dcf-grid-small dcf-flex dcf-flex-right\"\n >\n @if (!action) {\n <div [class.dcf-hidden]=\"!showCancelButton\">\n <ion-button\n fill=\"clear\"\n (click)=\"handleReset()\"\n >\n @if (options.buttons.clear?.icon) {\n <ion-icon\n aria-hidden=\"true\"\n [slot]=\"options.buttons.clear?.iconSlot\"\n [name]=\"options.buttons.clear?.icon\"\n ></ion-icon>\n }\n {{\n locale +\n '.' +\n (allowClear ? options.buttons.clear?.text : 'back')\n | translate\n }}\n </ion-button>\n </div>\n }\n <div>\n <ion-button\n type=\"submit\"\n [expand]=\"action ? 'block' : 'default'\"\n >\n @if (options.buttons.submit.icon) {\n <ion-icon\n aria-hidden=\"true\"\n [slot]=\"options.buttons.submit.iconSlot\"\n [name]=\"options.buttons.submit.icon\"\n ></ion-icon>\n }\n {{\n action\n ? action\n : (locale + '.' + options.buttons.submit.text | translate)\n }}\n </ion-button>\n </div>\n </div>\n }\n </form>\n} @else {\n <section\n #component\n [id]=\"uid\"\n >\n <ngx-decaf-layout\n [className]=\"''\"\n [pk]=\"pk\"\n [isModalChild]=\"isModalChild\"\n [modelId]=\"modelId\"\n [children]=\"children || []\"\n [operation]=\"operation\"\n [cardType]=\"cardType ?? 'blank'\"\n [modelId]=\"modelId\"\n [match]=\"match ?? false\"\n [gap]=\"'small'\"\n [isModalChild]=\"isModalChild\"\n (listenEvent)=\"handleEvent($event)\"\n [flexMode]=\"props.flexMode || false\"\n [rows]=\"rows\"\n [borders]=\"borders ?? false\"\n [breakpoint]=\"breakpoint ?? 'large'\"\n [cols]=\"cols\"\n />\n </section>\n\n <section\n [class]=\"\n 'dcf-buttons-grid dcf-grid dcf-grid-small dcf-flex dcf-flex-left ' +\n operation\n \"\n [id]=\"uid\"\n >\n @if ([OperationKeys.DELETE].includes(operation) && modelId) {\n <div>\n <ion-button\n (click)=\"handleDelete()\"\n color=\"danger\"\n type=\"button\"\n >\n @if (options.buttons.submit.icon) {\n <ion-icon\n aria-hidden=\"true\"\n [slot]=\"options.buttons.submit.iconSlot\"\n [name]=\"options.buttons.submit.icon\"\n ></ion-icon>\n }\n {{ locale + '.delete' | translate }}\n </ion-button>\n </div>\n }\n @if (\n operation === OperationKeys.CREATE || operation === OperationKeys.UPDATE\n ) {\n <div>\n <ion-button type=\"submit\">\n @if (options.buttons.submit.icon) {\n <ion-icon\n aria-hidden=\"true\"\n [slot]=\"options.buttons.submit.iconSlot\"\n [name]=\"options.buttons.submit.icon\"\n ></ion-icon>\n }\n {{\n action\n ? action\n : (locale + '.' + options.buttons.submit.text | translate)\n }}\n </ion-button>\n </div>\n }\n <div>\n <ion-button\n fill=\"clear\"\n (click)=\"handleReset()\"\n >\n @if (options.buttons.clear?.icon) {\n <ion-icon\n aria-hidden=\"true\"\n [slot]=\"options.buttons.clear?.iconSlot\"\n [name]=\"options.buttons.clear?.icon\"\n ></ion-icon>\n }\n {{\n [\n OperationKeys.DELETE,\n OperationKeys.READ,\n OperationKeys.UPDATE,\n ].includes(operation)\n ? (locale + '.back' | translate)\n : options.buttons.clear?.text\n }}\n </ion-button>\n </div>\n </section>\n}\n", styles: [".dcf-buttons-grid{margin-top:var(--dcf-margin-medium);margin-bottom:var(--dcf-margin)}@media (min-width: 577px){.dcf-buttons-grid.dcf-flex.read,.dcf-buttons-grid.dcf-flex.delete{flex-direction:row-reverse}}@media (max-width: 576px){.dcf-buttons-grid.dcf-flex{flex-direction:column-reverse}.dcf-buttons-grid.dcf-flex>div{width:100%}.dcf-buttons-grid.dcf-flex>div+div{margin-top:1rem}.dcf-buttons-grid.dcf-flex ion-button{width:100%}}.dcf-form-grid.create,.dcf-form-grid.update{margin-top:var(--dcf-margin-small)}.dcf-form-grid .dcf-form-item{margin-top:0!important}.dcf-form-grid.read .dcf-form-item{margin-bottom:var(--dcf-margin-small)}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: LayoutComponent, selector: "ngx-decaf-layout", inputs: ["gap", "grid", "flexMode", "rowCard", "maxColsLength", "accordion"] }, { 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" }] }); }
8730
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: CrudFormComponent, isStandalone: true, selector: "ngx-decaf-crud-form", inputs: { showCancelButton: "showCancelButton" }, host: { properties: { "attr.id": "uid" } }, usesInheritance: true, ngImport: i0, template: "@if (operation !== 'read' && operation !== 'delete') {\n <form\n [class]=\"'dcf-form-grid ' + operation\"\n #component\n [id]=\"rendererId\"\n [formGroup]=\"formGroup\"\n (ngSubmit)=\"submit($event)\"\n novalidate\n [target]=\"target\"\n >\n @if (!children?.length) {\n <ng-content #formContent></ng-content>\n } @else {\n <ngx-decaf-layout\n [className]=\"'dcf-crud-form-grid dcf-grid-nested '\"\n [children]=\"children || []\"\n [isModalChild]=\"isModalChild\"\n [pk]=\"pk\"\n (listenEvent)=\"handleEvent($event)\"\n [parentForm]=\"formGroup || parentForm\"\n [operation]=\"operation\"\n [modelId]=\"modelId\"\n [cardType]=\"cardType ?? 'blank'\"\n [match]=\"match ?? false\"\n [refreshing]=\"refreshing\"\n [gap]=\"'small'\"\n [flexMode]=\"props.flexMode || false\"\n [rows]=\"rows\"\n [borders]=\"borders ?? false\"\n [breakpoint]=\"breakpoint ?? 'large'\"\n [cols]=\"cols\"\n />\n }\n @if (initialized) {\n <div\n class=\"dcf-buttons-grid dcf-grid dcf-grid-small dcf-flex dcf-flex-right\"\n >\n @if (!action) {\n <div [class.dcf-hidden]=\"!showCancelButton\">\n <ion-button\n fill=\"clear\"\n (click)=\"handleReset()\"\n >\n @if (buttons.clear?.icon) {\n <ion-icon\n aria-hidden=\"true\"\n [slot]=\"buttons.clear?.iconSlot\"\n [name]=\"buttons.clear?.icon\"\n ></ion-icon>\n }\n {{\n locale + '.' + (allowClear ? buttons.clear?.text : 'back')\n | translate\n }}\n </ion-button>\n </div>\n }\n <div>\n <ion-button\n type=\"submit\"\n [expand]=\"action ? 'block' : 'default'\"\n >\n @if (buttons.submit.icon) {\n <ion-icon\n aria-hidden=\"true\"\n [slot]=\"buttons.submit.iconSlot\"\n [name]=\"buttons.submit.icon\"\n ></ion-icon>\n }\n {{\n action ? action : (locale + '.' + buttons.submit.text | translate)\n }}\n </ion-button>\n </div>\n </div>\n }\n </form>\n} @else {\n <section\n #component\n [id]=\"uid\"\n >\n <ngx-decaf-layout\n [className]=\"''\"\n [pk]=\"pk\"\n [isModalChild]=\"isModalChild\"\n [modelId]=\"modelId\"\n [children]=\"children || []\"\n [operation]=\"operation\"\n [cardType]=\"cardType ?? 'blank'\"\n [modelId]=\"modelId\"\n [match]=\"match ?? false\"\n [gap]=\"'small'\"\n [isModalChild]=\"isModalChild\"\n (listenEvent)=\"handleEvent($event)\"\n [flexMode]=\"props.flexMode || false\"\n [rows]=\"rows\"\n [borders]=\"borders ?? false\"\n [breakpoint]=\"breakpoint ?? 'large'\"\n [cols]=\"cols\"\n />\n </section>\n\n <section\n [class]=\"\n 'dcf-buttons-grid dcf-grid dcf-grid-small dcf-flex dcf-flex-left ' +\n operation\n \"\n [id]=\"uid\"\n >\n @if ([OperationKeys.DELETE].includes(operation) && modelId) {\n <div>\n <ion-button\n (click)=\"handleDelete()\"\n color=\"danger\"\n type=\"button\"\n >\n @if (buttons.submit.icon) {\n <ion-icon\n aria-hidden=\"true\"\n [slot]=\"buttons.submit.iconSlot\"\n [name]=\"buttons.submit.icon\"\n ></ion-icon>\n }\n {{ locale + '.delete' | translate }}\n </ion-button>\n </div>\n }\n @if (\n operation === OperationKeys.CREATE || operation === OperationKeys.UPDATE\n ) {\n <div>\n <ion-button type=\"submit\">\n @if (buttons.submit.icon) {\n <ion-icon\n aria-hidden=\"true\"\n [slot]=\"buttons.submit.iconSlot\"\n [name]=\"buttons.submit.icon\"\n ></ion-icon>\n }\n {{\n action\n ? action\n : !translatable\n ? buttons.submit.text\n : (locale + '.' + buttons.submit.text | translate)\n }}\n </ion-button>\n </div>\n }\n <div>\n <ion-button\n fill=\"clear\"\n (click)=\"handleReset()\"\n >\n @if (buttons.clear?.icon) {\n <ion-icon\n aria-hidden=\"true\"\n [slot]=\"buttons.clear?.iconSlot\"\n [name]=\"buttons.clear?.icon\"\n ></ion-icon>\n }\n {{\n !translatable\n ? buttons.clear?.text\n : [\n OperationKeys.DELETE,\n OperationKeys.READ,\n OperationKeys.UPDATE,\n ].includes(operation)\n ? (locale + '.back' | translate)\n : (locale + '.' + buttons.clear.text | translate)\n }}\n </ion-button>\n </div>\n </section>\n}\n", styles: [".dcf-buttons-grid{margin-top:var(--dcf-margin-medium);margin-bottom:var(--dcf-margin)}@media (min-width: 577px){.dcf-buttons-grid.dcf-flex.read,.dcf-buttons-grid.dcf-flex.delete{flex-direction:row-reverse}}@media (max-width: 576px){.dcf-buttons-grid.dcf-flex{flex-direction:column-reverse}.dcf-buttons-grid.dcf-flex>div{width:100%}.dcf-buttons-grid.dcf-flex>div+div{margin-top:1rem}.dcf-buttons-grid.dcf-flex ion-button{width:100%}}.dcf-form-grid.create,.dcf-form-grid.update{margin-top:var(--dcf-margin-small)}.dcf-form-grid .dcf-form-item{margin-top:0!important}.dcf-form-grid.read .dcf-form-item{margin-bottom:var(--dcf-margin-small)}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: LayoutComponent, selector: "ngx-decaf-layout", inputs: ["gap", "grid", "flexMode", "rowCard", "maxColsLength", "accordion"] }, { 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" }] }); }
8721
8731
  };
8722
8732
  CrudFormComponent = __decorate([
8723
8733
  Dynamic(),
@@ -8725,7 +8735,7 @@ CrudFormComponent = __decorate([
8725
8735
  ], CrudFormComponent);
8726
8736
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: CrudFormComponent, decorators: [{
8727
8737
  type: Component,
8728
- args: [{ standalone: true, selector: 'ngx-decaf-crud-form', imports: [TranslatePipe, ReactiveFormsModule, LayoutComponent, IonButton, IonIcon], host: { '[attr.id]': 'uid' }, template: "@if (operation !== 'read' && operation !== 'delete') {\n <form\n [class]=\"'dcf-form-grid ' + operation\"\n #component\n [id]=\"rendererId\"\n [formGroup]=\"formGroup\"\n (ngSubmit)=\"submit($event)\"\n novalidate\n [target]=\"target\"\n >\n @if (!children?.length) {\n <ng-content #formContent></ng-content>\n } @else {\n <ngx-decaf-layout\n [className]=\"'dcf-crud-form-grid dcf-grid-nested '\"\n [children]=\"children || []\"\n [isModalChild]=\"isModalChild\"\n [pk]=\"pk\"\n (listenEvent)=\"handleEvent($event)\"\n [parentForm]=\"formGroup || parentForm\"\n [operation]=\"operation\"\n [modelId]=\"modelId\"\n [cardType]=\"cardType ?? 'blank'\"\n [match]=\"match ?? false\"\n [refreshing]=\"refreshing\"\n [gap]=\"'small'\"\n [flexMode]=\"props.flexMode || false\"\n [rows]=\"rows\"\n [borders]=\"borders ?? false\"\n [breakpoint]=\"breakpoint ?? 'large'\"\n [cols]=\"cols\"\n />\n }\n @if (initialized) {\n <div\n class=\"dcf-buttons-grid dcf-grid dcf-grid-small dcf-flex dcf-flex-right\"\n >\n @if (!action) {\n <div [class.dcf-hidden]=\"!showCancelButton\">\n <ion-button\n fill=\"clear\"\n (click)=\"handleReset()\"\n >\n @if (options.buttons.clear?.icon) {\n <ion-icon\n aria-hidden=\"true\"\n [slot]=\"options.buttons.clear?.iconSlot\"\n [name]=\"options.buttons.clear?.icon\"\n ></ion-icon>\n }\n {{\n locale +\n '.' +\n (allowClear ? options.buttons.clear?.text : 'back')\n | translate\n }}\n </ion-button>\n </div>\n }\n <div>\n <ion-button\n type=\"submit\"\n [expand]=\"action ? 'block' : 'default'\"\n >\n @if (options.buttons.submit.icon) {\n <ion-icon\n aria-hidden=\"true\"\n [slot]=\"options.buttons.submit.iconSlot\"\n [name]=\"options.buttons.submit.icon\"\n ></ion-icon>\n }\n {{\n action\n ? action\n : (locale + '.' + options.buttons.submit.text | translate)\n }}\n </ion-button>\n </div>\n </div>\n }\n </form>\n} @else {\n <section\n #component\n [id]=\"uid\"\n >\n <ngx-decaf-layout\n [className]=\"''\"\n [pk]=\"pk\"\n [isModalChild]=\"isModalChild\"\n [modelId]=\"modelId\"\n [children]=\"children || []\"\n [operation]=\"operation\"\n [cardType]=\"cardType ?? 'blank'\"\n [modelId]=\"modelId\"\n [match]=\"match ?? false\"\n [gap]=\"'small'\"\n [isModalChild]=\"isModalChild\"\n (listenEvent)=\"handleEvent($event)\"\n [flexMode]=\"props.flexMode || false\"\n [rows]=\"rows\"\n [borders]=\"borders ?? false\"\n [breakpoint]=\"breakpoint ?? 'large'\"\n [cols]=\"cols\"\n />\n </section>\n\n <section\n [class]=\"\n 'dcf-buttons-grid dcf-grid dcf-grid-small dcf-flex dcf-flex-left ' +\n operation\n \"\n [id]=\"uid\"\n >\n @if ([OperationKeys.DELETE].includes(operation) && modelId) {\n <div>\n <ion-button\n (click)=\"handleDelete()\"\n color=\"danger\"\n type=\"button\"\n >\n @if (options.buttons.submit.icon) {\n <ion-icon\n aria-hidden=\"true\"\n [slot]=\"options.buttons.submit.iconSlot\"\n [name]=\"options.buttons.submit.icon\"\n ></ion-icon>\n }\n {{ locale + '.delete' | translate }}\n </ion-button>\n </div>\n }\n @if (\n operation === OperationKeys.CREATE || operation === OperationKeys.UPDATE\n ) {\n <div>\n <ion-button type=\"submit\">\n @if (options.buttons.submit.icon) {\n <ion-icon\n aria-hidden=\"true\"\n [slot]=\"options.buttons.submit.iconSlot\"\n [name]=\"options.buttons.submit.icon\"\n ></ion-icon>\n }\n {{\n action\n ? action\n : (locale + '.' + options.buttons.submit.text | translate)\n }}\n </ion-button>\n </div>\n }\n <div>\n <ion-button\n fill=\"clear\"\n (click)=\"handleReset()\"\n >\n @if (options.buttons.clear?.icon) {\n <ion-icon\n aria-hidden=\"true\"\n [slot]=\"options.buttons.clear?.iconSlot\"\n [name]=\"options.buttons.clear?.icon\"\n ></ion-icon>\n }\n {{\n [\n OperationKeys.DELETE,\n OperationKeys.READ,\n OperationKeys.UPDATE,\n ].includes(operation)\n ? (locale + '.back' | translate)\n : options.buttons.clear?.text\n }}\n </ion-button>\n </div>\n </section>\n}\n", styles: [".dcf-buttons-grid{margin-top:var(--dcf-margin-medium);margin-bottom:var(--dcf-margin)}@media (min-width: 577px){.dcf-buttons-grid.dcf-flex.read,.dcf-buttons-grid.dcf-flex.delete{flex-direction:row-reverse}}@media (max-width: 576px){.dcf-buttons-grid.dcf-flex{flex-direction:column-reverse}.dcf-buttons-grid.dcf-flex>div{width:100%}.dcf-buttons-grid.dcf-flex>div+div{margin-top:1rem}.dcf-buttons-grid.dcf-flex ion-button{width:100%}}.dcf-form-grid.create,.dcf-form-grid.update{margin-top:var(--dcf-margin-small)}.dcf-form-grid .dcf-form-item{margin-top:0!important}.dcf-form-grid.read .dcf-form-item{margin-bottom:var(--dcf-margin-small)}\n"] }]
8738
+ args: [{ standalone: true, selector: 'ngx-decaf-crud-form', imports: [TranslatePipe, ReactiveFormsModule, LayoutComponent, IonButton, IonIcon], host: { '[attr.id]': 'uid' }, template: "@if (operation !== 'read' && operation !== 'delete') {\n <form\n [class]=\"'dcf-form-grid ' + operation\"\n #component\n [id]=\"rendererId\"\n [formGroup]=\"formGroup\"\n (ngSubmit)=\"submit($event)\"\n novalidate\n [target]=\"target\"\n >\n @if (!children?.length) {\n <ng-content #formContent></ng-content>\n } @else {\n <ngx-decaf-layout\n [className]=\"'dcf-crud-form-grid dcf-grid-nested '\"\n [children]=\"children || []\"\n [isModalChild]=\"isModalChild\"\n [pk]=\"pk\"\n (listenEvent)=\"handleEvent($event)\"\n [parentForm]=\"formGroup || parentForm\"\n [operation]=\"operation\"\n [modelId]=\"modelId\"\n [cardType]=\"cardType ?? 'blank'\"\n [match]=\"match ?? false\"\n [refreshing]=\"refreshing\"\n [gap]=\"'small'\"\n [flexMode]=\"props.flexMode || false\"\n [rows]=\"rows\"\n [borders]=\"borders ?? false\"\n [breakpoint]=\"breakpoint ?? 'large'\"\n [cols]=\"cols\"\n />\n }\n @if (initialized) {\n <div\n class=\"dcf-buttons-grid dcf-grid dcf-grid-small dcf-flex dcf-flex-right\"\n >\n @if (!action) {\n <div [class.dcf-hidden]=\"!showCancelButton\">\n <ion-button\n fill=\"clear\"\n (click)=\"handleReset()\"\n >\n @if (buttons.clear?.icon) {\n <ion-icon\n aria-hidden=\"true\"\n [slot]=\"buttons.clear?.iconSlot\"\n [name]=\"buttons.clear?.icon\"\n ></ion-icon>\n }\n {{\n locale + '.' + (allowClear ? buttons.clear?.text : 'back')\n | translate\n }}\n </ion-button>\n </div>\n }\n <div>\n <ion-button\n type=\"submit\"\n [expand]=\"action ? 'block' : 'default'\"\n >\n @if (buttons.submit.icon) {\n <ion-icon\n aria-hidden=\"true\"\n [slot]=\"buttons.submit.iconSlot\"\n [name]=\"buttons.submit.icon\"\n ></ion-icon>\n }\n {{\n action ? action : (locale + '.' + buttons.submit.text | translate)\n }}\n </ion-button>\n </div>\n </div>\n }\n </form>\n} @else {\n <section\n #component\n [id]=\"uid\"\n >\n <ngx-decaf-layout\n [className]=\"''\"\n [pk]=\"pk\"\n [isModalChild]=\"isModalChild\"\n [modelId]=\"modelId\"\n [children]=\"children || []\"\n [operation]=\"operation\"\n [cardType]=\"cardType ?? 'blank'\"\n [modelId]=\"modelId\"\n [match]=\"match ?? false\"\n [gap]=\"'small'\"\n [isModalChild]=\"isModalChild\"\n (listenEvent)=\"handleEvent($event)\"\n [flexMode]=\"props.flexMode || false\"\n [rows]=\"rows\"\n [borders]=\"borders ?? false\"\n [breakpoint]=\"breakpoint ?? 'large'\"\n [cols]=\"cols\"\n />\n </section>\n\n <section\n [class]=\"\n 'dcf-buttons-grid dcf-grid dcf-grid-small dcf-flex dcf-flex-left ' +\n operation\n \"\n [id]=\"uid\"\n >\n @if ([OperationKeys.DELETE].includes(operation) && modelId) {\n <div>\n <ion-button\n (click)=\"handleDelete()\"\n color=\"danger\"\n type=\"button\"\n >\n @if (buttons.submit.icon) {\n <ion-icon\n aria-hidden=\"true\"\n [slot]=\"buttons.submit.iconSlot\"\n [name]=\"buttons.submit.icon\"\n ></ion-icon>\n }\n {{ locale + '.delete' | translate }}\n </ion-button>\n </div>\n }\n @if (\n operation === OperationKeys.CREATE || operation === OperationKeys.UPDATE\n ) {\n <div>\n <ion-button type=\"submit\">\n @if (buttons.submit.icon) {\n <ion-icon\n aria-hidden=\"true\"\n [slot]=\"buttons.submit.iconSlot\"\n [name]=\"buttons.submit.icon\"\n ></ion-icon>\n }\n {{\n action\n ? action\n : !translatable\n ? buttons.submit.text\n : (locale + '.' + buttons.submit.text | translate)\n }}\n </ion-button>\n </div>\n }\n <div>\n <ion-button\n fill=\"clear\"\n (click)=\"handleReset()\"\n >\n @if (buttons.clear?.icon) {\n <ion-icon\n aria-hidden=\"true\"\n [slot]=\"buttons.clear?.iconSlot\"\n [name]=\"buttons.clear?.icon\"\n ></ion-icon>\n }\n {{\n !translatable\n ? buttons.clear?.text\n : [\n OperationKeys.DELETE,\n OperationKeys.READ,\n OperationKeys.UPDATE,\n ].includes(operation)\n ? (locale + '.back' | translate)\n : (locale + '.' + buttons.clear.text | translate)\n }}\n </ion-button>\n </div>\n </section>\n}\n", styles: [".dcf-buttons-grid{margin-top:var(--dcf-margin-medium);margin-bottom:var(--dcf-margin)}@media (min-width: 577px){.dcf-buttons-grid.dcf-flex.read,.dcf-buttons-grid.dcf-flex.delete{flex-direction:row-reverse}}@media (max-width: 576px){.dcf-buttons-grid.dcf-flex{flex-direction:column-reverse}.dcf-buttons-grid.dcf-flex>div{width:100%}.dcf-buttons-grid.dcf-flex>div+div{margin-top:1rem}.dcf-buttons-grid.dcf-flex ion-button{width:100%}}.dcf-form-grid.create,.dcf-form-grid.update{margin-top:var(--dcf-margin-small)}.dcf-form-grid .dcf-form-item{margin-top:0!important}.dcf-form-grid.read .dcf-form-item{margin-bottom:var(--dcf-margin-small)}\n"] }]
8729
8739
  }], ctorParameters: () => [], propDecorators: { showCancelButton: [{
8730
8740
  type: Input
8731
8741
  }] } });
@@ -10600,7 +10610,7 @@ let FilterComponent = class FilterComponent extends NgxComponentDirective {
10600
10610
  await this.ngOnDestroy();
10601
10611
  });
10602
10612
  await this.getSortOptions();
10603
- this.initialize();
10613
+ await super.initialize();
10604
10614
  }
10605
10615
  /**
10606
10616
  * @description Retrieves and configures available indexes for filtering and sorting.
@@ -12043,11 +12053,11 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
12043
12053
  * @param {string | number} uid - The ID of the item to create.
12044
12054
  * @returns {Promise<void>} A promise that resolves when the item is created and added to the list.
12045
12055
  */
12046
- async handleCreate(data, uid) {
12047
- if (!data || !Object.keys(data).length) {
12048
- data = (await this._repository?.read(uid));
12056
+ async handleCreate(model, uid) {
12057
+ if (!model || !Object.keys(model).length) {
12058
+ model = (await this._repository?.read(uid));
12049
12059
  }
12050
- const item = (await this.mapResults([data]))[0];
12060
+ const item = (await this.mapResults([model]))[0];
12051
12061
  this.items = this.data = [item, ...(this.items || [])];
12052
12062
  }
12053
12063
  /**
@@ -12059,9 +12069,9 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
12059
12069
  * @private
12060
12070
  * @memberOf ListComponent
12061
12071
  */
12062
- async handleUpdate(item, uid) {
12063
- if (!item || !Object.keys(item).length) {
12064
- item = (await this._repository?.read(uid));
12072
+ async handleUpdate(model, uid) {
12073
+ if (!model || !Object.keys(model).length) {
12074
+ model = (await this._repository?.read(uid));
12065
12075
  }
12066
12076
  // const item: KeyValue = this.itemMapper((await this._repository?.read(uid)) || {}, this.mapper);
12067
12077
  this.data = [];
@@ -12069,8 +12079,8 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
12069
12079
  for (const key in this.items) {
12070
12080
  const child = this.items[key];
12071
12081
  if (`${child['uid']}`.trim() === `${uid}`.trim()) {
12072
- this.items[key] = Object.assign({}, child, this.itemMapper(item || {}, this.mapper), {
12073
- model: item || {},
12082
+ this.items[key] = Object.assign({}, child, this.itemMapper(model || {}, this.mapper), {
12083
+ model: model || {},
12074
12084
  });
12075
12085
  break;
12076
12086
  }
@@ -12591,8 +12601,9 @@ let ListComponent = class ListComponent extends NgxComponentDirective {
12591
12601
  if (arrayValue.length === 1) {
12592
12602
  value = item?.[value] ? item[value] : '';
12593
12603
  // value = item?.[value] ? item[value] : value !== key ? value : "";
12594
- if (isValidDate(value))
12604
+ if (isValidDate(value)) {
12595
12605
  value = `${formatDate(dateFromString(value))}`;
12606
+ }
12596
12607
  accum[key] = value;
12597
12608
  }
12598
12609
  else {
@@ -13904,9 +13915,7 @@ let FileUploadComponent = class FileUploadComponent extends NgxFormFieldDirectiv
13904
13915
  }
13905
13916
  };
13906
13917
  if (this.previewHandler && typeof this.previewHandler === 'function') {
13907
- const clazz = new this.previewHandler();
13908
- const previewFn = clazz.handle.bind(this);
13909
- return previewFn({ data: file });
13918
+ return await this.previewHandler(this, { data: file });
13910
13919
  }
13911
13920
  else {
13912
13921
  content = parseXml(file);
@@ -14067,7 +14076,7 @@ let FileUploadComponent = class FileUploadComponent extends NgxFormFieldDirectiv
14067
14076
  })));
14068
14077
  }
14069
14078
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: FileUploadComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
14070
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: FileUploadComponent, isStandalone: true, selector: "ngx-decaf-file-upload", inputs: { formGroup: "formGroup", name: "name", formControl: "formControl", required: "required", multiple: "multiple", type: "type", valueType: "valueType", buttonLabel: "buttonLabel", size: "size", position: "position", accept: "accept", showIcon: "showIcon", enableDirectoryMode: "enableDirectoryMode", previewHandler: "previewHandler", maxFileSize: "maxFileSize", subType: "subType" }, outputs: { changeEvent: "changeEvent" }, viewQueries: [{ propertyName: "component", first: true, predicate: ["component"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<div\n class=\"decaf-file-component\"\n #component\n>\n <input\n id=\"dcf-file-input\"\n type=\"file\"\n placeholder=\"Select files\"\n [attr.accept]=\"accept\"\n [attr.multiple]=\"multiple ? true : null\"\n (change)=\"handleSelection($event)\"\n [multiple]=\"multiple\"\n hidden\n [attr.webkitdirectory]=\"enableDirectoryMode ? true : null\"\n />\n\n <ngx-decaf-card\n [className]=\"className\"\n [body]=\"'blank'\"\n >\n @if (['create', 'update'].includes(operation)) {\n <div>\n <div\n [class]=\"\n 'dcf-drop-area ' +\n ' dcf-' +\n size +\n ' dcf-flex dcf-flex-' +\n position +\n ' dcf-text-' +\n position\n \"\n [class.dcf-dragging]=\"dragging\"\n [class.dcf-has-files]=\"files.length\"\n (drop)=\"!files?.length ? handleDrop($event) : (dragging = false)\"\n (dragover)=\"\n !files?.length ? handleDragOver($event) : (dragging = false)\n \"\n (dragleave)=\"\n !files?.length ? handleDragLeave($event) : (dragging = false)\n \"\n >\n <div>\n @if (!previewFile) {\n @if (showIcon) {\n <ngx-decaf-icon\n name=\"cloud-upload-outline\"\n size=\"large\"\n />\n }\n <p class=\"dcf-drag-description\">\n {{\n label\n ? (label | translate)\n : (locale + '.drag_file' | translate)\n }}\n </p>\n <ion-button\n class=\"dcf-button-select\"\n (click)=\"handleClickToSelect()\"\n size=\"small\"\n >\n {{\n buttonLabel\n ? (buttonLabel | translate)\n : (locale +\n (enableDirectoryMode\n ? '.buttons.select_directory'\n : '.buttons.select') | translate)\n }}\n </ion-button>\n <div #container>\n <span\n class=\"dcf-error\"\n [innerHTML]=\"getErrors(container)\"\n ></span>\n </div>\n } @else {\n @if (!directoryMode && !multiple) {\n <div\n class=\"dcf-preview dcf-grid dcf-grid-match dcf-grid-collapse\"\n >\n <div\n class=\"dcf-width-1-4@m dcf-width-1-3@s dcf-flex dcf-flex-center dcf-flex-middle\"\n >\n <div class=\"dcf-preview-image\">\n <ion-img\n [src]=\"previewFile\"\n [title]=\"locale + '.preview' | translate\"\n [alt]=\"locale + '.preview' | translate\"\n />\n <div class=\"dcf-overlay\">\n <ion-button\n (click)=\"preview(previewFile)\"\n fill=\"clear\"\n color=\"light\"\n size=\"small\"\n >\n {{ locale + '.buttons.preview' | translate }}\n </ion-button>\n </div>\n </div>\n </div>\n <div\n class=\"description dcf-flex dcf-flex-middle dcf-width-expand@s\"\n >\n <div>\n <p class=\"dcf-title\">\n {{ locale + '.preview' | translate }}\n </p>\n <p class=\"subtitle\">{{ files[0].name }}</p>\n <ion-button\n (click)=\"handleClear()\"\n fill=\"clear\"\n color=\"danger\"\n size=\"small\"\n >\n {{ locale + '.buttons.clear' | translate }}\n </ion-button>\n </div>\n </div>\n </div>\n } @else {\n <div class=\"dcf-margin-bottom\">\n {{ locale + \".selection\" | translate: { \"0\": files.length > 10 ? files.length : `0${files.length}` } }}\n @if (errors.length > 0) {\n <br />\n <span class=\"dcf-error-message\">\n {{ locale + \".selection_error\" | translate: { \"0\": errors.length > 10 ? errors.length : `0${errors.length}` } }}\n </span>\n }\n </div>\n <div class=\"dcf-preview-list-container\">\n <ion-list class=\"dcf-preview-list\">\n @for (file of errors; track $index) {\n <ion-item\n lines=\"full\"\n class=\"dcf-error-item\"\n >\n <ion-label slot=\"start\">{{ file.name }}</ion-label>\n <div\n class=\"dcf-error-message\"\n slot=\"end\"\n >\n {{\n locale + '.errors.' + file.error\n | translate\n : {\n '0':\n file.error === 'max_size'\n ? maxFileSize / 1024 / 1024\n : file.name.split('.'),\n }\n }}\n </div>\n <ion-note slot=\"end\">\n {{ file.size / 1024 / 1024 | number: '1.1-1' }} MB\n </ion-note>\n </ion-item>\n }\n\n @for (file of files; track $index) {\n <ion-item lines=\"full\">\n <ion-label slot=\"start\">{{ file.name }}</ion-label>\n <ion-note slot=\"end\">\n {{ file.size / 1024 / 1024 | number: '1.1-1' }} MB\n </ion-note>\n <div\n class=\"dcf-flex dcf-flex-middle\"\n slot=\"end\"\n >\n <ngx-decaf-icon\n [button]=\"true\"\n [slot]=\"'icon-only'\"\n (click)=\"preview(file?.source || file, file.type)\"\n [name]=\"\n file.type.includes('image')\n ? 'image-outline'\n : 'document-text-outline'\n \"\n />\n <ngx-decaf-icon\n [button]=\"true\"\n [slot]=\"'icon-only'\"\n [name]=\"'trash-outline'\"\n (click)=\"removeFile($index)\"\n [color]=\"'danger'\"\n [size]=\"'small'\"\n />\n </div>\n </ion-item>\n }\n </ion-list>\n </div>\n }\n }\n </div>\n </div>\n </div>\n } @else {\n <div [class]=\"files?.length > 1 ? 'dcf-preview-list-container' : ''\">\n <ion-label [class]=\"operation ?? 'read'\">\n {{ label | translate }}\n </ion-label>\n @if (!files?.length) {\n <div class=\"dcf-padding-xsmall\">\n <ion-text>{{ locale + '.empty' | translate }}</ion-text>\n </div>\n } @else {\n @if (files?.length === 1 && isImageFile(files[0])) {\n <div\n class=\"dcf-preview dcf-grid dcf-grid-match dcf-grid-collapse read\"\n >\n <div\n class=\"dcf-width-1-4@m dcf-width-1-3@s dcf-flex dcf-flex-center dcf-flex-middle\"\n >\n <div class=\"dcf-preview-image\">\n <ion-img\n [src]=\"previewFile\"\n [title]=\"locale + '.preview' | translate\"\n [alt]=\"locale + '.preview' | translate\"\n />\n <div class=\"dcf-overlay\">\n <ion-button\n (click)=\"preview(previewFile)\"\n fill=\"clear\"\n color=\"light\"\n size=\"small\"\n >\n {{ locale + '.buttons.preview' | translate }}\n </ion-button>\n </div>\n </div>\n </div>\n <div\n class=\"description dcf-flex dcf-flex-middle dcf-width-expand@s\"\n >\n <div>\n <p class=\"dcf-title\">{{ locale + '.preview' | translate }}</p>\n <p class=\"subtitle\">{{ files[0].name }}</p>\n </div>\n </div>\n </div>\n } @else {\n <ion-list class=\"dcf-preview-list\">\n @for (file of files; track $index) {\n <ion-item lines=\"full\">\n @if (file?.name) {\n <ion-label slot=\"start\">{{ file.name }}</ion-label>\n }\n <div\n class=\"dcf-flex dcf-flex-middle\"\n slot=\"end\"\n >\n <ngx-decaf-icon\n [button]=\"true\"\n [slot]=\"'icon-only'\"\n (click)=\"preview(file.source, file.type)\"\n [name]=\"\n file.type.includes('image')\n ? 'image-outline'\n : 'document-text-outline'\n \"\n />\n </div>\n </ion-item>\n }\n </ion-list>\n }\n }\n </div>\n }\n </ngx-decaf-card>\n</div>\n", styles: [".decaf-file-component ion-label{font-weight:700;display:block;margin:.75rem;margin-bottom:0!important;font-size:.925rem;font-weight:1rem!important;color:var(--dcf-color-gray-8)!important}.decaf-file-component ion-label ion-text{font-weight:initial;position:relative;top:.8rem}.decaf-file-component.dcf-palette-dark .dcf-button-select{--background: rgb(var(--dcf-color-light-rgb), .1) !important;--background-hover: rgb(var(--dcf-color-light-rgb), .75) !important;--background-activated: rgb(var(--dcf-color-light-rgb), .4) !important;--background-focused: rgb(var(--dcf-color-light-rgb), .4) !important;--color: var(--dcf-color-light) !important}.decaf-file-component.dcf-palette-dark .dcf-has-files{border-style:solid;border-color:var(--dcf-color-gray-6)!important}.decaf-file-component .dcf-upload-icon{--box-shadow: none !important}.decaf-file-component .dcf-upload-icon ion-icon{width:1.5rem!important}.decaf-file-component ion-button.dcf-button-select{--background: rgb(var(--dcf-color-primary-rgb), .1);--background-hover: rgb(var(--dcf-color-primary-rgb), .75);--background-activated: rgb(var(--dcf-color-primary-rgb), .4);--background-focused: rgb(var(--dcf-color-primary-rgb), .4);--color: var(--dcf-color-primary-shade);--border-radius: var(--dcf-border-radius-small);--box-shadow: none;--padding-top: var(--dcf-padding-xsmall);--padding-bottom: var(--dcf-padding-xsmall);--padding-start: var(--dcf-padding-small);--padding-end: var(--dcf-padding-small);font-weight:500;text-transform:none;margin-top:var(--dcf-margin-small)!important}.decaf-file-component .dcf-error{color:var(--dcf-color-danger)!important;font-size:.8rem!important;font-weight:500!important;line-height:1.1rem;z-index:9999;animation-duration:.05s;animation-timing-function:ease-in;animation-fill-mode:both;animation-name:fadeBottomSmallAnimation}.decaf-file-component .dcf-error .ti,.decaf-file-component .dcf-error ion-icon{position:relative;top:2px!important;min-width:20px;font-size:1rem!important;text-align:left}.decaf-file-component ion-card-content{width:100%}.decaf-file-component .dcf-error-message{color:var(--dcf-color-danger);font-size:.875rem}.decaf-file-component .dcf-drag-description{font-size:1rem;line-height:1.5rem;font-weight:500;margin-bottom:var(--dcf-margin-small)}.decaf-file-component .dcf-drop-area{display:flex;align-items:center;border:1.5px dashed var(--dcf-color-gray-3);border-radius:var(--dcf-border-radius-small)!important;transition:border-style .15s ease,border-color .15s ease;background:transparent}.decaf-file-component .dcf-drop-area.dcf-large{min-height:180px}.decaf-file-component .dcf-drop-area>div{width:100%}.decaf-file-component .dcf-drop-area.dcf-has-files{border-style:solid;border-color:var(--dcf-color-primary-shade);transition:border-style .15s ease,border-color .15s ease;padding:var(--dcf-spacement) var(--dcf-spacement-small)!important}.decaf-file-component .dcf-drop-area:not(.dcf-has-files){border-style:dashed;padding:var(--dcf-spacement) var(--dcf-spacement-medium)}.decaf-file-component .dcf-drop-area.dcf-dragging{background:#00000008;border-color:var(--ion-color-primary);box-shadow:0 2px 8px #0000000f}.decaf-file-component .dcf-preview{padding:var(--dcf-padding-xsmall) var(--dcf-spacement-small)!important}.decaf-file-component .dcf-preview.read{padding:var(--dcf-spacement)!important}.decaf-file-component .dcf-preview .dcf-preview-image{border:1px solid var(--dcf-color-gray-3);border-radius:var(--dcf-border-radius-xsmall);max-width:320px;padding:.5rem;box-sizing:border-box;height:160px;position:relative;cursor:pointer;overflow:hidden}.decaf-file-component .dcf-preview .dcf-preview-image ion-img{height:140px!important;display:block;width:100%}.decaf-file-component .dcf-preview .dcf-preview-image:hover .dcf-overlay{opacity:1}.decaf-file-component .dcf-preview .dcf-preview-image .dcf-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background:#0009;display:flex;justify-content:center;align-items:center;opacity:0;transition:opacity .3s ease}.decaf-file-component .dcf-preview .description{text-align:left;padding:1rem;font-size:.75rem}.decaf-file-component .dcf-preview .description .dcf-title{font-size:1rem;font-weight:500}.decaf-file-component .dcf-preview .description ion-button{margin-top:var(--dcf-margin-small)!important}.decaf-file-component .dcf-preview-list-container{max-height:150px;overflow-y:auto}.decaf-file-component .dcf-preview-list-container ion-list{padding:0!important;margin:0!important}@media (max-width: 767px){.decaf-file-component .dcf-preview-list-container ion-list{width:100%;min-width:576px;overflow-x:auto}}.decaf-file-component .dcf-preview-list-container:not(:hover){scrollbar-color:rgba(var(--dcf-color-medium-rgb),.125) transparent!important}.decaf-file-component .dcf-preview-list-container ion-item{font-size:.875rem!important}.decaf-file-component .dcf-preview-list-container ion-item.dcf-error-item{--background: rgba(var(--dcf-color-danger-rgb), .02) !important;--border-color: rgba(var(--dcf-color-danger-rgb), .2) !important}.decaf-file-component .dcf-preview-list-container ion-item ion-item{--padding-top: .25rem;--padding-bottom: 0rem;--inner-padding-start: 0rem;--padding-start: var(--dcf-padding-xsmall) !important;--padding-end: 0rem;--inner-padding-end: var(--dcf-padding-xsmall) !important;--background-hover: var(--dcf-color-gray-8);--background-focused: var(--dcf-color-gray-8);--background-hover-opacity: .1;--background-focused-opacity: .1;--border-color: var(--dcf-color-gray-2)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: CardComponent, selector: "ngx-decaf-card", inputs: ["type", "title", "body", "subtitle", "color", "separator", "borders", "inlineContent", "inlineContentPosition"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IconComponent, selector: "ngx-decaf-icon", inputs: ["name", "color", "slot", "button", "buttonFill", "buttonShape", "width", "size", "inline"] }, { kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "pipe", type: i1$1.DecimalPipe, name: "number" }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
14079
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: FileUploadComponent, isStandalone: true, selector: "ngx-decaf-file-upload", inputs: { formGroup: "formGroup", name: "name", formControl: "formControl", required: "required", multiple: "multiple", type: "type", valueType: "valueType", buttonLabel: "buttonLabel", size: "size", position: "position", accept: "accept", showIcon: "showIcon", enableDirectoryMode: "enableDirectoryMode", previewHandler: "previewHandler", maxFileSize: "maxFileSize", subType: "subType" }, outputs: { changeEvent: "changeEvent" }, viewQueries: [{ propertyName: "component", first: true, predicate: ["component"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<div\n class=\"decaf-file-component\"\n #component\n>\n <input\n id=\"dcf-file-input\"\n type=\"file\"\n placeholder=\"Select files\"\n [attr.accept]=\"accept\"\n [attr.multiple]=\"multiple ? true : null\"\n (change)=\"handleSelection($event)\"\n [multiple]=\"multiple\"\n hidden\n [attr.webkitdirectory]=\"enableDirectoryMode ? true : null\"\n />\n\n <ngx-decaf-card\n [className]=\"className\"\n [body]=\"'blank'\"\n >\n @if (['create', 'update'].includes(operation)) {\n <div>\n <div\n [class]=\"\n 'dcf-drop-area ' +\n ' dcf-' +\n size +\n ' dcf-flex dcf-flex-' +\n position +\n ' dcf-text-' +\n position\n \"\n [class.dcf-dragging]=\"dragging\"\n [class.dcf-has-files]=\"files.length\"\n (drop)=\"!files?.length ? handleDrop($event) : (dragging = false)\"\n (dragover)=\"\n !files?.length ? handleDragOver($event) : (dragging = false)\n \"\n (dragleave)=\"\n !files?.length ? handleDragLeave($event) : (dragging = false)\n \"\n >\n <div>\n @if (!previewFile) {\n @if (showIcon) {\n <ngx-decaf-icon\n name=\"cloud-upload-outline\"\n size=\"large\"\n />\n }\n <p class=\"dcf-drag-description\">\n {{\n label\n ? (label | translate)\n : (locale + '.drag_file' | translate)\n }}\n </p>\n <ion-button\n class=\"dcf-button-select\"\n (click)=\"handleClickToSelect()\"\n size=\"small\"\n >\n {{\n buttonLabel\n ? (buttonLabel | translate)\n : (locale +\n (enableDirectoryMode\n ? '.buttons.select_directory'\n : '.buttons.select') | translate)\n }}\n </ion-button>\n <div #container>\n <span\n class=\"dcf-error\"\n [innerHTML]=\"getErrors(container)\"\n ></span>\n </div>\n } @else {\n @if (!directoryMode && !multiple) {\n <div\n class=\"dcf-preview dcf-grid dcf-grid-match dcf-grid-collapse\"\n >\n <div\n class=\"dcf-width-1-4@m dcf-width-1-3@s dcf-flex dcf-flex-center dcf-flex-middle\"\n >\n <div class=\"dcf-preview-image\">\n <ion-img\n [src]=\"previewFile\"\n [title]=\"locale + '.preview' | translate\"\n [alt]=\"locale + '.preview' | translate\"\n />\n <div class=\"dcf-overlay\">\n <ion-button\n (click)=\"preview(previewFile)\"\n fill=\"clear\"\n color=\"light\"\n size=\"small\"\n >\n {{ locale + '.buttons.preview' | translate }}\n </ion-button>\n </div>\n </div>\n </div>\n <div\n class=\"description dcf-flex dcf-flex-middle dcf-width-expand@s\"\n >\n <div>\n <p class=\"dcf-title\">\n {{ locale + '.preview' | translate }}\n </p>\n <p class=\"subtitle\">{{ files[0].name }}</p>\n <ion-button\n (click)=\"handleClear()\"\n fill=\"clear\"\n color=\"danger\"\n size=\"small\"\n >\n {{ locale + '.buttons.clear' | translate }}\n </ion-button>\n </div>\n </div>\n </div>\n } @else {\n <div class=\"dcf-margin-bottom\">\n {{ locale + \".selection\" | translate: { \"0\": files.length > 10 ? files.length : `0${files.length}` } }}\n @if (errors.length > 0) {\n <br />\n <span class=\"dcf-error-message\">\n {{ locale + \".selection_error\" | translate: { \"0\": errors.length > 10 ? errors.length : `0${errors.length}` } }}\n </span>\n }\n </div>\n <div class=\"dcf-preview-list-container\">\n <ion-list class=\"dcf-preview-list\">\n @for (file of errors; track $index) {\n <ion-item\n lines=\"full\"\n class=\"dcf-error-item\"\n >\n <ion-label slot=\"start\">{{ file.name }}</ion-label>\n <div\n class=\"dcf-error-message\"\n slot=\"end\"\n >\n {{\n locale + '.errors.' + file.error\n | translate\n : {\n '0':\n file.error === 'max_size'\n ? maxFileSize / 1024 / 1024\n : file.name.split('.'),\n }\n }}\n </div>\n <ion-note slot=\"end\">\n {{ file.size / 1024 / 1024 | number: '1.1-1' }} MB\n </ion-note>\n </ion-item>\n }\n\n @for (file of files; track $index) {\n <ion-item lines=\"full\">\n <ion-label slot=\"start\">{{ file.name }}</ion-label>\n <ion-note slot=\"end\">\n {{ file.size / 1024 / 1024 | number: '1.1-1' }} MB\n </ion-note>\n <div\n class=\"dcf-flex dcf-flex-middle\"\n slot=\"end\"\n >\n <ngx-decaf-icon\n [button]=\"true\"\n [slot]=\"'icon-only'\"\n (click)=\"preview(file?.source || file, file.type)\"\n [name]=\"\n file.type.includes('image')\n ? 'image-outline'\n : 'document-text-outline'\n \"\n />\n <ngx-decaf-icon\n [button]=\"true\"\n [slot]=\"'icon-only'\"\n [name]=\"'trash-outline'\"\n (click)=\"removeFile($index)\"\n [color]=\"'danger'\"\n [size]=\"'small'\"\n />\n </div>\n </ion-item>\n }\n </ion-list>\n </div>\n }\n }\n </div>\n </div>\n </div>\n } @else {\n <div [class]=\"files?.length > 1 ? 'dcf-preview-list-container' : ''\">\n <ion-label [class]=\"operation ?? 'read'\">\n {{ label | translate }}\n </ion-label>\n @if (!files?.length) {\n <div class=\"dcf-padding-xsmall\">\n @if (!refreshing && initialized) {\n <ion-text>{{ locale + '.empty' | translate }}</ion-text>\n } @else {\n <ion-skeleton-text animated></ion-skeleton-text>\n }\n </div>\n } @else {\n @if (files?.length === 1 && isImageFile(files[0])) {\n <div\n class=\"dcf-preview dcf-grid dcf-grid-match dcf-grid-collapse read dcf-single-file\"\n >\n <div\n class=\"dcf-width-1-4@m dcf-width-1-3@s dcf-flex dcf-flex-center dcf-flex-middle\"\n >\n <div class=\"dcf-preview-image\">\n <ion-img\n [src]=\"previewFile\"\n [title]=\"locale + '.preview' | translate\"\n [alt]=\"locale + '.preview' | translate\"\n />\n <div class=\"dcf-overlay\">\n <ion-button\n (click)=\"preview(previewFile)\"\n fill=\"clear\"\n color=\"light\"\n size=\"small\"\n >\n {{ locale + '.buttons.preview' | translate }}\n </ion-button>\n </div>\n </div>\n </div>\n <div\n class=\"description dcf-flex dcf-flex-middle dcf-width-expand@s\"\n >\n <div>\n <p class=\"dcf-title\">{{ locale + '.preview' | translate }}</p>\n <p class=\"subtitle\">{{ files[0].name }}</p>\n </div>\n </div>\n </div>\n } @else {\n <ion-list class=\"dcf-preview-list\">\n @for (file of files; track $index) {\n <ion-item\n [lines]=\"files?.length > 1 ? 'full' : 'none'\"\n (click)=\"preview(file.source, file.type)\"\n >\n @if (file?.name) {\n <ion-label slot=\"start\">\n {{ files?.length > 1 ? file.name : name }}\n </ion-label>\n }\n <div\n class=\"dcf-flex dcf-flex-middle\"\n slot=\"end\"\n >\n <ngx-decaf-icon\n [button]=\"true\"\n [slot]=\"'icon-only'\"\n [name]=\"\n file.type.includes('image')\n ? 'image-outline'\n : 'document-text-outline'\n \"\n />\n </div>\n </ion-item>\n }\n </ion-list>\n }\n }\n </div>\n }\n </ngx-decaf-card>\n</div>\n", styles: [".decaf-file-component ion-label{font-weight:700;display:block;margin:.75rem;margin-bottom:0!important;font-size:.925rem;font-weight:1rem!important;color:var(--dcf-color-gray-8)!important}.decaf-file-component ion-label ion-text{font-weight:initial;position:relative;top:.8rem}.decaf-file-component.dcf-palette-dark .dcf-button-select{--background: rgb(var(--dcf-color-light-rgb), .1) !important;--background-hover: rgb(var(--dcf-color-light-rgb), .75) !important;--background-activated: rgb(var(--dcf-color-light-rgb), .4) !important;--background-focused: rgb(var(--dcf-color-light-rgb), .4) !important;--color: var(--dcf-color-light) !important}.decaf-file-component.dcf-palette-dark .dcf-has-files{border-style:solid;border-color:var(--dcf-color-gray-6)!important}.decaf-file-component .dcf-upload-icon{--box-shadow: none !important}.decaf-file-component .dcf-upload-icon ion-icon{width:1.5rem!important}.decaf-file-component ion-skeleton-text{width:100%!important;height:1rem!important}.decaf-file-component ion-button.dcf-button-select{--background: rgb(var(--dcf-color-primary-rgb), .1);--background-hover: rgb(var(--dcf-color-primary-rgb), .75);--background-activated: rgb(var(--dcf-color-primary-rgb), .4);--background-focused: rgb(var(--dcf-color-primary-rgb), .4);--color: var(--dcf-color-primary-shade);--border-radius: var(--dcf-border-radius-small);--box-shadow: none;--padding-top: var(--dcf-padding-xsmall);--padding-bottom: var(--dcf-padding-xsmall);--padding-start: var(--dcf-padding-small);--padding-end: var(--dcf-padding-small);font-weight:500;text-transform:none;margin-top:var(--dcf-margin-small)!important}.decaf-file-component .dcf-error{color:var(--dcf-color-danger)!important;font-size:.8rem!important;font-weight:500!important;line-height:1.1rem;z-index:9999;animation-duration:.05s;animation-timing-function:ease-in;animation-fill-mode:both;animation-name:fadeBottomSmallAnimation}.decaf-file-component .dcf-error .ti,.decaf-file-component .dcf-error ion-icon{position:relative;top:2px!important;min-width:20px;font-size:1rem!important;text-align:left}.decaf-file-component ion-card-content{width:100%}.decaf-file-component .dcf-error-message{color:var(--dcf-color-danger);font-size:.875rem}.decaf-file-component .dcf-drag-description{font-size:1rem;line-height:1.5rem;font-weight:500;margin-bottom:var(--dcf-margin-small)}.decaf-file-component .dcf-drop-area{display:flex;align-items:center;border:1.5px dashed var(--dcf-color-gray-3);border-radius:var(--dcf-border-radius-small)!important;transition:border-style .15s ease,border-color .15s ease;background:transparent}.decaf-file-component .dcf-drop-area.dcf-large{min-height:180px}.decaf-file-component .dcf-drop-area>div{width:100%}.decaf-file-component .dcf-drop-area.dcf-has-files{border-style:solid;border-color:var(--dcf-color-primary-shade);transition:border-style .15s ease,border-color .15s ease;padding:var(--dcf-spacement) var(--dcf-spacement-small)!important}.decaf-file-component .dcf-drop-area:not(.dcf-has-files){border-style:dashed;padding:var(--dcf-spacement) var(--dcf-spacement-medium)}.decaf-file-component .dcf-drop-area.dcf-dragging{background:#00000008;border-color:var(--ion-color-primary);box-shadow:0 2px 8px #0000000f}.decaf-file-component .dcf-preview{padding:var(--dcf-padding-xsmall) var(--dcf-spacement-small)!important}.decaf-file-component .dcf-preview.read{padding:var(--dcf-spacement)!important}.decaf-file-component .dcf-preview .dcf-preview-image{border:1px solid var(--dcf-color-gray-3);border-radius:var(--dcf-border-radius-xsmall);max-width:320px;padding:.5rem;box-sizing:border-box;height:160px;position:relative;cursor:pointer;overflow:hidden}.decaf-file-component .dcf-preview .dcf-preview-image ion-img{height:140px!important;display:block;width:100%}.decaf-file-component .dcf-preview .dcf-preview-image:hover .dcf-overlay{opacity:1}.decaf-file-component .dcf-preview .dcf-preview-image .dcf-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background:#0009;display:flex;justify-content:center;align-items:center;opacity:0;transition:opacity .3s ease}.decaf-file-component .dcf-preview .description{text-align:left;padding:1rem;font-size:.75rem}.decaf-file-component .dcf-preview .description .dcf-title{font-size:1rem;font-weight:500}.decaf-file-component .dcf-preview .description ion-button{margin-top:var(--dcf-margin-small)!important}.decaf-file-component .dcf-preview-list-container{max-height:150px;overflow-y:auto}.decaf-file-component .dcf-preview-list-container ion-list{padding:0!important;margin:0!important}@media (max-width: 767px){.decaf-file-component .dcf-preview-list-container ion-list{width:100%;min-width:576px;overflow-x:auto}}.decaf-file-component .dcf-preview-list-container:not(:hover){scrollbar-color:rgba(var(--dcf-color-medium-rgb),.125) transparent!important}.decaf-file-component .dcf-preview-list-container ion-item{font-size:.875rem!important}.decaf-file-component .dcf-preview-list-container ion-item.dcf-error-item{--background: rgba(var(--dcf-color-danger-rgb), .02) !important;--border-color: rgba(var(--dcf-color-danger-rgb), .2) !important}.decaf-file-component .dcf-preview-list-container ion-item ion-item{--padding-top: .25rem;--padding-bottom: 0rem;--inner-padding-start: 0rem;--padding-start: var(--dcf-padding-xsmall) !important;--padding-end: 0rem;--inner-padding-end: var(--dcf-padding-xsmall) !important;--background-hover: var(--dcf-color-gray-8);--background-focused: var(--dcf-color-gray-8);--background-hover-opacity: .1;--background-focused-opacity: .1;--border-color: var(--dcf-color-gray-2)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: CardComponent, selector: "ngx-decaf-card", inputs: ["type", "title", "body", "subtitle", "color", "separator", "borders", "inlineContent", "inlineContentPosition"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IconComponent, selector: "ngx-decaf-icon", inputs: ["name", "color", "slot", "button", "buttonFill", "buttonShape", "width", "size", "inline"] }, { kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "pipe", type: i1$1.DecimalPipe, name: "number" }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
14071
14080
  };
14072
14081
  FileUploadComponent = __decorate([
14073
14082
  Dynamic(),
@@ -14086,7 +14095,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
14086
14095
  IonItem,
14087
14096
  TranslatePipe,
14088
14097
  IonButton,
14089
- ], template: "<div\n class=\"decaf-file-component\"\n #component\n>\n <input\n id=\"dcf-file-input\"\n type=\"file\"\n placeholder=\"Select files\"\n [attr.accept]=\"accept\"\n [attr.multiple]=\"multiple ? true : null\"\n (change)=\"handleSelection($event)\"\n [multiple]=\"multiple\"\n hidden\n [attr.webkitdirectory]=\"enableDirectoryMode ? true : null\"\n />\n\n <ngx-decaf-card\n [className]=\"className\"\n [body]=\"'blank'\"\n >\n @if (['create', 'update'].includes(operation)) {\n <div>\n <div\n [class]=\"\n 'dcf-drop-area ' +\n ' dcf-' +\n size +\n ' dcf-flex dcf-flex-' +\n position +\n ' dcf-text-' +\n position\n \"\n [class.dcf-dragging]=\"dragging\"\n [class.dcf-has-files]=\"files.length\"\n (drop)=\"!files?.length ? handleDrop($event) : (dragging = false)\"\n (dragover)=\"\n !files?.length ? handleDragOver($event) : (dragging = false)\n \"\n (dragleave)=\"\n !files?.length ? handleDragLeave($event) : (dragging = false)\n \"\n >\n <div>\n @if (!previewFile) {\n @if (showIcon) {\n <ngx-decaf-icon\n name=\"cloud-upload-outline\"\n size=\"large\"\n />\n }\n <p class=\"dcf-drag-description\">\n {{\n label\n ? (label | translate)\n : (locale + '.drag_file' | translate)\n }}\n </p>\n <ion-button\n class=\"dcf-button-select\"\n (click)=\"handleClickToSelect()\"\n size=\"small\"\n >\n {{\n buttonLabel\n ? (buttonLabel | translate)\n : (locale +\n (enableDirectoryMode\n ? '.buttons.select_directory'\n : '.buttons.select') | translate)\n }}\n </ion-button>\n <div #container>\n <span\n class=\"dcf-error\"\n [innerHTML]=\"getErrors(container)\"\n ></span>\n </div>\n } @else {\n @if (!directoryMode && !multiple) {\n <div\n class=\"dcf-preview dcf-grid dcf-grid-match dcf-grid-collapse\"\n >\n <div\n class=\"dcf-width-1-4@m dcf-width-1-3@s dcf-flex dcf-flex-center dcf-flex-middle\"\n >\n <div class=\"dcf-preview-image\">\n <ion-img\n [src]=\"previewFile\"\n [title]=\"locale + '.preview' | translate\"\n [alt]=\"locale + '.preview' | translate\"\n />\n <div class=\"dcf-overlay\">\n <ion-button\n (click)=\"preview(previewFile)\"\n fill=\"clear\"\n color=\"light\"\n size=\"small\"\n >\n {{ locale + '.buttons.preview' | translate }}\n </ion-button>\n </div>\n </div>\n </div>\n <div\n class=\"description dcf-flex dcf-flex-middle dcf-width-expand@s\"\n >\n <div>\n <p class=\"dcf-title\">\n {{ locale + '.preview' | translate }}\n </p>\n <p class=\"subtitle\">{{ files[0].name }}</p>\n <ion-button\n (click)=\"handleClear()\"\n fill=\"clear\"\n color=\"danger\"\n size=\"small\"\n >\n {{ locale + '.buttons.clear' | translate }}\n </ion-button>\n </div>\n </div>\n </div>\n } @else {\n <div class=\"dcf-margin-bottom\">\n {{ locale + \".selection\" | translate: { \"0\": files.length > 10 ? files.length : `0${files.length}` } }}\n @if (errors.length > 0) {\n <br />\n <span class=\"dcf-error-message\">\n {{ locale + \".selection_error\" | translate: { \"0\": errors.length > 10 ? errors.length : `0${errors.length}` } }}\n </span>\n }\n </div>\n <div class=\"dcf-preview-list-container\">\n <ion-list class=\"dcf-preview-list\">\n @for (file of errors; track $index) {\n <ion-item\n lines=\"full\"\n class=\"dcf-error-item\"\n >\n <ion-label slot=\"start\">{{ file.name }}</ion-label>\n <div\n class=\"dcf-error-message\"\n slot=\"end\"\n >\n {{\n locale + '.errors.' + file.error\n | translate\n : {\n '0':\n file.error === 'max_size'\n ? maxFileSize / 1024 / 1024\n : file.name.split('.'),\n }\n }}\n </div>\n <ion-note slot=\"end\">\n {{ file.size / 1024 / 1024 | number: '1.1-1' }} MB\n </ion-note>\n </ion-item>\n }\n\n @for (file of files; track $index) {\n <ion-item lines=\"full\">\n <ion-label slot=\"start\">{{ file.name }}</ion-label>\n <ion-note slot=\"end\">\n {{ file.size / 1024 / 1024 | number: '1.1-1' }} MB\n </ion-note>\n <div\n class=\"dcf-flex dcf-flex-middle\"\n slot=\"end\"\n >\n <ngx-decaf-icon\n [button]=\"true\"\n [slot]=\"'icon-only'\"\n (click)=\"preview(file?.source || file, file.type)\"\n [name]=\"\n file.type.includes('image')\n ? 'image-outline'\n : 'document-text-outline'\n \"\n />\n <ngx-decaf-icon\n [button]=\"true\"\n [slot]=\"'icon-only'\"\n [name]=\"'trash-outline'\"\n (click)=\"removeFile($index)\"\n [color]=\"'danger'\"\n [size]=\"'small'\"\n />\n </div>\n </ion-item>\n }\n </ion-list>\n </div>\n }\n }\n </div>\n </div>\n </div>\n } @else {\n <div [class]=\"files?.length > 1 ? 'dcf-preview-list-container' : ''\">\n <ion-label [class]=\"operation ?? 'read'\">\n {{ label | translate }}\n </ion-label>\n @if (!files?.length) {\n <div class=\"dcf-padding-xsmall\">\n <ion-text>{{ locale + '.empty' | translate }}</ion-text>\n </div>\n } @else {\n @if (files?.length === 1 && isImageFile(files[0])) {\n <div\n class=\"dcf-preview dcf-grid dcf-grid-match dcf-grid-collapse read\"\n >\n <div\n class=\"dcf-width-1-4@m dcf-width-1-3@s dcf-flex dcf-flex-center dcf-flex-middle\"\n >\n <div class=\"dcf-preview-image\">\n <ion-img\n [src]=\"previewFile\"\n [title]=\"locale + '.preview' | translate\"\n [alt]=\"locale + '.preview' | translate\"\n />\n <div class=\"dcf-overlay\">\n <ion-button\n (click)=\"preview(previewFile)\"\n fill=\"clear\"\n color=\"light\"\n size=\"small\"\n >\n {{ locale + '.buttons.preview' | translate }}\n </ion-button>\n </div>\n </div>\n </div>\n <div\n class=\"description dcf-flex dcf-flex-middle dcf-width-expand@s\"\n >\n <div>\n <p class=\"dcf-title\">{{ locale + '.preview' | translate }}</p>\n <p class=\"subtitle\">{{ files[0].name }}</p>\n </div>\n </div>\n </div>\n } @else {\n <ion-list class=\"dcf-preview-list\">\n @for (file of files; track $index) {\n <ion-item lines=\"full\">\n @if (file?.name) {\n <ion-label slot=\"start\">{{ file.name }}</ion-label>\n }\n <div\n class=\"dcf-flex dcf-flex-middle\"\n slot=\"end\"\n >\n <ngx-decaf-icon\n [button]=\"true\"\n [slot]=\"'icon-only'\"\n (click)=\"preview(file.source, file.type)\"\n [name]=\"\n file.type.includes('image')\n ? 'image-outline'\n : 'document-text-outline'\n \"\n />\n </div>\n </ion-item>\n }\n </ion-list>\n }\n }\n </div>\n }\n </ngx-decaf-card>\n</div>\n", styles: [".decaf-file-component ion-label{font-weight:700;display:block;margin:.75rem;margin-bottom:0!important;font-size:.925rem;font-weight:1rem!important;color:var(--dcf-color-gray-8)!important}.decaf-file-component ion-label ion-text{font-weight:initial;position:relative;top:.8rem}.decaf-file-component.dcf-palette-dark .dcf-button-select{--background: rgb(var(--dcf-color-light-rgb), .1) !important;--background-hover: rgb(var(--dcf-color-light-rgb), .75) !important;--background-activated: rgb(var(--dcf-color-light-rgb), .4) !important;--background-focused: rgb(var(--dcf-color-light-rgb), .4) !important;--color: var(--dcf-color-light) !important}.decaf-file-component.dcf-palette-dark .dcf-has-files{border-style:solid;border-color:var(--dcf-color-gray-6)!important}.decaf-file-component .dcf-upload-icon{--box-shadow: none !important}.decaf-file-component .dcf-upload-icon ion-icon{width:1.5rem!important}.decaf-file-component ion-button.dcf-button-select{--background: rgb(var(--dcf-color-primary-rgb), .1);--background-hover: rgb(var(--dcf-color-primary-rgb), .75);--background-activated: rgb(var(--dcf-color-primary-rgb), .4);--background-focused: rgb(var(--dcf-color-primary-rgb), .4);--color: var(--dcf-color-primary-shade);--border-radius: var(--dcf-border-radius-small);--box-shadow: none;--padding-top: var(--dcf-padding-xsmall);--padding-bottom: var(--dcf-padding-xsmall);--padding-start: var(--dcf-padding-small);--padding-end: var(--dcf-padding-small);font-weight:500;text-transform:none;margin-top:var(--dcf-margin-small)!important}.decaf-file-component .dcf-error{color:var(--dcf-color-danger)!important;font-size:.8rem!important;font-weight:500!important;line-height:1.1rem;z-index:9999;animation-duration:.05s;animation-timing-function:ease-in;animation-fill-mode:both;animation-name:fadeBottomSmallAnimation}.decaf-file-component .dcf-error .ti,.decaf-file-component .dcf-error ion-icon{position:relative;top:2px!important;min-width:20px;font-size:1rem!important;text-align:left}.decaf-file-component ion-card-content{width:100%}.decaf-file-component .dcf-error-message{color:var(--dcf-color-danger);font-size:.875rem}.decaf-file-component .dcf-drag-description{font-size:1rem;line-height:1.5rem;font-weight:500;margin-bottom:var(--dcf-margin-small)}.decaf-file-component .dcf-drop-area{display:flex;align-items:center;border:1.5px dashed var(--dcf-color-gray-3);border-radius:var(--dcf-border-radius-small)!important;transition:border-style .15s ease,border-color .15s ease;background:transparent}.decaf-file-component .dcf-drop-area.dcf-large{min-height:180px}.decaf-file-component .dcf-drop-area>div{width:100%}.decaf-file-component .dcf-drop-area.dcf-has-files{border-style:solid;border-color:var(--dcf-color-primary-shade);transition:border-style .15s ease,border-color .15s ease;padding:var(--dcf-spacement) var(--dcf-spacement-small)!important}.decaf-file-component .dcf-drop-area:not(.dcf-has-files){border-style:dashed;padding:var(--dcf-spacement) var(--dcf-spacement-medium)}.decaf-file-component .dcf-drop-area.dcf-dragging{background:#00000008;border-color:var(--ion-color-primary);box-shadow:0 2px 8px #0000000f}.decaf-file-component .dcf-preview{padding:var(--dcf-padding-xsmall) var(--dcf-spacement-small)!important}.decaf-file-component .dcf-preview.read{padding:var(--dcf-spacement)!important}.decaf-file-component .dcf-preview .dcf-preview-image{border:1px solid var(--dcf-color-gray-3);border-radius:var(--dcf-border-radius-xsmall);max-width:320px;padding:.5rem;box-sizing:border-box;height:160px;position:relative;cursor:pointer;overflow:hidden}.decaf-file-component .dcf-preview .dcf-preview-image ion-img{height:140px!important;display:block;width:100%}.decaf-file-component .dcf-preview .dcf-preview-image:hover .dcf-overlay{opacity:1}.decaf-file-component .dcf-preview .dcf-preview-image .dcf-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background:#0009;display:flex;justify-content:center;align-items:center;opacity:0;transition:opacity .3s ease}.decaf-file-component .dcf-preview .description{text-align:left;padding:1rem;font-size:.75rem}.decaf-file-component .dcf-preview .description .dcf-title{font-size:1rem;font-weight:500}.decaf-file-component .dcf-preview .description ion-button{margin-top:var(--dcf-margin-small)!important}.decaf-file-component .dcf-preview-list-container{max-height:150px;overflow-y:auto}.decaf-file-component .dcf-preview-list-container ion-list{padding:0!important;margin:0!important}@media (max-width: 767px){.decaf-file-component .dcf-preview-list-container ion-list{width:100%;min-width:576px;overflow-x:auto}}.decaf-file-component .dcf-preview-list-container:not(:hover){scrollbar-color:rgba(var(--dcf-color-medium-rgb),.125) transparent!important}.decaf-file-component .dcf-preview-list-container ion-item{font-size:.875rem!important}.decaf-file-component .dcf-preview-list-container ion-item.dcf-error-item{--background: rgba(var(--dcf-color-danger-rgb), .02) !important;--border-color: rgba(var(--dcf-color-danger-rgb), .2) !important}.decaf-file-component .dcf-preview-list-container ion-item ion-item{--padding-top: .25rem;--padding-bottom: 0rem;--inner-padding-start: 0rem;--padding-start: var(--dcf-padding-xsmall) !important;--padding-end: 0rem;--inner-padding-end: var(--dcf-padding-xsmall) !important;--background-hover: var(--dcf-color-gray-8);--background-focused: var(--dcf-color-gray-8);--background-hover-opacity: .1;--background-focused-opacity: .1;--border-color: var(--dcf-color-gray-2)}\n"] }]
14098
+ ], template: "<div\n class=\"decaf-file-component\"\n #component\n>\n <input\n id=\"dcf-file-input\"\n type=\"file\"\n placeholder=\"Select files\"\n [attr.accept]=\"accept\"\n [attr.multiple]=\"multiple ? true : null\"\n (change)=\"handleSelection($event)\"\n [multiple]=\"multiple\"\n hidden\n [attr.webkitdirectory]=\"enableDirectoryMode ? true : null\"\n />\n\n <ngx-decaf-card\n [className]=\"className\"\n [body]=\"'blank'\"\n >\n @if (['create', 'update'].includes(operation)) {\n <div>\n <div\n [class]=\"\n 'dcf-drop-area ' +\n ' dcf-' +\n size +\n ' dcf-flex dcf-flex-' +\n position +\n ' dcf-text-' +\n position\n \"\n [class.dcf-dragging]=\"dragging\"\n [class.dcf-has-files]=\"files.length\"\n (drop)=\"!files?.length ? handleDrop($event) : (dragging = false)\"\n (dragover)=\"\n !files?.length ? handleDragOver($event) : (dragging = false)\n \"\n (dragleave)=\"\n !files?.length ? handleDragLeave($event) : (dragging = false)\n \"\n >\n <div>\n @if (!previewFile) {\n @if (showIcon) {\n <ngx-decaf-icon\n name=\"cloud-upload-outline\"\n size=\"large\"\n />\n }\n <p class=\"dcf-drag-description\">\n {{\n label\n ? (label | translate)\n : (locale + '.drag_file' | translate)\n }}\n </p>\n <ion-button\n class=\"dcf-button-select\"\n (click)=\"handleClickToSelect()\"\n size=\"small\"\n >\n {{\n buttonLabel\n ? (buttonLabel | translate)\n : (locale +\n (enableDirectoryMode\n ? '.buttons.select_directory'\n : '.buttons.select') | translate)\n }}\n </ion-button>\n <div #container>\n <span\n class=\"dcf-error\"\n [innerHTML]=\"getErrors(container)\"\n ></span>\n </div>\n } @else {\n @if (!directoryMode && !multiple) {\n <div\n class=\"dcf-preview dcf-grid dcf-grid-match dcf-grid-collapse\"\n >\n <div\n class=\"dcf-width-1-4@m dcf-width-1-3@s dcf-flex dcf-flex-center dcf-flex-middle\"\n >\n <div class=\"dcf-preview-image\">\n <ion-img\n [src]=\"previewFile\"\n [title]=\"locale + '.preview' | translate\"\n [alt]=\"locale + '.preview' | translate\"\n />\n <div class=\"dcf-overlay\">\n <ion-button\n (click)=\"preview(previewFile)\"\n fill=\"clear\"\n color=\"light\"\n size=\"small\"\n >\n {{ locale + '.buttons.preview' | translate }}\n </ion-button>\n </div>\n </div>\n </div>\n <div\n class=\"description dcf-flex dcf-flex-middle dcf-width-expand@s\"\n >\n <div>\n <p class=\"dcf-title\">\n {{ locale + '.preview' | translate }}\n </p>\n <p class=\"subtitle\">{{ files[0].name }}</p>\n <ion-button\n (click)=\"handleClear()\"\n fill=\"clear\"\n color=\"danger\"\n size=\"small\"\n >\n {{ locale + '.buttons.clear' | translate }}\n </ion-button>\n </div>\n </div>\n </div>\n } @else {\n <div class=\"dcf-margin-bottom\">\n {{ locale + \".selection\" | translate: { \"0\": files.length > 10 ? files.length : `0${files.length}` } }}\n @if (errors.length > 0) {\n <br />\n <span class=\"dcf-error-message\">\n {{ locale + \".selection_error\" | translate: { \"0\": errors.length > 10 ? errors.length : `0${errors.length}` } }}\n </span>\n }\n </div>\n <div class=\"dcf-preview-list-container\">\n <ion-list class=\"dcf-preview-list\">\n @for (file of errors; track $index) {\n <ion-item\n lines=\"full\"\n class=\"dcf-error-item\"\n >\n <ion-label slot=\"start\">{{ file.name }}</ion-label>\n <div\n class=\"dcf-error-message\"\n slot=\"end\"\n >\n {{\n locale + '.errors.' + file.error\n | translate\n : {\n '0':\n file.error === 'max_size'\n ? maxFileSize / 1024 / 1024\n : file.name.split('.'),\n }\n }}\n </div>\n <ion-note slot=\"end\">\n {{ file.size / 1024 / 1024 | number: '1.1-1' }} MB\n </ion-note>\n </ion-item>\n }\n\n @for (file of files; track $index) {\n <ion-item lines=\"full\">\n <ion-label slot=\"start\">{{ file.name }}</ion-label>\n <ion-note slot=\"end\">\n {{ file.size / 1024 / 1024 | number: '1.1-1' }} MB\n </ion-note>\n <div\n class=\"dcf-flex dcf-flex-middle\"\n slot=\"end\"\n >\n <ngx-decaf-icon\n [button]=\"true\"\n [slot]=\"'icon-only'\"\n (click)=\"preview(file?.source || file, file.type)\"\n [name]=\"\n file.type.includes('image')\n ? 'image-outline'\n : 'document-text-outline'\n \"\n />\n <ngx-decaf-icon\n [button]=\"true\"\n [slot]=\"'icon-only'\"\n [name]=\"'trash-outline'\"\n (click)=\"removeFile($index)\"\n [color]=\"'danger'\"\n [size]=\"'small'\"\n />\n </div>\n </ion-item>\n }\n </ion-list>\n </div>\n }\n }\n </div>\n </div>\n </div>\n } @else {\n <div [class]=\"files?.length > 1 ? 'dcf-preview-list-container' : ''\">\n <ion-label [class]=\"operation ?? 'read'\">\n {{ label | translate }}\n </ion-label>\n @if (!files?.length) {\n <div class=\"dcf-padding-xsmall\">\n @if (!refreshing && initialized) {\n <ion-text>{{ locale + '.empty' | translate }}</ion-text>\n } @else {\n <ion-skeleton-text animated></ion-skeleton-text>\n }\n </div>\n } @else {\n @if (files?.length === 1 && isImageFile(files[0])) {\n <div\n class=\"dcf-preview dcf-grid dcf-grid-match dcf-grid-collapse read dcf-single-file\"\n >\n <div\n class=\"dcf-width-1-4@m dcf-width-1-3@s dcf-flex dcf-flex-center dcf-flex-middle\"\n >\n <div class=\"dcf-preview-image\">\n <ion-img\n [src]=\"previewFile\"\n [title]=\"locale + '.preview' | translate\"\n [alt]=\"locale + '.preview' | translate\"\n />\n <div class=\"dcf-overlay\">\n <ion-button\n (click)=\"preview(previewFile)\"\n fill=\"clear\"\n color=\"light\"\n size=\"small\"\n >\n {{ locale + '.buttons.preview' | translate }}\n </ion-button>\n </div>\n </div>\n </div>\n <div\n class=\"description dcf-flex dcf-flex-middle dcf-width-expand@s\"\n >\n <div>\n <p class=\"dcf-title\">{{ locale + '.preview' | translate }}</p>\n <p class=\"subtitle\">{{ files[0].name }}</p>\n </div>\n </div>\n </div>\n } @else {\n <ion-list class=\"dcf-preview-list\">\n @for (file of files; track $index) {\n <ion-item\n [lines]=\"files?.length > 1 ? 'full' : 'none'\"\n (click)=\"preview(file.source, file.type)\"\n >\n @if (file?.name) {\n <ion-label slot=\"start\">\n {{ files?.length > 1 ? file.name : name }}\n </ion-label>\n }\n <div\n class=\"dcf-flex dcf-flex-middle\"\n slot=\"end\"\n >\n <ngx-decaf-icon\n [button]=\"true\"\n [slot]=\"'icon-only'\"\n [name]=\"\n file.type.includes('image')\n ? 'image-outline'\n : 'document-text-outline'\n \"\n />\n </div>\n </ion-item>\n }\n </ion-list>\n }\n }\n </div>\n }\n </ngx-decaf-card>\n</div>\n", styles: [".decaf-file-component ion-label{font-weight:700;display:block;margin:.75rem;margin-bottom:0!important;font-size:.925rem;font-weight:1rem!important;color:var(--dcf-color-gray-8)!important}.decaf-file-component ion-label ion-text{font-weight:initial;position:relative;top:.8rem}.decaf-file-component.dcf-palette-dark .dcf-button-select{--background: rgb(var(--dcf-color-light-rgb), .1) !important;--background-hover: rgb(var(--dcf-color-light-rgb), .75) !important;--background-activated: rgb(var(--dcf-color-light-rgb), .4) !important;--background-focused: rgb(var(--dcf-color-light-rgb), .4) !important;--color: var(--dcf-color-light) !important}.decaf-file-component.dcf-palette-dark .dcf-has-files{border-style:solid;border-color:var(--dcf-color-gray-6)!important}.decaf-file-component .dcf-upload-icon{--box-shadow: none !important}.decaf-file-component .dcf-upload-icon ion-icon{width:1.5rem!important}.decaf-file-component ion-skeleton-text{width:100%!important;height:1rem!important}.decaf-file-component ion-button.dcf-button-select{--background: rgb(var(--dcf-color-primary-rgb), .1);--background-hover: rgb(var(--dcf-color-primary-rgb), .75);--background-activated: rgb(var(--dcf-color-primary-rgb), .4);--background-focused: rgb(var(--dcf-color-primary-rgb), .4);--color: var(--dcf-color-primary-shade);--border-radius: var(--dcf-border-radius-small);--box-shadow: none;--padding-top: var(--dcf-padding-xsmall);--padding-bottom: var(--dcf-padding-xsmall);--padding-start: var(--dcf-padding-small);--padding-end: var(--dcf-padding-small);font-weight:500;text-transform:none;margin-top:var(--dcf-margin-small)!important}.decaf-file-component .dcf-error{color:var(--dcf-color-danger)!important;font-size:.8rem!important;font-weight:500!important;line-height:1.1rem;z-index:9999;animation-duration:.05s;animation-timing-function:ease-in;animation-fill-mode:both;animation-name:fadeBottomSmallAnimation}.decaf-file-component .dcf-error .ti,.decaf-file-component .dcf-error ion-icon{position:relative;top:2px!important;min-width:20px;font-size:1rem!important;text-align:left}.decaf-file-component ion-card-content{width:100%}.decaf-file-component .dcf-error-message{color:var(--dcf-color-danger);font-size:.875rem}.decaf-file-component .dcf-drag-description{font-size:1rem;line-height:1.5rem;font-weight:500;margin-bottom:var(--dcf-margin-small)}.decaf-file-component .dcf-drop-area{display:flex;align-items:center;border:1.5px dashed var(--dcf-color-gray-3);border-radius:var(--dcf-border-radius-small)!important;transition:border-style .15s ease,border-color .15s ease;background:transparent}.decaf-file-component .dcf-drop-area.dcf-large{min-height:180px}.decaf-file-component .dcf-drop-area>div{width:100%}.decaf-file-component .dcf-drop-area.dcf-has-files{border-style:solid;border-color:var(--dcf-color-primary-shade);transition:border-style .15s ease,border-color .15s ease;padding:var(--dcf-spacement) var(--dcf-spacement-small)!important}.decaf-file-component .dcf-drop-area:not(.dcf-has-files){border-style:dashed;padding:var(--dcf-spacement) var(--dcf-spacement-medium)}.decaf-file-component .dcf-drop-area.dcf-dragging{background:#00000008;border-color:var(--ion-color-primary);box-shadow:0 2px 8px #0000000f}.decaf-file-component .dcf-preview{padding:var(--dcf-padding-xsmall) var(--dcf-spacement-small)!important}.decaf-file-component .dcf-preview.read{padding:var(--dcf-spacement)!important}.decaf-file-component .dcf-preview .dcf-preview-image{border:1px solid var(--dcf-color-gray-3);border-radius:var(--dcf-border-radius-xsmall);max-width:320px;padding:.5rem;box-sizing:border-box;height:160px;position:relative;cursor:pointer;overflow:hidden}.decaf-file-component .dcf-preview .dcf-preview-image ion-img{height:140px!important;display:block;width:100%}.decaf-file-component .dcf-preview .dcf-preview-image:hover .dcf-overlay{opacity:1}.decaf-file-component .dcf-preview .dcf-preview-image .dcf-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background:#0009;display:flex;justify-content:center;align-items:center;opacity:0;transition:opacity .3s ease}.decaf-file-component .dcf-preview .description{text-align:left;padding:1rem;font-size:.75rem}.decaf-file-component .dcf-preview .description .dcf-title{font-size:1rem;font-weight:500}.decaf-file-component .dcf-preview .description ion-button{margin-top:var(--dcf-margin-small)!important}.decaf-file-component .dcf-preview-list-container{max-height:150px;overflow-y:auto}.decaf-file-component .dcf-preview-list-container ion-list{padding:0!important;margin:0!important}@media (max-width: 767px){.decaf-file-component .dcf-preview-list-container ion-list{width:100%;min-width:576px;overflow-x:auto}}.decaf-file-component .dcf-preview-list-container:not(:hover){scrollbar-color:rgba(var(--dcf-color-medium-rgb),.125) transparent!important}.decaf-file-component .dcf-preview-list-container ion-item{font-size:.875rem!important}.decaf-file-component .dcf-preview-list-container ion-item.dcf-error-item{--background: rgba(var(--dcf-color-danger-rgb), .02) !important;--border-color: rgba(var(--dcf-color-danger-rgb), .2) !important}.decaf-file-component .dcf-preview-list-container ion-item ion-item{--padding-top: .25rem;--padding-bottom: 0rem;--inner-padding-start: 0rem;--padding-start: var(--dcf-padding-xsmall) !important;--padding-end: 0rem;--inner-padding-end: var(--dcf-padding-xsmall) !important;--background-hover: var(--dcf-color-gray-8);--background-focused: var(--dcf-color-gray-8);--background-hover-opacity: .1;--background-focused-opacity: .1;--border-color: var(--dcf-color-gray-2)}\n"] }]
14090
14099
  }], ctorParameters: () => [], propDecorators: { component: [{
14091
14100
  type: ViewChild,
14092
14101
  args: ['component', { static: true }]
@@ -14996,6 +15005,36 @@ let TableComponent = class TableComponent extends ListComponent {
14996
15005
  await this.clearSearch();
14997
15006
  }
14998
15007
  }
15008
+ /**
15009
+ * @description Updates the matching rendered table row after an edit operation.
15010
+ * @summary Executes the default update flow inherited from `ListComponent` and then
15011
+ * finds the already-mapped row in `this.items` by `uid`. When found, it synchronizes
15012
+ * each displayed cell value (except the `uid` field) with the latest values from
15013
+ * `model`, preserving the mapped row structure used by the table.
15014
+ * @param {Model} model - Model instance containing updated values.
15015
+ * @param {string | number} uid - Unique identifier of the row to update.
15016
+ * @return {Promise<void>}
15017
+ */
15018
+ async handleUpdate(model, uid) {
15019
+ await super.handleUpdate(model, uid);
15020
+ const item = this.items.find((item) => `${item['uid']?.value}`.trim() === `${uid}`.trim());
15021
+ if (item) {
15022
+ for (const [key, entry] of Object.entries(item)) {
15023
+ const { prop } = entry;
15024
+ if (key !== 'uid' && prop in model) {
15025
+ const value = model[prop];
15026
+ if (value !== undefined) {
15027
+ if (isValidDate$1(value)) {
15028
+ entry.value = `${formatDate(dateFromString(value))}`;
15029
+ }
15030
+ else {
15031
+ entry.value = value;
15032
+ }
15033
+ }
15034
+ }
15035
+ }
15036
+ }
15037
+ }
14999
15038
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: TableComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
15000
15039
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: TableComponent, isStandalone: true, selector: "ngx-decaf-table", inputs: { maxContentLength: "maxContentLength", preserve: "preserve", filterModel: "filterModel", filterOptions: "filterOptions", filterLabel: "filterLabel", filterOptionsMapper: "filterOptionsMapper", allowOperations: "allowOperations" }, usesInheritance: true, ngImport: i0, template: "@if (showSearchbar && (data?.length || searching)) {\n <div class=\"dcf-grid-actions\">\n <div class=\"dcf-grid dcf-grid-small\">\n <div class=\"dcf-width-expand@s\">\n <ngx-decaf-searchbar\n [emitEventToWindow]=\"false\"\n [debounce]=\"500\"\n (searchEvent)=\"handleSearch($event)\"\n />\n </div>\n @if (filterOptions?.length) {\n <div\n class=\"dcf-width-1-3@s dcf-width-1-4@m dcf-select-filter-container dcf-flex dcf-flex-middle\"\n >\n <ion-select\n [id]=\"name\"\n toggleIcon=\"chevron-down-outline\"\n expandedIcon=\"chevron-up-outline\"\n [mode]=\"'md'\"\n fill=\"outline\"\n [value]=\"filterValue ?? ''\"\n [labelPlacement]=\"'floating'\"\n [label]=\"locale + '.filter.label' | translate\"\n (click)=\"openFilterSelectOptions($event)\"\n [placeholder]=\"locale + '.filter.label' | translate\"\n interface=\"popover\"\n >\n <ion-select-option value=\"\">\n {{ locale + '.filter.all' | translate }}\n </ion-select-option>\n @for (option of filterOptions; track $index) {\n <ion-select-option value=\"{{ option.value }}\">\n {{ option.text }}\n </ion-select-option>\n }\n <ion-button\n fill=\"clear\"\n (click)=\"handleFilterSelectClear($event)\"\n slot=\"end\"\n size=\"small\"\n [disabled]=\"!filterValue\"\n >\n <ngx-decaf-icon\n fill=\"clear\"\n slot=\"icon-only\"\n [name]=\"'ti-input-x'\"\n />\n </ion-button>\n </ion-select>\n </div>\n }\n </div>\n </div>\n}\n<div\n class=\"dcf-table-container\"\n [class.dcf-empty]=\"!data?.length\"\n #component\n>\n @if (initialized && data?.length) {\n <table class=\"dcf-table\">\n <thead>\n <tr>\n @for (header of headers; track $index) {\n <th>{{ locale + '.' + header + '.label' | translate }}</th>\n }\n </tr>\n </thead>\n <tbody>\n @for (item of items; track trackItemFn($index, item)) {\n <tr>\n @for (col of item | keyvalue; track $index) {\n @if (!['handler', 'actions', 'uid'].includes(col.key)) {\n <td\n (click)=\"\n handleAction(\n $event,\n col?.value.handler ? col.value.handler.handle : undefined,\n item.uid.value,\n OperationKeys.READ\n )\n \"\n [innerHTML]=\"col.value.value\"\n [ngx-decaf-tooltip]=\"\n maxContentLength > 0 && !preserve.includes(col.value.prop)\n ? {\n text: col.value.value,\n truncate: true,\n limit: maxContentLength,\n }\n : {}\n \"\n ></td>\n } @else {\n @if (allowOperations && col.key !== 'handler') {\n <td class=\"dcf-col-actions\">\n <div class=\"\">\n @if (operations?.includes(OperationKeys.UPDATE)) {\n <ngx-decaf-icon\n [button]=\"true\"\n (click)=\"\n handleRedirect(\n $event,\n item.uid.value,\n OperationKeys.UPDATE,\n true\n )\n \"\n fill=\"clear\"\n slot=\"icon-only\"\n color=\"primary\"\n name=\"ti-edit\"\n />\n }\n @if (operations?.includes(OperationKeys.DELETE)) {\n <ngx-decaf-icon\n [button]=\"true\"\n (click)=\"\n handleRedirect(\n $event,\n item.uid.value,\n OperationKeys.DELETE,\n true\n )\n \"\n fill=\"clear\"\n slot=\"icon-only\"\n color=\"danger\"\n name=\"ti-trash\"\n />\n }\n </div>\n </td>\n }\n }\n }\n </tr>\n }\n </tbody>\n </table>\n } @else {\n @if (!searching) {\n <ngx-decaf-empty-state\n [title]=\"'component.list.empty.title' | translate\"\n [subtitle]=\"'component.list.empty.subtitle' | translate\"\n [model]=\"empty?.showButton ? model : undefined\"\n [route]=\"route\"\n [refreshing]=\"refreshing\"\n [modelId]=\"modelId\"\n [buttonLink]=\"empty?.link ?? undefined\"\n [borders]=\"borders\"\n [icon]=\"(item?.icon ?? 'folder-open-outline') || empty.icon\"\n className=\"dcf-empty-data\"\n />\n } @else {\n <ngx-decaf-empty-state\n icon=\"search-outline\"\n [model]=\"empty?.showButton ? model : undefined\"\n [route]=\"route\"\n [modelId]=\"modelId\"\n [borders]=\"borders\"\n [operations]=\"operations\"\n [body]=\"'small'\"\n [translatable]=\"true\"\n [title]=\"'component.list.search.title' | translate\"\n [subtitle]=\"\n 'component.list.search.subtitle'\n | translate: { '0': parseSearchValue() }\n \"\n [searchValue]=\"searchValue\"\n />\n }\n }\n</div>\n\n<div class=\"dcf-table-pagination\">\n @if ((pages > 0 || bookMarkPagination) && !searchValue) {\n <ngx-decaf-pagination\n [table]=\"component\"\n [bookMarkPagination]=\"bookMarkPagination\"\n [nextBookmark]=\"paginator?._bookmark\"\n [totalPages]=\"pages\"\n [disablePages]=\"disablePaginationPages\"\n [truncatePages]=\"truncatePaginationPages\"\n [current]=\"page\"\n (clickEvent)=\"handlePaginate($event)\"\n />\n }\n</div>\n", styles: [".dcf-table-container{display:block;overflow-x:auto!important;box-sizing:border-box;overflow-y:hidden;scrollbar-width:thin;border-radius:var(--dcf-border-radius-small);box-shadow:var(--dcf-box-shadow-small)!important;background-color:var(--dcf-card-background);border:1px solid var(--dcf-color-gray-2)}.dcf-table-container::-webkit-scrollbar{width:5px}.dcf-table-container table{min-width:680px}.dcf-table{width:100%;border-collapse:collapse;border-radius:var(--dcf-border-radius-xsmall);overflow:hidden;background:var(--dcf-card-background);color:var(--dcf-text-color);font-size:.8rem}.dcf-table thead{background:rgba(var(--dcf-color-primary-rgb),.075);text-transform:uppercase;color:var(--dcf-color-dark);letter-spacing:.06em;font-size:.825rem;white-space:nowrap;width:auto}.dcf-table thead th{text-align:left;padding:.875rem 1rem;font-weight:600;max-width:max-content}.dcf-table tbody tr{transition:background .12s ease,box-shadow .12s ease}.dcf-table tbody tr:hover{background:rgba(var(--dcf-color-primary-rgb),.05);cursor:pointer}.dcf-table tbody tr:not(:last-child){border-bottom:1px solid var(--dcf-color-gray-2)}.dcf-table tbody td{padding:1rem 1.125rem;font-size:.875rem}.dcf-table tbody td:first-child{font-weight:600}.dcf-table tbody td.dcf-col-actions{padding-top:0!important;padding-bottom:0!important}.dcf-table tfoot{font-size:.85rem}.dcf-table tfoot td{padding:.875rem 1.125rem;border-top:1px solid 1px solid var(--dcf-color-gray-2)}.dcf-select-filter-container{min-width:200px}.dcf-buttons-grid{margin-top:var(--dcf-margin-medium);margin-bottom:var(--dcf-margin)}@media (max-width: 480px){.dcf-buttons-grid{flex-direction:row-reverse!important}.dcf-buttons-grid>div{width:100%}.dcf-buttons-grid>div+div{margin-top:1rem}.dcf-buttons-grid ion-button{width:100%}}ion-select{margin-top:.5rem;max-height:40px!important}ion-select ion-button{transform:scale(.75)!important;margin:0!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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: "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: IconComponent, selector: "ngx-decaf-icon", inputs: ["name", "color", "slot", "button", "buttonFill", "buttonShape", "width", "size", "inline"] }, { kind: "component", type: PaginationComponent, selector: "ngx-decaf-pagination", inputs: ["table", "totalPages", "current", "truncatePages", "disablePages", "bookMarkPagination", "nextBookmark"], outputs: ["clickEvent"] }, { kind: "directive", type: DecafTooltipDirective, selector: "[ngx-decaf-tooltip]", inputs: ["ngx-decaf-tooltip"] }, { kind: "pipe", type: i1$1.KeyValuePipe, name: "keyvalue" }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
15001
15040
  };
@@ -15292,5 +15331,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
15292
15331
  * Generated bundle index. Do not edit.
15293
15332
  */
15294
15333
 
15295
- export { ActionRoles, AngularEngineKeys, BaseComponentProps, CPTKN, CardComponent, ComponentRendererComponent, ComponentsTagNames, CrudFieldComponent, CrudFormComponent, CssClasses, DB_ADAPTER_FLAVOUR_TOKEN, DB_ADAPTER_PROVIDER_TOKEN, DecafFakerRepository, DecafTooltipDirective, DecafTranslatePipe, DecafTruncatePipe, DefaultFormReactiveOptions, DefaultListEmptyOptions, DefaultModalOptions, Dynamic, DynamicModule, EmptyStateComponent, FieldsetComponent, FileUploadComponent, FilterComponent, ForAngularCommonModule, ForAngularComponentsModule, I18N_CONFIG_TOKEN, I18nLoader, I18nLoaderFactory, I18nParser, IconComponent, LOCALE_ROOT_TOKEN, LayoutComponent, ListComponent, ListComponentsTypes, ListItemComponent, ListItemPositions, ModalComponent, ModalConfirmComponent, ModelRendererComponent, NgxComponentDirective, NgxEventHandler, NgxFormDirective, NgxFormFieldDirective, NgxFormService, NgxMediaService, NgxModelPageDirective, NgxPageDirective, NgxParentComponentDirective, NgxRenderingEngine, NgxRouterService, NgxSvgDirective, PaginationComponent, RouteDirections, SearchbarComponent, SelectFieldInterfaces, SteppedFormComponent, TableComponent, WindowColorSchemes, cleanSpaces, dataMapper, dateFromString, decafPageTransition, filterString, formatDate, generateRandomValue, getDbAdapterFlavour, getFakerData, getInjectablesRegistry, getLocaleContext, getLocaleContextByKey, getLocaleFromClassName, getLocaleLanguage, getLogger, getMenuIcon, getModelAndRepository, getNgxInlineModal, getNgxModalComponent, getNgxModalCrudComponent, getNgxSelectOptionsModal, getOnWindow, getOnWindowDocument, getWindow, getWindowDocument, getWindowWidth, isDarkMode, isDevelopmentMode, isNotUndefined, isValidDate, itemMapper, patternValidators, presentModalConfirm, presentNgxInlineModal, presentNgxLightBoxModal, provideDecafDarkMode, provideDecafDbAdapter, provideDecafDynamicComponents, provideDecafI18nConfig, provideDecafI18nLoader, provideDecafPageTransition, removeFocusTrap, setOnWindow, stringToBoolean, windowEventEmitter };
15334
+ export { ActionRoles, AngularEngineKeys, BaseComponentProps, CPTKN, CardComponent, ComponentRendererComponent, ComponentsTagNames, CrudFieldComponent, CrudFormComponent, CssClasses, DB_ADAPTER_FLAVOUR_TOKEN, DB_ADAPTER_PROVIDER_TOKEN, DecafFakerRepository, DecafTooltipDirective, DecafTranslatePipe, DecafTruncatePipe, DefaultFormButtonsOptions, DefaultListEmptyOptions, DefaultModalOptions, Dynamic, DynamicModule, EmptyStateComponent, FieldsetComponent, FileUploadComponent, FilterComponent, ForAngularCommonModule, ForAngularComponentsModule, I18N_CONFIG_TOKEN, I18nLoader, I18nLoaderFactory, I18nParser, IconComponent, LOCALE_ROOT_TOKEN, LayoutComponent, ListComponent, ListComponentsTypes, ListItemComponent, ListItemPositions, ModalComponent, ModalConfirmComponent, ModelRendererComponent, NgxComponentDirective, NgxEventHandler, NgxFormDirective, NgxFormFieldDirective, NgxFormService, NgxMediaService, NgxModelPageDirective, NgxPageDirective, NgxParentComponentDirective, NgxRenderingEngine, NgxRouterService, NgxSvgDirective, PaginationComponent, RouteDirections, SearchbarComponent, SelectFieldInterfaces, SteppedFormComponent, TableComponent, WindowColorSchemes, cleanSpaces, dataMapper, dateFromString, decafPageTransition, filterString, formatDate, generateRandomValue, getDbAdapterFlavour, getFakerData, getInjectablesRegistry, getLocaleContext, getLocaleContextByKey, getLocaleFromClassName, getLocaleLanguage, getLogger, getMenuIcon, getModelAndRepository, getNgxInlineModal, getNgxModalComponent, getNgxModalCrudComponent, getNgxSelectOptionsModal, getOnWindow, getOnWindowDocument, getWindow, getWindowDocument, getWindowWidth, isDarkMode, isDevelopmentMode, isNotUndefined, isValidBase64, isValidDate, itemMapper, patternValidators, presentModalConfirm, presentNgxInlineModal, presentNgxLightBoxModal, provideDecafDarkMode, provideDecafDbAdapter, provideDecafDynamicComponents, provideDecafI18nConfig, provideDecafI18nLoader, provideDecafPageTransition, removeFocusTrap, setOnWindow, stringToBoolean, windowEventEmitter };
15296
15335
  //# sourceMappingURL=decaf-ts-for-angular.mjs.map