@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,46 +10,46 @@ import { customElement, property } from 'lit/decorators.js';
10
10
  import { MoniElement, sharedStyles } from './_base/index.js';
11
11
 
12
12
  /**
13
- * Material Design 3 Top App Bar (Toolbar) component.
13
+ * Componente Material Design 3 Top App Bar (Barra de herramientas superior).
14
14
  *
15
- * Top app bars display information and actions at the top of a screen.
16
- * They are used for branding, screen titles, navigation, and actions.
15
+ * Las barras de aplicación superiores muestran información y acciones en la parte superior de una pantalla.
16
+ * Se utilizan para identidad de marca, títulos de pantalla, navegación y acciones.
17
17
  *
18
- * **M3 spec reference:** `m3-docs/components/top-app-bar/specs.md`
18
+ * **Referencia a la especificación M3:** `m3-docs/components/top-app-bar/specs.md`
19
19
  *
20
- * **Note:** This is the standard top-level toolbar. For bottom navigation
21
- * bars (often used on mobile), use `<moni-app-bar>`.
20
+ * **Nota:** Esta es la barra de herramientas estándar de nivel superior. Para barras de navegación
21
+ * inferiores (a menudo usadas en móviles), usa `<moni-app-bar>`.
22
22
  *
23
- * **Variants:**
24
- * - `standard` (default): A full-width bar (64dp height) that sits flush
25
- * against the top of the screen.
26
- * - `floating`: A detached bar with a 4dp margin and rounded 8dp corners,
27
- * appearing to float above the content.
23
+ * **Variantes:**
24
+ * - `standard` (por defecto): Una barra de ancho completo (altura de 64dp) que se asienta al ras
25
+ * contra la parte superior de la pantalla.
26
+ * - `floating`: Una barra separada con un margen de 4dp y esquinas redondeadas de 8dp,
27
+ * que parece flotar sobre el contenido.
28
28
  *
29
- * **Scroll behavior:**
30
- * When the `scroll` attribute is present, the toolbar visually responds to
31
- * scrolling by increasing its elevation (shadow) and dynamically shifting
32
- * its surface color to indicate depth over the scrolling content.
29
+ * **Comportamiento de desplazamiento (scroll):**
30
+ * Cuando el atributo `scroll` está presente, la barra de herramientas responde visualmente al
31
+ * desplazamiento aumentando su elevación (sombra) y cambiando dinámicamente
32
+ * su color de superficie para indicar profundidad sobre el contenido desplazado.
33
33
  *
34
34
  * @example
35
35
  * ```html
36
- * <!-- Standard toolbar with navigation and actions -->
37
- * <moni-toolbar title="Inbox">
36
+ * <!-- Barra de herramientas estándar con navegación y acciones -->
37
+ * <moni-toolbar title="Bandeja de entrada">
38
38
  * <moni-icon-button slot="leading" icon="menu"></moni-icon-button>
39
39
  * <moni-icon-button slot="trailing" icon="search"></moni-icon-button>
40
40
  * <moni-icon-button slot="trailing" icon="more_vert"></moni-icon-button>
41
41
  * </moni-toolbar>
42
42
  *
43
- * <!-- Floating toolbar with an attached FAB -->
44
- * <moni-toolbar type="floating" title="Notes">
43
+ * <!-- Barra de herramientas flotante con un FAB adjunto -->
44
+ * <moni-toolbar type="floating" title="Notas">
45
45
  * <moni-fab slot="action-button" icon="add"></moni-fab>
46
46
  * </moni-toolbar>
47
47
  * ```
48
48
  *
49
- * @slot default - The title text or center content.
50
- * @slot leading - Navigation icon/button placed on the far left.
51
- * @slot trailing - Action icons/buttons placed on the far right.
52
- * @slot action-button - A floating action button (FAB) anchored to the right side.
49
+ * @slot default - El texto del título o contenido central.
50
+ * @slot leading - Icono/botón de navegación colocado en el extremo izquierdo.
51
+ * @slot trailing - Iconos/botones de acción colocados en el extremo derecho.
52
+ * @slot action-button - Un botón de acción flotante (FAB) anclado al lado derecho.
53
53
  */
54
54
  @customElement('moni-toolbar')
55
55
  export class MoniToolbar extends MoniElement {
@@ -123,6 +123,20 @@ export class MoniToolbar extends MoniElement {
123
123
  `
124
124
  ];
125
125
 
126
+ /**
127
+ * Renderiza el diseño `<header>` de 3 zonas de la barra de herramientas.
128
+ *
129
+ * **Zonas:**
130
+ * - `.leading` — slot inicial para iconos de navegación o controles de migas de pan (breadcrumb).
131
+ * - `.title` — zona del título central; renderiza `this.title` como texto si el atributo
132
+ * está configurado, de lo contrario recurre al slot por defecto para contenido rico.
133
+ * - `.trailing` — slot final para iconos de acción (buscar, más, etc.).
134
+ *
135
+ * **Slot `action-button`:**
136
+ * Un slot nombrado separado, fuera del `<header>`, para un botón de acción flotante
137
+ * (FAB) o disparador de menú contextual que no debe participar en el diseño
138
+ * flex de la fila del título.
139
+ */
126
140
  override render() {
127
141
  return html`
128
142
  <header class="container" part="container">
@@ -18,24 +18,24 @@ describe('moni-tooltip (P3.1)', () => {
18
18
  parent.remove();
19
19
  });
20
20
 
21
- it('renders role="tooltip" on the inner element (M3 a11y)', async () => {
21
+ it('renderiza role="tooltip" en el elemento interno (accesibilidad M3)', async () => {
22
22
  await el.updateComplete;
23
23
  const tip = el.shadowRoot?.querySelector('[role="tooltip"]');
24
24
  expect(tip).toBeTruthy();
25
25
  });
26
26
 
27
- it('reflects the text on the host', async () => {
27
+ it('refleja el texto en el host', async () => {
28
28
  await el.updateComplete;
29
29
  expect(el.text).toBe('Save changes');
30
30
  });
31
31
 
32
- it('reflects position (default top)', async () => {
32
+ it('refleja la posición (top por defecto)', async () => {
33
33
  await el.updateComplete;
34
34
  const tip = el.shadowRoot?.querySelector('.tooltip');
35
35
  expect(tip?.classList.contains('top')).toBe(true);
36
36
  });
37
37
 
38
- it('accepts all 6 M3 placements (top/top-start/top-end/bottom/bottom-start/bottom-end)', async () => {
38
+ it('acepta los 6 posicionamientos M3 (top/top-start/top-end/bottom/bottom-start/bottom-end)', async () => {
39
39
  const positions: Array<'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end'> = [
40
40
  'top',
41
41
  'top-start',
@@ -52,20 +52,20 @@ describe('moni-tooltip (P3.1)', () => {
52
52
  }
53
53
  });
54
54
 
55
- it('defaults to plain (rich=false)', async () => {
55
+ it('es plano (plain) por defecto (rich=false)', async () => {
56
56
  await el.updateComplete;
57
57
  expect(el.rich).toBe(false);
58
58
  expect(el.hasAttribute('rich')).toBe(false);
59
59
  });
60
60
 
61
- it('rich=true enables rich content mode (rich attribute reflected)', async () => {
61
+ it('rich=true habilita el modo de contenido enriquecido (atributo rich reflejado)', async () => {
62
62
  el.rich = true;
63
63
  await el.updateComplete;
64
64
  expect(el.rich).toBe(true);
65
65
  expect(el.hasAttribute('rich')).toBe(true);
66
66
  });
67
67
 
68
- it('shows the tooltip on mouseenter and hides on mouseleave', async () => {
68
+ it('muestra el tooltip en mouseenter y lo oculta en mouseleave', async () => {
69
69
  await el.updateComplete;
70
70
  const tip = el.shadowRoot?.querySelector('.tooltip') as HTMLElement;
71
71
  expect(tip?.classList.contains('visible')).toBe(false);
@@ -79,7 +79,7 @@ describe('moni-tooltip (P3.1)', () => {
79
79
  expect(tip?.classList.contains('visible')).toBe(false);
80
80
  });
81
81
 
82
- it('shows the tooltip on focusin and hides on focusout', async () => {
82
+ it('muestra el tooltip en focusin y lo oculta en focusout', async () => {
83
83
  await el.updateComplete;
84
84
  const tip = el.shadowRoot?.querySelector('.tooltip') as HTMLElement;
85
85
  parent.dispatchEvent(new FocusEvent('focusin', { bubbles: true }));
@@ -91,7 +91,7 @@ describe('moni-tooltip (P3.1)', () => {
91
91
  expect(tip?.classList.contains('visible')).toBe(false);
92
92
  });
93
93
 
94
- it('Escape key closes a visible tooltip', async () => {
94
+ it('la tecla Escape cierra un tooltip visible', async () => {
95
95
  await el.updateComplete;
96
96
  const tip = el.shadowRoot?.querySelector('.tooltip') as HTMLElement;
97
97
  parent.dispatchEvent(new MouseEvent('mouseenter', { bubbles: true }));
@@ -103,20 +103,20 @@ describe('moni-tooltip (P3.1)', () => {
103
103
  expect(tip?.classList.contains('visible')).toBe(false);
104
104
  });
105
105
 
106
- it('applies size variants (small/medium/large)', async () => {
106
+ it('aplica las variantes de tamaño (small/medium/large)', async () => {
107
107
  for (const size of ['small', 'medium', 'large'] as const) {
108
108
  el.size = size;
109
109
  await el.updateComplete;
110
110
  const tip = el.shadowRoot?.querySelector('.tooltip');
111
- expect(tip?.classList.contains(size), `expected class ${size}`).toBe(true);
111
+ expect(tip?.classList.contains(size), `esperada clase ${size}`).toBe(true);
112
112
  }
113
113
  });
114
114
 
115
- it('cleans up listeners on disconnect', () => {
116
- // Sanity: removing the parent cleans up.
115
+ it('limpia los listeners al desconectarse', () => {
116
+ // Sanidad: remover el padre limpia todo.
117
117
  parent.remove();
118
- // No assertion needed; if listeners leaked, the next beforeEach would
119
- // accumulate them but vitest would still pass. Visual coverage only.
118
+ // No se necesita aserción; si los listeners se fugaran, el siguiente beforeEach
119
+ // acumularía listeners pero vitest pasaría. Solo cobertura visual.
120
120
  expect(parent.isConnected).toBe(false);
121
121
  });
122
122
  });
@@ -10,62 +10,72 @@ import { customElement, property } from 'lit/decorators.js';
10
10
  import { MoniElement, sharedStyles } from './_base/index.js';
11
11
 
12
12
  /**
13
- * Material Design 3 Tooltip component.
13
+ * Componente Material Design 3 Tooltip (Información sobre herramientas).
14
14
  *
15
- * Tooltips provide contextual text labels or rich content that appear when
16
- * users hover over, focus on, or tap an element. They surface supplementary
17
- * information that helps users understand interface elements without
18
- * permanently occupying screen space.
15
+ * Los tooltips proporcionan etiquetas de texto contextual o contenido enriquecido que aparecen cuando
16
+ * los usuarios pasan el cursor por encima, enfocan o tocan un elemento. Muestran información
17
+ * complementaria que ayuda a los usuarios a entender los elementos de la interfaz sin
18
+ * ocupar permanentemente espacio en la pantalla.
19
19
  *
20
- * **M3 spec reference:** `m3-docs/components/tooltips/specs.md`
20
+ * **Referencia a la especificación M3:** `m3-docs/components/tooltips/specs.md`
21
21
  *
22
- * **Types:**
23
- * - **Plain** (default) — Text-only label for simple descriptions (max 1 line).
24
- * - **Rich** (`rich` attribute) — HTML content including formatted text,
25
- * links, and icons. Rich tooltips can contain multiple lines and action links.
22
+ * **Tipos:**
23
+ * - **Plain** (por defecto) — Etiqueta solo de texto para descripciones simples (máx. 1 línea).
24
+ * - **Rich** (atributo `rich`) — Contenido HTML que incluye texto formateado,
25
+ * enlaces e iconos. Los tooltips enriquecidos pueden contener múltiples líneas y enlaces de acción.
26
26
  *
27
- * **Placements:**
28
- * - `top` (default), `top-start`, `top-end`
27
+ * **Ubicaciones (Placements):**
28
+ * - `top` (por defecto), `top-start`, `top-end`
29
29
  * - `bottom`, `bottom-start`, `bottom-end`
30
30
  *
31
- * **Trigger mechanism:**
32
- * The tooltip uses `position: absolute` inside the parent element. The parent
33
- * must have `position: relative` (set automatically via `connectedCallback`).
34
- * Hover/focus events on the parent trigger the tooltip's CSS `:hover` and
35
- * `:focus-within` selectors, which drive the show/hide transition.
31
+ * **Mecanismo de activación (Trigger):**
32
+ * El tooltip usa `position: absolute` dentro del elemento padre. El padre
33
+ * debe tener `position: relative` (establecido automáticamente vía `connectedCallback`).
34
+ * Los eventos hover/focus en el padre activan los selectores CSS `:hover` y
35
+ * `:focus-within` del tooltip, los cuales impulsan la transición de mostrar/ocultar.
36
36
  *
37
- * **Accessibility:**
38
- * - The tooltip has `role="tooltip"`.
39
- * - For keyboard accessibility, the parent should have `aria-describedby`
40
- * pointing to the tooltip's `id` attribute. The component exposes a
41
- * `tooltipId` getter for this purpose.
42
- * - The `Escape` key closes rich tooltips.
37
+ * **Accesibilidad:**
38
+ * - El tooltip tiene `role="tooltip"`.
39
+ * - Para accesibilidad por teclado, el padre debe tener `aria-describedby`
40
+ * apuntando al atributo `id` del tooltip. El componente expone un
41
+ * getter `tooltipId` para este propósito.
42
+ * - La tecla `Escape` cierra los tooltips enriquecidos.
43
43
  *
44
44
  * @example
45
45
  * ```html
46
- * <!-- Plain tooltip -->
46
+ * <!-- Tooltip simple (Plain) -->
47
47
  * <button aria-describedby="save-tip">
48
- * Save
48
+ * Guardar
49
49
  * <moni-tooltip id="save-tip" text="Ctrl+S"></moni-tooltip>
50
50
  * </button>
51
51
  *
52
- * <!-- Rich tooltip -->
52
+ * <!-- Tooltip enriquecido (Rich) -->
53
53
  * <button>
54
- * Filter
54
+ * Filtrar
55
55
  * <moni-tooltip rich position="bottom">
56
- * <strong>Filter by date</strong>
57
- * <p>Select a date range to filter results.</p>
56
+ * <strong>Filtrar por fecha</strong>
57
+ * <p>Selecciona un rango de fechas para filtrar resultados.</p>
58
58
  * </moni-tooltip>
59
59
  * </button>
60
60
  * ```
61
61
  *
62
- * @slot default - Rich content for the tooltip body (only used when `rich=true`).
62
+ * @slot default - Contenido enriquecido para el cuerpo del tooltip (solo usado cuando `rich=true`).
63
63
  *
64
- * @csspart tooltip - The tooltip container element.
64
+ * @csspart tooltip - El elemento contenedor del tooltip.
65
65
  */
66
66
  @customElement('moni-tooltip')
67
67
  export class MoniTooltip extends MoniElement {
68
+ /**
69
+ * Contenido de texto simple para mostrar. Utilizado cuando `rich` es falso.
70
+ * @type {string}
71
+ */
68
72
  @property({ reflect: true }) text = '';
73
+
74
+ /**
75
+ * Ubicación preferida relativa al ancla/activador.
76
+ * @type {'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end'}
77
+ * @default 'top'
78
+ */
69
79
  @property({ reflect: true })
70
80
  position:
71
81
  | 'top'
@@ -74,25 +84,47 @@ export class MoniTooltip extends MoniElement {
74
84
  | 'bottom'
75
85
  | 'bottom-start'
76
86
  | 'bottom-end' = 'top';
87
+
88
+ /**
89
+ * Mapeo de tamaño opcional (usado por hojas de estilo internas para escalar fuente/relleno).
90
+ * @type {'' | 'small' | 'medium' | 'large'}
91
+ * @default ''
92
+ */
77
93
  @property({ reflect: true })
78
94
  size: '' | 'small' | 'medium' | 'large' = '';
95
+
96
+ /**
97
+ * Si es true, cambia al modo de Tooltip Enriquecido (permite HTML/componentes en el slot por defecto).
98
+ * @type {boolean}
99
+ */
79
100
  @property({ type: Boolean, reflect: true }) rich = false;
80
101
 
81
102
  private _target: HTMLElement | null = null;
82
103
  private _tooltipEl: HTMLElement | null = null;
104
+ /**
105
+ * Wrapper estático para el evento de teclado global.
106
+ * Mantiene fijo el contexto léxico para registrar/desregistrar limpiamente.
107
+ */
83
108
  private _docKeydown = (e: KeyboardEvent) => this._handleDocKeydown(e);
84
109
  /**
85
- * CSS `anchor-name` registered on the parent trigger so the tooltip
86
- * can use `position-anchor` to bind to it. Generated per-instance via
87
- * `crypto.randomUUID()` when CSS anchor positioning is supported.
110
+ * Nombre de anclaje CSS (`anchor-name`) registrado en el activador padre para que el tooltip
111
+ * pueda usar `position-anchor` para vincularse a él. Generado por instancia vía
112
+ * `crypto.randomUUID()` cuando el posicionamiento de anclaje CSS está soportado.
88
113
  */
89
114
  private _anchorName: string | null = null;
90
115
 
116
+ /**
117
+ * Hook de inicialización (Lit).
118
+ * Resuelve la asociación nativa con su elemento padre (trigger), forzando un contexto
119
+ * de posicionamiento relativo (`position: relative`) si es necesario. Vincula dinámicamente
120
+ * listeners de `mouseenter/leave` y `focusin/out` para controlar la visibilidad del globo.
121
+ * También auto-registra la revolucionaria CSS Anchor Positioning API si el navegador la soporta.
122
+ */
91
123
  override connectedCallback() {
92
124
  super.connectedCallback();
93
125
  this._target = this.parentElement;
94
126
  if (this._target) {
95
- // Ensure parent has position: relative so absolute tooltip is anchored
127
+ // Asegura que el padre tenga position: relative para anclar el tooltip absoluto
96
128
  const style = getComputedStyle(this._target);
97
129
  if (style.position === 'static') {
98
130
  this._target.style.position = 'relative';
@@ -102,9 +134,9 @@ export class MoniTooltip extends MoniElement {
102
134
  this._target.addEventListener('mouseleave', this._hide);
103
135
  this._target.addEventListener('focusout', this._hide);
104
136
 
105
- // Auto-register a CSS anchor name on the parent trigger when the
106
- // browser supports anchor positioning. Consumers can opt out by
107
- // setting `data-no-anchor` on the trigger.
137
+ // Auto-registra un nombre de ancla CSS en el activador padre cuando el
138
+ // navegador soporta posicionamiento de ancla. Los consumidores pueden excluirse
139
+ // estableciendo `data-no-anchor` en el activador.
108
140
  const cssSupports = (globalThis as unknown as {
109
141
  CSS?: { supports?: (k: string) => boolean };
110
142
  }).CSS?.supports;
@@ -124,6 +156,11 @@ export class MoniTooltip extends MoniElement {
124
156
  document.addEventListener('keydown', this._docKeydown);
125
157
  }
126
158
 
159
+ /**
160
+ * Hook de destrucción (Lit).
161
+ * Remueve diligentemente todos los detectores de eventos del padre (trigger)
162
+ * y limpia las declaraciones generadas dinámicamente en estilos inline (`anchor-name`).
163
+ */
127
164
  override disconnectedCallback() {
128
165
  if (this._target) {
129
166
  this._target.removeEventListener('mouseenter', this._show);
@@ -139,6 +176,10 @@ export class MoniTooltip extends MoniElement {
139
176
  super.disconnectedCallback();
140
177
  }
141
178
 
179
+ /**
180
+ * Inyecta la clase activa (`.visible`) desencadenando la animación de opacidad/escalado.
181
+ * Cached-query: Recupera asíncronamente el tooltip del Shadow DOM si no lo había hecho.
182
+ */
142
183
  private _show = () => {
143
184
  if (!this._tooltipEl) {
144
185
  this._tooltipEl = this.shadowRoot?.querySelector('.tooltip') as HTMLElement;
@@ -148,6 +189,9 @@ export class MoniTooltip extends MoniElement {
148
189
  }
149
190
  };
150
191
 
192
+ /**
193
+ * Retira la clase activa (`.visible`), desvaneciendo el globo con gracia.
194
+ */
151
195
  private _hide = () => {
152
196
  if (!this._tooltipEl) {
153
197
  this._tooltipEl = this.shadowRoot?.querySelector('.tooltip') as HTMLElement;
@@ -157,6 +201,11 @@ export class MoniTooltip extends MoniElement {
157
201
  }
158
202
  };
159
203
 
204
+ /**
205
+ * Manejador global del teclado (a11y).
206
+ * Permite disipar instantáneamente el tooltip presionando `Escape`
207
+ * sin necesidad de mover el ratón o perder el foco.
208
+ */
160
209
  private _handleDocKeydown(e: KeyboardEvent) {
161
210
  if (e.key !== 'Escape') return;
162
211
  if (!this._tooltipEl?.classList.contains('visible')) return;
@@ -164,8 +213,8 @@ export class MoniTooltip extends MoniElement {
164
213
  }
165
214
 
166
215
  /**
167
- * Public ID of the tooltip element, suitable for `aria-describedby` on
168
- * the trigger parent. Auto-generated if the consumer did not set `id`.
216
+ * ID público del elemento tooltip, adecuado para `aria-describedby` en
217
+ * el padre activador. Generado automáticamente si el consumidor no estableció un `id`.
169
218
  */
170
219
  get tooltipId(): string {
171
220
  return this._tooltipEl?.id || '';
@@ -328,6 +377,24 @@ export class MoniTooltip extends MoniElement {
328
377
  `
329
378
  ];
330
379
 
380
+ /**
381
+ * Renderiza el `<div>` del tooltip con su lista de clases calculada y atributos ARIA.
382
+ *
383
+ * **Composición de clases:**
384
+ * - `'tooltip'` — siempre presente; estilos base.
385
+ * - `this.position` — variante de ubicación (ej. `'top'`, `'bottom-start'`).
386
+ * - `this.size` — modificador de tamaño (`'small'`, `'medium'`, `'large'`).
387
+ *
388
+ * **CSS Anchor Positioning:**
389
+ * Si `_anchorName` está poblado, lo inyecta como la propiedad personalizada `--_anchor-name`.
390
+ * La declaración CSS `@anchor-name` conecta este tooltip a su elemento activador
391
+ * a través de la API CSS Anchor Positioning (Chrome 125+).
392
+ * En navegadores no compatibles, se utiliza un posicionamiento absoluto clásico como respaldo.
393
+ *
394
+ * **Respaldo de contenido:**
395
+ * El slot por defecto renderiza el contenido distribuido (slotted); si no hay hijos,
396
+ * el valor del atributo `text` se muestra como la etiqueta del tooltip.
397
+ */
331
398
  override render() {
332
399
  const classes = [
333
400
  'tooltip',
@@ -14,13 +14,13 @@ describe('moni-typography (P5.2 — recreated)', () => {
14
14
  el.remove();
15
15
  });
16
16
 
17
- it('defaults to variant=body, size=medium', async () => {
17
+ it('variant=body, size=medium por defecto', async () => {
18
18
  await el.updateComplete;
19
19
  expect(el.variant).toBe('body');
20
20
  expect(el.size).toBe('medium');
21
21
  });
22
22
 
23
- it('renders the default <p> tag for body variant', async () => {
23
+ it('renderiza la etiqueta <p> por defecto para la variante body', async () => {
24
24
  el.text = 'Hello';
25
25
  await el.updateComplete;
26
26
  const el_tag = el.shadowRoot?.querySelector('p');
@@ -28,7 +28,7 @@ describe('moni-typography (P5.2 — recreated)', () => {
28
28
  expect(el_tag?.textContent?.trim()).toBe('Hello');
29
29
  });
30
30
 
31
- it('renders <h1> for display variant', async () => {
31
+ it('renderiza <h1> para la variante display', async () => {
32
32
  el.variant = 'display';
33
33
  el.text = 'Big text';
34
34
  await el.updateComplete;
@@ -37,7 +37,7 @@ describe('moni-typography (P5.2 — recreated)', () => {
37
37
  expect(h1?.classList.contains('display')).toBe(true);
38
38
  });
39
39
 
40
- it('renders <h2> for headline variant', async () => {
40
+ it('renderiza <h2> para la variante headline', async () => {
41
41
  el.variant = 'headline';
42
42
  el.text = 'Section';
43
43
  await el.updateComplete;
@@ -46,21 +46,21 @@ describe('moni-typography (P5.2 — recreated)', () => {
46
46
  expect(h2?.classList.contains('headline')).toBe(true);
47
47
  });
48
48
 
49
- it('renders <h3> for title variant', async () => {
49
+ it('renderiza <h3> para la variante title', async () => {
50
50
  el.variant = 'title';
51
51
  await el.updateComplete;
52
52
  const h3 = el.shadowRoot?.querySelector('h3');
53
53
  expect(h3).toBeTruthy();
54
54
  });
55
55
 
56
- it('renders <label> for label variant', async () => {
56
+ it('renderiza <label> para la variante label', async () => {
57
57
  el.variant = 'label';
58
58
  await el.updateComplete;
59
59
  const label = el.shadowRoot?.querySelector('label');
60
60
  expect(label).toBeTruthy();
61
61
  });
62
62
 
63
- it('overrides the tag via the as attribute', async () => {
63
+ it('sobrescribe la etiqueta mediante el atributo as', async () => {
64
64
  el.variant = 'headline';
65
65
  el.as = 'span';
66
66
  await el.updateComplete;
@@ -69,7 +69,7 @@ describe('moni-typography (P5.2 — recreated)', () => {
69
69
  expect(span?.classList.contains('headline')).toBe(true);
70
70
  });
71
71
 
72
- it('reflects size variations', async () => {
72
+ it('refleja las variaciones de tamaño', async () => {
73
73
  el.variant = 'title';
74
74
  for (const size of ['large', 'medium', 'small'] as const) {
75
75
  el.size = size;
@@ -79,7 +79,7 @@ describe('moni-typography (P5.2 — recreated)', () => {
79
79
  }
80
80
  });
81
81
 
82
- it('supports all 5 variants × 3 sizes', async () => {
82
+ it('soporta las 5 variantes × 3 tamaños', async () => {
83
83
  const variants: Array<'display' | 'headline' | 'title' | 'body' | 'label'> = [
84
84
  'display',
85
85
  'headline',
@@ -106,7 +106,7 @@ describe('moni-typography (P5.2 — recreated)', () => {
106
106
  }
107
107
  });
108
108
 
109
- it('renders slot content when text attribute is empty', async () => {
109
+ it('renderiza el contenido del slot cuando el atributo text está vacío', async () => {
110
110
  el.text = '';
111
111
  el.textContent = 'Slotted content';
112
112
  await el.updateComplete;