ngx-eiffage-material 0.0.42 → 0.0.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { input, Component, inject, ChangeDetectorRef, signal, viewChild, afterRenderEffect, effect, untracked, forwardRef, output, ViewContainerRef, Directive, Injectable, Pipe, InjectionToken, computed, Optional, HostListener, DestroyRef, ViewEncapsulation, booleanAttribute } from '@angular/core';
2
+ import { input, Component, inject, ChangeDetectorRef, signal, viewChild, afterRenderEffect, effect, untracked, forwardRef, output, ViewContainerRef, Directive, Injectable, Pipe, InjectionToken, computed, Optional, HostListener, DestroyRef, ViewEncapsulation, booleanAttribute, PLATFORM_ID } from '@angular/core';
3
3
  import * as i1 from '@angular/material/button';
4
4
  import { MatButtonModule } from '@angular/material/button';
5
5
  import * as i2$1 from '@angular/material/icon';
@@ -9,7 +9,7 @@ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
9
9
  import * as i3$1 from '@angular/forms';
10
10
  import { FormControl, ReactiveFormsModule, NG_VALUE_ACCESSOR, Validators, FormArray, FormGroup, FormBuilder, FormsModule } from '@angular/forms';
11
11
  import * as i4$1 from '@angular/common';
12
- import { CommonModule, DatePipe, LowerCasePipe } from '@angular/common';
12
+ import { CommonModule, DatePipe, LowerCasePipe, isPlatformBrowser } from '@angular/common';
13
13
  import * as i2$2 from '@angular/material/chips';
14
14
  import { MatChipsModule } from '@angular/material/chips';
15
15
  import * as i3 from '@angular/material/form-field';
@@ -3359,7 +3359,11 @@ class NgxPaginatedSelect {
3359
3359
  selectAllLabel: this.selectAllLabel(),
3360
3360
  };
3361
3361
  this._bottomSheet
3362
- .open(NgxPaginatedSelectBottomSheetComponent, { data, panelClass: 'ngx-paginated-select-panel' })
3362
+ .open(NgxPaginatedSelectBottomSheetComponent, {
3363
+ data,
3364
+ panelClass: 'ngx-paginated-select-panel',
3365
+ autoFocus: data.showSearch ? '.ps-bs__search-input' : 'first-tabbable',
3366
+ })
3363
3367
  .afterDismissed()
3364
3368
  .subscribe(result => {
3365
3369
  this._isOpen.set(false);
@@ -3412,6 +3416,355 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
3412
3416
  ], template: "<!-- \u2500\u2500 Chips mode (multiple + displayMode = 'chips') \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n@if (showChips()) {\n <mat-form-field\n appearance=\"outline\"\n floatLabel=\"always\"\n class=\"ps-trigger\"\n [class.ps-trigger--disabled]=\"_isDisabled()\"\n [class.ps-trigger--open]=\"_isOpen()\"\n (click)=\"openBottomSheet($event)\"\n >\n <mat-label>{{ label() }}</mat-label>\n\n <mat-chip-grid #chipGrid class=\"ps-trigger__chip-grid\" [class.ps-trigger__chip-grid--column]=\"chipsDirection() === 'column'\" [formControl]=\"control()\">\n @for (item of displayedChips(); track item[config().valueKey]) {\n <mat-chip-row\n class=\"ps-trigger__chip\"\n [disabled]=\"_isDisabled()\"\n (removed)=\"removeChip(item, $event)\"\n >\n {{ getLabel(item) }}\n <button matChipRemove [disabled]=\"_isDisabled()\">\n <mat-icon>cancel</mat-icon>\n </button>\n </mat-chip-row>\n }\n </mat-chip-grid>\n\n @if (remainingChipsCount() > 0) {\n <span class=\"ps-trigger__remaining\">+{{ remainingChipsCount() }}</span>\n }\n\n <!-- Hidden input required for mat-chip-grid -->\n <input matInput [matChipInputFor]=\"chipGrid\" style=\"display: none\" readonly />\n\n <div matSuffix class=\"ps-trigger__suffix\">\n @if (clearable() && hasSelection() && !_isDisabled()) {\n <button matIconButton matSuffix (click)=\"clearSelection($event)\">\n <mat-icon>close</mat-icon>\n </button>\n }\n <mat-icon [class.ps-trigger__arrow--open]=\"_isOpen()\">arrow_drop_down</mat-icon>\n </div>\n\n @if (error()) {\n <mat-error>{{ error() }}</mat-error>\n }\n @if (hint()) {\n <mat-hint>{{ hint() }}</mat-hint>\n }\n </mat-form-field>\n}\n\n<!-- \u2500\u2500 Text mode (single or multiple + displayMode = 'text') \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n@if (!showChips()) {\n <mat-form-field\n appearance=\"outline\"\n floatLabel=\"always\"\n class=\"ps-trigger\"\n [class.ps-trigger--disabled]=\"_isDisabled()\"\n [class.ps-trigger--open]=\"_isOpen()\"\n (click)=\"openBottomSheet($event)\"\n >\n <mat-label>{{ label() }}</mat-label>\n\n <mat-select\n #matSelect\n class=\"ps-trigger__input\"\n [formControl]=\"control()\"\n [multiple]=\"multiple()\"\n style=\"pointer-events: none\"\n (openedChange)=\"preventOpen($event)\"\n >\n @for (item of _selectedItems(); track item[config().valueKey]) {\n <mat-option [value]=\"item[config().valueKey]\">{{ getLabel(item) }}</mat-option>\n }\n </mat-select>\n\n <div matSuffix class=\"ps-trigger__suffix\">\n @if (clearable() && hasSelection() && !_isDisabled()) {\n <button matIconButton matSuffix (click)=\"clearSelection($event)\">\n <mat-icon>close</mat-icon>\n </button>\n }\n </div>\n\n @if (error()) {\n <mat-error>{{ error() }}</mat-error>\n }\n @if (hint()) {\n <mat-hint>{{ hint() }}</mat-hint>\n }\n </mat-form-field>\n}\n\n\n", styles: [":host{display:block}.ps-trigger{width:100%;cursor:pointer;--mat-form-field-outlined-focus-outline-color: var(--mat-sys-outline);--mat-form-field-outlined-outline-color: var(--mat-sys-outline);--mat-form-field-outlined-hover-outline-color: var(--mat-sys-outline)}.ps-trigger ::ng-deep .mat-mdc-form-field-flex{cursor:pointer}.ps-trigger__input{cursor:pointer!important;caret-color:transparent;pointer-events:none}.ps-trigger__chip-grid{cursor:pointer;min-height:36px}.ps-trigger__chip-grid ::ng-deep .mdc-evolution-chip-set__chips{flex-wrap:nowrap;overflow:hidden}.ps-trigger__chip-grid--column ::ng-deep .mdc-evolution-chip-set__chips{flex-wrap:wrap;overflow:visible}.ps-trigger__chip{font-size:13px}.ps-trigger__chip ::ng-deep .mdc-evolution-chip__cell--primary,.ps-trigger__chip ::ng-deep .mdc-evolution-chip__action--primary{padding-left:10px;padding-right:0}.ps-trigger__suffix{display:flex;align-items:center;gap:0;flex-shrink:0}.ps-trigger__clear{width:28px;height:28px;line-height:28px;opacity:.6}.ps-trigger__clear:hover{opacity:1}.ps-trigger__clear mat-icon{font-size:18px;width:18px;height:18px}.ps-trigger__remaining{display:inline-flex;align-items:center;justify-content:center;min-width:24px;height:22px;padding:0 7px;border-radius:12px;font-size:11px;font-weight:700;background:var(--mat-sys-primary);color:var(--mat-sys-on-primary);margin-left:6px;white-space:nowrap;flex-shrink:0}.ps-trigger .ps-trigger__arrow--open{transform:rotate(180deg);transition:transform .2s ease}.ps-trigger mat-icon:not(.ps-trigger__clear mat-icon){transition:transform .2s ease}.ps-trigger--disabled{cursor:not-allowed}.ps-trigger--disabled ::ng-deep .mat-mdc-form-field-flex{cursor:not-allowed}\n"] }]
3413
3417
  }], ctorParameters: () => [], propDecorators: { _matSelect: [{ type: i0.ViewChild, args: ['matSelect', { isSignal: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], endpoint: [{ type: i0.Input, args: [{ isSignal: true, alias: "endpoint", required: true }] }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: true }] }], filters: [{ type: i0.Input, args: [{ isSignal: true, alias: "filters", required: false }] }], control: [{ type: i0.Input, args: [{ isSignal: true, alias: "control", required: false }] }], selectedItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedItems", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], displayMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayMode", required: false }] }], showSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSearch", required: false }] }], searchPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchPlaceholder", required: false }] }], noResultsMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "noResultsMessage", required: false }] }], confirmLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "confirmLabel", required: false }] }], resetLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "resetLabel", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], optionTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionTemplate", required: false }] }], extraFiltersTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "extraFiltersTemplate", required: false }] }], maxChipsDisplayed: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxChipsDisplayed", required: false }] }], chipsDirection: [{ type: i0.Input, args: [{ isSignal: true, alias: "chipsDirection", required: false }] }], showSelectAll: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSelectAll", required: false }] }], selectAllLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectAllLabel", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }] } });
3414
3418
 
3419
+ class NgxSkeleton {
3420
+ /** Shape variant of the skeleton: text (horizontal bars), circle, rect, or rounded rect. */
3421
+ variant = input('rect', ...(ngDevMode ? [{ debugName: "variant" }] : []));
3422
+ /** Width of the skeleton element. Accepts any valid CSS value (px, %, rem, etc.). */
3423
+ width = input('100%', ...(ngDevMode ? [{ debugName: "width" }] : []));
3424
+ /** Height of the skeleton element. Accepts any valid CSS value (px, %, rem, etc.). */
3425
+ height = input('1rem', ...(ngDevMode ? [{ debugName: "height" }] : []));
3426
+ /** Number of lines to render. Only applies when variant is 'text'. */
3427
+ lines = input(1, ...(ngDevMode ? [{ debugName: "lines" }] : []));
3428
+ /** Vertical spacing between text lines. Accepts any valid CSS value. */
3429
+ lineSpacing = input('0.5rem', ...(ngDevMode ? [{ debugName: "lineSpacing" }] : []));
3430
+ /** Width of the last text line for a realistic paragraph effect. Accepts any valid CSS value. */
3431
+ lastLineWidth = input('70%', ...(ngDevMode ? [{ debugName: "lastLineWidth" }] : []));
3432
+ /** Type of loading animation: shimmer (sliding highlight), pulse (opacity), or none. */
3433
+ animation = input('shimmer', ...(ngDevMode ? [{ debugName: "animation" }] : []));
3434
+ /** Duration of one full animation cycle. Accepts any valid CSS time value. */
3435
+ animationDuration = input('1.5s', ...(ngDevMode ? [{ debugName: "animationDuration" }] : []));
3436
+ /** Overrides the default border-radius derived from the variant. */
3437
+ borderRadius = input(null, ...(ngDevMode ? [{ debugName: "borderRadius" }] : []));
3438
+ /** Accessible label read by screen readers. */
3439
+ ariaLabel = input('Cargando...', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
3440
+ /** Whether the component should render multiple stacked lines. */
3441
+ isMultiLine = computed(() => this.variant() === 'text' && this.lines() > 1, ...(ngDevMode ? [{ debugName: "isMultiLine" }] : []));
3442
+ /** Index array used to iterate over text lines in the template. */
3443
+ lineIndices = computed(() => {
3444
+ const count = this.variant() === 'text' ? this.lines() : 1;
3445
+ return Array.from({ length: count }, (_, i) => i);
3446
+ }, ...(ngDevMode ? [{ debugName: "lineIndices" }] : []));
3447
+ /** Resolved border-radius based on variant with optional override. */
3448
+ computedBorderRadius = computed(() => {
3449
+ if (this.borderRadius() !== null)
3450
+ return this.borderRadius();
3451
+ switch (this.variant()) {
3452
+ case 'text': return '4px';
3453
+ case 'circle': return '50%';
3454
+ case 'rounded': return '12px';
3455
+ case 'rect':
3456
+ default: return '0';
3457
+ }
3458
+ }, ...(ngDevMode ? [{ debugName: "computedBorderRadius" }] : []));
3459
+ /** For circle variant, width equals height to ensure a perfect circle. */
3460
+ computedWidth = computed(() => {
3461
+ if (this.variant() === 'circle')
3462
+ return this.height();
3463
+ return this.width();
3464
+ }, ...(ngDevMode ? [{ debugName: "computedWidth" }] : []));
3465
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: NgxSkeleton, deps: [], target: i0.ɵɵFactoryTarget.Component });
3466
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: NgxSkeleton, isStandalone: true, selector: "ngx-skeleton", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, lines: { classPropertyName: "lines", publicName: "lines", isSignal: true, isRequired: false, transformFunction: null }, lineSpacing: { classPropertyName: "lineSpacing", publicName: "lineSpacing", isSignal: true, isRequired: false, transformFunction: null }, lastLineWidth: { classPropertyName: "lastLineWidth", publicName: "lastLineWidth", isSignal: true, isRequired: false, transformFunction: null }, animation: { classPropertyName: "animation", publicName: "animation", isSignal: true, isRequired: false, transformFunction: null }, animationDuration: { classPropertyName: "animationDuration", publicName: "animationDuration", isSignal: true, isRequired: false, transformFunction: null }, borderRadius: { classPropertyName: "borderRadius", publicName: "borderRadius", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "status" }, properties: { "attr.aria-label": "ariaLabel()", "attr.aria-busy": "\"true\"" } }, ngImport: i0, template: "@if (isMultiLine()) {\n <div class=\"ngx-skeleton-text-container\" [style.gap]=\"lineSpacing()\">\n @for (i of lineIndices(); track i) {\n <div\n class=\"ngx-skeleton-bone\"\n [class.ngx-skeleton-shimmer]=\"animation() === 'shimmer'\"\n [class.ngx-skeleton-pulse]=\"animation() === 'pulse'\"\n [style.width]=\"i === lineIndices().length - 1 ? lastLineWidth() : width()\"\n [style.height]=\"height()\"\n [style.border-radius]=\"computedBorderRadius()\"\n [style.--ngx-skeleton-duration]=\"animationDuration()\"\n ></div>\n }\n </div>\n} @else {\n <div\n class=\"ngx-skeleton-bone\"\n [class.ngx-skeleton-shimmer]=\"animation() === 'shimmer'\"\n [class.ngx-skeleton-pulse]=\"animation() === 'pulse'\"\n [style.width]=\"computedWidth()\"\n [style.height]=\"height()\"\n [style.border-radius]=\"computedBorderRadius()\"\n [style.--ngx-skeleton-duration]=\"animationDuration()\"\n ></div>\n}\n", styles: [":host{display:block}.ngx-skeleton-text-container{display:flex;flex-direction:column}.ngx-skeleton-bone{background-color:var(--mat-sys-surface-dim, var(--mat-sys-surface-variant, #e0e0e0));position:relative;overflow:hidden}.ngx-skeleton-bone.ngx-skeleton-shimmer:after{content:\"\";position:absolute;inset:0 0 0 -100%;width:100%;background:linear-gradient(90deg,transparent 0%,rgba(255,255,255,.08) 25%,rgba(255,255,255,.18) 45%,rgba(255,255,255,.28) 50%,rgba(255,255,255,.18) 55%,rgba(255,255,255,.08) 75%,transparent 100%);will-change:transform;animation:ngx-skeleton-shimmer var(--ngx-skeleton-duration, 1.5s) infinite ease-in-out}.ngx-skeleton-bone.ngx-skeleton-pulse{animation:ngx-skeleton-pulse var(--ngx-skeleton-duration, 1.5s) infinite ease-in-out}@keyframes ngx-skeleton-shimmer{0%{transform:translate(0)}to{transform:translate(200%)}}@keyframes ngx-skeleton-pulse{0%,to{opacity:1}50%{opacity:.4}}\n"] });
3467
+ }
3468
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: NgxSkeleton, decorators: [{
3469
+ type: Component,
3470
+ args: [{ selector: 'ngx-skeleton', host: {
3471
+ 'role': 'status',
3472
+ '[attr.aria-label]': 'ariaLabel()',
3473
+ '[attr.aria-busy]': '"true"',
3474
+ }, template: "@if (isMultiLine()) {\n <div class=\"ngx-skeleton-text-container\" [style.gap]=\"lineSpacing()\">\n @for (i of lineIndices(); track i) {\n <div\n class=\"ngx-skeleton-bone\"\n [class.ngx-skeleton-shimmer]=\"animation() === 'shimmer'\"\n [class.ngx-skeleton-pulse]=\"animation() === 'pulse'\"\n [style.width]=\"i === lineIndices().length - 1 ? lastLineWidth() : width()\"\n [style.height]=\"height()\"\n [style.border-radius]=\"computedBorderRadius()\"\n [style.--ngx-skeleton-duration]=\"animationDuration()\"\n ></div>\n }\n </div>\n} @else {\n <div\n class=\"ngx-skeleton-bone\"\n [class.ngx-skeleton-shimmer]=\"animation() === 'shimmer'\"\n [class.ngx-skeleton-pulse]=\"animation() === 'pulse'\"\n [style.width]=\"computedWidth()\"\n [style.height]=\"height()\"\n [style.border-radius]=\"computedBorderRadius()\"\n [style.--ngx-skeleton-duration]=\"animationDuration()\"\n ></div>\n}\n", styles: [":host{display:block}.ngx-skeleton-text-container{display:flex;flex-direction:column}.ngx-skeleton-bone{background-color:var(--mat-sys-surface-dim, var(--mat-sys-surface-variant, #e0e0e0));position:relative;overflow:hidden}.ngx-skeleton-bone.ngx-skeleton-shimmer:after{content:\"\";position:absolute;inset:0 0 0 -100%;width:100%;background:linear-gradient(90deg,transparent 0%,rgba(255,255,255,.08) 25%,rgba(255,255,255,.18) 45%,rgba(255,255,255,.28) 50%,rgba(255,255,255,.18) 55%,rgba(255,255,255,.08) 75%,transparent 100%);will-change:transform;animation:ngx-skeleton-shimmer var(--ngx-skeleton-duration, 1.5s) infinite ease-in-out}.ngx-skeleton-bone.ngx-skeleton-pulse{animation:ngx-skeleton-pulse var(--ngx-skeleton-duration, 1.5s) infinite ease-in-out}@keyframes ngx-skeleton-shimmer{0%{transform:translate(0)}to{transform:translate(200%)}}@keyframes ngx-skeleton-pulse{0%,to{opacity:1}50%{opacity:.4}}\n"] }]
3475
+ }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: false }] }], lines: [{ type: i0.Input, args: [{ isSignal: true, alias: "lines", required: false }] }], lineSpacing: [{ type: i0.Input, args: [{ isSignal: true, alias: "lineSpacing", required: false }] }], lastLineWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "lastLineWidth", required: false }] }], animation: [{ type: i0.Input, args: [{ isSignal: true, alias: "animation", required: false }] }], animationDuration: [{ type: i0.Input, args: [{ isSignal: true, alias: "animationDuration", required: false }] }], borderRadius: [{ type: i0.Input, args: [{ isSignal: true, alias: "borderRadius", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }] } });
3476
+
3477
+ let _uid = 0;
3478
+ class NgxFileInput {
3479
+ _platform = inject(PLATFORM_ID);
3480
+ _inputId = `ngx-fi-${++_uid}`;
3481
+ // ── Inputs ──────────────────────────────────────────────────────────────────
3482
+ /** Accepted MIME types or extensions (e.g. `'image/*,.pdf'`). */
3483
+ accept = input('*', ...(ngDevMode ? [{ debugName: "accept" }] : []));
3484
+ /** Allow selecting multiple files. */
3485
+ multiple = input(false, ...(ngDevMode ? [{ debugName: "multiple", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
3486
+ /** Maximum file size in bytes per file. `null` means no limit. */
3487
+ maxSize = input(null, ...(ngDevMode ? [{ debugName: "maxSize" }] : []));
3488
+ /** Maximum number of files when `multiple` is true. `null` means no limit. */
3489
+ maxFiles = input(null, ...(ngDevMode ? [{ debugName: "maxFiles" }] : []));
3490
+ /** Disables the component. */
3491
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
3492
+ /** Label text shown inside the drop zone. */
3493
+ label = input('Arrastra archivos aquí', ...(ngDevMode ? [{ debugName: "label" }] : []));
3494
+ /** Secondary hint text (formats, sizes…). */
3495
+ hint = input(null, ...(ngDevMode ? [{ debugName: "hint" }] : []));
3496
+ /** Show the file preview list below the drop zone. */
3497
+ showPreview = input(true, ...(ngDevMode ? [{ debugName: "showPreview", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
3498
+ /** Visual variant: `'default'` (large zone), `'compact'` (horizontal), or `'button'`. */
3499
+ variant = input('default', ...(ngDevMode ? [{ debugName: "variant" }] : []));
3500
+ // ── Outputs ─────────────────────────────────────────────────────────────────
3501
+ /** Emits when valid files are added. */
3502
+ filesSelected = output();
3503
+ /** Emits when a file is removed from the list. */
3504
+ fileRemoved = output();
3505
+ /** Emits for each file that fails validation. */
3506
+ validationError = output();
3507
+ // ── Internal state ──────────────────────────────────────────────────────────
3508
+ /** All file items (valid + invalid). */
3509
+ items = signal([], ...(ngDevMode ? [{ debugName: "items" }] : []));
3510
+ /** Whether the user is dragging files over the drop zone. */
3511
+ isDragOver = signal(false, ...(ngDevMode ? [{ debugName: "isDragOver" }] : []));
3512
+ /** Brief flash after a successful drop. */
3513
+ showDropConfirm = signal(false, ...(ngDevMode ? [{ debugName: "showDropConfirm" }] : []));
3514
+ /** Announcement text for screen readers. */
3515
+ liveAnnouncement = signal('', ...(ngDevMode ? [{ debugName: "liveAnnouncement" }] : []));
3516
+ /** Unique id for the hidden file input. */
3517
+ inputId = this._inputId;
3518
+ /** Derived: valid files only (used as FormControl value). */
3519
+ validFiles = computed(() => this.items().filter(i => i.status === 'valid').map(i => i.file), ...(ngDevMode ? [{ debugName: "validFiles" }] : []));
3520
+ // ── ControlValueAccessor ────────────────────────────────────────────────────
3521
+ _onChange = () => { };
3522
+ _onTouched = () => { };
3523
+ writeValue(files) {
3524
+ if (!files || files.length === 0) {
3525
+ this.items.set([]);
3526
+ return;
3527
+ }
3528
+ this.items.set(files.map(f => this._toFileItem(f)));
3529
+ this._generatePreviews(this.items());
3530
+ }
3531
+ registerOnChange(fn) {
3532
+ this._onChange = fn;
3533
+ }
3534
+ registerOnTouched(fn) {
3535
+ this._onTouched = fn;
3536
+ }
3537
+ // ── Drag & Drop ─────────────────────────────────────────────────────────────
3538
+ onDragOver(event) {
3539
+ event.preventDefault();
3540
+ event.stopPropagation();
3541
+ if (!this.disabled())
3542
+ this.isDragOver.set(true);
3543
+ }
3544
+ onDragLeave(event) {
3545
+ event.preventDefault();
3546
+ event.stopPropagation();
3547
+ this.isDragOver.set(false);
3548
+ }
3549
+ onDrop(event) {
3550
+ event.preventDefault();
3551
+ event.stopPropagation();
3552
+ this.isDragOver.set(false);
3553
+ if (this.disabled())
3554
+ return;
3555
+ const files = event.dataTransfer?.files;
3556
+ if (files && files.length > 0) {
3557
+ this._processFiles(Array.from(files));
3558
+ this._flashDropConfirm();
3559
+ }
3560
+ }
3561
+ // ── File input ──────────────────────────────────────────────────────────────
3562
+ onFileInputChange(event) {
3563
+ const input = event.target;
3564
+ if (input.files && input.files.length > 0) {
3565
+ this._processFiles(Array.from(input.files));
3566
+ }
3567
+ input.value = '';
3568
+ }
3569
+ openFilePicker() {
3570
+ if (this.disabled())
3571
+ return;
3572
+ this._onTouched();
3573
+ document.getElementById(this._inputId)?.click();
3574
+ }
3575
+ // ── Remove ──────────────────────────────────────────────────────────────────
3576
+ removeFile(item) {
3577
+ this.items.update(list => list.filter(i => i.id !== item.id));
3578
+ this.fileRemoved.emit(item);
3579
+ this._emitChange();
3580
+ this.liveAnnouncement.set(`Archivo ${item.name} eliminado`);
3581
+ }
3582
+ // ── Helpers ─────────────────────────────────────────────────────────────────
3583
+ /** Format bytes to human-readable string. */
3584
+ formatSize(bytes) {
3585
+ if (bytes < 1024)
3586
+ return `${bytes} B`;
3587
+ if (bytes < 1024 * 1024)
3588
+ return `${(bytes / 1024).toFixed(1)} KB`;
3589
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
3590
+ }
3591
+ /** Get a Material icon name based on MIME type. */
3592
+ getFileIcon(type) {
3593
+ if (type.startsWith('image/'))
3594
+ return 'image';
3595
+ if (type === 'application/pdf')
3596
+ return 'picture_as_pdf';
3597
+ if (type.startsWith('video/'))
3598
+ return 'videocam';
3599
+ if (type.startsWith('audio/'))
3600
+ return 'audiotrack';
3601
+ if (type.includes('spreadsheet') || type.includes('excel'))
3602
+ return 'table_chart';
3603
+ if (type.includes('document') || type.includes('word'))
3604
+ return 'description';
3605
+ if (type.includes('zip') || type.includes('compressed'))
3606
+ return 'folder_zip';
3607
+ return 'insert_drive_file';
3608
+ }
3609
+ /** Get an accent color class based on MIME type. */
3610
+ getFileColorClass(type) {
3611
+ if (type.startsWith('image/'))
3612
+ return 'ngx-fi-icon--image';
3613
+ if (type === 'application/pdf')
3614
+ return 'ngx-fi-icon--pdf';
3615
+ if (type.startsWith('video/'))
3616
+ return 'ngx-fi-icon--video';
3617
+ if (type.startsWith('audio/'))
3618
+ return 'ngx-fi-icon--audio';
3619
+ return 'ngx-fi-icon--generic';
3620
+ }
3621
+ // ── Private ─────────────────────────────────────────────────────────────────
3622
+ _processFiles(files) {
3623
+ this._onTouched();
3624
+ let incoming = files;
3625
+ const currentCount = this.items().length;
3626
+ const max = this.maxFiles();
3627
+ // Max files check
3628
+ if (this.multiple() && max !== null && currentCount + incoming.length > max) {
3629
+ const allowed = Math.max(0, max - currentCount);
3630
+ const rejected = incoming.slice(allowed);
3631
+ incoming = incoming.slice(0, allowed);
3632
+ for (const f of rejected) {
3633
+ const err = {
3634
+ file: f,
3635
+ code: 'MAX_FILES_EXCEEDED',
3636
+ message: `Máximo ${max} archivos permitidos`,
3637
+ };
3638
+ this.validationError.emit(err);
3639
+ }
3640
+ }
3641
+ // Single mode replaces current
3642
+ if (!this.multiple()) {
3643
+ incoming = incoming.slice(0, 1);
3644
+ }
3645
+ const newItems = incoming.map(f => this._validateAndCreate(f));
3646
+ if (this.multiple()) {
3647
+ this.items.update(list => [...list, ...newItems]);
3648
+ }
3649
+ else {
3650
+ this.items.set(newItems);
3651
+ }
3652
+ this._generatePreviews(newItems);
3653
+ this._emitChange();
3654
+ const validCount = newItems.filter(i => i.status === 'valid').length;
3655
+ if (validCount > 0) {
3656
+ this.filesSelected.emit(newItems.filter(i => i.status === 'valid'));
3657
+ this.liveAnnouncement.set(`${validCount} archivo${validCount > 1 ? 's' : ''} añadido${validCount > 1 ? 's' : ''}`);
3658
+ }
3659
+ }
3660
+ _validateAndCreate(file) {
3661
+ const item = this._toFileItem(file);
3662
+ // Type validation
3663
+ if (this.accept() !== '*' && !this._isTypeAllowed(file)) {
3664
+ item.status = 'error';
3665
+ item.error = `Tipo no permitido: ${file.type || file.name.split('.').pop()}`;
3666
+ this.validationError.emit({
3667
+ file,
3668
+ code: 'TYPE_NOT_ALLOWED',
3669
+ message: item.error,
3670
+ });
3671
+ return item;
3672
+ }
3673
+ // Size validation
3674
+ const maxSz = this.maxSize();
3675
+ if (maxSz !== null && file.size > maxSz) {
3676
+ item.status = 'error';
3677
+ item.error = `Excede el tamaño máximo (${this.formatSize(maxSz)})`;
3678
+ this.validationError.emit({
3679
+ file,
3680
+ code: 'SIZE_EXCEEDED',
3681
+ message: item.error,
3682
+ });
3683
+ return item;
3684
+ }
3685
+ return item;
3686
+ }
3687
+ _toFileItem(file) {
3688
+ return {
3689
+ file,
3690
+ id: this._generateId(),
3691
+ name: file.name,
3692
+ size: file.size,
3693
+ type: file.type,
3694
+ status: 'valid',
3695
+ };
3696
+ }
3697
+ _isTypeAllowed(file) {
3698
+ const accept = this.accept();
3699
+ const parts = accept.split(',').map(p => p.trim().toLowerCase());
3700
+ const fileType = file.type.toLowerCase();
3701
+ const fileName = file.name.toLowerCase();
3702
+ return parts.some(pattern => {
3703
+ // Extension pattern like .pdf
3704
+ if (pattern.startsWith('.')) {
3705
+ return fileName.endsWith(pattern);
3706
+ }
3707
+ // Wildcard MIME like image/*
3708
+ if (pattern.endsWith('/*')) {
3709
+ const prefix = pattern.slice(0, -2);
3710
+ return fileType.startsWith(prefix + '/');
3711
+ }
3712
+ // Exact MIME
3713
+ return fileType === pattern;
3714
+ });
3715
+ }
3716
+ _generatePreviews(items) {
3717
+ if (!isPlatformBrowser(this._platform))
3718
+ return;
3719
+ for (const item of items) {
3720
+ if (item.file.type.startsWith('image/') && item.status === 'valid') {
3721
+ const reader = new FileReader();
3722
+ reader.onload = () => {
3723
+ this.items.update(list => list.map(i => i.id === item.id ? { ...i, preview: reader.result } : i));
3724
+ };
3725
+ reader.readAsDataURL(item.file);
3726
+ }
3727
+ }
3728
+ }
3729
+ _emitChange() {
3730
+ this._onChange(this.validFiles());
3731
+ }
3732
+ _flashDropConfirm() {
3733
+ this.showDropConfirm.set(true);
3734
+ setTimeout(() => this.showDropConfirm.set(false), 450);
3735
+ }
3736
+ _generateId() {
3737
+ if (isPlatformBrowser(this._platform) && typeof crypto !== 'undefined' && crypto.randomUUID) {
3738
+ return crypto.randomUUID();
3739
+ }
3740
+ return `${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
3741
+ }
3742
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: NgxFileInput, deps: [], target: i0.ɵɵFactoryTarget.Component });
3743
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: NgxFileInput, isStandalone: true, selector: "ngx-file-input", inputs: { accept: { classPropertyName: "accept", publicName: "accept", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, maxSize: { classPropertyName: "maxSize", publicName: "maxSize", isSignal: true, isRequired: false, transformFunction: null }, maxFiles: { classPropertyName: "maxFiles", publicName: "maxFiles", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, showPreview: { classPropertyName: "showPreview", publicName: "showPreview", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { filesSelected: "filesSelected", fileRemoved: "fileRemoved", validationError: "validationError" }, host: { properties: { "class.ngx-fi--disabled": "disabled()", "class.ngx-fi--default": "variant() === 'default'", "class.ngx-fi--compact": "variant() === 'compact'", "class.ngx-fi--button": "variant() === 'button'" }, classAttribute: "ngx-file-input" }, providers: [
3744
+ {
3745
+ provide: NG_VALUE_ACCESSOR,
3746
+ useExisting: forwardRef(() => NgxFileInput),
3747
+ multi: true,
3748
+ },
3749
+ ], ngImport: i0, template: "<!-- Hidden native file input \u2014 always in DOM for accessibility -->\n<input\n [id]=\"inputId\"\n class=\"ngx-fi-native-input\"\n type=\"file\"\n [accept]=\"accept()\"\n [multiple]=\"multiple()\"\n [disabled]=\"disabled()\"\n (change)=\"onFileInputChange($event)\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n/>\n\n<!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n VARIANT: DEFAULT \u2014 large drop zone\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n@if (variant() === 'default') {\n <div\n class=\"ngx-fi-zone\"\n [class.ngx-fi-zone--dragover]=\"isDragOver()\"\n [class.ngx-fi-zone--disabled]=\"disabled()\"\n role=\"region\"\n [attr.aria-label]=\"label()\"\n [attr.aria-disabled]=\"disabled()\"\n tabindex=\"0\"\n (click)=\"openFilePicker()\"\n (keydown.enter)=\"openFilePicker()\"\n (keydown.space)=\"openFilePicker(); $event.preventDefault()\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n >\n <mat-icon class=\"ngx-fi-zone__icon\">cloud_upload</mat-icon>\n <span class=\"ngx-fi-zone__label\">{{ label() }}</span>\n @if (hint()) {\n <span class=\"ngx-fi-zone__hint\">{{ hint() }}</span>\n }\n <span class=\"ngx-fi-zone__btn-text\">o haz clic para seleccionar</span>\n\n <!-- Drop confirmation flash -->\n @if (showDropConfirm()) {\n <div class=\"ngx-fi-zone__confirm\">\n <mat-icon>check_circle</mat-icon>\n </div>\n }\n </div>\n}\n\n<!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n VARIANT: COMPACT \u2014 horizontal bar\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n@if (variant() === 'compact') {\n <div\n class=\"ngx-fi-compact\"\n [class.ngx-fi-compact--dragover]=\"isDragOver()\"\n [class.ngx-fi-compact--disabled]=\"disabled()\"\n role=\"region\"\n [attr.aria-label]=\"label()\"\n [attr.aria-disabled]=\"disabled()\"\n tabindex=\"0\"\n (click)=\"openFilePicker()\"\n (keydown.enter)=\"openFilePicker()\"\n (keydown.space)=\"openFilePicker(); $event.preventDefault()\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n >\n <mat-icon class=\"ngx-fi-compact__icon\">cloud_upload</mat-icon>\n <div class=\"ngx-fi-compact__text\">\n <span class=\"ngx-fi-compact__label\">{{ label() }}</span>\n @if (hint()) {\n <span class=\"ngx-fi-compact__hint\">{{ hint() }}</span>\n }\n </div>\n\n @if (showDropConfirm()) {\n <div class=\"ngx-fi-zone__confirm\">\n <mat-icon>check_circle</mat-icon>\n </div>\n }\n </div>\n}\n\n<!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n VARIANT: BUTTON \u2014 only a button\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n@if (variant() === 'button') {\n <div\n class=\"ngx-fi-button-wrap\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n [class.ngx-fi-button-wrap--dragover]=\"isDragOver()\"\n >\n <button\n mat-raised-button\n color=\"primary\"\n [disabled]=\"disabled()\"\n (click)=\"openFilePicker()\"\n type=\"button\"\n >\n <mat-icon>attach_file</mat-icon>\n {{ label() }}\n </button>\n </div>\n}\n\n<!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n FILE PREVIEW LIST\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n@if (showPreview() && items().length > 0) {\n <div class=\"ngx-fi-list\">\n @for (item of items(); track item.id) {\n <div\n class=\"ngx-fi-item\"\n [class.ngx-fi-item--error]=\"item.status === 'error'\"\n >\n <!-- Thumbnail / Icon -->\n <div class=\"ngx-fi-item__thumb\" [class]=\"getFileColorClass(item.type)\">\n @if (item.preview) {\n <img [src]=\"item.preview\" [alt]=\"item.name\" />\n } @else {\n <mat-icon>{{ getFileIcon(item.type) }}</mat-icon>\n }\n </div>\n\n <!-- Info -->\n <div class=\"ngx-fi-item__info\">\n <span class=\"ngx-fi-item__name\" [matTooltip]=\"item.name\">{{ item.name }}</span>\n <span class=\"ngx-fi-item__meta\">\n {{ formatSize(item.size) }}\n @if (item.error) {\n <span class=\"ngx-fi-item__error\">\n <mat-icon>warning</mat-icon> {{ item.error }}\n </span>\n }\n </span>\n </div>\n\n <!-- Remove -->\n <button\n class=\"ngx-fi-item__remove\"\n type=\"button\"\n mat-icon-button\n (click)=\"removeFile(item); $event.stopPropagation()\"\n [matTooltip]=\"'Eliminar ' + item.name\"\n >\n <mat-icon>close</mat-icon>\n </button>\n </div>\n }\n </div>\n}\n\n<!-- Screen reader announcements -->\n<div class=\"ngx-fi-sr-only\" aria-live=\"polite\">{{ liveAnnouncement() }}</div>\n", styles: [".ngx-fi-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.ngx-fi-native-input{position:absolute;width:0;height:0;opacity:0;pointer-events:none}.ngx-fi-zone{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;min-height:180px;padding:2rem 1.5rem;border:2px dashed var(--mat-sys-outline-variant, #c4c4c4);border-radius:12px;background:var(--mat-sys-surface-container-low, #fafafa);cursor:pointer;transition:border-color .2s,background-color .2s,box-shadow .2s;outline:none;-webkit-user-select:none;user-select:none;overflow:hidden}.ngx-fi-zone:hover:not(.ngx-fi-zone--disabled){border-style:solid;background:var(--mat-sys-surface-container, #f0f0f0)}.ngx-fi-zone:focus-visible:not(.ngx-fi-zone--disabled){box-shadow:0 0 0 3px #5c6bc040;border-color:var(--mat-sys-primary, #5c6bc0)}.ngx-fi-zone--dragover{border-color:var(--mat-sys-primary, #5c6bc0);border-style:solid;background:var(--mat-sys-primary-container, rgba(92, 107, 192, .08));box-shadow:inset 0 0 0 2px var(--mat-sys-primary, #5c6bc0),0 0 16px #5c6bc033;animation:ngx-fi-glow 1s ease-in-out infinite}.ngx-fi-zone--dragover .ngx-fi-zone__icon{transform:scale(1.15);color:var(--mat-sys-primary, #5c6bc0)}.ngx-fi-zone--disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.ngx-fi-zone__icon{font-size:48px;width:48px;height:48px;color:var(--mat-sys-on-surface-variant, #666);transition:transform .2s,color .2s}.ngx-fi-zone__label{font-size:1.05rem;font-weight:500;color:var(--mat-sys-on-surface, #333);text-align:center}.ngx-fi-zone__hint{font-size:.82rem;color:var(--mat-sys-on-surface-variant, #666);text-align:center}.ngx-fi-zone__btn-text{font-size:.82rem;color:var(--mat-sys-primary, #5c6bc0);font-weight:500;margin-top:.25rem}.ngx-fi-zone__confirm{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:#43a0471f;pointer-events:none;animation:ngx-fi-confirm-flash .4s ease-out forwards}.ngx-fi-zone__confirm mat-icon{font-size:56px;width:56px;height:56px;color:var(--mat-sys-tertiary, #43a047)}.ngx-fi-compact{position:relative;display:flex;align-items:center;gap:1rem;height:80px;padding:0 1.25rem;border:2px dashed var(--mat-sys-outline-variant, #c4c4c4);border-radius:12px;background:var(--mat-sys-surface-container-low, #fafafa);cursor:pointer;transition:border-color .2s,background-color .2s,box-shadow .2s;outline:none;-webkit-user-select:none;user-select:none;overflow:hidden}.ngx-fi-compact:hover:not(.ngx-fi-compact--disabled){border-style:solid;background:var(--mat-sys-surface-container, #f0f0f0)}.ngx-fi-compact:focus-visible:not(.ngx-fi-compact--disabled){box-shadow:0 0 0 3px #5c6bc040;border-color:var(--mat-sys-primary, #5c6bc0)}.ngx-fi-compact--dragover{border-color:var(--mat-sys-primary, #5c6bc0);border-style:solid;background:var(--mat-sys-primary-container, rgba(92, 107, 192, .08));box-shadow:inset 0 0 0 2px var(--mat-sys-primary, #5c6bc0),0 0 16px #5c6bc033;animation:ngx-fi-glow 1s ease-in-out infinite}.ngx-fi-compact--dragover .ngx-fi-compact__icon{transform:scale(1.1);color:var(--mat-sys-primary, #5c6bc0)}.ngx-fi-compact--disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.ngx-fi-compact__icon{font-size:32px;width:32px;height:32px;color:var(--mat-sys-on-surface-variant, #666);flex-shrink:0;transition:transform .2s,color .2s}.ngx-fi-compact__text{display:flex;flex-direction:column;gap:.15rem;min-width:0}.ngx-fi-compact__label{font-size:.95rem;font-weight:500;color:var(--mat-sys-on-surface, #333)}.ngx-fi-compact__hint{font-size:.78rem;color:var(--mat-sys-on-surface-variant, #666)}.ngx-fi-button-wrap{display:inline-block;position:relative;padding:4px;border-radius:8px;transition:background-color .2s,box-shadow .2s}.ngx-fi-button-wrap--dragover{background:var(--mat-sys-primary-container, rgba(92, 107, 192, .08));box-shadow:0 0 12px #5c6bc040}.ngx-fi-list{display:flex;flex-direction:column;gap:.5rem;margin-top:.75rem}.ngx-fi-item{display:flex;align-items:center;gap:.75rem;padding:.5rem .65rem;border-radius:10px;background:var(--mat-sys-surface-container-low, #fafafa);border:1px solid var(--mat-sys-outline-variant, #e0e0e0);transition:border-color .2s,background-color .2s;animation:ngx-fi-item-enter .2s ease-out both}.ngx-fi-item--error{border-color:var(--mat-sys-error, #d32f2f);background:#d32f2f0a}.ngx-fi-item__thumb{width:42px;height:42px;border-radius:8px;display:flex;align-items:center;justify-content:center;flex-shrink:0;overflow:hidden}.ngx-fi-item__thumb img{width:100%;height:100%;object-fit:cover;border-radius:8px}.ngx-fi-item__thumb mat-icon{font-size:24px;width:24px;height:24px}.ngx-fi-item__info{flex:1;min-width:0;display:flex;flex-direction:column;gap:.1rem}.ngx-fi-item__name{font-size:.88rem;font-weight:500;color:var(--mat-sys-on-surface, #333);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ngx-fi-item__meta{font-size:.75rem;color:var(--mat-sys-on-surface-variant, #666);display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}.ngx-fi-item__error{color:var(--mat-sys-error, #d32f2f);display:inline-flex;align-items:center;gap:.2rem;font-weight:500}.ngx-fi-item__error mat-icon{font-size:14px;width:14px;height:14px}.ngx-fi-item__remove{flex-shrink:0}.ngx-fi-icon--image{background:#5c6bc01a}.ngx-fi-icon--image mat-icon{color:#5c6bc0}.ngx-fi-icon--pdf{background:#d32f2f1a}.ngx-fi-icon--pdf mat-icon{color:#d32f2f}.ngx-fi-icon--video{background:#1e88e51a}.ngx-fi-icon--video mat-icon{color:#1e88e5}.ngx-fi-icon--audio{background:#8e24aa1a}.ngx-fi-icon--audio mat-icon{color:#8e24aa}.ngx-fi-icon--generic{background:#0000000f}.ngx-fi-icon--generic mat-icon{color:#757575}@keyframes ngx-fi-item-enter{0%{opacity:0;transform:translateY(8px) scale(.96)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes ngx-fi-confirm-flash{0%{opacity:1}to{opacity:0}}.ngx-fi-item:nth-child(1){animation-delay:0ms}.ngx-fi-item:nth-child(2){animation-delay:50ms}.ngx-fi-item:nth-child(3){animation-delay:.1s}.ngx-fi-item:nth-child(4){animation-delay:.15s}.ngx-fi-item:nth-child(5){animation-delay:.2s}.ngx-fi-item:nth-child(6){animation-delay:.25s}.ngx-fi-item:nth-child(7){animation-delay:.3s}.ngx-fi-item:nth-child(8){animation-delay:.35s}.ngx-fi-item:nth-child(9){animation-delay:.4s}.ngx-fi-item:nth-child(10){animation-delay:.45s}.ngx-fi-item:nth-child(11){animation-delay:.5s}.ngx-fi-item:nth-child(12){animation-delay:.55s}.ngx-fi-item:nth-child(13){animation-delay:.6s}.ngx-fi-item:nth-child(14){animation-delay:.65s}.ngx-fi-item:nth-child(15){animation-delay:.7s}.ngx-fi-item:nth-child(16){animation-delay:.75s}.ngx-fi-item:nth-child(17){animation-delay:.8s}.ngx-fi-item:nth-child(18){animation-delay:.85s}.ngx-fi-item:nth-child(19){animation-delay:.9s}.ngx-fi-item:nth-child(20){animation-delay:.95s}@keyframes ngx-fi-glow{0%,to{box-shadow:inset 0 0 0 2px var(--mat-sys-primary, #5c6bc0),0 0 12px #5c6bc02e}50%{box-shadow:inset 0 0 0 2px var(--mat-sys-primary, #5c6bc0),0 0 22px #5c6bc059}}\n"], dependencies: [{ kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i7.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }], encapsulation: i0.ViewEncapsulation.None });
3750
+ }
3751
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: NgxFileInput, decorators: [{
3752
+ type: Component,
3753
+ args: [{ selector: 'ngx-file-input', imports: [MatButtonModule, MatIconModule, MatTooltipModule], encapsulation: ViewEncapsulation.None, providers: [
3754
+ {
3755
+ provide: NG_VALUE_ACCESSOR,
3756
+ useExisting: forwardRef(() => NgxFileInput),
3757
+ multi: true,
3758
+ },
3759
+ ], host: {
3760
+ 'class': 'ngx-file-input',
3761
+ '[class.ngx-fi--disabled]': 'disabled()',
3762
+ '[class.ngx-fi--default]': "variant() === 'default'",
3763
+ '[class.ngx-fi--compact]': "variant() === 'compact'",
3764
+ '[class.ngx-fi--button]': "variant() === 'button'",
3765
+ }, template: "<!-- Hidden native file input \u2014 always in DOM for accessibility -->\n<input\n [id]=\"inputId\"\n class=\"ngx-fi-native-input\"\n type=\"file\"\n [accept]=\"accept()\"\n [multiple]=\"multiple()\"\n [disabled]=\"disabled()\"\n (change)=\"onFileInputChange($event)\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n/>\n\n<!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n VARIANT: DEFAULT \u2014 large drop zone\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n@if (variant() === 'default') {\n <div\n class=\"ngx-fi-zone\"\n [class.ngx-fi-zone--dragover]=\"isDragOver()\"\n [class.ngx-fi-zone--disabled]=\"disabled()\"\n role=\"region\"\n [attr.aria-label]=\"label()\"\n [attr.aria-disabled]=\"disabled()\"\n tabindex=\"0\"\n (click)=\"openFilePicker()\"\n (keydown.enter)=\"openFilePicker()\"\n (keydown.space)=\"openFilePicker(); $event.preventDefault()\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n >\n <mat-icon class=\"ngx-fi-zone__icon\">cloud_upload</mat-icon>\n <span class=\"ngx-fi-zone__label\">{{ label() }}</span>\n @if (hint()) {\n <span class=\"ngx-fi-zone__hint\">{{ hint() }}</span>\n }\n <span class=\"ngx-fi-zone__btn-text\">o haz clic para seleccionar</span>\n\n <!-- Drop confirmation flash -->\n @if (showDropConfirm()) {\n <div class=\"ngx-fi-zone__confirm\">\n <mat-icon>check_circle</mat-icon>\n </div>\n }\n </div>\n}\n\n<!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n VARIANT: COMPACT \u2014 horizontal bar\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n@if (variant() === 'compact') {\n <div\n class=\"ngx-fi-compact\"\n [class.ngx-fi-compact--dragover]=\"isDragOver()\"\n [class.ngx-fi-compact--disabled]=\"disabled()\"\n role=\"region\"\n [attr.aria-label]=\"label()\"\n [attr.aria-disabled]=\"disabled()\"\n tabindex=\"0\"\n (click)=\"openFilePicker()\"\n (keydown.enter)=\"openFilePicker()\"\n (keydown.space)=\"openFilePicker(); $event.preventDefault()\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n >\n <mat-icon class=\"ngx-fi-compact__icon\">cloud_upload</mat-icon>\n <div class=\"ngx-fi-compact__text\">\n <span class=\"ngx-fi-compact__label\">{{ label() }}</span>\n @if (hint()) {\n <span class=\"ngx-fi-compact__hint\">{{ hint() }}</span>\n }\n </div>\n\n @if (showDropConfirm()) {\n <div class=\"ngx-fi-zone__confirm\">\n <mat-icon>check_circle</mat-icon>\n </div>\n }\n </div>\n}\n\n<!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n VARIANT: BUTTON \u2014 only a button\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n@if (variant() === 'button') {\n <div\n class=\"ngx-fi-button-wrap\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n [class.ngx-fi-button-wrap--dragover]=\"isDragOver()\"\n >\n <button\n mat-raised-button\n color=\"primary\"\n [disabled]=\"disabled()\"\n (click)=\"openFilePicker()\"\n type=\"button\"\n >\n <mat-icon>attach_file</mat-icon>\n {{ label() }}\n </button>\n </div>\n}\n\n<!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n FILE PREVIEW LIST\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n@if (showPreview() && items().length > 0) {\n <div class=\"ngx-fi-list\">\n @for (item of items(); track item.id) {\n <div\n class=\"ngx-fi-item\"\n [class.ngx-fi-item--error]=\"item.status === 'error'\"\n >\n <!-- Thumbnail / Icon -->\n <div class=\"ngx-fi-item__thumb\" [class]=\"getFileColorClass(item.type)\">\n @if (item.preview) {\n <img [src]=\"item.preview\" [alt]=\"item.name\" />\n } @else {\n <mat-icon>{{ getFileIcon(item.type) }}</mat-icon>\n }\n </div>\n\n <!-- Info -->\n <div class=\"ngx-fi-item__info\">\n <span class=\"ngx-fi-item__name\" [matTooltip]=\"item.name\">{{ item.name }}</span>\n <span class=\"ngx-fi-item__meta\">\n {{ formatSize(item.size) }}\n @if (item.error) {\n <span class=\"ngx-fi-item__error\">\n <mat-icon>warning</mat-icon> {{ item.error }}\n </span>\n }\n </span>\n </div>\n\n <!-- Remove -->\n <button\n class=\"ngx-fi-item__remove\"\n type=\"button\"\n mat-icon-button\n (click)=\"removeFile(item); $event.stopPropagation()\"\n [matTooltip]=\"'Eliminar ' + item.name\"\n >\n <mat-icon>close</mat-icon>\n </button>\n </div>\n }\n </div>\n}\n\n<!-- Screen reader announcements -->\n<div class=\"ngx-fi-sr-only\" aria-live=\"polite\">{{ liveAnnouncement() }}</div>\n", styles: [".ngx-fi-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.ngx-fi-native-input{position:absolute;width:0;height:0;opacity:0;pointer-events:none}.ngx-fi-zone{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;min-height:180px;padding:2rem 1.5rem;border:2px dashed var(--mat-sys-outline-variant, #c4c4c4);border-radius:12px;background:var(--mat-sys-surface-container-low, #fafafa);cursor:pointer;transition:border-color .2s,background-color .2s,box-shadow .2s;outline:none;-webkit-user-select:none;user-select:none;overflow:hidden}.ngx-fi-zone:hover:not(.ngx-fi-zone--disabled){border-style:solid;background:var(--mat-sys-surface-container, #f0f0f0)}.ngx-fi-zone:focus-visible:not(.ngx-fi-zone--disabled){box-shadow:0 0 0 3px #5c6bc040;border-color:var(--mat-sys-primary, #5c6bc0)}.ngx-fi-zone--dragover{border-color:var(--mat-sys-primary, #5c6bc0);border-style:solid;background:var(--mat-sys-primary-container, rgba(92, 107, 192, .08));box-shadow:inset 0 0 0 2px var(--mat-sys-primary, #5c6bc0),0 0 16px #5c6bc033;animation:ngx-fi-glow 1s ease-in-out infinite}.ngx-fi-zone--dragover .ngx-fi-zone__icon{transform:scale(1.15);color:var(--mat-sys-primary, #5c6bc0)}.ngx-fi-zone--disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.ngx-fi-zone__icon{font-size:48px;width:48px;height:48px;color:var(--mat-sys-on-surface-variant, #666);transition:transform .2s,color .2s}.ngx-fi-zone__label{font-size:1.05rem;font-weight:500;color:var(--mat-sys-on-surface, #333);text-align:center}.ngx-fi-zone__hint{font-size:.82rem;color:var(--mat-sys-on-surface-variant, #666);text-align:center}.ngx-fi-zone__btn-text{font-size:.82rem;color:var(--mat-sys-primary, #5c6bc0);font-weight:500;margin-top:.25rem}.ngx-fi-zone__confirm{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:#43a0471f;pointer-events:none;animation:ngx-fi-confirm-flash .4s ease-out forwards}.ngx-fi-zone__confirm mat-icon{font-size:56px;width:56px;height:56px;color:var(--mat-sys-tertiary, #43a047)}.ngx-fi-compact{position:relative;display:flex;align-items:center;gap:1rem;height:80px;padding:0 1.25rem;border:2px dashed var(--mat-sys-outline-variant, #c4c4c4);border-radius:12px;background:var(--mat-sys-surface-container-low, #fafafa);cursor:pointer;transition:border-color .2s,background-color .2s,box-shadow .2s;outline:none;-webkit-user-select:none;user-select:none;overflow:hidden}.ngx-fi-compact:hover:not(.ngx-fi-compact--disabled){border-style:solid;background:var(--mat-sys-surface-container, #f0f0f0)}.ngx-fi-compact:focus-visible:not(.ngx-fi-compact--disabled){box-shadow:0 0 0 3px #5c6bc040;border-color:var(--mat-sys-primary, #5c6bc0)}.ngx-fi-compact--dragover{border-color:var(--mat-sys-primary, #5c6bc0);border-style:solid;background:var(--mat-sys-primary-container, rgba(92, 107, 192, .08));box-shadow:inset 0 0 0 2px var(--mat-sys-primary, #5c6bc0),0 0 16px #5c6bc033;animation:ngx-fi-glow 1s ease-in-out infinite}.ngx-fi-compact--dragover .ngx-fi-compact__icon{transform:scale(1.1);color:var(--mat-sys-primary, #5c6bc0)}.ngx-fi-compact--disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.ngx-fi-compact__icon{font-size:32px;width:32px;height:32px;color:var(--mat-sys-on-surface-variant, #666);flex-shrink:0;transition:transform .2s,color .2s}.ngx-fi-compact__text{display:flex;flex-direction:column;gap:.15rem;min-width:0}.ngx-fi-compact__label{font-size:.95rem;font-weight:500;color:var(--mat-sys-on-surface, #333)}.ngx-fi-compact__hint{font-size:.78rem;color:var(--mat-sys-on-surface-variant, #666)}.ngx-fi-button-wrap{display:inline-block;position:relative;padding:4px;border-radius:8px;transition:background-color .2s,box-shadow .2s}.ngx-fi-button-wrap--dragover{background:var(--mat-sys-primary-container, rgba(92, 107, 192, .08));box-shadow:0 0 12px #5c6bc040}.ngx-fi-list{display:flex;flex-direction:column;gap:.5rem;margin-top:.75rem}.ngx-fi-item{display:flex;align-items:center;gap:.75rem;padding:.5rem .65rem;border-radius:10px;background:var(--mat-sys-surface-container-low, #fafafa);border:1px solid var(--mat-sys-outline-variant, #e0e0e0);transition:border-color .2s,background-color .2s;animation:ngx-fi-item-enter .2s ease-out both}.ngx-fi-item--error{border-color:var(--mat-sys-error, #d32f2f);background:#d32f2f0a}.ngx-fi-item__thumb{width:42px;height:42px;border-radius:8px;display:flex;align-items:center;justify-content:center;flex-shrink:0;overflow:hidden}.ngx-fi-item__thumb img{width:100%;height:100%;object-fit:cover;border-radius:8px}.ngx-fi-item__thumb mat-icon{font-size:24px;width:24px;height:24px}.ngx-fi-item__info{flex:1;min-width:0;display:flex;flex-direction:column;gap:.1rem}.ngx-fi-item__name{font-size:.88rem;font-weight:500;color:var(--mat-sys-on-surface, #333);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ngx-fi-item__meta{font-size:.75rem;color:var(--mat-sys-on-surface-variant, #666);display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}.ngx-fi-item__error{color:var(--mat-sys-error, #d32f2f);display:inline-flex;align-items:center;gap:.2rem;font-weight:500}.ngx-fi-item__error mat-icon{font-size:14px;width:14px;height:14px}.ngx-fi-item__remove{flex-shrink:0}.ngx-fi-icon--image{background:#5c6bc01a}.ngx-fi-icon--image mat-icon{color:#5c6bc0}.ngx-fi-icon--pdf{background:#d32f2f1a}.ngx-fi-icon--pdf mat-icon{color:#d32f2f}.ngx-fi-icon--video{background:#1e88e51a}.ngx-fi-icon--video mat-icon{color:#1e88e5}.ngx-fi-icon--audio{background:#8e24aa1a}.ngx-fi-icon--audio mat-icon{color:#8e24aa}.ngx-fi-icon--generic{background:#0000000f}.ngx-fi-icon--generic mat-icon{color:#757575}@keyframes ngx-fi-item-enter{0%{opacity:0;transform:translateY(8px) scale(.96)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes ngx-fi-confirm-flash{0%{opacity:1}to{opacity:0}}.ngx-fi-item:nth-child(1){animation-delay:0ms}.ngx-fi-item:nth-child(2){animation-delay:50ms}.ngx-fi-item:nth-child(3){animation-delay:.1s}.ngx-fi-item:nth-child(4){animation-delay:.15s}.ngx-fi-item:nth-child(5){animation-delay:.2s}.ngx-fi-item:nth-child(6){animation-delay:.25s}.ngx-fi-item:nth-child(7){animation-delay:.3s}.ngx-fi-item:nth-child(8){animation-delay:.35s}.ngx-fi-item:nth-child(9){animation-delay:.4s}.ngx-fi-item:nth-child(10){animation-delay:.45s}.ngx-fi-item:nth-child(11){animation-delay:.5s}.ngx-fi-item:nth-child(12){animation-delay:.55s}.ngx-fi-item:nth-child(13){animation-delay:.6s}.ngx-fi-item:nth-child(14){animation-delay:.65s}.ngx-fi-item:nth-child(15){animation-delay:.7s}.ngx-fi-item:nth-child(16){animation-delay:.75s}.ngx-fi-item:nth-child(17){animation-delay:.8s}.ngx-fi-item:nth-child(18){animation-delay:.85s}.ngx-fi-item:nth-child(19){animation-delay:.9s}.ngx-fi-item:nth-child(20){animation-delay:.95s}@keyframes ngx-fi-glow{0%,to{box-shadow:inset 0 0 0 2px var(--mat-sys-primary, #5c6bc0),0 0 12px #5c6bc02e}50%{box-shadow:inset 0 0 0 2px var(--mat-sys-primary, #5c6bc0),0 0 22px #5c6bc059}}\n"] }]
3766
+ }], propDecorators: { accept: [{ type: i0.Input, args: [{ isSignal: true, alias: "accept", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], maxSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxSize", required: false }] }], maxFiles: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFiles", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], showPreview: [{ type: i0.Input, args: [{ isSignal: true, alias: "showPreview", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], filesSelected: [{ type: i0.Output, args: ["filesSelected"] }], fileRemoved: [{ type: i0.Output, args: ["fileRemoved"] }], validationError: [{ type: i0.Output, args: ["validationError"] }] } });
3767
+
3415
3768
  class NgxDialogService {
3416
3769
  // dependencies injection
3417
3770
  _dialog = inject(MatDialog);
@@ -3568,5 +3921,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
3568
3921
  * Generated bundle index. Do not edit.
3569
3922
  */
3570
3923
 
3571
- export { DynamicHostDirective, NgxAlert, NgxBasicSelect, NgxBasicTable, NgxConfirmDialogComponent, NgxDialog, NgxDialogService, NgxInputFile, NgxLoadingButton, NgxPaginatedSelect, NgxPaginatedSelectBottomSheetComponent, NgxPaginatedTable, NgxTablesIntl, OPERATOR_BY_FILTER_TYPE, PaginatedSearchableSelectComponent, SearchableSelectComponent, USER_ID_FACTORY, base64ToUtf8, includeNoSensible, isFilterOption };
3924
+ export { DynamicHostDirective, NgxAlert, NgxBasicSelect, NgxBasicTable, NgxConfirmDialogComponent, NgxDialog, NgxDialogService, NgxFileInput, NgxInputFile, NgxLoadingButton, NgxPaginatedSelect, NgxPaginatedSelectBottomSheetComponent, NgxPaginatedTable, NgxSkeleton, NgxTablesIntl, OPERATOR_BY_FILTER_TYPE, PaginatedSearchableSelectComponent, SearchableSelectComponent, USER_ID_FACTORY, base64ToUtf8, includeNoSensible, isFilterOption };
3572
3925
  //# sourceMappingURL=ngx-eiffage-material.mjs.map