@meshmakers/shared-ui 3.3.530 → 3.3.550

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, signal, ViewChild, Input, Component, Injectable, NgZone, Pipe, EventEmitter, ChangeDetectorRef, Directive, Output, ChangeDetectionStrategy, InjectionToken, HostListener, ElementRef, forwardRef, computed, effect, makeEnvironmentProviders } from '@angular/core';
2
+ import { inject, signal, ViewChild, Input, Component, Injectable, NgZone, Pipe, EventEmitter, ChangeDetectorRef, Directive, Output, ChangeDetectionStrategy, InjectionToken, HostListener, TemplateRef, ContentChild, ElementRef, forwardRef, computed, effect, makeEnvironmentProviders } from '@angular/core';
3
3
  import * as i3$2 from '@progress/kendo-angular-dialog';
4
4
  import { DialogContentBase, DialogRef, DialogActionsComponent, DialogService, WindowRef, WindowService, WindowModule, WindowCloseResult, DialogModule } from '@progress/kendo-angular-dialog';
5
5
  import { NotificationService } from '@progress/kendo-angular-notification';
@@ -236,28 +236,29 @@ class ConfirmationWindowComponent extends DialogContentBase {
236
236
  }
237
237
  ngOnInit() {
238
238
  if (this.data) {
239
+ const labels = this.data.buttonLabels;
239
240
  if (this.data.dialogType === DialogType.OkCancel) {
240
- this.button1Text = 'OK';
241
+ this.button1Text = labels?.ok ?? 'OK';
241
242
  this.button1Result = ButtonTypes.Ok;
242
- this.button2Text = 'Cancel';
243
+ this.button2Text = labels?.cancel ?? 'Cancel';
243
244
  this.button2Result = ButtonTypes.Cancel;
244
245
  }
245
246
  else if (this.data.dialogType === DialogType.YesNoCancel) {
246
- this.button1Text = 'Yes';
247
+ this.button1Text = labels?.yes ?? 'Yes';
247
248
  this.button1Result = ButtonTypes.Yes;
248
- this.button2Text = 'No';
249
+ this.button2Text = labels?.no ?? 'No';
249
250
  this.button2Result = ButtonTypes.No;
250
- this.button3Text = 'Cancel';
251
+ this.button3Text = labels?.cancel ?? 'Cancel';
251
252
  this.button3Result = ButtonTypes.Cancel;
252
253
  }
253
254
  else if (this.data.dialogType === DialogType.Ok) {
254
- this.button1Text = 'OK';
255
+ this.button1Text = labels?.ok ?? 'OK';
255
256
  this.button1Result = ButtonTypes.Ok;
256
257
  }
257
258
  else {
258
- this.button1Text = 'Yes';
259
+ this.button1Text = labels?.yes ?? 'Yes';
259
260
  this.button1Result = ButtonTypes.Yes;
260
- this.button2Text = 'No';
261
+ this.button2Text = labels?.no ?? 'No';
261
262
  this.button2Result = ButtonTypes.No;
262
263
  }
263
264
  }
@@ -287,8 +288,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
287
288
 
288
289
  class ConfirmationService {
289
290
  dialogService = inject(DialogService);
290
- async showYesNoConfirmationDialog(title, message, cssClass) {
291
- const dialogRef = this.openDialog(title, message, DialogType.YesNo, cssClass);
291
+ async showYesNoConfirmationDialog(title, message, cssClass, buttonLabels) {
292
+ const dialogRef = this.openDialog(title, message, DialogType.YesNo, cssClass, buttonLabels);
292
293
  const result = await firstValueFrom(dialogRef.result);
293
294
  if (result instanceof ConfirmationWindowResult) {
294
295
  return result.result === ButtonTypes.Yes;
@@ -297,8 +298,8 @@ class ConfirmationService {
297
298
  return false;
298
299
  }
299
300
  }
300
- async showYesNoCancelConfirmationDialog(title, message) {
301
- const dialogRef = this.openDialog(title, message, DialogType.YesNoCancel);
301
+ async showYesNoCancelConfirmationDialog(title, message, buttonLabels) {
302
+ const dialogRef = this.openDialog(title, message, DialogType.YesNoCancel, undefined, buttonLabels);
302
303
  const result = await firstValueFrom(dialogRef.result);
303
304
  if (result instanceof ConfirmationWindowResult) {
304
305
  return result;
@@ -331,7 +332,7 @@ class ConfirmationService {
331
332
  return false;
332
333
  }
333
334
  }
334
- openDialog(title, message, dialogType, cssClass) {
335
+ openDialog(title, message, dialogType, cssClass, buttonLabels) {
335
336
  const dialogRef = this.dialogService.open({
336
337
  title,
337
338
  content: ConfirmationWindowComponent,
@@ -341,7 +342,8 @@ class ConfirmationService {
341
342
  component.data = {
342
343
  title,
343
344
  message,
344
- dialogType: dialogType
345
+ dialogType,
346
+ buttonLabels,
345
347
  };
346
348
  return dialogRef;
347
349
  }
@@ -2049,11 +2051,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
2049
2051
  args: ['window:beforeunload', ['$event']]
2050
2052
  }] } });
2051
2053
 
2054
+ class FormTitleExtraDirective {
2055
+ templateRef = inject((TemplateRef));
2056
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: FormTitleExtraDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
2057
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.0", type: FormTitleExtraDirective, isStandalone: true, selector: "[mmFormTitleExtra]", ngImport: i0 });
2058
+ }
2059
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: FormTitleExtraDirective, decorators: [{
2060
+ type: Directive,
2061
+ args: [{ selector: '[mmFormTitleExtra]', standalone: true }]
2062
+ }] });
2052
2063
  // Default responsive breakpoint for 2-column to 1-column
2053
2064
  const DEFAULT_RESPONSIVE_COLSPAN = [
2054
2065
  { maxWidth: 768, value: 2 } // Full width on mobile
2055
2066
  ];
2056
2067
  class BaseFormComponent {
2068
+ titleExtra;
2057
2069
  form;
2058
2070
  config = {
2059
2071
  showCard: true,
@@ -2069,21 +2081,36 @@ class BaseFormComponent {
2069
2081
  get title() {
2070
2082
  if (this.config.title)
2071
2083
  return this.config.title;
2084
+ const msgs = this.config.messages;
2072
2085
  if (this.config.isViewMode)
2073
- return 'View Details';
2074
- return this.config.isEditMode ? 'Edit' : 'New';
2086
+ return msgs?.viewTitle ?? 'View Details';
2087
+ return this.config.isEditMode ? (msgs?.editTitle ?? 'Edit') : (msgs?.newTitle ?? 'New');
2075
2088
  }
2076
2089
  get saveButtonText() {
2077
2090
  if (this.config.saveButtonText)
2078
2091
  return this.config.saveButtonText;
2092
+ const msgs = this.config.messages;
2079
2093
  if (this.config.isSaving)
2080
- return 'Saving...';
2081
- return this.config.isEditMode ? 'Update' : 'Create';
2094
+ return msgs?.savingText ?? 'Saving...';
2095
+ return this.config.isEditMode ? (msgs?.updateText ?? 'Update') : (msgs?.createText ?? 'Create');
2082
2096
  }
2083
2097
  get cancelButtonText() {
2084
2098
  if (this.config.cancelButtonText)
2085
2099
  return this.config.cancelButtonText;
2086
- return this.config.isViewMode ? 'Back' : 'Cancel';
2100
+ const msgs = this.config.messages;
2101
+ return this.config.isViewMode ? (msgs?.backText ?? 'Back') : (msgs?.cancelText ?? 'Cancel');
2102
+ }
2103
+ get unsavedChangesText() {
2104
+ return this.config.messages?.unsavedChangesText ?? 'Unsaved Changes';
2105
+ }
2106
+ get loadingText() {
2107
+ return this.config.messages?.loadingText ?? 'Loading...';
2108
+ }
2109
+ get modifiedText() {
2110
+ return this.config.messages?.modifiedText ?? 'MODIFIED';
2111
+ }
2112
+ get readyText() {
2113
+ return this.config.messages?.readyText ?? 'READY';
2087
2114
  }
2088
2115
  get showSaveButton() {
2089
2116
  return !this.config.isViewMode && !this.config.isLoading;
@@ -2120,15 +2147,18 @@ class BaseFormComponent {
2120
2147
  return this.form?.dirty ?? false;
2121
2148
  }
2122
2149
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: BaseFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2123
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.0", type: BaseFormComponent, isStandalone: true, selector: "mm-base-form", inputs: { form: "form", config: "config" }, outputs: { saveForm: "saveForm", cancelForm: "cancelForm" }, providers: [{ provide: HAS_UNSAVED_CHANGES, useExisting: BaseFormComponent }], hostDirectives: [{ directive: UnsavedChangesDirective }], ngImport: i0, template: "<div class=\"mm-base-form-container\" [class.with-card]=\"config.showCard\" [class.without-card]=\"!config.showCard\">\n <!-- Title (no card mode) -->\n <div *ngIf=\"!config.showCard && title\" class=\"mm-form-title-row mm-form-title-standalone\">\n <h2 class=\"mm-form-title\">{{ title }}</h2>\n <span *ngIf=\"config.hasChanges\" class=\"mm-modified-badge\">Unsaved Changes</span>\n </div>\n\n <!-- Main form wrapper - styled as card or plain based on CSS class -->\n <div class=\"mm-form-wrapper\" [style.maxWidth]=\"config.showCard ? (config.cardWidth || '800px') : null\">\n <!-- Card header (only in card mode) -->\n <div *ngIf=\"config.showCard && title\" class=\"mm-form-header\">\n <h2 class=\"mm-form-title\">{{ title }}</h2>\n <span *ngIf=\"config.hasChanges\" class=\"mm-modified-badge\">Unsaved Changes</span>\n </div>\n\n <!-- Form body with content projection -->\n <div class=\"mm-form-body\">\n <div *ngIf=\"config.isLoading && config.showLoadingOverlay\" class=\"mm-loading-overlay\">\n <div class=\"k-loader k-loader-lg\"></div>\n <p>Loading...</p>\n </div>\n <ng-content></ng-content>\n </div>\n\n <!-- Form actions -->\n <div class=\"mm-form-actions\">\n <!-- Status indicator (left side) -->\n <div class=\"mm-form-status\">\n <span class=\"mm-status-indicator\" [class.modified]=\"config.hasChanges\">\n <span class=\"mm-status-dot\"></span>\n <span class=\"mm-status-text\">{{ config.hasChanges ? 'MODIFIED' : 'READY' }}</span>\n </span>\n </div>\n\n <!-- Action buttons (right side) -->\n <div class=\"mm-form-buttons\">\n <button\n *ngIf=\"showSaveButton\"\n kendoButton\n type=\"submit\"\n [svgIcon]=\"saveIcon\"\n themeColor=\"primary\"\n [disabled]=\"saveButtonDisabled\"\n (click)=\"onSave()\">\n {{ saveButtonText }}\n </button>\n <button\n *ngIf=\"showCancelButton\"\n kendoButton\n type=\"button\"\n [svgIcon]=\"cancelIcon\"\n [disabled]=\"!!config.isSaving\"\n (click)=\"onCancel()\">\n {{ cancelButtonText }}\n </button>\n <ng-content select=\"[additionalActions]\"></ng-content>\n </div>\n </div>\n </div>\n</div>\n", styles: [":host{--mm-form-bg: var(--kendo-color-surface);--mm-form-bg-alt: var(--kendo-color-surface-alt);--mm-form-bg-elevated: var(--kendo-color-surface-alt);--mm-form-border: var(--kendo-color-border);--mm-form-border-subtle: var(--kendo-color-border-alt, var(--mm-form-border));--mm-form-text: var(--kendo-color-on-app-surface);--mm-form-text-subtle: var(--kendo-color-subtle);--mm-form-text-label: var(--kendo-color-on-app-surface);--mm-form-accent: var(--kendo-color-primary);--mm-form-error: var(--kendo-color-error);--mm-form-status-ready: #37b400;--mm-form-status-modified: #da9162;--mm-form-padding: 1.5rem;--mm-form-padding-sm: 1rem;--mm-form-gap: .5rem;--mm-form-radius: 4px;--mm-form-shadow: 0 2px 6px rgba(0, 0, 0, .15);--mm-form-overlay-bg: var(--kendo-color-surface)}.mm-base-form-container{padding:var(--mm-form-padding);height:100%;overflow:auto}.mm-base-form-container .mm-form-wrapper{margin:0 auto}.mm-base-form-container.with-card .mm-form-wrapper{background:var(--mm-form-bg);border:1px solid var(--mm-form-border);border-radius:var(--mm-form-radius);box-shadow:var(--mm-form-shadow)}.mm-base-form-container.with-card .mm-form-header{display:flex;align-items:center;gap:1rem;padding:var(--mm-form-padding-sm) var(--mm-form-padding);border-bottom:1px solid var(--mm-form-border);background:var(--mm-form-bg-alt)}.mm-base-form-container.with-card .mm-form-body{padding:var(--mm-form-padding)}.mm-base-form-container.with-card .mm-form-actions{padding:var(--mm-form-padding-sm) var(--mm-form-padding);border-top:1px solid var(--mm-form-border);background:var(--mm-form-bg-alt)}.mm-base-form-container.without-card .mm-form-wrapper{max-width:1200px}.mm-base-form-container.without-card .mm-form-title-standalone{margin-bottom:var(--mm-form-padding)}.mm-base-form-container.without-card .mm-form-actions{margin-top:var(--mm-form-padding);padding-top:var(--mm-form-padding);border-top:1px solid var(--mm-form-border)}.mm-base-form-container .mm-form-title-row{display:flex;align-items:center;gap:1rem}.mm-base-form-container .mm-form-title{font-size:1.5rem;font-weight:500;margin:0;color:var(--mm-form-text)}.mm-base-form-container .mm-modified-badge{display:inline-flex;align-items:center;padding:.25rem .75rem;font-size:.75rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--mm-form-status-modified);background:#da916226;border:1px solid rgba(218,145,98,.4);border-radius:var(--mm-form-radius);animation:pulse-badge 2s ease-in-out infinite}@keyframes pulse-badge{0%,to{opacity:1}50%{opacity:.7}}.mm-base-form-container .mm-form-body{position:relative;min-height:100px}.mm-base-form-container .mm-form-actions{display:flex;gap:var(--mm-form-gap);justify-content:space-between;align-items:center}.mm-base-form-container .mm-form-status{display:flex;align-items:center}.mm-base-form-container .mm-status-indicator{display:flex;align-items:center;gap:.5rem;padding:.25rem .75rem;background:#37b4001a;border:1px solid rgba(55,180,0,.3);border-radius:var(--mm-form-radius)}.mm-base-form-container .mm-status-indicator .mm-status-dot{width:8px;height:8px;border-radius:50%;background:var(--mm-form-status-ready);box-shadow:0 0 8px #37b40099;animation:pulse-dot 2s ease-in-out infinite}.mm-base-form-container .mm-status-indicator .mm-status-text{font-size:.7rem;font-weight:600;letter-spacing:1px;color:var(--mm-form-status-ready);text-transform:uppercase}.mm-base-form-container .mm-status-indicator.modified{background:#da91621a;border-color:#da91624d}.mm-base-form-container .mm-status-indicator.modified .mm-status-dot{background:var(--mm-form-status-modified);box-shadow:0 0 8px #da916299}.mm-base-form-container .mm-status-indicator.modified .mm-status-text{color:var(--mm-form-status-modified)}@keyframes pulse-dot{0%,to{opacity:1}50%{opacity:.6}}.mm-base-form-container .mm-form-buttons{display:flex;gap:var(--mm-form-gap)}.mm-base-form-container .mm-form-buttons button{min-width:100px}.mm-base-form-container .mm-loading-overlay{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;background-color:var(--mm-form-overlay-bg);opacity:.95;z-index:10}.mm-base-form-container .mm-loading-overlay p{margin-top:1rem;color:var(--mm-form-text-subtle);font-size:1rem}::ng-deep .mm-base-form-container fieldset[kendoformfieldset],::ng-deep .mm-base-form-container .k-form-fieldset{border:1px solid var(--mm-form-border);border-radius:var(--mm-form-radius);padding:var(--mm-form-padding);margin:0;background:var(--mm-form-bg-alt)}::ng-deep .mm-base-form-container fieldset[kendoformfieldset] legend,::ng-deep .mm-base-form-container fieldset[kendoformfieldset] .k-form-legend,::ng-deep .mm-base-form-container .k-form-fieldset legend,::ng-deep .mm-base-form-container .k-form-fieldset .k-form-legend{font-size:1.125rem;font-weight:500;color:var(--mm-form-accent);padding:0 .5rem}::ng-deep .mm-base-form-container kendo-formfield kendo-label,::ng-deep .mm-base-form-container kendo-formfield .k-label,::ng-deep .mm-base-form-container .k-form-field kendo-label,::ng-deep .mm-base-form-container .k-form-field .k-label{font-weight:500;color:var(--mm-form-text-label);margin-bottom:.25rem}::ng-deep .mm-base-form-container kendo-formfield kendo-label .k-required,::ng-deep .mm-base-form-container kendo-formfield .k-label .k-required,::ng-deep .mm-base-form-container .k-form-field kendo-label .k-required,::ng-deep .mm-base-form-container .k-form-field .k-label .k-required{color:var(--mm-form-error)}::ng-deep .mm-base-form-container kendo-formfield kendo-textbox,::ng-deep .mm-base-form-container kendo-formfield kendo-numerictextbox,::ng-deep .mm-base-form-container kendo-formfield kendo-textarea,::ng-deep .mm-base-form-container kendo-formfield kendo-datepicker,::ng-deep .mm-base-form-container kendo-formfield kendo-datetimepicker,::ng-deep .mm-base-form-container kendo-formfield kendo-timepicker,::ng-deep .mm-base-form-container kendo-formfield kendo-dropdownlist,::ng-deep .mm-base-form-container kendo-formfield kendo-combobox,::ng-deep .mm-base-form-container kendo-formfield kendo-multiselect,::ng-deep .mm-base-form-container kendo-formfield kendo-autocomplete,::ng-deep .mm-base-form-container .k-form-field kendo-textbox,::ng-deep .mm-base-form-container .k-form-field kendo-numerictextbox,::ng-deep .mm-base-form-container .k-form-field kendo-textarea,::ng-deep .mm-base-form-container .k-form-field kendo-datepicker,::ng-deep .mm-base-form-container .k-form-field kendo-datetimepicker,::ng-deep .mm-base-form-container .k-form-field kendo-timepicker,::ng-deep .mm-base-form-container .k-form-field kendo-dropdownlist,::ng-deep .mm-base-form-container .k-form-field kendo-combobox,::ng-deep .mm-base-form-container .k-form-field kendo-multiselect,::ng-deep .mm-base-form-container .k-form-field kendo-autocomplete{width:100%}::ng-deep .mm-base-form-container kendo-formfield kendo-formhint,::ng-deep .mm-base-form-container kendo-formfield .k-form-hint,::ng-deep .mm-base-form-container .k-form-field kendo-formhint,::ng-deep .mm-base-form-container .k-form-field .k-form-hint{color:var(--mm-form-text-subtle);font-size:.875rem}::ng-deep .mm-base-form-container kendo-formfield kendo-formerror,::ng-deep .mm-base-form-container kendo-formfield .k-form-error,::ng-deep .mm-base-form-container .k-form-field kendo-formerror,::ng-deep .mm-base-form-container .k-form-field .k-form-error{color:var(--mm-form-error);font-size:.875rem}::ng-deep .mm-base-form-container .status-indicator{display:inline-flex;align-items:center;gap:.5rem;padding:.25rem .75rem;border-radius:var(--mm-form-radius);font-size:.875rem}::ng-deep .mm-base-form-container .status-indicator.success{background-color:var(--kendo-color-success-subtle);color:var(--kendo-color-success-on-subtle)}::ng-deep .mm-base-form-container .status-indicator.warning{background-color:var(--kendo-color-warning-subtle);color:var(--kendo-color-warning-on-subtle)}::ng-deep .mm-base-form-container .status-indicator.error{background-color:var(--kendo-color-error-subtle);color:var(--kendo-color-error-on-subtle)}::ng-deep .mm-base-form-container .status-indicator.info{background-color:var(--kendo-color-info-subtle);color:var(--kendo-color-info-on-subtle)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i4.ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }] });
2150
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.0", type: BaseFormComponent, isStandalone: true, selector: "mm-base-form", inputs: { form: "form", config: "config" }, outputs: { saveForm: "saveForm", cancelForm: "cancelForm" }, providers: [{ provide: HAS_UNSAVED_CHANGES, useExisting: BaseFormComponent }], queries: [{ propertyName: "titleExtra", first: true, predicate: FormTitleExtraDirective, descendants: true }], hostDirectives: [{ directive: UnsavedChangesDirective }], ngImport: i0, template: "<div class=\"mm-base-form-container\" [class.with-card]=\"config.showCard\" [class.without-card]=\"!config.showCard\">\n <!-- Title (no card mode) -->\n <div *ngIf=\"!config.showCard && title\" class=\"mm-form-title-row mm-form-title-standalone\">\n <h2 class=\"mm-form-title\">{{ title }}</h2>\n <ng-container *ngIf=\"titleExtra\" [ngTemplateOutlet]=\"titleExtra.templateRef\"></ng-container>\n <span *ngIf=\"config.hasChanges\" class=\"mm-modified-badge\">{{ unsavedChangesText }}</span>\n </div>\n\n <!-- Main form wrapper - styled as card or plain based on CSS class -->\n <div class=\"mm-form-wrapper\" [style.maxWidth]=\"config.showCard ? (config.cardWidth || '800px') : null\">\n <!-- Card header (only in card mode) -->\n <div *ngIf=\"config.showCard && title\" class=\"mm-form-header\">\n <h2 class=\"mm-form-title\">{{ title }}</h2>\n <ng-container *ngIf=\"titleExtra\" [ngTemplateOutlet]=\"titleExtra.templateRef\"></ng-container>\n <span *ngIf=\"config.hasChanges\" class=\"mm-modified-badge\">{{ unsavedChangesText }}</span>\n </div>\n\n <!-- Form body with content projection -->\n <div class=\"mm-form-body\">\n <div *ngIf=\"config.isLoading && config.showLoadingOverlay\" class=\"mm-loading-overlay\">\n <div class=\"k-loader k-loader-lg\"></div>\n <p>{{ loadingText }}</p>\n </div>\n <ng-content></ng-content>\n </div>\n\n <!-- Form actions -->\n <div class=\"mm-form-actions\">\n <!-- Status indicator (left side) -->\n <div class=\"mm-form-status\">\n <span class=\"mm-status-indicator\" [class.modified]=\"config.hasChanges\">\n <span class=\"mm-status-dot\"></span>\n <span class=\"mm-status-text\">{{ config.hasChanges ? modifiedText : readyText }}</span>\n </span>\n </div>\n\n <!-- Action buttons (right side) -->\n <div class=\"mm-form-buttons\">\n <button\n *ngIf=\"showSaveButton\"\n kendoButton\n type=\"submit\"\n [svgIcon]=\"saveIcon\"\n themeColor=\"primary\"\n [disabled]=\"saveButtonDisabled\"\n (click)=\"onSave()\">\n {{ saveButtonText }}\n </button>\n <button\n *ngIf=\"showCancelButton\"\n kendoButton\n type=\"button\"\n [svgIcon]=\"cancelIcon\"\n [disabled]=\"!!config.isSaving\"\n (click)=\"onCancel()\">\n {{ cancelButtonText }}\n </button>\n <ng-content select=\"[additionalActions]\"></ng-content>\n </div>\n </div>\n </div>\n</div>\n", styles: [":host{--mm-form-bg: var(--kendo-color-surface);--mm-form-bg-alt: var(--kendo-color-surface-alt);--mm-form-bg-elevated: var(--kendo-color-surface-alt);--mm-form-border: var(--kendo-color-border);--mm-form-border-subtle: var(--kendo-color-border-alt, var(--mm-form-border));--mm-form-text: var(--kendo-color-on-app-surface);--mm-form-text-subtle: var(--kendo-color-subtle);--mm-form-text-label: var(--kendo-color-on-app-surface);--mm-form-accent: var(--kendo-color-primary);--mm-form-error: var(--kendo-color-error);--mm-form-status-ready: #37b400;--mm-form-status-modified: #da9162;--mm-form-padding: 1.5rem;--mm-form-padding-sm: 1rem;--mm-form-gap: .5rem;--mm-form-radius: 4px;--mm-form-shadow: 0 2px 6px rgba(0, 0, 0, .15);--mm-form-overlay-bg: var(--kendo-color-surface)}.mm-base-form-container{padding:var(--mm-form-padding);height:100%;overflow:auto}.mm-base-form-container .mm-form-wrapper{margin:0 auto}.mm-base-form-container.with-card .mm-form-wrapper{background:var(--mm-form-bg);border:1px solid var(--mm-form-border);border-radius:var(--mm-form-radius);box-shadow:var(--mm-form-shadow)}.mm-base-form-container.with-card .mm-form-header{display:flex;align-items:center;gap:1rem;padding:var(--mm-form-padding-sm) var(--mm-form-padding);border-bottom:1px solid var(--mm-form-border);background:var(--mm-form-bg-alt)}.mm-base-form-container.with-card .mm-form-body{padding:var(--mm-form-padding)}.mm-base-form-container.with-card .mm-form-actions{padding:var(--mm-form-padding-sm) var(--mm-form-padding);border-top:1px solid var(--mm-form-border);background:var(--mm-form-bg-alt)}.mm-base-form-container.without-card .mm-form-wrapper{max-width:1200px}.mm-base-form-container.without-card .mm-form-title-standalone{margin-bottom:var(--mm-form-padding)}.mm-base-form-container.without-card .mm-form-actions{margin-top:var(--mm-form-padding);padding-top:var(--mm-form-padding);border-top:1px solid var(--mm-form-border)}.mm-base-form-container .mm-form-title-row{display:flex;align-items:center;gap:1rem}.mm-base-form-container .mm-form-title{font-size:1.5rem;font-weight:500;margin:0;color:var(--mm-form-text)}.mm-base-form-container .mm-modified-badge{display:inline-flex;align-items:center;padding:.25rem .75rem;font-size:.75rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--mm-form-status-modified);background:#da916226;border:1px solid rgba(218,145,98,.4);border-radius:var(--mm-form-radius);animation:pulse-badge 2s ease-in-out infinite}@keyframes pulse-badge{0%,to{opacity:1}50%{opacity:.7}}.mm-base-form-container .mm-form-body{position:relative;min-height:100px}.mm-base-form-container .mm-form-actions{display:flex;gap:var(--mm-form-gap);justify-content:space-between;align-items:center}.mm-base-form-container .mm-form-status{display:flex;align-items:center}.mm-base-form-container .mm-status-indicator{display:flex;align-items:center;gap:.5rem;padding:.25rem .75rem;background:#37b4001a;border:1px solid rgba(55,180,0,.3);border-radius:var(--mm-form-radius)}.mm-base-form-container .mm-status-indicator .mm-status-dot{width:8px;height:8px;border-radius:50%;background:var(--mm-form-status-ready);box-shadow:0 0 8px #37b40099;animation:pulse-dot 2s ease-in-out infinite}.mm-base-form-container .mm-status-indicator .mm-status-text{font-size:.7rem;font-weight:600;letter-spacing:1px;color:var(--mm-form-status-ready);text-transform:uppercase}.mm-base-form-container .mm-status-indicator.modified{background:#da91621a;border-color:#da91624d}.mm-base-form-container .mm-status-indicator.modified .mm-status-dot{background:var(--mm-form-status-modified);box-shadow:0 0 8px #da916299}.mm-base-form-container .mm-status-indicator.modified .mm-status-text{color:var(--mm-form-status-modified)}@keyframes pulse-dot{0%,to{opacity:1}50%{opacity:.6}}.mm-base-form-container .mm-form-buttons{display:flex;gap:var(--mm-form-gap)}.mm-base-form-container .mm-form-buttons button{min-width:100px}.mm-base-form-container .mm-loading-overlay{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;background-color:var(--mm-form-overlay-bg);opacity:.95;z-index:10}.mm-base-form-container .mm-loading-overlay p{margin-top:1rem;color:var(--mm-form-text-subtle);font-size:1rem}::ng-deep .mm-base-form-container fieldset[kendoformfieldset],::ng-deep .mm-base-form-container .k-form-fieldset{border:1px solid var(--mm-form-border);border-radius:var(--mm-form-radius);padding:var(--mm-form-padding);margin:0;background:var(--mm-form-bg-alt)}::ng-deep .mm-base-form-container fieldset[kendoformfieldset] legend,::ng-deep .mm-base-form-container fieldset[kendoformfieldset] .k-form-legend,::ng-deep .mm-base-form-container .k-form-fieldset legend,::ng-deep .mm-base-form-container .k-form-fieldset .k-form-legend{font-size:1.125rem;font-weight:500;color:var(--mm-form-accent);padding:0 .5rem}::ng-deep .mm-base-form-container kendo-formfield kendo-label,::ng-deep .mm-base-form-container kendo-formfield .k-label,::ng-deep .mm-base-form-container .k-form-field kendo-label,::ng-deep .mm-base-form-container .k-form-field .k-label{font-weight:500;color:var(--mm-form-text-label);margin-bottom:.25rem}::ng-deep .mm-base-form-container kendo-formfield kendo-label .k-required,::ng-deep .mm-base-form-container kendo-formfield .k-label .k-required,::ng-deep .mm-base-form-container .k-form-field kendo-label .k-required,::ng-deep .mm-base-form-container .k-form-field .k-label .k-required{color:var(--mm-form-error)}::ng-deep .mm-base-form-container kendo-formfield kendo-textbox,::ng-deep .mm-base-form-container kendo-formfield kendo-numerictextbox,::ng-deep .mm-base-form-container kendo-formfield kendo-textarea,::ng-deep .mm-base-form-container kendo-formfield kendo-datepicker,::ng-deep .mm-base-form-container kendo-formfield kendo-datetimepicker,::ng-deep .mm-base-form-container kendo-formfield kendo-timepicker,::ng-deep .mm-base-form-container kendo-formfield kendo-dropdownlist,::ng-deep .mm-base-form-container kendo-formfield kendo-combobox,::ng-deep .mm-base-form-container kendo-formfield kendo-multiselect,::ng-deep .mm-base-form-container kendo-formfield kendo-autocomplete,::ng-deep .mm-base-form-container .k-form-field kendo-textbox,::ng-deep .mm-base-form-container .k-form-field kendo-numerictextbox,::ng-deep .mm-base-form-container .k-form-field kendo-textarea,::ng-deep .mm-base-form-container .k-form-field kendo-datepicker,::ng-deep .mm-base-form-container .k-form-field kendo-datetimepicker,::ng-deep .mm-base-form-container .k-form-field kendo-timepicker,::ng-deep .mm-base-form-container .k-form-field kendo-dropdownlist,::ng-deep .mm-base-form-container .k-form-field kendo-combobox,::ng-deep .mm-base-form-container .k-form-field kendo-multiselect,::ng-deep .mm-base-form-container .k-form-field kendo-autocomplete{width:100%}::ng-deep .mm-base-form-container kendo-formfield kendo-formhint,::ng-deep .mm-base-form-container kendo-formfield .k-form-hint,::ng-deep .mm-base-form-container .k-form-field kendo-formhint,::ng-deep .mm-base-form-container .k-form-field .k-form-hint{color:var(--mm-form-text-subtle);font-size:.875rem}::ng-deep .mm-base-form-container kendo-formfield kendo-formerror,::ng-deep .mm-base-form-container kendo-formfield .k-form-error,::ng-deep .mm-base-form-container .k-form-field kendo-formerror,::ng-deep .mm-base-form-container .k-form-field .k-form-error{color:var(--mm-form-error);font-size:.875rem}::ng-deep .mm-base-form-container .status-indicator{display:inline-flex;align-items:center;gap:.5rem;padding:.25rem .75rem;border-radius:var(--mm-form-radius);font-size:.875rem}::ng-deep .mm-base-form-container .status-indicator.success{background-color:var(--kendo-color-success-subtle);color:var(--kendo-color-success-on-subtle)}::ng-deep .mm-base-form-container .status-indicator.warning{background-color:var(--kendo-color-warning-subtle);color:var(--kendo-color-warning-on-subtle)}::ng-deep .mm-base-form-container .status-indicator.error{background-color:var(--kendo-color-error-subtle);color:var(--kendo-color-error-on-subtle)}::ng-deep .mm-base-form-container .status-indicator.info{background-color:var(--kendo-color-info-subtle);color:var(--kendo-color-info-on-subtle)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i4.ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }] });
2124
2151
  }
2125
2152
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: BaseFormComponent, decorators: [{
2126
2153
  type: Component,
2127
2154
  args: [{ selector: 'mm-base-form', standalone: true, imports: [
2128
2155
  CommonModule,
2129
2156
  ButtonModule
2130
- ], hostDirectives: [UnsavedChangesDirective], providers: [{ provide: HAS_UNSAVED_CHANGES, useExisting: BaseFormComponent }], template: "<div class=\"mm-base-form-container\" [class.with-card]=\"config.showCard\" [class.without-card]=\"!config.showCard\">\n <!-- Title (no card mode) -->\n <div *ngIf=\"!config.showCard && title\" class=\"mm-form-title-row mm-form-title-standalone\">\n <h2 class=\"mm-form-title\">{{ title }}</h2>\n <span *ngIf=\"config.hasChanges\" class=\"mm-modified-badge\">Unsaved Changes</span>\n </div>\n\n <!-- Main form wrapper - styled as card or plain based on CSS class -->\n <div class=\"mm-form-wrapper\" [style.maxWidth]=\"config.showCard ? (config.cardWidth || '800px') : null\">\n <!-- Card header (only in card mode) -->\n <div *ngIf=\"config.showCard && title\" class=\"mm-form-header\">\n <h2 class=\"mm-form-title\">{{ title }}</h2>\n <span *ngIf=\"config.hasChanges\" class=\"mm-modified-badge\">Unsaved Changes</span>\n </div>\n\n <!-- Form body with content projection -->\n <div class=\"mm-form-body\">\n <div *ngIf=\"config.isLoading && config.showLoadingOverlay\" class=\"mm-loading-overlay\">\n <div class=\"k-loader k-loader-lg\"></div>\n <p>Loading...</p>\n </div>\n <ng-content></ng-content>\n </div>\n\n <!-- Form actions -->\n <div class=\"mm-form-actions\">\n <!-- Status indicator (left side) -->\n <div class=\"mm-form-status\">\n <span class=\"mm-status-indicator\" [class.modified]=\"config.hasChanges\">\n <span class=\"mm-status-dot\"></span>\n <span class=\"mm-status-text\">{{ config.hasChanges ? 'MODIFIED' : 'READY' }}</span>\n </span>\n </div>\n\n <!-- Action buttons (right side) -->\n <div class=\"mm-form-buttons\">\n <button\n *ngIf=\"showSaveButton\"\n kendoButton\n type=\"submit\"\n [svgIcon]=\"saveIcon\"\n themeColor=\"primary\"\n [disabled]=\"saveButtonDisabled\"\n (click)=\"onSave()\">\n {{ saveButtonText }}\n </button>\n <button\n *ngIf=\"showCancelButton\"\n kendoButton\n type=\"button\"\n [svgIcon]=\"cancelIcon\"\n [disabled]=\"!!config.isSaving\"\n (click)=\"onCancel()\">\n {{ cancelButtonText }}\n </button>\n <ng-content select=\"[additionalActions]\"></ng-content>\n </div>\n </div>\n </div>\n</div>\n", styles: [":host{--mm-form-bg: var(--kendo-color-surface);--mm-form-bg-alt: var(--kendo-color-surface-alt);--mm-form-bg-elevated: var(--kendo-color-surface-alt);--mm-form-border: var(--kendo-color-border);--mm-form-border-subtle: var(--kendo-color-border-alt, var(--mm-form-border));--mm-form-text: var(--kendo-color-on-app-surface);--mm-form-text-subtle: var(--kendo-color-subtle);--mm-form-text-label: var(--kendo-color-on-app-surface);--mm-form-accent: var(--kendo-color-primary);--mm-form-error: var(--kendo-color-error);--mm-form-status-ready: #37b400;--mm-form-status-modified: #da9162;--mm-form-padding: 1.5rem;--mm-form-padding-sm: 1rem;--mm-form-gap: .5rem;--mm-form-radius: 4px;--mm-form-shadow: 0 2px 6px rgba(0, 0, 0, .15);--mm-form-overlay-bg: var(--kendo-color-surface)}.mm-base-form-container{padding:var(--mm-form-padding);height:100%;overflow:auto}.mm-base-form-container .mm-form-wrapper{margin:0 auto}.mm-base-form-container.with-card .mm-form-wrapper{background:var(--mm-form-bg);border:1px solid var(--mm-form-border);border-radius:var(--mm-form-radius);box-shadow:var(--mm-form-shadow)}.mm-base-form-container.with-card .mm-form-header{display:flex;align-items:center;gap:1rem;padding:var(--mm-form-padding-sm) var(--mm-form-padding);border-bottom:1px solid var(--mm-form-border);background:var(--mm-form-bg-alt)}.mm-base-form-container.with-card .mm-form-body{padding:var(--mm-form-padding)}.mm-base-form-container.with-card .mm-form-actions{padding:var(--mm-form-padding-sm) var(--mm-form-padding);border-top:1px solid var(--mm-form-border);background:var(--mm-form-bg-alt)}.mm-base-form-container.without-card .mm-form-wrapper{max-width:1200px}.mm-base-form-container.without-card .mm-form-title-standalone{margin-bottom:var(--mm-form-padding)}.mm-base-form-container.without-card .mm-form-actions{margin-top:var(--mm-form-padding);padding-top:var(--mm-form-padding);border-top:1px solid var(--mm-form-border)}.mm-base-form-container .mm-form-title-row{display:flex;align-items:center;gap:1rem}.mm-base-form-container .mm-form-title{font-size:1.5rem;font-weight:500;margin:0;color:var(--mm-form-text)}.mm-base-form-container .mm-modified-badge{display:inline-flex;align-items:center;padding:.25rem .75rem;font-size:.75rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--mm-form-status-modified);background:#da916226;border:1px solid rgba(218,145,98,.4);border-radius:var(--mm-form-radius);animation:pulse-badge 2s ease-in-out infinite}@keyframes pulse-badge{0%,to{opacity:1}50%{opacity:.7}}.mm-base-form-container .mm-form-body{position:relative;min-height:100px}.mm-base-form-container .mm-form-actions{display:flex;gap:var(--mm-form-gap);justify-content:space-between;align-items:center}.mm-base-form-container .mm-form-status{display:flex;align-items:center}.mm-base-form-container .mm-status-indicator{display:flex;align-items:center;gap:.5rem;padding:.25rem .75rem;background:#37b4001a;border:1px solid rgba(55,180,0,.3);border-radius:var(--mm-form-radius)}.mm-base-form-container .mm-status-indicator .mm-status-dot{width:8px;height:8px;border-radius:50%;background:var(--mm-form-status-ready);box-shadow:0 0 8px #37b40099;animation:pulse-dot 2s ease-in-out infinite}.mm-base-form-container .mm-status-indicator .mm-status-text{font-size:.7rem;font-weight:600;letter-spacing:1px;color:var(--mm-form-status-ready);text-transform:uppercase}.mm-base-form-container .mm-status-indicator.modified{background:#da91621a;border-color:#da91624d}.mm-base-form-container .mm-status-indicator.modified .mm-status-dot{background:var(--mm-form-status-modified);box-shadow:0 0 8px #da916299}.mm-base-form-container .mm-status-indicator.modified .mm-status-text{color:var(--mm-form-status-modified)}@keyframes pulse-dot{0%,to{opacity:1}50%{opacity:.6}}.mm-base-form-container .mm-form-buttons{display:flex;gap:var(--mm-form-gap)}.mm-base-form-container .mm-form-buttons button{min-width:100px}.mm-base-form-container .mm-loading-overlay{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;background-color:var(--mm-form-overlay-bg);opacity:.95;z-index:10}.mm-base-form-container .mm-loading-overlay p{margin-top:1rem;color:var(--mm-form-text-subtle);font-size:1rem}::ng-deep .mm-base-form-container fieldset[kendoformfieldset],::ng-deep .mm-base-form-container .k-form-fieldset{border:1px solid var(--mm-form-border);border-radius:var(--mm-form-radius);padding:var(--mm-form-padding);margin:0;background:var(--mm-form-bg-alt)}::ng-deep .mm-base-form-container fieldset[kendoformfieldset] legend,::ng-deep .mm-base-form-container fieldset[kendoformfieldset] .k-form-legend,::ng-deep .mm-base-form-container .k-form-fieldset legend,::ng-deep .mm-base-form-container .k-form-fieldset .k-form-legend{font-size:1.125rem;font-weight:500;color:var(--mm-form-accent);padding:0 .5rem}::ng-deep .mm-base-form-container kendo-formfield kendo-label,::ng-deep .mm-base-form-container kendo-formfield .k-label,::ng-deep .mm-base-form-container .k-form-field kendo-label,::ng-deep .mm-base-form-container .k-form-field .k-label{font-weight:500;color:var(--mm-form-text-label);margin-bottom:.25rem}::ng-deep .mm-base-form-container kendo-formfield kendo-label .k-required,::ng-deep .mm-base-form-container kendo-formfield .k-label .k-required,::ng-deep .mm-base-form-container .k-form-field kendo-label .k-required,::ng-deep .mm-base-form-container .k-form-field .k-label .k-required{color:var(--mm-form-error)}::ng-deep .mm-base-form-container kendo-formfield kendo-textbox,::ng-deep .mm-base-form-container kendo-formfield kendo-numerictextbox,::ng-deep .mm-base-form-container kendo-formfield kendo-textarea,::ng-deep .mm-base-form-container kendo-formfield kendo-datepicker,::ng-deep .mm-base-form-container kendo-formfield kendo-datetimepicker,::ng-deep .mm-base-form-container kendo-formfield kendo-timepicker,::ng-deep .mm-base-form-container kendo-formfield kendo-dropdownlist,::ng-deep .mm-base-form-container kendo-formfield kendo-combobox,::ng-deep .mm-base-form-container kendo-formfield kendo-multiselect,::ng-deep .mm-base-form-container kendo-formfield kendo-autocomplete,::ng-deep .mm-base-form-container .k-form-field kendo-textbox,::ng-deep .mm-base-form-container .k-form-field kendo-numerictextbox,::ng-deep .mm-base-form-container .k-form-field kendo-textarea,::ng-deep .mm-base-form-container .k-form-field kendo-datepicker,::ng-deep .mm-base-form-container .k-form-field kendo-datetimepicker,::ng-deep .mm-base-form-container .k-form-field kendo-timepicker,::ng-deep .mm-base-form-container .k-form-field kendo-dropdownlist,::ng-deep .mm-base-form-container .k-form-field kendo-combobox,::ng-deep .mm-base-form-container .k-form-field kendo-multiselect,::ng-deep .mm-base-form-container .k-form-field kendo-autocomplete{width:100%}::ng-deep .mm-base-form-container kendo-formfield kendo-formhint,::ng-deep .mm-base-form-container kendo-formfield .k-form-hint,::ng-deep .mm-base-form-container .k-form-field kendo-formhint,::ng-deep .mm-base-form-container .k-form-field .k-form-hint{color:var(--mm-form-text-subtle);font-size:.875rem}::ng-deep .mm-base-form-container kendo-formfield kendo-formerror,::ng-deep .mm-base-form-container kendo-formfield .k-form-error,::ng-deep .mm-base-form-container .k-form-field kendo-formerror,::ng-deep .mm-base-form-container .k-form-field .k-form-error{color:var(--mm-form-error);font-size:.875rem}::ng-deep .mm-base-form-container .status-indicator{display:inline-flex;align-items:center;gap:.5rem;padding:.25rem .75rem;border-radius:var(--mm-form-radius);font-size:.875rem}::ng-deep .mm-base-form-container .status-indicator.success{background-color:var(--kendo-color-success-subtle);color:var(--kendo-color-success-on-subtle)}::ng-deep .mm-base-form-container .status-indicator.warning{background-color:var(--kendo-color-warning-subtle);color:var(--kendo-color-warning-on-subtle)}::ng-deep .mm-base-form-container .status-indicator.error{background-color:var(--kendo-color-error-subtle);color:var(--kendo-color-error-on-subtle)}::ng-deep .mm-base-form-container .status-indicator.info{background-color:var(--kendo-color-info-subtle);color:var(--kendo-color-info-on-subtle)}\n"] }]
2131
- }], propDecorators: { form: [{
2157
+ ], hostDirectives: [UnsavedChangesDirective], providers: [{ provide: HAS_UNSAVED_CHANGES, useExisting: BaseFormComponent }], template: "<div class=\"mm-base-form-container\" [class.with-card]=\"config.showCard\" [class.without-card]=\"!config.showCard\">\n <!-- Title (no card mode) -->\n <div *ngIf=\"!config.showCard && title\" class=\"mm-form-title-row mm-form-title-standalone\">\n <h2 class=\"mm-form-title\">{{ title }}</h2>\n <ng-container *ngIf=\"titleExtra\" [ngTemplateOutlet]=\"titleExtra.templateRef\"></ng-container>\n <span *ngIf=\"config.hasChanges\" class=\"mm-modified-badge\">{{ unsavedChangesText }}</span>\n </div>\n\n <!-- Main form wrapper - styled as card or plain based on CSS class -->\n <div class=\"mm-form-wrapper\" [style.maxWidth]=\"config.showCard ? (config.cardWidth || '800px') : null\">\n <!-- Card header (only in card mode) -->\n <div *ngIf=\"config.showCard && title\" class=\"mm-form-header\">\n <h2 class=\"mm-form-title\">{{ title }}</h2>\n <ng-container *ngIf=\"titleExtra\" [ngTemplateOutlet]=\"titleExtra.templateRef\"></ng-container>\n <span *ngIf=\"config.hasChanges\" class=\"mm-modified-badge\">{{ unsavedChangesText }}</span>\n </div>\n\n <!-- Form body with content projection -->\n <div class=\"mm-form-body\">\n <div *ngIf=\"config.isLoading && config.showLoadingOverlay\" class=\"mm-loading-overlay\">\n <div class=\"k-loader k-loader-lg\"></div>\n <p>{{ loadingText }}</p>\n </div>\n <ng-content></ng-content>\n </div>\n\n <!-- Form actions -->\n <div class=\"mm-form-actions\">\n <!-- Status indicator (left side) -->\n <div class=\"mm-form-status\">\n <span class=\"mm-status-indicator\" [class.modified]=\"config.hasChanges\">\n <span class=\"mm-status-dot\"></span>\n <span class=\"mm-status-text\">{{ config.hasChanges ? modifiedText : readyText }}</span>\n </span>\n </div>\n\n <!-- Action buttons (right side) -->\n <div class=\"mm-form-buttons\">\n <button\n *ngIf=\"showSaveButton\"\n kendoButton\n type=\"submit\"\n [svgIcon]=\"saveIcon\"\n themeColor=\"primary\"\n [disabled]=\"saveButtonDisabled\"\n (click)=\"onSave()\">\n {{ saveButtonText }}\n </button>\n <button\n *ngIf=\"showCancelButton\"\n kendoButton\n type=\"button\"\n [svgIcon]=\"cancelIcon\"\n [disabled]=\"!!config.isSaving\"\n (click)=\"onCancel()\">\n {{ cancelButtonText }}\n </button>\n <ng-content select=\"[additionalActions]\"></ng-content>\n </div>\n </div>\n </div>\n</div>\n", styles: [":host{--mm-form-bg: var(--kendo-color-surface);--mm-form-bg-alt: var(--kendo-color-surface-alt);--mm-form-bg-elevated: var(--kendo-color-surface-alt);--mm-form-border: var(--kendo-color-border);--mm-form-border-subtle: var(--kendo-color-border-alt, var(--mm-form-border));--mm-form-text: var(--kendo-color-on-app-surface);--mm-form-text-subtle: var(--kendo-color-subtle);--mm-form-text-label: var(--kendo-color-on-app-surface);--mm-form-accent: var(--kendo-color-primary);--mm-form-error: var(--kendo-color-error);--mm-form-status-ready: #37b400;--mm-form-status-modified: #da9162;--mm-form-padding: 1.5rem;--mm-form-padding-sm: 1rem;--mm-form-gap: .5rem;--mm-form-radius: 4px;--mm-form-shadow: 0 2px 6px rgba(0, 0, 0, .15);--mm-form-overlay-bg: var(--kendo-color-surface)}.mm-base-form-container{padding:var(--mm-form-padding);height:100%;overflow:auto}.mm-base-form-container .mm-form-wrapper{margin:0 auto}.mm-base-form-container.with-card .mm-form-wrapper{background:var(--mm-form-bg);border:1px solid var(--mm-form-border);border-radius:var(--mm-form-radius);box-shadow:var(--mm-form-shadow)}.mm-base-form-container.with-card .mm-form-header{display:flex;align-items:center;gap:1rem;padding:var(--mm-form-padding-sm) var(--mm-form-padding);border-bottom:1px solid var(--mm-form-border);background:var(--mm-form-bg-alt)}.mm-base-form-container.with-card .mm-form-body{padding:var(--mm-form-padding)}.mm-base-form-container.with-card .mm-form-actions{padding:var(--mm-form-padding-sm) var(--mm-form-padding);border-top:1px solid var(--mm-form-border);background:var(--mm-form-bg-alt)}.mm-base-form-container.without-card .mm-form-wrapper{max-width:1200px}.mm-base-form-container.without-card .mm-form-title-standalone{margin-bottom:var(--mm-form-padding)}.mm-base-form-container.without-card .mm-form-actions{margin-top:var(--mm-form-padding);padding-top:var(--mm-form-padding);border-top:1px solid var(--mm-form-border)}.mm-base-form-container .mm-form-title-row{display:flex;align-items:center;gap:1rem}.mm-base-form-container .mm-form-title{font-size:1.5rem;font-weight:500;margin:0;color:var(--mm-form-text)}.mm-base-form-container .mm-modified-badge{display:inline-flex;align-items:center;padding:.25rem .75rem;font-size:.75rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--mm-form-status-modified);background:#da916226;border:1px solid rgba(218,145,98,.4);border-radius:var(--mm-form-radius);animation:pulse-badge 2s ease-in-out infinite}@keyframes pulse-badge{0%,to{opacity:1}50%{opacity:.7}}.mm-base-form-container .mm-form-body{position:relative;min-height:100px}.mm-base-form-container .mm-form-actions{display:flex;gap:var(--mm-form-gap);justify-content:space-between;align-items:center}.mm-base-form-container .mm-form-status{display:flex;align-items:center}.mm-base-form-container .mm-status-indicator{display:flex;align-items:center;gap:.5rem;padding:.25rem .75rem;background:#37b4001a;border:1px solid rgba(55,180,0,.3);border-radius:var(--mm-form-radius)}.mm-base-form-container .mm-status-indicator .mm-status-dot{width:8px;height:8px;border-radius:50%;background:var(--mm-form-status-ready);box-shadow:0 0 8px #37b40099;animation:pulse-dot 2s ease-in-out infinite}.mm-base-form-container .mm-status-indicator .mm-status-text{font-size:.7rem;font-weight:600;letter-spacing:1px;color:var(--mm-form-status-ready);text-transform:uppercase}.mm-base-form-container .mm-status-indicator.modified{background:#da91621a;border-color:#da91624d}.mm-base-form-container .mm-status-indicator.modified .mm-status-dot{background:var(--mm-form-status-modified);box-shadow:0 0 8px #da916299}.mm-base-form-container .mm-status-indicator.modified .mm-status-text{color:var(--mm-form-status-modified)}@keyframes pulse-dot{0%,to{opacity:1}50%{opacity:.6}}.mm-base-form-container .mm-form-buttons{display:flex;gap:var(--mm-form-gap)}.mm-base-form-container .mm-form-buttons button{min-width:100px}.mm-base-form-container .mm-loading-overlay{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;background-color:var(--mm-form-overlay-bg);opacity:.95;z-index:10}.mm-base-form-container .mm-loading-overlay p{margin-top:1rem;color:var(--mm-form-text-subtle);font-size:1rem}::ng-deep .mm-base-form-container fieldset[kendoformfieldset],::ng-deep .mm-base-form-container .k-form-fieldset{border:1px solid var(--mm-form-border);border-radius:var(--mm-form-radius);padding:var(--mm-form-padding);margin:0;background:var(--mm-form-bg-alt)}::ng-deep .mm-base-form-container fieldset[kendoformfieldset] legend,::ng-deep .mm-base-form-container fieldset[kendoformfieldset] .k-form-legend,::ng-deep .mm-base-form-container .k-form-fieldset legend,::ng-deep .mm-base-form-container .k-form-fieldset .k-form-legend{font-size:1.125rem;font-weight:500;color:var(--mm-form-accent);padding:0 .5rem}::ng-deep .mm-base-form-container kendo-formfield kendo-label,::ng-deep .mm-base-form-container kendo-formfield .k-label,::ng-deep .mm-base-form-container .k-form-field kendo-label,::ng-deep .mm-base-form-container .k-form-field .k-label{font-weight:500;color:var(--mm-form-text-label);margin-bottom:.25rem}::ng-deep .mm-base-form-container kendo-formfield kendo-label .k-required,::ng-deep .mm-base-form-container kendo-formfield .k-label .k-required,::ng-deep .mm-base-form-container .k-form-field kendo-label .k-required,::ng-deep .mm-base-form-container .k-form-field .k-label .k-required{color:var(--mm-form-error)}::ng-deep .mm-base-form-container kendo-formfield kendo-textbox,::ng-deep .mm-base-form-container kendo-formfield kendo-numerictextbox,::ng-deep .mm-base-form-container kendo-formfield kendo-textarea,::ng-deep .mm-base-form-container kendo-formfield kendo-datepicker,::ng-deep .mm-base-form-container kendo-formfield kendo-datetimepicker,::ng-deep .mm-base-form-container kendo-formfield kendo-timepicker,::ng-deep .mm-base-form-container kendo-formfield kendo-dropdownlist,::ng-deep .mm-base-form-container kendo-formfield kendo-combobox,::ng-deep .mm-base-form-container kendo-formfield kendo-multiselect,::ng-deep .mm-base-form-container kendo-formfield kendo-autocomplete,::ng-deep .mm-base-form-container .k-form-field kendo-textbox,::ng-deep .mm-base-form-container .k-form-field kendo-numerictextbox,::ng-deep .mm-base-form-container .k-form-field kendo-textarea,::ng-deep .mm-base-form-container .k-form-field kendo-datepicker,::ng-deep .mm-base-form-container .k-form-field kendo-datetimepicker,::ng-deep .mm-base-form-container .k-form-field kendo-timepicker,::ng-deep .mm-base-form-container .k-form-field kendo-dropdownlist,::ng-deep .mm-base-form-container .k-form-field kendo-combobox,::ng-deep .mm-base-form-container .k-form-field kendo-multiselect,::ng-deep .mm-base-form-container .k-form-field kendo-autocomplete{width:100%}::ng-deep .mm-base-form-container kendo-formfield kendo-formhint,::ng-deep .mm-base-form-container kendo-formfield .k-form-hint,::ng-deep .mm-base-form-container .k-form-field kendo-formhint,::ng-deep .mm-base-form-container .k-form-field .k-form-hint{color:var(--mm-form-text-subtle);font-size:.875rem}::ng-deep .mm-base-form-container kendo-formfield kendo-formerror,::ng-deep .mm-base-form-container kendo-formfield .k-form-error,::ng-deep .mm-base-form-container .k-form-field kendo-formerror,::ng-deep .mm-base-form-container .k-form-field .k-form-error{color:var(--mm-form-error);font-size:.875rem}::ng-deep .mm-base-form-container .status-indicator{display:inline-flex;align-items:center;gap:.5rem;padding:.25rem .75rem;border-radius:var(--mm-form-radius);font-size:.875rem}::ng-deep .mm-base-form-container .status-indicator.success{background-color:var(--kendo-color-success-subtle);color:var(--kendo-color-success-on-subtle)}::ng-deep .mm-base-form-container .status-indicator.warning{background-color:var(--kendo-color-warning-subtle);color:var(--kendo-color-warning-on-subtle)}::ng-deep .mm-base-form-container .status-indicator.error{background-color:var(--kendo-color-error-subtle);color:var(--kendo-color-error-on-subtle)}::ng-deep .mm-base-form-container .status-indicator.info{background-color:var(--kendo-color-info-subtle);color:var(--kendo-color-info-on-subtle)}\n"] }]
2158
+ }], propDecorators: { titleExtra: [{
2159
+ type: ContentChild,
2160
+ args: [FormTitleExtraDirective]
2161
+ }], form: [{
2132
2162
  type: Input
2133
2163
  }], config: [{
2134
2164
  type: Input
@@ -2464,6 +2494,29 @@ var ImportStrategyDto;
2464
2494
  ImportStrategyDto[ImportStrategyDto["Upsert"] = 1] = "Upsert";
2465
2495
  })(ImportStrategyDto || (ImportStrategyDto = {}));
2466
2496
 
2497
+ const DEFAULT_ENTITY_SELECT_DIALOG_MESSAGES = {
2498
+ searchPlaceholder: 'Search...',
2499
+ cancelButton: 'Cancel',
2500
+ confirmButton: 'OK',
2501
+ selectedSuffix: 'selected',
2502
+ pagerItemsPerPage: 'items per page',
2503
+ pagerOf: 'of',
2504
+ pagerItems: 'items',
2505
+ pagerPage: 'Page',
2506
+ pagerFirstPage: 'Go to the first page',
2507
+ pagerLastPage: 'Go to the last page',
2508
+ pagerPreviousPage: 'Go to the previous page',
2509
+ pagerNextPage: 'Go to the next page',
2510
+ };
2511
+ const DEFAULT_ENTITY_SELECT_INPUT_MESSAGES = {
2512
+ placeholder: 'Select an entity...',
2513
+ advancedSearchLabel: 'Advanced Search...',
2514
+ dialogTitle: 'Select Entity',
2515
+ noEntitiesFound: 'No entities found for "{0}"',
2516
+ minCharactersHint: 'Type at least {0} characters to search...',
2517
+ selectedSuffix: 'selected',
2518
+ };
2519
+
2467
2520
  class EntitySelectDialogComponent {
2468
2521
  windowRef = inject(WindowRef);
2469
2522
  searchSubject = new Subject();
@@ -2471,6 +2524,10 @@ class EntitySelectDialogComponent {
2471
2524
  dataSource;
2472
2525
  multiSelect = false;
2473
2526
  preSelectedEntities = [];
2527
+ _messages = { ...DEFAULT_ENTITY_SELECT_DIALOG_MESSAGES };
2528
+ set messages(value) {
2529
+ this._messages = { ...DEFAULT_ENTITY_SELECT_DIALOG_MESSAGES, ...value };
2530
+ }
2474
2531
  columns = [];
2475
2532
  gridData = { data: [], total: 0 };
2476
2533
  selectedEntities = [];
@@ -2599,14 +2656,14 @@ class EntitySelectDialogComponent {
2599
2656
  this.windowRef.close();
2600
2657
  }
2601
2658
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: EntitySelectDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2602
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.0", type: EntitySelectDialogComponent, isStandalone: true, selector: "mm-entity-select-dialog", inputs: { dataSource: "dataSource", multiSelect: "multiSelect", preSelectedEntities: "preSelectedEntities" }, ngImport: i0, template: `
2659
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.0", type: EntitySelectDialogComponent, isStandalone: true, selector: "mm-entity-select-dialog", inputs: { dataSource: "dataSource", multiSelect: "multiSelect", preSelectedEntities: "preSelectedEntities", messages: "messages" }, ngImport: i0, template: `
2603
2660
  <div class="entity-select-dialog-content">
2604
2661
  <div class="search-toolbar">
2605
2662
  <kendo-textbox
2606
2663
  [style.width.px]="250"
2607
- placeholder="Search..."
2664
+ [placeholder]="_messages.searchPlaceholder"
2608
2665
  [value]="searchValue"
2609
- (valueChange)="onSearchChange($event)">
2666
+ (valueChange)="onSearchChange($event ?? '')">
2610
2667
  </kendo-textbox>
2611
2668
  </div>
2612
2669
 
@@ -2621,6 +2678,17 @@ class EntitySelectDialogComponent {
2621
2678
  (selectionChange)="onSelectionChange($event)"
2622
2679
  class="entity-grid">
2623
2680
 
2681
+ <kendo-grid-messages
2682
+ [pagerItemsPerPage]="_messages.pagerItemsPerPage"
2683
+ [pagerOf]="_messages.pagerOf"
2684
+ [pagerItems]="_messages.pagerItems"
2685
+ [pagerPage]="_messages.pagerPage"
2686
+ [pagerFirstPage]="_messages.pagerFirstPage"
2687
+ [pagerLastPage]="_messages.pagerLastPage"
2688
+ [pagerPreviousPage]="_messages.pagerPreviousPage"
2689
+ [pagerNextPage]="_messages.pagerNextPage"
2690
+ ></kendo-grid-messages>
2691
+
2624
2692
  <kendo-grid-checkbox-column
2625
2693
  [width]="40"
2626
2694
  [showSelectAll]="multiSelect">
@@ -2635,20 +2703,20 @@ class EntitySelectDialogComponent {
2635
2703
  </kendo-grid>
2636
2704
 
2637
2705
  <div class="selection-info" *ngIf="selectedEntities.length > 0">
2638
- {{ selectedEntities.length }} selected
2706
+ {{ selectedEntities.length }} {{ _messages.selectedSuffix }}
2639
2707
  </div>
2640
2708
 
2641
2709
  <div class="dialog-actions">
2642
- <button kendoButton (click)="onCancel()">Cancel</button>
2710
+ <button kendoButton (click)="onCancel()">{{ _messages.cancelButton }}</button>
2643
2711
  <button kendoButton
2644
2712
  themeColor="primary"
2645
2713
  [disabled]="selectedEntities.length === 0"
2646
2714
  (click)="onConfirm()">
2647
- OK
2715
+ {{ _messages.confirmButton }}
2648
2716
  </button>
2649
2717
  </div>
2650
2718
  </div>
2651
- `, isInline: true, styles: [":host{display:flex;flex-direction:column;height:100%}.entity-select-dialog-content{display:flex;flex-direction:column;flex:1;min-height:0;padding:16px 20px;box-sizing:border-box;gap:12px}.search-toolbar{flex-shrink:0}.entity-grid{flex:1;min-height:200px;border:1px solid var(--kendo-color-border)}.selection-info{padding:8px 0;font-size:12px;color:var(--kendo-color-subtle);flex-shrink:0}.dialog-actions{display:flex;justify-content:flex-end;gap:8px;flex-shrink:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ButtonsModule }, { kind: "component", type: i4.ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "ngmodule", type: WindowModule }, { kind: "component", type: GridComponent, selector: "kendo-grid", inputs: ["data", "pageSize", "height", "rowHeight", "adaptiveMode", "detailRowHeight", "skip", "scrollable", "selectable", "sort", "size", "trackBy", "filter", "group", "virtualColumns", "filterable", "sortable", "pageable", "groupable", "gridResizable", "rowReorderable", "navigable", "autoSize", "rowClass", "rowSticky", "rowSelected", "isRowSelectable", "cellSelected", "resizable", "reorderable", "loading", "columnMenu", "hideHeader", "showInactiveTools", "isDetailExpanded", "isGroupExpanded", "dataLayoutMode"], outputs: ["filterChange", "pageChange", "groupChange", "sortChange", "selectionChange", "rowReorder", "dataStateChange", "gridStateChange", "groupExpand", "groupCollapse", "detailExpand", "detailCollapse", "edit", "cancel", "save", "remove", "add", "cellClose", "cellClick", "pdfExport", "excelExport", "csvExport", "columnResize", "columnReorder", "columnVisibilityChange", "columnLockedChange", "columnStickyChange", "scrollBottom", "contentScroll"], exportAs: ["kendoGrid"] }, { kind: "component", type: ColumnComponent, selector: "kendo-grid-column", inputs: ["field", "format", "sortable", "groupable", "editor", "filter", "filterVariant", "filterable", "editable"] }, { kind: "component", type: CheckboxColumnComponent, selector: "kendo-grid-checkbox-column", inputs: ["showSelectAll", "showDisabledCheckbox"] }, { kind: "component", type: TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "pipe", type: PascalCasePipe, name: "pascalCase" }] });
2719
+ `, isInline: true, styles: [":host{display:flex;flex-direction:column;height:100%}.entity-select-dialog-content{display:flex;flex-direction:column;flex:1;min-height:0;padding:16px 20px;box-sizing:border-box;gap:12px}.search-toolbar{flex-shrink:0}.entity-grid{flex:1;min-height:200px;border:1px solid var(--kendo-color-border)}.selection-info{padding:8px 0;font-size:12px;color:var(--kendo-color-subtle);flex-shrink:0}.dialog-actions{display:flex;justify-content:flex-end;gap:8px;flex-shrink:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ButtonsModule }, { kind: "component", type: i4.ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "ngmodule", type: WindowModule }, { kind: "component", type: GridComponent, selector: "kendo-grid", inputs: ["data", "pageSize", "height", "rowHeight", "adaptiveMode", "detailRowHeight", "skip", "scrollable", "selectable", "sort", "size", "trackBy", "filter", "group", "virtualColumns", "filterable", "sortable", "pageable", "groupable", "gridResizable", "rowReorderable", "navigable", "autoSize", "rowClass", "rowSticky", "rowSelected", "isRowSelectable", "cellSelected", "resizable", "reorderable", "loading", "columnMenu", "hideHeader", "showInactiveTools", "isDetailExpanded", "isGroupExpanded", "dataLayoutMode"], outputs: ["filterChange", "pageChange", "groupChange", "sortChange", "selectionChange", "rowReorder", "dataStateChange", "gridStateChange", "groupExpand", "groupCollapse", "detailExpand", "detailCollapse", "edit", "cancel", "save", "remove", "add", "cellClose", "cellClick", "pdfExport", "excelExport", "csvExport", "columnResize", "columnReorder", "columnVisibilityChange", "columnLockedChange", "columnStickyChange", "scrollBottom", "contentScroll"], exportAs: ["kendoGrid"] }, { kind: "component", type: ColumnComponent, selector: "kendo-grid-column", inputs: ["field", "format", "sortable", "groupable", "editor", "filter", "filterVariant", "filterable", "editable"] }, { kind: "component", type: CheckboxColumnComponent, selector: "kendo-grid-checkbox-column", inputs: ["showSelectAll", "showDisabledCheckbox"] }, { kind: "component", type: CustomMessagesComponent, selector: "kendo-grid-messages" }, { kind: "component", type: TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "pipe", type: PascalCasePipe, name: "pascalCase" }] });
2652
2720
  }
2653
2721
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: EntitySelectDialogComponent, decorators: [{
2654
2722
  type: Component,
@@ -2659,6 +2727,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
2659
2727
  GridComponent,
2660
2728
  ColumnComponent,
2661
2729
  CheckboxColumnComponent,
2730
+ CustomMessagesComponent,
2662
2731
  TextBoxComponent,
2663
2732
  PascalCasePipe
2664
2733
  ], template: `
@@ -2666,9 +2735,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
2666
2735
  <div class="search-toolbar">
2667
2736
  <kendo-textbox
2668
2737
  [style.width.px]="250"
2669
- placeholder="Search..."
2738
+ [placeholder]="_messages.searchPlaceholder"
2670
2739
  [value]="searchValue"
2671
- (valueChange)="onSearchChange($event)">
2740
+ (valueChange)="onSearchChange($event ?? '')">
2672
2741
  </kendo-textbox>
2673
2742
  </div>
2674
2743
 
@@ -2683,6 +2752,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
2683
2752
  (selectionChange)="onSelectionChange($event)"
2684
2753
  class="entity-grid">
2685
2754
 
2755
+ <kendo-grid-messages
2756
+ [pagerItemsPerPage]="_messages.pagerItemsPerPage"
2757
+ [pagerOf]="_messages.pagerOf"
2758
+ [pagerItems]="_messages.pagerItems"
2759
+ [pagerPage]="_messages.pagerPage"
2760
+ [pagerFirstPage]="_messages.pagerFirstPage"
2761
+ [pagerLastPage]="_messages.pagerLastPage"
2762
+ [pagerPreviousPage]="_messages.pagerPreviousPage"
2763
+ [pagerNextPage]="_messages.pagerNextPage"
2764
+ ></kendo-grid-messages>
2765
+
2686
2766
  <kendo-grid-checkbox-column
2687
2767
  [width]="40"
2688
2768
  [showSelectAll]="multiSelect">
@@ -2697,16 +2777,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
2697
2777
  </kendo-grid>
2698
2778
 
2699
2779
  <div class="selection-info" *ngIf="selectedEntities.length > 0">
2700
- {{ selectedEntities.length }} selected
2780
+ {{ selectedEntities.length }} {{ _messages.selectedSuffix }}
2701
2781
  </div>
2702
2782
 
2703
2783
  <div class="dialog-actions">
2704
- <button kendoButton (click)="onCancel()">Cancel</button>
2784
+ <button kendoButton (click)="onCancel()">{{ _messages.cancelButton }}</button>
2705
2785
  <button kendoButton
2706
2786
  themeColor="primary"
2707
2787
  [disabled]="selectedEntities.length === 0"
2708
2788
  (click)="onConfirm()">
2709
- OK
2789
+ {{ _messages.confirmButton }}
2710
2790
  </button>
2711
2791
  </div>
2712
2792
  </div>
@@ -2717,6 +2797,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
2717
2797
  type: Input
2718
2798
  }], preSelectedEntities: [{
2719
2799
  type: Input
2800
+ }], messages: [{
2801
+ type: Input
2720
2802
  }] } });
2721
2803
 
2722
2804
  class EntitySelectDialogService {
@@ -2742,6 +2824,9 @@ class EntitySelectDialogService {
2742
2824
  contentRef.instance.dataSource = dataSource;
2743
2825
  contentRef.instance.multiSelect = options.multiSelect ?? false;
2744
2826
  contentRef.instance.preSelectedEntities = options.selectedEntities ?? [];
2827
+ if (options.messages) {
2828
+ contentRef.instance.messages = options.messages;
2829
+ }
2745
2830
  }
2746
2831
  const result = await firstValueFrom(windowRef.result);
2747
2832
  if (result instanceof WindowCloseResult) {
@@ -2764,7 +2849,7 @@ class EntitySelectInputComponent {
2764
2849
  // Inputs
2765
2850
  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- generic component accepts any entity type
2766
2851
  dataSource;
2767
- placeholder = 'Select an entity...';
2852
+ placeholder = '';
2768
2853
  minSearchLength = 3;
2769
2854
  maxResults = 50;
2770
2855
  debounceMs = 300;
@@ -2772,9 +2857,16 @@ class EntitySelectInputComponent {
2772
2857
  // Dialog inputs
2773
2858
  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- generic component accepts any entity type
2774
2859
  dialogDataSource;
2775
- dialogTitle = 'Select Entity';
2860
+ dialogTitle = '';
2776
2861
  multiSelect = false;
2777
- advancedSearchLabel = 'Advanced Search...';
2862
+ advancedSearchLabel = '';
2863
+ // Dialog messages (passed through to the dialog component)
2864
+ dialogMessages;
2865
+ // Messages
2866
+ _messages = { ...DEFAULT_ENTITY_SELECT_INPUT_MESSAGES };
2867
+ set messages(value) {
2868
+ this._messages = { ...DEFAULT_ENTITY_SELECT_INPUT_MESSAGES, ...value };
2869
+ }
2778
2870
  _disabled = false;
2779
2871
  get disabled() {
2780
2872
  return this._disabled;
@@ -2818,6 +2910,9 @@ class EntitySelectInputComponent {
2818
2910
  // Injected dependencies
2819
2911
  elRef = inject(ElementRef);
2820
2912
  dialogService = inject(EntitySelectDialogService, { optional: true });
2913
+ formatMessage(template, ...args) {
2914
+ return template.replace(/\{(\d+)\}/g, (_, index) => String(args[+index] ?? ''));
2915
+ }
2821
2916
  ngOnInit() {
2822
2917
  this.setupSearch();
2823
2918
  }
@@ -2978,9 +3073,10 @@ class EntitySelectInputComponent {
2978
3073
  // Close the autocomplete dropdown
2979
3074
  this.autocomplete.toggle(false);
2980
3075
  const result = await this.dialogService.open(this.dialogDataSource, {
2981
- title: this.dialogTitle,
3076
+ title: this.dialogTitle || this._messages.dialogTitle,
2982
3077
  multiSelect: this.multiSelect,
2983
- selectedEntities: this.selectedEntity ? [this.selectedEntity] : []
3078
+ selectedEntities: this.selectedEntity ? [this.selectedEntity] : [],
3079
+ messages: this.dialogMessages,
2984
3080
  });
2985
3081
  if (result && result.selectedEntities.length > 0) {
2986
3082
  if (this.multiSelect) {
@@ -2992,7 +3088,7 @@ class EntitySelectInputComponent {
2992
3088
  }
2993
3089
  else {
2994
3090
  // Multiple selected - update display to show count
2995
- const displayText = `${result.selectedEntities.length} selected`;
3091
+ const displayText = `${result.selectedEntities.length} ${this._messages.selectedSuffix}`;
2996
3092
  this.searchFormControl.setValue(displayText, { emitEvent: false });
2997
3093
  this.selectedEntity = result.selectedEntities;
2998
3094
  this.onChange(result.selectedEntities);
@@ -3005,7 +3101,7 @@ class EntitySelectInputComponent {
3005
3101
  }
3006
3102
  }
3007
3103
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: EntitySelectInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3008
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.0", type: EntitySelectInputComponent, isStandalone: true, selector: "mm-entity-select-input", inputs: { dataSource: "dataSource", placeholder: "placeholder", minSearchLength: "minSearchLength", maxResults: "maxResults", debounceMs: "debounceMs", prefix: "prefix", dialogDataSource: "dialogDataSource", dialogTitle: "dialogTitle", multiSelect: "multiSelect", advancedSearchLabel: "advancedSearchLabel", disabled: "disabled", required: "required" }, outputs: { entitySelected: "entitySelected", entityCleared: "entityCleared", entitiesSelected: "entitiesSelected" }, providers: [
3104
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.0", type: EntitySelectInputComponent, isStandalone: true, selector: "mm-entity-select-input", inputs: { dataSource: "dataSource", placeholder: "placeholder", minSearchLength: "minSearchLength", maxResults: "maxResults", debounceMs: "debounceMs", prefix: "prefix", dialogDataSource: "dialogDataSource", dialogTitle: "dialogTitle", multiSelect: "multiSelect", advancedSearchLabel: "advancedSearchLabel", dialogMessages: "dialogMessages", messages: "messages", disabled: "disabled", required: "required" }, outputs: { entitySelected: "entitySelected", entityCleared: "entityCleared", entitiesSelected: "entitiesSelected" }, providers: [
3009
3105
  {
3010
3106
  provide: NG_VALUE_ACCESSOR,
3011
3107
  useExisting: forwardRef(() => EntitySelectInputComponent),
@@ -3024,7 +3120,7 @@ class EntitySelectInputComponent {
3024
3120
  [data]="filteredEntities"
3025
3121
  [loading]="isLoading"
3026
3122
  [disabled]="disabled"
3027
- [placeholder]="placeholder"
3123
+ [placeholder]="placeholder || _messages.placeholder"
3028
3124
  [suggest]="true"
3029
3125
  [clearButton]="true"
3030
3126
  [filterable]="true"
@@ -3045,10 +3141,10 @@ class EntitySelectInputComponent {
3045
3141
  <ng-template kendoAutoCompleteNoDataTemplate>
3046
3142
  <div class="no-data-message">
3047
3143
  <span *ngIf="!isLoading && searchFormControl.value && searchFormControl.value.length >= minSearchLength">
3048
- No entities found for "{{ searchFormControl.value }}"
3144
+ {{ formatMessage(_messages.noEntitiesFound, searchFormControl.value) }}
3049
3145
  </span>
3050
3146
  <span *ngIf="!isLoading && (!searchFormControl.value || searchFormControl.value.length < minSearchLength)">
3051
- Type at least {{ minSearchLength }} characters to search...
3147
+ {{ formatMessage(_messages.minCharactersHint, minSearchLength) }}
3052
3148
  </span>
3053
3149
  </div>
3054
3150
  </ng-template>
@@ -3057,7 +3153,7 @@ class EntitySelectInputComponent {
3057
3153
  <ng-template kendoAutoCompleteFooterTemplate *ngIf="dialogDataSource">
3058
3154
  <div class="advanced-search-footer" (click)="openAdvancedSearch($event)">
3059
3155
  <kendo-svg-icon [icon]="searchIcon" size="small"></kendo-svg-icon>
3060
- <span>{{ advancedSearchLabel }}</span>
3156
+ <span>{{ advancedSearchLabel || _messages.advancedSearchLabel }}</span>
3061
3157
  </div>
3062
3158
  </ng-template>
3063
3159
 
@@ -3069,7 +3165,7 @@ class EntitySelectInputComponent {
3069
3165
  type="button"
3070
3166
  [svgIcon]="searchIcon"
3071
3167
  [disabled]="disabled"
3072
- [title]="advancedSearchLabel"
3168
+ [title]="advancedSearchLabel || _messages.advancedSearchLabel"
3073
3169
  class="dialog-button"
3074
3170
  (click)="openAdvancedSearch()">
3075
3171
  </button>
@@ -3105,7 +3201,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
3105
3201
  [data]="filteredEntities"
3106
3202
  [loading]="isLoading"
3107
3203
  [disabled]="disabled"
3108
- [placeholder]="placeholder"
3204
+ [placeholder]="placeholder || _messages.placeholder"
3109
3205
  [suggest]="true"
3110
3206
  [clearButton]="true"
3111
3207
  [filterable]="true"
@@ -3126,10 +3222,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
3126
3222
  <ng-template kendoAutoCompleteNoDataTemplate>
3127
3223
  <div class="no-data-message">
3128
3224
  <span *ngIf="!isLoading && searchFormControl.value && searchFormControl.value.length >= minSearchLength">
3129
- No entities found for "{{ searchFormControl.value }}"
3225
+ {{ formatMessage(_messages.noEntitiesFound, searchFormControl.value) }}
3130
3226
  </span>
3131
3227
  <span *ngIf="!isLoading && (!searchFormControl.value || searchFormControl.value.length < minSearchLength)">
3132
- Type at least {{ minSearchLength }} characters to search...
3228
+ {{ formatMessage(_messages.minCharactersHint, minSearchLength) }}
3133
3229
  </span>
3134
3230
  </div>
3135
3231
  </ng-template>
@@ -3138,7 +3234,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
3138
3234
  <ng-template kendoAutoCompleteFooterTemplate *ngIf="dialogDataSource">
3139
3235
  <div class="advanced-search-footer" (click)="openAdvancedSearch($event)">
3140
3236
  <kendo-svg-icon [icon]="searchIcon" size="small"></kendo-svg-icon>
3141
- <span>{{ advancedSearchLabel }}</span>
3237
+ <span>{{ advancedSearchLabel || _messages.advancedSearchLabel }}</span>
3142
3238
  </div>
3143
3239
  </ng-template>
3144
3240
 
@@ -3150,7 +3246,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
3150
3246
  type="button"
3151
3247
  [svgIcon]="searchIcon"
3152
3248
  [disabled]="disabled"
3153
- [title]="advancedSearchLabel"
3249
+ [title]="advancedSearchLabel || _messages.advancedSearchLabel"
3154
3250
  class="dialog-button"
3155
3251
  (click)="openAdvancedSearch()">
3156
3252
  </button>
@@ -3179,6 +3275,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
3179
3275
  type: Input
3180
3276
  }], advancedSearchLabel: [{
3181
3277
  type: Input
3278
+ }], dialogMessages: [{
3279
+ type: Input
3280
+ }], messages: [{
3281
+ type: Input
3182
3282
  }], disabled: [{
3183
3283
  type: Input
3184
3284
  }], required: [{
@@ -3228,10 +3328,19 @@ class UnsavedChangesGuard {
3228
3328
  if (!component.hasUnsavedChanges()) {
3229
3329
  return true;
3230
3330
  }
3331
+ // Get optional translated messages from the component
3332
+ const msgs = typeof component.unsavedChangesMessages === 'function'
3333
+ ? component.unsavedChangesMessages()
3334
+ : undefined;
3335
+ const title = msgs?.title ?? 'Unsaved Changes';
3336
+ const buttonLabels = (msgs?.yesButton || msgs?.noButton || msgs?.cancelButton)
3337
+ ? { yes: msgs?.yesButton, no: msgs?.noButton, cancel: msgs?.cancelButton }
3338
+ : undefined;
3231
3339
  // Component has unsaved changes - ask user what to do
3232
3340
  if (typeof component.saveChanges === 'function') {
3233
3341
  // Component supports saving - show Yes/No/Cancel dialog
3234
- const result = await this.confirmationService.showYesNoCancelConfirmationDialog('Unsaved Changes', 'You have unsaved changes. Do you want to save before leaving?');
3342
+ const message = msgs?.savePrompt ?? 'You have unsaved changes. Do you want to save before leaving?';
3343
+ const result = await this.confirmationService.showYesNoCancelConfirmationDialog(title, message, buttonLabels);
3235
3344
  if (result === undefined) {
3236
3345
  // Dialog was closed without selection - cancel navigation
3237
3346
  return false;
@@ -3254,7 +3363,8 @@ class UnsavedChangesGuard {
3254
3363
  }
3255
3364
  else {
3256
3365
  // Component doesn't support saving - show simple Yes/No dialog
3257
- const confirmed = await this.confirmationService.showYesNoConfirmationDialog('Unsaved Changes', 'You have unsaved changes. Are you sure you want to leave? Your changes will be lost.');
3366
+ const message = msgs?.discardPrompt ?? 'You have unsaved changes. Are you sure you want to leave? Your changes will be lost.';
3367
+ const confirmed = await this.confirmationService.showYesNoConfirmationDialog(title, message, undefined, buttonLabels);
3258
3368
  return confirmed;
3259
3369
  }
3260
3370
  }
@@ -4958,5 +5068,5 @@ function provideMmSharedUi() {
4958
5068
  * Generated bundle index. Do not edit.
4959
5069
  */
4960
5070
 
4961
- export { BaseFormComponent, BaseTreeDetailComponent, BytesToSizePipe, CRON_PRESETS, ConfirmationService, CopyableTextComponent, CronBuilderComponent, CronHumanizerService, CronParserService, DEFAULT_CRON_BUILDER_CONFIG, DEFAULT_LIST_VIEW_MESSAGES, DEFAULT_RESPONSIVE_COLSPAN, DEFAULT_TIME_RANGE_LABELS, DataSourceBase, DataSourceTyped, EntitySelectDialogComponent, EntitySelectDialogService, EntitySelectInputComponent, FetchResultBase, FetchResultTyped, FileUploadService, HAS_UNSAVED_CHANGES, HOUR_INTERVALS, HierarchyDataSource, HierarchyDataSourceBase, ImportStrategyDialogComponent, ImportStrategyDialogResult, ImportStrategyDialogService, ImportStrategyDto, InputDialogComponent, InputService, ListViewComponent, MINUTE_INTERVALS, MessageDetailsDialogComponent, MessageDetailsDialogService, MessageListenerService, MmListViewDataBindingDirective, NotificationDisplayService, PascalCasePipe, ProgressValue, ProgressWindowComponent, ProgressWindowService, RELATIVE_WEEKS, SECOND_INTERVALS, SaveAsDialogComponent, SaveAsDialogService, TimeRangePickerComponent, TimeRangeUtils, TreeComponent, UnsavedChangesDirective, UnsavedChangesGuard, UploadFileDialogComponent, WEEKDAYS, WEEKDAY_ABBREVIATIONS, generateDayOfMonthOptions, generateHourOptions, generateMinuteOptions, provideMmSharedUi };
5071
+ export { BaseFormComponent, BaseTreeDetailComponent, ButtonTypes, BytesToSizePipe, CRON_PRESETS, ConfirmationService, ConfirmationWindowResult, CopyableTextComponent, CronBuilderComponent, CronHumanizerService, CronParserService, DEFAULT_CRON_BUILDER_CONFIG, DEFAULT_ENTITY_SELECT_DIALOG_MESSAGES, DEFAULT_ENTITY_SELECT_INPUT_MESSAGES, DEFAULT_LIST_VIEW_MESSAGES, DEFAULT_RESPONSIVE_COLSPAN, DEFAULT_TIME_RANGE_LABELS, DataSourceBase, DataSourceTyped, DialogType, EntitySelectDialogComponent, EntitySelectDialogService, EntitySelectInputComponent, FetchResultBase, FetchResultTyped, FileUploadResult, FileUploadService, FormTitleExtraDirective, HAS_UNSAVED_CHANGES, HOUR_INTERVALS, HierarchyDataSource, HierarchyDataSourceBase, ImportStrategyDialogComponent, ImportStrategyDialogResult, ImportStrategyDialogService, ImportStrategyDto, InputDialogComponent, InputService, ListViewComponent, MINUTE_INTERVALS, MessageDetailsDialogComponent, MessageDetailsDialogService, MessageListenerService, MmListViewDataBindingDirective, NotificationDisplayService, PascalCasePipe, ProgressValue, ProgressWindowComponent, ProgressWindowService, RELATIVE_WEEKS, SECOND_INTERVALS, SaveAsDialogComponent, SaveAsDialogService, TimeRangePickerComponent, TimeRangeUtils, TreeComponent, UnsavedChangesDirective, UnsavedChangesGuard, UploadFileDialogComponent, WEEKDAYS, WEEKDAY_ABBREVIATIONS, generateDayOfMonthOptions, generateHourOptions, generateMinuteOptions, provideMmSharedUi };
4962
5072
  //# sourceMappingURL=meshmakers-shared-ui.mjs.map