@mmlogic/components 0.5.8 → 0.5.10
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/dist/cjs/mrd-boolean-field_25.cjs.entry.js +62 -12
- package/dist/collection/components/fields/mrd-currency-field/mrd-currency-field.js +23 -12
- package/dist/collection/components/form/mrd-field/mrd-field.js +6 -1
- package/dist/collection/components/table/mrd-table/mrd-table.js +41 -7
- package/dist/components/mrd-currency-field2.js +1 -1
- package/dist/components/mrd-table2.js +1 -1
- package/dist/esm/mrd-boolean-field_25.entry.js +62 -12
- package/dist/mosterdcomponents/mosterdcomponents.esm.js +1 -1
- package/dist/mosterdcomponents/{p-6f6c8e53.entry.js → p-7da6790e.entry.js} +2 -2
- package/dist/types/components/fields/mrd-currency-field/mrd-currency-field.d.ts +11 -3
- package/dist/types/components/table/mrd-table/mrd-table.d.ts +13 -0
- package/dist/types/components.d.ts +10 -8
- package/package.json +1 -1
- package/dist/mosterdcomponents/cell-renderer-B8u5BCK-.js.map +0 -1
- package/dist/mosterdcomponents/client-layout-Bc42CfJB.js.map +0 -1
- package/dist/mosterdcomponents/document-attachments-BufPmMRv.js.map +0 -1
- package/dist/mosterdcomponents/field-helpers-CUJsHr1V.js.map +0 -1
- package/dist/mosterdcomponents/file-upload-common-DdTDuxEU.js.map +0 -1
- package/dist/mosterdcomponents/format-gcecItcD.js.map +0 -1
- package/dist/mosterdcomponents/i18n-Ba7_jO9I.js.map +0 -1
- package/dist/mosterdcomponents/index-1ayBojyN.js.map +0 -1
- package/dist/mosterdcomponents/index-DhffneUF.js.map +0 -1
- package/dist/mosterdcomponents/index.esm.js.map +0 -1
- package/dist/mosterdcomponents/mosterdcomponents.esm.js.map +0 -1
- package/dist/mosterdcomponents/purify.es-_duHfPgC.js.map +0 -1
- package/dist/mosterdcomponents/query-params-BZbQoeYF.js.map +0 -1
- package/dist/mosterdcomponents/quill-C9pgw_k-.js.map +0 -1
- package/dist/mosterdcomponents/validation-CjjTt66G.js.map +0 -1
|
@@ -114,7 +114,10 @@ const MrdCurrencyField = class {
|
|
|
114
114
|
this.mrdBlur = index.createEvent(this, "mrdBlur");
|
|
115
115
|
this.name = '';
|
|
116
116
|
this.label = '';
|
|
117
|
-
|
|
117
|
+
/** Accepts a partial object on the way in (hosts pre-fill the currency from the layout's
|
|
118
|
+
* currencyCode before an amount exists); on the way out only null or a complete object
|
|
119
|
+
* is ever emitted — see handleAmountBlur. */
|
|
120
|
+
this.value = null;
|
|
118
121
|
this.required = false;
|
|
119
122
|
this.disabled = false;
|
|
120
123
|
this.locale = navigator.language;
|
|
@@ -141,14 +144,15 @@ const MrdCurrencyField = class {
|
|
|
141
144
|
const parsed = cellRenderer.parseLocalizedNumber(raw, this.locale);
|
|
142
145
|
this.error = requiredError(raw, this.required, this.locale);
|
|
143
146
|
this.amountDisplay = parsed !== null ? this.formatAmount(parsed) : '';
|
|
144
|
-
const val =
|
|
147
|
+
const val = this.currentValue(parsed);
|
|
145
148
|
this.mrdChange.emit({ name: this.name, value: val });
|
|
146
149
|
this.mrdBlur.emit({ name: this.name, value: val });
|
|
147
150
|
};
|
|
148
151
|
this.handleCurrencyChange = (e) => {
|
|
149
152
|
this.currency = e.target.value;
|
|
150
153
|
const parsed = cellRenderer.parseLocalizedNumber(this.amountDisplay, this.locale);
|
|
151
|
-
|
|
154
|
+
// Picking a currency for an empty amount does not make the field filled in.
|
|
155
|
+
this.mrdChange.emit({ name: this.name, value: this.currentValue(parsed) });
|
|
152
156
|
};
|
|
153
157
|
}
|
|
154
158
|
componentWillLoad() {
|
|
@@ -186,9 +190,16 @@ const MrdCurrencyField = class {
|
|
|
186
190
|
formatAmount(amount) {
|
|
187
191
|
return cellRenderer.formatNumber(amount, this.locale, { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
|
188
192
|
}
|
|
193
|
+
/** Emit either a complete value or nothing at all. A half-filled
|
|
194
|
+
* { amount: null, currency } reaches the API as a currency object without an amount,
|
|
195
|
+
* which it cannot store — and it makes clearing an optional amount impossible, because
|
|
196
|
+
* the field would never report itself as empty (FINDING-0141 / TASK-0234). */
|
|
197
|
+
currentValue(amount) {
|
|
198
|
+
return amount === null ? null : { amount, currency: this.currency };
|
|
199
|
+
}
|
|
189
200
|
render() {
|
|
190
201
|
const hasError = !!this.error;
|
|
191
|
-
return (index.h(index.Host, { key: '
|
|
202
|
+
return (index.h(index.Host, { key: '9529c8ff013107056ea549f70f10016dec00cff6' }, index.h("div", { key: 'eef1f1400cc9b1f87353413f3f476b028bf3ecbf', class: "mrd-currency-field" }, index.h(FieldLabel, { key: '76004f615bda7669814d4b5f55c4ec54ae078e12', base: "mrd-currency-field", label: this.label, required: this.required }), index.h("div", { key: '03a2ec6ada9b2e185e247a228225aed3b67a5bec', class: "mrd-currency-field__row" }, index.h("input", { key: 'ee9004f4cc306c8a9f417812b573e000c055c09c', class: controlClass('mrd-currency-field', hasError, 'amount'), type: "text", inputMode: "decimal", name: `${this.name}_amount`, value: this.amountDisplay, placeholder: this.formatAmount(0), required: this.required, disabled: this.disabled, onInput: this.handleAmountInput, onFocus: this.handleAmountFocus, onBlur: this.handleAmountBlur }), index.h("select", { key: '06547e3716881b3c574c6355eef56a92983470bb', class: "mrd-currency-field__currency", ref: el => (this.selectEl = el), disabled: this.disabled, onChange: this.handleCurrencyChange }, this.currencyOptions().map(c => (index.h("option", { key: c, value: c, selected: c === this.currency }, c))))), index.h(FieldError, { key: '4cbab3a887fece60ae31baccb24e3b68ecf1b947', base: "mrd-currency-field", error: this.error }))));
|
|
192
203
|
}
|
|
193
204
|
static get watchers() { return {
|
|
194
205
|
"value": [{
|
|
@@ -4165,7 +4176,12 @@ const MrdField = class {
|
|
|
4165
4176
|
case clientLayout.ClientLayoutItemFieldDataType.PERCENTAGE:
|
|
4166
4177
|
return (index.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 : '' })));
|
|
4167
4178
|
case clientLayout.ClientLayoutItemFieldDataType.CURRENCY:
|
|
4168
|
-
return (index.h("mrd-currency-field", Object.assign({}, commonProps, {
|
|
4179
|
+
return (index.h("mrd-currency-field", Object.assign({}, commonProps, {
|
|
4180
|
+
// Input-only fallback: it preselects the layout's currencyCode in the dropdown
|
|
4181
|
+
// before an amount exists. The field never emits this shape back — an empty
|
|
4182
|
+
// amount emits null (FINDING-0141).
|
|
4183
|
+
value: (_j = displayValue) !== null && _j !== void 0 ? _j : { amount: null, currency: (_k = item.currencyCode) !== null && _k !== void 0 ? _k : 'EUR' }
|
|
4184
|
+
})));
|
|
4169
4185
|
case clientLayout.ClientLayoutItemFieldDataType.BOOLEAN:
|
|
4170
4186
|
return (index.h("mrd-boolean-field", Object.assign({}, commonProps, { value: (_l = displayValue) !== null && _l !== void 0 ? _l : false })));
|
|
4171
4187
|
case clientLayout.ClientLayoutItemFieldDataType.DATE:
|
|
@@ -6867,11 +6883,12 @@ const MrdTable = class {
|
|
|
6867
6883
|
this.loadedPages.size > 0) {
|
|
6868
6884
|
this.colWidthMeasureScheduled = true;
|
|
6869
6885
|
index.writeTask(() => {
|
|
6886
|
+
var _a;
|
|
6870
6887
|
this.colWidthMeasureScheduled = false;
|
|
6871
6888
|
// Re-check: state may have changed (e.g. a reset) between scheduling and running.
|
|
6872
6889
|
if (this.colWidths.length !== 0)
|
|
6873
6890
|
return;
|
|
6874
|
-
const measured = this.measureColWidths();
|
|
6891
|
+
const measured = (_a = this.measureContentWidths()) !== null && _a !== void 0 ? _a : this.measureColWidths();
|
|
6875
6892
|
if (measured)
|
|
6876
6893
|
this.colWidths = measured;
|
|
6877
6894
|
});
|
|
@@ -6885,6 +6902,44 @@ const MrdTable = class {
|
|
|
6885
6902
|
return null;
|
|
6886
6903
|
return Array.from(ths).map(th => Math.round(th.getBoundingClientRect().width));
|
|
6887
6904
|
}
|
|
6905
|
+
/** Width one cell needs to show its content in full, borders included.
|
|
6906
|
+
* Read from scrollWidth rather than the laid-out box: cells clip with `overflow: hidden`,
|
|
6907
|
+
* so a squeezed cell reports the width it *was given*, not the width it needs. */
|
|
6908
|
+
neededWidth(cell) {
|
|
6909
|
+
// The layout metrics are absent in the mock DOM the specs run on; treat them as 0
|
|
6910
|
+
// rather than letting a NaN poison the Math.max chain the callers build.
|
|
6911
|
+
const px = (v) => (typeof v === 'number' && Number.isFinite(v) ? v : 0);
|
|
6912
|
+
const clientWidth = px(cell.clientWidth);
|
|
6913
|
+
const scrollWidth = px(cell.scrollWidth);
|
|
6914
|
+
const paddingRight = px(parseFloat(getComputedStyle(cell).paddingRight || '0'));
|
|
6915
|
+
const borders = Math.max(0, px(cell.offsetWidth) - clientWidth);
|
|
6916
|
+
// scrollWidth drops the right padding once the content overflows the clipped box;
|
|
6917
|
+
// when it fits, clientWidth is already the full padded box.
|
|
6918
|
+
const content = scrollWidth > clientWidth ? scrollWidth + paddingRight : clientWidth;
|
|
6919
|
+
return Math.ceil(content + borders);
|
|
6920
|
+
}
|
|
6921
|
+
/** Width each column needs for its header and its rendered page-0 cells — what the columns
|
|
6922
|
+
* are locked to, so they never end up narrower than their content.
|
|
6923
|
+
*
|
|
6924
|
+
* Deliberately not the laid-out widths: with many columns the browser squeezes them to fit
|
|
6925
|
+
* the container instead of overflowing (the cells clip, so they no longer resist), which
|
|
6926
|
+
* cost the horizontal scrollbar. Locking the needed widths makes the summed table width
|
|
6927
|
+
* exceed the container again, and `.mrd-table__scroll` scrolls. Capped per column at
|
|
6928
|
+
* MAX_AUTOFIT_WIDTH so one outlier value can't blow up the layout — same cap as auto-fit. */
|
|
6929
|
+
measureContentWidths() {
|
|
6930
|
+
const ths = this.el.querySelectorAll('.mrd-table__header');
|
|
6931
|
+
if (ths.length === 0 || ths.length !== this.columns.length)
|
|
6932
|
+
return null;
|
|
6933
|
+
return Array.from(ths).map((th, idx) => {
|
|
6934
|
+
let widest = this.neededWidth(th);
|
|
6935
|
+
// .mrd-table__cell only matches real data cells — the shimmer/retry rows render a single
|
|
6936
|
+
// colSpan cell (without that class) which would measure as the full table width.
|
|
6937
|
+
this.el
|
|
6938
|
+
.querySelectorAll(`.mrd-table__cell:nth-child(${idx + 1})`)
|
|
6939
|
+
.forEach(cell => { widest = Math.max(widest, this.neededWidth(cell)); });
|
|
6940
|
+
return Math.min(Math.max(widest, MIN_COL_WIDTH), MAX_AUTOFIT_WIDTH);
|
|
6941
|
+
});
|
|
6942
|
+
}
|
|
6888
6943
|
/** Re-reads the rendered header widths into colWidths so a drag starts from what is
|
|
6889
6944
|
* actually on screen — and locks the columns if they weren't locked yet.
|
|
6890
6945
|
*
|
|
@@ -6945,12 +7000,7 @@ const MrdTable = class {
|
|
|
6945
7000
|
// colSpan cell (without that class) which would otherwise measure as the full table width.
|
|
6946
7001
|
const cells = this.el.querySelectorAll(`.mrd-table__header:nth-child(${idx + 1}), .mrd-table__cell:nth-child(${idx + 1})`);
|
|
6947
7002
|
let widest = 0;
|
|
6948
|
-
cells.forEach(cell => {
|
|
6949
|
-
// scrollWidth is the untruncated content width; cells clip with overflow: hidden.
|
|
6950
|
-
const style = getComputedStyle(cell);
|
|
6951
|
-
const padding = parseFloat(style.paddingLeft || '0') + parseFloat(style.paddingRight || '0');
|
|
6952
|
-
widest = Math.max(widest, cell.scrollWidth + padding);
|
|
6953
|
-
});
|
|
7003
|
+
cells.forEach(cell => { widest = Math.max(widest, this.neededWidth(cell)); });
|
|
6954
7004
|
if (widest > 0)
|
|
6955
7005
|
this.setColWidth(idx, Math.min(widest, MAX_AUTOFIT_WIDTH));
|
|
6956
7006
|
}
|
|
@@ -10,7 +10,10 @@ export class MrdCurrencyField {
|
|
|
10
10
|
constructor() {
|
|
11
11
|
this.name = '';
|
|
12
12
|
this.label = '';
|
|
13
|
-
|
|
13
|
+
/** Accepts a partial object on the way in (hosts pre-fill the currency from the layout's
|
|
14
|
+
* currencyCode before an amount exists); on the way out only null or a complete object
|
|
15
|
+
* is ever emitted — see handleAmountBlur. */
|
|
16
|
+
this.value = null;
|
|
14
17
|
this.required = false;
|
|
15
18
|
this.disabled = false;
|
|
16
19
|
this.locale = navigator.language;
|
|
@@ -37,14 +40,15 @@ export class MrdCurrencyField {
|
|
|
37
40
|
const parsed = parseLocalizedNumber(raw, this.locale);
|
|
38
41
|
this.error = requiredError(raw, this.required, this.locale);
|
|
39
42
|
this.amountDisplay = parsed !== null ? this.formatAmount(parsed) : '';
|
|
40
|
-
const val =
|
|
43
|
+
const val = this.currentValue(parsed);
|
|
41
44
|
this.mrdChange.emit({ name: this.name, value: val });
|
|
42
45
|
this.mrdBlur.emit({ name: this.name, value: val });
|
|
43
46
|
};
|
|
44
47
|
this.handleCurrencyChange = (e) => {
|
|
45
48
|
this.currency = e.target.value;
|
|
46
49
|
const parsed = parseLocalizedNumber(this.amountDisplay, this.locale);
|
|
47
|
-
|
|
50
|
+
// Picking a currency for an empty amount does not make the field filled in.
|
|
51
|
+
this.mrdChange.emit({ name: this.name, value: this.currentValue(parsed) });
|
|
48
52
|
};
|
|
49
53
|
}
|
|
50
54
|
componentWillLoad() {
|
|
@@ -82,9 +86,16 @@ export class MrdCurrencyField {
|
|
|
82
86
|
formatAmount(amount) {
|
|
83
87
|
return formatNumber(amount, this.locale, { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
|
84
88
|
}
|
|
89
|
+
/** Emit either a complete value or nothing at all. A half-filled
|
|
90
|
+
* { amount: null, currency } reaches the API as a currency object without an amount,
|
|
91
|
+
* which it cannot store — and it makes clearing an optional amount impossible, because
|
|
92
|
+
* the field would never report itself as empty (FINDING-0141 / TASK-0234). */
|
|
93
|
+
currentValue(amount) {
|
|
94
|
+
return amount === null ? null : { amount, currency: this.currency };
|
|
95
|
+
}
|
|
85
96
|
render() {
|
|
86
97
|
const hasError = !!this.error;
|
|
87
|
-
return (h(Host, { key: '
|
|
98
|
+
return (h(Host, { key: '9529c8ff013107056ea549f70f10016dec00cff6' }, h("div", { key: 'eef1f1400cc9b1f87353413f3f476b028bf3ecbf', class: "mrd-currency-field" }, h(FieldLabel, { key: '76004f615bda7669814d4b5f55c4ec54ae078e12', base: "mrd-currency-field", label: this.label, required: this.required }), h("div", { key: '03a2ec6ada9b2e185e247a228225aed3b67a5bec', class: "mrd-currency-field__row" }, h("input", { key: 'ee9004f4cc306c8a9f417812b573e000c055c09c', class: controlClass('mrd-currency-field', hasError, 'amount'), type: "text", inputMode: "decimal", name: `${this.name}_amount`, value: this.amountDisplay, placeholder: this.formatAmount(0), required: this.required, disabled: this.disabled, onInput: this.handleAmountInput, onFocus: this.handleAmountFocus, onBlur: this.handleAmountBlur }), h("select", { key: '06547e3716881b3c574c6355eef56a92983470bb', class: "mrd-currency-field__currency", ref: el => (this.selectEl = el), disabled: this.disabled, onChange: this.handleCurrencyChange }, this.currencyOptions().map(c => (h("option", { key: c, value: c, selected: c === this.currency }, c))))), h(FieldError, { key: '4cbab3a887fece60ae31baccb24e3b68ecf1b947', base: "mrd-currency-field", error: this.error }))));
|
|
88
99
|
}
|
|
89
100
|
static get is() { return "mrd-currency-field"; }
|
|
90
101
|
static get encapsulation() { return "scoped"; }
|
|
@@ -144,8 +155,8 @@ export class MrdCurrencyField {
|
|
|
144
155
|
"type": "unknown",
|
|
145
156
|
"mutable": false,
|
|
146
157
|
"complexType": {
|
|
147
|
-
"original": "CurrencyValue",
|
|
148
|
-
"resolved": "CurrencyValue",
|
|
158
|
+
"original": "CurrencyValue | null",
|
|
159
|
+
"resolved": "CurrencyValue | null",
|
|
149
160
|
"references": {
|
|
150
161
|
"CurrencyValue": {
|
|
151
162
|
"location": "import",
|
|
@@ -159,11 +170,11 @@ export class MrdCurrencyField {
|
|
|
159
170
|
"optional": false,
|
|
160
171
|
"docs": {
|
|
161
172
|
"tags": [],
|
|
162
|
-
"text": ""
|
|
173
|
+
"text": "Accepts a partial object on the way in (hosts pre-fill the currency from the layout's\ncurrencyCode before an amount exists); on the way out only null or a complete object\nis ever emitted \u2014 see handleAmountBlur."
|
|
163
174
|
},
|
|
164
175
|
"getter": false,
|
|
165
176
|
"setter": false,
|
|
166
|
-
"defaultValue": "
|
|
177
|
+
"defaultValue": "null"
|
|
167
178
|
},
|
|
168
179
|
"required": {
|
|
169
180
|
"type": "boolean",
|
|
@@ -246,8 +257,8 @@ export class MrdCurrencyField {
|
|
|
246
257
|
"text": ""
|
|
247
258
|
},
|
|
248
259
|
"complexType": {
|
|
249
|
-
"original": "{ name: string; value: CurrencyValue }",
|
|
250
|
-
"resolved": "{ name: string; value: CurrencyValue; }",
|
|
260
|
+
"original": "{ name: string; value: CurrencyValue | null }",
|
|
261
|
+
"resolved": "{ name: string; value: CurrencyValue | null; }",
|
|
251
262
|
"references": {
|
|
252
263
|
"CurrencyValue": {
|
|
253
264
|
"location": "import",
|
|
@@ -268,8 +279,8 @@ export class MrdCurrencyField {
|
|
|
268
279
|
"text": ""
|
|
269
280
|
},
|
|
270
281
|
"complexType": {
|
|
271
|
-
"original": "{ name: string; value: CurrencyValue }",
|
|
272
|
-
"resolved": "{ name: string; value: CurrencyValue; }",
|
|
282
|
+
"original": "{ name: string; value: CurrencyValue | null }",
|
|
283
|
+
"resolved": "{ name: string; value: CurrencyValue | null; }",
|
|
273
284
|
"references": {
|
|
274
285
|
"CurrencyValue": {
|
|
275
286
|
"location": "import",
|
|
@@ -132,7 +132,12 @@ export class MrdField {
|
|
|
132
132
|
case ClientLayoutItemFieldDataType.PERCENTAGE:
|
|
133
133
|
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 : '' })));
|
|
134
134
|
case ClientLayoutItemFieldDataType.CURRENCY:
|
|
135
|
-
return (h("mrd-currency-field", Object.assign({}, commonProps, {
|
|
135
|
+
return (h("mrd-currency-field", Object.assign({}, commonProps, {
|
|
136
|
+
// Input-only fallback: it preselects the layout's currencyCode in the dropdown
|
|
137
|
+
// before an amount exists. The field never emits this shape back — an empty
|
|
138
|
+
// amount emits null (FINDING-0141).
|
|
139
|
+
value: (_j = displayValue) !== null && _j !== void 0 ? _j : { amount: null, currency: (_k = item.currencyCode) !== null && _k !== void 0 ? _k : 'EUR' }
|
|
140
|
+
})));
|
|
136
141
|
case ClientLayoutItemFieldDataType.BOOLEAN:
|
|
137
142
|
return (h("mrd-boolean-field", Object.assign({}, commonProps, { value: (_l = displayValue) !== null && _l !== void 0 ? _l : false })));
|
|
138
143
|
case ClientLayoutItemFieldDataType.DATE:
|
|
@@ -269,11 +269,12 @@ export class MrdTable {
|
|
|
269
269
|
this.loadedPages.size > 0) {
|
|
270
270
|
this.colWidthMeasureScheduled = true;
|
|
271
271
|
writeTask(() => {
|
|
272
|
+
var _a;
|
|
272
273
|
this.colWidthMeasureScheduled = false;
|
|
273
274
|
// Re-check: state may have changed (e.g. a reset) between scheduling and running.
|
|
274
275
|
if (this.colWidths.length !== 0)
|
|
275
276
|
return;
|
|
276
|
-
const measured = this.measureColWidths();
|
|
277
|
+
const measured = (_a = this.measureContentWidths()) !== null && _a !== void 0 ? _a : this.measureColWidths();
|
|
277
278
|
if (measured)
|
|
278
279
|
this.colWidths = measured;
|
|
279
280
|
});
|
|
@@ -287,6 +288,44 @@ export class MrdTable {
|
|
|
287
288
|
return null;
|
|
288
289
|
return Array.from(ths).map(th => Math.round(th.getBoundingClientRect().width));
|
|
289
290
|
}
|
|
291
|
+
/** Width one cell needs to show its content in full, borders included.
|
|
292
|
+
* Read from scrollWidth rather than the laid-out box: cells clip with `overflow: hidden`,
|
|
293
|
+
* so a squeezed cell reports the width it *was given*, not the width it needs. */
|
|
294
|
+
neededWidth(cell) {
|
|
295
|
+
// The layout metrics are absent in the mock DOM the specs run on; treat them as 0
|
|
296
|
+
// rather than letting a NaN poison the Math.max chain the callers build.
|
|
297
|
+
const px = (v) => (typeof v === 'number' && Number.isFinite(v) ? v : 0);
|
|
298
|
+
const clientWidth = px(cell.clientWidth);
|
|
299
|
+
const scrollWidth = px(cell.scrollWidth);
|
|
300
|
+
const paddingRight = px(parseFloat(getComputedStyle(cell).paddingRight || '0'));
|
|
301
|
+
const borders = Math.max(0, px(cell.offsetWidth) - clientWidth);
|
|
302
|
+
// scrollWidth drops the right padding once the content overflows the clipped box;
|
|
303
|
+
// when it fits, clientWidth is already the full padded box.
|
|
304
|
+
const content = scrollWidth > clientWidth ? scrollWidth + paddingRight : clientWidth;
|
|
305
|
+
return Math.ceil(content + borders);
|
|
306
|
+
}
|
|
307
|
+
/** Width each column needs for its header and its rendered page-0 cells — what the columns
|
|
308
|
+
* are locked to, so they never end up narrower than their content.
|
|
309
|
+
*
|
|
310
|
+
* Deliberately not the laid-out widths: with many columns the browser squeezes them to fit
|
|
311
|
+
* the container instead of overflowing (the cells clip, so they no longer resist), which
|
|
312
|
+
* cost the horizontal scrollbar. Locking the needed widths makes the summed table width
|
|
313
|
+
* exceed the container again, and `.mrd-table__scroll` scrolls. Capped per column at
|
|
314
|
+
* MAX_AUTOFIT_WIDTH so one outlier value can't blow up the layout — same cap as auto-fit. */
|
|
315
|
+
measureContentWidths() {
|
|
316
|
+
const ths = this.el.querySelectorAll('.mrd-table__header');
|
|
317
|
+
if (ths.length === 0 || ths.length !== this.columns.length)
|
|
318
|
+
return null;
|
|
319
|
+
return Array.from(ths).map((th, idx) => {
|
|
320
|
+
let widest = this.neededWidth(th);
|
|
321
|
+
// .mrd-table__cell only matches real data cells — the shimmer/retry rows render a single
|
|
322
|
+
// colSpan cell (without that class) which would measure as the full table width.
|
|
323
|
+
this.el
|
|
324
|
+
.querySelectorAll(`.mrd-table__cell:nth-child(${idx + 1})`)
|
|
325
|
+
.forEach(cell => { widest = Math.max(widest, this.neededWidth(cell)); });
|
|
326
|
+
return Math.min(Math.max(widest, MIN_COL_WIDTH), MAX_AUTOFIT_WIDTH);
|
|
327
|
+
});
|
|
328
|
+
}
|
|
290
329
|
/** Re-reads the rendered header widths into colWidths so a drag starts from what is
|
|
291
330
|
* actually on screen — and locks the columns if they weren't locked yet.
|
|
292
331
|
*
|
|
@@ -347,12 +386,7 @@ export class MrdTable {
|
|
|
347
386
|
// colSpan cell (without that class) which would otherwise measure as the full table width.
|
|
348
387
|
const cells = this.el.querySelectorAll(`.mrd-table__header:nth-child(${idx + 1}), .mrd-table__cell:nth-child(${idx + 1})`);
|
|
349
388
|
let widest = 0;
|
|
350
|
-
cells.forEach(cell => {
|
|
351
|
-
// scrollWidth is the untruncated content width; cells clip with overflow: hidden.
|
|
352
|
-
const style = getComputedStyle(cell);
|
|
353
|
-
const padding = parseFloat(style.paddingLeft || '0') + parseFloat(style.paddingRight || '0');
|
|
354
|
-
widest = Math.max(widest, cell.scrollWidth + padding);
|
|
355
|
-
});
|
|
389
|
+
cells.forEach(cell => { widest = Math.max(widest, this.neededWidth(cell)); });
|
|
356
390
|
if (widest > 0)
|
|
357
391
|
this.setColWidth(idx, Math.min(widest, MAX_AUTOFIT_WIDTH));
|
|
358
392
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{proxyCustomElement as r,HTMLElement as e,createEvent as i,h as
|
|
1
|
+
import{proxyCustomElement as r,HTMLElement as e,createEvent as i,h as c,Host as d,transformTag as o}from"@stencil/core/internal/client";import{p as t,f as a}from"./format.js";import{r as s,F as n,c as l,a as u}from"./field-helpers.js";const m=["EUR","USD","GBP","CHF","JPY","CNY","AUD","CAD","SEK","NOK","DKK","NZD","SGD","HKD","PLN","CZK","HUF","MXN","BRL","INR","TRY","ZAR","AED","SAR"],h=r(class extends e{constructor(r){super(),!1!==r&&this.__registerHost(),this.mrdChange=i(this,"mrdChange",7),this.mrdBlur=i(this,"mrdBlur",7),this.name="",this.label="",this.value=null,this.required=!1,this.disabled=!1,this.locale=navigator.language,this.amountDisplay="",this.currency="EUR",this.error="",this.focused=!1,this.handleAmountInput=r=>{this.amountDisplay=r.target.value},this.handleAmountFocus=()=>{this.focused=!0;const r=t(this.amountDisplay,this.locale);null!==r&&(this.amountDisplay=a(r,this.locale,{useGrouping:!1,maximumFractionDigits:20}))},this.handleAmountBlur=r=>{this.focused=!1;const e=r.target.value,i=t(e,this.locale);this.error=s(e,this.required,this.locale),this.amountDisplay=null!==i?this.formatAmount(i):"";const c=this.currentValue(i);this.mrdChange.emit({name:this.name,value:c}),this.mrdBlur.emit({name:this.name,value:c})},this.handleCurrencyChange=r=>{this.currency=r.target.value;const e=t(this.amountDisplay,this.locale);this.mrdChange.emit({name:this.name,value:this.currentValue(e)})}}componentWillLoad(){this.syncFromValue()}componentDidRender(){this.selectEl&&this.selectEl.value!==this.currency&&(this.selectEl.value=this.currency)}currencyOptions(){return m.includes(this.currency)?m:[this.currency,...m]}valueChanged(){this.focused||this.syncFromValue()}localeChanged(){this.focused||this.syncFromValue()}syncFromValue(){const r=this.value;this.currency=(null==r?void 0:r.currency)||"EUR",this.amountDisplay=null!=(null==r?void 0:r.amount)?this.formatAmount(r.amount):""}formatAmount(r){return a(r,this.locale,{minimumFractionDigits:2,maximumFractionDigits:2})}currentValue(r){return null===r?null:{amount:r,currency:this.currency}}render(){const r=!!this.error;return c(d,{key:"9529c8ff013107056ea549f70f10016dec00cff6"},c("div",{key:"eef1f1400cc9b1f87353413f3f476b028bf3ecbf",class:"mrd-currency-field"},c(n,{key:"76004f615bda7669814d4b5f55c4ec54ae078e12",base:"mrd-currency-field",label:this.label,required:this.required}),c("div",{key:"03a2ec6ada9b2e185e247a228225aed3b67a5bec",class:"mrd-currency-field__row"},c("input",{key:"ee9004f4cc306c8a9f417812b573e000c055c09c",class:l("mrd-currency-field",r,"amount"),type:"text",inputMode:"decimal",name:`${this.name}_amount`,value:this.amountDisplay,placeholder:this.formatAmount(0),required:this.required,disabled:this.disabled,onInput:this.handleAmountInput,onFocus:this.handleAmountFocus,onBlur:this.handleAmountBlur}),c("select",{key:"06547e3716881b3c574c6355eef56a92983470bb",class:"mrd-currency-field__currency",ref:r=>this.selectEl=r,disabled:this.disabled,onChange:this.handleCurrencyChange},this.currencyOptions().map((r=>c("option",{key:r,value:r,selected:r===this.currency},r))))),c(u,{key:"4cbab3a887fece60ae31baccb24e3b68ecf1b947",base:"mrd-currency-field",error:this.error})))}static get watchers(){return{value:[{valueChanged:0}],locale:[{localeChanged:0}]}}static get style(){return'.sc-mrd-currency-field-h{display:block}.mrd-currency-field.sc-mrd-currency-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-currency-field__label.sc-mrd-currency-field{display:block;font-family:var(--mrd-font-family);font-size:var(--mrd-label-font-size);font-weight:var(--mrd-label-font-weight);color:var(--mrd-label-color)}.mrd-currency-field__label--required.sc-mrd-currency-field::after{content:" *";color:var(--mrd-color-danger)}.mrd-currency-field__row.sc-mrd-currency-field{display:flex;gap:var(--mrd-space-2);align-items:stretch}.mrd-currency-field__amount.sc-mrd-currency-field{display:block;width:100%;height:var(--mrd-input-height);padding:var(--mrd-input-padding-y) var(--mrd-input-padding-x);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-input-color);background-color:var(--mrd-input-bg);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);transition:border-color var(--mrd-transition), box-shadow var(--mrd-transition);outline:none;appearance:none;box-sizing:border-box}.mrd-currency-field__amount.sc-mrd-currency-field::placeholder{color:var(--mrd-input-placeholder-color)}.mrd-currency-field__amount.sc-mrd-currency-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-currency-field__amount.sc-mrd-currency-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.mrd-currency-field__amount--error.sc-mrd-currency-field{border-color:var(--mrd-border-color-error)}.mrd-currency-field__amount--error.sc-mrd-currency-field:focus{box-shadow:var(--mrd-shadow-focus-error)}.mrd-currency-field__amount.sc-mrd-currency-field{flex:1;text-align:right}.mrd-currency-field__currency.sc-mrd-currency-field{width:90px;height:var(--mrd-input-height);padding:var(--mrd-input-padding-y) var(--mrd-space-2);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);font-weight:var(--mrd-font-weight-medium);color:var(--mrd-input-color);background-color:var(--mrd-color-neutral-50);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);outline:none;cursor:pointer;box-sizing:border-box;appearance:none;text-align:center}.mrd-currency-field__currency.sc-mrd-currency-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-currency-field__currency.sc-mrd-currency-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.mrd-currency-field__error.sc-mrd-currency-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}'}},[2,"mrd-currency-field",{name:[1],label:[1],value:[16],required:[4],disabled:[4],locale:[1],amountDisplay:[32],currency:[32],error:[32]},void 0,{value:[{valueChanged:0}],locale:[{localeChanged:0}]}]);function f(){"undefined"!=typeof customElements&&["mrd-currency-field"].forEach((r=>{"mrd-currency-field"===r&&(customElements.get(o(r))||customElements.define(o(r),h))}))}export{h as M,f as d}
|