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