@acorex/platform 20.6.0-next.2 → 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.
package/core/index.d.ts CHANGED
@@ -989,8 +989,8 @@ type AXPWidgetTriggers = AXPWidgetTrigger[];
989
989
 
990
990
  type AXPFileStatus = 'attached' | 'uploading' | 'uploaded' | 'deleted' | 'remote';
991
991
  interface AXPFileSource {
992
- kind: 'blob' | 'url' | 'preview' | 'none' | 'fileId' | 'documentId';
993
- value?: Blob | string;
992
+ kind: 'blob' | 'url' | 'preview' | 'none' | 'fileId' | 'reference';
993
+ value?: Blob | string | AXPEntityReference;
994
994
  }
995
995
  interface AXPFileListItem {
996
996
  id?: string;
@@ -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';
@@ -8178,6 +8179,7 @@ const FileUploaderWebhookKeys = {
8178
8179
  AfterDownload: 'file-uploader.fileItem.after-download',
8179
8180
  AfterEdit: 'file-uploader.fileItem.after-edit',
8180
8181
  AfterRemove: 'file-uploader.fileItem.after-remove',
8182
+ DownloadReference: 'file-uploader.fileItem.download-reference',
8181
8183
  },
8182
8184
  EditDialog: {
8183
8185
  Params: {
@@ -8472,8 +8474,6 @@ class AXPFileListComponent {
8472
8474
  this.displayFiles = computed(() => this.files(), ...(ngDevMode ? [{ debugName: "displayFiles" }] : []));
8473
8475
  // Cache for per-file actions provided by hooks
8474
8476
  this.fileIdToActions = signal({}, ...(ngDevMode ? [{ debugName: "fileIdToActions" }] : []));
8475
- // Upload trigger for empty state click
8476
- this.uploadTrigger = input(undefined, ...(ngDevMode ? [{ debugName: "uploadTrigger" }] : []));
8477
8477
  }
8478
8478
  actionsFor(file, index) {
8479
8479
  const key = file.id ?? String(index);
@@ -8513,7 +8513,9 @@ class AXPFileListComponent {
8513
8513
  type: fileType?.name || 'Unknown',
8514
8514
  };
8515
8515
  }
8516
- async handleFileDownload(file) {
8516
+ async handleFileDownload(event, file) {
8517
+ event.nativeEvent.preventDefault();
8518
+ event.nativeEvent.stopPropagation();
8517
8519
  try {
8518
8520
  await this.hooks.runAsync(FileUploaderWebhookKeys.FileItem.BeforeDownload, {
8519
8521
  host: this.host(),
@@ -8588,6 +8590,46 @@ class AXPFileListComponent {
8588
8590
  console.error('Source kind is url, but value is not a string URL.', file);
8589
8591
  }
8590
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;
8591
8633
  case 'preview':
8592
8634
  case 'none':
8593
8635
  default:
@@ -8604,7 +8646,9 @@ class AXPFileListComponent {
8604
8646
  }
8605
8647
  catch { }
8606
8648
  }
8607
- async handleFileRemove(file) {
8649
+ async handleFileRemove(event, file) {
8650
+ event.nativeEvent.preventDefault();
8651
+ event.nativeEvent.stopPropagation();
8608
8652
  this.onRemove.emit(file);
8609
8653
  try {
8610
8654
  await this.hooks.runAsync(FileUploaderWebhookKeys.FileItem.AfterRemove, {
@@ -8619,13 +8663,23 @@ class AXPFileListComponent {
8619
8663
  /**
8620
8664
  * Handle revert action – emit the file so parent components can update the status.
8621
8665
  */
8622
- handleFileRevert(file) {
8666
+ handleFileRevert(event, file) {
8667
+ event.nativeEvent.preventDefault();
8668
+ event.nativeEvent.stopPropagation();
8623
8669
  this.onRevert.emit(file);
8624
8670
  }
8625
8671
  /**
8626
8672
  * Handle file edit action – open rename popup
8627
8673
  */
8628
- 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
+ // }
8629
8683
  if (this.readonly()) {
8630
8684
  return;
8631
8685
  }
@@ -8655,21 +8709,8 @@ class AXPFileListComponent {
8655
8709
  console.error(e);
8656
8710
  }
8657
8711
  }
8658
- //#region ---- Empty State Handler ----
8659
- /**
8660
- * Handle empty state click - trigger file upload
8661
- */
8662
- async handleEmptyStateClick() {
8663
- if (this.readonly() && !this.uploadTrigger()) {
8664
- return;
8665
- }
8666
- const trigger = this.uploadTrigger();
8667
- if (trigger) {
8668
- await trigger();
8669
- }
8670
- }
8671
8712
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: AXPFileListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8672
- 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:
8673
8714
  // Angular
8674
8715
  CommonModule }, { kind: "directive", type: i1$3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type:
8675
8716
  // ACoreX
@@ -8692,8 +8733,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImpo
8692
8733
  AXTranslationModule,
8693
8734
  // Platform
8694
8735
  AXPStateMessageComponent,
8695
- ], 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"] }]
8696
- }], 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 }] }] } });
8697
8738
 
8698
8739
  class AXPFileUploaderWidgetService {
8699
8740
  constructor() {
@@ -8954,44 +8995,8 @@ class AXPFileUploaderWidgetEditComponent extends AXPValueWidgetComponent {
8954
8995
  }
8955
8996
  }
8956
8997
  //#region ---- Drag & Drop Handlers ----
8957
- /**
8958
- * Handle drag entered event - show visual feedback
8959
- */
8960
- handleDragEntered() {
8961
- if (this.readonly()) {
8962
- return;
8963
- }
8964
- this.isDragOver.set(true);
8965
- }
8966
- /**
8967
- * Handle drag exited event - remove visual feedback
8968
- */
8969
- handleDragExited() {
8970
- if (this.readonly()) {
8971
- return;
8972
- }
8973
- this.isDragOver.set(false);
8974
- }
8975
- /**
8976
- * Handle drop event wrapper - process dropped files
8977
- */
8978
- handleDropWrapper(event) {
8979
- const dragEvent = event;
8980
- this.handleDrop(dragEvent);
8981
- }
8982
- /**
8983
- * Handle drop event - process dropped files
8984
- */
8985
- async handleDrop(event) {
8986
- if (this.readonly()) {
8987
- return;
8988
- }
8989
- this.isDragOver.set(false);
8990
- const files = event.dataTransfer?.files;
8991
- if (files && files.length > 0) {
8992
- const fileArray = Array.from(files);
8993
- await this.processFiles(fileArray);
8994
- }
8998
+ onFileChange(event) {
8999
+ this.processFiles(event.files);
8995
9000
  }
8996
9001
  //#endregion
8997
9002
  get __class() {
@@ -9044,11 +9049,8 @@ class AXPFileUploaderWidgetEditComponent extends AXPValueWidgetComponent {
9044
9049
  }
9045
9050
  <div
9046
9051
  class="ax-p-2"
9047
- axDropZone
9048
- (axDropZoneEntered)="handleDragEntered()"
9049
- (axDropZoneExited)="handleDragExited()"
9050
- (axDropZoneDropped)="handleDropWrapper($event)"
9051
- [class.__drag-over]="isDragOver()"
9052
+ axUploaderZone
9053
+ (fileChange)="onFileChange($event)"
9052
9054
  >
9053
9055
  <axp-file-list
9054
9056
  [files]="files()"
@@ -9057,14 +9059,13 @@ class AXPFileUploaderWidgetEditComponent extends AXPValueWidgetComponent {
9057
9059
  [plugins]="plugins()"
9058
9060
  [excludePlugins]="excludePlugins()"
9059
9061
  [host]="this"
9060
- [uploadTrigger]="uploadFromComputer.bind(this)"
9061
9062
  (onRemove)="handleFileRemove($event)"
9062
9063
  (onRevert)="handleFileRevert($event)"
9063
9064
  (onRename)="handleFileRename($event)"
9064
9065
  [readonly]="readonly()"
9065
9066
  ></axp-file-list>
9066
9067
  </div>
9067
- `, 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 }); }
9068
9069
  }
9069
9070
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: AXPFileUploaderWidgetEditComponent, decorators: [{
9070
9071
  type: Component,
@@ -9108,11 +9109,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImpo
9108
9109
  }
9109
9110
  <div
9110
9111
  class="ax-p-2"
9111
- axDropZone
9112
- (axDropZoneEntered)="handleDragEntered()"
9113
- (axDropZoneExited)="handleDragExited()"
9114
- (axDropZoneDropped)="handleDropWrapper($event)"
9115
- [class.__drag-over]="isDragOver()"
9112
+ axUploaderZone
9113
+ (fileChange)="onFileChange($event)"
9116
9114
  >
9117
9115
  <axp-file-list
9118
9116
  [files]="files()"
@@ -9121,7 +9119,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImpo
9121
9119
  [plugins]="plugins()"
9122
9120
  [excludePlugins]="excludePlugins()"
9123
9121
  [host]="this"
9124
- [uploadTrigger]="uploadFromComputer.bind(this)"
9125
9122
  (onRemove)="handleFileRemove($event)"
9126
9123
  (onRevert)="handleFileRevert($event)"
9127
9124
  (onRename)="handleFileRename($event)"
@@ -9133,8 +9130,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImpo
9133
9130
  }, changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
9134
9131
  CommonModule,
9135
9132
  FormsModule,
9136
- AXDropZoneDirective,
9137
9133
  AXButtonModule,
9134
+ AXUploaderZoneDirective,
9138
9135
  AXDecoratorModule,
9139
9136
  AXLoadingModule,
9140
9137
  AXDropdownModule,
@@ -9166,7 +9163,7 @@ class AXPFileUploaderWidgetViewComponent extends AXPValueWidgetComponent {
9166
9163
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: AXPFileUploaderWidgetViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
9167
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: `
9168
9165
  <axp-file-list [files]="files()" [readonly]="true"></axp-file-list>
9169
- `, 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 }); }
9170
9167
  }
9171
9168
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: AXPFileUploaderWidgetViewComponent, decorators: [{
9172
9169
  type: Component,
@@ -10679,9 +10676,12 @@ class AXPStatusWidgetEditComponent extends AXPValueWidgetComponent {
10679
10676
  class="ax-flex ax-w-full ax-items-center ax-gap-3 ax-rounded ax-p-2 "
10680
10677
  >
10681
10678
  <div
10682
- 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"
10683
10680
  [style.background-color]="item.color"
10684
10681
  >
10682
+ @if (item.icon) {
10683
+ <i [class]="item.icon" class="ax-text-white ax-text-xs"></i>
10684
+ }
10685
10685
  </div>
10686
10686
  <div class="ax-flex-1">
10687
10687
  <ax-title>{{ item.title | translate | async }}</ax-title>
@@ -10718,9 +10718,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImpo
10718
10718
  class="ax-flex ax-w-full ax-items-center ax-gap-3 ax-rounded ax-p-2 "
10719
10719
  >
10720
10720
  <div
10721
- 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"
10722
10722
  [style.background-color]="item.color"
10723
10723
  >
10724
+ @if (item.icon) {
10725
+ <i [class]="item.icon" class="ax-text-white ax-text-xs"></i>
10726
+ }
10724
10727
  </div>
10725
10728
  <div class="ax-flex-1">
10726
10729
  <ax-title>{{ item.title | translate | async }}</ax-title>