@moni-labs/moni-ui 0.3.0 → 0.3.2
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.
- package/custom-elements.json +5230 -1007
- package/dist/components/_base/moni-element.d.ts +16 -9
- package/dist/components/_base/moni-element.d.ts.map +1 -1
- package/dist/components/_base/moni-element.js +63 -9
- package/dist/components/index.js +2 -2
- package/dist/components/loading-shapes.d.ts +19 -0
- package/dist/components/loading-shapes.d.ts.map +1 -1
- package/dist/components/loading-shapes.js +19 -0
- package/dist/components/moni-app-bar.d.ts +72 -62
- package/dist/components/moni-app-bar.d.ts.map +1 -1
- package/dist/components/moni-app-bar.js +72 -62
- package/dist/components/moni-badge.d.ts +64 -65
- package/dist/components/moni-badge.d.ts.map +1 -1
- package/dist/components/moni-badge.js +64 -66
- package/dist/components/moni-bottom-sheet.d.ts +129 -61
- package/dist/components/moni-bottom-sheet.d.ts.map +1 -1
- package/dist/components/moni-bottom-sheet.js +217 -131
- package/dist/components/moni-button-group.d.ts +107 -29
- package/dist/components/moni-button-group.d.ts.map +1 -1
- package/dist/components/moni-button-group.js +107 -29
- package/dist/components/moni-button-segment.d.ts +53 -12
- package/dist/components/moni-button-segment.d.ts.map +1 -1
- package/dist/components/moni-button-segment.js +53 -12
- package/dist/components/moni-button.d.ts +116 -38
- package/dist/components/moni-button.d.ts.map +1 -1
- package/dist/components/moni-button.js +128 -38
- package/dist/components/moni-card.d.ts +68 -50
- package/dist/components/moni-card.d.ts.map +1 -1
- package/dist/components/moni-card.js +68 -50
- package/dist/components/moni-carousel.d.ts +484 -53
- package/dist/components/moni-carousel.d.ts.map +1 -1
- package/dist/components/moni-carousel.js +1024 -245
- package/dist/components/moni-checkbox.d.ts +49 -46
- package/dist/components/moni-checkbox.d.ts.map +1 -1
- package/dist/components/moni-checkbox.js +55 -48
- package/dist/components/moni-chip.d.ts +100 -33
- package/dist/components/moni-chip.d.ts.map +1 -1
- package/dist/components/moni-chip.js +104 -34
- package/dist/components/moni-color-field.d.ts +99 -24
- package/dist/components/moni-color-field.d.ts.map +1 -1
- package/dist/components/moni-color-field.js +99 -24
- package/dist/components/moni-context-menu.d.ts +72 -26
- package/dist/components/moni-context-menu.d.ts.map +1 -1
- package/dist/components/moni-context-menu.js +76 -30
- package/dist/components/moni-dialog.d.ts +84 -59
- package/dist/components/moni-dialog.d.ts.map +1 -1
- package/dist/components/moni-dialog.js +105 -58
- package/dist/components/moni-divider.d.ts +39 -27
- package/dist/components/moni-divider.d.ts.map +1 -1
- package/dist/components/moni-divider.js +42 -30
- package/dist/components/moni-expansion.d.ts +32 -22
- package/dist/components/moni-expansion.d.ts.map +1 -1
- package/dist/components/moni-expansion.js +32 -22
- package/dist/components/moni-fab-menu.d.ts +61 -23
- package/dist/components/moni-fab-menu.d.ts.map +1 -1
- package/dist/components/moni-fab-menu.js +69 -31
- package/dist/components/moni-fab.d.ts +86 -28
- package/dist/components/moni-fab.d.ts.map +1 -1
- package/dist/components/moni-fab.js +92 -34
- package/dist/components/moni-file-field.d.ts +118 -30
- package/dist/components/moni-file-field.d.ts.map +1 -1
- package/dist/components/moni-file-field.js +118 -30
- package/dist/components/moni-icon.d.ts +40 -35
- package/dist/components/moni-icon.d.ts.map +1 -1
- package/dist/components/moni-icon.js +43 -38
- package/dist/components/moni-list-item.d.ts +46 -33
- package/dist/components/moni-list-item.d.ts.map +1 -1
- package/dist/components/moni-list-item.js +61 -41
- package/dist/components/moni-list.d.ts +30 -20
- package/dist/components/moni-list.d.ts.map +1 -1
- package/dist/components/moni-list.js +36 -21
- package/dist/components/moni-loading-indicator.d.ts +54 -22
- package/dist/components/moni-loading-indicator.d.ts.map +1 -1
- package/dist/components/moni-loading-indicator.js +54 -22
- package/dist/components/moni-menu-item.d.ts +23 -16
- package/dist/components/moni-menu-item.d.ts.map +1 -1
- package/dist/components/moni-menu-item.js +23 -16
- package/dist/components/moni-menu.d.ts +81 -28
- package/dist/components/moni-menu.d.ts.map +1 -1
- package/dist/components/moni-menu.js +81 -30
- package/dist/components/moni-morph-modal.d.ts +141 -0
- package/dist/components/moni-morph-modal.d.ts.map +1 -1
- package/dist/components/moni-morph-modal.js +295 -58
- package/dist/components/moni-nav-item.d.ts +59 -29
- package/dist/components/moni-nav-item.d.ts.map +1 -1
- package/dist/components/moni-nav-item.js +59 -29
- package/dist/components/moni-nav.d.ts +94 -35
- package/dist/components/moni-nav.d.ts.map +1 -1
- package/dist/components/moni-nav.js +94 -35
- package/dist/components/moni-progress.d.ts +99 -55
- package/dist/components/moni-progress.d.ts.map +1 -1
- package/dist/components/moni-progress.js +99 -55
- package/dist/components/moni-radio.d.ts +62 -50
- package/dist/components/moni-radio.d.ts.map +1 -1
- package/dist/components/moni-radio.js +65 -52
- package/dist/components/moni-ripple.d.ts +74 -59
- package/dist/components/moni-ripple.d.ts.map +1 -1
- package/dist/components/moni-ripple.js +74 -59
- package/dist/components/moni-segmented-button.d.ts +91 -16
- package/dist/components/moni-segmented-button.d.ts.map +1 -1
- package/dist/components/moni-segmented-button.js +94 -17
- package/dist/components/moni-select-option.d.ts +30 -23
- package/dist/components/moni-select-option.d.ts.map +1 -1
- package/dist/components/moni-select-option.js +30 -23
- package/dist/components/moni-select.d.ts +300 -35
- package/dist/components/moni-select.d.ts.map +1 -1
- package/dist/components/moni-select.js +323 -39
- package/dist/components/moni-side-sheet.d.ts +94 -32
- package/dist/components/moni-side-sheet.d.ts.map +1 -1
- package/dist/components/moni-side-sheet.js +94 -32
- package/dist/components/moni-slider.d.ts +152 -41
- package/dist/components/moni-slider.d.ts.map +1 -1
- package/dist/components/moni-slider.js +154 -42
- package/dist/components/moni-snackbar.d.ts +53 -43
- package/dist/components/moni-snackbar.d.ts.map +1 -1
- package/dist/components/moni-snackbar.js +53 -43
- package/dist/components/moni-split-button.d.ts +63 -18
- package/dist/components/moni-split-button.d.ts.map +1 -1
- package/dist/components/moni-split-button.js +63 -18
- package/dist/components/moni-step.d.ts +36 -24
- package/dist/components/moni-step.d.ts.map +1 -1
- package/dist/components/moni-step.js +41 -29
- package/dist/components/moni-stepper.d.ts +64 -27
- package/dist/components/moni-stepper.d.ts.map +1 -1
- package/dist/components/moni-stepper.js +72 -34
- package/dist/components/moni-switch.d.ts +57 -46
- package/dist/components/moni-switch.d.ts.map +1 -1
- package/dist/components/moni-switch.js +59 -47
- package/dist/components/moni-tab.d.ts +26 -18
- package/dist/components/moni-tab.d.ts.map +1 -1
- package/dist/components/moni-tab.js +29 -21
- package/dist/components/moni-tabs.d.ts +34 -28
- package/dist/components/moni-tabs.d.ts.map +1 -1
- package/dist/components/moni-tabs.js +34 -28
- package/dist/components/moni-text-field.d.ts +139 -29
- package/dist/components/moni-text-field.d.ts.map +1 -1
- package/dist/components/moni-text-field.js +157 -31
- package/dist/components/moni-textarea.d.ts +127 -29
- package/dist/components/moni-textarea.d.ts.map +1 -1
- package/dist/components/moni-textarea.js +131 -32
- package/dist/components/moni-time-picker.d.ts +114 -24
- package/dist/components/moni-time-picker.d.ts.map +1 -1
- package/dist/components/moni-time-picker.js +127 -33
- package/dist/components/moni-toolbar.d.ts +37 -23
- package/dist/components/moni-toolbar.d.ts.map +1 -1
- package/dist/components/moni-toolbar.js +37 -23
- package/dist/components/moni-tooltip.d.ts +100 -36
- package/dist/components/moni-tooltip.d.ts.map +1 -1
- package/dist/components/moni-tooltip.js +104 -40
- package/dist/components/moni-typography.d.ts +68 -30
- package/dist/components/moni-typography.d.ts.map +1 -1
- package/dist/components/moni-typography.js +70 -32
- package/dist/styles/tokens.css +7 -7
- package/dist/types/events.d.ts +17 -0
- package/dist/types/events.d.ts.map +1 -0
- package/dist/types/events.js +1 -0
- package/dist/utils/event-emitter.d.ts +13 -0
- package/dist/utils/event-emitter.d.ts.map +1 -0
- package/dist/utils/event-emitter.js +13 -0
- package/package.json +2 -1
- package/src/components/_base/moni-element.ts +73 -9
- package/src/components/index.ts +2 -2
- package/src/components/loading-shapes.ts +19 -0
- package/src/components/moni-app-bar.test.ts +10 -10
- package/src/components/moni-app-bar.ts +72 -62
- package/src/components/moni-badge.ts +64 -66
- package/src/components/moni-bottom-sheet.test.ts +39 -45
- package/src/components/moni-bottom-sheet.ts +222 -131
- package/src/components/moni-button-group.test.ts +14 -14
- package/src/components/moni-button-group.ts +107 -29
- package/src/components/moni-button-segment.ts +53 -12
- package/src/components/moni-button.test.ts +28 -26
- package/src/components/moni-button.ts +139 -39
- package/src/components/moni-card.test.ts +6 -6
- package/src/components/moni-card.ts +70 -50
- package/src/components/moni-carousel.test.ts +12 -12
- package/src/components/moni-carousel.ts +1129 -269
- package/src/components/moni-checkbox.test.ts +7 -7
- package/src/components/moni-checkbox.ts +62 -48
- package/src/components/moni-chip.test.ts +17 -17
- package/src/components/moni-chip.ts +112 -34
- package/src/components/moni-color-field.test.ts +5 -5
- package/src/components/moni-color-field.ts +108 -24
- package/src/components/moni-context-menu.test.ts +11 -11
- package/src/components/moni-context-menu.ts +76 -30
- package/src/components/moni-dialog.ts +108 -59
- package/src/components/moni-divider.test.ts +4 -4
- package/src/components/moni-divider.ts +42 -30
- package/src/components/moni-expansion.ts +32 -22
- package/src/components/moni-fab-menu.test.ts +11 -11
- package/src/components/moni-fab-menu.ts +69 -31
- package/src/components/moni-fab.test.ts +16 -16
- package/src/components/moni-fab.ts +100 -34
- package/src/components/moni-file-field.test.ts +8 -8
- package/src/components/moni-file-field.ts +132 -30
- package/src/components/moni-icon.test.ts +11 -11
- package/src/components/moni-icon.ts +43 -38
- package/src/components/moni-list-item.test.ts +10 -10
- package/src/components/moni-list-item.ts +61 -41
- package/src/components/moni-list.ts +37 -21
- package/src/components/moni-loading-indicator.test.ts +3 -3
- package/src/components/moni-loading-indicator.ts +54 -22
- package/src/components/moni-menu-item.ts +23 -16
- package/src/components/moni-menu.test.ts +7 -7
- package/src/components/moni-menu.ts +87 -30
- package/src/components/moni-morph-modal.test.ts +18 -17
- package/src/components/moni-morph-modal.ts +327 -60
- package/src/components/moni-nav-item.ts +59 -29
- package/src/components/moni-nav.test.ts +11 -11
- package/src/components/moni-nav.ts +94 -35
- package/src/components/moni-progress.test.ts +9 -9
- package/src/components/moni-progress.ts +100 -56
- package/src/components/moni-radio.test.ts +8 -8
- package/src/components/moni-radio.ts +71 -51
- package/src/components/moni-ripple.ts +74 -59
- package/src/components/moni-segmented-button.test.ts +4 -4
- package/src/components/moni-segmented-button.ts +94 -17
- package/src/components/moni-select-option.ts +30 -23
- package/src/components/moni-select.test.ts +11 -11
- package/src/components/moni-select.ts +361 -50
- package/src/components/moni-side-sheet.test.ts +7 -7
- package/src/components/moni-side-sheet.ts +94 -32
- package/src/components/moni-slider.test.ts +7 -7
- package/src/components/moni-slider.ts +165 -42
- package/src/components/moni-snackbar.test.ts +8 -8
- package/src/components/moni-snackbar.ts +53 -43
- package/src/components/moni-split-button.ts +63 -18
- package/src/components/moni-step.test.ts +7 -7
- package/src/components/moni-step.ts +41 -29
- package/src/components/moni-stepper.test.ts +7 -7
- package/src/components/moni-stepper.ts +72 -34
- package/src/components/moni-switch.test.ts +12 -12
- package/src/components/moni-switch.ts +66 -47
- package/src/components/moni-tab.test.ts +5 -5
- package/src/components/moni-tab.ts +29 -21
- package/src/components/moni-tabs.ts +34 -28
- package/src/components/moni-text-field.test.ts +13 -13
- package/src/components/moni-text-field.ts +181 -30
- package/src/components/moni-textarea.test.ts +17 -17
- package/src/components/moni-textarea.ts +155 -31
- package/src/components/moni-time-picker.test.ts +5 -5
- package/src/components/moni-time-picker.ts +128 -33
- package/src/components/moni-toolbar.test.ts +8 -8
- package/src/components/moni-toolbar.ts +37 -23
- package/src/components/moni-tooltip.test.ts +15 -15
- package/src/components/moni-tooltip.ts +107 -40
- package/src/components/moni-typography.test.ts +10 -10
- package/src/components/moni-typography.ts +73 -32
- package/src/styles/tokens.css +7 -7
- package/src/types/events.ts +17 -0
- package/src/utils/event-emitter.ts +26 -0
|
@@ -22,49 +22,49 @@ gsap.registerPlugin(Flip, CustomEase);
|
|
|
22
22
|
CustomEase.create('morph-open', '0.15, 0.85, 0.2, 1');
|
|
23
23
|
CustomEase.create('morph-close', '0.4, 0, 0.2, 1');
|
|
24
24
|
/**
|
|
25
|
-
* Material Design 3 Morph Modal
|
|
25
|
+
* Componente Material Design 3 Morph Modal.
|
|
26
26
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* modal
|
|
27
|
+
* Un diálogo altamente interactivo que usa animaciones GSAP FLIP (First, Last, Invert, Play)
|
|
28
|
+
* para "transformar" (morph) sin problemas cualquier elemento clickeado en la página en una superficie
|
|
29
|
+
* modal completa, y transformarlo de vuelta cuando se cierra.
|
|
30
30
|
*
|
|
31
|
-
* **
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
31
|
+
* **Coreografía de movimiento:**
|
|
32
|
+
* Este componente implementa el patrón complejo de transformación de contenedor de M3. Cuando
|
|
33
|
+
* se activa, el elemento origen se expande visualmente hacia el modal. El color de fondo,
|
|
34
|
+
* el radio del borde y la tipografía del modal se desvanecen y se funden
|
|
35
|
+
* perfectamente con el elemento de origen.
|
|
36
36
|
*
|
|
37
|
-
* **
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
37
|
+
* **Mecanismo de activación:**
|
|
38
|
+
* Los consumidores deben proporcionar la propiedad `triggerEvent` que contenga el `Event`
|
|
39
|
+
* de puntero/clic original que inició la acción de apertura. El componente extrae
|
|
40
|
+
* el `event.target` (o usa `clientX/Y` como respaldo) para determinar las coordenadas
|
|
41
|
+
* de origen exactas para la animación GSAP FLIP.
|
|
42
42
|
*
|
|
43
|
-
* **
|
|
44
|
-
*
|
|
45
|
-
* `Escape`
|
|
46
|
-
*
|
|
43
|
+
* **Comportamiento del diálogo:**
|
|
44
|
+
* Internamente, utiliza el elemento nativo `<dialog>`. Atrapa el foco, soporta
|
|
45
|
+
* `Escape` para cerrar, y maneja clics en el fondo/scrim (que activan la
|
|
46
|
+
* animación de morphing inverso antes de cerrar realmente el diálogo nativo).
|
|
47
47
|
*
|
|
48
48
|
* @example
|
|
49
49
|
* ```html
|
|
50
|
-
* <moni-morph-modal id="myModal" title="
|
|
51
|
-
* <p>
|
|
50
|
+
* <moni-morph-modal id="myModal" title="Detalles">
|
|
51
|
+
* <p>Este modal se transformó desde el botón que acabas de clickear.</p>
|
|
52
52
|
* </moni-morph-modal>
|
|
53
53
|
*
|
|
54
|
-
* <moni-button id="openBtn">
|
|
54
|
+
* <moni-button id="openBtn">Abrir Detalles</moni-button>
|
|
55
55
|
*
|
|
56
56
|
* <script>
|
|
57
57
|
* const modal = document.getElementById('myModal');
|
|
58
58
|
* document.getElementById('openBtn').addEventListener('click', (e) => {
|
|
59
|
-
* modal.triggerEvent = e; //
|
|
59
|
+
* modal.triggerEvent = e; // Pasa el evento para que sepa desde dónde transformarse
|
|
60
60
|
* modal.open = true;
|
|
61
61
|
* });
|
|
62
62
|
* </script>
|
|
63
63
|
* ```
|
|
64
64
|
*
|
|
65
|
-
* @slot default -
|
|
66
|
-
* @slot header -
|
|
67
|
-
* @slot actions -
|
|
65
|
+
* @slot default - El contenido del cuerpo principal del modal.
|
|
66
|
+
* @slot header - Contenido de encabezado personalizado (sobrescribe el atributo `title`).
|
|
67
|
+
* @slot actions - Botones de acción mostrados en la parte inferior derecha.
|
|
68
68
|
*/
|
|
69
69
|
const litBool = {
|
|
70
70
|
fromAttribute: (value) => value !== 'false' && value !== null,
|
|
@@ -73,20 +73,95 @@ const litBool = {
|
|
|
73
73
|
let MoniMorphModal = class MoniMorphModal extends MoniElement {
|
|
74
74
|
constructor() {
|
|
75
75
|
super(...arguments);
|
|
76
|
+
/**
|
|
77
|
+
* Selector del elemento disparador desde el cual transformarse (ej. '#fab' o '.my-button').
|
|
78
|
+
* Si se omite, el modal aún puede activarse programáticamente estableciendo `open = true`.
|
|
79
|
+
* @type {string}
|
|
80
|
+
*/
|
|
76
81
|
this.target = '';
|
|
82
|
+
/**
|
|
83
|
+
* Controla el estado abierto/cerrado del modal.
|
|
84
|
+
* Puede establecerse directamente, o se gestiona internamente cuando se hace clic en el elemento `target`.
|
|
85
|
+
* @type {boolean}
|
|
86
|
+
*/
|
|
77
87
|
this.open = false;
|
|
88
|
+
/**
|
|
89
|
+
* Si es true, renderiza un fondo y atrapa el foco, actuando como un verdadero diálogo modal.
|
|
90
|
+
* @type {boolean}
|
|
91
|
+
* @default true
|
|
92
|
+
*/
|
|
78
93
|
this.modal = true;
|
|
94
|
+
/**
|
|
95
|
+
* Posición preferida del modal en relación con la ventana gráfica.
|
|
96
|
+
* @type {Placement}
|
|
97
|
+
* @default 'center'
|
|
98
|
+
*/
|
|
79
99
|
this.placement = 'center';
|
|
100
|
+
/**
|
|
101
|
+
* El ancho del modal cuando está completamente expandido.
|
|
102
|
+
* @type {string}
|
|
103
|
+
* @default '22rem'
|
|
104
|
+
*/
|
|
80
105
|
this.expandedWidth = '22rem';
|
|
106
|
+
/**
|
|
107
|
+
* La altura del modal cuando está completamente expandido.
|
|
108
|
+
* @type {string}
|
|
109
|
+
* @default '18rem'
|
|
110
|
+
*/
|
|
81
111
|
this.expandedHeight = '18rem';
|
|
112
|
+
/**
|
|
113
|
+
* Si es true, hacer clic fuera del modal lo cerrará.
|
|
114
|
+
* @type {boolean}
|
|
115
|
+
* @default true
|
|
116
|
+
*/
|
|
82
117
|
this.closeOnClickOutside = true;
|
|
118
|
+
/**
|
|
119
|
+
* Si es true, presionar la tecla Escape cerrará el modal.
|
|
120
|
+
* @type {boolean}
|
|
121
|
+
* @default true
|
|
122
|
+
*/
|
|
83
123
|
this.closeOnEsc = true;
|
|
124
|
+
/**
|
|
125
|
+
* Si es true, muestra un botón de icono de cierre por defecto en el encabezado.
|
|
126
|
+
* @type {boolean}
|
|
127
|
+
*/
|
|
84
128
|
this.showCloseButton = false;
|
|
129
|
+
/**
|
|
130
|
+
* Si es true, intenta fundir/transformar una etiqueta del disparador hacia el encabezado del modal.
|
|
131
|
+
* @type {boolean}
|
|
132
|
+
*/
|
|
85
133
|
this.morphLabel = false;
|
|
134
|
+
/**
|
|
135
|
+
* Un selector CSS personalizado utilizado para encontrar el elemento de etiqueta específico dentro del target a transformar.
|
|
136
|
+
* @type {string}
|
|
137
|
+
*/
|
|
86
138
|
this.morphLabelSelector = '';
|
|
139
|
+
/**
|
|
140
|
+
* Si es true, renderiza un fondo atenuado detrás del modal.
|
|
141
|
+
* @type {boolean}
|
|
142
|
+
* @default true
|
|
143
|
+
*/
|
|
87
144
|
this.hasBackdrop = true;
|
|
145
|
+
/**
|
|
146
|
+
* Si es true, oculta el elemento disparador (target) mientras el modal está abierto.
|
|
147
|
+
* @type {boolean}
|
|
148
|
+
*/
|
|
88
149
|
this.hideTarget = false;
|
|
150
|
+
/**
|
|
151
|
+
* Si es true, fuerza al modal a cubrir visualmente la ubicación original del target antes de expandirse.
|
|
152
|
+
* @type {boolean}
|
|
153
|
+
*/
|
|
89
154
|
this.coverTarget = false;
|
|
155
|
+
/**
|
|
156
|
+
* Si es true, el modal calcula automáticamente su tamaño final basándose en el contenido interno (ignora expandedWidth y expandedHeight).
|
|
157
|
+
* @type {boolean}
|
|
158
|
+
*/
|
|
159
|
+
this.autoSize = false;
|
|
160
|
+
/**
|
|
161
|
+
* Si es true, aplica un efecto de desenfoque (blur) al contenido durante la animación de entrada y salida.
|
|
162
|
+
* @type {boolean}
|
|
163
|
+
*/
|
|
164
|
+
this.blurContent = false;
|
|
90
165
|
this._hasHeader = false;
|
|
91
166
|
this._hasFooter = false;
|
|
92
167
|
this._hasTriggerLabel = false;
|
|
@@ -97,8 +172,20 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
|
|
|
97
172
|
this._zIndex = 100;
|
|
98
173
|
this._morphEls = { text: null, icon: null };
|
|
99
174
|
this._targetStylesCache = new Map();
|
|
175
|
+
/**
|
|
176
|
+
* Handler encapsulado para el evento click en el trigger.
|
|
177
|
+
* Dispara la animación de apertura.
|
|
178
|
+
*/
|
|
100
179
|
this._onTargetClick = () => this.show();
|
|
180
|
+
/**
|
|
181
|
+
* Handler encapsulado para interceptar teclas a nivel global (ej: Escape).
|
|
182
|
+
*/
|
|
101
183
|
this._onDocKeydown = (e) => this._handleDocKeydown(e);
|
|
184
|
+
/**
|
|
185
|
+
* Handler de clics globales para detectar interacciones fuera del modal (Click outside).
|
|
186
|
+
* Sólo cierra el modal si `closeOnClickOutside` es true y el usuario no hizo clic
|
|
187
|
+
* dentro de las dimensiones del panel animado ni del botón original.
|
|
188
|
+
*/
|
|
102
189
|
this._onDocClick = (e) => {
|
|
103
190
|
if (!this.open || !this._visible || !this.closeOnClickOutside)
|
|
104
191
|
return;
|
|
@@ -134,6 +221,12 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
|
|
|
134
221
|
this._restoreTargetContent();
|
|
135
222
|
super.disconnectedCallback();
|
|
136
223
|
}
|
|
224
|
+
/**
|
|
225
|
+
* Hook del ciclo de vida reactivo (Lit).
|
|
226
|
+
* Observa cambios asíncronos en el atributo `target` para re-bindear el disparador,
|
|
227
|
+
* y reacciona a cambios programáticos de la propiedad `open` para ejecutar
|
|
228
|
+
* imperativamente la animación de apertura (`show`) o cierre (`hide`).
|
|
229
|
+
*/
|
|
137
230
|
updated(changed) {
|
|
138
231
|
super.updated(changed);
|
|
139
232
|
if (changed.has('target')) {
|
|
@@ -146,21 +239,34 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
|
|
|
146
239
|
this.hide();
|
|
147
240
|
}
|
|
148
241
|
}
|
|
242
|
+
/**
|
|
243
|
+
* Busca en el DOM el elemento que dispara el modal (el trigger) basándose en la propiedad `target`.
|
|
244
|
+
* Establece el listener de click que iniciará la animación de morphing.
|
|
245
|
+
*/
|
|
149
246
|
_resolveTarget() {
|
|
150
247
|
if (!this.target)
|
|
151
248
|
return;
|
|
152
249
|
const el = document.querySelector(this.target);
|
|
153
250
|
if (!el) {
|
|
154
|
-
|
|
251
|
+
// Es normal que no se encuentre el target si está condicionado por un #if en Svelte
|
|
252
|
+
// Se intentará resolver nuevamente al llamar a show()
|
|
155
253
|
return;
|
|
156
254
|
}
|
|
255
|
+
// Si el target cambió dinámicamente, limpiamos el listener anterior para evitar memory leaks
|
|
157
256
|
if (this._targetEl && this._targetEl !== el) {
|
|
158
257
|
this._targetEl.removeEventListener('click', this._onTargetClick);
|
|
159
258
|
}
|
|
160
259
|
this._targetEl = el;
|
|
161
260
|
this._targetEl.addEventListener('click', this._onTargetClick);
|
|
162
261
|
}
|
|
262
|
+
/**
|
|
263
|
+
* Dispara la apertura del modal y coordina la animación de FLIP (First, Last, Invert, Play) / Morphing.
|
|
264
|
+
* 1. Oculta visualmente el target original.
|
|
265
|
+
* 2. Posiciona el modal colapsado exactamente sobre el target original (mismas dimensiones, color, y radios).
|
|
266
|
+
* 3. Expande fluidamente el modal a sus dimensiones finales mediante transformaciones CSS.
|
|
267
|
+
*/
|
|
163
268
|
show() {
|
|
269
|
+
// Prevenimos ejecuciones concurrentes si ya se está animando o está visible
|
|
164
270
|
if (this._isAnimating || this._visible)
|
|
165
271
|
return;
|
|
166
272
|
if (!this._targetEl)
|
|
@@ -170,25 +276,35 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
|
|
|
170
276
|
return;
|
|
171
277
|
}
|
|
172
278
|
this._isAnimating = true;
|
|
279
|
+
// Flag interno para evitar loops infinitos en el hook `updated()`
|
|
173
280
|
this._handlingOpenChange = true;
|
|
174
281
|
this.open = true;
|
|
175
282
|
this._handlingOpenChange = false;
|
|
283
|
+
// Apilamos el modal globalmente para manejar correctamente el z-index en modales anidados
|
|
176
284
|
MoniMorphModal_1._openStack.push(this);
|
|
177
285
|
this._zIndex = 1000 + MoniMorphModal_1._openStack.length;
|
|
286
|
+
// Aplicamos variables CSS inline para gestionar las transiciones del backdrop y el modal
|
|
178
287
|
this.style.zIndex = String(this._zIndex);
|
|
179
288
|
this.style.setProperty('--_z-index', String(this._zIndex));
|
|
180
289
|
this.style.setProperty('--_backdrop-duration', '0.38s');
|
|
181
290
|
this.style.setProperty('--_backdrop-ease', 'cubic-bezier(0.15, 0.85, 0.2, 1)');
|
|
291
|
+
// Fase "First": Ocultamos o cubrimos el trigger original según la configuración del desarrollador
|
|
182
292
|
this._hideTargetContent();
|
|
183
293
|
void this.updateComplete.then(async () => {
|
|
184
294
|
if (!this._targetEl || !this._panel || !this._inner) {
|
|
185
295
|
this._isAnimating = false;
|
|
186
296
|
return;
|
|
187
297
|
}
|
|
298
|
+
// Añadimos clase para prevenir interacciones durante la animación
|
|
188
299
|
this._panel.classList.add('is-animating');
|
|
300
|
+
// Esperamos un frame para asegurar que el navegador aplicó el `display: block`
|
|
301
|
+
// necesario antes de poder leer las dimensiones.
|
|
189
302
|
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
303
|
+
// 1. "First": Calculamos el estado visual actual del trigger
|
|
190
304
|
const targetState = this._getTargetState(this._targetEl);
|
|
191
305
|
const panel = this._panel;
|
|
306
|
+
// 2. "Invert": Posicionamos el modal como un clon visual exacto del trigger.
|
|
307
|
+
// Desactivamos la sombra y forzamos el color/borde para coincidir con el botón/FAB.
|
|
192
308
|
this._applyRect(panel, targetState.rect);
|
|
193
309
|
panel.style.backgroundColor = targetState.backgroundColor;
|
|
194
310
|
panel.style.color = targetState.color;
|
|
@@ -201,20 +317,27 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
|
|
|
201
317
|
if (this._backdrop) {
|
|
202
318
|
this._backdrop.style.zIndex = String(this._zIndex - 1);
|
|
203
319
|
}
|
|
320
|
+
// Limpiamos elementos fantasma previos si el usuario interactuó muy rápido
|
|
204
321
|
this._cleanupMorphElements();
|
|
322
|
+
// Respetamos la preferencia de sistema de animaciones reducidas por accesibilidad (a11y)
|
|
205
323
|
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
324
|
+
// 3. Verificamos si debemos orquestar la animación compleja del label flotante cruzado
|
|
206
325
|
let shouldMorph = this._shouldMorphLabel() && !prefersReducedMotion;
|
|
207
326
|
const morphTargets = [];
|
|
208
327
|
let source = null;
|
|
209
328
|
const headerWrapper = this.shadowRoot.querySelector('.header-morph-wrapper');
|
|
210
329
|
if (shouldMorph) {
|
|
330
|
+
// Preparamos la estructura del header para que el texto real entre con un fade in
|
|
211
331
|
this._animateLabelOpen();
|
|
332
|
+
// Buscamos el ícono y el texto dentro del botón de origen (trigger)
|
|
212
333
|
source = this._resolveMorphSource();
|
|
334
|
+
// Si existe un nodo de texto, creamos un elemento flotante (fantasma) en el modal
|
|
213
335
|
if (source.text) {
|
|
214
336
|
const el = this._createMorphText(source.text.content, source.text.sourceEl);
|
|
215
337
|
this._positionElement(el, source.text.rect);
|
|
216
338
|
morphTargets.push(el);
|
|
217
339
|
}
|
|
340
|
+
// Hacemos lo mismo si el botón original contenía un icono
|
|
218
341
|
if (source.icon) {
|
|
219
342
|
const el = this._createMorphIcon(source.icon.element);
|
|
220
343
|
this._positionElement(el, source.icon.rect);
|
|
@@ -224,27 +347,56 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
|
|
|
224
347
|
shouldMorph = false;
|
|
225
348
|
}
|
|
226
349
|
if (shouldMorph && headerWrapper) {
|
|
350
|
+
// Ocultamos temporalmente el contenido final del header mientras animamos los elementos flotantes
|
|
227
351
|
headerWrapper.style.opacity = '0';
|
|
228
352
|
}
|
|
353
|
+
// Capturamos el estado "First" del panel (tamaño pequeño de botón) y de los elementos flotantes
|
|
229
354
|
const state = Flip.getState(panel, {
|
|
230
355
|
props: 'backgroundColor,borderRadius,color,boxShadow'
|
|
231
356
|
});
|
|
232
357
|
const morphState = Flip.getState(morphTargets, {
|
|
233
358
|
props: 'color,fontSize,fontWeight,lineHeight'
|
|
234
359
|
});
|
|
235
|
-
|
|
360
|
+
// Fase "Last": Calculamos las dimensiones expandidas del modal basándonos en la configuración
|
|
361
|
+
let naturalSize;
|
|
362
|
+
if (this.autoSize) {
|
|
363
|
+
const prevW = panel.style.getPropertyValue('--_panel-width');
|
|
364
|
+
const prevH = panel.style.getPropertyValue('--_panel-height');
|
|
365
|
+
const prevPanelW = panel.style.width;
|
|
366
|
+
const prevPanelH = panel.style.height;
|
|
367
|
+
panel.style.width = 'auto';
|
|
368
|
+
panel.style.height = 'auto';
|
|
369
|
+
panel.style.setProperty('--_panel-width', 'max-content');
|
|
370
|
+
panel.style.setProperty('--_panel-height', 'max-content');
|
|
371
|
+
const bodyEl = this.shadowRoot.querySelector('.body');
|
|
372
|
+
const prevOverflow = bodyEl ? bodyEl.style.overflow : '';
|
|
373
|
+
if (bodyEl)
|
|
374
|
+
bodyEl.style.overflow = 'visible';
|
|
375
|
+
// Forzamos al panel-inner a expandirse para medir su contenido real
|
|
376
|
+
naturalSize = { width: this._inner.scrollWidth, height: this._inner.scrollHeight };
|
|
377
|
+
panel.style.setProperty('--_panel-width', prevW);
|
|
378
|
+
panel.style.setProperty('--_panel-height', prevH);
|
|
379
|
+
panel.style.width = prevPanelW;
|
|
380
|
+
panel.style.height = prevPanelH;
|
|
381
|
+
if (bodyEl)
|
|
382
|
+
bodyEl.style.overflow = prevOverflow;
|
|
383
|
+
}
|
|
384
|
+
const finalRect = this._computeFinalRect(targetState.rect, naturalSize);
|
|
236
385
|
panel.style.setProperty('--_panel-width', `${finalRect.width}px`);
|
|
237
386
|
panel.style.setProperty('--_panel-height', `${finalRect.height}px`);
|
|
238
387
|
this._applyRect(panel, finalRect);
|
|
388
|
+
// Removemos las forzadas de estilo del trigger para que herede las propias del modal
|
|
239
389
|
panel.style.backgroundColor = '';
|
|
240
390
|
panel.style.color = '';
|
|
241
391
|
panel.style.borderRadius = '';
|
|
242
392
|
panel.style.boxShadow = '';
|
|
243
393
|
if (shouldMorph && source) {
|
|
394
|
+
// Medimos dónde van a terminar el icono y el texto dentro del modal ya expandido
|
|
244
395
|
const textRect = this._measureHeaderTextRect();
|
|
245
396
|
const iconRect = this._measureHeaderIconRect();
|
|
246
397
|
const headerComputed = window.getComputedStyle(this._header);
|
|
247
398
|
if (this._morphEls.text && textRect) {
|
|
399
|
+
// Movemos el texto flotante a su destino y le pedimos que adopte los estilos del header
|
|
248
400
|
this._positionElement(this._morphEls.text, textRect);
|
|
249
401
|
this._morphEls.text.style.color = headerComputed.color || 'var(--on-surface)';
|
|
250
402
|
this._morphEls.text.style.fontSize = headerComputed.fontSize || 'inherit';
|
|
@@ -252,6 +404,7 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
|
|
|
252
404
|
this._morphEls.text.style.lineHeight = headerComputed.lineHeight || 'inherit';
|
|
253
405
|
}
|
|
254
406
|
if (this._morphEls.icon && iconRect) {
|
|
407
|
+
// Hacemos lo mismo con el icono
|
|
255
408
|
this._positionElement(this._morphEls.icon, iconRect);
|
|
256
409
|
this._morphEls.icon.style.color = headerComputed.color || 'var(--on-surface)';
|
|
257
410
|
}
|
|
@@ -264,28 +417,34 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
|
|
|
264
417
|
onComplete: () => {
|
|
265
418
|
this._isAnimating = false;
|
|
266
419
|
this._visible = true;
|
|
267
|
-
this._panel.classList.remove('is-animating');
|
|
268
420
|
this._cleanupMorphElements();
|
|
269
421
|
if (headerWrapper)
|
|
270
422
|
headerWrapper.style.opacity = '1';
|
|
271
423
|
}
|
|
272
424
|
});
|
|
273
425
|
if (morphTargets.length > 0) {
|
|
274
|
-
|
|
426
|
+
if (this.blurContent) {
|
|
427
|
+
gsap.set(morphTargets, { filter: 'blur(16px)' });
|
|
428
|
+
}
|
|
429
|
+
const flipConfig = {
|
|
275
430
|
targets: morphTargets,
|
|
276
431
|
duration: 0.38,
|
|
277
432
|
ease: 'morph-open',
|
|
278
433
|
zIndex: this._zIndex + 10
|
|
279
|
-
}
|
|
434
|
+
};
|
|
435
|
+
if (this.blurContent) {
|
|
436
|
+
flipConfig.filter = 'blur(0px)';
|
|
437
|
+
flipConfig.clearProps = 'filter';
|
|
438
|
+
}
|
|
439
|
+
Flip.from(morphState, flipConfig);
|
|
280
440
|
}
|
|
281
|
-
const
|
|
282
|
-
const
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
gsap.
|
|
288
|
-
gsap.fromTo(fadeTargets, { opacity: 0, y: 8, filter: 'blur(8px)' }, {
|
|
441
|
+
const body = this.shadowRoot.querySelector('.body');
|
|
442
|
+
const footer = this.shadowRoot.querySelector('footer');
|
|
443
|
+
const closeBtn = this.shadowRoot.querySelector('.close-btn');
|
|
444
|
+
const fadeTargets = [body, footer, closeBtn].filter(Boolean);
|
|
445
|
+
const initialBlur = this.blurContent ? 'blur(16px)' : 'blur(0px)';
|
|
446
|
+
gsap.set(fadeTargets, { opacity: 0, y: 8, filter: initialBlur });
|
|
447
|
+
gsap.fromTo(fadeTargets, { opacity: 0, y: 8, filter: initialBlur }, {
|
|
289
448
|
opacity: 1,
|
|
290
449
|
y: 0,
|
|
291
450
|
filter: 'blur(0px)',
|
|
@@ -295,10 +454,18 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
|
|
|
295
454
|
ease: 'power2.out',
|
|
296
455
|
onComplete: () => {
|
|
297
456
|
gsap.set(fadeTargets, { clearProps: 'opacity,transform,filter' });
|
|
457
|
+
this._panel.classList.remove('is-animating');
|
|
298
458
|
}
|
|
299
459
|
});
|
|
300
460
|
});
|
|
301
461
|
}
|
|
462
|
+
/**
|
|
463
|
+
* Solución a un caso borde de FLIP Animations:
|
|
464
|
+
* Si el `.panel` original carece de un color de fondo sólido, la interpolación
|
|
465
|
+
* de GSAP puede comportarse erráticamente. Este método "asciende" el árbol del DOM
|
|
466
|
+
* hasta encontrar un padre con un color de fondo sólido y lo aplica, garantizando
|
|
467
|
+
* que el modal no colapse de forma transparente de regreso hacia el gatillo.
|
|
468
|
+
*/
|
|
302
469
|
_ensureSolidPanelBackground() {
|
|
303
470
|
if (!this._panel)
|
|
304
471
|
return;
|
|
@@ -327,16 +494,15 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
|
|
|
327
494
|
this._ensureSolidPanelBackground();
|
|
328
495
|
this.style.setProperty('--_backdrop-duration', '0.3s');
|
|
329
496
|
this.style.setProperty('--_backdrop-ease', 'cubic-bezier(0.4, 0, 0.2, 1)');
|
|
330
|
-
const
|
|
331
|
-
const
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
this.shadowRoot.querySelector('.close-btn')
|
|
335
|
-
].filter(Boolean);
|
|
497
|
+
const body = this.shadowRoot.querySelector('.body');
|
|
498
|
+
const footer = this.shadowRoot.querySelector('footer');
|
|
499
|
+
const closeBtn = this.shadowRoot.querySelector('.close-btn');
|
|
500
|
+
const fadeTargets = [body, footer, closeBtn].filter(Boolean);
|
|
336
501
|
const headerWrapper = this.shadowRoot.querySelector('.header-morph-wrapper');
|
|
502
|
+
const targetBlur = this.blurContent ? 'blur(12px)' : 'blur(0px)';
|
|
337
503
|
gsap.fromTo(fadeTargets, { opacity: 1, filter: 'blur(0px)' }, {
|
|
338
504
|
opacity: 0,
|
|
339
|
-
filter:
|
|
505
|
+
filter: targetBlur,
|
|
340
506
|
duration: 0.12,
|
|
341
507
|
ease: 'power2.in',
|
|
342
508
|
onComplete: () => {
|
|
@@ -380,7 +546,29 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
|
|
|
380
546
|
props: 'color,fontSize,fontWeight,lineHeight'
|
|
381
547
|
});
|
|
382
548
|
const targetState = this._getTargetState(this._targetEl);
|
|
383
|
-
|
|
549
|
+
let naturalSize;
|
|
550
|
+
if (this.autoSize) {
|
|
551
|
+
const prevW = panel.style.getPropertyValue('--_panel-width');
|
|
552
|
+
const prevH = panel.style.getPropertyValue('--_panel-height');
|
|
553
|
+
const prevPanelW = panel.style.width;
|
|
554
|
+
const prevPanelH = panel.style.height;
|
|
555
|
+
panel.style.width = 'auto';
|
|
556
|
+
panel.style.height = 'auto';
|
|
557
|
+
panel.style.setProperty('--_panel-width', 'max-content');
|
|
558
|
+
panel.style.setProperty('--_panel-height', 'max-content');
|
|
559
|
+
const bodyEl = this.shadowRoot.querySelector('.body');
|
|
560
|
+
const prevOverflow = bodyEl ? bodyEl.style.overflow : '';
|
|
561
|
+
if (bodyEl)
|
|
562
|
+
bodyEl.style.overflow = 'visible';
|
|
563
|
+
naturalSize = { width: this._inner.scrollWidth, height: this._inner.scrollHeight };
|
|
564
|
+
panel.style.setProperty('--_panel-width', prevW);
|
|
565
|
+
panel.style.setProperty('--_panel-height', prevH);
|
|
566
|
+
panel.style.width = prevPanelW;
|
|
567
|
+
panel.style.height = prevPanelH;
|
|
568
|
+
if (bodyEl)
|
|
569
|
+
bodyEl.style.overflow = prevOverflow;
|
|
570
|
+
}
|
|
571
|
+
const finalRect = this._computeFinalRect(targetState.rect, naturalSize);
|
|
384
572
|
panel.style.setProperty('--_panel-width', `${finalRect.width}px`);
|
|
385
573
|
panel.style.setProperty('--_panel-height', `${finalRect.height}px`);
|
|
386
574
|
this._applyRect(panel, targetState.rect);
|
|
@@ -438,12 +626,19 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
|
|
|
438
626
|
}
|
|
439
627
|
});
|
|
440
628
|
if (morphTargets.length > 0) {
|
|
441
|
-
|
|
629
|
+
if (this.blurContent) {
|
|
630
|
+
gsap.set(morphTargets, { filter: 'blur(0px)' });
|
|
631
|
+
}
|
|
632
|
+
const flipConfig = {
|
|
442
633
|
targets: morphTargets,
|
|
443
634
|
duration: 0.3,
|
|
444
635
|
ease: 'morph-close',
|
|
445
636
|
zIndex: this._zIndex + 10
|
|
446
|
-
}
|
|
637
|
+
};
|
|
638
|
+
if (this.blurContent) {
|
|
639
|
+
flipConfig.filter = 'blur(12px)';
|
|
640
|
+
}
|
|
641
|
+
Flip.from(morphState, flipConfig);
|
|
447
642
|
}
|
|
448
643
|
}
|
|
449
644
|
});
|
|
@@ -463,6 +658,12 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
|
|
|
463
658
|
e.stopPropagation();
|
|
464
659
|
this.hide();
|
|
465
660
|
}
|
|
661
|
+
/**
|
|
662
|
+
* Fase "First" de la animación (Cierre del Trigger):
|
|
663
|
+
* Determina cómo desaparecer u ocultar el botón original mientras el modal ocupa su lugar.
|
|
664
|
+
* Mantiene el cache de opacidades y colores originales para poder restaurarlos
|
|
665
|
+
* idénticamente al cerrar el modal (evitando saltos visuales).
|
|
666
|
+
*/
|
|
466
667
|
_hideTargetContent() {
|
|
467
668
|
if (!this._targetEl)
|
|
468
669
|
return;
|
|
@@ -495,6 +696,10 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
|
|
|
495
696
|
saveAndHide(icon, 'opacity');
|
|
496
697
|
}
|
|
497
698
|
}
|
|
699
|
+
/**
|
|
700
|
+
* Restaura puramente los estilos originales del botón Trigger tras terminar
|
|
701
|
+
* la animación de cierre, leyendo las opacidades/colores almacenados en caché.
|
|
702
|
+
*/
|
|
498
703
|
_restoreTargetContent() {
|
|
499
704
|
if (!this._targetEl)
|
|
500
705
|
return;
|
|
@@ -559,10 +764,10 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
|
|
|
559
764
|
}
|
|
560
765
|
}
|
|
561
766
|
_animateLabelOpen() {
|
|
562
|
-
// No-op:
|
|
767
|
+
// No-op: el morphing de la etiqueta es manejado por el timeline unificado FLIP en show()
|
|
563
768
|
}
|
|
564
769
|
_animateLabelClose() {
|
|
565
|
-
// No-op:
|
|
770
|
+
// No-op: el morphing de la etiqueta es manejado por el timeline unificado FLIP en hide()
|
|
566
771
|
}
|
|
567
772
|
_createMorphText(sourceText, sourceEl) {
|
|
568
773
|
const el = document.createElement('div');
|
|
@@ -866,12 +1071,12 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
|
|
|
866
1071
|
el.style.width = `${rect.width}px`;
|
|
867
1072
|
el.style.height = `${rect.height}px`;
|
|
868
1073
|
}
|
|
869
|
-
_computeFinalRect(targetRect) {
|
|
1074
|
+
_computeFinalRect(targetRect, naturalSize) {
|
|
870
1075
|
const vw = window.innerWidth;
|
|
871
1076
|
const vh = window.innerHeight;
|
|
872
1077
|
const padding = 16;
|
|
873
|
-
let width = this._parseSize(this.expandedWidth, vw);
|
|
874
|
-
let height = this._parseSize(this.expandedHeight, vh);
|
|
1078
|
+
let width = this.autoSize && naturalSize ? naturalSize.width : this._parseSize(this.expandedWidth, vw);
|
|
1079
|
+
let height = this.autoSize && naturalSize ? naturalSize.height : this._parseSize(this.expandedHeight, vh);
|
|
875
1080
|
width = Math.min(width, vw - padding * 2);
|
|
876
1081
|
height = Math.min(height, vh - padding * 2);
|
|
877
1082
|
let top = targetRect.top;
|
|
@@ -1046,7 +1251,7 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
|
|
|
1046
1251
|
overflow: hidden;
|
|
1047
1252
|
background-color: var(--surface-container-high);
|
|
1048
1253
|
color: var(--on-surface);
|
|
1049
|
-
border-radius: 1.75rem;
|
|
1254
|
+
border-radius: var(--moni-morph-panel-radius, 1.75rem);
|
|
1050
1255
|
box-shadow: var(--elevate2);
|
|
1051
1256
|
z-index: var(--_z-index, 100);
|
|
1052
1257
|
}
|
|
@@ -1075,13 +1280,18 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
|
|
|
1075
1280
|
|
|
1076
1281
|
.body {
|
|
1077
1282
|
flex: 1;
|
|
1078
|
-
overflow-y: auto;
|
|
1079
|
-
|
|
1080
|
-
|
|
1283
|
+
overflow-y: var(--moni-morph-body-overflow-y, auto);
|
|
1284
|
+
overflow-x: var(--moni-morph-body-overflow-x, hidden);
|
|
1285
|
+
padding: var(--moni-morph-body-padding, 0 1.5rem);
|
|
1286
|
+
scrollbar-gutter: var(--moni-morph-body-scrollbar-gutter, stable);
|
|
1081
1287
|
}
|
|
1082
1288
|
|
|
1083
1289
|
.panel.is-animating .body {
|
|
1084
|
-
overflow: hidden;
|
|
1290
|
+
overflow: hidden !important;
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
.panel.is-animating .body::-webkit-scrollbar {
|
|
1294
|
+
display: none;
|
|
1085
1295
|
}
|
|
1086
1296
|
|
|
1087
1297
|
footer {
|
|
@@ -1130,6 +1340,27 @@ let MoniMorphModal = class MoniMorphModal extends MoniElement {
|
|
|
1130
1340
|
}
|
|
1131
1341
|
`
|
|
1132
1342
|
]; }
|
|
1343
|
+
/**
|
|
1344
|
+
* Renderiza el caparazón del modal morph: fondo opcional + contenedor de panel.
|
|
1345
|
+
*
|
|
1346
|
+
* **Bandera `_visible`:**
|
|
1347
|
+
* `visible = this._visible || this.open` mantiene vivo el DOM mientras se reproduce
|
|
1348
|
+
* la animación de cierre de GSAP. `_visible` se establece en `true` al inicio de la apertura y
|
|
1349
|
+
* en `false` solo después de que se dispara el `onComplete` de la animación de cierre. Sin esto,
|
|
1350
|
+
* Lit eliminaría el panel del DOM antes de que la animación termine.
|
|
1351
|
+
*
|
|
1352
|
+
* **Condicional del fondo (backdrop):**
|
|
1353
|
+
* El div `.backdrop` solo se renderiza cuando `hasBackdrop=true`. Cuando `modal=false`,
|
|
1354
|
+
* el `background-color` del fondo se establece en `transparent` para que el fondo superpuesto
|
|
1355
|
+
* (scrim) sea invisible, pero los eventos del puntero aún se consumen (clic para cerrar).
|
|
1356
|
+
*
|
|
1357
|
+
* **Objetivo de morphing de GSAP:**
|
|
1358
|
+
* `.panel` es el objetivo de la animación GSAP. Al abrir: se anima desde el
|
|
1359
|
+
* `getBoundingClientRect()` del elemento anclaje (posición + tamaño) a su tamaño CSS natural
|
|
1360
|
+
* mediante `gsap.fromTo()`. Al cerrar: a la inversa. `.panel-inner` recibe una
|
|
1361
|
+
* contra-escala para evitar que el contenido interno se escale junto con el panel,
|
|
1362
|
+
* creando una ilusión física de "expandirse desde el origen".
|
|
1363
|
+
*/
|
|
1133
1364
|
render() {
|
|
1134
1365
|
const visible = this._visible || this.open;
|
|
1135
1366
|
const headerEmpty = !this._hasHeader && !this.showCloseButton;
|
|
@@ -1217,6 +1448,12 @@ __decorate([
|
|
|
1217
1448
|
__decorate([
|
|
1218
1449
|
property({ type: Boolean, reflect: true, attribute: 'cover-target', converter: litBool })
|
|
1219
1450
|
], MoniMorphModal.prototype, "coverTarget", void 0);
|
|
1451
|
+
__decorate([
|
|
1452
|
+
property({ type: Boolean, reflect: true, attribute: 'auto-size', converter: litBool })
|
|
1453
|
+
], MoniMorphModal.prototype, "autoSize", void 0);
|
|
1454
|
+
__decorate([
|
|
1455
|
+
property({ type: Boolean, reflect: true, attribute: 'blur-content', converter: litBool })
|
|
1456
|
+
], MoniMorphModal.prototype, "blurContent", void 0);
|
|
1220
1457
|
__decorate([
|
|
1221
1458
|
query('.panel')
|
|
1222
1459
|
], MoniMorphModal.prototype, "_panel", void 0);
|