@mmlogic/components 0.5.14 → 0.5.16

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 (91) hide show
  1. package/dist/cjs/{cell-renderer-mjS630f1.js → cell-renderer-CLVKTVVQ.js} +105 -1
  2. package/dist/cjs/{client-layout-CqVuJumR.js → client-layout-Eg2VwW-7.js} +2 -0
  3. package/dist/cjs/index.cjs.js +2 -1
  4. package/dist/cjs/loader.cjs.js +1 -1
  5. package/dist/cjs/mosterdcomponents.cjs.js +1 -1
  6. package/dist/cjs/{mrd-boolean-field_25.cjs.entry.js → mrd-boolean-field_28.cjs.entry.js} +1168 -314
  7. package/dist/cjs/mrd-merge-view.cjs.entry.js +4 -4
  8. package/dist/collection/collection-manifest.json +3 -0
  9. package/dist/collection/components/fields/mrd-textarea-field/mrd-textarea-field.js +47 -2
  10. package/dist/collection/components/form/mrd-field/mrd-field.css +69 -0
  11. package/dist/collection/components/form/mrd-field/mrd-field.js +95 -25
  12. package/dist/collection/components/form/mrd-form/mrd-form.css +29 -0
  13. package/dist/collection/components/form/mrd-form/mrd-form.js +44 -8
  14. package/dist/collection/components/layout/mrd-layout-section/field-value.js +19 -2
  15. package/dist/collection/components/layout/mrd-layout-section/layout-helpers.js +10 -0
  16. package/dist/collection/components/layout/mrd-layout-section/mrd-layout-section.css +4 -3
  17. package/dist/collection/components/layout/mrd-layout-section/mrd-layout-section.js +169 -18
  18. package/dist/collection/components/memo/mrd-memo-container/mrd-memo-container.css +204 -0
  19. package/dist/collection/components/memo/mrd-memo-container/mrd-memo-container.js +769 -0
  20. package/dist/collection/components/memo/mrd-memo-list/mrd-memo-list.css +164 -0
  21. package/dist/collection/components/memo/mrd-memo-list/mrd-memo-list.js +559 -0
  22. package/dist/collection/components/memo/mrd-memo-view/mrd-memo-view.css +108 -0
  23. package/dist/collection/components/memo/mrd-memo-view/mrd-memo-view.js +204 -0
  24. package/dist/collection/components/merge/mrd-merge-view/mrd-merge-view.js +2 -2
  25. package/dist/collection/components/table/mrd-table/mrd-table.js +9 -6
  26. package/dist/collection/dev/app.js +30 -15
  27. package/dist/collection/dev/example-data.js +15 -1
  28. package/dist/collection/types/client-layout.js +1 -0
  29. package/dist/collection/utils/i18n.js +104 -0
  30. package/dist/collection/utils/query-params.js +9 -0
  31. package/dist/components/client-layout.js +1 -1
  32. package/dist/components/i18n.js +1 -1
  33. package/dist/components/index.js +1 -1
  34. package/dist/components/mrd-field2.js +1 -1
  35. package/dist/components/mrd-form.js +1 -1
  36. package/dist/components/mrd-layout-section.js +1 -1
  37. package/dist/components/mrd-memo-container.d.ts +11 -0
  38. package/dist/components/mrd-memo-container.js +1 -0
  39. package/dist/components/mrd-memo-container2.js +1 -0
  40. package/dist/components/mrd-memo-list.d.ts +11 -0
  41. package/dist/components/mrd-memo-list.js +1 -0
  42. package/dist/components/mrd-memo-list2.js +1 -0
  43. package/dist/components/mrd-memo-view.d.ts +11 -0
  44. package/dist/components/mrd-memo-view.js +1 -0
  45. package/dist/components/mrd-memo-view2.js +1 -0
  46. package/dist/components/mrd-merge-view.js +1 -1
  47. package/dist/components/mrd-table2.js +1 -1
  48. package/dist/components/mrd-textarea-field2.js +1 -1
  49. package/dist/components/query-params.js +1 -1
  50. package/dist/components/table-query.js +1 -0
  51. package/dist/esm/{cell-renderer-BDY8UXkH.js → cell-renderer-4NKEzZWw.js} +105 -1
  52. package/dist/esm/{client-layout-Bc42CfJB.js → client-layout-BJkVeSq6.js} +2 -1
  53. package/dist/esm/index.js +1 -1
  54. package/dist/esm/loader.js +1 -1
  55. package/dist/esm/mosterdcomponents.js +1 -1
  56. package/dist/esm/{mrd-boolean-field_25.entry.js → mrd-boolean-field_28.entry.js} +1166 -315
  57. package/dist/esm/mrd-merge-view.entry.js +4 -4
  58. package/dist/mosterdcomponents/{cell-renderer-B8u5BCK-.js.map → cell-renderer-CMUxFREW.js.map} +1 -1
  59. package/dist/mosterdcomponents/client-layout-BJkVeSq6.js.map +1 -0
  60. package/dist/mosterdcomponents/{field-helpers-CNQcI3Hf.js.map → field-helpers-BWAp5fD8.js.map} +1 -1
  61. package/dist/mosterdcomponents/{file-upload-common-C9wp47CB.js.map → file-upload-common-DDWuC9-3.js.map} +1 -1
  62. package/dist/mosterdcomponents/i18n-OzbszktW.js.map +1 -0
  63. package/dist/mosterdcomponents/index-CkcFwdPc.js.map +1 -0
  64. package/dist/mosterdcomponents/index.esm.js +1 -1
  65. package/dist/mosterdcomponents/mosterdcomponents.esm.js +1 -1
  66. package/dist/mosterdcomponents/p-8a7fa81d.entry.js +3 -0
  67. package/dist/mosterdcomponents/{p-Bc42CfJB.js → p-BJkVeSq6.js} +1 -1
  68. package/dist/mosterdcomponents/p-BMx6VAJ6.js +1 -0
  69. package/dist/mosterdcomponents/{p-e8b0880f.entry.js → p-e68dfbb0.entry.js} +1 -1
  70. package/dist/mosterdcomponents/query-params-3TXd5CUO.js.map +1 -0
  71. package/dist/mosterdcomponents/table-query-DJq1uKqJ.js.map +1 -0
  72. package/dist/mosterdcomponents/{validation-CjjTt66G.js.map → validation-B_0Lx9DE.js.map} +1 -1
  73. package/dist/types/components/fields/mrd-textarea-field/mrd-textarea-field.d.ts +10 -0
  74. package/dist/types/components/form/mrd-field/mrd-field.d.ts +16 -0
  75. package/dist/types/components/form/mrd-form/mrd-form.d.ts +6 -0
  76. package/dist/types/components/layout/mrd-layout-section/field-value.d.ts +4 -0
  77. package/dist/types/components/layout/mrd-layout-section/layout-helpers.d.ts +3 -0
  78. package/dist/types/components/layout/mrd-layout-section/mrd-layout-section.d.ts +25 -1
  79. package/dist/types/components/memo/mrd-memo-container/mrd-memo-container.d.ts +173 -0
  80. package/dist/types/components/memo/mrd-memo-list/mrd-memo-list.d.ts +91 -0
  81. package/dist/types/components/memo/mrd-memo-view/mrd-memo-view.d.ts +33 -0
  82. package/dist/types/components.d.ts +571 -1
  83. package/dist/types/types/client-layout.d.ts +1 -0
  84. package/dist/types/utils/query-params.d.ts +16 -0
  85. package/package.json +1 -1
  86. package/dist/mosterdcomponents/client-layout-Bc42CfJB.js.map +0 -1
  87. package/dist/mosterdcomponents/i18n-ydNM87-Q.js.map +0 -1
  88. package/dist/mosterdcomponents/index-DhffneUF.js.map +0 -1
  89. package/dist/mosterdcomponents/p-Dkm4WxMy.js +0 -1
  90. package/dist/mosterdcomponents/p-c834951a.entry.js +0 -3
  91. package/dist/mosterdcomponents/query-params-BZbQoeYF.js.map +0 -1
@@ -1,6 +1,6 @@
1
1
  import { r as registerInstance, c as createEvent, h, H as Host, g as getElement, w as writeTask } from './index-CDiBvvJU.js';
2
- import { t, p as parseLocalizedNumber, f as formatNumber, a as formatDate, b as formatDateTime, c as formatCurrency, C as CellRenderer, d as formatPercentage } from './cell-renderer-BDY8UXkH.js';
3
- import { b as ClientLayoutItemFieldDataType, e as ClientLayoutNavigateBehaviour, a as ClientLayoutItemType, c as ClientLayoutItemRelationDisplayType, d as ClientLayoutItemRelationEditBehavior, r as resolveArchetype, A as ARCHETYPE_DOCUMENT, h as ARCHETYPE_INVOICE_LINE, f as ARCHETYPE_INVOICE, g as ARCHETYPE_EMAIL } from './client-layout-Bc42CfJB.js';
2
+ import { t, p as parseLocalizedNumber, f as formatNumber, a as formatDate, b as formatDateTime, c as formatCurrency, C as CellRenderer, d as formatPercentage } from './cell-renderer-4NKEzZWw.js';
3
+ import { b as ClientLayoutItemFieldDataType, e as ClientLayoutNavigateBehaviour, a as ClientLayoutItemType, c as ClientLayoutItemRelationDisplayType, d as ClientLayoutItemRelationEditBehavior, r as resolveArchetype, A as ARCHETYPE_DOCUMENT, i as ARCHETYPE_MEMO, h as ARCHETYPE_INVOICE_LINE, f as ARCHETYPE_INVOICE, g as ARCHETYPE_EMAIL } from './client-layout-BJkVeSq6.js';
4
4
 
5
5
  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)}`;
6
6
 
@@ -520,6 +520,15 @@ function buildListPath(opts) {
520
520
  }
521
521
  return `/${(_c = opts.dataClass) !== null && _c !== void 0 ? _c : ''}`;
522
522
  }
523
+ /** The `mrdAction` detail for a toolbar "create" action: `parentPath` locates the
524
+ * RELATED_VIEW's parent (`/{fromClass}/{parentId}`) so the host can route to
525
+ * `.../{parentPath}/{dataClass}/new`; `null` for a top-level VIEW. Shared by
526
+ * mrd-table and mrd-memo-container so both toolbars build an identical payload. */
527
+ function buildCreateActionDetail(opts) {
528
+ var _a, _b;
529
+ const parentPath = opts.isRelatedView ? `/${(_a = opts.fromClass) !== null && _a !== void 0 ? _a : ''}/${opts.parentId}` : null;
530
+ return Object.assign({ action: 'create', dataClass: (_b = opts.dataClass) !== null && _b !== void 0 ? _b : '', parentPath }, (opts.basicType ? { basicType: opts.basicType } : {}));
531
+ }
523
532
 
524
533
  /**
525
534
  * Tree model and pure tree logic for mrd-document-list.
@@ -4070,7 +4079,7 @@ const MrdEmailView = class {
4070
4079
  };
4071
4080
  MrdEmailView.style = mrdEmailViewCss();
4072
4081
 
4073
- 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)}`;
4082
+ 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)}.mrd-field__multi.sc-mrd-field{display:flex;flex-direction:column;gap:var(--mrd-space-1)}.mrd-field__multi__label.sc-mrd-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-field__multi__label--required.sc-mrd-field::after{content:" *";color:var(--mrd-color-danger)}.mrd-field__multi__error.sc-mrd-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}.mrd-field__multi-row.sc-mrd-field{display:flex;align-items:flex-start;gap:var(--mrd-space-2)}.mrd-field__multi-row-input.sc-mrd-field{flex:1 1 0;min-width:0}.mrd-field__multi-remove.sc-mrd-field{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:2rem;height:var(--mrd-input-height);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__multi-remove.sc-mrd-field:hover{color:var(--mrd-color-danger);background-color:var(--mrd-color-danger-light)}.mrd-field__multi-remove.sc-mrd-field svg.sc-mrd-field{width:1rem;height:1rem}.mrd-field__multi-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__multi-add.sc-mrd-field:hover{background-color:var(--mrd-color-primary-light)}`;
4074
4083
 
4075
4084
  const MrdField = class {
4076
4085
  constructor(hostRef) {
@@ -4083,6 +4092,13 @@ const MrdField = class {
4083
4092
  this.locale = navigator.language;
4084
4093
  this.historyEntries = [];
4085
4094
  this.currentValue = undefined;
4095
+ this.multiValues = [];
4096
+ this.multiError = '';
4097
+ this.handleMultiRowBlur = () => {
4098
+ var _a;
4099
+ this.multiError = requiredError(this.multiValues, (_a = this.item.required) !== null && _a !== void 0 ? _a : false, this.locale);
4100
+ this.mrdBlur.emit({ name: this.item.name, value: this.multiValues });
4101
+ };
4086
4102
  this.handleChange = (e) => {
4087
4103
  var _a, _b, _c, _d;
4088
4104
  e.stopPropagation();
@@ -4127,9 +4143,11 @@ const MrdField = class {
4127
4143
  }
4128
4144
  componentWillLoad() {
4129
4145
  this.initHistoryState();
4146
+ this.initMultiState();
4130
4147
  }
4131
4148
  valueChanged() {
4132
4149
  this.initHistoryState();
4150
+ this.initMultiState();
4133
4151
  }
4134
4152
  initHistoryState() {
4135
4153
  var _a, _b, _c, _d, _e;
@@ -4140,6 +4158,43 @@ const MrdField = class {
4140
4158
  this.currentValue = (_e = raw === null || raw === void 0 ? void 0 : raw.current) !== null && _e !== void 0 ? _e : raw;
4141
4159
  this.historyEntries = Array.isArray(raw === null || raw === void 0 ? void 0 : raw.history) ? [...raw.history] : [];
4142
4160
  }
4161
+ /** LIST/FILE/IMAGE already own their multiple-value UI end to end; every
4162
+ * other scalar dataType routes through the generic repeater below instead
4163
+ * of each leaf field re-implementing add/remove itself (FINDING-0149). */
4164
+ isMultiScalar() {
4165
+ var _a, _b;
4166
+ if (((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) !== ClientLayoutItemType.FIELD || !((_b = this.item) === null || _b === void 0 ? void 0 : _b.multiple))
4167
+ return false;
4168
+ const dt = this.item.dataType;
4169
+ return dt !== ClientLayoutItemFieldDataType.LIST
4170
+ && dt !== ClientLayoutItemFieldDataType.FILE
4171
+ && dt !== ClientLayoutItemFieldDataType.IMAGE;
4172
+ }
4173
+ initMultiState() {
4174
+ if (!this.isMultiScalar())
4175
+ return;
4176
+ const v = this.value;
4177
+ this.multiValues = Array.isArray(v) ? [...v] : (v != null && v !== '' ? [v] : []);
4178
+ }
4179
+ emptyRowValue() {
4180
+ var _a;
4181
+ switch (this.item.dataType) {
4182
+ case ClientLayoutItemFieldDataType.INTEGER:
4183
+ case ClientLayoutItemFieldDataType.DECIMAL:
4184
+ case ClientLayoutItemFieldDataType.PERCENTAGE:
4185
+ return null;
4186
+ case ClientLayoutItemFieldDataType.CURRENCY:
4187
+ return { amount: null, currency: (_a = this.item.currencyCode) !== null && _a !== void 0 ? _a : 'EUR' };
4188
+ case ClientLayoutItemFieldDataType.BOOLEAN:
4189
+ return false;
4190
+ default:
4191
+ return '';
4192
+ }
4193
+ }
4194
+ emitMultiChange(values) {
4195
+ this.multiValues = values;
4196
+ this.mrdChange.emit({ name: this.item.name, value: values });
4197
+ }
4143
4198
  getDisplayValue() {
4144
4199
  var _a, _b, _c, _d;
4145
4200
  const hist = (_b = (_a = this.item) === null || _a === void 0 ? void 0 : _a.historyEnabled) !== null && _b !== void 0 ? _b : (_d = (_c = this.item) === null || _c === void 0 ? void 0 : _c.field) === null || _d === void 0 ? void 0 : _d.historyEnabled;
@@ -4168,6 +4223,9 @@ const MrdField = class {
4168
4223
  value: { current: this.currentValue, history: entries },
4169
4224
  });
4170
4225
  }
4226
+ renderRemoveIcon() {
4227
+ return (h("svg", { viewBox: "0 0 20 20", fill: "currentColor", "aria-hidden": "true" }, h("path", { "fill-rule": "evenodd", d: "M8.75 1A2.75 2.75 0 006 3.75v.443c-.795.077-1.584.176-2.365.298a.75.75 0 10.23 1.482l.149-.022.841 10.518A2.75 2.75 0 007.596 19h4.807a2.75 2.75 0 002.742-2.53l.841-10.52.149.023a.75.75 0 00.23-1.482A41.03 41.03 0 0014 4.193V3.75A2.75 2.75 0 0011.25 1h-2.5zM10 4c.84 0 1.673.025 2.5.075V3.75c0-.69-.56-1.25-1.25-1.25h-2.5c-.69 0-1.25.56-1.25 1.25v.325C8.327 4.025 9.16 4 10 4zM8.58 7.72a.75.75 0 00-1.5.06l.3 7.5a.75.75 0 101.5-.06l-.3-7.5zm4.34.06a.75.75 0 10-1.5-.06l-.3 7.5a.75.75 0 101.5.06l.3-7.5z", "clip-rule": "evenodd" })));
4228
+ }
4171
4229
  renderHistoryEditor() {
4172
4230
  var _a, _b, _c, _d;
4173
4231
  const hist = (_b = (_a = this.item) === null || _a === void 0 ? void 0 : _a.historyEnabled) !== null && _b !== void 0 ? _b : (_d = (_c = this.item) === null || _c === void 0 ? void 0 : _c.field) === null || _d === void 0 ? void 0 : _d.historyEnabled;
@@ -4185,62 +4243,80 @@ const MrdField = class {
4185
4243
  const addEntry = () => {
4186
4244
  this.emitHistoryChange([...this.historyEntries, { value: '', until: '' }]);
4187
4245
  };
4188
- return (h("div", { class: "mrd-field__history-editor" }, this.historyEntries.length > 0 && (h("span", { class: "mrd-field__history-editor-label" }, t('history_badge_tooltip', locale))), this.historyEntries.map((entry, i) => (h("div", { key: String(i), class: "mrd-field__history-editor-row" }, h("input", { class: "mrd-field__history-editor-value", type: valueType, value: entry.value, onInput: (e) => updateEntry(i, 'value', e.target.value) }), h("span", { class: "mrd-field__history-editor-sep" }, t('history_until', locale)), h("input", { class: "mrd-field__history-editor-until", type: "date", value: entry.until, onInput: (e) => updateEntry(i, 'until', e.target.value) }), h("button", { type: "button", class: "mrd-field__history-editor-remove", onClick: () => removeEntry(i), "aria-label": t('remove', locale) }, h("svg", { viewBox: "0 0 20 20", fill: "currentColor", "aria-hidden": "true" }, h("path", { "fill-rule": "evenodd", d: "M8.75 1A2.75 2.75 0 006 3.75v.443c-.795.077-1.584.176-2.365.298a.75.75 0 10.23 1.482l.149-.022.841 10.518A2.75 2.75 0 007.596 19h4.807a2.75 2.75 0 002.742-2.53l.841-10.52.149.023a.75.75 0 00.23-1.482A41.03 41.03 0 0014 4.193V3.75A2.75 2.75 0 0011.25 1h-2.5zM10 4c.84 0 1.673.025 2.5.075V3.75c0-.69-.56-1.25-1.25-1.25h-2.5c-.69 0-1.25.56-1.25 1.25v.325C8.327 4.025 9.16 4 10 4zM8.58 7.72a.75.75 0 00-1.5.06l.3 7.5a.75.75 0 101.5-.06l-.3-7.5zm4.34.06a.75.75 0 10-1.5-.06l-.3 7.5a.75.75 0 101.5.06l.3-7.5z", "clip-rule": "evenodd" })))))), h("button", { type: "button", class: "mrd-field__history-editor-add", onClick: addEntry }, "+ ", t('add', locale))));
4246
+ return (h("div", { class: "mrd-field__history-editor" }, this.historyEntries.length > 0 && (h("span", { class: "mrd-field__history-editor-label" }, t('history_badge_tooltip', locale))), this.historyEntries.map((entry, i) => (h("div", { key: String(i), class: "mrd-field__history-editor-row" }, h("input", { class: "mrd-field__history-editor-value", type: valueType, value: entry.value, onInput: (e) => updateEntry(i, 'value', e.target.value) }), h("span", { class: "mrd-field__history-editor-sep" }, t('history_until', locale)), h("input", { class: "mrd-field__history-editor-until", type: "date", value: entry.until, onInput: (e) => updateEntry(i, 'until', e.target.value) }), h("button", { type: "button", class: "mrd-field__history-editor-remove", onClick: () => removeEntry(i), "aria-label": t('remove', locale) }, this.renderRemoveIcon())))), h("button", { type: "button", class: "mrd-field__history-editor-add", onClick: addEntry }, "+ ", t('add', locale))));
4189
4247
  }
4190
- renderLeafField(displayValue) {
4191
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6;
4248
+ renderLeafField(displayValue, onChange = this.handleChange, onBlur = this.handleBlur, overrides = {}) {
4249
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8;
4192
4250
  const { item, locale } = this;
4193
4251
  const commonProps = {
4194
4252
  name: item.name,
4195
- label: item.label,
4196
- required: item.required,
4197
- disabled: (_a = item.disabled) !== null && _a !== void 0 ? _a : false,
4253
+ label: (_a = overrides.label) !== null && _a !== void 0 ? _a : item.label,
4254
+ required: (_b = overrides.required) !== null && _b !== void 0 ? _b : item.required,
4255
+ disabled: (_c = item.disabled) !== null && _c !== void 0 ? _c : false,
4198
4256
  locale,
4199
- onMrdChange: this.handleChange,
4200
- onMrdBlur: this.handleBlur,
4257
+ onMrdChange: onChange,
4258
+ onMrdBlur: onBlur,
4201
4259
  };
4202
4260
  switch (item.dataType) {
4203
4261
  case ClientLayoutItemFieldDataType.TEXT:
4204
- return (h("mrd-text-field", Object.assign({}, commonProps, { value: (_b = displayValue) !== null && _b !== void 0 ? _b : '', placeholder: (_c = item.placeholder) !== null && _c !== void 0 ? _c : '' })));
4262
+ return (h("mrd-text-field", Object.assign({}, commonProps, { value: (_d = displayValue) !== null && _d !== void 0 ? _d : '', placeholder: (_e = item.placeholder) !== null && _e !== void 0 ? _e : '' })));
4205
4263
  case ClientLayoutItemFieldDataType.TEXTBLOCK:
4206
- return (h("mrd-textarea-field", Object.assign({}, commonProps, { value: (_d = displayValue) !== null && _d !== void 0 ? _d : '', placeholder: (_e = item.placeholder) !== null && _e !== void 0 ? _e : '' })));
4264
+ return (h("mrd-textarea-field", Object.assign({}, commonProps, { value: (_f = displayValue) !== null && _f !== void 0 ? _f : '', placeholder: (_g = item.placeholder) !== null && _g !== void 0 ? _g : '' })));
4207
4265
  case ClientLayoutItemFieldDataType.INTEGER:
4208
4266
  case ClientLayoutItemFieldDataType.DECIMAL:
4209
4267
  case ClientLayoutItemFieldDataType.PERCENTAGE:
4210
- return (h("mrd-number-field", Object.assign({}, commonProps, { value: (_f = displayValue) !== null && _f !== void 0 ? _f : null, dataType: item.dataType, decimalPrecision: (_g = item.decimalPrecision) !== null && _g !== void 0 ? _g : 2, placeholder: (_h = item.placeholder) !== null && _h !== void 0 ? _h : '' })));
4268
+ return (h("mrd-number-field", Object.assign({}, commonProps, { value: (_h = displayValue) !== null && _h !== void 0 ? _h : null, dataType: item.dataType, decimalPrecision: (_j = item.decimalPrecision) !== null && _j !== void 0 ? _j : 2, placeholder: (_k = item.placeholder) !== null && _k !== void 0 ? _k : '' })));
4211
4269
  case ClientLayoutItemFieldDataType.CURRENCY:
4212
4270
  return (h("mrd-currency-field", Object.assign({}, commonProps, {
4213
4271
  // Input-only fallback: it preselects the layout's currencyCode in the dropdown
4214
4272
  // before an amount exists. The field never emits this shape back — an empty
4215
4273
  // amount emits null (FINDING-0141).
4216
- value: (_j = displayValue) !== null && _j !== void 0 ? _j : { amount: null, currency: (_k = item.currencyCode) !== null && _k !== void 0 ? _k : 'EUR' }
4274
+ value: (_l = displayValue) !== null && _l !== void 0 ? _l : { amount: null, currency: (_m = item.currencyCode) !== null && _m !== void 0 ? _m : 'EUR' }
4217
4275
  })));
4218
4276
  case ClientLayoutItemFieldDataType.BOOLEAN:
4219
- return (h("mrd-boolean-field", Object.assign({}, commonProps, { value: (_l = displayValue) !== null && _l !== void 0 ? _l : false })));
4277
+ return (h("mrd-boolean-field", Object.assign({}, commonProps, { value: (_o = displayValue) !== null && _o !== void 0 ? _o : false })));
4220
4278
  case ClientLayoutItemFieldDataType.DATE:
4221
- return (h("mrd-date-field", Object.assign({}, commonProps, { value: (_m = displayValue) !== null && _m !== void 0 ? _m : '' })));
4279
+ return (h("mrd-date-field", Object.assign({}, commonProps, { value: (_p = displayValue) !== null && _p !== void 0 ? _p : '' })));
4222
4280
  case ClientLayoutItemFieldDataType.DATETIME:
4223
- return (h("mrd-datetime-field", Object.assign({}, commonProps, { value: (_o = displayValue) !== null && _o !== void 0 ? _o : '' })));
4281
+ return (h("mrd-datetime-field", Object.assign({}, commonProps, { value: (_q = displayValue) !== null && _q !== void 0 ? _q : '' })));
4224
4282
  case ClientLayoutItemFieldDataType.TIME:
4225
- return (h("mrd-time-field", Object.assign({}, commonProps, { value: (_p = displayValue) !== null && _p !== void 0 ? _p : '' })));
4283
+ return (h("mrd-time-field", Object.assign({}, commonProps, { value: (_r = displayValue) !== null && _r !== void 0 ? _r : '' })));
4226
4284
  case ClientLayoutItemFieldDataType.EMAIL:
4227
- return (h("mrd-email-field", Object.assign({}, commonProps, { value: (_q = displayValue) !== null && _q !== void 0 ? _q : '', placeholder: (_r = item.placeholder) !== null && _r !== void 0 ? _r : '' })));
4285
+ return (h("mrd-email-field", Object.assign({}, commonProps, { value: (_s = displayValue) !== null && _s !== void 0 ? _s : '', placeholder: (_t = item.placeholder) !== null && _t !== void 0 ? _t : '' })));
4228
4286
  case ClientLayoutItemFieldDataType.HYPERLINK:
4229
- return (h("mrd-hyperlink-field", Object.assign({}, commonProps, { value: (_s = displayValue) !== null && _s !== void 0 ? _s : '', placeholder: (_t = item.placeholder) !== null && _t !== void 0 ? _t : '' })));
4287
+ return (h("mrd-hyperlink-field", Object.assign({}, commonProps, { value: (_u = displayValue) !== null && _u !== void 0 ? _u : '', placeholder: (_v = item.placeholder) !== null && _v !== void 0 ? _v : '' })));
4230
4288
  case ClientLayoutItemFieldDataType.LIST:
4231
- return (h("mrd-list-field", Object.assign({}, commonProps, { value: (_u = displayValue) !== null && _u !== void 0 ? _u : '', multiple: (_v = item.multiple) !== null && _v !== void 0 ? _v : false, listItems: (_w = item.listItems) !== null && _w !== void 0 ? _w : [] })));
4289
+ return (h("mrd-list-field", Object.assign({}, commonProps, { value: (_w = displayValue) !== null && _w !== void 0 ? _w : '', multiple: (_x = item.multiple) !== null && _x !== void 0 ? _x : false, listItems: (_y = item.listItems) !== null && _y !== void 0 ? _y : [] })));
4232
4290
  case ClientLayoutItemFieldDataType.FILE:
4233
- return (h("mrd-file-field", Object.assign({}, commonProps, { value: displayValue, accept: (_x = item.accept) !== null && _x !== void 0 ? _x : '', maxSize: (_y = item.maxSize) !== null && _y !== void 0 ? _y : 0, multiple: (_z = item.multiple) !== null && _z !== void 0 ? _z : false, onMrdUpload: this.handleUpload })));
4291
+ return (h("mrd-file-field", Object.assign({}, commonProps, { value: displayValue, accept: (_z = item.accept) !== null && _z !== void 0 ? _z : '', maxSize: (_0 = item.maxSize) !== null && _0 !== void 0 ? _0 : 0, multiple: (_1 = item.multiple) !== null && _1 !== void 0 ? _1 : false, onMrdUpload: this.handleUpload })));
4234
4292
  case ClientLayoutItemFieldDataType.IMAGE:
4235
- return (h("mrd-image-field", Object.assign({}, commonProps, { value: displayValue, accept: (_0 = item.accept) !== null && _0 !== void 0 ? _0 : 'image/*', maxSize: (_1 = item.maxSize) !== null && _1 !== void 0 ? _1 : 0, multiple: (_2 = item.multiple) !== null && _2 !== void 0 ? _2 : false, onMrdUpload: this.handleUpload })));
4293
+ return (h("mrd-image-field", Object.assign({}, commonProps, { value: displayValue, accept: (_2 = item.accept) !== null && _2 !== void 0 ? _2 : 'image/*', maxSize: (_3 = item.maxSize) !== null && _3 !== void 0 ? _3 : 0, multiple: (_4 = item.multiple) !== null && _4 !== void 0 ? _4 : false, onMrdUpload: this.handleUpload })));
4236
4294
  case ClientLayoutItemFieldDataType.LONGTEXT:
4237
- return (h("mrd-longtext-field", Object.assign({}, commonProps, { value: (_3 = displayValue) !== null && _3 !== void 0 ? _3 : '', placeholder: (_4 = item.placeholder) !== null && _4 !== void 0 ? _4 : '' })));
4295
+ return (h("mrd-longtext-field", Object.assign({}, commonProps, { value: (_5 = displayValue) !== null && _5 !== void 0 ? _5 : '', placeholder: (_6 = item.placeholder) !== null && _6 !== void 0 ? _6 : '' })));
4238
4296
  case ClientLayoutItemFieldDataType.SECRET:
4239
- return (h("mrd-secret-field", Object.assign({}, commonProps, { value: (_5 = displayValue) !== null && _5 !== void 0 ? _5 : '', placeholder: (_6 = item.placeholder) !== null && _6 !== void 0 ? _6 : '' })));
4297
+ return (h("mrd-secret-field", Object.assign({}, commonProps, { value: (_7 = displayValue) !== null && _7 !== void 0 ? _7 : '', placeholder: (_8 = item.placeholder) !== null && _8 !== void 0 ? _8 : '' })));
4240
4298
  default:
4241
4299
  return null;
4242
4300
  }
4243
4301
  }
4302
+ /** Repeatable-row UI for a scalar dataType with multiple: true — mirrors the
4303
+ * add/remove pattern already established by renderHistoryEditor(), reusing
4304
+ * the single-row renderLeafField() per entry instead of duplicating repeat
4305
+ * UI into every leaf field component (FINDING-0149). */
4306
+ renderMultiScalarField() {
4307
+ var _a, _b;
4308
+ const { item, locale } = this;
4309
+ const updateRow = (i, val) => {
4310
+ this.emitMultiChange(this.multiValues.map((v, idx) => (idx === i ? val : v)));
4311
+ };
4312
+ const removeRow = (i) => {
4313
+ this.emitMultiChange(this.multiValues.filter((_, idx) => idx !== i));
4314
+ };
4315
+ const addRow = () => {
4316
+ this.emitMultiChange([...this.multiValues, this.emptyRowValue()]);
4317
+ };
4318
+ return (h("div", { class: "mrd-field__multi" }, h(FieldLabel, { base: "mrd-field__multi", label: (_a = item.label) !== null && _a !== void 0 ? _a : '', required: (_b = item.required) !== null && _b !== void 0 ? _b : false }), this.multiValues.map((v, i) => (h("div", { key: String(i), class: "mrd-field__multi-row" }, h("div", { class: "mrd-field__multi-row-input" }, this.renderLeafField(v, (e) => { e.stopPropagation(); updateRow(i, e.detail.value); }, (e) => { e.stopPropagation(); this.handleMultiRowBlur(); }, { label: '', required: false })), h("button", { type: "button", class: "mrd-field__multi-remove", onClick: () => removeRow(i), "aria-label": t('remove', locale) }, this.renderRemoveIcon())))), h("button", { type: "button", class: "mrd-field__multi-add", onClick: addRow }, "+ ", t('add', locale)), h(FieldError, { base: "mrd-field__multi", error: this.multiError })));
4319
+ }
4244
4320
  render() {
4245
4321
  var _a, _b, _c, _d, _e, _f;
4246
4322
  const { item, locale, value } = this;
@@ -4251,7 +4327,7 @@ const MrdField = class {
4251
4327
  return h(Host, null);
4252
4328
  }
4253
4329
  const displayValue = this.getDisplayValue();
4254
- return (h(Host, null, h("div", { class: "mrd-field__inner" }, this.renderLeafField(displayValue), this.renderHistoryEditor())));
4330
+ return (h(Host, null, h("div", { class: "mrd-field__inner" }, this.isMultiScalar() ? this.renderMultiScalarField() : this.renderLeafField(displayValue), this.renderHistoryEditor())));
4255
4331
  }
4256
4332
  get el() { return getElement(this); }
4257
4333
  static get watchers() { return {
@@ -4442,13 +4518,14 @@ const MrdFileField = class {
4442
4518
  };
4443
4519
  MrdFileField.style = mrdFileFieldCss();
4444
4520
 
4445
- 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)}`;
4521
+ 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)}.mrd-form__delete.sc-mrd-form{display:inline-flex;align-items:center;justify-content:center;height:var(--mrd-input-height);padding:0 var(--mrd-space-6);margin-right:auto;background-color:transparent;color:var(--mrd-color-danger);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-color-danger);border-radius:var(--mrd-border-radius);cursor:pointer;transition:background-color var(--mrd-transition), color var(--mrd-transition)}.mrd-form__delete.sc-mrd-form:hover{background-color:var(--mrd-color-danger-light);color:var(--mrd-color-danger-dark)}.mrd-form__delete.sc-mrd-form:focus{outline:none;box-shadow:0 0 0 3px var(--mrd-color-danger-light)}.mrd-form__delete.sc-mrd-form:active{background-color:var(--mrd-color-danger-light);border-color:var(--mrd-color-danger-dark)}`;
4446
4522
 
4447
4523
  const MrdForm = class {
4448
4524
  constructor(hostRef) {
4449
4525
  registerInstance(this, hostRef);
4450
4526
  this.mrdSubmit = createEvent(this, "mrdSubmit");
4451
4527
  this.mrdCancel = createEvent(this, "mrdCancel");
4528
+ this.mrdDelete = createEvent(this, "mrdDelete");
4452
4529
  this.mrdSearch = createEvent(this, "mrdSearch");
4453
4530
  this.mrdFetchAll = createEvent(this, "mrdFetchAll");
4454
4531
  this.mrdUpload = createEvent(this, "mrdUpload");
@@ -4475,6 +4552,11 @@ const MrdForm = class {
4475
4552
  this.referenceClass = '';
4476
4553
  /** When true, a cancel button is shown next to the submit button. */
4477
4554
  this.showCancel = false;
4555
+ /** When true, a delete button is shown next to the submit button (edit mode only —
4556
+ * the host decides when a delete affordance makes sense, e.g. only for an existing
4557
+ * record). Deletion itself (confirmation, the actual API call) is entirely the
4558
+ * host's responsibility; mrd-form only emits the request via mrdDelete. */
4559
+ this.showDelete = false;
4478
4560
  /**
4479
4561
  * The currently logged-in user, resolved by the host via /accounts/me.
4480
4562
  * Used to pre-fill RELATION fields whose defaultValue is "@me".
@@ -4762,15 +4844,11 @@ const MrdForm = class {
4762
4844
  normalizeRelationValue(value) {
4763
4845
  if (value == null || value === '')
4764
4846
  return null;
4765
- if (typeof value === 'string')
4766
- return value || null;
4767
4847
  if (Array.isArray(value)) {
4768
- return value.map(v => typeof v === 'object' && v !== null && 'id' in v ? v.id : String(v));
4769
- }
4770
- if (typeof value === 'object' && 'id' in value) {
4771
- return value.id || null;
4848
+ const hrefs = value.map(v => this.getHref(v)).filter(v => v !== '');
4849
+ return hrefs.length ? hrefs : null;
4772
4850
  }
4773
- return null;
4851
+ return this.getHref(value) || null;
4774
4852
  }
4775
4853
  deepEqual(a, b) {
4776
4854
  if (a === b)
@@ -4843,7 +4921,7 @@ const MrdForm = class {
4843
4921
  return h(Host, null);
4844
4922
  }
4845
4923
  const dir = this.locale.startsWith('ar') ? 'rtl' : 'ltr';
4846
- return (h(Host, null, h("form", { class: "mrd-form", dir: dir, onSubmit: this.handleSubmit, noValidate: true }, this.layout.title && h("h2", { class: "mrd-form__title" }, this.layout.title), h("div", { class: "mrd-form__body" }, this.renderItems(this.layout.items)), h("div", { class: "mrd-form__footer" }, h("button", { type: "submit", class: "mrd-form__submit" }, t('submit', this.locale)), this.showCancel && (h("button", { type: "button", class: "mrd-form__cancel", onClick: () => this.mrdCancel.emit() }, t('cancel', this.locale)))))));
4924
+ return (h(Host, null, h("form", { class: "mrd-form", dir: dir, onSubmit: this.handleSubmit, noValidate: true }, this.layout.title && h("h2", { class: "mrd-form__title" }, this.layout.title), h("div", { class: "mrd-form__body" }, this.renderItems(this.layout.items)), h("div", { class: "mrd-form__footer" }, this.showDelete && (h("button", { type: "button", class: "mrd-form__delete", onClick: () => this.mrdDelete.emit() }, t('delete', this.locale))), h("button", { type: "submit", class: "mrd-form__submit" }, t('submit', this.locale)), this.showCancel && (h("button", { type: "button", class: "mrd-form__cancel", onClick: () => this.mrdCancel.emit() }, t('cancel', this.locale)))))));
4847
4925
  }
4848
4926
  static get watchers() { return {
4849
4927
  "values": [{
@@ -5188,6 +5266,16 @@ function showsEmpty(item) {
5188
5266
  var _a, _b, _c, _d, _e;
5189
5267
  return (_e = (_c = (_a = item.showEmpty) !== null && _a !== void 0 ? _a : (_b = item.field) === null || _b === void 0 ? void 0 : _b.showEmpty) !== null && _c !== void 0 ? _c : (_d = item.relation) === null || _d === void 0 ? void 0 : _d.showEmpty) !== null && _e !== void 0 ? _e : false;
5190
5268
  }
5269
+ /** Whether a RELATION item has a resolvable link value (`_links[item.name]`
5270
+ * carries either a multi-value `values[]` or a single `name`). */
5271
+ function hasRelationValue(item, data) {
5272
+ var _a, _b;
5273
+ if (!item.name)
5274
+ return false;
5275
+ const links = ((_a = data === null || data === void 0 ? void 0 : data._links) !== null && _a !== void 0 ? _a : {});
5276
+ const link = links[item.name];
5277
+ return !!(((_b = link === null || link === void 0 ? void 0 : link.values) === null || _b === void 0 ? void 0 : _b.length) || (link === null || link === void 0 ? void 0 : link.name));
5278
+ }
5191
5279
  /** Depth-first flatten of the SECTION/GROUP tree. */
5192
5280
  function flattenItems(items) {
5193
5281
  const result = [];
@@ -5300,7 +5388,7 @@ function renderHistoryBadge(ctx, item, raw) {
5300
5388
  ctx.on.toggleHistory(isOpen ? null : item.name);
5301
5389
  } }, h("svg", { class: "mrd-layout-section__history-icon", viewBox: "0 0 20 20", fill: "currentColor", "aria-hidden": "true" }, h("path", { "fill-rule": "evenodd", d: "M10 18a8 8 0 100-16 8 8 0 000 16zm.75-13a.75.75 0 00-1.5 0v5c0 .207.085.394.22.53l2.5 2.5a.75.75 0 101.06-1.06L10.75 9.69V5z", "clip-rule": "evenodd" }))), isOpen && (h("div", { class: "mrd-layout-section__history-popover", role: "listbox" }, sorted.map((entry, i) => (h("div", { key: String(i), class: "mrd-layout-section__history-entry" }, entry.value, " (", t('history_until', ctx.locale), " ", formatDate(entry.until, ctx.locale), ")")))))));
5302
5390
  }
5303
- function renderField(ctx, item) {
5391
+ function fieldRenderState(ctx, item) {
5304
5392
  var _a, _b;
5305
5393
  if (!item.name)
5306
5394
  return null;
@@ -5310,10 +5398,27 @@ function renderField(ctx, item) {
5310
5398
  ? raw.current
5311
5399
  : raw;
5312
5400
  const renderedValue = renderFieldValue(ctx, item, rawValue);
5401
+ return { raw, rawValue, renderedValue, isEmpty: renderedValue == null };
5402
+ }
5403
+ /** Whether a FIELD item would render anything at all (value, or a showEmpty
5404
+ * placeholder). A `header` field always renders. Used by mrd-layout-section
5405
+ * to decide whether a preceding HEADER item's block is entirely empty. */
5406
+ function isFieldVisible(ctx, item) {
5407
+ if (item.header)
5408
+ return true;
5409
+ const state = fieldRenderState(ctx, item);
5410
+ if (!state)
5411
+ return false;
5412
+ return !state.isEmpty || showsEmpty(item);
5413
+ }
5414
+ function renderField(ctx, item) {
5415
+ const state = fieldRenderState(ctx, item);
5416
+ if (!state)
5417
+ return null;
5418
+ const { raw, rawValue, renderedValue, isEmpty } = state;
5313
5419
  if (item.header) {
5314
5420
  return (h("h1", { class: "mrd-layout-section__field-header", key: item.name }, typeof renderedValue === 'string' ? renderedValue : rawValue != null ? String(rawValue) : item.label));
5315
5421
  }
5316
- const isEmpty = renderedValue == null;
5317
5422
  if (isEmpty && !showsEmpty(item))
5318
5423
  return null;
5319
5424
  const isBlock = item.dataType === ClientLayoutItemFieldDataType.TEXTBLOCK
@@ -5322,7 +5427,7 @@ function renderField(ctx, item) {
5322
5427
  return (h("div", { class: `mrd-layout-section__field${isBlock ? ' mrd-layout-section__field--block' : ''}${isEmpty ? ' mrd-layout-section__field--empty' : ''}`, key: item.name }, h("span", { class: "mrd-layout-section__field-label" }, item.label), h("span", { class: "mrd-layout-section__field-value" }, isEmpty ? t('value_empty', ctx.locale) : renderedValue, renderHistoryBadge(ctx, item, raw))));
5323
5428
  }
5324
5429
 
5325
- const mrdLayoutSectionCss = () => `.sc-mrd-layout-section-h{display:block;width:100%}.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--block.sc-mrd-layout-section{grid-template-columns:1fr}.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__field--empty.sc-mrd-layout-section .mrd-layout-section__field-value.sc-mrd-layout-section{color:var(--mrd-color-neutral-400);font-weight:var(--mrd-font-weight-normal)}.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__file-list.sc-mrd-layout-section{display:flex;flex-direction:column;align-items:flex-start;gap:var(--mrd-space-1)}.mrd-layout-section__file-list-item.sc-mrd-layout-section{min-width:0;max-width:100%}.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__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}`;
5430
+ const mrdLayoutSectionCss = () => `.sc-mrd-layout-section-h{display:block;width:100%}.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--block.sc-mrd-layout-section{grid-template-columns:1fr}.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__field--empty.sc-mrd-layout-section .mrd-layout-section__field-value.sc-mrd-layout-section{color:var(--mrd-color-neutral-400);font-weight:var(--mrd-font-weight-normal)}.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-sm);font-weight:var(--mrd-font-weight-semibold);color:var(--mrd-color-neutral-500);letter-spacing:0.01em;margin:var(--mrd-space-5) 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__file-list.sc-mrd-layout-section{display:flex;flex-direction:column;align-items:flex-start;gap:var(--mrd-space-1)}.mrd-layout-section__file-list-item.sc-mrd-layout-section{min-width:0;max-width:100%}.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__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}`;
5326
5431
 
5327
5432
  const MrdLayoutSection = class {
5328
5433
  constructor(hostRef) {
@@ -5337,6 +5442,7 @@ const MrdLayoutSection = class {
5337
5442
  this.mrdLoadViewAggregations = createEvent(this, "mrdLoadViewAggregations");
5338
5443
  this.mrdLoadViewDistinct = createEvent(this, "mrdLoadViewDistinct");
5339
5444
  this.mrdUpdateObject = createEvent(this, "mrdUpdateObject");
5445
+ this.mrdDeleteObject = createEvent(this, "mrdDeleteObject");
5340
5446
  this.mrdViewUpload = createEvent(this, "mrdViewUpload");
5341
5447
  this.mrdCreateObject = createEvent(this, "mrdCreateObject");
5342
5448
  /** Items from one layout entry in ClientDashboardMetadata.layouts[]. */
@@ -5355,6 +5461,11 @@ const MrdLayoutSection = class {
5355
5461
  * create ("+") action and the documents view's New folder / Upload are disabled
5356
5462
  * with a tooltip explaining why, so it's clear at a glance the user can't mutate data. */
5357
5463
  this.readOnly = false;
5464
+ /** The active account's linked person record (userProfile.links.person), if any.
5465
+ * Threaded to mrd-memo-container so a top-level memo VIEW (no parent record to
5466
+ * attach a new memo to) can still offer "New memo" by falling back to the
5467
+ * account's own record as the container. */
5468
+ this.me = null;
5358
5469
  this.searchQueryMap = {};
5359
5470
  this.searchResultsMap = {};
5360
5471
  this.imagePreviewUrl = null;
@@ -5408,6 +5519,14 @@ const MrdLayoutSection = class {
5408
5519
  await table.init();
5409
5520
  }
5410
5521
  }
5522
+ // mrd-memo-container's card mode has no <mrd-table> — mrd-memo-list needs the
5523
+ // same init() call to request its first page.
5524
+ const memoLists = this.el.querySelectorAll('mrd-memo-list[data-view]');
5525
+ for (const list of Array.from(memoLists)) {
5526
+ if (typeof list.init === 'function') {
5527
+ await list.init();
5528
+ }
5529
+ }
5411
5530
  }
5412
5531
  emitLoadImages() {
5413
5532
  for (const item of flattenItems(this.items)) {
@@ -5441,12 +5560,18 @@ const MrdLayoutSection = class {
5441
5560
  return;
5442
5561
  }
5443
5562
  const table = this.el.querySelector(`mrd-table[data-view="${name}"]`);
5444
- if (!table)
5563
+ if (table) {
5564
+ if (totalElements !== undefined) {
5565
+ table.totalElements = totalElements;
5566
+ }
5567
+ await table.setPage(page, rows, hasNext);
5445
5568
  return;
5446
- if (totalElements !== undefined) {
5447
- table.totalElements = totalElements;
5448
5569
  }
5449
- await table.setPage(page, rows, hasNext);
5570
+ // Cards mode: mrd-memo-container mounts mrd-memo-list instead of mrd-table.
5571
+ const memoList = this.el.querySelector(`mrd-memo-list[data-view="${name}"]`);
5572
+ if (memoList) {
5573
+ await memoList.setPage(page, rows, hasNext);
5574
+ }
5450
5575
  }
5451
5576
  /** Inject aggregation totals into an embedded mrd-table for a VIEW or RELATED_VIEW item. */
5452
5577
  async setViewAggregations(name, data) {
@@ -5469,11 +5594,18 @@ const MrdLayoutSection = class {
5469
5594
  await list.setFileReference(uri);
5470
5595
  }
5471
5596
  /** Inject the created document's href after a file-drop create, so the
5472
- * optimistic row becomes navigable (see mrdCreateObject). */
5597
+ * optimistic row becomes navigable (see mrdCreateObject). For a memo
5598
+ * quick-create there is no optimistic row to resolve — simply reload the
5599
+ * container's current body so the new memo shows up. */
5473
5600
  async setViewCreatedObject(name, href) {
5474
5601
  const list = this.el.querySelector(`mrd-document-list[data-doclist="${name}"]`);
5475
- if (list === null || list === void 0 ? void 0 : list.setCreatedHref)
5602
+ if (list === null || list === void 0 ? void 0 : list.setCreatedHref) {
5476
5603
  await list.setCreatedHref(href);
5604
+ return;
5605
+ }
5606
+ const memoContainer = this.el.querySelector(`mrd-memo-container[data-view="${name}"]`);
5607
+ if (memoContainer === null || memoContainer === void 0 ? void 0 : memoContainer.refresh)
5608
+ await memoContainer.refresh();
5477
5609
  }
5478
5610
  /** Provide a resolved URL for an IMAGE field. Shows as thumbnail; clicking opens the lightbox. */
5479
5611
  async setImagePreview(fieldName, url) {
@@ -5520,7 +5652,7 @@ const MrdLayoutSection = class {
5520
5652
  else if (link === null || link === void 0 ? void 0 : link.name) {
5521
5653
  valueContent = makeBtn(link.href, link.name);
5522
5654
  }
5523
- const isEmpty = !valueContent;
5655
+ const isEmpty = !hasRelationValue(item, this.data);
5524
5656
  if (isEmpty && !showsEmpty(item))
5525
5657
  return null;
5526
5658
  return (h("div", { class: `mrd-layout-section__field${isEmpty ? ' mrd-layout-section__field--empty' : ''}`, key: item.name }, h("span", { class: "mrd-layout-section__field-label" }, item.label), h("span", { class: "mrd-layout-section__field-value" }, isEmpty ? t('value_empty', this.locale) : valueContent)));
@@ -5535,7 +5667,7 @@ const MrdLayoutSection = class {
5535
5667
  return (h("div", { class: "mrd-layout-section__search", key: `search-${dataClass}` }, h("div", { class: "mrd-layout-section__search-wrap" }, h("svg", { class: "mrd-layout-section__search-icon", xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 20 20", fill: "currentColor", "aria-hidden": "true" }, h("path", { "fill-rule": "evenodd", d: "M9 3.5a5.5 5.5 0 100 11 5.5 5.5 0 000-11zM2 9a7 7 0 1112.452 4.391l3.328 3.329a.75.75 0 11-1.06 1.06l-3.329-3.328A7 7 0 012 9z", "clip-rule": "evenodd" })), h("input", { class: "mrd-layout-section__search-input", type: "text", value: query, placeholder: (_c = item.label) !== null && _c !== void 0 ? _c : '', onInput: e => this.handleSearchInput(dataClass, e.target.value) })), results.length > 0 && (h("ul", { class: "mrd-layout-section__search-results" }, results.map(r => (h("li", { key: r.id, class: "mrd-layout-section__search-result" }, h("button", { class: "mrd-layout-section__search-result-btn", onClick: () => this.mrdNavigate.emit({ href: r.id, label: r.label }) }, h("span", { class: "mrd-layout-section__search-result-label" }, r.label), r.description && h("span", { class: "mrd-layout-section__search-result-desc" }, r.description)))))))));
5536
5668
  }
5537
5669
  renderRelatedView(item) {
5538
- var _a, _b, _c, _d, _e, _f, _g, _h;
5670
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
5539
5671
  const key = viewKeyFor(item);
5540
5672
  if (!key)
5541
5673
  return null;
@@ -5548,13 +5680,25 @@ const MrdLayoutSection = class {
5548
5680
  // The API publishes `archetypes` on the VIEW/RELATED_VIEW item itself
5549
5681
  // (sibling of `view`), not inside `view`.
5550
5682
  const docArchetype = resolveArchetype((_g = item.archetypes) !== null && _g !== void 0 ? _g : (_h = item.view) === null || _h === void 0 ? void 0 : _h.archetypes, ARCHETYPE_DOCUMENT);
5683
+ const memoArchetype = !docArchetype ? resolveArchetype((_j = item.archetypes) !== null && _j !== void 0 ? _j : (_k = item.view) === null || _k === void 0 ? void 0 : _k.archetypes, ARCHETYPE_MEMO) : undefined;
5551
5684
  // Canonical parent href for single-container seeding: use the RELATED_VIEW's
5552
5685
  // fromClass (base class) rather than the route class, so polymorphic subtypes
5553
5686
  // resolve to the same container the documents actually reference.
5554
5687
  const containerHref = buildContainerHref(item, selfHref, parentId);
5555
- return (h("div", { class: "mrd-layout-section__related-view", key: `view-${key}` }, showTitle && item.label && h("h3", { class: "mrd-layout-section__related-view-title" }, item.label), docArchetype
5556
- ? this.renderDocumentContainer(item, key, parentId, docArchetype, containerHref)
5557
- : this.renderTable(item, key, parentId)));
5688
+ // A memo RELATED_VIEW isn't necessarily scoped by the container relation
5689
+ // e.g. a person's dashboard can show "memos I authored" via the author
5690
+ // relation instead. inverseRelation names which relation on the memo points
5691
+ // back to this parent; only when it matches the container slot does the
5692
+ // parent's own href double as the memo's container.
5693
+ const memoContainerRelated = item.type !== ClientLayoutItemType.RELATED_VIEW
5694
+ || item.inverseRelation === ((_l = memoArchetype === null || memoArchetype === void 0 ? void 0 : memoArchetype.slots) === null || _l === void 0 ? void 0 : _l.container);
5695
+ const memoContainerHref = memoContainerRelated ? containerHref : '';
5696
+ // Distinct from memoContainerRelated: only a genuine container-scoped
5697
+ // RELATED_VIEW (a company's own memo tab) makes every card's container
5698
+ // obvious from the page itself. A top-level VIEW or an author-scoped
5699
+ // RELATED_VIEW both still need the per-card container link.
5700
+ const memoContainerImplied = item.type === ClientLayoutItemType.RELATED_VIEW && memoContainerRelated;
5701
+ return (h("div", { class: "mrd-layout-section__related-view", key: `view-${key}` }, showTitle && item.label && h("h3", { class: "mrd-layout-section__related-view-title" }, item.label), docArchetype && this.renderDocumentContainer(item, key, parentId, docArchetype, containerHref), memoArchetype && this.renderMemoContainer(item, key, parentId, memoArchetype, memoContainerHref, memoContainerRelated, !memoContainerImplied), !docArchetype && !memoArchetype && this.renderTable(item, key, parentId)));
5558
5702
  }
5559
5703
  /** Document collection view: owns the view-switch + collection actions and
5560
5704
  * swaps between the folder tree and the flat table. Events are re-emitted to
@@ -5592,6 +5736,37 @@ const MrdLayoutSection = class {
5592
5736
  this.mrdCreateObject.emit(Object.assign({ name: key }, e.detail));
5593
5737
  } }));
5594
5738
  }
5739
+ /** Memo collection view: owns the view-switch + "New memo" and swaps between
5740
+ * the card list and the flat table, mirroring renderDocumentContainer(). */
5741
+ renderMemoContainer(item, key, parentId, archetype, containerHref, containerRelated, showContainerLink) {
5742
+ var _a, _b, _c, _d;
5743
+ const labelsListItems = (_d = (_c = (_b = (_a = item.view) === null || _a === void 0 ? void 0 : _a.values) === null || _b === void 0 ? void 0 : _b.find(v => { var _a; return v.name === ((_a = archetype.slots) === null || _a === void 0 ? void 0 : _a.labels); })) === null || _c === void 0 ? void 0 : _c.listItems) !== null && _d !== void 0 ? _d : null;
5744
+ return (h("mrd-memo-container", { "data-view": key, item: item, archetype: archetype, parentId: parentId, containerHref: containerHref, containerRelated: containerRelated, showContainerLink: showContainerLink, viewKey: key, locale: this.locale, readOnly: this.readOnly, me: this.me, labelsListItems: labelsListItems, onMrdNavigate: (e) => {
5745
+ var _a;
5746
+ e.stopPropagation();
5747
+ this.mrdNavigate.emit(Object.assign(Object.assign({}, e.detail), { navigateBehaviour: (_a = item.navigateBehaviour) !== null && _a !== void 0 ? _a : ClientLayoutNavigateBehaviour.PAGE }));
5748
+ }, onMrdLoadPage: (e) => {
5749
+ e.stopPropagation();
5750
+ this.mrdLoadViewPage.emit(Object.assign({ name: key }, e.detail));
5751
+ }, onMrdLoadAggregations: (e) => {
5752
+ var _a;
5753
+ e.stopPropagation();
5754
+ this.mrdLoadViewAggregations.emit(Object.assign({ name: key, dataClass: (_a = item.dataClass) !== null && _a !== void 0 ? _a : key }, e.detail));
5755
+ }, onMrdAction: (e) => {
5756
+ var _a;
5757
+ e.stopPropagation();
5758
+ this.mrdViewAction.emit(Object.assign({ name: key, dataClass: (_a = item.dataClass) !== null && _a !== void 0 ? _a : key }, e.detail));
5759
+ }, onMrdCreateObject: (e) => {
5760
+ e.stopPropagation();
5761
+ this.mrdCreateObject.emit(Object.assign({ name: key }, e.detail));
5762
+ }, onMrdUpdateObject: (e) => {
5763
+ e.stopPropagation();
5764
+ this.mrdUpdateObject.emit(e.detail);
5765
+ }, onMrdDeleteObject: (e) => {
5766
+ e.stopPropagation();
5767
+ this.mrdDeleteObject.emit(e.detail);
5768
+ } }));
5769
+ }
5595
5770
  renderTable(item, key, parentId) {
5596
5771
  return (h("mrd-table", { "data-view": key, item: item, parentId: parentId, locale: this.locale, readOnly: this.readOnly, onMrdLoadPage: (e) => this.handleViewLoadPage(e, key), onMrdLoadAggregations: (e) => {
5597
5772
  var _a;
@@ -5621,7 +5796,26 @@ const MrdLayoutSection = class {
5621
5796
  });
5622
5797
  } }));
5623
5798
  }
5624
- renderItem(item) {
5799
+ /** Whether every FIELD/RELATION item following a HEADER (up to the next
5800
+ * HEADER/SECTION/GROUP or the end of `siblings`) would itself render
5801
+ * nothing — i.e. the HEADER would introduce an empty block. Other item
5802
+ * types (VIEW, NAVIGATE, TEXT, ...) always count as visible. */
5803
+ isHeaderBlockEmpty(siblings, index) {
5804
+ const ctx = this.fieldCtx();
5805
+ for (let i = index + 1; i < siblings.length; i++) {
5806
+ const sib = siblings[i];
5807
+ if (sib.type === ClientLayoutItemType.HEADER || sib.type === ClientLayoutItemType.SECTION || sib.type === ClientLayoutItemType.GROUP)
5808
+ break;
5809
+ if (sib.type === ClientLayoutItemType.FIELD && isFieldVisible(ctx, sib))
5810
+ return false;
5811
+ if (sib.type === ClientLayoutItemType.RELATION && (hasRelationValue(sib, this.data) || showsEmpty(sib)))
5812
+ return false;
5813
+ if (sib.type !== ClientLayoutItemType.FIELD && sib.type !== ClientLayoutItemType.RELATION)
5814
+ return false;
5815
+ }
5816
+ return true;
5817
+ }
5818
+ renderItem(item, siblings = this.items, index = -1) {
5625
5819
  var _a, _b;
5626
5820
  switch (item.type) {
5627
5821
  case ClientLayoutItemType.FIELD:
@@ -5629,6 +5823,8 @@ const MrdLayoutSection = class {
5629
5823
  case ClientLayoutItemType.RELATION:
5630
5824
  return this.renderRelation(item);
5631
5825
  case ClientLayoutItemType.HEADER:
5826
+ if (index >= 0 && this.isHeaderBlockEmpty(siblings, index))
5827
+ return null;
5632
5828
  return (h("h2", { class: "mrd-layout-section__header", key: `header-${item.label}` }, item.label));
5633
5829
  case ClientLayoutItemType.TEXT:
5634
5830
  return h("div", { class: "mrd-layout-section__text", key: `text-${item.label}`, innerHTML: (_a = item.label) !== null && _a !== void 0 ? _a : '' });
@@ -5638,7 +5834,7 @@ const MrdLayoutSection = class {
5638
5834
  return this.renderSearch(item);
5639
5835
  case ClientLayoutItemType.SECTION:
5640
5836
  case ClientLayoutItemType.GROUP:
5641
- return (h("div", { class: "mrd-layout-section__group", key: `group-${item.label}` }, item.label && h("h3", { class: "mrd-layout-section__group-title" }, item.label), ((_b = item.items) !== null && _b !== void 0 ? _b : []).map(child => this.renderItem(child))));
5837
+ return (h("div", { class: "mrd-layout-section__group", key: `group-${item.label}` }, item.label && h("h3", { class: "mrd-layout-section__group-title" }, item.label), ((_b = item.items) !== null && _b !== void 0 ? _b : []).map((child, i) => { var _a; return this.renderItem(child, (_a = item.items) !== null && _a !== void 0 ? _a : [], i); })));
5642
5838
  case ClientLayoutItemType.RELATED_VIEW:
5643
5839
  case ClientLayoutItemType.VIEW:
5644
5840
  return this.renderRelatedView(item);
@@ -5693,11 +5889,24 @@ const MrdLayoutSection = class {
5693
5889
  ...this.relatedItems().map(it => this.renderItem(it)),
5694
5890
  ];
5695
5891
  }
5892
+ /** Single-memo view: the record's own type carries commons.memo. Renders a
5893
+ * recognisable memo (title/body prominent, author/date subtle) instead of
5894
+ * generic fields, keeping any related views/searches below it. */
5895
+ renderMemoObject(archetype) {
5896
+ var _a, _b;
5897
+ const labelsListItems = (_b = (_a = this.items.find(it => { var _a; return it.name === ((_a = archetype.slots) === null || _a === void 0 ? void 0 : _a.labels); })) === null || _a === void 0 ? void 0 : _a.listItems) !== null && _b !== void 0 ? _b : null;
5898
+ return [
5899
+ h("mrd-memo-view", { archetype: archetype, data: this.data, locale: this.locale, labelsListItems: labelsListItems, onMrdNavigate: (e) => { e.stopPropagation(); this.mrdNavigate.emit(e.detail); } }),
5900
+ ...this.relatedItems().map(it => this.renderItem(it)),
5901
+ ];
5902
+ }
5696
5903
  render() {
5697
5904
  const docArchetype = resolveArchetype(this.archetypes, ARCHETYPE_DOCUMENT);
5698
5905
  const invoiceArchetype = !docArchetype ? resolveArchetype(this.archetypes, ARCHETYPE_INVOICE) : undefined;
5699
5906
  const emailArchetype = !docArchetype && !invoiceArchetype ? resolveArchetype(this.archetypes, ARCHETYPE_EMAIL) : undefined;
5700
- return (h(Host, { key: '07b1d61b170a5ae971ba54eaf775e1787dea1642' }, h("div", { key: 'd146e0542b1de11bd130eb3d36d54e4faf055309', class: "mrd-layout-section" }, docArchetype && this.renderDocumentObject(docArchetype), invoiceArchetype && this.renderInvoiceObject(invoiceArchetype), emailArchetype && this.renderEmailObject(emailArchetype), !docArchetype && !invoiceArchetype && !emailArchetype && this.items.map(item => this.renderItem(item))), this.renderImageModal()));
5907
+ const memoArchetype = !docArchetype && !invoiceArchetype && !emailArchetype ? resolveArchetype(this.archetypes, ARCHETYPE_MEMO) : undefined;
5908
+ const anyArchetype = docArchetype || invoiceArchetype || emailArchetype || memoArchetype;
5909
+ return (h(Host, { key: '057d145da172e68f84b6ff34f71ae649d6d6bf92' }, h("div", { key: 'e03a1761dc6bcd9ff54b264fee56130270bddc2f', class: "mrd-layout-section" }, docArchetype && this.renderDocumentObject(docArchetype), invoiceArchetype && this.renderInvoiceObject(invoiceArchetype), emailArchetype && this.renderEmailObject(emailArchetype), memoArchetype && this.renderMemoObject(memoArchetype), !anyArchetype && this.items.map((item, i) => this.renderItem(item, this.items, i))), this.renderImageModal()));
5701
5910
  }
5702
5911
  get el() { return getElement(this); }
5703
5912
  static get watchers() { return {
@@ -5821,97 +6030,895 @@ const MrdLongtextField = class {
5821
6030
  };
5822
6031
  MrdLongtextField.style = mrdLongtextFieldCss();
5823
6032
 
5824
- 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)}`;
6033
+ const mrdMemoContainerCss = () => `.sc-mrd-memo-container-h{display:block}.mrd-memo-container__toolbar.sc-mrd-memo-container{display:flex;align-items:center;justify-content:flex-end;gap:var(--mrd-space-2);padding:var(--mrd-space-2) 0;border-bottom:1px solid var(--mrd-color-neutral-100)}.mrd-memo-container__action.sc-mrd-memo-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-memo-container__action.sc-mrd-memo-container svg.sc-mrd-memo-container{width:1rem;height:1rem}.mrd-memo-container__action.sc-mrd-memo-container:hover:not(:disabled){background:var(--mrd-color-neutral-50);border-color:var(--mrd-color-neutral-300)}.mrd-memo-container__action.sc-mrd-memo-container:disabled{opacity:0.5;cursor:not-allowed}.mrd-memo-container__seg.sc-mrd-memo-container{display:inline-flex;gap:2px;padding:2px;background:var(--mrd-color-neutral-100);border-radius:var(--mrd-border-radius)}.mrd-memo-container__seg-btn.sc-mrd-memo-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-memo-container__seg-btn.sc-mrd-memo-container:hover{color:var(--mrd-color-neutral-800)}.mrd-memo-container__seg-btn[aria-pressed=true].sc-mrd-memo-container{background:var(--mrd-color-white);color:var(--mrd-color-primary-dark);box-shadow:var(--mrd-shadow-sm)}.mrd-memo-container__seg-btn.sc-mrd-memo-container svg.sc-mrd-memo-container{width:1rem;height:1rem}.mrd-memo-container__body.sc-mrd-memo-container{padding-top:var(--mrd-space-3)}.mrd-memo-container__modal-backdrop.sc-mrd-memo-container{position:fixed;inset:0;background:rgba(0, 0, 0, 0.6);z-index:300;display:flex;align-items:center;justify-content:center;padding:var(--mrd-space-4)}.mrd-memo-container__modal.sc-mrd-memo-container{width:100%;max-width:960px;max-height:90vh;overflow-y:auto;display:flex;flex-direction:column;gap:var(--mrd-space-4);background:var(--mrd-color-white);border-radius:var(--mrd-border-radius-md);padding:var(--mrd-space-5);box-shadow:var(--mrd-shadow-lg)}.mrd-memo-container__modal-title.sc-mrd-memo-container{font-size:var(--mrd-font-size-lg);font-weight:var(--mrd-font-weight-bold);color:var(--mrd-color-neutral-900);margin:0}.mrd-memo-container__modal-field.sc-mrd-memo-container{display:flex;flex-direction:column;gap:var(--mrd-space-1)}.mrd-memo-container__modal-error.sc-mrd-memo-container{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}.mrd-memo-container__modal-warning.sc-mrd-memo-container{margin:0;font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);color:var(--mrd-color-neutral-600)}.mrd-memo-container__modal-actions.sc-mrd-memo-container{display:flex;justify-content:flex-end;gap:var(--mrd-space-3);margin-top:var(--mrd-space-2);padding-top:var(--mrd-space-4);border-top:var(--mrd-border-width) solid var(--mrd-border-color)}.mrd-memo-container__modal-delete.sc-mrd-memo-container{display:inline-flex;align-items:center;justify-content:center;height:var(--mrd-input-height);padding:0 var(--mrd-space-6);margin-right:auto;background-color:transparent;color:var(--mrd-color-danger);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-color-danger);border-radius:var(--mrd-border-radius);cursor:pointer;transition:background-color var(--mrd-transition), color var(--mrd-transition)}.mrd-memo-container__modal-delete.sc-mrd-memo-container:hover{background-color:var(--mrd-color-danger-light);color:var(--mrd-color-danger-dark)}.mrd-memo-container__modal-delete-confirm.sc-mrd-memo-container{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-danger);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-memo-container__modal-delete-confirm.sc-mrd-memo-container:hover{background-color:var(--mrd-color-danger-dark)}.mrd-memo-container__modal-cancel.sc-mrd-memo-container{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-memo-container__modal-cancel.sc-mrd-memo-container:hover{background-color:var(--mrd-color-neutral-100);color:var(--mrd-color-neutral-800)}.mrd-memo-container__modal-submit.sc-mrd-memo-container{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-memo-container__modal-submit.sc-mrd-memo-container:hover{background-color:var(--mrd-color-primary-hover)}`;
5825
6034
 
5826
- const MrdNumberField = class {
6035
+ const MrdMemoContainer = class {
5827
6036
  constructor(hostRef) {
5828
6037
  registerInstance(this, hostRef);
5829
- this.mrdChange = createEvent(this, "mrdChange");
5830
- this.mrdBlur = createEvent(this, "mrdBlur");
5831
- this.name = '';
5832
- this.label = '';
5833
- this.value = null;
5834
- this.placeholder = '';
5835
- this.required = false;
5836
- this.disabled = false;
6038
+ this.mrdLoadPage = createEvent(this, "mrdLoadPage");
6039
+ this.mrdLoadAggregations = createEvent(this, "mrdLoadAggregations");
6040
+ this.mrdNavigate = createEvent(this, "mrdNavigate");
6041
+ this.mrdAction = createEvent(this, "mrdAction");
6042
+ this.mrdCreateObject = createEvent(this, "mrdCreateObject");
6043
+ this.mrdUpdateObject = createEvent(this, "mrdUpdateObject");
6044
+ this.mrdDeleteObject = createEvent(this, "mrdDeleteObject");
6045
+ /** The VIEW or RELATED_VIEW layout item (dataClass, fromClass, view config). */
6046
+ this.item = null;
6047
+ /** Parent record id — required for RELATED_VIEW path building. */
6048
+ this.parentId = '';
6049
+ /** Canonical parent href — set when this is a RELATED_VIEW embedded under a
6050
+ * parent record, which already gives a new memo something to attach to. */
6051
+ this.containerHref = '';
6052
+ /** False when this RELATED_VIEW's parent is related via a relation other than
6053
+ * the archetype's container slot (e.g. a person's "memos I authored" list,
6054
+ * related via `author`) — mrd-layout-section resolves this from the item's
6055
+ * `inverseRelation`. In that case the parent is not a valid container for a
6056
+ * new memo, and — unlike a top-level VIEW with no context at all — falling
6057
+ * back to `me` would be wrong too (creating a memo "on myself" from someone
6058
+ * else's authored-memos list makes no sense), so "New memo" is hidden outright. */
6059
+ this.containerRelated = true;
6060
+ /** True unless this is a container-scoped RELATED_VIEW (a company's own memo
6061
+ * tab, say) where every card's container is obviously the page you're
6062
+ * already on — forwarded to mrd-memo-list to show/hide its per-card
6063
+ * container link. A top-level VIEW or an author-scoped RELATED_VIEW both
6064
+ * still need it, since the container isn't implied by the page context. */
6065
+ this.showContainerLink = true;
6066
+ /** Lookup key used for the embedded `data-view` attribute. */
6067
+ this.viewKey = '';
5837
6068
  this.locale = navigator.language;
5838
- this.dataType = ClientLayoutItemFieldDataType.INTEGER;
5839
- this.decimalPrecision = 2;
5840
- this.displayValue = '';
5841
- this.error = '';
5842
- /** While focused the user owns the text; prop updates must not overwrite it. */
5843
- this.focused = false;
5844
- this.handleInput = (e) => {
5845
- this.displayValue = e.target.value;
6069
+ /** listItems of the FIELD bound to the `labels` slot; forwarded to whichever
6070
+ * body is mounted and used to render the dialog's label checkboxes. */
6071
+ this.labelsListItems = null;
6072
+ /** When true, this dashboard is read-only: "New memo" is disabled with a
6073
+ * tooltip, cards/rows are not clickable, and the embedded table's own
6074
+ * create action is disabled too. */
6075
+ this.readOnly = false;
6076
+ /** The active account's linked person record (userProfile.links.person), if any.
6077
+ * Used both to gate "New memo" (see effectiveContainerHref) and, on submit, to
6078
+ * fill the author slot. */
6079
+ this.me = null;
6080
+ /** Active body: card list or flat table. */
6081
+ this.mode = 'cards';
6082
+ this.dialogOpen = false;
6083
+ /** Href of the memo being edited; null while creating. */
6084
+ this.editingHref = null;
6085
+ this.dialogBody = '';
6086
+ this.dialogTitle = '';
6087
+ this.dialogLabels = [];
6088
+ this.dialogImportant = false;
6089
+ this.dialogTouched = false;
6090
+ /** True while the dialog shows the delete confirmation step in place of the
6091
+ * form fields — mirrors mrd-merge-view's MergeConfirmStep (same panel,
6092
+ * swapped content) rather than stacking a second modal. */
6093
+ this.deleteConfirmOpen = false;
6094
+ /** Whether the currently mounted body has been init()'d. Reset on every mode switch. */
6095
+ this.listInited = false;
6096
+ this.tableInited = false;
6097
+ this.escapeHandler = null;
6098
+ this.openCreate = () => {
6099
+ if (!this.canAdd)
6100
+ return;
6101
+ this.editingHref = null;
6102
+ this.dialogBody = '';
6103
+ this.dialogTitle = '';
6104
+ this.dialogLabels = [];
6105
+ this.dialogImportant = false;
6106
+ this.dialogTouched = false;
6107
+ this.deleteConfirmOpen = false;
6108
+ this.dialogOpen = true;
5846
6109
  };
5847
- this.handleBlur = (e) => {
5848
- this.focused = false;
5849
- const raw = e.target.value;
5850
- const parsed = parseLocalizedNumber(raw, this.locale);
5851
- if (this.required && (parsed === null || raw === '')) {
5852
- this.error = t('required', this.locale);
5853
- }
5854
- else if (raw !== '' && !validateNumber(parsed, this.dataType)) {
5855
- this.error = t('invalid_number', this.locale);
6110
+ /** Opens the same dialog pre-filled from an existing memo row/record —
6111
+ * triggered by clicking a card or a table row. No separate detail page. */
6112
+ this.openEdit = (row) => {
6113
+ var _a, _b;
6114
+ if (this.readOnly)
6115
+ return;
6116
+ const href = (_b = (_a = row === null || row === void 0 ? void 0 : row._links) === null || _a === void 0 ? void 0 : _a.self) === null || _b === void 0 ? void 0 : _b.href;
6117
+ if (!href)
6118
+ return;
6119
+ this.editingHref = href;
6120
+ const bodyRaw = this.slotValue(row, 'body');
6121
+ this.dialogBody = bodyRaw != null ? String(bodyRaw) : '';
6122
+ const titleRaw = this.slotValue(row, 'title');
6123
+ this.dialogTitle = titleRaw != null ? String(titleRaw) : '';
6124
+ const labelsRaw = this.slotValue(row, 'labels');
6125
+ this.dialogLabels = Array.isArray(labelsRaw)
6126
+ ? labelsRaw.map(String)
6127
+ : (labelsRaw != null && labelsRaw !== '' ? [String(labelsRaw)] : []);
6128
+ this.dialogImportant = !!this.slotValue(row, 'important');
6129
+ this.dialogTouched = false;
6130
+ this.deleteConfirmOpen = false;
6131
+ this.dialogOpen = true;
6132
+ };
6133
+ this.closeDialog = () => {
6134
+ this.dialogOpen = false;
6135
+ this.deleteConfirmOpen = false;
6136
+ };
6137
+ this.openDeleteConfirm = () => {
6138
+ this.deleteConfirmOpen = true;
6139
+ };
6140
+ this.cancelDeleteConfirm = () => {
6141
+ this.deleteConfirmOpen = false;
6142
+ };
6143
+ this.confirmDelete = () => {
6144
+ var _a;
6145
+ if (!this.editingHref)
6146
+ return;
6147
+ const href = this.editingHref;
6148
+ this.mrdDeleteObject.emit({ href });
6149
+ if (this.mode === 'cards') {
6150
+ (_a = this.listEl) === null || _a === void 0 ? void 0 : _a.removeRow(href);
5856
6151
  }
5857
6152
  else {
5858
- this.error = '';
5859
- }
5860
- if (parsed !== null && validateRequired(raw)) {
5861
- this.displayValue = this.formatForDisplay(parsed);
6153
+ this.refresh();
5862
6154
  }
5863
- this.mrdChange.emit({ name: this.name, value: parsed });
5864
- this.mrdBlur.emit({ name: this.name, value: parsed });
6155
+ this.deleteConfirmOpen = false;
6156
+ this.dialogOpen = false;
5865
6157
  };
5866
- this.handleFocus = () => {
5867
- this.focused = true;
5868
- // Drop the grouping separators while editing, but keep the locale's decimal
5869
- // separator: String(1234.56) would be re-read as 123456 where '.' groups.
5870
- const parsed = parseLocalizedNumber(this.displayValue, this.locale);
5871
- if (parsed !== null) {
5872
- this.displayValue = formatNumber(parsed, this.locale, { useGrouping: false, maximumFractionDigits: 20 });
6158
+ this.submitDialog = () => {
6159
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
6160
+ this.dialogTouched = true;
6161
+ if (!this.dialogBody.trim())
6162
+ return;
6163
+ const slots = (_b = (_a = this.archetype) === null || _a === void 0 ? void 0 : _a.slots) !== null && _b !== void 0 ? _b : {};
6164
+ if (this.editingHref) {
6165
+ // Every shown field is sent explicitly, even when cleared/unchecked —
6166
+ // this is a PATCH, so omitting a field would leave its old value intact.
6167
+ const values = { [(_c = slots.body) !== null && _c !== void 0 ? _c : 'body']: this.dialogBody };
6168
+ if (this.hasTitleSlot)
6169
+ values[(_d = slots.title) !== null && _d !== void 0 ? _d : 'title'] = this.dialogTitle.trim() || null;
6170
+ if (((_e = this.labelsListItems) !== null && _e !== void 0 ? _e : []).length)
6171
+ values[(_f = slots.labels) !== null && _f !== void 0 ? _f : 'labels'] = this.dialogLabels;
6172
+ if (this.hasImportantSlot)
6173
+ values[(_g = slots.important) !== null && _g !== void 0 ? _g : 'important'] = this.dialogImportant;
6174
+ this.mrdUpdateObject.emit({ href: this.editingHref, values });
6175
+ if (this.mode === 'cards') {
6176
+ (_h = this.listEl) === null || _h === void 0 ? void 0 : _h.patchRow(this.editingHref, values);
6177
+ }
6178
+ else {
6179
+ this.refresh();
6180
+ }
6181
+ }
6182
+ else {
6183
+ if (!this.canAdd)
6184
+ return;
6185
+ const values = {
6186
+ [(_j = slots.body) !== null && _j !== void 0 ? _j : 'body']: this.dialogBody,
6187
+ // now(), same token/format mrd-form's own defaultValue resolution uses.
6188
+ [(_k = slots.date) !== null && _k !== void 0 ? _k : 'date']: new Date().toISOString().replace(/\.\d{3}Z$/, 'Z'),
6189
+ };
6190
+ if (this.hasTitleSlot && this.dialogTitle.trim())
6191
+ values[(_l = slots.title) !== null && _l !== void 0 ? _l : 'title'] = this.dialogTitle.trim();
6192
+ if (((_m = this.labelsListItems) !== null && _m !== void 0 ? _m : []).length && this.dialogLabels.length)
6193
+ values[(_o = slots.labels) !== null && _o !== void 0 ? _o : 'labels'] = this.dialogLabels;
6194
+ if (this.hasImportantSlot && this.dialogImportant)
6195
+ values[(_p = slots.important) !== null && _p !== void 0 ? _p : 'important'] = true;
6196
+ if (this.meHref())
6197
+ values[(_q = slots.author) !== null && _q !== void 0 ? _q : 'author'] = this.meHref();
6198
+ // Always explicit — relation values are never inferred from the URL elsewhere
6199
+ // in this codebase (e.g. mrd-form's own submit payload), so don't assume it here.
6200
+ values[(_r = slots.container) !== null && _r !== void 0 ? _r : 'container'] = this.effectiveContainerHref;
6201
+ this.mrdCreateObject.emit({ path: this.buildCreatePath(), values });
5873
6202
  }
6203
+ this.dialogOpen = false;
5874
6204
  };
5875
6205
  }
5876
- componentWillLoad() {
5877
- this.syncFromValue();
5878
- }
5879
- /** Edit mode loads the record after mount, so the incoming value must re-sync. */
5880
- valueChanged() {
5881
- if (!this.focused)
5882
- this.syncFromValue();
5883
- }
5884
- localeChanged() {
5885
- if (!this.focused)
5886
- this.syncFromValue();
6206
+ disconnectedCallback() {
6207
+ this.unbindEscape();
6208
+ }
6209
+ /** Escape backs out of the delete-confirm step first (matches Cancel there),
6210
+ * or closes the whole dialog. Bound to `document` — bubbling from inside the
6211
+ * Quill editor is not reliable enough to rely on a local key handler. */
6212
+ dialogOpenChanged(open) {
6213
+ if (open) {
6214
+ this.escapeHandler = (e) => {
6215
+ if (e.key !== 'Escape')
6216
+ return;
6217
+ if (this.deleteConfirmOpen)
6218
+ this.cancelDeleteConfirm();
6219
+ else
6220
+ this.closeDialog();
6221
+ };
6222
+ document.addEventListener('keydown', this.escapeHandler);
6223
+ }
6224
+ else {
6225
+ this.unbindEscape();
6226
+ }
5887
6227
  }
5888
- syncFromValue() {
5889
- this.displayValue =
5890
- this.value !== null && this.value !== undefined ? this.formatForDisplay(this.value) : '';
6228
+ unbindEscape() {
6229
+ if (this.escapeHandler) {
6230
+ document.removeEventListener('keydown', this.escapeHandler);
6231
+ this.escapeHandler = null;
6232
+ }
5891
6233
  }
5892
- formatForDisplay(val) {
5893
- if (this.dataType === ClientLayoutItemFieldDataType.PERCENTAGE) {
5894
- return formatNumber(val, this.locale, {
5895
- minimumFractionDigits: 0,
5896
- maximumFractionDigits: this.decimalPrecision,
5897
- }) + '%';
6234
+ /** Neither body self-loads: like mrd-table, both wait for init(). mrd-layout-section
6235
+ * init()s whichever is mounted at load time via its own querySelector pass; when the
6236
+ * user switches mode here, the freshly mounted body needs the same treatment. */
6237
+ componentDidRender() {
6238
+ var _a, _b;
6239
+ if (this.mode === 'cards' && this.listEl && !this.listInited) {
6240
+ this.listInited = true;
6241
+ const list = this.listEl;
6242
+ Promise.resolve((_a = list.componentOnReady) === null || _a === void 0 ? void 0 : _a.call(list)).then(() => list.init());
5898
6243
  }
5899
- if (this.dataType === ClientLayoutItemFieldDataType.DECIMAL) {
5900
- return formatNumber(val, this.locale, {
5901
- minimumFractionDigits: this.decimalPrecision,
5902
- maximumFractionDigits: this.decimalPrecision,
5903
- });
6244
+ if (this.mode === 'table' && this.tableEl && !this.tableInited) {
6245
+ this.tableInited = true;
6246
+ const table = this.tableEl;
6247
+ Promise.resolve((_b = table.componentOnReady) === null || _b === void 0 ? void 0 : _b.call(table)).then(() => table.init());
5904
6248
  }
5905
- return formatNumber(val, this.locale, { maximumFractionDigits: 0 });
6249
+ }
6250
+ setMode(mode) {
6251
+ if (mode === this.mode)
6252
+ return;
6253
+ this.listInited = false;
6254
+ this.tableInited = false;
6255
+ this.mode = mode;
6256
+ }
6257
+ /** Re-request page 0 of whichever body is currently mounted — called by
6258
+ * mrd-layout-section after a successful mrdCreateObject, and by this
6259
+ * component itself after an edit to a table row (which has no per-row
6260
+ * optimistic-patch method the way mrd-memo-list does). */
6261
+ async refresh() {
6262
+ if (this.mode === 'cards' && this.listEl) {
6263
+ await this.listEl.init();
6264
+ }
6265
+ else if (this.mode === 'table' && this.tableEl) {
6266
+ await this.tableEl.init();
6267
+ }
6268
+ }
6269
+ /** `me` is typed as RelationSearchResult ({ id, label }) but hosts differ on
6270
+ * which shape they actually populate: this repo's own dev preview resolves
6271
+ * it via /accounts/me as a real { id, label } RelationSearchResult, while
6272
+ * content-app feeds it from userProfile.links.person, the raw API link shape
6273
+ * ({ href, name }). Both occur in practice — same dual tolerance as
6274
+ * mrd-form's own getHref(). */
6275
+ meHref() {
6276
+ var _a, _b;
6277
+ const m = this.me;
6278
+ return (_b = (_a = m === null || m === void 0 ? void 0 : m.id) !== null && _a !== void 0 ? _a : m === null || m === void 0 ? void 0 : m.href) !== null && _b !== void 0 ? _b : '';
6279
+ }
6280
+ /** Value of a value-slot: reads row[field] via the slot→field map. */
6281
+ slotValue(row, slot) {
6282
+ var _a, _b;
6283
+ const field = (_b = (_a = this.archetype) === null || _a === void 0 ? void 0 : _a.slots) === null || _b === void 0 ? void 0 : _b[slot];
6284
+ if (!field)
6285
+ return undefined;
6286
+ return row[field];
6287
+ }
6288
+ get hasTitleSlot() {
6289
+ var _a, _b;
6290
+ return !!((_b = (_a = this.archetype) === null || _a === void 0 ? void 0 : _a.slots) === null || _b === void 0 ? void 0 : _b.title);
6291
+ }
6292
+ get hasImportantSlot() {
6293
+ var _a, _b;
6294
+ return !!((_b = (_a = this.archetype) === null || _a === void 0 ? void 0 : _a.slots) === null || _b === void 0 ? void 0 : _b.important);
6295
+ }
6296
+ /** A parent record already gives a new memo somewhere to attach to (RELATED_VIEW);
6297
+ * otherwise fall back to the account's own linked person (top-level VIEW) — but
6298
+ * only when containerRelated allows it (see its doc comment). */
6299
+ get effectiveContainerHref() {
6300
+ if (!this.containerRelated)
6301
+ return '';
6302
+ return this.containerHref || this.meHref();
6303
+ }
6304
+ /** The author slot is always filled from `me` (there is no author picker in
6305
+ * the dialog), so without it there is nothing valid to create — regardless
6306
+ * of whether a parent record already supplies a container. */
6307
+ get canAdd() {
6308
+ return !this.readOnly && !!this.meHref() && !!this.effectiveContainerHref;
6309
+ }
6310
+ /** Path for creating a new memo: `/{dataClass}` for a top-level VIEW, or
6311
+ * `/{fromClass}/{parentId}/{dataClass}` when nested under a parent record. */
6312
+ buildCreatePath() {
6313
+ var _a, _b, _c, _d, _e, _f, _g;
6314
+ return buildListPath({
6315
+ isRelatedView: ((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === ClientLayoutItemType.RELATED_VIEW,
6316
+ fromClass: (_b = this.item) === null || _b === void 0 ? void 0 : _b.fromClass,
6317
+ parentId: this.parentId,
6318
+ dataClass: (_f = (_d = (_c = this.item) === null || _c === void 0 ? void 0 : _c.filterClass) !== null && _d !== void 0 ? _d : (_e = this.item) === null || _e === void 0 ? void 0 : _e.dataClass) !== null && _f !== void 0 ? _f : (_g = this.item) === null || _g === void 0 ? void 0 : _g.relatedClass,
6319
+ });
6320
+ }
6321
+ renderToolbar() {
6322
+ return (h("div", { class: "mrd-memo-container__toolbar" }, this.mode === 'cards' && (h("button", { type: "button", class: "mrd-memo-container__action", disabled: !this.canAdd, title: this.readOnly ? t('readonly_access', this.locale) : undefined, onClick: this.openCreate }, h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M12 5v14M5 12h14" })), t('memo_new', this.locale))), h("div", { class: "mrd-memo-container__seg", role: "group", "aria-label": t('doc_view_switch', this.locale) }, h("button", { class: "mrd-memo-container__seg-btn", "aria-pressed": String(this.mode === 'cards'), title: t('memo_view_cards', this.locale), "aria-label": t('memo_view_cards', this.locale), onClick: () => this.setMode('cards') }, h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("rect", { x: "3", y: "4", width: "7", height: "7", rx: "1" }), h("rect", { x: "14", y: "4", width: "7", height: "7", rx: "1" }), h("rect", { x: "3", y: "15", width: "7", height: "5", rx: "1" }), h("rect", { x: "14", y: "15", width: "7", height: "5", rx: "1" }))), h("button", { class: "mrd-memo-container__seg-btn", "aria-pressed": String(this.mode === 'table'), title: t('memo_view_table', this.locale), "aria-label": t('memo_view_table', this.locale), onClick: () => this.setMode('table') }, h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01" }))))));
6323
+ }
6324
+ renderDeleteConfirm() {
6325
+ return (h("div", null, h("h2", { class: "mrd-memo-container__modal-title" }, t('memo_delete_confirm_title', this.locale)), h("p", { class: "mrd-memo-container__modal-warning" }, t('memo_delete_confirm_body', this.locale)), h("div", { class: "mrd-memo-container__modal-actions" }, h("button", { type: "button", class: "mrd-memo-container__modal-cancel", onClick: this.cancelDeleteConfirm }, t('cancel', this.locale)), h("button", { type: "button", class: "mrd-memo-container__modal-delete-confirm", onClick: this.confirmDelete }, t('delete', this.locale)))));
6326
+ }
6327
+ renderForm() {
6328
+ var _a, _b, _c;
6329
+ const bodyMissing = this.dialogTouched && !this.dialogBody.trim();
6330
+ return [
6331
+ h("h2", { class: "mrd-memo-container__modal-title" }, t(this.editingHref ? 'memo_edit' : 'memo_new', this.locale)),
6332
+ h("div", { class: "mrd-memo-container__modal-field" }, h("mrd-textarea-field", { key: (_a = this.editingHref) !== null && _a !== void 0 ? _a : 'new', name: "body", value: this.dialogBody, required: true, autofocus: true, locale: this.locale, onMrdChange: (e) => { this.dialogBody = e.detail.value; } }), bodyMissing && h("span", { class: "mrd-memo-container__modal-error" }, t('required', this.locale))),
6333
+ this.hasTitleSlot && (h("div", { class: "mrd-memo-container__modal-field" }, h("mrd-text-field", { name: "title", label: t('memo_field_title', this.locale), value: this.dialogTitle, locale: this.locale, onMrdChange: (e) => { this.dialogTitle = e.detail.value; } }))),
6334
+ !!((_b = this.labelsListItems) !== null && _b !== void 0 ? _b : []).length && (h("div", { class: "mrd-memo-container__modal-field" }, h("mrd-list-field", { name: "labels", label: t('memo_field_labels', this.locale), value: this.dialogLabels, multiple: true, listItems: (_c = this.labelsListItems) !== null && _c !== void 0 ? _c : [], locale: this.locale, onMrdChange: (e) => {
6335
+ this.dialogLabels = Array.isArray(e.detail.value) ? e.detail.value : [e.detail.value].filter(Boolean);
6336
+ } }))),
6337
+ this.hasImportantSlot && (h("div", { class: "mrd-memo-container__modal-field" }, h("mrd-boolean-field", { name: "important", label: t('memo_important', this.locale), value: this.dialogImportant, locale: this.locale, onMrdChange: (e) => { this.dialogImportant = e.detail.value; } }))),
6338
+ h("div", { class: "mrd-memo-container__modal-actions" }, this.editingHref && (h("button", { type: "button", class: "mrd-memo-container__modal-delete", onClick: this.openDeleteConfirm }, t('delete', this.locale))), h("button", { type: "button", class: "mrd-memo-container__modal-cancel", onClick: this.closeDialog }, t('cancel', this.locale)), h("button", { type: "button", class: "mrd-memo-container__modal-submit", onClick: this.submitDialog }, t('submit', this.locale))),
6339
+ ];
6340
+ }
6341
+ renderDialog() {
6342
+ if (!this.dialogOpen)
6343
+ return null;
6344
+ return (h("div", { class: "mrd-memo-container__modal-backdrop", onClick: this.closeDialog }, h("div", { class: "mrd-memo-container__modal", onClick: (e) => e.stopPropagation() }, this.deleteConfirmOpen ? this.renderDeleteConfirm() : this.renderForm())));
6345
+ }
6346
+ renderCards() {
6347
+ return (h("mrd-memo-list", { "data-view": this.viewKey, ref: el => (this.listEl = el), item: this.item, archetype: this.archetype, parentId: this.parentId, locale: this.locale, readOnly: this.readOnly, labelsListItems: this.labelsListItems, showContainerLink: this.showContainerLink, onMrdLoadPage: (e) => {
6348
+ e.stopPropagation();
6349
+ this.mrdLoadPage.emit(e.detail);
6350
+ }, onMrdEdit: (e) => {
6351
+ e.stopPropagation();
6352
+ this.openEdit(e.detail.row);
6353
+ }, onMrdNavigate: (e) => {
6354
+ e.stopPropagation();
6355
+ this.mrdNavigate.emit(e.detail);
6356
+ } }));
6357
+ }
6358
+ renderTable() {
6359
+ return (h("mrd-table", { "data-view": this.viewKey, ref: el => (this.tableEl = el), item: this.item, parentId: this.parentId, locale: this.locale, readOnly: this.readOnly, onMrdLoadPage: (e) => {
6360
+ e.stopPropagation();
6361
+ this.mrdLoadPage.emit(e.detail);
6362
+ }, onMrdLoadAggregations: (e) => {
6363
+ e.stopPropagation();
6364
+ this.mrdLoadAggregations.emit(e.detail);
6365
+ }, onMrdRowClick: (e) => {
6366
+ e.stopPropagation();
6367
+ this.openEdit(e.detail.row);
6368
+ }, onMrdAction: (e) => {
6369
+ e.stopPropagation();
6370
+ this.mrdAction.emit(e.detail);
6371
+ } }));
5906
6372
  }
5907
6373
  render() {
5908
- const hasError = !!this.error;
5909
- const suffix = this.dataType === ClientLayoutItemFieldDataType.PERCENTAGE ? '%' :
5910
- this.dataType === ClientLayoutItemFieldDataType.DECIMAL ? '' : '';
5911
- return (h(Host, { key: '7343dbca882b5054f22de17672ac748a8e3eca11' }, h("div", { key: 'cef10b39515b48fc9c44e651910c6a0c2a847628', class: "mrd-number-field" }, h(FieldLabel, { key: '66f178cf20f1f2f0587bd9614db150d6ae63023e', base: "mrd-number-field", label: this.label, required: this.required }), h("div", { key: 'c57c22e663a570f6e5a70b07b817970f135e850c', class: "mrd-number-field__input-wrapper" }, h("input", { key: '388b20ac11fa4aaf78df124c858b579e12f53619', class: controlClass('mrd-number-field', hasError), type: "text", inputMode: "decimal", name: this.name, value: this.displayValue, placeholder: this.placeholder || (suffix ? `0${suffix}` : '0'), required: this.required, disabled: this.disabled, onInput: this.handleInput, onBlur: this.handleBlur, onFocus: this.handleFocus })), h(FieldError, { key: 'f99bb85668b047a97162ffee2582eb45dc0589ae', base: "mrd-number-field", error: this.error }))));
6374
+ return (h(Host, { key: 'a000221db6b1ba12351f38619f319b277b791f68' }, this.renderToolbar(), h("div", { key: '712951c8e391ed693bf6e4263c4f1076172b0451', class: "mrd-memo-container__body" }, this.mode === 'cards' ? this.renderCards() : this.renderTable()), this.renderDialog()));
5912
6375
  }
5913
6376
  static get watchers() { return {
5914
- "value": [{
6377
+ "dialogOpen": [{
6378
+ "dialogOpenChanged": 0
6379
+ }]
6380
+ }; }
6381
+ };
6382
+ MrdMemoContainer.style = mrdMemoContainerCss();
6383
+
6384
+ /**
6385
+ * Pure sort/filter/aggregation query logic for mrd-table.
6386
+ * No component state — everything is passed in.
6387
+ */
6388
+ const TEXT_TYPES = new Set(['TEXT', 'TEXTBLOCK', 'EMAIL', 'HYPERLINK']);
6389
+ const NUMERIC_TYPES = new Set(['INTEGER', 'DECIMAL', 'PERCENTAGE', 'CURRENCY']);
6390
+ const DATE_TYPES = new Set(['DATE', 'DATETIME', 'TIME']);
6391
+ const NO_FILTER_TYPES = new Set(['FILE', 'IMAGE']);
6392
+ /** Column types that cannot be sorted or filtered (not stored in PostgreSQL). */
6393
+ const NON_INTERACTIVE_TYPES = new Set(['LONGTEXT', 'JSON', 'FILE', 'IMAGE']);
6394
+ /** Wait this long (ms) after the user stops typing in the free-text search box
6395
+ * before firing the search request — mirrors REQUEST_DEBOUNCE_MS's purpose
6396
+ * (skip intermediate keystrokes) but is tuned for typing, not scrolling. */
6397
+ const SEARCH_DEBOUNCE_MS = 400;
6398
+ function parseDefaultSort(defaultSort) {
6399
+ var _a;
6400
+ if (!defaultSort)
6401
+ return { field: '', dir: 'asc' };
6402
+ const parts = defaultSort.split(',');
6403
+ return { field: parts[0].trim(), dir: ((_a = parts[1]) === null || _a === void 0 ? void 0 : _a.trim()) === 'desc' ? 'desc' : 'asc' };
6404
+ }
6405
+ /** Raw sort query-param value, e.g. "name" or "name,desc". */
6406
+ function buildSortParam(field, dir) {
6407
+ if (!field)
6408
+ return '';
6409
+ return dir === 'desc' ? `${field},desc` : field;
6410
+ }
6411
+ /** Query params for a page request: page + sort + filterClass + view filters + active column filters. */
6412
+ function buildTableQueryParams(opts) {
6413
+ var _a, _b;
6414
+ const p = new URLSearchParams();
6415
+ if (opts.page > 0)
6416
+ p.set('page', String(opts.page));
6417
+ if (opts.sort)
6418
+ p.set('sort', opts.sort);
6419
+ if (opts.filterClass)
6420
+ p.set('type', opts.filterClass);
6421
+ applyViewFilters(p, opts.viewFilters);
6422
+ if (opts.query)
6423
+ p.set('q', opts.query);
6424
+ for (const f of opts.activeFilters) {
6425
+ if (f.operator === 'isEmpty') {
6426
+ p.set(f.field, '');
6427
+ continue;
6428
+ }
6429
+ if (f.operator === 'isNotEmpty') {
6430
+ p.set(f.field + '_notempty', 'true');
6431
+ continue;
6432
+ }
6433
+ if (f.operator === 'startsWith') {
6434
+ p.set(f.field + '_startswith', String((_a = f.value) !== null && _a !== void 0 ? _a : ''));
6435
+ continue;
6436
+ }
6437
+ if ((_b = f.values) === null || _b === void 0 ? void 0 : _b.length) {
6438
+ p.set(f.field, f.values.join(','));
6439
+ continue;
6440
+ }
6441
+ if (f.value != null)
6442
+ p.set(f.field, String(f.value));
6443
+ if (f.from != null)
6444
+ p.set(f.field + '_from', String(f.from));
6445
+ if (f.to != null)
6446
+ p.set(f.field + '_to', String(f.to));
6447
+ }
6448
+ return p.toString();
6449
+ }
6450
+ /** Groups aggregate columns by function; null when the view has no aggregates. */
6451
+ function buildAggregationParams(columns) {
6452
+ var _a;
6453
+ const groups = { sum: [], avg: [], count: [] };
6454
+ for (const col of columns) {
6455
+ if (col.type !== 'FIELD' || !col.aggregate)
6456
+ continue;
6457
+ const fn = col.aggregate.toLowerCase();
6458
+ if (fn in groups)
6459
+ groups[fn].push((_a = col.name) !== null && _a !== void 0 ? _a : '');
6460
+ }
6461
+ const params = {};
6462
+ if (groups.sum.length)
6463
+ params.sum = groups.sum;
6464
+ if (groups.avg.length)
6465
+ params.avg = groups.avg;
6466
+ if (groups.count.length)
6467
+ params.count = groups.count;
6468
+ return Object.keys(params).length > 0 ? params : null;
6469
+ }
6470
+ /** Aggregation query string: the page-0 query params without page/sort, plus sum/avg/count. */
6471
+ function buildAggregationQs(basePageQs, columns) {
6472
+ var _a, _b, _c;
6473
+ const p = new URLSearchParams(basePageQs);
6474
+ p.delete('page');
6475
+ p.delete('sort');
6476
+ const groups = buildAggregationParams(columns);
6477
+ if ((_a = groups === null || groups === void 0 ? void 0 : groups.sum) === null || _a === void 0 ? void 0 : _a.length)
6478
+ p.set('sum', groups.sum.join(','));
6479
+ if ((_b = groups === null || groups === void 0 ? void 0 : groups.avg) === null || _b === void 0 ? void 0 : _b.length)
6480
+ p.set('avg', groups.avg.join(','));
6481
+ if ((_c = groups === null || groups === void 0 ? void 0 : groups.count) === null || _c === void 0 ? void 0 : _c.length)
6482
+ p.set('count', groups.count.join(','));
6483
+ return p.toString();
6484
+ }
6485
+ /** True when the pending filter actually constrains anything. */
6486
+ function filterHasValue(f) {
6487
+ if (f.operator === 'isEmpty' || f.operator === 'isNotEmpty')
6488
+ return true;
6489
+ if (f.values !== undefined && f.values.length > 0)
6490
+ return true;
6491
+ if (f.value != null && f.value !== '')
6492
+ return true;
6493
+ if (typeof f.value === 'boolean')
6494
+ return true;
6495
+ if (f.from != null && f.from !== '')
6496
+ return true;
6497
+ if (f.to != null && f.to !== '')
6498
+ return true;
6499
+ return false;
6500
+ }
6501
+ // ── DATETIME filters: the user edits local "YYYY-MM-DD" dates, the API stores UTC ISO ──
6502
+ /** UTC ISO string at the start (midnight) of the given local day. */
6503
+ function dateLocalToUTCStart(dateStr) {
6504
+ if (!dateStr)
6505
+ return dateStr;
6506
+ const [year, month, day] = dateStr.split('-').map(Number);
6507
+ return new Date(year, month - 1, day).toISOString().replace(/\.\d{3}Z$/, 'Z');
6508
+ }
6509
+ /** Start of the day AFTER the given local date (exclusive range end). */
6510
+ function dateLocalToUTCEndExclusive(dateStr) {
6511
+ if (!dateStr)
6512
+ return dateStr;
6513
+ const [year, month, day] = dateStr.split('-').map(Number);
6514
+ return new Date(year, month - 1, day + 1).toISOString().replace(/\.\d{3}Z$/, 'Z');
6515
+ }
6516
+ /** Stored UTC ISO string back to the local "YYYY-MM-DD" date. */
6517
+ function utcISOToLocalDate(utcStr) {
6518
+ if (!utcStr)
6519
+ return utcStr;
6520
+ const d = new Date(utcStr);
6521
+ if (isNaN(d.getTime()))
6522
+ return utcStr;
6523
+ return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
6524
+ }
6525
+ /** The stored "to" is the exclusive end (next midnight); subtract a day to recover the entered date. */
6526
+ function utcISOToLocalDateExclusiveEnd(utcStr) {
6527
+ if (!utcStr)
6528
+ return utcStr;
6529
+ const d = new Date(utcStr);
6530
+ if (isNaN(d.getTime()))
6531
+ return utcStr;
6532
+ d.setDate(d.getDate() - 1);
6533
+ return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
6534
+ }
6535
+ /** Applies the local→UTC conversion when a DATETIME filter is submitted.
6536
+ * Exact date → range covering the full local day. */
6537
+ function normalizeDatetimeFilter(f) {
6538
+ const normalized = Object.assign({}, f);
6539
+ if (f.dataType === 'DATETIME' && f.operator !== 'isEmpty' && f.operator !== 'isNotEmpty') {
6540
+ if (typeof normalized.value === 'string' && normalized.value) {
6541
+ normalized.from = dateLocalToUTCStart(normalized.value);
6542
+ normalized.to = dateLocalToUTCEndExclusive(normalized.value);
6543
+ normalized.value = undefined;
6544
+ }
6545
+ else {
6546
+ if (typeof normalized.from === 'string' && normalized.from)
6547
+ normalized.from = dateLocalToUTCStart(normalized.from);
6548
+ if (typeof normalized.to === 'string' && normalized.to)
6549
+ normalized.to = dateLocalToUTCEndExclusive(normalized.to);
6550
+ }
6551
+ }
6552
+ return normalized;
6553
+ }
6554
+ /** Converts a stored DATETIME filter back to local dates for the popup.
6555
+ * A range covering a single local day is restored to exact-date mode. */
6556
+ function datetimeFilterToDisplay(existing) {
6557
+ const display = Object.assign({}, existing);
6558
+ if (typeof display.from === 'string' && display.from)
6559
+ display.from = utcISOToLocalDate(display.from);
6560
+ if (typeof display.to === 'string' && display.to)
6561
+ display.to = utcISOToLocalDateExclusiveEnd(display.to);
6562
+ if (display.from && display.to && display.from === display.to) {
6563
+ return Object.assign(Object.assign({}, display), { value: display.from, from: undefined, to: undefined });
6564
+ }
6565
+ return display;
6566
+ }
6567
+
6568
+ const mrdMemoListCss = () => `@charset "UTF-8";.sc-mrd-memo-list-h{display:block}.mrd-memo-list.sc-mrd-memo-list{display:flex;flex-direction:column;gap:var(--mrd-space-3)}.mrd-memo-list__card.sc-mrd-memo-list{display:flex;flex-direction:column;gap:var(--mrd-space-2);width:100%;padding:var(--mrd-space-4);background:var(--mrd-color-white);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius-md);font-family:var(--mrd-font-family);text-align:left;cursor:pointer;transition:border-color var(--mrd-transition), box-shadow var(--mrd-transition)}.mrd-memo-list__card.sc-mrd-memo-list:hover{border-color:var(--mrd-color-primary);box-shadow:var(--mrd-shadow-sm, 0 1px 2px rgba(0, 0, 0, 0.06))}.mrd-memo-list__card.sc-mrd-memo-list:focus-visible{outline:none;box-shadow:var(--mrd-shadow-focus)}.mrd-memo-list__card--readonly.sc-mrd-memo-list{cursor:default}.mrd-memo-list__card--readonly.sc-mrd-memo-list:hover{border-color:var(--mrd-border-color);box-shadow:none}.mrd-memo-list__card-header.sc-mrd-memo-list{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--mrd-space-2)}.mrd-memo-list__card-title.sc-mrd-memo-list{font-size:var(--mrd-font-size-base);font-weight:var(--mrd-font-weight-semibold);color:var(--mrd-color-neutral-900)}.mrd-memo-list__card-important.sc-mrd-memo-list{display:inline-flex;flex-shrink:0;color:var(--mrd-color-warning)}.mrd-memo-list__card-important.sc-mrd-memo-list svg.sc-mrd-memo-list{width:1rem;height:1rem}.mrd-memo-list__card-body-wrap.sc-mrd-memo-list{display:flex;flex-direction:column;align-items:flex-start;gap:var(--mrd-space-1)}.mrd-memo-list__card-body.sc-mrd-memo-list{margin:0;font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-600);line-height:var(--mrd-line-height-relaxed);word-break:break-word}.mrd-memo-list__card-body.sc-mrd-memo-list p.sc-mrd-memo-list,.mrd-memo-list__card-body.sc-mrd-memo-list ul.sc-mrd-memo-list,.mrd-memo-list__card-body.sc-mrd-memo-list ol.sc-mrd-memo-list{margin:0 0 var(--mrd-space-1) 0}.mrd-memo-list__card-body--clamped.sc-mrd-memo-list{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.mrd-memo-list__card-toggle.sc-mrd-memo-list{background:none;border:none;padding:0;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);cursor:pointer}.mrd-memo-list__card-toggle.sc-mrd-memo-list:hover{text-decoration:underline}.mrd-memo-list__labels.sc-mrd-memo-list{display:flex;flex-wrap:wrap;gap:var(--mrd-space-2)}.mrd-memo-list__badge.sc-mrd-memo-list{display:inline-flex;align-items:center;height:1.25rem;padding:0 var(--mrd-space-2);border-radius:var(--mrd-border-radius-full, 999px);font-size:var(--mrd-font-size-xs);font-weight:var(--mrd-font-weight-medium)}.mrd-memo-list__badge--plain.sc-mrd-memo-list{background:var(--mrd-color-neutral-100);color:var(--mrd-color-neutral-600)}.mrd-memo-list__card-meta.sc-mrd-memo-list{display:flex;align-items:center;gap:var(--mrd-space-2);font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-400)}.mrd-memo-list__card-author.sc-mrd-memo-list+.mrd-memo-list__card-date.sc-mrd-memo-list::before{content:"·";margin-right:var(--mrd-space-2)}.mrd-memo-list__card-container.sc-mrd-memo-list{align-self:flex-start;background:none;border:none;padding:0;font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-xs);font-weight:var(--mrd-font-weight-semibold);color:var(--mrd-color-primary);cursor:pointer}.mrd-memo-list__card-container.sc-mrd-memo-list:hover{text-decoration:underline}.mrd-memo-list__empty.sc-mrd-memo-list{padding:var(--mrd-space-6);text-align:center;color:var(--mrd-color-neutral-400);font-size:var(--mrd-font-size-sm)}.mrd-memo-list__load-more.sc-mrd-memo-list{align-self:center;height:var(--mrd-input-height);padding:0 var(--mrd-space-6);background:transparent;color:var(--mrd-color-neutral-600);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);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)}.mrd-memo-list__load-more.sc-mrd-memo-list:hover:not(:disabled){background-color:var(--mrd-color-neutral-100)}.mrd-memo-list__load-more.sc-mrd-memo-list:disabled{opacity:0.6;cursor:default}`;
6569
+
6570
+ /** Plain-text length above which a card's body is clamped with a show-more toggle. */
6571
+ const BODY_PREVIEW_THRESHOLD = 220;
6572
+ const MrdMemoList = class {
6573
+ constructor(hostRef) {
6574
+ registerInstance(this, hostRef);
6575
+ this.mrdLoadPage = createEvent(this, "mrdLoadPage");
6576
+ this.mrdEdit = createEvent(this, "mrdEdit");
6577
+ this.mrdNavigate = createEvent(this, "mrdNavigate");
6578
+ /** The VIEW or RELATED_VIEW layout item (dataClass, fromClass, view config). */
6579
+ this.item = null;
6580
+ /** Parent record id — required for RELATED_VIEW path building. */
6581
+ this.parentId = '';
6582
+ /** Records per page (must match API page size). */
6583
+ this.pageSize = 20;
6584
+ this.locale = navigator.language;
6585
+ /** When true, cards are not clickable (no mrdEdit) — matches mrd-table's own
6586
+ * readOnly gating on its create action. */
6587
+ this.readOnly = false;
6588
+ /** listItems of the FIELD bound to the `labels` slot, resolved by mrd-layout-section
6589
+ * from its own items array, same reason mrd-memo-view needs it. */
6590
+ this.labelsListItems = null;
6591
+ /** False when the list is already scoped to its own container (a company's own
6592
+ * memo tab) — showing "belongs to: <this same company>" on every card there
6593
+ * would be redundant. True everywhere else (top-level VIEW, or a RELATED_VIEW
6594
+ * scoped by a different relation, e.g. a person's authored-memos list). */
6595
+ this.showContainerLink = true;
6596
+ this.rows = [];
6597
+ this.loading = false;
6598
+ this.exhausted = false;
6599
+ this.started = false;
6600
+ this.expandedHrefs = new Set();
6601
+ this.nextPage = 0;
6602
+ this.loadMore = () => {
6603
+ if (this.loading || this.exhausted)
6604
+ return;
6605
+ this.emitLoadPage(this.nextPage);
6606
+ };
6607
+ this.toggleExpanded = (e, href) => {
6608
+ e.stopPropagation();
6609
+ const next = new Set(this.expandedHrefs);
6610
+ if (next.has(href))
6611
+ next.delete(href);
6612
+ else
6613
+ next.add(href);
6614
+ this.expandedHrefs = next;
6615
+ };
6616
+ }
6617
+ buildDataPath() {
6618
+ var _a, _b, _c, _d, _e;
6619
+ return buildListPath({
6620
+ isRelatedView: ((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === 'RELATED_VIEW',
6621
+ fromClass: (_b = this.item) === null || _b === void 0 ? void 0 : _b.fromClass,
6622
+ parentId: this.parentId,
6623
+ dataClass: (_d = (_c = this.item) === null || _c === void 0 ? void 0 : _c.dataClass) !== null && _d !== void 0 ? _d : (_e = this.item) === null || _e === void 0 ? void 0 : _e.relatedClass,
6624
+ });
6625
+ }
6626
+ sortParam() {
6627
+ var _a, _b, _c;
6628
+ const { field, dir } = parseDefaultSort((_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 : '');
6629
+ return buildSortParam(field, dir);
6630
+ }
6631
+ emitLoadPage(page) {
6632
+ var _a, _b, _c;
6633
+ this.loading = true;
6634
+ this.mrdLoadPage.emit({
6635
+ page,
6636
+ sort: this.sortParam(),
6637
+ path: this.buildDataPath(),
6638
+ qs: buildTableQueryParams({
6639
+ page,
6640
+ sort: this.sortParam(),
6641
+ filterClass: (_a = this.item) === null || _a === void 0 ? void 0 : _a.filterClass,
6642
+ viewFilters: (_c = (_b = this.item) === null || _b === void 0 ? void 0 : _b.view) === null || _c === void 0 ? void 0 : _c.filter,
6643
+ activeFilters: [],
6644
+ }),
6645
+ });
6646
+ }
6647
+ /** Reset and request page 0. Call after setting all props, mirrors mrd-table.init(). */
6648
+ async init() {
6649
+ this.rows = [];
6650
+ this.loading = false;
6651
+ this.exhausted = false;
6652
+ this.started = true;
6653
+ this.nextPage = 0;
6654
+ this.emitLoadPage(0);
6655
+ }
6656
+ /** Inject the rows for a page (0-based); page 0 replaces, later pages append. */
6657
+ async setPage(pageNumber, rows, hasNext) {
6658
+ this.loading = false;
6659
+ this.rows = pageNumber === 0 ? rows : [...this.rows, ...rows];
6660
+ this.nextPage = pageNumber + 1;
6661
+ this.exhausted = hasNext !== undefined ? !hasNext : rows.length < this.pageSize;
6662
+ }
6663
+ /** Optimistically merge an edit into the matching row — mrdUpdateObject's PATCH
6664
+ * is fire-and-forget on the host side, so this is what makes an edit visible
6665
+ * immediately rather than only after the next full reload. */
6666
+ async patchRow(href, values) {
6667
+ this.rows = this.rows.map(row => { var _a, _b; return ((_b = (_a = row === null || row === void 0 ? void 0 : row._links) === null || _a === void 0 ? void 0 : _a.self) === null || _b === void 0 ? void 0 : _b.href) === href ? Object.assign(Object.assign({}, row), values) : row; });
6668
+ }
6669
+ /** Optimistically drop a deleted row — mrdDeleteObject's DELETE is fire-and-
6670
+ * forget on the host side, same reasoning as patchRow(). */
6671
+ async removeRow(href) {
6672
+ this.rows = this.rows.filter(row => { var _a, _b; return ((_b = (_a = row === null || row === void 0 ? void 0 : row._links) === null || _a === void 0 ? void 0 : _a.self) === null || _b === void 0 ? void 0 : _b.href) !== href; });
6673
+ }
6674
+ /** Value of a value-slot: reads row[field] via the slot→field map. */
6675
+ slotValue(row, slot) {
6676
+ var _a, _b;
6677
+ const field = (_b = (_a = this.archetype) === null || _a === void 0 ? void 0 : _a.slots) === null || _b === void 0 ? void 0 : _b[slot];
6678
+ if (!field)
6679
+ return undefined;
6680
+ return row[field];
6681
+ }
6682
+ /** Relation link for a relation-slot: reads row._links[field]. */
6683
+ slotLink(row, slot) {
6684
+ var _a, _b, _c;
6685
+ const field = (_b = (_a = this.archetype) === null || _a === void 0 ? void 0 : _a.slots) === null || _b === void 0 ? void 0 : _b[slot];
6686
+ if (!field)
6687
+ return undefined;
6688
+ const links = ((_c = row === null || row === void 0 ? void 0 : row._links) !== null && _c !== void 0 ? _c : {});
6689
+ return links[field];
6690
+ }
6691
+ plainTextLength(row) {
6692
+ const raw = this.slotValue(row, 'body');
6693
+ if (raw == null || raw === '')
6694
+ return 0;
6695
+ return String(raw).replace(/<[^>]*>/g, ' ').replace(/\s+/g, ' ').trim().length;
6696
+ }
6697
+ renderContainer(row) {
6698
+ if (!this.showContainerLink)
6699
+ return null;
6700
+ const link = this.slotLink(row, 'container');
6701
+ if (!(link === null || link === void 0 ? void 0 : link.href) || !link.name)
6702
+ return null;
6703
+ return (h("button", { type: "button", class: "mrd-memo-list__card-container", onClick: e => { e.stopPropagation(); this.mrdNavigate.emit({ href: link.href, label: link.name }); } }, link.name));
6704
+ }
6705
+ renderLabels(row) {
6706
+ const raw = this.slotValue(row, 'labels');
6707
+ const keys = Array.isArray(raw) ? raw.map(String) : (raw != null && raw !== '' ? [String(raw)] : []);
6708
+ if (!keys.length)
6709
+ return null;
6710
+ return (h("div", { class: "mrd-memo-list__labels" }, keys.map(key => {
6711
+ var _a, _b;
6712
+ const listItem = ((_a = this.labelsListItems) !== null && _a !== void 0 ? _a : []).find(li => li.key === key);
6713
+ const label = (_b = listItem === null || listItem === void 0 ? void 0 : listItem.label) !== null && _b !== void 0 ? _b : key;
6714
+ if ((listItem === null || listItem === void 0 ? void 0 : listItem.color) && (listItem === null || listItem === void 0 ? void 0 : listItem.backgroundColor)) {
6715
+ return (h("span", { key: key, class: "mrd-memo-list__badge", style: { color: listItem.color, backgroundColor: listItem.backgroundColor } }, label));
6716
+ }
6717
+ return h("span", { key: key, class: "mrd-memo-list__badge mrd-memo-list__badge--plain" }, label);
6718
+ })));
6719
+ }
6720
+ renderBody(row, href) {
6721
+ const raw = this.slotValue(row, 'body');
6722
+ if (raw == null || raw === '')
6723
+ return null;
6724
+ const expanded = this.expandedHrefs.has(href);
6725
+ const needsToggle = this.plainTextLength(row) > BODY_PREVIEW_THRESHOLD;
6726
+ return (h("div", { class: "mrd-memo-list__card-body-wrap" }, h("div", { class: {
6727
+ 'mrd-memo-list__card-body': true,
6728
+ 'mrd-memo-list__card-body--clamped': needsToggle && !expanded,
6729
+ }, innerHTML: purify.sanitize(String(raw)) }), needsToggle && (h("button", { type: "button", class: "mrd-memo-list__card-toggle", onClick: e => this.toggleExpanded(e, href) }, t(expanded ? 'textblock_show_less' : 'textblock_show_more', this.locale)))));
6730
+ }
6731
+ renderCard(row, index) {
6732
+ var _a, _b, _c;
6733
+ const titleRaw = this.slotValue(row, 'title');
6734
+ const title = titleRaw != null && titleRaw !== '' ? String(titleRaw) : null;
6735
+ const dateRaw = this.slotValue(row, 'date');
6736
+ const author = this.slotLink(row, 'author');
6737
+ const important = !!this.slotValue(row, 'important');
6738
+ const href = (_c = (_b = (_a = row === null || row === void 0 ? void 0 : row._links) === null || _a === void 0 ? void 0 : _a.self) === null || _b === void 0 ? void 0 : _b.href) !== null && _c !== void 0 ? _c : '';
6739
+ return (h("div", { key: href || index, class: { 'mrd-memo-list__card': true, 'mrd-memo-list__card--readonly': this.readOnly }, role: this.readOnly ? undefined : 'button', tabIndex: this.readOnly ? undefined : 0, onClick: () => {
6740
+ if (!this.readOnly)
6741
+ this.mrdEdit.emit({ row });
6742
+ }, onKeyDown: e => {
6743
+ if (this.readOnly)
6744
+ return;
6745
+ if (e.key === 'Enter' || e.key === ' ') {
6746
+ e.preventDefault();
6747
+ this.mrdEdit.emit({ row });
6748
+ }
6749
+ } }, h("div", { class: "mrd-memo-list__card-header" }, title && h("span", { class: "mrd-memo-list__card-title" }, title), important && (h("span", { class: "mrd-memo-list__card-important", title: t('memo_important', this.locale) }, h("svg", { viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true" }, h("path", { d: "M12 2l2.9 6.26L22 9.27l-5 4.87L18.18 21 12 17.27 5.82 21 7 14.14l-5-4.87 7.1-1.01z" }))))), this.renderBody(row, href), this.renderLabels(row), h("div", { class: "mrd-memo-list__card-meta" }, (author === null || author === void 0 ? void 0 : author.name) && h("span", { class: "mrd-memo-list__card-author" }, author.name), dateRaw != null && dateRaw !== '' && (h("span", { class: "mrd-memo-list__card-date" }, formatDateTime(dateRaw, this.locale)))), this.renderContainer(row)));
6750
+ }
6751
+ render() {
6752
+ return (h(Host, { key: '18294fc609b741d38f9933d3ae01d20d6dda5ec5' }, h("div", { key: 'ac6c1adc6575ae1edb2cd507c8ac31b1f28ea35c', class: "mrd-memo-list" }, this.rows.map((row, i) => this.renderCard(row, i)), this.started && !this.loading && this.rows.length === 0 && (h("div", { key: '271281b2e087f8fd55dc51b32b1fe4cce387cdcb', class: "mrd-memo-list__empty" }, t('no_results', this.locale))), !this.exhausted && this.rows.length > 0 && (h("button", { key: '24861c35323d759d69bfd4f358657fe201ca7727', type: "button", class: "mrd-memo-list__load-more", disabled: this.loading, onClick: this.loadMore }, t('load_more', this.locale))))));
6753
+ }
6754
+ };
6755
+ MrdMemoList.style = mrdMemoListCss();
6756
+
6757
+ const mrdMemoViewCss = () => `@charset "UTF-8";.sc-mrd-memo-view-h{display:block}.mrd-memo-view.sc-mrd-memo-view{max-width:720px;display:flex;flex-direction:column;gap:var(--mrd-space-3)}.mrd-memo-view__header.sc-mrd-memo-view{display:flex;align-items:baseline;flex-wrap:wrap;gap:var(--mrd-space-3)}.mrd-memo-view__title.sc-mrd-memo-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}.mrd-memo-view__important.sc-mrd-memo-view{display:inline-flex;align-items:center;gap:var(--mrd-space-1);font-size:var(--mrd-font-size-xs);font-weight:var(--mrd-font-weight-semibold);color:var(--mrd-color-warning);text-transform:uppercase;letter-spacing:0.04em}.mrd-memo-view__important.sc-mrd-memo-view svg.sc-mrd-memo-view{width:0.875rem;height:0.875rem}.mrd-memo-view__meta.sc-mrd-memo-view{display:flex;align-items:center;gap:var(--mrd-space-2);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-400)}.mrd-memo-view__meta-author.sc-mrd-memo-view{background:none;border:none;padding:0;font-family:var(--mrd-font-family);font-size:inherit;font-weight:var(--mrd-font-weight-medium);color:var(--mrd-color-neutral-500);cursor:pointer}.mrd-memo-view__meta-author.sc-mrd-memo-view:hover{color:var(--mrd-color-primary);text-decoration:underline}.mrd-memo-view__meta-date.sc-mrd-memo-view::before{content:"·";margin-right:var(--mrd-space-2)}.mrd-memo-view__meta-author.sc-mrd-memo-view+.mrd-memo-view__meta-date.sc-mrd-memo-view::before{content:"·"}.mrd-memo-view__labels.sc-mrd-memo-view{display:flex;flex-wrap:wrap;gap:var(--mrd-space-2)}.mrd-memo-view__badge.sc-mrd-memo-view{display:inline-flex;align-items:center;height:1.375rem;padding:0 var(--mrd-space-2);border-radius:var(--mrd-border-radius-full, 999px);font-size:var(--mrd-font-size-xs);font-weight:var(--mrd-font-weight-medium)}.mrd-memo-view__badge--plain.sc-mrd-memo-view{background:var(--mrd-color-neutral-100);color:var(--mrd-color-neutral-600)}.mrd-memo-view__container-link.sc-mrd-memo-view{align-self:flex-start;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}.mrd-memo-view__container-link.sc-mrd-memo-view:hover{text-decoration:underline}.mrd-memo-view__divider.sc-mrd-memo-view{height:var(--mrd-border-width);background:var(--mrd-color-neutral-200)}.mrd-memo-view__body.sc-mrd-memo-view{font-size:var(--mrd-font-size-base);color:var(--mrd-color-neutral-800);line-height:var(--mrd-line-height-relaxed);word-break:break-word}`;
6758
+
6759
+ const MrdMemoView = class {
6760
+ constructor(hostRef) {
6761
+ registerInstance(this, hostRef);
6762
+ this.mrdNavigate = createEvent(this, "mrdNavigate");
6763
+ /** The data record from the /data endpoint. Fields keyed by name; relations under `_links`. */
6764
+ this.data = {};
6765
+ this.locale = navigator.language;
6766
+ /** listItems of the FIELD bound to the `labels` slot, resolved by mrd-layout-section
6767
+ * from its own items array (archetype metadata does not publish listItems), so the
6768
+ * label badges get a real label/color instead of the raw stored key. */
6769
+ this.labelsListItems = null;
6770
+ }
6771
+ /** Value of a value-slot: reads data[field] via the slot→field map. */
6772
+ slotValue(slot) {
6773
+ var _a, _b;
6774
+ const field = (_b = (_a = this.archetype) === null || _a === void 0 ? void 0 : _a.slots) === null || _b === void 0 ? void 0 : _b[slot];
6775
+ if (!field)
6776
+ return undefined;
6777
+ return this.data[field];
6778
+ }
6779
+ /** Relation link for a relation-slot: reads data._links[field]. */
6780
+ slotLink(slot) {
6781
+ var _a, _b, _c, _d;
6782
+ const field = (_b = (_a = this.archetype) === null || _a === void 0 ? void 0 : _a.slots) === null || _b === void 0 ? void 0 : _b[slot];
6783
+ if (!field)
6784
+ return undefined;
6785
+ const links = ((_d = (_c = this.data) === null || _c === void 0 ? void 0 : _c._links) !== null && _d !== void 0 ? _d : {});
6786
+ return links[field];
6787
+ }
6788
+ renderAuthor() {
6789
+ const link = this.slotLink('author');
6790
+ if (!(link === null || link === void 0 ? void 0 : link.href) || !link.name)
6791
+ return null;
6792
+ return (h("button", { type: "button", class: "mrd-memo-view__meta-author", onClick: () => this.mrdNavigate.emit({ href: link.href, label: link.name }) }, link.name));
6793
+ }
6794
+ renderContainer() {
6795
+ const link = this.slotLink('container');
6796
+ if (!(link === null || link === void 0 ? void 0 : link.href) || !link.name)
6797
+ return null;
6798
+ return (h("button", { type: "button", class: "mrd-memo-view__container-link", onClick: () => this.mrdNavigate.emit({ href: link.href, label: link.name }) }, link.name));
6799
+ }
6800
+ renderLabels() {
6801
+ const raw = this.slotValue('labels');
6802
+ const keys = Array.isArray(raw) ? raw.map(String) : (raw != null && raw !== '' ? [String(raw)] : []);
6803
+ if (!keys.length)
6804
+ return null;
6805
+ return (h("div", { class: "mrd-memo-view__labels" }, keys.map(key => {
6806
+ var _a, _b;
6807
+ const listItem = ((_a = this.labelsListItems) !== null && _a !== void 0 ? _a : []).find(li => li.key === key);
6808
+ const label = (_b = listItem === null || listItem === void 0 ? void 0 : listItem.label) !== null && _b !== void 0 ? _b : key;
6809
+ if ((listItem === null || listItem === void 0 ? void 0 : listItem.color) && (listItem === null || listItem === void 0 ? void 0 : listItem.backgroundColor)) {
6810
+ return (h("span", { key: key, class: "mrd-memo-view__badge", style: { color: listItem.color, backgroundColor: listItem.backgroundColor } }, label));
6811
+ }
6812
+ return h("span", { key: key, class: "mrd-memo-view__badge mrd-memo-view__badge--plain" }, label);
6813
+ })));
6814
+ }
6815
+ renderBody() {
6816
+ const bodyRaw = this.slotValue('body');
6817
+ if (bodyRaw == null || bodyRaw === '')
6818
+ return null;
6819
+ return h("div", { class: "mrd-memo-view__body", innerHTML: purify.sanitize(String(bodyRaw)) });
6820
+ }
6821
+ render() {
6822
+ const titleRaw = this.slotValue('title');
6823
+ const title = titleRaw != null && titleRaw !== '' ? String(titleRaw) : null;
6824
+ const dateRaw = this.slotValue('date');
6825
+ const important = !!this.slotValue('important');
6826
+ return (h(Host, { key: '4d8ed14c54449fbcfddc94a34dcfb220338f8bba' }, h("div", { key: '0e0456277715607580e5373ada10706db1067c7d', class: "mrd-memo-view" }, h("div", { key: 'd5c548617eca9a99eb34409b2082be025cfce2f4', class: "mrd-memo-view__header" }, title && h("h1", { key: '2ecd2eae3f8fdba310679515aa2fe76e02f0c2b2', class: "mrd-memo-view__title" }, title), important && (h("span", { key: 'e5e8284310ab6040f1677bc1241d04d65784c2da', class: "mrd-memo-view__important", title: t('memo_important', this.locale) }, h("svg", { key: 'babe987244b384330533721276b5392c9fe72c5a', viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true" }, h("path", { key: '511956710ae8e440328f9e477551ba1c2d478f1a', d: "M12 2l2.9 6.26L22 9.27l-5 4.87L18.18 21 12 17.27 5.82 21 7 14.14l-5-4.87 7.1-1.01z" })), t('memo_important', this.locale)))), h("div", { key: '41c25e5376d94078debaf62121b8bdf400511d16', class: "mrd-memo-view__meta" }, this.renderAuthor(), dateRaw != null && dateRaw !== '' && (h("span", { key: 'caff8047249745ca98da77b374438e58d150ad7f', class: "mrd-memo-view__meta-date" }, formatDateTime(dateRaw, this.locale)))), this.renderLabels(), this.renderContainer(), h("div", { key: 'bfa4c55458ea19fb920338df9478006b1883e606', class: "mrd-memo-view__divider" }), this.renderBody())));
6827
+ }
6828
+ };
6829
+ MrdMemoView.style = mrdMemoViewCss();
6830
+
6831
+ 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)}`;
6832
+
6833
+ const MrdNumberField = class {
6834
+ constructor(hostRef) {
6835
+ registerInstance(this, hostRef);
6836
+ this.mrdChange = createEvent(this, "mrdChange");
6837
+ this.mrdBlur = createEvent(this, "mrdBlur");
6838
+ this.name = '';
6839
+ this.label = '';
6840
+ this.value = null;
6841
+ this.placeholder = '';
6842
+ this.required = false;
6843
+ this.disabled = false;
6844
+ this.locale = navigator.language;
6845
+ this.dataType = ClientLayoutItemFieldDataType.INTEGER;
6846
+ this.decimalPrecision = 2;
6847
+ this.displayValue = '';
6848
+ this.error = '';
6849
+ /** While focused the user owns the text; prop updates must not overwrite it. */
6850
+ this.focused = false;
6851
+ this.handleInput = (e) => {
6852
+ this.displayValue = e.target.value;
6853
+ };
6854
+ this.handleBlur = (e) => {
6855
+ this.focused = false;
6856
+ const raw = e.target.value;
6857
+ const parsed = parseLocalizedNumber(raw, this.locale);
6858
+ if (this.required && (parsed === null || raw === '')) {
6859
+ this.error = t('required', this.locale);
6860
+ }
6861
+ else if (raw !== '' && !validateNumber(parsed, this.dataType)) {
6862
+ this.error = t('invalid_number', this.locale);
6863
+ }
6864
+ else {
6865
+ this.error = '';
6866
+ }
6867
+ if (parsed !== null && validateRequired(raw)) {
6868
+ this.displayValue = this.formatForDisplay(parsed);
6869
+ }
6870
+ this.mrdChange.emit({ name: this.name, value: parsed });
6871
+ this.mrdBlur.emit({ name: this.name, value: parsed });
6872
+ };
6873
+ this.handleFocus = () => {
6874
+ this.focused = true;
6875
+ // Drop the grouping separators while editing, but keep the locale's decimal
6876
+ // separator: String(1234.56) would be re-read as 123456 where '.' groups.
6877
+ const parsed = parseLocalizedNumber(this.displayValue, this.locale);
6878
+ if (parsed !== null) {
6879
+ this.displayValue = formatNumber(parsed, this.locale, { useGrouping: false, maximumFractionDigits: 20 });
6880
+ }
6881
+ };
6882
+ }
6883
+ componentWillLoad() {
6884
+ this.syncFromValue();
6885
+ }
6886
+ /** Edit mode loads the record after mount, so the incoming value must re-sync. */
6887
+ valueChanged() {
6888
+ if (!this.focused)
6889
+ this.syncFromValue();
6890
+ }
6891
+ localeChanged() {
6892
+ if (!this.focused)
6893
+ this.syncFromValue();
6894
+ }
6895
+ syncFromValue() {
6896
+ this.displayValue =
6897
+ this.value !== null && this.value !== undefined ? this.formatForDisplay(this.value) : '';
6898
+ }
6899
+ formatForDisplay(val) {
6900
+ if (this.dataType === ClientLayoutItemFieldDataType.PERCENTAGE) {
6901
+ return formatNumber(val, this.locale, {
6902
+ minimumFractionDigits: 0,
6903
+ maximumFractionDigits: this.decimalPrecision,
6904
+ }) + '%';
6905
+ }
6906
+ if (this.dataType === ClientLayoutItemFieldDataType.DECIMAL) {
6907
+ return formatNumber(val, this.locale, {
6908
+ minimumFractionDigits: this.decimalPrecision,
6909
+ maximumFractionDigits: this.decimalPrecision,
6910
+ });
6911
+ }
6912
+ return formatNumber(val, this.locale, { maximumFractionDigits: 0 });
6913
+ }
6914
+ render() {
6915
+ const hasError = !!this.error;
6916
+ const suffix = this.dataType === ClientLayoutItemFieldDataType.PERCENTAGE ? '%' :
6917
+ this.dataType === ClientLayoutItemFieldDataType.DECIMAL ? '' : '';
6918
+ return (h(Host, { key: '7343dbca882b5054f22de17672ac748a8e3eca11' }, h("div", { key: 'cef10b39515b48fc9c44e651910c6a0c2a847628', class: "mrd-number-field" }, h(FieldLabel, { key: '66f178cf20f1f2f0587bd9614db150d6ae63023e', base: "mrd-number-field", label: this.label, required: this.required }), h("div", { key: 'c57c22e663a570f6e5a70b07b817970f135e850c', class: "mrd-number-field__input-wrapper" }, h("input", { key: '388b20ac11fa4aaf78df124c858b579e12f53619', class: controlClass('mrd-number-field', hasError), type: "text", inputMode: "decimal", name: this.name, value: this.displayValue, placeholder: this.placeholder || (suffix ? `0${suffix}` : '0'), required: this.required, disabled: this.disabled, onInput: this.handleInput, onBlur: this.handleBlur, onFocus: this.handleFocus })), h(FieldError, { key: 'f99bb85668b047a97162ffee2582eb45dc0589ae', base: "mrd-number-field", error: this.error }))));
6919
+ }
6920
+ static get watchers() { return {
6921
+ "value": [{
5915
6922
  "valueChanged": 0
5916
6923
  }],
5917
6924
  "locale": [{
@@ -6211,190 +7218,6 @@ const MrdSecretField = class {
6211
7218
  };
6212
7219
  MrdSecretField.style = mrdSecretFieldCss();
6213
7220
 
6214
- /**
6215
- * Pure sort/filter/aggregation query logic for mrd-table.
6216
- * No component state — everything is passed in.
6217
- */
6218
- const TEXT_TYPES = new Set(['TEXT', 'TEXTBLOCK', 'EMAIL', 'HYPERLINK']);
6219
- const NUMERIC_TYPES = new Set(['INTEGER', 'DECIMAL', 'PERCENTAGE', 'CURRENCY']);
6220
- const DATE_TYPES = new Set(['DATE', 'DATETIME', 'TIME']);
6221
- const NO_FILTER_TYPES = new Set(['FILE', 'IMAGE']);
6222
- /** Column types that cannot be sorted or filtered (not stored in PostgreSQL). */
6223
- const NON_INTERACTIVE_TYPES = new Set(['LONGTEXT', 'JSON', 'FILE', 'IMAGE']);
6224
- /** Wait this long (ms) after the user stops typing in the free-text search box
6225
- * before firing the search request — mirrors REQUEST_DEBOUNCE_MS's purpose
6226
- * (skip intermediate keystrokes) but is tuned for typing, not scrolling. */
6227
- const SEARCH_DEBOUNCE_MS = 400;
6228
- function parseDefaultSort(defaultSort) {
6229
- var _a;
6230
- if (!defaultSort)
6231
- return { field: '', dir: 'asc' };
6232
- const parts = defaultSort.split(',');
6233
- return { field: parts[0].trim(), dir: ((_a = parts[1]) === null || _a === void 0 ? void 0 : _a.trim()) === 'desc' ? 'desc' : 'asc' };
6234
- }
6235
- /** Raw sort query-param value, e.g. "name" or "name,desc". */
6236
- function buildSortParam(field, dir) {
6237
- if (!field)
6238
- return '';
6239
- return dir === 'desc' ? `${field},desc` : field;
6240
- }
6241
- /** Query params for a page request: page + sort + filterClass + view filters + active column filters. */
6242
- function buildTableQueryParams(opts) {
6243
- var _a, _b;
6244
- const p = new URLSearchParams();
6245
- if (opts.page > 0)
6246
- p.set('page', String(opts.page));
6247
- if (opts.sort)
6248
- p.set('sort', opts.sort);
6249
- if (opts.filterClass)
6250
- p.set('type', opts.filterClass);
6251
- applyViewFilters(p, opts.viewFilters);
6252
- if (opts.query)
6253
- p.set('q', opts.query);
6254
- for (const f of opts.activeFilters) {
6255
- if (f.operator === 'isEmpty') {
6256
- p.set(f.field, '');
6257
- continue;
6258
- }
6259
- if (f.operator === 'isNotEmpty') {
6260
- p.set(f.field + '_notempty', 'true');
6261
- continue;
6262
- }
6263
- if (f.operator === 'startsWith') {
6264
- p.set(f.field + '_startswith', String((_a = f.value) !== null && _a !== void 0 ? _a : ''));
6265
- continue;
6266
- }
6267
- if ((_b = f.values) === null || _b === void 0 ? void 0 : _b.length) {
6268
- p.set(f.field, f.values.join(','));
6269
- continue;
6270
- }
6271
- if (f.value != null)
6272
- p.set(f.field, String(f.value));
6273
- if (f.from != null)
6274
- p.set(f.field + '_from', String(f.from));
6275
- if (f.to != null)
6276
- p.set(f.field + '_to', String(f.to));
6277
- }
6278
- return p.toString();
6279
- }
6280
- /** Groups aggregate columns by function; null when the view has no aggregates. */
6281
- function buildAggregationParams(columns) {
6282
- var _a;
6283
- const groups = { sum: [], avg: [], count: [] };
6284
- for (const col of columns) {
6285
- if (col.type !== 'FIELD' || !col.aggregate)
6286
- continue;
6287
- const fn = col.aggregate.toLowerCase();
6288
- if (fn in groups)
6289
- groups[fn].push((_a = col.name) !== null && _a !== void 0 ? _a : '');
6290
- }
6291
- const params = {};
6292
- if (groups.sum.length)
6293
- params.sum = groups.sum;
6294
- if (groups.avg.length)
6295
- params.avg = groups.avg;
6296
- if (groups.count.length)
6297
- params.count = groups.count;
6298
- return Object.keys(params).length > 0 ? params : null;
6299
- }
6300
- /** Aggregation query string: the page-0 query params without page/sort, plus sum/avg/count. */
6301
- function buildAggregationQs(basePageQs, columns) {
6302
- var _a, _b, _c;
6303
- const p = new URLSearchParams(basePageQs);
6304
- p.delete('page');
6305
- p.delete('sort');
6306
- const groups = buildAggregationParams(columns);
6307
- if ((_a = groups === null || groups === void 0 ? void 0 : groups.sum) === null || _a === void 0 ? void 0 : _a.length)
6308
- p.set('sum', groups.sum.join(','));
6309
- if ((_b = groups === null || groups === void 0 ? void 0 : groups.avg) === null || _b === void 0 ? void 0 : _b.length)
6310
- p.set('avg', groups.avg.join(','));
6311
- if ((_c = groups === null || groups === void 0 ? void 0 : groups.count) === null || _c === void 0 ? void 0 : _c.length)
6312
- p.set('count', groups.count.join(','));
6313
- return p.toString();
6314
- }
6315
- /** True when the pending filter actually constrains anything. */
6316
- function filterHasValue(f) {
6317
- if (f.operator === 'isEmpty' || f.operator === 'isNotEmpty')
6318
- return true;
6319
- if (f.values !== undefined && f.values.length > 0)
6320
- return true;
6321
- if (f.value != null && f.value !== '')
6322
- return true;
6323
- if (typeof f.value === 'boolean')
6324
- return true;
6325
- if (f.from != null && f.from !== '')
6326
- return true;
6327
- if (f.to != null && f.to !== '')
6328
- return true;
6329
- return false;
6330
- }
6331
- // ── DATETIME filters: the user edits local "YYYY-MM-DD" dates, the API stores UTC ISO ──
6332
- /** UTC ISO string at the start (midnight) of the given local day. */
6333
- function dateLocalToUTCStart(dateStr) {
6334
- if (!dateStr)
6335
- return dateStr;
6336
- const [year, month, day] = dateStr.split('-').map(Number);
6337
- return new Date(year, month - 1, day).toISOString().replace(/\.\d{3}Z$/, 'Z');
6338
- }
6339
- /** Start of the day AFTER the given local date (exclusive range end). */
6340
- function dateLocalToUTCEndExclusive(dateStr) {
6341
- if (!dateStr)
6342
- return dateStr;
6343
- const [year, month, day] = dateStr.split('-').map(Number);
6344
- return new Date(year, month - 1, day + 1).toISOString().replace(/\.\d{3}Z$/, 'Z');
6345
- }
6346
- /** Stored UTC ISO string back to the local "YYYY-MM-DD" date. */
6347
- function utcISOToLocalDate(utcStr) {
6348
- if (!utcStr)
6349
- return utcStr;
6350
- const d = new Date(utcStr);
6351
- if (isNaN(d.getTime()))
6352
- return utcStr;
6353
- return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
6354
- }
6355
- /** The stored "to" is the exclusive end (next midnight); subtract a day to recover the entered date. */
6356
- function utcISOToLocalDateExclusiveEnd(utcStr) {
6357
- if (!utcStr)
6358
- return utcStr;
6359
- const d = new Date(utcStr);
6360
- if (isNaN(d.getTime()))
6361
- return utcStr;
6362
- d.setDate(d.getDate() - 1);
6363
- return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
6364
- }
6365
- /** Applies the local→UTC conversion when a DATETIME filter is submitted.
6366
- * Exact date → range covering the full local day. */
6367
- function normalizeDatetimeFilter(f) {
6368
- const normalized = Object.assign({}, f);
6369
- if (f.dataType === 'DATETIME' && f.operator !== 'isEmpty' && f.operator !== 'isNotEmpty') {
6370
- if (typeof normalized.value === 'string' && normalized.value) {
6371
- normalized.from = dateLocalToUTCStart(normalized.value);
6372
- normalized.to = dateLocalToUTCEndExclusive(normalized.value);
6373
- normalized.value = undefined;
6374
- }
6375
- else {
6376
- if (typeof normalized.from === 'string' && normalized.from)
6377
- normalized.from = dateLocalToUTCStart(normalized.from);
6378
- if (typeof normalized.to === 'string' && normalized.to)
6379
- normalized.to = dateLocalToUTCEndExclusive(normalized.to);
6380
- }
6381
- }
6382
- return normalized;
6383
- }
6384
- /** Converts a stored DATETIME filter back to local dates for the popup.
6385
- * A range covering a single local day is restored to exact-date mode. */
6386
- function datetimeFilterToDisplay(existing) {
6387
- const display = Object.assign({}, existing);
6388
- if (typeof display.from === 'string' && display.from)
6389
- display.from = utcISOToLocalDate(display.from);
6390
- if (typeof display.to === 'string' && display.to)
6391
- display.to = utcISOToLocalDateExclusiveEnd(display.to);
6392
- if (display.from && display.to && display.from === display.to) {
6393
- return Object.assign(Object.assign({}, display), { value: display.from, from: undefined, to: undefined });
6394
- }
6395
- return display;
6396
- }
6397
-
6398
7221
  /**
6399
7222
  * Stateless render parts of mrd-table. All state and handlers stay in the
6400
7223
  * component; these components receive plain values and callbacks.
@@ -7272,16 +8095,19 @@ const MrdTable = class {
7272
8095
  });
7273
8096
  }
7274
8097
  buildActionDetail(action, basicType) {
7275
- var _a, _b, _c;
8098
+ var _a;
7276
8099
  if (action === 'export') {
7277
8100
  return { action, path: this.buildExcelPath(), qs: this.buildQueryParams(0) };
7278
8101
  }
7279
8102
  if (action === 'create') {
7280
8103
  const v = this.allViews[this.activeViewIdx];
7281
- const parentPath = ((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === 'RELATED_VIEW'
7282
- ? `/${(_b = v === null || v === void 0 ? void 0 : v.fromClass) !== null && _b !== void 0 ? _b : ''}/${this.parentId}`
7283
- : null;
7284
- return Object.assign({ action, dataClass: (_c = v === null || v === void 0 ? void 0 : v.dataClass) !== null && _c !== void 0 ? _c : '', parentPath }, (basicType ? { basicType } : {}));
8104
+ return buildCreateActionDetail({
8105
+ isRelatedView: ((_a = this.item) === null || _a === void 0 ? void 0 : _a.type) === 'RELATED_VIEW',
8106
+ fromClass: v === null || v === void 0 ? void 0 : v.fromClass,
8107
+ parentId: this.parentId,
8108
+ dataClass: v === null || v === void 0 ? void 0 : v.dataClass,
8109
+ basicType,
8110
+ });
7285
8111
  }
7286
8112
  return { action };
7287
8113
  }
@@ -7973,12 +8799,29 @@ const MrdTextareaField = class {
7973
8799
  this.required = false;
7974
8800
  this.disabled = false;
7975
8801
  this.locale = navigator.language;
8802
+ /** Focus the editor as soon as it's ready — opt-in, since auto-focusing every
8803
+ * textarea field on mount would be wrong for a regular multi-field form. */
8804
+ this.autofocus = false;
7976
8805
  this.error = '';
7977
8806
  this.editorReady = false;
7978
8807
  }
7979
8808
  componentDidLoad() {
7980
8809
  this.initQuill();
7981
8810
  }
8811
+ /** The host may reuse the same element for a different record (e.g. mrd-memo-
8812
+ * container's quick-create/edit dialog editing a second memo without the
8813
+ * dialog itself remounting) — Quill only reads `value` once at construction,
8814
+ * so re-apply it here when it changes to something the editor doesn't already
8815
+ * hold. Guarded against our own emitted mrdChange feeding back in as a no-op. */
8816
+ valueChanged(newValue) {
8817
+ if (!this.editorReady || !this.quill)
8818
+ return;
8819
+ if (newValue === this.getSanitizedHtml())
8820
+ return;
8821
+ this.quill.setText('');
8822
+ if (newValue)
8823
+ this.quill.clipboard.dangerouslyPasteHTML(newValue);
8824
+ }
7982
8825
  async initQuill() {
7983
8826
  try {
7984
8827
  // Dynamically import Quill
@@ -8000,6 +8843,7 @@ const MrdTextareaField = class {
8000
8843
  ],
8001
8844
  },
8002
8845
  });
8846
+ this.quill = quill;
8003
8847
  if (this.value) {
8004
8848
  quill.clipboard.dangerouslyPasteHTML(this.value);
8005
8849
  }
@@ -8015,6 +8859,8 @@ const MrdTextareaField = class {
8015
8859
  }
8016
8860
  });
8017
8861
  this.editorReady = true;
8862
+ if (this.autofocus)
8863
+ quill.focus();
8018
8864
  }
8019
8865
  catch (err) {
8020
8866
  console.error('Failed to load Quill editor:', err);
@@ -8026,9 +8872,14 @@ const MrdTextareaField = class {
8026
8872
  return purify.sanitize(html);
8027
8873
  }
8028
8874
  render() {
8029
- return (h(Host, { key: 'e132531881f68f373e700617aac8033c8ebccb47' }, h("div", { key: 'fec0cf56cd7868d3fcd5a4e8a382b2dcdb6e5c50', class: "mrd-textarea-field" }, h(FieldLabel, { key: '333aa2ff57cce9e3178f0c4be4a1df1077884248', base: "mrd-textarea-field", label: this.label, required: this.required }), h("div", { key: '40025207580eb5768981b85aaa0a8ff95fce7234', class: controlClass('mrd-textarea-field', !!this.error, 'container') }, h("div", { key: '621987b3b2b1d8b4836bff065075ba527a82db81', class: "mrd-textarea-field__editor" })), h(FieldError, { key: 'ac2d8de22f008cd1c91842137ccd0cd36eb9ce19', base: "mrd-textarea-field", error: this.error }))));
8875
+ return (h(Host, { key: '5dad54667601fce064107311e741e4e0dad94298' }, h("div", { key: 'bd7bd538155ec3172fa8cc1cf4cf66ad23d07a3b', class: "mrd-textarea-field" }, h(FieldLabel, { key: 'a3fe2c714340bbdcd3521e9782f87f3773c65e62', base: "mrd-textarea-field", label: this.label, required: this.required }), h("div", { key: 'a7a628f94bc628fd358c7fc876ee1bdd2c7ef520', class: controlClass('mrd-textarea-field', !!this.error, 'container') }, h("div", { key: '30ecd27d9e928094178f8f011524ff5633cb875e', class: "mrd-textarea-field__editor" })), h(FieldError, { key: '589d5cbf28c3ae1bdbe5f663aaf6cae840bdcffe', base: "mrd-textarea-field", error: this.error }))));
8030
8876
  }
8031
8877
  get el() { return getElement(this); }
8878
+ static get watchers() { return {
8879
+ "value": [{
8880
+ "valueChanged": 0
8881
+ }]
8882
+ }; }
8032
8883
  };
8033
8884
  MrdTextareaField.style = mrdTextareaFieldCss();
8034
8885
 
@@ -8062,4 +8913,4 @@ const MrdTimeField = class {
8062
8913
  };
8063
8914
  MrdTimeField.style = mrdTimeFieldCss();
8064
8915
 
8065
- export { MrdBooleanField as mrd_boolean_field, MrdCurrencyField as mrd_currency_field, MrdDateField as mrd_date_field, MrdDatetimeField as mrd_datetime_field, MrdDocumentContainer as mrd_document_container, MrdDocumentList as mrd_document_list, MrdDocumentView as mrd_document_view, MrdEmailField as mrd_email_field, MrdEmailView as mrd_email_view, MrdField as mrd_field, MrdFileField as mrd_file_field, MrdForm as mrd_form, MrdHyperlinkField as mrd_hyperlink_field, MrdImageField as mrd_image_field, MrdInvoiceView as mrd_invoice_view, MrdLayoutSection as mrd_layout_section, MrdListField as mrd_list_field, MrdLongtextField as mrd_longtext_field, MrdNumberField as mrd_number_field, MrdRelationField as mrd_relation_field, MrdSecretField as mrd_secret_field, MrdTable as mrd_table, MrdTextField as mrd_text_field, MrdTextareaField as mrd_textarea_field, MrdTimeField as mrd_time_field };
8916
+ export { MrdBooleanField as mrd_boolean_field, MrdCurrencyField as mrd_currency_field, MrdDateField as mrd_date_field, MrdDatetimeField as mrd_datetime_field, MrdDocumentContainer as mrd_document_container, MrdDocumentList as mrd_document_list, MrdDocumentView as mrd_document_view, MrdEmailField as mrd_email_field, MrdEmailView as mrd_email_view, MrdField as mrd_field, MrdFileField as mrd_file_field, MrdForm as mrd_form, MrdHyperlinkField as mrd_hyperlink_field, MrdImageField as mrd_image_field, MrdInvoiceView as mrd_invoice_view, MrdLayoutSection as mrd_layout_section, MrdListField as mrd_list_field, MrdLongtextField as mrd_longtext_field, MrdMemoContainer as mrd_memo_container, MrdMemoList as mrd_memo_list, MrdMemoView as mrd_memo_view, MrdNumberField as mrd_number_field, MrdRelationField as mrd_relation_field, MrdSecretField as mrd_secret_field, MrdTable as mrd_table, MrdTextField as mrd_text_field, MrdTextareaField as mrd_textarea_field, MrdTimeField as mrd_time_field };