@mmlogic/components 0.3.8 → 0.3.9

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 (77) hide show
  1. package/dist/cjs/index.cjs.js +13 -0
  2. package/dist/cjs/loader.cjs.js +1 -1
  3. package/dist/cjs/mosterdcomponents.cjs.js +1 -1
  4. package/dist/cjs/{mrd-boolean-field_20.cjs.entry.js → mrd-boolean-field_22.cjs.entry.js} +504 -23
  5. package/dist/collection/collection-manifest.json +2 -0
  6. package/dist/collection/components/mrd-boolean-field/mrd-boolean-field.js +1 -1
  7. package/dist/collection/components/mrd-currency-field/mrd-currency-field.js +1 -1
  8. package/dist/collection/components/mrd-date-field/mrd-date-field.js +1 -1
  9. package/dist/collection/components/mrd-datetime-field/mrd-datetime-field.js +1 -1
  10. package/dist/collection/components/mrd-document-list/mrd-document-list.js +578 -0
  11. package/dist/collection/components/mrd-document-list/mrd-document-list.scss +126 -0
  12. package/dist/collection/components/mrd-document-view/mrd-document-view.js +177 -0
  13. package/dist/collection/components/mrd-document-view/mrd-document-view.scss +121 -0
  14. package/dist/collection/components/mrd-email-field/mrd-email-field.js +1 -1
  15. package/dist/collection/components/mrd-file-field/mrd-file-field.js +1 -1
  16. package/dist/collection/components/mrd-image-field/mrd-image-field.js +1 -1
  17. package/dist/collection/components/mrd-layout-section/mrd-layout-section.js +153 -15
  18. package/dist/collection/components/mrd-layout-section/mrd-layout-section.scss +46 -3
  19. package/dist/collection/components/mrd-longtext-field/mrd-longtext-field.js +1 -1
  20. package/dist/collection/components/mrd-number-field/mrd-number-field.js +1 -1
  21. package/dist/collection/components/mrd-secret-field/mrd-secret-field.js +2 -2
  22. package/dist/collection/components/mrd-text-field/mrd-text-field.js +1 -1
  23. package/dist/collection/components/mrd-textarea-field/mrd-textarea-field.js +1 -1
  24. package/dist/collection/components/mrd-time-field/mrd-time-field.js +1 -1
  25. package/dist/collection/dev/app.js +19 -2
  26. package/dist/collection/types/client-layout.js +10 -0
  27. package/dist/collection/utils/i18n.js +24 -0
  28. package/dist/components/client-layout.js +1 -1
  29. package/dist/components/format.js +1 -1
  30. package/dist/components/i18n.js +1 -1
  31. package/dist/components/index.js +1 -1
  32. package/dist/components/mrd-boolean-field2.js +1 -1
  33. package/dist/components/mrd-currency-field2.js +1 -1
  34. package/dist/components/mrd-date-field2.js +1 -1
  35. package/dist/components/mrd-datetime-field2.js +1 -1
  36. package/dist/components/mrd-document-list.d.ts +11 -0
  37. package/dist/components/mrd-document-list.js +1 -0
  38. package/dist/components/mrd-document-list2.js +1 -0
  39. package/dist/components/mrd-document-view.d.ts +11 -0
  40. package/dist/components/mrd-document-view.js +1 -0
  41. package/dist/components/mrd-document-view2.js +1 -0
  42. package/dist/components/mrd-email-field2.js +1 -1
  43. package/dist/components/mrd-file-field2.js +1 -1
  44. package/dist/components/mrd-image-field2.js +1 -1
  45. package/dist/components/mrd-layout-section.js +1 -1
  46. package/dist/components/mrd-longtext-field2.js +1 -1
  47. package/dist/components/mrd-number-field2.js +1 -1
  48. package/dist/components/mrd-secret-field2.js +1 -1
  49. package/dist/components/mrd-table2.js +1 -1
  50. package/dist/components/mrd-text-field2.js +1 -1
  51. package/dist/components/mrd-textarea-field2.js +1 -1
  52. package/dist/components/mrd-time-field2.js +1 -1
  53. package/dist/esm/index.js +11 -1
  54. package/dist/esm/loader.js +1 -1
  55. package/dist/esm/mosterdcomponents.js +1 -1
  56. package/dist/esm/{mrd-boolean-field_20.entry.js → mrd-boolean-field_22.entry.js} +504 -25
  57. package/dist/mosterdcomponents/index.esm.js +1 -1
  58. package/dist/mosterdcomponents/mosterdcomponents.css +1 -1
  59. package/dist/mosterdcomponents/mosterdcomponents.esm.js +1 -1
  60. package/dist/mosterdcomponents/p-b547291b.entry.js +1 -0
  61. package/dist/types/components/mrd-document-list/mrd-document-list.d.ts +108 -0
  62. package/dist/types/components/mrd-document-view/mrd-document-view.d.ts +36 -0
  63. package/dist/types/components/mrd-layout-section/mrd-layout-section.d.ts +33 -6
  64. package/dist/types/components.d.ts +290 -15
  65. package/dist/types/types/client-layout.d.ts +38 -0
  66. package/package.json +1 -1
  67. package/dist/mosterdcomponents/cell-renderer-CbRwLOo8.js.map +0 -1
  68. package/dist/mosterdcomponents/client-layout-D88nn5zf.js.map +0 -1
  69. package/dist/mosterdcomponents/format-BAfsQfy1.js.map +0 -1
  70. package/dist/mosterdcomponents/i18n-hoGGKbKU.js.map +0 -1
  71. package/dist/mosterdcomponents/index-6yQUNVww.js.map +0 -1
  72. package/dist/mosterdcomponents/index-I5SuYv7a.js.map +0 -1
  73. package/dist/mosterdcomponents/index.esm.js.map +0 -1
  74. package/dist/mosterdcomponents/mosterdcomponents.esm.js.map +0 -1
  75. package/dist/mosterdcomponents/p-7bfaee51.entry.js +0 -1
  76. package/dist/mosterdcomponents/quill-C9pgw_k-.js.map +0 -1
  77. package/dist/mosterdcomponents/validation-ixb43cqU.js.map +0 -1
@@ -1,9 +1,11 @@
1
1
  {
2
2
  "entries": [
3
+ "components/mrd-document-list/mrd-document-list.js",
3
4
  "components/mrd-boolean-field/mrd-boolean-field.js",
4
5
  "components/mrd-currency-field/mrd-currency-field.js",
5
6
  "components/mrd-date-field/mrd-date-field.js",
6
7
  "components/mrd-datetime-field/mrd-datetime-field.js",
8
+ "components/mrd-document-view/mrd-document-view.js",
7
9
  "components/mrd-email-field/mrd-email-field.js",
8
10
  "components/mrd-field/mrd-field.js",
9
11
  "components/mrd-file-field/mrd-file-field.js",
@@ -20,7 +20,7 @@ export class MrdBooleanField {
20
20
  this.checked = !!this.value;
21
21
  }
22
22
  render() {
23
- return (h(Host, { key: 'aed1d936d686870114a12aad9fc4cccb76ecd31e' }, h("div", { key: '5cc8aaa0f12d4195d02fce8a810d7d993e2e8c99', class: "mrd-boolean-field" }, h("label", { key: '41c3b3e0f01778fc2654ba86e3fe4e5a07c8537a', class: "mrd-boolean-field__toggle-label" }, h("input", { key: 'c261e6903e050d2f3d8df8abb90c74d99ed20161', class: "mrd-boolean-field__checkbox", type: "checkbox", name: this.name, checked: this.checked, disabled: this.disabled, onChange: this.handleChange, onBlur: this.handleBlur }), h("span", { key: '079ee220fe692536af15a7fb4286626102ae940e', class: "mrd-boolean-field__toggle", "aria-hidden": "true" }), this.label && (h("span", { key: '1f4f52a41f0bd6ba4c61cf9d4db74ab2f1aa8877', class: `mrd-boolean-field__text${this.required ? ' mrd-boolean-field__text--required' : ''}` }, this.label))))));
23
+ return (h(Host, { key: '38e65a1c7971912f8259d09281b272d7cbd446f2' }, h("div", { key: 'e10919998731d744cc2a13130c5f355c9b8fc9aa', class: "mrd-boolean-field" }, h("label", { key: 'db85a2c80cc62fdfd25237e3f5c7750bf1666819', class: "mrd-boolean-field__toggle-label" }, h("input", { key: 'cddd7004593fa4671abb89f4f805c4a009db99ef', class: "mrd-boolean-field__checkbox", type: "checkbox", name: this.name, checked: this.checked, disabled: this.disabled, onChange: this.handleChange, onBlur: this.handleBlur }), h("span", { key: 'f90f0ed6d74d6688e51b8d85a5397a0597d95ad8', class: "mrd-boolean-field__toggle", "aria-hidden": "true" }), this.label && (h("span", { key: '7e4582b1d9a5b08c00c220bec53baa6c14cbfe43', class: `mrd-boolean-field__text${this.required ? ' mrd-boolean-field__text--required' : ''}` }, this.label))))));
24
24
  }
25
25
  static get is() { return "mrd-boolean-field"; }
26
26
  static get encapsulation() { return "scoped"; }
@@ -48,7 +48,7 @@ export class MrdCurrencyField {
48
48
  }
49
49
  render() {
50
50
  const hasError = !!this.error;
51
- return (h(Host, { key: 'd3450e9c26b1a755d3e6a5a3561d93b2ac566a28' }, h("div", { key: 'b66942cc1953daff728504deef8a9cc1330ef549', class: "mrd-currency-field" }, this.label && (h("label", { key: '3d3f2f06e9ffea944552f0f7cf3150d0246c54f0', class: `mrd-currency-field__label${this.required ? ' mrd-currency-field__label--required' : ''}` }, this.label)), h("div", { key: 'd30a2adfceefdbefef2d4fe6633a163a753b15d0', class: "mrd-currency-field__row" }, h("input", { key: '9af09b19b6cbe24498d6ca8edf7b28f675afdec5', class: `mrd-currency-field__amount${hasError ? ' mrd-currency-field__amount--error' : ''}`, type: "text", inputMode: "decimal", name: `${this.name}_amount`, value: this.amountDisplay, placeholder: "0.00", required: this.required, disabled: this.disabled, onInput: this.handleAmountInput, onBlur: this.handleAmountBlur }), h("select", { key: '21e55b04b7bf16586b5cfaa82d77db45c6dedf21', class: "mrd-currency-field__currency", disabled: this.disabled, onChange: this.handleCurrencyChange }, COMMON_CURRENCIES.map(c => (h("option", { key: c, value: c, selected: c === this.currency }, c))))), hasError && h("span", { key: '7a0006d4230557cf9c58f82f21de73b5d12f7e17', class: "mrd-currency-field__error" }, this.error))));
51
+ return (h(Host, { key: 'fe3520c44d831caf36b388cb5968a9518b16cb8b' }, h("div", { key: '50c1fd2d53038e46da575d3e46e1ec26c2da423b', class: "mrd-currency-field" }, this.label && (h("label", { key: 'a2649d41bf6e3765c8a62ba6559c64c41615027a', class: `mrd-currency-field__label${this.required ? ' mrd-currency-field__label--required' : ''}` }, this.label)), h("div", { key: '952b51f315b4a5c05a8373ce3a3f1041086ba8b8', class: "mrd-currency-field__row" }, h("input", { key: '137a72ffc5d79fc8e0a8cf44c012d84a50c26d5b', class: `mrd-currency-field__amount${hasError ? ' mrd-currency-field__amount--error' : ''}`, type: "text", inputMode: "decimal", name: `${this.name}_amount`, value: this.amountDisplay, placeholder: "0.00", required: this.required, disabled: this.disabled, onInput: this.handleAmountInput, onBlur: this.handleAmountBlur }), h("select", { key: '1755854ca9b76dc4b41ad84b6b788685931ace36', class: "mrd-currency-field__currency", disabled: this.disabled, onChange: this.handleCurrencyChange }, COMMON_CURRENCIES.map(c => (h("option", { key: c, value: c, selected: c === this.currency }, c))))), hasError && h("span", { key: '0f10eb98c2e6444651d79d1de92acd0dbcc7133b', class: "mrd-currency-field__error" }, this.error))));
52
52
  }
53
53
  static get is() { return "mrd-currency-field"; }
54
54
  static get encapsulation() { return "scoped"; }
@@ -27,7 +27,7 @@ export class MrdDateField {
27
27
  }
28
28
  render() {
29
29
  const hasError = !!this.error;
30
- return (h(Host, { key: '84c777fc68a95e0b1ceb08d61e3af7afa199ce94' }, h("div", { key: '6653d94ab79c74342ce792792547018e4464a814', class: "mrd-date-field" }, this.label && (h("label", { key: '2fa7b7ec50c784f9410ca48b93d50e39dc6e0bee', class: `mrd-date-field__label${this.required ? ' mrd-date-field__label--required' : ''}` }, this.label)), h("input", { key: 'f79ebbaf0e28ad7668a5400d1df514b66457b72d', class: `mrd-date-field__input${hasError ? ' mrd-date-field__input--error' : ''}`, type: "date", name: this.name, value: this.value, required: this.required, disabled: this.disabled, onChange: this.handleChange, onBlur: this.handleBlur }), hasError && h("span", { key: 'e52f0b720d76e8ba0586fb40395b6875860762db', class: "mrd-date-field__error" }, this.error))));
30
+ return (h(Host, { key: '2c0dc2311068a5c759fe8efe58a98a71a9cf4b7b' }, h("div", { key: 'ee1cc0e9a2943cc42439825b8f21cd3492eaca05', class: "mrd-date-field" }, this.label && (h("label", { key: '3f836a991e676b6070a8b3800edfce00cc0d3b3d', class: `mrd-date-field__label${this.required ? ' mrd-date-field__label--required' : ''}` }, this.label)), h("input", { key: '575185661987eea3dc91950f51995b2cc75debea', class: `mrd-date-field__input${hasError ? ' mrd-date-field__input--error' : ''}`, type: "date", name: this.name, value: this.value, required: this.required, disabled: this.disabled, onChange: this.handleChange, onBlur: this.handleBlur }), hasError && h("span", { key: '480ec99200989f3dc543d9afc648d83d31992b3c', class: "mrd-date-field__error" }, this.error))));
31
31
  }
32
32
  static get is() { return "mrd-date-field"; }
33
33
  static get encapsulation() { return "scoped"; }
@@ -54,7 +54,7 @@ export class MrdDatetimeField {
54
54
  }
55
55
  render() {
56
56
  const hasError = !!this.error;
57
- return (h(Host, { key: '6052b08238484bee345ae4bb9b3025c7f2474c35' }, h("div", { key: 'f9073be4496e35a7d40405ae4e6a27a5c1607626', class: "mrd-datetime-field" }, this.label && (h("label", { key: '5933c3b2dfcae9bfad378441210ada6b625657a2', class: `mrd-datetime-field__label${this.required ? ' mrd-datetime-field__label--required' : ''}` }, this.label)), h("input", { key: '7a947b104c38960d2326a4877e4ca52db9fd9d84', class: `mrd-datetime-field__input${hasError ? ' mrd-datetime-field__input--error' : ''}`, type: "datetime-local", name: this.name, value: this.localValue, required: this.required, disabled: this.disabled, onChange: this.handleChange, onBlur: this.handleBlur }), hasError && h("span", { key: 'cea3dba7e14e18a3a08394ef3027b661f1808969', class: "mrd-datetime-field__error" }, this.error))));
57
+ return (h(Host, { key: 'ea8b3b68100ffdb316bc5048f82d85d238bb2e4b' }, h("div", { key: 'c192c6998ee474aaf4df7b3b97ae0bd61f6d624d', class: "mrd-datetime-field" }, this.label && (h("label", { key: '1fbd66c17d76508f0d698a2c258be6779e98d85e', class: `mrd-datetime-field__label${this.required ? ' mrd-datetime-field__label--required' : ''}` }, this.label)), h("input", { key: 'fc9612c062a1cab5076a06598cabf227adce996c', class: `mrd-datetime-field__input${hasError ? ' mrd-datetime-field__input--error' : ''}`, type: "datetime-local", name: this.name, value: this.localValue, required: this.required, disabled: this.disabled, onChange: this.handleChange, onBlur: this.handleBlur }), hasError && h("span", { key: '8788ac01739302f6ad61010b238ff38d45e1b68a', class: "mrd-datetime-field__error" }, this.error))));
58
58
  }
59
59
  static get is() { return "mrd-datetime-field"; }
60
60
  static get encapsulation() { return "scoped"; }
@@ -0,0 +1,578 @@
1
+ import { Host, h } from "@stencil/core";
2
+ import { ClientLayoutItemType } from "../../types/client-layout";
3
+ import { t } from "../../utils/i18n";
4
+ import { formatDate } from "../../utils/format";
5
+ /**
6
+ * Archetype-driven document collection view. Renders documents as a lazy,
7
+ * file-explorer-style folder tree, grouped by the `commons.document` archetype's
8
+ * `container` (dossier, the top folder) and `folder` (a path string like
9
+ * `/draft documents/may 2020`, the sub-path beneath it).
10
+ *
11
+ * Loading is lazy per level, mirroring the /distinct endpoint (FINDING-0106):
12
+ * - on load → `mrdLoadDistinct` for the `container` relation → top folders;
13
+ * - on expanding a container → `mrdLoadDistinct` for the `folder` field, filtered
14
+ * by `{containerField}_href` → all folder path strings for that container
15
+ * (the client splits them on `/` and builds the sub-tree locally);
16
+ * - on expanding a node that holds documents → `mrdLoadPage` (a plain filtered list
17
+ * load, the same one a table page uses), filtered by container + exact folder string.
18
+ *
19
+ * When exactly one container exists (e.g. a dossier detail page) the container
20
+ * level is hidden and its folder tree is shown directly at the root.
21
+ */
22
+ export class MrdDocumentList {
23
+ constructor() {
24
+ /** The VIEW or RELATED_VIEW layout item (dataClass, fromClass, view config). */
25
+ this.item = null;
26
+ /** Parent record id — required for RELATED_VIEW path building. */
27
+ this.parentId = '';
28
+ this.locale = navigator.language;
29
+ this.containers = [];
30
+ this.rootLoading = true;
31
+ /** True when the single-container level is collapsed away (dossier context). */
32
+ this.singleContainer = false;
33
+ this.nodeIndex = new Map();
34
+ }
35
+ componentDidLoad() {
36
+ this.emitContainerDistinct();
37
+ }
38
+ // ── Slot field names ─────────────────────────────────────────────────────
39
+ get containerField() {
40
+ var _a, _b, _c;
41
+ return (_c = (_b = (_a = this.archetype) === null || _a === void 0 ? void 0 : _a.slots) === null || _b === void 0 ? void 0 : _b.container) !== null && _c !== void 0 ? _c : 'container';
42
+ }
43
+ get folderField() {
44
+ var _a, _b, _c;
45
+ return (_c = (_b = (_a = this.archetype) === null || _a === void 0 ? void 0 : _a.slots) === null || _b === void 0 ? void 0 : _b.folder) !== null && _c !== void 0 ? _c : 'folder';
46
+ }
47
+ get titleField() {
48
+ var _a, _b, _c;
49
+ return (_c = (_b = (_a = this.archetype) === null || _a === void 0 ? void 0 : _a.slots) === null || _b === void 0 ? void 0 : _b.title) !== null && _c !== void 0 ? _c : 'name';
50
+ }
51
+ get dateField() {
52
+ var _a, _b;
53
+ return (_b = (_a = this.archetype) === null || _a === void 0 ? void 0 : _a.slots) === null || _b === void 0 ? void 0 : _b.date;
54
+ }
55
+ // ── Path / query building (mirrors mrd-table conventions) ────────────────
56
+ /** VIEW: `/{dataClass}`; RELATED_VIEW: `/{fromClass}/{parentId}/{dataClass}`. */
57
+ buildDataPath() {
58
+ var _a, _b, _c;
59
+ const it = this.item;
60
+ const dataClass = (_b = (_a = it === null || it === void 0 ? void 0 : it.dataClass) !== null && _a !== void 0 ? _a : it === null || it === void 0 ? void 0 : it.relatedClass) !== null && _b !== void 0 ? _b : '';
61
+ if ((it === null || it === void 0 ? void 0 : it.type) === ClientLayoutItemType.RELATED_VIEW) {
62
+ return `/${(_c = it.fromClass) !== null && _c !== void 0 ? _c : ''}/${this.parentId}/${dataClass}`;
63
+ }
64
+ return `/${dataClass}`;
65
+ }
66
+ /** View-level static filters + filterClass, shared by every request. */
67
+ baseParams() {
68
+ var _a, _b, _c, _d, _e, _f, _g;
69
+ const p = new URLSearchParams();
70
+ const filterClass = (_a = this.item) === null || _a === void 0 ? void 0 : _a.filterClass;
71
+ if (filterClass)
72
+ p.set('type', filterClass);
73
+ for (const f of ((_d = (_c = (_b = this.item) === null || _b === void 0 ? void 0 : _b.view) === null || _c === void 0 ? void 0 : _c.filter) !== null && _d !== void 0 ? _d : [])) {
74
+ if (!f.name)
75
+ continue;
76
+ if (f.operator === 'EMPTY') {
77
+ p.set(f.name, '');
78
+ continue;
79
+ }
80
+ if (f.operator === 'NOT_EMPTY') {
81
+ p.set(f.name + '_notempty', 'true');
82
+ continue;
83
+ }
84
+ if (f.operator === 'STARTS_WITH') {
85
+ p.set(f.name + '_startswith', String((_e = f.value) !== null && _e !== void 0 ? _e : ''));
86
+ continue;
87
+ }
88
+ if (f.operator === 'FROM') {
89
+ p.set(f.name + '_from', String((_f = f.value) !== null && _f !== void 0 ? _f : ''));
90
+ continue;
91
+ }
92
+ if (f.operator === 'TO') {
93
+ p.set(f.name + '_to', String((_g = f.value) !== null && _g !== void 0 ? _g : ''));
94
+ continue;
95
+ }
96
+ if (f.value != null) {
97
+ p.set(f.name, String(f.value));
98
+ }
99
+ }
100
+ return p;
101
+ }
102
+ emitContainerDistinct() {
103
+ const p = this.baseParams();
104
+ p.set('distinct', this.containerField);
105
+ this.mrdLoadDistinct.emit({
106
+ nodeId: MrdDocumentList.ROOT,
107
+ distinct: this.containerField,
108
+ path: this.buildDataPath() + '/distinct',
109
+ qs: p.toString(),
110
+ });
111
+ }
112
+ emitFolderDistinct(container) {
113
+ var _a;
114
+ const p = this.baseParams();
115
+ p.set('distinct', this.folderField);
116
+ p.set(this.containerField + '_href', (_a = container.href) !== null && _a !== void 0 ? _a : '');
117
+ container.loading = true;
118
+ this.mrdLoadDistinct.emit({
119
+ nodeId: container.id,
120
+ distinct: this.folderField,
121
+ path: this.buildDataPath() + '/distinct',
122
+ qs: p.toString(),
123
+ });
124
+ }
125
+ emitDocuments(container, node) {
126
+ var _a, _b;
127
+ const p = this.baseParams();
128
+ p.set(this.containerField + '_href', (_a = container.href) !== null && _a !== void 0 ? _a : '');
129
+ p.set(this.folderField, (_b = node.fullPath) !== null && _b !== void 0 ? _b : '');
130
+ node.loading = true;
131
+ this.mrdLoadPage.emit({
132
+ nodeId: node.id,
133
+ page: 0,
134
+ sort: '',
135
+ path: this.buildDataPath(),
136
+ qs: p.toString(),
137
+ });
138
+ }
139
+ // ── Public injection API ─────────────────────────────────────────────────
140
+ /** Inject distinct values for a node. `nodeId` is the sentinel root (containers)
141
+ * or a container node id (folders). */
142
+ async setDistinct(nodeId, values) {
143
+ if (nodeId === MrdDocumentList.ROOT) {
144
+ this.applyContainers(values);
145
+ }
146
+ else {
147
+ this.applyFolders(nodeId, values);
148
+ }
149
+ }
150
+ /** Inject the documents loaded for one folder node. */
151
+ async setDocuments(nodeId, docs) {
152
+ const node = this.nodeIndex.get(nodeId);
153
+ if (!node)
154
+ return;
155
+ node.docs = docs !== null && docs !== void 0 ? docs : [];
156
+ node.docsLoaded = true;
157
+ node.loading = false;
158
+ this.bump();
159
+ }
160
+ applyContainers(values) {
161
+ const nodes = [];
162
+ for (const v of values) {
163
+ if (!v.value || typeof v.value !== 'object')
164
+ continue;
165
+ const href = v.value.href;
166
+ const node = this.makeContainerNode(href, v.value.name, v.count);
167
+ nodes.push(node);
168
+ this.nodeIndex.set(node.id, node);
169
+ }
170
+ this.containers = nodes;
171
+ this.rootLoading = false;
172
+ this.singleContainer = nodes.length === 1;
173
+ // Single container (dossier context): collapse the level away, load its folders now.
174
+ if (this.singleContainer) {
175
+ const only = nodes[0];
176
+ only.open = true;
177
+ this.emitFolderDistinct(only);
178
+ }
179
+ }
180
+ applyFolders(containerId, values) {
181
+ const container = this.nodeIndex.get(containerId);
182
+ if (!container)
183
+ return;
184
+ container.children = [];
185
+ container.hasDocs = false;
186
+ container.docCount = 0;
187
+ for (const v of values) {
188
+ const raw = typeof v.value === 'string' ? v.value : v.value == null ? '' : String(v.value);
189
+ const segs = this.splitFolder(raw);
190
+ if (segs.length === 0) {
191
+ // Root documents — the container's own direct documents.
192
+ container.hasDocs = true;
193
+ container.docCount = v.count;
194
+ container.fullPath = raw;
195
+ continue;
196
+ }
197
+ let node = container;
198
+ const acc = [];
199
+ for (const seg of segs) {
200
+ acc.push(seg);
201
+ let child = node.children.find(c => c.label === seg);
202
+ if (!child) {
203
+ child = this.makeFolderNode(container.id + '/' + acc.join('/'), seg);
204
+ node.children.push(child);
205
+ this.nodeIndex.set(child.id, child);
206
+ }
207
+ node = child;
208
+ }
209
+ node.hasDocs = true;
210
+ node.docCount = v.count;
211
+ node.fullPath = raw;
212
+ }
213
+ this.computeTotals(container);
214
+ container.foldersLoaded = true;
215
+ container.loading = false;
216
+ // If the container has root documents, load them now (they show inline on expand).
217
+ if (container.hasDocs && !container.docsLoaded) {
218
+ this.emitDocuments(container, container);
219
+ }
220
+ this.bump();
221
+ }
222
+ // ── Tree helpers ─────────────────────────────────────────────────────────
223
+ /** Normalise a folder path: null/""/"/" → root ([]); else split on "/" dropping empties. */
224
+ splitFolder(path) {
225
+ if (path == null)
226
+ return [];
227
+ const s = String(path).trim();
228
+ if (s === '' || s === '/')
229
+ return [];
230
+ return s.split('/').map(x => x.trim()).filter(Boolean);
231
+ }
232
+ makeContainerNode(href, label, count) {
233
+ return {
234
+ id: 'c:' + href, kind: 'container', label, href,
235
+ hasDocs: false, docCount: 0, totalCount: count, children: [],
236
+ open: false, loading: false, foldersLoaded: false, docsLoaded: false, docs: [],
237
+ };
238
+ }
239
+ makeFolderNode(id, label) {
240
+ return {
241
+ id, kind: 'folder', label,
242
+ hasDocs: false, docCount: 0, totalCount: 0, children: [],
243
+ open: false, loading: false, foldersLoaded: false, docsLoaded: false, docs: [],
244
+ };
245
+ }
246
+ computeTotals(node) {
247
+ let total = node.docCount;
248
+ for (const c of node.children)
249
+ total += this.computeTotals(c);
250
+ node.totalCount = total;
251
+ return total;
252
+ }
253
+ /** Force a re-render after mutating nodes in place. */
254
+ bump() {
255
+ this.containers = [...this.containers];
256
+ }
257
+ // ── Interaction ──────────────────────────────────────────────────────────
258
+ toggleContainer(node) {
259
+ node.open = !node.open;
260
+ if (node.open && !node.foldersLoaded && !node.loading) {
261
+ this.emitFolderDistinct(node);
262
+ }
263
+ this.bump();
264
+ }
265
+ toggleFolder(container, node) {
266
+ node.open = !node.open;
267
+ if (node.open && node.hasDocs && !node.docsLoaded && !node.loading) {
268
+ this.emitDocuments(container, node);
269
+ }
270
+ this.bump();
271
+ }
272
+ openDoc(doc) {
273
+ var _a, _b, _c, _d;
274
+ const href = (_b = (_a = doc === null || doc === void 0 ? void 0 : doc._links) === null || _a === void 0 ? void 0 : _a.self) === null || _b === void 0 ? void 0 : _b.href;
275
+ const label = (_d = (_c = doc === null || doc === void 0 ? void 0 : doc[this.titleField]) !== null && _c !== void 0 ? _c : doc === null || doc === void 0 ? void 0 : doc.name) !== null && _d !== void 0 ? _d : '';
276
+ this.mrdNavigate.emit({ href, label });
277
+ }
278
+ // ── Render ───────────────────────────────────────────────────────────────
279
+ renderChevron(open, leaf) {
280
+ return (h("span", { class: `mrd-document-list__chev${leaf ? ' mrd-document-list__chev--leaf' : ''}${open ? ' mrd-document-list__chev--open' : ''}` }, h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M9 6l6 6-6 6" }))));
281
+ }
282
+ renderDossierIcon() {
283
+ return (h("svg", { class: "mrd-document-list__icon mrd-document-list__icon--dossier", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" })));
284
+ }
285
+ renderFolderIcon() {
286
+ return (h("svg", { class: "mrd-document-list__icon mrd-document-list__icon--folder", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" })));
287
+ }
288
+ renderDocIcon() {
289
+ return (h("svg", { class: "mrd-document-list__icon mrd-document-list__icon--doc", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }), h("path", { d: "M14 2v6h6" })));
290
+ }
291
+ indent(depth) {
292
+ return h("span", { class: "mrd-document-list__indent", style: { width: `${depth * 18}px` } });
293
+ }
294
+ renderDocRow(doc, depth) {
295
+ var _a, _b, _c, _d, _e;
296
+ const label = (_b = (_a = doc === null || doc === void 0 ? void 0 : doc[this.titleField]) !== null && _a !== void 0 ? _a : doc === null || doc === void 0 ? void 0 : doc.name) !== null && _b !== void 0 ? _b : '';
297
+ const dateRaw = this.dateField ? doc === null || doc === void 0 ? void 0 : doc[this.dateField] : undefined;
298
+ const date = dateRaw ? formatDate(dateRaw, this.locale) : '';
299
+ return (h("div", { class: "mrd-document-list__row mrd-document-list__row--doc", key: (_e = (_d = (_c = doc === null || doc === void 0 ? void 0 : doc._links) === null || _c === void 0 ? void 0 : _c.self) === null || _d === void 0 ? void 0 : _d.href) !== null && _e !== void 0 ? _e : label, onClick: () => this.openDoc(doc) }, this.indent(depth), this.renderChevron(false, true), this.renderDocIcon(), h("span", { class: "mrd-document-list__label" }, label), date && h("span", { class: "mrd-document-list__date" }, date)));
300
+ }
301
+ renderLoadingRow(depth) {
302
+ return (h("div", { class: "mrd-document-list__loading", key: "loading" }, this.indent(depth), h("span", { class: "mrd-document-list__spinner" }), t('loading', this.locale)));
303
+ }
304
+ renderChildren(container, node, depth) {
305
+ const out = [];
306
+ // Direct documents of this node (root docs live on the container node).
307
+ if (node.hasDocs) {
308
+ if (node.docsLoaded) {
309
+ for (const doc of node.docs)
310
+ out.push(this.renderDocRow(doc, depth));
311
+ }
312
+ else if (node.loading) {
313
+ out.push(this.renderLoadingRow(depth));
314
+ }
315
+ }
316
+ // Child folders.
317
+ for (const child of node.children) {
318
+ out.push(this.renderFolderNode(container, child, depth));
319
+ }
320
+ return out;
321
+ }
322
+ renderFolderNode(container, node, depth) {
323
+ const leaf = node.children.length === 0 && !node.hasDocs;
324
+ return (h("div", { class: "mrd-document-list__node", key: node.id }, h("div", { class: "mrd-document-list__row", onClick: () => this.toggleFolder(container, node) }, this.indent(depth), this.renderChevron(node.open, leaf), this.renderFolderIcon(), h("span", { class: "mrd-document-list__label" }, node.label), h("span", { class: "mrd-document-list__count" }, node.totalCount)), node.open && h("div", { class: "mrd-document-list__kids" }, this.renderChildren(container, node, depth + 1))));
325
+ }
326
+ renderContainerNode(node, depth) {
327
+ return (h("div", { class: "mrd-document-list__node", key: node.id }, h("div", { class: "mrd-document-list__row mrd-document-list__row--dossier", onClick: () => this.toggleContainer(node) }, this.indent(depth), this.renderChevron(node.open, false), this.renderDossierIcon(), h("span", { class: "mrd-document-list__label" }, node.label), h("span", { class: "mrd-document-list__count" }, node.totalCount)), node.open && (h("div", { class: "mrd-document-list__kids" }, node.loading && !node.foldersLoaded
328
+ ? this.renderLoadingRow(depth + 1)
329
+ : this.renderChildren(node, node, depth + 1)))));
330
+ }
331
+ render() {
332
+ let body;
333
+ if (this.rootLoading) {
334
+ body = this.renderLoadingRow(0);
335
+ }
336
+ else if (this.containers.length === 0) {
337
+ body = h("div", { key: '0c4190bb86543e2d37cc1584b3495eb6eab5664c', class: "mrd-document-list__empty" }, t('no_results', this.locale));
338
+ }
339
+ else if (this.singleContainer) {
340
+ // Dossier context: render the single container's folder tree at the root.
341
+ const only = this.containers[0];
342
+ body = only.loading && !only.foldersLoaded
343
+ ? this.renderLoadingRow(0)
344
+ : this.renderChildren(only, only, 0);
345
+ }
346
+ else {
347
+ body = this.containers.map(c => this.renderContainerNode(c, 0));
348
+ }
349
+ return (h(Host, { key: '4e38d9ef5a1df137a41516a47dc5debbea6b2f35' }, h("div", { key: '6d2f162624e5bbc8650a2978a3b045c21fe13ea3', class: "mrd-document-list" }, body)));
350
+ }
351
+ static get is() { return "mrd-document-list"; }
352
+ static get encapsulation() { return "scoped"; }
353
+ static get originalStyleUrls() {
354
+ return {
355
+ "$": ["mrd-document-list.scss"]
356
+ };
357
+ }
358
+ static get styleUrls() {
359
+ return {
360
+ "$": ["mrd-document-list.css"]
361
+ };
362
+ }
363
+ static get properties() {
364
+ return {
365
+ "item": {
366
+ "type": "unknown",
367
+ "mutable": false,
368
+ "complexType": {
369
+ "original": "ClientLayoutItem | null",
370
+ "resolved": "ClientLayoutItem | null",
371
+ "references": {
372
+ "ClientLayoutItem": {
373
+ "location": "import",
374
+ "path": "../../types/client-layout",
375
+ "id": "src/types/client-layout.ts::ClientLayoutItem",
376
+ "referenceLocation": "ClientLayoutItem"
377
+ }
378
+ }
379
+ },
380
+ "required": false,
381
+ "optional": false,
382
+ "docs": {
383
+ "tags": [],
384
+ "text": "The VIEW or RELATED_VIEW layout item (dataClass, fromClass, view config)."
385
+ },
386
+ "getter": false,
387
+ "setter": false,
388
+ "defaultValue": "null"
389
+ },
390
+ "archetype": {
391
+ "type": "unknown",
392
+ "mutable": false,
393
+ "complexType": {
394
+ "original": "ClientArchetype",
395
+ "resolved": "ClientArchetype",
396
+ "references": {
397
+ "ClientArchetype": {
398
+ "location": "import",
399
+ "path": "../../types/client-layout",
400
+ "id": "src/types/client-layout.ts::ClientArchetype",
401
+ "referenceLocation": "ClientArchetype"
402
+ }
403
+ }
404
+ },
405
+ "required": true,
406
+ "optional": false,
407
+ "docs": {
408
+ "tags": [],
409
+ "text": "Resolved `commons.document` binding: slot name \u2192 concrete field/relation name."
410
+ },
411
+ "getter": false,
412
+ "setter": false
413
+ },
414
+ "parentId": {
415
+ "type": "string",
416
+ "mutable": false,
417
+ "complexType": {
418
+ "original": "string",
419
+ "resolved": "string",
420
+ "references": {}
421
+ },
422
+ "required": false,
423
+ "optional": false,
424
+ "docs": {
425
+ "tags": [],
426
+ "text": "Parent record id \u2014 required for RELATED_VIEW path building."
427
+ },
428
+ "getter": false,
429
+ "setter": false,
430
+ "reflect": false,
431
+ "attribute": "parent-id",
432
+ "defaultValue": "''"
433
+ },
434
+ "locale": {
435
+ "type": "string",
436
+ "mutable": false,
437
+ "complexType": {
438
+ "original": "string",
439
+ "resolved": "string",
440
+ "references": {}
441
+ },
442
+ "required": false,
443
+ "optional": false,
444
+ "docs": {
445
+ "tags": [],
446
+ "text": ""
447
+ },
448
+ "getter": false,
449
+ "setter": false,
450
+ "reflect": false,
451
+ "attribute": "locale",
452
+ "defaultValue": "navigator.language"
453
+ }
454
+ };
455
+ }
456
+ static get states() {
457
+ return {
458
+ "containers": {},
459
+ "rootLoading": {},
460
+ "singleContainer": {}
461
+ };
462
+ }
463
+ static get events() {
464
+ return [{
465
+ "method": "mrdLoadDistinct",
466
+ "name": "mrdLoadDistinct",
467
+ "bubbles": true,
468
+ "cancelable": true,
469
+ "composed": true,
470
+ "docs": {
471
+ "tags": [],
472
+ "text": "Request distinct values for a field/relation. Host fetches `{path}?{qs}` and calls `setDistinct(nodeId, values)`."
473
+ },
474
+ "complexType": {
475
+ "original": "{ nodeId: string; distinct: string; path: string; qs: string }",
476
+ "resolved": "{ nodeId: string; distinct: string; path: string; qs: string; }",
477
+ "references": {}
478
+ }
479
+ }, {
480
+ "method": "mrdLoadPage",
481
+ "name": "mrdLoadPage",
482
+ "bubbles": true,
483
+ "cancelable": true,
484
+ "composed": true,
485
+ "docs": {
486
+ "tags": [],
487
+ "text": "Request the documents in one folder \u2014 the same filtered list load a table does.\nHost fetches `{path}?{qs}` and calls `setDocuments(nodeId, docs)` (via setViewPage)."
488
+ },
489
+ "complexType": {
490
+ "original": "{ nodeId: string; page: number; sort: string; path: string; qs: string }",
491
+ "resolved": "{ nodeId: string; page: number; sort: string; path: string; qs: string; }",
492
+ "references": {}
493
+ }
494
+ }, {
495
+ "method": "mrdNavigate",
496
+ "name": "mrdNavigate",
497
+ "bubbles": true,
498
+ "cancelable": true,
499
+ "composed": true,
500
+ "docs": {
501
+ "tags": [],
502
+ "text": "A document row was clicked. Host routes to the document object page."
503
+ },
504
+ "complexType": {
505
+ "original": "{ href?: string; label: string }",
506
+ "resolved": "{ href?: string | undefined; label: string; }",
507
+ "references": {}
508
+ }
509
+ }];
510
+ }
511
+ static get methods() {
512
+ return {
513
+ "setDistinct": {
514
+ "complexType": {
515
+ "signature": "(nodeId: string, values: DistinctValue[]) => Promise<void>",
516
+ "parameters": [{
517
+ "name": "nodeId",
518
+ "type": "string",
519
+ "docs": ""
520
+ }, {
521
+ "name": "values",
522
+ "type": "DistinctValue[]",
523
+ "docs": ""
524
+ }],
525
+ "references": {
526
+ "Promise": {
527
+ "location": "global",
528
+ "id": "global::Promise"
529
+ },
530
+ "DistinctValue": {
531
+ "location": "local",
532
+ "path": "/Users/michiel/Mosterd/mosterd-components/src/components/mrd-document-list/mrd-document-list.tsx",
533
+ "id": "src/components/mrd-document-list/mrd-document-list.tsx::DistinctValue"
534
+ }
535
+ },
536
+ "return": "Promise<void>"
537
+ },
538
+ "docs": {
539
+ "text": "Inject distinct values for a node. `nodeId` is the sentinel root (containers)\nor a container node id (folders).",
540
+ "tags": []
541
+ }
542
+ },
543
+ "setDocuments": {
544
+ "complexType": {
545
+ "signature": "(nodeId: string, docs: DocRow[]) => Promise<void>",
546
+ "parameters": [{
547
+ "name": "nodeId",
548
+ "type": "string",
549
+ "docs": ""
550
+ }, {
551
+ "name": "docs",
552
+ "type": "DocRow[]",
553
+ "docs": ""
554
+ }],
555
+ "references": {
556
+ "Promise": {
557
+ "location": "global",
558
+ "id": "global::Promise"
559
+ },
560
+ "DocRow": {
561
+ "location": "local",
562
+ "path": "/Users/michiel/Mosterd/mosterd-components/src/components/mrd-document-list/mrd-document-list.tsx",
563
+ "id": "src/components/mrd-document-list/mrd-document-list.tsx::DocRow"
564
+ }
565
+ },
566
+ "return": "Promise<void>"
567
+ },
568
+ "docs": {
569
+ "text": "Inject the documents loaded for one folder node.",
570
+ "tags": []
571
+ }
572
+ }
573
+ };
574
+ }
575
+ static get elementRef() { return "el"; }
576
+ }
577
+ /** Root sentinel id for the container-level distinct request. */
578
+ MrdDocumentList.ROOT = '__root__';