@moni-labs/moni-ui 0.4.13 → 0.4.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/custom-elements.json +101 -81
  2. package/dist/browser/moni-ui.iife.min.js +1538 -1384
  3. package/dist/browser/moni-ui.iife.min.js.br +0 -0
  4. package/dist/browser/moni-ui.iife.min.js.gz +0 -0
  5. package/dist/browser/moni-ui.iife.min.js.map +1 -1
  6. package/dist/browser/moni-ui.min.js +2751 -2501
  7. package/dist/browser/moni-ui.min.js.br +0 -0
  8. package/dist/browser/moni-ui.min.js.gz +0 -0
  9. package/dist/browser/moni-ui.min.js.map +1 -1
  10. package/dist/cdn/chunks/{class-map-DsL1Jr2T.js → class-map-QyT9W7rZ.js} +1 -1
  11. package/dist/cdn/chunks/{decorate-DxJYS4gw.js → decorate-B7wZvwrn.js} +629 -543
  12. package/dist/cdn/chunks/if-defined-5hr_ccFw.js +1 -0
  13. package/dist/cdn/chunks/{live-D52JqeKf.js → live-Hm1Di_ND.js} +1 -1
  14. package/dist/cdn/components/moni-app-bar.js +1 -1
  15. package/dist/cdn/components/moni-badge.js +1 -1
  16. package/dist/cdn/components/moni-bottom-sheet.js +2 -1
  17. package/dist/cdn/components/moni-button-group.js +1 -1
  18. package/dist/cdn/components/moni-button-segment.js +1 -1
  19. package/dist/cdn/components/moni-button.js +1 -1
  20. package/dist/cdn/components/moni-card.js +1 -1
  21. package/dist/cdn/components/moni-carousel.js +1 -1
  22. package/dist/cdn/components/moni-checkbox.js +1 -1
  23. package/dist/cdn/components/moni-chip.js +1 -1
  24. package/dist/cdn/components/moni-color-field.js +1 -1
  25. package/dist/cdn/components/moni-context-menu.js +1 -1
  26. package/dist/cdn/components/moni-dialog.js +1 -1
  27. package/dist/cdn/components/moni-divider.js +1 -1
  28. package/dist/cdn/components/moni-expansion.js +1 -1
  29. package/dist/cdn/components/moni-fab-menu.js +1 -1
  30. package/dist/cdn/components/moni-fab.js +1 -1
  31. package/dist/cdn/components/moni-file-field.js +1 -1
  32. package/dist/cdn/components/moni-icon.js +1 -1
  33. package/dist/cdn/components/moni-list-item.js +1 -1
  34. package/dist/cdn/components/moni-list.js +1 -1
  35. package/dist/cdn/components/moni-loading-indicator.js +1 -1
  36. package/dist/cdn/components/moni-menu-item.js +1 -1
  37. package/dist/cdn/components/moni-menu.js +1 -1
  38. package/dist/cdn/components/moni-morph-modal.js +3 -2
  39. package/dist/cdn/components/moni-nav-item.js +1 -1
  40. package/dist/cdn/components/moni-nav.js +1 -1
  41. package/dist/cdn/components/moni-progress.js +1 -1
  42. package/dist/cdn/components/moni-radio.js +1 -1
  43. package/dist/cdn/components/moni-ripple.js +1 -1
  44. package/dist/cdn/components/moni-segmented-button.js +1 -1
  45. package/dist/cdn/components/moni-select-option.js +1 -1
  46. package/dist/cdn/components/moni-select.js +512 -473
  47. package/dist/cdn/components/moni-shape.js +1 -1
  48. package/dist/cdn/components/moni-side-sheet.js +1 -1
  49. package/dist/cdn/components/moni-slider.js +1 -1
  50. package/dist/cdn/components/moni-snackbar.js +1 -1
  51. package/dist/cdn/components/moni-split-button.js +1 -1
  52. package/dist/cdn/components/moni-step.js +1 -1
  53. package/dist/cdn/components/moni-stepper.js +1 -1
  54. package/dist/cdn/components/moni-switch.js +1 -1
  55. package/dist/cdn/components/moni-tab.js +1 -1
  56. package/dist/cdn/components/moni-tabs.js +1 -1
  57. package/dist/cdn/components/moni-text-field.js +122 -95
  58. package/dist/cdn/components/moni-textarea.js +52 -52
  59. package/dist/cdn/components/moni-time-picker.js +1 -1
  60. package/dist/cdn/components/moni-toolbar.js +1 -1
  61. package/dist/cdn/components/moni-tooltip.js +1 -1
  62. package/dist/cdn/components/moni-typography.js +1 -1
  63. package/dist/cdn/importmap.json +98 -98
  64. package/dist/components/_base/field-styles.d.ts.map +1 -1
  65. package/dist/components/_base/field-styles.js +662 -576
  66. package/dist/components/moni-bottom-sheet.d.ts +19 -5
  67. package/dist/components/moni-bottom-sheet.d.ts.map +1 -1
  68. package/dist/components/moni-bottom-sheet.js +111 -30
  69. package/dist/components/moni-morph-modal.d.ts +10 -0
  70. package/dist/components/moni-morph-modal.d.ts.map +1 -1
  71. package/dist/components/moni-morph-modal.js +323 -217
  72. package/dist/components/moni-select.d.ts +16 -16
  73. package/dist/components/moni-select.d.ts.map +1 -1
  74. package/dist/components/moni-select.js +797 -727
  75. package/dist/components/moni-text-field.d.ts +15 -15
  76. package/dist/components/moni-text-field.d.ts.map +1 -1
  77. package/dist/components/moni-text-field.js +224 -180
  78. package/dist/components/moni-textarea.d.ts +13 -13
  79. package/dist/components/moni-textarea.d.ts.map +1 -1
  80. package/dist/components/moni-textarea.js +127 -122
  81. package/docs/api.json +109 -89
  82. package/docs/assets/moni-color-field/shape--square.png +0 -0
  83. package/docs/assets/moni-file-field/shape--square.png +0 -0
  84. package/docs/assets/moni-morph-modal/autoHeight--false.png +0 -0
  85. package/docs/assets/moni-morph-modal/autoHeight--true.png +0 -0
  86. package/docs/components/bottom-sheet.md +2 -1
  87. package/docs/components/morph-modal.md +16 -7
  88. package/docs/components/select.md +74 -74
  89. package/docs/components/text-field.md +75 -66
  90. package/docs/components/textarea.md +51 -51
  91. package/docs/llms.txt +3 -3
  92. package/package.json +1 -1
  93. package/src/components/_base/field-styles.ts +723 -637
  94. package/src/components/moni-bottom-sheet.test.ts +331 -0
  95. package/src/components/moni-bottom-sheet.ts +117 -29
  96. package/src/components/moni-morph-modal.test.ts +490 -413
  97. package/src/components/moni-morph-modal.ts +2274 -2162
  98. package/src/components/moni-select.test.ts +489 -466
  99. package/src/components/moni-select.ts +1963 -1815
  100. package/src/components/moni-text-field.test.ts +366 -342
  101. package/src/components/moni-text-field.ts +717 -645
  102. package/src/components/moni-textarea.test.ts +201 -197
  103. package/src/components/moni-textarea.ts +476 -460
  104. package/dist/cdn/chunks/if-defined-DdzvcoI7.js +0 -1
@@ -157,6 +157,8 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
157
157
  * @type {boolean}
158
158
  */
159
159
  this.autoSize = false;
160
+ /** Ajusta sólo la altura al contenido, sin superar expanded-height. */
161
+ this.autoHeight = false;
160
162
  /** Fuerza al modal expandido a ocupar todo el viewport. */
161
163
  this.fullscreen = false;
162
164
  /** Activa fullscreen únicamente cuando el viewport no supera el breakpoint configurado. */
@@ -208,6 +210,8 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
208
210
  }
209
211
  static { MoniMorphModal_1 = this; }
210
212
  static { this._openStack = []; }
213
+ static { this._scrollLockOwners = new Set(); }
214
+ static { this._scrollLockSnapshot = null; }
211
215
  connectedCallback() {
212
216
  super.connectedCallback();
213
217
  this._resolveTarget();
@@ -227,6 +231,7 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
227
231
  this.style.removeProperty('--_z-index');
228
232
  this.style.removeProperty('--_backdrop-duration');
229
233
  this.style.removeProperty('--_backdrop-ease');
234
+ this._releaseDocumentScrollLock();
230
235
  this._cleanupMorphElements();
231
236
  this._restoreTargetContent();
232
237
  super.disconnectedCallback();
@@ -248,6 +253,44 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
248
253
  else
249
254
  this.hide();
250
255
  }
256
+ if ((changed.has('hasBackdrop') || changed.has('fullscreen') || changed.has('responsiveFullscreen') || changed.has('fullscreenBreakpoint')) && (this.open || this._visible)) {
257
+ this._syncDocumentScrollLock();
258
+ }
259
+ }
260
+ _shouldLockDocumentScroll() {
261
+ return this.hasBackdrop || this._usesFullscreen();
262
+ }
263
+ _syncDocumentScrollLock() {
264
+ if (this._shouldLockDocumentScroll())
265
+ this._acquireDocumentScrollLock();
266
+ else
267
+ this._releaseDocumentScrollLock();
268
+ }
269
+ _acquireDocumentScrollLock() {
270
+ if (MoniMorphModal_1._scrollLockOwners.has(this))
271
+ return;
272
+ if (MoniMorphModal_1._scrollLockOwners.size === 0) {
273
+ MoniMorphModal_1._scrollLockSnapshot = {
274
+ documentOverflow: document.documentElement.style.overflow,
275
+ bodyOverflow: document.body.style.overflow,
276
+ bodyOverscrollBehavior: document.body.style.overscrollBehavior
277
+ };
278
+ document.documentElement.style.overflow = 'hidden';
279
+ document.body.style.overflow = 'hidden';
280
+ document.body.style.overscrollBehavior = 'none';
281
+ }
282
+ MoniMorphModal_1._scrollLockOwners.add(this);
283
+ }
284
+ _releaseDocumentScrollLock() {
285
+ if (!MoniMorphModal_1._scrollLockOwners.delete(this) || MoniMorphModal_1._scrollLockOwners.size > 0)
286
+ return;
287
+ const snapshot = MoniMorphModal_1._scrollLockSnapshot;
288
+ if (snapshot) {
289
+ document.documentElement.style.overflow = snapshot.documentOverflow;
290
+ document.body.style.overflow = snapshot.bodyOverflow;
291
+ document.body.style.overscrollBehavior = snapshot.bodyOverscrollBehavior;
292
+ }
293
+ MoniMorphModal_1._scrollLockSnapshot = null;
251
294
  }
252
295
  /**
253
296
  * Busca en el DOM el elemento que dispara el modal (el trigger) basándose en la propiedad `target`.
@@ -291,6 +334,7 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
291
334
  this._handlingOpenChange = true;
292
335
  this.open = true;
293
336
  this._handlingOpenChange = false;
337
+ this._syncDocumentScrollLock();
294
338
  // Apilamos el modal globalmente para manejar correctamente el z-index en modales anidados
295
339
  MoniMorphModal_1._openStack.push(this);
296
340
  this._zIndex = 1000 + MoniMorphModal_1._openStack.length;
@@ -373,28 +417,8 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
373
417
  });
374
418
  // Fase "Last": Calculamos las dimensiones expandidas del modal basándonos en la configuración
375
419
  let naturalSize;
376
- if (this.autoSize) {
377
- const prevW = panel.style.getPropertyValue('--_panel-width');
378
- const prevH = panel.style.getPropertyValue('--_panel-height');
379
- const prevPanelW = panel.style.width;
380
- const prevPanelH = panel.style.height;
381
- panel.style.width = 'auto';
382
- panel.style.height = 'auto';
383
- panel.style.setProperty('--_panel-width', 'max-content');
384
- panel.style.setProperty('--_panel-height', 'max-content');
385
- const bodyEl = this.shadowRoot.querySelector('.body');
386
- const prevOverflow = bodyEl ? bodyEl.style.overflow : '';
387
- if (bodyEl)
388
- bodyEl.style.overflow = 'visible';
389
- // Forzamos al panel-inner a expandirse para medir su contenido real
390
- naturalSize = { width: this._inner.scrollWidth, height: this._inner.scrollHeight };
391
- panel.style.setProperty('--_panel-width', prevW);
392
- panel.style.setProperty('--_panel-height', prevH);
393
- panel.style.width = prevPanelW;
394
- panel.style.height = prevPanelH;
395
- if (bodyEl)
396
- bodyEl.style.overflow = prevOverflow;
397
- }
420
+ if (this.autoSize || this.autoHeight)
421
+ naturalSize = this._measureNaturalSize(panel);
398
422
  const finalRect = this._computeFinalRect(targetState.rect, naturalSize);
399
423
  panel.style.setProperty('--_panel-width', `${finalRect.width}px`);
400
424
  panel.style.setProperty('--_panel-height', `${finalRect.height}px`);
@@ -668,27 +692,8 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
668
692
  return;
669
693
  }
670
694
  let naturalSize;
671
- if (this.autoSize) {
672
- const prevW = panel.style.getPropertyValue('--_panel-width');
673
- const prevH = panel.style.getPropertyValue('--_panel-height');
674
- const prevPanelW = panel.style.width;
675
- const prevPanelH = panel.style.height;
676
- panel.style.width = 'auto';
677
- panel.style.height = 'auto';
678
- panel.style.setProperty('--_panel-width', 'max-content');
679
- panel.style.setProperty('--_panel-height', 'max-content');
680
- const bodyEl = this.shadowRoot.querySelector('.body');
681
- const prevOverflow = bodyEl ? bodyEl.style.overflow : '';
682
- if (bodyEl)
683
- bodyEl.style.overflow = 'visible';
684
- naturalSize = { width: this._inner.scrollWidth, height: this._inner.scrollHeight };
685
- panel.style.setProperty('--_panel-width', prevW);
686
- panel.style.setProperty('--_panel-height', prevH);
687
- panel.style.width = prevPanelW;
688
- panel.style.height = prevPanelH;
689
- if (bodyEl)
690
- bodyEl.style.overflow = prevOverflow;
691
- }
695
+ if (this.autoSize || this.autoHeight)
696
+ naturalSize = this._measureNaturalSize(panel);
692
697
  const finalRect = this._computeFinalRect(targetState.rect, naturalSize);
693
698
  panel.style.setProperty('--_panel-width', `${finalRect.width}px`);
694
699
  panel.style.setProperty('--_panel-height', `${finalRect.height}px`);
@@ -831,6 +836,27 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
831
836
  this._backdrop.style.opacity = '1';
832
837
  const motion = { progress: 0 };
833
838
  let contentAttached = false;
839
+ const sampleInterval = 1000 / 30;
840
+ const initialVisualWidth = destination.source.offsetWidth || targetRect.width;
841
+ const initialVisualHeight = destination.source.offsetHeight || targetRect.height;
842
+ const captureTargetSample = () => {
843
+ const state = this._getTargetState(destination.source);
844
+ const rect = this._toPanelCoordinateRect(state.rect);
845
+ return {
846
+ rect: { left: rect.left, top: rect.top, width: rect.width, height: rect.height },
847
+ transform: this._readTransformState(destination.source),
848
+ visualWidth: destination.source.offsetWidth || rect.width,
849
+ visualHeight: destination.source.offsetHeight || rect.height,
850
+ backgroundColor: state.backgroundColor,
851
+ color: state.color,
852
+ borderRadius: state.borderRadius,
853
+ boxShadow: state.boxShadow
854
+ };
855
+ };
856
+ let previousSample = captureTargetSample();
857
+ let nextSample = previousSample;
858
+ let sampledAt = performance.now();
859
+ const lerp = (from, to, amount) => from + (to - from) * amount;
834
860
  if (this.debug) {
835
861
  console.log('[moni-morph-modal] arc', { start, control, end, distance, arc, morphDuration });
836
862
  }
@@ -842,9 +868,28 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
842
868
  ease: 'power2.inOut',
843
869
  onUpdate: () => {
844
870
  const progress = motion.progress;
845
- const liveState = this._getTargetState(destination.source);
846
- const liveRect = this._toPanelCoordinateRect(liveState.rect);
847
- const liveTransform = this._readTransformState(destination.source);
871
+ const now = performance.now();
872
+ const forceFinalSample = progress >= 0.999;
873
+ if (forceFinalSample || now - sampledAt >= sampleInterval) {
874
+ previousSample = nextSample;
875
+ nextSample = captureTargetSample();
876
+ sampledAt = now;
877
+ }
878
+ const sampleProgress = forceFinalSample
879
+ ? 1
880
+ : Math.min(1, (now - sampledAt) / sampleInterval);
881
+ const liveRect = {
882
+ left: lerp(previousSample.rect.left, nextSample.rect.left, sampleProgress),
883
+ top: lerp(previousSample.rect.top, nextSample.rect.top, sampleProgress),
884
+ width: lerp(previousSample.rect.width, nextSample.rect.width, sampleProgress),
885
+ height: lerp(previousSample.rect.height, nextSample.rect.height, sampleProgress)
886
+ };
887
+ const liveTransform = {
888
+ rotation: lerp(previousSample.transform.rotation, nextSample.transform.rotation, sampleProgress),
889
+ skewX: lerp(previousSample.transform.skewX, nextSample.transform.skewX, sampleProgress),
890
+ scaleX: lerp(previousSample.transform.scaleX, nextSample.transform.scaleX, sampleProgress),
891
+ scaleY: lerp(previousSample.transform.scaleY, nextSample.transform.scaleY, sampleProgress)
892
+ };
848
893
  const liveEnd = {
849
894
  x: liveRect.left + liveRect.width / 2,
850
895
  y: liveRect.top + liveRect.height / 2
@@ -877,10 +922,8 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
877
922
  progress * progress * liveEnd.y;
878
923
  // La contracción modal mantiene su easing, pero cualquier mutación
879
924
  // adicional del target se suma completa para seguirla en tiempo real.
880
- const liveVisualWidth = destination.source.offsetWidth || liveRect.width;
881
- const liveVisualHeight = destination.source.offsetHeight || liveRect.height;
882
- const initialVisualWidth = destination.source.offsetWidth || targetRect.width;
883
- const initialVisualHeight = destination.source.offsetHeight || targetRect.height;
925
+ const liveVisualWidth = lerp(previousSample.visualWidth, nextSample.visualWidth, sampleProgress);
926
+ const liveVisualHeight = lerp(previousSample.visualHeight, nextSample.visualHeight, sampleProgress);
884
927
  const width = current.width + (initialVisualWidth - current.width) * progress +
885
928
  (liveVisualWidth - initialVisualWidth);
886
929
  const height = current.height + (initialVisualHeight - current.height) * progress +
@@ -894,10 +937,10 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
894
937
  skewX: liveTransform.skewX * progress,
895
938
  scaleX: 1 + (liveTransform.scaleX - 1) * progress,
896
939
  scaleY: 1 + (liveTransform.scaleY - 1) * progress,
897
- backgroundColor: gsap.utils.interpolate(panelStartVisual.backgroundColor, liveState.backgroundColor, progress),
898
- color: gsap.utils.interpolate(panelStartVisual.color, liveState.color, progress),
899
- borderRadius: gsap.utils.interpolate(panelStartVisual.borderRadius, liveState.borderRadius, progress),
900
- boxShadow: gsap.utils.interpolate(panelStartVisual.boxShadow, liveState.boxShadow, progress)
940
+ backgroundColor: gsap.utils.interpolate(panelStartVisual.backgroundColor, gsap.utils.interpolate(previousSample.backgroundColor, nextSample.backgroundColor, sampleProgress), progress),
941
+ color: gsap.utils.interpolate(panelStartVisual.color, gsap.utils.interpolate(previousSample.color, nextSample.color, sampleProgress), progress),
942
+ borderRadius: gsap.utils.interpolate(panelStartVisual.borderRadius, gsap.utils.interpolate(previousSample.borderRadius, nextSample.borderRadius, sampleProgress), progress),
943
+ boxShadow: gsap.utils.interpolate(panelStartVisual.boxShadow, gsap.utils.interpolate(previousSample.boxShadow, nextSample.boxShadow, sampleProgress), progress)
901
944
  });
902
945
  // El contenido del target no debe flotar sobre el modal grande. Solo
903
946
  // comienza a materializarse cuando posición y relación de aspecto ya
@@ -964,6 +1007,7 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
964
1007
  const idx = MoniMorphModal_1._openStack.indexOf(this);
965
1008
  if (idx > -1)
966
1009
  MoniMorphModal_1._openStack.splice(idx, 1);
1010
+ this._releaseDocumentScrollLock();
967
1011
  }
968
1012
  _captureOriginFallbacks(origin) {
969
1013
  this._originFallbacks = [];
@@ -983,11 +1027,28 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
983
1027
  if (this.target)
984
1028
  this._resolveTarget();
985
1029
  const candidates = [this._targetEl, ...this._originFallbacks].filter((candidate, index, all) => !!candidate && all.indexOf(candidate) === index);
1030
+ // Si el trigger original sigue en el DOM pero salio del viewport, no se
1031
+ // debe sustituir por uno de sus ancestros visibles. Ese fallback haria que
1032
+ // el modal colapsara hacia un contenedor que nunca fue su origen visual.
1033
+ // En este caso el cierre seguro es la animacion sin origen (fade + scale).
1034
+ if (this._targetEl?.isConnected && !this._intersectsViewport(this._targetEl)) {
1035
+ this._debugMorph('close', null, 'fade', candidates);
1036
+ return null;
1037
+ }
986
1038
  const resolved = candidates.find((candidate) => this._isUsableClosingTarget(candidate)) ?? null;
987
1039
  const strategy = !resolved ? 'fade' : resolved === this._targetEl ? 'target' : 'ancestor';
988
1040
  this._debugMorph('close', resolved, strategy, candidates);
989
1041
  return resolved;
990
1042
  }
1043
+ _intersectsViewport(el) {
1044
+ const rect = el.getBoundingClientRect();
1045
+ return rect.width >= 2
1046
+ && rect.height >= 2
1047
+ && rect.right > 0
1048
+ && rect.bottom > 0
1049
+ && rect.left < window.innerWidth
1050
+ && rect.top < window.innerHeight;
1051
+ }
991
1052
  _debugMorph(phase, resolved, strategy, candidates) {
992
1053
  if (!this.debug)
993
1054
  return;
@@ -1013,10 +1074,7 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
1013
1074
  _isUsableClosingTarget(el) {
1014
1075
  if (!el?.isConnected)
1015
1076
  return false;
1016
- const rect = el.getBoundingClientRect();
1017
- if (rect.width < 2 || rect.height < 2)
1018
- return false;
1019
- if (rect.right <= 0 || rect.bottom <= 0 || rect.left >= window.innerWidth || rect.top >= window.innerHeight)
1077
+ if (!this._intersectsViewport(el))
1020
1078
  return false;
1021
1079
  let current = el;
1022
1080
  while (current && current !== document.body) {
@@ -1665,8 +1723,12 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
1665
1723
  if (this._usesFullscreen())
1666
1724
  return new DOMRect(0, 0, vw, vh);
1667
1725
  const padding = 16;
1668
- let width = this.autoSize && naturalSize ? naturalSize.width : this._parseSize(this.expandedWidth, vw);
1669
- let height = this.autoSize && naturalSize ? naturalSize.height : this._parseSize(this.expandedHeight, vh);
1726
+ const configuredWidth = this._parseSize(this.expandedWidth, vw, 'width');
1727
+ const configuredHeight = this._parseSize(this.expandedHeight, vh, 'height');
1728
+ let width = this.autoSize && naturalSize ? naturalSize.width : configuredWidth;
1729
+ let height = (this.autoSize || this.autoHeight) && naturalSize
1730
+ ? Math.min(naturalSize.height, configuredHeight)
1731
+ : configuredHeight;
1670
1732
  width = Math.min(width, vw - padding * 2);
1671
1733
  height = Math.min(height, vh - padding * 2);
1672
1734
  let top = targetRect.top;
@@ -1789,60 +1851,100 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
1789
1851
  top = Math.max(padding, Math.min(top, vh - height - padding));
1790
1852
  return new DOMRect(left, top, width, height);
1791
1853
  }
1792
- _parseSize(value, ref) {
1793
- const num = parseFloat(value);
1854
+ _measureNaturalSize(panel) {
1855
+ const prevW = panel.style.getPropertyValue('--_panel-width');
1856
+ const prevH = panel.style.getPropertyValue('--_panel-height');
1857
+ const prevPanelW = panel.style.width;
1858
+ const prevPanelH = panel.style.height;
1859
+ const bodyEl = this.shadowRoot.querySelector('.body');
1860
+ const prevOverflow = bodyEl?.style.overflow ?? '';
1861
+ const configuredWidth = Math.min(this._parseSize(this.expandedWidth, window.innerWidth, 'width'), window.innerWidth - 32);
1862
+ panel.style.width = this.autoSize ? 'auto' : `${configuredWidth}px`;
1863
+ panel.style.height = 'auto';
1864
+ panel.style.setProperty('--_panel-width', this.autoSize ? 'max-content' : `${configuredWidth}px`);
1865
+ panel.style.setProperty('--_panel-height', 'max-content');
1866
+ if (bodyEl)
1867
+ bodyEl.style.overflow = 'visible';
1868
+ const size = { width: this._inner.scrollWidth, height: this._inner.scrollHeight };
1869
+ panel.style.setProperty('--_panel-width', prevW);
1870
+ panel.style.setProperty('--_panel-height', prevH);
1871
+ panel.style.width = prevPanelW;
1872
+ panel.style.height = prevPanelH;
1873
+ if (bodyEl)
1874
+ bodyEl.style.overflow = prevOverflow;
1875
+ return size;
1876
+ }
1877
+ _parseSize(value, ref, axis) {
1878
+ const normalized = value.trim();
1879
+ if (/^(calc|min|max|clamp)\(/i.test(normalized) && CSS.supports(axis, normalized)) {
1880
+ const probe = document.createElement('div');
1881
+ Object.assign(probe.style, {
1882
+ position: 'fixed',
1883
+ visibility: 'hidden',
1884
+ pointerEvents: 'none',
1885
+ contain: 'strict',
1886
+ width: axis === 'width' ? normalized : '0',
1887
+ height: axis === 'height' ? normalized : '0'
1888
+ });
1889
+ document.body.appendChild(probe);
1890
+ const measured = probe.getBoundingClientRect()[axis];
1891
+ probe.remove();
1892
+ if (measured > 0)
1893
+ return measured;
1894
+ }
1895
+ const num = parseFloat(normalized);
1794
1896
  if (Number.isNaN(num))
1795
1897
  return 352;
1796
- if (value.endsWith('px'))
1898
+ if (normalized.endsWith('px'))
1797
1899
  return num;
1798
- if (value.endsWith('rem'))
1900
+ if (normalized.endsWith('rem'))
1799
1901
  return num * 16;
1800
- if (value.endsWith('em'))
1902
+ if (normalized.endsWith('em'))
1801
1903
  return num * 16;
1802
- if (value.endsWith('%'))
1904
+ if (normalized.endsWith('%'))
1803
1905
  return (num / 100) * ref;
1804
- if (value.endsWith('vw'))
1906
+ if (normalized.endsWith('vw'))
1805
1907
  return (num / 100) * window.innerWidth;
1806
- if (value.endsWith('vh'))
1908
+ if (normalized.endsWith('vh'))
1807
1909
  return (num / 100) * window.innerHeight;
1808
1910
  return num;
1809
1911
  }
1810
1912
  static { this.styles = [
1811
1913
  sharedStyles,
1812
- css `
1813
- :host {
1814
- display: contents;
1815
- }
1816
-
1817
- .backdrop {
1818
- position: fixed;
1819
- inset: 0;
1820
- background-color: var(--scrim);
1821
- opacity: 0;
1822
- visibility: hidden;
1823
- transition:
1824
- opacity var(--_backdrop-duration, 0.35s) var(--_backdrop-ease, cubic-bezier(0.2, 0, 0, 1)),
1825
- visibility var(--_backdrop-duration, 0.35s) var(--_backdrop-ease, cubic-bezier(0.2, 0, 0, 1));
1826
- z-index: calc(var(--_z-index, 100) - 1);
1827
- }
1828
-
1829
- .backdrop.open {
1830
- opacity: 1;
1831
- visibility: visible;
1832
- }
1833
-
1834
- .panel {
1835
- position: fixed;
1836
- visibility: hidden;
1837
- opacity: 0;
1838
- pointer-events: none;
1839
- display: flex;
1840
- flex-direction: column;
1841
- overflow: hidden;
1842
- background-color: var(--surface-container-high);
1843
- color: var(--on-surface);
1844
- border-radius: var(--moni-morph-panel-radius, 1.75rem);
1845
- box-shadow: var(--elevate2);
1914
+ css `
1915
+ :host {
1916
+ display: contents;
1917
+ }
1918
+
1919
+ .backdrop {
1920
+ position: fixed;
1921
+ inset: 0;
1922
+ background-color: var(--scrim);
1923
+ opacity: 0;
1924
+ visibility: hidden;
1925
+ transition:
1926
+ opacity var(--_backdrop-duration, 0.35s) var(--_backdrop-ease, cubic-bezier(0.2, 0, 0, 1)),
1927
+ visibility var(--_backdrop-duration, 0.35s) var(--_backdrop-ease, cubic-bezier(0.2, 0, 0, 1));
1928
+ z-index: calc(var(--_z-index, 100) - 1);
1929
+ }
1930
+
1931
+ .backdrop.open {
1932
+ opacity: 1;
1933
+ visibility: visible;
1934
+ }
1935
+
1936
+ .panel {
1937
+ position: fixed;
1938
+ visibility: hidden;
1939
+ opacity: 0;
1940
+ pointer-events: none;
1941
+ display: flex;
1942
+ flex-direction: column;
1943
+ overflow: hidden;
1944
+ background-color: var(--surface-container-high);
1945
+ color: var(--on-surface);
1946
+ border-radius: var(--moni-morph-panel-radius, 1.75rem);
1947
+ box-shadow: var(--elevate2);
1846
1948
  z-index: var(--_z-index, 100);
1847
1949
  }
1848
1950
 
@@ -1858,89 +1960,90 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
1858
1960
  .panel.fullscreen footer {
1859
1961
  padding-block-end: max(1.5rem, env(safe-area-inset-bottom));
1860
1962
  }
1861
-
1862
- .panel-inner {
1863
- display: flex;
1864
- flex-direction: column;
1865
- width: var(--_panel-width, 100%);
1866
- height: var(--_panel-height, 100%);
1867
- flex-shrink: 0;
1868
- overflow: hidden;
1869
- }
1870
-
1871
- header {
1872
- display: flex;
1873
- align-items: center;
1874
- justify-content: space-between;
1875
- gap: 0.75rem;
1876
- padding: 1.25rem 1.5rem 0.75rem;
1877
- min-block-size: 3.5rem;
1878
- }
1879
-
1880
- header.is-empty {
1881
- display: none;
1882
- }
1883
-
1963
+
1964
+ .panel-inner {
1965
+ display: flex;
1966
+ flex-direction: column;
1967
+ width: var(--_panel-width, 100%);
1968
+ height: var(--_panel-height, 100%);
1969
+ flex-shrink: 0;
1970
+ overflow: hidden;
1971
+ }
1972
+
1973
+ header {
1974
+ display: flex;
1975
+ align-items: center;
1976
+ justify-content: space-between;
1977
+ gap: 0.75rem;
1978
+ padding: 1.25rem 1.5rem 0.75rem;
1979
+ min-block-size: 3.5rem;
1980
+ }
1981
+
1982
+ header.is-empty {
1983
+ display: none;
1984
+ }
1985
+
1884
1986
  .body {
1885
1987
  flex: 1;
1886
1988
  overflow-y: var(--moni-morph-body-overflow-y, auto);
1887
1989
  overflow-x: var(--moni-morph-body-overflow-x, hidden);
1888
- padding: var(--moni-morph-body-padding, 0 1.5rem);
1889
- scrollbar-gutter: var(--moni-morph-body-scrollbar-gutter, stable);
1890
- }
1891
-
1892
- .panel.is-animating .body {
1893
- overflow: hidden !important;
1894
- }
1895
-
1896
- .panel.is-animating .body::-webkit-scrollbar {
1897
- display: none;
1898
- }
1899
-
1900
- footer {
1901
- display: flex;
1902
- align-items: center;
1903
- justify-content: flex-end;
1904
- gap: 0.5rem;
1905
- padding: 1rem 1.5rem 1.5rem;
1906
- border-top: 0.0625rem solid var(--outline-variant);
1907
- }
1908
-
1909
- footer.is-empty {
1910
- display: none;
1911
- }
1912
-
1913
- .close-btn {
1914
- display: inline-flex;
1915
- align-items: center;
1916
- justify-content: center;
1917
- inline-size: 2.5rem;
1918
- block-size: 2.5rem;
1919
- padding: 0;
1920
- border: none;
1921
- border-radius: 50%;
1922
- background: transparent;
1923
- color: var(--on-surface-variant);
1924
- cursor: pointer;
1925
- font-size: 1.25rem;
1926
- }
1927
-
1928
- .close-btn:hover {
1929
- background-color: var(--active);
1930
- }
1931
-
1932
- .morph-text,
1933
- .morph-icon {
1934
- position: fixed;
1935
- pointer-events: none;
1936
- box-sizing: border-box;
1937
- overflow: hidden;
1938
- will-change: transform, width, height, color, font-size;
1939
- }
1940
-
1941
- .trigger-label-slot {
1942
- display: none;
1943
- }
1990
+ overscroll-behavior: contain;
1991
+ padding: var(--moni-morph-body-padding, 0 1.5rem);
1992
+ scrollbar-gutter: var(--moni-morph-body-scrollbar-gutter, stable);
1993
+ }
1994
+
1995
+ .panel.is-animating .body {
1996
+ overflow: hidden !important;
1997
+ }
1998
+
1999
+ .panel.is-animating .body::-webkit-scrollbar {
2000
+ display: none;
2001
+ }
2002
+
2003
+ footer {
2004
+ display: flex;
2005
+ align-items: center;
2006
+ justify-content: flex-end;
2007
+ gap: 0.5rem;
2008
+ padding: 1rem 1.5rem 1.5rem;
2009
+ border-top: 0.0625rem solid var(--outline-variant);
2010
+ }
2011
+
2012
+ footer.is-empty {
2013
+ display: none;
2014
+ }
2015
+
2016
+ .close-btn {
2017
+ display: inline-flex;
2018
+ align-items: center;
2019
+ justify-content: center;
2020
+ inline-size: 2.5rem;
2021
+ block-size: 2.5rem;
2022
+ padding: 0;
2023
+ border: none;
2024
+ border-radius: 50%;
2025
+ background: transparent;
2026
+ color: var(--on-surface-variant);
2027
+ cursor: pointer;
2028
+ font-size: 1.25rem;
2029
+ }
2030
+
2031
+ .close-btn:hover {
2032
+ background-color: var(--active);
2033
+ }
2034
+
2035
+ .morph-text,
2036
+ .morph-icon {
2037
+ position: fixed;
2038
+ pointer-events: none;
2039
+ box-sizing: border-box;
2040
+ overflow: hidden;
2041
+ will-change: transform, width, height, color, font-size;
2042
+ }
2043
+
2044
+ .trigger-label-slot {
2045
+ display: none;
2046
+ }
1944
2047
  `
1945
2048
  ]; }
1946
2049
  /**
@@ -1968,45 +2071,45 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
1968
2071
  const visible = this._visible || this.open;
1969
2072
  const headerEmpty = !this._hasHeader && !this.showCloseButton;
1970
2073
  const fullscreen = this._usesFullscreen();
1971
- return html `
1972
- ${this.hasBackdrop ? html `
1973
- <div
1974
- class="backdrop ${visible ? 'open' : ''}"
1975
- part="backdrop"
1976
- style="${!this.modal ? 'background-color: transparent;' : ''}"
1977
- ></div>
1978
- ` : ''}
2074
+ return html `
2075
+ ${this.hasBackdrop ? html `
2076
+ <div
2077
+ class="backdrop ${visible ? 'open' : ''}"
2078
+ part="backdrop"
2079
+ style="${!this.modal ? 'background-color: transparent;' : ''}"
2080
+ ></div>
2081
+ ` : ''}
1979
2082
  <div class="panel ${fullscreen ? 'fullscreen' : ''}" part="panel">
1980
- <div class="panel-inner" part="panel-inner">
1981
- <header
1982
- class="${headerEmpty ? 'is-empty' : ''}"
1983
- part="header"
1984
- >
1985
- <div class="header-morph-wrapper"><slot name="header" @slotchange=${this._onHeaderSlotChange}></slot></div>
2083
+ <div class="panel-inner" part="panel-inner">
2084
+ <header
2085
+ class="${headerEmpty ? 'is-empty' : ''}"
2086
+ part="header"
2087
+ >
2088
+ <div class="header-morph-wrapper"><slot name="header" @slotchange=${this._onHeaderSlotChange}></slot></div>
1986
2089
  ${this.showCloseButton
1987
- ? html `
1988
- <button
1989
- class="close-btn"
1990
- @click=${this.hide}
1991
- aria-label="Cerrar"
1992
- >
1993
- <moni-icon name="close"></moni-icon>
1994
- </button>
2090
+ ? html `
2091
+ <button
2092
+ class="close-btn"
2093
+ @click=${this.hide}
2094
+ aria-label="Cerrar"
2095
+ >
2096
+ <moni-icon name="close"></moni-icon>
2097
+ </button>
1995
2098
  `
1996
- : ''}
1997
- </header>
1998
- <div class="body" part="body"><slot></slot></div>
1999
- <footer
2000
- class="${this._hasFooter ? '' : 'is-empty'}"
2001
- part="footer"
2002
- >
2003
- <slot name="footer" @slotchange=${this._onFooterSlotChange}></slot>
2004
- </footer>
2005
- </div>
2006
- </div>
2007
- <div class="trigger-label-slot">
2008
- <slot name="trigger-label" @slotchange=${this._onTriggerLabelSlotChange}></slot>
2009
- </div>
2099
+ : ''}
2100
+ </header>
2101
+ <div class="body" part="body"><slot></slot></div>
2102
+ <footer
2103
+ class="${this._hasFooter ? '' : 'is-empty'}"
2104
+ part="footer"
2105
+ >
2106
+ <slot name="footer" @slotchange=${this._onFooterSlotChange}></slot>
2107
+ </footer>
2108
+ </div>
2109
+ </div>
2110
+ <div class="trigger-label-slot">
2111
+ <slot name="trigger-label" @slotchange=${this._onTriggerLabelSlotChange}></slot>
2112
+ </div>
2010
2113
  `;
2011
2114
  }
2012
2115
  };
@@ -2055,6 +2158,9 @@ __decorate([
2055
2158
  __decorate([
2056
2159
  property({ type: Boolean, reflect: true, attribute: 'auto-size', converter: litBool })
2057
2160
  ], MoniMorphModal.prototype, "autoSize", void 0);
2161
+ __decorate([
2162
+ property({ type: Boolean, reflect: true, attribute: 'auto-height', converter: litBool })
2163
+ ], MoniMorphModal.prototype, "autoHeight", void 0);
2058
2164
  __decorate([
2059
2165
  property({ type: Boolean, reflect: true, converter: litBool })
2060
2166
  ], MoniMorphModal.prototype, "fullscreen", void 0);