@mmlogic/components 0.3.5 → 0.3.6

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 (169) hide show
  1. package/dist/{collection/utils/cell-renderer.js → mosterdcomponents/cell-renderer-CbRwLOo8.js} +9 -3
  2. package/dist/mosterdcomponents/cell-renderer-CbRwLOo8.js.map +1 -0
  3. package/dist/{esm/index.js → mosterdcomponents/client-layout-D88nn5zf.js} +4 -1
  4. package/dist/mosterdcomponents/client-layout-D88nn5zf.js.map +1 -0
  5. package/dist/{collection/utils/format.js → mosterdcomponents/format-BAfsQfy1.js} +12 -7
  6. package/dist/mosterdcomponents/format-BAfsQfy1.js.map +1 -0
  7. package/dist/{collection/utils/i18n.js → mosterdcomponents/i18n-hoGGKbKU.js} +6 -1
  8. package/dist/mosterdcomponents/i18n-hoGGKbKU.js.map +1 -0
  9. package/dist/mosterdcomponents/index-B_tPFIvS.js +4585 -0
  10. package/dist/mosterdcomponents/index-B_tPFIvS.js.map +1 -0
  11. package/dist/mosterdcomponents/index-I5SuYv7a.js +4 -0
  12. package/dist/mosterdcomponents/index-I5SuYv7a.js.map +1 -0
  13. package/dist/mosterdcomponents/index.esm.js +5 -1
  14. package/dist/mosterdcomponents/index.esm.js.map +1 -0
  15. package/dist/mosterdcomponents/mosterdcomponents.css +180 -1
  16. package/dist/mosterdcomponents/mosterdcomponents.esm.js +50 -1
  17. package/dist/mosterdcomponents/mosterdcomponents.esm.js.map +1 -0
  18. package/dist/mosterdcomponents/mrd-boolean-field.entry.js +37 -0
  19. package/dist/mosterdcomponents/mrd-boolean-field.entry.js.map +1 -0
  20. package/dist/mosterdcomponents/mrd-currency-field.entry.js +67 -0
  21. package/dist/mosterdcomponents/mrd-currency-field.entry.js.map +1 -0
  22. package/dist/mosterdcomponents/mrd-date-field.entry.js +46 -0
  23. package/dist/mosterdcomponents/mrd-date-field.entry.js.map +1 -0
  24. package/dist/mosterdcomponents/mrd-datetime-field.entry.js +78 -0
  25. package/dist/mosterdcomponents/mrd-datetime-field.entry.js.map +1 -0
  26. package/dist/mosterdcomponents/mrd-email-field.entry.js +50 -0
  27. package/dist/mosterdcomponents/mrd-email-field.entry.js.map +1 -0
  28. package/dist/{collection/components/mrd-field/mrd-field.js → mosterdcomponents/mrd-field.entry.js} +28 -179
  29. package/dist/mosterdcomponents/mrd-field.entry.js.map +1 -0
  30. package/dist/mosterdcomponents/mrd-file-field.entry.js +108 -0
  31. package/dist/mosterdcomponents/mrd-file-field.entry.js.map +1 -0
  32. package/dist/{collection/components/mrd-form/mrd-form.js → mosterdcomponents/mrd-form.entry.js} +31 -308
  33. package/dist/mosterdcomponents/mrd-form.entry.js.map +1 -0
  34. package/dist/mosterdcomponents/mrd-hyperlink-field.entry.js +87 -0
  35. package/dist/mosterdcomponents/mrd-hyperlink-field.entry.js.map +1 -0
  36. package/dist/mosterdcomponents/mrd-image-field.entry.js +122 -0
  37. package/dist/mosterdcomponents/mrd-image-field.entry.js.map +1 -0
  38. package/dist/{collection/components/mrd-layout-section/mrd-layout-section.js → mosterdcomponents/mrd-layout-section.entry.js} +31 -418
  39. package/dist/mosterdcomponents/mrd-layout-section.entry.js.map +1 -0
  40. package/dist/mosterdcomponents/mrd-list-field.entry.js +107 -0
  41. package/dist/mosterdcomponents/mrd-list-field.entry.js.map +1 -0
  42. package/dist/mosterdcomponents/mrd-longtext-field.entry.js +47 -0
  43. package/dist/mosterdcomponents/mrd-longtext-field.entry.js.map +1 -0
  44. package/dist/mosterdcomponents/mrd-number-field.entry.js +87 -0
  45. package/dist/mosterdcomponents/mrd-number-field.entry.js.map +1 -0
  46. package/dist/mosterdcomponents/mrd-relation-field.entry.js +267 -0
  47. package/dist/mosterdcomponents/mrd-relation-field.entry.js.map +1 -0
  48. package/dist/mosterdcomponents/mrd-secret-field.entry.js +49 -0
  49. package/dist/mosterdcomponents/mrd-secret-field.entry.js.map +1 -0
  50. package/dist/{collection/components/mrd-table/mrd-table.js → mosterdcomponents/mrd-table.entry.js} +32 -394
  51. package/dist/mosterdcomponents/mrd-table.entry.js.map +1 -0
  52. package/dist/mosterdcomponents/mrd-text-field.entry.js +47 -0
  53. package/dist/mosterdcomponents/mrd-text-field.entry.js.map +1 -0
  54. package/dist/mosterdcomponents/mrd-textarea-field.entry.js +86 -0
  55. package/dist/mosterdcomponents/mrd-textarea-field.entry.js.map +1 -0
  56. package/dist/mosterdcomponents/mrd-time-field.entry.js +46 -0
  57. package/dist/mosterdcomponents/mrd-time-field.entry.js.map +1 -0
  58. package/dist/{esm/quill-CiuCgGz_.js → mosterdcomponents/quill-C9pgw_k-.js} +16282 -1397
  59. package/dist/mosterdcomponents/quill-C9pgw_k-.js.map +1 -0
  60. package/dist/{collection/utils/validation.js → mosterdcomponents/validation-ixb43cqU.js} +12 -5
  61. package/dist/mosterdcomponents/validation-ixb43cqU.js.map +1 -0
  62. package/package.json +1 -1
  63. package/dist/cjs/app-globals-V2Kpy_OQ.js +0 -5
  64. package/dist/cjs/index-BPj2cBXs.js +0 -1570
  65. package/dist/cjs/index.cjs.js +0 -66
  66. package/dist/cjs/loader.cjs.js +0 -13
  67. package/dist/cjs/mosterdcomponents.cjs.js +0 -25
  68. package/dist/cjs/mrd-boolean-field_20.cjs.entry.js +0 -3961
  69. package/dist/cjs/quill-DmFfnC1f.js +0 -16272
  70. package/dist/collection/collection-manifest.json +0 -32
  71. package/dist/collection/components/mrd-boolean-field/mrd-boolean-field.js +0 -199
  72. package/dist/collection/components/mrd-boolean-field/mrd-boolean-field.scss +0 -77
  73. package/dist/collection/components/mrd-currency-field/mrd-currency-field.js +0 -248
  74. package/dist/collection/components/mrd-currency-field/mrd-currency-field.scss +0 -100
  75. package/dist/collection/components/mrd-date-field/mrd-date-field.js +0 -206
  76. package/dist/collection/components/mrd-date-field/mrd-date-field.scss +0 -66
  77. package/dist/collection/components/mrd-datetime-field/mrd-datetime-field.js +0 -240
  78. package/dist/collection/components/mrd-datetime-field/mrd-datetime-field.scss +0 -66
  79. package/dist/collection/components/mrd-email-field/mrd-email-field.js +0 -230
  80. package/dist/collection/components/mrd-email-field/mrd-email-field.scss +0 -69
  81. package/dist/collection/components/mrd-field/mrd-field.scss +0 -118
  82. package/dist/collection/components/mrd-file-field/mrd-file-field.js +0 -341
  83. package/dist/collection/components/mrd-file-field/mrd-file-field.scss +0 -153
  84. package/dist/collection/components/mrd-form/mrd-form.scss +0 -148
  85. package/dist/collection/components/mrd-hyperlink-field/mrd-hyperlink-field.js +0 -291
  86. package/dist/collection/components/mrd-hyperlink-field/mrd-hyperlink-field.scss +0 -91
  87. package/dist/collection/components/mrd-image-field/mrd-image-field.js +0 -356
  88. package/dist/collection/components/mrd-image-field/mrd-image-field.scss +0 -190
  89. package/dist/collection/components/mrd-layout-section/mrd-layout-section.scss +0 -445
  90. package/dist/collection/components/mrd-list-field/mrd-list-field.js +0 -313
  91. package/dist/collection/components/mrd-list-field/mrd-list-field.scss +0 -109
  92. package/dist/collection/components/mrd-longtext-field/mrd-longtext-field.js +0 -227
  93. package/dist/collection/components/mrd-longtext-field/mrd-longtext-field.scss +0 -78
  94. package/dist/collection/components/mrd-number-field/mrd-number-field.js +0 -316
  95. package/dist/collection/components/mrd-number-field/mrd-number-field.scss +0 -77
  96. package/dist/collection/components/mrd-relation-field/mrd-relation-field.js +0 -707
  97. package/dist/collection/components/mrd-relation-field/mrd-relation-field.scss +0 -266
  98. package/dist/collection/components/mrd-secret-field/mrd-secret-field.js +0 -229
  99. package/dist/collection/components/mrd-secret-field/mrd-secret-field.scss +0 -73
  100. package/dist/collection/components/mrd-table/mrd-table.scss +0 -809
  101. package/dist/collection/components/mrd-text-field/mrd-text-field.js +0 -227
  102. package/dist/collection/components/mrd-text-field/mrd-text-field.scss +0 -69
  103. package/dist/collection/components/mrd-textarea-field/mrd-textarea-field.js +0 -267
  104. package/dist/collection/components/mrd-textarea-field/mrd-textarea-field.scss +0 -135
  105. package/dist/collection/components/mrd-time-field/mrd-time-field.js +0 -206
  106. package/dist/collection/components/mrd-time-field/mrd-time-field.scss +0 -66
  107. package/dist/collection/dev/api.js +0 -145
  108. package/dist/collection/dev/app.js +0 -890
  109. package/dist/collection/dev/auth.js +0 -156
  110. package/dist/collection/dev/example-data.js +0 -403
  111. package/dist/collection/dev/sprites.svg +0 -55
  112. package/dist/collection/index.js +0 -1
  113. package/dist/collection/types/client-layout.js +0 -64
  114. package/dist/collection/types/index.js +0 -1
  115. package/dist/components/client-layout.js +0 -1
  116. package/dist/components/format.js +0 -1
  117. package/dist/components/i18n.js +0 -1
  118. package/dist/components/index.js +0 -1
  119. package/dist/components/mrd-boolean-field.js +0 -1
  120. package/dist/components/mrd-boolean-field2.js +0 -1
  121. package/dist/components/mrd-currency-field.js +0 -1
  122. package/dist/components/mrd-currency-field2.js +0 -1
  123. package/dist/components/mrd-date-field.js +0 -1
  124. package/dist/components/mrd-date-field2.js +0 -1
  125. package/dist/components/mrd-datetime-field.js +0 -1
  126. package/dist/components/mrd-datetime-field2.js +0 -1
  127. package/dist/components/mrd-email-field.js +0 -1
  128. package/dist/components/mrd-email-field2.js +0 -1
  129. package/dist/components/mrd-field.js +0 -1
  130. package/dist/components/mrd-field2.js +0 -1
  131. package/dist/components/mrd-file-field.js +0 -1
  132. package/dist/components/mrd-file-field2.js +0 -1
  133. package/dist/components/mrd-form.js +0 -1
  134. package/dist/components/mrd-hyperlink-field.js +0 -1
  135. package/dist/components/mrd-hyperlink-field2.js +0 -1
  136. package/dist/components/mrd-image-field.js +0 -1
  137. package/dist/components/mrd-image-field2.js +0 -1
  138. package/dist/components/mrd-layout-section.js +0 -1
  139. package/dist/components/mrd-list-field.js +0 -1
  140. package/dist/components/mrd-list-field2.js +0 -1
  141. package/dist/components/mrd-longtext-field.js +0 -1
  142. package/dist/components/mrd-longtext-field2.js +0 -1
  143. package/dist/components/mrd-number-field.js +0 -1
  144. package/dist/components/mrd-number-field2.js +0 -1
  145. package/dist/components/mrd-relation-field.js +0 -1
  146. package/dist/components/mrd-relation-field2.js +0 -1
  147. package/dist/components/mrd-secret-field.js +0 -1
  148. package/dist/components/mrd-secret-field2.js +0 -1
  149. package/dist/components/mrd-table.js +0 -1
  150. package/dist/components/mrd-table2.js +0 -1
  151. package/dist/components/mrd-text-field.js +0 -1
  152. package/dist/components/mrd-text-field2.js +0 -1
  153. package/dist/components/mrd-textarea-field.js +0 -1
  154. package/dist/components/mrd-textarea-field2.js +0 -1
  155. package/dist/components/mrd-time-field.js +0 -1
  156. package/dist/components/mrd-time-field2.js +0 -1
  157. package/dist/components/quill.js +0 -1
  158. package/dist/components/validation.js +0 -1
  159. package/dist/esm/app-globals-DQuL1Twl.js +0 -3
  160. package/dist/esm/index-_tsCCkAi.js +0 -1561
  161. package/dist/esm/loader.js +0 -11
  162. package/dist/esm/mosterdcomponents.js +0 -21
  163. package/dist/esm/mrd-boolean-field_20.entry.js +0 -3940
  164. package/dist/index.cjs.js +0 -1
  165. package/dist/index.js +0 -1
  166. package/dist/mosterdcomponents/p-CiuCgGz_.js +0 -1
  167. package/dist/mosterdcomponents/p-DQuL1Twl.js +0 -1
  168. package/dist/mosterdcomponents/p-_tsCCkAi.js +0 -2
  169. package/dist/mosterdcomponents/p-e477187c.entry.js +0 -1
@@ -1,3940 +0,0 @@
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
- // history badge
95
- history_until: 'tot',
96
- history_badge_tooltip: 'Vorige waarden',
97
- hyperlink_name: 'Linktekst (optioneel)',
98
- },
99
- en: {
100
- required: 'This field is required',
101
- select_placeholder: 'Select an option',
102
- search_placeholder: 'Search...',
103
- upload_file: 'Upload file',
104
- choose_file: 'Choose file',
105
- clear: 'Clear',
106
- today: 'Today',
107
- invalid_email: 'Please enter a valid email address',
108
- invalid_url: 'Please enter a valid URL',
109
- invalid_number: 'Please enter a valid number',
110
- drop_file_here: 'Drop file here or',
111
- browse: 'browse',
112
- file_too_large: 'File is too large',
113
- search_results: 'Search results',
114
- no_results: 'No results found',
115
- loading: 'Loading...',
116
- submit: 'Save',
117
- cancel: 'Cancel',
118
- remove: 'Remove',
119
- add: 'Add',
120
- yes: 'Yes',
121
- no: 'No',
122
- // mrd-table footer
123
- table_of: 'of',
124
- download: 'Download',
125
- // mrd-table toolbar
126
- table_filter: 'Filter',
127
- table_filter_hide: 'Hide filter',
128
- table_filter_active: 'active',
129
- table_filter_clear_all: 'Clear all filters',
130
- table_new_record: 'New record',
131
- table_export_excel: 'Export to Excel',
132
- // mrd-table filter popup
133
- filter_sorting: 'Sorting',
134
- filter_ascending: 'Ascending',
135
- filter_descending: 'Descending',
136
- filter_section: 'Filter',
137
- filter_apply: 'Apply',
138
- filter_clear: 'Clear',
139
- filter_contains: 'Contains',
140
- filter_starts_with: 'Starts with',
141
- filter_equals: 'Equals',
142
- filter_has_value: 'Has value',
143
- filter_is_empty: 'Is empty',
144
- filter_is_not_empty: 'Is not empty',
145
- filter_exact: 'Exact',
146
- filter_range: 'Range',
147
- filter_from: 'From',
148
- filter_to: 'To',
149
- filter_all: 'All',
150
- filter_select_all: 'All',
151
- filter_select_none: 'None',
152
- filter_search_value: 'Search value...',
153
- filter_no_support: 'Filtering is not available for this field type.',
154
- // mrd-table textblock
155
- textblock_show_more: 'Show more',
156
- close: 'Close',
157
- // history badge
158
- history_until: 'until',
159
- history_badge_tooltip: 'Previous values',
160
- hyperlink_name: 'Link text (optional)',
161
- },
162
- ar: {
163
- required: 'هذا الحقل مطلوب',
164
- select_placeholder: 'اختر خياراً',
165
- search_placeholder: 'بحث...',
166
- upload_file: 'رفع ملف',
167
- choose_file: 'اختر ملفاً',
168
- clear: 'مسح',
169
- today: 'اليوم',
170
- invalid_email: 'يرجى إدخال عنوان بريد إلكتروني صحيح',
171
- invalid_url: 'يرجى إدخال رابط صحيح',
172
- invalid_number: 'يرجى إدخال رقم صحيح',
173
- drop_file_here: 'اسحب الملف هنا أو',
174
- browse: 'تصفح',
175
- file_too_large: 'الملف كبير جداً',
176
- search_results: 'نتائج البحث',
177
- no_results: 'لم يتم العثور على نتائج',
178
- loading: 'جار التحميل...',
179
- submit: 'حفظ',
180
- cancel: 'إلغاء',
181
- remove: 'إزالة',
182
- add: 'إضافة',
183
- yes: 'نعم',
184
- no: 'لا',
185
- // mrd-table footer
186
- table_of: 'من أصل',
187
- download: 'تنزيل',
188
- // mrd-table toolbar
189
- table_filter: 'تصفية',
190
- table_filter_hide: 'إخفاء التصفية',
191
- table_filter_active: 'نشط',
192
- table_filter_clear_all: 'مسح جميع الفلاتر',
193
- table_new_record: 'سجل جديد',
194
- table_export_excel: 'تصدير إلى Excel',
195
- // mrd-table filter popup
196
- filter_sorting: 'الترتيب',
197
- filter_ascending: 'تصاعدي',
198
- filter_descending: 'تنازلي',
199
- filter_section: 'تصفية',
200
- filter_apply: 'تطبيق',
201
- filter_clear: 'مسح',
202
- filter_contains: 'يحتوي على',
203
- filter_starts_with: 'يبدأ بـ',
204
- filter_equals: 'يساوي',
205
- filter_has_value: 'له قيمة',
206
- filter_is_empty: 'فارغ',
207
- filter_is_not_empty: 'ليس فارغاً',
208
- filter_exact: 'دقيق',
209
- filter_range: 'نطاق',
210
- filter_from: 'من',
211
- filter_to: 'إلى',
212
- filter_all: 'الكل',
213
- filter_select_all: 'الكل',
214
- filter_select_none: 'لا شيء',
215
- filter_search_value: 'قيمة البحث...',
216
- filter_no_support: 'التصفية غير متاحة لهذا النوع من الحقول.',
217
- // mrd-table textblock
218
- textblock_show_more: 'عرض المزيد',
219
- close: 'إغلاق',
220
- // history badge
221
- history_until: 'حتى',
222
- history_badge_tooltip: 'القيم السابقة',
223
- hyperlink_name: 'نص الرابط (اختياري)',
224
- },
225
- fr: {
226
- required: 'Ce champ est obligatoire',
227
- select_placeholder: 'Sélectionner une option',
228
- search_placeholder: 'Rechercher...',
229
- upload_file: 'Télécharger un fichier',
230
- choose_file: 'Choisir un fichier',
231
- clear: 'Effacer',
232
- today: "Aujourd'hui",
233
- invalid_email: 'Veuillez saisir une adresse e-mail valide',
234
- invalid_url: 'Veuillez saisir une URL valide',
235
- invalid_number: 'Veuillez saisir un nombre valide',
236
- drop_file_here: 'Déposez le fichier ici ou',
237
- browse: 'parcourir',
238
- file_too_large: 'Le fichier est trop volumineux',
239
- search_results: 'Résultats de recherche',
240
- no_results: 'Aucun résultat trouvé',
241
- loading: 'Chargement...',
242
- submit: 'Enregistrer',
243
- cancel: 'Annuler',
244
- remove: 'Supprimer',
245
- add: 'Ajouter',
246
- yes: 'Oui',
247
- no: 'Non',
248
- // mrd-table footer
249
- table_of: 'sur',
250
- download: 'Télécharger',
251
- // mrd-table toolbar
252
- table_filter: 'Filtrer',
253
- table_filter_hide: 'Masquer le filtre',
254
- table_filter_active: 'actif',
255
- table_filter_clear_all: 'Effacer tous les filtres',
256
- table_new_record: 'Nouvel enregistrement',
257
- table_export_excel: 'Exporter vers Excel',
258
- // mrd-table filter popup
259
- filter_sorting: 'Tri',
260
- filter_ascending: 'Croissant',
261
- filter_descending: 'Décroissant',
262
- filter_section: 'Filtre',
263
- filter_apply: 'Appliquer',
264
- filter_clear: 'Effacer',
265
- filter_contains: 'Contient',
266
- filter_starts_with: 'Commence par',
267
- filter_equals: 'Égal à',
268
- filter_has_value: 'A une valeur',
269
- filter_is_empty: 'Est vide',
270
- filter_is_not_empty: "N'est pas vide",
271
- filter_exact: 'Exact',
272
- filter_range: 'Plage',
273
- filter_from: 'De',
274
- filter_to: 'À',
275
- filter_all: 'Tous',
276
- filter_select_all: 'Tous',
277
- filter_select_none: 'Aucun',
278
- filter_search_value: 'Valeur de recherche...',
279
- filter_no_support: "Le filtrage n'est pas disponible pour ce type de champ.",
280
- // mrd-table textblock
281
- textblock_show_more: 'Voir plus',
282
- close: 'Fermer',
283
- // history badge
284
- history_until: "jusqu'au",
285
- history_badge_tooltip: 'Valeurs précédentes',
286
- hyperlink_name: 'Texte du lien (optionnel)',
287
- },
288
- de: {
289
- required: 'Dieses Feld ist erforderlich',
290
- select_placeholder: 'Option auswählen',
291
- search_placeholder: 'Suchen...',
292
- upload_file: 'Datei hochladen',
293
- choose_file: 'Datei auswählen',
294
- clear: 'Löschen',
295
- today: 'Heute',
296
- invalid_email: 'Bitte geben Sie eine gültige E-Mail-Adresse ein',
297
- invalid_url: 'Bitte geben Sie eine gültige URL ein',
298
- invalid_number: 'Bitte geben Sie eine gültige Zahl ein',
299
- drop_file_here: 'Datei hier ablegen oder',
300
- browse: 'durchsuchen',
301
- file_too_large: 'Datei ist zu groß',
302
- search_results: 'Suchergebnisse',
303
- no_results: 'Keine Ergebnisse gefunden',
304
- loading: 'Laden...',
305
- submit: 'Speichern',
306
- cancel: 'Abbrechen',
307
- remove: 'Entfernen',
308
- add: 'Hinzufügen',
309
- yes: 'Ja',
310
- no: 'Nein',
311
- // mrd-table footer
312
- table_of: 'von',
313
- download: 'Herunterladen',
314
- // mrd-table toolbar
315
- table_filter: 'Filtern',
316
- table_filter_hide: 'Filter ausblenden',
317
- table_filter_active: 'aktiv',
318
- table_filter_clear_all: 'Alle Filter löschen',
319
- table_new_record: 'Neuer Eintrag',
320
- table_export_excel: 'Als Excel exportieren',
321
- // mrd-table filter popup
322
- filter_sorting: 'Sortierung',
323
- filter_ascending: 'Aufsteigend',
324
- filter_descending: 'Absteigend',
325
- filter_section: 'Filter',
326
- filter_apply: 'Anwenden',
327
- filter_clear: 'Löschen',
328
- filter_contains: 'Enthält',
329
- filter_starts_with: 'Beginnt mit',
330
- filter_equals: 'Gleich',
331
- filter_has_value: 'Hat Wert',
332
- filter_is_empty: 'Ist leer',
333
- filter_is_not_empty: 'Ist nicht leer',
334
- filter_exact: 'Genau',
335
- filter_range: 'Bereich',
336
- filter_from: 'Von',
337
- filter_to: 'Bis',
338
- filter_all: 'Alle',
339
- filter_select_all: 'Alle',
340
- filter_select_none: 'Keine',
341
- filter_search_value: 'Suchwert...',
342
- filter_no_support: 'Filterung ist für diesen Feldtyp nicht verfügbar.',
343
- // mrd-table textblock
344
- textblock_show_more: 'Mehr anzeigen',
345
- close: 'Schließen',
346
- // history badge
347
- history_until: 'bis',
348
- history_badge_tooltip: 'Vorherige Werte',
349
- hyperlink_name: 'Linktext (optional)',
350
- },
351
- es: {
352
- required: 'Este campo es obligatorio',
353
- select_placeholder: 'Seleccionar una opción',
354
- search_placeholder: 'Buscar...',
355
- upload_file: 'Subir archivo',
356
- choose_file: 'Elegir archivo',
357
- clear: 'Borrar',
358
- today: 'Hoy',
359
- invalid_email: 'Por favor, introduzca una dirección de correo electrónico válida',
360
- invalid_url: 'Por favor, introduzca una URL válida',
361
- invalid_number: 'Por favor, introduzca un número válido',
362
- drop_file_here: 'Suelte el archivo aquí o',
363
- browse: 'explorar',
364
- file_too_large: 'El archivo es demasiado grande',
365
- search_results: 'Resultados de búsqueda',
366
- no_results: 'No se encontraron resultados',
367
- loading: 'Cargando...',
368
- submit: 'Guardar',
369
- cancel: 'Cancelar',
370
- remove: 'Eliminar',
371
- add: 'Añadir',
372
- yes: 'Sí',
373
- no: 'No',
374
- // mrd-table footer
375
- table_of: 'de',
376
- download: 'Descargar',
377
- // mrd-table toolbar
378
- table_filter: 'Filtrar',
379
- table_filter_hide: 'Ocultar filtro',
380
- table_filter_active: 'activo',
381
- table_filter_clear_all: 'Borrar todos los filtros',
382
- table_new_record: 'Nuevo registro',
383
- table_export_excel: 'Exportar a Excel',
384
- // mrd-table filter popup
385
- filter_sorting: 'Ordenación',
386
- filter_ascending: 'Ascendente',
387
- filter_descending: 'Descendente',
388
- filter_section: 'Filtro',
389
- filter_apply: 'Aplicar',
390
- filter_clear: 'Borrar',
391
- filter_contains: 'Contiene',
392
- filter_starts_with: 'Empieza por',
393
- filter_equals: 'Igual a',
394
- filter_has_value: 'Tiene valor',
395
- filter_is_empty: 'Está vacío',
396
- filter_is_not_empty: 'No está vacío',
397
- filter_exact: 'Exacto',
398
- filter_range: 'Rango',
399
- filter_from: 'Desde',
400
- filter_to: 'Hasta',
401
- filter_all: 'Todos',
402
- filter_select_all: 'Todos',
403
- filter_select_none: 'Ninguno',
404
- filter_search_value: 'Valor de búsqueda...',
405
- filter_no_support: 'El filtrado no está disponible para este tipo de campo.',
406
- // mrd-table textblock
407
- textblock_show_more: 'Mostrar más',
408
- close: 'Cerrar',
409
- // history badge
410
- history_until: 'hasta',
411
- history_badge_tooltip: 'Valores anteriores',
412
- hyperlink_name: 'Texto del enlace (opcional)',
413
- },
414
- it: {
415
- required: 'Questo campo è obbligatorio',
416
- select_placeholder: "Seleziona un'opzione",
417
- search_placeholder: 'Cerca...',
418
- upload_file: 'Carica file',
419
- choose_file: 'Scegli file',
420
- clear: 'Cancella',
421
- today: 'Oggi',
422
- invalid_email: 'Inserisci un indirizzo email valido',
423
- invalid_url: 'Inserisci un URL valido',
424
- invalid_number: 'Inserisci un numero valido',
425
- drop_file_here: 'Trascina il file qui o',
426
- browse: 'sfoglia',
427
- file_too_large: 'Il file è troppo grande',
428
- search_results: 'Risultati della ricerca',
429
- no_results: 'Nessun risultato trovato',
430
- loading: 'Caricamento...',
431
- submit: 'Salva',
432
- cancel: 'Annulla',
433
- remove: 'Rimuovi',
434
- add: 'Aggiungi',
435
- yes: 'Sì',
436
- no: 'No',
437
- // mrd-table footer
438
- table_of: 'di',
439
- download: 'Scarica',
440
- // mrd-table toolbar
441
- table_filter: 'Filtra',
442
- table_filter_hide: 'Nascondi filtro',
443
- table_filter_active: 'attivo',
444
- table_filter_clear_all: 'Cancella tutti i filtri',
445
- table_new_record: 'Nuovo record',
446
- table_export_excel: 'Esporta in Excel',
447
- // mrd-table filter popup
448
- filter_sorting: 'Ordinamento',
449
- filter_ascending: 'Crescente',
450
- filter_descending: 'Decrescente',
451
- filter_section: 'Filtro',
452
- filter_apply: 'Applica',
453
- filter_clear: 'Cancella',
454
- filter_contains: 'Contiene',
455
- filter_starts_with: 'Inizia con',
456
- filter_equals: 'Uguale a',
457
- filter_has_value: 'Ha valore',
458
- filter_is_empty: 'È vuoto',
459
- filter_is_not_empty: 'Non è vuoto',
460
- filter_exact: 'Esatto',
461
- filter_range: 'Intervallo',
462
- filter_from: 'Da',
463
- filter_to: 'A',
464
- filter_all: 'Tutti',
465
- filter_select_all: 'Tutti',
466
- filter_select_none: 'Nessuno',
467
- filter_search_value: 'Valore di ricerca...',
468
- filter_no_support: 'Il filtro non è disponibile per questo tipo di campo.',
469
- // mrd-table textblock
470
- textblock_show_more: 'Mostra altro',
471
- close: 'Chiudi',
472
- // history badge
473
- history_until: 'fino a',
474
- history_badge_tooltip: 'Valori precedenti',
475
- hyperlink_name: 'Testo del collegamento (opzionale)',
476
- },
477
- uk: {
478
- required: "Це поле обов'язкове",
479
- select_placeholder: 'Виберіть варіант',
480
- search_placeholder: 'Пошук...',
481
- upload_file: 'Завантажити файл',
482
- choose_file: 'Вибрати файл',
483
- clear: 'Очистити',
484
- today: 'Сьогодні',
485
- invalid_email: 'Будь ласка, введіть дійсну адресу електронної пошти',
486
- invalid_url: 'Будь ласка, введіть дійсну URL-адресу',
487
- invalid_number: 'Будь ласка, введіть дійсне число',
488
- drop_file_here: 'Перетягніть файл сюди або',
489
- browse: 'огляд',
490
- file_too_large: 'Файл занадто великий',
491
- search_results: 'Результати пошуку',
492
- no_results: 'Результатів не знайдено',
493
- loading: 'Завантаження...',
494
- submit: 'Зберегти',
495
- cancel: 'Скасувати',
496
- remove: 'Видалити',
497
- add: 'Додати',
498
- yes: 'Так',
499
- no: 'Ні',
500
- // mrd-table footer
501
- table_of: 'з',
502
- download: 'Завантажити',
503
- // mrd-table toolbar
504
- table_filter: 'Фільтрувати',
505
- table_filter_hide: 'Сховати фільтр',
506
- table_filter_active: 'активний',
507
- table_filter_clear_all: 'Очистити всі фільтри',
508
- table_new_record: 'Новий запис',
509
- table_export_excel: 'Експортувати до Excel',
510
- // mrd-table filter popup
511
- filter_sorting: 'Сортування',
512
- filter_ascending: 'За зростанням',
513
- filter_descending: 'За спаданням',
514
- filter_section: 'Фільтр',
515
- filter_apply: 'Застосувати',
516
- filter_clear: 'Очистити',
517
- filter_contains: 'Містить',
518
- filter_starts_with: 'Починається з',
519
- filter_equals: 'Дорівнює',
520
- filter_has_value: 'Має значення',
521
- filter_is_empty: 'Порожнє',
522
- filter_is_not_empty: 'Не порожнє',
523
- filter_exact: 'Точно',
524
- filter_range: 'Діапазон',
525
- filter_from: 'Від',
526
- filter_to: 'До',
527
- filter_all: 'Всі',
528
- filter_select_all: 'Всі',
529
- filter_select_none: 'Жодного',
530
- filter_search_value: 'Значення для пошуку...',
531
- filter_no_support: 'Фільтрування недоступне для цього типу поля.',
532
- // mrd-table textblock
533
- textblock_show_more: 'Показати більше',
534
- close: 'Закрити',
535
- // history badge
536
- history_until: 'до',
537
- history_badge_tooltip: 'Попередні значення',
538
- hyperlink_name: "Текст посилання (необов'язково)",
539
- },
540
- };
541
- function t(key, locale) {
542
- var _a, _b, _c;
543
- const lang = (locale !== null && locale !== void 0 ? locale : 'en').split('-')[0].toLowerCase();
544
- const dict = (_a = translations[lang]) !== null && _a !== void 0 ? _a : translations['en'];
545
- return (_c = (_b = dict[key]) !== null && _b !== void 0 ? _b : translations['en'][key]) !== null && _c !== void 0 ? _c : key;
546
- }
547
-
548
- function validateRequired(value) {
549
- if (value === null || value === undefined)
550
- return false;
551
- if (typeof value === 'string')
552
- return value.trim().length > 0;
553
- if (Array.isArray(value))
554
- return value.length > 0;
555
- if (typeof value === 'object') {
556
- // HyperlinkValue check
557
- const hv = value;
558
- if ('href' in hv)
559
- return typeof hv.href === 'string' && hv.href.trim().length > 0;
560
- // CurrencyValue check
561
- const cv = value;
562
- if ('amount' in cv)
563
- return cv.amount !== null && cv.amount !== undefined && cv.amount !== '';
564
- }
565
- return true;
566
- }
567
- function validateEmail(value) {
568
- if (!value)
569
- return true;
570
- return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
571
- }
572
- function validateUrl(value) {
573
- if (!value)
574
- return true;
575
- try {
576
- const url = new URL(value);
577
- return url.protocol === 'http:' || url.protocol === 'https:';
578
- }
579
- catch (_a) {
580
- return false;
581
- }
582
- }
583
- function validateNumber(value, dataType) {
584
- if (value === null || value === undefined || value === '')
585
- return true;
586
- const num = Number(value);
587
- if (isNaN(num))
588
- return false;
589
- if (dataType === ClientLayoutItemFieldDataType.INTEGER) {
590
- return Number.isInteger(num);
591
- }
592
- if (dataType === ClientLayoutItemFieldDataType.PERCENTAGE) {
593
- return num >= 0 && num <= 100;
594
- }
595
- return true;
596
- }
597
-
598
- function formatNumber(value, locale, options) {
599
- if (value === null || value === undefined || isNaN(value))
600
- return '';
601
- return new Intl.NumberFormat(locale, options).format(value);
602
- }
603
- function formatCurrency(amount, currency, locale) {
604
- if (amount === null || amount === undefined || isNaN(amount))
605
- return '';
606
- return new Intl.NumberFormat(locale, {
607
- style: 'currency',
608
- currency,
609
- minimumFractionDigits: 2,
610
- maximumFractionDigits: 2,
611
- }).format(amount);
612
- }
613
- function formatPercentage(value, locale, decimalPrecision = 2) {
614
- if (value === null || value === undefined || isNaN(value))
615
- return '';
616
- return new Intl.NumberFormat(locale, {
617
- style: 'percent',
618
- minimumFractionDigits: decimalPrecision,
619
- maximumFractionDigits: decimalPrecision,
620
- }).format(value);
621
- }
622
- function formatDate(value, locale) {
623
- if (!value)
624
- return '';
625
- const date = typeof value === 'string' ? new Date(value) : value;
626
- if (isNaN(date.getTime()))
627
- return '';
628
- return new Intl.DateTimeFormat(locale, { year: 'numeric', month: '2-digit', day: '2-digit' }).format(date);
629
- }
630
- function formatDateTime(value, locale) {
631
- if (!value)
632
- return '';
633
- const date = typeof value === 'string' ? new Date(value) : value;
634
- if (isNaN(date.getTime()))
635
- return '';
636
- return new Intl.DateTimeFormat(locale, {
637
- year: 'numeric',
638
- month: '2-digit',
639
- day: '2-digit',
640
- hour: '2-digit',
641
- minute: '2-digit',
642
- }).format(date);
643
- }
644
- function formatTime(value, locale) {
645
- if (!value)
646
- return '';
647
- // value is HH:MM or HH:MM:SS
648
- const [hours, minutes] = value.split(':').map(Number);
649
- const date = new Date();
650
- date.setHours(hours, minutes, 0, 0);
651
- return new Intl.DateTimeFormat(locale, { hour: '2-digit', minute: '2-digit' }).format(date);
652
- }
653
- function parseLocalizedNumber(str, locale) {
654
- var _a, _b, _c, _d;
655
- if (!str || !str.trim())
656
- return null;
657
- // Detect decimal and thousands separators from the locale
658
- const parts = new Intl.NumberFormat(locale).formatToParts(1234567.89);
659
- const groupSep = (_b = (_a = parts.find((p) => p.type === 'group')) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : ',';
660
- const decimalSep = (_d = (_c = parts.find((p) => p.type === 'decimal')) === null || _c === void 0 ? void 0 : _c.value) !== null && _d !== void 0 ? _d : '.';
661
- // Remove group separators, replace decimal separator with '.'
662
- const normalized = str
663
- .replace(new RegExp(`\\${groupSep}`, 'g'), '')
664
- .replace(new RegExp(`\\${decimalSep}`), '.')
665
- .replace('%', '')
666
- .trim();
667
- const parsed = parseFloat(normalized);
668
- return isNaN(parsed) ? null : parsed;
669
- }
670
-
671
- 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)}`;
672
-
673
- const COMMON_CURRENCIES = [
674
- 'EUR', 'USD', 'GBP', 'CHF', 'JPY', 'CNY', 'AUD', 'CAD',
675
- 'SEK', 'NOK', 'DKK', 'NZD', 'SGD', 'HKD', 'PLN', 'CZK',
676
- 'HUF', 'MXN', 'BRL', 'INR', 'TRY', 'ZAR', 'AED', 'SAR',
677
- ];
678
- const MrdCurrencyField = class {
679
- constructor(hostRef) {
680
- registerInstance(this, hostRef);
681
- this.mrdChange = createEvent(this, "mrdChange");
682
- this.mrdBlur = createEvent(this, "mrdBlur");
683
- this.name = '';
684
- this.label = '';
685
- this.value = { amount: null, currency: 'EUR' };
686
- this.required = false;
687
- this.disabled = false;
688
- this.locale = navigator.language;
689
- this.amountDisplay = '';
690
- this.currency = 'EUR';
691
- this.error = '';
692
- this.handleAmountInput = (e) => {
693
- this.amountDisplay = e.target.value;
694
- };
695
- this.handleAmountBlur = (e) => {
696
- const raw = e.target.value;
697
- const parsed = parseLocalizedNumber(raw, this.locale);
698
- if (this.required && !validateRequired(raw)) {
699
- this.error = t('required', this.locale);
700
- }
701
- else {
702
- this.error = '';
703
- }
704
- const val = { amount: parsed, currency: this.currency };
705
- this.mrdChange.emit({ name: this.name, value: val });
706
- this.mrdBlur.emit({ name: this.name, value: val });
707
- };
708
- this.handleCurrencyChange = (e) => {
709
- this.currency = e.target.value;
710
- const parsed = parseLocalizedNumber(this.amountDisplay, this.locale);
711
- this.mrdChange.emit({ name: this.name, value: { amount: parsed, currency: this.currency } });
712
- };
713
- }
714
- componentWillLoad() {
715
- if (this.value) {
716
- this.currency = this.value.currency || 'EUR';
717
- this.amountDisplay = this.value.amount !== null ? String(this.value.amount) : '';
718
- }
719
- }
720
- render() {
721
- const hasError = !!this.error;
722
- 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))));
723
- }
724
- };
725
- MrdCurrencyField.style = mrdCurrencyFieldScss();
726
-
727
- 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)}`;
728
-
729
- const MrdDateField = class {
730
- constructor(hostRef) {
731
- registerInstance(this, hostRef);
732
- this.mrdChange = createEvent(this, "mrdChange");
733
- this.mrdBlur = createEvent(this, "mrdBlur");
734
- this.name = '';
735
- this.label = '';
736
- this.value = '';
737
- this.required = false;
738
- this.disabled = false;
739
- this.locale = navigator.language;
740
- this.error = '';
741
- this.handleChange = (e) => {
742
- const val = e.target.value;
743
- if (this.required && !validateRequired(val)) {
744
- this.error = t('required', this.locale);
745
- }
746
- else {
747
- this.error = '';
748
- }
749
- this.mrdChange.emit({ name: this.name, value: val });
750
- };
751
- this.handleBlur = (e) => {
752
- const val = e.target.value;
753
- this.mrdBlur.emit({ name: this.name, value: val });
754
- };
755
- }
756
- render() {
757
- const hasError = !!this.error;
758
- 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))));
759
- }
760
- };
761
- MrdDateField.style = mrdDateFieldScss();
762
-
763
- 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)}`;
764
-
765
- const MrdDatetimeField = class {
766
- constructor(hostRef) {
767
- registerInstance(this, hostRef);
768
- this.mrdChange = createEvent(this, "mrdChange");
769
- this.mrdBlur = createEvent(this, "mrdBlur");
770
- this.name = '';
771
- this.label = '';
772
- this.value = '';
773
- this.required = false;
774
- this.disabled = false;
775
- this.locale = navigator.language;
776
- this.error = '';
777
- this.localValue = '';
778
- this.handleChange = (e) => {
779
- const localVal = e.target.value;
780
- this.localValue = localVal;
781
- if (this.required && !validateRequired(localVal)) {
782
- this.error = t('required', this.locale);
783
- }
784
- else {
785
- this.error = '';
786
- }
787
- this.mrdChange.emit({ name: this.name, value: this.localToUtc(localVal) });
788
- };
789
- this.handleBlur = (e) => {
790
- const localVal = e.target.value;
791
- this.mrdBlur.emit({ name: this.name, value: this.localToUtc(localVal) });
792
- };
793
- }
794
- componentWillLoad() {
795
- this.localValue = this.utcToLocal(this.value);
796
- }
797
- valueChanged(newVal) {
798
- this.localValue = this.utcToLocal(newVal);
799
- }
800
- // UTC ISO string → "YYYY-MM-DDTHH:mm" in local timezone (for datetime-local input)
801
- utcToLocal(utcStr) {
802
- if (!utcStr)
803
- return '';
804
- const d = new Date(utcStr);
805
- if (isNaN(d.getTime()))
806
- return '';
807
- const pad = (n) => String(n).padStart(2, '0');
808
- return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;
809
- }
810
- // "YYYY-MM-DDTHH:mm" local time → UTC ISO string (for API)
811
- localToUtc(localStr) {
812
- if (!localStr)
813
- return '';
814
- const d = new Date(localStr);
815
- if (isNaN(d.getTime()))
816
- return '';
817
- return d.toISOString().replace(/\.\d{3}Z$/, 'Z');
818
- }
819
- render() {
820
- const hasError = !!this.error;
821
- 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))));
822
- }
823
- static get watchers() { return {
824
- "value": [{
825
- "valueChanged": 0
826
- }]
827
- }; }
828
- };
829
- MrdDatetimeField.style = mrdDatetimeFieldScss();
830
-
831
- 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)}`;
832
-
833
- const MrdEmailField = class {
834
- constructor(hostRef) {
835
- registerInstance(this, hostRef);
836
- this.mrdChange = createEvent(this, "mrdChange");
837
- this.mrdBlur = createEvent(this, "mrdBlur");
838
- this.name = '';
839
- this.label = '';
840
- this.value = '';
841
- this.placeholder = '';
842
- this.required = false;
843
- this.disabled = false;
844
- this.locale = navigator.language;
845
- this.error = '';
846
- this.handleInput = (e) => {
847
- const val = e.target.value;
848
- this.mrdChange.emit({ name: this.name, value: val });
849
- };
850
- this.handleBlur = (e) => {
851
- const val = e.target.value;
852
- if (this.required && !validateRequired(val)) {
853
- this.error = t('required', this.locale);
854
- }
855
- else if (val && !validateEmail(val)) {
856
- this.error = t('invalid_email', this.locale);
857
- }
858
- else {
859
- this.error = '';
860
- }
861
- this.mrdBlur.emit({ name: this.name, value: val });
862
- };
863
- }
864
- render() {
865
- const hasError = !!this.error;
866
- 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))));
867
- }
868
- };
869
- MrdEmailField.style = mrdEmailFieldScss();
870
-
871
- const mrdFieldScss = () => `.sc-mrd-field-h{display:block}.mrd-field__inner.sc-mrd-field{display:block;width:100%}.mrd-field__history-editor.sc-mrd-field{margin-top:var(--mrd-space-2);display:flex;flex-direction:column;gap:var(--mrd-space-1)}.mrd-field__history-editor-label.sc-mrd-field{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-xs);font-weight:var(--mrd-font-weight-medium);color:var(--mrd-color-neutral-500)}.mrd-field__history-editor-row.sc-mrd-field{display:flex;align-items:center;gap:var(--mrd-space-2)}.mrd-field__history-editor-sep.sc-mrd-field{flex-shrink:0;font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-500)}.mrd-field__history-editor-value.sc-mrd-field{flex:1 1 0;min-width:0;height:var(--mrd-input-height);padding:0 var(--mrd-space-3);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-800);background-color:var(--mrd-color-white);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius-md);outline:none;transition:border-color var(--mrd-transition-fast), box-shadow var(--mrd-transition-fast)}.mrd-field__history-editor-value.sc-mrd-field:focus{border-color:var(--mrd-color-primary);box-shadow:var(--mrd-shadow-focus)}.mrd-field__history-editor-until.sc-mrd-field{flex:0 0 10rem;height:var(--mrd-input-height);padding:0 var(--mrd-space-3);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-800);background-color:var(--mrd-color-white);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius-md);outline:none;transition:border-color var(--mrd-transition-fast), box-shadow var(--mrd-transition-fast)}.mrd-field__history-editor-until.sc-mrd-field:focus{border-color:var(--mrd-color-primary);box-shadow:var(--mrd-shadow-focus)}.mrd-field__history-editor-remove.sc-mrd-field{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:2rem;height:2rem;padding:0;background:transparent;border:none;border-radius:var(--mrd-border-radius-sm);color:var(--mrd-color-neutral-400);cursor:pointer;transition:color var(--mrd-transition-fast), background-color var(--mrd-transition-fast)}.mrd-field__history-editor-remove.sc-mrd-field:hover{color:var(--mrd-color-danger);background-color:var(--mrd-color-danger-light)}.mrd-field__history-editor-remove.sc-mrd-field svg.sc-mrd-field{width:1rem;height:1rem}.mrd-field__history-editor-add.sc-mrd-field{align-self:flex-start;padding:var(--mrd-space-1) var(--mrd-space-3);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-xs);font-weight:var(--mrd-font-weight-medium);color:var(--mrd-color-primary);background:transparent;border:var(--mrd-border-width) solid var(--mrd-color-primary);border-radius:var(--mrd-border-radius-md);cursor:pointer;transition:background-color var(--mrd-transition-fast), color var(--mrd-transition-fast)}.mrd-field__history-editor-add.sc-mrd-field:hover{background-color:var(--mrd-color-primary-light)}`;
872
-
873
- const MrdField = class {
874
- constructor(hostRef) {
875
- registerInstance(this, hostRef);
876
- this.mrdChange = createEvent(this, "mrdChange");
877
- this.mrdBlur = createEvent(this, "mrdBlur");
878
- this.mrdSearch = createEvent(this, "mrdSearch");
879
- this.mrdFetchAll = createEvent(this, "mrdFetchAll");
880
- this.mrdUpload = createEvent(this, "mrdUpload");
881
- this.locale = navigator.language;
882
- this.historyEntries = [];
883
- this.currentValue = undefined;
884
- this.handleChange = (e) => {
885
- var _a, _b, _c, _d;
886
- e.stopPropagation();
887
- const hist = (_b = (_a = this.item) === null || _a === void 0 ? void 0 : _a.historyEnabled) !== null && _b !== void 0 ? _b : (_d = (_c = this.item) === null || _c === void 0 ? void 0 : _c.field) === null || _d === void 0 ? void 0 : _d.historyEnabled;
888
- if (hist) {
889
- this.currentValue = e.detail.value;
890
- this.mrdChange.emit({
891
- name: e.detail.name,
892
- value: { current: e.detail.value, history: this.historyEntries },
893
- });
894
- }
895
- else {
896
- this.mrdChange.emit(e.detail);
897
- }
898
- };
899
- this.handleBlur = (e) => {
900
- var _a, _b, _c, _d;
901
- e.stopPropagation();
902
- const hist = (_b = (_a = this.item) === null || _a === void 0 ? void 0 : _a.historyEnabled) !== null && _b !== void 0 ? _b : (_d = (_c = this.item) === null || _c === void 0 ? void 0 : _c.field) === null || _d === void 0 ? void 0 : _d.historyEnabled;
903
- if (hist) {
904
- this.mrdBlur.emit({
905
- name: e.detail.name,
906
- value: { current: this.currentValue, history: this.historyEntries },
907
- });
908
- }
909
- else {
910
- this.mrdBlur.emit(e.detail);
911
- }
912
- };
913
- this.handleSearch = (e) => {
914
- e.stopPropagation();
915
- this.mrdSearch.emit(e.detail);
916
- };
917
- this.handleFetchAll = (e) => {
918
- e.stopPropagation();
919
- this.mrdFetchAll.emit(e.detail);
920
- };
921
- this.handleUpload = (e) => {
922
- e.stopPropagation();
923
- this.mrdUpload.emit(e.detail);
924
- };
925
- }
926
- componentWillLoad() {
927
- this.initHistoryState();
928
- }
929
- valueChanged() {
930
- this.initHistoryState();
931
- }
932
- initHistoryState() {
933
- var _a, _b, _c, _d, _e;
934
- const hist = (_b = (_a = this.item) === null || _a === void 0 ? void 0 : _a.historyEnabled) !== null && _b !== void 0 ? _b : (_d = (_c = this.item) === null || _c === void 0 ? void 0 : _c.field) === null || _d === void 0 ? void 0 : _d.historyEnabled;
935
- if (!hist)
936
- return;
937
- const raw = this.value;
938
- this.currentValue = (_e = raw === null || raw === void 0 ? void 0 : raw.current) !== null && _e !== void 0 ? _e : raw;
939
- this.historyEntries = Array.isArray(raw === null || raw === void 0 ? void 0 : raw.history) ? [...raw.history] : [];
940
- }
941
- getDisplayValue() {
942
- var _a, _b, _c, _d;
943
- const hist = (_b = (_a = this.item) === null || _a === void 0 ? void 0 : _a.historyEnabled) !== null && _b !== void 0 ? _b : (_d = (_c = this.item) === null || _c === void 0 ? void 0 : _c.field) === null || _d === void 0 ? void 0 : _d.historyEnabled;
944
- if (hist && this.value !== null && typeof this.value === 'object' && 'current' in this.value) {
945
- return this.value.current;
946
- }
947
- return this.value;
948
- }
949
- historyValueInputType() {
950
- var _a;
951
- switch ((_a = this.item) === null || _a === void 0 ? void 0 : _a.dataType) {
952
- case ClientLayoutItemFieldDataType.DATE: return 'date';
953
- case ClientLayoutItemFieldDataType.DATETIME: return 'datetime-local';
954
- case ClientLayoutItemFieldDataType.TIME: return 'time';
955
- case ClientLayoutItemFieldDataType.INTEGER:
956
- case ClientLayoutItemFieldDataType.DECIMAL:
957
- case ClientLayoutItemFieldDataType.PERCENTAGE: return 'number';
958
- case ClientLayoutItemFieldDataType.EMAIL: return 'email';
959
- default: return 'text';
960
- }
961
- }
962
- emitHistoryChange(entries) {
963
- this.historyEntries = entries;
964
- this.mrdChange.emit({
965
- name: this.item.name,
966
- value: { current: this.currentValue, history: entries },
967
- });
968
- }
969
- renderHistoryEditor() {
970
- var _a, _b, _c, _d;
971
- const hist = (_b = (_a = this.item) === null || _a === void 0 ? void 0 : _a.historyEnabled) !== null && _b !== void 0 ? _b : (_d = (_c = this.item) === null || _c === void 0 ? void 0 : _c.field) === null || _d === void 0 ? void 0 : _d.historyEnabled;
972
- if (!hist)
973
- return null;
974
- const { locale } = this;
975
- const valueType = this.historyValueInputType();
976
- const updateEntry = (i, field, val) => {
977
- const updated = this.historyEntries.map((e, idx) => idx === i ? Object.assign(Object.assign({}, e), { [field]: val }) : e);
978
- this.emitHistoryChange(updated);
979
- };
980
- const removeEntry = (i) => {
981
- this.emitHistoryChange(this.historyEntries.filter((_, idx) => idx !== i));
982
- };
983
- const addEntry = () => {
984
- this.emitHistoryChange([...this.historyEntries, { value: '', until: '' }]);
985
- };
986
- return (h("div", { class: "mrd-field__history-editor" }, this.historyEntries.length > 0 && (h("span", { class: "mrd-field__history-editor-label" }, t('history_badge_tooltip', locale))), this.historyEntries.map((entry, i) => (h("div", { key: String(i), class: "mrd-field__history-editor-row" }, h("input", { class: "mrd-field__history-editor-value", type: valueType, value: entry.value, onInput: (e) => updateEntry(i, 'value', e.target.value) }), h("span", { class: "mrd-field__history-editor-sep" }, t('history_until', locale)), h("input", { class: "mrd-field__history-editor-until", type: "date", value: entry.until, onInput: (e) => updateEntry(i, 'until', e.target.value) }), h("button", { type: "button", class: "mrd-field__history-editor-remove", onClick: () => removeEntry(i), "aria-label": t('remove', locale) }, h("svg", { viewBox: "0 0 20 20", fill: "currentColor", "aria-hidden": "true" }, h("path", { "fill-rule": "evenodd", d: "M8.75 1A2.75 2.75 0 006 3.75v.443c-.795.077-1.584.176-2.365.298a.75.75 0 10.23 1.482l.149-.022.841 10.518A2.75 2.75 0 007.596 19h4.807a2.75 2.75 0 002.742-2.53l.841-10.52.149.023a.75.75 0 00.23-1.482A41.03 41.03 0 0014 4.193V3.75A2.75 2.75 0 0011.25 1h-2.5zM10 4c.84 0 1.673.025 2.5.075V3.75c0-.69-.56-1.25-1.25-1.25h-2.5c-.69 0-1.25.56-1.25 1.25v.325C8.327 4.025 9.16 4 10 4zM8.58 7.72a.75.75 0 00-1.5.06l.3 7.5a.75.75 0 101.5-.06l-.3-7.5zm4.34.06a.75.75 0 10-1.5-.06l-.3 7.5a.75.75 0 101.5.06l.3-7.5z", "clip-rule": "evenodd" })))))), h("button", { type: "button", class: "mrd-field__history-editor-add", onClick: addEntry }, "+ ", t('add', locale))));
987
- }
988
- renderLeafField(displayValue) {
989
- 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;
990
- const { item, locale } = this;
991
- const commonProps = {
992
- name: item.name,
993
- label: item.label,
994
- required: item.required,
995
- disabled: (_a = item.disabled) !== null && _a !== void 0 ? _a : false,
996
- locale,
997
- onMrdChange: this.handleChange,
998
- onMrdBlur: this.handleBlur,
999
- };
1000
- switch (item.dataType) {
1001
- case ClientLayoutItemFieldDataType.TEXT:
1002
- return (h("mrd-text-field", Object.assign({}, commonProps, { value: (_b = displayValue) !== null && _b !== void 0 ? _b : '', placeholder: (_c = item.placeholder) !== null && _c !== void 0 ? _c : '' })));
1003
- case ClientLayoutItemFieldDataType.TEXTBLOCK:
1004
- return (h("mrd-textarea-field", Object.assign({}, commonProps, { value: (_d = displayValue) !== null && _d !== void 0 ? _d : '', placeholder: (_e = item.placeholder) !== null && _e !== void 0 ? _e : '' })));
1005
- case ClientLayoutItemFieldDataType.INTEGER:
1006
- case ClientLayoutItemFieldDataType.DECIMAL:
1007
- case ClientLayoutItemFieldDataType.PERCENTAGE:
1008
- return (h("mrd-number-field", Object.assign({}, commonProps, { value: (_f = displayValue) !== null && _f !== void 0 ? _f : null, dataType: item.dataType, decimalPrecision: (_g = item.decimalPrecision) !== null && _g !== void 0 ? _g : 2, placeholder: (_h = item.placeholder) !== null && _h !== void 0 ? _h : '' })));
1009
- case ClientLayoutItemFieldDataType.CURRENCY:
1010
- return (h("mrd-currency-field", Object.assign({}, commonProps, { value: (_j = displayValue) !== null && _j !== void 0 ? _j : { amount: null, currency: (_k = item.currencyCode) !== null && _k !== void 0 ? _k : 'EUR' } })));
1011
- case ClientLayoutItemFieldDataType.BOOLEAN:
1012
- return (h("mrd-boolean-field", Object.assign({}, commonProps, { value: (_l = displayValue) !== null && _l !== void 0 ? _l : false })));
1013
- case ClientLayoutItemFieldDataType.DATE:
1014
- return (h("mrd-date-field", Object.assign({}, commonProps, { value: (_m = displayValue) !== null && _m !== void 0 ? _m : '' })));
1015
- case ClientLayoutItemFieldDataType.DATETIME:
1016
- return (h("mrd-datetime-field", Object.assign({}, commonProps, { value: (_o = displayValue) !== null && _o !== void 0 ? _o : '' })));
1017
- case ClientLayoutItemFieldDataType.TIME:
1018
- return (h("mrd-time-field", Object.assign({}, commonProps, { value: (_p = displayValue) !== null && _p !== void 0 ? _p : '' })));
1019
- case ClientLayoutItemFieldDataType.EMAIL:
1020
- return (h("mrd-email-field", Object.assign({}, commonProps, { value: (_q = displayValue) !== null && _q !== void 0 ? _q : '', placeholder: (_r = item.placeholder) !== null && _r !== void 0 ? _r : '' })));
1021
- case ClientLayoutItemFieldDataType.HYPERLINK:
1022
- return (h("mrd-hyperlink-field", Object.assign({}, commonProps, { value: (_s = displayValue) !== null && _s !== void 0 ? _s : '', placeholder: (_t = item.placeholder) !== null && _t !== void 0 ? _t : '' })));
1023
- case ClientLayoutItemFieldDataType.LIST:
1024
- return (h("mrd-list-field", Object.assign({}, commonProps, { value: (_u = displayValue) !== null && _u !== void 0 ? _u : '', multiple: (_v = item.multiple) !== null && _v !== void 0 ? _v : false, listItems: (_w = item.listItems) !== null && _w !== void 0 ? _w : [] })));
1025
- case ClientLayoutItemFieldDataType.FILE:
1026
- return (h("mrd-file-field", Object.assign({}, commonProps, { value: displayValue, accept: (_x = item.accept) !== null && _x !== void 0 ? _x : '', maxSize: (_y = item.maxSize) !== null && _y !== void 0 ? _y : 0, onMrdUpload: this.handleUpload })));
1027
- case ClientLayoutItemFieldDataType.IMAGE:
1028
- return (h("mrd-image-field", Object.assign({}, commonProps, { value: displayValue, accept: (_z = item.accept) !== null && _z !== void 0 ? _z : 'image/*', maxSize: (_0 = item.maxSize) !== null && _0 !== void 0 ? _0 : 0, onMrdUpload: this.handleUpload })));
1029
- case ClientLayoutItemFieldDataType.LONGTEXT:
1030
- return (h("mrd-longtext-field", Object.assign({}, commonProps, { value: (_1 = displayValue) !== null && _1 !== void 0 ? _1 : '', placeholder: (_2 = item.placeholder) !== null && _2 !== void 0 ? _2 : '' })));
1031
- case ClientLayoutItemFieldDataType.SECRET:
1032
- return (h("mrd-secret-field", Object.assign({}, commonProps, { value: (_3 = displayValue) !== null && _3 !== void 0 ? _3 : '', placeholder: (_4 = item.placeholder) !== null && _4 !== void 0 ? _4 : '' })));
1033
- default:
1034
- return null;
1035
- }
1036
- }
1037
- render() {
1038
- var _a, _b, _c, _d, _e, _f;
1039
- const { item, locale, value } = this;
1040
- if (item.type === ClientLayoutItemType.RELATION) {
1041
- return (h(Host, null, h("mrd-relation-field", { name: item.name, label: item.label, required: item.required, disabled: (_a = item.disabled) !== null && _a !== void 0 ? _a : false, locale: locale, relatedClass: item.relatedClass, mostSignificantClass: (_b = item.mostSignificantClass) !== null && _b !== void 0 ? _b : '', displayType: (_c = item.displayType) !== null && _c !== void 0 ? _c : ClientLayoutItemRelationDisplayType.SEARCH, editBehavior: (_d = item.editBehavior) !== null && _d !== void 0 ? _d : null, commonRelation: item.commonRelation, multiple: (_e = item.multiple) !== null && _e !== void 0 ? _e : false, dropdownValues: (_f = item.dropdownValues) !== null && _f !== void 0 ? _f : [], value: value, onMrdChange: this.handleChange, onMrdBlur: this.handleBlur, onMrdSearch: this.handleSearch, onMrdFetchAll: this.handleFetchAll })));
1042
- }
1043
- if (item.type !== ClientLayoutItemType.FIELD) {
1044
- return h(Host, null);
1045
- }
1046
- const displayValue = this.getDisplayValue();
1047
- return (h(Host, null, h("div", { class: "mrd-field__inner" }, this.renderLeafField(displayValue), this.renderHistoryEditor())));
1048
- }
1049
- get el() { return getElement(this); }
1050
- static get watchers() { return {
1051
- "value": [{
1052
- "valueChanged": 0
1053
- }]
1054
- }; }
1055
- };
1056
- MrdField.style = mrdFieldScss();
1057
-
1058
- 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)}`;
1059
-
1060
- const MrdFileField = class {
1061
- constructor(hostRef) {
1062
- registerInstance(this, hostRef);
1063
- this.mrdChange = createEvent(this, "mrdChange");
1064
- this.mrdBlur = createEvent(this, "mrdBlur");
1065
- this.mrdUpload = createEvent(this, "mrdUpload");
1066
- this.name = '';
1067
- this.label = '';
1068
- this.value = null;
1069
- this.required = false;
1070
- this.disabled = false;
1071
- this.locale = navigator.language;
1072
- this.accept = '';
1073
- this.maxSize = 0; // bytes, 0 = no limit
1074
- this.fileName = '';
1075
- this.isDragging = false;
1076
- this.uploading = false;
1077
- this.error = '';
1078
- this.handleInputChange = (e) => {
1079
- var _a;
1080
- const files = e.target.files;
1081
- this.handleFile((_a = files === null || files === void 0 ? void 0 : files[0]) !== null && _a !== void 0 ? _a : null);
1082
- };
1083
- this.handleDragOver = (e) => {
1084
- e.preventDefault();
1085
- this.isDragging = true;
1086
- };
1087
- this.handleDragLeave = () => {
1088
- this.isDragging = false;
1089
- };
1090
- this.handleDrop = (e) => {
1091
- var _a, _b, _c;
1092
- e.preventDefault();
1093
- this.isDragging = false;
1094
- 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;
1095
- this.handleFile(file);
1096
- };
1097
- this.handleZoneClick = () => {
1098
- var _a;
1099
- if (!this.disabled && !this.uploading) {
1100
- (_a = this.fileInputRef) === null || _a === void 0 ? void 0 : _a.click();
1101
- }
1102
- };
1103
- this.handleClear = (e) => {
1104
- e.stopPropagation();
1105
- this.fileName = '';
1106
- this.error = '';
1107
- this.uploading = false;
1108
- if (this.fileInputRef)
1109
- this.fileInputRef.value = '';
1110
- this.mrdChange.emit({ name: this.name, value: null });
1111
- };
1112
- }
1113
- /** When the host provides a URI back via setFieldValue, the upload is done. */
1114
- valueChanged(newVal) {
1115
- if (typeof newVal === 'string' && newVal) {
1116
- this.uploading = false;
1117
- }
1118
- else if (!newVal) {
1119
- this.uploading = false;
1120
- this.fileName = '';
1121
- }
1122
- }
1123
- handleFile(file) {
1124
- if (!file) {
1125
- this.fileName = '';
1126
- this.uploading = false;
1127
- this.mrdChange.emit({ name: this.name, value: null });
1128
- return;
1129
- }
1130
- if (this.maxSize > 0 && file.size > this.maxSize) {
1131
- this.error = t('file_too_large', this.locale);
1132
- return;
1133
- }
1134
- this.error = '';
1135
- this.fileName = file.name;
1136
- this.uploading = true;
1137
- this.mrdChange.emit({ name: this.name, value: file });
1138
- this.mrdUpload.emit({ name: this.name, file });
1139
- }
1140
- render() {
1141
- const hasFile = this.uploading || (typeof this.value === 'string' && this.value) || this.fileName;
1142
- const hasError = !!this.error;
1143
- const zoneClass = [
1144
- 'mrd-file-field__zone',
1145
- this.isDragging ? 'mrd-file-field__zone--dragging' : '',
1146
- hasError ? 'mrd-file-field__zone--error' : '',
1147
- this.disabled || this.uploading ? 'mrd-file-field__zone--disabled' : '',
1148
- ].filter(Boolean).join(' ');
1149
- 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))));
1150
- }
1151
- static get watchers() { return {
1152
- "value": [{
1153
- "valueChanged": 0
1154
- }]
1155
- }; }
1156
- };
1157
- MrdFileField.style = mrdFileFieldScss();
1158
-
1159
- 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)}`;
1160
-
1161
- const MrdForm = class {
1162
- constructor(hostRef) {
1163
- registerInstance(this, hostRef);
1164
- this.mrdSubmit = createEvent(this, "mrdSubmit");
1165
- this.mrdCancel = createEvent(this, "mrdCancel");
1166
- this.mrdSearch = createEvent(this, "mrdSearch");
1167
- this.mrdFetchAll = createEvent(this, "mrdFetchAll");
1168
- this.mrdUpload = createEvent(this, "mrdUpload");
1169
- this.locale = navigator.language;
1170
- this.values = {};
1171
- /**
1172
- * Absolute href of the parent/reference object (e.g. the clientAgreement href
1173
- * when creating an invoice from within a client agreement).
1174
- * Combined with `referenceClass`, mrd-form will automatically pre-fill the
1175
- * matching relation field so dependent DROPDOWN fields can be fetched on load
1176
- * — without the host app needing to know anything about the form layout.
1177
- */
1178
- /**
1179
- * Absolute href of the parent/reference object (e.g. the clientAgreement href
1180
- * when creating an invoice from within a client agreement).
1181
- * Combined with `referenceClass`, mrd-form will automatically pre-fill the
1182
- * matching relation field so dependent DROPDOWN fields can be fetched on load.
1183
- */
1184
- this.referenceHref = '';
1185
- /**
1186
- * The `mostSignificantClass` of the parent/reference object
1187
- * (e.g. `'clientAgreements'`). Used to locate the matching RELATION field.
1188
- */
1189
- this.referenceClass = '';
1190
- /** When true, a cancel button is shown next to the submit button. */
1191
- this.showCancel = false;
1192
- /**
1193
- * The currently logged-in user, resolved by the host via /accounts/me.
1194
- * Used to pre-fill RELATION fields whose defaultValue is "@me".
1195
- * May be null when not authenticated or not yet resolved.
1196
- */
1197
- this.me = null;
1198
- this.formValues = {};
1199
- this.errors = {};
1200
- this.submitted = false;
1201
- this.initialValues = {};
1202
- this.handleFieldChange = (e) => {
1203
- const { name, value } = e.detail;
1204
- const prevHref = this.getHref(this.formValues[name]);
1205
- this.formValues = Object.assign(Object.assign({}, this.formValues), { [name]: value });
1206
- if (this.errors[name]) {
1207
- this.errors = Object.assign(Object.assign({}, this.errors), { [name]: '' });
1208
- }
1209
- // When a field changes, check if it is the commonRelation dependency for any
1210
- // DROPDOWN relation. If so, reset the dependent field and re-fetch its options.
1211
- // Skip when the effective href did not change (e.g. mrdBlur fires after mrdChange
1212
- // with the same value, which would otherwise trigger a duplicate fetch).
1213
- const newHref = this.getHref(value);
1214
- if (newHref === prevHref)
1215
- return;
1216
- for (const item of this.collectDependentDropdowns()) {
1217
- if (item.commonRelation !== name)
1218
- continue;
1219
- // Clear the dependent field's current selection (options have changed)
1220
- this.formValues = Object.assign(Object.assign({}, this.formValues), { [item.name]: null });
1221
- this.mrdFetchAll.emit({
1222
- name: item.name,
1223
- relatedClass: item.relatedClass,
1224
- mostSignificantClass: item.mostSignificantClass,
1225
- commonRelation: item.commonRelation,
1226
- filter: item.commonRelation + '_href',
1227
- filterValue: newHref, // empty string when dependency was cleared → host should clear the list
1228
- });
1229
- }
1230
- };
1231
- this.handleSearch = (e) => {
1232
- e.stopPropagation();
1233
- this.mrdSearch.emit(e.detail);
1234
- };
1235
- this.handleFetchAll = (e) => {
1236
- e.stopPropagation();
1237
- this.mrdFetchAll.emit(e.detail);
1238
- };
1239
- this.handleUpload = (e) => {
1240
- e.stopPropagation();
1241
- this.mrdUpload.emit(e.detail);
1242
- };
1243
- this.handleSubmit = (e) => {
1244
- e.preventDefault();
1245
- this.submitted = true;
1246
- if (this.validate()) {
1247
- this.mrdSubmit.emit(this.buildSubmitPayload());
1248
- }
1249
- };
1250
- }
1251
- componentWillLoad() {
1252
- var _a, _b;
1253
- this.initialValues = Object.assign({}, ((_a = this.values) !== null && _a !== void 0 ? _a : {}));
1254
- this.formValues = Object.assign({}, ((_b = this.values) !== null && _b !== void 0 ? _b : {}));
1255
- this.applyDefaultValues();
1256
- }
1257
- componentDidLoad() {
1258
- // Apply reference pre-fill and emit mrdFetchAll for dependent DROPDOWN fields.
1259
- // Deferred so Angular/host prop bindings are settled before we read them.
1260
- setTimeout(() => {
1261
- this.applyReferenceValue();
1262
- this.emitDependentFetchAll();
1263
- }, 0);
1264
- }
1265
- /** Sync formValues when the values prop is set from outside after mount
1266
- * (e.g. when pre-filling an existing record in edit mode). */
1267
- valuesChanged(newValues) {
1268
- this.initialValues = Object.assign({}, (newValues !== null && newValues !== void 0 ? newValues : {}));
1269
- this.formValues = Object.assign({}, (newValues !== null && newValues !== void 0 ? newValues : {}));
1270
- this.applyReferenceValue();
1271
- this.applyDefaultValues();
1272
- this.errors = {};
1273
- this.submitted = false;
1274
- // Re-check DROPDOWN dependencies now that formValues are updated
1275
- setTimeout(() => this.emitDependentFetchAll(), 0);
1276
- }
1277
- /** Re-apply @me defaults when the me prop arrives after mount. */
1278
- meChanged() {
1279
- this.applyDefaultValues();
1280
- }
1281
- /** Apply defaultValue from layout items to fields that have no value yet.
1282
- * Tokens: today() → YYYY-MM-DD, now() → YYYY-MM-DDTHH:mm, @me → this.me. */
1283
- applyDefaultValues() {
1284
- var _a, _b, _c, _d, _e, _f, _g, _h;
1285
- const allFields = this.collectFields((_b = (_a = this.layout) === null || _a === void 0 ? void 0 : _a.items) !== null && _b !== void 0 ? _b : []);
1286
- const updates = {};
1287
- for (const item of allFields) {
1288
- if (!item.name)
1289
- continue;
1290
- const current = this.formValues[item.name];
1291
- if (current != null && current !== '')
1292
- continue;
1293
- const dv = (_e = (_c = item.defaultValue) !== null && _c !== void 0 ? _c : (_d = item.field) === null || _d === void 0 ? void 0 : _d.defaultValue) !== null && _e !== void 0 ? _e : (_f = item.relation) === null || _f === void 0 ? void 0 : _f.defaultValue;
1294
- if (!dv)
1295
- continue;
1296
- if (item.type === ClientLayoutItemType.FIELD) {
1297
- const resolved = this.resolveFieldDefault(dv, (_g = item.dataType) !== null && _g !== void 0 ? _g : (_h = item.field) === null || _h === void 0 ? void 0 : _h.dataType);
1298
- if (resolved != null)
1299
- updates[item.name] = resolved;
1300
- }
1301
- else if (item.type === ClientLayoutItemType.RELATION) {
1302
- if (dv === 'me()' && this.me) {
1303
- updates[item.name] = this.me;
1304
- }
1305
- }
1306
- }
1307
- if (Object.keys(updates).length > 0) {
1308
- this.formValues = Object.assign(Object.assign({}, this.formValues), updates);
1309
- }
1310
- }
1311
- resolveFieldDefault(dv, _dataType) {
1312
- if (dv === 'today()') {
1313
- return new Date().toISOString().slice(0, 10);
1314
- }
1315
- if (dv === 'now()') {
1316
- return new Date().toISOString().replace(/\.\d{3}Z$/, 'Z');
1317
- }
1318
- return dv;
1319
- }
1320
- /**
1321
- * When referenceHref + referenceClass are set, find the matching layout field
1322
- * and inject its value into formValues. This allows dependent DROPDOWN fields
1323
- * (those with commonRelation pointing to that field) to be fetched on load
1324
- * without the host app doing any form-domain logic.
1325
- *
1326
- * Two lookup strategies:
1327
- * 1. Find a RELATION whose mostSignificantClass matches referenceClass.
1328
- * 2. Fallback: find a DROPDOWN whose commonRelation field is absent from the
1329
- * layout (API omitted it because it is implied by the reference context).
1330
- */
1331
- applyReferenceValue() {
1332
- if (!this.referenceHref || !this.referenceClass)
1333
- return;
1334
- const fieldName = this.resolveReferenceFieldName();
1335
- if (!fieldName)
1336
- return;
1337
- // Only set when not already present (don't overwrite an explicit value)
1338
- if (!this.formValues[fieldName]) {
1339
- this.formValues = Object.assign(Object.assign({}, this.formValues), { [fieldName]: this.referenceHref });
1340
- }
1341
- }
1342
- resolveReferenceFieldName() {
1343
- var _a, _b;
1344
- const allItems = this.collectFields((_b = (_a = this.layout) === null || _a === void 0 ? void 0 : _a.items) !== null && _b !== void 0 ? _b : []);
1345
- // Strategy 1: direct match on mostSignificantClass
1346
- const direct = allItems.find(item => item.type === ClientLayoutItemType.RELATION &&
1347
- item.mostSignificantClass === this.referenceClass);
1348
- if (direct === null || direct === void 0 ? void 0 : direct.name)
1349
- return direct.name;
1350
- // Strategy 2: a DROPDOWN whose commonRelation field was omitted from the layout
1351
- const layoutRelationNames = new Set(allItems
1352
- .filter(item => item.type === ClientLayoutItemType.RELATION)
1353
- .map(item => item.name));
1354
- for (const item of allItems) {
1355
- if (item.type === ClientLayoutItemType.RELATION &&
1356
- item.editBehavior === ClientLayoutItemRelationEditBehavior.DROPDOWN &&
1357
- item.commonRelation &&
1358
- !layoutRelationNames.has(item.commonRelation)) {
1359
- return item.commonRelation;
1360
- }
1361
- }
1362
- return null;
1363
- }
1364
- async setFieldValue(name, value) {
1365
- this.formValues = Object.assign(Object.assign({}, this.formValues), { [name]: value });
1366
- if (this.errors[name]) {
1367
- this.errors = Object.assign(Object.assign({}, this.errors), { [name]: '' });
1368
- }
1369
- }
1370
- /** Collect all RELATION items that use editBehavior=DROPDOWN with a commonRelation. */
1371
- collectDependentDropdowns() {
1372
- var _a, _b;
1373
- return this.collectFields((_b = (_a = this.layout) === null || _a === void 0 ? void 0 : _a.items) !== null && _b !== void 0 ? _b : [])
1374
- .filter(item => item.type === ClientLayoutItemType.RELATION &&
1375
- item.editBehavior === ClientLayoutItemRelationEditBehavior.DROPDOWN &&
1376
- !!item.commonRelation);
1377
- }
1378
- /** Emit mrdFetchAll for every dependent DROPDOWN whose filter value is currently set. */
1379
- emitDependentFetchAll() {
1380
- for (const item of this.collectDependentDropdowns()) {
1381
- const filterValue = this.getHref(this.formValues[item.commonRelation]);
1382
- if (filterValue) {
1383
- this.mrdFetchAll.emit({
1384
- name: item.name,
1385
- relatedClass: item.relatedClass,
1386
- mostSignificantClass: item.mostSignificantClass,
1387
- commonRelation: item.commonRelation,
1388
- filter: item.commonRelation + '_href',
1389
- filterValue,
1390
- });
1391
- }
1392
- }
1393
- }
1394
- /** Extract a plain href string from a form value, which can be a string or
1395
- * a RelationSearchResult-like object with an `id` field. */
1396
- getHref(value) {
1397
- if (!value)
1398
- return '';
1399
- if (typeof value === 'string')
1400
- return value;
1401
- if (typeof value === 'object' && 'id' in value)
1402
- return value.id;
1403
- return '';
1404
- }
1405
- collectFields(items) {
1406
- const fields = [];
1407
- for (const item of items) {
1408
- if (item.type === ClientLayoutItemType.FIELD || item.type === ClientLayoutItemType.RELATION) {
1409
- fields.push(item);
1410
- }
1411
- if (item.items) {
1412
- fields.push(...this.collectFields(item.items));
1413
- }
1414
- }
1415
- return fields;
1416
- }
1417
- validate() {
1418
- var _a, _b;
1419
- const newErrors = {};
1420
- const allFields = this.collectFields((_b = (_a = this.layout) === null || _a === void 0 ? void 0 : _a.items) !== null && _b !== void 0 ? _b : []);
1421
- for (const item of allFields) {
1422
- if (!item.name)
1423
- continue;
1424
- if (item.required && !validateRequired(this.formValues[item.name])) {
1425
- newErrors[item.name] = t('required', this.locale);
1426
- }
1427
- }
1428
- this.errors = newErrors;
1429
- return Object.keys(newErrors).length === 0;
1430
- }
1431
- normalizeFieldValue(value) {
1432
- return (value === '' || value == null) ? null : value;
1433
- }
1434
- normalizeRelationValue(value) {
1435
- if (value == null || value === '')
1436
- return null;
1437
- if (typeof value === 'string')
1438
- return value || null;
1439
- if (Array.isArray(value)) {
1440
- return value.map(v => typeof v === 'object' && v !== null && 'id' in v ? v.id : String(v));
1441
- }
1442
- if (typeof value === 'object' && 'id' in value) {
1443
- return value.id || null;
1444
- }
1445
- return null;
1446
- }
1447
- deepEqual(a, b) {
1448
- if (a === b)
1449
- return true;
1450
- if (a == null && b == null)
1451
- return true;
1452
- if (a == null || b == null)
1453
- return false;
1454
- if (Array.isArray(a) && Array.isArray(b)) {
1455
- if (a.length !== b.length)
1456
- return false;
1457
- const sa = [...a].sort();
1458
- const sb = [...b].sort();
1459
- return JSON.stringify(sa) === JSON.stringify(sb);
1460
- }
1461
- return JSON.stringify(a) === JSON.stringify(b);
1462
- }
1463
- /** Build a submit payload containing only fields that changed relative to
1464
- * initialValues. For a new record (POST) initialValues is empty, so every
1465
- * non-null field is included. For edit (PATCH) only modified fields are sent,
1466
- * including fields explicitly cleared to null.
1467
- */
1468
- buildSubmitPayload() {
1469
- var _a, _b;
1470
- const payload = {};
1471
- const allFields = this.collectFields((_b = (_a = this.layout) === null || _a === void 0 ? void 0 : _a.items) !== null && _b !== void 0 ? _b : []);
1472
- for (const item of allFields) {
1473
- if (!item.name)
1474
- continue;
1475
- const name = item.name;
1476
- if (item.type === ClientLayoutItemType.FIELD) {
1477
- const rawValue = this.formValues[name];
1478
- if (rawValue instanceof File)
1479
- continue;
1480
- const current = this.normalizeFieldValue(rawValue);
1481
- const initial = this.normalizeFieldValue(this.initialValues[name]);
1482
- if (this.deepEqual(current, initial))
1483
- continue;
1484
- payload[name] = current;
1485
- }
1486
- else if (item.type === ClientLayoutItemType.RELATION) {
1487
- const current = this.normalizeRelationValue(this.formValues[name]);
1488
- const initial = this.normalizeRelationValue(this.initialValues[name]);
1489
- if (this.deepEqual(current, initial))
1490
- continue;
1491
- payload[name] = current;
1492
- }
1493
- }
1494
- return payload;
1495
- }
1496
- renderItems(items) {
1497
- return items.map(item => {
1498
- var _a;
1499
- if (item.type === ClientLayoutItemType.SECTION) {
1500
- 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))));
1501
- }
1502
- if (item.type === ClientLayoutItemType.GROUP) {
1503
- 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))));
1504
- }
1505
- const fieldName = (_a = item.name) !== null && _a !== void 0 ? _a : '';
1506
- const fieldValue = this.formValues[fieldName];
1507
- 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]))));
1508
- });
1509
- }
1510
- render() {
1511
- if (!this.layout) {
1512
- return h(Host, null);
1513
- }
1514
- const dir = this.locale.startsWith('ar') ? 'rtl' : 'ltr';
1515
- 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)))))));
1516
- }
1517
- static get watchers() { return {
1518
- "values": [{
1519
- "valuesChanged": 0
1520
- }],
1521
- "me": [{
1522
- "meChanged": 0
1523
- }]
1524
- }; }
1525
- };
1526
- MrdForm.style = mrdFormScss();
1527
-
1528
- 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__input--name.sc-mrd-hyperlink-field{margin-top:var(--mrd-space-1)}.mrd-hyperlink-field__link.sc-mrd-hyperlink-field{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-color-primary);text-decoration:underline;word-break:break-all}.mrd-hyperlink-field__link.sc-mrd-hyperlink-field:hover{opacity:0.8}.mrd-hyperlink-field__empty.sc-mrd-hyperlink-field{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-color-neutral-400)}.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)}`;
1529
-
1530
- const MrdHyperlinkField = class {
1531
- constructor(hostRef) {
1532
- registerInstance(this, hostRef);
1533
- this.mrdChange = createEvent(this, "mrdChange");
1534
- this.mrdBlur = createEvent(this, "mrdBlur");
1535
- this.name = '';
1536
- this.label = '';
1537
- this.value = '';
1538
- this.placeholder = '';
1539
- this.required = false;
1540
- this.disabled = false;
1541
- this.locale = navigator.language;
1542
- this.internalHref = '';
1543
- this.internalName = '';
1544
- this.error = '';
1545
- this.handleHrefInput = (e) => {
1546
- this.internalHref = e.target.value;
1547
- this.mrdChange.emit({ name: this.name, value: this.buildValue() });
1548
- };
1549
- this.handleNameInput = (e) => {
1550
- this.internalName = e.target.value;
1551
- this.mrdChange.emit({ name: this.name, value: this.buildValue() });
1552
- };
1553
- this.handleBlur = () => {
1554
- if (this.required && !validateRequired(this.internalHref)) {
1555
- this.error = t('required', this.locale);
1556
- }
1557
- else if (this.internalHref && !validateUrl(this.internalHref)) {
1558
- this.error = t('invalid_url', this.locale);
1559
- }
1560
- else {
1561
- this.error = '';
1562
- }
1563
- this.mrdBlur.emit({ name: this.name, value: this.buildValue() });
1564
- };
1565
- }
1566
- componentWillLoad() {
1567
- this.parseValue(this.value);
1568
- }
1569
- valueChanged(val) {
1570
- this.parseValue(val);
1571
- }
1572
- parseValue(val) {
1573
- var _a, _b, _c;
1574
- if (val !== null && val !== undefined && typeof val === 'object' && 'href' in val) {
1575
- this.internalHref = (_a = val.href) !== null && _a !== void 0 ? _a : '';
1576
- this.internalName = (_b = val.name) !== null && _b !== void 0 ? _b : '';
1577
- }
1578
- else {
1579
- this.internalHref = (_c = val) !== null && _c !== void 0 ? _c : '';
1580
- this.internalName = '';
1581
- }
1582
- }
1583
- buildValue() {
1584
- return this.internalName.trim()
1585
- ? { href: this.internalHref, name: this.internalName }
1586
- : { href: this.internalHref };
1587
- }
1588
- render() {
1589
- const hasError = !!this.error;
1590
- if (this.disabled) {
1591
- return (h(Host, null, h("div", { class: "mrd-hyperlink-field" }, this.label && h("span", { class: "mrd-hyperlink-field__label" }, this.label), this.internalHref
1592
- ? h("a", { class: "mrd-hyperlink-field__link", href: this.internalHref, target: "_blank", rel: "noopener noreferrer" }, this.internalName || this.internalHref)
1593
- : h("span", { class: "mrd-hyperlink-field__empty" }, "\u2014"))));
1594
- }
1595
- return (h(Host, null, h("div", { class: "mrd-hyperlink-field" }, this.label && (h("label", { class: `mrd-hyperlink-field__label${this.required ? ' mrd-hyperlink-field__label--required' : ''}` }, this.label)), h("input", { class: `mrd-hyperlink-field__input${hasError ? ' mrd-hyperlink-field__input--error' : ''}`, type: "url", name: this.name, value: this.internalHref, placeholder: this.placeholder || 'https://', required: this.required, onInput: this.handleHrefInput, onBlur: this.handleBlur }), h("input", { class: "mrd-hyperlink-field__input mrd-hyperlink-field__input--name", type: "text", value: this.internalName, placeholder: t('hyperlink_name', this.locale), onInput: this.handleNameInput, onBlur: this.handleBlur }), hasError && h("span", { class: "mrd-hyperlink-field__error" }, this.error))));
1596
- }
1597
- static get watchers() { return {
1598
- "value": [{
1599
- "valueChanged": 0
1600
- }]
1601
- }; }
1602
- };
1603
- MrdHyperlinkField.style = mrdHyperlinkFieldScss();
1604
-
1605
- 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)}`;
1606
-
1607
- const MrdImageField = class {
1608
- constructor(hostRef) {
1609
- registerInstance(this, hostRef);
1610
- this.mrdChange = createEvent(this, "mrdChange");
1611
- this.mrdBlur = createEvent(this, "mrdBlur");
1612
- this.mrdUpload = createEvent(this, "mrdUpload");
1613
- this.name = '';
1614
- this.label = '';
1615
- this.value = null;
1616
- this.required = false;
1617
- this.disabled = false;
1618
- this.locale = navigator.language;
1619
- this.accept = 'image/*';
1620
- this.maxSize = 0;
1621
- this.previewUrl = '';
1622
- this.fileName = '';
1623
- this.isDragging = false;
1624
- this.uploading = false;
1625
- this.error = '';
1626
- this.handleInputChange = (e) => {
1627
- var _a;
1628
- const files = e.target.files;
1629
- this.handleFile((_a = files === null || files === void 0 ? void 0 : files[0]) !== null && _a !== void 0 ? _a : null);
1630
- };
1631
- this.handleDragOver = (e) => {
1632
- e.preventDefault();
1633
- this.isDragging = true;
1634
- };
1635
- this.handleDragLeave = () => {
1636
- this.isDragging = false;
1637
- };
1638
- this.handleDrop = (e) => {
1639
- var _a, _b, _c;
1640
- e.preventDefault();
1641
- this.isDragging = false;
1642
- 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;
1643
- this.handleFile(file);
1644
- };
1645
- this.handleZoneClick = () => {
1646
- var _a;
1647
- if (!this.disabled && !this.uploading) {
1648
- (_a = this.fileInputRef) === null || _a === void 0 ? void 0 : _a.click();
1649
- }
1650
- };
1651
- this.handleClear = (e) => {
1652
- e.stopPropagation();
1653
- this.previewUrl = '';
1654
- this.fileName = '';
1655
- this.error = '';
1656
- this.uploading = false;
1657
- if (this.fileInputRef)
1658
- this.fileInputRef.value = '';
1659
- this.mrdChange.emit({ name: this.name, value: null });
1660
- };
1661
- }
1662
- /** When the host provides a URI back via setFieldValue, the upload is done. */
1663
- valueChanged(newVal) {
1664
- if (typeof newVal === 'string' && newVal) {
1665
- this.uploading = false;
1666
- }
1667
- else if (!newVal) {
1668
- this.uploading = false;
1669
- this.previewUrl = '';
1670
- this.fileName = '';
1671
- }
1672
- }
1673
- handleFile(file) {
1674
- if (!file) {
1675
- this.previewUrl = '';
1676
- this.fileName = '';
1677
- this.uploading = false;
1678
- this.mrdChange.emit({ name: this.name, value: null });
1679
- return;
1680
- }
1681
- if (this.maxSize > 0 && file.size > this.maxSize) {
1682
- this.error = t('file_too_large', this.locale);
1683
- return;
1684
- }
1685
- if (!file.type.startsWith('image/')) {
1686
- this.error = 'Please select an image file';
1687
- return;
1688
- }
1689
- this.error = '';
1690
- this.fileName = file.name;
1691
- this.uploading = true;
1692
- // Show local preview immediately while upload is in progress
1693
- const reader = new FileReader();
1694
- reader.onload = (ev) => {
1695
- var _a;
1696
- this.previewUrl = (_a = ev.target) === null || _a === void 0 ? void 0 : _a.result;
1697
- };
1698
- reader.readAsDataURL(file);
1699
- this.mrdChange.emit({ name: this.name, value: file });
1700
- this.mrdUpload.emit({ name: this.name, file });
1701
- }
1702
- render() {
1703
- const hasError = !!this.error;
1704
- const zoneClass = [
1705
- 'mrd-image-field__zone',
1706
- this.isDragging ? 'mrd-image-field__zone--dragging' : '',
1707
- hasError ? 'mrd-image-field__zone--error' : '',
1708
- this.disabled || this.uploading ? 'mrd-image-field__zone--disabled' : '',
1709
- ].filter(Boolean).join(' ');
1710
- return (h(Host, { key: '71be4c1df559cff87280cac30be58beab3149064' }, h("div", { key: '9d0811d87068ce258aca9b2c5223a5594af9f6a3', class: "mrd-image-field" }, this.label && (h("label", { key: '63e129db968a2edfcc04fcac466d908ba4715158', class: `mrd-image-field__label${this.required ? ' mrd-image-field__label--required' : ''}` }, this.label)), h("div", { key: 'c7e560ad4dda43499707a2d1771a8eb561653a1b', class: zoneClass, onClick: this.handleZoneClick, onDragOver: this.handleDragOver, onDragLeave: this.handleDragLeave, onDrop: this.handleDrop }, h("input", { key: 'd325ee1aa3baccd689cc579e4cfa21abe977a575', 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: 'b0442d6f5c07ef22443194b3f1a95d2dfc409c4e', class: "mrd-image-field__error" }, this.error))));
1711
- }
1712
- static get watchers() { return {
1713
- "value": [{
1714
- "valueChanged": 0
1715
- }]
1716
- }; }
1717
- };
1718
- MrdImageField.style = mrdImageFieldScss();
1719
-
1720
- class CellRenderer {
1721
- static render(column, row, locale) {
1722
- var _a, _b, _c, _d;
1723
- if (column.type === ClientLayoutItemType.RELATION) {
1724
- const name = (_a = column.name) !== null && _a !== void 0 ? _a : '';
1725
- const link = (_b = row === null || row === void 0 ? void 0 : row._links) === null || _b === void 0 ? void 0 : _b[name];
1726
- if (!link)
1727
- return '';
1728
- if (Array.isArray(link))
1729
- return link.map((l) => { var _a; return (_a = l.name) !== null && _a !== void 0 ? _a : ''; }).filter(Boolean).join(', ');
1730
- return (_c = link.name) !== null && _c !== void 0 ? _c : '';
1731
- }
1732
- if (column.type !== ClientLayoutItemType.FIELD)
1733
- return '';
1734
- const name = (_d = column.name) !== null && _d !== void 0 ? _d : '';
1735
- const dataType = column.dataType;
1736
- const listItems = column.listItems;
1737
- const raw = row === null || row === void 0 ? void 0 : row[name];
1738
- if (raw == null || raw === '')
1739
- return '';
1740
- const values = Array.isArray(raw) ? raw : [raw];
1741
- return values
1742
- .map(v => CellRenderer.renderValue(dataType !== null && dataType !== void 0 ? dataType : 'TEXT', v, listItems !== null && listItems !== void 0 ? listItems : [], locale))
1743
- .filter(s => s !== '')
1744
- .join(', ');
1745
- }
1746
- static renderValue(dataType, value, listItems, locale) {
1747
- var _a, _b;
1748
- switch (dataType) {
1749
- case 'INTEGER':
1750
- return formatNumber(Number(value), locale, { maximumFractionDigits: 0 });
1751
- case 'DECIMAL':
1752
- return formatNumber(Number(value), locale);
1753
- case 'PERCENTAGE':
1754
- return formatPercentage(Number(value), locale);
1755
- case 'CURRENCY': {
1756
- const { amount, currency } = typeof value === 'object' && value !== null
1757
- ? value
1758
- : { amount: value, currency: '' };
1759
- return currency
1760
- ? formatCurrency(Number(amount), currency, locale)
1761
- : formatNumber(Number(amount), locale);
1762
- }
1763
- case 'DATE':
1764
- return formatDate(value, locale);
1765
- case 'DATETIME':
1766
- return formatDateTime(value, locale);
1767
- case 'TIME':
1768
- return formatTime(value, locale);
1769
- case 'BOOLEAN':
1770
- return value ? '✓' : '';
1771
- case 'FILE':
1772
- case 'IMAGE':
1773
- return typeof value === 'object' && value !== null ? ((_a = value.fileName) !== null && _a !== void 0 ? _a : '') : '';
1774
- case 'LIST': {
1775
- const item = listItems.find(li => li.key === String(value));
1776
- return (_b = item === null || item === void 0 ? void 0 : item.label) !== null && _b !== void 0 ? _b : String(value);
1777
- }
1778
- case 'TEXTBLOCK': {
1779
- const stripped = String(value).replace(/<[^>]*>/g, '');
1780
- const txt = document.createElement('textarea');
1781
- txt.innerHTML = stripped;
1782
- return txt.value.trim();
1783
- }
1784
- case 'LONGTEXT':
1785
- return String(value).replace(/[\r\n]+/g, ' ').trim();
1786
- case 'JSON': {
1787
- const str = typeof value === 'object' ? JSON.stringify(value) : String(value);
1788
- return str.replace(/[\r\n]+/g, ' ').trim();
1789
- }
1790
- case 'SECRET':
1791
- return value ? '••••••••' : '';
1792
- default:
1793
- return String(value);
1794
- }
1795
- }
1796
- /**
1797
- * Returns syntax-highlighted JSON as an HTML string with inline styles.
1798
- * compact=true → single line (no indentation); compact=false → pretty-printed.
1799
- */
1800
- static formatJson(value, compact = false) {
1801
- try {
1802
- const parsed = typeof value === 'string' ? JSON.parse(value) : value;
1803
- const json = compact ? JSON.stringify(parsed) : JSON.stringify(parsed, null, 2);
1804
- return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, match => {
1805
- let style = 'color:#2aa198';
1806
- if (/^"/.test(match)) {
1807
- style = /:$/.test(match) ? 'color:#881391' : 'color:#268bd2';
1808
- }
1809
- else if (/true|false/.test(match)) {
1810
- style = 'color:#b58900';
1811
- }
1812
- else if (/null/.test(match)) {
1813
- style = 'color:#dc322f';
1814
- }
1815
- return `<span style="${style}">${match}</span>`;
1816
- });
1817
- }
1818
- catch (_a) {
1819
- return String(value);
1820
- }
1821
- }
1822
- }
1823
-
1824
- 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;display:inline-flex;align-items:center;gap:var(--mrd-space-1)}.mrd-layout-section__history-wrap.sc-mrd-layout-section{position:relative;display:inline-flex;align-items:center}.mrd-layout-section__history-btn.sc-mrd-layout-section{display:inline-flex;align-items:center;justify-content:center;width:1.25rem;height:1.25rem;padding:0;background:transparent;border:none;border-radius:var(--mrd-border-radius-sm);color:var(--mrd-color-neutral-400);cursor:pointer;flex-shrink:0;transition:color var(--mrd-transition-fast), background-color var(--mrd-transition-fast)}.mrd-layout-section__history-btn.sc-mrd-layout-section:hover{color:var(--mrd-color-neutral-700);background-color:var(--mrd-color-neutral-100)}.mrd-layout-section__history-btn.sc-mrd-layout-section:focus{outline:none;box-shadow:var(--mrd-shadow-focus)}.mrd-layout-section__history-icon.sc-mrd-layout-section{width:0.875rem;height:0.875rem}.mrd-layout-section__history-popover.sc-mrd-layout-section{position:absolute;top:calc(100% + 0.25rem);left:0;min-width:24rem;max-width:24rem;background-color:var(--mrd-color-white);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius-md);box-shadow:var(--mrd-shadow-md);padding:var(--mrd-space-1) 0;z-index:var(--mrd-z-dropdown)}.mrd-layout-section__history-entry.sc-mrd-layout-section{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);font-weight:var(--mrd-font-weight-normal);color:var(--mrd-color-neutral-700);padding:var(--mrd-space-2) var(--mrd-space-3);line-height:var(--mrd-line-height-normal)}.mrd-layout-section__history-entry.sc-mrd-layout-section:not(:last-child){border-bottom:var(--mrd-border-width) solid var(--mrd-color-neutral-100)}.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__secret-masked.sc-mrd-layout-section{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-label-color);letter-spacing:0.15em;user-select:none;pointer-events:none}.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-wrap.sc-mrd-layout-section{position:relative}.mrd-layout-section__search-icon.sc-mrd-layout-section{position:absolute;left:var(--mrd-input-padding-x);top:50%;transform:translateY(-50%);width:1rem;height:1rem;color:var(--mrd-color-neutral-400);pointer-events:none}.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) var(--mrd-input-padding-y) calc(var(--mrd-input-padding-x) + 1rem + var(--mrd-space-2));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}`;
1825
-
1826
- const MrdLayoutSection = class {
1827
- constructor(hostRef) {
1828
- registerInstance(this, hostRef);
1829
- this.mrdNavigate = createEvent(this, "mrdNavigate");
1830
- this.mrdSearch = createEvent(this, "mrdSearch");
1831
- this.mrdDownload = createEvent(this, "mrdDownload");
1832
- this.mrdLoadViewPage = createEvent(this, "mrdLoadViewPage");
1833
- this.mrdLoadImage = createEvent(this, "mrdLoadImage");
1834
- this.mrdViewAction = createEvent(this, "mrdViewAction");
1835
- this.mrdLoadViewAggregations = createEvent(this, "mrdLoadViewAggregations");
1836
- /** Items from one layout entry in ClientDashboardMetadata.layouts[]. */
1837
- this.items = [];
1838
- /** Record data object; keys are field names, _links holds relation and related-view links. */
1839
- this.data = {};
1840
- /** Legacy: view metadata map (ClientDashboardMetadata.views). Not needed in new flat format. */
1841
- this.views = {};
1842
- /** Legacy: top-level _links from ClientDashboardMetadata. Not needed in new flat format. */
1843
- this.links = {};
1844
- this.locale = navigator.language;
1845
- this.searchQueryMap = {};
1846
- this.searchResultsMap = {};
1847
- this.imagePreviewUrl = null;
1848
- this.imagePreviews = {};
1849
- this.openHistoryField = null;
1850
- this.historyClickOutside = null;
1851
- this.searchTimers = {};
1852
- this.handleViewLoadPage = (e, name) => {
1853
- e.stopPropagation();
1854
- this.mrdLoadViewPage.emit({ name, page: e.detail.page, sort: e.detail.sort, path: e.detail.path, qs: e.detail.qs });
1855
- };
1856
- this.handleSearchInput = (dataClass, query) => {
1857
- this.searchQueryMap = Object.assign(Object.assign({}, this.searchQueryMap), { [dataClass]: query });
1858
- if (this.searchTimers[dataClass])
1859
- clearTimeout(this.searchTimers[dataClass]);
1860
- if (query.length < 2) {
1861
- this.searchResultsMap = Object.assign(Object.assign({}, this.searchResultsMap), { [dataClass]: [] });
1862
- return;
1863
- }
1864
- this.searchTimers[dataClass] = setTimeout(() => {
1865
- this.mrdSearch.emit({ query, dataClass });
1866
- }, 300);
1867
- };
1868
- }
1869
- componentDidLoad() {
1870
- setTimeout(() => {
1871
- this.initEmbeddedTables();
1872
- this.emitLoadImages();
1873
- }, 0);
1874
- this.historyClickOutside = (e) => {
1875
- if (!this.el.contains(e.target))
1876
- this.openHistoryField = null;
1877
- };
1878
- document.addEventListener('mousedown', this.historyClickOutside);
1879
- }
1880
- disconnectedCallback() {
1881
- if (this.historyClickOutside) {
1882
- document.removeEventListener('mousedown', this.historyClickOutside);
1883
- this.historyClickOutside = null;
1884
- }
1885
- }
1886
- dataChanged(newVal) {
1887
- if (newVal && Object.keys(newVal).length > 0) {
1888
- setTimeout(() => this.initEmbeddedTables(), 0);
1889
- }
1890
- }
1891
- async initEmbeddedTables() {
1892
- const tables = this.el.querySelectorAll('mrd-table[data-view]');
1893
- for (const table of Array.from(tables)) {
1894
- if (typeof table.init === 'function') {
1895
- await table.init();
1896
- }
1897
- }
1898
- }
1899
- viewKeyFor(item) {
1900
- var _a, _b, _c, _d;
1901
- if (item.type === ClientLayoutItemType.RELATED_VIEW)
1902
- return (_b = (_a = item.relatedClass) !== null && _a !== void 0 ? _a : item.name) !== null && _b !== void 0 ? _b : '';
1903
- return (_d = (_c = item.dataClass) !== null && _c !== void 0 ? _c : item.name) !== null && _d !== void 0 ? _d : '';
1904
- }
1905
- emitLoadImages() {
1906
- for (const item of this.flattenItems(this.items)) {
1907
- if (item.type === ClientLayoutItemType.FIELD && item.dataType === ClientLayoutItemFieldDataType.IMAGE) {
1908
- const fieldName = item.name;
1909
- const raw = this.data[fieldName];
1910
- const href = raw === null || raw === void 0 ? void 0 : raw.href;
1911
- if (href)
1912
- this.mrdLoadImage.emit({ fieldName, href });
1913
- }
1914
- }
1915
- }
1916
- flattenItems(items) {
1917
- const result = [];
1918
- for (const item of items) {
1919
- result.push(item);
1920
- if (item.items)
1921
- result.push(...this.flattenItems(item.items));
1922
- }
1923
- return result;
1924
- }
1925
- /** Inject search results. Pass dataClass to target a specific SEARCH item; omit when there is only one. */
1926
- async setSearchResults(results, dataClass) {
1927
- const key = dataClass !== null && dataClass !== void 0 ? dataClass : this.resolveSearchKey();
1928
- if (key) {
1929
- this.searchResultsMap = Object.assign(Object.assign({}, this.searchResultsMap), { [key]: results });
1930
- }
1931
- }
1932
- /**
1933
- * Inject data into an embedded mrd-table for a RELATED_VIEW or VIEW item.
1934
- * Pass totalElements to update the pagination total (safe to pass on every page).
1935
- * Pass hasNext (from _links.next presence) so the table can decide whether to emit aggregations.
1936
- */
1937
- async setViewPage(name, page, rows, totalElements, hasNext) {
1938
- const table = this.el.querySelector(`mrd-table[data-view="${name}"]`);
1939
- if (!table)
1940
- return;
1941
- if (totalElements !== undefined) {
1942
- table.totalElements = totalElements;
1943
- }
1944
- await table.setPage(page, rows, hasNext);
1945
- }
1946
- /** Inject aggregation totals into an embedded mrd-table for a VIEW or RELATED_VIEW item. */
1947
- async setViewAggregations(name, data) {
1948
- const table = this.el.querySelector(`mrd-table[data-view="${name}"]`);
1949
- if (!table)
1950
- return;
1951
- await table.setAggregations(data);
1952
- }
1953
- /** Provide a resolved URL for an IMAGE field. Shows as thumbnail; clicking opens the lightbox. */
1954
- async setImagePreview(fieldName, url) {
1955
- this.imagePreviews = Object.assign(Object.assign({}, this.imagePreviews), { [fieldName]: url });
1956
- }
1957
- /** Open the lightbox directly with a URL (e.g. after mrdDownload on a FILE field). */
1958
- async openImagePreview(url) {
1959
- this.imagePreviewUrl = url;
1960
- }
1961
- resolveSearchKey() {
1962
- var _a;
1963
- const items = this.flattenItems(this.items).filter(i => i.type === ClientLayoutItemType.SEARCH);
1964
- if (items.length === 1)
1965
- return (_a = items[0].dataClass) !== null && _a !== void 0 ? _a : null;
1966
- return null;
1967
- }
1968
- renderSingleFieldValue(item, value) {
1969
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
1970
- const dt = item.dataType;
1971
- switch (dt) {
1972
- case ClientLayoutItemFieldDataType.HYPERLINK: {
1973
- const v = value;
1974
- const href = (_a = v === null || v === void 0 ? void 0 : v.href) !== null && _a !== void 0 ? _a : String(value);
1975
- const label = (_d = (_c = (_b = v === null || v === void 0 ? void 0 : v.name) !== null && _b !== void 0 ? _b : v === null || v === void 0 ? void 0 : v.text) !== null && _c !== void 0 ? _c : v === null || v === void 0 ? void 0 : v.label) !== null && _d !== void 0 ? _d : href;
1976
- return (h("a", { class: "mrd-layout-section__link", href: href, target: "_blank", rel: "noopener noreferrer" }, label));
1977
- }
1978
- case ClientLayoutItemFieldDataType.TEXTBLOCK:
1979
- return h("span", { innerHTML: String(value) });
1980
- case ClientLayoutItemFieldDataType.LONGTEXT:
1981
- return h("pre", { class: "mrd-layout-section__pre" }, String(value));
1982
- case ClientLayoutItemFieldDataType.JSON:
1983
- return h("pre", { class: "mrd-layout-section__pre", innerHTML: CellRenderer.formatJson(value) });
1984
- case ClientLayoutItemFieldDataType.FILE: {
1985
- const v = value;
1986
- const fileName = (_e = v === null || v === void 0 ? void 0 : v.fileName) !== null && _e !== void 0 ? _e : String(value);
1987
- const href = (_f = v === null || v === void 0 ? void 0 : v.href) !== null && _f !== void 0 ? _f : '';
1988
- 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)));
1989
- }
1990
- case ClientLayoutItemFieldDataType.IMAGE: {
1991
- const v = value;
1992
- const href = (_g = v === null || v === void 0 ? void 0 : v.href) !== null && _g !== void 0 ? _g : '';
1993
- const fileName = (_h = v === null || v === void 0 ? void 0 : v.fileName) !== null && _h !== void 0 ? _h : '';
1994
- const previewUrl = this.imagePreviews[item.name];
1995
- if (previewUrl) {
1996
- 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 })));
1997
- }
1998
- 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));
1999
- }
2000
- case ClientLayoutItemFieldDataType.BOOLEAN:
2001
- return (h("span", { class: `mrd-layout-section__boolean mrd-layout-section__boolean--${value ? 'true' : 'false'}` }, value ? t('yes', this.locale) : t('no', this.locale)));
2002
- case ClientLayoutItemFieldDataType.LIST: {
2003
- const listItem = ((_j = item.listItems) !== null && _j !== void 0 ? _j : []).find(li => li.key === String(value));
2004
- const label = (_k = listItem === null || listItem === void 0 ? void 0 : listItem.label) !== null && _k !== void 0 ? _k : String(value);
2005
- const color = listItem === null || listItem === void 0 ? void 0 : listItem.color;
2006
- const bg = listItem === null || listItem === void 0 ? void 0 : listItem.backgroundColor;
2007
- if (color && bg) {
2008
- return (h("span", { class: "mrd-layout-section__badge", style: { color, backgroundColor: bg } }, label));
2009
- }
2010
- if (color) {
2011
- return (h("span", { class: "mrd-layout-section__badge-dot-row" }, h("span", { class: "mrd-layout-section__badge-dot", style: { backgroundColor: color } }), label));
2012
- }
2013
- return label;
2014
- }
2015
- case ClientLayoutItemFieldDataType.SECRET:
2016
- return value ? h("span", { class: "mrd-layout-section__secret-masked" }, '••••••••') : null;
2017
- default: {
2018
- const text = CellRenderer.renderValue(dt, value, (_l = item.listItems) !== null && _l !== void 0 ? _l : [], this.locale);
2019
- return text || null;
2020
- }
2021
- }
2022
- }
2023
- renderFieldValue(item, rawValue) {
2024
- if (rawValue == null || rawValue === '')
2025
- return null;
2026
- if (item.multiple && Array.isArray(rawValue)) {
2027
- const rendered = rawValue.map(v => this.renderSingleFieldValue(item, v));
2028
- if (rendered.every(r => typeof r === 'string' || r == null)) {
2029
- return rendered.filter(Boolean).join(', ') || null;
2030
- }
2031
- return (h("span", null, rendered.map((r, i) => (h("span", { key: String(i) }, r, i < rendered.length - 1 ? ', ' : '')))));
2032
- }
2033
- return this.renderSingleFieldValue(item, rawValue);
2034
- }
2035
- renderHistoryBadge(item, raw) {
2036
- var _a, _b, _c;
2037
- const hist = (_a = item.historyEnabled) !== null && _a !== void 0 ? _a : (_b = item.field) === null || _b === void 0 ? void 0 : _b.historyEnabled;
2038
- if (!hist || !item.name)
2039
- return null;
2040
- const history = (_c = raw === null || raw === void 0 ? void 0 : raw.history) !== null && _c !== void 0 ? _c : [];
2041
- if (!history.length)
2042
- return null;
2043
- const sorted = [...history].sort((a, b) => b.until.localeCompare(a.until));
2044
- const isOpen = this.openHistoryField === item.name;
2045
- const { locale } = this;
2046
- return (h("span", { class: "mrd-layout-section__history-wrap" }, h("button", { type: "button", class: "mrd-layout-section__history-btn", title: t('history_badge_tooltip', locale), "aria-label": t('history_badge_tooltip', locale), onClick: (e) => {
2047
- e.stopPropagation();
2048
- this.openHistoryField = isOpen ? null : item.name;
2049
- } }, h("svg", { class: "mrd-layout-section__history-icon", viewBox: "0 0 20 20", fill: "currentColor", "aria-hidden": "true" }, h("path", { "fill-rule": "evenodd", d: "M10 18a8 8 0 100-16 8 8 0 000 16zm.75-13a.75.75 0 00-1.5 0v5c0 .207.085.394.22.53l2.5 2.5a.75.75 0 101.06-1.06L10.75 9.69V5z", "clip-rule": "evenodd" }))), isOpen && (h("div", { class: "mrd-layout-section__history-popover", role: "listbox" }, sorted.map((entry, i) => (h("div", { key: String(i), class: "mrd-layout-section__history-entry" }, entry.value, " (", t('history_until', locale), " ", formatDate(entry.until, locale), ")")))))));
2050
- }
2051
- renderField(item) {
2052
- var _a, _b;
2053
- if (!item.name)
2054
- return null;
2055
- const raw = this.data[item.name];
2056
- const hist = (_a = item.historyEnabled) !== null && _a !== void 0 ? _a : (_b = item.field) === null || _b === void 0 ? void 0 : _b.historyEnabled;
2057
- const rawValue = hist && raw !== null && typeof raw === 'object' && 'current' in raw
2058
- ? raw.current
2059
- : raw;
2060
- const renderedValue = this.renderFieldValue(item, rawValue);
2061
- if (item.header) {
2062
- return (h("h1", { class: "mrd-layout-section__field-header", key: item.name }, typeof renderedValue === 'string' ? renderedValue : rawValue != null ? String(rawValue) : item.label));
2063
- }
2064
- if (renderedValue == null)
2065
- return null;
2066
- const isBlock = item.dataType === ClientLayoutItemFieldDataType.TEXTBLOCK
2067
- || item.dataType === ClientLayoutItemFieldDataType.LONGTEXT
2068
- || item.dataType === ClientLayoutItemFieldDataType.JSON;
2069
- return (h("div", { class: `mrd-layout-section__field${isBlock ? ' mrd-layout-section__field--block' : ''}`, key: item.name }, h("span", { class: "mrd-layout-section__field-label" }, item.label), h("span", { class: "mrd-layout-section__field-value" }, renderedValue, this.renderHistoryBadge(item, raw))));
2070
- }
2071
- renderRelation(item) {
2072
- var _a, _b, _c;
2073
- if (!item.name)
2074
- return null;
2075
- const links = ((_b = (_a = this.data) === null || _a === void 0 ? void 0 : _a._links) !== null && _b !== void 0 ? _b : {});
2076
- const link = links[item.name];
2077
- if (!link)
2078
- return null;
2079
- const makeBtn = (href, name) => (h("button", { key: href, class: "mrd-layout-section__relation-link", onClick: () => this.mrdNavigate.emit({ href, label: name }) }, name));
2080
- let valueContent;
2081
- if ((_c = link.values) === null || _c === void 0 ? void 0 : _c.length) {
2082
- valueContent = link.values.map(v => makeBtn(v.href, v.name));
2083
- }
2084
- else if (link.name) {
2085
- valueContent = makeBtn(link.href, link.name);
2086
- }
2087
- if (!valueContent)
2088
- return null;
2089
- return (h("div", { class: "mrd-layout-section__field", key: item.name }, h("span", { class: "mrd-layout-section__field-label" }, item.label), h("span", { class: "mrd-layout-section__field-value" }, valueContent)));
2090
- }
2091
- renderSearch(item) {
2092
- var _a, _b, _c;
2093
- if (!item.dataClass)
2094
- return null;
2095
- const dataClass = item.dataClass;
2096
- const query = (_a = this.searchQueryMap[dataClass]) !== null && _a !== void 0 ? _a : '';
2097
- const results = (_b = this.searchResultsMap[dataClass]) !== null && _b !== void 0 ? _b : [];
2098
- return (h("div", { class: "mrd-layout-section__search", key: `search-${dataClass}` }, h("div", { class: "mrd-layout-section__search-wrap" }, h("svg", { class: "mrd-layout-section__search-icon", xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 20 20", fill: "currentColor", "aria-hidden": "true" }, h("path", { "fill-rule": "evenodd", d: "M9 3.5a5.5 5.5 0 100 11 5.5 5.5 0 000-11zM2 9a7 7 0 1112.452 4.391l3.328 3.329a.75.75 0 11-1.06 1.06l-3.329-3.328A7 7 0 012 9z", "clip-rule": "evenodd" })), 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)))))))));
2099
- }
2100
- renderRelatedView(item) {
2101
- var _a, _b, _c, _d, _e, _f;
2102
- const key = this.viewKeyFor(item);
2103
- if (!key)
2104
- return null;
2105
- if (!item.view)
2106
- return null;
2107
- const showTitle = (_a = item.showTitle) !== null && _a !== void 0 ? _a : false;
2108
- // Extract parentId from data._links.self.href for RELATED_VIEW path construction
2109
- const selfHref = (_e = (_d = (_c = (_b = this.data) === null || _b === void 0 ? void 0 : _b._links) === null || _c === void 0 ? void 0 : _c.self) === null || _d === void 0 ? void 0 : _d.href) !== null && _e !== void 0 ? _e : '';
2110
- const parentId = (_f = selfHref.split('/').filter(Boolean).pop()) !== null && _f !== void 0 ? _f : '';
2111
- return (h("div", { class: "mrd-layout-section__related-view", key: `view-${key}` }, showTitle && item.label && h("h3", { class: "mrd-layout-section__related-view-title" }, item.label), h("mrd-table", { "data-view": key, item: item, parentId: parentId, locale: this.locale, onMrdLoadPage: (e) => this.handleViewLoadPage(e, key), onMrdLoadAggregations: (e) => {
2112
- var _a;
2113
- e.stopPropagation();
2114
- this.mrdLoadViewAggregations.emit(Object.assign({ name: key, dataClass: (_a = item.dataClass) !== null && _a !== void 0 ? _a : key }, e.detail));
2115
- }, onMrdRowClick: (e) => {
2116
- var _a, _b, _c;
2117
- e.stopPropagation();
2118
- const row = e.detail;
2119
- this.mrdNavigate.emit({ href: (_b = (_a = row === null || row === void 0 ? void 0 : row._links) === null || _a === void 0 ? void 0 : _a.self) === null || _b === void 0 ? void 0 : _b.href, label: (_c = row === null || row === void 0 ? void 0 : row.name) !== null && _c !== void 0 ? _c : '' });
2120
- }, onMrdAction: (e) => {
2121
- var _a;
2122
- e.stopPropagation();
2123
- this.mrdViewAction.emit({
2124
- name: key,
2125
- action: e.detail.action,
2126
- dataClass: (_a = item.dataClass) !== null && _a !== void 0 ? _a : key,
2127
- path: e.detail.path,
2128
- qs: e.detail.qs,
2129
- parentPath: e.detail.parentPath,
2130
- basicType: e.detail.basicType,
2131
- });
2132
- } })));
2133
- }
2134
- renderItem(item) {
2135
- var _a, _b;
2136
- switch (item.type) {
2137
- case ClientLayoutItemType.FIELD:
2138
- return this.renderField(item);
2139
- case ClientLayoutItemType.RELATION:
2140
- return this.renderRelation(item);
2141
- case ClientLayoutItemType.HEADER:
2142
- return (h("h2", { class: "mrd-layout-section__header", key: `header-${item.label}` }, item.label));
2143
- case ClientLayoutItemType.TEXT:
2144
- return h("div", { class: "mrd-layout-section__text", key: `text-${item.label}`, innerHTML: (_a = item.label) !== null && _a !== void 0 ? _a : '' });
2145
- case ClientLayoutItemType.NAVIGATE:
2146
- return (h("button", { class: "mrd-layout-section__navigate", key: `nav-${item.label}`, onClick: () => { var _a, _b, _c; return this.mrdNavigate.emit({ label: (_a = item.label) !== null && _a !== void 0 ? _a : '', navigate: (_b = item.navigate) !== null && _b !== void 0 ? _b : { dataClass: (_c = item.dataClass) !== null && _c !== void 0 ? _c : '', icon: item.icon, navigationType: item.navigationType } }); } }, item.label));
2147
- case ClientLayoutItemType.SEARCH:
2148
- return this.renderSearch(item);
2149
- case ClientLayoutItemType.SECTION:
2150
- case ClientLayoutItemType.GROUP:
2151
- 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))));
2152
- case ClientLayoutItemType.RELATED_VIEW:
2153
- case ClientLayoutItemType.VIEW:
2154
- return this.renderRelatedView(item);
2155
- default:
2156
- return null;
2157
- }
2158
- }
2159
- renderImageModal() {
2160
- if (!this.imagePreviewUrl)
2161
- return null;
2162
- 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: "" }))));
2163
- }
2164
- render() {
2165
- return (h(Host, { key: '8966198eebd98570d2db2f4d2fe9ef3f8b466ec6' }, h("div", { key: '645ddbfdd829a0f9c1a4eab18105662af6c078b2', class: "mrd-layout-section" }, this.items.map(item => this.renderItem(item))), this.renderImageModal()));
2166
- }
2167
- get el() { return getElement(this); }
2168
- static get watchers() { return {
2169
- "data": [{
2170
- "dataChanged": 0
2171
- }]
2172
- }; }
2173
- };
2174
- MrdLayoutSection.style = mrdLayoutSectionScss();
2175
-
2176
- 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)}`;
2177
-
2178
- const MrdListField = class {
2179
- constructor(hostRef) {
2180
- registerInstance(this, hostRef);
2181
- this.mrdChange = createEvent(this, "mrdChange");
2182
- this.mrdBlur = createEvent(this, "mrdBlur");
2183
- this.name = '';
2184
- this.label = '';
2185
- this.value = '';
2186
- this.required = false;
2187
- this.disabled = false;
2188
- this.multiple = false;
2189
- this.locale = navigator.language;
2190
- /** List items from the API. Each item has a `key` (stored value) and `label`. */
2191
- this.listItems = [];
2192
- this.error = '';
2193
- this.selected = [];
2194
- this.handleSelectChange = (e) => {
2195
- const select = e.target;
2196
- if (this.multiple) {
2197
- const vals = Array.from(select.selectedOptions).map(o => o.value);
2198
- this.selected = vals;
2199
- if (this.required && !validateRequired(vals)) {
2200
- this.error = t('required', this.locale);
2201
- }
2202
- else {
2203
- this.error = '';
2204
- }
2205
- this.mrdChange.emit({ name: this.name, value: vals });
2206
- }
2207
- else {
2208
- const val = select.value;
2209
- if (this.required && !validateRequired(val)) {
2210
- this.error = t('required', this.locale);
2211
- }
2212
- else {
2213
- this.error = '';
2214
- }
2215
- this.mrdChange.emit({ name: this.name, value: val });
2216
- }
2217
- };
2218
- this.handleBlur = () => {
2219
- const val = this.multiple ? this.selected : this.value;
2220
- this.mrdBlur.emit({ name: this.name, value: val });
2221
- };
2222
- this.toggleCheckbox = (key) => {
2223
- if (this.selected.includes(key)) {
2224
- this.selected = this.selected.filter(v => v !== key);
2225
- }
2226
- else {
2227
- this.selected = [...this.selected, key];
2228
- }
2229
- if (this.required && !validateRequired(this.selected)) {
2230
- this.error = t('required', this.locale);
2231
- }
2232
- else {
2233
- this.error = '';
2234
- }
2235
- this.mrdChange.emit({ name: this.name, value: this.selected });
2236
- };
2237
- }
2238
- componentWillLoad() {
2239
- if (this.multiple) {
2240
- this.selected = Array.isArray(this.value) ? this.value : this.value ? [this.value] : [];
2241
- }
2242
- }
2243
- getContrastColor(bgColor) {
2244
- if (!bgColor)
2245
- return '#000000';
2246
- const hex = bgColor.replace('#', '');
2247
- const r = parseInt(hex.substr(0, 2), 16);
2248
- const g = parseInt(hex.substr(2, 2), 16);
2249
- const b = parseInt(hex.substr(4, 2), 16);
2250
- const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
2251
- return luminance > 0.5 ? '#000000' : '#ffffff';
2252
- }
2253
- render() {
2254
- var _a, _b;
2255
- const hasError = !!this.error;
2256
- const currentValue = Array.isArray(this.value) ? ((_a = this.value[0]) !== null && _a !== void 0 ? _a : '') : ((_b = this.value) !== null && _b !== void 0 ? _b : '');
2257
- if (this.multiple) {
2258
- 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 => {
2259
- var _a, _b;
2260
- 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)));
2261
- })), hasError && h("span", { class: "mrd-list-field__error" }, this.error))));
2262
- }
2263
- 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 => {
2264
- var _a, _b;
2265
- const bg = (_b = (_a = lv.backgroundColor) !== null && _a !== void 0 ? _a : lv.color) !== null && _b !== void 0 ? _b : null;
2266
- const style = bg ? { backgroundColor: bg, color: this.getContrastColor(bg) } : {};
2267
- return (h("option", { key: lv.key, value: lv.key, selected: lv.key === currentValue, style: style }, lv.label));
2268
- })), hasError && h("span", { class: "mrd-list-field__error" }, this.error))));
2269
- }
2270
- };
2271
- MrdListField.style = mrdListFieldScss();
2272
-
2273
- 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)}`;
2274
-
2275
- const MrdLongtextField = class {
2276
- constructor(hostRef) {
2277
- registerInstance(this, hostRef);
2278
- this.mrdChange = createEvent(this, "mrdChange");
2279
- this.mrdBlur = createEvent(this, "mrdBlur");
2280
- this.name = '';
2281
- this.label = '';
2282
- this.value = '';
2283
- this.placeholder = '';
2284
- this.required = false;
2285
- this.disabled = false;
2286
- this.locale = navigator.language;
2287
- this.error = '';
2288
- this.handleInput = (e) => {
2289
- const val = e.target.value;
2290
- this.mrdChange.emit({ name: this.name, value: val });
2291
- };
2292
- this.handleBlur = (e) => {
2293
- const val = e.target.value;
2294
- if (this.required && !validateRequired(val)) {
2295
- this.error = t('required', this.locale);
2296
- }
2297
- else {
2298
- this.error = '';
2299
- }
2300
- this.mrdBlur.emit({ name: this.name, value: val });
2301
- };
2302
- }
2303
- render() {
2304
- const hasError = !!this.error;
2305
- return (h(Host, { key: '10d998b80f54cf7b10be26bf451d808c78579e69' }, h("div", { key: 'af45fe94a41f668bf6ddca670b42e065ee83ef23', class: "mrd-longtext-field" }, this.label && (h("label", { key: '31a08490d695ac9f4bbe5dff6a1ae3bb2a94337d', 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: '7f133e72a882a8aaf33245445829754da1e6377b', class: "mrd-longtext-field__error" }, this.error))));
2306
- }
2307
- };
2308
- MrdLongtextField.style = mrdLongtextFieldScss();
2309
-
2310
- 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)}`;
2311
-
2312
- const MrdNumberField = class {
2313
- constructor(hostRef) {
2314
- registerInstance(this, hostRef);
2315
- this.mrdChange = createEvent(this, "mrdChange");
2316
- this.mrdBlur = createEvent(this, "mrdBlur");
2317
- this.name = '';
2318
- this.label = '';
2319
- this.value = null;
2320
- this.placeholder = '';
2321
- this.required = false;
2322
- this.disabled = false;
2323
- this.locale = navigator.language;
2324
- this.dataType = ClientLayoutItemFieldDataType.INTEGER;
2325
- this.decimalPrecision = 2;
2326
- this.displayValue = '';
2327
- this.error = '';
2328
- this.handleInput = (e) => {
2329
- this.displayValue = e.target.value;
2330
- };
2331
- this.handleBlur = (e) => {
2332
- const raw = e.target.value;
2333
- const parsed = parseLocalizedNumber(raw, this.locale);
2334
- if (this.required && (parsed === null || raw === '')) {
2335
- this.error = t('required', this.locale);
2336
- }
2337
- else if (raw !== '' && !validateNumber(parsed, this.dataType)) {
2338
- this.error = t('invalid_number', this.locale);
2339
- }
2340
- else {
2341
- this.error = '';
2342
- }
2343
- if (parsed !== null && validateRequired(raw)) {
2344
- this.displayValue = this.formatForDisplay(parsed);
2345
- }
2346
- this.mrdChange.emit({ name: this.name, value: parsed });
2347
- this.mrdBlur.emit({ name: this.name, value: parsed });
2348
- };
2349
- this.handleFocus = () => {
2350
- // Show raw number on focus
2351
- if (this.value !== null && this.value !== undefined) {
2352
- const str = String(this.value);
2353
- this.displayValue = str;
2354
- }
2355
- };
2356
- }
2357
- componentWillLoad() {
2358
- if (this.value !== null && this.value !== undefined) {
2359
- this.displayValue = this.formatForDisplay(this.value);
2360
- }
2361
- }
2362
- formatForDisplay(val) {
2363
- if (this.dataType === ClientLayoutItemFieldDataType.PERCENTAGE) {
2364
- return formatNumber(val, this.locale, {
2365
- minimumFractionDigits: 0,
2366
- maximumFractionDigits: this.decimalPrecision,
2367
- }) + '%';
2368
- }
2369
- if (this.dataType === ClientLayoutItemFieldDataType.DECIMAL) {
2370
- return formatNumber(val, this.locale, {
2371
- minimumFractionDigits: this.decimalPrecision,
2372
- maximumFractionDigits: this.decimalPrecision,
2373
- });
2374
- }
2375
- return formatNumber(val, this.locale, { maximumFractionDigits: 0 });
2376
- }
2377
- render() {
2378
- const hasError = !!this.error;
2379
- const suffix = this.dataType === ClientLayoutItemFieldDataType.PERCENTAGE ? '%' :
2380
- this.dataType === ClientLayoutItemFieldDataType.DECIMAL ? '' : '';
2381
- return (h(Host, { key: '195beed4d6453597320b79654feaabe8f742eff2' }, h("div", { key: 'c641d7a4d27ba28dd34acda98d38f245945d20bb', class: "mrd-number-field" }, this.label && (h("label", { key: '2a5f6eb48889a3ab0aa76d6b2ca5d59b20625bb2', class: `mrd-number-field__label${this.required ? ' mrd-number-field__label--required' : ''}` }, this.label)), h("div", { key: 'a844b89e6a278629a8aefa4ac72e5e18e5904cab', class: "mrd-number-field__input-wrapper" }, h("input", { key: '1ce9c3d67b458601a0de95b3b8478ef05df73069', 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: '4226614a65a8d27543d1287e2c1f61f67c427e63', class: "mrd-number-field__error" }, this.error))));
2382
- }
2383
- };
2384
- MrdNumberField.style = mrdNumberFieldScss();
2385
-
2386
- 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)}`;
2387
-
2388
- const MrdRelationField = class {
2389
- constructor(hostRef) {
2390
- registerInstance(this, hostRef);
2391
- this.mrdChange = createEvent(this, "mrdChange");
2392
- this.mrdBlur = createEvent(this, "mrdBlur");
2393
- this.mrdSearch = createEvent(this, "mrdSearch");
2394
- this.mrdFetchAll = createEvent(this, "mrdFetchAll");
2395
- this.name = '';
2396
- this.label = '';
2397
- this.required = false;
2398
- this.disabled = false;
2399
- this.locale = navigator.language;
2400
- this.relatedClass = '';
2401
- /** When set, used instead of relatedClass for search queries (mostSignificantClass from API). */
2402
- this.mostSignificantClass = '';
2403
- this.displayType = ClientLayoutItemRelationDisplayType.SEARCH;
2404
- this.multiple = false;
2405
- this.dropdownValues = [];
2406
- /** Plain href string/array for normal use; pass { id, label } objects to pre-fill a loaded record. */
2407
- this.value = null;
2408
- this.searchQuery = '';
2409
- this.searchResults = [];
2410
- this.allRecords = [];
2411
- this.isLoading = false;
2412
- this.selectedItems = [];
2413
- this.showResults = false;
2414
- this.error = '';
2415
- this.highlightedIndex = -1;
2416
- this.searchDebounce = null;
2417
- this.handleKeyDown = (e) => {
2418
- if (!this.showResults || this.searchResults.length === 0) {
2419
- if (e.key === 'Escape') {
2420
- this.showResults = false;
2421
- this.highlightedIndex = -1;
2422
- }
2423
- return;
2424
- }
2425
- if (e.key === 'ArrowDown') {
2426
- e.preventDefault();
2427
- this.highlightedIndex = Math.min(this.highlightedIndex + 1, this.searchResults.length - 1);
2428
- }
2429
- else if (e.key === 'ArrowUp') {
2430
- e.preventDefault();
2431
- this.highlightedIndex = Math.max(this.highlightedIndex - 1, 0);
2432
- }
2433
- else if (e.key === 'Enter') {
2434
- e.preventDefault();
2435
- if (this.highlightedIndex >= 0) {
2436
- this.handleResultSelect(this.searchResults[this.highlightedIndex]);
2437
- }
2438
- }
2439
- else if (e.key === 'Escape') {
2440
- this.showResults = false;
2441
- this.highlightedIndex = -1;
2442
- }
2443
- };
2444
- this.clearSelection = () => {
2445
- this.selectedItems = [];
2446
- this.searchQuery = '';
2447
- this.searchResults = [];
2448
- this.showResults = false;
2449
- this.highlightedIndex = -1;
2450
- this.mrdChange.emit({ name: this.name, value: this.multiple ? [] : null });
2451
- };
2452
- this.handleSearchInput = (e) => {
2453
- const query = e.target.value;
2454
- this.searchQuery = query;
2455
- if (this.searchDebounce)
2456
- clearTimeout(this.searchDebounce);
2457
- if (query.trim().length >= 2) {
2458
- this.isLoading = true;
2459
- this.showResults = true;
2460
- this.searchDebounce = setTimeout(() => {
2461
- this.mrdSearch.emit({ name: this.name, query, relatedClass: this.mostSignificantClass });
2462
- }, 300);
2463
- }
2464
- else {
2465
- this.searchResults = [];
2466
- this.showResults = false;
2467
- this.isLoading = false;
2468
- }
2469
- };
2470
- this.handleResultSelect = (result) => {
2471
- if (this.multiple) {
2472
- if (!this.selectedItems.find(i => i.id === result.id)) {
2473
- this.selectedItems = [...this.selectedItems, result];
2474
- }
2475
- this.searchQuery = '';
2476
- this.searchResults = [];
2477
- this.showResults = false;
2478
- const ids = this.selectedItems.map(i => i.id);
2479
- this.mrdChange.emit({ name: this.name, value: ids });
2480
- }
2481
- else {
2482
- this.selectedItems = [result];
2483
- this.searchQuery = result.label;
2484
- this.showResults = false;
2485
- this.mrdChange.emit({ name: this.name, value: result.id });
2486
- }
2487
- if (this.required && !validateRequired(this.selectedItems)) {
2488
- this.error = t('required', this.locale);
2489
- }
2490
- else {
2491
- this.error = '';
2492
- }
2493
- };
2494
- this.handleRemoveSelected = (id) => {
2495
- this.selectedItems = this.selectedItems.filter(i => i.id !== id);
2496
- const ids = this.selectedItems.map(i => i.id);
2497
- this.mrdChange.emit({ name: this.name, value: this.multiple ? ids : null });
2498
- };
2499
- this.handleDropdownChange = (e) => {
2500
- const val = e.target.value;
2501
- if (this.required && !validateRequired(val)) {
2502
- this.error = t('required', this.locale);
2503
- }
2504
- else {
2505
- this.error = '';
2506
- }
2507
- this.mrdChange.emit({ name: this.name, value: val });
2508
- };
2509
- this.handleBlur = () => {
2510
- var _a, _b;
2511
- setTimeout(() => {
2512
- this.showResults = false;
2513
- this.highlightedIndex = -1;
2514
- }, 200);
2515
- 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);
2516
- this.mrdBlur.emit({ name: this.name, value: val });
2517
- };
2518
- }
2519
- async setAllRecords(records) {
2520
- this.allRecords = records;
2521
- }
2522
- getValueHref() {
2523
- var _a, _b, _c;
2524
- const v = Array.isArray(this.value) ? ((_a = this.value[0]) !== null && _a !== void 0 ? _a : '') : ((_b = this.value) !== null && _b !== void 0 ? _b : '');
2525
- if (!v)
2526
- return '';
2527
- if (typeof v === 'object')
2528
- return (_c = v.id) !== null && _c !== void 0 ? _c : '';
2529
- return v;
2530
- }
2531
- allRecordsChanged() {
2532
- if (this.editBehavior !== ClientLayoutItemRelationEditBehavior.DROPDOWN)
2533
- return;
2534
- const current = this.getValueHref();
2535
- if (!current)
2536
- return;
2537
- // Defer past Stencil's async render cycle: options must exist in the DOM before
2538
- // select.value can be set. setAttribute('selected') alone is ignored by browsers
2539
- // when the select already has an established value.
2540
- setTimeout(() => {
2541
- var _a;
2542
- const select = (_a = this.el) === null || _a === void 0 ? void 0 : _a.querySelector('select');
2543
- if (select)
2544
- select.value = current;
2545
- }, 0);
2546
- }
2547
- async setSearchResults(results) {
2548
- this.searchResults = results;
2549
- this.isLoading = false;
2550
- this.showResults = true;
2551
- this.highlightedIndex = -1;
2552
- }
2553
- async setLoading(loading) {
2554
- this.isLoading = loading;
2555
- }
2556
- toSearchResult(v) {
2557
- var _a, _b, _c, _d;
2558
- return {
2559
- id: (_b = (_a = v.id) !== null && _a !== void 0 ? _a : v.href) !== null && _b !== void 0 ? _b : '',
2560
- label: (_d = (_c = v.label) !== null && _c !== void 0 ? _c : v.name) !== null && _d !== void 0 ? _d : '',
2561
- description: v.description,
2562
- };
2563
- }
2564
- applyValuePrefill(v) {
2565
- if (!v)
2566
- return;
2567
- if (Array.isArray(v)) {
2568
- if (v.length > 0 && typeof v[0] === 'object') {
2569
- this.selectedItems = v.map(item => this.toSearchResult(item));
2570
- this.searchQuery = '';
2571
- }
2572
- // array of strings → user interaction, ignore
2573
- }
2574
- else if (typeof v === 'object') {
2575
- const obj = v;
2576
- if (Array.isArray(obj.values)) {
2577
- // Multiple relation: API embeds selected items in values[]
2578
- this.selectedItems = obj.values.map((item) => this.toSearchResult(item));
2579
- this.searchQuery = '';
2580
- }
2581
- else if (!this.multiple && (obj.id || obj.name || obj.label)) {
2582
- // Single relation: { href, name } or already { id, label }
2583
- const result = this.toSearchResult(obj);
2584
- this.selectedItems = [result];
2585
- this.searchQuery = result.label;
2586
- }
2587
- // else: collection href (multiple without values) or unrecognised — skip
2588
- }
2589
- }
2590
- componentWillLoad() {
2591
- this.applyValuePrefill(this.value);
2592
- }
2593
- // Handles edit-mode: values prop on mrd-form is often set async after mount.
2594
- // Only updates selectedItems when the new value contains { id, label } objects
2595
- // (host pre-fill). Plain href strings from user interaction are ignored.
2596
- valueChanged(newValue) {
2597
- this.applyValuePrefill(newValue);
2598
- }
2599
- componentDidLoad() {
2600
- // Only emit when there is no commonRelation dependency — the form orchestrates those.
2601
- if (this.editBehavior === ClientLayoutItemRelationEditBehavior.DROPDOWN && !this.commonRelation) {
2602
- // Defer to next tick so parent event listeners are registered after DOM patching
2603
- setTimeout(() => {
2604
- this.mrdFetchAll.emit({
2605
- name: this.name,
2606
- relatedClass: this.relatedClass,
2607
- mostSignificantClass: this.mostSignificantClass || undefined,
2608
- });
2609
- }, 0);
2610
- }
2611
- }
2612
- render() {
2613
- var _a, _b;
2614
- const hasError = !!this.error;
2615
- if (this.editBehavior === ClientLayoutItemRelationEditBehavior.DROPDOWN) {
2616
- const currentValue = this.getValueHref();
2617
- 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))));
2618
- }
2619
- if (this.displayType === ClientLayoutItemRelationDisplayType.DROPDOWN) {
2620
- const currentValue = Array.isArray(this.value) ? ((_a = this.value[0]) !== null && _a !== void 0 ? _a : '') : ((_b = this.value) !== null && _b !== void 0 ? _b : '');
2621
- 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))));
2622
- }
2623
- // SEARCH mode
2624
- const labelEl = this.label && (h("label", { class: `mrd-relation-field__label${this.required ? ' mrd-relation-field__label--required' : ''}` }, this.label));
2625
- // Single selection: show selected value as a badge, hide the search input
2626
- if (!this.multiple && this.selectedItems.length > 0) {
2627
- 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))));
2628
- }
2629
- 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))));
2630
- }
2631
- get el() { return getElement(this); }
2632
- static get watchers() { return {
2633
- "allRecords": [{
2634
- "allRecordsChanged": 0
2635
- }],
2636
- "value": [{
2637
- "valueChanged": 0
2638
- }]
2639
- }; }
2640
- };
2641
- MrdRelationField.style = mrdRelationFieldScss();
2642
-
2643
- const mrdSecretFieldScss = () => `.sc-mrd-secret-field-h{display:block}.mrd-secret-field.sc-mrd-secret-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-secret-field__label.sc-mrd-secret-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-secret-field__label--required.sc-mrd-secret-field::after{content:' *';color:var(--mrd-color-danger)}.mrd-secret-field__input.sc-mrd-secret-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-secret-field__input.sc-mrd-secret-field::placeholder{color:var(--mrd-input-placeholder-color)}.mrd-secret-field__input.sc-mrd-secret-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-secret-field__input--error.sc-mrd-secret-field{border-color:var(--mrd-border-color-error)}.mrd-secret-field__input--error.sc-mrd-secret-field:focus{box-shadow:var(--mrd-shadow-focus-error)}.mrd-secret-field__error.sc-mrd-secret-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}.mrd-secret-field__masked.sc-mrd-secret-field{display:block;font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-label-color);letter-spacing:0.15em;user-select:none;pointer-events:none}`;
2644
-
2645
- const MrdSecretField = class {
2646
- constructor(hostRef) {
2647
- registerInstance(this, hostRef);
2648
- this.mrdChange = createEvent(this, "mrdChange");
2649
- this.mrdBlur = createEvent(this, "mrdBlur");
2650
- this.name = '';
2651
- this.label = '';
2652
- this.value = '';
2653
- this.placeholder = '';
2654
- this.required = false;
2655
- this.disabled = false;
2656
- this.locale = navigator.language;
2657
- this.error = '';
2658
- this.handleInput = (e) => {
2659
- const val = e.target.value;
2660
- this.mrdChange.emit({ name: this.name, value: val });
2661
- };
2662
- this.handleBlur = (e) => {
2663
- const val = e.target.value;
2664
- if (this.required && !validateRequired(val)) {
2665
- this.error = t('required', this.locale);
2666
- }
2667
- else {
2668
- this.error = '';
2669
- }
2670
- this.mrdBlur.emit({ name: this.name, value: val });
2671
- };
2672
- }
2673
- render() {
2674
- const hasError = !!this.error;
2675
- return (h(Host, { key: '08f1aa9d8ab9f4e41abb6d3286e5e383427a5409' }, h("div", { key: 'fabe38aa130e211cea81f2c2f227bc15ad3ebf7d', class: "mrd-secret-field" }, this.label && (h("label", { key: '69af8844eff8ce84daa622635c79130fb491eb0b', class: `mrd-secret-field__label${this.required ? ' mrd-secret-field__label--required' : ''}` }, this.label)), this.disabled
2676
- ? (h("span", { class: "mrd-secret-field__masked", "aria-label": this.label }, this.value ? '••••••••' : ''))
2677
- : (h("input", { class: `mrd-secret-field__input${hasError ? ' mrd-secret-field__input--error' : ''}`, type: "password", name: this.name, value: this.value, placeholder: this.placeholder, required: this.required, autocomplete: "new-password", onInput: this.handleInput, onBlur: this.handleBlur })), hasError && h("span", { key: 'e602004f0bb10916d1015e3c2b003523a292997c', class: "mrd-secret-field__error" }, this.error))));
2678
- }
2679
- };
2680
- MrdSecretField.style = mrdSecretFieldScss();
2681
-
2682
- 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-switcher.sc-mrd-table{display:flex;align-items:center;gap:var(--mrd-space-1)}.mrd-table__view-arrow.sc-mrd-table{background:none;border:none;cursor:pointer;padding:0 var(--mrd-space-1);color:var(--mrd-color-neutral-500);font-size:var(--mrd-font-size-xs);line-height:1}.mrd-table__view-arrow.sc-mrd-table:hover{color:var(--mrd-color-neutral-800)}.mrd-table__view-title-wrap.sc-mrd-table{position:relative}.mrd-table__view-title.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 var(--mrd-space-1);max-width:220px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mrd-table__view-title.sc-mrd-table:hover{color:var(--mrd-color-primary)}.mrd-table__view-popover.sc-mrd-table{position:absolute;top:calc(100% + var(--mrd-space-1));left:50%;transform:translateX(-50%);background:var(--mrd-color-white);border:1px solid var(--mrd-color-neutral-200);border-radius:var(--mrd-radius-md);box-shadow:var(--mrd-shadow-md);z-index:100;min-width:160px;padding:var(--mrd-space-1) 0}.mrd-table__view-popover-item.sc-mrd-table{display:block;width:100%;text-align:left;background:none;border:none;cursor:pointer;padding:var(--mrd-space-2) var(--mrd-space-3);font-size:var(--mrd-font-size-sm);font-family:var(--mrd-font-family);color:var(--mrd-color-neutral-700);white-space:nowrap}.mrd-table__view-popover-item.sc-mrd-table:hover{background:var(--mrd-color-neutral-50)}.mrd-table__view-popover-item--active.sc-mrd-table{font-weight:600;color:var(--mrd-color-primary)}.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__create-picker-wrap.sc-mrd-table{position:relative}.mrd-table__create-picker.sc-mrd-table{position:absolute;right:0;top:calc(100% + 4px);background:var(--mrd-color-white, #fff);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, 0.12));z-index:10;min-width:10rem;padding:var(--mrd-space-1) 0}.mrd-table__create-picker-item.sc-mrd-table{display:block;width:100%;text-align:left;padding:var(--mrd-space-2) var(--mrd-space-3);background:none;border:none;cursor:pointer;font-size:var(--mrd-font-size-sm);font-family:var(--mrd-font-family);color:var(--mrd-color-neutral-800)}.mrd-table__create-picker-item.sc-mrd-table:hover{background:var(--mrd-color-neutral-50);color:var(--mrd-color-neutral-900)}.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}`;
2683
-
2684
- const BUFFER = 10;
2685
- /** Wacht deze tijd (ms) na het laatste scroll-event voordat pagina's worden
2686
- * aangevraagd. Pagina's die de gebruiker snel voorbij scrollt worden zo geskipt. */
2687
- const REQUEST_DEBOUNCE_MS = 150;
2688
- /** Breedte van de filterpopup in px — voor overflow-correctie. */
2689
- const POPUP_WIDTH = 280;
2690
- const TEXT_TYPES = new Set(['TEXT', 'TEXTBLOCK', 'EMAIL', 'HYPERLINK']);
2691
- const NUMERIC_TYPES = new Set(['INTEGER', 'DECIMAL', 'PERCENTAGE', 'CURRENCY']);
2692
- const DATE_TYPES = new Set(['DATE', 'DATETIME', 'TIME']);
2693
- const NO_FILTER_TYPES = new Set(['FILE', 'IMAGE']);
2694
- /** Column types that cannot be sorted or filtered (not stored in PostgreSQL). */
2695
- const NON_INTERACTIVE_TYPES = new Set(['LONGTEXT', 'JSON', 'FILE', 'IMAGE']);
2696
- const MrdTable = class {
2697
- constructor(hostRef) {
2698
- registerInstance(this, hostRef);
2699
- this.mrdLoadPage = createEvent(this, "mrdLoadPage");
2700
- this.mrdRowClick = createEvent(this, "mrdRowClick");
2701
- this.mrdAction = createEvent(this, "mrdAction");
2702
- this.mrdDownload = createEvent(this, "mrdDownload");
2703
- this.mrdLoadAggregations = createEvent(this, "mrdLoadAggregations");
2704
- // ── Non-state internals ────────────────────────────────────────────────────
2705
- this.pendingPages = new Set();
2706
- this.debounceTimer = null;
2707
- this.outsideClickHandler = null;
2708
- this.keydownHandler = null;
2709
- this.createPickerClickHandler = null;
2710
- this.viewPopoverClickHandler = null;
2711
- // ── Props ──────────────────────────────────────────────────────────────────
2712
- /** The VIEW or RELATED_VIEW layout item. Contains view config, dataClass, fromClass, actions etc. */
2713
- this.item = null;
2714
- /** Parent record id — required for RELATED_VIEW to build /{fromClass}/{parentId}/{dataClass}. */
2715
- this.parentId = '';
2716
- /** Direct rows (non-paginated mode, used when totalElements === 0). */
2717
- this.rows = [];
2718
- this.locale = navigator.language;
2719
- /** Total number of records across all pages. 0 = non-paginated mode. */
2720
- this.totalElements = 0;
2721
- /** Records per page (must match the API page size). */
2722
- this.pageSize = 20;
2723
- /** Row height in px — used for spacer and scroll-position maths. */
2724
- this.rowHeight = 36;
2725
- /** Height of the scroll container in px. */
2726
- this.tableHeight = 500;
2727
- // ── Internal state ─────────────────────────────────────────────────────────
2728
- /** Index into allViews[] for the currently displayed view. 0 = primary, 1+ = alternatives. */
2729
- this.activeViewIdx = 0;
2730
- this.loadedPages = new Map();
2731
- this.requestedPages = new Set();
2732
- this.renderStart = 0;
2733
- this.renderEnd = 0;
2734
- this.colWidths = [];
2735
- this.sortField = '';
2736
- this.sortDir = 'asc';
2737
- /** Whether the filter UI is visible on column headers. */
2738
- this.filterMode = false;
2739
- /** Active filters keyed by field name. */
2740
- this.activeFilters = new Map();
2741
- /** Field name of the currently open filter popup (null = closed). */
2742
- this.openFilterCol = null;
2743
- /** Filter state being edited in the open popup. */
2744
- this.pendingFilter = null;
2745
- /** Viewport-relative position for the filter popup. */
2746
- this.popupPos = { top: 0, left: 0 };
2747
- /** Whether the create-type picker dropdown is open. */
2748
- this.createPickerOpen = false;
2749
- /** Whether the view-switcher popover (full list) is open. */
2750
- this.viewPopoverOpen = false;
2751
- /** Current scroll offset of the scroll container — drives pagination footer. */
2752
- this.scrollTop = 0;
2753
- /** Full text shown in the TEXTBLOCK expand modal (null = closed). */
2754
- this.textblockModal = null;
2755
- /** Syntax-highlighted JSON HTML shown in the JSON expand modal (null = closed). */
2756
- this.jsonModal = null;
2757
- /** Aggregation totals received from the host via setAggregations(). Null = not yet loaded. */
2758
- this.aggregations = null;
2759
- /** Record count received via setAggregations().total; overrides totalElements for display. */
2760
- this.aggregationsTotal = null;
2761
- /** True when a fresh aggregations request is needed (set on init / filter change). */
2762
- this.aggregationsPending = false;
2763
- /** Lower bound on total derived from setPage() hasNext info; grows as pages load. */
2764
- this.minKnownTotal = 0;
2765
- this.handleScroll = (e) => {
2766
- const scroller = e.currentTarget;
2767
- const scrollTop = scroller.scrollTop;
2768
- const total = this.baseTotal;
2769
- const visStart = Math.floor(scrollTop / this.rowHeight);
2770
- const visEnd = Math.min(visStart + this.visibleCount(), total - 1);
2771
- this.scrollTop = scrollTop;
2772
- this.renderStart = Math.max(0, visStart - BUFFER);
2773
- this.renderEnd = Math.min(total - 1, visEnd + BUFFER);
2774
- this.requestPagesForWindow(this.renderStart, this.renderEnd);
2775
- };
2776
- }
2777
- // ── Prop watchers ─────────────────────────────────────────────────────────
2778
- /** Clamp renderEnd when totalElements shrinks (e.g. after a filter is applied). */
2779
- totalElementsChanged(newVal) {
2780
- this.renderEnd = Math.min(this.renderEnd, Math.max(0, newVal - 1));
2781
- }
2782
- /** Reset to primary view when the item prop is replaced from outside. */
2783
- itemChanged(newVal) {
2784
- var _a, _b;
2785
- this.activeViewIdx = 0;
2786
- this.applyDefaultSort((_b = (_a = newVal === null || newVal === void 0 ? void 0 : newVal.view) === null || _a === void 0 ? void 0 : _a.defaultSort) !== null && _b !== void 0 ? _b : '');
2787
- }
2788
- // ── Lifecycle ──────────────────────────────────────────────────────────────
2789
- componentWillLoad() {
2790
- var _a, _b, _c;
2791
- this.applyDefaultSort((_c = (_b = (_a = this.item) === null || _a === void 0 ? void 0 : _a.view) === null || _b === void 0 ? void 0 : _b.defaultSort) !== null && _c !== void 0 ? _c : '');
2792
- }
2793
- // ── Helpers ────────────────────────────────────────────────────────────────
2794
- applyDefaultSort(defaultSort) {
2795
- var _a;
2796
- if (defaultSort) {
2797
- const parts = defaultSort.split(',');
2798
- this.sortField = parts[0].trim();
2799
- this.sortDir = ((_a = parts[1]) === null || _a === void 0 ? void 0 : _a.trim()) === 'desc' ? 'desc' : 'asc';
2800
- }
2801
- else {
2802
- this.sortField = '';
2803
- this.sortDir = 'asc';
2804
- }
2805
- }
2806
- // ── Public API ─────────────────────────────────────────────────────────────
2807
- /**
2808
- * Initialise (or reset) the virtual scroll.
2809
- * Call after setting all props and registering the mrdLoadPage listener,
2810
- * but before calling setPage(0, rows).
2811
- */
2812
- async init() {
2813
- if (this.debounceTimer !== null) {
2814
- clearTimeout(this.debounceTimer);
2815
- this.debounceTimer = null;
2816
- }
2817
- this.pendingPages.clear();
2818
- this.loadedPages = new Map();
2819
- this.requestedPages = new Set();
2820
- this.colWidths = [];
2821
- this.scrollTop = 0;
2822
- this.renderStart = 0;
2823
- // Always fill the visible viewport on init — totalElements may be stale from a
2824
- // previous view. setPage() clamps renderEnd when the page is shorter than pageSize.
2825
- this.renderEnd = this.visibleCount() - 1;
2826
- const scroller = this.el.querySelector('.mrd-table__scroll');
2827
- if (scroller)
2828
- scroller.scrollTop = 0;
2829
- this.aggregations = null;
2830
- this.aggregationsTotal = null;
2831
- this.aggregationsPending = true;
2832
- this.minKnownTotal = 0;
2833
- // Always request page 0 — totalElements may be unknown (0) on first load.
2834
- this.mrdLoadPage.emit({ page: 0, sort: this.sortParam(), path: this.buildDataPath(), qs: this.buildQueryParams(0) });
2835
- this.requestedPages = new Set([0]);
2836
- }
2837
- /**
2838
- * Inject the rows for a given page (0-based).
2839
- * Creates a new Map reference so Stencil detects the state change.
2840
- *
2841
- * When the page contains fewer rows than pageSize it is the last page.
2842
- * renderEnd is clamped immediately so no loading-placeholder rows appear
2843
- * beyond the actual data — without requiring the host to update totalElements.
2844
- *
2845
- * Pass hasNext (from _links.next in the API response) for accurate last-page
2846
- * detection even when rows.length === pageSize (exact multiple of page size).
2847
- */
2848
- async setPage(pageNumber, rows, hasNext) {
2849
- const isLastPage = hasNext !== undefined ? !hasNext : rows.length < this.pageSize;
2850
- if (isLastPage) {
2851
- // lastRowIdx is -1 when the page is empty; clamp renderEnd to -1 so the
2852
- // render loop does not execute and no shimmer rows appear.
2853
- const lastRowIdx = pageNumber * this.pageSize + rows.length - 1;
2854
- this.renderEnd = Math.min(this.renderEnd, lastRowIdx);
2855
- // Exact total is known: update minKnownTotal so the scroll container has the right height.
2856
- this.minKnownTotal = pageNumber * this.pageSize + rows.length;
2857
- }
2858
- else {
2859
- // There is at least one more page — ensure the scrollbar covers at least that next page.
2860
- this.minKnownTotal = Math.max(this.minKnownTotal, (pageNumber + 1) * this.pageSize + 1);
2861
- }
2862
- const next = new Map(this.loadedPages);
2863
- next.set(pageNumber, rows);
2864
- this.loadedPages = next;
2865
- if (pageNumber === 0 && this.aggregationsPending) {
2866
- this.aggregationsPending = false;
2867
- const hasAggColumns = this.columns.some(c => c.type === 'FIELD' && c.aggregate);
2868
- if (!isLastPage || hasAggColumns) {
2869
- this.emitLoadAggregations();
2870
- }
2871
- }
2872
- }
2873
- /** Inject aggregation totals returned by the /aggregations endpoint. */
2874
- async setAggregations(data) {
2875
- var _a;
2876
- const total = (_a = data.total) !== null && _a !== void 0 ? _a : (typeof data.count === 'number' ? data.count : undefined);
2877
- if (total != null)
2878
- this.aggregationsTotal = total;
2879
- this.aggregations = data;
2880
- }
2881
- // ── Lifecycle ──────────────────────────────────────────────────────────────
2882
- disconnectedCallback() {
2883
- if (this.outsideClickHandler) {
2884
- document.removeEventListener('click', this.outsideClickHandler);
2885
- this.outsideClickHandler = null;
2886
- }
2887
- if (this.createPickerClickHandler) {
2888
- document.removeEventListener('click', this.createPickerClickHandler);
2889
- this.createPickerClickHandler = null;
2890
- }
2891
- if (this.keydownHandler) {
2892
- document.removeEventListener('keydown', this.keydownHandler);
2893
- this.keydownHandler = null;
2894
- }
2895
- if (this.viewPopoverClickHandler) {
2896
- document.removeEventListener('click', this.viewPopoverClickHandler);
2897
- this.viewPopoverClickHandler = null;
2898
- }
2899
- }
2900
- componentDidRender() {
2901
- if (this.colWidths.length === 0 && this.loadedPages.size > 0 && this.totalElements > 0) {
2902
- const ths = this.el.querySelectorAll('.mrd-table__header');
2903
- if (ths.length > 0) {
2904
- this.colWidths = Array.from(ths).map(th => th.offsetWidth);
2905
- }
2906
- }
2907
- }
2908
- // ── Paging / scroll helpers ────────────────────────────────────────────────
2909
- visibleCount() {
2910
- return Math.ceil(this.tableHeight / this.rowHeight);
2911
- }
2912
- sortParam() {
2913
- if (!this.sortField)
2914
- return '';
2915
- return this.sortDir === 'desc' ? `${this.sortField},desc` : this.sortField;
2916
- }
2917
- /** Stable ordered list: primary view first, then alternatives (from the item prop). */
2918
- get allViews() {
2919
- var _a, _b, _c, _d, _e, _f, _g;
2920
- if (!this.item)
2921
- return [];
2922
- const it = this.item;
2923
- return [
2924
- { label: (_e = (_d = (_c = (_a = it.label) !== null && _a !== void 0 ? _a : (_b = it.view) === null || _b === void 0 ? void 0 : _b.pluralLabel) !== null && _c !== void 0 ? _c : it.dataClass) !== null && _d !== void 0 ? _d : it.relatedClass) !== null && _e !== void 0 ? _e : '', dataClass: (_f = it.dataClass) !== null && _f !== void 0 ? _f : it.relatedClass, fromClass: it.fromClass, filterClass: it.filterClass, view: it.view },
2925
- ...((_g = it.alternativeViews) !== null && _g !== void 0 ? _g : []).map(av => {
2926
- var _a, _b, _c, _d;
2927
- return ({
2928
- label: (_d = (_c = (_a = av.label) !== null && _a !== void 0 ? _a : (_b = av.view) === null || _b === void 0 ? void 0 : _b.pluralLabel) !== null && _c !== void 0 ? _c : av.dataClass) !== null && _d !== void 0 ? _d : '',
2929
- dataClass: av.dataClass,
2930
- fromClass: av.fromClass,
2931
- filterClass: av.filterClass,
2932
- view: av.view,
2933
- });
2934
- }),
2935
- ];
2936
- }
2937
- /** Relative excel export path for the current view.
2938
- * VIEW: /excel/{dataClass}
2939
- * RELATED_VIEW: /excel/{fromClass}/{parentId}/{dataClass} */
2940
- buildExcelPath() {
2941
- var _a, _b, _c, _d;
2942
- const v = this.allViews[this.activeViewIdx];
2943
- if (!v)
2944
- return '';
2945
- if (((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === 'RELATED_VIEW') {
2946
- return `/excel/${(_b = v.fromClass) !== null && _b !== void 0 ? _b : ''}/${this.parentId}/${(_c = v.dataClass) !== null && _c !== void 0 ? _c : ''}`;
2947
- }
2948
- return `/excel/${(_d = v.dataClass) !== null && _d !== void 0 ? _d : ''}`;
2949
- }
2950
- buildActionDetail(action, basicType) {
2951
- var _a, _b, _c;
2952
- if (action === 'export') {
2953
- return { action, path: this.buildExcelPath(), qs: this.buildQueryParams(0) };
2954
- }
2955
- if (action === 'create') {
2956
- const v = this.allViews[this.activeViewIdx];
2957
- const parentPath = ((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === 'RELATED_VIEW'
2958
- ? `/${(_b = v === null || v === void 0 ? void 0 : v.fromClass) !== null && _b !== void 0 ? _b : ''}/${this.parentId}`
2959
- : null;
2960
- return Object.assign({ action, dataClass: (_c = v === null || v === void 0 ? void 0 : v.dataClass) !== null && _c !== void 0 ? _c : '', parentPath }, (basicType ? { basicType } : {}));
2961
- }
2962
- return { action };
2963
- }
2964
- /** Relative data path for the current view, without query string.
2965
- * VIEW: /{dataClass}
2966
- * RELATED_VIEW: /{fromClass}/{parentId}/{dataClass} */
2967
- buildDataPath() {
2968
- var _a, _b, _c, _d;
2969
- const v = this.allViews[this.activeViewIdx];
2970
- if (!v)
2971
- return '';
2972
- if (((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === 'RELATED_VIEW') {
2973
- return `/${(_b = v.fromClass) !== null && _b !== void 0 ? _b : ''}/${this.parentId}/${(_c = v.dataClass) !== null && _c !== void 0 ? _c : ''}`;
2974
- }
2975
- return `/${(_d = v.dataClass) !== null && _d !== void 0 ? _d : ''}`;
2976
- }
2977
- /** Build query params for a page request from current sort, view filters, filterClass and active column filters. */
2978
- buildQueryParams(page) {
2979
- var _a, _b, _c, _d, _e, _f, _g;
2980
- const v = this.allViews[this.activeViewIdx];
2981
- const p = new URLSearchParams();
2982
- if (page > 0)
2983
- p.set('page', String(page));
2984
- const sort = this.sortParam();
2985
- if (sort)
2986
- p.set('sort', sort);
2987
- const filterClass = v === null || v === void 0 ? void 0 : v.filterClass;
2988
- if (filterClass)
2989
- p.set('type', filterClass);
2990
- for (const f of ((_b = (_a = v === null || v === void 0 ? void 0 : v.view) === null || _a === void 0 ? void 0 : _a.filter) !== null && _b !== void 0 ? _b : [])) {
2991
- if (!f.name)
2992
- continue;
2993
- if (f.operator === 'EMPTY') {
2994
- p.set(f.name, '');
2995
- continue;
2996
- }
2997
- if (f.operator === 'NOT_EMPTY') {
2998
- p.set(f.name + '_notempty', 'true');
2999
- continue;
3000
- }
3001
- if (f.operator === 'STARTS_WITH') {
3002
- p.set(f.name + '_startswith', String((_c = f.value) !== null && _c !== void 0 ? _c : ''));
3003
- continue;
3004
- }
3005
- if (f.operator === 'FROM') {
3006
- p.set(f.name + '_from', String((_d = f.value) !== null && _d !== void 0 ? _d : ''));
3007
- continue;
3008
- }
3009
- if (f.operator === 'TO') {
3010
- p.set(f.name + '_to', String((_e = f.value) !== null && _e !== void 0 ? _e : ''));
3011
- continue;
3012
- }
3013
- if (f.value != null) {
3014
- p.set(f.name, String(f.value));
3015
- }
3016
- }
3017
- for (const f of this.activeFilters.values()) {
3018
- if (f.operator === 'isEmpty') {
3019
- p.set(f.field, '');
3020
- continue;
3021
- }
3022
- if (f.operator === 'isNotEmpty') {
3023
- p.set(f.field + '_notempty', 'true');
3024
- continue;
3025
- }
3026
- if (f.operator === 'startsWith') {
3027
- p.set(f.field + '_startswith', String((_f = f.value) !== null && _f !== void 0 ? _f : ''));
3028
- continue;
3029
- }
3030
- if ((_g = f.values) === null || _g === void 0 ? void 0 : _g.length) {
3031
- p.set(f.field, f.values.join(','));
3032
- continue;
3033
- }
3034
- if (f.value != null)
3035
- p.set(f.field, String(f.value));
3036
- if (f.from != null)
3037
- p.set(f.field + '_from', String(f.from));
3038
- if (f.to != null)
3039
- p.set(f.field + '_to', String(f.to));
3040
- }
3041
- return p.toString();
3042
- }
3043
- get columns() {
3044
- var _a, _b, _c;
3045
- return ((_c = (_b = (_a = this.allViews[this.activeViewIdx]) === null || _a === void 0 ? void 0 : _a.view) === null || _b === void 0 ? void 0 : _b.values) !== null && _c !== void 0 ? _c : []);
3046
- }
3047
- get tableActions() {
3048
- var _a, _b;
3049
- const raw = (_b = (_a = this.item) === null || _a === void 0 ? void 0 : _a.actions) !== null && _b !== void 0 ? _b : [];
3050
- return (raw !== null && raw !== void 0 ? raw : []).reduce((acc, a) => {
3051
- if (a === 'NEW')
3052
- acc.push({ action: 'create', label: t('table_new_record', this.locale), icon: 'assets/sprites.svg#icon-plus', variant: 'primary' });
3053
- if (a === 'EXPORT')
3054
- acc.push({ action: 'export', label: t('table_export_excel', this.locale), icon: 'assets/sprites.svg#icon-file-excel' });
3055
- return acc;
3056
- }, []);
3057
- }
3058
- toggleCreatePicker() {
3059
- if (this.createPickerOpen) {
3060
- this.closeCreatePicker();
3061
- }
3062
- else {
3063
- this.createPickerOpen = true;
3064
- if (this.createPickerClickHandler)
3065
- document.removeEventListener('click', this.createPickerClickHandler);
3066
- this.createPickerClickHandler = (ev) => {
3067
- const wrap = this.el.querySelector('.mrd-table__create-picker-wrap');
3068
- if (wrap && !wrap.contains(ev.target))
3069
- this.closeCreatePicker();
3070
- };
3071
- document.addEventListener('click', this.createPickerClickHandler);
3072
- }
3073
- }
3074
- closeCreatePicker() {
3075
- this.createPickerOpen = false;
3076
- if (this.createPickerClickHandler) {
3077
- document.removeEventListener('click', this.createPickerClickHandler);
3078
- this.createPickerClickHandler = null;
3079
- }
3080
- }
3081
- colName(col) {
3082
- var _a;
3083
- return (_a = col.name) !== null && _a !== void 0 ? _a : '';
3084
- }
3085
- colDataType(col) {
3086
- var _a;
3087
- if (col.type === 'RELATION')
3088
- return 'RELATION';
3089
- return (_a = col.dataType) !== null && _a !== void 0 ? _a : 'TEXT';
3090
- }
3091
- /** True when we have a reliable total: either from the aggregations response or because
3092
- * a short page told us it was the last page (exact count from row length). */
3093
- isTotalKnown() {
3094
- if (this.aggregationsTotal != null)
3095
- return true;
3096
- for (const rows of this.loadedPages.values()) {
3097
- if (rows.length < this.pageSize)
3098
- return true;
3099
- }
3100
- return false;
3101
- }
3102
- /** Effective total: aggregations-response > totalElements prop > minKnownTotal from setPage(). */
3103
- get baseTotal() {
3104
- if (this.aggregationsTotal != null)
3105
- return this.aggregationsTotal;
3106
- if (this.totalElements > 0)
3107
- return this.totalElements;
3108
- return this.minKnownTotal;
3109
- }
3110
- // ── Aggregation helpers ────────────────────────────────────────────────────
3111
- buildAggregationParams() {
3112
- var _a;
3113
- const groups = { sum: [], avg: [], count: [] };
3114
- for (const col of this.columns) {
3115
- if (col.type !== 'FIELD' || !col.aggregate)
3116
- continue;
3117
- const fn = col.aggregate.toLowerCase();
3118
- if (fn in groups)
3119
- groups[fn].push((_a = col.name) !== null && _a !== void 0 ? _a : '');
3120
- }
3121
- const params = {};
3122
- if (groups.sum.length)
3123
- params.sum = groups.sum;
3124
- if (groups.avg.length)
3125
- params.avg = groups.avg;
3126
- if (groups.count.length)
3127
- params.count = groups.count;
3128
- return Object.keys(params).length > 0 ? params : null;
3129
- }
3130
- buildAggregationQs() {
3131
- var _a, _b, _c;
3132
- const p = new URLSearchParams(this.buildQueryParams(0));
3133
- p.delete('page');
3134
- p.delete('sort');
3135
- const groups = this.buildAggregationParams();
3136
- if ((_a = groups === null || groups === void 0 ? void 0 : groups.sum) === null || _a === void 0 ? void 0 : _a.length)
3137
- p.set('sum', groups.sum.join(','));
3138
- if ((_b = groups === null || groups === void 0 ? void 0 : groups.avg) === null || _b === void 0 ? void 0 : _b.length)
3139
- p.set('avg', groups.avg.join(','));
3140
- if ((_c = groups === null || groups === void 0 ? void 0 : groups.count) === null || _c === void 0 ? void 0 : _c.length)
3141
- p.set('count', groups.count.join(','));
3142
- return p.toString();
3143
- }
3144
- emitLoadAggregations() {
3145
- this.mrdLoadAggregations.emit({ path: this.buildDataPath(), qs: this.buildQueryParams(0), aggQs: this.buildAggregationQs() });
3146
- }
3147
- renderAggregationValue(col) {
3148
- var _a;
3149
- if (col.type !== 'FIELD' || !col.aggregate || !this.aggregations)
3150
- return '';
3151
- const fn = col.aggregate.toLowerCase();
3152
- const aggData = this.aggregations[fn];
3153
- const val = typeof aggData === 'object' && aggData !== null
3154
- ? aggData[(_a = col.name) !== null && _a !== void 0 ? _a : '']
3155
- : undefined;
3156
- if (val == null)
3157
- return '';
3158
- const dt = col.dataType;
3159
- if (dt === 'INTEGER')
3160
- return formatNumber(val, this.locale, { maximumFractionDigits: 0 });
3161
- if (dt === 'PERCENTAGE')
3162
- return formatPercentage(val, this.locale);
3163
- if (dt === 'CURRENCY' && col.currencyCode)
3164
- return formatCurrency(val, col.currencyCode, this.locale);
3165
- return formatNumber(val, this.locale);
3166
- }
3167
- // ── Reset pagination ───────────────────────────────────────────────────────
3168
- /** Reset pagination state and scroll to top (used after sort or filter change). */
3169
- resetPages() {
3170
- if (this.debounceTimer !== null) {
3171
- clearTimeout(this.debounceTimer);
3172
- this.debounceTimer = null;
3173
- }
3174
- this.pendingPages.clear();
3175
- this.loadedPages = new Map();
3176
- this.requestedPages = new Set();
3177
- this.colWidths = [];
3178
- this.scrollTop = 0;
3179
- this.renderStart = 0;
3180
- this.minKnownTotal = 0;
3181
- // Mirror init(): use visibleCount so the first page is always requested.
3182
- // setPage() will clamp renderEnd down when the last page is shorter.
3183
- this.renderEnd = this.visibleCount() - 1;
3184
- const scroller = this.el.querySelector('.mrd-table__scroll');
3185
- if (scroller)
3186
- scroller.scrollTop = 0;
3187
- }
3188
- handleSortClick(col) {
3189
- const name = this.colName(col);
3190
- if (this.sortField === name) {
3191
- this.sortDir = this.sortDir === 'asc' ? 'desc' : 'asc';
3192
- }
3193
- else {
3194
- this.sortField = name;
3195
- this.sortDir = 'asc';
3196
- }
3197
- this.resetPages();
3198
- this.emitPagesForWindow(this.renderStart, this.renderEnd);
3199
- }
3200
- applySort(col, dir) {
3201
- this.sortField = this.colName(col);
3202
- this.sortDir = dir;
3203
- this.resetPages();
3204
- this.emitPagesForWindow(this.renderStart, this.renderEnd);
3205
- }
3206
- emitPagesForWindow(start, end) {
3207
- const firstPage = Math.floor(start / this.pageSize);
3208
- const lastPage = Math.floor(end / this.pageSize);
3209
- const next = new Set(this.requestedPages);
3210
- let changed = false;
3211
- for (let p = firstPage; p <= lastPage; p++) {
3212
- if (!this.loadedPages.has(p) && !next.has(p)) {
3213
- next.add(p);
3214
- this.mrdLoadPage.emit({ page: p, sort: this.sortParam(), path: this.buildDataPath(), qs: this.buildQueryParams(p) });
3215
- changed = true;
3216
- }
3217
- }
3218
- if (changed)
3219
- this.requestedPages = next;
3220
- }
3221
- getRow(i) {
3222
- var _a;
3223
- const page = this.loadedPages.get(Math.floor(i / this.pageSize));
3224
- return (_a = page === null || page === void 0 ? void 0 : page[i % this.pageSize]) !== null && _a !== void 0 ? _a : null;
3225
- }
3226
- requestPagesForWindow(start, end) {
3227
- const firstPage = Math.floor(start / this.pageSize);
3228
- const lastPage = Math.floor(end / this.pageSize);
3229
- let anyNew = false;
3230
- for (let p = firstPage; p <= lastPage; p++) {
3231
- if (!this.loadedPages.has(p) && !this.requestedPages.has(p) && !this.pendingPages.has(p)) {
3232
- this.pendingPages.add(p);
3233
- anyNew = true;
3234
- }
3235
- }
3236
- if (!anyNew)
3237
- return;
3238
- if (this.debounceTimer !== null)
3239
- clearTimeout(this.debounceTimer);
3240
- this.debounceTimer = setTimeout(() => this.flushPendingPages(), REQUEST_DEBOUNCE_MS);
3241
- }
3242
- flushPendingPages() {
3243
- this.debounceTimer = null;
3244
- if (this.pendingPages.size === 0)
3245
- return;
3246
- const next = new Set(this.requestedPages);
3247
- let changed = false;
3248
- for (const page of this.pendingPages) {
3249
- if (this.loadedPages.has(page) || next.has(page))
3250
- continue;
3251
- const pageStart = page * this.pageSize;
3252
- const pageEnd = pageStart + this.pageSize - 1;
3253
- if (pageEnd < this.renderStart || pageStart > this.renderEnd)
3254
- continue;
3255
- next.add(page);
3256
- this.mrdLoadPage.emit({ page, sort: this.sortParam(), path: this.buildDataPath(), qs: this.buildQueryParams(page) });
3257
- changed = true;
3258
- }
3259
- this.pendingPages.clear();
3260
- if (changed)
3261
- this.requestedPages = next;
3262
- }
3263
- // ── Filter helpers ─────────────────────────────────────────────────────────
3264
- handleFilterToggle() {
3265
- this.filterMode = !this.filterMode;
3266
- if (!this.filterMode)
3267
- this.closeFilterPopup();
3268
- }
3269
- handleFilterOpen(col, e) {
3270
- e.stopPropagation();
3271
- const btn = e.currentTarget;
3272
- const rect = btn.getBoundingClientRect();
3273
- let left = rect.left;
3274
- if (left + POPUP_WIDTH > window.innerWidth - 8)
3275
- left = rect.right - POPUP_WIDTH;
3276
- this.popupPos = { top: rect.bottom + 4, left: Math.max(8, left) };
3277
- const name = this.colName(col);
3278
- const dataType = this.colDataType(col);
3279
- const existing = this.activeFilters.get(name);
3280
- // Set the default operator explicitly so it is present in the ColumnFilter
3281
- // even when the user never touches the operator dropdown.
3282
- const defaultOperator = (TEXT_TYPES.has(dataType) || dataType === 'RELATION')
3283
- ? 'startsWith'
3284
- : undefined;
3285
- // For DATETIME, stored values are UTC ISO strings; convert back to local
3286
- // "YYYY-MM-DD" dates so the date inputs show what the user originally entered.
3287
- // If from and to cover the same local day it was an exact-date filter — restore
3288
- // to exact mode so the user sees the single-date input again.
3289
- if (dataType === 'DATETIME' && existing && existing.operator !== 'isEmpty' && existing.operator !== 'isNotEmpty') {
3290
- const display = Object.assign({}, existing);
3291
- if (typeof display.from === 'string' && display.from)
3292
- display.from = this.utcISOToLocalDate(display.from);
3293
- if (typeof display.to === 'string' && display.to)
3294
- display.to = this.utcISOToLocalDateExclusiveEnd(display.to);
3295
- if (display.from && display.to && display.from === display.to) {
3296
- this.pendingFilter = Object.assign(Object.assign({}, display), { value: display.from, from: undefined, to: undefined });
3297
- }
3298
- else {
3299
- this.pendingFilter = display;
3300
- }
3301
- }
3302
- else {
3303
- this.pendingFilter = existing ? Object.assign({}, existing) : { field: name, dataType, operator: defaultOperator };
3304
- }
3305
- this.openFilterCol = name;
3306
- // Close on outside click — re-register to replace any stale handler
3307
- if (this.outsideClickHandler)
3308
- document.removeEventListener('click', this.outsideClickHandler);
3309
- this.outsideClickHandler = (ev) => {
3310
- const popup = this.el.querySelector('.mrd-table__filter-popup');
3311
- if (popup && !popup.contains(ev.target))
3312
- this.closeFilterPopup();
3313
- };
3314
- document.addEventListener('click', this.outsideClickHandler);
3315
- }
3316
- closeFilterPopup() {
3317
- this.openFilterCol = null;
3318
- this.pendingFilter = null;
3319
- if (this.outsideClickHandler) {
3320
- document.removeEventListener('click', this.outsideClickHandler);
3321
- this.outsideClickHandler = null;
3322
- }
3323
- }
3324
- openTextblockModal(text) {
3325
- this.textblockModal = text;
3326
- if (this.keydownHandler)
3327
- document.removeEventListener('keydown', this.keydownHandler);
3328
- this.keydownHandler = (ev) => {
3329
- if (ev.key === 'Escape')
3330
- this.closeTextblockModal();
3331
- };
3332
- document.addEventListener('keydown', this.keydownHandler);
3333
- }
3334
- closeTextblockModal() {
3335
- this.textblockModal = null;
3336
- if (this.keydownHandler) {
3337
- document.removeEventListener('keydown', this.keydownHandler);
3338
- this.keydownHandler = null;
3339
- }
3340
- }
3341
- openJsonModal(html) {
3342
- this.jsonModal = html;
3343
- if (this.keydownHandler)
3344
- document.removeEventListener('keydown', this.keydownHandler);
3345
- this.keydownHandler = (ev) => {
3346
- if (ev.key === 'Escape')
3347
- this.closeJsonModal();
3348
- };
3349
- document.addEventListener('keydown', this.keydownHandler);
3350
- }
3351
- closeJsonModal() {
3352
- this.jsonModal = null;
3353
- if (this.keydownHandler) {
3354
- document.removeEventListener('keydown', this.keydownHandler);
3355
- this.keydownHandler = null;
3356
- }
3357
- }
3358
- setPending(key, val) {
3359
- this.pendingFilter = Object.assign(Object.assign({}, this.pendingFilter), { [key]: val });
3360
- }
3361
- togglePendingValue(key, checked) {
3362
- var _a, _b;
3363
- const current = (_b = (_a = this.pendingFilter) === null || _a === void 0 ? void 0 : _a.values) !== null && _b !== void 0 ? _b : [];
3364
- this.pendingFilter = Object.assign(Object.assign({}, this.pendingFilter), { values: checked ? [...current, key] : current.filter(k => k !== key) });
3365
- }
3366
- filterHasValue(f) {
3367
- if (f.operator === 'isEmpty' || f.operator === 'isNotEmpty')
3368
- return true;
3369
- if (f.values !== undefined && f.values.length > 0)
3370
- return true;
3371
- if (f.value != null && f.value !== '')
3372
- return true;
3373
- if (typeof f.value === 'boolean')
3374
- return true;
3375
- if (f.from != null && f.from !== '')
3376
- return true;
3377
- if (f.to != null && f.to !== '')
3378
- return true;
3379
- return false;
3380
- }
3381
- // Convert a local "YYYY-MM-DD" date string to the UTC ISO string at the
3382
- // start of that local day (midnight). new Date(y, m, d) uses local time.
3383
- dateLocalToUTCStart(dateStr) {
3384
- if (!dateStr)
3385
- return dateStr;
3386
- const [year, month, day] = dateStr.split('-').map(Number);
3387
- return new Date(year, month - 1, day).toISOString().replace(/\.\d{3}Z$/, 'Z');
3388
- }
3389
- // Start of the day AFTER the given local date (exclusive range end).
3390
- dateLocalToUTCEndExclusive(dateStr) {
3391
- if (!dateStr)
3392
- return dateStr;
3393
- const [year, month, day] = dateStr.split('-').map(Number);
3394
- return new Date(year, month - 1, day + 1).toISOString().replace(/\.\d{3}Z$/, 'Z');
3395
- }
3396
- // Convert a stored UTC ISO string back to the local "YYYY-MM-DD" date.
3397
- utcISOToLocalDate(utcStr) {
3398
- if (!utcStr)
3399
- return utcStr;
3400
- const d = new Date(utcStr);
3401
- if (isNaN(d.getTime()))
3402
- return utcStr;
3403
- return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
3404
- }
3405
- // The stored "to" value is the exclusive end (midnight of the next day).
3406
- // Subtract one day to recover the local date the user entered.
3407
- utcISOToLocalDateExclusiveEnd(utcStr) {
3408
- if (!utcStr)
3409
- return utcStr;
3410
- const d = new Date(utcStr);
3411
- if (isNaN(d.getTime()))
3412
- return utcStr;
3413
- d.setDate(d.getDate() - 1);
3414
- return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
3415
- }
3416
- applyFilter() {
3417
- const f = this.pendingFilter;
3418
- if (!(f === null || f === void 0 ? void 0 : f.field)) {
3419
- this.closeFilterPopup();
3420
- return;
3421
- }
3422
- // For DATETIME fields the user enters local dates; convert to UTC ISO strings.
3423
- // Exact date → range covering the full local day (from = midnight, to = next midnight).
3424
- // "to" is always the exclusive end (midnight of the next local day).
3425
- let normalized = Object.assign({}, f);
3426
- if (f.dataType === 'DATETIME' && f.operator !== 'isEmpty' && f.operator !== 'isNotEmpty') {
3427
- if (typeof normalized.value === 'string' && normalized.value) {
3428
- normalized.from = this.dateLocalToUTCStart(normalized.value);
3429
- normalized.to = this.dateLocalToUTCEndExclusive(normalized.value);
3430
- normalized.value = undefined;
3431
- }
3432
- else {
3433
- if (typeof normalized.from === 'string' && normalized.from)
3434
- normalized.from = this.dateLocalToUTCStart(normalized.from);
3435
- if (typeof normalized.to === 'string' && normalized.to)
3436
- normalized.to = this.dateLocalToUTCEndExclusive(normalized.to);
3437
- }
3438
- }
3439
- const next = new Map(this.activeFilters);
3440
- if (this.filterHasValue(normalized)) {
3441
- next.set(normalized.field, normalized);
3442
- }
3443
- else {
3444
- next.delete(normalized.field);
3445
- }
3446
- this.activeFilters = next;
3447
- this.closeFilterPopup();
3448
- this.aggregations = null;
3449
- this.aggregationsTotal = null;
3450
- this.aggregationsPending = true;
3451
- if (this.totalElements > 0 || this.minKnownTotal > 0) {
3452
- this.resetPages();
3453
- this.emitPagesForWindow(this.renderStart, this.renderEnd);
3454
- }
3455
- }
3456
- clearFilter() {
3457
- const name = this.openFilterCol;
3458
- const next = new Map(this.activeFilters);
3459
- if (name)
3460
- next.delete(name);
3461
- this.activeFilters = next;
3462
- this.closeFilterPopup();
3463
- this.aggregations = null;
3464
- this.aggregationsTotal = null;
3465
- this.aggregationsPending = true;
3466
- if (this.totalElements > 0 || this.minKnownTotal > 0) {
3467
- this.resetPages();
3468
- this.emitPagesForWindow(this.renderStart, this.renderEnd);
3469
- }
3470
- }
3471
- clearAllFilters() {
3472
- this.activeFilters = new Map();
3473
- this.aggregations = null;
3474
- this.aggregationsTotal = null;
3475
- this.aggregationsPending = true;
3476
- if (this.totalElements > 0 || this.minKnownTotal > 0) {
3477
- this.resetPages();
3478
- this.emitPagesForWindow(this.renderStart, this.renderEnd);
3479
- }
3480
- }
3481
- // ── View switcher ──────────────────────────────────────────────────────────
3482
- handleViewSwitch(targetIdx) {
3483
- var _a, _b;
3484
- const target = this.allViews[targetIdx];
3485
- if (!(target === null || target === void 0 ? void 0 : target.view))
3486
- return;
3487
- this.activeViewIdx = targetIdx;
3488
- this.applyDefaultSort((_b = (_a = target.view) === null || _a === void 0 ? void 0 : _a.defaultSort) !== null && _b !== void 0 ? _b : '');
3489
- this.activeFilters = new Map();
3490
- this.init();
3491
- }
3492
- toggleViewPopover(e) {
3493
- e.stopPropagation();
3494
- if (this.viewPopoverOpen) {
3495
- this.viewPopoverOpen = false;
3496
- if (this.viewPopoverClickHandler) {
3497
- document.removeEventListener('click', this.viewPopoverClickHandler);
3498
- this.viewPopoverClickHandler = null;
3499
- }
3500
- return;
3501
- }
3502
- this.viewPopoverOpen = true;
3503
- this.viewPopoverClickHandler = () => {
3504
- this.viewPopoverOpen = false;
3505
- document.removeEventListener('click', this.viewPopoverClickHandler);
3506
- this.viewPopoverClickHandler = null;
3507
- };
3508
- document.addEventListener('click', this.viewPopoverClickHandler);
3509
- }
3510
- // ── Render: toolbar ────────────────────────────────────────────────────────
3511
- renderToolbar() {
3512
- var _a;
3513
- const filterCount = this.activeFilters.size;
3514
- const actions = this.tableActions;
3515
- const allViews = this.allViews;
3516
- const hasActions = actions.length > 0;
3517
- const hasViewSwitcher = allViews.length > 1;
3518
- 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("div", { class: "mrd-table__view-switcher" }, h("button", { class: "mrd-table__view-arrow", "aria-label": "Previous view", onClick: () => this.handleViewSwitch((this.activeViewIdx - 1 + allViews.length) % allViews.length) }, "\u25C0"), h("div", { class: "mrd-table__view-title-wrap" }, h("button", { class: "mrd-table__view-title", onClick: (e) => this.toggleViewPopover(e) }, (_a = allViews[this.activeViewIdx]) === null || _a === void 0 ? void 0 : _a.label), this.viewPopoverOpen && (h("div", { class: "mrd-table__view-popover", onClick: (e) => e.stopPropagation() }, allViews.map((v, i) => (h("button", { key: String(i), class: `mrd-table__view-popover-item${i === this.activeViewIdx ? ' mrd-table__view-popover-item--active' : ''}`, onClick: () => {
3519
- if (i !== this.activeViewIdx)
3520
- this.handleViewSwitch(i);
3521
- this.viewPopoverOpen = false;
3522
- if (this.viewPopoverClickHandler) {
3523
- document.removeEventListener('click', this.viewPopoverClickHandler);
3524
- this.viewPopoverClickHandler = null;
3525
- }
3526
- } }, v.label)))))), h("button", { class: "mrd-table__view-arrow", "aria-label": "Next view", onClick: () => this.handleViewSwitch((this.activeViewIdx + 1) % allViews.length) }, "\u25B6")))), hasActions && (h("div", { class: "mrd-table__toolbar-right" }, actions.map(a => {
3527
- var _a, _b, _c;
3528
- const createTypes = a.action === 'create' ? (_a = this.item) === null || _a === void 0 ? void 0 : _a.createTypes : null;
3529
- if (createTypes === null || createTypes === void 0 ? void 0 : createTypes.length) {
3530
- return (h("div", { class: "mrd-table__create-picker-wrap", key: `action-${a.action}` }, h("button", { class: `mrd-table__action mrd-table__action--${(_b = a.variant) !== null && _b !== void 0 ? _b : 'secondary'}`, onClick: () => this.toggleCreatePicker() }, a.icon
3531
- ? h("svg", { class: "mrd-table__action-icon", "aria-hidden": "true" }, h("use", { href: a.icon }))
3532
- : a.label, h("span", { class: "mrd-table__action-tooltip" }, a.label)), this.createPickerOpen && (h("div", { class: "mrd-table__create-picker" }, createTypes.map(ct => (h("button", { key: ct.type, class: "mrd-table__create-picker-item", onClick: () => {
3533
- this.mrdAction.emit(this.buildActionDetail('create', ct.type));
3534
- this.closeCreatePicker();
3535
- } }, ct.label)))))));
3536
- }
3537
- return (h("button", { key: `action-${a.action}`, class: `mrd-table__action mrd-table__action--${(_c = a.variant) !== null && _c !== void 0 ? _c : 'secondary'}`, disabled: a.disabled, onClick: () => this.mrdAction.emit(this.buildActionDetail(a.action)) }, a.icon
3538
- ? h("svg", { class: "mrd-table__action-icon", "aria-hidden": "true" }, h("use", { href: a.icon }))
3539
- : a.label, h("span", { class: "mrd-table__action-tooltip" }, a.label)));
3540
- })))));
3541
- }
3542
- // ── Render: filter popup ───────────────────────────────────────────────────
3543
- renderFilterEditor(col) {
3544
- var _a, _b, _c, _d, _e, _f, _g;
3545
- const pf = (_a = this.pendingFilter) !== null && _a !== void 0 ? _a : {};
3546
- const dataType = this.colDataType(col);
3547
- if (NO_FILTER_TYPES.has(dataType)) {
3548
- return h("p", { class: "mrd-table__filter-no-support" }, t('filter_no_support', this.locale));
3549
- }
3550
- if (dataType === 'BOOLEAN') {
3551
- const boolOp = pf.operator;
3552
- const noValueOp = boolOp === 'isEmpty' || boolOp === 'isNotEmpty';
3553
- return (h("div", { class: "mrd-table__filter-radio-group" }, [
3554
- { labelKey: 'filter_all', value: null },
3555
- { labelKey: 'yes', value: true },
3556
- { labelKey: 'no', value: false },
3557
- ].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))));
3558
- }
3559
- if (dataType === 'LIST') {
3560
- const items = (_b = col.listItems) !== null && _b !== void 0 ? _b : [];
3561
- const selected = (_c = pf.values) !== null && _c !== void 0 ? _c : [];
3562
- 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)))));
3563
- }
3564
- if (TEXT_TYPES.has(dataType) || dataType === 'RELATION') {
3565
- const op = (_d = pf.operator) !== null && _d !== void 0 ? _d : 'startsWith';
3566
- const noInput = op === 'isEmpty' || op === 'isNotEmpty';
3567
- return (h("div", { class: "mrd-table__filter-editor" }, h("select", { class: "mrd-table__filter-select", onChange: (e) => this.setPending('operator', e.target.value) }, [
3568
- { val: 'startsWith', labelKey: 'filter_starts_with' },
3569
- { val: 'equals', labelKey: 'filter_equals' },
3570
- { val: 'isEmpty', labelKey: 'filter_is_empty' },
3571
- { val: 'isNotEmpty', labelKey: 'filter_is_not_empty' },
3572
- ].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((_e = pf.value) !== null && _e !== void 0 ? _e : ''), placeholder: t('filter_search_value', this.locale), onInput: (e) => this.setPending('value', e.target.value) }))));
3573
- }
3574
- if (NUMERIC_TYPES.has(dataType)) {
3575
- const numOp = pf.operator;
3576
- const noInput = numOp === 'isEmpty' || numOp === 'isNotEmpty';
3577
- const rangeMode = !noInput && (pf.from !== undefined || pf.to !== undefined);
3578
- return (h("div", { class: "mrd-table__filter-editor" }, h("select", { class: "mrd-table__filter-select", onChange: (e) => {
3579
- const val = e.target.value;
3580
- if (val === 'isEmpty' || val === 'isNotEmpty') {
3581
- this.pendingFilter = Object.assign(Object.assign({}, pf), { operator: val, value: undefined, from: undefined, to: undefined });
3582
- }
3583
- else {
3584
- this.pendingFilter = Object.assign(Object.assign({}, pf), { operator: undefined });
3585
- }
3586
- } }, 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) })))))));
3587
- }
3588
- if (dataType === 'DATETIME') {
3589
- const dtOp = pf.operator;
3590
- const noInput = dtOp === 'isEmpty' || dtOp === 'isNotEmpty';
3591
- const rangeMode = !noInput && (pf.from !== undefined || pf.to !== undefined);
3592
- return (h("div", { class: "mrd-table__filter-editor" }, h("select", { class: "mrd-table__filter-select", onChange: (e) => {
3593
- const val = e.target.value;
3594
- if (val === 'isEmpty' || val === 'isNotEmpty') {
3595
- this.pendingFilter = Object.assign(Object.assign({}, pf), { operator: val, value: undefined, from: undefined, to: undefined });
3596
- }
3597
- else {
3598
- this.pendingFilter = Object.assign(Object.assign({}, pf), { operator: undefined });
3599
- }
3600
- } }, 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((_f = pf.value) !== null && _f !== void 0 ? _f : ''), 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) })))))));
3601
- }
3602
- if (DATE_TYPES.has(dataType)) {
3603
- const inputType = dataType === 'DATE' ? 'date' : 'time';
3604
- const dtdOp = pf.operator;
3605
- const noInput = dtdOp === 'isEmpty' || dtdOp === 'isNotEmpty';
3606
- const rangeMode = !noInput && (pf.from !== undefined || pf.to !== undefined);
3607
- return (h("div", { class: "mrd-table__filter-editor" }, h("select", { class: "mrd-table__filter-select", onChange: (e) => {
3608
- const val = e.target.value;
3609
- if (val === 'isEmpty' || val === 'isNotEmpty') {
3610
- this.pendingFilter = Object.assign(Object.assign({}, pf), { operator: val, value: undefined, from: undefined, to: undefined });
3611
- }
3612
- else {
3613
- this.pendingFilter = Object.assign(Object.assign({}, pf), { operator: undefined });
3614
- }
3615
- } }, 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((_g = pf.value) !== null && _g !== void 0 ? _g : ''), 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) })))))));
3616
- }
3617
- return null;
3618
- }
3619
- renderFilterPopup() {
3620
- var _a;
3621
- if (!this.openFilterCol || !this.pendingFilter)
3622
- return null;
3623
- const col = this.columns.find(c => this.colName(c) === this.openFilterCol);
3624
- if (!col)
3625
- return null;
3626
- const label = (_a = col.label) !== null && _a !== void 0 ? _a : this.openFilterCol;
3627
- const sortActive = this.sortField === this.openFilterCol;
3628
- 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)))));
3629
- }
3630
- // ── Render: footer ────────────────────────────────────────────────────────
3631
- renderFooter(rowCount, effectiveTotal, isTotalKnown = true) {
3632
- // Non-paginated mode: totalElements=0 and no paginated data loaded yet
3633
- if (this.totalElements === 0 && this.loadedPages.size === 0) {
3634
- const count = rowCount !== null && rowCount !== void 0 ? rowCount : 0;
3635
- if (count === 0)
3636
- return null;
3637
- return (h("div", { class: "mrd-table__footer" }, count, " ", t('table_of', this.locale), " ", count));
3638
- }
3639
- // Paginated mode: only show once page 0 has loaded (avoids stale total during filter reset)
3640
- if (!this.loadedPages.has(0))
3641
- return null;
3642
- // effectiveTotal from render(); fall back to baseTotal when not provided.
3643
- const displayTotal = effectiveTotal !== null && effectiveTotal !== void 0 ? effectiveTotal : this.baseTotal;
3644
- // Compute from/to independently so partial rows at top/bottom are included.
3645
- const from = Math.min(Math.floor(this.scrollTop / this.rowHeight) + 1, displayTotal);
3646
- const to = Math.min(Math.ceil((this.scrollTop + this.tableHeight) / this.rowHeight), displayTotal);
3647
- // Show '…' for the total until we have a reliable count (aggregations or last page loaded).
3648
- const totalLabel = isTotalKnown ? String(displayTotal) : '…';
3649
- return (h("div", { class: "mrd-table__footer" }, from, "\u2013", to, " ", t('table_of', this.locale), " ", totalLabel));
3650
- }
3651
- // ── Render: cell ──────────────────────────────────────────────────────────
3652
- renderCell(col, row) {
3653
- var _a, _b, _c;
3654
- const numericTypes = new Set(['INTEGER', 'DECIMAL', 'PERCENTAGE', 'CURRENCY']);
3655
- const dataType = (_a = col.dataType) !== null && _a !== void 0 ? _a : '';
3656
- const isNumeric = col.type === 'FIELD' && numericTypes.has(dataType);
3657
- const isFile = col.type === 'FIELD' && (dataType === 'FILE' || dataType === 'IMAGE');
3658
- if (isFile) {
3659
- const name = (_b = col.name) !== null && _b !== void 0 ? _b : '';
3660
- const fileVal = row === null || row === void 0 ? void 0 : row[name];
3661
- const href = fileVal === null || fileVal === void 0 ? void 0 : fileVal.href;
3662
- const fileName = fileVal === null || fileVal === void 0 ? void 0 : fileVal.fileName;
3663
- return (h("td", { class: "mrd-table__cell" }, href && fileName ? (h("button", { class: "mrd-table__file-btn", title: fileName, onClick: (e) => {
3664
- e.stopPropagation();
3665
- this.mrdDownload.emit({ href, fileName });
3666
- } }, 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))) : ''));
3667
- }
3668
- if (dataType === 'JSON') {
3669
- const name = (_c = col.name) !== null && _c !== void 0 ? _c : '';
3670
- const rawValue = name ? row === null || row === void 0 ? void 0 : row[name] : undefined;
3671
- if (rawValue == null || rawValue === '')
3672
- return h("td", { class: "mrd-table__cell" });
3673
- const compactHtml = CellRenderer.formatJson(rawValue, true);
3674
- const prettyHtml = CellRenderer.formatJson(rawValue, false);
3675
- 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")));
3676
- }
3677
- const TEXTBLOCK_MAX = 200;
3678
- if (dataType === 'TEXTBLOCK') {
3679
- const full = CellRenderer.render(col, row, this.locale);
3680
- if (full.length <= TEXTBLOCK_MAX) {
3681
- return h("td", { class: "mrd-table__cell" }, full);
3682
- }
3683
- const preview = full.slice(0, TEXTBLOCK_MAX) + '…';
3684
- 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")));
3685
- }
3686
- const value = CellRenderer.render(col, row, this.locale);
3687
- return (h("td", { class: `mrd-table__cell${isNumeric ? ' mrd-table__cell--numeric' : ''}` }, value));
3688
- }
3689
- // ── Render: totals row ────────────────────────────────────────────────────
3690
- renderTotalsRow() {
3691
- if (!this.aggregations)
3692
- return null;
3693
- if (!this.columns.some(c => c.type === 'FIELD' && c.aggregate))
3694
- return null;
3695
- return (h("tfoot", null, h("tr", { class: "mrd-table__totals-row" }, this.columns.map(col => {
3696
- var _a;
3697
- const val = this.renderAggregationValue(col);
3698
- const isNumeric = col.type === 'FIELD' && NUMERIC_TYPES.has((_a = col.dataType) !== null && _a !== void 0 ? _a : '');
3699
- return (h("td", { class: `mrd-table__totals-cell${isNumeric ? ' mrd-table__totals-cell--numeric' : ''}` }, val));
3700
- }))));
3701
- }
3702
- // ── Render ─────────────────────────────────────────────────────────────────
3703
- render() {
3704
- var _a, _b, _c;
3705
- if (!((_a = this.columns) === null || _a === void 0 ? void 0 : _a.length))
3706
- return null;
3707
- // ── Non-paginated mode ──────────────────────────────────────────────────
3708
- // Only enter non-paginated mode when totalElements is 0 AND no paginated data
3709
- // has been loaded yet — prevents the wrong branch when the host omits totalElements.
3710
- if (this.totalElements === 0 && this.loadedPages.size === 0) {
3711
- 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 => {
3712
- var _a;
3713
- const name = this.colName(col);
3714
- const isFiltered = this.activeFilters.has(name);
3715
- const cls = [
3716
- 'mrd-table__header',
3717
- isFiltered ? 'mrd-table__header--filtered' : '',
3718
- this.filterMode ? 'mrd-table__header--sortable' : '',
3719
- ].filter(Boolean).join(' ');
3720
- return (h("th", { class: cls, onClick: this.filterMode ? (e) => this.handleFilterOpen(col, e) : undefined }, h("span", { class: "mrd-table__header-label" }, (_a = col.label) !== null && _a !== void 0 ? _a : ''), isFiltered && this.renderFilterIcon()));
3721
- }))), 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()));
3722
- }
3723
- // ── Paginated / virtual-scroll mode ────────────────────────────────────
3724
- // Derive the authoritative row count from loaded pages:
3725
- // if any loaded page is shorter than pageSize it is the last page,
3726
- // so the true total cannot exceed (pageNum * pageSize + pageRows.length).
3727
- // aggregationsTotal (from setAggregations) takes priority over the totalElements prop.
3728
- let effectiveTotal = this.baseTotal;
3729
- for (const [pageNum, pageRows] of this.loadedPages) {
3730
- if (pageRows.length < this.pageSize) {
3731
- effectiveTotal = Math.min(effectiveTotal, pageNum * this.pageSize + pageRows.length);
3732
- }
3733
- }
3734
- // Clamp renderEnd to what we actually know exists (-1 when empty)
3735
- const clampedEnd = Math.min(this.renderEnd, effectiveTotal - 1);
3736
- const colCount = this.columns.length;
3737
- const topSpacerHeight = this.renderStart * this.rowHeight;
3738
- const bottomSpacerHeight = Math.max(0, (effectiveTotal - 1 - clampedEnd) * this.rowHeight);
3739
- const tableStyle = this.colWidths.length > 0
3740
- ? { tableLayout: 'fixed' }
3741
- : undefined;
3742
- const renderedRows = [];
3743
- for (let i = this.renderStart; i <= clampedEnd; i++) {
3744
- const row = this.getRow(i);
3745
- if (row === null) {
3746
- 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" }))));
3747
- }
3748
- else {
3749
- 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))));
3750
- }
3751
- }
3752
- 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) => {
3753
- var _a;
3754
- const name = this.colName(col);
3755
- const isActive = this.sortField === name;
3756
- const isFiltered = this.activeFilters.has(name);
3757
- const isInteractive = !NON_INTERACTIVE_TYPES.has(this.colDataType(col));
3758
- const cls = [
3759
- 'mrd-table__header',
3760
- isInteractive ? 'mrd-table__header--sortable' : '',
3761
- isActive ? `mrd-table__header--sorted-${this.sortDir}` : '',
3762
- isFiltered ? 'mrd-table__header--filtered' : '',
3763
- ].filter(Boolean).join(' ');
3764
- 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" }, (_a = col.label) !== null && _a !== void 0 ? _a : ''), 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()));
3765
- }))), 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.isTotalKnown()), this.renderFilterPopup(), this.renderTextblockModal()));
3766
- }
3767
- renderFilterIcon() {
3768
- 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" }))));
3769
- }
3770
- renderTextblockModal() {
3771
- if (this.textblockModal === null)
3772
- return null;
3773
- 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))));
3774
- }
3775
- renderJsonModal() {
3776
- if (this.jsonModal === null)
3777
- return null;
3778
- 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 }))));
3779
- }
3780
- get el() { return getElement(this); }
3781
- static get watchers() { return {
3782
- "totalElements": [{
3783
- "totalElementsChanged": 0
3784
- }],
3785
- "item": [{
3786
- "itemChanged": 0
3787
- }]
3788
- }; }
3789
- };
3790
- MrdTable.style = mrdTableScss();
3791
-
3792
- 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)}`;
3793
-
3794
- const MrdTextField = class {
3795
- constructor(hostRef) {
3796
- registerInstance(this, hostRef);
3797
- this.mrdChange = createEvent(this, "mrdChange");
3798
- this.mrdBlur = createEvent(this, "mrdBlur");
3799
- this.name = '';
3800
- this.label = '';
3801
- this.value = '';
3802
- this.placeholder = '';
3803
- this.required = false;
3804
- this.disabled = false;
3805
- this.locale = navigator.language;
3806
- this.error = '';
3807
- this.handleInput = (e) => {
3808
- const val = e.target.value;
3809
- this.mrdChange.emit({ name: this.name, value: val });
3810
- };
3811
- this.handleBlur = (e) => {
3812
- const val = e.target.value;
3813
- if (this.required && !validateRequired(val)) {
3814
- this.error = t('required', this.locale);
3815
- }
3816
- else {
3817
- this.error = '';
3818
- }
3819
- this.mrdBlur.emit({ name: this.name, value: val });
3820
- };
3821
- }
3822
- render() {
3823
- const hasError = !!this.error;
3824
- return (h(Host, { key: 'fd4e1f389cb452ab80a1e1c7295d884ca935999e' }, h("div", { key: '7b7bde7a18fcd9b8d5779daab88ddabb45dd8692', class: "mrd-text-field" }, this.label && (h("label", { key: '8e2ad4053473cfad4eae4c4634b863ac5ef32fea', class: `mrd-text-field__label${this.required ? ' mrd-text-field__label--required' : ''}` }, this.label)), h("input", { key: 'd32712a6dc2aee4691bc4a580d5ca2ad81e0ff9f', 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: '31585dbf82020c81834e1eeada5cd9907a5ead56', class: "mrd-text-field__error" }, this.error))));
3825
- }
3826
- };
3827
- MrdTextField.style = mrdTextFieldScss();
3828
-
3829
- 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__editor.sc-mrd-textarea-field .ql-editor.sc-mrd-textarea-field p.sc-mrd-textarea-field{margin-bottom:0.75em}.mrd-textarea-field__editor.sc-mrd-textarea-field .ql-editor.sc-mrd-textarea-field p.sc-mrd-textarea-field:last-child{margin-bottom:0}.mrd-textarea-field__editor.sc-mrd-textarea-field .ql-editor.sc-mrd-textarea-field ul.sc-mrd-textarea-field{list-style:disc;padding-left:1.5em;margin-bottom:0.75em}.mrd-textarea-field__editor.sc-mrd-textarea-field .ql-editor.sc-mrd-textarea-field ol.sc-mrd-textarea-field{list-style:decimal;padding-left:1.5em;margin-bottom:0.75em}.mrd-textarea-field__editor.sc-mrd-textarea-field .ql-editor.sc-mrd-textarea-field li.sc-mrd-textarea-field{margin-bottom:0.25em}.mrd-textarea-field__editor.sc-mrd-textarea-field .ql-editor.sc-mrd-textarea-field h1.sc-mrd-textarea-field{font-size:1.75em;font-weight:700;margin-bottom:0.5em}.mrd-textarea-field__editor.sc-mrd-textarea-field .ql-editor.sc-mrd-textarea-field h2.sc-mrd-textarea-field{font-size:1.375em;font-weight:700;margin-bottom:0.5em}.mrd-textarea-field__editor.sc-mrd-textarea-field .ql-editor.sc-mrd-textarea-field h3.sc-mrd-textarea-field{font-size:1.125em;font-weight:600;margin-bottom:0.5em}.mrd-textarea-field__editor.sc-mrd-textarea-field .ql-editor.sc-mrd-textarea-field a.sc-mrd-textarea-field{color:var(--mrd-color-primary);text-decoration:underline}.mrd-textarea-field__editor.sc-mrd-textarea-field .ql-editor.sc-mrd-textarea-field strong.sc-mrd-textarea-field{font-weight:700}.mrd-textarea-field__editor.sc-mrd-textarea-field .ql-editor.sc-mrd-textarea-field em.sc-mrd-textarea-field{font-style:italic}.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)}`;
3830
-
3831
- const MrdTextareaField = class {
3832
- constructor(hostRef) {
3833
- registerInstance(this, hostRef);
3834
- this.mrdChange = createEvent(this, "mrdChange");
3835
- this.mrdBlur = createEvent(this, "mrdBlur");
3836
- this.name = '';
3837
- this.label = '';
3838
- this.value = '';
3839
- this.placeholder = '';
3840
- this.required = false;
3841
- this.disabled = false;
3842
- this.locale = navigator.language;
3843
- this.error = '';
3844
- this.editorReady = false;
3845
- }
3846
- componentDidLoad() {
3847
- this.initQuill();
3848
- }
3849
- async initQuill() {
3850
- try {
3851
- // Dynamically import Quill
3852
- const Quill = (await import('./quill-CiuCgGz_.js')).default;
3853
- this.editorEl = this.el.querySelector('.mrd-textarea-field__editor');
3854
- if (!this.editorEl)
3855
- return;
3856
- const quill = new Quill(this.editorEl, {
3857
- theme: 'snow',
3858
- placeholder: this.placeholder,
3859
- readOnly: this.disabled,
3860
- modules: {
3861
- toolbar: [
3862
- ['bold', 'italic', 'underline', 'strike'],
3863
- [{ list: 'ordered' }, { list: 'bullet' }],
3864
- [{ header: [1, 2, 3, false] }],
3865
- ['link'],
3866
- ['clean'],
3867
- ],
3868
- },
3869
- });
3870
- if (this.value) {
3871
- quill.clipboard.dangerouslyPasteHTML(this.value);
3872
- }
3873
- quill.on('text-change', () => {
3874
- var _a, _b;
3875
- const html = (_b = (_a = this.editorEl.querySelector('.ql-editor')) === null || _a === void 0 ? void 0 : _a.innerHTML) !== null && _b !== void 0 ? _b : '';
3876
- this.mrdChange.emit({ name: this.name, value: html });
3877
- });
3878
- quill.on('selection-change', (range) => {
3879
- var _a, _b;
3880
- if (!range) {
3881
- const html = (_b = (_a = this.editorEl.querySelector('.ql-editor')) === null || _a === void 0 ? void 0 : _a.innerHTML) !== null && _b !== void 0 ? _b : '';
3882
- if (this.required && !validateRequired(html)) {
3883
- this.error = t('required', this.locale);
3884
- }
3885
- else {
3886
- this.error = '';
3887
- }
3888
- this.mrdBlur.emit({ name: this.name, value: html });
3889
- }
3890
- });
3891
- this.editorReady = true;
3892
- }
3893
- catch (err) {
3894
- console.error('Failed to load Quill editor:', err);
3895
- }
3896
- }
3897
- render() {
3898
- return (h(Host, { key: 'e1fd819c598f01e3986946357ec18d608f2c7adc' }, h("div", { key: '20c28e54e61429655b2d4f297bd84e183ad7e971', class: "mrd-textarea-field" }, this.label && (h("label", { key: 'fa46a20badc35c931563600f24a32e0a8c8c07ad', class: `mrd-textarea-field__label${this.required ? ' mrd-textarea-field__label--required' : ''}` }, this.label)), h("div", { key: 'ee928eca0a1b85401b346b7fae8adbe9214a7664', class: `mrd-textarea-field__container${this.error ? ' mrd-textarea-field__container--error' : ''}` }, h("div", { key: '89b00f3c526623c47f0aff7ad862f70dfdc2fe15', class: "mrd-textarea-field__editor" })), this.error && h("span", { key: '458cf8fddee36ddbc384ce4d25765e5aacd3c9d5', class: "mrd-textarea-field__error" }, this.error))));
3899
- }
3900
- get el() { return getElement(this); }
3901
- };
3902
- MrdTextareaField.style = mrdTextareaFieldScss();
3903
-
3904
- 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)}`;
3905
-
3906
- const MrdTimeField = class {
3907
- constructor(hostRef) {
3908
- registerInstance(this, hostRef);
3909
- this.mrdChange = createEvent(this, "mrdChange");
3910
- this.mrdBlur = createEvent(this, "mrdBlur");
3911
- this.name = '';
3912
- this.label = '';
3913
- this.value = '';
3914
- this.required = false;
3915
- this.disabled = false;
3916
- this.locale = navigator.language;
3917
- this.error = '';
3918
- this.handleChange = (e) => {
3919
- const val = e.target.value;
3920
- if (this.required && !validateRequired(val)) {
3921
- this.error = t('required', this.locale);
3922
- }
3923
- else {
3924
- this.error = '';
3925
- }
3926
- this.mrdChange.emit({ name: this.name, value: val });
3927
- };
3928
- this.handleBlur = (e) => {
3929
- const val = e.target.value;
3930
- this.mrdBlur.emit({ name: this.name, value: val });
3931
- };
3932
- }
3933
- render() {
3934
- const hasError = !!this.error;
3935
- return (h(Host, { key: 'c507996709437d8982f9175b286e25598997002d' }, h("div", { key: 'd5f1b7f14d26cae8298cd40491898b39044158f8', class: "mrd-time-field" }, this.label && (h("label", { key: '10976e18df09240e00b045314c4ddd3845d4bfdc', class: `mrd-time-field__label${this.required ? ' mrd-time-field__label--required' : ''}` }, this.label)), h("input", { key: 'bc557333f107a371a7005f9b56dd0395190e63d7', 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: 'b5a09c2aa063fa9e2fc3aba411e86b57d879c408', class: "mrd-time-field__error" }, this.error))));
3936
- }
3937
- };
3938
- MrdTimeField.style = mrdTimeFieldScss();
3939
-
3940
- 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, MrdSecretField as mrd_secret_field, MrdTable as mrd_table, MrdTextField as mrd_text_field, MrdTextareaField as mrd_textarea_field, MrdTimeField as mrd_time_field };