@mmlogic/components 0.3.11 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/dist/cjs/{index-BPj2cBXs.js → index-CAzwGt9u.js} +38 -0
  2. package/dist/cjs/loader.cjs.js +1 -1
  3. package/dist/cjs/mosterdcomponents.cjs.js +1 -1
  4. package/dist/cjs/mrd-boolean-field_23.cjs.entry.js +1203 -1084
  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} +11 -13
  57. package/dist/collection/components/{mrd-table → table/mrd-table}/mrd-table.js +111 -439
  58. package/dist/collection/components/table/mrd-table/table-filter-popup.js +85 -0
  59. package/dist/collection/components/table/mrd-table/table-parts.js +110 -0
  60. package/dist/collection/components/table/mrd-table/table-query.js +178 -0
  61. package/dist/collection/components/table/mrd-table/virtual-scroll.js +49 -0
  62. package/dist/collection/dev/app.js +19 -18
  63. package/dist/collection/dev/example-data.js +58 -43
  64. package/dist/collection/utils/i18n.js +8 -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 +2 -2
  94. package/dist/esm/mosterdcomponents.js +2 -2
  95. package/dist/esm/mrd-boolean-field_23.entry.js +1203 -1084
  96. package/dist/mosterdcomponents/mosterdcomponents.css +1 -1
  97. package/dist/mosterdcomponents/mosterdcomponents.esm.js +1 -1
  98. package/dist/mosterdcomponents/p-9b3c0917.entry.js +1 -0
  99. package/dist/mosterdcomponents/p-DiSEJMA8.js +2 -0
  100. package/dist/types/components/{mrd-document-container → documents/mrd-document-container}/mrd-document-container.d.ts +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 +6 -13
  129. package/dist/types/components/table/mrd-table/table-filter-popup.d.ts +35 -0
  130. package/dist/types/components/table/mrd-table/table-parts.d.ts +61 -0
  131. package/dist/types/components/table/mrd-table/table-query.d.ts +50 -0
  132. package/dist/types/components/table/mrd-table/virtual-scroll.d.ts +26 -0
  133. package/dist/types/components.d.ts +3 -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,6 +120,7 @@ const translations = {
47
120
  drop_file_here: 'Sleep bestand hierheen of',
48
121
  browse: 'bladeren',
49
122
  file_too_large: 'Bestand is te groot',
123
+ invalid_image: 'Selecteer een afbeeldingsbestand',
50
124
  search_results: 'Zoekresultaten',
51
125
  no_results: 'Geen resultaten gevonden',
52
126
  loading: 'Laden...',
@@ -119,6 +193,7 @@ const translations = {
119
193
  drop_file_here: 'Drop file here or',
120
194
  browse: 'browse',
121
195
  file_too_large: 'File is too large',
196
+ invalid_image: 'Please select an image file',
122
197
  search_results: 'Search results',
123
198
  no_results: 'No results found',
124
199
  loading: 'Loading...',
@@ -191,6 +266,7 @@ const translations = {
191
266
  drop_file_here: 'اسحب الملف هنا أو',
192
267
  browse: 'تصفح',
193
268
  file_too_large: 'الملف كبير جداً',
269
+ invalid_image: 'يرجى اختيار ملف صورة',
194
270
  search_results: 'نتائج البحث',
195
271
  no_results: 'لم يتم العثور على نتائج',
196
272
  loading: 'جار التحميل...',
@@ -257,6 +333,7 @@ const translations = {
257
333
  drop_file_here: 'Déposez le fichier ici ou',
258
334
  browse: 'parcourir',
259
335
  file_too_large: 'Le fichier est trop volumineux',
336
+ invalid_image: 'Veuillez sélectionner un fichier image',
260
337
  search_results: 'Résultats de recherche',
261
338
  no_results: 'Aucun résultat trouvé',
262
339
  loading: 'Chargement...',
@@ -323,6 +400,7 @@ const translations = {
323
400
  drop_file_here: 'Datei hier ablegen oder',
324
401
  browse: 'durchsuchen',
325
402
  file_too_large: 'Datei ist zu groß',
403
+ invalid_image: 'Bitte eine Bilddatei auswählen',
326
404
  search_results: 'Suchergebnisse',
327
405
  no_results: 'Keine Ergebnisse gefunden',
328
406
  loading: 'Laden...',
@@ -389,6 +467,7 @@ const translations = {
389
467
  drop_file_here: 'Suelte el archivo aquí o',
390
468
  browse: 'explorar',
391
469
  file_too_large: 'El archivo es demasiado grande',
470
+ invalid_image: 'Seleccione un archivo de imagen',
392
471
  search_results: 'Resultados de búsqueda',
393
472
  no_results: 'No se encontraron resultados',
394
473
  loading: 'Cargando...',
@@ -455,6 +534,7 @@ const translations = {
455
534
  drop_file_here: 'Trascina il file qui o',
456
535
  browse: 'sfoglia',
457
536
  file_too_large: 'Il file è troppo grande',
537
+ invalid_image: 'Seleziona un file immagine',
458
538
  search_results: 'Risultati della ricerca',
459
539
  no_results: 'Nessun risultato trovato',
460
540
  loading: 'Caricamento...',
@@ -521,6 +601,7 @@ const translations = {
521
601
  drop_file_here: 'Перетягніть файл сюди або',
522
602
  browse: 'огляд',
523
603
  file_too_large: 'Файл занадто великий',
604
+ invalid_image: 'Будь ласка, виберіть файл зображення',
524
605
  search_results: 'Результати пошуку',
525
606
  no_results: 'Результатів не знайдено',
526
607
  loading: 'Завантаження...',
@@ -631,80 +712,22 @@ function validateNumber(value, dataType) {
631
712
  return true;
632
713
  }
633
714
 
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);
715
+ /**
716
+ * Shared building blocks for the leaf field components.
717
+ * `base` is the BEM block name, e.g. 'mrd-text-field'.
718
+ */
719
+ const FieldLabel = ({ base, label, required }) => label ? h("label", { class: `${base}__label${required ? ` ${base}__label--required` : ''}` }, label) : null;
720
+ const FieldError = ({ base, error }) => error ? h("span", { class: `${base}__error` }, error) : null;
721
+ /** Class string for the form control, with the --error modifier when applicable. */
722
+ function controlClass(base, hasError, element = 'input') {
723
+ return `${base}__${element}${hasError ? ` ${base}__${element}--error` : ''}`;
657
724
  }
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;
725
+ /** Returns the localised required-error, or '' when the value passes. */
726
+ function requiredError(value, required, locale) {
727
+ return required && !validateRequired(value) ? t('required', locale) : '';
705
728
  }
706
729
 
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)}`;
730
+ const mrdCurrencyFieldCss = () => `.sc-mrd-currency-field-h{display:block}.mrd-currency-field.sc-mrd-currency-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-currency-field__label.sc-mrd-currency-field{display:block;font-family:var(--mrd-font-family);font-size:var(--mrd-label-font-size);font-weight:var(--mrd-label-font-weight);color:var(--mrd-label-color)}.mrd-currency-field__label--required.sc-mrd-currency-field::after{content:" *";color:var(--mrd-color-danger)}.mrd-currency-field__row.sc-mrd-currency-field{display:flex;gap:var(--mrd-space-2);align-items:stretch}.mrd-currency-field__amount.sc-mrd-currency-field{display:block;width:100%;height:var(--mrd-input-height);padding:var(--mrd-input-padding-y) var(--mrd-input-padding-x);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-input-color);background-color:var(--mrd-input-bg);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);transition:border-color var(--mrd-transition), box-shadow var(--mrd-transition);outline:none;appearance:none;box-sizing:border-box}.mrd-currency-field__amount.sc-mrd-currency-field::placeholder{color:var(--mrd-input-placeholder-color)}.mrd-currency-field__amount.sc-mrd-currency-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-currency-field__amount.sc-mrd-currency-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.mrd-currency-field__amount--error.sc-mrd-currency-field{border-color:var(--mrd-border-color-error)}.mrd-currency-field__amount--error.sc-mrd-currency-field:focus{box-shadow:var(--mrd-shadow-focus-error)}.mrd-currency-field__amount.sc-mrd-currency-field{flex:1;text-align:right}.mrd-currency-field__currency.sc-mrd-currency-field{width:90px;height:var(--mrd-input-height);padding:var(--mrd-input-padding-y) var(--mrd-space-2);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);font-weight:var(--mrd-font-weight-medium);color:var(--mrd-input-color);background-color:var(--mrd-color-neutral-50);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);outline:none;cursor:pointer;box-sizing:border-box;appearance:none;text-align:center}.mrd-currency-field__currency.sc-mrd-currency-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-currency-field__currency.sc-mrd-currency-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.mrd-currency-field__error.sc-mrd-currency-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}`;
708
731
 
709
732
  const COMMON_CURRENCIES = [
710
733
  'EUR', 'USD', 'GBP', 'CHF', 'JPY', 'CNY', 'AUD', 'CAD',
@@ -731,12 +754,7 @@ const MrdCurrencyField = class {
731
754
  this.handleAmountBlur = (e) => {
732
755
  const raw = e.target.value;
733
756
  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
- }
757
+ this.error = requiredError(raw, this.required, this.locale);
740
758
  const val = { amount: parsed, currency: this.currency };
741
759
  this.mrdChange.emit({ name: this.name, value: val });
742
760
  this.mrdBlur.emit({ name: this.name, value: val });
@@ -755,12 +773,12 @@ const MrdCurrencyField = class {
755
773
  }
756
774
  render() {
757
775
  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))));
776
+ return (h(Host, { key: '24c530db6e0420af39fa0a35b31e966286f2d00c' }, h("div", { key: '795bc336425fbf1b86828f4a8f5df93930169a3c', class: "mrd-currency-field" }, h(FieldLabel, { key: 'b302cd9296c29ed5719b1f768bd5d4eea86f6406', base: "mrd-currency-field", label: this.label, required: this.required }), h("div", { key: '7efca51615f405ffd660e120accae32f55a9b5a0', class: "mrd-currency-field__row" }, h("input", { key: '5c6fd3549d5631fba49a8a701e6c3a1d0a672890', class: controlClass('mrd-currency-field', hasError, 'amount'), type: "text", inputMode: "decimal", name: `${this.name}_amount`, value: this.amountDisplay, placeholder: "0.00", required: this.required, disabled: this.disabled, onInput: this.handleAmountInput, onBlur: this.handleAmountBlur }), h("select", { key: '83ad5e92b623c3c60d161b8828e780adb476682c', class: "mrd-currency-field__currency", disabled: this.disabled, onChange: this.handleCurrencyChange }, COMMON_CURRENCIES.map(c => (h("option", { key: c, value: c, selected: c === this.currency }, c))))), h(FieldError, { key: 'b059290bb566b119c4f192e750b3e365446243e6', base: "mrd-currency-field", error: this.error }))));
759
777
  }
760
778
  };
761
- MrdCurrencyField.style = mrdCurrencyFieldScss();
779
+ MrdCurrencyField.style = mrdCurrencyFieldCss();
762
780
 
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)}`;
781
+ const mrdDateFieldCss = () => `.sc-mrd-date-field-h{display:block}.mrd-date-field.sc-mrd-date-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-date-field__label.sc-mrd-date-field{display:block;font-family:var(--mrd-font-family);font-size:var(--mrd-label-font-size);font-weight:var(--mrd-label-font-weight);color:var(--mrd-label-color)}.mrd-date-field__label--required.sc-mrd-date-field::after{content:" *";color:var(--mrd-color-danger)}.mrd-date-field__input.sc-mrd-date-field{display:block;width:100%;height:var(--mrd-input-height);padding:var(--mrd-input-padding-y) var(--mrd-input-padding-x);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-input-color);background-color:var(--mrd-input-bg);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);transition:border-color var(--mrd-transition), box-shadow var(--mrd-transition);outline:none;appearance:none;box-sizing:border-box}.mrd-date-field__input.sc-mrd-date-field::placeholder{color:var(--mrd-input-placeholder-color)}.mrd-date-field__input.sc-mrd-date-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-date-field__input.sc-mrd-date-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.mrd-date-field__input--error.sc-mrd-date-field{border-color:var(--mrd-border-color-error)}.mrd-date-field__input--error.sc-mrd-date-field:focus{box-shadow:var(--mrd-shadow-focus-error)}.mrd-date-field__error.sc-mrd-date-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}.mrd-date-field__input.sc-mrd-date-field{cursor:pointer}`;
764
782
 
765
783
  const MrdDateField = class {
766
784
  constructor(hostRef) {
@@ -776,12 +794,7 @@ const MrdDateField = class {
776
794
  this.error = '';
777
795
  this.handleChange = (e) => {
778
796
  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
- }
797
+ this.error = requiredError(val, this.required, this.locale);
785
798
  this.mrdChange.emit({ name: this.name, value: val });
786
799
  };
787
800
  this.handleBlur = (e) => {
@@ -790,13 +803,12 @@ const MrdDateField = class {
790
803
  };
791
804
  }
792
805
  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))));
806
+ return (h(Host, { key: '71be9e4bcc87b40cf3b777d3fe0bff23c1a0fa94' }, h("div", { key: '40ced03df5d4185264ba9d03c832b3870ce8ae19', class: "mrd-date-field" }, h(FieldLabel, { key: 'd85ec7c4617a22c8c5862253e8090c85484f8c41', base: "mrd-date-field", label: this.label, required: this.required }), h("input", { key: 'c9211fdefdd9527c7ff40ed9de33153303fc1742', class: controlClass('mrd-date-field', !!this.error), type: "date", name: this.name, value: this.value, required: this.required, disabled: this.disabled, onChange: this.handleChange, onBlur: this.handleBlur }), h(FieldError, { key: '9dd64475bf8a77bea5344faa71f20485b34b86f9', base: "mrd-date-field", error: this.error }))));
795
807
  }
796
808
  };
797
- MrdDateField.style = mrdDateFieldScss();
809
+ MrdDateField.style = mrdDateFieldCss();
798
810
 
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)}`;
811
+ const mrdDatetimeFieldCss = () => `.sc-mrd-datetime-field-h{display:block}.mrd-datetime-field.sc-mrd-datetime-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-datetime-field__label.sc-mrd-datetime-field{display:block;font-family:var(--mrd-font-family);font-size:var(--mrd-label-font-size);font-weight:var(--mrd-label-font-weight);color:var(--mrd-label-color)}.mrd-datetime-field__label--required.sc-mrd-datetime-field::after{content:" *";color:var(--mrd-color-danger)}.mrd-datetime-field__input.sc-mrd-datetime-field{display:block;width:100%;height:var(--mrd-input-height);padding:var(--mrd-input-padding-y) var(--mrd-input-padding-x);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-input-color);background-color:var(--mrd-input-bg);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);transition:border-color var(--mrd-transition), box-shadow var(--mrd-transition);outline:none;appearance:none;box-sizing:border-box}.mrd-datetime-field__input.sc-mrd-datetime-field::placeholder{color:var(--mrd-input-placeholder-color)}.mrd-datetime-field__input.sc-mrd-datetime-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-datetime-field__input.sc-mrd-datetime-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.mrd-datetime-field__input--error.sc-mrd-datetime-field{border-color:var(--mrd-border-color-error)}.mrd-datetime-field__input--error.sc-mrd-datetime-field:focus{box-shadow:var(--mrd-shadow-focus-error)}.mrd-datetime-field__error.sc-mrd-datetime-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}.mrd-datetime-field__input.sc-mrd-datetime-field{cursor:pointer}`;
800
812
 
801
813
  const MrdDatetimeField = class {
802
814
  constructor(hostRef) {
@@ -814,12 +826,7 @@ const MrdDatetimeField = class {
814
826
  this.handleChange = (e) => {
815
827
  const localVal = e.target.value;
816
828
  this.localValue = localVal;
817
- if (this.required && !validateRequired(localVal)) {
818
- this.error = t('required', this.locale);
819
- }
820
- else {
821
- this.error = '';
822
- }
829
+ this.error = requiredError(localVal, this.required, this.locale);
823
830
  this.mrdChange.emit({ name: this.name, value: this.localToUtc(localVal) });
824
831
  };
825
832
  this.handleBlur = (e) => {
@@ -853,8 +860,7 @@ const MrdDatetimeField = class {
853
860
  return d.toISOString().replace(/\.\d{3}Z$/, 'Z');
854
861
  }
855
862
  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))));
863
+ return (h(Host, { key: 'ac07ec2ba79cde998d1247e9d71de336c0e72a64' }, h("div", { key: '8144cf68c4b6b9cbc8396903b84bb355f380ceda', class: "mrd-datetime-field" }, h(FieldLabel, { key: '972686469f68c932e33b8d2c3806422553a3cce3', base: "mrd-datetime-field", label: this.label, required: this.required }), h("input", { key: '370b6032c38fbee22e662c1b2871f96b53b58956', class: controlClass('mrd-datetime-field', !!this.error), type: "datetime-local", name: this.name, value: this.localValue, required: this.required, disabled: this.disabled, onChange: this.handleChange, onBlur: this.handleBlur }), h(FieldError, { key: 'b7a812f82a6b0d2c938aa1f1c2494df685258555', base: "mrd-datetime-field", error: this.error }))));
858
864
  }
859
865
  static get watchers() { return {
860
866
  "value": [{
@@ -862,9 +868,9 @@ const MrdDatetimeField = class {
862
868
  }]
863
869
  }; }
864
870
  };
865
- MrdDatetimeField.style = mrdDatetimeFieldScss();
871
+ MrdDatetimeField.style = mrdDatetimeFieldCss();
866
872
 
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}`;
873
+ const mrdDocumentContainerCss = () => `.sc-mrd-document-container-h{display:block}.mrd-document-container__toolbar.sc-mrd-document-container{display:flex;align-items:center;justify-content:flex-end;gap:var(--mrd-space-2);padding:var(--mrd-space-2) var(--mrd-space-4);border-bottom:1px solid var(--mrd-color-neutral-100)}.mrd-document-container__action.sc-mrd-document-container{display:inline-flex;align-items:center;gap:var(--mrd-space-2);height:1.625rem;padding:0 var(--mrd-space-3);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-700);background:var(--mrd-color-white);border:1px solid var(--mrd-color-neutral-200);border-radius:var(--mrd-border-radius);cursor:pointer;transition:background var(--mrd-transition-fast), border-color var(--mrd-transition-fast)}.mrd-document-container__action.sc-mrd-document-container svg.sc-mrd-document-container{width:1rem;height:1rem;color:var(--mrd-color-folder)}.mrd-document-container__action.sc-mrd-document-container:hover:not(:disabled){background:var(--mrd-color-neutral-50);border-color:var(--mrd-color-neutral-300)}.mrd-document-container__action.sc-mrd-document-container:disabled{opacity:0.5;cursor:not-allowed}.mrd-document-container__seg.sc-mrd-document-container{display:inline-flex;gap:2px;padding:2px;background:var(--mrd-color-neutral-100);border-radius:var(--mrd-border-radius)}.mrd-document-container__seg-btn.sc-mrd-document-container{width:1.875rem;height:1.625rem;display:grid;place-items:center;border:none;background:none;border-radius:var(--mrd-border-radius-sm);color:var(--mrd-color-neutral-500);cursor:pointer;transition:color var(--mrd-transition-fast), background var(--mrd-transition-fast)}.mrd-document-container__seg-btn.sc-mrd-document-container:hover{color:var(--mrd-color-neutral-800)}.mrd-document-container__seg-btn[aria-pressed=true].sc-mrd-document-container{background:var(--mrd-color-white);color:var(--mrd-color-primary-dark);box-shadow:var(--mrd-shadow-sm)}.mrd-document-container__seg-btn.sc-mrd-document-container svg.sc-mrd-document-container{width:1rem;height:1rem}`;
868
874
 
869
875
  const MrdDocumentContainer = class {
870
876
  constructor(hostRef) {
@@ -896,8 +902,8 @@ const MrdDocumentContainer = class {
896
902
  /** Whether the currently mounted table has been init()'d. Reset on every mode switch. */
897
903
  this.tableInited = false;
898
904
  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);
905
+ var _a;
906
+ (_a = this.listEl) === null || _a === void 0 ? void 0 : _a.createFolder();
901
907
  };
902
908
  }
903
909
  /** The embedded table does not self-load: like every mrd-table it waits for the
@@ -909,7 +915,7 @@ const MrdDocumentContainer = class {
909
915
  if (this.mode === 'list' && this.tableEl && !this.tableInited) {
910
916
  this.tableInited = true;
911
917
  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); });
918
+ Promise.resolve((_a = table.componentOnReady) === null || _a === void 0 ? void 0 : _a.call(table)).then(() => table.init());
913
919
  }
914
920
  }
915
921
  setMode(mode) {
@@ -969,13 +975,240 @@ const MrdDocumentContainer = class {
969
975
  }
970
976
  render() {
971
977
  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())));
978
+ return (h(Host, { key: '018c9eacd169fdf7d352a51472651348af2b45df' }, this.renderToolbar(), h("div", { key: '5ff2ac77d4d12369905696ff075f99785dc1c809', class: "mrd-document-container__body", style: treeMode ? { height: `${this.height}px`, overflowY: 'auto' } : {} }, treeMode ? this.renderTree() : this.renderList())));
973
979
  }
974
980
  get el() { return getElement(this); }
975
981
  };
976
- MrdDocumentContainer.style = mrdDocumentContainerScss();
982
+ MrdDocumentContainer.style = mrdDocumentContainerCss();
983
+
984
+ /**
985
+ * Shared path/query-param conventions for list requests,
986
+ * used by mrd-table and mrd-document-list.
987
+ */
988
+ /** Applies the view-level static filters to `params` using the API operator conventions. */
989
+ function applyViewFilters(params, filters) {
990
+ var _a, _b, _c;
991
+ for (const f of filters !== null && filters !== void 0 ? filters : []) {
992
+ if (!f.name)
993
+ continue;
994
+ if (f.operator === 'EMPTY') {
995
+ params.set(f.name, '');
996
+ continue;
997
+ }
998
+ if (f.operator === 'NOT_EMPTY') {
999
+ params.set(f.name + '_notempty', 'true');
1000
+ continue;
1001
+ }
1002
+ if (f.operator === 'STARTS_WITH') {
1003
+ params.set(f.name + '_startswith', String((_a = f.value) !== null && _a !== void 0 ? _a : ''));
1004
+ continue;
1005
+ }
1006
+ if (f.operator === 'FROM') {
1007
+ params.set(f.name + '_from', String((_b = f.value) !== null && _b !== void 0 ? _b : ''));
1008
+ continue;
1009
+ }
1010
+ if (f.operator === 'TO') {
1011
+ params.set(f.name + '_to', String((_c = f.value) !== null && _c !== void 0 ? _c : ''));
1012
+ continue;
1013
+ }
1014
+ if (f.value != null) {
1015
+ params.set(f.name, String(f.value));
1016
+ }
1017
+ }
1018
+ }
1019
+ /** VIEW: `/{dataClass}`; RELATED_VIEW: `/{fromClass}/{parentId}/{dataClass}`. */
1020
+ function buildListPath(opts) {
1021
+ var _a, _b, _c;
1022
+ if (opts.isRelatedView) {
1023
+ return `/${(_a = opts.fromClass) !== null && _a !== void 0 ? _a : ''}/${opts.parentId}/${(_b = opts.dataClass) !== null && _b !== void 0 ? _b : ''}`;
1024
+ }
1025
+ return `/${(_c = opts.dataClass) !== null && _c !== void 0 ? _c : ''}`;
1026
+ }
1027
+
1028
+ /**
1029
+ * Tree model and pure tree logic for mrd-document-list.
1030
+ * Nodes are mutated in place; the component triggers re-renders via bump().
1031
+ */
1032
+ /** Normalise a folder path: null/""/"/" → root ([]); else split on "/" dropping empties. */
1033
+ function splitFolder(path) {
1034
+ if (path == null)
1035
+ return [];
1036
+ const s = String(path).trim();
1037
+ if (s === '' || s === '/')
1038
+ return [];
1039
+ return s.split('/').map(x => x.trim()).filter(Boolean);
1040
+ }
1041
+ function makeContainerNode(href, label, count) {
1042
+ return {
1043
+ id: 'c:' + href, kind: 'container', label, href,
1044
+ hasDocs: false, docCount: 0, totalCount: count, children: [],
1045
+ open: false, loading: false, foldersLoaded: false, docsLoaded: false, docs: [],
1046
+ };
1047
+ }
1048
+ function makeFolderNode(id, label, containerId) {
1049
+ return {
1050
+ id, kind: 'folder', label, containerId,
1051
+ hasDocs: false, docCount: 0, totalCount: 0, children: [],
1052
+ open: false, loading: false, foldersLoaded: false, docsLoaded: false, docs: [],
1053
+ };
1054
+ }
1055
+ /** Recompute totalCount over the subtree; returns the node's aggregate. */
1056
+ function computeTotals(node) {
1057
+ let total = node.docCount;
1058
+ for (const c of node.children)
1059
+ total += computeTotals(c);
1060
+ node.totalCount = total;
1061
+ return total;
1062
+ }
1063
+ /** Folder path segments of a node relative to its container (derived from its id). */
1064
+ function segmentsOf(node, container) {
1065
+ if (node.kind === 'container')
1066
+ return [];
1067
+ const prefix = container.id + '/';
1068
+ const rest = node.id.startsWith(prefix) ? node.id.slice(prefix.length) : '';
1069
+ return rest ? rest.split('/') : [];
1070
+ }
1071
+ /** Folder string a node represents: the raw distinct value when it holds
1072
+ * documents, else derived from its path segments; null for a container root. */
1073
+ function folderStringOf(node, container) {
1074
+ if (node.kind === 'container')
1075
+ return null;
1076
+ if (node.fullPath != null && node.fullPath !== '')
1077
+ return node.fullPath;
1078
+ const segs = segmentsOf(node, container);
1079
+ return segs.length ? '/' + segs.join('/') : null;
1080
+ }
1081
+ /** Strip a single trailing extension for the document title. */
1082
+ function stripExtension(name) {
1083
+ return name.replace(/\.[^./\\]+$/, '');
1084
+ }
1085
+ /** Rebuild a container's folder subtree from the /distinct folder strings.
1086
+ * New nodes are registered in `nodeIndex`; the container is mutated in place. */
1087
+ function applyFolderDistinct(container, values, nodeIndex) {
1088
+ container.children = [];
1089
+ container.hasDocs = false;
1090
+ container.docCount = 0;
1091
+ for (const v of values) {
1092
+ const raw = typeof v.value === 'string' ? v.value : v.value == null ? '' : String(v.value);
1093
+ const segs = splitFolder(raw);
1094
+ if (segs.length === 0) {
1095
+ // Root documents — the container's own direct documents.
1096
+ container.hasDocs = true;
1097
+ container.docCount = v.count;
1098
+ container.fullPath = raw;
1099
+ continue;
1100
+ }
1101
+ let node = container;
1102
+ const acc = [];
1103
+ for (const seg of segs) {
1104
+ acc.push(seg);
1105
+ let child = node.children.find(c => c.label === seg);
1106
+ if (!child) {
1107
+ child = makeFolderNode(container.id + '/' + acc.join('/'), seg, container.id);
1108
+ node.children.push(child);
1109
+ nodeIndex.set(child.id, child);
1110
+ }
1111
+ node = child;
1112
+ }
1113
+ node.hasDocs = true;
1114
+ node.docCount = v.count;
1115
+ node.fullPath = raw;
1116
+ }
1117
+ computeTotals(container);
1118
+ container.foldersLoaded = true;
1119
+ container.loading = false;
1120
+ }
1121
+ /** Optimistic in-place tree update for a document moved between folders. */
1122
+ function applyDocMove(doc, fromNode, toNode, targetFolder) {
1123
+ fromNode.docs = fromNode.docs.filter(d => d !== doc);
1124
+ fromNode.docCount = Math.max(0, fromNode.docCount - 1);
1125
+ // A now-empty folder should stop showing an expand chevron (it disappears on
1126
+ // the next reload anyway, since it is derived from document folder strings).
1127
+ if (fromNode.docsLoaded)
1128
+ fromNode.hasDocs = fromNode.docs.length > 0;
1129
+ toNode.hasDocs = true;
1130
+ toNode.pending = false; // a pending folder is now materialised
1131
+ toNode.docCount += 1;
1132
+ if (toNode.kind === 'folder')
1133
+ toNode.fullPath = targetFolder !== null && targetFolder !== void 0 ? targetFolder : '';
1134
+ if (toNode.docsLoaded)
1135
+ toNode.docs = [...toNode.docs, doc];
1136
+ }
1137
+
1138
+ function chevron(open, leaf) {
1139
+ return (h("span", { class: `mrd-document-list__chev${leaf ? ' mrd-document-list__chev--leaf' : ''}${open ? ' mrd-document-list__chev--open' : ''}` }, h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M9 6l6 6-6 6" }))));
1140
+ }
1141
+ function dossierIcon() {
1142
+ return (h("svg", { class: "mrd-document-list__icon mrd-document-list__icon--dossier", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" })));
1143
+ }
1144
+ function folderIcon() {
1145
+ return (h("svg", { class: "mrd-document-list__icon mrd-document-list__icon--folder", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" })));
1146
+ }
1147
+ function docIcon() {
1148
+ return (h("svg", { class: "mrd-document-list__icon mrd-document-list__icon--doc", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }), h("path", { d: "M14 2v6h6" })));
1149
+ }
1150
+ function indent(depth) {
1151
+ return h("span", { class: "mrd-document-list__indent", style: { width: `${depth * 18}px` } });
1152
+ }
1153
+ function renderLoadingRow(ctx, depth) {
1154
+ return (h("div", { class: "mrd-document-list__loading", key: "loading" }, indent(depth), h("span", { class: "mrd-document-list__spinner" }), t('loading', ctx.locale)));
1155
+ }
1156
+ function renderUploadingRow(ctx, depth) {
1157
+ return (h("div", { class: "mrd-document-list__loading", key: "uploading" }, indent(depth), h("span", { class: "mrd-document-list__spinner" }), t('upload_file', ctx.locale)));
1158
+ }
1159
+ function renderDocRow(ctx, doc, node, container, depth) {
1160
+ var _a, _b, _c, _d, _e;
1161
+ const label = (_b = (_a = doc === null || doc === void 0 ? void 0 : doc[ctx.titleField]) !== null && _a !== void 0 ? _a : doc === null || doc === void 0 ? void 0 : doc.name) !== null && _b !== void 0 ? _b : '';
1162
+ const dateRaw = ctx.dateField ? doc === null || doc === void 0 ? void 0 : doc[ctx.dateField] : undefined;
1163
+ const date = dateRaw ? formatDate(dateRaw, ctx.locale) : '';
1164
+ return (h("div", { class: "mrd-document-list__row mrd-document-list__row--doc", key: (_e = (_d = (_c = doc === null || doc === void 0 ? void 0 : doc._links) === null || _c === void 0 ? void 0 : _c.self) === null || _d === void 0 ? void 0 : _d.href) !== null && _e !== void 0 ? _e : label, draggable: true, onClick: () => ctx.on.openDoc(doc), onDragStart: (e) => ctx.on.docDragStart(e, doc, node), onDragEnd: ctx.on.docDragEnd, onDragOver: (e) => ctx.on.nodeDragOver(e, node), onDragLeave: () => ctx.on.nodeDragLeave(node), onDrop: (e) => ctx.on.nodeDrop(e, node, container) }, indent(depth), chevron(false, true), docIcon(), h("span", { class: "mrd-document-list__label" }, label), date && h("span", { class: "mrd-document-list__date" }, date)));
1165
+ }
1166
+ function renderFolderEditRow(ctx, node, depth) {
1167
+ return (h("div", { class: "mrd-document-list__node", key: node.id }, h("div", { class: "mrd-document-list__row mrd-document-list__row--edit" }, indent(depth), chevron(false, true), folderIcon(), h("input", { class: "mrd-document-list__name-input", type: "text", placeholder: t('folder_name_placeholder', ctx.locale), ref: el => ctx.on.setPendingInputEl(el), onInput: ctx.on.pendingInput, onKeyDown: ctx.on.pendingKeyDown, onBlur: () => ctx.on.cancelFolder() })), node.error && (h("div", { class: "mrd-document-list__error", style: { paddingLeft: `${depth * 18 + 52}px` } }, node.error))));
1168
+ }
1169
+ function renderNodeChildren(ctx, container, node, depth) {
1170
+ const out = [];
1171
+ // Direct documents of this node (root docs live on the container node).
1172
+ if (node.hasDocs) {
1173
+ if (node.docsLoaded) {
1174
+ for (const doc of node.docs)
1175
+ out.push(renderDocRow(ctx, doc, node, container, depth));
1176
+ }
1177
+ else if (node.loading) {
1178
+ out.push(renderLoadingRow(ctx, depth));
1179
+ }
1180
+ }
1181
+ // Child folders.
1182
+ for (const child of node.children) {
1183
+ out.push(renderFolderNode(ctx, container, child, depth));
1184
+ }
1185
+ // An uploading file dropped onto this node.
1186
+ if (node.id === ctx.uploadingNodeId)
1187
+ out.push(renderUploadingRow(ctx, depth));
1188
+ return out;
1189
+ }
1190
+ function renderFolderNode(ctx, container, node, depth) {
1191
+ if (node.editing)
1192
+ return renderFolderEditRow(ctx, node, depth);
1193
+ const leaf = node.children.length === 0 && !node.hasDocs;
1194
+ const selected = node.id === ctx.selectedId;
1195
+ const cls = 'mrd-document-list__row'
1196
+ + (selected ? ' mrd-document-list__row--selected' : '')
1197
+ + (node.pending ? ' mrd-document-list__row--pending' : '')
1198
+ + (node.id === ctx.dropTargetId ? ' mrd-document-list__row--drop' : '');
1199
+ return (h("div", { class: "mrd-document-list__node", key: node.id }, h("div", { class: cls, onClick: () => ctx.on.toggleFolder(container, node), onDragOver: (e) => ctx.on.nodeDragOver(e, node), onDragLeave: () => ctx.on.nodeDragLeave(node), onDrop: (e) => ctx.on.nodeDrop(e, node, container) }, indent(depth), chevron(node.open, leaf), folderIcon(), h("span", { class: "mrd-document-list__label" }, node.label), h("span", { class: "mrd-document-list__count" }, node.totalCount)), node.open && h("div", { class: "mrd-document-list__kids" }, renderNodeChildren(ctx, container, node, depth + 1))));
1200
+ }
1201
+ function renderContainerNode(ctx, node, depth) {
1202
+ const selected = node.id === ctx.selectedId;
1203
+ const cls = 'mrd-document-list__row mrd-document-list__row--dossier'
1204
+ + (selected ? ' mrd-document-list__row--selected' : '')
1205
+ + (node.id === ctx.dropTargetId ? ' mrd-document-list__row--drop' : '');
1206
+ return (h("div", { class: "mrd-document-list__node", key: node.id }, h("div", { class: cls, onClick: () => ctx.on.toggleContainer(node), onDragOver: (e) => ctx.on.nodeDragOver(e, node), onDragLeave: () => ctx.on.nodeDragLeave(node), onDrop: (e) => ctx.on.nodeDrop(e, node, node) }, indent(depth), chevron(node.open, false), dossierIcon(), h("span", { class: "mrd-document-list__label" }, node.label), h("span", { class: "mrd-document-list__count" }, node.totalCount)), node.open && (h("div", { class: "mrd-document-list__kids" }, node.loading && !node.foldersLoaded
1207
+ ? renderLoadingRow(ctx, depth + 1)
1208
+ : renderNodeChildren(ctx, node, node, depth + 1)))));
1209
+ }
977
1210
 
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)}`;
1211
+ const mrdDocumentListCss = () => `@charset "UTF-8";.sc-mrd-document-list-h{display:block;height:100%}.mrd-document-list.sc-mrd-document-list{padding:var(--mrd-space-2) 0;min-height:100%;box-sizing:border-box}.mrd-document-list--drop-active.sc-mrd-document-list{outline:2px dashed var(--mrd-color-primary);outline-offset:-4px;background:var(--mrd-color-primary-50, rgba(22, 163, 74, 0.06))}.mrd-document-list__row.sc-mrd-document-list{display:flex;align-items:center;gap:var(--mrd-space-2);height:2.125rem;padding:0 var(--mrd-space-4);cursor:pointer;user-select:none;font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-800)}.mrd-document-list__row.sc-mrd-document-list:hover{background:var(--mrd-color-neutral-50)}.mrd-document-list__row--selected.sc-mrd-document-list{background:var(--mrd-color-primary-50, rgba(22, 163, 74, 0.1))}.mrd-document-list__row--selected.sc-mrd-document-list:hover{background:var(--mrd-color-primary-50, rgba(22, 163, 74, 0.1))}.mrd-document-list__row--pending.sc-mrd-document-list .mrd-document-list__label.sc-mrd-document-list{font-style:italic;color:var(--mrd-color-neutral-500)}.mrd-document-list__row--doc.sc-mrd-document-list{cursor:grab}.mrd-document-list__row--doc.sc-mrd-document-list:active{cursor:grabbing}.mrd-document-list__row--drop.sc-mrd-document-list{background:var(--mrd-color-primary-50, rgba(22, 163, 74, 0.1));box-shadow:inset 0 0 0 1px var(--mrd-color-primary)}.mrd-document-list__row--drop.sc-mrd-document-list:hover{background:var(--mrd-color-primary-50, rgba(22, 163, 74, 0.1))}.mrd-document-list__row--edit.sc-mrd-document-list{cursor:default}.mrd-document-list__name-input.sc-mrd-document-list{flex:1;min-width:0;height:1.625rem;padding:0 var(--mrd-space-2);font-size:var(--mrd-font-size-sm);font-family:inherit;color:var(--mrd-color-neutral-800);border:1px solid var(--mrd-color-primary);border-radius:var(--mrd-border-radius);outline:none;box-shadow:var(--mrd-shadow-focus)}.mrd-document-list__error.sc-mrd-document-list{font-size:var(--mrd-font-size-xs);color:var(--mrd-color-danger, #dc2626);padding-top:0.125rem;padding-bottom:0.25rem}.mrd-document-list__row--dossier.sc-mrd-document-list .mrd-document-list__label.sc-mrd-document-list{font-weight:var(--mrd-font-weight-semibold)}.mrd-document-list__indent.sc-mrd-document-list{flex:none}.mrd-document-list__chev.sc-mrd-document-list{width:1rem;height:1rem;flex:none;display:grid;place-items:center;color:var(--mrd-color-neutral-400);transition:transform var(--mrd-transition-fast)}.mrd-document-list__chev.sc-mrd-document-list svg.sc-mrd-document-list{width:0.6875rem;height:0.6875rem}.mrd-document-list__chev--open.sc-mrd-document-list{transform:rotate(90deg)}.mrd-document-list__chev--leaf.sc-mrd-document-list{visibility:hidden}.mrd-document-list__icon.sc-mrd-document-list{width:1.0625rem;height:1.0625rem;flex:none}.mrd-document-list__icon--dossier.sc-mrd-document-list{color:var(--mrd-color-primary)}.mrd-document-list__icon--folder.sc-mrd-document-list{color:var(--mrd-color-folder)}.mrd-document-list__icon--doc.sc-mrd-document-list{color:var(--mrd-color-neutral-400)}.mrd-document-list__label.sc-mrd-document-list{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mrd-document-list__count.sc-mrd-document-list{flex:none;font-family:var(--mrd-font-family-mono);font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-500);background:var(--mrd-color-neutral-100);border-radius:var(--mrd-border-radius-full);padding:0.0625rem 0.5rem}.mrd-document-list__date.sc-mrd-document-list{flex:none;font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-400);font-variant-numeric:tabular-nums}.mrd-document-list__loading.sc-mrd-document-list{display:flex;align-items:center;gap:var(--mrd-space-2);height:1.875rem;padding:0 var(--mrd-space-4);font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-400)}.mrd-document-list__spinner.sc-mrd-document-list{width:0.75rem;height:0.75rem;border:2px solid var(--mrd-color-neutral-300);border-top-color:var(--mrd-color-primary);border-radius:50%;animation:mrd-document-list-spin 0.7s linear infinite}@keyframes mrd-document-list-spin{to{transform:rotate(360deg)}}.mrd-document-list__empty.sc-mrd-document-list{padding:var(--mrd-space-8) var(--mrd-space-4);text-align:center;color:var(--mrd-color-neutral-400);font-size:var(--mrd-font-size-sm)}`;
979
1212
 
980
1213
  const MrdDocumentList = class {
981
1214
  constructor(hostRef) {
@@ -1042,7 +1275,7 @@ const MrdDocumentList = class {
1042
1275
  return;
1043
1276
  const { target, container } = resolved;
1044
1277
  const tempId = `${container.id}/__new__${this.newFolderSeq++}`;
1045
- const node = this.makeFolderNode(tempId, '', container.id);
1278
+ const node = makeFolderNode(tempId, '', container.id);
1046
1279
  node.pending = true;
1047
1280
  node.editing = true;
1048
1281
  target.children = [...target.children, node];
@@ -1181,7 +1414,7 @@ const MrdDocumentList = class {
1181
1414
  }
1182
1415
  /** Seed the single implied container from context and load its folders. */
1183
1416
  seedSingleContainer() {
1184
- const node = this.makeContainerNode(this.containerHref, this.containerField, 0);
1417
+ const node = makeContainerNode(this.containerHref, this.containerField, 0);
1185
1418
  this.nodeIndex.set(node.id, node);
1186
1419
  this.containers = [node];
1187
1420
  this.rootLoading = false;
@@ -1228,61 +1461,37 @@ const MrdDocumentList = class {
1228
1461
  * type (e.g. "contents"), filtered down to the concrete `filterClass` via the
1229
1462
  * `type` query param — see baseParams(). */
1230
1463
  buildDataPath() {
1231
- var _a, _b, _c;
1464
+ var _a, _b;
1232
1465
  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}`;
1466
+ return buildListPath({
1467
+ isRelatedView: (it === null || it === void 0 ? void 0 : it.type) === ClientLayoutItemType.RELATED_VIEW,
1468
+ fromClass: it === null || it === void 0 ? void 0 : it.fromClass,
1469
+ parentId: this.parentId,
1470
+ dataClass: (_b = (_a = it === null || it === void 0 ? void 0 : it.dataClass) !== null && _a !== void 0 ? _a : it === null || it === void 0 ? void 0 : it.relatedClass) !== null && _b !== void 0 ? _b : '',
1471
+ });
1238
1472
  }
1239
1473
  /** Path for creating a new document (file-drop). Unlike buildDataPath(), this
1240
1474
  * must target the concrete type: `dataClass`/`relatedClass` can be an abstract
1241
1475
  * base type (e.g. "contents") that cannot be POSTed to directly, so prefer
1242
1476
  * `filterClass` (e.g. "documents") when present. */
1243
1477
  buildCreatePath() {
1244
- var _a, _b, _c, _d;
1478
+ var _a, _b, _c;
1245
1479
  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}`;
1480
+ return buildListPath({
1481
+ isRelatedView: (it === null || it === void 0 ? void 0 : it.type) === ClientLayoutItemType.RELATED_VIEW,
1482
+ fromClass: it === null || it === void 0 ? void 0 : it.fromClass,
1483
+ parentId: this.parentId,
1484
+ dataClass: (_c = (_b = (_a = it === null || it === void 0 ? void 0 : it.filterClass) !== null && _a !== void 0 ? _a : it === null || it === void 0 ? void 0 : it.dataClass) !== null && _b !== void 0 ? _b : it === null || it === void 0 ? void 0 : it.relatedClass) !== null && _c !== void 0 ? _c : '',
1485
+ });
1251
1486
  }
1252
1487
  /** View-level static filters + filterClass, shared by every request. */
1253
1488
  baseParams() {
1254
- var _a, _b, _c, _d, _e, _f, _g;
1489
+ var _a, _b, _c;
1255
1490
  const p = new URLSearchParams();
1256
1491
  const filterClass = (_a = this.item) === null || _a === void 0 ? void 0 : _a.filterClass;
1257
1492
  if (filterClass)
1258
1493
  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
- }
1494
+ applyViewFilters(p, (_c = (_b = this.item) === null || _b === void 0 ? void 0 : _b.view) === null || _c === void 0 ? void 0 : _c.filter);
1286
1495
  return p;
1287
1496
  }
1288
1497
  emitContainerDistinct() {
@@ -1349,7 +1558,7 @@ const MrdDocumentList = class {
1349
1558
  if (!v.value || typeof v.value !== 'object')
1350
1559
  continue;
1351
1560
  const href = v.value.href;
1352
- const node = this.makeContainerNode(href, v.value.name, v.count);
1561
+ const node = makeContainerNode(href, v.value.name, v.count);
1353
1562
  nodes.push(node);
1354
1563
  this.nodeIndex.set(node.id, node);
1355
1564
  }
@@ -1367,38 +1576,7 @@ const MrdDocumentList = class {
1367
1576
  const container = this.nodeIndex.get(containerId);
1368
1577
  if (!container)
1369
1578
  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;
1579
+ applyFolderDistinct(container, values, this.nodeIndex);
1402
1580
  // If the container has root documents, load them now (they show inline on expand).
1403
1581
  if (container.hasDocs && !container.docsLoaded) {
1404
1582
  this.emitDocuments(container, container);
@@ -1406,36 +1584,6 @@ const MrdDocumentList = class {
1406
1584
  this.bump();
1407
1585
  }
1408
1586
  // ── 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
1587
  /** Force a re-render after mutating nodes in place. */
1440
1588
  bump() {
1441
1589
  this.containers = [...this.containers];
@@ -1485,14 +1633,6 @@ const MrdDocumentList = class {
1485
1633
  async createFolder() {
1486
1634
  this.startCreateFolder();
1487
1635
  }
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
1636
  commitFolder() {
1497
1637
  const node = this.pendingNode;
1498
1638
  const parent = this.pendingParent;
@@ -1517,7 +1657,7 @@ const MrdDocumentList = class {
1517
1657
  }
1518
1658
  // Finalise: swap the temp id for the real path-derived id so a later distinct
1519
1659
  // value with the same folder string merges onto this node.
1520
- const segs = [...this.segmentsOf(parent, container), name];
1660
+ const segs = [...segmentsOf(parent, container), name];
1521
1661
  this.nodeIndex.delete(node.id);
1522
1662
  node.id = container.id + '/' + segs.join('/');
1523
1663
  node.fullPath = '/' + segs.join('/');
@@ -1566,10 +1706,6 @@ const MrdDocumentList = class {
1566
1706
  this.bump();
1567
1707
  this.mrdUpload.emit({ file });
1568
1708
  }
1569
- /** Strip a single trailing extension for the document title. */
1570
- stripExtension(name) {
1571
- return name.replace(/\.[^./\\]+$/, '');
1572
- }
1573
1709
  /** Host callback with the uploaded file reference. Builds the create payload
1574
1710
  * from the archetype slots and requests the new document. */
1575
1711
  async setFileReference(uri) {
@@ -1577,16 +1713,20 @@ const MrdDocumentList = class {
1577
1713
  if (!up)
1578
1714
  return;
1579
1715
  const { file, node, container } = up;
1580
- const folder = this.folderStringOf(node, container);
1716
+ const folder = folderStringOf(node, container);
1581
1717
  const values = {
1582
1718
  [this.fileField]: uri,
1583
- [this.titleField]: this.stripExtension(file.name),
1719
+ [this.titleField]: stripExtension(file.name),
1584
1720
  [this.folderField]: folder,
1585
- [this.containerField]: container.href,
1586
1721
  };
1722
+ // The create path already embeds the container (/{fromClass}/{parentId}/...)
1723
+ // when this is the seeded single-container context; omit the redundant field.
1724
+ if (!this.isSeededSingleContainer()) {
1725
+ values[this.containerField] = container.href;
1726
+ }
1587
1727
  this.mrdCreateObject.emit({ path: this.buildCreatePath(), values });
1588
1728
  // Optimistically show the new document (no href until a reload).
1589
- const optimistic = { [this.titleField]: this.stripExtension(file.name), _optimistic: true };
1729
+ const optimistic = { [this.titleField]: stripExtension(file.name), _optimistic: true };
1590
1730
  const wasUnloadedEmpty = !node.docsLoaded && node.docCount === 0;
1591
1731
  node.hasDocs = true;
1592
1732
  node.pending = false;
@@ -1615,16 +1755,6 @@ const MrdDocumentList = class {
1615
1755
  this.lastOptimisticDoc = null;
1616
1756
  this.bump();
1617
1757
  }
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
1758
  moveDocument(toNode, toContainer) {
1629
1759
  var _a, _b;
1630
1760
  const doc = this.dragDoc;
@@ -1636,26 +1766,14 @@ const MrdDocumentList = class {
1636
1766
  : (fromNode.containerId ? this.nodeIndex.get(fromNode.containerId) : undefined);
1637
1767
  if (!fromContainer)
1638
1768
  return;
1639
- const targetFolder = this.folderStringOf(toNode, toContainer);
1640
- const sourceFolder = this.folderStringOf(fromNode, fromContainer);
1769
+ const targetFolder = folderStringOf(toNode, toContainer);
1770
+ const sourceFolder = folderStringOf(fromNode, fromContainer);
1641
1771
  const sameContainer = toContainer === fromContainer;
1642
1772
  // No-op: dropped back onto its own folder.
1643
1773
  if (toNode === fromNode || (sameContainer && targetFolder === sourceFolder))
1644
1774
  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];
1775
+ // Optimistic tree update (fire-and-forget; no refetch).
1776
+ applyDocMove(doc, fromNode, toNode, targetFolder);
1659
1777
  this.recomputeContainerTotals(fromContainer, -1);
1660
1778
  if (!sameContainer)
1661
1779
  this.recomputeContainerTotals(toContainer, 1);
@@ -1673,7 +1791,7 @@ const MrdDocumentList = class {
1673
1791
  * loaded; otherwise just nudge the aggregate badge by the delta. */
1674
1792
  recomputeContainerTotals(container, delta) {
1675
1793
  if (container.foldersLoaded) {
1676
- this.computeTotals(container);
1794
+ computeTotals(container);
1677
1795
  }
1678
1796
  else {
1679
1797
  container.totalCount = Math.max(0, container.totalCount + delta);
@@ -1686,111 +1804,64 @@ const MrdDocumentList = class {
1686
1804
  this.mrdNavigate.emit({ href, label });
1687
1805
  }
1688
1806
  // ── 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)))));
1807
+ treeCtx() {
1808
+ return {
1809
+ locale: this.locale,
1810
+ titleField: this.titleField,
1811
+ dateField: this.dateField,
1812
+ selectedId: this.selectedId,
1813
+ dropTargetId: this.dropTargetId,
1814
+ uploadingNodeId: this.uploadingNodeId,
1815
+ on: {
1816
+ toggleContainer: node => this.toggleContainer(node),
1817
+ toggleFolder: (container, node) => this.toggleFolder(container, node),
1818
+ openDoc: doc => this.openDoc(doc),
1819
+ docDragStart: this.onDocDragStart,
1820
+ docDragEnd: this.onDocDragEnd,
1821
+ nodeDragOver: this.onNodeDragOver,
1822
+ nodeDragLeave: this.onNodeDragLeave,
1823
+ nodeDrop: this.onNodeDrop,
1824
+ pendingInput: this.onPendingInput,
1825
+ pendingKeyDown: this.onPendingKeyDown,
1826
+ cancelFolder: () => this.cancelFolder(),
1827
+ setPendingInputEl: el => (this.pendingInputEl = el),
1828
+ },
1829
+ };
1760
1830
  }
1761
1831
  render() {
1832
+ const ctx = this.treeCtx();
1762
1833
  let body;
1763
1834
  if (this.rootLoading) {
1764
- body = this.renderLoadingRow(0);
1835
+ body = renderLoadingRow(ctx, 0);
1765
1836
  }
1766
1837
  else if (this.containers.length === 0) {
1767
- body = h("div", { key: '9c38a2e26320a8173ba82cac412c1b32a8a1882e', class: "mrd-document-list__empty" }, t('no_results', this.locale));
1838
+ body = h("div", { key: 'ce40dab51ab61447838e5059159ae4778209a6f3', class: "mrd-document-list__empty" }, t('no_results', this.locale));
1768
1839
  }
1769
1840
  else if (this.singleContainer) {
1770
1841
  // Dossier context: render the single container's folder tree at the root.
1771
1842
  const only = this.containers[0];
1772
1843
  if (only.loading && !only.foldersLoaded) {
1773
- body = this.renderLoadingRow(0);
1844
+ body = renderLoadingRow(ctx, 0);
1774
1845
  }
1775
1846
  else {
1776
- const kids = this.renderChildren(only, only, 0);
1847
+ const kids = renderNodeChildren(ctx, only, only, 0);
1777
1848
  body = kids.length
1778
1849
  ? kids
1779
1850
  : h("div", { class: "mrd-document-list__empty" }, t('doc_empty_drop', this.locale));
1780
1851
  }
1781
1852
  }
1782
1853
  else {
1783
- body = this.containers.map(c => this.renderContainerNode(c, 0));
1854
+ body = this.containers.map(c => renderContainerNode(ctx, c, 0));
1784
1855
  }
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)));
1856
+ return (h(Host, { key: '9e1f7805ae18bce506c530a481db902900ad95f3' }, h("div", { key: 'a51334634e94310a71650ad49f17f0a20e2aed4d', class: 'mrd-document-list' + (this.rootDropActive ? ' mrd-document-list--drop-active' : ''), onDragOver: this.onRootDragOver, onDragLeave: this.onRootDragLeave, onDrop: this.onRootDrop }, body)));
1786
1857
  }
1787
1858
  get el() { return getElement(this); }
1788
1859
  };
1789
1860
  /** Root sentinel id for the container-level distinct request. */
1790
1861
  MrdDocumentList.ROOT = '__root__';
1791
- MrdDocumentList.style = mrdDocumentListScss();
1862
+ MrdDocumentList.style = mrdDocumentListCss();
1792
1863
 
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)}`;
1864
+ const mrdDocumentViewCss = () => `.sc-mrd-document-view-h{display:block}.mrd-document-view.sc-mrd-document-view{max-width:720px}.mrd-document-view__crumb.sc-mrd-document-view{display:inline-flex;align-items:center;gap:var(--mrd-space-2);margin-bottom:var(--mrd-space-4);padding:var(--mrd-space-1) var(--mrd-space-3);background:var(--mrd-color-primary-light);border:1px solid transparent;border-radius:var(--mrd-border-radius);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-primary-dark);cursor:pointer}.mrd-document-view__crumb.sc-mrd-document-view:hover{border-color:var(--mrd-color-primary)}.mrd-document-view__crumb-icon.sc-mrd-document-view{width:0.875rem;height:0.875rem;flex-shrink:0}.mrd-document-view__title.sc-mrd-document-view{font-size:var(--mrd-font-size-2xl);font-weight:var(--mrd-font-weight-bold);color:var(--mrd-color-neutral-900);letter-spacing:-0.02em;margin:0 0 var(--mrd-space-1) 0}.mrd-document-view__date.sc-mrd-document-view{font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-400);font-variant-numeric:tabular-nums;margin:0 0 var(--mrd-space-6) 0}.mrd-document-view__file.sc-mrd-document-view{display:flex;align-items:center;gap:var(--mrd-space-4);padding:var(--mrd-space-4);border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius-md);background:var(--mrd-color-neutral-50);margin-bottom:var(--mrd-space-6)}.mrd-document-view__file-preview.sc-mrd-document-view{width:2.875rem;height:3.625rem;flex-shrink:0;display:grid;place-items:center;border-radius:var(--mrd-border-radius-sm);background:var(--mrd-color-white);border:1px solid var(--mrd-border-color);color:var(--mrd-color-danger);box-shadow:var(--mrd-shadow-sm)}.mrd-document-view__file-preview.sc-mrd-document-view svg.sc-mrd-document-view{width:1.5rem;height:1.5rem}.mrd-document-view__file-meta.sc-mrd-document-view{flex:1;min-width:0}.mrd-document-view__file-name.sc-mrd-document-view{font-weight:var(--mrd-font-weight-semibold);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-800);word-break:break-word}.mrd-document-view__download.sc-mrd-document-view{display:inline-flex;align-items:center;gap:var(--mrd-space-2);flex-shrink:0;height:2rem;padding:0 var(--mrd-space-3);background:var(--mrd-color-white);border:1px solid var(--mrd-color-neutral-300);border-radius:var(--mrd-border-radius);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);font-weight:var(--mrd-font-weight-medium);color:var(--mrd-color-neutral-700);cursor:pointer}.mrd-document-view__download.sc-mrd-document-view:hover{background:var(--mrd-color-neutral-100);color:var(--mrd-color-neutral-900)}.mrd-document-view__download.sc-mrd-document-view svg.sc-mrd-document-view{width:0.9375rem;height:0.9375rem}.mrd-document-view__summary-body.sc-mrd-document-view{font-size:var(--mrd-font-size-base);color:var(--mrd-color-neutral-700);line-height:var(--mrd-line-height-relaxed)}`;
1794
1865
 
1795
1866
  const MrdDocumentView = class {
1796
1867
  constructor(hostRef) {
@@ -1840,12 +1911,12 @@ const MrdDocumentView = class {
1840
1911
  const date = dateRaw != null && dateRaw !== '' ? formatDate(dateRaw, this.locale) : null;
1841
1912
  const summaryRaw = this.slotValue('summary');
1842
1913
  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 }))))));
1914
+ return (h(Host, { key: '0c64c72eaf5e1eefc2ca9aebb2543081eb1eae32' }, h("div", { key: '70cce81b089fee81a4c163a6ba5fbcc8cb46131c', class: "mrd-document-view" }, this.renderContainer(), title && h("h1", { key: '50f85b32a6740d6cf57fdf1bb0bcc597b5e97b31', class: "mrd-document-view__title" }, title), date && h("p", { key: 'b3c8fb3b4382104858d49ef9a1597034665122bb', class: "mrd-document-view__date" }, date), this.renderFile(), summary && (h("div", { key: '2046c1eca7601549115de0c95ff778abaf5faf46', class: "mrd-document-view__summary" }, h("div", { key: '875863d3e438eee3d4df10473a93f09370fde08c', class: "mrd-document-view__summary-body", innerHTML: summary }))))));
1844
1915
  }
1845
1916
  };
1846
- MrdDocumentView.style = mrdDocumentViewScss();
1917
+ MrdDocumentView.style = mrdDocumentViewCss();
1847
1918
 
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)}`;
1919
+ const mrdEmailFieldCss = () => `.sc-mrd-email-field-h{display:block}.mrd-email-field.sc-mrd-email-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-email-field__label.sc-mrd-email-field{display:block;font-family:var(--mrd-font-family);font-size:var(--mrd-label-font-size);font-weight:var(--mrd-label-font-weight);color:var(--mrd-label-color)}.mrd-email-field__label--required.sc-mrd-email-field::after{content:" *";color:var(--mrd-color-danger)}.mrd-email-field__input.sc-mrd-email-field{display:block;width:100%;height:var(--mrd-input-height);padding:var(--mrd-input-padding-y) var(--mrd-input-padding-x);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-input-color);background-color:var(--mrd-input-bg);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);transition:border-color var(--mrd-transition), box-shadow var(--mrd-transition);outline:none;appearance:none;box-sizing:border-box}.mrd-email-field__input.sc-mrd-email-field::placeholder{color:var(--mrd-input-placeholder-color)}.mrd-email-field__input.sc-mrd-email-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-email-field__input.sc-mrd-email-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.mrd-email-field__input--error.sc-mrd-email-field{border-color:var(--mrd-border-color-error)}.mrd-email-field__input--error.sc-mrd-email-field:focus{box-shadow:var(--mrd-shadow-focus-error)}.mrd-email-field__error.sc-mrd-email-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}`;
1849
1920
 
1850
1921
  const MrdEmailField = class {
1851
1922
  constructor(hostRef) {
@@ -1866,26 +1937,18 @@ const MrdEmailField = class {
1866
1937
  };
1867
1938
  this.handleBlur = (e) => {
1868
1939
  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
- }
1940
+ this.error = requiredError(val, this.required, this.locale)
1941
+ || (val && !validateEmail(val) ? t('invalid_email', this.locale) : '');
1878
1942
  this.mrdBlur.emit({ name: this.name, value: val });
1879
1943
  };
1880
1944
  }
1881
1945
  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))));
1946
+ return (h(Host, { key: '93f7c4975c24e6001e772f2858344edec04cda10' }, h("div", { key: '4f49a2a1f68a4161762861c5d54fd3690c88ac5d', class: "mrd-email-field" }, h(FieldLabel, { key: '23b20799f3e7c04889b7bc3a271e61b0bb5d7537', base: "mrd-email-field", label: this.label, required: this.required }), h("input", { key: '0fc452bfb9295a80102eeed4b32bcc9475c9d17b', class: controlClass('mrd-email-field', !!this.error), type: "email", name: this.name, value: this.value, placeholder: this.placeholder || 'name@example.com', required: this.required, disabled: this.disabled, onInput: this.handleInput, onBlur: this.handleBlur }), h(FieldError, { key: '34945fff9c69cf2f0aeb56492c95052250514d5c', base: "mrd-email-field", error: this.error }))));
1884
1947
  }
1885
1948
  };
1886
- MrdEmailField.style = mrdEmailFieldScss();
1949
+ MrdEmailField.style = mrdEmailFieldCss();
1887
1950
 
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)}`;
1951
+ const mrdFieldCss = () => `.sc-mrd-field-h{display:block}.mrd-field__inner.sc-mrd-field{display:block;width:100%}.mrd-field__history-editor.sc-mrd-field{margin-top:var(--mrd-space-2);display:flex;flex-direction:column;gap:var(--mrd-space-1)}.mrd-field__history-editor-label.sc-mrd-field{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-xs);font-weight:var(--mrd-font-weight-medium);color:var(--mrd-color-neutral-500)}.mrd-field__history-editor-row.sc-mrd-field{display:flex;align-items:center;gap:var(--mrd-space-2)}.mrd-field__history-editor-sep.sc-mrd-field{flex-shrink:0;font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-500)}.mrd-field__history-editor-value.sc-mrd-field{flex:1 1 0;min-width:0;height:var(--mrd-input-height);padding:0 var(--mrd-space-3);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-800);background-color:var(--mrd-color-white);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius-md);outline:none;transition:border-color var(--mrd-transition-fast), box-shadow var(--mrd-transition-fast)}.mrd-field__history-editor-value.sc-mrd-field:focus{border-color:var(--mrd-color-primary);box-shadow:var(--mrd-shadow-focus)}.mrd-field__history-editor-until.sc-mrd-field{flex:0 0 10rem;height:var(--mrd-input-height);padding:0 var(--mrd-space-3);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-800);background-color:var(--mrd-color-white);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius-md);outline:none;transition:border-color var(--mrd-transition-fast), box-shadow var(--mrd-transition-fast)}.mrd-field__history-editor-until.sc-mrd-field:focus{border-color:var(--mrd-color-primary);box-shadow:var(--mrd-shadow-focus)}.mrd-field__history-editor-remove.sc-mrd-field{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:2rem;height:2rem;padding:0;background:transparent;border:none;border-radius:var(--mrd-border-radius-sm);color:var(--mrd-color-neutral-400);cursor:pointer;transition:color var(--mrd-transition-fast), background-color var(--mrd-transition-fast)}.mrd-field__history-editor-remove.sc-mrd-field:hover{color:var(--mrd-color-danger);background-color:var(--mrd-color-danger-light)}.mrd-field__history-editor-remove.sc-mrd-field svg.sc-mrd-field{width:1rem;height:1rem}.mrd-field__history-editor-add.sc-mrd-field{align-self:flex-start;padding:var(--mrd-space-1) var(--mrd-space-3);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-xs);font-weight:var(--mrd-font-weight-medium);color:var(--mrd-color-primary);background:transparent;border:var(--mrd-border-width) solid var(--mrd-color-primary);border-radius:var(--mrd-border-radius-md);cursor:pointer;transition:background-color var(--mrd-transition-fast), color var(--mrd-transition-fast)}.mrd-field__history-editor-add.sc-mrd-field:hover{background-color:var(--mrd-color-primary-light)}`;
1889
1952
 
1890
1953
  const MrdField = class {
1891
1954
  constructor(hostRef) {
@@ -2070,9 +2133,47 @@ const MrdField = class {
2070
2133
  }]
2071
2134
  }; }
2072
2135
  };
2073
- MrdField.style = mrdFieldScss();
2136
+ MrdField.style = mrdFieldCss();
2137
+
2138
+ /**
2139
+ * Shared upload behaviour for mrd-file-field and mrd-image-field:
2140
+ * file validation, drop-zone class building and drag-drop wiring.
2141
+ */
2142
+ /** Validates a selected/dropped file; returns a localised error message or '' when accepted. */
2143
+ function validateUploadFile(file, maxSize, locale, requireImage = false) {
2144
+ if (maxSize > 0 && file.size > maxSize)
2145
+ return t('file_too_large', locale);
2146
+ if (requireImage && !file.type.startsWith('image/'))
2147
+ return t('invalid_image', locale);
2148
+ return '';
2149
+ }
2150
+ /** BEM class string for the drop zone, e.g. base 'mrd-file-field' → 'mrd-file-field__zone …'. */
2151
+ function uploadZoneClass(base, opts) {
2152
+ return [
2153
+ `${base}__zone`,
2154
+ opts.dragging ? `${base}__zone--dragging` : '',
2155
+ opts.error ? `${base}__zone--error` : '',
2156
+ opts.disabled ? `${base}__zone--disabled` : '',
2157
+ ].filter(Boolean).join(' ');
2158
+ }
2159
+ /** Drag-drop handlers for the drop zone; the component owns the dragging state and file handling. */
2160
+ function makeDragHandlers(setDragging, onFile) {
2161
+ return {
2162
+ onDragOver: (e) => {
2163
+ e.preventDefault();
2164
+ setDragging(true);
2165
+ },
2166
+ onDragLeave: () => setDragging(false),
2167
+ onDrop: (e) => {
2168
+ var _a, _b, _c;
2169
+ e.preventDefault();
2170
+ setDragging(false);
2171
+ onFile((_c = (_b = (_a = e.dataTransfer) === null || _a === void 0 ? void 0 : _a.files) === null || _b === void 0 ? void 0 : _b[0]) !== null && _c !== void 0 ? _c : null);
2172
+ },
2173
+ };
2174
+ }
2074
2175
 
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)}`;
2176
+ const mrdFileFieldCss = () => `.sc-mrd-file-field-h{display:block}.mrd-file-field.sc-mrd-file-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-file-field__label.sc-mrd-file-field{display:block;font-family:var(--mrd-font-family);font-size:var(--mrd-label-font-size);font-weight:var(--mrd-label-font-weight);color:var(--mrd-label-color)}.mrd-file-field__label--required.sc-mrd-file-field::after{content:" *";color:var(--mrd-color-danger)}.mrd-file-field__error.sc-mrd-file-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}.mrd-file-field__zone.sc-mrd-file-field{display:flex;align-items:center;justify-content:center;border:2px dashed var(--mrd-border-color);border-radius:var(--mrd-border-radius-md);background-color:var(--mrd-color-neutral-50);cursor:pointer;transition:border-color var(--mrd-transition), background-color var(--mrd-transition);min-height:100px;position:relative}.mrd-file-field__zone.sc-mrd-file-field:hover,.mrd-file-field__zone--dragging.sc-mrd-file-field{border-color:var(--mrd-color-primary);background-color:var(--mrd-color-primary-light)}.mrd-file-field__zone--error.sc-mrd-file-field{border-color:var(--mrd-border-color-error)}.mrd-file-field__zone--disabled.sc-mrd-file-field{opacity:0.6;cursor:not-allowed}.mrd-file-field__zone--disabled.sc-mrd-file-field:hover{border-color:var(--mrd-border-color);background-color:var(--mrd-color-neutral-50)}.mrd-file-field__zone.sc-mrd-file-field{padding:var(--mrd-space-6)}.mrd-file-field__input.sc-mrd-file-field{position:absolute;inset:0;opacity:0;width:100%;height:100%;pointer-events:none;cursor:pointer}.mrd-file-field__prompt.sc-mrd-file-field{display:flex;flex-direction:column;align-items:center;gap:var(--mrd-space-2);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-500);text-align:center}.mrd-file-field__upload-icon.sc-mrd-file-field{width:32px;height:32px;color:var(--mrd-color-neutral-400)}.mrd-file-field__browse.sc-mrd-file-field{color:var(--mrd-color-primary);font-weight:var(--mrd-font-weight-medium);text-decoration:underline}.mrd-file-field__selected.sc-mrd-file-field{display:flex;align-items:center;gap:var(--mrd-space-2);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-700)}.mrd-file-field__icon.sc-mrd-file-field{width:20px;height:20px;color:var(--mrd-color-primary);flex-shrink:0}.mrd-file-field__filename.sc-mrd-file-field{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:200px}.mrd-file-field__clear.sc-mrd-file-field{background:none;border:none;cursor:pointer;color:var(--mrd-color-neutral-400);font-size:var(--mrd-font-size-sm);padding:var(--mrd-space-1);border-radius:var(--mrd-border-radius-sm);line-height:1}.mrd-file-field__clear.sc-mrd-file-field:hover{color:var(--mrd-color-danger);background-color:var(--mrd-color-danger-light)}.mrd-file-field__spinner.sc-mrd-file-field{display:inline-block;width:18px;height:18px;border:2px solid var(--mrd-color-neutral-300);border-top-color:var(--mrd-color-primary);border-radius:50%;animation:mrd-spin 0.6s linear infinite;flex-shrink:0}@keyframes mrd-spin{to{transform:rotate(360deg)}}`;
2076
2177
 
2077
2178
  const MrdFileField = class {
2078
2179
  constructor(hostRef) {
@@ -2097,20 +2198,7 @@ const MrdFileField = class {
2097
2198
  const files = e.target.files;
2098
2199
  this.handleFile((_a = files === null || files === void 0 ? void 0 : files[0]) !== null && _a !== void 0 ? _a : null);
2099
2200
  };
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
- };
2201
+ this.drag = makeDragHandlers(dragging => (this.isDragging = dragging), file => this.handleFile(file));
2114
2202
  this.handleZoneClick = () => {
2115
2203
  var _a;
2116
2204
  if (!this.disabled && !this.uploading) {
@@ -2144,8 +2232,9 @@ const MrdFileField = class {
2144
2232
  this.mrdChange.emit({ name: this.name, value: null });
2145
2233
  return;
2146
2234
  }
2147
- if (this.maxSize > 0 && file.size > this.maxSize) {
2148
- this.error = t('file_too_large', this.locale);
2235
+ const uploadError = validateUploadFile(file, this.maxSize, this.locale);
2236
+ if (uploadError) {
2237
+ this.error = uploadError;
2149
2238
  return;
2150
2239
  }
2151
2240
  this.error = '';
@@ -2157,13 +2246,12 @@ const MrdFileField = class {
2157
2246
  render() {
2158
2247
  const hasFile = this.uploading || (typeof this.value === 'string' && this.value) || this.fileName;
2159
2248
  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))));
2249
+ const zoneClass = uploadZoneClass('mrd-file-field', {
2250
+ dragging: this.isDragging,
2251
+ error: hasError,
2252
+ disabled: this.disabled || this.uploading,
2253
+ });
2254
+ return (h(Host, { key: '2c4cee79cd0f95ed3750dfc86007a2b36aa3da15' }, h("div", { key: '5b47d0f83e8e38b22bb04409544ec2af580274f1', class: "mrd-file-field" }, h(FieldLabel, { key: '47a92d5680670bf750854fa6e7883da54a40baec', base: "mrd-file-field", label: this.label, required: this.required }), h("div", { key: '684f6ab39c32635fb5ca966ccab4a061d8682f89', class: zoneClass, onClick: this.handleZoneClick, onDragOver: this.drag.onDragOver, onDragLeave: this.drag.onDragLeave, onDrop: this.drag.onDrop }, h("input", { key: 'a47231d8c68280623daf0c5a2e4341417e7a88d0', ref: el => (this.fileInputRef = el), class: "mrd-file-field__input", type: "file", name: this.name, accept: this.accept, disabled: this.disabled || this.uploading, required: this.required && !hasFile, onChange: this.handleInputChange }), hasFile ? (h("div", { class: "mrd-file-field__selected" }, this.uploading ? (h("span", { class: "mrd-file-field__spinner", "aria-label": t('loading', this.locale) })) : (h("svg", { class: "mrd-file-field__icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2" }, h("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }), h("polyline", { points: "14 2 14 8 20 8" }))), h("span", { class: "mrd-file-field__filename" }, this.fileName), !this.uploading && (h("button", { class: "mrd-file-field__clear", type: "button", onClick: this.handleClear, "aria-label": t('clear', this.locale) }, "\u2715")))) : (h("div", { class: "mrd-file-field__prompt" }, h("svg", { class: "mrd-file-field__upload-icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2" }, h("polyline", { points: "16 16 12 12 8 16" }), h("line", { x1: "12", y1: "12", x2: "12", y2: "21" }), h("path", { d: "M20.39 18.39A5 5 0 0 0 18 9h-1.26A8 8 0 1 0 3 16.3" })), h("span", null, t('drop_file_here', this.locale), ' ', h("span", { class: "mrd-file-field__browse" }, t('browse', this.locale)))))), h(FieldError, { key: '5f18e91aa94319a5571c368e745c108fb0d371a7', base: "mrd-file-field", error: this.error }))));
2167
2255
  }
2168
2256
  static get watchers() { return {
2169
2257
  "value": [{
@@ -2171,9 +2259,9 @@ const MrdFileField = class {
2171
2259
  }]
2172
2260
  }; }
2173
2261
  };
2174
- MrdFileField.style = mrdFileFieldScss();
2262
+ MrdFileField.style = mrdFileFieldCss();
2175
2263
 
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)}`;
2264
+ const mrdFormCss = () => `.sc-mrd-form-h{display:block}.mrd-form.sc-mrd-form{font-family:var(--mrd-font-family);width:100%}.mrd-form__title.sc-mrd-form{font-size:var(--mrd-font-size-2xl);font-weight:var(--mrd-font-weight-bold);color:var(--mrd-color-neutral-900);margin:0 0 var(--mrd-space-6) 0}.mrd-form__body.sc-mrd-form{display:flex;flex-direction:column;gap:var(--mrd-space-5)}.mrd-form__field.sc-mrd-form{display:flex;flex-direction:column;gap:var(--mrd-space-1)}.mrd-form__field-error.sc-mrd-form{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}.mrd-form__section.sc-mrd-form{border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius-md);padding:var(--mrd-space-4) var(--mrd-space-5);margin:0}.mrd-form__section-legend.sc-mrd-form{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);font-weight:var(--mrd-font-weight-semibold);color:var(--mrd-color-neutral-700);padding:0 var(--mrd-space-2)}.mrd-form__section-body.sc-mrd-form{display:flex;flex-direction:column;gap:var(--mrd-space-4);margin-top:var(--mrd-space-2)}.mrd-form__group.sc-mrd-form{display:flex;flex-direction:column;gap:var(--mrd-space-2)}.mrd-form__group-label.sc-mrd-form{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);font-weight:var(--mrd-font-weight-semibold);color:var(--mrd-color-neutral-500);text-transform:uppercase;letter-spacing:0.05em}.mrd-form__group-body.sc-mrd-form{display:flex;flex-direction:column;gap:var(--mrd-space-4);padding-left:var(--mrd-space-4);border-left:3px solid var(--mrd-color-neutral-200)}.mrd-form__footer.sc-mrd-form{margin-top:var(--mrd-space-8);padding-top:var(--mrd-space-5);border-top:var(--mrd-border-width) solid var(--mrd-border-color);display:flex;justify-content:flex-end;gap:var(--mrd-space-3)}.mrd-form__submit.sc-mrd-form{display:inline-flex;align-items:center;justify-content:center;height:var(--mrd-input-height);padding:0 var(--mrd-space-6);background-color:var(--mrd-color-primary);color:var(--mrd-color-white);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);font-weight:var(--mrd-font-weight-medium);border:none;border-radius:var(--mrd-border-radius);cursor:pointer;transition:background-color var(--mrd-transition)}.mrd-form__submit.sc-mrd-form:hover{background-color:var(--mrd-color-primary-hover)}.mrd-form__submit.sc-mrd-form:focus{outline:none;box-shadow:var(--mrd-shadow-focus)}.mrd-form__submit.sc-mrd-form:active{background-color:var(--mrd-color-primary-dark)}.mrd-form__cancel.sc-mrd-form{display:inline-flex;align-items:center;justify-content:center;height:var(--mrd-input-height);padding:0 var(--mrd-space-6);background-color:transparent;color:var(--mrd-color-neutral-600);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);font-weight:var(--mrd-font-weight-medium);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);cursor:pointer;transition:background-color var(--mrd-transition), color var(--mrd-transition)}.mrd-form__cancel.sc-mrd-form:hover{background-color:var(--mrd-color-neutral-100);color:var(--mrd-color-neutral-800)}.mrd-form__cancel.sc-mrd-form:focus{outline:none;box-shadow:var(--mrd-shadow-focus)}.mrd-form__cancel.sc-mrd-form:active{background-color:var(--mrd-color-neutral-200)}`;
2177
2265
 
2178
2266
  const MrdForm = class {
2179
2267
  constructor(hostRef) {
@@ -2540,9 +2628,9 @@ const MrdForm = class {
2540
2628
  }]
2541
2629
  }; }
2542
2630
  };
2543
- MrdForm.style = mrdFormScss();
2631
+ MrdForm.style = mrdFormCss();
2544
2632
 
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)}`;
2633
+ const mrdHyperlinkFieldCss = () => `.sc-mrd-hyperlink-field-h{display:block}.mrd-hyperlink-field.sc-mrd-hyperlink-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-hyperlink-field__label.sc-mrd-hyperlink-field{display:block;font-family:var(--mrd-font-family);font-size:var(--mrd-label-font-size);font-weight:var(--mrd-label-font-weight);color:var(--mrd-label-color)}.mrd-hyperlink-field__label--required.sc-mrd-hyperlink-field::after{content:" *";color:var(--mrd-color-danger)}.mrd-hyperlink-field__input.sc-mrd-hyperlink-field{display:block;width:100%;height:var(--mrd-input-height);padding:var(--mrd-input-padding-y) var(--mrd-input-padding-x);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-input-color);background-color:var(--mrd-input-bg);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);transition:border-color var(--mrd-transition), box-shadow var(--mrd-transition);outline:none;appearance:none;box-sizing:border-box}.mrd-hyperlink-field__input.sc-mrd-hyperlink-field::placeholder{color:var(--mrd-input-placeholder-color)}.mrd-hyperlink-field__input.sc-mrd-hyperlink-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-hyperlink-field__input.sc-mrd-hyperlink-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.mrd-hyperlink-field__input--error.sc-mrd-hyperlink-field{border-color:var(--mrd-border-color-error)}.mrd-hyperlink-field__input--error.sc-mrd-hyperlink-field:focus{box-shadow:var(--mrd-shadow-focus-error)}.mrd-hyperlink-field__error.sc-mrd-hyperlink-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}.mrd-hyperlink-field__input--name.sc-mrd-hyperlink-field{margin-top:var(--mrd-space-1)}.mrd-hyperlink-field__link.sc-mrd-hyperlink-field{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-color-primary);text-decoration:underline;word-break:break-all}.mrd-hyperlink-field__link.sc-mrd-hyperlink-field:hover{opacity:0.8}.mrd-hyperlink-field__empty.sc-mrd-hyperlink-field{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-color-neutral-400)}`;
2546
2634
 
2547
2635
  const MrdHyperlinkField = class {
2548
2636
  constructor(hostRef) {
@@ -2568,15 +2656,8 @@ const MrdHyperlinkField = class {
2568
2656
  this.mrdChange.emit({ name: this.name, value: this.buildValue() });
2569
2657
  };
2570
2658
  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
- }
2659
+ this.error = requiredError(this.internalHref, this.required, this.locale)
2660
+ || (this.internalHref && !validateUrl(this.internalHref) ? t('invalid_url', this.locale) : '');
2580
2661
  this.mrdBlur.emit({ name: this.name, value: this.buildValue() });
2581
2662
  };
2582
2663
  }
@@ -2609,7 +2690,7 @@ const MrdHyperlinkField = class {
2609
2690
  ? h("a", { class: "mrd-hyperlink-field__link", href: this.internalHref, target: "_blank", rel: "noopener noreferrer" }, this.internalName || this.internalHref)
2610
2691
  : h("span", { class: "mrd-hyperlink-field__empty" }, "\u2014"))));
2611
2692
  }
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))));
2693
+ return (h(Host, null, h("div", { class: "mrd-hyperlink-field" }, h(FieldLabel, { base: "mrd-hyperlink-field", label: this.label, required: this.required }), h("input", { class: controlClass('mrd-hyperlink-field', hasError), type: "url", name: this.name, value: this.internalHref, placeholder: this.placeholder || 'https://', required: this.required, onInput: this.handleHrefInput, onBlur: this.handleBlur }), h("input", { class: "mrd-hyperlink-field__input mrd-hyperlink-field__input--name", type: "text", value: this.internalName, placeholder: t('hyperlink_name', this.locale), onInput: this.handleNameInput, onBlur: this.handleBlur }), h(FieldError, { base: "mrd-hyperlink-field", error: this.error }))));
2613
2694
  }
2614
2695
  static get watchers() { return {
2615
2696
  "value": [{
@@ -2617,9 +2698,9 @@ const MrdHyperlinkField = class {
2617
2698
  }]
2618
2699
  }; }
2619
2700
  };
2620
- MrdHyperlinkField.style = mrdHyperlinkFieldScss();
2701
+ MrdHyperlinkField.style = mrdHyperlinkFieldCss();
2621
2702
 
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)}`;
2703
+ const mrdImageFieldCss = () => `.sc-mrd-image-field-h{display:block}.mrd-image-field.sc-mrd-image-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-image-field__label.sc-mrd-image-field{display:block;font-family:var(--mrd-font-family);font-size:var(--mrd-label-font-size);font-weight:var(--mrd-label-font-weight);color:var(--mrd-label-color)}.mrd-image-field__label--required.sc-mrd-image-field::after{content:" *";color:var(--mrd-color-danger)}.mrd-image-field__error.sc-mrd-image-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}.mrd-image-field__zone.sc-mrd-image-field{display:flex;align-items:center;justify-content:center;border:2px dashed var(--mrd-border-color);border-radius:var(--mrd-border-radius-md);background-color:var(--mrd-color-neutral-50);cursor:pointer;transition:border-color var(--mrd-transition), background-color var(--mrd-transition);min-height:100px;position:relative}.mrd-image-field__zone.sc-mrd-image-field:hover,.mrd-image-field__zone--dragging.sc-mrd-image-field{border-color:var(--mrd-color-primary);background-color:var(--mrd-color-primary-light)}.mrd-image-field__zone--error.sc-mrd-image-field{border-color:var(--mrd-border-color-error)}.mrd-image-field__zone--disabled.sc-mrd-image-field{opacity:0.6;cursor:not-allowed}.mrd-image-field__zone--disabled.sc-mrd-image-field:hover{border-color:var(--mrd-border-color);background-color:var(--mrd-color-neutral-50)}.mrd-image-field__input.sc-mrd-image-field{position:absolute;inset:0;opacity:0;width:100%;height:100%;pointer-events:none}.mrd-image-field__prompt.sc-mrd-image-field{display:flex;flex-direction:column;align-items:center;gap:var(--mrd-space-2);padding:var(--mrd-space-6);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-500);text-align:center}.mrd-image-field__upload-icon.sc-mrd-image-field{width:40px;height:40px;color:var(--mrd-color-neutral-400)}.mrd-image-field__browse.sc-mrd-image-field{color:var(--mrd-color-primary);font-weight:var(--mrd-font-weight-medium);text-decoration:underline}.mrd-image-field__preview-container.sc-mrd-image-field{display:flex;align-items:center;gap:var(--mrd-space-4);padding:var(--mrd-space-4);width:100%}.mrd-image-field__preview-thumb.sc-mrd-image-field{flex-shrink:0;width:80px;height:80px;border-radius:var(--mrd-border-radius);overflow:hidden;border:var(--mrd-border-width) solid var(--mrd-border-color);background-color:var(--mrd-color-neutral-100)}.mrd-image-field__preview.sc-mrd-image-field{width:100%;height:100%;object-fit:cover;display:block}.mrd-image-field__preview-info.sc-mrd-image-field{flex:1;min-width:0;display:flex;flex-direction:column;gap:var(--mrd-space-1)}.mrd-image-field__preview-name.sc-mrd-image-field{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);font-weight:var(--mrd-font-weight-medium);color:var(--mrd-color-neutral-800);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mrd-image-field__preview-overlay.sc-mrd-image-field{position:absolute;inset:0;background:rgba(255, 255, 255, 0.7);display:flex;align-items:center;justify-content:center;border-radius:var(--mrd-border-radius)}.mrd-image-field__spinner.sc-mrd-image-field{display:inline-block;width:24px;height:24px;border:2px solid var(--mrd-color-neutral-300);border-top-color:var(--mrd-color-primary);border-radius:50%;animation:mrd-spin 0.6s linear infinite}@keyframes mrd-spin{to{transform:rotate(360deg)}}.mrd-image-field__upload-status.sc-mrd-image-field{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-500)}.mrd-image-field__clear.sc-mrd-image-field{flex-shrink:0;background-color:var(--mrd-color-white);color:var(--mrd-color-danger);border:var(--mrd-border-width) solid var(--mrd-color-danger);border-radius:var(--mrd-border-radius);padding:var(--mrd-space-1) var(--mrd-space-3);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);font-weight:var(--mrd-font-weight-medium);cursor:pointer;transition:background-color var(--mrd-transition), color var(--mrd-transition)}.mrd-image-field__clear.sc-mrd-image-field:hover{background-color:var(--mrd-color-danger);color:var(--mrd-color-white)}`;
2623
2704
 
2624
2705
  const MrdImageField = class {
2625
2706
  constructor(hostRef) {
@@ -2645,20 +2726,7 @@ const MrdImageField = class {
2645
2726
  const files = e.target.files;
2646
2727
  this.handleFile((_a = files === null || files === void 0 ? void 0 : files[0]) !== null && _a !== void 0 ? _a : null);
2647
2728
  };
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
- };
2729
+ this.drag = makeDragHandlers(dragging => (this.isDragging = dragging), file => this.handleFile(file));
2662
2730
  this.handleZoneClick = () => {
2663
2731
  var _a;
2664
2732
  if (!this.disabled && !this.uploading) {
@@ -2695,12 +2763,9 @@ const MrdImageField = class {
2695
2763
  this.mrdChange.emit({ name: this.name, value: null });
2696
2764
  return;
2697
2765
  }
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';
2766
+ const uploadError = validateUploadFile(file, this.maxSize, this.locale, true);
2767
+ if (uploadError) {
2768
+ this.error = uploadError;
2704
2769
  return;
2705
2770
  }
2706
2771
  this.error = '';
@@ -2718,13 +2783,12 @@ const MrdImageField = class {
2718
2783
  }
2719
2784
  render() {
2720
2785
  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))));
2786
+ const zoneClass = uploadZoneClass('mrd-image-field', {
2787
+ dragging: this.isDragging,
2788
+ error: hasError,
2789
+ disabled: this.disabled || this.uploading,
2790
+ });
2791
+ return (h(Host, { key: 'ab78d93ab6c810363a8993bea4545f7406680e58' }, h("div", { key: '727ae5d9c1cce22d90d26229a9ea5d677abb4b07', class: "mrd-image-field" }, h(FieldLabel, { key: 'aab0e9fcc0204e8ea617453b5ca458f683194125', base: "mrd-image-field", label: this.label, required: this.required }), h("div", { key: '1241faff26c47a303fd0431201f490c6b8725987', class: zoneClass, onClick: this.handleZoneClick, onDragOver: this.drag.onDragOver, onDragLeave: this.drag.onDragLeave, onDrop: this.drag.onDrop }, h("input", { key: '70e3b8f869927ad525465ace96ed3ea24f5b7555', ref: el => (this.fileInputRef = el), class: "mrd-image-field__input", type: "file", name: this.name, accept: this.accept, disabled: this.disabled || this.uploading, required: this.required && !this.previewUrl, onChange: this.handleInputChange }), this.previewUrl ? (h("div", { class: "mrd-image-field__preview-container" }, h("div", { class: "mrd-image-field__preview-thumb" }, h("img", { class: "mrd-image-field__preview", src: this.previewUrl, alt: this.fileName }), this.uploading && h("div", { class: "mrd-image-field__preview-overlay" }, h("span", { class: "mrd-image-field__spinner" }))), h("div", { class: "mrd-image-field__preview-info" }, h("span", { class: "mrd-image-field__preview-name" }, this.fileName), this.uploading && (h("span", { class: "mrd-image-field__upload-status" }, t('loading', this.locale)))), !this.uploading && (h("button", { class: "mrd-image-field__clear", type: "button", onClick: this.handleClear, "aria-label": t('clear', this.locale) }, t('remove', this.locale))))) : (h("div", { class: "mrd-image-field__prompt" }, h("svg", { class: "mrd-image-field__upload-icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2" }, h("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }), h("circle", { cx: "8.5", cy: "8.5", r: "1.5" }), h("polyline", { points: "21 15 16 10 5 21" })), h("span", null, t('drop_file_here', this.locale), ' ', h("span", { class: "mrd-image-field__browse" }, t('browse', this.locale)))))), h(FieldError, { key: '01552a994c1e5a9f25129586a95562c32a377046', base: "mrd-image-field", error: this.error }))));
2728
2792
  }
2729
2793
  static get watchers() { return {
2730
2794
  "value": [{
@@ -2732,7 +2796,36 @@ const MrdImageField = class {
2732
2796
  }]
2733
2797
  }; }
2734
2798
  };
2735
- MrdImageField.style = mrdImageFieldScss();
2799
+ MrdImageField.style = mrdImageFieldCss();
2800
+
2801
+ /** Key an embedded view is addressed by (setViewPage etc.). */
2802
+ function viewKeyFor(item) {
2803
+ var _a, _b, _c, _d;
2804
+ if (item.type === ClientLayoutItemType.RELATED_VIEW)
2805
+ return (_b = (_a = item.relatedClass) !== null && _a !== void 0 ? _a : item.name) !== null && _b !== void 0 ? _b : '';
2806
+ return (_d = (_c = item.dataClass) !== null && _c !== void 0 ? _c : item.name) !== null && _d !== void 0 ? _d : '';
2807
+ }
2808
+ /** Depth-first flatten of the SECTION/GROUP tree. */
2809
+ function flattenItems(items) {
2810
+ const result = [];
2811
+ for (const item of items) {
2812
+ result.push(item);
2813
+ if (item.items)
2814
+ result.push(...flattenItems(item.items));
2815
+ }
2816
+ return result;
2817
+ }
2818
+ /** Build the canonical parent href `/{base}/{tenant}/{fromClass}/{parentId}` from
2819
+ * the object's self href. Empty unless it is a RELATED_VIEW with a fromClass. */
2820
+ function buildContainerHref(item, selfHref, parentId) {
2821
+ if (item.type !== ClientLayoutItemType.RELATED_VIEW || !item.fromClass || !parentId)
2822
+ return '';
2823
+ const segs = selfHref.split('/').filter(Boolean);
2824
+ if (segs.length < 2)
2825
+ return '';
2826
+ const [base, tenant] = segs;
2827
+ return `/${base}/${tenant}/${item.fromClass}/${parentId}`;
2828
+ }
2736
2829
 
2737
2830
  class CellRenderer {
2738
2831
  static render(column, row, locale) {
@@ -2838,7 +2931,114 @@ class CellRenderer {
2838
2931
  }
2839
2932
  }
2840
2933
 
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}`;
2934
+ /** FILE and IMAGE cells share the same download button. */
2935
+ function downloadLink(ctx, href, fileName, label) {
2936
+ return (h("button", { class: "mrd-layout-section__download-link", onClick: () => href && ctx.on.download({ href, fileName }) }, h("svg", { class: "mrd-layout-section__file-icon", viewBox: "0 0 24 24", "aria-hidden": "true" }, h("path", { fill: "currentColor", d: "M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm-1 7V3.5L18.5 9H13zm-3 8l-3-3 1.41-1.41L10 14.17l4.59-4.58L16 11l-6 6z" })), label));
2937
+ }
2938
+ function renderSingleFieldValue(ctx, item, value) {
2939
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
2940
+ const dt = item.dataType;
2941
+ switch (dt) {
2942
+ case ClientLayoutItemFieldDataType.HYPERLINK: {
2943
+ const v = value;
2944
+ const href = (_a = v === null || v === void 0 ? void 0 : v.href) !== null && _a !== void 0 ? _a : String(value);
2945
+ const label = (_d = (_c = (_b = v === null || v === void 0 ? void 0 : v.name) !== null && _b !== void 0 ? _b : v === null || v === void 0 ? void 0 : v.text) !== null && _c !== void 0 ? _c : v === null || v === void 0 ? void 0 : v.label) !== null && _d !== void 0 ? _d : href;
2946
+ return (h("a", { class: "mrd-layout-section__link", href: href, target: "_blank", rel: "noopener noreferrer" }, label));
2947
+ }
2948
+ case ClientLayoutItemFieldDataType.TEXTBLOCK:
2949
+ return h("div", { class: "mrd-layout-section__prose", innerHTML: String(value) });
2950
+ case ClientLayoutItemFieldDataType.LONGTEXT:
2951
+ return h("pre", { class: "mrd-layout-section__pre" }, String(value));
2952
+ case ClientLayoutItemFieldDataType.JSON:
2953
+ return h("pre", { class: "mrd-layout-section__pre", innerHTML: CellRenderer.formatJson(value) });
2954
+ case ClientLayoutItemFieldDataType.FILE: {
2955
+ const v = value;
2956
+ const fileName = (_e = v === null || v === void 0 ? void 0 : v.fileName) !== null && _e !== void 0 ? _e : String(value);
2957
+ const href = (_f = v === null || v === void 0 ? void 0 : v.href) !== null && _f !== void 0 ? _f : '';
2958
+ return downloadLink(ctx, href, fileName, t('download', ctx.locale));
2959
+ }
2960
+ case ClientLayoutItemFieldDataType.IMAGE: {
2961
+ const v = value;
2962
+ const href = (_g = v === null || v === void 0 ? void 0 : v.href) !== null && _g !== void 0 ? _g : '';
2963
+ const fileName = (_h = v === null || v === void 0 ? void 0 : v.fileName) !== null && _h !== void 0 ? _h : '';
2964
+ const previewUrl = ctx.imagePreviews[item.name];
2965
+ if (previewUrl) {
2966
+ return (h("button", { class: "mrd-layout-section__image-thumb-btn", onClick: () => ctx.on.openImage(previewUrl), title: fileName || undefined }, h("img", { class: "mrd-layout-section__image-thumb", src: previewUrl, alt: fileName })));
2967
+ }
2968
+ return downloadLink(ctx, href, fileName, fileName || href);
2969
+ }
2970
+ case ClientLayoutItemFieldDataType.BOOLEAN:
2971
+ return (h("span", { class: `mrd-layout-section__boolean mrd-layout-section__boolean--${value ? 'true' : 'false'}` }, value ? t('yes', ctx.locale) : t('no', ctx.locale)));
2972
+ case ClientLayoutItemFieldDataType.LIST: {
2973
+ const listItem = ((_j = item.listItems) !== null && _j !== void 0 ? _j : []).find(li => li.key === String(value));
2974
+ const label = (_k = listItem === null || listItem === void 0 ? void 0 : listItem.label) !== null && _k !== void 0 ? _k : String(value);
2975
+ const color = listItem === null || listItem === void 0 ? void 0 : listItem.color;
2976
+ const bg = listItem === null || listItem === void 0 ? void 0 : listItem.backgroundColor;
2977
+ if (color && bg) {
2978
+ return (h("span", { class: "mrd-layout-section__badge", style: { color, backgroundColor: bg } }, label));
2979
+ }
2980
+ if (color) {
2981
+ return (h("span", { class: "mrd-layout-section__badge-dot-row" }, h("span", { class: "mrd-layout-section__badge-dot", style: { backgroundColor: color } }), label));
2982
+ }
2983
+ return label;
2984
+ }
2985
+ case ClientLayoutItemFieldDataType.SECRET:
2986
+ return value ? h("span", { class: "mrd-layout-section__secret-masked" }, '••••••••') : null;
2987
+ default: {
2988
+ const text = CellRenderer.renderValue(dt, value, (_l = item.listItems) !== null && _l !== void 0 ? _l : [], ctx.locale);
2989
+ return text || null;
2990
+ }
2991
+ }
2992
+ }
2993
+ function renderFieldValue(ctx, item, rawValue) {
2994
+ if (rawValue == null || rawValue === '')
2995
+ return null;
2996
+ if (item.multiple && Array.isArray(rawValue)) {
2997
+ const rendered = rawValue.map(v => renderSingleFieldValue(ctx, item, v));
2998
+ if (rendered.every(r => typeof r === 'string' || r == null)) {
2999
+ return rendered.filter(Boolean).join(', ') || null;
3000
+ }
3001
+ return (h("span", null, rendered.map((r, i) => (h("span", { key: String(i) }, r, i < rendered.length - 1 ? ', ' : '')))));
3002
+ }
3003
+ return renderSingleFieldValue(ctx, item, rawValue);
3004
+ }
3005
+ function renderHistoryBadge(ctx, item, raw) {
3006
+ var _a, _b, _c;
3007
+ const hist = (_a = item.historyEnabled) !== null && _a !== void 0 ? _a : (_b = item.field) === null || _b === void 0 ? void 0 : _b.historyEnabled;
3008
+ if (!hist || !item.name)
3009
+ return null;
3010
+ const history = (_c = raw === null || raw === void 0 ? void 0 : raw.history) !== null && _c !== void 0 ? _c : [];
3011
+ if (!history.length)
3012
+ return null;
3013
+ const sorted = [...history].sort((a, b) => b.until.localeCompare(a.until));
3014
+ const isOpen = ctx.openHistoryField === item.name;
3015
+ return (h("span", { class: "mrd-layout-section__history-wrap" }, h("button", { type: "button", class: "mrd-layout-section__history-btn", title: t('history_badge_tooltip', ctx.locale), "aria-label": t('history_badge_tooltip', ctx.locale), onClick: (e) => {
3016
+ e.stopPropagation();
3017
+ ctx.on.toggleHistory(isOpen ? null : item.name);
3018
+ } }, h("svg", { class: "mrd-layout-section__history-icon", viewBox: "0 0 20 20", fill: "currentColor", "aria-hidden": "true" }, h("path", { "fill-rule": "evenodd", d: "M10 18a8 8 0 100-16 8 8 0 000 16zm.75-13a.75.75 0 00-1.5 0v5c0 .207.085.394.22.53l2.5 2.5a.75.75 0 101.06-1.06L10.75 9.69V5z", "clip-rule": "evenodd" }))), isOpen && (h("div", { class: "mrd-layout-section__history-popover", role: "listbox" }, sorted.map((entry, i) => (h("div", { key: String(i), class: "mrd-layout-section__history-entry" }, entry.value, " (", t('history_until', ctx.locale), " ", formatDate(entry.until, ctx.locale), ")")))))));
3019
+ }
3020
+ function renderField(ctx, item) {
3021
+ var _a, _b;
3022
+ if (!item.name)
3023
+ return null;
3024
+ const raw = ctx.data[item.name];
3025
+ const hist = (_a = item.historyEnabled) !== null && _a !== void 0 ? _a : (_b = item.field) === null || _b === void 0 ? void 0 : _b.historyEnabled;
3026
+ const rawValue = hist && raw !== null && typeof raw === 'object' && 'current' in raw
3027
+ ? raw.current
3028
+ : raw;
3029
+ const renderedValue = renderFieldValue(ctx, item, rawValue);
3030
+ if (item.header) {
3031
+ return (h("h1", { class: "mrd-layout-section__field-header", key: item.name }, typeof renderedValue === 'string' ? renderedValue : rawValue != null ? String(rawValue) : item.label));
3032
+ }
3033
+ if (renderedValue == null)
3034
+ return null;
3035
+ const isBlock = item.dataType === ClientLayoutItemFieldDataType.TEXTBLOCK
3036
+ || item.dataType === ClientLayoutItemFieldDataType.LONGTEXT
3037
+ || item.dataType === ClientLayoutItemFieldDataType.JSON;
3038
+ return (h("div", { class: `mrd-layout-section__field${isBlock ? ' mrd-layout-section__field--block' : ''}`, key: item.name }, h("span", { class: "mrd-layout-section__field-label" }, item.label), h("span", { class: "mrd-layout-section__field-value" }, renderedValue, renderHistoryBadge(ctx, item, raw))));
3039
+ }
3040
+
3041
+ const mrdLayoutSectionCss = () => `.mrd-layout-section.sc-mrd-layout-section{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-color-neutral-800)}.mrd-layout-section__field.sc-mrd-layout-section{display:grid;grid-template-columns:200px 1fr;align-items:baseline;gap:0 var(--mrd-space-2);padding:var(--mrd-space-1) 0}.mrd-layout-section__field-label.sc-mrd-layout-section{font-size:var(--mrd-font-size-xs);font-weight:var(--mrd-font-weight-normal);color:var(--mrd-color-neutral-500);padding-top:1px}.mrd-layout-section__field-value.sc-mrd-layout-section{font-size:var(--mrd-font-size-sm);font-weight:var(--mrd-font-weight-medium);color:var(--mrd-color-neutral-800);word-break:break-word;display:inline-flex;align-items:center;gap:var(--mrd-space-1)}.mrd-layout-section__history-wrap.sc-mrd-layout-section{position:relative;display:inline-flex;align-items:center}.mrd-layout-section__history-btn.sc-mrd-layout-section{display:inline-flex;align-items:center;justify-content:center;width:1.25rem;height:1.25rem;padding:0;background:transparent;border:none;border-radius:var(--mrd-border-radius-sm);color:var(--mrd-color-neutral-400);cursor:pointer;flex-shrink:0;transition:color var(--mrd-transition-fast), background-color var(--mrd-transition-fast)}.mrd-layout-section__history-btn.sc-mrd-layout-section:hover{color:var(--mrd-color-neutral-700);background-color:var(--mrd-color-neutral-100)}.mrd-layout-section__history-btn.sc-mrd-layout-section:focus{outline:none;box-shadow:var(--mrd-shadow-focus)}.mrd-layout-section__history-icon.sc-mrd-layout-section{width:0.875rem;height:0.875rem}.mrd-layout-section__history-popover.sc-mrd-layout-section{position:absolute;top:calc(100% + 0.25rem);left:0;min-width:24rem;max-width:24rem;background-color:var(--mrd-color-white);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius-md);box-shadow:var(--mrd-shadow-md);padding:var(--mrd-space-1) 0;z-index:var(--mrd-z-dropdown)}.mrd-layout-section__history-entry.sc-mrd-layout-section{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);font-weight:var(--mrd-font-weight-normal);color:var(--mrd-color-neutral-700);padding:var(--mrd-space-2) var(--mrd-space-3);line-height:var(--mrd-line-height-normal)}.mrd-layout-section__history-entry.sc-mrd-layout-section:not(:last-child){border-bottom:var(--mrd-border-width) solid var(--mrd-color-neutral-100)}.mrd-layout-section__field-header.sc-mrd-layout-section{font-size:var(--mrd-font-size-2xl);font-weight:var(--mrd-font-weight-bold);color:var(--mrd-color-neutral-900);margin:0 0 var(--mrd-space-4) 0;padding:0}.mrd-layout-section__header.sc-mrd-layout-section{font-size:var(--mrd-font-size-xl);font-weight:var(--mrd-font-weight-semibold);color:var(--mrd-color-neutral-800);margin:var(--mrd-space-4) 0 var(--mrd-space-2) 0;padding:0}.mrd-layout-section__text.sc-mrd-layout-section{font-size:var(--mrd-font-size-base);color:var(--mrd-color-neutral-700);line-height:var(--mrd-line-height-relaxed);margin:var(--mrd-space-2) 0}.mrd-layout-section__navigate.sc-mrd-layout-section{display:inline-flex;align-items:center;gap:var(--mrd-space-2);padding:var(--mrd-space-2) var(--mrd-space-3);background:none;border:1px solid var(--mrd-color-neutral-300);border-radius:var(--mrd-border-radius);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-primary);cursor:pointer;margin:var(--mrd-space-2) 0}.mrd-layout-section__navigate.sc-mrd-layout-section:hover{background-color:var(--mrd-color-primary-light);border-color:var(--mrd-color-primary)}.mrd-layout-section__link.sc-mrd-layout-section{color:var(--mrd-color-primary);text-decoration:none}.mrd-layout-section__link.sc-mrd-layout-section:hover{text-decoration:underline}.mrd-layout-section__relation-link.sc-mrd-layout-section{background:none;border:none;padding:0;font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);font-weight:var(--mrd-font-weight-semibold);color:var(--mrd-color-primary);cursor:pointer;text-align:left}.mrd-layout-section__relation-link.sc-mrd-layout-section:hover{text-decoration:underline}.mrd-layout-section__download-link.sc-mrd-layout-section{display:inline-flex;align-items:center;gap:var(--mrd-space-1);background:none;border:none;padding:0;font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-primary);cursor:pointer;text-align:left}.mrd-layout-section__download-link.sc-mrd-layout-section:hover{text-decoration:underline;color:var(--mrd-color-primary-dark)}.mrd-layout-section__file-icon.sc-mrd-layout-section{flex-shrink:0;width:1rem;height:1rem}.mrd-layout-section__boolean--true.sc-mrd-layout-section{color:var(--mrd-color-success);font-weight:var(--mrd-font-weight-semibold)}.mrd-layout-section__boolean--false.sc-mrd-layout-section{color:var(--mrd-color-neutral-400)}.mrd-layout-section__field--block.sc-mrd-layout-section{grid-template-columns:1fr}.mrd-layout-section__badge.sc-mrd-layout-section{display:inline-block;font-size:var(--mrd-font-size-xs);font-weight:var(--mrd-font-weight-medium);padding:2px var(--mrd-space-3);border-radius:10px}.mrd-layout-section__badge-dot-row.sc-mrd-layout-section{display:inline-flex;align-items:center;gap:var(--mrd-space-2)}.mrd-layout-section__badge-dot.sc-mrd-layout-section{display:inline-block;width:10px;height:10px;border-radius:50%;flex-shrink:0}.mrd-layout-section__secret-masked.sc-mrd-layout-section{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-label-color);letter-spacing:0.15em;user-select:none;pointer-events:none}.mrd-layout-section__pre.sc-mrd-layout-section{font-family:var(--mrd-font-family-mono);font-size:var(--mrd-font-size-xs);background-color:var(--mrd-color-neutral-50);border:1px solid var(--mrd-color-neutral-200);border-radius:var(--mrd-border-radius);padding:var(--mrd-space-3);margin:0;max-height:calc(15 * var(--mrd-font-size-xs));overflow-x:auto;overflow-y:auto;white-space:pre-wrap;word-break:break-word}.mrd-layout-section__group.sc-mrd-layout-section{margin:var(--mrd-space-4) 0}.mrd-layout-section__group-title.sc-mrd-layout-section{font-size:var(--mrd-font-size-xs);font-weight:var(--mrd-font-weight-semibold);color:var(--mrd-color-neutral-500);margin:0 0 var(--mrd-space-2) 0;padding-bottom:0;letter-spacing:0.01em}.mrd-layout-section__related-view.sc-mrd-layout-section{margin:var(--mrd-space-4) 0}.mrd-layout-section__related-view-title.sc-mrd-layout-section{font-size:var(--mrd-font-size-lg);font-weight:var(--mrd-font-weight-semibold);color:var(--mrd-color-neutral-800);margin:0 0 var(--mrd-space-3) 0}.mrd-layout-section__search.sc-mrd-layout-section{position:relative;margin:var(--mrd-space-2) 0}.mrd-layout-section__search-wrap.sc-mrd-layout-section{position:relative}.mrd-layout-section__search-icon.sc-mrd-layout-section{position:absolute;left:var(--mrd-input-padding-x);top:50%;transform:translateY(-50%);width:1rem;height:1rem;color:var(--mrd-color-neutral-400);pointer-events:none}.mrd-layout-section__search-input.sc-mrd-layout-section{display:block;width:100%;height:var(--mrd-input-height);padding:var(--mrd-input-padding-y) var(--mrd-input-padding-x) var(--mrd-input-padding-y) calc(var(--mrd-input-padding-x) + 1rem + var(--mrd-space-2));font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-input-color);background-color:var(--mrd-input-bg);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);outline:none;appearance:none;box-sizing:border-box}.mrd-layout-section__search-input.sc-mrd-layout-section:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-layout-section__search-input.sc-mrd-layout-section::placeholder{color:var(--mrd-input-placeholder-color)}.mrd-layout-section__search-results.sc-mrd-layout-section{position:absolute;top:100%;left:0;right:0;background-color:var(--mrd-color-white);border:1px solid var(--mrd-color-neutral-300);border-top:none;border-radius:0 0 var(--mrd-border-radius) var(--mrd-border-radius);box-shadow:var(--mrd-shadow-sm);z-index:100;max-height:300px;overflow-y:auto;list-style:none;margin:0;padding:var(--mrd-space-1) 0}.mrd-layout-section__search-result.sc-mrd-layout-section{margin:0;padding:0}.mrd-layout-section__search-result-btn.sc-mrd-layout-section{display:flex;flex-direction:column;width:100%;padding:var(--mrd-space-2) var(--mrd-space-3);background:none;border:none;text-align:left;cursor:pointer;font-family:var(--mrd-font-family)}.mrd-layout-section__search-result-btn.sc-mrd-layout-section:hover{background-color:var(--mrd-color-primary-light)}.mrd-layout-section__search-result-label.sc-mrd-layout-section{font-size:var(--mrd-font-size-sm);font-weight:var(--mrd-font-weight-medium);color:var(--mrd-color-neutral-800)}.mrd-layout-section__search-result-desc.sc-mrd-layout-section{font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-500);margin-top:var(--mrd-space-1)}.mrd-layout-section__image-thumb-btn.sc-mrd-layout-section{background:none;border:none;padding:0;cursor:pointer;display:inline-block;border-radius:var(--mrd-border-radius);overflow:hidden;line-height:0}.mrd-layout-section__image-thumb-btn.sc-mrd-layout-section:hover .mrd-layout-section__image-thumb.sc-mrd-layout-section{opacity:0.85}.mrd-layout-section__image-thumb.sc-mrd-layout-section{display:block;max-width:160px;max-height:100px;border-radius:var(--mrd-border-radius);object-fit:cover;transition:opacity 0.15s}.mrd-layout-section__modal-backdrop.sc-mrd-layout-section{position:fixed;inset:0;background:rgba(0, 0, 0, 0.6);z-index:300;display:flex;align-items:center;justify-content:center}.mrd-layout-section__modal.sc-mrd-layout-section{position:relative;background:var(--mrd-color-white);border-radius:var(--mrd-border-radius);padding:var(--mrd-space-3);max-width:min(90vw, 900px);max-height:90vh;display:flex;align-items:center;justify-content:center;box-shadow:var(--mrd-shadow-lg)}.mrd-layout-section__modal-close.sc-mrd-layout-section{position:absolute;top:var(--mrd-space-2);right:var(--mrd-space-2);background:rgba(0, 0, 0, 0.5);border:none;border-radius:50%;width:28px;height:28px;display:flex;align-items:center;justify-content:center;color:var(--mrd-color-white);cursor:pointer;font-size:var(--mrd-font-size-sm);line-height:1;z-index:1}.mrd-layout-section__modal-close.sc-mrd-layout-section:hover{background:rgba(0, 0, 0, 0.8)}.mrd-layout-section__modal-image.sc-mrd-layout-section{display:block;max-width:100%;max-height:calc(90vh - 2rem);border-radius:var(--mrd-border-radius);object-fit:contain}`;
2842
3042
 
2843
3043
  const MrdLayoutSection = class {
2844
3044
  constructor(hostRef) {
@@ -2920,14 +3120,8 @@ const MrdLayoutSection = class {
2920
3120
  }
2921
3121
  }
2922
3122
  }
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
3123
  emitLoadImages() {
2930
- for (const item of this.flattenItems(this.items)) {
3124
+ for (const item of flattenItems(this.items)) {
2931
3125
  if (item.type === ClientLayoutItemType.FIELD && item.dataType === ClientLayoutItemFieldDataType.IMAGE) {
2932
3126
  const fieldName = item.name;
2933
3127
  const raw = this.data[fieldName];
@@ -2937,15 +3131,6 @@ const MrdLayoutSection = class {
2937
3131
  }
2938
3132
  }
2939
3133
  }
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
3134
  /** Inject search results. Pass dataClass to target a specific SEARCH item; omit when there is only one. */
2950
3135
  async setSearchResults(results, dataClass) {
2951
3136
  const key = dataClass !== null && dataClass !== void 0 ? dataClass : this.resolveSearchKey();
@@ -3011,113 +3196,26 @@ const MrdLayoutSection = class {
3011
3196
  }
3012
3197
  resolveSearchKey() {
3013
3198
  var _a;
3014
- const items = this.flattenItems(this.items).filter(i => i.type === ClientLayoutItemType.SEARCH);
3199
+ const items = flattenItems(this.items).filter(i => i.type === ClientLayoutItemType.SEARCH);
3015
3200
  if (items.length === 1)
3016
3201
  return (_a = items[0].dataClass) !== null && _a !== void 0 ? _a : null;
3017
3202
  return null;
3018
3203
  }
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), ")")))))));
3204
+ fieldCtx() {
3205
+ return {
3206
+ locale: this.locale,
3207
+ data: this.data,
3208
+ imagePreviews: this.imagePreviews,
3209
+ openHistoryField: this.openHistoryField,
3210
+ on: {
3211
+ download: detail => this.mrdDownload.emit(detail),
3212
+ openImage: url => { this.imagePreviewUrl = url; },
3213
+ toggleHistory: fieldName => { this.openHistoryField = fieldName; },
3214
+ },
3215
+ };
3101
3216
  }
3102
3217
  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))));
3218
+ return renderField(this.fieldCtx(), item);
3121
3219
  }
3122
3220
  renderRelation(item) {
3123
3221
  var _a, _b, _c;
@@ -3150,7 +3248,7 @@ const MrdLayoutSection = class {
3150
3248
  }
3151
3249
  renderRelatedView(item) {
3152
3250
  var _a, _b, _c, _d, _e, _f, _g, _h;
3153
- const key = this.viewKeyFor(item);
3251
+ const key = viewKeyFor(item);
3154
3252
  if (!key)
3155
3253
  return null;
3156
3254
  if (!item.view)
@@ -3165,22 +3263,11 @@ const MrdLayoutSection = class {
3165
3263
  // Canonical parent href for single-container seeding: use the RELATED_VIEW's
3166
3264
  // fromClass (base class) rather than the route class, so polymorphic subtypes
3167
3265
  // resolve to the same container the documents actually reference.
3168
- const containerHref = this.buildContainerHref(item, selfHref, parentId);
3266
+ const containerHref = buildContainerHref(item, selfHref, parentId);
3169
3267
  return (h("div", { class: "mrd-layout-section__related-view", key: `view-${key}` }, showTitle && item.label && h("h3", { class: "mrd-layout-section__related-view-title" }, item.label), docArchetype
3170
3268
  ? this.renderDocumentContainer(item, key, parentId, docArchetype, containerHref)
3171
3269
  : this.renderTable(item, key, parentId)));
3172
3270
  }
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
3271
  /** Document collection view: owns the view-switch + collection actions and
3185
3272
  * swaps between the folder tree and the flat table. Events are re-emitted to
3186
3273
  * the host with the view key, exactly as the raw list/table events were. */
@@ -3281,7 +3368,7 @@ const MrdLayoutSection = class {
3281
3368
  }
3282
3369
  render() {
3283
3370
  const docArchetype = resolveArchetype(this.archetypes, ARCHETYPE_DOCUMENT);
3284
- return (h(Host, { key: '231f5c3e282375b5850291611645fe3c904831bb' }, h("div", { key: '314e39ec3aa1eabeb1a98f6e6d63fcf07e13ccec', class: "mrd-layout-section" }, docArchetype
3371
+ return (h(Host, { key: '5d778188356a25ea13d45745dc5ed573ab2b2ef0' }, h("div", { key: '0b673a4bcf8b36cd21662bb8a3506cc3f30edb04', class: "mrd-layout-section" }, docArchetype
3285
3372
  ? this.renderDocumentObject(docArchetype)
3286
3373
  : this.items.map(item => this.renderItem(item))), this.renderImageModal()));
3287
3374
  }
@@ -3292,9 +3379,9 @@ const MrdLayoutSection = class {
3292
3379
  }]
3293
3380
  }; }
3294
3381
  };
3295
- MrdLayoutSection.style = mrdLayoutSectionScss();
3382
+ MrdLayoutSection.style = mrdLayoutSectionCss();
3296
3383
 
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)}`;
3384
+ const mrdListFieldCss = () => `.sc-mrd-list-field-h{display:block}.mrd-list-field.sc-mrd-list-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-list-field__label.sc-mrd-list-field{display:block;font-family:var(--mrd-font-family);font-size:var(--mrd-label-font-size);font-weight:var(--mrd-label-font-weight);color:var(--mrd-label-color)}.mrd-list-field__label--required.sc-mrd-list-field::after{content:" *";color:var(--mrd-color-danger)}.mrd-list-field__select.sc-mrd-list-field{display:block;width:100%;height:var(--mrd-input-height);padding:var(--mrd-input-padding-y) var(--mrd-input-padding-x);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-input-color);background-color:var(--mrd-input-bg);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);transition:border-color var(--mrd-transition), box-shadow var(--mrd-transition);outline:none;appearance:none;box-sizing:border-box}.mrd-list-field__select.sc-mrd-list-field::placeholder{color:var(--mrd-input-placeholder-color)}.mrd-list-field__select.sc-mrd-list-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-list-field__select.sc-mrd-list-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.mrd-list-field__select--error.sc-mrd-list-field{border-color:var(--mrd-border-color-error)}.mrd-list-field__select--error.sc-mrd-list-field:focus{box-shadow:var(--mrd-shadow-focus-error)}.mrd-list-field__select.sc-mrd-list-field{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right var(--mrd-space-3) center;padding-right:calc(var(--mrd-input-padding-x) + 1.5rem);cursor:pointer}.mrd-list-field__error.sc-mrd-list-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}.mrd-list-field__checkbox-list.sc-mrd-list-field{display:flex;flex-direction:column;gap:var(--mrd-space-2);padding:var(--mrd-space-3);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);background-color:var(--mrd-input-bg)}.mrd-list-field__checkbox-list--error.sc-mrd-list-field{border-color:var(--mrd-border-color-error)}.mrd-list-field__checkbox-item.sc-mrd-list-field{display:flex;align-items:center;gap:var(--mrd-space-2);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-input-color);cursor:pointer}.mrd-list-field__checkbox-item.sc-mrd-list-field input[type=checkbox].sc-mrd-list-field{width:1rem;height:1rem;cursor:pointer;accent-color:var(--mrd-color-primary)}.mrd-list-field__color-dot.sc-mrd-list-field{display:inline-block;width:12px;height:12px;border-radius:50%;flex-shrink:0}`;
3298
3385
 
3299
3386
  const MrdListField = class {
3300
3387
  constructor(hostRef) {
@@ -3317,22 +3404,12 @@ const MrdListField = class {
3317
3404
  if (this.multiple) {
3318
3405
  const vals = Array.from(select.selectedOptions).map(o => o.value);
3319
3406
  this.selected = vals;
3320
- if (this.required && !validateRequired(vals)) {
3321
- this.error = t('required', this.locale);
3322
- }
3323
- else {
3324
- this.error = '';
3325
- }
3407
+ this.error = requiredError(vals, this.required, this.locale);
3326
3408
  this.mrdChange.emit({ name: this.name, value: vals });
3327
3409
  }
3328
3410
  else {
3329
3411
  const val = select.value;
3330
- if (this.required && !validateRequired(val)) {
3331
- this.error = t('required', this.locale);
3332
- }
3333
- else {
3334
- this.error = '';
3335
- }
3412
+ this.error = requiredError(val, this.required, this.locale);
3336
3413
  this.mrdChange.emit({ name: this.name, value: val });
3337
3414
  }
3338
3415
  };
@@ -3347,12 +3424,7 @@ const MrdListField = class {
3347
3424
  else {
3348
3425
  this.selected = [...this.selected, key];
3349
3426
  }
3350
- if (this.required && !validateRequired(this.selected)) {
3351
- this.error = t('required', this.locale);
3352
- }
3353
- else {
3354
- this.error = '';
3355
- }
3427
+ this.error = requiredError(this.selected, this.required, this.locale);
3356
3428
  this.mrdChange.emit({ name: this.name, value: this.selected });
3357
3429
  };
3358
3430
  }
@@ -3376,22 +3448,22 @@ const MrdListField = class {
3376
3448
  const hasError = !!this.error;
3377
3449
  const currentValue = Array.isArray(this.value) ? ((_a = this.value[0]) !== null && _a !== void 0 ? _a : '') : ((_b = this.value) !== null && _b !== void 0 ? _b : '');
3378
3450
  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 => {
3451
+ return (h(Host, null, h("div", { class: "mrd-list-field" }, h(FieldLabel, { base: "mrd-list-field", label: this.label, required: this.required }), h("div", { class: controlClass('mrd-list-field', hasError, 'checkbox-list') }, this.listItems.map(lv => {
3380
3452
  var _a, _b;
3381
3453
  return (h("label", { key: lv.key, class: "mrd-list-field__checkbox-item" }, h("input", { type: "checkbox", checked: this.selected.includes(lv.key), disabled: this.disabled, onChange: () => this.toggleCheckbox(lv.key) }), (lv.color || lv.backgroundColor) && (h("span", { class: "mrd-list-field__color-dot", style: { backgroundColor: (_b = (_a = lv.backgroundColor) !== null && _a !== void 0 ? _a : lv.color) !== null && _b !== void 0 ? _b : '' } })), h("span", null, lv.label)));
3382
- })), hasError && h("span", { class: "mrd-list-field__error" }, this.error))));
3454
+ })), h(FieldError, { base: "mrd-list-field", error: this.error }))));
3383
3455
  }
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 => {
3456
+ return (h(Host, null, h("div", { class: "mrd-list-field" }, h(FieldLabel, { base: "mrd-list-field", label: this.label, required: this.required }), h("select", { class: controlClass('mrd-list-field', hasError, 'select'), name: this.name, required: this.required, disabled: this.disabled, onChange: this.handleSelectChange, onBlur: this.handleBlur }, h("option", { value: "" }, t('select_placeholder', this.locale)), this.listItems.map(lv => {
3385
3457
  var _a, _b;
3386
3458
  const bg = (_b = (_a = lv.backgroundColor) !== null && _a !== void 0 ? _a : lv.color) !== null && _b !== void 0 ? _b : null;
3387
3459
  const style = bg ? { backgroundColor: bg, color: this.getContrastColor(bg) } : {};
3388
3460
  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))));
3461
+ })), h(FieldError, { base: "mrd-list-field", error: this.error }))));
3390
3462
  }
3391
3463
  };
3392
- MrdListField.style = mrdListFieldScss();
3464
+ MrdListField.style = mrdListFieldCss();
3393
3465
 
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)}`;
3466
+ const mrdLongtextFieldCss = () => `.sc-mrd-longtext-field-h{display:block}.mrd-longtext-field.sc-mrd-longtext-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-longtext-field__label.sc-mrd-longtext-field{display:block;font-family:var(--mrd-font-family);font-size:var(--mrd-label-font-size);font-weight:var(--mrd-label-font-weight);color:var(--mrd-label-color)}.mrd-longtext-field__label--required.sc-mrd-longtext-field::after{content:" *";color:var(--mrd-color-danger)}.mrd-longtext-field__input.sc-mrd-longtext-field{display:block;width:100%;height:var(--mrd-input-height);padding:var(--mrd-input-padding-y) var(--mrd-input-padding-x);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-input-color);background-color:var(--mrd-input-bg);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);transition:border-color var(--mrd-transition), box-shadow var(--mrd-transition);outline:none;appearance:none;box-sizing:border-box}.mrd-longtext-field__input.sc-mrd-longtext-field::placeholder{color:var(--mrd-input-placeholder-color)}.mrd-longtext-field__input.sc-mrd-longtext-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-longtext-field__input.sc-mrd-longtext-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.mrd-longtext-field__input--error.sc-mrd-longtext-field{border-color:var(--mrd-border-color-error)}.mrd-longtext-field__input--error.sc-mrd-longtext-field:focus{box-shadow:var(--mrd-shadow-focus-error)}.mrd-longtext-field__error.sc-mrd-longtext-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}.mrd-longtext-field__input.sc-mrd-longtext-field{height:auto;min-height:calc(var(--mrd-input-height) * 5);resize:vertical;line-height:1.5}.mrd-longtext-field__content.sc-mrd-longtext-field{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-input-color);white-space:pre-wrap;word-break:break-word;margin:0;padding:var(--mrd-input-padding-y) var(--mrd-input-padding-x);background-color:var(--mrd-input-bg-disabled);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);line-height:1.5}`;
3395
3467
 
3396
3468
  const MrdLongtextField = class {
3397
3469
  constructor(hostRef) {
@@ -3412,23 +3484,17 @@ const MrdLongtextField = class {
3412
3484
  };
3413
3485
  this.handleBlur = (e) => {
3414
3486
  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
- }
3487
+ this.error = requiredError(val, this.required, this.locale);
3421
3488
  this.mrdBlur.emit({ name: this.name, value: val });
3422
3489
  };
3423
3490
  }
3424
3491
  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))));
3492
+ return (h(Host, { key: '1d23db1324fa0fc97a07fdae65f2d84e43419a72' }, h("div", { key: '0ad2b262088aa3745f088a44af26649593805840', class: "mrd-longtext-field" }, h(FieldLabel, { key: '5a78739d6ced4e2df77589b64c66401819c4b5c7', base: "mrd-longtext-field", label: this.label, required: this.required }), this.disabled ? (h("pre", { class: "mrd-longtext-field__content" }, this.value)) : (h("textarea", { class: controlClass('mrd-longtext-field', !!this.error), name: this.name, placeholder: this.placeholder, required: this.required, rows: 10, onInput: this.handleInput, onBlur: this.handleBlur }, this.value)), h(FieldError, { key: '5b870a75b518e2808518b83c9abebf8589a86108', base: "mrd-longtext-field", error: this.error }))));
3427
3493
  }
3428
3494
  };
3429
- MrdLongtextField.style = mrdLongtextFieldScss();
3495
+ MrdLongtextField.style = mrdLongtextFieldCss();
3430
3496
 
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)}`;
3497
+ const mrdNumberFieldCss = () => `.sc-mrd-number-field-h{display:block}.mrd-number-field.sc-mrd-number-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-number-field__label.sc-mrd-number-field{display:block;font-family:var(--mrd-font-family);font-size:var(--mrd-label-font-size);font-weight:var(--mrd-label-font-weight);color:var(--mrd-label-color)}.mrd-number-field__label--required.sc-mrd-number-field::after{content:" *";color:var(--mrd-color-danger)}.mrd-number-field__input-wrapper.sc-mrd-number-field{position:relative;display:flex;align-items:center}.mrd-number-field__input.sc-mrd-number-field{display:block;width:100%;height:var(--mrd-input-height);padding:var(--mrd-input-padding-y) var(--mrd-input-padding-x);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-input-color);background-color:var(--mrd-input-bg);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);transition:border-color var(--mrd-transition), box-shadow var(--mrd-transition);outline:none;appearance:none;box-sizing:border-box}.mrd-number-field__input.sc-mrd-number-field::placeholder{color:var(--mrd-input-placeholder-color)}.mrd-number-field__input.sc-mrd-number-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-number-field__input.sc-mrd-number-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.mrd-number-field__input--error.sc-mrd-number-field{border-color:var(--mrd-border-color-error)}.mrd-number-field__input--error.sc-mrd-number-field:focus{box-shadow:var(--mrd-shadow-focus-error)}.mrd-number-field__input.sc-mrd-number-field{text-align:right}.mrd-number-field__input.sc-mrd-number-field::placeholder{text-align:left}.mrd-number-field__error.sc-mrd-number-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}`;
3432
3498
 
3433
3499
  const MrdNumberField = class {
3434
3500
  constructor(hostRef) {
@@ -3499,12 +3565,12 @@ const MrdNumberField = class {
3499
3565
  const hasError = !!this.error;
3500
3566
  const suffix = this.dataType === ClientLayoutItemFieldDataType.PERCENTAGE ? '%' :
3501
3567
  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))));
3568
+ return (h(Host, { key: 'fd7220e0a7f574ab0c61094a9ba7fd764e1adafd' }, h("div", { key: 'ef6118a339c9766f187cd2b1fa3fcc85ef8cb69f', class: "mrd-number-field" }, h(FieldLabel, { key: '015207ae65df07f7ee7bbc24ccab45524176dbf7', base: "mrd-number-field", label: this.label, required: this.required }), h("div", { key: '954b99cbcf4002b0336810e354f1a46d39cb8076', class: "mrd-number-field__input-wrapper" }, h("input", { key: 'dddc08e090b200736d186960db1436e44f42703c', class: controlClass('mrd-number-field', hasError), type: "text", inputMode: "decimal", name: this.name, value: this.displayValue, placeholder: this.placeholder || (suffix ? `0${suffix}` : '0'), required: this.required, disabled: this.disabled, onInput: this.handleInput, onBlur: this.handleBlur, onFocus: this.handleFocus })), h(FieldError, { key: '87e12bd737aed0a845470cef66d7a6d61d11de0b', base: "mrd-number-field", error: this.error }))));
3503
3569
  }
3504
3570
  };
3505
- MrdNumberField.style = mrdNumberFieldScss();
3571
+ MrdNumberField.style = mrdNumberFieldCss();
3506
3572
 
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)}`;
3573
+ const mrdRelationFieldCss = () => `.sc-mrd-relation-field-h{display:block}.mrd-relation-field.sc-mrd-relation-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%;position:relative}.mrd-relation-field__label.sc-mrd-relation-field{display:block;font-family:var(--mrd-font-family);font-size:var(--mrd-label-font-size);font-weight:var(--mrd-label-font-weight);color:var(--mrd-label-color)}.mrd-relation-field__label--required.sc-mrd-relation-field::after{content:" *";color:var(--mrd-color-danger)}.mrd-relation-field__select.sc-mrd-relation-field{display:block;width:100%;height:var(--mrd-input-height);padding:var(--mrd-input-padding-y) var(--mrd-input-padding-x);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-input-color);background-color:var(--mrd-input-bg);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);transition:border-color var(--mrd-transition), box-shadow var(--mrd-transition);outline:none;appearance:none;box-sizing:border-box}.mrd-relation-field__select.sc-mrd-relation-field::placeholder{color:var(--mrd-input-placeholder-color)}.mrd-relation-field__select.sc-mrd-relation-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-relation-field__select.sc-mrd-relation-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.mrd-relation-field__select--error.sc-mrd-relation-field{border-color:var(--mrd-border-color-error)}.mrd-relation-field__select--error.sc-mrd-relation-field:focus{box-shadow:var(--mrd-shadow-focus-error)}.mrd-relation-field__select.sc-mrd-relation-field{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right var(--mrd-space-3) center;padding-right:calc(var(--mrd-input-padding-x) + 1.5rem);cursor:pointer}.mrd-relation-field__search.sc-mrd-relation-field{display:block;width:100%;height:var(--mrd-input-height);padding:var(--mrd-input-padding-y) var(--mrd-input-padding-x);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-input-color);background-color:var(--mrd-input-bg);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);transition:border-color var(--mrd-transition), box-shadow var(--mrd-transition);outline:none;appearance:none;box-sizing:border-box}.mrd-relation-field__search.sc-mrd-relation-field::placeholder{color:var(--mrd-input-placeholder-color)}.mrd-relation-field__search.sc-mrd-relation-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-relation-field__search.sc-mrd-relation-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.mrd-relation-field__search--error.sc-mrd-relation-field{border-color:var(--mrd-border-color-error)}.mrd-relation-field__search--error.sc-mrd-relation-field:focus{box-shadow:var(--mrd-shadow-focus-error)}.mrd-relation-field__error.sc-mrd-relation-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}.mrd-relation-field__tags.sc-mrd-relation-field{display:flex;flex-wrap:wrap;gap:var(--mrd-space-1);margin-bottom:var(--mrd-space-1)}.mrd-relation-field__tag.sc-mrd-relation-field{display:inline-flex;align-items:center;gap:var(--mrd-space-1);padding:var(--mrd-space-1) var(--mrd-space-2);background-color:var(--mrd-color-primary-light);color:var(--mrd-color-primary-dark);border-radius:var(--mrd-border-radius-full);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);font-weight:var(--mrd-font-weight-medium)}.mrd-relation-field__tag-remove.sc-mrd-relation-field{background:none;border:none;cursor:pointer;color:var(--mrd-color-primary-dark);font-size:var(--mrd-font-size-xs);padding:0;line-height:1;opacity:0.7}.mrd-relation-field__tag-remove.sc-mrd-relation-field:hover{opacity:1}.mrd-relation-field__search-wrapper.sc-mrd-relation-field{position:relative;display:flex;align-items:center}.mrd-relation-field__spinner.sc-mrd-relation-field{position:absolute;right:var(--mrd-space-3);width:16px;height:16px;border:2px solid var(--mrd-color-neutral-200);border-top-color:var(--mrd-color-primary);border-radius:50%;animation:mrd-spin 0.7s linear infinite}@keyframes mrd-spin{to{transform:rotate(360deg)}}.mrd-relation-field__results.sc-mrd-relation-field{position:absolute;top:calc(100% + var(--mrd-space-1));left:0;right:0;background-color:var(--mrd-color-white);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);box-shadow:var(--mrd-shadow-md);z-index:var(--mrd-z-dropdown);max-height:240px;overflow-y:auto}.mrd-relation-field__result-item.sc-mrd-relation-field{display:flex;flex-direction:column;padding:var(--mrd-space-2) var(--mrd-space-3);cursor:pointer;transition:background-color var(--mrd-transition-fast)}.mrd-relation-field__result-item.sc-mrd-relation-field:hover{background-color:var(--mrd-color-neutral-50)}.mrd-relation-field__result-item.sc-mrd-relation-field:not(:last-child){border-bottom:var(--mrd-border-width) solid var(--mrd-color-neutral-100)}.mrd-relation-field__result-label.sc-mrd-relation-field{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-color-neutral-800);font-weight:var(--mrd-font-weight-medium)}.mrd-relation-field__result-desc.sc-mrd-relation-field{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-500);margin-top:var(--mrd-space-1)}.mrd-relation-field__result-item--highlighted.sc-mrd-relation-field{background-color:var(--mrd-color-primary-light)}.mrd-relation-field__selected-value.sc-mrd-relation-field{display:flex;align-items:center;gap:var(--mrd-space-2);height:var(--mrd-input-height);padding:var(--mrd-input-padding-y) var(--mrd-input-padding-x);background-color:var(--mrd-color-primary-light);border:var(--mrd-border-width) solid var(--mrd-color-primary);border-radius:var(--mrd-border-radius);box-sizing:border-box}.mrd-relation-field__selected-value--error.sc-mrd-relation-field{border-color:var(--mrd-border-color-error);background-color:var(--mrd-color-danger-light)}.mrd-relation-field__selected-name.sc-mrd-relation-field{flex:1;font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);font-weight:var(--mrd-font-weight-medium);color:var(--mrd-color-primary-dark);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mrd-relation-field__selected-clear.sc-mrd-relation-field{flex-shrink:0;background:none;border:none;cursor:pointer;color:var(--mrd-color-primary-dark);font-size:var(--mrd-font-size-sm);padding:0;line-height:1;opacity:0.6;transition:opacity var(--mrd-transition-fast)}.mrd-relation-field__selected-clear.sc-mrd-relation-field:hover{opacity:1}.mrd-relation-field__no-results.sc-mrd-relation-field{padding:var(--mrd-space-4);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-500);text-align:center}`;
3508
3574
 
3509
3575
  const MrdRelationField = class {
3510
3576
  constructor(hostRef) {
@@ -3605,12 +3671,7 @@ const MrdRelationField = class {
3605
3671
  this.showResults = false;
3606
3672
  this.mrdChange.emit({ name: this.name, value: result.id });
3607
3673
  }
3608
- if (this.required && !validateRequired(this.selectedItems)) {
3609
- this.error = t('required', this.locale);
3610
- }
3611
- else {
3612
- this.error = '';
3613
- }
3674
+ this.error = requiredError(this.selectedItems, this.required, this.locale);
3614
3675
  };
3615
3676
  this.handleRemoveSelected = (id) => {
3616
3677
  this.selectedItems = this.selectedItems.filter(i => i.id !== id);
@@ -3619,12 +3680,7 @@ const MrdRelationField = class {
3619
3680
  };
3620
3681
  this.handleDropdownChange = (e) => {
3621
3682
  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
- }
3683
+ this.error = requiredError(val, this.required, this.locale);
3628
3684
  this.mrdChange.emit({ name: this.name, value: val });
3629
3685
  };
3630
3686
  this.handleBlur = () => {
@@ -3735,19 +3791,19 @@ const MrdRelationField = class {
3735
3791
  const hasError = !!this.error;
3736
3792
  if (this.editBehavior === ClientLayoutItemRelationEditBehavior.DROPDOWN) {
3737
3793
  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))));
3794
+ return (h(Host, null, h("div", { class: "mrd-relation-field" }, h(FieldLabel, { base: "mrd-relation-field", label: this.label, required: this.required }), h("select", { class: controlClass('mrd-relation-field', hasError, 'select'), name: this.name, required: this.required, disabled: this.disabled, onChange: this.handleDropdownChange }, h("option", { value: "" }, t('select_placeholder', this.locale)), this.allRecords.map(record => (h("option", { key: record.id, value: record.id, selected: record.id === currentValue }, record.label)))), h(FieldError, { base: "mrd-relation-field", error: this.error }))));
3739
3795
  }
3740
3796
  if (this.displayType === ClientLayoutItemRelationDisplayType.DROPDOWN) {
3741
3797
  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))));
3798
+ return (h(Host, null, h("div", { class: "mrd-relation-field" }, h(FieldLabel, { base: "mrd-relation-field", label: this.label, required: this.required }), h("select", { class: controlClass('mrd-relation-field', hasError, 'select'), name: this.name, required: this.required, disabled: this.disabled, onChange: this.handleDropdownChange }, h("option", { value: "" }, t('select_placeholder', this.locale)), this.dropdownValues.map(dv => (h("option", { key: dv.key, value: dv.key, selected: dv.key === currentValue }, dv.label)))), h(FieldError, { base: "mrd-relation-field", error: this.error }))));
3743
3799
  }
3744
3800
  // SEARCH mode
3745
- const labelEl = this.label && (h("label", { class: `mrd-relation-field__label${this.required ? ' mrd-relation-field__label--required' : ''}` }, this.label));
3801
+ const labelEl = h(FieldLabel, { base: "mrd-relation-field", label: this.label, required: this.required });
3746
3802
  // Single selection: show selected value as a badge, hide the search input
3747
3803
  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))));
3804
+ return (h(Host, null, h("div", { class: "mrd-relation-field" }, labelEl, h("div", { class: `mrd-relation-field__selected-value${hasError ? ' mrd-relation-field__selected-value--error' : ''}` }, h("span", { class: "mrd-relation-field__selected-name" }, this.selectedItems[0].label), h("button", { type: "button", class: "mrd-relation-field__selected-clear", onClick: this.clearSelection, "aria-label": t('remove', this.locale) }, "\u2715")), h(FieldError, { base: "mrd-relation-field", error: this.error }))));
3749
3805
  }
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))));
3806
+ return (h(Host, null, h("div", { class: "mrd-relation-field" }, labelEl, this.multiple && this.selectedItems.length > 0 && (h("div", { class: "mrd-relation-field__tags" }, this.selectedItems.map(item => (h("span", { key: item.id, class: "mrd-relation-field__tag" }, item.label, h("button", { type: "button", class: "mrd-relation-field__tag-remove", onClick: () => this.handleRemoveSelected(item.id), "aria-label": t('remove', this.locale) }, "\u2715")))))), h("div", { class: "mrd-relation-field__search-wrapper" }, h("input", { class: `mrd-relation-field__search${hasError ? ' mrd-relation-field__search--error' : ''}`, type: "text", value: this.searchQuery, placeholder: t('search_placeholder', this.locale), disabled: this.disabled, onInput: this.handleSearchInput, onKeyDown: this.handleKeyDown, onBlur: this.handleBlur }), this.isLoading && (h("span", { class: "mrd-relation-field__spinner", "aria-label": t('loading', this.locale) }))), this.showResults && (h("div", { class: "mrd-relation-field__results" }, this.searchResults.length === 0 && !this.isLoading ? (h("div", { class: "mrd-relation-field__no-results" }, t('no_results', this.locale))) : (this.searchResults.map((result, i) => (h("div", { key: result.id, class: `mrd-relation-field__result-item${i === this.highlightedIndex ? ' mrd-relation-field__result-item--highlighted' : ''}`, onMouseDown: () => this.handleResultSelect(result) }, h("span", { class: "mrd-relation-field__result-label" }, result.label), result.description && (h("span", { class: "mrd-relation-field__result-desc" }, result.description)))))))), h(FieldError, { base: "mrd-relation-field", error: this.error }))));
3751
3807
  }
3752
3808
  get el() { return getElement(this); }
3753
3809
  static get watchers() { return {
@@ -3759,9 +3815,9 @@ const MrdRelationField = class {
3759
3815
  }]
3760
3816
  }; }
3761
3817
  };
3762
- MrdRelationField.style = mrdRelationFieldScss();
3818
+ MrdRelationField.style = mrdRelationFieldCss();
3763
3819
 
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}`;
3820
+ const mrdSecretFieldCss = () => `.sc-mrd-secret-field-h{display:block}.mrd-secret-field.sc-mrd-secret-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-secret-field__label.sc-mrd-secret-field{display:block;font-family:var(--mrd-font-family);font-size:var(--mrd-label-font-size);font-weight:var(--mrd-label-font-weight);color:var(--mrd-label-color)}.mrd-secret-field__label--required.sc-mrd-secret-field::after{content:" *";color:var(--mrd-color-danger)}.mrd-secret-field__input.sc-mrd-secret-field{display:block;width:100%;height:var(--mrd-input-height);padding:var(--mrd-input-padding-y) var(--mrd-input-padding-x);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-input-color);background-color:var(--mrd-input-bg);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);transition:border-color var(--mrd-transition), box-shadow var(--mrd-transition);outline:none;appearance:none;box-sizing:border-box}.mrd-secret-field__input.sc-mrd-secret-field::placeholder{color:var(--mrd-input-placeholder-color)}.mrd-secret-field__input.sc-mrd-secret-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-secret-field__input.sc-mrd-secret-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.mrd-secret-field__input--error.sc-mrd-secret-field{border-color:var(--mrd-border-color-error)}.mrd-secret-field__input--error.sc-mrd-secret-field:focus{box-shadow:var(--mrd-shadow-focus-error)}.mrd-secret-field__error.sc-mrd-secret-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}.mrd-secret-field__masked.sc-mrd-secret-field{display:block;font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-label-color);letter-spacing:0.15em;user-select:none;pointer-events:none}`;
3765
3821
 
3766
3822
  const MrdSecretField = class {
3767
3823
  constructor(hostRef) {
@@ -3782,38 +3838,439 @@ const MrdSecretField = class {
3782
3838
  };
3783
3839
  this.handleBlur = (e) => {
3784
3840
  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
- }
3841
+ this.error = requiredError(val, this.required, this.locale);
3791
3842
  this.mrdBlur.emit({ name: this.name, value: val });
3792
3843
  };
3793
3844
  }
3794
3845
  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
3846
+ return (h(Host, { key: 'acb865b235652feba713aedda7a7fccbdc01ad20' }, h("div", { key: 'e7471ade9c683cac9469ec89778c967badb046f9', class: "mrd-secret-field" }, h(FieldLabel, { key: '2f9b864779ead352fda53af8597ddcd31377249d', base: "mrd-secret-field", label: this.label, required: this.required }), this.disabled
3797
3847
  ? (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))));
3848
+ : (h("input", { class: controlClass('mrd-secret-field', !!this.error), type: "password", name: this.name, value: this.value, placeholder: this.placeholder, required: this.required, autocomplete: "new-password", onInput: this.handleInput, onBlur: this.handleBlur })), h(FieldError, { key: '438418e2cf0f53a6c247d5f332aae8e8978b94ea', base: "mrd-secret-field", error: this.error }))));
3799
3849
  }
3800
3850
  };
3801
- MrdSecretField.style = mrdSecretFieldScss();
3851
+ MrdSecretField.style = mrdSecretFieldCss();
3802
3852
 
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;
3853
+ /**
3854
+ * Pure sort/filter/aggregation query logic for mrd-table.
3855
+ * No component state — everything is passed in.
3856
+ */
3811
3857
  const TEXT_TYPES = new Set(['TEXT', 'TEXTBLOCK', 'EMAIL', 'HYPERLINK']);
3812
3858
  const NUMERIC_TYPES = new Set(['INTEGER', 'DECIMAL', 'PERCENTAGE', 'CURRENCY']);
3813
3859
  const DATE_TYPES = new Set(['DATE', 'DATETIME', 'TIME']);
3814
3860
  const NO_FILTER_TYPES = new Set(['FILE', 'IMAGE']);
3815
3861
  /** Column types that cannot be sorted or filtered (not stored in PostgreSQL). */
3816
3862
  const NON_INTERACTIVE_TYPES = new Set(['LONGTEXT', 'JSON', 'FILE', 'IMAGE']);
3863
+ function parseDefaultSort(defaultSort) {
3864
+ var _a;
3865
+ if (!defaultSort)
3866
+ return { field: '', dir: 'asc' };
3867
+ const parts = defaultSort.split(',');
3868
+ return { field: parts[0].trim(), dir: ((_a = parts[1]) === null || _a === void 0 ? void 0 : _a.trim()) === 'desc' ? 'desc' : 'asc' };
3869
+ }
3870
+ /** Raw sort query-param value, e.g. "name" or "name,desc". */
3871
+ function buildSortParam(field, dir) {
3872
+ if (!field)
3873
+ return '';
3874
+ return dir === 'desc' ? `${field},desc` : field;
3875
+ }
3876
+ /** Query params for a page request: page + sort + filterClass + view filters + active column filters. */
3877
+ function buildTableQueryParams(opts) {
3878
+ var _a, _b;
3879
+ const p = new URLSearchParams();
3880
+ if (opts.page > 0)
3881
+ p.set('page', String(opts.page));
3882
+ if (opts.sort)
3883
+ p.set('sort', opts.sort);
3884
+ if (opts.filterClass)
3885
+ p.set('type', opts.filterClass);
3886
+ applyViewFilters(p, opts.viewFilters);
3887
+ for (const f of opts.activeFilters) {
3888
+ if (f.operator === 'isEmpty') {
3889
+ p.set(f.field, '');
3890
+ continue;
3891
+ }
3892
+ if (f.operator === 'isNotEmpty') {
3893
+ p.set(f.field + '_notempty', 'true');
3894
+ continue;
3895
+ }
3896
+ if (f.operator === 'startsWith') {
3897
+ p.set(f.field + '_startswith', String((_a = f.value) !== null && _a !== void 0 ? _a : ''));
3898
+ continue;
3899
+ }
3900
+ if ((_b = f.values) === null || _b === void 0 ? void 0 : _b.length) {
3901
+ p.set(f.field, f.values.join(','));
3902
+ continue;
3903
+ }
3904
+ if (f.value != null)
3905
+ p.set(f.field, String(f.value));
3906
+ if (f.from != null)
3907
+ p.set(f.field + '_from', String(f.from));
3908
+ if (f.to != null)
3909
+ p.set(f.field + '_to', String(f.to));
3910
+ }
3911
+ return p.toString();
3912
+ }
3913
+ /** Groups aggregate columns by function; null when the view has no aggregates. */
3914
+ function buildAggregationParams(columns) {
3915
+ var _a;
3916
+ const groups = { sum: [], avg: [], count: [] };
3917
+ for (const col of columns) {
3918
+ if (col.type !== 'FIELD' || !col.aggregate)
3919
+ continue;
3920
+ const fn = col.aggregate.toLowerCase();
3921
+ if (fn in groups)
3922
+ groups[fn].push((_a = col.name) !== null && _a !== void 0 ? _a : '');
3923
+ }
3924
+ const params = {};
3925
+ if (groups.sum.length)
3926
+ params.sum = groups.sum;
3927
+ if (groups.avg.length)
3928
+ params.avg = groups.avg;
3929
+ if (groups.count.length)
3930
+ params.count = groups.count;
3931
+ return Object.keys(params).length > 0 ? params : null;
3932
+ }
3933
+ /** Aggregation query string: the page-0 query params without page/sort, plus sum/avg/count. */
3934
+ function buildAggregationQs(basePageQs, columns) {
3935
+ var _a, _b, _c;
3936
+ const p = new URLSearchParams(basePageQs);
3937
+ p.delete('page');
3938
+ p.delete('sort');
3939
+ const groups = buildAggregationParams(columns);
3940
+ if ((_a = groups === null || groups === void 0 ? void 0 : groups.sum) === null || _a === void 0 ? void 0 : _a.length)
3941
+ p.set('sum', groups.sum.join(','));
3942
+ if ((_b = groups === null || groups === void 0 ? void 0 : groups.avg) === null || _b === void 0 ? void 0 : _b.length)
3943
+ p.set('avg', groups.avg.join(','));
3944
+ if ((_c = groups === null || groups === void 0 ? void 0 : groups.count) === null || _c === void 0 ? void 0 : _c.length)
3945
+ p.set('count', groups.count.join(','));
3946
+ return p.toString();
3947
+ }
3948
+ /** True when the pending filter actually constrains anything. */
3949
+ function filterHasValue(f) {
3950
+ if (f.operator === 'isEmpty' || f.operator === 'isNotEmpty')
3951
+ return true;
3952
+ if (f.values !== undefined && f.values.length > 0)
3953
+ return true;
3954
+ if (f.value != null && f.value !== '')
3955
+ return true;
3956
+ if (typeof f.value === 'boolean')
3957
+ return true;
3958
+ if (f.from != null && f.from !== '')
3959
+ return true;
3960
+ if (f.to != null && f.to !== '')
3961
+ return true;
3962
+ return false;
3963
+ }
3964
+ // ── DATETIME filters: the user edits local "YYYY-MM-DD" dates, the API stores UTC ISO ──
3965
+ /** UTC ISO string at the start (midnight) of the given local day. */
3966
+ function dateLocalToUTCStart(dateStr) {
3967
+ if (!dateStr)
3968
+ return dateStr;
3969
+ const [year, month, day] = dateStr.split('-').map(Number);
3970
+ return new Date(year, month - 1, day).toISOString().replace(/\.\d{3}Z$/, 'Z');
3971
+ }
3972
+ /** Start of the day AFTER the given local date (exclusive range end). */
3973
+ function dateLocalToUTCEndExclusive(dateStr) {
3974
+ if (!dateStr)
3975
+ return dateStr;
3976
+ const [year, month, day] = dateStr.split('-').map(Number);
3977
+ return new Date(year, month - 1, day + 1).toISOString().replace(/\.\d{3}Z$/, 'Z');
3978
+ }
3979
+ /** Stored UTC ISO string back to the local "YYYY-MM-DD" date. */
3980
+ function utcISOToLocalDate(utcStr) {
3981
+ if (!utcStr)
3982
+ return utcStr;
3983
+ const d = new Date(utcStr);
3984
+ if (isNaN(d.getTime()))
3985
+ return utcStr;
3986
+ return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
3987
+ }
3988
+ /** The stored "to" is the exclusive end (next midnight); subtract a day to recover the entered date. */
3989
+ function utcISOToLocalDateExclusiveEnd(utcStr) {
3990
+ if (!utcStr)
3991
+ return utcStr;
3992
+ const d = new Date(utcStr);
3993
+ if (isNaN(d.getTime()))
3994
+ return utcStr;
3995
+ d.setDate(d.getDate() - 1);
3996
+ return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
3997
+ }
3998
+ /** Applies the local→UTC conversion when a DATETIME filter is submitted.
3999
+ * Exact date → range covering the full local day. */
4000
+ function normalizeDatetimeFilter(f) {
4001
+ const normalized = Object.assign({}, f);
4002
+ if (f.dataType === 'DATETIME' && f.operator !== 'isEmpty' && f.operator !== 'isNotEmpty') {
4003
+ if (typeof normalized.value === 'string' && normalized.value) {
4004
+ normalized.from = dateLocalToUTCStart(normalized.value);
4005
+ normalized.to = dateLocalToUTCEndExclusive(normalized.value);
4006
+ normalized.value = undefined;
4007
+ }
4008
+ else {
4009
+ if (typeof normalized.from === 'string' && normalized.from)
4010
+ normalized.from = dateLocalToUTCStart(normalized.from);
4011
+ if (typeof normalized.to === 'string' && normalized.to)
4012
+ normalized.to = dateLocalToUTCEndExclusive(normalized.to);
4013
+ }
4014
+ }
4015
+ return normalized;
4016
+ }
4017
+ /** Converts a stored DATETIME filter back to local dates for the popup.
4018
+ * A range covering a single local day is restored to exact-date mode. */
4019
+ function datetimeFilterToDisplay(existing) {
4020
+ const display = Object.assign({}, existing);
4021
+ if (typeof display.from === 'string' && display.from)
4022
+ display.from = utcISOToLocalDate(display.from);
4023
+ if (typeof display.to === 'string' && display.to)
4024
+ display.to = utcISOToLocalDateExclusiveEnd(display.to);
4025
+ if (display.from && display.to && display.from === display.to) {
4026
+ return Object.assign(Object.assign({}, display), { value: display.from, from: undefined, to: undefined });
4027
+ }
4028
+ return display;
4029
+ }
4030
+
4031
+ /**
4032
+ * Stateless render parts of mrd-table. All state and handlers stay in the
4033
+ * component; these components receive plain values and callbacks.
4034
+ */
4035
+ const FilterIcon = () => (h("span", { class: "mrd-table__filter-icon", "aria-hidden": "true" }, h("svg", { viewBox: "0 0 24 24", width: "14", height: "14", fill: "currentColor" }, h("path", { d: "M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z" }))));
4036
+ const TEXTBLOCK_MAX = 200;
4037
+ const TableCell = ({ col, row, locale, onDownload, onOpenTextblock, onOpenJson }) => {
4038
+ var _a, _b, _c;
4039
+ const dataType = (_a = col.dataType) !== null && _a !== void 0 ? _a : '';
4040
+ const isNumeric = col.type === 'FIELD' && NUMERIC_TYPES.has(dataType);
4041
+ const isFile = col.type === 'FIELD' && (dataType === 'FILE' || dataType === 'IMAGE');
4042
+ if (isFile) {
4043
+ const name = (_b = col.name) !== null && _b !== void 0 ? _b : '';
4044
+ const fileVal = row === null || row === void 0 ? void 0 : row[name];
4045
+ const href = fileVal === null || fileVal === void 0 ? void 0 : fileVal.href;
4046
+ const fileName = fileVal === null || fileVal === void 0 ? void 0 : fileVal.fileName;
4047
+ return (h("td", { class: "mrd-table__cell" }, href && fileName ? (h("button", { class: "mrd-table__file-btn", title: fileName, onClick: (e) => {
4048
+ e.stopPropagation();
4049
+ onDownload({ href, fileName });
4050
+ } }, h("svg", { class: "mrd-table__file-icon", viewBox: "0 0 24 24", "aria-hidden": "true" }, h("path", { fill: "currentColor", d: "M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm-1 7V3.5L18.5 9H13zm-3 8l-3-3 1.41-1.41L10 14.17l4.59-4.58L16 11l-6 6z" })), t('download', locale))) : ''));
4051
+ }
4052
+ if (dataType === 'JSON') {
4053
+ const name = (_c = col.name) !== null && _c !== void 0 ? _c : '';
4054
+ const rawValue = name ? row === null || row === void 0 ? void 0 : row[name] : undefined;
4055
+ if (rawValue == null || rawValue === '')
4056
+ return h("td", { class: "mrd-table__cell" });
4057
+ const compactHtml = CellRenderer.formatJson(rawValue, true);
4058
+ const prettyHtml = CellRenderer.formatJson(rawValue, false);
4059
+ return (h("td", { class: "mrd-table__cell" }, h("span", { class: "mrd-table__json-preview", innerHTML: compactHtml }), h("button", { class: "mrd-table__textblock-btn", onClick: (e) => { e.stopPropagation(); onOpenJson(prettyHtml); }, "aria-label": t('textblock_show_more', locale) }, "\u22EF")));
4060
+ }
4061
+ if (dataType === 'TEXTBLOCK') {
4062
+ const full = CellRenderer.render(col, row, locale);
4063
+ if (full.length <= TEXTBLOCK_MAX) {
4064
+ return h("td", { class: "mrd-table__cell" }, full);
4065
+ }
4066
+ const preview = full.slice(0, TEXTBLOCK_MAX) + '…';
4067
+ return (h("td", { class: "mrd-table__cell" }, preview, h("button", { class: "mrd-table__textblock-btn", onClick: (e) => { e.stopPropagation(); onOpenTextblock(full); }, "aria-label": t('textblock_show_more', locale) }, "\u22EF")));
4068
+ }
4069
+ const value = CellRenderer.render(col, row, locale);
4070
+ return (h("td", { class: `mrd-table__cell${isNumeric ? ' mrd-table__cell--numeric' : ''}` }, value));
4071
+ };
4072
+ /** Formats the aggregation total for one column, '' when not applicable. */
4073
+ function formatAggregationValue(col, aggregations, locale) {
4074
+ var _a;
4075
+ if (col.type !== 'FIELD' || !col.aggregate || !aggregations)
4076
+ return '';
4077
+ const fn = col.aggregate.toLowerCase();
4078
+ const aggData = aggregations[fn];
4079
+ const val = typeof aggData === 'object' && aggData !== null
4080
+ ? aggData[(_a = col.name) !== null && _a !== void 0 ? _a : '']
4081
+ : undefined;
4082
+ if (val == null)
4083
+ return '';
4084
+ const dt = col.dataType;
4085
+ if (dt === 'INTEGER')
4086
+ return formatNumber(val, locale, { maximumFractionDigits: 0 });
4087
+ if (dt === 'PERCENTAGE')
4088
+ return formatPercentage(val, locale);
4089
+ if (dt === 'CURRENCY' && col.currencyCode)
4090
+ return formatCurrency(val, col.currencyCode, locale);
4091
+ return formatNumber(val, locale);
4092
+ }
4093
+ const TotalsRow = ({ columns, aggregations, locale }) => {
4094
+ if (!aggregations)
4095
+ return null;
4096
+ if (!columns.some(c => c.type === 'FIELD' && c.aggregate))
4097
+ return null;
4098
+ return (h("tfoot", null, h("tr", { class: "mrd-table__totals-row" }, columns.map(col => {
4099
+ var _a;
4100
+ const val = formatAggregationValue(col, aggregations, locale);
4101
+ const isNumeric = col.type === 'FIELD' && NUMERIC_TYPES.has((_a = col.dataType) !== null && _a !== void 0 ? _a : '');
4102
+ return (h("td", { class: `mrd-table__totals-cell${isNumeric ? ' mrd-table__totals-cell--numeric' : ''}` }, val));
4103
+ }))));
4104
+ };
4105
+ const TextblockModal = ({ text, locale, onClose }) => {
4106
+ if (text === null)
4107
+ return null;
4108
+ return (h("div", { class: "mrd-table__modal-backdrop", onClick: onClose, role: "dialog", "aria-modal": "true" }, h("div", { class: "mrd-table__modal", onClick: (e) => e.stopPropagation() }, h("button", { class: "mrd-table__modal-close", onClick: onClose, "aria-label": t('close', locale) }, "\u2715"), h("p", { class: "mrd-table__modal-text" }, text))));
4109
+ };
4110
+ const JsonModal = ({ html, locale, onClose }) => {
4111
+ if (html === null)
4112
+ return null;
4113
+ return (h("div", { class: "mrd-table__modal-backdrop", onClick: onClose, role: "dialog", "aria-modal": "true" }, h("div", { class: "mrd-table__modal", onClick: (e) => e.stopPropagation() }, h("button", { class: "mrd-table__modal-close", onClick: onClose, "aria-label": t('close', locale) }, "\u2715"), h("pre", { class: "mrd-table__modal-json", innerHTML: html }))));
4114
+ };
4115
+ const Toolbar = ({ locale, filterMode, filterCount, actions, views, activeViewIdx, viewPopoverOpen, createPickerOpen, createTypes, cb }) => {
4116
+ var _a;
4117
+ const hasActions = actions.length > 0;
4118
+ const hasViewSwitcher = views.length > 1;
4119
+ return (h("div", { class: "mrd-table__toolbar" }, h("div", { class: "mrd-table__toolbar-left" }, h("button", { class: `mrd-table__action mrd-table__action--secondary mrd-table__filter-toggle${filterMode ? ' mrd-table__filter-toggle--active' : ''}`, onClick: cb.onFilterToggle }, h("svg", { class: "mrd-table__action-icon", viewBox: "0 0 24 24", "aria-hidden": "true" }, h("path", { fill: "currentColor", d: "M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z" })), filterCount > 0 && h("span", { class: "mrd-table__filter-badge" }, filterCount), h("span", { class: "mrd-table__action-tooltip" }, filterMode ? t('table_filter_hide', locale) : t('table_filter', locale), filterCount > 0 ? ` (${filterCount} ${t('table_filter_active', locale)})` : '')), filterCount > 0 && (h("button", { class: "mrd-table__action mrd-table__action--secondary", onClick: cb.onClearAllFilters }, h("svg", { class: "mrd-table__action-icon", viewBox: "0 0 24 24", "aria-hidden": "true" }, h("path", { fill: "currentColor", d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" })), h("span", { class: "mrd-table__action-tooltip" }, t('table_filter_clear_all', locale))))), hasViewSwitcher && (h("div", { class: "mrd-table__toolbar-center" }, h("div", { class: "mrd-table__view-switcher" }, h("button", { class: "mrd-table__view-arrow", "aria-label": "Previous view", onClick: () => cb.onViewSwitch((activeViewIdx - 1 + views.length) % views.length) }, "\u25C0"), h("div", { class: "mrd-table__view-title-wrap" }, h("button", { class: "mrd-table__view-title", onClick: (e) => cb.onToggleViewPopover(e) }, (_a = views[activeViewIdx]) === null || _a === void 0 ? void 0 : _a.label), viewPopoverOpen && (h("div", { class: "mrd-table__view-popover", onClick: (e) => e.stopPropagation() }, views.map((v, i) => (h("button", { key: String(i), class: `mrd-table__view-popover-item${i === activeViewIdx ? ' mrd-table__view-popover-item--active' : ''}`, onClick: () => {
4120
+ if (i !== activeViewIdx)
4121
+ cb.onViewSwitch(i);
4122
+ cb.onCloseViewPopover();
4123
+ } }, v.label)))))), h("button", { class: "mrd-table__view-arrow", "aria-label": "Next view", onClick: () => cb.onViewSwitch((activeViewIdx + 1) % views.length) }, "\u25B6")))), hasActions && (h("div", { class: "mrd-table__toolbar-right" }, actions.map(a => {
4124
+ var _a, _b;
4125
+ const pickerTypes = a.action === 'create' ? createTypes : null;
4126
+ if (pickerTypes === null || pickerTypes === void 0 ? void 0 : pickerTypes.length) {
4127
+ return (h("div", { class: "mrd-table__create-picker-wrap", key: `action-${a.action}` }, h("button", { class: `mrd-table__action mrd-table__action--${(_a = a.variant) !== null && _a !== void 0 ? _a : 'secondary'}`, onClick: cb.onToggleCreatePicker }, a.icon
4128
+ ? h("svg", { class: "mrd-table__action-icon", "aria-hidden": "true" }, h("use", { href: a.icon }))
4129
+ : a.label, h("span", { class: "mrd-table__action-tooltip" }, a.label)), createPickerOpen && (h("div", { class: "mrd-table__create-picker" }, pickerTypes.map(ct => (h("button", { key: ct.type, class: "mrd-table__create-picker-item", onClick: () => cb.onCreate(ct.type) }, ct.label)))))));
4130
+ }
4131
+ return (h("button", { key: `action-${a.action}`, class: `mrd-table__action mrd-table__action--${(_b = a.variant) !== null && _b !== void 0 ? _b : 'secondary'}`, disabled: a.disabled, onClick: () => cb.onAction(a.action) }, a.icon
4132
+ ? h("svg", { class: "mrd-table__action-icon", "aria-hidden": "true" }, h("use", { href: a.icon }))
4133
+ : a.label, h("span", { class: "mrd-table__action-tooltip" }, a.label)));
4134
+ })))));
4135
+ };
4136
+
4137
+ const FilterEditor = ({ col, dataType, openFilterCol, pendingFilter, locale, cb }) => {
4138
+ var _a, _b, _c, _d, _e, _f;
4139
+ const pf = pendingFilter;
4140
+ if (NO_FILTER_TYPES.has(dataType)) {
4141
+ return h("p", { class: "mrd-table__filter-no-support" }, t('filter_no_support', locale));
4142
+ }
4143
+ if (dataType === 'BOOLEAN') {
4144
+ const boolOp = pf.operator;
4145
+ const noValueOp = boolOp === 'isEmpty' || boolOp === 'isNotEmpty';
4146
+ return (h("div", { class: "mrd-table__filter-radio-group" }, [
4147
+ { labelKey: 'filter_all', value: null },
4148
+ { labelKey: 'yes', value: true },
4149
+ { labelKey: 'no', value: false },
4150
+ ].map(opt => (h("label", { class: "mrd-table__filter-radio-label" }, h("input", { type: "radio", name: `bf-${openFilterCol}`, checked: !noValueOp && pf.value === opt.value, onChange: () => cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: undefined, value: opt.value })) }), t(opt.labelKey, locale)))), h("label", { class: "mrd-table__filter-radio-label" }, h("input", { type: "radio", name: `bf-${openFilterCol}`, checked: boolOp === 'isEmpty', onChange: () => cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: 'isEmpty', value: undefined })) }), t('filter_is_empty', locale)), h("label", { class: "mrd-table__filter-radio-label" }, h("input", { type: "radio", name: `bf-${openFilterCol}`, checked: boolOp === 'isNotEmpty', onChange: () => cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: 'isNotEmpty', value: undefined })) }), t('filter_is_not_empty', locale))));
4151
+ }
4152
+ if (dataType === 'LIST') {
4153
+ const items = (_a = col.listItems) !== null && _a !== void 0 ? _a : [];
4154
+ const selected = (_b = pf.values) !== null && _b !== void 0 ? _b : [];
4155
+ return (h("div", { class: "mrd-table__filter-list" }, h("div", { class: "mrd-table__filter-list-controls" }, h("button", { class: "mrd-table__filter-list-btn", onClick: () => cb.onReplacePending(Object.assign(Object.assign({}, pf), { values: items.map(i => i.key) })) }, t('filter_select_all', locale)), h("button", { class: "mrd-table__filter-list-btn", onClick: () => cb.onReplacePending(Object.assign(Object.assign({}, pf), { values: [] })) }, t('filter_select_none', locale))), items.map(item => (h("label", { class: "mrd-table__filter-checkbox-label" }, h("input", { type: "checkbox", checked: selected.includes(item.key), onChange: (e) => cb.onToggleValue(item.key, e.target.checked) }), item.label)))));
4156
+ }
4157
+ if (TEXT_TYPES.has(dataType) || dataType === 'RELATION') {
4158
+ const op = (_c = pf.operator) !== null && _c !== void 0 ? _c : 'startsWith';
4159
+ const noInput = op === 'isEmpty' || op === 'isNotEmpty';
4160
+ return (h("div", { class: "mrd-table__filter-editor" }, h("select", { class: "mrd-table__filter-select", onChange: (e) => cb.onSetPending('operator', e.target.value) }, [
4161
+ { val: 'startsWith', labelKey: 'filter_starts_with' },
4162
+ { val: 'equals', labelKey: 'filter_equals' },
4163
+ { val: 'isEmpty', labelKey: 'filter_is_empty' },
4164
+ { val: 'isNotEmpty', labelKey: 'filter_is_not_empty' },
4165
+ ].map(o => h("option", { value: o.val, selected: op === o.val }, t(o.labelKey, locale)))), !noInput && (h("input", { type: "text", class: "mrd-table__filter-input", value: String((_d = pf.value) !== null && _d !== void 0 ? _d : ''), placeholder: t('filter_search_value', locale), onInput: (e) => cb.onSetPending('value', e.target.value) }))));
4166
+ }
4167
+ if (NUMERIC_TYPES.has(dataType)) {
4168
+ const numOp = pf.operator;
4169
+ const noInput = numOp === 'isEmpty' || numOp === 'isNotEmpty';
4170
+ const rangeMode = !noInput && (pf.from !== undefined || pf.to !== undefined);
4171
+ return (h("div", { class: "mrd-table__filter-editor" }, h("select", { class: "mrd-table__filter-select", onChange: (e) => {
4172
+ const val = e.target.value;
4173
+ if (val === 'isEmpty' || val === 'isNotEmpty') {
4174
+ cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: val, value: undefined, from: undefined, to: undefined }));
4175
+ }
4176
+ else {
4177
+ cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: undefined }));
4178
+ }
4179
+ } }, h("option", { value: "", selected: !noInput }, t('filter_has_value', locale)), h("option", { value: "isEmpty", selected: numOp === 'isEmpty' }, t('filter_is_empty', locale)), h("option", { value: "isNotEmpty", selected: numOp === 'isNotEmpty' }, t('filter_is_not_empty', locale))), !noInput && (h("div", { class: "mrd-table__filter-editor" }, h("div", { class: "mrd-table__filter-radio-group mrd-table__filter-radio-group--inline" }, h("label", { class: "mrd-table__filter-radio-label" }, h("input", { type: "radio", name: `nm-${openFilterCol}`, checked: !rangeMode, onChange: () => cb.onReplacePending(Object.assign(Object.assign({}, pf), { from: undefined, to: undefined })) }), t('filter_exact', locale)), h("label", { class: "mrd-table__filter-radio-label" }, h("input", { type: "radio", name: `nm-${openFilterCol}`, checked: rangeMode, onChange: () => cb.onReplacePending(Object.assign(Object.assign({}, pf), { value: undefined, from: null, to: null })) }), t('filter_range', locale))), !rangeMode ? (h("input", { type: "number", class: "mrd-table__filter-input", value: pf.value != null ? String(pf.value) : '', onInput: (e) => cb.onSetPending('value', e.target.value) })) : (h("div", { class: "mrd-table__filter-range" }, h("input", { type: "number", class: "mrd-table__filter-input", placeholder: t('filter_from', locale), value: pf.from != null ? String(pf.from) : '', onInput: (e) => cb.onSetPending('from', e.target.value) }), h("span", { class: "mrd-table__filter-range-sep" }, "\u2013"), h("input", { type: "number", class: "mrd-table__filter-input", placeholder: t('filter_to', locale), value: pf.to != null ? String(pf.to) : '', onInput: (e) => cb.onSetPending('to', e.target.value) })))))));
4180
+ }
4181
+ if (dataType === 'DATETIME') {
4182
+ const dtOp = pf.operator;
4183
+ const noInput = dtOp === 'isEmpty' || dtOp === 'isNotEmpty';
4184
+ const rangeMode = !noInput && (pf.from !== undefined || pf.to !== undefined);
4185
+ return (h("div", { class: "mrd-table__filter-editor" }, h("select", { class: "mrd-table__filter-select", onChange: (e) => {
4186
+ const val = e.target.value;
4187
+ if (val === 'isEmpty' || val === 'isNotEmpty') {
4188
+ cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: val, value: undefined, from: undefined, to: undefined }));
4189
+ }
4190
+ else {
4191
+ cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: undefined }));
4192
+ }
4193
+ } }, h("option", { value: "", selected: !noInput }, t('filter_has_value', locale)), h("option", { value: "isEmpty", selected: dtOp === 'isEmpty' }, t('filter_is_empty', locale)), h("option", { value: "isNotEmpty", selected: dtOp === 'isNotEmpty' }, t('filter_is_not_empty', locale))), !noInput && (h("div", { class: "mrd-table__filter-editor" }, h("div", { class: "mrd-table__filter-radio-group mrd-table__filter-radio-group--inline" }, h("label", { class: "mrd-table__filter-radio-label" }, h("input", { type: "radio", name: `dt-${openFilterCol}`, checked: !rangeMode, onChange: () => cb.onReplacePending(Object.assign(Object.assign({}, pf), { from: undefined, to: undefined })) }), t('filter_exact', locale)), h("label", { class: "mrd-table__filter-radio-label" }, h("input", { type: "radio", name: `dt-${openFilterCol}`, checked: rangeMode, onChange: () => cb.onReplacePending(Object.assign(Object.assign({}, pf), { value: undefined, from: null, to: null })) }), t('filter_range', locale))), !rangeMode ? (h("input", { type: "date", class: "mrd-table__filter-input", value: String((_e = pf.value) !== null && _e !== void 0 ? _e : ''), onInput: (e) => cb.onSetPending('value', e.target.value) })) : (h("div", { class: "mrd-table__filter-range mrd-table__filter-range--stacked" }, h("label", { class: "mrd-table__filter-range-label" }, t('filter_from', locale)), h("input", { type: "date", class: "mrd-table__filter-input", value: pf.from != null ? String(pf.from) : '', onInput: (e) => cb.onSetPending('from', e.target.value) }), h("label", { class: "mrd-table__filter-range-label" }, t('filter_to', locale)), h("input", { type: "date", class: "mrd-table__filter-input", value: pf.to != null ? String(pf.to) : '', onInput: (e) => cb.onSetPending('to', e.target.value) })))))));
4194
+ }
4195
+ if (DATE_TYPES.has(dataType)) {
4196
+ const inputType = dataType === 'DATE' ? 'date' : 'time';
4197
+ const dtdOp = pf.operator;
4198
+ const noInput = dtdOp === 'isEmpty' || dtdOp === 'isNotEmpty';
4199
+ const rangeMode = !noInput && (pf.from !== undefined || pf.to !== undefined);
4200
+ return (h("div", { class: "mrd-table__filter-editor" }, h("select", { class: "mrd-table__filter-select", onChange: (e) => {
4201
+ const val = e.target.value;
4202
+ if (val === 'isEmpty' || val === 'isNotEmpty') {
4203
+ cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: val, value: undefined, from: undefined, to: undefined }));
4204
+ }
4205
+ else {
4206
+ cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: undefined }));
4207
+ }
4208
+ } }, h("option", { value: "", selected: !noInput }, t('filter_has_value', locale)), h("option", { value: "isEmpty", selected: dtdOp === 'isEmpty' }, t('filter_is_empty', locale)), h("option", { value: "isNotEmpty", selected: dtdOp === 'isNotEmpty' }, t('filter_is_not_empty', locale))), !noInput && (h("div", { class: "mrd-table__filter-editor" }, h("div", { class: "mrd-table__filter-radio-group mrd-table__filter-radio-group--inline" }, h("label", { class: "mrd-table__filter-radio-label" }, h("input", { type: "radio", name: `dt-${openFilterCol}`, checked: !rangeMode, onChange: () => cb.onReplacePending(Object.assign(Object.assign({}, pf), { from: undefined, to: undefined })) }), t('filter_exact', locale)), h("label", { class: "mrd-table__filter-radio-label" }, h("input", { type: "radio", name: `dt-${openFilterCol}`, checked: rangeMode, onChange: () => cb.onReplacePending(Object.assign(Object.assign({}, pf), { value: undefined, from: null, to: null })) }), t('filter_range', locale))), !rangeMode ? (h("input", { type: inputType, class: "mrd-table__filter-input", value: String((_f = pf.value) !== null && _f !== void 0 ? _f : ''), onInput: (e) => cb.onSetPending('value', e.target.value) })) : (h("div", { class: "mrd-table__filter-range" }, h("input", { type: inputType, class: "mrd-table__filter-input", placeholder: t('filter_from', locale), value: pf.from != null ? String(pf.from) : '', onInput: (e) => cb.onSetPending('from', e.target.value) }), h("input", { type: inputType, class: "mrd-table__filter-input", placeholder: t('filter_to', locale), value: pf.to != null ? String(pf.to) : '', onInput: (e) => cb.onSetPending('to', e.target.value) })))))));
4209
+ }
4210
+ return null;
4211
+ };
4212
+ const FilterPopup = (props) => {
4213
+ var _a;
4214
+ const { col, openFilterCol, popupPos, sortField, sortDir, locale, cb } = props;
4215
+ const label = (_a = col.label) !== null && _a !== void 0 ? _a : openFilterCol;
4216
+ const sortActive = sortField === openFilterCol;
4217
+ return (h("div", { class: "mrd-table__filter-popup", style: { top: `${popupPos.top}px`, left: `${popupPos.left}px` }, onClick: (e) => e.stopPropagation() }, h("div", { class: "mrd-table__filter-popup-header" }, h("span", { class: "mrd-table__filter-popup-title" }, label), h("button", { class: "mrd-table__filter-close", onClick: cb.onClose }, "\u2715")), h("div", { class: "mrd-table__filter-section" }, h("div", { class: "mrd-table__filter-section-label" }, t('filter_sorting', locale)), h("div", { class: "mrd-table__filter-sort-buttons" }, h("button", { class: `mrd-table__filter-sort-btn${sortActive && sortDir === 'asc' ? ' mrd-table__filter-sort-btn--active' : ''}`, onClick: () => cb.onApplySort('asc') }, "\u25B2 ", t('filter_ascending', locale)), h("button", { class: `mrd-table__filter-sort-btn${sortActive && sortDir === 'desc' ? ' mrd-table__filter-sort-btn--active' : ''}`, onClick: () => cb.onApplySort('desc') }, "\u25BC ", t('filter_descending', locale)))), h("div", { class: "mrd-table__filter-divider" }), h("div", { class: "mrd-table__filter-section" }, h("div", { class: "mrd-table__filter-section-label" }, t('filter_section', locale)), h(FilterEditor, Object.assign({}, props))), h("div", { class: "mrd-table__filter-popup-footer" }, h("button", { class: "mrd-table__filter-btn mrd-table__filter-btn--clear", onClick: cb.onClear }, t('filter_clear', locale)), h("button", { class: "mrd-table__filter-btn mrd-table__filter-btn--apply", onClick: cb.onApply }, t('filter_apply', locale)))));
4218
+ };
4219
+
4220
+ /**
4221
+ * Pure window/paging maths for the mrd-table virtual scroll.
4222
+ * The window state itself stays @State in the component; these
4223
+ * functions only compute values from it.
4224
+ */
4225
+ const BUFFER = 10;
4226
+ /** Wait this long (ms) after the last scroll event before requesting pages,
4227
+ * so pages the user quickly scrolls past are skipped. */
4228
+ const REQUEST_DEBOUNCE_MS = 150;
4229
+ function visibleCount(tableHeight, rowHeight) {
4230
+ return Math.ceil(tableHeight / rowHeight);
4231
+ }
4232
+ /** Render window (with buffer) for the given scroll offset. */
4233
+ function computeWindow(scrollTop, rowHeight, tableHeight, total) {
4234
+ const visStart = Math.floor(scrollTop / rowHeight);
4235
+ const visEnd = Math.min(visStart + visibleCount(tableHeight, rowHeight), total - 1);
4236
+ return {
4237
+ renderStart: Math.max(0, visStart - BUFFER),
4238
+ renderEnd: Math.min(total - 1, visEnd + BUFFER),
4239
+ };
4240
+ }
4241
+ /** First/last page (0-based) covering the given row window. */
4242
+ function pageRange(start, end, pageSize) {
4243
+ return { firstPage: Math.floor(start / pageSize), lastPage: Math.floor(end / pageSize) };
4244
+ }
4245
+ function getRowFromPages(pages, index, pageSize) {
4246
+ var _a;
4247
+ const page = pages.get(Math.floor(index / pageSize));
4248
+ return (_a = page === null || page === void 0 ? void 0 : page[index % pageSize]) !== null && _a !== void 0 ? _a : null;
4249
+ }
4250
+ /** Authoritative row count: a page shorter than pageSize is the last page,
4251
+ * so the true total cannot exceed its end index. */
4252
+ function computeEffectiveTotal(loadedPages, pageSize, baseTotal) {
4253
+ let effectiveTotal = baseTotal;
4254
+ for (const [pageNum, pageRows] of loadedPages) {
4255
+ if (pageRows.length < pageSize) {
4256
+ effectiveTotal = Math.min(effectiveTotal, pageNum * pageSize + pageRows.length);
4257
+ }
4258
+ }
4259
+ return effectiveTotal;
4260
+ }
4261
+ /** True when some loaded page was short — the exact total is then known. */
4262
+ function isTotalKnownFromPages(loadedPages, pageSize) {
4263
+ for (const rows of loadedPages.values()) {
4264
+ if (rows.length < pageSize)
4265
+ return true;
4266
+ }
4267
+ return false;
4268
+ }
4269
+
4270
+ const mrdTableCss = () => `@charset "UTF-8";.sc-mrd-table-h{display:block;width:100%}.mrd-table__scroll.sc-mrd-table{overflow-y:auto;overflow-x:auto;border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);overflow-anchor:none}.mrd-table.sc-mrd-table{overflow-x:auto}.mrd-table__table.sc-mrd-table{width:auto;min-width:100%;border-collapse:collapse;font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-900)}.mrd-table__scroll.sc-mrd-table .mrd-table__table.sc-mrd-table{min-width:max-content}.mrd-table__header.sc-mrd-table{position:sticky;top:0;z-index:1;background:var(--mrd-color-white);text-align:left;padding:var(--mrd-space-2) var(--mrd-space-4);border-bottom:2px solid var(--mrd-border-color);color:var(--mrd-color-neutral-600);font-weight:var(--mrd-font-weight-medium);white-space:nowrap;font-size:var(--mrd-font-size-xs);text-transform:uppercase;letter-spacing:0.04em}.mrd-table__header--sortable.sc-mrd-table{cursor:pointer;user-select:none}.mrd-table__header--sortable.sc-mrd-table:hover{background:var(--mrd-color-neutral-50);color:var(--mrd-color-neutral-800)}.mrd-table__header--sorted-asc.sc-mrd-table,.mrd-table__header--sorted-desc.sc-mrd-table{color:var(--mrd-color-primary);border-bottom-color:var(--mrd-color-primary)}.mrd-table__header-label.sc-mrd-table{margin-right:var(--mrd-space-1)}.mrd-table__sort-icon.sc-mrd-table{font-size:0.85rem;opacity:0.4;vertical-align:middle}.mrd-table__header--sorted-asc.sc-mrd-table .mrd-table__sort-icon.sc-mrd-table,.mrd-table__header--sorted-desc.sc-mrd-table .mrd-table__sort-icon.sc-mrd-table{opacity:1;color:var(--mrd-color-primary)}.mrd-table__filter-icon.sc-mrd-table{display:inline-flex;align-items:center;vertical-align:middle;margin-left:var(--mrd-space-1);color:var(--mrd-color-primary)}.mrd-table__row.sc-mrd-table{border-bottom:1px solid var(--mrd-border-color)}.mrd-table__row.sc-mrd-table:hover{background:var(--mrd-color-neutral-200) !important}.mrd-table__row--clickable.sc-mrd-table{cursor:pointer}.mrd-table__spacer.sc-mrd-table{border:none}.mrd-table__spacer.sc-mrd-table td.sc-mrd-table{padding:0;border:none}.mrd-table__cell.sc-mrd-table{padding:var(--mrd-space-2) var(--mrd-space-4);vertical-align:top;white-space:nowrap}.mrd-table__cell--numeric.sc-mrd-table{text-align:right;font-variant-numeric:tabular-nums}.mrd-table__row--loading.sc-mrd-table{background:transparent}.mrd-table__cell--placeholder.sc-mrd-table{padding:var(--mrd-space-2) var(--mrd-space-4);border-bottom:1px solid var(--mrd-border-color)}.mrd-table__placeholder-bar.sc-mrd-table{display:block;height:0.75rem;width:55%;border-radius:var(--mrd-border-radius-sm);background:linear-gradient(90deg, var(--mrd-color-neutral-200) 25%, var(--mrd-color-neutral-100) 50%, var(--mrd-color-neutral-200) 75%);background-size:200% 100%;animation:mrd-shimmer 1.4s ease infinite}@keyframes mrd-shimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}.mrd-table__toolbar.sc-mrd-table{display:flex;align-items:center;justify-content:space-between;padding-bottom:var(--mrd-space-2)}.mrd-table__toolbar-left.sc-mrd-table,.mrd-table__toolbar-right.sc-mrd-table{display:flex;gap:var(--mrd-space-2);align-items:center}.mrd-table__toolbar-center.sc-mrd-table{flex:1;display:flex;justify-content:center;align-items:center;gap:var(--mrd-space-1)}.mrd-table__view-switcher.sc-mrd-table{display:flex;align-items:center;gap:var(--mrd-space-1)}.mrd-table__view-arrow.sc-mrd-table{background:none;border:none;cursor:pointer;padding:0 var(--mrd-space-1);color:var(--mrd-color-neutral-500);font-size:var(--mrd-font-size-xs);line-height:1}.mrd-table__view-arrow.sc-mrd-table:hover{color:var(--mrd-color-neutral-800)}.mrd-table__view-title-wrap.sc-mrd-table{position:relative}.mrd-table__view-title.sc-mrd-table{font-size:var(--mrd-font-size-sm);font-weight:600;color:var(--mrd-color-neutral-800);font-family:var(--mrd-font-family);background:none;border:none;outline:none;cursor:pointer;padding:0 var(--mrd-space-1);max-width:220px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mrd-table__view-title.sc-mrd-table:hover{color:var(--mrd-color-primary)}.mrd-table__view-popover.sc-mrd-table{position:absolute;top:calc(100% + var(--mrd-space-1));left:50%;transform:translateX(-50%);background:var(--mrd-color-white);border:1px solid var(--mrd-color-neutral-200);border-radius:var(--mrd-radius-md);box-shadow:var(--mrd-shadow-md);z-index:100;min-width:160px;padding:var(--mrd-space-1) 0}.mrd-table__view-popover-item.sc-mrd-table{display:block;width:100%;text-align:left;background:none;border:none;cursor:pointer;padding:var(--mrd-space-2) var(--mrd-space-3);font-size:var(--mrd-font-size-sm);font-family:var(--mrd-font-family);color:var(--mrd-color-neutral-700);white-space:nowrap}.mrd-table__view-popover-item.sc-mrd-table:hover{background:var(--mrd-color-neutral-50)}.mrd-table__view-popover-item--active.sc-mrd-table{font-weight:600;color:var(--mrd-color-primary)}.mrd-table__action.sc-mrd-table{position:relative;display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;padding:0;background:transparent;border:1px solid transparent;border-radius:var(--mrd-border-radius);cursor:pointer;color:var(--mrd-color-neutral-400);transition:background-color 0.15s, border-color 0.15s, color 0.15s}.mrd-table__action.sc-mrd-table:hover{background-color:var(--mrd-color-neutral-100);border-color:var(--mrd-color-neutral-300);color:var(--mrd-color-neutral-700)}.mrd-table__action.sc-mrd-table:disabled{opacity:0.4;cursor:not-allowed}.mrd-table__action--primary.sc-mrd-table{color:var(--mrd-color-neutral-500)}.mrd-table__action--primary.sc-mrd-table:hover{background:var(--mrd-color-primary);border-color:var(--mrd-color-primary);color:var(--mrd-color-white)}.mrd-table__action--danger.sc-mrd-table{color:var(--mrd-color-error)}.mrd-table__action--danger.sc-mrd-table:hover{background-color:var(--mrd-color-error-light, #fef2f2);border-color:var(--mrd-color-error)}.mrd-table__action-icon.sc-mrd-table{width:1.25rem;height:1.25rem;pointer-events:none;fill:currentColor}.mrd-table__action-tooltip.sc-mrd-table{display:none;position:absolute;bottom:calc(100% + 6px);right:0;padding:var(--mrd-space-1) var(--mrd-space-2);font-size:var(--mrd-font-size-xs);white-space:nowrap;background:var(--mrd-color-tooltip, #fffce1);color:var(--mrd-color-neutral-900);border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius-sm, var(--mrd-border-radius));pointer-events:none;z-index:10}.mrd-table__action.sc-mrd-table:hover .mrd-table__action-tooltip.sc-mrd-table{display:block}.mrd-table__create-picker-wrap.sc-mrd-table{position:relative}.mrd-table__create-picker.sc-mrd-table{position:absolute;right:0;top:calc(100% + 4px);background:var(--mrd-color-white, #fff);border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);box-shadow:var(--mrd-shadow-md, 0 4px 12px rgba(0, 0, 0, 0.12));z-index:10;min-width:10rem;padding:var(--mrd-space-1) 0}.mrd-table__create-picker-item.sc-mrd-table{display:block;width:100%;text-align:left;padding:var(--mrd-space-2) var(--mrd-space-3);background:none;border:none;cursor:pointer;font-size:var(--mrd-font-size-sm);font-family:var(--mrd-font-family);color:var(--mrd-color-neutral-800)}.mrd-table__create-picker-item.sc-mrd-table:hover{background:var(--mrd-color-neutral-50);color:var(--mrd-color-neutral-900)}.mrd-table__filter-toggle--active.sc-mrd-table{background:var(--mrd-color-primary);border-color:var(--mrd-color-primary);color:var(--mrd-color-white)}.mrd-table__filter-toggle--active.sc-mrd-table:hover{background:var(--mrd-color-primary-dark, var(--mrd-color-primary));border-color:var(--mrd-color-primary-dark, var(--mrd-color-primary));color:var(--mrd-color-white)}.mrd-table__filter-badge.sc-mrd-table{position:absolute;top:-6px;right:-6px;min-width:1.25rem;height:1.25rem;padding:0 3px;background:var(--mrd-color-error, #e53e3e);color:var(--mrd-color-white);border-radius:9999px;font-size:0.65rem;font-weight:var(--mrd-font-weight-medium);line-height:1.25rem;text-align:center;pointer-events:none}.mrd-table__header--filtered.sc-mrd-table{color:var(--mrd-color-primary);border-bottom-color:var(--mrd-color-primary)}.mrd-table__filter-popup.sc-mrd-table{position:fixed;width:280px;background:var(--mrd-color-white);border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);box-shadow:var(--mrd-shadow-md, 0 4px 12px rgba(0, 0, 0, 0.12));z-index:var(--mrd-z-dropdown, 200);font-size:var(--mrd-font-size-sm)}.mrd-table__filter-popup-header.sc-mrd-table{display:flex;align-items:center;justify-content:space-between;padding:var(--mrd-space-2) var(--mrd-space-3);border-bottom:1px solid var(--mrd-border-color)}.mrd-table__filter-popup-title.sc-mrd-table{font-weight:var(--mrd-font-weight-medium);color:var(--mrd-color-neutral-800);font-size:var(--mrd-font-size-sm)}.mrd-table__filter-close.sc-mrd-table{background:transparent;border:none;cursor:pointer;color:var(--mrd-color-neutral-500);font-size:0.9rem;padding:2px 4px;border-radius:3px;line-height:1}.mrd-table__filter-close.sc-mrd-table:hover{background:var(--mrd-color-neutral-100);color:var(--mrd-color-neutral-800)}.mrd-table__filter-section.sc-mrd-table{padding:var(--mrd-space-2) var(--mrd-space-3)}.mrd-table__filter-section-label.sc-mrd-table{font-size:var(--mrd-font-size-xs);font-weight:var(--mrd-font-weight-medium);text-transform:uppercase;letter-spacing:0.04em;color:var(--mrd-color-neutral-500);margin-bottom:var(--mrd-space-2)}.mrd-table__filter-sort-buttons.sc-mrd-table{display:flex;gap:var(--mrd-space-2)}.mrd-table__filter-sort-btn.sc-mrd-table{flex:1;padding:var(--mrd-space-1) var(--mrd-space-2);background:transparent;border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);cursor:pointer;font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-700)}.mrd-table__filter-sort-btn.sc-mrd-table:hover{background:var(--mrd-color-neutral-100)}.mrd-table__filter-sort-btn--active.sc-mrd-table{background:var(--mrd-color-primary);border-color:var(--mrd-color-primary);color:var(--mrd-color-white)}.mrd-table__filter-divider.sc-mrd-table{height:1px;background:var(--mrd-border-color);margin:0}.mrd-table__filter-editor.sc-mrd-table{display:flex;flex-direction:column;gap:var(--mrd-space-2)}.mrd-table__filter-select.sc-mrd-table,.mrd-table__filter-input.sc-mrd-table{width:100%;padding:var(--mrd-space-1) var(--mrd-space-2);border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-900);background:var(--mrd-color-white);box-sizing:border-box}.mrd-table__filter-select.sc-mrd-table:focus,.mrd-table__filter-input.sc-mrd-table:focus{outline:none;border-color:var(--mrd-color-primary);box-shadow:0 0 0 2px rgba(0, 0, 0, 0.06)}.mrd-table__filter-range.sc-mrd-table{display:flex;align-items:center;gap:var(--mrd-space-1)}.mrd-table__filter-range.sc-mrd-table .mrd-table__filter-input.sc-mrd-table{flex:1;min-width:0}.mrd-table__filter-range-sep.sc-mrd-table{color:var(--mrd-color-neutral-400);flex-shrink:0}.mrd-table__filter-range--stacked.sc-mrd-table{flex-direction:column;align-items:stretch;gap:var(--mrd-space-2)}.mrd-table__filter-range-label.sc-mrd-table{font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-500);margin-bottom:2px}.mrd-table__filter-radio-group.sc-mrd-table{display:flex;flex-direction:column;gap:var(--mrd-space-1)}.mrd-table__filter-radio-group--inline.sc-mrd-table{flex-direction:row;gap:var(--mrd-space-3)}.mrd-table__filter-radio-label.sc-mrd-table{display:flex;align-items:center;gap:var(--mrd-space-1);cursor:pointer;font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-800)}.mrd-table__filter-list.sc-mrd-table{display:flex;flex-direction:column;gap:var(--mrd-space-1);max-height:180px;overflow-y:auto}.mrd-table__filter-list-controls.sc-mrd-table{display:flex;gap:var(--mrd-space-2);margin-bottom:var(--mrd-space-1)}.mrd-table__filter-list-btn.sc-mrd-table{font-size:var(--mrd-font-size-xs);color:var(--mrd-color-primary);background:transparent;border:none;cursor:pointer;padding:0;text-decoration:underline}.mrd-table__filter-checkbox-label.sc-mrd-table{display:flex;align-items:center;gap:var(--mrd-space-1);cursor:pointer;font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-800)}.mrd-table__filter-no-support.sc-mrd-table{font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-500);margin:0;font-style:italic}.mrd-table__filter-popup-footer.sc-mrd-table{display:flex;justify-content:flex-end;gap:var(--mrd-space-2);padding:var(--mrd-space-2) var(--mrd-space-3);border-top:1px solid var(--mrd-border-color)}.mrd-table__filter-btn.sc-mrd-table{padding:var(--mrd-space-1) var(--mrd-space-3);border-radius:var(--mrd-border-radius);border:1px solid var(--mrd-border-color);font-size:var(--mrd-font-size-sm);cursor:pointer}.mrd-table__filter-btn--clear.sc-mrd-table{background:transparent;color:var(--mrd-color-neutral-600)}.mrd-table__filter-btn--clear.sc-mrd-table:hover{background:var(--mrd-color-neutral-100)}.mrd-table__filter-btn--apply.sc-mrd-table{background:var(--mrd-color-primary);border-color:var(--mrd-color-primary);color:var(--mrd-color-white)}.mrd-table__filter-btn--apply.sc-mrd-table:hover{background:var(--mrd-color-primary-dark, var(--mrd-color-primary));border-color:var(--mrd-color-primary-dark, var(--mrd-color-primary))}.mrd-table__totals-row.sc-mrd-table{border-top:2px solid var(--mrd-border-color)}.mrd-table__totals-cell.sc-mrd-table{position:sticky;bottom:0;z-index:2;padding:var(--mrd-space-2) var(--mrd-space-4);background:var(--mrd-color-white);font-weight:var(--mrd-font-weight-medium);font-variant-numeric:tabular-nums;white-space:nowrap;border-top:2px solid var(--mrd-border-color)}.mrd-table__totals-cell--numeric.sc-mrd-table{text-align:right}.mrd-table__footer.sc-mrd-table{padding:var(--mrd-space-1) var(--mrd-space-2);font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-500);text-align:right}.mrd-table__empty.sc-mrd-table{padding:var(--mrd-space-4) var(--mrd-space-3);color:var(--mrd-color-neutral-500);font-size:var(--mrd-font-size-sm);text-align:center;margin:0}.mrd-table__file-btn.sc-mrd-table{display:inline-flex;align-items:center;gap:var(--mrd-space-1);background:none;border:none;padding:0;cursor:pointer;color:var(--mrd-color-primary);font-size:var(--mrd-font-size-sm);font-family:inherit;max-width:100%;overflow:hidden}.mrd-table__file-btn.sc-mrd-table:hover{text-decoration:underline;color:var(--mrd-color-primary-dark)}.mrd-table__file-icon.sc-mrd-table{flex-shrink:0;width:1rem;height:1rem}.mrd-table__textblock-btn.sc-mrd-table{display:inline;background:none;border:none;padding:0 0 0 var(--mrd-space-1);cursor:pointer;color:var(--mrd-color-primary);font-size:var(--mrd-font-size-sm);font-family:inherit;line-height:inherit;vertical-align:middle}.mrd-table__textblock-btn.sc-mrd-table:hover{color:var(--mrd-color-primary-dark)}.mrd-table__modal-backdrop.sc-mrd-table{position:fixed;inset:0;background:rgba(0, 0, 0, 0.4);z-index:var(--mrd-z-modal, 300);display:flex;align-items:center;justify-content:center}.mrd-table__modal.sc-mrd-table{background:#fff;border-radius:var(--mrd-radius-md, 0.5rem);padding:var(--mrd-space-6);max-width:min(600px, 90vw);max-height:70vh;overflow-y:auto;position:relative;box-shadow:var(--mrd-shadow-lg)}.mrd-table__modal-close.sc-mrd-table{position:absolute;top:var(--mrd-space-3);right:var(--mrd-space-3);background:none;border:none;cursor:pointer;font-size:1.25rem;line-height:1;color:var(--mrd-color-text-muted, #6b7280);padding:0}.mrd-table__modal-close.sc-mrd-table:hover{color:var(--mrd-color-text, #111827)}.mrd-table__modal-text.sc-mrd-table{margin:0;padding-right:var(--mrd-space-6);white-space:pre-wrap;word-break:break-word;font-size:var(--mrd-font-size-sm);line-height:1.6}.mrd-table__json-preview.sc-mrd-table{font-family:var(--mrd-font-family-mono);font-size:var(--mrd-font-size-xs);overflow:hidden;white-space:nowrap;text-overflow:ellipsis;display:inline-block;max-width:calc(100% - 1.5rem);vertical-align:middle}.mrd-table__modal-json.sc-mrd-table{margin:0;padding-right:var(--mrd-space-6);font-family:var(--mrd-font-family-mono);font-size:var(--mrd-font-size-xs);white-space:pre-wrap;word-break:break-word;line-height:1.6;background:none;border:none}`;
4271
+
4272
+ /** Breedte van de filterpopup in px — voor overflow-correctie. */
4273
+ const POPUP_WIDTH = 280;
3817
4274
  const MrdTable = class {
3818
4275
  constructor(hostRef) {
3819
4276
  registerInstance(this, hostRef);
@@ -3829,6 +4286,8 @@ const MrdTable = class {
3829
4286
  this.keydownHandler = null;
3830
4287
  this.createPickerClickHandler = null;
3831
4288
  this.viewPopoverClickHandler = null;
4289
+ /** Guards against scheduling more than one column-width measurement per freeze. */
4290
+ this.colWidthMeasureScheduled = false;
3832
4291
  // ── Props ──────────────────────────────────────────────────────────────────
3833
4292
  /** The VIEW or RELATED_VIEW layout item. Contains view config, dataClass, fromClass, actions etc. */
3834
4293
  this.item = null;
@@ -3885,13 +4344,10 @@ const MrdTable = class {
3885
4344
  this.minKnownTotal = 0;
3886
4345
  this.handleScroll = (e) => {
3887
4346
  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);
4347
+ const { renderStart, renderEnd } = computeWindow(scroller.scrollTop, this.rowHeight, this.tableHeight, this.baseTotal);
4348
+ this.scrollTop = scroller.scrollTop;
4349
+ this.renderStart = renderStart;
4350
+ this.renderEnd = renderEnd;
3895
4351
  this.requestPagesForWindow(this.renderStart, this.renderEnd);
3896
4352
  };
3897
4353
  }
@@ -3913,16 +4369,9 @@ const MrdTable = class {
3913
4369
  }
3914
4370
  // ── Helpers ────────────────────────────────────────────────────────────────
3915
4371
  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
- }
4372
+ const { field, dir } = parseDefaultSort(defaultSort);
4373
+ this.sortField = field;
4374
+ this.sortDir = dir;
3926
4375
  }
3927
4376
  // ── Public API ─────────────────────────────────────────────────────────────
3928
4377
  /**
@@ -3939,6 +4388,7 @@ const MrdTable = class {
3939
4388
  this.loadedPages = new Map();
3940
4389
  this.requestedPages = new Set();
3941
4390
  this.colWidths = [];
4391
+ this.colWidthMeasureScheduled = false;
3942
4392
  this.scrollTop = 0;
3943
4393
  this.renderStart = 0;
3944
4394
  // Always fill the visible viewport on init — totalElements may be stale from a
@@ -4019,21 +4469,34 @@ const MrdTable = class {
4019
4469
  }
4020
4470
  }
4021
4471
  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
- }
4472
+ // Freeze header widths once the first data page has rendered. The measurement
4473
+ // reads offsetWidth and writes the colWidths @State, which would trigger a
4474
+ // re-render *during* the render cycle if done synchronously here. Defer it to a
4475
+ // writeTask so the state mutation happens outside the render pass (avoids the
4476
+ // Stencil "state/prop changed during rendering" warning and potential loops).
4477
+ if (this.colWidths.length === 0 &&
4478
+ !this.colWidthMeasureScheduled &&
4479
+ this.loadedPages.size > 0 &&
4480
+ this.totalElements > 0) {
4481
+ this.colWidthMeasureScheduled = true;
4482
+ writeTask(() => {
4483
+ this.colWidthMeasureScheduled = false;
4484
+ // Re-check: state may have changed (e.g. a reset) between scheduling and running.
4485
+ if (this.colWidths.length !== 0)
4486
+ return;
4487
+ const ths = this.el.querySelectorAll('.mrd-table__header');
4488
+ if (ths.length > 0) {
4489
+ this.colWidths = Array.from(ths).map(th => th.offsetWidth);
4490
+ }
4491
+ });
4027
4492
  }
4028
4493
  }
4029
4494
  // ── Paging / scroll helpers ────────────────────────────────────────────────
4030
4495
  visibleCount() {
4031
- return Math.ceil(this.tableHeight / this.rowHeight);
4496
+ return visibleCount(this.tableHeight, this.rowHeight);
4032
4497
  }
4033
4498
  sortParam() {
4034
- if (!this.sortField)
4035
- return '';
4036
- return this.sortDir === 'desc' ? `${this.sortField},desc` : this.sortField;
4499
+ return buildSortParam(this.sortField, this.sortDir);
4037
4500
  }
4038
4501
  /** Stable ordered list: primary view first, then alternatives (from the item prop). */
4039
4502
  get allViews() {
@@ -4059,14 +4522,16 @@ const MrdTable = class {
4059
4522
  * VIEW: /excel/{dataClass}
4060
4523
  * RELATED_VIEW: /excel/{fromClass}/{parentId}/{dataClass} */
4061
4524
  buildExcelPath() {
4062
- var _a, _b, _c, _d;
4525
+ var _a;
4063
4526
  const v = this.allViews[this.activeViewIdx];
4064
4527
  if (!v)
4065
4528
  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 : ''}`;
4529
+ return '/excel' + buildListPath({
4530
+ isRelatedView: ((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === 'RELATED_VIEW',
4531
+ fromClass: v.fromClass,
4532
+ parentId: this.parentId,
4533
+ dataClass: v.dataClass,
4534
+ });
4070
4535
  }
4071
4536
  buildActionDetail(action, basicType) {
4072
4537
  var _a, _b, _c;
@@ -4086,80 +4551,28 @@ const MrdTable = class {
4086
4551
  * VIEW: /{dataClass}
4087
4552
  * RELATED_VIEW: /{fromClass}/{parentId}/{dataClass} */
4088
4553
  buildDataPath() {
4089
- var _a, _b, _c, _d;
4554
+ var _a;
4090
4555
  const v = this.allViews[this.activeViewIdx];
4091
4556
  if (!v)
4092
4557
  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 : ''}`;
4558
+ return buildListPath({
4559
+ isRelatedView: ((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === 'RELATED_VIEW',
4560
+ fromClass: v.fromClass,
4561
+ parentId: this.parentId,
4562
+ dataClass: v.dataClass,
4563
+ });
4097
4564
  }
4098
4565
  /** Build query params for a page request from current sort, view filters, filterClass and active column filters. */
4099
4566
  buildQueryParams(page) {
4100
- var _a, _b, _c, _d, _e, _f, _g;
4567
+ var _a;
4101
4568
  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();
4569
+ return buildTableQueryParams({
4570
+ page,
4571
+ sort: this.sortParam(),
4572
+ filterClass: v === null || v === void 0 ? void 0 : v.filterClass,
4573
+ viewFilters: (_a = v === null || v === void 0 ? void 0 : v.view) === null || _a === void 0 ? void 0 : _a.filter,
4574
+ activeFilters: this.activeFilters.values(),
4575
+ });
4163
4576
  }
4164
4577
  get columns() {
4165
4578
  var _a, _b, _c;
@@ -4214,11 +4627,7 @@ const MrdTable = class {
4214
4627
  isTotalKnown() {
4215
4628
  if (this.aggregationsTotal != null)
4216
4629
  return true;
4217
- for (const rows of this.loadedPages.values()) {
4218
- if (rows.length < this.pageSize)
4219
- return true;
4220
- }
4221
- return false;
4630
+ return isTotalKnownFromPages(this.loadedPages, this.pageSize);
4222
4631
  }
4223
4632
  /** Effective total: aggregations-response > totalElements prop > minKnownTotal from setPage(). */
4224
4633
  get baseTotal() {
@@ -4229,61 +4638,9 @@ const MrdTable = class {
4229
4638
  return this.minKnownTotal;
4230
4639
  }
4231
4640
  // ── 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
4641
  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);
4642
+ const qs = this.buildQueryParams(0);
4643
+ this.mrdLoadAggregations.emit({ path: this.buildDataPath(), qs, aggQs: buildAggregationQs(qs, this.columns) });
4287
4644
  }
4288
4645
  // ── Reset pagination ───────────────────────────────────────────────────────
4289
4646
  /** Reset pagination state and scroll to top (used after sort or filter change). */
@@ -4296,6 +4653,7 @@ const MrdTable = class {
4296
4653
  this.loadedPages = new Map();
4297
4654
  this.requestedPages = new Set();
4298
4655
  this.colWidths = [];
4656
+ this.colWidthMeasureScheduled = false;
4299
4657
  this.scrollTop = 0;
4300
4658
  this.renderStart = 0;
4301
4659
  this.minKnownTotal = 0;
@@ -4325,8 +4683,7 @@ const MrdTable = class {
4325
4683
  this.emitPagesForWindow(this.renderStart, this.renderEnd);
4326
4684
  }
4327
4685
  emitPagesForWindow(start, end) {
4328
- const firstPage = Math.floor(start / this.pageSize);
4329
- const lastPage = Math.floor(end / this.pageSize);
4686
+ const { firstPage, lastPage } = pageRange(start, end, this.pageSize);
4330
4687
  const next = new Set(this.requestedPages);
4331
4688
  let changed = false;
4332
4689
  for (let p = firstPage; p <= lastPage; p++) {
@@ -4340,13 +4697,10 @@ const MrdTable = class {
4340
4697
  this.requestedPages = next;
4341
4698
  }
4342
4699
  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;
4700
+ return getRowFromPages(this.loadedPages, i, this.pageSize);
4346
4701
  }
4347
4702
  requestPagesForWindow(start, end) {
4348
- const firstPage = Math.floor(start / this.pageSize);
4349
- const lastPage = Math.floor(end / this.pageSize);
4703
+ const { firstPage, lastPage } = pageRange(start, end, this.pageSize);
4350
4704
  let anyNew = false;
4351
4705
  for (let p = firstPage; p <= lastPage; p++) {
4352
4706
  if (!this.loadedPages.has(p) && !this.requestedPages.has(p) && !this.pendingPages.has(p)) {
@@ -4408,17 +4762,7 @@ const MrdTable = class {
4408
4762
  // If from and to cover the same local day it was an exact-date filter — restore
4409
4763
  // to exact mode so the user sees the single-date input again.
4410
4764
  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
- }
4765
+ this.pendingFilter = datetimeFilterToDisplay(existing);
4422
4766
  }
4423
4767
  else {
4424
4768
  this.pendingFilter = existing ? Object.assign({}, existing) : { field: name, dataType, operator: defaultOperator };
@@ -4484,81 +4828,15 @@ const MrdTable = class {
4484
4828
  const current = (_b = (_a = this.pendingFilter) === null || _a === void 0 ? void 0 : _a.values) !== null && _b !== void 0 ? _b : [];
4485
4829
  this.pendingFilter = Object.assign(Object.assign({}, this.pendingFilter), { values: checked ? [...current, key] : current.filter(k => k !== key) });
4486
4830
  }
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
4831
  applyFilter() {
4538
4832
  const f = this.pendingFilter;
4539
4833
  if (!(f === null || f === void 0 ? void 0 : f.field)) {
4540
4834
  this.closeFilterPopup();
4541
4835
  return;
4542
4836
  }
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
- }
4837
+ const normalized = normalizeDatetimeFilter(f);
4560
4838
  const next = new Map(this.activeFilters);
4561
- if (this.filterHasValue(normalized)) {
4839
+ if (filterHasValue(normalized)) {
4562
4840
  next.set(normalized.field, normalized);
4563
4841
  }
4564
4842
  else {
@@ -4613,140 +4891,53 @@ const MrdTable = class {
4613
4891
  toggleViewPopover(e) {
4614
4892
  e.stopPropagation();
4615
4893
  if (this.viewPopoverOpen) {
4616
- this.viewPopoverOpen = false;
4617
- if (this.viewPopoverClickHandler) {
4618
- document.removeEventListener('click', this.viewPopoverClickHandler);
4619
- this.viewPopoverClickHandler = null;
4620
- }
4894
+ this.closeViewPopover();
4621
4895
  return;
4622
4896
  }
4623
4897
  this.viewPopoverOpen = true;
4624
- this.viewPopoverClickHandler = () => {
4625
- this.viewPopoverOpen = false;
4898
+ this.viewPopoverClickHandler = () => this.closeViewPopover();
4899
+ document.addEventListener('click', this.viewPopoverClickHandler);
4900
+ }
4901
+ closeViewPopover() {
4902
+ this.viewPopoverOpen = false;
4903
+ if (this.viewPopoverClickHandler) {
4626
4904
  document.removeEventListener('click', this.viewPopoverClickHandler);
4627
4905
  this.viewPopoverClickHandler = null;
4628
- };
4629
- document.addEventListener('click', this.viewPopoverClickHandler);
4906
+ }
4630
4907
  }
4631
4908
  // ── Render: toolbar ────────────────────────────────────────────────────────
4632
4909
  renderToolbar() {
4633
4910
  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
- })))));
4911
+ return (h(Toolbar, { locale: this.locale, filterMode: this.filterMode, filterCount: this.activeFilters.size, actions: this.tableActions, views: this.allViews, activeViewIdx: this.activeViewIdx, viewPopoverOpen: this.viewPopoverOpen, createPickerOpen: this.createPickerOpen, createTypes: (_a = this.item) === null || _a === void 0 ? void 0 : _a.createTypes, cb: {
4912
+ onFilterToggle: () => this.handleFilterToggle(),
4913
+ onClearAllFilters: () => this.clearAllFilters(),
4914
+ onViewSwitch: idx => this.handleViewSwitch(idx),
4915
+ onToggleViewPopover: e => this.toggleViewPopover(e),
4916
+ onCloseViewPopover: () => this.closeViewPopover(),
4917
+ onToggleCreatePicker: () => this.toggleCreatePicker(),
4918
+ onCreate: basicType => {
4919
+ this.mrdAction.emit(this.buildActionDetail('create', basicType));
4920
+ this.closeCreatePicker();
4921
+ },
4922
+ onAction: action => this.mrdAction.emit(this.buildActionDetail(action)),
4923
+ } }));
4662
4924
  }
4663
4925
  // ── 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
4926
  renderFilterPopup() {
4741
- var _a;
4742
4927
  if (!this.openFilterCol || !this.pendingFilter)
4743
4928
  return null;
4744
4929
  const col = this.columns.find(c => this.colName(c) === this.openFilterCol);
4745
4930
  if (!col)
4746
4931
  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)))));
4932
+ return (h(FilterPopup, { col: col, dataType: this.colDataType(col), openFilterCol: this.openFilterCol, pendingFilter: this.pendingFilter, popupPos: this.popupPos, sortField: this.sortField, sortDir: this.sortDir, locale: this.locale, cb: {
4933
+ onSetPending: (key, val) => this.setPending(key, val),
4934
+ onReplacePending: pf => (this.pendingFilter = pf),
4935
+ onToggleValue: (key, checked) => this.togglePendingValue(key, checked),
4936
+ onApplySort: dir => this.applySort(col, dir),
4937
+ onApply: () => this.applyFilter(),
4938
+ onClear: () => this.clearFilter(),
4939
+ onClose: () => this.closeFilterPopup(),
4940
+ } }));
4750
4941
  }
4751
4942
  // ── Render: footer ────────────────────────────────────────────────────────
4752
4943
  renderFooter(rowCount, effectiveTotal, isTotalKnown = true) {
@@ -4771,54 +4962,11 @@ const MrdTable = class {
4771
4962
  }
4772
4963
  // ── Render: cell ──────────────────────────────────────────────────────────
4773
4964
  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));
4965
+ return (h(TableCell, { col: col, row: row, locale: this.locale, onDownload: detail => this.mrdDownload.emit(detail), onOpenTextblock: full => this.openTextblockModal(full), onOpenJson: html => this.openJsonModal(html) }));
4809
4966
  }
4810
4967
  // ── Render: totals row ────────────────────────────────────────────────────
4811
4968
  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
- }))));
4969
+ return h(TotalsRow, { columns: this.columns, aggregations: this.aggregations, locale: this.locale });
4822
4970
  }
4823
4971
  // ── Render ─────────────────────────────────────────────────────────────────
4824
4972
  render() {
@@ -4838,7 +4986,7 @@ const MrdTable = class {
4838
4986
  isFiltered ? 'mrd-table__header--filtered' : '',
4839
4987
  this.filterMode ? 'mrd-table__header--sortable' : '',
4840
4988
  ].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()));
4989
+ return (h("th", { class: cls, onClick: this.filterMode ? (e) => this.handleFilterOpen(col, e) : undefined }, h("span", { class: "mrd-table__header-label" }, (_a = col.label) !== null && _a !== void 0 ? _a : ''), isFiltered && h(FilterIcon, null)));
4842
4990
  }))), h("tbody", null, (_b = this.rows) === null || _b === void 0 ? void 0 : _b.map((row, i) => (h("tr", { class: "mrd-table__row mrd-table__row--clickable", style: { background: i % 2 === 0 ? '' : 'var(--mrd-color-neutral-100)' }, onClick: () => this.mrdRowClick.emit(row) }, this.columns.map(col => this.renderCell(col, row)))))), this.renderTotalsRow()), (!this.rows || this.rows.length === 0) && (h("p", { class: "mrd-table__empty" }, t('no_results', this.locale)))), this.renderFooter((_c = this.rows) === null || _c === void 0 ? void 0 : _c.length), this.renderFilterPopup(), this.renderTextblockModal(), this.renderJsonModal()));
4843
4991
  }
4844
4992
  // ── Paginated / virtual-scroll mode ────────────────────────────────────
@@ -4846,12 +4994,7 @@ const MrdTable = class {
4846
4994
  // if any loaded page is shorter than pageSize it is the last page,
4847
4995
  // so the true total cannot exceed (pageNum * pageSize + pageRows.length).
4848
4996
  // 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
- }
4997
+ const effectiveTotal = computeEffectiveTotal(this.loadedPages, this.pageSize, this.baseTotal);
4855
4998
  // Clamp renderEnd to what we actually know exists (-1 when empty)
4856
4999
  const clampedEnd = Math.min(this.renderEnd, effectiveTotal - 1);
4857
5000
  const colCount = this.columns.length;
@@ -4882,21 +5025,14 @@ const MrdTable = class {
4882
5025
  isActive ? `mrd-table__header--sorted-${this.sortDir}` : '',
4883
5026
  isFiltered ? 'mrd-table__header--filtered' : '',
4884
5027
  ].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" }))));
5028
+ return (h("th", { class: cls, style: this.colWidths[idx] ? { width: `${this.colWidths[idx]}px` } : undefined, onClick: isInteractive ? ((e) => this.filterMode ? this.handleFilterOpen(col, e) : this.handleSortClick(col)) : undefined }, h("span", { class: "mrd-table__header-label" }, (_a = col.label) !== null && _a !== void 0 ? _a : ''), isInteractive && isActive && (h("span", { class: "mrd-table__sort-icon", "aria-hidden": "true" }, this.sortDir === 'asc' ? '▲' : '▼')), isInteractive && !isActive && !this.filterMode && (h("span", { class: "mrd-table__sort-icon", "aria-hidden": "true" }, "\u21C5")), isInteractive && isFiltered && h(FilterIcon, null)));
5029
+ }))), h("tbody", null, topSpacerHeight > 0 && (h("tr", { class: "mrd-table__spacer", style: { height: `${topSpacerHeight}px` } }, h("td", { colSpan: colCount }))), renderedRows, bottomSpacerHeight > 0 && (h("tr", { class: "mrd-table__spacer", style: { height: `${bottomSpacerHeight}px` } }, h("td", { colSpan: colCount })))), this.renderTotalsRow())), effectiveTotal === 0 && this.loadedPages.has(0) && (h("p", { class: "mrd-table__empty" }, t('no_results', this.locale))), effectiveTotal > 0 && this.renderFooter(undefined, effectiveTotal, this.isTotalKnown()), this.renderFilterPopup(), this.renderTextblockModal(), this.renderJsonModal()));
4890
5030
  }
4891
5031
  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))));
5032
+ return h(TextblockModal, { text: this.textblockModal, locale: this.locale, onClose: () => this.closeTextblockModal() });
4895
5033
  }
4896
5034
  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 }))));
5035
+ return h(JsonModal, { html: this.jsonModal, locale: this.locale, onClose: () => this.closeJsonModal() });
4900
5036
  }
4901
5037
  get el() { return getElement(this); }
4902
5038
  static get watchers() { return {
@@ -4908,9 +5044,9 @@ const MrdTable = class {
4908
5044
  }]
4909
5045
  }; }
4910
5046
  };
4911
- MrdTable.style = mrdTableScss();
5047
+ MrdTable.style = mrdTableCss();
4912
5048
 
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)}`;
5049
+ const mrdTextFieldCss = () => `.sc-mrd-text-field-h{display:block}.mrd-text-field.sc-mrd-text-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-text-field__label.sc-mrd-text-field{display:block;font-family:var(--mrd-font-family);font-size:var(--mrd-label-font-size);font-weight:var(--mrd-label-font-weight);color:var(--mrd-label-color)}.mrd-text-field__label--required.sc-mrd-text-field::after{content:" *";color:var(--mrd-color-danger)}.mrd-text-field__input.sc-mrd-text-field{display:block;width:100%;height:var(--mrd-input-height);padding:var(--mrd-input-padding-y) var(--mrd-input-padding-x);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-input-color);background-color:var(--mrd-input-bg);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);transition:border-color var(--mrd-transition), box-shadow var(--mrd-transition);outline:none;appearance:none;box-sizing:border-box}.mrd-text-field__input.sc-mrd-text-field::placeholder{color:var(--mrd-input-placeholder-color)}.mrd-text-field__input.sc-mrd-text-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-text-field__input.sc-mrd-text-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.mrd-text-field__input--error.sc-mrd-text-field{border-color:var(--mrd-border-color-error)}.mrd-text-field__input--error.sc-mrd-text-field:focus{box-shadow:var(--mrd-shadow-focus-error)}.mrd-text-field__error.sc-mrd-text-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}`;
4914
5050
 
4915
5051
  const MrdTextField = class {
4916
5052
  constructor(hostRef) {
@@ -4931,23 +5067,17 @@ const MrdTextField = class {
4931
5067
  };
4932
5068
  this.handleBlur = (e) => {
4933
5069
  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
- }
5070
+ this.error = requiredError(val, this.required, this.locale);
4940
5071
  this.mrdBlur.emit({ name: this.name, value: val });
4941
5072
  };
4942
5073
  }
4943
5074
  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))));
5075
+ return (h(Host, { key: '71de1ae949941820574fc2d45cac6cca8264d8f9' }, h("div", { key: 'a63d3dd0811e012ae3d5a9f02c1a2ad1fcc0af86', class: "mrd-text-field" }, h(FieldLabel, { key: '1a6db878b634364f47522209344540a9cdc20635', base: "mrd-text-field", label: this.label, required: this.required }), h("input", { key: 'b3cd0338f13c5c2c8b744df62d3d02f3bc380aa1', class: controlClass('mrd-text-field', !!this.error), type: "text", name: this.name, value: this.value, placeholder: this.placeholder, required: this.required, disabled: this.disabled, onInput: this.handleInput, onBlur: this.handleBlur }), h(FieldError, { key: '1530066fefbda722df0c37871978995a139fcef0', base: "mrd-text-field", error: this.error }))));
4946
5076
  }
4947
5077
  };
4948
- MrdTextField.style = mrdTextFieldScss();
5078
+ MrdTextField.style = mrdTextFieldCss();
4949
5079
 
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)}`;
5080
+ const mrdTextareaFieldCss = () => `.sc-mrd-textarea-field-h{display:block}.mrd-textarea-field.sc-mrd-textarea-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-textarea-field__label.sc-mrd-textarea-field{display:block;font-family:var(--mrd-font-family);font-size:var(--mrd-label-font-size);font-weight:var(--mrd-label-font-weight);color:var(--mrd-label-color)}.mrd-textarea-field__label--required.sc-mrd-textarea-field::after{content:" *";color:var(--mrd-color-danger)}.mrd-textarea-field__error.sc-mrd-textarea-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}.mrd-textarea-field__container.sc-mrd-textarea-field{border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);overflow:hidden;background-color:var(--mrd-input-bg);transition:border-color var(--mrd-transition), box-shadow var(--mrd-transition)}.mrd-textarea-field__container.sc-mrd-textarea-field:focus-within{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-textarea-field__container--error.sc-mrd-textarea-field{border-color:var(--mrd-border-color-error)}.mrd-textarea-field__container--error.sc-mrd-textarea-field:focus-within{box-shadow:var(--mrd-shadow-focus-error)}.mrd-textarea-field__editor.sc-mrd-textarea-field{min-height:150px;font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base)}.mrd-textarea-field__editor.sc-mrd-textarea-field .ql-toolbar.sc-mrd-textarea-field{border:none;border-bottom:var(--mrd-border-width) solid var(--mrd-border-color);font-family:var(--mrd-font-family)}.mrd-textarea-field__editor.sc-mrd-textarea-field .ql-container.sc-mrd-textarea-field{border:none;font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base)}.mrd-textarea-field__editor.sc-mrd-textarea-field .ql-editor.sc-mrd-textarea-field{min-height:120px;padding:var(--mrd-input-padding-y) var(--mrd-input-padding-x)}.mrd-textarea-field__editor.sc-mrd-textarea-field .ql-editor.ql-blank.sc-mrd-textarea-field::before{color:var(--mrd-input-placeholder-color);font-style:normal}`;
4951
5081
 
4952
5082
  const MrdTextareaField = class {
4953
5083
  constructor(hostRef) {
@@ -5000,12 +5130,7 @@ const MrdTextareaField = class {
5000
5130
  var _a, _b;
5001
5131
  if (!range) {
5002
5132
  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
- }
5133
+ this.error = requiredError(html, this.required, this.locale);
5009
5134
  this.mrdBlur.emit({ name: this.name, value: html });
5010
5135
  }
5011
5136
  });
@@ -5016,13 +5141,13 @@ const MrdTextareaField = class {
5016
5141
  }
5017
5142
  }
5018
5143
  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))));
5144
+ return (h(Host, { key: '464c1edde8447043d9352f1b5f9757bba97e9b17' }, h("div", { key: '8d06728214f54feeb1063700e5aaf7c439eb5473', class: "mrd-textarea-field" }, h(FieldLabel, { key: 'dbf93ecf41bd704706b49f8c455262798fbbe10b', base: "mrd-textarea-field", label: this.label, required: this.required }), h("div", { key: '9c39ccfa38ee01b880973966e910ee32aa60b144', class: controlClass('mrd-textarea-field', !!this.error, 'container') }, h("div", { key: '0217cd4350c1933018b2b8f489516b6d43a52538', class: "mrd-textarea-field__editor" })), h(FieldError, { key: '62d2a5db053ea6e4ec6868440f3ab31e1c05e633', base: "mrd-textarea-field", error: this.error }))));
5020
5145
  }
5021
5146
  get el() { return getElement(this); }
5022
5147
  };
5023
- MrdTextareaField.style = mrdTextareaFieldScss();
5148
+ MrdTextareaField.style = mrdTextareaFieldCss();
5024
5149
 
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)}`;
5150
+ const mrdTimeFieldCss = () => `.sc-mrd-time-field-h{display:block}.mrd-time-field.sc-mrd-time-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-time-field__label.sc-mrd-time-field{display:block;font-family:var(--mrd-font-family);font-size:var(--mrd-label-font-size);font-weight:var(--mrd-label-font-weight);color:var(--mrd-label-color)}.mrd-time-field__label--required.sc-mrd-time-field::after{content:" *";color:var(--mrd-color-danger)}.mrd-time-field__input.sc-mrd-time-field{display:block;width:100%;height:var(--mrd-input-height);padding:var(--mrd-input-padding-y) var(--mrd-input-padding-x);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-input-color);background-color:var(--mrd-input-bg);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);transition:border-color var(--mrd-transition), box-shadow var(--mrd-transition);outline:none;appearance:none;box-sizing:border-box}.mrd-time-field__input.sc-mrd-time-field::placeholder{color:var(--mrd-input-placeholder-color)}.mrd-time-field__input.sc-mrd-time-field:focus{border-color:var(--mrd-border-color-focus);box-shadow:var(--mrd-shadow-focus)}.mrd-time-field__input.sc-mrd-time-field:disabled{background-color:var(--mrd-input-bg-disabled);cursor:not-allowed;opacity:0.7}.mrd-time-field__input--error.sc-mrd-time-field{border-color:var(--mrd-border-color-error)}.mrd-time-field__input--error.sc-mrd-time-field:focus{box-shadow:var(--mrd-shadow-focus-error)}.mrd-time-field__error.sc-mrd-time-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}.mrd-time-field__input.sc-mrd-time-field{cursor:pointer}`;
5026
5151
 
5027
5152
  const MrdTimeField = class {
5028
5153
  constructor(hostRef) {
@@ -5038,12 +5163,7 @@ const MrdTimeField = class {
5038
5163
  this.error = '';
5039
5164
  this.handleChange = (e) => {
5040
5165
  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
- }
5166
+ this.error = requiredError(val, this.required, this.locale);
5047
5167
  this.mrdChange.emit({ name: this.name, value: val });
5048
5168
  };
5049
5169
  this.handleBlur = (e) => {
@@ -5052,10 +5172,9 @@ const MrdTimeField = class {
5052
5172
  };
5053
5173
  }
5054
5174
  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))));
5175
+ return (h(Host, { key: 'fc30bdeb7c8d37bebc67a768f48013602879fb3d' }, h("div", { key: '52f899a889376773c1948f0c116670684db25cf4', class: "mrd-time-field" }, h(FieldLabel, { key: '3aba58f122fa4bb9f0ba4ad0b56fc3b29f03d4a3', base: "mrd-time-field", label: this.label, required: this.required }), h("input", { key: 'e39718394a195eafaf47aa2e62d560341bb0daed', class: controlClass('mrd-time-field', !!this.error), type: "time", name: this.name, value: this.value, required: this.required, disabled: this.disabled, onChange: this.handleChange, onBlur: this.handleBlur }), h(FieldError, { key: '07ad4ccbc5188e129d8bd3085e856839ec6a81c9', base: "mrd-time-field", error: this.error }))));
5057
5176
  }
5058
5177
  };
5059
- MrdTimeField.style = mrdTimeFieldScss();
5178
+ MrdTimeField.style = mrdTimeFieldCss();
5060
5179
 
5061
5180
  export { MrdBooleanField as mrd_boolean_field, MrdCurrencyField as mrd_currency_field, MrdDateField as mrd_date_field, MrdDatetimeField as mrd_datetime_field, MrdDocumentContainer as mrd_document_container, MrdDocumentList as mrd_document_list, MrdDocumentView as mrd_document_view, MrdEmailField as mrd_email_field, MrdField as mrd_field, MrdFileField as mrd_file_field, MrdForm as mrd_form, MrdHyperlinkField as mrd_hyperlink_field, MrdImageField as mrd_image_field, MrdLayoutSection as mrd_layout_section, MrdListField as mrd_list_field, MrdLongtextField as mrd_longtext_field, MrdNumberField as mrd_number_field, MrdRelationField as mrd_relation_field, MrdSecretField as mrd_secret_field, MrdTable as mrd_table, MrdTextField as mrd_text_field, MrdTextareaField as mrd_textarea_field, MrdTimeField as mrd_time_field };