@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,9 +1,9 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-BPj2cBXs.js');
3
+ var index = require('./index-CAzwGt9u.js');
4
4
  var index$1 = require('./index.cjs.js');
5
5
 
6
- 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)}`;
6
+ 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)}`;
7
7
 
8
8
  const MrdBooleanField = class {
9
9
  constructor(hostRef) {
@@ -29,10 +29,83 @@ const MrdBooleanField = class {
29
29
  this.checked = !!this.value;
30
30
  }
31
31
  render() {
32
- return (index.h(index.Host, { key: '38e65a1c7971912f8259d09281b272d7cbd446f2' }, index.h("div", { key: 'e10919998731d744cc2a13130c5f355c9b8fc9aa', class: "mrd-boolean-field" }, index.h("label", { key: 'db85a2c80cc62fdfd25237e3f5c7750bf1666819', class: "mrd-boolean-field__toggle-label" }, index.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 }), index.h("span", { key: 'f90f0ed6d74d6688e51b8d85a5397a0597d95ad8', class: "mrd-boolean-field__toggle", "aria-hidden": "true" }), this.label && (index.h("span", { key: '7e4582b1d9a5b08c00c220bec53baa6c14cbfe43', class: `mrd-boolean-field__text${this.required ? ' mrd-boolean-field__text--required' : ''}` }, this.label))))));
32
+ return (index.h(index.Host, { key: 'f7851813646d31c565c262bf3c8d4083177dd993' }, index.h("div", { key: '4b3c9f46e8b79bdc97ef5815afb85ba5ddde0c9a', class: "mrd-boolean-field" }, index.h("label", { key: 'f81fa28d5a79de0445c2c192352343f0807609a1', class: "mrd-boolean-field__toggle-label" }, index.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 }), index.h("span", { key: '949e042c8af0f2872cf973a0d5407fce972eb240', class: "mrd-boolean-field__toggle", "aria-hidden": "true" }), this.label && (index.h("span", { key: 'e8c52b5820887b2a8ec9a20eb7e4116a528d27d4', class: `mrd-boolean-field__text${this.required ? ' mrd-boolean-field__text--required' : ''}` }, this.label))))));
33
33
  }
34
34
  };
35
- MrdBooleanField.style = mrdBooleanFieldScss();
35
+ MrdBooleanField.style = mrdBooleanFieldCss();
36
+
37
+ function formatNumber(value, locale, options) {
38
+ if (value === null || value === undefined || isNaN(value))
39
+ return '';
40
+ return new Intl.NumberFormat(locale, options).format(value);
41
+ }
42
+ function formatCurrency(amount, currency, locale) {
43
+ if (amount === null || amount === undefined || isNaN(amount))
44
+ return '';
45
+ return new Intl.NumberFormat(locale, {
46
+ style: 'currency',
47
+ currency,
48
+ minimumFractionDigits: 2,
49
+ maximumFractionDigits: 2,
50
+ }).format(amount);
51
+ }
52
+ function formatPercentage(value, locale, decimalPrecision = 2) {
53
+ if (value === null || value === undefined || isNaN(value))
54
+ return '';
55
+ return new Intl.NumberFormat(locale, {
56
+ style: 'percent',
57
+ minimumFractionDigits: decimalPrecision,
58
+ maximumFractionDigits: decimalPrecision,
59
+ }).format(value);
60
+ }
61
+ function formatDate(value, locale) {
62
+ if (!value)
63
+ return '';
64
+ const date = typeof value === 'string' ? new Date(value) : value;
65
+ if (isNaN(date.getTime()))
66
+ return '';
67
+ return new Intl.DateTimeFormat(locale, { year: 'numeric', month: '2-digit', day: '2-digit' }).format(date);
68
+ }
69
+ function formatDateTime(value, locale) {
70
+ if (!value)
71
+ return '';
72
+ const date = typeof value === 'string' ? new Date(value) : value;
73
+ if (isNaN(date.getTime()))
74
+ return '';
75
+ return new Intl.DateTimeFormat(locale, {
76
+ year: 'numeric',
77
+ month: '2-digit',
78
+ day: '2-digit',
79
+ hour: '2-digit',
80
+ minute: '2-digit',
81
+ }).format(date);
82
+ }
83
+ function formatTime(value, locale) {
84
+ if (!value)
85
+ return '';
86
+ // value is HH:MM or HH:MM:SS
87
+ const [hours, minutes] = value.split(':').map(Number);
88
+ const date = new Date();
89
+ date.setHours(hours, minutes, 0, 0);
90
+ return new Intl.DateTimeFormat(locale, { hour: '2-digit', minute: '2-digit' }).format(date);
91
+ }
92
+ function parseLocalizedNumber(str, locale) {
93
+ var _a, _b, _c, _d;
94
+ if (!str || !str.trim())
95
+ return null;
96
+ // Detect decimal and thousands separators from the locale
97
+ const parts = new Intl.NumberFormat(locale).formatToParts(1234567.89);
98
+ const groupSep = (_b = (_a = parts.find((p) => p.type === 'group')) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : ',';
99
+ const decimalSep = (_d = (_c = parts.find((p) => p.type === 'decimal')) === null || _c === void 0 ? void 0 : _c.value) !== null && _d !== void 0 ? _d : '.';
100
+ // Remove group separators, replace decimal separator with '.'
101
+ const normalized = str
102
+ .replace(new RegExp(`\\${groupSep}`, 'g'), '')
103
+ .replace(new RegExp(`\\${decimalSep}`), '.')
104
+ .replace('%', '')
105
+ .trim();
106
+ const parsed = parseFloat(normalized);
107
+ return isNaN(parsed) ? null : parsed;
108
+ }
36
109
 
37
110
  const translations = {
38
111
  nl: {
@@ -49,6 +122,7 @@ const translations = {
49
122
  drop_file_here: 'Sleep bestand hierheen of',
50
123
  browse: 'bladeren',
51
124
  file_too_large: 'Bestand is te groot',
125
+ invalid_image: 'Selecteer een afbeeldingsbestand',
52
126
  search_results: 'Zoekresultaten',
53
127
  no_results: 'Geen resultaten gevonden',
54
128
  loading: 'Laden...',
@@ -121,6 +195,7 @@ const translations = {
121
195
  drop_file_here: 'Drop file here or',
122
196
  browse: 'browse',
123
197
  file_too_large: 'File is too large',
198
+ invalid_image: 'Please select an image file',
124
199
  search_results: 'Search results',
125
200
  no_results: 'No results found',
126
201
  loading: 'Loading...',
@@ -193,6 +268,7 @@ const translations = {
193
268
  drop_file_here: 'اسحب الملف هنا أو',
194
269
  browse: 'تصفح',
195
270
  file_too_large: 'الملف كبير جداً',
271
+ invalid_image: 'يرجى اختيار ملف صورة',
196
272
  search_results: 'نتائج البحث',
197
273
  no_results: 'لم يتم العثور على نتائج',
198
274
  loading: 'جار التحميل...',
@@ -259,6 +335,7 @@ const translations = {
259
335
  drop_file_here: 'Déposez le fichier ici ou',
260
336
  browse: 'parcourir',
261
337
  file_too_large: 'Le fichier est trop volumineux',
338
+ invalid_image: 'Veuillez sélectionner un fichier image',
262
339
  search_results: 'Résultats de recherche',
263
340
  no_results: 'Aucun résultat trouvé',
264
341
  loading: 'Chargement...',
@@ -325,6 +402,7 @@ const translations = {
325
402
  drop_file_here: 'Datei hier ablegen oder',
326
403
  browse: 'durchsuchen',
327
404
  file_too_large: 'Datei ist zu groß',
405
+ invalid_image: 'Bitte eine Bilddatei auswählen',
328
406
  search_results: 'Suchergebnisse',
329
407
  no_results: 'Keine Ergebnisse gefunden',
330
408
  loading: 'Laden...',
@@ -391,6 +469,7 @@ const translations = {
391
469
  drop_file_here: 'Suelte el archivo aquí o',
392
470
  browse: 'explorar',
393
471
  file_too_large: 'El archivo es demasiado grande',
472
+ invalid_image: 'Seleccione un archivo de imagen',
394
473
  search_results: 'Resultados de búsqueda',
395
474
  no_results: 'No se encontraron resultados',
396
475
  loading: 'Cargando...',
@@ -457,6 +536,7 @@ const translations = {
457
536
  drop_file_here: 'Trascina il file qui o',
458
537
  browse: 'sfoglia',
459
538
  file_too_large: 'Il file è troppo grande',
539
+ invalid_image: 'Seleziona un file immagine',
460
540
  search_results: 'Risultati della ricerca',
461
541
  no_results: 'Nessun risultato trovato',
462
542
  loading: 'Caricamento...',
@@ -523,6 +603,7 @@ const translations = {
523
603
  drop_file_here: 'Перетягніть файл сюди або',
524
604
  browse: 'огляд',
525
605
  file_too_large: 'Файл занадто великий',
606
+ invalid_image: 'Будь ласка, виберіть файл зображення',
526
607
  search_results: 'Результати пошуку',
527
608
  no_results: 'Результатів не знайдено',
528
609
  loading: 'Завантаження...',
@@ -633,80 +714,22 @@ function validateNumber(value, dataType) {
633
714
  return true;
634
715
  }
635
716
 
636
- function formatNumber(value, locale, options) {
637
- if (value === null || value === undefined || isNaN(value))
638
- return '';
639
- return new Intl.NumberFormat(locale, options).format(value);
640
- }
641
- function formatCurrency(amount, currency, locale) {
642
- if (amount === null || amount === undefined || isNaN(amount))
643
- return '';
644
- return new Intl.NumberFormat(locale, {
645
- style: 'currency',
646
- currency,
647
- minimumFractionDigits: 2,
648
- maximumFractionDigits: 2,
649
- }).format(amount);
650
- }
651
- function formatPercentage(value, locale, decimalPrecision = 2) {
652
- if (value === null || value === undefined || isNaN(value))
653
- return '';
654
- return new Intl.NumberFormat(locale, {
655
- style: 'percent',
656
- minimumFractionDigits: decimalPrecision,
657
- maximumFractionDigits: decimalPrecision,
658
- }).format(value);
717
+ /**
718
+ * Shared building blocks for the leaf field components.
719
+ * `base` is the BEM block name, e.g. 'mrd-text-field'.
720
+ */
721
+ const FieldLabel = ({ base, label, required }) => label ? index.h("label", { class: `${base}__label${required ? ` ${base}__label--required` : ''}` }, label) : null;
722
+ const FieldError = ({ base, error }) => error ? index.h("span", { class: `${base}__error` }, error) : null;
723
+ /** Class string for the form control, with the --error modifier when applicable. */
724
+ function controlClass(base, hasError, element = 'input') {
725
+ return `${base}__${element}${hasError ? ` ${base}__${element}--error` : ''}`;
659
726
  }
660
- function formatDate(value, locale) {
661
- if (!value)
662
- return '';
663
- const date = typeof value === 'string' ? new Date(value) : value;
664
- if (isNaN(date.getTime()))
665
- return '';
666
- return new Intl.DateTimeFormat(locale, { year: 'numeric', month: '2-digit', day: '2-digit' }).format(date);
667
- }
668
- function formatDateTime(value, locale) {
669
- if (!value)
670
- return '';
671
- const date = typeof value === 'string' ? new Date(value) : value;
672
- if (isNaN(date.getTime()))
673
- return '';
674
- return new Intl.DateTimeFormat(locale, {
675
- year: 'numeric',
676
- month: '2-digit',
677
- day: '2-digit',
678
- hour: '2-digit',
679
- minute: '2-digit',
680
- }).format(date);
681
- }
682
- function formatTime(value, locale) {
683
- if (!value)
684
- return '';
685
- // value is HH:MM or HH:MM:SS
686
- const [hours, minutes] = value.split(':').map(Number);
687
- const date = new Date();
688
- date.setHours(hours, minutes, 0, 0);
689
- return new Intl.DateTimeFormat(locale, { hour: '2-digit', minute: '2-digit' }).format(date);
690
- }
691
- function parseLocalizedNumber(str, locale) {
692
- var _a, _b, _c, _d;
693
- if (!str || !str.trim())
694
- return null;
695
- // Detect decimal and thousands separators from the locale
696
- const parts = new Intl.NumberFormat(locale).formatToParts(1234567.89);
697
- const groupSep = (_b = (_a = parts.find((p) => p.type === 'group')) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : ',';
698
- const decimalSep = (_d = (_c = parts.find((p) => p.type === 'decimal')) === null || _c === void 0 ? void 0 : _c.value) !== null && _d !== void 0 ? _d : '.';
699
- // Remove group separators, replace decimal separator with '.'
700
- const normalized = str
701
- .replace(new RegExp(`\\${groupSep}`, 'g'), '')
702
- .replace(new RegExp(`\\${decimalSep}`), '.')
703
- .replace('%', '')
704
- .trim();
705
- const parsed = parseFloat(normalized);
706
- return isNaN(parsed) ? null : parsed;
727
+ /** Returns the localised required-error, or '' when the value passes. */
728
+ function requiredError(value, required, locale) {
729
+ return required && !validateRequired(value) ? t('required', locale) : '';
707
730
  }
708
731
 
709
- 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)}`;
732
+ 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)}`;
710
733
 
711
734
  const COMMON_CURRENCIES = [
712
735
  'EUR', 'USD', 'GBP', 'CHF', 'JPY', 'CNY', 'AUD', 'CAD',
@@ -733,12 +756,7 @@ const MrdCurrencyField = class {
733
756
  this.handleAmountBlur = (e) => {
734
757
  const raw = e.target.value;
735
758
  const parsed = parseLocalizedNumber(raw, this.locale);
736
- if (this.required && !validateRequired(raw)) {
737
- this.error = t('required', this.locale);
738
- }
739
- else {
740
- this.error = '';
741
- }
759
+ this.error = requiredError(raw, this.required, this.locale);
742
760
  const val = { amount: parsed, currency: this.currency };
743
761
  this.mrdChange.emit({ name: this.name, value: val });
744
762
  this.mrdBlur.emit({ name: this.name, value: val });
@@ -757,12 +775,12 @@ const MrdCurrencyField = class {
757
775
  }
758
776
  render() {
759
777
  const hasError = !!this.error;
760
- return (index.h(index.Host, { key: 'fe3520c44d831caf36b388cb5968a9518b16cb8b' }, index.h("div", { key: '50c1fd2d53038e46da575d3e46e1ec26c2da423b', class: "mrd-currency-field" }, this.label && (index.h("label", { key: 'a2649d41bf6e3765c8a62ba6559c64c41615027a', class: `mrd-currency-field__label${this.required ? ' mrd-currency-field__label--required' : ''}` }, this.label)), index.h("div", { key: '952b51f315b4a5c05a8373ce3a3f1041086ba8b8', class: "mrd-currency-field__row" }, index.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 }), index.h("select", { key: '1755854ca9b76dc4b41ad84b6b788685931ace36', class: "mrd-currency-field__currency", disabled: this.disabled, onChange: this.handleCurrencyChange }, COMMON_CURRENCIES.map(c => (index.h("option", { key: c, value: c, selected: c === this.currency }, c))))), hasError && index.h("span", { key: '0f10eb98c2e6444651d79d1de92acd0dbcc7133b', class: "mrd-currency-field__error" }, this.error))));
778
+ return (index.h(index.Host, { key: '24c530db6e0420af39fa0a35b31e966286f2d00c' }, index.h("div", { key: '795bc336425fbf1b86828f4a8f5df93930169a3c', class: "mrd-currency-field" }, index.h(FieldLabel, { key: 'b302cd9296c29ed5719b1f768bd5d4eea86f6406', base: "mrd-currency-field", label: this.label, required: this.required }), index.h("div", { key: '7efca51615f405ffd660e120accae32f55a9b5a0', class: "mrd-currency-field__row" }, index.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 }), index.h("select", { key: '83ad5e92b623c3c60d161b8828e780adb476682c', class: "mrd-currency-field__currency", disabled: this.disabled, onChange: this.handleCurrencyChange }, COMMON_CURRENCIES.map(c => (index.h("option", { key: c, value: c, selected: c === this.currency }, c))))), index.h(FieldError, { key: 'b059290bb566b119c4f192e750b3e365446243e6', base: "mrd-currency-field", error: this.error }))));
761
779
  }
762
780
  };
763
- MrdCurrencyField.style = mrdCurrencyFieldScss();
781
+ MrdCurrencyField.style = mrdCurrencyFieldCss();
764
782
 
765
- 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)}`;
783
+ 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}`;
766
784
 
767
785
  const MrdDateField = class {
768
786
  constructor(hostRef) {
@@ -778,12 +796,7 @@ const MrdDateField = class {
778
796
  this.error = '';
779
797
  this.handleChange = (e) => {
780
798
  const val = e.target.value;
781
- if (this.required && !validateRequired(val)) {
782
- this.error = t('required', this.locale);
783
- }
784
- else {
785
- this.error = '';
786
- }
799
+ this.error = requiredError(val, this.required, this.locale);
787
800
  this.mrdChange.emit({ name: this.name, value: val });
788
801
  };
789
802
  this.handleBlur = (e) => {
@@ -792,13 +805,12 @@ const MrdDateField = class {
792
805
  };
793
806
  }
794
807
  render() {
795
- const hasError = !!this.error;
796
- return (index.h(index.Host, { key: '2c0dc2311068a5c759fe8efe58a98a71a9cf4b7b' }, index.h("div", { key: 'ee1cc0e9a2943cc42439825b8f21cd3492eaca05', class: "mrd-date-field" }, this.label && (index.h("label", { key: '3f836a991e676b6070a8b3800edfce00cc0d3b3d', class: `mrd-date-field__label${this.required ? ' mrd-date-field__label--required' : ''}` }, this.label)), index.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 && index.h("span", { key: '480ec99200989f3dc543d9afc648d83d31992b3c', class: "mrd-date-field__error" }, this.error))));
808
+ return (index.h(index.Host, { key: '71be9e4bcc87b40cf3b777d3fe0bff23c1a0fa94' }, index.h("div", { key: '40ced03df5d4185264ba9d03c832b3870ce8ae19', class: "mrd-date-field" }, index.h(FieldLabel, { key: 'd85ec7c4617a22c8c5862253e8090c85484f8c41', base: "mrd-date-field", label: this.label, required: this.required }), index.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 }), index.h(FieldError, { key: '9dd64475bf8a77bea5344faa71f20485b34b86f9', base: "mrd-date-field", error: this.error }))));
797
809
  }
798
810
  };
799
- MrdDateField.style = mrdDateFieldScss();
811
+ MrdDateField.style = mrdDateFieldCss();
800
812
 
801
- 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)}`;
813
+ 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}`;
802
814
 
803
815
  const MrdDatetimeField = class {
804
816
  constructor(hostRef) {
@@ -816,12 +828,7 @@ const MrdDatetimeField = class {
816
828
  this.handleChange = (e) => {
817
829
  const localVal = e.target.value;
818
830
  this.localValue = localVal;
819
- if (this.required && !validateRequired(localVal)) {
820
- this.error = t('required', this.locale);
821
- }
822
- else {
823
- this.error = '';
824
- }
831
+ this.error = requiredError(localVal, this.required, this.locale);
825
832
  this.mrdChange.emit({ name: this.name, value: this.localToUtc(localVal) });
826
833
  };
827
834
  this.handleBlur = (e) => {
@@ -855,8 +862,7 @@ const MrdDatetimeField = class {
855
862
  return d.toISOString().replace(/\.\d{3}Z$/, 'Z');
856
863
  }
857
864
  render() {
858
- const hasError = !!this.error;
859
- return (index.h(index.Host, { key: 'ea8b3b68100ffdb316bc5048f82d85d238bb2e4b' }, index.h("div", { key: 'c192c6998ee474aaf4df7b3b97ae0bd61f6d624d', class: "mrd-datetime-field" }, this.label && (index.h("label", { key: '1fbd66c17d76508f0d698a2c258be6779e98d85e', class: `mrd-datetime-field__label${this.required ? ' mrd-datetime-field__label--required' : ''}` }, this.label)), index.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 && index.h("span", { key: '8788ac01739302f6ad61010b238ff38d45e1b68a', class: "mrd-datetime-field__error" }, this.error))));
865
+ return (index.h(index.Host, { key: 'ac07ec2ba79cde998d1247e9d71de336c0e72a64' }, index.h("div", { key: '8144cf68c4b6b9cbc8396903b84bb355f380ceda', class: "mrd-datetime-field" }, index.h(FieldLabel, { key: '972686469f68c932e33b8d2c3806422553a3cce3', base: "mrd-datetime-field", label: this.label, required: this.required }), index.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 }), index.h(FieldError, { key: 'b7a812f82a6b0d2c938aa1f1c2494df685258555', base: "mrd-datetime-field", error: this.error }))));
860
866
  }
861
867
  static get watchers() { return {
862
868
  "value": [{
@@ -864,9 +870,9 @@ const MrdDatetimeField = class {
864
870
  }]
865
871
  }; }
866
872
  };
867
- MrdDatetimeField.style = mrdDatetimeFieldScss();
873
+ MrdDatetimeField.style = mrdDatetimeFieldCss();
868
874
 
869
- 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}`;
875
+ 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}`;
870
876
 
871
877
  const MrdDocumentContainer = class {
872
878
  constructor(hostRef) {
@@ -898,8 +904,8 @@ const MrdDocumentContainer = class {
898
904
  /** Whether the currently mounted table has been init()'d. Reset on every mode switch. */
899
905
  this.tableInited = false;
900
906
  this.createFolder = () => {
901
- var _a, _b;
902
- (_b = (_a = this.listEl) === null || _a === void 0 ? void 0 : _a.createFolder) === null || _b === void 0 ? void 0 : _b.call(_a);
907
+ var _a;
908
+ (_a = this.listEl) === null || _a === void 0 ? void 0 : _a.createFolder();
903
909
  };
904
910
  }
905
911
  /** The embedded table does not self-load: like every mrd-table it waits for the
@@ -911,7 +917,7 @@ const MrdDocumentContainer = class {
911
917
  if (this.mode === 'list' && this.tableEl && !this.tableInited) {
912
918
  this.tableInited = true;
913
919
  const table = this.tableEl;
914
- 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); });
920
+ Promise.resolve((_a = table.componentOnReady) === null || _a === void 0 ? void 0 : _a.call(table)).then(() => table.init());
915
921
  }
916
922
  }
917
923
  setMode(mode) {
@@ -971,13 +977,240 @@ const MrdDocumentContainer = class {
971
977
  }
972
978
  render() {
973
979
  const treeMode = this.mode === 'tree';
974
- return (index.h(index.Host, { key: '5d8a9a9bb4f1126a304b796aff9d1cb0100b8fc6' }, this.renderToolbar(), index.h("div", { key: '80ac7e5dd39ffcc4161059447221045a6e035099', class: "mrd-document-container__body", style: treeMode ? { height: `${this.height}px`, overflowY: 'auto' } : {} }, treeMode ? this.renderTree() : this.renderList())));
980
+ return (index.h(index.Host, { key: '018c9eacd169fdf7d352a51472651348af2b45df' }, this.renderToolbar(), index.h("div", { key: '5ff2ac77d4d12369905696ff075f99785dc1c809', class: "mrd-document-container__body", style: treeMode ? { height: `${this.height}px`, overflowY: 'auto' } : {} }, treeMode ? this.renderTree() : this.renderList())));
975
981
  }
976
982
  get el() { return index.getElement(this); }
977
983
  };
978
- MrdDocumentContainer.style = mrdDocumentContainerScss();
984
+ MrdDocumentContainer.style = mrdDocumentContainerCss();
985
+
986
+ /**
987
+ * Shared path/query-param conventions for list requests,
988
+ * used by mrd-table and mrd-document-list.
989
+ */
990
+ /** Applies the view-level static filters to `params` using the API operator conventions. */
991
+ function applyViewFilters(params, filters) {
992
+ var _a, _b, _c;
993
+ for (const f of filters !== null && filters !== void 0 ? filters : []) {
994
+ if (!f.name)
995
+ continue;
996
+ if (f.operator === 'EMPTY') {
997
+ params.set(f.name, '');
998
+ continue;
999
+ }
1000
+ if (f.operator === 'NOT_EMPTY') {
1001
+ params.set(f.name + '_notempty', 'true');
1002
+ continue;
1003
+ }
1004
+ if (f.operator === 'STARTS_WITH') {
1005
+ params.set(f.name + '_startswith', String((_a = f.value) !== null && _a !== void 0 ? _a : ''));
1006
+ continue;
1007
+ }
1008
+ if (f.operator === 'FROM') {
1009
+ params.set(f.name + '_from', String((_b = f.value) !== null && _b !== void 0 ? _b : ''));
1010
+ continue;
1011
+ }
1012
+ if (f.operator === 'TO') {
1013
+ params.set(f.name + '_to', String((_c = f.value) !== null && _c !== void 0 ? _c : ''));
1014
+ continue;
1015
+ }
1016
+ if (f.value != null) {
1017
+ params.set(f.name, String(f.value));
1018
+ }
1019
+ }
1020
+ }
1021
+ /** VIEW: `/{dataClass}`; RELATED_VIEW: `/{fromClass}/{parentId}/{dataClass}`. */
1022
+ function buildListPath(opts) {
1023
+ var _a, _b, _c;
1024
+ if (opts.isRelatedView) {
1025
+ return `/${(_a = opts.fromClass) !== null && _a !== void 0 ? _a : ''}/${opts.parentId}/${(_b = opts.dataClass) !== null && _b !== void 0 ? _b : ''}`;
1026
+ }
1027
+ return `/${(_c = opts.dataClass) !== null && _c !== void 0 ? _c : ''}`;
1028
+ }
1029
+
1030
+ /**
1031
+ * Tree model and pure tree logic for mrd-document-list.
1032
+ * Nodes are mutated in place; the component triggers re-renders via bump().
1033
+ */
1034
+ /** Normalise a folder path: null/""/"/" → root ([]); else split on "/" dropping empties. */
1035
+ function splitFolder(path) {
1036
+ if (path == null)
1037
+ return [];
1038
+ const s = String(path).trim();
1039
+ if (s === '' || s === '/')
1040
+ return [];
1041
+ return s.split('/').map(x => x.trim()).filter(Boolean);
1042
+ }
1043
+ function makeContainerNode(href, label, count) {
1044
+ return {
1045
+ id: 'c:' + href, kind: 'container', label, href,
1046
+ hasDocs: false, docCount: 0, totalCount: count, children: [],
1047
+ open: false, loading: false, foldersLoaded: false, docsLoaded: false, docs: [],
1048
+ };
1049
+ }
1050
+ function makeFolderNode(id, label, containerId) {
1051
+ return {
1052
+ id, kind: 'folder', label, containerId,
1053
+ hasDocs: false, docCount: 0, totalCount: 0, children: [],
1054
+ open: false, loading: false, foldersLoaded: false, docsLoaded: false, docs: [],
1055
+ };
1056
+ }
1057
+ /** Recompute totalCount over the subtree; returns the node's aggregate. */
1058
+ function computeTotals(node) {
1059
+ let total = node.docCount;
1060
+ for (const c of node.children)
1061
+ total += computeTotals(c);
1062
+ node.totalCount = total;
1063
+ return total;
1064
+ }
1065
+ /** Folder path segments of a node relative to its container (derived from its id). */
1066
+ function segmentsOf(node, container) {
1067
+ if (node.kind === 'container')
1068
+ return [];
1069
+ const prefix = container.id + '/';
1070
+ const rest = node.id.startsWith(prefix) ? node.id.slice(prefix.length) : '';
1071
+ return rest ? rest.split('/') : [];
1072
+ }
1073
+ /** Folder string a node represents: the raw distinct value when it holds
1074
+ * documents, else derived from its path segments; null for a container root. */
1075
+ function folderStringOf(node, container) {
1076
+ if (node.kind === 'container')
1077
+ return null;
1078
+ if (node.fullPath != null && node.fullPath !== '')
1079
+ return node.fullPath;
1080
+ const segs = segmentsOf(node, container);
1081
+ return segs.length ? '/' + segs.join('/') : null;
1082
+ }
1083
+ /** Strip a single trailing extension for the document title. */
1084
+ function stripExtension(name) {
1085
+ return name.replace(/\.[^./\\]+$/, '');
1086
+ }
1087
+ /** Rebuild a container's folder subtree from the /distinct folder strings.
1088
+ * New nodes are registered in `nodeIndex`; the container is mutated in place. */
1089
+ function applyFolderDistinct(container, values, nodeIndex) {
1090
+ container.children = [];
1091
+ container.hasDocs = false;
1092
+ container.docCount = 0;
1093
+ for (const v of values) {
1094
+ const raw = typeof v.value === 'string' ? v.value : v.value == null ? '' : String(v.value);
1095
+ const segs = splitFolder(raw);
1096
+ if (segs.length === 0) {
1097
+ // Root documents — the container's own direct documents.
1098
+ container.hasDocs = true;
1099
+ container.docCount = v.count;
1100
+ container.fullPath = raw;
1101
+ continue;
1102
+ }
1103
+ let node = container;
1104
+ const acc = [];
1105
+ for (const seg of segs) {
1106
+ acc.push(seg);
1107
+ let child = node.children.find(c => c.label === seg);
1108
+ if (!child) {
1109
+ child = makeFolderNode(container.id + '/' + acc.join('/'), seg, container.id);
1110
+ node.children.push(child);
1111
+ nodeIndex.set(child.id, child);
1112
+ }
1113
+ node = child;
1114
+ }
1115
+ node.hasDocs = true;
1116
+ node.docCount = v.count;
1117
+ node.fullPath = raw;
1118
+ }
1119
+ computeTotals(container);
1120
+ container.foldersLoaded = true;
1121
+ container.loading = false;
1122
+ }
1123
+ /** Optimistic in-place tree update for a document moved between folders. */
1124
+ function applyDocMove(doc, fromNode, toNode, targetFolder) {
1125
+ fromNode.docs = fromNode.docs.filter(d => d !== doc);
1126
+ fromNode.docCount = Math.max(0, fromNode.docCount - 1);
1127
+ // A now-empty folder should stop showing an expand chevron (it disappears on
1128
+ // the next reload anyway, since it is derived from document folder strings).
1129
+ if (fromNode.docsLoaded)
1130
+ fromNode.hasDocs = fromNode.docs.length > 0;
1131
+ toNode.hasDocs = true;
1132
+ toNode.pending = false; // a pending folder is now materialised
1133
+ toNode.docCount += 1;
1134
+ if (toNode.kind === 'folder')
1135
+ toNode.fullPath = targetFolder !== null && targetFolder !== void 0 ? targetFolder : '';
1136
+ if (toNode.docsLoaded)
1137
+ toNode.docs = [...toNode.docs, doc];
1138
+ }
1139
+
1140
+ function chevron(open, leaf) {
1141
+ return (index.h("span", { class: `mrd-document-list__chev${leaf ? ' mrd-document-list__chev--leaf' : ''}${open ? ' mrd-document-list__chev--open' : ''}` }, index.h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, index.h("path", { d: "M9 6l6 6-6 6" }))));
1142
+ }
1143
+ function dossierIcon() {
1144
+ return (index.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" }, index.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" })));
1145
+ }
1146
+ function folderIcon() {
1147
+ return (index.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" }, index.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" })));
1148
+ }
1149
+ function docIcon() {
1150
+ return (index.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" }, index.h("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }), index.h("path", { d: "M14 2v6h6" })));
1151
+ }
1152
+ function indent(depth) {
1153
+ return index.h("span", { class: "mrd-document-list__indent", style: { width: `${depth * 18}px` } });
1154
+ }
1155
+ function renderLoadingRow(ctx, depth) {
1156
+ return (index.h("div", { class: "mrd-document-list__loading", key: "loading" }, indent(depth), index.h("span", { class: "mrd-document-list__spinner" }), t('loading', ctx.locale)));
1157
+ }
1158
+ function renderUploadingRow(ctx, depth) {
1159
+ return (index.h("div", { class: "mrd-document-list__loading", key: "uploading" }, indent(depth), index.h("span", { class: "mrd-document-list__spinner" }), t('upload_file', ctx.locale)));
1160
+ }
1161
+ function renderDocRow(ctx, doc, node, container, depth) {
1162
+ var _a, _b, _c, _d, _e;
1163
+ 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 : '';
1164
+ const dateRaw = ctx.dateField ? doc === null || doc === void 0 ? void 0 : doc[ctx.dateField] : undefined;
1165
+ const date = dateRaw ? formatDate(dateRaw, ctx.locale) : '';
1166
+ return (index.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(), index.h("span", { class: "mrd-document-list__label" }, label), date && index.h("span", { class: "mrd-document-list__date" }, date)));
1167
+ }
1168
+ function renderFolderEditRow(ctx, node, depth) {
1169
+ return (index.h("div", { class: "mrd-document-list__node", key: node.id }, index.h("div", { class: "mrd-document-list__row mrd-document-list__row--edit" }, indent(depth), chevron(false, true), folderIcon(), index.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 && (index.h("div", { class: "mrd-document-list__error", style: { paddingLeft: `${depth * 18 + 52}px` } }, node.error))));
1170
+ }
1171
+ function renderNodeChildren(ctx, container, node, depth) {
1172
+ const out = [];
1173
+ // Direct documents of this node (root docs live on the container node).
1174
+ if (node.hasDocs) {
1175
+ if (node.docsLoaded) {
1176
+ for (const doc of node.docs)
1177
+ out.push(renderDocRow(ctx, doc, node, container, depth));
1178
+ }
1179
+ else if (node.loading) {
1180
+ out.push(renderLoadingRow(ctx, depth));
1181
+ }
1182
+ }
1183
+ // Child folders.
1184
+ for (const child of node.children) {
1185
+ out.push(renderFolderNode(ctx, container, child, depth));
1186
+ }
1187
+ // An uploading file dropped onto this node.
1188
+ if (node.id === ctx.uploadingNodeId)
1189
+ out.push(renderUploadingRow(ctx, depth));
1190
+ return out;
1191
+ }
1192
+ function renderFolderNode(ctx, container, node, depth) {
1193
+ if (node.editing)
1194
+ return renderFolderEditRow(ctx, node, depth);
1195
+ const leaf = node.children.length === 0 && !node.hasDocs;
1196
+ const selected = node.id === ctx.selectedId;
1197
+ const cls = 'mrd-document-list__row'
1198
+ + (selected ? ' mrd-document-list__row--selected' : '')
1199
+ + (node.pending ? ' mrd-document-list__row--pending' : '')
1200
+ + (node.id === ctx.dropTargetId ? ' mrd-document-list__row--drop' : '');
1201
+ return (index.h("div", { class: "mrd-document-list__node", key: node.id }, index.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(), index.h("span", { class: "mrd-document-list__label" }, node.label), index.h("span", { class: "mrd-document-list__count" }, node.totalCount)), node.open && index.h("div", { class: "mrd-document-list__kids" }, renderNodeChildren(ctx, container, node, depth + 1))));
1202
+ }
1203
+ function renderContainerNode(ctx, node, depth) {
1204
+ const selected = node.id === ctx.selectedId;
1205
+ const cls = 'mrd-document-list__row mrd-document-list__row--dossier'
1206
+ + (selected ? ' mrd-document-list__row--selected' : '')
1207
+ + (node.id === ctx.dropTargetId ? ' mrd-document-list__row--drop' : '');
1208
+ return (index.h("div", { class: "mrd-document-list__node", key: node.id }, index.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(), index.h("span", { class: "mrd-document-list__label" }, node.label), index.h("span", { class: "mrd-document-list__count" }, node.totalCount)), node.open && (index.h("div", { class: "mrd-document-list__kids" }, node.loading && !node.foldersLoaded
1209
+ ? renderLoadingRow(ctx, depth + 1)
1210
+ : renderNodeChildren(ctx, node, node, depth + 1)))));
1211
+ }
979
1212
 
980
- 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)}`;
1213
+ 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)}`;
981
1214
 
982
1215
  const MrdDocumentList = class {
983
1216
  constructor(hostRef) {
@@ -1044,7 +1277,7 @@ const MrdDocumentList = class {
1044
1277
  return;
1045
1278
  const { target, container } = resolved;
1046
1279
  const tempId = `${container.id}/__new__${this.newFolderSeq++}`;
1047
- const node = this.makeFolderNode(tempId, '', container.id);
1280
+ const node = makeFolderNode(tempId, '', container.id);
1048
1281
  node.pending = true;
1049
1282
  node.editing = true;
1050
1283
  target.children = [...target.children, node];
@@ -1183,7 +1416,7 @@ const MrdDocumentList = class {
1183
1416
  }
1184
1417
  /** Seed the single implied container from context and load its folders. */
1185
1418
  seedSingleContainer() {
1186
- const node = this.makeContainerNode(this.containerHref, this.containerField, 0);
1419
+ const node = makeContainerNode(this.containerHref, this.containerField, 0);
1187
1420
  this.nodeIndex.set(node.id, node);
1188
1421
  this.containers = [node];
1189
1422
  this.rootLoading = false;
@@ -1230,61 +1463,37 @@ const MrdDocumentList = class {
1230
1463
  * type (e.g. "contents"), filtered down to the concrete `filterClass` via the
1231
1464
  * `type` query param — see baseParams(). */
1232
1465
  buildDataPath() {
1233
- var _a, _b, _c;
1466
+ var _a, _b;
1234
1467
  const it = this.item;
1235
- 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 : '';
1236
- if ((it === null || it === void 0 ? void 0 : it.type) === index$1.ClientLayoutItemType.RELATED_VIEW) {
1237
- return `/${(_c = it.fromClass) !== null && _c !== void 0 ? _c : ''}/${this.parentId}/${dataClass}`;
1238
- }
1239
- return `/${dataClass}`;
1468
+ return buildListPath({
1469
+ isRelatedView: (it === null || it === void 0 ? void 0 : it.type) === index$1.ClientLayoutItemType.RELATED_VIEW,
1470
+ fromClass: it === null || it === void 0 ? void 0 : it.fromClass,
1471
+ parentId: this.parentId,
1472
+ 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 : '',
1473
+ });
1240
1474
  }
1241
1475
  /** Path for creating a new document (file-drop). Unlike buildDataPath(), this
1242
1476
  * must target the concrete type: `dataClass`/`relatedClass` can be an abstract
1243
1477
  * base type (e.g. "contents") that cannot be POSTed to directly, so prefer
1244
1478
  * `filterClass` (e.g. "documents") when present. */
1245
1479
  buildCreatePath() {
1246
- var _a, _b, _c, _d;
1480
+ var _a, _b, _c;
1247
1481
  const it = this.item;
1248
- 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 : '';
1249
- if ((it === null || it === void 0 ? void 0 : it.type) === index$1.ClientLayoutItemType.RELATED_VIEW) {
1250
- return `/${(_d = it.fromClass) !== null && _d !== void 0 ? _d : ''}/${this.parentId}/${dataClass}`;
1251
- }
1252
- return `/${dataClass}`;
1482
+ return buildListPath({
1483
+ isRelatedView: (it === null || it === void 0 ? void 0 : it.type) === index$1.ClientLayoutItemType.RELATED_VIEW,
1484
+ fromClass: it === null || it === void 0 ? void 0 : it.fromClass,
1485
+ parentId: this.parentId,
1486
+ 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 : '',
1487
+ });
1253
1488
  }
1254
1489
  /** View-level static filters + filterClass, shared by every request. */
1255
1490
  baseParams() {
1256
- var _a, _b, _c, _d, _e, _f, _g;
1491
+ var _a, _b, _c;
1257
1492
  const p = new URLSearchParams();
1258
1493
  const filterClass = (_a = this.item) === null || _a === void 0 ? void 0 : _a.filterClass;
1259
1494
  if (filterClass)
1260
1495
  p.set('type', filterClass);
1261
- 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 : [])) {
1262
- if (!f.name)
1263
- continue;
1264
- if (f.operator === 'EMPTY') {
1265
- p.set(f.name, '');
1266
- continue;
1267
- }
1268
- if (f.operator === 'NOT_EMPTY') {
1269
- p.set(f.name + '_notempty', 'true');
1270
- continue;
1271
- }
1272
- if (f.operator === 'STARTS_WITH') {
1273
- p.set(f.name + '_startswith', String((_e = f.value) !== null && _e !== void 0 ? _e : ''));
1274
- continue;
1275
- }
1276
- if (f.operator === 'FROM') {
1277
- p.set(f.name + '_from', String((_f = f.value) !== null && _f !== void 0 ? _f : ''));
1278
- continue;
1279
- }
1280
- if (f.operator === 'TO') {
1281
- p.set(f.name + '_to', String((_g = f.value) !== null && _g !== void 0 ? _g : ''));
1282
- continue;
1283
- }
1284
- if (f.value != null) {
1285
- p.set(f.name, String(f.value));
1286
- }
1287
- }
1496
+ applyViewFilters(p, (_c = (_b = this.item) === null || _b === void 0 ? void 0 : _b.view) === null || _c === void 0 ? void 0 : _c.filter);
1288
1497
  return p;
1289
1498
  }
1290
1499
  emitContainerDistinct() {
@@ -1351,7 +1560,7 @@ const MrdDocumentList = class {
1351
1560
  if (!v.value || typeof v.value !== 'object')
1352
1561
  continue;
1353
1562
  const href = v.value.href;
1354
- const node = this.makeContainerNode(href, v.value.name, v.count);
1563
+ const node = makeContainerNode(href, v.value.name, v.count);
1355
1564
  nodes.push(node);
1356
1565
  this.nodeIndex.set(node.id, node);
1357
1566
  }
@@ -1369,38 +1578,7 @@ const MrdDocumentList = class {
1369
1578
  const container = this.nodeIndex.get(containerId);
1370
1579
  if (!container)
1371
1580
  return;
1372
- container.children = [];
1373
- container.hasDocs = false;
1374
- container.docCount = 0;
1375
- for (const v of values) {
1376
- const raw = typeof v.value === 'string' ? v.value : v.value == null ? '' : String(v.value);
1377
- const segs = this.splitFolder(raw);
1378
- if (segs.length === 0) {
1379
- // Root documents — the container's own direct documents.
1380
- container.hasDocs = true;
1381
- container.docCount = v.count;
1382
- container.fullPath = raw;
1383
- continue;
1384
- }
1385
- let node = container;
1386
- const acc = [];
1387
- for (const seg of segs) {
1388
- acc.push(seg);
1389
- let child = node.children.find(c => c.label === seg);
1390
- if (!child) {
1391
- child = this.makeFolderNode(container.id + '/' + acc.join('/'), seg, container.id);
1392
- node.children.push(child);
1393
- this.nodeIndex.set(child.id, child);
1394
- }
1395
- node = child;
1396
- }
1397
- node.hasDocs = true;
1398
- node.docCount = v.count;
1399
- node.fullPath = raw;
1400
- }
1401
- this.computeTotals(container);
1402
- container.foldersLoaded = true;
1403
- container.loading = false;
1581
+ applyFolderDistinct(container, values, this.nodeIndex);
1404
1582
  // If the container has root documents, load them now (they show inline on expand).
1405
1583
  if (container.hasDocs && !container.docsLoaded) {
1406
1584
  this.emitDocuments(container, container);
@@ -1408,36 +1586,6 @@ const MrdDocumentList = class {
1408
1586
  this.bump();
1409
1587
  }
1410
1588
  // ── Tree helpers ─────────────────────────────────────────────────────────
1411
- /** Normalise a folder path: null/""/"/" → root ([]); else split on "/" dropping empties. */
1412
- splitFolder(path) {
1413
- if (path == null)
1414
- return [];
1415
- const s = String(path).trim();
1416
- if (s === '' || s === '/')
1417
- return [];
1418
- return s.split('/').map(x => x.trim()).filter(Boolean);
1419
- }
1420
- makeContainerNode(href, label, count) {
1421
- return {
1422
- id: 'c:' + href, kind: 'container', label, href,
1423
- hasDocs: false, docCount: 0, totalCount: count, children: [],
1424
- open: false, loading: false, foldersLoaded: false, docsLoaded: false, docs: [],
1425
- };
1426
- }
1427
- makeFolderNode(id, label, containerId) {
1428
- return {
1429
- id, kind: 'folder', label, containerId,
1430
- hasDocs: false, docCount: 0, totalCount: 0, children: [],
1431
- open: false, loading: false, foldersLoaded: false, docsLoaded: false, docs: [],
1432
- };
1433
- }
1434
- computeTotals(node) {
1435
- let total = node.docCount;
1436
- for (const c of node.children)
1437
- total += this.computeTotals(c);
1438
- node.totalCount = total;
1439
- return total;
1440
- }
1441
1589
  /** Force a re-render after mutating nodes in place. */
1442
1590
  bump() {
1443
1591
  this.containers = [...this.containers];
@@ -1487,14 +1635,6 @@ const MrdDocumentList = class {
1487
1635
  async createFolder() {
1488
1636
  this.startCreateFolder();
1489
1637
  }
1490
- /** Folder path segments of a node relative to its container (derived from its id). */
1491
- segmentsOf(node, container) {
1492
- if (node.kind === 'container')
1493
- return [];
1494
- const prefix = container.id + '/';
1495
- const rest = node.id.startsWith(prefix) ? node.id.slice(prefix.length) : '';
1496
- return rest ? rest.split('/') : [];
1497
- }
1498
1638
  commitFolder() {
1499
1639
  const node = this.pendingNode;
1500
1640
  const parent = this.pendingParent;
@@ -1519,7 +1659,7 @@ const MrdDocumentList = class {
1519
1659
  }
1520
1660
  // Finalise: swap the temp id for the real path-derived id so a later distinct
1521
1661
  // value with the same folder string merges onto this node.
1522
- const segs = [...this.segmentsOf(parent, container), name];
1662
+ const segs = [...segmentsOf(parent, container), name];
1523
1663
  this.nodeIndex.delete(node.id);
1524
1664
  node.id = container.id + '/' + segs.join('/');
1525
1665
  node.fullPath = '/' + segs.join('/');
@@ -1568,10 +1708,6 @@ const MrdDocumentList = class {
1568
1708
  this.bump();
1569
1709
  this.mrdUpload.emit({ file });
1570
1710
  }
1571
- /** Strip a single trailing extension for the document title. */
1572
- stripExtension(name) {
1573
- return name.replace(/\.[^./\\]+$/, '');
1574
- }
1575
1711
  /** Host callback with the uploaded file reference. Builds the create payload
1576
1712
  * from the archetype slots and requests the new document. */
1577
1713
  async setFileReference(uri) {
@@ -1579,16 +1715,20 @@ const MrdDocumentList = class {
1579
1715
  if (!up)
1580
1716
  return;
1581
1717
  const { file, node, container } = up;
1582
- const folder = this.folderStringOf(node, container);
1718
+ const folder = folderStringOf(node, container);
1583
1719
  const values = {
1584
1720
  [this.fileField]: uri,
1585
- [this.titleField]: this.stripExtension(file.name),
1721
+ [this.titleField]: stripExtension(file.name),
1586
1722
  [this.folderField]: folder,
1587
- [this.containerField]: container.href,
1588
1723
  };
1724
+ // The create path already embeds the container (/{fromClass}/{parentId}/...)
1725
+ // when this is the seeded single-container context; omit the redundant field.
1726
+ if (!this.isSeededSingleContainer()) {
1727
+ values[this.containerField] = container.href;
1728
+ }
1589
1729
  this.mrdCreateObject.emit({ path: this.buildCreatePath(), values });
1590
1730
  // Optimistically show the new document (no href until a reload).
1591
- const optimistic = { [this.titleField]: this.stripExtension(file.name), _optimistic: true };
1731
+ const optimistic = { [this.titleField]: stripExtension(file.name), _optimistic: true };
1592
1732
  const wasUnloadedEmpty = !node.docsLoaded && node.docCount === 0;
1593
1733
  node.hasDocs = true;
1594
1734
  node.pending = false;
@@ -1617,16 +1757,6 @@ const MrdDocumentList = class {
1617
1757
  this.lastOptimisticDoc = null;
1618
1758
  this.bump();
1619
1759
  }
1620
- /** Folder string a node represents: the raw distinct value when it holds
1621
- * documents, else derived from its path segments; null for a container root. */
1622
- folderStringOf(node, container) {
1623
- if (node.kind === 'container')
1624
- return null;
1625
- if (node.fullPath != null && node.fullPath !== '')
1626
- return node.fullPath;
1627
- const segs = this.segmentsOf(node, container);
1628
- return segs.length ? '/' + segs.join('/') : null;
1629
- }
1630
1760
  moveDocument(toNode, toContainer) {
1631
1761
  var _a, _b;
1632
1762
  const doc = this.dragDoc;
@@ -1638,26 +1768,14 @@ const MrdDocumentList = class {
1638
1768
  : (fromNode.containerId ? this.nodeIndex.get(fromNode.containerId) : undefined);
1639
1769
  if (!fromContainer)
1640
1770
  return;
1641
- const targetFolder = this.folderStringOf(toNode, toContainer);
1642
- const sourceFolder = this.folderStringOf(fromNode, fromContainer);
1771
+ const targetFolder = folderStringOf(toNode, toContainer);
1772
+ const sourceFolder = folderStringOf(fromNode, fromContainer);
1643
1773
  const sameContainer = toContainer === fromContainer;
1644
1774
  // No-op: dropped back onto its own folder.
1645
1775
  if (toNode === fromNode || (sameContainer && targetFolder === sourceFolder))
1646
1776
  return;
1647
- // ── Optimistic tree update (fire-and-forget; no refetch) ──
1648
- fromNode.docs = fromNode.docs.filter(d => d !== doc);
1649
- fromNode.docCount = Math.max(0, fromNode.docCount - 1);
1650
- // A now-empty folder should stop showing an expand chevron (it disappears on
1651
- // the next reload anyway, since it is derived from document folder strings).
1652
- if (fromNode.docsLoaded)
1653
- fromNode.hasDocs = fromNode.docs.length > 0;
1654
- toNode.hasDocs = true;
1655
- toNode.pending = false; // a pending folder is now materialised
1656
- toNode.docCount += 1;
1657
- if (toNode.kind === 'folder')
1658
- toNode.fullPath = targetFolder !== null && targetFolder !== void 0 ? targetFolder : '';
1659
- if (toNode.docsLoaded)
1660
- toNode.docs = [...toNode.docs, doc];
1777
+ // Optimistic tree update (fire-and-forget; no refetch).
1778
+ applyDocMove(doc, fromNode, toNode, targetFolder);
1661
1779
  this.recomputeContainerTotals(fromContainer, -1);
1662
1780
  if (!sameContainer)
1663
1781
  this.recomputeContainerTotals(toContainer, 1);
@@ -1675,7 +1793,7 @@ const MrdDocumentList = class {
1675
1793
  * loaded; otherwise just nudge the aggregate badge by the delta. */
1676
1794
  recomputeContainerTotals(container, delta) {
1677
1795
  if (container.foldersLoaded) {
1678
- this.computeTotals(container);
1796
+ computeTotals(container);
1679
1797
  }
1680
1798
  else {
1681
1799
  container.totalCount = Math.max(0, container.totalCount + delta);
@@ -1688,111 +1806,64 @@ const MrdDocumentList = class {
1688
1806
  this.mrdNavigate.emit({ href, label });
1689
1807
  }
1690
1808
  // ── Render ───────────────────────────────────────────────────────────────
1691
- renderChevron(open, leaf) {
1692
- return (index.h("span", { class: `mrd-document-list__chev${leaf ? ' mrd-document-list__chev--leaf' : ''}${open ? ' mrd-document-list__chev--open' : ''}` }, index.h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, index.h("path", { d: "M9 6l6 6-6 6" }))));
1693
- }
1694
- renderDossierIcon() {
1695
- return (index.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" }, index.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" })));
1696
- }
1697
- renderFolderIcon() {
1698
- return (index.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" }, index.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" })));
1699
- }
1700
- renderDocIcon() {
1701
- return (index.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" }, index.h("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }), index.h("path", { d: "M14 2v6h6" })));
1702
- }
1703
- indent(depth) {
1704
- return index.h("span", { class: "mrd-document-list__indent", style: { width: `${depth * 18}px` } });
1705
- }
1706
- renderDocRow(doc, node, container, depth) {
1707
- var _a, _b, _c, _d, _e;
1708
- 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 : '';
1709
- const dateRaw = this.dateField ? doc === null || doc === void 0 ? void 0 : doc[this.dateField] : undefined;
1710
- const date = dateRaw ? formatDate(dateRaw, this.locale) : '';
1711
- return (index.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(), index.h("span", { class: "mrd-document-list__label" }, label), date && index.h("span", { class: "mrd-document-list__date" }, date)));
1712
- }
1713
- renderLoadingRow(depth) {
1714
- return (index.h("div", { class: "mrd-document-list__loading", key: "loading" }, this.indent(depth), index.h("span", { class: "mrd-document-list__spinner" }), t('loading', this.locale)));
1715
- }
1716
- renderChildren(container, node, depth) {
1717
- const out = [];
1718
- // Direct documents of this node (root docs live on the container node).
1719
- if (node.hasDocs) {
1720
- if (node.docsLoaded) {
1721
- for (const doc of node.docs)
1722
- out.push(this.renderDocRow(doc, node, container, depth));
1723
- }
1724
- else if (node.loading) {
1725
- out.push(this.renderLoadingRow(depth));
1726
- }
1727
- }
1728
- // Child folders.
1729
- for (const child of node.children) {
1730
- out.push(this.renderFolderNode(container, child, depth));
1731
- }
1732
- // An uploading file dropped onto this node.
1733
- if (node.id === this.uploadingNodeId)
1734
- out.push(this.renderUploadingRow(depth));
1735
- return out;
1736
- }
1737
- renderUploadingRow(depth) {
1738
- return (index.h("div", { class: "mrd-document-list__loading", key: "uploading" }, this.indent(depth), index.h("span", { class: "mrd-document-list__spinner" }), t('upload_file', this.locale)));
1739
- }
1740
- renderFolderEditRow(node, depth) {
1741
- return (index.h("div", { class: "mrd-document-list__node", key: node.id }, index.h("div", { class: "mrd-document-list__row mrd-document-list__row--edit" }, this.indent(depth), this.renderChevron(false, true), this.renderFolderIcon(), index.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 && (index.h("div", { class: "mrd-document-list__error", style: { paddingLeft: `${depth * 18 + 52}px` } }, node.error))));
1742
- }
1743
- renderFolderNode(container, node, depth) {
1744
- if (node.editing)
1745
- return this.renderFolderEditRow(node, depth);
1746
- const leaf = node.children.length === 0 && !node.hasDocs;
1747
- const selected = node.id === this.selectedId;
1748
- const cls = 'mrd-document-list__row'
1749
- + (selected ? ' mrd-document-list__row--selected' : '')
1750
- + (node.pending ? ' mrd-document-list__row--pending' : '')
1751
- + (node.id === this.dropTargetId ? ' mrd-document-list__row--drop' : '');
1752
- return (index.h("div", { class: "mrd-document-list__node", key: node.id }, index.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(), index.h("span", { class: "mrd-document-list__label" }, node.label), index.h("span", { class: "mrd-document-list__count" }, node.totalCount)), node.open && index.h("div", { class: "mrd-document-list__kids" }, this.renderChildren(container, node, depth + 1))));
1753
- }
1754
- renderContainerNode(node, depth) {
1755
- const selected = node.id === this.selectedId;
1756
- const cls = 'mrd-document-list__row mrd-document-list__row--dossier'
1757
- + (selected ? ' mrd-document-list__row--selected' : '')
1758
- + (node.id === this.dropTargetId ? ' mrd-document-list__row--drop' : '');
1759
- return (index.h("div", { class: "mrd-document-list__node", key: node.id }, index.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(), index.h("span", { class: "mrd-document-list__label" }, node.label), index.h("span", { class: "mrd-document-list__count" }, node.totalCount)), node.open && (index.h("div", { class: "mrd-document-list__kids" }, node.loading && !node.foldersLoaded
1760
- ? this.renderLoadingRow(depth + 1)
1761
- : this.renderChildren(node, node, depth + 1)))));
1809
+ treeCtx() {
1810
+ return {
1811
+ locale: this.locale,
1812
+ titleField: this.titleField,
1813
+ dateField: this.dateField,
1814
+ selectedId: this.selectedId,
1815
+ dropTargetId: this.dropTargetId,
1816
+ uploadingNodeId: this.uploadingNodeId,
1817
+ on: {
1818
+ toggleContainer: node => this.toggleContainer(node),
1819
+ toggleFolder: (container, node) => this.toggleFolder(container, node),
1820
+ openDoc: doc => this.openDoc(doc),
1821
+ docDragStart: this.onDocDragStart,
1822
+ docDragEnd: this.onDocDragEnd,
1823
+ nodeDragOver: this.onNodeDragOver,
1824
+ nodeDragLeave: this.onNodeDragLeave,
1825
+ nodeDrop: this.onNodeDrop,
1826
+ pendingInput: this.onPendingInput,
1827
+ pendingKeyDown: this.onPendingKeyDown,
1828
+ cancelFolder: () => this.cancelFolder(),
1829
+ setPendingInputEl: el => (this.pendingInputEl = el),
1830
+ },
1831
+ };
1762
1832
  }
1763
1833
  render() {
1834
+ const ctx = this.treeCtx();
1764
1835
  let body;
1765
1836
  if (this.rootLoading) {
1766
- body = this.renderLoadingRow(0);
1837
+ body = renderLoadingRow(ctx, 0);
1767
1838
  }
1768
1839
  else if (this.containers.length === 0) {
1769
- body = index.h("div", { key: '9c38a2e26320a8173ba82cac412c1b32a8a1882e', class: "mrd-document-list__empty" }, t('no_results', this.locale));
1840
+ body = index.h("div", { key: 'ce40dab51ab61447838e5059159ae4778209a6f3', class: "mrd-document-list__empty" }, t('no_results', this.locale));
1770
1841
  }
1771
1842
  else if (this.singleContainer) {
1772
1843
  // Dossier context: render the single container's folder tree at the root.
1773
1844
  const only = this.containers[0];
1774
1845
  if (only.loading && !only.foldersLoaded) {
1775
- body = this.renderLoadingRow(0);
1846
+ body = renderLoadingRow(ctx, 0);
1776
1847
  }
1777
1848
  else {
1778
- const kids = this.renderChildren(only, only, 0);
1849
+ const kids = renderNodeChildren(ctx, only, only, 0);
1779
1850
  body = kids.length
1780
1851
  ? kids
1781
1852
  : index.h("div", { class: "mrd-document-list__empty" }, t('doc_empty_drop', this.locale));
1782
1853
  }
1783
1854
  }
1784
1855
  else {
1785
- body = this.containers.map(c => this.renderContainerNode(c, 0));
1856
+ body = this.containers.map(c => renderContainerNode(ctx, c, 0));
1786
1857
  }
1787
- return (index.h(index.Host, { key: 'dd83a6a609e01d21a2b5da5b3ab929f6f9315402' }, index.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)));
1858
+ return (index.h(index.Host, { key: '9e1f7805ae18bce506c530a481db902900ad95f3' }, index.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)));
1788
1859
  }
1789
1860
  get el() { return index.getElement(this); }
1790
1861
  };
1791
1862
  /** Root sentinel id for the container-level distinct request. */
1792
1863
  MrdDocumentList.ROOT = '__root__';
1793
- MrdDocumentList.style = mrdDocumentListScss();
1864
+ MrdDocumentList.style = mrdDocumentListCss();
1794
1865
 
1795
- 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)}`;
1866
+ 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)}`;
1796
1867
 
1797
1868
  const MrdDocumentView = class {
1798
1869
  constructor(hostRef) {
@@ -1842,12 +1913,12 @@ const MrdDocumentView = class {
1842
1913
  const date = dateRaw != null && dateRaw !== '' ? formatDate(dateRaw, this.locale) : null;
1843
1914
  const summaryRaw = this.slotValue('summary');
1844
1915
  const summary = summaryRaw != null && summaryRaw !== '' ? String(summaryRaw) : null;
1845
- return (index.h(index.Host, { key: '0a2071925ecdb21738376d66fa4babf4590e694c' }, index.h("div", { key: 'a2d29c0b6e211cab142adc780466bc885a602e96', class: "mrd-document-view" }, this.renderContainer(), title && index.h("h1", { key: '7f5ac202c21bc8a70f0dd15e2e1fa06e651b5bce', class: "mrd-document-view__title" }, title), date && index.h("p", { key: 'b1dce94d5fd8bfd5e078644f631a38f91b87e7ff', class: "mrd-document-view__date" }, date), this.renderFile(), summary && (index.h("div", { key: '588b9ca40a49ae9ea303852620bde75333b440ab', class: "mrd-document-view__summary" }, index.h("div", { key: 'd3b8adb85ac346b72451e789c10aedd539c966de', class: "mrd-document-view__summary-body", innerHTML: summary }))))));
1916
+ return (index.h(index.Host, { key: '0c64c72eaf5e1eefc2ca9aebb2543081eb1eae32' }, index.h("div", { key: '70cce81b089fee81a4c163a6ba5fbcc8cb46131c', class: "mrd-document-view" }, this.renderContainer(), title && index.h("h1", { key: '50f85b32a6740d6cf57fdf1bb0bcc597b5e97b31', class: "mrd-document-view__title" }, title), date && index.h("p", { key: 'b3c8fb3b4382104858d49ef9a1597034665122bb', class: "mrd-document-view__date" }, date), this.renderFile(), summary && (index.h("div", { key: '2046c1eca7601549115de0c95ff778abaf5faf46', class: "mrd-document-view__summary" }, index.h("div", { key: '875863d3e438eee3d4df10473a93f09370fde08c', class: "mrd-document-view__summary-body", innerHTML: summary }))))));
1846
1917
  }
1847
1918
  };
1848
- MrdDocumentView.style = mrdDocumentViewScss();
1919
+ MrdDocumentView.style = mrdDocumentViewCss();
1849
1920
 
1850
- 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)}`;
1921
+ 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)}`;
1851
1922
 
1852
1923
  const MrdEmailField = class {
1853
1924
  constructor(hostRef) {
@@ -1868,26 +1939,18 @@ const MrdEmailField = class {
1868
1939
  };
1869
1940
  this.handleBlur = (e) => {
1870
1941
  const val = e.target.value;
1871
- if (this.required && !validateRequired(val)) {
1872
- this.error = t('required', this.locale);
1873
- }
1874
- else if (val && !validateEmail(val)) {
1875
- this.error = t('invalid_email', this.locale);
1876
- }
1877
- else {
1878
- this.error = '';
1879
- }
1942
+ this.error = requiredError(val, this.required, this.locale)
1943
+ || (val && !validateEmail(val) ? t('invalid_email', this.locale) : '');
1880
1944
  this.mrdBlur.emit({ name: this.name, value: val });
1881
1945
  };
1882
1946
  }
1883
1947
  render() {
1884
- const hasError = !!this.error;
1885
- return (index.h(index.Host, { key: '0d442ab2a711c26c83fcdbf0fd8cd006d8dd8649' }, index.h("div", { key: 'ceb2a80679514c4c5b888fe096c90ed6cc973f64', class: "mrd-email-field" }, this.label && (index.h("label", { key: '663f95eff1002ee56cfc3104514bf31b47e26750', class: `mrd-email-field__label${this.required ? ' mrd-email-field__label--required' : ''}` }, this.label)), index.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 && index.h("span", { key: '626ee856ceaa7051fb9dd1de8b7cbd708e83f617', class: "mrd-email-field__error" }, this.error))));
1948
+ return (index.h(index.Host, { key: '93f7c4975c24e6001e772f2858344edec04cda10' }, index.h("div", { key: '4f49a2a1f68a4161762861c5d54fd3690c88ac5d', class: "mrd-email-field" }, index.h(FieldLabel, { key: '23b20799f3e7c04889b7bc3a271e61b0bb5d7537', base: "mrd-email-field", label: this.label, required: this.required }), index.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 }), index.h(FieldError, { key: '34945fff9c69cf2f0aeb56492c95052250514d5c', base: "mrd-email-field", error: this.error }))));
1886
1949
  }
1887
1950
  };
1888
- MrdEmailField.style = mrdEmailFieldScss();
1951
+ MrdEmailField.style = mrdEmailFieldCss();
1889
1952
 
1890
- 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)}`;
1953
+ 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)}`;
1891
1954
 
1892
1955
  const MrdField = class {
1893
1956
  constructor(hostRef) {
@@ -2072,9 +2135,47 @@ const MrdField = class {
2072
2135
  }]
2073
2136
  }; }
2074
2137
  };
2075
- MrdField.style = mrdFieldScss();
2138
+ MrdField.style = mrdFieldCss();
2139
+
2140
+ /**
2141
+ * Shared upload behaviour for mrd-file-field and mrd-image-field:
2142
+ * file validation, drop-zone class building and drag-drop wiring.
2143
+ */
2144
+ /** Validates a selected/dropped file; returns a localised error message or '' when accepted. */
2145
+ function validateUploadFile(file, maxSize, locale, requireImage = false) {
2146
+ if (maxSize > 0 && file.size > maxSize)
2147
+ return t('file_too_large', locale);
2148
+ if (requireImage && !file.type.startsWith('image/'))
2149
+ return t('invalid_image', locale);
2150
+ return '';
2151
+ }
2152
+ /** BEM class string for the drop zone, e.g. base 'mrd-file-field' → 'mrd-file-field__zone …'. */
2153
+ function uploadZoneClass(base, opts) {
2154
+ return [
2155
+ `${base}__zone`,
2156
+ opts.dragging ? `${base}__zone--dragging` : '',
2157
+ opts.error ? `${base}__zone--error` : '',
2158
+ opts.disabled ? `${base}__zone--disabled` : '',
2159
+ ].filter(Boolean).join(' ');
2160
+ }
2161
+ /** Drag-drop handlers for the drop zone; the component owns the dragging state and file handling. */
2162
+ function makeDragHandlers(setDragging, onFile) {
2163
+ return {
2164
+ onDragOver: (e) => {
2165
+ e.preventDefault();
2166
+ setDragging(true);
2167
+ },
2168
+ onDragLeave: () => setDragging(false),
2169
+ onDrop: (e) => {
2170
+ var _a, _b, _c;
2171
+ e.preventDefault();
2172
+ setDragging(false);
2173
+ 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);
2174
+ },
2175
+ };
2176
+ }
2076
2177
 
2077
- 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)}`;
2178
+ 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)}}`;
2078
2179
 
2079
2180
  const MrdFileField = class {
2080
2181
  constructor(hostRef) {
@@ -2099,20 +2200,7 @@ const MrdFileField = class {
2099
2200
  const files = e.target.files;
2100
2201
  this.handleFile((_a = files === null || files === void 0 ? void 0 : files[0]) !== null && _a !== void 0 ? _a : null);
2101
2202
  };
2102
- this.handleDragOver = (e) => {
2103
- e.preventDefault();
2104
- this.isDragging = true;
2105
- };
2106
- this.handleDragLeave = () => {
2107
- this.isDragging = false;
2108
- };
2109
- this.handleDrop = (e) => {
2110
- var _a, _b, _c;
2111
- e.preventDefault();
2112
- this.isDragging = false;
2113
- 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;
2114
- this.handleFile(file);
2115
- };
2203
+ this.drag = makeDragHandlers(dragging => (this.isDragging = dragging), file => this.handleFile(file));
2116
2204
  this.handleZoneClick = () => {
2117
2205
  var _a;
2118
2206
  if (!this.disabled && !this.uploading) {
@@ -2146,8 +2234,9 @@ const MrdFileField = class {
2146
2234
  this.mrdChange.emit({ name: this.name, value: null });
2147
2235
  return;
2148
2236
  }
2149
- if (this.maxSize > 0 && file.size > this.maxSize) {
2150
- this.error = t('file_too_large', this.locale);
2237
+ const uploadError = validateUploadFile(file, this.maxSize, this.locale);
2238
+ if (uploadError) {
2239
+ this.error = uploadError;
2151
2240
  return;
2152
2241
  }
2153
2242
  this.error = '';
@@ -2159,13 +2248,12 @@ const MrdFileField = class {
2159
2248
  render() {
2160
2249
  const hasFile = this.uploading || (typeof this.value === 'string' && this.value) || this.fileName;
2161
2250
  const hasError = !!this.error;
2162
- const zoneClass = [
2163
- 'mrd-file-field__zone',
2164
- this.isDragging ? 'mrd-file-field__zone--dragging' : '',
2165
- hasError ? 'mrd-file-field__zone--error' : '',
2166
- this.disabled || this.uploading ? 'mrd-file-field__zone--disabled' : '',
2167
- ].filter(Boolean).join(' ');
2168
- return (index.h(index.Host, { key: '095bb39f3cb1680cf5e7e51bdfd06d8eb087f237' }, index.h("div", { key: '7e5b5fe6e63b6530221083c8bcb82bcac59a5fe7', class: "mrd-file-field" }, this.label && (index.h("label", { key: 'c34723f4199371d6fe8ea87463d878b89c038590', class: `mrd-file-field__label${this.required ? ' mrd-file-field__label--required' : ''}` }, this.label)), index.h("div", { key: '4727667345d3cd4a5c65a431744a09f366943c13', class: zoneClass, onClick: this.handleZoneClick, onDragOver: this.handleDragOver, onDragLeave: this.handleDragLeave, onDrop: this.handleDrop }, index.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 ? (index.h("div", { class: "mrd-file-field__selected" }, this.uploading ? (index.h("span", { class: "mrd-file-field__spinner", "aria-label": t('loading', this.locale) })) : (index.h("svg", { class: "mrd-file-field__icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2" }, index.h("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }), index.h("polyline", { points: "14 2 14 8 20 8" }))), index.h("span", { class: "mrd-file-field__filename" }, this.fileName), !this.uploading && (index.h("button", { class: "mrd-file-field__clear", type: "button", onClick: this.handleClear, "aria-label": t('clear', this.locale) }, "\u2715")))) : (index.h("div", { class: "mrd-file-field__prompt" }, index.h("svg", { class: "mrd-file-field__upload-icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2" }, index.h("polyline", { points: "16 16 12 12 8 16" }), index.h("line", { x1: "12", y1: "12", x2: "12", y2: "21" }), index.h("path", { d: "M20.39 18.39A5 5 0 0 0 18 9h-1.26A8 8 0 1 0 3 16.3" })), index.h("span", null, t('drop_file_here', this.locale), ' ', index.h("span", { class: "mrd-file-field__browse" }, t('browse', this.locale)))))), hasError && index.h("span", { key: '00ce94ead3c32ed63e903cfd9d8480084a308d84', class: "mrd-file-field__error" }, this.error))));
2251
+ const zoneClass = uploadZoneClass('mrd-file-field', {
2252
+ dragging: this.isDragging,
2253
+ error: hasError,
2254
+ disabled: this.disabled || this.uploading,
2255
+ });
2256
+ return (index.h(index.Host, { key: '2c4cee79cd0f95ed3750dfc86007a2b36aa3da15' }, index.h("div", { key: '5b47d0f83e8e38b22bb04409544ec2af580274f1', class: "mrd-file-field" }, index.h(FieldLabel, { key: '47a92d5680670bf750854fa6e7883da54a40baec', base: "mrd-file-field", label: this.label, required: this.required }), index.h("div", { key: '684f6ab39c32635fb5ca966ccab4a061d8682f89', class: zoneClass, onClick: this.handleZoneClick, onDragOver: this.drag.onDragOver, onDragLeave: this.drag.onDragLeave, onDrop: this.drag.onDrop }, index.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 ? (index.h("div", { class: "mrd-file-field__selected" }, this.uploading ? (index.h("span", { class: "mrd-file-field__spinner", "aria-label": t('loading', this.locale) })) : (index.h("svg", { class: "mrd-file-field__icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2" }, index.h("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }), index.h("polyline", { points: "14 2 14 8 20 8" }))), index.h("span", { class: "mrd-file-field__filename" }, this.fileName), !this.uploading && (index.h("button", { class: "mrd-file-field__clear", type: "button", onClick: this.handleClear, "aria-label": t('clear', this.locale) }, "\u2715")))) : (index.h("div", { class: "mrd-file-field__prompt" }, index.h("svg", { class: "mrd-file-field__upload-icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2" }, index.h("polyline", { points: "16 16 12 12 8 16" }), index.h("line", { x1: "12", y1: "12", x2: "12", y2: "21" }), index.h("path", { d: "M20.39 18.39A5 5 0 0 0 18 9h-1.26A8 8 0 1 0 3 16.3" })), index.h("span", null, t('drop_file_here', this.locale), ' ', index.h("span", { class: "mrd-file-field__browse" }, t('browse', this.locale)))))), index.h(FieldError, { key: '5f18e91aa94319a5571c368e745c108fb0d371a7', base: "mrd-file-field", error: this.error }))));
2169
2257
  }
2170
2258
  static get watchers() { return {
2171
2259
  "value": [{
@@ -2173,9 +2261,9 @@ const MrdFileField = class {
2173
2261
  }]
2174
2262
  }; }
2175
2263
  };
2176
- MrdFileField.style = mrdFileFieldScss();
2264
+ MrdFileField.style = mrdFileFieldCss();
2177
2265
 
2178
- 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)}`;
2266
+ 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)}`;
2179
2267
 
2180
2268
  const MrdForm = class {
2181
2269
  constructor(hostRef) {
@@ -2542,9 +2630,9 @@ const MrdForm = class {
2542
2630
  }]
2543
2631
  }; }
2544
2632
  };
2545
- MrdForm.style = mrdFormScss();
2633
+ MrdForm.style = mrdFormCss();
2546
2634
 
2547
- 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)}`;
2635
+ 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)}`;
2548
2636
 
2549
2637
  const MrdHyperlinkField = class {
2550
2638
  constructor(hostRef) {
@@ -2570,15 +2658,8 @@ const MrdHyperlinkField = class {
2570
2658
  this.mrdChange.emit({ name: this.name, value: this.buildValue() });
2571
2659
  };
2572
2660
  this.handleBlur = () => {
2573
- if (this.required && !validateRequired(this.internalHref)) {
2574
- this.error = t('required', this.locale);
2575
- }
2576
- else if (this.internalHref && !validateUrl(this.internalHref)) {
2577
- this.error = t('invalid_url', this.locale);
2578
- }
2579
- else {
2580
- this.error = '';
2581
- }
2661
+ this.error = requiredError(this.internalHref, this.required, this.locale)
2662
+ || (this.internalHref && !validateUrl(this.internalHref) ? t('invalid_url', this.locale) : '');
2582
2663
  this.mrdBlur.emit({ name: this.name, value: this.buildValue() });
2583
2664
  };
2584
2665
  }
@@ -2611,7 +2692,7 @@ const MrdHyperlinkField = class {
2611
2692
  ? index.h("a", { class: "mrd-hyperlink-field__link", href: this.internalHref, target: "_blank", rel: "noopener noreferrer" }, this.internalName || this.internalHref)
2612
2693
  : index.h("span", { class: "mrd-hyperlink-field__empty" }, "\u2014"))));
2613
2694
  }
2614
- return (index.h(index.Host, null, index.h("div", { class: "mrd-hyperlink-field" }, this.label && (index.h("label", { class: `mrd-hyperlink-field__label${this.required ? ' mrd-hyperlink-field__label--required' : ''}` }, this.label)), index.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 }), index.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 && index.h("span", { class: "mrd-hyperlink-field__error" }, this.error))));
2695
+ return (index.h(index.Host, null, index.h("div", { class: "mrd-hyperlink-field" }, index.h(FieldLabel, { base: "mrd-hyperlink-field", label: this.label, required: this.required }), index.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 }), index.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 }), index.h(FieldError, { base: "mrd-hyperlink-field", error: this.error }))));
2615
2696
  }
2616
2697
  static get watchers() { return {
2617
2698
  "value": [{
@@ -2619,9 +2700,9 @@ const MrdHyperlinkField = class {
2619
2700
  }]
2620
2701
  }; }
2621
2702
  };
2622
- MrdHyperlinkField.style = mrdHyperlinkFieldScss();
2703
+ MrdHyperlinkField.style = mrdHyperlinkFieldCss();
2623
2704
 
2624
- 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)}`;
2705
+ 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)}`;
2625
2706
 
2626
2707
  const MrdImageField = class {
2627
2708
  constructor(hostRef) {
@@ -2647,20 +2728,7 @@ const MrdImageField = class {
2647
2728
  const files = e.target.files;
2648
2729
  this.handleFile((_a = files === null || files === void 0 ? void 0 : files[0]) !== null && _a !== void 0 ? _a : null);
2649
2730
  };
2650
- this.handleDragOver = (e) => {
2651
- e.preventDefault();
2652
- this.isDragging = true;
2653
- };
2654
- this.handleDragLeave = () => {
2655
- this.isDragging = false;
2656
- };
2657
- this.handleDrop = (e) => {
2658
- var _a, _b, _c;
2659
- e.preventDefault();
2660
- this.isDragging = false;
2661
- 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;
2662
- this.handleFile(file);
2663
- };
2731
+ this.drag = makeDragHandlers(dragging => (this.isDragging = dragging), file => this.handleFile(file));
2664
2732
  this.handleZoneClick = () => {
2665
2733
  var _a;
2666
2734
  if (!this.disabled && !this.uploading) {
@@ -2697,12 +2765,9 @@ const MrdImageField = class {
2697
2765
  this.mrdChange.emit({ name: this.name, value: null });
2698
2766
  return;
2699
2767
  }
2700
- if (this.maxSize > 0 && file.size > this.maxSize) {
2701
- this.error = t('file_too_large', this.locale);
2702
- return;
2703
- }
2704
- if (!file.type.startsWith('image/')) {
2705
- this.error = 'Please select an image file';
2768
+ const uploadError = validateUploadFile(file, this.maxSize, this.locale, true);
2769
+ if (uploadError) {
2770
+ this.error = uploadError;
2706
2771
  return;
2707
2772
  }
2708
2773
  this.error = '';
@@ -2720,13 +2785,12 @@ const MrdImageField = class {
2720
2785
  }
2721
2786
  render() {
2722
2787
  const hasError = !!this.error;
2723
- const zoneClass = [
2724
- 'mrd-image-field__zone',
2725
- this.isDragging ? 'mrd-image-field__zone--dragging' : '',
2726
- hasError ? 'mrd-image-field__zone--error' : '',
2727
- this.disabled || this.uploading ? 'mrd-image-field__zone--disabled' : '',
2728
- ].filter(Boolean).join(' ');
2729
- return (index.h(index.Host, { key: '97db2df72839f36b7a46e153a5dd1c208c52b522' }, index.h("div", { key: 'c8f2d3d858f90d322d26082aaf5adb57acfc78f4', class: "mrd-image-field" }, this.label && (index.h("label", { key: '6625e5031ff0b7c06f76c1ea0387f1bd5c1858a4', class: `mrd-image-field__label${this.required ? ' mrd-image-field__label--required' : ''}` }, this.label)), index.h("div", { key: '364216e6a96e845e21c42e821fdff02bd2612ff8', class: zoneClass, onClick: this.handleZoneClick, onDragOver: this.handleDragOver, onDragLeave: this.handleDragLeave, onDrop: this.handleDrop }, index.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 ? (index.h("div", { class: "mrd-image-field__preview-container" }, index.h("div", { class: "mrd-image-field__preview-thumb" }, index.h("img", { class: "mrd-image-field__preview", src: this.previewUrl, alt: this.fileName }), this.uploading && index.h("div", { class: "mrd-image-field__preview-overlay" }, index.h("span", { class: "mrd-image-field__spinner" }))), index.h("div", { class: "mrd-image-field__preview-info" }, index.h("span", { class: "mrd-image-field__preview-name" }, this.fileName), this.uploading && (index.h("span", { class: "mrd-image-field__upload-status" }, t('loading', this.locale)))), !this.uploading && (index.h("button", { class: "mrd-image-field__clear", type: "button", onClick: this.handleClear, "aria-label": t('clear', this.locale) }, t('remove', this.locale))))) : (index.h("div", { class: "mrd-image-field__prompt" }, index.h("svg", { class: "mrd-image-field__upload-icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2" }, index.h("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }), index.h("circle", { cx: "8.5", cy: "8.5", r: "1.5" }), index.h("polyline", { points: "21 15 16 10 5 21" })), index.h("span", null, t('drop_file_here', this.locale), ' ', index.h("span", { class: "mrd-image-field__browse" }, t('browse', this.locale)))))), hasError && index.h("span", { key: 'bd505ef4f4b67c4e9138d8825c6e600f583f4cab', class: "mrd-image-field__error" }, this.error))));
2788
+ const zoneClass = uploadZoneClass('mrd-image-field', {
2789
+ dragging: this.isDragging,
2790
+ error: hasError,
2791
+ disabled: this.disabled || this.uploading,
2792
+ });
2793
+ return (index.h(index.Host, { key: 'ab78d93ab6c810363a8993bea4545f7406680e58' }, index.h("div", { key: '727ae5d9c1cce22d90d26229a9ea5d677abb4b07', class: "mrd-image-field" }, index.h(FieldLabel, { key: 'aab0e9fcc0204e8ea617453b5ca458f683194125', base: "mrd-image-field", label: this.label, required: this.required }), index.h("div", { key: '1241faff26c47a303fd0431201f490c6b8725987', class: zoneClass, onClick: this.handleZoneClick, onDragOver: this.drag.onDragOver, onDragLeave: this.drag.onDragLeave, onDrop: this.drag.onDrop }, index.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 ? (index.h("div", { class: "mrd-image-field__preview-container" }, index.h("div", { class: "mrd-image-field__preview-thumb" }, index.h("img", { class: "mrd-image-field__preview", src: this.previewUrl, alt: this.fileName }), this.uploading && index.h("div", { class: "mrd-image-field__preview-overlay" }, index.h("span", { class: "mrd-image-field__spinner" }))), index.h("div", { class: "mrd-image-field__preview-info" }, index.h("span", { class: "mrd-image-field__preview-name" }, this.fileName), this.uploading && (index.h("span", { class: "mrd-image-field__upload-status" }, t('loading', this.locale)))), !this.uploading && (index.h("button", { class: "mrd-image-field__clear", type: "button", onClick: this.handleClear, "aria-label": t('clear', this.locale) }, t('remove', this.locale))))) : (index.h("div", { class: "mrd-image-field__prompt" }, index.h("svg", { class: "mrd-image-field__upload-icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2" }, index.h("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }), index.h("circle", { cx: "8.5", cy: "8.5", r: "1.5" }), index.h("polyline", { points: "21 15 16 10 5 21" })), index.h("span", null, t('drop_file_here', this.locale), ' ', index.h("span", { class: "mrd-image-field__browse" }, t('browse', this.locale)))))), index.h(FieldError, { key: '01552a994c1e5a9f25129586a95562c32a377046', base: "mrd-image-field", error: this.error }))));
2730
2794
  }
2731
2795
  static get watchers() { return {
2732
2796
  "value": [{
@@ -2734,7 +2798,36 @@ const MrdImageField = class {
2734
2798
  }]
2735
2799
  }; }
2736
2800
  };
2737
- MrdImageField.style = mrdImageFieldScss();
2801
+ MrdImageField.style = mrdImageFieldCss();
2802
+
2803
+ /** Key an embedded view is addressed by (setViewPage etc.). */
2804
+ function viewKeyFor(item) {
2805
+ var _a, _b, _c, _d;
2806
+ if (item.type === index$1.ClientLayoutItemType.RELATED_VIEW)
2807
+ return (_b = (_a = item.relatedClass) !== null && _a !== void 0 ? _a : item.name) !== null && _b !== void 0 ? _b : '';
2808
+ return (_d = (_c = item.dataClass) !== null && _c !== void 0 ? _c : item.name) !== null && _d !== void 0 ? _d : '';
2809
+ }
2810
+ /** Depth-first flatten of the SECTION/GROUP tree. */
2811
+ function flattenItems(items) {
2812
+ const result = [];
2813
+ for (const item of items) {
2814
+ result.push(item);
2815
+ if (item.items)
2816
+ result.push(...flattenItems(item.items));
2817
+ }
2818
+ return result;
2819
+ }
2820
+ /** Build the canonical parent href `/{base}/{tenant}/{fromClass}/{parentId}` from
2821
+ * the object's self href. Empty unless it is a RELATED_VIEW with a fromClass. */
2822
+ function buildContainerHref(item, selfHref, parentId) {
2823
+ if (item.type !== index$1.ClientLayoutItemType.RELATED_VIEW || !item.fromClass || !parentId)
2824
+ return '';
2825
+ const segs = selfHref.split('/').filter(Boolean);
2826
+ if (segs.length < 2)
2827
+ return '';
2828
+ const [base, tenant] = segs;
2829
+ return `/${base}/${tenant}/${item.fromClass}/${parentId}`;
2830
+ }
2738
2831
 
2739
2832
  class CellRenderer {
2740
2833
  static render(column, row, locale) {
@@ -2840,7 +2933,114 @@ class CellRenderer {
2840
2933
  }
2841
2934
  }
2842
2935
 
2843
- 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}`;
2936
+ /** FILE and IMAGE cells share the same download button. */
2937
+ function downloadLink(ctx, href, fileName, label) {
2938
+ return (index.h("button", { class: "mrd-layout-section__download-link", onClick: () => href && ctx.on.download({ href, fileName }) }, index.h("svg", { class: "mrd-layout-section__file-icon", viewBox: "0 0 24 24", "aria-hidden": "true" }, index.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));
2939
+ }
2940
+ function renderSingleFieldValue(ctx, item, value) {
2941
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
2942
+ const dt = item.dataType;
2943
+ switch (dt) {
2944
+ case index$1.ClientLayoutItemFieldDataType.HYPERLINK: {
2945
+ const v = value;
2946
+ const href = (_a = v === null || v === void 0 ? void 0 : v.href) !== null && _a !== void 0 ? _a : String(value);
2947
+ 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;
2948
+ return (index.h("a", { class: "mrd-layout-section__link", href: href, target: "_blank", rel: "noopener noreferrer" }, label));
2949
+ }
2950
+ case index$1.ClientLayoutItemFieldDataType.TEXTBLOCK:
2951
+ return index.h("div", { class: "mrd-layout-section__prose", innerHTML: String(value) });
2952
+ case index$1.ClientLayoutItemFieldDataType.LONGTEXT:
2953
+ return index.h("pre", { class: "mrd-layout-section__pre" }, String(value));
2954
+ case index$1.ClientLayoutItemFieldDataType.JSON:
2955
+ return index.h("pre", { class: "mrd-layout-section__pre", innerHTML: CellRenderer.formatJson(value) });
2956
+ case index$1.ClientLayoutItemFieldDataType.FILE: {
2957
+ const v = value;
2958
+ const fileName = (_e = v === null || v === void 0 ? void 0 : v.fileName) !== null && _e !== void 0 ? _e : String(value);
2959
+ const href = (_f = v === null || v === void 0 ? void 0 : v.href) !== null && _f !== void 0 ? _f : '';
2960
+ return downloadLink(ctx, href, fileName, t('download', ctx.locale));
2961
+ }
2962
+ case index$1.ClientLayoutItemFieldDataType.IMAGE: {
2963
+ const v = value;
2964
+ const href = (_g = v === null || v === void 0 ? void 0 : v.href) !== null && _g !== void 0 ? _g : '';
2965
+ const fileName = (_h = v === null || v === void 0 ? void 0 : v.fileName) !== null && _h !== void 0 ? _h : '';
2966
+ const previewUrl = ctx.imagePreviews[item.name];
2967
+ if (previewUrl) {
2968
+ return (index.h("button", { class: "mrd-layout-section__image-thumb-btn", onClick: () => ctx.on.openImage(previewUrl), title: fileName || undefined }, index.h("img", { class: "mrd-layout-section__image-thumb", src: previewUrl, alt: fileName })));
2969
+ }
2970
+ return downloadLink(ctx, href, fileName, fileName || href);
2971
+ }
2972
+ case index$1.ClientLayoutItemFieldDataType.BOOLEAN:
2973
+ return (index.h("span", { class: `mrd-layout-section__boolean mrd-layout-section__boolean--${value ? 'true' : 'false'}` }, value ? t('yes', ctx.locale) : t('no', ctx.locale)));
2974
+ case index$1.ClientLayoutItemFieldDataType.LIST: {
2975
+ const listItem = ((_j = item.listItems) !== null && _j !== void 0 ? _j : []).find(li => li.key === String(value));
2976
+ const label = (_k = listItem === null || listItem === void 0 ? void 0 : listItem.label) !== null && _k !== void 0 ? _k : String(value);
2977
+ const color = listItem === null || listItem === void 0 ? void 0 : listItem.color;
2978
+ const bg = listItem === null || listItem === void 0 ? void 0 : listItem.backgroundColor;
2979
+ if (color && bg) {
2980
+ return (index.h("span", { class: "mrd-layout-section__badge", style: { color, backgroundColor: bg } }, label));
2981
+ }
2982
+ if (color) {
2983
+ return (index.h("span", { class: "mrd-layout-section__badge-dot-row" }, index.h("span", { class: "mrd-layout-section__badge-dot", style: { backgroundColor: color } }), label));
2984
+ }
2985
+ return label;
2986
+ }
2987
+ case index$1.ClientLayoutItemFieldDataType.SECRET:
2988
+ return value ? index.h("span", { class: "mrd-layout-section__secret-masked" }, '••••••••') : null;
2989
+ default: {
2990
+ const text = CellRenderer.renderValue(dt, value, (_l = item.listItems) !== null && _l !== void 0 ? _l : [], ctx.locale);
2991
+ return text || null;
2992
+ }
2993
+ }
2994
+ }
2995
+ function renderFieldValue(ctx, item, rawValue) {
2996
+ if (rawValue == null || rawValue === '')
2997
+ return null;
2998
+ if (item.multiple && Array.isArray(rawValue)) {
2999
+ const rendered = rawValue.map(v => renderSingleFieldValue(ctx, item, v));
3000
+ if (rendered.every(r => typeof r === 'string' || r == null)) {
3001
+ return rendered.filter(Boolean).join(', ') || null;
3002
+ }
3003
+ return (index.h("span", null, rendered.map((r, i) => (index.h("span", { key: String(i) }, r, i < rendered.length - 1 ? ', ' : '')))));
3004
+ }
3005
+ return renderSingleFieldValue(ctx, item, rawValue);
3006
+ }
3007
+ function renderHistoryBadge(ctx, item, raw) {
3008
+ var _a, _b, _c;
3009
+ const hist = (_a = item.historyEnabled) !== null && _a !== void 0 ? _a : (_b = item.field) === null || _b === void 0 ? void 0 : _b.historyEnabled;
3010
+ if (!hist || !item.name)
3011
+ return null;
3012
+ const history = (_c = raw === null || raw === void 0 ? void 0 : raw.history) !== null && _c !== void 0 ? _c : [];
3013
+ if (!history.length)
3014
+ return null;
3015
+ const sorted = [...history].sort((a, b) => b.until.localeCompare(a.until));
3016
+ const isOpen = ctx.openHistoryField === item.name;
3017
+ return (index.h("span", { class: "mrd-layout-section__history-wrap" }, index.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) => {
3018
+ e.stopPropagation();
3019
+ ctx.on.toggleHistory(isOpen ? null : item.name);
3020
+ } }, index.h("svg", { class: "mrd-layout-section__history-icon", viewBox: "0 0 20 20", fill: "currentColor", "aria-hidden": "true" }, index.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 && (index.h("div", { class: "mrd-layout-section__history-popover", role: "listbox" }, sorted.map((entry, i) => (index.h("div", { key: String(i), class: "mrd-layout-section__history-entry" }, entry.value, " (", t('history_until', ctx.locale), " ", formatDate(entry.until, ctx.locale), ")")))))));
3021
+ }
3022
+ function renderField(ctx, item) {
3023
+ var _a, _b;
3024
+ if (!item.name)
3025
+ return null;
3026
+ const raw = ctx.data[item.name];
3027
+ const hist = (_a = item.historyEnabled) !== null && _a !== void 0 ? _a : (_b = item.field) === null || _b === void 0 ? void 0 : _b.historyEnabled;
3028
+ const rawValue = hist && raw !== null && typeof raw === 'object' && 'current' in raw
3029
+ ? raw.current
3030
+ : raw;
3031
+ const renderedValue = renderFieldValue(ctx, item, rawValue);
3032
+ if (item.header) {
3033
+ return (index.h("h1", { class: "mrd-layout-section__field-header", key: item.name }, typeof renderedValue === 'string' ? renderedValue : rawValue != null ? String(rawValue) : item.label));
3034
+ }
3035
+ if (renderedValue == null)
3036
+ return null;
3037
+ const isBlock = item.dataType === index$1.ClientLayoutItemFieldDataType.TEXTBLOCK
3038
+ || item.dataType === index$1.ClientLayoutItemFieldDataType.LONGTEXT
3039
+ || item.dataType === index$1.ClientLayoutItemFieldDataType.JSON;
3040
+ return (index.h("div", { class: `mrd-layout-section__field${isBlock ? ' mrd-layout-section__field--block' : ''}`, key: item.name }, index.h("span", { class: "mrd-layout-section__field-label" }, item.label), index.h("span", { class: "mrd-layout-section__field-value" }, renderedValue, renderHistoryBadge(ctx, item, raw))));
3041
+ }
3042
+
3043
+ 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}`;
2844
3044
 
2845
3045
  const MrdLayoutSection = class {
2846
3046
  constructor(hostRef) {
@@ -2922,14 +3122,8 @@ const MrdLayoutSection = class {
2922
3122
  }
2923
3123
  }
2924
3124
  }
2925
- viewKeyFor(item) {
2926
- var _a, _b, _c, _d;
2927
- if (item.type === index$1.ClientLayoutItemType.RELATED_VIEW)
2928
- return (_b = (_a = item.relatedClass) !== null && _a !== void 0 ? _a : item.name) !== null && _b !== void 0 ? _b : '';
2929
- return (_d = (_c = item.dataClass) !== null && _c !== void 0 ? _c : item.name) !== null && _d !== void 0 ? _d : '';
2930
- }
2931
3125
  emitLoadImages() {
2932
- for (const item of this.flattenItems(this.items)) {
3126
+ for (const item of flattenItems(this.items)) {
2933
3127
  if (item.type === index$1.ClientLayoutItemType.FIELD && item.dataType === index$1.ClientLayoutItemFieldDataType.IMAGE) {
2934
3128
  const fieldName = item.name;
2935
3129
  const raw = this.data[fieldName];
@@ -2939,15 +3133,6 @@ const MrdLayoutSection = class {
2939
3133
  }
2940
3134
  }
2941
3135
  }
2942
- flattenItems(items) {
2943
- const result = [];
2944
- for (const item of items) {
2945
- result.push(item);
2946
- if (item.items)
2947
- result.push(...this.flattenItems(item.items));
2948
- }
2949
- return result;
2950
- }
2951
3136
  /** Inject search results. Pass dataClass to target a specific SEARCH item; omit when there is only one. */
2952
3137
  async setSearchResults(results, dataClass) {
2953
3138
  const key = dataClass !== null && dataClass !== void 0 ? dataClass : this.resolveSearchKey();
@@ -3013,113 +3198,26 @@ const MrdLayoutSection = class {
3013
3198
  }
3014
3199
  resolveSearchKey() {
3015
3200
  var _a;
3016
- const items = this.flattenItems(this.items).filter(i => i.type === index$1.ClientLayoutItemType.SEARCH);
3201
+ const items = flattenItems(this.items).filter(i => i.type === index$1.ClientLayoutItemType.SEARCH);
3017
3202
  if (items.length === 1)
3018
3203
  return (_a = items[0].dataClass) !== null && _a !== void 0 ? _a : null;
3019
3204
  return null;
3020
3205
  }
3021
- renderSingleFieldValue(item, value) {
3022
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
3023
- const dt = item.dataType;
3024
- switch (dt) {
3025
- case index$1.ClientLayoutItemFieldDataType.HYPERLINK: {
3026
- const v = value;
3027
- const href = (_a = v === null || v === void 0 ? void 0 : v.href) !== null && _a !== void 0 ? _a : String(value);
3028
- 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;
3029
- return (index.h("a", { class: "mrd-layout-section__link", href: href, target: "_blank", rel: "noopener noreferrer" }, label));
3030
- }
3031
- case index$1.ClientLayoutItemFieldDataType.TEXTBLOCK:
3032
- return index.h("div", { class: "mrd-layout-section__prose", innerHTML: String(value) });
3033
- case index$1.ClientLayoutItemFieldDataType.LONGTEXT:
3034
- return index.h("pre", { class: "mrd-layout-section__pre" }, String(value));
3035
- case index$1.ClientLayoutItemFieldDataType.JSON:
3036
- return index.h("pre", { class: "mrd-layout-section__pre", innerHTML: CellRenderer.formatJson(value) });
3037
- case index$1.ClientLayoutItemFieldDataType.FILE: {
3038
- const v = value;
3039
- const fileName = (_e = v === null || v === void 0 ? void 0 : v.fileName) !== null && _e !== void 0 ? _e : String(value);
3040
- const href = (_f = v === null || v === void 0 ? void 0 : v.href) !== null && _f !== void 0 ? _f : '';
3041
- return (index.h("button", { class: "mrd-layout-section__download-link", onClick: () => href && this.mrdDownload.emit({ href, fileName }) }, index.h("svg", { class: "mrd-layout-section__file-icon", viewBox: "0 0 24 24", "aria-hidden": "true" }, index.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)));
3042
- }
3043
- case index$1.ClientLayoutItemFieldDataType.IMAGE: {
3044
- const v = value;
3045
- const href = (_g = v === null || v === void 0 ? void 0 : v.href) !== null && _g !== void 0 ? _g : '';
3046
- const fileName = (_h = v === null || v === void 0 ? void 0 : v.fileName) !== null && _h !== void 0 ? _h : '';
3047
- const previewUrl = this.imagePreviews[item.name];
3048
- if (previewUrl) {
3049
- return (index.h("button", { class: "mrd-layout-section__image-thumb-btn", onClick: () => { this.imagePreviewUrl = previewUrl; }, title: fileName || undefined }, index.h("img", { class: "mrd-layout-section__image-thumb", src: previewUrl, alt: fileName })));
3050
- }
3051
- return (index.h("button", { class: "mrd-layout-section__download-link", onClick: () => href && this.mrdDownload.emit({ href, fileName }) }, index.h("svg", { class: "mrd-layout-section__file-icon", viewBox: "0 0 24 24", "aria-hidden": "true" }, index.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));
3052
- }
3053
- case index$1.ClientLayoutItemFieldDataType.BOOLEAN:
3054
- return (index.h("span", { class: `mrd-layout-section__boolean mrd-layout-section__boolean--${value ? 'true' : 'false'}` }, value ? t('yes', this.locale) : t('no', this.locale)));
3055
- case index$1.ClientLayoutItemFieldDataType.LIST: {
3056
- const listItem = ((_j = item.listItems) !== null && _j !== void 0 ? _j : []).find(li => li.key === String(value));
3057
- const label = (_k = listItem === null || listItem === void 0 ? void 0 : listItem.label) !== null && _k !== void 0 ? _k : String(value);
3058
- const color = listItem === null || listItem === void 0 ? void 0 : listItem.color;
3059
- const bg = listItem === null || listItem === void 0 ? void 0 : listItem.backgroundColor;
3060
- if (color && bg) {
3061
- return (index.h("span", { class: "mrd-layout-section__badge", style: { color, backgroundColor: bg } }, label));
3062
- }
3063
- if (color) {
3064
- return (index.h("span", { class: "mrd-layout-section__badge-dot-row" }, index.h("span", { class: "mrd-layout-section__badge-dot", style: { backgroundColor: color } }), label));
3065
- }
3066
- return label;
3067
- }
3068
- case index$1.ClientLayoutItemFieldDataType.SECRET:
3069
- return value ? index.h("span", { class: "mrd-layout-section__secret-masked" }, '••••••••') : null;
3070
- default: {
3071
- const text = CellRenderer.renderValue(dt, value, (_l = item.listItems) !== null && _l !== void 0 ? _l : [], this.locale);
3072
- return text || null;
3073
- }
3074
- }
3075
- }
3076
- renderFieldValue(item, rawValue) {
3077
- if (rawValue == null || rawValue === '')
3078
- return null;
3079
- if (item.multiple && Array.isArray(rawValue)) {
3080
- const rendered = rawValue.map(v => this.renderSingleFieldValue(item, v));
3081
- if (rendered.every(r => typeof r === 'string' || r == null)) {
3082
- return rendered.filter(Boolean).join(', ') || null;
3083
- }
3084
- return (index.h("span", null, rendered.map((r, i) => (index.h("span", { key: String(i) }, r, i < rendered.length - 1 ? ', ' : '')))));
3085
- }
3086
- return this.renderSingleFieldValue(item, rawValue);
3087
- }
3088
- renderHistoryBadge(item, raw) {
3089
- var _a, _b, _c;
3090
- const hist = (_a = item.historyEnabled) !== null && _a !== void 0 ? _a : (_b = item.field) === null || _b === void 0 ? void 0 : _b.historyEnabled;
3091
- if (!hist || !item.name)
3092
- return null;
3093
- const history = (_c = raw === null || raw === void 0 ? void 0 : raw.history) !== null && _c !== void 0 ? _c : [];
3094
- if (!history.length)
3095
- return null;
3096
- const sorted = [...history].sort((a, b) => b.until.localeCompare(a.until));
3097
- const isOpen = this.openHistoryField === item.name;
3098
- const { locale } = this;
3099
- return (index.h("span", { class: "mrd-layout-section__history-wrap" }, index.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) => {
3100
- e.stopPropagation();
3101
- this.openHistoryField = isOpen ? null : item.name;
3102
- } }, index.h("svg", { class: "mrd-layout-section__history-icon", viewBox: "0 0 20 20", fill: "currentColor", "aria-hidden": "true" }, index.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 && (index.h("div", { class: "mrd-layout-section__history-popover", role: "listbox" }, sorted.map((entry, i) => (index.h("div", { key: String(i), class: "mrd-layout-section__history-entry" }, entry.value, " (", t('history_until', locale), " ", formatDate(entry.until, locale), ")")))))));
3206
+ fieldCtx() {
3207
+ return {
3208
+ locale: this.locale,
3209
+ data: this.data,
3210
+ imagePreviews: this.imagePreviews,
3211
+ openHistoryField: this.openHistoryField,
3212
+ on: {
3213
+ download: detail => this.mrdDownload.emit(detail),
3214
+ openImage: url => { this.imagePreviewUrl = url; },
3215
+ toggleHistory: fieldName => { this.openHistoryField = fieldName; },
3216
+ },
3217
+ };
3103
3218
  }
3104
3219
  renderField(item) {
3105
- var _a, _b;
3106
- if (!item.name)
3107
- return null;
3108
- const raw = this.data[item.name];
3109
- const hist = (_a = item.historyEnabled) !== null && _a !== void 0 ? _a : (_b = item.field) === null || _b === void 0 ? void 0 : _b.historyEnabled;
3110
- const rawValue = hist && raw !== null && typeof raw === 'object' && 'current' in raw
3111
- ? raw.current
3112
- : raw;
3113
- const renderedValue = this.renderFieldValue(item, rawValue);
3114
- if (item.header) {
3115
- return (index.h("h1", { class: "mrd-layout-section__field-header", key: item.name }, typeof renderedValue === 'string' ? renderedValue : rawValue != null ? String(rawValue) : item.label));
3116
- }
3117
- if (renderedValue == null)
3118
- return null;
3119
- const isBlock = item.dataType === index$1.ClientLayoutItemFieldDataType.TEXTBLOCK
3120
- || item.dataType === index$1.ClientLayoutItemFieldDataType.LONGTEXT
3121
- || item.dataType === index$1.ClientLayoutItemFieldDataType.JSON;
3122
- return (index.h("div", { class: `mrd-layout-section__field${isBlock ? ' mrd-layout-section__field--block' : ''}`, key: item.name }, index.h("span", { class: "mrd-layout-section__field-label" }, item.label), index.h("span", { class: "mrd-layout-section__field-value" }, renderedValue, this.renderHistoryBadge(item, raw))));
3220
+ return renderField(this.fieldCtx(), item);
3123
3221
  }
3124
3222
  renderRelation(item) {
3125
3223
  var _a, _b, _c;
@@ -3152,7 +3250,7 @@ const MrdLayoutSection = class {
3152
3250
  }
3153
3251
  renderRelatedView(item) {
3154
3252
  var _a, _b, _c, _d, _e, _f, _g, _h;
3155
- const key = this.viewKeyFor(item);
3253
+ const key = viewKeyFor(item);
3156
3254
  if (!key)
3157
3255
  return null;
3158
3256
  if (!item.view)
@@ -3167,22 +3265,11 @@ const MrdLayoutSection = class {
3167
3265
  // Canonical parent href for single-container seeding: use the RELATED_VIEW's
3168
3266
  // fromClass (base class) rather than the route class, so polymorphic subtypes
3169
3267
  // resolve to the same container the documents actually reference.
3170
- const containerHref = this.buildContainerHref(item, selfHref, parentId);
3268
+ const containerHref = buildContainerHref(item, selfHref, parentId);
3171
3269
  return (index.h("div", { class: "mrd-layout-section__related-view", key: `view-${key}` }, showTitle && item.label && index.h("h3", { class: "mrd-layout-section__related-view-title" }, item.label), docArchetype
3172
3270
  ? this.renderDocumentContainer(item, key, parentId, docArchetype, containerHref)
3173
3271
  : this.renderTable(item, key, parentId)));
3174
3272
  }
3175
- /** Build the canonical parent href `/{base}/{tenant}/{fromClass}/{parentId}` from
3176
- * the object's self href. Empty unless it is a RELATED_VIEW with a fromClass. */
3177
- buildContainerHref(item, selfHref, parentId) {
3178
- if (item.type !== index$1.ClientLayoutItemType.RELATED_VIEW || !item.fromClass || !parentId)
3179
- return '';
3180
- const segs = selfHref.split('/').filter(Boolean);
3181
- if (segs.length < 2)
3182
- return '';
3183
- const [base, tenant] = segs;
3184
- return `/${base}/${tenant}/${item.fromClass}/${parentId}`;
3185
- }
3186
3273
  /** Document collection view: owns the view-switch + collection actions and
3187
3274
  * swaps between the folder tree and the flat table. Events are re-emitted to
3188
3275
  * the host with the view key, exactly as the raw list/table events were. */
@@ -3283,7 +3370,7 @@ const MrdLayoutSection = class {
3283
3370
  }
3284
3371
  render() {
3285
3372
  const docArchetype = index$1.resolveArchetype(this.archetypes, index$1.ARCHETYPE_DOCUMENT);
3286
- return (index.h(index.Host, { key: '231f5c3e282375b5850291611645fe3c904831bb' }, index.h("div", { key: '314e39ec3aa1eabeb1a98f6e6d63fcf07e13ccec', class: "mrd-layout-section" }, docArchetype
3373
+ return (index.h(index.Host, { key: '5d778188356a25ea13d45745dc5ed573ab2b2ef0' }, index.h("div", { key: '0b673a4bcf8b36cd21662bb8a3506cc3f30edb04', class: "mrd-layout-section" }, docArchetype
3287
3374
  ? this.renderDocumentObject(docArchetype)
3288
3375
  : this.items.map(item => this.renderItem(item))), this.renderImageModal()));
3289
3376
  }
@@ -3294,9 +3381,9 @@ const MrdLayoutSection = class {
3294
3381
  }]
3295
3382
  }; }
3296
3383
  };
3297
- MrdLayoutSection.style = mrdLayoutSectionScss();
3384
+ MrdLayoutSection.style = mrdLayoutSectionCss();
3298
3385
 
3299
- 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)}`;
3386
+ 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}`;
3300
3387
 
3301
3388
  const MrdListField = class {
3302
3389
  constructor(hostRef) {
@@ -3319,22 +3406,12 @@ const MrdListField = class {
3319
3406
  if (this.multiple) {
3320
3407
  const vals = Array.from(select.selectedOptions).map(o => o.value);
3321
3408
  this.selected = vals;
3322
- if (this.required && !validateRequired(vals)) {
3323
- this.error = t('required', this.locale);
3324
- }
3325
- else {
3326
- this.error = '';
3327
- }
3409
+ this.error = requiredError(vals, this.required, this.locale);
3328
3410
  this.mrdChange.emit({ name: this.name, value: vals });
3329
3411
  }
3330
3412
  else {
3331
3413
  const val = select.value;
3332
- if (this.required && !validateRequired(val)) {
3333
- this.error = t('required', this.locale);
3334
- }
3335
- else {
3336
- this.error = '';
3337
- }
3414
+ this.error = requiredError(val, this.required, this.locale);
3338
3415
  this.mrdChange.emit({ name: this.name, value: val });
3339
3416
  }
3340
3417
  };
@@ -3349,12 +3426,7 @@ const MrdListField = class {
3349
3426
  else {
3350
3427
  this.selected = [...this.selected, key];
3351
3428
  }
3352
- if (this.required && !validateRequired(this.selected)) {
3353
- this.error = t('required', this.locale);
3354
- }
3355
- else {
3356
- this.error = '';
3357
- }
3429
+ this.error = requiredError(this.selected, this.required, this.locale);
3358
3430
  this.mrdChange.emit({ name: this.name, value: this.selected });
3359
3431
  };
3360
3432
  }
@@ -3378,22 +3450,22 @@ const MrdListField = class {
3378
3450
  const hasError = !!this.error;
3379
3451
  const currentValue = Array.isArray(this.value) ? ((_a = this.value[0]) !== null && _a !== void 0 ? _a : '') : ((_b = this.value) !== null && _b !== void 0 ? _b : '');
3380
3452
  if (this.multiple) {
3381
- return (index.h(index.Host, null, index.h("div", { class: "mrd-list-field" }, this.label && (index.h("label", { class: `mrd-list-field__label${this.required ? ' mrd-list-field__label--required' : ''}` }, this.label)), index.h("div", { class: `mrd-list-field__checkbox-list${hasError ? ' mrd-list-field__checkbox-list--error' : ''}` }, this.listItems.map(lv => {
3453
+ return (index.h(index.Host, null, index.h("div", { class: "mrd-list-field" }, index.h(FieldLabel, { base: "mrd-list-field", label: this.label, required: this.required }), index.h("div", { class: controlClass('mrd-list-field', hasError, 'checkbox-list') }, this.listItems.map(lv => {
3382
3454
  var _a, _b;
3383
3455
  return (index.h("label", { key: lv.key, class: "mrd-list-field__checkbox-item" }, index.h("input", { type: "checkbox", checked: this.selected.includes(lv.key), disabled: this.disabled, onChange: () => this.toggleCheckbox(lv.key) }), (lv.color || lv.backgroundColor) && (index.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 : '' } })), index.h("span", null, lv.label)));
3384
- })), hasError && index.h("span", { class: "mrd-list-field__error" }, this.error))));
3456
+ })), index.h(FieldError, { base: "mrd-list-field", error: this.error }))));
3385
3457
  }
3386
- return (index.h(index.Host, null, index.h("div", { class: "mrd-list-field" }, this.label && (index.h("label", { class: `mrd-list-field__label${this.required ? ' mrd-list-field__label--required' : ''}` }, this.label)), index.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 }, index.h("option", { value: "" }, t('select_placeholder', this.locale)), this.listItems.map(lv => {
3458
+ return (index.h(index.Host, null, index.h("div", { class: "mrd-list-field" }, index.h(FieldLabel, { base: "mrd-list-field", label: this.label, required: this.required }), index.h("select", { class: controlClass('mrd-list-field', hasError, 'select'), name: this.name, required: this.required, disabled: this.disabled, onChange: this.handleSelectChange, onBlur: this.handleBlur }, index.h("option", { value: "" }, t('select_placeholder', this.locale)), this.listItems.map(lv => {
3387
3459
  var _a, _b;
3388
3460
  const bg = (_b = (_a = lv.backgroundColor) !== null && _a !== void 0 ? _a : lv.color) !== null && _b !== void 0 ? _b : null;
3389
3461
  const style = bg ? { backgroundColor: bg, color: this.getContrastColor(bg) } : {};
3390
3462
  return (index.h("option", { key: lv.key, value: lv.key, selected: lv.key === currentValue, style: style }, lv.label));
3391
- })), hasError && index.h("span", { class: "mrd-list-field__error" }, this.error))));
3463
+ })), index.h(FieldError, { base: "mrd-list-field", error: this.error }))));
3392
3464
  }
3393
3465
  };
3394
- MrdListField.style = mrdListFieldScss();
3466
+ MrdListField.style = mrdListFieldCss();
3395
3467
 
3396
- 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)}`;
3468
+ 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}`;
3397
3469
 
3398
3470
  const MrdLongtextField = class {
3399
3471
  constructor(hostRef) {
@@ -3414,23 +3486,17 @@ const MrdLongtextField = class {
3414
3486
  };
3415
3487
  this.handleBlur = (e) => {
3416
3488
  const val = e.target.value;
3417
- if (this.required && !validateRequired(val)) {
3418
- this.error = t('required', this.locale);
3419
- }
3420
- else {
3421
- this.error = '';
3422
- }
3489
+ this.error = requiredError(val, this.required, this.locale);
3423
3490
  this.mrdBlur.emit({ name: this.name, value: val });
3424
3491
  };
3425
3492
  }
3426
3493
  render() {
3427
- const hasError = !!this.error;
3428
- return (index.h(index.Host, { key: 'f00f81944748f8f09e22d44befe5e288456b7cc8' }, index.h("div", { key: '7b0ae9cf5b6b684cddb648fe4db6005494322535', class: "mrd-longtext-field" }, this.label && (index.h("label", { key: '3fc6a8710d0e98fe685c45d214a88ae1b0947973', class: `mrd-longtext-field__label${this.required ? ' mrd-longtext-field__label--required' : ''}` }, this.label)), this.disabled ? (index.h("pre", { class: "mrd-longtext-field__content" }, this.value)) : (index.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 && index.h("span", { key: 'e96f1dbc6c00a1602f4ce3c97d514a229aeb7cb7', class: "mrd-longtext-field__error" }, this.error))));
3494
+ return (index.h(index.Host, { key: '1d23db1324fa0fc97a07fdae65f2d84e43419a72' }, index.h("div", { key: '0ad2b262088aa3745f088a44af26649593805840', class: "mrd-longtext-field" }, index.h(FieldLabel, { key: '5a78739d6ced4e2df77589b64c66401819c4b5c7', base: "mrd-longtext-field", label: this.label, required: this.required }), this.disabled ? (index.h("pre", { class: "mrd-longtext-field__content" }, this.value)) : (index.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)), index.h(FieldError, { key: '5b870a75b518e2808518b83c9abebf8589a86108', base: "mrd-longtext-field", error: this.error }))));
3429
3495
  }
3430
3496
  };
3431
- MrdLongtextField.style = mrdLongtextFieldScss();
3497
+ MrdLongtextField.style = mrdLongtextFieldCss();
3432
3498
 
3433
- 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)}`;
3499
+ 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)}`;
3434
3500
 
3435
3501
  const MrdNumberField = class {
3436
3502
  constructor(hostRef) {
@@ -3501,12 +3567,12 @@ const MrdNumberField = class {
3501
3567
  const hasError = !!this.error;
3502
3568
  const suffix = this.dataType === index$1.ClientLayoutItemFieldDataType.PERCENTAGE ? '%' :
3503
3569
  this.dataType === index$1.ClientLayoutItemFieldDataType.DECIMAL ? '' : '';
3504
- return (index.h(index.Host, { key: 'b034a3cc8d841641c0ec167e138904586b044121' }, index.h("div", { key: '7379bfadb8bd0c4e0a945a37013053a4e22477ab', class: "mrd-number-field" }, this.label && (index.h("label", { key: '5518d40b7158e17704633c2b95ac7e3efc0c5568', class: `mrd-number-field__label${this.required ? ' mrd-number-field__label--required' : ''}` }, this.label)), index.h("div", { key: '38ad9f3c945d66c23bd77c743306e916eaefed7f', class: "mrd-number-field__input-wrapper" }, index.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 && index.h("span", { key: '09f5a58b769c81acdf4bdd48f9325934c4bb875d', class: "mrd-number-field__error" }, this.error))));
3570
+ return (index.h(index.Host, { key: 'fd7220e0a7f574ab0c61094a9ba7fd764e1adafd' }, index.h("div", { key: 'ef6118a339c9766f187cd2b1fa3fcc85ef8cb69f', class: "mrd-number-field" }, index.h(FieldLabel, { key: '015207ae65df07f7ee7bbc24ccab45524176dbf7', base: "mrd-number-field", label: this.label, required: this.required }), index.h("div", { key: '954b99cbcf4002b0336810e354f1a46d39cb8076', class: "mrd-number-field__input-wrapper" }, index.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 })), index.h(FieldError, { key: '87e12bd737aed0a845470cef66d7a6d61d11de0b', base: "mrd-number-field", error: this.error }))));
3505
3571
  }
3506
3572
  };
3507
- MrdNumberField.style = mrdNumberFieldScss();
3573
+ MrdNumberField.style = mrdNumberFieldCss();
3508
3574
 
3509
- 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)}`;
3575
+ 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}`;
3510
3576
 
3511
3577
  const MrdRelationField = class {
3512
3578
  constructor(hostRef) {
@@ -3607,12 +3673,7 @@ const MrdRelationField = class {
3607
3673
  this.showResults = false;
3608
3674
  this.mrdChange.emit({ name: this.name, value: result.id });
3609
3675
  }
3610
- if (this.required && !validateRequired(this.selectedItems)) {
3611
- this.error = t('required', this.locale);
3612
- }
3613
- else {
3614
- this.error = '';
3615
- }
3676
+ this.error = requiredError(this.selectedItems, this.required, this.locale);
3616
3677
  };
3617
3678
  this.handleRemoveSelected = (id) => {
3618
3679
  this.selectedItems = this.selectedItems.filter(i => i.id !== id);
@@ -3621,12 +3682,7 @@ const MrdRelationField = class {
3621
3682
  };
3622
3683
  this.handleDropdownChange = (e) => {
3623
3684
  const val = e.target.value;
3624
- if (this.required && !validateRequired(val)) {
3625
- this.error = t('required', this.locale);
3626
- }
3627
- else {
3628
- this.error = '';
3629
- }
3685
+ this.error = requiredError(val, this.required, this.locale);
3630
3686
  this.mrdChange.emit({ name: this.name, value: val });
3631
3687
  };
3632
3688
  this.handleBlur = () => {
@@ -3737,19 +3793,19 @@ const MrdRelationField = class {
3737
3793
  const hasError = !!this.error;
3738
3794
  if (this.editBehavior === index$1.ClientLayoutItemRelationEditBehavior.DROPDOWN) {
3739
3795
  const currentValue = this.getValueHref();
3740
- return (index.h(index.Host, null, index.h("div", { class: "mrd-relation-field" }, this.label && (index.h("label", { class: `mrd-relation-field__label${this.required ? ' mrd-relation-field__label--required' : ''}` }, this.label)), index.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 }, index.h("option", { value: "" }, t('select_placeholder', this.locale)), this.allRecords.map(record => (index.h("option", { key: record.id, value: record.id, selected: record.id === currentValue }, record.label)))), hasError && index.h("span", { class: "mrd-relation-field__error" }, this.error))));
3796
+ return (index.h(index.Host, null, index.h("div", { class: "mrd-relation-field" }, index.h(FieldLabel, { base: "mrd-relation-field", label: this.label, required: this.required }), index.h("select", { class: controlClass('mrd-relation-field', hasError, 'select'), name: this.name, required: this.required, disabled: this.disabled, onChange: this.handleDropdownChange }, index.h("option", { value: "" }, t('select_placeholder', this.locale)), this.allRecords.map(record => (index.h("option", { key: record.id, value: record.id, selected: record.id === currentValue }, record.label)))), index.h(FieldError, { base: "mrd-relation-field", error: this.error }))));
3741
3797
  }
3742
3798
  if (this.displayType === index$1.ClientLayoutItemRelationDisplayType.DROPDOWN) {
3743
3799
  const currentValue = Array.isArray(this.value) ? ((_a = this.value[0]) !== null && _a !== void 0 ? _a : '') : ((_b = this.value) !== null && _b !== void 0 ? _b : '');
3744
- return (index.h(index.Host, null, index.h("div", { class: "mrd-relation-field" }, this.label && (index.h("label", { class: `mrd-relation-field__label${this.required ? ' mrd-relation-field__label--required' : ''}` }, this.label)), index.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 }, index.h("option", { value: "" }, t('select_placeholder', this.locale)), this.dropdownValues.map(dv => (index.h("option", { key: dv.key, value: dv.key, selected: dv.key === currentValue }, dv.label)))), hasError && index.h("span", { class: "mrd-relation-field__error" }, this.error))));
3800
+ return (index.h(index.Host, null, index.h("div", { class: "mrd-relation-field" }, index.h(FieldLabel, { base: "mrd-relation-field", label: this.label, required: this.required }), index.h("select", { class: controlClass('mrd-relation-field', hasError, 'select'), name: this.name, required: this.required, disabled: this.disabled, onChange: this.handleDropdownChange }, index.h("option", { value: "" }, t('select_placeholder', this.locale)), this.dropdownValues.map(dv => (index.h("option", { key: dv.key, value: dv.key, selected: dv.key === currentValue }, dv.label)))), index.h(FieldError, { base: "mrd-relation-field", error: this.error }))));
3745
3801
  }
3746
3802
  // SEARCH mode
3747
- const labelEl = this.label && (index.h("label", { class: `mrd-relation-field__label${this.required ? ' mrd-relation-field__label--required' : ''}` }, this.label));
3803
+ const labelEl = index.h(FieldLabel, { base: "mrd-relation-field", label: this.label, required: this.required });
3748
3804
  // Single selection: show selected value as a badge, hide the search input
3749
3805
  if (!this.multiple && this.selectedItems.length > 0) {
3750
- return (index.h(index.Host, null, index.h("div", { class: "mrd-relation-field" }, labelEl, index.h("div", { class: `mrd-relation-field__selected-value${hasError ? ' mrd-relation-field__selected-value--error' : ''}` }, index.h("span", { class: "mrd-relation-field__selected-name" }, this.selectedItems[0].label), index.h("button", { type: "button", class: "mrd-relation-field__selected-clear", onClick: this.clearSelection, "aria-label": t('remove', this.locale) }, "\u2715")), hasError && index.h("span", { class: "mrd-relation-field__error" }, this.error))));
3806
+ return (index.h(index.Host, null, index.h("div", { class: "mrd-relation-field" }, labelEl, index.h("div", { class: `mrd-relation-field__selected-value${hasError ? ' mrd-relation-field__selected-value--error' : ''}` }, index.h("span", { class: "mrd-relation-field__selected-name" }, this.selectedItems[0].label), index.h("button", { type: "button", class: "mrd-relation-field__selected-clear", onClick: this.clearSelection, "aria-label": t('remove', this.locale) }, "\u2715")), index.h(FieldError, { base: "mrd-relation-field", error: this.error }))));
3751
3807
  }
3752
- return (index.h(index.Host, null, index.h("div", { class: "mrd-relation-field" }, labelEl, this.multiple && this.selectedItems.length > 0 && (index.h("div", { class: "mrd-relation-field__tags" }, this.selectedItems.map(item => (index.h("span", { key: item.id, class: "mrd-relation-field__tag" }, item.label, index.h("button", { type: "button", class: "mrd-relation-field__tag-remove", onClick: () => this.handleRemoveSelected(item.id), "aria-label": t('remove', this.locale) }, "\u2715")))))), index.h("div", { class: "mrd-relation-field__search-wrapper" }, index.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 && (index.h("span", { class: "mrd-relation-field__spinner", "aria-label": t('loading', this.locale) }))), this.showResults && (index.h("div", { class: "mrd-relation-field__results" }, this.searchResults.length === 0 && !this.isLoading ? (index.h("div", { class: "mrd-relation-field__no-results" }, t('no_results', this.locale))) : (this.searchResults.map((result, i) => (index.h("div", { key: result.id, class: `mrd-relation-field__result-item${i === this.highlightedIndex ? ' mrd-relation-field__result-item--highlighted' : ''}`, onMouseDown: () => this.handleResultSelect(result) }, index.h("span", { class: "mrd-relation-field__result-label" }, result.label), result.description && (index.h("span", { class: "mrd-relation-field__result-desc" }, result.description)))))))), hasError && index.h("span", { class: "mrd-relation-field__error" }, this.error))));
3808
+ return (index.h(index.Host, null, index.h("div", { class: "mrd-relation-field" }, labelEl, this.multiple && this.selectedItems.length > 0 && (index.h("div", { class: "mrd-relation-field__tags" }, this.selectedItems.map(item => (index.h("span", { key: item.id, class: "mrd-relation-field__tag" }, item.label, index.h("button", { type: "button", class: "mrd-relation-field__tag-remove", onClick: () => this.handleRemoveSelected(item.id), "aria-label": t('remove', this.locale) }, "\u2715")))))), index.h("div", { class: "mrd-relation-field__search-wrapper" }, index.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 && (index.h("span", { class: "mrd-relation-field__spinner", "aria-label": t('loading', this.locale) }))), this.showResults && (index.h("div", { class: "mrd-relation-field__results" }, this.searchResults.length === 0 && !this.isLoading ? (index.h("div", { class: "mrd-relation-field__no-results" }, t('no_results', this.locale))) : (this.searchResults.map((result, i) => (index.h("div", { key: result.id, class: `mrd-relation-field__result-item${i === this.highlightedIndex ? ' mrd-relation-field__result-item--highlighted' : ''}`, onMouseDown: () => this.handleResultSelect(result) }, index.h("span", { class: "mrd-relation-field__result-label" }, result.label), result.description && (index.h("span", { class: "mrd-relation-field__result-desc" }, result.description)))))))), index.h(FieldError, { base: "mrd-relation-field", error: this.error }))));
3753
3809
  }
3754
3810
  get el() { return index.getElement(this); }
3755
3811
  static get watchers() { return {
@@ -3761,9 +3817,9 @@ const MrdRelationField = class {
3761
3817
  }]
3762
3818
  }; }
3763
3819
  };
3764
- MrdRelationField.style = mrdRelationFieldScss();
3820
+ MrdRelationField.style = mrdRelationFieldCss();
3765
3821
 
3766
- 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}`;
3822
+ 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}`;
3767
3823
 
3768
3824
  const MrdSecretField = class {
3769
3825
  constructor(hostRef) {
@@ -3784,38 +3840,439 @@ const MrdSecretField = class {
3784
3840
  };
3785
3841
  this.handleBlur = (e) => {
3786
3842
  const val = e.target.value;
3787
- if (this.required && !validateRequired(val)) {
3788
- this.error = t('required', this.locale);
3789
- }
3790
- else {
3791
- this.error = '';
3792
- }
3843
+ this.error = requiredError(val, this.required, this.locale);
3793
3844
  this.mrdBlur.emit({ name: this.name, value: val });
3794
3845
  };
3795
3846
  }
3796
3847
  render() {
3797
- const hasError = !!this.error;
3798
- return (index.h(index.Host, { key: 'c850ec5bc5967ca0aefca7d7cb65ecae121a9dc1' }, index.h("div", { key: '3249ffbc441422af054a20806dd8dfce954a8ffc', class: "mrd-secret-field" }, this.label && (index.h("label", { key: '0b4a86da9cafad32f153af1bc5487a4e9b941e2f', class: `mrd-secret-field__label${this.required ? ' mrd-secret-field__label--required' : ''}` }, this.label)), this.disabled
3848
+ return (index.h(index.Host, { key: 'acb865b235652feba713aedda7a7fccbdc01ad20' }, index.h("div", { key: 'e7471ade9c683cac9469ec89778c967badb046f9', class: "mrd-secret-field" }, index.h(FieldLabel, { key: '2f9b864779ead352fda53af8597ddcd31377249d', base: "mrd-secret-field", label: this.label, required: this.required }), this.disabled
3799
3849
  ? (index.h("span", { class: "mrd-secret-field__masked", "aria-label": this.label }, this.value ? '••••••••' : ''))
3800
- : (index.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 && index.h("span", { key: 'b0d0105f3d43d2e214f070b24e745dbce0e33977', class: "mrd-secret-field__error" }, this.error))));
3850
+ : (index.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 })), index.h(FieldError, { key: '438418e2cf0f53a6c247d5f332aae8e8978b94ea', base: "mrd-secret-field", error: this.error }))));
3801
3851
  }
3802
3852
  };
3803
- MrdSecretField.style = mrdSecretFieldScss();
3853
+ MrdSecretField.style = mrdSecretFieldCss();
3804
3854
 
3805
- 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}`;
3806
-
3807
- const BUFFER = 10;
3808
- /** Wacht deze tijd (ms) na het laatste scroll-event voordat pagina's worden
3809
- * aangevraagd. Pagina's die de gebruiker snel voorbij scrollt worden zo geskipt. */
3810
- const REQUEST_DEBOUNCE_MS = 150;
3811
- /** Breedte van de filterpopup in px — voor overflow-correctie. */
3812
- const POPUP_WIDTH = 280;
3855
+ /**
3856
+ * Pure sort/filter/aggregation query logic for mrd-table.
3857
+ * No component state — everything is passed in.
3858
+ */
3813
3859
  const TEXT_TYPES = new Set(['TEXT', 'TEXTBLOCK', 'EMAIL', 'HYPERLINK']);
3814
3860
  const NUMERIC_TYPES = new Set(['INTEGER', 'DECIMAL', 'PERCENTAGE', 'CURRENCY']);
3815
3861
  const DATE_TYPES = new Set(['DATE', 'DATETIME', 'TIME']);
3816
3862
  const NO_FILTER_TYPES = new Set(['FILE', 'IMAGE']);
3817
3863
  /** Column types that cannot be sorted or filtered (not stored in PostgreSQL). */
3818
3864
  const NON_INTERACTIVE_TYPES = new Set(['LONGTEXT', 'JSON', 'FILE', 'IMAGE']);
3865
+ function parseDefaultSort(defaultSort) {
3866
+ var _a;
3867
+ if (!defaultSort)
3868
+ return { field: '', dir: 'asc' };
3869
+ const parts = defaultSort.split(',');
3870
+ return { field: parts[0].trim(), dir: ((_a = parts[1]) === null || _a === void 0 ? void 0 : _a.trim()) === 'desc' ? 'desc' : 'asc' };
3871
+ }
3872
+ /** Raw sort query-param value, e.g. "name" or "name,desc". */
3873
+ function buildSortParam(field, dir) {
3874
+ if (!field)
3875
+ return '';
3876
+ return dir === 'desc' ? `${field},desc` : field;
3877
+ }
3878
+ /** Query params for a page request: page + sort + filterClass + view filters + active column filters. */
3879
+ function buildTableQueryParams(opts) {
3880
+ var _a, _b;
3881
+ const p = new URLSearchParams();
3882
+ if (opts.page > 0)
3883
+ p.set('page', String(opts.page));
3884
+ if (opts.sort)
3885
+ p.set('sort', opts.sort);
3886
+ if (opts.filterClass)
3887
+ p.set('type', opts.filterClass);
3888
+ applyViewFilters(p, opts.viewFilters);
3889
+ for (const f of opts.activeFilters) {
3890
+ if (f.operator === 'isEmpty') {
3891
+ p.set(f.field, '');
3892
+ continue;
3893
+ }
3894
+ if (f.operator === 'isNotEmpty') {
3895
+ p.set(f.field + '_notempty', 'true');
3896
+ continue;
3897
+ }
3898
+ if (f.operator === 'startsWith') {
3899
+ p.set(f.field + '_startswith', String((_a = f.value) !== null && _a !== void 0 ? _a : ''));
3900
+ continue;
3901
+ }
3902
+ if ((_b = f.values) === null || _b === void 0 ? void 0 : _b.length) {
3903
+ p.set(f.field, f.values.join(','));
3904
+ continue;
3905
+ }
3906
+ if (f.value != null)
3907
+ p.set(f.field, String(f.value));
3908
+ if (f.from != null)
3909
+ p.set(f.field + '_from', String(f.from));
3910
+ if (f.to != null)
3911
+ p.set(f.field + '_to', String(f.to));
3912
+ }
3913
+ return p.toString();
3914
+ }
3915
+ /** Groups aggregate columns by function; null when the view has no aggregates. */
3916
+ function buildAggregationParams(columns) {
3917
+ var _a;
3918
+ const groups = { sum: [], avg: [], count: [] };
3919
+ for (const col of columns) {
3920
+ if (col.type !== 'FIELD' || !col.aggregate)
3921
+ continue;
3922
+ const fn = col.aggregate.toLowerCase();
3923
+ if (fn in groups)
3924
+ groups[fn].push((_a = col.name) !== null && _a !== void 0 ? _a : '');
3925
+ }
3926
+ const params = {};
3927
+ if (groups.sum.length)
3928
+ params.sum = groups.sum;
3929
+ if (groups.avg.length)
3930
+ params.avg = groups.avg;
3931
+ if (groups.count.length)
3932
+ params.count = groups.count;
3933
+ return Object.keys(params).length > 0 ? params : null;
3934
+ }
3935
+ /** Aggregation query string: the page-0 query params without page/sort, plus sum/avg/count. */
3936
+ function buildAggregationQs(basePageQs, columns) {
3937
+ var _a, _b, _c;
3938
+ const p = new URLSearchParams(basePageQs);
3939
+ p.delete('page');
3940
+ p.delete('sort');
3941
+ const groups = buildAggregationParams(columns);
3942
+ if ((_a = groups === null || groups === void 0 ? void 0 : groups.sum) === null || _a === void 0 ? void 0 : _a.length)
3943
+ p.set('sum', groups.sum.join(','));
3944
+ if ((_b = groups === null || groups === void 0 ? void 0 : groups.avg) === null || _b === void 0 ? void 0 : _b.length)
3945
+ p.set('avg', groups.avg.join(','));
3946
+ if ((_c = groups === null || groups === void 0 ? void 0 : groups.count) === null || _c === void 0 ? void 0 : _c.length)
3947
+ p.set('count', groups.count.join(','));
3948
+ return p.toString();
3949
+ }
3950
+ /** True when the pending filter actually constrains anything. */
3951
+ function filterHasValue(f) {
3952
+ if (f.operator === 'isEmpty' || f.operator === 'isNotEmpty')
3953
+ return true;
3954
+ if (f.values !== undefined && f.values.length > 0)
3955
+ return true;
3956
+ if (f.value != null && f.value !== '')
3957
+ return true;
3958
+ if (typeof f.value === 'boolean')
3959
+ return true;
3960
+ if (f.from != null && f.from !== '')
3961
+ return true;
3962
+ if (f.to != null && f.to !== '')
3963
+ return true;
3964
+ return false;
3965
+ }
3966
+ // ── DATETIME filters: the user edits local "YYYY-MM-DD" dates, the API stores UTC ISO ──
3967
+ /** UTC ISO string at the start (midnight) of the given local day. */
3968
+ function dateLocalToUTCStart(dateStr) {
3969
+ if (!dateStr)
3970
+ return dateStr;
3971
+ const [year, month, day] = dateStr.split('-').map(Number);
3972
+ return new Date(year, month - 1, day).toISOString().replace(/\.\d{3}Z$/, 'Z');
3973
+ }
3974
+ /** Start of the day AFTER the given local date (exclusive range end). */
3975
+ function dateLocalToUTCEndExclusive(dateStr) {
3976
+ if (!dateStr)
3977
+ return dateStr;
3978
+ const [year, month, day] = dateStr.split('-').map(Number);
3979
+ return new Date(year, month - 1, day + 1).toISOString().replace(/\.\d{3}Z$/, 'Z');
3980
+ }
3981
+ /** Stored UTC ISO string back to the local "YYYY-MM-DD" date. */
3982
+ function utcISOToLocalDate(utcStr) {
3983
+ if (!utcStr)
3984
+ return utcStr;
3985
+ const d = new Date(utcStr);
3986
+ if (isNaN(d.getTime()))
3987
+ return utcStr;
3988
+ return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
3989
+ }
3990
+ /** The stored "to" is the exclusive end (next midnight); subtract a day to recover the entered date. */
3991
+ function utcISOToLocalDateExclusiveEnd(utcStr) {
3992
+ if (!utcStr)
3993
+ return utcStr;
3994
+ const d = new Date(utcStr);
3995
+ if (isNaN(d.getTime()))
3996
+ return utcStr;
3997
+ d.setDate(d.getDate() - 1);
3998
+ return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
3999
+ }
4000
+ /** Applies the local→UTC conversion when a DATETIME filter is submitted.
4001
+ * Exact date → range covering the full local day. */
4002
+ function normalizeDatetimeFilter(f) {
4003
+ const normalized = Object.assign({}, f);
4004
+ if (f.dataType === 'DATETIME' && f.operator !== 'isEmpty' && f.operator !== 'isNotEmpty') {
4005
+ if (typeof normalized.value === 'string' && normalized.value) {
4006
+ normalized.from = dateLocalToUTCStart(normalized.value);
4007
+ normalized.to = dateLocalToUTCEndExclusive(normalized.value);
4008
+ normalized.value = undefined;
4009
+ }
4010
+ else {
4011
+ if (typeof normalized.from === 'string' && normalized.from)
4012
+ normalized.from = dateLocalToUTCStart(normalized.from);
4013
+ if (typeof normalized.to === 'string' && normalized.to)
4014
+ normalized.to = dateLocalToUTCEndExclusive(normalized.to);
4015
+ }
4016
+ }
4017
+ return normalized;
4018
+ }
4019
+ /** Converts a stored DATETIME filter back to local dates for the popup.
4020
+ * A range covering a single local day is restored to exact-date mode. */
4021
+ function datetimeFilterToDisplay(existing) {
4022
+ const display = Object.assign({}, existing);
4023
+ if (typeof display.from === 'string' && display.from)
4024
+ display.from = utcISOToLocalDate(display.from);
4025
+ if (typeof display.to === 'string' && display.to)
4026
+ display.to = utcISOToLocalDateExclusiveEnd(display.to);
4027
+ if (display.from && display.to && display.from === display.to) {
4028
+ return Object.assign(Object.assign({}, display), { value: display.from, from: undefined, to: undefined });
4029
+ }
4030
+ return display;
4031
+ }
4032
+
4033
+ /**
4034
+ * Stateless render parts of mrd-table. All state and handlers stay in the
4035
+ * component; these components receive plain values and callbacks.
4036
+ */
4037
+ const FilterIcon = () => (index.h("span", { class: "mrd-table__filter-icon", "aria-hidden": "true" }, index.h("svg", { viewBox: "0 0 24 24", width: "14", height: "14", fill: "currentColor" }, index.h("path", { d: "M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z" }))));
4038
+ const TEXTBLOCK_MAX = 200;
4039
+ const TableCell = ({ col, row, locale, onDownload, onOpenTextblock, onOpenJson }) => {
4040
+ var _a, _b, _c;
4041
+ const dataType = (_a = col.dataType) !== null && _a !== void 0 ? _a : '';
4042
+ const isNumeric = col.type === 'FIELD' && NUMERIC_TYPES.has(dataType);
4043
+ const isFile = col.type === 'FIELD' && (dataType === 'FILE' || dataType === 'IMAGE');
4044
+ if (isFile) {
4045
+ const name = (_b = col.name) !== null && _b !== void 0 ? _b : '';
4046
+ const fileVal = row === null || row === void 0 ? void 0 : row[name];
4047
+ const href = fileVal === null || fileVal === void 0 ? void 0 : fileVal.href;
4048
+ const fileName = fileVal === null || fileVal === void 0 ? void 0 : fileVal.fileName;
4049
+ return (index.h("td", { class: "mrd-table__cell" }, href && fileName ? (index.h("button", { class: "mrd-table__file-btn", title: fileName, onClick: (e) => {
4050
+ e.stopPropagation();
4051
+ onDownload({ href, fileName });
4052
+ } }, index.h("svg", { class: "mrd-table__file-icon", viewBox: "0 0 24 24", "aria-hidden": "true" }, index.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))) : ''));
4053
+ }
4054
+ if (dataType === 'JSON') {
4055
+ const name = (_c = col.name) !== null && _c !== void 0 ? _c : '';
4056
+ const rawValue = name ? row === null || row === void 0 ? void 0 : row[name] : undefined;
4057
+ if (rawValue == null || rawValue === '')
4058
+ return index.h("td", { class: "mrd-table__cell" });
4059
+ const compactHtml = CellRenderer.formatJson(rawValue, true);
4060
+ const prettyHtml = CellRenderer.formatJson(rawValue, false);
4061
+ return (index.h("td", { class: "mrd-table__cell" }, index.h("span", { class: "mrd-table__json-preview", innerHTML: compactHtml }), index.h("button", { class: "mrd-table__textblock-btn", onClick: (e) => { e.stopPropagation(); onOpenJson(prettyHtml); }, "aria-label": t('textblock_show_more', locale) }, "\u22EF")));
4062
+ }
4063
+ if (dataType === 'TEXTBLOCK') {
4064
+ const full = CellRenderer.render(col, row, locale);
4065
+ if (full.length <= TEXTBLOCK_MAX) {
4066
+ return index.h("td", { class: "mrd-table__cell" }, full);
4067
+ }
4068
+ const preview = full.slice(0, TEXTBLOCK_MAX) + '…';
4069
+ return (index.h("td", { class: "mrd-table__cell" }, preview, index.h("button", { class: "mrd-table__textblock-btn", onClick: (e) => { e.stopPropagation(); onOpenTextblock(full); }, "aria-label": t('textblock_show_more', locale) }, "\u22EF")));
4070
+ }
4071
+ const value = CellRenderer.render(col, row, locale);
4072
+ return (index.h("td", { class: `mrd-table__cell${isNumeric ? ' mrd-table__cell--numeric' : ''}` }, value));
4073
+ };
4074
+ /** Formats the aggregation total for one column, '' when not applicable. */
4075
+ function formatAggregationValue(col, aggregations, locale) {
4076
+ var _a;
4077
+ if (col.type !== 'FIELD' || !col.aggregate || !aggregations)
4078
+ return '';
4079
+ const fn = col.aggregate.toLowerCase();
4080
+ const aggData = aggregations[fn];
4081
+ const val = typeof aggData === 'object' && aggData !== null
4082
+ ? aggData[(_a = col.name) !== null && _a !== void 0 ? _a : '']
4083
+ : undefined;
4084
+ if (val == null)
4085
+ return '';
4086
+ const dt = col.dataType;
4087
+ if (dt === 'INTEGER')
4088
+ return formatNumber(val, locale, { maximumFractionDigits: 0 });
4089
+ if (dt === 'PERCENTAGE')
4090
+ return formatPercentage(val, locale);
4091
+ if (dt === 'CURRENCY' && col.currencyCode)
4092
+ return formatCurrency(val, col.currencyCode, locale);
4093
+ return formatNumber(val, locale);
4094
+ }
4095
+ const TotalsRow = ({ columns, aggregations, locale }) => {
4096
+ if (!aggregations)
4097
+ return null;
4098
+ if (!columns.some(c => c.type === 'FIELD' && c.aggregate))
4099
+ return null;
4100
+ return (index.h("tfoot", null, index.h("tr", { class: "mrd-table__totals-row" }, columns.map(col => {
4101
+ var _a;
4102
+ const val = formatAggregationValue(col, aggregations, locale);
4103
+ const isNumeric = col.type === 'FIELD' && NUMERIC_TYPES.has((_a = col.dataType) !== null && _a !== void 0 ? _a : '');
4104
+ return (index.h("td", { class: `mrd-table__totals-cell${isNumeric ? ' mrd-table__totals-cell--numeric' : ''}` }, val));
4105
+ }))));
4106
+ };
4107
+ const TextblockModal = ({ text, locale, onClose }) => {
4108
+ if (text === null)
4109
+ return null;
4110
+ return (index.h("div", { class: "mrd-table__modal-backdrop", onClick: onClose, role: "dialog", "aria-modal": "true" }, index.h("div", { class: "mrd-table__modal", onClick: (e) => e.stopPropagation() }, index.h("button", { class: "mrd-table__modal-close", onClick: onClose, "aria-label": t('close', locale) }, "\u2715"), index.h("p", { class: "mrd-table__modal-text" }, text))));
4111
+ };
4112
+ const JsonModal = ({ html, locale, onClose }) => {
4113
+ if (html === null)
4114
+ return null;
4115
+ return (index.h("div", { class: "mrd-table__modal-backdrop", onClick: onClose, role: "dialog", "aria-modal": "true" }, index.h("div", { class: "mrd-table__modal", onClick: (e) => e.stopPropagation() }, index.h("button", { class: "mrd-table__modal-close", onClick: onClose, "aria-label": t('close', locale) }, "\u2715"), index.h("pre", { class: "mrd-table__modal-json", innerHTML: html }))));
4116
+ };
4117
+ const Toolbar = ({ locale, filterMode, filterCount, actions, views, activeViewIdx, viewPopoverOpen, createPickerOpen, createTypes, cb }) => {
4118
+ var _a;
4119
+ const hasActions = actions.length > 0;
4120
+ const hasViewSwitcher = views.length > 1;
4121
+ return (index.h("div", { class: "mrd-table__toolbar" }, index.h("div", { class: "mrd-table__toolbar-left" }, index.h("button", { class: `mrd-table__action mrd-table__action--secondary mrd-table__filter-toggle${filterMode ? ' mrd-table__filter-toggle--active' : ''}`, onClick: cb.onFilterToggle }, index.h("svg", { class: "mrd-table__action-icon", viewBox: "0 0 24 24", "aria-hidden": "true" }, index.h("path", { fill: "currentColor", d: "M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z" })), filterCount > 0 && index.h("span", { class: "mrd-table__filter-badge" }, filterCount), index.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 && (index.h("button", { class: "mrd-table__action mrd-table__action--secondary", onClick: cb.onClearAllFilters }, index.h("svg", { class: "mrd-table__action-icon", viewBox: "0 0 24 24", "aria-hidden": "true" }, index.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" })), index.h("span", { class: "mrd-table__action-tooltip" }, t('table_filter_clear_all', locale))))), hasViewSwitcher && (index.h("div", { class: "mrd-table__toolbar-center" }, index.h("div", { class: "mrd-table__view-switcher" }, index.h("button", { class: "mrd-table__view-arrow", "aria-label": "Previous view", onClick: () => cb.onViewSwitch((activeViewIdx - 1 + views.length) % views.length) }, "\u25C0"), index.h("div", { class: "mrd-table__view-title-wrap" }, index.h("button", { class: "mrd-table__view-title", onClick: (e) => cb.onToggleViewPopover(e) }, (_a = views[activeViewIdx]) === null || _a === void 0 ? void 0 : _a.label), viewPopoverOpen && (index.h("div", { class: "mrd-table__view-popover", onClick: (e) => e.stopPropagation() }, views.map((v, i) => (index.h("button", { key: String(i), class: `mrd-table__view-popover-item${i === activeViewIdx ? ' mrd-table__view-popover-item--active' : ''}`, onClick: () => {
4122
+ if (i !== activeViewIdx)
4123
+ cb.onViewSwitch(i);
4124
+ cb.onCloseViewPopover();
4125
+ } }, v.label)))))), index.h("button", { class: "mrd-table__view-arrow", "aria-label": "Next view", onClick: () => cb.onViewSwitch((activeViewIdx + 1) % views.length) }, "\u25B6")))), hasActions && (index.h("div", { class: "mrd-table__toolbar-right" }, actions.map(a => {
4126
+ var _a, _b;
4127
+ const pickerTypes = a.action === 'create' ? createTypes : null;
4128
+ if (pickerTypes === null || pickerTypes === void 0 ? void 0 : pickerTypes.length) {
4129
+ return (index.h("div", { class: "mrd-table__create-picker-wrap", key: `action-${a.action}` }, index.h("button", { class: `mrd-table__action mrd-table__action--${(_a = a.variant) !== null && _a !== void 0 ? _a : 'secondary'}`, onClick: cb.onToggleCreatePicker }, a.icon
4130
+ ? index.h("svg", { class: "mrd-table__action-icon", "aria-hidden": "true" }, index.h("use", { href: a.icon }))
4131
+ : a.label, index.h("span", { class: "mrd-table__action-tooltip" }, a.label)), createPickerOpen && (index.h("div", { class: "mrd-table__create-picker" }, pickerTypes.map(ct => (index.h("button", { key: ct.type, class: "mrd-table__create-picker-item", onClick: () => cb.onCreate(ct.type) }, ct.label)))))));
4132
+ }
4133
+ return (index.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
4134
+ ? index.h("svg", { class: "mrd-table__action-icon", "aria-hidden": "true" }, index.h("use", { href: a.icon }))
4135
+ : a.label, index.h("span", { class: "mrd-table__action-tooltip" }, a.label)));
4136
+ })))));
4137
+ };
4138
+
4139
+ const FilterEditor = ({ col, dataType, openFilterCol, pendingFilter, locale, cb }) => {
4140
+ var _a, _b, _c, _d, _e, _f;
4141
+ const pf = pendingFilter;
4142
+ if (NO_FILTER_TYPES.has(dataType)) {
4143
+ return index.h("p", { class: "mrd-table__filter-no-support" }, t('filter_no_support', locale));
4144
+ }
4145
+ if (dataType === 'BOOLEAN') {
4146
+ const boolOp = pf.operator;
4147
+ const noValueOp = boolOp === 'isEmpty' || boolOp === 'isNotEmpty';
4148
+ return (index.h("div", { class: "mrd-table__filter-radio-group" }, [
4149
+ { labelKey: 'filter_all', value: null },
4150
+ { labelKey: 'yes', value: true },
4151
+ { labelKey: 'no', value: false },
4152
+ ].map(opt => (index.h("label", { class: "mrd-table__filter-radio-label" }, index.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)))), index.h("label", { class: "mrd-table__filter-radio-label" }, index.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)), index.h("label", { class: "mrd-table__filter-radio-label" }, index.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))));
4153
+ }
4154
+ if (dataType === 'LIST') {
4155
+ const items = (_a = col.listItems) !== null && _a !== void 0 ? _a : [];
4156
+ const selected = (_b = pf.values) !== null && _b !== void 0 ? _b : [];
4157
+ return (index.h("div", { class: "mrd-table__filter-list" }, index.h("div", { class: "mrd-table__filter-list-controls" }, index.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)), index.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 => (index.h("label", { class: "mrd-table__filter-checkbox-label" }, index.h("input", { type: "checkbox", checked: selected.includes(item.key), onChange: (e) => cb.onToggleValue(item.key, e.target.checked) }), item.label)))));
4158
+ }
4159
+ if (TEXT_TYPES.has(dataType) || dataType === 'RELATION') {
4160
+ const op = (_c = pf.operator) !== null && _c !== void 0 ? _c : 'startsWith';
4161
+ const noInput = op === 'isEmpty' || op === 'isNotEmpty';
4162
+ return (index.h("div", { class: "mrd-table__filter-editor" }, index.h("select", { class: "mrd-table__filter-select", onChange: (e) => cb.onSetPending('operator', e.target.value) }, [
4163
+ { val: 'startsWith', labelKey: 'filter_starts_with' },
4164
+ { val: 'equals', labelKey: 'filter_equals' },
4165
+ { val: 'isEmpty', labelKey: 'filter_is_empty' },
4166
+ { val: 'isNotEmpty', labelKey: 'filter_is_not_empty' },
4167
+ ].map(o => index.h("option", { value: o.val, selected: op === o.val }, t(o.labelKey, locale)))), !noInput && (index.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) }))));
4168
+ }
4169
+ if (NUMERIC_TYPES.has(dataType)) {
4170
+ const numOp = pf.operator;
4171
+ const noInput = numOp === 'isEmpty' || numOp === 'isNotEmpty';
4172
+ const rangeMode = !noInput && (pf.from !== undefined || pf.to !== undefined);
4173
+ return (index.h("div", { class: "mrd-table__filter-editor" }, index.h("select", { class: "mrd-table__filter-select", onChange: (e) => {
4174
+ const val = e.target.value;
4175
+ if (val === 'isEmpty' || val === 'isNotEmpty') {
4176
+ cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: val, value: undefined, from: undefined, to: undefined }));
4177
+ }
4178
+ else {
4179
+ cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: undefined }));
4180
+ }
4181
+ } }, index.h("option", { value: "", selected: !noInput }, t('filter_has_value', locale)), index.h("option", { value: "isEmpty", selected: numOp === 'isEmpty' }, t('filter_is_empty', locale)), index.h("option", { value: "isNotEmpty", selected: numOp === 'isNotEmpty' }, t('filter_is_not_empty', locale))), !noInput && (index.h("div", { class: "mrd-table__filter-editor" }, index.h("div", { class: "mrd-table__filter-radio-group mrd-table__filter-radio-group--inline" }, index.h("label", { class: "mrd-table__filter-radio-label" }, index.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)), index.h("label", { class: "mrd-table__filter-radio-label" }, index.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 ? (index.h("input", { type: "number", class: "mrd-table__filter-input", value: pf.value != null ? String(pf.value) : '', onInput: (e) => cb.onSetPending('value', e.target.value) })) : (index.h("div", { class: "mrd-table__filter-range" }, index.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) }), index.h("span", { class: "mrd-table__filter-range-sep" }, "\u2013"), index.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) })))))));
4182
+ }
4183
+ if (dataType === 'DATETIME') {
4184
+ const dtOp = pf.operator;
4185
+ const noInput = dtOp === 'isEmpty' || dtOp === 'isNotEmpty';
4186
+ const rangeMode = !noInput && (pf.from !== undefined || pf.to !== undefined);
4187
+ return (index.h("div", { class: "mrd-table__filter-editor" }, index.h("select", { class: "mrd-table__filter-select", onChange: (e) => {
4188
+ const val = e.target.value;
4189
+ if (val === 'isEmpty' || val === 'isNotEmpty') {
4190
+ cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: val, value: undefined, from: undefined, to: undefined }));
4191
+ }
4192
+ else {
4193
+ cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: undefined }));
4194
+ }
4195
+ } }, index.h("option", { value: "", selected: !noInput }, t('filter_has_value', locale)), index.h("option", { value: "isEmpty", selected: dtOp === 'isEmpty' }, t('filter_is_empty', locale)), index.h("option", { value: "isNotEmpty", selected: dtOp === 'isNotEmpty' }, t('filter_is_not_empty', locale))), !noInput && (index.h("div", { class: "mrd-table__filter-editor" }, index.h("div", { class: "mrd-table__filter-radio-group mrd-table__filter-radio-group--inline" }, index.h("label", { class: "mrd-table__filter-radio-label" }, index.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)), index.h("label", { class: "mrd-table__filter-radio-label" }, index.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 ? (index.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) })) : (index.h("div", { class: "mrd-table__filter-range mrd-table__filter-range--stacked" }, index.h("label", { class: "mrd-table__filter-range-label" }, t('filter_from', locale)), index.h("input", { type: "date", class: "mrd-table__filter-input", value: pf.from != null ? String(pf.from) : '', onInput: (e) => cb.onSetPending('from', e.target.value) }), index.h("label", { class: "mrd-table__filter-range-label" }, t('filter_to', locale)), index.h("input", { type: "date", class: "mrd-table__filter-input", value: pf.to != null ? String(pf.to) : '', onInput: (e) => cb.onSetPending('to', e.target.value) })))))));
4196
+ }
4197
+ if (DATE_TYPES.has(dataType)) {
4198
+ const inputType = dataType === 'DATE' ? 'date' : 'time';
4199
+ const dtdOp = pf.operator;
4200
+ const noInput = dtdOp === 'isEmpty' || dtdOp === 'isNotEmpty';
4201
+ const rangeMode = !noInput && (pf.from !== undefined || pf.to !== undefined);
4202
+ return (index.h("div", { class: "mrd-table__filter-editor" }, index.h("select", { class: "mrd-table__filter-select", onChange: (e) => {
4203
+ const val = e.target.value;
4204
+ if (val === 'isEmpty' || val === 'isNotEmpty') {
4205
+ cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: val, value: undefined, from: undefined, to: undefined }));
4206
+ }
4207
+ else {
4208
+ cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: undefined }));
4209
+ }
4210
+ } }, index.h("option", { value: "", selected: !noInput }, t('filter_has_value', locale)), index.h("option", { value: "isEmpty", selected: dtdOp === 'isEmpty' }, t('filter_is_empty', locale)), index.h("option", { value: "isNotEmpty", selected: dtdOp === 'isNotEmpty' }, t('filter_is_not_empty', locale))), !noInput && (index.h("div", { class: "mrd-table__filter-editor" }, index.h("div", { class: "mrd-table__filter-radio-group mrd-table__filter-radio-group--inline" }, index.h("label", { class: "mrd-table__filter-radio-label" }, index.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)), index.h("label", { class: "mrd-table__filter-radio-label" }, index.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 ? (index.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) })) : (index.h("div", { class: "mrd-table__filter-range" }, index.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) }), index.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) })))))));
4211
+ }
4212
+ return null;
4213
+ };
4214
+ const FilterPopup = (props) => {
4215
+ var _a;
4216
+ const { col, openFilterCol, popupPos, sortField, sortDir, locale, cb } = props;
4217
+ const label = (_a = col.label) !== null && _a !== void 0 ? _a : openFilterCol;
4218
+ const sortActive = sortField === openFilterCol;
4219
+ return (index.h("div", { class: "mrd-table__filter-popup", style: { top: `${popupPos.top}px`, left: `${popupPos.left}px` }, onClick: (e) => e.stopPropagation() }, index.h("div", { class: "mrd-table__filter-popup-header" }, index.h("span", { class: "mrd-table__filter-popup-title" }, label), index.h("button", { class: "mrd-table__filter-close", onClick: cb.onClose }, "\u2715")), index.h("div", { class: "mrd-table__filter-section" }, index.h("div", { class: "mrd-table__filter-section-label" }, t('filter_sorting', locale)), index.h("div", { class: "mrd-table__filter-sort-buttons" }, index.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)), index.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)))), index.h("div", { class: "mrd-table__filter-divider" }), index.h("div", { class: "mrd-table__filter-section" }, index.h("div", { class: "mrd-table__filter-section-label" }, t('filter_section', locale)), index.h(FilterEditor, Object.assign({}, props))), index.h("div", { class: "mrd-table__filter-popup-footer" }, index.h("button", { class: "mrd-table__filter-btn mrd-table__filter-btn--clear", onClick: cb.onClear }, t('filter_clear', locale)), index.h("button", { class: "mrd-table__filter-btn mrd-table__filter-btn--apply", onClick: cb.onApply }, t('filter_apply', locale)))));
4220
+ };
4221
+
4222
+ /**
4223
+ * Pure window/paging maths for the mrd-table virtual scroll.
4224
+ * The window state itself stays @State in the component; these
4225
+ * functions only compute values from it.
4226
+ */
4227
+ const BUFFER = 10;
4228
+ /** Wait this long (ms) after the last scroll event before requesting pages,
4229
+ * so pages the user quickly scrolls past are skipped. */
4230
+ const REQUEST_DEBOUNCE_MS = 150;
4231
+ function visibleCount(tableHeight, rowHeight) {
4232
+ return Math.ceil(tableHeight / rowHeight);
4233
+ }
4234
+ /** Render window (with buffer) for the given scroll offset. */
4235
+ function computeWindow(scrollTop, rowHeight, tableHeight, total) {
4236
+ const visStart = Math.floor(scrollTop / rowHeight);
4237
+ const visEnd = Math.min(visStart + visibleCount(tableHeight, rowHeight), total - 1);
4238
+ return {
4239
+ renderStart: Math.max(0, visStart - BUFFER),
4240
+ renderEnd: Math.min(total - 1, visEnd + BUFFER),
4241
+ };
4242
+ }
4243
+ /** First/last page (0-based) covering the given row window. */
4244
+ function pageRange(start, end, pageSize) {
4245
+ return { firstPage: Math.floor(start / pageSize), lastPage: Math.floor(end / pageSize) };
4246
+ }
4247
+ function getRowFromPages(pages, index, pageSize) {
4248
+ var _a;
4249
+ const page = pages.get(Math.floor(index / pageSize));
4250
+ return (_a = page === null || page === void 0 ? void 0 : page[index % pageSize]) !== null && _a !== void 0 ? _a : null;
4251
+ }
4252
+ /** Authoritative row count: a page shorter than pageSize is the last page,
4253
+ * so the true total cannot exceed its end index. */
4254
+ function computeEffectiveTotal(loadedPages, pageSize, baseTotal) {
4255
+ let effectiveTotal = baseTotal;
4256
+ for (const [pageNum, pageRows] of loadedPages) {
4257
+ if (pageRows.length < pageSize) {
4258
+ effectiveTotal = Math.min(effectiveTotal, pageNum * pageSize + pageRows.length);
4259
+ }
4260
+ }
4261
+ return effectiveTotal;
4262
+ }
4263
+ /** True when some loaded page was short — the exact total is then known. */
4264
+ function isTotalKnownFromPages(loadedPages, pageSize) {
4265
+ for (const rows of loadedPages.values()) {
4266
+ if (rows.length < pageSize)
4267
+ return true;
4268
+ }
4269
+ return false;
4270
+ }
4271
+
4272
+ 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}`;
4273
+
4274
+ /** Breedte van de filterpopup in px — voor overflow-correctie. */
4275
+ const POPUP_WIDTH = 280;
3819
4276
  const MrdTable = class {
3820
4277
  constructor(hostRef) {
3821
4278
  index.registerInstance(this, hostRef);
@@ -3831,6 +4288,8 @@ const MrdTable = class {
3831
4288
  this.keydownHandler = null;
3832
4289
  this.createPickerClickHandler = null;
3833
4290
  this.viewPopoverClickHandler = null;
4291
+ /** Guards against scheduling more than one column-width measurement per freeze. */
4292
+ this.colWidthMeasureScheduled = false;
3834
4293
  // ── Props ──────────────────────────────────────────────────────────────────
3835
4294
  /** The VIEW or RELATED_VIEW layout item. Contains view config, dataClass, fromClass, actions etc. */
3836
4295
  this.item = null;
@@ -3887,13 +4346,10 @@ const MrdTable = class {
3887
4346
  this.minKnownTotal = 0;
3888
4347
  this.handleScroll = (e) => {
3889
4348
  const scroller = e.currentTarget;
3890
- const scrollTop = scroller.scrollTop;
3891
- const total = this.baseTotal;
3892
- const visStart = Math.floor(scrollTop / this.rowHeight);
3893
- const visEnd = Math.min(visStart + this.visibleCount(), total - 1);
3894
- this.scrollTop = scrollTop;
3895
- this.renderStart = Math.max(0, visStart - BUFFER);
3896
- this.renderEnd = Math.min(total - 1, visEnd + BUFFER);
4349
+ const { renderStart, renderEnd } = computeWindow(scroller.scrollTop, this.rowHeight, this.tableHeight, this.baseTotal);
4350
+ this.scrollTop = scroller.scrollTop;
4351
+ this.renderStart = renderStart;
4352
+ this.renderEnd = renderEnd;
3897
4353
  this.requestPagesForWindow(this.renderStart, this.renderEnd);
3898
4354
  };
3899
4355
  }
@@ -3915,16 +4371,9 @@ const MrdTable = class {
3915
4371
  }
3916
4372
  // ── Helpers ────────────────────────────────────────────────────────────────
3917
4373
  applyDefaultSort(defaultSort) {
3918
- var _a;
3919
- if (defaultSort) {
3920
- const parts = defaultSort.split(',');
3921
- this.sortField = parts[0].trim();
3922
- this.sortDir = ((_a = parts[1]) === null || _a === void 0 ? void 0 : _a.trim()) === 'desc' ? 'desc' : 'asc';
3923
- }
3924
- else {
3925
- this.sortField = '';
3926
- this.sortDir = 'asc';
3927
- }
4374
+ const { field, dir } = parseDefaultSort(defaultSort);
4375
+ this.sortField = field;
4376
+ this.sortDir = dir;
3928
4377
  }
3929
4378
  // ── Public API ─────────────────────────────────────────────────────────────
3930
4379
  /**
@@ -3941,6 +4390,7 @@ const MrdTable = class {
3941
4390
  this.loadedPages = new Map();
3942
4391
  this.requestedPages = new Set();
3943
4392
  this.colWidths = [];
4393
+ this.colWidthMeasureScheduled = false;
3944
4394
  this.scrollTop = 0;
3945
4395
  this.renderStart = 0;
3946
4396
  // Always fill the visible viewport on init — totalElements may be stale from a
@@ -4021,21 +4471,34 @@ const MrdTable = class {
4021
4471
  }
4022
4472
  }
4023
4473
  componentDidRender() {
4024
- if (this.colWidths.length === 0 && this.loadedPages.size > 0 && this.totalElements > 0) {
4025
- const ths = this.el.querySelectorAll('.mrd-table__header');
4026
- if (ths.length > 0) {
4027
- this.colWidths = Array.from(ths).map(th => th.offsetWidth);
4028
- }
4474
+ // Freeze header widths once the first data page has rendered. The measurement
4475
+ // reads offsetWidth and writes the colWidths @State, which would trigger a
4476
+ // re-render *during* the render cycle if done synchronously here. Defer it to a
4477
+ // writeTask so the state mutation happens outside the render pass (avoids the
4478
+ // Stencil "state/prop changed during rendering" warning and potential loops).
4479
+ if (this.colWidths.length === 0 &&
4480
+ !this.colWidthMeasureScheduled &&
4481
+ this.loadedPages.size > 0 &&
4482
+ this.totalElements > 0) {
4483
+ this.colWidthMeasureScheduled = true;
4484
+ index.writeTask(() => {
4485
+ this.colWidthMeasureScheduled = false;
4486
+ // Re-check: state may have changed (e.g. a reset) between scheduling and running.
4487
+ if (this.colWidths.length !== 0)
4488
+ return;
4489
+ const ths = this.el.querySelectorAll('.mrd-table__header');
4490
+ if (ths.length > 0) {
4491
+ this.colWidths = Array.from(ths).map(th => th.offsetWidth);
4492
+ }
4493
+ });
4029
4494
  }
4030
4495
  }
4031
4496
  // ── Paging / scroll helpers ────────────────────────────────────────────────
4032
4497
  visibleCount() {
4033
- return Math.ceil(this.tableHeight / this.rowHeight);
4498
+ return visibleCount(this.tableHeight, this.rowHeight);
4034
4499
  }
4035
4500
  sortParam() {
4036
- if (!this.sortField)
4037
- return '';
4038
- return this.sortDir === 'desc' ? `${this.sortField},desc` : this.sortField;
4501
+ return buildSortParam(this.sortField, this.sortDir);
4039
4502
  }
4040
4503
  /** Stable ordered list: primary view first, then alternatives (from the item prop). */
4041
4504
  get allViews() {
@@ -4061,14 +4524,16 @@ const MrdTable = class {
4061
4524
  * VIEW: /excel/{dataClass}
4062
4525
  * RELATED_VIEW: /excel/{fromClass}/{parentId}/{dataClass} */
4063
4526
  buildExcelPath() {
4064
- var _a, _b, _c, _d;
4527
+ var _a;
4065
4528
  const v = this.allViews[this.activeViewIdx];
4066
4529
  if (!v)
4067
4530
  return '';
4068
- if (((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === 'RELATED_VIEW') {
4069
- return `/excel/${(_b = v.fromClass) !== null && _b !== void 0 ? _b : ''}/${this.parentId}/${(_c = v.dataClass) !== null && _c !== void 0 ? _c : ''}`;
4070
- }
4071
- return `/excel/${(_d = v.dataClass) !== null && _d !== void 0 ? _d : ''}`;
4531
+ return '/excel' + buildListPath({
4532
+ isRelatedView: ((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === 'RELATED_VIEW',
4533
+ fromClass: v.fromClass,
4534
+ parentId: this.parentId,
4535
+ dataClass: v.dataClass,
4536
+ });
4072
4537
  }
4073
4538
  buildActionDetail(action, basicType) {
4074
4539
  var _a, _b, _c;
@@ -4088,80 +4553,28 @@ const MrdTable = class {
4088
4553
  * VIEW: /{dataClass}
4089
4554
  * RELATED_VIEW: /{fromClass}/{parentId}/{dataClass} */
4090
4555
  buildDataPath() {
4091
- var _a, _b, _c, _d;
4556
+ var _a;
4092
4557
  const v = this.allViews[this.activeViewIdx];
4093
4558
  if (!v)
4094
4559
  return '';
4095
- if (((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === 'RELATED_VIEW') {
4096
- return `/${(_b = v.fromClass) !== null && _b !== void 0 ? _b : ''}/${this.parentId}/${(_c = v.dataClass) !== null && _c !== void 0 ? _c : ''}`;
4097
- }
4098
- return `/${(_d = v.dataClass) !== null && _d !== void 0 ? _d : ''}`;
4560
+ return buildListPath({
4561
+ isRelatedView: ((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === 'RELATED_VIEW',
4562
+ fromClass: v.fromClass,
4563
+ parentId: this.parentId,
4564
+ dataClass: v.dataClass,
4565
+ });
4099
4566
  }
4100
4567
  /** Build query params for a page request from current sort, view filters, filterClass and active column filters. */
4101
4568
  buildQueryParams(page) {
4102
- var _a, _b, _c, _d, _e, _f, _g;
4569
+ var _a;
4103
4570
  const v = this.allViews[this.activeViewIdx];
4104
- const p = new URLSearchParams();
4105
- if (page > 0)
4106
- p.set('page', String(page));
4107
- const sort = this.sortParam();
4108
- if (sort)
4109
- p.set('sort', sort);
4110
- const filterClass = v === null || v === void 0 ? void 0 : v.filterClass;
4111
- if (filterClass)
4112
- p.set('type', filterClass);
4113
- 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 : [])) {
4114
- if (!f.name)
4115
- continue;
4116
- if (f.operator === 'EMPTY') {
4117
- p.set(f.name, '');
4118
- continue;
4119
- }
4120
- if (f.operator === 'NOT_EMPTY') {
4121
- p.set(f.name + '_notempty', 'true');
4122
- continue;
4123
- }
4124
- if (f.operator === 'STARTS_WITH') {
4125
- p.set(f.name + '_startswith', String((_c = f.value) !== null && _c !== void 0 ? _c : ''));
4126
- continue;
4127
- }
4128
- if (f.operator === 'FROM') {
4129
- p.set(f.name + '_from', String((_d = f.value) !== null && _d !== void 0 ? _d : ''));
4130
- continue;
4131
- }
4132
- if (f.operator === 'TO') {
4133
- p.set(f.name + '_to', String((_e = f.value) !== null && _e !== void 0 ? _e : ''));
4134
- continue;
4135
- }
4136
- if (f.value != null) {
4137
- p.set(f.name, String(f.value));
4138
- }
4139
- }
4140
- for (const f of this.activeFilters.values()) {
4141
- if (f.operator === 'isEmpty') {
4142
- p.set(f.field, '');
4143
- continue;
4144
- }
4145
- if (f.operator === 'isNotEmpty') {
4146
- p.set(f.field + '_notempty', 'true');
4147
- continue;
4148
- }
4149
- if (f.operator === 'startsWith') {
4150
- p.set(f.field + '_startswith', String((_f = f.value) !== null && _f !== void 0 ? _f : ''));
4151
- continue;
4152
- }
4153
- if ((_g = f.values) === null || _g === void 0 ? void 0 : _g.length) {
4154
- p.set(f.field, f.values.join(','));
4155
- continue;
4156
- }
4157
- if (f.value != null)
4158
- p.set(f.field, String(f.value));
4159
- if (f.from != null)
4160
- p.set(f.field + '_from', String(f.from));
4161
- if (f.to != null)
4162
- p.set(f.field + '_to', String(f.to));
4163
- }
4164
- return p.toString();
4571
+ return buildTableQueryParams({
4572
+ page,
4573
+ sort: this.sortParam(),
4574
+ filterClass: v === null || v === void 0 ? void 0 : v.filterClass,
4575
+ viewFilters: (_a = v === null || v === void 0 ? void 0 : v.view) === null || _a === void 0 ? void 0 : _a.filter,
4576
+ activeFilters: this.activeFilters.values(),
4577
+ });
4165
4578
  }
4166
4579
  get columns() {
4167
4580
  var _a, _b, _c;
@@ -4216,11 +4629,7 @@ const MrdTable = class {
4216
4629
  isTotalKnown() {
4217
4630
  if (this.aggregationsTotal != null)
4218
4631
  return true;
4219
- for (const rows of this.loadedPages.values()) {
4220
- if (rows.length < this.pageSize)
4221
- return true;
4222
- }
4223
- return false;
4632
+ return isTotalKnownFromPages(this.loadedPages, this.pageSize);
4224
4633
  }
4225
4634
  /** Effective total: aggregations-response > totalElements prop > minKnownTotal from setPage(). */
4226
4635
  get baseTotal() {
@@ -4231,61 +4640,9 @@ const MrdTable = class {
4231
4640
  return this.minKnownTotal;
4232
4641
  }
4233
4642
  // ── Aggregation helpers ────────────────────────────────────────────────────
4234
- buildAggregationParams() {
4235
- var _a;
4236
- const groups = { sum: [], avg: [], count: [] };
4237
- for (const col of this.columns) {
4238
- if (col.type !== 'FIELD' || !col.aggregate)
4239
- continue;
4240
- const fn = col.aggregate.toLowerCase();
4241
- if (fn in groups)
4242
- groups[fn].push((_a = col.name) !== null && _a !== void 0 ? _a : '');
4243
- }
4244
- const params = {};
4245
- if (groups.sum.length)
4246
- params.sum = groups.sum;
4247
- if (groups.avg.length)
4248
- params.avg = groups.avg;
4249
- if (groups.count.length)
4250
- params.count = groups.count;
4251
- return Object.keys(params).length > 0 ? params : null;
4252
- }
4253
- buildAggregationQs() {
4254
- var _a, _b, _c;
4255
- const p = new URLSearchParams(this.buildQueryParams(0));
4256
- p.delete('page');
4257
- p.delete('sort');
4258
- const groups = this.buildAggregationParams();
4259
- if ((_a = groups === null || groups === void 0 ? void 0 : groups.sum) === null || _a === void 0 ? void 0 : _a.length)
4260
- p.set('sum', groups.sum.join(','));
4261
- if ((_b = groups === null || groups === void 0 ? void 0 : groups.avg) === null || _b === void 0 ? void 0 : _b.length)
4262
- p.set('avg', groups.avg.join(','));
4263
- if ((_c = groups === null || groups === void 0 ? void 0 : groups.count) === null || _c === void 0 ? void 0 : _c.length)
4264
- p.set('count', groups.count.join(','));
4265
- return p.toString();
4266
- }
4267
4643
  emitLoadAggregations() {
4268
- this.mrdLoadAggregations.emit({ path: this.buildDataPath(), qs: this.buildQueryParams(0), aggQs: this.buildAggregationQs() });
4269
- }
4270
- renderAggregationValue(col) {
4271
- var _a;
4272
- if (col.type !== 'FIELD' || !col.aggregate || !this.aggregations)
4273
- return '';
4274
- const fn = col.aggregate.toLowerCase();
4275
- const aggData = this.aggregations[fn];
4276
- const val = typeof aggData === 'object' && aggData !== null
4277
- ? aggData[(_a = col.name) !== null && _a !== void 0 ? _a : '']
4278
- : undefined;
4279
- if (val == null)
4280
- return '';
4281
- const dt = col.dataType;
4282
- if (dt === 'INTEGER')
4283
- return formatNumber(val, this.locale, { maximumFractionDigits: 0 });
4284
- if (dt === 'PERCENTAGE')
4285
- return formatPercentage(val, this.locale);
4286
- if (dt === 'CURRENCY' && col.currencyCode)
4287
- return formatCurrency(val, col.currencyCode, this.locale);
4288
- return formatNumber(val, this.locale);
4644
+ const qs = this.buildQueryParams(0);
4645
+ this.mrdLoadAggregations.emit({ path: this.buildDataPath(), qs, aggQs: buildAggregationQs(qs, this.columns) });
4289
4646
  }
4290
4647
  // ── Reset pagination ───────────────────────────────────────────────────────
4291
4648
  /** Reset pagination state and scroll to top (used after sort or filter change). */
@@ -4298,6 +4655,7 @@ const MrdTable = class {
4298
4655
  this.loadedPages = new Map();
4299
4656
  this.requestedPages = new Set();
4300
4657
  this.colWidths = [];
4658
+ this.colWidthMeasureScheduled = false;
4301
4659
  this.scrollTop = 0;
4302
4660
  this.renderStart = 0;
4303
4661
  this.minKnownTotal = 0;
@@ -4327,8 +4685,7 @@ const MrdTable = class {
4327
4685
  this.emitPagesForWindow(this.renderStart, this.renderEnd);
4328
4686
  }
4329
4687
  emitPagesForWindow(start, end) {
4330
- const firstPage = Math.floor(start / this.pageSize);
4331
- const lastPage = Math.floor(end / this.pageSize);
4688
+ const { firstPage, lastPage } = pageRange(start, end, this.pageSize);
4332
4689
  const next = new Set(this.requestedPages);
4333
4690
  let changed = false;
4334
4691
  for (let p = firstPage; p <= lastPage; p++) {
@@ -4342,13 +4699,10 @@ const MrdTable = class {
4342
4699
  this.requestedPages = next;
4343
4700
  }
4344
4701
  getRow(i) {
4345
- var _a;
4346
- const page = this.loadedPages.get(Math.floor(i / this.pageSize));
4347
- return (_a = page === null || page === void 0 ? void 0 : page[i % this.pageSize]) !== null && _a !== void 0 ? _a : null;
4702
+ return getRowFromPages(this.loadedPages, i, this.pageSize);
4348
4703
  }
4349
4704
  requestPagesForWindow(start, end) {
4350
- const firstPage = Math.floor(start / this.pageSize);
4351
- const lastPage = Math.floor(end / this.pageSize);
4705
+ const { firstPage, lastPage } = pageRange(start, end, this.pageSize);
4352
4706
  let anyNew = false;
4353
4707
  for (let p = firstPage; p <= lastPage; p++) {
4354
4708
  if (!this.loadedPages.has(p) && !this.requestedPages.has(p) && !this.pendingPages.has(p)) {
@@ -4410,17 +4764,7 @@ const MrdTable = class {
4410
4764
  // If from and to cover the same local day it was an exact-date filter — restore
4411
4765
  // to exact mode so the user sees the single-date input again.
4412
4766
  if (dataType === 'DATETIME' && existing && existing.operator !== 'isEmpty' && existing.operator !== 'isNotEmpty') {
4413
- const display = Object.assign({}, existing);
4414
- if (typeof display.from === 'string' && display.from)
4415
- display.from = this.utcISOToLocalDate(display.from);
4416
- if (typeof display.to === 'string' && display.to)
4417
- display.to = this.utcISOToLocalDateExclusiveEnd(display.to);
4418
- if (display.from && display.to && display.from === display.to) {
4419
- this.pendingFilter = Object.assign(Object.assign({}, display), { value: display.from, from: undefined, to: undefined });
4420
- }
4421
- else {
4422
- this.pendingFilter = display;
4423
- }
4767
+ this.pendingFilter = datetimeFilterToDisplay(existing);
4424
4768
  }
4425
4769
  else {
4426
4770
  this.pendingFilter = existing ? Object.assign({}, existing) : { field: name, dataType, operator: defaultOperator };
@@ -4486,81 +4830,15 @@ const MrdTable = class {
4486
4830
  const current = (_b = (_a = this.pendingFilter) === null || _a === void 0 ? void 0 : _a.values) !== null && _b !== void 0 ? _b : [];
4487
4831
  this.pendingFilter = Object.assign(Object.assign({}, this.pendingFilter), { values: checked ? [...current, key] : current.filter(k => k !== key) });
4488
4832
  }
4489
- filterHasValue(f) {
4490
- if (f.operator === 'isEmpty' || f.operator === 'isNotEmpty')
4491
- return true;
4492
- if (f.values !== undefined && f.values.length > 0)
4493
- return true;
4494
- if (f.value != null && f.value !== '')
4495
- return true;
4496
- if (typeof f.value === 'boolean')
4497
- return true;
4498
- if (f.from != null && f.from !== '')
4499
- return true;
4500
- if (f.to != null && f.to !== '')
4501
- return true;
4502
- return false;
4503
- }
4504
- // Convert a local "YYYY-MM-DD" date string to the UTC ISO string at the
4505
- // start of that local day (midnight). new Date(y, m, d) uses local time.
4506
- dateLocalToUTCStart(dateStr) {
4507
- if (!dateStr)
4508
- return dateStr;
4509
- const [year, month, day] = dateStr.split('-').map(Number);
4510
- return new Date(year, month - 1, day).toISOString().replace(/\.\d{3}Z$/, 'Z');
4511
- }
4512
- // Start of the day AFTER the given local date (exclusive range end).
4513
- dateLocalToUTCEndExclusive(dateStr) {
4514
- if (!dateStr)
4515
- return dateStr;
4516
- const [year, month, day] = dateStr.split('-').map(Number);
4517
- return new Date(year, month - 1, day + 1).toISOString().replace(/\.\d{3}Z$/, 'Z');
4518
- }
4519
- // Convert a stored UTC ISO string back to the local "YYYY-MM-DD" date.
4520
- utcISOToLocalDate(utcStr) {
4521
- if (!utcStr)
4522
- return utcStr;
4523
- const d = new Date(utcStr);
4524
- if (isNaN(d.getTime()))
4525
- return utcStr;
4526
- return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
4527
- }
4528
- // The stored "to" value is the exclusive end (midnight of the next day).
4529
- // Subtract one day to recover the local date the user entered.
4530
- utcISOToLocalDateExclusiveEnd(utcStr) {
4531
- if (!utcStr)
4532
- return utcStr;
4533
- const d = new Date(utcStr);
4534
- if (isNaN(d.getTime()))
4535
- return utcStr;
4536
- d.setDate(d.getDate() - 1);
4537
- return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
4538
- }
4539
4833
  applyFilter() {
4540
4834
  const f = this.pendingFilter;
4541
4835
  if (!(f === null || f === void 0 ? void 0 : f.field)) {
4542
4836
  this.closeFilterPopup();
4543
4837
  return;
4544
4838
  }
4545
- // For DATETIME fields the user enters local dates; convert to UTC ISO strings.
4546
- // Exact date → range covering the full local day (from = midnight, to = next midnight).
4547
- // "to" is always the exclusive end (midnight of the next local day).
4548
- let normalized = Object.assign({}, f);
4549
- if (f.dataType === 'DATETIME' && f.operator !== 'isEmpty' && f.operator !== 'isNotEmpty') {
4550
- if (typeof normalized.value === 'string' && normalized.value) {
4551
- normalized.from = this.dateLocalToUTCStart(normalized.value);
4552
- normalized.to = this.dateLocalToUTCEndExclusive(normalized.value);
4553
- normalized.value = undefined;
4554
- }
4555
- else {
4556
- if (typeof normalized.from === 'string' && normalized.from)
4557
- normalized.from = this.dateLocalToUTCStart(normalized.from);
4558
- if (typeof normalized.to === 'string' && normalized.to)
4559
- normalized.to = this.dateLocalToUTCEndExclusive(normalized.to);
4560
- }
4561
- }
4839
+ const normalized = normalizeDatetimeFilter(f);
4562
4840
  const next = new Map(this.activeFilters);
4563
- if (this.filterHasValue(normalized)) {
4841
+ if (filterHasValue(normalized)) {
4564
4842
  next.set(normalized.field, normalized);
4565
4843
  }
4566
4844
  else {
@@ -4615,140 +4893,53 @@ const MrdTable = class {
4615
4893
  toggleViewPopover(e) {
4616
4894
  e.stopPropagation();
4617
4895
  if (this.viewPopoverOpen) {
4618
- this.viewPopoverOpen = false;
4619
- if (this.viewPopoverClickHandler) {
4620
- document.removeEventListener('click', this.viewPopoverClickHandler);
4621
- this.viewPopoverClickHandler = null;
4622
- }
4896
+ this.closeViewPopover();
4623
4897
  return;
4624
4898
  }
4625
4899
  this.viewPopoverOpen = true;
4626
- this.viewPopoverClickHandler = () => {
4627
- this.viewPopoverOpen = false;
4900
+ this.viewPopoverClickHandler = () => this.closeViewPopover();
4901
+ document.addEventListener('click', this.viewPopoverClickHandler);
4902
+ }
4903
+ closeViewPopover() {
4904
+ this.viewPopoverOpen = false;
4905
+ if (this.viewPopoverClickHandler) {
4628
4906
  document.removeEventListener('click', this.viewPopoverClickHandler);
4629
4907
  this.viewPopoverClickHandler = null;
4630
- };
4631
- document.addEventListener('click', this.viewPopoverClickHandler);
4908
+ }
4632
4909
  }
4633
4910
  // ── Render: toolbar ────────────────────────────────────────────────────────
4634
4911
  renderToolbar() {
4635
4912
  var _a;
4636
- const filterCount = this.activeFilters.size;
4637
- const actions = this.tableActions;
4638
- const allViews = this.allViews;
4639
- const hasActions = actions.length > 0;
4640
- const hasViewSwitcher = allViews.length > 1;
4641
- return (index.h("div", { class: "mrd-table__toolbar" }, index.h("div", { class: "mrd-table__toolbar-left" }, index.h("button", { class: `mrd-table__action mrd-table__action--secondary mrd-table__filter-toggle${this.filterMode ? ' mrd-table__filter-toggle--active' : ''}`, onClick: () => this.handleFilterToggle() }, index.h("svg", { class: "mrd-table__action-icon", viewBox: "0 0 24 24", "aria-hidden": "true" }, index.h("path", { fill: "currentColor", d: "M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z" })), filterCount > 0 && index.h("span", { class: "mrd-table__filter-badge" }, filterCount), index.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 && (index.h("button", { class: "mrd-table__action mrd-table__action--secondary", onClick: () => this.clearAllFilters() }, index.h("svg", { class: "mrd-table__action-icon", viewBox: "0 0 24 24", "aria-hidden": "true" }, index.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" })), index.h("span", { class: "mrd-table__action-tooltip" }, t('table_filter_clear_all', this.locale))))), hasViewSwitcher && (index.h("div", { class: "mrd-table__toolbar-center" }, index.h("div", { class: "mrd-table__view-switcher" }, index.h("button", { class: "mrd-table__view-arrow", "aria-label": "Previous view", onClick: () => this.handleViewSwitch((this.activeViewIdx - 1 + allViews.length) % allViews.length) }, "\u25C0"), index.h("div", { class: "mrd-table__view-title-wrap" }, index.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 && (index.h("div", { class: "mrd-table__view-popover", onClick: (e) => e.stopPropagation() }, allViews.map((v, i) => (index.h("button", { key: String(i), class: `mrd-table__view-popover-item${i === this.activeViewIdx ? ' mrd-table__view-popover-item--active' : ''}`, onClick: () => {
4642
- if (i !== this.activeViewIdx)
4643
- this.handleViewSwitch(i);
4644
- this.viewPopoverOpen = false;
4645
- if (this.viewPopoverClickHandler) {
4646
- document.removeEventListener('click', this.viewPopoverClickHandler);
4647
- this.viewPopoverClickHandler = null;
4648
- }
4649
- } }, v.label)))))), index.h("button", { class: "mrd-table__view-arrow", "aria-label": "Next view", onClick: () => this.handleViewSwitch((this.activeViewIdx + 1) % allViews.length) }, "\u25B6")))), hasActions && (index.h("div", { class: "mrd-table__toolbar-right" }, actions.map(a => {
4650
- var _a, _b, _c;
4651
- const createTypes = a.action === 'create' ? (_a = this.item) === null || _a === void 0 ? void 0 : _a.createTypes : null;
4652
- if (createTypes === null || createTypes === void 0 ? void 0 : createTypes.length) {
4653
- return (index.h("div", { class: "mrd-table__create-picker-wrap", key: `action-${a.action}` }, index.h("button", { class: `mrd-table__action mrd-table__action--${(_b = a.variant) !== null && _b !== void 0 ? _b : 'secondary'}`, onClick: () => this.toggleCreatePicker() }, a.icon
4654
- ? index.h("svg", { class: "mrd-table__action-icon", "aria-hidden": "true" }, index.h("use", { href: a.icon }))
4655
- : a.label, index.h("span", { class: "mrd-table__action-tooltip" }, a.label)), this.createPickerOpen && (index.h("div", { class: "mrd-table__create-picker" }, createTypes.map(ct => (index.h("button", { key: ct.type, class: "mrd-table__create-picker-item", onClick: () => {
4656
- this.mrdAction.emit(this.buildActionDetail('create', ct.type));
4657
- this.closeCreatePicker();
4658
- } }, ct.label)))))));
4659
- }
4660
- return (index.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
4661
- ? index.h("svg", { class: "mrd-table__action-icon", "aria-hidden": "true" }, index.h("use", { href: a.icon }))
4662
- : a.label, index.h("span", { class: "mrd-table__action-tooltip" }, a.label)));
4663
- })))));
4913
+ return (index.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: {
4914
+ onFilterToggle: () => this.handleFilterToggle(),
4915
+ onClearAllFilters: () => this.clearAllFilters(),
4916
+ onViewSwitch: idx => this.handleViewSwitch(idx),
4917
+ onToggleViewPopover: e => this.toggleViewPopover(e),
4918
+ onCloseViewPopover: () => this.closeViewPopover(),
4919
+ onToggleCreatePicker: () => this.toggleCreatePicker(),
4920
+ onCreate: basicType => {
4921
+ this.mrdAction.emit(this.buildActionDetail('create', basicType));
4922
+ this.closeCreatePicker();
4923
+ },
4924
+ onAction: action => this.mrdAction.emit(this.buildActionDetail(action)),
4925
+ } }));
4664
4926
  }
4665
4927
  // ── Render: filter popup ───────────────────────────────────────────────────
4666
- renderFilterEditor(col) {
4667
- var _a, _b, _c, _d, _e, _f, _g;
4668
- const pf = (_a = this.pendingFilter) !== null && _a !== void 0 ? _a : {};
4669
- const dataType = this.colDataType(col);
4670
- if (NO_FILTER_TYPES.has(dataType)) {
4671
- return index.h("p", { class: "mrd-table__filter-no-support" }, t('filter_no_support', this.locale));
4672
- }
4673
- if (dataType === 'BOOLEAN') {
4674
- const boolOp = pf.operator;
4675
- const noValueOp = boolOp === 'isEmpty' || boolOp === 'isNotEmpty';
4676
- return (index.h("div", { class: "mrd-table__filter-radio-group" }, [
4677
- { labelKey: 'filter_all', value: null },
4678
- { labelKey: 'yes', value: true },
4679
- { labelKey: 'no', value: false },
4680
- ].map(opt => (index.h("label", { class: "mrd-table__filter-radio-label" }, index.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)))), index.h("label", { class: "mrd-table__filter-radio-label" }, index.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)), index.h("label", { class: "mrd-table__filter-radio-label" }, index.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))));
4681
- }
4682
- if (dataType === 'LIST') {
4683
- const items = (_b = col.listItems) !== null && _b !== void 0 ? _b : [];
4684
- const selected = (_c = pf.values) !== null && _c !== void 0 ? _c : [];
4685
- return (index.h("div", { class: "mrd-table__filter-list" }, index.h("div", { class: "mrd-table__filter-list-controls" }, index.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)), index.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 => (index.h("label", { class: "mrd-table__filter-checkbox-label" }, index.h("input", { type: "checkbox", checked: selected.includes(item.key), onChange: (e) => this.togglePendingValue(item.key, e.target.checked) }), item.label)))));
4686
- }
4687
- if (TEXT_TYPES.has(dataType) || dataType === 'RELATION') {
4688
- const op = (_d = pf.operator) !== null && _d !== void 0 ? _d : 'startsWith';
4689
- const noInput = op === 'isEmpty' || op === 'isNotEmpty';
4690
- return (index.h("div", { class: "mrd-table__filter-editor" }, index.h("select", { class: "mrd-table__filter-select", onChange: (e) => this.setPending('operator', e.target.value) }, [
4691
- { val: 'startsWith', labelKey: 'filter_starts_with' },
4692
- { val: 'equals', labelKey: 'filter_equals' },
4693
- { val: 'isEmpty', labelKey: 'filter_is_empty' },
4694
- { val: 'isNotEmpty', labelKey: 'filter_is_not_empty' },
4695
- ].map(o => index.h("option", { value: o.val, selected: op === o.val }, t(o.labelKey, this.locale)))), !noInput && (index.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) }))));
4696
- }
4697
- if (NUMERIC_TYPES.has(dataType)) {
4698
- const numOp = pf.operator;
4699
- const noInput = numOp === 'isEmpty' || numOp === 'isNotEmpty';
4700
- const rangeMode = !noInput && (pf.from !== undefined || pf.to !== undefined);
4701
- return (index.h("div", { class: "mrd-table__filter-editor" }, index.h("select", { class: "mrd-table__filter-select", onChange: (e) => {
4702
- const val = e.target.value;
4703
- if (val === 'isEmpty' || val === 'isNotEmpty') {
4704
- this.pendingFilter = Object.assign(Object.assign({}, pf), { operator: val, value: undefined, from: undefined, to: undefined });
4705
- }
4706
- else {
4707
- this.pendingFilter = Object.assign(Object.assign({}, pf), { operator: undefined });
4708
- }
4709
- } }, index.h("option", { value: "", selected: !noInput }, t('filter_has_value', this.locale)), index.h("option", { value: "isEmpty", selected: numOp === 'isEmpty' }, t('filter_is_empty', this.locale)), index.h("option", { value: "isNotEmpty", selected: numOp === 'isNotEmpty' }, t('filter_is_not_empty', this.locale))), !noInput && (index.h("div", { class: "mrd-table__filter-editor" }, index.h("div", { class: "mrd-table__filter-radio-group mrd-table__filter-radio-group--inline" }, index.h("label", { class: "mrd-table__filter-radio-label" }, index.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)), index.h("label", { class: "mrd-table__filter-radio-label" }, index.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 ? (index.h("input", { type: "number", class: "mrd-table__filter-input", value: pf.value != null ? String(pf.value) : '', onInput: (e) => this.setPending('value', e.target.value) })) : (index.h("div", { class: "mrd-table__filter-range" }, index.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) }), index.h("span", { class: "mrd-table__filter-range-sep" }, "\u2013"), index.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) })))))));
4710
- }
4711
- if (dataType === 'DATETIME') {
4712
- const dtOp = pf.operator;
4713
- const noInput = dtOp === 'isEmpty' || dtOp === 'isNotEmpty';
4714
- const rangeMode = !noInput && (pf.from !== undefined || pf.to !== undefined);
4715
- return (index.h("div", { class: "mrd-table__filter-editor" }, index.h("select", { class: "mrd-table__filter-select", onChange: (e) => {
4716
- const val = e.target.value;
4717
- if (val === 'isEmpty' || val === 'isNotEmpty') {
4718
- this.pendingFilter = Object.assign(Object.assign({}, pf), { operator: val, value: undefined, from: undefined, to: undefined });
4719
- }
4720
- else {
4721
- this.pendingFilter = Object.assign(Object.assign({}, pf), { operator: undefined });
4722
- }
4723
- } }, index.h("option", { value: "", selected: !noInput }, t('filter_has_value', this.locale)), index.h("option", { value: "isEmpty", selected: dtOp === 'isEmpty' }, t('filter_is_empty', this.locale)), index.h("option", { value: "isNotEmpty", selected: dtOp === 'isNotEmpty' }, t('filter_is_not_empty', this.locale))), !noInput && (index.h("div", { class: "mrd-table__filter-editor" }, index.h("div", { class: "mrd-table__filter-radio-group mrd-table__filter-radio-group--inline" }, index.h("label", { class: "mrd-table__filter-radio-label" }, index.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)), index.h("label", { class: "mrd-table__filter-radio-label" }, index.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 ? (index.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) })) : (index.h("div", { class: "mrd-table__filter-range mrd-table__filter-range--stacked" }, index.h("label", { class: "mrd-table__filter-range-label" }, t('filter_from', this.locale)), index.h("input", { type: "date", class: "mrd-table__filter-input", value: pf.from != null ? String(pf.from) : '', onInput: (e) => this.setPending('from', e.target.value) }), index.h("label", { class: "mrd-table__filter-range-label" }, t('filter_to', this.locale)), index.h("input", { type: "date", class: "mrd-table__filter-input", value: pf.to != null ? String(pf.to) : '', onInput: (e) => this.setPending('to', e.target.value) })))))));
4724
- }
4725
- if (DATE_TYPES.has(dataType)) {
4726
- const inputType = dataType === 'DATE' ? 'date' : 'time';
4727
- const dtdOp = pf.operator;
4728
- const noInput = dtdOp === 'isEmpty' || dtdOp === 'isNotEmpty';
4729
- const rangeMode = !noInput && (pf.from !== undefined || pf.to !== undefined);
4730
- return (index.h("div", { class: "mrd-table__filter-editor" }, index.h("select", { class: "mrd-table__filter-select", onChange: (e) => {
4731
- const val = e.target.value;
4732
- if (val === 'isEmpty' || val === 'isNotEmpty') {
4733
- this.pendingFilter = Object.assign(Object.assign({}, pf), { operator: val, value: undefined, from: undefined, to: undefined });
4734
- }
4735
- else {
4736
- this.pendingFilter = Object.assign(Object.assign({}, pf), { operator: undefined });
4737
- }
4738
- } }, index.h("option", { value: "", selected: !noInput }, t('filter_has_value', this.locale)), index.h("option", { value: "isEmpty", selected: dtdOp === 'isEmpty' }, t('filter_is_empty', this.locale)), index.h("option", { value: "isNotEmpty", selected: dtdOp === 'isNotEmpty' }, t('filter_is_not_empty', this.locale))), !noInput && (index.h("div", { class: "mrd-table__filter-editor" }, index.h("div", { class: "mrd-table__filter-radio-group mrd-table__filter-radio-group--inline" }, index.h("label", { class: "mrd-table__filter-radio-label" }, index.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)), index.h("label", { class: "mrd-table__filter-radio-label" }, index.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 ? (index.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) })) : (index.h("div", { class: "mrd-table__filter-range" }, index.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) }), index.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) })))))));
4739
- }
4740
- return null;
4741
- }
4742
4928
  renderFilterPopup() {
4743
- var _a;
4744
4929
  if (!this.openFilterCol || !this.pendingFilter)
4745
4930
  return null;
4746
4931
  const col = this.columns.find(c => this.colName(c) === this.openFilterCol);
4747
4932
  if (!col)
4748
4933
  return null;
4749
- const label = (_a = col.label) !== null && _a !== void 0 ? _a : this.openFilterCol;
4750
- const sortActive = this.sortField === this.openFilterCol;
4751
- return (index.h("div", { class: "mrd-table__filter-popup", style: { top: `${this.popupPos.top}px`, left: `${this.popupPos.left}px` }, onClick: (e) => e.stopPropagation() }, index.h("div", { class: "mrd-table__filter-popup-header" }, index.h("span", { class: "mrd-table__filter-popup-title" }, label), index.h("button", { class: "mrd-table__filter-close", onClick: () => this.closeFilterPopup() }, "\u2715")), index.h("div", { class: "mrd-table__filter-section" }, index.h("div", { class: "mrd-table__filter-section-label" }, t('filter_sorting', this.locale)), index.h("div", { class: "mrd-table__filter-sort-buttons" }, index.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)), index.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)))), index.h("div", { class: "mrd-table__filter-divider" }), index.h("div", { class: "mrd-table__filter-section" }, index.h("div", { class: "mrd-table__filter-section-label" }, t('filter_section', this.locale)), this.renderFilterEditor(col)), index.h("div", { class: "mrd-table__filter-popup-footer" }, index.h("button", { class: "mrd-table__filter-btn mrd-table__filter-btn--clear", onClick: () => this.clearFilter() }, t('filter_clear', this.locale)), index.h("button", { class: "mrd-table__filter-btn mrd-table__filter-btn--apply", onClick: () => this.applyFilter() }, t('filter_apply', this.locale)))));
4934
+ return (index.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: {
4935
+ onSetPending: (key, val) => this.setPending(key, val),
4936
+ onReplacePending: pf => (this.pendingFilter = pf),
4937
+ onToggleValue: (key, checked) => this.togglePendingValue(key, checked),
4938
+ onApplySort: dir => this.applySort(col, dir),
4939
+ onApply: () => this.applyFilter(),
4940
+ onClear: () => this.clearFilter(),
4941
+ onClose: () => this.closeFilterPopup(),
4942
+ } }));
4752
4943
  }
4753
4944
  // ── Render: footer ────────────────────────────────────────────────────────
4754
4945
  renderFooter(rowCount, effectiveTotal, isTotalKnown = true) {
@@ -4773,54 +4964,11 @@ const MrdTable = class {
4773
4964
  }
4774
4965
  // ── Render: cell ──────────────────────────────────────────────────────────
4775
4966
  renderCell(col, row) {
4776
- var _a, _b, _c;
4777
- const numericTypes = new Set(['INTEGER', 'DECIMAL', 'PERCENTAGE', 'CURRENCY']);
4778
- const dataType = (_a = col.dataType) !== null && _a !== void 0 ? _a : '';
4779
- const isNumeric = col.type === 'FIELD' && numericTypes.has(dataType);
4780
- const isFile = col.type === 'FIELD' && (dataType === 'FILE' || dataType === 'IMAGE');
4781
- if (isFile) {
4782
- const name = (_b = col.name) !== null && _b !== void 0 ? _b : '';
4783
- const fileVal = row === null || row === void 0 ? void 0 : row[name];
4784
- const href = fileVal === null || fileVal === void 0 ? void 0 : fileVal.href;
4785
- const fileName = fileVal === null || fileVal === void 0 ? void 0 : fileVal.fileName;
4786
- return (index.h("td", { class: "mrd-table__cell" }, href && fileName ? (index.h("button", { class: "mrd-table__file-btn", title: fileName, onClick: (e) => {
4787
- e.stopPropagation();
4788
- this.mrdDownload.emit({ href, fileName });
4789
- } }, index.h("svg", { class: "mrd-table__file-icon", viewBox: "0 0 24 24", "aria-hidden": "true" }, index.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))) : ''));
4790
- }
4791
- if (dataType === 'JSON') {
4792
- const name = (_c = col.name) !== null && _c !== void 0 ? _c : '';
4793
- const rawValue = name ? row === null || row === void 0 ? void 0 : row[name] : undefined;
4794
- if (rawValue == null || rawValue === '')
4795
- return index.h("td", { class: "mrd-table__cell" });
4796
- const compactHtml = CellRenderer.formatJson(rawValue, true);
4797
- const prettyHtml = CellRenderer.formatJson(rawValue, false);
4798
- return (index.h("td", { class: "mrd-table__cell" }, index.h("span", { class: "mrd-table__json-preview", innerHTML: compactHtml }), index.h("button", { class: "mrd-table__textblock-btn", onClick: (e) => { e.stopPropagation(); this.openJsonModal(prettyHtml); }, "aria-label": t('textblock_show_more', this.locale) }, "\u22EF")));
4799
- }
4800
- const TEXTBLOCK_MAX = 200;
4801
- if (dataType === 'TEXTBLOCK') {
4802
- const full = CellRenderer.render(col, row, this.locale);
4803
- if (full.length <= TEXTBLOCK_MAX) {
4804
- return index.h("td", { class: "mrd-table__cell" }, full);
4805
- }
4806
- const preview = full.slice(0, TEXTBLOCK_MAX) + '…';
4807
- return (index.h("td", { class: "mrd-table__cell" }, preview, index.h("button", { class: "mrd-table__textblock-btn", onClick: (e) => { e.stopPropagation(); this.openTextblockModal(full); }, "aria-label": t('textblock_show_more', this.locale) }, "\u22EF")));
4808
- }
4809
- const value = CellRenderer.render(col, row, this.locale);
4810
- return (index.h("td", { class: `mrd-table__cell${isNumeric ? ' mrd-table__cell--numeric' : ''}` }, value));
4967
+ return (index.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) }));
4811
4968
  }
4812
4969
  // ── Render: totals row ────────────────────────────────────────────────────
4813
4970
  renderTotalsRow() {
4814
- if (!this.aggregations)
4815
- return null;
4816
- if (!this.columns.some(c => c.type === 'FIELD' && c.aggregate))
4817
- return null;
4818
- return (index.h("tfoot", null, index.h("tr", { class: "mrd-table__totals-row" }, this.columns.map(col => {
4819
- var _a;
4820
- const val = this.renderAggregationValue(col);
4821
- const isNumeric = col.type === 'FIELD' && NUMERIC_TYPES.has((_a = col.dataType) !== null && _a !== void 0 ? _a : '');
4822
- return (index.h("td", { class: `mrd-table__totals-cell${isNumeric ? ' mrd-table__totals-cell--numeric' : ''}` }, val));
4823
- }))));
4971
+ return index.h(TotalsRow, { columns: this.columns, aggregations: this.aggregations, locale: this.locale });
4824
4972
  }
4825
4973
  // ── Render ─────────────────────────────────────────────────────────────────
4826
4974
  render() {
@@ -4840,7 +4988,7 @@ const MrdTable = class {
4840
4988
  isFiltered ? 'mrd-table__header--filtered' : '',
4841
4989
  this.filterMode ? 'mrd-table__header--sortable' : '',
4842
4990
  ].filter(Boolean).join(' ');
4843
- return (index.h("th", { class: cls, onClick: this.filterMode ? (e) => this.handleFilterOpen(col, e) : undefined }, index.h("span", { class: "mrd-table__header-label" }, (_a = col.label) !== null && _a !== void 0 ? _a : ''), isFiltered && this.renderFilterIcon()));
4991
+ return (index.h("th", { class: cls, onClick: this.filterMode ? (e) => this.handleFilterOpen(col, e) : undefined }, index.h("span", { class: "mrd-table__header-label" }, (_a = col.label) !== null && _a !== void 0 ? _a : ''), isFiltered && index.h(FilterIcon, null)));
4844
4992
  }))), index.h("tbody", null, (_b = this.rows) === null || _b === void 0 ? void 0 : _b.map((row, i) => (index.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) && (index.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()));
4845
4993
  }
4846
4994
  // ── Paginated / virtual-scroll mode ────────────────────────────────────
@@ -4848,12 +4996,7 @@ const MrdTable = class {
4848
4996
  // if any loaded page is shorter than pageSize it is the last page,
4849
4997
  // so the true total cannot exceed (pageNum * pageSize + pageRows.length).
4850
4998
  // aggregationsTotal (from setAggregations) takes priority over the totalElements prop.
4851
- let effectiveTotal = this.baseTotal;
4852
- for (const [pageNum, pageRows] of this.loadedPages) {
4853
- if (pageRows.length < this.pageSize) {
4854
- effectiveTotal = Math.min(effectiveTotal, pageNum * this.pageSize + pageRows.length);
4855
- }
4856
- }
4999
+ const effectiveTotal = computeEffectiveTotal(this.loadedPages, this.pageSize, this.baseTotal);
4857
5000
  // Clamp renderEnd to what we actually know exists (-1 when empty)
4858
5001
  const clampedEnd = Math.min(this.renderEnd, effectiveTotal - 1);
4859
5002
  const colCount = this.columns.length;
@@ -4884,21 +5027,14 @@ const MrdTable = class {
4884
5027
  isActive ? `mrd-table__header--sorted-${this.sortDir}` : '',
4885
5028
  isFiltered ? 'mrd-table__header--filtered' : '',
4886
5029
  ].filter(Boolean).join(' ');
4887
- return (index.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 }, index.h("span", { class: "mrd-table__header-label" }, (_a = col.label) !== null && _a !== void 0 ? _a : ''), isInteractive && isActive && (index.h("span", { class: "mrd-table__sort-icon", "aria-hidden": "true" }, this.sortDir === 'asc' ? '▲' : '▼')), isInteractive && !isActive && !this.filterMode && (index.h("span", { class: "mrd-table__sort-icon", "aria-hidden": "true" }, "\u21C5")), isInteractive && isFiltered && this.renderFilterIcon()));
4888
- }))), index.h("tbody", null, topSpacerHeight > 0 && (index.h("tr", { class: "mrd-table__spacer", style: { height: `${topSpacerHeight}px` } }, index.h("td", { colSpan: colCount }))), renderedRows, bottomSpacerHeight > 0 && (index.h("tr", { class: "mrd-table__spacer", style: { height: `${bottomSpacerHeight}px` } }, index.h("td", { colSpan: colCount })))), this.renderTotalsRow())), effectiveTotal === 0 && this.loadedPages.has(0) && (index.h("p", { class: "mrd-table__empty" }, t('no_results', this.locale))), effectiveTotal > 0 && this.renderFooter(undefined, effectiveTotal, this.isTotalKnown()), this.renderFilterPopup(), this.renderTextblockModal()));
4889
- }
4890
- renderFilterIcon() {
4891
- return (index.h("span", { class: "mrd-table__filter-icon", "aria-hidden": "true" }, index.h("svg", { viewBox: "0 0 24 24", width: "14", height: "14", fill: "currentColor" }, index.h("path", { d: "M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z" }))));
5030
+ return (index.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 }, index.h("span", { class: "mrd-table__header-label" }, (_a = col.label) !== null && _a !== void 0 ? _a : ''), isInteractive && isActive && (index.h("span", { class: "mrd-table__sort-icon", "aria-hidden": "true" }, this.sortDir === 'asc' ? '▲' : '▼')), isInteractive && !isActive && !this.filterMode && (index.h("span", { class: "mrd-table__sort-icon", "aria-hidden": "true" }, "\u21C5")), isInteractive && isFiltered && index.h(FilterIcon, null)));
5031
+ }))), index.h("tbody", null, topSpacerHeight > 0 && (index.h("tr", { class: "mrd-table__spacer", style: { height: `${topSpacerHeight}px` } }, index.h("td", { colSpan: colCount }))), renderedRows, bottomSpacerHeight > 0 && (index.h("tr", { class: "mrd-table__spacer", style: { height: `${bottomSpacerHeight}px` } }, index.h("td", { colSpan: colCount })))), this.renderTotalsRow())), effectiveTotal === 0 && this.loadedPages.has(0) && (index.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()));
4892
5032
  }
4893
5033
  renderTextblockModal() {
4894
- if (this.textblockModal === null)
4895
- return null;
4896
- return (index.h("div", { class: "mrd-table__modal-backdrop", onClick: () => this.closeTextblockModal(), role: "dialog", "aria-modal": "true" }, index.h("div", { class: "mrd-table__modal", onClick: (e) => e.stopPropagation() }, index.h("button", { class: "mrd-table__modal-close", onClick: () => this.closeTextblockModal(), "aria-label": t('close', this.locale) }, "\u2715"), index.h("p", { class: "mrd-table__modal-text" }, this.textblockModal))));
5034
+ return index.h(TextblockModal, { text: this.textblockModal, locale: this.locale, onClose: () => this.closeTextblockModal() });
4897
5035
  }
4898
5036
  renderJsonModal() {
4899
- if (this.jsonModal === null)
4900
- return null;
4901
- return (index.h("div", { class: "mrd-table__modal-backdrop", onClick: () => this.closeJsonModal(), role: "dialog", "aria-modal": "true" }, index.h("div", { class: "mrd-table__modal", onClick: (e) => e.stopPropagation() }, index.h("button", { class: "mrd-table__modal-close", onClick: () => this.closeJsonModal(), "aria-label": t('close', this.locale) }, "\u2715"), index.h("pre", { class: "mrd-table__modal-json", innerHTML: this.jsonModal }))));
5037
+ return index.h(JsonModal, { html: this.jsonModal, locale: this.locale, onClose: () => this.closeJsonModal() });
4902
5038
  }
4903
5039
  get el() { return index.getElement(this); }
4904
5040
  static get watchers() { return {
@@ -4910,9 +5046,9 @@ const MrdTable = class {
4910
5046
  }]
4911
5047
  }; }
4912
5048
  };
4913
- MrdTable.style = mrdTableScss();
5049
+ MrdTable.style = mrdTableCss();
4914
5050
 
4915
- 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)}`;
5051
+ 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)}`;
4916
5052
 
4917
5053
  const MrdTextField = class {
4918
5054
  constructor(hostRef) {
@@ -4933,23 +5069,17 @@ const MrdTextField = class {
4933
5069
  };
4934
5070
  this.handleBlur = (e) => {
4935
5071
  const val = e.target.value;
4936
- if (this.required && !validateRequired(val)) {
4937
- this.error = t('required', this.locale);
4938
- }
4939
- else {
4940
- this.error = '';
4941
- }
5072
+ this.error = requiredError(val, this.required, this.locale);
4942
5073
  this.mrdBlur.emit({ name: this.name, value: val });
4943
5074
  };
4944
5075
  }
4945
5076
  render() {
4946
- const hasError = !!this.error;
4947
- return (index.h(index.Host, { key: 'e9252b251faf98ab190e643b97c13fa32d12ef22' }, index.h("div", { key: '37f4259a111c293f2fe12f321f08c00c25e77feb', class: "mrd-text-field" }, this.label && (index.h("label", { key: 'c59e0346fb71a765ea38629b03c06341567ed210', class: `mrd-text-field__label${this.required ? ' mrd-text-field__label--required' : ''}` }, this.label)), index.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 && index.h("span", { key: '037653857a372854a16b28ebf8994b23e3e0d696', class: "mrd-text-field__error" }, this.error))));
5077
+ return (index.h(index.Host, { key: '71de1ae949941820574fc2d45cac6cca8264d8f9' }, index.h("div", { key: 'a63d3dd0811e012ae3d5a9f02c1a2ad1fcc0af86', class: "mrd-text-field" }, index.h(FieldLabel, { key: '1a6db878b634364f47522209344540a9cdc20635', base: "mrd-text-field", label: this.label, required: this.required }), index.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 }), index.h(FieldError, { key: '1530066fefbda722df0c37871978995a139fcef0', base: "mrd-text-field", error: this.error }))));
4948
5078
  }
4949
5079
  };
4950
- MrdTextField.style = mrdTextFieldScss();
5080
+ MrdTextField.style = mrdTextFieldCss();
4951
5081
 
4952
- 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)}`;
5082
+ 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}`;
4953
5083
 
4954
5084
  const MrdTextareaField = class {
4955
5085
  constructor(hostRef) {
@@ -5002,12 +5132,7 @@ const MrdTextareaField = class {
5002
5132
  var _a, _b;
5003
5133
  if (!range) {
5004
5134
  const html = (_b = (_a = this.editorEl.querySelector('.ql-editor')) === null || _a === void 0 ? void 0 : _a.innerHTML) !== null && _b !== void 0 ? _b : '';
5005
- if (this.required && !validateRequired(html)) {
5006
- this.error = t('required', this.locale);
5007
- }
5008
- else {
5009
- this.error = '';
5010
- }
5135
+ this.error = requiredError(html, this.required, this.locale);
5011
5136
  this.mrdBlur.emit({ name: this.name, value: html });
5012
5137
  }
5013
5138
  });
@@ -5018,13 +5143,13 @@ const MrdTextareaField = class {
5018
5143
  }
5019
5144
  }
5020
5145
  render() {
5021
- return (index.h(index.Host, { key: 'fe7824c81e082c3f2c1cf18c11dde20cb1f40f2c' }, index.h("div", { key: 'adf394a7e146d16bc79006873a209b11d88b2e17', class: "mrd-textarea-field" }, this.label && (index.h("label", { key: '1b0dd2b4cf26c55a0af05c67a3178edc0c9d56c4', class: `mrd-textarea-field__label${this.required ? ' mrd-textarea-field__label--required' : ''}` }, this.label)), index.h("div", { key: '7c8fe88b222af0beed08db492aa9f6d890e0dc5b', class: `mrd-textarea-field__container${this.error ? ' mrd-textarea-field__container--error' : ''}` }, index.h("div", { key: '295968283e94812cb04660117c5bdeaf3647469c', class: "mrd-textarea-field__editor" })), this.error && index.h("span", { key: '5b5ab61053ab0792d4c249de04bd1d13b51469bf', class: "mrd-textarea-field__error" }, this.error))));
5146
+ return (index.h(index.Host, { key: '464c1edde8447043d9352f1b5f9757bba97e9b17' }, index.h("div", { key: '8d06728214f54feeb1063700e5aaf7c439eb5473', class: "mrd-textarea-field" }, index.h(FieldLabel, { key: 'dbf93ecf41bd704706b49f8c455262798fbbe10b', base: "mrd-textarea-field", label: this.label, required: this.required }), index.h("div", { key: '9c39ccfa38ee01b880973966e910ee32aa60b144', class: controlClass('mrd-textarea-field', !!this.error, 'container') }, index.h("div", { key: '0217cd4350c1933018b2b8f489516b6d43a52538', class: "mrd-textarea-field__editor" })), index.h(FieldError, { key: '62d2a5db053ea6e4ec6868440f3ab31e1c05e633', base: "mrd-textarea-field", error: this.error }))));
5022
5147
  }
5023
5148
  get el() { return index.getElement(this); }
5024
5149
  };
5025
- MrdTextareaField.style = mrdTextareaFieldScss();
5150
+ MrdTextareaField.style = mrdTextareaFieldCss();
5026
5151
 
5027
- 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)}`;
5152
+ 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}`;
5028
5153
 
5029
5154
  const MrdTimeField = class {
5030
5155
  constructor(hostRef) {
@@ -5040,12 +5165,7 @@ const MrdTimeField = class {
5040
5165
  this.error = '';
5041
5166
  this.handleChange = (e) => {
5042
5167
  const val = e.target.value;
5043
- if (this.required && !validateRequired(val)) {
5044
- this.error = t('required', this.locale);
5045
- }
5046
- else {
5047
- this.error = '';
5048
- }
5168
+ this.error = requiredError(val, this.required, this.locale);
5049
5169
  this.mrdChange.emit({ name: this.name, value: val });
5050
5170
  };
5051
5171
  this.handleBlur = (e) => {
@@ -5054,11 +5174,10 @@ const MrdTimeField = class {
5054
5174
  };
5055
5175
  }
5056
5176
  render() {
5057
- const hasError = !!this.error;
5058
- return (index.h(index.Host, { key: '579219a478e31325b5a676465807c1d936724a2b' }, index.h("div", { key: '51b25f6e083a29989505c0ad79edbcd3b0060736', class: "mrd-time-field" }, this.label && (index.h("label", { key: '67d98bebb8803deea2d2a4a63f36706789ccd8c7', class: `mrd-time-field__label${this.required ? ' mrd-time-field__label--required' : ''}` }, this.label)), index.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 && index.h("span", { key: '0dbd168d14966dc56a77c97cd8fd8f9b208a4bf5', class: "mrd-time-field__error" }, this.error))));
5177
+ return (index.h(index.Host, { key: 'fc30bdeb7c8d37bebc67a768f48013602879fb3d' }, index.h("div", { key: '52f899a889376773c1948f0c116670684db25cf4', class: "mrd-time-field" }, index.h(FieldLabel, { key: '3aba58f122fa4bb9f0ba4ad0b56fc3b29f03d4a3', base: "mrd-time-field", label: this.label, required: this.required }), index.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 }), index.h(FieldError, { key: '07ad4ccbc5188e129d8bd3085e856839ec6a81c9', base: "mrd-time-field", error: this.error }))));
5059
5178
  }
5060
5179
  };
5061
- MrdTimeField.style = mrdTimeFieldScss();
5180
+ MrdTimeField.style = mrdTimeFieldCss();
5062
5181
 
5063
5182
  exports.mrd_boolean_field = MrdBooleanField;
5064
5183
  exports.mrd_currency_field = MrdCurrencyField;