@mmlogic/components 0.5.3 → 0.5.5

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 (85) hide show
  1. package/dist/cjs/{cell-renderer-7KX9Qbml.js → cell-renderer-Mx3pwONr.js} +261 -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_25.cjs.entry.js +391 -77
  5. package/dist/cjs/mrd-merge-view.cjs.entry.js +3 -3
  6. package/dist/collection/components/documents/mrd-document-container/mrd-document-container.css +3 -0
  7. package/dist/collection/components/documents/mrd-document-container/mrd-document-container.js +23 -3
  8. package/dist/collection/components/documents/mrd-document-list/mrd-document-list.js +76 -2
  9. package/dist/collection/components/fields/mrd-currency-field/mrd-currency-field.js +56 -5
  10. package/dist/collection/components/fields/mrd-date-field/mrd-date-field.css +55 -4
  11. package/dist/collection/components/fields/mrd-date-field/mrd-date-field.js +118 -8
  12. package/dist/collection/components/fields/mrd-datetime-field/mrd-datetime-field.css +55 -4
  13. package/dist/collection/components/fields/mrd-datetime-field/mrd-datetime-field.js +117 -15
  14. package/dist/collection/components/fields/mrd-email-field/mrd-email-field.js +1 -1
  15. package/dist/collection/components/fields/mrd-file-field/mrd-file-field.js +1 -1
  16. package/dist/collection/components/fields/mrd-image-field/mrd-image-field.js +1 -1
  17. package/dist/collection/components/fields/mrd-longtext-field/mrd-longtext-field.js +1 -1
  18. package/dist/collection/components/fields/mrd-number-field/mrd-number-field.js +33 -8
  19. package/dist/collection/components/fields/mrd-relation-field/mrd-relation-field.js +13 -3
  20. package/dist/collection/components/fields/mrd-secret-field/mrd-secret-field.js +2 -2
  21. package/dist/collection/components/fields/mrd-text-field/mrd-text-field.js +1 -1
  22. package/dist/collection/components/fields/mrd-textarea-field/mrd-textarea-field.js +1 -1
  23. package/dist/collection/components/fields/mrd-time-field/mrd-time-field.js +1 -1
  24. package/dist/collection/components/form/mrd-field/mrd-field.js +11 -11
  25. package/dist/collection/components/form/mrd-form/mrd-form.js +8 -4
  26. package/dist/collection/components/invoice/mrd-invoice-view/mrd-invoice-view.js +1 -1
  27. package/dist/collection/components/layout/mrd-layout-section/field-value.js +4 -2
  28. package/dist/collection/components/layout/mrd-layout-section/layout-helpers.js +6 -0
  29. package/dist/collection/components/layout/mrd-layout-section/mrd-layout-section.css +4 -0
  30. package/dist/collection/components/layout/mrd-layout-section/mrd-layout-section.js +8 -8
  31. package/dist/collection/components/merge/mrd-merge-view/mrd-merge-view.js +2 -2
  32. package/dist/collection/dev/app.js +58 -13
  33. package/dist/collection/dev/example-data.js +6 -1
  34. package/dist/collection/utils/format.js +160 -0
  35. package/dist/collection/utils/i18n.js +96 -0
  36. package/dist/components/cell-renderer.js +1 -1
  37. package/dist/components/format.js +1 -1
  38. package/dist/components/i18n.js +1 -1
  39. package/dist/components/mrd-currency-field2.js +1 -1
  40. package/dist/components/mrd-date-field2.js +1 -1
  41. package/dist/components/mrd-datetime-field2.js +1 -1
  42. package/dist/components/mrd-document-container2.js +1 -1
  43. package/dist/components/mrd-document-list2.js +1 -1
  44. package/dist/components/mrd-document-view2.js +1 -1
  45. package/dist/components/mrd-email-field2.js +1 -1
  46. package/dist/components/mrd-email-view2.js +1 -1
  47. package/dist/components/mrd-field2.js +1 -1
  48. package/dist/components/mrd-file-field2.js +1 -1
  49. package/dist/components/mrd-form.js +1 -1
  50. package/dist/components/mrd-image-field2.js +1 -1
  51. package/dist/components/mrd-invoice-view2.js +1 -1
  52. package/dist/components/mrd-layout-section.js +1 -1
  53. package/dist/components/mrd-longtext-field2.js +1 -1
  54. package/dist/components/mrd-merge-view.js +1 -1
  55. package/dist/components/mrd-number-field2.js +1 -1
  56. package/dist/components/mrd-relation-field2.js +1 -1
  57. package/dist/components/mrd-secret-field2.js +1 -1
  58. package/dist/components/mrd-table2.js +1 -1
  59. package/dist/components/mrd-text-field2.js +1 -1
  60. package/dist/components/mrd-textarea-field2.js +1 -1
  61. package/dist/components/mrd-time-field2.js +1 -1
  62. package/dist/esm/{cell-renderer-DIsNX9D7.js → cell-renderer-UQOYlDv7.js} +257 -1
  63. package/dist/esm/loader.js +1 -1
  64. package/dist/esm/mosterdcomponents.js +1 -1
  65. package/dist/esm/mrd-boolean-field_25.entry.js +391 -77
  66. package/dist/esm/mrd-merge-view.entry.js +3 -3
  67. package/dist/mosterdcomponents/mosterdcomponents.esm.js +1 -1
  68. package/dist/mosterdcomponents/p-8cc374e0.entry.js +3 -0
  69. package/dist/mosterdcomponents/p-CF--ScWr.js +1 -0
  70. package/dist/mosterdcomponents/{p-4e061416.entry.js → p-d31b71d9.entry.js} +1 -1
  71. package/dist/types/components/documents/mrd-document-container/mrd-document-container.d.ts +7 -0
  72. package/dist/types/components/documents/mrd-document-list/mrd-document-list.d.ts +17 -0
  73. package/dist/types/components/fields/mrd-currency-field/mrd-currency-field.d.ts +13 -0
  74. package/dist/types/components/fields/mrd-date-field/mrd-date-field.d.ts +22 -1
  75. package/dist/types/components/fields/mrd-datetime-field/mrd-datetime-field.d.ts +21 -2
  76. package/dist/types/components/fields/mrd-number-field/mrd-number-field.d.ts +6 -0
  77. package/dist/types/components/fields/mrd-relation-field/mrd-relation-field.d.ts +7 -0
  78. package/dist/types/components/form/mrd-form/mrd-form.d.ts +3 -2
  79. package/dist/types/components/layout/mrd-layout-section/layout-helpers.d.ts +3 -0
  80. package/dist/types/components.d.ts +35 -0
  81. package/dist/types/types/client-layout.d.ts +7 -0
  82. package/dist/types/utils/format.d.ts +34 -0
  83. package/package.json +1 -1
  84. package/dist/mosterdcomponents/p-910ebfee.entry.js +0 -3
  85. package/dist/mosterdcomponents/p-Ce2QDq0t.js +0 -1
@@ -2,7 +2,7 @@
2
2
 
3
3
  var index = require('./index-DVbdkYO3.js');
4
4
  var clientLayout = require('./client-layout-CqVuJumR.js');
5
- var cellRenderer = require('./cell-renderer-7KX9Qbml.js');
5
+ var cellRenderer = require('./cell-renderer-Mx3pwONr.js');
6
6
 
7
7
  /**
8
8
  * Whether a layout item can appear in the merge diff at all. m-n relations
@@ -257,14 +257,14 @@ const MrdMergeView = class {
257
257
  var _a, _b;
258
258
  let stepContent;
259
259
  if (this.step === 'search') {
260
- stepContent = (index.h(MergeSearchStep, { key: '3adb36fb46aa7260641a46a2cf27cc0ef320876f', locale: this.locale, searchQuery: this.searchQuery, searchResults: this.searchResults, isLoading: this.isLoading, onSearchInput: this.handleSearchInput, onSelect: this.handleSelect }));
260
+ stepContent = (index.h(MergeSearchStep, { key: 'b965c21176faf7844e58cb156958fa1305d07cdc', locale: this.locale, searchQuery: this.searchQuery, searchResults: this.searchResults, isLoading: this.isLoading, onSearchInput: this.handleSearchInput, onSelect: this.handleSelect }));
261
261
  }
262
262
  else {
263
263
  const diff = diffFields(this.fields, this.currentRecord, this.candidate);
264
264
  const bLabel = candidateLabel(this.candidate);
265
265
  stepContent = this.step === 'compare' ? (index.h(MergeCompareStep, { locale: this.locale, currentLabel: this.currentLabel, candidateLabel: bLabel, conflicts: diff.conflicts, autoFilled: diff.autoFilled, recordA: this.currentRecord, recordB: (_a = this.candidate) !== null && _a !== void 0 ? _a : {}, resolutions: this.resolutions, openHistoryKey: this.openHistoryKey, onResolve: this.handleResolve, onToggleHistory: this.handleToggleHistory, onChangeCandidate: this.handleChangeCandidate, onContinue: this.handleContinue })) : (index.h(MergeConfirmStep, { locale: this.locale, candidateLabel: bLabel, conflicts: diff.conflicts, autoFilled: diff.autoFilled, resolutions: this.resolutions, recordB: (_b = this.candidate) !== null && _b !== void 0 ? _b : {}, openHistoryKey: this.openHistoryKey, onToggleHistory: this.handleToggleHistory, onBack: this.handleBack, onConfirm: this.handleConfirm }));
266
266
  }
267
- return (index.h(index.Host, { key: 'e33a6d66a220b28cc9533da78dc274e2d7ec5c4a' }, index.h("div", { key: 'b5fb1390d86192f9f6f15e3ccb89e2d21d9c7c8b', class: "mrd-merge-view" }, stepContent)));
267
+ return (index.h(index.Host, { key: 'e9cffda6c5cff51f802b044f3d8e417df83b7846' }, index.h("div", { key: '26690ef2db7489cbf7994191ad19491a0fdd7002', class: "mrd-merge-view" }, stepContent)));
268
268
  }
269
269
  get el() { return index.getElement(this); }
270
270
  };
@@ -42,6 +42,9 @@
42
42
  opacity: 0.5;
43
43
  cursor: not-allowed;
44
44
  }
45
+ .mrd-document-container__file-input {
46
+ display: none;
47
+ }
45
48
  .mrd-document-container__seg {
46
49
  display: inline-flex;
47
50
  gap: 2px;
@@ -32,12 +32,28 @@ export class MrdDocumentContainer {
32
32
  this.mode = 'tree';
33
33
  /** Whether the folder tree currently has a valid target for "New folder". */
34
34
  this.canCreate = false;
35
+ /** Name of that target (folder path, or the container's label), for the upload tooltip. */
36
+ this.targetLabel = '';
35
37
  /** Whether the currently mounted table has been init()'d. Reset on every mode switch. */
36
38
  this.tableInited = false;
37
39
  this.createFolder = () => {
38
40
  var _a;
39
41
  (_a = this.listEl) === null || _a === void 0 ? void 0 : _a.createFolder();
40
42
  };
43
+ this.pickFile = () => {
44
+ var _a;
45
+ (_a = this.fileInputEl) === null || _a === void 0 ? void 0 : _a.click();
46
+ };
47
+ /** One file per upload, matching the drop handler. Reset the input afterwards
48
+ * so picking the same file twice in a row still fires a change event. */
49
+ this.onFilePicked = (e) => {
50
+ var _a, _b;
51
+ const input = e.target;
52
+ const file = (_a = input.files) === null || _a === void 0 ? void 0 : _a[0];
53
+ if (file)
54
+ (_b = this.listEl) === null || _b === void 0 ? void 0 : _b.uploadFile(file);
55
+ input.value = '';
56
+ };
41
57
  }
42
58
  /** The embedded table does not self-load: like every mrd-table it waits for the
43
59
  * host to call init() (which emits mrdLoadPage, and — once page 0 lands —
@@ -62,7 +78,7 @@ export class MrdDocumentContainer {
62
78
  }
63
79
  // ── Toolbar ────────────────────────────────────────────────────────────────
64
80
  renderToolbar() {
65
- return (h("div", { class: "mrd-document-container__toolbar" }, this.mode === 'tree' && (h("button", { type: "button", class: "mrd-document-container__action", disabled: !this.canCreate, onClick: this.createFolder }, 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: "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" }), h("path", { d: "M12 11v4M10 13h4" })), t('new_folder', this.locale))), h("div", { class: "mrd-document-container__seg", role: "group", "aria-label": t('doc_view_switch', this.locale) }, h("button", { class: "mrd-document-container__seg-btn", "aria-pressed": String(this.mode === 'tree'), title: t('doc_view_tree', this.locale), "aria-label": t('doc_view_tree', this.locale), onClick: () => this.setMode('tree') }, 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: "M3 5h6M3 12h9M3 19h6" }), h("circle", { cx: "18", cy: "5", r: "1.6" }), h("circle", { cx: "18", cy: "19", r: "1.6" }), h("path", { d: "M16 12h4" }))), h("button", { class: "mrd-document-container__seg-btn", "aria-pressed": String(this.mode === 'list'), title: t('doc_view_list', this.locale), "aria-label": t('doc_view_list', this.locale), onClick: () => this.setMode('list') }, h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01" }))))));
81
+ return (h("div", { class: "mrd-document-container__toolbar" }, this.mode === 'tree' && (h("button", { type: "button", class: "mrd-document-container__action", disabled: !this.canCreate, onClick: this.createFolder }, 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: "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" }), h("path", { d: "M12 11v4M10 13h4" })), t('new_folder', this.locale))), this.mode === 'tree' && (h("button", { type: "button", class: "mrd-document-container__action", disabled: !this.canCreate, title: this.targetLabel ? `${t('doc_upload_to', this.locale)} ${this.targetLabel}` : undefined, onClick: this.pickFile }, 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: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }), h("path", { d: "M12 3v13M7 8l5-5 5 5" })), t('doc_upload', this.locale))), h("input", { type: "file", class: "mrd-document-container__file-input", ref: el => (this.fileInputEl = el), onChange: this.onFilePicked }), h("div", { class: "mrd-document-container__seg", role: "group", "aria-label": t('doc_view_switch', this.locale) }, h("button", { class: "mrd-document-container__seg-btn", "aria-pressed": String(this.mode === 'tree'), title: t('doc_view_tree', this.locale), "aria-label": t('doc_view_tree', this.locale), onClick: () => this.setMode('tree') }, 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: "M3 5h6M3 12h9M3 19h6" }), h("circle", { cx: "18", cy: "5", r: "1.6" }), h("circle", { cx: "18", cy: "19", r: "1.6" }), h("path", { d: "M16 12h4" }))), h("button", { class: "mrd-document-container__seg-btn", "aria-pressed": String(this.mode === 'list'), title: t('doc_view_list', this.locale), "aria-label": t('doc_view_list', this.locale), onClick: () => this.setMode('list') }, h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01" }))))));
66
82
  }
67
83
  // ── Bodies ───────────────────────────────────────────────────────────────
68
84
  renderTree() {
@@ -78,6 +94,9 @@ export class MrdDocumentContainer {
78
94
  }, onMrdCanCreate: (e) => {
79
95
  e.stopPropagation();
80
96
  this.canCreate = e.detail;
97
+ }, onMrdTargetLabel: (e) => {
98
+ e.stopPropagation();
99
+ this.targetLabel = e.detail;
81
100
  }, onMrdUpdateObject: (e) => {
82
101
  e.stopPropagation();
83
102
  this.mrdUpdateObject.emit(e.detail);
@@ -114,7 +133,7 @@ export class MrdDocumentContainer {
114
133
  }
115
134
  render() {
116
135
  const treeMode = this.mode === 'tree';
117
- return (h(Host, { key: '4d21f26c956773c63cbf5118394c6afa29d6014d' }, this.renderToolbar(), h("div", { key: 'bc070236bf9a7d0eba57aa2cd70fa3ae36cbf5f1', class: {
136
+ return (h(Host, { key: 'ae948e2458d9087179e850b527802c489067d93f' }, this.renderToolbar(), h("div", { key: 'a04e1a78413aa794d0bda551aeb9c6245f1aafa2', class: {
118
137
  'mrd-document-container__body': true,
119
138
  'mrd-document-container__body--tree': treeMode,
120
139
  }, style: treeMode ? { height: `${this.height}px`, overflowY: 'auto' } : {} }, treeMode ? this.renderTree() : this.renderList())));
@@ -287,7 +306,8 @@ export class MrdDocumentContainer {
287
306
  static get states() {
288
307
  return {
289
308
  "mode": {},
290
- "canCreate": {}
309
+ "canCreate": {},
310
+ "targetLabel": {}
291
311
  };
292
312
  }
293
313
  static get events() {
@@ -64,6 +64,8 @@ export class MrdDocumentList {
64
64
  this.newFolderSeq = 0;
65
65
  /** Last emitted canCreateFolder value, to only emit mrdCanCreate on change. */
66
66
  this.lastCanCreate = false;
67
+ /** Last emitted upload-target label, to only emit mrdTargetLabel on change. */
68
+ this.lastTargetLabel = '';
67
69
  // ── Drag & drop (move a document into another folder) ──────────────────────
68
70
  /** The document row currently being dragged. */
69
71
  this.dragDoc = null;
@@ -237,6 +239,22 @@ export class MrdDocumentList {
237
239
  this.lastCanCreate = can;
238
240
  this.mrdCanCreate.emit(can);
239
241
  }
242
+ const label = this.targetLabel;
243
+ if (label !== this.lastTargetLabel) {
244
+ this.lastTargetLabel = label;
245
+ this.mrdTargetLabel.emit(label);
246
+ }
247
+ }
248
+ /** Human-readable name of the node a new folder or upload lands in — the
249
+ * folder path when one is selected, otherwise the container's own label.
250
+ * Empty when there is no target at all. */
251
+ get targetLabel() {
252
+ var _a;
253
+ const resolved = this.resolveTarget();
254
+ if (!resolved)
255
+ return '';
256
+ const { target, container } = resolved;
257
+ return (_a = folderStringOf(target, container)) !== null && _a !== void 0 ? _a : target.label;
240
258
  }
241
259
  // ── Slot field names ─────────────────────────────────────────────────────
242
260
  get containerField() {
@@ -510,12 +528,28 @@ export class MrdDocumentList {
510
528
  this.dropTargetId = null;
511
529
  if (!file)
512
530
  return;
531
+ this.beginUpload(file, node, container);
532
+ }
533
+ /** Shared by the file drop and the host toolbar's upload button. */
534
+ beginUpload(file, node, container) {
513
535
  this.pendingUpload = { file, node, container };
514
536
  node.open = true;
515
537
  this.uploadingNodeId = node.id;
516
538
  this.bump();
517
539
  this.mrdUpload.emit({ file });
518
540
  }
541
+ /** Upload a file into the current target — the selected folder/container, or
542
+ * the only container when there is just one. Called by the host toolbar
543
+ * (mrd-document-container). No-op without a target, or while another upload
544
+ * is still awaiting its setFileReference. */
545
+ async uploadFile(file) {
546
+ if (!file || this.pendingUpload)
547
+ return;
548
+ const resolved = this.resolveTarget();
549
+ if (!resolved)
550
+ return;
551
+ this.beginUpload(file, resolved.target, resolved.container);
552
+ }
519
553
  /** Host callback with the uploaded file reference. Builds the create payload
520
554
  * from the archetype slots and requests the new document. */
521
555
  async setFileReference(uri) {
@@ -650,7 +684,7 @@ export class MrdDocumentList {
650
684
  body = renderLoadingRow(ctx, 0);
651
685
  }
652
686
  else if (this.containers.length === 0) {
653
- body = h("div", { key: '308725d741deb384082bd514edd34593f7d662a2', class: "mrd-document-list__empty" }, t('no_results', this.locale));
687
+ body = h("div", { key: '63604a99fc62d9108f61b8efc126c0cd3e8fc5ed', class: "mrd-document-list__empty" }, t('no_results', this.locale));
654
688
  }
655
689
  else if (this.singleContainer) {
656
690
  // Dossier context: render the single container's folder tree at the root.
@@ -668,7 +702,7 @@ export class MrdDocumentList {
668
702
  else {
669
703
  body = this.containers.map(c => renderContainerNode(ctx, c, 0));
670
704
  }
671
- return (h(Host, { key: '9d5fde912999b57a0f0b737980d59e94f385f11d' }, h("div", { key: '17191411c2e626995f08b66bad755342fe3b13ae', class: 'mrd-document-list' + (this.rootDropActive ? ' mrd-document-list--drop-active' : ''), onDragOver: this.onRootDragOver, onDragLeave: this.onRootDragLeave, onDrop: this.onRootDrop }, body)));
705
+ return (h(Host, { key: '2a092e3a7483deb1fb30753b0c0428aaf75c303a' }, h("div", { key: '2b716c912a272b925a95133de5b1ff2abedd9dbc', class: 'mrd-document-list' + (this.rootDropActive ? ' mrd-document-list--drop-active' : ''), onDragOver: this.onRootDragOver, onDragLeave: this.onRootDragLeave, onDrop: this.onRootDrop }, body)));
672
706
  }
673
707
  static get is() { return "mrd-document-list"; }
674
708
  static get encapsulation() { return "scoped"; }
@@ -880,6 +914,21 @@ export class MrdDocumentList {
880
914
  "resolved": "boolean",
881
915
  "references": {}
882
916
  }
917
+ }, {
918
+ "method": "mrdTargetLabel",
919
+ "name": "mrdTargetLabel",
920
+ "bubbles": true,
921
+ "cancelable": true,
922
+ "composed": true,
923
+ "docs": {
924
+ "tags": [],
925
+ "text": "Emitted whenever the current target changes: the folder path a new folder or\nupload lands in, or the container's label when no folder is selected. Empty\nwhen there is no target. Lets a host toolbar name the destination."
926
+ },
927
+ "complexType": {
928
+ "original": "string",
929
+ "resolved": "string",
930
+ "references": {}
931
+ }
883
932
  }, {
884
933
  "method": "mrdUpdateObject",
885
934
  "name": "mrdUpdateObject",
@@ -1023,6 +1072,31 @@ export class MrdDocumentList {
1023
1072
  "tags": []
1024
1073
  }
1025
1074
  },
1075
+ "uploadFile": {
1076
+ "complexType": {
1077
+ "signature": "(file: File) => Promise<void>",
1078
+ "parameters": [{
1079
+ "name": "file",
1080
+ "type": "File",
1081
+ "docs": ""
1082
+ }],
1083
+ "references": {
1084
+ "Promise": {
1085
+ "location": "global",
1086
+ "id": "global::Promise"
1087
+ },
1088
+ "File": {
1089
+ "location": "global",
1090
+ "id": "global::File"
1091
+ }
1092
+ },
1093
+ "return": "Promise<void>"
1094
+ },
1095
+ "docs": {
1096
+ "text": "Upload a file into the current target \u2014 the selected folder/container, or\nthe only container when there is just one. Called by the host toolbar\n(mrd-document-container). No-op without a target, or while another upload\nis still awaiting its setFileReference.",
1097
+ "tags": []
1098
+ }
1099
+ },
1026
1100
  "setFileReference": {
1027
1101
  "complexType": {
1028
1102
  "signature": "(uri: string) => Promise<void>",
@@ -1,5 +1,5 @@
1
1
  import { Host, h } from "@stencil/core";
2
- import { parseLocalizedNumber } from "../../../utils/format";
2
+ import { formatNumber, parseLocalizedNumber } from "../../../utils/format";
3
3
  import { FieldLabel, FieldError, controlClass, requiredError } from "../field-helpers";
4
4
  const COMMON_CURRENCIES = [
5
5
  'EUR', 'USD', 'GBP', 'CHF', 'JPY', 'CNY', 'AUD', 'CAD',
@@ -17,13 +17,26 @@ export class MrdCurrencyField {
17
17
  this.amountDisplay = '';
18
18
  this.currency = 'EUR';
19
19
  this.error = '';
20
+ /** While focused the user owns the text; prop updates must not overwrite it. */
21
+ this.focused = false;
20
22
  this.handleAmountInput = (e) => {
21
23
  this.amountDisplay = e.target.value;
22
24
  };
25
+ this.handleAmountFocus = () => {
26
+ this.focused = true;
27
+ // Drop the grouping separators while editing, but keep the locale's decimal
28
+ // separator: String(1234.56) would be re-read as 123456 where '.' groups.
29
+ const parsed = parseLocalizedNumber(this.amountDisplay, this.locale);
30
+ if (parsed !== null) {
31
+ this.amountDisplay = formatNumber(parsed, this.locale, { useGrouping: false, maximumFractionDigits: 20 });
32
+ }
33
+ };
23
34
  this.handleAmountBlur = (e) => {
35
+ this.focused = false;
24
36
  const raw = e.target.value;
25
37
  const parsed = parseLocalizedNumber(raw, this.locale);
26
38
  this.error = requiredError(raw, this.required, this.locale);
39
+ this.amountDisplay = parsed !== null ? this.formatAmount(parsed) : '';
27
40
  const val = { amount: parsed, currency: this.currency };
28
41
  this.mrdChange.emit({ name: this.name, value: val });
29
42
  this.mrdBlur.emit({ name: this.name, value: val });
@@ -35,14 +48,43 @@ export class MrdCurrencyField {
35
48
  };
36
49
  }
37
50
  componentWillLoad() {
38
- if (this.value) {
39
- this.currency = this.value.currency || 'EUR';
40
- this.amountDisplay = this.value.amount !== null ? String(this.value.amount) : '';
51
+ this.syncFromValue();
52
+ }
53
+ componentDidRender() {
54
+ // A rendered `selected` attribute is ignored once the select has an established
55
+ // value, so the currency is applied imperatively — same reason as the DROPDOWN
56
+ // preselect in mrd-relation-field. Without this an edit-mode record that loads
57
+ // after mount keeps showing EUR and would be saved back with the wrong currency.
58
+ if (this.selectEl && this.selectEl.value !== this.currency) {
59
+ this.selectEl.value = this.currency;
41
60
  }
42
61
  }
62
+ /** The record's own currency may sit outside the common list; never drop it. */
63
+ currencyOptions() {
64
+ return COMMON_CURRENCIES.includes(this.currency) ? COMMON_CURRENCIES : [this.currency, ...COMMON_CURRENCIES];
65
+ }
66
+ /** Edit mode loads the record after mount, so the incoming value must re-sync. */
67
+ valueChanged() {
68
+ if (!this.focused)
69
+ this.syncFromValue();
70
+ }
71
+ localeChanged() {
72
+ if (!this.focused)
73
+ this.syncFromValue();
74
+ }
75
+ syncFromValue() {
76
+ const value = this.value;
77
+ this.currency = (value === null || value === void 0 ? void 0 : value.currency) || 'EUR';
78
+ this.amountDisplay =
79
+ (value === null || value === void 0 ? void 0 : value.amount) !== null && (value === null || value === void 0 ? void 0 : value.amount) !== undefined ? this.formatAmount(value.amount) : '';
80
+ }
81
+ /** Display form: locale separators, always two decimals. The ISO code sits in the select. */
82
+ formatAmount(amount) {
83
+ return formatNumber(amount, this.locale, { minimumFractionDigits: 2, maximumFractionDigits: 2 });
84
+ }
43
85
  render() {
44
86
  const hasError = !!this.error;
45
- return (h(Host, { key: 'e1a76ab778820c0d781d5ec1549448716d368c1f' }, h("div", { key: '8298720abac7f689fe3e697c3c4410702e6a87f2', class: "mrd-currency-field" }, h(FieldLabel, { key: 'b23782aef9a866f1fb72e152cb91aeae00a975fa', base: "mrd-currency-field", label: this.label, required: this.required }), h("div", { key: '51e5177f9be3c5a6bdf3a5c1187f9261fcc349cf', class: "mrd-currency-field__row" }, h("input", { key: 'c6bda6cc92f3a2a34861d44b6163d417e200a6e4', class: controlClass('mrd-currency-field', hasError, 'amount'), type: "text", inputMode: "decimal", name: `${this.name}_amount`, value: this.amountDisplay, placeholder: "0.00", required: this.required, disabled: this.disabled, onInput: this.handleAmountInput, onBlur: this.handleAmountBlur }), h("select", { key: '29231cfa142d26aa81594609f1bf7bd5168df073', 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))))), h(FieldError, { key: 'bea9615466427631f08a6ac8a779ae77695d36e3', base: "mrd-currency-field", error: this.error }))));
87
+ return (h(Host, { key: '43ef1fe660c4eaef025203544916b077975b6aa3' }, h("div", { key: '00b8e79182c8e2a353d57ad5c341024caf00d4ea', class: "mrd-currency-field" }, h(FieldLabel, { key: '96835c311e0d490864c484b818f1dcc623f488b2', base: "mrd-currency-field", label: this.label, required: this.required }), h("div", { key: '80317cfe562af00cc4cbf9aabf4bac2126cf6fe5', class: "mrd-currency-field__row" }, h("input", { key: '1983ef1e4d19e0fc529cf5e8be7d287fea36620a', class: controlClass('mrd-currency-field', hasError, 'amount'), type: "text", inputMode: "decimal", name: `${this.name}_amount`, value: this.amountDisplay, placeholder: this.formatAmount(0), required: this.required, disabled: this.disabled, onInput: this.handleAmountInput, onFocus: this.handleAmountFocus, onBlur: this.handleAmountBlur }), h("select", { key: 'b5fe3f03590bebaa564d76bc5fcb47c327eacece', class: "mrd-currency-field__currency", ref: el => (this.selectEl = el), disabled: this.disabled, onChange: this.handleCurrencyChange }, this.currencyOptions().map(c => (h("option", { key: c, value: c, selected: c === this.currency }, c))))), h(FieldError, { key: '1a128b26293170d4137f787622d4e89a23e62c0b', base: "mrd-currency-field", error: this.error }))));
46
88
  }
47
89
  static get is() { return "mrd-currency-field"; }
48
90
  static get encapsulation() { return "scoped"; }
@@ -239,4 +281,13 @@ export class MrdCurrencyField {
239
281
  }
240
282
  }];
241
283
  }
284
+ static get watchers() {
285
+ return [{
286
+ "propName": "value",
287
+ "methodName": "valueChanged"
288
+ }, {
289
+ "propName": "locale",
290
+ "methodName": "localeChanged"
291
+ }];
292
+ }
242
293
  }
@@ -19,6 +19,10 @@
19
19
  content: " *";
20
20
  color: var(--mrd-color-danger);
21
21
  }
22
+ .mrd-date-field__control {
23
+ position: relative;
24
+ display: block;
25
+ }
22
26
  .mrd-date-field__input {
23
27
  display: block;
24
28
  width: 100%;
@@ -53,12 +57,59 @@
53
57
  .mrd-date-field__input--error:focus {
54
58
  box-shadow: var(--mrd-shadow-focus-error);
55
59
  }
60
+ .mrd-date-field__input {
61
+ padding-inline-end: calc(var(--mrd-input-padding-x) + 1.75rem);
62
+ }
63
+ .mrd-date-field__picker {
64
+ position: absolute;
65
+ inset-inline-end: var(--mrd-space-1);
66
+ top: 50%;
67
+ transform: translateY(-50%);
68
+ width: 1.75rem;
69
+ height: 1.75rem;
70
+ }
71
+ .mrd-date-field__picker-button {
72
+ display: inline-flex;
73
+ align-items: center;
74
+ justify-content: center;
75
+ width: 100%;
76
+ height: 100%;
77
+ padding: 0;
78
+ border: 0;
79
+ border-radius: var(--mrd-border-radius-sm);
80
+ background: transparent;
81
+ color: var(--mrd-color-neutral-500);
82
+ cursor: pointer;
83
+ transition: color var(--mrd-transition), background-color var(--mrd-transition);
84
+ }
85
+ .mrd-date-field__picker-button svg {
86
+ width: 1.125rem;
87
+ height: 1.125rem;
88
+ }
89
+ .mrd-date-field__picker-button:hover:not(:disabled) {
90
+ color: var(--mrd-color-primary);
91
+ background-color: var(--mrd-color-neutral-100);
92
+ }
93
+ .mrd-date-field__picker-button:focus-visible {
94
+ outline: 2px solid var(--mrd-border-color-focus);
95
+ outline-offset: 1px;
96
+ }
97
+ .mrd-date-field__picker-button:disabled {
98
+ cursor: not-allowed;
99
+ opacity: 0.5;
100
+ }
101
+ .mrd-date-field__picker-native {
102
+ position: absolute;
103
+ inset: 0;
104
+ width: 100%;
105
+ height: 100%;
106
+ padding: 0;
107
+ border: 0;
108
+ opacity: 0;
109
+ pointer-events: none;
110
+ }
56
111
  .mrd-date-field__error {
57
112
  font-family: var(--mrd-font-family);
58
113
  font-size: var(--mrd-error-font-size);
59
114
  color: var(--mrd-error-color);
60
- }
61
-
62
- .mrd-date-field__input {
63
- cursor: pointer;
64
115
  }
@@ -1,26 +1,106 @@
1
1
  import { Host, h } from "@stencil/core";
2
+ import { t } from "../../../utils/i18n";
3
+ import { formatIsoDate, localeDatePattern, parseLocalizedDate } from "../../../utils/format";
2
4
  import { FieldLabel, FieldError, controlClass, requiredError } from "../field-helpers";
3
5
  export class MrdDateField {
4
6
  constructor() {
5
7
  this.name = '';
6
8
  this.label = '';
9
+ /** ISO date, 'YYYY-MM-DD'. */
7
10
  this.value = '';
11
+ /** Overrides the locale-derived pattern placeholder (e.g. 'dd-mm-jjjj'). */
12
+ this.placeholder = '';
8
13
  this.required = false;
9
14
  this.disabled = false;
10
15
  this.locale = navigator.language;
16
+ /** What the user sees: the value formatted for `locale`, or their raw typing. */
17
+ this.displayValue = '';
11
18
  this.error = '';
12
- this.handleChange = (e) => {
13
- const val = e.target.value;
14
- this.error = requiredError(val, this.required, this.locale);
15
- this.mrdChange.emit({ name: this.name, value: val });
19
+ /** While focused the user owns the text; prop updates must not overwrite it. */
20
+ this.focused = false;
21
+ this.handleFocus = () => {
22
+ this.focused = true;
23
+ };
24
+ this.handleInput = (e) => {
25
+ this.displayValue = e.target.value;
16
26
  };
17
27
  this.handleBlur = (e) => {
18
- const val = e.target.value;
19
- this.mrdBlur.emit({ name: this.name, value: val });
28
+ this.focused = false;
29
+ const value = this.commit(e.target.value);
30
+ this.mrdChange.emit({ name: this.name, value });
31
+ this.mrdBlur.emit({ name: this.name, value });
32
+ };
33
+ this.handleKeyDown = (e) => {
34
+ // Submitting with Enter never fires blur, so commit the typed text here too.
35
+ if (e.key !== 'Enter')
36
+ return;
37
+ const value = this.commit(e.target.value);
38
+ this.mrdChange.emit({ name: this.name, value });
39
+ };
40
+ this.openPicker = () => {
41
+ const native = this.nativeInput;
42
+ if (!native || this.disabled)
43
+ return;
44
+ // The blur commit that precedes this click re-renders asynchronously, so sync by hand first.
45
+ native.value = this.currentIso();
46
+ try {
47
+ native.showPicker();
48
+ }
49
+ catch (_a) {
50
+ // Browsers without showPicker(): focusing at least surfaces the platform control.
51
+ native.focus();
52
+ }
20
53
  };
54
+ this.handlePickerChange = (e) => {
55
+ const iso = e.target.value; // native inputs always yield 'YYYY-MM-DD'
56
+ this.displayValue = formatIsoDate(iso, this.locale);
57
+ this.error = requiredError(iso, this.required, this.locale);
58
+ this.mrdChange.emit({ name: this.name, value: iso });
59
+ this.mrdBlur.emit({ name: this.name, value: iso });
60
+ };
61
+ }
62
+ componentWillLoad() {
63
+ this.displayValue = formatIsoDate(this.value, this.locale);
64
+ }
65
+ valueChanged(newValue) {
66
+ if (!this.focused)
67
+ this.displayValue = formatIsoDate(newValue, this.locale);
68
+ }
69
+ localeChanged() {
70
+ if (!this.focused)
71
+ this.displayValue = formatIsoDate(this.value, this.locale);
72
+ }
73
+ patternPlaceholder() {
74
+ if (this.placeholder)
75
+ return this.placeholder;
76
+ return localeDatePattern(this.locale, {
77
+ day: t('date_token_day', this.locale),
78
+ month: t('date_token_month', this.locale),
79
+ year: t('date_token_year', this.locale),
80
+ });
81
+ }
82
+ /** Parse the typed text, reformat it, and emit the ISO value. */
83
+ commit(raw) {
84
+ const trimmed = raw.trim();
85
+ const iso = trimmed ? parseLocalizedDate(trimmed, this.locale) : '';
86
+ if (trimmed && iso === null) {
87
+ // Keep the raw text so the user can correct it instead of retyping.
88
+ this.error = t('invalid_date', this.locale);
89
+ this.displayValue = trimmed;
90
+ }
91
+ else {
92
+ this.error = requiredError(iso, this.required, this.locale);
93
+ this.displayValue = iso ? formatIsoDate(iso, this.locale) : '';
94
+ }
95
+ return iso !== null && iso !== void 0 ? iso : '';
96
+ }
97
+ /** The ISO value currently shown, so the picker opens on the right date. */
98
+ currentIso() {
99
+ var _a;
100
+ return (_a = (this.displayValue ? parseLocalizedDate(this.displayValue, this.locale) : '')) !== null && _a !== void 0 ? _a : '';
21
101
  }
22
102
  render() {
23
- return (h(Host, { key: 'd83beef11c2b9402e251a50885b92e7a057f02ee' }, h("div", { key: '6a26e4969e9bde8c5c87771d7b8c7b4d6c1dd942', class: "mrd-date-field" }, h(FieldLabel, { key: 'a7bc1b1c56e933a51f6b1b1feb794a4678d9d334', base: "mrd-date-field", label: this.label, required: this.required }), h("input", { key: '82e3855654f3b3c554f80d647e783234cca8dae1', class: controlClass('mrd-date-field', !!this.error), type: "date", name: this.name, value: this.value, required: this.required, disabled: this.disabled, onChange: this.handleChange, onBlur: this.handleBlur }), h(FieldError, { key: '294b3cdc1004725267aa8265366f5009ab324203', base: "mrd-date-field", error: this.error }))));
103
+ return (h(Host, { key: '06ba48bd538ee4c8de4e071285535451f783c259' }, h("div", { key: '73ea6ea23c85fe3325bb151afb755cc11a13cf58', class: "mrd-date-field" }, h(FieldLabel, { key: '527848cf72323aef176fc7d5bcd47dcf2f7e46f6', base: "mrd-date-field", label: this.label, required: this.required }), h("div", { key: '2ff7586f4e6298d1f9b9b131106044533de82c6d', class: "mrd-date-field__control" }, h("input", { key: '68fdf2f1f7961ca049ab6493494c8c0707e6a4af', class: controlClass('mrd-date-field', !!this.error), type: "text", name: this.name, value: this.displayValue, placeholder: this.patternPlaceholder(), autocomplete: "off", required: this.required, disabled: this.disabled, onFocus: this.handleFocus, onInput: this.handleInput, onBlur: this.handleBlur, onKeyDown: this.handleKeyDown }), h("span", { key: '9557b7a3f6780b8a05030ab8e7c941c44df9f4a5', class: "mrd-date-field__picker" }, h("button", { key: '586973e0440ed0b74e1fa0affae9e462257024c3', type: "button", class: "mrd-date-field__picker-button", title: t('open_calendar', this.locale), "aria-label": t('open_calendar', this.locale), disabled: this.disabled, onClick: this.openPicker }, h("svg", { key: '144319d3a50d0d38c75c59dd3321d4b9097322a6', viewBox: "0 0 20 20", fill: "none", stroke: "currentColor", "stroke-width": "1.5", "aria-hidden": "true" }, h("rect", { key: 'aec01ca5c620bf3116705b7a28052eb3bc210cfd', x: "3", y: "4.5", width: "14", height: "12", rx: "2" }), h("path", { key: 'a0e13dd3a2005bfbee40f5a071b6760270d0d58d', d: "M3 8.5h14M7 2.5v3M13 2.5v3", "stroke-linecap": "round" }))), h("input", { key: 'be02df44f31a59a26ce166ab9a9eab9db2635d89', class: "mrd-date-field__picker-native", type: "date", ref: el => (this.nativeInput = el), value: this.currentIso(), disabled: this.disabled, tabIndex: -1, "aria-hidden": "true", onChange: this.handlePickerChange }))), h(FieldError, { key: '2f8b2072bee32170a35f98ec5c962018774c7e8c', base: "mrd-date-field", error: this.error }))));
24
104
  }
25
105
  static get is() { return "mrd-date-field"; }
26
106
  static get encapsulation() { return "scoped"; }
@@ -88,7 +168,7 @@ export class MrdDateField {
88
168
  "optional": false,
89
169
  "docs": {
90
170
  "tags": [],
91
- "text": ""
171
+ "text": "ISO date, 'YYYY-MM-DD'."
92
172
  },
93
173
  "getter": false,
94
174
  "setter": false,
@@ -96,6 +176,26 @@ export class MrdDateField {
96
176
  "attribute": "value",
97
177
  "defaultValue": "''"
98
178
  },
179
+ "placeholder": {
180
+ "type": "string",
181
+ "mutable": false,
182
+ "complexType": {
183
+ "original": "string",
184
+ "resolved": "string",
185
+ "references": {}
186
+ },
187
+ "required": false,
188
+ "optional": false,
189
+ "docs": {
190
+ "tags": [],
191
+ "text": "Overrides the locale-derived pattern placeholder (e.g. 'dd-mm-jjjj')."
192
+ },
193
+ "getter": false,
194
+ "setter": false,
195
+ "reflect": false,
196
+ "attribute": "placeholder",
197
+ "defaultValue": "''"
198
+ },
99
199
  "required": {
100
200
  "type": "boolean",
101
201
  "mutable": false,
@@ -160,6 +260,7 @@ export class MrdDateField {
160
260
  }
161
261
  static get states() {
162
262
  return {
263
+ "displayValue": {},
163
264
  "error": {}
164
265
  };
165
266
  }
@@ -196,4 +297,13 @@ export class MrdDateField {
196
297
  }
197
298
  }];
198
299
  }
300
+ static get watchers() {
301
+ return [{
302
+ "propName": "value",
303
+ "methodName": "valueChanged"
304
+ }, {
305
+ "propName": "locale",
306
+ "methodName": "localeChanged"
307
+ }];
308
+ }
199
309
  }