@yuuvis/client-framework 2.1.27 → 2.1.29

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,9 +1,9 @@
1
1
  import * as i1$2 from '@angular/common';
2
2
  import { CommonModule, DecimalPipe, DatePipe, NgClass } from '@angular/common';
3
3
  import * as i0 from '@angular/core';
4
- import { inject, signal, input, forwardRef, ChangeDetectionStrategy, Component, computed, effect, untracked, viewChild, DestroyRef, Input, output, ElementRef, NgModule } from '@angular/core';
4
+ import { inject, signal, input, forwardRef, ChangeDetectionStrategy, Component, ChangeDetectorRef, ElementRef, computed, effect, untracked, viewChild, DestroyRef, Input, output, NgModule } from '@angular/core';
5
5
  import * as i1 from '@angular/forms';
6
- import { FormBuilder, Validators, ReactiveFormsModule, NG_VALUE_ACCESSOR, FormsModule, FormGroup, FormControl } from '@angular/forms';
6
+ import { FormBuilder, Validators, ReactiveFormsModule, NG_VALUE_ACCESSOR, NG_VALIDATORS, FormsModule, FormGroup, FormControl } from '@angular/forms';
7
7
  import { MatButtonModule } from '@angular/material/button';
8
8
  import { MAT_DIALOG_DATA, MatDialogRef, MatDialogModule, MatDialog } from '@angular/material/dialog';
9
9
  import * as i3 from '@angular/material/icon';
@@ -15,11 +15,11 @@ import { MatTableModule } from '@angular/material/table';
15
15
  import * as i2 from '@yuuvis/client-core';
16
16
  import { SystemService, Situation, TranslateModule, ClipboardService, TranslateService, Operator, OperatorLabel, Utils, LocaleNumberPipe, FileSizePipe, Classification, UserService, YuvUser, IdmService, SearchUtils, LocaleDatePipe, ClassificationPrefix } from '@yuuvis/client-core';
17
17
  import { YUV_ICONS } from '@yuuvis/client-framework/icons';
18
- import { map, of, forkJoin } from 'rxjs';
18
+ import { YmtButtonDirective, YmtIconButtonDirective } from '@yuuvis/material';
19
+ import { map, timer, take, of, forkJoin } from 'rxjs';
19
20
  import { MatFormFieldModule, MatFormFieldControl } from '@angular/material/form-field';
20
21
  import { FormTranslateService, DialogComponent, AbstractMatFormField, injectNgControl } from '@yuuvis/client-framework/common';
21
22
  import { MetadataFormFieldComponent } from '@yuuvis/client-framework/metadata-form';
22
- import { YmtButtonDirective } from '@yuuvis/material';
23
23
  import { MatDatepickerModule } from '@angular/material/datepicker';
24
24
  import { MatInputModule } from '@angular/material/input';
25
25
  import { TranslateService as TranslateService$1, TranslateModule as TranslateModule$1 } from '@ngx-translate/core';
@@ -160,6 +160,8 @@ class DataGridComponent {
160
160
  this.#decimalPipe = inject(DecimalPipe);
161
161
  this.#datePipe = inject(DatePipe);
162
162
  this.translate = inject(TranslateService);
163
+ this.cd = inject(ChangeDetectorRef);
164
+ this.el = inject((ElementRef));
163
165
  this.situation = input(Situation.EDIT);
164
166
  this.formElement = input(undefined);
165
167
  this.formControl = input(undefined);
@@ -171,6 +173,8 @@ class DataGridComponent {
171
173
  this.dataSource = signal([]);
172
174
  this.tableLabel = computed(() => this.formElement()?.['label'] ?? '');
173
175
  this.selectedRow = signal(null);
176
+ this.isRequired = false;
177
+ this.isInvalid = false;
174
178
  this.initalTableUpdate = true;
175
179
  this.icons = {
176
180
  add: YUV_ICONS.add,
@@ -188,7 +192,7 @@ class DataGridComponent {
188
192
  // eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/no-unused-vars
189
193
  this.propagateChange = (fn) => { };
190
194
  // eslint-disable-next-line @typescript-eslint/no-empty-function
191
- this.validationChange = () => { };
195
+ this.onTouched = () => { };
192
196
  }
193
197
  #dialog;
194
198
  #clipboardService;
@@ -216,7 +220,7 @@ class DataGridComponent {
216
220
  copyLine(element) {
217
221
  this.#clipboardService.addToNavigatorClipBoard(JSON.stringify(element));
218
222
  }
219
- onMenuTriggert(element) {
223
+ onMenuTrigger(element) {
220
224
  this.selectedRow.set(element);
221
225
  }
222
226
  editRow(element) {
@@ -236,7 +240,6 @@ class DataGridComponent {
236
240
  const data = [...currentData];
237
241
  if (result) {
238
242
  data.push(result);
239
- console.log('Adding row with data:', result);
240
243
  const formElement = this.formElement();
241
244
  formElement && this.#updateTable(formElement['elements'], data);
242
245
  }
@@ -263,8 +266,8 @@ class DataGridComponent {
263
266
  if (elements.length > 0) {
264
267
  this.displayedColumns.set(elements.reduce((acc, el) => {
265
268
  acc.push({
266
- columnDef: el.label,
267
- header: el.label,
269
+ columnDef: el.name,
270
+ header: el.name,
268
271
  type: el.type,
269
272
  cell: (element) => (element.isAddRow ? '' : this.#cellValue(el, element[el.name]))
270
273
  });
@@ -286,7 +289,7 @@ class DataGridComponent {
286
289
  this.propagateChange = fn;
287
290
  }
288
291
  registerOnTouched(fn) {
289
- this.validationChange = fn;
292
+ this.onTouched = fn;
290
293
  }
291
294
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
292
295
  setDisabledState(isDisabled) {
@@ -295,30 +298,62 @@ class DataGridComponent {
295
298
  onValueChange(e) {
296
299
  this.propagateChange(e);
297
300
  }
301
+ validate(control) {
302
+ //Has to be delayed here because form init in object-form.component is also delayed
303
+ timer(300)
304
+ .pipe(take(1))
305
+ .subscribe(() => {
306
+ //There are multiple validators set on a formControl
307
+ //if there were a function reference available: const isRequired = Validators.required - we could use control.hasValidator(isRequired)
308
+ //this.isRequired = control.hasValidator(Validators.required);
309
+ this.isRequired = !!control._eoFormElement?.required;
310
+ this.isInvalid = !!control.errors && (control.touched || control.dirty);
311
+ this.cd.markForCheck();
312
+ });
313
+ return null;
314
+ }
315
+ onHostFocusOut(ev) {
316
+ const next = ev.relatedTarget;
317
+ const host = this.el.nativeElement;
318
+ if (next && host.contains(next))
319
+ return;
320
+ this.onTouched();
321
+ }
298
322
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: DataGridComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
299
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.12", type: DataGridComponent, isStandalone: true, selector: "yuv-data-grid", inputs: { situation: { classPropertyName: "situation", publicName: "situation", isSignal: true, isRequired: false, transformFunction: null }, formElement: { classPropertyName: "formElement", publicName: "formElement", isSignal: true, isRequired: false, transformFunction: null }, formControl: { classPropertyName: "formControl", publicName: "formControl", isSignal: true, isRequired: false, transformFunction: null }, classifications: { classPropertyName: "classifications", publicName: "classifications", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "yuv-data-grid" }, providers: [
323
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.12", type: DataGridComponent, isStandalone: true, selector: "yuv-data-grid", inputs: { situation: { classPropertyName: "situation", publicName: "situation", isSignal: true, isRequired: false, transformFunction: null }, formElement: { classPropertyName: "formElement", publicName: "formElement", isSignal: true, isRequired: false, transformFunction: null }, formControl: { classPropertyName: "formControl", publicName: "formControl", isSignal: true, isRequired: false, transformFunction: null }, classifications: { classPropertyName: "classifications", publicName: "classifications", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "focusout": "onHostFocusOut($event)" }, classAttribute: "yuv-data-grid" }, providers: [
300
324
  {
301
325
  provide: NG_VALUE_ACCESSOR,
302
326
  useExisting: forwardRef(() => DataGridComponent),
303
327
  multi: true
304
328
  },
329
+ {
330
+ provide: NG_VALIDATORS,
331
+ useExisting: forwardRef(() => DataGridComponent),
332
+ multi: true
333
+ },
305
334
  DecimalPipe,
306
335
  DatePipe
307
- ], ngImport: i0, template: "<header>\n <h3>{{ tableLabel() }}</h3>\n @if (!readonly()) {\n <button (click)=\"addRow()\" class=\"table-options-add-row\">\n <mat-icon>add</mat-icon>\n </button>\n }\n</header>\n@let displayedCol = displayedColumns();\n@let displayedColActions = displayedColumnsWithActions();\n<div class=\"table-wrapper\" [ngClass]=\"size()\">\n <table mat-table [dataSource]=\"dataSource()\" class=\"mat-elevation-z8\">\n @for (column of displayedCol; track column) {\n <ng-container [matColumnDef]=\"column.columnDef\">\n <th mat-header-cell *matHeaderCellDef [attr.aria-label]=\"column.header\" [title]=\"column.header\">{{ column.header }}</th>\n <td [ngClass]=\"{'number-cell': column.type === 'integer' || column.type === 'decimal'}\" mat-cell *matCellDef=\"let element\">{{ column.cell(element) }}</td>\n </ng-container>\n }\n\n @if (!readonly()) {\n <ng-container matColumnDef=\"actions\" stickyEnd>\n <th mat-header-cell *matHeaderCellDef class=\"actions-row\" aria-label=\"row actions\"></th>\n <td mat-cell *matCellDef=\"let element\" class=\"actions-row\">\n <!-- Only show the button in the last (empty) row -->\n <button class=\"table-options-menu-bar-item\" [matMenuTriggerFor]=\"menu\" (click)=\"onMenuTriggert(element)\">\n <mat-icon>more_vert</mat-icon>\n </button>\n </td>\n </ng-container>\n }\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColActions; sticky: ['header-1']\"></tr>\n @if (!readonly()) {\n <tr (dblclick)=\"editRow(row)\" [class.selected-row]=\"row === selectedRow()\" mat-row *matRowDef=\"let row; columns: displayedColActions\"></tr>\n } @else {\n <tr mat-row *matRowDef=\"let row; columns: displayedColActions\"></tr>\n }\n </table>\n</div>\n\n<mat-menu #menu=\"matMenu\">\n <button mat-menu-item (click)=\"copyLine(selectedRow())\">{{ 'yuv.form.element.data.grid.copy' | translate }}</button>\n <button mat-menu-item (click)=\"editRow(selectedRow())\">{{ 'yuv.form.element.data.grid.edit' | translate }}</button>\n <button mat-menu-item (click)=\"removeRow(selectedRow())\">{{ 'yuv.form.element.data.grid.remove' | translate }}</button>\n</mat-menu>\n", styles: [":host{--table-size-small: 200px;--table-size-medium: 400px;--table-size-large: 600px;--table-size-extra-large: 800px;border:1px solid var(--ymt-outline-variant);max-width:100%;overflow:auto;width:100%}:host header{display:flex;justify-content:space-between;background-color:var(--ymt-surface-panel-grey)}:host header h3{text-align:start;-webkit-user-select:none;user-select:none;flex:0 1 auto;padding:1rem;margin:0;color:var(--ymt-text-color-subtle);border-radius:2px;font:var(--ymt-font-body-subtle);font-weight:400}:host .actions-row{max-width:230px;padding:0}:host.yuv-data-grid{display:block}:host.yuv-data-grid .table-wrapper{overflow:auto;position:relative;white-space:nowrap}:host.yuv-data-grid .table-wrapper.small{height:var(--table-size-small)}:host.yuv-data-grid .table-wrapper.medium{height:var(--table-size-medium)}:host.yuv-data-grid .table-wrapper.large{height:var(--table-size-large)}:host.yuv-data-grid .table-wrapper.extra-large{height:var(--table-size-extra-large)}:host.yuv-data-grid ::ng-deep .cdk-header-cell:not(:last-child){padding:.5rem 1rem}:host.yuv-data-grid ::ng-deep table{border-spacing:0}:host.yuv-data-grid ::ng-deep th{border-bottom:1px solid var(--ymt-outline-variant);border-right:1px solid var(--ymt-outline-variant);padding:.5rem 0}:host.yuv-data-grid ::ng-deep thead{background-color:var(--ymt-surface-panel)}:host.yuv-data-grid ::ng-deep tr.cdk-row{cursor:pointer;-webkit-user-select:none;user-select:none;transition:color .2s ease-in-out}:host.yuv-data-grid ::ng-deep tr.cdk-row:hover td{border-top:1px solid var(--ymt-surface-panel);border-bottom:1px solid var(--ymt-surface-panel)}:host.yuv-data-grid ::ng-deep tr.cdk-row:hover:has(.actions-row) td.cdk-cell.actions-row.sticky{opacity:1}:host.yuv-data-grid ::ng-deep tr.cdk-row.selected-row{color:var(--ymt-text-color-subtle)}:host.yuv-data-grid ::ng-deep tr.cdk-row td{border-bottom:1px solid transparent;border-top:1px solid transparent}:host.yuv-data-grid ::ng-deep tr.cdk-row td:not(:last-child){padding:.5rem 1rem}:host.yuv-data-grid ::ng-deep tr.cdk-row td.number-cell{text-align:right}:host.yuv-data-grid ::ng-deep .cdk-table .cdk-header-row th[role=columnheader]{font-weight:500}:host.yuv-data-grid th.cdk-header-cell.sticky-column{position:sticky;top:0;background-color:var(--ymt-surface-panel)}:host.yuv-data-grid td.cdk-cell.actions-row.sticky{position:sticky;right:0;opacity:0;background-color:var(--ymt-surface-panel);transition:opacity .2s ease-in-out}:host .table-options-menu-bar-item,:host .table-options-add-row{cursor:pointer;border:none;-webkit-user-select:none;user-select:none;min-width:34px;line-height:26px;padding:0;display:flex;align-items:center;justify-content:center}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i2$1.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i2$1.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i2$1.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i4.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i4.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i4.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i4.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i4.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i4.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i4.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i4.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i4.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i4.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
336
+ ], ngImport: i0, template: "\n<fieldset [attr.aria-required]=\"isRequired\" [attr.aria-invalid]=\"isInvalid\" >\n <legend class=\"ymt-hide-sr\">{{ tableLabel() }} @if(isRequired) {*}</legend>\n <header class=\"yuv-data-grid__header\">\n <span class=\"yuv-data-grid__header-title\" [ngClass]=\"{'yuv-data-grid__header-title--invalid' : isInvalid}\" aria-hidden=\"true\">\n {{ tableLabel() }} @if(isRequired) {*}\n </span>\n\n @if (!readonly()) {\n <button ymtIconButton (click)=\"addRow()\" class=\"yuv-data-grid__header-action\">\n <mat-icon>add</mat-icon>\n </button>\n }\n </header>\n\n @let displayedCol = displayedColumns();\n @let displayedColActions = displayedColumnsWithActions();\n\n <div class=\"yuv-data-grid__table\" [ngClass]=\"size()\">\n <table mat-table [dataSource]=\"dataSource()\" class=\"mat-elevation-z8\">\n <caption class=\"ymt-hide-sr\">{{ tableLabel() }}</caption>\n\n @for (column of displayedCol; track column) {\n <ng-container [matColumnDef]=\"column.columnDef\">\n <th mat-header-cell *matHeaderCellDef [attr.aria-label]=\"column.header\" [title]=\"column.header\">{{ column.header }}</th>\n <td [ngClass]=\"{'number-cell': column.type === 'integer' || column.type === 'decimal', 'yuv-data-grid__cell--editable': !readonly()}\" mat-cell *matCellDef=\"let element\">{{ column.cell(element) }}</td>\n </ng-container>\n }\n\n @if (!readonly()) {\n <ng-container matColumnDef=\"actions\" stickyEnd>\n <th mat-header-cell *matHeaderCellDef aria-label=\"row actions\"></th>\n <td class=\"yuv-data-grid__cell--editable\" mat-cell *matCellDef=\"let element\">\n <div class=\"yuv-data-grid__table-actions\">\n <!-- Only show the button in the last (empty) row -->\n <button ymtIconButton icon-button-size=\"small\" class=\"table-options-menu-bar-item\" [matMenuTriggerFor]=\"menu\" (click)=\"onMenuTrigger(element)\">\n <mat-icon>more_vert</mat-icon>\n </button>\n </div>\n </td>\n </ng-container>\n }\n <tr mat-header-row *matHeaderRowDef=\"displayedColActions; sticky: ['header-1']\"></tr>\n\n @if (!readonly()) {\n <tr (dblclick)=\"editRow(row)\" [class.selected-row]=\"row === selectedRow()\" mat-row *matRowDef=\"let row; columns: displayedColActions\"></tr>\n } @else {\n <tr mat-row *matRowDef=\"let row; columns: displayedColActions\"></tr>\n }\n\n </table>\n </div>\n</fieldset>\n<mat-menu #menu=\"matMenu\">\n <button mat-menu-item (click)=\"copyLine(selectedRow())\">{{ 'yuv.form.element.data.grid.copy' | translate }}</button>\n <button mat-menu-item (click)=\"editRow(selectedRow())\">{{ 'yuv.form.element.data.grid.edit' | translate }}</button>\n <button mat-menu-item (click)=\"removeRow(selectedRow())\">{{ 'yuv.form.element.data.grid.remove' | translate }}</button>\n</mat-menu>\n", styles: [":host{--table-size-small: 200px;--table-size-medium: 400px;--table-size-large: 600px;--table-size-extra-large: 800px;max-width:100%;width:100%}:host .yuv-data-grid__header{display:flex;justify-content:space-between;margin-block-end:var(--ymt-spacing-m)}:host .yuv-data-grid__header-title--invalid{background-color:var(--ymt-danger-container);color:var(--ymt-on-danger-container);align-self:baseline}:host .yuv-data-grid__cell--editable{-webkit-user-select:none;user-select:none}:host .yuv-data-grid__table{overflow:auto;white-space:nowrap}:host .yuv-data-grid__table.small{height:var(--table-size-small)}:host .yuv-data-grid__table.medium{height:var(--table-size-medium)}:host .yuv-data-grid__table.large{height:var(--table-size-large)}:host .yuv-data-grid__table.extra-large{height:var(--table-size-extra-large)}:host .yuv-data-grid__table-actions{display:flex;align-items:center;justify-content:flex-end}:host.yuv-data-grid{display:block}:host.yuv-data-grid ::ng-deep tr.cdk-row td.number-cell{text-align:right}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i2$1.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i2$1.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i2$1.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i4.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i4.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i4.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i4.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i4.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i4.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i4.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i4.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i4.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i4.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "directive", type: YmtIconButtonDirective, selector: "button[ymtIconButton],button[ymt-icon-button],a[ymtIconButton],a[ymt-icon-button]", inputs: ["disabled", "disableRipple", "aria-disabled", "disabledInteractive", "icon-button-size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
308
337
  }
309
338
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: DataGridComponent, decorators: [{
310
339
  type: Component,
311
- args: [{ selector: 'yuv-data-grid', standalone: true, imports: [NgClass, TranslateModule, ...MATERIAL], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
340
+ args: [{ selector: 'yuv-data-grid', standalone: true, imports: [NgClass, TranslateModule, ...MATERIAL, YmtIconButtonDirective], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
312
341
  {
313
342
  provide: NG_VALUE_ACCESSOR,
314
343
  useExisting: forwardRef(() => DataGridComponent),
315
344
  multi: true
316
345
  },
346
+ {
347
+ provide: NG_VALIDATORS,
348
+ useExisting: forwardRef(() => DataGridComponent),
349
+ multi: true
350
+ },
317
351
  DecimalPipe,
318
352
  DatePipe
319
353
  ], host: {
320
- class: 'yuv-data-grid'
321
- }, template: "<header>\n <h3>{{ tableLabel() }}</h3>\n @if (!readonly()) {\n <button (click)=\"addRow()\" class=\"table-options-add-row\">\n <mat-icon>add</mat-icon>\n </button>\n }\n</header>\n@let displayedCol = displayedColumns();\n@let displayedColActions = displayedColumnsWithActions();\n<div class=\"table-wrapper\" [ngClass]=\"size()\">\n <table mat-table [dataSource]=\"dataSource()\" class=\"mat-elevation-z8\">\n @for (column of displayedCol; track column) {\n <ng-container [matColumnDef]=\"column.columnDef\">\n <th mat-header-cell *matHeaderCellDef [attr.aria-label]=\"column.header\" [title]=\"column.header\">{{ column.header }}</th>\n <td [ngClass]=\"{'number-cell': column.type === 'integer' || column.type === 'decimal'}\" mat-cell *matCellDef=\"let element\">{{ column.cell(element) }}</td>\n </ng-container>\n }\n\n @if (!readonly()) {\n <ng-container matColumnDef=\"actions\" stickyEnd>\n <th mat-header-cell *matHeaderCellDef class=\"actions-row\" aria-label=\"row actions\"></th>\n <td mat-cell *matCellDef=\"let element\" class=\"actions-row\">\n <!-- Only show the button in the last (empty) row -->\n <button class=\"table-options-menu-bar-item\" [matMenuTriggerFor]=\"menu\" (click)=\"onMenuTriggert(element)\">\n <mat-icon>more_vert</mat-icon>\n </button>\n </td>\n </ng-container>\n }\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColActions; sticky: ['header-1']\"></tr>\n @if (!readonly()) {\n <tr (dblclick)=\"editRow(row)\" [class.selected-row]=\"row === selectedRow()\" mat-row *matRowDef=\"let row; columns: displayedColActions\"></tr>\n } @else {\n <tr mat-row *matRowDef=\"let row; columns: displayedColActions\"></tr>\n }\n </table>\n</div>\n\n<mat-menu #menu=\"matMenu\">\n <button mat-menu-item (click)=\"copyLine(selectedRow())\">{{ 'yuv.form.element.data.grid.copy' | translate }}</button>\n <button mat-menu-item (click)=\"editRow(selectedRow())\">{{ 'yuv.form.element.data.grid.edit' | translate }}</button>\n <button mat-menu-item (click)=\"removeRow(selectedRow())\">{{ 'yuv.form.element.data.grid.remove' | translate }}</button>\n</mat-menu>\n", styles: [":host{--table-size-small: 200px;--table-size-medium: 400px;--table-size-large: 600px;--table-size-extra-large: 800px;border:1px solid var(--ymt-outline-variant);max-width:100%;overflow:auto;width:100%}:host header{display:flex;justify-content:space-between;background-color:var(--ymt-surface-panel-grey)}:host header h3{text-align:start;-webkit-user-select:none;user-select:none;flex:0 1 auto;padding:1rem;margin:0;color:var(--ymt-text-color-subtle);border-radius:2px;font:var(--ymt-font-body-subtle);font-weight:400}:host .actions-row{max-width:230px;padding:0}:host.yuv-data-grid{display:block}:host.yuv-data-grid .table-wrapper{overflow:auto;position:relative;white-space:nowrap}:host.yuv-data-grid .table-wrapper.small{height:var(--table-size-small)}:host.yuv-data-grid .table-wrapper.medium{height:var(--table-size-medium)}:host.yuv-data-grid .table-wrapper.large{height:var(--table-size-large)}:host.yuv-data-grid .table-wrapper.extra-large{height:var(--table-size-extra-large)}:host.yuv-data-grid ::ng-deep .cdk-header-cell:not(:last-child){padding:.5rem 1rem}:host.yuv-data-grid ::ng-deep table{border-spacing:0}:host.yuv-data-grid ::ng-deep th{border-bottom:1px solid var(--ymt-outline-variant);border-right:1px solid var(--ymt-outline-variant);padding:.5rem 0}:host.yuv-data-grid ::ng-deep thead{background-color:var(--ymt-surface-panel)}:host.yuv-data-grid ::ng-deep tr.cdk-row{cursor:pointer;-webkit-user-select:none;user-select:none;transition:color .2s ease-in-out}:host.yuv-data-grid ::ng-deep tr.cdk-row:hover td{border-top:1px solid var(--ymt-surface-panel);border-bottom:1px solid var(--ymt-surface-panel)}:host.yuv-data-grid ::ng-deep tr.cdk-row:hover:has(.actions-row) td.cdk-cell.actions-row.sticky{opacity:1}:host.yuv-data-grid ::ng-deep tr.cdk-row.selected-row{color:var(--ymt-text-color-subtle)}:host.yuv-data-grid ::ng-deep tr.cdk-row td{border-bottom:1px solid transparent;border-top:1px solid transparent}:host.yuv-data-grid ::ng-deep tr.cdk-row td:not(:last-child){padding:.5rem 1rem}:host.yuv-data-grid ::ng-deep tr.cdk-row td.number-cell{text-align:right}:host.yuv-data-grid ::ng-deep .cdk-table .cdk-header-row th[role=columnheader]{font-weight:500}:host.yuv-data-grid th.cdk-header-cell.sticky-column{position:sticky;top:0;background-color:var(--ymt-surface-panel)}:host.yuv-data-grid td.cdk-cell.actions-row.sticky{position:sticky;right:0;opacity:0;background-color:var(--ymt-surface-panel);transition:opacity .2s ease-in-out}:host .table-options-menu-bar-item,:host .table-options-add-row{cursor:pointer;border:none;-webkit-user-select:none;user-select:none;min-width:34px;line-height:26px;padding:0;display:flex;align-items:center;justify-content:center}\n"] }]
354
+ class: 'yuv-data-grid',
355
+ '(focusout)': 'onHostFocusOut($event)'
356
+ }, template: "\n<fieldset [attr.aria-required]=\"isRequired\" [attr.aria-invalid]=\"isInvalid\" >\n <legend class=\"ymt-hide-sr\">{{ tableLabel() }} @if(isRequired) {*}</legend>\n <header class=\"yuv-data-grid__header\">\n <span class=\"yuv-data-grid__header-title\" [ngClass]=\"{'yuv-data-grid__header-title--invalid' : isInvalid}\" aria-hidden=\"true\">\n {{ tableLabel() }} @if(isRequired) {*}\n </span>\n\n @if (!readonly()) {\n <button ymtIconButton (click)=\"addRow()\" class=\"yuv-data-grid__header-action\">\n <mat-icon>add</mat-icon>\n </button>\n }\n </header>\n\n @let displayedCol = displayedColumns();\n @let displayedColActions = displayedColumnsWithActions();\n\n <div class=\"yuv-data-grid__table\" [ngClass]=\"size()\">\n <table mat-table [dataSource]=\"dataSource()\" class=\"mat-elevation-z8\">\n <caption class=\"ymt-hide-sr\">{{ tableLabel() }}</caption>\n\n @for (column of displayedCol; track column) {\n <ng-container [matColumnDef]=\"column.columnDef\">\n <th mat-header-cell *matHeaderCellDef [attr.aria-label]=\"column.header\" [title]=\"column.header\">{{ column.header }}</th>\n <td [ngClass]=\"{'number-cell': column.type === 'integer' || column.type === 'decimal', 'yuv-data-grid__cell--editable': !readonly()}\" mat-cell *matCellDef=\"let element\">{{ column.cell(element) }}</td>\n </ng-container>\n }\n\n @if (!readonly()) {\n <ng-container matColumnDef=\"actions\" stickyEnd>\n <th mat-header-cell *matHeaderCellDef aria-label=\"row actions\"></th>\n <td class=\"yuv-data-grid__cell--editable\" mat-cell *matCellDef=\"let element\">\n <div class=\"yuv-data-grid__table-actions\">\n <!-- Only show the button in the last (empty) row -->\n <button ymtIconButton icon-button-size=\"small\" class=\"table-options-menu-bar-item\" [matMenuTriggerFor]=\"menu\" (click)=\"onMenuTrigger(element)\">\n <mat-icon>more_vert</mat-icon>\n </button>\n </div>\n </td>\n </ng-container>\n }\n <tr mat-header-row *matHeaderRowDef=\"displayedColActions; sticky: ['header-1']\"></tr>\n\n @if (!readonly()) {\n <tr (dblclick)=\"editRow(row)\" [class.selected-row]=\"row === selectedRow()\" mat-row *matRowDef=\"let row; columns: displayedColActions\"></tr>\n } @else {\n <tr mat-row *matRowDef=\"let row; columns: displayedColActions\"></tr>\n }\n\n </table>\n </div>\n</fieldset>\n<mat-menu #menu=\"matMenu\">\n <button mat-menu-item (click)=\"copyLine(selectedRow())\">{{ 'yuv.form.element.data.grid.copy' | translate }}</button>\n <button mat-menu-item (click)=\"editRow(selectedRow())\">{{ 'yuv.form.element.data.grid.edit' | translate }}</button>\n <button mat-menu-item (click)=\"removeRow(selectedRow())\">{{ 'yuv.form.element.data.grid.remove' | translate }}</button>\n</mat-menu>\n", styles: [":host{--table-size-small: 200px;--table-size-medium: 400px;--table-size-large: 600px;--table-size-extra-large: 800px;max-width:100%;width:100%}:host .yuv-data-grid__header{display:flex;justify-content:space-between;margin-block-end:var(--ymt-spacing-m)}:host .yuv-data-grid__header-title--invalid{background-color:var(--ymt-danger-container);color:var(--ymt-on-danger-container);align-self:baseline}:host .yuv-data-grid__cell--editable{-webkit-user-select:none;user-select:none}:host .yuv-data-grid__table{overflow:auto;white-space:nowrap}:host .yuv-data-grid__table.small{height:var(--table-size-small)}:host .yuv-data-grid__table.medium{height:var(--table-size-medium)}:host .yuv-data-grid__table.large{height:var(--table-size-large)}:host .yuv-data-grid__table.extra-large{height:var(--table-size-extra-large)}:host .yuv-data-grid__table-actions{display:flex;align-items:center;justify-content:flex-end}:host.yuv-data-grid{display:block}:host.yuv-data-grid ::ng-deep tr.cdk-row td.number-cell{text-align:right}\n"] }]
322
357
  }] });
323
358
 
324
359
  class DatetimeComponent extends AbstractMatFormField {