@mmlogic/components 0.3.2 → 0.3.3

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,11 +1,25 @@
1
1
  import { Host, h } from "@stencil/core";
2
2
  import { ClientLayoutItemType, ClientLayoutItemFieldDataType, ClientLayoutItemRelationDisplayType, } from "../../types";
3
+ import { t } from "../../utils/i18n";
3
4
  export class MrdField {
4
5
  constructor() {
5
6
  this.locale = navigator.language;
7
+ this.historyEntries = [];
8
+ this.currentValue = undefined;
6
9
  this.handleChange = (e) => {
10
+ var _a, _b, _c, _d;
7
11
  e.stopPropagation();
8
- this.mrdChange.emit(e.detail);
12
+ const hist = (_b = (_a = this.item) === null || _a === void 0 ? void 0 : _a.historyEnabled) !== null && _b !== void 0 ? _b : (_d = (_c = this.item) === null || _c === void 0 ? void 0 : _c.field) === null || _d === void 0 ? void 0 : _d.historyEnabled;
13
+ if (hist) {
14
+ this.currentValue = e.detail.value;
15
+ this.mrdChange.emit({
16
+ name: e.detail.name,
17
+ value: { current: e.detail.value, history: this.historyEntries },
18
+ });
19
+ }
20
+ else {
21
+ this.mrdChange.emit(e.detail);
22
+ }
9
23
  };
10
24
  this.handleBlur = (e) => {
11
25
  e.stopPropagation();
@@ -24,63 +38,139 @@ export class MrdField {
24
38
  this.mrdUpload.emit(e.detail);
25
39
  };
26
40
  }
27
- render() {
28
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8;
29
- const { item, locale, value } = this;
30
- if (item.type === ClientLayoutItemType.RELATION) {
31
- return (h(Host, null, h("mrd-relation-field", { name: item.name, label: item.label, required: item.required, disabled: (_a = item.disabled) !== null && _a !== void 0 ? _a : false, locale: locale, relatedClass: item.relatedClass, mostSignificantClass: (_b = item.mostSignificantClass) !== null && _b !== void 0 ? _b : '', displayType: (_c = item.displayType) !== null && _c !== void 0 ? _c : ClientLayoutItemRelationDisplayType.SEARCH, editBehavior: (_d = item.editBehavior) !== null && _d !== void 0 ? _d : null, commonRelation: item.commonRelation, multiple: (_e = item.multiple) !== null && _e !== void 0 ? _e : false, dropdownValues: (_f = item.dropdownValues) !== null && _f !== void 0 ? _f : [], value: value, onMrdChange: this.handleChange, onMrdBlur: this.handleBlur, onMrdSearch: this.handleSearch, onMrdFetchAll: this.handleFetchAll })));
41
+ componentWillLoad() {
42
+ this.initHistoryState();
43
+ }
44
+ valueChanged() {
45
+ this.initHistoryState();
46
+ }
47
+ initHistoryState() {
48
+ var _a, _b, _c, _d, _e;
49
+ const hist = (_b = (_a = this.item) === null || _a === void 0 ? void 0 : _a.historyEnabled) !== null && _b !== void 0 ? _b : (_d = (_c = this.item) === null || _c === void 0 ? void 0 : _c.field) === null || _d === void 0 ? void 0 : _d.historyEnabled;
50
+ if (!hist)
51
+ return;
52
+ const raw = this.value;
53
+ this.currentValue = (_e = raw === null || raw === void 0 ? void 0 : raw.current) !== null && _e !== void 0 ? _e : raw;
54
+ this.historyEntries = Array.isArray(raw === null || raw === void 0 ? void 0 : raw.history) ? [...raw.history] : [];
55
+ }
56
+ getDisplayValue() {
57
+ var _a, _b, _c, _d;
58
+ const hist = (_b = (_a = this.item) === null || _a === void 0 ? void 0 : _a.historyEnabled) !== null && _b !== void 0 ? _b : (_d = (_c = this.item) === null || _c === void 0 ? void 0 : _c.field) === null || _d === void 0 ? void 0 : _d.historyEnabled;
59
+ if (hist && this.value !== null && typeof this.value === 'object' && 'current' in this.value) {
60
+ return this.value.current;
32
61
  }
33
- if (item.type !== ClientLayoutItemType.FIELD) {
34
- return h(Host, null);
62
+ return this.value;
63
+ }
64
+ historyValueInputType() {
65
+ var _a;
66
+ switch ((_a = this.item) === null || _a === void 0 ? void 0 : _a.dataType) {
67
+ case ClientLayoutItemFieldDataType.DATE: return 'date';
68
+ case ClientLayoutItemFieldDataType.DATETIME: return 'datetime-local';
69
+ case ClientLayoutItemFieldDataType.TIME: return 'time';
70
+ case ClientLayoutItemFieldDataType.INTEGER:
71
+ case ClientLayoutItemFieldDataType.DECIMAL:
72
+ case ClientLayoutItemFieldDataType.PERCENTAGE: return 'number';
73
+ case ClientLayoutItemFieldDataType.EMAIL: return 'email';
74
+ default: return 'text';
35
75
  }
76
+ }
77
+ emitHistoryChange(entries) {
78
+ this.historyEntries = entries;
79
+ this.mrdChange.emit({
80
+ name: this.item.name,
81
+ value: { current: this.currentValue, history: entries },
82
+ });
83
+ }
84
+ renderHistoryEditor() {
85
+ var _a, _b, _c, _d;
86
+ const hist = (_b = (_a = this.item) === null || _a === void 0 ? void 0 : _a.historyEnabled) !== null && _b !== void 0 ? _b : (_d = (_c = this.item) === null || _c === void 0 ? void 0 : _c.field) === null || _d === void 0 ? void 0 : _d.historyEnabled;
87
+ if (!hist)
88
+ return null;
89
+ const { locale } = this;
90
+ const valueType = this.historyValueInputType();
91
+ const updateEntry = (i, field, val) => {
92
+ const updated = this.historyEntries.map((e, idx) => idx === i ? Object.assign(Object.assign({}, e), { [field]: val }) : e);
93
+ this.emitHistoryChange(updated);
94
+ };
95
+ const removeEntry = (i) => {
96
+ this.emitHistoryChange(this.historyEntries.filter((_, idx) => idx !== i));
97
+ };
98
+ const addEntry = () => {
99
+ this.emitHistoryChange([...this.historyEntries, { value: '', until: '' }]);
100
+ };
101
+ return (h("div", { class: "mrd-field__history-editor" }, this.historyEntries.length > 0 && (h("span", { class: "mrd-field__history-editor-label" }, t('history_badge_tooltip', locale))), this.historyEntries.map((entry, i) => (h("div", { key: String(i), class: "mrd-field__history-editor-row" }, h("input", { class: "mrd-field__history-editor-value", type: valueType, value: entry.value, onInput: (e) => updateEntry(i, 'value', e.target.value) }), h("span", { class: "mrd-field__history-editor-sep" }, t('history_until', locale)), h("input", { class: "mrd-field__history-editor-until", type: "date", value: entry.until, onInput: (e) => updateEntry(i, 'until', e.target.value) }), h("button", { type: "button", class: "mrd-field__history-editor-remove", onClick: () => removeEntry(i), "aria-label": t('remove', locale) }, h("svg", { viewBox: "0 0 20 20", fill: "currentColor", "aria-hidden": "true" }, h("path", { "fill-rule": "evenodd", d: "M8.75 1A2.75 2.75 0 006 3.75v.443c-.795.077-1.584.176-2.365.298a.75.75 0 10.23 1.482l.149-.022.841 10.518A2.75 2.75 0 007.596 19h4.807a2.75 2.75 0 002.742-2.53l.841-10.52.149.023a.75.75 0 00.23-1.482A41.03 41.03 0 0014 4.193V3.75A2.75 2.75 0 0011.25 1h-2.5zM10 4c.84 0 1.673.025 2.5.075V3.75c0-.69-.56-1.25-1.25-1.25h-2.5c-.69 0-1.25.56-1.25 1.25v.325C8.327 4.025 9.16 4 10 4zM8.58 7.72a.75.75 0 00-1.5.06l.3 7.5a.75.75 0 101.5-.06l-.3-7.5zm4.34.06a.75.75 0 10-1.5-.06l-.3 7.5a.75.75 0 101.5.06l.3-7.5z", "clip-rule": "evenodd" })))))), h("button", { type: "button", class: "mrd-field__history-editor-add", onClick: addEntry }, "+ ", t('add', locale))));
102
+ }
103
+ renderLeafField(displayValue) {
104
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2;
105
+ const { item, locale } = this;
36
106
  const commonProps = {
37
107
  name: item.name,
38
108
  label: item.label,
39
109
  required: item.required,
40
- disabled: (_g = item.disabled) !== null && _g !== void 0 ? _g : false,
110
+ disabled: (_a = item.disabled) !== null && _a !== void 0 ? _a : false,
41
111
  locale,
42
112
  onMrdChange: this.handleChange,
43
113
  onMrdBlur: this.handleBlur,
44
114
  };
45
115
  switch (item.dataType) {
46
116
  case ClientLayoutItemFieldDataType.TEXT:
47
- return (h(Host, null, h("mrd-text-field", Object.assign({}, commonProps, { value: (_h = value) !== null && _h !== void 0 ? _h : '', placeholder: (_j = item.placeholder) !== null && _j !== void 0 ? _j : '' }))));
117
+ return (h("mrd-text-field", Object.assign({}, commonProps, { value: (_b = displayValue) !== null && _b !== void 0 ? _b : '', placeholder: (_c = item.placeholder) !== null && _c !== void 0 ? _c : '' })));
48
118
  case ClientLayoutItemFieldDataType.TEXTBLOCK:
49
- return (h(Host, null, h("mrd-textarea-field", Object.assign({}, commonProps, { value: (_k = value) !== null && _k !== void 0 ? _k : '', placeholder: (_l = item.placeholder) !== null && _l !== void 0 ? _l : '' }))));
119
+ return (h("mrd-textarea-field", Object.assign({}, commonProps, { value: (_d = displayValue) !== null && _d !== void 0 ? _d : '', placeholder: (_e = item.placeholder) !== null && _e !== void 0 ? _e : '' })));
50
120
  case ClientLayoutItemFieldDataType.INTEGER:
51
121
  case ClientLayoutItemFieldDataType.DECIMAL:
52
122
  case ClientLayoutItemFieldDataType.PERCENTAGE:
53
- return (h(Host, null, h("mrd-number-field", Object.assign({}, commonProps, { value: (_m = value) !== null && _m !== void 0 ? _m : null, dataType: item.dataType, decimalPrecision: (_o = item.decimalPrecision) !== null && _o !== void 0 ? _o : 2, placeholder: (_p = item.placeholder) !== null && _p !== void 0 ? _p : '' }))));
123
+ return (h("mrd-number-field", Object.assign({}, commonProps, { value: (_f = displayValue) !== null && _f !== void 0 ? _f : null, dataType: item.dataType, decimalPrecision: (_g = item.decimalPrecision) !== null && _g !== void 0 ? _g : 2, placeholder: (_h = item.placeholder) !== null && _h !== void 0 ? _h : '' })));
54
124
  case ClientLayoutItemFieldDataType.CURRENCY:
55
- return (h(Host, null, h("mrd-currency-field", Object.assign({}, commonProps, { value: (_q = value) !== null && _q !== void 0 ? _q : { amount: null, currency: (_r = item.currencyCode) !== null && _r !== void 0 ? _r : 'EUR' } }))));
125
+ return (h("mrd-currency-field", Object.assign({}, commonProps, { value: (_j = displayValue) !== null && _j !== void 0 ? _j : { amount: null, currency: (_k = item.currencyCode) !== null && _k !== void 0 ? _k : 'EUR' } })));
56
126
  case ClientLayoutItemFieldDataType.BOOLEAN:
57
- return (h(Host, null, h("mrd-boolean-field", Object.assign({}, commonProps, { value: (_s = value) !== null && _s !== void 0 ? _s : false }))));
127
+ return (h("mrd-boolean-field", Object.assign({}, commonProps, { value: (_l = displayValue) !== null && _l !== void 0 ? _l : false })));
58
128
  case ClientLayoutItemFieldDataType.DATE:
59
- return (h(Host, null, h("mrd-date-field", Object.assign({}, commonProps, { value: (_t = value) !== null && _t !== void 0 ? _t : '' }))));
129
+ return (h("mrd-date-field", Object.assign({}, commonProps, { value: (_m = displayValue) !== null && _m !== void 0 ? _m : '' })));
60
130
  case ClientLayoutItemFieldDataType.DATETIME:
61
- return (h(Host, null, h("mrd-datetime-field", Object.assign({}, commonProps, { value: (_u = value) !== null && _u !== void 0 ? _u : '' }))));
131
+ return (h("mrd-datetime-field", Object.assign({}, commonProps, { value: (_o = displayValue) !== null && _o !== void 0 ? _o : '' })));
62
132
  case ClientLayoutItemFieldDataType.TIME:
63
- return (h(Host, null, h("mrd-time-field", Object.assign({}, commonProps, { value: (_v = value) !== null && _v !== void 0 ? _v : '' }))));
133
+ return (h("mrd-time-field", Object.assign({}, commonProps, { value: (_p = displayValue) !== null && _p !== void 0 ? _p : '' })));
64
134
  case ClientLayoutItemFieldDataType.EMAIL:
65
- return (h(Host, null, h("mrd-email-field", Object.assign({}, commonProps, { value: (_w = value) !== null && _w !== void 0 ? _w : '', placeholder: (_x = item.placeholder) !== null && _x !== void 0 ? _x : '' }))));
135
+ return (h("mrd-email-field", Object.assign({}, commonProps, { value: (_q = displayValue) !== null && _q !== void 0 ? _q : '', placeholder: (_r = item.placeholder) !== null && _r !== void 0 ? _r : '' })));
66
136
  case ClientLayoutItemFieldDataType.HYPERLINK:
67
- return (h(Host, null, h("mrd-hyperlink-field", Object.assign({}, commonProps, { value: (_y = value) !== null && _y !== void 0 ? _y : '', placeholder: (_z = item.placeholder) !== null && _z !== void 0 ? _z : '' }))));
137
+ return (h("mrd-hyperlink-field", Object.assign({}, commonProps, { value: (_s = displayValue) !== null && _s !== void 0 ? _s : '', placeholder: (_t = item.placeholder) !== null && _t !== void 0 ? _t : '' })));
68
138
  case ClientLayoutItemFieldDataType.LIST:
69
- return (h(Host, null, h("mrd-list-field", Object.assign({}, commonProps, { value: (_0 = value) !== null && _0 !== void 0 ? _0 : '', multiple: (_1 = item.multiple) !== null && _1 !== void 0 ? _1 : false, listItems: (_2 = item.listItems) !== null && _2 !== void 0 ? _2 : [] }))));
139
+ return (h("mrd-list-field", Object.assign({}, commonProps, { value: (_u = displayValue) !== null && _u !== void 0 ? _u : '', multiple: (_v = item.multiple) !== null && _v !== void 0 ? _v : false, listItems: (_w = item.listItems) !== null && _w !== void 0 ? _w : [] })));
70
140
  case ClientLayoutItemFieldDataType.FILE:
71
- return (h(Host, null, h("mrd-file-field", Object.assign({}, commonProps, { value: value, accept: (_3 = item.accept) !== null && _3 !== void 0 ? _3 : '', maxSize: (_4 = item.maxSize) !== null && _4 !== void 0 ? _4 : 0, onMrdUpload: this.handleUpload }))));
141
+ return (h("mrd-file-field", Object.assign({}, commonProps, { value: displayValue, accept: (_x = item.accept) !== null && _x !== void 0 ? _x : '', maxSize: (_y = item.maxSize) !== null && _y !== void 0 ? _y : 0, onMrdUpload: this.handleUpload })));
72
142
  case ClientLayoutItemFieldDataType.IMAGE:
73
- return (h(Host, null, h("mrd-image-field", Object.assign({}, commonProps, { value: value, accept: (_5 = item.accept) !== null && _5 !== void 0 ? _5 : 'image/*', maxSize: (_6 = item.maxSize) !== null && _6 !== void 0 ? _6 : 0, onMrdUpload: this.handleUpload }))));
143
+ return (h("mrd-image-field", Object.assign({}, commonProps, { value: displayValue, accept: (_z = item.accept) !== null && _z !== void 0 ? _z : 'image/*', maxSize: (_0 = item.maxSize) !== null && _0 !== void 0 ? _0 : 0, onMrdUpload: this.handleUpload })));
74
144
  case ClientLayoutItemFieldDataType.LONGTEXT:
75
- return (h(Host, null, h("mrd-longtext-field", Object.assign({}, commonProps, { value: (_7 = value) !== null && _7 !== void 0 ? _7 : '', placeholder: (_8 = item.placeholder) !== null && _8 !== void 0 ? _8 : '' }))));
76
- case ClientLayoutItemFieldDataType.JSON:
77
- return h(Host, null);
145
+ return (h("mrd-longtext-field", Object.assign({}, commonProps, { value: (_1 = displayValue) !== null && _1 !== void 0 ? _1 : '', placeholder: (_2 = item.placeholder) !== null && _2 !== void 0 ? _2 : '' })));
78
146
  default:
79
- return h(Host, null);
147
+ return null;
80
148
  }
81
149
  }
150
+ render() {
151
+ var _a, _b, _c, _d, _e, _f;
152
+ const { item, locale, value } = this;
153
+ if (item.type === ClientLayoutItemType.RELATION) {
154
+ return (h(Host, null, h("mrd-relation-field", { name: item.name, label: item.label, required: item.required, disabled: (_a = item.disabled) !== null && _a !== void 0 ? _a : false, locale: locale, relatedClass: item.relatedClass, mostSignificantClass: (_b = item.mostSignificantClass) !== null && _b !== void 0 ? _b : '', displayType: (_c = item.displayType) !== null && _c !== void 0 ? _c : ClientLayoutItemRelationDisplayType.SEARCH, editBehavior: (_d = item.editBehavior) !== null && _d !== void 0 ? _d : null, commonRelation: item.commonRelation, multiple: (_e = item.multiple) !== null && _e !== void 0 ? _e : false, dropdownValues: (_f = item.dropdownValues) !== null && _f !== void 0 ? _f : [], value: value, onMrdChange: this.handleChange, onMrdBlur: this.handleBlur, onMrdSearch: this.handleSearch, onMrdFetchAll: this.handleFetchAll })));
155
+ }
156
+ if (item.type !== ClientLayoutItemType.FIELD) {
157
+ return h(Host, null);
158
+ }
159
+ const displayValue = this.getDisplayValue();
160
+ return (h(Host, null, h("div", { class: "mrd-field__inner" }, this.renderLeafField(displayValue), this.renderHistoryEditor())));
161
+ }
82
162
  static get is() { return "mrd-field"; }
83
163
  static get encapsulation() { return "scoped"; }
164
+ static get originalStyleUrls() {
165
+ return {
166
+ "$": ["mrd-field.scss"]
167
+ };
168
+ }
169
+ static get styleUrls() {
170
+ return {
171
+ "$": ["mrd-field.css"]
172
+ };
173
+ }
84
174
  static get properties() {
85
175
  return {
86
176
  "item": {
@@ -146,6 +236,12 @@ export class MrdField {
146
236
  }
147
237
  };
148
238
  }
239
+ static get states() {
240
+ return {
241
+ "historyEntries": {},
242
+ "currentValue": {}
243
+ };
244
+ }
149
245
  static get events() {
150
246
  return [{
151
247
  "method": "mrdChange",
@@ -229,4 +325,11 @@ export class MrdField {
229
325
  }
230
326
  }];
231
327
  }
328
+ static get elementRef() { return "el"; }
329
+ static get watchers() {
330
+ return [{
331
+ "propName": "value",
332
+ "methodName": "valueChanged"
333
+ }];
334
+ }
232
335
  }
@@ -0,0 +1,118 @@
1
+ :host {
2
+ display: block;
3
+ }
4
+
5
+ .mrd-field__inner {
6
+ display: block;
7
+ width: 100%;
8
+ }
9
+
10
+ .mrd-field__history-editor {
11
+ margin-top: var(--mrd-space-2);
12
+ display: flex;
13
+ flex-direction: column;
14
+ gap: var(--mrd-space-1);
15
+ }
16
+
17
+ .mrd-field__history-editor-label {
18
+ font-family: var(--mrd-font-family);
19
+ font-size: var(--mrd-font-size-xs);
20
+ font-weight: var(--mrd-font-weight-medium);
21
+ color: var(--mrd-color-neutral-500);
22
+ }
23
+
24
+ .mrd-field__history-editor-row {
25
+ display: flex;
26
+ align-items: center;
27
+ gap: var(--mrd-space-2);
28
+ }
29
+
30
+ .mrd-field__history-editor-sep {
31
+ flex-shrink: 0;
32
+ font-family: var(--mrd-font-family);
33
+ font-size: var(--mrd-font-size-xs);
34
+ color: var(--mrd-color-neutral-500);
35
+ }
36
+
37
+ .mrd-field__history-editor-value {
38
+ flex: 1 1 0;
39
+ min-width: 0;
40
+ height: var(--mrd-input-height);
41
+ padding: 0 var(--mrd-space-3);
42
+ font-family: var(--mrd-font-family);
43
+ font-size: var(--mrd-font-size-sm);
44
+ color: var(--mrd-color-neutral-800);
45
+ background-color: var(--mrd-color-white);
46
+ border: var(--mrd-border-width) solid var(--mrd-border-color);
47
+ border-radius: var(--mrd-border-radius-md);
48
+ outline: none;
49
+ transition: border-color var(--mrd-transition-fast), box-shadow var(--mrd-transition-fast);
50
+ }
51
+
52
+ .mrd-field__history-editor-value:focus {
53
+ border-color: var(--mrd-color-primary);
54
+ box-shadow: var(--mrd-shadow-focus);
55
+ }
56
+
57
+ .mrd-field__history-editor-until {
58
+ flex: 0 0 10rem;
59
+ height: var(--mrd-input-height);
60
+ padding: 0 var(--mrd-space-3);
61
+ font-family: var(--mrd-font-family);
62
+ font-size: var(--mrd-font-size-sm);
63
+ color: var(--mrd-color-neutral-800);
64
+ background-color: var(--mrd-color-white);
65
+ border: var(--mrd-border-width) solid var(--mrd-border-color);
66
+ border-radius: var(--mrd-border-radius-md);
67
+ outline: none;
68
+ transition: border-color var(--mrd-transition-fast), box-shadow var(--mrd-transition-fast);
69
+ }
70
+
71
+ .mrd-field__history-editor-until:focus {
72
+ border-color: var(--mrd-color-primary);
73
+ box-shadow: var(--mrd-shadow-focus);
74
+ }
75
+
76
+ .mrd-field__history-editor-remove {
77
+ display: inline-flex;
78
+ align-items: center;
79
+ justify-content: center;
80
+ flex-shrink: 0;
81
+ width: 2rem;
82
+ height: 2rem;
83
+ padding: 0;
84
+ background: transparent;
85
+ border: none;
86
+ border-radius: var(--mrd-border-radius-sm);
87
+ color: var(--mrd-color-neutral-400);
88
+ cursor: pointer;
89
+ transition: color var(--mrd-transition-fast), background-color var(--mrd-transition-fast);
90
+ }
91
+
92
+ .mrd-field__history-editor-remove:hover {
93
+ color: var(--mrd-color-danger);
94
+ background-color: var(--mrd-color-danger-light);
95
+ }
96
+
97
+ .mrd-field__history-editor-remove svg {
98
+ width: 1rem;
99
+ height: 1rem;
100
+ }
101
+
102
+ .mrd-field__history-editor-add {
103
+ align-self: flex-start;
104
+ padding: var(--mrd-space-1) var(--mrd-space-3);
105
+ font-family: var(--mrd-font-family);
106
+ font-size: var(--mrd-font-size-xs);
107
+ font-weight: var(--mrd-font-weight-medium);
108
+ color: var(--mrd-color-primary);
109
+ background: transparent;
110
+ border: var(--mrd-border-width) solid var(--mrd-color-primary);
111
+ border-radius: var(--mrd-border-radius-md);
112
+ cursor: pointer;
113
+ transition: background-color var(--mrd-transition-fast), color var(--mrd-transition-fast);
114
+ }
115
+
116
+ .mrd-field__history-editor-add:hover {
117
+ background-color: var(--mrd-color-primary-light);
118
+ }
@@ -261,10 +261,10 @@ export class MrdForm {
261
261
  continue;
262
262
  const name = item.name;
263
263
  if (item.type === ClientLayoutItemType.FIELD) {
264
- const value = this.formValues[name];
265
- if (value instanceof File)
264
+ const rawValue = this.formValues[name];
265
+ if (rawValue instanceof File)
266
266
  continue;
267
- const current = this.normalizeFieldValue(value);
267
+ const current = this.normalizeFieldValue(rawValue);
268
268
  const initial = this.normalizeFieldValue(this.initialValues[name]);
269
269
  if (this.deepEqual(current, initial))
270
270
  continue;
@@ -2,6 +2,7 @@ import { Host, h } from "@stencil/core";
2
2
  import { ClientLayoutItemType, ClientLayoutItemFieldDataType, } from "../../types/client-layout";
3
3
  import { CellRenderer } from "../../utils/cell-renderer";
4
4
  import { t } from "../../utils/i18n";
5
+ import { formatDate } from "../../utils/format";
5
6
  export class MrdLayoutSection {
6
7
  constructor() {
7
8
  /** Items from one layout entry in ClientDashboardMetadata.layouts[]. */
@@ -17,6 +18,8 @@ export class MrdLayoutSection {
17
18
  this.searchResultsMap = {};
18
19
  this.imagePreviewUrl = null;
19
20
  this.imagePreviews = {};
21
+ this.openHistoryField = null;
22
+ this.historyClickOutside = null;
20
23
  this.searchTimers = {};
21
24
  this.handleViewLoadPage = (e, name) => {
22
25
  e.stopPropagation();
@@ -40,6 +43,17 @@ export class MrdLayoutSection {
40
43
  this.initEmbeddedTables();
41
44
  this.emitLoadImages();
42
45
  }, 0);
46
+ this.historyClickOutside = (e) => {
47
+ if (!this.el.contains(e.target))
48
+ this.openHistoryField = null;
49
+ };
50
+ document.addEventListener('mousedown', this.historyClickOutside);
51
+ }
52
+ disconnectedCallback() {
53
+ if (this.historyClickOutside) {
54
+ document.removeEventListener('mousedown', this.historyClickOutside);
55
+ this.historyClickOutside = null;
56
+ }
43
57
  }
44
58
  dataChanged(newVal) {
45
59
  if (newVal && Object.keys(newVal).length > 0) {
@@ -188,10 +202,31 @@ export class MrdLayoutSection {
188
202
  }
189
203
  return this.renderSingleFieldValue(item, rawValue);
190
204
  }
205
+ renderHistoryBadge(item, raw) {
206
+ var _a, _b, _c;
207
+ const hist = (_a = item.historyEnabled) !== null && _a !== void 0 ? _a : (_b = item.field) === null || _b === void 0 ? void 0 : _b.historyEnabled;
208
+ if (!hist || !item.name)
209
+ return null;
210
+ const history = (_c = raw === null || raw === void 0 ? void 0 : raw.history) !== null && _c !== void 0 ? _c : [];
211
+ if (!history.length)
212
+ return null;
213
+ const sorted = [...history].sort((a, b) => b.until.localeCompare(a.until));
214
+ const isOpen = this.openHistoryField === item.name;
215
+ const { locale } = this;
216
+ return (h("span", { class: "mrd-layout-section__history-wrap" }, h("button", { type: "button", class: "mrd-layout-section__history-btn", title: t('history_badge_tooltip', locale), "aria-label": t('history_badge_tooltip', locale), onClick: (e) => {
217
+ e.stopPropagation();
218
+ this.openHistoryField = isOpen ? null : item.name;
219
+ } }, h("svg", { class: "mrd-layout-section__history-icon", viewBox: "0 0 20 20", fill: "currentColor", "aria-hidden": "true" }, h("path", { "fill-rule": "evenodd", d: "M10 18a8 8 0 100-16 8 8 0 000 16zm.75-13a.75.75 0 00-1.5 0v5c0 .207.085.394.22.53l2.5 2.5a.75.75 0 101.06-1.06L10.75 9.69V5z", "clip-rule": "evenodd" }))), isOpen && (h("div", { class: "mrd-layout-section__history-popover", role: "listbox" }, sorted.map((entry, i) => (h("div", { key: String(i), class: "mrd-layout-section__history-entry" }, entry.value, " (", t('history_until', locale), " ", formatDate(entry.until, locale), ")")))))));
220
+ }
191
221
  renderField(item) {
222
+ var _a, _b;
192
223
  if (!item.name)
193
224
  return null;
194
- const rawValue = this.data[item.name];
225
+ const raw = this.data[item.name];
226
+ const hist = (_a = item.historyEnabled) !== null && _a !== void 0 ? _a : (_b = item.field) === null || _b === void 0 ? void 0 : _b.historyEnabled;
227
+ const rawValue = hist && raw !== null && typeof raw === 'object' && 'current' in raw
228
+ ? raw.current
229
+ : raw;
195
230
  const renderedValue = this.renderFieldValue(item, rawValue);
196
231
  if (item.header) {
197
232
  return (h("h1", { class: "mrd-layout-section__field-header", key: item.name }, typeof renderedValue === 'string' ? renderedValue : rawValue != null ? String(rawValue) : item.label));
@@ -201,7 +236,7 @@ export class MrdLayoutSection {
201
236
  const isBlock = item.dataType === ClientLayoutItemFieldDataType.TEXTBLOCK
202
237
  || item.dataType === ClientLayoutItemFieldDataType.LONGTEXT
203
238
  || item.dataType === ClientLayoutItemFieldDataType.JSON;
204
- return (h("div", { class: `mrd-layout-section__field${isBlock ? ' mrd-layout-section__field--block' : ''}`, key: item.name }, h("span", { class: "mrd-layout-section__field-label" }, item.label), h("span", { class: "mrd-layout-section__field-value" }, renderedValue)));
239
+ return (h("div", { class: `mrd-layout-section__field${isBlock ? ' mrd-layout-section__field--block' : ''}`, key: item.name }, h("span", { class: "mrd-layout-section__field-label" }, item.label), h("span", { class: "mrd-layout-section__field-value" }, renderedValue, this.renderHistoryBadge(item, raw))));
205
240
  }
206
241
  renderRelation(item) {
207
242
  var _a, _b, _c;
@@ -296,7 +331,7 @@ export class MrdLayoutSection {
296
331
  return (h("div", { class: "mrd-layout-section__modal-backdrop", onClick: () => { this.imagePreviewUrl = null; } }, h("div", { class: "mrd-layout-section__modal", onClick: (e) => e.stopPropagation() }, h("button", { class: "mrd-layout-section__modal-close", onClick: () => { this.imagePreviewUrl = null; } }, "\u2715"), h("img", { class: "mrd-layout-section__modal-image", src: this.imagePreviewUrl, alt: "" }))));
297
332
  }
298
333
  render() {
299
- return (h(Host, { key: '0a3a58f5c80716bc0a7ba1b9468b721706d2ce4a' }, h("div", { key: '7cf63580c584811c1bb84b419e8d13026e432fba', class: "mrd-layout-section" }, this.items.map(item => this.renderItem(item))), this.renderImageModal()));
334
+ return (h(Host, { key: '39ba6fc1fc823864025ca6a8df4c97b0f4cb96e6' }, h("div", { key: 'b1af15adfec5c699e00546b03b535149b834b6e4', class: "mrd-layout-section" }, this.items.map(item => this.renderItem(item))), this.renderImageModal()));
300
335
  }
301
336
  static get is() { return "mrd-layout-section"; }
302
337
  static get encapsulation() { return "scoped"; }
@@ -439,7 +474,8 @@ export class MrdLayoutSection {
439
474
  "searchQueryMap": {},
440
475
  "searchResultsMap": {},
441
476
  "imagePreviewUrl": {},
442
- "imagePreviews": {}
477
+ "imagePreviews": {},
478
+ "openHistoryField": {}
443
479
  };
444
480
  }
445
481
  static get events() {
@@ -24,6 +24,73 @@
24
24
  font-weight: var(--mrd-font-weight-medium);
25
25
  color: var(--mrd-color-neutral-800);
26
26
  word-break: break-word;
27
+ display: inline-flex;
28
+ align-items: center;
29
+ gap: var(--mrd-space-1);
30
+ }
31
+
32
+ .mrd-layout-section__history-wrap {
33
+ position: relative;
34
+ display: inline-flex;
35
+ align-items: center;
36
+ }
37
+
38
+ .mrd-layout-section__history-btn {
39
+ display: inline-flex;
40
+ align-items: center;
41
+ justify-content: center;
42
+ width: 1.25rem;
43
+ height: 1.25rem;
44
+ padding: 0;
45
+ background: transparent;
46
+ border: none;
47
+ border-radius: var(--mrd-border-radius-sm);
48
+ color: var(--mrd-color-neutral-400);
49
+ cursor: pointer;
50
+ flex-shrink: 0;
51
+ transition: color var(--mrd-transition-fast), background-color var(--mrd-transition-fast);
52
+ }
53
+
54
+ .mrd-layout-section__history-btn:hover {
55
+ color: var(--mrd-color-neutral-700);
56
+ background-color: var(--mrd-color-neutral-100);
57
+ }
58
+
59
+ .mrd-layout-section__history-btn:focus {
60
+ outline: none;
61
+ box-shadow: var(--mrd-shadow-focus);
62
+ }
63
+
64
+ .mrd-layout-section__history-icon {
65
+ width: 0.875rem;
66
+ height: 0.875rem;
67
+ }
68
+
69
+ .mrd-layout-section__history-popover {
70
+ position: absolute;
71
+ top: calc(100% + 0.25rem);
72
+ left: 0;
73
+ min-width: 24rem;
74
+ max-width: 24rem;
75
+ background-color: var(--mrd-color-white);
76
+ border: var(--mrd-border-width) solid var(--mrd-border-color);
77
+ border-radius: var(--mrd-border-radius-md);
78
+ box-shadow: var(--mrd-shadow-md);
79
+ padding: var(--mrd-space-1) 0;
80
+ z-index: var(--mrd-z-dropdown);
81
+ }
82
+
83
+ .mrd-layout-section__history-entry {
84
+ font-family: var(--mrd-font-family);
85
+ font-size: var(--mrd-font-size-sm);
86
+ font-weight: var(--mrd-font-weight-normal);
87
+ color: var(--mrd-color-neutral-700);
88
+ padding: var(--mrd-space-2) var(--mrd-space-3);
89
+ line-height: var(--mrd-line-height-normal);
90
+ }
91
+
92
+ .mrd-layout-section__history-entry:not(:last-child) {
93
+ border-bottom: var(--mrd-border-width) solid var(--mrd-color-neutral-100);
27
94
  }
28
95
 
29
96
  .mrd-layout-section__field-header {
@@ -344,7 +344,7 @@ function renderSectionTabs(layouts) {
344
344
  });
345
345
  }
346
346
 
347
- function renderSection(index) {
347
+ async function renderSection(index) {
348
348
  _activeLayoutIndex = index;
349
349
  const generation = ++_sectionGeneration; // snapshot for stale-fetch detection
350
350
 
@@ -357,6 +357,11 @@ function renderSection(index) {
357
357
  const container = document.getElementById('sections-container');
358
358
  container.innerHTML = '';
359
359
 
360
+ if (_dashboardType === 'form') {
361
+ await renderForm(layout, _dashboardRecord, _dashboardRecord?._links?.self?.href ?? null, container);
362
+ return;
363
+ }
364
+
360
365
  const section = document.createElement('mrd-layout-section');
361
366
  section.items = layout.items;
362
367
  section.data = _dashboardRecord ?? { _links: _dashboardData._links ?? {} };
@@ -581,7 +586,7 @@ async function loadForm() {
581
586
  * @param record - existing record for edit mode (null = new record)
582
587
  * @param selfHref - absolute URL for PATCH; null = POST (new record)
583
588
  */
584
- async function renderForm(layout, record = null, selfHref = null) {
589
+ async function renderForm(layout, record = null, selfHref = null, containerEl = null) {
585
590
  // Build relation metadata map keyed by both relatedClass and mostSignificantClass
586
591
  // so lookups work regardless of which value arrives in events (mrdSearch uses mostSignificantClass).
587
592
  _relationMeta = {};
@@ -623,10 +628,10 @@ async function renderForm(layout, record = null, selfHref = null) {
623
628
  }
624
629
  }
625
630
 
626
- const formPanel = document.getElementById('panel-form');
631
+ const formPanel = containerEl ?? document.getElementById('panel-form');
627
632
  formPanel.innerHTML = `<mrd-form id="live-form" locale="${escHtml(_locale)}"></mrd-form>`;
628
633
 
629
- const form = document.getElementById('live-form');
634
+ const form = formPanel.querySelector('#live-form') ?? document.getElementById('live-form');
630
635
  // Wait for Stencil to fully initialize this specific instance before setting props.
631
636
  // componentOnReady() resolves after componentDidLoad — more reliable than customElements.whenDefined.
632
637
  if (typeof form.componentOnReady === 'function') {