@openmfp/ngx 1.2.0 → 1.3.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.
- package/fesm2022/openmfp-ngx.mjs +68 -3
- package/package.json +1 -1
- package/types/openmfp-ngx.d.ts +27 -0
package/fesm2022/openmfp-ngx.mjs
CHANGED
|
@@ -27,6 +27,7 @@ import '@ui5/webcomponents-icons/dist/add.js';
|
|
|
27
27
|
import '@ui5/webcomponents-icons/dist/delete.js';
|
|
28
28
|
import '@ui5/webcomponents-icons/dist/navigation-down-arrow.js';
|
|
29
29
|
import '@ui5/webcomponents-icons/dist/navigation-right-arrow.js';
|
|
30
|
+
import { InputIcon } from '@fundamental-ngx/ui5-webcomponents/input-icon';
|
|
30
31
|
import { Label } from '@fundamental-ngx/ui5-webcomponents/label';
|
|
31
32
|
import { Option } from '@fundamental-ngx/ui5-webcomponents/option';
|
|
32
33
|
import { Select } from '@fundamental-ngx/ui5-webcomponents/select';
|
|
@@ -1832,6 +1833,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImpor
|
|
|
1832
1833
|
], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.ShadowDom, schemas: [CUSTOM_ELEMENTS_SCHEMA], template: "<ui5-dialog\n data-testid=\"generic-table-card-delete-dialog\"\n [accessibleName]=\"config()?.title ?? 'Confirm Delete'\"\n [open]=\"open()\"\n (ui5BeforeClose)=\"cancelled.emit()\"\n>\n <div class=\"dialog__header\" slot=\"header\">\n <ui5-icon class=\"dialog__header-icon\" design=\"Critical\" name=\"alert\" />\n <ui5-title level=\"H5\">\n <span\n [innerHTML]=\"config()?.title ?? 'Confirm Delete' | sanitizeHtml\"\n ></span>\n </ui5-title>\n </div>\n @if (config()?.message || requiresConfirmation()) {\n <div class=\"dialog__body\">\n @if (config()?.message; as message) {\n <p class=\"dialog__message\" [innerHTML]=\"message | sanitizeHtml\"></p>\n }\n @if (requiresConfirmation()) {\n <p class=\"dialog__message\">\n <ui5-input\n class=\"dialog__confirmation-input\"\n data-testid=\"generic-table-card-delete-confirmation-input\"\n [formControl]=\"confirmationControl\"\n [placeholder]=\"\n config()?.confirmationPlaceholder ?? 'Type to confirm'\n \"\n [valueState]=\"\n confirmationControl.invalid && confirmationControl.dirty\n ? 'Negative'\n : 'None'\n \"\n />\n </p>\n }\n </div>\n }\n <div class=\"dialog__footer\" slot=\"footer\">\n <ui5-button\n data-testid=\"generic-table-card-delete-confirm\"\n design=\"Negative\"\n [disabled]=\"confirmDisabled()\"\n (click)=\"onConfirm()\"\n >\n {{ config()?.confirmLabel ?? 'Delete' }}\n </ui5-button>\n <ui5-button\n data-testid=\"generic-table-card-delete-cancel\"\n design=\"Transparent\"\n (click)=\"cancelled.emit()\"\n >\n {{ config()?.cancelLabel ?? 'Cancel' }}\n </ui5-button>\n </div>\n</ui5-dialog>\n", styles: [":host{display:contents}.dialog__header{display:flex;align-items:center;gap:.5rem;padding:.75rem 1rem}.dialog__header-icon{color:var(--sapCriticalColor)}.dialog__body{margin:-1rem;min-width:320px;padding:1rem}.dialog__message{margin:0;font-size:.875rem;max-width:320px}.dialog__message--critical{color:var(--sapCriticalElementColor)}.dialog__confirmation-input{display:block;width:100%;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"] }]
|
|
1833
1834
|
}], ctorParameters: () => [], propDecorators: { open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], confirmed: [{ type: i0.Output, args: ["confirmed"] }], cancelled: [{ type: i0.Output, args: ["cancelled"] }] } });
|
|
1834
1835
|
|
|
1836
|
+
function coerceBoolean(value) {
|
|
1837
|
+
if (typeof value === 'boolean')
|
|
1838
|
+
return value;
|
|
1839
|
+
if (typeof value === 'string') {
|
|
1840
|
+
return value.trim().toLowerCase() === 'true';
|
|
1841
|
+
}
|
|
1842
|
+
return false;
|
|
1843
|
+
}
|
|
1844
|
+
|
|
1835
1845
|
const FORBIDDEN_SEGMENTS = new Set(['__proto__', 'prototype', 'constructor']);
|
|
1836
1846
|
function setPropertyByPath(object, path, value) {
|
|
1837
1847
|
const segments = path.split('.').filter(Boolean);
|
|
@@ -1941,6 +1951,8 @@ class DeclarativeForm {
|
|
|
1941
1951
|
form;
|
|
1942
1952
|
collectionSeeds = signal({}, /* @ts-ignore */
|
|
1943
1953
|
...(ngDevMode ? [{ debugName: "collectionSeeds" }] : /* istanbul ignore next */ []));
|
|
1954
|
+
passwordVisible = signal({}, /* @ts-ignore */
|
|
1955
|
+
...(ngDevMode ? [{ debugName: "passwordVisible" }] : /* istanbul ignore next */ []));
|
|
1944
1956
|
fb = inject(FormBuilder);
|
|
1945
1957
|
constructor() {
|
|
1946
1958
|
this.form = this.fb.group({});
|
|
@@ -1977,6 +1989,47 @@ class DeclarativeForm {
|
|
|
1977
1989
|
});
|
|
1978
1990
|
}
|
|
1979
1991
|
}
|
|
1992
|
+
setSwitchValue($event, field) {
|
|
1993
|
+
const target = $event.target;
|
|
1994
|
+
const control = this.form.controls[field.name];
|
|
1995
|
+
const checked = coerceBoolean(target.checked);
|
|
1996
|
+
control.setValue(checked);
|
|
1997
|
+
control.markAsTouched();
|
|
1998
|
+
control.markAsDirty();
|
|
1999
|
+
this.formValueChange.emit(this.form.value);
|
|
2000
|
+
if (field.validation === 'onChange') {
|
|
2001
|
+
this.fieldChange.emit({
|
|
2002
|
+
fieldProperty: field.name,
|
|
2003
|
+
value: checked,
|
|
2004
|
+
});
|
|
2005
|
+
}
|
|
2006
|
+
}
|
|
2007
|
+
coerceChecked = coerceBoolean;
|
|
2008
|
+
isPasswordVisible(field) {
|
|
2009
|
+
return this.passwordVisible()[field.name] ?? false;
|
|
2010
|
+
}
|
|
2011
|
+
passwordInputType(field) {
|
|
2012
|
+
if (field.inputType !== 'Password') {
|
|
2013
|
+
return 'Text';
|
|
2014
|
+
}
|
|
2015
|
+
return this.isPasswordVisible(field) ? 'Text' : 'Password';
|
|
2016
|
+
}
|
|
2017
|
+
passwordToggleIcon(field) {
|
|
2018
|
+
return this.isPasswordVisible(field) ? 'hide' : 'show';
|
|
2019
|
+
}
|
|
2020
|
+
passwordToggleLabel(field) {
|
|
2021
|
+
return this.isPasswordVisible(field) ? 'Hide value' : 'Show value';
|
|
2022
|
+
}
|
|
2023
|
+
shouldShowPasswordToggle(field) {
|
|
2024
|
+
return field.inputType === 'Password' && (field.showPasswordToggle ?? true);
|
|
2025
|
+
}
|
|
2026
|
+
togglePasswordVisibility(field, event) {
|
|
2027
|
+
event.stopPropagation();
|
|
2028
|
+
this.passwordVisible.update((state) => ({
|
|
2029
|
+
...state,
|
|
2030
|
+
[field.name]: !this.isPasswordVisible(field),
|
|
2031
|
+
}));
|
|
2032
|
+
}
|
|
1980
2033
|
onCollectionValueChange(field, entries) {
|
|
1981
2034
|
const array = this.form.controls[field.name];
|
|
1982
2035
|
if (!array)
|
|
@@ -2017,6 +2070,7 @@ class DeclarativeForm {
|
|
|
2017
2070
|
}
|
|
2018
2071
|
clear() {
|
|
2019
2072
|
this.form.reset();
|
|
2073
|
+
this.passwordVisible.set({});
|
|
2020
2074
|
}
|
|
2021
2075
|
collectionEntries(field) {
|
|
2022
2076
|
return this.collectionSeeds()[field.name] ?? [];
|
|
@@ -2039,6 +2093,9 @@ class DeclarativeForm {
|
|
|
2039
2093
|
if (wantsCollection) {
|
|
2040
2094
|
this.form.addControl(field.name, this.fb.array([]));
|
|
2041
2095
|
}
|
|
2096
|
+
else if (field.inputType === 'Switch') {
|
|
2097
|
+
this.form.addControl(field.name, new FormControl(false));
|
|
2098
|
+
}
|
|
2042
2099
|
else {
|
|
2043
2100
|
this.form.addControl(field.name, new FormControl(''));
|
|
2044
2101
|
}
|
|
@@ -2073,7 +2130,13 @@ class DeclarativeForm {
|
|
|
2073
2130
|
seeds[field.name] = entries;
|
|
2074
2131
|
}
|
|
2075
2132
|
this.collectionSeeds.set(seeds);
|
|
2076
|
-
|
|
2133
|
+
const normalizedValues = { ...initialValues };
|
|
2134
|
+
for (const field of this.fields()) {
|
|
2135
|
+
if (field.inputType === 'Switch') {
|
|
2136
|
+
normalizedValues[field.name] = coerceBoolean(normalizedValues[field.name]);
|
|
2137
|
+
}
|
|
2138
|
+
}
|
|
2139
|
+
this.form.patchValue(normalizedValues, { emitEvent: false });
|
|
2077
2140
|
this.form.markAsPristine({ emitEvent: false });
|
|
2078
2141
|
this.form.updateValueAndValidity({ emitEvent: false });
|
|
2079
2142
|
}
|
|
@@ -2095,18 +2158,20 @@ class DeclarativeForm {
|
|
|
2095
2158
|
});
|
|
2096
2159
|
}
|
|
2097
2160
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: DeclarativeForm, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2098
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.2", type: DeclarativeForm, isStandalone: true, selector: "mfp-declarative-form", inputs: { fields: { classPropertyName: "fields", publicName: "fields", isSignal: true, isRequired: false, 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 [attr.for]=\"'generic-form-field-input-' + 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 [initialEntries]=\"collectionEntries(field)\"\n [label]=\"field.label\"\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 [id]=\"'generic-form-field-input-' + field.name\"\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 [id]=\"'generic-form-field-input-' + field.name\"\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: ["accessibleDescription", "accessibleDescriptionRef", "accessibleName", "accessibleNameRef", "disabled", "filter", "maxlength", "name", "noTypeahead", "open", "placeholder", "readonly", "required", "showClearIcon", "showSuggestions", "type", "value", "valueState"], outputs: ["ui5Change", "ui5Close", "ui5Input", "ui5Open", "ui5Select", "ui5SelectionChange"], exportAs: ["ui5Input"] }, { kind: "component", type: Label, selector: "ui5-label, [ui5-label]", inputs: ["for", "required", "showColon", "wrappingType"], exportAs: ["ui5Label"] }, { kind: "component", type: Select, selector: "ui5-select, [ui5-select]", inputs: ["accessibleDescription", "accessibleDescriptionRef", "accessibleName", "accessibleNameRef", "disabled", "name", "readonly", "required", "textSeparator", "tooltip", "value", "valueState"], outputs: ["ui5Change", "ui5Close", "ui5LiveChange", "ui5Open"], exportAs: ["ui5Select"] }, { kind: "component", type: Option, selector: "ui5-option, [ui5-option]", inputs: ["additionalText", "icon", "selected", "tooltip", "value"], outputs: ["ui5Click"], exportAs: ["ui5Option"] }, { kind: "component", type: FormCollectionField, selector: "mfp-form-collection-field", inputs: ["fields", "label", "initialEntries"], outputs: ["valueChange"] }], encapsulation: i0.ViewEncapsulation.ShadowDom });
|
|
2161
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.2", type: DeclarativeForm, isStandalone: true, selector: "mfp-declarative-form", inputs: { fields: { classPropertyName: "fields", publicName: "fields", isSignal: true, isRequired: false, 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 [class.inputs--switch]=\"field.inputType === 'Switch'\"\n >\n <ui5-label\n show-colon\n [attr.data-testid]=\"'generic-form-field-label-' + field.name\"\n [attr.for]=\"\n field.inputType === 'Switch'\n ? null\n : 'generic-form-field-input-' + field.name\n \"\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 [initialEntries]=\"collectionEntries(field)\"\n [label]=\"field.label\"\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 [id]=\"'generic-form-field-input-' + field.name\"\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 if (field.inputType === 'Switch') {\n <ui5-switch\n class=\"switch\"\n [accessibleName]=\"field.label\"\n [attr.data-testid]=\"'generic-form-field-' + field.name\"\n [checked]=\"coerceChecked(control.value)\"\n [disabled]=\"field.disabled\"\n (blur)=\"onFieldBlur(field)\"\n (ui5Change)=\"setSwitchValue($event, field)\"\n />\n @if (getError(field.name); as error) {\n <div class=\"field-error\" role=\"alert\">{{ error }}</div>\n }\n } @else {\n <ui5-input\n class=\"input\"\n [attr.data-testid]=\"'generic-form-field-' + field.name\"\n [attr.title]=\"field.placeholder || null\"\n [disabled]=\"field.disabled\"\n [id]=\"'generic-form-field-input-' + field.name\"\n [placeholder]=\"field.placeholder ?? ''\"\n [required]=\"field.required\"\n [type]=\"passwordInputType(field)\"\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 (shouldShowPasswordToggle(field)) {\n <ui5-input-icon\n slot=\"icon\"\n [accessibleName]=\"passwordToggleLabel(field)\"\n [attr.data-testid]=\"\n 'generic-form-field-' + field.name + '-password-toggle'\n \"\n [name]=\"passwordToggleIcon(field)\"\n (ui5Click)=\"togglePasswordVisibility(field, $event)\"\n />\n }\n @if (getError(field.name); as error) {\n <div slot=\"valueStateMessage\">{{ error }}</div>\n }\n </ui5-input>\n }\n @if (field.hint && !field.propertyCollection?.length) {\n <div\n class=\"field-hint\"\n [attr.data-testid]=\"'generic-form-field-hint-' + field.name\"\n >\n {{ field.hint }}\n </div>\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%}.inputs--switch{flex-direction:row;align-items:center;gap:.75rem}.switch{flex-shrink:0}.inputs--switch .field-hint{flex-basis:100%}.collection-error,.field-error{color:var(--sapNegativeColor, #b00);font-size:.75rem;margin-top:.25rem}.inputs--switch .field-error{flex-basis:100%}.field-hint{color:var(--sapContent_LabelColor, #6a6d70);font-size:.75rem;line-height:1.4;margin-top:.25rem;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: ["accessibleDescription", "accessibleDescriptionRef", "accessibleName", "accessibleNameRef", "disabled", "filter", "maxlength", "name", "noTypeahead", "open", "placeholder", "readonly", "required", "showClearIcon", "showSuggestions", "type", "value", "valueState"], outputs: ["ui5Change", "ui5Close", "ui5Input", "ui5Open", "ui5Select", "ui5SelectionChange"], exportAs: ["ui5Input"] }, { kind: "component", type: InputIcon, selector: "ui5-input-icon, [ui5-input-icon]", inputs: ["accessibleName", "name"], outputs: ["ui5Click"], exportAs: ["ui5InputIcon"] }, { kind: "component", type: Label, selector: "ui5-label, [ui5-label]", inputs: ["for", "required", "showColon", "wrappingType"], exportAs: ["ui5Label"] }, { kind: "component", type: Select, selector: "ui5-select, [ui5-select]", inputs: ["accessibleDescription", "accessibleDescriptionRef", "accessibleName", "accessibleNameRef", "disabled", "name", "readonly", "required", "textSeparator", "tooltip", "value", "valueState"], outputs: ["ui5Change", "ui5Close", "ui5LiveChange", "ui5Open"], exportAs: ["ui5Select"] }, { kind: "component", type: Option, selector: "ui5-option, [ui5-option]", inputs: ["additionalText", "icon", "selected", "tooltip", "value"], outputs: ["ui5Click"], exportAs: ["ui5Option"] }, { kind: "component", type: Switch, selector: "ui5-switch, [ui5-switch]", inputs: ["accessibleName", "accessibleNameRef", "checked", "design", "disabled", "name", "readonly", "required", "textOff", "textOn", "tooltip", "value"], outputs: ["ui5Change"], exportAs: ["ui5Switch"] }, { kind: "component", type: FormCollectionField, selector: "mfp-form-collection-field", inputs: ["fields", "label", "initialEntries"], outputs: ["valueChange"] }], encapsulation: i0.ViewEncapsulation.ShadowDom });
|
|
2099
2162
|
}
|
|
2100
2163
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: DeclarativeForm, decorators: [{
|
|
2101
2164
|
type: Component,
|
|
2102
2165
|
args: [{ selector: 'mfp-declarative-form', imports: [
|
|
2103
2166
|
ReactiveFormsModule,
|
|
2104
2167
|
Input,
|
|
2168
|
+
InputIcon,
|
|
2105
2169
|
Label,
|
|
2106
2170
|
Select,
|
|
2107
2171
|
Option,
|
|
2172
|
+
Switch,
|
|
2108
2173
|
FormCollectionField,
|
|
2109
|
-
], 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 [attr.for]=\"'generic-form-field-input-' + 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 [initialEntries]=\"collectionEntries(field)\"\n [label]=\"field.label\"\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 [id]=\"'generic-form-field-input-' + field.name\"\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 [id]=\"'generic-form-field-input-' + field.name\"\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"] }]
|
|
2174
|
+
], 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 [class.inputs--switch]=\"field.inputType === 'Switch'\"\n >\n <ui5-label\n show-colon\n [attr.data-testid]=\"'generic-form-field-label-' + field.name\"\n [attr.for]=\"\n field.inputType === 'Switch'\n ? null\n : 'generic-form-field-input-' + field.name\n \"\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 [initialEntries]=\"collectionEntries(field)\"\n [label]=\"field.label\"\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 [id]=\"'generic-form-field-input-' + field.name\"\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 if (field.inputType === 'Switch') {\n <ui5-switch\n class=\"switch\"\n [accessibleName]=\"field.label\"\n [attr.data-testid]=\"'generic-form-field-' + field.name\"\n [checked]=\"coerceChecked(control.value)\"\n [disabled]=\"field.disabled\"\n (blur)=\"onFieldBlur(field)\"\n (ui5Change)=\"setSwitchValue($event, field)\"\n />\n @if (getError(field.name); as error) {\n <div class=\"field-error\" role=\"alert\">{{ error }}</div>\n }\n } @else {\n <ui5-input\n class=\"input\"\n [attr.data-testid]=\"'generic-form-field-' + field.name\"\n [attr.title]=\"field.placeholder || null\"\n [disabled]=\"field.disabled\"\n [id]=\"'generic-form-field-input-' + field.name\"\n [placeholder]=\"field.placeholder ?? ''\"\n [required]=\"field.required\"\n [type]=\"passwordInputType(field)\"\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 (shouldShowPasswordToggle(field)) {\n <ui5-input-icon\n slot=\"icon\"\n [accessibleName]=\"passwordToggleLabel(field)\"\n [attr.data-testid]=\"\n 'generic-form-field-' + field.name + '-password-toggle'\n \"\n [name]=\"passwordToggleIcon(field)\"\n (ui5Click)=\"togglePasswordVisibility(field, $event)\"\n />\n }\n @if (getError(field.name); as error) {\n <div slot=\"valueStateMessage\">{{ error }}</div>\n }\n </ui5-input>\n }\n @if (field.hint && !field.propertyCollection?.length) {\n <div\n class=\"field-hint\"\n [attr.data-testid]=\"'generic-form-field-hint-' + field.name\"\n >\n {{ field.hint }}\n </div>\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%}.inputs--switch{flex-direction:row;align-items:center;gap:.75rem}.switch{flex-shrink:0}.inputs--switch .field-hint{flex-basis:100%}.collection-error,.field-error{color:var(--sapNegativeColor, #b00);font-size:.75rem;margin-top:.25rem}.inputs--switch .field-error{flex-basis:100%}.field-hint{color:var(--sapContent_LabelColor, #6a6d70);font-size:.75rem;line-height:1.4;margin-top:.25rem;width:100%}\n"] }]
|
|
2110
2175
|
}], ctorParameters: () => [], propDecorators: { fields: [{ type: i0.Input, args: [{ isSignal: true, alias: "fields", required: false }] }], 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"] }] } });
|
|
2111
2176
|
|
|
2112
2177
|
class ResourceFormDialog {
|
package/package.json
CHANGED
package/types/openmfp-ngx.d.ts
CHANGED
|
@@ -526,6 +526,22 @@ interface FormFieldDefinition {
|
|
|
526
526
|
values?: string[];
|
|
527
527
|
/** When `true`, the field is disabled (not interactive). */
|
|
528
528
|
disabled?: boolean;
|
|
529
|
+
/** UI5 input type rendered by `mfp-declarative-form`. */
|
|
530
|
+
inputType?: 'Text' | 'Password' | 'Switch';
|
|
531
|
+
/**
|
|
532
|
+
* When `inputType` is `Password`, renders a show/hide icon inside the input.
|
|
533
|
+
* Defaults to `true`; set to `false` to keep the field masked without a toggle.
|
|
534
|
+
*/
|
|
535
|
+
showPasswordToggle?: boolean;
|
|
536
|
+
/** UI5 input placeholder (functional, not example values). */
|
|
537
|
+
placeholder?: string;
|
|
538
|
+
/** Persistent help text below the control; never submitted with the form. */
|
|
539
|
+
hint?: string;
|
|
540
|
+
/**
|
|
541
|
+
* When `true`, the host should omit this field from read queries and skip
|
|
542
|
+
* empty values on edit submit (e.g. write-only secrets).
|
|
543
|
+
*/
|
|
544
|
+
writeOnly?: boolean;
|
|
529
545
|
/** Controls when `fieldChange` is emitted for this field. When omitted, `fieldChange` is never emitted. */
|
|
530
546
|
validation?: 'onBlur' | 'onChange';
|
|
531
547
|
/**
|
|
@@ -553,6 +569,8 @@ interface FormFieldChangeEvent {
|
|
|
553
569
|
/** Map of field names to their current validation error messages (`null` = no error). */
|
|
554
570
|
type FormFieldErrors = Record<string, string | null>;
|
|
555
571
|
|
|
572
|
+
declare function coerceBoolean(value: unknown): boolean;
|
|
573
|
+
|
|
556
574
|
declare class DeclarativeForm<T extends GenericResource> {
|
|
557
575
|
readonly fields: _angular_core.InputSignal<FormFieldDefinition[]>;
|
|
558
576
|
readonly initialValues: _angular_core.InputSignal<T>;
|
|
@@ -562,9 +580,18 @@ declare class DeclarativeForm<T extends GenericResource> {
|
|
|
562
580
|
readonly formValueChange: _angular_core.OutputEmitterRef<Record<string, unknown>>;
|
|
563
581
|
readonly form: FormGroup;
|
|
564
582
|
protected readonly collectionSeeds: _angular_core.WritableSignal<Record<string, Record<string, unknown>[]>>;
|
|
583
|
+
private readonly passwordVisible;
|
|
565
584
|
private readonly fb;
|
|
566
585
|
constructor();
|
|
567
586
|
setFormControlValue($event: Event, field: FormFieldDefinition): void;
|
|
587
|
+
setSwitchValue($event: Event, field: FormFieldDefinition): void;
|
|
588
|
+
protected readonly coerceChecked: typeof coerceBoolean;
|
|
589
|
+
isPasswordVisible(field: FormFieldDefinition): boolean;
|
|
590
|
+
passwordInputType(field: FormFieldDefinition): 'Text' | 'Password';
|
|
591
|
+
passwordToggleIcon(field: FormFieldDefinition): 'hide' | 'show';
|
|
592
|
+
passwordToggleLabel(field: FormFieldDefinition): string;
|
|
593
|
+
shouldShowPasswordToggle(field: FormFieldDefinition): boolean;
|
|
594
|
+
togglePasswordVisibility(field: FormFieldDefinition, event: Event): void;
|
|
568
595
|
onCollectionValueChange(field: FormFieldDefinition, entries: Record<string, unknown>[]): void;
|
|
569
596
|
getError(name: string): string | null;
|
|
570
597
|
getValueState(name: string): 'None' | 'Negative';
|