@acorex-platform/framework-client 2.0.0-next.12 → 2.0.0-next.13

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.
Files changed (44) hide show
  1. package/fesm2022/{acorex-platform-framework-client-common-common-settings.provider-ChU2tvyt.mjs → acorex-platform-framework-client-common-common-settings.provider-Cyr1DaiD.mjs} +19 -2
  2. package/fesm2022/{acorex-platform-framework-client-common-common-settings.provider-ChU2tvyt.mjs.map → acorex-platform-framework-client-common-common-settings.provider-Cyr1DaiD.mjs.map} +1 -1
  3. package/fesm2022/acorex-platform-framework-client-common.mjs +126 -26
  4. package/fesm2022/acorex-platform-framework-client-common.mjs.map +1 -1
  5. package/fesm2022/acorex-platform-framework-client-layout-components.mjs +221 -98
  6. package/fesm2022/acorex-platform-framework-client-layout-components.mjs.map +1 -1
  7. package/fesm2022/{acorex-platform-framework-client-layout-entity-acorex-platform-framework-client-layout-entity-BUUIRvjv.mjs → acorex-platform-framework-client-layout-entity-acorex-platform-framework-client-layout-entity-D2kZxLOh.mjs} +16 -8
  8. package/fesm2022/{acorex-platform-framework-client-layout-entity-acorex-platform-framework-client-layout-entity-BUUIRvjv.mjs.map → acorex-platform-framework-client-layout-entity-acorex-platform-framework-client-layout-entity-D2kZxLOh.mjs.map} +1 -1
  9. package/fesm2022/{acorex-platform-framework-client-layout-entity-attachments-page.component-Bvu_DFae.mjs → acorex-platform-framework-client-layout-entity-attachments-page.component-BManmr01.mjs} +2 -2
  10. package/fesm2022/{acorex-platform-framework-client-layout-entity-attachments-page.component-Bvu_DFae.mjs.map → acorex-platform-framework-client-layout-entity-attachments-page.component-BManmr01.mjs.map} +1 -1
  11. package/fesm2022/{acorex-platform-framework-client-layout-entity-bulk-entity.command-AQyQql3E.mjs → acorex-platform-framework-client-layout-entity-bulk-entity.command-B8XsnrnO.mjs} +2 -2
  12. package/fesm2022/{acorex-platform-framework-client-layout-entity-bulk-entity.command-AQyQql3E.mjs.map → acorex-platform-framework-client-layout-entity-bulk-entity.command-B8XsnrnO.mjs.map} +1 -1
  13. package/fesm2022/{acorex-platform-framework-client-layout-entity-file-list-popup.component-BIlmfAGh.mjs → acorex-platform-framework-client-layout-entity-file-list-popup.component-DGZVS11E.mjs} +2 -2
  14. package/fesm2022/{acorex-platform-framework-client-layout-entity-file-list-popup.component-BIlmfAGh.mjs.map → acorex-platform-framework-client-layout-entity-file-list-popup.component-DGZVS11E.mjs.map} +1 -1
  15. package/fesm2022/{acorex-platform-framework-client-layout-entity-gallery-page.component-C9VXr6zx.mjs → acorex-platform-framework-client-layout-entity-gallery-page.component-Be348QCj.mjs} +2 -2
  16. package/fesm2022/{acorex-platform-framework-client-layout-entity-gallery-page.component-C9VXr6zx.mjs.map → acorex-platform-framework-client-layout-entity-gallery-page.component-Be348QCj.mjs.map} +1 -1
  17. package/fesm2022/acorex-platform-framework-client-layout-entity.mjs +1 -1
  18. package/fesm2022/acorex-platform-framework-client-layout-views.mjs +59 -10
  19. package/fesm2022/acorex-platform-framework-client-layout-views.mjs.map +1 -1
  20. package/fesm2022/{acorex-platform-framework-client-layout-widgets-acorex-platform-framework-client-layout-widgets-CzhP4_OE.mjs → acorex-platform-framework-client-layout-widgets-acorex-platform-framework-client-layout-widgets-M8SZFPQx.mjs} +13 -5
  21. package/fesm2022/acorex-platform-framework-client-layout-widgets-acorex-platform-framework-client-layout-widgets-M8SZFPQx.mjs.map +1 -0
  22. package/fesm2022/{acorex-platform-framework-client-layout-widgets-repeater-widget-column.component-BIl416zF.mjs → acorex-platform-framework-client-layout-widgets-repeater-widget-column.component-DsLgZbZA.mjs} +2 -2
  23. package/fesm2022/{acorex-platform-framework-client-layout-widgets-repeater-widget-column.component-BIl416zF.mjs.map → acorex-platform-framework-client-layout-widgets-repeater-widget-column.component-DsLgZbZA.mjs.map} +1 -1
  24. package/fesm2022/{acorex-platform-framework-client-layout-widgets-text-block-widget-designer.component-DK8XXQuT.mjs → acorex-platform-framework-client-layout-widgets-text-block-widget-designer.component-Vpz3itLZ.mjs} +2 -2
  25. package/fesm2022/{acorex-platform-framework-client-layout-widgets-text-block-widget-designer.component-DK8XXQuT.mjs.map → acorex-platform-framework-client-layout-widgets-text-block-widget-designer.component-Vpz3itLZ.mjs.map} +1 -1
  26. package/fesm2022/acorex-platform-framework-client-layout-widgets.mjs +1 -1
  27. package/fesm2022/acorex-platform-framework-client-realtime.mjs +49 -7
  28. package/fesm2022/acorex-platform-framework-client-realtime.mjs.map +1 -1
  29. package/fesm2022/acorex-platform-framework-client-themes-default.mjs +14 -7
  30. package/fesm2022/acorex-platform-framework-client-themes-default.mjs.map +1 -1
  31. package/i18n/en-AU/general.json +16 -4
  32. package/i18n/en-AU/layout.json +2 -1
  33. package/i18n/en-US/general.json +16 -4
  34. package/i18n/en-US/layout.json +2 -1
  35. package/i18n/fa-IR/general.json +16 -4
  36. package/i18n/fa-IR/layout.json +2 -1
  37. package/package.json +2 -2
  38. package/types/acorex-platform-framework-client-common.d.ts +40 -5
  39. package/types/acorex-platform-framework-client-layout-components.d.ts +9 -3
  40. package/types/acorex-platform-framework-client-layout-entity.d.ts +2 -0
  41. package/types/acorex-platform-framework-client-layout-views.d.ts +15 -0
  42. package/types/acorex-platform-framework-client-layout-widgets.d.ts +12 -0
  43. package/types/acorex-platform-framework-client-realtime.d.ts +5 -0
  44. package/fesm2022/acorex-platform-framework-client-layout-widgets-acorex-platform-framework-client-layout-widgets-CzhP4_OE.mjs.map +0 -1
@@ -14,12 +14,12 @@ import * as i4$3 from '@acorex/core/format';
14
14
  import { AXFormatService, AXFormatModule } from '@acorex/core/format';
15
15
  import { AXPLayoutRendererComponent, AXPDialogOpener, AXPLayoutBuilderService, resolveLayoutBuilderDialogResult } from '@acorex-platform/framework-client/layout/builder';
16
16
  import * as i1 from '@angular/common';
17
- import { CommonModule, NgTemplateOutlet, AsyncPipe, isPlatformBrowser, NgComponentOutlet, DOCUMENT } from '@angular/common';
17
+ import { CommonModule, NgTemplateOutlet, AsyncPipe, isPlatformBrowser, DOCUMENT, NgComponentOutlet } from '@angular/common';
18
18
  import * as i0 from '@angular/core';
19
19
  import { inject, input, signal, effect, ViewEncapsulation, ChangeDetectionStrategy, Component, output, computed, linkedSignal, InjectionToken, Injector, Injectable, Directive, viewChild, contentChild, ElementRef, afterNextRender, model, EventEmitter, forwardRef, ViewChild, Output, Input, untracked, DestroyRef, PLATFORM_ID, createComponent, EnvironmentInjector, runInInjectionContext, ApplicationRef, makeEnvironmentProviders, viewChildren, ViewChildren, TemplateRef, contentChildren } from '@angular/core';
20
20
  import { AXAccordionCdkModule } from '@acorex/cdk/accordion';
21
21
  import { AXTagModule } from '@acorex/components/tag';
22
- import { AXPSettingsService, AXPStateMessageComponent, AXPFileChooserSettings, normalizeStoredImageRef, extractFileExtension, AXPFileStorageService, AXPFileTypeProviderService, resolveFileTypeDisplay, AXPCommonSettings, coerceAXPSettingRawValueByKind, AXPFilterOperatorMiddlewareService, ALL_DEFAULT_OPERATORS, withDefaultMultiLanguageOnWidgetProperty, AXPDefaultMultiLanguageConfigService, resolveSearchableText, isStoredImageFileId, resolveStoredImageDisplayUrl } from '@acorex-platform/framework-client/common';
22
+ import { AXPSettingsService, AXPStateMessageComponent, openSystemFileDialog, AXPFileChooserSettings, normalizeStoredImageRef, extractFileExtension, AXPFileStorageService, AXPFileTypeProviderService, resolveFileTypeDisplay, AXPCommonSettings, coerceAXPSettingRawValueByKind, AXPFilterOperatorMiddlewareService, ALL_DEFAULT_OPERATORS, withDefaultMultiLanguageOnWidgetProperty, AXPDefaultMultiLanguageConfigService, resolveSearchableText, isStoredImageFileId, resolveStoredImageDisplayUrl, AXPUserStatusFeatureService } from '@acorex-platform/framework-client/common';
23
23
  export { AXPFileChooserSettings, AXPStateMessageComponent } from '@acorex-platform/framework-client/common';
24
24
  import * as i1$1 from '@acorex/components/avatar';
25
25
  import { AXAvatarModule } from '@acorex/components/avatar';
@@ -65,8 +65,8 @@ import { AXPopupService } from '@acorex/components/popup';
65
65
  import { moveItemInArray as moveItemInArray$1, AXDragDirective, AXDragHandleDirective, AXDropListDirective } from '@acorex/cdk/drag-drop';
66
66
  import { normalizeEntityListUserStylingRules, AXP_ENTITY_LIST_RECORD_STYLING_TARGET, createEntityListStylingCondition, isEntityListRecordStylingTarget, resolveEntityListFilterQueryField, resolveEntityListFilterContextField, isCustomQueryView } from '@acorex-platform/framework-shared/entity';
67
67
  import { AXLookupComponent } from '@acorex/components/lookup';
68
- import { DomSanitizer } from '@angular/platform-browser';
69
68
  import { AXToastService } from '@acorex/components/toast';
69
+ import { DomSanitizer } from '@angular/platform-browser';
70
70
  import { getFileExtension, AXFileService } from '@acorex/core/file';
71
71
  import { AXDialogService } from '@acorex/components/dialog';
72
72
  import { resolveFileViewerFileType, AXFileViewerContainerComponent, AXFileViewerService, AXFileViewerGalleryService } from '@acorex/components/file-viewer';
@@ -4264,36 +4264,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
4264
4264
  args: [{ providedIn: 'root' }]
4265
4265
  }] });
4266
4266
 
4267
- //#region ---- Rejection notifications ----
4268
- async function notifyFileAcceptRejections(rejected, deps) {
4269
- if (rejected.length === 0) {
4270
- return;
4271
- }
4272
- const { translateService, toastService, maxFileSize } = deps;
4273
- const errorTitle = await translateService.translateAsync('@general:messages.error.title');
4274
- const typeRejections = rejected.filter((entry) => entry.reason === 'type');
4275
- const sizeRejections = rejected.filter((entry) => entry.reason === 'size');
4276
- if (typeRejections.length === 1) {
4277
- const content = await translateService.translateAsync('@general:widgets.file-uploader.validation.file-type-not-allowed', { params: { fileName: typeRejections[0].file.name } });
4278
- toastService.show({ color: 'danger', title: errorTitle, content });
4279
- return;
4280
- }
4281
- if (typeRejections.length > 1) {
4282
- const content = await translateService.translateAsync('@general:widgets.file-uploader.validation.file-type-not-allowed-summary', { params: { count: typeRejections.length } });
4283
- toastService.show({ color: 'danger', title: errorTitle, content });
4284
- return;
4285
- }
4286
- if (sizeRejections.length === 1) {
4287
- const maxMb = Math.round((maxFileSize / (1024 * 1024)) * 10) / 10;
4288
- const content = await translateService.translateAsync('@general:widgets.file-uploader.validation.file-size-exceeds-limit', { params: { fileName: sizeRejections[0].file.name, maxSizeMb: maxMb } });
4289
- toastService.show({ color: 'danger', title: errorTitle, content });
4290
- return;
4291
- }
4292
- const content = await translateService.translateAsync('@general:widgets.file-uploader.validation.files-rejected-summary', { params: { count: rejected.length } });
4293
- toastService.show({ color: 'danger', title: errorTitle, content });
4294
- }
4295
- //#endregion
4296
-
4297
4267
  //#endregion
4298
4268
  //#region ---- Validation ----
4299
4269
  function isUnrestrictedFileAccept(accept) {
@@ -4478,6 +4448,36 @@ function matchesCategoryByExtension(fileName, category) {
4478
4448
  }
4479
4449
  //#endregion
4480
4450
 
4451
+ //#region ---- Rejection notifications ----
4452
+ async function notifyFileAcceptRejections(rejected, deps) {
4453
+ if (rejected.length === 0) {
4454
+ return;
4455
+ }
4456
+ const { translateService, toastService, maxFileSize } = deps;
4457
+ const errorTitle = await translateService.translateAsync('@general:messages.generic.error.title');
4458
+ const typeRejections = rejected.filter((entry) => entry.reason === 'type');
4459
+ const sizeRejections = rejected.filter((entry) => entry.reason === 'size');
4460
+ if (typeRejections.length === 1) {
4461
+ const content = await translateService.translateAsync('@general:widgets.file-uploader.validation.file-type-not-allowed', { params: { fileName: typeRejections[0].file.name } });
4462
+ toastService.show({ color: 'danger', title: errorTitle, content });
4463
+ }
4464
+ else if (typeRejections.length > 1) {
4465
+ const content = await translateService.translateAsync('@general:widgets.file-uploader.validation.file-type-not-allowed-summary', { params: { count: typeRejections.length } });
4466
+ toastService.show({ color: 'danger', title: errorTitle, content });
4467
+ }
4468
+ if (sizeRejections.length === 1) {
4469
+ const maxSize = formatMaxFileSizeForDisplay(maxFileSize);
4470
+ const content = await translateService.translateAsync('@general:widgets.file-uploader.validation.file-size-exceeds-limit', { params: { fileName: sizeRejections[0].file.name, maxSize } });
4471
+ toastService.show({ color: 'danger', title: errorTitle, content });
4472
+ return;
4473
+ }
4474
+ if (sizeRejections.length > 1) {
4475
+ const content = await translateService.translateAsync('@general:widgets.file-uploader.validation.files-rejected-summary', { params: { count: sizeRejections.length } });
4476
+ toastService.show({ color: 'danger', title: errorTitle, content });
4477
+ }
4478
+ }
4479
+ //#endregion
4480
+
4481
4481
  //#region ---- Accept resolution ----
4482
4482
  const ZIP_ACCEPT_TOKENS = '.zip,application/zip';
4483
4483
  /**
@@ -4503,7 +4503,8 @@ function resolveFileChooserAccept(accept, promptZipOnMultiple) {
4503
4503
  //#endregion
4504
4504
 
4505
4505
  //#region ---- Chooser result validation ----
4506
- function fileFromListItem(item) {
4506
+ /** Blob-backed chooser item as a {@link File}. Drive and file-id items return undefined. */
4507
+ function resolveChooserItemFile(item) {
4507
4508
  const source = item.source;
4508
4509
  if (source?.kind !== 'blob' || source.value == null) {
4509
4510
  return undefined;
@@ -4512,7 +4513,8 @@ function fileFromListItem(item) {
4512
4513
  return source.value;
4513
4514
  }
4514
4515
  if (source.value instanceof Blob) {
4515
- return new File([source.value], item.name, {
4516
+ const name = item.name?.trim() || 'file';
4517
+ return new File([source.value], name, {
4516
4518
  type: source.value.type ?? '',
4517
4519
  });
4518
4520
  }
@@ -4525,30 +4527,38 @@ function validateFileChooserItems(items, options) {
4525
4527
  const accept = options['accept'];
4526
4528
  const maxFileSize = defaultTo(options['maxFileSize'], 0);
4527
4529
  const passthrough = [];
4528
- const blobItems = [];
4529
- const blobFiles = [];
4530
+ const blobEntries = [];
4530
4531
  for (const item of items) {
4531
- const file = fileFromListItem(item);
4532
+ const file = resolveChooserItemFile(item);
4532
4533
  if (file) {
4533
- blobItems.push(item);
4534
- blobFiles.push(file);
4534
+ blobEntries.push({ item, file });
4535
4535
  continue;
4536
4536
  }
4537
4537
  passthrough.push(item);
4538
4538
  }
4539
- const namedAccepted = passthrough.filter((item) => isUnrestrictedFileAccept(accept) || fileNameMatchesAccept(item.name ?? '', accept));
4540
- const namedRejected = passthrough
4541
- .filter((item) => !namedAccepted.includes(item))
4542
- .map((item) => ({
4543
- file: new File([], item.name ?? 'file', { type: '' }),
4544
- reason: 'type',
4545
- }));
4546
- if (!blobFiles.length) {
4539
+ const namedAccepted = [];
4540
+ const namedRejected = [];
4541
+ for (const item of passthrough) {
4542
+ const placeholder = new File([], item.name ?? 'file', { type: '' });
4543
+ const typeOk = isUnrestrictedFileAccept(accept) || fileNameMatchesAccept(item.name ?? '', accept);
4544
+ if (!typeOk) {
4545
+ namedRejected.push({ file: placeholder, reason: 'type' });
4546
+ continue;
4547
+ }
4548
+ if (maxFileSize > 0 && (item.size ?? 0) > maxFileSize) {
4549
+ namedRejected.push({ file: placeholder, reason: 'size' });
4550
+ continue;
4551
+ }
4552
+ namedAccepted.push(item);
4553
+ }
4554
+ if (!blobEntries.length) {
4547
4555
  return { accepted: namedAccepted, rejected: namedRejected };
4548
4556
  }
4549
- const { accepted, rejected } = filterFilesByAcceptAndMaxSize(blobFiles, accept, maxFileSize);
4557
+ const { accepted, rejected } = filterFilesByAcceptAndMaxSize(blobEntries.map((entry) => entry.file), accept, maxFileSize);
4550
4558
  const acceptedSet = new Set(accepted);
4551
- const acceptedItems = blobItems.filter((item) => acceptedSet.has(fileFromListItem(item)));
4559
+ const acceptedItems = blobEntries
4560
+ .filter((entry) => acceptedSet.has(entry.file))
4561
+ .map((entry) => entry.item);
4552
4562
  return {
4553
4563
  accepted: [...namedAccepted, ...acceptedItems],
4554
4564
  rejected: [...namedRejected, ...rejected],
@@ -4564,9 +4574,7 @@ const AXPFileChooserHookKeys = {
4564
4574
 
4565
4575
  //#region ---- File chooser tokens ----
4566
4576
  /**
4567
-
4568
4577
  * Multi token for file chooser providers (system disk, drive, external systems).
4569
-
4570
4578
  */
4571
4579
  const AXP_FILE_CHOOSER_PROVIDERS = new InjectionToken('AXP_FILE_CHOOSER_PROVIDERS');
4572
4580
  //#endregion
@@ -4578,14 +4586,37 @@ const AXP_SYSTEM_FILE_CHOOSER_PROVIDER = {
4578
4586
  order: 1,
4579
4587
  choose: async (context) => {
4580
4588
  const fileService = inject(AXFileService);
4589
+ const documentRef = inject(DOCUMENT);
4590
+ const translateService = inject(AXTranslationService);
4591
+ const toastService = inject(AXToastService);
4581
4592
  const multiple = Boolean(context.options['multiple']);
4582
4593
  const fileType = context.options['fileType'];
4583
- const accept = context.options['accept'];
4584
- const files = await fileService.choose({
4585
- fileType,
4586
- accept,
4587
- multiple,
4588
- });
4594
+ const acceptOption = context.options['accept'];
4595
+ const maxFileSizeOption = context.options['maxFileSize'];
4596
+ const maxFileSize = typeof maxFileSizeOption === 'number' ? maxFileSizeOption : 0;
4597
+ const accept = fileType
4598
+ ? (acceptOption ?? (await fileService.getAcceptAttribute(fileType)))
4599
+ : (acceptOption ?? '');
4600
+ const picked = await openSystemFileDialog(documentRef, { accept, multiple });
4601
+ if (!picked.length) {
4602
+ return undefined;
4603
+ }
4604
+ let files = picked;
4605
+ if (fileType) {
4606
+ const validation = await fileService.validateMany(picked, fileType);
4607
+ files = validation.accepted;
4608
+ if (validation.rejected.length > 0) {
4609
+ const rejected = validation.rejected.map((entry) => ({
4610
+ file: entry.file,
4611
+ reason: catalogRejectionReason(entry.errors, maxFileSize),
4612
+ }));
4613
+ await notifyFileAcceptRejections(rejected, {
4614
+ translateService,
4615
+ toastService,
4616
+ maxFileSize,
4617
+ });
4618
+ }
4619
+ }
4589
4620
  if (!files.length) {
4590
4621
  return undefined;
4591
4622
  }
@@ -4602,9 +4633,13 @@ const AXP_SYSTEM_FILE_CHOOSER_PROVIDER = {
4602
4633
  if (!multiple) {
4603
4634
  return next.slice(0, 1);
4604
4635
  }
4605
- return [...context.items, ...next];
4636
+ return [...(context.items ?? []), ...next];
4606
4637
  },
4607
4638
  };
4639
+ function catalogRejectionReason(errors, maxFileSize) {
4640
+ const failedForSize = errors.some((error) => (error.rule ?? '').toLowerCase().includes('size'));
4641
+ return failedForSize && maxFileSize > 0 ? 'size' : 'type';
4642
+ }
4608
4643
  //#endregion
4609
4644
 
4610
4645
  //#region ---- File chooser platform settings ----
@@ -4960,13 +4995,18 @@ class AXPFileChooserService {
4960
4995
  if (!items?.length) {
4961
4996
  return items;
4962
4997
  }
4998
+ const previousItems = new Set(context.items ?? []);
4999
+ const incoming = items.filter((item) => !previousItems.has(item));
5000
+ if (incoming.length === 0) {
5001
+ return items;
5002
+ }
4963
5003
  const maxFileSize = defaultTo(context.options['maxFileSize'], 0);
4964
5004
  const promptZipOnMultiple = (await this.settingsService.get(AXPFileChooserSettings.PromptZipOnMultiple)) ?? false;
4965
5005
  const validationOptions = {
4966
5006
  ...context.options,
4967
5007
  accept: resolveFileChooserAccept(context.options['accept'], promptZipOnMultiple),
4968
5008
  };
4969
- const { accepted, rejected } = validateFileChooserItems(items, validationOptions);
5009
+ const { accepted, rejected } = validateFileChooserItems(incoming, validationOptions);
4970
5010
  if (rejected.length > 0) {
4971
5011
  await notifyFileAcceptRejections(rejected, {
4972
5012
  translateService: this.translateService,
@@ -4974,7 +5014,14 @@ class AXPFileChooserService {
4974
5014
  maxFileSize,
4975
5015
  });
4976
5016
  }
4977
- return accepted.length > 0 ? accepted : undefined;
5017
+ if (accepted.length === 0) {
5018
+ return undefined;
5019
+ }
5020
+ if (previousItems.size === 0) {
5021
+ return accepted;
5022
+ }
5023
+ const acceptedIncoming = new Set(accepted);
5024
+ return items.filter((item) => previousItems.has(item) || acceptedIncoming.has(item));
4978
5025
  }
4979
5026
  async runAfterChosenHook(providerKey, context, items) {
4980
5027
  if (!items?.length) {
@@ -5004,6 +5051,8 @@ class AXPFileChooserDirective {
5004
5051
  constructor() {
5005
5052
  //#region ---- Services & Dependencies ----
5006
5053
  this.chooserService = inject(AXPFileChooserService);
5054
+ this.toastService = inject(AXToastService);
5055
+ this.translateService = inject(AXTranslationService);
5007
5056
  this.elementRef = inject(ElementRef);
5008
5057
  this.envInjector = inject(EnvironmentInjector);
5009
5058
  this.appRef = inject(ApplicationRef);
@@ -5064,10 +5113,16 @@ class AXPFileChooserDirective {
5064
5113
  ...this.context(),
5065
5114
  items: this.items(),
5066
5115
  });
5067
- if (result) {
5116
+ if (result?.length) {
5068
5117
  this.items.set(result);
5069
5118
  }
5070
5119
  }
5120
+ catch (error) {
5121
+ console.error('[AXPFileChooserDirective] choose failed', error);
5122
+ const title = await this.translateService.translateAsync('@general:messages.generic.error.title');
5123
+ const content = await this.translateService.translateAsync('@layout:components.file-chooser.messages.choose-failed');
5124
+ this.toastService.show({ color: 'danger', title, content });
5125
+ }
5071
5126
  finally {
5072
5127
  this.busy.set(false);
5073
5128
  }
@@ -5101,30 +5156,38 @@ async function compressImageFile(file, quality = 0.7, maxDimension = 1920) {
5101
5156
  if (!file.type.startsWith('image/') || file.type === 'image/svg+xml') {
5102
5157
  return file;
5103
5158
  }
5104
- const bitmap = await createImageBitmap(file);
5105
- const scale = Math.min(1, maxDimension / Math.max(bitmap.width, bitmap.height));
5106
- const width = Math.max(1, Math.round(bitmap.width * scale));
5107
- const height = Math.max(1, Math.round(bitmap.height * scale));
5108
- const canvas = document.createElement('canvas');
5109
- canvas.width = width;
5110
- canvas.height = height;
5111
- const context = canvas.getContext('2d');
5112
- if (!context) {
5113
- bitmap.close();
5114
- return file;
5159
+ let bitmap;
5160
+ try {
5161
+ bitmap = await createImageBitmap(file);
5162
+ const longestSide = Math.max(bitmap.width, bitmap.height);
5163
+ const scale = longestSide > 0 ? Math.min(1, maxDimension / longestSide) : 1;
5164
+ const width = Math.max(1, Math.round(bitmap.width * scale));
5165
+ const height = Math.max(1, Math.round(bitmap.height * scale));
5166
+ const canvas = document.createElement('canvas');
5167
+ canvas.width = width;
5168
+ canvas.height = height;
5169
+ const context = canvas.getContext('2d');
5170
+ if (!context) {
5171
+ return file;
5172
+ }
5173
+ context.drawImage(bitmap, 0, 0, width, height);
5174
+ const mimeType = file.type === 'image/png' ? 'image/png' : 'image/jpeg';
5175
+ const blob = await new Promise((resolve) => {
5176
+ canvas.toBlob(resolve, mimeType, quality);
5177
+ });
5178
+ if (!blob || blob.size >= file.size) {
5179
+ return file;
5180
+ }
5181
+ const extension = mimeType === 'image/png' ? 'png' : 'jpg';
5182
+ const baseName = file.name.includes('.') ? file.name.slice(0, file.name.lastIndexOf('.')) : file.name;
5183
+ return new File([blob], `${baseName}.${extension}`, { type: mimeType, lastModified: Date.now() });
5115
5184
  }
5116
- context.drawImage(bitmap, 0, 0, width, height);
5117
- bitmap.close();
5118
- const mimeType = file.type === 'image/png' ? 'image/png' : 'image/jpeg';
5119
- const blob = await new Promise((resolve) => {
5120
- canvas.toBlob(resolve, mimeType, quality);
5121
- });
5122
- if (!blob || blob.size >= file.size) {
5185
+ catch {
5123
5186
  return file;
5124
5187
  }
5125
- const extension = mimeType === 'image/png' ? 'png' : 'jpg';
5126
- const baseName = file.name.includes('.') ? file.name.slice(0, file.name.lastIndexOf('.')) : file.name;
5127
- return new File([blob], `${baseName}.${extension}`, { type: mimeType, lastModified: Date.now() });
5188
+ finally {
5189
+ bitmap?.close();
5190
+ }
5128
5191
  }
5129
5192
  /**
5130
5193
  * Builds a store-only ZIP archive (no compression) from the given files.
@@ -5136,9 +5199,10 @@ async function createZipArchive(files, archiveName = 'archive.zip') {
5136
5199
  })));
5137
5200
  const chunks = [];
5138
5201
  const centralDirectory = [];
5202
+ const usedNames = new Set();
5139
5203
  let offset = 0;
5140
5204
  for (const entry of entries) {
5141
- const nameBytes = new TextEncoder().encode(entry.name);
5205
+ const nameBytes = new TextEncoder().encode(uniqueZipEntryName(entry.name, usedNames));
5142
5206
  const crc = crc32(entry.data);
5143
5207
  const localHeader = buildLocalFileHeader(nameBytes, entry.data.length, crc);
5144
5208
  chunks.push(localHeader, nameBytes, entry.data);
@@ -5157,10 +5221,32 @@ async function createZipArchive(files, archiveName = 'archive.zip') {
5157
5221
  }
5158
5222
  return new File([archive], archiveName, { type: 'application/zip', lastModified: Date.now() });
5159
5223
  }
5224
+ const ZIP_VERSION_NEEDED = 20;
5225
+ const ZIP_UTF8_FLAG = 0x0800;
5226
+ function uniqueZipEntryName(name, used) {
5227
+ const baseName = name || 'file';
5228
+ if (!used.has(baseName)) {
5229
+ used.add(baseName);
5230
+ return baseName;
5231
+ }
5232
+ const dot = baseName.lastIndexOf('.');
5233
+ const stem = dot > 0 ? baseName.slice(0, dot) : baseName;
5234
+ const extension = dot > 0 ? baseName.slice(dot) : '';
5235
+ let index = 2;
5236
+ let candidate = `${stem} (${index})${extension}`;
5237
+ while (used.has(candidate)) {
5238
+ index += 1;
5239
+ candidate = `${stem} (${index})${extension}`;
5240
+ }
5241
+ used.add(candidate);
5242
+ return candidate;
5243
+ }
5160
5244
  function buildLocalFileHeader(nameBytes, size, crc) {
5161
5245
  const header = new Uint8Array(30);
5162
5246
  const view = new DataView(header.buffer);
5163
5247
  view.setUint32(0, 0x04034b50, true);
5248
+ view.setUint16(4, ZIP_VERSION_NEEDED, true);
5249
+ view.setUint16(6, ZIP_UTF8_FLAG, true);
5164
5250
  view.setUint16(8, 0, true);
5165
5251
  view.setUint16(10, 0, true);
5166
5252
  view.setUint32(14, crc, true);
@@ -5174,6 +5260,9 @@ function buildCentralDirectoryHeader(nameBytes, size, crc, offset) {
5174
5260
  const header = new Uint8Array(46);
5175
5261
  const view = new DataView(header.buffer);
5176
5262
  view.setUint32(0, 0x02014b50, true);
5263
+ view.setUint16(4, ZIP_VERSION_NEEDED, true);
5264
+ view.setUint16(6, ZIP_VERSION_NEEDED, true);
5265
+ view.setUint16(8, ZIP_UTF8_FLAG, true);
5177
5266
  view.setUint16(10, 0, true);
5178
5267
  view.setUint16(12, 0, true);
5179
5268
  view.setUint32(16, crc, true);
@@ -5783,21 +5872,44 @@ const AXP_SYSTEM_FILE_UPLOADER_PROVIDER = {
5783
5872
  icon: 'fa-light fa-file-arrow-up',
5784
5873
  order: 1,
5785
5874
  upload: async (context) => {
5875
+ const fileStorage = inject(AXPFileStorageService);
5876
+ const translateService = inject(AXTranslationService);
5877
+ const toastService = inject(AXToastService);
5786
5878
  const multiple = Boolean(context.options['multiple']);
5787
- const maxFileSize = defaultTo(context.options['maxFileSize'], 10 * 1024 * 1024);
5879
+ const maxFileSizeOption = context.options['maxFileSize'];
5880
+ // Omitted maxFileSize keeps the historical 10 MB cap. Zero or negative means no limit.
5881
+ const maxFileSize = typeof maxFileSizeOption === 'number' ? maxFileSizeOption : 10 * 1024 * 1024;
5788
5882
  const refId = defaultTo(context.options['refId'], 'temp');
5789
5883
  const refType = defaultTo(context.options['refType'], 'file-uploader');
5790
5884
  const category = defaultTo(context.options['category'], 'attachment');
5791
- const chosen = context.chosen.filter((item) => (item.size ?? 0) <= maxFileSize &&
5792
- item.source?.kind === 'blob' &&
5793
- item.source.value instanceof File);
5794
- if (isEmpty(chosen)) {
5885
+ const chosen = Array.isArray(context.chosen) ? context.chosen : [];
5886
+ const rejected = [];
5887
+ const uploadable = [];
5888
+ for (const item of chosen) {
5889
+ const file = resolveChooserItemFile(item);
5890
+ if (!file) {
5891
+ continue;
5892
+ }
5893
+ const comparableSize = Math.max(item.size ?? 0, file.size);
5894
+ if (maxFileSize > 0 && comparableSize > maxFileSize) {
5895
+ rejected.push({ file, reason: 'size' });
5896
+ continue;
5897
+ }
5898
+ uploadable.push({ item, file });
5899
+ }
5900
+ if (rejected.length > 0) {
5901
+ await notifyFileAcceptRejections(rejected, {
5902
+ translateService,
5903
+ toastService,
5904
+ maxFileSize,
5905
+ });
5906
+ }
5907
+ const queue = multiple ? uploadable : uploadable.slice(0, 1);
5908
+ if (queue.length === 0) {
5795
5909
  return undefined;
5796
5910
  }
5797
- const fileStorage = inject(AXPFileStorageService);
5798
5911
  const uploaded = [];
5799
- for (const item of chosen) {
5800
- const file = item.source.value;
5912
+ for (const { item, file } of queue) {
5801
5913
  const info = await fileStorage.save({
5802
5914
  file,
5803
5915
  name: item.name,
@@ -5820,7 +5932,7 @@ const AXP_SYSTEM_FILE_UPLOADER_PROVIDER = {
5820
5932
  if (!multiple) {
5821
5933
  return uploaded.slice(0, 1);
5822
5934
  }
5823
- return [...context.items, ...uploaded];
5935
+ return [...(context.items ?? []), ...uploaded];
5824
5936
  },
5825
5937
  };
5826
5938
  //#endregion
@@ -5898,6 +6010,8 @@ class AXPFileUploaderDirective {
5898
6010
  constructor() {
5899
6011
  //#region ---- Services & Dependencies ----
5900
6012
  this.uploaderService = inject(AXPFileUploaderService);
6013
+ this.toastService = inject(AXToastService);
6014
+ this.translateService = inject(AXTranslationService);
5901
6015
  this.elementRef = inject(ElementRef);
5902
6016
  this.envInjector = inject(EnvironmentInjector);
5903
6017
  this.appRef = inject(ApplicationRef);
@@ -5962,6 +6076,12 @@ class AXPFileUploaderDirective {
5962
6076
  this.uploaded.set(result);
5963
6077
  }
5964
6078
  }
6079
+ catch (error) {
6080
+ console.error('[AXPFileUploaderDirective] upload failed', error);
6081
+ const title = await this.translateService.translateAsync('@general:messages.generic.error.title');
6082
+ const content = await this.translateService.translateAsync('@general:widgets.file-uploader.messages.upload-failed');
6083
+ this.toastService.show({ color: 'danger', title, content });
6084
+ }
5965
6085
  finally {
5966
6086
  this.busy.set(false);
5967
6087
  }
@@ -15234,6 +15354,7 @@ class AXPUserAvatarComponent {
15234
15354
  this.sessionService = inject(AXPSessionService);
15235
15355
  this.fileStorage = inject(AXPFileStorageService);
15236
15356
  this.presenceService = inject(AXPUserPresenceService, { optional: true });
15357
+ this.userStatus = inject(AXPUserStatusFeatureService);
15237
15358
  this.resolveGeneration = 0;
15238
15359
  this.lastResolvedRef = null;
15239
15360
  this.userInfo = signal(null, /* @ts-ignore */
@@ -15281,13 +15402,14 @@ class AXPUserAvatarComponent {
15281
15402
  ...(ngDevMode ? [{ debugName: "isAway" }] : /* istanbul ignore next */ []));
15282
15403
  this.isBusy = computed(() => this.presenceStatus() === 'busy', /* @ts-ignore */
15283
15404
  ...(ngDevMode ? [{ debugName: "isBusy" }] : /* istanbul ignore next */ []));
15284
- this.showPresenceDot = computed(() => this.showPresence() &&
15405
+ this.showPresenceDot = computed(() => this.userStatus.enabled() &&
15406
+ this.showPresence() &&
15285
15407
  isWatchablePresenceUserId(String(this.userId() ?? '')) &&
15286
15408
  this.presenceStatus() !== null, /* @ts-ignore */
15287
15409
  ...(ngDevMode ? [{ debugName: "showPresenceDot" }] : /* istanbul ignore next */ []));
15288
15410
  effect((onCleanup) => {
15289
15411
  const id = String(this.userId() ?? '').trim();
15290
- const showPresence = this.showPresence();
15412
+ const showPresence = this.showPresence() && this.userStatus.enabled();
15291
15413
  void this.displayName();
15292
15414
  void this.displayAvatar();
15293
15415
  if (!id) {
@@ -15553,6 +15675,7 @@ class AXPUserCardComponent {
15553
15675
  //#region ----- Services & Dependencies -----
15554
15676
  this.avatarService = inject(AXPUserAvatarService);
15555
15677
  this.presenceService = inject(AXPUserPresenceService, { optional: true });
15678
+ this.userStatus = inject(AXPUserStatusFeatureService);
15556
15679
  this.formatService = inject(AXFormatService);
15557
15680
  this.settingsService = inject(AXPSettingsService);
15558
15681
  this.translation = inject(AXTranslationService);
@@ -15609,7 +15732,7 @@ class AXPUserCardComponent {
15609
15732
  }
15610
15733
  }, /* @ts-ignore */
15611
15734
  ...(ngDevMode ? [{ debugName: "presenceLabelKey" }] : /* istanbul ignore next */ []));
15612
- this.showPresence = computed(() => isWatchablePresenceUserId(this.userId()), /* @ts-ignore */
15735
+ this.showPresence = computed(() => this.userStatus.enabled() && isWatchablePresenceUserId(this.userId()), /* @ts-ignore */
15613
15736
  ...(ngDevMode ? [{ debugName: "showPresence" }] : /* istanbul ignore next */ []));
15614
15737
  this.tooltipDisabled = computed(() => !this.tooltipText(), /* @ts-ignore */
15615
15738
  ...(ngDevMode ? [{ debugName: "tooltipDisabled" }] : /* istanbul ignore next */ []));
@@ -15637,7 +15760,7 @@ class AXPUserCardComponent {
15637
15760
  this.subscriptions.add(this.avatarService.getUserInfo$(userId).subscribe((data) => {
15638
15761
  this.identity.set(data);
15639
15762
  }));
15640
- if (this.presenceService && isWatchablePresenceUserId(userId)) {
15763
+ if (this.userStatus.enabled() && this.presenceService && isWatchablePresenceUserId(userId)) {
15641
15764
  this.presenceService.watch(userId);
15642
15765
  this.watchedUserId = userId;
15643
15766
  this.presence.set(this.presenceService.get(userId) ?? { userId, status: 'offline' });
@@ -17019,5 +17142,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
17019
17142
  * Generated bundle index. Do not edit.
17020
17143
  */
17021
17144
 
17022
- export { AXPActivityLogComponent, AXPAvatarComponent, AXPCategoryTreeComponent, AXPColorChooserComponent, AXPColorPalettePickerComponent, AXPColumnItemListComponent, AXPCompareViewComponent, AXPConditionBuilderComponent, AXPConditionBuilderConditionComponent, AXPDataSelectorComponent, AXPDataSelectorService, AXPDragDropListComponent, AXPEntityListStylingDialogService, AXPEntityListStylingPopupComponent, AXPExpressionFieldDefinitions, AXPFileChooserCompressImagesHook, AXPFileChooserDirective, AXPFileChooserHookKeys, AXPFileChooserService, AXPFileChooserZipFilesHook, AXPFileUploaderDirective, AXPFileUploaderHookKeys, AXPFileUploaderService, AXPFileViewerComponent, AXPFileViewerFallbackContentComponent, AXPFileViewerService, AXPImageEditorPopupComponent, AXPImageEditorService, AXPInfiniteScrollDirective, AXPItemConfiguratorComponent, AXPLayoutFloatingZoomBarComponent, AXPLayoutSideDetailPanelComponent, AXPLayoutSideDetailPanelSectionDirective, AXPLocalDataSourceEditorDialogService, AXPMarkdownTemplateDirective, AXPMarkdownViewerComponent, AXPMenuBadgeHelper, AXPMenuCustomizerComponent, AXPMenuCustomizerService, AXPOutcomeResultsViewerComponent, AXPPageComponentRegistryService, AXPPreloadFiltersComponent, AXPPropertyViewerComponent, AXPPropertyViewerPopupComponent, AXPPropertyViewerService, AXPQueryColumnsComponent, AXPQueryFiltersComponent, AXPQuerySortsComponent, AXPQueryViewSaveButtonComponent, AXPQueryViewSaveDialogService, AXPQueryViewTabsComponent, AXPQueryViewsComponent, AXPRepeaterRowsLayoutComponent, AXPResourceAppointmentBoardProvider, AXPResourceAppointmentComponent, AXPResourceAppointmentService, AXPSectionItemsBuilderComponent, AXPSignatureEditorService, AXPSpreadsheetComponent, AXPStandardSectionItemsBuilderComponent, AXPStopwatchComponent, AXPTableColumnsEditorComponent, AXPTableColumnsEditorPopupComponent, AXPTableColumnsEditorService, AXPTableDataEditorComponent, AXPTableDataEditorPopupComponent, AXPTableDataEditorService, AXPTaskBadgeDirective, AXPTaskBadgeProvider, AXPTaskBadgeService, AXPTemplateViewerComponent, AXPTemplateViewerService, AXPTextCommandColumnComponent, AXPThemeLayoutActionsComponent, AXPThemeLayoutBlockComponent, AXPThemeLayoutContainerComponent, AXPThemeLayoutEndSideComponent, AXPThemeLayoutFooterComponent, AXPThemeLayoutHeaderComponent, AXPThemeLayoutListComponent, AXPThemeLayoutListItemComponent, AXPThemeLayoutListItemsGroupComponent, AXPThemeLayoutPageHeaderComponent, AXPThemeLayoutPagePrimaryActionsComponent, AXPThemeLayoutPageSecondaryActionsComponent, AXPThemeLayoutSectionComponent, AXPThemeLayoutStartSideComponent, AXPThemeLayoutToolbarComponent, AXPUserAvatarComponent, AXPUserAvatarService, AXPUserCardComponent, AXPUserCardDirective, AXPUserCardService, AXPVirtualKeypadComponent, AXPWidgetFieldConfiguratorComponent, AXPWidgetItemComponent, AXPWidgetPropertyViewerComponent, AXPWidgetPropertyViewerPopupComponent, AXPWidgetPropertyViewerService, AXP_EXPRESSION_LOGIC_DEFINITIONS, AXP_EXPRESSION_OPERATION_DEFINITIONS, AXP_FILE_CHOOSER_DEFAULT_ZIP_ARCHIVE_NAME, AXP_FILE_CHOOSER_HOOK_PROVIDERS, AXP_FILE_CHOOSER_OPTION_KEYS, AXP_FILE_CHOOSER_PROVIDERS, AXP_FILE_UPLOADER_PROVIDERS, AXP_IMAGE_FILE_CHOOSER_ACCEPT, AXP_INFINITE_SCROLL_DEFAULT_ROOT_MARGIN, AXP_MENU_CUSTOMIZER_SERVICE, AXP_PAGE_COMPONENT_PROVIDER, AXP_PAGE_LAYOUT_ELEMENT_ID, AXP_PROFILE_PHOTO_GRAVATAR_SOURCE_KEY, AXP_RESOURCE_APPOINTMENT_PROVIDER, AXP_SIGNATURE_PROVIDER, AXP_SPREADSHEET_COLUMN_WIDGET_TYPES, AXP_SYSTEM_FILE_CHOOSER_PROVIDER, AXP_SYSTEM_FILE_UPLOADER_PROVIDER, AXP_TASK_BADGE_PROVIDERS, AXP_USER_AVATAR_PROVIDER, PROPERTY_VIEWER_EXPRESSION_EDITOR_MIN_LINES, SPREADSHEET_COLUMN_NAME_PATH, SPREADSHEET_COLUMN_TITLE_PATH, STANDARD_SECTION_ITEMS_SECTION_TABS, USER_CARD_HOVER_OPEN_DELAY_MS, USER_CARD_ITEMS_HOOK, USER_CARD_ITEMS_SKELETON_DELAY_MS, asSpreadsheetColumnTitle, buildEntityListStylingRulesLayout, buildFileChooserOptions, buildGravatarAvatarUrl, buildPropertyViewerInitialContextFromProperties, buildPropertyViewerTabsFromProperties, buildTableColumnsEditorLayout, compressImageFile, createAttachedFileProviderMenu, createZipArchive, fetchGravatarImageFile, fileListItemToFileViewerItem, fileListItemToImageFile, fileMatchesAccept, fileNameMatchesAccept, filterFileProvidersByContext, filterFilesByAcceptAndMaxSize, formatAcceptForDisplay, formatMaxFileSizeForDisplay, getFieldDefinitions, getLogicDefinition, getOperationDefinition, isPropertyBindingExpressionFormValue, isUnrestrictedFileAccept, mapFileListToViewerItems, md5Hex, mergeInfiniteScrollPage, mergeObjectsReplacingArrays, normalizeFileViewerBoundValue, normalizeSpreadsheetColumnName, notifyFileAcceptRejections, observeInfiniteScroll, pickImageFileViaFileChooser, pickProfilePhotoImageFile, preparePropertyForViewer, preparePropertyViewerTabs, provideFileChooserHooks, readSpreadsheetColumnIdentity, readSpreadsheetColumnWidth, registerFieldDefinitions, resolveExcludedFileProviderKeys, resolveFileChooserAccept, resolveFileChooserExtension, resolveFileListItemUrl, resolveFileUploaderEmptyStateDescription, resolveInfiniteScrollRoot, sortUserCardActions, sortUserCardRows, spreadsheetColumnIdentityProperties, toSpreadsheetColumnWidget, validateFileChooserItems, visibleUserCardActions, withValidationsOnEditorNode };
17145
+ export { AXPActivityLogComponent, AXPAvatarComponent, AXPCategoryTreeComponent, AXPColorChooserComponent, AXPColorPalettePickerComponent, AXPColumnItemListComponent, AXPCompareViewComponent, AXPConditionBuilderComponent, AXPConditionBuilderConditionComponent, AXPDataSelectorComponent, AXPDataSelectorService, AXPDragDropListComponent, AXPEntityListStylingDialogService, AXPEntityListStylingPopupComponent, AXPExpressionFieldDefinitions, AXPFileChooserCompressImagesHook, AXPFileChooserDirective, AXPFileChooserHookKeys, AXPFileChooserService, AXPFileChooserZipFilesHook, AXPFileUploaderDirective, AXPFileUploaderHookKeys, AXPFileUploaderService, AXPFileViewerComponent, AXPFileViewerFallbackContentComponent, AXPFileViewerService, AXPImageEditorPopupComponent, AXPImageEditorService, AXPInfiniteScrollDirective, AXPItemConfiguratorComponent, AXPLayoutFloatingZoomBarComponent, AXPLayoutSideDetailPanelComponent, AXPLayoutSideDetailPanelSectionDirective, AXPLocalDataSourceEditorDialogService, AXPMarkdownTemplateDirective, AXPMarkdownViewerComponent, AXPMenuBadgeHelper, AXPMenuCustomizerComponent, AXPMenuCustomizerService, AXPOutcomeResultsViewerComponent, AXPPageComponentRegistryService, AXPPreloadFiltersComponent, AXPPropertyViewerComponent, AXPPropertyViewerPopupComponent, AXPPropertyViewerService, AXPQueryColumnsComponent, AXPQueryFiltersComponent, AXPQuerySortsComponent, AXPQueryViewSaveButtonComponent, AXPQueryViewSaveDialogService, AXPQueryViewTabsComponent, AXPQueryViewsComponent, AXPRepeaterRowsLayoutComponent, AXPResourceAppointmentBoardProvider, AXPResourceAppointmentComponent, AXPResourceAppointmentService, AXPSectionItemsBuilderComponent, AXPSignatureEditorService, AXPSpreadsheetComponent, AXPStandardSectionItemsBuilderComponent, AXPStopwatchComponent, AXPTableColumnsEditorComponent, AXPTableColumnsEditorPopupComponent, AXPTableColumnsEditorService, AXPTableDataEditorComponent, AXPTableDataEditorPopupComponent, AXPTableDataEditorService, AXPTaskBadgeDirective, AXPTaskBadgeProvider, AXPTaskBadgeService, AXPTemplateViewerComponent, AXPTemplateViewerService, AXPTextCommandColumnComponent, AXPThemeLayoutActionsComponent, AXPThemeLayoutBlockComponent, AXPThemeLayoutContainerComponent, AXPThemeLayoutEndSideComponent, AXPThemeLayoutFooterComponent, AXPThemeLayoutHeaderComponent, AXPThemeLayoutListComponent, AXPThemeLayoutListItemComponent, AXPThemeLayoutListItemsGroupComponent, AXPThemeLayoutPageHeaderComponent, AXPThemeLayoutPagePrimaryActionsComponent, AXPThemeLayoutPageSecondaryActionsComponent, AXPThemeLayoutSectionComponent, AXPThemeLayoutStartSideComponent, AXPThemeLayoutToolbarComponent, AXPUserAvatarComponent, AXPUserAvatarService, AXPUserCardComponent, AXPUserCardDirective, AXPUserCardService, AXPVirtualKeypadComponent, AXPWidgetFieldConfiguratorComponent, AXPWidgetItemComponent, AXPWidgetPropertyViewerComponent, AXPWidgetPropertyViewerPopupComponent, AXPWidgetPropertyViewerService, AXP_EXPRESSION_LOGIC_DEFINITIONS, AXP_EXPRESSION_OPERATION_DEFINITIONS, AXP_FILE_CHOOSER_DEFAULT_ZIP_ARCHIVE_NAME, AXP_FILE_CHOOSER_HOOK_PROVIDERS, AXP_FILE_CHOOSER_OPTION_KEYS, AXP_FILE_CHOOSER_PROVIDERS, AXP_FILE_UPLOADER_PROVIDERS, AXP_IMAGE_FILE_CHOOSER_ACCEPT, AXP_INFINITE_SCROLL_DEFAULT_ROOT_MARGIN, AXP_MENU_CUSTOMIZER_SERVICE, AXP_PAGE_COMPONENT_PROVIDER, AXP_PAGE_LAYOUT_ELEMENT_ID, AXP_PROFILE_PHOTO_GRAVATAR_SOURCE_KEY, AXP_RESOURCE_APPOINTMENT_PROVIDER, AXP_SIGNATURE_PROVIDER, AXP_SPREADSHEET_COLUMN_WIDGET_TYPES, AXP_SYSTEM_FILE_CHOOSER_PROVIDER, AXP_SYSTEM_FILE_UPLOADER_PROVIDER, AXP_TASK_BADGE_PROVIDERS, AXP_USER_AVATAR_PROVIDER, PROPERTY_VIEWER_EXPRESSION_EDITOR_MIN_LINES, SPREADSHEET_COLUMN_NAME_PATH, SPREADSHEET_COLUMN_TITLE_PATH, STANDARD_SECTION_ITEMS_SECTION_TABS, USER_CARD_HOVER_OPEN_DELAY_MS, USER_CARD_ITEMS_HOOK, USER_CARD_ITEMS_SKELETON_DELAY_MS, asSpreadsheetColumnTitle, buildEntityListStylingRulesLayout, buildFileChooserOptions, buildGravatarAvatarUrl, buildPropertyViewerInitialContextFromProperties, buildPropertyViewerTabsFromProperties, buildTableColumnsEditorLayout, compressImageFile, createAttachedFileProviderMenu, createZipArchive, fetchGravatarImageFile, fileListItemToFileViewerItem, fileListItemToImageFile, fileMatchesAccept, fileNameMatchesAccept, filterFileProvidersByContext, filterFilesByAcceptAndMaxSize, formatAcceptForDisplay, formatMaxFileSizeForDisplay, getFieldDefinitions, getLogicDefinition, getOperationDefinition, isPropertyBindingExpressionFormValue, isUnrestrictedFileAccept, mapFileListToViewerItems, md5Hex, mergeInfiniteScrollPage, mergeObjectsReplacingArrays, normalizeFileViewerBoundValue, normalizeSpreadsheetColumnName, notifyFileAcceptRejections, observeInfiniteScroll, pickImageFileViaFileChooser, pickProfilePhotoImageFile, preparePropertyForViewer, preparePropertyViewerTabs, provideFileChooserHooks, readSpreadsheetColumnIdentity, readSpreadsheetColumnWidth, registerFieldDefinitions, resolveChooserItemFile, resolveExcludedFileProviderKeys, resolveFileChooserAccept, resolveFileChooserExtension, resolveFileListItemUrl, resolveFileUploaderEmptyStateDescription, resolveInfiniteScrollRoot, sortUserCardActions, sortUserCardRows, spreadsheetColumnIdentityProperties, toSpreadsheetColumnWidget, validateFileChooserItems, visibleUserCardActions, withValidationsOnEditorNode };
17023
17146
  //# sourceMappingURL=acorex-platform-framework-client-layout-components.mjs.map