@openmfp/ngx 0.15.0 → 0.16.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,8 +1,10 @@
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, linkedSignal, forwardRef, inject, effect, viewChild, Injector, afterNextRender, Injectable, reflectComponentType, isStandalone, isDevMode, ViewContainerRef, Renderer2, ElementRef, model, SecurityContext } from '@angular/core';
3
+ import { input, computed, CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, Component, signal, ViewEncapsulation, forwardRef, output, linkedSignal, 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
+ import '@ui5/webcomponents-icons/dist/navigation-down-arrow.js';
7
+ import '@ui5/webcomponents-icons/dist/navigation-right-arrow.js';
6
8
  import { Tag } from '@fundamental-ngx/ui5-webcomponents/tag';
7
9
  import { Button } from '@fundamental-ngx/ui5-webcomponents/button';
8
10
  import '@ui5/webcomponents-icons/dist/AllIcons.js';
@@ -18,8 +20,6 @@ import { TableRow } from '@fundamental-ngx/ui5-webcomponents/table-row';
18
20
  import '@ui5/webcomponents-fiori/dist/illustrations/NoData.js';
19
21
  import '@ui5/webcomponents-icons/dist/add.js';
20
22
  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';
23
23
  import * as i1 from '@angular/forms';
24
24
  import { FormBuilder, FormArray, FormControl, ReactiveFormsModule } from '@angular/forms';
25
25
  import { Input } from '@fundamental-ngx/ui5-webcomponents/input';
@@ -47,68 +47,6 @@ import { Card } from '@fundamental-ngx/ui5-webcomponents/card';
47
47
  import { CardHeader } from '@fundamental-ngx/ui5-webcomponents/card-header';
48
48
  import { ListItemStandard } from '@fundamental-ngx/ui5-webcomponents/list-item-standard';
49
49
 
50
- const parseStringValue = (value) => {
51
- if (value === 'true') {
52
- return true;
53
- }
54
- if (value === 'false') {
55
- return false;
56
- }
57
- if (!isNaN(Number(value))) {
58
- return Number(value);
59
- }
60
- return value;
61
- };
62
- const ruleResolver = (rule, resourceValue) => {
63
- const parsedResouceValue = parseStringValue(resourceValue);
64
- const parsedConditionValue = parseStringValue(rule.if.value);
65
- switch (rule.if.condition) {
66
- case 'equals':
67
- return parsedResouceValue === parsedConditionValue;
68
- case 'notEquals':
69
- return parsedResouceValue !== parsedConditionValue;
70
- case 'greaterThan':
71
- return parsedResouceValue > parsedConditionValue;
72
- case 'greaterThanOrEqual':
73
- return parsedResouceValue >= parsedConditionValue;
74
- case 'lessThan':
75
- return parsedResouceValue < parsedConditionValue;
76
- case 'lessThanOrEqual':
77
- return parsedResouceValue <= parsedConditionValue;
78
- case 'contains':
79
- if (Array.isArray(parsedResouceValue)) {
80
- return parsedResouceValue.includes(parsedConditionValue);
81
- }
82
- else if (typeof parsedResouceValue === 'string' &&
83
- typeof parsedConditionValue === 'string') {
84
- return parsedResouceValue.includes(parsedConditionValue);
85
- }
86
- return false;
87
- }
88
- return false;
89
- };
90
- const evaluateCssRules = (value, rules) => {
91
- if (!rules) {
92
- return {};
93
- }
94
- return rules.reduce((acc, rule) => {
95
- const result = ruleResolver(rule, value);
96
- if (result) {
97
- return { ...acc, ...rule.styles };
98
- }
99
- return acc;
100
- }, {});
101
- };
102
- const evaluateValueRules = (value, rules) => {
103
- if (!rules)
104
- return value;
105
- for (const rule of rules) {
106
- if (ruleResolver(rule, value))
107
- return rule.then;
108
- }
109
- return value;
110
- };
111
-
112
50
  const getResourceValueByJsonPath = (resource, field) => {
113
51
  const property = field.jsonPathExpression || field.property;
114
52
  if (!property) {
@@ -203,6 +141,68 @@ function getFieldValue(field, resource) {
203
141
  return field.value;
204
142
  }
205
143
 
144
+ const parseStringValue = (value) => {
145
+ if (value === 'true') {
146
+ return true;
147
+ }
148
+ if (value === 'false') {
149
+ return false;
150
+ }
151
+ if (!isNaN(Number(value))) {
152
+ return Number(value);
153
+ }
154
+ return value;
155
+ };
156
+ const ruleResolver = (rule, resourceValue) => {
157
+ const parsedResouceValue = parseStringValue(resourceValue);
158
+ const parsedConditionValue = parseStringValue(rule.if.value);
159
+ switch (rule.if.condition) {
160
+ case 'equals':
161
+ return parsedResouceValue === parsedConditionValue;
162
+ case 'notEquals':
163
+ return parsedResouceValue !== parsedConditionValue;
164
+ case 'greaterThan':
165
+ return parsedResouceValue > parsedConditionValue;
166
+ case 'greaterThanOrEqual':
167
+ return parsedResouceValue >= parsedConditionValue;
168
+ case 'lessThan':
169
+ return parsedResouceValue < parsedConditionValue;
170
+ case 'lessThanOrEqual':
171
+ return parsedResouceValue <= parsedConditionValue;
172
+ case 'contains':
173
+ if (Array.isArray(parsedResouceValue)) {
174
+ return parsedResouceValue.includes(parsedConditionValue);
175
+ }
176
+ else if (typeof parsedResouceValue === 'string' &&
177
+ typeof parsedConditionValue === 'string') {
178
+ return parsedResouceValue.includes(parsedConditionValue);
179
+ }
180
+ return false;
181
+ }
182
+ return false;
183
+ };
184
+ const evaluateCssRules = (value, rules) => {
185
+ if (!rules) {
186
+ return {};
187
+ }
188
+ return rules.reduce((acc, rule) => {
189
+ const result = ruleResolver(rule, value);
190
+ if (result) {
191
+ return { ...acc, ...rule.styles };
192
+ }
193
+ return acc;
194
+ }, {});
195
+ };
196
+ const evaluateValueRules = (value, rules) => {
197
+ if (!rules)
198
+ return value;
199
+ for (const rule of rules) {
200
+ if (ruleResolver(rule, value))
201
+ return rule.then;
202
+ }
203
+ return value;
204
+ };
205
+
206
206
  const ICON_DESIGN_POSITIVE = 'Positive';
207
207
  const ICON_DESIGN_NEGATIVE = 'Negative';
208
208
  const ICON_NAME_POSITIVE = 'accept';
@@ -239,6 +239,77 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
239
239
  args: [{ selector: 'mfp-link-value', imports: [Link], changeDetection: ChangeDetectionStrategy.OnPush, schemas: [CUSTOM_ELEMENTS_SCHEMA], template: "<ui5-link\n target=\"_blank\"\n [attr.data-testid]=\"testId()\"\n [href]=\"urlValue()\"\n [tooltip]=\"urlValue()\"\n (click)=\"stopPropagation($event)\"\n>Link</ui5-link>\n" }]
240
240
  }], propDecorators: { urlValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "urlValue", required: true }] }], testId: [{ type: i0.Input, args: [{ isSignal: true, alias: "testId", required: false }] }] } });
241
241
 
242
+ /**
243
+ * Read-only display for a `propertyCollection` field. Renders the resolved
244
+ * array as a column of collapsed cards; expanding a card lists each sub-field
245
+ * as a `label: value` row rendered through `mfp-resource-field`, so per-
246
+ * sub-field `uiSettings` still apply. Mirrors the styling of the editable
247
+ * `mfp-form-collection-field`.
248
+ */
249
+ class ResourceCollectionField {
250
+ fieldDefinition = input.required(...(ngDevMode ? [{ debugName: "fieldDefinition" }] : /* istanbul ignore next */ []));
251
+ resource = input(...(ngDevMode ? [undefined, { debugName: "resource" }] : /* istanbul ignore next */ []));
252
+ expandedIndex = signal(null, ...(ngDevMode ? [{ debugName: "expandedIndex" }] : /* istanbul ignore next */ []));
253
+ collectionPath = computed(() => {
254
+ const property = this.fieldDefinition().property;
255
+ return typeof property === 'string' ? property : undefined;
256
+ }, ...(ngDevMode ? [{ debugName: "collectionPath" }] : /* istanbul ignore next */ []));
257
+ entries = computed(() => {
258
+ const value = getResourceValueByJsonPath(this.resource() ?? {}, {
259
+ property: this.collectionPath(),
260
+ });
261
+ return Array.isArray(value) ? value : [];
262
+ }, ...(ngDevMode ? [{ debugName: "entries" }] : /* istanbul ignore next */ []));
263
+ rows = computed(() => {
264
+ const parent = this.collectionPath();
265
+ return (this.fieldDefinition().propertyCollection ?? []).map((sub) => {
266
+ const property = typeof sub.property === 'string'
267
+ ? this.stripParentPath(sub.property, parent)
268
+ : sub.property;
269
+ return {
270
+ label: sub.label ?? this.leafOf(property),
271
+ field: { ...sub, property },
272
+ };
273
+ });
274
+ }, ...(ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []));
275
+ toggle(index, event) {
276
+ event?.stopPropagation();
277
+ this.expandedIndex.set(this.expandedIndex() === index ? null : index);
278
+ }
279
+ previewFor(entry, index) {
280
+ for (const row of this.rows()) {
281
+ const raw = getResourceValueByJsonPath(entry, {
282
+ property: row.field.property,
283
+ });
284
+ if (raw !== undefined && raw !== null && String(raw).trim() !== '') {
285
+ return `${row.label}: ${String(raw)}`;
286
+ }
287
+ }
288
+ const prefix = (this.fieldDefinition().label ?? '').trim() || 'Item';
289
+ return `${prefix} ${index + 1}`;
290
+ }
291
+ stripParentPath(name, parent) {
292
+ if (!parent)
293
+ return name;
294
+ if (name.startsWith(parent + '.')) {
295
+ return name.slice(parent.length + 1);
296
+ }
297
+ return name;
298
+ }
299
+ leafOf(property) {
300
+ if (typeof property !== 'string')
301
+ return '';
302
+ const segments = property.split('.');
303
+ return segments[segments.length - 1];
304
+ }
305
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: ResourceCollectionField, deps: [], target: i0.ɵɵFactoryTarget.Component });
306
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: ResourceCollectionField, isStandalone: true, selector: "mfp-resource-collection-field", inputs: { fieldDefinition: { classPropertyName: "fieldDefinition", publicName: "fieldDefinition", isSignal: true, isRequired: true, transformFunction: null }, resource: { classPropertyName: "resource", publicName: "resource", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"collection\" data-testid=\"resource-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]=\"'resource-collection-item-' + index\"\n >\n <button\n type=\"button\"\n class=\"card__header\"\n [attr.aria-expanded]=\"expanded\"\n [attr.data-testid]=\"'resource-collection-item-' + index + '-toggle'\"\n (click)=\"toggle(index, $event)\"\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 </button>\n\n @if (expanded) {\n <div class=\"card__body\" (click)=\"$event.stopPropagation()\">\n @for (row of rows(); track row.field.property) {\n <div class=\"row\">\n <span class=\"row__label\">{{ row.label }}:</span>\n <mfp-resource-field\n [fieldDefinition]=\"row.field\"\n [resource]=\"entry\"\n />\n </div>\n }\n </div>\n }\n </div>\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__body{display:flex;flex-direction:column;gap:.5rem;padding:.75rem 1rem 1rem;border-top:1px solid var(--sapGroup_ContentBorderColor, #d9d9d9)}.row{display:flex;gap:.25rem;align-items:baseline}.row__label{font-weight:500;color:var(--sapContent_LabelColor, #556b82);white-space:nowrap}\n"], dependencies: [{ 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(() => ResourceField), selector: "mfp-resource-field", inputs: ["fieldDefinition", "resource"], outputs: ["buttonClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.ShadowDom });
307
+ }
308
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: ResourceCollectionField, decorators: [{
309
+ type: Component,
310
+ args: [{ selector: 'mfp-resource-collection-field', imports: [Icon, forwardRef(() => ResourceField)], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.ShadowDom, schemas: [CUSTOM_ELEMENTS_SCHEMA], template: "<div class=\"collection\" data-testid=\"resource-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]=\"'resource-collection-item-' + index\"\n >\n <button\n type=\"button\"\n class=\"card__header\"\n [attr.aria-expanded]=\"expanded\"\n [attr.data-testid]=\"'resource-collection-item-' + index + '-toggle'\"\n (click)=\"toggle(index, $event)\"\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 </button>\n\n @if (expanded) {\n <div class=\"card__body\" (click)=\"$event.stopPropagation()\">\n @for (row of rows(); track row.field.property) {\n <div class=\"row\">\n <span class=\"row__label\">{{ row.label }}:</span>\n <mfp-resource-field\n [fieldDefinition]=\"row.field\"\n [resource]=\"entry\"\n />\n </div>\n }\n </div>\n }\n </div>\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__body{display:flex;flex-direction:column;gap:.5rem;padding:.75rem 1rem 1rem;border-top:1px solid var(--sapGroup_ContentBorderColor, #d9d9d9)}.row{display:flex;gap:.25rem;align-items:baseline}.row__label{font-weight:500;color:var(--sapContent_LabelColor, #556b82);white-space:nowrap}\n"] }]
311
+ }], propDecorators: { fieldDefinition: [{ type: i0.Input, args: [{ isSignal: true, alias: "fieldDefinition", required: true }] }], resource: [{ type: i0.Input, args: [{ isSignal: true, alias: "resource", required: false }] }] } });
312
+
242
313
  class SecretValue {
243
314
  value = input.required(...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
244
315
  isVisible = input(false, ...(ngDevMode ? [{ debugName: "isVisible" }] : /* istanbul ignore next */ []));
@@ -288,6 +359,7 @@ class ResourceField {
288
359
  tags = computed(() => this.normalizeTagsArray(this.value()), ...(ngDevMode ? [{ debugName: "tags" }] : /* istanbul ignore next */ []));
289
360
  isVisible = signal(false, ...(ngDevMode ? [{ debugName: "isVisible" }] : /* istanbul ignore next */ []));
290
361
  copySuccess = signal(false, ...(ngDevMode ? [{ debugName: "copySuccess" }] : /* istanbul ignore next */ []));
362
+ isCollection = computed(() => !!this.fieldDefinition().propertyCollection?.length, ...(ngDevMode ? [{ debugName: "isCollection" }] : /* istanbul ignore next */ []));
291
363
  toggleVisibility(e) {
292
364
  e.stopPropagation();
293
365
  this.isVisible.set(!this.isVisible());
@@ -310,11 +382,14 @@ class ResourceField {
310
382
  }
311
383
  normalizeTagsArray(value) {
312
384
  if (Array.isArray(value)) {
313
- return value.map(v => String(v).trim()).filter(v => v.length > 0);
385
+ return value.map((v) => String(v).trim()).filter((v) => v.length > 0);
314
386
  }
315
387
  if (typeof value === 'string') {
316
388
  const separator = this.uiSettings()?.tagSettings?.valueSeparator ?? ',';
317
- return value.split(separator).map(v => v.trim()).filter(v => v.length > 0);
389
+ return value
390
+ .split(separator)
391
+ .map((v) => v.trim())
392
+ .filter((v) => v.length > 0);
318
393
  }
319
394
  return [];
320
395
  }
@@ -348,11 +423,25 @@ class ResourceField {
348
423
  });
349
424
  }
350
425
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: ResourceField, deps: [], target: i0.ɵɵFactoryTarget.Component });
351
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: ResourceField, isStandalone: true, selector: "mfp-resource-field", inputs: { fieldDefinition: { classPropertyName: "fieldDefinition", publicName: "fieldDefinition", isSignal: true, isRequired: true, transformFunction: null }, resource: { classPropertyName: "resource", publicName: "resource", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { buttonClick: "buttonClick" }, ngImport: i0, template: "@let displayType = displayAs();\n<span [attr.data-testid]=\"testId()\" [style]=\"cssStyles()\">\n @if (displayType === 'secret') {\n <span class=\"secret-value-container\">\n <mfp-secret-value [isVisible]=\"isVisible()\" [testId]=\"testId() + '-secret'\" [value]=\"value()\" />\n <ui5-icon\n class=\"toggle-icon\"\n mode=\"Interactive\"\n [accessibleName]=\"isVisible() ? 'Hide value' : 'Show value'\"\n [attr.data-testid]=\"testId() + '-secret-toggle'\"\n [name]=\"isVisible() ? 'hide' : 'show'\"\n (click)=\"toggleVisibility($event)\"\n />\n </span>\n } @else if (displayType === 'boolIcon' && isBoolLike()) {\n <mfp-boolean-value [boolValue]=\"boolValue()!\" [testId]=\"testId() + '-boolean'\" />\n } @else if (displayType === 'link' && isUrlValue()) {\n <mfp-link-value [testId]=\"testId() + '-link'\" [urlValue]=\"stringValue()!\" />\n } @else if (displayType === 'tooltip') {\n <ui5-icon\n [accessibleName]=\"stringValue()!\"\n [attr.data-testid]=\"testId() + '-tooltip'\"\n [name]=\"tooltipIcon() ?? 'hint'\"\n [showTooltip]=\"true\"\n />\n } @else if (displayType === 'alert') {\n @if (!value()) {\n <ui5-icon\n design=\"Critical\"\n name=\"alert\"\n [accessibleName]=\"resource()?.accessibleName ?? ''\"\n [attr.data-testid]=\"testId() + '-icon'\"\n [showTooltip]=\"true\"\n (click)=\"$event.stopPropagation()\"\n />\n }\n } @else if (displayType === 'img' && value()) {\n <img alt=\"Resource image\" class=\"image-cell\" [src]=\"value()\" />\n } @else if (displayType === 'button') {\n @let buttonSettings = uiSettings()?.buttonSettings;\n <ui5-button\n [attr.data-testid]=\"testId() + '-button'\"\n [accessibleName]=\"buttonSettings?.text || buttonSettings?.tooltip || buttonSettings?.icon || ''\"\n [design]=\"buttonSettings?.design\"\n [endIcon]=\"buttonSettings?.endIcon\"\n [icon]=\"buttonSettings?.icon\"\n [tooltip]=\"buttonSettings?.tooltip\"\n (click)=\"buttonClicked($event)\"\n >{{ buttonSettings?.text }}</ui5-button\n >&nbsp;\n } @else if (displayType === 'tag') {\n <mfp-tag-list-value\n [tagSettings]=\"uiSettings()?.tagSettings\"\n [tags]=\"tags()\"\n [testId]=\"testId() + '-tags'\"\n />\n } @else {\n {{ displayValue() }}\n }\n</span>\n\n@if (withCopyButton()) {\n <ui5-icon\n class=\"toggle-icon\"\n mode=\"Interactive\"\n [accessibleName]=\"copySuccess() ? 'Copied' : 'Copy value'\"\n [attr.data-testid]=\"testId() + '-copy'\"\n [design]=\"copySuccess() ? 'Positive' : 'Default'\"\n [name]=\"copySuccess() ? 'accept' : 'copy'\"\n (click)=\"copyValue($event)\"\n />\n}\n", styles: [":host{display:inline-flex;align-items:center}.secret-value-container{display:flex;align-items:center;gap:.25rem}.toggle-icon{cursor:pointer;transition:color .2s ease;padding:.25rem}.toggle-icon:hover{color:var(--sapButton_Hover_TextColor, #0854a0)}\n"], dependencies: [{ kind: "component", type: Icon, selector: "ui5-icon, [ui5-icon]", inputs: ["design", "name", "accessibleName", "showTooltip", "mode"], outputs: ["ui5Click"], exportAs: ["ui5Icon"] }, { kind: "component", type: BooleanValue, selector: "mfp-boolean-value", inputs: ["boolValue", "testId"] }, { kind: "component", type: LinkValue, selector: "mfp-link-value", inputs: ["urlValue", "testId"] }, { kind: "component", type: SecretValue, selector: "mfp-secret-value", inputs: ["value", "isVisible", "testId"] }, { 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: TagListValue, selector: "mfp-tag-list-value", inputs: ["tags", "tagSettings", "testId"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.ShadowDom });
426
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: ResourceField, isStandalone: true, selector: "mfp-resource-field", inputs: { fieldDefinition: { classPropertyName: "fieldDefinition", publicName: "fieldDefinition", isSignal: true, isRequired: true, transformFunction: null }, resource: { classPropertyName: "resource", publicName: "resource", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { buttonClick: "buttonClick" }, host: { properties: { "class.resource-field--collection": "isCollection()" } }, ngImport: i0, template: "@if (isCollection()) {\n <mfp-resource-collection-field\n [fieldDefinition]=\"fieldDefinition()\"\n [resource]=\"resource()\"\n />\n} @else {\n @let displayType = displayAs();\n <span [attr.data-testid]=\"testId()\" [style]=\"cssStyles()\">\n @if (displayType === 'secret') {\n <span class=\"secret-value-container\">\n <mfp-secret-value [isVisible]=\"isVisible()\" [testId]=\"testId() + '-secret'\" [value]=\"value()\" />\n <ui5-icon\n class=\"toggle-icon\"\n mode=\"Interactive\"\n [accessibleName]=\"isVisible() ? 'Hide value' : 'Show value'\"\n [attr.data-testid]=\"testId() + '-secret-toggle'\"\n [name]=\"isVisible() ? 'hide' : 'show'\"\n (click)=\"toggleVisibility($event)\"\n />\n </span>\n } @else if (displayType === 'boolIcon' && isBoolLike()) {\n <mfp-boolean-value [boolValue]=\"boolValue()!\" [testId]=\"testId() + '-boolean'\" />\n } @else if (displayType === 'link' && isUrlValue()) {\n <mfp-link-value [testId]=\"testId() + '-link'\" [urlValue]=\"stringValue()!\" />\n } @else if (displayType === 'tooltip') {\n <ui5-icon\n [accessibleName]=\"stringValue()!\"\n [attr.data-testid]=\"testId() + '-tooltip'\"\n [name]=\"tooltipIcon() ?? 'hint'\"\n [showTooltip]=\"true\"\n />\n } @else if (displayType === 'alert') {\n @if (!value()) {\n <ui5-icon\n design=\"Critical\"\n name=\"alert\"\n [accessibleName]=\"resource()?.accessibleName ?? ''\"\n [attr.data-testid]=\"testId() + '-icon'\"\n [showTooltip]=\"true\"\n (click)=\"$event.stopPropagation()\"\n />\n }\n } @else if (displayType === 'img' && value()) {\n <img alt=\"Resource image\" class=\"image-cell\" [src]=\"value()\" />\n } @else if (displayType === 'button') {\n @let buttonSettings = uiSettings()?.buttonSettings;\n <ui5-button\n [attr.data-testid]=\"testId() + '-button'\"\n [accessibleName]=\"buttonSettings?.text || buttonSettings?.tooltip || buttonSettings?.icon || ''\"\n [design]=\"buttonSettings?.design\"\n [endIcon]=\"buttonSettings?.endIcon\"\n [icon]=\"buttonSettings?.icon\"\n [tooltip]=\"buttonSettings?.tooltip\"\n (click)=\"buttonClicked($event)\"\n >{{ buttonSettings?.text }}</ui5-button\n >&nbsp;\n } @else if (displayType === 'tag') {\n <mfp-tag-list-value\n [tagSettings]=\"uiSettings()?.tagSettings\"\n [tags]=\"tags()\"\n [testId]=\"testId() + '-tags'\"\n />\n } @else {\n {{ displayValue() }}\n }\n </span>\n\n @if (withCopyButton()) {\n <ui5-icon\n class=\"toggle-icon\"\n mode=\"Interactive\"\n [accessibleName]=\"copySuccess() ? 'Copied' : 'Copy value'\"\n [attr.data-testid]=\"testId() + '-copy'\"\n [design]=\"copySuccess() ? 'Positive' : 'Default'\"\n [name]=\"copySuccess() ? 'accept' : 'copy'\"\n (click)=\"copyValue($event)\"\n />\n }\n}\n", styles: [":host{display:inline-flex;align-items:center}:host(.resource-field--collection){display:block;width:100%}.secret-value-container{display:flex;align-items:center;gap:.25rem}.toggle-icon{cursor:pointer;transition:color .2s ease;padding:.25rem}.toggle-icon:hover{color:var(--sapButton_Hover_TextColor, #0854a0)}\n"], dependencies: [{ 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(() => BooleanValue), selector: "mfp-boolean-value", inputs: ["boolValue", "testId"] }, { kind: "component", type: i0.forwardRef(() => LinkValue), selector: "mfp-link-value", inputs: ["urlValue", "testId"] }, { kind: "component", type: i0.forwardRef(() => SecretValue), selector: "mfp-secret-value", inputs: ["value", "isVisible", "testId"] }, { 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(() => TagListValue), selector: "mfp-tag-list-value", inputs: ["tags", "tagSettings", "testId"] }, { kind: "component", type: i0.forwardRef(() => ResourceCollectionField), selector: "mfp-resource-collection-field", inputs: ["fieldDefinition", "resource"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.ShadowDom });
352
427
  }
353
428
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: ResourceField, decorators: [{
354
429
  type: Component,
355
- args: [{ selector: 'mfp-resource-field', imports: [Icon, BooleanValue, LinkValue, SecretValue, Button, TagListValue], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.ShadowDom, schemas: [CUSTOM_ELEMENTS_SCHEMA], template: "@let displayType = displayAs();\n<span [attr.data-testid]=\"testId()\" [style]=\"cssStyles()\">\n @if (displayType === 'secret') {\n <span class=\"secret-value-container\">\n <mfp-secret-value [isVisible]=\"isVisible()\" [testId]=\"testId() + '-secret'\" [value]=\"value()\" />\n <ui5-icon\n class=\"toggle-icon\"\n mode=\"Interactive\"\n [accessibleName]=\"isVisible() ? 'Hide value' : 'Show value'\"\n [attr.data-testid]=\"testId() + '-secret-toggle'\"\n [name]=\"isVisible() ? 'hide' : 'show'\"\n (click)=\"toggleVisibility($event)\"\n />\n </span>\n } @else if (displayType === 'boolIcon' && isBoolLike()) {\n <mfp-boolean-value [boolValue]=\"boolValue()!\" [testId]=\"testId() + '-boolean'\" />\n } @else if (displayType === 'link' && isUrlValue()) {\n <mfp-link-value [testId]=\"testId() + '-link'\" [urlValue]=\"stringValue()!\" />\n } @else if (displayType === 'tooltip') {\n <ui5-icon\n [accessibleName]=\"stringValue()!\"\n [attr.data-testid]=\"testId() + '-tooltip'\"\n [name]=\"tooltipIcon() ?? 'hint'\"\n [showTooltip]=\"true\"\n />\n } @else if (displayType === 'alert') {\n @if (!value()) {\n <ui5-icon\n design=\"Critical\"\n name=\"alert\"\n [accessibleName]=\"resource()?.accessibleName ?? ''\"\n [attr.data-testid]=\"testId() + '-icon'\"\n [showTooltip]=\"true\"\n (click)=\"$event.stopPropagation()\"\n />\n }\n } @else if (displayType === 'img' && value()) {\n <img alt=\"Resource image\" class=\"image-cell\" [src]=\"value()\" />\n } @else if (displayType === 'button') {\n @let buttonSettings = uiSettings()?.buttonSettings;\n <ui5-button\n [attr.data-testid]=\"testId() + '-button'\"\n [accessibleName]=\"buttonSettings?.text || buttonSettings?.tooltip || buttonSettings?.icon || ''\"\n [design]=\"buttonSettings?.design\"\n [endIcon]=\"buttonSettings?.endIcon\"\n [icon]=\"buttonSettings?.icon\"\n [tooltip]=\"buttonSettings?.tooltip\"\n (click)=\"buttonClicked($event)\"\n >{{ buttonSettings?.text }}</ui5-button\n >&nbsp;\n } @else if (displayType === 'tag') {\n <mfp-tag-list-value\n [tagSettings]=\"uiSettings()?.tagSettings\"\n [tags]=\"tags()\"\n [testId]=\"testId() + '-tags'\"\n />\n } @else {\n {{ displayValue() }}\n }\n</span>\n\n@if (withCopyButton()) {\n <ui5-icon\n class=\"toggle-icon\"\n mode=\"Interactive\"\n [accessibleName]=\"copySuccess() ? 'Copied' : 'Copy value'\"\n [attr.data-testid]=\"testId() + '-copy'\"\n [design]=\"copySuccess() ? 'Positive' : 'Default'\"\n [name]=\"copySuccess() ? 'accept' : 'copy'\"\n (click)=\"copyValue($event)\"\n />\n}\n", styles: [":host{display:inline-flex;align-items:center}.secret-value-container{display:flex;align-items:center;gap:.25rem}.toggle-icon{cursor:pointer;transition:color .2s ease;padding:.25rem}.toggle-icon:hover{color:var(--sapButton_Hover_TextColor, #0854a0)}\n"] }]
430
+ args: [{ selector: 'mfp-resource-field', imports: [
431
+ Icon,
432
+ BooleanValue,
433
+ LinkValue,
434
+ SecretValue,
435
+ Button,
436
+ TagListValue,
437
+ // `ResourceCollectionField` imports this component back (each expanded
438
+ // card renders its sub-fields via `mfp-resource-field`), so the two form
439
+ // a module-init cycle. `forwardRef` defers resolution until the template
440
+ // is instantiated, by which point both classes are defined.
441
+ forwardRef(() => ResourceCollectionField),
442
+ ], host: {
443
+ '[class.resource-field--collection]': 'isCollection()',
444
+ }, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.ShadowDom, schemas: [CUSTOM_ELEMENTS_SCHEMA], template: "@if (isCollection()) {\n <mfp-resource-collection-field\n [fieldDefinition]=\"fieldDefinition()\"\n [resource]=\"resource()\"\n />\n} @else {\n @let displayType = displayAs();\n <span [attr.data-testid]=\"testId()\" [style]=\"cssStyles()\">\n @if (displayType === 'secret') {\n <span class=\"secret-value-container\">\n <mfp-secret-value [isVisible]=\"isVisible()\" [testId]=\"testId() + '-secret'\" [value]=\"value()\" />\n <ui5-icon\n class=\"toggle-icon\"\n mode=\"Interactive\"\n [accessibleName]=\"isVisible() ? 'Hide value' : 'Show value'\"\n [attr.data-testid]=\"testId() + '-secret-toggle'\"\n [name]=\"isVisible() ? 'hide' : 'show'\"\n (click)=\"toggleVisibility($event)\"\n />\n </span>\n } @else if (displayType === 'boolIcon' && isBoolLike()) {\n <mfp-boolean-value [boolValue]=\"boolValue()!\" [testId]=\"testId() + '-boolean'\" />\n } @else if (displayType === 'link' && isUrlValue()) {\n <mfp-link-value [testId]=\"testId() + '-link'\" [urlValue]=\"stringValue()!\" />\n } @else if (displayType === 'tooltip') {\n <ui5-icon\n [accessibleName]=\"stringValue()!\"\n [attr.data-testid]=\"testId() + '-tooltip'\"\n [name]=\"tooltipIcon() ?? 'hint'\"\n [showTooltip]=\"true\"\n />\n } @else if (displayType === 'alert') {\n @if (!value()) {\n <ui5-icon\n design=\"Critical\"\n name=\"alert\"\n [accessibleName]=\"resource()?.accessibleName ?? ''\"\n [attr.data-testid]=\"testId() + '-icon'\"\n [showTooltip]=\"true\"\n (click)=\"$event.stopPropagation()\"\n />\n }\n } @else if (displayType === 'img' && value()) {\n <img alt=\"Resource image\" class=\"image-cell\" [src]=\"value()\" />\n } @else if (displayType === 'button') {\n @let buttonSettings = uiSettings()?.buttonSettings;\n <ui5-button\n [attr.data-testid]=\"testId() + '-button'\"\n [accessibleName]=\"buttonSettings?.text || buttonSettings?.tooltip || buttonSettings?.icon || ''\"\n [design]=\"buttonSettings?.design\"\n [endIcon]=\"buttonSettings?.endIcon\"\n [icon]=\"buttonSettings?.icon\"\n [tooltip]=\"buttonSettings?.tooltip\"\n (click)=\"buttonClicked($event)\"\n >{{ buttonSettings?.text }}</ui5-button\n >&nbsp;\n } @else if (displayType === 'tag') {\n <mfp-tag-list-value\n [tagSettings]=\"uiSettings()?.tagSettings\"\n [tags]=\"tags()\"\n [testId]=\"testId() + '-tags'\"\n />\n } @else {\n {{ displayValue() }}\n }\n </span>\n\n @if (withCopyButton()) {\n <ui5-icon\n class=\"toggle-icon\"\n mode=\"Interactive\"\n [accessibleName]=\"copySuccess() ? 'Copied' : 'Copy value'\"\n [attr.data-testid]=\"testId() + '-copy'\"\n [design]=\"copySuccess() ? 'Positive' : 'Default'\"\n [name]=\"copySuccess() ? 'accept' : 'copy'\"\n (click)=\"copyValue($event)\"\n />\n }\n}\n", styles: [":host{display:inline-flex;align-items:center}:host(.resource-field--collection){display:block;width:100%}.secret-value-container{display:flex;align-items:center;gap:.25rem}.toggle-icon{cursor:pointer;transition:color .2s ease;padding:.25rem}.toggle-icon:hover{color:var(--sapButton_Hover_TextColor, #0854a0)}\n"] }]
356
445
  }], propDecorators: { fieldDefinition: [{ type: i0.Input, args: [{ isSignal: true, alias: "fieldDefinition", required: true }] }], resource: [{ type: i0.Input, args: [{ isSignal: true, alias: "resource", required: false }] }], buttonClick: [{ type: i0.Output, args: ["buttonClick"] }] } });
357
446
 
358
447
  const processGroupFields = (fields) => {