@openmfp/ngx 0.14.11 → 0.15.0

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,6 +1,6 @@
1
1
  import { JSONPath } from 'jsonpath-plus';
2
2
  import * as i0 from '@angular/core';
3
- import { input, computed, CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, Component, output, signal, ViewEncapsulation, inject, effect, viewChild, Injector, afterNextRender, Injectable, reflectComponentType, isStandalone, isDevMode, ViewContainerRef, Renderer2, ElementRef, model, SecurityContext, linkedSignal } from '@angular/core';
3
+ import { input, computed, CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, Component, output, signal, ViewEncapsulation, linkedSignal, forwardRef, inject, effect, viewChild, Injector, afterNextRender, Injectable, reflectComponentType, isStandalone, isDevMode, ViewContainerRef, Renderer2, ElementRef, model, SecurityContext } from '@angular/core';
4
4
  import { Icon } from '@fundamental-ngx/ui5-webcomponents/icon';
5
5
  import { Link } from '@fundamental-ngx/ui5-webcomponents/link';
6
6
  import { Tag } from '@fundamental-ngx/ui5-webcomponents/tag';
@@ -16,16 +16,18 @@ import { TableHeaderCell } from '@fundamental-ngx/ui5-webcomponents/table-header
16
16
  import { TableHeaderRow } from '@fundamental-ngx/ui5-webcomponents/table-header-row';
17
17
  import { TableRow } from '@fundamental-ngx/ui5-webcomponents/table-row';
18
18
  import '@ui5/webcomponents-fiori/dist/illustrations/NoData.js';
19
+ import '@ui5/webcomponents-icons/dist/add.js';
20
+ import '@ui5/webcomponents-icons/dist/delete.js';
21
+ import '@ui5/webcomponents-icons/dist/navigation-down-arrow.js';
22
+ import '@ui5/webcomponents-icons/dist/navigation-right-arrow.js';
19
23
  import * as i1 from '@angular/forms';
20
- import { FormBuilder, FormControl, ReactiveFormsModule } from '@angular/forms';
24
+ import { FormBuilder, FormArray, FormControl, ReactiveFormsModule } from '@angular/forms';
21
25
  import { Input } from '@fundamental-ngx/ui5-webcomponents/input';
22
26
  import { Label } from '@fundamental-ngx/ui5-webcomponents/label';
23
27
  import '@ui5/webcomponents-icons/dist/navigation-left-arrow.js';
24
- import '@ui5/webcomponents-icons/dist/navigation-right-arrow.js';
25
28
  import { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';
26
29
  import { Dialog } from '@fundamental-ngx/ui5-webcomponents/dialog';
27
30
  import { Title } from '@fundamental-ngx/ui5-webcomponents/title';
28
- import '@ui5/webcomponents-icons/dist/add.js';
29
31
  import '@ui5/webcomponents-icons/dist/search.js';
30
32
  import { debounceTime, map, filter } from 'rxjs';
31
33
  import { DomSanitizer } from '@angular/platform-browser';
@@ -455,13 +457,80 @@ function setPropertyByPath(object, path, value) {
455
457
  return object;
456
458
  }
457
459
 
460
+ /**
461
+ * Internal collection editor rendered by `mfp-declarative-form` when a field
462
+ * carries `propertyCollection` sub-fields.
463
+ *
464
+ * Each entry renders as a collapsible card whose expanded body is a nested
465
+ * `<mfp-declarative-form>` bound to that entry. Live changes flow up
466
+ * through the nested form's `(formValueChange)` output — no `viewChildren`
467
+ * on the class, so this component can safely participate in the mutual
468
+ * import cycle with `DeclarativeForm`.
469
+ */
470
+ class FormCollectionField {
471
+ fields = input.required(...(ngDevMode ? [{ debugName: "fields" }] : /* istanbul ignore next */ []));
472
+ label = input.required(...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
473
+ initialEntries = input([], ...(ngDevMode ? [{ debugName: "initialEntries" }] : /* istanbul ignore next */ []));
474
+ valueChange = output();
475
+ entries = linkedSignal(() => [
476
+ ...(this.initialEntries() ?? []),
477
+ ], ...(ngDevMode ? [{ debugName: "entries" }] : /* istanbul ignore next */ []));
478
+ expandedIndex = linkedSignal({ ...(ngDevMode ? { debugName: "expandedIndex" } : /* istanbul ignore next */ {}), source: this.initialEntries,
479
+ computation: () => null });
480
+ previewFor(entry, index) {
481
+ for (const field of this.fields()) {
482
+ const raw = entry[field.name];
483
+ if (raw !== undefined && raw !== null && String(raw).trim() !== '') {
484
+ return `${field.label ?? field.name}: ${String(raw)}`;
485
+ }
486
+ }
487
+ const prefix = this.label().trim() || 'Item';
488
+ return `${prefix} ${index + 1}`;
489
+ }
490
+ toggle(index) {
491
+ this.expandedIndex.set(this.expandedIndex() === index ? null : index);
492
+ }
493
+ add() {
494
+ const next = [...this.entries(), {}];
495
+ this.entries.set(next);
496
+ this.expandedIndex.set(next.length - 1);
497
+ this.valueChange.emit(next);
498
+ }
499
+ remove(index) {
500
+ const next = this.entries().filter((_, i) => i !== index);
501
+ this.entries.set(next);
502
+ const expandedIndex = this.expandedIndex();
503
+ if (expandedIndex === index) {
504
+ this.expandedIndex.set(null);
505
+ }
506
+ else if (expandedIndex !== null && expandedIndex > index) {
507
+ // Preserve the same expanded row after removing an earlier one.
508
+ this.expandedIndex.set(expandedIndex - 1);
509
+ }
510
+ this.valueChange.emit(next);
511
+ }
512
+ onEntryValueChange(index, value) {
513
+ const next = this.entries().map((entry, i) => i === index ? { ...value } : entry);
514
+ this.entries.set(next);
515
+ this.valueChange.emit(next);
516
+ }
517
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: FormCollectionField, deps: [], target: i0.ɵɵFactoryTarget.Component });
518
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: FormCollectionField, isStandalone: true, selector: "mfp-form-collection-field", inputs: { fields: { classPropertyName: "fields", publicName: "fields", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, initialEntries: { classPropertyName: "initialEntries", publicName: "initialEntries", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: "<div class=\"collection\" data-testid=\"collection-field\">\n @for (entry of entries(); track $index; let index = $index) {\n @let expanded = expandedIndex() === index;\n <div\n class=\"card\"\n [class.card--expanded]=\"expanded\"\n [attr.data-testid]=\"'collection-item-' + index\"\n >\n <button\n type=\"button\"\n class=\"card__header\"\n [attr.aria-expanded]=\"expanded\"\n [attr.data-testid]=\"'collection-item-' + index + '-toggle'\"\n (click)=\"toggle(index)\"\n >\n <ui5-icon\n class=\"card__chevron\"\n [name]=\"expanded ? 'navigation-down-arrow' : 'navigation-right-arrow'\"\n />\n <span class=\"card__preview\">{{ previewFor(entry, index) }}</span>\n <span class=\"card__spacer\"></span>\n <ui5-button\n class=\"card__action\"\n design=\"Transparent\"\n icon=\"delete\"\n accessibleName=\"Remove\"\n tooltip=\"Remove\"\n [attr.data-testid]=\"'collection-item-' + index + '-remove'\"\n (click)=\"remove(index); $event.stopPropagation()\"\n />\n </button>\n\n @if (expanded) {\n <div class=\"card__body\">\n <mfp-declarative-form\n [attr.data-testid]=\"'collection-item-' + index + '-form'\"\n [fields]=\"fields()\"\n [initialValues]=\"entry\"\n (formValueChange)=\"onEntryValueChange(index, $event)\"\n />\n </div>\n }\n </div>\n }\n\n <ui5-button\n class=\"collection__add\"\n design=\"Transparent\"\n icon=\"add\"\n accessibleName=\"Add\"\n data-testid=\"collection-add\"\n (click)=\"add()\"\n />\n</div>\n", styles: [":host{display:block;width:100%}.collection{display:flex;flex-direction:column;gap:.5rem;width:100%;padding-top:.25rem}.card{border:1px solid var(--sapGroup_ContentBorderColor, #d9d9d9);border-radius:.5rem;background:var(--sapGroup_TitleBackground, #fff);overflow:hidden}.card--expanded{box-shadow:0 1px 2px #0000000a}.card__header{display:flex;align-items:center;gap:.5rem;width:100%;padding:0 .75rem;background:transparent;border:0;text-align:left;cursor:pointer;font:inherit;min-height:1.5rem;color:var(--sapTextColor, #1d2d3e)}.card__header:hover{background:var(--sapList_Hover_Background, rgba(0, 0, 0, .03))}.card__chevron{flex:0 0 auto;color:var(--sapContent_IconColor, #6a6d70)}.card__preview{font-weight:500;color:var(--sapTextColor, #1d2d3e);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.card__spacer{flex:1}.card__action{flex:0 0 auto}.card__body{padding:.75rem 1rem 1rem;border-top:1px solid var(--sapGroup_ContentBorderColor, #d9d9d9)}.collection__add{align-self:flex-start;color:var(--sapButton_IconColor, #0070f2)}\n"], dependencies: [{ kind: "component", type: i0.forwardRef(() => Button), selector: "ui5-button, [ui5-button]", inputs: ["design", "disabled", "icon", "endIcon", "submits", "tooltip", "accessibleName", "accessibleNameRef", "accessibilityAttributes", "accessibleDescription", "type", "accessibleRole", "loading", "loadingDelay"], outputs: ["ui5Click"], exportAs: ["ui5Button"] }, { kind: "component", type: i0.forwardRef(() => Icon), selector: "ui5-icon, [ui5-icon]", inputs: ["design", "name", "accessibleName", "showTooltip", "mode"], outputs: ["ui5Click"], exportAs: ["ui5Icon"] }, { kind: "component", type: i0.forwardRef(() => DeclarativeForm), selector: "mfp-declarative-form", inputs: ["fields", "initialValues", "fieldErrors"], outputs: ["fieldChange", "formSubmit", "formValueChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.ShadowDom });
519
+ }
520
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: FormCollectionField, decorators: [{
521
+ type: Component,
522
+ args: [{ selector: 'mfp-form-collection-field', standalone: true, imports: [Button, Icon, forwardRef(() => DeclarativeForm)], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.ShadowDom, template: "<div class=\"collection\" data-testid=\"collection-field\">\n @for (entry of entries(); track $index; let index = $index) {\n @let expanded = expandedIndex() === index;\n <div\n class=\"card\"\n [class.card--expanded]=\"expanded\"\n [attr.data-testid]=\"'collection-item-' + index\"\n >\n <button\n type=\"button\"\n class=\"card__header\"\n [attr.aria-expanded]=\"expanded\"\n [attr.data-testid]=\"'collection-item-' + index + '-toggle'\"\n (click)=\"toggle(index)\"\n >\n <ui5-icon\n class=\"card__chevron\"\n [name]=\"expanded ? 'navigation-down-arrow' : 'navigation-right-arrow'\"\n />\n <span class=\"card__preview\">{{ previewFor(entry, index) }}</span>\n <span class=\"card__spacer\"></span>\n <ui5-button\n class=\"card__action\"\n design=\"Transparent\"\n icon=\"delete\"\n accessibleName=\"Remove\"\n tooltip=\"Remove\"\n [attr.data-testid]=\"'collection-item-' + index + '-remove'\"\n (click)=\"remove(index); $event.stopPropagation()\"\n />\n </button>\n\n @if (expanded) {\n <div class=\"card__body\">\n <mfp-declarative-form\n [attr.data-testid]=\"'collection-item-' + index + '-form'\"\n [fields]=\"fields()\"\n [initialValues]=\"entry\"\n (formValueChange)=\"onEntryValueChange(index, $event)\"\n />\n </div>\n }\n </div>\n }\n\n <ui5-button\n class=\"collection__add\"\n design=\"Transparent\"\n icon=\"add\"\n accessibleName=\"Add\"\n data-testid=\"collection-add\"\n (click)=\"add()\"\n />\n</div>\n", styles: [":host{display:block;width:100%}.collection{display:flex;flex-direction:column;gap:.5rem;width:100%;padding-top:.25rem}.card{border:1px solid var(--sapGroup_ContentBorderColor, #d9d9d9);border-radius:.5rem;background:var(--sapGroup_TitleBackground, #fff);overflow:hidden}.card--expanded{box-shadow:0 1px 2px #0000000a}.card__header{display:flex;align-items:center;gap:.5rem;width:100%;padding:0 .75rem;background:transparent;border:0;text-align:left;cursor:pointer;font:inherit;min-height:1.5rem;color:var(--sapTextColor, #1d2d3e)}.card__header:hover{background:var(--sapList_Hover_Background, rgba(0, 0, 0, .03))}.card__chevron{flex:0 0 auto;color:var(--sapContent_IconColor, #6a6d70)}.card__preview{font-weight:500;color:var(--sapTextColor, #1d2d3e);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.card__spacer{flex:1}.card__action{flex:0 0 auto}.card__body{padding:.75rem 1rem 1rem;border-top:1px solid var(--sapGroup_ContentBorderColor, #d9d9d9)}.collection__add{align-self:flex-start;color:var(--sapButton_IconColor, #0070f2)}\n"] }]
523
+ }], propDecorators: { fields: [{ type: i0.Input, args: [{ isSignal: true, alias: "fields", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], initialEntries: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialEntries", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }] } });
524
+
458
525
  class DeclarativeForm {
459
526
  fields = input.required(...(ngDevMode ? [{ debugName: "fields" }] : /* istanbul ignore next */ []));
460
527
  initialValues = input({}, ...(ngDevMode ? [{ debugName: "initialValues" }] : /* istanbul ignore next */ []));
461
528
  fieldErrors = input({}, ...(ngDevMode ? [{ debugName: "fieldErrors" }] : /* istanbul ignore next */ []));
462
529
  fieldChange = output();
463
530
  formSubmit = output();
531
+ formValueChange = output();
464
532
  form;
533
+ collectionSeeds = signal({}, ...(ngDevMode ? [{ debugName: "collectionSeeds" }] : /* istanbul ignore next */ []));
465
534
  fb = inject(FormBuilder);
466
535
  constructor() {
467
536
  this.form = this.fb.group({});
@@ -490,6 +559,7 @@ class DeclarativeForm {
490
559
  control.setValue(target.value);
491
560
  control.markAsTouched();
492
561
  control.markAsDirty();
562
+ this.formValueChange.emit(this.form.value);
493
563
  if (field.validation === 'onChange') {
494
564
  this.fieldChange.emit({
495
565
  fieldProperty: field.name,
@@ -497,6 +567,24 @@ class DeclarativeForm {
497
567
  });
498
568
  }
499
569
  }
570
+ onCollectionValueChange(field, entries) {
571
+ const array = this.form.controls[field.name];
572
+ if (!array)
573
+ return;
574
+ while (array.length)
575
+ array.removeAt(0);
576
+ for (const entry of entries) {
577
+ array.push(this.buildEntryGroup(entry));
578
+ }
579
+ array.markAsDirty();
580
+ array.markAsTouched();
581
+ if (field.validation === 'onChange' || field.validation === 'onBlur') {
582
+ this.fieldChange.emit({
583
+ fieldProperty: field.name,
584
+ value: entries,
585
+ });
586
+ }
587
+ }
500
588
  getError(name) {
501
589
  const control = this.form.controls[name];
502
590
  const error = this.fieldErrors()[name];
@@ -520,17 +608,30 @@ class DeclarativeForm {
520
608
  clear() {
521
609
  this.form.reset();
522
610
  }
611
+ collectionEntries(field) {
612
+ return this.collectionSeeds()[field.name] ?? [];
613
+ }
523
614
  rebuildControls(fields) {
524
615
  const existingControls = this.form.controls;
525
616
  const nextFieldNames = new Set(fields.map((field) => field.name));
526
617
  for (const field of fields) {
527
618
  const existingControl = existingControls[field.name];
528
- if (existingControl) {
619
+ const wantsCollection = !!field.propertyCollection?.length;
620
+ const existingIsCollection = existingControl instanceof FormArray;
621
+ if (existingControl && wantsCollection !== existingIsCollection) {
622
+ this.form.removeControl(field.name);
623
+ }
624
+ else if (existingControl) {
529
625
  existingControl.clearValidators();
530
626
  existingControl.updateValueAndValidity({ emitEvent: false });
531
627
  continue;
532
628
  }
533
- this.form.addControl(field.name, new FormControl(''));
629
+ if (wantsCollection) {
630
+ this.form.addControl(field.name, this.fb.array([]));
631
+ }
632
+ else {
633
+ this.form.addControl(field.name, new FormControl(''));
634
+ }
534
635
  }
535
636
  for (const controlName of Object.keys(existingControls)) {
536
637
  if (!nextFieldNames.has(controlName)) {
@@ -543,6 +644,25 @@ class DeclarativeForm {
543
644
  if (!initialValues) {
544
645
  return;
545
646
  }
647
+ const seeds = {};
648
+ for (const field of this.fields()) {
649
+ if (!field.propertyCollection?.length)
650
+ continue;
651
+ const raw = initialValues[field.name];
652
+ const entries = Array.isArray(raw)
653
+ ? raw
654
+ : [];
655
+ const array = this.form.controls[field.name];
656
+ if (array) {
657
+ while (array.length)
658
+ array.removeAt(0);
659
+ for (const entry of entries) {
660
+ array.push(this.buildEntryGroup(entry));
661
+ }
662
+ }
663
+ seeds[field.name] = entries;
664
+ }
665
+ this.collectionSeeds.set(seeds);
546
666
  this.form.patchValue(initialValues, { emitEvent: false });
547
667
  this.form.markAsPristine({ emitEvent: false });
548
668
  this.form.updateValueAndValidity({ emitEvent: false });
@@ -550,17 +670,34 @@ class DeclarativeForm {
550
670
  buildOutputValue() {
551
671
  const result = {};
552
672
  for (const key of Object.keys(this.form.controls)) {
553
- setPropertyByPath(result, key, this.form.controls[key].value);
673
+ const control = this.form.controls[key];
674
+ let value = control.value;
675
+ if (control instanceof FormArray) {
676
+ value = control.controls.map((group) => group.controls['entry']?.value ?? {});
677
+ }
678
+ setPropertyByPath(result, key, value);
554
679
  }
555
680
  return result;
556
681
  }
682
+ buildEntryGroup(entry) {
683
+ return this.fb.group({
684
+ entry: new FormControl(entry),
685
+ });
686
+ }
557
687
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: DeclarativeForm, deps: [], target: i0.ɵɵFactoryTarget.Component });
558
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: DeclarativeForm, isStandalone: true, selector: "mfp-declarative-form", inputs: { fields: { classPropertyName: "fields", publicName: "fields", isSignal: true, isRequired: true, transformFunction: null }, initialValues: { classPropertyName: "initialValues", publicName: "initialValues", isSignal: true, isRequired: false, transformFunction: null }, fieldErrors: { classPropertyName: "fieldErrors", publicName: "fieldErrors", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { fieldChange: "fieldChange", formSubmit: "formSubmit" }, ngImport: i0, template: "<section class=\"form\" data-testid=\"generic-form\" [formGroup]=\"form\">\n @for (field of fields(); track field.name) {\n @let control = form.controls[field.name];\n <div\n class=\"inputs\"\n [attr.data-testid]=\"'generic-form-field-container-' + field.name\"\n >\n <ui5-label\n show-colon\n [attr.data-testid]=\"'generic-form-field-label-' + field.name\"\n [required]=\"field.required\"\n >{{ field.label }}</ui5-label\n >\n @if (field.values?.length) {\n <ui5-select\n class=\"input\"\n [attr.data-testid]=\"'generic-form-field-' + field.name\"\n [disabled]=\"field.disabled\"\n [required]=\"field.required\"\n [value]=\"control.value\"\n [valueState]=\"getValueState(field.name)\"\n (blur)=\"onFieldBlur(field)\"\n (change)=\"setFormControlValue($event, field)\"\n (input)=\"setFormControlValue($event, field)\"\n >\n @if (getError(field.name); as error) {\n <div slot=\"valueStateMessage\">{{ error }}</div>\n }\n @for (value of [''].concat(field.values ?? []); track value) {\n <ui5-option\n [attr.data-testid]=\"\n 'generic-form-field-' +\n field.name +\n '-option-' +\n (value || 'empty')\n \"\n [selected]=\"value === control.value\"\n [value]=\"value\"\n >{{ value }}</ui5-option\n >\n }\n </ui5-select>\n } @else {\n <ui5-input\n class=\"input\"\n [attr.data-testid]=\"'generic-form-field-' + field.name\"\n [disabled]=\"field.disabled\"\n [required]=\"field.required\"\n [value]=\"control.value\"\n [valueState]=\"getValueState(field.name)\"\n (blur)=\"onFieldBlur(field)\"\n (change)=\"setFormControlValue($event, field)\"\n (input)=\"setFormControlValue($event, field)\"\n >\n @if (getError(field.name); as error) {\n <div slot=\"valueStateMessage\">{{ error }}</div>\n }\n </ui5-input>\n }\n </div>\n }\n</section>\n", styles: [".form>div{display:flex;flex-direction:column;justify-content:space-evenly;align-items:flex-start;margin-bottom:.5rem;width:100%}.input{width:100%}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: Input, selector: "ui5-input, [ui5-input]", inputs: ["disabled", "placeholder", "readonly", "required", "noTypeahead", "type", "value", "valueState", "name", "showSuggestions", "maxlength", "accessibleName", "accessibleNameRef", "accessibleDescription", "accessibleDescriptionRef", "showClearIcon", "open", "filter"], outputs: ["ui5Change", "ui5Input", "ui5Select", "ui5SelectionChange", "ui5Open", "ui5Close"], exportAs: ["ui5Input"] }, { kind: "component", type: Label, selector: "ui5-label, [ui5-label]", inputs: ["for", "showColon", "required", "wrappingType"], exportAs: ["ui5Label"] }, { kind: "component", type: Select, selector: "ui5-select, [ui5-select]", inputs: ["disabled", "name", "valueState", "required", "readonly", "accessibleName", "accessibleNameRef", "accessibleDescription", "accessibleDescriptionRef", "tooltip", "textSeparator", "value"], outputs: ["ui5Change", "ui5LiveChange", "ui5Open", "ui5Close"], exportAs: ["ui5Select"] }, { kind: "component", type: Option, selector: "ui5-option, [ui5-option]", inputs: ["value", "icon", "additionalText", "tooltip", "selected"], exportAs: ["ui5Option"] }], encapsulation: i0.ViewEncapsulation.ShadowDom });
688
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: DeclarativeForm, isStandalone: true, selector: "mfp-declarative-form", inputs: { fields: { classPropertyName: "fields", publicName: "fields", isSignal: true, isRequired: true, transformFunction: null }, initialValues: { classPropertyName: "initialValues", publicName: "initialValues", isSignal: true, isRequired: false, transformFunction: null }, fieldErrors: { classPropertyName: "fieldErrors", publicName: "fieldErrors", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { fieldChange: "fieldChange", formSubmit: "formSubmit", formValueChange: "formValueChange" }, ngImport: i0, template: "<section class=\"form\" data-testid=\"generic-form\" [formGroup]=\"form\">\n @for (field of fields(); track field.name) {\n @let control = form.controls[field.name];\n <div\n class=\"inputs\"\n [attr.data-testid]=\"'generic-form-field-container-' + field.name\"\n >\n <ui5-label\n show-colon\n [attr.data-testid]=\"'generic-form-field-label-' + field.name\"\n [required]=\"field.required\"\n >{{ field.label }}</ui5-label\n >\n @if (field.propertyCollection?.length) {\n <mfp-form-collection-field\n [attr.data-testid]=\"'generic-form-field-' + field.name\"\n [fields]=\"field.propertyCollection!\"\n [label]=\"field.label\"\n [initialEntries]=\"collectionEntries(field)\"\n (valueChange)=\"onCollectionValueChange(field, $event)\"\n />\n @if (getError(field.name); as error) {\n <div class=\"collection-error\" role=\"alert\">{{ error }}</div>\n }\n } @else if (field.values?.length) {\n <ui5-select\n class=\"input\"\n [attr.data-testid]=\"'generic-form-field-' + field.name\"\n [disabled]=\"field.disabled\"\n [required]=\"field.required\"\n [value]=\"control.value\"\n [valueState]=\"getValueState(field.name)\"\n (blur)=\"onFieldBlur(field)\"\n (change)=\"setFormControlValue($event, field)\"\n (input)=\"setFormControlValue($event, field)\"\n >\n @if (getError(field.name); as error) {\n <div slot=\"valueStateMessage\">{{ error }}</div>\n }\n @for (value of [''].concat(field.values ?? []); track value) {\n <ui5-option\n [attr.data-testid]=\"\n 'generic-form-field-' +\n field.name +\n '-option-' +\n (value || 'empty')\n \"\n [selected]=\"value === control.value\"\n [value]=\"value\"\n >{{ value }}</ui5-option\n >\n }\n </ui5-select>\n } @else {\n <ui5-input\n class=\"input\"\n [attr.data-testid]=\"'generic-form-field-' + field.name\"\n [disabled]=\"field.disabled\"\n [required]=\"field.required\"\n [value]=\"control.value\"\n [valueState]=\"getValueState(field.name)\"\n (blur)=\"onFieldBlur(field)\"\n (change)=\"setFormControlValue($event, field)\"\n (input)=\"setFormControlValue($event, field)\"\n >\n @if (getError(field.name); as error) {\n <div slot=\"valueStateMessage\">{{ error }}</div>\n }\n </ui5-input>\n }\n </div>\n }\n</section>\n", styles: [".form>div{display:flex;flex-direction:column;justify-content:space-evenly;align-items:flex-start;margin-bottom:.5rem;width:100%}.input{width:100%}.collection-error{color:var(--sapNegativeColor, #b00);font-size:.75rem;margin-top:.25rem}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: Input, selector: "ui5-input, [ui5-input]", inputs: ["disabled", "placeholder", "readonly", "required", "noTypeahead", "type", "value", "valueState", "name", "showSuggestions", "maxlength", "accessibleName", "accessibleNameRef", "accessibleDescription", "accessibleDescriptionRef", "showClearIcon", "open", "filter"], outputs: ["ui5Change", "ui5Input", "ui5Select", "ui5SelectionChange", "ui5Open", "ui5Close"], exportAs: ["ui5Input"] }, { kind: "component", type: Label, selector: "ui5-label, [ui5-label]", inputs: ["for", "showColon", "required", "wrappingType"], exportAs: ["ui5Label"] }, { kind: "component", type: Select, selector: "ui5-select, [ui5-select]", inputs: ["disabled", "name", "valueState", "required", "readonly", "accessibleName", "accessibleNameRef", "accessibleDescription", "accessibleDescriptionRef", "tooltip", "textSeparator", "value"], outputs: ["ui5Change", "ui5LiveChange", "ui5Open", "ui5Close"], exportAs: ["ui5Select"] }, { kind: "component", type: Option, selector: "ui5-option, [ui5-option]", inputs: ["value", "icon", "additionalText", "tooltip", "selected"], exportAs: ["ui5Option"] }, { kind: "component", type: FormCollectionField, selector: "mfp-form-collection-field", inputs: ["fields", "label", "initialEntries"], outputs: ["valueChange"] }], encapsulation: i0.ViewEncapsulation.ShadowDom });
559
689
  }
560
690
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: DeclarativeForm, decorators: [{
561
691
  type: Component,
562
- args: [{ selector: 'mfp-declarative-form', imports: [ReactiveFormsModule, Input, Label, Select, Option], encapsulation: ViewEncapsulation.ShadowDom, template: "<section class=\"form\" data-testid=\"generic-form\" [formGroup]=\"form\">\n @for (field of fields(); track field.name) {\n @let control = form.controls[field.name];\n <div\n class=\"inputs\"\n [attr.data-testid]=\"'generic-form-field-container-' + field.name\"\n >\n <ui5-label\n show-colon\n [attr.data-testid]=\"'generic-form-field-label-' + field.name\"\n [required]=\"field.required\"\n >{{ field.label }}</ui5-label\n >\n @if (field.values?.length) {\n <ui5-select\n class=\"input\"\n [attr.data-testid]=\"'generic-form-field-' + field.name\"\n [disabled]=\"field.disabled\"\n [required]=\"field.required\"\n [value]=\"control.value\"\n [valueState]=\"getValueState(field.name)\"\n (blur)=\"onFieldBlur(field)\"\n (change)=\"setFormControlValue($event, field)\"\n (input)=\"setFormControlValue($event, field)\"\n >\n @if (getError(field.name); as error) {\n <div slot=\"valueStateMessage\">{{ error }}</div>\n }\n @for (value of [''].concat(field.values ?? []); track value) {\n <ui5-option\n [attr.data-testid]=\"\n 'generic-form-field-' +\n field.name +\n '-option-' +\n (value || 'empty')\n \"\n [selected]=\"value === control.value\"\n [value]=\"value\"\n >{{ value }}</ui5-option\n >\n }\n </ui5-select>\n } @else {\n <ui5-input\n class=\"input\"\n [attr.data-testid]=\"'generic-form-field-' + field.name\"\n [disabled]=\"field.disabled\"\n [required]=\"field.required\"\n [value]=\"control.value\"\n [valueState]=\"getValueState(field.name)\"\n (blur)=\"onFieldBlur(field)\"\n (change)=\"setFormControlValue($event, field)\"\n (input)=\"setFormControlValue($event, field)\"\n >\n @if (getError(field.name); as error) {\n <div slot=\"valueStateMessage\">{{ error }}</div>\n }\n </ui5-input>\n }\n </div>\n }\n</section>\n", styles: [".form>div{display:flex;flex-direction:column;justify-content:space-evenly;align-items:flex-start;margin-bottom:.5rem;width:100%}.input{width:100%}\n"] }]
563
- }], ctorParameters: () => [], propDecorators: { fields: [{ type: i0.Input, args: [{ isSignal: true, alias: "fields", required: true }] }], initialValues: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialValues", required: false }] }], fieldErrors: [{ type: i0.Input, args: [{ isSignal: true, alias: "fieldErrors", required: false }] }], fieldChange: [{ type: i0.Output, args: ["fieldChange"] }], formSubmit: [{ type: i0.Output, args: ["formSubmit"] }] } });
692
+ args: [{ selector: 'mfp-declarative-form', imports: [
693
+ ReactiveFormsModule,
694
+ Input,
695
+ Label,
696
+ Select,
697
+ Option,
698
+ FormCollectionField,
699
+ ], encapsulation: ViewEncapsulation.ShadowDom, template: "<section class=\"form\" data-testid=\"generic-form\" [formGroup]=\"form\">\n @for (field of fields(); track field.name) {\n @let control = form.controls[field.name];\n <div\n class=\"inputs\"\n [attr.data-testid]=\"'generic-form-field-container-' + field.name\"\n >\n <ui5-label\n show-colon\n [attr.data-testid]=\"'generic-form-field-label-' + field.name\"\n [required]=\"field.required\"\n >{{ field.label }}</ui5-label\n >\n @if (field.propertyCollection?.length) {\n <mfp-form-collection-field\n [attr.data-testid]=\"'generic-form-field-' + field.name\"\n [fields]=\"field.propertyCollection!\"\n [label]=\"field.label\"\n [initialEntries]=\"collectionEntries(field)\"\n (valueChange)=\"onCollectionValueChange(field, $event)\"\n />\n @if (getError(field.name); as error) {\n <div class=\"collection-error\" role=\"alert\">{{ error }}</div>\n }\n } @else if (field.values?.length) {\n <ui5-select\n class=\"input\"\n [attr.data-testid]=\"'generic-form-field-' + field.name\"\n [disabled]=\"field.disabled\"\n [required]=\"field.required\"\n [value]=\"control.value\"\n [valueState]=\"getValueState(field.name)\"\n (blur)=\"onFieldBlur(field)\"\n (change)=\"setFormControlValue($event, field)\"\n (input)=\"setFormControlValue($event, field)\"\n >\n @if (getError(field.name); as error) {\n <div slot=\"valueStateMessage\">{{ error }}</div>\n }\n @for (value of [''].concat(field.values ?? []); track value) {\n <ui5-option\n [attr.data-testid]=\"\n 'generic-form-field-' +\n field.name +\n '-option-' +\n (value || 'empty')\n \"\n [selected]=\"value === control.value\"\n [value]=\"value\"\n >{{ value }}</ui5-option\n >\n }\n </ui5-select>\n } @else {\n <ui5-input\n class=\"input\"\n [attr.data-testid]=\"'generic-form-field-' + field.name\"\n [disabled]=\"field.disabled\"\n [required]=\"field.required\"\n [value]=\"control.value\"\n [valueState]=\"getValueState(field.name)\"\n (blur)=\"onFieldBlur(field)\"\n (change)=\"setFormControlValue($event, field)\"\n (input)=\"setFormControlValue($event, field)\"\n >\n @if (getError(field.name); as error) {\n <div slot=\"valueStateMessage\">{{ error }}</div>\n }\n </ui5-input>\n }\n </div>\n }\n</section>\n", styles: [".form>div{display:flex;flex-direction:column;justify-content:space-evenly;align-items:flex-start;margin-bottom:.5rem;width:100%}.input{width:100%}.collection-error{color:var(--sapNegativeColor, #b00);font-size:.75rem;margin-top:.25rem}\n"] }]
700
+ }], ctorParameters: () => [], propDecorators: { fields: [{ type: i0.Input, args: [{ isSignal: true, alias: "fields", required: true }] }], initialValues: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialValues", required: false }] }], fieldErrors: [{ type: i0.Input, args: [{ isSignal: true, alias: "fieldErrors", required: false }] }], fieldChange: [{ type: i0.Output, args: ["fieldChange"] }], formSubmit: [{ type: i0.Output, args: ["formSubmit"] }], formValueChange: [{ type: i0.Output, args: ["formValueChange"] }] } });
564
701
 
565
702
  /**
566
703
  * Horizontal filter-tab strip rendered above the table by
@@ -863,7 +1000,7 @@ class DeclarativeTableCard {
863
1000
  }, {});
864
1001
  }
865
1002
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: DeclarativeTableCard, deps: [], target: i0.ɵɵFactoryTarget.Component });
866
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: DeclarativeTableCard, isStandalone: true, selector: "mfp-declarative-table-card", inputs: { resources: { classPropertyName: "resources", publicName: "resources", isSignal: true, isRequired: true, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null }, createFormState: { classPropertyName: "createFormState", publicName: "createFormState", isSignal: true, isRequired: false, transformFunction: null }, editFormState: { classPropertyName: "editFormState", publicName: "editFormState", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { actionButtonClick: "actionButtonClick", tableRowClicked: "tableRowClicked", loadMoreResources: "loadMoreResources", paginationLimitChanged: "paginationLimitChanged", searchChanged: "searchChanged", createFieldChange: "createFieldChange", editFieldChange: "editFieldChange", createSubmit: "createSubmit", editSubmit: "editSubmit", deleteSubmit: "deleteSubmit", filterTabChanged: "filterTabChanged" }, viewQueries: [{ propertyName: "searchInputRef", first: true, predicate: ["searchInput"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"card\" data-testid=\"generic-table-card\">\n <div class=\"card__header\">\n <div class=\"card__title\">\n @if (header(); as header) {\n {{ header }}\n @if (headerTooltip(); as tooltip) {\n <ui5-icon\n class=\"card__info-icon\"\n name=\"hint\"\n [accessibleName]=\"tooltip\"\n [showTooltip]=\"true\"\n />\n }\n }\n </div>\n <div class=\"card__actions\">\n @if (resourcesSearchable()) {\n @if (searchExpanded()) {\n <ui5-input\n #searchInput\n data-testid=\"generic-table-card-search-input\"\n [class]=\"\n 'card__search-input card__search-input--' +\n (searchCollapsing() ? 'leave' : 'enter')\n \"\n [formControl]=\"searchControl\"\n (animationend)=\"onSearchAnimationEnd()\"\n (blur)=\"onSearchBlur()\"\n />\n }\n <ui5-button\n class=\"card__search-btn\"\n data-testid=\"generic-table-card-search-btn\"\n design=\"Transparent\"\n [accessibleName]=\"searchButtonConfig()?.tooltip ?? 'Search'\"\n [icon]=\"searchButtonConfig()?.icon ?? 'search'\"\n [tooltip]=\"searchButtonConfig()?.tooltip ?? 'Search'\"\n (click)=\"toggleSearch()\"\n />\n }\n @if (createFormConfig()) {\n <ui5-button\n class=\"card__create-btn\"\n data-testid=\"generic-table-card-create-btn\"\n [accessibleName]=\"createButtonConfig()?.text || createButtonConfig()?.tooltip || 'Create'\"\n [design]=\"createButtonConfig()?.design ?? 'Transparent'\"\n [icon]=\"createButtonConfig()?.icon ?? 'add'\"\n [tooltip]=\"createButtonConfig()?.tooltip\"\n (click)=\"createDialogOpen.set(true)\"\n >\n {{ createButtonConfig()?.text ?? '' }}\n </ui5-button>\n }\n </div>\n </div>\n\n @if (hasFilterTabs()) {\n <mfp-filter-tabs\n [tabs]=\"filterTabs()\"\n (tabChanged)=\"onFilterTabChanged($event)\"\n />\n }\n\n <div class=\"card__body\">\n @if (tableConfig(); as config) {\n <mfp-declarative-table\n [columns]=\"effectiveColumns()\"\n [growMode]=\"config.growMode ?? 'Button'\"\n [hasMore]=\"config.hasMore ?? false\"\n [height]=\"config.height\"\n [loadMoreButtonText]=\"config.loadMoreButtonText ?? 'Load More'\"\n [paginationLimit]=\"config.paginationLimit ?? 5\"\n [resources]=\"resources()\"\n [totalItemsCount]=\"config.totalItemsCount\"\n (buttonClick)=\"onButtonClick($event)\"\n (loadMoreResources)=\"loadMoreResources.emit()\"\n (paginationLimitChanged)=\"paginationLimitChanged.emit($event)\"\n (tableRowClicked)=\"tableRowClicked.emit($event)\"\n />\n }\n </div>\n</div>\n\n@if (createFormConfig(); as config) {\n <ui5-dialog\n data-testid=\"generic-table-card-create-dialog\"\n [accessibleName]=\"config.title ?? 'Create'\"\n [open]=\"createDialogOpen()\"\n (ui5BeforeClose)=\"createDialogOpen.set(false)\"\n >\n <div class=\"dialog__header\" slot=\"header\">\n <ui5-title level=\"H5\">{{ config.title ?? 'Create' }}</ui5-title>\n </div>\n <div class=\"dialog__body\">\n <mfp-declarative-form\n #createForm\n [fieldErrors]=\"createFormState().fieldErrors ?? {}\"\n [fields]=\"config.fields\"\n (fieldChange)=\"onCreateFieldChange($event)\"\n (formSubmit)=\"onCreateSubmit($event)\"\n />\n </div>\n <div class=\"dialog__footer\" slot=\"footer\">\n <ui5-button\n data-testid=\"generic-table-card-create-confirm\"\n design=\"Emphasized\"\n [disabled]=\"hasErrors(createFormState())\"\n (click)=\"createForm.submit()\"\n >\n {{ config.confirmLabel ?? 'Save' }}\n </ui5-button>\n <ui5-button data-testid=\"generic-table-card-create-cancel\" design=\"Transparent\" (click)=\"closeCreateDialog()\">\n {{ config.cancelLabel ?? 'Cancel' }}\n </ui5-button>\n </div>\n </ui5-dialog>\n}\n\n@if (editFormConfig(); as config) {\n <ui5-dialog\n data-testid=\"generic-table-card-edit-dialog\"\n [accessibleName]=\"config.title ?? 'Edit'\"\n [open]=\"editDialogOpen()\"\n (ui5BeforeClose)=\"editDialogOpen.set(false)\"\n >\n <div class=\"dialog__header\" slot=\"header\">\n <ui5-title level=\"H5\">{{ config.title ?? 'Edit' }}</ui5-title>\n </div>\n <div class=\"dialog__body\">\n <mfp-declarative-form\n #editForm\n [fieldErrors]=\"editFormState().fieldErrors ?? {}\"\n [fields]=\"config.fields\"\n [initialValues]=\"editInitialValue()\"\n (fieldChange)=\"onEditFieldChange($event)\"\n (formSubmit)=\"onEditSubmit($event)\"\n />\n </div>\n <div class=\"dialog__footer\" slot=\"footer\">\n <ui5-button\n data-testid=\"generic-table-card-edit-confirm\"\n design=\"Emphasized\"\n [disabled]=\"hasErrors(editFormState())\"\n (click)=\"editForm.submit()\"\n >\n {{ config.confirmLabel ?? 'Edit' }}\n </ui5-button>\n <ui5-button data-testid=\"generic-table-card-edit-cancel\" design=\"Transparent\" (click)=\"closeEditDialog()\">\n {{ config.cancelLabel ?? 'Cancel' }}\n </ui5-button>\n </div>\n </ui5-dialog>\n}\n\n@if (deleteConfirmationConfig(); as config) {\n <ui5-dialog\n data-testid=\"generic-table-card-delete-dialog\"\n [accessibleName]=\"config.title ?? 'Confirm Delete'\"\n [open]=\"deleteDialogOpen()\"\n (ui5BeforeClose)=\"deleteDialogOpen.set(false)\"\n >\n <div class=\"dialog__header\" slot=\"header\">\n <ui5-title level=\"H5\">{{ config.title ?? 'Confirm Delete' }}</ui5-title>\n </div>\n @if (config.message) {\n <div class=\"dialog__body\">\n <p class=\"dialog__message\">{{ config.message }}</p>\n </div>\n }\n <div class=\"dialog__footer\" slot=\"footer\">\n <ui5-button data-testid=\"generic-table-card-delete-confirm\" design=\"Negative\" (click)=\"onDeleteSubmit()\">\n {{ config.confirmLabel ?? 'Delete' }}\n </ui5-button>\n <ui5-button data-testid=\"generic-table-card-delete-cancel\" design=\"Transparent\" (click)=\"closeDeleteDialog()\">\n {{ config.cancelLabel ?? 'Cancel' }}\n </ui5-button>\n </div>\n </ui5-dialog>\n}\n", styles: [":host{display:block}@keyframes slide-in{0%{opacity:0;transform:scaleX(0)}to{opacity:1;transform:scaleX(1)}}@keyframes slide-out{0%{opacity:1;transform:scaleX(1)}to{opacity:0;transform:scaleX(0)}}.card{display:flex;flex-direction:column;border:1px solid var(--sapGroup_ContentBorderColor, #d9d9d9);border-radius:16px;background:var(--sapGroup_TitleBackground, #fff)}.card__header{display:flex;align-items:center;justify-content:space-between;min-height:3rem;padding:0 1rem}.card__title{color:var(--sapTile_TitleTextColor);text-overflow:ellipsis;font-family:var(--Font-Family-sapFontFamily, 72);font-size:var(--Font-Size-sapFontHeader6Size, 16px);font-style:normal;font-weight:700;line-height:normal;display:flex;align-items:center}.card__actions{display:flex;align-items:center;gap:.5rem}.card__info-icon{color:var(--sapButton_IconColor, #0070f2);margin-left:.5rem}.card__search-input{transform-origin:right center}.card__search-input--enter{animation:slide-in .2s ease-out both}.card__search-input--leave{animation:slide-out .2s ease-in both}.card__create-btn,.card__search-btn{min-width:auto;color:var(--sapButton_IconColor, #0070f2)}.card__body{flex:1;overflow:auto}.dialog__header{display:flex;align-items:flex-start;padding:.75rem 1rem}.dialog__body{margin:-1rem;min-width:320px;padding:1rem}.dialog__message{padding:1rem;margin:0;font-size:.875rem;max-width:320px}.dialog__footer{display:flex;justify-content:space-between;align-items:center;gap:.5rem;padding:.5rem 1rem;margin:0 -1rem;width:100%}\n"], dependencies: [{ kind: "component", type: DeclarativeTable, selector: "mfp-declarative-table", inputs: ["columns", "resources", "trackByPath", "totalItemsCount", "paginationLimit", "hasMore", "growMode", "loadMoreButtonText", "height"], outputs: ["buttonClick", "tableRowClicked", "loadMoreResources", "paginationLimitChanged"] }, { kind: "component", type: DeclarativeForm, selector: "mfp-declarative-form", inputs: ["fields", "initialValues", "fieldErrors"], outputs: ["fieldChange", "formSubmit"] }, { kind: "component", type: FilterTabs, selector: "mfp-filter-tabs", inputs: ["tabs"], outputs: ["tabChanged"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: Dialog, selector: "ui5-dialog, [ui5-dialog]", inputs: ["headerText", "stretch", "draggable", "resizable", "state", "initialFocus", "preventFocusRestore", "accessibleName", "accessibleNameRef", "accessibleRole", "accessibleDescription", "accessibleDescriptionRef", "preventInitialFocus", "open"], outputs: ["ui5BeforeOpen", "ui5Open", "ui5BeforeClose", "ui5Close"], exportAs: ["ui5Dialog"] }, { kind: "component", type: Title, selector: "ui5-title, [ui5-title]", inputs: ["wrappingType", "level", "size"], exportAs: ["ui5Title"] }, { kind: "component", type: Button, selector: "ui5-button, [ui5-button]", inputs: ["design", "disabled", "icon", "endIcon", "submits", "tooltip", "accessibleName", "accessibleNameRef", "accessibilityAttributes", "accessibleDescription", "type", "accessibleRole", "loading", "loadingDelay"], outputs: ["ui5Click"], exportAs: ["ui5Button"] }, { kind: "component", type: Icon, selector: "ui5-icon, [ui5-icon]", inputs: ["design", "name", "accessibleName", "showTooltip", "mode"], outputs: ["ui5Click"], exportAs: ["ui5Icon"] }, { kind: "component", type: Input, selector: "ui5-input, [ui5-input]", inputs: ["disabled", "placeholder", "readonly", "required", "noTypeahead", "type", "value", "valueState", "name", "showSuggestions", "maxlength", "accessibleName", "accessibleNameRef", "accessibleDescription", "accessibleDescriptionRef", "showClearIcon", "open", "filter"], outputs: ["ui5Change", "ui5Input", "ui5Select", "ui5SelectionChange", "ui5Open", "ui5Close"], exportAs: ["ui5Input"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.ShadowDom });
1003
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: DeclarativeTableCard, isStandalone: true, selector: "mfp-declarative-table-card", inputs: { resources: { classPropertyName: "resources", publicName: "resources", isSignal: true, isRequired: true, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null }, createFormState: { classPropertyName: "createFormState", publicName: "createFormState", isSignal: true, isRequired: false, transformFunction: null }, editFormState: { classPropertyName: "editFormState", publicName: "editFormState", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { actionButtonClick: "actionButtonClick", tableRowClicked: "tableRowClicked", loadMoreResources: "loadMoreResources", paginationLimitChanged: "paginationLimitChanged", searchChanged: "searchChanged", createFieldChange: "createFieldChange", editFieldChange: "editFieldChange", createSubmit: "createSubmit", editSubmit: "editSubmit", deleteSubmit: "deleteSubmit", filterTabChanged: "filterTabChanged" }, viewQueries: [{ propertyName: "searchInputRef", first: true, predicate: ["searchInput"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"card\" data-testid=\"generic-table-card\">\n <div class=\"card__header\">\n <div class=\"card__title\">\n @if (header(); as header) {\n {{ header }}\n @if (headerTooltip(); as tooltip) {\n <ui5-icon\n class=\"card__info-icon\"\n name=\"hint\"\n [accessibleName]=\"tooltip\"\n [showTooltip]=\"true\"\n />\n }\n }\n </div>\n <div class=\"card__actions\">\n @if (resourcesSearchable()) {\n @if (searchExpanded()) {\n <ui5-input\n #searchInput\n data-testid=\"generic-table-card-search-input\"\n [class]=\"\n 'card__search-input card__search-input--' +\n (searchCollapsing() ? 'leave' : 'enter')\n \"\n [formControl]=\"searchControl\"\n (animationend)=\"onSearchAnimationEnd()\"\n (blur)=\"onSearchBlur()\"\n />\n }\n <ui5-button\n class=\"card__search-btn\"\n data-testid=\"generic-table-card-search-btn\"\n design=\"Transparent\"\n [accessibleName]=\"searchButtonConfig()?.tooltip ?? 'Search'\"\n [icon]=\"searchButtonConfig()?.icon ?? 'search'\"\n [tooltip]=\"searchButtonConfig()?.tooltip ?? 'Search'\"\n (click)=\"toggleSearch()\"\n />\n }\n @if (createFormConfig()) {\n <ui5-button\n class=\"card__create-btn\"\n data-testid=\"generic-table-card-create-btn\"\n [accessibleName]=\"createButtonConfig()?.text || createButtonConfig()?.tooltip || 'Create'\"\n [design]=\"createButtonConfig()?.design ?? 'Transparent'\"\n [icon]=\"createButtonConfig()?.icon ?? 'add'\"\n [tooltip]=\"createButtonConfig()?.tooltip\"\n (click)=\"createDialogOpen.set(true)\"\n >\n {{ createButtonConfig()?.text ?? '' }}\n </ui5-button>\n }\n </div>\n </div>\n\n @if (hasFilterTabs()) {\n <mfp-filter-tabs\n [tabs]=\"filterTabs()\"\n (tabChanged)=\"onFilterTabChanged($event)\"\n />\n }\n\n <div class=\"card__body\">\n @if (tableConfig(); as config) {\n <mfp-declarative-table\n [columns]=\"effectiveColumns()\"\n [growMode]=\"config.growMode ?? 'Button'\"\n [hasMore]=\"config.hasMore ?? false\"\n [height]=\"config.height\"\n [loadMoreButtonText]=\"config.loadMoreButtonText ?? 'Load More'\"\n [paginationLimit]=\"config.paginationLimit ?? 5\"\n [resources]=\"resources()\"\n [totalItemsCount]=\"config.totalItemsCount\"\n (buttonClick)=\"onButtonClick($event)\"\n (loadMoreResources)=\"loadMoreResources.emit()\"\n (paginationLimitChanged)=\"paginationLimitChanged.emit($event)\"\n (tableRowClicked)=\"tableRowClicked.emit($event)\"\n />\n }\n </div>\n</div>\n\n@if (createFormConfig(); as config) {\n <ui5-dialog\n data-testid=\"generic-table-card-create-dialog\"\n [accessibleName]=\"config.title ?? 'Create'\"\n [open]=\"createDialogOpen()\"\n (ui5BeforeClose)=\"createDialogOpen.set(false)\"\n >\n <div class=\"dialog__header\" slot=\"header\">\n <ui5-title level=\"H5\">{{ config.title ?? 'Create' }}</ui5-title>\n </div>\n <div class=\"dialog__body\">\n <mfp-declarative-form\n #createForm\n [fieldErrors]=\"createFormState().fieldErrors ?? {}\"\n [fields]=\"config.fields\"\n (fieldChange)=\"onCreateFieldChange($event)\"\n (formSubmit)=\"onCreateSubmit($event)\"\n />\n </div>\n <div class=\"dialog__footer\" slot=\"footer\">\n <ui5-button\n data-testid=\"generic-table-card-create-confirm\"\n design=\"Emphasized\"\n [disabled]=\"hasErrors(createFormState())\"\n (click)=\"createForm.submit()\"\n >\n {{ config.confirmLabel ?? 'Save' }}\n </ui5-button>\n <ui5-button data-testid=\"generic-table-card-create-cancel\" design=\"Transparent\" (click)=\"closeCreateDialog()\">\n {{ config.cancelLabel ?? 'Cancel' }}\n </ui5-button>\n </div>\n </ui5-dialog>\n}\n\n@if (editFormConfig(); as config) {\n <ui5-dialog\n data-testid=\"generic-table-card-edit-dialog\"\n [accessibleName]=\"config.title ?? 'Edit'\"\n [open]=\"editDialogOpen()\"\n (ui5BeforeClose)=\"editDialogOpen.set(false)\"\n >\n <div class=\"dialog__header\" slot=\"header\">\n <ui5-title level=\"H5\">{{ config.title ?? 'Edit' }}</ui5-title>\n </div>\n <div class=\"dialog__body\">\n <mfp-declarative-form\n #editForm\n [fieldErrors]=\"editFormState().fieldErrors ?? {}\"\n [fields]=\"config.fields\"\n [initialValues]=\"editInitialValue()\"\n (fieldChange)=\"onEditFieldChange($event)\"\n (formSubmit)=\"onEditSubmit($event)\"\n />\n </div>\n <div class=\"dialog__footer\" slot=\"footer\">\n <ui5-button\n data-testid=\"generic-table-card-edit-confirm\"\n design=\"Emphasized\"\n [disabled]=\"hasErrors(editFormState())\"\n (click)=\"editForm.submit()\"\n >\n {{ config.confirmLabel ?? 'Edit' }}\n </ui5-button>\n <ui5-button data-testid=\"generic-table-card-edit-cancel\" design=\"Transparent\" (click)=\"closeEditDialog()\">\n {{ config.cancelLabel ?? 'Cancel' }}\n </ui5-button>\n </div>\n </ui5-dialog>\n}\n\n@if (deleteConfirmationConfig(); as config) {\n <ui5-dialog\n data-testid=\"generic-table-card-delete-dialog\"\n [accessibleName]=\"config.title ?? 'Confirm Delete'\"\n [open]=\"deleteDialogOpen()\"\n (ui5BeforeClose)=\"deleteDialogOpen.set(false)\"\n >\n <div class=\"dialog__header\" slot=\"header\">\n <ui5-title level=\"H5\">{{ config.title ?? 'Confirm Delete' }}</ui5-title>\n </div>\n @if (config.message) {\n <div class=\"dialog__body\">\n <p class=\"dialog__message\">{{ config.message }}</p>\n </div>\n }\n <div class=\"dialog__footer\" slot=\"footer\">\n <ui5-button data-testid=\"generic-table-card-delete-confirm\" design=\"Negative\" (click)=\"onDeleteSubmit()\">\n {{ config.confirmLabel ?? 'Delete' }}\n </ui5-button>\n <ui5-button data-testid=\"generic-table-card-delete-cancel\" design=\"Transparent\" (click)=\"closeDeleteDialog()\">\n {{ config.cancelLabel ?? 'Cancel' }}\n </ui5-button>\n </div>\n </ui5-dialog>\n}\n", styles: [":host{display:block}@keyframes slide-in{0%{opacity:0;transform:scaleX(0)}to{opacity:1;transform:scaleX(1)}}@keyframes slide-out{0%{opacity:1;transform:scaleX(1)}to{opacity:0;transform:scaleX(0)}}.card{display:flex;flex-direction:column;border:1px solid var(--sapGroup_ContentBorderColor, #d9d9d9);border-radius:16px;background:var(--sapGroup_TitleBackground, #fff)}.card__header{display:flex;align-items:center;justify-content:space-between;min-height:3rem;padding:0 1rem}.card__title{color:var(--sapTile_TitleTextColor);text-overflow:ellipsis;font-family:var(--Font-Family-sapFontFamily, 72);font-size:var(--Font-Size-sapFontHeader6Size, 16px);font-style:normal;font-weight:700;line-height:normal;display:flex;align-items:center}.card__actions{display:flex;align-items:center;gap:.5rem}.card__info-icon{color:var(--sapButton_IconColor, #0070f2);margin-left:.5rem}.card__search-input{transform-origin:right center}.card__search-input--enter{animation:slide-in .2s ease-out both}.card__search-input--leave{animation:slide-out .2s ease-in both}.card__create-btn,.card__search-btn{min-width:auto;color:var(--sapButton_IconColor, #0070f2)}.card__body{flex:1;overflow:auto}.dialog__header{display:flex;align-items:flex-start;padding:.75rem 1rem}.dialog__body{margin:-1rem;min-width:320px;padding:1rem}.dialog__message{padding:1rem;margin:0;font-size:.875rem;max-width:320px}.dialog__footer{display:flex;justify-content:space-between;align-items:center;gap:.5rem;padding:.5rem 1rem;margin:0 -1rem;width:100%}\n"], dependencies: [{ kind: "component", type: DeclarativeTable, selector: "mfp-declarative-table", inputs: ["columns", "resources", "trackByPath", "totalItemsCount", "paginationLimit", "hasMore", "growMode", "loadMoreButtonText", "height"], outputs: ["buttonClick", "tableRowClicked", "loadMoreResources", "paginationLimitChanged"] }, { kind: "component", type: DeclarativeForm, selector: "mfp-declarative-form", inputs: ["fields", "initialValues", "fieldErrors"], outputs: ["fieldChange", "formSubmit", "formValueChange"] }, { kind: "component", type: FilterTabs, selector: "mfp-filter-tabs", inputs: ["tabs"], outputs: ["tabChanged"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: Dialog, selector: "ui5-dialog, [ui5-dialog]", inputs: ["headerText", "stretch", "draggable", "resizable", "state", "initialFocus", "preventFocusRestore", "accessibleName", "accessibleNameRef", "accessibleRole", "accessibleDescription", "accessibleDescriptionRef", "preventInitialFocus", "open"], outputs: ["ui5BeforeOpen", "ui5Open", "ui5BeforeClose", "ui5Close"], exportAs: ["ui5Dialog"] }, { kind: "component", type: Title, selector: "ui5-title, [ui5-title]", inputs: ["wrappingType", "level", "size"], exportAs: ["ui5Title"] }, { kind: "component", type: Button, selector: "ui5-button, [ui5-button]", inputs: ["design", "disabled", "icon", "endIcon", "submits", "tooltip", "accessibleName", "accessibleNameRef", "accessibilityAttributes", "accessibleDescription", "type", "accessibleRole", "loading", "loadingDelay"], outputs: ["ui5Click"], exportAs: ["ui5Button"] }, { kind: "component", type: Icon, selector: "ui5-icon, [ui5-icon]", inputs: ["design", "name", "accessibleName", "showTooltip", "mode"], outputs: ["ui5Click"], exportAs: ["ui5Icon"] }, { kind: "component", type: Input, selector: "ui5-input, [ui5-input]", inputs: ["disabled", "placeholder", "readonly", "required", "noTypeahead", "type", "value", "valueState", "name", "showSuggestions", "maxlength", "accessibleName", "accessibleNameRef", "accessibleDescription", "accessibleDescriptionRef", "showClearIcon", "open", "filter"], outputs: ["ui5Change", "ui5Input", "ui5Select", "ui5SelectionChange", "ui5Open", "ui5Close"], exportAs: ["ui5Input"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.ShadowDom });
867
1004
  }
868
1005
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: DeclarativeTableCard, decorators: [{
869
1006
  type: Component,