@mmlogic/components 0.1.24 → 0.1.26

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.
Files changed (45) hide show
  1. package/dist/cjs/loader.cjs.js +1 -1
  2. package/dist/cjs/mosterdcomponents.cjs.js +1 -1
  3. package/dist/cjs/mrd-boolean-field_19.cjs.entry.js +3142 -0
  4. package/dist/collection/collection-manifest.json +1 -0
  5. package/dist/collection/components/mrd-layout-section/mrd-layout-section.js +733 -0
  6. package/dist/collection/components/mrd-layout-section/mrd-layout-section.scss +354 -0
  7. package/dist/collection/components/mrd-longtext-field/mrd-longtext-field.js +1 -1
  8. package/dist/collection/components/mrd-number-field/mrd-number-field.js +1 -1
  9. package/dist/collection/components/mrd-table/mrd-table.js +53 -42
  10. package/dist/collection/components/mrd-table/mrd-table.scss +29 -71
  11. package/dist/collection/components/mrd-text-field/mrd-text-field.js +1 -1
  12. package/dist/collection/components/mrd-textarea-field/mrd-textarea-field.js +1 -1
  13. package/dist/collection/components/mrd-time-field/mrd-time-field.js +1 -1
  14. package/dist/collection/dev/app.js +109 -3
  15. package/dist/collection/dev/example-data.js +324 -0
  16. package/dist/collection/utils/cell-renderer.js +26 -0
  17. package/dist/components/mrd-layout-section.d.ts +11 -0
  18. package/dist/components/mrd-layout-section.js +1 -0
  19. package/dist/components/mrd-longtext-field2.js +1 -1
  20. package/dist/components/mrd-number-field2.js +1 -1
  21. package/dist/components/mrd-table.js +1 -1
  22. package/dist/components/mrd-table2.js +1 -0
  23. package/dist/components/mrd-text-field2.js +1 -1
  24. package/dist/components/mrd-textarea-field2.js +1 -1
  25. package/dist/components/mrd-time-field2.js +1 -1
  26. package/dist/esm/loader.js +1 -1
  27. package/dist/esm/mosterdcomponents.js +1 -1
  28. package/dist/esm/mrd-boolean-field_19.entry.js +3122 -0
  29. package/dist/mosterdcomponents/mosterdcomponents.esm.js +1 -1
  30. package/dist/mosterdcomponents/p-e1a5587b.entry.js +1 -0
  31. package/dist/types/components/mrd-layout-section/mrd-layout-section.d.ts +93 -0
  32. package/dist/types/components/mrd-table/mrd-table.d.ts +5 -6
  33. package/dist/types/components.d.ts +128 -8
  34. package/dist/types/types/client-layout.d.ts +19 -0
  35. package/dist/types/utils/cell-renderer.d.ts +9 -1
  36. package/package.json +1 -1
  37. package/dist/cjs/format-DExY8_nu.js +0 -328
  38. package/dist/cjs/mrd-boolean-field_17.cjs.entry.js +0 -1554
  39. package/dist/cjs/mrd-table.cjs.entry.js +0 -888
  40. package/dist/esm/format-CcRjWvcb.js +0 -319
  41. package/dist/esm/mrd-boolean-field_17.entry.js +0 -1536
  42. package/dist/esm/mrd-table.entry.js +0 -886
  43. package/dist/mosterdcomponents/p-17fe94c6.entry.js +0 -1
  44. package/dist/mosterdcomponents/p-3d856b27.entry.js +0 -1
  45. package/dist/mosterdcomponents/p-CcRjWvcb.js +0 -1
@@ -0,0 +1,3122 @@
1
+ import { r as registerInstance, c as createEvent, h, H as Host, g as getElement } from './index-_tsCCkAi.js';
2
+ import { ClientLayoutItemFieldDataType, ClientLayoutItemType, ClientLayoutItemRelationDisplayType, ClientLayoutItemRelationEditBehavior } from './index.js';
3
+
4
+ const mrdBooleanFieldScss = () => `.sc-mrd-boolean-field-h{display:block}.mrd-boolean-field.sc-mrd-boolean-field{display:flex;align-items:center;width:100%}.mrd-boolean-field__toggle-label.sc-mrd-boolean-field{display:flex;align-items:center;gap:var(--mrd-space-3);cursor:pointer;user-select:none}.mrd-boolean-field__checkbox.sc-mrd-boolean-field{position:absolute;opacity:0;width:0;height:0;pointer-events:none}.mrd-boolean-field__checkbox.sc-mrd-boolean-field:checked+.mrd-boolean-field__toggle.sc-mrd-boolean-field{background-color:var(--mrd-color-primary)}.mrd-boolean-field__checkbox.sc-mrd-boolean-field:checked+.mrd-boolean-field__toggle.sc-mrd-boolean-field::after{transform:translateX(20px)}.mrd-boolean-field__checkbox.sc-mrd-boolean-field:focus+.mrd-boolean-field__toggle.sc-mrd-boolean-field{box-shadow:var(--mrd-shadow-focus)}.mrd-boolean-field__checkbox.sc-mrd-boolean-field:disabled+.mrd-boolean-field__toggle.sc-mrd-boolean-field{opacity:0.5;cursor:not-allowed}.mrd-boolean-field__toggle.sc-mrd-boolean-field{position:relative;display:inline-block;width:44px;height:24px;background-color:var(--mrd-color-neutral-300);border-radius:var(--mrd-border-radius-full);transition:background-color var(--mrd-transition);flex-shrink:0}.mrd-boolean-field__toggle.sc-mrd-boolean-field::after{content:'';position:absolute;top:2px;left:2px;width:20px;height:20px;background-color:var(--mrd-color-white);border-radius:50%;transition:transform var(--mrd-transition);box-shadow:var(--mrd-shadow-sm)}.mrd-boolean-field__text.sc-mrd-boolean-field{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-color-neutral-800)}.mrd-boolean-field__text--required.sc-mrd-boolean-field::after{content:' *';color:var(--mrd-color-danger)}`;
5
+
6
+ const MrdBooleanField = class {
7
+ constructor(hostRef) {
8
+ registerInstance(this, hostRef);
9
+ this.mrdChange = createEvent(this, "mrdChange");
10
+ this.mrdBlur = createEvent(this, "mrdBlur");
11
+ this.name = '';
12
+ this.label = '';
13
+ this.value = false;
14
+ this.required = false;
15
+ this.disabled = false;
16
+ this.locale = navigator.language;
17
+ this.checked = false;
18
+ this.handleChange = (e) => {
19
+ this.checked = e.target.checked;
20
+ this.mrdChange.emit({ name: this.name, value: this.checked });
21
+ };
22
+ this.handleBlur = () => {
23
+ this.mrdBlur.emit({ name: this.name, value: this.checked });
24
+ };
25
+ }
26
+ componentWillLoad() {
27
+ this.checked = !!this.value;
28
+ }
29
+ render() {
30
+ return (h(Host, { key: 'aed1d936d686870114a12aad9fc4cccb76ecd31e' }, h("div", { key: '5cc8aaa0f12d4195d02fce8a810d7d993e2e8c99', class: "mrd-boolean-field" }, h("label", { key: '41c3b3e0f01778fc2654ba86e3fe4e5a07c8537a', class: "mrd-boolean-field__toggle-label" }, h("input", { key: 'c261e6903e050d2f3d8df8abb90c74d99ed20161', class: "mrd-boolean-field__checkbox", type: "checkbox", name: this.name, checked: this.checked, disabled: this.disabled, onChange: this.handleChange, onBlur: this.handleBlur }), h("span", { key: '079ee220fe692536af15a7fb4286626102ae940e', class: "mrd-boolean-field__toggle", "aria-hidden": "true" }), this.label && (h("span", { key: '1f4f52a41f0bd6ba4c61cf9d4db74ab2f1aa8877', class: `mrd-boolean-field__text${this.required ? ' mrd-boolean-field__text--required' : ''}` }, this.label))))));
31
+ }
32
+ };
33
+ MrdBooleanField.style = mrdBooleanFieldScss();
34
+
35
+ const translations = {
36
+ nl: {
37
+ required: 'Dit veld is verplicht',
38
+ select_placeholder: 'Selecteer een optie',
39
+ search_placeholder: 'Zoeken...',
40
+ upload_file: 'Bestand uploaden',
41
+ choose_file: 'Bestand kiezen',
42
+ clear: 'Wissen',
43
+ today: 'Vandaag',
44
+ invalid_email: 'Voer een geldig e-mailadres in',
45
+ invalid_url: 'Voer een geldige URL in',
46
+ invalid_number: 'Voer een geldig getal in',
47
+ drop_file_here: 'Sleep bestand hierheen of',
48
+ browse: 'bladeren',
49
+ file_too_large: 'Bestand is te groot',
50
+ search_results: 'Zoekresultaten',
51
+ no_results: 'Geen resultaten gevonden',
52
+ loading: 'Laden...',
53
+ submit: 'Opslaan',
54
+ cancel: 'Annuleren',
55
+ remove: 'Verwijderen',
56
+ add: 'Toevoegen',
57
+ yes: 'Ja',
58
+ no: 'Nee',
59
+ // mrd-table footer
60
+ table_of: 'van',
61
+ download: 'Downloaden',
62
+ // mrd-table toolbar
63
+ table_filter: 'Filteren',
64
+ table_filter_hide: 'Filter verbergen',
65
+ table_filter_active: 'actief',
66
+ table_filter_clear_all: 'Alle filters wissen',
67
+ table_new_record: 'Nieuw record',
68
+ table_export_excel: 'Exporteer naar Excel',
69
+ // mrd-table filter popup
70
+ filter_sorting: 'Sortering',
71
+ filter_ascending: 'Oplopend',
72
+ filter_descending: 'Aflopend',
73
+ filter_section: 'Filter',
74
+ filter_apply: 'Toepassen',
75
+ filter_clear: 'Wissen',
76
+ filter_contains: 'Bevat',
77
+ filter_starts_with: 'Begint met',
78
+ filter_equals: 'Gelijk aan',
79
+ filter_has_value: 'Heeft waarde',
80
+ filter_is_empty: 'Is leeg',
81
+ filter_is_not_empty: 'Is niet leeg',
82
+ filter_exact: 'Exact',
83
+ filter_range: 'Bereik',
84
+ filter_from: 'Van',
85
+ filter_to: 'Tot',
86
+ filter_all: 'Alle',
87
+ filter_select_all: 'Alles',
88
+ filter_select_none: 'Geen',
89
+ filter_search_value: 'Zoekwaarde...',
90
+ filter_no_support: 'Geen filtering beschikbaar voor dit veldtype.',
91
+ // mrd-table textblock
92
+ textblock_show_more: 'Meer tonen',
93
+ close: 'Sluiten',
94
+ },
95
+ en: {
96
+ required: 'This field is required',
97
+ select_placeholder: 'Select an option',
98
+ search_placeholder: 'Search...',
99
+ upload_file: 'Upload file',
100
+ choose_file: 'Choose file',
101
+ clear: 'Clear',
102
+ today: 'Today',
103
+ invalid_email: 'Please enter a valid email address',
104
+ invalid_url: 'Please enter a valid URL',
105
+ invalid_number: 'Please enter a valid number',
106
+ drop_file_here: 'Drop file here or',
107
+ browse: 'browse',
108
+ file_too_large: 'File is too large',
109
+ search_results: 'Search results',
110
+ no_results: 'No results found',
111
+ loading: 'Loading...',
112
+ submit: 'Save',
113
+ cancel: 'Cancel',
114
+ remove: 'Remove',
115
+ add: 'Add',
116
+ yes: 'Yes',
117
+ no: 'No',
118
+ // mrd-table footer
119
+ table_of: 'of',
120
+ download: 'Download',
121
+ // mrd-table toolbar
122
+ table_filter: 'Filter',
123
+ table_filter_hide: 'Hide filter',
124
+ table_filter_active: 'active',
125
+ table_filter_clear_all: 'Clear all filters',
126
+ table_new_record: 'New record',
127
+ table_export_excel: 'Export to Excel',
128
+ // mrd-table filter popup
129
+ filter_sorting: 'Sorting',
130
+ filter_ascending: 'Ascending',
131
+ filter_descending: 'Descending',
132
+ filter_section: 'Filter',
133
+ filter_apply: 'Apply',
134
+ filter_clear: 'Clear',
135
+ filter_contains: 'Contains',
136
+ filter_starts_with: 'Starts with',
137
+ filter_equals: 'Equals',
138
+ filter_has_value: 'Has value',
139
+ filter_is_empty: 'Is empty',
140
+ filter_is_not_empty: 'Is not empty',
141
+ filter_exact: 'Exact',
142
+ filter_range: 'Range',
143
+ filter_from: 'From',
144
+ filter_to: 'To',
145
+ filter_all: 'All',
146
+ filter_select_all: 'All',
147
+ filter_select_none: 'None',
148
+ filter_search_value: 'Search value...',
149
+ filter_no_support: 'Filtering is not available for this field type.',
150
+ // mrd-table textblock
151
+ textblock_show_more: 'Show more',
152
+ close: 'Close',
153
+ },
154
+ ar: {
155
+ required: 'هذا الحقل مطلوب',
156
+ select_placeholder: 'اختر خياراً',
157
+ search_placeholder: 'بحث...',
158
+ upload_file: 'رفع ملف',
159
+ choose_file: 'اختر ملفاً',
160
+ clear: 'مسح',
161
+ today: 'اليوم',
162
+ invalid_email: 'يرجى إدخال عنوان بريد إلكتروني صحيح',
163
+ invalid_url: 'يرجى إدخال رابط صحيح',
164
+ invalid_number: 'يرجى إدخال رقم صحيح',
165
+ drop_file_here: 'اسحب الملف هنا أو',
166
+ browse: 'تصفح',
167
+ file_too_large: 'الملف كبير جداً',
168
+ search_results: 'نتائج البحث',
169
+ no_results: 'لم يتم العثور على نتائج',
170
+ loading: 'جار التحميل...',
171
+ submit: 'حفظ',
172
+ cancel: 'إلغاء',
173
+ remove: 'إزالة',
174
+ add: 'إضافة',
175
+ yes: 'نعم',
176
+ no: 'لا',
177
+ // mrd-table footer
178
+ table_of: 'من أصل',
179
+ download: 'تنزيل',
180
+ // mrd-table toolbar
181
+ table_filter: 'تصفية',
182
+ table_filter_hide: 'إخفاء التصفية',
183
+ table_filter_active: 'نشط',
184
+ table_filter_clear_all: 'مسح جميع الفلاتر',
185
+ table_new_record: 'سجل جديد',
186
+ table_export_excel: 'تصدير إلى Excel',
187
+ // mrd-table filter popup
188
+ filter_sorting: 'الترتيب',
189
+ filter_ascending: 'تصاعدي',
190
+ filter_descending: 'تنازلي',
191
+ filter_section: 'تصفية',
192
+ filter_apply: 'تطبيق',
193
+ filter_clear: 'مسح',
194
+ filter_contains: 'يحتوي على',
195
+ filter_starts_with: 'يبدأ بـ',
196
+ filter_equals: 'يساوي',
197
+ filter_has_value: 'له قيمة',
198
+ filter_is_empty: 'فارغ',
199
+ filter_is_not_empty: 'ليس فارغاً',
200
+ filter_exact: 'دقيق',
201
+ filter_range: 'نطاق',
202
+ filter_from: 'من',
203
+ filter_to: 'إلى',
204
+ filter_all: 'الكل',
205
+ filter_select_all: 'الكل',
206
+ filter_select_none: 'لا شيء',
207
+ filter_search_value: 'قيمة البحث...',
208
+ filter_no_support: 'التصفية غير متاحة لهذا النوع من الحقول.',
209
+ // mrd-table textblock
210
+ textblock_show_more: 'عرض المزيد',
211
+ close: 'إغلاق',
212
+ },
213
+ fr: {
214
+ required: 'Ce champ est obligatoire',
215
+ select_placeholder: 'Sélectionner une option',
216
+ search_placeholder: 'Rechercher...',
217
+ upload_file: 'Télécharger un fichier',
218
+ choose_file: 'Choisir un fichier',
219
+ clear: 'Effacer',
220
+ today: "Aujourd'hui",
221
+ invalid_email: 'Veuillez saisir une adresse e-mail valide',
222
+ invalid_url: 'Veuillez saisir une URL valide',
223
+ invalid_number: 'Veuillez saisir un nombre valide',
224
+ drop_file_here: 'Déposez le fichier ici ou',
225
+ browse: 'parcourir',
226
+ file_too_large: 'Le fichier est trop volumineux',
227
+ search_results: 'Résultats de recherche',
228
+ no_results: 'Aucun résultat trouvé',
229
+ loading: 'Chargement...',
230
+ submit: 'Enregistrer',
231
+ cancel: 'Annuler',
232
+ remove: 'Supprimer',
233
+ add: 'Ajouter',
234
+ yes: 'Oui',
235
+ no: 'Non',
236
+ // mrd-table footer
237
+ table_of: 'sur',
238
+ download: 'Télécharger',
239
+ // mrd-table toolbar
240
+ table_filter: 'Filtrer',
241
+ table_filter_hide: 'Masquer le filtre',
242
+ table_filter_active: 'actif',
243
+ table_filter_clear_all: 'Effacer tous les filtres',
244
+ table_new_record: 'Nouvel enregistrement',
245
+ table_export_excel: 'Exporter vers Excel',
246
+ // mrd-table filter popup
247
+ filter_sorting: 'Tri',
248
+ filter_ascending: 'Croissant',
249
+ filter_descending: 'Décroissant',
250
+ filter_section: 'Filtre',
251
+ filter_apply: 'Appliquer',
252
+ filter_clear: 'Effacer',
253
+ filter_contains: 'Contient',
254
+ filter_starts_with: 'Commence par',
255
+ filter_equals: 'Égal à',
256
+ filter_has_value: 'A une valeur',
257
+ filter_is_empty: 'Est vide',
258
+ filter_is_not_empty: "N'est pas vide",
259
+ filter_exact: 'Exact',
260
+ filter_range: 'Plage',
261
+ filter_from: 'De',
262
+ filter_to: 'À',
263
+ filter_all: 'Tous',
264
+ filter_select_all: 'Tous',
265
+ filter_select_none: 'Aucun',
266
+ filter_search_value: 'Valeur de recherche...',
267
+ filter_no_support: "Le filtrage n'est pas disponible pour ce type de champ.",
268
+ // mrd-table textblock
269
+ textblock_show_more: 'Voir plus',
270
+ close: 'Fermer',
271
+ },
272
+ };
273
+ function t(key, locale) {
274
+ var _a, _b, _c;
275
+ const lang = locale.split('-')[0].toLowerCase();
276
+ const dict = (_a = translations[lang]) !== null && _a !== void 0 ? _a : translations['en'];
277
+ return (_c = (_b = dict[key]) !== null && _b !== void 0 ? _b : translations['en'][key]) !== null && _c !== void 0 ? _c : key;
278
+ }
279
+
280
+ function validateRequired(value) {
281
+ if (value === null || value === undefined)
282
+ return false;
283
+ if (typeof value === 'string')
284
+ return value.trim().length > 0;
285
+ if (Array.isArray(value))
286
+ return value.length > 0;
287
+ if (typeof value === 'object') {
288
+ // CurrencyValue check
289
+ const cv = value;
290
+ if ('amount' in cv)
291
+ return cv.amount !== null && cv.amount !== undefined && cv.amount !== '';
292
+ }
293
+ return true;
294
+ }
295
+ function validateEmail(value) {
296
+ if (!value)
297
+ return true;
298
+ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
299
+ }
300
+ function validateUrl(value) {
301
+ if (!value)
302
+ return true;
303
+ try {
304
+ new URL(value);
305
+ return true;
306
+ }
307
+ catch (_a) {
308
+ return false;
309
+ }
310
+ }
311
+ function validateNumber(value, dataType) {
312
+ if (value === null || value === undefined || value === '')
313
+ return true;
314
+ const num = Number(value);
315
+ if (isNaN(num))
316
+ return false;
317
+ if (dataType === ClientLayoutItemFieldDataType.INTEGER) {
318
+ return Number.isInteger(num);
319
+ }
320
+ if (dataType === ClientLayoutItemFieldDataType.PERCENTAGE) {
321
+ return num >= 0 && num <= 100;
322
+ }
323
+ return true;
324
+ }
325
+
326
+ function formatNumber(value, locale, options) {
327
+ if (value === null || value === undefined || isNaN(value))
328
+ return '';
329
+ return new Intl.NumberFormat(locale, options).format(value);
330
+ }
331
+ function formatCurrency(amount, currency, locale) {
332
+ if (amount === null || amount === undefined || isNaN(amount))
333
+ return '';
334
+ return new Intl.NumberFormat(locale, {
335
+ style: 'currency',
336
+ currency,
337
+ minimumFractionDigits: 2,
338
+ maximumFractionDigits: 2,
339
+ }).format(amount);
340
+ }
341
+ function formatPercentage(value, locale, decimalPrecision = 2) {
342
+ if (value === null || value === undefined || isNaN(value))
343
+ return '';
344
+ return new Intl.NumberFormat(locale, {
345
+ style: 'percent',
346
+ minimumFractionDigits: decimalPrecision,
347
+ maximumFractionDigits: decimalPrecision,
348
+ }).format(value);
349
+ }
350
+ function formatDate(value, locale) {
351
+ if (!value)
352
+ return '';
353
+ const date = typeof value === 'string' ? new Date(value) : value;
354
+ if (isNaN(date.getTime()))
355
+ return '';
356
+ return new Intl.DateTimeFormat(locale, { year: 'numeric', month: '2-digit', day: '2-digit' }).format(date);
357
+ }
358
+ function formatDateTime(value, locale) {
359
+ if (!value)
360
+ return '';
361
+ const date = typeof value === 'string' ? new Date(value) : value;
362
+ if (isNaN(date.getTime()))
363
+ return '';
364
+ return new Intl.DateTimeFormat(locale, {
365
+ year: 'numeric',
366
+ month: '2-digit',
367
+ day: '2-digit',
368
+ hour: '2-digit',
369
+ minute: '2-digit',
370
+ }).format(date);
371
+ }
372
+ function formatTime(value, locale) {
373
+ if (!value)
374
+ return '';
375
+ // value is HH:MM or HH:MM:SS
376
+ const [hours, minutes] = value.split(':').map(Number);
377
+ const date = new Date();
378
+ date.setHours(hours, minutes, 0, 0);
379
+ return new Intl.DateTimeFormat(locale, { hour: '2-digit', minute: '2-digit' }).format(date);
380
+ }
381
+ function parseLocalizedNumber(str, locale) {
382
+ var _a, _b, _c, _d;
383
+ if (!str || !str.trim())
384
+ return null;
385
+ // Detect decimal and thousands separators from the locale
386
+ const parts = new Intl.NumberFormat(locale).formatToParts(1234567.89);
387
+ const groupSep = (_b = (_a = parts.find((p) => p.type === 'group')) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : ',';
388
+ const decimalSep = (_d = (_c = parts.find((p) => p.type === 'decimal')) === null || _c === void 0 ? void 0 : _c.value) !== null && _d !== void 0 ? _d : '.';
389
+ // Remove group separators, replace decimal separator with '.'
390
+ const normalized = str
391
+ .replace(new RegExp(`\\${groupSep}`, 'g'), '')
392
+ .replace(new RegExp(`\\${decimalSep}`), '.')
393
+ .replace('%', '')
394
+ .trim();
395
+ const parsed = parseFloat(normalized);
396
+ return isNaN(parsed) ? null : parsed;
397
+ }
398
+
399
+ const mrdCurrencyFieldScss = () => `.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{flex:1;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;text-align:right;box-sizing:border-box}.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__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)}`;
400
+
401
+ const COMMON_CURRENCIES = [
402
+ 'EUR', 'USD', 'GBP', 'CHF', 'JPY', 'CNY', 'AUD', 'CAD',
403
+ 'SEK', 'NOK', 'DKK', 'NZD', 'SGD', 'HKD', 'PLN', 'CZK',
404
+ 'HUF', 'MXN', 'BRL', 'INR', 'TRY', 'ZAR', 'AED', 'SAR',
405
+ ];
406
+ const MrdCurrencyField = class {
407
+ constructor(hostRef) {
408
+ registerInstance(this, hostRef);
409
+ this.mrdChange = createEvent(this, "mrdChange");
410
+ this.mrdBlur = createEvent(this, "mrdBlur");
411
+ this.name = '';
412
+ this.label = '';
413
+ this.value = { amount: null, currency: 'EUR' };
414
+ this.required = false;
415
+ this.disabled = false;
416
+ this.locale = navigator.language;
417
+ this.amountDisplay = '';
418
+ this.currency = 'EUR';
419
+ this.error = '';
420
+ this.handleAmountInput = (e) => {
421
+ this.amountDisplay = e.target.value;
422
+ };
423
+ this.handleAmountBlur = (e) => {
424
+ const raw = e.target.value;
425
+ const parsed = parseLocalizedNumber(raw, this.locale);
426
+ if (this.required && !validateRequired(raw)) {
427
+ this.error = t('required', this.locale);
428
+ }
429
+ else {
430
+ this.error = '';
431
+ }
432
+ const val = { amount: parsed, currency: this.currency };
433
+ this.mrdChange.emit({ name: this.name, value: val });
434
+ this.mrdBlur.emit({ name: this.name, value: val });
435
+ };
436
+ this.handleCurrencyChange = (e) => {
437
+ this.currency = e.target.value;
438
+ const parsed = parseLocalizedNumber(this.amountDisplay, this.locale);
439
+ this.mrdChange.emit({ name: this.name, value: { amount: parsed, currency: this.currency } });
440
+ };
441
+ }
442
+ componentWillLoad() {
443
+ if (this.value) {
444
+ this.currency = this.value.currency || 'EUR';
445
+ this.amountDisplay = this.value.amount !== null ? String(this.value.amount) : '';
446
+ }
447
+ }
448
+ render() {
449
+ const hasError = !!this.error;
450
+ return (h(Host, { key: 'd3450e9c26b1a755d3e6a5a3561d93b2ac566a28' }, h("div", { key: 'b66942cc1953daff728504deef8a9cc1330ef549', class: "mrd-currency-field" }, this.label && (h("label", { key: '3d3f2f06e9ffea944552f0f7cf3150d0246c54f0', class: `mrd-currency-field__label${this.required ? ' mrd-currency-field__label--required' : ''}` }, this.label)), h("div", { key: 'd30a2adfceefdbefef2d4fe6633a163a753b15d0', class: "mrd-currency-field__row" }, h("input", { key: '9af09b19b6cbe24498d6ca8edf7b28f675afdec5', class: `mrd-currency-field__amount${hasError ? ' mrd-currency-field__amount--error' : ''}`, type: "text", inputMode: "decimal", name: `${this.name}_amount`, value: this.amountDisplay, placeholder: "0.00", required: this.required, disabled: this.disabled, onInput: this.handleAmountInput, onBlur: this.handleAmountBlur }), h("select", { key: '21e55b04b7bf16586b5cfaa82d77db45c6dedf21', class: "mrd-currency-field__currency", disabled: this.disabled, onChange: this.handleCurrencyChange }, COMMON_CURRENCIES.map(c => (h("option", { key: c, value: c, selected: c === this.currency }, c))))), hasError && h("span", { key: '7a0006d4230557cf9c58f82f21de73b5d12f7e17', class: "mrd-currency-field__error" }, this.error))));
451
+ }
452
+ };
453
+ MrdCurrencyField.style = mrdCurrencyFieldScss();
454
+
455
+ const mrdDateFieldScss = () => `.sc-mrd-date-field-h{display:block}.mrd-date-field.sc-mrd-date-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-date-field__label.sc-mrd-date-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-date-field__label--required.sc-mrd-date-field::after{content:' *';color:var(--mrd-color-danger)}.mrd-date-field__input.sc-mrd-date-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;cursor:pointer}.mrd-date-field__input.sc-mrd-date-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-date-field__input.sc-mrd-date-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.mrd-date-field__input--error.sc-mrd-date-field{border-color:var(--mrd-border-color-error)}.mrd-date-field__input--error.sc-mrd-date-field:focus{box-shadow:var(--mrd-shadow-focus-error)}.mrd-date-field__error.sc-mrd-date-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}`;
456
+
457
+ const MrdDateField = class {
458
+ constructor(hostRef) {
459
+ registerInstance(this, hostRef);
460
+ this.mrdChange = createEvent(this, "mrdChange");
461
+ this.mrdBlur = createEvent(this, "mrdBlur");
462
+ this.name = '';
463
+ this.label = '';
464
+ this.value = '';
465
+ this.required = false;
466
+ this.disabled = false;
467
+ this.locale = navigator.language;
468
+ this.error = '';
469
+ this.handleChange = (e) => {
470
+ const val = e.target.value;
471
+ if (this.required && !validateRequired(val)) {
472
+ this.error = t('required', this.locale);
473
+ }
474
+ else {
475
+ this.error = '';
476
+ }
477
+ this.mrdChange.emit({ name: this.name, value: val });
478
+ };
479
+ this.handleBlur = (e) => {
480
+ const val = e.target.value;
481
+ this.mrdBlur.emit({ name: this.name, value: val });
482
+ };
483
+ }
484
+ render() {
485
+ const hasError = !!this.error;
486
+ return (h(Host, { key: '84c777fc68a95e0b1ceb08d61e3af7afa199ce94' }, h("div", { key: '6653d94ab79c74342ce792792547018e4464a814', class: "mrd-date-field" }, this.label && (h("label", { key: '2fa7b7ec50c784f9410ca48b93d50e39dc6e0bee', class: `mrd-date-field__label${this.required ? ' mrd-date-field__label--required' : ''}` }, this.label)), h("input", { key: 'f79ebbaf0e28ad7668a5400d1df514b66457b72d', class: `mrd-date-field__input${hasError ? ' mrd-date-field__input--error' : ''}`, type: "date", name: this.name, value: this.value, required: this.required, disabled: this.disabled, onChange: this.handleChange, onBlur: this.handleBlur }), hasError && h("span", { key: 'e52f0b720d76e8ba0586fb40395b6875860762db', class: "mrd-date-field__error" }, this.error))));
487
+ }
488
+ };
489
+ MrdDateField.style = mrdDateFieldScss();
490
+
491
+ const mrdDatetimeFieldScss = () => `.sc-mrd-datetime-field-h{display:block}.mrd-datetime-field.sc-mrd-datetime-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-datetime-field__label.sc-mrd-datetime-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-datetime-field__label--required.sc-mrd-datetime-field::after{content:' *';color:var(--mrd-color-danger)}.mrd-datetime-field__input.sc-mrd-datetime-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;cursor:pointer}.mrd-datetime-field__input.sc-mrd-datetime-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-datetime-field__input.sc-mrd-datetime-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.mrd-datetime-field__input--error.sc-mrd-datetime-field{border-color:var(--mrd-border-color-error)}.mrd-datetime-field__input--error.sc-mrd-datetime-field:focus{box-shadow:var(--mrd-shadow-focus-error)}.mrd-datetime-field__error.sc-mrd-datetime-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}`;
492
+
493
+ const MrdDatetimeField = class {
494
+ constructor(hostRef) {
495
+ registerInstance(this, hostRef);
496
+ this.mrdChange = createEvent(this, "mrdChange");
497
+ this.mrdBlur = createEvent(this, "mrdBlur");
498
+ this.name = '';
499
+ this.label = '';
500
+ this.value = '';
501
+ this.required = false;
502
+ this.disabled = false;
503
+ this.locale = navigator.language;
504
+ this.error = '';
505
+ this.localValue = '';
506
+ this.handleChange = (e) => {
507
+ const localVal = e.target.value;
508
+ this.localValue = localVal;
509
+ if (this.required && !validateRequired(localVal)) {
510
+ this.error = t('required', this.locale);
511
+ }
512
+ else {
513
+ this.error = '';
514
+ }
515
+ this.mrdChange.emit({ name: this.name, value: this.localToUtc(localVal) });
516
+ };
517
+ this.handleBlur = (e) => {
518
+ const localVal = e.target.value;
519
+ this.mrdBlur.emit({ name: this.name, value: this.localToUtc(localVal) });
520
+ };
521
+ }
522
+ componentWillLoad() {
523
+ this.localValue = this.utcToLocal(this.value);
524
+ }
525
+ valueChanged(newVal) {
526
+ this.localValue = this.utcToLocal(newVal);
527
+ }
528
+ // UTC ISO string → "YYYY-MM-DDTHH:mm" in local timezone (for datetime-local input)
529
+ utcToLocal(utcStr) {
530
+ if (!utcStr)
531
+ return '';
532
+ const d = new Date(utcStr);
533
+ if (isNaN(d.getTime()))
534
+ return '';
535
+ const pad = (n) => String(n).padStart(2, '0');
536
+ return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;
537
+ }
538
+ // "YYYY-MM-DDTHH:mm" local time → UTC ISO string (for API)
539
+ localToUtc(localStr) {
540
+ if (!localStr)
541
+ return '';
542
+ const d = new Date(localStr);
543
+ if (isNaN(d.getTime()))
544
+ return '';
545
+ return d.toISOString().replace(/\.\d{3}Z$/, 'Z');
546
+ }
547
+ render() {
548
+ const hasError = !!this.error;
549
+ return (h(Host, { key: '6052b08238484bee345ae4bb9b3025c7f2474c35' }, h("div", { key: 'f9073be4496e35a7d40405ae4e6a27a5c1607626', class: "mrd-datetime-field" }, this.label && (h("label", { key: '5933c3b2dfcae9bfad378441210ada6b625657a2', class: `mrd-datetime-field__label${this.required ? ' mrd-datetime-field__label--required' : ''}` }, this.label)), h("input", { key: '7a947b104c38960d2326a4877e4ca52db9fd9d84', class: `mrd-datetime-field__input${hasError ? ' mrd-datetime-field__input--error' : ''}`, type: "datetime-local", name: this.name, value: this.localValue, required: this.required, disabled: this.disabled, onChange: this.handleChange, onBlur: this.handleBlur }), hasError && h("span", { key: 'cea3dba7e14e18a3a08394ef3027b661f1808969', class: "mrd-datetime-field__error" }, this.error))));
550
+ }
551
+ static get watchers() { return {
552
+ "value": [{
553
+ "valueChanged": 0
554
+ }]
555
+ }; }
556
+ };
557
+ MrdDatetimeField.style = mrdDatetimeFieldScss();
558
+
559
+ const mrdEmailFieldScss = () => `.sc-mrd-email-field-h{display:block}.mrd-email-field.sc-mrd-email-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-email-field__label.sc-mrd-email-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-email-field__label--required.sc-mrd-email-field::after{content:' *';color:var(--mrd-color-danger)}.mrd-email-field__input.sc-mrd-email-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-email-field__input.sc-mrd-email-field::placeholder{color:var(--mrd-input-placeholder-color)}.mrd-email-field__input.sc-mrd-email-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-email-field__input.sc-mrd-email-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.mrd-email-field__input--error.sc-mrd-email-field{border-color:var(--mrd-border-color-error)}.mrd-email-field__input--error.sc-mrd-email-field:focus{box-shadow:var(--mrd-shadow-focus-error)}.mrd-email-field__error.sc-mrd-email-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}`;
560
+
561
+ const MrdEmailField = class {
562
+ constructor(hostRef) {
563
+ registerInstance(this, hostRef);
564
+ this.mrdChange = createEvent(this, "mrdChange");
565
+ this.mrdBlur = createEvent(this, "mrdBlur");
566
+ this.name = '';
567
+ this.label = '';
568
+ this.value = '';
569
+ this.placeholder = '';
570
+ this.required = false;
571
+ this.disabled = false;
572
+ this.locale = navigator.language;
573
+ this.error = '';
574
+ this.handleInput = (e) => {
575
+ const val = e.target.value;
576
+ this.mrdChange.emit({ name: this.name, value: val });
577
+ };
578
+ this.handleBlur = (e) => {
579
+ const val = e.target.value;
580
+ if (this.required && !validateRequired(val)) {
581
+ this.error = t('required', this.locale);
582
+ }
583
+ else if (val && !validateEmail(val)) {
584
+ this.error = t('invalid_email', this.locale);
585
+ }
586
+ else {
587
+ this.error = '';
588
+ }
589
+ this.mrdBlur.emit({ name: this.name, value: val });
590
+ };
591
+ }
592
+ render() {
593
+ const hasError = !!this.error;
594
+ return (h(Host, { key: '851ec092957ab86e811b292eaabe29d04a600fe0' }, h("div", { key: '2d8969d60378f3161656369494549d682de8ec0e', class: "mrd-email-field" }, this.label && (h("label", { key: '7a35cc60d4804097e1a54f984c7da1829f6bbd11', class: `mrd-email-field__label${this.required ? ' mrd-email-field__label--required' : ''}` }, this.label)), h("input", { key: '1fc20e860aa021886f7ed522c3a0c8dd2cb1e093', class: `mrd-email-field__input${hasError ? ' mrd-email-field__input--error' : ''}`, type: "email", name: this.name, value: this.value, placeholder: this.placeholder || 'name@example.com', required: this.required, disabled: this.disabled, onInput: this.handleInput, onBlur: this.handleBlur }), hasError && h("span", { key: 'a44b3b41b7cd6b8c643cc64e6aadd884a2ba4961', class: "mrd-email-field__error" }, this.error))));
595
+ }
596
+ };
597
+ MrdEmailField.style = mrdEmailFieldScss();
598
+
599
+ const MrdField = class {
600
+ constructor(hostRef) {
601
+ registerInstance(this, hostRef);
602
+ this.mrdChange = createEvent(this, "mrdChange");
603
+ this.mrdBlur = createEvent(this, "mrdBlur");
604
+ this.mrdSearch = createEvent(this, "mrdSearch");
605
+ this.mrdFetchAll = createEvent(this, "mrdFetchAll");
606
+ this.mrdUpload = createEvent(this, "mrdUpload");
607
+ this.locale = navigator.language;
608
+ this.handleChange = (e) => {
609
+ e.stopPropagation();
610
+ this.mrdChange.emit(e.detail);
611
+ };
612
+ this.handleBlur = (e) => {
613
+ e.stopPropagation();
614
+ this.mrdBlur.emit(e.detail);
615
+ };
616
+ this.handleSearch = (e) => {
617
+ e.stopPropagation();
618
+ this.mrdSearch.emit(e.detail);
619
+ };
620
+ this.handleFetchAll = (e) => {
621
+ e.stopPropagation();
622
+ this.mrdFetchAll.emit(e.detail);
623
+ };
624
+ this.handleUpload = (e) => {
625
+ e.stopPropagation();
626
+ this.mrdUpload.emit(e.detail);
627
+ };
628
+ }
629
+ render() {
630
+ 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;
631
+ const { item, locale, value } = this;
632
+ if (item.type === ClientLayoutItemType.RELATION && item.relation) {
633
+ const rel = item.relation;
634
+ return (h(Host, null, h("mrd-relation-field", { name: rel.name, label: rel.label, required: rel.required, disabled: (_a = rel.disabled) !== null && _a !== void 0 ? _a : false, locale: locale, relatedClass: rel.relatedClass, mostSignificantClass: (_b = rel.mostSignificantClass) !== null && _b !== void 0 ? _b : '', displayType: (_c = rel.displayType) !== null && _c !== void 0 ? _c : ClientLayoutItemRelationDisplayType.SEARCH, editBehavior: (_d = rel.editBehavior) !== null && _d !== void 0 ? _d : null, commonRelation: rel.commonRelation, multiple: (_e = rel.multiple) !== null && _e !== void 0 ? _e : false, dropdownValues: (_f = rel.dropdownValues) !== null && _f !== void 0 ? _f : [], value: value, onMrdChange: this.handleChange, onMrdBlur: this.handleBlur, onMrdSearch: this.handleSearch, onMrdFetchAll: this.handleFetchAll })));
635
+ }
636
+ if (item.type !== ClientLayoutItemType.FIELD || !item.field) {
637
+ return h(Host, null);
638
+ }
639
+ const field = item.field;
640
+ const commonProps = {
641
+ name: field.name,
642
+ label: field.label,
643
+ required: field.required,
644
+ disabled: (_g = field.disabled) !== null && _g !== void 0 ? _g : false,
645
+ locale,
646
+ onMrdChange: this.handleChange,
647
+ onMrdBlur: this.handleBlur,
648
+ };
649
+ switch (field.dataType) {
650
+ case ClientLayoutItemFieldDataType.TEXT:
651
+ return (h(Host, null, h("mrd-text-field", Object.assign({}, commonProps, { value: (_h = value) !== null && _h !== void 0 ? _h : '', placeholder: (_j = field.placeholder) !== null && _j !== void 0 ? _j : '' }))));
652
+ case ClientLayoutItemFieldDataType.TEXTBLOCK:
653
+ return (h(Host, null, h("mrd-textarea-field", Object.assign({}, commonProps, { value: (_k = value) !== null && _k !== void 0 ? _k : '', placeholder: (_l = field.placeholder) !== null && _l !== void 0 ? _l : '' }))));
654
+ case ClientLayoutItemFieldDataType.INTEGER:
655
+ case ClientLayoutItemFieldDataType.DECIMAL:
656
+ case ClientLayoutItemFieldDataType.PERCENTAGE:
657
+ return (h(Host, null, h("mrd-number-field", Object.assign({}, commonProps, { value: (_m = value) !== null && _m !== void 0 ? _m : null, dataType: field.dataType, decimalPrecision: (_o = field.decimalPrecision) !== null && _o !== void 0 ? _o : 2, placeholder: (_p = field.placeholder) !== null && _p !== void 0 ? _p : '' }))));
658
+ case ClientLayoutItemFieldDataType.CURRENCY:
659
+ return (h(Host, null, h("mrd-currency-field", Object.assign({}, commonProps, { value: (_q = value) !== null && _q !== void 0 ? _q : { amount: null, currency: (_r = field.currencyCode) !== null && _r !== void 0 ? _r : 'EUR' } }))));
660
+ case ClientLayoutItemFieldDataType.BOOLEAN:
661
+ return (h(Host, null, h("mrd-boolean-field", Object.assign({}, commonProps, { value: (_s = value) !== null && _s !== void 0 ? _s : false }))));
662
+ case ClientLayoutItemFieldDataType.DATE:
663
+ return (h(Host, null, h("mrd-date-field", Object.assign({}, commonProps, { value: (_t = value) !== null && _t !== void 0 ? _t : '' }))));
664
+ case ClientLayoutItemFieldDataType.DATETIME:
665
+ return (h(Host, null, h("mrd-datetime-field", Object.assign({}, commonProps, { value: (_u = value) !== null && _u !== void 0 ? _u : '' }))));
666
+ case ClientLayoutItemFieldDataType.TIME:
667
+ return (h(Host, null, h("mrd-time-field", Object.assign({}, commonProps, { value: (_v = value) !== null && _v !== void 0 ? _v : '' }))));
668
+ case ClientLayoutItemFieldDataType.EMAIL:
669
+ return (h(Host, null, h("mrd-email-field", Object.assign({}, commonProps, { value: (_w = value) !== null && _w !== void 0 ? _w : '', placeholder: (_x = field.placeholder) !== null && _x !== void 0 ? _x : '' }))));
670
+ case ClientLayoutItemFieldDataType.HYPERLINK:
671
+ return (h(Host, null, h("mrd-hyperlink-field", Object.assign({}, commonProps, { value: (_y = value) !== null && _y !== void 0 ? _y : '', placeholder: (_z = field.placeholder) !== null && _z !== void 0 ? _z : '' }))));
672
+ case ClientLayoutItemFieldDataType.LIST:
673
+ return (h(Host, null, h("mrd-list-field", Object.assign({}, commonProps, { value: (_0 = value) !== null && _0 !== void 0 ? _0 : '', multiple: (_1 = field.multiple) !== null && _1 !== void 0 ? _1 : false, listItems: (_2 = field.listItems) !== null && _2 !== void 0 ? _2 : [] }))));
674
+ case ClientLayoutItemFieldDataType.FILE:
675
+ return (h(Host, null, h("mrd-file-field", Object.assign({}, commonProps, { value: value, accept: (_3 = field.accept) !== null && _3 !== void 0 ? _3 : '', maxSize: (_4 = field.maxSize) !== null && _4 !== void 0 ? _4 : 0, onMrdUpload: this.handleUpload }))));
676
+ case ClientLayoutItemFieldDataType.IMAGE:
677
+ return (h(Host, null, h("mrd-image-field", Object.assign({}, commonProps, { value: value, accept: (_5 = field.accept) !== null && _5 !== void 0 ? _5 : 'image/*', maxSize: (_6 = field.maxSize) !== null && _6 !== void 0 ? _6 : 0, onMrdUpload: this.handleUpload }))));
678
+ case ClientLayoutItemFieldDataType.LONGTEXT:
679
+ return (h(Host, null, h("mrd-longtext-field", Object.assign({}, commonProps, { value: (_7 = value) !== null && _7 !== void 0 ? _7 : '', placeholder: (_8 = field.placeholder) !== null && _8 !== void 0 ? _8 : '' }))));
680
+ case ClientLayoutItemFieldDataType.JSON:
681
+ return h(Host, null);
682
+ default:
683
+ return h(Host, null);
684
+ }
685
+ }
686
+ };
687
+
688
+ const mrdFileFieldScss = () => `.sc-mrd-file-field-h{display:block}.mrd-file-field.sc-mrd-file-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-file-field__label.sc-mrd-file-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-file-field__label--required.sc-mrd-file-field::after{content:' *';color:var(--mrd-color-danger)}.mrd-file-field__zone.sc-mrd-file-field{display:flex;align-items:center;justify-content:center;padding:var(--mrd-space-6);border:2px dashed var(--mrd-border-color);border-radius:var(--mrd-border-radius-md);background-color:var(--mrd-color-neutral-50);cursor:pointer;transition:border-color var(--mrd-transition), background-color var(--mrd-transition);min-height:100px;position:relative}.mrd-file-field__zone.sc-mrd-file-field:hover{border-color:var(--mrd-color-primary);background-color:var(--mrd-color-primary-light)}.mrd-file-field__zone--dragging.sc-mrd-file-field{border-color:var(--mrd-color-primary);background-color:var(--mrd-color-primary-light)}.mrd-file-field__zone--error.sc-mrd-file-field{border-color:var(--mrd-border-color-error)}.mrd-file-field__zone--disabled.sc-mrd-file-field{opacity:0.6;cursor:not-allowed}.mrd-file-field__zone--disabled.sc-mrd-file-field:hover{border-color:var(--mrd-border-color);background-color:var(--mrd-color-neutral-50)}.mrd-file-field__input.sc-mrd-file-field{position:absolute;inset:0;opacity:0;width:100%;height:100%;cursor:pointer;pointer-events:none}.mrd-file-field__prompt.sc-mrd-file-field{display:flex;flex-direction:column;align-items:center;gap:var(--mrd-space-2);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-500);text-align:center}.mrd-file-field__upload-icon.sc-mrd-file-field{width:32px;height:32px;color:var(--mrd-color-neutral-400)}.mrd-file-field__browse.sc-mrd-file-field{color:var(--mrd-color-primary);font-weight:var(--mrd-font-weight-medium);text-decoration:underline}.mrd-file-field__selected.sc-mrd-file-field{display:flex;align-items:center;gap:var(--mrd-space-2);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-700)}.mrd-file-field__icon.sc-mrd-file-field{width:20px;height:20px;color:var(--mrd-color-primary);flex-shrink:0}.mrd-file-field__filename.sc-mrd-file-field{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:200px}.mrd-file-field__clear.sc-mrd-file-field{background:none;border:none;cursor:pointer;color:var(--mrd-color-neutral-400);font-size:var(--mrd-font-size-sm);padding:var(--mrd-space-1);border-radius:var(--mrd-border-radius-sm);line-height:1}.mrd-file-field__clear.sc-mrd-file-field:hover{color:var(--mrd-color-danger);background-color:var(--mrd-color-danger-light)}.mrd-file-field__spinner.sc-mrd-file-field{display:inline-block;flex-shrink:0;width:18px;height:18px;border:2px solid var(--mrd-color-neutral-300);border-top-color:var(--mrd-color-primary);border-radius:50%;animation:mrd-file-spin 0.6s linear infinite}@keyframes mrd-file-spin{to{transform:rotate(360deg)}}.mrd-file-field__error.sc-mrd-file-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}`;
689
+
690
+ const MrdFileField = class {
691
+ constructor(hostRef) {
692
+ registerInstance(this, hostRef);
693
+ this.mrdChange = createEvent(this, "mrdChange");
694
+ this.mrdBlur = createEvent(this, "mrdBlur");
695
+ this.mrdUpload = createEvent(this, "mrdUpload");
696
+ this.name = '';
697
+ this.label = '';
698
+ this.value = null;
699
+ this.required = false;
700
+ this.disabled = false;
701
+ this.locale = navigator.language;
702
+ this.accept = '';
703
+ this.maxSize = 0; // bytes, 0 = no limit
704
+ this.fileName = '';
705
+ this.isDragging = false;
706
+ this.uploading = false;
707
+ this.error = '';
708
+ this.handleInputChange = (e) => {
709
+ var _a;
710
+ const files = e.target.files;
711
+ this.handleFile((_a = files === null || files === void 0 ? void 0 : files[0]) !== null && _a !== void 0 ? _a : null);
712
+ };
713
+ this.handleDragOver = (e) => {
714
+ e.preventDefault();
715
+ this.isDragging = true;
716
+ };
717
+ this.handleDragLeave = () => {
718
+ this.isDragging = false;
719
+ };
720
+ this.handleDrop = (e) => {
721
+ var _a, _b, _c;
722
+ e.preventDefault();
723
+ this.isDragging = false;
724
+ const file = (_c = (_b = (_a = e.dataTransfer) === null || _a === void 0 ? void 0 : _a.files) === null || _b === void 0 ? void 0 : _b[0]) !== null && _c !== void 0 ? _c : null;
725
+ this.handleFile(file);
726
+ };
727
+ this.handleZoneClick = () => {
728
+ var _a;
729
+ if (!this.disabled && !this.uploading) {
730
+ (_a = this.fileInputRef) === null || _a === void 0 ? void 0 : _a.click();
731
+ }
732
+ };
733
+ this.handleClear = (e) => {
734
+ e.stopPropagation();
735
+ this.fileName = '';
736
+ this.error = '';
737
+ this.uploading = false;
738
+ if (this.fileInputRef)
739
+ this.fileInputRef.value = '';
740
+ this.mrdChange.emit({ name: this.name, value: null });
741
+ };
742
+ }
743
+ /** When the host provides a URI back via setFieldValue, the upload is done. */
744
+ valueChanged(newVal) {
745
+ if (typeof newVal === 'string' && newVal) {
746
+ this.uploading = false;
747
+ }
748
+ else if (!newVal) {
749
+ this.uploading = false;
750
+ this.fileName = '';
751
+ }
752
+ }
753
+ handleFile(file) {
754
+ if (!file) {
755
+ this.fileName = '';
756
+ this.uploading = false;
757
+ this.mrdChange.emit({ name: this.name, value: null });
758
+ return;
759
+ }
760
+ if (this.maxSize > 0 && file.size > this.maxSize) {
761
+ this.error = t('file_too_large', this.locale);
762
+ return;
763
+ }
764
+ this.error = '';
765
+ this.fileName = file.name;
766
+ this.uploading = true;
767
+ this.mrdChange.emit({ name: this.name, value: file });
768
+ this.mrdUpload.emit({ name: this.name, file });
769
+ }
770
+ render() {
771
+ const hasFile = this.uploading || (typeof this.value === 'string' && this.value) || this.fileName;
772
+ const hasError = !!this.error;
773
+ const zoneClass = [
774
+ 'mrd-file-field__zone',
775
+ this.isDragging ? 'mrd-file-field__zone--dragging' : '',
776
+ hasError ? 'mrd-file-field__zone--error' : '',
777
+ this.disabled || this.uploading ? 'mrd-file-field__zone--disabled' : '',
778
+ ].filter(Boolean).join(' ');
779
+ return (h(Host, { key: '2090102df8169226c1e66f87cbc837296e4b55d4' }, h("div", { key: '7a37a09df1bfa2eaf28ed04c806ad5f7c0337bb0', class: "mrd-file-field" }, this.label && (h("label", { key: '8f1fcb8adbb66b792be902c7c548e50db99b6a53', class: `mrd-file-field__label${this.required ? ' mrd-file-field__label--required' : ''}` }, this.label)), h("div", { key: '66d992298f537b24d69ce3ead3dd229f6d124f3d', class: zoneClass, onClick: this.handleZoneClick, onDragOver: this.handleDragOver, onDragLeave: this.handleDragLeave, onDrop: this.handleDrop }, h("input", { key: '95ba6560e71ee08c6b2526802727b29a18cdc454', ref: el => (this.fileInputRef = el), class: "mrd-file-field__input", type: "file", name: this.name, accept: this.accept, disabled: this.disabled || this.uploading, required: this.required && !hasFile, onChange: this.handleInputChange }), hasFile ? (h("div", { class: "mrd-file-field__selected" }, this.uploading ? (h("span", { class: "mrd-file-field__spinner", "aria-label": t('loading', this.locale) })) : (h("svg", { class: "mrd-file-field__icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2" }, h("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }), h("polyline", { points: "14 2 14 8 20 8" }))), h("span", { class: "mrd-file-field__filename" }, this.fileName), !this.uploading && (h("button", { class: "mrd-file-field__clear", type: "button", onClick: this.handleClear, "aria-label": t('clear', this.locale) }, "\u2715")))) : (h("div", { class: "mrd-file-field__prompt" }, h("svg", { class: "mrd-file-field__upload-icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2" }, h("polyline", { points: "16 16 12 12 8 16" }), h("line", { x1: "12", y1: "12", x2: "12", y2: "21" }), h("path", { d: "M20.39 18.39A5 5 0 0 0 18 9h-1.26A8 8 0 1 0 3 16.3" })), h("span", null, t('drop_file_here', this.locale), ' ', h("span", { class: "mrd-file-field__browse" }, t('browse', this.locale)))))), hasError && h("span", { key: 'a6020e63bebb01e31a980a903f81badd486585aa', class: "mrd-file-field__error" }, this.error))));
780
+ }
781
+ static get watchers() { return {
782
+ "value": [{
783
+ "valueChanged": 0
784
+ }]
785
+ }; }
786
+ };
787
+ MrdFileField.style = mrdFileFieldScss();
788
+
789
+ const mrdFormScss = () => `.sc-mrd-form-h{display:block}.mrd-form.sc-mrd-form{font-family:var(--mrd-font-family);width:100%}.mrd-form__title.sc-mrd-form{font-size:var(--mrd-font-size-2xl);font-weight:var(--mrd-font-weight-bold);color:var(--mrd-color-neutral-900);margin:0 0 var(--mrd-space-6) 0}.mrd-form__body.sc-mrd-form{display:flex;flex-direction:column;gap:var(--mrd-space-5)}.mrd-form__field.sc-mrd-form{display:flex;flex-direction:column;gap:var(--mrd-space-1)}.mrd-form__field-error.sc-mrd-form{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}.mrd-form__section.sc-mrd-form{border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius-md);padding:var(--mrd-space-4) var(--mrd-space-5);margin:0}.mrd-form__section-legend.sc-mrd-form{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);font-weight:var(--mrd-font-weight-semibold);color:var(--mrd-color-neutral-700);padding:0 var(--mrd-space-2)}.mrd-form__section-body.sc-mrd-form{display:flex;flex-direction:column;gap:var(--mrd-space-4);margin-top:var(--mrd-space-2)}.mrd-form__group.sc-mrd-form{display:flex;flex-direction:column;gap:var(--mrd-space-2)}.mrd-form__group-label.sc-mrd-form{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);font-weight:var(--mrd-font-weight-semibold);color:var(--mrd-color-neutral-500);text-transform:uppercase;letter-spacing:0.05em}.mrd-form__group-body.sc-mrd-form{display:flex;flex-direction:column;gap:var(--mrd-space-4);padding-left:var(--mrd-space-4);border-left:3px solid var(--mrd-color-neutral-200)}.mrd-form__footer.sc-mrd-form{margin-top:var(--mrd-space-8);padding-top:var(--mrd-space-5);border-top:var(--mrd-border-width) solid var(--mrd-border-color);display:flex;justify-content:flex-end;gap:var(--mrd-space-3)}.mrd-form__submit.sc-mrd-form{display:inline-flex;align-items:center;justify-content:center;height:var(--mrd-input-height);padding:0 var(--mrd-space-6);background-color:var(--mrd-color-primary);color:var(--mrd-color-white);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);font-weight:var(--mrd-font-weight-medium);border:none;border-radius:var(--mrd-border-radius);cursor:pointer;transition:background-color var(--mrd-transition)}.mrd-form__submit.sc-mrd-form:hover{background-color:var(--mrd-color-primary-hover)}.mrd-form__submit.sc-mrd-form:focus{outline:none;box-shadow:var(--mrd-shadow-focus)}.mrd-form__submit.sc-mrd-form:active{background-color:var(--mrd-color-primary-dark)}.mrd-form__cancel.sc-mrd-form{display:inline-flex;align-items:center;justify-content:center;height:var(--mrd-input-height);padding:0 var(--mrd-space-6);background-color:transparent;color:var(--mrd-color-neutral-600);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);font-weight:var(--mrd-font-weight-medium);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);cursor:pointer;transition:background-color var(--mrd-transition), color var(--mrd-transition)}.mrd-form__cancel.sc-mrd-form:hover{background-color:var(--mrd-color-neutral-100);color:var(--mrd-color-neutral-800)}.mrd-form__cancel.sc-mrd-form:focus{outline:none;box-shadow:var(--mrd-shadow-focus)}.mrd-form__cancel.sc-mrd-form:active{background-color:var(--mrd-color-neutral-200)}`;
790
+
791
+ const MrdForm = class {
792
+ constructor(hostRef) {
793
+ registerInstance(this, hostRef);
794
+ this.mrdSubmit = createEvent(this, "mrdSubmit");
795
+ this.mrdCancel = createEvent(this, "mrdCancel");
796
+ this.mrdSearch = createEvent(this, "mrdSearch");
797
+ this.mrdFetchAll = createEvent(this, "mrdFetchAll");
798
+ this.mrdUpload = createEvent(this, "mrdUpload");
799
+ this.locale = navigator.language;
800
+ this.values = {};
801
+ /**
802
+ * Absolute href of the parent/reference object (e.g. the clientAgreement href
803
+ * when creating an invoice from within a client agreement).
804
+ * Combined with `referenceClass`, mrd-form will automatically pre-fill the
805
+ * matching relation field so dependent DROPDOWN fields can be fetched on load
806
+ * — without the host app needing to know anything about the form layout.
807
+ */
808
+ /**
809
+ * Absolute href of the parent/reference object (e.g. the clientAgreement href
810
+ * when creating an invoice from within a client agreement).
811
+ * Combined with `referenceClass`, mrd-form will automatically pre-fill the
812
+ * matching relation field so dependent DROPDOWN fields can be fetched on load.
813
+ */
814
+ this.referenceHref = '';
815
+ /**
816
+ * The `mostSignificantClass` of the parent/reference object
817
+ * (e.g. `'clientAgreements'`). Used to locate the matching RELATION field.
818
+ */
819
+ this.referenceClass = '';
820
+ /** When true, a cancel button is shown next to the submit button. */
821
+ this.showCancel = false;
822
+ this.formValues = {};
823
+ this.errors = {};
824
+ this.submitted = false;
825
+ this.initialValues = {};
826
+ this.handleFieldChange = (e) => {
827
+ const { name, value } = e.detail;
828
+ const prevHref = this.getHref(this.formValues[name]);
829
+ this.formValues = Object.assign(Object.assign({}, this.formValues), { [name]: value });
830
+ if (this.errors[name]) {
831
+ this.errors = Object.assign(Object.assign({}, this.errors), { [name]: '' });
832
+ }
833
+ // When a field changes, check if it is the commonRelation dependency for any
834
+ // DROPDOWN relation. If so, reset the dependent field and re-fetch its options.
835
+ // Skip when the effective href did not change (e.g. mrdBlur fires after mrdChange
836
+ // with the same value, which would otherwise trigger a duplicate fetch).
837
+ const newHref = this.getHref(value);
838
+ if (newHref === prevHref)
839
+ return;
840
+ for (const rel of this.collectDependentDropdowns()) {
841
+ if (rel.commonRelation !== name)
842
+ continue;
843
+ // Clear the dependent field's current selection (options have changed)
844
+ this.formValues = Object.assign(Object.assign({}, this.formValues), { [rel.name]: null });
845
+ this.mrdFetchAll.emit({
846
+ name: rel.name,
847
+ relatedClass: rel.relatedClass,
848
+ mostSignificantClass: rel.mostSignificantClass,
849
+ commonRelation: rel.commonRelation,
850
+ filter: rel.commonRelation + '_href',
851
+ filterValue: newHref, // empty string when dependency was cleared → host should clear the list
852
+ });
853
+ }
854
+ };
855
+ this.handleSearch = (e) => {
856
+ e.stopPropagation();
857
+ this.mrdSearch.emit(e.detail);
858
+ };
859
+ this.handleFetchAll = (e) => {
860
+ e.stopPropagation();
861
+ this.mrdFetchAll.emit(e.detail);
862
+ };
863
+ this.handleUpload = (e) => {
864
+ e.stopPropagation();
865
+ this.mrdUpload.emit(e.detail);
866
+ };
867
+ this.handleSubmit = (e) => {
868
+ e.preventDefault();
869
+ this.submitted = true;
870
+ if (this.validate()) {
871
+ this.mrdSubmit.emit(this.buildSubmitPayload());
872
+ }
873
+ };
874
+ }
875
+ componentWillLoad() {
876
+ var _a, _b;
877
+ this.initialValues = Object.assign({}, ((_a = this.values) !== null && _a !== void 0 ? _a : {}));
878
+ this.formValues = Object.assign({}, ((_b = this.values) !== null && _b !== void 0 ? _b : {}));
879
+ }
880
+ componentDidLoad() {
881
+ // Apply reference pre-fill and emit mrdFetchAll for dependent DROPDOWN fields.
882
+ // Deferred so Angular/host prop bindings are settled before we read them.
883
+ setTimeout(() => {
884
+ this.applyReferenceValue();
885
+ this.emitDependentFetchAll();
886
+ }, 0);
887
+ }
888
+ /** Sync formValues when the values prop is set from outside after mount
889
+ * (e.g. when pre-filling an existing record in edit mode). */
890
+ valuesChanged(newValues) {
891
+ this.initialValues = Object.assign({}, (newValues !== null && newValues !== void 0 ? newValues : {}));
892
+ this.formValues = Object.assign({}, (newValues !== null && newValues !== void 0 ? newValues : {}));
893
+ this.applyReferenceValue();
894
+ this.errors = {};
895
+ this.submitted = false;
896
+ // Re-check DROPDOWN dependencies now that formValues are updated
897
+ setTimeout(() => this.emitDependentFetchAll(), 0);
898
+ }
899
+ /**
900
+ * When referenceHref + referenceClass are set, find the matching layout field
901
+ * and inject its value into formValues. This allows dependent DROPDOWN fields
902
+ * (those with commonRelation pointing to that field) to be fetched on load
903
+ * without the host app doing any form-domain logic.
904
+ *
905
+ * Two lookup strategies:
906
+ * 1. Find a RELATION whose mostSignificantClass matches referenceClass.
907
+ * 2. Fallback: find a DROPDOWN whose commonRelation field is absent from the
908
+ * layout (API omitted it because it is implied by the reference context).
909
+ */
910
+ applyReferenceValue() {
911
+ if (!this.referenceHref || !this.referenceClass)
912
+ return;
913
+ const fieldName = this.resolveReferenceFieldName();
914
+ if (!fieldName)
915
+ return;
916
+ // Only set when not already present (don't overwrite an explicit value)
917
+ if (!this.formValues[fieldName]) {
918
+ this.formValues = Object.assign(Object.assign({}, this.formValues), { [fieldName]: this.referenceHref });
919
+ }
920
+ }
921
+ resolveReferenceFieldName() {
922
+ var _a, _b;
923
+ const allItems = this.collectFields((_b = (_a = this.layout) === null || _a === void 0 ? void 0 : _a.items) !== null && _b !== void 0 ? _b : []);
924
+ // Strategy 1: direct match on mostSignificantClass
925
+ const direct = allItems.find(item => {
926
+ var _a;
927
+ return item.type === ClientLayoutItemType.RELATION &&
928
+ ((_a = item.relation) === null || _a === void 0 ? void 0 : _a.mostSignificantClass) === this.referenceClass;
929
+ });
930
+ if (direct === null || direct === void 0 ? void 0 : direct.relation)
931
+ return direct.relation.name;
932
+ // Strategy 2: a DROPDOWN whose commonRelation field was omitted from the layout
933
+ const layoutRelationNames = new Set(allItems
934
+ .filter(item => item.type === ClientLayoutItemType.RELATION)
935
+ .map(item => item.relation.name));
936
+ for (const item of allItems) {
937
+ const rel = item.relation;
938
+ if (item.type === ClientLayoutItemType.RELATION &&
939
+ (rel === null || rel === void 0 ? void 0 : rel.editBehavior) === ClientLayoutItemRelationEditBehavior.DROPDOWN &&
940
+ rel.commonRelation &&
941
+ !layoutRelationNames.has(rel.commonRelation)) {
942
+ return rel.commonRelation;
943
+ }
944
+ }
945
+ return null;
946
+ }
947
+ async setFieldValue(name, value) {
948
+ this.formValues = Object.assign(Object.assign({}, this.formValues), { [name]: value });
949
+ if (this.errors[name]) {
950
+ this.errors = Object.assign(Object.assign({}, this.errors), { [name]: '' });
951
+ }
952
+ }
953
+ /** Collect all RELATION items that use editBehavior=DROPDOWN with a commonRelation. */
954
+ collectDependentDropdowns() {
955
+ var _a, _b;
956
+ return this.collectFields((_b = (_a = this.layout) === null || _a === void 0 ? void 0 : _a.items) !== null && _b !== void 0 ? _b : [])
957
+ .filter(item => {
958
+ var _a;
959
+ return item.type === ClientLayoutItemType.RELATION &&
960
+ ((_a = item.relation) === null || _a === void 0 ? void 0 : _a.editBehavior) === ClientLayoutItemRelationEditBehavior.DROPDOWN &&
961
+ !!item.relation.commonRelation;
962
+ })
963
+ .map(item => item.relation);
964
+ }
965
+ /** Emit mrdFetchAll for every dependent DROPDOWN whose filter value is currently set. */
966
+ emitDependentFetchAll() {
967
+ for (const rel of this.collectDependentDropdowns()) {
968
+ const filterValue = this.getHref(this.formValues[rel.commonRelation]);
969
+ if (filterValue) {
970
+ this.mrdFetchAll.emit({
971
+ name: rel.name,
972
+ relatedClass: rel.relatedClass,
973
+ mostSignificantClass: rel.mostSignificantClass,
974
+ commonRelation: rel.commonRelation,
975
+ filter: rel.commonRelation + '_href',
976
+ filterValue,
977
+ });
978
+ }
979
+ }
980
+ }
981
+ /** Extract a plain href string from a form value, which can be a string or
982
+ * a RelationSearchResult-like object with an `id` field. */
983
+ getHref(value) {
984
+ if (!value)
985
+ return '';
986
+ if (typeof value === 'string')
987
+ return value;
988
+ if (typeof value === 'object' && 'id' in value)
989
+ return value.id;
990
+ return '';
991
+ }
992
+ collectFields(items) {
993
+ const fields = [];
994
+ for (const item of items) {
995
+ if (item.type === ClientLayoutItemType.FIELD || item.type === ClientLayoutItemType.RELATION) {
996
+ fields.push(item);
997
+ }
998
+ if (item.items) {
999
+ fields.push(...this.collectFields(item.items));
1000
+ }
1001
+ }
1002
+ return fields;
1003
+ }
1004
+ validate() {
1005
+ var _a, _b, _c;
1006
+ const newErrors = {};
1007
+ const allFields = this.collectFields((_b = (_a = this.layout) === null || _a === void 0 ? void 0 : _a.items) !== null && _b !== void 0 ? _b : []);
1008
+ for (const item of allFields) {
1009
+ const def = (_c = item.field) !== null && _c !== void 0 ? _c : item.relation;
1010
+ if (!def)
1011
+ continue;
1012
+ if (def.required && !validateRequired(this.formValues[def.name])) {
1013
+ newErrors[def.name] = t('required', this.locale);
1014
+ }
1015
+ }
1016
+ this.errors = newErrors;
1017
+ return Object.keys(newErrors).length === 0;
1018
+ }
1019
+ normalizeFieldValue(value) {
1020
+ return (value === '' || value == null) ? null : value;
1021
+ }
1022
+ normalizeRelationValue(value) {
1023
+ if (value == null || value === '')
1024
+ return null;
1025
+ if (typeof value === 'string')
1026
+ return value || null;
1027
+ if (Array.isArray(value)) {
1028
+ return value.map(v => typeof v === 'object' && v !== null && 'id' in v ? v.id : String(v));
1029
+ }
1030
+ if (typeof value === 'object' && 'id' in value) {
1031
+ return value.id || null;
1032
+ }
1033
+ return null;
1034
+ }
1035
+ deepEqual(a, b) {
1036
+ if (a === b)
1037
+ return true;
1038
+ if (a == null && b == null)
1039
+ return true;
1040
+ if (a == null || b == null)
1041
+ return false;
1042
+ if (Array.isArray(a) && Array.isArray(b)) {
1043
+ if (a.length !== b.length)
1044
+ return false;
1045
+ const sa = [...a].sort();
1046
+ const sb = [...b].sort();
1047
+ return JSON.stringify(sa) === JSON.stringify(sb);
1048
+ }
1049
+ return JSON.stringify(a) === JSON.stringify(b);
1050
+ }
1051
+ /** Build a submit payload containing only fields that changed relative to
1052
+ * initialValues. For a new record (POST) initialValues is empty, so every
1053
+ * non-null field is included. For edit (PATCH) only modified fields are sent,
1054
+ * including fields explicitly cleared to null.
1055
+ */
1056
+ buildSubmitPayload() {
1057
+ var _a, _b;
1058
+ const payload = {};
1059
+ const allFields = this.collectFields((_b = (_a = this.layout) === null || _a === void 0 ? void 0 : _a.items) !== null && _b !== void 0 ? _b : []);
1060
+ for (const item of allFields) {
1061
+ if (item.type === ClientLayoutItemType.FIELD && item.field) {
1062
+ const name = item.field.name;
1063
+ const value = this.formValues[name];
1064
+ if (value instanceof File)
1065
+ continue;
1066
+ const current = this.normalizeFieldValue(value);
1067
+ const initial = this.normalizeFieldValue(this.initialValues[name]);
1068
+ if (this.deepEqual(current, initial))
1069
+ continue;
1070
+ payload[name] = current;
1071
+ }
1072
+ else if (item.type === ClientLayoutItemType.RELATION && item.relation) {
1073
+ const name = item.relation.name;
1074
+ const current = this.normalizeRelationValue(this.formValues[name]);
1075
+ const initial = this.normalizeRelationValue(this.initialValues[name]);
1076
+ if (this.deepEqual(current, initial))
1077
+ continue;
1078
+ payload[name] = current;
1079
+ }
1080
+ }
1081
+ return payload;
1082
+ }
1083
+ renderItems(items) {
1084
+ return items.map(item => {
1085
+ var _a, _b, _c, _d;
1086
+ if (item.type === ClientLayoutItemType.SECTION) {
1087
+ return (h("fieldset", { class: "mrd-form__section" }, item.label && h("legend", { class: "mrd-form__section-legend" }, item.label), h("div", { class: "mrd-form__section-body" }, item.items && this.renderItems(item.items))));
1088
+ }
1089
+ if (item.type === ClientLayoutItemType.GROUP) {
1090
+ return (h("div", { class: "mrd-form__group" }, item.label && h("div", { class: "mrd-form__group-label" }, item.label), h("div", { class: "mrd-form__group-body" }, item.items && this.renderItems(item.items))));
1091
+ }
1092
+ const fieldName = (_d = (_b = (_a = item.field) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : (_c = item.relation) === null || _c === void 0 ? void 0 : _c.name) !== null && _d !== void 0 ? _d : '';
1093
+ const fieldValue = this.formValues[fieldName];
1094
+ return (h("div", { class: "mrd-form__field" }, h("mrd-field", { item: item, locale: this.locale, value: fieldValue, onMrdChange: this.handleFieldChange, onMrdBlur: this.handleFieldChange, onMrdSearch: this.handleSearch, onMrdFetchAll: this.handleFetchAll, onMrdUpload: this.handleUpload }), this.errors[fieldName] && (h("span", { class: "mrd-form__field-error" }, this.errors[fieldName]))));
1095
+ });
1096
+ }
1097
+ render() {
1098
+ if (!this.layout) {
1099
+ return h(Host, null);
1100
+ }
1101
+ const dir = this.locale.startsWith('ar') ? 'rtl' : 'ltr';
1102
+ return (h(Host, null, h("form", { class: "mrd-form", dir: dir, onSubmit: this.handleSubmit, noValidate: true }, this.layout.title && h("h2", { class: "mrd-form__title" }, this.layout.title), h("div", { class: "mrd-form__body" }, this.renderItems(this.layout.items)), h("div", { class: "mrd-form__footer" }, h("button", { type: "submit", class: "mrd-form__submit" }, t('submit', this.locale)), this.showCancel && (h("button", { type: "button", class: "mrd-form__cancel", onClick: () => this.mrdCancel.emit() }, t('cancel', this.locale)))))));
1103
+ }
1104
+ static get watchers() { return {
1105
+ "values": [{
1106
+ "valuesChanged": 0
1107
+ }]
1108
+ }; }
1109
+ };
1110
+ MrdForm.style = mrdFormScss();
1111
+
1112
+ const mrdHyperlinkFieldScss = () => `.sc-mrd-hyperlink-field-h{display:block}.mrd-hyperlink-field.sc-mrd-hyperlink-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-hyperlink-field__label.sc-mrd-hyperlink-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-hyperlink-field__label--required.sc-mrd-hyperlink-field::after{content:' *';color:var(--mrd-color-danger)}.mrd-hyperlink-field__input.sc-mrd-hyperlink-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-hyperlink-field__input.sc-mrd-hyperlink-field::placeholder{color:var(--mrd-input-placeholder-color)}.mrd-hyperlink-field__input.sc-mrd-hyperlink-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-hyperlink-field__input.sc-mrd-hyperlink-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.mrd-hyperlink-field__input--error.sc-mrd-hyperlink-field{border-color:var(--mrd-border-color-error)}.mrd-hyperlink-field__input--error.sc-mrd-hyperlink-field:focus{box-shadow:var(--mrd-shadow-focus-error)}.mrd-hyperlink-field__error.sc-mrd-hyperlink-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}`;
1113
+
1114
+ const MrdHyperlinkField = class {
1115
+ constructor(hostRef) {
1116
+ registerInstance(this, hostRef);
1117
+ this.mrdChange = createEvent(this, "mrdChange");
1118
+ this.mrdBlur = createEvent(this, "mrdBlur");
1119
+ this.name = '';
1120
+ this.label = '';
1121
+ this.value = '';
1122
+ this.placeholder = '';
1123
+ this.required = false;
1124
+ this.disabled = false;
1125
+ this.locale = navigator.language;
1126
+ this.error = '';
1127
+ this.handleInput = (e) => {
1128
+ const val = e.target.value;
1129
+ this.mrdChange.emit({ name: this.name, value: val });
1130
+ };
1131
+ this.handleBlur = (e) => {
1132
+ const val = e.target.value;
1133
+ if (this.required && !validateRequired(val)) {
1134
+ this.error = t('required', this.locale);
1135
+ }
1136
+ else if (val && !validateUrl(val)) {
1137
+ this.error = t('invalid_url', this.locale);
1138
+ }
1139
+ else {
1140
+ this.error = '';
1141
+ }
1142
+ this.mrdBlur.emit({ name: this.name, value: val });
1143
+ };
1144
+ }
1145
+ render() {
1146
+ const hasError = !!this.error;
1147
+ return (h(Host, { key: '4f642cb037c6e25786593dbf0cbead71ce34580c' }, h("div", { key: 'c679d95924bc2d22089c435ec15a35132a4a062d', class: "mrd-hyperlink-field" }, this.label && (h("label", { key: 'b391dd2d152c68fe75517926c40779313a23b9d9', class: `mrd-hyperlink-field__label${this.required ? ' mrd-hyperlink-field__label--required' : ''}` }, this.label)), h("input", { key: 'ea0d2aba8520ecbde4df8e4507e0f16bd497baa9', class: `mrd-hyperlink-field__input${hasError ? ' mrd-hyperlink-field__input--error' : ''}`, type: "url", name: this.name, value: this.value, placeholder: this.placeholder || 'https://', required: this.required, disabled: this.disabled, onInput: this.handleInput, onBlur: this.handleBlur }), hasError && h("span", { key: 'fab1d90c726b69c6c43c7997fd1b7480678c2c78', class: "mrd-hyperlink-field__error" }, this.error))));
1148
+ }
1149
+ };
1150
+ MrdHyperlinkField.style = mrdHyperlinkFieldScss();
1151
+
1152
+ const mrdImageFieldScss = () => `.sc-mrd-image-field-h{display:block}.mrd-image-field.sc-mrd-image-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-image-field__label.sc-mrd-image-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-image-field__label--required.sc-mrd-image-field::after{content:' *';color:var(--mrd-color-danger)}.mrd-image-field__zone.sc-mrd-image-field{display:flex;align-items:center;justify-content:center;border:2px dashed var(--mrd-border-color);border-radius:var(--mrd-border-radius-md);background-color:var(--mrd-color-neutral-50);cursor:pointer;transition:border-color var(--mrd-transition), background-color var(--mrd-transition);min-height:100px;position:relative}.mrd-image-field__zone.sc-mrd-image-field:hover{border-color:var(--mrd-color-primary);background-color:var(--mrd-color-primary-light)}.mrd-image-field__zone--dragging.sc-mrd-image-field{border-color:var(--mrd-color-primary);background-color:var(--mrd-color-primary-light)}.mrd-image-field__zone--error.sc-mrd-image-field{border-color:var(--mrd-border-color-error)}.mrd-image-field__zone--disabled.sc-mrd-image-field{opacity:0.6;cursor:not-allowed}.mrd-image-field__zone--disabled.sc-mrd-image-field:hover{border-color:var(--mrd-border-color);background-color:var(--mrd-color-neutral-50)}.mrd-image-field__input.sc-mrd-image-field{position:absolute;inset:0;opacity:0;width:100%;height:100%;pointer-events:none}.mrd-image-field__prompt.sc-mrd-image-field{display:flex;flex-direction:column;align-items:center;gap:var(--mrd-space-2);padding:var(--mrd-space-6);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-500);text-align:center}.mrd-image-field__upload-icon.sc-mrd-image-field{width:40px;height:40px;color:var(--mrd-color-neutral-400)}.mrd-image-field__browse.sc-mrd-image-field{color:var(--mrd-color-primary);font-weight:var(--mrd-font-weight-medium);text-decoration:underline}.mrd-image-field__preview-container.sc-mrd-image-field{display:flex;align-items:center;gap:var(--mrd-space-4);padding:var(--mrd-space-4);width:100%}.mrd-image-field__preview-thumb.sc-mrd-image-field{flex-shrink:0;width:80px;height:80px;border-radius:var(--mrd-border-radius);overflow:hidden;border:var(--mrd-border-width) solid var(--mrd-border-color);background-color:var(--mrd-color-neutral-100)}.mrd-image-field__preview.sc-mrd-image-field{width:100%;height:100%;object-fit:cover;display:block}.mrd-image-field__preview-info.sc-mrd-image-field{flex:1;min-width:0;display:flex;flex-direction:column;gap:var(--mrd-space-1)}.mrd-image-field__preview-name.sc-mrd-image-field{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);font-weight:var(--mrd-font-weight-medium);color:var(--mrd-color-neutral-800);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mrd-image-field__preview-overlay.sc-mrd-image-field{position:absolute;inset:0;background:rgb(255 255 255 / 0.7);display:flex;align-items:center;justify-content:center;border-radius:var(--mrd-border-radius)}.mrd-image-field__spinner.sc-mrd-image-field{display:inline-block;width:24px;height:24px;border:2px solid var(--mrd-color-neutral-300);border-top-color:var(--mrd-color-primary);border-radius:50%;animation:mrd-image-spin 0.6s linear infinite}@keyframes mrd-image-spin{to{transform:rotate(360deg)}}.mrd-image-field__upload-status.sc-mrd-image-field{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-500)}.mrd-image-field__clear.sc-mrd-image-field{flex-shrink:0;background-color:var(--mrd-color-white);color:var(--mrd-color-danger);border:var(--mrd-border-width) solid var(--mrd-color-danger);border-radius:var(--mrd-border-radius);padding:var(--mrd-space-1) var(--mrd-space-3);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);font-weight:var(--mrd-font-weight-medium);cursor:pointer;transition:background-color var(--mrd-transition), color var(--mrd-transition)}.mrd-image-field__clear.sc-mrd-image-field:hover{background-color:var(--mrd-color-danger);color:var(--mrd-color-white)}.mrd-image-field__error.sc-mrd-image-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}`;
1153
+
1154
+ const MrdImageField = class {
1155
+ constructor(hostRef) {
1156
+ registerInstance(this, hostRef);
1157
+ this.mrdChange = createEvent(this, "mrdChange");
1158
+ this.mrdBlur = createEvent(this, "mrdBlur");
1159
+ this.mrdUpload = createEvent(this, "mrdUpload");
1160
+ this.name = '';
1161
+ this.label = '';
1162
+ this.value = null;
1163
+ this.required = false;
1164
+ this.disabled = false;
1165
+ this.locale = navigator.language;
1166
+ this.accept = 'image/*';
1167
+ this.maxSize = 0;
1168
+ this.previewUrl = '';
1169
+ this.fileName = '';
1170
+ this.isDragging = false;
1171
+ this.uploading = false;
1172
+ this.error = '';
1173
+ this.handleInputChange = (e) => {
1174
+ var _a;
1175
+ const files = e.target.files;
1176
+ this.handleFile((_a = files === null || files === void 0 ? void 0 : files[0]) !== null && _a !== void 0 ? _a : null);
1177
+ };
1178
+ this.handleDragOver = (e) => {
1179
+ e.preventDefault();
1180
+ this.isDragging = true;
1181
+ };
1182
+ this.handleDragLeave = () => {
1183
+ this.isDragging = false;
1184
+ };
1185
+ this.handleDrop = (e) => {
1186
+ var _a, _b, _c;
1187
+ e.preventDefault();
1188
+ this.isDragging = false;
1189
+ const file = (_c = (_b = (_a = e.dataTransfer) === null || _a === void 0 ? void 0 : _a.files) === null || _b === void 0 ? void 0 : _b[0]) !== null && _c !== void 0 ? _c : null;
1190
+ this.handleFile(file);
1191
+ };
1192
+ this.handleZoneClick = () => {
1193
+ var _a;
1194
+ if (!this.disabled && !this.uploading) {
1195
+ (_a = this.fileInputRef) === null || _a === void 0 ? void 0 : _a.click();
1196
+ }
1197
+ };
1198
+ this.handleClear = (e) => {
1199
+ e.stopPropagation();
1200
+ this.previewUrl = '';
1201
+ this.fileName = '';
1202
+ this.error = '';
1203
+ this.uploading = false;
1204
+ if (this.fileInputRef)
1205
+ this.fileInputRef.value = '';
1206
+ this.mrdChange.emit({ name: this.name, value: null });
1207
+ };
1208
+ }
1209
+ /** When the host provides a URI back via setFieldValue, the upload is done. */
1210
+ valueChanged(newVal) {
1211
+ if (typeof newVal === 'string' && newVal) {
1212
+ this.uploading = false;
1213
+ }
1214
+ else if (!newVal) {
1215
+ this.uploading = false;
1216
+ this.previewUrl = '';
1217
+ this.fileName = '';
1218
+ }
1219
+ }
1220
+ handleFile(file) {
1221
+ if (!file) {
1222
+ this.previewUrl = '';
1223
+ this.fileName = '';
1224
+ this.uploading = false;
1225
+ this.mrdChange.emit({ name: this.name, value: null });
1226
+ return;
1227
+ }
1228
+ if (this.maxSize > 0 && file.size > this.maxSize) {
1229
+ this.error = t('file_too_large', this.locale);
1230
+ return;
1231
+ }
1232
+ if (!file.type.startsWith('image/')) {
1233
+ this.error = 'Please select an image file';
1234
+ return;
1235
+ }
1236
+ this.error = '';
1237
+ this.fileName = file.name;
1238
+ this.uploading = true;
1239
+ // Show local preview immediately while upload is in progress
1240
+ const reader = new FileReader();
1241
+ reader.onload = (ev) => {
1242
+ var _a;
1243
+ this.previewUrl = (_a = ev.target) === null || _a === void 0 ? void 0 : _a.result;
1244
+ };
1245
+ reader.readAsDataURL(file);
1246
+ this.mrdChange.emit({ name: this.name, value: file });
1247
+ this.mrdUpload.emit({ name: this.name, file });
1248
+ }
1249
+ render() {
1250
+ const hasError = !!this.error;
1251
+ const zoneClass = [
1252
+ 'mrd-image-field__zone',
1253
+ this.isDragging ? 'mrd-image-field__zone--dragging' : '',
1254
+ hasError ? 'mrd-image-field__zone--error' : '',
1255
+ this.disabled || this.uploading ? 'mrd-image-field__zone--disabled' : '',
1256
+ ].filter(Boolean).join(' ');
1257
+ return (h(Host, { key: '76b5a36a7f5a420ded3400c8a1481843363d1cbe' }, h("div", { key: '3544df84aaf427a25518bafe13d60cf89ed28537', class: "mrd-image-field" }, this.label && (h("label", { key: 'dca64c1600cb98526eb4b91a908106087f099ad1', class: `mrd-image-field__label${this.required ? ' mrd-image-field__label--required' : ''}` }, this.label)), h("div", { key: 'ce07f32126f0956e47ff6fc41ff231590e0503d3', class: zoneClass, onClick: this.handleZoneClick, onDragOver: this.handleDragOver, onDragLeave: this.handleDragLeave, onDrop: this.handleDrop }, h("input", { key: '660fbae5f730834c465522a11dd674fc8e50a54e', ref: el => (this.fileInputRef = el), class: "mrd-image-field__input", type: "file", name: this.name, accept: this.accept, disabled: this.disabled || this.uploading, required: this.required && !this.previewUrl, onChange: this.handleInputChange }), this.previewUrl ? (h("div", { class: "mrd-image-field__preview-container" }, h("div", { class: "mrd-image-field__preview-thumb" }, h("img", { class: "mrd-image-field__preview", src: this.previewUrl, alt: this.fileName }), this.uploading && h("div", { class: "mrd-image-field__preview-overlay" }, h("span", { class: "mrd-image-field__spinner" }))), h("div", { class: "mrd-image-field__preview-info" }, h("span", { class: "mrd-image-field__preview-name" }, this.fileName), this.uploading && (h("span", { class: "mrd-image-field__upload-status" }, t('loading', this.locale)))), !this.uploading && (h("button", { class: "mrd-image-field__clear", type: "button", onClick: this.handleClear, "aria-label": t('clear', this.locale) }, t('remove', this.locale))))) : (h("div", { class: "mrd-image-field__prompt" }, h("svg", { class: "mrd-image-field__upload-icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2" }, h("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }), h("circle", { cx: "8.5", cy: "8.5", r: "1.5" }), h("polyline", { points: "21 15 16 10 5 21" })), h("span", null, t('drop_file_here', this.locale), ' ', h("span", { class: "mrd-image-field__browse" }, t('browse', this.locale)))))), hasError && h("span", { key: '9b8f9563fea63bd12c38f5c480e9cbd24106c3af', class: "mrd-image-field__error" }, this.error))));
1258
+ }
1259
+ static get watchers() { return {
1260
+ "value": [{
1261
+ "valueChanged": 0
1262
+ }]
1263
+ }; }
1264
+ };
1265
+ MrdImageField.style = mrdImageFieldScss();
1266
+
1267
+ class CellRenderer {
1268
+ static render(column, row, locale) {
1269
+ var _a, _b, _c, _d;
1270
+ if (column.type === ClientLayoutItemType.RELATION) {
1271
+ const name = (_b = (_a = column.relation) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : '';
1272
+ const link = (_c = row === null || row === void 0 ? void 0 : row._links) === null || _c === void 0 ? void 0 : _c[name];
1273
+ if (!link)
1274
+ return '';
1275
+ if (Array.isArray(link))
1276
+ return link.map((l) => { var _a; return (_a = l.name) !== null && _a !== void 0 ? _a : ''; }).filter(Boolean).join(', ');
1277
+ return (_d = link.name) !== null && _d !== void 0 ? _d : '';
1278
+ }
1279
+ if (column.type !== ClientLayoutItemType.FIELD || !column.field)
1280
+ return '';
1281
+ const { name, dataType, listItems } = column.field;
1282
+ const raw = row === null || row === void 0 ? void 0 : row[name];
1283
+ if (raw == null || raw === '')
1284
+ return '';
1285
+ const values = Array.isArray(raw) ? raw : [raw];
1286
+ return values
1287
+ .map(v => CellRenderer.renderValue(dataType !== null && dataType !== void 0 ? dataType : 'TEXT', v, listItems !== null && listItems !== void 0 ? listItems : [], locale))
1288
+ .filter(s => s !== '')
1289
+ .join(', ');
1290
+ }
1291
+ static renderValue(dataType, value, listItems, locale) {
1292
+ var _a, _b;
1293
+ switch (dataType) {
1294
+ case 'INTEGER':
1295
+ return formatNumber(Number(value), locale, { maximumFractionDigits: 0 });
1296
+ case 'DECIMAL':
1297
+ return formatNumber(Number(value), locale);
1298
+ case 'PERCENTAGE':
1299
+ return formatPercentage(Number(value), locale);
1300
+ case 'CURRENCY': {
1301
+ const { amount, currency } = typeof value === 'object' && value !== null
1302
+ ? value
1303
+ : { amount: value, currency: '' };
1304
+ return currency
1305
+ ? formatCurrency(Number(amount), currency, locale)
1306
+ : formatNumber(Number(amount), locale);
1307
+ }
1308
+ case 'DATE':
1309
+ return formatDate(value, locale);
1310
+ case 'DATETIME':
1311
+ return formatDateTime(value, locale);
1312
+ case 'TIME':
1313
+ return formatTime(value, locale);
1314
+ case 'BOOLEAN':
1315
+ return value ? '✓' : '';
1316
+ case 'FILE':
1317
+ case 'IMAGE':
1318
+ return typeof value === 'object' && value !== null ? ((_a = value.fileName) !== null && _a !== void 0 ? _a : '') : '';
1319
+ case 'LIST': {
1320
+ const item = listItems.find(li => li.key === String(value));
1321
+ return (_b = item === null || item === void 0 ? void 0 : item.label) !== null && _b !== void 0 ? _b : String(value);
1322
+ }
1323
+ case 'TEXTBLOCK': {
1324
+ const stripped = String(value).replace(/<[^>]*>/g, '');
1325
+ const txt = document.createElement('textarea');
1326
+ txt.innerHTML = stripped;
1327
+ return txt.value.trim();
1328
+ }
1329
+ case 'LONGTEXT':
1330
+ return String(value).replace(/[\r\n]+/g, ' ').trim();
1331
+ case 'JSON': {
1332
+ const str = typeof value === 'object' ? JSON.stringify(value) : String(value);
1333
+ return str.replace(/[\r\n]+/g, ' ').trim();
1334
+ }
1335
+ default:
1336
+ return String(value);
1337
+ }
1338
+ }
1339
+ /**
1340
+ * Returns syntax-highlighted JSON as an HTML string with inline styles.
1341
+ * compact=true → single line (no indentation); compact=false → pretty-printed.
1342
+ */
1343
+ static formatJson(value, compact = false) {
1344
+ try {
1345
+ const parsed = typeof value === 'string' ? JSON.parse(value) : value;
1346
+ const json = compact ? JSON.stringify(parsed) : JSON.stringify(parsed, null, 2);
1347
+ return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, match => {
1348
+ let style = 'color:#2aa198';
1349
+ if (/^"/.test(match)) {
1350
+ style = /:$/.test(match) ? 'color:#881391' : 'color:#268bd2';
1351
+ }
1352
+ else if (/true|false/.test(match)) {
1353
+ style = 'color:#b58900';
1354
+ }
1355
+ else if (/null/.test(match)) {
1356
+ style = 'color:#dc322f';
1357
+ }
1358
+ return `<span style="${style}">${match}</span>`;
1359
+ });
1360
+ }
1361
+ catch (_a) {
1362
+ return String(value);
1363
+ }
1364
+ }
1365
+ }
1366
+
1367
+ const mrdLayoutSectionScss = () => `.mrd-layout-section.sc-mrd-layout-section{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-color-neutral-800)}.mrd-layout-section__field.sc-mrd-layout-section{display:grid;grid-template-columns:200px 1fr;align-items:baseline;gap:0 var(--mrd-space-2);padding:var(--mrd-space-1) 0}.mrd-layout-section__field-label.sc-mrd-layout-section{font-size:var(--mrd-font-size-xs);font-weight:var(--mrd-font-weight-normal);color:var(--mrd-color-neutral-500);padding-top:1px}.mrd-layout-section__field-value.sc-mrd-layout-section{font-size:var(--mrd-font-size-sm);font-weight:var(--mrd-font-weight-medium);color:var(--mrd-color-neutral-800);word-break:break-word}.mrd-layout-section__field-header.sc-mrd-layout-section{font-size:var(--mrd-font-size-2xl);font-weight:var(--mrd-font-weight-bold);color:var(--mrd-color-neutral-900);margin:0 0 var(--mrd-space-4) 0;padding:0}.mrd-layout-section__header.sc-mrd-layout-section{font-size:var(--mrd-font-size-xl);font-weight:var(--mrd-font-weight-semibold);color:var(--mrd-color-neutral-800);margin:var(--mrd-space-4) 0 var(--mrd-space-2) 0;padding:0}.mrd-layout-section__text.sc-mrd-layout-section{font-size:var(--mrd-font-size-base);color:var(--mrd-color-neutral-700);line-height:var(--mrd-line-height-relaxed);margin:var(--mrd-space-2) 0}.mrd-layout-section__navigate.sc-mrd-layout-section{display:inline-flex;align-items:center;gap:var(--mrd-space-2);padding:var(--mrd-space-2) var(--mrd-space-3);background:none;border:1px solid var(--mrd-color-neutral-300);border-radius:var(--mrd-border-radius);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-primary);cursor:pointer;margin:var(--mrd-space-2) 0}.mrd-layout-section__navigate.sc-mrd-layout-section:hover{background-color:var(--mrd-color-primary-light);border-color:var(--mrd-color-primary)}.mrd-layout-section__link.sc-mrd-layout-section{color:var(--mrd-color-primary);text-decoration:none}.mrd-layout-section__link.sc-mrd-layout-section:hover{text-decoration:underline}.mrd-layout-section__relation-link.sc-mrd-layout-section{background:none;border:none;padding:0;font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);font-weight:var(--mrd-font-weight-semibold);color:var(--mrd-color-primary);cursor:pointer;text-align:left}.mrd-layout-section__relation-link.sc-mrd-layout-section:hover{text-decoration:underline}.mrd-layout-section__download-link.sc-mrd-layout-section{display:inline-flex;align-items:center;gap:var(--mrd-space-1);background:none;border:none;padding:0;font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-primary);cursor:pointer;text-align:left}.mrd-layout-section__download-link.sc-mrd-layout-section:hover{text-decoration:underline;color:var(--mrd-color-primary-dark)}.mrd-layout-section__file-icon.sc-mrd-layout-section{flex-shrink:0;width:1rem;height:1rem}.mrd-layout-section__boolean--true.sc-mrd-layout-section{color:var(--mrd-color-success);font-weight:var(--mrd-font-weight-semibold)}.mrd-layout-section__boolean--false.sc-mrd-layout-section{color:var(--mrd-color-neutral-400)}.mrd-layout-section__field--block.sc-mrd-layout-section{grid-template-columns:1fr}.mrd-layout-section__badge.sc-mrd-layout-section{display:inline-block;font-size:var(--mrd-font-size-xs);font-weight:var(--mrd-font-weight-medium);padding:2px var(--mrd-space-3);border-radius:10px}.mrd-layout-section__badge-dot-row.sc-mrd-layout-section{display:inline-flex;align-items:center;gap:var(--mrd-space-2)}.mrd-layout-section__badge-dot.sc-mrd-layout-section{display:inline-block;width:10px;height:10px;border-radius:50%;flex-shrink:0}.mrd-layout-section__pre.sc-mrd-layout-section{font-family:var(--mrd-font-family-mono);font-size:var(--mrd-font-size-xs);background-color:var(--mrd-color-neutral-50);border:1px solid var(--mrd-color-neutral-200);border-radius:var(--mrd-border-radius);padding:var(--mrd-space-3);margin:0;max-height:calc(10 * 1.5 * var(--mrd-font-size-xs));overflow-x:auto;overflow-y:auto;white-space:pre-wrap;word-break:break-word}.mrd-layout-section__group.sc-mrd-layout-section{margin:var(--mrd-space-4) 0}.mrd-layout-section__group-title.sc-mrd-layout-section{font-size:var(--mrd-font-size-sm);font-weight:var(--mrd-font-weight-semibold);color:var(--mrd-color-neutral-500);margin:0 0 var(--mrd-space-2) 0;padding-bottom:0;text-transform:uppercase;letter-spacing:0.05em}.mrd-layout-section__related-view.sc-mrd-layout-section{margin:var(--mrd-space-4) 0}.mrd-layout-section__related-view-title.sc-mrd-layout-section{font-size:var(--mrd-font-size-lg);font-weight:var(--mrd-font-weight-semibold);color:var(--mrd-color-neutral-800);margin:0 0 var(--mrd-space-3) 0}.mrd-layout-section__search.sc-mrd-layout-section{position:relative;margin:var(--mrd-space-2) 0}.mrd-layout-section__search-input.sc-mrd-layout-section{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);outline:none;appearance:none;box-sizing:border-box}.mrd-layout-section__search-input.sc-mrd-layout-section:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-layout-section__search-input.sc-mrd-layout-section::placeholder{color:var(--mrd-input-placeholder-color)}.mrd-layout-section__search-results.sc-mrd-layout-section{position:absolute;top:100%;left:0;right:0;background-color:var(--mrd-color-white);border:1px solid var(--mrd-color-neutral-300);border-top:none;border-radius:0 0 var(--mrd-border-radius) var(--mrd-border-radius);box-shadow:var(--mrd-shadow-sm);z-index:100;max-height:300px;overflow-y:auto;list-style:none;margin:0;padding:var(--mrd-space-1) 0}.mrd-layout-section__search-result.sc-mrd-layout-section{margin:0;padding:0}.mrd-layout-section__search-result-btn.sc-mrd-layout-section{display:flex;flex-direction:column;width:100%;padding:var(--mrd-space-2) var(--mrd-space-3);background:none;border:none;text-align:left;cursor:pointer;font-family:var(--mrd-font-family)}.mrd-layout-section__search-result-btn.sc-mrd-layout-section:hover{background-color:var(--mrd-color-primary-light)}.mrd-layout-section__search-result-label.sc-mrd-layout-section{font-size:var(--mrd-font-size-sm);font-weight:var(--mrd-font-weight-medium);color:var(--mrd-color-neutral-800)}.mrd-layout-section__search-result-desc.sc-mrd-layout-section{font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-500);margin-top:var(--mrd-space-1)}.mrd-layout-section__image-thumb-btn.sc-mrd-layout-section{background:none;border:none;padding:0;cursor:pointer;display:inline-block;border-radius:var(--mrd-border-radius);overflow:hidden;line-height:0}.mrd-layout-section__image-thumb-btn.sc-mrd-layout-section:hover .mrd-layout-section__image-thumb.sc-mrd-layout-section{opacity:0.85}.mrd-layout-section__image-thumb.sc-mrd-layout-section{display:block;max-width:160px;max-height:100px;border-radius:var(--mrd-border-radius);object-fit:cover;transition:opacity 0.15s}.mrd-layout-section__modal-backdrop.sc-mrd-layout-section{position:fixed;inset:0;background:rgba(0, 0, 0, 0.6);z-index:300;display:flex;align-items:center;justify-content:center}.mrd-layout-section__modal.sc-mrd-layout-section{position:relative;background:#fff;border-radius:var(--mrd-border-radius);padding:var(--mrd-space-3);max-width:min(90vw, 900px);max-height:90vh;display:flex;align-items:center;justify-content:center;box-shadow:var(--mrd-shadow-lg)}.mrd-layout-section__modal-close.sc-mrd-layout-section{position:absolute;top:var(--mrd-space-2);right:var(--mrd-space-2);background:rgba(0, 0, 0, 0.5);border:none;border-radius:50%;width:28px;height:28px;display:flex;align-items:center;justify-content:center;color:#fff;cursor:pointer;font-size:var(--mrd-font-size-sm);line-height:1;z-index:1}.mrd-layout-section__modal-close.sc-mrd-layout-section:hover{background:rgba(0, 0, 0, 0.8)}.mrd-layout-section__modal-image.sc-mrd-layout-section{display:block;max-width:100%;max-height:calc(90vh - 2rem);border-radius:var(--mrd-border-radius);object-fit:contain}`;
1368
+
1369
+ const MrdLayoutSection = class {
1370
+ constructor(hostRef) {
1371
+ registerInstance(this, hostRef);
1372
+ this.mrdNavigate = createEvent(this, "mrdNavigate");
1373
+ this.mrdSearch = createEvent(this, "mrdSearch");
1374
+ this.mrdDownload = createEvent(this, "mrdDownload");
1375
+ this.mrdLoadView = createEvent(this, "mrdLoadView");
1376
+ this.mrdLoadViewPage = createEvent(this, "mrdLoadViewPage");
1377
+ this.mrdLoadImage = createEvent(this, "mrdLoadImage");
1378
+ this.mrdViewAction = createEvent(this, "mrdViewAction");
1379
+ /** Items from one layout entry in ClientDashboardMetadata.layouts[]. */
1380
+ this.items = [];
1381
+ /** Record data object; keys are field names, _links holds relation and related-view links. */
1382
+ this.data = {};
1383
+ /** View metadata map (ClientDashboardMetadata.views) for RELATED_VIEW and VIEW items. */
1384
+ this.views = {};
1385
+ /** Top-level _links from ClientDashboardMetadata; used to resolve hrefs for VIEW items. */
1386
+ this.links = {};
1387
+ this.locale = navigator.language;
1388
+ this.searchQueryMap = {};
1389
+ this.searchResultsMap = {};
1390
+ this.imagePreviewUrl = null;
1391
+ this.imagePreviews = {};
1392
+ this.activeViewMap = {};
1393
+ this.viewLinksMap = {};
1394
+ this.searchTimers = {};
1395
+ this.handleViewLoadPage = (e, name) => {
1396
+ e.stopPropagation();
1397
+ this.mrdLoadViewPage.emit({ name, page: e.detail.page, sort: e.detail.sort });
1398
+ };
1399
+ this.handleSearchInput = (dataClass, query) => {
1400
+ this.searchQueryMap = Object.assign(Object.assign({}, this.searchQueryMap), { [dataClass]: query });
1401
+ if (this.searchTimers[dataClass])
1402
+ clearTimeout(this.searchTimers[dataClass]);
1403
+ if (query.length < 2) {
1404
+ this.searchResultsMap = Object.assign(Object.assign({}, this.searchResultsMap), { [dataClass]: [] });
1405
+ return;
1406
+ }
1407
+ this.searchTimers[dataClass] = setTimeout(() => {
1408
+ this.mrdSearch.emit({ query, dataClass });
1409
+ }, 300);
1410
+ };
1411
+ }
1412
+ componentDidLoad() {
1413
+ setTimeout(() => {
1414
+ this.emitLoadViews();
1415
+ this.emitLoadImages();
1416
+ }, 0);
1417
+ }
1418
+ linksChanged(newVal) {
1419
+ if (Object.keys(newVal !== null && newVal !== void 0 ? newVal : {}).length > 0) {
1420
+ this.emitLoadViews();
1421
+ }
1422
+ }
1423
+ dataChanged(newVal) {
1424
+ var _a;
1425
+ if (newVal && Object.keys((_a = newVal === null || newVal === void 0 ? void 0 : newVal._links) !== null && _a !== void 0 ? _a : {}).length > 0) {
1426
+ this.emitLoadViews();
1427
+ }
1428
+ }
1429
+ emitLoadViews() {
1430
+ var _a, _b, _c, _d, _e, _f;
1431
+ const dataLinks = ((_b = (_a = this.data) === null || _a === void 0 ? void 0 : _a._links) !== null && _b !== void 0 ? _b : {});
1432
+ for (const item of this.flattenItems(this.items)) {
1433
+ if (item.type === ClientLayoutItemType.RELATED_VIEW && item.relatedView) {
1434
+ const rv = item.relatedView;
1435
+ const viewConfig = this.views[rv.name];
1436
+ if (!viewConfig)
1437
+ continue;
1438
+ const href = (_c = dataLinks[rv.relatedClass]) === null || _c === void 0 ? void 0 : _c.href;
1439
+ this.mrdLoadView.emit({ name: rv.name, href, viewConfig });
1440
+ }
1441
+ else if (item.type === ClientLayoutItemType.VIEW) {
1442
+ const viewName = (_e = (_d = item.view) === null || _d === void 0 ? void 0 : _d.name) !== null && _e !== void 0 ? _e : item.name;
1443
+ if (!viewName)
1444
+ continue;
1445
+ const viewConfig = this.views[viewName];
1446
+ if (!viewConfig)
1447
+ continue;
1448
+ const href = (_f = this.links[viewName]) === null || _f === void 0 ? void 0 : _f.href;
1449
+ this.mrdLoadView.emit({ name: viewName, href, viewConfig });
1450
+ }
1451
+ }
1452
+ }
1453
+ emitLoadImages() {
1454
+ var _a;
1455
+ for (const item of this.flattenItems(this.items)) {
1456
+ if (item.type === ClientLayoutItemType.FIELD && ((_a = item.field) === null || _a === void 0 ? void 0 : _a.dataType) === ClientLayoutItemFieldDataType.IMAGE) {
1457
+ const fieldName = item.field.name;
1458
+ const raw = this.data[fieldName];
1459
+ const href = raw === null || raw === void 0 ? void 0 : raw.href;
1460
+ if (href)
1461
+ this.mrdLoadImage.emit({ fieldName, href });
1462
+ }
1463
+ }
1464
+ }
1465
+ flattenItems(items) {
1466
+ const result = [];
1467
+ for (const item of items) {
1468
+ result.push(item);
1469
+ if (item.items)
1470
+ result.push(...this.flattenItems(item.items));
1471
+ }
1472
+ return result;
1473
+ }
1474
+ /** Inject search results. Pass dataClass to target a specific SEARCH item; omit when there is only one. */
1475
+ async setSearchResults(results, dataClass) {
1476
+ const key = dataClass !== null && dataClass !== void 0 ? dataClass : this.resolveSearchKey();
1477
+ if (key) {
1478
+ this.searchResultsMap = Object.assign(Object.assign({}, this.searchResultsMap), { [key]: results });
1479
+ }
1480
+ }
1481
+ /**
1482
+ * Inject data into an embedded mrd-table for a RELATED_VIEW or VIEW item.
1483
+ * Pass totalElements on page 0 to initialise the table; omit on subsequent pages.
1484
+ * Pass pageLinks (_links from the page response) on page 0 to enable action hrefs in mrdViewAction.
1485
+ */
1486
+ async setViewPage(name, page, rows, totalElements, pageLinks) {
1487
+ if (pageLinks) {
1488
+ this.viewLinksMap = Object.assign(Object.assign({}, this.viewLinksMap), { [name]: pageLinks });
1489
+ }
1490
+ const table = this.el.querySelector(`mrd-table[data-view="${name}"]`);
1491
+ if (!table)
1492
+ return;
1493
+ if (totalElements !== undefined) {
1494
+ table.totalElements = totalElements;
1495
+ await table.init();
1496
+ }
1497
+ await table.setPage(page, rows);
1498
+ }
1499
+ /** Provide a resolved URL for an IMAGE field. Shows as thumbnail; clicking opens the lightbox. */
1500
+ async setImagePreview(fieldName, url) {
1501
+ this.imagePreviews = Object.assign(Object.assign({}, this.imagePreviews), { [fieldName]: url });
1502
+ }
1503
+ /** Open the lightbox directly with a URL (e.g. after mrdDownload on a FILE field). */
1504
+ async openImagePreview(url) {
1505
+ this.imagePreviewUrl = url;
1506
+ }
1507
+ resolveSearchKey() {
1508
+ const items = this.flattenItems(this.items).filter(i => i.type === ClientLayoutItemType.SEARCH);
1509
+ if (items.length === 1 && items[0].search)
1510
+ return items[0].search.dataClass;
1511
+ return null;
1512
+ }
1513
+ renderSingleFieldValue(item, value) {
1514
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
1515
+ const field = item.field;
1516
+ const dt = field.dataType;
1517
+ switch (dt) {
1518
+ case ClientLayoutItemFieldDataType.HYPERLINK: {
1519
+ const v = value;
1520
+ const href = (_a = v === null || v === void 0 ? void 0 : v.href) !== null && _a !== void 0 ? _a : String(value);
1521
+ const label = (_c = (_b = v === null || v === void 0 ? void 0 : v.text) !== null && _b !== void 0 ? _b : v === null || v === void 0 ? void 0 : v.label) !== null && _c !== void 0 ? _c : href;
1522
+ return (h("a", { class: "mrd-layout-section__link", href: href, target: "_blank", rel: "noopener noreferrer" }, label));
1523
+ }
1524
+ case ClientLayoutItemFieldDataType.TEXTBLOCK:
1525
+ return h("span", { innerHTML: String(value) });
1526
+ case ClientLayoutItemFieldDataType.LONGTEXT:
1527
+ return h("pre", { class: "mrd-layout-section__pre" }, String(value));
1528
+ case ClientLayoutItemFieldDataType.JSON:
1529
+ return h("pre", { class: "mrd-layout-section__pre", innerHTML: CellRenderer.formatJson(value) });
1530
+ case ClientLayoutItemFieldDataType.FILE: {
1531
+ const v = value;
1532
+ const fileName = (_d = v === null || v === void 0 ? void 0 : v.fileName) !== null && _d !== void 0 ? _d : String(value);
1533
+ const href = (_e = v === null || v === void 0 ? void 0 : v.href) !== null && _e !== void 0 ? _e : '';
1534
+ return (h("button", { class: "mrd-layout-section__download-link", onClick: () => href && this.mrdDownload.emit({ href, fileName }) }, h("svg", { class: "mrd-layout-section__file-icon", viewBox: "0 0 24 24", "aria-hidden": "true" }, h("path", { fill: "currentColor", d: "M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm-1 7V3.5L18.5 9H13zm-3 8l-3-3 1.41-1.41L10 14.17l4.59-4.58L16 11l-6 6z" })), t('download', this.locale)));
1535
+ }
1536
+ case ClientLayoutItemFieldDataType.IMAGE: {
1537
+ const v = value;
1538
+ const href = (_f = v === null || v === void 0 ? void 0 : v.href) !== null && _f !== void 0 ? _f : '';
1539
+ const fileName = (_g = v === null || v === void 0 ? void 0 : v.fileName) !== null && _g !== void 0 ? _g : '';
1540
+ const previewUrl = this.imagePreviews[field.name];
1541
+ if (previewUrl) {
1542
+ return (h("button", { class: "mrd-layout-section__image-thumb-btn", onClick: () => { this.imagePreviewUrl = previewUrl; }, title: fileName || undefined }, h("img", { class: "mrd-layout-section__image-thumb", src: previewUrl, alt: fileName })));
1543
+ }
1544
+ return (h("button", { class: "mrd-layout-section__download-link", onClick: () => href && this.mrdDownload.emit({ href, fileName }) }, h("svg", { class: "mrd-layout-section__file-icon", viewBox: "0 0 24 24", "aria-hidden": "true" }, h("path", { fill: "currentColor", d: "M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm-1 7V3.5L18.5 9H13zm-3 8l-3-3 1.41-1.41L10 14.17l4.59-4.58L16 11l-6 6z" })), fileName || href));
1545
+ }
1546
+ case ClientLayoutItemFieldDataType.BOOLEAN:
1547
+ return (h("span", { class: `mrd-layout-section__boolean mrd-layout-section__boolean--${value ? 'true' : 'false'}` }, value ? t('yes', this.locale) : t('no', this.locale)));
1548
+ case ClientLayoutItemFieldDataType.LIST: {
1549
+ const listItem = ((_h = field.listItems) !== null && _h !== void 0 ? _h : []).find(li => li.key === String(value));
1550
+ const label = (_j = listItem === null || listItem === void 0 ? void 0 : listItem.label) !== null && _j !== void 0 ? _j : String(value);
1551
+ const color = listItem === null || listItem === void 0 ? void 0 : listItem.color;
1552
+ const bg = listItem === null || listItem === void 0 ? void 0 : listItem.backgroundColor;
1553
+ if (color && bg) {
1554
+ return (h("span", { class: "mrd-layout-section__badge", style: { color, backgroundColor: bg } }, label));
1555
+ }
1556
+ if (color) {
1557
+ return (h("span", { class: "mrd-layout-section__badge-dot-row" }, h("span", { class: "mrd-layout-section__badge-dot", style: { backgroundColor: color } }), label));
1558
+ }
1559
+ return label;
1560
+ }
1561
+ default: {
1562
+ const text = CellRenderer.renderValue(dt, value, (_k = field.listItems) !== null && _k !== void 0 ? _k : [], this.locale);
1563
+ return text || null;
1564
+ }
1565
+ }
1566
+ }
1567
+ renderFieldValue(item, rawValue) {
1568
+ if (rawValue == null || rawValue === '')
1569
+ return null;
1570
+ const field = item.field;
1571
+ if (field.multiple && Array.isArray(rawValue)) {
1572
+ const rendered = rawValue.map(v => this.renderSingleFieldValue(item, v));
1573
+ if (rendered.every(r => typeof r === 'string' || r == null)) {
1574
+ return rendered.filter(Boolean).join(', ') || null;
1575
+ }
1576
+ return (h("span", null, rendered.map((r, i) => (h("span", { key: String(i) }, r, i < rendered.length - 1 ? ', ' : '')))));
1577
+ }
1578
+ return this.renderSingleFieldValue(item, rawValue);
1579
+ }
1580
+ renderField(item) {
1581
+ if (!item.field)
1582
+ return null;
1583
+ const field = item.field;
1584
+ const rawValue = this.data[field.name];
1585
+ const renderedValue = this.renderFieldValue(item, rawValue);
1586
+ if (field.header) {
1587
+ return (h("h1", { class: "mrd-layout-section__field-header", key: field.name }, typeof renderedValue === 'string' ? renderedValue : rawValue != null ? String(rawValue) : item.label));
1588
+ }
1589
+ if (renderedValue == null)
1590
+ return null;
1591
+ const isBlock = field.dataType === ClientLayoutItemFieldDataType.TEXTBLOCK
1592
+ || field.dataType === ClientLayoutItemFieldDataType.LONGTEXT
1593
+ || field.dataType === ClientLayoutItemFieldDataType.JSON;
1594
+ return (h("div", { class: `mrd-layout-section__field${isBlock ? ' mrd-layout-section__field--block' : ''}`, key: field.name }, h("span", { class: "mrd-layout-section__field-label" }, item.label), h("span", { class: "mrd-layout-section__field-value" }, renderedValue)));
1595
+ }
1596
+ renderRelation(item) {
1597
+ var _a, _b, _c;
1598
+ if (!item.relation)
1599
+ return null;
1600
+ const links = ((_b = (_a = this.data) === null || _a === void 0 ? void 0 : _a._links) !== null && _b !== void 0 ? _b : {});
1601
+ const link = links[item.relation.name];
1602
+ if (!link)
1603
+ return null;
1604
+ const makeBtn = (href, name) => (h("button", { key: href, class: "mrd-layout-section__relation-link", onClick: () => this.mrdNavigate.emit({ href, label: name }) }, name));
1605
+ let valueContent;
1606
+ if ((_c = link.values) === null || _c === void 0 ? void 0 : _c.length) {
1607
+ valueContent = link.values.map(v => makeBtn(v.href, v.name));
1608
+ }
1609
+ else if (link.name) {
1610
+ valueContent = makeBtn(link.href, link.name);
1611
+ }
1612
+ if (!valueContent)
1613
+ return null;
1614
+ return (h("div", { class: "mrd-layout-section__field", key: item.relation.name }, h("span", { class: "mrd-layout-section__field-label" }, item.label), h("span", { class: "mrd-layout-section__field-value" }, valueContent)));
1615
+ }
1616
+ renderSearch(item) {
1617
+ var _a, _b, _c;
1618
+ if (!item.search)
1619
+ return null;
1620
+ const dataClass = item.search.dataClass;
1621
+ const query = (_a = this.searchQueryMap[dataClass]) !== null && _a !== void 0 ? _a : '';
1622
+ const results = (_b = this.searchResultsMap[dataClass]) !== null && _b !== void 0 ? _b : [];
1623
+ return (h("div", { class: "mrd-layout-section__search", key: `search-${dataClass}` }, h("input", { class: "mrd-layout-section__search-input", type: "text", value: query, placeholder: (_c = item.label) !== null && _c !== void 0 ? _c : '', onInput: e => this.handleSearchInput(dataClass, e.target.value) }), results.length > 0 && (h("ul", { class: "mrd-layout-section__search-results" }, results.map(r => (h("li", { key: r.id, class: "mrd-layout-section__search-result" }, h("button", { class: "mrd-layout-section__search-result-btn", onClick: () => this.mrdNavigate.emit({ href: r.id, label: r.label }) }, h("span", { class: "mrd-layout-section__search-result-label" }, r.label), r.description && h("span", { class: "mrd-layout-section__search-result-desc" }, r.description)))))))));
1624
+ }
1625
+ renderRelatedView(item) {
1626
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
1627
+ const isRelated = item.type === ClientLayoutItemType.RELATED_VIEW;
1628
+ // Support both nested (item.view / item.relatedView) and flat API format (item.name)
1629
+ const name = isRelated
1630
+ ? (_a = item.relatedView) === null || _a === void 0 ? void 0 : _a.name
1631
+ : ((_c = (_b = item.view) === null || _b === void 0 ? void 0 : _b.name) !== null && _c !== void 0 ? _c : item.name);
1632
+ if (!name)
1633
+ return null;
1634
+ const viewConfig = this.views[name];
1635
+ if (!viewConfig)
1636
+ return null;
1637
+ const showTitle = isRelated
1638
+ ? (_d = item.relatedView) === null || _d === void 0 ? void 0 : _d.showTitle
1639
+ : ((_g = (_f = (_e = item.view) === null || _e === void 0 ? void 0 : _e.showTitle) !== null && _f !== void 0 ? _f : item.showTitle) !== null && _g !== void 0 ? _g : false);
1640
+ const altViews = item.alternativeViews;
1641
+ const activeName = (_h = this.activeViewMap[name]) !== null && _h !== void 0 ? _h : name;
1642
+ const activeViewConfig = (_j = this.views[activeName]) !== null && _j !== void 0 ? _j : viewConfig;
1643
+ const viewLabel = (_m = (_l = (_k = item.label) !== null && _k !== void 0 ? _k : activeViewConfig.pluralLabel) !== null && _l !== void 0 ? _l : activeViewConfig.singularLabel) !== null && _m !== void 0 ? _m : '';
1644
+ const rawActions = (_o = item.actions) !== null && _o !== void 0 ? _o : ['NEW', 'EXPORT'];
1645
+ const tableActions = rawActions.reduce((acc, a) => {
1646
+ if (a === 'NEW')
1647
+ acc.push({ action: 'create', label: t('table_new_record', this.locale), icon: 'assets/sprites.svg#icon-plus', variant: 'primary' });
1648
+ if (a === 'EXPORT')
1649
+ acc.push({ action: 'export', label: t('table_export_excel', this.locale), icon: 'assets/sprites.svg#icon-file-excel' });
1650
+ return acc;
1651
+ }, []);
1652
+ return (h("div", { class: "mrd-layout-section__related-view", key: `view-${name}` }, showTitle && item.label && h("h3", { class: "mrd-layout-section__related-view-title" }, item.label), h("mrd-table", { "data-view": name, columns: activeViewConfig.values, locale: this.locale, defaultSort: (_p = activeViewConfig.defaultSort) !== null && _p !== void 0 ? _p : '', viewLabel: viewLabel, alternativeViews: altViews, actions: tableActions, onMrdLoadPage: (e) => this.handleViewLoadPage(e, name), onMrdSwitchView: (e) => {
1653
+ var _a, _b, _c, _d, _e, _f;
1654
+ e.stopPropagation();
1655
+ const newViewName = e.detail.name;
1656
+ const newViewConfig = this.views[newViewName];
1657
+ if (!newViewConfig)
1658
+ return;
1659
+ this.activeViewMap = Object.assign(Object.assign({}, this.activeViewMap), { [name]: newViewName });
1660
+ const dataLinks = ((_b = (_a = this.data) === null || _a === void 0 ? void 0 : _a._links) !== null && _b !== void 0 ? _b : {});
1661
+ const href = isRelated
1662
+ ? (_c = dataLinks[item.relatedView.relatedClass]) === null || _c === void 0 ? void 0 : _c.href
1663
+ : ((_e = (_d = this.links[newViewName]) === null || _d === void 0 ? void 0 : _d.href) !== null && _e !== void 0 ? _e : (_f = this.links[name]) === null || _f === void 0 ? void 0 : _f.href);
1664
+ this.mrdLoadView.emit({ name, href, viewConfig: newViewConfig });
1665
+ }, onMrdAction: (e) => {
1666
+ var _a, _b, _c;
1667
+ e.stopPropagation();
1668
+ const pl = (_a = this.viewLinksMap[name]) !== null && _a !== void 0 ? _a : {};
1669
+ const href = e.detail.action === 'export' ? (_b = pl['excel']) === null || _b === void 0 ? void 0 : _b.href : (_c = pl['self']) === null || _c === void 0 ? void 0 : _c.href;
1670
+ this.mrdViewAction.emit({ name, action: e.detail.action, href });
1671
+ } })));
1672
+ }
1673
+ renderItem(item) {
1674
+ var _a, _b;
1675
+ switch (item.type) {
1676
+ case ClientLayoutItemType.FIELD:
1677
+ return this.renderField(item);
1678
+ case ClientLayoutItemType.RELATION:
1679
+ return this.renderRelation(item);
1680
+ case ClientLayoutItemType.HEADER:
1681
+ return (h("h2", { class: "mrd-layout-section__header", key: `header-${item.label}` }, item.label));
1682
+ case ClientLayoutItemType.TEXT:
1683
+ return h("div", { class: "mrd-layout-section__text", key: `text-${item.label}`, innerHTML: (_a = item.label) !== null && _a !== void 0 ? _a : '' });
1684
+ case ClientLayoutItemType.NAVIGATE:
1685
+ return (h("button", { class: "mrd-layout-section__navigate", key: `nav-${item.label}`, onClick: () => { var _a; return this.mrdNavigate.emit({ label: (_a = item.label) !== null && _a !== void 0 ? _a : '', navigate: item.navigate }); } }, item.label));
1686
+ case ClientLayoutItemType.SEARCH:
1687
+ return this.renderSearch(item);
1688
+ case ClientLayoutItemType.SECTION:
1689
+ case ClientLayoutItemType.GROUP:
1690
+ return (h("div", { class: "mrd-layout-section__group", key: `group-${item.label}` }, item.label && h("h3", { class: "mrd-layout-section__group-title" }, item.label), ((_b = item.items) !== null && _b !== void 0 ? _b : []).map(child => this.renderItem(child))));
1691
+ case ClientLayoutItemType.RELATED_VIEW:
1692
+ case ClientLayoutItemType.VIEW:
1693
+ return this.renderRelatedView(item);
1694
+ default:
1695
+ return null;
1696
+ }
1697
+ }
1698
+ renderImageModal() {
1699
+ if (!this.imagePreviewUrl)
1700
+ return null;
1701
+ 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: "" }))));
1702
+ }
1703
+ render() {
1704
+ return (h(Host, { key: 'd489c4a7810477f52ecfd664ac5d0614bef2509e' }, h("div", { key: 'e6b1478990ac8ae6adeea11adaca591b3e680e0d', class: "mrd-layout-section" }, this.items.map(item => this.renderItem(item))), this.renderImageModal()));
1705
+ }
1706
+ get el() { return getElement(this); }
1707
+ static get watchers() { return {
1708
+ "links": [{
1709
+ "linksChanged": 0
1710
+ }],
1711
+ "data": [{
1712
+ "dataChanged": 0
1713
+ }]
1714
+ }; }
1715
+ };
1716
+ MrdLayoutSection.style = mrdLayoutSectionScss();
1717
+
1718
+ const mrdListFieldScss = () => `.sc-mrd-list-field-h{display:block}.mrd-list-field.sc-mrd-list-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-list-field__label.sc-mrd-list-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-list-field__label--required.sc-mrd-list-field::after{content:' *';color:var(--mrd-color-danger)}.mrd-list-field__select.sc-mrd-list-field{display:block;width:100%;height:var(--mrd-input-height);padding:var(--mrd-input-padding-y) var(--mrd-input-padding-x);padding-right:calc(var(--mrd-input-padding-x) + 1.5rem);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-input-color);background-color:var(--mrd-input-bg);background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right var(--mrd-space-3) center;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;cursor:pointer;box-sizing:border-box}.mrd-list-field__select.sc-mrd-list-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-list-field__select.sc-mrd-list-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.mrd-list-field__select--error.sc-mrd-list-field{border-color:var(--mrd-border-color-error)}.mrd-list-field__select--error.sc-mrd-list-field:focus{box-shadow:var(--mrd-shadow-focus-error)}.mrd-list-field__checkbox-list.sc-mrd-list-field{display:flex;flex-direction:column;gap:var(--mrd-space-2);padding:var(--mrd-space-3);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);background-color:var(--mrd-input-bg)}.mrd-list-field__checkbox-list--error.sc-mrd-list-field{border-color:var(--mrd-border-color-error)}.mrd-list-field__checkbox-item.sc-mrd-list-field{display:flex;align-items:center;gap:var(--mrd-space-2);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-input-color);cursor:pointer}.mrd-list-field__checkbox-item.sc-mrd-list-field input[type='checkbox'].sc-mrd-list-field{width:1rem;height:1rem;cursor:pointer;accent-color:var(--mrd-color-primary)}.mrd-list-field__color-dot.sc-mrd-list-field{display:inline-block;width:12px;height:12px;border-radius:50%;flex-shrink:0}.mrd-list-field__error.sc-mrd-list-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}`;
1719
+
1720
+ const MrdListField = class {
1721
+ constructor(hostRef) {
1722
+ registerInstance(this, hostRef);
1723
+ this.mrdChange = createEvent(this, "mrdChange");
1724
+ this.mrdBlur = createEvent(this, "mrdBlur");
1725
+ this.name = '';
1726
+ this.label = '';
1727
+ this.value = '';
1728
+ this.required = false;
1729
+ this.disabled = false;
1730
+ this.multiple = false;
1731
+ this.locale = navigator.language;
1732
+ /** List items from the API. Each item has a `key` (stored value) and `label`. */
1733
+ this.listItems = [];
1734
+ this.error = '';
1735
+ this.selected = [];
1736
+ this.handleSelectChange = (e) => {
1737
+ const select = e.target;
1738
+ if (this.multiple) {
1739
+ const vals = Array.from(select.selectedOptions).map(o => o.value);
1740
+ this.selected = vals;
1741
+ if (this.required && !validateRequired(vals)) {
1742
+ this.error = t('required', this.locale);
1743
+ }
1744
+ else {
1745
+ this.error = '';
1746
+ }
1747
+ this.mrdChange.emit({ name: this.name, value: vals });
1748
+ }
1749
+ else {
1750
+ const val = select.value;
1751
+ if (this.required && !validateRequired(val)) {
1752
+ this.error = t('required', this.locale);
1753
+ }
1754
+ else {
1755
+ this.error = '';
1756
+ }
1757
+ this.mrdChange.emit({ name: this.name, value: val });
1758
+ }
1759
+ };
1760
+ this.handleBlur = () => {
1761
+ const val = this.multiple ? this.selected : this.value;
1762
+ this.mrdBlur.emit({ name: this.name, value: val });
1763
+ };
1764
+ this.toggleCheckbox = (key) => {
1765
+ if (this.selected.includes(key)) {
1766
+ this.selected = this.selected.filter(v => v !== key);
1767
+ }
1768
+ else {
1769
+ this.selected = [...this.selected, key];
1770
+ }
1771
+ if (this.required && !validateRequired(this.selected)) {
1772
+ this.error = t('required', this.locale);
1773
+ }
1774
+ else {
1775
+ this.error = '';
1776
+ }
1777
+ this.mrdChange.emit({ name: this.name, value: this.selected });
1778
+ };
1779
+ }
1780
+ componentWillLoad() {
1781
+ if (this.multiple) {
1782
+ this.selected = Array.isArray(this.value) ? this.value : this.value ? [this.value] : [];
1783
+ }
1784
+ }
1785
+ getContrastColor(bgColor) {
1786
+ if (!bgColor)
1787
+ return '#000000';
1788
+ const hex = bgColor.replace('#', '');
1789
+ const r = parseInt(hex.substr(0, 2), 16);
1790
+ const g = parseInt(hex.substr(2, 2), 16);
1791
+ const b = parseInt(hex.substr(4, 2), 16);
1792
+ const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
1793
+ return luminance > 0.5 ? '#000000' : '#ffffff';
1794
+ }
1795
+ render() {
1796
+ var _a, _b;
1797
+ const hasError = !!this.error;
1798
+ const currentValue = Array.isArray(this.value) ? ((_a = this.value[0]) !== null && _a !== void 0 ? _a : '') : ((_b = this.value) !== null && _b !== void 0 ? _b : '');
1799
+ if (this.multiple) {
1800
+ return (h(Host, null, h("div", { class: "mrd-list-field" }, this.label && (h("label", { class: `mrd-list-field__label${this.required ? ' mrd-list-field__label--required' : ''}` }, this.label)), h("div", { class: `mrd-list-field__checkbox-list${hasError ? ' mrd-list-field__checkbox-list--error' : ''}` }, this.listItems.map(lv => {
1801
+ var _a, _b;
1802
+ return (h("label", { key: lv.key, class: "mrd-list-field__checkbox-item" }, h("input", { type: "checkbox", checked: this.selected.includes(lv.key), disabled: this.disabled, onChange: () => this.toggleCheckbox(lv.key) }), (lv.color || lv.backgroundColor) && (h("span", { class: "mrd-list-field__color-dot", style: { backgroundColor: (_b = (_a = lv.backgroundColor) !== null && _a !== void 0 ? _a : lv.color) !== null && _b !== void 0 ? _b : '' } })), h("span", null, lv.label)));
1803
+ })), hasError && h("span", { class: "mrd-list-field__error" }, this.error))));
1804
+ }
1805
+ return (h(Host, null, h("div", { class: "mrd-list-field" }, this.label && (h("label", { class: `mrd-list-field__label${this.required ? ' mrd-list-field__label--required' : ''}` }, this.label)), h("select", { class: `mrd-list-field__select${hasError ? ' mrd-list-field__select--error' : ''}`, name: this.name, required: this.required, disabled: this.disabled, onChange: this.handleSelectChange, onBlur: this.handleBlur }, h("option", { value: "" }, t('select_placeholder', this.locale)), this.listItems.map(lv => {
1806
+ var _a, _b;
1807
+ const bg = (_b = (_a = lv.backgroundColor) !== null && _a !== void 0 ? _a : lv.color) !== null && _b !== void 0 ? _b : null;
1808
+ const style = bg ? { backgroundColor: bg, color: this.getContrastColor(bg) } : {};
1809
+ return (h("option", { key: lv.key, value: lv.key, selected: lv.key === currentValue, style: style }, lv.label));
1810
+ })), hasError && h("span", { class: "mrd-list-field__error" }, this.error))));
1811
+ }
1812
+ };
1813
+ MrdListField.style = mrdListFieldScss();
1814
+
1815
+ const mrdLongtextFieldScss = () => `.sc-mrd-longtext-field-h{display:block}.mrd-longtext-field.sc-mrd-longtext-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-longtext-field__label.sc-mrd-longtext-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-longtext-field__label--required.sc-mrd-longtext-field::after{content:' *';color:var(--mrd-color-danger)}.mrd-longtext-field__input.sc-mrd-longtext-field{display:block;width:100%;min-height:calc(var(--mrd-input-height) * 5);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;resize:vertical;box-sizing:border-box;line-height:1.5}.mrd-longtext-field__input.sc-mrd-longtext-field::placeholder{color:var(--mrd-input-placeholder-color)}.mrd-longtext-field__input.sc-mrd-longtext-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-longtext-field__input--error.sc-mrd-longtext-field{border-color:var(--mrd-border-color-error)}.mrd-longtext-field__input--error.sc-mrd-longtext-field:focus{box-shadow:var(--mrd-shadow-focus-error)}.mrd-longtext-field__content.sc-mrd-longtext-field{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-input-color);white-space:pre-wrap;word-break:break-word;margin:0;padding:var(--mrd-input-padding-y) var(--mrd-input-padding-x);background-color:var(--mrd-input-bg-disabled);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);line-height:1.5}.mrd-longtext-field__error.sc-mrd-longtext-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}`;
1816
+
1817
+ const MrdLongtextField = class {
1818
+ constructor(hostRef) {
1819
+ registerInstance(this, hostRef);
1820
+ this.mrdChange = createEvent(this, "mrdChange");
1821
+ this.mrdBlur = createEvent(this, "mrdBlur");
1822
+ this.name = '';
1823
+ this.label = '';
1824
+ this.value = '';
1825
+ this.placeholder = '';
1826
+ this.required = false;
1827
+ this.disabled = false;
1828
+ this.locale = navigator.language;
1829
+ this.error = '';
1830
+ this.handleInput = (e) => {
1831
+ const val = e.target.value;
1832
+ this.mrdChange.emit({ name: this.name, value: val });
1833
+ };
1834
+ this.handleBlur = (e) => {
1835
+ const val = e.target.value;
1836
+ if (this.required && !validateRequired(val)) {
1837
+ this.error = t('required', this.locale);
1838
+ }
1839
+ else {
1840
+ this.error = '';
1841
+ }
1842
+ this.mrdBlur.emit({ name: this.name, value: val });
1843
+ };
1844
+ }
1845
+ render() {
1846
+ const hasError = !!this.error;
1847
+ return (h(Host, { key: '3142f97e26fdef5547c8dd9d236ed8bc40d5c65f' }, h("div", { key: 'b78567596d8c6459c8e9b28ea6b02d3fe65fd16c', class: "mrd-longtext-field" }, this.label && (h("label", { key: 'e85d8657fcc49fc7e15c06b8a98b34c03738ef5b', class: `mrd-longtext-field__label${this.required ? ' mrd-longtext-field__label--required' : ''}` }, this.label)), this.disabled ? (h("pre", { class: "mrd-longtext-field__content" }, this.value)) : (h("textarea", { class: `mrd-longtext-field__input${hasError ? ' mrd-longtext-field__input--error' : ''}`, name: this.name, placeholder: this.placeholder, required: this.required, rows: 10, onInput: this.handleInput, onBlur: this.handleBlur }, this.value)), hasError && h("span", { key: '63cdcaf136e345197c42516f150752ec1d8665fa', class: "mrd-longtext-field__error" }, this.error))));
1848
+ }
1849
+ };
1850
+ MrdLongtextField.style = mrdLongtextFieldScss();
1851
+
1852
+ const mrdNumberFieldScss = () => `.sc-mrd-number-field-h{display:block}.mrd-number-field.sc-mrd-number-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-number-field__label.sc-mrd-number-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-number-field__label--required.sc-mrd-number-field::after{content:' *';color:var(--mrd-color-danger)}.mrd-number-field__input-wrapper.sc-mrd-number-field{position:relative;display:flex;align-items:center}.mrd-number-field__input.sc-mrd-number-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;text-align:right}.mrd-number-field__input.sc-mrd-number-field::placeholder{color:var(--mrd-input-placeholder-color);text-align:left}.mrd-number-field__input.sc-mrd-number-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-number-field__input.sc-mrd-number-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.mrd-number-field__input--error.sc-mrd-number-field{border-color:var(--mrd-border-color-error)}.mrd-number-field__input--error.sc-mrd-number-field:focus{box-shadow:var(--mrd-shadow-focus-error)}.mrd-number-field__error.sc-mrd-number-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}`;
1853
+
1854
+ const MrdNumberField = class {
1855
+ constructor(hostRef) {
1856
+ registerInstance(this, hostRef);
1857
+ this.mrdChange = createEvent(this, "mrdChange");
1858
+ this.mrdBlur = createEvent(this, "mrdBlur");
1859
+ this.name = '';
1860
+ this.label = '';
1861
+ this.value = null;
1862
+ this.placeholder = '';
1863
+ this.required = false;
1864
+ this.disabled = false;
1865
+ this.locale = navigator.language;
1866
+ this.dataType = ClientLayoutItemFieldDataType.INTEGER;
1867
+ this.decimalPrecision = 2;
1868
+ this.displayValue = '';
1869
+ this.error = '';
1870
+ this.handleInput = (e) => {
1871
+ this.displayValue = e.target.value;
1872
+ };
1873
+ this.handleBlur = (e) => {
1874
+ const raw = e.target.value;
1875
+ const parsed = parseLocalizedNumber(raw, this.locale);
1876
+ if (this.required && (parsed === null || raw === '')) {
1877
+ this.error = t('required', this.locale);
1878
+ }
1879
+ else if (raw !== '' && !validateNumber(parsed, this.dataType)) {
1880
+ this.error = t('invalid_number', this.locale);
1881
+ }
1882
+ else {
1883
+ this.error = '';
1884
+ }
1885
+ if (parsed !== null && validateRequired(raw)) {
1886
+ this.displayValue = this.formatForDisplay(parsed);
1887
+ }
1888
+ this.mrdChange.emit({ name: this.name, value: parsed });
1889
+ this.mrdBlur.emit({ name: this.name, value: parsed });
1890
+ };
1891
+ this.handleFocus = () => {
1892
+ // Show raw number on focus
1893
+ if (this.value !== null && this.value !== undefined) {
1894
+ const str = String(this.value);
1895
+ this.displayValue = str;
1896
+ }
1897
+ };
1898
+ }
1899
+ componentWillLoad() {
1900
+ if (this.value !== null && this.value !== undefined) {
1901
+ this.displayValue = this.formatForDisplay(this.value);
1902
+ }
1903
+ }
1904
+ formatForDisplay(val) {
1905
+ if (this.dataType === ClientLayoutItemFieldDataType.PERCENTAGE) {
1906
+ return formatNumber(val, this.locale, {
1907
+ minimumFractionDigits: 0,
1908
+ maximumFractionDigits: this.decimalPrecision,
1909
+ }) + '%';
1910
+ }
1911
+ if (this.dataType === ClientLayoutItemFieldDataType.DECIMAL) {
1912
+ return formatNumber(val, this.locale, {
1913
+ minimumFractionDigits: this.decimalPrecision,
1914
+ maximumFractionDigits: this.decimalPrecision,
1915
+ });
1916
+ }
1917
+ return formatNumber(val, this.locale, { maximumFractionDigits: 0 });
1918
+ }
1919
+ render() {
1920
+ const hasError = !!this.error;
1921
+ const suffix = this.dataType === ClientLayoutItemFieldDataType.PERCENTAGE ? '%' :
1922
+ this.dataType === ClientLayoutItemFieldDataType.DECIMAL ? '' : '';
1923
+ return (h(Host, { key: 'ba3488fb12f72bb04164e3e94c028fb8a085f1f2' }, h("div", { key: '582e30a2a256c16cc3b0cab6e64460a0a5ec1fa2', class: "mrd-number-field" }, this.label && (h("label", { key: '87fe77ce80e888406ecedaa450e8c3d2a61c790a', class: `mrd-number-field__label${this.required ? ' mrd-number-field__label--required' : ''}` }, this.label)), h("div", { key: 'e3d8cf06f585add372e385d6e6ef7d60ece8071b', class: "mrd-number-field__input-wrapper" }, h("input", { key: '04710b67ee0dcb9db327e25b2467b1b3499bc9a8', class: `mrd-number-field__input${hasError ? ' mrd-number-field__input--error' : ''}`, type: "text", inputMode: "decimal", name: this.name, value: this.displayValue, placeholder: this.placeholder || (suffix ? `0${suffix}` : '0'), required: this.required, disabled: this.disabled, onInput: this.handleInput, onBlur: this.handleBlur, onFocus: this.handleFocus })), hasError && h("span", { key: '9713244d784c82213ea835a5a6d47d468ccb0bb9', class: "mrd-number-field__error" }, this.error))));
1924
+ }
1925
+ };
1926
+ MrdNumberField.style = mrdNumberFieldScss();
1927
+
1928
+ const mrdRelationFieldScss = () => `.sc-mrd-relation-field-h{display:block}.mrd-relation-field.sc-mrd-relation-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%;position:relative}.mrd-relation-field__label.sc-mrd-relation-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-relation-field__label--required.sc-mrd-relation-field::after{content:' *';color:var(--mrd-color-danger)}.mrd-relation-field__select.sc-mrd-relation-field{display:block;width:100%;height:var(--mrd-input-height);padding:var(--mrd-input-padding-y) var(--mrd-input-padding-x);padding-right:calc(var(--mrd-input-padding-x) + 1.5rem);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-input-color);background-color:var(--mrd-input-bg);background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right var(--mrd-space-3) center;border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);outline:none;appearance:none;cursor:pointer;box-sizing:border-box}.mrd-relation-field__select.sc-mrd-relation-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-relation-field__select.sc-mrd-relation-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.mrd-relation-field__select--error.sc-mrd-relation-field{border-color:var(--mrd-border-color-error)}.mrd-relation-field__select--error.sc-mrd-relation-field:focus{box-shadow:var(--mrd-shadow-focus-error)}.mrd-relation-field__tags.sc-mrd-relation-field{display:flex;flex-wrap:wrap;gap:var(--mrd-space-1);margin-bottom:var(--mrd-space-1)}.mrd-relation-field__tag.sc-mrd-relation-field{display:inline-flex;align-items:center;gap:var(--mrd-space-1);padding:var(--mrd-space-1) var(--mrd-space-2);background-color:var(--mrd-color-primary-light);color:var(--mrd-color-primary-dark);border-radius:var(--mrd-border-radius-full);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);font-weight:var(--mrd-font-weight-medium)}.mrd-relation-field__tag-remove.sc-mrd-relation-field{background:none;border:none;cursor:pointer;color:var(--mrd-color-primary-dark);font-size:var(--mrd-font-size-xs);padding:0;line-height:1;opacity:0.7}.mrd-relation-field__tag-remove.sc-mrd-relation-field:hover{opacity:1}.mrd-relation-field__search-wrapper.sc-mrd-relation-field{position:relative;display:flex;align-items:center}.mrd-relation-field__search.sc-mrd-relation-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);outline:none;appearance:none;box-sizing:border-box}.mrd-relation-field__search.sc-mrd-relation-field::placeholder{color:var(--mrd-input-placeholder-color)}.mrd-relation-field__search.sc-mrd-relation-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-relation-field__search.sc-mrd-relation-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.mrd-relation-field__search--error.sc-mrd-relation-field{border-color:var(--mrd-border-color-error)}.mrd-relation-field__search--error.sc-mrd-relation-field:focus{box-shadow:var(--mrd-shadow-focus-error)}.mrd-relation-field__spinner.sc-mrd-relation-field{position:absolute;right:var(--mrd-space-3);width:16px;height:16px;border:2px solid var(--mrd-color-neutral-200);border-top-color:var(--mrd-color-primary);border-radius:50%;animation:mrd-spin 0.7s linear infinite}@keyframes mrd-spin{to{transform:rotate(360deg)}}.mrd-relation-field__results.sc-mrd-relation-field{position:absolute;top:calc(100% + var(--mrd-space-1));left:0;right:0;background-color:var(--mrd-color-white);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);box-shadow:var(--mrd-shadow-md);z-index:var(--mrd-z-dropdown);max-height:240px;overflow-y:auto}.mrd-relation-field__result-item.sc-mrd-relation-field{display:flex;flex-direction:column;padding:var(--mrd-space-2) var(--mrd-space-3);cursor:pointer;transition:background-color var(--mrd-transition-fast)}.mrd-relation-field__result-item.sc-mrd-relation-field:hover{background-color:var(--mrd-color-neutral-50)}.mrd-relation-field__result-item.sc-mrd-relation-field:not(:last-child){border-bottom:var(--mrd-border-width) solid var(--mrd-color-neutral-100)}.mrd-relation-field__result-label.sc-mrd-relation-field{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-color-neutral-800);font-weight:var(--mrd-font-weight-medium)}.mrd-relation-field__result-desc.sc-mrd-relation-field{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-500);margin-top:var(--mrd-space-1)}.mrd-relation-field__result-item--highlighted.sc-mrd-relation-field{background-color:var(--mrd-color-primary-light)}.mrd-relation-field__selected-value.sc-mrd-relation-field{display:flex;align-items:center;gap:var(--mrd-space-2);height:var(--mrd-input-height);padding:var(--mrd-input-padding-y) var(--mrd-input-padding-x);background-color:var(--mrd-color-primary-light);border:var(--mrd-border-width) solid var(--mrd-color-primary);border-radius:var(--mrd-border-radius);box-sizing:border-box}.mrd-relation-field__selected-value--error.sc-mrd-relation-field{border-color:var(--mrd-border-color-error);background-color:var(--mrd-color-danger-light)}.mrd-relation-field__selected-name.sc-mrd-relation-field{flex:1;font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);font-weight:var(--mrd-font-weight-medium);color:var(--mrd-color-primary-dark);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mrd-relation-field__selected-clear.sc-mrd-relation-field{flex-shrink:0;background:none;border:none;cursor:pointer;color:var(--mrd-color-primary-dark);font-size:var(--mrd-font-size-sm);padding:0;line-height:1;opacity:0.6;transition:opacity var(--mrd-transition-fast)}.mrd-relation-field__selected-clear.sc-mrd-relation-field:hover{opacity:1}.mrd-relation-field__no-results.sc-mrd-relation-field{padding:var(--mrd-space-4);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-500);text-align:center}.mrd-relation-field__error.sc-mrd-relation-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}`;
1929
+
1930
+ const MrdRelationField = class {
1931
+ constructor(hostRef) {
1932
+ registerInstance(this, hostRef);
1933
+ this.mrdChange = createEvent(this, "mrdChange");
1934
+ this.mrdBlur = createEvent(this, "mrdBlur");
1935
+ this.mrdSearch = createEvent(this, "mrdSearch");
1936
+ this.mrdFetchAll = createEvent(this, "mrdFetchAll");
1937
+ this.name = '';
1938
+ this.label = '';
1939
+ this.required = false;
1940
+ this.disabled = false;
1941
+ this.locale = navigator.language;
1942
+ this.relatedClass = '';
1943
+ /** When set, used instead of relatedClass for search queries (mostSignificantClass from API). */
1944
+ this.mostSignificantClass = '';
1945
+ this.displayType = ClientLayoutItemRelationDisplayType.SEARCH;
1946
+ this.multiple = false;
1947
+ this.dropdownValues = [];
1948
+ /** Plain href string/array for normal use; pass { id, label } objects to pre-fill a loaded record. */
1949
+ this.value = null;
1950
+ this.searchQuery = '';
1951
+ this.searchResults = [];
1952
+ this.allRecords = [];
1953
+ this.isLoading = false;
1954
+ this.selectedItems = [];
1955
+ this.showResults = false;
1956
+ this.error = '';
1957
+ this.highlightedIndex = -1;
1958
+ this.searchDebounce = null;
1959
+ this.handleKeyDown = (e) => {
1960
+ if (!this.showResults || this.searchResults.length === 0) {
1961
+ if (e.key === 'Escape') {
1962
+ this.showResults = false;
1963
+ this.highlightedIndex = -1;
1964
+ }
1965
+ return;
1966
+ }
1967
+ if (e.key === 'ArrowDown') {
1968
+ e.preventDefault();
1969
+ this.highlightedIndex = Math.min(this.highlightedIndex + 1, this.searchResults.length - 1);
1970
+ }
1971
+ else if (e.key === 'ArrowUp') {
1972
+ e.preventDefault();
1973
+ this.highlightedIndex = Math.max(this.highlightedIndex - 1, 0);
1974
+ }
1975
+ else if (e.key === 'Enter') {
1976
+ e.preventDefault();
1977
+ if (this.highlightedIndex >= 0) {
1978
+ this.handleResultSelect(this.searchResults[this.highlightedIndex]);
1979
+ }
1980
+ }
1981
+ else if (e.key === 'Escape') {
1982
+ this.showResults = false;
1983
+ this.highlightedIndex = -1;
1984
+ }
1985
+ };
1986
+ this.clearSelection = () => {
1987
+ this.selectedItems = [];
1988
+ this.searchQuery = '';
1989
+ this.searchResults = [];
1990
+ this.showResults = false;
1991
+ this.highlightedIndex = -1;
1992
+ this.mrdChange.emit({ name: this.name, value: this.multiple ? [] : null });
1993
+ };
1994
+ this.handleSearchInput = (e) => {
1995
+ const query = e.target.value;
1996
+ this.searchQuery = query;
1997
+ if (this.searchDebounce)
1998
+ clearTimeout(this.searchDebounce);
1999
+ if (query.trim().length >= 2) {
2000
+ this.isLoading = true;
2001
+ this.showResults = true;
2002
+ this.searchDebounce = setTimeout(() => {
2003
+ this.mrdSearch.emit({ name: this.name, query, relatedClass: this.mostSignificantClass });
2004
+ }, 300);
2005
+ }
2006
+ else {
2007
+ this.searchResults = [];
2008
+ this.showResults = false;
2009
+ this.isLoading = false;
2010
+ }
2011
+ };
2012
+ this.handleResultSelect = (result) => {
2013
+ if (this.multiple) {
2014
+ if (!this.selectedItems.find(i => i.id === result.id)) {
2015
+ this.selectedItems = [...this.selectedItems, result];
2016
+ }
2017
+ this.searchQuery = '';
2018
+ this.searchResults = [];
2019
+ this.showResults = false;
2020
+ const ids = this.selectedItems.map(i => i.id);
2021
+ this.mrdChange.emit({ name: this.name, value: ids });
2022
+ }
2023
+ else {
2024
+ this.selectedItems = [result];
2025
+ this.searchQuery = result.label;
2026
+ this.showResults = false;
2027
+ this.mrdChange.emit({ name: this.name, value: result.id });
2028
+ }
2029
+ if (this.required && !validateRequired(this.selectedItems)) {
2030
+ this.error = t('required', this.locale);
2031
+ }
2032
+ else {
2033
+ this.error = '';
2034
+ }
2035
+ };
2036
+ this.handleRemoveSelected = (id) => {
2037
+ this.selectedItems = this.selectedItems.filter(i => i.id !== id);
2038
+ const ids = this.selectedItems.map(i => i.id);
2039
+ this.mrdChange.emit({ name: this.name, value: this.multiple ? ids : null });
2040
+ };
2041
+ this.handleDropdownChange = (e) => {
2042
+ const val = e.target.value;
2043
+ if (this.required && !validateRequired(val)) {
2044
+ this.error = t('required', this.locale);
2045
+ }
2046
+ else {
2047
+ this.error = '';
2048
+ }
2049
+ this.mrdChange.emit({ name: this.name, value: val });
2050
+ };
2051
+ this.handleBlur = () => {
2052
+ var _a, _b;
2053
+ setTimeout(() => {
2054
+ this.showResults = false;
2055
+ this.highlightedIndex = -1;
2056
+ }, 200);
2057
+ const val = this.multiple ? this.selectedItems.map(i => i.id) : ((_b = (_a = this.selectedItems[0]) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : null);
2058
+ this.mrdBlur.emit({ name: this.name, value: val });
2059
+ };
2060
+ }
2061
+ async setAllRecords(records) {
2062
+ this.allRecords = records;
2063
+ }
2064
+ getValueHref() {
2065
+ var _a, _b, _c;
2066
+ const v = Array.isArray(this.value) ? ((_a = this.value[0]) !== null && _a !== void 0 ? _a : '') : ((_b = this.value) !== null && _b !== void 0 ? _b : '');
2067
+ if (!v)
2068
+ return '';
2069
+ if (typeof v === 'object')
2070
+ return (_c = v.id) !== null && _c !== void 0 ? _c : '';
2071
+ return v;
2072
+ }
2073
+ allRecordsChanged() {
2074
+ if (this.editBehavior !== ClientLayoutItemRelationEditBehavior.DROPDOWN)
2075
+ return;
2076
+ const current = this.getValueHref();
2077
+ if (!current)
2078
+ return;
2079
+ // Defer past Stencil's async render cycle: options must exist in the DOM before
2080
+ // select.value can be set. setAttribute('selected') alone is ignored by browsers
2081
+ // when the select already has an established value.
2082
+ setTimeout(() => {
2083
+ var _a;
2084
+ const select = (_a = this.el) === null || _a === void 0 ? void 0 : _a.querySelector('select');
2085
+ if (select)
2086
+ select.value = current;
2087
+ }, 0);
2088
+ }
2089
+ async setSearchResults(results) {
2090
+ this.searchResults = results;
2091
+ this.isLoading = false;
2092
+ this.showResults = true;
2093
+ this.highlightedIndex = -1;
2094
+ }
2095
+ async setLoading(loading) {
2096
+ this.isLoading = loading;
2097
+ }
2098
+ componentWillLoad() {
2099
+ var _a;
2100
+ // Pre-fill selectedItems when value is passed as { id, label } objects
2101
+ // (e.g. when editing an existing record fetched from the API).
2102
+ if (this.value) {
2103
+ if (Array.isArray(this.value)) {
2104
+ if (this.value.length > 0 && typeof this.value[0] === 'object') {
2105
+ this.selectedItems = this.value;
2106
+ this.searchQuery = '';
2107
+ }
2108
+ }
2109
+ else if (typeof this.value === 'object') {
2110
+ this.selectedItems = [this.value];
2111
+ this.searchQuery = (_a = this.value.label) !== null && _a !== void 0 ? _a : '';
2112
+ }
2113
+ }
2114
+ }
2115
+ componentDidLoad() {
2116
+ // Only emit when there is no commonRelation dependency — the form orchestrates those.
2117
+ if (this.editBehavior === ClientLayoutItemRelationEditBehavior.DROPDOWN && !this.commonRelation) {
2118
+ // Defer to next tick so parent event listeners are registered after DOM patching
2119
+ setTimeout(() => {
2120
+ this.mrdFetchAll.emit({
2121
+ name: this.name,
2122
+ relatedClass: this.relatedClass,
2123
+ mostSignificantClass: this.mostSignificantClass || undefined,
2124
+ });
2125
+ }, 0);
2126
+ }
2127
+ }
2128
+ render() {
2129
+ var _a, _b;
2130
+ const hasError = !!this.error;
2131
+ if (this.editBehavior === ClientLayoutItemRelationEditBehavior.DROPDOWN) {
2132
+ const currentValue = this.getValueHref();
2133
+ return (h(Host, null, h("div", { class: "mrd-relation-field" }, this.label && (h("label", { class: `mrd-relation-field__label${this.required ? ' mrd-relation-field__label--required' : ''}` }, this.label)), h("select", { class: `mrd-relation-field__select${hasError ? ' mrd-relation-field__select--error' : ''}`, name: this.name, required: this.required, disabled: this.disabled, onChange: this.handleDropdownChange }, h("option", { value: "" }, t('select_placeholder', this.locale)), this.allRecords.map(record => (h("option", { key: record.id, value: record.id, selected: record.id === currentValue }, record.label)))), hasError && h("span", { class: "mrd-relation-field__error" }, this.error))));
2134
+ }
2135
+ if (this.displayType === ClientLayoutItemRelationDisplayType.DROPDOWN) {
2136
+ const currentValue = Array.isArray(this.value) ? ((_a = this.value[0]) !== null && _a !== void 0 ? _a : '') : ((_b = this.value) !== null && _b !== void 0 ? _b : '');
2137
+ return (h(Host, null, h("div", { class: "mrd-relation-field" }, this.label && (h("label", { class: `mrd-relation-field__label${this.required ? ' mrd-relation-field__label--required' : ''}` }, this.label)), h("select", { class: `mrd-relation-field__select${hasError ? ' mrd-relation-field__select--error' : ''}`, name: this.name, required: this.required, disabled: this.disabled, onChange: this.handleDropdownChange }, h("option", { value: "" }, t('select_placeholder', this.locale)), this.dropdownValues.map(dv => (h("option", { key: dv.key, value: dv.key, selected: dv.key === currentValue }, dv.label)))), hasError && h("span", { class: "mrd-relation-field__error" }, this.error))));
2138
+ }
2139
+ // SEARCH mode
2140
+ const labelEl = this.label && (h("label", { class: `mrd-relation-field__label${this.required ? ' mrd-relation-field__label--required' : ''}` }, this.label));
2141
+ // Single selection: show selected value as a badge, hide the search input
2142
+ if (!this.multiple && this.selectedItems.length > 0) {
2143
+ return (h(Host, null, h("div", { class: "mrd-relation-field" }, labelEl, h("div", { class: `mrd-relation-field__selected-value${hasError ? ' mrd-relation-field__selected-value--error' : ''}` }, h("span", { class: "mrd-relation-field__selected-name" }, this.selectedItems[0].label), h("button", { type: "button", class: "mrd-relation-field__selected-clear", onClick: this.clearSelection, "aria-label": t('remove', this.locale) }, "\u2715")), hasError && h("span", { class: "mrd-relation-field__error" }, this.error))));
2144
+ }
2145
+ return (h(Host, null, h("div", { class: "mrd-relation-field" }, labelEl, this.multiple && this.selectedItems.length > 0 && (h("div", { class: "mrd-relation-field__tags" }, this.selectedItems.map(item => (h("span", { key: item.id, class: "mrd-relation-field__tag" }, item.label, h("button", { type: "button", class: "mrd-relation-field__tag-remove", onClick: () => this.handleRemoveSelected(item.id), "aria-label": t('remove', this.locale) }, "\u2715")))))), h("div", { class: "mrd-relation-field__search-wrapper" }, h("input", { class: `mrd-relation-field__search${hasError ? ' mrd-relation-field__search--error' : ''}`, type: "text", value: this.searchQuery, placeholder: t('search_placeholder', this.locale), disabled: this.disabled, onInput: this.handleSearchInput, onKeyDown: this.handleKeyDown, onBlur: this.handleBlur }), this.isLoading && (h("span", { class: "mrd-relation-field__spinner", "aria-label": t('loading', this.locale) }))), this.showResults && (h("div", { class: "mrd-relation-field__results" }, this.searchResults.length === 0 && !this.isLoading ? (h("div", { class: "mrd-relation-field__no-results" }, t('no_results', this.locale))) : (this.searchResults.map((result, i) => (h("div", { key: result.id, class: `mrd-relation-field__result-item${i === this.highlightedIndex ? ' mrd-relation-field__result-item--highlighted' : ''}`, onMouseDown: () => this.handleResultSelect(result) }, h("span", { class: "mrd-relation-field__result-label" }, result.label), result.description && (h("span", { class: "mrd-relation-field__result-desc" }, result.description)))))))), hasError && h("span", { class: "mrd-relation-field__error" }, this.error))));
2146
+ }
2147
+ get el() { return getElement(this); }
2148
+ static get watchers() { return {
2149
+ "allRecords": [{
2150
+ "allRecordsChanged": 0
2151
+ }]
2152
+ }; }
2153
+ };
2154
+ MrdRelationField.style = mrdRelationFieldScss();
2155
+
2156
+ const mrdTableScss = () => `.sc-mrd-table-h{display:block;width:100%}.mrd-table__scroll.sc-mrd-table{overflow-y:auto;overflow-x:auto;border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);overflow-anchor:none}.mrd-table.sc-mrd-table{overflow-x:auto}.mrd-table__table.sc-mrd-table{width:auto;min-width:100%;border-collapse:collapse;font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-900)}.mrd-table__scroll.sc-mrd-table .mrd-table__table.sc-mrd-table{min-width:max-content}.mrd-table__header.sc-mrd-table{position:sticky;top:0;z-index:1;background:var(--mrd-color-white);text-align:left;padding:var(--mrd-space-2) var(--mrd-space-4);border-bottom:2px solid var(--mrd-border-color);color:var(--mrd-color-neutral-600);font-weight:var(--mrd-font-weight-medium);white-space:nowrap;font-size:var(--mrd-font-size-xs);text-transform:uppercase;letter-spacing:0.04em}.mrd-table__header--sortable.sc-mrd-table{cursor:pointer;user-select:none}.mrd-table__header--sortable.sc-mrd-table:hover{background:var(--mrd-color-neutral-50);color:var(--mrd-color-neutral-800)}.mrd-table__header--sorted-asc.sc-mrd-table,.mrd-table__header--sorted-desc.sc-mrd-table{color:var(--mrd-color-primary);border-bottom-color:var(--mrd-color-primary)}.mrd-table__header-label.sc-mrd-table{margin-right:var(--mrd-space-1)}.mrd-table__sort-icon.sc-mrd-table{font-size:0.85rem;opacity:0.4;vertical-align:middle}.mrd-table__header--sorted-asc.sc-mrd-table .mrd-table__sort-icon.sc-mrd-table,.mrd-table__header--sorted-desc.sc-mrd-table .mrd-table__sort-icon.sc-mrd-table{opacity:1;color:var(--mrd-color-primary)}.mrd-table__filter-icon.sc-mrd-table{display:inline-flex;align-items:center;vertical-align:middle;margin-left:var(--mrd-space-1);color:var(--mrd-color-primary)}.mrd-table__row.sc-mrd-table{border-bottom:1px solid var(--mrd-border-color)}.mrd-table__row.sc-mrd-table:hover{background:var(--mrd-color-neutral-200) !important}.mrd-table__row--clickable.sc-mrd-table{cursor:pointer}.mrd-table__spacer.sc-mrd-table{border:none}.mrd-table__spacer.sc-mrd-table td.sc-mrd-table{padding:0;border:none}.mrd-table__cell.sc-mrd-table{padding:var(--mrd-space-2) var(--mrd-space-4);vertical-align:top;white-space:nowrap}.mrd-table__cell--numeric.sc-mrd-table{text-align:right;font-variant-numeric:tabular-nums}.mrd-table__row--loading.sc-mrd-table{background:transparent}.mrd-table__cell--placeholder.sc-mrd-table{padding:var(--mrd-space-2) var(--mrd-space-4);border-bottom:1px solid var(--mrd-border-color)}.mrd-table__placeholder-bar.sc-mrd-table{display:block;height:0.75rem;width:55%;border-radius:var(--mrd-border-radius-sm);background:linear-gradient( 90deg, var(--mrd-color-neutral-200) 25%, var(--mrd-color-neutral-100) 50%, var(--mrd-color-neutral-200) 75% );background-size:200% 100%;animation:mrd-shimmer 1.4s ease infinite}@keyframes mrd-shimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}.mrd-table__toolbar.sc-mrd-table{display:flex;align-items:center;justify-content:space-between;padding-bottom:var(--mrd-space-2)}.mrd-table__toolbar-left.sc-mrd-table,.mrd-table__toolbar-right.sc-mrd-table{display:flex;gap:var(--mrd-space-2);align-items:center}.mrd-table__toolbar-center.sc-mrd-table{flex:1;display:flex;justify-content:center;align-items:center;gap:var(--mrd-space-1)}.mrd-table__view-select.sc-mrd-table{font-size:var(--mrd-font-size-sm);font-weight:600;color:var(--mrd-color-neutral-800);font-family:var(--mrd-font-family);background:none;border:none;outline:none;cursor:pointer;padding:0;max-width:220px}.mrd-table__action.sc-mrd-table{position:relative;display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;padding:0;background:transparent;border:1px solid transparent;border-radius:var(--mrd-border-radius);cursor:pointer;color:var(--mrd-color-neutral-400);transition:background-color 0.15s, border-color 0.15s, color 0.15s}.mrd-table__action.sc-mrd-table:hover{background-color:var(--mrd-color-neutral-100);border-color:var(--mrd-color-neutral-300);color:var(--mrd-color-neutral-700)}.mrd-table__action.sc-mrd-table:disabled{opacity:0.4;cursor:not-allowed}.mrd-table__action--primary.sc-mrd-table{color:var(--mrd-color-neutral-500)}.mrd-table__action--primary.sc-mrd-table:hover{background:var(--mrd-color-primary);border-color:var(--mrd-color-primary);color:var(--mrd-color-white)}.mrd-table__action--danger.sc-mrd-table{color:var(--mrd-color-error)}.mrd-table__action--danger.sc-mrd-table:hover{background-color:var(--mrd-color-error-light, #fef2f2);border-color:var(--mrd-color-error)}.mrd-table__action-icon.sc-mrd-table{width:1.25rem;height:1.25rem;pointer-events:none;fill:currentColor}.mrd-table__action-tooltip.sc-mrd-table{display:none;position:absolute;bottom:calc(100% + 6px);right:0;padding:var(--mrd-space-1) var(--mrd-space-2);font-size:var(--mrd-font-size-xs);white-space:nowrap;background:var(--mrd-color-tooltip, #fffce1);color:var(--mrd-color-neutral-900);border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius-sm, var(--mrd-border-radius));pointer-events:none;z-index:10}.mrd-table__action.sc-mrd-table:hover .mrd-table__action-tooltip.sc-mrd-table{display:block}.mrd-table__filter-toggle--active.sc-mrd-table{background:var(--mrd-color-primary);border-color:var(--mrd-color-primary);color:var(--mrd-color-white)}.mrd-table__filter-toggle--active.sc-mrd-table:hover{background:var(--mrd-color-primary-dark, var(--mrd-color-primary));border-color:var(--mrd-color-primary-dark, var(--mrd-color-primary));color:var(--mrd-color-white)}.mrd-table__filter-badge.sc-mrd-table{position:absolute;top:-6px;right:-6px;min-width:1.25rem;height:1.25rem;padding:0 3px;background:var(--mrd-color-error, #e53e3e);color:var(--mrd-color-white);border-radius:9999px;font-size:0.65rem;font-weight:var(--mrd-font-weight-medium);line-height:1.25rem;text-align:center;pointer-events:none}.mrd-table__header--filtered.sc-mrd-table{color:var(--mrd-color-primary);border-bottom-color:var(--mrd-color-primary)}.mrd-table__filter-popup.sc-mrd-table{position:fixed;width:280px;background:var(--mrd-color-white);border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);box-shadow:var(--mrd-shadow-md, 0 4px 12px rgba(0,0,0,.12));z-index:var(--mrd-z-dropdown, 200);font-size:var(--mrd-font-size-sm)}.mrd-table__filter-popup-header.sc-mrd-table{display:flex;align-items:center;justify-content:space-between;padding:var(--mrd-space-2) var(--mrd-space-3);border-bottom:1px solid var(--mrd-border-color)}.mrd-table__filter-popup-title.sc-mrd-table{font-weight:var(--mrd-font-weight-medium);color:var(--mrd-color-neutral-800);font-size:var(--mrd-font-size-sm)}.mrd-table__filter-close.sc-mrd-table{background:transparent;border:none;cursor:pointer;color:var(--mrd-color-neutral-500);font-size:0.9rem;padding:2px 4px;border-radius:3px;line-height:1}.mrd-table__filter-close.sc-mrd-table:hover{background:var(--mrd-color-neutral-100);color:var(--mrd-color-neutral-800)}.mrd-table__filter-section.sc-mrd-table{padding:var(--mrd-space-2) var(--mrd-space-3)}.mrd-table__filter-section-label.sc-mrd-table{font-size:var(--mrd-font-size-xs);font-weight:var(--mrd-font-weight-medium);text-transform:uppercase;letter-spacing:0.04em;color:var(--mrd-color-neutral-500);margin-bottom:var(--mrd-space-2)}.mrd-table__filter-sort-buttons.sc-mrd-table{display:flex;gap:var(--mrd-space-2)}.mrd-table__filter-sort-btn.sc-mrd-table{flex:1;padding:var(--mrd-space-1) var(--mrd-space-2);background:transparent;border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);cursor:pointer;font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-700)}.mrd-table__filter-sort-btn.sc-mrd-table:hover{background:var(--mrd-color-neutral-100)}.mrd-table__filter-sort-btn--active.sc-mrd-table{background:var(--mrd-color-primary);border-color:var(--mrd-color-primary);color:var(--mrd-color-white)}.mrd-table__filter-divider.sc-mrd-table{height:1px;background:var(--mrd-border-color);margin:0}.mrd-table__filter-editor.sc-mrd-table{display:flex;flex-direction:column;gap:var(--mrd-space-2)}.mrd-table__filter-select.sc-mrd-table,.mrd-table__filter-input.sc-mrd-table{width:100%;padding:var(--mrd-space-1) var(--mrd-space-2);border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-900);background:var(--mrd-color-white);box-sizing:border-box}.mrd-table__filter-select.sc-mrd-table:focus,.mrd-table__filter-input.sc-mrd-table:focus{outline:none;border-color:var(--mrd-color-primary);box-shadow:0 0 0 2px rgba(0,0,0,.06)}.mrd-table__filter-range.sc-mrd-table{display:flex;align-items:center;gap:var(--mrd-space-1)}.mrd-table__filter-range.sc-mrd-table .mrd-table__filter-input.sc-mrd-table{flex:1;min-width:0}.mrd-table__filter-range-sep.sc-mrd-table{color:var(--mrd-color-neutral-400);flex-shrink:0}.mrd-table__filter-range--stacked.sc-mrd-table{flex-direction:column;align-items:stretch;gap:var(--mrd-space-2)}.mrd-table__filter-range-label.sc-mrd-table{font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-500);margin-bottom:2px}.mrd-table__filter-radio-group.sc-mrd-table{display:flex;flex-direction:column;gap:var(--mrd-space-1)}.mrd-table__filter-radio-group--inline.sc-mrd-table{flex-direction:row;gap:var(--mrd-space-3)}.mrd-table__filter-radio-label.sc-mrd-table{display:flex;align-items:center;gap:var(--mrd-space-1);cursor:pointer;font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-800)}.mrd-table__filter-list.sc-mrd-table{display:flex;flex-direction:column;gap:var(--mrd-space-1);max-height:180px;overflow-y:auto}.mrd-table__filter-list-controls.sc-mrd-table{display:flex;gap:var(--mrd-space-2);margin-bottom:var(--mrd-space-1)}.mrd-table__filter-list-btn.sc-mrd-table{font-size:var(--mrd-font-size-xs);color:var(--mrd-color-primary);background:transparent;border:none;cursor:pointer;padding:0;text-decoration:underline}.mrd-table__filter-checkbox-label.sc-mrd-table{display:flex;align-items:center;gap:var(--mrd-space-1);cursor:pointer;font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-800)}.mrd-table__filter-no-support.sc-mrd-table{font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-500);margin:0;font-style:italic}.mrd-table__filter-popup-footer.sc-mrd-table{display:flex;justify-content:flex-end;gap:var(--mrd-space-2);padding:var(--mrd-space-2) var(--mrd-space-3);border-top:1px solid var(--mrd-border-color)}.mrd-table__filter-btn.sc-mrd-table{padding:var(--mrd-space-1) var(--mrd-space-3);border-radius:var(--mrd-border-radius);border:1px solid var(--mrd-border-color);font-size:var(--mrd-font-size-sm);cursor:pointer}.mrd-table__filter-btn--clear.sc-mrd-table{background:transparent;color:var(--mrd-color-neutral-600)}.mrd-table__filter-btn--clear.sc-mrd-table:hover{background:var(--mrd-color-neutral-100)}.mrd-table__filter-btn--apply.sc-mrd-table{background:var(--mrd-color-primary);border-color:var(--mrd-color-primary);color:var(--mrd-color-white)}.mrd-table__filter-btn--apply.sc-mrd-table:hover{background:var(--mrd-color-primary-dark, var(--mrd-color-primary));border-color:var(--mrd-color-primary-dark, var(--mrd-color-primary))}.mrd-table__totals-row.sc-mrd-table{border-top:2px solid var(--mrd-border-color)}.mrd-table__totals-cell.sc-mrd-table{position:sticky;bottom:0;z-index:2;padding:var(--mrd-space-2) var(--mrd-space-4);background:var(--mrd-color-white);font-weight:var(--mrd-font-weight-medium);font-variant-numeric:tabular-nums;white-space:nowrap;border-top:2px solid var(--mrd-border-color)}.mrd-table__totals-cell--numeric.sc-mrd-table{text-align:right}.mrd-table__footer.sc-mrd-table{padding:var(--mrd-space-1) var(--mrd-space-2);font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-500);text-align:right}.mrd-table__empty.sc-mrd-table{padding:var(--mrd-space-4) var(--mrd-space-3);color:var(--mrd-color-neutral-500);font-size:var(--mrd-font-size-sm);text-align:center;margin:0}.mrd-table__file-btn.sc-mrd-table{display:inline-flex;align-items:center;gap:var(--mrd-space-1);background:none;border:none;padding:0;cursor:pointer;color:var(--mrd-color-primary);font-size:var(--mrd-font-size-sm);font-family:inherit;max-width:100%;overflow:hidden}.mrd-table__file-btn.sc-mrd-table:hover{text-decoration:underline;color:var(--mrd-color-primary-dark)}.mrd-table__file-icon.sc-mrd-table{flex-shrink:0;width:1rem;height:1rem}.mrd-table__textblock-btn.sc-mrd-table{display:inline;background:none;border:none;padding:0 0 0 var(--mrd-space-1);cursor:pointer;color:var(--mrd-color-primary);font-size:var(--mrd-font-size-sm);font-family:inherit;line-height:inherit;vertical-align:middle}.mrd-table__textblock-btn.sc-mrd-table:hover{color:var(--mrd-color-primary-dark)}.mrd-table__modal-backdrop.sc-mrd-table{position:fixed;inset:0;background:rgba(0, 0, 0, 0.4);z-index:var(--mrd-z-modal, 300);display:flex;align-items:center;justify-content:center}.mrd-table__modal.sc-mrd-table{background:#fff;border-radius:var(--mrd-radius-md, 0.5rem);padding:var(--mrd-space-6);max-width:min(600px, 90vw);max-height:70vh;overflow-y:auto;position:relative;box-shadow:var(--mrd-shadow-lg)}.mrd-table__modal-close.sc-mrd-table{position:absolute;top:var(--mrd-space-3);right:var(--mrd-space-3);background:none;border:none;cursor:pointer;font-size:1.25rem;line-height:1;color:var(--mrd-color-text-muted, #6b7280);padding:0}.mrd-table__modal-close.sc-mrd-table:hover{color:var(--mrd-color-text, #111827)}.mrd-table__modal-text.sc-mrd-table{margin:0;padding-right:var(--mrd-space-6);white-space:pre-wrap;word-break:break-word;font-size:var(--mrd-font-size-sm);line-height:1.6}.mrd-table__json-preview.sc-mrd-table{font-family:var(--mrd-font-family-mono);font-size:var(--mrd-font-size-xs);overflow:hidden;white-space:nowrap;text-overflow:ellipsis;display:inline-block;max-width:calc(100% - 1.5rem);vertical-align:middle}.mrd-table__modal-json.sc-mrd-table{margin:0;padding-right:var(--mrd-space-6);font-family:var(--mrd-font-family-mono);font-size:var(--mrd-font-size-xs);white-space:pre-wrap;word-break:break-word;line-height:1.6;background:none;border:none}`;
2157
+
2158
+ const BUFFER = 10;
2159
+ /** Wacht deze tijd (ms) na het laatste scroll-event voordat pagina's worden
2160
+ * aangevraagd. Pagina's die de gebruiker snel voorbij scrollt worden zo geskipt. */
2161
+ const REQUEST_DEBOUNCE_MS = 150;
2162
+ /** Breedte van de filterpopup in px — voor overflow-correctie. */
2163
+ const POPUP_WIDTH = 280;
2164
+ const TEXT_TYPES = new Set(['TEXT', 'TEXTBLOCK', 'EMAIL', 'HYPERLINK']);
2165
+ const NUMERIC_TYPES = new Set(['INTEGER', 'DECIMAL', 'PERCENTAGE', 'CURRENCY']);
2166
+ const DATE_TYPES = new Set(['DATE', 'DATETIME', 'TIME']);
2167
+ const NO_FILTER_TYPES = new Set(['FILE', 'IMAGE']);
2168
+ /** Column types that cannot be sorted or filtered (not stored in PostgreSQL). */
2169
+ const NON_INTERACTIVE_TYPES = new Set(['LONGTEXT', 'JSON']);
2170
+ const MrdTable = class {
2171
+ constructor(hostRef) {
2172
+ registerInstance(this, hostRef);
2173
+ this.mrdLoadPage = createEvent(this, "mrdLoadPage");
2174
+ this.mrdRowClick = createEvent(this, "mrdRowClick");
2175
+ this.mrdAction = createEvent(this, "mrdAction");
2176
+ this.mrdFilter = createEvent(this, "mrdFilter");
2177
+ this.mrdDownload = createEvent(this, "mrdDownload");
2178
+ this.mrdSwitchView = createEvent(this, "mrdSwitchView");
2179
+ this.mrdLoadAggregations = createEvent(this, "mrdLoadAggregations");
2180
+ // ── Non-state internals ────────────────────────────────────────────────────
2181
+ this.pendingPages = new Set();
2182
+ this.debounceTimer = null;
2183
+ this.outsideClickHandler = null;
2184
+ this.keydownHandler = null;
2185
+ // ── Props ──────────────────────────────────────────────────────────────────
2186
+ this.columns = [];
2187
+ /** Direct rows (non-paginated mode, used when totalElements === 0). */
2188
+ this.rows = [];
2189
+ this.locale = navigator.language;
2190
+ /** Total number of records across all pages. 0 = non-paginated mode. */
2191
+ this.totalElements = 0;
2192
+ /** Records per page (must match the API page size). */
2193
+ this.pageSize = 20;
2194
+ /** Row height in px — used for spacer and scroll-position maths. */
2195
+ this.rowHeight = 36;
2196
+ /** Height of the scroll container in px. */
2197
+ this.tableHeight = 500;
2198
+ /** Initial sort applied on load, e.g. "timestamp,desc" or "name".
2199
+ * Parsed by init() into sortField + sortDir. */
2200
+ this.defaultSort = '';
2201
+ /** Toolbar action buttons rendered above the table. */
2202
+ this.actions = [];
2203
+ /** Display label of the current view — shown in the toolbar center as a view picker trigger. */
2204
+ this.viewLabel = '';
2205
+ /** Alternative views available for this table; renders a dropdown when non-empty. */
2206
+ this.alternativeViews = [];
2207
+ // ── Internal state ─────────────────────────────────────────────────────────
2208
+ this.loadedPages = new Map();
2209
+ this.requestedPages = new Set();
2210
+ this.renderStart = 0;
2211
+ this.renderEnd = 0;
2212
+ this.colWidths = [];
2213
+ this.sortField = '';
2214
+ this.sortDir = 'asc';
2215
+ /** Whether the filter UI is visible on column headers. */
2216
+ this.filterMode = false;
2217
+ /** Active filters keyed by field name. */
2218
+ this.activeFilters = new Map();
2219
+ /** Field name of the currently open filter popup (null = closed). */
2220
+ this.openFilterCol = null;
2221
+ /** Filter state being edited in the open popup. */
2222
+ this.pendingFilter = null;
2223
+ /** Viewport-relative position for the filter popup. */
2224
+ this.popupPos = { top: 0, left: 0 };
2225
+ /** Current scroll offset of the scroll container — drives pagination footer. */
2226
+ this.scrollTop = 0;
2227
+ /** Full text shown in the TEXTBLOCK expand modal (null = closed). */
2228
+ this.textblockModal = null;
2229
+ /** Syntax-highlighted JSON HTML shown in the JSON expand modal (null = closed). */
2230
+ this.jsonModal = null;
2231
+ /** Aggregation totals received from the host via setAggregations(). Null = not yet loaded. */
2232
+ this.aggregations = null;
2233
+ this.handleScroll = (e) => {
2234
+ const scroller = e.currentTarget;
2235
+ const scrollTop = scroller.scrollTop;
2236
+ const total = this.totalElements;
2237
+ const visStart = Math.floor(scrollTop / this.rowHeight);
2238
+ const visEnd = Math.min(visStart + this.visibleCount(), total - 1);
2239
+ this.scrollTop = scrollTop;
2240
+ this.renderStart = Math.max(0, visStart - BUFFER);
2241
+ this.renderEnd = Math.min(total - 1, visEnd + BUFFER);
2242
+ this.requestPagesForWindow(this.renderStart, this.renderEnd);
2243
+ };
2244
+ }
2245
+ // ── Prop watchers ─────────────────────────────────────────────────────────
2246
+ /** Clamp renderEnd when totalElements shrinks (e.g. after a filter is applied). */
2247
+ totalElementsChanged(newVal) {
2248
+ this.renderEnd = Math.min(this.renderEnd, Math.max(0, newVal - 1));
2249
+ }
2250
+ // ── Public API ─────────────────────────────────────────────────────────────
2251
+ /**
2252
+ * Initialise (or reset) the virtual scroll.
2253
+ * Call after setting all props and registering the mrdLoadPage listener,
2254
+ * but before calling setPage(0, rows).
2255
+ */
2256
+ async init() {
2257
+ var _a;
2258
+ if (this.debounceTimer !== null) {
2259
+ clearTimeout(this.debounceTimer);
2260
+ this.debounceTimer = null;
2261
+ }
2262
+ this.pendingPages.clear();
2263
+ this.loadedPages = new Map();
2264
+ this.requestedPages = new Set();
2265
+ this.colWidths = [];
2266
+ if (this.defaultSort) {
2267
+ const parts = this.defaultSort.split(',');
2268
+ this.sortField = parts[0].trim();
2269
+ this.sortDir = ((_a = parts[1]) === null || _a === void 0 ? void 0 : _a.trim()) === 'desc' ? 'desc' : 'asc';
2270
+ }
2271
+ else {
2272
+ this.sortField = '';
2273
+ this.sortDir = 'asc';
2274
+ }
2275
+ this.scrollTop = 0;
2276
+ this.renderStart = 0;
2277
+ // No BUFFER on init — only request what fits the visible area (page 0).
2278
+ // BUFFER is applied during scroll to pre-fetch the next page proactively.
2279
+ this.renderEnd = Math.max(0, Math.min(this.visibleCount() - 1, this.totalElements - 1));
2280
+ const scroller = this.el.querySelector('.mrd-table__scroll');
2281
+ if (scroller)
2282
+ scroller.scrollTop = 0;
2283
+ this.aggregations = null;
2284
+ this.emitLoadAggregations();
2285
+ }
2286
+ /**
2287
+ * Inject the rows for a given page (0-based).
2288
+ * Creates a new Map reference so Stencil detects the state change.
2289
+ *
2290
+ * When the page contains fewer rows than pageSize it is the last page.
2291
+ * renderEnd is clamped immediately so no loading-placeholder rows appear
2292
+ * beyond the actual data — without requiring the host to update totalElements.
2293
+ */
2294
+ async setPage(pageNumber, rows) {
2295
+ if (rows.length < this.pageSize) {
2296
+ // lastRowIdx is -1 when the page is empty; clamp renderEnd to -1 so the
2297
+ // render loop does not execute and no shimmer rows appear.
2298
+ const lastRowIdx = pageNumber * this.pageSize + rows.length - 1;
2299
+ this.renderEnd = Math.min(this.renderEnd, lastRowIdx);
2300
+ }
2301
+ const next = new Map(this.loadedPages);
2302
+ next.set(pageNumber, rows);
2303
+ this.loadedPages = next;
2304
+ }
2305
+ /** Inject aggregation totals returned by the /aggregations endpoint. */
2306
+ async setAggregations(data) {
2307
+ this.aggregations = data;
2308
+ }
2309
+ // ── Lifecycle ──────────────────────────────────────────────────────────────
2310
+ disconnectedCallback() {
2311
+ if (this.outsideClickHandler) {
2312
+ document.removeEventListener('click', this.outsideClickHandler);
2313
+ this.outsideClickHandler = null;
2314
+ }
2315
+ if (this.keydownHandler) {
2316
+ document.removeEventListener('keydown', this.keydownHandler);
2317
+ this.keydownHandler = null;
2318
+ }
2319
+ }
2320
+ componentDidRender() {
2321
+ if (this.colWidths.length === 0 && this.loadedPages.size > 0 && this.totalElements > 0) {
2322
+ const ths = this.el.querySelectorAll('.mrd-table__header');
2323
+ if (ths.length > 0) {
2324
+ this.colWidths = Array.from(ths).map(th => th.offsetWidth);
2325
+ }
2326
+ }
2327
+ }
2328
+ // ── Paging / scroll helpers ────────────────────────────────────────────────
2329
+ visibleCount() {
2330
+ return Math.ceil(this.tableHeight / this.rowHeight);
2331
+ }
2332
+ sortParam() {
2333
+ if (!this.sortField)
2334
+ return '';
2335
+ return this.sortDir === 'desc' ? `${this.sortField},desc` : this.sortField;
2336
+ }
2337
+ colName(col) {
2338
+ var _a, _b, _c, _d;
2339
+ return (_d = (_b = (_a = col.field) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : (_c = col.relation) === null || _c === void 0 ? void 0 : _c.name) !== null && _d !== void 0 ? _d : '';
2340
+ }
2341
+ colDataType(col) {
2342
+ var _a, _b;
2343
+ if (col.type === 'RELATION')
2344
+ return 'RELATION';
2345
+ return (_b = (_a = col.field) === null || _a === void 0 ? void 0 : _a.dataType) !== null && _b !== void 0 ? _b : 'TEXT';
2346
+ }
2347
+ // ── Aggregation helpers ────────────────────────────────────────────────────
2348
+ buildAggregationParams() {
2349
+ var _a;
2350
+ const groups = { sum: [], avg: [], count: [] };
2351
+ for (const col of this.columns) {
2352
+ if (col.type !== 'FIELD' || !((_a = col.field) === null || _a === void 0 ? void 0 : _a.aggregate))
2353
+ continue;
2354
+ const fn = col.field.aggregate.toLowerCase();
2355
+ if (fn in groups)
2356
+ groups[fn].push(col.field.name);
2357
+ }
2358
+ const params = {};
2359
+ if (groups.sum.length)
2360
+ params.sum = groups.sum;
2361
+ if (groups.avg.length)
2362
+ params.avg = groups.avg;
2363
+ if (groups.count.length)
2364
+ params.count = groups.count;
2365
+ return Object.keys(params).length > 0 ? params : null;
2366
+ }
2367
+ emitLoadAggregations() {
2368
+ const params = this.buildAggregationParams();
2369
+ if (params)
2370
+ this.mrdLoadAggregations.emit(params);
2371
+ }
2372
+ renderAggregationValue(col) {
2373
+ var _a, _b;
2374
+ if (col.type !== 'FIELD' || !((_a = col.field) === null || _a === void 0 ? void 0 : _a.aggregate) || !this.aggregations)
2375
+ return '';
2376
+ const fn = col.field.aggregate.toLowerCase();
2377
+ const val = (_b = this.aggregations[fn]) === null || _b === void 0 ? void 0 : _b[col.field.name];
2378
+ if (val == null)
2379
+ return '';
2380
+ const dt = col.field.dataType;
2381
+ if (dt === 'INTEGER')
2382
+ return formatNumber(val, this.locale, { maximumFractionDigits: 0 });
2383
+ if (dt === 'PERCENTAGE')
2384
+ return formatPercentage(val, this.locale);
2385
+ if (dt === 'CURRENCY' && col.field.currencyCode)
2386
+ return formatCurrency(val, col.field.currencyCode, this.locale);
2387
+ return formatNumber(val, this.locale);
2388
+ }
2389
+ // ── Reset pagination ───────────────────────────────────────────────────────
2390
+ /** Reset pagination state and scroll to top (used after sort or filter change). */
2391
+ resetPages() {
2392
+ if (this.debounceTimer !== null) {
2393
+ clearTimeout(this.debounceTimer);
2394
+ this.debounceTimer = null;
2395
+ }
2396
+ this.pendingPages.clear();
2397
+ this.loadedPages = new Map();
2398
+ this.requestedPages = new Set();
2399
+ this.colWidths = [];
2400
+ this.scrollTop = 0;
2401
+ this.renderStart = 0;
2402
+ // No BUFFER here — totalElements may be stale after a filter change.
2403
+ // Only request what is visible; BUFFER kicks in during scroll as usual.
2404
+ this.renderEnd = Math.max(0, Math.min(this.visibleCount() - 1, this.totalElements - 1));
2405
+ const scroller = this.el.querySelector('.mrd-table__scroll');
2406
+ if (scroller)
2407
+ scroller.scrollTop = 0;
2408
+ }
2409
+ handleSortClick(col) {
2410
+ const name = this.colName(col);
2411
+ if (this.sortField === name) {
2412
+ this.sortDir = this.sortDir === 'asc' ? 'desc' : 'asc';
2413
+ }
2414
+ else {
2415
+ this.sortField = name;
2416
+ this.sortDir = 'asc';
2417
+ }
2418
+ this.resetPages();
2419
+ this.emitPagesForWindow(this.renderStart, this.renderEnd);
2420
+ }
2421
+ applySort(col, dir) {
2422
+ this.sortField = this.colName(col);
2423
+ this.sortDir = dir;
2424
+ this.resetPages();
2425
+ this.emitPagesForWindow(this.renderStart, this.renderEnd);
2426
+ }
2427
+ emitPagesForWindow(start, end) {
2428
+ const firstPage = Math.floor(start / this.pageSize);
2429
+ const lastPage = Math.floor(end / this.pageSize);
2430
+ const next = new Set(this.requestedPages);
2431
+ let changed = false;
2432
+ for (let p = firstPage; p <= lastPage; p++) {
2433
+ if (!this.loadedPages.has(p) && !next.has(p)) {
2434
+ next.add(p);
2435
+ this.mrdLoadPage.emit({ page: p, sort: this.sortParam() });
2436
+ changed = true;
2437
+ }
2438
+ }
2439
+ if (changed)
2440
+ this.requestedPages = next;
2441
+ }
2442
+ getRow(i) {
2443
+ var _a;
2444
+ const page = this.loadedPages.get(Math.floor(i / this.pageSize));
2445
+ return (_a = page === null || page === void 0 ? void 0 : page[i % this.pageSize]) !== null && _a !== void 0 ? _a : null;
2446
+ }
2447
+ requestPagesForWindow(start, end) {
2448
+ const firstPage = Math.floor(start / this.pageSize);
2449
+ const lastPage = Math.floor(end / this.pageSize);
2450
+ let anyNew = false;
2451
+ for (let p = firstPage; p <= lastPage; p++) {
2452
+ if (!this.loadedPages.has(p) && !this.requestedPages.has(p) && !this.pendingPages.has(p)) {
2453
+ this.pendingPages.add(p);
2454
+ anyNew = true;
2455
+ }
2456
+ }
2457
+ if (!anyNew)
2458
+ return;
2459
+ if (this.debounceTimer !== null)
2460
+ clearTimeout(this.debounceTimer);
2461
+ this.debounceTimer = setTimeout(() => this.flushPendingPages(), REQUEST_DEBOUNCE_MS);
2462
+ }
2463
+ flushPendingPages() {
2464
+ this.debounceTimer = null;
2465
+ if (this.pendingPages.size === 0)
2466
+ return;
2467
+ const next = new Set(this.requestedPages);
2468
+ let changed = false;
2469
+ for (const page of this.pendingPages) {
2470
+ if (this.loadedPages.has(page) || next.has(page))
2471
+ continue;
2472
+ const pageStart = page * this.pageSize;
2473
+ const pageEnd = pageStart + this.pageSize - 1;
2474
+ if (pageEnd < this.renderStart || pageStart > this.renderEnd)
2475
+ continue;
2476
+ next.add(page);
2477
+ this.mrdLoadPage.emit({ page, sort: this.sortParam() });
2478
+ changed = true;
2479
+ }
2480
+ this.pendingPages.clear();
2481
+ if (changed)
2482
+ this.requestedPages = next;
2483
+ }
2484
+ // ── Filter helpers ─────────────────────────────────────────────────────────
2485
+ handleFilterToggle() {
2486
+ this.filterMode = !this.filterMode;
2487
+ if (!this.filterMode)
2488
+ this.closeFilterPopup();
2489
+ }
2490
+ handleFilterOpen(col, e) {
2491
+ e.stopPropagation();
2492
+ const btn = e.currentTarget;
2493
+ const rect = btn.getBoundingClientRect();
2494
+ let left = rect.left;
2495
+ if (left + POPUP_WIDTH > window.innerWidth - 8)
2496
+ left = rect.right - POPUP_WIDTH;
2497
+ this.popupPos = { top: rect.bottom + 4, left: Math.max(8, left) };
2498
+ const name = this.colName(col);
2499
+ const dataType = this.colDataType(col);
2500
+ const existing = this.activeFilters.get(name);
2501
+ // Set the default operator explicitly so it is present in the ColumnFilter
2502
+ // even when the user never touches the operator dropdown.
2503
+ const defaultOperator = (TEXT_TYPES.has(dataType) || dataType === 'RELATION')
2504
+ ? 'startsWith'
2505
+ : undefined;
2506
+ // For DATETIME, stored values are UTC ISO strings; convert back to local
2507
+ // "YYYY-MM-DD" dates so the date inputs show what the user originally entered.
2508
+ // If from and to cover the same local day it was an exact-date filter — restore
2509
+ // to exact mode so the user sees the single-date input again.
2510
+ if (dataType === 'DATETIME' && existing && existing.operator !== 'isEmpty' && existing.operator !== 'isNotEmpty') {
2511
+ const display = Object.assign({}, existing);
2512
+ if (typeof display.from === 'string' && display.from)
2513
+ display.from = this.utcISOToLocalDate(display.from);
2514
+ if (typeof display.to === 'string' && display.to)
2515
+ display.to = this.utcISOToLocalDateExclusiveEnd(display.to);
2516
+ if (display.from && display.to && display.from === display.to) {
2517
+ this.pendingFilter = Object.assign(Object.assign({}, display), { value: display.from, from: undefined, to: undefined });
2518
+ }
2519
+ else {
2520
+ this.pendingFilter = display;
2521
+ }
2522
+ }
2523
+ else {
2524
+ this.pendingFilter = existing ? Object.assign({}, existing) : { field: name, dataType, operator: defaultOperator };
2525
+ }
2526
+ this.openFilterCol = name;
2527
+ // Close on outside click — re-register to replace any stale handler
2528
+ if (this.outsideClickHandler)
2529
+ document.removeEventListener('click', this.outsideClickHandler);
2530
+ this.outsideClickHandler = (ev) => {
2531
+ const popup = this.el.querySelector('.mrd-table__filter-popup');
2532
+ if (popup && !popup.contains(ev.target))
2533
+ this.closeFilterPopup();
2534
+ };
2535
+ document.addEventListener('click', this.outsideClickHandler);
2536
+ }
2537
+ closeFilterPopup() {
2538
+ this.openFilterCol = null;
2539
+ this.pendingFilter = null;
2540
+ if (this.outsideClickHandler) {
2541
+ document.removeEventListener('click', this.outsideClickHandler);
2542
+ this.outsideClickHandler = null;
2543
+ }
2544
+ }
2545
+ openTextblockModal(text) {
2546
+ this.textblockModal = text;
2547
+ if (this.keydownHandler)
2548
+ document.removeEventListener('keydown', this.keydownHandler);
2549
+ this.keydownHandler = (ev) => {
2550
+ if (ev.key === 'Escape')
2551
+ this.closeTextblockModal();
2552
+ };
2553
+ document.addEventListener('keydown', this.keydownHandler);
2554
+ }
2555
+ closeTextblockModal() {
2556
+ this.textblockModal = null;
2557
+ if (this.keydownHandler) {
2558
+ document.removeEventListener('keydown', this.keydownHandler);
2559
+ this.keydownHandler = null;
2560
+ }
2561
+ }
2562
+ openJsonModal(html) {
2563
+ this.jsonModal = html;
2564
+ if (this.keydownHandler)
2565
+ document.removeEventListener('keydown', this.keydownHandler);
2566
+ this.keydownHandler = (ev) => {
2567
+ if (ev.key === 'Escape')
2568
+ this.closeJsonModal();
2569
+ };
2570
+ document.addEventListener('keydown', this.keydownHandler);
2571
+ }
2572
+ closeJsonModal() {
2573
+ this.jsonModal = null;
2574
+ if (this.keydownHandler) {
2575
+ document.removeEventListener('keydown', this.keydownHandler);
2576
+ this.keydownHandler = null;
2577
+ }
2578
+ }
2579
+ setPending(key, val) {
2580
+ this.pendingFilter = Object.assign(Object.assign({}, this.pendingFilter), { [key]: val });
2581
+ }
2582
+ togglePendingValue(key, checked) {
2583
+ var _a, _b;
2584
+ const current = (_b = (_a = this.pendingFilter) === null || _a === void 0 ? void 0 : _a.values) !== null && _b !== void 0 ? _b : [];
2585
+ this.pendingFilter = Object.assign(Object.assign({}, this.pendingFilter), { values: checked ? [...current, key] : current.filter(k => k !== key) });
2586
+ }
2587
+ filterHasValue(f) {
2588
+ if (f.operator === 'isEmpty' || f.operator === 'isNotEmpty')
2589
+ return true;
2590
+ if (f.values !== undefined && f.values.length > 0)
2591
+ return true;
2592
+ if (f.value != null && f.value !== '')
2593
+ return true;
2594
+ if (typeof f.value === 'boolean')
2595
+ return true;
2596
+ if (f.from != null && f.from !== '')
2597
+ return true;
2598
+ if (f.to != null && f.to !== '')
2599
+ return true;
2600
+ return false;
2601
+ }
2602
+ // Convert a local "YYYY-MM-DD" date string to the UTC ISO string at the
2603
+ // start of that local day (midnight). new Date(y, m, d) uses local time.
2604
+ dateLocalToUTCStart(dateStr) {
2605
+ if (!dateStr)
2606
+ return dateStr;
2607
+ const [year, month, day] = dateStr.split('-').map(Number);
2608
+ return new Date(year, month - 1, day).toISOString().replace(/\.\d{3}Z$/, 'Z');
2609
+ }
2610
+ // Start of the day AFTER the given local date (exclusive range end).
2611
+ dateLocalToUTCEndExclusive(dateStr) {
2612
+ if (!dateStr)
2613
+ return dateStr;
2614
+ const [year, month, day] = dateStr.split('-').map(Number);
2615
+ return new Date(year, month - 1, day + 1).toISOString().replace(/\.\d{3}Z$/, 'Z');
2616
+ }
2617
+ // Convert a stored UTC ISO string back to the local "YYYY-MM-DD" date.
2618
+ utcISOToLocalDate(utcStr) {
2619
+ if (!utcStr)
2620
+ return utcStr;
2621
+ const d = new Date(utcStr);
2622
+ if (isNaN(d.getTime()))
2623
+ return utcStr;
2624
+ return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
2625
+ }
2626
+ // The stored "to" value is the exclusive end (midnight of the next day).
2627
+ // Subtract one day to recover the local date the user entered.
2628
+ utcISOToLocalDateExclusiveEnd(utcStr) {
2629
+ if (!utcStr)
2630
+ return utcStr;
2631
+ const d = new Date(utcStr);
2632
+ if (isNaN(d.getTime()))
2633
+ return utcStr;
2634
+ d.setDate(d.getDate() - 1);
2635
+ return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
2636
+ }
2637
+ applyFilter() {
2638
+ const f = this.pendingFilter;
2639
+ if (!(f === null || f === void 0 ? void 0 : f.field)) {
2640
+ this.closeFilterPopup();
2641
+ return;
2642
+ }
2643
+ // For DATETIME fields the user enters local dates; convert to UTC ISO strings.
2644
+ // Exact date → range covering the full local day (from = midnight, to = next midnight).
2645
+ // "to" is always the exclusive end (midnight of the next local day).
2646
+ let normalized = Object.assign({}, f);
2647
+ if (f.dataType === 'DATETIME' && f.operator !== 'isEmpty' && f.operator !== 'isNotEmpty') {
2648
+ if (typeof normalized.value === 'string' && normalized.value) {
2649
+ normalized.from = this.dateLocalToUTCStart(normalized.value);
2650
+ normalized.to = this.dateLocalToUTCEndExclusive(normalized.value);
2651
+ normalized.value = undefined;
2652
+ }
2653
+ else {
2654
+ if (typeof normalized.from === 'string' && normalized.from)
2655
+ normalized.from = this.dateLocalToUTCStart(normalized.from);
2656
+ if (typeof normalized.to === 'string' && normalized.to)
2657
+ normalized.to = this.dateLocalToUTCEndExclusive(normalized.to);
2658
+ }
2659
+ }
2660
+ const next = new Map(this.activeFilters);
2661
+ if (this.filterHasValue(normalized)) {
2662
+ next.set(normalized.field, normalized);
2663
+ }
2664
+ else {
2665
+ next.delete(normalized.field);
2666
+ }
2667
+ this.activeFilters = next;
2668
+ this.closeFilterPopup();
2669
+ this.mrdFilter.emit({ filters: Array.from(this.activeFilters.values()) });
2670
+ this.aggregations = null;
2671
+ this.emitLoadAggregations();
2672
+ if (this.totalElements > 0) {
2673
+ this.resetPages();
2674
+ this.emitPagesForWindow(this.renderStart, this.renderEnd);
2675
+ }
2676
+ }
2677
+ clearFilter() {
2678
+ const name = this.openFilterCol;
2679
+ const next = new Map(this.activeFilters);
2680
+ if (name)
2681
+ next.delete(name);
2682
+ this.activeFilters = next;
2683
+ this.closeFilterPopup();
2684
+ this.mrdFilter.emit({ filters: Array.from(this.activeFilters.values()) });
2685
+ this.aggregations = null;
2686
+ this.emitLoadAggregations();
2687
+ if (this.totalElements > 0) {
2688
+ this.resetPages();
2689
+ this.emitPagesForWindow(this.renderStart, this.renderEnd);
2690
+ }
2691
+ }
2692
+ clearAllFilters() {
2693
+ this.activeFilters = new Map();
2694
+ this.mrdFilter.emit({ filters: [] });
2695
+ this.aggregations = null;
2696
+ this.emitLoadAggregations();
2697
+ if (this.totalElements > 0) {
2698
+ this.resetPages();
2699
+ this.emitPagesForWindow(this.renderStart, this.renderEnd);
2700
+ }
2701
+ }
2702
+ // ── View switcher ──────────────────────────────────────────────────────────
2703
+ handleViewSwitch(view) {
2704
+ this.mrdSwitchView.emit({ name: view.name, class: view.class });
2705
+ }
2706
+ // ── Render: toolbar ────────────────────────────────────────────────────────
2707
+ renderToolbar() {
2708
+ var _a, _b;
2709
+ const filterCount = this.activeFilters.size;
2710
+ const hasActions = ((_a = this.actions) === null || _a === void 0 ? void 0 : _a.length) > 0;
2711
+ const hasViewSwitcher = !!this.viewLabel && ((_b = this.alternativeViews) === null || _b === void 0 ? void 0 : _b.length) > 0;
2712
+ return (h("div", { class: "mrd-table__toolbar" }, h("div", { class: "mrd-table__toolbar-left" }, h("button", { class: `mrd-table__action mrd-table__action--secondary mrd-table__filter-toggle${this.filterMode ? ' mrd-table__filter-toggle--active' : ''}`, onClick: () => this.handleFilterToggle() }, h("svg", { class: "mrd-table__action-icon", viewBox: "0 0 24 24", "aria-hidden": "true" }, h("path", { fill: "currentColor", d: "M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z" })), filterCount > 0 && h("span", { class: "mrd-table__filter-badge" }, filterCount), h("span", { class: "mrd-table__action-tooltip" }, this.filterMode ? t('table_filter_hide', this.locale) : t('table_filter', this.locale), filterCount > 0 ? ` (${filterCount} ${t('table_filter_active', this.locale)})` : '')), filterCount > 0 && (h("button", { class: "mrd-table__action mrd-table__action--secondary", onClick: () => this.clearAllFilters() }, h("svg", { class: "mrd-table__action-icon", viewBox: "0 0 24 24", "aria-hidden": "true" }, h("path", { fill: "currentColor", d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" })), h("span", { class: "mrd-table__action-tooltip" }, t('table_filter_clear_all', this.locale))))), hasViewSwitcher && (h("div", { class: "mrd-table__toolbar-center" }, h("select", { class: "mrd-table__view-select", onChange: (e) => {
2713
+ const sel = e.target;
2714
+ const view = this.alternativeViews.find(v => v.name === sel.value);
2715
+ if (view) {
2716
+ sel.selectedIndex = 0;
2717
+ this.handleViewSwitch(view);
2718
+ }
2719
+ } }, h("option", { value: "" }, this.viewLabel), this.alternativeViews.map(v => {
2720
+ var _a;
2721
+ return (h("option", { value: v.name }, (_a = v.label) !== null && _a !== void 0 ? _a : v.name));
2722
+ })))), hasActions && (h("div", { class: "mrd-table__toolbar-right" }, this.actions.map(a => {
2723
+ var _a;
2724
+ return (h("button", { class: `mrd-table__action mrd-table__action--${(_a = a.variant) !== null && _a !== void 0 ? _a : 'secondary'}`, disabled: a.disabled, onClick: () => this.mrdAction.emit({ action: a.action }) }, a.icon
2725
+ ? h("svg", { class: "mrd-table__action-icon", "aria-hidden": "true" }, h("use", { href: a.icon }))
2726
+ : a.label, h("span", { class: "mrd-table__action-tooltip" }, a.label)));
2727
+ })))));
2728
+ }
2729
+ // ── Render: filter popup ───────────────────────────────────────────────────
2730
+ renderFilterEditor(col) {
2731
+ var _a, _b, _c, _d, _e, _f, _g, _h;
2732
+ const pf = (_a = this.pendingFilter) !== null && _a !== void 0 ? _a : {};
2733
+ const dataType = this.colDataType(col);
2734
+ if (NO_FILTER_TYPES.has(dataType)) {
2735
+ return h("p", { class: "mrd-table__filter-no-support" }, t('filter_no_support', this.locale));
2736
+ }
2737
+ if (dataType === 'BOOLEAN') {
2738
+ const boolOp = pf.operator;
2739
+ const noValueOp = boolOp === 'isEmpty' || boolOp === 'isNotEmpty';
2740
+ return (h("div", { class: "mrd-table__filter-radio-group" }, [
2741
+ { labelKey: 'filter_all', value: null },
2742
+ { labelKey: 'yes', value: true },
2743
+ { labelKey: 'no', value: false },
2744
+ ].map(opt => (h("label", { class: "mrd-table__filter-radio-label" }, h("input", { type: "radio", name: `bf-${this.openFilterCol}`, checked: !noValueOp && pf.value === opt.value, onChange: () => { this.pendingFilter = Object.assign(Object.assign({}, pf), { operator: undefined, value: opt.value }); } }), t(opt.labelKey, this.locale)))), h("label", { class: "mrd-table__filter-radio-label" }, h("input", { type: "radio", name: `bf-${this.openFilterCol}`, checked: boolOp === 'isEmpty', onChange: () => { this.pendingFilter = Object.assign(Object.assign({}, pf), { operator: 'isEmpty', value: undefined }); } }), t('filter_is_empty', this.locale)), h("label", { class: "mrd-table__filter-radio-label" }, h("input", { type: "radio", name: `bf-${this.openFilterCol}`, checked: boolOp === 'isNotEmpty', onChange: () => { this.pendingFilter = Object.assign(Object.assign({}, pf), { operator: 'isNotEmpty', value: undefined }); } }), t('filter_is_not_empty', this.locale))));
2745
+ }
2746
+ if (dataType === 'LIST') {
2747
+ const items = (_c = (_b = col.field) === null || _b === void 0 ? void 0 : _b.listItems) !== null && _c !== void 0 ? _c : [];
2748
+ const selected = (_d = pf.values) !== null && _d !== void 0 ? _d : [];
2749
+ return (h("div", { class: "mrd-table__filter-list" }, h("div", { class: "mrd-table__filter-list-controls" }, h("button", { class: "mrd-table__filter-list-btn", onClick: () => { this.pendingFilter = Object.assign(Object.assign({}, pf), { values: items.map(i => i.key) }); } }, t('filter_select_all', this.locale)), h("button", { class: "mrd-table__filter-list-btn", onClick: () => { this.pendingFilter = Object.assign(Object.assign({}, pf), { values: [] }); } }, t('filter_select_none', this.locale))), items.map(item => (h("label", { class: "mrd-table__filter-checkbox-label" }, h("input", { type: "checkbox", checked: selected.includes(item.key), onChange: (e) => this.togglePendingValue(item.key, e.target.checked) }), item.label)))));
2750
+ }
2751
+ if (TEXT_TYPES.has(dataType) || dataType === 'RELATION') {
2752
+ const op = (_e = pf.operator) !== null && _e !== void 0 ? _e : 'startsWith';
2753
+ const noInput = op === 'isEmpty' || op === 'isNotEmpty';
2754
+ return (h("div", { class: "mrd-table__filter-editor" }, h("select", { class: "mrd-table__filter-select", onChange: (e) => this.setPending('operator', e.target.value) }, [
2755
+ { val: 'startsWith', labelKey: 'filter_starts_with' },
2756
+ { val: 'equals', labelKey: 'filter_equals' },
2757
+ { val: 'isEmpty', labelKey: 'filter_is_empty' },
2758
+ { val: 'isNotEmpty', labelKey: 'filter_is_not_empty' },
2759
+ ].map(o => h("option", { value: o.val, selected: op === o.val }, t(o.labelKey, this.locale)))), !noInput && (h("input", { type: "text", class: "mrd-table__filter-input", value: String((_f = pf.value) !== null && _f !== void 0 ? _f : ''), placeholder: t('filter_search_value', this.locale), onInput: (e) => this.setPending('value', e.target.value) }))));
2760
+ }
2761
+ if (NUMERIC_TYPES.has(dataType)) {
2762
+ const numOp = pf.operator;
2763
+ const noInput = numOp === 'isEmpty' || numOp === 'isNotEmpty';
2764
+ const rangeMode = !noInput && (pf.from !== undefined || pf.to !== undefined);
2765
+ return (h("div", { class: "mrd-table__filter-editor" }, h("select", { class: "mrd-table__filter-select", onChange: (e) => {
2766
+ const val = e.target.value;
2767
+ if (val === 'isEmpty' || val === 'isNotEmpty') {
2768
+ this.pendingFilter = Object.assign(Object.assign({}, pf), { operator: val, value: undefined, from: undefined, to: undefined });
2769
+ }
2770
+ else {
2771
+ this.pendingFilter = Object.assign(Object.assign({}, pf), { operator: undefined });
2772
+ }
2773
+ } }, h("option", { value: "", selected: !noInput }, t('filter_has_value', this.locale)), h("option", { value: "isEmpty", selected: numOp === 'isEmpty' }, t('filter_is_empty', this.locale)), h("option", { value: "isNotEmpty", selected: numOp === 'isNotEmpty' }, t('filter_is_not_empty', this.locale))), !noInput && (h("div", { class: "mrd-table__filter-editor" }, h("div", { class: "mrd-table__filter-radio-group mrd-table__filter-radio-group--inline" }, h("label", { class: "mrd-table__filter-radio-label" }, h("input", { type: "radio", name: `nm-${this.openFilterCol}`, checked: !rangeMode, onChange: () => { this.pendingFilter = Object.assign(Object.assign({}, pf), { from: undefined, to: undefined }); } }), t('filter_exact', this.locale)), h("label", { class: "mrd-table__filter-radio-label" }, h("input", { type: "radio", name: `nm-${this.openFilterCol}`, checked: rangeMode, onChange: () => { this.pendingFilter = Object.assign(Object.assign({}, pf), { value: undefined, from: null, to: null }); } }), t('filter_range', this.locale))), !rangeMode ? (h("input", { type: "number", class: "mrd-table__filter-input", value: pf.value != null ? String(pf.value) : '', onInput: (e) => this.setPending('value', e.target.value) })) : (h("div", { class: "mrd-table__filter-range" }, h("input", { type: "number", class: "mrd-table__filter-input", placeholder: t('filter_from', this.locale), value: pf.from != null ? String(pf.from) : '', onInput: (e) => this.setPending('from', e.target.value) }), h("span", { class: "mrd-table__filter-range-sep" }, "\u2013"), h("input", { type: "number", class: "mrd-table__filter-input", placeholder: t('filter_to', this.locale), value: pf.to != null ? String(pf.to) : '', onInput: (e) => this.setPending('to', e.target.value) })))))));
2774
+ }
2775
+ if (dataType === 'DATETIME') {
2776
+ const dtOp = pf.operator;
2777
+ const noInput = dtOp === 'isEmpty' || dtOp === 'isNotEmpty';
2778
+ const rangeMode = !noInput && (pf.from !== undefined || pf.to !== undefined);
2779
+ return (h("div", { class: "mrd-table__filter-editor" }, h("select", { class: "mrd-table__filter-select", onChange: (e) => {
2780
+ const val = e.target.value;
2781
+ if (val === 'isEmpty' || val === 'isNotEmpty') {
2782
+ this.pendingFilter = Object.assign(Object.assign({}, pf), { operator: val, value: undefined, from: undefined, to: undefined });
2783
+ }
2784
+ else {
2785
+ this.pendingFilter = Object.assign(Object.assign({}, pf), { operator: undefined });
2786
+ }
2787
+ } }, h("option", { value: "", selected: !noInput }, t('filter_has_value', this.locale)), h("option", { value: "isEmpty", selected: dtOp === 'isEmpty' }, t('filter_is_empty', this.locale)), h("option", { value: "isNotEmpty", selected: dtOp === 'isNotEmpty' }, t('filter_is_not_empty', this.locale))), !noInput && (h("div", { class: "mrd-table__filter-editor" }, h("div", { class: "mrd-table__filter-radio-group mrd-table__filter-radio-group--inline" }, h("label", { class: "mrd-table__filter-radio-label" }, h("input", { type: "radio", name: `dt-${this.openFilterCol}`, checked: !rangeMode, onChange: () => { this.pendingFilter = Object.assign(Object.assign({}, pf), { from: undefined, to: undefined }); } }), t('filter_exact', this.locale)), h("label", { class: "mrd-table__filter-radio-label" }, h("input", { type: "radio", name: `dt-${this.openFilterCol}`, checked: rangeMode, onChange: () => { this.pendingFilter = Object.assign(Object.assign({}, pf), { value: undefined, from: null, to: null }); } }), t('filter_range', this.locale))), !rangeMode ? (h("input", { type: "date", class: "mrd-table__filter-input", value: String((_g = pf.value) !== null && _g !== void 0 ? _g : ''), onInput: (e) => this.setPending('value', e.target.value) })) : (h("div", { class: "mrd-table__filter-range mrd-table__filter-range--stacked" }, h("label", { class: "mrd-table__filter-range-label" }, t('filter_from', this.locale)), h("input", { type: "date", class: "mrd-table__filter-input", value: pf.from != null ? String(pf.from) : '', onInput: (e) => this.setPending('from', e.target.value) }), h("label", { class: "mrd-table__filter-range-label" }, t('filter_to', this.locale)), h("input", { type: "date", class: "mrd-table__filter-input", value: pf.to != null ? String(pf.to) : '', onInput: (e) => this.setPending('to', e.target.value) })))))));
2788
+ }
2789
+ if (DATE_TYPES.has(dataType)) {
2790
+ const inputType = dataType === 'DATE' ? 'date' : 'time';
2791
+ const dtdOp = pf.operator;
2792
+ const noInput = dtdOp === 'isEmpty' || dtdOp === 'isNotEmpty';
2793
+ const rangeMode = !noInput && (pf.from !== undefined || pf.to !== undefined);
2794
+ return (h("div", { class: "mrd-table__filter-editor" }, h("select", { class: "mrd-table__filter-select", onChange: (e) => {
2795
+ const val = e.target.value;
2796
+ if (val === 'isEmpty' || val === 'isNotEmpty') {
2797
+ this.pendingFilter = Object.assign(Object.assign({}, pf), { operator: val, value: undefined, from: undefined, to: undefined });
2798
+ }
2799
+ else {
2800
+ this.pendingFilter = Object.assign(Object.assign({}, pf), { operator: undefined });
2801
+ }
2802
+ } }, h("option", { value: "", selected: !noInput }, t('filter_has_value', this.locale)), h("option", { value: "isEmpty", selected: dtdOp === 'isEmpty' }, t('filter_is_empty', this.locale)), h("option", { value: "isNotEmpty", selected: dtdOp === 'isNotEmpty' }, t('filter_is_not_empty', this.locale))), !noInput && (h("div", { class: "mrd-table__filter-editor" }, h("div", { class: "mrd-table__filter-radio-group mrd-table__filter-radio-group--inline" }, h("label", { class: "mrd-table__filter-radio-label" }, h("input", { type: "radio", name: `dt-${this.openFilterCol}`, checked: !rangeMode, onChange: () => { this.pendingFilter = Object.assign(Object.assign({}, pf), { from: undefined, to: undefined }); } }), t('filter_exact', this.locale)), h("label", { class: "mrd-table__filter-radio-label" }, h("input", { type: "radio", name: `dt-${this.openFilterCol}`, checked: rangeMode, onChange: () => { this.pendingFilter = Object.assign(Object.assign({}, pf), { value: undefined, from: null, to: null }); } }), t('filter_range', this.locale))), !rangeMode ? (h("input", { type: inputType, class: "mrd-table__filter-input", value: String((_h = pf.value) !== null && _h !== void 0 ? _h : ''), onInput: (e) => this.setPending('value', e.target.value) })) : (h("div", { class: "mrd-table__filter-range" }, h("input", { type: inputType, class: "mrd-table__filter-input", placeholder: t('filter_from', this.locale), value: pf.from != null ? String(pf.from) : '', onInput: (e) => this.setPending('from', e.target.value) }), h("input", { type: inputType, class: "mrd-table__filter-input", placeholder: t('filter_to', this.locale), value: pf.to != null ? String(pf.to) : '', onInput: (e) => this.setPending('to', e.target.value) })))))));
2803
+ }
2804
+ return null;
2805
+ }
2806
+ renderFilterPopup() {
2807
+ var _a, _b, _c, _d;
2808
+ if (!this.openFilterCol || !this.pendingFilter)
2809
+ return null;
2810
+ const col = this.columns.find(c => this.colName(c) === this.openFilterCol);
2811
+ if (!col)
2812
+ return null;
2813
+ const label = (_d = (_b = (_a = col.field) === null || _a === void 0 ? void 0 : _a.label) !== null && _b !== void 0 ? _b : (_c = col.relation) === null || _c === void 0 ? void 0 : _c.label) !== null && _d !== void 0 ? _d : this.openFilterCol;
2814
+ const sortActive = this.sortField === this.openFilterCol;
2815
+ return (h("div", { class: "mrd-table__filter-popup", style: { top: `${this.popupPos.top}px`, left: `${this.popupPos.left}px` }, onClick: (e) => e.stopPropagation() }, h("div", { class: "mrd-table__filter-popup-header" }, h("span", { class: "mrd-table__filter-popup-title" }, label), h("button", { class: "mrd-table__filter-close", onClick: () => this.closeFilterPopup() }, "\u2715")), h("div", { class: "mrd-table__filter-section" }, h("div", { class: "mrd-table__filter-section-label" }, t('filter_sorting', this.locale)), h("div", { class: "mrd-table__filter-sort-buttons" }, h("button", { class: `mrd-table__filter-sort-btn${sortActive && this.sortDir === 'asc' ? ' mrd-table__filter-sort-btn--active' : ''}`, onClick: () => this.applySort(col, 'asc') }, "\u25B2 ", t('filter_ascending', this.locale)), h("button", { class: `mrd-table__filter-sort-btn${sortActive && this.sortDir === 'desc' ? ' mrd-table__filter-sort-btn--active' : ''}`, onClick: () => this.applySort(col, 'desc') }, "\u25BC ", t('filter_descending', this.locale)))), h("div", { class: "mrd-table__filter-divider" }), h("div", { class: "mrd-table__filter-section" }, h("div", { class: "mrd-table__filter-section-label" }, t('filter_section', this.locale)), this.renderFilterEditor(col)), h("div", { class: "mrd-table__filter-popup-footer" }, h("button", { class: "mrd-table__filter-btn mrd-table__filter-btn--clear", onClick: () => this.clearFilter() }, t('filter_clear', this.locale)), h("button", { class: "mrd-table__filter-btn mrd-table__filter-btn--apply", onClick: () => this.applyFilter() }, t('filter_apply', this.locale)))));
2816
+ }
2817
+ // ── Render: footer ────────────────────────────────────────────────────────
2818
+ renderFooter(rowCount, effectiveTotal) {
2819
+ const total = this.totalElements;
2820
+ // Non-paginated mode: show plain row count
2821
+ if (total === 0) {
2822
+ const count = rowCount !== null && rowCount !== void 0 ? rowCount : 0;
2823
+ if (count === 0)
2824
+ return null;
2825
+ return (h("div", { class: "mrd-table__footer" }, count, " ", t('table_of', this.locale), " ", count));
2826
+ }
2827
+ // Paginated mode: only show once page 0 has loaded (avoids stale total during filter reset)
2828
+ if (!this.loadedPages.has(0))
2829
+ return null;
2830
+ // Use effectiveTotal (derived from actual page lengths) so the counter
2831
+ // is correct even when the host has not yet updated totalElements.
2832
+ const displayTotal = effectiveTotal !== null && effectiveTotal !== void 0 ? effectiveTotal : total;
2833
+ // Compute from/to independently so partial rows at top/bottom are included.
2834
+ const from = Math.min(Math.floor(this.scrollTop / this.rowHeight) + 1, displayTotal);
2835
+ const to = Math.min(Math.ceil((this.scrollTop + this.tableHeight) / this.rowHeight), displayTotal);
2836
+ return (h("div", { class: "mrd-table__footer" }, from, "\u2013", to, " ", t('table_of', this.locale), " ", displayTotal));
2837
+ }
2838
+ // ── Render: cell ──────────────────────────────────────────────────────────
2839
+ renderCell(col, row) {
2840
+ var _a, _b, _c, _d, _e, _f;
2841
+ const numericTypes = new Set(['INTEGER', 'DECIMAL', 'PERCENTAGE', 'CURRENCY']);
2842
+ const dataType = (_b = (_a = col.field) === null || _a === void 0 ? void 0 : _a.dataType) !== null && _b !== void 0 ? _b : '';
2843
+ const isNumeric = col.type === 'FIELD' && numericTypes.has(dataType);
2844
+ const isFile = col.type === 'FIELD' && (dataType === 'FILE' || dataType === 'IMAGE');
2845
+ if (isFile) {
2846
+ const name = (_d = (_c = col.field) === null || _c === void 0 ? void 0 : _c.name) !== null && _d !== void 0 ? _d : '';
2847
+ const fileVal = row === null || row === void 0 ? void 0 : row[name];
2848
+ const href = fileVal === null || fileVal === void 0 ? void 0 : fileVal.href;
2849
+ const fileName = fileVal === null || fileVal === void 0 ? void 0 : fileVal.fileName;
2850
+ return (h("td", { class: "mrd-table__cell" }, href && fileName ? (h("button", { class: "mrd-table__file-btn", title: fileName, onClick: (e) => {
2851
+ e.stopPropagation();
2852
+ this.mrdDownload.emit({ href, fileName });
2853
+ } }, h("svg", { class: "mrd-table__file-icon", viewBox: "0 0 24 24", "aria-hidden": "true" }, h("path", { fill: "currentColor", d: "M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm-1 7V3.5L18.5 9H13zm-3 8l-3-3 1.41-1.41L10 14.17l4.59-4.58L16 11l-6 6z" })), t('download', this.locale))) : ''));
2854
+ }
2855
+ if (dataType === 'JSON') {
2856
+ const name = (_f = (_e = col.field) === null || _e === void 0 ? void 0 : _e.name) !== null && _f !== void 0 ? _f : '';
2857
+ const rawValue = name ? row === null || row === void 0 ? void 0 : row[name] : undefined;
2858
+ if (rawValue == null || rawValue === '')
2859
+ return h("td", { class: "mrd-table__cell" });
2860
+ const compactHtml = CellRenderer.formatJson(rawValue, true);
2861
+ const prettyHtml = CellRenderer.formatJson(rawValue, false);
2862
+ return (h("td", { class: "mrd-table__cell" }, h("span", { class: "mrd-table__json-preview", innerHTML: compactHtml }), h("button", { class: "mrd-table__textblock-btn", onClick: (e) => { e.stopPropagation(); this.openJsonModal(prettyHtml); }, "aria-label": t('textblock_show_more', this.locale) }, "\u22EF")));
2863
+ }
2864
+ const TEXTBLOCK_MAX = 200;
2865
+ if (dataType === 'TEXTBLOCK') {
2866
+ const full = CellRenderer.render(col, row, this.locale);
2867
+ if (full.length <= TEXTBLOCK_MAX) {
2868
+ return h("td", { class: "mrd-table__cell" }, full);
2869
+ }
2870
+ const preview = full.slice(0, TEXTBLOCK_MAX) + '…';
2871
+ return (h("td", { class: "mrd-table__cell" }, preview, h("button", { class: "mrd-table__textblock-btn", onClick: (e) => { e.stopPropagation(); this.openTextblockModal(full); }, "aria-label": t('textblock_show_more', this.locale) }, "\u22EF")));
2872
+ }
2873
+ const value = CellRenderer.render(col, row, this.locale);
2874
+ return (h("td", { class: `mrd-table__cell${isNumeric ? ' mrd-table__cell--numeric' : ''}` }, value));
2875
+ }
2876
+ // ── Render: totals row ────────────────────────────────────────────────────
2877
+ renderTotalsRow() {
2878
+ if (!this.aggregations)
2879
+ return null;
2880
+ if (!this.columns.some(c => { var _a; return c.type === 'FIELD' && ((_a = c.field) === null || _a === void 0 ? void 0 : _a.aggregate); }))
2881
+ return null;
2882
+ return (h("tfoot", null, h("tr", { class: "mrd-table__totals-row" }, this.columns.map(col => {
2883
+ var _a, _b;
2884
+ const val = this.renderAggregationValue(col);
2885
+ const isNumeric = col.type === 'FIELD' && NUMERIC_TYPES.has((_b = (_a = col.field) === null || _a === void 0 ? void 0 : _a.dataType) !== null && _b !== void 0 ? _b : '');
2886
+ return (h("td", { class: `mrd-table__totals-cell${isNumeric ? ' mrd-table__totals-cell--numeric' : ''}` }, val));
2887
+ }))));
2888
+ }
2889
+ // ── Render ─────────────────────────────────────────────────────────────────
2890
+ render() {
2891
+ var _a, _b, _c;
2892
+ if (!((_a = this.columns) === null || _a === void 0 ? void 0 : _a.length))
2893
+ return null;
2894
+ // ── Non-paginated mode ──────────────────────────────────────────────────
2895
+ if (this.totalElements === 0) {
2896
+ return (h(Host, null, this.renderToolbar(), h("div", { class: "mrd-table" }, h("table", { class: "mrd-table__table" }, h("thead", null, h("tr", null, this.columns.map(col => {
2897
+ var _a, _b, _c, _d;
2898
+ const name = this.colName(col);
2899
+ const isFiltered = this.activeFilters.has(name);
2900
+ const cls = [
2901
+ 'mrd-table__header',
2902
+ isFiltered ? 'mrd-table__header--filtered' : '',
2903
+ this.filterMode ? 'mrd-table__header--sortable' : '',
2904
+ ].filter(Boolean).join(' ');
2905
+ return (h("th", { class: cls, onClick: this.filterMode ? (e) => this.handleFilterOpen(col, e) : undefined }, h("span", { class: "mrd-table__header-label" }, (_d = (_b = (_a = col.field) === null || _a === void 0 ? void 0 : _a.label) !== null && _b !== void 0 ? _b : (_c = col.relation) === null || _c === void 0 ? void 0 : _c.label) !== null && _d !== void 0 ? _d : ''), isFiltered && this.renderFilterIcon()));
2906
+ }))), h("tbody", null, (_b = this.rows) === null || _b === void 0 ? void 0 : _b.map((row, i) => (h("tr", { class: "mrd-table__row mrd-table__row--clickable", style: { background: i % 2 === 0 ? '' : 'var(--mrd-color-neutral-100)' }, onClick: () => this.mrdRowClick.emit(row) }, this.columns.map(col => this.renderCell(col, row)))))), this.renderTotalsRow()), (!this.rows || this.rows.length === 0) && (h("p", { class: "mrd-table__empty" }, t('no_results', this.locale)))), this.renderFooter((_c = this.rows) === null || _c === void 0 ? void 0 : _c.length), this.renderFilterPopup(), this.renderTextblockModal(), this.renderJsonModal()));
2907
+ }
2908
+ // ── Paginated / virtual-scroll mode ────────────────────────────────────
2909
+ // Derive the authoritative row count from loaded pages:
2910
+ // if any loaded page is shorter than pageSize it is the last page,
2911
+ // so the true total cannot exceed (pageNum * pageSize + pageRows.length).
2912
+ // This self-corrects without requiring the host to update totalElements.
2913
+ let effectiveTotal = this.totalElements;
2914
+ for (const [pageNum, pageRows] of this.loadedPages) {
2915
+ if (pageRows.length < this.pageSize) {
2916
+ effectiveTotal = Math.min(effectiveTotal, pageNum * this.pageSize + pageRows.length);
2917
+ }
2918
+ }
2919
+ // Clamp renderEnd to what we actually know exists (-1 when empty)
2920
+ const clampedEnd = Math.min(this.renderEnd, effectiveTotal - 1);
2921
+ const colCount = this.columns.length;
2922
+ const topSpacerHeight = this.renderStart * this.rowHeight;
2923
+ const bottomSpacerHeight = Math.max(0, (effectiveTotal - 1 - clampedEnd) * this.rowHeight);
2924
+ const tableStyle = this.colWidths.length > 0
2925
+ ? { tableLayout: 'fixed' }
2926
+ : undefined;
2927
+ const renderedRows = [];
2928
+ for (let i = this.renderStart; i <= clampedEnd; i++) {
2929
+ const row = this.getRow(i);
2930
+ if (row === null) {
2931
+ renderedRows.push(h("tr", { class: "mrd-table__row mrd-table__row--loading" }, h("td", { class: "mrd-table__cell--placeholder", colSpan: colCount }, h("span", { class: "mrd-table__placeholder-bar" }))));
2932
+ }
2933
+ else {
2934
+ renderedRows.push(h("tr", { class: "mrd-table__row mrd-table__row--clickable", style: { background: i % 2 === 0 ? '' : 'var(--mrd-color-neutral-100)' }, onClick: () => this.mrdRowClick.emit(row) }, this.columns.map(col => this.renderCell(col, row))));
2935
+ }
2936
+ }
2937
+ return (h(Host, null, this.renderToolbar(), h("div", { class: "mrd-table__scroll", style: { height: `${this.tableHeight}px` }, onScroll: this.handleScroll }, h("table", { class: "mrd-table__table", style: tableStyle }, h("thead", null, h("tr", null, this.columns.map((col, idx) => {
2938
+ var _a, _b, _c, _d;
2939
+ const name = this.colName(col);
2940
+ const isActive = this.sortField === name;
2941
+ const isFiltered = this.activeFilters.has(name);
2942
+ const isInteractive = !NON_INTERACTIVE_TYPES.has(this.colDataType(col));
2943
+ const cls = [
2944
+ 'mrd-table__header',
2945
+ isInteractive ? 'mrd-table__header--sortable' : '',
2946
+ isActive ? `mrd-table__header--sorted-${this.sortDir}` : '',
2947
+ isFiltered ? 'mrd-table__header--filtered' : '',
2948
+ ].filter(Boolean).join(' ');
2949
+ return (h("th", { class: cls, style: this.colWidths[idx] ? { width: `${this.colWidths[idx]}px` } : undefined, onClick: isInteractive ? ((e) => this.filterMode ? this.handleFilterOpen(col, e) : this.handleSortClick(col)) : undefined }, h("span", { class: "mrd-table__header-label" }, (_d = (_b = (_a = col.field) === null || _a === void 0 ? void 0 : _a.label) !== null && _b !== void 0 ? _b : (_c = col.relation) === null || _c === void 0 ? void 0 : _c.label) !== null && _d !== void 0 ? _d : ''), isInteractive && isActive && (h("span", { class: "mrd-table__sort-icon", "aria-hidden": "true" }, this.sortDir === 'asc' ? '▲' : '▼')), isInteractive && !isActive && !this.filterMode && (h("span", { class: "mrd-table__sort-icon", "aria-hidden": "true" }, "\u21C5")), isInteractive && isFiltered && this.renderFilterIcon()));
2950
+ }))), h("tbody", null, topSpacerHeight > 0 && (h("tr", { class: "mrd-table__spacer", style: { height: `${topSpacerHeight}px` } }, h("td", { colSpan: colCount }))), renderedRows, bottomSpacerHeight > 0 && (h("tr", { class: "mrd-table__spacer", style: { height: `${bottomSpacerHeight}px` } }, h("td", { colSpan: colCount })))), this.renderTotalsRow())), effectiveTotal === 0 && this.loadedPages.has(0) && (h("p", { class: "mrd-table__empty" }, t('no_results', this.locale))), effectiveTotal > 0 && this.renderFooter(undefined, effectiveTotal), this.renderFilterPopup(), this.renderTextblockModal()));
2951
+ }
2952
+ renderFilterIcon() {
2953
+ return (h("span", { class: "mrd-table__filter-icon", "aria-hidden": "true" }, h("svg", { viewBox: "0 0 24 24", width: "14", height: "14", fill: "currentColor" }, h("path", { d: "M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z" }))));
2954
+ }
2955
+ renderTextblockModal() {
2956
+ if (this.textblockModal === null)
2957
+ return null;
2958
+ return (h("div", { class: "mrd-table__modal-backdrop", onClick: () => this.closeTextblockModal(), role: "dialog", "aria-modal": "true" }, h("div", { class: "mrd-table__modal", onClick: (e) => e.stopPropagation() }, h("button", { class: "mrd-table__modal-close", onClick: () => this.closeTextblockModal(), "aria-label": t('close', this.locale) }, "\u2715"), h("p", { class: "mrd-table__modal-text" }, this.textblockModal))));
2959
+ }
2960
+ renderJsonModal() {
2961
+ if (this.jsonModal === null)
2962
+ return null;
2963
+ return (h("div", { class: "mrd-table__modal-backdrop", onClick: () => this.closeJsonModal(), role: "dialog", "aria-modal": "true" }, h("div", { class: "mrd-table__modal", onClick: (e) => e.stopPropagation() }, h("button", { class: "mrd-table__modal-close", onClick: () => this.closeJsonModal(), "aria-label": t('close', this.locale) }, "\u2715"), h("pre", { class: "mrd-table__modal-json", innerHTML: this.jsonModal }))));
2964
+ }
2965
+ get el() { return getElement(this); }
2966
+ static get watchers() { return {
2967
+ "totalElements": [{
2968
+ "totalElementsChanged": 0
2969
+ }]
2970
+ }; }
2971
+ };
2972
+ MrdTable.style = mrdTableScss();
2973
+
2974
+ const mrdTextFieldScss = () => `.sc-mrd-text-field-h{display:block}.mrd-text-field.sc-mrd-text-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-text-field__label.sc-mrd-text-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-text-field__label--required.sc-mrd-text-field::after{content:' *';color:var(--mrd-color-danger)}.mrd-text-field__input.sc-mrd-text-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-text-field__input.sc-mrd-text-field::placeholder{color:var(--mrd-input-placeholder-color)}.mrd-text-field__input.sc-mrd-text-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-text-field__input.sc-mrd-text-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.mrd-text-field__input--error.sc-mrd-text-field{border-color:var(--mrd-border-color-error)}.mrd-text-field__input--error.sc-mrd-text-field:focus{box-shadow:var(--mrd-shadow-focus-error)}.mrd-text-field__error.sc-mrd-text-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}`;
2975
+
2976
+ const MrdTextField = class {
2977
+ constructor(hostRef) {
2978
+ registerInstance(this, hostRef);
2979
+ this.mrdChange = createEvent(this, "mrdChange");
2980
+ this.mrdBlur = createEvent(this, "mrdBlur");
2981
+ this.name = '';
2982
+ this.label = '';
2983
+ this.value = '';
2984
+ this.placeholder = '';
2985
+ this.required = false;
2986
+ this.disabled = false;
2987
+ this.locale = navigator.language;
2988
+ this.error = '';
2989
+ this.handleInput = (e) => {
2990
+ const val = e.target.value;
2991
+ this.mrdChange.emit({ name: this.name, value: val });
2992
+ };
2993
+ this.handleBlur = (e) => {
2994
+ const val = e.target.value;
2995
+ if (this.required && !validateRequired(val)) {
2996
+ this.error = t('required', this.locale);
2997
+ }
2998
+ else {
2999
+ this.error = '';
3000
+ }
3001
+ this.mrdBlur.emit({ name: this.name, value: val });
3002
+ };
3003
+ }
3004
+ render() {
3005
+ const hasError = !!this.error;
3006
+ return (h(Host, { key: 'b1ea3dce848a4ad41b60599804c69a35ccd35570' }, h("div", { key: '2e327824843fe02c5851beae96d52f9eb9ee67ce', class: "mrd-text-field" }, this.label && (h("label", { key: '99026834b30a53d7cf715c59099895211ff6ddb7', class: `mrd-text-field__label${this.required ? ' mrd-text-field__label--required' : ''}` }, this.label)), h("input", { key: '0e56c9115b2016ad3cb3ce8e734297354c70c7e2', class: `mrd-text-field__input${hasError ? ' mrd-text-field__input--error' : ''}`, type: "text", name: this.name, value: this.value, placeholder: this.placeholder, required: this.required, disabled: this.disabled, onInput: this.handleInput, onBlur: this.handleBlur }), hasError && h("span", { key: '0430c32b083484747962147e167b11ed7a1597cc', class: "mrd-text-field__error" }, this.error))));
3007
+ }
3008
+ };
3009
+ MrdTextField.style = mrdTextFieldScss();
3010
+
3011
+ const mrdTextareaFieldScss = () => `.sc-mrd-textarea-field-h{display:block}.mrd-textarea-field.sc-mrd-textarea-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-textarea-field__label.sc-mrd-textarea-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-textarea-field__label--required.sc-mrd-textarea-field::after{content:' *';color:var(--mrd-color-danger)}.mrd-textarea-field__container.sc-mrd-textarea-field{border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);overflow:hidden;background-color:var(--mrd-input-bg);transition:border-color var(--mrd-transition), box-shadow var(--mrd-transition)}.mrd-textarea-field__container.sc-mrd-textarea-field:focus-within{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-textarea-field__container--error.sc-mrd-textarea-field{border-color:var(--mrd-border-color-error)}.mrd-textarea-field__container--error.sc-mrd-textarea-field:focus-within{box-shadow:var(--mrd-shadow-focus-error)}.mrd-textarea-field__editor.sc-mrd-textarea-field{min-height:150px;font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base)}.mrd-textarea-field__editor.sc-mrd-textarea-field .ql-toolbar.sc-mrd-textarea-field{border:none;border-bottom:var(--mrd-border-width) solid var(--mrd-border-color);font-family:var(--mrd-font-family)}.mrd-textarea-field__editor.sc-mrd-textarea-field .ql-container.sc-mrd-textarea-field{border:none;font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base)}.mrd-textarea-field__editor.sc-mrd-textarea-field .ql-editor.sc-mrd-textarea-field{min-height:120px;padding:var(--mrd-input-padding-y) var(--mrd-input-padding-x)}.mrd-textarea-field__editor.sc-mrd-textarea-field .ql-editor.ql-blank.sc-mrd-textarea-field::before{color:var(--mrd-input-placeholder-color);font-style:normal}.mrd-textarea-field__error.sc-mrd-textarea-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}`;
3012
+
3013
+ const MrdTextareaField = class {
3014
+ constructor(hostRef) {
3015
+ registerInstance(this, hostRef);
3016
+ this.mrdChange = createEvent(this, "mrdChange");
3017
+ this.mrdBlur = createEvent(this, "mrdBlur");
3018
+ this.name = '';
3019
+ this.label = '';
3020
+ this.value = '';
3021
+ this.placeholder = '';
3022
+ this.required = false;
3023
+ this.disabled = false;
3024
+ this.locale = navigator.language;
3025
+ this.error = '';
3026
+ this.editorReady = false;
3027
+ }
3028
+ componentDidLoad() {
3029
+ this.initQuill();
3030
+ }
3031
+ async initQuill() {
3032
+ try {
3033
+ // Dynamically import Quill
3034
+ const Quill = (await import('./quill-CiuCgGz_.js')).default;
3035
+ this.editorEl = this.el.querySelector('.mrd-textarea-field__editor');
3036
+ if (!this.editorEl)
3037
+ return;
3038
+ const quill = new Quill(this.editorEl, {
3039
+ theme: 'snow',
3040
+ placeholder: this.placeholder,
3041
+ readOnly: this.disabled,
3042
+ modules: {
3043
+ toolbar: [
3044
+ ['bold', 'italic', 'underline', 'strike'],
3045
+ [{ list: 'ordered' }, { list: 'bullet' }],
3046
+ [{ header: [1, 2, 3, false] }],
3047
+ ['link'],
3048
+ ['clean'],
3049
+ ],
3050
+ },
3051
+ });
3052
+ if (this.value) {
3053
+ quill.clipboard.dangerouslyPasteHTML(this.value);
3054
+ }
3055
+ quill.on('text-change', () => {
3056
+ var _a, _b;
3057
+ const html = (_b = (_a = this.editorEl.querySelector('.ql-editor')) === null || _a === void 0 ? void 0 : _a.innerHTML) !== null && _b !== void 0 ? _b : '';
3058
+ this.mrdChange.emit({ name: this.name, value: html });
3059
+ });
3060
+ quill.on('selection-change', (range) => {
3061
+ var _a, _b;
3062
+ if (!range) {
3063
+ const html = (_b = (_a = this.editorEl.querySelector('.ql-editor')) === null || _a === void 0 ? void 0 : _a.innerHTML) !== null && _b !== void 0 ? _b : '';
3064
+ if (this.required && !validateRequired(html)) {
3065
+ this.error = t('required', this.locale);
3066
+ }
3067
+ else {
3068
+ this.error = '';
3069
+ }
3070
+ this.mrdBlur.emit({ name: this.name, value: html });
3071
+ }
3072
+ });
3073
+ this.editorReady = true;
3074
+ }
3075
+ catch (err) {
3076
+ console.error('Failed to load Quill editor:', err);
3077
+ }
3078
+ }
3079
+ render() {
3080
+ return (h(Host, { key: '7bc05fae8d48c43b56bde892537930552605727a' }, h("div", { key: '3416e9c5fdf6362602715de8427c5d2ccfa52925', class: "mrd-textarea-field" }, this.label && (h("label", { key: 'c6bd35076738b1a700b53092fb0754250c73e085', class: `mrd-textarea-field__label${this.required ? ' mrd-textarea-field__label--required' : ''}` }, this.label)), h("div", { key: 'ed0483a25a62399d1ac8ee14bc59e3eb44b91814', class: `mrd-textarea-field__container${this.error ? ' mrd-textarea-field__container--error' : ''}` }, h("div", { key: 'd17c6997602b81e8b7f66f1e5cfb12b4836cb892', class: "mrd-textarea-field__editor" })), this.error && h("span", { key: '30a068872e73ca78781c9a5e1fac2c9e3ce30765', class: "mrd-textarea-field__error" }, this.error))));
3081
+ }
3082
+ get el() { return getElement(this); }
3083
+ };
3084
+ MrdTextareaField.style = mrdTextareaFieldScss();
3085
+
3086
+ const mrdTimeFieldScss = () => `.sc-mrd-time-field-h{display:block}.mrd-time-field.sc-mrd-time-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-time-field__label.sc-mrd-time-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-time-field__label--required.sc-mrd-time-field::after{content:' *';color:var(--mrd-color-danger)}.mrd-time-field__input.sc-mrd-time-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;cursor:pointer}.mrd-time-field__input.sc-mrd-time-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-time-field__input.sc-mrd-time-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.mrd-time-field__input--error.sc-mrd-time-field{border-color:var(--mrd-border-color-error)}.mrd-time-field__input--error.sc-mrd-time-field:focus{box-shadow:var(--mrd-shadow-focus-error)}.mrd-time-field__error.sc-mrd-time-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}`;
3087
+
3088
+ const MrdTimeField = class {
3089
+ constructor(hostRef) {
3090
+ registerInstance(this, hostRef);
3091
+ this.mrdChange = createEvent(this, "mrdChange");
3092
+ this.mrdBlur = createEvent(this, "mrdBlur");
3093
+ this.name = '';
3094
+ this.label = '';
3095
+ this.value = '';
3096
+ this.required = false;
3097
+ this.disabled = false;
3098
+ this.locale = navigator.language;
3099
+ this.error = '';
3100
+ this.handleChange = (e) => {
3101
+ const val = e.target.value;
3102
+ if (this.required && !validateRequired(val)) {
3103
+ this.error = t('required', this.locale);
3104
+ }
3105
+ else {
3106
+ this.error = '';
3107
+ }
3108
+ this.mrdChange.emit({ name: this.name, value: val });
3109
+ };
3110
+ this.handleBlur = (e) => {
3111
+ const val = e.target.value;
3112
+ this.mrdBlur.emit({ name: this.name, value: val });
3113
+ };
3114
+ }
3115
+ render() {
3116
+ const hasError = !!this.error;
3117
+ return (h(Host, { key: '6a6828d9c5224ddfcc5d17124523037512f4970c' }, h("div", { key: '468d5295170cefc93b1e2d49b7189c8366d306b7', class: "mrd-time-field" }, this.label && (h("label", { key: '52ea233ea0a7e8563145c326c4ef9d27557b6dc8', class: `mrd-time-field__label${this.required ? ' mrd-time-field__label--required' : ''}` }, this.label)), h("input", { key: 'e9f0f75517638bf4e4ead95bf69530b5c395f8bc', class: `mrd-time-field__input${hasError ? ' mrd-time-field__input--error' : ''}`, type: "time", name: this.name, value: this.value, required: this.required, disabled: this.disabled, onChange: this.handleChange, onBlur: this.handleBlur }), hasError && h("span", { key: '4f734c3373444df4f686a7ae6bde84a2ee39d9f4', class: "mrd-time-field__error" }, this.error))));
3118
+ }
3119
+ };
3120
+ MrdTimeField.style = mrdTimeFieldScss();
3121
+
3122
+ export { MrdBooleanField as mrd_boolean_field, MrdCurrencyField as mrd_currency_field, MrdDateField as mrd_date_field, MrdDatetimeField as mrd_datetime_field, MrdEmailField as mrd_email_field, MrdField as mrd_field, MrdFileField as mrd_file_field, MrdForm as mrd_form, MrdHyperlinkField as mrd_hyperlink_field, MrdImageField as mrd_image_field, MrdLayoutSection as mrd_layout_section, MrdListField as mrd_list_field, MrdLongtextField as mrd_longtext_field, MrdNumberField as mrd_number_field, MrdRelationField as mrd_relation_field, MrdTable as mrd_table, MrdTextField as mrd_text_field, MrdTextareaField as mrd_textarea_field, MrdTimeField as mrd_time_field };