@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
|
@@ -10,44 +10,44 @@ import { customElement, property, query, state } from 'lit/decorators.js';
|
|
|
10
10
|
import { MoniElement, sharedStyles } from './_base/index.js';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
* Material Design 3 Menu
|
|
13
|
+
* Componente Material Design 3 Menu (Menú).
|
|
14
14
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
15
|
+
* Los menús muestran una lista de opciones en una superficie temporal. Aparecen cuando
|
|
16
|
+
* los usuarios interactúan con un botón, acción u otro control.
|
|
17
17
|
*
|
|
18
|
-
* **
|
|
18
|
+
* **Referencia de la especificación M3:** `m3-docs/components/menus/guidelines.md`
|
|
19
19
|
*
|
|
20
|
-
* **
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* **Crucial:**
|
|
25
|
-
*
|
|
20
|
+
* **Arquitectura de posicionamiento:**
|
|
21
|
+
* El menú usa `position: absolute` relativo a su ancestro posicionado más cercano.
|
|
22
|
+
* El `:host` del componente usa `display: contents`, lo que significa que el
|
|
23
|
+
* elemento interior `<menu>` participa directamente en el contexto de diseño del consumidor.
|
|
24
|
+
* **Crucial:** El consumidor debe aplicar `position: relative` al elemento contenedor
|
|
25
|
+
* que contiene tanto el activador (trigger) como el `<moni-menu>`.
|
|
26
26
|
*
|
|
27
|
-
* **
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* - **
|
|
31
|
-
*
|
|
32
|
-
* - **Fallback:**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
27
|
+
* **Posicionamiento de auto-volteo (auto-flip):**
|
|
28
|
+
* Según las pautas de M3, los menús deben voltearse hacia el lado opuesto del anclaje
|
|
29
|
+
* si se desbordan de la ventana gráfica (viewport).
|
|
30
|
+
* - **Navegadores modernos (Chrome/Edge 125+, Safari 18+):** Utiliza el posicionamiento
|
|
31
|
+
* de anclaje de CSS y `@position-try-fallback` nativamente cuando `flip=true`.
|
|
32
|
+
* - **Alternativa (Fallback):** Un polyfill de JavaScript mide el menú después de que se abre. Si
|
|
33
|
+
* se desborda de la posición `placement` solicitada, establece un estado interno para voltear
|
|
34
|
+
* las clases de posicionamiento.
|
|
35
35
|
*
|
|
36
|
-
* **
|
|
37
|
-
*
|
|
38
|
-
*
|
|
36
|
+
* **Gestión del estado:**
|
|
37
|
+
* El atributo `active` controla la visibilidad. Los consumidores deben escuchar los eventos
|
|
38
|
+
* del activador (como `click`) y alternar la propiedad `active`.
|
|
39
39
|
*
|
|
40
40
|
* @example
|
|
41
41
|
* ```html
|
|
42
|
-
* <!--
|
|
42
|
+
* <!-- El contenedor debe tener position: relative -->
|
|
43
43
|
* <div style="position: relative; display: inline-block;">
|
|
44
|
-
* <moni-button id="menu-trigger">
|
|
44
|
+
* <moni-button id="menu-trigger">Abrir Menú</moni-button>
|
|
45
45
|
*
|
|
46
46
|
* <moni-menu placement="bottom" flip id="my-menu">
|
|
47
|
-
* <moni-menu-item icon="edit">
|
|
48
|
-
* <moni-menu-item icon="content_copy">
|
|
47
|
+
* <moni-menu-item icon="edit">Editar</moni-menu-item>
|
|
48
|
+
* <moni-menu-item icon="content_copy">Copiar</moni-menu-item>
|
|
49
49
|
* <moni-divider></moni-divider>
|
|
50
|
-
* <moni-menu-item icon="delete">
|
|
50
|
+
* <moni-menu-item icon="delete">Eliminar</moni-menu-item>
|
|
51
51
|
* </moni-menu>
|
|
52
52
|
* </div>
|
|
53
53
|
*
|
|
@@ -58,16 +58,37 @@ import { MoniElement, sharedStyles } from './_base/index.js';
|
|
|
58
58
|
* </script>
|
|
59
59
|
* ```
|
|
60
60
|
*
|
|
61
|
-
* @slot default - `<moni-menu-item>`, `<moni-divider>`,
|
|
61
|
+
* @slot default - Elementos `<moni-menu-item>`, `<moni-divider>`, o elementos `<li>` en bruto.
|
|
62
62
|
*
|
|
63
|
-
* @csspart menu -
|
|
63
|
+
* @csspart menu - El contenedor interior `<menu>`.
|
|
64
64
|
*/
|
|
65
65
|
@customElement('moni-menu')
|
|
66
66
|
export class MoniMenu extends MoniElement {
|
|
67
|
+
/**
|
|
68
|
+
* Posición preferida en relación con el anclaje padre.
|
|
69
|
+
* @type {'bottom' | 'top' | 'left' | 'right' | 'min' | 'max'}
|
|
70
|
+
* @default 'bottom'
|
|
71
|
+
*/
|
|
67
72
|
@property({ reflect: true })
|
|
68
73
|
placement: 'bottom' | 'top' | 'left' | 'right' | 'min' | 'max' = 'bottom';
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Deshabilita el ajuste de texto dentro del menú.
|
|
77
|
+
* @type {boolean}
|
|
78
|
+
*/
|
|
69
79
|
@property({ type: Boolean, reflect: true, attribute: 'no-wrap' }) noWrap = false;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Controla si el menú está visible.
|
|
83
|
+
* @type {boolean}
|
|
84
|
+
*/
|
|
70
85
|
@property({ type: Boolean, reflect: true }) active = false;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Lógica de espaciado entre el anclaje y el menú.
|
|
89
|
+
* @type {'no-space' | 'space' | 'small-space' | 'medium-space' | 'large-space' | 'extra-space'}
|
|
90
|
+
* @default 'no-space'
|
|
91
|
+
*/
|
|
71
92
|
@property({ reflect: true })
|
|
72
93
|
space:
|
|
73
94
|
| 'no-space'
|
|
@@ -76,6 +97,12 @@ export class MoniMenu extends MoniElement {
|
|
|
76
97
|
| 'medium-space'
|
|
77
98
|
| 'large-space'
|
|
78
99
|
| 'extra-space' = 'no-space';
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Habilita la evitación de colisiones basada en JS (volteando la posición si está fuera de los límites).
|
|
103
|
+
* Útil para navegadores que carecen de soporte para anclaje CSS.
|
|
104
|
+
* @type {boolean}
|
|
105
|
+
*/
|
|
79
106
|
@property({ type: Boolean, reflect: true }) flip = false;
|
|
80
107
|
|
|
81
108
|
@state() private _resolvedPlacement:
|
|
@@ -88,25 +115,36 @@ export class MoniMenu extends MoniElement {
|
|
|
88
115
|
|
|
89
116
|
@query('menu') private _menuEl?: HTMLElement;
|
|
90
117
|
|
|
118
|
+
/**
|
|
119
|
+
* Hook de ciclo de vida de Lit.
|
|
120
|
+
* Detecta si el menú se acaba de abrir (active = true) con la propiedad de 'flip' habilitada.
|
|
121
|
+
* Usa una Promesa (`updateComplete`) para esperar a que Lit termine de renderizar el DOM y
|
|
122
|
+
* el navegador haga el reflow antes de medir sus dimensiones.
|
|
123
|
+
*/
|
|
91
124
|
override updated(changed: Map<string, unknown>) {
|
|
92
125
|
super.updated(changed);
|
|
93
126
|
if (changed.has('active') && this.active && this.flip) {
|
|
94
|
-
// JS polyfill for browsers without @position-try-fallback.
|
|
95
|
-
// Wait one frame so the menu is laid out, then measure.
|
|
96
127
|
this.updateComplete.then(() => this._maybeFlip());
|
|
97
128
|
}
|
|
98
129
|
}
|
|
99
130
|
|
|
131
|
+
/**
|
|
132
|
+
* Polyfill manual en JS para "position-try-fallbacks" (CSS Anchoring API).
|
|
133
|
+
* Si el menú desborda el viewport en su posición actual, invierte lógicamente
|
|
134
|
+
* su colocación (ej. de 'bottom' a 'top') calculando los BoundingClientRect.
|
|
135
|
+
*/
|
|
100
136
|
private _maybeFlip() {
|
|
101
137
|
const menu = this._menuEl;
|
|
102
138
|
if (!menu || !this.flip) return;
|
|
103
139
|
const rect = menu.getBoundingClientRect();
|
|
104
140
|
const vw = window.innerWidth;
|
|
105
141
|
const vh = window.innerHeight;
|
|
142
|
+
|
|
106
143
|
const overflowsBottom = rect.bottom > vh;
|
|
107
144
|
const overflowsTop = rect.top < 0;
|
|
108
145
|
const overflowsRight = rect.right > vw;
|
|
109
146
|
const overflowsLeft = rect.left < 0;
|
|
147
|
+
|
|
110
148
|
if (this.placement === 'bottom' && overflowsBottom) {
|
|
111
149
|
this._resolvedPlacement = 'top';
|
|
112
150
|
} else if (this.placement === 'top' && overflowsTop) {
|
|
@@ -284,6 +322,25 @@ export class MoniMenu extends MoniElement {
|
|
|
284
322
|
`
|
|
285
323
|
];
|
|
286
324
|
|
|
325
|
+
/**
|
|
326
|
+
* Renderiza el menú como una superposición Popover API o un `<div>` posicionado.
|
|
327
|
+
*
|
|
328
|
+
* **Popover API (`popover="auto"`):**
|
|
329
|
+
* Cuando se establece `popover`, el menú usa la Popover API nativa del navegador.
|
|
330
|
+
* Esto proporciona descarte ligero (light-dismiss) automático (clic fuera para cerrar) y
|
|
331
|
+
* apilamiento en la capa superior sin gestión de `z-index`.
|
|
332
|
+
*
|
|
333
|
+
* **Patrón de menú ARIA:**
|
|
334
|
+
* El contenedor del menú lleva `role="menu"`. Cada hijo `<moni-menu-item>`
|
|
335
|
+
* debe llevar `role="menuitem"`. La navegación con las teclas de flecha se maneja a través de
|
|
336
|
+
* `@keydown` en el contenedor del menú, ciclando a través de los elementos usando
|
|
337
|
+
* `_focusedItemIndex` (incrementado/decrementado con ciclo continuo).
|
|
338
|
+
*
|
|
339
|
+
* **Posicionamiento:**
|
|
340
|
+
* Cuando se establece `anchor`, `_computeStyle()` calcula `top`/`left` desde
|
|
341
|
+
* `getBoundingClientRect()` del elemento anclaje y los inyecta como
|
|
342
|
+
* estilos en línea en el `<div>` del menú.
|
|
343
|
+
*/
|
|
287
344
|
override render() {
|
|
288
345
|
const effectivePlacement = this.active && this.flip
|
|
289
346
|
? this._resolvedPlacement
|
|
@@ -74,11 +74,11 @@ describe('moni-morph-modal', () => {
|
|
|
74
74
|
target.remove();
|
|
75
75
|
});
|
|
76
76
|
|
|
77
|
-
it('
|
|
77
|
+
it('registra el elemento personalizado', () => {
|
|
78
78
|
expect(customElements.get('moni-morph-modal')).toBeTruthy();
|
|
79
79
|
});
|
|
80
80
|
|
|
81
|
-
it('
|
|
81
|
+
it('renderiza un panel y un backdrop en el shadow root', async () => {
|
|
82
82
|
await el.updateComplete;
|
|
83
83
|
const panel = el.shadowRoot?.querySelector('.panel');
|
|
84
84
|
const backdrop = el.shadowRoot?.querySelector('.backdrop');
|
|
@@ -86,18 +86,18 @@ describe('moni-morph-modal', () => {
|
|
|
86
86
|
expect(backdrop).toBeTruthy();
|
|
87
87
|
});
|
|
88
88
|
|
|
89
|
-
it('
|
|
89
|
+
it('refleja el atributo target', async () => {
|
|
90
90
|
await el.updateComplete;
|
|
91
91
|
expect(el.getAttribute('target')).toBe('#test-target');
|
|
92
92
|
});
|
|
93
93
|
|
|
94
|
-
it('
|
|
94
|
+
it('refleja el atributo open', async () => {
|
|
95
95
|
el.open = true;
|
|
96
96
|
await el.updateComplete;
|
|
97
97
|
expect(el.hasAttribute('open')).toBe(true);
|
|
98
98
|
});
|
|
99
99
|
|
|
100
|
-
it('
|
|
100
|
+
it('proyecta el contenido del slot por defecto', async () => {
|
|
101
101
|
const content = document.createElement('p');
|
|
102
102
|
content.textContent = 'Hello';
|
|
103
103
|
el.appendChild(content);
|
|
@@ -108,7 +108,7 @@ describe('moni-morph-modal', () => {
|
|
|
108
108
|
expect(slot).toBeTruthy();
|
|
109
109
|
});
|
|
110
110
|
|
|
111
|
-
it('
|
|
111
|
+
it('proyecta el contenido del slot header', async () => {
|
|
112
112
|
const header = document.createElement('div');
|
|
113
113
|
header.setAttribute('slot', 'header');
|
|
114
114
|
header.textContent = 'Title';
|
|
@@ -118,7 +118,7 @@ describe('moni-morph-modal', () => {
|
|
|
118
118
|
expect(headerSlot).toBeTruthy();
|
|
119
119
|
});
|
|
120
120
|
|
|
121
|
-
it('
|
|
121
|
+
it('proyecta el contenido del slot footer', async () => {
|
|
122
122
|
const footer = document.createElement('div');
|
|
123
123
|
footer.setAttribute('slot', 'footer');
|
|
124
124
|
footer.textContent = 'Actions';
|
|
@@ -128,14 +128,14 @@ describe('moni-morph-modal', () => {
|
|
|
128
128
|
expect(footerSlot).toBeTruthy();
|
|
129
129
|
});
|
|
130
130
|
|
|
131
|
-
it('
|
|
131
|
+
it('muestra el botón de cerrar cuando show-close-button es true', async () => {
|
|
132
132
|
el.showCloseButton = true;
|
|
133
133
|
await el.updateComplete;
|
|
134
134
|
const closeBtn = el.shadowRoot?.querySelector('.close-btn');
|
|
135
135
|
expect(closeBtn).toBeTruthy();
|
|
136
136
|
});
|
|
137
137
|
|
|
138
|
-
it('
|
|
138
|
+
it('alterna el estado open cuando se llaman a show() y hide()', async () => {
|
|
139
139
|
expect(el.open).toBe(false);
|
|
140
140
|
el.show();
|
|
141
141
|
await waitForRaf();
|
|
@@ -145,7 +145,7 @@ describe('moni-morph-modal', () => {
|
|
|
145
145
|
expect(el.open).toBe(false);
|
|
146
146
|
});
|
|
147
147
|
|
|
148
|
-
it('
|
|
148
|
+
it('alterna el estado open cuando se llama a toggle()', async () => {
|
|
149
149
|
el.toggle();
|
|
150
150
|
await waitForRaf();
|
|
151
151
|
expect(el.open).toBe(true);
|
|
@@ -154,11 +154,12 @@ describe('moni-morph-modal', () => {
|
|
|
154
154
|
expect(el.open).toBe(false);
|
|
155
155
|
});
|
|
156
156
|
|
|
157
|
-
it('
|
|
157
|
+
it('advierte cuando no se encuentra el objetivo (target)', () => {
|
|
158
158
|
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
159
159
|
const modal = document.createElement('moni-morph-modal') as MoniMorphModal;
|
|
160
160
|
modal.target = '#missing-target';
|
|
161
161
|
document.body.appendChild(modal);
|
|
162
|
+
modal.show();
|
|
162
163
|
const call = warnSpy.mock.calls.find((c) =>
|
|
163
164
|
String(c[0]).includes('[moni-morph-modal]')
|
|
164
165
|
);
|
|
@@ -167,7 +168,7 @@ describe('moni-morph-modal', () => {
|
|
|
167
168
|
warnSpy.mockRestore();
|
|
168
169
|
});
|
|
169
170
|
|
|
170
|
-
it('
|
|
171
|
+
it('soporta la declaración recursiva de modales morph anidados', async () => {
|
|
171
172
|
const innerTarget = document.createElement('button');
|
|
172
173
|
innerTarget.id = 'inner-target';
|
|
173
174
|
el.appendChild(innerTarget);
|
|
@@ -188,14 +189,14 @@ describe('moni-morph-modal', () => {
|
|
|
188
189
|
innerTarget.remove();
|
|
189
190
|
});
|
|
190
191
|
|
|
191
|
-
it('
|
|
192
|
+
it('no crea elementos morph por defecto', async () => {
|
|
192
193
|
el.show();
|
|
193
194
|
await waitForRaf();
|
|
194
195
|
expect(el.shadowRoot?.querySelector('.morph-text')).toBeFalsy();
|
|
195
196
|
expect(el.shadowRoot?.querySelector('.morph-icon')).toBeFalsy();
|
|
196
197
|
});
|
|
197
198
|
|
|
198
|
-
it('
|
|
199
|
+
it('crea y limpia morph-text cuando morph-label es true', async () => {
|
|
199
200
|
(el as unknown as { _hasHeader: boolean })._hasHeader = true;
|
|
200
201
|
el.morphLabel = true;
|
|
201
202
|
await el.updateComplete;
|
|
@@ -212,7 +213,7 @@ describe('moni-morph-modal', () => {
|
|
|
212
213
|
createSpy.mockRestore();
|
|
213
214
|
});
|
|
214
215
|
|
|
215
|
-
it('
|
|
216
|
+
it('usa el contenido del slot trigger-label cuando se proporciona', async () => {
|
|
216
217
|
const triggerLabel = document.createElement('span');
|
|
217
218
|
triggerLabel.setAttribute('slot', 'trigger-label');
|
|
218
219
|
triggerLabel.textContent = 'Custom label';
|
|
@@ -237,7 +238,7 @@ describe('moni-morph-modal', () => {
|
|
|
237
238
|
getNodes.mockRestore();
|
|
238
239
|
});
|
|
239
240
|
|
|
240
|
-
it('
|
|
241
|
+
it('ejecuta la animación FLIP de label al cerrar cuando morph-label es true', async () => {
|
|
241
242
|
(el as unknown as { _hasHeader: boolean })._hasHeader = true;
|
|
242
243
|
el.morphLabel = true;
|
|
243
244
|
await el.updateComplete;
|
|
@@ -257,7 +258,7 @@ describe('moni-morph-modal', () => {
|
|
|
257
258
|
closeSpy.mockRestore();
|
|
258
259
|
});
|
|
259
260
|
|
|
260
|
-
it('
|
|
261
|
+
it('no crea elementos morph cuando se prefiere movimiento reducido (reduced motion)', async () => {
|
|
261
262
|
(el as unknown as { _hasHeader: boolean })._hasHeader = true;
|
|
262
263
|
el.morphLabel = true;
|
|
263
264
|
await el.updateComplete;
|