@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.
Files changed (251) hide show
  1. package/custom-elements.json +5230 -1007
  2. package/dist/components/_base/moni-element.d.ts +16 -9
  3. package/dist/components/_base/moni-element.d.ts.map +1 -1
  4. package/dist/components/_base/moni-element.js +63 -9
  5. package/dist/components/index.js +2 -2
  6. package/dist/components/loading-shapes.d.ts +19 -0
  7. package/dist/components/loading-shapes.d.ts.map +1 -1
  8. package/dist/components/loading-shapes.js +19 -0
  9. package/dist/components/moni-app-bar.d.ts +72 -62
  10. package/dist/components/moni-app-bar.d.ts.map +1 -1
  11. package/dist/components/moni-app-bar.js +72 -62
  12. package/dist/components/moni-badge.d.ts +64 -65
  13. package/dist/components/moni-badge.d.ts.map +1 -1
  14. package/dist/components/moni-badge.js +64 -66
  15. package/dist/components/moni-bottom-sheet.d.ts +129 -61
  16. package/dist/components/moni-bottom-sheet.d.ts.map +1 -1
  17. package/dist/components/moni-bottom-sheet.js +217 -131
  18. package/dist/components/moni-button-group.d.ts +107 -29
  19. package/dist/components/moni-button-group.d.ts.map +1 -1
  20. package/dist/components/moni-button-group.js +107 -29
  21. package/dist/components/moni-button-segment.d.ts +53 -12
  22. package/dist/components/moni-button-segment.d.ts.map +1 -1
  23. package/dist/components/moni-button-segment.js +53 -12
  24. package/dist/components/moni-button.d.ts +116 -38
  25. package/dist/components/moni-button.d.ts.map +1 -1
  26. package/dist/components/moni-button.js +128 -38
  27. package/dist/components/moni-card.d.ts +68 -50
  28. package/dist/components/moni-card.d.ts.map +1 -1
  29. package/dist/components/moni-card.js +68 -50
  30. package/dist/components/moni-carousel.d.ts +484 -53
  31. package/dist/components/moni-carousel.d.ts.map +1 -1
  32. package/dist/components/moni-carousel.js +1024 -245
  33. package/dist/components/moni-checkbox.d.ts +49 -46
  34. package/dist/components/moni-checkbox.d.ts.map +1 -1
  35. package/dist/components/moni-checkbox.js +55 -48
  36. package/dist/components/moni-chip.d.ts +100 -33
  37. package/dist/components/moni-chip.d.ts.map +1 -1
  38. package/dist/components/moni-chip.js +104 -34
  39. package/dist/components/moni-color-field.d.ts +99 -24
  40. package/dist/components/moni-color-field.d.ts.map +1 -1
  41. package/dist/components/moni-color-field.js +99 -24
  42. package/dist/components/moni-context-menu.d.ts +72 -26
  43. package/dist/components/moni-context-menu.d.ts.map +1 -1
  44. package/dist/components/moni-context-menu.js +76 -30
  45. package/dist/components/moni-dialog.d.ts +84 -59
  46. package/dist/components/moni-dialog.d.ts.map +1 -1
  47. package/dist/components/moni-dialog.js +105 -58
  48. package/dist/components/moni-divider.d.ts +39 -27
  49. package/dist/components/moni-divider.d.ts.map +1 -1
  50. package/dist/components/moni-divider.js +42 -30
  51. package/dist/components/moni-expansion.d.ts +32 -22
  52. package/dist/components/moni-expansion.d.ts.map +1 -1
  53. package/dist/components/moni-expansion.js +32 -22
  54. package/dist/components/moni-fab-menu.d.ts +61 -23
  55. package/dist/components/moni-fab-menu.d.ts.map +1 -1
  56. package/dist/components/moni-fab-menu.js +69 -31
  57. package/dist/components/moni-fab.d.ts +86 -28
  58. package/dist/components/moni-fab.d.ts.map +1 -1
  59. package/dist/components/moni-fab.js +92 -34
  60. package/dist/components/moni-file-field.d.ts +118 -30
  61. package/dist/components/moni-file-field.d.ts.map +1 -1
  62. package/dist/components/moni-file-field.js +118 -30
  63. package/dist/components/moni-icon.d.ts +40 -35
  64. package/dist/components/moni-icon.d.ts.map +1 -1
  65. package/dist/components/moni-icon.js +43 -38
  66. package/dist/components/moni-list-item.d.ts +46 -33
  67. package/dist/components/moni-list-item.d.ts.map +1 -1
  68. package/dist/components/moni-list-item.js +61 -41
  69. package/dist/components/moni-list.d.ts +30 -20
  70. package/dist/components/moni-list.d.ts.map +1 -1
  71. package/dist/components/moni-list.js +36 -21
  72. package/dist/components/moni-loading-indicator.d.ts +54 -22
  73. package/dist/components/moni-loading-indicator.d.ts.map +1 -1
  74. package/dist/components/moni-loading-indicator.js +54 -22
  75. package/dist/components/moni-menu-item.d.ts +23 -16
  76. package/dist/components/moni-menu-item.d.ts.map +1 -1
  77. package/dist/components/moni-menu-item.js +23 -16
  78. package/dist/components/moni-menu.d.ts +81 -28
  79. package/dist/components/moni-menu.d.ts.map +1 -1
  80. package/dist/components/moni-menu.js +81 -30
  81. package/dist/components/moni-morph-modal.d.ts +141 -0
  82. package/dist/components/moni-morph-modal.d.ts.map +1 -1
  83. package/dist/components/moni-morph-modal.js +295 -58
  84. package/dist/components/moni-nav-item.d.ts +59 -29
  85. package/dist/components/moni-nav-item.d.ts.map +1 -1
  86. package/dist/components/moni-nav-item.js +59 -29
  87. package/dist/components/moni-nav.d.ts +94 -35
  88. package/dist/components/moni-nav.d.ts.map +1 -1
  89. package/dist/components/moni-nav.js +94 -35
  90. package/dist/components/moni-progress.d.ts +99 -55
  91. package/dist/components/moni-progress.d.ts.map +1 -1
  92. package/dist/components/moni-progress.js +99 -55
  93. package/dist/components/moni-radio.d.ts +62 -50
  94. package/dist/components/moni-radio.d.ts.map +1 -1
  95. package/dist/components/moni-radio.js +65 -52
  96. package/dist/components/moni-ripple.d.ts +74 -59
  97. package/dist/components/moni-ripple.d.ts.map +1 -1
  98. package/dist/components/moni-ripple.js +74 -59
  99. package/dist/components/moni-segmented-button.d.ts +91 -16
  100. package/dist/components/moni-segmented-button.d.ts.map +1 -1
  101. package/dist/components/moni-segmented-button.js +94 -17
  102. package/dist/components/moni-select-option.d.ts +30 -23
  103. package/dist/components/moni-select-option.d.ts.map +1 -1
  104. package/dist/components/moni-select-option.js +30 -23
  105. package/dist/components/moni-select.d.ts +300 -35
  106. package/dist/components/moni-select.d.ts.map +1 -1
  107. package/dist/components/moni-select.js +323 -39
  108. package/dist/components/moni-side-sheet.d.ts +94 -32
  109. package/dist/components/moni-side-sheet.d.ts.map +1 -1
  110. package/dist/components/moni-side-sheet.js +94 -32
  111. package/dist/components/moni-slider.d.ts +152 -41
  112. package/dist/components/moni-slider.d.ts.map +1 -1
  113. package/dist/components/moni-slider.js +154 -42
  114. package/dist/components/moni-snackbar.d.ts +53 -43
  115. package/dist/components/moni-snackbar.d.ts.map +1 -1
  116. package/dist/components/moni-snackbar.js +53 -43
  117. package/dist/components/moni-split-button.d.ts +63 -18
  118. package/dist/components/moni-split-button.d.ts.map +1 -1
  119. package/dist/components/moni-split-button.js +63 -18
  120. package/dist/components/moni-step.d.ts +36 -24
  121. package/dist/components/moni-step.d.ts.map +1 -1
  122. package/dist/components/moni-step.js +41 -29
  123. package/dist/components/moni-stepper.d.ts +64 -27
  124. package/dist/components/moni-stepper.d.ts.map +1 -1
  125. package/dist/components/moni-stepper.js +72 -34
  126. package/dist/components/moni-switch.d.ts +57 -46
  127. package/dist/components/moni-switch.d.ts.map +1 -1
  128. package/dist/components/moni-switch.js +59 -47
  129. package/dist/components/moni-tab.d.ts +26 -18
  130. package/dist/components/moni-tab.d.ts.map +1 -1
  131. package/dist/components/moni-tab.js +29 -21
  132. package/dist/components/moni-tabs.d.ts +34 -28
  133. package/dist/components/moni-tabs.d.ts.map +1 -1
  134. package/dist/components/moni-tabs.js +34 -28
  135. package/dist/components/moni-text-field.d.ts +139 -29
  136. package/dist/components/moni-text-field.d.ts.map +1 -1
  137. package/dist/components/moni-text-field.js +157 -31
  138. package/dist/components/moni-textarea.d.ts +127 -29
  139. package/dist/components/moni-textarea.d.ts.map +1 -1
  140. package/dist/components/moni-textarea.js +131 -32
  141. package/dist/components/moni-time-picker.d.ts +114 -24
  142. package/dist/components/moni-time-picker.d.ts.map +1 -1
  143. package/dist/components/moni-time-picker.js +127 -33
  144. package/dist/components/moni-toolbar.d.ts +37 -23
  145. package/dist/components/moni-toolbar.d.ts.map +1 -1
  146. package/dist/components/moni-toolbar.js +37 -23
  147. package/dist/components/moni-tooltip.d.ts +100 -36
  148. package/dist/components/moni-tooltip.d.ts.map +1 -1
  149. package/dist/components/moni-tooltip.js +104 -40
  150. package/dist/components/moni-typography.d.ts +68 -30
  151. package/dist/components/moni-typography.d.ts.map +1 -1
  152. package/dist/components/moni-typography.js +70 -32
  153. package/dist/styles/tokens.css +7 -7
  154. package/dist/types/events.d.ts +17 -0
  155. package/dist/types/events.d.ts.map +1 -0
  156. package/dist/types/events.js +1 -0
  157. package/dist/utils/event-emitter.d.ts +13 -0
  158. package/dist/utils/event-emitter.d.ts.map +1 -0
  159. package/dist/utils/event-emitter.js +13 -0
  160. package/package.json +2 -1
  161. package/src/components/_base/moni-element.ts +73 -9
  162. package/src/components/index.ts +2 -2
  163. package/src/components/loading-shapes.ts +19 -0
  164. package/src/components/moni-app-bar.test.ts +10 -10
  165. package/src/components/moni-app-bar.ts +72 -62
  166. package/src/components/moni-badge.ts +64 -66
  167. package/src/components/moni-bottom-sheet.test.ts +39 -45
  168. package/src/components/moni-bottom-sheet.ts +222 -131
  169. package/src/components/moni-button-group.test.ts +14 -14
  170. package/src/components/moni-button-group.ts +107 -29
  171. package/src/components/moni-button-segment.ts +53 -12
  172. package/src/components/moni-button.test.ts +28 -26
  173. package/src/components/moni-button.ts +139 -39
  174. package/src/components/moni-card.test.ts +6 -6
  175. package/src/components/moni-card.ts +70 -50
  176. package/src/components/moni-carousel.test.ts +12 -12
  177. package/src/components/moni-carousel.ts +1129 -269
  178. package/src/components/moni-checkbox.test.ts +7 -7
  179. package/src/components/moni-checkbox.ts +62 -48
  180. package/src/components/moni-chip.test.ts +17 -17
  181. package/src/components/moni-chip.ts +112 -34
  182. package/src/components/moni-color-field.test.ts +5 -5
  183. package/src/components/moni-color-field.ts +108 -24
  184. package/src/components/moni-context-menu.test.ts +11 -11
  185. package/src/components/moni-context-menu.ts +76 -30
  186. package/src/components/moni-dialog.ts +108 -59
  187. package/src/components/moni-divider.test.ts +4 -4
  188. package/src/components/moni-divider.ts +42 -30
  189. package/src/components/moni-expansion.ts +32 -22
  190. package/src/components/moni-fab-menu.test.ts +11 -11
  191. package/src/components/moni-fab-menu.ts +69 -31
  192. package/src/components/moni-fab.test.ts +16 -16
  193. package/src/components/moni-fab.ts +100 -34
  194. package/src/components/moni-file-field.test.ts +8 -8
  195. package/src/components/moni-file-field.ts +132 -30
  196. package/src/components/moni-icon.test.ts +11 -11
  197. package/src/components/moni-icon.ts +43 -38
  198. package/src/components/moni-list-item.test.ts +10 -10
  199. package/src/components/moni-list-item.ts +61 -41
  200. package/src/components/moni-list.ts +37 -21
  201. package/src/components/moni-loading-indicator.test.ts +3 -3
  202. package/src/components/moni-loading-indicator.ts +54 -22
  203. package/src/components/moni-menu-item.ts +23 -16
  204. package/src/components/moni-menu.test.ts +7 -7
  205. package/src/components/moni-menu.ts +87 -30
  206. package/src/components/moni-morph-modal.test.ts +18 -17
  207. package/src/components/moni-morph-modal.ts +327 -60
  208. package/src/components/moni-nav-item.ts +59 -29
  209. package/src/components/moni-nav.test.ts +11 -11
  210. package/src/components/moni-nav.ts +94 -35
  211. package/src/components/moni-progress.test.ts +9 -9
  212. package/src/components/moni-progress.ts +100 -56
  213. package/src/components/moni-radio.test.ts +8 -8
  214. package/src/components/moni-radio.ts +71 -51
  215. package/src/components/moni-ripple.ts +74 -59
  216. package/src/components/moni-segmented-button.test.ts +4 -4
  217. package/src/components/moni-segmented-button.ts +94 -17
  218. package/src/components/moni-select-option.ts +30 -23
  219. package/src/components/moni-select.test.ts +11 -11
  220. package/src/components/moni-select.ts +361 -50
  221. package/src/components/moni-side-sheet.test.ts +7 -7
  222. package/src/components/moni-side-sheet.ts +94 -32
  223. package/src/components/moni-slider.test.ts +7 -7
  224. package/src/components/moni-slider.ts +165 -42
  225. package/src/components/moni-snackbar.test.ts +8 -8
  226. package/src/components/moni-snackbar.ts +53 -43
  227. package/src/components/moni-split-button.ts +63 -18
  228. package/src/components/moni-step.test.ts +7 -7
  229. package/src/components/moni-step.ts +41 -29
  230. package/src/components/moni-stepper.test.ts +7 -7
  231. package/src/components/moni-stepper.ts +72 -34
  232. package/src/components/moni-switch.test.ts +12 -12
  233. package/src/components/moni-switch.ts +66 -47
  234. package/src/components/moni-tab.test.ts +5 -5
  235. package/src/components/moni-tab.ts +29 -21
  236. package/src/components/moni-tabs.ts +34 -28
  237. package/src/components/moni-text-field.test.ts +13 -13
  238. package/src/components/moni-text-field.ts +181 -30
  239. package/src/components/moni-textarea.test.ts +17 -17
  240. package/src/components/moni-textarea.ts +155 -31
  241. package/src/components/moni-time-picker.test.ts +5 -5
  242. package/src/components/moni-time-picker.ts +128 -33
  243. package/src/components/moni-toolbar.test.ts +8 -8
  244. package/src/components/moni-toolbar.ts +37 -23
  245. package/src/components/moni-tooltip.test.ts +15 -15
  246. package/src/components/moni-tooltip.ts +107 -40
  247. package/src/components/moni-typography.test.ts +10 -10
  248. package/src/components/moni-typography.ts +73 -32
  249. package/src/styles/tokens.css +7 -7
  250. package/src/types/events.ts +17 -0
  251. 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 component.
13
+ * Componente Material Design 3 Menu (Menú).
14
14
  *
15
- * Menus display a list of choices on a temporary surface. They appear when
16
- * users interact with a button, action, or other control.
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
- * **M3 spec reference:** `m3-docs/components/menus/guidelines.md`
18
+ * **Referencia de la especificación M3:** `m3-docs/components/menus/guidelines.md`
19
19
  *
20
- * **Positioning architecture:**
21
- * The menu uses `position: absolute` relative to its nearest positioned
22
- * ancestor. The component's `:host` uses `display: contents`, meaning the
23
- * inner `<menu>` element directly participates in the consumer's layout context.
24
- * **Crucial:** The consumer must apply `position: relative` to the wrapper
25
- * element that contains both the trigger and the `<moni-menu>`.
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
- * **Auto-flip positioning:**
28
- * Per M3 guidelines, menus should flip to the opposite side of the anchor
29
- * if they overflow the viewport.
30
- * - **Modern browsers (Chrome/Edge 125+, Safari 18+):** Uses CSS anchor
31
- * positioning and `@position-try-fallback` natively when `flip=true`.
32
- * - **Fallback:** A JavaScript polyfill measures the menu after it opens. If
33
- * it overflows the requested `placement`, it sets an internal state to flip
34
- * the placement classes.
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
- * **State management:**
37
- * The `active` attribute controls visibility. Consumers must listen to trigger
38
- * events (like `click`) and toggle the `active` property.
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
- * <!-- Wrapper must have position: relative -->
42
+ * <!-- El contenedor debe tener position: relative -->
43
43
  * <div style="position: relative; display: inline-block;">
44
- * <moni-button id="menu-trigger">Open Menu</moni-button>
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">Edit</moni-menu-item>
48
- * <moni-menu-item icon="content_copy">Copy</moni-menu-item>
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">Delete</moni-menu-item>
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>`, or raw `<li>` elements.
61
+ * @slot default - Elementos `<moni-menu-item>`, `<moni-divider>`, o elementos `<li>` en bruto.
62
62
  *
63
- * @csspart menu - The inner `<menu>` container.
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('registers the custom element', () => {
77
+ it('registra el elemento personalizado', () => {
78
78
  expect(customElements.get('moni-morph-modal')).toBeTruthy();
79
79
  });
80
80
 
81
- it('renders a panel and a backdrop in shadow root', async () => {
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('reflects the target attribute', async () => {
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('reflects the open attribute', async () => {
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('projects the default slot content', async () => {
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('projects the header slot content', async () => {
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('projects the footer slot content', async () => {
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('shows the close button when show-close-button is true', async () => {
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('toggles open state when show() and hide() are called', async () => {
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('toggles open state when toggle() is called', async () => {
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('warns when target is not found', () => {
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('supports recursive declaration of nested morph modals', async () => {
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('does not create morph elements by default', async () => {
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('creates and cleans up morph-text when morph-label is true', async () => {
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('uses trigger-label slot content when provided', async () => {
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('runs label FLIP on close when morph-label is true', async () => {
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('does not create morph elements when reduced motion is preferred', async () => {
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;