@mmlogic/components 0.1.8 → 0.1.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 (26) hide show
  1. package/dist/cjs/loader.cjs.js +1 -1
  2. package/dist/cjs/mosterdcomponents.cjs.js +1 -1
  3. package/dist/cjs/mrd-boolean-field_16.cjs.entry.js +167 -17
  4. package/dist/collection/components/mrd-field/mrd-field.js +26 -2
  5. package/dist/collection/components/mrd-file-field/mrd-file-field.js +70 -2
  6. package/dist/collection/components/mrd-file-field/mrd-file-field.scss +13 -0
  7. package/dist/collection/components/mrd-form/mrd-form.js +187 -8
  8. package/dist/collection/components/mrd-form/mrd-form.scss +32 -0
  9. package/dist/collection/components/mrd-image-field/mrd-image-field.js +71 -2
  10. package/dist/collection/components/mrd-image-field/mrd-image-field.scss +26 -2
  11. package/dist/components/mrd-field2.js +1 -1
  12. package/dist/components/mrd-file-field2.js +1 -1
  13. package/dist/components/mrd-form.js +1 -1
  14. package/dist/components/mrd-image-field2.js +1 -1
  15. package/dist/esm/loader.js +1 -1
  16. package/dist/esm/mosterdcomponents.js +1 -1
  17. package/dist/esm/mrd-boolean-field_16.entry.js +167 -17
  18. package/dist/mosterdcomponents/mosterdcomponents.esm.js +1 -1
  19. package/dist/mosterdcomponents/p-bb567c32.entry.js +1 -0
  20. package/dist/types/components/mrd-field/mrd-field.d.ts +5 -0
  21. package/dist/types/components/mrd-file-field/mrd-file-field.d.ts +10 -0
  22. package/dist/types/components/mrd-form/mrd-form.d.ts +40 -0
  23. package/dist/types/components/mrd-image-field/mrd-image-field.d.ts +10 -0
  24. package/dist/types/components.d.ts +65 -0
  25. package/package.json +1 -1
  26. package/dist/mosterdcomponents/p-5a453e03.entry.js +0 -1
@@ -335,6 +335,7 @@ const MrdField = class {
335
335
  this.mrdBlur = createEvent(this, "mrdBlur");
336
336
  this.mrdSearch = createEvent(this, "mrdSearch");
337
337
  this.mrdFetchAll = createEvent(this, "mrdFetchAll");
338
+ this.mrdUpload = createEvent(this, "mrdUpload");
338
339
  this.locale = navigator.language;
339
340
  this.handleChange = (e) => {
340
341
  e.stopPropagation();
@@ -352,6 +353,10 @@ const MrdField = class {
352
353
  e.stopPropagation();
353
354
  this.mrdFetchAll.emit(e.detail);
354
355
  };
356
+ this.handleUpload = (e) => {
357
+ e.stopPropagation();
358
+ this.mrdUpload.emit(e.detail);
359
+ };
355
360
  }
356
361
  render() {
357
362
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6;
@@ -399,24 +404,26 @@ const MrdField = class {
399
404
  case ClientLayoutItemFieldDataType.LIST:
400
405
  return (h(Host, null, h("mrd-list-field", Object.assign({}, commonProps, { value: (_0 = value) !== null && _0 !== void 0 ? _0 : '', multiple: (_1 = field.multiple) !== null && _1 !== void 0 ? _1 : false, listItems: (_2 = field.listItems) !== null && _2 !== void 0 ? _2 : [] }))));
401
406
  case ClientLayoutItemFieldDataType.FILE:
402
- return (h(Host, null, h("mrd-file-field", Object.assign({}, commonProps, { accept: (_3 = field.accept) !== null && _3 !== void 0 ? _3 : '', maxSize: (_4 = field.maxSize) !== null && _4 !== void 0 ? _4 : 0 }))));
407
+ return (h(Host, null, h("mrd-file-field", Object.assign({}, commonProps, { value: value, accept: (_3 = field.accept) !== null && _3 !== void 0 ? _3 : '', maxSize: (_4 = field.maxSize) !== null && _4 !== void 0 ? _4 : 0, onMrdUpload: this.handleUpload }))));
403
408
  case ClientLayoutItemFieldDataType.IMAGE:
404
- return (h(Host, null, h("mrd-image-field", Object.assign({}, commonProps, { accept: (_5 = field.accept) !== null && _5 !== void 0 ? _5 : 'image/*', maxSize: (_6 = field.maxSize) !== null && _6 !== void 0 ? _6 : 0 }))));
409
+ return (h(Host, null, h("mrd-image-field", Object.assign({}, commonProps, { value: value, accept: (_5 = field.accept) !== null && _5 !== void 0 ? _5 : 'image/*', maxSize: (_6 = field.maxSize) !== null && _6 !== void 0 ? _6 : 0, onMrdUpload: this.handleUpload }))));
405
410
  default:
406
411
  return h(Host, null);
407
412
  }
408
413
  }
409
414
  };
410
415
 
411
- const mrdFileFieldScss = () => `.sc-mrd-file-field-h{display:block}.mrd-file-field.sc-mrd-file-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-file-field__label.sc-mrd-file-field{display:block;font-family:var(--mrd-font-family);font-size:var(--mrd-label-font-size);font-weight:var(--mrd-label-font-weight);color:var(--mrd-label-color)}.mrd-file-field__label--required.sc-mrd-file-field::after{content:' *';color:var(--mrd-color-danger)}.mrd-file-field__zone.sc-mrd-file-field{display:flex;align-items:center;justify-content:center;padding:var(--mrd-space-6);border:2px dashed var(--mrd-border-color);border-radius:var(--mrd-border-radius-md);background-color:var(--mrd-color-neutral-50);cursor:pointer;transition:border-color var(--mrd-transition), background-color var(--mrd-transition);min-height:100px;position:relative}.mrd-file-field__zone.sc-mrd-file-field:hover{border-color:var(--mrd-color-primary);background-color:var(--mrd-color-primary-light)}.mrd-file-field__zone--dragging.sc-mrd-file-field{border-color:var(--mrd-color-primary);background-color:var(--mrd-color-primary-light)}.mrd-file-field__zone--error.sc-mrd-file-field{border-color:var(--mrd-border-color-error)}.mrd-file-field__zone--disabled.sc-mrd-file-field{opacity:0.6;cursor:not-allowed}.mrd-file-field__zone--disabled.sc-mrd-file-field:hover{border-color:var(--mrd-border-color);background-color:var(--mrd-color-neutral-50)}.mrd-file-field__input.sc-mrd-file-field{position:absolute;inset:0;opacity:0;width:100%;height:100%;cursor:pointer;pointer-events:none}.mrd-file-field__prompt.sc-mrd-file-field{display:flex;flex-direction:column;align-items:center;gap:var(--mrd-space-2);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-500);text-align:center}.mrd-file-field__upload-icon.sc-mrd-file-field{width:32px;height:32px;color:var(--mrd-color-neutral-400)}.mrd-file-field__browse.sc-mrd-file-field{color:var(--mrd-color-primary);font-weight:var(--mrd-font-weight-medium);text-decoration:underline}.mrd-file-field__selected.sc-mrd-file-field{display:flex;align-items:center;gap:var(--mrd-space-2);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-700)}.mrd-file-field__icon.sc-mrd-file-field{width:20px;height:20px;color:var(--mrd-color-primary);flex-shrink:0}.mrd-file-field__filename.sc-mrd-file-field{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:200px}.mrd-file-field__clear.sc-mrd-file-field{background:none;border:none;cursor:pointer;color:var(--mrd-color-neutral-400);font-size:var(--mrd-font-size-sm);padding:var(--mrd-space-1);border-radius:var(--mrd-border-radius-sm);line-height:1}.mrd-file-field__clear.sc-mrd-file-field:hover{color:var(--mrd-color-danger);background-color:var(--mrd-color-danger-light)}.mrd-file-field__error.sc-mrd-file-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}`;
416
+ const mrdFileFieldScss = () => `.sc-mrd-file-field-h{display:block}.mrd-file-field.sc-mrd-file-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-file-field__label.sc-mrd-file-field{display:block;font-family:var(--mrd-font-family);font-size:var(--mrd-label-font-size);font-weight:var(--mrd-label-font-weight);color:var(--mrd-label-color)}.mrd-file-field__label--required.sc-mrd-file-field::after{content:' *';color:var(--mrd-color-danger)}.mrd-file-field__zone.sc-mrd-file-field{display:flex;align-items:center;justify-content:center;padding:var(--mrd-space-6);border:2px dashed var(--mrd-border-color);border-radius:var(--mrd-border-radius-md);background-color:var(--mrd-color-neutral-50);cursor:pointer;transition:border-color var(--mrd-transition), background-color var(--mrd-transition);min-height:100px;position:relative}.mrd-file-field__zone.sc-mrd-file-field:hover{border-color:var(--mrd-color-primary);background-color:var(--mrd-color-primary-light)}.mrd-file-field__zone--dragging.sc-mrd-file-field{border-color:var(--mrd-color-primary);background-color:var(--mrd-color-primary-light)}.mrd-file-field__zone--error.sc-mrd-file-field{border-color:var(--mrd-border-color-error)}.mrd-file-field__zone--disabled.sc-mrd-file-field{opacity:0.6;cursor:not-allowed}.mrd-file-field__zone--disabled.sc-mrd-file-field:hover{border-color:var(--mrd-border-color);background-color:var(--mrd-color-neutral-50)}.mrd-file-field__input.sc-mrd-file-field{position:absolute;inset:0;opacity:0;width:100%;height:100%;cursor:pointer;pointer-events:none}.mrd-file-field__prompt.sc-mrd-file-field{display:flex;flex-direction:column;align-items:center;gap:var(--mrd-space-2);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-500);text-align:center}.mrd-file-field__upload-icon.sc-mrd-file-field{width:32px;height:32px;color:var(--mrd-color-neutral-400)}.mrd-file-field__browse.sc-mrd-file-field{color:var(--mrd-color-primary);font-weight:var(--mrd-font-weight-medium);text-decoration:underline}.mrd-file-field__selected.sc-mrd-file-field{display:flex;align-items:center;gap:var(--mrd-space-2);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-700)}.mrd-file-field__icon.sc-mrd-file-field{width:20px;height:20px;color:var(--mrd-color-primary);flex-shrink:0}.mrd-file-field__filename.sc-mrd-file-field{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:200px}.mrd-file-field__clear.sc-mrd-file-field{background:none;border:none;cursor:pointer;color:var(--mrd-color-neutral-400);font-size:var(--mrd-font-size-sm);padding:var(--mrd-space-1);border-radius:var(--mrd-border-radius-sm);line-height:1}.mrd-file-field__clear.sc-mrd-file-field:hover{color:var(--mrd-color-danger);background-color:var(--mrd-color-danger-light)}.mrd-file-field__spinner.sc-mrd-file-field{display:inline-block;flex-shrink:0;width:18px;height:18px;border:2px solid var(--mrd-color-neutral-300);border-top-color:var(--mrd-color-primary);border-radius:50%;animation:mrd-file-spin 0.6s linear infinite}@keyframes mrd-file-spin{to{transform:rotate(360deg)}}.mrd-file-field__error.sc-mrd-file-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}`;
412
417
 
413
418
  const MrdFileField = class {
414
419
  constructor(hostRef) {
415
420
  registerInstance(this, hostRef);
416
421
  this.mrdChange = createEvent(this, "mrdChange");
417
422
  this.mrdBlur = createEvent(this, "mrdBlur");
423
+ this.mrdUpload = createEvent(this, "mrdUpload");
418
424
  this.name = '';
419
425
  this.label = '';
426
+ this.value = null;
420
427
  this.required = false;
421
428
  this.disabled = false;
422
429
  this.locale = navigator.language;
@@ -424,6 +431,7 @@ const MrdFileField = class {
424
431
  this.maxSize = 0; // bytes, 0 = no limit
425
432
  this.fileName = '';
426
433
  this.isDragging = false;
434
+ this.uploading = false;
427
435
  this.error = '';
428
436
  this.handleInputChange = (e) => {
429
437
  var _a;
@@ -446,7 +454,7 @@ const MrdFileField = class {
446
454
  };
447
455
  this.handleZoneClick = () => {
448
456
  var _a;
449
- if (!this.disabled) {
457
+ if (!this.disabled && !this.uploading) {
450
458
  (_a = this.fileInputRef) === null || _a === void 0 ? void 0 : _a.click();
451
459
  }
452
460
  };
@@ -454,14 +462,26 @@ const MrdFileField = class {
454
462
  e.stopPropagation();
455
463
  this.fileName = '';
456
464
  this.error = '';
465
+ this.uploading = false;
457
466
  if (this.fileInputRef)
458
467
  this.fileInputRef.value = '';
459
468
  this.mrdChange.emit({ name: this.name, value: null });
460
469
  };
461
470
  }
471
+ /** When the host provides a URI back via setFieldValue, the upload is done. */
472
+ valueChanged(newVal) {
473
+ if (typeof newVal === 'string' && newVal) {
474
+ this.uploading = false;
475
+ }
476
+ else if (!newVal) {
477
+ this.uploading = false;
478
+ this.fileName = '';
479
+ }
480
+ }
462
481
  handleFile(file) {
463
482
  if (!file) {
464
483
  this.fileName = '';
484
+ this.uploading = false;
465
485
  this.mrdChange.emit({ name: this.name, value: null });
466
486
  return;
467
487
  }
@@ -471,49 +491,91 @@ const MrdFileField = class {
471
491
  }
472
492
  this.error = '';
473
493
  this.fileName = file.name;
494
+ this.uploading = true;
474
495
  this.mrdChange.emit({ name: this.name, value: file });
496
+ this.mrdUpload.emit({ name: this.name, file });
475
497
  }
476
498
  render() {
499
+ const hasFile = this.uploading || (typeof this.value === 'string' && this.value) || this.fileName;
477
500
  const hasError = !!this.error;
478
- return (h(Host, { key: '6617c70edaf193c204a951ff8116d54742592f84' }, h("div", { key: '69a45446da411c1cfdadd9ee7051e3ceea95a2d2', class: "mrd-file-field" }, this.label && (h("label", { key: 'ca415565514c5a3829b1e4a446493916bd1b5b17', class: `mrd-file-field__label${this.required ? ' mrd-file-field__label--required' : ''}` }, this.label)), h("div", { key: 'abee0fc6a53c9f1266e6ed2d0ec8ab85a20a81ca', class: `mrd-file-field__zone${this.isDragging ? ' mrd-file-field__zone--dragging' : ''}${hasError ? ' mrd-file-field__zone--error' : ''}${this.disabled ? ' mrd-file-field__zone--disabled' : ''}`, onClick: this.handleZoneClick, onDragOver: this.handleDragOver, onDragLeave: this.handleDragLeave, onDrop: this.handleDrop }, h("input", { key: 'c1dbca750d4115b7d8ea3dcd9ed3405ed11c93a2', ref: el => (this.fileInputRef = el), class: "mrd-file-field__input", type: "file", name: this.name, accept: this.accept, disabled: this.disabled, required: this.required && !this.fileName, onChange: this.handleInputChange }), this.fileName ? (h("div", { class: "mrd-file-field__selected" }, h("svg", { class: "mrd-file-field__icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2" }, h("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }), h("polyline", { points: "14 2 14 8 20 8" })), h("span", { class: "mrd-file-field__filename" }, this.fileName), h("button", { class: "mrd-file-field__clear", type: "button", onClick: this.handleClear, "aria-label": t('clear', this.locale) }, "\u2715"))) : (h("div", { class: "mrd-file-field__prompt" }, h("svg", { class: "mrd-file-field__upload-icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2" }, h("polyline", { points: "16 16 12 12 8 16" }), h("line", { x1: "12", y1: "12", x2: "12", y2: "21" }), h("path", { d: "M20.39 18.39A5 5 0 0 0 18 9h-1.26A8 8 0 1 0 3 16.3" })), h("span", null, t('drop_file_here', this.locale), ' ', h("span", { class: "mrd-file-field__browse" }, t('browse', this.locale)))))), hasError && h("span", { key: '91ef6a6240f139e161288cb812d17e13a619ec89', class: "mrd-file-field__error" }, this.error))));
501
+ const zoneClass = [
502
+ 'mrd-file-field__zone',
503
+ this.isDragging ? 'mrd-file-field__zone--dragging' : '',
504
+ hasError ? 'mrd-file-field__zone--error' : '',
505
+ this.disabled || this.uploading ? 'mrd-file-field__zone--disabled' : '',
506
+ ].filter(Boolean).join(' ');
507
+ return (h(Host, { key: '2090102df8169226c1e66f87cbc837296e4b55d4' }, h("div", { key: '7a37a09df1bfa2eaf28ed04c806ad5f7c0337bb0', class: "mrd-file-field" }, this.label && (h("label", { key: '8f1fcb8adbb66b792be902c7c548e50db99b6a53', class: `mrd-file-field__label${this.required ? ' mrd-file-field__label--required' : ''}` }, this.label)), h("div", { key: '66d992298f537b24d69ce3ead3dd229f6d124f3d', class: zoneClass, onClick: this.handleZoneClick, onDragOver: this.handleDragOver, onDragLeave: this.handleDragLeave, onDrop: this.handleDrop }, h("input", { key: '95ba6560e71ee08c6b2526802727b29a18cdc454', ref: el => (this.fileInputRef = el), class: "mrd-file-field__input", type: "file", name: this.name, accept: this.accept, disabled: this.disabled || this.uploading, required: this.required && !hasFile, onChange: this.handleInputChange }), hasFile ? (h("div", { class: "mrd-file-field__selected" }, this.uploading ? (h("span", { class: "mrd-file-field__spinner", "aria-label": t('loading', this.locale) })) : (h("svg", { class: "mrd-file-field__icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2" }, h("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }), h("polyline", { points: "14 2 14 8 20 8" }))), h("span", { class: "mrd-file-field__filename" }, this.fileName), !this.uploading && (h("button", { class: "mrd-file-field__clear", type: "button", onClick: this.handleClear, "aria-label": t('clear', this.locale) }, "\u2715")))) : (h("div", { class: "mrd-file-field__prompt" }, h("svg", { class: "mrd-file-field__upload-icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2" }, h("polyline", { points: "16 16 12 12 8 16" }), h("line", { x1: "12", y1: "12", x2: "12", y2: "21" }), h("path", { d: "M20.39 18.39A5 5 0 0 0 18 9h-1.26A8 8 0 1 0 3 16.3" })), h("span", null, t('drop_file_here', this.locale), ' ', h("span", { class: "mrd-file-field__browse" }, t('browse', this.locale)))))), hasError && h("span", { key: 'a6020e63bebb01e31a980a903f81badd486585aa', class: "mrd-file-field__error" }, this.error))));
479
508
  }
509
+ static get watchers() { return {
510
+ "value": [{
511
+ "valueChanged": 0
512
+ }]
513
+ }; }
480
514
  };
481
515
  MrdFileField.style = mrdFileFieldScss();
482
516
 
483
- const mrdFormScss = () => `.sc-mrd-form-h{display:block}.mrd-form.sc-mrd-form{font-family:var(--mrd-font-family);width:100%}.mrd-form__title.sc-mrd-form{font-size:var(--mrd-font-size-2xl);font-weight:var(--mrd-font-weight-bold);color:var(--mrd-color-neutral-900);margin:0 0 var(--mrd-space-6) 0}.mrd-form__body.sc-mrd-form{display:flex;flex-direction:column;gap:var(--mrd-space-5)}.mrd-form__field.sc-mrd-form{display:flex;flex-direction:column;gap:var(--mrd-space-1)}.mrd-form__field-error.sc-mrd-form{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}.mrd-form__section.sc-mrd-form{border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius-md);padding:var(--mrd-space-4) var(--mrd-space-5);margin:0}.mrd-form__section-legend.sc-mrd-form{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);font-weight:var(--mrd-font-weight-semibold);color:var(--mrd-color-neutral-700);padding:0 var(--mrd-space-2)}.mrd-form__section-body.sc-mrd-form{display:flex;flex-direction:column;gap:var(--mrd-space-4);margin-top:var(--mrd-space-2)}.mrd-form__group.sc-mrd-form{display:flex;flex-direction:column;gap:var(--mrd-space-2)}.mrd-form__group-label.sc-mrd-form{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);font-weight:var(--mrd-font-weight-semibold);color:var(--mrd-color-neutral-500);text-transform:uppercase;letter-spacing:0.05em}.mrd-form__group-body.sc-mrd-form{display:flex;flex-direction:column;gap:var(--mrd-space-4);padding-left:var(--mrd-space-4);border-left:3px solid var(--mrd-color-neutral-200)}.mrd-form__footer.sc-mrd-form{margin-top:var(--mrd-space-8);padding-top:var(--mrd-space-5);border-top:var(--mrd-border-width) solid var(--mrd-border-color);display:flex;justify-content:flex-end}.mrd-form__submit.sc-mrd-form{display:inline-flex;align-items:center;justify-content:center;height:var(--mrd-input-height);padding:0 var(--mrd-space-6);background-color:var(--mrd-color-primary);color:var(--mrd-color-white);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);font-weight:var(--mrd-font-weight-medium);border:none;border-radius:var(--mrd-border-radius);cursor:pointer;transition:background-color var(--mrd-transition)}.mrd-form__submit.sc-mrd-form:hover{background-color:var(--mrd-color-primary-hover)}.mrd-form__submit.sc-mrd-form:focus{outline:none;box-shadow:var(--mrd-shadow-focus)}.mrd-form__submit.sc-mrd-form:active{background-color:var(--mrd-color-primary-dark)}`;
517
+ const mrdFormScss = () => `.sc-mrd-form-h{display:block}.mrd-form.sc-mrd-form{font-family:var(--mrd-font-family);width:100%}.mrd-form__title.sc-mrd-form{font-size:var(--mrd-font-size-2xl);font-weight:var(--mrd-font-weight-bold);color:var(--mrd-color-neutral-900);margin:0 0 var(--mrd-space-6) 0}.mrd-form__body.sc-mrd-form{display:flex;flex-direction:column;gap:var(--mrd-space-5)}.mrd-form__field.sc-mrd-form{display:flex;flex-direction:column;gap:var(--mrd-space-1)}.mrd-form__field-error.sc-mrd-form{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}.mrd-form__section.sc-mrd-form{border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius-md);padding:var(--mrd-space-4) var(--mrd-space-5);margin:0}.mrd-form__section-legend.sc-mrd-form{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);font-weight:var(--mrd-font-weight-semibold);color:var(--mrd-color-neutral-700);padding:0 var(--mrd-space-2)}.mrd-form__section-body.sc-mrd-form{display:flex;flex-direction:column;gap:var(--mrd-space-4);margin-top:var(--mrd-space-2)}.mrd-form__group.sc-mrd-form{display:flex;flex-direction:column;gap:var(--mrd-space-2)}.mrd-form__group-label.sc-mrd-form{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);font-weight:var(--mrd-font-weight-semibold);color:var(--mrd-color-neutral-500);text-transform:uppercase;letter-spacing:0.05em}.mrd-form__group-body.sc-mrd-form{display:flex;flex-direction:column;gap:var(--mrd-space-4);padding-left:var(--mrd-space-4);border-left:3px solid var(--mrd-color-neutral-200)}.mrd-form__footer.sc-mrd-form{margin-top:var(--mrd-space-8);padding-top:var(--mrd-space-5);border-top:var(--mrd-border-width) solid var(--mrd-border-color);display:flex;justify-content:flex-end;gap:var(--mrd-space-3)}.mrd-form__submit.sc-mrd-form{display:inline-flex;align-items:center;justify-content:center;height:var(--mrd-input-height);padding:0 var(--mrd-space-6);background-color:var(--mrd-color-primary);color:var(--mrd-color-white);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);font-weight:var(--mrd-font-weight-medium);border:none;border-radius:var(--mrd-border-radius);cursor:pointer;transition:background-color var(--mrd-transition)}.mrd-form__submit.sc-mrd-form:hover{background-color:var(--mrd-color-primary-hover)}.mrd-form__submit.sc-mrd-form:focus{outline:none;box-shadow:var(--mrd-shadow-focus)}.mrd-form__submit.sc-mrd-form:active{background-color:var(--mrd-color-primary-dark)}.mrd-form__cancel.sc-mrd-form{display:inline-flex;align-items:center;justify-content:center;height:var(--mrd-input-height);padding:0 var(--mrd-space-6);background-color:transparent;color:var(--mrd-color-neutral-600);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-base);font-weight:var(--mrd-font-weight-medium);border:var(--mrd-border-width) solid var(--mrd-border-color);border-radius:var(--mrd-border-radius);cursor:pointer;transition:background-color var(--mrd-transition), color var(--mrd-transition)}.mrd-form__cancel.sc-mrd-form:hover{background-color:var(--mrd-color-neutral-100);color:var(--mrd-color-neutral-800)}.mrd-form__cancel.sc-mrd-form:focus{outline:none;box-shadow:var(--mrd-shadow-focus)}.mrd-form__cancel.sc-mrd-form:active{background-color:var(--mrd-color-neutral-200)}`;
484
518
 
485
519
  const MrdForm = class {
486
520
  constructor(hostRef) {
487
521
  registerInstance(this, hostRef);
488
522
  this.mrdSubmit = createEvent(this, "mrdSubmit");
523
+ this.mrdCancel = createEvent(this, "mrdCancel");
489
524
  this.mrdSearch = createEvent(this, "mrdSearch");
490
525
  this.mrdFetchAll = createEvent(this, "mrdFetchAll");
526
+ this.mrdUpload = createEvent(this, "mrdUpload");
491
527
  this.locale = navigator.language;
492
528
  this.values = {};
529
+ /**
530
+ * Absolute href of the parent/reference object (e.g. the clientAgreement href
531
+ * when creating an invoice from within a client agreement).
532
+ * Combined with `referenceClass`, mrd-form will automatically pre-fill the
533
+ * matching relation field so dependent DROPDOWN fields can be fetched on load
534
+ * — without the host app needing to know anything about the form layout.
535
+ */
536
+ /**
537
+ * Absolute href of the parent/reference object (e.g. the clientAgreement href
538
+ * when creating an invoice from within a client agreement).
539
+ * Combined with `referenceClass`, mrd-form will automatically pre-fill the
540
+ * matching relation field so dependent DROPDOWN fields can be fetched on load.
541
+ */
542
+ this.referenceHref = '';
543
+ /**
544
+ * The `mostSignificantClass` of the parent/reference object
545
+ * (e.g. `'clientAgreements'`). Used to locate the matching RELATION field.
546
+ */
547
+ this.referenceClass = '';
548
+ /** When true, a cancel button is shown next to the submit button. */
549
+ this.showCancel = false;
493
550
  this.formValues = {};
494
551
  this.errors = {};
495
552
  this.submitted = false;
496
553
  this.handleFieldChange = (e) => {
497
554
  const { name, value } = e.detail;
555
+ const prevHref = this.getHref(this.formValues[name]);
498
556
  this.formValues = Object.assign(Object.assign({}, this.formValues), { [name]: value });
499
557
  if (this.errors[name]) {
500
558
  this.errors = Object.assign(Object.assign({}, this.errors), { [name]: '' });
501
559
  }
502
560
  // When a field changes, check if it is the commonRelation dependency for any
503
561
  // DROPDOWN relation. If so, reset the dependent field and re-fetch its options.
562
+ // Skip when the effective href did not change (e.g. mrdBlur fires after mrdChange
563
+ // with the same value, which would otherwise trigger a duplicate fetch).
564
+ const newHref = this.getHref(value);
565
+ if (newHref === prevHref)
566
+ return;
504
567
  for (const rel of this.collectDependentDropdowns()) {
505
568
  if (rel.commonRelation !== name)
506
569
  continue;
507
570
  // Clear the dependent field's current selection (options have changed)
508
571
  this.formValues = Object.assign(Object.assign({}, this.formValues), { [rel.name]: null });
509
- const filterValue = this.getHref(value);
510
572
  this.mrdFetchAll.emit({
511
573
  name: rel.name,
512
574
  relatedClass: rel.relatedClass,
513
575
  mostSignificantClass: rel.mostSignificantClass,
514
576
  commonRelation: rel.commonRelation,
515
577
  filter: rel.commonRelation,
516
- filterValue, // empty string when dependency was cleared → host should clear the list
578
+ filterValue: newHref, // empty string when dependency was cleared → host should clear the list
517
579
  });
518
580
  }
519
581
  };
@@ -525,6 +587,10 @@ const MrdForm = class {
525
587
  e.stopPropagation();
526
588
  this.mrdFetchAll.emit(e.detail);
527
589
  };
590
+ this.handleUpload = (e) => {
591
+ e.stopPropagation();
592
+ this.mrdUpload.emit(e.detail);
593
+ };
528
594
  this.handleSubmit = (e) => {
529
595
  e.preventDefault();
530
596
  this.submitted = true;
@@ -538,20 +604,71 @@ const MrdForm = class {
538
604
  this.formValues = Object.assign({}, ((_a = this.values) !== null && _a !== void 0 ? _a : {}));
539
605
  }
540
606
  componentDidLoad() {
541
- // Emit mrdFetchAll for DROPDOWN fields with commonRelation whose dependency
542
- // already has a value this handles the edit-mode case where values are set
543
- // as a prop before mount.
544
- setTimeout(() => this.emitDependentFetchAll(), 0);
607
+ // Apply reference pre-fill and emit mrdFetchAll for dependent DROPDOWN fields.
608
+ // Deferred so Angular/host prop bindings are settled before we read them.
609
+ setTimeout(() => {
610
+ this.applyReferenceValue();
611
+ this.emitDependentFetchAll();
612
+ }, 0);
545
613
  }
546
614
  /** Sync formValues when the values prop is set from outside after mount
547
615
  * (e.g. when pre-filling an existing record in edit mode). */
548
616
  valuesChanged(newValues) {
549
617
  this.formValues = Object.assign({}, (newValues !== null && newValues !== void 0 ? newValues : {}));
618
+ this.applyReferenceValue();
550
619
  this.errors = {};
551
620
  this.submitted = false;
552
621
  // Re-check DROPDOWN dependencies now that formValues are updated
553
622
  setTimeout(() => this.emitDependentFetchAll(), 0);
554
623
  }
624
+ /**
625
+ * When referenceHref + referenceClass are set, find the matching layout field
626
+ * and inject its value into formValues. This allows dependent DROPDOWN fields
627
+ * (those with commonRelation pointing to that field) to be fetched on load
628
+ * without the host app doing any form-domain logic.
629
+ *
630
+ * Two lookup strategies:
631
+ * 1. Find a RELATION whose mostSignificantClass matches referenceClass.
632
+ * 2. Fallback: find a DROPDOWN whose commonRelation field is absent from the
633
+ * layout (API omitted it because it is implied by the reference context).
634
+ */
635
+ applyReferenceValue() {
636
+ if (!this.referenceHref || !this.referenceClass)
637
+ return;
638
+ const fieldName = this.resolveReferenceFieldName();
639
+ if (!fieldName)
640
+ return;
641
+ // Only set when not already present (don't overwrite an explicit value)
642
+ if (!this.formValues[fieldName]) {
643
+ this.formValues = Object.assign(Object.assign({}, this.formValues), { [fieldName]: this.referenceHref });
644
+ }
645
+ }
646
+ resolveReferenceFieldName() {
647
+ var _a, _b;
648
+ const allItems = this.collectFields((_b = (_a = this.layout) === null || _a === void 0 ? void 0 : _a.items) !== null && _b !== void 0 ? _b : []);
649
+ // Strategy 1: direct match on mostSignificantClass
650
+ const direct = allItems.find(item => {
651
+ var _a;
652
+ return item.type === ClientLayoutItemType.RELATION &&
653
+ ((_a = item.relation) === null || _a === void 0 ? void 0 : _a.mostSignificantClass) === this.referenceClass;
654
+ });
655
+ if (direct === null || direct === void 0 ? void 0 : direct.relation)
656
+ return direct.relation.name;
657
+ // Strategy 2: a DROPDOWN whose commonRelation field was omitted from the layout
658
+ const layoutRelationNames = new Set(allItems
659
+ .filter(item => item.type === ClientLayoutItemType.RELATION)
660
+ .map(item => item.relation.name));
661
+ for (const item of allItems) {
662
+ const rel = item.relation;
663
+ if (item.type === ClientLayoutItemType.RELATION &&
664
+ (rel === null || rel === void 0 ? void 0 : rel.editBehavior) === ClientLayoutItemRelationEditBehavior.DROPDOWN &&
665
+ rel.commonRelation &&
666
+ !layoutRelationNames.has(rel.commonRelation)) {
667
+ return rel.commonRelation;
668
+ }
669
+ }
670
+ return null;
671
+ }
555
672
  async setFieldValue(name, value) {
556
673
  this.formValues = Object.assign(Object.assign({}, this.formValues), { [name]: value });
557
674
  if (this.errors[name]) {
@@ -637,6 +754,9 @@ const MrdForm = class {
637
754
  if (item.type === ClientLayoutItemType.FIELD && item.field) {
638
755
  const name = item.field.name;
639
756
  const value = this.formValues[name];
757
+ // Skip file/image fields that are still uploading (value is a File object)
758
+ if (value instanceof File)
759
+ continue;
640
760
  // Omit empty strings for optional fields
641
761
  if (value !== '')
642
762
  payload[name] = value !== null && value !== void 0 ? value : null;
@@ -666,7 +786,7 @@ const MrdForm = class {
666
786
  }
667
787
  const fieldName = (_d = (_b = (_a = item.field) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : (_c = item.relation) === null || _c === void 0 ? void 0 : _c.name) !== null && _d !== void 0 ? _d : '';
668
788
  const fieldValue = this.formValues[fieldName];
669
- return (h("div", { class: "mrd-form__field" }, h("mrd-field", { item: item, locale: this.locale, value: fieldValue, onMrdChange: this.handleFieldChange, onMrdBlur: this.handleFieldChange, onMrdSearch: this.handleSearch, onMrdFetchAll: this.handleFetchAll }), this.errors[fieldName] && (h("span", { class: "mrd-form__field-error" }, this.errors[fieldName]))));
789
+ return (h("div", { class: "mrd-form__field" }, h("mrd-field", { item: item, locale: this.locale, value: fieldValue, onMrdChange: this.handleFieldChange, onMrdBlur: this.handleFieldChange, onMrdSearch: this.handleSearch, onMrdFetchAll: this.handleFetchAll, onMrdUpload: this.handleUpload }), this.errors[fieldName] && (h("span", { class: "mrd-form__field-error" }, this.errors[fieldName]))));
670
790
  });
671
791
  }
672
792
  render() {
@@ -674,7 +794,7 @@ const MrdForm = class {
674
794
  return h(Host, null);
675
795
  }
676
796
  const dir = this.locale.startsWith('ar') ? 'rtl' : 'ltr';
677
- return (h(Host, null, h("form", { class: "mrd-form", dir: dir, onSubmit: this.handleSubmit, noValidate: true }, this.layout.title && h("h2", { class: "mrd-form__title" }, this.layout.title), h("div", { class: "mrd-form__body" }, this.renderItems(this.layout.items)), h("div", { class: "mrd-form__footer" }, h("button", { type: "submit", class: "mrd-form__submit" }, t('submit', this.locale))))));
797
+ return (h(Host, null, h("form", { class: "mrd-form", dir: dir, onSubmit: this.handleSubmit, noValidate: true }, this.layout.title && h("h2", { class: "mrd-form__title" }, this.layout.title), h("div", { class: "mrd-form__body" }, this.renderItems(this.layout.items)), h("div", { class: "mrd-form__footer" }, h("button", { type: "submit", class: "mrd-form__submit" }, t('submit', this.locale)), this.showCancel && (h("button", { type: "button", class: "mrd-form__cancel", onClick: () => this.mrdCancel.emit() }, t('cancel', this.locale)))))));
678
798
  }
679
799
  static get watchers() { return {
680
800
  "values": [{
@@ -724,15 +844,17 @@ const MrdHyperlinkField = class {
724
844
  };
725
845
  MrdHyperlinkField.style = mrdHyperlinkFieldScss();
726
846
 
727
- const mrdImageFieldScss = () => `.sc-mrd-image-field-h{display:block}.mrd-image-field.sc-mrd-image-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-image-field__label.sc-mrd-image-field{display:block;font-family:var(--mrd-font-family);font-size:var(--mrd-label-font-size);font-weight:var(--mrd-label-font-weight);color:var(--mrd-label-color)}.mrd-image-field__label--required.sc-mrd-image-field::after{content:' *';color:var(--mrd-color-danger)}.mrd-image-field__zone.sc-mrd-image-field{display:flex;align-items:center;justify-content:center;border:2px dashed var(--mrd-border-color);border-radius:var(--mrd-border-radius-md);background-color:var(--mrd-color-neutral-50);cursor:pointer;transition:border-color var(--mrd-transition), background-color var(--mrd-transition);min-height:100px;position:relative}.mrd-image-field__zone.sc-mrd-image-field:hover{border-color:var(--mrd-color-primary);background-color:var(--mrd-color-primary-light)}.mrd-image-field__zone--dragging.sc-mrd-image-field{border-color:var(--mrd-color-primary);background-color:var(--mrd-color-primary-light)}.mrd-image-field__zone--error.sc-mrd-image-field{border-color:var(--mrd-border-color-error)}.mrd-image-field__zone--disabled.sc-mrd-image-field{opacity:0.6;cursor:not-allowed}.mrd-image-field__zone--disabled.sc-mrd-image-field:hover{border-color:var(--mrd-border-color);background-color:var(--mrd-color-neutral-50)}.mrd-image-field__input.sc-mrd-image-field{position:absolute;inset:0;opacity:0;width:100%;height:100%;pointer-events:none}.mrd-image-field__prompt.sc-mrd-image-field{display:flex;flex-direction:column;align-items:center;gap:var(--mrd-space-2);padding:var(--mrd-space-6);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-500);text-align:center}.mrd-image-field__upload-icon.sc-mrd-image-field{width:40px;height:40px;color:var(--mrd-color-neutral-400)}.mrd-image-field__browse.sc-mrd-image-field{color:var(--mrd-color-primary);font-weight:var(--mrd-font-weight-medium);text-decoration:underline}.mrd-image-field__preview-container.sc-mrd-image-field{display:flex;align-items:center;gap:var(--mrd-space-4);padding:var(--mrd-space-4);width:100%}.mrd-image-field__preview-thumb.sc-mrd-image-field{flex-shrink:0;width:80px;height:80px;border-radius:var(--mrd-border-radius);overflow:hidden;border:var(--mrd-border-width) solid var(--mrd-border-color);background-color:var(--mrd-color-neutral-100)}.mrd-image-field__preview.sc-mrd-image-field{width:100%;height:100%;object-fit:cover;display:block}.mrd-image-field__preview-info.sc-mrd-image-field{flex:1;min-width:0;display:flex;flex-direction:column;gap:var(--mrd-space-1)}.mrd-image-field__preview-name.sc-mrd-image-field{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);font-weight:var(--mrd-font-weight-medium);color:var(--mrd-color-neutral-800);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mrd-image-field__overlay.sc-mrd-image-field{display:none}.mrd-image-field__clear.sc-mrd-image-field{flex-shrink:0;background-color:var(--mrd-color-white);color:var(--mrd-color-danger);border:var(--mrd-border-width) solid var(--mrd-color-danger);border-radius:var(--mrd-border-radius);padding:var(--mrd-space-1) var(--mrd-space-3);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);font-weight:var(--mrd-font-weight-medium);cursor:pointer;transition:background-color var(--mrd-transition), color var(--mrd-transition)}.mrd-image-field__clear.sc-mrd-image-field:hover{background-color:var(--mrd-color-danger);color:var(--mrd-color-white)}.mrd-image-field__error.sc-mrd-image-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}`;
847
+ const mrdImageFieldScss = () => `.sc-mrd-image-field-h{display:block}.mrd-image-field.sc-mrd-image-field{display:flex;flex-direction:column;gap:var(--mrd-space-1);width:100%}.mrd-image-field__label.sc-mrd-image-field{display:block;font-family:var(--mrd-font-family);font-size:var(--mrd-label-font-size);font-weight:var(--mrd-label-font-weight);color:var(--mrd-label-color)}.mrd-image-field__label--required.sc-mrd-image-field::after{content:' *';color:var(--mrd-color-danger)}.mrd-image-field__zone.sc-mrd-image-field{display:flex;align-items:center;justify-content:center;border:2px dashed var(--mrd-border-color);border-radius:var(--mrd-border-radius-md);background-color:var(--mrd-color-neutral-50);cursor:pointer;transition:border-color var(--mrd-transition), background-color var(--mrd-transition);min-height:100px;position:relative}.mrd-image-field__zone.sc-mrd-image-field:hover{border-color:var(--mrd-color-primary);background-color:var(--mrd-color-primary-light)}.mrd-image-field__zone--dragging.sc-mrd-image-field{border-color:var(--mrd-color-primary);background-color:var(--mrd-color-primary-light)}.mrd-image-field__zone--error.sc-mrd-image-field{border-color:var(--mrd-border-color-error)}.mrd-image-field__zone--disabled.sc-mrd-image-field{opacity:0.6;cursor:not-allowed}.mrd-image-field__zone--disabled.sc-mrd-image-field:hover{border-color:var(--mrd-border-color);background-color:var(--mrd-color-neutral-50)}.mrd-image-field__input.sc-mrd-image-field{position:absolute;inset:0;opacity:0;width:100%;height:100%;pointer-events:none}.mrd-image-field__prompt.sc-mrd-image-field{display:flex;flex-direction:column;align-items:center;gap:var(--mrd-space-2);padding:var(--mrd-space-6);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);color:var(--mrd-color-neutral-500);text-align:center}.mrd-image-field__upload-icon.sc-mrd-image-field{width:40px;height:40px;color:var(--mrd-color-neutral-400)}.mrd-image-field__browse.sc-mrd-image-field{color:var(--mrd-color-primary);font-weight:var(--mrd-font-weight-medium);text-decoration:underline}.mrd-image-field__preview-container.sc-mrd-image-field{display:flex;align-items:center;gap:var(--mrd-space-4);padding:var(--mrd-space-4);width:100%}.mrd-image-field__preview-thumb.sc-mrd-image-field{flex-shrink:0;width:80px;height:80px;border-radius:var(--mrd-border-radius);overflow:hidden;border:var(--mrd-border-width) solid var(--mrd-border-color);background-color:var(--mrd-color-neutral-100)}.mrd-image-field__preview.sc-mrd-image-field{width:100%;height:100%;object-fit:cover;display:block}.mrd-image-field__preview-info.sc-mrd-image-field{flex:1;min-width:0;display:flex;flex-direction:column;gap:var(--mrd-space-1)}.mrd-image-field__preview-name.sc-mrd-image-field{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);font-weight:var(--mrd-font-weight-medium);color:var(--mrd-color-neutral-800);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mrd-image-field__preview-overlay.sc-mrd-image-field{position:absolute;inset:0;background:rgb(255 255 255 / 0.7);display:flex;align-items:center;justify-content:center;border-radius:var(--mrd-border-radius)}.mrd-image-field__spinner.sc-mrd-image-field{display:inline-block;width:24px;height:24px;border:2px solid var(--mrd-color-neutral-300);border-top-color:var(--mrd-color-primary);border-radius:50%;animation:mrd-image-spin 0.6s linear infinite}@keyframes mrd-image-spin{to{transform:rotate(360deg)}}.mrd-image-field__upload-status.sc-mrd-image-field{font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-xs);color:var(--mrd-color-neutral-500)}.mrd-image-field__clear.sc-mrd-image-field{flex-shrink:0;background-color:var(--mrd-color-white);color:var(--mrd-color-danger);border:var(--mrd-border-width) solid var(--mrd-color-danger);border-radius:var(--mrd-border-radius);padding:var(--mrd-space-1) var(--mrd-space-3);font-family:var(--mrd-font-family);font-size:var(--mrd-font-size-sm);font-weight:var(--mrd-font-weight-medium);cursor:pointer;transition:background-color var(--mrd-transition), color var(--mrd-transition)}.mrd-image-field__clear.sc-mrd-image-field:hover{background-color:var(--mrd-color-danger);color:var(--mrd-color-white)}.mrd-image-field__error.sc-mrd-image-field{font-family:var(--mrd-font-family);font-size:var(--mrd-error-font-size);color:var(--mrd-error-color)}`;
728
848
 
729
849
  const MrdImageField = class {
730
850
  constructor(hostRef) {
731
851
  registerInstance(this, hostRef);
732
852
  this.mrdChange = createEvent(this, "mrdChange");
733
853
  this.mrdBlur = createEvent(this, "mrdBlur");
854
+ this.mrdUpload = createEvent(this, "mrdUpload");
734
855
  this.name = '';
735
856
  this.label = '';
857
+ this.value = null;
736
858
  this.required = false;
737
859
  this.disabled = false;
738
860
  this.locale = navigator.language;
@@ -741,6 +863,7 @@ const MrdImageField = class {
741
863
  this.previewUrl = '';
742
864
  this.fileName = '';
743
865
  this.isDragging = false;
866
+ this.uploading = false;
744
867
  this.error = '';
745
868
  this.handleInputChange = (e) => {
746
869
  var _a;
@@ -763,7 +886,7 @@ const MrdImageField = class {
763
886
  };
764
887
  this.handleZoneClick = () => {
765
888
  var _a;
766
- if (!this.disabled) {
889
+ if (!this.disabled && !this.uploading) {
767
890
  (_a = this.fileInputRef) === null || _a === void 0 ? void 0 : _a.click();
768
891
  }
769
892
  };
@@ -772,15 +895,28 @@ const MrdImageField = class {
772
895
  this.previewUrl = '';
773
896
  this.fileName = '';
774
897
  this.error = '';
898
+ this.uploading = false;
775
899
  if (this.fileInputRef)
776
900
  this.fileInputRef.value = '';
777
901
  this.mrdChange.emit({ name: this.name, value: null });
778
902
  };
779
903
  }
904
+ /** When the host provides a URI back via setFieldValue, the upload is done. */
905
+ valueChanged(newVal) {
906
+ if (typeof newVal === 'string' && newVal) {
907
+ this.uploading = false;
908
+ }
909
+ else if (!newVal) {
910
+ this.uploading = false;
911
+ this.previewUrl = '';
912
+ this.fileName = '';
913
+ }
914
+ }
780
915
  handleFile(file) {
781
916
  if (!file) {
782
917
  this.previewUrl = '';
783
918
  this.fileName = '';
919
+ this.uploading = false;
784
920
  this.mrdChange.emit({ name: this.name, value: null });
785
921
  return;
786
922
  }
@@ -794,6 +930,8 @@ const MrdImageField = class {
794
930
  }
795
931
  this.error = '';
796
932
  this.fileName = file.name;
933
+ this.uploading = true;
934
+ // Show local preview immediately while upload is in progress
797
935
  const reader = new FileReader();
798
936
  reader.onload = (ev) => {
799
937
  var _a;
@@ -801,11 +939,23 @@ const MrdImageField = class {
801
939
  };
802
940
  reader.readAsDataURL(file);
803
941
  this.mrdChange.emit({ name: this.name, value: file });
942
+ this.mrdUpload.emit({ name: this.name, file });
804
943
  }
805
944
  render() {
806
945
  const hasError = !!this.error;
807
- return (h(Host, { key: 'c188d49744b7044d46b6c6f42126032f1ecc8a8f' }, h("div", { key: '53990650a5109172addca5ae274b180569b08860', class: "mrd-image-field" }, this.label && (h("label", { key: '3dc78faca422fcafed31833a11307cace9f2ff13', class: `mrd-image-field__label${this.required ? ' mrd-image-field__label--required' : ''}` }, this.label)), h("div", { key: '4ca9eb1362c999721742ac3d727326078fe844c7', class: `mrd-image-field__zone${this.isDragging ? ' mrd-image-field__zone--dragging' : ''}${hasError ? ' mrd-image-field__zone--error' : ''}${this.disabled ? ' mrd-image-field__zone--disabled' : ''}`, onClick: this.handleZoneClick, onDragOver: this.handleDragOver, onDragLeave: this.handleDragLeave, onDrop: this.handleDrop }, h("input", { key: '9e3a237ffb69ce9f6fb20e6b3e603e4db453e7e9', ref: el => (this.fileInputRef = el), class: "mrd-image-field__input", type: "file", name: this.name, accept: this.accept, disabled: this.disabled, required: this.required && !this.previewUrl, onChange: this.handleInputChange }), this.previewUrl ? (h("div", { class: "mrd-image-field__preview-container" }, h("div", { class: "mrd-image-field__preview-thumb" }, h("img", { class: "mrd-image-field__preview", src: this.previewUrl, alt: this.fileName })), h("div", { class: "mrd-image-field__preview-info" }, h("span", { class: "mrd-image-field__preview-name" }, this.fileName)), h("button", { class: "mrd-image-field__clear", type: "button", onClick: this.handleClear, "aria-label": t('clear', this.locale) }, t('remove', this.locale)))) : (h("div", { class: "mrd-image-field__prompt" }, h("svg", { class: "mrd-image-field__upload-icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2" }, h("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }), h("circle", { cx: "8.5", cy: "8.5", r: "1.5" }), h("polyline", { points: "21 15 16 10 5 21" })), h("span", null, t('drop_file_here', this.locale), ' ', h("span", { class: "mrd-image-field__browse" }, t('browse', this.locale)))))), hasError && h("span", { key: '85cf998e1ab26cce7fbf87836df25672971a4eb1', class: "mrd-image-field__error" }, this.error))));
946
+ const zoneClass = [
947
+ 'mrd-image-field__zone',
948
+ this.isDragging ? 'mrd-image-field__zone--dragging' : '',
949
+ hasError ? 'mrd-image-field__zone--error' : '',
950
+ this.disabled || this.uploading ? 'mrd-image-field__zone--disabled' : '',
951
+ ].filter(Boolean).join(' ');
952
+ return (h(Host, { key: '76b5a36a7f5a420ded3400c8a1481843363d1cbe' }, h("div", { key: '3544df84aaf427a25518bafe13d60cf89ed28537', class: "mrd-image-field" }, this.label && (h("label", { key: 'dca64c1600cb98526eb4b91a908106087f099ad1', class: `mrd-image-field__label${this.required ? ' mrd-image-field__label--required' : ''}` }, this.label)), h("div", { key: 'ce07f32126f0956e47ff6fc41ff231590e0503d3', class: zoneClass, onClick: this.handleZoneClick, onDragOver: this.handleDragOver, onDragLeave: this.handleDragLeave, onDrop: this.handleDrop }, h("input", { key: '660fbae5f730834c465522a11dd674fc8e50a54e', ref: el => (this.fileInputRef = el), class: "mrd-image-field__input", type: "file", name: this.name, accept: this.accept, disabled: this.disabled || this.uploading, required: this.required && !this.previewUrl, onChange: this.handleInputChange }), this.previewUrl ? (h("div", { class: "mrd-image-field__preview-container" }, h("div", { class: "mrd-image-field__preview-thumb" }, h("img", { class: "mrd-image-field__preview", src: this.previewUrl, alt: this.fileName }), this.uploading && h("div", { class: "mrd-image-field__preview-overlay" }, h("span", { class: "mrd-image-field__spinner" }))), h("div", { class: "mrd-image-field__preview-info" }, h("span", { class: "mrd-image-field__preview-name" }, this.fileName), this.uploading && (h("span", { class: "mrd-image-field__upload-status" }, t('loading', this.locale)))), !this.uploading && (h("button", { class: "mrd-image-field__clear", type: "button", onClick: this.handleClear, "aria-label": t('clear', this.locale) }, t('remove', this.locale))))) : (h("div", { class: "mrd-image-field__prompt" }, h("svg", { class: "mrd-image-field__upload-icon", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2" }, h("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }), h("circle", { cx: "8.5", cy: "8.5", r: "1.5" }), h("polyline", { points: "21 15 16 10 5 21" })), h("span", null, t('drop_file_here', this.locale), ' ', h("span", { class: "mrd-image-field__browse" }, t('browse', this.locale)))))), hasError && h("span", { key: '9b8f9563fea63bd12c38f5c480e9cbd24106c3af', class: "mrd-image-field__error" }, this.error))));
808
953
  }
954
+ static get watchers() { return {
955
+ "value": [{
956
+ "valueChanged": 0
957
+ }]
958
+ }; }
809
959
  };
810
960
  MrdImageField.style = mrdImageFieldScss();
811
961
 
@@ -1 +1 @@
1
- import{p as e,b as l}from"./p-_tsCCkAi.js";export{s as setNonce}from"./p-_tsCCkAi.js";import{g as a}from"./p-DQuL1Twl.js";(()=>{const l=import.meta.url,a={};return""!==l&&(a.resourcesUrl=new URL(".",l).href),e(a)})().then((async e=>(await a(),l([["p-baf08615",[[2,"mrd-table",{columns:[16],rows:[16],locale:[1],totalElements:[2,"total-elements"],pageSize:[2,"page-size"],rowHeight:[2,"row-height"],tableHeight:[2,"table-height"],defaultSort:[1,"default-sort"],loadedPages:[32],requestedPages:[32],renderStart:[32],renderEnd:[32],colWidths:[32],sortField:[32],sortDir:[32],init:[64],setPage:[64]}]]],["p-5a453e03",[[2,"mrd-form",{layout:[16],locale:[1],values:[16],formValues:[32],errors:[32],submitted:[32],setFieldValue:[64]},null,{values:[{valuesChanged:0}]}],[2,"mrd-field",{item:[16],locale:[1],value:[16]}],[2,"mrd-boolean-field",{name:[1],label:[1],value:[4],required:[4],disabled:[4],locale:[1],checked:[32]}],[2,"mrd-currency-field",{name:[1],label:[1],value:[16],required:[4],disabled:[4],locale:[1],amountDisplay:[32],currency:[32],error:[32]}],[2,"mrd-date-field",{name:[1],label:[1],value:[1],required:[4],disabled:[4],locale:[1],error:[32]}],[2,"mrd-datetime-field",{name:[1],label:[1],value:[1],required:[4],disabled:[4],locale:[1],error:[32]}],[2,"mrd-email-field",{name:[1],label:[1],value:[1],placeholder:[1],required:[4],disabled:[4],locale:[1],error:[32]}],[2,"mrd-file-field",{name:[1],label:[1],required:[4],disabled:[4],locale:[1],accept:[1],maxSize:[2,"max-size"],fileName:[32],isDragging:[32],error:[32]}],[2,"mrd-hyperlink-field",{name:[1],label:[1],value:[1],placeholder:[1],required:[4],disabled:[4],locale:[1],error:[32]}],[2,"mrd-image-field",{name:[1],label:[1],required:[4],disabled:[4],locale:[1],accept:[1],maxSize:[2,"max-size"],previewUrl:[32],fileName:[32],isDragging:[32],error:[32]}],[2,"mrd-list-field",{name:[1],label:[1],value:[1],required:[4],disabled:[4],multiple:[4],locale:[1],listItems:[16],error:[32],selected:[32]}],[2,"mrd-number-field",{name:[1],label:[1],value:[2],placeholder:[1],required:[4],disabled:[4],locale:[1],dataType:[1,"data-type"],decimalPrecision:[2,"decimal-precision"],displayValue:[32],error:[32]}],[2,"mrd-relation-field",{name:[1],label:[1],required:[4],disabled:[4],locale:[1],relatedClass:[1,"related-class"],mostSignificantClass:[1,"most-significant-class"],displayType:[1,"display-type"],editBehavior:[1,"edit-behavior"],commonRelation:[1,"common-relation"],multiple:[4],dropdownValues:[16],value:[1],searchQuery:[32],searchResults:[32],allRecords:[32],isLoading:[32],selectedItems:[32],showResults:[32],error:[32],highlightedIndex:[32],setAllRecords:[64],setSearchResults:[64],setLoading:[64]}],[2,"mrd-text-field",{name:[1],label:[1],value:[1],placeholder:[1],required:[4],disabled:[4],locale:[1],error:[32]}],[2,"mrd-textarea-field",{name:[1],label:[1],value:[1],placeholder:[1],required:[4],disabled:[4],locale:[1],error:[32],editorReady:[32]}],[2,"mrd-time-field",{name:[1],label:[1],value:[1],required:[4],disabled:[4],locale:[1],error:[32]}]]]],e))));
1
+ import{p as e,b as l}from"./p-_tsCCkAi.js";export{s as setNonce}from"./p-_tsCCkAi.js";import{g as a}from"./p-DQuL1Twl.js";(()=>{const l=import.meta.url,a={};return""!==l&&(a.resourcesUrl=new URL(".",l).href),e(a)})().then((async e=>(await a(),l([["p-baf08615",[[2,"mrd-table",{columns:[16],rows:[16],locale:[1],totalElements:[2,"total-elements"],pageSize:[2,"page-size"],rowHeight:[2,"row-height"],tableHeight:[2,"table-height"],defaultSort:[1,"default-sort"],loadedPages:[32],requestedPages:[32],renderStart:[32],renderEnd:[32],colWidths:[32],sortField:[32],sortDir:[32],init:[64],setPage:[64]}]]],["p-bb567c32",[[2,"mrd-form",{layout:[16],locale:[1],values:[16],referenceHref:[1,"reference-href"],referenceClass:[1,"reference-class"],showCancel:[4,"show-cancel"],formValues:[32],errors:[32],submitted:[32],setFieldValue:[64]},null,{values:[{valuesChanged:0}]}],[2,"mrd-field",{item:[16],locale:[1],value:[16]}],[2,"mrd-boolean-field",{name:[1],label:[1],value:[4],required:[4],disabled:[4],locale:[1],checked:[32]}],[2,"mrd-currency-field",{name:[1],label:[1],value:[16],required:[4],disabled:[4],locale:[1],amountDisplay:[32],currency:[32],error:[32]}],[2,"mrd-date-field",{name:[1],label:[1],value:[1],required:[4],disabled:[4],locale:[1],error:[32]}],[2,"mrd-datetime-field",{name:[1],label:[1],value:[1],required:[4],disabled:[4],locale:[1],error:[32]}],[2,"mrd-email-field",{name:[1],label:[1],value:[1],placeholder:[1],required:[4],disabled:[4],locale:[1],error:[32]}],[2,"mrd-file-field",{name:[1],label:[1],value:[16],required:[4],disabled:[4],locale:[1],accept:[1],maxSize:[2,"max-size"],fileName:[32],isDragging:[32],uploading:[32],error:[32]},null,{value:[{valueChanged:0}]}],[2,"mrd-hyperlink-field",{name:[1],label:[1],value:[1],placeholder:[1],required:[4],disabled:[4],locale:[1],error:[32]}],[2,"mrd-image-field",{name:[1],label:[1],value:[16],required:[4],disabled:[4],locale:[1],accept:[1],maxSize:[2,"max-size"],previewUrl:[32],fileName:[32],isDragging:[32],uploading:[32],error:[32]},null,{value:[{valueChanged:0}]}],[2,"mrd-list-field",{name:[1],label:[1],value:[1],required:[4],disabled:[4],multiple:[4],locale:[1],listItems:[16],error:[32],selected:[32]}],[2,"mrd-number-field",{name:[1],label:[1],value:[2],placeholder:[1],required:[4],disabled:[4],locale:[1],dataType:[1,"data-type"],decimalPrecision:[2,"decimal-precision"],displayValue:[32],error:[32]}],[2,"mrd-relation-field",{name:[1],label:[1],required:[4],disabled:[4],locale:[1],relatedClass:[1,"related-class"],mostSignificantClass:[1,"most-significant-class"],displayType:[1,"display-type"],editBehavior:[1,"edit-behavior"],commonRelation:[1,"common-relation"],multiple:[4],dropdownValues:[16],value:[1],searchQuery:[32],searchResults:[32],allRecords:[32],isLoading:[32],selectedItems:[32],showResults:[32],error:[32],highlightedIndex:[32],setAllRecords:[64],setSearchResults:[64],setLoading:[64]}],[2,"mrd-text-field",{name:[1],label:[1],value:[1],placeholder:[1],required:[4],disabled:[4],locale:[1],error:[32]}],[2,"mrd-textarea-field",{name:[1],label:[1],value:[1],placeholder:[1],required:[4],disabled:[4],locale:[1],error:[32],editorReady:[32]}],[2,"mrd-time-field",{name:[1],label:[1],value:[1],required:[4],disabled:[4],locale:[1],error:[32]}]]]],e))));