@meshmakers/shared-ui 3.4.1050 → 3.4.1080

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -39,7 +39,7 @@ npm run build:shared-ui
39
39
  npm run lint:shared-ui
40
40
 
41
41
  # Run tests
42
- npm test -- --project=@meshmakers/shared-ui --watch=false
42
+ npm run test:shared-ui
43
43
  ```
44
44
 
45
45
  ## Architecture
@@ -124,10 +124,7 @@ class UploadFileDialogComponent extends DialogContentBase {
124
124
  if (!file) {
125
125
  return;
126
126
  }
127
- console.debug("type: " + file.type);
128
- console.debug("name: " + file.name);
129
127
  const extension = file.name.substring(file.name.lastIndexOf('.')).toLowerCase();
130
- console.debug("extension: " + extension);
131
128
  if ((allowedFileExtensions.includes(extension) || allowedMimeTypes.includes(file.type)) ||
132
129
  allowedFileExtensions.length > 0 && allowedMimeTypes.length > 0) {
133
130
  this.selectedFile = file;
@@ -142,9 +139,9 @@ class UploadFileDialogComponent extends DialogContentBase {
142
139
  this.notificationService.show({
143
140
  content: 'File type not supported!',
144
141
  hideAfter: 600,
145
- position: { horizontal: "right", vertical: "top" },
146
- animation: { type: "fade", duration: 400 },
147
- type: { style: "error", icon: true },
142
+ position: { horizontal: 'right', vertical: 'top' },
143
+ animation: { type: 'fade', duration: 400 },
144
+ type: { style: 'error', icon: true },
148
145
  });
149
146
  }
150
147
  }
@@ -165,8 +162,8 @@ class UploadFileDialogComponent extends DialogContentBase {
165
162
  onCancel() {
166
163
  this.dialogRef.close(null);
167
164
  }
168
- upload = upload;
169
- deleteIcon = deleteIcon;
165
+ get upload() { return upload; }
166
+ get deleteIcon() { return deleteIcon; }
170
167
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: UploadFileDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
171
168
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.5", type: UploadFileDialogComponent, isStandalone: true, selector: "mm-upload-file-dialog", inputs: { message: "message", mimeTypes: "mimeTypes", fileExtensions: "fileExtensions" }, viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<div\n class=\"file-upload-wrapper\"\n [class.success]=\"uploadSuccess\"\n [class.error]=\"uploadError\"\n (drop)=\"onFileDrop($event)\"\n (dragover)=\"onDragOver($event)\"\n>\n <input type=\"file\" accept=\"{{fileExtensions}}\" (change)=\"onFileChange($event)\" hidden #fileInput/>\n <div class=\"file-dropper\" (click)=\"fileInput.click()\">\n <kendo-svgicon [icon]=\"upload\" size=\"xxxlarge\"></kendo-svgicon>\n <p>{{ message }}</p>\n <div *ngIf=\"fileName()\">\n <div *ngIf=\"selectedFile\">\n <p>\n <span class=\"image-name\">{{ fileName() }}</span> ({{\n fileSize()\n }} KB)\n </p>\n <kendo-svgicon class=\"delete-icon\" [icon]=\"deleteIcon\" size=\"xlarge\"></kendo-svgicon>\n </div>\n </div>\n </div>\n</div>\n<kendo-dialog-actions>\n <button kendoButton (click)=\"onOk()\" [disabled]=\"!selectedFile\" themeColor=\"primary\">Upload</button>\n <button kendoButton (click)=\"onCancel()\">Cancel</button>\n</kendo-dialog-actions>\n\n\n\n", styles: [".file-upload-wrapper{display:flex;justify-content:center;align-items:center;flex-direction:column;border:2px dashed #ccc;padding:1rem;margin-bottom:1rem;margin-left:1rem;margin-right:1rem;border-radius:10px;cursor:pointer}.file-upload-wrapper.success{border-color:green}.file-upload-wrapper.error{border-color:red}.file-dropper{display:flex;flex-direction:column;align-items:center}.image-name{font-weight:700}.image-preview{max-width:100%;height:auto;margin-bottom:.5rem;border-radius:10px}.delete-icon{cursor:pointer;color:red}\n"], dependencies: [{ kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "component", type: DialogActionsComponent, selector: "kendo-dialog-actions", inputs: ["actions", "layout"], outputs: ["action"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: SVGIconComponent, selector: "kendo-svg-icon, kendo-svgicon", inputs: ["icon", "variant"], exportAs: ["kendoSVGIcon"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
172
169
  }
@@ -393,9 +390,9 @@ const DEFAULT_INPUT_DIALOG_MESSAGES = {
393
390
  class InputDialogComponent extends DialogContentBase {
394
391
  dialogRef;
395
392
  buttonOkText = DEFAULT_INPUT_DIALOG_MESSAGES.ok;
396
- message = "";
393
+ message = '';
397
394
  placeholder = DEFAULT_INPUT_DIALOG_MESSAGES.placeholder;
398
- inputValue = "";
395
+ inputValue = '';
399
396
  _messages = { ...DEFAULT_INPUT_DIALOG_MESSAGES };
400
397
  set messages(value) {
401
398
  this._messages = { ...DEFAULT_INPUT_DIALOG_MESSAGES, ...(value ?? {}) };
@@ -448,7 +445,7 @@ class InputService {
448
445
  const dialogRef = this.dialogService.open({
449
446
  title,
450
447
  content: InputDialogComponent,
451
- autoFocusedElement: "input"
448
+ autoFocusedElement: 'input'
452
449
  });
453
450
  const component = dialogRef.content.instance;
454
451
  component.message = message;
@@ -784,7 +781,7 @@ class WindowStateService {
784
781
  height: Math.min(size.height, maxHeight)
785
782
  };
786
783
  }
787
- /** Seam for tests — window.innerWidth/innerHeight are not assignable in Karma. */
784
+ /** Seam for tests — window.innerWidth/innerHeight are not assignable in jsdom. */
788
785
  viewportSize() {
789
786
  return { width: window.innerWidth, height: window.innerHeight };
790
787
  }
@@ -880,7 +877,9 @@ class WindowStateService {
880
877
  if (!el) {
881
878
  el = document.createElement('div');
882
879
  el.className = 'mm-window-backdrop';
883
- el.style.cssText = 'position:fixed;inset:0;background:rgba(0,0,0,0.4);z-index:11499;display:none;';
880
+ // background-color, not the `background` shorthand: jsdom's CSSOM (cssstyle) drops the
881
+ // entire declaration block when the shorthand carries an rgba() value. Same rendering.
882
+ el.style.cssText = 'position:fixed;inset:0;background-color:rgba(0,0,0,0.4);z-index:11499;display:none;';
884
883
  document.body.appendChild(el);
885
884
  }
886
885
  return el;
@@ -1363,7 +1362,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
1363
1362
  type: Pipe,
1364
1363
  args: [{
1365
1364
  standalone: true,
1366
- name: "pascalCase"
1365
+ name: 'pascalCase'
1367
1366
  }]
1368
1367
  }] });
1369
1368
 
@@ -1644,7 +1643,7 @@ class MmListViewDataBindingDirective extends DataBindingDirective {
1644
1643
  if (stored.filter) {
1645
1644
  this.filter = stored.filter;
1646
1645
  }
1647
- if (typeof stored.skip === "number") {
1646
+ if (typeof stored.skip === 'number') {
1648
1647
  this.skip = stored.skip;
1649
1648
  }
1650
1649
  if (stored.textSearch) {
@@ -1662,7 +1661,7 @@ class MmListViewDataBindingDirective extends DataBindingDirective {
1662
1661
  */
1663
1662
  resetState() {
1664
1663
  this.sort = [];
1665
- this.filter = { logic: "and", filters: [] };
1664
+ this.filter = { logic: 'and', filters: [] };
1666
1665
  this.skip = 0;
1667
1666
  this._textSearchValue = null;
1668
1667
  const key = this.stateKey();
@@ -1738,7 +1737,7 @@ class MmListViewDataBindingDirective extends DataBindingDirective {
1738
1737
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: MmListViewDataBindingDirective, decorators: [{
1739
1738
  type: Directive,
1740
1739
  args: [{
1741
- selector: "[mmListViewDataBinding]",
1740
+ selector: '[mmListViewDataBinding]',
1742
1741
  }]
1743
1742
  }], ctorParameters: () => [] });
1744
1743
 
@@ -1966,8 +1965,8 @@ class ListViewComponent extends CommandBaseService {
1966
1965
  this._contextMenuCommandItems = commandItems;
1967
1966
  this._contextMenuItems = this.buildMenuItems(commandItems);
1968
1967
  }
1969
- excelExportFileName = "Export.xlsx";
1970
- pdfExportFileName = "Export.pdf";
1968
+ excelExportFileName = 'Export.xlsx';
1969
+ pdfExportFileName = 'Export.pdf';
1971
1970
  pageable = {
1972
1971
  buttonCount: 5,
1973
1972
  info: true,
@@ -2105,7 +2104,7 @@ class ListViewComponent extends CommandBaseService {
2105
2104
  this._columns = [];
2106
2105
  for (const column of cols) {
2107
2106
  if (typeof column === 'string') {
2108
- this._columns.push({ field: column, dataType: "text" });
2107
+ this._columns.push({ field: column, dataType: 'text' });
2109
2108
  }
2110
2109
  else {
2111
2110
  this._columns.push(column);
@@ -2570,7 +2569,7 @@ class ListViewComponent extends CommandBaseService {
2570
2569
  }
2571
2570
  }
2572
2571
  onCellClick(e) {
2573
- if (e.type === "contextmenu" && this.contextMenuType == 'contextMenu') {
2572
+ if (e.type === 'contextmenu' && this.contextMenuType === 'contextMenu') {
2574
2573
  const originalEvent = e.originalEvent;
2575
2574
  originalEvent.preventDefault();
2576
2575
  this._contextMenuSelectedRow = e.dataItem;
@@ -2749,7 +2748,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
2749
2748
  args: [MmListViewDataBindingDirective]
2750
2749
  }], gridContextMenu: [{
2751
2750
  type: ViewChild,
2752
- args: ["gridmenu"]
2751
+ args: ['gridmenu']
2753
2752
  }], rowClicked: [{
2754
2753
  type: Output
2755
2754
  }], pageSize: [{
@@ -5894,20 +5893,28 @@ class CronBuilderComponent {
5894
5893
  }, /* @ts-ignore */
5895
5894
  ...(ngDevMode ? [{ debugName: "presetsByCategory" }] : /* istanbul ignore next */ []));
5896
5895
  // --- Dropdown options ---
5897
- secondIntervalOptions = SECOND_INTERVALS;
5898
- minuteIntervalOptions = MINUTE_INTERVALS;
5899
- hourIntervalOptions = HOUR_INTERVALS;
5900
- weekdayOptions = WEEKDAYS;
5901
- weekdayAbbreviations = WEEKDAY_ABBREVIATIONS;
5902
- relativeWeekOptions = RELATIVE_WEEKS;
5903
- hourOptions = generateHourOptions();
5904
- minuteOptions = generateMinuteOptions();
5905
- dayOfMonthOptions = generateDayOfMonthOptions();
5896
+ get secondIntervalOptions() { return SECOND_INTERVALS; }
5897
+ get minuteIntervalOptions() { return MINUTE_INTERVALS; }
5898
+ get hourIntervalOptions() { return HOUR_INTERVALS; }
5899
+ get weekdayOptions() { return WEEKDAYS; }
5900
+ get weekdayAbbreviations() { return WEEKDAY_ABBREVIATIONS; }
5901
+ get relativeWeekOptions() { return RELATIVE_WEEKS; }
5902
+ hourOptions;
5903
+ minuteOptions;
5904
+ dayOfMonthOptions;
5906
5905
  // --- Tab mapping ---
5907
5906
  tabIndexToType = [
5908
5907
  'seconds', 'minutes', 'hourly', 'daily', 'weekly', 'monthly', 'custom'
5909
5908
  ];
5910
5909
  constructor() {
5910
+ // Assigned here rather than as field initialisers: a class field initialised from a
5911
+ // relative import reads `undefined` under the Vitest module runner, so calling the
5912
+ // imported generator at field-init time would throw (see CLAUDE.md,
5913
+ // "Vite/esbuild class-field snapshot"). A getter is not an option — the template reads
5914
+ // these three every change detection cycle and would rebuild the option arrays each time.
5915
+ this.hourOptions = generateHourOptions();
5916
+ this.minuteOptions = generateMinuteOptions();
5917
+ this.dayOfMonthOptions = generateDayOfMonthOptions();
5911
5918
  // Effect to generate expression when schedule values change
5912
5919
  effect(() => {
5913
5920
  const type = this.scheduleType();
@@ -6325,12 +6332,16 @@ class ImportStrategyDialogResult {
6325
6332
  class ImportStrategyDialogComponent extends DialogContentBase {
6326
6333
  dialogRef;
6327
6334
  message = '';
6328
- selectedStrategy = ImportStrategyDto.Upsert;
6329
- ImportStrategyDto = ImportStrategyDto;
6335
+ selectedStrategy;
6336
+ get ImportStrategyDto() { return ImportStrategyDto; }
6330
6337
  constructor() {
6331
6338
  const dialogRef = inject(DialogRef);
6332
6339
  super(dialogRef);
6333
6340
  this.dialogRef = dialogRef;
6341
+ // Assigned here rather than as a field initialiser: a class field initialised from a
6342
+ // relative import reads `undefined` under the Vitest module runner, so the member access
6343
+ // would throw (see CLAUDE.md, "Vite/esbuild class-field snapshot").
6344
+ this.selectedStrategy = ImportStrategyDto.Upsert;
6334
6345
  }
6335
6346
  onImport() {
6336
6347
  this.dialogRef.close(new ImportStrategyDialogResult(this.selectedStrategy));