@mmlogic/components 0.3.10 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. package/dist/cjs/{index-BPj2cBXs.js → index-CAzwGt9u.js} +38 -0
  2. package/dist/cjs/loader.cjs.js +2 -2
  3. package/dist/cjs/mosterdcomponents.cjs.js +2 -2
  4. package/dist/cjs/mrd-boolean-field_23.cjs.entry.js +1280 -1073
  5. package/dist/collection/collection-manifest.json +23 -23
  6. package/dist/collection/components/{mrd-document-container/mrd-document-container.scss → documents/mrd-document-container/mrd-document-container.css} +3 -3
  7. package/dist/collection/components/{mrd-document-container → documents/mrd-document-container}/mrd-document-container.js +54 -8
  8. package/dist/collection/components/documents/mrd-document-list/folder-tree.js +109 -0
  9. package/dist/collection/components/{mrd-document-list/mrd-document-list.scss → documents/mrd-document-list/mrd-document-list.css} +17 -4
  10. package/dist/collection/components/{mrd-document-list → documents/mrd-document-list}/mrd-document-list.js +166 -237
  11. package/dist/collection/components/documents/mrd-document-list/tree-view.js +75 -0
  12. package/dist/collection/components/{mrd-document-view/mrd-document-view.scss → documents/mrd-document-view/mrd-document-view.css} +1 -1
  13. package/dist/collection/components/{mrd-document-view → documents/mrd-document-view}/mrd-document-view.js +4 -4
  14. package/dist/collection/components/fields/field-helpers.js +17 -0
  15. package/dist/collection/components/fields/file-upload-common.js +38 -0
  16. package/dist/collection/components/{mrd-boolean-field/mrd-boolean-field.scss → fields/mrd-boolean-field/mrd-boolean-field.css} +3 -3
  17. package/dist/collection/components/{mrd-boolean-field → fields/mrd-boolean-field}/mrd-boolean-field.js +1 -1
  18. package/dist/collection/components/{mrd-currency-field/mrd-currency-field.scss → fields/mrd-currency-field/mrd-currency-field.css} +11 -9
  19. package/dist/collection/components/{mrd-currency-field → fields/mrd-currency-field}/mrd-currency-field.js +7 -13
  20. package/dist/collection/components/{mrd-date-field/mrd-date-field.scss → fields/mrd-date-field/mrd-date-field.css} +8 -10
  21. package/dist/collection/components/{mrd-date-field → fields/mrd-date-field}/mrd-date-field.js +3 -10
  22. package/dist/collection/components/{mrd-datetime-field/mrd-datetime-field.scss → fields/mrd-datetime-field/mrd-datetime-field.css} +8 -10
  23. package/dist/collection/components/{mrd-datetime-field → fields/mrd-datetime-field}/mrd-datetime-field.js +3 -10
  24. package/dist/collection/components/{mrd-email-field/mrd-email-field.scss → fields/mrd-email-field/mrd-email-field.css} +2 -11
  25. package/dist/collection/components/{mrd-email-field → fields/mrd-email-field}/mrd-email-field.js +6 -13
  26. package/dist/collection/components/{mrd-file-field/mrd-file-field.scss → fields/mrd-file-field/mrd-file-field.css} +19 -24
  27. package/dist/collection/components/{mrd-file-field → fields/mrd-file-field}/mrd-file-field.js +13 -24
  28. package/dist/collection/components/{mrd-hyperlink-field/mrd-hyperlink-field.scss → fields/mrd-hyperlink-field/mrd-hyperlink-field.css} +7 -16
  29. package/dist/collection/components/{mrd-hyperlink-field → fields/mrd-hyperlink-field}/mrd-hyperlink-field.js +9 -15
  30. package/dist/collection/components/{mrd-image-field/mrd-image-field.scss → fields/mrd-image-field/mrd-image-field.css} +15 -24
  31. package/dist/collection/components/{mrd-image-field → fields/mrd-image-field}/mrd-image-field.js +13 -28
  32. package/dist/collection/components/{mrd-list-field/mrd-list-field.scss → fields/mrd-list-field/mrd-list-field.css} +18 -21
  33. package/dist/collection/components/{mrd-list-field → fields/mrd-list-field}/mrd-list-field.js +10 -25
  34. package/dist/collection/components/{mrd-longtext-field/mrd-longtext-field.scss → fields/mrd-longtext-field/mrd-longtext-field.css} +21 -18
  35. package/dist/collection/components/{mrd-longtext-field → fields/mrd-longtext-field}/mrd-longtext-field.js +3 -10
  36. package/dist/collection/components/{mrd-number-field/mrd-number-field.scss → fields/mrd-number-field/mrd-number-field.css} +9 -10
  37. package/dist/collection/components/{mrd-number-field → fields/mrd-number-field}/mrd-number-field.js +7 -6
  38. package/dist/collection/components/{mrd-relation-field/mrd-relation-field.scss → fields/mrd-relation-field/mrd-relation-field.css} +61 -59
  39. package/dist/collection/components/{mrd-relation-field → fields/mrd-relation-field}/mrd-relation-field.js +16 -26
  40. package/dist/collection/components/{mrd-secret-field/mrd-secret-field.scss → fields/mrd-secret-field/mrd-secret-field.css} +7 -10
  41. package/dist/collection/components/{mrd-secret-field → fields/mrd-secret-field}/mrd-secret-field.js +4 -11
  42. package/dist/collection/components/{mrd-text-field/mrd-text-field.scss → fields/mrd-text-field/mrd-text-field.css} +2 -11
  43. package/dist/collection/components/{mrd-text-field → fields/mrd-text-field}/mrd-text-field.js +3 -10
  44. package/dist/collection/components/{mrd-textarea-field/mrd-textarea-field.scss → fields/mrd-textarea-field/mrd-textarea-field.css} +7 -10
  45. package/dist/collection/components/{mrd-textarea-field → fields/mrd-textarea-field}/mrd-textarea-field.js +3 -9
  46. package/dist/collection/components/{mrd-time-field/mrd-time-field.scss → fields/mrd-time-field/mrd-time-field.css} +8 -10
  47. package/dist/collection/components/{mrd-time-field → fields/mrd-time-field}/mrd-time-field.js +3 -10
  48. package/dist/collection/components/{mrd-field/mrd-field.scss → form/mrd-field/mrd-field.css} +1 -1
  49. package/dist/collection/components/{mrd-field → form/mrd-field}/mrd-field.js +3 -3
  50. package/dist/collection/components/{mrd-form/mrd-form.scss → form/mrd-form/mrd-form.css} +1 -1
  51. package/dist/collection/components/{mrd-form → form/mrd-form}/mrd-form.js +5 -5
  52. package/dist/collection/components/layout/mrd-layout-section/field-value.js +111 -0
  53. package/dist/collection/components/layout/mrd-layout-section/layout-helpers.js +29 -0
  54. package/dist/collection/components/{mrd-layout-section/mrd-layout-section.scss → layout/mrd-layout-section/mrd-layout-section.css} +4 -4
  55. package/dist/collection/components/{mrd-layout-section → layout/mrd-layout-section}/mrd-layout-section.js +58 -133
  56. package/dist/collection/components/{mrd-table/mrd-table.scss → table/mrd-table/mrd-table.css} +11 -13
  57. package/dist/collection/components/{mrd-table → table/mrd-table}/mrd-table.js +111 -439
  58. package/dist/collection/components/table/mrd-table/table-filter-popup.js +85 -0
  59. package/dist/collection/components/table/mrd-table/table-parts.js +110 -0
  60. package/dist/collection/components/table/mrd-table/table-query.js +178 -0
  61. package/dist/collection/components/table/mrd-table/virtual-scroll.js +49 -0
  62. package/dist/collection/dev/app.js +19 -18
  63. package/dist/collection/dev/example-data.js +58 -43
  64. package/dist/collection/utils/i18n.js +10 -0
  65. package/dist/collection/utils/query-params.js +43 -0
  66. package/dist/components/field-helpers.js +1 -0
  67. package/dist/components/file-upload-common.js +1 -0
  68. package/dist/components/i18n.js +1 -1
  69. package/dist/components/mrd-boolean-field2.js +1 -1
  70. package/dist/components/mrd-currency-field2.js +1 -1
  71. package/dist/components/mrd-date-field2.js +1 -1
  72. package/dist/components/mrd-datetime-field2.js +1 -1
  73. package/dist/components/mrd-document-container2.js +1 -1
  74. package/dist/components/mrd-document-list2.js +1 -1
  75. package/dist/components/mrd-document-view2.js +1 -1
  76. package/dist/components/mrd-email-field2.js +1 -1
  77. package/dist/components/mrd-file-field2.js +1 -1
  78. package/dist/components/mrd-form.js +1 -1
  79. package/dist/components/mrd-hyperlink-field2.js +1 -1
  80. package/dist/components/mrd-image-field2.js +1 -1
  81. package/dist/components/mrd-layout-section.js +1 -1
  82. package/dist/components/mrd-list-field2.js +1 -1
  83. package/dist/components/mrd-longtext-field2.js +1 -1
  84. package/dist/components/mrd-number-field2.js +1 -1
  85. package/dist/components/mrd-relation-field2.js +1 -1
  86. package/dist/components/mrd-secret-field2.js +1 -1
  87. package/dist/components/mrd-table2.js +1 -1
  88. package/dist/components/mrd-text-field2.js +1 -1
  89. package/dist/components/mrd-textarea-field2.js +1 -1
  90. package/dist/components/mrd-time-field2.js +1 -1
  91. package/dist/components/query-params.js +1 -0
  92. package/dist/esm/{index-_tsCCkAi.js → index-DiSEJMA8.js} +38 -1
  93. package/dist/esm/loader.js +3 -3
  94. package/dist/esm/mosterdcomponents.js +3 -3
  95. package/dist/esm/mrd-boolean-field_23.entry.js +1280 -1073
  96. package/dist/mosterdcomponents/mosterdcomponents.css +1 -1
  97. package/dist/mosterdcomponents/mosterdcomponents.esm.js +1 -1
  98. package/dist/mosterdcomponents/p-9b3c0917.entry.js +1 -0
  99. package/dist/mosterdcomponents/p-DiSEJMA8.js +2 -0
  100. package/dist/types/components/{mrd-document-container → documents/mrd-document-container}/mrd-document-container.d.ts +7 -2
  101. package/dist/types/components/documents/mrd-document-list/folder-tree.d.ts +66 -0
  102. package/dist/types/components/{mrd-document-list → documents/mrd-document-list}/mrd-document-list.d.ts +28 -38
  103. package/dist/types/components/documents/mrd-document-list/tree-view.d.ts +32 -0
  104. package/dist/types/components/{mrd-document-view → documents/mrd-document-view}/mrd-document-view.d.ts +2 -2
  105. package/dist/types/components/fields/field-helpers.d.ts +18 -0
  106. package/dist/types/components/fields/file-upload-common.d.ts +18 -0
  107. package/dist/types/components/{mrd-boolean-field → fields/mrd-boolean-field}/mrd-boolean-field.d.ts +1 -1
  108. package/dist/types/components/{mrd-currency-field → fields/mrd-currency-field}/mrd-currency-field.d.ts +2 -2
  109. package/dist/types/components/{mrd-date-field → fields/mrd-date-field}/mrd-date-field.d.ts +1 -1
  110. package/dist/types/components/{mrd-datetime-field → fields/mrd-datetime-field}/mrd-datetime-field.d.ts +1 -1
  111. package/dist/types/components/{mrd-email-field → fields/mrd-email-field}/mrd-email-field.d.ts +1 -1
  112. package/dist/types/components/{mrd-file-field → fields/mrd-file-field}/mrd-file-field.d.ts +2 -4
  113. package/dist/types/components/{mrd-hyperlink-field → fields/mrd-hyperlink-field}/mrd-hyperlink-field.d.ts +2 -2
  114. package/dist/types/components/{mrd-image-field → fields/mrd-image-field}/mrd-image-field.d.ts +2 -4
  115. package/dist/types/components/{mrd-list-field → fields/mrd-list-field}/mrd-list-field.d.ts +2 -2
  116. package/dist/types/components/{mrd-longtext-field → fields/mrd-longtext-field}/mrd-longtext-field.d.ts +1 -1
  117. package/dist/types/components/{mrd-number-field → fields/mrd-number-field}/mrd-number-field.d.ts +2 -2
  118. package/dist/types/components/{mrd-relation-field → fields/mrd-relation-field}/mrd-relation-field.d.ts +2 -2
  119. package/dist/types/components/{mrd-secret-field → fields/mrd-secret-field}/mrd-secret-field.d.ts +1 -1
  120. package/dist/types/components/{mrd-text-field → fields/mrd-text-field}/mrd-text-field.d.ts +1 -1
  121. package/dist/types/components/{mrd-textarea-field → fields/mrd-textarea-field}/mrd-textarea-field.d.ts +1 -1
  122. package/dist/types/components/{mrd-time-field → fields/mrd-time-field}/mrd-time-field.d.ts +1 -1
  123. package/dist/types/components/{mrd-field → form/mrd-field}/mrd-field.d.ts +2 -2
  124. package/dist/types/components/{mrd-form → form/mrd-form}/mrd-form.d.ts +2 -2
  125. package/dist/types/components/layout/mrd-layout-section/field-value.d.ts +22 -0
  126. package/dist/types/components/layout/mrd-layout-section/layout-helpers.d.ts +8 -0
  127. package/dist/types/components/{mrd-layout-section → layout/mrd-layout-section}/mrd-layout-section.d.ts +4 -8
  128. package/dist/types/components/{mrd-table → table/mrd-table}/mrd-table.d.ts +6 -13
  129. package/dist/types/components/table/mrd-table/table-filter-popup.d.ts +35 -0
  130. package/dist/types/components/table/mrd-table/table-parts.d.ts +61 -0
  131. package/dist/types/components/table/mrd-table/table-query.d.ts +50 -0
  132. package/dist/types/components/table/mrd-table/virtual-scroll.d.ts +26 -0
  133. package/dist/types/components.d.ts +36 -5
  134. package/dist/types/types/client-layout.d.ts +5 -0
  135. package/dist/types/utils/query-params.d.ts +14 -0
  136. package/package.json +7 -2
  137. package/dist/components/validation.js +0 -1
  138. package/dist/mosterdcomponents/cell-renderer-B-AJDBcj.js.map +0 -1
  139. package/dist/mosterdcomponents/client-layout-ChqRA3AF.js.map +0 -1
  140. package/dist/mosterdcomponents/format-BAfsQfy1.js.map +0 -1
  141. package/dist/mosterdcomponents/i18n-s1XrKcD2.js.map +0 -1
  142. package/dist/mosterdcomponents/index-DkY-NQj0.js.map +0 -1
  143. package/dist/mosterdcomponents/index-DwF_Sp__.js.map +0 -1
  144. package/dist/mosterdcomponents/index.esm.js.map +0 -1
  145. package/dist/mosterdcomponents/mosterdcomponents.esm.js.map +0 -1
  146. package/dist/mosterdcomponents/p-69452249.entry.js +0 -1
  147. package/dist/mosterdcomponents/p-_tsCCkAi.js +0 -2
  148. package/dist/mosterdcomponents/quill-C9pgw_k-.js.map +0 -1
  149. package/dist/mosterdcomponents/validation-Br9k2Ztw.js.map +0 -1
@@ -1,7 +1,7 @@
1
- import { r as registerInstance, c as createEvent, h, H as Host, g as getElement } from './index-_tsCCkAi.js';
1
+ import { r as registerInstance, c as createEvent, h, H as Host, g as getElement, w as writeTask } from './index-DiSEJMA8.js';
2
2
  import { ClientLayoutItemFieldDataType, ClientLayoutItemType, ClientLayoutItemRelationDisplayType, ClientLayoutItemRelationEditBehavior, resolveArchetype, ARCHETYPE_DOCUMENT } from './index.js';
3
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)}`;
4
+ const mrdBooleanFieldCss = () => `.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
5
 
6
6
  const MrdBooleanField = class {
7
7
  constructor(hostRef) {
@@ -27,10 +27,83 @@ const MrdBooleanField = class {
27
27
  this.checked = !!this.value;
28
28
  }
29
29
  render() {
30
- return (h(Host, { key: '38e65a1c7971912f8259d09281b272d7cbd446f2' }, h("div", { key: 'e10919998731d744cc2a13130c5f355c9b8fc9aa', class: "mrd-boolean-field" }, h("label", { key: 'db85a2c80cc62fdfd25237e3f5c7750bf1666819', class: "mrd-boolean-field__toggle-label" }, h("input", { key: 'cddd7004593fa4671abb89f4f805c4a009db99ef', 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: 'f90f0ed6d74d6688e51b8d85a5397a0597d95ad8', class: "mrd-boolean-field__toggle", "aria-hidden": "true" }), this.label && (h("span", { key: '7e4582b1d9a5b08c00c220bec53baa6c14cbfe43', class: `mrd-boolean-field__text${this.required ? ' mrd-boolean-field__text--required' : ''}` }, this.label))))));
30
+ return (h(Host, { key: 'f7851813646d31c565c262bf3c8d4083177dd993' }, h("div", { key: '4b3c9f46e8b79bdc97ef5815afb85ba5ddde0c9a', class: "mrd-boolean-field" }, h("label", { key: 'f81fa28d5a79de0445c2c192352343f0807609a1', class: "mrd-boolean-field__toggle-label" }, h("input", { key: '510a4f5533cbe2741b8df34cb64fc739475a26cf', 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: '949e042c8af0f2872cf973a0d5407fce972eb240', class: "mrd-boolean-field__toggle", "aria-hidden": "true" }), this.label && (h("span", { key: 'e8c52b5820887b2a8ec9a20eb7e4116a528d27d4', class: `mrd-boolean-field__text${this.required ? ' mrd-boolean-field__text--required' : ''}` }, this.label))))));
31
31
  }
32
32
  };
33
- MrdBooleanField.style = mrdBooleanFieldScss();
33
+ MrdBooleanField.style = mrdBooleanFieldCss();
34
+
35
+ function formatNumber(value, locale, options) {
36
+ if (value === null || value === undefined || isNaN(value))
37
+ return '';
38
+ return new Intl.NumberFormat(locale, options).format(value);
39
+ }
40
+ function formatCurrency(amount, currency, locale) {
41
+ if (amount === null || amount === undefined || isNaN(amount))
42
+ return '';
43
+ return new Intl.NumberFormat(locale, {
44
+ style: 'currency',
45
+ currency,
46
+ minimumFractionDigits: 2,
47
+ maximumFractionDigits: 2,
48
+ }).format(amount);
49
+ }
50
+ function formatPercentage(value, locale, decimalPrecision = 2) {
51
+ if (value === null || value === undefined || isNaN(value))
52
+ return '';
53
+ return new Intl.NumberFormat(locale, {
54
+ style: 'percent',
55
+ minimumFractionDigits: decimalPrecision,
56
+ maximumFractionDigits: decimalPrecision,
57
+ }).format(value);
58
+ }
59
+ function formatDate(value, locale) {
60
+ if (!value)
61
+ return '';
62
+ const date = typeof value === 'string' ? new Date(value) : value;
63
+ if (isNaN(date.getTime()))
64
+ return '';
65
+ return new Intl.DateTimeFormat(locale, { year: 'numeric', month: '2-digit', day: '2-digit' }).format(date);
66
+ }
67
+ function formatDateTime(value, locale) {
68
+ if (!value)
69
+ return '';
70
+ const date = typeof value === 'string' ? new Date(value) : value;
71
+ if (isNaN(date.getTime()))
72
+ return '';
73
+ return new Intl.DateTimeFormat(locale, {
74
+ year: 'numeric',
75
+ month: '2-digit',
76
+ day: '2-digit',
77
+ hour: '2-digit',
78
+ minute: '2-digit',
79
+ }).format(date);
80
+ }
81
+ function formatTime(value, locale) {
82
+ if (!value)
83
+ return '';
84
+ // value is HH:MM or HH:MM:SS
85
+ const [hours, minutes] = value.split(':').map(Number);
86
+ const date = new Date();
87
+ date.setHours(hours, minutes, 0, 0);
88
+ return new Intl.DateTimeFormat(locale, { hour: '2-digit', minute: '2-digit' }).format(date);
89
+ }
90
+ function parseLocalizedNumber(str, locale) {
91
+ var _a, _b, _c, _d;
92
+ if (!str || !str.trim())
93
+ return null;
94
+ // Detect decimal and thousands separators from the locale
95
+ const parts = new Intl.NumberFormat(locale).formatToParts(1234567.89);
96
+ const groupSep = (_b = (_a = parts.find((p) => p.type === 'group')) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : ',';
97
+ const decimalSep = (_d = (_c = parts.find((p) => p.type === 'decimal')) === null || _c === void 0 ? void 0 : _c.value) !== null && _d !== void 0 ? _d : '.';
98
+ // Remove group separators, replace decimal separator with '.'
99
+ const normalized = str
100
+ .replace(new RegExp(`\\${groupSep}`, 'g'), '')
101
+ .replace(new RegExp(`\\${decimalSep}`), '.')
102
+ .replace('%', '')
103
+ .trim();
104
+ const parsed = parseFloat(normalized);
105
+ return isNaN(parsed) ? null : parsed;
106
+ }
34
107
 
35
108
  const translations = {
36
109
  nl: {
@@ -47,6 +120,7 @@ const translations = {
47
120
  drop_file_here: 'Sleep bestand hierheen of',
48
121
  browse: 'bladeren',
49
122
  file_too_large: 'Bestand is te groot',
123
+ invalid_image: 'Selecteer een afbeeldingsbestand',
50
124
  search_results: 'Zoekresultaten',
51
125
  no_results: 'Geen resultaten gevonden',
52
126
  loading: 'Laden...',
@@ -103,6 +177,7 @@ const translations = {
103
177
  folder_name_placeholder: 'Foldernaam',
104
178
  folder_no_slash: "Een foldernaam mag geen '/' bevatten",
105
179
  folder_duplicate: 'Er bestaat al een folder met deze naam',
180
+ doc_empty_drop: 'Nog geen documenten — sleep bestanden hierheen',
106
181
  },
107
182
  en: {
108
183
  required: 'This field is required',
@@ -118,6 +193,7 @@ const translations = {
118
193
  drop_file_here: 'Drop file here or',
119
194
  browse: 'browse',
120
195
  file_too_large: 'File is too large',
196
+ invalid_image: 'Please select an image file',
121
197
  search_results: 'Search results',
122
198
  no_results: 'No results found',
123
199
  loading: 'Loading...',
@@ -174,6 +250,7 @@ const translations = {
174
250
  folder_name_placeholder: 'Folder name',
175
251
  folder_no_slash: "A folder name cannot contain '/'",
176
252
  folder_duplicate: 'A folder with this name already exists',
253
+ doc_empty_drop: 'No documents yet — drop files here',
177
254
  },
178
255
  ar: {
179
256
  required: 'هذا الحقل مطلوب',
@@ -189,6 +266,7 @@ const translations = {
189
266
  drop_file_here: 'اسحب الملف هنا أو',
190
267
  browse: 'تصفح',
191
268
  file_too_large: 'الملف كبير جداً',
269
+ invalid_image: 'يرجى اختيار ملف صورة',
192
270
  search_results: 'نتائج البحث',
193
271
  no_results: 'لم يتم العثور على نتائج',
194
272
  loading: 'جار التحميل...',
@@ -255,6 +333,7 @@ const translations = {
255
333
  drop_file_here: 'Déposez le fichier ici ou',
256
334
  browse: 'parcourir',
257
335
  file_too_large: 'Le fichier est trop volumineux',
336
+ invalid_image: 'Veuillez sélectionner un fichier image',
258
337
  search_results: 'Résultats de recherche',
259
338
  no_results: 'Aucun résultat trouvé',
260
339
  loading: 'Chargement...',
@@ -321,6 +400,7 @@ const translations = {
321
400
  drop_file_here: 'Datei hier ablegen oder',
322
401
  browse: 'durchsuchen',
323
402
  file_too_large: 'Datei ist zu groß',
403
+ invalid_image: 'Bitte eine Bilddatei auswählen',
324
404
  search_results: 'Suchergebnisse',
325
405
  no_results: 'Keine Ergebnisse gefunden',
326
406
  loading: 'Laden...',
@@ -387,6 +467,7 @@ const translations = {
387
467
  drop_file_here: 'Suelte el archivo aquí o',
388
468
  browse: 'explorar',
389
469
  file_too_large: 'El archivo es demasiado grande',
470
+ invalid_image: 'Seleccione un archivo de imagen',
390
471
  search_results: 'Resultados de búsqueda',
391
472
  no_results: 'No se encontraron resultados',
392
473
  loading: 'Cargando...',
@@ -453,6 +534,7 @@ const translations = {
453
534
  drop_file_here: 'Trascina il file qui o',
454
535
  browse: 'sfoglia',
455
536
  file_too_large: 'Il file è troppo grande',
537
+ invalid_image: 'Seleziona un file immagine',
456
538
  search_results: 'Risultati della ricerca',
457
539
  no_results: 'Nessun risultato trovato',
458
540
  loading: 'Caricamento...',
@@ -519,6 +601,7 @@ const translations = {
519
601
  drop_file_here: 'Перетягніть файл сюди або',
520
602
  browse: 'огляд',
521
603
  file_too_large: 'Файл занадто великий',
604
+ invalid_image: 'Будь ласка, виберіть файл зображення',
522
605
  search_results: 'Результати пошуку',
523
606
  no_results: 'Результатів не знайдено',
524
607
  loading: 'Завантаження...',
@@ -629,80 +712,22 @@ function validateNumber(value, dataType) {
629
712
  return true;
630
713
  }
631
714
 
632
- function formatNumber(value, locale, options) {
633
- if (value === null || value === undefined || isNaN(value))
634
- return '';
635
- return new Intl.NumberFormat(locale, options).format(value);
715
+ /**
716
+ * Shared building blocks for the leaf field components.
717
+ * `base` is the BEM block name, e.g. 'mrd-text-field'.
718
+ */
719
+ const FieldLabel = ({ base, label, required }) => label ? h("label", { class: `${base}__label${required ? ` ${base}__label--required` : ''}` }, label) : null;
720
+ const FieldError = ({ base, error }) => error ? h("span", { class: `${base}__error` }, error) : null;
721
+ /** Class string for the form control, with the --error modifier when applicable. */
722
+ function controlClass(base, hasError, element = 'input') {
723
+ return `${base}__${element}${hasError ? ` ${base}__${element}--error` : ''}`;
636
724
  }
637
- function formatCurrency(amount, currency, locale) {
638
- if (amount === null || amount === undefined || isNaN(amount))
639
- return '';
640
- return new Intl.NumberFormat(locale, {
641
- style: 'currency',
642
- currency,
643
- minimumFractionDigits: 2,
644
- maximumFractionDigits: 2,
645
- }).format(amount);
646
- }
647
- function formatPercentage(value, locale, decimalPrecision = 2) {
648
- if (value === null || value === undefined || isNaN(value))
649
- return '';
650
- return new Intl.NumberFormat(locale, {
651
- style: 'percent',
652
- minimumFractionDigits: decimalPrecision,
653
- maximumFractionDigits: decimalPrecision,
654
- }).format(value);
655
- }
656
- function formatDate(value, locale) {
657
- if (!value)
658
- return '';
659
- const date = typeof value === 'string' ? new Date(value) : value;
660
- if (isNaN(date.getTime()))
661
- return '';
662
- return new Intl.DateTimeFormat(locale, { year: 'numeric', month: '2-digit', day: '2-digit' }).format(date);
663
- }
664
- function formatDateTime(value, locale) {
665
- if (!value)
666
- return '';
667
- const date = typeof value === 'string' ? new Date(value) : value;
668
- if (isNaN(date.getTime()))
669
- return '';
670
- return new Intl.DateTimeFormat(locale, {
671
- year: 'numeric',
672
- month: '2-digit',
673
- day: '2-digit',
674
- hour: '2-digit',
675
- minute: '2-digit',
676
- }).format(date);
677
- }
678
- function formatTime(value, locale) {
679
- if (!value)
680
- return '';
681
- // value is HH:MM or HH:MM:SS
682
- const [hours, minutes] = value.split(':').map(Number);
683
- const date = new Date();
684
- date.setHours(hours, minutes, 0, 0);
685
- return new Intl.DateTimeFormat(locale, { hour: '2-digit', minute: '2-digit' }).format(date);
686
- }
687
- function parseLocalizedNumber(str, locale) {
688
- var _a, _b, _c, _d;
689
- if (!str || !str.trim())
690
- return null;
691
- // Detect decimal and thousands separators from the locale
692
- const parts = new Intl.NumberFormat(locale).formatToParts(1234567.89);
693
- const groupSep = (_b = (_a = parts.find((p) => p.type === 'group')) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : ',';
694
- const decimalSep = (_d = (_c = parts.find((p) => p.type === 'decimal')) === null || _c === void 0 ? void 0 : _c.value) !== null && _d !== void 0 ? _d : '.';
695
- // Remove group separators, replace decimal separator with '.'
696
- const normalized = str
697
- .replace(new RegExp(`\\${groupSep}`, 'g'), '')
698
- .replace(new RegExp(`\\${decimalSep}`), '.')
699
- .replace('%', '')
700
- .trim();
701
- const parsed = parseFloat(normalized);
702
- return isNaN(parsed) ? null : parsed;
725
+ /** Returns the localised required-error, or '' when the value passes. */
726
+ function requiredError(value, required, locale) {
727
+ return required && !validateRequired(value) ? t('required', locale) : '';
703
728
  }
704
729
 
705
- 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)}`;
730
+ const mrdCurrencyFieldCss = () => `.sc-mrd-currency-field-h{display:block}.mrd-currency-field.sc-mrd-currency-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-currency-field__label.sc-mrd-currency-field{display:block;font-family:var(--mrd-font-family);font-size:var(--mrd-label-font-size);font-weight:var(--mrd-label-font-weight);color:var(--mrd-label-color)}.mrd-currency-field__label--required.sc-mrd-currency-field::after{content:" *";color:var(--mrd-color-danger)}.mrd-currency-field__row.sc-mrd-currency-field{display:flex;gap:var(--mrd-space-2);align-items:stretch}.mrd-currency-field__amount.sc-mrd-currency-field{display:block;width:100%;height:var(--mrd-input-height);padding:var(--mrd-input-padding-y) var(--mrd-input-padding-x);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-input-color);background-color:var(--mrd-input-bg);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);transition:border-color var(--mrd-transition), box-shadow var(--mrd-transition);outline:none;appearance:none;box-sizing:border-box}.mrd-currency-field__amount.sc-mrd-currency-field::placeholder{color:var(--mrd-input-placeholder-color)}.mrd-currency-field__amount.sc-mrd-currency-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-currency-field__amount.sc-mrd-currency-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.mrd-currency-field__amount--error.sc-mrd-currency-field{border-color:var(--mrd-border-color-error)}.mrd-currency-field__amount--error.sc-mrd-currency-field:focus{box-shadow:var(--mrd-shadow-focus-error)}.mrd-currency-field__amount.sc-mrd-currency-field{flex:1;text-align:right}.mrd-currency-field__currency.sc-mrd-currency-field{width:90px;height:var(--mrd-input-height);padding:var(--mrd-input-padding-y) var(--mrd-space-2);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);font-weight:var(--mrd-font-weight-medium);color:var(--mrd-input-color);background-color:var(--mrd-color-neutral-50);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);outline:none;cursor:pointer;box-sizing:border-box;appearance:none;text-align:center}.mrd-currency-field__currency.sc-mrd-currency-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-currency-field__currency.sc-mrd-currency-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.mrd-currency-field__error.sc-mrd-currency-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}`;
706
731
 
707
732
  const COMMON_CURRENCIES = [
708
733
  'EUR', 'USD', 'GBP', 'CHF', 'JPY', 'CNY', 'AUD', 'CAD',
@@ -729,12 +754,7 @@ const MrdCurrencyField = class {
729
754
  this.handleAmountBlur = (e) => {
730
755
  const raw = e.target.value;
731
756
  const parsed = parseLocalizedNumber(raw, this.locale);
732
- if (this.required && !validateRequired(raw)) {
733
- this.error = t('required', this.locale);
734
- }
735
- else {
736
- this.error = '';
737
- }
757
+ this.error = requiredError(raw, this.required, this.locale);
738
758
  const val = { amount: parsed, currency: this.currency };
739
759
  this.mrdChange.emit({ name: this.name, value: val });
740
760
  this.mrdBlur.emit({ name: this.name, value: val });
@@ -753,12 +773,12 @@ const MrdCurrencyField = class {
753
773
  }
754
774
  render() {
755
775
  const hasError = !!this.error;
756
- return (h(Host, { key: 'fe3520c44d831caf36b388cb5968a9518b16cb8b' }, h("div", { key: '50c1fd2d53038e46da575d3e46e1ec26c2da423b', class: "mrd-currency-field" }, this.label && (h("label", { key: 'a2649d41bf6e3765c8a62ba6559c64c41615027a', class: `mrd-currency-field__label${this.required ? ' mrd-currency-field__label--required' : ''}` }, this.label)), h("div", { key: '952b51f315b4a5c05a8373ce3a3f1041086ba8b8', class: "mrd-currency-field__row" }, h("input", { key: '137a72ffc5d79fc8e0a8cf44c012d84a50c26d5b', 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: '1755854ca9b76dc4b41ad84b6b788685931ace36', 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: '0f10eb98c2e6444651d79d1de92acd0dbcc7133b', class: "mrd-currency-field__error" }, this.error))));
776
+ return (h(Host, { key: '24c530db6e0420af39fa0a35b31e966286f2d00c' }, h("div", { key: '795bc336425fbf1b86828f4a8f5df93930169a3c', class: "mrd-currency-field" }, h(FieldLabel, { key: 'b302cd9296c29ed5719b1f768bd5d4eea86f6406', base: "mrd-currency-field", label: this.label, required: this.required }), h("div", { key: '7efca51615f405ffd660e120accae32f55a9b5a0', class: "mrd-currency-field__row" }, h("input", { key: '5c6fd3549d5631fba49a8a701e6c3a1d0a672890', class: controlClass('mrd-currency-field', hasError, 'amount'), 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: '83ad5e92b623c3c60d161b8828e780adb476682c', 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))))), h(FieldError, { key: 'b059290bb566b119c4f192e750b3e365446243e6', base: "mrd-currency-field", error: this.error }))));
757
777
  }
758
778
  };
759
- MrdCurrencyField.style = mrdCurrencyFieldScss();
779
+ MrdCurrencyField.style = mrdCurrencyFieldCss();
760
780
 
761
- 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)}`;
781
+ const mrdDateFieldCss = () => `.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}.mrd-date-field__input.sc-mrd-date-field::placeholder{color:var(--mrd-input-placeholder-color)}.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)}.mrd-date-field__input.sc-mrd-date-field{cursor:pointer}`;
762
782
 
763
783
  const MrdDateField = class {
764
784
  constructor(hostRef) {
@@ -774,12 +794,7 @@ const MrdDateField = class {
774
794
  this.error = '';
775
795
  this.handleChange = (e) => {
776
796
  const val = e.target.value;
777
- if (this.required && !validateRequired(val)) {
778
- this.error = t('required', this.locale);
779
- }
780
- else {
781
- this.error = '';
782
- }
797
+ this.error = requiredError(val, this.required, this.locale);
783
798
  this.mrdChange.emit({ name: this.name, value: val });
784
799
  };
785
800
  this.handleBlur = (e) => {
@@ -788,13 +803,12 @@ const MrdDateField = class {
788
803
  };
789
804
  }
790
805
  render() {
791
- const hasError = !!this.error;
792
- return (h(Host, { key: '2c0dc2311068a5c759fe8efe58a98a71a9cf4b7b' }, h("div", { key: 'ee1cc0e9a2943cc42439825b8f21cd3492eaca05', class: "mrd-date-field" }, this.label && (h("label", { key: '3f836a991e676b6070a8b3800edfce00cc0d3b3d', class: `mrd-date-field__label${this.required ? ' mrd-date-field__label--required' : ''}` }, this.label)), h("input", { key: '575185661987eea3dc91950f51995b2cc75debea', 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: '480ec99200989f3dc543d9afc648d83d31992b3c', class: "mrd-date-field__error" }, this.error))));
806
+ return (h(Host, { key: '71be9e4bcc87b40cf3b777d3fe0bff23c1a0fa94' }, h("div", { key: '40ced03df5d4185264ba9d03c832b3870ce8ae19', class: "mrd-date-field" }, h(FieldLabel, { key: 'd85ec7c4617a22c8c5862253e8090c85484f8c41', base: "mrd-date-field", label: this.label, required: this.required }), h("input", { key: 'c9211fdefdd9527c7ff40ed9de33153303fc1742', class: controlClass('mrd-date-field', !!this.error), type: "date", name: this.name, value: this.value, required: this.required, disabled: this.disabled, onChange: this.handleChange, onBlur: this.handleBlur }), h(FieldError, { key: '9dd64475bf8a77bea5344faa71f20485b34b86f9', base: "mrd-date-field", error: this.error }))));
793
807
  }
794
808
  };
795
- MrdDateField.style = mrdDateFieldScss();
809
+ MrdDateField.style = mrdDateFieldCss();
796
810
 
797
- 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)}`;
811
+ const mrdDatetimeFieldCss = () => `.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}.mrd-datetime-field__input.sc-mrd-datetime-field::placeholder{color:var(--mrd-input-placeholder-color)}.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)}.mrd-datetime-field__input.sc-mrd-datetime-field{cursor:pointer}`;
798
812
 
799
813
  const MrdDatetimeField = class {
800
814
  constructor(hostRef) {
@@ -812,12 +826,7 @@ const MrdDatetimeField = class {
812
826
  this.handleChange = (e) => {
813
827
  const localVal = e.target.value;
814
828
  this.localValue = localVal;
815
- if (this.required && !validateRequired(localVal)) {
816
- this.error = t('required', this.locale);
817
- }
818
- else {
819
- this.error = '';
820
- }
829
+ this.error = requiredError(localVal, this.required, this.locale);
821
830
  this.mrdChange.emit({ name: this.name, value: this.localToUtc(localVal) });
822
831
  };
823
832
  this.handleBlur = (e) => {
@@ -851,8 +860,7 @@ const MrdDatetimeField = class {
851
860
  return d.toISOString().replace(/\.\d{3}Z$/, 'Z');
852
861
  }
853
862
  render() {
854
- const hasError = !!this.error;
855
- return (h(Host, { key: 'ea8b3b68100ffdb316bc5048f82d85d238bb2e4b' }, h("div", { key: 'c192c6998ee474aaf4df7b3b97ae0bd61f6d624d', class: "mrd-datetime-field" }, this.label && (h("label", { key: '1fbd66c17d76508f0d698a2c258be6779e98d85e', class: `mrd-datetime-field__label${this.required ? ' mrd-datetime-field__label--required' : ''}` }, this.label)), h("input", { key: 'fc9612c062a1cab5076a06598cabf227adce996c', 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: '8788ac01739302f6ad61010b238ff38d45e1b68a', class: "mrd-datetime-field__error" }, this.error))));
863
+ return (h(Host, { key: 'ac07ec2ba79cde998d1247e9d71de336c0e72a64' }, h("div", { key: '8144cf68c4b6b9cbc8396903b84bb355f380ceda', class: "mrd-datetime-field" }, h(FieldLabel, { key: '972686469f68c932e33b8d2c3806422553a3cce3', base: "mrd-datetime-field", label: this.label, required: this.required }), h("input", { key: '370b6032c38fbee22e662c1b2871f96b53b58956', class: controlClass('mrd-datetime-field', !!this.error), type: "datetime-local", name: this.name, value: this.localValue, required: this.required, disabled: this.disabled, onChange: this.handleChange, onBlur: this.handleBlur }), h(FieldError, { key: 'b7a812f82a6b0d2c938aa1f1c2494df685258555', base: "mrd-datetime-field", error: this.error }))));
856
864
  }
857
865
  static get watchers() { return {
858
866
  "value": [{
@@ -860,9 +868,9 @@ const MrdDatetimeField = class {
860
868
  }]
861
869
  }; }
862
870
  };
863
- MrdDatetimeField.style = mrdDatetimeFieldScss();
871
+ MrdDatetimeField.style = mrdDatetimeFieldCss();
864
872
 
865
- const mrdDocumentContainerScss = () => `.sc-mrd-document-container-h{display:block}.mrd-document-container__toolbar.sc-mrd-document-container{display:flex;align-items:center;justify-content:flex-end;gap:var(--mrd-space-2);padding:var(--mrd-space-2) var(--mrd-space-4);border-bottom:1px solid var(--mrd-color-neutral-100)}.mrd-document-container__action.sc-mrd-document-container{display:inline-flex;align-items:center;gap:var(--mrd-space-2);height:1.625rem;padding:0 var(--mrd-space-3);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-700);background:var(--mrd-color-white);border:1px solid var(--mrd-color-neutral-200);border-radius:var(--mrd-border-radius);cursor:pointer;transition:background var(--mrd-transition-fast), border-color var(--mrd-transition-fast)}.mrd-document-container__action.sc-mrd-document-container svg.sc-mrd-document-container{width:1rem;height:1rem;color:#d9a441}.mrd-document-container__action.sc-mrd-document-container:hover:not(:disabled){background:var(--mrd-color-neutral-50);border-color:var(--mrd-color-neutral-300)}.mrd-document-container__action.sc-mrd-document-container:disabled{opacity:0.5;cursor:not-allowed}.mrd-document-container__seg.sc-mrd-document-container{display:inline-flex;gap:2px;padding:2px;background:var(--mrd-color-neutral-100);border-radius:var(--mrd-border-radius)}.mrd-document-container__seg-btn.sc-mrd-document-container{width:1.875rem;height:1.625rem;display:grid;place-items:center;border:none;background:none;border-radius:var(--mrd-border-radius-sm);color:var(--mrd-color-neutral-500);cursor:pointer;transition:color var(--mrd-transition-fast), background var(--mrd-transition-fast)}.mrd-document-container__seg-btn.sc-mrd-document-container:hover{color:var(--mrd-color-neutral-800)}.mrd-document-container__seg-btn[aria-pressed='true'].sc-mrd-document-container{background:var(--mrd-color-white);color:var(--mrd-color-primary-dark);box-shadow:var(--mrd-shadow-sm)}.mrd-document-container__seg-btn.sc-mrd-document-container svg.sc-mrd-document-container{width:1rem;height:1rem}`;
873
+ const mrdDocumentContainerCss = () => `.sc-mrd-document-container-h{display:block}.mrd-document-container__toolbar.sc-mrd-document-container{display:flex;align-items:center;justify-content:flex-end;gap:var(--mrd-space-2);padding:var(--mrd-space-2) var(--mrd-space-4);border-bottom:1px solid var(--mrd-color-neutral-100)}.mrd-document-container__action.sc-mrd-document-container{display:inline-flex;align-items:center;gap:var(--mrd-space-2);height:1.625rem;padding:0 var(--mrd-space-3);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-700);background:var(--mrd-color-white);border:1px solid var(--mrd-color-neutral-200);border-radius:var(--mrd-border-radius);cursor:pointer;transition:background var(--mrd-transition-fast), border-color var(--mrd-transition-fast)}.mrd-document-container__action.sc-mrd-document-container svg.sc-mrd-document-container{width:1rem;height:1rem;color:var(--mrd-color-folder)}.mrd-document-container__action.sc-mrd-document-container:hover:not(:disabled){background:var(--mrd-color-neutral-50);border-color:var(--mrd-color-neutral-300)}.mrd-document-container__action.sc-mrd-document-container:disabled{opacity:0.5;cursor:not-allowed}.mrd-document-container__seg.sc-mrd-document-container{display:inline-flex;gap:2px;padding:2px;background:var(--mrd-color-neutral-100);border-radius:var(--mrd-border-radius)}.mrd-document-container__seg-btn.sc-mrd-document-container{width:1.875rem;height:1.625rem;display:grid;place-items:center;border:none;background:none;border-radius:var(--mrd-border-radius-sm);color:var(--mrd-color-neutral-500);cursor:pointer;transition:color var(--mrd-transition-fast), background var(--mrd-transition-fast)}.mrd-document-container__seg-btn.sc-mrd-document-container:hover{color:var(--mrd-color-neutral-800)}.mrd-document-container__seg-btn[aria-pressed=true].sc-mrd-document-container{background:var(--mrd-color-white);color:var(--mrd-color-primary-dark);box-shadow:var(--mrd-shadow-sm)}.mrd-document-container__seg-btn.sc-mrd-document-container svg.sc-mrd-document-container{width:1rem;height:1rem}`;
866
874
 
867
875
  const MrdDocumentContainer = class {
868
876
  constructor(hostRef) {
@@ -879,8 +887,13 @@ const MrdDocumentContainer = class {
879
887
  this.item = null;
880
888
  /** Parent record id — required for RELATED_VIEW path building. */
881
889
  this.parentId = '';
890
+ /** Canonical parent href, forwarded to the folder tree for single-container seeding. */
891
+ this.containerHref = '';
882
892
  /** Lookup key used for the embedded `data-doclist` / `data-view` attributes. */
883
893
  this.viewKey = '';
894
+ /** Fixed height (px) of the scrolling folder-tree body — the toolbar stays put
895
+ * on top, Finder-style. The table manages its own height. */
896
+ this.height = 460;
884
897
  this.locale = navigator.language;
885
898
  /** Active body: folder tree or flat table. */
886
899
  this.mode = 'tree';
@@ -889,8 +902,8 @@ const MrdDocumentContainer = class {
889
902
  /** Whether the currently mounted table has been init()'d. Reset on every mode switch. */
890
903
  this.tableInited = false;
891
904
  this.createFolder = () => {
892
- var _a, _b;
893
- (_b = (_a = this.listEl) === null || _a === void 0 ? void 0 : _a.createFolder) === null || _b === void 0 ? void 0 : _b.call(_a);
905
+ var _a;
906
+ (_a = this.listEl) === null || _a === void 0 ? void 0 : _a.createFolder();
894
907
  };
895
908
  }
896
909
  /** The embedded table does not self-load: like every mrd-table it waits for the
@@ -902,7 +915,7 @@ const MrdDocumentContainer = class {
902
915
  if (this.mode === 'list' && this.tableEl && !this.tableInited) {
903
916
  this.tableInited = true;
904
917
  const table = this.tableEl;
905
- Promise.resolve((_a = table.componentOnReady) === null || _a === void 0 ? void 0 : _a.call(table)).then(() => { var _a; return (_a = table.init) === null || _a === void 0 ? void 0 : _a.call(table); });
918
+ Promise.resolve((_a = table.componentOnReady) === null || _a === void 0 ? void 0 : _a.call(table)).then(() => table.init());
906
919
  }
907
920
  }
908
921
  setMode(mode) {
@@ -920,7 +933,7 @@ const MrdDocumentContainer = class {
920
933
  }
921
934
  // ── Bodies ───────────────────────────────────────────────────────────────
922
935
  renderTree() {
923
- return (h("mrd-document-list", { "data-doclist": this.viewKey, ref: el => (this.listEl = el), item: this.item, archetype: this.archetype, parentId: this.parentId, locale: this.locale, onMrdLoadDistinct: (e) => {
936
+ return (h("mrd-document-list", { "data-doclist": this.viewKey, ref: el => (this.listEl = el), item: this.item, archetype: this.archetype, parentId: this.parentId, containerHref: this.containerHref, locale: this.locale, onMrdLoadDistinct: (e) => {
924
937
  e.stopPropagation();
925
938
  this.mrdLoadDistinct.emit(e.detail);
926
939
  }, onMrdLoadPage: (e) => {
@@ -961,13 +974,241 @@ const MrdDocumentContainer = class {
961
974
  } }));
962
975
  }
963
976
  render() {
964
- return (h(Host, { key: 'a5393d484bdc202b57c6d32d9ce917e760aff95a' }, this.renderToolbar(), h("div", { key: '52f82de8f7734e13f34d323e3e831e6de5676f46', class: "mrd-document-container__body" }, this.mode === 'tree' ? this.renderTree() : this.renderList())));
977
+ const treeMode = this.mode === 'tree';
978
+ return (h(Host, { key: '018c9eacd169fdf7d352a51472651348af2b45df' }, this.renderToolbar(), h("div", { key: '5ff2ac77d4d12369905696ff075f99785dc1c809', class: "mrd-document-container__body", style: treeMode ? { height: `${this.height}px`, overflowY: 'auto' } : {} }, treeMode ? this.renderTree() : this.renderList())));
965
979
  }
966
980
  get el() { return getElement(this); }
967
981
  };
968
- MrdDocumentContainer.style = mrdDocumentContainerScss();
982
+ MrdDocumentContainer.style = mrdDocumentContainerCss();
983
+
984
+ /**
985
+ * Shared path/query-param conventions for list requests,
986
+ * used by mrd-table and mrd-document-list.
987
+ */
988
+ /** Applies the view-level static filters to `params` using the API operator conventions. */
989
+ function applyViewFilters(params, filters) {
990
+ var _a, _b, _c;
991
+ for (const f of filters !== null && filters !== void 0 ? filters : []) {
992
+ if (!f.name)
993
+ continue;
994
+ if (f.operator === 'EMPTY') {
995
+ params.set(f.name, '');
996
+ continue;
997
+ }
998
+ if (f.operator === 'NOT_EMPTY') {
999
+ params.set(f.name + '_notempty', 'true');
1000
+ continue;
1001
+ }
1002
+ if (f.operator === 'STARTS_WITH') {
1003
+ params.set(f.name + '_startswith', String((_a = f.value) !== null && _a !== void 0 ? _a : ''));
1004
+ continue;
1005
+ }
1006
+ if (f.operator === 'FROM') {
1007
+ params.set(f.name + '_from', String((_b = f.value) !== null && _b !== void 0 ? _b : ''));
1008
+ continue;
1009
+ }
1010
+ if (f.operator === 'TO') {
1011
+ params.set(f.name + '_to', String((_c = f.value) !== null && _c !== void 0 ? _c : ''));
1012
+ continue;
1013
+ }
1014
+ if (f.value != null) {
1015
+ params.set(f.name, String(f.value));
1016
+ }
1017
+ }
1018
+ }
1019
+ /** VIEW: `/{dataClass}`; RELATED_VIEW: `/{fromClass}/{parentId}/{dataClass}`. */
1020
+ function buildListPath(opts) {
1021
+ var _a, _b, _c;
1022
+ if (opts.isRelatedView) {
1023
+ return `/${(_a = opts.fromClass) !== null && _a !== void 0 ? _a : ''}/${opts.parentId}/${(_b = opts.dataClass) !== null && _b !== void 0 ? _b : ''}`;
1024
+ }
1025
+ return `/${(_c = opts.dataClass) !== null && _c !== void 0 ? _c : ''}`;
1026
+ }
1027
+
1028
+ /**
1029
+ * Tree model and pure tree logic for mrd-document-list.
1030
+ * Nodes are mutated in place; the component triggers re-renders via bump().
1031
+ */
1032
+ /** Normalise a folder path: null/""/"/" → root ([]); else split on "/" dropping empties. */
1033
+ function splitFolder(path) {
1034
+ if (path == null)
1035
+ return [];
1036
+ const s = String(path).trim();
1037
+ if (s === '' || s === '/')
1038
+ return [];
1039
+ return s.split('/').map(x => x.trim()).filter(Boolean);
1040
+ }
1041
+ function makeContainerNode(href, label, count) {
1042
+ return {
1043
+ id: 'c:' + href, kind: 'container', label, href,
1044
+ hasDocs: false, docCount: 0, totalCount: count, children: [],
1045
+ open: false, loading: false, foldersLoaded: false, docsLoaded: false, docs: [],
1046
+ };
1047
+ }
1048
+ function makeFolderNode(id, label, containerId) {
1049
+ return {
1050
+ id, kind: 'folder', label, containerId,
1051
+ hasDocs: false, docCount: 0, totalCount: 0, children: [],
1052
+ open: false, loading: false, foldersLoaded: false, docsLoaded: false, docs: [],
1053
+ };
1054
+ }
1055
+ /** Recompute totalCount over the subtree; returns the node's aggregate. */
1056
+ function computeTotals(node) {
1057
+ let total = node.docCount;
1058
+ for (const c of node.children)
1059
+ total += computeTotals(c);
1060
+ node.totalCount = total;
1061
+ return total;
1062
+ }
1063
+ /** Folder path segments of a node relative to its container (derived from its id). */
1064
+ function segmentsOf(node, container) {
1065
+ if (node.kind === 'container')
1066
+ return [];
1067
+ const prefix = container.id + '/';
1068
+ const rest = node.id.startsWith(prefix) ? node.id.slice(prefix.length) : '';
1069
+ return rest ? rest.split('/') : [];
1070
+ }
1071
+ /** Folder string a node represents: the raw distinct value when it holds
1072
+ * documents, else derived from its path segments; null for a container root. */
1073
+ function folderStringOf(node, container) {
1074
+ if (node.kind === 'container')
1075
+ return null;
1076
+ if (node.fullPath != null && node.fullPath !== '')
1077
+ return node.fullPath;
1078
+ const segs = segmentsOf(node, container);
1079
+ return segs.length ? '/' + segs.join('/') : null;
1080
+ }
1081
+ /** Strip a single trailing extension for the document title. */
1082
+ function stripExtension(name) {
1083
+ return name.replace(/\.[^./\\]+$/, '');
1084
+ }
1085
+ /** Rebuild a container's folder subtree from the /distinct folder strings.
1086
+ * New nodes are registered in `nodeIndex`; the container is mutated in place. */
1087
+ function applyFolderDistinct(container, values, nodeIndex) {
1088
+ container.children = [];
1089
+ container.hasDocs = false;
1090
+ container.docCount = 0;
1091
+ for (const v of values) {
1092
+ const raw = typeof v.value === 'string' ? v.value : v.value == null ? '' : String(v.value);
1093
+ const segs = splitFolder(raw);
1094
+ if (segs.length === 0) {
1095
+ // Root documents — the container's own direct documents.
1096
+ container.hasDocs = true;
1097
+ container.docCount = v.count;
1098
+ container.fullPath = raw;
1099
+ continue;
1100
+ }
1101
+ let node = container;
1102
+ const acc = [];
1103
+ for (const seg of segs) {
1104
+ acc.push(seg);
1105
+ let child = node.children.find(c => c.label === seg);
1106
+ if (!child) {
1107
+ child = makeFolderNode(container.id + '/' + acc.join('/'), seg, container.id);
1108
+ node.children.push(child);
1109
+ nodeIndex.set(child.id, child);
1110
+ }
1111
+ node = child;
1112
+ }
1113
+ node.hasDocs = true;
1114
+ node.docCount = v.count;
1115
+ node.fullPath = raw;
1116
+ }
1117
+ computeTotals(container);
1118
+ container.foldersLoaded = true;
1119
+ container.loading = false;
1120
+ }
1121
+ /** Optimistic in-place tree update for a document moved between folders. */
1122
+ function applyDocMove(doc, fromNode, toNode, targetFolder) {
1123
+ fromNode.docs = fromNode.docs.filter(d => d !== doc);
1124
+ fromNode.docCount = Math.max(0, fromNode.docCount - 1);
1125
+ // A now-empty folder should stop showing an expand chevron (it disappears on
1126
+ // the next reload anyway, since it is derived from document folder strings).
1127
+ if (fromNode.docsLoaded)
1128
+ fromNode.hasDocs = fromNode.docs.length > 0;
1129
+ toNode.hasDocs = true;
1130
+ toNode.pending = false; // a pending folder is now materialised
1131
+ toNode.docCount += 1;
1132
+ if (toNode.kind === 'folder')
1133
+ toNode.fullPath = targetFolder !== null && targetFolder !== void 0 ? targetFolder : '';
1134
+ if (toNode.docsLoaded)
1135
+ toNode.docs = [...toNode.docs, doc];
1136
+ }
969
1137
 
970
- const mrdDocumentListScss = () => `.sc-mrd-document-list-h{display:block}.mrd-document-list.sc-mrd-document-list{padding:var(--mrd-space-2) 0}.mrd-document-list__row.sc-mrd-document-list{display:flex;align-items:center;gap:var(--mrd-space-2);height:2.125rem;padding:0 var(--mrd-space-4);cursor:pointer;user-select:none;font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-800)}.mrd-document-list__row.sc-mrd-document-list:hover{background:var(--mrd-color-neutral-50)}.mrd-document-list__row--selected.sc-mrd-document-list{background:var(--mrd-color-primary-50, rgba(22, 163, 74, 0.1))}.mrd-document-list__row--selected.sc-mrd-document-list:hover{background:var(--mrd-color-primary-50, rgba(22, 163, 74, 0.1))}.mrd-document-list__row--pending.sc-mrd-document-list .mrd-document-list__label.sc-mrd-document-list{font-style:italic;color:var(--mrd-color-neutral-500)}.mrd-document-list__row--doc.sc-mrd-document-list{cursor:grab}.mrd-document-list__row--doc.sc-mrd-document-list:active{cursor:grabbing}.mrd-document-list__row--drop.sc-mrd-document-list{background:var(--mrd-color-primary-50, rgba(22, 163, 74, 0.1));box-shadow:inset 0 0 0 1px var(--mrd-color-primary)}.mrd-document-list__row--drop.sc-mrd-document-list:hover{background:var(--mrd-color-primary-50, rgba(22, 163, 74, 0.1))}.mrd-document-list__row--edit.sc-mrd-document-list{cursor:default}.mrd-document-list__name-input.sc-mrd-document-list{flex:1;min-width:0;height:1.625rem;padding:0 var(--mrd-space-2);font-size:var(--mrd-font-size-sm);font-family:inherit;color:var(--mrd-color-neutral-800);border:1px solid var(--mrd-color-primary);border-radius:var(--mrd-border-radius);outline:none;box-shadow:var(--mrd-shadow-focus)}.mrd-document-list__error.sc-mrd-document-list{font-size:var(--mrd-font-size-xs);color:var(--mrd-color-danger, #dc2626);padding-top:0.125rem;padding-bottom:0.25rem}.mrd-document-list__row--dossier.sc-mrd-document-list .mrd-document-list__label.sc-mrd-document-list{font-weight:var(--mrd-font-weight-semibold)}.mrd-document-list__indent.sc-mrd-document-list{flex:none}.mrd-document-list__chev.sc-mrd-document-list{width:1rem;height:1rem;flex:none;display:grid;place-items:center;color:var(--mrd-color-neutral-400);transition:transform var(--mrd-transition-fast)}.mrd-document-list__chev.sc-mrd-document-list svg.sc-mrd-document-list{width:0.6875rem;height:0.6875rem}.mrd-document-list__chev--open.sc-mrd-document-list{transform:rotate(90deg)}.mrd-document-list__chev--leaf.sc-mrd-document-list{visibility:hidden}.mrd-document-list__icon.sc-mrd-document-list{width:1.0625rem;height:1.0625rem;flex:none}.mrd-document-list__icon--dossier.sc-mrd-document-list{color:var(--mrd-color-primary)}.mrd-document-list__icon--folder.sc-mrd-document-list{color:#d9a441}.mrd-document-list__icon--doc.sc-mrd-document-list{color:var(--mrd-color-neutral-400)}.mrd-document-list__label.sc-mrd-document-list{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mrd-document-list__count.sc-mrd-document-list{flex:none;font-family:var(--mrd-font-family-mono);font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-500);background:var(--mrd-color-neutral-100);border-radius:var(--mrd-border-radius-full);padding:0.0625rem 0.5rem}.mrd-document-list__date.sc-mrd-document-list{flex:none;font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-400);font-variant-numeric:tabular-nums}.mrd-document-list__loading.sc-mrd-document-list{display:flex;align-items:center;gap:var(--mrd-space-2);height:1.875rem;padding:0 var(--mrd-space-4);font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-400)}.mrd-document-list__spinner.sc-mrd-document-list{width:0.75rem;height:0.75rem;border:2px solid var(--mrd-color-neutral-300);border-top-color:var(--mrd-color-primary);border-radius:50%;animation:mrd-document-list-spin 0.7s linear infinite}@keyframes mrd-document-list-spin{to{transform:rotate(360deg)}}.mrd-document-list__empty.sc-mrd-document-list{padding:var(--mrd-space-8) var(--mrd-space-4);text-align:center;color:var(--mrd-color-neutral-400);font-size:var(--mrd-font-size-sm)}`;
1138
+ function chevron(open, leaf) {
1139
+ return (h("span", { class: `mrd-document-list__chev${leaf ? ' mrd-document-list__chev--leaf' : ''}${open ? ' mrd-document-list__chev--open' : ''}` }, h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M9 6l6 6-6 6" }))));
1140
+ }
1141
+ function dossierIcon() {
1142
+ return (h("svg", { class: "mrd-document-list__icon mrd-document-list__icon--dossier", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" })));
1143
+ }
1144
+ function folderIcon() {
1145
+ return (h("svg", { class: "mrd-document-list__icon mrd-document-list__icon--folder", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" })));
1146
+ }
1147
+ function docIcon() {
1148
+ return (h("svg", { class: "mrd-document-list__icon mrd-document-list__icon--doc", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }), h("path", { d: "M14 2v6h6" })));
1149
+ }
1150
+ function indent(depth) {
1151
+ return h("span", { class: "mrd-document-list__indent", style: { width: `${depth * 18}px` } });
1152
+ }
1153
+ function renderLoadingRow(ctx, depth) {
1154
+ return (h("div", { class: "mrd-document-list__loading", key: "loading" }, indent(depth), h("span", { class: "mrd-document-list__spinner" }), t('loading', ctx.locale)));
1155
+ }
1156
+ function renderUploadingRow(ctx, depth) {
1157
+ return (h("div", { class: "mrd-document-list__loading", key: "uploading" }, indent(depth), h("span", { class: "mrd-document-list__spinner" }), t('upload_file', ctx.locale)));
1158
+ }
1159
+ function renderDocRow(ctx, doc, node, container, depth) {
1160
+ var _a, _b, _c, _d, _e;
1161
+ const label = (_b = (_a = doc === null || doc === void 0 ? void 0 : doc[ctx.titleField]) !== null && _a !== void 0 ? _a : doc === null || doc === void 0 ? void 0 : doc.name) !== null && _b !== void 0 ? _b : '';
1162
+ const dateRaw = ctx.dateField ? doc === null || doc === void 0 ? void 0 : doc[ctx.dateField] : undefined;
1163
+ const date = dateRaw ? formatDate(dateRaw, ctx.locale) : '';
1164
+ return (h("div", { class: "mrd-document-list__row mrd-document-list__row--doc", key: (_e = (_d = (_c = doc === null || doc === void 0 ? void 0 : doc._links) === null || _c === void 0 ? void 0 : _c.self) === null || _d === void 0 ? void 0 : _d.href) !== null && _e !== void 0 ? _e : label, draggable: true, onClick: () => ctx.on.openDoc(doc), onDragStart: (e) => ctx.on.docDragStart(e, doc, node), onDragEnd: ctx.on.docDragEnd, onDragOver: (e) => ctx.on.nodeDragOver(e, node), onDragLeave: () => ctx.on.nodeDragLeave(node), onDrop: (e) => ctx.on.nodeDrop(e, node, container) }, indent(depth), chevron(false, true), docIcon(), h("span", { class: "mrd-document-list__label" }, label), date && h("span", { class: "mrd-document-list__date" }, date)));
1165
+ }
1166
+ function renderFolderEditRow(ctx, node, depth) {
1167
+ return (h("div", { class: "mrd-document-list__node", key: node.id }, h("div", { class: "mrd-document-list__row mrd-document-list__row--edit" }, indent(depth), chevron(false, true), folderIcon(), h("input", { class: "mrd-document-list__name-input", type: "text", placeholder: t('folder_name_placeholder', ctx.locale), ref: el => ctx.on.setPendingInputEl(el), onInput: ctx.on.pendingInput, onKeyDown: ctx.on.pendingKeyDown, onBlur: () => ctx.on.cancelFolder() })), node.error && (h("div", { class: "mrd-document-list__error", style: { paddingLeft: `${depth * 18 + 52}px` } }, node.error))));
1168
+ }
1169
+ function renderNodeChildren(ctx, container, node, depth) {
1170
+ const out = [];
1171
+ // Direct documents of this node (root docs live on the container node).
1172
+ if (node.hasDocs) {
1173
+ if (node.docsLoaded) {
1174
+ for (const doc of node.docs)
1175
+ out.push(renderDocRow(ctx, doc, node, container, depth));
1176
+ }
1177
+ else if (node.loading) {
1178
+ out.push(renderLoadingRow(ctx, depth));
1179
+ }
1180
+ }
1181
+ // Child folders.
1182
+ for (const child of node.children) {
1183
+ out.push(renderFolderNode(ctx, container, child, depth));
1184
+ }
1185
+ // An uploading file dropped onto this node.
1186
+ if (node.id === ctx.uploadingNodeId)
1187
+ out.push(renderUploadingRow(ctx, depth));
1188
+ return out;
1189
+ }
1190
+ function renderFolderNode(ctx, container, node, depth) {
1191
+ if (node.editing)
1192
+ return renderFolderEditRow(ctx, node, depth);
1193
+ const leaf = node.children.length === 0 && !node.hasDocs;
1194
+ const selected = node.id === ctx.selectedId;
1195
+ const cls = 'mrd-document-list__row'
1196
+ + (selected ? ' mrd-document-list__row--selected' : '')
1197
+ + (node.pending ? ' mrd-document-list__row--pending' : '')
1198
+ + (node.id === ctx.dropTargetId ? ' mrd-document-list__row--drop' : '');
1199
+ return (h("div", { class: "mrd-document-list__node", key: node.id }, h("div", { class: cls, onClick: () => ctx.on.toggleFolder(container, node), onDragOver: (e) => ctx.on.nodeDragOver(e, node), onDragLeave: () => ctx.on.nodeDragLeave(node), onDrop: (e) => ctx.on.nodeDrop(e, node, container) }, indent(depth), chevron(node.open, leaf), folderIcon(), h("span", { class: "mrd-document-list__label" }, node.label), h("span", { class: "mrd-document-list__count" }, node.totalCount)), node.open && h("div", { class: "mrd-document-list__kids" }, renderNodeChildren(ctx, container, node, depth + 1))));
1200
+ }
1201
+ function renderContainerNode(ctx, node, depth) {
1202
+ const selected = node.id === ctx.selectedId;
1203
+ const cls = 'mrd-document-list__row mrd-document-list__row--dossier'
1204
+ + (selected ? ' mrd-document-list__row--selected' : '')
1205
+ + (node.id === ctx.dropTargetId ? ' mrd-document-list__row--drop' : '');
1206
+ return (h("div", { class: "mrd-document-list__node", key: node.id }, h("div", { class: cls, onClick: () => ctx.on.toggleContainer(node), onDragOver: (e) => ctx.on.nodeDragOver(e, node), onDragLeave: () => ctx.on.nodeDragLeave(node), onDrop: (e) => ctx.on.nodeDrop(e, node, node) }, indent(depth), chevron(node.open, false), dossierIcon(), h("span", { class: "mrd-document-list__label" }, node.label), h("span", { class: "mrd-document-list__count" }, node.totalCount)), node.open && (h("div", { class: "mrd-document-list__kids" }, node.loading && !node.foldersLoaded
1207
+ ? renderLoadingRow(ctx, depth + 1)
1208
+ : renderNodeChildren(ctx, node, node, depth + 1)))));
1209
+ }
1210
+
1211
+ const mrdDocumentListCss = () => `@charset "UTF-8";.sc-mrd-document-list-h{display:block;height:100%}.mrd-document-list.sc-mrd-document-list{padding:var(--mrd-space-2) 0;min-height:100%;box-sizing:border-box}.mrd-document-list--drop-active.sc-mrd-document-list{outline:2px dashed var(--mrd-color-primary);outline-offset:-4px;background:var(--mrd-color-primary-50, rgba(22, 163, 74, 0.06))}.mrd-document-list__row.sc-mrd-document-list{display:flex;align-items:center;gap:var(--mrd-space-2);height:2.125rem;padding:0 var(--mrd-space-4);cursor:pointer;user-select:none;font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-800)}.mrd-document-list__row.sc-mrd-document-list:hover{background:var(--mrd-color-neutral-50)}.mrd-document-list__row--selected.sc-mrd-document-list{background:var(--mrd-color-primary-50, rgba(22, 163, 74, 0.1))}.mrd-document-list__row--selected.sc-mrd-document-list:hover{background:var(--mrd-color-primary-50, rgba(22, 163, 74, 0.1))}.mrd-document-list__row--pending.sc-mrd-document-list .mrd-document-list__label.sc-mrd-document-list{font-style:italic;color:var(--mrd-color-neutral-500)}.mrd-document-list__row--doc.sc-mrd-document-list{cursor:grab}.mrd-document-list__row--doc.sc-mrd-document-list:active{cursor:grabbing}.mrd-document-list__row--drop.sc-mrd-document-list{background:var(--mrd-color-primary-50, rgba(22, 163, 74, 0.1));box-shadow:inset 0 0 0 1px var(--mrd-color-primary)}.mrd-document-list__row--drop.sc-mrd-document-list:hover{background:var(--mrd-color-primary-50, rgba(22, 163, 74, 0.1))}.mrd-document-list__row--edit.sc-mrd-document-list{cursor:default}.mrd-document-list__name-input.sc-mrd-document-list{flex:1;min-width:0;height:1.625rem;padding:0 var(--mrd-space-2);font-size:var(--mrd-font-size-sm);font-family:inherit;color:var(--mrd-color-neutral-800);border:1px solid var(--mrd-color-primary);border-radius:var(--mrd-border-radius);outline:none;box-shadow:var(--mrd-shadow-focus)}.mrd-document-list__error.sc-mrd-document-list{font-size:var(--mrd-font-size-xs);color:var(--mrd-color-danger, #dc2626);padding-top:0.125rem;padding-bottom:0.25rem}.mrd-document-list__row--dossier.sc-mrd-document-list .mrd-document-list__label.sc-mrd-document-list{font-weight:var(--mrd-font-weight-semibold)}.mrd-document-list__indent.sc-mrd-document-list{flex:none}.mrd-document-list__chev.sc-mrd-document-list{width:1rem;height:1rem;flex:none;display:grid;place-items:center;color:var(--mrd-color-neutral-400);transition:transform var(--mrd-transition-fast)}.mrd-document-list__chev.sc-mrd-document-list svg.sc-mrd-document-list{width:0.6875rem;height:0.6875rem}.mrd-document-list__chev--open.sc-mrd-document-list{transform:rotate(90deg)}.mrd-document-list__chev--leaf.sc-mrd-document-list{visibility:hidden}.mrd-document-list__icon.sc-mrd-document-list{width:1.0625rem;height:1.0625rem;flex:none}.mrd-document-list__icon--dossier.sc-mrd-document-list{color:var(--mrd-color-primary)}.mrd-document-list__icon--folder.sc-mrd-document-list{color:var(--mrd-color-folder)}.mrd-document-list__icon--doc.sc-mrd-document-list{color:var(--mrd-color-neutral-400)}.mrd-document-list__label.sc-mrd-document-list{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mrd-document-list__count.sc-mrd-document-list{flex:none;font-family:var(--mrd-font-family-mono);font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-500);background:var(--mrd-color-neutral-100);border-radius:var(--mrd-border-radius-full);padding:0.0625rem 0.5rem}.mrd-document-list__date.sc-mrd-document-list{flex:none;font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-400);font-variant-numeric:tabular-nums}.mrd-document-list__loading.sc-mrd-document-list{display:flex;align-items:center;gap:var(--mrd-space-2);height:1.875rem;padding:0 var(--mrd-space-4);font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-400)}.mrd-document-list__spinner.sc-mrd-document-list{width:0.75rem;height:0.75rem;border:2px solid var(--mrd-color-neutral-300);border-top-color:var(--mrd-color-primary);border-radius:50%;animation:mrd-document-list-spin 0.7s linear infinite}@keyframes mrd-document-list-spin{to{transform:rotate(360deg)}}.mrd-document-list__empty.sc-mrd-document-list{padding:var(--mrd-space-8) var(--mrd-space-4);text-align:center;color:var(--mrd-color-neutral-400);font-size:var(--mrd-font-size-sm)}`;
971
1212
 
972
1213
  const MrdDocumentList = class {
973
1214
  constructor(hostRef) {
@@ -983,6 +1224,11 @@ const MrdDocumentList = class {
983
1224
  this.item = null;
984
1225
  /** Parent record id — required for RELATED_VIEW path building. */
985
1226
  this.parentId = '';
1227
+ /** Canonical parent href (`/{base}/{tenant}/{fromClass}/{parentId}`) supplied by
1228
+ * the host. When the RELATED_VIEW's `inverseRelation` equals the archetype
1229
+ * `container` slot, this seeds a single container so an empty dossier still
1230
+ * accepts file drops and folder creation. */
1231
+ this.containerHref = '';
986
1232
  this.locale = navigator.language;
987
1233
  this.containers = [];
988
1234
  this.rootLoading = true;
@@ -994,6 +1240,8 @@ const MrdDocumentList = class {
994
1240
  this.dropTargetId = null;
995
1241
  /** Node id showing an "uploading…" indicator while a dropped file is processed. */
996
1242
  this.uploadingNodeId = null;
1243
+ /** Whether a drag is hovering the root drop-zone (single-container area highlight). */
1244
+ this.rootDropActive = false;
997
1245
  this.nodeIndex = new Map();
998
1246
  // ── New-folder editing state ───────────────────────────────────────────────
999
1247
  /** The pending node whose inline name input is open (null = not creating). */
@@ -1027,7 +1275,7 @@ const MrdDocumentList = class {
1027
1275
  return;
1028
1276
  const { target, container } = resolved;
1029
1277
  const tempId = `${container.id}/__new__${this.newFolderSeq++}`;
1030
- const node = this.makeFolderNode(tempId, '', container.id);
1278
+ const node = makeFolderNode(tempId, '', container.id);
1031
1279
  node.pending = true;
1032
1280
  node.editing = true;
1033
1281
  target.children = [...target.children, node];
@@ -1118,8 +1366,18 @@ const MrdDocumentList = class {
1118
1366
  e.preventDefault();
1119
1367
  if (e.dataTransfer)
1120
1368
  e.dataTransfer.dropEffect = file ? 'copy' : 'move';
1369
+ if (!this.rootDropActive)
1370
+ this.rootDropActive = true;
1371
+ };
1372
+ this.onRootDragLeave = (e) => {
1373
+ const related = e.relatedTarget;
1374
+ if (related && this.el.contains(related))
1375
+ return; // moved onto a child, still inside
1376
+ if (this.rootDropActive)
1377
+ this.rootDropActive = false;
1121
1378
  };
1122
1379
  this.onRootDrop = (e) => {
1380
+ this.rootDropActive = false;
1123
1381
  if (!this.singleContainer)
1124
1382
  return;
1125
1383
  const only = this.containers[0];
@@ -1136,7 +1394,33 @@ const MrdDocumentList = class {
1136
1394
  };
1137
1395
  }
1138
1396
  componentDidLoad() {
1139
- this.emitContainerDistinct();
1397
+ if (this.isSeededSingleContainer()) {
1398
+ this.seedSingleContainer();
1399
+ }
1400
+ else {
1401
+ this.emitContainerDistinct();
1402
+ }
1403
+ }
1404
+ /** True when the view is a single-container context: a RELATED_VIEW whose
1405
+ * `inverseRelation` matches the archetype `container` slot, with a known
1406
+ * parent href. The container is then implied by context (not by distinct),
1407
+ * so it works even with zero documents. */
1408
+ isSeededSingleContainer() {
1409
+ var _a, _b;
1410
+ return (((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === ClientLayoutItemType.RELATED_VIEW &&
1411
+ !!((_b = this.item) === null || _b === void 0 ? void 0 : _b.inverseRelation) &&
1412
+ this.item.inverseRelation === this.containerField &&
1413
+ !!this.containerHref);
1414
+ }
1415
+ /** Seed the single implied container from context and load its folders. */
1416
+ seedSingleContainer() {
1417
+ const node = makeContainerNode(this.containerHref, this.containerField, 0);
1418
+ this.nodeIndex.set(node.id, node);
1419
+ this.containers = [node];
1420
+ this.rootLoading = false;
1421
+ this.singleContainer = true;
1422
+ node.open = true;
1423
+ this.emitFolderDistinct(node);
1140
1424
  }
1141
1425
  componentDidRender() {
1142
1426
  if (this.pendingNeedsFocus && this.pendingInputEl) {
@@ -1172,50 +1456,42 @@ const MrdDocumentList = class {
1172
1456
  return (_b = (_a = this.archetype) === null || _a === void 0 ? void 0 : _a.slots) === null || _b === void 0 ? void 0 : _b.date;
1173
1457
  }
1174
1458
  // ── Path / query building (mirrors mrd-table conventions) ────────────────
1175
- /** VIEW: `/{dataClass}`; RELATED_VIEW: `/{fromClass}/{parentId}/{dataClass}`. */
1459
+ /** VIEW: `/{dataClass}`; RELATED_VIEW: `/{fromClass}/{parentId}/{dataClass}`.
1460
+ * Used for reads (list/distinct): `dataClass`/`relatedClass` may be an abstract
1461
+ * type (e.g. "contents"), filtered down to the concrete `filterClass` via the
1462
+ * `type` query param — see baseParams(). */
1176
1463
  buildDataPath() {
1464
+ var _a, _b;
1465
+ const it = this.item;
1466
+ return buildListPath({
1467
+ isRelatedView: (it === null || it === void 0 ? void 0 : it.type) === ClientLayoutItemType.RELATED_VIEW,
1468
+ fromClass: it === null || it === void 0 ? void 0 : it.fromClass,
1469
+ parentId: this.parentId,
1470
+ dataClass: (_b = (_a = it === null || it === void 0 ? void 0 : it.dataClass) !== null && _a !== void 0 ? _a : it === null || it === void 0 ? void 0 : it.relatedClass) !== null && _b !== void 0 ? _b : '',
1471
+ });
1472
+ }
1473
+ /** Path for creating a new document (file-drop). Unlike buildDataPath(), this
1474
+ * must target the concrete type: `dataClass`/`relatedClass` can be an abstract
1475
+ * base type (e.g. "contents") that cannot be POSTed to directly, so prefer
1476
+ * `filterClass` (e.g. "documents") when present. */
1477
+ buildCreatePath() {
1177
1478
  var _a, _b, _c;
1178
1479
  const it = this.item;
1179
- const dataClass = (_b = (_a = it === null || it === void 0 ? void 0 : it.dataClass) !== null && _a !== void 0 ? _a : it === null || it === void 0 ? void 0 : it.relatedClass) !== null && _b !== void 0 ? _b : '';
1180
- if ((it === null || it === void 0 ? void 0 : it.type) === ClientLayoutItemType.RELATED_VIEW) {
1181
- return `/${(_c = it.fromClass) !== null && _c !== void 0 ? _c : ''}/${this.parentId}/${dataClass}`;
1182
- }
1183
- return `/${dataClass}`;
1480
+ return buildListPath({
1481
+ isRelatedView: (it === null || it === void 0 ? void 0 : it.type) === ClientLayoutItemType.RELATED_VIEW,
1482
+ fromClass: it === null || it === void 0 ? void 0 : it.fromClass,
1483
+ parentId: this.parentId,
1484
+ dataClass: (_c = (_b = (_a = it === null || it === void 0 ? void 0 : it.filterClass) !== null && _a !== void 0 ? _a : it === null || it === void 0 ? void 0 : it.dataClass) !== null && _b !== void 0 ? _b : it === null || it === void 0 ? void 0 : it.relatedClass) !== null && _c !== void 0 ? _c : '',
1485
+ });
1184
1486
  }
1185
1487
  /** View-level static filters + filterClass, shared by every request. */
1186
1488
  baseParams() {
1187
- var _a, _b, _c, _d, _e, _f, _g;
1489
+ var _a, _b, _c;
1188
1490
  const p = new URLSearchParams();
1189
1491
  const filterClass = (_a = this.item) === null || _a === void 0 ? void 0 : _a.filterClass;
1190
1492
  if (filterClass)
1191
1493
  p.set('type', filterClass);
1192
- for (const f of ((_d = (_c = (_b = this.item) === null || _b === void 0 ? void 0 : _b.view) === null || _c === void 0 ? void 0 : _c.filter) !== null && _d !== void 0 ? _d : [])) {
1193
- if (!f.name)
1194
- continue;
1195
- if (f.operator === 'EMPTY') {
1196
- p.set(f.name, '');
1197
- continue;
1198
- }
1199
- if (f.operator === 'NOT_EMPTY') {
1200
- p.set(f.name + '_notempty', 'true');
1201
- continue;
1202
- }
1203
- if (f.operator === 'STARTS_WITH') {
1204
- p.set(f.name + '_startswith', String((_e = f.value) !== null && _e !== void 0 ? _e : ''));
1205
- continue;
1206
- }
1207
- if (f.operator === 'FROM') {
1208
- p.set(f.name + '_from', String((_f = f.value) !== null && _f !== void 0 ? _f : ''));
1209
- continue;
1210
- }
1211
- if (f.operator === 'TO') {
1212
- p.set(f.name + '_to', String((_g = f.value) !== null && _g !== void 0 ? _g : ''));
1213
- continue;
1214
- }
1215
- if (f.value != null) {
1216
- p.set(f.name, String(f.value));
1217
- }
1218
- }
1494
+ applyViewFilters(p, (_c = (_b = this.item) === null || _b === void 0 ? void 0 : _b.view) === null || _c === void 0 ? void 0 : _c.filter);
1219
1495
  return p;
1220
1496
  }
1221
1497
  emitContainerDistinct() {
@@ -1282,7 +1558,7 @@ const MrdDocumentList = class {
1282
1558
  if (!v.value || typeof v.value !== 'object')
1283
1559
  continue;
1284
1560
  const href = v.value.href;
1285
- const node = this.makeContainerNode(href, v.value.name, v.count);
1561
+ const node = makeContainerNode(href, v.value.name, v.count);
1286
1562
  nodes.push(node);
1287
1563
  this.nodeIndex.set(node.id, node);
1288
1564
  }
@@ -1300,38 +1576,7 @@ const MrdDocumentList = class {
1300
1576
  const container = this.nodeIndex.get(containerId);
1301
1577
  if (!container)
1302
1578
  return;
1303
- container.children = [];
1304
- container.hasDocs = false;
1305
- container.docCount = 0;
1306
- for (const v of values) {
1307
- const raw = typeof v.value === 'string' ? v.value : v.value == null ? '' : String(v.value);
1308
- const segs = this.splitFolder(raw);
1309
- if (segs.length === 0) {
1310
- // Root documents — the container's own direct documents.
1311
- container.hasDocs = true;
1312
- container.docCount = v.count;
1313
- container.fullPath = raw;
1314
- continue;
1315
- }
1316
- let node = container;
1317
- const acc = [];
1318
- for (const seg of segs) {
1319
- acc.push(seg);
1320
- let child = node.children.find(c => c.label === seg);
1321
- if (!child) {
1322
- child = this.makeFolderNode(container.id + '/' + acc.join('/'), seg, container.id);
1323
- node.children.push(child);
1324
- this.nodeIndex.set(child.id, child);
1325
- }
1326
- node = child;
1327
- }
1328
- node.hasDocs = true;
1329
- node.docCount = v.count;
1330
- node.fullPath = raw;
1331
- }
1332
- this.computeTotals(container);
1333
- container.foldersLoaded = true;
1334
- container.loading = false;
1579
+ applyFolderDistinct(container, values, this.nodeIndex);
1335
1580
  // If the container has root documents, load them now (they show inline on expand).
1336
1581
  if (container.hasDocs && !container.docsLoaded) {
1337
1582
  this.emitDocuments(container, container);
@@ -1339,36 +1584,6 @@ const MrdDocumentList = class {
1339
1584
  this.bump();
1340
1585
  }
1341
1586
  // ── Tree helpers ─────────────────────────────────────────────────────────
1342
- /** Normalise a folder path: null/""/"/" → root ([]); else split on "/" dropping empties. */
1343
- splitFolder(path) {
1344
- if (path == null)
1345
- return [];
1346
- const s = String(path).trim();
1347
- if (s === '' || s === '/')
1348
- return [];
1349
- return s.split('/').map(x => x.trim()).filter(Boolean);
1350
- }
1351
- makeContainerNode(href, label, count) {
1352
- return {
1353
- id: 'c:' + href, kind: 'container', label, href,
1354
- hasDocs: false, docCount: 0, totalCount: count, children: [],
1355
- open: false, loading: false, foldersLoaded: false, docsLoaded: false, docs: [],
1356
- };
1357
- }
1358
- makeFolderNode(id, label, containerId) {
1359
- return {
1360
- id, kind: 'folder', label, containerId,
1361
- hasDocs: false, docCount: 0, totalCount: 0, children: [],
1362
- open: false, loading: false, foldersLoaded: false, docsLoaded: false, docs: [],
1363
- };
1364
- }
1365
- computeTotals(node) {
1366
- let total = node.docCount;
1367
- for (const c of node.children)
1368
- total += this.computeTotals(c);
1369
- node.totalCount = total;
1370
- return total;
1371
- }
1372
1587
  /** Force a re-render after mutating nodes in place. */
1373
1588
  bump() {
1374
1589
  this.containers = [...this.containers];
@@ -1418,14 +1633,6 @@ const MrdDocumentList = class {
1418
1633
  async createFolder() {
1419
1634
  this.startCreateFolder();
1420
1635
  }
1421
- /** Folder path segments of a node relative to its container (derived from its id). */
1422
- segmentsOf(node, container) {
1423
- if (node.kind === 'container')
1424
- return [];
1425
- const prefix = container.id + '/';
1426
- const rest = node.id.startsWith(prefix) ? node.id.slice(prefix.length) : '';
1427
- return rest ? rest.split('/') : [];
1428
- }
1429
1636
  commitFolder() {
1430
1637
  const node = this.pendingNode;
1431
1638
  const parent = this.pendingParent;
@@ -1450,7 +1657,7 @@ const MrdDocumentList = class {
1450
1657
  }
1451
1658
  // Finalise: swap the temp id for the real path-derived id so a later distinct
1452
1659
  // value with the same folder string merges onto this node.
1453
- const segs = [...this.segmentsOf(parent, container), name];
1660
+ const segs = [...segmentsOf(parent, container), name];
1454
1661
  this.nodeIndex.delete(node.id);
1455
1662
  node.id = container.id + '/' + segs.join('/');
1456
1663
  node.fullPath = '/' + segs.join('/');
@@ -1499,10 +1706,6 @@ const MrdDocumentList = class {
1499
1706
  this.bump();
1500
1707
  this.mrdUpload.emit({ file });
1501
1708
  }
1502
- /** Strip a single trailing extension for the document title. */
1503
- stripExtension(name) {
1504
- return name.replace(/\.[^./\\]+$/, '');
1505
- }
1506
1709
  /** Host callback with the uploaded file reference. Builds the create payload
1507
1710
  * from the archetype slots and requests the new document. */
1508
1711
  async setFileReference(uri) {
@@ -1510,16 +1713,20 @@ const MrdDocumentList = class {
1510
1713
  if (!up)
1511
1714
  return;
1512
1715
  const { file, node, container } = up;
1513
- const folder = this.folderStringOf(node, container);
1716
+ const folder = folderStringOf(node, container);
1514
1717
  const values = {
1515
1718
  [this.fileField]: uri,
1516
- [this.titleField]: this.stripExtension(file.name),
1719
+ [this.titleField]: stripExtension(file.name),
1517
1720
  [this.folderField]: folder,
1518
- [this.containerField]: container.href,
1519
1721
  };
1520
- this.mrdCreateObject.emit({ path: this.buildDataPath(), values });
1722
+ // The create path already embeds the container (/{fromClass}/{parentId}/...)
1723
+ // when this is the seeded single-container context; omit the redundant field.
1724
+ if (!this.isSeededSingleContainer()) {
1725
+ values[this.containerField] = container.href;
1726
+ }
1727
+ this.mrdCreateObject.emit({ path: this.buildCreatePath(), values });
1521
1728
  // Optimistically show the new document (no href until a reload).
1522
- const optimistic = { [this.titleField]: this.stripExtension(file.name), _optimistic: true };
1729
+ const optimistic = { [this.titleField]: stripExtension(file.name), _optimistic: true };
1523
1730
  const wasUnloadedEmpty = !node.docsLoaded && node.docCount === 0;
1524
1731
  node.hasDocs = true;
1525
1732
  node.pending = false;
@@ -1548,16 +1755,6 @@ const MrdDocumentList = class {
1548
1755
  this.lastOptimisticDoc = null;
1549
1756
  this.bump();
1550
1757
  }
1551
- /** Folder string a node represents: the raw distinct value when it holds
1552
- * documents, else derived from its path segments; null for a container root. */
1553
- folderStringOf(node, container) {
1554
- if (node.kind === 'container')
1555
- return null;
1556
- if (node.fullPath != null && node.fullPath !== '')
1557
- return node.fullPath;
1558
- const segs = this.segmentsOf(node, container);
1559
- return segs.length ? '/' + segs.join('/') : null;
1560
- }
1561
1758
  moveDocument(toNode, toContainer) {
1562
1759
  var _a, _b;
1563
1760
  const doc = this.dragDoc;
@@ -1569,26 +1766,14 @@ const MrdDocumentList = class {
1569
1766
  : (fromNode.containerId ? this.nodeIndex.get(fromNode.containerId) : undefined);
1570
1767
  if (!fromContainer)
1571
1768
  return;
1572
- const targetFolder = this.folderStringOf(toNode, toContainer);
1573
- const sourceFolder = this.folderStringOf(fromNode, fromContainer);
1769
+ const targetFolder = folderStringOf(toNode, toContainer);
1770
+ const sourceFolder = folderStringOf(fromNode, fromContainer);
1574
1771
  const sameContainer = toContainer === fromContainer;
1575
1772
  // No-op: dropped back onto its own folder.
1576
1773
  if (toNode === fromNode || (sameContainer && targetFolder === sourceFolder))
1577
1774
  return;
1578
- // ── Optimistic tree update (fire-and-forget; no refetch) ──
1579
- fromNode.docs = fromNode.docs.filter(d => d !== doc);
1580
- fromNode.docCount = Math.max(0, fromNode.docCount - 1);
1581
- // A now-empty folder should stop showing an expand chevron (it disappears on
1582
- // the next reload anyway, since it is derived from document folder strings).
1583
- if (fromNode.docsLoaded)
1584
- fromNode.hasDocs = fromNode.docs.length > 0;
1585
- toNode.hasDocs = true;
1586
- toNode.pending = false; // a pending folder is now materialised
1587
- toNode.docCount += 1;
1588
- if (toNode.kind === 'folder')
1589
- toNode.fullPath = targetFolder !== null && targetFolder !== void 0 ? targetFolder : '';
1590
- if (toNode.docsLoaded)
1591
- toNode.docs = [...toNode.docs, doc];
1775
+ // Optimistic tree update (fire-and-forget; no refetch).
1776
+ applyDocMove(doc, fromNode, toNode, targetFolder);
1592
1777
  this.recomputeContainerTotals(fromContainer, -1);
1593
1778
  if (!sameContainer)
1594
1779
  this.recomputeContainerTotals(toContainer, 1);
@@ -1606,7 +1791,7 @@ const MrdDocumentList = class {
1606
1791
  * loaded; otherwise just nudge the aggregate badge by the delta. */
1607
1792
  recomputeContainerTotals(container, delta) {
1608
1793
  if (container.foldersLoaded) {
1609
- this.computeTotals(container);
1794
+ computeTotals(container);
1610
1795
  }
1611
1796
  else {
1612
1797
  container.totalCount = Math.max(0, container.totalCount + delta);
@@ -1619,105 +1804,64 @@ const MrdDocumentList = class {
1619
1804
  this.mrdNavigate.emit({ href, label });
1620
1805
  }
1621
1806
  // ── Render ───────────────────────────────────────────────────────────────
1622
- renderChevron(open, leaf) {
1623
- return (h("span", { class: `mrd-document-list__chev${leaf ? ' mrd-document-list__chev--leaf' : ''}${open ? ' mrd-document-list__chev--open' : ''}` }, h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M9 6l6 6-6 6" }))));
1624
- }
1625
- renderDossierIcon() {
1626
- return (h("svg", { class: "mrd-document-list__icon mrd-document-list__icon--dossier", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" })));
1627
- }
1628
- renderFolderIcon() {
1629
- return (h("svg", { class: "mrd-document-list__icon mrd-document-list__icon--folder", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" })));
1630
- }
1631
- renderDocIcon() {
1632
- return (h("svg", { class: "mrd-document-list__icon mrd-document-list__icon--doc", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }), h("path", { d: "M14 2v6h6" })));
1633
- }
1634
- indent(depth) {
1635
- return h("span", { class: "mrd-document-list__indent", style: { width: `${depth * 18}px` } });
1636
- }
1637
- renderDocRow(doc, node, container, depth) {
1638
- var _a, _b, _c, _d, _e;
1639
- const label = (_b = (_a = doc === null || doc === void 0 ? void 0 : doc[this.titleField]) !== null && _a !== void 0 ? _a : doc === null || doc === void 0 ? void 0 : doc.name) !== null && _b !== void 0 ? _b : '';
1640
- const dateRaw = this.dateField ? doc === null || doc === void 0 ? void 0 : doc[this.dateField] : undefined;
1641
- const date = dateRaw ? formatDate(dateRaw, this.locale) : '';
1642
- return (h("div", { class: "mrd-document-list__row mrd-document-list__row--doc", key: (_e = (_d = (_c = doc === null || doc === void 0 ? void 0 : doc._links) === null || _c === void 0 ? void 0 : _c.self) === null || _d === void 0 ? void 0 : _d.href) !== null && _e !== void 0 ? _e : label, draggable: true, onClick: () => this.openDoc(doc), onDragStart: (e) => this.onDocDragStart(e, doc, node), onDragEnd: this.onDocDragEnd, onDragOver: (e) => this.onNodeDragOver(e, node), onDragLeave: () => this.onNodeDragLeave(node), onDrop: (e) => this.onNodeDrop(e, node, container) }, this.indent(depth), this.renderChevron(false, true), this.renderDocIcon(), h("span", { class: "mrd-document-list__label" }, label), date && h("span", { class: "mrd-document-list__date" }, date)));
1643
- }
1644
- renderLoadingRow(depth) {
1645
- return (h("div", { class: "mrd-document-list__loading", key: "loading" }, this.indent(depth), h("span", { class: "mrd-document-list__spinner" }), t('loading', this.locale)));
1646
- }
1647
- renderChildren(container, node, depth) {
1648
- const out = [];
1649
- // Direct documents of this node (root docs live on the container node).
1650
- if (node.hasDocs) {
1651
- if (node.docsLoaded) {
1652
- for (const doc of node.docs)
1653
- out.push(this.renderDocRow(doc, node, container, depth));
1654
- }
1655
- else if (node.loading) {
1656
- out.push(this.renderLoadingRow(depth));
1657
- }
1658
- }
1659
- // Child folders.
1660
- for (const child of node.children) {
1661
- out.push(this.renderFolderNode(container, child, depth));
1662
- }
1663
- // An uploading file dropped onto this node.
1664
- if (node.id === this.uploadingNodeId)
1665
- out.push(this.renderUploadingRow(depth));
1666
- return out;
1667
- }
1668
- renderUploadingRow(depth) {
1669
- return (h("div", { class: "mrd-document-list__loading", key: "uploading" }, this.indent(depth), h("span", { class: "mrd-document-list__spinner" }), t('upload_file', this.locale)));
1670
- }
1671
- renderFolderEditRow(node, depth) {
1672
- return (h("div", { class: "mrd-document-list__node", key: node.id }, h("div", { class: "mrd-document-list__row mrd-document-list__row--edit" }, this.indent(depth), this.renderChevron(false, true), this.renderFolderIcon(), h("input", { class: "mrd-document-list__name-input", type: "text", placeholder: t('folder_name_placeholder', this.locale), ref: el => (this.pendingInputEl = el), onInput: this.onPendingInput, onKeyDown: this.onPendingKeyDown, onBlur: () => this.cancelFolder() })), node.error && (h("div", { class: "mrd-document-list__error", style: { paddingLeft: `${depth * 18 + 52}px` } }, node.error))));
1673
- }
1674
- renderFolderNode(container, node, depth) {
1675
- if (node.editing)
1676
- return this.renderFolderEditRow(node, depth);
1677
- const leaf = node.children.length === 0 && !node.hasDocs;
1678
- const selected = node.id === this.selectedId;
1679
- const cls = 'mrd-document-list__row'
1680
- + (selected ? ' mrd-document-list__row--selected' : '')
1681
- + (node.pending ? ' mrd-document-list__row--pending' : '')
1682
- + (node.id === this.dropTargetId ? ' mrd-document-list__row--drop' : '');
1683
- return (h("div", { class: "mrd-document-list__node", key: node.id }, h("div", { class: cls, onClick: () => this.toggleFolder(container, node), onDragOver: (e) => this.onNodeDragOver(e, node), onDragLeave: () => this.onNodeDragLeave(node), onDrop: (e) => this.onNodeDrop(e, node, container) }, this.indent(depth), this.renderChevron(node.open, leaf), this.renderFolderIcon(), h("span", { class: "mrd-document-list__label" }, node.label), h("span", { class: "mrd-document-list__count" }, node.totalCount)), node.open && h("div", { class: "mrd-document-list__kids" }, this.renderChildren(container, node, depth + 1))));
1684
- }
1685
- renderContainerNode(node, depth) {
1686
- const selected = node.id === this.selectedId;
1687
- const cls = 'mrd-document-list__row mrd-document-list__row--dossier'
1688
- + (selected ? ' mrd-document-list__row--selected' : '')
1689
- + (node.id === this.dropTargetId ? ' mrd-document-list__row--drop' : '');
1690
- return (h("div", { class: "mrd-document-list__node", key: node.id }, h("div", { class: cls, onClick: () => this.toggleContainer(node), onDragOver: (e) => this.onNodeDragOver(e, node), onDragLeave: () => this.onNodeDragLeave(node), onDrop: (e) => this.onNodeDrop(e, node, node) }, this.indent(depth), this.renderChevron(node.open, false), this.renderDossierIcon(), h("span", { class: "mrd-document-list__label" }, node.label), h("span", { class: "mrd-document-list__count" }, node.totalCount)), node.open && (h("div", { class: "mrd-document-list__kids" }, node.loading && !node.foldersLoaded
1691
- ? this.renderLoadingRow(depth + 1)
1692
- : this.renderChildren(node, node, depth + 1)))));
1807
+ treeCtx() {
1808
+ return {
1809
+ locale: this.locale,
1810
+ titleField: this.titleField,
1811
+ dateField: this.dateField,
1812
+ selectedId: this.selectedId,
1813
+ dropTargetId: this.dropTargetId,
1814
+ uploadingNodeId: this.uploadingNodeId,
1815
+ on: {
1816
+ toggleContainer: node => this.toggleContainer(node),
1817
+ toggleFolder: (container, node) => this.toggleFolder(container, node),
1818
+ openDoc: doc => this.openDoc(doc),
1819
+ docDragStart: this.onDocDragStart,
1820
+ docDragEnd: this.onDocDragEnd,
1821
+ nodeDragOver: this.onNodeDragOver,
1822
+ nodeDragLeave: this.onNodeDragLeave,
1823
+ nodeDrop: this.onNodeDrop,
1824
+ pendingInput: this.onPendingInput,
1825
+ pendingKeyDown: this.onPendingKeyDown,
1826
+ cancelFolder: () => this.cancelFolder(),
1827
+ setPendingInputEl: el => (this.pendingInputEl = el),
1828
+ },
1829
+ };
1693
1830
  }
1694
1831
  render() {
1832
+ const ctx = this.treeCtx();
1695
1833
  let body;
1696
1834
  if (this.rootLoading) {
1697
- body = this.renderLoadingRow(0);
1835
+ body = renderLoadingRow(ctx, 0);
1698
1836
  }
1699
1837
  else if (this.containers.length === 0) {
1700
- body = h("div", { key: 'b8c3297cd7cff5bf79ce694d2ee1a64c570df5ce', class: "mrd-document-list__empty" }, t('no_results', this.locale));
1838
+ body = h("div", { key: 'ce40dab51ab61447838e5059159ae4778209a6f3', class: "mrd-document-list__empty" }, t('no_results', this.locale));
1701
1839
  }
1702
1840
  else if (this.singleContainer) {
1703
1841
  // Dossier context: render the single container's folder tree at the root.
1704
1842
  const only = this.containers[0];
1705
- body = only.loading && !only.foldersLoaded
1706
- ? this.renderLoadingRow(0)
1707
- : this.renderChildren(only, only, 0);
1843
+ if (only.loading && !only.foldersLoaded) {
1844
+ body = renderLoadingRow(ctx, 0);
1845
+ }
1846
+ else {
1847
+ const kids = renderNodeChildren(ctx, only, only, 0);
1848
+ body = kids.length
1849
+ ? kids
1850
+ : h("div", { class: "mrd-document-list__empty" }, t('doc_empty_drop', this.locale));
1851
+ }
1708
1852
  }
1709
1853
  else {
1710
- body = this.containers.map(c => this.renderContainerNode(c, 0));
1854
+ body = this.containers.map(c => renderContainerNode(ctx, c, 0));
1711
1855
  }
1712
- return (h(Host, { key: 'ff3b024a79ba2270aa28861923bc6406f98061aa' }, h("div", { key: '9db121e5336a4e3c82443257f6424db5ab4f0baf', class: "mrd-document-list", onDragOver: this.onRootDragOver, onDrop: this.onRootDrop }, body)));
1856
+ return (h(Host, { key: '9e1f7805ae18bce506c530a481db902900ad95f3' }, h("div", { key: 'a51334634e94310a71650ad49f17f0a20e2aed4d', class: 'mrd-document-list' + (this.rootDropActive ? ' mrd-document-list--drop-active' : ''), onDragOver: this.onRootDragOver, onDragLeave: this.onRootDragLeave, onDrop: this.onRootDrop }, body)));
1713
1857
  }
1714
1858
  get el() { return getElement(this); }
1715
1859
  };
1716
1860
  /** Root sentinel id for the container-level distinct request. */
1717
1861
  MrdDocumentList.ROOT = '__root__';
1718
- MrdDocumentList.style = mrdDocumentListScss();
1862
+ MrdDocumentList.style = mrdDocumentListCss();
1719
1863
 
1720
- const mrdDocumentViewScss = () => `.sc-mrd-document-view-h{display:block}.mrd-document-view.sc-mrd-document-view{max-width:720px}.mrd-document-view__crumb.sc-mrd-document-view{display:inline-flex;align-items:center;gap:var(--mrd-space-2);margin-bottom:var(--mrd-space-4);padding:var(--mrd-space-1) var(--mrd-space-3);background:var(--mrd-color-primary-light);border:1px solid transparent;border-radius:var(--mrd-border-radius);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-primary-dark);cursor:pointer}.mrd-document-view__crumb.sc-mrd-document-view:hover{border-color:var(--mrd-color-primary)}.mrd-document-view__crumb-icon.sc-mrd-document-view{width:0.875rem;height:0.875rem;flex-shrink:0}.mrd-document-view__title.sc-mrd-document-view{font-size:var(--mrd-font-size-2xl);font-weight:var(--mrd-font-weight-bold);color:var(--mrd-color-neutral-900);letter-spacing:-0.02em;margin:0 0 var(--mrd-space-1) 0}.mrd-document-view__date.sc-mrd-document-view{font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-400);font-variant-numeric:tabular-nums;margin:0 0 var(--mrd-space-6) 0}.mrd-document-view__file.sc-mrd-document-view{display:flex;align-items:center;gap:var(--mrd-space-4);padding:var(--mrd-space-4);border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius-md);background:var(--mrd-color-neutral-50);margin-bottom:var(--mrd-space-6)}.mrd-document-view__file-preview.sc-mrd-document-view{width:2.875rem;height:3.625rem;flex-shrink:0;display:grid;place-items:center;border-radius:var(--mrd-border-radius-sm);background:var(--mrd-color-white);border:1px solid var(--mrd-border-color);color:var(--mrd-color-danger);box-shadow:var(--mrd-shadow-sm)}.mrd-document-view__file-preview.sc-mrd-document-view svg.sc-mrd-document-view{width:1.5rem;height:1.5rem}.mrd-document-view__file-meta.sc-mrd-document-view{flex:1;min-width:0}.mrd-document-view__file-name.sc-mrd-document-view{font-weight:var(--mrd-font-weight-semibold);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-800);word-break:break-word}.mrd-document-view__download.sc-mrd-document-view{display:inline-flex;align-items:center;gap:var(--mrd-space-2);flex-shrink:0;height:2rem;padding:0 var(--mrd-space-3);background:var(--mrd-color-white);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);font-weight:var(--mrd-font-weight-medium);color:var(--mrd-color-neutral-700);cursor:pointer}.mrd-document-view__download.sc-mrd-document-view:hover{background:var(--mrd-color-neutral-100);color:var(--mrd-color-neutral-900)}.mrd-document-view__download.sc-mrd-document-view svg.sc-mrd-document-view{width:0.9375rem;height:0.9375rem}.mrd-document-view__summary-body.sc-mrd-document-view{font-size:var(--mrd-font-size-base);color:var(--mrd-color-neutral-700);line-height:var(--mrd-line-height-relaxed)}`;
1864
+ const mrdDocumentViewCss = () => `.sc-mrd-document-view-h{display:block}.mrd-document-view.sc-mrd-document-view{max-width:720px}.mrd-document-view__crumb.sc-mrd-document-view{display:inline-flex;align-items:center;gap:var(--mrd-space-2);margin-bottom:var(--mrd-space-4);padding:var(--mrd-space-1) var(--mrd-space-3);background:var(--mrd-color-primary-light);border:1px solid transparent;border-radius:var(--mrd-border-radius);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-primary-dark);cursor:pointer}.mrd-document-view__crumb.sc-mrd-document-view:hover{border-color:var(--mrd-color-primary)}.mrd-document-view__crumb-icon.sc-mrd-document-view{width:0.875rem;height:0.875rem;flex-shrink:0}.mrd-document-view__title.sc-mrd-document-view{font-size:var(--mrd-font-size-2xl);font-weight:var(--mrd-font-weight-bold);color:var(--mrd-color-neutral-900);letter-spacing:-0.02em;margin:0 0 var(--mrd-space-1) 0}.mrd-document-view__date.sc-mrd-document-view{font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-400);font-variant-numeric:tabular-nums;margin:0 0 var(--mrd-space-6) 0}.mrd-document-view__file.sc-mrd-document-view{display:flex;align-items:center;gap:var(--mrd-space-4);padding:var(--mrd-space-4);border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius-md);background:var(--mrd-color-neutral-50);margin-bottom:var(--mrd-space-6)}.mrd-document-view__file-preview.sc-mrd-document-view{width:2.875rem;height:3.625rem;flex-shrink:0;display:grid;place-items:center;border-radius:var(--mrd-border-radius-sm);background:var(--mrd-color-white);border:1px solid var(--mrd-border-color);color:var(--mrd-color-danger);box-shadow:var(--mrd-shadow-sm)}.mrd-document-view__file-preview.sc-mrd-document-view svg.sc-mrd-document-view{width:1.5rem;height:1.5rem}.mrd-document-view__file-meta.sc-mrd-document-view{flex:1;min-width:0}.mrd-document-view__file-name.sc-mrd-document-view{font-weight:var(--mrd-font-weight-semibold);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-800);word-break:break-word}.mrd-document-view__download.sc-mrd-document-view{display:inline-flex;align-items:center;gap:var(--mrd-space-2);flex-shrink:0;height:2rem;padding:0 var(--mrd-space-3);background:var(--mrd-color-white);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);font-weight:var(--mrd-font-weight-medium);color:var(--mrd-color-neutral-700);cursor:pointer}.mrd-document-view__download.sc-mrd-document-view:hover{background:var(--mrd-color-neutral-100);color:var(--mrd-color-neutral-900)}.mrd-document-view__download.sc-mrd-document-view svg.sc-mrd-document-view{width:0.9375rem;height:0.9375rem}.mrd-document-view__summary-body.sc-mrd-document-view{font-size:var(--mrd-font-size-base);color:var(--mrd-color-neutral-700);line-height:var(--mrd-line-height-relaxed)}`;
1721
1865
 
1722
1866
  const MrdDocumentView = class {
1723
1867
  constructor(hostRef) {
@@ -1767,12 +1911,12 @@ const MrdDocumentView = class {
1767
1911
  const date = dateRaw != null && dateRaw !== '' ? formatDate(dateRaw, this.locale) : null;
1768
1912
  const summaryRaw = this.slotValue('summary');
1769
1913
  const summary = summaryRaw != null && summaryRaw !== '' ? String(summaryRaw) : null;
1770
- return (h(Host, { key: '0a2071925ecdb21738376d66fa4babf4590e694c' }, h("div", { key: 'a2d29c0b6e211cab142adc780466bc885a602e96', class: "mrd-document-view" }, this.renderContainer(), title && h("h1", { key: '7f5ac202c21bc8a70f0dd15e2e1fa06e651b5bce', class: "mrd-document-view__title" }, title), date && h("p", { key: 'b1dce94d5fd8bfd5e078644f631a38f91b87e7ff', class: "mrd-document-view__date" }, date), this.renderFile(), summary && (h("div", { key: '588b9ca40a49ae9ea303852620bde75333b440ab', class: "mrd-document-view__summary" }, h("div", { key: 'd3b8adb85ac346b72451e789c10aedd539c966de', class: "mrd-document-view__summary-body", innerHTML: summary }))))));
1914
+ return (h(Host, { key: '0c64c72eaf5e1eefc2ca9aebb2543081eb1eae32' }, h("div", { key: '70cce81b089fee81a4c163a6ba5fbcc8cb46131c', class: "mrd-document-view" }, this.renderContainer(), title && h("h1", { key: '50f85b32a6740d6cf57fdf1bb0bcc597b5e97b31', class: "mrd-document-view__title" }, title), date && h("p", { key: 'b3c8fb3b4382104858d49ef9a1597034665122bb', class: "mrd-document-view__date" }, date), this.renderFile(), summary && (h("div", { key: '2046c1eca7601549115de0c95ff778abaf5faf46', class: "mrd-document-view__summary" }, h("div", { key: '875863d3e438eee3d4df10473a93f09370fde08c', class: "mrd-document-view__summary-body", innerHTML: summary }))))));
1771
1915
  }
1772
1916
  };
1773
- MrdDocumentView.style = mrdDocumentViewScss();
1917
+ MrdDocumentView.style = mrdDocumentViewCss();
1774
1918
 
1775
- 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)}`;
1919
+ const mrdEmailFieldCss = () => `.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)}`;
1776
1920
 
1777
1921
  const MrdEmailField = class {
1778
1922
  constructor(hostRef) {
@@ -1793,26 +1937,18 @@ const MrdEmailField = class {
1793
1937
  };
1794
1938
  this.handleBlur = (e) => {
1795
1939
  const val = e.target.value;
1796
- if (this.required && !validateRequired(val)) {
1797
- this.error = t('required', this.locale);
1798
- }
1799
- else if (val && !validateEmail(val)) {
1800
- this.error = t('invalid_email', this.locale);
1801
- }
1802
- else {
1803
- this.error = '';
1804
- }
1940
+ this.error = requiredError(val, this.required, this.locale)
1941
+ || (val && !validateEmail(val) ? t('invalid_email', this.locale) : '');
1805
1942
  this.mrdBlur.emit({ name: this.name, value: val });
1806
1943
  };
1807
1944
  }
1808
1945
  render() {
1809
- const hasError = !!this.error;
1810
- return (h(Host, { key: '0d442ab2a711c26c83fcdbf0fd8cd006d8dd8649' }, h("div", { key: 'ceb2a80679514c4c5b888fe096c90ed6cc973f64', class: "mrd-email-field" }, this.label && (h("label", { key: '663f95eff1002ee56cfc3104514bf31b47e26750', class: `mrd-email-field__label${this.required ? ' mrd-email-field__label--required' : ''}` }, this.label)), h("input", { key: '42dbdec25a47b37cfd68d00d0b8a481f96fe8241', 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: '626ee856ceaa7051fb9dd1de8b7cbd708e83f617', class: "mrd-email-field__error" }, this.error))));
1946
+ return (h(Host, { key: '93f7c4975c24e6001e772f2858344edec04cda10' }, h("div", { key: '4f49a2a1f68a4161762861c5d54fd3690c88ac5d', class: "mrd-email-field" }, h(FieldLabel, { key: '23b20799f3e7c04889b7bc3a271e61b0bb5d7537', base: "mrd-email-field", label: this.label, required: this.required }), h("input", { key: '0fc452bfb9295a80102eeed4b32bcc9475c9d17b', class: controlClass('mrd-email-field', !!this.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 }), h(FieldError, { key: '34945fff9c69cf2f0aeb56492c95052250514d5c', base: "mrd-email-field", error: this.error }))));
1811
1947
  }
1812
1948
  };
1813
- MrdEmailField.style = mrdEmailFieldScss();
1949
+ MrdEmailField.style = mrdEmailFieldCss();
1814
1950
 
1815
- 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)}`;
1951
+ const mrdFieldCss = () => `.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)}`;
1816
1952
 
1817
1953
  const MrdField = class {
1818
1954
  constructor(hostRef) {
@@ -1997,9 +2133,47 @@ const MrdField = class {
1997
2133
  }]
1998
2134
  }; }
1999
2135
  };
2000
- MrdField.style = mrdFieldScss();
2136
+ MrdField.style = mrdFieldCss();
2001
2137
 
2002
- 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)}`;
2138
+ /**
2139
+ * Shared upload behaviour for mrd-file-field and mrd-image-field:
2140
+ * file validation, drop-zone class building and drag-drop wiring.
2141
+ */
2142
+ /** Validates a selected/dropped file; returns a localised error message or '' when accepted. */
2143
+ function validateUploadFile(file, maxSize, locale, requireImage = false) {
2144
+ if (maxSize > 0 && file.size > maxSize)
2145
+ return t('file_too_large', locale);
2146
+ if (requireImage && !file.type.startsWith('image/'))
2147
+ return t('invalid_image', locale);
2148
+ return '';
2149
+ }
2150
+ /** BEM class string for the drop zone, e.g. base 'mrd-file-field' → 'mrd-file-field__zone …'. */
2151
+ function uploadZoneClass(base, opts) {
2152
+ return [
2153
+ `${base}__zone`,
2154
+ opts.dragging ? `${base}__zone--dragging` : '',
2155
+ opts.error ? `${base}__zone--error` : '',
2156
+ opts.disabled ? `${base}__zone--disabled` : '',
2157
+ ].filter(Boolean).join(' ');
2158
+ }
2159
+ /** Drag-drop handlers for the drop zone; the component owns the dragging state and file handling. */
2160
+ function makeDragHandlers(setDragging, onFile) {
2161
+ return {
2162
+ onDragOver: (e) => {
2163
+ e.preventDefault();
2164
+ setDragging(true);
2165
+ },
2166
+ onDragLeave: () => setDragging(false),
2167
+ onDrop: (e) => {
2168
+ var _a, _b, _c;
2169
+ e.preventDefault();
2170
+ setDragging(false);
2171
+ onFile((_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);
2172
+ },
2173
+ };
2174
+ }
2175
+
2176
+ const mrdFileFieldCss = () => `.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__error.sc-mrd-file-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}.mrd-file-field__zone.sc-mrd-file-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-file-field__zone.sc-mrd-file-field:hover,.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__zone.sc-mrd-file-field{padding:var(--mrd-space-6)}.mrd-file-field__input.sc-mrd-file-field{position:absolute;inset:0;opacity:0;width:100%;height:100%;pointer-events:none;cursor:pointer}.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;width:18px;height:18px;border:2px solid var(--mrd-color-neutral-300);border-top-color:var(--mrd-color-primary);border-radius:50%;animation:mrd-spin 0.6s linear infinite;flex-shrink:0}@keyframes mrd-spin{to{transform:rotate(360deg)}}`;
2003
2177
 
2004
2178
  const MrdFileField = class {
2005
2179
  constructor(hostRef) {
@@ -2024,20 +2198,7 @@ const MrdFileField = class {
2024
2198
  const files = e.target.files;
2025
2199
  this.handleFile((_a = files === null || files === void 0 ? void 0 : files[0]) !== null && _a !== void 0 ? _a : null);
2026
2200
  };
2027
- this.handleDragOver = (e) => {
2028
- e.preventDefault();
2029
- this.isDragging = true;
2030
- };
2031
- this.handleDragLeave = () => {
2032
- this.isDragging = false;
2033
- };
2034
- this.handleDrop = (e) => {
2035
- var _a, _b, _c;
2036
- e.preventDefault();
2037
- this.isDragging = false;
2038
- 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;
2039
- this.handleFile(file);
2040
- };
2201
+ this.drag = makeDragHandlers(dragging => (this.isDragging = dragging), file => this.handleFile(file));
2041
2202
  this.handleZoneClick = () => {
2042
2203
  var _a;
2043
2204
  if (!this.disabled && !this.uploading) {
@@ -2071,8 +2232,9 @@ const MrdFileField = class {
2071
2232
  this.mrdChange.emit({ name: this.name, value: null });
2072
2233
  return;
2073
2234
  }
2074
- if (this.maxSize > 0 && file.size > this.maxSize) {
2075
- this.error = t('file_too_large', this.locale);
2235
+ const uploadError = validateUploadFile(file, this.maxSize, this.locale);
2236
+ if (uploadError) {
2237
+ this.error = uploadError;
2076
2238
  return;
2077
2239
  }
2078
2240
  this.error = '';
@@ -2084,13 +2246,12 @@ const MrdFileField = class {
2084
2246
  render() {
2085
2247
  const hasFile = this.uploading || (typeof this.value === 'string' && this.value) || this.fileName;
2086
2248
  const hasError = !!this.error;
2087
- const zoneClass = [
2088
- 'mrd-file-field__zone',
2089
- this.isDragging ? 'mrd-file-field__zone--dragging' : '',
2090
- hasError ? 'mrd-file-field__zone--error' : '',
2091
- this.disabled || this.uploading ? 'mrd-file-field__zone--disabled' : '',
2092
- ].filter(Boolean).join(' ');
2093
- return (h(Host, { key: '095bb39f3cb1680cf5e7e51bdfd06d8eb087f237' }, h("div", { key: '7e5b5fe6e63b6530221083c8bcb82bcac59a5fe7', class: "mrd-file-field" }, this.label && (h("label", { key: 'c34723f4199371d6fe8ea87463d878b89c038590', class: `mrd-file-field__label${this.required ? ' mrd-file-field__label--required' : ''}` }, this.label)), h("div", { key: '4727667345d3cd4a5c65a431744a09f366943c13', class: zoneClass, onClick: this.handleZoneClick, onDragOver: this.handleDragOver, onDragLeave: this.handleDragLeave, onDrop: this.handleDrop }, h("input", { key: '45ed41c0f094dbe269561c8586e473f908cdf4a4', 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: '00ce94ead3c32ed63e903cfd9d8480084a308d84', class: "mrd-file-field__error" }, this.error))));
2249
+ const zoneClass = uploadZoneClass('mrd-file-field', {
2250
+ dragging: this.isDragging,
2251
+ error: hasError,
2252
+ disabled: this.disabled || this.uploading,
2253
+ });
2254
+ return (h(Host, { key: '2c4cee79cd0f95ed3750dfc86007a2b36aa3da15' }, h("div", { key: '5b47d0f83e8e38b22bb04409544ec2af580274f1', class: "mrd-file-field" }, h(FieldLabel, { key: '47a92d5680670bf750854fa6e7883da54a40baec', base: "mrd-file-field", label: this.label, required: this.required }), h("div", { key: '684f6ab39c32635fb5ca966ccab4a061d8682f89', class: zoneClass, onClick: this.handleZoneClick, onDragOver: this.drag.onDragOver, onDragLeave: this.drag.onDragLeave, onDrop: this.drag.onDrop }, h("input", { key: 'a47231d8c68280623daf0c5a2e4341417e7a88d0', 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)))))), h(FieldError, { key: '5f18e91aa94319a5571c368e745c108fb0d371a7', base: "mrd-file-field", error: this.error }))));
2094
2255
  }
2095
2256
  static get watchers() { return {
2096
2257
  "value": [{
@@ -2098,9 +2259,9 @@ const MrdFileField = class {
2098
2259
  }]
2099
2260
  }; }
2100
2261
  };
2101
- MrdFileField.style = mrdFileFieldScss();
2262
+ MrdFileField.style = mrdFileFieldCss();
2102
2263
 
2103
- 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)}`;
2264
+ const mrdFormCss = () => `.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)}`;
2104
2265
 
2105
2266
  const MrdForm = class {
2106
2267
  constructor(hostRef) {
@@ -2467,9 +2628,9 @@ const MrdForm = class {
2467
2628
  }]
2468
2629
  }; }
2469
2630
  };
2470
- MrdForm.style = mrdFormScss();
2631
+ MrdForm.style = mrdFormCss();
2471
2632
 
2472
- 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)}`;
2633
+ const mrdHyperlinkFieldCss = () => `.sc-mrd-hyperlink-field-h{display:block}.mrd-hyperlink-field.sc-mrd-hyperlink-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-hyperlink-field__label.sc-mrd-hyperlink-field{display:block;font-family:var(--mrd-font-family);font-size:var(--mrd-label-font-size);font-weight:var(--mrd-label-font-weight);color:var(--mrd-label-color)}.mrd-hyperlink-field__label--required.sc-mrd-hyperlink-field::after{content:" *";color:var(--mrd-color-danger)}.mrd-hyperlink-field__input.sc-mrd-hyperlink-field{display:block;width:100%;height:var(--mrd-input-height);padding:var(--mrd-input-padding-y) var(--mrd-input-padding-x);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-input-color);background-color:var(--mrd-input-bg);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);transition:border-color var(--mrd-transition), box-shadow var(--mrd-transition);outline:none;appearance:none;box-sizing:border-box}.mrd-hyperlink-field__input.sc-mrd-hyperlink-field::placeholder{color:var(--mrd-input-placeholder-color)}.mrd-hyperlink-field__input.sc-mrd-hyperlink-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-hyperlink-field__input.sc-mrd-hyperlink-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.mrd-hyperlink-field__input--error.sc-mrd-hyperlink-field{border-color:var(--mrd-border-color-error)}.mrd-hyperlink-field__input--error.sc-mrd-hyperlink-field:focus{box-shadow:var(--mrd-shadow-focus-error)}.mrd-hyperlink-field__error.sc-mrd-hyperlink-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}.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)}`;
2473
2634
 
2474
2635
  const MrdHyperlinkField = class {
2475
2636
  constructor(hostRef) {
@@ -2495,15 +2656,8 @@ const MrdHyperlinkField = class {
2495
2656
  this.mrdChange.emit({ name: this.name, value: this.buildValue() });
2496
2657
  };
2497
2658
  this.handleBlur = () => {
2498
- if (this.required && !validateRequired(this.internalHref)) {
2499
- this.error = t('required', this.locale);
2500
- }
2501
- else if (this.internalHref && !validateUrl(this.internalHref)) {
2502
- this.error = t('invalid_url', this.locale);
2503
- }
2504
- else {
2505
- this.error = '';
2506
- }
2659
+ this.error = requiredError(this.internalHref, this.required, this.locale)
2660
+ || (this.internalHref && !validateUrl(this.internalHref) ? t('invalid_url', this.locale) : '');
2507
2661
  this.mrdBlur.emit({ name: this.name, value: this.buildValue() });
2508
2662
  };
2509
2663
  }
@@ -2536,7 +2690,7 @@ const MrdHyperlinkField = class {
2536
2690
  ? h("a", { class: "mrd-hyperlink-field__link", href: this.internalHref, target: "_blank", rel: "noopener noreferrer" }, this.internalName || this.internalHref)
2537
2691
  : h("span", { class: "mrd-hyperlink-field__empty" }, "\u2014"))));
2538
2692
  }
2539
- 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))));
2693
+ return (h(Host, null, h("div", { class: "mrd-hyperlink-field" }, h(FieldLabel, { base: "mrd-hyperlink-field", label: this.label, required: this.required }), h("input", { class: controlClass('mrd-hyperlink-field', hasError), 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 }), h(FieldError, { base: "mrd-hyperlink-field", error: this.error }))));
2540
2694
  }
2541
2695
  static get watchers() { return {
2542
2696
  "value": [{
@@ -2544,9 +2698,9 @@ const MrdHyperlinkField = class {
2544
2698
  }]
2545
2699
  }; }
2546
2700
  };
2547
- MrdHyperlinkField.style = mrdHyperlinkFieldScss();
2701
+ MrdHyperlinkField.style = mrdHyperlinkFieldCss();
2548
2702
 
2549
- 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)}`;
2703
+ const mrdImageFieldCss = () => `.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__error.sc-mrd-image-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}.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,.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:rgba(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-spin 0.6s linear infinite}@keyframes mrd-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)}`;
2550
2704
 
2551
2705
  const MrdImageField = class {
2552
2706
  constructor(hostRef) {
@@ -2572,20 +2726,7 @@ const MrdImageField = class {
2572
2726
  const files = e.target.files;
2573
2727
  this.handleFile((_a = files === null || files === void 0 ? void 0 : files[0]) !== null && _a !== void 0 ? _a : null);
2574
2728
  };
2575
- this.handleDragOver = (e) => {
2576
- e.preventDefault();
2577
- this.isDragging = true;
2578
- };
2579
- this.handleDragLeave = () => {
2580
- this.isDragging = false;
2581
- };
2582
- this.handleDrop = (e) => {
2583
- var _a, _b, _c;
2584
- e.preventDefault();
2585
- this.isDragging = false;
2586
- 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;
2587
- this.handleFile(file);
2588
- };
2729
+ this.drag = makeDragHandlers(dragging => (this.isDragging = dragging), file => this.handleFile(file));
2589
2730
  this.handleZoneClick = () => {
2590
2731
  var _a;
2591
2732
  if (!this.disabled && !this.uploading) {
@@ -2622,12 +2763,9 @@ const MrdImageField = class {
2622
2763
  this.mrdChange.emit({ name: this.name, value: null });
2623
2764
  return;
2624
2765
  }
2625
- if (this.maxSize > 0 && file.size > this.maxSize) {
2626
- this.error = t('file_too_large', this.locale);
2627
- return;
2628
- }
2629
- if (!file.type.startsWith('image/')) {
2630
- this.error = 'Please select an image file';
2766
+ const uploadError = validateUploadFile(file, this.maxSize, this.locale, true);
2767
+ if (uploadError) {
2768
+ this.error = uploadError;
2631
2769
  return;
2632
2770
  }
2633
2771
  this.error = '';
@@ -2645,13 +2783,12 @@ const MrdImageField = class {
2645
2783
  }
2646
2784
  render() {
2647
2785
  const hasError = !!this.error;
2648
- const zoneClass = [
2649
- 'mrd-image-field__zone',
2650
- this.isDragging ? 'mrd-image-field__zone--dragging' : '',
2651
- hasError ? 'mrd-image-field__zone--error' : '',
2652
- this.disabled || this.uploading ? 'mrd-image-field__zone--disabled' : '',
2653
- ].filter(Boolean).join(' ');
2654
- return (h(Host, { key: '97db2df72839f36b7a46e153a5dd1c208c52b522' }, h("div", { key: 'c8f2d3d858f90d322d26082aaf5adb57acfc78f4', class: "mrd-image-field" }, this.label && (h("label", { key: '6625e5031ff0b7c06f76c1ea0387f1bd5c1858a4', class: `mrd-image-field__label${this.required ? ' mrd-image-field__label--required' : ''}` }, this.label)), h("div", { key: '364216e6a96e845e21c42e821fdff02bd2612ff8', class: zoneClass, onClick: this.handleZoneClick, onDragOver: this.handleDragOver, onDragLeave: this.handleDragLeave, onDrop: this.handleDrop }, h("input", { key: '0487706ddd9f48cda1cb0c2a178809d90674486b', 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: 'bd505ef4f4b67c4e9138d8825c6e600f583f4cab', class: "mrd-image-field__error" }, this.error))));
2786
+ const zoneClass = uploadZoneClass('mrd-image-field', {
2787
+ dragging: this.isDragging,
2788
+ error: hasError,
2789
+ disabled: this.disabled || this.uploading,
2790
+ });
2791
+ return (h(Host, { key: 'ab78d93ab6c810363a8993bea4545f7406680e58' }, h("div", { key: '727ae5d9c1cce22d90d26229a9ea5d677abb4b07', class: "mrd-image-field" }, h(FieldLabel, { key: 'aab0e9fcc0204e8ea617453b5ca458f683194125', base: "mrd-image-field", label: this.label, required: this.required }), h("div", { key: '1241faff26c47a303fd0431201f490c6b8725987', class: zoneClass, onClick: this.handleZoneClick, onDragOver: this.drag.onDragOver, onDragLeave: this.drag.onDragLeave, onDrop: this.drag.onDrop }, h("input", { key: '70e3b8f869927ad525465ace96ed3ea24f5b7555', 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)))))), h(FieldError, { key: '01552a994c1e5a9f25129586a95562c32a377046', base: "mrd-image-field", error: this.error }))));
2655
2792
  }
2656
2793
  static get watchers() { return {
2657
2794
  "value": [{
@@ -2659,7 +2796,36 @@ const MrdImageField = class {
2659
2796
  }]
2660
2797
  }; }
2661
2798
  };
2662
- MrdImageField.style = mrdImageFieldScss();
2799
+ MrdImageField.style = mrdImageFieldCss();
2800
+
2801
+ /** Key an embedded view is addressed by (setViewPage etc.). */
2802
+ function viewKeyFor(item) {
2803
+ var _a, _b, _c, _d;
2804
+ if (item.type === ClientLayoutItemType.RELATED_VIEW)
2805
+ return (_b = (_a = item.relatedClass) !== null && _a !== void 0 ? _a : item.name) !== null && _b !== void 0 ? _b : '';
2806
+ return (_d = (_c = item.dataClass) !== null && _c !== void 0 ? _c : item.name) !== null && _d !== void 0 ? _d : '';
2807
+ }
2808
+ /** Depth-first flatten of the SECTION/GROUP tree. */
2809
+ function flattenItems(items) {
2810
+ const result = [];
2811
+ for (const item of items) {
2812
+ result.push(item);
2813
+ if (item.items)
2814
+ result.push(...flattenItems(item.items));
2815
+ }
2816
+ return result;
2817
+ }
2818
+ /** Build the canonical parent href `/{base}/{tenant}/{fromClass}/{parentId}` from
2819
+ * the object's self href. Empty unless it is a RELATED_VIEW with a fromClass. */
2820
+ function buildContainerHref(item, selfHref, parentId) {
2821
+ if (item.type !== ClientLayoutItemType.RELATED_VIEW || !item.fromClass || !parentId)
2822
+ return '';
2823
+ const segs = selfHref.split('/').filter(Boolean);
2824
+ if (segs.length < 2)
2825
+ return '';
2826
+ const [base, tenant] = segs;
2827
+ return `/${base}/${tenant}/${item.fromClass}/${parentId}`;
2828
+ }
2663
2829
 
2664
2830
  class CellRenderer {
2665
2831
  static render(column, row, locale) {
@@ -2765,7 +2931,114 @@ class CellRenderer {
2765
2931
  }
2766
2932
  }
2767
2933
 
2768
- 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-xs);font-weight:var(--mrd-font-weight-semibold);color:var(--mrd-color-neutral-500);margin:0 0 var(--mrd-space-2) 0;padding-bottom:0;letter-spacing:0.01em}.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}`;
2934
+ /** FILE and IMAGE cells share the same download button. */
2935
+ function downloadLink(ctx, href, fileName, label) {
2936
+ return (h("button", { class: "mrd-layout-section__download-link", onClick: () => href && ctx.on.download({ 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" })), label));
2937
+ }
2938
+ function renderSingleFieldValue(ctx, item, value) {
2939
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
2940
+ const dt = item.dataType;
2941
+ switch (dt) {
2942
+ case ClientLayoutItemFieldDataType.HYPERLINK: {
2943
+ const v = value;
2944
+ const href = (_a = v === null || v === void 0 ? void 0 : v.href) !== null && _a !== void 0 ? _a : String(value);
2945
+ 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;
2946
+ return (h("a", { class: "mrd-layout-section__link", href: href, target: "_blank", rel: "noopener noreferrer" }, label));
2947
+ }
2948
+ case ClientLayoutItemFieldDataType.TEXTBLOCK:
2949
+ return h("div", { class: "mrd-layout-section__prose", innerHTML: String(value) });
2950
+ case ClientLayoutItemFieldDataType.LONGTEXT:
2951
+ return h("pre", { class: "mrd-layout-section__pre" }, String(value));
2952
+ case ClientLayoutItemFieldDataType.JSON:
2953
+ return h("pre", { class: "mrd-layout-section__pre", innerHTML: CellRenderer.formatJson(value) });
2954
+ case ClientLayoutItemFieldDataType.FILE: {
2955
+ const v = value;
2956
+ const fileName = (_e = v === null || v === void 0 ? void 0 : v.fileName) !== null && _e !== void 0 ? _e : String(value);
2957
+ const href = (_f = v === null || v === void 0 ? void 0 : v.href) !== null && _f !== void 0 ? _f : '';
2958
+ return downloadLink(ctx, href, fileName, t('download', ctx.locale));
2959
+ }
2960
+ case ClientLayoutItemFieldDataType.IMAGE: {
2961
+ const v = value;
2962
+ const href = (_g = v === null || v === void 0 ? void 0 : v.href) !== null && _g !== void 0 ? _g : '';
2963
+ const fileName = (_h = v === null || v === void 0 ? void 0 : v.fileName) !== null && _h !== void 0 ? _h : '';
2964
+ const previewUrl = ctx.imagePreviews[item.name];
2965
+ if (previewUrl) {
2966
+ return (h("button", { class: "mrd-layout-section__image-thumb-btn", onClick: () => ctx.on.openImage(previewUrl), title: fileName || undefined }, h("img", { class: "mrd-layout-section__image-thumb", src: previewUrl, alt: fileName })));
2967
+ }
2968
+ return downloadLink(ctx, href, fileName, fileName || href);
2969
+ }
2970
+ case ClientLayoutItemFieldDataType.BOOLEAN:
2971
+ return (h("span", { class: `mrd-layout-section__boolean mrd-layout-section__boolean--${value ? 'true' : 'false'}` }, value ? t('yes', ctx.locale) : t('no', ctx.locale)));
2972
+ case ClientLayoutItemFieldDataType.LIST: {
2973
+ const listItem = ((_j = item.listItems) !== null && _j !== void 0 ? _j : []).find(li => li.key === String(value));
2974
+ const label = (_k = listItem === null || listItem === void 0 ? void 0 : listItem.label) !== null && _k !== void 0 ? _k : String(value);
2975
+ const color = listItem === null || listItem === void 0 ? void 0 : listItem.color;
2976
+ const bg = listItem === null || listItem === void 0 ? void 0 : listItem.backgroundColor;
2977
+ if (color && bg) {
2978
+ return (h("span", { class: "mrd-layout-section__badge", style: { color, backgroundColor: bg } }, label));
2979
+ }
2980
+ if (color) {
2981
+ return (h("span", { class: "mrd-layout-section__badge-dot-row" }, h("span", { class: "mrd-layout-section__badge-dot", style: { backgroundColor: color } }), label));
2982
+ }
2983
+ return label;
2984
+ }
2985
+ case ClientLayoutItemFieldDataType.SECRET:
2986
+ return value ? h("span", { class: "mrd-layout-section__secret-masked" }, '••••••••') : null;
2987
+ default: {
2988
+ const text = CellRenderer.renderValue(dt, value, (_l = item.listItems) !== null && _l !== void 0 ? _l : [], ctx.locale);
2989
+ return text || null;
2990
+ }
2991
+ }
2992
+ }
2993
+ function renderFieldValue(ctx, item, rawValue) {
2994
+ if (rawValue == null || rawValue === '')
2995
+ return null;
2996
+ if (item.multiple && Array.isArray(rawValue)) {
2997
+ const rendered = rawValue.map(v => renderSingleFieldValue(ctx, item, v));
2998
+ if (rendered.every(r => typeof r === 'string' || r == null)) {
2999
+ return rendered.filter(Boolean).join(', ') || null;
3000
+ }
3001
+ return (h("span", null, rendered.map((r, i) => (h("span", { key: String(i) }, r, i < rendered.length - 1 ? ', ' : '')))));
3002
+ }
3003
+ return renderSingleFieldValue(ctx, item, rawValue);
3004
+ }
3005
+ function renderHistoryBadge(ctx, item, raw) {
3006
+ var _a, _b, _c;
3007
+ const hist = (_a = item.historyEnabled) !== null && _a !== void 0 ? _a : (_b = item.field) === null || _b === void 0 ? void 0 : _b.historyEnabled;
3008
+ if (!hist || !item.name)
3009
+ return null;
3010
+ const history = (_c = raw === null || raw === void 0 ? void 0 : raw.history) !== null && _c !== void 0 ? _c : [];
3011
+ if (!history.length)
3012
+ return null;
3013
+ const sorted = [...history].sort((a, b) => b.until.localeCompare(a.until));
3014
+ const isOpen = ctx.openHistoryField === item.name;
3015
+ return (h("span", { class: "mrd-layout-section__history-wrap" }, h("button", { type: "button", class: "mrd-layout-section__history-btn", title: t('history_badge_tooltip', ctx.locale), "aria-label": t('history_badge_tooltip', ctx.locale), onClick: (e) => {
3016
+ e.stopPropagation();
3017
+ ctx.on.toggleHistory(isOpen ? null : item.name);
3018
+ } }, 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', ctx.locale), " ", formatDate(entry.until, ctx.locale), ")")))))));
3019
+ }
3020
+ function renderField(ctx, item) {
3021
+ var _a, _b;
3022
+ if (!item.name)
3023
+ return null;
3024
+ const raw = ctx.data[item.name];
3025
+ const hist = (_a = item.historyEnabled) !== null && _a !== void 0 ? _a : (_b = item.field) === null || _b === void 0 ? void 0 : _b.historyEnabled;
3026
+ const rawValue = hist && raw !== null && typeof raw === 'object' && 'current' in raw
3027
+ ? raw.current
3028
+ : raw;
3029
+ const renderedValue = renderFieldValue(ctx, item, rawValue);
3030
+ if (item.header) {
3031
+ return (h("h1", { class: "mrd-layout-section__field-header", key: item.name }, typeof renderedValue === 'string' ? renderedValue : rawValue != null ? String(rawValue) : item.label));
3032
+ }
3033
+ if (renderedValue == null)
3034
+ return null;
3035
+ const isBlock = item.dataType === ClientLayoutItemFieldDataType.TEXTBLOCK
3036
+ || item.dataType === ClientLayoutItemFieldDataType.LONGTEXT
3037
+ || item.dataType === ClientLayoutItemFieldDataType.JSON;
3038
+ 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, renderHistoryBadge(ctx, item, raw))));
3039
+ }
3040
+
3041
+ const mrdLayoutSectionCss = () => `.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(15 * 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-xs);font-weight:var(--mrd-font-weight-semibold);color:var(--mrd-color-neutral-500);margin:0 0 var(--mrd-space-2) 0;padding-bottom:0;letter-spacing:0.01em}.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:var(--mrd-color-white);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:var(--mrd-color-white);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}`;
2769
3042
 
2770
3043
  const MrdLayoutSection = class {
2771
3044
  constructor(hostRef) {
@@ -2847,14 +3120,8 @@ const MrdLayoutSection = class {
2847
3120
  }
2848
3121
  }
2849
3122
  }
2850
- viewKeyFor(item) {
2851
- var _a, _b, _c, _d;
2852
- if (item.type === ClientLayoutItemType.RELATED_VIEW)
2853
- return (_b = (_a = item.relatedClass) !== null && _a !== void 0 ? _a : item.name) !== null && _b !== void 0 ? _b : '';
2854
- return (_d = (_c = item.dataClass) !== null && _c !== void 0 ? _c : item.name) !== null && _d !== void 0 ? _d : '';
2855
- }
2856
3123
  emitLoadImages() {
2857
- for (const item of this.flattenItems(this.items)) {
3124
+ for (const item of flattenItems(this.items)) {
2858
3125
  if (item.type === ClientLayoutItemType.FIELD && item.dataType === ClientLayoutItemFieldDataType.IMAGE) {
2859
3126
  const fieldName = item.name;
2860
3127
  const raw = this.data[fieldName];
@@ -2864,15 +3131,6 @@ const MrdLayoutSection = class {
2864
3131
  }
2865
3132
  }
2866
3133
  }
2867
- flattenItems(items) {
2868
- const result = [];
2869
- for (const item of items) {
2870
- result.push(item);
2871
- if (item.items)
2872
- result.push(...this.flattenItems(item.items));
2873
- }
2874
- return result;
2875
- }
2876
3134
  /** Inject search results. Pass dataClass to target a specific SEARCH item; omit when there is only one. */
2877
3135
  async setSearchResults(results, dataClass) {
2878
3136
  const key = dataClass !== null && dataClass !== void 0 ? dataClass : this.resolveSearchKey();
@@ -2938,113 +3196,26 @@ const MrdLayoutSection = class {
2938
3196
  }
2939
3197
  resolveSearchKey() {
2940
3198
  var _a;
2941
- const items = this.flattenItems(this.items).filter(i => i.type === ClientLayoutItemType.SEARCH);
3199
+ const items = flattenItems(this.items).filter(i => i.type === ClientLayoutItemType.SEARCH);
2942
3200
  if (items.length === 1)
2943
3201
  return (_a = items[0].dataClass) !== null && _a !== void 0 ? _a : null;
2944
- return null;
2945
- }
2946
- renderSingleFieldValue(item, value) {
2947
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
2948
- const dt = item.dataType;
2949
- switch (dt) {
2950
- case ClientLayoutItemFieldDataType.HYPERLINK: {
2951
- const v = value;
2952
- const href = (_a = v === null || v === void 0 ? void 0 : v.href) !== null && _a !== void 0 ? _a : String(value);
2953
- 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;
2954
- return (h("a", { class: "mrd-layout-section__link", href: href, target: "_blank", rel: "noopener noreferrer" }, label));
2955
- }
2956
- case ClientLayoutItemFieldDataType.TEXTBLOCK:
2957
- return h("div", { class: "mrd-layout-section__prose", innerHTML: String(value) });
2958
- case ClientLayoutItemFieldDataType.LONGTEXT:
2959
- return h("pre", { class: "mrd-layout-section__pre" }, String(value));
2960
- case ClientLayoutItemFieldDataType.JSON:
2961
- return h("pre", { class: "mrd-layout-section__pre", innerHTML: CellRenderer.formatJson(value) });
2962
- case ClientLayoutItemFieldDataType.FILE: {
2963
- const v = value;
2964
- const fileName = (_e = v === null || v === void 0 ? void 0 : v.fileName) !== null && _e !== void 0 ? _e : String(value);
2965
- const href = (_f = v === null || v === void 0 ? void 0 : v.href) !== null && _f !== void 0 ? _f : '';
2966
- 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)));
2967
- }
2968
- case ClientLayoutItemFieldDataType.IMAGE: {
2969
- const v = value;
2970
- const href = (_g = v === null || v === void 0 ? void 0 : v.href) !== null && _g !== void 0 ? _g : '';
2971
- const fileName = (_h = v === null || v === void 0 ? void 0 : v.fileName) !== null && _h !== void 0 ? _h : '';
2972
- const previewUrl = this.imagePreviews[item.name];
2973
- if (previewUrl) {
2974
- 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 })));
2975
- }
2976
- 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));
2977
- }
2978
- case ClientLayoutItemFieldDataType.BOOLEAN:
2979
- return (h("span", { class: `mrd-layout-section__boolean mrd-layout-section__boolean--${value ? 'true' : 'false'}` }, value ? t('yes', this.locale) : t('no', this.locale)));
2980
- case ClientLayoutItemFieldDataType.LIST: {
2981
- const listItem = ((_j = item.listItems) !== null && _j !== void 0 ? _j : []).find(li => li.key === String(value));
2982
- const label = (_k = listItem === null || listItem === void 0 ? void 0 : listItem.label) !== null && _k !== void 0 ? _k : String(value);
2983
- const color = listItem === null || listItem === void 0 ? void 0 : listItem.color;
2984
- const bg = listItem === null || listItem === void 0 ? void 0 : listItem.backgroundColor;
2985
- if (color && bg) {
2986
- return (h("span", { class: "mrd-layout-section__badge", style: { color, backgroundColor: bg } }, label));
2987
- }
2988
- if (color) {
2989
- return (h("span", { class: "mrd-layout-section__badge-dot-row" }, h("span", { class: "mrd-layout-section__badge-dot", style: { backgroundColor: color } }), label));
2990
- }
2991
- return label;
2992
- }
2993
- case ClientLayoutItemFieldDataType.SECRET:
2994
- return value ? h("span", { class: "mrd-layout-section__secret-masked" }, '••••••••') : null;
2995
- default: {
2996
- const text = CellRenderer.renderValue(dt, value, (_l = item.listItems) !== null && _l !== void 0 ? _l : [], this.locale);
2997
- return text || null;
2998
- }
2999
- }
3000
- }
3001
- renderFieldValue(item, rawValue) {
3002
- if (rawValue == null || rawValue === '')
3003
- return null;
3004
- if (item.multiple && Array.isArray(rawValue)) {
3005
- const rendered = rawValue.map(v => this.renderSingleFieldValue(item, v));
3006
- if (rendered.every(r => typeof r === 'string' || r == null)) {
3007
- return rendered.filter(Boolean).join(', ') || null;
3008
- }
3009
- return (h("span", null, rendered.map((r, i) => (h("span", { key: String(i) }, r, i < rendered.length - 1 ? ', ' : '')))));
3010
- }
3011
- return this.renderSingleFieldValue(item, rawValue);
3202
+ return null;
3012
3203
  }
3013
- renderHistoryBadge(item, raw) {
3014
- var _a, _b, _c;
3015
- const hist = (_a = item.historyEnabled) !== null && _a !== void 0 ? _a : (_b = item.field) === null || _b === void 0 ? void 0 : _b.historyEnabled;
3016
- if (!hist || !item.name)
3017
- return null;
3018
- const history = (_c = raw === null || raw === void 0 ? void 0 : raw.history) !== null && _c !== void 0 ? _c : [];
3019
- if (!history.length)
3020
- return null;
3021
- const sorted = [...history].sort((a, b) => b.until.localeCompare(a.until));
3022
- const isOpen = this.openHistoryField === item.name;
3023
- const { locale } = this;
3024
- 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) => {
3025
- e.stopPropagation();
3026
- this.openHistoryField = isOpen ? null : item.name;
3027
- } }, 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), ")")))))));
3204
+ fieldCtx() {
3205
+ return {
3206
+ locale: this.locale,
3207
+ data: this.data,
3208
+ imagePreviews: this.imagePreviews,
3209
+ openHistoryField: this.openHistoryField,
3210
+ on: {
3211
+ download: detail => this.mrdDownload.emit(detail),
3212
+ openImage: url => { this.imagePreviewUrl = url; },
3213
+ toggleHistory: fieldName => { this.openHistoryField = fieldName; },
3214
+ },
3215
+ };
3028
3216
  }
3029
3217
  renderField(item) {
3030
- var _a, _b;
3031
- if (!item.name)
3032
- return null;
3033
- const raw = this.data[item.name];
3034
- const hist = (_a = item.historyEnabled) !== null && _a !== void 0 ? _a : (_b = item.field) === null || _b === void 0 ? void 0 : _b.historyEnabled;
3035
- const rawValue = hist && raw !== null && typeof raw === 'object' && 'current' in raw
3036
- ? raw.current
3037
- : raw;
3038
- const renderedValue = this.renderFieldValue(item, rawValue);
3039
- if (item.header) {
3040
- return (h("h1", { class: "mrd-layout-section__field-header", key: item.name }, typeof renderedValue === 'string' ? renderedValue : rawValue != null ? String(rawValue) : item.label));
3041
- }
3042
- if (renderedValue == null)
3043
- return null;
3044
- const isBlock = item.dataType === ClientLayoutItemFieldDataType.TEXTBLOCK
3045
- || item.dataType === ClientLayoutItemFieldDataType.LONGTEXT
3046
- || item.dataType === ClientLayoutItemFieldDataType.JSON;
3047
- 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))));
3218
+ return renderField(this.fieldCtx(), item);
3048
3219
  }
3049
3220
  renderRelation(item) {
3050
3221
  var _a, _b, _c;
@@ -3077,7 +3248,7 @@ const MrdLayoutSection = class {
3077
3248
  }
3078
3249
  renderRelatedView(item) {
3079
3250
  var _a, _b, _c, _d, _e, _f, _g, _h;
3080
- const key = this.viewKeyFor(item);
3251
+ const key = viewKeyFor(item);
3081
3252
  if (!key)
3082
3253
  return null;
3083
3254
  if (!item.view)
@@ -3089,15 +3260,19 @@ const MrdLayoutSection = class {
3089
3260
  // The API publishes `archetypes` on the VIEW/RELATED_VIEW item itself
3090
3261
  // (sibling of `view`), not inside `view`.
3091
3262
  const docArchetype = resolveArchetype((_g = item.archetypes) !== null && _g !== void 0 ? _g : (_h = item.view) === null || _h === void 0 ? void 0 : _h.archetypes, ARCHETYPE_DOCUMENT);
3263
+ // Canonical parent href for single-container seeding: use the RELATED_VIEW's
3264
+ // fromClass (base class) rather than the route class, so polymorphic subtypes
3265
+ // resolve to the same container the documents actually reference.
3266
+ const containerHref = buildContainerHref(item, selfHref, parentId);
3092
3267
  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), docArchetype
3093
- ? this.renderDocumentContainer(item, key, parentId, docArchetype)
3268
+ ? this.renderDocumentContainer(item, key, parentId, docArchetype, containerHref)
3094
3269
  : this.renderTable(item, key, parentId)));
3095
3270
  }
3096
3271
  /** Document collection view: owns the view-switch + collection actions and
3097
3272
  * swaps between the folder tree and the flat table. Events are re-emitted to
3098
3273
  * the host with the view key, exactly as the raw list/table events were. */
3099
- renderDocumentContainer(item, key, parentId, archetype) {
3100
- return (h("mrd-document-container", { item: item, archetype: archetype, parentId: parentId, viewKey: key, locale: this.locale, onMrdLoadDistinct: (e) => {
3274
+ renderDocumentContainer(item, key, parentId, archetype, containerHref) {
3275
+ return (h("mrd-document-container", { item: item, archetype: archetype, parentId: parentId, containerHref: containerHref, viewKey: key, locale: this.locale, onMrdLoadDistinct: (e) => {
3101
3276
  e.stopPropagation();
3102
3277
  this.mrdLoadViewDistinct.emit(Object.assign({ name: key }, e.detail));
3103
3278
  }, onMrdLoadPage: (e) => {
@@ -3193,7 +3368,7 @@ const MrdLayoutSection = class {
3193
3368
  }
3194
3369
  render() {
3195
3370
  const docArchetype = resolveArchetype(this.archetypes, ARCHETYPE_DOCUMENT);
3196
- return (h(Host, { key: '6e737354daec0137b6ebe304efcce9990f02739f' }, h("div", { key: '31a73a8a78999793f5dacee5f2da41df5f23156e', class: "mrd-layout-section" }, docArchetype
3371
+ return (h(Host, { key: '5d778188356a25ea13d45745dc5ed573ab2b2ef0' }, h("div", { key: '0b673a4bcf8b36cd21662bb8a3506cc3f30edb04', class: "mrd-layout-section" }, docArchetype
3197
3372
  ? this.renderDocumentObject(docArchetype)
3198
3373
  : this.items.map(item => this.renderItem(item))), this.renderImageModal()));
3199
3374
  }
@@ -3204,9 +3379,9 @@ const MrdLayoutSection = class {
3204
3379
  }]
3205
3380
  }; }
3206
3381
  };
3207
- MrdLayoutSection.style = mrdLayoutSectionScss();
3382
+ MrdLayoutSection.style = mrdLayoutSectionCss();
3208
3383
 
3209
- 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)}`;
3384
+ const mrdListFieldCss = () => `.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);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-list-field__select.sc-mrd-list-field::placeholder{color:var(--mrd-input-placeholder-color)}.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__select.sc-mrd-list-field{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;padding-right:calc(var(--mrd-input-padding-x) + 1.5rem);cursor:pointer}.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)}.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}`;
3210
3385
 
3211
3386
  const MrdListField = class {
3212
3387
  constructor(hostRef) {
@@ -3229,22 +3404,12 @@ const MrdListField = class {
3229
3404
  if (this.multiple) {
3230
3405
  const vals = Array.from(select.selectedOptions).map(o => o.value);
3231
3406
  this.selected = vals;
3232
- if (this.required && !validateRequired(vals)) {
3233
- this.error = t('required', this.locale);
3234
- }
3235
- else {
3236
- this.error = '';
3237
- }
3407
+ this.error = requiredError(vals, this.required, this.locale);
3238
3408
  this.mrdChange.emit({ name: this.name, value: vals });
3239
3409
  }
3240
3410
  else {
3241
3411
  const val = select.value;
3242
- if (this.required && !validateRequired(val)) {
3243
- this.error = t('required', this.locale);
3244
- }
3245
- else {
3246
- this.error = '';
3247
- }
3412
+ this.error = requiredError(val, this.required, this.locale);
3248
3413
  this.mrdChange.emit({ name: this.name, value: val });
3249
3414
  }
3250
3415
  };
@@ -3259,12 +3424,7 @@ const MrdListField = class {
3259
3424
  else {
3260
3425
  this.selected = [...this.selected, key];
3261
3426
  }
3262
- if (this.required && !validateRequired(this.selected)) {
3263
- this.error = t('required', this.locale);
3264
- }
3265
- else {
3266
- this.error = '';
3267
- }
3427
+ this.error = requiredError(this.selected, this.required, this.locale);
3268
3428
  this.mrdChange.emit({ name: this.name, value: this.selected });
3269
3429
  };
3270
3430
  }
@@ -3288,22 +3448,22 @@ const MrdListField = class {
3288
3448
  const hasError = !!this.error;
3289
3449
  const currentValue = Array.isArray(this.value) ? ((_a = this.value[0]) !== null && _a !== void 0 ? _a : '') : ((_b = this.value) !== null && _b !== void 0 ? _b : '');
3290
3450
  if (this.multiple) {
3291
- 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 => {
3451
+ return (h(Host, null, h("div", { class: "mrd-list-field" }, h(FieldLabel, { base: "mrd-list-field", label: this.label, required: this.required }), h("div", { class: controlClass('mrd-list-field', hasError, 'checkbox-list') }, this.listItems.map(lv => {
3292
3452
  var _a, _b;
3293
3453
  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)));
3294
- })), hasError && h("span", { class: "mrd-list-field__error" }, this.error))));
3454
+ })), h(FieldError, { base: "mrd-list-field", error: this.error }))));
3295
3455
  }
3296
- 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 => {
3456
+ return (h(Host, null, h("div", { class: "mrd-list-field" }, h(FieldLabel, { base: "mrd-list-field", label: this.label, required: this.required }), h("select", { class: controlClass('mrd-list-field', hasError, 'select'), 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 => {
3297
3457
  var _a, _b;
3298
3458
  const bg = (_b = (_a = lv.backgroundColor) !== null && _a !== void 0 ? _a : lv.color) !== null && _b !== void 0 ? _b : null;
3299
3459
  const style = bg ? { backgroundColor: bg, color: this.getContrastColor(bg) } : {};
3300
3460
  return (h("option", { key: lv.key, value: lv.key, selected: lv.key === currentValue, style: style }, lv.label));
3301
- })), hasError && h("span", { class: "mrd-list-field__error" }, this.error))));
3461
+ })), h(FieldError, { base: "mrd-list-field", error: this.error }))));
3302
3462
  }
3303
3463
  };
3304
- MrdListField.style = mrdListFieldScss();
3464
+ MrdListField.style = mrdListFieldCss();
3305
3465
 
3306
- 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)}`;
3466
+ const mrdLongtextFieldCss = () => `.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%;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-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.sc-mrd-longtext-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.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__error.sc-mrd-longtext-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}.mrd-longtext-field__input.sc-mrd-longtext-field{height:auto;min-height:calc(var(--mrd-input-height) * 5);resize:vertical;line-height:1.5}.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}`;
3307
3467
 
3308
3468
  const MrdLongtextField = class {
3309
3469
  constructor(hostRef) {
@@ -3324,23 +3484,17 @@ const MrdLongtextField = class {
3324
3484
  };
3325
3485
  this.handleBlur = (e) => {
3326
3486
  const val = e.target.value;
3327
- if (this.required && !validateRequired(val)) {
3328
- this.error = t('required', this.locale);
3329
- }
3330
- else {
3331
- this.error = '';
3332
- }
3487
+ this.error = requiredError(val, this.required, this.locale);
3333
3488
  this.mrdBlur.emit({ name: this.name, value: val });
3334
3489
  };
3335
3490
  }
3336
3491
  render() {
3337
- const hasError = !!this.error;
3338
- return (h(Host, { key: 'f00f81944748f8f09e22d44befe5e288456b7cc8' }, h("div", { key: '7b0ae9cf5b6b684cddb648fe4db6005494322535', class: "mrd-longtext-field" }, this.label && (h("label", { key: '3fc6a8710d0e98fe685c45d214a88ae1b0947973', 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: 'e96f1dbc6c00a1602f4ce3c97d514a229aeb7cb7', class: "mrd-longtext-field__error" }, this.error))));
3492
+ return (h(Host, { key: '1d23db1324fa0fc97a07fdae65f2d84e43419a72' }, h("div", { key: '0ad2b262088aa3745f088a44af26649593805840', class: "mrd-longtext-field" }, h(FieldLabel, { key: '5a78739d6ced4e2df77589b64c66401819c4b5c7', base: "mrd-longtext-field", label: this.label, required: this.required }), this.disabled ? (h("pre", { class: "mrd-longtext-field__content" }, this.value)) : (h("textarea", { class: controlClass('mrd-longtext-field', !!this.error), name: this.name, placeholder: this.placeholder, required: this.required, rows: 10, onInput: this.handleInput, onBlur: this.handleBlur }, this.value)), h(FieldError, { key: '5b870a75b518e2808518b83c9abebf8589a86108', base: "mrd-longtext-field", error: this.error }))));
3339
3493
  }
3340
3494
  };
3341
- MrdLongtextField.style = mrdLongtextFieldScss();
3495
+ MrdLongtextField.style = mrdLongtextFieldCss();
3342
3496
 
3343
- 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)}`;
3497
+ const mrdNumberFieldCss = () => `.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}.mrd-number-field__input.sc-mrd-number-field::placeholder{color:var(--mrd-input-placeholder-color)}.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__input.sc-mrd-number-field{text-align:right}.mrd-number-field__input.sc-mrd-number-field::placeholder{text-align:left}.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)}`;
3344
3498
 
3345
3499
  const MrdNumberField = class {
3346
3500
  constructor(hostRef) {
@@ -3411,12 +3565,12 @@ const MrdNumberField = class {
3411
3565
  const hasError = !!this.error;
3412
3566
  const suffix = this.dataType === ClientLayoutItemFieldDataType.PERCENTAGE ? '%' :
3413
3567
  this.dataType === ClientLayoutItemFieldDataType.DECIMAL ? '' : '';
3414
- return (h(Host, { key: 'b034a3cc8d841641c0ec167e138904586b044121' }, h("div", { key: '7379bfadb8bd0c4e0a945a37013053a4e22477ab', class: "mrd-number-field" }, this.label && (h("label", { key: '5518d40b7158e17704633c2b95ac7e3efc0c5568', class: `mrd-number-field__label${this.required ? ' mrd-number-field__label--required' : ''}` }, this.label)), h("div", { key: '38ad9f3c945d66c23bd77c743306e916eaefed7f', class: "mrd-number-field__input-wrapper" }, h("input", { key: 'ac8b4bc1ea4431cc9306664522ebfda21760ae83', 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: '09f5a58b769c81acdf4bdd48f9325934c4bb875d', class: "mrd-number-field__error" }, this.error))));
3568
+ return (h(Host, { key: 'fd7220e0a7f574ab0c61094a9ba7fd764e1adafd' }, h("div", { key: 'ef6118a339c9766f187cd2b1fa3fcc85ef8cb69f', class: "mrd-number-field" }, h(FieldLabel, { key: '015207ae65df07f7ee7bbc24ccab45524176dbf7', base: "mrd-number-field", label: this.label, required: this.required }), h("div", { key: '954b99cbcf4002b0336810e354f1a46d39cb8076', class: "mrd-number-field__input-wrapper" }, h("input", { key: 'dddc08e090b200736d186960db1436e44f42703c', class: controlClass('mrd-number-field', hasError), 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 })), h(FieldError, { key: '87e12bd737aed0a845470cef66d7a6d61d11de0b', base: "mrd-number-field", error: this.error }))));
3415
3569
  }
3416
3570
  };
3417
- MrdNumberField.style = mrdNumberFieldScss();
3571
+ MrdNumberField.style = mrdNumberFieldCss();
3418
3572
 
3419
- 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)}`;
3573
+ const mrdRelationFieldCss = () => `.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);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-relation-field__select.sc-mrd-relation-field::placeholder{color:var(--mrd-input-placeholder-color)}.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__select.sc-mrd-relation-field{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;padding-right:calc(var(--mrd-input-padding-x) + 1.5rem);cursor:pointer}.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);transition:border-color var(--mrd-transition), box-shadow var(--mrd-transition);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__error.sc-mrd-relation-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}.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__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}`;
3420
3574
 
3421
3575
  const MrdRelationField = class {
3422
3576
  constructor(hostRef) {
@@ -3517,12 +3671,7 @@ const MrdRelationField = class {
3517
3671
  this.showResults = false;
3518
3672
  this.mrdChange.emit({ name: this.name, value: result.id });
3519
3673
  }
3520
- if (this.required && !validateRequired(this.selectedItems)) {
3521
- this.error = t('required', this.locale);
3522
- }
3523
- else {
3524
- this.error = '';
3525
- }
3674
+ this.error = requiredError(this.selectedItems, this.required, this.locale);
3526
3675
  };
3527
3676
  this.handleRemoveSelected = (id) => {
3528
3677
  this.selectedItems = this.selectedItems.filter(i => i.id !== id);
@@ -3531,12 +3680,7 @@ const MrdRelationField = class {
3531
3680
  };
3532
3681
  this.handleDropdownChange = (e) => {
3533
3682
  const val = e.target.value;
3534
- if (this.required && !validateRequired(val)) {
3535
- this.error = t('required', this.locale);
3536
- }
3537
- else {
3538
- this.error = '';
3539
- }
3683
+ this.error = requiredError(val, this.required, this.locale);
3540
3684
  this.mrdChange.emit({ name: this.name, value: val });
3541
3685
  };
3542
3686
  this.handleBlur = () => {
@@ -3647,19 +3791,19 @@ const MrdRelationField = class {
3647
3791
  const hasError = !!this.error;
3648
3792
  if (this.editBehavior === ClientLayoutItemRelationEditBehavior.DROPDOWN) {
3649
3793
  const currentValue = this.getValueHref();
3650
- 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))));
3794
+ return (h(Host, null, h("div", { class: "mrd-relation-field" }, h(FieldLabel, { base: "mrd-relation-field", label: this.label, required: this.required }), h("select", { class: controlClass('mrd-relation-field', hasError, 'select'), 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)))), h(FieldError, { base: "mrd-relation-field", error: this.error }))));
3651
3795
  }
3652
3796
  if (this.displayType === ClientLayoutItemRelationDisplayType.DROPDOWN) {
3653
3797
  const currentValue = Array.isArray(this.value) ? ((_a = this.value[0]) !== null && _a !== void 0 ? _a : '') : ((_b = this.value) !== null && _b !== void 0 ? _b : '');
3654
- 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))));
3798
+ return (h(Host, null, h("div", { class: "mrd-relation-field" }, h(FieldLabel, { base: "mrd-relation-field", label: this.label, required: this.required }), h("select", { class: controlClass('mrd-relation-field', hasError, 'select'), 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)))), h(FieldError, { base: "mrd-relation-field", error: this.error }))));
3655
3799
  }
3656
3800
  // SEARCH mode
3657
- const labelEl = this.label && (h("label", { class: `mrd-relation-field__label${this.required ? ' mrd-relation-field__label--required' : ''}` }, this.label));
3801
+ const labelEl = h(FieldLabel, { base: "mrd-relation-field", label: this.label, required: this.required });
3658
3802
  // Single selection: show selected value as a badge, hide the search input
3659
3803
  if (!this.multiple && this.selectedItems.length > 0) {
3660
- 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))));
3804
+ 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")), h(FieldError, { base: "mrd-relation-field", error: this.error }))));
3661
3805
  }
3662
- 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))));
3806
+ 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)))))))), h(FieldError, { base: "mrd-relation-field", error: this.error }))));
3663
3807
  }
3664
3808
  get el() { return getElement(this); }
3665
3809
  static get watchers() { return {
@@ -3671,9 +3815,9 @@ const MrdRelationField = class {
3671
3815
  }]
3672
3816
  }; }
3673
3817
  };
3674
- MrdRelationField.style = mrdRelationFieldScss();
3818
+ MrdRelationField.style = mrdRelationFieldCss();
3675
3819
 
3676
- 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}`;
3820
+ const mrdSecretFieldCss = () => `.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.sc-mrd-secret-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.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}`;
3677
3821
 
3678
3822
  const MrdSecretField = class {
3679
3823
  constructor(hostRef) {
@@ -3694,38 +3838,439 @@ const MrdSecretField = class {
3694
3838
  };
3695
3839
  this.handleBlur = (e) => {
3696
3840
  const val = e.target.value;
3697
- if (this.required && !validateRequired(val)) {
3698
- this.error = t('required', this.locale);
3699
- }
3700
- else {
3701
- this.error = '';
3702
- }
3841
+ this.error = requiredError(val, this.required, this.locale);
3703
3842
  this.mrdBlur.emit({ name: this.name, value: val });
3704
3843
  };
3705
3844
  }
3706
3845
  render() {
3707
- const hasError = !!this.error;
3708
- return (h(Host, { key: 'c850ec5bc5967ca0aefca7d7cb65ecae121a9dc1' }, h("div", { key: '3249ffbc441422af054a20806dd8dfce954a8ffc', class: "mrd-secret-field" }, this.label && (h("label", { key: '0b4a86da9cafad32f153af1bc5487a4e9b941e2f', class: `mrd-secret-field__label${this.required ? ' mrd-secret-field__label--required' : ''}` }, this.label)), this.disabled
3846
+ return (h(Host, { key: 'acb865b235652feba713aedda7a7fccbdc01ad20' }, h("div", { key: 'e7471ade9c683cac9469ec89778c967badb046f9', class: "mrd-secret-field" }, h(FieldLabel, { key: '2f9b864779ead352fda53af8597ddcd31377249d', base: "mrd-secret-field", label: this.label, required: this.required }), this.disabled
3709
3847
  ? (h("span", { class: "mrd-secret-field__masked", "aria-label": this.label }, this.value ? '••••••••' : ''))
3710
- : (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: 'b0d0105f3d43d2e214f070b24e745dbce0e33977', class: "mrd-secret-field__error" }, this.error))));
3848
+ : (h("input", { class: controlClass('mrd-secret-field', !!this.error), type: "password", name: this.name, value: this.value, placeholder: this.placeholder, required: this.required, autocomplete: "new-password", onInput: this.handleInput, onBlur: this.handleBlur })), h(FieldError, { key: '438418e2cf0f53a6c247d5f332aae8e8978b94ea', base: "mrd-secret-field", error: this.error }))));
3711
3849
  }
3712
3850
  };
3713
- MrdSecretField.style = mrdSecretFieldScss();
3714
-
3715
- 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}`;
3851
+ MrdSecretField.style = mrdSecretFieldCss();
3716
3852
 
3717
- const BUFFER = 10;
3718
- /** Wacht deze tijd (ms) na het laatste scroll-event voordat pagina's worden
3719
- * aangevraagd. Pagina's die de gebruiker snel voorbij scrollt worden zo geskipt. */
3720
- const REQUEST_DEBOUNCE_MS = 150;
3721
- /** Breedte van de filterpopup in px — voor overflow-correctie. */
3722
- const POPUP_WIDTH = 280;
3853
+ /**
3854
+ * Pure sort/filter/aggregation query logic for mrd-table.
3855
+ * No component state everything is passed in.
3856
+ */
3723
3857
  const TEXT_TYPES = new Set(['TEXT', 'TEXTBLOCK', 'EMAIL', 'HYPERLINK']);
3724
3858
  const NUMERIC_TYPES = new Set(['INTEGER', 'DECIMAL', 'PERCENTAGE', 'CURRENCY']);
3725
3859
  const DATE_TYPES = new Set(['DATE', 'DATETIME', 'TIME']);
3726
3860
  const NO_FILTER_TYPES = new Set(['FILE', 'IMAGE']);
3727
3861
  /** Column types that cannot be sorted or filtered (not stored in PostgreSQL). */
3728
3862
  const NON_INTERACTIVE_TYPES = new Set(['LONGTEXT', 'JSON', 'FILE', 'IMAGE']);
3863
+ function parseDefaultSort(defaultSort) {
3864
+ var _a;
3865
+ if (!defaultSort)
3866
+ return { field: '', dir: 'asc' };
3867
+ const parts = defaultSort.split(',');
3868
+ return { field: parts[0].trim(), dir: ((_a = parts[1]) === null || _a === void 0 ? void 0 : _a.trim()) === 'desc' ? 'desc' : 'asc' };
3869
+ }
3870
+ /** Raw sort query-param value, e.g. "name" or "name,desc". */
3871
+ function buildSortParam(field, dir) {
3872
+ if (!field)
3873
+ return '';
3874
+ return dir === 'desc' ? `${field},desc` : field;
3875
+ }
3876
+ /** Query params for a page request: page + sort + filterClass + view filters + active column filters. */
3877
+ function buildTableQueryParams(opts) {
3878
+ var _a, _b;
3879
+ const p = new URLSearchParams();
3880
+ if (opts.page > 0)
3881
+ p.set('page', String(opts.page));
3882
+ if (opts.sort)
3883
+ p.set('sort', opts.sort);
3884
+ if (opts.filterClass)
3885
+ p.set('type', opts.filterClass);
3886
+ applyViewFilters(p, opts.viewFilters);
3887
+ for (const f of opts.activeFilters) {
3888
+ if (f.operator === 'isEmpty') {
3889
+ p.set(f.field, '');
3890
+ continue;
3891
+ }
3892
+ if (f.operator === 'isNotEmpty') {
3893
+ p.set(f.field + '_notempty', 'true');
3894
+ continue;
3895
+ }
3896
+ if (f.operator === 'startsWith') {
3897
+ p.set(f.field + '_startswith', String((_a = f.value) !== null && _a !== void 0 ? _a : ''));
3898
+ continue;
3899
+ }
3900
+ if ((_b = f.values) === null || _b === void 0 ? void 0 : _b.length) {
3901
+ p.set(f.field, f.values.join(','));
3902
+ continue;
3903
+ }
3904
+ if (f.value != null)
3905
+ p.set(f.field, String(f.value));
3906
+ if (f.from != null)
3907
+ p.set(f.field + '_from', String(f.from));
3908
+ if (f.to != null)
3909
+ p.set(f.field + '_to', String(f.to));
3910
+ }
3911
+ return p.toString();
3912
+ }
3913
+ /** Groups aggregate columns by function; null when the view has no aggregates. */
3914
+ function buildAggregationParams(columns) {
3915
+ var _a;
3916
+ const groups = { sum: [], avg: [], count: [] };
3917
+ for (const col of columns) {
3918
+ if (col.type !== 'FIELD' || !col.aggregate)
3919
+ continue;
3920
+ const fn = col.aggregate.toLowerCase();
3921
+ if (fn in groups)
3922
+ groups[fn].push((_a = col.name) !== null && _a !== void 0 ? _a : '');
3923
+ }
3924
+ const params = {};
3925
+ if (groups.sum.length)
3926
+ params.sum = groups.sum;
3927
+ if (groups.avg.length)
3928
+ params.avg = groups.avg;
3929
+ if (groups.count.length)
3930
+ params.count = groups.count;
3931
+ return Object.keys(params).length > 0 ? params : null;
3932
+ }
3933
+ /** Aggregation query string: the page-0 query params without page/sort, plus sum/avg/count. */
3934
+ function buildAggregationQs(basePageQs, columns) {
3935
+ var _a, _b, _c;
3936
+ const p = new URLSearchParams(basePageQs);
3937
+ p.delete('page');
3938
+ p.delete('sort');
3939
+ const groups = buildAggregationParams(columns);
3940
+ if ((_a = groups === null || groups === void 0 ? void 0 : groups.sum) === null || _a === void 0 ? void 0 : _a.length)
3941
+ p.set('sum', groups.sum.join(','));
3942
+ if ((_b = groups === null || groups === void 0 ? void 0 : groups.avg) === null || _b === void 0 ? void 0 : _b.length)
3943
+ p.set('avg', groups.avg.join(','));
3944
+ if ((_c = groups === null || groups === void 0 ? void 0 : groups.count) === null || _c === void 0 ? void 0 : _c.length)
3945
+ p.set('count', groups.count.join(','));
3946
+ return p.toString();
3947
+ }
3948
+ /** True when the pending filter actually constrains anything. */
3949
+ function filterHasValue(f) {
3950
+ if (f.operator === 'isEmpty' || f.operator === 'isNotEmpty')
3951
+ return true;
3952
+ if (f.values !== undefined && f.values.length > 0)
3953
+ return true;
3954
+ if (f.value != null && f.value !== '')
3955
+ return true;
3956
+ if (typeof f.value === 'boolean')
3957
+ return true;
3958
+ if (f.from != null && f.from !== '')
3959
+ return true;
3960
+ if (f.to != null && f.to !== '')
3961
+ return true;
3962
+ return false;
3963
+ }
3964
+ // ── DATETIME filters: the user edits local "YYYY-MM-DD" dates, the API stores UTC ISO ──
3965
+ /** UTC ISO string at the start (midnight) of the given local day. */
3966
+ function dateLocalToUTCStart(dateStr) {
3967
+ if (!dateStr)
3968
+ return dateStr;
3969
+ const [year, month, day] = dateStr.split('-').map(Number);
3970
+ return new Date(year, month - 1, day).toISOString().replace(/\.\d{3}Z$/, 'Z');
3971
+ }
3972
+ /** Start of the day AFTER the given local date (exclusive range end). */
3973
+ function dateLocalToUTCEndExclusive(dateStr) {
3974
+ if (!dateStr)
3975
+ return dateStr;
3976
+ const [year, month, day] = dateStr.split('-').map(Number);
3977
+ return new Date(year, month - 1, day + 1).toISOString().replace(/\.\d{3}Z$/, 'Z');
3978
+ }
3979
+ /** Stored UTC ISO string back to the local "YYYY-MM-DD" date. */
3980
+ function utcISOToLocalDate(utcStr) {
3981
+ if (!utcStr)
3982
+ return utcStr;
3983
+ const d = new Date(utcStr);
3984
+ if (isNaN(d.getTime()))
3985
+ return utcStr;
3986
+ return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
3987
+ }
3988
+ /** The stored "to" is the exclusive end (next midnight); subtract a day to recover the entered date. */
3989
+ function utcISOToLocalDateExclusiveEnd(utcStr) {
3990
+ if (!utcStr)
3991
+ return utcStr;
3992
+ const d = new Date(utcStr);
3993
+ if (isNaN(d.getTime()))
3994
+ return utcStr;
3995
+ d.setDate(d.getDate() - 1);
3996
+ return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
3997
+ }
3998
+ /** Applies the local→UTC conversion when a DATETIME filter is submitted.
3999
+ * Exact date → range covering the full local day. */
4000
+ function normalizeDatetimeFilter(f) {
4001
+ const normalized = Object.assign({}, f);
4002
+ if (f.dataType === 'DATETIME' && f.operator !== 'isEmpty' && f.operator !== 'isNotEmpty') {
4003
+ if (typeof normalized.value === 'string' && normalized.value) {
4004
+ normalized.from = dateLocalToUTCStart(normalized.value);
4005
+ normalized.to = dateLocalToUTCEndExclusive(normalized.value);
4006
+ normalized.value = undefined;
4007
+ }
4008
+ else {
4009
+ if (typeof normalized.from === 'string' && normalized.from)
4010
+ normalized.from = dateLocalToUTCStart(normalized.from);
4011
+ if (typeof normalized.to === 'string' && normalized.to)
4012
+ normalized.to = dateLocalToUTCEndExclusive(normalized.to);
4013
+ }
4014
+ }
4015
+ return normalized;
4016
+ }
4017
+ /** Converts a stored DATETIME filter back to local dates for the popup.
4018
+ * A range covering a single local day is restored to exact-date mode. */
4019
+ function datetimeFilterToDisplay(existing) {
4020
+ const display = Object.assign({}, existing);
4021
+ if (typeof display.from === 'string' && display.from)
4022
+ display.from = utcISOToLocalDate(display.from);
4023
+ if (typeof display.to === 'string' && display.to)
4024
+ display.to = utcISOToLocalDateExclusiveEnd(display.to);
4025
+ if (display.from && display.to && display.from === display.to) {
4026
+ return Object.assign(Object.assign({}, display), { value: display.from, from: undefined, to: undefined });
4027
+ }
4028
+ return display;
4029
+ }
4030
+
4031
+ /**
4032
+ * Stateless render parts of mrd-table. All state and handlers stay in the
4033
+ * component; these components receive plain values and callbacks.
4034
+ */
4035
+ const FilterIcon = () => (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" }))));
4036
+ const TEXTBLOCK_MAX = 200;
4037
+ const TableCell = ({ col, row, locale, onDownload, onOpenTextblock, onOpenJson }) => {
4038
+ var _a, _b, _c;
4039
+ const dataType = (_a = col.dataType) !== null && _a !== void 0 ? _a : '';
4040
+ const isNumeric = col.type === 'FIELD' && NUMERIC_TYPES.has(dataType);
4041
+ const isFile = col.type === 'FIELD' && (dataType === 'FILE' || dataType === 'IMAGE');
4042
+ if (isFile) {
4043
+ const name = (_b = col.name) !== null && _b !== void 0 ? _b : '';
4044
+ const fileVal = row === null || row === void 0 ? void 0 : row[name];
4045
+ const href = fileVal === null || fileVal === void 0 ? void 0 : fileVal.href;
4046
+ const fileName = fileVal === null || fileVal === void 0 ? void 0 : fileVal.fileName;
4047
+ return (h("td", { class: "mrd-table__cell" }, href && fileName ? (h("button", { class: "mrd-table__file-btn", title: fileName, onClick: (e) => {
4048
+ e.stopPropagation();
4049
+ onDownload({ href, fileName });
4050
+ } }, 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', locale))) : ''));
4051
+ }
4052
+ if (dataType === 'JSON') {
4053
+ const name = (_c = col.name) !== null && _c !== void 0 ? _c : '';
4054
+ const rawValue = name ? row === null || row === void 0 ? void 0 : row[name] : undefined;
4055
+ if (rawValue == null || rawValue === '')
4056
+ return h("td", { class: "mrd-table__cell" });
4057
+ const compactHtml = CellRenderer.formatJson(rawValue, true);
4058
+ const prettyHtml = CellRenderer.formatJson(rawValue, false);
4059
+ 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(); onOpenJson(prettyHtml); }, "aria-label": t('textblock_show_more', locale) }, "\u22EF")));
4060
+ }
4061
+ if (dataType === 'TEXTBLOCK') {
4062
+ const full = CellRenderer.render(col, row, locale);
4063
+ if (full.length <= TEXTBLOCK_MAX) {
4064
+ return h("td", { class: "mrd-table__cell" }, full);
4065
+ }
4066
+ const preview = full.slice(0, TEXTBLOCK_MAX) + '…';
4067
+ return (h("td", { class: "mrd-table__cell" }, preview, h("button", { class: "mrd-table__textblock-btn", onClick: (e) => { e.stopPropagation(); onOpenTextblock(full); }, "aria-label": t('textblock_show_more', locale) }, "\u22EF")));
4068
+ }
4069
+ const value = CellRenderer.render(col, row, locale);
4070
+ return (h("td", { class: `mrd-table__cell${isNumeric ? ' mrd-table__cell--numeric' : ''}` }, value));
4071
+ };
4072
+ /** Formats the aggregation total for one column, '' when not applicable. */
4073
+ function formatAggregationValue(col, aggregations, locale) {
4074
+ var _a;
4075
+ if (col.type !== 'FIELD' || !col.aggregate || !aggregations)
4076
+ return '';
4077
+ const fn = col.aggregate.toLowerCase();
4078
+ const aggData = aggregations[fn];
4079
+ const val = typeof aggData === 'object' && aggData !== null
4080
+ ? aggData[(_a = col.name) !== null && _a !== void 0 ? _a : '']
4081
+ : undefined;
4082
+ if (val == null)
4083
+ return '';
4084
+ const dt = col.dataType;
4085
+ if (dt === 'INTEGER')
4086
+ return formatNumber(val, locale, { maximumFractionDigits: 0 });
4087
+ if (dt === 'PERCENTAGE')
4088
+ return formatPercentage(val, locale);
4089
+ if (dt === 'CURRENCY' && col.currencyCode)
4090
+ return formatCurrency(val, col.currencyCode, locale);
4091
+ return formatNumber(val, locale);
4092
+ }
4093
+ const TotalsRow = ({ columns, aggregations, locale }) => {
4094
+ if (!aggregations)
4095
+ return null;
4096
+ if (!columns.some(c => c.type === 'FIELD' && c.aggregate))
4097
+ return null;
4098
+ return (h("tfoot", null, h("tr", { class: "mrd-table__totals-row" }, columns.map(col => {
4099
+ var _a;
4100
+ const val = formatAggregationValue(col, aggregations, locale);
4101
+ const isNumeric = col.type === 'FIELD' && NUMERIC_TYPES.has((_a = col.dataType) !== null && _a !== void 0 ? _a : '');
4102
+ return (h("td", { class: `mrd-table__totals-cell${isNumeric ? ' mrd-table__totals-cell--numeric' : ''}` }, val));
4103
+ }))));
4104
+ };
4105
+ const TextblockModal = ({ text, locale, onClose }) => {
4106
+ if (text === null)
4107
+ return null;
4108
+ return (h("div", { class: "mrd-table__modal-backdrop", onClick: onClose, role: "dialog", "aria-modal": "true" }, h("div", { class: "mrd-table__modal", onClick: (e) => e.stopPropagation() }, h("button", { class: "mrd-table__modal-close", onClick: onClose, "aria-label": t('close', locale) }, "\u2715"), h("p", { class: "mrd-table__modal-text" }, text))));
4109
+ };
4110
+ const JsonModal = ({ html, locale, onClose }) => {
4111
+ if (html === null)
4112
+ return null;
4113
+ return (h("div", { class: "mrd-table__modal-backdrop", onClick: onClose, role: "dialog", "aria-modal": "true" }, h("div", { class: "mrd-table__modal", onClick: (e) => e.stopPropagation() }, h("button", { class: "mrd-table__modal-close", onClick: onClose, "aria-label": t('close', locale) }, "\u2715"), h("pre", { class: "mrd-table__modal-json", innerHTML: html }))));
4114
+ };
4115
+ const Toolbar = ({ locale, filterMode, filterCount, actions, views, activeViewIdx, viewPopoverOpen, createPickerOpen, createTypes, cb }) => {
4116
+ var _a;
4117
+ const hasActions = actions.length > 0;
4118
+ const hasViewSwitcher = views.length > 1;
4119
+ 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${filterMode ? ' mrd-table__filter-toggle--active' : ''}`, onClick: cb.onFilterToggle }, 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" }, filterMode ? t('table_filter_hide', locale) : t('table_filter', locale), filterCount > 0 ? ` (${filterCount} ${t('table_filter_active', locale)})` : '')), filterCount > 0 && (h("button", { class: "mrd-table__action mrd-table__action--secondary", onClick: cb.onClearAllFilters }, 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', 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: () => cb.onViewSwitch((activeViewIdx - 1 + views.length) % views.length) }, "\u25C0"), h("div", { class: "mrd-table__view-title-wrap" }, h("button", { class: "mrd-table__view-title", onClick: (e) => cb.onToggleViewPopover(e) }, (_a = views[activeViewIdx]) === null || _a === void 0 ? void 0 : _a.label), viewPopoverOpen && (h("div", { class: "mrd-table__view-popover", onClick: (e) => e.stopPropagation() }, views.map((v, i) => (h("button", { key: String(i), class: `mrd-table__view-popover-item${i === activeViewIdx ? ' mrd-table__view-popover-item--active' : ''}`, onClick: () => {
4120
+ if (i !== activeViewIdx)
4121
+ cb.onViewSwitch(i);
4122
+ cb.onCloseViewPopover();
4123
+ } }, v.label)))))), h("button", { class: "mrd-table__view-arrow", "aria-label": "Next view", onClick: () => cb.onViewSwitch((activeViewIdx + 1) % views.length) }, "\u25B6")))), hasActions && (h("div", { class: "mrd-table__toolbar-right" }, actions.map(a => {
4124
+ var _a, _b;
4125
+ const pickerTypes = a.action === 'create' ? createTypes : null;
4126
+ if (pickerTypes === null || pickerTypes === void 0 ? void 0 : pickerTypes.length) {
4127
+ return (h("div", { class: "mrd-table__create-picker-wrap", key: `action-${a.action}` }, h("button", { class: `mrd-table__action mrd-table__action--${(_a = a.variant) !== null && _a !== void 0 ? _a : 'secondary'}`, onClick: cb.onToggleCreatePicker }, a.icon
4128
+ ? h("svg", { class: "mrd-table__action-icon", "aria-hidden": "true" }, h("use", { href: a.icon }))
4129
+ : a.label, h("span", { class: "mrd-table__action-tooltip" }, a.label)), createPickerOpen && (h("div", { class: "mrd-table__create-picker" }, pickerTypes.map(ct => (h("button", { key: ct.type, class: "mrd-table__create-picker-item", onClick: () => cb.onCreate(ct.type) }, ct.label)))))));
4130
+ }
4131
+ return (h("button", { key: `action-${a.action}`, class: `mrd-table__action mrd-table__action--${(_b = a.variant) !== null && _b !== void 0 ? _b : 'secondary'}`, disabled: a.disabled, onClick: () => cb.onAction(a.action) }, a.icon
4132
+ ? h("svg", { class: "mrd-table__action-icon", "aria-hidden": "true" }, h("use", { href: a.icon }))
4133
+ : a.label, h("span", { class: "mrd-table__action-tooltip" }, a.label)));
4134
+ })))));
4135
+ };
4136
+
4137
+ const FilterEditor = ({ col, dataType, openFilterCol, pendingFilter, locale, cb }) => {
4138
+ var _a, _b, _c, _d, _e, _f;
4139
+ const pf = pendingFilter;
4140
+ if (NO_FILTER_TYPES.has(dataType)) {
4141
+ return h("p", { class: "mrd-table__filter-no-support" }, t('filter_no_support', locale));
4142
+ }
4143
+ if (dataType === 'BOOLEAN') {
4144
+ const boolOp = pf.operator;
4145
+ const noValueOp = boolOp === 'isEmpty' || boolOp === 'isNotEmpty';
4146
+ return (h("div", { class: "mrd-table__filter-radio-group" }, [
4147
+ { labelKey: 'filter_all', value: null },
4148
+ { labelKey: 'yes', value: true },
4149
+ { labelKey: 'no', value: false },
4150
+ ].map(opt => (h("label", { class: "mrd-table__filter-radio-label" }, h("input", { type: "radio", name: `bf-${openFilterCol}`, checked: !noValueOp && pf.value === opt.value, onChange: () => cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: undefined, value: opt.value })) }), t(opt.labelKey, locale)))), h("label", { class: "mrd-table__filter-radio-label" }, h("input", { type: "radio", name: `bf-${openFilterCol}`, checked: boolOp === 'isEmpty', onChange: () => cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: 'isEmpty', value: undefined })) }), t('filter_is_empty', locale)), h("label", { class: "mrd-table__filter-radio-label" }, h("input", { type: "radio", name: `bf-${openFilterCol}`, checked: boolOp === 'isNotEmpty', onChange: () => cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: 'isNotEmpty', value: undefined })) }), t('filter_is_not_empty', locale))));
4151
+ }
4152
+ if (dataType === 'LIST') {
4153
+ const items = (_a = col.listItems) !== null && _a !== void 0 ? _a : [];
4154
+ const selected = (_b = pf.values) !== null && _b !== void 0 ? _b : [];
4155
+ 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: () => cb.onReplacePending(Object.assign(Object.assign({}, pf), { values: items.map(i => i.key) })) }, t('filter_select_all', locale)), h("button", { class: "mrd-table__filter-list-btn", onClick: () => cb.onReplacePending(Object.assign(Object.assign({}, pf), { values: [] })) }, t('filter_select_none', locale))), items.map(item => (h("label", { class: "mrd-table__filter-checkbox-label" }, h("input", { type: "checkbox", checked: selected.includes(item.key), onChange: (e) => cb.onToggleValue(item.key, e.target.checked) }), item.label)))));
4156
+ }
4157
+ if (TEXT_TYPES.has(dataType) || dataType === 'RELATION') {
4158
+ const op = (_c = pf.operator) !== null && _c !== void 0 ? _c : 'startsWith';
4159
+ const noInput = op === 'isEmpty' || op === 'isNotEmpty';
4160
+ return (h("div", { class: "mrd-table__filter-editor" }, h("select", { class: "mrd-table__filter-select", onChange: (e) => cb.onSetPending('operator', e.target.value) }, [
4161
+ { val: 'startsWith', labelKey: 'filter_starts_with' },
4162
+ { val: 'equals', labelKey: 'filter_equals' },
4163
+ { val: 'isEmpty', labelKey: 'filter_is_empty' },
4164
+ { val: 'isNotEmpty', labelKey: 'filter_is_not_empty' },
4165
+ ].map(o => h("option", { value: o.val, selected: op === o.val }, t(o.labelKey, locale)))), !noInput && (h("input", { type: "text", class: "mrd-table__filter-input", value: String((_d = pf.value) !== null && _d !== void 0 ? _d : ''), placeholder: t('filter_search_value', locale), onInput: (e) => cb.onSetPending('value', e.target.value) }))));
4166
+ }
4167
+ if (NUMERIC_TYPES.has(dataType)) {
4168
+ const numOp = pf.operator;
4169
+ const noInput = numOp === 'isEmpty' || numOp === 'isNotEmpty';
4170
+ const rangeMode = !noInput && (pf.from !== undefined || pf.to !== undefined);
4171
+ return (h("div", { class: "mrd-table__filter-editor" }, h("select", { class: "mrd-table__filter-select", onChange: (e) => {
4172
+ const val = e.target.value;
4173
+ if (val === 'isEmpty' || val === 'isNotEmpty') {
4174
+ cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: val, value: undefined, from: undefined, to: undefined }));
4175
+ }
4176
+ else {
4177
+ cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: undefined }));
4178
+ }
4179
+ } }, h("option", { value: "", selected: !noInput }, t('filter_has_value', locale)), h("option", { value: "isEmpty", selected: numOp === 'isEmpty' }, t('filter_is_empty', locale)), h("option", { value: "isNotEmpty", selected: numOp === 'isNotEmpty' }, t('filter_is_not_empty', 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-${openFilterCol}`, checked: !rangeMode, onChange: () => cb.onReplacePending(Object.assign(Object.assign({}, pf), { from: undefined, to: undefined })) }), t('filter_exact', locale)), h("label", { class: "mrd-table__filter-radio-label" }, h("input", { type: "radio", name: `nm-${openFilterCol}`, checked: rangeMode, onChange: () => cb.onReplacePending(Object.assign(Object.assign({}, pf), { value: undefined, from: null, to: null })) }), t('filter_range', locale))), !rangeMode ? (h("input", { type: "number", class: "mrd-table__filter-input", value: pf.value != null ? String(pf.value) : '', onInput: (e) => cb.onSetPending('value', e.target.value) })) : (h("div", { class: "mrd-table__filter-range" }, h("input", { type: "number", class: "mrd-table__filter-input", placeholder: t('filter_from', locale), value: pf.from != null ? String(pf.from) : '', onInput: (e) => cb.onSetPending('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', locale), value: pf.to != null ? String(pf.to) : '', onInput: (e) => cb.onSetPending('to', e.target.value) })))))));
4180
+ }
4181
+ if (dataType === 'DATETIME') {
4182
+ const dtOp = pf.operator;
4183
+ const noInput = dtOp === 'isEmpty' || dtOp === 'isNotEmpty';
4184
+ const rangeMode = !noInput && (pf.from !== undefined || pf.to !== undefined);
4185
+ return (h("div", { class: "mrd-table__filter-editor" }, h("select", { class: "mrd-table__filter-select", onChange: (e) => {
4186
+ const val = e.target.value;
4187
+ if (val === 'isEmpty' || val === 'isNotEmpty') {
4188
+ cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: val, value: undefined, from: undefined, to: undefined }));
4189
+ }
4190
+ else {
4191
+ cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: undefined }));
4192
+ }
4193
+ } }, h("option", { value: "", selected: !noInput }, t('filter_has_value', locale)), h("option", { value: "isEmpty", selected: dtOp === 'isEmpty' }, t('filter_is_empty', locale)), h("option", { value: "isNotEmpty", selected: dtOp === 'isNotEmpty' }, t('filter_is_not_empty', 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-${openFilterCol}`, checked: !rangeMode, onChange: () => cb.onReplacePending(Object.assign(Object.assign({}, pf), { from: undefined, to: undefined })) }), t('filter_exact', locale)), h("label", { class: "mrd-table__filter-radio-label" }, h("input", { type: "radio", name: `dt-${openFilterCol}`, checked: rangeMode, onChange: () => cb.onReplacePending(Object.assign(Object.assign({}, pf), { value: undefined, from: null, to: null })) }), t('filter_range', locale))), !rangeMode ? (h("input", { type: "date", class: "mrd-table__filter-input", value: String((_e = pf.value) !== null && _e !== void 0 ? _e : ''), onInput: (e) => cb.onSetPending('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', locale)), h("input", { type: "date", class: "mrd-table__filter-input", value: pf.from != null ? String(pf.from) : '', onInput: (e) => cb.onSetPending('from', e.target.value) }), h("label", { class: "mrd-table__filter-range-label" }, t('filter_to', locale)), h("input", { type: "date", class: "mrd-table__filter-input", value: pf.to != null ? String(pf.to) : '', onInput: (e) => cb.onSetPending('to', e.target.value) })))))));
4194
+ }
4195
+ if (DATE_TYPES.has(dataType)) {
4196
+ const inputType = dataType === 'DATE' ? 'date' : 'time';
4197
+ const dtdOp = pf.operator;
4198
+ const noInput = dtdOp === 'isEmpty' || dtdOp === 'isNotEmpty';
4199
+ const rangeMode = !noInput && (pf.from !== undefined || pf.to !== undefined);
4200
+ return (h("div", { class: "mrd-table__filter-editor" }, h("select", { class: "mrd-table__filter-select", onChange: (e) => {
4201
+ const val = e.target.value;
4202
+ if (val === 'isEmpty' || val === 'isNotEmpty') {
4203
+ cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: val, value: undefined, from: undefined, to: undefined }));
4204
+ }
4205
+ else {
4206
+ cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: undefined }));
4207
+ }
4208
+ } }, h("option", { value: "", selected: !noInput }, t('filter_has_value', locale)), h("option", { value: "isEmpty", selected: dtdOp === 'isEmpty' }, t('filter_is_empty', locale)), h("option", { value: "isNotEmpty", selected: dtdOp === 'isNotEmpty' }, t('filter_is_not_empty', 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-${openFilterCol}`, checked: !rangeMode, onChange: () => cb.onReplacePending(Object.assign(Object.assign({}, pf), { from: undefined, to: undefined })) }), t('filter_exact', locale)), h("label", { class: "mrd-table__filter-radio-label" }, h("input", { type: "radio", name: `dt-${openFilterCol}`, checked: rangeMode, onChange: () => cb.onReplacePending(Object.assign(Object.assign({}, pf), { value: undefined, from: null, to: null })) }), t('filter_range', locale))), !rangeMode ? (h("input", { type: inputType, class: "mrd-table__filter-input", value: String((_f = pf.value) !== null && _f !== void 0 ? _f : ''), onInput: (e) => cb.onSetPending('value', e.target.value) })) : (h("div", { class: "mrd-table__filter-range" }, h("input", { type: inputType, class: "mrd-table__filter-input", placeholder: t('filter_from', locale), value: pf.from != null ? String(pf.from) : '', onInput: (e) => cb.onSetPending('from', e.target.value) }), h("input", { type: inputType, class: "mrd-table__filter-input", placeholder: t('filter_to', locale), value: pf.to != null ? String(pf.to) : '', onInput: (e) => cb.onSetPending('to', e.target.value) })))))));
4209
+ }
4210
+ return null;
4211
+ };
4212
+ const FilterPopup = (props) => {
4213
+ var _a;
4214
+ const { col, openFilterCol, popupPos, sortField, sortDir, locale, cb } = props;
4215
+ const label = (_a = col.label) !== null && _a !== void 0 ? _a : openFilterCol;
4216
+ const sortActive = sortField === openFilterCol;
4217
+ return (h("div", { class: "mrd-table__filter-popup", style: { top: `${popupPos.top}px`, left: `${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: cb.onClose }, "\u2715")), h("div", { class: "mrd-table__filter-section" }, h("div", { class: "mrd-table__filter-section-label" }, t('filter_sorting', locale)), h("div", { class: "mrd-table__filter-sort-buttons" }, h("button", { class: `mrd-table__filter-sort-btn${sortActive && sortDir === 'asc' ? ' mrd-table__filter-sort-btn--active' : ''}`, onClick: () => cb.onApplySort('asc') }, "\u25B2 ", t('filter_ascending', locale)), h("button", { class: `mrd-table__filter-sort-btn${sortActive && sortDir === 'desc' ? ' mrd-table__filter-sort-btn--active' : ''}`, onClick: () => cb.onApplySort('desc') }, "\u25BC ", t('filter_descending', 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', locale)), h(FilterEditor, Object.assign({}, props))), h("div", { class: "mrd-table__filter-popup-footer" }, h("button", { class: "mrd-table__filter-btn mrd-table__filter-btn--clear", onClick: cb.onClear }, t('filter_clear', locale)), h("button", { class: "mrd-table__filter-btn mrd-table__filter-btn--apply", onClick: cb.onApply }, t('filter_apply', locale)))));
4218
+ };
4219
+
4220
+ /**
4221
+ * Pure window/paging maths for the mrd-table virtual scroll.
4222
+ * The window state itself stays @State in the component; these
4223
+ * functions only compute values from it.
4224
+ */
4225
+ const BUFFER = 10;
4226
+ /** Wait this long (ms) after the last scroll event before requesting pages,
4227
+ * so pages the user quickly scrolls past are skipped. */
4228
+ const REQUEST_DEBOUNCE_MS = 150;
4229
+ function visibleCount(tableHeight, rowHeight) {
4230
+ return Math.ceil(tableHeight / rowHeight);
4231
+ }
4232
+ /** Render window (with buffer) for the given scroll offset. */
4233
+ function computeWindow(scrollTop, rowHeight, tableHeight, total) {
4234
+ const visStart = Math.floor(scrollTop / rowHeight);
4235
+ const visEnd = Math.min(visStart + visibleCount(tableHeight, rowHeight), total - 1);
4236
+ return {
4237
+ renderStart: Math.max(0, visStart - BUFFER),
4238
+ renderEnd: Math.min(total - 1, visEnd + BUFFER),
4239
+ };
4240
+ }
4241
+ /** First/last page (0-based) covering the given row window. */
4242
+ function pageRange(start, end, pageSize) {
4243
+ return { firstPage: Math.floor(start / pageSize), lastPage: Math.floor(end / pageSize) };
4244
+ }
4245
+ function getRowFromPages(pages, index, pageSize) {
4246
+ var _a;
4247
+ const page = pages.get(Math.floor(index / pageSize));
4248
+ return (_a = page === null || page === void 0 ? void 0 : page[index % pageSize]) !== null && _a !== void 0 ? _a : null;
4249
+ }
4250
+ /** Authoritative row count: a page shorter than pageSize is the last page,
4251
+ * so the true total cannot exceed its end index. */
4252
+ function computeEffectiveTotal(loadedPages, pageSize, baseTotal) {
4253
+ let effectiveTotal = baseTotal;
4254
+ for (const [pageNum, pageRows] of loadedPages) {
4255
+ if (pageRows.length < pageSize) {
4256
+ effectiveTotal = Math.min(effectiveTotal, pageNum * pageSize + pageRows.length);
4257
+ }
4258
+ }
4259
+ return effectiveTotal;
4260
+ }
4261
+ /** True when some loaded page was short — the exact total is then known. */
4262
+ function isTotalKnownFromPages(loadedPages, pageSize) {
4263
+ for (const rows of loadedPages.values()) {
4264
+ if (rows.length < pageSize)
4265
+ return true;
4266
+ }
4267
+ return false;
4268
+ }
4269
+
4270
+ const mrdTableCss = () => `@charset "UTF-8";.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, 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, 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}`;
4271
+
4272
+ /** Breedte van de filterpopup in px — voor overflow-correctie. */
4273
+ const POPUP_WIDTH = 280;
3729
4274
  const MrdTable = class {
3730
4275
  constructor(hostRef) {
3731
4276
  registerInstance(this, hostRef);
@@ -3741,6 +4286,8 @@ const MrdTable = class {
3741
4286
  this.keydownHandler = null;
3742
4287
  this.createPickerClickHandler = null;
3743
4288
  this.viewPopoverClickHandler = null;
4289
+ /** Guards against scheduling more than one column-width measurement per freeze. */
4290
+ this.colWidthMeasureScheduled = false;
3744
4291
  // ── Props ──────────────────────────────────────────────────────────────────
3745
4292
  /** The VIEW or RELATED_VIEW layout item. Contains view config, dataClass, fromClass, actions etc. */
3746
4293
  this.item = null;
@@ -3797,13 +4344,10 @@ const MrdTable = class {
3797
4344
  this.minKnownTotal = 0;
3798
4345
  this.handleScroll = (e) => {
3799
4346
  const scroller = e.currentTarget;
3800
- const scrollTop = scroller.scrollTop;
3801
- const total = this.baseTotal;
3802
- const visStart = Math.floor(scrollTop / this.rowHeight);
3803
- const visEnd = Math.min(visStart + this.visibleCount(), total - 1);
3804
- this.scrollTop = scrollTop;
3805
- this.renderStart = Math.max(0, visStart - BUFFER);
3806
- this.renderEnd = Math.min(total - 1, visEnd + BUFFER);
4347
+ const { renderStart, renderEnd } = computeWindow(scroller.scrollTop, this.rowHeight, this.tableHeight, this.baseTotal);
4348
+ this.scrollTop = scroller.scrollTop;
4349
+ this.renderStart = renderStart;
4350
+ this.renderEnd = renderEnd;
3807
4351
  this.requestPagesForWindow(this.renderStart, this.renderEnd);
3808
4352
  };
3809
4353
  }
@@ -3825,16 +4369,9 @@ const MrdTable = class {
3825
4369
  }
3826
4370
  // ── Helpers ────────────────────────────────────────────────────────────────
3827
4371
  applyDefaultSort(defaultSort) {
3828
- var _a;
3829
- if (defaultSort) {
3830
- const parts = defaultSort.split(',');
3831
- this.sortField = parts[0].trim();
3832
- this.sortDir = ((_a = parts[1]) === null || _a === void 0 ? void 0 : _a.trim()) === 'desc' ? 'desc' : 'asc';
3833
- }
3834
- else {
3835
- this.sortField = '';
3836
- this.sortDir = 'asc';
3837
- }
4372
+ const { field, dir } = parseDefaultSort(defaultSort);
4373
+ this.sortField = field;
4374
+ this.sortDir = dir;
3838
4375
  }
3839
4376
  // ── Public API ─────────────────────────────────────────────────────────────
3840
4377
  /**
@@ -3851,6 +4388,7 @@ const MrdTable = class {
3851
4388
  this.loadedPages = new Map();
3852
4389
  this.requestedPages = new Set();
3853
4390
  this.colWidths = [];
4391
+ this.colWidthMeasureScheduled = false;
3854
4392
  this.scrollTop = 0;
3855
4393
  this.renderStart = 0;
3856
4394
  // Always fill the visible viewport on init — totalElements may be stale from a
@@ -3931,21 +4469,34 @@ const MrdTable = class {
3931
4469
  }
3932
4470
  }
3933
4471
  componentDidRender() {
3934
- if (this.colWidths.length === 0 && this.loadedPages.size > 0 && this.totalElements > 0) {
3935
- const ths = this.el.querySelectorAll('.mrd-table__header');
3936
- if (ths.length > 0) {
3937
- this.colWidths = Array.from(ths).map(th => th.offsetWidth);
3938
- }
4472
+ // Freeze header widths once the first data page has rendered. The measurement
4473
+ // reads offsetWidth and writes the colWidths @State, which would trigger a
4474
+ // re-render *during* the render cycle if done synchronously here. Defer it to a
4475
+ // writeTask so the state mutation happens outside the render pass (avoids the
4476
+ // Stencil "state/prop changed during rendering" warning and potential loops).
4477
+ if (this.colWidths.length === 0 &&
4478
+ !this.colWidthMeasureScheduled &&
4479
+ this.loadedPages.size > 0 &&
4480
+ this.totalElements > 0) {
4481
+ this.colWidthMeasureScheduled = true;
4482
+ writeTask(() => {
4483
+ this.colWidthMeasureScheduled = false;
4484
+ // Re-check: state may have changed (e.g. a reset) between scheduling and running.
4485
+ if (this.colWidths.length !== 0)
4486
+ return;
4487
+ const ths = this.el.querySelectorAll('.mrd-table__header');
4488
+ if (ths.length > 0) {
4489
+ this.colWidths = Array.from(ths).map(th => th.offsetWidth);
4490
+ }
4491
+ });
3939
4492
  }
3940
4493
  }
3941
4494
  // ── Paging / scroll helpers ────────────────────────────────────────────────
3942
4495
  visibleCount() {
3943
- return Math.ceil(this.tableHeight / this.rowHeight);
4496
+ return visibleCount(this.tableHeight, this.rowHeight);
3944
4497
  }
3945
4498
  sortParam() {
3946
- if (!this.sortField)
3947
- return '';
3948
- return this.sortDir === 'desc' ? `${this.sortField},desc` : this.sortField;
4499
+ return buildSortParam(this.sortField, this.sortDir);
3949
4500
  }
3950
4501
  /** Stable ordered list: primary view first, then alternatives (from the item prop). */
3951
4502
  get allViews() {
@@ -3971,14 +4522,16 @@ const MrdTable = class {
3971
4522
  * VIEW: /excel/{dataClass}
3972
4523
  * RELATED_VIEW: /excel/{fromClass}/{parentId}/{dataClass} */
3973
4524
  buildExcelPath() {
3974
- var _a, _b, _c, _d;
4525
+ var _a;
3975
4526
  const v = this.allViews[this.activeViewIdx];
3976
4527
  if (!v)
3977
4528
  return '';
3978
- if (((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === 'RELATED_VIEW') {
3979
- return `/excel/${(_b = v.fromClass) !== null && _b !== void 0 ? _b : ''}/${this.parentId}/${(_c = v.dataClass) !== null && _c !== void 0 ? _c : ''}`;
3980
- }
3981
- return `/excel/${(_d = v.dataClass) !== null && _d !== void 0 ? _d : ''}`;
4529
+ return '/excel' + buildListPath({
4530
+ isRelatedView: ((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === 'RELATED_VIEW',
4531
+ fromClass: v.fromClass,
4532
+ parentId: this.parentId,
4533
+ dataClass: v.dataClass,
4534
+ });
3982
4535
  }
3983
4536
  buildActionDetail(action, basicType) {
3984
4537
  var _a, _b, _c;
@@ -3998,80 +4551,28 @@ const MrdTable = class {
3998
4551
  * VIEW: /{dataClass}
3999
4552
  * RELATED_VIEW: /{fromClass}/{parentId}/{dataClass} */
4000
4553
  buildDataPath() {
4001
- var _a, _b, _c, _d;
4554
+ var _a;
4002
4555
  const v = this.allViews[this.activeViewIdx];
4003
4556
  if (!v)
4004
4557
  return '';
4005
- if (((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === 'RELATED_VIEW') {
4006
- return `/${(_b = v.fromClass) !== null && _b !== void 0 ? _b : ''}/${this.parentId}/${(_c = v.dataClass) !== null && _c !== void 0 ? _c : ''}`;
4007
- }
4008
- return `/${(_d = v.dataClass) !== null && _d !== void 0 ? _d : ''}`;
4558
+ return buildListPath({
4559
+ isRelatedView: ((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === 'RELATED_VIEW',
4560
+ fromClass: v.fromClass,
4561
+ parentId: this.parentId,
4562
+ dataClass: v.dataClass,
4563
+ });
4009
4564
  }
4010
4565
  /** Build query params for a page request from current sort, view filters, filterClass and active column filters. */
4011
4566
  buildQueryParams(page) {
4012
- var _a, _b, _c, _d, _e, _f, _g;
4567
+ var _a;
4013
4568
  const v = this.allViews[this.activeViewIdx];
4014
- const p = new URLSearchParams();
4015
- if (page > 0)
4016
- p.set('page', String(page));
4017
- const sort = this.sortParam();
4018
- if (sort)
4019
- p.set('sort', sort);
4020
- const filterClass = v === null || v === void 0 ? void 0 : v.filterClass;
4021
- if (filterClass)
4022
- p.set('type', filterClass);
4023
- 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 : [])) {
4024
- if (!f.name)
4025
- continue;
4026
- if (f.operator === 'EMPTY') {
4027
- p.set(f.name, '');
4028
- continue;
4029
- }
4030
- if (f.operator === 'NOT_EMPTY') {
4031
- p.set(f.name + '_notempty', 'true');
4032
- continue;
4033
- }
4034
- if (f.operator === 'STARTS_WITH') {
4035
- p.set(f.name + '_startswith', String((_c = f.value) !== null && _c !== void 0 ? _c : ''));
4036
- continue;
4037
- }
4038
- if (f.operator === 'FROM') {
4039
- p.set(f.name + '_from', String((_d = f.value) !== null && _d !== void 0 ? _d : ''));
4040
- continue;
4041
- }
4042
- if (f.operator === 'TO') {
4043
- p.set(f.name + '_to', String((_e = f.value) !== null && _e !== void 0 ? _e : ''));
4044
- continue;
4045
- }
4046
- if (f.value != null) {
4047
- p.set(f.name, String(f.value));
4048
- }
4049
- }
4050
- for (const f of this.activeFilters.values()) {
4051
- if (f.operator === 'isEmpty') {
4052
- p.set(f.field, '');
4053
- continue;
4054
- }
4055
- if (f.operator === 'isNotEmpty') {
4056
- p.set(f.field + '_notempty', 'true');
4057
- continue;
4058
- }
4059
- if (f.operator === 'startsWith') {
4060
- p.set(f.field + '_startswith', String((_f = f.value) !== null && _f !== void 0 ? _f : ''));
4061
- continue;
4062
- }
4063
- if ((_g = f.values) === null || _g === void 0 ? void 0 : _g.length) {
4064
- p.set(f.field, f.values.join(','));
4065
- continue;
4066
- }
4067
- if (f.value != null)
4068
- p.set(f.field, String(f.value));
4069
- if (f.from != null)
4070
- p.set(f.field + '_from', String(f.from));
4071
- if (f.to != null)
4072
- p.set(f.field + '_to', String(f.to));
4073
- }
4074
- return p.toString();
4569
+ return buildTableQueryParams({
4570
+ page,
4571
+ sort: this.sortParam(),
4572
+ filterClass: v === null || v === void 0 ? void 0 : v.filterClass,
4573
+ viewFilters: (_a = v === null || v === void 0 ? void 0 : v.view) === null || _a === void 0 ? void 0 : _a.filter,
4574
+ activeFilters: this.activeFilters.values(),
4575
+ });
4075
4576
  }
4076
4577
  get columns() {
4077
4578
  var _a, _b, _c;
@@ -4126,11 +4627,7 @@ const MrdTable = class {
4126
4627
  isTotalKnown() {
4127
4628
  if (this.aggregationsTotal != null)
4128
4629
  return true;
4129
- for (const rows of this.loadedPages.values()) {
4130
- if (rows.length < this.pageSize)
4131
- return true;
4132
- }
4133
- return false;
4630
+ return isTotalKnownFromPages(this.loadedPages, this.pageSize);
4134
4631
  }
4135
4632
  /** Effective total: aggregations-response > totalElements prop > minKnownTotal from setPage(). */
4136
4633
  get baseTotal() {
@@ -4141,61 +4638,9 @@ const MrdTable = class {
4141
4638
  return this.minKnownTotal;
4142
4639
  }
4143
4640
  // ── Aggregation helpers ────────────────────────────────────────────────────
4144
- buildAggregationParams() {
4145
- var _a;
4146
- const groups = { sum: [], avg: [], count: [] };
4147
- for (const col of this.columns) {
4148
- if (col.type !== 'FIELD' || !col.aggregate)
4149
- continue;
4150
- const fn = col.aggregate.toLowerCase();
4151
- if (fn in groups)
4152
- groups[fn].push((_a = col.name) !== null && _a !== void 0 ? _a : '');
4153
- }
4154
- const params = {};
4155
- if (groups.sum.length)
4156
- params.sum = groups.sum;
4157
- if (groups.avg.length)
4158
- params.avg = groups.avg;
4159
- if (groups.count.length)
4160
- params.count = groups.count;
4161
- return Object.keys(params).length > 0 ? params : null;
4162
- }
4163
- buildAggregationQs() {
4164
- var _a, _b, _c;
4165
- const p = new URLSearchParams(this.buildQueryParams(0));
4166
- p.delete('page');
4167
- p.delete('sort');
4168
- const groups = this.buildAggregationParams();
4169
- if ((_a = groups === null || groups === void 0 ? void 0 : groups.sum) === null || _a === void 0 ? void 0 : _a.length)
4170
- p.set('sum', groups.sum.join(','));
4171
- if ((_b = groups === null || groups === void 0 ? void 0 : groups.avg) === null || _b === void 0 ? void 0 : _b.length)
4172
- p.set('avg', groups.avg.join(','));
4173
- if ((_c = groups === null || groups === void 0 ? void 0 : groups.count) === null || _c === void 0 ? void 0 : _c.length)
4174
- p.set('count', groups.count.join(','));
4175
- return p.toString();
4176
- }
4177
4641
  emitLoadAggregations() {
4178
- this.mrdLoadAggregations.emit({ path: this.buildDataPath(), qs: this.buildQueryParams(0), aggQs: this.buildAggregationQs() });
4179
- }
4180
- renderAggregationValue(col) {
4181
- var _a;
4182
- if (col.type !== 'FIELD' || !col.aggregate || !this.aggregations)
4183
- return '';
4184
- const fn = col.aggregate.toLowerCase();
4185
- const aggData = this.aggregations[fn];
4186
- const val = typeof aggData === 'object' && aggData !== null
4187
- ? aggData[(_a = col.name) !== null && _a !== void 0 ? _a : '']
4188
- : undefined;
4189
- if (val == null)
4190
- return '';
4191
- const dt = col.dataType;
4192
- if (dt === 'INTEGER')
4193
- return formatNumber(val, this.locale, { maximumFractionDigits: 0 });
4194
- if (dt === 'PERCENTAGE')
4195
- return formatPercentage(val, this.locale);
4196
- if (dt === 'CURRENCY' && col.currencyCode)
4197
- return formatCurrency(val, col.currencyCode, this.locale);
4198
- return formatNumber(val, this.locale);
4642
+ const qs = this.buildQueryParams(0);
4643
+ this.mrdLoadAggregations.emit({ path: this.buildDataPath(), qs, aggQs: buildAggregationQs(qs, this.columns) });
4199
4644
  }
4200
4645
  // ── Reset pagination ───────────────────────────────────────────────────────
4201
4646
  /** Reset pagination state and scroll to top (used after sort or filter change). */
@@ -4208,6 +4653,7 @@ const MrdTable = class {
4208
4653
  this.loadedPages = new Map();
4209
4654
  this.requestedPages = new Set();
4210
4655
  this.colWidths = [];
4656
+ this.colWidthMeasureScheduled = false;
4211
4657
  this.scrollTop = 0;
4212
4658
  this.renderStart = 0;
4213
4659
  this.minKnownTotal = 0;
@@ -4237,8 +4683,7 @@ const MrdTable = class {
4237
4683
  this.emitPagesForWindow(this.renderStart, this.renderEnd);
4238
4684
  }
4239
4685
  emitPagesForWindow(start, end) {
4240
- const firstPage = Math.floor(start / this.pageSize);
4241
- const lastPage = Math.floor(end / this.pageSize);
4686
+ const { firstPage, lastPage } = pageRange(start, end, this.pageSize);
4242
4687
  const next = new Set(this.requestedPages);
4243
4688
  let changed = false;
4244
4689
  for (let p = firstPage; p <= lastPage; p++) {
@@ -4252,13 +4697,10 @@ const MrdTable = class {
4252
4697
  this.requestedPages = next;
4253
4698
  }
4254
4699
  getRow(i) {
4255
- var _a;
4256
- const page = this.loadedPages.get(Math.floor(i / this.pageSize));
4257
- return (_a = page === null || page === void 0 ? void 0 : page[i % this.pageSize]) !== null && _a !== void 0 ? _a : null;
4700
+ return getRowFromPages(this.loadedPages, i, this.pageSize);
4258
4701
  }
4259
4702
  requestPagesForWindow(start, end) {
4260
- const firstPage = Math.floor(start / this.pageSize);
4261
- const lastPage = Math.floor(end / this.pageSize);
4703
+ const { firstPage, lastPage } = pageRange(start, end, this.pageSize);
4262
4704
  let anyNew = false;
4263
4705
  for (let p = firstPage; p <= lastPage; p++) {
4264
4706
  if (!this.loadedPages.has(p) && !this.requestedPages.has(p) && !this.pendingPages.has(p)) {
@@ -4320,17 +4762,7 @@ const MrdTable = class {
4320
4762
  // If from and to cover the same local day it was an exact-date filter — restore
4321
4763
  // to exact mode so the user sees the single-date input again.
4322
4764
  if (dataType === 'DATETIME' && existing && existing.operator !== 'isEmpty' && existing.operator !== 'isNotEmpty') {
4323
- const display = Object.assign({}, existing);
4324
- if (typeof display.from === 'string' && display.from)
4325
- display.from = this.utcISOToLocalDate(display.from);
4326
- if (typeof display.to === 'string' && display.to)
4327
- display.to = this.utcISOToLocalDateExclusiveEnd(display.to);
4328
- if (display.from && display.to && display.from === display.to) {
4329
- this.pendingFilter = Object.assign(Object.assign({}, display), { value: display.from, from: undefined, to: undefined });
4330
- }
4331
- else {
4332
- this.pendingFilter = display;
4333
- }
4765
+ this.pendingFilter = datetimeFilterToDisplay(existing);
4334
4766
  }
4335
4767
  else {
4336
4768
  this.pendingFilter = existing ? Object.assign({}, existing) : { field: name, dataType, operator: defaultOperator };
@@ -4396,81 +4828,15 @@ const MrdTable = class {
4396
4828
  const current = (_b = (_a = this.pendingFilter) === null || _a === void 0 ? void 0 : _a.values) !== null && _b !== void 0 ? _b : [];
4397
4829
  this.pendingFilter = Object.assign(Object.assign({}, this.pendingFilter), { values: checked ? [...current, key] : current.filter(k => k !== key) });
4398
4830
  }
4399
- filterHasValue(f) {
4400
- if (f.operator === 'isEmpty' || f.operator === 'isNotEmpty')
4401
- return true;
4402
- if (f.values !== undefined && f.values.length > 0)
4403
- return true;
4404
- if (f.value != null && f.value !== '')
4405
- return true;
4406
- if (typeof f.value === 'boolean')
4407
- return true;
4408
- if (f.from != null && f.from !== '')
4409
- return true;
4410
- if (f.to != null && f.to !== '')
4411
- return true;
4412
- return false;
4413
- }
4414
- // Convert a local "YYYY-MM-DD" date string to the UTC ISO string at the
4415
- // start of that local day (midnight). new Date(y, m, d) uses local time.
4416
- dateLocalToUTCStart(dateStr) {
4417
- if (!dateStr)
4418
- return dateStr;
4419
- const [year, month, day] = dateStr.split('-').map(Number);
4420
- return new Date(year, month - 1, day).toISOString().replace(/\.\d{3}Z$/, 'Z');
4421
- }
4422
- // Start of the day AFTER the given local date (exclusive range end).
4423
- dateLocalToUTCEndExclusive(dateStr) {
4424
- if (!dateStr)
4425
- return dateStr;
4426
- const [year, month, day] = dateStr.split('-').map(Number);
4427
- return new Date(year, month - 1, day + 1).toISOString().replace(/\.\d{3}Z$/, 'Z');
4428
- }
4429
- // Convert a stored UTC ISO string back to the local "YYYY-MM-DD" date.
4430
- utcISOToLocalDate(utcStr) {
4431
- if (!utcStr)
4432
- return utcStr;
4433
- const d = new Date(utcStr);
4434
- if (isNaN(d.getTime()))
4435
- return utcStr;
4436
- return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
4437
- }
4438
- // The stored "to" value is the exclusive end (midnight of the next day).
4439
- // Subtract one day to recover the local date the user entered.
4440
- utcISOToLocalDateExclusiveEnd(utcStr) {
4441
- if (!utcStr)
4442
- return utcStr;
4443
- const d = new Date(utcStr);
4444
- if (isNaN(d.getTime()))
4445
- return utcStr;
4446
- d.setDate(d.getDate() - 1);
4447
- return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
4448
- }
4449
4831
  applyFilter() {
4450
4832
  const f = this.pendingFilter;
4451
4833
  if (!(f === null || f === void 0 ? void 0 : f.field)) {
4452
4834
  this.closeFilterPopup();
4453
4835
  return;
4454
4836
  }
4455
- // For DATETIME fields the user enters local dates; convert to UTC ISO strings.
4456
- // Exact date → range covering the full local day (from = midnight, to = next midnight).
4457
- // "to" is always the exclusive end (midnight of the next local day).
4458
- let normalized = Object.assign({}, f);
4459
- if (f.dataType === 'DATETIME' && f.operator !== 'isEmpty' && f.operator !== 'isNotEmpty') {
4460
- if (typeof normalized.value === 'string' && normalized.value) {
4461
- normalized.from = this.dateLocalToUTCStart(normalized.value);
4462
- normalized.to = this.dateLocalToUTCEndExclusive(normalized.value);
4463
- normalized.value = undefined;
4464
- }
4465
- else {
4466
- if (typeof normalized.from === 'string' && normalized.from)
4467
- normalized.from = this.dateLocalToUTCStart(normalized.from);
4468
- if (typeof normalized.to === 'string' && normalized.to)
4469
- normalized.to = this.dateLocalToUTCEndExclusive(normalized.to);
4470
- }
4471
- }
4837
+ const normalized = normalizeDatetimeFilter(f);
4472
4838
  const next = new Map(this.activeFilters);
4473
- if (this.filterHasValue(normalized)) {
4839
+ if (filterHasValue(normalized)) {
4474
4840
  next.set(normalized.field, normalized);
4475
4841
  }
4476
4842
  else {
@@ -4525,140 +4891,53 @@ const MrdTable = class {
4525
4891
  toggleViewPopover(e) {
4526
4892
  e.stopPropagation();
4527
4893
  if (this.viewPopoverOpen) {
4528
- this.viewPopoverOpen = false;
4529
- if (this.viewPopoverClickHandler) {
4530
- document.removeEventListener('click', this.viewPopoverClickHandler);
4531
- this.viewPopoverClickHandler = null;
4532
- }
4894
+ this.closeViewPopover();
4533
4895
  return;
4534
4896
  }
4535
4897
  this.viewPopoverOpen = true;
4536
- this.viewPopoverClickHandler = () => {
4537
- this.viewPopoverOpen = false;
4898
+ this.viewPopoverClickHandler = () => this.closeViewPopover();
4899
+ document.addEventListener('click', this.viewPopoverClickHandler);
4900
+ }
4901
+ closeViewPopover() {
4902
+ this.viewPopoverOpen = false;
4903
+ if (this.viewPopoverClickHandler) {
4538
4904
  document.removeEventListener('click', this.viewPopoverClickHandler);
4539
4905
  this.viewPopoverClickHandler = null;
4540
- };
4541
- document.addEventListener('click', this.viewPopoverClickHandler);
4906
+ }
4542
4907
  }
4543
4908
  // ── Render: toolbar ────────────────────────────────────────────────────────
4544
4909
  renderToolbar() {
4545
4910
  var _a;
4546
- const filterCount = this.activeFilters.size;
4547
- const actions = this.tableActions;
4548
- const allViews = this.allViews;
4549
- const hasActions = actions.length > 0;
4550
- const hasViewSwitcher = allViews.length > 1;
4551
- 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: () => {
4552
- if (i !== this.activeViewIdx)
4553
- this.handleViewSwitch(i);
4554
- this.viewPopoverOpen = false;
4555
- if (this.viewPopoverClickHandler) {
4556
- document.removeEventListener('click', this.viewPopoverClickHandler);
4557
- this.viewPopoverClickHandler = null;
4558
- }
4559
- } }, 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 => {
4560
- var _a, _b, _c;
4561
- const createTypes = a.action === 'create' ? (_a = this.item) === null || _a === void 0 ? void 0 : _a.createTypes : null;
4562
- if (createTypes === null || createTypes === void 0 ? void 0 : createTypes.length) {
4563
- 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
4564
- ? h("svg", { class: "mrd-table__action-icon", "aria-hidden": "true" }, h("use", { href: a.icon }))
4565
- : 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: () => {
4566
- this.mrdAction.emit(this.buildActionDetail('create', ct.type));
4567
- this.closeCreatePicker();
4568
- } }, ct.label)))))));
4569
- }
4570
- 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
4571
- ? h("svg", { class: "mrd-table__action-icon", "aria-hidden": "true" }, h("use", { href: a.icon }))
4572
- : a.label, h("span", { class: "mrd-table__action-tooltip" }, a.label)));
4573
- })))));
4911
+ return (h(Toolbar, { locale: this.locale, filterMode: this.filterMode, filterCount: this.activeFilters.size, actions: this.tableActions, views: this.allViews, activeViewIdx: this.activeViewIdx, viewPopoverOpen: this.viewPopoverOpen, createPickerOpen: this.createPickerOpen, createTypes: (_a = this.item) === null || _a === void 0 ? void 0 : _a.createTypes, cb: {
4912
+ onFilterToggle: () => this.handleFilterToggle(),
4913
+ onClearAllFilters: () => this.clearAllFilters(),
4914
+ onViewSwitch: idx => this.handleViewSwitch(idx),
4915
+ onToggleViewPopover: e => this.toggleViewPopover(e),
4916
+ onCloseViewPopover: () => this.closeViewPopover(),
4917
+ onToggleCreatePicker: () => this.toggleCreatePicker(),
4918
+ onCreate: basicType => {
4919
+ this.mrdAction.emit(this.buildActionDetail('create', basicType));
4920
+ this.closeCreatePicker();
4921
+ },
4922
+ onAction: action => this.mrdAction.emit(this.buildActionDetail(action)),
4923
+ } }));
4574
4924
  }
4575
4925
  // ── Render: filter popup ───────────────────────────────────────────────────
4576
- renderFilterEditor(col) {
4577
- var _a, _b, _c, _d, _e, _f, _g;
4578
- const pf = (_a = this.pendingFilter) !== null && _a !== void 0 ? _a : {};
4579
- const dataType = this.colDataType(col);
4580
- if (NO_FILTER_TYPES.has(dataType)) {
4581
- return h("p", { class: "mrd-table__filter-no-support" }, t('filter_no_support', this.locale));
4582
- }
4583
- if (dataType === 'BOOLEAN') {
4584
- const boolOp = pf.operator;
4585
- const noValueOp = boolOp === 'isEmpty' || boolOp === 'isNotEmpty';
4586
- return (h("div", { class: "mrd-table__filter-radio-group" }, [
4587
- { labelKey: 'filter_all', value: null },
4588
- { labelKey: 'yes', value: true },
4589
- { labelKey: 'no', value: false },
4590
- ].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))));
4591
- }
4592
- if (dataType === 'LIST') {
4593
- const items = (_b = col.listItems) !== null && _b !== void 0 ? _b : [];
4594
- const selected = (_c = pf.values) !== null && _c !== void 0 ? _c : [];
4595
- 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)))));
4596
- }
4597
- if (TEXT_TYPES.has(dataType) || dataType === 'RELATION') {
4598
- const op = (_d = pf.operator) !== null && _d !== void 0 ? _d : 'startsWith';
4599
- const noInput = op === 'isEmpty' || op === 'isNotEmpty';
4600
- return (h("div", { class: "mrd-table__filter-editor" }, h("select", { class: "mrd-table__filter-select", onChange: (e) => this.setPending('operator', e.target.value) }, [
4601
- { val: 'startsWith', labelKey: 'filter_starts_with' },
4602
- { val: 'equals', labelKey: 'filter_equals' },
4603
- { val: 'isEmpty', labelKey: 'filter_is_empty' },
4604
- { val: 'isNotEmpty', labelKey: 'filter_is_not_empty' },
4605
- ].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) }))));
4606
- }
4607
- if (NUMERIC_TYPES.has(dataType)) {
4608
- const numOp = pf.operator;
4609
- const noInput = numOp === 'isEmpty' || numOp === 'isNotEmpty';
4610
- const rangeMode = !noInput && (pf.from !== undefined || pf.to !== undefined);
4611
- return (h("div", { class: "mrd-table__filter-editor" }, h("select", { class: "mrd-table__filter-select", onChange: (e) => {
4612
- const val = e.target.value;
4613
- if (val === 'isEmpty' || val === 'isNotEmpty') {
4614
- this.pendingFilter = Object.assign(Object.assign({}, pf), { operator: val, value: undefined, from: undefined, to: undefined });
4615
- }
4616
- else {
4617
- this.pendingFilter = Object.assign(Object.assign({}, pf), { operator: undefined });
4618
- }
4619
- } }, 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) })))))));
4620
- }
4621
- if (dataType === 'DATETIME') {
4622
- const dtOp = pf.operator;
4623
- const noInput = dtOp === 'isEmpty' || dtOp === 'isNotEmpty';
4624
- const rangeMode = !noInput && (pf.from !== undefined || pf.to !== undefined);
4625
- return (h("div", { class: "mrd-table__filter-editor" }, h("select", { class: "mrd-table__filter-select", onChange: (e) => {
4626
- const val = e.target.value;
4627
- if (val === 'isEmpty' || val === 'isNotEmpty') {
4628
- this.pendingFilter = Object.assign(Object.assign({}, pf), { operator: val, value: undefined, from: undefined, to: undefined });
4629
- }
4630
- else {
4631
- this.pendingFilter = Object.assign(Object.assign({}, pf), { operator: undefined });
4632
- }
4633
- } }, 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) })))))));
4634
- }
4635
- if (DATE_TYPES.has(dataType)) {
4636
- const inputType = dataType === 'DATE' ? 'date' : 'time';
4637
- const dtdOp = pf.operator;
4638
- const noInput = dtdOp === 'isEmpty' || dtdOp === 'isNotEmpty';
4639
- const rangeMode = !noInput && (pf.from !== undefined || pf.to !== undefined);
4640
- return (h("div", { class: "mrd-table__filter-editor" }, h("select", { class: "mrd-table__filter-select", onChange: (e) => {
4641
- const val = e.target.value;
4642
- if (val === 'isEmpty' || val === 'isNotEmpty') {
4643
- this.pendingFilter = Object.assign(Object.assign({}, pf), { operator: val, value: undefined, from: undefined, to: undefined });
4644
- }
4645
- else {
4646
- this.pendingFilter = Object.assign(Object.assign({}, pf), { operator: undefined });
4647
- }
4648
- } }, 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) })))))));
4649
- }
4650
- return null;
4651
- }
4652
4926
  renderFilterPopup() {
4653
- var _a;
4654
4927
  if (!this.openFilterCol || !this.pendingFilter)
4655
4928
  return null;
4656
4929
  const col = this.columns.find(c => this.colName(c) === this.openFilterCol);
4657
4930
  if (!col)
4658
4931
  return null;
4659
- const label = (_a = col.label) !== null && _a !== void 0 ? _a : this.openFilterCol;
4660
- const sortActive = this.sortField === this.openFilterCol;
4661
- 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)))));
4932
+ return (h(FilterPopup, { col: col, dataType: this.colDataType(col), openFilterCol: this.openFilterCol, pendingFilter: this.pendingFilter, popupPos: this.popupPos, sortField: this.sortField, sortDir: this.sortDir, locale: this.locale, cb: {
4933
+ onSetPending: (key, val) => this.setPending(key, val),
4934
+ onReplacePending: pf => (this.pendingFilter = pf),
4935
+ onToggleValue: (key, checked) => this.togglePendingValue(key, checked),
4936
+ onApplySort: dir => this.applySort(col, dir),
4937
+ onApply: () => this.applyFilter(),
4938
+ onClear: () => this.clearFilter(),
4939
+ onClose: () => this.closeFilterPopup(),
4940
+ } }));
4662
4941
  }
4663
4942
  // ── Render: footer ────────────────────────────────────────────────────────
4664
4943
  renderFooter(rowCount, effectiveTotal, isTotalKnown = true) {
@@ -4683,54 +4962,11 @@ const MrdTable = class {
4683
4962
  }
4684
4963
  // ── Render: cell ──────────────────────────────────────────────────────────
4685
4964
  renderCell(col, row) {
4686
- var _a, _b, _c;
4687
- const numericTypes = new Set(['INTEGER', 'DECIMAL', 'PERCENTAGE', 'CURRENCY']);
4688
- const dataType = (_a = col.dataType) !== null && _a !== void 0 ? _a : '';
4689
- const isNumeric = col.type === 'FIELD' && numericTypes.has(dataType);
4690
- const isFile = col.type === 'FIELD' && (dataType === 'FILE' || dataType === 'IMAGE');
4691
- if (isFile) {
4692
- const name = (_b = col.name) !== null && _b !== void 0 ? _b : '';
4693
- const fileVal = row === null || row === void 0 ? void 0 : row[name];
4694
- const href = fileVal === null || fileVal === void 0 ? void 0 : fileVal.href;
4695
- const fileName = fileVal === null || fileVal === void 0 ? void 0 : fileVal.fileName;
4696
- return (h("td", { class: "mrd-table__cell" }, href && fileName ? (h("button", { class: "mrd-table__file-btn", title: fileName, onClick: (e) => {
4697
- e.stopPropagation();
4698
- this.mrdDownload.emit({ href, fileName });
4699
- } }, 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))) : ''));
4700
- }
4701
- if (dataType === 'JSON') {
4702
- const name = (_c = col.name) !== null && _c !== void 0 ? _c : '';
4703
- const rawValue = name ? row === null || row === void 0 ? void 0 : row[name] : undefined;
4704
- if (rawValue == null || rawValue === '')
4705
- return h("td", { class: "mrd-table__cell" });
4706
- const compactHtml = CellRenderer.formatJson(rawValue, true);
4707
- const prettyHtml = CellRenderer.formatJson(rawValue, false);
4708
- 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")));
4709
- }
4710
- const TEXTBLOCK_MAX = 200;
4711
- if (dataType === 'TEXTBLOCK') {
4712
- const full = CellRenderer.render(col, row, this.locale);
4713
- if (full.length <= TEXTBLOCK_MAX) {
4714
- return h("td", { class: "mrd-table__cell" }, full);
4715
- }
4716
- const preview = full.slice(0, TEXTBLOCK_MAX) + '…';
4717
- 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")));
4718
- }
4719
- const value = CellRenderer.render(col, row, this.locale);
4720
- return (h("td", { class: `mrd-table__cell${isNumeric ? ' mrd-table__cell--numeric' : ''}` }, value));
4965
+ return (h(TableCell, { col: col, row: row, locale: this.locale, onDownload: detail => this.mrdDownload.emit(detail), onOpenTextblock: full => this.openTextblockModal(full), onOpenJson: html => this.openJsonModal(html) }));
4721
4966
  }
4722
4967
  // ── Render: totals row ────────────────────────────────────────────────────
4723
4968
  renderTotalsRow() {
4724
- if (!this.aggregations)
4725
- return null;
4726
- if (!this.columns.some(c => c.type === 'FIELD' && c.aggregate))
4727
- return null;
4728
- return (h("tfoot", null, h("tr", { class: "mrd-table__totals-row" }, this.columns.map(col => {
4729
- var _a;
4730
- const val = this.renderAggregationValue(col);
4731
- const isNumeric = col.type === 'FIELD' && NUMERIC_TYPES.has((_a = col.dataType) !== null && _a !== void 0 ? _a : '');
4732
- return (h("td", { class: `mrd-table__totals-cell${isNumeric ? ' mrd-table__totals-cell--numeric' : ''}` }, val));
4733
- }))));
4969
+ return h(TotalsRow, { columns: this.columns, aggregations: this.aggregations, locale: this.locale });
4734
4970
  }
4735
4971
  // ── Render ─────────────────────────────────────────────────────────────────
4736
4972
  render() {
@@ -4750,7 +4986,7 @@ const MrdTable = class {
4750
4986
  isFiltered ? 'mrd-table__header--filtered' : '',
4751
4987
  this.filterMode ? 'mrd-table__header--sortable' : '',
4752
4988
  ].filter(Boolean).join(' ');
4753
- 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()));
4989
+ 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 && h(FilterIcon, null)));
4754
4990
  }))), 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()));
4755
4991
  }
4756
4992
  // ── Paginated / virtual-scroll mode ────────────────────────────────────
@@ -4758,12 +4994,7 @@ const MrdTable = class {
4758
4994
  // if any loaded page is shorter than pageSize it is the last page,
4759
4995
  // so the true total cannot exceed (pageNum * pageSize + pageRows.length).
4760
4996
  // aggregationsTotal (from setAggregations) takes priority over the totalElements prop.
4761
- let effectiveTotal = this.baseTotal;
4762
- for (const [pageNum, pageRows] of this.loadedPages) {
4763
- if (pageRows.length < this.pageSize) {
4764
- effectiveTotal = Math.min(effectiveTotal, pageNum * this.pageSize + pageRows.length);
4765
- }
4766
- }
4997
+ const effectiveTotal = computeEffectiveTotal(this.loadedPages, this.pageSize, this.baseTotal);
4767
4998
  // Clamp renderEnd to what we actually know exists (-1 when empty)
4768
4999
  const clampedEnd = Math.min(this.renderEnd, effectiveTotal - 1);
4769
5000
  const colCount = this.columns.length;
@@ -4794,21 +5025,14 @@ const MrdTable = class {
4794
5025
  isActive ? `mrd-table__header--sorted-${this.sortDir}` : '',
4795
5026
  isFiltered ? 'mrd-table__header--filtered' : '',
4796
5027
  ].filter(Boolean).join(' ');
4797
- 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()));
4798
- }))), 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()));
4799
- }
4800
- renderFilterIcon() {
4801
- 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" }))));
5028
+ 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 && h(FilterIcon, null)));
5029
+ }))), 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(), this.renderJsonModal()));
4802
5030
  }
4803
5031
  renderTextblockModal() {
4804
- if (this.textblockModal === null)
4805
- return null;
4806
- 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))));
5032
+ return h(TextblockModal, { text: this.textblockModal, locale: this.locale, onClose: () => this.closeTextblockModal() });
4807
5033
  }
4808
5034
  renderJsonModal() {
4809
- if (this.jsonModal === null)
4810
- return null;
4811
- 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 }))));
5035
+ return h(JsonModal, { html: this.jsonModal, locale: this.locale, onClose: () => this.closeJsonModal() });
4812
5036
  }
4813
5037
  get el() { return getElement(this); }
4814
5038
  static get watchers() { return {
@@ -4820,9 +5044,9 @@ const MrdTable = class {
4820
5044
  }]
4821
5045
  }; }
4822
5046
  };
4823
- MrdTable.style = mrdTableScss();
5047
+ MrdTable.style = mrdTableCss();
4824
5048
 
4825
- 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)}`;
5049
+ const mrdTextFieldCss = () => `.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)}`;
4826
5050
 
4827
5051
  const MrdTextField = class {
4828
5052
  constructor(hostRef) {
@@ -4843,23 +5067,17 @@ const MrdTextField = class {
4843
5067
  };
4844
5068
  this.handleBlur = (e) => {
4845
5069
  const val = e.target.value;
4846
- if (this.required && !validateRequired(val)) {
4847
- this.error = t('required', this.locale);
4848
- }
4849
- else {
4850
- this.error = '';
4851
- }
5070
+ this.error = requiredError(val, this.required, this.locale);
4852
5071
  this.mrdBlur.emit({ name: this.name, value: val });
4853
5072
  };
4854
5073
  }
4855
5074
  render() {
4856
- const hasError = !!this.error;
4857
- return (h(Host, { key: 'e9252b251faf98ab190e643b97c13fa32d12ef22' }, h("div", { key: '37f4259a111c293f2fe12f321f08c00c25e77feb', class: "mrd-text-field" }, this.label && (h("label", { key: 'c59e0346fb71a765ea38629b03c06341567ed210', class: `mrd-text-field__label${this.required ? ' mrd-text-field__label--required' : ''}` }, this.label)), h("input", { key: 'dc09953a672472348719f29904d900966d945843', 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: '037653857a372854a16b28ebf8994b23e3e0d696', class: "mrd-text-field__error" }, this.error))));
5075
+ return (h(Host, { key: '71de1ae949941820574fc2d45cac6cca8264d8f9' }, h("div", { key: 'a63d3dd0811e012ae3d5a9f02c1a2ad1fcc0af86', class: "mrd-text-field" }, h(FieldLabel, { key: '1a6db878b634364f47522209344540a9cdc20635', base: "mrd-text-field", label: this.label, required: this.required }), h("input", { key: 'b3cd0338f13c5c2c8b744df62d3d02f3bc380aa1', class: controlClass('mrd-text-field', !!this.error), type: "text", name: this.name, value: this.value, placeholder: this.placeholder, required: this.required, disabled: this.disabled, onInput: this.handleInput, onBlur: this.handleBlur }), h(FieldError, { key: '1530066fefbda722df0c37871978995a139fcef0', base: "mrd-text-field", error: this.error }))));
4858
5076
  }
4859
5077
  };
4860
- MrdTextField.style = mrdTextFieldScss();
5078
+ MrdTextField.style = mrdTextFieldCss();
4861
5079
 
4862
- const mrdTextareaFieldScss = () => `.sc-mrd-textarea-field-h{display:block}.mrd-textarea-field.sc-mrd-textarea-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-textarea-field__label.sc-mrd-textarea-field{display:block;font-family:var(--mrd-font-family);font-size:var(--mrd-label-font-size);font-weight:var(--mrd-label-font-weight);color:var(--mrd-label-color)}.mrd-textarea-field__label--required.sc-mrd-textarea-field::after{content:' *';color:var(--mrd-color-danger)}.mrd-textarea-field__container.sc-mrd-textarea-field{border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);overflow:hidden;background-color:var(--mrd-input-bg);transition:border-color var(--mrd-transition), box-shadow var(--mrd-transition)}.mrd-textarea-field__container.sc-mrd-textarea-field:focus-within{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-textarea-field__container--error.sc-mrd-textarea-field{border-color:var(--mrd-border-color-error)}.mrd-textarea-field__container--error.sc-mrd-textarea-field:focus-within{box-shadow:var(--mrd-shadow-focus-error)}.mrd-textarea-field__editor.sc-mrd-textarea-field{min-height:150px;font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base)}.mrd-textarea-field__editor.sc-mrd-textarea-field .ql-toolbar.sc-mrd-textarea-field{border:none;border-bottom:var(--mrd-border-width) solid var(--mrd-border-color);font-family:var(--mrd-font-family)}.mrd-textarea-field__editor.sc-mrd-textarea-field .ql-container.sc-mrd-textarea-field{border:none;font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base)}.mrd-textarea-field__editor.sc-mrd-textarea-field .ql-editor.sc-mrd-textarea-field{min-height:120px;padding:var(--mrd-input-padding-y) var(--mrd-input-padding-x)}.mrd-textarea-field__editor.sc-mrd-textarea-field .ql-editor.ql-blank.sc-mrd-textarea-field::before{color:var(--mrd-input-placeholder-color);font-style:normal}.mrd-textarea-field__error.sc-mrd-textarea-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}`;
5080
+ const mrdTextareaFieldCss = () => `.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__error.sc-mrd-textarea-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}.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}`;
4863
5081
 
4864
5082
  const MrdTextareaField = class {
4865
5083
  constructor(hostRef) {
@@ -4912,12 +5130,7 @@ const MrdTextareaField = class {
4912
5130
  var _a, _b;
4913
5131
  if (!range) {
4914
5132
  const html = (_b = (_a = this.editorEl.querySelector('.ql-editor')) === null || _a === void 0 ? void 0 : _a.innerHTML) !== null && _b !== void 0 ? _b : '';
4915
- if (this.required && !validateRequired(html)) {
4916
- this.error = t('required', this.locale);
4917
- }
4918
- else {
4919
- this.error = '';
4920
- }
5133
+ this.error = requiredError(html, this.required, this.locale);
4921
5134
  this.mrdBlur.emit({ name: this.name, value: html });
4922
5135
  }
4923
5136
  });
@@ -4928,13 +5141,13 @@ const MrdTextareaField = class {
4928
5141
  }
4929
5142
  }
4930
5143
  render() {
4931
- return (h(Host, { key: 'fe7824c81e082c3f2c1cf18c11dde20cb1f40f2c' }, h("div", { key: 'adf394a7e146d16bc79006873a209b11d88b2e17', class: "mrd-textarea-field" }, this.label && (h("label", { key: '1b0dd2b4cf26c55a0af05c67a3178edc0c9d56c4', class: `mrd-textarea-field__label${this.required ? ' mrd-textarea-field__label--required' : ''}` }, this.label)), h("div", { key: '7c8fe88b222af0beed08db492aa9f6d890e0dc5b', class: `mrd-textarea-field__container${this.error ? ' mrd-textarea-field__container--error' : ''}` }, h("div", { key: '295968283e94812cb04660117c5bdeaf3647469c', class: "mrd-textarea-field__editor" })), this.error && h("span", { key: '5b5ab61053ab0792d4c249de04bd1d13b51469bf', class: "mrd-textarea-field__error" }, this.error))));
5144
+ return (h(Host, { key: '464c1edde8447043d9352f1b5f9757bba97e9b17' }, h("div", { key: '8d06728214f54feeb1063700e5aaf7c439eb5473', class: "mrd-textarea-field" }, h(FieldLabel, { key: 'dbf93ecf41bd704706b49f8c455262798fbbe10b', base: "mrd-textarea-field", label: this.label, required: this.required }), h("div", { key: '9c39ccfa38ee01b880973966e910ee32aa60b144', class: controlClass('mrd-textarea-field', !!this.error, 'container') }, h("div", { key: '0217cd4350c1933018b2b8f489516b6d43a52538', class: "mrd-textarea-field__editor" })), h(FieldError, { key: '62d2a5db053ea6e4ec6868440f3ab31e1c05e633', base: "mrd-textarea-field", error: this.error }))));
4932
5145
  }
4933
5146
  get el() { return getElement(this); }
4934
5147
  };
4935
- MrdTextareaField.style = mrdTextareaFieldScss();
5148
+ MrdTextareaField.style = mrdTextareaFieldCss();
4936
5149
 
4937
- 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)}`;
5150
+ const mrdTimeFieldCss = () => `.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}.mrd-time-field__input.sc-mrd-time-field::placeholder{color:var(--mrd-input-placeholder-color)}.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)}.mrd-time-field__input.sc-mrd-time-field{cursor:pointer}`;
4938
5151
 
4939
5152
  const MrdTimeField = class {
4940
5153
  constructor(hostRef) {
@@ -4950,12 +5163,7 @@ const MrdTimeField = class {
4950
5163
  this.error = '';
4951
5164
  this.handleChange = (e) => {
4952
5165
  const val = e.target.value;
4953
- if (this.required && !validateRequired(val)) {
4954
- this.error = t('required', this.locale);
4955
- }
4956
- else {
4957
- this.error = '';
4958
- }
5166
+ this.error = requiredError(val, this.required, this.locale);
4959
5167
  this.mrdChange.emit({ name: this.name, value: val });
4960
5168
  };
4961
5169
  this.handleBlur = (e) => {
@@ -4964,10 +5172,9 @@ const MrdTimeField = class {
4964
5172
  };
4965
5173
  }
4966
5174
  render() {
4967
- const hasError = !!this.error;
4968
- return (h(Host, { key: '579219a478e31325b5a676465807c1d936724a2b' }, h("div", { key: '51b25f6e083a29989505c0ad79edbcd3b0060736', class: "mrd-time-field" }, this.label && (h("label", { key: '67d98bebb8803deea2d2a4a63f36706789ccd8c7', class: `mrd-time-field__label${this.required ? ' mrd-time-field__label--required' : ''}` }, this.label)), h("input", { key: '734741e0db1bdd5886fef37bba3b2f8d7200a0ab', 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: '0dbd168d14966dc56a77c97cd8fd8f9b208a4bf5', class: "mrd-time-field__error" }, this.error))));
5175
+ return (h(Host, { key: 'fc30bdeb7c8d37bebc67a768f48013602879fb3d' }, h("div", { key: '52f899a889376773c1948f0c116670684db25cf4', class: "mrd-time-field" }, h(FieldLabel, { key: '3aba58f122fa4bb9f0ba4ad0b56fc3b29f03d4a3', base: "mrd-time-field", label: this.label, required: this.required }), h("input", { key: 'e39718394a195eafaf47aa2e62d560341bb0daed', class: controlClass('mrd-time-field', !!this.error), type: "time", name: this.name, value: this.value, required: this.required, disabled: this.disabled, onChange: this.handleChange, onBlur: this.handleBlur }), h(FieldError, { key: '07ad4ccbc5188e129d8bd3085e856839ec6a81c9', base: "mrd-time-field", error: this.error }))));
4969
5176
  }
4970
5177
  };
4971
- MrdTimeField.style = mrdTimeFieldScss();
5178
+ MrdTimeField.style = mrdTimeFieldCss();
4972
5179
 
4973
5180
  export { MrdBooleanField as mrd_boolean_field, MrdCurrencyField as mrd_currency_field, MrdDateField as mrd_date_field, MrdDatetimeField as mrd_datetime_field, MrdDocumentContainer as mrd_document_container, MrdDocumentList as mrd_document_list, MrdDocumentView as mrd_document_view, 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 };