@mmlogic/components 0.3.8 → 0.3.10

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 (82) 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_23.cjs.entry.js} +1059 -23
  5. package/dist/collection/collection-manifest.json +3 -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-container/mrd-document-container.js +375 -0
  11. package/dist/collection/components/mrd-document-container/mrd-document-container.scss +79 -0
  12. package/dist/collection/components/mrd-document-list/mrd-document-list.js +1129 -0
  13. package/dist/collection/components/mrd-document-list/mrd-document-list.scss +181 -0
  14. package/dist/collection/components/mrd-document-view/mrd-document-view.js +177 -0
  15. package/dist/collection/components/mrd-document-view/mrd-document-view.scss +121 -0
  16. package/dist/collection/components/mrd-email-field/mrd-email-field.js +1 -1
  17. package/dist/collection/components/mrd-file-field/mrd-file-field.js +1 -1
  18. package/dist/collection/components/mrd-image-field/mrd-image-field.js +1 -1
  19. package/dist/collection/components/mrd-layout-section/mrd-layout-section.js +288 -14
  20. package/dist/collection/components/mrd-layout-section/mrd-layout-section.scss +2 -3
  21. package/dist/collection/components/mrd-longtext-field/mrd-longtext-field.js +1 -1
  22. package/dist/collection/components/mrd-number-field/mrd-number-field.js +1 -1
  23. package/dist/collection/components/mrd-secret-field/mrd-secret-field.js +2 -2
  24. package/dist/collection/components/mrd-text-field/mrd-text-field.js +1 -1
  25. package/dist/collection/components/mrd-textarea-field/mrd-textarea-field.js +1 -1
  26. package/dist/collection/components/mrd-time-field/mrd-time-field.js +1 -1
  27. package/dist/collection/dev/app.js +66 -2
  28. package/dist/collection/types/client-layout.js +10 -0
  29. package/dist/collection/utils/i18n.js +34 -0
  30. package/dist/components/client-layout.js +1 -1
  31. package/dist/components/format.js +1 -1
  32. package/dist/components/i18n.js +1 -1
  33. package/dist/components/index.js +1 -1
  34. package/dist/components/mrd-boolean-field2.js +1 -1
  35. package/dist/components/mrd-currency-field2.js +1 -1
  36. package/dist/components/mrd-date-field2.js +1 -1
  37. package/dist/components/mrd-datetime-field2.js +1 -1
  38. package/dist/components/mrd-document-container.d.ts +11 -0
  39. package/dist/components/mrd-document-container.js +1 -0
  40. package/dist/components/mrd-document-container2.js +1 -0
  41. package/dist/components/mrd-document-list.d.ts +11 -0
  42. package/dist/components/mrd-document-list.js +1 -0
  43. package/dist/components/mrd-document-list2.js +1 -0
  44. package/dist/components/mrd-document-view.d.ts +11 -0
  45. package/dist/components/mrd-document-view.js +1 -0
  46. package/dist/components/mrd-document-view2.js +1 -0
  47. package/dist/components/mrd-email-field2.js +1 -1
  48. package/dist/components/mrd-file-field2.js +1 -1
  49. package/dist/components/mrd-image-field2.js +1 -1
  50. package/dist/components/mrd-layout-section.js +1 -1
  51. package/dist/components/mrd-longtext-field2.js +1 -1
  52. package/dist/components/mrd-number-field2.js +1 -1
  53. package/dist/components/mrd-secret-field2.js +1 -1
  54. package/dist/components/mrd-table2.js +1 -1
  55. package/dist/components/mrd-text-field2.js +1 -1
  56. package/dist/components/mrd-textarea-field2.js +1 -1
  57. package/dist/components/mrd-time-field2.js +1 -1
  58. package/dist/esm/index.js +11 -1
  59. package/dist/esm/loader.js +1 -1
  60. package/dist/esm/mosterdcomponents.js +1 -1
  61. package/dist/esm/{mrd-boolean-field_20.entry.js → mrd-boolean-field_23.entry.js} +1058 -25
  62. package/dist/mosterdcomponents/{cell-renderer-CbRwLOo8.js.map → cell-renderer-B-AJDBcj.js.map} +1 -1
  63. package/dist/mosterdcomponents/{client-layout-D88nn5zf.js.map → client-layout-ChqRA3AF.js.map} +1 -1
  64. package/dist/mosterdcomponents/i18n-s1XrKcD2.js.map +1 -0
  65. package/dist/mosterdcomponents/index-DkY-NQj0.js.map +1 -0
  66. package/dist/mosterdcomponents/index-DwF_Sp__.js.map +1 -0
  67. package/dist/mosterdcomponents/index.esm.js +1 -1
  68. package/dist/mosterdcomponents/mosterdcomponents.css +1 -1
  69. package/dist/mosterdcomponents/mosterdcomponents.esm.js +1 -1
  70. package/dist/mosterdcomponents/p-69452249.entry.js +1 -0
  71. package/dist/mosterdcomponents/{validation-ixb43cqU.js.map → validation-Br9k2Ztw.js.map} +1 -1
  72. package/dist/types/components/mrd-document-container/mrd-document-container.d.ts +94 -0
  73. package/dist/types/components/mrd-document-list/mrd-document-list.d.ts +210 -0
  74. package/dist/types/components/mrd-document-view/mrd-document-view.d.ts +36 -0
  75. package/dist/types/components/mrd-layout-section/mrd-layout-section.d.ts +57 -6
  76. package/dist/types/components.d.ts +507 -15
  77. package/dist/types/types/client-layout.d.ts +38 -0
  78. package/package.json +1 -1
  79. package/dist/mosterdcomponents/i18n-hoGGKbKU.js.map +0 -1
  80. package/dist/mosterdcomponents/index-6yQUNVww.js.map +0 -1
  81. package/dist/mosterdcomponents/index-I5SuYv7a.js.map +0 -1
  82. package/dist/mosterdcomponents/p-7bfaee51.entry.js +0 -1
@@ -0,0 +1,1129 @@
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
+ /** Currently selected node id — the target for "New folder" and (later) drops. */
34
+ this.selectedId = null;
35
+ /** Node id currently highlighted as a drag-drop target (null = none). */
36
+ this.dropTargetId = null;
37
+ /** Node id showing an "uploading…" indicator while a dropped file is processed. */
38
+ this.uploadingNodeId = null;
39
+ this.nodeIndex = new Map();
40
+ // ── New-folder editing state ───────────────────────────────────────────────
41
+ /** The pending node whose inline name input is open (null = not creating). */
42
+ this.pendingNode = null;
43
+ /** The node the pending folder is being created under. */
44
+ this.pendingParent = null;
45
+ /** The container the pending folder belongs to. */
46
+ this.pendingContainer = null;
47
+ /** Current text in the inline name input. */
48
+ this.pendingName = '';
49
+ /** Ref to the inline input, so we can focus it after it mounts. */
50
+ this.pendingInputEl = null;
51
+ /** Set when a fresh input needs focus on the next render. */
52
+ this.pendingNeedsFocus = false;
53
+ /** Monotonic counter for unique temporary pending-node ids. */
54
+ this.newFolderSeq = 0;
55
+ /** Last emitted canCreateFolder value, to only emit mrdCanCreate on change. */
56
+ this.lastCanCreate = false;
57
+ // ── Drag & drop (move a document into another folder) ──────────────────────
58
+ /** The document row currently being dragged. */
59
+ this.dragDoc = null;
60
+ /** Id of the node the dragged document currently lives in. */
61
+ this.dragFromId = null;
62
+ /** External file dropped onto a node, awaiting its upload to complete. */
63
+ this.pendingUpload = null;
64
+ /** The optimistic document row awaiting its self href from the create POST. */
65
+ this.lastOptimisticDoc = null;
66
+ this.startCreateFolder = () => {
67
+ const resolved = this.resolveTarget();
68
+ if (!resolved || this.pendingNode)
69
+ return;
70
+ const { target, container } = resolved;
71
+ const tempId = `${container.id}/__new__${this.newFolderSeq++}`;
72
+ const node = this.makeFolderNode(tempId, '', container.id);
73
+ node.pending = true;
74
+ node.editing = true;
75
+ target.children = [...target.children, node];
76
+ target.open = true;
77
+ this.nodeIndex.set(node.id, node);
78
+ this.pendingNode = node;
79
+ this.pendingParent = target;
80
+ this.pendingContainer = container;
81
+ this.pendingName = '';
82
+ this.pendingNeedsFocus = true;
83
+ this.bump();
84
+ };
85
+ this.onPendingInput = (e) => {
86
+ var _a;
87
+ this.pendingName = e.target.value;
88
+ if ((_a = this.pendingNode) === null || _a === void 0 ? void 0 : _a.error) {
89
+ this.pendingNode.error = undefined;
90
+ this.bump();
91
+ }
92
+ };
93
+ this.onPendingKeyDown = (e) => {
94
+ if (e.key === 'Enter') {
95
+ e.preventDefault();
96
+ this.commitFolder();
97
+ }
98
+ else if (e.key === 'Escape') {
99
+ e.preventDefault();
100
+ this.cancelFolder();
101
+ }
102
+ };
103
+ // ── Drag & drop: move a document into another folder / container ────────────
104
+ this.onDocDragStart = (e, doc, node) => {
105
+ var _a, _b, _c;
106
+ this.dragDoc = doc;
107
+ this.dragFromId = node.id;
108
+ if (e.dataTransfer) {
109
+ e.dataTransfer.effectAllowed = 'move';
110
+ // A payload is required for a drag to start in some browsers.
111
+ e.dataTransfer.setData('text/plain', (_c = (_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) !== null && _c !== void 0 ? _c : '');
112
+ }
113
+ };
114
+ this.onDocDragEnd = () => {
115
+ this.dragDoc = null;
116
+ this.dragFromId = null;
117
+ if (this.dropTargetId !== null)
118
+ this.dropTargetId = null;
119
+ };
120
+ /** A folder/container node (or a document inside it) accepts an internal move
121
+ * or an external file drop. Always claims the event so it never bubbles to the
122
+ * root drop-zone; a different node is highlighted (its own folder = no-op). */
123
+ this.onNodeDragOver = (e, node) => {
124
+ const file = this.isFileDrag(e);
125
+ if (!this.dragDoc && !file)
126
+ return;
127
+ e.preventDefault();
128
+ e.stopPropagation();
129
+ if (e.dataTransfer)
130
+ e.dataTransfer.dropEffect = file ? 'copy' : 'move';
131
+ const target = !file && node.id === this.dragFromId ? null : node.id;
132
+ if (this.dropTargetId !== target)
133
+ this.dropTargetId = target;
134
+ };
135
+ this.onNodeDragLeave = (node) => {
136
+ if (this.dropTargetId === node.id)
137
+ this.dropTargetId = null;
138
+ };
139
+ this.onNodeDrop = (e, node, container) => {
140
+ if (this.isFileDrag(e)) {
141
+ e.preventDefault();
142
+ e.stopPropagation();
143
+ this.startFileUpload(e, node, container);
144
+ return;
145
+ }
146
+ if (!this.dragDoc)
147
+ return;
148
+ e.preventDefault();
149
+ e.stopPropagation();
150
+ this.moveDocument(node, container);
151
+ this.onDocDragEnd();
152
+ };
153
+ /** Root-zone drop (dossier context): target the single container's root. */
154
+ this.onRootDragOver = (e) => {
155
+ if (!this.singleContainer)
156
+ return;
157
+ const file = this.isFileDrag(e);
158
+ if (!this.dragDoc && !file)
159
+ return;
160
+ e.preventDefault();
161
+ if (e.dataTransfer)
162
+ e.dataTransfer.dropEffect = file ? 'copy' : 'move';
163
+ };
164
+ this.onRootDrop = (e) => {
165
+ if (!this.singleContainer)
166
+ return;
167
+ const only = this.containers[0];
168
+ if (this.isFileDrag(e)) {
169
+ e.preventDefault();
170
+ this.startFileUpload(e, only, only);
171
+ return;
172
+ }
173
+ if (!this.dragDoc)
174
+ return;
175
+ e.preventDefault();
176
+ this.moveDocument(only, only);
177
+ this.onDocDragEnd();
178
+ };
179
+ }
180
+ componentDidLoad() {
181
+ this.emitContainerDistinct();
182
+ }
183
+ componentDidRender() {
184
+ if (this.pendingNeedsFocus && this.pendingInputEl) {
185
+ this.pendingInputEl.focus();
186
+ this.pendingInputEl.select();
187
+ this.pendingNeedsFocus = false;
188
+ }
189
+ const can = this.canCreateFolder;
190
+ if (can !== this.lastCanCreate) {
191
+ this.lastCanCreate = can;
192
+ this.mrdCanCreate.emit(can);
193
+ }
194
+ }
195
+ // ── Slot field names ─────────────────────────────────────────────────────
196
+ get containerField() {
197
+ var _a, _b, _c;
198
+ 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';
199
+ }
200
+ get folderField() {
201
+ var _a, _b, _c;
202
+ 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';
203
+ }
204
+ get titleField() {
205
+ var _a, _b, _c;
206
+ 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';
207
+ }
208
+ get fileField() {
209
+ var _a, _b, _c;
210
+ return (_c = (_b = (_a = this.archetype) === null || _a === void 0 ? void 0 : _a.slots) === null || _b === void 0 ? void 0 : _b.file) !== null && _c !== void 0 ? _c : 'file';
211
+ }
212
+ get dateField() {
213
+ var _a, _b;
214
+ return (_b = (_a = this.archetype) === null || _a === void 0 ? void 0 : _a.slots) === null || _b === void 0 ? void 0 : _b.date;
215
+ }
216
+ // ── Path / query building (mirrors mrd-table conventions) ────────────────
217
+ /** VIEW: `/{dataClass}`; RELATED_VIEW: `/{fromClass}/{parentId}/{dataClass}`. */
218
+ buildDataPath() {
219
+ var _a, _b, _c;
220
+ const it = this.item;
221
+ 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 : '';
222
+ if ((it === null || it === void 0 ? void 0 : it.type) === ClientLayoutItemType.RELATED_VIEW) {
223
+ return `/${(_c = it.fromClass) !== null && _c !== void 0 ? _c : ''}/${this.parentId}/${dataClass}`;
224
+ }
225
+ return `/${dataClass}`;
226
+ }
227
+ /** View-level static filters + filterClass, shared by every request. */
228
+ baseParams() {
229
+ var _a, _b, _c, _d, _e, _f, _g;
230
+ const p = new URLSearchParams();
231
+ const filterClass = (_a = this.item) === null || _a === void 0 ? void 0 : _a.filterClass;
232
+ if (filterClass)
233
+ p.set('type', filterClass);
234
+ 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 : [])) {
235
+ if (!f.name)
236
+ continue;
237
+ if (f.operator === 'EMPTY') {
238
+ p.set(f.name, '');
239
+ continue;
240
+ }
241
+ if (f.operator === 'NOT_EMPTY') {
242
+ p.set(f.name + '_notempty', 'true');
243
+ continue;
244
+ }
245
+ if (f.operator === 'STARTS_WITH') {
246
+ p.set(f.name + '_startswith', String((_e = f.value) !== null && _e !== void 0 ? _e : ''));
247
+ continue;
248
+ }
249
+ if (f.operator === 'FROM') {
250
+ p.set(f.name + '_from', String((_f = f.value) !== null && _f !== void 0 ? _f : ''));
251
+ continue;
252
+ }
253
+ if (f.operator === 'TO') {
254
+ p.set(f.name + '_to', String((_g = f.value) !== null && _g !== void 0 ? _g : ''));
255
+ continue;
256
+ }
257
+ if (f.value != null) {
258
+ p.set(f.name, String(f.value));
259
+ }
260
+ }
261
+ return p;
262
+ }
263
+ emitContainerDistinct() {
264
+ const p = this.baseParams();
265
+ p.set('distinct', this.containerField);
266
+ this.mrdLoadDistinct.emit({
267
+ nodeId: MrdDocumentList.ROOT,
268
+ distinct: this.containerField,
269
+ path: this.buildDataPath() + '/distinct',
270
+ qs: p.toString(),
271
+ });
272
+ }
273
+ emitFolderDistinct(container) {
274
+ var _a;
275
+ const p = this.baseParams();
276
+ p.set('distinct', this.folderField);
277
+ p.set(this.containerField + '_href', (_a = container.href) !== null && _a !== void 0 ? _a : '');
278
+ container.loading = true;
279
+ this.mrdLoadDistinct.emit({
280
+ nodeId: container.id,
281
+ distinct: this.folderField,
282
+ path: this.buildDataPath() + '/distinct',
283
+ qs: p.toString(),
284
+ });
285
+ }
286
+ emitDocuments(container, node) {
287
+ var _a, _b;
288
+ const p = this.baseParams();
289
+ p.set(this.containerField + '_href', (_a = container.href) !== null && _a !== void 0 ? _a : '');
290
+ p.set(this.folderField, (_b = node.fullPath) !== null && _b !== void 0 ? _b : '');
291
+ node.loading = true;
292
+ this.mrdLoadPage.emit({
293
+ nodeId: node.id,
294
+ page: 0,
295
+ sort: '',
296
+ path: this.buildDataPath(),
297
+ qs: p.toString(),
298
+ });
299
+ }
300
+ // ── Public injection API ─────────────────────────────────────────────────
301
+ /** Inject distinct values for a node. `nodeId` is the sentinel root (containers)
302
+ * or a container node id (folders). */
303
+ async setDistinct(nodeId, values) {
304
+ if (nodeId === MrdDocumentList.ROOT) {
305
+ this.applyContainers(values);
306
+ }
307
+ else {
308
+ this.applyFolders(nodeId, values);
309
+ }
310
+ }
311
+ /** Inject the documents loaded for one folder node. */
312
+ async setDocuments(nodeId, docs) {
313
+ const node = this.nodeIndex.get(nodeId);
314
+ if (!node)
315
+ return;
316
+ node.docs = docs !== null && docs !== void 0 ? docs : [];
317
+ node.docsLoaded = true;
318
+ node.loading = false;
319
+ this.bump();
320
+ }
321
+ applyContainers(values) {
322
+ const nodes = [];
323
+ for (const v of values) {
324
+ if (!v.value || typeof v.value !== 'object')
325
+ continue;
326
+ const href = v.value.href;
327
+ const node = this.makeContainerNode(href, v.value.name, v.count);
328
+ nodes.push(node);
329
+ this.nodeIndex.set(node.id, node);
330
+ }
331
+ this.containers = nodes;
332
+ this.rootLoading = false;
333
+ this.singleContainer = nodes.length === 1;
334
+ // Single container (dossier context): collapse the level away, load its folders now.
335
+ if (this.singleContainer) {
336
+ const only = nodes[0];
337
+ only.open = true;
338
+ this.emitFolderDistinct(only);
339
+ }
340
+ }
341
+ applyFolders(containerId, values) {
342
+ const container = this.nodeIndex.get(containerId);
343
+ if (!container)
344
+ return;
345
+ container.children = [];
346
+ container.hasDocs = false;
347
+ container.docCount = 0;
348
+ for (const v of values) {
349
+ const raw = typeof v.value === 'string' ? v.value : v.value == null ? '' : String(v.value);
350
+ const segs = this.splitFolder(raw);
351
+ if (segs.length === 0) {
352
+ // Root documents — the container's own direct documents.
353
+ container.hasDocs = true;
354
+ container.docCount = v.count;
355
+ container.fullPath = raw;
356
+ continue;
357
+ }
358
+ let node = container;
359
+ const acc = [];
360
+ for (const seg of segs) {
361
+ acc.push(seg);
362
+ let child = node.children.find(c => c.label === seg);
363
+ if (!child) {
364
+ child = this.makeFolderNode(container.id + '/' + acc.join('/'), seg, container.id);
365
+ node.children.push(child);
366
+ this.nodeIndex.set(child.id, child);
367
+ }
368
+ node = child;
369
+ }
370
+ node.hasDocs = true;
371
+ node.docCount = v.count;
372
+ node.fullPath = raw;
373
+ }
374
+ this.computeTotals(container);
375
+ container.foldersLoaded = true;
376
+ container.loading = false;
377
+ // If the container has root documents, load them now (they show inline on expand).
378
+ if (container.hasDocs && !container.docsLoaded) {
379
+ this.emitDocuments(container, container);
380
+ }
381
+ this.bump();
382
+ }
383
+ // ── Tree helpers ─────────────────────────────────────────────────────────
384
+ /** Normalise a folder path: null/""/"/" → root ([]); else split on "/" dropping empties. */
385
+ splitFolder(path) {
386
+ if (path == null)
387
+ return [];
388
+ const s = String(path).trim();
389
+ if (s === '' || s === '/')
390
+ return [];
391
+ return s.split('/').map(x => x.trim()).filter(Boolean);
392
+ }
393
+ makeContainerNode(href, label, count) {
394
+ return {
395
+ id: 'c:' + href, kind: 'container', label, href,
396
+ hasDocs: false, docCount: 0, totalCount: count, children: [],
397
+ open: false, loading: false, foldersLoaded: false, docsLoaded: false, docs: [],
398
+ };
399
+ }
400
+ makeFolderNode(id, label, containerId) {
401
+ return {
402
+ id, kind: 'folder', label, containerId,
403
+ hasDocs: false, docCount: 0, totalCount: 0, children: [],
404
+ open: false, loading: false, foldersLoaded: false, docsLoaded: false, docs: [],
405
+ };
406
+ }
407
+ computeTotals(node) {
408
+ let total = node.docCount;
409
+ for (const c of node.children)
410
+ total += this.computeTotals(c);
411
+ node.totalCount = total;
412
+ return total;
413
+ }
414
+ /** Force a re-render after mutating nodes in place. */
415
+ bump() {
416
+ this.containers = [...this.containers];
417
+ }
418
+ // ── Interaction ──────────────────────────────────────────────────────────
419
+ toggleContainer(node) {
420
+ this.selectedId = node.id;
421
+ node.open = !node.open;
422
+ if (node.open && !node.foldersLoaded && !node.loading) {
423
+ this.emitFolderDistinct(node);
424
+ }
425
+ this.bump();
426
+ }
427
+ toggleFolder(container, node) {
428
+ this.selectedId = node.id;
429
+ node.open = !node.open;
430
+ if (node.open && node.hasDocs && !node.docsLoaded && !node.loading) {
431
+ this.emitDocuments(container, node);
432
+ }
433
+ this.bump();
434
+ }
435
+ // ── New folder (client-side pending, materialises on document drop) ─────────
436
+ /** Resolve the node a new folder should be created under, and its container.
437
+ * Uses the current selection; falls back to the single container (dossier). */
438
+ resolveTarget() {
439
+ if (this.selectedId) {
440
+ const n = this.nodeIndex.get(this.selectedId);
441
+ if (n && n.kind === 'container')
442
+ return { target: n, container: n };
443
+ if (n && n.kind === 'folder') {
444
+ const container = n.containerId ? this.nodeIndex.get(n.containerId) : undefined;
445
+ if (container)
446
+ return { target: n, container };
447
+ }
448
+ }
449
+ if (this.singleContainer && this.containers[0]) {
450
+ const only = this.containers[0];
451
+ return { target: only, container: only };
452
+ }
453
+ return null;
454
+ }
455
+ get canCreateFolder() {
456
+ return !this.pendingNode && this.resolveTarget() !== null;
457
+ }
458
+ /** Start creating a folder under the current target. Called by the host toolbar
459
+ * (mrd-document-container). No-op when there is no valid target. */
460
+ async createFolder() {
461
+ this.startCreateFolder();
462
+ }
463
+ /** Folder path segments of a node relative to its container (derived from its id). */
464
+ segmentsOf(node, container) {
465
+ if (node.kind === 'container')
466
+ return [];
467
+ const prefix = container.id + '/';
468
+ const rest = node.id.startsWith(prefix) ? node.id.slice(prefix.length) : '';
469
+ return rest ? rest.split('/') : [];
470
+ }
471
+ commitFolder() {
472
+ const node = this.pendingNode;
473
+ const parent = this.pendingParent;
474
+ const container = this.pendingContainer;
475
+ if (!node || !parent || !container)
476
+ return;
477
+ const name = this.pendingName.trim();
478
+ if (!name) {
479
+ this.cancelFolder();
480
+ return;
481
+ }
482
+ if (name.includes('/')) {
483
+ node.error = t('folder_no_slash', this.locale);
484
+ this.bump();
485
+ return;
486
+ }
487
+ const dup = parent.children.some(c => c !== node && c.label.toLowerCase() === name.toLowerCase());
488
+ if (dup) {
489
+ node.error = t('folder_duplicate', this.locale);
490
+ this.bump();
491
+ return;
492
+ }
493
+ // Finalise: swap the temp id for the real path-derived id so a later distinct
494
+ // value with the same folder string merges onto this node.
495
+ const segs = [...this.segmentsOf(parent, container), name];
496
+ this.nodeIndex.delete(node.id);
497
+ node.id = container.id + '/' + segs.join('/');
498
+ node.fullPath = '/' + segs.join('/');
499
+ node.label = name;
500
+ node.editing = false;
501
+ node.error = undefined;
502
+ node.open = true;
503
+ this.nodeIndex.set(node.id, node);
504
+ this.selectedId = node.id;
505
+ this.clearPending();
506
+ this.bump();
507
+ }
508
+ cancelFolder() {
509
+ const node = this.pendingNode;
510
+ const parent = this.pendingParent;
511
+ if (node && parent) {
512
+ parent.children = parent.children.filter(c => c !== node);
513
+ this.nodeIndex.delete(node.id);
514
+ }
515
+ this.clearPending();
516
+ this.bump();
517
+ }
518
+ clearPending() {
519
+ this.pendingNode = null;
520
+ this.pendingParent = null;
521
+ this.pendingContainer = null;
522
+ this.pendingName = '';
523
+ this.pendingInputEl = null;
524
+ this.pendingNeedsFocus = false;
525
+ }
526
+ /** True when the drag carries external files (an OS file drop, not an internal move). */
527
+ isFileDrag(e) {
528
+ return !this.dragDoc && !!e.dataTransfer && Array.from(e.dataTransfer.types).includes('Files');
529
+ }
530
+ // ── External file drop → upload → create document ──────────────────────────
531
+ /** Begin an upload: emit mrdUpload; the host uploads and calls setFileReference. */
532
+ startFileUpload(e, node, container) {
533
+ var _a, _b;
534
+ const file = (_b = (_a = e.dataTransfer) === null || _a === void 0 ? void 0 : _a.files) === null || _b === void 0 ? void 0 : _b[0]; // single file per drop
535
+ this.dropTargetId = null;
536
+ if (!file)
537
+ return;
538
+ this.pendingUpload = { file, node, container };
539
+ node.open = true;
540
+ this.uploadingNodeId = node.id;
541
+ this.bump();
542
+ this.mrdUpload.emit({ file });
543
+ }
544
+ /** Strip a single trailing extension for the document title. */
545
+ stripExtension(name) {
546
+ return name.replace(/\.[^./\\]+$/, '');
547
+ }
548
+ /** Host callback with the uploaded file reference. Builds the create payload
549
+ * from the archetype slots and requests the new document. */
550
+ async setFileReference(uri) {
551
+ const up = this.pendingUpload;
552
+ if (!up)
553
+ return;
554
+ const { file, node, container } = up;
555
+ const folder = this.folderStringOf(node, container);
556
+ const values = {
557
+ [this.fileField]: uri,
558
+ [this.titleField]: this.stripExtension(file.name),
559
+ [this.folderField]: folder,
560
+ [this.containerField]: container.href,
561
+ };
562
+ this.mrdCreateObject.emit({ path: this.buildDataPath(), values });
563
+ // Optimistically show the new document (no href until a reload).
564
+ const optimistic = { [this.titleField]: this.stripExtension(file.name), _optimistic: true };
565
+ const wasUnloadedEmpty = !node.docsLoaded && node.docCount === 0;
566
+ node.hasDocs = true;
567
+ node.pending = false;
568
+ node.docCount += 1;
569
+ if (wasUnloadedEmpty) {
570
+ node.docsLoaded = true;
571
+ node.docs = [optimistic];
572
+ }
573
+ else if (node.docsLoaded)
574
+ node.docs = [...node.docs, optimistic];
575
+ this.recomputeContainerTotals(container, +1);
576
+ this.lastOptimisticDoc = optimistic;
577
+ this.pendingUpload = null;
578
+ this.uploadingNodeId = null;
579
+ this.bump();
580
+ }
581
+ /** Host callback with the created document's self href, so the optimistic row
582
+ * becomes navigable without waiting for a reload. */
583
+ async setCreatedHref(href) {
584
+ var _a;
585
+ const doc = this.lastOptimisticDoc;
586
+ if (!doc || !href)
587
+ return;
588
+ doc._links = Object.assign(Object.assign({}, ((_a = doc._links) !== null && _a !== void 0 ? _a : {})), { self: { href } });
589
+ doc._optimistic = false;
590
+ this.lastOptimisticDoc = null;
591
+ this.bump();
592
+ }
593
+ /** Folder string a node represents: the raw distinct value when it holds
594
+ * documents, else derived from its path segments; null for a container root. */
595
+ folderStringOf(node, container) {
596
+ if (node.kind === 'container')
597
+ return null;
598
+ if (node.fullPath != null && node.fullPath !== '')
599
+ return node.fullPath;
600
+ const segs = this.segmentsOf(node, container);
601
+ return segs.length ? '/' + segs.join('/') : null;
602
+ }
603
+ moveDocument(toNode, toContainer) {
604
+ var _a, _b;
605
+ const doc = this.dragDoc;
606
+ const fromNode = this.dragFromId ? this.nodeIndex.get(this.dragFromId) : undefined;
607
+ if (!doc || !fromNode)
608
+ return;
609
+ const fromContainer = fromNode.kind === 'container'
610
+ ? fromNode
611
+ : (fromNode.containerId ? this.nodeIndex.get(fromNode.containerId) : undefined);
612
+ if (!fromContainer)
613
+ return;
614
+ const targetFolder = this.folderStringOf(toNode, toContainer);
615
+ const sourceFolder = this.folderStringOf(fromNode, fromContainer);
616
+ const sameContainer = toContainer === fromContainer;
617
+ // No-op: dropped back onto its own folder.
618
+ if (toNode === fromNode || (sameContainer && targetFolder === sourceFolder))
619
+ return;
620
+ // ── Optimistic tree update (fire-and-forget; no refetch) ──
621
+ fromNode.docs = fromNode.docs.filter(d => d !== doc);
622
+ fromNode.docCount = Math.max(0, fromNode.docCount - 1);
623
+ // A now-empty folder should stop showing an expand chevron (it disappears on
624
+ // the next reload anyway, since it is derived from document folder strings).
625
+ if (fromNode.docsLoaded)
626
+ fromNode.hasDocs = fromNode.docs.length > 0;
627
+ toNode.hasDocs = true;
628
+ toNode.pending = false; // a pending folder is now materialised
629
+ toNode.docCount += 1;
630
+ if (toNode.kind === 'folder')
631
+ toNode.fullPath = targetFolder !== null && targetFolder !== void 0 ? targetFolder : '';
632
+ if (toNode.docsLoaded)
633
+ toNode.docs = [...toNode.docs, doc];
634
+ this.recomputeContainerTotals(fromContainer, -1);
635
+ if (!sameContainer)
636
+ this.recomputeContainerTotals(toContainer, +1);
637
+ // ── Emit the generic update; host PATCHes the document ──
638
+ 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;
639
+ if (href) {
640
+ const values = { [this.folderField]: targetFolder };
641
+ if (!sameContainer)
642
+ values[this.containerField] = toContainer.href;
643
+ this.mrdUpdateObject.emit({ href, values });
644
+ }
645
+ this.bump();
646
+ }
647
+ /** Recompute a container's subtree totals from docCounts when its folders are
648
+ * loaded; otherwise just nudge the aggregate badge by the delta. */
649
+ recomputeContainerTotals(container, delta) {
650
+ if (container.foldersLoaded) {
651
+ this.computeTotals(container);
652
+ }
653
+ else {
654
+ container.totalCount = Math.max(0, container.totalCount + delta);
655
+ }
656
+ }
657
+ openDoc(doc) {
658
+ var _a, _b, _c, _d;
659
+ 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;
660
+ 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 : '';
661
+ this.mrdNavigate.emit({ href, label });
662
+ }
663
+ // ── Render ───────────────────────────────────────────────────────────────
664
+ renderChevron(open, leaf) {
665
+ 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" }))));
666
+ }
667
+ renderDossierIcon() {
668
+ 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" })));
669
+ }
670
+ renderFolderIcon() {
671
+ 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" })));
672
+ }
673
+ renderDocIcon() {
674
+ 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" })));
675
+ }
676
+ indent(depth) {
677
+ return h("span", { class: "mrd-document-list__indent", style: { width: `${depth * 18}px` } });
678
+ }
679
+ renderDocRow(doc, node, container, depth) {
680
+ var _a, _b, _c, _d, _e;
681
+ 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 : '';
682
+ const dateRaw = this.dateField ? doc === null || doc === void 0 ? void 0 : doc[this.dateField] : undefined;
683
+ const date = dateRaw ? formatDate(dateRaw, this.locale) : '';
684
+ 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, draggable: true, onClick: () => this.openDoc(doc), onDragStart: (e) => this.onDocDragStart(e, doc, node), onDragEnd: this.onDocDragEnd, onDragOver: (e) => this.onNodeDragOver(e, node), onDragLeave: () => this.onNodeDragLeave(node), onDrop: (e) => this.onNodeDrop(e, node, container) }, this.indent(depth), this.renderChevron(false, true), this.renderDocIcon(), h("span", { class: "mrd-document-list__label" }, label), date && h("span", { class: "mrd-document-list__date" }, date)));
685
+ }
686
+ renderLoadingRow(depth) {
687
+ return (h("div", { class: "mrd-document-list__loading", key: "loading" }, this.indent(depth), h("span", { class: "mrd-document-list__spinner" }), t('loading', this.locale)));
688
+ }
689
+ renderChildren(container, node, depth) {
690
+ const out = [];
691
+ // Direct documents of this node (root docs live on the container node).
692
+ if (node.hasDocs) {
693
+ if (node.docsLoaded) {
694
+ for (const doc of node.docs)
695
+ out.push(this.renderDocRow(doc, node, container, depth));
696
+ }
697
+ else if (node.loading) {
698
+ out.push(this.renderLoadingRow(depth));
699
+ }
700
+ }
701
+ // Child folders.
702
+ for (const child of node.children) {
703
+ out.push(this.renderFolderNode(container, child, depth));
704
+ }
705
+ // An uploading file dropped onto this node.
706
+ if (node.id === this.uploadingNodeId)
707
+ out.push(this.renderUploadingRow(depth));
708
+ return out;
709
+ }
710
+ renderUploadingRow(depth) {
711
+ return (h("div", { class: "mrd-document-list__loading", key: "uploading" }, this.indent(depth), h("span", { class: "mrd-document-list__spinner" }), t('upload_file', this.locale)));
712
+ }
713
+ renderFolderEditRow(node, depth) {
714
+ return (h("div", { class: "mrd-document-list__node", key: node.id }, h("div", { class: "mrd-document-list__row mrd-document-list__row--edit" }, this.indent(depth), this.renderChevron(false, true), this.renderFolderIcon(), h("input", { class: "mrd-document-list__name-input", type: "text", placeholder: t('folder_name_placeholder', this.locale), ref: el => (this.pendingInputEl = el), onInput: this.onPendingInput, onKeyDown: this.onPendingKeyDown, onBlur: () => this.cancelFolder() })), node.error && (h("div", { class: "mrd-document-list__error", style: { paddingLeft: `${depth * 18 + 52}px` } }, node.error))));
715
+ }
716
+ renderFolderNode(container, node, depth) {
717
+ if (node.editing)
718
+ return this.renderFolderEditRow(node, depth);
719
+ const leaf = node.children.length === 0 && !node.hasDocs;
720
+ const selected = node.id === this.selectedId;
721
+ const cls = 'mrd-document-list__row'
722
+ + (selected ? ' mrd-document-list__row--selected' : '')
723
+ + (node.pending ? ' mrd-document-list__row--pending' : '')
724
+ + (node.id === this.dropTargetId ? ' mrd-document-list__row--drop' : '');
725
+ return (h("div", { class: "mrd-document-list__node", key: node.id }, h("div", { class: cls, onClick: () => this.toggleFolder(container, node), onDragOver: (e) => this.onNodeDragOver(e, node), onDragLeave: () => this.onNodeDragLeave(node), onDrop: (e) => this.onNodeDrop(e, node, container) }, this.indent(depth), this.renderChevron(node.open, leaf), this.renderFolderIcon(), 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))));
726
+ }
727
+ renderContainerNode(node, depth) {
728
+ const selected = node.id === this.selectedId;
729
+ const cls = 'mrd-document-list__row mrd-document-list__row--dossier'
730
+ + (selected ? ' mrd-document-list__row--selected' : '')
731
+ + (node.id === this.dropTargetId ? ' mrd-document-list__row--drop' : '');
732
+ return (h("div", { class: "mrd-document-list__node", key: node.id }, h("div", { class: cls, onClick: () => this.toggleContainer(node), onDragOver: (e) => this.onNodeDragOver(e, node), onDragLeave: () => this.onNodeDragLeave(node), onDrop: (e) => this.onNodeDrop(e, node, node) }, this.indent(depth), this.renderChevron(node.open, false), this.renderDossierIcon(), 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
733
+ ? this.renderLoadingRow(depth + 1)
734
+ : this.renderChildren(node, node, depth + 1)))));
735
+ }
736
+ render() {
737
+ let body;
738
+ if (this.rootLoading) {
739
+ body = this.renderLoadingRow(0);
740
+ }
741
+ else if (this.containers.length === 0) {
742
+ body = h("div", { key: 'b8c3297cd7cff5bf79ce694d2ee1a64c570df5ce', class: "mrd-document-list__empty" }, t('no_results', this.locale));
743
+ }
744
+ else if (this.singleContainer) {
745
+ // Dossier context: render the single container's folder tree at the root.
746
+ const only = this.containers[0];
747
+ body = only.loading && !only.foldersLoaded
748
+ ? this.renderLoadingRow(0)
749
+ : this.renderChildren(only, only, 0);
750
+ }
751
+ else {
752
+ body = this.containers.map(c => this.renderContainerNode(c, 0));
753
+ }
754
+ return (h(Host, { key: 'ff3b024a79ba2270aa28861923bc6406f98061aa' }, h("div", { key: '9db121e5336a4e3c82443257f6424db5ab4f0baf', class: "mrd-document-list", onDragOver: this.onRootDragOver, onDrop: this.onRootDrop }, body)));
755
+ }
756
+ static get is() { return "mrd-document-list"; }
757
+ static get encapsulation() { return "scoped"; }
758
+ static get originalStyleUrls() {
759
+ return {
760
+ "$": ["mrd-document-list.scss"]
761
+ };
762
+ }
763
+ static get styleUrls() {
764
+ return {
765
+ "$": ["mrd-document-list.css"]
766
+ };
767
+ }
768
+ static get properties() {
769
+ return {
770
+ "item": {
771
+ "type": "unknown",
772
+ "mutable": false,
773
+ "complexType": {
774
+ "original": "ClientLayoutItem | null",
775
+ "resolved": "ClientLayoutItem | null",
776
+ "references": {
777
+ "ClientLayoutItem": {
778
+ "location": "import",
779
+ "path": "../../types/client-layout",
780
+ "id": "src/types/client-layout.ts::ClientLayoutItem",
781
+ "referenceLocation": "ClientLayoutItem"
782
+ }
783
+ }
784
+ },
785
+ "required": false,
786
+ "optional": false,
787
+ "docs": {
788
+ "tags": [],
789
+ "text": "The VIEW or RELATED_VIEW layout item (dataClass, fromClass, view config)."
790
+ },
791
+ "getter": false,
792
+ "setter": false,
793
+ "defaultValue": "null"
794
+ },
795
+ "archetype": {
796
+ "type": "unknown",
797
+ "mutable": false,
798
+ "complexType": {
799
+ "original": "ClientArchetype",
800
+ "resolved": "ClientArchetype",
801
+ "references": {
802
+ "ClientArchetype": {
803
+ "location": "import",
804
+ "path": "../../types/client-layout",
805
+ "id": "src/types/client-layout.ts::ClientArchetype",
806
+ "referenceLocation": "ClientArchetype"
807
+ }
808
+ }
809
+ },
810
+ "required": true,
811
+ "optional": false,
812
+ "docs": {
813
+ "tags": [],
814
+ "text": "Resolved `commons.document` binding: slot name \u2192 concrete field/relation name."
815
+ },
816
+ "getter": false,
817
+ "setter": false
818
+ },
819
+ "parentId": {
820
+ "type": "string",
821
+ "mutable": false,
822
+ "complexType": {
823
+ "original": "string",
824
+ "resolved": "string",
825
+ "references": {}
826
+ },
827
+ "required": false,
828
+ "optional": false,
829
+ "docs": {
830
+ "tags": [],
831
+ "text": "Parent record id \u2014 required for RELATED_VIEW path building."
832
+ },
833
+ "getter": false,
834
+ "setter": false,
835
+ "reflect": false,
836
+ "attribute": "parent-id",
837
+ "defaultValue": "''"
838
+ },
839
+ "locale": {
840
+ "type": "string",
841
+ "mutable": false,
842
+ "complexType": {
843
+ "original": "string",
844
+ "resolved": "string",
845
+ "references": {}
846
+ },
847
+ "required": false,
848
+ "optional": false,
849
+ "docs": {
850
+ "tags": [],
851
+ "text": ""
852
+ },
853
+ "getter": false,
854
+ "setter": false,
855
+ "reflect": false,
856
+ "attribute": "locale",
857
+ "defaultValue": "navigator.language"
858
+ }
859
+ };
860
+ }
861
+ static get states() {
862
+ return {
863
+ "containers": {},
864
+ "rootLoading": {},
865
+ "singleContainer": {},
866
+ "selectedId": {},
867
+ "dropTargetId": {},
868
+ "uploadingNodeId": {}
869
+ };
870
+ }
871
+ static get events() {
872
+ return [{
873
+ "method": "mrdLoadDistinct",
874
+ "name": "mrdLoadDistinct",
875
+ "bubbles": true,
876
+ "cancelable": true,
877
+ "composed": true,
878
+ "docs": {
879
+ "tags": [],
880
+ "text": "Request distinct values for a field/relation. Host fetches `{path}?{qs}` and calls `setDistinct(nodeId, values)`."
881
+ },
882
+ "complexType": {
883
+ "original": "{ nodeId: string; distinct: string; path: string; qs: string }",
884
+ "resolved": "{ nodeId: string; distinct: string; path: string; qs: string; }",
885
+ "references": {}
886
+ }
887
+ }, {
888
+ "method": "mrdLoadPage",
889
+ "name": "mrdLoadPage",
890
+ "bubbles": true,
891
+ "cancelable": true,
892
+ "composed": true,
893
+ "docs": {
894
+ "tags": [],
895
+ "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)."
896
+ },
897
+ "complexType": {
898
+ "original": "{ nodeId: string; page: number; sort: string; path: string; qs: string }",
899
+ "resolved": "{ nodeId: string; page: number; sort: string; path: string; qs: string; }",
900
+ "references": {}
901
+ }
902
+ }, {
903
+ "method": "mrdNavigate",
904
+ "name": "mrdNavigate",
905
+ "bubbles": true,
906
+ "cancelable": true,
907
+ "composed": true,
908
+ "docs": {
909
+ "tags": [],
910
+ "text": "A document row was clicked. Host routes to the document object page."
911
+ },
912
+ "complexType": {
913
+ "original": "{ href?: string; label: string }",
914
+ "resolved": "{ href?: string | undefined; label: string; }",
915
+ "references": {}
916
+ }
917
+ }, {
918
+ "method": "mrdCanCreate",
919
+ "name": "mrdCanCreate",
920
+ "bubbles": true,
921
+ "cancelable": true,
922
+ "composed": true,
923
+ "docs": {
924
+ "tags": [],
925
+ "text": "Emitted whenever the \"can create a folder here\" state changes, so a host\ntoolbar (mrd-document-container) can enable/disable its New folder button."
926
+ },
927
+ "complexType": {
928
+ "original": "boolean",
929
+ "resolved": "boolean",
930
+ "references": {}
931
+ }
932
+ }, {
933
+ "method": "mrdUpdateObject",
934
+ "name": "mrdUpdateObject",
935
+ "bubbles": true,
936
+ "cancelable": true,
937
+ "composed": true,
938
+ "docs": {
939
+ "tags": [],
940
+ "text": "Generic \"update an existing object\" request \u2014 fired when a document is\ndragged into another folder/container. Host PATCHes `href` with `values`\n(no move/folder knowledge needed). `values` carries the new folder string\n(or null for the container root) and, on a cross-container move, the new\ncontainer relation href."
941
+ },
942
+ "complexType": {
943
+ "original": "{ href: string; values: Record<string, unknown> }",
944
+ "resolved": "{ href: string; values: Record<string, unknown>; }",
945
+ "references": {
946
+ "Record": {
947
+ "location": "global",
948
+ "id": "global::Record"
949
+ }
950
+ }
951
+ }
952
+ }, {
953
+ "method": "mrdUpload",
954
+ "name": "mrdUpload",
955
+ "bubbles": true,
956
+ "cancelable": true,
957
+ "composed": true,
958
+ "docs": {
959
+ "tags": [],
960
+ "text": "An external file was dropped onto a folder/container. Same flow as mrd-form:\nhost uploads the file and calls `setFileReference(uri)` with the result."
961
+ },
962
+ "complexType": {
963
+ "original": "{ file: File }",
964
+ "resolved": "{ file: File; }",
965
+ "references": {
966
+ "File": {
967
+ "location": "global",
968
+ "id": "global::File"
969
+ }
970
+ }
971
+ }
972
+ }, {
973
+ "method": "mrdCreateObject",
974
+ "name": "mrdCreateObject",
975
+ "bubbles": true,
976
+ "cancelable": true,
977
+ "composed": true,
978
+ "docs": {
979
+ "tags": [],
980
+ "text": "Fired once the dropped file is uploaded \u2014 requests creation of a new document.\nHost POSTs `values` to `path` (on a 400 it can open the create form itself)."
981
+ },
982
+ "complexType": {
983
+ "original": "{ path: string; values: Record<string, unknown> }",
984
+ "resolved": "{ path: string; values: Record<string, unknown>; }",
985
+ "references": {
986
+ "Record": {
987
+ "location": "global",
988
+ "id": "global::Record"
989
+ }
990
+ }
991
+ }
992
+ }];
993
+ }
994
+ static get methods() {
995
+ return {
996
+ "setDistinct": {
997
+ "complexType": {
998
+ "signature": "(nodeId: string, values: DistinctValue[]) => Promise<void>",
999
+ "parameters": [{
1000
+ "name": "nodeId",
1001
+ "type": "string",
1002
+ "docs": ""
1003
+ }, {
1004
+ "name": "values",
1005
+ "type": "DistinctValue[]",
1006
+ "docs": ""
1007
+ }],
1008
+ "references": {
1009
+ "Promise": {
1010
+ "location": "global",
1011
+ "id": "global::Promise"
1012
+ },
1013
+ "DistinctValue": {
1014
+ "location": "local",
1015
+ "path": "/Users/michiel/Mosterd/mosterd-components/src/components/mrd-document-list/mrd-document-list.tsx",
1016
+ "id": "src/components/mrd-document-list/mrd-document-list.tsx::DistinctValue"
1017
+ }
1018
+ },
1019
+ "return": "Promise<void>"
1020
+ },
1021
+ "docs": {
1022
+ "text": "Inject distinct values for a node. `nodeId` is the sentinel root (containers)\nor a container node id (folders).",
1023
+ "tags": []
1024
+ }
1025
+ },
1026
+ "setDocuments": {
1027
+ "complexType": {
1028
+ "signature": "(nodeId: string, docs: DocRow[]) => Promise<void>",
1029
+ "parameters": [{
1030
+ "name": "nodeId",
1031
+ "type": "string",
1032
+ "docs": ""
1033
+ }, {
1034
+ "name": "docs",
1035
+ "type": "DocRow[]",
1036
+ "docs": ""
1037
+ }],
1038
+ "references": {
1039
+ "Promise": {
1040
+ "location": "global",
1041
+ "id": "global::Promise"
1042
+ },
1043
+ "DocRow": {
1044
+ "location": "local",
1045
+ "path": "/Users/michiel/Mosterd/mosterd-components/src/components/mrd-document-list/mrd-document-list.tsx",
1046
+ "id": "src/components/mrd-document-list/mrd-document-list.tsx::DocRow"
1047
+ }
1048
+ },
1049
+ "return": "Promise<void>"
1050
+ },
1051
+ "docs": {
1052
+ "text": "Inject the documents loaded for one folder node.",
1053
+ "tags": []
1054
+ }
1055
+ },
1056
+ "createFolder": {
1057
+ "complexType": {
1058
+ "signature": "() => Promise<void>",
1059
+ "parameters": [],
1060
+ "references": {
1061
+ "Promise": {
1062
+ "location": "global",
1063
+ "id": "global::Promise"
1064
+ }
1065
+ },
1066
+ "return": "Promise<void>"
1067
+ },
1068
+ "docs": {
1069
+ "text": "Start creating a folder under the current target. Called by the host toolbar\n(mrd-document-container). No-op when there is no valid target.",
1070
+ "tags": []
1071
+ }
1072
+ },
1073
+ "setFileReference": {
1074
+ "complexType": {
1075
+ "signature": "(uri: string) => Promise<void>",
1076
+ "parameters": [{
1077
+ "name": "uri",
1078
+ "type": "string",
1079
+ "docs": ""
1080
+ }],
1081
+ "references": {
1082
+ "Promise": {
1083
+ "location": "global",
1084
+ "id": "global::Promise"
1085
+ },
1086
+ "Record": {
1087
+ "location": "global",
1088
+ "id": "global::Record"
1089
+ },
1090
+ "DocRow": {
1091
+ "location": "local",
1092
+ "path": "/Users/michiel/Mosterd/mosterd-components/src/components/mrd-document-list/mrd-document-list.tsx",
1093
+ "id": "src/components/mrd-document-list/mrd-document-list.tsx::DocRow"
1094
+ }
1095
+ },
1096
+ "return": "Promise<void>"
1097
+ },
1098
+ "docs": {
1099
+ "text": "Host callback with the uploaded file reference. Builds the create payload\nfrom the archetype slots and requests the new document.",
1100
+ "tags": []
1101
+ }
1102
+ },
1103
+ "setCreatedHref": {
1104
+ "complexType": {
1105
+ "signature": "(href: string) => Promise<void>",
1106
+ "parameters": [{
1107
+ "name": "href",
1108
+ "type": "string",
1109
+ "docs": ""
1110
+ }],
1111
+ "references": {
1112
+ "Promise": {
1113
+ "location": "global",
1114
+ "id": "global::Promise"
1115
+ }
1116
+ },
1117
+ "return": "Promise<void>"
1118
+ },
1119
+ "docs": {
1120
+ "text": "Host callback with the created document's self href, so the optimistic row\nbecomes navigable without waiting for a reload.",
1121
+ "tags": []
1122
+ }
1123
+ }
1124
+ };
1125
+ }
1126
+ static get elementRef() { return "el"; }
1127
+ }
1128
+ /** Root sentinel id for the container-level distinct request. */
1129
+ MrdDocumentList.ROOT = '__root__';