@praxisui/files-upload 1.0.0-beta.5 → 1.0.0-beta.52

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,6 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { Injectable, inject, signal, Inject, Component, InjectionToken, Optional, EventEmitter, ViewChild, Output, Input, ChangeDetectionStrategy, ENVIRONMENT_INITIALIZER } from '@angular/core';
3
+ import { ActivatedRoute } from '@angular/router';
3
4
  import * as i7 from '@angular/common';
4
5
  import { CommonModule } from '@angular/common';
5
6
  import * as i1$1 from '@angular/forms';
@@ -8,13 +9,13 @@ import * as i9 from '@angular/material/button';
8
9
  import { MatButtonModule } from '@angular/material/button';
9
10
  import * as i10 from '@angular/material/icon';
10
11
  import { MatIconModule } from '@angular/material/icon';
11
- import * as i11 from '@angular/material/progress-bar';
12
+ import * as i11$1 from '@angular/material/progress-bar';
12
13
  import { MatProgressBarModule } from '@angular/material/progress-bar';
13
14
  import * as i3$1 from '@angular/material/menu';
14
15
  import { MatMenuModule } from '@angular/material/menu';
15
16
  import * as i1 from '@angular/common/http';
16
17
  import { HttpHeaders, HttpEventType, HttpErrorResponse } from '@angular/common/http';
17
- import { CONFIG_STORAGE, PraxisIconDirective, ComponentMetadataRegistry } from '@praxisui/core';
18
+ import { ComponentKeyService, ASYNC_CONFIG_STORAGE, PraxisIconDirective, ComponentMetadataRegistry } from '@praxisui/core';
18
19
  import * as i4 from '@angular/material/tabs';
19
20
  import { MatTabsModule } from '@angular/material/tabs';
20
21
  import * as i5 from '@angular/material/form-field';
@@ -25,16 +26,16 @@ import * as i7$1 from '@angular/material/checkbox';
25
26
  import { MatCheckboxModule } from '@angular/material/checkbox';
26
27
  import * as i8 from '@angular/material/select';
27
28
  import { MatSelectModule } from '@angular/material/select';
29
+ import * as i11 from '@angular/material/tooltip';
30
+ import { MatTooltipModule } from '@angular/material/tooltip';
28
31
  import * as i2 from '@angular/material/snack-bar';
29
32
  import { MatSnackBarModule } from '@angular/material/snack-bar';
30
33
  import { toObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop';
31
34
  import { of, throwError, BehaviorSubject, map as map$1, startWith, retry, debounceTime } from 'rxjs';
32
35
  import * as i1$2 from '@praxisui/settings-panel';
33
36
  import { SETTINGS_PANEL_DATA } from '@praxisui/settings-panel';
34
- import { map, catchError } from 'rxjs/operators';
37
+ import { map, catchError, take } from 'rxjs/operators';
35
38
  import { TemplatePortal } from '@angular/cdk/portal';
36
- import * as i13 from '@angular/material/tooltip';
37
- import { MatTooltipModule } from '@angular/material/tooltip';
38
39
  import * as i3 from '@angular/cdk/overlay';
39
40
  import { SimpleBaseInputComponent } from '@praxisui/dynamic-fields';
40
41
 
@@ -131,10 +132,10 @@ class ConfigService {
131
132
  return throwError(() => err);
132
133
  }));
133
134
  }
134
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: ConfigService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
135
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: ConfigService, providedIn: 'root' });
135
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ConfigService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
136
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ConfigService, providedIn: 'root' });
136
137
  }
137
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: ConfigService, decorators: [{
138
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ConfigService, decorators: [{
138
139
  type: Injectable,
139
140
  args: [{ providedIn: 'root' }]
140
141
  }], ctorParameters: () => [{ type: i1.HttpClient }] });
@@ -724,8 +725,8 @@ class PraxisFilesUploadConfigEditor {
724
725
  refetchServerConfig() {
725
726
  this.state.refetch();
726
727
  }
727
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PraxisFilesUploadConfigEditor, deps: [{ token: i1$1.FormBuilder }, { token: SETTINGS_PANEL_DATA }, { token: i2.MatSnackBar }, { token: i0.DestroyRef }], target: i0.ɵɵFactoryTarget.Component });
728
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.4", type: PraxisFilesUploadConfigEditor, isStandalone: true, selector: "praxis-files-upload-config-editor", ngImport: i0, template: `
728
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisFilesUploadConfigEditor, deps: [{ token: i1$1.FormBuilder }, { token: SETTINGS_PANEL_DATA }, { token: i2.MatSnackBar }, { token: i0.DestroyRef }], target: i0.ɵɵFactoryTarget.Component });
729
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: PraxisFilesUploadConfigEditor, isStandalone: true, selector: "praxis-files-upload-config-editor", ngImport: i0, template: `
729
730
  <mat-tab-group>
730
731
  <mat-tab label="Comportamento">
731
732
  <form [formGroup]="form">
@@ -734,11 +735,20 @@ class PraxisFilesUploadConfigEditor {
734
735
  <mat-select formControlName="strategy">
735
736
  <mat-option value="direct">Direto (HTTP padrão)</mat-option>
736
737
  <mat-option value="presign">URL pré-assinada (S3/GCS)</mat-option>
737
- <mat-option value="auto"
738
- >Automático (tenta pré-assinada e volta ao direto)</mat-option
739
- >
740
- </mat-select>
741
- <mat-hint>Como os arquivos serão enviados ao servidor.</mat-hint>
738
+ <mat-option value="auto"
739
+ >Automático (tenta pré-assinada e volta ao direto)</mat-option
740
+ >
741
+ </mat-select>
742
+ <button
743
+ mat-icon-button
744
+ matSuffix
745
+ class="help-icon-button"
746
+ type="button"
747
+ [matTooltip]="'Como os arquivos serão enviados ao servidor.'"
748
+ matTooltipPosition="above"
749
+ >
750
+ <mat-icon>help_outline</mat-icon>
751
+ </button>
742
752
  </mat-form-field>
743
753
  </form>
744
754
  <form [formGroup]="bulkGroup">
@@ -749,17 +759,44 @@ class PraxisFilesUploadConfigEditor {
749
759
  <mat-form-field appearance="fill">
750
760
  <mat-label>Uploads paralelos <span class="opt-tag">opcional</span></mat-label>
751
761
  <input matInput type="number" formControlName="parallelUploads" />
752
- <mat-hint>Quantos arquivos enviar ao mesmo tempo.</mat-hint>
762
+ <button
763
+ mat-icon-button
764
+ matSuffix
765
+ class="help-icon-button"
766
+ type="button"
767
+ [matTooltip]="'Quantos arquivos enviar ao mesmo tempo.'"
768
+ matTooltipPosition="above"
769
+ >
770
+ <mat-icon>help_outline</mat-icon>
771
+ </button>
753
772
  </mat-form-field>
754
773
  <mat-form-field appearance="fill">
755
774
  <mat-label>Número de tentativas <span class="opt-tag">opcional</span></mat-label>
756
775
  <input matInput type="number" formControlName="retryCount" />
757
- <mat-hint>Tentativas automáticas em caso de falha.</mat-hint>
776
+ <button
777
+ mat-icon-button
778
+ matSuffix
779
+ class="help-icon-button"
780
+ type="button"
781
+ [matTooltip]="'Tentativas automáticas em caso de falha.'"
782
+ matTooltipPosition="above"
783
+ >
784
+ <mat-icon>help_outline</mat-icon>
785
+ </button>
758
786
  </mat-form-field>
759
787
  <mat-form-field appearance="fill">
760
788
  <mat-label>Intervalo entre tentativas (ms) <span class="opt-tag">opcional</span></mat-label>
761
789
  <input matInput type="number" formControlName="retryBackoffMs" />
762
- <mat-hint>Tempo de espera entre tentativas.</mat-hint>
790
+ <button
791
+ mat-icon-button
792
+ matSuffix
793
+ class="help-icon-button"
794
+ type="button"
795
+ [matTooltip]="'Tempo de espera entre tentativas.'"
796
+ matTooltipPosition="above"
797
+ >
798
+ <mat-icon>help_outline</mat-icon>
799
+ </button>
763
800
  </mat-form-field>
764
801
  </form>
765
802
  </mat-tab>
@@ -789,7 +826,16 @@ class PraxisFilesUploadConfigEditor {
789
826
  formControlName="accept"
790
827
  placeholder="ex.: pdf,jpg,png"
791
828
  />
792
- <mat-hint>Lista separada por vírgula (opcional).</mat-hint>
829
+ <button
830
+ mat-icon-button
831
+ matSuffix
832
+ class="help-icon-button"
833
+ type="button"
834
+ [matTooltip]="'Lista separada por vírgula (opcional).'"
835
+ matTooltipPosition="above"
836
+ >
837
+ <mat-icon>help_outline</mat-icon>
838
+ </button>
793
839
  </mat-form-field>
794
840
  <mat-checkbox formControlName="showMetadataForm"
795
841
  >Exibir formulário de metadados (JSON)</mat-checkbox
@@ -850,11 +896,20 @@ class PraxisFilesUploadConfigEditor {
850
896
  <mat-checkbox formControlName="detailsShowTechnical">
851
897
  Mostrar detalhes técnicos por padrão
852
898
  </mat-checkbox>
853
- <mat-form-field appearance="fill">
854
- <mat-label>Campos de metadados (whitelist) <span class="opt-tag">opcional</span></mat-label>
855
- <input matInput formControlName="detailsFields" placeholder="ex.: id,fileName,contentType" />
856
- <mat-hint>Lista separada por vírgula; vazio = todos.</mat-hint>
857
- </mat-form-field>
899
+ <mat-form-field appearance="fill">
900
+ <mat-label>Campos de metadados (whitelist) <span class="opt-tag">opcional</span></mat-label>
901
+ <input matInput formControlName="detailsFields" placeholder="ex.: id,fileName,contentType" />
902
+ <button
903
+ mat-icon-button
904
+ matSuffix
905
+ class="help-icon-button"
906
+ type="button"
907
+ [matTooltip]="'Lista separada por vírgula; vazio = todos.'"
908
+ matTooltipPosition="above"
909
+ >
910
+ <mat-icon>help_outline</mat-icon>
911
+ </button>
912
+ </mat-form-field>
858
913
  <mat-form-field appearance="fill">
859
914
  <mat-label>Âncora do overlay</mat-label>
860
915
  <mat-select formControlName="detailsAnchor">
@@ -874,7 +929,16 @@ class PraxisFilesUploadConfigEditor {
874
929
  <mat-form-field appearance="fill">
875
930
  <mat-label>Tamanho máximo do arquivo (bytes) <span class="opt-tag">opcional</span></mat-label>
876
931
  <input matInput type="number" formControlName="maxFileSizeBytes" />
877
- <mat-hint>Limite de validação no cliente (opcional).</mat-hint>
932
+ <button
933
+ mat-icon-button
934
+ matSuffix
935
+ class="help-icon-button"
936
+ type="button"
937
+ [matTooltip]="'Limite de validação no cliente (opcional).'"
938
+ matTooltipPosition="above"
939
+ >
940
+ <mat-icon>help_outline</mat-icon>
941
+ </button>
878
942
  </mat-form-field>
879
943
  <mat-form-field appearance="fill">
880
944
  <mat-label>Máx. arquivos por lote <span class="opt-tag">opcional</span></mat-label>
@@ -893,7 +957,16 @@ class PraxisFilesUploadConfigEditor {
893
957
  <mat-option value="SKIP">Pular se já existir</mat-option>
894
958
  <mat-option value="ERROR">Falhar (erro)</mat-option>
895
959
  </mat-select>
896
- <mat-hint>O que fazer quando o nome do arquivo já existe.</mat-hint>
960
+ <button
961
+ mat-icon-button
962
+ matSuffix
963
+ class="help-icon-button"
964
+ type="button"
965
+ [matTooltip]="'O que fazer quando o nome do arquivo já existe.'"
966
+ matTooltipPosition="above"
967
+ >
968
+ <mat-icon>help_outline</mat-icon>
969
+ </button>
897
970
  <div class="warn" *ngIf="limitsGroup.get('defaultConflictPolicy')?.value === 'OVERWRITE'">
898
971
  <mat-icon color="warn" aria-hidden="true">warning</mat-icon>
899
972
  Atenção: OVERWRITE pode sobrescrever arquivos existentes.
@@ -908,7 +981,16 @@ class PraxisFilesUploadConfigEditor {
908
981
  <mat-form-field appearance="fill">
909
982
  <mat-label>Tamanho máx. por arquivo (MB) <span class="req-tag">mandatório</span></mat-label>
910
983
  <input matInput type="number" formControlName="maxUploadSizeMb" required />
911
- <mat-hint>Validado pelo backend (1–500 MB).</mat-hint>
984
+ <button
985
+ mat-icon-button
986
+ matSuffix
987
+ class="help-icon-button"
988
+ type="button"
989
+ [matTooltip]="'Validado pelo backend (1–500 MB).'"
990
+ matTooltipPosition="above"
991
+ >
992
+ <mat-icon>help_outline</mat-icon>
993
+ </button>
912
994
  </mat-form-field>
913
995
  </form>
914
996
  <form [formGroup]="optionsGroup">
@@ -923,7 +1005,16 @@ class PraxisFilesUploadConfigEditor {
923
1005
  formControlName="allowedExtensions"
924
1006
  placeholder="ex.: pdf,docx,xlsx"
925
1007
  />
926
- <mat-hint>Lista separada por vírgula (opcional).</mat-hint>
1008
+ <button
1009
+ mat-icon-button
1010
+ matSuffix
1011
+ class="help-icon-button"
1012
+ type="button"
1013
+ [matTooltip]="'Lista separada por vírgula (opcional).'"
1014
+ matTooltipPosition="above"
1015
+ >
1016
+ <mat-icon>help_outline</mat-icon>
1017
+ </button>
927
1018
  </mat-form-field>
928
1019
  <mat-form-field appearance="fill">
929
1020
  <mat-label>MIME types aceitos <span class="opt-tag">opcional</span></mat-label>
@@ -932,7 +1023,16 @@ class PraxisFilesUploadConfigEditor {
932
1023
  formControlName="acceptMimeTypes"
933
1024
  placeholder="ex.: application/pdf,image/png"
934
1025
  />
935
- <mat-hint>Lista separada por vírgula (opcional).</mat-hint>
1026
+ <button
1027
+ mat-icon-button
1028
+ matSuffix
1029
+ class="help-icon-button"
1030
+ type="button"
1031
+ [matTooltip]="'Lista separada por vírgula (opcional).'"
1032
+ matTooltipPosition="above"
1033
+ >
1034
+ <mat-icon>help_outline</mat-icon>
1035
+ </button>
936
1036
  </mat-form-field>
937
1037
  <mat-form-field appearance="fill">
938
1038
  <mat-label>Diretório destino <span class="opt-tag">opcional</span></mat-label>
@@ -1154,14 +1254,11 @@ class PraxisFilesUploadConfigEditor {
1154
1254
  <div class="error" *ngIf="jsonError">{{ jsonError }}</div>
1155
1255
  </mat-tab>
1156
1256
  </mat-tab-group>
1157
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i7.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i7.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "component", type: i4.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass", "id"], exportAs: ["matTab"] }, { kind: "component", type: i4.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "mat-align-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5.MatLabel, selector: "mat-label" }, { kind: "directive", type: i5.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i6.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i7$1.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i8.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i8.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i9.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i10.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatSnackBarModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: i7.JsonPipe, name: "json" }] });
1257
+ `, isInline: true, styles: [".help-icon-button{--mdc-icon-button-state-layer-size: 28px;--mdc-icon-button-icon-size: 18px;width:28px;height:28px;padding:0;display:inline-flex;align-items:center;justify-content:center;margin-right:-4px}.help-icon-button mat-icon{font-size:18px;width:18px;height:18px}.mat-mdc-form-field-icon-suffix{align-self:center}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i7.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i7.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "component", type: i4.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass", "id"], exportAs: ["matTab"] }, { kind: "component", type: i4.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "mat-align-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5.MatLabel, selector: "mat-label" }, { kind: "directive", type: i5.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i5.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i6.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i7$1.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i8.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i8.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i9.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i10.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i11.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatSnackBarModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: i7.JsonPipe, name: "json" }] });
1158
1258
  }
1159
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PraxisFilesUploadConfigEditor, decorators: [{
1259
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisFilesUploadConfigEditor, decorators: [{
1160
1260
  type: Component,
1161
- args: [{
1162
- selector: 'praxis-files-upload-config-editor',
1163
- standalone: true,
1164
- imports: [
1261
+ args: [{ selector: 'praxis-files-upload-config-editor', standalone: true, imports: [
1165
1262
  CommonModule,
1166
1263
  ReactiveFormsModule,
1167
1264
  MatTabsModule,
@@ -1171,10 +1268,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
1171
1268
  MatSelectModule,
1172
1269
  MatButtonModule,
1173
1270
  MatIconModule,
1271
+ MatTooltipModule,
1174
1272
  MatSnackBarModule,
1175
1273
  FormsModule,
1176
- ],
1177
- template: `
1274
+ ], template: `
1178
1275
  <mat-tab-group>
1179
1276
  <mat-tab label="Comportamento">
1180
1277
  <form [formGroup]="form">
@@ -1183,11 +1280,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
1183
1280
  <mat-select formControlName="strategy">
1184
1281
  <mat-option value="direct">Direto (HTTP padrão)</mat-option>
1185
1282
  <mat-option value="presign">URL pré-assinada (S3/GCS)</mat-option>
1186
- <mat-option value="auto"
1187
- >Automático (tenta pré-assinada e volta ao direto)</mat-option
1188
- >
1189
- </mat-select>
1190
- <mat-hint>Como os arquivos serão enviados ao servidor.</mat-hint>
1283
+ <mat-option value="auto"
1284
+ >Automático (tenta pré-assinada e volta ao direto)</mat-option
1285
+ >
1286
+ </mat-select>
1287
+ <button
1288
+ mat-icon-button
1289
+ matSuffix
1290
+ class="help-icon-button"
1291
+ type="button"
1292
+ [matTooltip]="'Como os arquivos serão enviados ao servidor.'"
1293
+ matTooltipPosition="above"
1294
+ >
1295
+ <mat-icon>help_outline</mat-icon>
1296
+ </button>
1191
1297
  </mat-form-field>
1192
1298
  </form>
1193
1299
  <form [formGroup]="bulkGroup">
@@ -1198,17 +1304,44 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
1198
1304
  <mat-form-field appearance="fill">
1199
1305
  <mat-label>Uploads paralelos <span class="opt-tag">opcional</span></mat-label>
1200
1306
  <input matInput type="number" formControlName="parallelUploads" />
1201
- <mat-hint>Quantos arquivos enviar ao mesmo tempo.</mat-hint>
1307
+ <button
1308
+ mat-icon-button
1309
+ matSuffix
1310
+ class="help-icon-button"
1311
+ type="button"
1312
+ [matTooltip]="'Quantos arquivos enviar ao mesmo tempo.'"
1313
+ matTooltipPosition="above"
1314
+ >
1315
+ <mat-icon>help_outline</mat-icon>
1316
+ </button>
1202
1317
  </mat-form-field>
1203
1318
  <mat-form-field appearance="fill">
1204
1319
  <mat-label>Número de tentativas <span class="opt-tag">opcional</span></mat-label>
1205
1320
  <input matInput type="number" formControlName="retryCount" />
1206
- <mat-hint>Tentativas automáticas em caso de falha.</mat-hint>
1321
+ <button
1322
+ mat-icon-button
1323
+ matSuffix
1324
+ class="help-icon-button"
1325
+ type="button"
1326
+ [matTooltip]="'Tentativas automáticas em caso de falha.'"
1327
+ matTooltipPosition="above"
1328
+ >
1329
+ <mat-icon>help_outline</mat-icon>
1330
+ </button>
1207
1331
  </mat-form-field>
1208
1332
  <mat-form-field appearance="fill">
1209
1333
  <mat-label>Intervalo entre tentativas (ms) <span class="opt-tag">opcional</span></mat-label>
1210
1334
  <input matInput type="number" formControlName="retryBackoffMs" />
1211
- <mat-hint>Tempo de espera entre tentativas.</mat-hint>
1335
+ <button
1336
+ mat-icon-button
1337
+ matSuffix
1338
+ class="help-icon-button"
1339
+ type="button"
1340
+ [matTooltip]="'Tempo de espera entre tentativas.'"
1341
+ matTooltipPosition="above"
1342
+ >
1343
+ <mat-icon>help_outline</mat-icon>
1344
+ </button>
1212
1345
  </mat-form-field>
1213
1346
  </form>
1214
1347
  </mat-tab>
@@ -1238,7 +1371,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
1238
1371
  formControlName="accept"
1239
1372
  placeholder="ex.: pdf,jpg,png"
1240
1373
  />
1241
- <mat-hint>Lista separada por vírgula (opcional).</mat-hint>
1374
+ <button
1375
+ mat-icon-button
1376
+ matSuffix
1377
+ class="help-icon-button"
1378
+ type="button"
1379
+ [matTooltip]="'Lista separada por vírgula (opcional).'"
1380
+ matTooltipPosition="above"
1381
+ >
1382
+ <mat-icon>help_outline</mat-icon>
1383
+ </button>
1242
1384
  </mat-form-field>
1243
1385
  <mat-checkbox formControlName="showMetadataForm"
1244
1386
  >Exibir formulário de metadados (JSON)</mat-checkbox
@@ -1299,11 +1441,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
1299
1441
  <mat-checkbox formControlName="detailsShowTechnical">
1300
1442
  Mostrar detalhes técnicos por padrão
1301
1443
  </mat-checkbox>
1302
- <mat-form-field appearance="fill">
1303
- <mat-label>Campos de metadados (whitelist) <span class="opt-tag">opcional</span></mat-label>
1304
- <input matInput formControlName="detailsFields" placeholder="ex.: id,fileName,contentType" />
1305
- <mat-hint>Lista separada por vírgula; vazio = todos.</mat-hint>
1306
- </mat-form-field>
1444
+ <mat-form-field appearance="fill">
1445
+ <mat-label>Campos de metadados (whitelist) <span class="opt-tag">opcional</span></mat-label>
1446
+ <input matInput formControlName="detailsFields" placeholder="ex.: id,fileName,contentType" />
1447
+ <button
1448
+ mat-icon-button
1449
+ matSuffix
1450
+ class="help-icon-button"
1451
+ type="button"
1452
+ [matTooltip]="'Lista separada por vírgula; vazio = todos.'"
1453
+ matTooltipPosition="above"
1454
+ >
1455
+ <mat-icon>help_outline</mat-icon>
1456
+ </button>
1457
+ </mat-form-field>
1307
1458
  <mat-form-field appearance="fill">
1308
1459
  <mat-label>Âncora do overlay</mat-label>
1309
1460
  <mat-select formControlName="detailsAnchor">
@@ -1323,7 +1474,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
1323
1474
  <mat-form-field appearance="fill">
1324
1475
  <mat-label>Tamanho máximo do arquivo (bytes) <span class="opt-tag">opcional</span></mat-label>
1325
1476
  <input matInput type="number" formControlName="maxFileSizeBytes" />
1326
- <mat-hint>Limite de validação no cliente (opcional).</mat-hint>
1477
+ <button
1478
+ mat-icon-button
1479
+ matSuffix
1480
+ class="help-icon-button"
1481
+ type="button"
1482
+ [matTooltip]="'Limite de validação no cliente (opcional).'"
1483
+ matTooltipPosition="above"
1484
+ >
1485
+ <mat-icon>help_outline</mat-icon>
1486
+ </button>
1327
1487
  </mat-form-field>
1328
1488
  <mat-form-field appearance="fill">
1329
1489
  <mat-label>Máx. arquivos por lote <span class="opt-tag">opcional</span></mat-label>
@@ -1342,7 +1502,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
1342
1502
  <mat-option value="SKIP">Pular se já existir</mat-option>
1343
1503
  <mat-option value="ERROR">Falhar (erro)</mat-option>
1344
1504
  </mat-select>
1345
- <mat-hint>O que fazer quando o nome do arquivo já existe.</mat-hint>
1505
+ <button
1506
+ mat-icon-button
1507
+ matSuffix
1508
+ class="help-icon-button"
1509
+ type="button"
1510
+ [matTooltip]="'O que fazer quando o nome do arquivo já existe.'"
1511
+ matTooltipPosition="above"
1512
+ >
1513
+ <mat-icon>help_outline</mat-icon>
1514
+ </button>
1346
1515
  <div class="warn" *ngIf="limitsGroup.get('defaultConflictPolicy')?.value === 'OVERWRITE'">
1347
1516
  <mat-icon color="warn" aria-hidden="true">warning</mat-icon>
1348
1517
  Atenção: OVERWRITE pode sobrescrever arquivos existentes.
@@ -1357,7 +1526,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
1357
1526
  <mat-form-field appearance="fill">
1358
1527
  <mat-label>Tamanho máx. por arquivo (MB) <span class="req-tag">mandatório</span></mat-label>
1359
1528
  <input matInput type="number" formControlName="maxUploadSizeMb" required />
1360
- <mat-hint>Validado pelo backend (1–500 MB).</mat-hint>
1529
+ <button
1530
+ mat-icon-button
1531
+ matSuffix
1532
+ class="help-icon-button"
1533
+ type="button"
1534
+ [matTooltip]="'Validado pelo backend (1–500 MB).'"
1535
+ matTooltipPosition="above"
1536
+ >
1537
+ <mat-icon>help_outline</mat-icon>
1538
+ </button>
1361
1539
  </mat-form-field>
1362
1540
  </form>
1363
1541
  <form [formGroup]="optionsGroup">
@@ -1372,7 +1550,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
1372
1550
  formControlName="allowedExtensions"
1373
1551
  placeholder="ex.: pdf,docx,xlsx"
1374
1552
  />
1375
- <mat-hint>Lista separada por vírgula (opcional).</mat-hint>
1553
+ <button
1554
+ mat-icon-button
1555
+ matSuffix
1556
+ class="help-icon-button"
1557
+ type="button"
1558
+ [matTooltip]="'Lista separada por vírgula (opcional).'"
1559
+ matTooltipPosition="above"
1560
+ >
1561
+ <mat-icon>help_outline</mat-icon>
1562
+ </button>
1376
1563
  </mat-form-field>
1377
1564
  <mat-form-field appearance="fill">
1378
1565
  <mat-label>MIME types aceitos <span class="opt-tag">opcional</span></mat-label>
@@ -1381,7 +1568,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
1381
1568
  formControlName="acceptMimeTypes"
1382
1569
  placeholder="ex.: application/pdf,image/png"
1383
1570
  />
1384
- <mat-hint>Lista separada por vírgula (opcional).</mat-hint>
1571
+ <button
1572
+ mat-icon-button
1573
+ matSuffix
1574
+ class="help-icon-button"
1575
+ type="button"
1576
+ [matTooltip]="'Lista separada por vírgula (opcional).'"
1577
+ matTooltipPosition="above"
1578
+ >
1579
+ <mat-icon>help_outline</mat-icon>
1580
+ </button>
1385
1581
  </mat-form-field>
1386
1582
  <mat-form-field appearance="fill">
1387
1583
  <mat-label>Diretório destino <span class="opt-tag">opcional</span></mat-label>
@@ -1603,8 +1799,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
1603
1799
  <div class="error" *ngIf="jsonError">{{ jsonError }}</div>
1604
1800
  </mat-tab>
1605
1801
  </mat-tab-group>
1606
- `,
1607
- }]
1802
+ `, styles: [".help-icon-button{--mdc-icon-button-state-layer-size: 28px;--mdc-icon-button-icon-size: 18px;width:28px;height:28px;padding:0;display:inline-flex;align-items:center;justify-content:center;margin-right:-4px}.help-icon-button mat-icon{font-size:18px;width:18px;height:18px}.mat-mdc-form-field-icon-suffix{align-self:center}\n"] }]
1608
1803
  }], ctorParameters: () => [{ type: i1$1.FormBuilder }, { type: undefined, decorators: [{
1609
1804
  type: Inject,
1610
1805
  args: [SETTINGS_PANEL_DATA]
@@ -1696,10 +1891,10 @@ class ErrorMapperService {
1696
1891
  }
1697
1892
  return mapped;
1698
1893
  }
1699
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: ErrorMapperService, deps: [{ token: FILES_UPLOAD_ERROR_MESSAGES, optional: true }, { token: TRANSLATE_LIKE, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
1700
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: ErrorMapperService, providedIn: 'root' });
1894
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ErrorMapperService, deps: [{ token: FILES_UPLOAD_ERROR_MESSAGES, optional: true }, { token: TRANSLATE_LIKE, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
1895
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ErrorMapperService, providedIn: 'root' });
1701
1896
  }
1702
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: ErrorMapperService, decorators: [{
1897
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ErrorMapperService, decorators: [{
1703
1898
  type: Injectable,
1704
1899
  args: [{ providedIn: 'root' }]
1705
1900
  }], ctorParameters: () => [{ type: undefined, decorators: [{
@@ -1836,10 +2031,10 @@ class DragProximityService {
1836
2031
  this.draggingWithFiles$.next(false);
1837
2032
  this.pointer$.next({ x: -9999, y: -9999 });
1838
2033
  };
1839
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: DragProximityService, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable });
1840
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: DragProximityService, providedIn: 'root' });
2034
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: DragProximityService, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable });
2035
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: DragProximityService, providedIn: 'root' });
1841
2036
  }
1842
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: DragProximityService, decorators: [{
2037
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: DragProximityService, decorators: [{
1843
2038
  type: Injectable,
1844
2039
  args: [{ providedIn: 'root' }]
1845
2040
  }], ctorParameters: () => [{ type: i0.NgZone }] });
@@ -1903,10 +2098,10 @@ class FilesApiClient {
1903
2098
  const url = `${baseUrl}/upload/presign?filename=${encodeURIComponent(fileName)}`;
1904
2099
  return this.http.post(url, null, { observe: 'body' });
1905
2100
  }
1906
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: FilesApiClient, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
1907
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: FilesApiClient, providedIn: 'root' });
2101
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: FilesApiClient, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
2102
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: FilesApiClient, providedIn: 'root' });
1908
2103
  }
1909
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: FilesApiClient, decorators: [{
2104
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: FilesApiClient, decorators: [{
1910
2105
  type: Injectable,
1911
2106
  args: [{ providedIn: 'root' }]
1912
2107
  }], ctorParameters: () => [{ type: i1.HttpClient }] });
@@ -1936,10 +2131,10 @@ class PresignedUploaderService {
1936
2131
  })
1937
2132
  .pipe(retry(retryCount));
1938
2133
  }
1939
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PresignedUploaderService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
1940
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PresignedUploaderService, providedIn: 'root' });
2134
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PresignedUploaderService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
2135
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PresignedUploaderService, providedIn: 'root' });
1941
2136
  }
1942
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PresignedUploaderService, decorators: [{
2137
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PresignedUploaderService, decorators: [{
1943
2138
  type: Injectable,
1944
2139
  args: [{ providedIn: 'root' }]
1945
2140
  }], ctorParameters: () => [{ type: i1.HttpClient }] });
@@ -1951,19 +2146,43 @@ class PraxisFilesUpload {
1951
2146
  overlay;
1952
2147
  viewContainerRef;
1953
2148
  cdr;
2149
+ configStorage;
1954
2150
  api;
1955
2151
  presign;
1956
2152
  errors;
1957
2153
  translate;
1958
- configStorage;
1959
2154
  config = null;
1960
- componentId = 'default';
2155
+ _filesUploadId = '';
2156
+ _uploadId = '';
2157
+ set filesUploadId(value) {
2158
+ this._filesUploadId = value ?? '';
2159
+ if (!this._uploadId)
2160
+ this._uploadId = this._filesUploadId;
2161
+ }
2162
+ get filesUploadId() {
2163
+ return this._filesUploadId;
2164
+ }
2165
+ set uploadId(value) {
2166
+ const v = value ?? '';
2167
+ this._uploadId = v;
2168
+ if (!this._filesUploadId)
2169
+ this._filesUploadId = v;
2170
+ }
2171
+ get uploadId() {
2172
+ return this._uploadId;
2173
+ }
2174
+ componentInstanceId;
1961
2175
  baseUrl;
1962
2176
  displayMode = 'full';
2177
+ context = null;
2178
+ editModeEnabled = true;
1963
2179
  uploadSuccess = new EventEmitter();
1964
2180
  bulkComplete = new EventEmitter();
1965
2181
  error = new EventEmitter();
1966
2182
  rateLimited = new EventEmitter();
2183
+ uploadStart = new EventEmitter();
2184
+ uploadProgress = new EventEmitter();
2185
+ uploadError = new EventEmitter();
1967
2186
  // Novos outputs Sub-issue 4
1968
2187
  retry = new EventEmitter();
1969
2188
  download = new EventEmitter();
@@ -1979,7 +2198,7 @@ class PraxisFilesUpload {
1979
2198
  selectedOverlayTmpl;
1980
2199
  conflictPolicies = ['RENAME', 'ERROR', 'OVERWRITE', 'SKIP', 'MAKE_UNIQUE'];
1981
2200
  conflictPolicy = new FormControl('RENAME');
1982
- uploadProgress = 0;
2201
+ uploadProgressValue = 0;
1983
2202
  allowMultiple = false;
1984
2203
  rateLimit = null;
1985
2204
  quotaExceeded = false;
@@ -2022,20 +2241,28 @@ class PraxisFilesUpload {
2022
2241
  selectedOverlayRef;
2023
2242
  // Lista: colapso
2024
2243
  showAllResults = false;
2025
- constructor(settingsPanel, dragProx, defaultTexts, overlay, viewContainerRef, cdr, api, presign, errors, translate, configStorage) {
2244
+ constructor(settingsPanel, dragProx, defaultTexts, overlay, viewContainerRef, cdr, configStorage, api, presign, errors, translate) {
2026
2245
  this.settingsPanel = settingsPanel;
2027
2246
  this.dragProx = dragProx;
2028
2247
  this.defaultTexts = defaultTexts;
2029
2248
  this.overlay = overlay;
2030
2249
  this.viewContainerRef = viewContainerRef;
2031
2250
  this.cdr = cdr;
2251
+ this.configStorage = configStorage;
2032
2252
  this.api = api;
2033
2253
  this.presign = presign;
2034
2254
  this.errors = errors;
2035
2255
  this.translate = translate;
2036
- this.configStorage = configStorage;
2037
2256
  this.texts = defaultTexts;
2038
2257
  }
2258
+ componentKeys = inject(ComponentKeyService);
2259
+ route = (() => { try {
2260
+ return inject(ActivatedRoute);
2261
+ }
2262
+ catch {
2263
+ return undefined;
2264
+ } })();
2265
+ warnedMissingId = false;
2039
2266
  // Helpers de UI
2040
2267
  get showProgress() {
2041
2268
  return this.uploading;
@@ -2106,12 +2333,18 @@ class PraxisFilesUpload {
2106
2333
  }
2107
2334
  }
2108
2335
  ngOnInit() {
2109
- const stored = this.configStorage?.loadConfig(`files-upload-config:${this.componentId}`) ?? this.loadLocalConfig();
2110
- if (stored) {
2111
- this.config = stored;
2112
- }
2336
+ const key = this.storageKey();
2113
2337
  this.applyConfig(this.config ?? {});
2114
2338
  this.resolveTexts();
2339
+ if (key) {
2340
+ this.configStorage.loadConfig(key).pipe(take(1)).subscribe((stored) => {
2341
+ if (stored) {
2342
+ this.config = stored;
2343
+ this.applyConfig(this.config ?? {});
2344
+ this.resolveTexts();
2345
+ }
2346
+ });
2347
+ }
2115
2348
  // Nota: carregamento da configuração efetiva do servidor foi desabilitado aqui
2116
2349
  // para evitar dependência de HttpClient em testes. O fallback permanece opcional.
2117
2350
  }
@@ -2340,9 +2573,12 @@ class PraxisFilesUpload {
2340
2573
  return v && v !== k ? v : fallback;
2341
2574
  }
2342
2575
  openSettings() {
2576
+ if (!this.editModeEnabled)
2577
+ return;
2343
2578
  const configCopy = JSON.parse(JSON.stringify(this.config ?? {}));
2579
+ const key = this.storageKey();
2344
2580
  const ref = this.settingsPanel.open({
2345
- id: `files-upload.${this.componentId}`,
2581
+ id: `files-upload.${key || this.filesUploadId || 'default'}`,
2346
2582
  title: this.t('settingsTitle', 'Configuração de Upload de Arquivos'),
2347
2583
  content: {
2348
2584
  component: PraxisFilesUploadConfigEditor,
@@ -2351,11 +2587,11 @@ class PraxisFilesUpload {
2351
2587
  });
2352
2588
  ref.applied$.subscribe((cfg) => this.applyConfig(cfg));
2353
2589
  ref.saved$.subscribe((cfg) => {
2354
- if (this.configStorage) {
2355
- this.configStorage.saveConfig(`files-upload-config:${this.componentId}`, cfg);
2356
- }
2357
- else {
2358
- this.saveLocalConfig(cfg);
2590
+ if (key) {
2591
+ this.configStorage
2592
+ .saveConfig(key, cfg)
2593
+ .pipe(take(1))
2594
+ .subscribe({ error: () => { } });
2359
2595
  }
2360
2596
  this.applyConfig(cfg);
2361
2597
  });
@@ -2370,20 +2606,28 @@ class PraxisFilesUpload {
2370
2606
  const acc = cfg.ui?.accept ?? [];
2371
2607
  this.acceptString = acc.includes('*') ? '' : acc.join(',');
2372
2608
  }
2373
- loadLocalConfig() {
2374
- try {
2375
- const raw = localStorage.getItem(`files-upload-config:${this.componentId}`);
2376
- return raw ? JSON.parse(raw) : null;
2377
- }
2378
- catch {
2379
- return null;
2380
- }
2609
+ storageKey() {
2610
+ const id = this.componentKeyId();
2611
+ return id ? `files-upload-config:${id}` : null;
2381
2612
  }
2382
- saveLocalConfig(cfg) {
2383
- try {
2384
- localStorage.setItem(`files-upload-config:${this.componentId}`, JSON.stringify(cfg));
2385
- }
2386
- catch { }
2613
+ componentKeyId() {
2614
+ const key = this.componentKeys.buildComponentId({
2615
+ componentType: 'praxis-files-upload',
2616
+ componentId: this.filesUploadId,
2617
+ instanceKey: this.componentInstanceId,
2618
+ componentRef: this,
2619
+ route: this.route,
2620
+ requireComponentId: true,
2621
+ });
2622
+ if (!key)
2623
+ this.warnMissingId();
2624
+ return key;
2625
+ }
2626
+ warnMissingId() {
2627
+ if (this.warnedMissingId)
2628
+ return;
2629
+ this.warnedMissingId = true;
2630
+ console.warn('[PraxisFilesUpload] filesUploadId ou uploadId sao necessarios para persistencia de configuracao.');
2387
2631
  }
2388
2632
  onDragOver(evt) {
2389
2633
  evt.preventDefault();
@@ -2458,7 +2702,7 @@ class PraxisFilesUpload {
2458
2702
  return;
2459
2703
  }
2460
2704
  this.uploading = true;
2461
- this.uploadProgress = 0;
2705
+ this.uploadProgressValue = 0;
2462
2706
  this.rateLimit = null;
2463
2707
  this.uploadedFiles = [];
2464
2708
  this.currentFiles = files;
@@ -2479,6 +2723,13 @@ class PraxisFilesUpload {
2479
2723
  }
2480
2724
  const optionsJson = this.buildOptionsJson(metadataObj);
2481
2725
  const strategy = this.config?.strategy ?? 'direct';
2726
+ this.uploadStart.emit({
2727
+ files,
2728
+ mode: files.length > 1 && this.allowMultiple ? 'bulk' : 'single',
2729
+ strategy,
2730
+ uploadId: this.uploadId || this.filesUploadId,
2731
+ baseUrl: this.baseUrl,
2732
+ });
2482
2733
  if (files.length > 1 && this.allowMultiple) {
2483
2734
  const policy = this.conflictPolicy.value || 'RENAME';
2484
2735
  const bulkFiles = files.map((f) => ({
@@ -2639,8 +2890,10 @@ class PraxisFilesUpload {
2639
2890
  if (customMeta && typeof customMeta === 'object') {
2640
2891
  const mapped = {};
2641
2892
  for (const [k, v] of Object.entries(customMeta)) {
2642
- if (v !== undefined && v !== null)
2643
- mapped[k] = String(v);
2893
+ if (v === undefined || v === null)
2894
+ continue;
2895
+ const resolved = typeof v === 'string' ? this.resolveTemplateString(v) : v;
2896
+ mapped[k] = String(resolved);
2644
2897
  }
2645
2898
  if (Object.keys(mapped).length)
2646
2899
  options.customMetadata = mapped;
@@ -2654,7 +2907,13 @@ class PraxisFilesUpload {
2654
2907
  }
2655
2908
  handleProgress(event) {
2656
2909
  if (event.type === HttpEventType.UploadProgress && event.total) {
2657
- this.uploadProgress = Math.round((event.loaded / event.total) * 100);
2910
+ const progress = Math.round((event.loaded / event.total) * 100);
2911
+ this.uploadProgressValue = progress;
2912
+ this.uploadProgress.emit({
2913
+ progress,
2914
+ loaded: event.loaded,
2915
+ total: event.total,
2916
+ });
2658
2917
  }
2659
2918
  }
2660
2919
  handleError(err) {
@@ -2681,15 +2940,17 @@ class PraxisFilesUpload {
2681
2940
  this.quotaExceeded = true;
2682
2941
  }
2683
2942
  this.error.emit(err.error);
2943
+ this.uploadError.emit(err.error);
2684
2944
  }
2685
2945
  else {
2686
2946
  this.errorMessage = this.t('genericUploadError', 'Erro no envio de arquivo.');
2687
2947
  this.error.emit(err);
2948
+ this.uploadError.emit(err);
2688
2949
  }
2689
2950
  }
2690
2951
  finishUpload(success, meta, results) {
2691
2952
  this.uploading = false;
2692
- this.uploadProgress = 100;
2953
+ this.uploadProgressValue = 100;
2693
2954
  if (success) {
2694
2955
  if (meta) {
2695
2956
  this.uploadedFiles.push({ fileName: meta.fileName, success: true });
@@ -2843,6 +3104,7 @@ class PraxisFilesUpload {
2843
3104
  this.t('maxBulkSizeError', 'Tamanho total dos arquivos excedido.');
2844
3105
  }
2845
3106
  this.error.emit(errors);
3107
+ this.uploadError.emit(errors);
2846
3108
  return false;
2847
3109
  }
2848
3110
  return true;
@@ -2858,8 +3120,25 @@ class PraxisFilesUpload {
2858
3120
  const maxCount = this.config?.limits?.maxFilesPerBulk ?? (this.allowMultiple ? 99 : 1);
2859
3121
  return `Tipos: ${acc} • Máx. por arquivo: ${maxFile} • Qtde: ${maxCount}`;
2860
3122
  }
2861
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PraxisFilesUpload, deps: [{ token: i1$2.SettingsPanelService }, { token: DragProximityService }, { token: FILES_UPLOAD_TEXTS }, { token: i3.Overlay }, { token: i0.ViewContainerRef }, { token: i0.ChangeDetectorRef }, { token: FilesApiClient, optional: true }, { token: PresignedUploaderService, optional: true }, { token: ErrorMapperService, optional: true }, { token: TRANSLATE_LIKE, optional: true }, { token: CONFIG_STORAGE, optional: true }], target: i0.ɵɵFactoryTarget.Component });
2862
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.4", type: PraxisFilesUpload, isStandalone: true, selector: "praxis-files-upload", inputs: { config: "config", componentId: "componentId", baseUrl: "baseUrl", displayMode: "displayMode" }, outputs: { uploadSuccess: "uploadSuccess", bulkComplete: "bulkComplete", error: "error", rateLimited: "rateLimited", retry: "retry", download: "download", copyLink: "copyLink", detailsOpened: "detailsOpened", detailsClosed: "detailsClosed", pendingFilesChange: "pendingFilesChange", proximityChange: "proximityChange" }, viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }, { propertyName: "hostRef", first: true, predicate: ["host"], descendants: true, static: true }, { propertyName: "overlayTmpl", first: true, predicate: ["proximityOverlayTmpl"], descendants: true }, { propertyName: "selectedOverlayTmpl", first: true, predicate: ["selectedOverlayTmpl"], descendants: true }], ngImport: i0, template: `
3123
+ resolveTemplateString(value) {
3124
+ if (!this.context || !value.includes('${'))
3125
+ return value;
3126
+ return value.replace(/\$\{([^}]+)\}/g, (_match, path) => {
3127
+ const resolved = this.resolveContextPath(this.context, String(path).trim());
3128
+ return resolved === undefined || resolved === null ? '' : String(resolved);
3129
+ });
3130
+ }
3131
+ resolveContextPath(context, path) {
3132
+ if (!path)
3133
+ return undefined;
3134
+ return path.split('.').reduce((acc, key) => {
3135
+ if (!acc || typeof acc !== 'object')
3136
+ return undefined;
3137
+ return acc[key];
3138
+ }, context);
3139
+ }
3140
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisFilesUpload, deps: [{ token: i1$2.SettingsPanelService }, { token: DragProximityService }, { token: FILES_UPLOAD_TEXTS }, { token: i3.Overlay }, { token: i0.ViewContainerRef }, { token: i0.ChangeDetectorRef }, { token: ASYNC_CONFIG_STORAGE }, { token: FilesApiClient, optional: true }, { token: PresignedUploaderService, optional: true }, { token: ErrorMapperService, optional: true }, { token: TRANSLATE_LIKE, optional: true }], target: i0.ɵɵFactoryTarget.Component });
3141
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: PraxisFilesUpload, isStandalone: true, selector: "praxis-files-upload", inputs: { config: "config", filesUploadId: "filesUploadId", uploadId: "uploadId", componentInstanceId: "componentInstanceId", baseUrl: "baseUrl", displayMode: "displayMode", context: "context", editModeEnabled: "editModeEnabled" }, outputs: { uploadSuccess: "uploadSuccess", bulkComplete: "bulkComplete", error: "error", rateLimited: "rateLimited", uploadStart: "uploadStart", uploadProgress: "uploadProgress", uploadError: "uploadError", retry: "retry", download: "download", copyLink: "copyLink", detailsOpened: "detailsOpened", detailsClosed: "detailsClosed", pendingFilesChange: "pendingFilesChange", proximityChange: "proximityChange" }, viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }, { propertyName: "hostRef", first: true, predicate: ["host"], descendants: true, static: true }, { propertyName: "overlayTmpl", first: true, predicate: ["proximityOverlayTmpl"], descendants: true }, { propertyName: "selectedOverlayTmpl", first: true, predicate: ["selectedOverlayTmpl"], descendants: true }], ngImport: i0, template: `
2863
3142
  <div class="praxis-files-upload" [class.dense]="config?.ui?.dense" #host>
2864
3143
  <!-- Proximity overlay inline (fallback quando expandMode === 'inline') -->
2865
3144
  <div
@@ -2970,6 +3249,7 @@ class PraxisFilesUpload {
2970
3249
  class="settings-btn"
2971
3250
  (click)="openSettings()"
2972
3251
  [attr.aria-label]="texts.settingsAriaLabel"
3252
+ *ngIf="editModeEnabled"
2973
3253
  >
2974
3254
  <mat-icon [praxisIcon]="'settings'"></mat-icon>
2975
3255
  </button>
@@ -3112,10 +3392,10 @@ class PraxisFilesUpload {
3112
3392
  <div class="progress" *ngIf="showProgress">
3113
3393
  <mat-progress-bar
3114
3394
  mode="determinate"
3115
- [value]="uploadProgress"
3395
+ [value]="uploadProgressValue"
3116
3396
  [attr.aria-label]="texts.progressAriaLabel"
3117
3397
  ></mat-progress-bar>
3118
- <span class="sr-only">{{ uploadProgress }}%</span>
3398
+ <span class="sr-only">{{ uploadProgressValue }}%</span>
3119
3399
  </div>
3120
3400
 
3121
3401
  <ul class="file-feedback" *ngIf="hasUploadedFiles">
@@ -3273,9 +3553,9 @@ class PraxisFilesUpload {
3273
3553
 
3274
3554
  <ng-content></ng-content>
3275
3555
  </div>
3276
- `, isInline: true, styles: ["@charset \"UTF-8\";.praxis-files-upload{position:relative}.praxis-files-upload .settings-btn{position:absolute;top:.5rem;right:.5rem}.praxis-files-upload .rate-limit-banner,.praxis-files-upload .quota-banner,.praxis-files-upload .error{margin:.5rem 0;padding:.5rem 1rem;border-radius:var(--mat-sys-shape-corner-small, 4px)}.praxis-files-upload .rate-limit-banner{background:var(--mat-sys-color-error-container);color:var(--mat-sys-color-on-error-container)}.praxis-files-upload .quota-banner{background:var(--mat-sys-color-tertiary-container);color:var(--mat-sys-color-on-tertiary-container)}.praxis-files-upload .dropzone{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:2rem;border:2px dashed var(--mat-sys-color-outline);border-radius:var(--mat-sys-shape-corner-medium, 4px);background:var(--mat-sys-color-surface-container-low);color:var(--mat-sys-color-on-surface);text-align:center;cursor:pointer;transition:background-color .2s;width:100%;min-height:160px;margin:.5rem 0;gap:.5rem;position:relative}.praxis-files-upload .dropzone:focus,.praxis-files-upload .dropzone:hover{outline:none;background:var(--mat-sys-color-surface-container-high);border-color:var(--mat-sys-color-primary)}.praxis-files-upload .dropzone.dragover{background:var(--mat-sys-color-surface-container-high);border-color:var(--mat-sys-color-primary)}.praxis-files-upload .dropzone.disabled{opacity:.6;cursor:not-allowed;pointer-events:none}.praxis-files-upload .dropzone p{margin:0 0 .5rem}.praxis-files-upload .dropzone .dz-icon{font-size:40px;color:var(--mat-sys-color-primary);margin-bottom:.25rem}.praxis-files-upload .dropzone .dz-title{font-weight:600}.praxis-files-upload .dropzone .dz-hint{margin:0;opacity:.8;font-size:.9rem}.praxis-files-upload .dropzone .field-actions{position:absolute;top:.25rem;right:.25rem;display:flex;gap:.25rem;pointer-events:auto}.praxis-files-upload .dropzone .field-actions button[mat-icon-button]{width:32px;height:32px}.praxis-files-upload .dropzone .field-actions mat-icon{font-size:20px}.praxis-files-upload .progress{margin-top:1rem}.praxis-files-upload .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);border:0}.praxis-files-upload .bulk-results{margin-top:1rem}.praxis-files-upload .bulk-results .bulk-summary{display:flex;gap:1rem;align-items:center;margin-bottom:.5rem}.praxis-files-upload .bulk-results .bulk-summary .stat{display:flex;align-items:center;gap:.35rem;padding:.25rem .5rem;border-radius:6px;background:var(--mat-sys-color-surface-container-low)}.praxis-files-upload .bulk-results .bulk-summary .stat.success{color:var(--mat-sys-color-primary)}.praxis-files-upload .bulk-results .bulk-summary .stat.failed{color:var(--mat-sys-color-error)}.praxis-files-upload .bulk-results .bulk-summary .stat .label{opacity:.9}.praxis-files-upload .bulk-results .bulk-summary .stat .value{font-weight:600}.praxis-files-upload .bulk-results .results-list{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:.5rem}.praxis-files-upload .bulk-results .result-item{display:flex;gap:.75rem;padding:.5rem .75rem;border:1px solid var(--mat-sys-color-outline-variant);border-radius:8px;background:var(--mat-sys-color-surface-container-lowest)}.praxis-files-upload .bulk-results .result-item.ok{border-color:var(--mat-sys-color-primary)}.praxis-files-upload .bulk-results .result-item.err{border-color:var(--mat-sys-color-error)}.praxis-files-upload .bulk-results .result-item .status-icon{align-self:flex-start;color:currentColor}.praxis-files-upload .bulk-results .result-item .main{flex:1;min-width:0}.praxis-files-upload .bulk-results .result-item .title{display:flex;align-items:center;gap:.5rem}.praxis-files-upload .bulk-results .result-item .name{font-weight:600}.praxis-files-upload .bulk-results .result-item .badge{font-size:.75rem;padding:.1rem .4rem;border-radius:999px;background:color-mix(in oklab,var(--mat-sys-color-primary) 15%,transparent);color:var(--mat-sys-color-primary)}.praxis-files-upload .bulk-results .result-item .badge.err{background:color-mix(in oklab,var(--mat-sys-color-error) 15%,transparent);color:var(--mat-sys-color-error)}.praxis-files-upload .bulk-results .result-item .meta,.praxis-files-upload .bulk-results .result-item .error{display:flex;flex-wrap:wrap;gap:.5rem 1rem;margin-top:.25rem}.praxis-files-upload .bulk-results .result-item .error .code{font-weight:600}.praxis-files-upload .bulk-results .result-item .extra{margin-top:.25rem}.praxis-files-upload .bulk-results .result-item .item-actions{display:flex;align-items:center;gap:.25rem}.praxis-files-upload .bulk-results .list-footer{margin-top:.5rem;display:flex;justify-content:center}.praxis-files-upload .proximity-overlay{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;border:2px dashed var(--mat-sys-color-outline);border-radius:var(--mat-sys-shape-corner-medium, 4px);background:color-mix(in oklab,var(--mat-sys-color-surface-container-high) 80%,transparent);color:var(--mat-sys-color-on-surface);text-align:center;z-index:2;pointer-events:none}.praxis-files-upload .proximity-overlay .dz-icon{font-size:40px;color:var(--mat-sys-color-primary)}.praxis-files-upload .proximity-overlay .dz-title{font-weight:600}.praxis-files-upload .proximity-overlay .dz-hint{opacity:.85}.praxis-files-upload .selected-overlay{background:var(--mat-sys-color-surface);color:var(--mat-sys-color-on-surface);border:1px solid var(--mat-sys-color-outline-variant);border-radius:8px;box-shadow:var(--mat-sys-level2, 0 2px 6px rgba(0, 0, 0, .15));max-height:260px;overflow:auto;padding:.5rem}.praxis-files-upload .selected-overlay .sel-header{position:sticky;top:0;z-index:1;background:var(--mat-sys-color-surface);display:flex;align-items:center;gap:.5rem;padding-bottom:.25rem;margin-bottom:.25rem}.praxis-files-upload .selected-overlay .sel-header .title{font-weight:600}.praxis-files-upload .selected-overlay .sel-header .spacer{flex:1}.praxis-files-upload .selected-overlay .sel-list{list-style:none;margin:0;padding:0}.praxis-files-upload .selected-overlay .sel-list .sel-item{display:flex;align-items:center;gap:.75rem;padding:.5rem .75rem;border-bottom:1px solid var(--mat-sys-color-outline-variant, #ccc);transition:background-color .12s ease}.praxis-files-upload .selected-overlay .sel-list .sel-item .file-icon{opacity:.9;color:var(--mat-sys-color-primary, #1976d2)}.praxis-files-upload .selected-overlay .sel-list .sel-item .info{flex:1;min-width:0}.praxis-files-upload .selected-overlay .sel-list .sel-item .info .name{font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.praxis-files-upload .selected-overlay .sel-list .sel-item .info .meta{font-size:.8rem;opacity:.7}.praxis-files-upload .selected-overlay .sel-list .sel-item .remove-btn{color:var(--mat-sys-color-error, #b00020)}.praxis-files-upload .selected-overlay .sel-list .sel-item .more-btn{margin-left:.25rem}.praxis-files-upload .selected-overlay .sel-list .sel-item:hover{background:color-mix(in oklab,#000 8%,transparent)}:host ::ng-deep .praxis-files-upload-overlay-panel{pointer-events:none}:host ::ng-deep .praxis-files-selected-overlay-panel{pointer-events:auto;z-index:3}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i7.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i7.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i9.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: i9.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i10.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "ngmodule", type: MatProgressBarModule }, { kind: "component", type: i11.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i3$1.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i3$1.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i3$1.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i13.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "pipe", type: i7.JsonPipe, name: "json" }, { kind: "pipe", type: i7.DatePipe, name: "date" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3556
+ `, isInline: true, styles: ["@charset \"UTF-8\";.praxis-files-upload{position:relative}.praxis-files-upload .settings-btn{position:absolute;top:.5rem;right:.5rem}.praxis-files-upload .rate-limit-banner,.praxis-files-upload .quota-banner,.praxis-files-upload .error{margin:.5rem 0;padding:.5rem 1rem;border-radius:var(--md-sys-shape-corner-small, 4px)}.praxis-files-upload .rate-limit-banner{background:var(--md-sys-color-error-container);color:var(--md-sys-color-on-error-container)}.praxis-files-upload .quota-banner{background:var(--md-sys-color-tertiary-container);color:var(--md-sys-color-on-tertiary-container)}.praxis-files-upload .dropzone{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:2rem;border:2px dashed var(--md-sys-color-outline);border-radius:var(--md-sys-shape-corner-medium, 4px);background:var(--md-sys-color-surface-container-low);color:var(--md-sys-color-on-surface);text-align:center;cursor:pointer;transition:background-color .2s;width:100%;min-height:160px;margin:.5rem 0;gap:.5rem;position:relative}.praxis-files-upload .dropzone:focus,.praxis-files-upload .dropzone:hover{outline:none;background:var(--md-sys-color-surface-container-high);border-color:var(--md-sys-color-primary)}.praxis-files-upload .dropzone.dragover{background:var(--md-sys-color-surface-container-high);border-color:var(--md-sys-color-primary)}.praxis-files-upload .dropzone.disabled{opacity:.6;cursor:not-allowed;pointer-events:none}.praxis-files-upload .dropzone p{margin:0 0 .5rem}.praxis-files-upload .dropzone .dz-icon{font-size:40px;color:var(--md-sys-color-primary);margin-bottom:.25rem}.praxis-files-upload .dropzone .dz-title{font-weight:600}.praxis-files-upload .dropzone .dz-hint{margin:0;opacity:.8;font-size:.9rem}.praxis-files-upload .dropzone .field-actions{position:absolute;top:.25rem;right:.25rem;display:flex;gap:.25rem;pointer-events:auto}.praxis-files-upload .dropzone .field-actions button[mat-icon-button]{width:32px;height:32px}.praxis-files-upload .dropzone .field-actions mat-icon{font-size:20px}.praxis-files-upload .progress{margin-top:1rem}.praxis-files-upload .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);border:0}.praxis-files-upload .bulk-results{margin-top:1rem}.praxis-files-upload .bulk-results .bulk-summary{display:flex;gap:1rem;align-items:center;margin-bottom:.5rem}.praxis-files-upload .bulk-results .bulk-summary .stat{display:flex;align-items:center;gap:.35rem;padding:.25rem .5rem;border-radius:6px;background:var(--md-sys-color-surface-container-low)}.praxis-files-upload .bulk-results .bulk-summary .stat.success{color:var(--md-sys-color-primary)}.praxis-files-upload .bulk-results .bulk-summary .stat.failed{color:var(--md-sys-color-error)}.praxis-files-upload .bulk-results .bulk-summary .stat .label{opacity:.9}.praxis-files-upload .bulk-results .bulk-summary .stat .value{font-weight:600}.praxis-files-upload .bulk-results .results-list{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:.5rem}.praxis-files-upload .bulk-results .result-item{display:flex;gap:.75rem;padding:.5rem .75rem;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface-container-lowest)}.praxis-files-upload .bulk-results .result-item.ok{border-color:var(--md-sys-color-primary)}.praxis-files-upload .bulk-results .result-item.err{border-color:var(--md-sys-color-error)}.praxis-files-upload .bulk-results .result-item .status-icon{align-self:flex-start;color:currentColor}.praxis-files-upload .bulk-results .result-item .main{flex:1;min-width:0}.praxis-files-upload .bulk-results .result-item .title{display:flex;align-items:center;gap:.5rem}.praxis-files-upload .bulk-results .result-item .name{font-weight:600}.praxis-files-upload .bulk-results .result-item .badge{font-size:.75rem;padding:.1rem .4rem;border-radius:999px;background:var(--md-sys-color-primary-container);color:var(--md-sys-color-on-primary-container)}.praxis-files-upload .bulk-results .result-item .badge.err{background:var(--md-sys-color-error-container);color:var(--md-sys-color-on-error-container)}.praxis-files-upload .bulk-results .result-item .meta,.praxis-files-upload .bulk-results .result-item .error{display:flex;flex-wrap:wrap;gap:.5rem 1rem;margin-top:.25rem}.praxis-files-upload .bulk-results .result-item .error .code{font-weight:600}.praxis-files-upload .bulk-results .result-item .extra{margin-top:.25rem}.praxis-files-upload .bulk-results .result-item .item-actions{display:flex;align-items:center;gap:.25rem}.praxis-files-upload .bulk-results .list-footer{margin-top:.5rem;display:flex;justify-content:center}.praxis-files-upload .proximity-overlay{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;border:2px dashed var(--md-sys-color-outline);border-radius:var(--md-sys-shape-corner-medium, 4px);background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface);text-align:center;z-index:2;pointer-events:none}.praxis-files-upload .proximity-overlay .dz-icon{font-size:40px;color:var(--md-sys-color-primary)}.praxis-files-upload .proximity-overlay .dz-title{font-weight:600}.praxis-files-upload .proximity-overlay .dz-hint{opacity:.85}.praxis-files-upload .selected-overlay{background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface);border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;box-shadow:var(--md-sys-elevation-level2, 0 2px 6px rgba(0, 0, 0, .15));max-height:260px;overflow:auto;padding:.5rem}.praxis-files-upload .selected-overlay .sel-header{position:sticky;top:0;z-index:1;background:var(--md-sys-color-surface);display:flex;align-items:center;gap:.5rem;padding-bottom:.25rem;margin-bottom:.25rem}.praxis-files-upload .selected-overlay .sel-header .title{font-weight:600}.praxis-files-upload .selected-overlay .sel-header .spacer{flex:1}.praxis-files-upload .selected-overlay .sel-list{list-style:none;margin:0;padding:0}.praxis-files-upload .selected-overlay .sel-list .sel-item{display:flex;align-items:center;gap:.75rem;padding:.5rem .75rem;border-bottom:1px solid var(--md-sys-color-outline-variant, #ccc);transition:background-color .12s ease}.praxis-files-upload .selected-overlay .sel-list .sel-item .file-icon{opacity:.9;color:var(--md-sys-color-primary, #1976d2)}.praxis-files-upload .selected-overlay .sel-list .sel-item .info{flex:1;min-width:0}.praxis-files-upload .selected-overlay .sel-list .sel-item .info .name{font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.praxis-files-upload .selected-overlay .sel-list .sel-item .info .meta{font-size:.8rem;opacity:.7}.praxis-files-upload .selected-overlay .sel-list .sel-item .remove-btn{color:var(--md-sys-color-error, #b00020)}.praxis-files-upload .selected-overlay .sel-list .sel-item .more-btn{margin-left:.25rem}.praxis-files-upload .selected-overlay .sel-list .sel-item:hover{background:var(--md-sys-color-surface-container-low)}:host ::ng-deep .praxis-files-upload-overlay-panel{pointer-events:none}:host ::ng-deep .praxis-files-selected-overlay-panel{pointer-events:auto;z-index:3}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i7.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i7.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i9.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: i9.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i10.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "ngmodule", type: MatProgressBarModule }, { kind: "component", type: i11$1.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i3$1.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i3$1.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i3$1.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i11.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "pipe", type: i7.JsonPipe, name: "json" }, { kind: "pipe", type: i7.DatePipe, name: "date" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3277
3557
  }
3278
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PraxisFilesUpload, decorators: [{
3558
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisFilesUpload, decorators: [{
3279
3559
  type: Component,
3280
3560
  args: [{ selector: 'praxis-files-upload', standalone: true, imports: [
3281
3561
  CommonModule,
@@ -3397,6 +3677,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
3397
3677
  class="settings-btn"
3398
3678
  (click)="openSettings()"
3399
3679
  [attr.aria-label]="texts.settingsAriaLabel"
3680
+ *ngIf="editModeEnabled"
3400
3681
  >
3401
3682
  <mat-icon [praxisIcon]="'settings'"></mat-icon>
3402
3683
  </button>
@@ -3539,10 +3820,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
3539
3820
  <div class="progress" *ngIf="showProgress">
3540
3821
  <mat-progress-bar
3541
3822
  mode="determinate"
3542
- [value]="uploadProgress"
3823
+ [value]="uploadProgressValue"
3543
3824
  [attr.aria-label]="texts.progressAriaLabel"
3544
3825
  ></mat-progress-bar>
3545
- <span class="sr-only">{{ uploadProgress }}%</span>
3826
+ <span class="sr-only">{{ uploadProgressValue }}%</span>
3546
3827
  </div>
3547
3828
 
3548
3829
  <ul class="file-feedback" *ngIf="hasUploadedFiles">
@@ -3700,11 +3981,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
3700
3981
 
3701
3982
  <ng-content></ng-content>
3702
3983
  </div>
3703
- `, styles: ["@charset \"UTF-8\";.praxis-files-upload{position:relative}.praxis-files-upload .settings-btn{position:absolute;top:.5rem;right:.5rem}.praxis-files-upload .rate-limit-banner,.praxis-files-upload .quota-banner,.praxis-files-upload .error{margin:.5rem 0;padding:.5rem 1rem;border-radius:var(--mat-sys-shape-corner-small, 4px)}.praxis-files-upload .rate-limit-banner{background:var(--mat-sys-color-error-container);color:var(--mat-sys-color-on-error-container)}.praxis-files-upload .quota-banner{background:var(--mat-sys-color-tertiary-container);color:var(--mat-sys-color-on-tertiary-container)}.praxis-files-upload .dropzone{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:2rem;border:2px dashed var(--mat-sys-color-outline);border-radius:var(--mat-sys-shape-corner-medium, 4px);background:var(--mat-sys-color-surface-container-low);color:var(--mat-sys-color-on-surface);text-align:center;cursor:pointer;transition:background-color .2s;width:100%;min-height:160px;margin:.5rem 0;gap:.5rem;position:relative}.praxis-files-upload .dropzone:focus,.praxis-files-upload .dropzone:hover{outline:none;background:var(--mat-sys-color-surface-container-high);border-color:var(--mat-sys-color-primary)}.praxis-files-upload .dropzone.dragover{background:var(--mat-sys-color-surface-container-high);border-color:var(--mat-sys-color-primary)}.praxis-files-upload .dropzone.disabled{opacity:.6;cursor:not-allowed;pointer-events:none}.praxis-files-upload .dropzone p{margin:0 0 .5rem}.praxis-files-upload .dropzone .dz-icon{font-size:40px;color:var(--mat-sys-color-primary);margin-bottom:.25rem}.praxis-files-upload .dropzone .dz-title{font-weight:600}.praxis-files-upload .dropzone .dz-hint{margin:0;opacity:.8;font-size:.9rem}.praxis-files-upload .dropzone .field-actions{position:absolute;top:.25rem;right:.25rem;display:flex;gap:.25rem;pointer-events:auto}.praxis-files-upload .dropzone .field-actions button[mat-icon-button]{width:32px;height:32px}.praxis-files-upload .dropzone .field-actions mat-icon{font-size:20px}.praxis-files-upload .progress{margin-top:1rem}.praxis-files-upload .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);border:0}.praxis-files-upload .bulk-results{margin-top:1rem}.praxis-files-upload .bulk-results .bulk-summary{display:flex;gap:1rem;align-items:center;margin-bottom:.5rem}.praxis-files-upload .bulk-results .bulk-summary .stat{display:flex;align-items:center;gap:.35rem;padding:.25rem .5rem;border-radius:6px;background:var(--mat-sys-color-surface-container-low)}.praxis-files-upload .bulk-results .bulk-summary .stat.success{color:var(--mat-sys-color-primary)}.praxis-files-upload .bulk-results .bulk-summary .stat.failed{color:var(--mat-sys-color-error)}.praxis-files-upload .bulk-results .bulk-summary .stat .label{opacity:.9}.praxis-files-upload .bulk-results .bulk-summary .stat .value{font-weight:600}.praxis-files-upload .bulk-results .results-list{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:.5rem}.praxis-files-upload .bulk-results .result-item{display:flex;gap:.75rem;padding:.5rem .75rem;border:1px solid var(--mat-sys-color-outline-variant);border-radius:8px;background:var(--mat-sys-color-surface-container-lowest)}.praxis-files-upload .bulk-results .result-item.ok{border-color:var(--mat-sys-color-primary)}.praxis-files-upload .bulk-results .result-item.err{border-color:var(--mat-sys-color-error)}.praxis-files-upload .bulk-results .result-item .status-icon{align-self:flex-start;color:currentColor}.praxis-files-upload .bulk-results .result-item .main{flex:1;min-width:0}.praxis-files-upload .bulk-results .result-item .title{display:flex;align-items:center;gap:.5rem}.praxis-files-upload .bulk-results .result-item .name{font-weight:600}.praxis-files-upload .bulk-results .result-item .badge{font-size:.75rem;padding:.1rem .4rem;border-radius:999px;background:color-mix(in oklab,var(--mat-sys-color-primary) 15%,transparent);color:var(--mat-sys-color-primary)}.praxis-files-upload .bulk-results .result-item .badge.err{background:color-mix(in oklab,var(--mat-sys-color-error) 15%,transparent);color:var(--mat-sys-color-error)}.praxis-files-upload .bulk-results .result-item .meta,.praxis-files-upload .bulk-results .result-item .error{display:flex;flex-wrap:wrap;gap:.5rem 1rem;margin-top:.25rem}.praxis-files-upload .bulk-results .result-item .error .code{font-weight:600}.praxis-files-upload .bulk-results .result-item .extra{margin-top:.25rem}.praxis-files-upload .bulk-results .result-item .item-actions{display:flex;align-items:center;gap:.25rem}.praxis-files-upload .bulk-results .list-footer{margin-top:.5rem;display:flex;justify-content:center}.praxis-files-upload .proximity-overlay{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;border:2px dashed var(--mat-sys-color-outline);border-radius:var(--mat-sys-shape-corner-medium, 4px);background:color-mix(in oklab,var(--mat-sys-color-surface-container-high) 80%,transparent);color:var(--mat-sys-color-on-surface);text-align:center;z-index:2;pointer-events:none}.praxis-files-upload .proximity-overlay .dz-icon{font-size:40px;color:var(--mat-sys-color-primary)}.praxis-files-upload .proximity-overlay .dz-title{font-weight:600}.praxis-files-upload .proximity-overlay .dz-hint{opacity:.85}.praxis-files-upload .selected-overlay{background:var(--mat-sys-color-surface);color:var(--mat-sys-color-on-surface);border:1px solid var(--mat-sys-color-outline-variant);border-radius:8px;box-shadow:var(--mat-sys-level2, 0 2px 6px rgba(0, 0, 0, .15));max-height:260px;overflow:auto;padding:.5rem}.praxis-files-upload .selected-overlay .sel-header{position:sticky;top:0;z-index:1;background:var(--mat-sys-color-surface);display:flex;align-items:center;gap:.5rem;padding-bottom:.25rem;margin-bottom:.25rem}.praxis-files-upload .selected-overlay .sel-header .title{font-weight:600}.praxis-files-upload .selected-overlay .sel-header .spacer{flex:1}.praxis-files-upload .selected-overlay .sel-list{list-style:none;margin:0;padding:0}.praxis-files-upload .selected-overlay .sel-list .sel-item{display:flex;align-items:center;gap:.75rem;padding:.5rem .75rem;border-bottom:1px solid var(--mat-sys-color-outline-variant, #ccc);transition:background-color .12s ease}.praxis-files-upload .selected-overlay .sel-list .sel-item .file-icon{opacity:.9;color:var(--mat-sys-color-primary, #1976d2)}.praxis-files-upload .selected-overlay .sel-list .sel-item .info{flex:1;min-width:0}.praxis-files-upload .selected-overlay .sel-list .sel-item .info .name{font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.praxis-files-upload .selected-overlay .sel-list .sel-item .info .meta{font-size:.8rem;opacity:.7}.praxis-files-upload .selected-overlay .sel-list .sel-item .remove-btn{color:var(--mat-sys-color-error, #b00020)}.praxis-files-upload .selected-overlay .sel-list .sel-item .more-btn{margin-left:.25rem}.praxis-files-upload .selected-overlay .sel-list .sel-item:hover{background:color-mix(in oklab,#000 8%,transparent)}:host ::ng-deep .praxis-files-upload-overlay-panel{pointer-events:none}:host ::ng-deep .praxis-files-selected-overlay-panel{pointer-events:auto;z-index:3}\n"] }]
3984
+ `, styles: ["@charset \"UTF-8\";.praxis-files-upload{position:relative}.praxis-files-upload .settings-btn{position:absolute;top:.5rem;right:.5rem}.praxis-files-upload .rate-limit-banner,.praxis-files-upload .quota-banner,.praxis-files-upload .error{margin:.5rem 0;padding:.5rem 1rem;border-radius:var(--md-sys-shape-corner-small, 4px)}.praxis-files-upload .rate-limit-banner{background:var(--md-sys-color-error-container);color:var(--md-sys-color-on-error-container)}.praxis-files-upload .quota-banner{background:var(--md-sys-color-tertiary-container);color:var(--md-sys-color-on-tertiary-container)}.praxis-files-upload .dropzone{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:2rem;border:2px dashed var(--md-sys-color-outline);border-radius:var(--md-sys-shape-corner-medium, 4px);background:var(--md-sys-color-surface-container-low);color:var(--md-sys-color-on-surface);text-align:center;cursor:pointer;transition:background-color .2s;width:100%;min-height:160px;margin:.5rem 0;gap:.5rem;position:relative}.praxis-files-upload .dropzone:focus,.praxis-files-upload .dropzone:hover{outline:none;background:var(--md-sys-color-surface-container-high);border-color:var(--md-sys-color-primary)}.praxis-files-upload .dropzone.dragover{background:var(--md-sys-color-surface-container-high);border-color:var(--md-sys-color-primary)}.praxis-files-upload .dropzone.disabled{opacity:.6;cursor:not-allowed;pointer-events:none}.praxis-files-upload .dropzone p{margin:0 0 .5rem}.praxis-files-upload .dropzone .dz-icon{font-size:40px;color:var(--md-sys-color-primary);margin-bottom:.25rem}.praxis-files-upload .dropzone .dz-title{font-weight:600}.praxis-files-upload .dropzone .dz-hint{margin:0;opacity:.8;font-size:.9rem}.praxis-files-upload .dropzone .field-actions{position:absolute;top:.25rem;right:.25rem;display:flex;gap:.25rem;pointer-events:auto}.praxis-files-upload .dropzone .field-actions button[mat-icon-button]{width:32px;height:32px}.praxis-files-upload .dropzone .field-actions mat-icon{font-size:20px}.praxis-files-upload .progress{margin-top:1rem}.praxis-files-upload .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);border:0}.praxis-files-upload .bulk-results{margin-top:1rem}.praxis-files-upload .bulk-results .bulk-summary{display:flex;gap:1rem;align-items:center;margin-bottom:.5rem}.praxis-files-upload .bulk-results .bulk-summary .stat{display:flex;align-items:center;gap:.35rem;padding:.25rem .5rem;border-radius:6px;background:var(--md-sys-color-surface-container-low)}.praxis-files-upload .bulk-results .bulk-summary .stat.success{color:var(--md-sys-color-primary)}.praxis-files-upload .bulk-results .bulk-summary .stat.failed{color:var(--md-sys-color-error)}.praxis-files-upload .bulk-results .bulk-summary .stat .label{opacity:.9}.praxis-files-upload .bulk-results .bulk-summary .stat .value{font-weight:600}.praxis-files-upload .bulk-results .results-list{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:.5rem}.praxis-files-upload .bulk-results .result-item{display:flex;gap:.75rem;padding:.5rem .75rem;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface-container-lowest)}.praxis-files-upload .bulk-results .result-item.ok{border-color:var(--md-sys-color-primary)}.praxis-files-upload .bulk-results .result-item.err{border-color:var(--md-sys-color-error)}.praxis-files-upload .bulk-results .result-item .status-icon{align-self:flex-start;color:currentColor}.praxis-files-upload .bulk-results .result-item .main{flex:1;min-width:0}.praxis-files-upload .bulk-results .result-item .title{display:flex;align-items:center;gap:.5rem}.praxis-files-upload .bulk-results .result-item .name{font-weight:600}.praxis-files-upload .bulk-results .result-item .badge{font-size:.75rem;padding:.1rem .4rem;border-radius:999px;background:var(--md-sys-color-primary-container);color:var(--md-sys-color-on-primary-container)}.praxis-files-upload .bulk-results .result-item .badge.err{background:var(--md-sys-color-error-container);color:var(--md-sys-color-on-error-container)}.praxis-files-upload .bulk-results .result-item .meta,.praxis-files-upload .bulk-results .result-item .error{display:flex;flex-wrap:wrap;gap:.5rem 1rem;margin-top:.25rem}.praxis-files-upload .bulk-results .result-item .error .code{font-weight:600}.praxis-files-upload .bulk-results .result-item .extra{margin-top:.25rem}.praxis-files-upload .bulk-results .result-item .item-actions{display:flex;align-items:center;gap:.25rem}.praxis-files-upload .bulk-results .list-footer{margin-top:.5rem;display:flex;justify-content:center}.praxis-files-upload .proximity-overlay{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;border:2px dashed var(--md-sys-color-outline);border-radius:var(--md-sys-shape-corner-medium, 4px);background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface);text-align:center;z-index:2;pointer-events:none}.praxis-files-upload .proximity-overlay .dz-icon{font-size:40px;color:var(--md-sys-color-primary)}.praxis-files-upload .proximity-overlay .dz-title{font-weight:600}.praxis-files-upload .proximity-overlay .dz-hint{opacity:.85}.praxis-files-upload .selected-overlay{background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface);border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;box-shadow:var(--md-sys-elevation-level2, 0 2px 6px rgba(0, 0, 0, .15));max-height:260px;overflow:auto;padding:.5rem}.praxis-files-upload .selected-overlay .sel-header{position:sticky;top:0;z-index:1;background:var(--md-sys-color-surface);display:flex;align-items:center;gap:.5rem;padding-bottom:.25rem;margin-bottom:.25rem}.praxis-files-upload .selected-overlay .sel-header .title{font-weight:600}.praxis-files-upload .selected-overlay .sel-header .spacer{flex:1}.praxis-files-upload .selected-overlay .sel-list{list-style:none;margin:0;padding:0}.praxis-files-upload .selected-overlay .sel-list .sel-item{display:flex;align-items:center;gap:.75rem;padding:.5rem .75rem;border-bottom:1px solid var(--md-sys-color-outline-variant, #ccc);transition:background-color .12s ease}.praxis-files-upload .selected-overlay .sel-list .sel-item .file-icon{opacity:.9;color:var(--md-sys-color-primary, #1976d2)}.praxis-files-upload .selected-overlay .sel-list .sel-item .info{flex:1;min-width:0}.praxis-files-upload .selected-overlay .sel-list .sel-item .info .name{font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.praxis-files-upload .selected-overlay .sel-list .sel-item .info .meta{font-size:.8rem;opacity:.7}.praxis-files-upload .selected-overlay .sel-list .sel-item .remove-btn{color:var(--md-sys-color-error, #b00020)}.praxis-files-upload .selected-overlay .sel-list .sel-item .more-btn{margin-left:.25rem}.praxis-files-upload .selected-overlay .sel-list .sel-item:hover{background:var(--md-sys-color-surface-container-low)}:host ::ng-deep .praxis-files-upload-overlay-panel{pointer-events:none}:host ::ng-deep .praxis-files-selected-overlay-panel{pointer-events:auto;z-index:3}\n"] }]
3704
3985
  }], ctorParameters: () => [{ type: i1$2.SettingsPanelService }, { type: DragProximityService }, { type: undefined, decorators: [{
3705
3986
  type: Inject,
3706
3987
  args: [FILES_UPLOAD_TEXTS]
3707
- }] }, { type: i3.Overlay }, { type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }, { type: FilesApiClient, decorators: [{
3988
+ }] }, { type: i3.Overlay }, { type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }, { type: undefined, decorators: [{
3989
+ type: Inject,
3990
+ args: [ASYNC_CONFIG_STORAGE]
3991
+ }] }, { type: FilesApiClient, decorators: [{
3708
3992
  type: Optional
3709
3993
  }] }, { type: PresignedUploaderService, decorators: [{
3710
3994
  type: Optional
@@ -3715,19 +3999,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
3715
3999
  }, {
3716
4000
  type: Inject,
3717
4001
  args: [TRANSLATE_LIKE]
3718
- }] }, { type: undefined, decorators: [{
3719
- type: Optional
3720
- }, {
3721
- type: Inject,
3722
- args: [CONFIG_STORAGE]
3723
4002
  }] }], propDecorators: { config: [{
3724
4003
  type: Input
3725
- }], componentId: [{
4004
+ }], filesUploadId: [{
4005
+ type: Input
4006
+ }], uploadId: [{
4007
+ type: Input
4008
+ }], componentInstanceId: [{
3726
4009
  type: Input
3727
4010
  }], baseUrl: [{
3728
4011
  type: Input
3729
4012
  }], displayMode: [{
3730
4013
  type: Input
4014
+ }], context: [{
4015
+ type: Input
4016
+ }], editModeEnabled: [{
4017
+ type: Input
3731
4018
  }], uploadSuccess: [{
3732
4019
  type: Output
3733
4020
  }], bulkComplete: [{
@@ -3736,6 +4023,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
3736
4023
  type: Output
3737
4024
  }], rateLimited: [{
3738
4025
  type: Output
4026
+ }], uploadStart: [{
4027
+ type: Output
4028
+ }], uploadProgress: [{
4029
+ type: Output
4030
+ }], uploadError: [{
4031
+ type: Output
3739
4032
  }], retry: [{
3740
4033
  type: Output
3741
4034
  }], download: [{
@@ -3885,8 +4178,8 @@ class PdxFilesUploadFieldComponent extends SimpleBaseInputComponent {
3885
4178
  const i = Math.floor(Math.log(bytes) / Math.log(k));
3886
4179
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
3887
4180
  }
3888
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PdxFilesUploadFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
3889
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.4", type: PdxFilesUploadFieldComponent, isStandalone: true, selector: "pdx-material-files-upload", inputs: { config: "config", valueMode: "valueMode", baseUrl: "baseUrl" }, host: { properties: { "class": "componentCssClasses()", "attr.data-field-type": "\"files-upload\"", "attr.data-field-name": "metadata()?.name", "attr.data-component-id": "componentId()" } }, viewQueries: [{ propertyName: "uploader", first: true, predicate: ["uploader"], descendants: true }], usesInheritance: true, ngImport: i0, template: `
4181
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PdxFilesUploadFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
4182
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: PdxFilesUploadFieldComponent, isStandalone: true, selector: "pdx-material-files-upload", inputs: { config: "config", valueMode: "valueMode", baseUrl: "baseUrl" }, host: { properties: { "class": "componentCssClasses()", "attr.data-field-type": "\"files-upload\"", "attr.data-field-name": "metadata()?.name", "attr.data-component-id": "componentId()" } }, viewQueries: [{ propertyName: "uploader", first: true, predicate: ["uploader"], descendants: true }], usesInheritance: true, ngImport: i0, template: `
3890
4183
  <!-- Casca compacta tipo input -->
3891
4184
  <div class="pdx-upload-field-shell"
3892
4185
  role="button"
@@ -3977,16 +4270,16 @@ class PdxFilesUploadFieldComponent extends SimpleBaseInputComponent {
3977
4270
  displayMode="compact"
3978
4271
  style="display: none;"
3979
4272
  [config]="config"
3980
- [componentId]="componentId()"
4273
+ [filesUploadId]="componentId()"
3981
4274
  [baseUrl]="baseUrl"
3982
4275
  (uploadSuccess)="onUploadSuccess($event)"
3983
4276
  (bulkComplete)="onBulkComplete($event)"
3984
4277
  (error)="onUploadError($event)"
3985
4278
  (pendingFilesChange)="handlePendingFiles($event)"
3986
4279
  />
3987
- `, isInline: true, styles: [":host{position:relative}.pdx-upload-field-shell{display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;border:1px solid var(--pfx-surface-border, #ccc);border-radius:8px;background:var(--pfx-surface, var(--md-sys-color-surface));color:var(--md-sys-color-on-surface);min-height:40px;cursor:pointer}.pdx-upload-field-shell:focus-within{outline:2px solid var(--md-sys-color-primary,#1976d2);outline-offset:2px}.pdx-upload-field-shell.error{border-color:var(--md-sys-color-error,#b00020)}.pdx-upload-field-shell.disabled{opacity:.6;cursor:not-allowed}.pdx-upload-field-shell .prefix{color:var(--md-sys-color-primary,#1976d2)}.pdx-upload-field-shell .content{flex:1;min-width:0;display:flex;align-items:center;gap:.5rem}.pdx-upload-field-shell .placeholder{color:var(--md-sys-color-on-surface-variant)}.pdx-upload-field-shell .value{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.pdx-upload-field-shell .chip{font-size:.75rem;padding:0 .4rem;border-radius:999px;background:color-mix(in oklab,var(--mat-sys-color-primary,#1976d2) 15%,transparent);color:var(--mat-sys-color-primary,#1976d2)}.pdx-upload-field-shell .suffixes{display:flex;align-items:center;gap:.25rem}.pdx-upload-field-shell .icon-btn{border:0;background:transparent;padding:.25rem;border-radius:6px;cursor:pointer;color:var(--md-sys-color-on-surface-variant)}.pdx-upload-field-shell .icon-btn:hover{background:#ffffff0d}.pdx-upload-field-shell.disabled .icon-btn{cursor:not-allowed}.field-messages{font-size:.82rem;margin-top:.25rem}.field-messages .hint{opacity:.8}.field-messages .error{color:var(--md-sys-color-error,#b00020)}.pending-text-btn{display:flex;align-items:center;gap:.25rem;background:0;border:0;color:var(--md-sys-color-on-surface);font-family:inherit;font-size:inherit;padding:0;margin:0;cursor:pointer}.pending-text-btn span,.pending-text-btn mat-icon{color:inherit}.pending-files-menu .mat-mdc-menu-content{padding:0}.pending-file-item{display:flex;align-items:center;width:100%;gap:.5rem;padding:8px 16px}.pending-file-item .file-info{flex:1;min-width:0;text-align:left}.pending-file-item .file-name{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.pending-file-item .file-size{font-size:.8rem;opacity:.7}.pending-file-item .spacer{flex:1 1 auto}.pending-file-item .remove-pending-btn{color:var(--md-sys-color-on-surface-variant)}.pdx-upload-field-shell.proximity-active{border-style:dashed;border-color:var(--md-sys-color-primary);transform:scale(1.02);background:color-mix(in oklab,var(--pfx-surface) 85%,var(--md-sys-color-primary) 15%);transition:all .2s ease-in-out}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i7.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i7.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: PraxisFilesUpload, selector: "praxis-files-upload", inputs: ["config", "componentId", "baseUrl", "displayMode"], outputs: ["uploadSuccess", "bulkComplete", "error", "rateLimited", "retry", "download", "copyLink", "detailsOpened", "detailsClosed", "pendingFilesChange", "proximityChange"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i10.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i3$1.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i3$1.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i3$1.MatMenuContent, selector: "ng-template[matMenuContent]" }, { kind: "directive", type: i3$1.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i13.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] });
4280
+ `, isInline: true, styles: [":host{position:relative}.pdx-upload-field-shell{display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;border:1px solid var(--pfx-surface-border, #ccc);border-radius:8px;background:var(--pfx-surface, var(--md-sys-color-surface));color:var(--md-sys-color-on-surface);min-height:40px;cursor:pointer}.pdx-upload-field-shell:focus-within{outline:2px solid var(--md-sys-color-primary,#1976d2);outline-offset:2px}.pdx-upload-field-shell.error{border-color:var(--md-sys-color-error,#b00020)}.pdx-upload-field-shell.disabled{opacity:.6;cursor:not-allowed}.pdx-upload-field-shell .prefix{color:var(--md-sys-color-primary,#1976d2)}.pdx-upload-field-shell .content{flex:1;min-width:0;display:flex;align-items:center;gap:.5rem}.pdx-upload-field-shell .placeholder{color:var(--md-sys-color-on-surface-variant)}.pdx-upload-field-shell .value{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.pdx-upload-field-shell .chip{font-size:.75rem;padding:0 .4rem;border-radius:999px;background:var(--md-sys-color-primary-container);color:var(--md-sys-color-on-primary-container)}.pdx-upload-field-shell .suffixes{display:flex;align-items:center;gap:.25rem}.pdx-upload-field-shell .icon-btn{border:0;background:transparent;padding:.25rem;border-radius:6px;cursor:pointer;color:var(--md-sys-color-on-surface-variant)}.pdx-upload-field-shell .icon-btn:hover{background:#ffffff0d}.pdx-upload-field-shell.disabled .icon-btn{cursor:not-allowed}.field-messages{font-size:.82rem;margin-top:.25rem}.field-messages .hint{opacity:.8}.field-messages .error{color:var(--md-sys-color-error,#b00020)}.pending-text-btn{display:flex;align-items:center;gap:.25rem;background:0;border:0;color:var(--md-sys-color-on-surface);font-family:inherit;font-size:inherit;padding:0;margin:0;cursor:pointer}.pending-text-btn span,.pending-text-btn mat-icon{color:inherit}.pending-files-menu .mat-mdc-menu-content{padding:0}.pending-file-item{display:flex;align-items:center;width:100%;gap:.5rem;padding:8px 16px}.pending-file-item .file-info{flex:1;min-width:0;text-align:left}.pending-file-item .file-name{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.pending-file-item .file-size{font-size:.8rem;opacity:.7}.pending-file-item .spacer{flex:1 1 auto}.pending-file-item .remove-pending-btn{color:var(--md-sys-color-on-surface-variant)}.pdx-upload-field-shell.proximity-active{border-style:dashed;border-color:var(--md-sys-color-primary);transform:scale(1.02);background:var(--md-sys-color-surface-container-low);transition:all .2s ease-in-out}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i7.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i7.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: PraxisFilesUpload, selector: "praxis-files-upload", inputs: ["config", "filesUploadId", "uploadId", "componentInstanceId", "baseUrl", "displayMode", "context", "editModeEnabled"], outputs: ["uploadSuccess", "bulkComplete", "error", "rateLimited", "uploadStart", "uploadProgress", "uploadError", "retry", "download", "copyLink", "detailsOpened", "detailsClosed", "pendingFilesChange", "proximityChange"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i10.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i3$1.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i3$1.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i3$1.MatMenuContent, selector: "ng-template[matMenuContent]" }, { kind: "directive", type: i3$1.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i11.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] });
3988
4281
  }
3989
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PdxFilesUploadFieldComponent, decorators: [{
4282
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PdxFilesUploadFieldComponent, decorators: [{
3990
4283
  type: Component,
3991
4284
  args: [{ selector: 'pdx-material-files-upload', standalone: true, imports: [CommonModule, PraxisFilesUpload, MatIconModule, MatMenuModule, MatTooltipModule], template: `
3992
4285
  <!-- Casca compacta tipo input -->
@@ -4079,7 +4372,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
4079
4372
  displayMode="compact"
4080
4373
  style="display: none;"
4081
4374
  [config]="config"
4082
- [componentId]="componentId()"
4375
+ [filesUploadId]="componentId()"
4083
4376
  [baseUrl]="baseUrl"
4084
4377
  (uploadSuccess)="onUploadSuccess($event)"
4085
4378
  (bulkComplete)="onBulkComplete($event)"
@@ -4091,7 +4384,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
4091
4384
  '[attr.data-field-type]': '"files-upload"',
4092
4385
  '[attr.data-field-name]': 'metadata()?.name',
4093
4386
  '[attr.data-component-id]': 'componentId()',
4094
- }, styles: [":host{position:relative}.pdx-upload-field-shell{display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;border:1px solid var(--pfx-surface-border, #ccc);border-radius:8px;background:var(--pfx-surface, var(--md-sys-color-surface));color:var(--md-sys-color-on-surface);min-height:40px;cursor:pointer}.pdx-upload-field-shell:focus-within{outline:2px solid var(--md-sys-color-primary,#1976d2);outline-offset:2px}.pdx-upload-field-shell.error{border-color:var(--md-sys-color-error,#b00020)}.pdx-upload-field-shell.disabled{opacity:.6;cursor:not-allowed}.pdx-upload-field-shell .prefix{color:var(--md-sys-color-primary,#1976d2)}.pdx-upload-field-shell .content{flex:1;min-width:0;display:flex;align-items:center;gap:.5rem}.pdx-upload-field-shell .placeholder{color:var(--md-sys-color-on-surface-variant)}.pdx-upload-field-shell .value{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.pdx-upload-field-shell .chip{font-size:.75rem;padding:0 .4rem;border-radius:999px;background:color-mix(in oklab,var(--mat-sys-color-primary,#1976d2) 15%,transparent);color:var(--mat-sys-color-primary,#1976d2)}.pdx-upload-field-shell .suffixes{display:flex;align-items:center;gap:.25rem}.pdx-upload-field-shell .icon-btn{border:0;background:transparent;padding:.25rem;border-radius:6px;cursor:pointer;color:var(--md-sys-color-on-surface-variant)}.pdx-upload-field-shell .icon-btn:hover{background:#ffffff0d}.pdx-upload-field-shell.disabled .icon-btn{cursor:not-allowed}.field-messages{font-size:.82rem;margin-top:.25rem}.field-messages .hint{opacity:.8}.field-messages .error{color:var(--md-sys-color-error,#b00020)}.pending-text-btn{display:flex;align-items:center;gap:.25rem;background:0;border:0;color:var(--md-sys-color-on-surface);font-family:inherit;font-size:inherit;padding:0;margin:0;cursor:pointer}.pending-text-btn span,.pending-text-btn mat-icon{color:inherit}.pending-files-menu .mat-mdc-menu-content{padding:0}.pending-file-item{display:flex;align-items:center;width:100%;gap:.5rem;padding:8px 16px}.pending-file-item .file-info{flex:1;min-width:0;text-align:left}.pending-file-item .file-name{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.pending-file-item .file-size{font-size:.8rem;opacity:.7}.pending-file-item .spacer{flex:1 1 auto}.pending-file-item .remove-pending-btn{color:var(--md-sys-color-on-surface-variant)}.pdx-upload-field-shell.proximity-active{border-style:dashed;border-color:var(--md-sys-color-primary);transform:scale(1.02);background:color-mix(in oklab,var(--pfx-surface) 85%,var(--md-sys-color-primary) 15%);transition:all .2s ease-in-out}\n"] }]
4387
+ }, styles: [":host{position:relative}.pdx-upload-field-shell{display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;border:1px solid var(--pfx-surface-border, #ccc);border-radius:8px;background:var(--pfx-surface, var(--md-sys-color-surface));color:var(--md-sys-color-on-surface);min-height:40px;cursor:pointer}.pdx-upload-field-shell:focus-within{outline:2px solid var(--md-sys-color-primary,#1976d2);outline-offset:2px}.pdx-upload-field-shell.error{border-color:var(--md-sys-color-error,#b00020)}.pdx-upload-field-shell.disabled{opacity:.6;cursor:not-allowed}.pdx-upload-field-shell .prefix{color:var(--md-sys-color-primary,#1976d2)}.pdx-upload-field-shell .content{flex:1;min-width:0;display:flex;align-items:center;gap:.5rem}.pdx-upload-field-shell .placeholder{color:var(--md-sys-color-on-surface-variant)}.pdx-upload-field-shell .value{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.pdx-upload-field-shell .chip{font-size:.75rem;padding:0 .4rem;border-radius:999px;background:var(--md-sys-color-primary-container);color:var(--md-sys-color-on-primary-container)}.pdx-upload-field-shell .suffixes{display:flex;align-items:center;gap:.25rem}.pdx-upload-field-shell .icon-btn{border:0;background:transparent;padding:.25rem;border-radius:6px;cursor:pointer;color:var(--md-sys-color-on-surface-variant)}.pdx-upload-field-shell .icon-btn:hover{background:#ffffff0d}.pdx-upload-field-shell.disabled .icon-btn{cursor:not-allowed}.field-messages{font-size:.82rem;margin-top:.25rem}.field-messages .hint{opacity:.8}.field-messages .error{color:var(--md-sys-color-error,#b00020)}.pending-text-btn{display:flex;align-items:center;gap:.25rem;background:0;border:0;color:var(--md-sys-color-on-surface);font-family:inherit;font-size:inherit;padding:0;margin:0;cursor:pointer}.pending-text-btn span,.pending-text-btn mat-icon{color:inherit}.pending-files-menu .mat-mdc-menu-content{padding:0}.pending-file-item{display:flex;align-items:center;width:100%;gap:.5rem;padding:8px 16px}.pending-file-item .file-info{flex:1;min-width:0;text-align:left}.pending-file-item .file-name{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.pending-file-item .file-size{font-size:.8rem;opacity:.7}.pending-file-item .spacer{flex:1 1 auto}.pending-file-item .remove-pending-btn{color:var(--md-sys-color-on-surface-variant)}.pdx-upload-field-shell.proximity-active{border-style:dashed;border-color:var(--md-sys-color-primary);transform:scale(1.02);background:var(--md-sys-color-surface-container-low);transition:all .2s ease-in-out}\n"] }]
4095
4388
  }], propDecorators: { config: [{
4096
4389
  type: Input
4097
4390
  }], valueMode: [{
@@ -4161,37 +4454,251 @@ const FILES_UPLOAD_PT_BR = {
4161
4454
  'praxis.filesUpload.errors.UNKNOWN_ERROR': 'Erro desconhecido.',
4162
4455
  };
4163
4456
 
4164
- /** Metadata for PraxisFilesUpload component */
4165
4457
  const PRAXIS_FILES_UPLOAD_COMPONENT_METADATA = {
4166
4458
  id: 'praxis-files-upload',
4167
4459
  selector: 'praxis-files-upload',
4168
4460
  component: PraxisFilesUpload,
4169
4461
  friendlyName: 'Praxis Files Upload',
4170
- description: 'Upload de arquivos com dropzone, envio em lote e lista de resultados rica.',
4462
+ description: 'Componente para upload de arquivos com suporte a configuracao dinamica, eventos e integracao com backend.',
4171
4463
  icon: 'upload_file',
4172
4464
  inputs: [
4173
- { name: 'config', type: 'FilesUploadConfig | null', description: 'Configuração de UI/limites/opções/bulk/quotas/rateLimit/messages' },
4174
- { name: 'componentId', type: 'string', default: 'default', description: 'Identificador do componente (ex.: storage de preferências)' },
4175
- { name: 'baseUrl', type: 'string', description: 'Base URL da API de arquivos' },
4176
- { name: 'displayMode', type: "'full' | 'compact'", default: 'full', description: 'Modo de exibição do componente' },
4465
+ {
4466
+ name: 'config',
4467
+ type: 'FilesUploadConfig',
4468
+ label: 'Configuracao',
4469
+ description: 'Configuracao do upload (tipos aceitos, limites, endpoints, comportamento).',
4470
+ },
4471
+ {
4472
+ name: 'filesUploadId',
4473
+ type: 'string',
4474
+ label: 'Upload ID',
4475
+ description: 'Identificador logico do upload para persistencia e rastreamento.',
4476
+ },
4477
+ {
4478
+ name: 'uploadId',
4479
+ type: 'string',
4480
+ label: 'Upload ID (alias)',
4481
+ description: 'Alias funcional de filesUploadId para compatibilidade com hosts.',
4482
+ },
4483
+ {
4484
+ name: 'componentInstanceId',
4485
+ type: 'string',
4486
+ label: 'ID da instancia',
4487
+ description: 'Identificador opcional para diferenciar multiplas instancias na mesma tela.',
4488
+ },
4489
+ {
4490
+ name: 'baseUrl',
4491
+ type: 'string',
4492
+ label: 'Base URL',
4493
+ description: 'Base URL da API de arquivos.',
4494
+ },
4495
+ {
4496
+ name: 'displayMode',
4497
+ type: "'full' | 'compact'",
4498
+ default: 'full',
4499
+ label: 'Modo de exibicao',
4500
+ description: 'Define o modo de exibicao do componente.',
4501
+ },
4502
+ {
4503
+ name: 'context',
4504
+ type: 'Record<string, unknown>',
4505
+ label: 'Contexto',
4506
+ description: 'Contexto usado para resolver expressoes em metadados.',
4507
+ },
4508
+ {
4509
+ name: 'editModeEnabled',
4510
+ type: 'boolean',
4511
+ default: true,
4512
+ label: 'Modo de edicao',
4513
+ description: 'Habilita a UI de configuracao no runtime.',
4514
+ },
4177
4515
  ],
4178
4516
  outputs: [
4179
- { name: 'uploadSuccess', type: '{ file: FileMetadata }', description: 'Emite após upload único com sucesso' },
4180
- { name: 'bulkComplete', type: 'BulkUploadResponse', description: 'Emite após upload em lote completar' },
4181
- { name: 'error', type: 'ErrorResponse', description: 'Erros de upload' },
4182
- { name: 'rateLimited', type: 'RateLimitInfo', description: 'Sinaliza rate limiting' },
4183
- { name: 'retry', type: 'BulkUploadFileResult', description: 'Usuário acionou reenvio' },
4184
- { name: 'download', type: 'BulkUploadFileResult', description: 'Usuário solicitou download' },
4185
- { name: 'copyLink', type: 'BulkUploadFileResult', description: 'Usuário copiou link' },
4186
- { name: 'detailsOpened', type: 'BulkUploadFileResult', description: 'Detalhes do item abertos' },
4187
- { name: 'detailsClosed', type: 'BulkUploadFileResult', description: 'Detalhes do item fechados' },
4188
- { name: 'pendingFilesChange', type: 'File[]', description: 'Mudança na lista de arquivos pendentes' },
4189
- { name: 'proximityChange', type: 'boolean', description: 'Mudança de estado de proximidade (drag-over expand)' },
4517
+ {
4518
+ name: 'uploadSuccess',
4519
+ type: '{ file: FileMetadata }',
4520
+ label: 'Upload concluido',
4521
+ description: 'Disparado quando o upload e finalizado com sucesso.',
4522
+ },
4523
+ {
4524
+ name: 'bulkComplete',
4525
+ type: 'BulkUploadResponse',
4526
+ label: 'Upload em lote concluido',
4527
+ description: 'Disparado quando o upload em lote e finalizado.',
4528
+ },
4529
+ {
4530
+ name: 'error',
4531
+ type: 'ErrorResponse',
4532
+ label: 'Erro no upload',
4533
+ description: 'Disparado quando ocorre erro durante o upload.',
4534
+ },
4535
+ {
4536
+ name: 'rateLimited',
4537
+ type: 'RateLimitInfo',
4538
+ label: 'Rate limit',
4539
+ description: 'Disparado quando ocorre rate limiting.',
4540
+ },
4541
+ {
4542
+ name: 'uploadStart',
4543
+ type: 'UploadStartEvent',
4544
+ label: 'Inicio do upload',
4545
+ description: 'Disparado quando o upload inicia com contexto do envio.',
4546
+ },
4547
+ {
4548
+ name: 'uploadProgress',
4549
+ type: 'UploadProgressEvent',
4550
+ label: 'Progresso',
4551
+ description: 'Disparado conforme o progresso de upload.',
4552
+ },
4553
+ {
4554
+ name: 'uploadError',
4555
+ type: 'ErrorResponse',
4556
+ label: 'Erro no upload',
4557
+ description: 'Disparado quando ocorre erro durante o upload.',
4558
+ },
4559
+ {
4560
+ name: 'retry',
4561
+ type: 'BulkUploadFileResult',
4562
+ label: 'Reenvio',
4563
+ description: 'Disparado quando o usuario aciona reenvio.',
4564
+ },
4565
+ {
4566
+ name: 'download',
4567
+ type: 'BulkUploadFileResult',
4568
+ label: 'Download',
4569
+ description: 'Disparado quando o usuario solicita download.',
4570
+ },
4571
+ {
4572
+ name: 'copyLink',
4573
+ type: 'BulkUploadFileResult',
4574
+ label: 'Copiar link',
4575
+ description: 'Disparado quando o usuario copia o link.',
4576
+ },
4577
+ {
4578
+ name: 'detailsOpened',
4579
+ type: 'BulkUploadFileResult',
4580
+ label: 'Detalhes abertos',
4581
+ description: 'Disparado quando os detalhes do item sao abertos.',
4582
+ },
4583
+ {
4584
+ name: 'detailsClosed',
4585
+ type: 'BulkUploadFileResult',
4586
+ label: 'Detalhes fechados',
4587
+ description: 'Disparado quando os detalhes do item sao fechados.',
4588
+ },
4589
+ {
4590
+ name: 'pendingFilesChange',
4591
+ type: 'File[]',
4592
+ label: 'Arquivos pendentes',
4593
+ description: 'Disparado quando a lista de arquivos pendentes muda.',
4594
+ },
4595
+ {
4596
+ name: 'proximityChange',
4597
+ type: 'boolean',
4598
+ label: 'Proximidade',
4599
+ description: 'Disparado quando muda o estado de proximidade do drag.',
4600
+ },
4190
4601
  ],
4191
- tags: ['widget', 'upload', 'configurable', 'hasWizard', 'stable'],
4602
+ actions: [
4603
+ {
4604
+ id: 'retry',
4605
+ label: 'Reenviar',
4606
+ icon: 'refresh',
4607
+ description: 'Emite evento de reenvio do item',
4608
+ emit: 'retry',
4609
+ payloadSchema: {
4610
+ type: 'object',
4611
+ properties: {
4612
+ fileName: { type: 'string', description: 'Nome do arquivo' },
4613
+ status: { type: 'string', description: 'Status do upload' },
4614
+ file: { type: 'object', description: 'Metadados do arquivo' },
4615
+ error: { type: 'object', description: 'Erro do upload' },
4616
+ },
4617
+ required: ['fileName', 'status'],
4618
+ example: { fileName: 'documento.pdf', status: 'failed' },
4619
+ },
4620
+ scope: 'context',
4621
+ },
4622
+ {
4623
+ id: 'download',
4624
+ label: 'Download',
4625
+ icon: 'file_download',
4626
+ description: 'Emite evento de download do item',
4627
+ emit: 'download',
4628
+ payloadSchema: {
4629
+ type: 'object',
4630
+ properties: {
4631
+ fileName: { type: 'string', description: 'Nome do arquivo' },
4632
+ status: { type: 'string', description: 'Status do upload' },
4633
+ file: { type: 'object', description: 'Metadados do arquivo' },
4634
+ error: { type: 'object', description: 'Erro do upload' },
4635
+ },
4636
+ required: ['fileName', 'status'],
4637
+ example: { fileName: 'documento.pdf', status: 'succeeded' },
4638
+ },
4639
+ scope: 'context',
4640
+ },
4641
+ {
4642
+ id: 'copy-link',
4643
+ label: 'Copiar link',
4644
+ icon: 'link',
4645
+ description: 'Emite evento ao copiar o link do item',
4646
+ emit: 'copyLink',
4647
+ payloadSchema: {
4648
+ type: 'object',
4649
+ properties: {
4650
+ fileName: { type: 'string', description: 'Nome do arquivo' },
4651
+ status: { type: 'string', description: 'Status do upload' },
4652
+ file: { type: 'object', description: 'Metadados do arquivo' },
4653
+ error: { type: 'object', description: 'Erro do upload' },
4654
+ },
4655
+ required: ['fileName', 'status'],
4656
+ example: { fileName: 'documento.pdf', status: 'succeeded' },
4657
+ },
4658
+ scope: 'context',
4659
+ },
4660
+ {
4661
+ id: 'details-opened',
4662
+ label: 'Abrir detalhes',
4663
+ icon: 'info',
4664
+ description: 'Emite evento ao abrir detalhes do item',
4665
+ emit: 'detailsOpened',
4666
+ payloadSchema: {
4667
+ type: 'object',
4668
+ properties: {
4669
+ fileName: { type: 'string', description: 'Nome do arquivo' },
4670
+ status: { type: 'string', description: 'Status do upload' },
4671
+ file: { type: 'object', description: 'Metadados do arquivo' },
4672
+ error: { type: 'object', description: 'Erro do upload' },
4673
+ },
4674
+ required: ['fileName', 'status'],
4675
+ example: { fileName: 'documento.pdf', status: 'succeeded' },
4676
+ },
4677
+ scope: 'context',
4678
+ },
4679
+ {
4680
+ id: 'details-closed',
4681
+ label: 'Fechar detalhes',
4682
+ icon: 'info_outline',
4683
+ description: 'Emite evento ao fechar detalhes do item',
4684
+ emit: 'detailsClosed',
4685
+ payloadSchema: {
4686
+ type: 'object',
4687
+ properties: {
4688
+ fileName: { type: 'string', description: 'Nome do arquivo' },
4689
+ status: { type: 'string', description: 'Status do upload' },
4690
+ file: { type: 'object', description: 'Metadados do arquivo' },
4691
+ error: { type: 'object', description: 'Erro do upload' },
4692
+ },
4693
+ required: ['fileName', 'status'],
4694
+ example: { fileName: 'documento.pdf', status: 'succeeded' },
4695
+ },
4696
+ scope: 'context',
4697
+ },
4698
+ ],
4699
+ tags: ['files', 'upload', 'widget', 'configurable'],
4192
4700
  lib: '@praxisui/files-upload',
4193
4701
  };
4194
- /** Provider para auto-registrar metadados do componente Files Upload. */
4195
4702
  function providePraxisFilesUploadMetadata() {
4196
4703
  return {
4197
4704
  provide: ENVIRONMENT_INITIALIZER,
@@ -4203,11 +4710,94 @@ function providePraxisFilesUploadMetadata() {
4203
4710
  };
4204
4711
  }
4205
4712
 
4713
+ /**
4714
+ * Capabilities catalog for FilesUploadConfig.
4715
+ * Paths follow FilesUploadConfig shape (patch merged at config root).
4716
+ */
4717
+ const ENUMS = {
4718
+ strategy: ['direct', 'presign', 'auto'],
4719
+ dropzoneExpandMode: ['overlay', 'inline'],
4720
+ listDetailsMode: ['card', 'sidesheet', 'auto'],
4721
+ listDetailsAnchor: ['item', 'field'],
4722
+ conflictPolicy: ['ERROR', 'SKIP', 'OVERWRITE', 'MAKE_UNIQUE', 'RENAME'],
4723
+ };
4724
+ const FILES_UPLOAD_AI_CAPABILITIES = {
4725
+ version: 'v1.0',
4726
+ enums: ENUMS,
4727
+ targets: ['praxis-files-upload', 'files-upload-dropzone'],
4728
+ notes: [
4729
+ 'limits.maxFileSizeBytes and limits.maxBulkSizeBytes are bytes (e.g., 10485760 for 10MB).',
4730
+ 'options.allowedExtensions is enforced by backend validation; ui.accept is only a client hint.',
4731
+ 'Use limits.defaultConflictPolicy to control name collisions on upload.',
4732
+ ],
4733
+ capabilities: [
4734
+ { path: 'strategy', category: 'strategy', valueKind: 'enum', allowedValues: ENUMS.strategy, description: 'Upload strategy.' },
4735
+ { path: 'ui', category: 'ui', valueKind: 'object', description: 'UI configuration.' },
4736
+ { path: 'ui.showDropzone', category: 'ui', valueKind: 'boolean', description: 'Show drag-and-drop dropzone.' },
4737
+ { path: 'ui.accept', category: 'ui', valueKind: 'array', description: 'Accept attribute hints (extensions or mime types).' },
4738
+ { path: 'ui.accept[]', category: 'ui', valueKind: 'string', description: 'Single accept entry.' },
4739
+ { path: 'ui.dense', category: 'ui', valueKind: 'boolean', description: 'Dense layout.' },
4740
+ { path: 'ui.showConflictPolicySelector', category: 'ui', valueKind: 'boolean', description: 'Show conflict policy selector.' },
4741
+ { path: 'ui.showMetadataForm', category: 'ui', valueKind: 'boolean', description: 'Show metadata form for each file.' },
4742
+ { path: 'ui.showProgress', category: 'ui', valueKind: 'boolean', description: 'Show progress UI.' },
4743
+ { path: 'ui.manualUpload', category: 'ui', valueKind: 'boolean', description: 'Require manual start for uploads.' },
4744
+ { path: 'ui.dropzone', category: 'ui', valueKind: 'object', description: 'Dropzone interaction options.' },
4745
+ { path: 'ui.dropzone.expandOnDragProximity', category: 'ui', valueKind: 'boolean', description: 'Expand dropzone on drag proximity.' },
4746
+ { path: 'ui.dropzone.proximityPx', category: 'ui', valueKind: 'number', description: 'Proximity radius in pixels.' },
4747
+ { path: 'ui.dropzone.expandMode', category: 'ui', valueKind: 'enum', allowedValues: ENUMS.dropzoneExpandMode, description: 'Dropzone expansion mode.' },
4748
+ { path: 'ui.dropzone.expandHeight', category: 'ui', valueKind: 'number', description: 'Expanded height (px).' },
4749
+ { path: 'ui.dropzone.expandDebounceMs', category: 'ui', valueKind: 'number', description: 'Drag debounce (ms).' },
4750
+ { path: 'ui.list', category: 'ui', valueKind: 'object', description: 'Uploaded files list options.' },
4751
+ { path: 'ui.list.collapseAfter', category: 'ui', valueKind: 'number', description: 'Collapse list after N items.' },
4752
+ { path: 'ui.list.detailsMode', category: 'ui', valueKind: 'enum', allowedValues: ENUMS.listDetailsMode, description: 'Details panel mode.' },
4753
+ { path: 'ui.list.detailsMaxWidth', category: 'ui', valueKind: 'number', description: 'Details panel max width (px).' },
4754
+ { path: 'ui.list.detailsShowTechnical', category: 'ui', valueKind: 'boolean', description: 'Show technical details by default.' },
4755
+ { path: 'ui.list.detailsFields', category: 'ui', valueKind: 'array', description: 'Allowed metadata fields to display.' },
4756
+ { path: 'ui.list.detailsFields[]', category: 'ui', valueKind: 'string', description: 'Single metadata field name.' },
4757
+ { path: 'ui.list.detailsAnchor', category: 'ui', valueKind: 'enum', allowedValues: ENUMS.listDetailsAnchor, description: 'Details overlay anchor.' },
4758
+ { path: 'limits', category: 'limits', valueKind: 'object', description: 'Upload limits.' },
4759
+ { path: 'limits.maxFileSizeBytes', category: 'limits', valueKind: 'number', description: 'Max file size (bytes).' },
4760
+ { path: 'limits.maxFilesPerBulk', category: 'limits', valueKind: 'number', description: 'Max files per bulk upload.' },
4761
+ { path: 'limits.maxBulkSizeBytes', category: 'limits', valueKind: 'number', description: 'Max bulk size (bytes).' },
4762
+ { path: 'limits.defaultConflictPolicy', category: 'limits', valueKind: 'enum', allowedValues: ENUMS.conflictPolicy, description: 'Default conflict policy.' },
4763
+ { path: 'limits.failFast', category: 'limits', valueKind: 'boolean', description: 'Abort on first error.' },
4764
+ { path: 'limits.strictValidation', category: 'limits', valueKind: 'boolean', description: 'Strict client validation.' },
4765
+ { path: 'limits.maxUploadSizeMb', category: 'limits', valueKind: 'number', description: 'Max upload size in MB.' },
4766
+ { path: 'options', category: 'options', valueKind: 'object', description: 'Backend options sent as JSON.' },
4767
+ { path: 'options.allowedExtensions', category: 'options', valueKind: 'array', description: 'Allowed file extensions.' },
4768
+ { path: 'options.allowedExtensions[]', category: 'options', valueKind: 'string', description: 'Single extension (e.g., pdf).' },
4769
+ { path: 'options.acceptMimeTypes', category: 'options', valueKind: 'array', description: 'Allowed mime types.' },
4770
+ { path: 'options.acceptMimeTypes[]', category: 'options', valueKind: 'string', description: 'Single mime type.' },
4771
+ { path: 'options.targetDirectory', category: 'options', valueKind: 'string', description: 'Target directory on backend.' },
4772
+ { path: 'options.enableVirusScanning', category: 'options', valueKind: 'boolean', description: 'Enable virus scanning.' },
4773
+ { path: 'bulk', category: 'bulk', valueKind: 'object', description: 'Bulk upload tuning.' },
4774
+ { path: 'bulk.parallelUploads', category: 'bulk', valueKind: 'number', description: 'Parallel uploads count.' },
4775
+ { path: 'bulk.retryCount', category: 'bulk', valueKind: 'number', description: 'Retry count.' },
4776
+ { path: 'bulk.retryBackoffMs', category: 'bulk', valueKind: 'number', description: 'Retry backoff (ms).' },
4777
+ { path: 'quotas', category: 'quotas', valueKind: 'object', description: 'Quota UX behavior.' },
4778
+ { path: 'quotas.showQuotaWarnings', category: 'quotas', valueKind: 'boolean', description: 'Show quota warnings.' },
4779
+ { path: 'quotas.blockOnExceed', category: 'quotas', valueKind: 'boolean', description: 'Block uploads when exceeded.' },
4780
+ { path: 'rateLimit', category: 'rateLimit', valueKind: 'object', description: '429 handling.' },
4781
+ { path: 'rateLimit.autoRetryOn429', category: 'rateLimit', valueKind: 'boolean', description: 'Auto retry on 429.' },
4782
+ { path: 'rateLimit.showBannerOn429', category: 'rateLimit', valueKind: 'boolean', description: 'Show rate limit banner.' },
4783
+ { path: 'rateLimit.maxAutoRetry', category: 'rateLimit', valueKind: 'number', description: 'Max auto retry attempts.' },
4784
+ { path: 'rateLimit.baseBackoffMs', category: 'rateLimit', valueKind: 'number', description: 'Base backoff (ms).' },
4785
+ { path: 'headers', category: 'headers', valueKind: 'object', description: 'Header mapping for backend.' },
4786
+ { path: 'headers.tenantHeader', category: 'headers', valueKind: 'string', description: 'Tenant header name.' },
4787
+ { path: 'headers.userHeader', category: 'headers', valueKind: 'string', description: 'User header name.' },
4788
+ { path: 'messages', category: 'messages', valueKind: 'object', description: 'User-facing text overrides.' },
4789
+ { path: 'messages.successSingle', category: 'messages', valueKind: 'string', description: 'Single upload success message.' },
4790
+ { path: 'messages.successBulk', category: 'messages', valueKind: 'string', description: 'Bulk upload success message.' },
4791
+ { path: 'messages.errors', category: 'messages', valueKind: 'object', description: 'Error message map.' },
4792
+ { path: 'messages.errors.[code]', category: 'messages', valueKind: 'string', description: 'Message for a specific error code.' },
4793
+ ],
4794
+ };
4795
+
4206
4796
  // Export all public API from subdirectories
4207
4797
 
4208
4798
  /**
4209
4799
  * Generated bundle index. Do not edit.
4210
4800
  */
4211
4801
 
4212
- export { BulkUploadResultStatus, ErrorCode, ErrorMapperService, FILES_UPLOAD_ERROR_MESSAGES, FILES_UPLOAD_PT_BR, FILES_UPLOAD_TEXTS, FilesApiClient, PRAXIS_FILES_UPLOAD_COMPONENT_METADATA, PdxFilesUploadFieldComponent, PraxisFilesUpload, PraxisFilesUploadConfigEditor, PresignedUploaderService, ScanStatus, TRANSLATE_LIKE, acceptValidator, maxBulkSizeValidator, maxFileSizeValidator, maxFilesPerBulkValidator, providePraxisFilesUploadMetadata };
4802
+ export { BulkUploadResultStatus, ErrorCode, ErrorMapperService, FILES_UPLOAD_AI_CAPABILITIES, FILES_UPLOAD_ERROR_MESSAGES, FILES_UPLOAD_PT_BR, FILES_UPLOAD_TEXTS, FilesApiClient, PRAXIS_FILES_UPLOAD_COMPONENT_METADATA, PdxFilesUploadFieldComponent, PraxisFilesUpload, PraxisFilesUploadConfigEditor, PresignedUploaderService, ScanStatus, TRANSLATE_LIKE, acceptValidator, maxBulkSizeValidator, maxFileSizeValidator, maxFilesPerBulkValidator, providePraxisFilesUploadMetadata };
4213
4803
  //# sourceMappingURL=praxisui-files-upload.mjs.map