@mmlogic/components 0.3.11 → 0.4.1

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 (138) 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 +1313 -1088
  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 +7 -7
  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} +6 -4
  10. package/dist/collection/components/{mrd-document-list → documents/mrd-document-list}/mrd-document-list.js +83 -240
  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 +52 -142
  56. package/dist/collection/components/{mrd-table/mrd-table.scss → table/mrd-table/mrd-table.css} +30 -12
  57. package/dist/collection/components/{mrd-table → table/mrd-table}/mrd-table.js +234 -443
  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 +63 -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 +16 -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 +1313 -1088
  96. package/dist/mosterdcomponents/mosterdcomponents.css +1 -1
  97. package/dist/mosterdcomponents/mosterdcomponents.esm.js +1 -1
  98. package/dist/mosterdcomponents/p-DiSEJMA8.js +2 -0
  99. package/dist/mosterdcomponents/p-b1a2e108.entry.js +1 -0
  100. package/dist/types/components/{mrd-document-container → documents/mrd-document-container}/mrd-document-container.d.ts +2 -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 +4 -37
  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 -11
  128. package/dist/types/components/{mrd-table → table/mrd-table}/mrd-table.d.ts +29 -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 +33 -0
  133. package/dist/types/components.d.ts +19 -5
  134. package/dist/types/utils/query-params.d.ts +14 -0
  135. package/package.json +7 -2
  136. package/dist/components/validation.js +0 -1
  137. package/dist/mosterdcomponents/p-_tsCCkAi.js +0 -2
  138. package/dist/mosterdcomponents/p-a9618055.entry.js +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,8 +120,10 @@ 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',
126
+ load_failed_retry: 'Laden mislukt — opnieuw proberen',
52
127
  loading: 'Laden...',
53
128
  submit: 'Opslaan',
54
129
  cancel: 'Annuleren',
@@ -119,8 +194,10 @@ const translations = {
119
194
  drop_file_here: 'Drop file here or',
120
195
  browse: 'browse',
121
196
  file_too_large: 'File is too large',
197
+ invalid_image: 'Please select an image file',
122
198
  search_results: 'Search results',
123
199
  no_results: 'No results found',
200
+ load_failed_retry: 'Failed to load — retry',
124
201
  loading: 'Loading...',
125
202
  submit: 'Save',
126
203
  cancel: 'Cancel',
@@ -191,8 +268,10 @@ const translations = {
191
268
  drop_file_here: 'اسحب الملف هنا أو',
192
269
  browse: 'تصفح',
193
270
  file_too_large: 'الملف كبير جداً',
271
+ invalid_image: 'يرجى اختيار ملف صورة',
194
272
  search_results: 'نتائج البحث',
195
273
  no_results: 'لم يتم العثور على نتائج',
274
+ load_failed_retry: 'فشل التحميل — إعادة المحاولة',
196
275
  loading: 'جار التحميل...',
197
276
  submit: 'حفظ',
198
277
  cancel: 'إلغاء',
@@ -257,8 +336,10 @@ const translations = {
257
336
  drop_file_here: 'Déposez le fichier ici ou',
258
337
  browse: 'parcourir',
259
338
  file_too_large: 'Le fichier est trop volumineux',
339
+ invalid_image: 'Veuillez sélectionner un fichier image',
260
340
  search_results: 'Résultats de recherche',
261
341
  no_results: 'Aucun résultat trouvé',
342
+ load_failed_retry: 'Échec du chargement — réessayer',
262
343
  loading: 'Chargement...',
263
344
  submit: 'Enregistrer',
264
345
  cancel: 'Annuler',
@@ -323,8 +404,10 @@ const translations = {
323
404
  drop_file_here: 'Datei hier ablegen oder',
324
405
  browse: 'durchsuchen',
325
406
  file_too_large: 'Datei ist zu groß',
407
+ invalid_image: 'Bitte eine Bilddatei auswählen',
326
408
  search_results: 'Suchergebnisse',
327
409
  no_results: 'Keine Ergebnisse gefunden',
410
+ load_failed_retry: 'Laden fehlgeschlagen — erneut versuchen',
328
411
  loading: 'Laden...',
329
412
  submit: 'Speichern',
330
413
  cancel: 'Abbrechen',
@@ -389,8 +472,10 @@ const translations = {
389
472
  drop_file_here: 'Suelte el archivo aquí o',
390
473
  browse: 'explorar',
391
474
  file_too_large: 'El archivo es demasiado grande',
475
+ invalid_image: 'Seleccione un archivo de imagen',
392
476
  search_results: 'Resultados de búsqueda',
393
477
  no_results: 'No se encontraron resultados',
478
+ load_failed_retry: 'Error al cargar — reintentar',
394
479
  loading: 'Cargando...',
395
480
  submit: 'Guardar',
396
481
  cancel: 'Cancelar',
@@ -455,8 +540,10 @@ const translations = {
455
540
  drop_file_here: 'Trascina il file qui o',
456
541
  browse: 'sfoglia',
457
542
  file_too_large: 'Il file è troppo grande',
543
+ invalid_image: 'Seleziona un file immagine',
458
544
  search_results: 'Risultati della ricerca',
459
545
  no_results: 'Nessun risultato trovato',
546
+ load_failed_retry: 'Caricamento non riuscito — riprova',
460
547
  loading: 'Caricamento...',
461
548
  submit: 'Salva',
462
549
  cancel: 'Annulla',
@@ -521,8 +608,10 @@ const translations = {
521
608
  drop_file_here: 'Перетягніть файл сюди або',
522
609
  browse: 'огляд',
523
610
  file_too_large: 'Файл занадто великий',
611
+ invalid_image: 'Будь ласка, виберіть файл зображення',
524
612
  search_results: 'Результати пошуку',
525
613
  no_results: 'Результатів не знайдено',
614
+ load_failed_retry: 'Не вдалося завантажити — повторити',
526
615
  loading: 'Завантаження...',
527
616
  submit: 'Зберегти',
528
617
  cancel: 'Скасувати',
@@ -631,80 +720,22 @@ function validateNumber(value, dataType) {
631
720
  return true;
632
721
  }
633
722
 
634
- function formatNumber(value, locale, options) {
635
- if (value === null || value === undefined || isNaN(value))
636
- return '';
637
- return new Intl.NumberFormat(locale, options).format(value);
638
- }
639
- function formatCurrency(amount, currency, locale) {
640
- if (amount === null || amount === undefined || isNaN(amount))
641
- return '';
642
- return new Intl.NumberFormat(locale, {
643
- style: 'currency',
644
- currency,
645
- minimumFractionDigits: 2,
646
- maximumFractionDigits: 2,
647
- }).format(amount);
648
- }
649
- function formatPercentage(value, locale, decimalPrecision = 2) {
650
- if (value === null || value === undefined || isNaN(value))
651
- return '';
652
- return new Intl.NumberFormat(locale, {
653
- style: 'percent',
654
- minimumFractionDigits: decimalPrecision,
655
- maximumFractionDigits: decimalPrecision,
656
- }).format(value);
723
+ /**
724
+ * Shared building blocks for the leaf field components.
725
+ * `base` is the BEM block name, e.g. 'mrd-text-field'.
726
+ */
727
+ const FieldLabel = ({ base, label, required }) => label ? h("label", { class: `${base}__label${required ? ` ${base}__label--required` : ''}` }, label) : null;
728
+ const FieldError = ({ base, error }) => error ? h("span", { class: `${base}__error` }, error) : null;
729
+ /** Class string for the form control, with the --error modifier when applicable. */
730
+ function controlClass(base, hasError, element = 'input') {
731
+ return `${base}__${element}${hasError ? ` ${base}__${element}--error` : ''}`;
657
732
  }
658
- function formatDate(value, locale) {
659
- if (!value)
660
- return '';
661
- const date = typeof value === 'string' ? new Date(value) : value;
662
- if (isNaN(date.getTime()))
663
- return '';
664
- return new Intl.DateTimeFormat(locale, { year: 'numeric', month: '2-digit', day: '2-digit' }).format(date);
665
- }
666
- function formatDateTime(value, locale) {
667
- if (!value)
668
- return '';
669
- const date = typeof value === 'string' ? new Date(value) : value;
670
- if (isNaN(date.getTime()))
671
- return '';
672
- return new Intl.DateTimeFormat(locale, {
673
- year: 'numeric',
674
- month: '2-digit',
675
- day: '2-digit',
676
- hour: '2-digit',
677
- minute: '2-digit',
678
- }).format(date);
679
- }
680
- function formatTime(value, locale) {
681
- if (!value)
682
- return '';
683
- // value is HH:MM or HH:MM:SS
684
- const [hours, minutes] = value.split(':').map(Number);
685
- const date = new Date();
686
- date.setHours(hours, minutes, 0, 0);
687
- return new Intl.DateTimeFormat(locale, { hour: '2-digit', minute: '2-digit' }).format(date);
688
- }
689
- function parseLocalizedNumber(str, locale) {
690
- var _a, _b, _c, _d;
691
- if (!str || !str.trim())
692
- return null;
693
- // Detect decimal and thousands separators from the locale
694
- const parts = new Intl.NumberFormat(locale).formatToParts(1234567.89);
695
- const groupSep = (_b = (_a = parts.find((p) => p.type === 'group')) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : ',';
696
- const decimalSep = (_d = (_c = parts.find((p) => p.type === 'decimal')) === null || _c === void 0 ? void 0 : _c.value) !== null && _d !== void 0 ? _d : '.';
697
- // Remove group separators, replace decimal separator with '.'
698
- const normalized = str
699
- .replace(new RegExp(`\\${groupSep}`, 'g'), '')
700
- .replace(new RegExp(`\\${decimalSep}`), '.')
701
- .replace('%', '')
702
- .trim();
703
- const parsed = parseFloat(normalized);
704
- return isNaN(parsed) ? null : parsed;
733
+ /** Returns the localised required-error, or '' when the value passes. */
734
+ function requiredError(value, required, locale) {
735
+ return required && !validateRequired(value) ? t('required', locale) : '';
705
736
  }
706
737
 
707
- 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)}`;
738
+ 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)}`;
708
739
 
709
740
  const COMMON_CURRENCIES = [
710
741
  'EUR', 'USD', 'GBP', 'CHF', 'JPY', 'CNY', 'AUD', 'CAD',
@@ -731,12 +762,7 @@ const MrdCurrencyField = class {
731
762
  this.handleAmountBlur = (e) => {
732
763
  const raw = e.target.value;
733
764
  const parsed = parseLocalizedNumber(raw, this.locale);
734
- if (this.required && !validateRequired(raw)) {
735
- this.error = t('required', this.locale);
736
- }
737
- else {
738
- this.error = '';
739
- }
765
+ this.error = requiredError(raw, this.required, this.locale);
740
766
  const val = { amount: parsed, currency: this.currency };
741
767
  this.mrdChange.emit({ name: this.name, value: val });
742
768
  this.mrdBlur.emit({ name: this.name, value: val });
@@ -755,12 +781,12 @@ const MrdCurrencyField = class {
755
781
  }
756
782
  render() {
757
783
  const hasError = !!this.error;
758
- 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))));
784
+ 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 }))));
759
785
  }
760
786
  };
761
- MrdCurrencyField.style = mrdCurrencyFieldScss();
787
+ MrdCurrencyField.style = mrdCurrencyFieldCss();
762
788
 
763
- 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)}`;
789
+ 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}`;
764
790
 
765
791
  const MrdDateField = class {
766
792
  constructor(hostRef) {
@@ -776,12 +802,7 @@ const MrdDateField = class {
776
802
  this.error = '';
777
803
  this.handleChange = (e) => {
778
804
  const val = e.target.value;
779
- if (this.required && !validateRequired(val)) {
780
- this.error = t('required', this.locale);
781
- }
782
- else {
783
- this.error = '';
784
- }
805
+ this.error = requiredError(val, this.required, this.locale);
785
806
  this.mrdChange.emit({ name: this.name, value: val });
786
807
  };
787
808
  this.handleBlur = (e) => {
@@ -790,13 +811,12 @@ const MrdDateField = class {
790
811
  };
791
812
  }
792
813
  render() {
793
- const hasError = !!this.error;
794
- 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))));
814
+ 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 }))));
795
815
  }
796
816
  };
797
- MrdDateField.style = mrdDateFieldScss();
817
+ MrdDateField.style = mrdDateFieldCss();
798
818
 
799
- 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)}`;
819
+ 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}`;
800
820
 
801
821
  const MrdDatetimeField = class {
802
822
  constructor(hostRef) {
@@ -814,12 +834,7 @@ const MrdDatetimeField = class {
814
834
  this.handleChange = (e) => {
815
835
  const localVal = e.target.value;
816
836
  this.localValue = localVal;
817
- if (this.required && !validateRequired(localVal)) {
818
- this.error = t('required', this.locale);
819
- }
820
- else {
821
- this.error = '';
822
- }
837
+ this.error = requiredError(localVal, this.required, this.locale);
823
838
  this.mrdChange.emit({ name: this.name, value: this.localToUtc(localVal) });
824
839
  };
825
840
  this.handleBlur = (e) => {
@@ -853,8 +868,7 @@ const MrdDatetimeField = class {
853
868
  return d.toISOString().replace(/\.\d{3}Z$/, 'Z');
854
869
  }
855
870
  render() {
856
- const hasError = !!this.error;
857
- 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))));
871
+ 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 }))));
858
872
  }
859
873
  static get watchers() { return {
860
874
  "value": [{
@@ -862,9 +876,9 @@ const MrdDatetimeField = class {
862
876
  }]
863
877
  }; }
864
878
  };
865
- MrdDatetimeField.style = mrdDatetimeFieldScss();
879
+ MrdDatetimeField.style = mrdDatetimeFieldCss();
866
880
 
867
- 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}`;
881
+ 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}`;
868
882
 
869
883
  const MrdDocumentContainer = class {
870
884
  constructor(hostRef) {
@@ -896,8 +910,8 @@ const MrdDocumentContainer = class {
896
910
  /** Whether the currently mounted table has been init()'d. Reset on every mode switch. */
897
911
  this.tableInited = false;
898
912
  this.createFolder = () => {
899
- var _a, _b;
900
- (_b = (_a = this.listEl) === null || _a === void 0 ? void 0 : _a.createFolder) === null || _b === void 0 ? void 0 : _b.call(_a);
913
+ var _a;
914
+ (_a = this.listEl) === null || _a === void 0 ? void 0 : _a.createFolder();
901
915
  };
902
916
  }
903
917
  /** The embedded table does not self-load: like every mrd-table it waits for the
@@ -909,7 +923,7 @@ const MrdDocumentContainer = class {
909
923
  if (this.mode === 'list' && this.tableEl && !this.tableInited) {
910
924
  this.tableInited = true;
911
925
  const table = this.tableEl;
912
- 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); });
926
+ Promise.resolve((_a = table.componentOnReady) === null || _a === void 0 ? void 0 : _a.call(table)).then(() => table.init());
913
927
  }
914
928
  }
915
929
  setMode(mode) {
@@ -969,13 +983,240 @@ const MrdDocumentContainer = class {
969
983
  }
970
984
  render() {
971
985
  const treeMode = this.mode === 'tree';
972
- return (h(Host, { key: '5d8a9a9bb4f1126a304b796aff9d1cb0100b8fc6' }, this.renderToolbar(), h("div", { key: '80ac7e5dd39ffcc4161059447221045a6e035099', class: "mrd-document-container__body", style: treeMode ? { height: `${this.height}px`, overflowY: 'auto' } : {} }, treeMode ? this.renderTree() : this.renderList())));
986
+ 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())));
973
987
  }
974
988
  get el() { return getElement(this); }
975
989
  };
976
- MrdDocumentContainer.style = mrdDocumentContainerScss();
990
+ MrdDocumentContainer.style = mrdDocumentContainerCss();
991
+
992
+ /**
993
+ * Shared path/query-param conventions for list requests,
994
+ * used by mrd-table and mrd-document-list.
995
+ */
996
+ /** Applies the view-level static filters to `params` using the API operator conventions. */
997
+ function applyViewFilters(params, filters) {
998
+ var _a, _b, _c;
999
+ for (const f of filters !== null && filters !== void 0 ? filters : []) {
1000
+ if (!f.name)
1001
+ continue;
1002
+ if (f.operator === 'EMPTY') {
1003
+ params.set(f.name, '');
1004
+ continue;
1005
+ }
1006
+ if (f.operator === 'NOT_EMPTY') {
1007
+ params.set(f.name + '_notempty', 'true');
1008
+ continue;
1009
+ }
1010
+ if (f.operator === 'STARTS_WITH') {
1011
+ params.set(f.name + '_startswith', String((_a = f.value) !== null && _a !== void 0 ? _a : ''));
1012
+ continue;
1013
+ }
1014
+ if (f.operator === 'FROM') {
1015
+ params.set(f.name + '_from', String((_b = f.value) !== null && _b !== void 0 ? _b : ''));
1016
+ continue;
1017
+ }
1018
+ if (f.operator === 'TO') {
1019
+ params.set(f.name + '_to', String((_c = f.value) !== null && _c !== void 0 ? _c : ''));
1020
+ continue;
1021
+ }
1022
+ if (f.value != null) {
1023
+ params.set(f.name, String(f.value));
1024
+ }
1025
+ }
1026
+ }
1027
+ /** VIEW: `/{dataClass}`; RELATED_VIEW: `/{fromClass}/{parentId}/{dataClass}`. */
1028
+ function buildListPath(opts) {
1029
+ var _a, _b, _c;
1030
+ if (opts.isRelatedView) {
1031
+ return `/${(_a = opts.fromClass) !== null && _a !== void 0 ? _a : ''}/${opts.parentId}/${(_b = opts.dataClass) !== null && _b !== void 0 ? _b : ''}`;
1032
+ }
1033
+ return `/${(_c = opts.dataClass) !== null && _c !== void 0 ? _c : ''}`;
1034
+ }
1035
+
1036
+ /**
1037
+ * Tree model and pure tree logic for mrd-document-list.
1038
+ * Nodes are mutated in place; the component triggers re-renders via bump().
1039
+ */
1040
+ /** Normalise a folder path: null/""/"/" → root ([]); else split on "/" dropping empties. */
1041
+ function splitFolder(path) {
1042
+ if (path == null)
1043
+ return [];
1044
+ const s = String(path).trim();
1045
+ if (s === '' || s === '/')
1046
+ return [];
1047
+ return s.split('/').map(x => x.trim()).filter(Boolean);
1048
+ }
1049
+ function makeContainerNode(href, label, count) {
1050
+ return {
1051
+ id: 'c:' + href, kind: 'container', label, href,
1052
+ hasDocs: false, docCount: 0, totalCount: count, children: [],
1053
+ open: false, loading: false, foldersLoaded: false, docsLoaded: false, docs: [],
1054
+ };
1055
+ }
1056
+ function makeFolderNode(id, label, containerId) {
1057
+ return {
1058
+ id, kind: 'folder', label, containerId,
1059
+ hasDocs: false, docCount: 0, totalCount: 0, children: [],
1060
+ open: false, loading: false, foldersLoaded: false, docsLoaded: false, docs: [],
1061
+ };
1062
+ }
1063
+ /** Recompute totalCount over the subtree; returns the node's aggregate. */
1064
+ function computeTotals(node) {
1065
+ let total = node.docCount;
1066
+ for (const c of node.children)
1067
+ total += computeTotals(c);
1068
+ node.totalCount = total;
1069
+ return total;
1070
+ }
1071
+ /** Folder path segments of a node relative to its container (derived from its id). */
1072
+ function segmentsOf(node, container) {
1073
+ if (node.kind === 'container')
1074
+ return [];
1075
+ const prefix = container.id + '/';
1076
+ const rest = node.id.startsWith(prefix) ? node.id.slice(prefix.length) : '';
1077
+ return rest ? rest.split('/') : [];
1078
+ }
1079
+ /** Folder string a node represents: the raw distinct value when it holds
1080
+ * documents, else derived from its path segments; null for a container root. */
1081
+ function folderStringOf(node, container) {
1082
+ if (node.kind === 'container')
1083
+ return null;
1084
+ if (node.fullPath != null && node.fullPath !== '')
1085
+ return node.fullPath;
1086
+ const segs = segmentsOf(node, container);
1087
+ return segs.length ? '/' + segs.join('/') : null;
1088
+ }
1089
+ /** Strip a single trailing extension for the document title. */
1090
+ function stripExtension(name) {
1091
+ return name.replace(/\.[^./\\]+$/, '');
1092
+ }
1093
+ /** Rebuild a container's folder subtree from the /distinct folder strings.
1094
+ * New nodes are registered in `nodeIndex`; the container is mutated in place. */
1095
+ function applyFolderDistinct(container, values, nodeIndex) {
1096
+ container.children = [];
1097
+ container.hasDocs = false;
1098
+ container.docCount = 0;
1099
+ for (const v of values) {
1100
+ const raw = typeof v.value === 'string' ? v.value : v.value == null ? '' : String(v.value);
1101
+ const segs = splitFolder(raw);
1102
+ if (segs.length === 0) {
1103
+ // Root documents — the container's own direct documents.
1104
+ container.hasDocs = true;
1105
+ container.docCount = v.count;
1106
+ container.fullPath = raw;
1107
+ continue;
1108
+ }
1109
+ let node = container;
1110
+ const acc = [];
1111
+ for (const seg of segs) {
1112
+ acc.push(seg);
1113
+ let child = node.children.find(c => c.label === seg);
1114
+ if (!child) {
1115
+ child = makeFolderNode(container.id + '/' + acc.join('/'), seg, container.id);
1116
+ node.children.push(child);
1117
+ nodeIndex.set(child.id, child);
1118
+ }
1119
+ node = child;
1120
+ }
1121
+ node.hasDocs = true;
1122
+ node.docCount = v.count;
1123
+ node.fullPath = raw;
1124
+ }
1125
+ computeTotals(container);
1126
+ container.foldersLoaded = true;
1127
+ container.loading = false;
1128
+ }
1129
+ /** Optimistic in-place tree update for a document moved between folders. */
1130
+ function applyDocMove(doc, fromNode, toNode, targetFolder) {
1131
+ fromNode.docs = fromNode.docs.filter(d => d !== doc);
1132
+ fromNode.docCount = Math.max(0, fromNode.docCount - 1);
1133
+ // A now-empty folder should stop showing an expand chevron (it disappears on
1134
+ // the next reload anyway, since it is derived from document folder strings).
1135
+ if (fromNode.docsLoaded)
1136
+ fromNode.hasDocs = fromNode.docs.length > 0;
1137
+ toNode.hasDocs = true;
1138
+ toNode.pending = false; // a pending folder is now materialised
1139
+ toNode.docCount += 1;
1140
+ if (toNode.kind === 'folder')
1141
+ toNode.fullPath = targetFolder !== null && targetFolder !== void 0 ? targetFolder : '';
1142
+ if (toNode.docsLoaded)
1143
+ toNode.docs = [...toNode.docs, doc];
1144
+ }
1145
+
1146
+ function chevron(open, leaf) {
1147
+ 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" }))));
1148
+ }
1149
+ function dossierIcon() {
1150
+ 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" })));
1151
+ }
1152
+ function folderIcon() {
1153
+ 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" })));
1154
+ }
1155
+ function docIcon() {
1156
+ 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" })));
1157
+ }
1158
+ function indent(depth) {
1159
+ return h("span", { class: "mrd-document-list__indent", style: { width: `${depth * 18}px` } });
1160
+ }
1161
+ function renderLoadingRow(ctx, depth) {
1162
+ return (h("div", { class: "mrd-document-list__loading", key: "loading" }, indent(depth), h("span", { class: "mrd-document-list__spinner" }), t('loading', ctx.locale)));
1163
+ }
1164
+ function renderUploadingRow(ctx, depth) {
1165
+ return (h("div", { class: "mrd-document-list__loading", key: "uploading" }, indent(depth), h("span", { class: "mrd-document-list__spinner" }), t('upload_file', ctx.locale)));
1166
+ }
1167
+ function renderDocRow(ctx, doc, node, container, depth) {
1168
+ var _a, _b, _c, _d, _e;
1169
+ 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 : '';
1170
+ const dateRaw = ctx.dateField ? doc === null || doc === void 0 ? void 0 : doc[ctx.dateField] : undefined;
1171
+ const date = dateRaw ? formatDate(dateRaw, ctx.locale) : '';
1172
+ 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)));
1173
+ }
1174
+ function renderFolderEditRow(ctx, node, depth) {
1175
+ 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))));
1176
+ }
1177
+ function renderNodeChildren(ctx, container, node, depth) {
1178
+ const out = [];
1179
+ // Direct documents of this node (root docs live on the container node).
1180
+ if (node.hasDocs) {
1181
+ if (node.docsLoaded) {
1182
+ for (const doc of node.docs)
1183
+ out.push(renderDocRow(ctx, doc, node, container, depth));
1184
+ }
1185
+ else if (node.loading) {
1186
+ out.push(renderLoadingRow(ctx, depth));
1187
+ }
1188
+ }
1189
+ // Child folders.
1190
+ for (const child of node.children) {
1191
+ out.push(renderFolderNode(ctx, container, child, depth));
1192
+ }
1193
+ // An uploading file dropped onto this node.
1194
+ if (node.id === ctx.uploadingNodeId)
1195
+ out.push(renderUploadingRow(ctx, depth));
1196
+ return out;
1197
+ }
1198
+ function renderFolderNode(ctx, container, node, depth) {
1199
+ if (node.editing)
1200
+ return renderFolderEditRow(ctx, node, depth);
1201
+ const leaf = node.children.length === 0 && !node.hasDocs;
1202
+ const selected = node.id === ctx.selectedId;
1203
+ const cls = 'mrd-document-list__row'
1204
+ + (selected ? ' mrd-document-list__row--selected' : '')
1205
+ + (node.pending ? ' mrd-document-list__row--pending' : '')
1206
+ + (node.id === ctx.dropTargetId ? ' mrd-document-list__row--drop' : '');
1207
+ 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))));
1208
+ }
1209
+ function renderContainerNode(ctx, node, depth) {
1210
+ const selected = node.id === ctx.selectedId;
1211
+ const cls = 'mrd-document-list__row mrd-document-list__row--dossier'
1212
+ + (selected ? ' mrd-document-list__row--selected' : '')
1213
+ + (node.id === ctx.dropTargetId ? ' mrd-document-list__row--drop' : '');
1214
+ 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
1215
+ ? renderLoadingRow(ctx, depth + 1)
1216
+ : renderNodeChildren(ctx, node, node, depth + 1)))));
1217
+ }
977
1218
 
978
- const mrdDocumentListScss = () => `.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:#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)}`;
1219
+ 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)}`;
979
1220
 
980
1221
  const MrdDocumentList = class {
981
1222
  constructor(hostRef) {
@@ -1042,7 +1283,7 @@ const MrdDocumentList = class {
1042
1283
  return;
1043
1284
  const { target, container } = resolved;
1044
1285
  const tempId = `${container.id}/__new__${this.newFolderSeq++}`;
1045
- const node = this.makeFolderNode(tempId, '', container.id);
1286
+ const node = makeFolderNode(tempId, '', container.id);
1046
1287
  node.pending = true;
1047
1288
  node.editing = true;
1048
1289
  target.children = [...target.children, node];
@@ -1181,7 +1422,7 @@ const MrdDocumentList = class {
1181
1422
  }
1182
1423
  /** Seed the single implied container from context and load its folders. */
1183
1424
  seedSingleContainer() {
1184
- const node = this.makeContainerNode(this.containerHref, this.containerField, 0);
1425
+ const node = makeContainerNode(this.containerHref, this.containerField, 0);
1185
1426
  this.nodeIndex.set(node.id, node);
1186
1427
  this.containers = [node];
1187
1428
  this.rootLoading = false;
@@ -1228,61 +1469,37 @@ const MrdDocumentList = class {
1228
1469
  * type (e.g. "contents"), filtered down to the concrete `filterClass` via the
1229
1470
  * `type` query param — see baseParams(). */
1230
1471
  buildDataPath() {
1231
- var _a, _b, _c;
1472
+ var _a, _b;
1232
1473
  const it = this.item;
1233
- 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 : '';
1234
- if ((it === null || it === void 0 ? void 0 : it.type) === ClientLayoutItemType.RELATED_VIEW) {
1235
- return `/${(_c = it.fromClass) !== null && _c !== void 0 ? _c : ''}/${this.parentId}/${dataClass}`;
1236
- }
1237
- return `/${dataClass}`;
1474
+ return buildListPath({
1475
+ isRelatedView: (it === null || it === void 0 ? void 0 : it.type) === ClientLayoutItemType.RELATED_VIEW,
1476
+ fromClass: it === null || it === void 0 ? void 0 : it.fromClass,
1477
+ parentId: this.parentId,
1478
+ 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 : '',
1479
+ });
1238
1480
  }
1239
1481
  /** Path for creating a new document (file-drop). Unlike buildDataPath(), this
1240
1482
  * must target the concrete type: `dataClass`/`relatedClass` can be an abstract
1241
1483
  * base type (e.g. "contents") that cannot be POSTed to directly, so prefer
1242
1484
  * `filterClass` (e.g. "documents") when present. */
1243
1485
  buildCreatePath() {
1244
- var _a, _b, _c, _d;
1486
+ var _a, _b, _c;
1245
1487
  const it = this.item;
1246
- const 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 : '';
1247
- if ((it === null || it === void 0 ? void 0 : it.type) === ClientLayoutItemType.RELATED_VIEW) {
1248
- return `/${(_d = it.fromClass) !== null && _d !== void 0 ? _d : ''}/${this.parentId}/${dataClass}`;
1249
- }
1250
- return `/${dataClass}`;
1488
+ return buildListPath({
1489
+ isRelatedView: (it === null || it === void 0 ? void 0 : it.type) === ClientLayoutItemType.RELATED_VIEW,
1490
+ fromClass: it === null || it === void 0 ? void 0 : it.fromClass,
1491
+ parentId: this.parentId,
1492
+ 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 : '',
1493
+ });
1251
1494
  }
1252
1495
  /** View-level static filters + filterClass, shared by every request. */
1253
1496
  baseParams() {
1254
- var _a, _b, _c, _d, _e, _f, _g;
1497
+ var _a, _b, _c;
1255
1498
  const p = new URLSearchParams();
1256
1499
  const filterClass = (_a = this.item) === null || _a === void 0 ? void 0 : _a.filterClass;
1257
1500
  if (filterClass)
1258
1501
  p.set('type', filterClass);
1259
- 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 : [])) {
1260
- if (!f.name)
1261
- continue;
1262
- if (f.operator === 'EMPTY') {
1263
- p.set(f.name, '');
1264
- continue;
1265
- }
1266
- if (f.operator === 'NOT_EMPTY') {
1267
- p.set(f.name + '_notempty', 'true');
1268
- continue;
1269
- }
1270
- if (f.operator === 'STARTS_WITH') {
1271
- p.set(f.name + '_startswith', String((_e = f.value) !== null && _e !== void 0 ? _e : ''));
1272
- continue;
1273
- }
1274
- if (f.operator === 'FROM') {
1275
- p.set(f.name + '_from', String((_f = f.value) !== null && _f !== void 0 ? _f : ''));
1276
- continue;
1277
- }
1278
- if (f.operator === 'TO') {
1279
- p.set(f.name + '_to', String((_g = f.value) !== null && _g !== void 0 ? _g : ''));
1280
- continue;
1281
- }
1282
- if (f.value != null) {
1283
- p.set(f.name, String(f.value));
1284
- }
1285
- }
1502
+ applyViewFilters(p, (_c = (_b = this.item) === null || _b === void 0 ? void 0 : _b.view) === null || _c === void 0 ? void 0 : _c.filter);
1286
1503
  return p;
1287
1504
  }
1288
1505
  emitContainerDistinct() {
@@ -1349,7 +1566,7 @@ const MrdDocumentList = class {
1349
1566
  if (!v.value || typeof v.value !== 'object')
1350
1567
  continue;
1351
1568
  const href = v.value.href;
1352
- const node = this.makeContainerNode(href, v.value.name, v.count);
1569
+ const node = makeContainerNode(href, v.value.name, v.count);
1353
1570
  nodes.push(node);
1354
1571
  this.nodeIndex.set(node.id, node);
1355
1572
  }
@@ -1367,38 +1584,7 @@ const MrdDocumentList = class {
1367
1584
  const container = this.nodeIndex.get(containerId);
1368
1585
  if (!container)
1369
1586
  return;
1370
- container.children = [];
1371
- container.hasDocs = false;
1372
- container.docCount = 0;
1373
- for (const v of values) {
1374
- const raw = typeof v.value === 'string' ? v.value : v.value == null ? '' : String(v.value);
1375
- const segs = this.splitFolder(raw);
1376
- if (segs.length === 0) {
1377
- // Root documents — the container's own direct documents.
1378
- container.hasDocs = true;
1379
- container.docCount = v.count;
1380
- container.fullPath = raw;
1381
- continue;
1382
- }
1383
- let node = container;
1384
- const acc = [];
1385
- for (const seg of segs) {
1386
- acc.push(seg);
1387
- let child = node.children.find(c => c.label === seg);
1388
- if (!child) {
1389
- child = this.makeFolderNode(container.id + '/' + acc.join('/'), seg, container.id);
1390
- node.children.push(child);
1391
- this.nodeIndex.set(child.id, child);
1392
- }
1393
- node = child;
1394
- }
1395
- node.hasDocs = true;
1396
- node.docCount = v.count;
1397
- node.fullPath = raw;
1398
- }
1399
- this.computeTotals(container);
1400
- container.foldersLoaded = true;
1401
- container.loading = false;
1587
+ applyFolderDistinct(container, values, this.nodeIndex);
1402
1588
  // If the container has root documents, load them now (they show inline on expand).
1403
1589
  if (container.hasDocs && !container.docsLoaded) {
1404
1590
  this.emitDocuments(container, container);
@@ -1406,36 +1592,6 @@ const MrdDocumentList = class {
1406
1592
  this.bump();
1407
1593
  }
1408
1594
  // ── Tree helpers ─────────────────────────────────────────────────────────
1409
- /** Normalise a folder path: null/""/"/" → root ([]); else split on "/" dropping empties. */
1410
- splitFolder(path) {
1411
- if (path == null)
1412
- return [];
1413
- const s = String(path).trim();
1414
- if (s === '' || s === '/')
1415
- return [];
1416
- return s.split('/').map(x => x.trim()).filter(Boolean);
1417
- }
1418
- makeContainerNode(href, label, count) {
1419
- return {
1420
- id: 'c:' + href, kind: 'container', label, href,
1421
- hasDocs: false, docCount: 0, totalCount: count, children: [],
1422
- open: false, loading: false, foldersLoaded: false, docsLoaded: false, docs: [],
1423
- };
1424
- }
1425
- makeFolderNode(id, label, containerId) {
1426
- return {
1427
- id, kind: 'folder', label, containerId,
1428
- hasDocs: false, docCount: 0, totalCount: 0, children: [],
1429
- open: false, loading: false, foldersLoaded: false, docsLoaded: false, docs: [],
1430
- };
1431
- }
1432
- computeTotals(node) {
1433
- let total = node.docCount;
1434
- for (const c of node.children)
1435
- total += this.computeTotals(c);
1436
- node.totalCount = total;
1437
- return total;
1438
- }
1439
1595
  /** Force a re-render after mutating nodes in place. */
1440
1596
  bump() {
1441
1597
  this.containers = [...this.containers];
@@ -1485,14 +1641,6 @@ const MrdDocumentList = class {
1485
1641
  async createFolder() {
1486
1642
  this.startCreateFolder();
1487
1643
  }
1488
- /** Folder path segments of a node relative to its container (derived from its id). */
1489
- segmentsOf(node, container) {
1490
- if (node.kind === 'container')
1491
- return [];
1492
- const prefix = container.id + '/';
1493
- const rest = node.id.startsWith(prefix) ? node.id.slice(prefix.length) : '';
1494
- return rest ? rest.split('/') : [];
1495
- }
1496
1644
  commitFolder() {
1497
1645
  const node = this.pendingNode;
1498
1646
  const parent = this.pendingParent;
@@ -1517,7 +1665,7 @@ const MrdDocumentList = class {
1517
1665
  }
1518
1666
  // Finalise: swap the temp id for the real path-derived id so a later distinct
1519
1667
  // value with the same folder string merges onto this node.
1520
- const segs = [...this.segmentsOf(parent, container), name];
1668
+ const segs = [...segmentsOf(parent, container), name];
1521
1669
  this.nodeIndex.delete(node.id);
1522
1670
  node.id = container.id + '/' + segs.join('/');
1523
1671
  node.fullPath = '/' + segs.join('/');
@@ -1566,10 +1714,6 @@ const MrdDocumentList = class {
1566
1714
  this.bump();
1567
1715
  this.mrdUpload.emit({ file });
1568
1716
  }
1569
- /** Strip a single trailing extension for the document title. */
1570
- stripExtension(name) {
1571
- return name.replace(/\.[^./\\]+$/, '');
1572
- }
1573
1717
  /** Host callback with the uploaded file reference. Builds the create payload
1574
1718
  * from the archetype slots and requests the new document. */
1575
1719
  async setFileReference(uri) {
@@ -1577,16 +1721,20 @@ const MrdDocumentList = class {
1577
1721
  if (!up)
1578
1722
  return;
1579
1723
  const { file, node, container } = up;
1580
- const folder = this.folderStringOf(node, container);
1724
+ const folder = folderStringOf(node, container);
1581
1725
  const values = {
1582
1726
  [this.fileField]: uri,
1583
- [this.titleField]: this.stripExtension(file.name),
1727
+ [this.titleField]: stripExtension(file.name),
1584
1728
  [this.folderField]: folder,
1585
- [this.containerField]: container.href,
1586
1729
  };
1730
+ // The create path already embeds the container (/{fromClass}/{parentId}/...)
1731
+ // when this is the seeded single-container context; omit the redundant field.
1732
+ if (!this.isSeededSingleContainer()) {
1733
+ values[this.containerField] = container.href;
1734
+ }
1587
1735
  this.mrdCreateObject.emit({ path: this.buildCreatePath(), values });
1588
1736
  // Optimistically show the new document (no href until a reload).
1589
- const optimistic = { [this.titleField]: this.stripExtension(file.name), _optimistic: true };
1737
+ const optimistic = { [this.titleField]: stripExtension(file.name), _optimistic: true };
1590
1738
  const wasUnloadedEmpty = !node.docsLoaded && node.docCount === 0;
1591
1739
  node.hasDocs = true;
1592
1740
  node.pending = false;
@@ -1615,16 +1763,6 @@ const MrdDocumentList = class {
1615
1763
  this.lastOptimisticDoc = null;
1616
1764
  this.bump();
1617
1765
  }
1618
- /** Folder string a node represents: the raw distinct value when it holds
1619
- * documents, else derived from its path segments; null for a container root. */
1620
- folderStringOf(node, container) {
1621
- if (node.kind === 'container')
1622
- return null;
1623
- if (node.fullPath != null && node.fullPath !== '')
1624
- return node.fullPath;
1625
- const segs = this.segmentsOf(node, container);
1626
- return segs.length ? '/' + segs.join('/') : null;
1627
- }
1628
1766
  moveDocument(toNode, toContainer) {
1629
1767
  var _a, _b;
1630
1768
  const doc = this.dragDoc;
@@ -1636,26 +1774,14 @@ const MrdDocumentList = class {
1636
1774
  : (fromNode.containerId ? this.nodeIndex.get(fromNode.containerId) : undefined);
1637
1775
  if (!fromContainer)
1638
1776
  return;
1639
- const targetFolder = this.folderStringOf(toNode, toContainer);
1640
- const sourceFolder = this.folderStringOf(fromNode, fromContainer);
1777
+ const targetFolder = folderStringOf(toNode, toContainer);
1778
+ const sourceFolder = folderStringOf(fromNode, fromContainer);
1641
1779
  const sameContainer = toContainer === fromContainer;
1642
1780
  // No-op: dropped back onto its own folder.
1643
1781
  if (toNode === fromNode || (sameContainer && targetFolder === sourceFolder))
1644
1782
  return;
1645
- // ── Optimistic tree update (fire-and-forget; no refetch) ──
1646
- fromNode.docs = fromNode.docs.filter(d => d !== doc);
1647
- fromNode.docCount = Math.max(0, fromNode.docCount - 1);
1648
- // A now-empty folder should stop showing an expand chevron (it disappears on
1649
- // the next reload anyway, since it is derived from document folder strings).
1650
- if (fromNode.docsLoaded)
1651
- fromNode.hasDocs = fromNode.docs.length > 0;
1652
- toNode.hasDocs = true;
1653
- toNode.pending = false; // a pending folder is now materialised
1654
- toNode.docCount += 1;
1655
- if (toNode.kind === 'folder')
1656
- toNode.fullPath = targetFolder !== null && targetFolder !== void 0 ? targetFolder : '';
1657
- if (toNode.docsLoaded)
1658
- toNode.docs = [...toNode.docs, doc];
1783
+ // Optimistic tree update (fire-and-forget; no refetch).
1784
+ applyDocMove(doc, fromNode, toNode, targetFolder);
1659
1785
  this.recomputeContainerTotals(fromContainer, -1);
1660
1786
  if (!sameContainer)
1661
1787
  this.recomputeContainerTotals(toContainer, 1);
@@ -1673,7 +1799,7 @@ const MrdDocumentList = class {
1673
1799
  * loaded; otherwise just nudge the aggregate badge by the delta. */
1674
1800
  recomputeContainerTotals(container, delta) {
1675
1801
  if (container.foldersLoaded) {
1676
- this.computeTotals(container);
1802
+ computeTotals(container);
1677
1803
  }
1678
1804
  else {
1679
1805
  container.totalCount = Math.max(0, container.totalCount + delta);
@@ -1686,111 +1812,64 @@ const MrdDocumentList = class {
1686
1812
  this.mrdNavigate.emit({ href, label });
1687
1813
  }
1688
1814
  // ── Render ───────────────────────────────────────────────────────────────
1689
- renderChevron(open, leaf) {
1690
- 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" }))));
1691
- }
1692
- renderDossierIcon() {
1693
- 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" })));
1694
- }
1695
- renderFolderIcon() {
1696
- 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" })));
1697
- }
1698
- renderDocIcon() {
1699
- 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" })));
1700
- }
1701
- indent(depth) {
1702
- return h("span", { class: "mrd-document-list__indent", style: { width: `${depth * 18}px` } });
1703
- }
1704
- renderDocRow(doc, node, container, depth) {
1705
- var _a, _b, _c, _d, _e;
1706
- 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 : '';
1707
- const dateRaw = this.dateField ? doc === null || doc === void 0 ? void 0 : doc[this.dateField] : undefined;
1708
- const date = dateRaw ? formatDate(dateRaw, this.locale) : '';
1709
- 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)));
1710
- }
1711
- renderLoadingRow(depth) {
1712
- return (h("div", { class: "mrd-document-list__loading", key: "loading" }, this.indent(depth), h("span", { class: "mrd-document-list__spinner" }), t('loading', this.locale)));
1713
- }
1714
- renderChildren(container, node, depth) {
1715
- const out = [];
1716
- // Direct documents of this node (root docs live on the container node).
1717
- if (node.hasDocs) {
1718
- if (node.docsLoaded) {
1719
- for (const doc of node.docs)
1720
- out.push(this.renderDocRow(doc, node, container, depth));
1721
- }
1722
- else if (node.loading) {
1723
- out.push(this.renderLoadingRow(depth));
1724
- }
1725
- }
1726
- // Child folders.
1727
- for (const child of node.children) {
1728
- out.push(this.renderFolderNode(container, child, depth));
1729
- }
1730
- // An uploading file dropped onto this node.
1731
- if (node.id === this.uploadingNodeId)
1732
- out.push(this.renderUploadingRow(depth));
1733
- return out;
1734
- }
1735
- renderUploadingRow(depth) {
1736
- 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)));
1737
- }
1738
- renderFolderEditRow(node, depth) {
1739
- 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))));
1740
- }
1741
- renderFolderNode(container, node, depth) {
1742
- if (node.editing)
1743
- return this.renderFolderEditRow(node, depth);
1744
- const leaf = node.children.length === 0 && !node.hasDocs;
1745
- const selected = node.id === this.selectedId;
1746
- const cls = 'mrd-document-list__row'
1747
- + (selected ? ' mrd-document-list__row--selected' : '')
1748
- + (node.pending ? ' mrd-document-list__row--pending' : '')
1749
- + (node.id === this.dropTargetId ? ' mrd-document-list__row--drop' : '');
1750
- 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))));
1751
- }
1752
- renderContainerNode(node, depth) {
1753
- const selected = node.id === this.selectedId;
1754
- const cls = 'mrd-document-list__row mrd-document-list__row--dossier'
1755
- + (selected ? ' mrd-document-list__row--selected' : '')
1756
- + (node.id === this.dropTargetId ? ' mrd-document-list__row--drop' : '');
1757
- 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
1758
- ? this.renderLoadingRow(depth + 1)
1759
- : this.renderChildren(node, node, depth + 1)))));
1815
+ treeCtx() {
1816
+ return {
1817
+ locale: this.locale,
1818
+ titleField: this.titleField,
1819
+ dateField: this.dateField,
1820
+ selectedId: this.selectedId,
1821
+ dropTargetId: this.dropTargetId,
1822
+ uploadingNodeId: this.uploadingNodeId,
1823
+ on: {
1824
+ toggleContainer: node => this.toggleContainer(node),
1825
+ toggleFolder: (container, node) => this.toggleFolder(container, node),
1826
+ openDoc: doc => this.openDoc(doc),
1827
+ docDragStart: this.onDocDragStart,
1828
+ docDragEnd: this.onDocDragEnd,
1829
+ nodeDragOver: this.onNodeDragOver,
1830
+ nodeDragLeave: this.onNodeDragLeave,
1831
+ nodeDrop: this.onNodeDrop,
1832
+ pendingInput: this.onPendingInput,
1833
+ pendingKeyDown: this.onPendingKeyDown,
1834
+ cancelFolder: () => this.cancelFolder(),
1835
+ setPendingInputEl: el => (this.pendingInputEl = el),
1836
+ },
1837
+ };
1760
1838
  }
1761
1839
  render() {
1840
+ const ctx = this.treeCtx();
1762
1841
  let body;
1763
1842
  if (this.rootLoading) {
1764
- body = this.renderLoadingRow(0);
1843
+ body = renderLoadingRow(ctx, 0);
1765
1844
  }
1766
1845
  else if (this.containers.length === 0) {
1767
- body = h("div", { key: '9c38a2e26320a8173ba82cac412c1b32a8a1882e', class: "mrd-document-list__empty" }, t('no_results', this.locale));
1846
+ body = h("div", { key: 'ce40dab51ab61447838e5059159ae4778209a6f3', class: "mrd-document-list__empty" }, t('no_results', this.locale));
1768
1847
  }
1769
1848
  else if (this.singleContainer) {
1770
1849
  // Dossier context: render the single container's folder tree at the root.
1771
1850
  const only = this.containers[0];
1772
1851
  if (only.loading && !only.foldersLoaded) {
1773
- body = this.renderLoadingRow(0);
1852
+ body = renderLoadingRow(ctx, 0);
1774
1853
  }
1775
1854
  else {
1776
- const kids = this.renderChildren(only, only, 0);
1855
+ const kids = renderNodeChildren(ctx, only, only, 0);
1777
1856
  body = kids.length
1778
1857
  ? kids
1779
1858
  : h("div", { class: "mrd-document-list__empty" }, t('doc_empty_drop', this.locale));
1780
1859
  }
1781
1860
  }
1782
1861
  else {
1783
- body = this.containers.map(c => this.renderContainerNode(c, 0));
1862
+ body = this.containers.map(c => renderContainerNode(ctx, c, 0));
1784
1863
  }
1785
- return (h(Host, { key: 'dd83a6a609e01d21a2b5da5b3ab929f6f9315402' }, h("div", { key: 'd539d938e1efd759730cccc90c4d6c2e535db936', class: 'mrd-document-list' + (this.rootDropActive ? ' mrd-document-list--drop-active' : ''), onDragOver: this.onRootDragOver, onDragLeave: this.onRootDragLeave, onDrop: this.onRootDrop }, body)));
1864
+ 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)));
1786
1865
  }
1787
1866
  get el() { return getElement(this); }
1788
1867
  };
1789
1868
  /** Root sentinel id for the container-level distinct request. */
1790
1869
  MrdDocumentList.ROOT = '__root__';
1791
- MrdDocumentList.style = mrdDocumentListScss();
1870
+ MrdDocumentList.style = mrdDocumentListCss();
1792
1871
 
1793
- 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)}`;
1872
+ 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)}`;
1794
1873
 
1795
1874
  const MrdDocumentView = class {
1796
1875
  constructor(hostRef) {
@@ -1840,12 +1919,12 @@ const MrdDocumentView = class {
1840
1919
  const date = dateRaw != null && dateRaw !== '' ? formatDate(dateRaw, this.locale) : null;
1841
1920
  const summaryRaw = this.slotValue('summary');
1842
1921
  const summary = summaryRaw != null && summaryRaw !== '' ? String(summaryRaw) : null;
1843
- 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 }))))));
1922
+ 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 }))))));
1844
1923
  }
1845
1924
  };
1846
- MrdDocumentView.style = mrdDocumentViewScss();
1925
+ MrdDocumentView.style = mrdDocumentViewCss();
1847
1926
 
1848
- 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)}`;
1927
+ 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)}`;
1849
1928
 
1850
1929
  const MrdEmailField = class {
1851
1930
  constructor(hostRef) {
@@ -1866,26 +1945,18 @@ const MrdEmailField = class {
1866
1945
  };
1867
1946
  this.handleBlur = (e) => {
1868
1947
  const val = e.target.value;
1869
- if (this.required && !validateRequired(val)) {
1870
- this.error = t('required', this.locale);
1871
- }
1872
- else if (val && !validateEmail(val)) {
1873
- this.error = t('invalid_email', this.locale);
1874
- }
1875
- else {
1876
- this.error = '';
1877
- }
1948
+ this.error = requiredError(val, this.required, this.locale)
1949
+ || (val && !validateEmail(val) ? t('invalid_email', this.locale) : '');
1878
1950
  this.mrdBlur.emit({ name: this.name, value: val });
1879
1951
  };
1880
1952
  }
1881
1953
  render() {
1882
- const hasError = !!this.error;
1883
- 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))));
1954
+ 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 }))));
1884
1955
  }
1885
1956
  };
1886
- MrdEmailField.style = mrdEmailFieldScss();
1957
+ MrdEmailField.style = mrdEmailFieldCss();
1887
1958
 
1888
- 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)}`;
1959
+ 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)}`;
1889
1960
 
1890
1961
  const MrdField = class {
1891
1962
  constructor(hostRef) {
@@ -2070,9 +2141,47 @@ const MrdField = class {
2070
2141
  }]
2071
2142
  }; }
2072
2143
  };
2073
- MrdField.style = mrdFieldScss();
2144
+ MrdField.style = mrdFieldCss();
2074
2145
 
2075
- 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)}`;
2146
+ /**
2147
+ * Shared upload behaviour for mrd-file-field and mrd-image-field:
2148
+ * file validation, drop-zone class building and drag-drop wiring.
2149
+ */
2150
+ /** Validates a selected/dropped file; returns a localised error message or '' when accepted. */
2151
+ function validateUploadFile(file, maxSize, locale, requireImage = false) {
2152
+ if (maxSize > 0 && file.size > maxSize)
2153
+ return t('file_too_large', locale);
2154
+ if (requireImage && !file.type.startsWith('image/'))
2155
+ return t('invalid_image', locale);
2156
+ return '';
2157
+ }
2158
+ /** BEM class string for the drop zone, e.g. base 'mrd-file-field' → 'mrd-file-field__zone …'. */
2159
+ function uploadZoneClass(base, opts) {
2160
+ return [
2161
+ `${base}__zone`,
2162
+ opts.dragging ? `${base}__zone--dragging` : '',
2163
+ opts.error ? `${base}__zone--error` : '',
2164
+ opts.disabled ? `${base}__zone--disabled` : '',
2165
+ ].filter(Boolean).join(' ');
2166
+ }
2167
+ /** Drag-drop handlers for the drop zone; the component owns the dragging state and file handling. */
2168
+ function makeDragHandlers(setDragging, onFile) {
2169
+ return {
2170
+ onDragOver: (e) => {
2171
+ e.preventDefault();
2172
+ setDragging(true);
2173
+ },
2174
+ onDragLeave: () => setDragging(false),
2175
+ onDrop: (e) => {
2176
+ var _a, _b, _c;
2177
+ e.preventDefault();
2178
+ setDragging(false);
2179
+ 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);
2180
+ },
2181
+ };
2182
+ }
2183
+
2184
+ 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)}}`;
2076
2185
 
2077
2186
  const MrdFileField = class {
2078
2187
  constructor(hostRef) {
@@ -2097,20 +2206,7 @@ const MrdFileField = class {
2097
2206
  const files = e.target.files;
2098
2207
  this.handleFile((_a = files === null || files === void 0 ? void 0 : files[0]) !== null && _a !== void 0 ? _a : null);
2099
2208
  };
2100
- this.handleDragOver = (e) => {
2101
- e.preventDefault();
2102
- this.isDragging = true;
2103
- };
2104
- this.handleDragLeave = () => {
2105
- this.isDragging = false;
2106
- };
2107
- this.handleDrop = (e) => {
2108
- var _a, _b, _c;
2109
- e.preventDefault();
2110
- this.isDragging = false;
2111
- 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;
2112
- this.handleFile(file);
2113
- };
2209
+ this.drag = makeDragHandlers(dragging => (this.isDragging = dragging), file => this.handleFile(file));
2114
2210
  this.handleZoneClick = () => {
2115
2211
  var _a;
2116
2212
  if (!this.disabled && !this.uploading) {
@@ -2144,8 +2240,9 @@ const MrdFileField = class {
2144
2240
  this.mrdChange.emit({ name: this.name, value: null });
2145
2241
  return;
2146
2242
  }
2147
- if (this.maxSize > 0 && file.size > this.maxSize) {
2148
- this.error = t('file_too_large', this.locale);
2243
+ const uploadError = validateUploadFile(file, this.maxSize, this.locale);
2244
+ if (uploadError) {
2245
+ this.error = uploadError;
2149
2246
  return;
2150
2247
  }
2151
2248
  this.error = '';
@@ -2157,13 +2254,12 @@ const MrdFileField = class {
2157
2254
  render() {
2158
2255
  const hasFile = this.uploading || (typeof this.value === 'string' && this.value) || this.fileName;
2159
2256
  const hasError = !!this.error;
2160
- const zoneClass = [
2161
- 'mrd-file-field__zone',
2162
- this.isDragging ? 'mrd-file-field__zone--dragging' : '',
2163
- hasError ? 'mrd-file-field__zone--error' : '',
2164
- this.disabled || this.uploading ? 'mrd-file-field__zone--disabled' : '',
2165
- ].filter(Boolean).join(' ');
2166
- 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))));
2257
+ const zoneClass = uploadZoneClass('mrd-file-field', {
2258
+ dragging: this.isDragging,
2259
+ error: hasError,
2260
+ disabled: this.disabled || this.uploading,
2261
+ });
2262
+ 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 }))));
2167
2263
  }
2168
2264
  static get watchers() { return {
2169
2265
  "value": [{
@@ -2171,9 +2267,9 @@ const MrdFileField = class {
2171
2267
  }]
2172
2268
  }; }
2173
2269
  };
2174
- MrdFileField.style = mrdFileFieldScss();
2270
+ MrdFileField.style = mrdFileFieldCss();
2175
2271
 
2176
- 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)}`;
2272
+ 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)}`;
2177
2273
 
2178
2274
  const MrdForm = class {
2179
2275
  constructor(hostRef) {
@@ -2540,9 +2636,9 @@ const MrdForm = class {
2540
2636
  }]
2541
2637
  }; }
2542
2638
  };
2543
- MrdForm.style = mrdFormScss();
2639
+ MrdForm.style = mrdFormCss();
2544
2640
 
2545
- 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)}`;
2641
+ 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)}`;
2546
2642
 
2547
2643
  const MrdHyperlinkField = class {
2548
2644
  constructor(hostRef) {
@@ -2568,15 +2664,8 @@ const MrdHyperlinkField = class {
2568
2664
  this.mrdChange.emit({ name: this.name, value: this.buildValue() });
2569
2665
  };
2570
2666
  this.handleBlur = () => {
2571
- if (this.required && !validateRequired(this.internalHref)) {
2572
- this.error = t('required', this.locale);
2573
- }
2574
- else if (this.internalHref && !validateUrl(this.internalHref)) {
2575
- this.error = t('invalid_url', this.locale);
2576
- }
2577
- else {
2578
- this.error = '';
2579
- }
2667
+ this.error = requiredError(this.internalHref, this.required, this.locale)
2668
+ || (this.internalHref && !validateUrl(this.internalHref) ? t('invalid_url', this.locale) : '');
2580
2669
  this.mrdBlur.emit({ name: this.name, value: this.buildValue() });
2581
2670
  };
2582
2671
  }
@@ -2609,7 +2698,7 @@ const MrdHyperlinkField = class {
2609
2698
  ? h("a", { class: "mrd-hyperlink-field__link", href: this.internalHref, target: "_blank", rel: "noopener noreferrer" }, this.internalName || this.internalHref)
2610
2699
  : h("span", { class: "mrd-hyperlink-field__empty" }, "\u2014"))));
2611
2700
  }
2612
- 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))));
2701
+ 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 }))));
2613
2702
  }
2614
2703
  static get watchers() { return {
2615
2704
  "value": [{
@@ -2617,9 +2706,9 @@ const MrdHyperlinkField = class {
2617
2706
  }]
2618
2707
  }; }
2619
2708
  };
2620
- MrdHyperlinkField.style = mrdHyperlinkFieldScss();
2709
+ MrdHyperlinkField.style = mrdHyperlinkFieldCss();
2621
2710
 
2622
- 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)}`;
2711
+ 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)}`;
2623
2712
 
2624
2713
  const MrdImageField = class {
2625
2714
  constructor(hostRef) {
@@ -2645,20 +2734,7 @@ const MrdImageField = class {
2645
2734
  const files = e.target.files;
2646
2735
  this.handleFile((_a = files === null || files === void 0 ? void 0 : files[0]) !== null && _a !== void 0 ? _a : null);
2647
2736
  };
2648
- this.handleDragOver = (e) => {
2649
- e.preventDefault();
2650
- this.isDragging = true;
2651
- };
2652
- this.handleDragLeave = () => {
2653
- this.isDragging = false;
2654
- };
2655
- this.handleDrop = (e) => {
2656
- var _a, _b, _c;
2657
- e.preventDefault();
2658
- this.isDragging = false;
2659
- 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;
2660
- this.handleFile(file);
2661
- };
2737
+ this.drag = makeDragHandlers(dragging => (this.isDragging = dragging), file => this.handleFile(file));
2662
2738
  this.handleZoneClick = () => {
2663
2739
  var _a;
2664
2740
  if (!this.disabled && !this.uploading) {
@@ -2695,12 +2771,9 @@ const MrdImageField = class {
2695
2771
  this.mrdChange.emit({ name: this.name, value: null });
2696
2772
  return;
2697
2773
  }
2698
- if (this.maxSize > 0 && file.size > this.maxSize) {
2699
- this.error = t('file_too_large', this.locale);
2700
- return;
2701
- }
2702
- if (!file.type.startsWith('image/')) {
2703
- this.error = 'Please select an image file';
2774
+ const uploadError = validateUploadFile(file, this.maxSize, this.locale, true);
2775
+ if (uploadError) {
2776
+ this.error = uploadError;
2704
2777
  return;
2705
2778
  }
2706
2779
  this.error = '';
@@ -2718,13 +2791,12 @@ const MrdImageField = class {
2718
2791
  }
2719
2792
  render() {
2720
2793
  const hasError = !!this.error;
2721
- const zoneClass = [
2722
- 'mrd-image-field__zone',
2723
- this.isDragging ? 'mrd-image-field__zone--dragging' : '',
2724
- hasError ? 'mrd-image-field__zone--error' : '',
2725
- this.disabled || this.uploading ? 'mrd-image-field__zone--disabled' : '',
2726
- ].filter(Boolean).join(' ');
2727
- 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))));
2794
+ const zoneClass = uploadZoneClass('mrd-image-field', {
2795
+ dragging: this.isDragging,
2796
+ error: hasError,
2797
+ disabled: this.disabled || this.uploading,
2798
+ });
2799
+ 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 }))));
2728
2800
  }
2729
2801
  static get watchers() { return {
2730
2802
  "value": [{
@@ -2732,7 +2804,36 @@ const MrdImageField = class {
2732
2804
  }]
2733
2805
  }; }
2734
2806
  };
2735
- MrdImageField.style = mrdImageFieldScss();
2807
+ MrdImageField.style = mrdImageFieldCss();
2808
+
2809
+ /** Key an embedded view is addressed by (setViewPage etc.). */
2810
+ function viewKeyFor(item) {
2811
+ var _a, _b, _c, _d;
2812
+ if (item.type === ClientLayoutItemType.RELATED_VIEW)
2813
+ return (_b = (_a = item.relatedClass) !== null && _a !== void 0 ? _a : item.name) !== null && _b !== void 0 ? _b : '';
2814
+ return (_d = (_c = item.dataClass) !== null && _c !== void 0 ? _c : item.name) !== null && _d !== void 0 ? _d : '';
2815
+ }
2816
+ /** Depth-first flatten of the SECTION/GROUP tree. */
2817
+ function flattenItems(items) {
2818
+ const result = [];
2819
+ for (const item of items) {
2820
+ result.push(item);
2821
+ if (item.items)
2822
+ result.push(...flattenItems(item.items));
2823
+ }
2824
+ return result;
2825
+ }
2826
+ /** Build the canonical parent href `/{base}/{tenant}/{fromClass}/{parentId}` from
2827
+ * the object's self href. Empty unless it is a RELATED_VIEW with a fromClass. */
2828
+ function buildContainerHref(item, selfHref, parentId) {
2829
+ if (item.type !== ClientLayoutItemType.RELATED_VIEW || !item.fromClass || !parentId)
2830
+ return '';
2831
+ const segs = selfHref.split('/').filter(Boolean);
2832
+ if (segs.length < 2)
2833
+ return '';
2834
+ const [base, tenant] = segs;
2835
+ return `/${base}/${tenant}/${item.fromClass}/${parentId}`;
2836
+ }
2736
2837
 
2737
2838
  class CellRenderer {
2738
2839
  static render(column, row, locale) {
@@ -2838,7 +2939,114 @@ class CellRenderer {
2838
2939
  }
2839
2940
  }
2840
2941
 
2841
- 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}`;
2942
+ /** FILE and IMAGE cells share the same download button. */
2943
+ function downloadLink(ctx, href, fileName, label) {
2944
+ 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));
2945
+ }
2946
+ function renderSingleFieldValue(ctx, 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 downloadLink(ctx, href, fileName, t('download', ctx.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 = ctx.imagePreviews[item.name];
2973
+ if (previewUrl) {
2974
+ 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 })));
2975
+ }
2976
+ return downloadLink(ctx, href, fileName, 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', ctx.locale) : t('no', ctx.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 : [], ctx.locale);
2997
+ return text || null;
2998
+ }
2999
+ }
3000
+ }
3001
+ function renderFieldValue(ctx, item, rawValue) {
3002
+ if (rawValue == null || rawValue === '')
3003
+ return null;
3004
+ if (item.multiple && Array.isArray(rawValue)) {
3005
+ const rendered = rawValue.map(v => renderSingleFieldValue(ctx, 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 renderSingleFieldValue(ctx, item, rawValue);
3012
+ }
3013
+ function renderHistoryBadge(ctx, 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 = ctx.openHistoryField === item.name;
3023
+ 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) => {
3024
+ e.stopPropagation();
3025
+ ctx.on.toggleHistory(isOpen ? null : item.name);
3026
+ } }, 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), ")")))))));
3027
+ }
3028
+ function renderField(ctx, item) {
3029
+ var _a, _b;
3030
+ if (!item.name)
3031
+ return null;
3032
+ const raw = ctx.data[item.name];
3033
+ const hist = (_a = item.historyEnabled) !== null && _a !== void 0 ? _a : (_b = item.field) === null || _b === void 0 ? void 0 : _b.historyEnabled;
3034
+ const rawValue = hist && raw !== null && typeof raw === 'object' && 'current' in raw
3035
+ ? raw.current
3036
+ : raw;
3037
+ const renderedValue = renderFieldValue(ctx, item, rawValue);
3038
+ if (item.header) {
3039
+ return (h("h1", { class: "mrd-layout-section__field-header", key: item.name }, typeof renderedValue === 'string' ? renderedValue : rawValue != null ? String(rawValue) : item.label));
3040
+ }
3041
+ if (renderedValue == null)
3042
+ return null;
3043
+ const isBlock = item.dataType === ClientLayoutItemFieldDataType.TEXTBLOCK
3044
+ || item.dataType === ClientLayoutItemFieldDataType.LONGTEXT
3045
+ || item.dataType === ClientLayoutItemFieldDataType.JSON;
3046
+ 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))));
3047
+ }
3048
+
3049
+ 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}`;
2842
3050
 
2843
3051
  const MrdLayoutSection = class {
2844
3052
  constructor(hostRef) {
@@ -2920,14 +3128,8 @@ const MrdLayoutSection = class {
2920
3128
  }
2921
3129
  }
2922
3130
  }
2923
- viewKeyFor(item) {
2924
- var _a, _b, _c, _d;
2925
- if (item.type === ClientLayoutItemType.RELATED_VIEW)
2926
- return (_b = (_a = item.relatedClass) !== null && _a !== void 0 ? _a : item.name) !== null && _b !== void 0 ? _b : '';
2927
- return (_d = (_c = item.dataClass) !== null && _c !== void 0 ? _c : item.name) !== null && _d !== void 0 ? _d : '';
2928
- }
2929
3131
  emitLoadImages() {
2930
- for (const item of this.flattenItems(this.items)) {
3132
+ for (const item of flattenItems(this.items)) {
2931
3133
  if (item.type === ClientLayoutItemType.FIELD && item.dataType === ClientLayoutItemFieldDataType.IMAGE) {
2932
3134
  const fieldName = item.name;
2933
3135
  const raw = this.data[fieldName];
@@ -2937,15 +3139,6 @@ const MrdLayoutSection = class {
2937
3139
  }
2938
3140
  }
2939
3141
  }
2940
- flattenItems(items) {
2941
- const result = [];
2942
- for (const item of items) {
2943
- result.push(item);
2944
- if (item.items)
2945
- result.push(...this.flattenItems(item.items));
2946
- }
2947
- return result;
2948
- }
2949
3142
  /** Inject search results. Pass dataClass to target a specific SEARCH item; omit when there is only one. */
2950
3143
  async setSearchResults(results, dataClass) {
2951
3144
  const key = dataClass !== null && dataClass !== void 0 ? dataClass : this.resolveSearchKey();
@@ -3011,113 +3204,26 @@ const MrdLayoutSection = class {
3011
3204
  }
3012
3205
  resolveSearchKey() {
3013
3206
  var _a;
3014
- const items = this.flattenItems(this.items).filter(i => i.type === ClientLayoutItemType.SEARCH);
3207
+ const items = flattenItems(this.items).filter(i => i.type === ClientLayoutItemType.SEARCH);
3015
3208
  if (items.length === 1)
3016
3209
  return (_a = items[0].dataClass) !== null && _a !== void 0 ? _a : null;
3017
3210
  return null;
3018
3211
  }
3019
- renderSingleFieldValue(item, value) {
3020
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
3021
- const dt = item.dataType;
3022
- switch (dt) {
3023
- case ClientLayoutItemFieldDataType.HYPERLINK: {
3024
- const v = value;
3025
- const href = (_a = v === null || v === void 0 ? void 0 : v.href) !== null && _a !== void 0 ? _a : String(value);
3026
- 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;
3027
- return (h("a", { class: "mrd-layout-section__link", href: href, target: "_blank", rel: "noopener noreferrer" }, label));
3028
- }
3029
- case ClientLayoutItemFieldDataType.TEXTBLOCK:
3030
- return h("div", { class: "mrd-layout-section__prose", innerHTML: String(value) });
3031
- case ClientLayoutItemFieldDataType.LONGTEXT:
3032
- return h("pre", { class: "mrd-layout-section__pre" }, String(value));
3033
- case ClientLayoutItemFieldDataType.JSON:
3034
- return h("pre", { class: "mrd-layout-section__pre", innerHTML: CellRenderer.formatJson(value) });
3035
- case ClientLayoutItemFieldDataType.FILE: {
3036
- const v = value;
3037
- const fileName = (_e = v === null || v === void 0 ? void 0 : v.fileName) !== null && _e !== void 0 ? _e : String(value);
3038
- const href = (_f = v === null || v === void 0 ? void 0 : v.href) !== null && _f !== void 0 ? _f : '';
3039
- 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)));
3040
- }
3041
- case ClientLayoutItemFieldDataType.IMAGE: {
3042
- const v = value;
3043
- const href = (_g = v === null || v === void 0 ? void 0 : v.href) !== null && _g !== void 0 ? _g : '';
3044
- const fileName = (_h = v === null || v === void 0 ? void 0 : v.fileName) !== null && _h !== void 0 ? _h : '';
3045
- const previewUrl = this.imagePreviews[item.name];
3046
- if (previewUrl) {
3047
- 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 })));
3048
- }
3049
- 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));
3050
- }
3051
- case ClientLayoutItemFieldDataType.BOOLEAN:
3052
- return (h("span", { class: `mrd-layout-section__boolean mrd-layout-section__boolean--${value ? 'true' : 'false'}` }, value ? t('yes', this.locale) : t('no', this.locale)));
3053
- case ClientLayoutItemFieldDataType.LIST: {
3054
- const listItem = ((_j = item.listItems) !== null && _j !== void 0 ? _j : []).find(li => li.key === String(value));
3055
- const label = (_k = listItem === null || listItem === void 0 ? void 0 : listItem.label) !== null && _k !== void 0 ? _k : String(value);
3056
- const color = listItem === null || listItem === void 0 ? void 0 : listItem.color;
3057
- const bg = listItem === null || listItem === void 0 ? void 0 : listItem.backgroundColor;
3058
- if (color && bg) {
3059
- return (h("span", { class: "mrd-layout-section__badge", style: { color, backgroundColor: bg } }, label));
3060
- }
3061
- if (color) {
3062
- return (h("span", { class: "mrd-layout-section__badge-dot-row" }, h("span", { class: "mrd-layout-section__badge-dot", style: { backgroundColor: color } }), label));
3063
- }
3064
- return label;
3065
- }
3066
- case ClientLayoutItemFieldDataType.SECRET:
3067
- return value ? h("span", { class: "mrd-layout-section__secret-masked" }, '••••••••') : null;
3068
- default: {
3069
- const text = CellRenderer.renderValue(dt, value, (_l = item.listItems) !== null && _l !== void 0 ? _l : [], this.locale);
3070
- return text || null;
3071
- }
3072
- }
3073
- }
3074
- renderFieldValue(item, rawValue) {
3075
- if (rawValue == null || rawValue === '')
3076
- return null;
3077
- if (item.multiple && Array.isArray(rawValue)) {
3078
- const rendered = rawValue.map(v => this.renderSingleFieldValue(item, v));
3079
- if (rendered.every(r => typeof r === 'string' || r == null)) {
3080
- return rendered.filter(Boolean).join(', ') || null;
3081
- }
3082
- return (h("span", null, rendered.map((r, i) => (h("span", { key: String(i) }, r, i < rendered.length - 1 ? ', ' : '')))));
3083
- }
3084
- return this.renderSingleFieldValue(item, rawValue);
3085
- }
3086
- renderHistoryBadge(item, raw) {
3087
- var _a, _b, _c;
3088
- const hist = (_a = item.historyEnabled) !== null && _a !== void 0 ? _a : (_b = item.field) === null || _b === void 0 ? void 0 : _b.historyEnabled;
3089
- if (!hist || !item.name)
3090
- return null;
3091
- const history = (_c = raw === null || raw === void 0 ? void 0 : raw.history) !== null && _c !== void 0 ? _c : [];
3092
- if (!history.length)
3093
- return null;
3094
- const sorted = [...history].sort((a, b) => b.until.localeCompare(a.until));
3095
- const isOpen = this.openHistoryField === item.name;
3096
- const { locale } = this;
3097
- 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) => {
3098
- e.stopPropagation();
3099
- this.openHistoryField = isOpen ? null : item.name;
3100
- } }, 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), ")")))))));
3212
+ fieldCtx() {
3213
+ return {
3214
+ locale: this.locale,
3215
+ data: this.data,
3216
+ imagePreviews: this.imagePreviews,
3217
+ openHistoryField: this.openHistoryField,
3218
+ on: {
3219
+ download: detail => this.mrdDownload.emit(detail),
3220
+ openImage: url => { this.imagePreviewUrl = url; },
3221
+ toggleHistory: fieldName => { this.openHistoryField = fieldName; },
3222
+ },
3223
+ };
3101
3224
  }
3102
3225
  renderField(item) {
3103
- var _a, _b;
3104
- if (!item.name)
3105
- return null;
3106
- const raw = this.data[item.name];
3107
- const hist = (_a = item.historyEnabled) !== null && _a !== void 0 ? _a : (_b = item.field) === null || _b === void 0 ? void 0 : _b.historyEnabled;
3108
- const rawValue = hist && raw !== null && typeof raw === 'object' && 'current' in raw
3109
- ? raw.current
3110
- : raw;
3111
- const renderedValue = this.renderFieldValue(item, rawValue);
3112
- if (item.header) {
3113
- return (h("h1", { class: "mrd-layout-section__field-header", key: item.name }, typeof renderedValue === 'string' ? renderedValue : rawValue != null ? String(rawValue) : item.label));
3114
- }
3115
- if (renderedValue == null)
3116
- return null;
3117
- const isBlock = item.dataType === ClientLayoutItemFieldDataType.TEXTBLOCK
3118
- || item.dataType === ClientLayoutItemFieldDataType.LONGTEXT
3119
- || item.dataType === ClientLayoutItemFieldDataType.JSON;
3120
- 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))));
3226
+ return renderField(this.fieldCtx(), item);
3121
3227
  }
3122
3228
  renderRelation(item) {
3123
3229
  var _a, _b, _c;
@@ -3150,7 +3256,7 @@ const MrdLayoutSection = class {
3150
3256
  }
3151
3257
  renderRelatedView(item) {
3152
3258
  var _a, _b, _c, _d, _e, _f, _g, _h;
3153
- const key = this.viewKeyFor(item);
3259
+ const key = viewKeyFor(item);
3154
3260
  if (!key)
3155
3261
  return null;
3156
3262
  if (!item.view)
@@ -3165,22 +3271,11 @@ const MrdLayoutSection = class {
3165
3271
  // Canonical parent href for single-container seeding: use the RELATED_VIEW's
3166
3272
  // fromClass (base class) rather than the route class, so polymorphic subtypes
3167
3273
  // resolve to the same container the documents actually reference.
3168
- const containerHref = this.buildContainerHref(item, selfHref, parentId);
3274
+ const containerHref = buildContainerHref(item, selfHref, parentId);
3169
3275
  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
3170
3276
  ? this.renderDocumentContainer(item, key, parentId, docArchetype, containerHref)
3171
3277
  : this.renderTable(item, key, parentId)));
3172
3278
  }
3173
- /** Build the canonical parent href `/{base}/{tenant}/{fromClass}/{parentId}` from
3174
- * the object's self href. Empty unless it is a RELATED_VIEW with a fromClass. */
3175
- buildContainerHref(item, selfHref, parentId) {
3176
- if (item.type !== ClientLayoutItemType.RELATED_VIEW || !item.fromClass || !parentId)
3177
- return '';
3178
- const segs = selfHref.split('/').filter(Boolean);
3179
- if (segs.length < 2)
3180
- return '';
3181
- const [base, tenant] = segs;
3182
- return `/${base}/${tenant}/${item.fromClass}/${parentId}`;
3183
- }
3184
3279
  /** Document collection view: owns the view-switch + collection actions and
3185
3280
  * swaps between the folder tree and the flat table. Events are re-emitted to
3186
3281
  * the host with the view key, exactly as the raw list/table events were. */
@@ -3281,7 +3376,7 @@ const MrdLayoutSection = class {
3281
3376
  }
3282
3377
  render() {
3283
3378
  const docArchetype = resolveArchetype(this.archetypes, ARCHETYPE_DOCUMENT);
3284
- return (h(Host, { key: '231f5c3e282375b5850291611645fe3c904831bb' }, h("div", { key: '314e39ec3aa1eabeb1a98f6e6d63fcf07e13ccec', class: "mrd-layout-section" }, docArchetype
3379
+ return (h(Host, { key: '5d778188356a25ea13d45745dc5ed573ab2b2ef0' }, h("div", { key: '0b673a4bcf8b36cd21662bb8a3506cc3f30edb04', class: "mrd-layout-section" }, docArchetype
3285
3380
  ? this.renderDocumentObject(docArchetype)
3286
3381
  : this.items.map(item => this.renderItem(item))), this.renderImageModal()));
3287
3382
  }
@@ -3292,9 +3387,9 @@ const MrdLayoutSection = class {
3292
3387
  }]
3293
3388
  }; }
3294
3389
  };
3295
- MrdLayoutSection.style = mrdLayoutSectionScss();
3390
+ MrdLayoutSection.style = mrdLayoutSectionCss();
3296
3391
 
3297
- 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)}`;
3392
+ 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}`;
3298
3393
 
3299
3394
  const MrdListField = class {
3300
3395
  constructor(hostRef) {
@@ -3317,22 +3412,12 @@ const MrdListField = class {
3317
3412
  if (this.multiple) {
3318
3413
  const vals = Array.from(select.selectedOptions).map(o => o.value);
3319
3414
  this.selected = vals;
3320
- if (this.required && !validateRequired(vals)) {
3321
- this.error = t('required', this.locale);
3322
- }
3323
- else {
3324
- this.error = '';
3325
- }
3415
+ this.error = requiredError(vals, this.required, this.locale);
3326
3416
  this.mrdChange.emit({ name: this.name, value: vals });
3327
3417
  }
3328
3418
  else {
3329
3419
  const val = select.value;
3330
- if (this.required && !validateRequired(val)) {
3331
- this.error = t('required', this.locale);
3332
- }
3333
- else {
3334
- this.error = '';
3335
- }
3420
+ this.error = requiredError(val, this.required, this.locale);
3336
3421
  this.mrdChange.emit({ name: this.name, value: val });
3337
3422
  }
3338
3423
  };
@@ -3347,12 +3432,7 @@ const MrdListField = class {
3347
3432
  else {
3348
3433
  this.selected = [...this.selected, key];
3349
3434
  }
3350
- if (this.required && !validateRequired(this.selected)) {
3351
- this.error = t('required', this.locale);
3352
- }
3353
- else {
3354
- this.error = '';
3355
- }
3435
+ this.error = requiredError(this.selected, this.required, this.locale);
3356
3436
  this.mrdChange.emit({ name: this.name, value: this.selected });
3357
3437
  };
3358
3438
  }
@@ -3376,22 +3456,22 @@ const MrdListField = class {
3376
3456
  const hasError = !!this.error;
3377
3457
  const currentValue = Array.isArray(this.value) ? ((_a = this.value[0]) !== null && _a !== void 0 ? _a : '') : ((_b = this.value) !== null && _b !== void 0 ? _b : '');
3378
3458
  if (this.multiple) {
3379
- 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 => {
3459
+ 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 => {
3380
3460
  var _a, _b;
3381
3461
  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)));
3382
- })), hasError && h("span", { class: "mrd-list-field__error" }, this.error))));
3462
+ })), h(FieldError, { base: "mrd-list-field", error: this.error }))));
3383
3463
  }
3384
- 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 => {
3464
+ 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 => {
3385
3465
  var _a, _b;
3386
3466
  const bg = (_b = (_a = lv.backgroundColor) !== null && _a !== void 0 ? _a : lv.color) !== null && _b !== void 0 ? _b : null;
3387
3467
  const style = bg ? { backgroundColor: bg, color: this.getContrastColor(bg) } : {};
3388
3468
  return (h("option", { key: lv.key, value: lv.key, selected: lv.key === currentValue, style: style }, lv.label));
3389
- })), hasError && h("span", { class: "mrd-list-field__error" }, this.error))));
3469
+ })), h(FieldError, { base: "mrd-list-field", error: this.error }))));
3390
3470
  }
3391
3471
  };
3392
- MrdListField.style = mrdListFieldScss();
3472
+ MrdListField.style = mrdListFieldCss();
3393
3473
 
3394
- 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)}`;
3474
+ 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}`;
3395
3475
 
3396
3476
  const MrdLongtextField = class {
3397
3477
  constructor(hostRef) {
@@ -3412,23 +3492,17 @@ const MrdLongtextField = class {
3412
3492
  };
3413
3493
  this.handleBlur = (e) => {
3414
3494
  const val = e.target.value;
3415
- if (this.required && !validateRequired(val)) {
3416
- this.error = t('required', this.locale);
3417
- }
3418
- else {
3419
- this.error = '';
3420
- }
3495
+ this.error = requiredError(val, this.required, this.locale);
3421
3496
  this.mrdBlur.emit({ name: this.name, value: val });
3422
3497
  };
3423
3498
  }
3424
3499
  render() {
3425
- const hasError = !!this.error;
3426
- 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))));
3500
+ 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 }))));
3427
3501
  }
3428
3502
  };
3429
- MrdLongtextField.style = mrdLongtextFieldScss();
3503
+ MrdLongtextField.style = mrdLongtextFieldCss();
3430
3504
 
3431
- 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)}`;
3505
+ 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)}`;
3432
3506
 
3433
3507
  const MrdNumberField = class {
3434
3508
  constructor(hostRef) {
@@ -3499,12 +3573,12 @@ const MrdNumberField = class {
3499
3573
  const hasError = !!this.error;
3500
3574
  const suffix = this.dataType === ClientLayoutItemFieldDataType.PERCENTAGE ? '%' :
3501
3575
  this.dataType === ClientLayoutItemFieldDataType.DECIMAL ? '' : '';
3502
- 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))));
3576
+ 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 }))));
3503
3577
  }
3504
3578
  };
3505
- MrdNumberField.style = mrdNumberFieldScss();
3579
+ MrdNumberField.style = mrdNumberFieldCss();
3506
3580
 
3507
- 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)}`;
3581
+ 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}`;
3508
3582
 
3509
3583
  const MrdRelationField = class {
3510
3584
  constructor(hostRef) {
@@ -3605,12 +3679,7 @@ const MrdRelationField = class {
3605
3679
  this.showResults = false;
3606
3680
  this.mrdChange.emit({ name: this.name, value: result.id });
3607
3681
  }
3608
- if (this.required && !validateRequired(this.selectedItems)) {
3609
- this.error = t('required', this.locale);
3610
- }
3611
- else {
3612
- this.error = '';
3613
- }
3682
+ this.error = requiredError(this.selectedItems, this.required, this.locale);
3614
3683
  };
3615
3684
  this.handleRemoveSelected = (id) => {
3616
3685
  this.selectedItems = this.selectedItems.filter(i => i.id !== id);
@@ -3619,12 +3688,7 @@ const MrdRelationField = class {
3619
3688
  };
3620
3689
  this.handleDropdownChange = (e) => {
3621
3690
  const val = e.target.value;
3622
- if (this.required && !validateRequired(val)) {
3623
- this.error = t('required', this.locale);
3624
- }
3625
- else {
3626
- this.error = '';
3627
- }
3691
+ this.error = requiredError(val, this.required, this.locale);
3628
3692
  this.mrdChange.emit({ name: this.name, value: val });
3629
3693
  };
3630
3694
  this.handleBlur = () => {
@@ -3735,19 +3799,19 @@ const MrdRelationField = class {
3735
3799
  const hasError = !!this.error;
3736
3800
  if (this.editBehavior === ClientLayoutItemRelationEditBehavior.DROPDOWN) {
3737
3801
  const currentValue = this.getValueHref();
3738
- 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))));
3802
+ 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 }))));
3739
3803
  }
3740
3804
  if (this.displayType === ClientLayoutItemRelationDisplayType.DROPDOWN) {
3741
3805
  const currentValue = Array.isArray(this.value) ? ((_a = this.value[0]) !== null && _a !== void 0 ? _a : '') : ((_b = this.value) !== null && _b !== void 0 ? _b : '');
3742
- 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))));
3806
+ 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 }))));
3743
3807
  }
3744
3808
  // SEARCH mode
3745
- const labelEl = this.label && (h("label", { class: `mrd-relation-field__label${this.required ? ' mrd-relation-field__label--required' : ''}` }, this.label));
3809
+ const labelEl = h(FieldLabel, { base: "mrd-relation-field", label: this.label, required: this.required });
3746
3810
  // Single selection: show selected value as a badge, hide the search input
3747
3811
  if (!this.multiple && this.selectedItems.length > 0) {
3748
- 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))));
3812
+ 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 }))));
3749
3813
  }
3750
- 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))));
3814
+ 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 }))));
3751
3815
  }
3752
3816
  get el() { return getElement(this); }
3753
3817
  static get watchers() { return {
@@ -3759,9 +3823,9 @@ const MrdRelationField = class {
3759
3823
  }]
3760
3824
  }; }
3761
3825
  };
3762
- MrdRelationField.style = mrdRelationFieldScss();
3826
+ MrdRelationField.style = mrdRelationFieldCss();
3763
3827
 
3764
- 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}`;
3828
+ 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}`;
3765
3829
 
3766
3830
  const MrdSecretField = class {
3767
3831
  constructor(hostRef) {
@@ -3782,42 +3846,460 @@ const MrdSecretField = class {
3782
3846
  };
3783
3847
  this.handleBlur = (e) => {
3784
3848
  const val = e.target.value;
3785
- if (this.required && !validateRequired(val)) {
3786
- this.error = t('required', this.locale);
3787
- }
3788
- else {
3789
- this.error = '';
3790
- }
3849
+ this.error = requiredError(val, this.required, this.locale);
3791
3850
  this.mrdBlur.emit({ name: this.name, value: val });
3792
3851
  };
3793
3852
  }
3794
3853
  render() {
3795
- const hasError = !!this.error;
3796
- 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
3854
+ 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
3797
3855
  ? (h("span", { class: "mrd-secret-field__masked", "aria-label": this.label }, this.value ? '••••••••' : ''))
3798
- : (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))));
3856
+ : (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 }))));
3799
3857
  }
3800
3858
  };
3801
- MrdSecretField.style = mrdSecretFieldScss();
3859
+ MrdSecretField.style = mrdSecretFieldCss();
3802
3860
 
3803
- 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}`;
3804
-
3805
- const BUFFER = 10;
3806
- /** Wacht deze tijd (ms) na het laatste scroll-event voordat pagina's worden
3807
- * aangevraagd. Pagina's die de gebruiker snel voorbij scrollt worden zo geskipt. */
3808
- const REQUEST_DEBOUNCE_MS = 150;
3809
- /** Breedte van de filterpopup in px — voor overflow-correctie. */
3810
- const POPUP_WIDTH = 280;
3861
+ /**
3862
+ * Pure sort/filter/aggregation query logic for mrd-table.
3863
+ * No component state — everything is passed in.
3864
+ */
3811
3865
  const TEXT_TYPES = new Set(['TEXT', 'TEXTBLOCK', 'EMAIL', 'HYPERLINK']);
3812
3866
  const NUMERIC_TYPES = new Set(['INTEGER', 'DECIMAL', 'PERCENTAGE', 'CURRENCY']);
3813
3867
  const DATE_TYPES = new Set(['DATE', 'DATETIME', 'TIME']);
3814
3868
  const NO_FILTER_TYPES = new Set(['FILE', 'IMAGE']);
3815
3869
  /** Column types that cannot be sorted or filtered (not stored in PostgreSQL). */
3816
3870
  const NON_INTERACTIVE_TYPES = new Set(['LONGTEXT', 'JSON', 'FILE', 'IMAGE']);
3871
+ function parseDefaultSort(defaultSort) {
3872
+ var _a;
3873
+ if (!defaultSort)
3874
+ return { field: '', dir: 'asc' };
3875
+ const parts = defaultSort.split(',');
3876
+ return { field: parts[0].trim(), dir: ((_a = parts[1]) === null || _a === void 0 ? void 0 : _a.trim()) === 'desc' ? 'desc' : 'asc' };
3877
+ }
3878
+ /** Raw sort query-param value, e.g. "name" or "name,desc". */
3879
+ function buildSortParam(field, dir) {
3880
+ if (!field)
3881
+ return '';
3882
+ return dir === 'desc' ? `${field},desc` : field;
3883
+ }
3884
+ /** Query params for a page request: page + sort + filterClass + view filters + active column filters. */
3885
+ function buildTableQueryParams(opts) {
3886
+ var _a, _b;
3887
+ const p = new URLSearchParams();
3888
+ if (opts.page > 0)
3889
+ p.set('page', String(opts.page));
3890
+ if (opts.sort)
3891
+ p.set('sort', opts.sort);
3892
+ if (opts.filterClass)
3893
+ p.set('type', opts.filterClass);
3894
+ applyViewFilters(p, opts.viewFilters);
3895
+ for (const f of opts.activeFilters) {
3896
+ if (f.operator === 'isEmpty') {
3897
+ p.set(f.field, '');
3898
+ continue;
3899
+ }
3900
+ if (f.operator === 'isNotEmpty') {
3901
+ p.set(f.field + '_notempty', 'true');
3902
+ continue;
3903
+ }
3904
+ if (f.operator === 'startsWith') {
3905
+ p.set(f.field + '_startswith', String((_a = f.value) !== null && _a !== void 0 ? _a : ''));
3906
+ continue;
3907
+ }
3908
+ if ((_b = f.values) === null || _b === void 0 ? void 0 : _b.length) {
3909
+ p.set(f.field, f.values.join(','));
3910
+ continue;
3911
+ }
3912
+ if (f.value != null)
3913
+ p.set(f.field, String(f.value));
3914
+ if (f.from != null)
3915
+ p.set(f.field + '_from', String(f.from));
3916
+ if (f.to != null)
3917
+ p.set(f.field + '_to', String(f.to));
3918
+ }
3919
+ return p.toString();
3920
+ }
3921
+ /** Groups aggregate columns by function; null when the view has no aggregates. */
3922
+ function buildAggregationParams(columns) {
3923
+ var _a;
3924
+ const groups = { sum: [], avg: [], count: [] };
3925
+ for (const col of columns) {
3926
+ if (col.type !== 'FIELD' || !col.aggregate)
3927
+ continue;
3928
+ const fn = col.aggregate.toLowerCase();
3929
+ if (fn in groups)
3930
+ groups[fn].push((_a = col.name) !== null && _a !== void 0 ? _a : '');
3931
+ }
3932
+ const params = {};
3933
+ if (groups.sum.length)
3934
+ params.sum = groups.sum;
3935
+ if (groups.avg.length)
3936
+ params.avg = groups.avg;
3937
+ if (groups.count.length)
3938
+ params.count = groups.count;
3939
+ return Object.keys(params).length > 0 ? params : null;
3940
+ }
3941
+ /** Aggregation query string: the page-0 query params without page/sort, plus sum/avg/count. */
3942
+ function buildAggregationQs(basePageQs, columns) {
3943
+ var _a, _b, _c;
3944
+ const p = new URLSearchParams(basePageQs);
3945
+ p.delete('page');
3946
+ p.delete('sort');
3947
+ const groups = buildAggregationParams(columns);
3948
+ if ((_a = groups === null || groups === void 0 ? void 0 : groups.sum) === null || _a === void 0 ? void 0 : _a.length)
3949
+ p.set('sum', groups.sum.join(','));
3950
+ if ((_b = groups === null || groups === void 0 ? void 0 : groups.avg) === null || _b === void 0 ? void 0 : _b.length)
3951
+ p.set('avg', groups.avg.join(','));
3952
+ if ((_c = groups === null || groups === void 0 ? void 0 : groups.count) === null || _c === void 0 ? void 0 : _c.length)
3953
+ p.set('count', groups.count.join(','));
3954
+ return p.toString();
3955
+ }
3956
+ /** True when the pending filter actually constrains anything. */
3957
+ function filterHasValue(f) {
3958
+ if (f.operator === 'isEmpty' || f.operator === 'isNotEmpty')
3959
+ return true;
3960
+ if (f.values !== undefined && f.values.length > 0)
3961
+ return true;
3962
+ if (f.value != null && f.value !== '')
3963
+ return true;
3964
+ if (typeof f.value === 'boolean')
3965
+ return true;
3966
+ if (f.from != null && f.from !== '')
3967
+ return true;
3968
+ if (f.to != null && f.to !== '')
3969
+ return true;
3970
+ return false;
3971
+ }
3972
+ // ── DATETIME filters: the user edits local "YYYY-MM-DD" dates, the API stores UTC ISO ──
3973
+ /** UTC ISO string at the start (midnight) of the given local day. */
3974
+ function dateLocalToUTCStart(dateStr) {
3975
+ if (!dateStr)
3976
+ return dateStr;
3977
+ const [year, month, day] = dateStr.split('-').map(Number);
3978
+ return new Date(year, month - 1, day).toISOString().replace(/\.\d{3}Z$/, 'Z');
3979
+ }
3980
+ /** Start of the day AFTER the given local date (exclusive range end). */
3981
+ function dateLocalToUTCEndExclusive(dateStr) {
3982
+ if (!dateStr)
3983
+ return dateStr;
3984
+ const [year, month, day] = dateStr.split('-').map(Number);
3985
+ return new Date(year, month - 1, day + 1).toISOString().replace(/\.\d{3}Z$/, 'Z');
3986
+ }
3987
+ /** Stored UTC ISO string back to the local "YYYY-MM-DD" date. */
3988
+ function utcISOToLocalDate(utcStr) {
3989
+ if (!utcStr)
3990
+ return utcStr;
3991
+ const d = new Date(utcStr);
3992
+ if (isNaN(d.getTime()))
3993
+ return utcStr;
3994
+ return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
3995
+ }
3996
+ /** The stored "to" is the exclusive end (next midnight); subtract a day to recover the entered date. */
3997
+ function utcISOToLocalDateExclusiveEnd(utcStr) {
3998
+ if (!utcStr)
3999
+ return utcStr;
4000
+ const d = new Date(utcStr);
4001
+ if (isNaN(d.getTime()))
4002
+ return utcStr;
4003
+ d.setDate(d.getDate() - 1);
4004
+ return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
4005
+ }
4006
+ /** Applies the local→UTC conversion when a DATETIME filter is submitted.
4007
+ * Exact date → range covering the full local day. */
4008
+ function normalizeDatetimeFilter(f) {
4009
+ const normalized = Object.assign({}, f);
4010
+ if (f.dataType === 'DATETIME' && f.operator !== 'isEmpty' && f.operator !== 'isNotEmpty') {
4011
+ if (typeof normalized.value === 'string' && normalized.value) {
4012
+ normalized.from = dateLocalToUTCStart(normalized.value);
4013
+ normalized.to = dateLocalToUTCEndExclusive(normalized.value);
4014
+ normalized.value = undefined;
4015
+ }
4016
+ else {
4017
+ if (typeof normalized.from === 'string' && normalized.from)
4018
+ normalized.from = dateLocalToUTCStart(normalized.from);
4019
+ if (typeof normalized.to === 'string' && normalized.to)
4020
+ normalized.to = dateLocalToUTCEndExclusive(normalized.to);
4021
+ }
4022
+ }
4023
+ return normalized;
4024
+ }
4025
+ /** Converts a stored DATETIME filter back to local dates for the popup.
4026
+ * A range covering a single local day is restored to exact-date mode. */
4027
+ function datetimeFilterToDisplay(existing) {
4028
+ const display = Object.assign({}, existing);
4029
+ if (typeof display.from === 'string' && display.from)
4030
+ display.from = utcISOToLocalDate(display.from);
4031
+ if (typeof display.to === 'string' && display.to)
4032
+ display.to = utcISOToLocalDateExclusiveEnd(display.to);
4033
+ if (display.from && display.to && display.from === display.to) {
4034
+ return Object.assign(Object.assign({}, display), { value: display.from, from: undefined, to: undefined });
4035
+ }
4036
+ return display;
4037
+ }
4038
+
4039
+ /**
4040
+ * Stateless render parts of mrd-table. All state and handlers stay in the
4041
+ * component; these components receive plain values and callbacks.
4042
+ */
4043
+ 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" }))));
4044
+ const TEXTBLOCK_MAX = 200;
4045
+ const TableCell = ({ col, row, locale, onDownload, onOpenTextblock, onOpenJson }) => {
4046
+ var _a, _b, _c;
4047
+ const dataType = (_a = col.dataType) !== null && _a !== void 0 ? _a : '';
4048
+ const isNumeric = col.type === 'FIELD' && NUMERIC_TYPES.has(dataType);
4049
+ const isFile = col.type === 'FIELD' && (dataType === 'FILE' || dataType === 'IMAGE');
4050
+ if (isFile) {
4051
+ const name = (_b = col.name) !== null && _b !== void 0 ? _b : '';
4052
+ const fileVal = row === null || row === void 0 ? void 0 : row[name];
4053
+ const href = fileVal === null || fileVal === void 0 ? void 0 : fileVal.href;
4054
+ const fileName = fileVal === null || fileVal === void 0 ? void 0 : fileVal.fileName;
4055
+ return (h("td", { class: "mrd-table__cell" }, href && fileName ? (h("button", { class: "mrd-table__file-btn", title: fileName, onClick: (e) => {
4056
+ e.stopPropagation();
4057
+ onDownload({ href, fileName });
4058
+ } }, 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))) : ''));
4059
+ }
4060
+ if (dataType === 'JSON') {
4061
+ const name = (_c = col.name) !== null && _c !== void 0 ? _c : '';
4062
+ const rawValue = name ? row === null || row === void 0 ? void 0 : row[name] : undefined;
4063
+ if (rawValue == null || rawValue === '')
4064
+ return h("td", { class: "mrd-table__cell" });
4065
+ const compactHtml = CellRenderer.formatJson(rawValue, true);
4066
+ const prettyHtml = CellRenderer.formatJson(rawValue, false);
4067
+ 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")));
4068
+ }
4069
+ if (dataType === 'TEXTBLOCK') {
4070
+ const full = CellRenderer.render(col, row, locale);
4071
+ if (full.length <= TEXTBLOCK_MAX) {
4072
+ return h("td", { class: "mrd-table__cell" }, full);
4073
+ }
4074
+ const preview = full.slice(0, TEXTBLOCK_MAX) + '…';
4075
+ 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")));
4076
+ }
4077
+ const value = CellRenderer.render(col, row, locale);
4078
+ return (h("td", { class: `mrd-table__cell${isNumeric ? ' mrd-table__cell--numeric' : ''}` }, value));
4079
+ };
4080
+ /** Formats the aggregation total for one column, '' when not applicable. */
4081
+ function formatAggregationValue(col, aggregations, locale) {
4082
+ var _a;
4083
+ if (col.type !== 'FIELD' || !col.aggregate || !aggregations)
4084
+ return '';
4085
+ const fn = col.aggregate.toLowerCase();
4086
+ const aggData = aggregations[fn];
4087
+ const val = typeof aggData === 'object' && aggData !== null
4088
+ ? aggData[(_a = col.name) !== null && _a !== void 0 ? _a : '']
4089
+ : undefined;
4090
+ if (val == null)
4091
+ return '';
4092
+ const dt = col.dataType;
4093
+ if (dt === 'INTEGER')
4094
+ return formatNumber(val, locale, { maximumFractionDigits: 0 });
4095
+ if (dt === 'PERCENTAGE')
4096
+ return formatPercentage(val, locale);
4097
+ if (dt === 'CURRENCY' && col.currencyCode)
4098
+ return formatCurrency(val, col.currencyCode, locale);
4099
+ return formatNumber(val, locale);
4100
+ }
4101
+ const TotalsRow = ({ columns, aggregations, locale }) => {
4102
+ if (!aggregations)
4103
+ return null;
4104
+ if (!columns.some(c => c.type === 'FIELD' && c.aggregate))
4105
+ return null;
4106
+ return (h("tfoot", null, h("tr", { class: "mrd-table__totals-row" }, columns.map(col => {
4107
+ var _a;
4108
+ const val = formatAggregationValue(col, aggregations, locale);
4109
+ const isNumeric = col.type === 'FIELD' && NUMERIC_TYPES.has((_a = col.dataType) !== null && _a !== void 0 ? _a : '');
4110
+ return (h("td", { class: `mrd-table__totals-cell${isNumeric ? ' mrd-table__totals-cell--numeric' : ''}` }, val));
4111
+ }))));
4112
+ };
4113
+ const TextblockModal = ({ text, locale, onClose }) => {
4114
+ if (text === null)
4115
+ return null;
4116
+ 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))));
4117
+ };
4118
+ const JsonModal = ({ html, locale, onClose }) => {
4119
+ if (html === null)
4120
+ return null;
4121
+ 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 }))));
4122
+ };
4123
+ const Toolbar = ({ locale, filterMode, filterCount, actions, views, activeViewIdx, viewPopoverOpen, createPickerOpen, createTypes, cb }) => {
4124
+ var _a;
4125
+ const hasActions = actions.length > 0;
4126
+ const hasViewSwitcher = views.length > 1;
4127
+ 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: () => {
4128
+ if (i !== activeViewIdx)
4129
+ cb.onViewSwitch(i);
4130
+ cb.onCloseViewPopover();
4131
+ } }, 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 => {
4132
+ var _a, _b;
4133
+ const pickerTypes = a.action === 'create' ? createTypes : null;
4134
+ if (pickerTypes === null || pickerTypes === void 0 ? void 0 : pickerTypes.length) {
4135
+ 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
4136
+ ? h("svg", { class: "mrd-table__action-icon", "aria-hidden": "true" }, h("use", { href: a.icon }))
4137
+ : 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)))))));
4138
+ }
4139
+ 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
4140
+ ? h("svg", { class: "mrd-table__action-icon", "aria-hidden": "true" }, h("use", { href: a.icon }))
4141
+ : a.label, h("span", { class: "mrd-table__action-tooltip" }, a.label)));
4142
+ })))));
4143
+ };
4144
+
4145
+ const FilterEditor = ({ col, dataType, openFilterCol, pendingFilter, locale, cb }) => {
4146
+ var _a, _b, _c, _d, _e, _f;
4147
+ const pf = pendingFilter;
4148
+ if (NO_FILTER_TYPES.has(dataType)) {
4149
+ return h("p", { class: "mrd-table__filter-no-support" }, t('filter_no_support', locale));
4150
+ }
4151
+ if (dataType === 'BOOLEAN') {
4152
+ const boolOp = pf.operator;
4153
+ const noValueOp = boolOp === 'isEmpty' || boolOp === 'isNotEmpty';
4154
+ return (h("div", { class: "mrd-table__filter-radio-group" }, [
4155
+ { labelKey: 'filter_all', value: null },
4156
+ { labelKey: 'yes', value: true },
4157
+ { labelKey: 'no', value: false },
4158
+ ].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))));
4159
+ }
4160
+ if (dataType === 'LIST') {
4161
+ const items = (_a = col.listItems) !== null && _a !== void 0 ? _a : [];
4162
+ const selected = (_b = pf.values) !== null && _b !== void 0 ? _b : [];
4163
+ 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)))));
4164
+ }
4165
+ if (TEXT_TYPES.has(dataType) || dataType === 'RELATION') {
4166
+ const op = (_c = pf.operator) !== null && _c !== void 0 ? _c : 'startsWith';
4167
+ const noInput = op === 'isEmpty' || op === 'isNotEmpty';
4168
+ return (h("div", { class: "mrd-table__filter-editor" }, h("select", { class: "mrd-table__filter-select", onChange: (e) => cb.onSetPending('operator', e.target.value) }, [
4169
+ { val: 'startsWith', labelKey: 'filter_starts_with' },
4170
+ { val: 'equals', labelKey: 'filter_equals' },
4171
+ { val: 'isEmpty', labelKey: 'filter_is_empty' },
4172
+ { val: 'isNotEmpty', labelKey: 'filter_is_not_empty' },
4173
+ ].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) }))));
4174
+ }
4175
+ if (NUMERIC_TYPES.has(dataType)) {
4176
+ const numOp = pf.operator;
4177
+ const noInput = numOp === 'isEmpty' || numOp === 'isNotEmpty';
4178
+ const rangeMode = !noInput && (pf.from !== undefined || pf.to !== undefined);
4179
+ return (h("div", { class: "mrd-table__filter-editor" }, h("select", { class: "mrd-table__filter-select", onChange: (e) => {
4180
+ const val = e.target.value;
4181
+ if (val === 'isEmpty' || val === 'isNotEmpty') {
4182
+ cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: val, value: undefined, from: undefined, to: undefined }));
4183
+ }
4184
+ else {
4185
+ cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: undefined }));
4186
+ }
4187
+ } }, 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) })))))));
4188
+ }
4189
+ if (dataType === 'DATETIME') {
4190
+ const dtOp = pf.operator;
4191
+ const noInput = dtOp === 'isEmpty' || dtOp === 'isNotEmpty';
4192
+ const rangeMode = !noInput && (pf.from !== undefined || pf.to !== undefined);
4193
+ return (h("div", { class: "mrd-table__filter-editor" }, h("select", { class: "mrd-table__filter-select", onChange: (e) => {
4194
+ const val = e.target.value;
4195
+ if (val === 'isEmpty' || val === 'isNotEmpty') {
4196
+ cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: val, value: undefined, from: undefined, to: undefined }));
4197
+ }
4198
+ else {
4199
+ cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: undefined }));
4200
+ }
4201
+ } }, 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) })))))));
4202
+ }
4203
+ if (DATE_TYPES.has(dataType)) {
4204
+ const inputType = dataType === 'DATE' ? 'date' : 'time';
4205
+ const dtdOp = pf.operator;
4206
+ const noInput = dtdOp === 'isEmpty' || dtdOp === 'isNotEmpty';
4207
+ const rangeMode = !noInput && (pf.from !== undefined || pf.to !== undefined);
4208
+ return (h("div", { class: "mrd-table__filter-editor" }, h("select", { class: "mrd-table__filter-select", onChange: (e) => {
4209
+ const val = e.target.value;
4210
+ if (val === 'isEmpty' || val === 'isNotEmpty') {
4211
+ cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: val, value: undefined, from: undefined, to: undefined }));
4212
+ }
4213
+ else {
4214
+ cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: undefined }));
4215
+ }
4216
+ } }, 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) })))))));
4217
+ }
4218
+ return null;
4219
+ };
4220
+ const FilterPopup = (props) => {
4221
+ var _a;
4222
+ const { col, openFilterCol, popupPos, sortField, sortDir, locale, cb } = props;
4223
+ const label = (_a = col.label) !== null && _a !== void 0 ? _a : openFilterCol;
4224
+ const sortActive = sortField === openFilterCol;
4225
+ 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)))));
4226
+ };
4227
+
4228
+ /**
4229
+ * Pure window/paging maths for the mrd-table virtual scroll.
4230
+ * The window state itself stays @State in the component; these
4231
+ * functions only compute values from it.
4232
+ */
4233
+ const BUFFER = 10;
4234
+ /** Wait this long (ms) after the last scroll event before requesting pages,
4235
+ * so pages the user quickly scrolls past are skipped. */
4236
+ const REQUEST_DEBOUNCE_MS = 150;
4237
+ /** Default time (ms) to wait for setPage() before treating a request as stale and retrying. */
4238
+ const REQUEST_TIMEOUT_MS = 15000;
4239
+ /** Max retries for a stale page request before giving up and showing a retry row. */
4240
+ const MAX_RETRY_ATTEMPTS = 3;
4241
+ function visibleCount(tableHeight, rowHeight) {
4242
+ return Math.ceil(tableHeight / rowHeight);
4243
+ }
4244
+ /** Render window (with buffer) for the given scroll offset. */
4245
+ function computeWindow(scrollTop, rowHeight, tableHeight, total) {
4246
+ const visStart = Math.floor(scrollTop / rowHeight);
4247
+ const visEnd = Math.min(visStart + visibleCount(tableHeight, rowHeight), total - 1);
4248
+ return {
4249
+ renderStart: Math.max(0, visStart - BUFFER),
4250
+ renderEnd: Math.min(total - 1, visEnd + BUFFER),
4251
+ };
4252
+ }
4253
+ /** First/last page (0-based) covering the given row window. */
4254
+ function pageRange(start, end, pageSize) {
4255
+ return { firstPage: Math.floor(start / pageSize), lastPage: Math.floor(end / pageSize) };
4256
+ }
4257
+ function getRowFromPages(pages, index, pageSize) {
4258
+ var _a;
4259
+ const page = pages.get(Math.floor(index / pageSize));
4260
+ return (_a = page === null || page === void 0 ? void 0 : page[index % pageSize]) !== null && _a !== void 0 ? _a : null;
4261
+ }
4262
+ /** Authoritative row count: a page shorter than pageSize is the last page,
4263
+ * so the true total cannot exceed its end index. */
4264
+ function computeEffectiveTotal(loadedPages, pageSize, baseTotal) {
4265
+ let effectiveTotal = baseTotal;
4266
+ for (const [pageNum, pageRows] of loadedPages) {
4267
+ if (pageRows.length < pageSize) {
4268
+ effectiveTotal = Math.min(effectiveTotal, pageNum * pageSize + pageRows.length);
4269
+ }
4270
+ }
4271
+ return effectiveTotal;
4272
+ }
4273
+ /** True when some loaded page was short — the exact total is then known. */
4274
+ function isTotalKnownFromPages(loadedPages, pageSize) {
4275
+ for (const rows of loadedPages.values()) {
4276
+ if (rows.length < pageSize)
4277
+ return true;
4278
+ }
4279
+ return false;
4280
+ }
4281
+ /** Pages whose request timestamp is older than timeoutMs — candidates for retry or failure.
4282
+ * Caller is expected to already exclude pages present in loadedPages. */
4283
+ function getStalePages(requestedAt, now, timeoutMs) {
4284
+ const stale = [];
4285
+ for (const [page, ts] of requestedAt) {
4286
+ if (now - ts >= timeoutMs)
4287
+ stale.push(page);
4288
+ }
4289
+ return stale;
4290
+ }
4291
+
4292
+ 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__row--failed.sc-mrd-table{background:transparent}.mrd-table__cell--failed.sc-mrd-table{padding:var(--mrd-space-2) var(--mrd-space-4);border-bottom:1px solid var(--mrd-border-color)}.mrd-table__retry-button.sc-mrd-table{border:none;background:none;padding:0;color:var(--mrd-color-danger);font-size:inherit;cursor:pointer;text-decoration:underline}.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}`;
4293
+
4294
+ /** How often (ms) to scan outstanding page requests for staleness. */
4295
+ const STALE_CHECK_INTERVAL_MS = 2000;
4296
+ /** Breedte van de filterpopup in px — voor overflow-correctie. */
4297
+ const POPUP_WIDTH = 280;
3817
4298
  const MrdTable = class {
3818
4299
  constructor(hostRef) {
3819
4300
  registerInstance(this, hostRef);
3820
4301
  this.mrdLoadPage = createEvent(this, "mrdLoadPage");
4302
+ this.mrdPageError = createEvent(this, "mrdPageError");
3821
4303
  this.mrdRowClick = createEvent(this, "mrdRowClick");
3822
4304
  this.mrdAction = createEvent(this, "mrdAction");
3823
4305
  this.mrdDownload = createEvent(this, "mrdDownload");
@@ -3825,10 +4307,17 @@ const MrdTable = class {
3825
4307
  // ── Non-state internals ────────────────────────────────────────────────────
3826
4308
  this.pendingPages = new Set();
3827
4309
  this.debounceTimer = null;
4310
+ /** Timestamp of the last mrdLoadPage emission per outstanding page — drives stale-request detection. */
4311
+ this.requestedAt = new Map();
4312
+ /** Retry count per page since it first became stale. */
4313
+ this.retryAttempts = new Map();
4314
+ this.staleCheckTimer = null;
3828
4315
  this.outsideClickHandler = null;
3829
4316
  this.keydownHandler = null;
3830
4317
  this.createPickerClickHandler = null;
3831
4318
  this.viewPopoverClickHandler = null;
4319
+ /** Guards against scheduling more than one column-width measurement per freeze. */
4320
+ this.colWidthMeasureScheduled = false;
3832
4321
  // ── Props ──────────────────────────────────────────────────────────────────
3833
4322
  /** The VIEW or RELATED_VIEW layout item. Contains view config, dataClass, fromClass, actions etc. */
3834
4323
  this.item = null;
@@ -3845,11 +4334,16 @@ const MrdTable = class {
3845
4334
  this.rowHeight = 36;
3846
4335
  /** Height of the scroll container in px. */
3847
4336
  this.tableHeight = 500;
4337
+ /** Time (ms) to wait for setPage() before retrying a page request; after
4338
+ * MAX_RETRY_ATTEMPTS retries the page is marked failed (see failedPages). */
4339
+ this.requestTimeoutMs = REQUEST_TIMEOUT_MS;
3848
4340
  // ── Internal state ─────────────────────────────────────────────────────────
3849
4341
  /** Index into allViews[] for the currently displayed view. 0 = primary, 1+ = alternatives. */
3850
4342
  this.activeViewIdx = 0;
3851
4343
  this.loadedPages = new Map();
3852
4344
  this.requestedPages = new Set();
4345
+ /** Pages that timed out MAX_RETRY_ATTEMPTS times — rendered as a retry row instead of shimmer. */
4346
+ this.failedPages = new Set();
3853
4347
  this.renderStart = 0;
3854
4348
  this.renderEnd = 0;
3855
4349
  this.colWidths = [];
@@ -3885,13 +4379,10 @@ const MrdTable = class {
3885
4379
  this.minKnownTotal = 0;
3886
4380
  this.handleScroll = (e) => {
3887
4381
  const scroller = e.currentTarget;
3888
- const scrollTop = scroller.scrollTop;
3889
- const total = this.baseTotal;
3890
- const visStart = Math.floor(scrollTop / this.rowHeight);
3891
- const visEnd = Math.min(visStart + this.visibleCount(), total - 1);
3892
- this.scrollTop = scrollTop;
3893
- this.renderStart = Math.max(0, visStart - BUFFER);
3894
- this.renderEnd = Math.min(total - 1, visEnd + BUFFER);
4382
+ const { renderStart, renderEnd } = computeWindow(scroller.scrollTop, this.rowHeight, this.tableHeight, this.baseTotal);
4383
+ this.scrollTop = scroller.scrollTop;
4384
+ this.renderStart = renderStart;
4385
+ this.renderEnd = renderEnd;
3895
4386
  this.requestPagesForWindow(this.renderStart, this.renderEnd);
3896
4387
  };
3897
4388
  }
@@ -3911,18 +4402,14 @@ const MrdTable = class {
3911
4402
  var _a, _b, _c;
3912
4403
  this.applyDefaultSort((_c = (_b = (_a = this.item) === null || _a === void 0 ? void 0 : _a.view) === null || _b === void 0 ? void 0 : _b.defaultSort) !== null && _c !== void 0 ? _c : '');
3913
4404
  }
4405
+ componentDidLoad() {
4406
+ this.staleCheckTimer = setInterval(() => this.checkStalePages(), STALE_CHECK_INTERVAL_MS);
4407
+ }
3914
4408
  // ── Helpers ────────────────────────────────────────────────────────────────
3915
4409
  applyDefaultSort(defaultSort) {
3916
- var _a;
3917
- if (defaultSort) {
3918
- const parts = defaultSort.split(',');
3919
- this.sortField = parts[0].trim();
3920
- this.sortDir = ((_a = parts[1]) === null || _a === void 0 ? void 0 : _a.trim()) === 'desc' ? 'desc' : 'asc';
3921
- }
3922
- else {
3923
- this.sortField = '';
3924
- this.sortDir = 'asc';
3925
- }
4410
+ const { field, dir } = parseDefaultSort(defaultSort);
4411
+ this.sortField = field;
4412
+ this.sortDir = dir;
3926
4413
  }
3927
4414
  // ── Public API ─────────────────────────────────────────────────────────────
3928
4415
  /**
@@ -3938,7 +4425,11 @@ const MrdTable = class {
3938
4425
  this.pendingPages.clear();
3939
4426
  this.loadedPages = new Map();
3940
4427
  this.requestedPages = new Set();
4428
+ this.failedPages = new Set();
4429
+ this.requestedAt.clear();
4430
+ this.retryAttempts.clear();
3941
4431
  this.colWidths = [];
4432
+ this.colWidthMeasureScheduled = false;
3942
4433
  this.scrollTop = 0;
3943
4434
  this.renderStart = 0;
3944
4435
  // Always fill the visible viewport on init — totalElements may be stale from a
@@ -3952,7 +4443,7 @@ const MrdTable = class {
3952
4443
  this.aggregationsPending = true;
3953
4444
  this.minKnownTotal = 0;
3954
4445
  // Always request page 0 — totalElements may be unknown (0) on first load.
3955
- this.mrdLoadPage.emit({ page: 0, sort: this.sortParam(), path: this.buildDataPath(), qs: this.buildQueryParams(0) });
4446
+ this.emitLoadPage(0);
3956
4447
  this.requestedPages = new Set([0]);
3957
4448
  }
3958
4449
  /**
@@ -3983,6 +4474,13 @@ const MrdTable = class {
3983
4474
  const next = new Map(this.loadedPages);
3984
4475
  next.set(pageNumber, rows);
3985
4476
  this.loadedPages = next;
4477
+ this.requestedAt.delete(pageNumber);
4478
+ this.retryAttempts.delete(pageNumber);
4479
+ if (this.failedPages.has(pageNumber)) {
4480
+ const nextFailed = new Set(this.failedPages);
4481
+ nextFailed.delete(pageNumber);
4482
+ this.failedPages = nextFailed;
4483
+ }
3986
4484
  if (pageNumber === 0 && this.aggregationsPending) {
3987
4485
  this.aggregationsPending = false;
3988
4486
  const hasAggColumns = this.columns.some(c => c.type === 'FIELD' && c.aggregate);
@@ -4001,6 +4499,10 @@ const MrdTable = class {
4001
4499
  }
4002
4500
  // ── Lifecycle ──────────────────────────────────────────────────────────────
4003
4501
  disconnectedCallback() {
4502
+ if (this.staleCheckTimer !== null) {
4503
+ clearInterval(this.staleCheckTimer);
4504
+ this.staleCheckTimer = null;
4505
+ }
4004
4506
  if (this.outsideClickHandler) {
4005
4507
  document.removeEventListener('click', this.outsideClickHandler);
4006
4508
  this.outsideClickHandler = null;
@@ -4019,21 +4521,34 @@ const MrdTable = class {
4019
4521
  }
4020
4522
  }
4021
4523
  componentDidRender() {
4022
- if (this.colWidths.length === 0 && this.loadedPages.size > 0 && this.totalElements > 0) {
4023
- const ths = this.el.querySelectorAll('.mrd-table__header');
4024
- if (ths.length > 0) {
4025
- this.colWidths = Array.from(ths).map(th => th.offsetWidth);
4026
- }
4524
+ // Freeze header widths once the first data page has rendered. The measurement
4525
+ // reads offsetWidth and writes the colWidths @State, which would trigger a
4526
+ // re-render *during* the render cycle if done synchronously here. Defer it to a
4527
+ // writeTask so the state mutation happens outside the render pass (avoids the
4528
+ // Stencil "state/prop changed during rendering" warning and potential loops).
4529
+ if (this.colWidths.length === 0 &&
4530
+ !this.colWidthMeasureScheduled &&
4531
+ this.loadedPages.size > 0 &&
4532
+ this.totalElements > 0) {
4533
+ this.colWidthMeasureScheduled = true;
4534
+ writeTask(() => {
4535
+ this.colWidthMeasureScheduled = false;
4536
+ // Re-check: state may have changed (e.g. a reset) between scheduling and running.
4537
+ if (this.colWidths.length !== 0)
4538
+ return;
4539
+ const ths = this.el.querySelectorAll('.mrd-table__header');
4540
+ if (ths.length > 0) {
4541
+ this.colWidths = Array.from(ths).map(th => th.offsetWidth);
4542
+ }
4543
+ });
4027
4544
  }
4028
4545
  }
4029
4546
  // ── Paging / scroll helpers ────────────────────────────────────────────────
4030
4547
  visibleCount() {
4031
- return Math.ceil(this.tableHeight / this.rowHeight);
4548
+ return visibleCount(this.tableHeight, this.rowHeight);
4032
4549
  }
4033
4550
  sortParam() {
4034
- if (!this.sortField)
4035
- return '';
4036
- return this.sortDir === 'desc' ? `${this.sortField},desc` : this.sortField;
4551
+ return buildSortParam(this.sortField, this.sortDir);
4037
4552
  }
4038
4553
  /** Stable ordered list: primary view first, then alternatives (from the item prop). */
4039
4554
  get allViews() {
@@ -4059,14 +4574,16 @@ const MrdTable = class {
4059
4574
  * VIEW: /excel/{dataClass}
4060
4575
  * RELATED_VIEW: /excel/{fromClass}/{parentId}/{dataClass} */
4061
4576
  buildExcelPath() {
4062
- var _a, _b, _c, _d;
4577
+ var _a;
4063
4578
  const v = this.allViews[this.activeViewIdx];
4064
4579
  if (!v)
4065
4580
  return '';
4066
- if (((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === 'RELATED_VIEW') {
4067
- return `/excel/${(_b = v.fromClass) !== null && _b !== void 0 ? _b : ''}/${this.parentId}/${(_c = v.dataClass) !== null && _c !== void 0 ? _c : ''}`;
4068
- }
4069
- return `/excel/${(_d = v.dataClass) !== null && _d !== void 0 ? _d : ''}`;
4581
+ return '/excel' + buildListPath({
4582
+ isRelatedView: ((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === 'RELATED_VIEW',
4583
+ fromClass: v.fromClass,
4584
+ parentId: this.parentId,
4585
+ dataClass: v.dataClass,
4586
+ });
4070
4587
  }
4071
4588
  buildActionDetail(action, basicType) {
4072
4589
  var _a, _b, _c;
@@ -4086,80 +4603,28 @@ const MrdTable = class {
4086
4603
  * VIEW: /{dataClass}
4087
4604
  * RELATED_VIEW: /{fromClass}/{parentId}/{dataClass} */
4088
4605
  buildDataPath() {
4089
- var _a, _b, _c, _d;
4606
+ var _a;
4090
4607
  const v = this.allViews[this.activeViewIdx];
4091
4608
  if (!v)
4092
4609
  return '';
4093
- if (((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === 'RELATED_VIEW') {
4094
- return `/${(_b = v.fromClass) !== null && _b !== void 0 ? _b : ''}/${this.parentId}/${(_c = v.dataClass) !== null && _c !== void 0 ? _c : ''}`;
4095
- }
4096
- return `/${(_d = v.dataClass) !== null && _d !== void 0 ? _d : ''}`;
4610
+ return buildListPath({
4611
+ isRelatedView: ((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === 'RELATED_VIEW',
4612
+ fromClass: v.fromClass,
4613
+ parentId: this.parentId,
4614
+ dataClass: v.dataClass,
4615
+ });
4097
4616
  }
4098
4617
  /** Build query params for a page request from current sort, view filters, filterClass and active column filters. */
4099
4618
  buildQueryParams(page) {
4100
- var _a, _b, _c, _d, _e, _f, _g;
4619
+ var _a;
4101
4620
  const v = this.allViews[this.activeViewIdx];
4102
- const p = new URLSearchParams();
4103
- if (page > 0)
4104
- p.set('page', String(page));
4105
- const sort = this.sortParam();
4106
- if (sort)
4107
- p.set('sort', sort);
4108
- const filterClass = v === null || v === void 0 ? void 0 : v.filterClass;
4109
- if (filterClass)
4110
- p.set('type', filterClass);
4111
- 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 : [])) {
4112
- if (!f.name)
4113
- continue;
4114
- if (f.operator === 'EMPTY') {
4115
- p.set(f.name, '');
4116
- continue;
4117
- }
4118
- if (f.operator === 'NOT_EMPTY') {
4119
- p.set(f.name + '_notempty', 'true');
4120
- continue;
4121
- }
4122
- if (f.operator === 'STARTS_WITH') {
4123
- p.set(f.name + '_startswith', String((_c = f.value) !== null && _c !== void 0 ? _c : ''));
4124
- continue;
4125
- }
4126
- if (f.operator === 'FROM') {
4127
- p.set(f.name + '_from', String((_d = f.value) !== null && _d !== void 0 ? _d : ''));
4128
- continue;
4129
- }
4130
- if (f.operator === 'TO') {
4131
- p.set(f.name + '_to', String((_e = f.value) !== null && _e !== void 0 ? _e : ''));
4132
- continue;
4133
- }
4134
- if (f.value != null) {
4135
- p.set(f.name, String(f.value));
4136
- }
4137
- }
4138
- for (const f of this.activeFilters.values()) {
4139
- if (f.operator === 'isEmpty') {
4140
- p.set(f.field, '');
4141
- continue;
4142
- }
4143
- if (f.operator === 'isNotEmpty') {
4144
- p.set(f.field + '_notempty', 'true');
4145
- continue;
4146
- }
4147
- if (f.operator === 'startsWith') {
4148
- p.set(f.field + '_startswith', String((_f = f.value) !== null && _f !== void 0 ? _f : ''));
4149
- continue;
4150
- }
4151
- if ((_g = f.values) === null || _g === void 0 ? void 0 : _g.length) {
4152
- p.set(f.field, f.values.join(','));
4153
- continue;
4154
- }
4155
- if (f.value != null)
4156
- p.set(f.field, String(f.value));
4157
- if (f.from != null)
4158
- p.set(f.field + '_from', String(f.from));
4159
- if (f.to != null)
4160
- p.set(f.field + '_to', String(f.to));
4161
- }
4162
- return p.toString();
4621
+ return buildTableQueryParams({
4622
+ page,
4623
+ sort: this.sortParam(),
4624
+ filterClass: v === null || v === void 0 ? void 0 : v.filterClass,
4625
+ viewFilters: (_a = v === null || v === void 0 ? void 0 : v.view) === null || _a === void 0 ? void 0 : _a.filter,
4626
+ activeFilters: this.activeFilters.values(),
4627
+ });
4163
4628
  }
4164
4629
  get columns() {
4165
4630
  var _a, _b, _c;
@@ -4214,11 +4679,7 @@ const MrdTable = class {
4214
4679
  isTotalKnown() {
4215
4680
  if (this.aggregationsTotal != null)
4216
4681
  return true;
4217
- for (const rows of this.loadedPages.values()) {
4218
- if (rows.length < this.pageSize)
4219
- return true;
4220
- }
4221
- return false;
4682
+ return isTotalKnownFromPages(this.loadedPages, this.pageSize);
4222
4683
  }
4223
4684
  /** Effective total: aggregations-response > totalElements prop > minKnownTotal from setPage(). */
4224
4685
  get baseTotal() {
@@ -4229,61 +4690,9 @@ const MrdTable = class {
4229
4690
  return this.minKnownTotal;
4230
4691
  }
4231
4692
  // ── Aggregation helpers ────────────────────────────────────────────────────
4232
- buildAggregationParams() {
4233
- var _a;
4234
- const groups = { sum: [], avg: [], count: [] };
4235
- for (const col of this.columns) {
4236
- if (col.type !== 'FIELD' || !col.aggregate)
4237
- continue;
4238
- const fn = col.aggregate.toLowerCase();
4239
- if (fn in groups)
4240
- groups[fn].push((_a = col.name) !== null && _a !== void 0 ? _a : '');
4241
- }
4242
- const params = {};
4243
- if (groups.sum.length)
4244
- params.sum = groups.sum;
4245
- if (groups.avg.length)
4246
- params.avg = groups.avg;
4247
- if (groups.count.length)
4248
- params.count = groups.count;
4249
- return Object.keys(params).length > 0 ? params : null;
4250
- }
4251
- buildAggregationQs() {
4252
- var _a, _b, _c;
4253
- const p = new URLSearchParams(this.buildQueryParams(0));
4254
- p.delete('page');
4255
- p.delete('sort');
4256
- const groups = this.buildAggregationParams();
4257
- if ((_a = groups === null || groups === void 0 ? void 0 : groups.sum) === null || _a === void 0 ? void 0 : _a.length)
4258
- p.set('sum', groups.sum.join(','));
4259
- if ((_b = groups === null || groups === void 0 ? void 0 : groups.avg) === null || _b === void 0 ? void 0 : _b.length)
4260
- p.set('avg', groups.avg.join(','));
4261
- if ((_c = groups === null || groups === void 0 ? void 0 : groups.count) === null || _c === void 0 ? void 0 : _c.length)
4262
- p.set('count', groups.count.join(','));
4263
- return p.toString();
4264
- }
4265
4693
  emitLoadAggregations() {
4266
- this.mrdLoadAggregations.emit({ path: this.buildDataPath(), qs: this.buildQueryParams(0), aggQs: this.buildAggregationQs() });
4267
- }
4268
- renderAggregationValue(col) {
4269
- var _a;
4270
- if (col.type !== 'FIELD' || !col.aggregate || !this.aggregations)
4271
- return '';
4272
- const fn = col.aggregate.toLowerCase();
4273
- const aggData = this.aggregations[fn];
4274
- const val = typeof aggData === 'object' && aggData !== null
4275
- ? aggData[(_a = col.name) !== null && _a !== void 0 ? _a : '']
4276
- : undefined;
4277
- if (val == null)
4278
- return '';
4279
- const dt = col.dataType;
4280
- if (dt === 'INTEGER')
4281
- return formatNumber(val, this.locale, { maximumFractionDigits: 0 });
4282
- if (dt === 'PERCENTAGE')
4283
- return formatPercentage(val, this.locale);
4284
- if (dt === 'CURRENCY' && col.currencyCode)
4285
- return formatCurrency(val, col.currencyCode, this.locale);
4286
- return formatNumber(val, this.locale);
4694
+ const qs = this.buildQueryParams(0);
4695
+ this.mrdLoadAggregations.emit({ path: this.buildDataPath(), qs, aggQs: buildAggregationQs(qs, this.columns) });
4287
4696
  }
4288
4697
  // ── Reset pagination ───────────────────────────────────────────────────────
4289
4698
  /** Reset pagination state and scroll to top (used after sort or filter change). */
@@ -4295,7 +4704,11 @@ const MrdTable = class {
4295
4704
  this.pendingPages.clear();
4296
4705
  this.loadedPages = new Map();
4297
4706
  this.requestedPages = new Set();
4707
+ this.failedPages = new Set();
4708
+ this.requestedAt.clear();
4709
+ this.retryAttempts.clear();
4298
4710
  this.colWidths = [];
4711
+ this.colWidthMeasureScheduled = false;
4299
4712
  this.scrollTop = 0;
4300
4713
  this.renderStart = 0;
4301
4714
  this.minKnownTotal = 0;
@@ -4324,15 +4737,19 @@ const MrdTable = class {
4324
4737
  this.resetPages();
4325
4738
  this.emitPagesForWindow(this.renderStart, this.renderEnd);
4326
4739
  }
4740
+ /** Emits mrdLoadPage for a page and records the request timestamp for stale-request detection. */
4741
+ emitLoadPage(page) {
4742
+ this.mrdLoadPage.emit({ page, sort: this.sortParam(), path: this.buildDataPath(), qs: this.buildQueryParams(page) });
4743
+ this.requestedAt.set(page, Date.now());
4744
+ }
4327
4745
  emitPagesForWindow(start, end) {
4328
- const firstPage = Math.floor(start / this.pageSize);
4329
- const lastPage = Math.floor(end / this.pageSize);
4746
+ const { firstPage, lastPage } = pageRange(start, end, this.pageSize);
4330
4747
  const next = new Set(this.requestedPages);
4331
4748
  let changed = false;
4332
4749
  for (let p = firstPage; p <= lastPage; p++) {
4333
4750
  if (!this.loadedPages.has(p) && !next.has(p)) {
4334
4751
  next.add(p);
4335
- this.mrdLoadPage.emit({ page: p, sort: this.sortParam(), path: this.buildDataPath(), qs: this.buildQueryParams(p) });
4752
+ this.emitLoadPage(p);
4336
4753
  changed = true;
4337
4754
  }
4338
4755
  }
@@ -4340,13 +4757,10 @@ const MrdTable = class {
4340
4757
  this.requestedPages = next;
4341
4758
  }
4342
4759
  getRow(i) {
4343
- var _a;
4344
- const page = this.loadedPages.get(Math.floor(i / this.pageSize));
4345
- return (_a = page === null || page === void 0 ? void 0 : page[i % this.pageSize]) !== null && _a !== void 0 ? _a : null;
4760
+ return getRowFromPages(this.loadedPages, i, this.pageSize);
4346
4761
  }
4347
4762
  requestPagesForWindow(start, end) {
4348
- const firstPage = Math.floor(start / this.pageSize);
4349
- const lastPage = Math.floor(end / this.pageSize);
4763
+ const { firstPage, lastPage } = pageRange(start, end, this.pageSize);
4350
4764
  let anyNew = false;
4351
4765
  for (let p = firstPage; p <= lastPage; p++) {
4352
4766
  if (!this.loadedPages.has(p) && !this.requestedPages.has(p) && !this.pendingPages.has(p)) {
@@ -4374,13 +4788,53 @@ const MrdTable = class {
4374
4788
  if (pageEnd < this.renderStart || pageStart > this.renderEnd)
4375
4789
  continue;
4376
4790
  next.add(page);
4377
- this.mrdLoadPage.emit({ page, sort: this.sortParam(), path: this.buildDataPath(), qs: this.buildQueryParams(page) });
4791
+ this.emitLoadPage(page);
4378
4792
  changed = true;
4379
4793
  }
4380
4794
  this.pendingPages.clear();
4381
4795
  if (changed)
4382
4796
  this.requestedPages = next;
4383
4797
  }
4798
+ /** Scans outstanding requests for staleness: retries up to MAX_RETRY_ATTEMPTS times,
4799
+ * then gives up and marks the page as failed (rendered as a retry row). */
4800
+ checkStalePages() {
4801
+ var _a;
4802
+ if (this.requestedAt.size === 0)
4803
+ return;
4804
+ const stale = getStalePages(this.requestedAt, Date.now(), this.requestTimeoutMs)
4805
+ .filter(p => !this.loadedPages.has(p));
4806
+ if (stale.length === 0)
4807
+ return;
4808
+ let nextFailed = null;
4809
+ for (const page of stale) {
4810
+ const attempts = (_a = this.retryAttempts.get(page)) !== null && _a !== void 0 ? _a : 0;
4811
+ if (attempts < MAX_RETRY_ATTEMPTS) {
4812
+ this.retryAttempts.set(page, attempts + 1);
4813
+ this.emitLoadPage(page);
4814
+ }
4815
+ else {
4816
+ this.requestedAt.delete(page);
4817
+ this.retryAttempts.delete(page);
4818
+ if (!nextFailed)
4819
+ nextFailed = new Set(this.failedPages);
4820
+ nextFailed.add(page);
4821
+ this.mrdPageError.emit({ page });
4822
+ }
4823
+ }
4824
+ if (nextFailed)
4825
+ this.failedPages = nextFailed;
4826
+ }
4827
+ /** Manually retry a page the user gave up on (clicked the retry row). */
4828
+ retryPage(page) {
4829
+ const next = new Set(this.failedPages);
4830
+ next.delete(page);
4831
+ this.failedPages = next;
4832
+ this.retryAttempts.delete(page);
4833
+ this.emitLoadPage(page);
4834
+ const requested = new Set(this.requestedPages);
4835
+ requested.add(page);
4836
+ this.requestedPages = requested;
4837
+ }
4384
4838
  // ── Filter helpers ─────────────────────────────────────────────────────────
4385
4839
  handleFilterToggle() {
4386
4840
  this.filterMode = !this.filterMode;
@@ -4408,17 +4862,7 @@ const MrdTable = class {
4408
4862
  // If from and to cover the same local day it was an exact-date filter — restore
4409
4863
  // to exact mode so the user sees the single-date input again.
4410
4864
  if (dataType === 'DATETIME' && existing && existing.operator !== 'isEmpty' && existing.operator !== 'isNotEmpty') {
4411
- const display = Object.assign({}, existing);
4412
- if (typeof display.from === 'string' && display.from)
4413
- display.from = this.utcISOToLocalDate(display.from);
4414
- if (typeof display.to === 'string' && display.to)
4415
- display.to = this.utcISOToLocalDateExclusiveEnd(display.to);
4416
- if (display.from && display.to && display.from === display.to) {
4417
- this.pendingFilter = Object.assign(Object.assign({}, display), { value: display.from, from: undefined, to: undefined });
4418
- }
4419
- else {
4420
- this.pendingFilter = display;
4421
- }
4865
+ this.pendingFilter = datetimeFilterToDisplay(existing);
4422
4866
  }
4423
4867
  else {
4424
4868
  this.pendingFilter = existing ? Object.assign({}, existing) : { field: name, dataType, operator: defaultOperator };
@@ -4484,81 +4928,15 @@ const MrdTable = class {
4484
4928
  const current = (_b = (_a = this.pendingFilter) === null || _a === void 0 ? void 0 : _a.values) !== null && _b !== void 0 ? _b : [];
4485
4929
  this.pendingFilter = Object.assign(Object.assign({}, this.pendingFilter), { values: checked ? [...current, key] : current.filter(k => k !== key) });
4486
4930
  }
4487
- filterHasValue(f) {
4488
- if (f.operator === 'isEmpty' || f.operator === 'isNotEmpty')
4489
- return true;
4490
- if (f.values !== undefined && f.values.length > 0)
4491
- return true;
4492
- if (f.value != null && f.value !== '')
4493
- return true;
4494
- if (typeof f.value === 'boolean')
4495
- return true;
4496
- if (f.from != null && f.from !== '')
4497
- return true;
4498
- if (f.to != null && f.to !== '')
4499
- return true;
4500
- return false;
4501
- }
4502
- // Convert a local "YYYY-MM-DD" date string to the UTC ISO string at the
4503
- // start of that local day (midnight). new Date(y, m, d) uses local time.
4504
- dateLocalToUTCStart(dateStr) {
4505
- if (!dateStr)
4506
- return dateStr;
4507
- const [year, month, day] = dateStr.split('-').map(Number);
4508
- return new Date(year, month - 1, day).toISOString().replace(/\.\d{3}Z$/, 'Z');
4509
- }
4510
- // Start of the day AFTER the given local date (exclusive range end).
4511
- dateLocalToUTCEndExclusive(dateStr) {
4512
- if (!dateStr)
4513
- return dateStr;
4514
- const [year, month, day] = dateStr.split('-').map(Number);
4515
- return new Date(year, month - 1, day + 1).toISOString().replace(/\.\d{3}Z$/, 'Z');
4516
- }
4517
- // Convert a stored UTC ISO string back to the local "YYYY-MM-DD" date.
4518
- utcISOToLocalDate(utcStr) {
4519
- if (!utcStr)
4520
- return utcStr;
4521
- const d = new Date(utcStr);
4522
- if (isNaN(d.getTime()))
4523
- return utcStr;
4524
- return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
4525
- }
4526
- // The stored "to" value is the exclusive end (midnight of the next day).
4527
- // Subtract one day to recover the local date the user entered.
4528
- utcISOToLocalDateExclusiveEnd(utcStr) {
4529
- if (!utcStr)
4530
- return utcStr;
4531
- const d = new Date(utcStr);
4532
- if (isNaN(d.getTime()))
4533
- return utcStr;
4534
- d.setDate(d.getDate() - 1);
4535
- return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
4536
- }
4537
4931
  applyFilter() {
4538
4932
  const f = this.pendingFilter;
4539
4933
  if (!(f === null || f === void 0 ? void 0 : f.field)) {
4540
4934
  this.closeFilterPopup();
4541
4935
  return;
4542
4936
  }
4543
- // For DATETIME fields the user enters local dates; convert to UTC ISO strings.
4544
- // Exact date → range covering the full local day (from = midnight, to = next midnight).
4545
- // "to" is always the exclusive end (midnight of the next local day).
4546
- let normalized = Object.assign({}, f);
4547
- if (f.dataType === 'DATETIME' && f.operator !== 'isEmpty' && f.operator !== 'isNotEmpty') {
4548
- if (typeof normalized.value === 'string' && normalized.value) {
4549
- normalized.from = this.dateLocalToUTCStart(normalized.value);
4550
- normalized.to = this.dateLocalToUTCEndExclusive(normalized.value);
4551
- normalized.value = undefined;
4552
- }
4553
- else {
4554
- if (typeof normalized.from === 'string' && normalized.from)
4555
- normalized.from = this.dateLocalToUTCStart(normalized.from);
4556
- if (typeof normalized.to === 'string' && normalized.to)
4557
- normalized.to = this.dateLocalToUTCEndExclusive(normalized.to);
4558
- }
4559
- }
4937
+ const normalized = normalizeDatetimeFilter(f);
4560
4938
  const next = new Map(this.activeFilters);
4561
- if (this.filterHasValue(normalized)) {
4939
+ if (filterHasValue(normalized)) {
4562
4940
  next.set(normalized.field, normalized);
4563
4941
  }
4564
4942
  else {
@@ -4613,140 +4991,53 @@ const MrdTable = class {
4613
4991
  toggleViewPopover(e) {
4614
4992
  e.stopPropagation();
4615
4993
  if (this.viewPopoverOpen) {
4616
- this.viewPopoverOpen = false;
4617
- if (this.viewPopoverClickHandler) {
4618
- document.removeEventListener('click', this.viewPopoverClickHandler);
4619
- this.viewPopoverClickHandler = null;
4620
- }
4994
+ this.closeViewPopover();
4621
4995
  return;
4622
4996
  }
4623
4997
  this.viewPopoverOpen = true;
4624
- this.viewPopoverClickHandler = () => {
4625
- this.viewPopoverOpen = false;
4998
+ this.viewPopoverClickHandler = () => this.closeViewPopover();
4999
+ document.addEventListener('click', this.viewPopoverClickHandler);
5000
+ }
5001
+ closeViewPopover() {
5002
+ this.viewPopoverOpen = false;
5003
+ if (this.viewPopoverClickHandler) {
4626
5004
  document.removeEventListener('click', this.viewPopoverClickHandler);
4627
5005
  this.viewPopoverClickHandler = null;
4628
- };
4629
- document.addEventListener('click', this.viewPopoverClickHandler);
5006
+ }
4630
5007
  }
4631
5008
  // ── Render: toolbar ────────────────────────────────────────────────────────
4632
5009
  renderToolbar() {
4633
5010
  var _a;
4634
- const filterCount = this.activeFilters.size;
4635
- const actions = this.tableActions;
4636
- const allViews = this.allViews;
4637
- const hasActions = actions.length > 0;
4638
- const hasViewSwitcher = allViews.length > 1;
4639
- 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: () => {
4640
- if (i !== this.activeViewIdx)
4641
- this.handleViewSwitch(i);
4642
- this.viewPopoverOpen = false;
4643
- if (this.viewPopoverClickHandler) {
4644
- document.removeEventListener('click', this.viewPopoverClickHandler);
4645
- this.viewPopoverClickHandler = null;
4646
- }
4647
- } }, 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 => {
4648
- var _a, _b, _c;
4649
- const createTypes = a.action === 'create' ? (_a = this.item) === null || _a === void 0 ? void 0 : _a.createTypes : null;
4650
- if (createTypes === null || createTypes === void 0 ? void 0 : createTypes.length) {
4651
- 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
4652
- ? h("svg", { class: "mrd-table__action-icon", "aria-hidden": "true" }, h("use", { href: a.icon }))
4653
- : 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: () => {
4654
- this.mrdAction.emit(this.buildActionDetail('create', ct.type));
4655
- this.closeCreatePicker();
4656
- } }, ct.label)))))));
4657
- }
4658
- 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
4659
- ? h("svg", { class: "mrd-table__action-icon", "aria-hidden": "true" }, h("use", { href: a.icon }))
4660
- : a.label, h("span", { class: "mrd-table__action-tooltip" }, a.label)));
4661
- })))));
5011
+ 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: {
5012
+ onFilterToggle: () => this.handleFilterToggle(),
5013
+ onClearAllFilters: () => this.clearAllFilters(),
5014
+ onViewSwitch: idx => this.handleViewSwitch(idx),
5015
+ onToggleViewPopover: e => this.toggleViewPopover(e),
5016
+ onCloseViewPopover: () => this.closeViewPopover(),
5017
+ onToggleCreatePicker: () => this.toggleCreatePicker(),
5018
+ onCreate: basicType => {
5019
+ this.mrdAction.emit(this.buildActionDetail('create', basicType));
5020
+ this.closeCreatePicker();
5021
+ },
5022
+ onAction: action => this.mrdAction.emit(this.buildActionDetail(action)),
5023
+ } }));
4662
5024
  }
4663
5025
  // ── Render: filter popup ───────────────────────────────────────────────────
4664
- renderFilterEditor(col) {
4665
- var _a, _b, _c, _d, _e, _f, _g;
4666
- const pf = (_a = this.pendingFilter) !== null && _a !== void 0 ? _a : {};
4667
- const dataType = this.colDataType(col);
4668
- if (NO_FILTER_TYPES.has(dataType)) {
4669
- return h("p", { class: "mrd-table__filter-no-support" }, t('filter_no_support', this.locale));
4670
- }
4671
- if (dataType === 'BOOLEAN') {
4672
- const boolOp = pf.operator;
4673
- const noValueOp = boolOp === 'isEmpty' || boolOp === 'isNotEmpty';
4674
- return (h("div", { class: "mrd-table__filter-radio-group" }, [
4675
- { labelKey: 'filter_all', value: null },
4676
- { labelKey: 'yes', value: true },
4677
- { labelKey: 'no', value: false },
4678
- ].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))));
4679
- }
4680
- if (dataType === 'LIST') {
4681
- const items = (_b = col.listItems) !== null && _b !== void 0 ? _b : [];
4682
- const selected = (_c = pf.values) !== null && _c !== void 0 ? _c : [];
4683
- 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)))));
4684
- }
4685
- if (TEXT_TYPES.has(dataType) || dataType === 'RELATION') {
4686
- const op = (_d = pf.operator) !== null && _d !== void 0 ? _d : 'startsWith';
4687
- const noInput = op === 'isEmpty' || op === 'isNotEmpty';
4688
- return (h("div", { class: "mrd-table__filter-editor" }, h("select", { class: "mrd-table__filter-select", onChange: (e) => this.setPending('operator', e.target.value) }, [
4689
- { val: 'startsWith', labelKey: 'filter_starts_with' },
4690
- { val: 'equals', labelKey: 'filter_equals' },
4691
- { val: 'isEmpty', labelKey: 'filter_is_empty' },
4692
- { val: 'isNotEmpty', labelKey: 'filter_is_not_empty' },
4693
- ].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) }))));
4694
- }
4695
- if (NUMERIC_TYPES.has(dataType)) {
4696
- const numOp = pf.operator;
4697
- const noInput = numOp === 'isEmpty' || numOp === 'isNotEmpty';
4698
- const rangeMode = !noInput && (pf.from !== undefined || pf.to !== undefined);
4699
- return (h("div", { class: "mrd-table__filter-editor" }, h("select", { class: "mrd-table__filter-select", onChange: (e) => {
4700
- const val = e.target.value;
4701
- if (val === 'isEmpty' || val === 'isNotEmpty') {
4702
- this.pendingFilter = Object.assign(Object.assign({}, pf), { operator: val, value: undefined, from: undefined, to: undefined });
4703
- }
4704
- else {
4705
- this.pendingFilter = Object.assign(Object.assign({}, pf), { operator: undefined });
4706
- }
4707
- } }, 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) })))))));
4708
- }
4709
- if (dataType === 'DATETIME') {
4710
- const dtOp = pf.operator;
4711
- const noInput = dtOp === 'isEmpty' || dtOp === 'isNotEmpty';
4712
- const rangeMode = !noInput && (pf.from !== undefined || pf.to !== undefined);
4713
- return (h("div", { class: "mrd-table__filter-editor" }, h("select", { class: "mrd-table__filter-select", onChange: (e) => {
4714
- const val = e.target.value;
4715
- if (val === 'isEmpty' || val === 'isNotEmpty') {
4716
- this.pendingFilter = Object.assign(Object.assign({}, pf), { operator: val, value: undefined, from: undefined, to: undefined });
4717
- }
4718
- else {
4719
- this.pendingFilter = Object.assign(Object.assign({}, pf), { operator: undefined });
4720
- }
4721
- } }, 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) })))))));
4722
- }
4723
- if (DATE_TYPES.has(dataType)) {
4724
- const inputType = dataType === 'DATE' ? 'date' : 'time';
4725
- const dtdOp = pf.operator;
4726
- const noInput = dtdOp === 'isEmpty' || dtdOp === 'isNotEmpty';
4727
- const rangeMode = !noInput && (pf.from !== undefined || pf.to !== undefined);
4728
- return (h("div", { class: "mrd-table__filter-editor" }, h("select", { class: "mrd-table__filter-select", onChange: (e) => {
4729
- const val = e.target.value;
4730
- if (val === 'isEmpty' || val === 'isNotEmpty') {
4731
- this.pendingFilter = Object.assign(Object.assign({}, pf), { operator: val, value: undefined, from: undefined, to: undefined });
4732
- }
4733
- else {
4734
- this.pendingFilter = Object.assign(Object.assign({}, pf), { operator: undefined });
4735
- }
4736
- } }, 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) })))))));
4737
- }
4738
- return null;
4739
- }
4740
5026
  renderFilterPopup() {
4741
- var _a;
4742
5027
  if (!this.openFilterCol || !this.pendingFilter)
4743
5028
  return null;
4744
5029
  const col = this.columns.find(c => this.colName(c) === this.openFilterCol);
4745
5030
  if (!col)
4746
5031
  return null;
4747
- const label = (_a = col.label) !== null && _a !== void 0 ? _a : this.openFilterCol;
4748
- const sortActive = this.sortField === this.openFilterCol;
4749
- 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)))));
5032
+ 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: {
5033
+ onSetPending: (key, val) => this.setPending(key, val),
5034
+ onReplacePending: pf => (this.pendingFilter = pf),
5035
+ onToggleValue: (key, checked) => this.togglePendingValue(key, checked),
5036
+ onApplySort: dir => this.applySort(col, dir),
5037
+ onApply: () => this.applyFilter(),
5038
+ onClear: () => this.clearFilter(),
5039
+ onClose: () => this.closeFilterPopup(),
5040
+ } }));
4750
5041
  }
4751
5042
  // ── Render: footer ────────────────────────────────────────────────────────
4752
5043
  renderFooter(rowCount, effectiveTotal, isTotalKnown = true) {
@@ -4771,54 +5062,11 @@ const MrdTable = class {
4771
5062
  }
4772
5063
  // ── Render: cell ──────────────────────────────────────────────────────────
4773
5064
  renderCell(col, row) {
4774
- var _a, _b, _c;
4775
- const numericTypes = new Set(['INTEGER', 'DECIMAL', 'PERCENTAGE', 'CURRENCY']);
4776
- const dataType = (_a = col.dataType) !== null && _a !== void 0 ? _a : '';
4777
- const isNumeric = col.type === 'FIELD' && numericTypes.has(dataType);
4778
- const isFile = col.type === 'FIELD' && (dataType === 'FILE' || dataType === 'IMAGE');
4779
- if (isFile) {
4780
- const name = (_b = col.name) !== null && _b !== void 0 ? _b : '';
4781
- const fileVal = row === null || row === void 0 ? void 0 : row[name];
4782
- const href = fileVal === null || fileVal === void 0 ? void 0 : fileVal.href;
4783
- const fileName = fileVal === null || fileVal === void 0 ? void 0 : fileVal.fileName;
4784
- return (h("td", { class: "mrd-table__cell" }, href && fileName ? (h("button", { class: "mrd-table__file-btn", title: fileName, onClick: (e) => {
4785
- e.stopPropagation();
4786
- this.mrdDownload.emit({ href, fileName });
4787
- } }, 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))) : ''));
4788
- }
4789
- if (dataType === 'JSON') {
4790
- const name = (_c = col.name) !== null && _c !== void 0 ? _c : '';
4791
- const rawValue = name ? row === null || row === void 0 ? void 0 : row[name] : undefined;
4792
- if (rawValue == null || rawValue === '')
4793
- return h("td", { class: "mrd-table__cell" });
4794
- const compactHtml = CellRenderer.formatJson(rawValue, true);
4795
- const prettyHtml = CellRenderer.formatJson(rawValue, false);
4796
- 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")));
4797
- }
4798
- const TEXTBLOCK_MAX = 200;
4799
- if (dataType === 'TEXTBLOCK') {
4800
- const full = CellRenderer.render(col, row, this.locale);
4801
- if (full.length <= TEXTBLOCK_MAX) {
4802
- return h("td", { class: "mrd-table__cell" }, full);
4803
- }
4804
- const preview = full.slice(0, TEXTBLOCK_MAX) + '…';
4805
- 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")));
4806
- }
4807
- const value = CellRenderer.render(col, row, this.locale);
4808
- return (h("td", { class: `mrd-table__cell${isNumeric ? ' mrd-table__cell--numeric' : ''}` }, value));
5065
+ 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) }));
4809
5066
  }
4810
5067
  // ── Render: totals row ────────────────────────────────────────────────────
4811
5068
  renderTotalsRow() {
4812
- if (!this.aggregations)
4813
- return null;
4814
- if (!this.columns.some(c => c.type === 'FIELD' && c.aggregate))
4815
- return null;
4816
- return (h("tfoot", null, h("tr", { class: "mrd-table__totals-row" }, this.columns.map(col => {
4817
- var _a;
4818
- const val = this.renderAggregationValue(col);
4819
- const isNumeric = col.type === 'FIELD' && NUMERIC_TYPES.has((_a = col.dataType) !== null && _a !== void 0 ? _a : '');
4820
- return (h("td", { class: `mrd-table__totals-cell${isNumeric ? ' mrd-table__totals-cell--numeric' : ''}` }, val));
4821
- }))));
5069
+ return h(TotalsRow, { columns: this.columns, aggregations: this.aggregations, locale: this.locale });
4822
5070
  }
4823
5071
  // ── Render ─────────────────────────────────────────────────────────────────
4824
5072
  render() {
@@ -4838,7 +5086,7 @@ const MrdTable = class {
4838
5086
  isFiltered ? 'mrd-table__header--filtered' : '',
4839
5087
  this.filterMode ? 'mrd-table__header--sortable' : '',
4840
5088
  ].filter(Boolean).join(' ');
4841
- 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()));
5089
+ 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)));
4842
5090
  }))), 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()));
4843
5091
  }
4844
5092
  // ── Paginated / virtual-scroll mode ────────────────────────────────────
@@ -4846,12 +5094,7 @@ const MrdTable = class {
4846
5094
  // if any loaded page is shorter than pageSize it is the last page,
4847
5095
  // so the true total cannot exceed (pageNum * pageSize + pageRows.length).
4848
5096
  // aggregationsTotal (from setAggregations) takes priority over the totalElements prop.
4849
- let effectiveTotal = this.baseTotal;
4850
- for (const [pageNum, pageRows] of this.loadedPages) {
4851
- if (pageRows.length < this.pageSize) {
4852
- effectiveTotal = Math.min(effectiveTotal, pageNum * this.pageSize + pageRows.length);
4853
- }
4854
- }
5097
+ const effectiveTotal = computeEffectiveTotal(this.loadedPages, this.pageSize, this.baseTotal);
4855
5098
  // Clamp renderEnd to what we actually know exists (-1 when empty)
4856
5099
  const clampedEnd = Math.min(this.renderEnd, effectiveTotal - 1);
4857
5100
  const colCount = this.columns.length;
@@ -4864,7 +5107,13 @@ const MrdTable = class {
4864
5107
  for (let i = this.renderStart; i <= clampedEnd; i++) {
4865
5108
  const row = this.getRow(i);
4866
5109
  if (row === null) {
4867
- renderedRows.push(h("tr", { class: "mrd-table__row mrd-table__row--loading" }, h("td", { class: "mrd-table__cell--placeholder", colSpan: colCount }, h("span", { class: "mrd-table__placeholder-bar" }))));
5110
+ const page = Math.floor(i / this.pageSize);
5111
+ if (this.failedPages.has(page)) {
5112
+ renderedRows.push(h("tr", { class: "mrd-table__row mrd-table__row--failed" }, h("td", { class: "mrd-table__cell--failed", colSpan: colCount }, h("button", { type: "button", class: "mrd-table__retry-button", onClick: () => this.retryPage(page) }, t('load_failed_retry', this.locale)))));
5113
+ }
5114
+ else {
5115
+ renderedRows.push(h("tr", { class: "mrd-table__row mrd-table__row--loading" }, h("td", { class: "mrd-table__cell--placeholder", colSpan: colCount }, h("span", { class: "mrd-table__placeholder-bar" }))));
5116
+ }
4868
5117
  }
4869
5118
  else {
4870
5119
  renderedRows.push(h("tr", { class: "mrd-table__row mrd-table__row--clickable", style: { background: i % 2 === 0 ? '' : 'var(--mrd-color-neutral-100)' }, onClick: () => this.mrdRowClick.emit(row) }, this.columns.map(col => this.renderCell(col, row))));
@@ -4882,21 +5131,14 @@ const MrdTable = class {
4882
5131
  isActive ? `mrd-table__header--sorted-${this.sortDir}` : '',
4883
5132
  isFiltered ? 'mrd-table__header--filtered' : '',
4884
5133
  ].filter(Boolean).join(' ');
4885
- 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()));
4886
- }))), 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()));
4887
- }
4888
- renderFilterIcon() {
4889
- 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" }))));
5134
+ 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)));
5135
+ }))), 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()));
4890
5136
  }
4891
5137
  renderTextblockModal() {
4892
- if (this.textblockModal === null)
4893
- return null;
4894
- 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))));
5138
+ return h(TextblockModal, { text: this.textblockModal, locale: this.locale, onClose: () => this.closeTextblockModal() });
4895
5139
  }
4896
5140
  renderJsonModal() {
4897
- if (this.jsonModal === null)
4898
- return null;
4899
- 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 }))));
5141
+ return h(JsonModal, { html: this.jsonModal, locale: this.locale, onClose: () => this.closeJsonModal() });
4900
5142
  }
4901
5143
  get el() { return getElement(this); }
4902
5144
  static get watchers() { return {
@@ -4908,9 +5150,9 @@ const MrdTable = class {
4908
5150
  }]
4909
5151
  }; }
4910
5152
  };
4911
- MrdTable.style = mrdTableScss();
5153
+ MrdTable.style = mrdTableCss();
4912
5154
 
4913
- 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)}`;
5155
+ 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)}`;
4914
5156
 
4915
5157
  const MrdTextField = class {
4916
5158
  constructor(hostRef) {
@@ -4931,23 +5173,17 @@ const MrdTextField = class {
4931
5173
  };
4932
5174
  this.handleBlur = (e) => {
4933
5175
  const val = e.target.value;
4934
- if (this.required && !validateRequired(val)) {
4935
- this.error = t('required', this.locale);
4936
- }
4937
- else {
4938
- this.error = '';
4939
- }
5176
+ this.error = requiredError(val, this.required, this.locale);
4940
5177
  this.mrdBlur.emit({ name: this.name, value: val });
4941
5178
  };
4942
5179
  }
4943
5180
  render() {
4944
- const hasError = !!this.error;
4945
- 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))));
5181
+ 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 }))));
4946
5182
  }
4947
5183
  };
4948
- MrdTextField.style = mrdTextFieldScss();
5184
+ MrdTextField.style = mrdTextFieldCss();
4949
5185
 
4950
- 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)}`;
5186
+ 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}`;
4951
5187
 
4952
5188
  const MrdTextareaField = class {
4953
5189
  constructor(hostRef) {
@@ -5000,12 +5236,7 @@ const MrdTextareaField = class {
5000
5236
  var _a, _b;
5001
5237
  if (!range) {
5002
5238
  const html = (_b = (_a = this.editorEl.querySelector('.ql-editor')) === null || _a === void 0 ? void 0 : _a.innerHTML) !== null && _b !== void 0 ? _b : '';
5003
- if (this.required && !validateRequired(html)) {
5004
- this.error = t('required', this.locale);
5005
- }
5006
- else {
5007
- this.error = '';
5008
- }
5239
+ this.error = requiredError(html, this.required, this.locale);
5009
5240
  this.mrdBlur.emit({ name: this.name, value: html });
5010
5241
  }
5011
5242
  });
@@ -5016,13 +5247,13 @@ const MrdTextareaField = class {
5016
5247
  }
5017
5248
  }
5018
5249
  render() {
5019
- 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))));
5250
+ 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 }))));
5020
5251
  }
5021
5252
  get el() { return getElement(this); }
5022
5253
  };
5023
- MrdTextareaField.style = mrdTextareaFieldScss();
5254
+ MrdTextareaField.style = mrdTextareaFieldCss();
5024
5255
 
5025
- 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)}`;
5256
+ 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}`;
5026
5257
 
5027
5258
  const MrdTimeField = class {
5028
5259
  constructor(hostRef) {
@@ -5038,12 +5269,7 @@ const MrdTimeField = class {
5038
5269
  this.error = '';
5039
5270
  this.handleChange = (e) => {
5040
5271
  const val = e.target.value;
5041
- if (this.required && !validateRequired(val)) {
5042
- this.error = t('required', this.locale);
5043
- }
5044
- else {
5045
- this.error = '';
5046
- }
5272
+ this.error = requiredError(val, this.required, this.locale);
5047
5273
  this.mrdChange.emit({ name: this.name, value: val });
5048
5274
  };
5049
5275
  this.handleBlur = (e) => {
@@ -5052,10 +5278,9 @@ const MrdTimeField = class {
5052
5278
  };
5053
5279
  }
5054
5280
  render() {
5055
- const hasError = !!this.error;
5056
- 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))));
5281
+ 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 }))));
5057
5282
  }
5058
5283
  };
5059
- MrdTimeField.style = mrdTimeFieldScss();
5284
+ MrdTimeField.style = mrdTimeFieldCss();
5060
5285
 
5061
5286
  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 };