@mmlogic/components 0.3.11 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/dist/cjs/{index-BPj2cBXs.js → index-CAzwGt9u.js} +38 -0
  2. package/dist/cjs/loader.cjs.js +2 -2
  3. package/dist/cjs/mosterdcomponents.cjs.js +2 -2
  4. package/dist/cjs/mrd-boolean-field_23.cjs.entry.js +1313 -1088
  5. package/dist/collection/collection-manifest.json +23 -23
  6. package/dist/collection/components/{mrd-document-container/mrd-document-container.scss → documents/mrd-document-container/mrd-document-container.css} +3 -3
  7. package/dist/collection/components/{mrd-document-container → documents/mrd-document-container}/mrd-document-container.js +7 -7
  8. package/dist/collection/components/documents/mrd-document-list/folder-tree.js +109 -0
  9. package/dist/collection/components/{mrd-document-list/mrd-document-list.scss → documents/mrd-document-list/mrd-document-list.css} +6 -4
  10. package/dist/collection/components/{mrd-document-list → documents/mrd-document-list}/mrd-document-list.js +83 -240
  11. package/dist/collection/components/documents/mrd-document-list/tree-view.js +75 -0
  12. package/dist/collection/components/{mrd-document-view/mrd-document-view.scss → documents/mrd-document-view/mrd-document-view.css} +1 -1
  13. package/dist/collection/components/{mrd-document-view → documents/mrd-document-view}/mrd-document-view.js +4 -4
  14. package/dist/collection/components/fields/field-helpers.js +17 -0
  15. package/dist/collection/components/fields/file-upload-common.js +38 -0
  16. package/dist/collection/components/{mrd-boolean-field/mrd-boolean-field.scss → fields/mrd-boolean-field/mrd-boolean-field.css} +3 -3
  17. package/dist/collection/components/{mrd-boolean-field → fields/mrd-boolean-field}/mrd-boolean-field.js +1 -1
  18. package/dist/collection/components/{mrd-currency-field/mrd-currency-field.scss → fields/mrd-currency-field/mrd-currency-field.css} +11 -9
  19. package/dist/collection/components/{mrd-currency-field → fields/mrd-currency-field}/mrd-currency-field.js +7 -13
  20. package/dist/collection/components/{mrd-date-field/mrd-date-field.scss → fields/mrd-date-field/mrd-date-field.css} +8 -10
  21. package/dist/collection/components/{mrd-date-field → fields/mrd-date-field}/mrd-date-field.js +3 -10
  22. package/dist/collection/components/{mrd-datetime-field/mrd-datetime-field.scss → fields/mrd-datetime-field/mrd-datetime-field.css} +8 -10
  23. package/dist/collection/components/{mrd-datetime-field → fields/mrd-datetime-field}/mrd-datetime-field.js +3 -10
  24. package/dist/collection/components/{mrd-email-field/mrd-email-field.scss → fields/mrd-email-field/mrd-email-field.css} +2 -11
  25. package/dist/collection/components/{mrd-email-field → fields/mrd-email-field}/mrd-email-field.js +6 -13
  26. package/dist/collection/components/{mrd-file-field/mrd-file-field.scss → fields/mrd-file-field/mrd-file-field.css} +19 -24
  27. package/dist/collection/components/{mrd-file-field → fields/mrd-file-field}/mrd-file-field.js +13 -24
  28. package/dist/collection/components/{mrd-hyperlink-field/mrd-hyperlink-field.scss → fields/mrd-hyperlink-field/mrd-hyperlink-field.css} +7 -16
  29. package/dist/collection/components/{mrd-hyperlink-field → fields/mrd-hyperlink-field}/mrd-hyperlink-field.js +9 -15
  30. package/dist/collection/components/{mrd-image-field/mrd-image-field.scss → fields/mrd-image-field/mrd-image-field.css} +15 -24
  31. package/dist/collection/components/{mrd-image-field → fields/mrd-image-field}/mrd-image-field.js +13 -28
  32. package/dist/collection/components/{mrd-list-field/mrd-list-field.scss → fields/mrd-list-field/mrd-list-field.css} +18 -21
  33. package/dist/collection/components/{mrd-list-field → fields/mrd-list-field}/mrd-list-field.js +10 -25
  34. package/dist/collection/components/{mrd-longtext-field/mrd-longtext-field.scss → fields/mrd-longtext-field/mrd-longtext-field.css} +21 -18
  35. package/dist/collection/components/{mrd-longtext-field → fields/mrd-longtext-field}/mrd-longtext-field.js +3 -10
  36. package/dist/collection/components/{mrd-number-field/mrd-number-field.scss → fields/mrd-number-field/mrd-number-field.css} +9 -10
  37. package/dist/collection/components/{mrd-number-field → fields/mrd-number-field}/mrd-number-field.js +7 -6
  38. package/dist/collection/components/{mrd-relation-field/mrd-relation-field.scss → fields/mrd-relation-field/mrd-relation-field.css} +61 -59
  39. package/dist/collection/components/{mrd-relation-field → fields/mrd-relation-field}/mrd-relation-field.js +16 -26
  40. package/dist/collection/components/{mrd-secret-field/mrd-secret-field.scss → fields/mrd-secret-field/mrd-secret-field.css} +7 -10
  41. package/dist/collection/components/{mrd-secret-field → fields/mrd-secret-field}/mrd-secret-field.js +4 -11
  42. package/dist/collection/components/{mrd-text-field/mrd-text-field.scss → fields/mrd-text-field/mrd-text-field.css} +2 -11
  43. package/dist/collection/components/{mrd-text-field → fields/mrd-text-field}/mrd-text-field.js +3 -10
  44. package/dist/collection/components/{mrd-textarea-field/mrd-textarea-field.scss → fields/mrd-textarea-field/mrd-textarea-field.css} +7 -10
  45. package/dist/collection/components/{mrd-textarea-field → fields/mrd-textarea-field}/mrd-textarea-field.js +3 -9
  46. package/dist/collection/components/{mrd-time-field/mrd-time-field.scss → fields/mrd-time-field/mrd-time-field.css} +8 -10
  47. package/dist/collection/components/{mrd-time-field → fields/mrd-time-field}/mrd-time-field.js +3 -10
  48. package/dist/collection/components/{mrd-field/mrd-field.scss → form/mrd-field/mrd-field.css} +1 -1
  49. package/dist/collection/components/{mrd-field → form/mrd-field}/mrd-field.js +3 -3
  50. package/dist/collection/components/{mrd-form/mrd-form.scss → form/mrd-form/mrd-form.css} +1 -1
  51. package/dist/collection/components/{mrd-form → form/mrd-form}/mrd-form.js +5 -5
  52. package/dist/collection/components/layout/mrd-layout-section/field-value.js +111 -0
  53. package/dist/collection/components/layout/mrd-layout-section/layout-helpers.js +29 -0
  54. package/dist/collection/components/{mrd-layout-section/mrd-layout-section.scss → layout/mrd-layout-section/mrd-layout-section.css} +4 -4
  55. package/dist/collection/components/{mrd-layout-section → layout/mrd-layout-section}/mrd-layout-section.js +52 -142
  56. package/dist/collection/components/{mrd-table/mrd-table.scss → table/mrd-table/mrd-table.css} +30 -12
  57. package/dist/collection/components/{mrd-table → table/mrd-table}/mrd-table.js +234 -443
  58. package/dist/collection/components/table/mrd-table/table-filter-popup.js +85 -0
  59. package/dist/collection/components/table/mrd-table/table-parts.js +110 -0
  60. package/dist/collection/components/table/mrd-table/table-query.js +178 -0
  61. package/dist/collection/components/table/mrd-table/virtual-scroll.js +63 -0
  62. package/dist/collection/dev/app.js +19 -18
  63. package/dist/collection/dev/example-data.js +58 -43
  64. package/dist/collection/utils/i18n.js +16 -0
  65. package/dist/collection/utils/query-params.js +43 -0
  66. package/dist/components/field-helpers.js +1 -0
  67. package/dist/components/file-upload-common.js +1 -0
  68. package/dist/components/i18n.js +1 -1
  69. package/dist/components/mrd-boolean-field2.js +1 -1
  70. package/dist/components/mrd-currency-field2.js +1 -1
  71. package/dist/components/mrd-date-field2.js +1 -1
  72. package/dist/components/mrd-datetime-field2.js +1 -1
  73. package/dist/components/mrd-document-container2.js +1 -1
  74. package/dist/components/mrd-document-list2.js +1 -1
  75. package/dist/components/mrd-document-view2.js +1 -1
  76. package/dist/components/mrd-email-field2.js +1 -1
  77. package/dist/components/mrd-file-field2.js +1 -1
  78. package/dist/components/mrd-form.js +1 -1
  79. package/dist/components/mrd-hyperlink-field2.js +1 -1
  80. package/dist/components/mrd-image-field2.js +1 -1
  81. package/dist/components/mrd-layout-section.js +1 -1
  82. package/dist/components/mrd-list-field2.js +1 -1
  83. package/dist/components/mrd-longtext-field2.js +1 -1
  84. package/dist/components/mrd-number-field2.js +1 -1
  85. package/dist/components/mrd-relation-field2.js +1 -1
  86. package/dist/components/mrd-secret-field2.js +1 -1
  87. package/dist/components/mrd-table2.js +1 -1
  88. package/dist/components/mrd-text-field2.js +1 -1
  89. package/dist/components/mrd-textarea-field2.js +1 -1
  90. package/dist/components/mrd-time-field2.js +1 -1
  91. package/dist/components/query-params.js +1 -0
  92. package/dist/esm/{index-_tsCCkAi.js → index-DiSEJMA8.js} +38 -1
  93. package/dist/esm/loader.js +3 -3
  94. package/dist/esm/mosterdcomponents.js +3 -3
  95. package/dist/esm/mrd-boolean-field_23.entry.js +1313 -1088
  96. package/dist/mosterdcomponents/mosterdcomponents.css +1 -1
  97. package/dist/mosterdcomponents/mosterdcomponents.esm.js +1 -1
  98. package/dist/mosterdcomponents/p-DiSEJMA8.js +2 -0
  99. package/dist/mosterdcomponents/p-b1a2e108.entry.js +1 -0
  100. package/dist/types/components/{mrd-document-container → documents/mrd-document-container}/mrd-document-container.d.ts +2 -2
  101. package/dist/types/components/documents/mrd-document-list/folder-tree.d.ts +66 -0
  102. package/dist/types/components/{mrd-document-list → documents/mrd-document-list}/mrd-document-list.d.ts +4 -37
  103. package/dist/types/components/documents/mrd-document-list/tree-view.d.ts +32 -0
  104. package/dist/types/components/{mrd-document-view → documents/mrd-document-view}/mrd-document-view.d.ts +2 -2
  105. package/dist/types/components/fields/field-helpers.d.ts +18 -0
  106. package/dist/types/components/fields/file-upload-common.d.ts +18 -0
  107. package/dist/types/components/{mrd-boolean-field → fields/mrd-boolean-field}/mrd-boolean-field.d.ts +1 -1
  108. package/dist/types/components/{mrd-currency-field → fields/mrd-currency-field}/mrd-currency-field.d.ts +2 -2
  109. package/dist/types/components/{mrd-date-field → fields/mrd-date-field}/mrd-date-field.d.ts +1 -1
  110. package/dist/types/components/{mrd-datetime-field → fields/mrd-datetime-field}/mrd-datetime-field.d.ts +1 -1
  111. package/dist/types/components/{mrd-email-field → fields/mrd-email-field}/mrd-email-field.d.ts +1 -1
  112. package/dist/types/components/{mrd-file-field → fields/mrd-file-field}/mrd-file-field.d.ts +2 -4
  113. package/dist/types/components/{mrd-hyperlink-field → fields/mrd-hyperlink-field}/mrd-hyperlink-field.d.ts +2 -2
  114. package/dist/types/components/{mrd-image-field → fields/mrd-image-field}/mrd-image-field.d.ts +2 -4
  115. package/dist/types/components/{mrd-list-field → fields/mrd-list-field}/mrd-list-field.d.ts +2 -2
  116. package/dist/types/components/{mrd-longtext-field → fields/mrd-longtext-field}/mrd-longtext-field.d.ts +1 -1
  117. package/dist/types/components/{mrd-number-field → fields/mrd-number-field}/mrd-number-field.d.ts +2 -2
  118. package/dist/types/components/{mrd-relation-field → fields/mrd-relation-field}/mrd-relation-field.d.ts +2 -2
  119. package/dist/types/components/{mrd-secret-field → fields/mrd-secret-field}/mrd-secret-field.d.ts +1 -1
  120. package/dist/types/components/{mrd-text-field → fields/mrd-text-field}/mrd-text-field.d.ts +1 -1
  121. package/dist/types/components/{mrd-textarea-field → fields/mrd-textarea-field}/mrd-textarea-field.d.ts +1 -1
  122. package/dist/types/components/{mrd-time-field → fields/mrd-time-field}/mrd-time-field.d.ts +1 -1
  123. package/dist/types/components/{mrd-field → form/mrd-field}/mrd-field.d.ts +2 -2
  124. package/dist/types/components/{mrd-form → form/mrd-form}/mrd-form.d.ts +2 -2
  125. package/dist/types/components/layout/mrd-layout-section/field-value.d.ts +22 -0
  126. package/dist/types/components/layout/mrd-layout-section/layout-helpers.d.ts +8 -0
  127. package/dist/types/components/{mrd-layout-section → layout/mrd-layout-section}/mrd-layout-section.d.ts +4 -11
  128. package/dist/types/components/{mrd-table → table/mrd-table}/mrd-table.d.ts +29 -13
  129. package/dist/types/components/table/mrd-table/table-filter-popup.d.ts +35 -0
  130. package/dist/types/components/table/mrd-table/table-parts.d.ts +61 -0
  131. package/dist/types/components/table/mrd-table/table-query.d.ts +50 -0
  132. package/dist/types/components/table/mrd-table/virtual-scroll.d.ts +33 -0
  133. package/dist/types/components.d.ts +19 -5
  134. package/dist/types/utils/query-params.d.ts +14 -0
  135. package/package.json +7 -2
  136. package/dist/components/validation.js +0 -1
  137. package/dist/mosterdcomponents/p-_tsCCkAi.js +0 -2
  138. package/dist/mosterdcomponents/p-a9618055.entry.js +0 -1
@@ -1,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,8 +122,10 @@ 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',
128
+ load_failed_retry: 'Laden mislukt — opnieuw proberen',
54
129
  loading: 'Laden...',
55
130
  submit: 'Opslaan',
56
131
  cancel: 'Annuleren',
@@ -121,8 +196,10 @@ const translations = {
121
196
  drop_file_here: 'Drop file here or',
122
197
  browse: 'browse',
123
198
  file_too_large: 'File is too large',
199
+ invalid_image: 'Please select an image file',
124
200
  search_results: 'Search results',
125
201
  no_results: 'No results found',
202
+ load_failed_retry: 'Failed to load — retry',
126
203
  loading: 'Loading...',
127
204
  submit: 'Save',
128
205
  cancel: 'Cancel',
@@ -193,8 +270,10 @@ const translations = {
193
270
  drop_file_here: 'اسحب الملف هنا أو',
194
271
  browse: 'تصفح',
195
272
  file_too_large: 'الملف كبير جداً',
273
+ invalid_image: 'يرجى اختيار ملف صورة',
196
274
  search_results: 'نتائج البحث',
197
275
  no_results: 'لم يتم العثور على نتائج',
276
+ load_failed_retry: 'فشل التحميل — إعادة المحاولة',
198
277
  loading: 'جار التحميل...',
199
278
  submit: 'حفظ',
200
279
  cancel: 'إلغاء',
@@ -259,8 +338,10 @@ const translations = {
259
338
  drop_file_here: 'Déposez le fichier ici ou',
260
339
  browse: 'parcourir',
261
340
  file_too_large: 'Le fichier est trop volumineux',
341
+ invalid_image: 'Veuillez sélectionner un fichier image',
262
342
  search_results: 'Résultats de recherche',
263
343
  no_results: 'Aucun résultat trouvé',
344
+ load_failed_retry: 'Échec du chargement — réessayer',
264
345
  loading: 'Chargement...',
265
346
  submit: 'Enregistrer',
266
347
  cancel: 'Annuler',
@@ -325,8 +406,10 @@ const translations = {
325
406
  drop_file_here: 'Datei hier ablegen oder',
326
407
  browse: 'durchsuchen',
327
408
  file_too_large: 'Datei ist zu groß',
409
+ invalid_image: 'Bitte eine Bilddatei auswählen',
328
410
  search_results: 'Suchergebnisse',
329
411
  no_results: 'Keine Ergebnisse gefunden',
412
+ load_failed_retry: 'Laden fehlgeschlagen — erneut versuchen',
330
413
  loading: 'Laden...',
331
414
  submit: 'Speichern',
332
415
  cancel: 'Abbrechen',
@@ -391,8 +474,10 @@ const translations = {
391
474
  drop_file_here: 'Suelte el archivo aquí o',
392
475
  browse: 'explorar',
393
476
  file_too_large: 'El archivo es demasiado grande',
477
+ invalid_image: 'Seleccione un archivo de imagen',
394
478
  search_results: 'Resultados de búsqueda',
395
479
  no_results: 'No se encontraron resultados',
480
+ load_failed_retry: 'Error al cargar — reintentar',
396
481
  loading: 'Cargando...',
397
482
  submit: 'Guardar',
398
483
  cancel: 'Cancelar',
@@ -457,8 +542,10 @@ const translations = {
457
542
  drop_file_here: 'Trascina il file qui o',
458
543
  browse: 'sfoglia',
459
544
  file_too_large: 'Il file è troppo grande',
545
+ invalid_image: 'Seleziona un file immagine',
460
546
  search_results: 'Risultati della ricerca',
461
547
  no_results: 'Nessun risultato trovato',
548
+ load_failed_retry: 'Caricamento non riuscito — riprova',
462
549
  loading: 'Caricamento...',
463
550
  submit: 'Salva',
464
551
  cancel: 'Annulla',
@@ -523,8 +610,10 @@ const translations = {
523
610
  drop_file_here: 'Перетягніть файл сюди або',
524
611
  browse: 'огляд',
525
612
  file_too_large: 'Файл занадто великий',
613
+ invalid_image: 'Будь ласка, виберіть файл зображення',
526
614
  search_results: 'Результати пошуку',
527
615
  no_results: 'Результатів не знайдено',
616
+ load_failed_retry: 'Не вдалося завантажити — повторити',
528
617
  loading: 'Завантаження...',
529
618
  submit: 'Зберегти',
530
619
  cancel: 'Скасувати',
@@ -633,80 +722,22 @@ function validateNumber(value, dataType) {
633
722
  return true;
634
723
  }
635
724
 
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);
725
+ /**
726
+ * Shared building blocks for the leaf field components.
727
+ * `base` is the BEM block name, e.g. 'mrd-text-field'.
728
+ */
729
+ const FieldLabel = ({ base, label, required }) => label ? index.h("label", { class: `${base}__label${required ? ` ${base}__label--required` : ''}` }, label) : null;
730
+ const FieldError = ({ base, error }) => error ? index.h("span", { class: `${base}__error` }, error) : null;
731
+ /** Class string for the form control, with the --error modifier when applicable. */
732
+ function controlClass(base, hasError, element = 'input') {
733
+ return `${base}__${element}${hasError ? ` ${base}__${element}--error` : ''}`;
659
734
  }
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;
735
+ /** Returns the localised required-error, or '' when the value passes. */
736
+ function requiredError(value, required, locale) {
737
+ return required && !validateRequired(value) ? t('required', locale) : '';
707
738
  }
708
739
 
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)}`;
740
+ 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
741
 
711
742
  const COMMON_CURRENCIES = [
712
743
  'EUR', 'USD', 'GBP', 'CHF', 'JPY', 'CNY', 'AUD', 'CAD',
@@ -733,12 +764,7 @@ const MrdCurrencyField = class {
733
764
  this.handleAmountBlur = (e) => {
734
765
  const raw = e.target.value;
735
766
  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
- }
767
+ this.error = requiredError(raw, this.required, this.locale);
742
768
  const val = { amount: parsed, currency: this.currency };
743
769
  this.mrdChange.emit({ name: this.name, value: val });
744
770
  this.mrdBlur.emit({ name: this.name, value: val });
@@ -757,12 +783,12 @@ const MrdCurrencyField = class {
757
783
  }
758
784
  render() {
759
785
  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))));
786
+ 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
787
  }
762
788
  };
763
- MrdCurrencyField.style = mrdCurrencyFieldScss();
789
+ MrdCurrencyField.style = mrdCurrencyFieldCss();
764
790
 
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)}`;
791
+ 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
792
 
767
793
  const MrdDateField = class {
768
794
  constructor(hostRef) {
@@ -778,12 +804,7 @@ const MrdDateField = class {
778
804
  this.error = '';
779
805
  this.handleChange = (e) => {
780
806
  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
- }
807
+ this.error = requiredError(val, this.required, this.locale);
787
808
  this.mrdChange.emit({ name: this.name, value: val });
788
809
  };
789
810
  this.handleBlur = (e) => {
@@ -792,13 +813,12 @@ const MrdDateField = class {
792
813
  };
793
814
  }
794
815
  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))));
816
+ 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
817
  }
798
818
  };
799
- MrdDateField.style = mrdDateFieldScss();
819
+ MrdDateField.style = mrdDateFieldCss();
800
820
 
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)}`;
821
+ 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
822
 
803
823
  const MrdDatetimeField = class {
804
824
  constructor(hostRef) {
@@ -816,12 +836,7 @@ const MrdDatetimeField = class {
816
836
  this.handleChange = (e) => {
817
837
  const localVal = e.target.value;
818
838
  this.localValue = localVal;
819
- if (this.required && !validateRequired(localVal)) {
820
- this.error = t('required', this.locale);
821
- }
822
- else {
823
- this.error = '';
824
- }
839
+ this.error = requiredError(localVal, this.required, this.locale);
825
840
  this.mrdChange.emit({ name: this.name, value: this.localToUtc(localVal) });
826
841
  };
827
842
  this.handleBlur = (e) => {
@@ -855,8 +870,7 @@ const MrdDatetimeField = class {
855
870
  return d.toISOString().replace(/\.\d{3}Z$/, 'Z');
856
871
  }
857
872
  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))));
873
+ 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
874
  }
861
875
  static get watchers() { return {
862
876
  "value": [{
@@ -864,9 +878,9 @@ const MrdDatetimeField = class {
864
878
  }]
865
879
  }; }
866
880
  };
867
- MrdDatetimeField.style = mrdDatetimeFieldScss();
881
+ MrdDatetimeField.style = mrdDatetimeFieldCss();
868
882
 
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}`;
883
+ 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
884
 
871
885
  const MrdDocumentContainer = class {
872
886
  constructor(hostRef) {
@@ -898,8 +912,8 @@ const MrdDocumentContainer = class {
898
912
  /** Whether the currently mounted table has been init()'d. Reset on every mode switch. */
899
913
  this.tableInited = false;
900
914
  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);
915
+ var _a;
916
+ (_a = this.listEl) === null || _a === void 0 ? void 0 : _a.createFolder();
903
917
  };
904
918
  }
905
919
  /** The embedded table does not self-load: like every mrd-table it waits for the
@@ -911,7 +925,7 @@ const MrdDocumentContainer = class {
911
925
  if (this.mode === 'list' && this.tableEl && !this.tableInited) {
912
926
  this.tableInited = true;
913
927
  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); });
928
+ Promise.resolve((_a = table.componentOnReady) === null || _a === void 0 ? void 0 : _a.call(table)).then(() => table.init());
915
929
  }
916
930
  }
917
931
  setMode(mode) {
@@ -971,13 +985,240 @@ const MrdDocumentContainer = class {
971
985
  }
972
986
  render() {
973
987
  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())));
988
+ 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
989
  }
976
990
  get el() { return index.getElement(this); }
977
991
  };
978
- MrdDocumentContainer.style = mrdDocumentContainerScss();
992
+ MrdDocumentContainer.style = mrdDocumentContainerCss();
993
+
994
+ /**
995
+ * Shared path/query-param conventions for list requests,
996
+ * used by mrd-table and mrd-document-list.
997
+ */
998
+ /** Applies the view-level static filters to `params` using the API operator conventions. */
999
+ function applyViewFilters(params, filters) {
1000
+ var _a, _b, _c;
1001
+ for (const f of filters !== null && filters !== void 0 ? filters : []) {
1002
+ if (!f.name)
1003
+ continue;
1004
+ if (f.operator === 'EMPTY') {
1005
+ params.set(f.name, '');
1006
+ continue;
1007
+ }
1008
+ if (f.operator === 'NOT_EMPTY') {
1009
+ params.set(f.name + '_notempty', 'true');
1010
+ continue;
1011
+ }
1012
+ if (f.operator === 'STARTS_WITH') {
1013
+ params.set(f.name + '_startswith', String((_a = f.value) !== null && _a !== void 0 ? _a : ''));
1014
+ continue;
1015
+ }
1016
+ if (f.operator === 'FROM') {
1017
+ params.set(f.name + '_from', String((_b = f.value) !== null && _b !== void 0 ? _b : ''));
1018
+ continue;
1019
+ }
1020
+ if (f.operator === 'TO') {
1021
+ params.set(f.name + '_to', String((_c = f.value) !== null && _c !== void 0 ? _c : ''));
1022
+ continue;
1023
+ }
1024
+ if (f.value != null) {
1025
+ params.set(f.name, String(f.value));
1026
+ }
1027
+ }
1028
+ }
1029
+ /** VIEW: `/{dataClass}`; RELATED_VIEW: `/{fromClass}/{parentId}/{dataClass}`. */
1030
+ function buildListPath(opts) {
1031
+ var _a, _b, _c;
1032
+ if (opts.isRelatedView) {
1033
+ return `/${(_a = opts.fromClass) !== null && _a !== void 0 ? _a : ''}/${opts.parentId}/${(_b = opts.dataClass) !== null && _b !== void 0 ? _b : ''}`;
1034
+ }
1035
+ return `/${(_c = opts.dataClass) !== null && _c !== void 0 ? _c : ''}`;
1036
+ }
1037
+
1038
+ /**
1039
+ * Tree model and pure tree logic for mrd-document-list.
1040
+ * Nodes are mutated in place; the component triggers re-renders via bump().
1041
+ */
1042
+ /** Normalise a folder path: null/""/"/" → root ([]); else split on "/" dropping empties. */
1043
+ function splitFolder(path) {
1044
+ if (path == null)
1045
+ return [];
1046
+ const s = String(path).trim();
1047
+ if (s === '' || s === '/')
1048
+ return [];
1049
+ return s.split('/').map(x => x.trim()).filter(Boolean);
1050
+ }
1051
+ function makeContainerNode(href, label, count) {
1052
+ return {
1053
+ id: 'c:' + href, kind: 'container', label, href,
1054
+ hasDocs: false, docCount: 0, totalCount: count, children: [],
1055
+ open: false, loading: false, foldersLoaded: false, docsLoaded: false, docs: [],
1056
+ };
1057
+ }
1058
+ function makeFolderNode(id, label, containerId) {
1059
+ return {
1060
+ id, kind: 'folder', label, containerId,
1061
+ hasDocs: false, docCount: 0, totalCount: 0, children: [],
1062
+ open: false, loading: false, foldersLoaded: false, docsLoaded: false, docs: [],
1063
+ };
1064
+ }
1065
+ /** Recompute totalCount over the subtree; returns the node's aggregate. */
1066
+ function computeTotals(node) {
1067
+ let total = node.docCount;
1068
+ for (const c of node.children)
1069
+ total += computeTotals(c);
1070
+ node.totalCount = total;
1071
+ return total;
1072
+ }
1073
+ /** Folder path segments of a node relative to its container (derived from its id). */
1074
+ function segmentsOf(node, container) {
1075
+ if (node.kind === 'container')
1076
+ return [];
1077
+ const prefix = container.id + '/';
1078
+ const rest = node.id.startsWith(prefix) ? node.id.slice(prefix.length) : '';
1079
+ return rest ? rest.split('/') : [];
1080
+ }
1081
+ /** Folder string a node represents: the raw distinct value when it holds
1082
+ * documents, else derived from its path segments; null for a container root. */
1083
+ function folderStringOf(node, container) {
1084
+ if (node.kind === 'container')
1085
+ return null;
1086
+ if (node.fullPath != null && node.fullPath !== '')
1087
+ return node.fullPath;
1088
+ const segs = segmentsOf(node, container);
1089
+ return segs.length ? '/' + segs.join('/') : null;
1090
+ }
1091
+ /** Strip a single trailing extension for the document title. */
1092
+ function stripExtension(name) {
1093
+ return name.replace(/\.[^./\\]+$/, '');
1094
+ }
1095
+ /** Rebuild a container's folder subtree from the /distinct folder strings.
1096
+ * New nodes are registered in `nodeIndex`; the container is mutated in place. */
1097
+ function applyFolderDistinct(container, values, nodeIndex) {
1098
+ container.children = [];
1099
+ container.hasDocs = false;
1100
+ container.docCount = 0;
1101
+ for (const v of values) {
1102
+ const raw = typeof v.value === 'string' ? v.value : v.value == null ? '' : String(v.value);
1103
+ const segs = splitFolder(raw);
1104
+ if (segs.length === 0) {
1105
+ // Root documents — the container's own direct documents.
1106
+ container.hasDocs = true;
1107
+ container.docCount = v.count;
1108
+ container.fullPath = raw;
1109
+ continue;
1110
+ }
1111
+ let node = container;
1112
+ const acc = [];
1113
+ for (const seg of segs) {
1114
+ acc.push(seg);
1115
+ let child = node.children.find(c => c.label === seg);
1116
+ if (!child) {
1117
+ child = makeFolderNode(container.id + '/' + acc.join('/'), seg, container.id);
1118
+ node.children.push(child);
1119
+ nodeIndex.set(child.id, child);
1120
+ }
1121
+ node = child;
1122
+ }
1123
+ node.hasDocs = true;
1124
+ node.docCount = v.count;
1125
+ node.fullPath = raw;
1126
+ }
1127
+ computeTotals(container);
1128
+ container.foldersLoaded = true;
1129
+ container.loading = false;
1130
+ }
1131
+ /** Optimistic in-place tree update for a document moved between folders. */
1132
+ function applyDocMove(doc, fromNode, toNode, targetFolder) {
1133
+ fromNode.docs = fromNode.docs.filter(d => d !== doc);
1134
+ fromNode.docCount = Math.max(0, fromNode.docCount - 1);
1135
+ // A now-empty folder should stop showing an expand chevron (it disappears on
1136
+ // the next reload anyway, since it is derived from document folder strings).
1137
+ if (fromNode.docsLoaded)
1138
+ fromNode.hasDocs = fromNode.docs.length > 0;
1139
+ toNode.hasDocs = true;
1140
+ toNode.pending = false; // a pending folder is now materialised
1141
+ toNode.docCount += 1;
1142
+ if (toNode.kind === 'folder')
1143
+ toNode.fullPath = targetFolder !== null && targetFolder !== void 0 ? targetFolder : '';
1144
+ if (toNode.docsLoaded)
1145
+ toNode.docs = [...toNode.docs, doc];
1146
+ }
1147
+
1148
+ function chevron(open, leaf) {
1149
+ 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" }))));
1150
+ }
1151
+ function dossierIcon() {
1152
+ 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" })));
1153
+ }
1154
+ function folderIcon() {
1155
+ 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" })));
1156
+ }
1157
+ function docIcon() {
1158
+ 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" })));
1159
+ }
1160
+ function indent(depth) {
1161
+ return index.h("span", { class: "mrd-document-list__indent", style: { width: `${depth * 18}px` } });
1162
+ }
1163
+ function renderLoadingRow(ctx, depth) {
1164
+ 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)));
1165
+ }
1166
+ function renderUploadingRow(ctx, depth) {
1167
+ 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)));
1168
+ }
1169
+ function renderDocRow(ctx, doc, node, container, depth) {
1170
+ var _a, _b, _c, _d, _e;
1171
+ 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 : '';
1172
+ const dateRaw = ctx.dateField ? doc === null || doc === void 0 ? void 0 : doc[ctx.dateField] : undefined;
1173
+ const date = dateRaw ? formatDate(dateRaw, ctx.locale) : '';
1174
+ 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)));
1175
+ }
1176
+ function renderFolderEditRow(ctx, node, depth) {
1177
+ 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))));
1178
+ }
1179
+ function renderNodeChildren(ctx, container, node, depth) {
1180
+ const out = [];
1181
+ // Direct documents of this node (root docs live on the container node).
1182
+ if (node.hasDocs) {
1183
+ if (node.docsLoaded) {
1184
+ for (const doc of node.docs)
1185
+ out.push(renderDocRow(ctx, doc, node, container, depth));
1186
+ }
1187
+ else if (node.loading) {
1188
+ out.push(renderLoadingRow(ctx, depth));
1189
+ }
1190
+ }
1191
+ // Child folders.
1192
+ for (const child of node.children) {
1193
+ out.push(renderFolderNode(ctx, container, child, depth));
1194
+ }
1195
+ // An uploading file dropped onto this node.
1196
+ if (node.id === ctx.uploadingNodeId)
1197
+ out.push(renderUploadingRow(ctx, depth));
1198
+ return out;
1199
+ }
1200
+ function renderFolderNode(ctx, container, node, depth) {
1201
+ if (node.editing)
1202
+ return renderFolderEditRow(ctx, node, depth);
1203
+ const leaf = node.children.length === 0 && !node.hasDocs;
1204
+ const selected = node.id === ctx.selectedId;
1205
+ const cls = 'mrd-document-list__row'
1206
+ + (selected ? ' mrd-document-list__row--selected' : '')
1207
+ + (node.pending ? ' mrd-document-list__row--pending' : '')
1208
+ + (node.id === ctx.dropTargetId ? ' mrd-document-list__row--drop' : '');
1209
+ 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))));
1210
+ }
1211
+ function renderContainerNode(ctx, node, depth) {
1212
+ const selected = node.id === ctx.selectedId;
1213
+ const cls = 'mrd-document-list__row mrd-document-list__row--dossier'
1214
+ + (selected ? ' mrd-document-list__row--selected' : '')
1215
+ + (node.id === ctx.dropTargetId ? ' mrd-document-list__row--drop' : '');
1216
+ 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
1217
+ ? renderLoadingRow(ctx, depth + 1)
1218
+ : renderNodeChildren(ctx, node, node, depth + 1)))));
1219
+ }
979
1220
 
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)}`;
1221
+ 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
1222
 
982
1223
  const MrdDocumentList = class {
983
1224
  constructor(hostRef) {
@@ -1044,7 +1285,7 @@ const MrdDocumentList = class {
1044
1285
  return;
1045
1286
  const { target, container } = resolved;
1046
1287
  const tempId = `${container.id}/__new__${this.newFolderSeq++}`;
1047
- const node = this.makeFolderNode(tempId, '', container.id);
1288
+ const node = makeFolderNode(tempId, '', container.id);
1048
1289
  node.pending = true;
1049
1290
  node.editing = true;
1050
1291
  target.children = [...target.children, node];
@@ -1183,7 +1424,7 @@ const MrdDocumentList = class {
1183
1424
  }
1184
1425
  /** Seed the single implied container from context and load its folders. */
1185
1426
  seedSingleContainer() {
1186
- const node = this.makeContainerNode(this.containerHref, this.containerField, 0);
1427
+ const node = makeContainerNode(this.containerHref, this.containerField, 0);
1187
1428
  this.nodeIndex.set(node.id, node);
1188
1429
  this.containers = [node];
1189
1430
  this.rootLoading = false;
@@ -1230,61 +1471,37 @@ const MrdDocumentList = class {
1230
1471
  * type (e.g. "contents"), filtered down to the concrete `filterClass` via the
1231
1472
  * `type` query param — see baseParams(). */
1232
1473
  buildDataPath() {
1233
- var _a, _b, _c;
1474
+ var _a, _b;
1234
1475
  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}`;
1476
+ return buildListPath({
1477
+ isRelatedView: (it === null || it === void 0 ? void 0 : it.type) === index$1.ClientLayoutItemType.RELATED_VIEW,
1478
+ fromClass: it === null || it === void 0 ? void 0 : it.fromClass,
1479
+ parentId: this.parentId,
1480
+ 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 : '',
1481
+ });
1240
1482
  }
1241
1483
  /** Path for creating a new document (file-drop). Unlike buildDataPath(), this
1242
1484
  * must target the concrete type: `dataClass`/`relatedClass` can be an abstract
1243
1485
  * base type (e.g. "contents") that cannot be POSTed to directly, so prefer
1244
1486
  * `filterClass` (e.g. "documents") when present. */
1245
1487
  buildCreatePath() {
1246
- var _a, _b, _c, _d;
1488
+ var _a, _b, _c;
1247
1489
  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}`;
1490
+ return buildListPath({
1491
+ isRelatedView: (it === null || it === void 0 ? void 0 : it.type) === index$1.ClientLayoutItemType.RELATED_VIEW,
1492
+ fromClass: it === null || it === void 0 ? void 0 : it.fromClass,
1493
+ parentId: this.parentId,
1494
+ 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 : '',
1495
+ });
1253
1496
  }
1254
1497
  /** View-level static filters + filterClass, shared by every request. */
1255
1498
  baseParams() {
1256
- var _a, _b, _c, _d, _e, _f, _g;
1499
+ var _a, _b, _c;
1257
1500
  const p = new URLSearchParams();
1258
1501
  const filterClass = (_a = this.item) === null || _a === void 0 ? void 0 : _a.filterClass;
1259
1502
  if (filterClass)
1260
1503
  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
- }
1504
+ applyViewFilters(p, (_c = (_b = this.item) === null || _b === void 0 ? void 0 : _b.view) === null || _c === void 0 ? void 0 : _c.filter);
1288
1505
  return p;
1289
1506
  }
1290
1507
  emitContainerDistinct() {
@@ -1351,7 +1568,7 @@ const MrdDocumentList = class {
1351
1568
  if (!v.value || typeof v.value !== 'object')
1352
1569
  continue;
1353
1570
  const href = v.value.href;
1354
- const node = this.makeContainerNode(href, v.value.name, v.count);
1571
+ const node = makeContainerNode(href, v.value.name, v.count);
1355
1572
  nodes.push(node);
1356
1573
  this.nodeIndex.set(node.id, node);
1357
1574
  }
@@ -1369,38 +1586,7 @@ const MrdDocumentList = class {
1369
1586
  const container = this.nodeIndex.get(containerId);
1370
1587
  if (!container)
1371
1588
  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;
1589
+ applyFolderDistinct(container, values, this.nodeIndex);
1404
1590
  // If the container has root documents, load them now (they show inline on expand).
1405
1591
  if (container.hasDocs && !container.docsLoaded) {
1406
1592
  this.emitDocuments(container, container);
@@ -1408,36 +1594,6 @@ const MrdDocumentList = class {
1408
1594
  this.bump();
1409
1595
  }
1410
1596
  // ── 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
1597
  /** Force a re-render after mutating nodes in place. */
1442
1598
  bump() {
1443
1599
  this.containers = [...this.containers];
@@ -1487,14 +1643,6 @@ const MrdDocumentList = class {
1487
1643
  async createFolder() {
1488
1644
  this.startCreateFolder();
1489
1645
  }
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
1646
  commitFolder() {
1499
1647
  const node = this.pendingNode;
1500
1648
  const parent = this.pendingParent;
@@ -1519,7 +1667,7 @@ const MrdDocumentList = class {
1519
1667
  }
1520
1668
  // Finalise: swap the temp id for the real path-derived id so a later distinct
1521
1669
  // value with the same folder string merges onto this node.
1522
- const segs = [...this.segmentsOf(parent, container), name];
1670
+ const segs = [...segmentsOf(parent, container), name];
1523
1671
  this.nodeIndex.delete(node.id);
1524
1672
  node.id = container.id + '/' + segs.join('/');
1525
1673
  node.fullPath = '/' + segs.join('/');
@@ -1568,10 +1716,6 @@ const MrdDocumentList = class {
1568
1716
  this.bump();
1569
1717
  this.mrdUpload.emit({ file });
1570
1718
  }
1571
- /** Strip a single trailing extension for the document title. */
1572
- stripExtension(name) {
1573
- return name.replace(/\.[^./\\]+$/, '');
1574
- }
1575
1719
  /** Host callback with the uploaded file reference. Builds the create payload
1576
1720
  * from the archetype slots and requests the new document. */
1577
1721
  async setFileReference(uri) {
@@ -1579,16 +1723,20 @@ const MrdDocumentList = class {
1579
1723
  if (!up)
1580
1724
  return;
1581
1725
  const { file, node, container } = up;
1582
- const folder = this.folderStringOf(node, container);
1726
+ const folder = folderStringOf(node, container);
1583
1727
  const values = {
1584
1728
  [this.fileField]: uri,
1585
- [this.titleField]: this.stripExtension(file.name),
1729
+ [this.titleField]: stripExtension(file.name),
1586
1730
  [this.folderField]: folder,
1587
- [this.containerField]: container.href,
1588
1731
  };
1732
+ // The create path already embeds the container (/{fromClass}/{parentId}/...)
1733
+ // when this is the seeded single-container context; omit the redundant field.
1734
+ if (!this.isSeededSingleContainer()) {
1735
+ values[this.containerField] = container.href;
1736
+ }
1589
1737
  this.mrdCreateObject.emit({ path: this.buildCreatePath(), values });
1590
1738
  // Optimistically show the new document (no href until a reload).
1591
- const optimistic = { [this.titleField]: this.stripExtension(file.name), _optimistic: true };
1739
+ const optimistic = { [this.titleField]: stripExtension(file.name), _optimistic: true };
1592
1740
  const wasUnloadedEmpty = !node.docsLoaded && node.docCount === 0;
1593
1741
  node.hasDocs = true;
1594
1742
  node.pending = false;
@@ -1617,16 +1765,6 @@ const MrdDocumentList = class {
1617
1765
  this.lastOptimisticDoc = null;
1618
1766
  this.bump();
1619
1767
  }
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
1768
  moveDocument(toNode, toContainer) {
1631
1769
  var _a, _b;
1632
1770
  const doc = this.dragDoc;
@@ -1638,26 +1776,14 @@ const MrdDocumentList = class {
1638
1776
  : (fromNode.containerId ? this.nodeIndex.get(fromNode.containerId) : undefined);
1639
1777
  if (!fromContainer)
1640
1778
  return;
1641
- const targetFolder = this.folderStringOf(toNode, toContainer);
1642
- const sourceFolder = this.folderStringOf(fromNode, fromContainer);
1779
+ const targetFolder = folderStringOf(toNode, toContainer);
1780
+ const sourceFolder = folderStringOf(fromNode, fromContainer);
1643
1781
  const sameContainer = toContainer === fromContainer;
1644
1782
  // No-op: dropped back onto its own folder.
1645
1783
  if (toNode === fromNode || (sameContainer && targetFolder === sourceFolder))
1646
1784
  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];
1785
+ // Optimistic tree update (fire-and-forget; no refetch).
1786
+ applyDocMove(doc, fromNode, toNode, targetFolder);
1661
1787
  this.recomputeContainerTotals(fromContainer, -1);
1662
1788
  if (!sameContainer)
1663
1789
  this.recomputeContainerTotals(toContainer, 1);
@@ -1675,7 +1801,7 @@ const MrdDocumentList = class {
1675
1801
  * loaded; otherwise just nudge the aggregate badge by the delta. */
1676
1802
  recomputeContainerTotals(container, delta) {
1677
1803
  if (container.foldersLoaded) {
1678
- this.computeTotals(container);
1804
+ computeTotals(container);
1679
1805
  }
1680
1806
  else {
1681
1807
  container.totalCount = Math.max(0, container.totalCount + delta);
@@ -1688,111 +1814,64 @@ const MrdDocumentList = class {
1688
1814
  this.mrdNavigate.emit({ href, label });
1689
1815
  }
1690
1816
  // ── 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)))));
1817
+ treeCtx() {
1818
+ return {
1819
+ locale: this.locale,
1820
+ titleField: this.titleField,
1821
+ dateField: this.dateField,
1822
+ selectedId: this.selectedId,
1823
+ dropTargetId: this.dropTargetId,
1824
+ uploadingNodeId: this.uploadingNodeId,
1825
+ on: {
1826
+ toggleContainer: node => this.toggleContainer(node),
1827
+ toggleFolder: (container, node) => this.toggleFolder(container, node),
1828
+ openDoc: doc => this.openDoc(doc),
1829
+ docDragStart: this.onDocDragStart,
1830
+ docDragEnd: this.onDocDragEnd,
1831
+ nodeDragOver: this.onNodeDragOver,
1832
+ nodeDragLeave: this.onNodeDragLeave,
1833
+ nodeDrop: this.onNodeDrop,
1834
+ pendingInput: this.onPendingInput,
1835
+ pendingKeyDown: this.onPendingKeyDown,
1836
+ cancelFolder: () => this.cancelFolder(),
1837
+ setPendingInputEl: el => (this.pendingInputEl = el),
1838
+ },
1839
+ };
1762
1840
  }
1763
1841
  render() {
1842
+ const ctx = this.treeCtx();
1764
1843
  let body;
1765
1844
  if (this.rootLoading) {
1766
- body = this.renderLoadingRow(0);
1845
+ body = renderLoadingRow(ctx, 0);
1767
1846
  }
1768
1847
  else if (this.containers.length === 0) {
1769
- body = index.h("div", { key: '9c38a2e26320a8173ba82cac412c1b32a8a1882e', class: "mrd-document-list__empty" }, t('no_results', this.locale));
1848
+ body = index.h("div", { key: 'ce40dab51ab61447838e5059159ae4778209a6f3', class: "mrd-document-list__empty" }, t('no_results', this.locale));
1770
1849
  }
1771
1850
  else if (this.singleContainer) {
1772
1851
  // Dossier context: render the single container's folder tree at the root.
1773
1852
  const only = this.containers[0];
1774
1853
  if (only.loading && !only.foldersLoaded) {
1775
- body = this.renderLoadingRow(0);
1854
+ body = renderLoadingRow(ctx, 0);
1776
1855
  }
1777
1856
  else {
1778
- const kids = this.renderChildren(only, only, 0);
1857
+ const kids = renderNodeChildren(ctx, only, only, 0);
1779
1858
  body = kids.length
1780
1859
  ? kids
1781
1860
  : index.h("div", { class: "mrd-document-list__empty" }, t('doc_empty_drop', this.locale));
1782
1861
  }
1783
1862
  }
1784
1863
  else {
1785
- body = this.containers.map(c => this.renderContainerNode(c, 0));
1864
+ body = this.containers.map(c => renderContainerNode(ctx, c, 0));
1786
1865
  }
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)));
1866
+ 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
1867
  }
1789
1868
  get el() { return index.getElement(this); }
1790
1869
  };
1791
1870
  /** Root sentinel id for the container-level distinct request. */
1792
1871
  MrdDocumentList.ROOT = '__root__';
1793
- MrdDocumentList.style = mrdDocumentListScss();
1872
+ MrdDocumentList.style = mrdDocumentListCss();
1794
1873
 
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)}`;
1874
+ 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
1875
 
1797
1876
  const MrdDocumentView = class {
1798
1877
  constructor(hostRef) {
@@ -1842,12 +1921,12 @@ const MrdDocumentView = class {
1842
1921
  const date = dateRaw != null && dateRaw !== '' ? formatDate(dateRaw, this.locale) : null;
1843
1922
  const summaryRaw = this.slotValue('summary');
1844
1923
  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 }))))));
1924
+ 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
1925
  }
1847
1926
  };
1848
- MrdDocumentView.style = mrdDocumentViewScss();
1927
+ MrdDocumentView.style = mrdDocumentViewCss();
1849
1928
 
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)}`;
1929
+ 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
1930
 
1852
1931
  const MrdEmailField = class {
1853
1932
  constructor(hostRef) {
@@ -1868,26 +1947,18 @@ const MrdEmailField = class {
1868
1947
  };
1869
1948
  this.handleBlur = (e) => {
1870
1949
  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
- }
1950
+ this.error = requiredError(val, this.required, this.locale)
1951
+ || (val && !validateEmail(val) ? t('invalid_email', this.locale) : '');
1880
1952
  this.mrdBlur.emit({ name: this.name, value: val });
1881
1953
  };
1882
1954
  }
1883
1955
  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))));
1956
+ 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
1957
  }
1887
1958
  };
1888
- MrdEmailField.style = mrdEmailFieldScss();
1959
+ MrdEmailField.style = mrdEmailFieldCss();
1889
1960
 
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)}`;
1961
+ 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
1962
 
1892
1963
  const MrdField = class {
1893
1964
  constructor(hostRef) {
@@ -2072,9 +2143,47 @@ const MrdField = class {
2072
2143
  }]
2073
2144
  }; }
2074
2145
  };
2075
- MrdField.style = mrdFieldScss();
2146
+ MrdField.style = mrdFieldCss();
2076
2147
 
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)}`;
2148
+ /**
2149
+ * Shared upload behaviour for mrd-file-field and mrd-image-field:
2150
+ * file validation, drop-zone class building and drag-drop wiring.
2151
+ */
2152
+ /** Validates a selected/dropped file; returns a localised error message or '' when accepted. */
2153
+ function validateUploadFile(file, maxSize, locale, requireImage = false) {
2154
+ if (maxSize > 0 && file.size > maxSize)
2155
+ return t('file_too_large', locale);
2156
+ if (requireImage && !file.type.startsWith('image/'))
2157
+ return t('invalid_image', locale);
2158
+ return '';
2159
+ }
2160
+ /** BEM class string for the drop zone, e.g. base 'mrd-file-field' → 'mrd-file-field__zone …'. */
2161
+ function uploadZoneClass(base, opts) {
2162
+ return [
2163
+ `${base}__zone`,
2164
+ opts.dragging ? `${base}__zone--dragging` : '',
2165
+ opts.error ? `${base}__zone--error` : '',
2166
+ opts.disabled ? `${base}__zone--disabled` : '',
2167
+ ].filter(Boolean).join(' ');
2168
+ }
2169
+ /** Drag-drop handlers for the drop zone; the component owns the dragging state and file handling. */
2170
+ function makeDragHandlers(setDragging, onFile) {
2171
+ return {
2172
+ onDragOver: (e) => {
2173
+ e.preventDefault();
2174
+ setDragging(true);
2175
+ },
2176
+ onDragLeave: () => setDragging(false),
2177
+ onDrop: (e) => {
2178
+ var _a, _b, _c;
2179
+ e.preventDefault();
2180
+ setDragging(false);
2181
+ 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);
2182
+ },
2183
+ };
2184
+ }
2185
+
2186
+ 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
2187
 
2079
2188
  const MrdFileField = class {
2080
2189
  constructor(hostRef) {
@@ -2099,20 +2208,7 @@ const MrdFileField = class {
2099
2208
  const files = e.target.files;
2100
2209
  this.handleFile((_a = files === null || files === void 0 ? void 0 : files[0]) !== null && _a !== void 0 ? _a : null);
2101
2210
  };
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
- };
2211
+ this.drag = makeDragHandlers(dragging => (this.isDragging = dragging), file => this.handleFile(file));
2116
2212
  this.handleZoneClick = () => {
2117
2213
  var _a;
2118
2214
  if (!this.disabled && !this.uploading) {
@@ -2146,8 +2242,9 @@ const MrdFileField = class {
2146
2242
  this.mrdChange.emit({ name: this.name, value: null });
2147
2243
  return;
2148
2244
  }
2149
- if (this.maxSize > 0 && file.size > this.maxSize) {
2150
- this.error = t('file_too_large', this.locale);
2245
+ const uploadError = validateUploadFile(file, this.maxSize, this.locale);
2246
+ if (uploadError) {
2247
+ this.error = uploadError;
2151
2248
  return;
2152
2249
  }
2153
2250
  this.error = '';
@@ -2159,13 +2256,12 @@ const MrdFileField = class {
2159
2256
  render() {
2160
2257
  const hasFile = this.uploading || (typeof this.value === 'string' && this.value) || this.fileName;
2161
2258
  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))));
2259
+ const zoneClass = uploadZoneClass('mrd-file-field', {
2260
+ dragging: this.isDragging,
2261
+ error: hasError,
2262
+ disabled: this.disabled || this.uploading,
2263
+ });
2264
+ 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
2265
  }
2170
2266
  static get watchers() { return {
2171
2267
  "value": [{
@@ -2173,9 +2269,9 @@ const MrdFileField = class {
2173
2269
  }]
2174
2270
  }; }
2175
2271
  };
2176
- MrdFileField.style = mrdFileFieldScss();
2272
+ MrdFileField.style = mrdFileFieldCss();
2177
2273
 
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)}`;
2274
+ 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
2275
 
2180
2276
  const MrdForm = class {
2181
2277
  constructor(hostRef) {
@@ -2542,9 +2638,9 @@ const MrdForm = class {
2542
2638
  }]
2543
2639
  }; }
2544
2640
  };
2545
- MrdForm.style = mrdFormScss();
2641
+ MrdForm.style = mrdFormCss();
2546
2642
 
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)}`;
2643
+ 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
2644
 
2549
2645
  const MrdHyperlinkField = class {
2550
2646
  constructor(hostRef) {
@@ -2570,15 +2666,8 @@ const MrdHyperlinkField = class {
2570
2666
  this.mrdChange.emit({ name: this.name, value: this.buildValue() });
2571
2667
  };
2572
2668
  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
- }
2669
+ this.error = requiredError(this.internalHref, this.required, this.locale)
2670
+ || (this.internalHref && !validateUrl(this.internalHref) ? t('invalid_url', this.locale) : '');
2582
2671
  this.mrdBlur.emit({ name: this.name, value: this.buildValue() });
2583
2672
  };
2584
2673
  }
@@ -2611,7 +2700,7 @@ const MrdHyperlinkField = class {
2611
2700
  ? index.h("a", { class: "mrd-hyperlink-field__link", href: this.internalHref, target: "_blank", rel: "noopener noreferrer" }, this.internalName || this.internalHref)
2612
2701
  : index.h("span", { class: "mrd-hyperlink-field__empty" }, "\u2014"))));
2613
2702
  }
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))));
2703
+ 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
2704
  }
2616
2705
  static get watchers() { return {
2617
2706
  "value": [{
@@ -2619,9 +2708,9 @@ const MrdHyperlinkField = class {
2619
2708
  }]
2620
2709
  }; }
2621
2710
  };
2622
- MrdHyperlinkField.style = mrdHyperlinkFieldScss();
2711
+ MrdHyperlinkField.style = mrdHyperlinkFieldCss();
2623
2712
 
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)}`;
2713
+ 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
2714
 
2626
2715
  const MrdImageField = class {
2627
2716
  constructor(hostRef) {
@@ -2647,20 +2736,7 @@ const MrdImageField = class {
2647
2736
  const files = e.target.files;
2648
2737
  this.handleFile((_a = files === null || files === void 0 ? void 0 : files[0]) !== null && _a !== void 0 ? _a : null);
2649
2738
  };
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
- };
2739
+ this.drag = makeDragHandlers(dragging => (this.isDragging = dragging), file => this.handleFile(file));
2664
2740
  this.handleZoneClick = () => {
2665
2741
  var _a;
2666
2742
  if (!this.disabled && !this.uploading) {
@@ -2697,12 +2773,9 @@ const MrdImageField = class {
2697
2773
  this.mrdChange.emit({ name: this.name, value: null });
2698
2774
  return;
2699
2775
  }
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';
2776
+ const uploadError = validateUploadFile(file, this.maxSize, this.locale, true);
2777
+ if (uploadError) {
2778
+ this.error = uploadError;
2706
2779
  return;
2707
2780
  }
2708
2781
  this.error = '';
@@ -2720,13 +2793,12 @@ const MrdImageField = class {
2720
2793
  }
2721
2794
  render() {
2722
2795
  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))));
2796
+ const zoneClass = uploadZoneClass('mrd-image-field', {
2797
+ dragging: this.isDragging,
2798
+ error: hasError,
2799
+ disabled: this.disabled || this.uploading,
2800
+ });
2801
+ 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
2802
  }
2731
2803
  static get watchers() { return {
2732
2804
  "value": [{
@@ -2734,7 +2806,36 @@ const MrdImageField = class {
2734
2806
  }]
2735
2807
  }; }
2736
2808
  };
2737
- MrdImageField.style = mrdImageFieldScss();
2809
+ MrdImageField.style = mrdImageFieldCss();
2810
+
2811
+ /** Key an embedded view is addressed by (setViewPage etc.). */
2812
+ function viewKeyFor(item) {
2813
+ var _a, _b, _c, _d;
2814
+ if (item.type === index$1.ClientLayoutItemType.RELATED_VIEW)
2815
+ return (_b = (_a = item.relatedClass) !== null && _a !== void 0 ? _a : item.name) !== null && _b !== void 0 ? _b : '';
2816
+ return (_d = (_c = item.dataClass) !== null && _c !== void 0 ? _c : item.name) !== null && _d !== void 0 ? _d : '';
2817
+ }
2818
+ /** Depth-first flatten of the SECTION/GROUP tree. */
2819
+ function flattenItems(items) {
2820
+ const result = [];
2821
+ for (const item of items) {
2822
+ result.push(item);
2823
+ if (item.items)
2824
+ result.push(...flattenItems(item.items));
2825
+ }
2826
+ return result;
2827
+ }
2828
+ /** Build the canonical parent href `/{base}/{tenant}/{fromClass}/{parentId}` from
2829
+ * the object's self href. Empty unless it is a RELATED_VIEW with a fromClass. */
2830
+ function buildContainerHref(item, selfHref, parentId) {
2831
+ if (item.type !== index$1.ClientLayoutItemType.RELATED_VIEW || !item.fromClass || !parentId)
2832
+ return '';
2833
+ const segs = selfHref.split('/').filter(Boolean);
2834
+ if (segs.length < 2)
2835
+ return '';
2836
+ const [base, tenant] = segs;
2837
+ return `/${base}/${tenant}/${item.fromClass}/${parentId}`;
2838
+ }
2738
2839
 
2739
2840
  class CellRenderer {
2740
2841
  static render(column, row, locale) {
@@ -2840,7 +2941,114 @@ class CellRenderer {
2840
2941
  }
2841
2942
  }
2842
2943
 
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}`;
2944
+ /** FILE and IMAGE cells share the same download button. */
2945
+ function downloadLink(ctx, href, fileName, label) {
2946
+ 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));
2947
+ }
2948
+ function renderSingleFieldValue(ctx, item, value) {
2949
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
2950
+ const dt = item.dataType;
2951
+ switch (dt) {
2952
+ case index$1.ClientLayoutItemFieldDataType.HYPERLINK: {
2953
+ const v = value;
2954
+ const href = (_a = v === null || v === void 0 ? void 0 : v.href) !== null && _a !== void 0 ? _a : String(value);
2955
+ 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;
2956
+ return (index.h("a", { class: "mrd-layout-section__link", href: href, target: "_blank", rel: "noopener noreferrer" }, label));
2957
+ }
2958
+ case index$1.ClientLayoutItemFieldDataType.TEXTBLOCK:
2959
+ return index.h("div", { class: "mrd-layout-section__prose", innerHTML: String(value) });
2960
+ case index$1.ClientLayoutItemFieldDataType.LONGTEXT:
2961
+ return index.h("pre", { class: "mrd-layout-section__pre" }, String(value));
2962
+ case index$1.ClientLayoutItemFieldDataType.JSON:
2963
+ return index.h("pre", { class: "mrd-layout-section__pre", innerHTML: CellRenderer.formatJson(value) });
2964
+ case index$1.ClientLayoutItemFieldDataType.FILE: {
2965
+ const v = value;
2966
+ const fileName = (_e = v === null || v === void 0 ? void 0 : v.fileName) !== null && _e !== void 0 ? _e : String(value);
2967
+ const href = (_f = v === null || v === void 0 ? void 0 : v.href) !== null && _f !== void 0 ? _f : '';
2968
+ return downloadLink(ctx, href, fileName, t('download', ctx.locale));
2969
+ }
2970
+ case index$1.ClientLayoutItemFieldDataType.IMAGE: {
2971
+ const v = value;
2972
+ const href = (_g = v === null || v === void 0 ? void 0 : v.href) !== null && _g !== void 0 ? _g : '';
2973
+ const fileName = (_h = v === null || v === void 0 ? void 0 : v.fileName) !== null && _h !== void 0 ? _h : '';
2974
+ const previewUrl = ctx.imagePreviews[item.name];
2975
+ if (previewUrl) {
2976
+ 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 })));
2977
+ }
2978
+ return downloadLink(ctx, href, fileName, fileName || href);
2979
+ }
2980
+ case index$1.ClientLayoutItemFieldDataType.BOOLEAN:
2981
+ 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)));
2982
+ case index$1.ClientLayoutItemFieldDataType.LIST: {
2983
+ const listItem = ((_j = item.listItems) !== null && _j !== void 0 ? _j : []).find(li => li.key === String(value));
2984
+ const label = (_k = listItem === null || listItem === void 0 ? void 0 : listItem.label) !== null && _k !== void 0 ? _k : String(value);
2985
+ const color = listItem === null || listItem === void 0 ? void 0 : listItem.color;
2986
+ const bg = listItem === null || listItem === void 0 ? void 0 : listItem.backgroundColor;
2987
+ if (color && bg) {
2988
+ return (index.h("span", { class: "mrd-layout-section__badge", style: { color, backgroundColor: bg } }, label));
2989
+ }
2990
+ if (color) {
2991
+ return (index.h("span", { class: "mrd-layout-section__badge-dot-row" }, index.h("span", { class: "mrd-layout-section__badge-dot", style: { backgroundColor: color } }), label));
2992
+ }
2993
+ return label;
2994
+ }
2995
+ case index$1.ClientLayoutItemFieldDataType.SECRET:
2996
+ return value ? index.h("span", { class: "mrd-layout-section__secret-masked" }, '••••••••') : null;
2997
+ default: {
2998
+ const text = CellRenderer.renderValue(dt, value, (_l = item.listItems) !== null && _l !== void 0 ? _l : [], ctx.locale);
2999
+ return text || null;
3000
+ }
3001
+ }
3002
+ }
3003
+ function renderFieldValue(ctx, item, rawValue) {
3004
+ if (rawValue == null || rawValue === '')
3005
+ return null;
3006
+ if (item.multiple && Array.isArray(rawValue)) {
3007
+ const rendered = rawValue.map(v => renderSingleFieldValue(ctx, item, v));
3008
+ if (rendered.every(r => typeof r === 'string' || r == null)) {
3009
+ return rendered.filter(Boolean).join(', ') || null;
3010
+ }
3011
+ return (index.h("span", null, rendered.map((r, i) => (index.h("span", { key: String(i) }, r, i < rendered.length - 1 ? ', ' : '')))));
3012
+ }
3013
+ return renderSingleFieldValue(ctx, item, rawValue);
3014
+ }
3015
+ function renderHistoryBadge(ctx, item, raw) {
3016
+ var _a, _b, _c;
3017
+ const hist = (_a = item.historyEnabled) !== null && _a !== void 0 ? _a : (_b = item.field) === null || _b === void 0 ? void 0 : _b.historyEnabled;
3018
+ if (!hist || !item.name)
3019
+ return null;
3020
+ const history = (_c = raw === null || raw === void 0 ? void 0 : raw.history) !== null && _c !== void 0 ? _c : [];
3021
+ if (!history.length)
3022
+ return null;
3023
+ const sorted = [...history].sort((a, b) => b.until.localeCompare(a.until));
3024
+ const isOpen = ctx.openHistoryField === item.name;
3025
+ 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) => {
3026
+ e.stopPropagation();
3027
+ ctx.on.toggleHistory(isOpen ? null : item.name);
3028
+ } }, 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), ")")))))));
3029
+ }
3030
+ function renderField(ctx, item) {
3031
+ var _a, _b;
3032
+ if (!item.name)
3033
+ return null;
3034
+ const raw = ctx.data[item.name];
3035
+ const hist = (_a = item.historyEnabled) !== null && _a !== void 0 ? _a : (_b = item.field) === null || _b === void 0 ? void 0 : _b.historyEnabled;
3036
+ const rawValue = hist && raw !== null && typeof raw === 'object' && 'current' in raw
3037
+ ? raw.current
3038
+ : raw;
3039
+ const renderedValue = renderFieldValue(ctx, item, rawValue);
3040
+ if (item.header) {
3041
+ return (index.h("h1", { class: "mrd-layout-section__field-header", key: item.name }, typeof renderedValue === 'string' ? renderedValue : rawValue != null ? String(rawValue) : item.label));
3042
+ }
3043
+ if (renderedValue == null)
3044
+ return null;
3045
+ const isBlock = item.dataType === index$1.ClientLayoutItemFieldDataType.TEXTBLOCK
3046
+ || item.dataType === index$1.ClientLayoutItemFieldDataType.LONGTEXT
3047
+ || item.dataType === index$1.ClientLayoutItemFieldDataType.JSON;
3048
+ 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))));
3049
+ }
3050
+
3051
+ 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
3052
 
2845
3053
  const MrdLayoutSection = class {
2846
3054
  constructor(hostRef) {
@@ -2922,14 +3130,8 @@ const MrdLayoutSection = class {
2922
3130
  }
2923
3131
  }
2924
3132
  }
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
3133
  emitLoadImages() {
2932
- for (const item of this.flattenItems(this.items)) {
3134
+ for (const item of flattenItems(this.items)) {
2933
3135
  if (item.type === index$1.ClientLayoutItemType.FIELD && item.dataType === index$1.ClientLayoutItemFieldDataType.IMAGE) {
2934
3136
  const fieldName = item.name;
2935
3137
  const raw = this.data[fieldName];
@@ -2939,15 +3141,6 @@ const MrdLayoutSection = class {
2939
3141
  }
2940
3142
  }
2941
3143
  }
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
3144
  /** Inject search results. Pass dataClass to target a specific SEARCH item; omit when there is only one. */
2952
3145
  async setSearchResults(results, dataClass) {
2953
3146
  const key = dataClass !== null && dataClass !== void 0 ? dataClass : this.resolveSearchKey();
@@ -3013,113 +3206,26 @@ const MrdLayoutSection = class {
3013
3206
  }
3014
3207
  resolveSearchKey() {
3015
3208
  var _a;
3016
- const items = this.flattenItems(this.items).filter(i => i.type === index$1.ClientLayoutItemType.SEARCH);
3209
+ const items = flattenItems(this.items).filter(i => i.type === index$1.ClientLayoutItemType.SEARCH);
3017
3210
  if (items.length === 1)
3018
3211
  return (_a = items[0].dataClass) !== null && _a !== void 0 ? _a : null;
3019
3212
  return null;
3020
3213
  }
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), ")")))))));
3214
+ fieldCtx() {
3215
+ return {
3216
+ locale: this.locale,
3217
+ data: this.data,
3218
+ imagePreviews: this.imagePreviews,
3219
+ openHistoryField: this.openHistoryField,
3220
+ on: {
3221
+ download: detail => this.mrdDownload.emit(detail),
3222
+ openImage: url => { this.imagePreviewUrl = url; },
3223
+ toggleHistory: fieldName => { this.openHistoryField = fieldName; },
3224
+ },
3225
+ };
3103
3226
  }
3104
3227
  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))));
3228
+ return renderField(this.fieldCtx(), item);
3123
3229
  }
3124
3230
  renderRelation(item) {
3125
3231
  var _a, _b, _c;
@@ -3152,7 +3258,7 @@ const MrdLayoutSection = class {
3152
3258
  }
3153
3259
  renderRelatedView(item) {
3154
3260
  var _a, _b, _c, _d, _e, _f, _g, _h;
3155
- const key = this.viewKeyFor(item);
3261
+ const key = viewKeyFor(item);
3156
3262
  if (!key)
3157
3263
  return null;
3158
3264
  if (!item.view)
@@ -3167,22 +3273,11 @@ const MrdLayoutSection = class {
3167
3273
  // Canonical parent href for single-container seeding: use the RELATED_VIEW's
3168
3274
  // fromClass (base class) rather than the route class, so polymorphic subtypes
3169
3275
  // resolve to the same container the documents actually reference.
3170
- const containerHref = this.buildContainerHref(item, selfHref, parentId);
3276
+ const containerHref = buildContainerHref(item, selfHref, parentId);
3171
3277
  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
3278
  ? this.renderDocumentContainer(item, key, parentId, docArchetype, containerHref)
3173
3279
  : this.renderTable(item, key, parentId)));
3174
3280
  }
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
3281
  /** Document collection view: owns the view-switch + collection actions and
3187
3282
  * swaps between the folder tree and the flat table. Events are re-emitted to
3188
3283
  * the host with the view key, exactly as the raw list/table events were. */
@@ -3283,7 +3378,7 @@ const MrdLayoutSection = class {
3283
3378
  }
3284
3379
  render() {
3285
3380
  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
3381
+ return (index.h(index.Host, { key: '5d778188356a25ea13d45745dc5ed573ab2b2ef0' }, index.h("div", { key: '0b673a4bcf8b36cd21662bb8a3506cc3f30edb04', class: "mrd-layout-section" }, docArchetype
3287
3382
  ? this.renderDocumentObject(docArchetype)
3288
3383
  : this.items.map(item => this.renderItem(item))), this.renderImageModal()));
3289
3384
  }
@@ -3294,9 +3389,9 @@ const MrdLayoutSection = class {
3294
3389
  }]
3295
3390
  }; }
3296
3391
  };
3297
- MrdLayoutSection.style = mrdLayoutSectionScss();
3392
+ MrdLayoutSection.style = mrdLayoutSectionCss();
3298
3393
 
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)}`;
3394
+ 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
3395
 
3301
3396
  const MrdListField = class {
3302
3397
  constructor(hostRef) {
@@ -3319,22 +3414,12 @@ const MrdListField = class {
3319
3414
  if (this.multiple) {
3320
3415
  const vals = Array.from(select.selectedOptions).map(o => o.value);
3321
3416
  this.selected = vals;
3322
- if (this.required && !validateRequired(vals)) {
3323
- this.error = t('required', this.locale);
3324
- }
3325
- else {
3326
- this.error = '';
3327
- }
3417
+ this.error = requiredError(vals, this.required, this.locale);
3328
3418
  this.mrdChange.emit({ name: this.name, value: vals });
3329
3419
  }
3330
3420
  else {
3331
3421
  const val = select.value;
3332
- if (this.required && !validateRequired(val)) {
3333
- this.error = t('required', this.locale);
3334
- }
3335
- else {
3336
- this.error = '';
3337
- }
3422
+ this.error = requiredError(val, this.required, this.locale);
3338
3423
  this.mrdChange.emit({ name: this.name, value: val });
3339
3424
  }
3340
3425
  };
@@ -3349,12 +3434,7 @@ const MrdListField = class {
3349
3434
  else {
3350
3435
  this.selected = [...this.selected, key];
3351
3436
  }
3352
- if (this.required && !validateRequired(this.selected)) {
3353
- this.error = t('required', this.locale);
3354
- }
3355
- else {
3356
- this.error = '';
3357
- }
3437
+ this.error = requiredError(this.selected, this.required, this.locale);
3358
3438
  this.mrdChange.emit({ name: this.name, value: this.selected });
3359
3439
  };
3360
3440
  }
@@ -3378,22 +3458,22 @@ const MrdListField = class {
3378
3458
  const hasError = !!this.error;
3379
3459
  const currentValue = Array.isArray(this.value) ? ((_a = this.value[0]) !== null && _a !== void 0 ? _a : '') : ((_b = this.value) !== null && _b !== void 0 ? _b : '');
3380
3460
  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 => {
3461
+ 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
3462
  var _a, _b;
3383
3463
  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))));
3464
+ })), index.h(FieldError, { base: "mrd-list-field", error: this.error }))));
3385
3465
  }
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 => {
3466
+ 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
3467
  var _a, _b;
3388
3468
  const bg = (_b = (_a = lv.backgroundColor) !== null && _a !== void 0 ? _a : lv.color) !== null && _b !== void 0 ? _b : null;
3389
3469
  const style = bg ? { backgroundColor: bg, color: this.getContrastColor(bg) } : {};
3390
3470
  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))));
3471
+ })), index.h(FieldError, { base: "mrd-list-field", error: this.error }))));
3392
3472
  }
3393
3473
  };
3394
- MrdListField.style = mrdListFieldScss();
3474
+ MrdListField.style = mrdListFieldCss();
3395
3475
 
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)}`;
3476
+ 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
3477
 
3398
3478
  const MrdLongtextField = class {
3399
3479
  constructor(hostRef) {
@@ -3414,23 +3494,17 @@ const MrdLongtextField = class {
3414
3494
  };
3415
3495
  this.handleBlur = (e) => {
3416
3496
  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
- }
3497
+ this.error = requiredError(val, this.required, this.locale);
3423
3498
  this.mrdBlur.emit({ name: this.name, value: val });
3424
3499
  };
3425
3500
  }
3426
3501
  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))));
3502
+ 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
3503
  }
3430
3504
  };
3431
- MrdLongtextField.style = mrdLongtextFieldScss();
3505
+ MrdLongtextField.style = mrdLongtextFieldCss();
3432
3506
 
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)}`;
3507
+ 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
3508
 
3435
3509
  const MrdNumberField = class {
3436
3510
  constructor(hostRef) {
@@ -3501,12 +3575,12 @@ const MrdNumberField = class {
3501
3575
  const hasError = !!this.error;
3502
3576
  const suffix = this.dataType === index$1.ClientLayoutItemFieldDataType.PERCENTAGE ? '%' :
3503
3577
  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))));
3578
+ 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
3579
  }
3506
3580
  };
3507
- MrdNumberField.style = mrdNumberFieldScss();
3581
+ MrdNumberField.style = mrdNumberFieldCss();
3508
3582
 
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)}`;
3583
+ 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
3584
 
3511
3585
  const MrdRelationField = class {
3512
3586
  constructor(hostRef) {
@@ -3607,12 +3681,7 @@ const MrdRelationField = class {
3607
3681
  this.showResults = false;
3608
3682
  this.mrdChange.emit({ name: this.name, value: result.id });
3609
3683
  }
3610
- if (this.required && !validateRequired(this.selectedItems)) {
3611
- this.error = t('required', this.locale);
3612
- }
3613
- else {
3614
- this.error = '';
3615
- }
3684
+ this.error = requiredError(this.selectedItems, this.required, this.locale);
3616
3685
  };
3617
3686
  this.handleRemoveSelected = (id) => {
3618
3687
  this.selectedItems = this.selectedItems.filter(i => i.id !== id);
@@ -3621,12 +3690,7 @@ const MrdRelationField = class {
3621
3690
  };
3622
3691
  this.handleDropdownChange = (e) => {
3623
3692
  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
- }
3693
+ this.error = requiredError(val, this.required, this.locale);
3630
3694
  this.mrdChange.emit({ name: this.name, value: val });
3631
3695
  };
3632
3696
  this.handleBlur = () => {
@@ -3737,19 +3801,19 @@ const MrdRelationField = class {
3737
3801
  const hasError = !!this.error;
3738
3802
  if (this.editBehavior === index$1.ClientLayoutItemRelationEditBehavior.DROPDOWN) {
3739
3803
  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))));
3804
+ 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
3805
  }
3742
3806
  if (this.displayType === index$1.ClientLayoutItemRelationDisplayType.DROPDOWN) {
3743
3807
  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))));
3808
+ 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
3809
  }
3746
3810
  // SEARCH mode
3747
- const labelEl = this.label && (index.h("label", { class: `mrd-relation-field__label${this.required ? ' mrd-relation-field__label--required' : ''}` }, this.label));
3811
+ const labelEl = index.h(FieldLabel, { base: "mrd-relation-field", label: this.label, required: this.required });
3748
3812
  // Single selection: show selected value as a badge, hide the search input
3749
3813
  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))));
3814
+ 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
3815
  }
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))));
3816
+ 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
3817
  }
3754
3818
  get el() { return index.getElement(this); }
3755
3819
  static get watchers() { return {
@@ -3761,9 +3825,9 @@ const MrdRelationField = class {
3761
3825
  }]
3762
3826
  }; }
3763
3827
  };
3764
- MrdRelationField.style = mrdRelationFieldScss();
3828
+ MrdRelationField.style = mrdRelationFieldCss();
3765
3829
 
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}`;
3830
+ 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
3831
 
3768
3832
  const MrdSecretField = class {
3769
3833
  constructor(hostRef) {
@@ -3784,42 +3848,460 @@ const MrdSecretField = class {
3784
3848
  };
3785
3849
  this.handleBlur = (e) => {
3786
3850
  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
- }
3851
+ this.error = requiredError(val, this.required, this.locale);
3793
3852
  this.mrdBlur.emit({ name: this.name, value: val });
3794
3853
  };
3795
3854
  }
3796
3855
  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
3856
+ 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
3857
  ? (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))));
3858
+ : (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
3859
  }
3802
3860
  };
3803
- MrdSecretField.style = mrdSecretFieldScss();
3861
+ MrdSecretField.style = mrdSecretFieldCss();
3804
3862
 
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;
3863
+ /**
3864
+ * Pure sort/filter/aggregation query logic for mrd-table.
3865
+ * No component state — everything is passed in.
3866
+ */
3813
3867
  const TEXT_TYPES = new Set(['TEXT', 'TEXTBLOCK', 'EMAIL', 'HYPERLINK']);
3814
3868
  const NUMERIC_TYPES = new Set(['INTEGER', 'DECIMAL', 'PERCENTAGE', 'CURRENCY']);
3815
3869
  const DATE_TYPES = new Set(['DATE', 'DATETIME', 'TIME']);
3816
3870
  const NO_FILTER_TYPES = new Set(['FILE', 'IMAGE']);
3817
3871
  /** Column types that cannot be sorted or filtered (not stored in PostgreSQL). */
3818
3872
  const NON_INTERACTIVE_TYPES = new Set(['LONGTEXT', 'JSON', 'FILE', 'IMAGE']);
3873
+ function parseDefaultSort(defaultSort) {
3874
+ var _a;
3875
+ if (!defaultSort)
3876
+ return { field: '', dir: 'asc' };
3877
+ const parts = defaultSort.split(',');
3878
+ return { field: parts[0].trim(), dir: ((_a = parts[1]) === null || _a === void 0 ? void 0 : _a.trim()) === 'desc' ? 'desc' : 'asc' };
3879
+ }
3880
+ /** Raw sort query-param value, e.g. "name" or "name,desc". */
3881
+ function buildSortParam(field, dir) {
3882
+ if (!field)
3883
+ return '';
3884
+ return dir === 'desc' ? `${field},desc` : field;
3885
+ }
3886
+ /** Query params for a page request: page + sort + filterClass + view filters + active column filters. */
3887
+ function buildTableQueryParams(opts) {
3888
+ var _a, _b;
3889
+ const p = new URLSearchParams();
3890
+ if (opts.page > 0)
3891
+ p.set('page', String(opts.page));
3892
+ if (opts.sort)
3893
+ p.set('sort', opts.sort);
3894
+ if (opts.filterClass)
3895
+ p.set('type', opts.filterClass);
3896
+ applyViewFilters(p, opts.viewFilters);
3897
+ for (const f of opts.activeFilters) {
3898
+ if (f.operator === 'isEmpty') {
3899
+ p.set(f.field, '');
3900
+ continue;
3901
+ }
3902
+ if (f.operator === 'isNotEmpty') {
3903
+ p.set(f.field + '_notempty', 'true');
3904
+ continue;
3905
+ }
3906
+ if (f.operator === 'startsWith') {
3907
+ p.set(f.field + '_startswith', String((_a = f.value) !== null && _a !== void 0 ? _a : ''));
3908
+ continue;
3909
+ }
3910
+ if ((_b = f.values) === null || _b === void 0 ? void 0 : _b.length) {
3911
+ p.set(f.field, f.values.join(','));
3912
+ continue;
3913
+ }
3914
+ if (f.value != null)
3915
+ p.set(f.field, String(f.value));
3916
+ if (f.from != null)
3917
+ p.set(f.field + '_from', String(f.from));
3918
+ if (f.to != null)
3919
+ p.set(f.field + '_to', String(f.to));
3920
+ }
3921
+ return p.toString();
3922
+ }
3923
+ /** Groups aggregate columns by function; null when the view has no aggregates. */
3924
+ function buildAggregationParams(columns) {
3925
+ var _a;
3926
+ const groups = { sum: [], avg: [], count: [] };
3927
+ for (const col of columns) {
3928
+ if (col.type !== 'FIELD' || !col.aggregate)
3929
+ continue;
3930
+ const fn = col.aggregate.toLowerCase();
3931
+ if (fn in groups)
3932
+ groups[fn].push((_a = col.name) !== null && _a !== void 0 ? _a : '');
3933
+ }
3934
+ const params = {};
3935
+ if (groups.sum.length)
3936
+ params.sum = groups.sum;
3937
+ if (groups.avg.length)
3938
+ params.avg = groups.avg;
3939
+ if (groups.count.length)
3940
+ params.count = groups.count;
3941
+ return Object.keys(params).length > 0 ? params : null;
3942
+ }
3943
+ /** Aggregation query string: the page-0 query params without page/sort, plus sum/avg/count. */
3944
+ function buildAggregationQs(basePageQs, columns) {
3945
+ var _a, _b, _c;
3946
+ const p = new URLSearchParams(basePageQs);
3947
+ p.delete('page');
3948
+ p.delete('sort');
3949
+ const groups = buildAggregationParams(columns);
3950
+ if ((_a = groups === null || groups === void 0 ? void 0 : groups.sum) === null || _a === void 0 ? void 0 : _a.length)
3951
+ p.set('sum', groups.sum.join(','));
3952
+ if ((_b = groups === null || groups === void 0 ? void 0 : groups.avg) === null || _b === void 0 ? void 0 : _b.length)
3953
+ p.set('avg', groups.avg.join(','));
3954
+ if ((_c = groups === null || groups === void 0 ? void 0 : groups.count) === null || _c === void 0 ? void 0 : _c.length)
3955
+ p.set('count', groups.count.join(','));
3956
+ return p.toString();
3957
+ }
3958
+ /** True when the pending filter actually constrains anything. */
3959
+ function filterHasValue(f) {
3960
+ if (f.operator === 'isEmpty' || f.operator === 'isNotEmpty')
3961
+ return true;
3962
+ if (f.values !== undefined && f.values.length > 0)
3963
+ return true;
3964
+ if (f.value != null && f.value !== '')
3965
+ return true;
3966
+ if (typeof f.value === 'boolean')
3967
+ return true;
3968
+ if (f.from != null && f.from !== '')
3969
+ return true;
3970
+ if (f.to != null && f.to !== '')
3971
+ return true;
3972
+ return false;
3973
+ }
3974
+ // ── DATETIME filters: the user edits local "YYYY-MM-DD" dates, the API stores UTC ISO ──
3975
+ /** UTC ISO string at the start (midnight) of the given local day. */
3976
+ function dateLocalToUTCStart(dateStr) {
3977
+ if (!dateStr)
3978
+ return dateStr;
3979
+ const [year, month, day] = dateStr.split('-').map(Number);
3980
+ return new Date(year, month - 1, day).toISOString().replace(/\.\d{3}Z$/, 'Z');
3981
+ }
3982
+ /** Start of the day AFTER the given local date (exclusive range end). */
3983
+ function dateLocalToUTCEndExclusive(dateStr) {
3984
+ if (!dateStr)
3985
+ return dateStr;
3986
+ const [year, month, day] = dateStr.split('-').map(Number);
3987
+ return new Date(year, month - 1, day + 1).toISOString().replace(/\.\d{3}Z$/, 'Z');
3988
+ }
3989
+ /** Stored UTC ISO string back to the local "YYYY-MM-DD" date. */
3990
+ function utcISOToLocalDate(utcStr) {
3991
+ if (!utcStr)
3992
+ return utcStr;
3993
+ const d = new Date(utcStr);
3994
+ if (isNaN(d.getTime()))
3995
+ return utcStr;
3996
+ return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
3997
+ }
3998
+ /** The stored "to" is the exclusive end (next midnight); subtract a day to recover the entered date. */
3999
+ function utcISOToLocalDateExclusiveEnd(utcStr) {
4000
+ if (!utcStr)
4001
+ return utcStr;
4002
+ const d = new Date(utcStr);
4003
+ if (isNaN(d.getTime()))
4004
+ return utcStr;
4005
+ d.setDate(d.getDate() - 1);
4006
+ return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
4007
+ }
4008
+ /** Applies the local→UTC conversion when a DATETIME filter is submitted.
4009
+ * Exact date → range covering the full local day. */
4010
+ function normalizeDatetimeFilter(f) {
4011
+ const normalized = Object.assign({}, f);
4012
+ if (f.dataType === 'DATETIME' && f.operator !== 'isEmpty' && f.operator !== 'isNotEmpty') {
4013
+ if (typeof normalized.value === 'string' && normalized.value) {
4014
+ normalized.from = dateLocalToUTCStart(normalized.value);
4015
+ normalized.to = dateLocalToUTCEndExclusive(normalized.value);
4016
+ normalized.value = undefined;
4017
+ }
4018
+ else {
4019
+ if (typeof normalized.from === 'string' && normalized.from)
4020
+ normalized.from = dateLocalToUTCStart(normalized.from);
4021
+ if (typeof normalized.to === 'string' && normalized.to)
4022
+ normalized.to = dateLocalToUTCEndExclusive(normalized.to);
4023
+ }
4024
+ }
4025
+ return normalized;
4026
+ }
4027
+ /** Converts a stored DATETIME filter back to local dates for the popup.
4028
+ * A range covering a single local day is restored to exact-date mode. */
4029
+ function datetimeFilterToDisplay(existing) {
4030
+ const display = Object.assign({}, existing);
4031
+ if (typeof display.from === 'string' && display.from)
4032
+ display.from = utcISOToLocalDate(display.from);
4033
+ if (typeof display.to === 'string' && display.to)
4034
+ display.to = utcISOToLocalDateExclusiveEnd(display.to);
4035
+ if (display.from && display.to && display.from === display.to) {
4036
+ return Object.assign(Object.assign({}, display), { value: display.from, from: undefined, to: undefined });
4037
+ }
4038
+ return display;
4039
+ }
4040
+
4041
+ /**
4042
+ * Stateless render parts of mrd-table. All state and handlers stay in the
4043
+ * component; these components receive plain values and callbacks.
4044
+ */
4045
+ 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" }))));
4046
+ const TEXTBLOCK_MAX = 200;
4047
+ const TableCell = ({ col, row, locale, onDownload, onOpenTextblock, onOpenJson }) => {
4048
+ var _a, _b, _c;
4049
+ const dataType = (_a = col.dataType) !== null && _a !== void 0 ? _a : '';
4050
+ const isNumeric = col.type === 'FIELD' && NUMERIC_TYPES.has(dataType);
4051
+ const isFile = col.type === 'FIELD' && (dataType === 'FILE' || dataType === 'IMAGE');
4052
+ if (isFile) {
4053
+ const name = (_b = col.name) !== null && _b !== void 0 ? _b : '';
4054
+ const fileVal = row === null || row === void 0 ? void 0 : row[name];
4055
+ const href = fileVal === null || fileVal === void 0 ? void 0 : fileVal.href;
4056
+ const fileName = fileVal === null || fileVal === void 0 ? void 0 : fileVal.fileName;
4057
+ return (index.h("td", { class: "mrd-table__cell" }, href && fileName ? (index.h("button", { class: "mrd-table__file-btn", title: fileName, onClick: (e) => {
4058
+ e.stopPropagation();
4059
+ onDownload({ href, fileName });
4060
+ } }, 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))) : ''));
4061
+ }
4062
+ if (dataType === 'JSON') {
4063
+ const name = (_c = col.name) !== null && _c !== void 0 ? _c : '';
4064
+ const rawValue = name ? row === null || row === void 0 ? void 0 : row[name] : undefined;
4065
+ if (rawValue == null || rawValue === '')
4066
+ return index.h("td", { class: "mrd-table__cell" });
4067
+ const compactHtml = CellRenderer.formatJson(rawValue, true);
4068
+ const prettyHtml = CellRenderer.formatJson(rawValue, false);
4069
+ 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")));
4070
+ }
4071
+ if (dataType === 'TEXTBLOCK') {
4072
+ const full = CellRenderer.render(col, row, locale);
4073
+ if (full.length <= TEXTBLOCK_MAX) {
4074
+ return index.h("td", { class: "mrd-table__cell" }, full);
4075
+ }
4076
+ const preview = full.slice(0, TEXTBLOCK_MAX) + '…';
4077
+ 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")));
4078
+ }
4079
+ const value = CellRenderer.render(col, row, locale);
4080
+ return (index.h("td", { class: `mrd-table__cell${isNumeric ? ' mrd-table__cell--numeric' : ''}` }, value));
4081
+ };
4082
+ /** Formats the aggregation total for one column, '' when not applicable. */
4083
+ function formatAggregationValue(col, aggregations, locale) {
4084
+ var _a;
4085
+ if (col.type !== 'FIELD' || !col.aggregate || !aggregations)
4086
+ return '';
4087
+ const fn = col.aggregate.toLowerCase();
4088
+ const aggData = aggregations[fn];
4089
+ const val = typeof aggData === 'object' && aggData !== null
4090
+ ? aggData[(_a = col.name) !== null && _a !== void 0 ? _a : '']
4091
+ : undefined;
4092
+ if (val == null)
4093
+ return '';
4094
+ const dt = col.dataType;
4095
+ if (dt === 'INTEGER')
4096
+ return formatNumber(val, locale, { maximumFractionDigits: 0 });
4097
+ if (dt === 'PERCENTAGE')
4098
+ return formatPercentage(val, locale);
4099
+ if (dt === 'CURRENCY' && col.currencyCode)
4100
+ return formatCurrency(val, col.currencyCode, locale);
4101
+ return formatNumber(val, locale);
4102
+ }
4103
+ const TotalsRow = ({ columns, aggregations, locale }) => {
4104
+ if (!aggregations)
4105
+ return null;
4106
+ if (!columns.some(c => c.type === 'FIELD' && c.aggregate))
4107
+ return null;
4108
+ return (index.h("tfoot", null, index.h("tr", { class: "mrd-table__totals-row" }, columns.map(col => {
4109
+ var _a;
4110
+ const val = formatAggregationValue(col, aggregations, locale);
4111
+ const isNumeric = col.type === 'FIELD' && NUMERIC_TYPES.has((_a = col.dataType) !== null && _a !== void 0 ? _a : '');
4112
+ return (index.h("td", { class: `mrd-table__totals-cell${isNumeric ? ' mrd-table__totals-cell--numeric' : ''}` }, val));
4113
+ }))));
4114
+ };
4115
+ const TextblockModal = ({ text, locale, onClose }) => {
4116
+ if (text === null)
4117
+ return null;
4118
+ 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))));
4119
+ };
4120
+ const JsonModal = ({ html, locale, onClose }) => {
4121
+ if (html === null)
4122
+ return null;
4123
+ 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 }))));
4124
+ };
4125
+ const Toolbar = ({ locale, filterMode, filterCount, actions, views, activeViewIdx, viewPopoverOpen, createPickerOpen, createTypes, cb }) => {
4126
+ var _a;
4127
+ const hasActions = actions.length > 0;
4128
+ const hasViewSwitcher = views.length > 1;
4129
+ 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: () => {
4130
+ if (i !== activeViewIdx)
4131
+ cb.onViewSwitch(i);
4132
+ cb.onCloseViewPopover();
4133
+ } }, 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 => {
4134
+ var _a, _b;
4135
+ const pickerTypes = a.action === 'create' ? createTypes : null;
4136
+ if (pickerTypes === null || pickerTypes === void 0 ? void 0 : pickerTypes.length) {
4137
+ 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
4138
+ ? index.h("svg", { class: "mrd-table__action-icon", "aria-hidden": "true" }, index.h("use", { href: a.icon }))
4139
+ : 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)))))));
4140
+ }
4141
+ 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
4142
+ ? index.h("svg", { class: "mrd-table__action-icon", "aria-hidden": "true" }, index.h("use", { href: a.icon }))
4143
+ : a.label, index.h("span", { class: "mrd-table__action-tooltip" }, a.label)));
4144
+ })))));
4145
+ };
4146
+
4147
+ const FilterEditor = ({ col, dataType, openFilterCol, pendingFilter, locale, cb }) => {
4148
+ var _a, _b, _c, _d, _e, _f;
4149
+ const pf = pendingFilter;
4150
+ if (NO_FILTER_TYPES.has(dataType)) {
4151
+ return index.h("p", { class: "mrd-table__filter-no-support" }, t('filter_no_support', locale));
4152
+ }
4153
+ if (dataType === 'BOOLEAN') {
4154
+ const boolOp = pf.operator;
4155
+ const noValueOp = boolOp === 'isEmpty' || boolOp === 'isNotEmpty';
4156
+ return (index.h("div", { class: "mrd-table__filter-radio-group" }, [
4157
+ { labelKey: 'filter_all', value: null },
4158
+ { labelKey: 'yes', value: true },
4159
+ { labelKey: 'no', value: false },
4160
+ ].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))));
4161
+ }
4162
+ if (dataType === 'LIST') {
4163
+ const items = (_a = col.listItems) !== null && _a !== void 0 ? _a : [];
4164
+ const selected = (_b = pf.values) !== null && _b !== void 0 ? _b : [];
4165
+ 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)))));
4166
+ }
4167
+ if (TEXT_TYPES.has(dataType) || dataType === 'RELATION') {
4168
+ const op = (_c = pf.operator) !== null && _c !== void 0 ? _c : 'startsWith';
4169
+ const noInput = op === 'isEmpty' || op === 'isNotEmpty';
4170
+ 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) }, [
4171
+ { val: 'startsWith', labelKey: 'filter_starts_with' },
4172
+ { val: 'equals', labelKey: 'filter_equals' },
4173
+ { val: 'isEmpty', labelKey: 'filter_is_empty' },
4174
+ { val: 'isNotEmpty', labelKey: 'filter_is_not_empty' },
4175
+ ].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) }))));
4176
+ }
4177
+ if (NUMERIC_TYPES.has(dataType)) {
4178
+ const numOp = pf.operator;
4179
+ const noInput = numOp === 'isEmpty' || numOp === 'isNotEmpty';
4180
+ const rangeMode = !noInput && (pf.from !== undefined || pf.to !== undefined);
4181
+ return (index.h("div", { class: "mrd-table__filter-editor" }, index.h("select", { class: "mrd-table__filter-select", onChange: (e) => {
4182
+ const val = e.target.value;
4183
+ if (val === 'isEmpty' || val === 'isNotEmpty') {
4184
+ cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: val, value: undefined, from: undefined, to: undefined }));
4185
+ }
4186
+ else {
4187
+ cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: undefined }));
4188
+ }
4189
+ } }, 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) })))))));
4190
+ }
4191
+ if (dataType === 'DATETIME') {
4192
+ const dtOp = pf.operator;
4193
+ const noInput = dtOp === 'isEmpty' || dtOp === 'isNotEmpty';
4194
+ const rangeMode = !noInput && (pf.from !== undefined || pf.to !== undefined);
4195
+ return (index.h("div", { class: "mrd-table__filter-editor" }, index.h("select", { class: "mrd-table__filter-select", onChange: (e) => {
4196
+ const val = e.target.value;
4197
+ if (val === 'isEmpty' || val === 'isNotEmpty') {
4198
+ cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: val, value: undefined, from: undefined, to: undefined }));
4199
+ }
4200
+ else {
4201
+ cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: undefined }));
4202
+ }
4203
+ } }, 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) })))))));
4204
+ }
4205
+ if (DATE_TYPES.has(dataType)) {
4206
+ const inputType = dataType === 'DATE' ? 'date' : 'time';
4207
+ const dtdOp = pf.operator;
4208
+ const noInput = dtdOp === 'isEmpty' || dtdOp === 'isNotEmpty';
4209
+ const rangeMode = !noInput && (pf.from !== undefined || pf.to !== undefined);
4210
+ return (index.h("div", { class: "mrd-table__filter-editor" }, index.h("select", { class: "mrd-table__filter-select", onChange: (e) => {
4211
+ const val = e.target.value;
4212
+ if (val === 'isEmpty' || val === 'isNotEmpty') {
4213
+ cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: val, value: undefined, from: undefined, to: undefined }));
4214
+ }
4215
+ else {
4216
+ cb.onReplacePending(Object.assign(Object.assign({}, pf), { operator: undefined }));
4217
+ }
4218
+ } }, 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) })))))));
4219
+ }
4220
+ return null;
4221
+ };
4222
+ const FilterPopup = (props) => {
4223
+ var _a;
4224
+ const { col, openFilterCol, popupPos, sortField, sortDir, locale, cb } = props;
4225
+ const label = (_a = col.label) !== null && _a !== void 0 ? _a : openFilterCol;
4226
+ const sortActive = sortField === openFilterCol;
4227
+ 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)))));
4228
+ };
4229
+
4230
+ /**
4231
+ * Pure window/paging maths for the mrd-table virtual scroll.
4232
+ * The window state itself stays @State in the component; these
4233
+ * functions only compute values from it.
4234
+ */
4235
+ const BUFFER = 10;
4236
+ /** Wait this long (ms) after the last scroll event before requesting pages,
4237
+ * so pages the user quickly scrolls past are skipped. */
4238
+ const REQUEST_DEBOUNCE_MS = 150;
4239
+ /** Default time (ms) to wait for setPage() before treating a request as stale and retrying. */
4240
+ const REQUEST_TIMEOUT_MS = 15000;
4241
+ /** Max retries for a stale page request before giving up and showing a retry row. */
4242
+ const MAX_RETRY_ATTEMPTS = 3;
4243
+ function visibleCount(tableHeight, rowHeight) {
4244
+ return Math.ceil(tableHeight / rowHeight);
4245
+ }
4246
+ /** Render window (with buffer) for the given scroll offset. */
4247
+ function computeWindow(scrollTop, rowHeight, tableHeight, total) {
4248
+ const visStart = Math.floor(scrollTop / rowHeight);
4249
+ const visEnd = Math.min(visStart + visibleCount(tableHeight, rowHeight), total - 1);
4250
+ return {
4251
+ renderStart: Math.max(0, visStart - BUFFER),
4252
+ renderEnd: Math.min(total - 1, visEnd + BUFFER),
4253
+ };
4254
+ }
4255
+ /** First/last page (0-based) covering the given row window. */
4256
+ function pageRange(start, end, pageSize) {
4257
+ return { firstPage: Math.floor(start / pageSize), lastPage: Math.floor(end / pageSize) };
4258
+ }
4259
+ function getRowFromPages(pages, index, pageSize) {
4260
+ var _a;
4261
+ const page = pages.get(Math.floor(index / pageSize));
4262
+ return (_a = page === null || page === void 0 ? void 0 : page[index % pageSize]) !== null && _a !== void 0 ? _a : null;
4263
+ }
4264
+ /** Authoritative row count: a page shorter than pageSize is the last page,
4265
+ * so the true total cannot exceed its end index. */
4266
+ function computeEffectiveTotal(loadedPages, pageSize, baseTotal) {
4267
+ let effectiveTotal = baseTotal;
4268
+ for (const [pageNum, pageRows] of loadedPages) {
4269
+ if (pageRows.length < pageSize) {
4270
+ effectiveTotal = Math.min(effectiveTotal, pageNum * pageSize + pageRows.length);
4271
+ }
4272
+ }
4273
+ return effectiveTotal;
4274
+ }
4275
+ /** True when some loaded page was short — the exact total is then known. */
4276
+ function isTotalKnownFromPages(loadedPages, pageSize) {
4277
+ for (const rows of loadedPages.values()) {
4278
+ if (rows.length < pageSize)
4279
+ return true;
4280
+ }
4281
+ return false;
4282
+ }
4283
+ /** Pages whose request timestamp is older than timeoutMs — candidates for retry or failure.
4284
+ * Caller is expected to already exclude pages present in loadedPages. */
4285
+ function getStalePages(requestedAt, now, timeoutMs) {
4286
+ const stale = [];
4287
+ for (const [page, ts] of requestedAt) {
4288
+ if (now - ts >= timeoutMs)
4289
+ stale.push(page);
4290
+ }
4291
+ return stale;
4292
+ }
4293
+
4294
+ const mrdTableCss = () => `@charset "UTF-8";.sc-mrd-table-h{display:block;width:100%}.mrd-table__scroll.sc-mrd-table{overflow-y:auto;overflow-x:auto;border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);overflow-anchor:none}.mrd-table.sc-mrd-table{overflow-x:auto}.mrd-table__table.sc-mrd-table{width:auto;min-width:100%;border-collapse:collapse;font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-900)}.mrd-table__scroll.sc-mrd-table .mrd-table__table.sc-mrd-table{min-width:max-content}.mrd-table__header.sc-mrd-table{position:sticky;top:0;z-index:1;background:var(--mrd-color-white);text-align:left;padding:var(--mrd-space-2) var(--mrd-space-4);border-bottom:2px solid var(--mrd-border-color);color:var(--mrd-color-neutral-600);font-weight:var(--mrd-font-weight-medium);white-space:nowrap;font-size:var(--mrd-font-size-xs);text-transform:uppercase;letter-spacing:0.04em}.mrd-table__header--sortable.sc-mrd-table{cursor:pointer;user-select:none}.mrd-table__header--sortable.sc-mrd-table:hover{background:var(--mrd-color-neutral-50);color:var(--mrd-color-neutral-800)}.mrd-table__header--sorted-asc.sc-mrd-table,.mrd-table__header--sorted-desc.sc-mrd-table{color:var(--mrd-color-primary);border-bottom-color:var(--mrd-color-primary)}.mrd-table__header-label.sc-mrd-table{margin-right:var(--mrd-space-1)}.mrd-table__sort-icon.sc-mrd-table{font-size:0.85rem;opacity:0.4;vertical-align:middle}.mrd-table__header--sorted-asc.sc-mrd-table .mrd-table__sort-icon.sc-mrd-table,.mrd-table__header--sorted-desc.sc-mrd-table .mrd-table__sort-icon.sc-mrd-table{opacity:1;color:var(--mrd-color-primary)}.mrd-table__filter-icon.sc-mrd-table{display:inline-flex;align-items:center;vertical-align:middle;margin-left:var(--mrd-space-1);color:var(--mrd-color-primary)}.mrd-table__row.sc-mrd-table{border-bottom:1px solid var(--mrd-border-color)}.mrd-table__row.sc-mrd-table:hover{background:var(--mrd-color-neutral-200) !important}.mrd-table__row--clickable.sc-mrd-table{cursor:pointer}.mrd-table__spacer.sc-mrd-table{border:none}.mrd-table__spacer.sc-mrd-table td.sc-mrd-table{padding:0;border:none}.mrd-table__cell.sc-mrd-table{padding:var(--mrd-space-2) var(--mrd-space-4);vertical-align:top;white-space:nowrap}.mrd-table__cell--numeric.sc-mrd-table{text-align:right;font-variant-numeric:tabular-nums}.mrd-table__row--loading.sc-mrd-table{background:transparent}.mrd-table__cell--placeholder.sc-mrd-table{padding:var(--mrd-space-2) var(--mrd-space-4);border-bottom:1px solid var(--mrd-border-color)}.mrd-table__placeholder-bar.sc-mrd-table{display:block;height:0.75rem;width:55%;border-radius:var(--mrd-border-radius-sm);background:linear-gradient(90deg, var(--mrd-color-neutral-200) 25%, var(--mrd-color-neutral-100) 50%, var(--mrd-color-neutral-200) 75%);background-size:200% 100%;animation:mrd-shimmer 1.4s ease infinite}@keyframes mrd-shimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}.mrd-table__row--failed.sc-mrd-table{background:transparent}.mrd-table__cell--failed.sc-mrd-table{padding:var(--mrd-space-2) var(--mrd-space-4);border-bottom:1px solid var(--mrd-border-color)}.mrd-table__retry-button.sc-mrd-table{border:none;background:none;padding:0;color:var(--mrd-color-danger);font-size:inherit;cursor:pointer;text-decoration:underline}.mrd-table__toolbar.sc-mrd-table{display:flex;align-items:center;justify-content:space-between;padding-bottom:var(--mrd-space-2)}.mrd-table__toolbar-left.sc-mrd-table,.mrd-table__toolbar-right.sc-mrd-table{display:flex;gap:var(--mrd-space-2);align-items:center}.mrd-table__toolbar-center.sc-mrd-table{flex:1;display:flex;justify-content:center;align-items:center;gap:var(--mrd-space-1)}.mrd-table__view-switcher.sc-mrd-table{display:flex;align-items:center;gap:var(--mrd-space-1)}.mrd-table__view-arrow.sc-mrd-table{background:none;border:none;cursor:pointer;padding:0 var(--mrd-space-1);color:var(--mrd-color-neutral-500);font-size:var(--mrd-font-size-xs);line-height:1}.mrd-table__view-arrow.sc-mrd-table:hover{color:var(--mrd-color-neutral-800)}.mrd-table__view-title-wrap.sc-mrd-table{position:relative}.mrd-table__view-title.sc-mrd-table{font-size:var(--mrd-font-size-sm);font-weight:600;color:var(--mrd-color-neutral-800);font-family:var(--mrd-font-family);background:none;border:none;outline:none;cursor:pointer;padding:0 var(--mrd-space-1);max-width:220px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mrd-table__view-title.sc-mrd-table:hover{color:var(--mrd-color-primary)}.mrd-table__view-popover.sc-mrd-table{position:absolute;top:calc(100% + var(--mrd-space-1));left:50%;transform:translateX(-50%);background:var(--mrd-color-white);border:1px solid var(--mrd-color-neutral-200);border-radius:var(--mrd-radius-md);box-shadow:var(--mrd-shadow-md);z-index:100;min-width:160px;padding:var(--mrd-space-1) 0}.mrd-table__view-popover-item.sc-mrd-table{display:block;width:100%;text-align:left;background:none;border:none;cursor:pointer;padding:var(--mrd-space-2) var(--mrd-space-3);font-size:var(--mrd-font-size-sm);font-family:var(--mrd-font-family);color:var(--mrd-color-neutral-700);white-space:nowrap}.mrd-table__view-popover-item.sc-mrd-table:hover{background:var(--mrd-color-neutral-50)}.mrd-table__view-popover-item--active.sc-mrd-table{font-weight:600;color:var(--mrd-color-primary)}.mrd-table__action.sc-mrd-table{position:relative;display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;padding:0;background:transparent;border:1px solid transparent;border-radius:var(--mrd-border-radius);cursor:pointer;color:var(--mrd-color-neutral-400);transition:background-color 0.15s, border-color 0.15s, color 0.15s}.mrd-table__action.sc-mrd-table:hover{background-color:var(--mrd-color-neutral-100);border-color:var(--mrd-color-neutral-300);color:var(--mrd-color-neutral-700)}.mrd-table__action.sc-mrd-table:disabled{opacity:0.4;cursor:not-allowed}.mrd-table__action--primary.sc-mrd-table{color:var(--mrd-color-neutral-500)}.mrd-table__action--primary.sc-mrd-table:hover{background:var(--mrd-color-primary);border-color:var(--mrd-color-primary);color:var(--mrd-color-white)}.mrd-table__action--danger.sc-mrd-table{color:var(--mrd-color-error)}.mrd-table__action--danger.sc-mrd-table:hover{background-color:var(--mrd-color-error-light, #fef2f2);border-color:var(--mrd-color-error)}.mrd-table__action-icon.sc-mrd-table{width:1.25rem;height:1.25rem;pointer-events:none;fill:currentColor}.mrd-table__action-tooltip.sc-mrd-table{display:none;position:absolute;bottom:calc(100% + 6px);right:0;padding:var(--mrd-space-1) var(--mrd-space-2);font-size:var(--mrd-font-size-xs);white-space:nowrap;background:var(--mrd-color-tooltip, #fffce1);color:var(--mrd-color-neutral-900);border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius-sm, var(--mrd-border-radius));pointer-events:none;z-index:10}.mrd-table__action.sc-mrd-table:hover .mrd-table__action-tooltip.sc-mrd-table{display:block}.mrd-table__create-picker-wrap.sc-mrd-table{position:relative}.mrd-table__create-picker.sc-mrd-table{position:absolute;right:0;top:calc(100% + 4px);background:var(--mrd-color-white, #fff);border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);box-shadow:var(--mrd-shadow-md, 0 4px 12px rgba(0, 0, 0, 0.12));z-index:10;min-width:10rem;padding:var(--mrd-space-1) 0}.mrd-table__create-picker-item.sc-mrd-table{display:block;width:100%;text-align:left;padding:var(--mrd-space-2) var(--mrd-space-3);background:none;border:none;cursor:pointer;font-size:var(--mrd-font-size-sm);font-family:var(--mrd-font-family);color:var(--mrd-color-neutral-800)}.mrd-table__create-picker-item.sc-mrd-table:hover{background:var(--mrd-color-neutral-50);color:var(--mrd-color-neutral-900)}.mrd-table__filter-toggle--active.sc-mrd-table{background:var(--mrd-color-primary);border-color:var(--mrd-color-primary);color:var(--mrd-color-white)}.mrd-table__filter-toggle--active.sc-mrd-table:hover{background:var(--mrd-color-primary-dark, var(--mrd-color-primary));border-color:var(--mrd-color-primary-dark, var(--mrd-color-primary));color:var(--mrd-color-white)}.mrd-table__filter-badge.sc-mrd-table{position:absolute;top:-6px;right:-6px;min-width:1.25rem;height:1.25rem;padding:0 3px;background:var(--mrd-color-error, #e53e3e);color:var(--mrd-color-white);border-radius:9999px;font-size:0.65rem;font-weight:var(--mrd-font-weight-medium);line-height:1.25rem;text-align:center;pointer-events:none}.mrd-table__header--filtered.sc-mrd-table{color:var(--mrd-color-primary);border-bottom-color:var(--mrd-color-primary)}.mrd-table__filter-popup.sc-mrd-table{position:fixed;width:280px;background:var(--mrd-color-white);border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);box-shadow:var(--mrd-shadow-md, 0 4px 12px rgba(0, 0, 0, 0.12));z-index:var(--mrd-z-dropdown, 200);font-size:var(--mrd-font-size-sm)}.mrd-table__filter-popup-header.sc-mrd-table{display:flex;align-items:center;justify-content:space-between;padding:var(--mrd-space-2) var(--mrd-space-3);border-bottom:1px solid var(--mrd-border-color)}.mrd-table__filter-popup-title.sc-mrd-table{font-weight:var(--mrd-font-weight-medium);color:var(--mrd-color-neutral-800);font-size:var(--mrd-font-size-sm)}.mrd-table__filter-close.sc-mrd-table{background:transparent;border:none;cursor:pointer;color:var(--mrd-color-neutral-500);font-size:0.9rem;padding:2px 4px;border-radius:3px;line-height:1}.mrd-table__filter-close.sc-mrd-table:hover{background:var(--mrd-color-neutral-100);color:var(--mrd-color-neutral-800)}.mrd-table__filter-section.sc-mrd-table{padding:var(--mrd-space-2) var(--mrd-space-3)}.mrd-table__filter-section-label.sc-mrd-table{font-size:var(--mrd-font-size-xs);font-weight:var(--mrd-font-weight-medium);text-transform:uppercase;letter-spacing:0.04em;color:var(--mrd-color-neutral-500);margin-bottom:var(--mrd-space-2)}.mrd-table__filter-sort-buttons.sc-mrd-table{display:flex;gap:var(--mrd-space-2)}.mrd-table__filter-sort-btn.sc-mrd-table{flex:1;padding:var(--mrd-space-1) var(--mrd-space-2);background:transparent;border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);cursor:pointer;font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-700)}.mrd-table__filter-sort-btn.sc-mrd-table:hover{background:var(--mrd-color-neutral-100)}.mrd-table__filter-sort-btn--active.sc-mrd-table{background:var(--mrd-color-primary);border-color:var(--mrd-color-primary);color:var(--mrd-color-white)}.mrd-table__filter-divider.sc-mrd-table{height:1px;background:var(--mrd-border-color);margin:0}.mrd-table__filter-editor.sc-mrd-table{display:flex;flex-direction:column;gap:var(--mrd-space-2)}.mrd-table__filter-select.sc-mrd-table,.mrd-table__filter-input.sc-mrd-table{width:100%;padding:var(--mrd-space-1) var(--mrd-space-2);border:1px solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-900);background:var(--mrd-color-white);box-sizing:border-box}.mrd-table__filter-select.sc-mrd-table:focus,.mrd-table__filter-input.sc-mrd-table:focus{outline:none;border-color:var(--mrd-color-primary);box-shadow:0 0 0 2px rgba(0, 0, 0, 0.06)}.mrd-table__filter-range.sc-mrd-table{display:flex;align-items:center;gap:var(--mrd-space-1)}.mrd-table__filter-range.sc-mrd-table .mrd-table__filter-input.sc-mrd-table{flex:1;min-width:0}.mrd-table__filter-range-sep.sc-mrd-table{color:var(--mrd-color-neutral-400);flex-shrink:0}.mrd-table__filter-range--stacked.sc-mrd-table{flex-direction:column;align-items:stretch;gap:var(--mrd-space-2)}.mrd-table__filter-range-label.sc-mrd-table{font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-500);margin-bottom:2px}.mrd-table__filter-radio-group.sc-mrd-table{display:flex;flex-direction:column;gap:var(--mrd-space-1)}.mrd-table__filter-radio-group--inline.sc-mrd-table{flex-direction:row;gap:var(--mrd-space-3)}.mrd-table__filter-radio-label.sc-mrd-table{display:flex;align-items:center;gap:var(--mrd-space-1);cursor:pointer;font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-800)}.mrd-table__filter-list.sc-mrd-table{display:flex;flex-direction:column;gap:var(--mrd-space-1);max-height:180px;overflow-y:auto}.mrd-table__filter-list-controls.sc-mrd-table{display:flex;gap:var(--mrd-space-2);margin-bottom:var(--mrd-space-1)}.mrd-table__filter-list-btn.sc-mrd-table{font-size:var(--mrd-font-size-xs);color:var(--mrd-color-primary);background:transparent;border:none;cursor:pointer;padding:0;text-decoration:underline}.mrd-table__filter-checkbox-label.sc-mrd-table{display:flex;align-items:center;gap:var(--mrd-space-1);cursor:pointer;font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-800)}.mrd-table__filter-no-support.sc-mrd-table{font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-500);margin:0;font-style:italic}.mrd-table__filter-popup-footer.sc-mrd-table{display:flex;justify-content:flex-end;gap:var(--mrd-space-2);padding:var(--mrd-space-2) var(--mrd-space-3);border-top:1px solid var(--mrd-border-color)}.mrd-table__filter-btn.sc-mrd-table{padding:var(--mrd-space-1) var(--mrd-space-3);border-radius:var(--mrd-border-radius);border:1px solid var(--mrd-border-color);font-size:var(--mrd-font-size-sm);cursor:pointer}.mrd-table__filter-btn--clear.sc-mrd-table{background:transparent;color:var(--mrd-color-neutral-600)}.mrd-table__filter-btn--clear.sc-mrd-table:hover{background:var(--mrd-color-neutral-100)}.mrd-table__filter-btn--apply.sc-mrd-table{background:var(--mrd-color-primary);border-color:var(--mrd-color-primary);color:var(--mrd-color-white)}.mrd-table__filter-btn--apply.sc-mrd-table:hover{background:var(--mrd-color-primary-dark, var(--mrd-color-primary));border-color:var(--mrd-color-primary-dark, var(--mrd-color-primary))}.mrd-table__totals-row.sc-mrd-table{border-top:2px solid var(--mrd-border-color)}.mrd-table__totals-cell.sc-mrd-table{position:sticky;bottom:0;z-index:2;padding:var(--mrd-space-2) var(--mrd-space-4);background:var(--mrd-color-white);font-weight:var(--mrd-font-weight-medium);font-variant-numeric:tabular-nums;white-space:nowrap;border-top:2px solid var(--mrd-border-color)}.mrd-table__totals-cell--numeric.sc-mrd-table{text-align:right}.mrd-table__footer.sc-mrd-table{padding:var(--mrd-space-1) var(--mrd-space-2);font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-500);text-align:right}.mrd-table__empty.sc-mrd-table{padding:var(--mrd-space-4) var(--mrd-space-3);color:var(--mrd-color-neutral-500);font-size:var(--mrd-font-size-sm);text-align:center;margin:0}.mrd-table__file-btn.sc-mrd-table{display:inline-flex;align-items:center;gap:var(--mrd-space-1);background:none;border:none;padding:0;cursor:pointer;color:var(--mrd-color-primary);font-size:var(--mrd-font-size-sm);font-family:inherit;max-width:100%;overflow:hidden}.mrd-table__file-btn.sc-mrd-table:hover{text-decoration:underline;color:var(--mrd-color-primary-dark)}.mrd-table__file-icon.sc-mrd-table{flex-shrink:0;width:1rem;height:1rem}.mrd-table__textblock-btn.sc-mrd-table{display:inline;background:none;border:none;padding:0 0 0 var(--mrd-space-1);cursor:pointer;color:var(--mrd-color-primary);font-size:var(--mrd-font-size-sm);font-family:inherit;line-height:inherit;vertical-align:middle}.mrd-table__textblock-btn.sc-mrd-table:hover{color:var(--mrd-color-primary-dark)}.mrd-table__modal-backdrop.sc-mrd-table{position:fixed;inset:0;background:rgba(0, 0, 0, 0.4);z-index:var(--mrd-z-modal, 300);display:flex;align-items:center;justify-content:center}.mrd-table__modal.sc-mrd-table{background:#fff;border-radius:var(--mrd-radius-md, 0.5rem);padding:var(--mrd-space-6);max-width:min(600px, 90vw);max-height:70vh;overflow-y:auto;position:relative;box-shadow:var(--mrd-shadow-lg)}.mrd-table__modal-close.sc-mrd-table{position:absolute;top:var(--mrd-space-3);right:var(--mrd-space-3);background:none;border:none;cursor:pointer;font-size:1.25rem;line-height:1;color:var(--mrd-color-text-muted, #6b7280);padding:0}.mrd-table__modal-close.sc-mrd-table:hover{color:var(--mrd-color-text, #111827)}.mrd-table__modal-text.sc-mrd-table{margin:0;padding-right:var(--mrd-space-6);white-space:pre-wrap;word-break:break-word;font-size:var(--mrd-font-size-sm);line-height:1.6}.mrd-table__json-preview.sc-mrd-table{font-family:var(--mrd-font-family-mono);font-size:var(--mrd-font-size-xs);overflow:hidden;white-space:nowrap;text-overflow:ellipsis;display:inline-block;max-width:calc(100% - 1.5rem);vertical-align:middle}.mrd-table__modal-json.sc-mrd-table{margin:0;padding-right:var(--mrd-space-6);font-family:var(--mrd-font-family-mono);font-size:var(--mrd-font-size-xs);white-space:pre-wrap;word-break:break-word;line-height:1.6;background:none;border:none}`;
4295
+
4296
+ /** How often (ms) to scan outstanding page requests for staleness. */
4297
+ const STALE_CHECK_INTERVAL_MS = 2000;
4298
+ /** Breedte van de filterpopup in px — voor overflow-correctie. */
4299
+ const POPUP_WIDTH = 280;
3819
4300
  const MrdTable = class {
3820
4301
  constructor(hostRef) {
3821
4302
  index.registerInstance(this, hostRef);
3822
4303
  this.mrdLoadPage = index.createEvent(this, "mrdLoadPage");
4304
+ this.mrdPageError = index.createEvent(this, "mrdPageError");
3823
4305
  this.mrdRowClick = index.createEvent(this, "mrdRowClick");
3824
4306
  this.mrdAction = index.createEvent(this, "mrdAction");
3825
4307
  this.mrdDownload = index.createEvent(this, "mrdDownload");
@@ -3827,10 +4309,17 @@ const MrdTable = class {
3827
4309
  // ── Non-state internals ────────────────────────────────────────────────────
3828
4310
  this.pendingPages = new Set();
3829
4311
  this.debounceTimer = null;
4312
+ /** Timestamp of the last mrdLoadPage emission per outstanding page — drives stale-request detection. */
4313
+ this.requestedAt = new Map();
4314
+ /** Retry count per page since it first became stale. */
4315
+ this.retryAttempts = new Map();
4316
+ this.staleCheckTimer = null;
3830
4317
  this.outsideClickHandler = null;
3831
4318
  this.keydownHandler = null;
3832
4319
  this.createPickerClickHandler = null;
3833
4320
  this.viewPopoverClickHandler = null;
4321
+ /** Guards against scheduling more than one column-width measurement per freeze. */
4322
+ this.colWidthMeasureScheduled = false;
3834
4323
  // ── Props ──────────────────────────────────────────────────────────────────
3835
4324
  /** The VIEW or RELATED_VIEW layout item. Contains view config, dataClass, fromClass, actions etc. */
3836
4325
  this.item = null;
@@ -3847,11 +4336,16 @@ const MrdTable = class {
3847
4336
  this.rowHeight = 36;
3848
4337
  /** Height of the scroll container in px. */
3849
4338
  this.tableHeight = 500;
4339
+ /** Time (ms) to wait for setPage() before retrying a page request; after
4340
+ * MAX_RETRY_ATTEMPTS retries the page is marked failed (see failedPages). */
4341
+ this.requestTimeoutMs = REQUEST_TIMEOUT_MS;
3850
4342
  // ── Internal state ─────────────────────────────────────────────────────────
3851
4343
  /** Index into allViews[] for the currently displayed view. 0 = primary, 1+ = alternatives. */
3852
4344
  this.activeViewIdx = 0;
3853
4345
  this.loadedPages = new Map();
3854
4346
  this.requestedPages = new Set();
4347
+ /** Pages that timed out MAX_RETRY_ATTEMPTS times — rendered as a retry row instead of shimmer. */
4348
+ this.failedPages = new Set();
3855
4349
  this.renderStart = 0;
3856
4350
  this.renderEnd = 0;
3857
4351
  this.colWidths = [];
@@ -3887,13 +4381,10 @@ const MrdTable = class {
3887
4381
  this.minKnownTotal = 0;
3888
4382
  this.handleScroll = (e) => {
3889
4383
  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);
4384
+ const { renderStart, renderEnd } = computeWindow(scroller.scrollTop, this.rowHeight, this.tableHeight, this.baseTotal);
4385
+ this.scrollTop = scroller.scrollTop;
4386
+ this.renderStart = renderStart;
4387
+ this.renderEnd = renderEnd;
3897
4388
  this.requestPagesForWindow(this.renderStart, this.renderEnd);
3898
4389
  };
3899
4390
  }
@@ -3913,18 +4404,14 @@ const MrdTable = class {
3913
4404
  var _a, _b, _c;
3914
4405
  this.applyDefaultSort((_c = (_b = (_a = this.item) === null || _a === void 0 ? void 0 : _a.view) === null || _b === void 0 ? void 0 : _b.defaultSort) !== null && _c !== void 0 ? _c : '');
3915
4406
  }
4407
+ componentDidLoad() {
4408
+ this.staleCheckTimer = setInterval(() => this.checkStalePages(), STALE_CHECK_INTERVAL_MS);
4409
+ }
3916
4410
  // ── Helpers ────────────────────────────────────────────────────────────────
3917
4411
  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
- }
4412
+ const { field, dir } = parseDefaultSort(defaultSort);
4413
+ this.sortField = field;
4414
+ this.sortDir = dir;
3928
4415
  }
3929
4416
  // ── Public API ─────────────────────────────────────────────────────────────
3930
4417
  /**
@@ -3940,7 +4427,11 @@ const MrdTable = class {
3940
4427
  this.pendingPages.clear();
3941
4428
  this.loadedPages = new Map();
3942
4429
  this.requestedPages = new Set();
4430
+ this.failedPages = new Set();
4431
+ this.requestedAt.clear();
4432
+ this.retryAttempts.clear();
3943
4433
  this.colWidths = [];
4434
+ this.colWidthMeasureScheduled = false;
3944
4435
  this.scrollTop = 0;
3945
4436
  this.renderStart = 0;
3946
4437
  // Always fill the visible viewport on init — totalElements may be stale from a
@@ -3954,7 +4445,7 @@ const MrdTable = class {
3954
4445
  this.aggregationsPending = true;
3955
4446
  this.minKnownTotal = 0;
3956
4447
  // Always request page 0 — totalElements may be unknown (0) on first load.
3957
- this.mrdLoadPage.emit({ page: 0, sort: this.sortParam(), path: this.buildDataPath(), qs: this.buildQueryParams(0) });
4448
+ this.emitLoadPage(0);
3958
4449
  this.requestedPages = new Set([0]);
3959
4450
  }
3960
4451
  /**
@@ -3985,6 +4476,13 @@ const MrdTable = class {
3985
4476
  const next = new Map(this.loadedPages);
3986
4477
  next.set(pageNumber, rows);
3987
4478
  this.loadedPages = next;
4479
+ this.requestedAt.delete(pageNumber);
4480
+ this.retryAttempts.delete(pageNumber);
4481
+ if (this.failedPages.has(pageNumber)) {
4482
+ const nextFailed = new Set(this.failedPages);
4483
+ nextFailed.delete(pageNumber);
4484
+ this.failedPages = nextFailed;
4485
+ }
3988
4486
  if (pageNumber === 0 && this.aggregationsPending) {
3989
4487
  this.aggregationsPending = false;
3990
4488
  const hasAggColumns = this.columns.some(c => c.type === 'FIELD' && c.aggregate);
@@ -4003,6 +4501,10 @@ const MrdTable = class {
4003
4501
  }
4004
4502
  // ── Lifecycle ──────────────────────────────────────────────────────────────
4005
4503
  disconnectedCallback() {
4504
+ if (this.staleCheckTimer !== null) {
4505
+ clearInterval(this.staleCheckTimer);
4506
+ this.staleCheckTimer = null;
4507
+ }
4006
4508
  if (this.outsideClickHandler) {
4007
4509
  document.removeEventListener('click', this.outsideClickHandler);
4008
4510
  this.outsideClickHandler = null;
@@ -4021,21 +4523,34 @@ const MrdTable = class {
4021
4523
  }
4022
4524
  }
4023
4525
  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
- }
4526
+ // Freeze header widths once the first data page has rendered. The measurement
4527
+ // reads offsetWidth and writes the colWidths @State, which would trigger a
4528
+ // re-render *during* the render cycle if done synchronously here. Defer it to a
4529
+ // writeTask so the state mutation happens outside the render pass (avoids the
4530
+ // Stencil "state/prop changed during rendering" warning and potential loops).
4531
+ if (this.colWidths.length === 0 &&
4532
+ !this.colWidthMeasureScheduled &&
4533
+ this.loadedPages.size > 0 &&
4534
+ this.totalElements > 0) {
4535
+ this.colWidthMeasureScheduled = true;
4536
+ index.writeTask(() => {
4537
+ this.colWidthMeasureScheduled = false;
4538
+ // Re-check: state may have changed (e.g. a reset) between scheduling and running.
4539
+ if (this.colWidths.length !== 0)
4540
+ return;
4541
+ const ths = this.el.querySelectorAll('.mrd-table__header');
4542
+ if (ths.length > 0) {
4543
+ this.colWidths = Array.from(ths).map(th => th.offsetWidth);
4544
+ }
4545
+ });
4029
4546
  }
4030
4547
  }
4031
4548
  // ── Paging / scroll helpers ────────────────────────────────────────────────
4032
4549
  visibleCount() {
4033
- return Math.ceil(this.tableHeight / this.rowHeight);
4550
+ return visibleCount(this.tableHeight, this.rowHeight);
4034
4551
  }
4035
4552
  sortParam() {
4036
- if (!this.sortField)
4037
- return '';
4038
- return this.sortDir === 'desc' ? `${this.sortField},desc` : this.sortField;
4553
+ return buildSortParam(this.sortField, this.sortDir);
4039
4554
  }
4040
4555
  /** Stable ordered list: primary view first, then alternatives (from the item prop). */
4041
4556
  get allViews() {
@@ -4061,14 +4576,16 @@ const MrdTable = class {
4061
4576
  * VIEW: /excel/{dataClass}
4062
4577
  * RELATED_VIEW: /excel/{fromClass}/{parentId}/{dataClass} */
4063
4578
  buildExcelPath() {
4064
- var _a, _b, _c, _d;
4579
+ var _a;
4065
4580
  const v = this.allViews[this.activeViewIdx];
4066
4581
  if (!v)
4067
4582
  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 : ''}`;
4583
+ return '/excel' + buildListPath({
4584
+ isRelatedView: ((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === 'RELATED_VIEW',
4585
+ fromClass: v.fromClass,
4586
+ parentId: this.parentId,
4587
+ dataClass: v.dataClass,
4588
+ });
4072
4589
  }
4073
4590
  buildActionDetail(action, basicType) {
4074
4591
  var _a, _b, _c;
@@ -4088,80 +4605,28 @@ const MrdTable = class {
4088
4605
  * VIEW: /{dataClass}
4089
4606
  * RELATED_VIEW: /{fromClass}/{parentId}/{dataClass} */
4090
4607
  buildDataPath() {
4091
- var _a, _b, _c, _d;
4608
+ var _a;
4092
4609
  const v = this.allViews[this.activeViewIdx];
4093
4610
  if (!v)
4094
4611
  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 : ''}`;
4612
+ return buildListPath({
4613
+ isRelatedView: ((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === 'RELATED_VIEW',
4614
+ fromClass: v.fromClass,
4615
+ parentId: this.parentId,
4616
+ dataClass: v.dataClass,
4617
+ });
4099
4618
  }
4100
4619
  /** Build query params for a page request from current sort, view filters, filterClass and active column filters. */
4101
4620
  buildQueryParams(page) {
4102
- var _a, _b, _c, _d, _e, _f, _g;
4621
+ var _a;
4103
4622
  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();
4623
+ return buildTableQueryParams({
4624
+ page,
4625
+ sort: this.sortParam(),
4626
+ filterClass: v === null || v === void 0 ? void 0 : v.filterClass,
4627
+ viewFilters: (_a = v === null || v === void 0 ? void 0 : v.view) === null || _a === void 0 ? void 0 : _a.filter,
4628
+ activeFilters: this.activeFilters.values(),
4629
+ });
4165
4630
  }
4166
4631
  get columns() {
4167
4632
  var _a, _b, _c;
@@ -4216,11 +4681,7 @@ const MrdTable = class {
4216
4681
  isTotalKnown() {
4217
4682
  if (this.aggregationsTotal != null)
4218
4683
  return true;
4219
- for (const rows of this.loadedPages.values()) {
4220
- if (rows.length < this.pageSize)
4221
- return true;
4222
- }
4223
- return false;
4684
+ return isTotalKnownFromPages(this.loadedPages, this.pageSize);
4224
4685
  }
4225
4686
  /** Effective total: aggregations-response > totalElements prop > minKnownTotal from setPage(). */
4226
4687
  get baseTotal() {
@@ -4231,61 +4692,9 @@ const MrdTable = class {
4231
4692
  return this.minKnownTotal;
4232
4693
  }
4233
4694
  // ── 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
4695
  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);
4696
+ const qs = this.buildQueryParams(0);
4697
+ this.mrdLoadAggregations.emit({ path: this.buildDataPath(), qs, aggQs: buildAggregationQs(qs, this.columns) });
4289
4698
  }
4290
4699
  // ── Reset pagination ───────────────────────────────────────────────────────
4291
4700
  /** Reset pagination state and scroll to top (used after sort or filter change). */
@@ -4297,7 +4706,11 @@ const MrdTable = class {
4297
4706
  this.pendingPages.clear();
4298
4707
  this.loadedPages = new Map();
4299
4708
  this.requestedPages = new Set();
4709
+ this.failedPages = new Set();
4710
+ this.requestedAt.clear();
4711
+ this.retryAttempts.clear();
4300
4712
  this.colWidths = [];
4713
+ this.colWidthMeasureScheduled = false;
4301
4714
  this.scrollTop = 0;
4302
4715
  this.renderStart = 0;
4303
4716
  this.minKnownTotal = 0;
@@ -4326,15 +4739,19 @@ const MrdTable = class {
4326
4739
  this.resetPages();
4327
4740
  this.emitPagesForWindow(this.renderStart, this.renderEnd);
4328
4741
  }
4742
+ /** Emits mrdLoadPage for a page and records the request timestamp for stale-request detection. */
4743
+ emitLoadPage(page) {
4744
+ this.mrdLoadPage.emit({ page, sort: this.sortParam(), path: this.buildDataPath(), qs: this.buildQueryParams(page) });
4745
+ this.requestedAt.set(page, Date.now());
4746
+ }
4329
4747
  emitPagesForWindow(start, end) {
4330
- const firstPage = Math.floor(start / this.pageSize);
4331
- const lastPage = Math.floor(end / this.pageSize);
4748
+ const { firstPage, lastPage } = pageRange(start, end, this.pageSize);
4332
4749
  const next = new Set(this.requestedPages);
4333
4750
  let changed = false;
4334
4751
  for (let p = firstPage; p <= lastPage; p++) {
4335
4752
  if (!this.loadedPages.has(p) && !next.has(p)) {
4336
4753
  next.add(p);
4337
- this.mrdLoadPage.emit({ page: p, sort: this.sortParam(), path: this.buildDataPath(), qs: this.buildQueryParams(p) });
4754
+ this.emitLoadPage(p);
4338
4755
  changed = true;
4339
4756
  }
4340
4757
  }
@@ -4342,13 +4759,10 @@ const MrdTable = class {
4342
4759
  this.requestedPages = next;
4343
4760
  }
4344
4761
  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;
4762
+ return getRowFromPages(this.loadedPages, i, this.pageSize);
4348
4763
  }
4349
4764
  requestPagesForWindow(start, end) {
4350
- const firstPage = Math.floor(start / this.pageSize);
4351
- const lastPage = Math.floor(end / this.pageSize);
4765
+ const { firstPage, lastPage } = pageRange(start, end, this.pageSize);
4352
4766
  let anyNew = false;
4353
4767
  for (let p = firstPage; p <= lastPage; p++) {
4354
4768
  if (!this.loadedPages.has(p) && !this.requestedPages.has(p) && !this.pendingPages.has(p)) {
@@ -4376,13 +4790,53 @@ const MrdTable = class {
4376
4790
  if (pageEnd < this.renderStart || pageStart > this.renderEnd)
4377
4791
  continue;
4378
4792
  next.add(page);
4379
- this.mrdLoadPage.emit({ page, sort: this.sortParam(), path: this.buildDataPath(), qs: this.buildQueryParams(page) });
4793
+ this.emitLoadPage(page);
4380
4794
  changed = true;
4381
4795
  }
4382
4796
  this.pendingPages.clear();
4383
4797
  if (changed)
4384
4798
  this.requestedPages = next;
4385
4799
  }
4800
+ /** Scans outstanding requests for staleness: retries up to MAX_RETRY_ATTEMPTS times,
4801
+ * then gives up and marks the page as failed (rendered as a retry row). */
4802
+ checkStalePages() {
4803
+ var _a;
4804
+ if (this.requestedAt.size === 0)
4805
+ return;
4806
+ const stale = getStalePages(this.requestedAt, Date.now(), this.requestTimeoutMs)
4807
+ .filter(p => !this.loadedPages.has(p));
4808
+ if (stale.length === 0)
4809
+ return;
4810
+ let nextFailed = null;
4811
+ for (const page of stale) {
4812
+ const attempts = (_a = this.retryAttempts.get(page)) !== null && _a !== void 0 ? _a : 0;
4813
+ if (attempts < MAX_RETRY_ATTEMPTS) {
4814
+ this.retryAttempts.set(page, attempts + 1);
4815
+ this.emitLoadPage(page);
4816
+ }
4817
+ else {
4818
+ this.requestedAt.delete(page);
4819
+ this.retryAttempts.delete(page);
4820
+ if (!nextFailed)
4821
+ nextFailed = new Set(this.failedPages);
4822
+ nextFailed.add(page);
4823
+ this.mrdPageError.emit({ page });
4824
+ }
4825
+ }
4826
+ if (nextFailed)
4827
+ this.failedPages = nextFailed;
4828
+ }
4829
+ /** Manually retry a page the user gave up on (clicked the retry row). */
4830
+ retryPage(page) {
4831
+ const next = new Set(this.failedPages);
4832
+ next.delete(page);
4833
+ this.failedPages = next;
4834
+ this.retryAttempts.delete(page);
4835
+ this.emitLoadPage(page);
4836
+ const requested = new Set(this.requestedPages);
4837
+ requested.add(page);
4838
+ this.requestedPages = requested;
4839
+ }
4386
4840
  // ── Filter helpers ─────────────────────────────────────────────────────────
4387
4841
  handleFilterToggle() {
4388
4842
  this.filterMode = !this.filterMode;
@@ -4410,17 +4864,7 @@ const MrdTable = class {
4410
4864
  // If from and to cover the same local day it was an exact-date filter — restore
4411
4865
  // to exact mode so the user sees the single-date input again.
4412
4866
  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
- }
4867
+ this.pendingFilter = datetimeFilterToDisplay(existing);
4424
4868
  }
4425
4869
  else {
4426
4870
  this.pendingFilter = existing ? Object.assign({}, existing) : { field: name, dataType, operator: defaultOperator };
@@ -4486,81 +4930,15 @@ const MrdTable = class {
4486
4930
  const current = (_b = (_a = this.pendingFilter) === null || _a === void 0 ? void 0 : _a.values) !== null && _b !== void 0 ? _b : [];
4487
4931
  this.pendingFilter = Object.assign(Object.assign({}, this.pendingFilter), { values: checked ? [...current, key] : current.filter(k => k !== key) });
4488
4932
  }
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
4933
  applyFilter() {
4540
4934
  const f = this.pendingFilter;
4541
4935
  if (!(f === null || f === void 0 ? void 0 : f.field)) {
4542
4936
  this.closeFilterPopup();
4543
4937
  return;
4544
4938
  }
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
- }
4939
+ const normalized = normalizeDatetimeFilter(f);
4562
4940
  const next = new Map(this.activeFilters);
4563
- if (this.filterHasValue(normalized)) {
4941
+ if (filterHasValue(normalized)) {
4564
4942
  next.set(normalized.field, normalized);
4565
4943
  }
4566
4944
  else {
@@ -4615,140 +4993,53 @@ const MrdTable = class {
4615
4993
  toggleViewPopover(e) {
4616
4994
  e.stopPropagation();
4617
4995
  if (this.viewPopoverOpen) {
4618
- this.viewPopoverOpen = false;
4619
- if (this.viewPopoverClickHandler) {
4620
- document.removeEventListener('click', this.viewPopoverClickHandler);
4621
- this.viewPopoverClickHandler = null;
4622
- }
4996
+ this.closeViewPopover();
4623
4997
  return;
4624
4998
  }
4625
4999
  this.viewPopoverOpen = true;
4626
- this.viewPopoverClickHandler = () => {
4627
- this.viewPopoverOpen = false;
5000
+ this.viewPopoverClickHandler = () => this.closeViewPopover();
5001
+ document.addEventListener('click', this.viewPopoverClickHandler);
5002
+ }
5003
+ closeViewPopover() {
5004
+ this.viewPopoverOpen = false;
5005
+ if (this.viewPopoverClickHandler) {
4628
5006
  document.removeEventListener('click', this.viewPopoverClickHandler);
4629
5007
  this.viewPopoverClickHandler = null;
4630
- };
4631
- document.addEventListener('click', this.viewPopoverClickHandler);
5008
+ }
4632
5009
  }
4633
5010
  // ── Render: toolbar ────────────────────────────────────────────────────────
4634
5011
  renderToolbar() {
4635
5012
  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
- })))));
5013
+ 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: {
5014
+ onFilterToggle: () => this.handleFilterToggle(),
5015
+ onClearAllFilters: () => this.clearAllFilters(),
5016
+ onViewSwitch: idx => this.handleViewSwitch(idx),
5017
+ onToggleViewPopover: e => this.toggleViewPopover(e),
5018
+ onCloseViewPopover: () => this.closeViewPopover(),
5019
+ onToggleCreatePicker: () => this.toggleCreatePicker(),
5020
+ onCreate: basicType => {
5021
+ this.mrdAction.emit(this.buildActionDetail('create', basicType));
5022
+ this.closeCreatePicker();
5023
+ },
5024
+ onAction: action => this.mrdAction.emit(this.buildActionDetail(action)),
5025
+ } }));
4664
5026
  }
4665
5027
  // ── 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
5028
  renderFilterPopup() {
4743
- var _a;
4744
5029
  if (!this.openFilterCol || !this.pendingFilter)
4745
5030
  return null;
4746
5031
  const col = this.columns.find(c => this.colName(c) === this.openFilterCol);
4747
5032
  if (!col)
4748
5033
  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)))));
5034
+ 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: {
5035
+ onSetPending: (key, val) => this.setPending(key, val),
5036
+ onReplacePending: pf => (this.pendingFilter = pf),
5037
+ onToggleValue: (key, checked) => this.togglePendingValue(key, checked),
5038
+ onApplySort: dir => this.applySort(col, dir),
5039
+ onApply: () => this.applyFilter(),
5040
+ onClear: () => this.clearFilter(),
5041
+ onClose: () => this.closeFilterPopup(),
5042
+ } }));
4752
5043
  }
4753
5044
  // ── Render: footer ────────────────────────────────────────────────────────
4754
5045
  renderFooter(rowCount, effectiveTotal, isTotalKnown = true) {
@@ -4773,54 +5064,11 @@ const MrdTable = class {
4773
5064
  }
4774
5065
  // ── Render: cell ──────────────────────────────────────────────────────────
4775
5066
  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));
5067
+ 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
5068
  }
4812
5069
  // ── Render: totals row ────────────────────────────────────────────────────
4813
5070
  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
- }))));
5071
+ return index.h(TotalsRow, { columns: this.columns, aggregations: this.aggregations, locale: this.locale });
4824
5072
  }
4825
5073
  // ── Render ─────────────────────────────────────────────────────────────────
4826
5074
  render() {
@@ -4840,7 +5088,7 @@ const MrdTable = class {
4840
5088
  isFiltered ? 'mrd-table__header--filtered' : '',
4841
5089
  this.filterMode ? 'mrd-table__header--sortable' : '',
4842
5090
  ].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()));
5091
+ 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
5092
  }))), 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
5093
  }
4846
5094
  // ── Paginated / virtual-scroll mode ────────────────────────────────────
@@ -4848,12 +5096,7 @@ const MrdTable = class {
4848
5096
  // if any loaded page is shorter than pageSize it is the last page,
4849
5097
  // so the true total cannot exceed (pageNum * pageSize + pageRows.length).
4850
5098
  // 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
- }
5099
+ const effectiveTotal = computeEffectiveTotal(this.loadedPages, this.pageSize, this.baseTotal);
4857
5100
  // Clamp renderEnd to what we actually know exists (-1 when empty)
4858
5101
  const clampedEnd = Math.min(this.renderEnd, effectiveTotal - 1);
4859
5102
  const colCount = this.columns.length;
@@ -4866,7 +5109,13 @@ const MrdTable = class {
4866
5109
  for (let i = this.renderStart; i <= clampedEnd; i++) {
4867
5110
  const row = this.getRow(i);
4868
5111
  if (row === null) {
4869
- renderedRows.push(index.h("tr", { class: "mrd-table__row mrd-table__row--loading" }, index.h("td", { class: "mrd-table__cell--placeholder", colSpan: colCount }, index.h("span", { class: "mrd-table__placeholder-bar" }))));
5112
+ const page = Math.floor(i / this.pageSize);
5113
+ if (this.failedPages.has(page)) {
5114
+ renderedRows.push(index.h("tr", { class: "mrd-table__row mrd-table__row--failed" }, index.h("td", { class: "mrd-table__cell--failed", colSpan: colCount }, index.h("button", { type: "button", class: "mrd-table__retry-button", onClick: () => this.retryPage(page) }, t('load_failed_retry', this.locale)))));
5115
+ }
5116
+ else {
5117
+ renderedRows.push(index.h("tr", { class: "mrd-table__row mrd-table__row--loading" }, index.h("td", { class: "mrd-table__cell--placeholder", colSpan: colCount }, index.h("span", { class: "mrd-table__placeholder-bar" }))));
5118
+ }
4870
5119
  }
4871
5120
  else {
4872
5121
  renderedRows.push(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))));
@@ -4884,21 +5133,14 @@ const MrdTable = class {
4884
5133
  isActive ? `mrd-table__header--sorted-${this.sortDir}` : '',
4885
5134
  isFiltered ? 'mrd-table__header--filtered' : '',
4886
5135
  ].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" }))));
5136
+ 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)));
5137
+ }))), 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
5138
  }
4893
5139
  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))));
5140
+ return index.h(TextblockModal, { text: this.textblockModal, locale: this.locale, onClose: () => this.closeTextblockModal() });
4897
5141
  }
4898
5142
  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 }))));
5143
+ return index.h(JsonModal, { html: this.jsonModal, locale: this.locale, onClose: () => this.closeJsonModal() });
4902
5144
  }
4903
5145
  get el() { return index.getElement(this); }
4904
5146
  static get watchers() { return {
@@ -4910,9 +5152,9 @@ const MrdTable = class {
4910
5152
  }]
4911
5153
  }; }
4912
5154
  };
4913
- MrdTable.style = mrdTableScss();
5155
+ MrdTable.style = mrdTableCss();
4914
5156
 
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)}`;
5157
+ 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
5158
 
4917
5159
  const MrdTextField = class {
4918
5160
  constructor(hostRef) {
@@ -4933,23 +5175,17 @@ const MrdTextField = class {
4933
5175
  };
4934
5176
  this.handleBlur = (e) => {
4935
5177
  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
- }
5178
+ this.error = requiredError(val, this.required, this.locale);
4942
5179
  this.mrdBlur.emit({ name: this.name, value: val });
4943
5180
  };
4944
5181
  }
4945
5182
  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))));
5183
+ 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
5184
  }
4949
5185
  };
4950
- MrdTextField.style = mrdTextFieldScss();
5186
+ MrdTextField.style = mrdTextFieldCss();
4951
5187
 
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)}`;
5188
+ 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
5189
 
4954
5190
  const MrdTextareaField = class {
4955
5191
  constructor(hostRef) {
@@ -5002,12 +5238,7 @@ const MrdTextareaField = class {
5002
5238
  var _a, _b;
5003
5239
  if (!range) {
5004
5240
  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
- }
5241
+ this.error = requiredError(html, this.required, this.locale);
5011
5242
  this.mrdBlur.emit({ name: this.name, value: html });
5012
5243
  }
5013
5244
  });
@@ -5018,13 +5249,13 @@ const MrdTextareaField = class {
5018
5249
  }
5019
5250
  }
5020
5251
  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))));
5252
+ 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
5253
  }
5023
5254
  get el() { return index.getElement(this); }
5024
5255
  };
5025
- MrdTextareaField.style = mrdTextareaFieldScss();
5256
+ MrdTextareaField.style = mrdTextareaFieldCss();
5026
5257
 
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)}`;
5258
+ 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
5259
 
5029
5260
  const MrdTimeField = class {
5030
5261
  constructor(hostRef) {
@@ -5040,12 +5271,7 @@ const MrdTimeField = class {
5040
5271
  this.error = '';
5041
5272
  this.handleChange = (e) => {
5042
5273
  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
- }
5274
+ this.error = requiredError(val, this.required, this.locale);
5049
5275
  this.mrdChange.emit({ name: this.name, value: val });
5050
5276
  };
5051
5277
  this.handleBlur = (e) => {
@@ -5054,11 +5280,10 @@ const MrdTimeField = class {
5054
5280
  };
5055
5281
  }
5056
5282
  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))));
5283
+ 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
5284
  }
5060
5285
  };
5061
- MrdTimeField.style = mrdTimeFieldScss();
5286
+ MrdTimeField.style = mrdTimeFieldCss();
5062
5287
 
5063
5288
  exports.mrd_boolean_field = MrdBooleanField;
5064
5289
  exports.mrd_currency_field = MrdCurrencyField;