eru-grid 0.0.70 → 0.0.71

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.
@@ -109,7 +109,7 @@ const INHERITED_FIELD_KEYS = [
109
109
  'start_value', 'end_value', 'emoji_value', 'is_perc',
110
110
  // Attachment constraints and destination
111
111
  'max_files', 'allowed_file_types', 'max_file_size',
112
- 'storage_name', 'folder_name', 'default_upload',
112
+ 'storage_name', 'folder_name', 'default_upload', 'show_delete',
113
113
  // Phone
114
114
  'default_country',
115
115
  // Cardinality and picker behaviour
@@ -11012,6 +11012,7 @@ class AttachmentComponent {
11012
11012
  eruGridStore = input(null, ...(ngDevMode ? [{ debugName: "eruGridStore" }] : []));
11013
11013
  // Pending view-file requests (fileName -> requestKey)
11014
11014
  pendingViewRequests = new Map();
11015
+ pending_upload_requests = new Map();
11015
11016
  // Outputs
11016
11017
  valueChange = new EventEmitter();
11017
11018
  blur = new EventEmitter();
@@ -11066,10 +11067,18 @@ class AttachmentComponent {
11066
11067
  // Read dynamicData() first to register the reactive dependency,
11067
11068
  // otherwise the effect won't re-run when studio sets the response.
11068
11069
  const dynamicDataMap = store.dynamicData();
11069
- if (this.pendingViewRequests.size === 0)
11070
- return;
11071
11070
  if (!dynamicDataMap)
11072
11071
  return;
11072
+ this.pending_upload_requests.forEach((requestKey, fileName) => {
11073
+ if (!dynamicDataMap.has(requestKey))
11074
+ return;
11075
+ const data = dynamicDataMap.get(requestKey);
11076
+ this.pending_upload_requests.delete(fileName);
11077
+ store.removeDynamicData(requestKey);
11078
+ untracked(() => this.applyUploadResponse(fileName, data));
11079
+ });
11080
+ if (this.pendingViewRequests.size === 0)
11081
+ return;
11073
11082
  this.pendingViewRequests.forEach((requestKey, fileName) => {
11074
11083
  if (dynamicDataMap.has(requestKey)) {
11075
11084
  const data = dynamicDataMap.get(requestKey);
@@ -11240,6 +11249,37 @@ class AttachmentComponent {
11240
11249
  folder_name: cfg.folderName ?? '',
11241
11250
  default_upload: cfg.defaultUpload !== false,
11242
11251
  });
11252
+ if (cfg.defaultUpload === false)
11253
+ return;
11254
+ const store = this.eruGridStore();
11255
+ if (!store)
11256
+ return;
11257
+ const requestKey = `ds_upload_file_grid:${fileName}`;
11258
+ const request = { key: requestKey, file: base64String, file_name: fileName };
11259
+ if (cfg.storageName)
11260
+ request.storage_name = cfg.storageName;
11261
+ if (cfg.folderName)
11262
+ request.folder_name = cfg.folderName;
11263
+ this.pending_upload_requests.set(fileName, requestKey);
11264
+ store.setDynamicDataRequest(request);
11265
+ }
11266
+ applyUploadResponse(fileName, data) {
11267
+ const files = this.currentValue();
11268
+ if (!data || data.error) {
11269
+ const remaining = files.filter(f => f !== fileName);
11270
+ this.currentValue.set(remaining);
11271
+ this.valueChange.emit(remaining.length > 0 ? remaining : null);
11272
+ this.rejectFile(`${fileName}: ${data?.error || 'upload failed'}`);
11273
+ this.cdr.markForCheck();
11274
+ return;
11275
+ }
11276
+ const stored_name = String(data.file_name || '').trim();
11277
+ if (!stored_name || stored_name === fileName)
11278
+ return;
11279
+ const updated = files.map(f => f === fileName ? stored_name : f);
11280
+ this.currentValue.set(updated);
11281
+ this.valueChange.emit(updated);
11282
+ this.cdr.markForCheck();
11243
11283
  }
11244
11284
  viewFile(file, event) {
11245
11285
  if (event) {
@@ -11253,7 +11293,13 @@ class AttachmentComponent {
11253
11293
  return;
11254
11294
  const requestKey = `ds_view_file_grid:${file}`;
11255
11295
  this.pendingViewRequests.set(file, requestKey);
11256
- store.setDynamicDataRequest(requestKey);
11296
+ const cfg = this.config();
11297
+ const request = { key: requestKey };
11298
+ if (cfg.storageName)
11299
+ request.storage_name = cfg.storageName;
11300
+ if (cfg.folderName)
11301
+ request.folder_name = cfg.folderName;
11302
+ store.setDynamicDataRequest(request);
11257
11303
  }
11258
11304
  openBase64InNewTab(base64, fileType, fileName) {
11259
11305
  try {
@@ -11296,7 +11342,7 @@ class AttachmentComponent {
11296
11342
  return file;
11297
11343
  }
11298
11344
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: AttachmentComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
11299
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: AttachmentComponent, isStandalone: true, selector: "eru-attachment", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, isEditable: { classPropertyName: "isEditable", publicName: "isEditable", isSignal: true, isRequired: false, transformFunction: null }, isActive: { classPropertyName: "isActive", publicName: "isActive", isSignal: true, isRequired: false, transformFunction: null }, isDrillable: { classPropertyName: "isDrillable", publicName: "isDrillable", isSignal: true, isRequired: false, transformFunction: null }, columnWidth: { classPropertyName: "columnWidth", publicName: "columnWidth", isSignal: true, isRequired: false, transformFunction: null }, eruGridStore: { classPropertyName: "eruGridStore", publicName: "eruGridStore", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange", blur: "blur", focus: "focus", drilldownClick: "drilldownClick", editModeChange: "editModeChange", fileAdded: "fileAdded", fileUpload: "fileUpload", fileDeleted: "fileDeleted", fileViewed: "fileViewed" }, viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }], ngImport: i0, template: "<div class=\"attachment-overlay-container\">\n <div \n class=\"attachment-cell-wrapper\"\n cdkOverlayOrigin \n #attachmentTrigger=\"cdkOverlayOrigin\"\n [class.attachment-display-editable]=\"isEditable() && !isActive()\"\n [class.attachment-display-viewable]=\"!isEditable() && hasFiles()\"\n (dblclick)=\"onActivate()\">\n @if(hasFiles()) {\n <div class=\"cell-attachment-container\">\n @if (isDrillable() && !isActive()) {\n <span class=\"drillable-value\" (click)=\"onDrillableClick($event)\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path fill-rule=\"evenodd\" clip-rule=\"evenodd\"\n d=\"M19 12.5C19 14.985 15.866 17 12 17C8.134 17 5 14.985 5 12.5C5 10.015 8.134 8 12 8C15.866 8 19 10.015 19 12.5Z\"\n stroke=\"#7C818C\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path fill-rule=\"evenodd\" clip-rule=\"evenodd\"\n d=\"M13.75 12.5001C13.7716 13.1394 13.4429 13.7397 12.8925 14.0657C12.3422 14.3918 11.6578 14.3918 11.1075 14.0657C10.5571 13.7397 10.2284 13.1394 10.25 12.5001C10.2284 11.8608 10.5571 11.2606 11.1075 10.9345C11.6578 10.6084 12.3422 10.6084 12.8925 10.9345C13.4429 11.2606 13.7716 11.8608 13.75 12.5001V12.5001Z\"\n stroke=\"#7C818C\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </span>\n } @else {\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path fill-rule=\"evenodd\" clip-rule=\"evenodd\"\n d=\"M19 12.5C19 14.985 15.866 17 12 17C8.134 17 5 14.985 5 12.5C5 10.015 8.134 8 12 8C15.866 8 19 10.015 19 12.5Z\"\n stroke=\"#7C818C\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path fill-rule=\"evenodd\" clip-rule=\"evenodd\"\n d=\"M13.75 12.5001C13.7716 13.1394 13.4429 13.7397 12.8925 14.0657C12.3422 14.3918 11.6578 14.3918 11.1075 14.0657C10.5571 13.7397 10.2284 13.1394 10.25 12.5001C10.2284 11.8608 10.5571 11.2606 11.1075 10.9345C11.6578 10.6084 12.3422 10.6084 12.8925 10.9345C13.4429 11.2606 13.7716 11.8608 13.75 12.5001V12.5001Z\"\n stroke=\"#7C818C\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n }\n </div>\n } @else {\n <div class=\"cell-attachment-container\">\n @if (isDrillable() && !isActive()) {\n <span class=\"drillable-value\" (click)=\"onDrillableClick($event)\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M14.67 11.053L10.68 15.315C10.3416 15.6932 9.85986 15.9119 9.35236 15.9178C8.84487 15.9237 8.35821 15.7162 8.01104 15.346C7.24412 14.5454 7.257 13.2788 8.04004 12.494L13.399 6.763C13.9902 6.10491 14.8315 5.72677 15.7161 5.72163C16.6006 5.71649 17.4463 6.08482 18.045 6.736C19.3222 8.14736 19.3131 10.2995 18.024 11.7L12.342 17.771C11.5334 18.5827 10.4265 19.0261 9.28113 18.9971C8.13575 18.9682 7.05268 18.4695 6.28604 17.618C4.5337 15.6414 4.57705 12.6549 6.38604 10.73L11.753 5\"\n stroke=\"#363B44\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </span>\n } @else {\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M14.67 11.053L10.68 15.315C10.3416 15.6932 9.85986 15.9119 9.35236 15.9178C8.84487 15.9237 8.35821 15.7162 8.01104 15.346C7.24412 14.5454 7.257 13.2788 8.04004 12.494L13.399 6.763C13.9902 6.10491 14.8315 5.72677 15.7161 5.72163C16.6006 5.71649 17.4463 6.08482 18.045 6.736C19.3222 8.14736 19.3131 10.2995 18.024 11.7L12.342 17.771C11.5334 18.5827 10.4265 19.0261 9.28113 18.9971C8.13575 18.9682 7.05268 18.4695 6.28604 17.618C4.5337 15.6414 4.57705 12.6549 6.38604 10.73L11.753 5\"\n stroke=\"#363B44\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n }\n </div>\n }\n </div>\n\n <ng-template \n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"attachmentTrigger\"\n [cdkConnectedOverlayOpen]=\"isOverlayOpen() && (isActive() || !isEditable())\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n [cdkConnectedOverlayBackdropClass]=\"'attachment-backdrop'\"\n (backdropClick)=\"onOverlayBackdropClick()\"\n (detach)=\"closeOverlay()\">\n <div \n class=\"attachment-menu-overlay\" \n [style.width.px]=\"columnWidth() || config().columnWidth || 300\" \n [style.min-width.px]=\"300\"\n (click)=\"onOverlayClick($event)\">\n <div class=\"attachment-container\" (click)=\"$event.stopPropagation()\">\n @if (rejectionMessage()) {\n <div class=\"attachment-rejection\" role=\"alert\">{{ rejectionMessage() }}</div>\n }\n @if (isEditable()) {\n <!-- Header Section -->\n <div class=\"attachment-header\">\n <span class=\"attachment-title\">Add or Drag files</span>\n <button\n mat-flat-button\n (click)=\"onUploadClick(); $event.stopPropagation()\"\n class=\"attachment-upload-btn\"\n [disabled]=\"config().disabled\">\n Upload\n </button>\n </div>\n\n <!-- Drop zone -->\n <div\n class=\"attachment-drop-zone\"\n (drop)=\"onFileDrop($event)\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (paste)=\"onPaste($event)\"\n (click)=\"onUploadClick(); $event.stopPropagation()\"\n [class.dragging]=\"isDragging()\">\n <div class=\"attachment-drop-content\">\n <div class=\"attachment-drop-icon\">+</div>\n <div class=\"attachment-drop-text\">\n <div class=\"primary-text\">Click to upload or drag files here</div>\n <div class=\"secondary-text\">Support multiple files</div>\n </div>\n </div>\n </div>\n\n <!-- Hidden file input -->\n <input\n #fileInput\n type=\"file\"\n multiple\n (change)=\"onFileInputChange($event)\"\n style=\"display: none;\">\n } @else {\n <!-- Read-only header -->\n <div class=\"attachment-header\">\n <span class=\"attachment-title\">Attachments</span>\n </div>\n }\n\n <!-- File list -->\n @if (hasFiles()) {\n <div class=\"attachment-file-list\">\n @for (file of currentValue(); track $index) {\n <div class=\"attachment-file-item\">\n <div class=\"file-info\">\n <mat-icon class=\"file-status-icon done-icon\">check_circle</mat-icon>\n <span class=\"file-name\">{{ getFileName(file) }}</span>\n </div>\n <div class=\"file-actions\">\n <button\n mat-icon-button\n class=\"file-action-btn\"\n (click)=\"viewFile(file, $event)\"\n title=\"View\"\n type=\"button\">\n <mat-icon>visibility</mat-icon>\n </button>\n @if (isEditable()) {\n <button\n mat-icon-button\n class=\"file-action-btn\"\n (click)=\"deleteFile(file, $event)\"\n title=\"Delete\"\n type=\"button\">\n <mat-icon>delete_outline</mat-icon>\n </button>\n }\n </div>\n </div>\n }\n </div>\n }\n </div>\n </div>\n </ng-template>\n</div>\n\n", styles: [".attachment-rejection{padding:8px 10px;margin-bottom:8px;border-radius:6px;background:#fef2f2;color:var(--cell-color, #b91c1c);font-size:var(--cell-font-size, 12px);line-height:1.4}.attachment-overlay-container{width:100%;height:100%}.attachment-cell-wrapper{display:flex;align-items:center;justify-content:center;padding:4px;min-height:32px;cursor:default}.attachment-cell-wrapper.attachment-display-editable{cursor:pointer}.attachment-cell-wrapper.attachment-display-editable:hover{background-color:#0000000a}.attachment-cell-wrapper.attachment-display-viewable{cursor:pointer}.attachment-cell-wrapper.attachment-display-viewable:hover{background-color:#0000000a}.cell-attachment-container{display:flex;align-items:center;justify-content:center;width:100%;height:100%}.drillable-value{display:flex;align-items:center;justify-content:center;cursor:pointer}.drillable-value svg{text-decoration:none}.drillable-value:hover{opacity:.8}.attachment-backdrop{background:transparent}.attachment-menu-overlay{background:#fff;border-radius:8px;box-shadow:0 4px 12px #00000026;overflow:hidden;position:relative;z-index:1000}.attachment-container{padding:16px}.attachment-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}.attachment-title{font-size:var(--cell-font-size, var(--grid-font-size-body, 12px));font-weight:var(--cell-font-weight, 500);color:var(--cell-color, var(--grid-on-surface, #1c1b1f))}.attachment-upload-btn{font-size:var(--cell-font-size, var(--grid-font-size-body, 12px))!important;min-width:50px}.attachment-drop-zone{border:2px dashed var(--grid-outline-variant, #cac4d0);border-radius:8px;padding:40px 20px;text-align:center;cursor:pointer;transition:all .3s ease;background:var(--grid-surface-variant, #e7e0ec);margin:16px 0}.attachment-drop-zone:hover{border-color:var(--grid-primary, #6750a4);background:var(--grid-surface-container, #f3edf7)}.attachment-drop-zone.dragging{border-color:var(--grid-primary, #6750a4);background:var(--grid-surface-container, #f3edf7);transform:scale(1.01)}.attachment-drop-content{display:flex;flex-direction:column;align-items:center;gap:12px}.attachment-drop-icon{font-size:var(--cell-font-size, 48px);color:var(--cell-color, var(--grid-primary, #6750a4));font-weight:var(--cell-font-weight, 300);line-height:1}.attachment-drop-text .primary-text{font-family:var(--grid-font-family, \"Poppins\");font-size:var(--cell-font-size, 14px);color:var(--cell-color, var(--grid-on-surface-variant, #49454f));font-weight:var(--cell-font-weight, 400);margin:0}.attachment-drop-text .secondary-text{font-family:var(--grid-font-family, \"Poppins\");font-size:var(--cell-font-size, 12px);color:var(--cell-color, var(--grid-on-surface-variant, #49454f));margin-top:4px;display:block}.attachment-file-list{display:block;margin-top:16px;max-height:300px;overflow-y:auto}.attachment-file-item{display:flex;justify-content:space-between;align-items:center;padding:8px 12px;border-radius:4px;margin-bottom:8px;background:var(--grid-surface-variant, #e7e0ec);transition:background-color .2s}.attachment-file-item:hover{background:var(--grid-surface-container, #f3edf7)}.file-info{display:flex;align-items:center;gap:8px;flex:1;min-width:0}.file-status-icon{font-size:var(--cell-font-size, 18px)!important;width:18px!important;height:18px!important;flex-shrink:0}.file-status-icon.done-icon{color:var(--cell-color, #22C55E)}.file-name{font-size:var(--cell-font-size, var(--grid-font-size-body, 12px));color:var(--cell-color, var(--grid-on-surface, #1c1b1f));overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.file-actions{display:flex;gap:8px;flex-shrink:0}.file-action-btn{width:28px!important;height:28px!important;padding:0!important;display:flex!important;align-items:center;justify-content:center}.file-action-btn .mat-icon{font-size:var(--cell-font-size, 18px);width:18px;height:18px;color:var(--cell-color, var(--grid-on-surface-variant, #49454f))}.file-action-btn:hover .mat-icon{color:var(--cell-color, var(--grid-on-surface, #1c1b1f))}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatInputModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i1$2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2$2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1$3.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i1$3.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
11345
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: AttachmentComponent, isStandalone: true, selector: "eru-attachment", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, isEditable: { classPropertyName: "isEditable", publicName: "isEditable", isSignal: true, isRequired: false, transformFunction: null }, isActive: { classPropertyName: "isActive", publicName: "isActive", isSignal: true, isRequired: false, transformFunction: null }, isDrillable: { classPropertyName: "isDrillable", publicName: "isDrillable", isSignal: true, isRequired: false, transformFunction: null }, columnWidth: { classPropertyName: "columnWidth", publicName: "columnWidth", isSignal: true, isRequired: false, transformFunction: null }, eruGridStore: { classPropertyName: "eruGridStore", publicName: "eruGridStore", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange", blur: "blur", focus: "focus", drilldownClick: "drilldownClick", editModeChange: "editModeChange", fileAdded: "fileAdded", fileUpload: "fileUpload", fileDeleted: "fileDeleted", fileViewed: "fileViewed" }, viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }], ngImport: i0, template: "<div class=\"attachment-overlay-container\">\n <div \n class=\"attachment-cell-wrapper\"\n cdkOverlayOrigin \n #attachmentTrigger=\"cdkOverlayOrigin\"\n [class.attachment-display-editable]=\"isEditable() && !isActive()\"\n [class.attachment-display-viewable]=\"!isEditable() && hasFiles()\"\n (dblclick)=\"onActivate()\">\n @if(hasFiles()) {\n <div class=\"cell-attachment-container\">\n @if (isDrillable() && !isActive()) {\n <span class=\"drillable-value\" (click)=\"onDrillableClick($event)\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path fill-rule=\"evenodd\" clip-rule=\"evenodd\"\n d=\"M19 12.5C19 14.985 15.866 17 12 17C8.134 17 5 14.985 5 12.5C5 10.015 8.134 8 12 8C15.866 8 19 10.015 19 12.5Z\"\n stroke=\"#7C818C\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path fill-rule=\"evenodd\" clip-rule=\"evenodd\"\n d=\"M13.75 12.5001C13.7716 13.1394 13.4429 13.7397 12.8925 14.0657C12.3422 14.3918 11.6578 14.3918 11.1075 14.0657C10.5571 13.7397 10.2284 13.1394 10.25 12.5001C10.2284 11.8608 10.5571 11.2606 11.1075 10.9345C11.6578 10.6084 12.3422 10.6084 12.8925 10.9345C13.4429 11.2606 13.7716 11.8608 13.75 12.5001V12.5001Z\"\n stroke=\"#7C818C\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </span>\n } @else {\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path fill-rule=\"evenodd\" clip-rule=\"evenodd\"\n d=\"M19 12.5C19 14.985 15.866 17 12 17C8.134 17 5 14.985 5 12.5C5 10.015 8.134 8 12 8C15.866 8 19 10.015 19 12.5Z\"\n stroke=\"#7C818C\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path fill-rule=\"evenodd\" clip-rule=\"evenodd\"\n d=\"M13.75 12.5001C13.7716 13.1394 13.4429 13.7397 12.8925 14.0657C12.3422 14.3918 11.6578 14.3918 11.1075 14.0657C10.5571 13.7397 10.2284 13.1394 10.25 12.5001C10.2284 11.8608 10.5571 11.2606 11.1075 10.9345C11.6578 10.6084 12.3422 10.6084 12.8925 10.9345C13.4429 11.2606 13.7716 11.8608 13.75 12.5001V12.5001Z\"\n stroke=\"#7C818C\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n }\n </div>\n } @else {\n <div class=\"cell-attachment-container\">\n @if (isDrillable() && !isActive()) {\n <span class=\"drillable-value\" (click)=\"onDrillableClick($event)\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M14.67 11.053L10.68 15.315C10.3416 15.6932 9.85986 15.9119 9.35236 15.9178C8.84487 15.9237 8.35821 15.7162 8.01104 15.346C7.24412 14.5454 7.257 13.2788 8.04004 12.494L13.399 6.763C13.9902 6.10491 14.8315 5.72677 15.7161 5.72163C16.6006 5.71649 17.4463 6.08482 18.045 6.736C19.3222 8.14736 19.3131 10.2995 18.024 11.7L12.342 17.771C11.5334 18.5827 10.4265 19.0261 9.28113 18.9971C8.13575 18.9682 7.05268 18.4695 6.28604 17.618C4.5337 15.6414 4.57705 12.6549 6.38604 10.73L11.753 5\"\n stroke=\"#363B44\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </span>\n } @else {\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M14.67 11.053L10.68 15.315C10.3416 15.6932 9.85986 15.9119 9.35236 15.9178C8.84487 15.9237 8.35821 15.7162 8.01104 15.346C7.24412 14.5454 7.257 13.2788 8.04004 12.494L13.399 6.763C13.9902 6.10491 14.8315 5.72677 15.7161 5.72163C16.6006 5.71649 17.4463 6.08482 18.045 6.736C19.3222 8.14736 19.3131 10.2995 18.024 11.7L12.342 17.771C11.5334 18.5827 10.4265 19.0261 9.28113 18.9971C8.13575 18.9682 7.05268 18.4695 6.28604 17.618C4.5337 15.6414 4.57705 12.6549 6.38604 10.73L11.753 5\"\n stroke=\"#363B44\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n }\n </div>\n }\n </div>\n\n <ng-template \n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"attachmentTrigger\"\n [cdkConnectedOverlayOpen]=\"isOverlayOpen() && (isActive() || !isEditable())\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n [cdkConnectedOverlayBackdropClass]=\"'attachment-backdrop'\"\n (backdropClick)=\"onOverlayBackdropClick()\"\n (detach)=\"closeOverlay()\">\n <div \n class=\"attachment-menu-overlay\" \n [style.width.px]=\"columnWidth() || config().columnWidth || 300\" \n [style.min-width.px]=\"300\"\n (click)=\"onOverlayClick($event)\">\n <div class=\"attachment-container\" (click)=\"$event.stopPropagation()\">\n @if (rejectionMessage()) {\n <div class=\"attachment-rejection\" role=\"alert\">{{ rejectionMessage() }}</div>\n }\n @if (isEditable()) {\n <!-- Header Section -->\n <div class=\"attachment-header\">\n <span class=\"attachment-title\">Add or Drag files</span>\n <button\n mat-flat-button\n (click)=\"onUploadClick(); $event.stopPropagation()\"\n class=\"attachment-upload-btn\"\n [disabled]=\"config().disabled\">\n Upload\n </button>\n </div>\n\n <!-- Drop zone -->\n <div\n class=\"attachment-drop-zone\"\n (drop)=\"onFileDrop($event)\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (paste)=\"onPaste($event)\"\n (click)=\"onUploadClick(); $event.stopPropagation()\"\n [class.dragging]=\"isDragging()\">\n <div class=\"attachment-drop-content\">\n <div class=\"attachment-drop-icon\">+</div>\n <div class=\"attachment-drop-text\">\n <div class=\"primary-text\">Click to upload or drag files here</div>\n <div class=\"secondary-text\">Support multiple files</div>\n </div>\n </div>\n </div>\n\n <!-- Hidden file input -->\n <input\n #fileInput\n type=\"file\"\n multiple\n (change)=\"onFileInputChange($event)\"\n style=\"display: none;\">\n } @else {\n <!-- Read-only header -->\n <div class=\"attachment-header\">\n <span class=\"attachment-title\">Attachments</span>\n </div>\n }\n\n <!-- File list -->\n @if (hasFiles()) {\n <div class=\"attachment-file-list\">\n @for (file of currentValue(); track $index) {\n <div class=\"attachment-file-item\">\n <div class=\"file-info\">\n <mat-icon class=\"file-status-icon done-icon\">check_circle</mat-icon>\n <span class=\"file-name\">{{ getFileName(file) }}</span>\n </div>\n <div class=\"file-actions\">\n <button\n mat-icon-button\n class=\"file-action-btn\"\n (click)=\"viewFile(file, $event)\"\n title=\"View\"\n type=\"button\">\n <mat-icon>visibility</mat-icon>\n </button>\n @if (isEditable() && config().showDelete !== false) {\n <button\n mat-icon-button\n class=\"file-action-btn\"\n (click)=\"deleteFile(file, $event)\"\n title=\"Delete\"\n type=\"button\">\n <mat-icon>delete_outline</mat-icon>\n </button>\n }\n </div>\n </div>\n }\n </div>\n }\n </div>\n </div>\n </ng-template>\n</div>\n\n", styles: [".attachment-rejection{padding:8px 10px;margin-bottom:8px;border-radius:6px;background:#fef2f2;color:var(--cell-color, #b91c1c);font-size:var(--cell-font-size, 12px);line-height:1.4}.attachment-overlay-container{width:100%;height:100%}.attachment-cell-wrapper{display:flex;align-items:center;justify-content:center;padding:4px;min-height:32px;cursor:default}.attachment-cell-wrapper.attachment-display-editable{cursor:pointer}.attachment-cell-wrapper.attachment-display-editable:hover{background-color:#0000000a}.attachment-cell-wrapper.attachment-display-viewable{cursor:pointer}.attachment-cell-wrapper.attachment-display-viewable:hover{background-color:#0000000a}.cell-attachment-container{display:flex;align-items:center;justify-content:center;width:100%;height:100%}.drillable-value{display:flex;align-items:center;justify-content:center;cursor:pointer}.drillable-value svg{text-decoration:none}.drillable-value:hover{opacity:.8}.attachment-backdrop{background:transparent}.attachment-menu-overlay{background:#fff;border-radius:8px;box-shadow:0 4px 12px #00000026;overflow:hidden;position:relative;z-index:1000}.attachment-container{padding:16px}.attachment-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}.attachment-title{font-size:var(--cell-font-size, var(--grid-font-size-body, 12px));font-weight:var(--cell-font-weight, 500);color:var(--cell-color, var(--grid-on-surface, #1c1b1f))}.attachment-upload-btn{font-size:var(--cell-font-size, var(--grid-font-size-body, 12px))!important;min-width:50px}.attachment-drop-zone{border:2px dashed var(--grid-outline-variant, #cac4d0);border-radius:8px;padding:40px 20px;text-align:center;cursor:pointer;transition:all .3s ease;background:var(--grid-surface-variant, #e7e0ec);margin:16px 0}.attachment-drop-zone:hover{border-color:var(--grid-primary, #6750a4);background:var(--grid-surface-container, #f3edf7)}.attachment-drop-zone.dragging{border-color:var(--grid-primary, #6750a4);background:var(--grid-surface-container, #f3edf7);transform:scale(1.01)}.attachment-drop-content{display:flex;flex-direction:column;align-items:center;gap:12px}.attachment-drop-icon{font-size:var(--cell-font-size, 48px);color:var(--cell-color, var(--grid-primary, #6750a4));font-weight:var(--cell-font-weight, 300);line-height:1}.attachment-drop-text .primary-text{font-family:var(--grid-font-family, \"Poppins\");font-size:var(--cell-font-size, 14px);color:var(--cell-color, var(--grid-on-surface-variant, #49454f));font-weight:var(--cell-font-weight, 400);margin:0}.attachment-drop-text .secondary-text{font-family:var(--grid-font-family, \"Poppins\");font-size:var(--cell-font-size, 12px);color:var(--cell-color, var(--grid-on-surface-variant, #49454f));margin-top:4px;display:block}.attachment-file-list{display:block;margin-top:16px;max-height:300px;overflow-y:auto}.attachment-file-item{display:flex;justify-content:space-between;align-items:center;padding:8px 12px;border-radius:4px;margin-bottom:8px;background:var(--grid-surface-variant, #e7e0ec);transition:background-color .2s}.attachment-file-item:hover{background:var(--grid-surface-container, #f3edf7)}.file-info{display:flex;align-items:center;gap:8px;flex:1;min-width:0}.file-status-icon{font-size:var(--cell-font-size, 18px)!important;width:18px!important;height:18px!important;flex-shrink:0}.file-status-icon.done-icon{color:var(--cell-color, #22C55E)}.file-name{font-size:var(--cell-font-size, var(--grid-font-size-body, 12px));color:var(--cell-color, var(--grid-on-surface, #1c1b1f));overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.file-actions{display:flex;gap:8px;flex-shrink:0}.file-action-btn{width:28px!important;height:28px!important;padding:0!important;display:flex!important;align-items:center;justify-content:center}.file-action-btn .mat-icon{font-size:var(--cell-font-size, 18px);width:18px;height:18px;color:var(--cell-color, var(--grid-on-surface-variant, #49454f))}.file-action-btn:hover .mat-icon{color:var(--cell-color, var(--grid-on-surface, #1c1b1f))}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatInputModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i1$2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2$2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1$3.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i1$3.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
11300
11346
  }
11301
11347
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: AttachmentComponent, decorators: [{
11302
11348
  type: Component,
@@ -11307,7 +11353,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
11307
11353
  MatButtonModule,
11308
11354
  MatIconModule,
11309
11355
  OverlayModule
11310
- ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div class=\"attachment-overlay-container\">\n <div \n class=\"attachment-cell-wrapper\"\n cdkOverlayOrigin \n #attachmentTrigger=\"cdkOverlayOrigin\"\n [class.attachment-display-editable]=\"isEditable() && !isActive()\"\n [class.attachment-display-viewable]=\"!isEditable() && hasFiles()\"\n (dblclick)=\"onActivate()\">\n @if(hasFiles()) {\n <div class=\"cell-attachment-container\">\n @if (isDrillable() && !isActive()) {\n <span class=\"drillable-value\" (click)=\"onDrillableClick($event)\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path fill-rule=\"evenodd\" clip-rule=\"evenodd\"\n d=\"M19 12.5C19 14.985 15.866 17 12 17C8.134 17 5 14.985 5 12.5C5 10.015 8.134 8 12 8C15.866 8 19 10.015 19 12.5Z\"\n stroke=\"#7C818C\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path fill-rule=\"evenodd\" clip-rule=\"evenodd\"\n d=\"M13.75 12.5001C13.7716 13.1394 13.4429 13.7397 12.8925 14.0657C12.3422 14.3918 11.6578 14.3918 11.1075 14.0657C10.5571 13.7397 10.2284 13.1394 10.25 12.5001C10.2284 11.8608 10.5571 11.2606 11.1075 10.9345C11.6578 10.6084 12.3422 10.6084 12.8925 10.9345C13.4429 11.2606 13.7716 11.8608 13.75 12.5001V12.5001Z\"\n stroke=\"#7C818C\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </span>\n } @else {\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path fill-rule=\"evenodd\" clip-rule=\"evenodd\"\n d=\"M19 12.5C19 14.985 15.866 17 12 17C8.134 17 5 14.985 5 12.5C5 10.015 8.134 8 12 8C15.866 8 19 10.015 19 12.5Z\"\n stroke=\"#7C818C\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path fill-rule=\"evenodd\" clip-rule=\"evenodd\"\n d=\"M13.75 12.5001C13.7716 13.1394 13.4429 13.7397 12.8925 14.0657C12.3422 14.3918 11.6578 14.3918 11.1075 14.0657C10.5571 13.7397 10.2284 13.1394 10.25 12.5001C10.2284 11.8608 10.5571 11.2606 11.1075 10.9345C11.6578 10.6084 12.3422 10.6084 12.8925 10.9345C13.4429 11.2606 13.7716 11.8608 13.75 12.5001V12.5001Z\"\n stroke=\"#7C818C\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n }\n </div>\n } @else {\n <div class=\"cell-attachment-container\">\n @if (isDrillable() && !isActive()) {\n <span class=\"drillable-value\" (click)=\"onDrillableClick($event)\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M14.67 11.053L10.68 15.315C10.3416 15.6932 9.85986 15.9119 9.35236 15.9178C8.84487 15.9237 8.35821 15.7162 8.01104 15.346C7.24412 14.5454 7.257 13.2788 8.04004 12.494L13.399 6.763C13.9902 6.10491 14.8315 5.72677 15.7161 5.72163C16.6006 5.71649 17.4463 6.08482 18.045 6.736C19.3222 8.14736 19.3131 10.2995 18.024 11.7L12.342 17.771C11.5334 18.5827 10.4265 19.0261 9.28113 18.9971C8.13575 18.9682 7.05268 18.4695 6.28604 17.618C4.5337 15.6414 4.57705 12.6549 6.38604 10.73L11.753 5\"\n stroke=\"#363B44\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </span>\n } @else {\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M14.67 11.053L10.68 15.315C10.3416 15.6932 9.85986 15.9119 9.35236 15.9178C8.84487 15.9237 8.35821 15.7162 8.01104 15.346C7.24412 14.5454 7.257 13.2788 8.04004 12.494L13.399 6.763C13.9902 6.10491 14.8315 5.72677 15.7161 5.72163C16.6006 5.71649 17.4463 6.08482 18.045 6.736C19.3222 8.14736 19.3131 10.2995 18.024 11.7L12.342 17.771C11.5334 18.5827 10.4265 19.0261 9.28113 18.9971C8.13575 18.9682 7.05268 18.4695 6.28604 17.618C4.5337 15.6414 4.57705 12.6549 6.38604 10.73L11.753 5\"\n stroke=\"#363B44\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n }\n </div>\n }\n </div>\n\n <ng-template \n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"attachmentTrigger\"\n [cdkConnectedOverlayOpen]=\"isOverlayOpen() && (isActive() || !isEditable())\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n [cdkConnectedOverlayBackdropClass]=\"'attachment-backdrop'\"\n (backdropClick)=\"onOverlayBackdropClick()\"\n (detach)=\"closeOverlay()\">\n <div \n class=\"attachment-menu-overlay\" \n [style.width.px]=\"columnWidth() || config().columnWidth || 300\" \n [style.min-width.px]=\"300\"\n (click)=\"onOverlayClick($event)\">\n <div class=\"attachment-container\" (click)=\"$event.stopPropagation()\">\n @if (rejectionMessage()) {\n <div class=\"attachment-rejection\" role=\"alert\">{{ rejectionMessage() }}</div>\n }\n @if (isEditable()) {\n <!-- Header Section -->\n <div class=\"attachment-header\">\n <span class=\"attachment-title\">Add or Drag files</span>\n <button\n mat-flat-button\n (click)=\"onUploadClick(); $event.stopPropagation()\"\n class=\"attachment-upload-btn\"\n [disabled]=\"config().disabled\">\n Upload\n </button>\n </div>\n\n <!-- Drop zone -->\n <div\n class=\"attachment-drop-zone\"\n (drop)=\"onFileDrop($event)\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (paste)=\"onPaste($event)\"\n (click)=\"onUploadClick(); $event.stopPropagation()\"\n [class.dragging]=\"isDragging()\">\n <div class=\"attachment-drop-content\">\n <div class=\"attachment-drop-icon\">+</div>\n <div class=\"attachment-drop-text\">\n <div class=\"primary-text\">Click to upload or drag files here</div>\n <div class=\"secondary-text\">Support multiple files</div>\n </div>\n </div>\n </div>\n\n <!-- Hidden file input -->\n <input\n #fileInput\n type=\"file\"\n multiple\n (change)=\"onFileInputChange($event)\"\n style=\"display: none;\">\n } @else {\n <!-- Read-only header -->\n <div class=\"attachment-header\">\n <span class=\"attachment-title\">Attachments</span>\n </div>\n }\n\n <!-- File list -->\n @if (hasFiles()) {\n <div class=\"attachment-file-list\">\n @for (file of currentValue(); track $index) {\n <div class=\"attachment-file-item\">\n <div class=\"file-info\">\n <mat-icon class=\"file-status-icon done-icon\">check_circle</mat-icon>\n <span class=\"file-name\">{{ getFileName(file) }}</span>\n </div>\n <div class=\"file-actions\">\n <button\n mat-icon-button\n class=\"file-action-btn\"\n (click)=\"viewFile(file, $event)\"\n title=\"View\"\n type=\"button\">\n <mat-icon>visibility</mat-icon>\n </button>\n @if (isEditable()) {\n <button\n mat-icon-button\n class=\"file-action-btn\"\n (click)=\"deleteFile(file, $event)\"\n title=\"Delete\"\n type=\"button\">\n <mat-icon>delete_outline</mat-icon>\n </button>\n }\n </div>\n </div>\n }\n </div>\n }\n </div>\n </div>\n </ng-template>\n</div>\n\n", styles: [".attachment-rejection{padding:8px 10px;margin-bottom:8px;border-radius:6px;background:#fef2f2;color:var(--cell-color, #b91c1c);font-size:var(--cell-font-size, 12px);line-height:1.4}.attachment-overlay-container{width:100%;height:100%}.attachment-cell-wrapper{display:flex;align-items:center;justify-content:center;padding:4px;min-height:32px;cursor:default}.attachment-cell-wrapper.attachment-display-editable{cursor:pointer}.attachment-cell-wrapper.attachment-display-editable:hover{background-color:#0000000a}.attachment-cell-wrapper.attachment-display-viewable{cursor:pointer}.attachment-cell-wrapper.attachment-display-viewable:hover{background-color:#0000000a}.cell-attachment-container{display:flex;align-items:center;justify-content:center;width:100%;height:100%}.drillable-value{display:flex;align-items:center;justify-content:center;cursor:pointer}.drillable-value svg{text-decoration:none}.drillable-value:hover{opacity:.8}.attachment-backdrop{background:transparent}.attachment-menu-overlay{background:#fff;border-radius:8px;box-shadow:0 4px 12px #00000026;overflow:hidden;position:relative;z-index:1000}.attachment-container{padding:16px}.attachment-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}.attachment-title{font-size:var(--cell-font-size, var(--grid-font-size-body, 12px));font-weight:var(--cell-font-weight, 500);color:var(--cell-color, var(--grid-on-surface, #1c1b1f))}.attachment-upload-btn{font-size:var(--cell-font-size, var(--grid-font-size-body, 12px))!important;min-width:50px}.attachment-drop-zone{border:2px dashed var(--grid-outline-variant, #cac4d0);border-radius:8px;padding:40px 20px;text-align:center;cursor:pointer;transition:all .3s ease;background:var(--grid-surface-variant, #e7e0ec);margin:16px 0}.attachment-drop-zone:hover{border-color:var(--grid-primary, #6750a4);background:var(--grid-surface-container, #f3edf7)}.attachment-drop-zone.dragging{border-color:var(--grid-primary, #6750a4);background:var(--grid-surface-container, #f3edf7);transform:scale(1.01)}.attachment-drop-content{display:flex;flex-direction:column;align-items:center;gap:12px}.attachment-drop-icon{font-size:var(--cell-font-size, 48px);color:var(--cell-color, var(--grid-primary, #6750a4));font-weight:var(--cell-font-weight, 300);line-height:1}.attachment-drop-text .primary-text{font-family:var(--grid-font-family, \"Poppins\");font-size:var(--cell-font-size, 14px);color:var(--cell-color, var(--grid-on-surface-variant, #49454f));font-weight:var(--cell-font-weight, 400);margin:0}.attachment-drop-text .secondary-text{font-family:var(--grid-font-family, \"Poppins\");font-size:var(--cell-font-size, 12px);color:var(--cell-color, var(--grid-on-surface-variant, #49454f));margin-top:4px;display:block}.attachment-file-list{display:block;margin-top:16px;max-height:300px;overflow-y:auto}.attachment-file-item{display:flex;justify-content:space-between;align-items:center;padding:8px 12px;border-radius:4px;margin-bottom:8px;background:var(--grid-surface-variant, #e7e0ec);transition:background-color .2s}.attachment-file-item:hover{background:var(--grid-surface-container, #f3edf7)}.file-info{display:flex;align-items:center;gap:8px;flex:1;min-width:0}.file-status-icon{font-size:var(--cell-font-size, 18px)!important;width:18px!important;height:18px!important;flex-shrink:0}.file-status-icon.done-icon{color:var(--cell-color, #22C55E)}.file-name{font-size:var(--cell-font-size, var(--grid-font-size-body, 12px));color:var(--cell-color, var(--grid-on-surface, #1c1b1f));overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.file-actions{display:flex;gap:8px;flex-shrink:0}.file-action-btn{width:28px!important;height:28px!important;padding:0!important;display:flex!important;align-items:center;justify-content:center}.file-action-btn .mat-icon{font-size:var(--cell-font-size, 18px);width:18px;height:18px;color:var(--cell-color, var(--grid-on-surface-variant, #49454f))}.file-action-btn:hover .mat-icon{color:var(--cell-color, var(--grid-on-surface, #1c1b1f))}\n"] }]
11356
+ ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div class=\"attachment-overlay-container\">\n <div \n class=\"attachment-cell-wrapper\"\n cdkOverlayOrigin \n #attachmentTrigger=\"cdkOverlayOrigin\"\n [class.attachment-display-editable]=\"isEditable() && !isActive()\"\n [class.attachment-display-viewable]=\"!isEditable() && hasFiles()\"\n (dblclick)=\"onActivate()\">\n @if(hasFiles()) {\n <div class=\"cell-attachment-container\">\n @if (isDrillable() && !isActive()) {\n <span class=\"drillable-value\" (click)=\"onDrillableClick($event)\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path fill-rule=\"evenodd\" clip-rule=\"evenodd\"\n d=\"M19 12.5C19 14.985 15.866 17 12 17C8.134 17 5 14.985 5 12.5C5 10.015 8.134 8 12 8C15.866 8 19 10.015 19 12.5Z\"\n stroke=\"#7C818C\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path fill-rule=\"evenodd\" clip-rule=\"evenodd\"\n d=\"M13.75 12.5001C13.7716 13.1394 13.4429 13.7397 12.8925 14.0657C12.3422 14.3918 11.6578 14.3918 11.1075 14.0657C10.5571 13.7397 10.2284 13.1394 10.25 12.5001C10.2284 11.8608 10.5571 11.2606 11.1075 10.9345C11.6578 10.6084 12.3422 10.6084 12.8925 10.9345C13.4429 11.2606 13.7716 11.8608 13.75 12.5001V12.5001Z\"\n stroke=\"#7C818C\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </span>\n } @else {\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path fill-rule=\"evenodd\" clip-rule=\"evenodd\"\n d=\"M19 12.5C19 14.985 15.866 17 12 17C8.134 17 5 14.985 5 12.5C5 10.015 8.134 8 12 8C15.866 8 19 10.015 19 12.5Z\"\n stroke=\"#7C818C\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path fill-rule=\"evenodd\" clip-rule=\"evenodd\"\n d=\"M13.75 12.5001C13.7716 13.1394 13.4429 13.7397 12.8925 14.0657C12.3422 14.3918 11.6578 14.3918 11.1075 14.0657C10.5571 13.7397 10.2284 13.1394 10.25 12.5001C10.2284 11.8608 10.5571 11.2606 11.1075 10.9345C11.6578 10.6084 12.3422 10.6084 12.8925 10.9345C13.4429 11.2606 13.7716 11.8608 13.75 12.5001V12.5001Z\"\n stroke=\"#7C818C\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n }\n </div>\n } @else {\n <div class=\"cell-attachment-container\">\n @if (isDrillable() && !isActive()) {\n <span class=\"drillable-value\" (click)=\"onDrillableClick($event)\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M14.67 11.053L10.68 15.315C10.3416 15.6932 9.85986 15.9119 9.35236 15.9178C8.84487 15.9237 8.35821 15.7162 8.01104 15.346C7.24412 14.5454 7.257 13.2788 8.04004 12.494L13.399 6.763C13.9902 6.10491 14.8315 5.72677 15.7161 5.72163C16.6006 5.71649 17.4463 6.08482 18.045 6.736C19.3222 8.14736 19.3131 10.2995 18.024 11.7L12.342 17.771C11.5334 18.5827 10.4265 19.0261 9.28113 18.9971C8.13575 18.9682 7.05268 18.4695 6.28604 17.618C4.5337 15.6414 4.57705 12.6549 6.38604 10.73L11.753 5\"\n stroke=\"#363B44\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </span>\n } @else {\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M14.67 11.053L10.68 15.315C10.3416 15.6932 9.85986 15.9119 9.35236 15.9178C8.84487 15.9237 8.35821 15.7162 8.01104 15.346C7.24412 14.5454 7.257 13.2788 8.04004 12.494L13.399 6.763C13.9902 6.10491 14.8315 5.72677 15.7161 5.72163C16.6006 5.71649 17.4463 6.08482 18.045 6.736C19.3222 8.14736 19.3131 10.2995 18.024 11.7L12.342 17.771C11.5334 18.5827 10.4265 19.0261 9.28113 18.9971C8.13575 18.9682 7.05268 18.4695 6.28604 17.618C4.5337 15.6414 4.57705 12.6549 6.38604 10.73L11.753 5\"\n stroke=\"#363B44\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n }\n </div>\n }\n </div>\n\n <ng-template \n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"attachmentTrigger\"\n [cdkConnectedOverlayOpen]=\"isOverlayOpen() && (isActive() || !isEditable())\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n [cdkConnectedOverlayBackdropClass]=\"'attachment-backdrop'\"\n (backdropClick)=\"onOverlayBackdropClick()\"\n (detach)=\"closeOverlay()\">\n <div \n class=\"attachment-menu-overlay\" \n [style.width.px]=\"columnWidth() || config().columnWidth || 300\" \n [style.min-width.px]=\"300\"\n (click)=\"onOverlayClick($event)\">\n <div class=\"attachment-container\" (click)=\"$event.stopPropagation()\">\n @if (rejectionMessage()) {\n <div class=\"attachment-rejection\" role=\"alert\">{{ rejectionMessage() }}</div>\n }\n @if (isEditable()) {\n <!-- Header Section -->\n <div class=\"attachment-header\">\n <span class=\"attachment-title\">Add or Drag files</span>\n <button\n mat-flat-button\n (click)=\"onUploadClick(); $event.stopPropagation()\"\n class=\"attachment-upload-btn\"\n [disabled]=\"config().disabled\">\n Upload\n </button>\n </div>\n\n <!-- Drop zone -->\n <div\n class=\"attachment-drop-zone\"\n (drop)=\"onFileDrop($event)\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (paste)=\"onPaste($event)\"\n (click)=\"onUploadClick(); $event.stopPropagation()\"\n [class.dragging]=\"isDragging()\">\n <div class=\"attachment-drop-content\">\n <div class=\"attachment-drop-icon\">+</div>\n <div class=\"attachment-drop-text\">\n <div class=\"primary-text\">Click to upload or drag files here</div>\n <div class=\"secondary-text\">Support multiple files</div>\n </div>\n </div>\n </div>\n\n <!-- Hidden file input -->\n <input\n #fileInput\n type=\"file\"\n multiple\n (change)=\"onFileInputChange($event)\"\n style=\"display: none;\">\n } @else {\n <!-- Read-only header -->\n <div class=\"attachment-header\">\n <span class=\"attachment-title\">Attachments</span>\n </div>\n }\n\n <!-- File list -->\n @if (hasFiles()) {\n <div class=\"attachment-file-list\">\n @for (file of currentValue(); track $index) {\n <div class=\"attachment-file-item\">\n <div class=\"file-info\">\n <mat-icon class=\"file-status-icon done-icon\">check_circle</mat-icon>\n <span class=\"file-name\">{{ getFileName(file) }}</span>\n </div>\n <div class=\"file-actions\">\n <button\n mat-icon-button\n class=\"file-action-btn\"\n (click)=\"viewFile(file, $event)\"\n title=\"View\"\n type=\"button\">\n <mat-icon>visibility</mat-icon>\n </button>\n @if (isEditable() && config().showDelete !== false) {\n <button\n mat-icon-button\n class=\"file-action-btn\"\n (click)=\"deleteFile(file, $event)\"\n title=\"Delete\"\n type=\"button\">\n <mat-icon>delete_outline</mat-icon>\n </button>\n }\n </div>\n </div>\n }\n </div>\n }\n </div>\n </div>\n </ng-template>\n</div>\n\n", styles: [".attachment-rejection{padding:8px 10px;margin-bottom:8px;border-radius:6px;background:#fef2f2;color:var(--cell-color, #b91c1c);font-size:var(--cell-font-size, 12px);line-height:1.4}.attachment-overlay-container{width:100%;height:100%}.attachment-cell-wrapper{display:flex;align-items:center;justify-content:center;padding:4px;min-height:32px;cursor:default}.attachment-cell-wrapper.attachment-display-editable{cursor:pointer}.attachment-cell-wrapper.attachment-display-editable:hover{background-color:#0000000a}.attachment-cell-wrapper.attachment-display-viewable{cursor:pointer}.attachment-cell-wrapper.attachment-display-viewable:hover{background-color:#0000000a}.cell-attachment-container{display:flex;align-items:center;justify-content:center;width:100%;height:100%}.drillable-value{display:flex;align-items:center;justify-content:center;cursor:pointer}.drillable-value svg{text-decoration:none}.drillable-value:hover{opacity:.8}.attachment-backdrop{background:transparent}.attachment-menu-overlay{background:#fff;border-radius:8px;box-shadow:0 4px 12px #00000026;overflow:hidden;position:relative;z-index:1000}.attachment-container{padding:16px}.attachment-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}.attachment-title{font-size:var(--cell-font-size, var(--grid-font-size-body, 12px));font-weight:var(--cell-font-weight, 500);color:var(--cell-color, var(--grid-on-surface, #1c1b1f))}.attachment-upload-btn{font-size:var(--cell-font-size, var(--grid-font-size-body, 12px))!important;min-width:50px}.attachment-drop-zone{border:2px dashed var(--grid-outline-variant, #cac4d0);border-radius:8px;padding:40px 20px;text-align:center;cursor:pointer;transition:all .3s ease;background:var(--grid-surface-variant, #e7e0ec);margin:16px 0}.attachment-drop-zone:hover{border-color:var(--grid-primary, #6750a4);background:var(--grid-surface-container, #f3edf7)}.attachment-drop-zone.dragging{border-color:var(--grid-primary, #6750a4);background:var(--grid-surface-container, #f3edf7);transform:scale(1.01)}.attachment-drop-content{display:flex;flex-direction:column;align-items:center;gap:12px}.attachment-drop-icon{font-size:var(--cell-font-size, 48px);color:var(--cell-color, var(--grid-primary, #6750a4));font-weight:var(--cell-font-weight, 300);line-height:1}.attachment-drop-text .primary-text{font-family:var(--grid-font-family, \"Poppins\");font-size:var(--cell-font-size, 14px);color:var(--cell-color, var(--grid-on-surface-variant, #49454f));font-weight:var(--cell-font-weight, 400);margin:0}.attachment-drop-text .secondary-text{font-family:var(--grid-font-family, \"Poppins\");font-size:var(--cell-font-size, 12px);color:var(--cell-color, var(--grid-on-surface-variant, #49454f));margin-top:4px;display:block}.attachment-file-list{display:block;margin-top:16px;max-height:300px;overflow-y:auto}.attachment-file-item{display:flex;justify-content:space-between;align-items:center;padding:8px 12px;border-radius:4px;margin-bottom:8px;background:var(--grid-surface-variant, #e7e0ec);transition:background-color .2s}.attachment-file-item:hover{background:var(--grid-surface-container, #f3edf7)}.file-info{display:flex;align-items:center;gap:8px;flex:1;min-width:0}.file-status-icon{font-size:var(--cell-font-size, 18px)!important;width:18px!important;height:18px!important;flex-shrink:0}.file-status-icon.done-icon{color:var(--cell-color, #22C55E)}.file-name{font-size:var(--cell-font-size, var(--grid-font-size-body, 12px));color:var(--cell-color, var(--grid-on-surface, #1c1b1f));overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.file-actions{display:flex;gap:8px;flex-shrink:0}.file-action-btn{width:28px!important;height:28px!important;padding:0!important;display:flex!important;align-items:center;justify-content:center}.file-action-btn .mat-icon{font-size:var(--cell-font-size, 18px);width:18px;height:18px;color:var(--cell-color, var(--grid-on-surface-variant, #49454f))}.file-action-btn:hover .mat-icon{color:var(--cell-color, var(--grid-on-surface, #1c1b1f))}\n"] }]
11311
11357
  }], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], isEditable: [{ type: i0.Input, args: [{ isSignal: true, alias: "isEditable", required: false }] }], isActive: [{ type: i0.Input, args: [{ isSignal: true, alias: "isActive", required: false }] }], isDrillable: [{ type: i0.Input, args: [{ isSignal: true, alias: "isDrillable", required: false }] }], columnWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnWidth", required: false }] }], eruGridStore: [{ type: i0.Input, args: [{ isSignal: true, alias: "eruGridStore", required: false }] }], valueChange: [{
11312
11358
  type: Output
11313
11359
  }], blur: [{
@@ -11736,6 +11782,13 @@ class DataCellComponent {
11736
11782
  // Currency component configuration
11737
11783
  // Event handlers
11738
11784
  onValueChange(value) {
11785
+ if (!this.isActive() && this.columnDatatype() === 'attachment') {
11786
+ const previous = this.currentValue();
11787
+ this.currentValue.set(value);
11788
+ if (this.hasValueChanged(previous, value))
11789
+ this.notifyStoreOfValueChange(previous, value);
11790
+ return;
11791
+ }
11739
11792
  this.currentValue.set(value);
11740
11793
  // Some types need immediate validation feedback
11741
11794
  const typesNeedingValidation = ['textbox', 'email', 'textarea', 'website', 'location'];
@@ -12080,7 +12133,8 @@ class DataCellComponent {
12080
12133
  columnWidth: config?.column_width || this.currentColumnWidth(),
12081
12134
  storageName: config?.storage_name || '',
12082
12135
  folderName: this.resolvedFolderName(config?.folder_name),
12083
- defaultUpload: config?.default_upload !== false
12136
+ defaultUpload: config?.default_upload !== false,
12137
+ showDelete: config?.show_delete !== false
12084
12138
  };
12085
12139
  }, ...(ngDevMode ? [{ debugName: "getAttachmentConfig" }] : []));
12086
12140
  /**
@@ -13931,6 +13985,7 @@ const DATATYPE_FIELDS = {
13931
13985
  { key: 'default_upload', label: 'Default upload', control: 'checkbox', defaultValue: true },
13932
13986
  { key: 'storage_name', label: 'Storage name', control: 'text', showWhen: f => f.default_upload !== false },
13933
13987
  { key: 'folder_name', label: 'Folder from field', control: 'text', showWhen: f => f.default_upload !== false },
13988
+ { key: 'show_delete', label: 'Show delete', control: 'checkbox', defaultValue: true },
13934
13989
  ],
13935
13990
  phone: [{ key: 'default_country', label: 'Default country (ISO)', control: 'text' }],
13936
13991
  people: [