@acorex/platform 20.6.0-next.1 → 20.6.0-next.3

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.
@@ -72,7 +72,7 @@ import { AXFileService } from '@acorex/core/file';
72
72
  import * as i1$9 from '@acorex/components/data-table';
73
73
  import { AXDataTableModule } from '@acorex/components/data-table';
74
74
  import { AXPCommandExecutor, provideCommandSetups } from '@acorex/platform/runtime';
75
- import { AXDropZoneDirective, moveItemInArray, AXDragDirective, AXDragHandleDirective, AXDropListDirective } from '@acorex/cdk/drag-drop';
75
+ import { AXUploaderZoneDirective } from '@acorex/cdk/uploader';
76
76
  import { AXUploaderModule } from '@acorex/components/uploader';
77
77
  import * as i1$a from '@acorex/components/media-viewer';
78
78
  import { AXMediaViewerModule } from '@acorex/components/media-viewer';
@@ -83,6 +83,7 @@ import { AXMapModule } from '@acorex/components/map';
83
83
  import * as i1$d from '@acorex/components/grid-layout-builder';
84
84
  import { AXGridLayoutContainerComponent, AXGridLayoutBuilderModule } from '@acorex/components/grid-layout-builder';
85
85
  import { AXPDesignerService, AXPWidgetDesignerRendererDirective, AXPDesignerGridDrawerComponent, AXPDesignerAddWidgetMiniButtonComponent, AXPDesignerFlexDrawerComponent } from '@acorex/platform/layout/designer';
86
+ import { moveItemInArray, AXDragDirective, AXDragHandleDirective, AXDropListDirective } from '@acorex/cdk/drag-drop';
86
87
  import * as i1$e from '@acorex/components/step-wizard';
87
88
  import { AXStepWizardModule } from '@acorex/components/step-wizard';
88
89
  import * as i1$f from '@acorex/components/button-group';
@@ -4780,7 +4781,9 @@ class AXPSelectBoxWidgetEditComponent extends AXPDataListWidgetComponent {
4780
4781
  if (this.filter()) {
4781
4782
  const cleanedFilters = AXPCleanNestedFilters([this.filter()]);
4782
4783
  if (cleanedFilters.length > 0) {
4783
- this.dataSource()?.filter(this.filterOperatorMiddleware.transformFilter(cleanedFilters[0]));
4784
+ untracked(() => {
4785
+ this.dataSource()?.filter(this.filterOperatorMiddleware.transformFilter(cleanedFilters[0]));
4786
+ });
4784
4787
  }
4785
4788
  }
4786
4789
  }, ...(ngDevMode ? [{ debugName: "#effect" }] : []));
@@ -8176,6 +8179,7 @@ const FileUploaderWebhookKeys = {
8176
8179
  AfterDownload: 'file-uploader.fileItem.after-download',
8177
8180
  AfterEdit: 'file-uploader.fileItem.after-edit',
8178
8181
  AfterRemove: 'file-uploader.fileItem.after-remove',
8182
+ DownloadReference: 'file-uploader.fileItem.download-reference',
8179
8183
  },
8180
8184
  EditDialog: {
8181
8185
  Params: {
@@ -8470,8 +8474,6 @@ class AXPFileListComponent {
8470
8474
  this.displayFiles = computed(() => this.files(), ...(ngDevMode ? [{ debugName: "displayFiles" }] : []));
8471
8475
  // Cache for per-file actions provided by hooks
8472
8476
  this.fileIdToActions = signal({}, ...(ngDevMode ? [{ debugName: "fileIdToActions" }] : []));
8473
- // Upload trigger for empty state click
8474
- this.uploadTrigger = input(undefined, ...(ngDevMode ? [{ debugName: "uploadTrigger" }] : []));
8475
8477
  }
8476
8478
  actionsFor(file, index) {
8477
8479
  const key = file.id ?? String(index);
@@ -8511,7 +8513,9 @@ class AXPFileListComponent {
8511
8513
  type: fileType?.name || 'Unknown',
8512
8514
  };
8513
8515
  }
8514
- async handleFileDownload(file) {
8516
+ async handleFileDownload(event, file) {
8517
+ event.nativeEvent.preventDefault();
8518
+ event.nativeEvent.stopPropagation();
8515
8519
  try {
8516
8520
  await this.hooks.runAsync(FileUploaderWebhookKeys.FileItem.BeforeDownload, {
8517
8521
  host: this.host(),
@@ -8586,6 +8590,46 @@ class AXPFileListComponent {
8586
8590
  console.error('Source kind is url, but value is not a string URL.', file);
8587
8591
  }
8588
8592
  break;
8593
+ case 'reference':
8594
+ if (file.source.value && typeof file.source.value === 'object' && 'id' in file.source.value && 'type' in file.source.value) {
8595
+ try {
8596
+ const result = await this.hooks.runAsync(FileUploaderWebhookKeys.FileItem.DownloadReference, {
8597
+ host: this.host(),
8598
+ file,
8599
+ reference: file.source.value,
8600
+ plugins: this.plugins() ?? [],
8601
+ excludePlugins: this.excludePlugins() ?? [],
8602
+ fileInfo: undefined,
8603
+ });
8604
+ if (result?.fileInfo) {
8605
+ if (result.fileInfo.url) {
8606
+ const link = document.createElement('a');
8607
+ link.href = result.fileInfo.url;
8608
+ link.download = file.name ?? result.fileInfo.name ?? 'download';
8609
+ link.target = '_blank';
8610
+ document.body.appendChild(link);
8611
+ link.click();
8612
+ document.body.removeChild(link);
8613
+ }
8614
+ else if (result.fileInfo.binary instanceof Blob) {
8615
+ triggerDownload(result.fileInfo.binary, file.name ?? result.fileInfo.name ?? 'download');
8616
+ }
8617
+ else {
8618
+ console.error('Could not retrieve file for download from reference:', result.fileInfo);
8619
+ }
8620
+ }
8621
+ else {
8622
+ console.error('Hook did not return fileInfo for reference download.', file);
8623
+ }
8624
+ }
8625
+ catch (error) {
8626
+ console.error('Error downloading file by reference:', file.source.value, error);
8627
+ }
8628
+ }
8629
+ else {
8630
+ console.error('Source kind is reference, but value is not a valid AXPEntityReference.', file);
8631
+ }
8632
+ break;
8589
8633
  case 'preview':
8590
8634
  case 'none':
8591
8635
  default:
@@ -8602,7 +8646,9 @@ class AXPFileListComponent {
8602
8646
  }
8603
8647
  catch { }
8604
8648
  }
8605
- async handleFileRemove(file) {
8649
+ async handleFileRemove(event, file) {
8650
+ event.nativeEvent.preventDefault();
8651
+ event.nativeEvent.stopPropagation();
8606
8652
  this.onRemove.emit(file);
8607
8653
  try {
8608
8654
  await this.hooks.runAsync(FileUploaderWebhookKeys.FileItem.AfterRemove, {
@@ -8617,13 +8663,23 @@ class AXPFileListComponent {
8617
8663
  /**
8618
8664
  * Handle revert action – emit the file so parent components can update the status.
8619
8665
  */
8620
- handleFileRevert(file) {
8666
+ handleFileRevert(event, file) {
8667
+ event.nativeEvent.preventDefault();
8668
+ event.nativeEvent.stopPropagation();
8621
8669
  this.onRevert.emit(file);
8622
8670
  }
8623
8671
  /**
8624
8672
  * Handle file edit action – open rename popup
8625
8673
  */
8626
- async handleFileEdit(file) {
8674
+ async handleFileEdit(event, file) {
8675
+ // if (event instanceof MouseEvent) {
8676
+ debugger;
8677
+ event.stopPropagation();
8678
+ event.preventDefault();
8679
+ // } else {
8680
+ // event.nativeEvent.preventDefault();
8681
+ // event.nativeEvent.stopPropagation();
8682
+ // }
8627
8683
  if (this.readonly()) {
8628
8684
  return;
8629
8685
  }
@@ -8653,21 +8709,8 @@ class AXPFileListComponent {
8653
8709
  console.error(e);
8654
8710
  }
8655
8711
  }
8656
- //#region ---- Empty State Handler ----
8657
- /**
8658
- * Handle empty state click - trigger file upload
8659
- */
8660
- async handleEmptyStateClick() {
8661
- if (this.readonly() && !this.uploadTrigger()) {
8662
- return;
8663
- }
8664
- const trigger = this.uploadTrigger();
8665
- if (trigger) {
8666
- await trigger();
8667
- }
8668
- }
8669
8712
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: AXPFileListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8670
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.10", type: AXPFileListComponent, isStandalone: true, selector: "axp-file-list", inputs: { readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, fileEditable: { classPropertyName: "fileEditable", publicName: "fileEditable", isSignal: true, isRequired: false, transformFunction: null }, files: { classPropertyName: "files", publicName: "files", isSignal: true, isRequired: false, transformFunction: null }, plugins: { classPropertyName: "plugins", publicName: "plugins", isSignal: true, isRequired: false, transformFunction: null }, excludePlugins: { classPropertyName: "excludePlugins", publicName: "excludePlugins", isSignal: true, isRequired: false, transformFunction: null }, host: { classPropertyName: "host", publicName: "host", isSignal: true, isRequired: false, transformFunction: null }, uploadTrigger: { classPropertyName: "uploadTrigger", publicName: "uploadTrigger", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onRemove: "onRemove", onRevert: "onRevert", onRename: "onRename" }, providers: [], ngImport: i0, template: "@for (file of displayFiles(); track $index) {\n <div\n class=\"__item\"\n [ngClass]=\"{ '--removed': file.status === 'deleted', '--attached': file.status === 'attached' }\"\n (dblclick)=\"handleFileEdit(file)\"\n >\n <div class=\"__icon\">\n <i class=\"fa-fw {{ getFileInfo(file.name).icon }} fa-solid\"></i>\n </div>\n <div class=\"__name\">{{ file.name }}</div>\n <div class=\"__actions\">\n @if (file.status === 'deleted') {\n <!-- Revert button -->\n <ax-button [look]=\"'blank'\" class=\"ax-sm\" color=\"warning\" (onClick)=\"handleFileRevert(file)\">\n <ax-icon class=\"fa-light fa-rotate-left\"></ax-icon>\n </ax-button>\n } @else {\n <!-- Regular actions -->\n <ax-button [look]=\"'blank'\" class=\"ax-sm\" color=\"primary\" (onClick)=\"handleFileDownload(file)\">\n <ax-icon class=\"fa-light fa-download\"></ax-icon>\n </ax-button>\n @if (!readonly() && ((!fileEditable() && file.status === 'attached') || fileEditable())) {\n <ax-button [look]=\"'blank'\" class=\"ax-sm\" color=\"secondary\" (onClick)=\"handleFileEdit(file)\">\n <ax-icon class=\"fa-light fa-pencil\"></ax-icon>\n </ax-button>\n <ax-button [look]=\"'blank'\" class=\"ax-sm\" color=\"danger\" (onClick)=\"handleFileRemove(file)\">\n <ax-icon class=\"fa-light fa-trash-can\"></ax-icon>\n </ax-button>\n <!-- Extension actions injected via hooks -->\n @for (action of actionsFor(file, $index); track action.textKey ?? action.text) {\n <ax-button [look]=\"'blank'\" class=\"ax-sm\" (onClick)=\"runAction(action)\">\n @if (action.icon) {\n <ax-icon class=\"{{ action.icon }}\"></ax-icon>\n }\n </ax-button>\n }\n }\n }\n </div>\n </div>\n} @empty {\n <div class=\"__empty-state\" (click)=\"handleEmptyStateClick()\">\n <axp-state-message\n icon=\"fa-light fa-folder-open\"\n [title]=\"'@general:widgets.file-uploader.empty-state.title'\"\n [description]=\"'@general:widgets.file-uploader.empty-state.description'\"\n >\n </axp-state-message>\n </div>\n}\n", styles: [":host{display:flex;width:100%;flex-direction:column;gap:.125rem;padding-top:.5rem;padding-bottom:.5rem}:host .__item{display:flex;cursor:pointer;align-items:center;gap:.75rem;border-left-width:4px;border-color:transparent;padding:.5rem}:host .__item:hover{background-color:rgb(var(--ax-sys-color-lighter-surface));color:rgb(var(--ax-sys-color-on-lighter-surface));border-color:rgb(var(--ax-sys-color-border-lighter-surface))}:host .__item.--removed{--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-danger-500),var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-danger-50),var(--tw-bg-opacity, 1))}:host .__item.--attached{--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-success-500),var(--tw-border-opacity, 1));animation:attached-flash 1s ease-out forwards}:host .__item .__icon{width:1.5rem;flex-shrink:0}:host .__item .__name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:start;font-size:.875rem;line-height:1.25rem;font-weight:500}:host .__item .__actions{margin-left:auto;display:flex}@keyframes attached-flash{0%{background-color:rgb(var(--ax-sys-color-success-50))}to{background-color:transparent}}.__empty-state{cursor:pointer;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s;animation-duration:.2s}.__empty-state:hover{opacity:.8}\n"], dependencies: [{ kind: "ngmodule", type:
8713
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.10", type: AXPFileListComponent, isStandalone: true, selector: "axp-file-list", inputs: { readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, fileEditable: { classPropertyName: "fileEditable", publicName: "fileEditable", isSignal: true, isRequired: false, transformFunction: null }, files: { classPropertyName: "files", publicName: "files", isSignal: true, isRequired: false, transformFunction: null }, plugins: { classPropertyName: "plugins", publicName: "plugins", isSignal: true, isRequired: false, transformFunction: null }, excludePlugins: { classPropertyName: "excludePlugins", publicName: "excludePlugins", isSignal: true, isRequired: false, transformFunction: null }, host: { classPropertyName: "host", publicName: "host", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onRemove: "onRemove", onRevert: "onRevert", onRename: "onRename" }, providers: [], ngImport: i0, template: "@for (file of displayFiles(); track $index) {\n <div\n class=\"__item\"\n [ngClass]=\"{ '--removed': file.status === 'deleted', '--attached': file.status === 'attached' }\"\n (click)=\"handleFileEdit($event,file)\"\n >\n <div class=\"__icon\">\n <i class=\"fa-fw {{ getFileInfo(file.name).icon }} fa-solid\"></i>\n </div>\n <div class=\"__name\">{{ file.name }}</div>\n <div class=\"__actions\">\n @if (file.status === 'deleted') {\n <!-- Revert button -->\n <ax-button [look]=\"'blank'\" class=\"ax-sm\" color=\"warning\" (onClick)=\"handleFileRevert($event,file)\">\n <ax-icon class=\"fa-light fa-rotate-left\"></ax-icon>\n </ax-button>\n } @else {\n <!-- Regular actions -->\n <ax-button [look]=\"'blank'\" class=\"ax-sm\" color=\"primary\" (onClick)=\"handleFileDownload($event,file)\">\n <ax-icon class=\"fa-light fa-download\"></ax-icon>\n </ax-button>\n @if (!readonly() && ((!fileEditable() && file.status === 'attached') || fileEditable())) {\n <ax-button [look]=\"'blank'\" class=\"ax-sm\" color=\"secondary\" (onClick)=\"handleFileEdit($event,file)\">\n <ax-icon class=\"fa-light fa-pencil\"></ax-icon>\n </ax-button>\n <ax-button [look]=\"'blank'\" class=\"ax-sm\" color=\"danger\" (onClick)=\"handleFileRemove($event,file)\">\n <ax-icon class=\"fa-light fa-trash-can\"></ax-icon>\n </ax-button>\n <!-- Extension actions injected via hooks -->\n @for (action of actionsFor(file, $index); track action.textKey ?? action.text) {\n <ax-button [look]=\"'blank'\" class=\"ax-sm\" (onClick)=\"runAction(action)\">\n @if (action.icon) {\n <ax-icon class=\"{{ action.icon }}\"></ax-icon>\n }\n </ax-button>\n }\n }\n }\n </div>\n </div>\n} @empty {\n <div class=\"__empty-state\">\n <axp-state-message\n icon=\"fa-light fa-folder-open\"\n [title]=\"'@general:widgets.file-uploader.empty-state.title'\"\n [description]=\"'@general:widgets.file-uploader.empty-state.description'\"\n >\n </axp-state-message>\n </div>\n}\n", styles: [":host{display:flex;width:100%;flex-direction:column;gap:.125rem;padding-top:.5rem;padding-bottom:.5rem}:host .__item{display:flex;cursor:pointer;align-items:center;gap:.75rem;border-left-width:4px;border-color:transparent;padding:.5rem}:host .__item:hover{background-color:rgb(var(--ax-sys-color-lighter-surface));color:rgb(var(--ax-sys-color-on-lighter-surface));border-color:rgb(var(--ax-sys-color-border-lighter-surface))}:host .__item.--removed{--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-danger-500),var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-danger-50),var(--tw-bg-opacity, 1))}:host .__item.--attached{--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-success-500),var(--tw-border-opacity, 1));animation:attached-flash 1s ease-out forwards}:host .__item .__icon{width:1.5rem;flex-shrink:0}:host .__item .__name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:start;font-size:.875rem;line-height:1.25rem;font-weight:500}:host .__item .__actions{margin-left:auto;display:flex}@keyframes attached-flash{0%{background-color:rgb(var(--ax-sys-color-success-50))}to{background-color:transparent}}.__empty-state{cursor:pointer;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s;animation-duration:.2s}.__empty-state:hover{opacity:.8}\n"], dependencies: [{ kind: "ngmodule", type:
8671
8714
  // Angular
8672
8715
  CommonModule }, { kind: "directive", type: i1$3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type:
8673
8716
  // ACoreX
@@ -8690,8 +8733,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImpo
8690
8733
  AXTranslationModule,
8691
8734
  // Platform
8692
8735
  AXPStateMessageComponent,
8693
- ], providers: [], template: "@for (file of displayFiles(); track $index) {\n <div\n class=\"__item\"\n [ngClass]=\"{ '--removed': file.status === 'deleted', '--attached': file.status === 'attached' }\"\n (dblclick)=\"handleFileEdit(file)\"\n >\n <div class=\"__icon\">\n <i class=\"fa-fw {{ getFileInfo(file.name).icon }} fa-solid\"></i>\n </div>\n <div class=\"__name\">{{ file.name }}</div>\n <div class=\"__actions\">\n @if (file.status === 'deleted') {\n <!-- Revert button -->\n <ax-button [look]=\"'blank'\" class=\"ax-sm\" color=\"warning\" (onClick)=\"handleFileRevert(file)\">\n <ax-icon class=\"fa-light fa-rotate-left\"></ax-icon>\n </ax-button>\n } @else {\n <!-- Regular actions -->\n <ax-button [look]=\"'blank'\" class=\"ax-sm\" color=\"primary\" (onClick)=\"handleFileDownload(file)\">\n <ax-icon class=\"fa-light fa-download\"></ax-icon>\n </ax-button>\n @if (!readonly() && ((!fileEditable() && file.status === 'attached') || fileEditable())) {\n <ax-button [look]=\"'blank'\" class=\"ax-sm\" color=\"secondary\" (onClick)=\"handleFileEdit(file)\">\n <ax-icon class=\"fa-light fa-pencil\"></ax-icon>\n </ax-button>\n <ax-button [look]=\"'blank'\" class=\"ax-sm\" color=\"danger\" (onClick)=\"handleFileRemove(file)\">\n <ax-icon class=\"fa-light fa-trash-can\"></ax-icon>\n </ax-button>\n <!-- Extension actions injected via hooks -->\n @for (action of actionsFor(file, $index); track action.textKey ?? action.text) {\n <ax-button [look]=\"'blank'\" class=\"ax-sm\" (onClick)=\"runAction(action)\">\n @if (action.icon) {\n <ax-icon class=\"{{ action.icon }}\"></ax-icon>\n }\n </ax-button>\n }\n }\n }\n </div>\n </div>\n} @empty {\n <div class=\"__empty-state\" (click)=\"handleEmptyStateClick()\">\n <axp-state-message\n icon=\"fa-light fa-folder-open\"\n [title]=\"'@general:widgets.file-uploader.empty-state.title'\"\n [description]=\"'@general:widgets.file-uploader.empty-state.description'\"\n >\n </axp-state-message>\n </div>\n}\n", styles: [":host{display:flex;width:100%;flex-direction:column;gap:.125rem;padding-top:.5rem;padding-bottom:.5rem}:host .__item{display:flex;cursor:pointer;align-items:center;gap:.75rem;border-left-width:4px;border-color:transparent;padding:.5rem}:host .__item:hover{background-color:rgb(var(--ax-sys-color-lighter-surface));color:rgb(var(--ax-sys-color-on-lighter-surface));border-color:rgb(var(--ax-sys-color-border-lighter-surface))}:host .__item.--removed{--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-danger-500),var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-danger-50),var(--tw-bg-opacity, 1))}:host .__item.--attached{--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-success-500),var(--tw-border-opacity, 1));animation:attached-flash 1s ease-out forwards}:host .__item .__icon{width:1.5rem;flex-shrink:0}:host .__item .__name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:start;font-size:.875rem;line-height:1.25rem;font-weight:500}:host .__item .__actions{margin-left:auto;display:flex}@keyframes attached-flash{0%{background-color:rgb(var(--ax-sys-color-success-50))}to{background-color:transparent}}.__empty-state{cursor:pointer;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s;animation-duration:.2s}.__empty-state:hover{opacity:.8}\n"] }]
8694
- }], propDecorators: { onRemove: [{ type: i0.Output, args: ["onRemove"] }], onRevert: [{ type: i0.Output, args: ["onRevert"] }], onRename: [{ type: i0.Output, args: ["onRename"] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], fileEditable: [{ type: i0.Input, args: [{ isSignal: true, alias: "fileEditable", required: false }] }], files: [{ type: i0.Input, args: [{ isSignal: true, alias: "files", required: false }] }], plugins: [{ type: i0.Input, args: [{ isSignal: true, alias: "plugins", required: false }] }], excludePlugins: [{ type: i0.Input, args: [{ isSignal: true, alias: "excludePlugins", required: false }] }], host: [{ type: i0.Input, args: [{ isSignal: true, alias: "host", required: false }] }], uploadTrigger: [{ type: i0.Input, args: [{ isSignal: true, alias: "uploadTrigger", required: false }] }] } });
8736
+ ], providers: [], template: "@for (file of displayFiles(); track $index) {\n <div\n class=\"__item\"\n [ngClass]=\"{ '--removed': file.status === 'deleted', '--attached': file.status === 'attached' }\"\n (click)=\"handleFileEdit($event,file)\"\n >\n <div class=\"__icon\">\n <i class=\"fa-fw {{ getFileInfo(file.name).icon }} fa-solid\"></i>\n </div>\n <div class=\"__name\">{{ file.name }}</div>\n <div class=\"__actions\">\n @if (file.status === 'deleted') {\n <!-- Revert button -->\n <ax-button [look]=\"'blank'\" class=\"ax-sm\" color=\"warning\" (onClick)=\"handleFileRevert($event,file)\">\n <ax-icon class=\"fa-light fa-rotate-left\"></ax-icon>\n </ax-button>\n } @else {\n <!-- Regular actions -->\n <ax-button [look]=\"'blank'\" class=\"ax-sm\" color=\"primary\" (onClick)=\"handleFileDownload($event,file)\">\n <ax-icon class=\"fa-light fa-download\"></ax-icon>\n </ax-button>\n @if (!readonly() && ((!fileEditable() && file.status === 'attached') || fileEditable())) {\n <ax-button [look]=\"'blank'\" class=\"ax-sm\" color=\"secondary\" (onClick)=\"handleFileEdit($event,file)\">\n <ax-icon class=\"fa-light fa-pencil\"></ax-icon>\n </ax-button>\n <ax-button [look]=\"'blank'\" class=\"ax-sm\" color=\"danger\" (onClick)=\"handleFileRemove($event,file)\">\n <ax-icon class=\"fa-light fa-trash-can\"></ax-icon>\n </ax-button>\n <!-- Extension actions injected via hooks -->\n @for (action of actionsFor(file, $index); track action.textKey ?? action.text) {\n <ax-button [look]=\"'blank'\" class=\"ax-sm\" (onClick)=\"runAction(action)\">\n @if (action.icon) {\n <ax-icon class=\"{{ action.icon }}\"></ax-icon>\n }\n </ax-button>\n }\n }\n }\n </div>\n </div>\n} @empty {\n <div class=\"__empty-state\">\n <axp-state-message\n icon=\"fa-light fa-folder-open\"\n [title]=\"'@general:widgets.file-uploader.empty-state.title'\"\n [description]=\"'@general:widgets.file-uploader.empty-state.description'\"\n >\n </axp-state-message>\n </div>\n}\n", styles: [":host{display:flex;width:100%;flex-direction:column;gap:.125rem;padding-top:.5rem;padding-bottom:.5rem}:host .__item{display:flex;cursor:pointer;align-items:center;gap:.75rem;border-left-width:4px;border-color:transparent;padding:.5rem}:host .__item:hover{background-color:rgb(var(--ax-sys-color-lighter-surface));color:rgb(var(--ax-sys-color-on-lighter-surface));border-color:rgb(var(--ax-sys-color-border-lighter-surface))}:host .__item.--removed{--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-danger-500),var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgba(var(--ax-sys-color-danger-50),var(--tw-bg-opacity, 1))}:host .__item.--attached{--tw-border-opacity: 1;border-color:rgba(var(--ax-sys-color-success-500),var(--tw-border-opacity, 1));animation:attached-flash 1s ease-out forwards}:host .__item .__icon{width:1.5rem;flex-shrink:0}:host .__item .__name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:start;font-size:.875rem;line-height:1.25rem;font-weight:500}:host .__item .__actions{margin-left:auto;display:flex}@keyframes attached-flash{0%{background-color:rgb(var(--ax-sys-color-success-50))}to{background-color:transparent}}.__empty-state{cursor:pointer;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s;animation-duration:.2s}.__empty-state:hover{opacity:.8}\n"] }]
8737
+ }], propDecorators: { onRemove: [{ type: i0.Output, args: ["onRemove"] }], onRevert: [{ type: i0.Output, args: ["onRevert"] }], onRename: [{ type: i0.Output, args: ["onRename"] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], fileEditable: [{ type: i0.Input, args: [{ isSignal: true, alias: "fileEditable", required: false }] }], files: [{ type: i0.Input, args: [{ isSignal: true, alias: "files", required: false }] }], plugins: [{ type: i0.Input, args: [{ isSignal: true, alias: "plugins", required: false }] }], excludePlugins: [{ type: i0.Input, args: [{ isSignal: true, alias: "excludePlugins", required: false }] }], host: [{ type: i0.Input, args: [{ isSignal: true, alias: "host", required: false }] }] } });
8695
8738
 
8696
8739
  class AXPFileUploaderWidgetService {
8697
8740
  constructor() {
@@ -8952,44 +8995,8 @@ class AXPFileUploaderWidgetEditComponent extends AXPValueWidgetComponent {
8952
8995
  }
8953
8996
  }
8954
8997
  //#region ---- Drag & Drop Handlers ----
8955
- /**
8956
- * Handle drag entered event - show visual feedback
8957
- */
8958
- handleDragEntered() {
8959
- if (this.readonly()) {
8960
- return;
8961
- }
8962
- this.isDragOver.set(true);
8963
- }
8964
- /**
8965
- * Handle drag exited event - remove visual feedback
8966
- */
8967
- handleDragExited() {
8968
- if (this.readonly()) {
8969
- return;
8970
- }
8971
- this.isDragOver.set(false);
8972
- }
8973
- /**
8974
- * Handle drop event wrapper - process dropped files
8975
- */
8976
- handleDropWrapper(event) {
8977
- const dragEvent = event;
8978
- this.handleDrop(dragEvent);
8979
- }
8980
- /**
8981
- * Handle drop event - process dropped files
8982
- */
8983
- async handleDrop(event) {
8984
- if (this.readonly()) {
8985
- return;
8986
- }
8987
- this.isDragOver.set(false);
8988
- const files = event.dataTransfer?.files;
8989
- if (files && files.length > 0) {
8990
- const fileArray = Array.from(files);
8991
- await this.processFiles(fileArray);
8992
- }
8998
+ onFileChange(event) {
8999
+ this.processFiles(event.files);
8993
9000
  }
8994
9001
  //#endregion
8995
9002
  get __class() {
@@ -9042,11 +9049,8 @@ class AXPFileUploaderWidgetEditComponent extends AXPValueWidgetComponent {
9042
9049
  }
9043
9050
  <div
9044
9051
  class="ax-p-2"
9045
- axDropZone
9046
- (axDropZoneEntered)="handleDragEntered()"
9047
- (axDropZoneExited)="handleDragExited()"
9048
- (axDropZoneDropped)="handleDropWrapper($event)"
9049
- [class.__drag-over]="isDragOver()"
9052
+ axUploaderZone
9053
+ (fileChange)="onFileChange($event)"
9050
9054
  >
9051
9055
  <axp-file-list
9052
9056
  [files]="files()"
@@ -9055,14 +9059,13 @@ class AXPFileUploaderWidgetEditComponent extends AXPValueWidgetComponent {
9055
9059
  [plugins]="plugins()"
9056
9060
  [excludePlugins]="excludePlugins()"
9057
9061
  [host]="this"
9058
- [uploadTrigger]="uploadFromComputer.bind(this)"
9059
9062
  (onRemove)="handleFileRemove($event)"
9060
9063
  (onRevert)="handleFileRevert($event)"
9061
9064
  (onRename)="handleFileRename($event)"
9062
9065
  [readonly]="readonly()"
9063
9066
  ></axp-file-list>
9064
9067
  </div>
9065
- `, isInline: true, styles: [".__drag-over{background-color:rgba(var(--ax-sys-color-primary-50),.1);border:2px dashed rgb(var(--ax-sys-color-primary-500));border-radius:.375rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: AXDropZoneDirective, selector: "[axDropZone]", inputs: ["dropZoneGroup"], outputs: ["onElementDrop", "onElementHover"], exportAs: ["axDropZone"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "component", type: i1.AXButtonItemComponent, selector: "ax-button-item", inputs: ["color", "disabled", "text", "selected", "divided", "data", "name"], outputs: ["onClick", "onFocus", "onBlur", "disabledChange"] }, { kind: "component", type: i1.AXButtonItemListComponent, selector: "ax-button-item-list", inputs: ["items"], outputs: ["onItemClick"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i2$1.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "component", type: i5$1.AXDropdownPanelComponent, selector: "ax-dropdown-panel", inputs: ["isOpen", "fitParent", "dropdownWidth", "position", "placement", "_target", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXPComponentSlotModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "directive", type: i5.AXTranslatorDirective, selector: "[translate]" }, { kind: "component", type: AXPFileListComponent, selector: "axp-file-list", inputs: ["readonly", "fileEditable", "files", "plugins", "excludePlugins", "host", "uploadTrigger"], outputs: ["onRemove", "onRevert", "onRename"] }, { kind: "pipe", type: i1$3.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
9068
+ `, isInline: true, styles: [".__drag-over{background-color:rgba(var(--ax-sys-color-primary-50),.1);border:2px dashed rgb(var(--ax-sys-color-primary-500));border-radius:.375rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "component", type: i1.AXButtonItemComponent, selector: "ax-button-item", inputs: ["color", "disabled", "text", "selected", "divided", "data", "name"], outputs: ["onClick", "onFocus", "onBlur", "disabledChange"] }, { kind: "component", type: i1.AXButtonItemListComponent, selector: "ax-button-item-list", inputs: ["items"], outputs: ["onItemClick"] }, { kind: "directive", type: AXUploaderZoneDirective, selector: "[axUploaderZone]", inputs: ["multiple", "accept", "overlayTemplate"], outputs: ["fileChange", "onChanged", "dragEnter", "dragLeave", "dragOver", "onFileUploadComplete", "onFilesUploadComplete"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i2$1.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i2$1.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "ngmodule", type: AXDropdownModule }, { kind: "component", type: i5$1.AXDropdownPanelComponent, selector: "ax-dropdown-panel", inputs: ["isOpen", "fitParent", "dropdownWidth", "position", "placement", "_target", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }, { kind: "ngmodule", type: AXPComponentSlotModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "directive", type: i5.AXTranslatorDirective, selector: "[translate]" }, { kind: "component", type: AXPFileListComponent, selector: "axp-file-list", inputs: ["readonly", "fileEditable", "files", "plugins", "excludePlugins", "host"], outputs: ["onRemove", "onRevert", "onRename"] }, { kind: "pipe", type: i1$3.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
9066
9069
  }
9067
9070
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: AXPFileUploaderWidgetEditComponent, decorators: [{
9068
9071
  type: Component,
@@ -9106,11 +9109,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImpo
9106
9109
  }
9107
9110
  <div
9108
9111
  class="ax-p-2"
9109
- axDropZone
9110
- (axDropZoneEntered)="handleDragEntered()"
9111
- (axDropZoneExited)="handleDragExited()"
9112
- (axDropZoneDropped)="handleDropWrapper($event)"
9113
- [class.__drag-over]="isDragOver()"
9112
+ axUploaderZone
9113
+ (fileChange)="onFileChange($event)"
9114
9114
  >
9115
9115
  <axp-file-list
9116
9116
  [files]="files()"
@@ -9119,7 +9119,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImpo
9119
9119
  [plugins]="plugins()"
9120
9120
  [excludePlugins]="excludePlugins()"
9121
9121
  [host]="this"
9122
- [uploadTrigger]="uploadFromComputer.bind(this)"
9123
9122
  (onRemove)="handleFileRemove($event)"
9124
9123
  (onRevert)="handleFileRevert($event)"
9125
9124
  (onRename)="handleFileRename($event)"
@@ -9131,8 +9130,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImpo
9131
9130
  }, changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
9132
9131
  CommonModule,
9133
9132
  FormsModule,
9134
- AXDropZoneDirective,
9135
9133
  AXButtonModule,
9134
+ AXUploaderZoneDirective,
9136
9135
  AXDecoratorModule,
9137
9136
  AXLoadingModule,
9138
9137
  AXDropdownModule,
@@ -9164,7 +9163,7 @@ class AXPFileUploaderWidgetViewComponent extends AXPValueWidgetComponent {
9164
9163
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: AXPFileUploaderWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
9165
9164
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.10", type: AXPFileUploaderWidgetViewComponent, isStandalone: true, selector: "axp-file-uploader-widget-view", host: { properties: { "class": "this.__class" } }, usesInheritance: true, ngImport: i0, template: `
9166
9165
  <axp-file-list [files]="files()" [readonly]="true"></axp-file-list>
9167
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "ngmodule", type: AXUploaderModule }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "component", type: AXPFileListComponent, selector: "axp-file-list", inputs: ["readonly", "fileEditable", "files", "plugins", "excludePlugins", "host", "uploadTrigger"], outputs: ["onRemove", "onRevert", "onRename"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
9166
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: AXButtonModule }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "ngmodule", type: AXUploaderModule }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "component", type: AXPFileListComponent, selector: "axp-file-list", inputs: ["readonly", "fileEditable", "files", "plugins", "excludePlugins", "host"], outputs: ["onRemove", "onRevert", "onRename"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
9168
9167
  }
9169
9168
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: AXPFileUploaderWidgetViewComponent, decorators: [{
9170
9169
  type: Component,
@@ -10677,9 +10676,12 @@ class AXPStatusWidgetEditComponent extends AXPValueWidgetComponent {
10677
10676
  class="ax-flex ax-w-full ax-items-center ax-gap-3 ax-rounded ax-p-2 "
10678
10677
  >
10679
10678
  <div
10680
- class="ax-flex ax-h-8 ax-w-8 ax-items-center ax-justify-center ax-rounded-full"
10679
+ class="ax-size-8 ax-rounded-full ax-grid ax-place-items-center"
10681
10680
  [style.background-color]="item.color"
10682
10681
  >
10682
+ @if (item.icon) {
10683
+ <i [class]="item.icon" class="ax-text-white ax-text-xs"></i>
10684
+ }
10683
10685
  </div>
10684
10686
  <div class="ax-flex-1">
10685
10687
  <ax-title>{{ item.title | translate | async }}</ax-title>
@@ -10716,9 +10718,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImpo
10716
10718
  class="ax-flex ax-w-full ax-items-center ax-gap-3 ax-rounded ax-p-2 "
10717
10719
  >
10718
10720
  <div
10719
- class="ax-flex ax-h-8 ax-w-8 ax-items-center ax-justify-center ax-rounded-full"
10721
+ class="ax-size-8 ax-rounded-full ax-grid ax-place-items-center"
10720
10722
  [style.background-color]="item.color"
10721
10723
  >
10724
+ @if (item.icon) {
10725
+ <i [class]="item.icon" class="ax-text-white ax-text-xs"></i>
10726
+ }
10722
10727
  </div>
10723
10728
  <div class="ax-flex-1">
10724
10729
  <ax-title>{{ item.title | translate | async }}</ax-title>